github vercel/eve eve@0.69.0

one hour ago

Minor Changes

  • efa0869: ctx.agent(name) in a workflow tool now returns a session with that agent: send(message, { outputSchema, signal }) returns a response whose result() resolves the turn's { data, message, status }, and the parent stream announces each session with agent.started, carrying the opening call's callId and turnId, which session.agent(started).stream() follows. ctx.agent(name, { message, agentId }) is removed, sessions end when the workflow run finishes, and remote agents now check a protocol version, so upgrade both deployments together.

  • c8d38a8: Every agent tool is now a serve(receive, ctx) tool built on ctx.agent, so every subagent call is a resumable task: the call returns a receipt, the agent's reply arrives as a task result, and the model continues the same agent by passing taskId (replacing agentId) or stops its current turn with task_cancel. The subagent.called, subagent.started, subagent.event, and subagent.completed events, their hooks, the [Agents] note, and the AGENT_* errors are removed; clients, hooks, and evals read task.started, task.settled, and agent.started instead, and session.agent(started).stream() follows a child from its agent.started event. task.started carries kind: "agent" for an agent tool's call and "tool" otherwise, so t.calledSubagent also sees an agent call that failed before its session opened. The default message reducer behind useEveAgent() settles a task call's tool part from task.settled (output, error, or cancellation).

  • 7869f50: The Chat SDK bridge's send now takes a message plus channel send options, and a new respond(inputResponses, { thread }) answers pending input requests. To migrate, replace send({ message, context }, { thread }) with send(message, { context, thread }), and replace send({ inputResponses }, { thread }) with respond(inputResponses, { thread }). Channel send options also accept outputSchema, as Session.send() does.

    Telegram and Chat SDK inbound messages now go through the public channel send(), so route wrappers see them. A Telegram reply to a bot message that no session owns now starts a session instead of failing delivery.

  • c8d38a8: session.streamSubagent(started) is now session.agent(started).stream(). session.agent() takes an agent.started event and returns a ClientAgentSession handle with the child's name, sessionId, and taskId; eval sessions get the same session.agent(started).stream().

  • cc14b3d: Connection tools no longer break the prompt cache. The model finds them with connection_search and calls them with the new connection_execute tool, so discovered tools are no longer added to the model's tool list. Connection names now arrive in append-only context messages instead of the system prompt. connection_execute returns MCP structuredContent or text instead of the raw MCP envelope, and stream events report each call as a nested <connection>__<tool> action with a new parentCallId. The eve/tools/connection_search export is removed, and both tools are reserved names that cannot be replaced or disabled.

  • c8d38a8: When eve holds a turn because its tasks are still working, the stream now emits turn.waiting for that turn in every session, and session.waiting comes only after the turn really ends. In a root session, the model's text before the wait now completes as an ordinary "stop" message, so a person sees it right away. Child and schedule turns still report it as "tool-calls", so they post once. send().result() and MCP agent_get return the final reply, not the text written before the wait.

  • 1a5bc56: Approval response policies now run for Cancel as well as Approve (response.decision is "approve" | "cancel"), so a responder the policy rejects can no longer cancel someone else's request; a policy that only restricts approval should return { status: "allowed" } for cancel. The responder moved from responder to response.principal, alongside request.principal.

  • b34bab8: Extension configuration and durable state now belong to each logical mount, so duplicate mounts can use independent config and state. Session handoffs across this upgrade boundary are rejected in both directions, including for agents without extensions; keep each session's owning deployment available until it finishes, or start a new session on the deployment you want to use.

  • efa0869: Remove background tasks: workflow tools and subagent calls now always block the turn until they settle, defineWorkflowTool rejects execution, and taskDeliveryPolicy, the task_cancel tool, session.cancel({ tasks }), task receipts and notifications, and <eve-empty-delivery/> are gone. Extensions built against earlier capability epochs must be rebuilt.

  • c8d38a8: Workflow tools can define serve(receive, ctx) to run a resumable task: receive() resolves the call that started the task, then each later call the model makes with the task's taskId, and ctx.reply(output) delivers a result while the task stays available. eve adds an optional taskId to a serve tool's model input (the build fails if inputSchema declares its own), idle tasks don't hold the turn and are listed in the [Tasks] note, and task_cancel aborts the current work's abortSignal while the task stays available for its next call, as long as the body returns to receive() within 30 seconds. While the task serves a later call, ctx.session describes that call, with its turn and the auth it was admitted with, and ctx.agents lists the agents that call may open. A session opened with ctx.agent is the child in lineage and trace of the call served when it opens, and each message sent to it carries the auth of the call served when it's sent. The events a call causes, including task.settled, agent.started, and questions, carry its callId and turnId.

  • 9c36b7c: Slack now shows each turn's tasks in a live task card: one message, updated in place, with a row per task that shows whether it is working or waiting on a person, and how it ended. Slack also acknowledges a mention or DM with Thinking... right away, even with a custom onAppMention or onDirectMessage, and clears it if the hook drops the message. While a turn waits on its tasks, the status names them. Outside DMs and private channels, the card shows a failed task as Failed without its error text, and a blocked task without the request's prompt. Channels can now handle input.resolved to learn when each question or approval ends, however it ended.

    slackChannel({ events }) is replaced by renderers, which wrap eve's default rendering instead of replacing it; without renderers, eve renders with its default. Move events: { … } to renderers: [{ events: { … } }] and handlers behave as before; call the new next argument to keep eve's default; next also replaces input.requested's defaultDeliver. A renderer can also shape the task card with taskCard(view, next), whose view includes the turn's other tool calls and their input, so your own tools, such as a checklist, can appear on the card. The experimental activity option, the experimental_slackActivity* renderers, and the activity collector behind them are removed, along with the activityObserver field on delegated and remote-agent sessions; remote agents ignore it when an older caller still sends it.

  • c09c0d6: Slack task cards and typing indicators name work more clearly. A task the agent hands to its own copy shows its brief instead of agent: …. Row titles and results use the first sentence, and results are cut to about 100 characters at a word boundary. The typing indicator shows the same labels as the card and says Waiting on 3 tasks... instead of naming one task and counting the rest. The describeActionRequest and describeActionRequests exports from eve/channels/slack are removed. A renderer can call next() for eve's default status, or read presentation from actions.requested.

  • efa0869: A steering message now aborts the ctx.abortSignal of each execute workflow tool call the turn waits on, so a waited call stops early and settles with what its body returns, or { interrupted: true } if the body rejects. ctx.ask(request, { signal }) withdraws the question when the call's abortSignal or signal aborts, resolving as cancelled with an input.resolved outcome of "cancelled". sleep and ask_question now stop early for a new message, and dismissible and the dismissed status are removed: a question in an execute call lapses when the conversation moves on, and a question asked from a task stays open.

  • c8d38a8: A workflow tool now defines exactly one of execute(input, ctx) or task(input, ctx). A task tool runs each call as a task: the model gets a receipt at once, the result arrives later in a task.result message, the model waits with task_wait or stops a task with task_cancel, and a turn can't end while its tasks work. agentRouter() and the workflow tool now run as tasks. The stream reports task.started and task.settled with each call's turnId, turn.waiting while task_wait waits, and the taskId on agent.started for a session a task opens; task results are not published as message.received. session.cancel() also stops working tasks, and execution now fails with a pointer to task(). Authored tools can no longer be named task_wait or task_cancel. Consecutive queued messages from one principal now share a turn even when their auth claims changed, and the turn runs with the latest claims.

  • 315b353: eve dev --subagents now accepts full, collapsed, or hidden, and defaults to collapsed. auto-collapsed was removed because it rendered the same as collapsed; pass collapsed instead.

  • efa0869: A question or sign-in from inside a running call, such as a workflow tool's ctx.ask(), ask_question, or a subagent's question or connection sign-in, no longer ends the turn: the stream emits input.requested or authorization.required, then the new turn.waiting event, and the turn resumes under the same turnId. The session you answer on now emits input.resolved for every subagent or workflow tool question it routes an answer to, and send().result() stops at turn.waiting only while a question is pending. The message stream version is now 26, which older eve clients reject, so upgrade them with the server.

