Skip to content
Night Owls.dev
Jump to a page

@nightowlsdev/engine-eve

EngineAdapter, reduced governance

The Vercel Eve protocol adapter engine, renders a running Eve app's NDJSON session as a single Night Owls agent. Adapter tier: reduced governance, tier-2 events (tool calls + usage visible, no delegation); durable park/resume on Vercel Workflows.

What it does

**Use this when:** you've deployed a Vercel Eve app (its own agent loop) and want to front its running session as a single agent inside a Night Owls swarm — chat with it, see its tool calls and usage. **How.** `eveEngine({ baseUrl, routeAuthSecret?, agentSlug? })` talks to the app's `/eve/v1/*` routes (deployed or `pnpm dev`) and maps Eve's NDJSON wire onto Night Owls events. Then `defineSwarm({ engine })` or `owl install engine-eve`. **What it can and can't do (adapter tier).** Eve's loop runs on the remote (parked durably on Vercel Workflows), so the in-process governance plane doesn't apply — the remote owns generation, the tool gate, cost caps, and its own secrets. It IS a notch richer than `engine-a2a`, though: `events.tier: 2`, so the remote's tool calls (`actions.requested`/`action.result`) and per-step usage are VISIBLE, not opaque. HITL crosses the boundary (Eve's `input.requested`, including two-option confirmations, maps onto the ask/answer loop) and durable resume is native to the Eve protocol. One honesty caveat: cancellation is client-stop-only — the remote durable turn may keep running after you stop listening.

Install

pnpm add @nightowlsdev/engine-eve

Key exports

  • eveEngine
  • EveEngine
  • EVE_ENGINE_CAPABILITIES
  • createFetchEveTransport
  • bearerToken / noneAuth / staticHeaders
  • mapEveEvent
  • extractEveUsage
  • assertStreamVersion / parseNdjsonStream
  • nightOwlsPlugin

Usage

engine-eve.ts
import { defineSwarm } from "@nightowlsdev/core";
import { eveEngine, EVE_ENGINE_CAPABILITIES } from "@nightowlsdev/engine-eve";

// An ADAPTER over a deployed Vercel Eve app's NDJSON session, the loop runs on the remote
// (parked on durable Vercel Workflows); this renders it as one Night Owls agent.
const swarm = defineSwarm({ agents, engine: eveEngine({ baseUrl: "https://my-eve-app.vercel.app" }) });

// Tier-2 events (tool calls + usage visible) but reduced governance, the remote owns the gate.
console.log(EVE_ENGINE_CAPABILITIES.events.tier); // 2
console.log(EVE_ENGINE_CAPABILITIES.governance.costCaps); // false

What it provides

engine-eve is a protocol ADAPTER over a deployed Vercel Eve app: Eve's own agent loop runs on the remote (parked durably on Vercel Workflows), and this renders its NDJSON session stream as a single Night Owls agent rather than executing in-process. It talks to every /eve/v1/* route under the app's base URL and maps Eve's wire — actions.requested / action.result (tool visibility), step.completed.usage, and input.requested (including two-option confirmations) — onto SwarmEvents. That makes it one notch richer than the opaque engine-a2a: tier-2 events (tool calls + usage visible), but still reduced governance because the remote owns generation, the tool gate, cost caps, and its own secrets.

When to use it

  • You have a deployed (or pnpm dev) Vercel Eve app and want to surface it as one Night Owls agent inside a swarm and its React UI.
  • You want tool visibility and per-step usage from the remote (tier 2), not just the opaque message/status surface A2A gives.
  • You want the remote's input.requested asks (including two-option confirmations) relayed into Night Owls' ask/answer HITL loop.

When not to

  • You need Night Owls' governance to actually enforce — the remote Eve loop owns generation, the tool gate, cost caps, and secrets; governance is all false here.
  • You need delegation, workflows, rules injection, or a scratchpad — none are driven across the Eve boundary (an Eve app IS one agent; subagent.called is a cosmetic status note only in v1).
  • You need a hard mid-stream cancel — cancellation is client-stream-stop only; the remote durable turn may continue after you stop listening.

Alternatives

  • engine-a2aYour remote speaks the A2A protocol (Bedrock/Azure/Google) rather than Eve's NDJSON wire — accept the opaque tier-1 surface (no tool events).
  • engine-trigger-chatYour remote loop is a Trigger.dev chat.agent Session rather than a Vercel Eve app — also a tier-2 remote adapter (but experimental).
  • A native engine (engine-mastra / engine-ai-sdk / engine-openai-agents)You control the loop and want the full governance plane and tool gate in-process instead of adapting a remote.