Patch Changes

  • 0ec0381: Channel activity, such as Slack, now shows each agent task or ctx.agent session as its own row under the call that opened it. The row settles as completed, failed, or cancelled when the agent's first turn ends, and a turn cancelled while it waits for an answer, including the caller's own, now settles as cancelled unless its own approval or sign-in can still be answered. Before, a local agent's activity merged into the caller's row and marked it done early, a remote agent's row stayed running until the caller's turn ended, and a later message to a remote agent, such as continuing its task by taskId, failed while activity was on. Later turns of the same session, such as a second send or a task continued by taskId, still appear under its first row.

  • c8d38a8: A message sent to an agent task by taskId just as the agent's turn ends now reaches the agent and gets the reply of the turn that read it. Before, the message could be settled with the earlier turn's reply without the agent ever seeing it, and a message sent just after a task_cancel could be left unanswered.

  • c8d38a8: Correcting an agent by taskId while it works now gets the agent's corrected reply, and a correction sent during the agent's first turn joins that turn instead of waiting for it to end. Before, a message the agent read only after its turn ended was answered with the earlier turn's reply, and the corrected reply was lost, which could leave the caller's turn waiting forever. The same applies to ctx.agent(name).send(): a response resolves with the result of the turn that read its message.

  • bbbf9fc: agent.started hooks keep the session state and sandbox changes they make. A child session that opens while the parent's model is generating appears on the parent stream when that model step ends.

  • c8d38a8: A ctx.agent turn that fails now reports why: result() returns error.message alongside status: "failed". Agent tasks and workflow program calls include that reason in their failure, so the parent sees the agent's error instead of "The agent's session ended."

  • 66f295e: Approved tools now execute correctly when memory recall and dynamic user instructions run during approval resume.

  • efa0869: A ctx.ask() question now resolves the way the session decided it: an answer that reached the session before its withdrawal resolves the ask as answered, even after the signal aborted, so ask_question and the channel never disagree. Cancelling a task() also reports its pending questions cancelled, and question requestIds are now <runId>-ask-<n> instead of an internal hook token.

  • a402836: authorization.required and authorization.completed events now include principalId, the session principal who started the sign-in, using the same value as responderPrincipalId on approval events. Candidate sign-in events also now include their attemptId.

  • e9dd418: Add an optional fallback model to auto model routing. When the evaluation model fails, eve now uses the configured fallback for the rest of the turn while preserving cancellation behavior.

  • c8d38a8: Cancelling a turn no longer erases the tool calls it was waiting on from the model's history. Each one stays, answered as cancelled, so in the next turn the model sees that the work was started and stopped instead of redoing a request that looks unanswered.

  • ce14b1e: defineChannel event handlers can now subscribe to step.completed, the same event hooks receive when a model step finishes.

  • cd3f263: Include channel kind and origin on agent step spans so traces can be classified while a turn is still running or waiting for input.

  • aa73bcb: Trace viewers now use the GenAI system-instructions attribute instead of recording a duplicate system prompt attribute.

  • 4902e93: The eve CLI now finishes writing stdout and stderr before it exits. A parent process that reads large output through a pipe, such as eve info --json for an agent with many tool schemas, now receives the complete output instead of output cut off partway through.

  • f0a9ee1: The Datadog reporter now records eval content by default and reuses one dataset across runs, so experiments can be compared in Datadog.

  • 47c2844: eve now defaults to openai/gpt-6-luna-fast with high reasoning when no model is configured, including newly initialized agents; explicit model and reasoning selections remain unchanged. The terminal UI shows compact model labels with dot-separated reasoning and a ⚡︎ speed marker in place of a trailing -fast suffix.

  • a9da46c: Delegated agents again share and count against the parent's session token and cost budgets: agent tasks started in the same model step split the parent's remaining quota, and delegated usage, including remote agents and nested subagents, counts toward the parent's maxInputTokensPerSession, maxOutputTokensPerSession, and maxTokenCostUsdPerSession and the usage the parent reports. An agent task's usage counts with each reply and when a cancelled turn ends; other workflow tools' ctx.agent usage counts when the tool replies or finishes.

  • 8149c72: The Braintrust and Datadog reporters now report one score per assertion name, the lowest, instead of numbering repeats like judge_boolean_2.

  • 4b195e9: Add eve/server, whose sessions.attach(sessionId).stream({ startIndex, follow, signal }) reads a session's durable event stream in process from hooks, tools, schedules, and channel routes, with the same shape as the client and no HTTP round trip.

  • 21e11d0: eve dev now reaches a ready server about 40% sooner. The bundled self-modification extension no longer re-bundles eve's internals for each module it loads, and dev builds no longer re-parse large output chunks. Installing eve also no longer reports npm audit advisories for undici, which is now 8.10.2.

  • e0dd11e: Fix imports of eve/extensions/code/sandbox from ES module consumers when bundled Connect dependencies include CommonJS code.

  • 0afae69: Restore completed-turn memory capture by providing memory providers with the settled conversation history.

  • f9c785f: When a target deployment cannot read the session checkpoint version, validation returns incompatibility instead of throwing so Workflow no longer retries the step. The turn is processed on the current owner immediately.

    Owners running this eve build remember every deployment that reported incompatibility and skip handoff to those targets for later turns in the same run. Sessions whose owner workflow started on an older build still attempt handoff each turn, but each attempt no longer triggers validation retries on the target.

  • 5181b14: Approval response policies now receive request.principal, the person whose turn requested the call, so a policy can let only that person approve it in a shared conversation. It is null when the caller was unauthenticated or anonymous.

  • 7869f50: Inbound Slack messages now go through the public from(address).send(), so a route wrapper that replaces send sees every inbound message and receives delivery failures as errors. Channel send() also forwards its state option to the deliver hook as payload.state on every delivery, as respond() already did.

  • 7869f50: eve info --json now includes toolInputSchemas: each static tool's input schema, for the root agent and each declared subagent, in the form eve sends to the model. Subagent entries are keyed by their path from the root agent, such as forecaster/reviewer, so nested subagents that share a name each get their own entry. eve/tools also exports serializeModelInputSchema(schema), which returns that JSON Schema for any tool input schema, so checks no longer need to read .eve/ build output.

  • 7869f50: eve/schedules now exports isScheduleAuth(auth), which returns true for the app principal that schedules pass as appAuth. Use it to tell the agent's own scheduled work from a user's turn without copying eve's internal principal values.

  • e6c90d0: Keep slash-command suggestions visible after a command name is fully typed, so the matching command and its description remain visible alongside any inline argument hint.

  • 7a33f37: Isolate extension module instances and configuration per logical mount, including directory overrides and their subagents, while preserving asset imports and extension-owned dependencies. Durable extension state still uses package-scoped keys.

  • 0e0fa1b: Record canonical logical mount identities in compiled extension metadata and contribution ownership. Flat and directory mounts share an identity, while mounts in different subagents retain distinct paths; this does not yet change extension configuration or state isolation.

  • c8d38a8: A serve task's ctx.reply() that answers several calls, such as an agent's reply to a message and its correction, now settles them together: task_wait no longer reports the task as both done and still working, and the model receives the reply once instead of once per call. Each call still gets its own task.settled event.

  • c8d38a8: A model response that mixes AI Gateway web_search results with local tool calls such as web_fetch no longer breaks the next model call. eve kept a local call ahead of a later search result, so Anthropic rejected the history with "tool_use ids were found without tool_result blocks" and the turn failed.

  • e0ad9a0: Agents using AI Gateway web search no longer claim on the next turn that they answered before searching. When a reply continues after a search result in the same model call, eve now stores that text as its own assistant message, so AI Gateway replays it after the result instead of before the search.

  • cd13d12: The initial eve dev composer now suggests concrete changes you can ask your agent to make, based on its instructions and capabilities. Fresh eve init agents get the customization hint even when scaffolded channels expose workflow webhook routes; agents with an added channel keep the minimal “Send a message…” placeholder.

  • 631122f: The eve dev terminal UI now hides Workflow SDK output such as [workflow-sdk] lines unless /loglevel all is on; the diagnostic log still records every line. eve also no longer warns with "Step execution already in flight in this process" when a queued step delivery loses a normal race with a new inline step.

  • 23dc0da: A remote agent on this release now serves callers on eve 0.66 through 0.68 instead of rejecting them with REMOTE_AGENT_PROTOCOL_MISMATCH, so you can upgrade remote agents before the deployments that call them. Those callers' turns, results, follow-ups, and resets work as before, and the remote agent's tool approvals and sign-in requests still reach the caller and accept its answers.

  • b0b975b: Remote subagents inherit the parent's human-input capability and forward questions and authorization requests through the parent channel, including concurrent workflow questions. Trusted remote receivers can read the replay-stable invocation operation ID in onMessage.

  • e005932: Traces no longer give each ctx.agent() call in a workflow tool its own agent.action caller span, and a workflow tool that calls agents stays an agent.action span instead of becoming invoke_workflow <tool> with gen_ai.workflow.name. Sessions opened with ctx.agent() now link to the calling tool's agent.action span, and their usage no longer appears on a separate caller span; it still counts toward the parent session's usage.

  • ba96305: Include provider-reported costUsd alongside token counts on terminal subagent action instrumentation events and spans.

  • 7e4ceb8: The self-modification registry_add tool no longer pauses for approval before installing an official registry item. It now refuses items that would replace the self-modification subagent's own mount, and search_registry hides them.

  • cd8fb87: The self-modification subagent no longer tries to install eve/self-modification when asked to change the agent's own instructions. To change the subagent's own model or reasoning, it now creates or edits agent/extensions/self-modification/extension.ts directly.

  • e167dd3: ctx.reply() in a serve workflow tool now withdraws the ctx.ask() questions still pending for the calls it settles, so they resolve as cancelled and channels stop offering them. Before, such a question stayed pending after its call had a result: it kept steering from interrupting a model step and could take the person's next plain message as its answer.

  • 99b4166: Session workflow steps now return only the session state they changed, and the workflow applies that change to the state it passed in. Each step used to return a full copy of the session, so stored step output and the data a workflow replay reads grew with conversation length on every step; they now grow only with what each step changes.

  • 138e3b1: The Shopify integration setup now scaffolds a UCP agent profile for protocol version 2026-08-25, with spec and schema declared on every capability.

  • 8d6cd3e: Slack now sends sign-in challenges and approval feedback privately to the Slack user behind the event's principal, not to whoever spoke last in the thread. Channel state replaces approvalResponderUsers and pendingApprovalCandidateUsers with a single slackUsersByPrincipal map.

  • 7869f50: eve/channels/slack now exports renderInputRequestBlocks, deriveHitlResponse, and HITL_ACTION_PREFIX, with the SlackHitlAction, DerivedHitlResponse, and SlackHitlRoute types. Apps can render eve's HITL Block Kit controls and decode clicks on them without importing from eve's build output.

  • 79fa2aa: task.settled for a cancelled call now carries cancel.reason: "task_cancel" when the model called task_cancel, "turn_cancelled" when someone cancelled the turn, or "turn_ended" when the turn ended while the task still worked. The Slack task card uses it: a task the model cancelled now shows a success check and Stopped early since it was no longer needed, and other stopped tasks say why, such as Stopped by request or Stopped when the turn ended.

  • ce19751: The Slack task card now shows how long each task took, as in Done in 1m 14s: Found three incidents. or Failed after 3m, and the finished plan title includes the turn's total time. A plan whose tasks are all subagent or remote agent calls names them, as in Asking researcher and reviewer or Waiting on reviewer · 1 of 2 tasks done. The card also keeps one block_id for the whole turn, so rows a reader expanded can stay open as the card updates. When a turn you keep messaging starts new tasks after its earlier ones settled, eve marks the earlier card finished and posts a new card instead of updating the old one further up the thread.

  • 47c2844: Clarify that task_wait should be called sparingly, only to deliberately withhold a user-facing reply while waiting for a task result. Tasks keep running and their results reach the model without an explicit wait.

  • 7869f50: Spreading a channel into a new object with replaced routes, such as { ...slackChannel(), routes }, now keeps its build metadata, so the Slack app manifest and Vercel Connect credentials still reach the build. The custom channels docs now describe wrapping an existing channel's routes as supported.

  • e5d45dd: A message that steers a turn right after a tool call, such as a question sent while a task works, now gets answered on Anthropic models. Before, the message reached the model in the same turn as the tool results, and Claude often treated it as tool output and kept waiting on its tasks without replying.

  • e0ad9a0: A message that interrupts a waiting tool call, such as a sleep or task_wait, no longer also interrupts the step that reads it. The stream no longer emits a stray step.started with no model call before the step that answers the message.

  • c8d38a8: Channel activity, such as Slack's activity message, now shows a call to a task as running from its receipt until the task settles, then marks it completed, failed, or cancelled. Before, the receipt marked the call done as soon as the task started.

  • c8d38a8: The task system prompt now tells the model it can reply before a task's result when it doesn't need the result yet. Its turn stays open and it gets the result when the task finishes, so a person who says there's no rush gets a reply right away. A question asked while tasks work is now answered before the model waits again.

  • 67ae5b5: A question or approval that a task run or workflow tool call relays, from its own ctx.ask() or from a session it opened with ctx.agent, now emits input.resolved with outcome: "cancelled" when that run finishes before anyone answers. Every question or approval a session relays does the same when the turn is cancelled. Previously these requests were dropped silently or left in place, so channels and useEveAgent UIs kept offering them even though no answer could reach anyone.

  • 7869f50: task.settled events now carry the task's tool name and kind, the same values as on the call's task.started, so clients and hooks can label a settled task without tracking its start. Events recorded by earlier versions omit both fields.

  • ce14b1e: Models now get clearer task guidance: call task_wait when there's nothing to say until a result arrives, reply when the person should hear something first, and in child and schedule sessions wait instead of replying. task_wait takes timeoutSeconds instead of timeout in milliseconds, task_cancel answers in plain text, and receipts and failed agent results tell the model what happens next.

  • 50afc41: Allow eve remote info to inspect deployments that report retired kernel-effect options, marking those options as unrecognized instead of rejecting the agent-info response.

  • ed2c04b: ToolContext now exposes messages, the model input for the step that requested the call, so tools can evaluate the conversation that led to them without recording it separately. It matches the ctx.messages dynamic resolvers receive at step.started.

  • 5a5561a: Tools can now end a turn without a reply. Set endsTurn: true on a defineTool tool whose action is the whole answer, such as a reaction: once every call in the model's step succeeds, the turn completes with no final message, so channels and schedule sends post nothing. With true, eve appends a sentence to the tool's model-facing description saying the call ends the turn; pass a function instead to decide from the execute output. The new opt-in no_reply tool (eve add tool/no_reply, or noReply() from eve/tools/no_reply) uses it to let the agent stay quiet, for example when a scheduled check finds nothing to report. Slack now clears its thread status when a turn completes.

  • f442363: System instructions now remain available in traces when JSON encoding would otherwise push them over the span attribute size limit.

  • d09e381: The eve dev TUI now labels the self-modification subagent as agent editor instead of its raw tool name, self-modification__agent, and the turn bar reads "Modifying your agent" while it works.

  • 315b353: The eve dev terminal UI now shows each task, such as a subagent call, as one line when it starts and one when it finishes, fails, or is stopped, with a panel above the prompt showing what every working task is doing. The transcript no longer jumps or rewrites while tasks work, the model's own task_wait and task_cancel calls no longer appear in the terminal UI or Slack typing indicators, and tools with a label show it instead of their raw arguments.

  • e0ad9a0: The eve dev terminal UI now shows text the model writes after a provider-executed tool such as web search in the same model call. Before, the answer after a search was dropped from the transcript even though the agent sent it.

  • bb70743: Workflow tools now wait for approval before starting, and calls denied by a person or policy never run. An approved workflow starts when it is approved.

  • efa0869: A workflow tool's action.partial updates now reach the channel adapter, stream-event hooks, and instrumentation, like the events a turn publishes, and the input.resolved a session emits when a question raised inside a call is answered or withdrawn now reaches the channel adapter and stream-event hooks. Both were previously written only to the session stream.

Don't miss a new eve release

NewReleases is sending notifications on new releases.