Strengths

  • Tier-2 events: tool calls (actions.requested/action.result) AND per-step usage (step.completed.usage) are visible, one notch richer than opaque A2A.
  • HITL relayed both ways: Eve's input.requested — including two-option confirmations — maps onto ask/approval; both hitl.ask and hitl.approval are true.
  • durableResume is STATICALLY true — Eve sessions park on durable Vercel Workflows, a fact of the remote protocol, not something your storage configures.
  • Simple wiring (baseUrl + optional routeAuthSecret), a versioned NDJSON wire (assertStreamVersion / parseNdjsonStream guard drift), and engine-wall clean.

Limits & trade-offs

  • Reduced-governance adapter tier: governance is all false — the remote loop owns generation, the tool gate, cost caps, and its own secrets; our plane can't reach it.
  • No delegation lane stitching, no workflow driving, no rules injection, and no scratchpad across the boundary (an Eve app is a single agent).
  • cancellation is 'between-steps' — a client-stream stop only; the remote durable turn may keep running, an honesty caveat, not a guaranteed abort.
  • No OTel telemetry (metering is swarm.usage / swarm.turn_usage only); Eve has no built-in per-session ownership ACL, so routeAuthSecret is just the credential its route auth expects.

How it works

eveEngine({ baseUrl, routeAuthSecret?, agentSlug? }) builds a fetch-backed transport over the app's /eve/v1/* routes (or takes a test transport override) and returns (opts) => new EveEngine(opts, cfg). At run time it drives the NDJSON session stream and maps Eve wire events onto SwarmEvents via mapEveEvent, pulling token counts with extractEveUsage. input.requested maps onto the ask/answer loop; hitl.durableResume is static true because Eve parks on Vercel Workflows. When agentSlug is set, run() rejects a mismatched ctx.agentSlug before any storage write and listAgents() surfaces only that slug. Reads/history come from OUR persisted event log.

Examples

Adapt a deployed Vercel Eve app

One factory renders the remote Eve session as a single Night Owls agent; routeAuthSecret is the credential the app's route auth expects.

engine-eve-example-1.ts
import { defineSwarm } from "@nightowlsdev/core";
import { eveEngine } from "@nightowlsdev/engine-eve";

export default defineSwarm({
  agents,
  engine: eveEngine({
    baseUrl: "https://my-eve-app.vercel.app",
    routeAuthSecret: process.env.EVE_ROUTE_SECRET,
  }),
});

Confirm the tier-2, reduced-governance posture

Tool calls and usage ARE visible (tier 2), but the remote owns the gate — governance is off.

engine-eve-example-2.ts
import { EVE_ENGINE_CAPABILITIES } from "@nightowlsdev/engine-eve";

console.log(EVE_ENGINE_CAPABILITIES.events.tier); // 2 — tool events + usage visible
console.log(EVE_ENGINE_CAPABILITIES.governance.costCaps); // false — remote owns it
console.log(EVE_ENGINE_CAPABILITIES.hitl.durableResume); // true (static — Vercel Workflows)

Doing the parts it doesn't support

  • Enforcing cost caps or a tool gate on the remoteYou can't — the Eve loop runs on the remote and owns generation, the tool gate, cost caps, and secrets. Use a native engine in-process for enforcement, or govern at Eve's own boundary.
  • Multi-agent delegation across the Eve boundaryAn Eve app is a single agent; delegation is false and subagent.called is a cosmetic status note only in v1. Compose multiple Eve agents at the swarm level, or use engine-mastra for real delegation.
  • A hard mid-stream cancelcancellation is between-steps — stopping the client stream doesn't abort the remote durable turn. Design for the remote to finish (or expose its own cancel) rather than relying on a mid-stream stop.

Related

  • coreThe required base — the adapter maps the Eve wire into core's SwarmEvent / ask loop and persists to core's event log.
  • engine-a2aThe other remote adapter — opaque tier-1, for A2A endpoints rather than an Eve app.
  • engine-trigger-chatA sibling tier-2 remote adapter, over a Trigger.dev chat.agent Session (experimental).
  • reactuseEngineCapabilities() reads EVE_ENGINE_CAPABILITIES to gate affordances the reduced-governance tier can't back.