Skip to content

eve@1.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 15 Nov 22:02
· 5 commits to main since this release
bde2452

Released 2026-11-15 · Compare with 0.91.0

Breaking Changes

  • Replace agentWithModel with agent({ models }) from eve/tools/agent, which lists the models a root-copy task may run on.
    agentWithModel let the model pass any AI Gateway model ID and did not tell it which models exist. agent({ models }) takes the same entries as auto() from eve/models: a string entry is the description, and its key is the AI Gateway model ID; an object entry holds an AI Gateway model ID or an AI SDK model, with its description and optional reasoning, modelContextWindowTokens, and modelOptions. The model sees each key with its description and can choose only those keys. A call without model runs on the current model, and agent() with no models is the default tool, with no model input. A task keeps the model it started with, so a continuation can omit model. Copies and declared subagents never get this tool.
    To migrate, replace export { agentWithModel as default } from "eve/tools/agent" with export default agent({ models: { "<gateway-model-id>": "<when to use it>" } }). agent is now this function; re-export default from eve/tools/agent to keep the default tool object. (#5959)
  • Every agent now gets a default edit_file tool, the code extension drops code__apply_patch, and bash results and eve's system prompt now match pi's.
    edit_file, exported from eve/tools/edit_file, edits one sandbox file with exact text replacements matched the same way as pi's edit tool. The model sends path and a list of { oldText, newText } edits, each matched once against the original file, with a fallback that ignores trailing whitespace and normalizes smart quotes, dashes, and special spaces. Files that are not valid UTF-8 are rejected rather than rewritten, and a file keeps its mode, such as its executable bit, on sandboxes that write files with a default mode. Remove it with defaultTools: false or an agent/tools/edit_file.ts that exports disableTool(); an authored agent/tools/edit_file.ts replaces it.
    edit_file changes existing files without write_file. If you disabled or wrapped write_file to limit writes, or gate write_file in an approval policy, do the same for edit_file. write_file can also overwrite a file the session read and then changed with edit_file, without another read_file call. A change made by anything else since the read still requires one.
    The code extension (eve/extensions/code) no longer mounts code__apply_patch, and the eve/extensions/code/tools entry point is removed. Import grep from eve/tools/grep instead of eve/extensions/code/tools. Move an override of the old tool, whether agent/tools/code__apply_patch.ts or agent/extensions/code/tools/apply_patch.ts, to agent/tools/edit_file.ts and spread editFile from eve/tools/edit_file. edit_file takes path and edits instead of a patch, so a wrapper that reads input.patch needs updating. A code__apply_patch.ts file that exports disableTool() fails eve build with disables a slot with no lower-precedence source; to keep agents from editing, export disableTool() from agent/tools/edit_file.ts instead.
    installCodeTooling() no longer installs TypeScript or the post-edit diagnostics worker, and CODE_TOOLING_REVALIDATION_KEY changed, so sandbox templates keyed on it rebuild once.
    The code extension adds the workspace root's AGENTS.md, or CLAUDE.md when there is none, to the conversation, and its coding instructions now follow pi's tool guidance. The extension reads the file once per session, with one sandbox command on the first turn, which starts the sandbox. A file over 64,000 bytes is cut off with a note that tells the model where to read the rest.
    A successful bash command shows only its output, or (no output), and a command that exits non-zero ends with [exit code: N] and reaches the model as an error result. bash waits 60 seconds by default before it leaves a command running in the background, and a truncated stdout or stderr now names a file in the sandbox that holds its full output.
    toolOutput.errorText(value) from eve/tools, or a { type: "error-text", value } literal, lets any tool's toModelOutput show the model a failure while the call still completes, so channels and hooks get the full output on call.settled. The MCP channel returns such a result as its text with isError: true.
    eve no longer adds a "Tool execution" note about parallel tool calls to every agent's system prompt. Tool calls in one response still run in parallel. Without the note, Sonnet 5.5 solved a concurrency task in 93% of replayed eve-code runs instead of 75%, matching how pi, which runs tool calls in parallel without telling the model, performs.
    Thanks @badlogic for pi, whose MIT-licensed edit tool edit_file adapts. (#5892)
  • eve 1.0 puts stable APIs under semantic versioning: they change incompatibly only in a major release, and a deprecated API keeps working until the next one.
    The stability policy lists which APIs are stable and which are experimental. To move an existing project, follow Upgrade to 1.0. (#5620)
  • The code extension (eve/extensions/code) no longer mounts its code__grep tool, which removes about 1.6K characters of tool schema from every model step.
    To keep a structured search tool, run eve add tool/grep, which writes agent/tools/grep.ts re-exporting eve/tools/grep. eve/extensions/code/tools still exports the same grep definition. Delete an agent/tools/code__grep.ts file that exports disableTool(), because eve build now rejects it with disables a slot with no lower-precedence source. An agent/tools/code__grep.ts override that spreads grep keeps working as your own tool named code__grep. (#5815)
  • The code extension (eve/extensions/code) no longer adds the read-only code__worker subagent, and code() rejects the worker option.
    To migrate, remove worker from your code() mount and delegate with the built-in agent tool. If an agent/tools/agent.ts override disables agent so delegation goes to code__worker, delete the override. A mount that still passes worker fails with Invalid extension config: eve-code no longer ships a worker subagent; delegate with the built-in `agent` tool and remove the `worker` option.
    The code__review skill starts a fresh-context agent with a no-edit audit brief when one is available and otherwise audits in the current session. The code__lookup-agent-run skill and the internal eve/internal/code/prwatch export are removed. (#5800)
  • A dynamic tool no longer replaces a static tool of the same name: the static tool keeps the name and eve logs an error, as it already did for two dynamic tools with the same name.
    To change a tool for some sessions only, define it only in a dynamic file that returns the usual version to the other sessions.
    Agents whose only tools are dynamic now get the parallel-calls note in their system prompt, and the $eve.tool_count span attribute counts the tools offered to the model rather than the tools the agent declares. (#5638)
  • New sessions now claim an address as they start, so racing first messages to a channel address reach one session, keyed sends and create() respond without waiting for the session to boot, and a session accepts commands as soon as it is created.
    Previously, two unkeyed first messages to the same new address could each get a receipt naming a different session: the losing run forwarded its message and exited, but its caller kept the dead session's ID. A cancel or end() sent by session ID before the session finished booting was answered with "no active turn" or "no active session" while the session kept running, and an early send had to retry 409 session_not_ready. A send by session ID to a session that is shutting down now gets 409 session_not_active at once instead of session_not_ready retries.
    eve now requires a Workflow world with atomic start hooks: the local world, Vercel Workflow, or @workflow/world-postgres 5.1.1 or later. On another world, starting a session fails with an error that names the requirement. Upgrade @workflow/world-postgres and run its bootstrap command before deploying this release.
    A session can no longer move to this release from a deployment on eve 0.81.0 or earlier, which released its addresses before handing off. Finish or end those sessions before upgrading.
    useEveAgent and the other framework bindings now send end(), clear(), and compact() called while the store is still creating its session to that session, instead of throwing SessionNotActiveError. (#5948)

Features

  • Agents can now be published as Agent2Agent (A2A) v1.0 servers with a2aChannel from eve/channels/a2a, so other agents can discover them from an Agent Card and delegate durable, streaming tasks over JSON-RPC. (#5693)
  • Set approval in agent.ts to gate every tool, connection, and subagent call from one policy.
    The agent's policy runs beside each entry's own approval and the stricter result wins, so it can add a gate but never remove one. Subagent sessions inherit the root agent's policy. Thanks @kingztech2019 and @taoufik-ia for the proposals in #145 and #2673. (#5793)
  • Record an agent.approval span for every wait on a person, including questions, budget prompts, and connection sign-ins, not just tool approvals.
    agent.approval.kind is tool-approval, question, budget, or sign-in. A wait sits under the tool call it's about, or under the turn when no call owns it, and a sign-in names its connection in eve.connection.name. Instrumentation providers now receive sign-ins on interaction.opened and interaction.settled, with signIn.name naming the connection or tool; the sign-in URL and code stay out of the event. Questions and sign-ins from workflow tools such as ask_question now reach providers too, reported by the session that owns the tool call; a request a subagent asks is still reported once, by that session. @vercel/agent-runs adds TurnOperation.approval and findApproval, and an optional kind and connectionName on approvals. (#6004)
  • Preselect an option in a display: "select" question by passing initialOptionId to ctx.ask.
    Slack, Discord, Microsoft Teams, and the eve dev terminal UI start with that option selected, and ACP clients receive it as the form field's default. On Slack and Discord, a Use button submits the preselected option, because those platforms send nothing when a person keeps the current selection. When initialOptionId matches none of the question's options, ctx.ask throws a TypeError. (#6202)
  • The provided bash tool accepts an optional timeout in seconds, so the model can wait up to 120 seconds for a build or test suite before the command keeps running in the background.
    Calls without timeout still wait 30 seconds. Values above 120 wait 120 seconds, and values below 1 wait 1 second. A command still running after the wait returns status: "running" as before. (#5813)
  • mcpChannel accepts a plainHttp option for plain HTTP requests from a TLS-terminating proxy or a private network, which were otherwise refused off loopback. (#5700)
  • Add ctx.conversation.space, which names the place a conversation happens, such as a Slack channel, so tools, approval policies, dynamic values, and memory scopes can share data per place.
    Slack, Discord, Teams, Telegram, Linq, Photon, and Chat SDK channels report a space with a stable id namespaced by platform and workspace, a type of direct or shared, a visibility of public or private when the platform says, and a workspaceId where the platform has one. Custom channels report theirs with a new space({ state }) hook beside audience. Tools and memory scope resolvers can now read ctx.conversation, which dynamic values already had. (#6111)
  • Add the experimental eve/experimental/extensions/custom-skills extension, which lets the people talking to an agent save their own versioned skills, for themselves or shared with everyone in a channel or group chat.
    Each skill has immutable versions and one live version, with drafts, publish and rollback, and always, on-demand, or deferred application modes saved per version. A validator and an approval rule you can replace decide which descriptions and instructions are accepted and which changes run, ask a person, or are refused, and the approval card shows the content that would go live. Shared skills follow the conversation's ctx.conversation.space on Slack, Discord, Teams, Telegram, and Chat SDK channels. Every skill has a stable ID beside its name. Skills are stored in any eve/memory/file document backend, Vercel Blob by default, in a documented, versioned layout whose index lists every scope for admin views, or in your own SkillRepository from eve/experimental/extensions/custom-skills/repository; eve/experimental/extensions/custom-skills/policies exports the built-in scopes, validator, and approval rule to compose your own. (#6106)
  • Dynamic schedules' auth and run callbacks receive a schedule handle that disables or deletes the schedule that fired, and auth can return only { attributes } to run as the stored creator.
    An auth that returns null now fails the occurrence permanently: on Vercel the occurrence is acknowledged without redelivery and occurrence.failed fires once, instead of after ten deliveries. The same applies when auth returns a principal other than the creator or a value of another shape. An error that auth throws is still retried. If your auth turns a failed lookup into null, make it throw instead, or an outage will fail occurrences without a retry.
    The handle and the auth result are exported as ScheduleHandle and ScheduleAuthResult. (#6211)
  • A dynamic schedule's run no longer starts its sessions again when the provider retries an occurrence.
    A to().send() without an idempotencyKey now takes one from the occurrence and the message, so the retry reaches the session the first attempt started. Before, each retry started another session unless run passed its own key. A message that differs between attempts still starts another session; pass an idempotencyKey to keep it to one. (#6358)
  • Add an optional id to the experimental defineDynamicSchedules, so a schedule collection keeps its stored schedules when its file is renamed or moved.
    Without id, the collection's name still comes from its path under agent/schedules/. To move a collection, set id to its old path-derived name. A collection that a mounted extension contributes uses its id as written, without the mount prefix.
    eve build now fails when two collections, or a collection and a static schedule, in one agent resolve to the same name. A tool file that replaces or disables a collection's tools is named for the resolved name, agent/tools/schedule__<name>.ts. (#6212)
  • A dynamic schedules definition can declare named scopes, for one kind of schedule with more than one owner.
    scopes takes the place of scope. The definition still offers one set of management tools, and each tool takes a scope input that names the scope to act in. A scope can set its own description, preparePayload, run, and approval, and an id that keeps the schedules an earlier definition stored. schedules(definition, { scope }) binds one scope from code. A definition with a single scope is unchanged. (#6360)
  • A dynamic schedule's preparePayload receives the schedule's timing as context.expression.
    It is the timing the caller passed, or the stored timing when an update replaces only the payload, so preparePayload can tell a recurring schedule from a one-time one without a payload field for it. (#6359)
  • Clarify the experimental dynamic schedules types and error messages, and deprecate the top-level identity fields of ScheduleOccurrenceEvent in favor of occurrence.
    The scope and preparePayload contexts are now exported as ScheduleScopeResolverContext and SchedulePreparePayloadContext. No fields were removed and runtime behavior is unchanged. (#6213)
  • Dynamic schedules reject a cron expression that Vercel Schedules can't run before the write is prepared, so a model's call fails before a person is asked to approve it.
    Vercel Schedules takes numeric fields only, and not both a day of the month and a day of the week. An expression that breaks these rules, such as one with MON or JAN, now fails with an error that says how to write it. eve dev applies the same rules. A custom ScheduleProvider can implement the optional validateExpression to check timing the same way. (#6357)
  • defineDynamic() in agent/tools/ can return a defineWorkflowTool() held by a top-level const, so a workflow tool can be offered only on some model calls.
    Its entry point can be written inline or reference a top-level "use workflow" function. The build fails when a workflow tool's entry point lacks "use workflow" or the tool is created inside the dynamic function. (#6235)
  • Add the eveVite() plugin from eve/vite to run eve agents alongside any Vite app in development, vite preview, and Vercel deployments.
    eveSvelteKit(), eveTanStack(), and the Nuxt module now share its agent discovery and Vercel services, so all of them mount agents/ workspace members at /eve/<name>/v1/*. The SvelteKit plugin no longer sets EVE_BASE_URL in the dev server process; set it yourself if your server code reads it to reach the agent. On non-Vercel hosts, the Nuxt module proxies each workspace member to its own local server on consecutive ports from EVE_NUXT_PRODUCTION_PORT (default 4274), or to /eve/<name>/v1 on EVE_NUXT_PRODUCTION_ORIGIN when set. (#6097)
  • eve/events exports createStreamChecker, which checks a stored session stream against its lifecycle rules.
    Run it over a stored or recorded stream to find lines that break the lifecycle rules, such as a turn that settles twice or a fact that names something never introduced. Its StreamChecker, Violation, and ViolationRule types, and the StoredLine, CommitLine, and ProgressLine types it reads, are exported beside it. (#5834)
  • Add optional IANA timezones to fixed schedules so jobs can keep a local time across daylight saving changes.
    Set timezone in defineSchedule or Markdown frontmatter on Vercel and self-hosted Node servers. Omitting it preserves the host's existing behavior. Other Nitro presets reject explicit timezones. (#6311)
  • executeGitHubShell now throws GitHubCommandInputError when a command's own input is refused, so a custom GitHub tool can tell the agent's mistakes from real failures.
    Shell syntax, an invalid repository, a workingDirectory outside the workspace, a gh-signed-commit directory that is not a repository root, and a missing --body-file used to throw a plain Error, like a missing configuration or an empty Connect token. Detect the new error with isGitHubCommandInputError(error) from eve/extensions/git/sandbox; its messages are unchanged. (#6181)
  • Add label: false to keep a tool's calls out of activity, such as emoji reactions.
    Channels show no status for these calls, and a call doesn't end a quiet turn's silence, so a deferred Slack turn that only reacts and ends with no_reply stays silent. The call's capability and its message part from eve/react, eve/vue, and eve/svelte carry hidden: true, and showsActivity(call) from eve/events applies the same rule in custom renderers. (#6017)
  • Add Slack's action_token to defaultSlackAuth as the action_token attribute, so tools can call the Real-time Search API without channel code.
    eve also exposes the token as message.actionToken, read from the top level of the event or from assistant_thread, where Slack sends it in app threads. (#6088)
  • Slack tool approvals now render as one card that holds the prompt, the tool input, and the Approve and Deny buttons.
    The card replaces the separate approval card and collapsed Tool input block. It lists up to 10 top-level input fields within a fixed size budget, and a batch of large approvals splits across messages, so a click's callback stays bounded however large the input is. Approvals without input keep the compact card. An answered approval keeps its input preview as a record of what was approved, where eve used to delete the separate tool-input message when the request ended.
    If you call renderInteractionBlocks from eve/channels/slack, an approval with tool input now returns one container block whose child_blocks hold the input preview and an actions block, instead of a card with actions followed by a Tool input container. Code that reads actions or stamps block_ids on interactive blocks should also look inside child_blocks. (#6271)
  • Slack's approvalChannel accepts "ephemeral" to show an approval or ctx.ask() question only to the person who started the turn, in the thread.
    Everyone else sees a Waiting on note naming that person, which shows the outcome once the request ends. The card needs only the chat:write scope and keeps the conversation in the thread, unlike "direct-message". A click replaces the card with the answer, because Slack can't edit an ephemeral message later. (#6270)
  • Slack sends a person's edit to a message the agent serves to that thread's session, as a <slack_message_edit> with a diff of the changed lines and the full edited text, and slackChannel({ onMessageEdited }) decides which edits reach the agent.
    An edit follows the channel's turnPolicy like any message: by default it joins a running turn, and if the agent already replied, it starts a new turn, which shows no thread status until its first tool call finishes; add the no_reply tool so the agent can stay quiet when an edit changes nothing. By default, eve sends edits to DMs, code channel messages, and messages that mention the agent before or after the edit. With an authored onAppMention, onDirectMessage, or onMessage, edits need their own onMessageEdited, so they can't skip those hooks' checks; until then they go to onEvent or are dropped.
    The generated Slack app manifest now subscribes to the message.channels, message.groups, message.im, and message.mpim events and adds the channels:history, groups:history, im:history, and mpim:history scopes, which Slack requires to send edits. Reinstall the Slack app to grant them. With these events, the default handler also answers DMs without extra setup, and an authored onEvent receives every message event in channels the app has joined. (#5796)
  • Slack message hooks can return status: "deferred" to keep a message's turn quiet until a tool call finishes, and guidance to tell the model how to treat that one message, so an agent can follow a thread and stay silent with no_reply when a reply isn't meant for it.
    status: "deferred" skips the received acknowledgement. Mentions and DMs outside code channels get that acknowledgement before their hook runs, so for them it keeps only the rest of the turn quiet. A message that isn't deferred and joins the turn shows the status again. eve adds guidance as a <guidance> block inside the message's <slack_message> or <slack_message_edit> block, after the metadata and before the content. The Slack docs show how to follow threads the agent already serves with onMessage.
    Message edits now go through an app's own message hooks. Without an authored onMessageEdited, an edit goes to the hook a new message of the same kind would reach: onDirectMessage, then onMessage, for DMs; onAppMention, then onMessage, for messages that mention the agent; onMessage, then onAppMention, in code channels; and onMessage for other messages. Without those hooks, the built-in defaults send edits to DMs, code channel messages, and messages that mention the agent before or after the edit, and drop the rest. Edits are always quiet and ignore status, and an authored onEvent still comes before this default. The new ctx.edit is set while a hook decides an edit.
    In 1.0.0-rc.2, an authored onAppMention, onDirectMessage, or onMessage turned off edits unless the app also defined onMessageEdited. Those hooks now also run for edits in threads that have a session. If a hook has side effects, such as ctx.send(), ctx.end(), or a decision model call, return early when ctx.edit is set. To keep edits off, define onMessageEdited and return null. (#5801)
  • Slack renderers can handle call.input to show a tool call's arguments while the model is still writing them.
    This lets a renderer post a draft of what a call will produce, such as a card, and edit it as the arguments stream in. eve's default rendering ignores call.input, so existing channels behave the same. (#6112)
  • Agents deployed to Vercel, including agents added to an app with withEve, now run schedules with Vercel Schedules through a private function instead of Vercel Cron Jobs.
    Each Vercel schedule is named after its file, such as eve.billing.sweep for schedules/billing/sweep.ts, and withEve agents add the agent's name, such as eve.billing.heartbeat. Building a withEve project requires Vercel CLI 65.14.0 or later. (#6087)
  • defineWorkflowTool tools with an execute entry point now accept endsTurn, so a workflow that waits for the user can end the turn without a model reply.
    Pass true, or a function that receives the call's output. task and serve entry points still reject it.
    Thanks @matchai for requesting this, and @xcscxr for the implementation plan in #5337. (#6336)
  • Add the Tavily MCP integration to the registry, so eve add connection/tavily connects web search, extraction, crawling, and URL mapping through Vercel Connect OAuth. (#5731)
  • The provided bash tool shows the model its output as plain text instead of JSON, so source code, diffs, and test logs reach the model without escaped newlines and quotes.
    The model reads stdout, then any stderr after a [stderr] line, then a final [exit code: N] line; for a command still running, its instructions replace the exit code line. The tool's execute output, its output schema, and call.settled events keep the structured fields. Authored code that reads the conversation, through ctx.messages in tools or ctx.messages() in dynamic capabilities, sees this text for new bash results, and sessions keep the JSON results they already saved. A bash tool published over MCP sends the text in content[0].text, and its structuredContent keeps the structured fields. Wrappers that spread bash keep the plain-text view: a wrapper's execute that returns a string reaches the model as text, and any other shape as JSON. (#5822)
  • Custom channels can answer pending approvals and questions from typed text, as eve's own channels do.
    Pass answerText to send() when the model reads a wrapped message, such as one with a speaker prefix, and show the request a reply answers with nextPrompt(view) from eve/events. (#5861)
  • auto() from eve/models and eve/tools/approval accept modelOptions.providerOptions, and decide() accepts providerOptions, so decision calls can set options such as AI Gateway's zeroDataRetention. (#5846)
  • Decision spans now name their turn and purpose, and record per-question results as gen_ai.decision.results when the trace records outputs.
    decision <model> spans carry agent.turn.id and agent.decision.purpose (model-selection, tool-approval, agent-routing, or custom), so Agent Runs can place a model-selection decision in a turn that is still running. Results follow the proposed OpenTelemetry GenAI decision conventions: choices, predicates, scores with their levels, and refusals, each keyed by the question's position. They are output content, recorded only when outputs are and dropped for any destination that declines outputs. AgentRun.decision accepts an optional purpose, and completing a decision with output records it as the results. (#6389)
  • Deployed agents start faster and use less memory, because hosted builds now include each installed package once instead of once per instrumentation file and once more for the agent's modules.
    Before, when instrumentation files imported the same packages as the agent, every one of those packages shipped, loaded, and ran more than once on each cold start. In one production agent with five instrumentation files, the workflow route's bundle dropped from 34 MB to 22 MB and its cold start from about 2.6 s to about 1.8 s. (#5943)
  • Start eve commands faster by enabling Node's on-disk compile cache for the CLI process. (#6423)
  • Make eve dev agents ready sooner by loading eve's vendored dependencies from its install instead of bundling them into every development host. (#6434)
  • Start eve commands and eve dev agents faster by resolving eve's internal imports directly instead of through Node's package.json lookup. (#6424)
  • Show the eve dev prompt sooner by loading only the startup draft's modules before the first paint. (#6433)
  • Make the eve dev agent answer its first request sooner by loading the published generation in the worker as soon as the server starts. (#6442)
  • Dynamic functions can read the session's sandbox with ctx.getSandbox(), the same handle tools and hooks get.
    eve runs dynamic functions before every model call, so read the sandbox inside ctx.memo, keyed on what would change the files, such as the latest checkout call in ctx.view. ctx.getSandbox() isn't available while choosing the model. (#5802)
  • Explain more prominently that defineDynamic functions run before every model call, so network requests, database queries, API calls, and sandbox reads belong inside ctx.memo. (#6278)
  • Add EVE_EVAL_OIDC_TOKEN to reach a protected Vercel deployment from eve eval --url through Trusted Sources. (#4894)
  • The code extension (eve/extensions/code) sends a prompt about a third of its previous size (4,942 to 1,636 characters) that keeps only coding and safety rules, so agents spend fewer tokens on every step.
    The prompt no longer assumes a chat product or sets consumer policy, such as brevity, asking one question, avoiding em dashes, omitting private references, or not rebasing. Agents that relied on those rules should state them in their own agent/instructions.md. Agents publish or write to external systems only when the requester asks for it or for an outcome that requires it, such as a pull request. The prompt asks agents to edit files with the editing tool instead of the shell, and no longer names apply_patch specifically. The issue and design checklists moved into the code__investigate skill. (#5805)
  • A new root session starts its first turn sooner: the workflow creates its initial state directly instead of in a separate durable step. (#6421)
  • A turn reuses the cancellation and steering controls an earlier turn left unaborted, so a message that arrives right after a turn no longer waits for new abort hooks. (#6420)
  • A followed session stream opens alongside its session check instead of after it, so its first lines arrive sooner. (#6418)
  • Session stream reads skip the earlier-eve version check for sessions the server created or already found current, so they start sooner. (#6417)
  • A turn settles without waiting for its model usage run attributes, which are now written behind it. (#6419)
  • Bundle the server faster in eve build and eve dev by resolving dependency imports and CommonJS path globals inside Rolldown instead of eve's JavaScript plugin hooks.
    eve build also no longer repeats the authored module builds after sandbox prewarm. (#6209)
  • Anthropic models on AI Gateway now cache the system prompt across sessions, and can cache it for 1 hour.
    eve adds gateway.cacheAnchorMessageIndex: 0 next to caching: "auto", so a resumed session whose cache expired reads the shared system prompt from cache instead of writing it again. An authored cacheAnchorMessageIndex, or caching set to anything other than "auto", is left as it is.
    On Anthropic models, eve now sends the base part of the system prompt as its own system message with the cache breakpoint, and the sections that differ by session (dynamic instructions, tasks and approvals) after it. Sessions with different channel or user instructions no longer write the shared base again.
    modelOptions.promptCache.anthropic.ttl: "1h" now also applies to Anthropic models through Gateway. eve then turns Gateway's automatic caching off, because Gateway ignores a 1-hour TTL under it, and places its own breakpoints for 1 hour, as it does on a directly called model. The default stays 5m. (#6151)
  • Add github.permissions to the git extension's "app" config. eve mints each installation token with only those permissions, so a broker no longer has to re-mint a narrower token and rebuild the credential header for every GitHub host eve leases. (#5966)
  • Each wait for a gh command's sandbox credential lock is recorded as an agent.github.lease.wait span, with agent.github.lease.outcome and agent.github.lease.attempts. (#6196)
  • New projects' AGENTS.md and the coding-agent setup prompt now point to guidance on keeping the deployed bundle small and cold starts fast. (#6079)
  • Hosted agents start faster: the bundled manifest is checked when the agent is built instead of on every cold start, the workflow driver code ships as plain text without an inline source map in production builds, and error-message formatters are created only when an error needs them. (#6047)
  • Chat SDK, Discord, Telegram, and Teams now say who answered a question or approval when they edit its prompt, as Slack already does: Approved by Alice or Answered by Alice: Saturday.
    Each channel records the person behind a principal when that principal sends a message or presses a button, then names them from the settlement's responder. Discord shows a mention, which doesn't notify anyone because the edit allows no mentions. Teams already named who pressed Approve; it now also names people who approve by text or answer questions. A prompt withdrawn without an answer, or answered by someone the channel never saw, reads as before. (#6110)
  • Speed up eve build and eve dev by parsing each workflow source once and, when eve is installed, reusing eve's own workflow driver bundle across builds. (#6215)
  • Removed the Build an Agent tutorial from the docs, and the link to it from the README that eve init writes; the old tutorial URLs redirect to the matching guides. (#5717)
  • Publish ghcr.io/vercel/eve-git, eve's default sandbox image plus the GitHub CLI (gh), and the same image to Vercel Container Registry as vcr.vercel.com/vercel/eve/git.
    Each eve release pins one tag of it, exported as DEFAULT_EVE_GIT_SANDBOX_IMAGE from eve/sandbox/docker and VERCEL_EVE_GIT_SANDBOX_IMAGE from eve/sandbox/vercel, and both from eve/extensions/git/sandbox, and latest moves to the tag of the released eve package.
    Pass the constant as image so installCodeTooling from eve/extensions/code/sandbox finds gh and skips its apt-get install, which takes about 7 seconds of a first build. A Vercel Sandbox session from a prepared snapshot of the eve-git image runs no base setup command, like the default image. The default image is unchanged. (#6246)
  • eve now targets Node.js 26: new projects pin engines.node and @types/node to 26.x, so Vercel deploys them on the nodejs26.x runtime, and the default sandbox image and generated Discord relay Dockerfile run Node.js 26.
    eve still supports Node.js 24 and later. When eve updates the package.json of an existing project that pins engines.node to another major, such as 24.x, it now sets 26.x and prints a warning. SvelteKit apps deployed to Vercel need @sveltejs/adapter-vercel 6.3.5 or later to build on Node.js 26. (#6304)
  • Sessions store much less as conversations grow: each session step now returns its changed values as frozen immer versions of the values it was given, so Workflow stores each step's input as a reference and its output as only what changed, instead of a full copy of the history every step. (#6219)
  • Slack onInteraction actions now include responseUrl, the click's response_url.
    POST to it to replace or delete the message the click came from, including an ephemeral message, which chat.update and chat.delete can't change. (#6247)
  • webSearch({ provider: "tako" }) selects Tako Search through AI Gateway, which returns web pages and Tako data cards with their rows in one call. "tako" also works as a fallback for webSearch({ provider: "native" }). (#5880)
  • eve add channel/telegram now offers guided setup with Vercel Connect or portable credentials.
    With Connect, it stores the bot token in a Telegram connector and routes the connector's triggers to /eve/v1/telegram, so Connect registers and verifies the webhook. With portable credentials, it writes the bot token and a generated webhook secret to .env.local. (#5810)
  • Add decision <model> OpenTelemetry spans for decide, automatic model selection, and tool approvals, with policy-aware model, usage, cost, and failure metadata that distinguishes refusals from request failures.
    A decision sits under the operation it runs in, or under the turn when model routing runs before the turn's first step. @vercel/agent-runs adds AgentRun.decision and an optional AgentTelemetry.activeSpan, so a decision nests under a host span inside its operation but not under a host span from another trace, such as a workflow step. (#5349)
  • Session events can now record a call or a content part that its turn made without a model run: call.requested accepts an owner of { turnId }, and content.completed leaves out runId, with scope.turnId naming the turn.
    The fold, the client's conversation, and the Slack channel place both under their turn. ContentCompletedData.runId is optional and CallOwner has a third variant in TypeScript, so code that reads runId as always present or switches over owners needs a default branch. Stream version 27 also now allows a later release to add call owners, and a reader treats a call whose owner it doesn't know as the session's. (#5771)
  • Fix vercelBlob() from eve/memory/file/vercel so a document whose key contains / can be read back after it is written.
    Before, such a read returned nothing, so the next write tried to create the document again and failed because it already existed. (#6106)
  • Update the bundled Workflow runtime to 5.3.0 and create new runs with Workflow spec version 9, which drives each run from one orchestrator.
    Workflow 5.3.0 lets parallel branches advance inline steps without waiting on slower siblings, reuses resolved hooks to skip token lookups on later resumes, and fixes a step that could be created but never run when two executions raced in one process. eve now sets WORKFLOW_SPEC_VERSION=9 before it creates a world unless WORKFLOW_SPEC_VERSION or WORKFLOW_SEALED_LOG is already set. Set WORKFLOW_SPEC_VERSION=8 to keep creating spec 8 runs. Existing runs keep their version. (#5860)
  • Update the bundled Workflow runtime to 5.4.0.
    Workflow 5.4.0 resumes a parent run once when a child run finishes instead of polling in a step, honors abort signals when waiting for a run to finish on the Vercel World, and recovers Hook token claims left by a crashed process right away on the local World instead of after 30 seconds. (#5944)
  • Update the bundled Workflow runtime and worlds to the Workflow 5.5.0 release. (#6219)

Bug Fixes

  • A successful endsTurn call now ends the turn even when the model calls other tools in the same step.
    Those calls still run, including ones that wait for an approval, a sign-in, or a workflow, and the turn ends once they all settle, whatever their outcome. Before, the turn ended only when every call in the step could end it, so no_reply called beside another tool started another model call whose text was posted as the reply. (#6371)

  • eve's two unauthenticated callback routes now resume only the hooks they exist for, so a request that guesses a token can't resume a hook your code created with createHook(), or an eve hook the route isn't for. (#6489)

    • /eve/v1/callback/:token resumes only a call that waits for a remote agent's reply. eve now generates a random token for each message to a remote agent, which adds one workflow step to that message. Someone who knew the run's identifiers could compute the earlier token.
    • /eve/v1/connections/:name/callback/:attemptId/:token delivers a sign-in callback only to a session's inbox or to a workflow tool's own sign-in hook.

    Both routes answer 404 for any other token. Don't start a createHook() token with eve:, because eve reserves that prefix for its own hooks.

    On Vercel, callbacks go to the current production deployment, but a workflow tool run or a task keeps running on the deployment that started it. Once production runs this release, a run on a deployment with an earlier release no longer receives a remote agent's reply, or a sign-in that a "use step" function asked for, and its call keeps waiting. That includes a task a session keeps after it moves to the new deployment, for as long as the task lives. If your agent calls remote agents or signs in from workflow steps, end its sessions after production runs this release, and start new ones. A sign-in link from a session that still runs on eve 0.56 or earlier is refused too.

  • Fix durable agent traces keeping every finished turn that called tools in parallel: each one stayed in the session's serialized context, so step inputs grew with every turn.
    A checkpoint this process had already written, read back through another execution context, was treated as another process's write and forked the turn's trace tree; the stale copy then overwrote the tool completions and the checkpoint was never deleted. A replaced tree now also stops persisting. (#5835)

  • AI SDK telemetry integrations such as Sentry's now receive model and decide() prompts and responses whenever the otel() trace policy or any instrumentation file's tracePolicy allows content, without an otelIntegration() destination.
    Starting with ai@7.0.163, the AI SDK removes content from telemetry when a call disables recordInputs or recordOutputs. Before this release, eve disabled both on every model call in apps without an OpenTelemetry destination, so a Sentry-only setup lost prompts, responses, and token usage. Apps that added an empty otelIntegration({}) only to work around this can remove it.
    In apps without OpenTelemetry, decide() calls previously left these settings unset, so AI SDK integrations received decision content for every conversation. They now follow the same rules as model calls: content for public conversations and in development by default, and otherwise only when a trace policy allows it. (#6234)

  • User-role instructions, static and dynamic, now join the conversation the same way: once ahead of the next turn's input, again when their content changes, and again after a compaction or clear removes them from the history.
    A newer deployment that changes a static user-role instruction adds the new text to existing sessions instead of keeping the text the session started with. Sessions that already hold an instruction don't receive it twice. (#5638)

  • Every eve build now reads paths aliases from the authored package's own tsconfig.json or jsconfig.json, and an asset import that leaves the authored package fails the build.
    The Nitro host, authored module bundles, and the workflow driver share one resolver. The workflow driver no longer searches parent directories for a config, and an agent directory without its own package.json uses the enclosing package's config in every build. Before, only ?raw asset imports were checked against the package root; now plain imports such as import notes from "../../notes.txt" are checked too. If a build fails with "resolves outside package root", move the file into the authored package or into the workspace package that imports it. (#5879)

  • Let auto() route messages longer than 16,000 characters using the configured decision provider's input limits.
    The decider receives the full text of the turn's opening input and up to seven earlier user and assistant messages. Larger inputs can increase decision cost and latency. Provider input-limit errors use the configured fallback, like other decision failures. (#6273)

  • Model calls made by decide() from eve/ai, and so by auto() and approval auto(), now count toward the session's usage and limits.sessionUsage. (#5638)

  • When a finished bash command's output is truncated, the result again keeps the start of a very long last line and the lines before it.
    The truncation note again gives the whole output's line count (showing last N of M lines), and memory stays bounded however much the command prints.
    Thanks @zackleman for reporting this in #5925 and for the implementation plan this fix follows. (#6248)

  • Limit MCP tool validation feedback to ten issues and 4096 characters, and stop published tools' JSON Schema validation at the first failure. (#6347)

  • Inline tool execution now requires permission from eve's approval gate.
    When a person answers the same call more than once, eve uses their latest answer. (#5638)

  • A cancelled sign-in is no longer asked for again in the same turn, and a scheduled run never asks for a sign-in.
    When a new message cancels an open sign-in, later calls in that turn that need the same grant fail with reason: "sign_in_cancelled" instead of posting another sign-in prompt. A turn a schedule started, including a scheduled send into an existing conversation, fails calls that need a sign-in with reason: "sign_in_unavailable". In both cases the model is told to say the action needs that access. A later message from the person asks again. (#6003)

  • eve now records which of its catalog tools a session has been offered in the same session state as its other definitions, rather than under a separate context key.
    A session an earlier deployment ran still keeps every catalog tool it was offered. (#5638)

  • A channel route whose path ends in a file extension, such as /.well-known/agent-card.json or /robots.txt, now builds and serves its handler.
    Thanks @mattcreager for reporting this and tracing it to the route module ids in #5742. (#5744)

  • Under eve dev, eve now throws if a tool call starts before its approval is accepted, or names a different approval as what cleared it. (#5638)

  • Compacting a session between turns no longer repeats the last question after its answer, so the next turn's new message follows the summary and recent history instead of an already-answered question. (#5638)

  • Compaction now summarizes directly and must bring the input under half the context window on the provider's token count, so a long session compacts once instead of several times in a row.
    It no longer caps old tool output first. A compaction whose result is still over the threshold on the next call skips the stage that fell short. (#6126)

  • A context compaction's summary request during a turn now exports its own chat <model> span under the turn's invoke_agent span, with its token usage, cost, and ai.settings.context.eve.compaction.request=summary, so traces no longer undercount compacting turns.
    Model spans now also carry agent.turn.id. @vercel/agent-runs adds TurnOperation.modelCall for model calls a turn makes outside its steps.
    Thanks @zackleman for reporting this in #5922. (#6251)

  • Sessions that switch back to a model now check its retained token measurement as well as the latest measurement, reducing compaction between steps.
    Different models' tokenizers can count the same history very differently. eve judged each call by the token count the previous call reported, so after switching to a model whose tokenizer counts higher, the history could cross the compaction threshold during the turn's first step and be rewritten before the next step, invalidating the prompt cache a second time in one turn. eve now keeps each model's latest measurement until history is rewritten. Before each call, eve uses the larger count after estimating additions from both the selected model's measurement and the latest measurement. A model without a retained measurement still falls back to the latest one. (#6186)

  • Computer use installs again because the sandbox takes the Firefox ESR line Mozilla currently serves instead of requiring ESR 140, which Mozilla no longer offers.
    The managed Firefox profile also skips the Terms of Use dialog that ESR 153 opens over the first page. COMPUTER_USE_REVALIDATION_KEY changes, so templates that include it rebuild and drop the cached ESR 140, which no longer gets security fixes. Thanks @treydoe1 for reporting this in #5829. (#5831)

  • Default scaffolded projects to @vercel/connect@2.7.0 and require ^2.7.0 for the optional @vercel/connect peer. (#5733)

  • Keep child questions and approvals answerable while a serving task remains active after replying to its original call.
    Upgrading a session whose history was cleared or compacted also restores its dynamic user instructions before the next model call. (#5638)

  • When a session stream write fails, the turn step now stops writing and fails at once, so Workflow retries it with a fresh stream, instead of retrying the model call, steering, or reporting a model call failure to the stream that just failed.
    Previously, eve read a failed write as a model call error: it retried the provider request, logged that it was "parking session for retry by the user", and tried to write a failure that could never arrive. The retried step closes the model attempt the write cut as abandoned, as it does for any interrupted step.
    Thanks @zackleman for reporting this in #5917. (#6264)

  • Fix tool-stub validation for memory-only agents, mounted dynamic connection names, and sandbox skill files when an earlier definition starts offering a colliding skill.
    The chosen model also remains visible to session code across separately bundled runtime modules. (#5638)

  • Update eve's bundled dependencies, including the AI SDK, Vercel SDKs, Chat SDK, and MCP, to their latest releases, and OpenTelemetry to its latest 2.x releases.
    eve now requires ai 7.0.172 or later.
    YAML frontmatter, eval data files, and OpenAPI specs now parse with js-yaml 5 and YAML 1.2 values. An unquoted date such as 2024-01-02 loads as a string instead of a Date, and a 0b binary literal such as 0b101 loads as a string instead of a number. The YAML 1.1 tags !!timestamp, !!binary, !!set, !!omap, and !!pairs are no longer recognized, and a mapping with a non-scalar key, such as ? [a], throws. << merge keys still work.
    MCP connections over Streamable HTTP now fail when the server/discover request fails before the server answers, instead of retrying with initialize. Set protocolVersionDiscovery: false for a server that can't handle that request. Servers that answer server/discover with a JSON-RPC error or an HTTP error status other than 401 still use initialize, and servers that reject the protocol version with a supported legacy version still negotiate it. (#6378)

  • eve dev now resolves a string agent model through a custom globalThis.AI_SDK_DEFAULT_PROVIDER, as eve start does, instead of routing it to the local AI Gateway connection. (#5789)

  • eve dev no longer answers every second request with an empty 400 Bad Request when the client sends Connection: close and the agent replies with a keep-alive response such as an MCP SSE stream, as happens behind the vercel dev proxy. (#6298)

  • Dynamic connection resolvers can exchange names within one evaluation without a transient collision, and namespaced tools and skills retain their full name-length validation. (#5638)

  • Dynamic values evaluated before a model call now see the task results and [Tasks] note that call delivers, so a dynamic model can react to a background task's result in the same step. (#6185)

  • Answer workflow tool calls from a model response that ended early (finish reason length or other) as not run, like other skipped calls, instead of starting their workflows without deciding their approval. (#6010)

  • Fix release asset uploads failing with 401 through the git extension's gh tool.
    The credential lease now covers uploads.github.com, not only api.github.com and github.com. A 401 there was read as a revoked token and opened a sign-in for a user who was already signed in.
    When Vercel Connect starts an authorization without a sign-in URL or device code, the user-scoped GitHub sign-in now fails with ConnectionAuthorizationFailedError instead of opening a sign-in prompt with no link. (#5852)

  • A turn whose step fails every Workflow retry now settles failed with code TURN_FAILED, a fixed message, and an error id, instead of the thrown error's class and raw message, which could carry prompt text or tool input.
    eve's own log line for the failure records that error id and the thrown error's class, but not its message or details, and the recovery step's stored input carries only the class. Workflow's own step-failure log still includes the error's stack.
    A turn cancelled while its failing step was between retries now settles cancelled and keeps its input in history, instead of settling failed with the step's error.
    Thanks @zackleman for reporting this and proposing the fix in #5915. (#6261)

  • Update vulnerable dependencies and bound MCP tool input validation to prevent excessive memory use. (#6177)

  • Fix signed inbox handles so follow-up messages can skip repeated hook lookups when EVE_INBOX_HANDLE_SECRET is set and the world supports guarded hook resumes. (#5904)

  • Fixed a parent session crediting or refusing the wrong person's answer when several people answer a subagent's approval before the subagent settles it, including for remote and protocol 2 subagents. (#6165)

  • When AI Gateway cuts a model stream at its maximum duration, eve now retries it once instead of up to three times.
    The error hint now says that eve already retried the request and suggests smaller turns or another model. (#6159)

  • A gh command whose lock was taken over after 10 minutes no longer clears the next command's GitHub credential when it finishes. (#6189)

  • Subagents that share a sandbox no longer trigger spurious GitHub sign-ins when they run gh commands at the same time.
    The gh tool's credential lease replaces the sandbox's network policy for the duration of one command. Leases were serialized per session, so sessions sharing a sandbox, such as parallel subagents, could replace or clear each other's credential mid-command; the stranded command got a 401 from GitHub, which asked the user to sign in again even though their grant was valid. Leases are now serialized per sandbox by a lock inside the sandbox, which works across processes. A command waits up to a minute for another to finish, then fails with a retryable error. (#6029)

  • Reword the GitHub sign-in failure message so it says plainly that the person does not have access yet and how to get it. (#5998)

  • A workflow tool's question that reaches the session after its turn was cancelled no longer fails the session: eve drops it, and the next message starts a turn. (#5638)

  • Turns no longer resume a session's sandbox in the background when they start, so a turn that never uses the sandbox no longer wakes it; the first tool or file operation that needs it resumes it instead. (#6187)

  • Make local world stream reads scale with new chunks: a repeated getInfo or cursor getChunks on a long stream no longer reopens every earlier chunk file. (#5910)

  • Fix local-world sessions that stalled after eve start or eve dev --resume restarted mid-turn: a turn waiting on a timer, such as sleep, now wakes on time, and a step that was running when the previous process stopped runs again right away instead of after about 14 minutes.
    The timer fix applies to spec 9 runs, which eve now creates by default. The step fix applies to spec 8 runs, including every session created before eve moved to spec 9. For those runs, the interrupted attempt counts toward the step's retries, so a workflow tool step with maxRetries: 0 that was running when the process stopped fails on restart instead of running again. Run one process per .eve/.workflow-data directory: recovery treats steps started before it booted as abandoned. (#5873)

  • Memory slots and schedule collections now offer their tools themselves, so agent info no longer lists them as generated dynamic tool files.
    A tool file at agent/tools/<slot>.ts or agent/tools/schedule__<name>.ts still replaces those tools, and disableTool() there still removes them. Sessions and approvals parked across the upgrade keep working. (#5638)

  • Name the memory store on memory provider tool calls, so a trace query by gen_ai.memory.store.id finds a scope's tool reads and writes as well as its recall and capture.
    The execute_tool span of a memory provider tool, such as profile__save, now carries gen_ai.memory.store.id and agent.memory.slot, matching the search_memory and upsert_memory spans of the same slot. The store ID is the slot's opaque scope key, so it is recorded whatever the trace policy captures. @vercel/agent-runs adds an optional memory lifecycle to ActiveOperation on tool operations to record it. (#6147)

  • Agent builds now build a workspace extension that only another workspace extension mounts or depends on, instead of failing with a missing compatibility manifest on a clean checkout. (#6160)

  • Keep a session open when its requests outgrow the compaction threshold or the model's context window.
    When the agent's instructions, tools, memory, and context leave no room under compaction.threshold, eve logs a warning and compacts against the model's context window instead of ending the session with COMPACTION_FAILED. When they don't fit the window either, only the turn fails with COMPACTION_FAILED. When a provider rejects a request as longer than the model's context window, only the turn fails with MODEL_CALL_FAILED, and the session can receive another message.
    Thanks @zackleman for reporting this in #5921. (#6262)

  • The Vercel project overview card now shows the agents' tools, schedules, and connections for a Next.js app that hosts an agents/ workspace through withEve from eve/next.
    During next build, withEve now writes the workspace's .eve/agent-summary.json index, the same index that withEve from eve/vercel writes since #5710. Standalone agents and agents configured with the agents option do not change. (#6163)

  • A HEAD request to a channel path that declares GET but not HEAD now gets 405 Method Not Allowed with an Allow header instead of 404, and the GET handler doesn't run.
    Declare HEAD() on a path to answer HEAD requests there, under any parameter name: HEAD("/items/:itemId") answers for GET("/items/:id"). Paths that already declare HEAD(), such as / and /eve/v1/health, are unchanged. On a CORS-enabled path, the 405 carries the CORS headers, so a browser can read it.
    eve build and eve dev no longer merge the app root's nitro.config, .nitrorc, or .env files into eve's own Nitro host, and no longer serve an app-root server.* or index.html as a catch-all in front of eve's routes. A Nitro app that shares its root with an eve agent, such as a TanStack Start host, keeps its Nitro configuration to itself. eve still loads .env, .env.local, .env.development, and .env.development.local for eve dev through its own environment handling, and still serves files in an app-root public/ directory as static files.
    eve dev now rebuilds its host when a connection turns on events or an extension mount changes the package export it imports. Before, those edits reused the running host, so the event receiver route or the new mount stayed missing until eve dev restarted. (#5692)

  • Upgrade Nitro to 3.0.261103-rc, the first Nitro 3 release candidate eve builds on.
    eve now declares Rolldown 1.2.16 itself and hands that copy to Nitro, so a plain npm install builds without relying on another package to provide Rolldown, and Nitro never installs a package into your app on demand. Importing nitro/storage, nitro/kv, or nitro/database from agent code now fails the build with an explanation instead of pulling in storage drivers. A request with a method its path doesn't declare, other than HEAD, now gets 405 Method Not Allowed with an Allow header instead of 404. eve dev runs on env-runner 0.3, and a stopped eve start server runs Nitro's close hooks and exits on its own.
    Thanks @pi0 for the investigation in #5167. (#5870)

  • Background work a channel route registers with waitUntil while its streamed response is still being sent now runs to completion on hosted platforms, instead of being dropped.
    Channel route params keep encoded path separators (%2F and %5C) encoded, so a param can no longer contain a / or \ that the request path never had. Other percent-encoded characters are still decoded, so /files/caf%C3%A9 gives café; a handler that expected %2F decoded to / must now decode it itself.
    Agent text that mentions a Nitro build constant such as import.meta.dev now reaches production builds unchanged, instead of being rewritten to its value or failing the build. Skill files are embedded in the server bundle instead of Nitro server assets, so hosted output no longer ships Nitro's storage layer unless authored code imports Nitro storage itself.
    A channel path that declares both GET() and WS() now accepts WebSocket upgrades, which the GET route used to answer as a plain HTTP request. WebSocket routes register for GET only, the method an upgrade uses. Because one handler serves both, the two routes must name their path parameters the same way; eve build rejects a pair such as GET("/rooms/:id") and WS("/rooms/:room").
    Vercel service builds keep the schedule consumer function and its queue trigger, so dynamic schedules deliver their occurrences.
    eve start now runs the server's shutdown hooks, such as flushing instrumentation, when it stops the server in an environment that sets CI. The built server no longer inherits CI or NITRO_UNIX_SOCKET from eve start.
    A server without eve's workflow program runtime installed now fails a generated workflow program with an error that explains why, instead of importing the runtime from a path hosted output can't resolve. (#5698)

  • eve now compiles an agent's dynamic tool, skill, connection, and instructions files, hooks, and memories to one list in the compiled manifest, and runs them as definitions of one shape.
    Rebuild agents after upgrading; authored files don't change. (#5638)

  • The discovery manifest in .eve/discovery/agent-discovery-manifest.json now lists an agent's authored files in one sources array, with each file's kind given by its path, instead of one array per kind. (#5638)

  • Session history now changes in one place, which checks every message as it joins, and under eve dev fails a step whose tool results don't follow the calls they answer.
    A turn that fails after the model delivered its structured reply keeps that reply in history instead of an unanswered eve__reply call. A compaction whose summary model fails to resolve now appears on the stream as a failed compaction instead of failing the turn before it starts. (#5638)

  • The model no longer sees an "awaiting approval" note in history after the approval it describes is answered or dropped, because eve now tells each model call about pending approvals from the session's current state instead of writing a note into history when the call parks. (#5638)

  • An agent or serve tool call whose taskId is the placeholder string "undefined" or "null" now starts a new task instead of failing with UNKNOWN_TASK.
    Some models send these placeholders instead of omitting the optional taskId. An empty taskId already started a new task. (#6183)

  • Sessions that started on eve 0.69 through 0.83 and delegated to a subagent now move to the new deployment instead of staying on the old one until they end.
    An idle resumable task no longer keeps such a session on its earlier deployment: the move ends the task's old run, and the model starts a new task on the current build when it needs one. A task that is still working, or has results the model hasn't read, still keeps the session where it is until that clears.
    Thanks @zackleman for reporting this and for the implementation plan in #5927. (#6260)

  • eve now renders each model call's system prompt from the current deployment's agent files instead of storing it with the session.
    Session checkpoints move to version 19, without agent.system. A deployment from before this change refuses to take over a session this one wrote, so the session stays on the deployment that wrote it, such as after a rollback. (#5638)

  • Show the expected GitHub-side result as the gh tool's activity label instead of the generic tool name. (#5668)

  • Fix workflow hook ownership checks and preserve workflow error types and retry timing.
    hook.getConflict() now returns the existing owner's run ID inside workflow bodies. FatalError and RetryableError caught from steps retain their class identity, and workflow-created RetryableError values honor retryAfter. (#5937)

  • Allow dynamic schedules on Vercel preview and custom-environment deployments instead of rejecting operations outside production.
    The default Vercel provider uses the deployment's OIDC credentials to access its own schedule track. Preview schedules remain separate from production schedules. (#5946)

  • Answers eve discards, such as an empty answer it asks the model for again or a content-filter answer that fails the turn, now record their usage on the session stream and count toward session usage and limits.sessionUsage, like a steered answer always has.
    A reissued answer's usage.recorded follows its model.retried; a failed run's follows its model.settled. Thanks @zackleman for reporting this in #5918. (#6253)

  • A prompt that OpenAI refuses for possible cybersecurity (cyber_policy) or biological (bio_policy) risk now fails only its turn instead of ending the session. (#5772)

  • Start a fresh session when a channel message reaches a session whose Vercel deployment was deleted, instead of failing with RunKeyFetchError.
    Thanks @kashifrayani for diagnosing the channel failure in #5261. (#5954)

  • Replace the vendored Turndown dependency with a small linear-time HTML-to-Markdown converter for web fetch and Microsoft Teams messages. (#6220)

  • Retry model calls that AI Gateway aborts with gateway_stream_timeout instead of parking the session after the first cut stream.
    Thanks @Benny-Gil for the original fix in #3108. (#4558)

  • Model calls now retry when a stream chunk fails the provider's schema (AI_TypeValidationError) or when AI Gateway's provider stream ends before the response finishes (gateway_stream_terminated).
    Thanks @zackleman for reporting these in #5911 and #5912. (#6249)

  • A root session whose otel({ tracePolicy }) withholds inputs or outputs, or drops the trace, no longer tags its workflow run as content-visible, so observability stops showing run data the policy excludes.
    A trace policy can only hide content its audience would show by default. A private or unknown-audience run stays hidden even when its policy records content, because Agent Runs' exportPolicy may still redact those spans. Sessions without OpenTelemetry keep the audience default.
    Thanks @zackleman for reporting the related visibility gap in #5931. (#6294)

  • Only sign-ins the runtime starts can hold a turn.
    A tool result shaped like a sign-in request, such as JSON from an MCP or OpenAPI connection, no longer opens a sign-in or changes who the turn runs as. (#5790)

  • Fail closed for repository-based authorization policies when GitHub commands use a caller's unscoped token.
    User-mode authorize callbacks always receive repository: null, regardless of the command's declaration. Use GitHub App tokens with a full owner/name declaration for repository allowlists. Policies that intentionally permit the caller's full GitHub access can continue to authorize through auth. (#5903)

  • Fix eve dev requests that use a sandbox failing with ENOENT … sandbox-preparation.lock when another request finished preparing sandboxes at the same time.
    These requests now wait for the other request and continue, as they already did while preparation was in progress. (#6388)

  • The experimental Vercel schedule provider bundles Schedules SDK 0.0.3, the first stable release after alpha.19. (#6027)

  • Fix delays and failures in server shutdown, session streams, successor sessions, and eve dev startup, and start every eve command faster. (#6349)

    • A self-hosted eve server exits promptly after SIGTERM or SIGINT, including after it ran sessions.
    • session.stream() stops reading a session's events as soon as a channel stops iterating it.
    • A successor session starts its next turn at once when the run it moved from has already ended, instead of up to 10 s later.
    • eve dev no longer fails requests that arrive during startup with a LoadCompiledManifestError.
    • Every eve command starts faster by loading the inspection code for eve remote info --url only when that command runs.
  • A turn's input now joins history before its first model call, so a model call that fails keeps the person's message for the next turn.
    A response the provider filters is the exception: a refusal note replaces its turn's input, so the next turn doesn't send that input again. Completed tool calls and their results stay in history, so the model knows which actions already ran.
    A compaction now opens only once it summarizes or rewrites the history, so session.compact() records no change when its model doesn't resolve or the history has nothing to compact. (#5638)

  • eve's session loop now runs as a kernel that owns every session transition, with no change in behavior. (#5638)

  • Report a sign-in the runtime cancelled (withdrawn, interrupted, or abandoned) as "sign-in cancelled" in Slack and other channels, instead of a red error with the internal reason code, such as (turn-cancelled).
    The GitHub sign-in's failure message now tells the person how to retry. (#5994)

  • One answer now settles every parallel subagent waiting on the same Vercel Connect sign-in for the same person.
    Signing in on any one of their sign-in cards completes every other subagent waiting on that grant, and declining one declines the others, so none of them asks again this turn. A sign-in callback with the provider's access_denied now settles the sign-in as declined rather than as a retryable failure. A failed sign-in still settles only its own card. The parent calls each subagent's own callback, and each subagent settles it under its own principal, so no principal or credential passes between them. Sign-ins without a grant, for another principal, or minted by another deployment are still answered one by one. (#6086)

  • Prevent gh-signed-commit from publishing another file's contents for paths that resemble Git stage syntax or silently losing file modes and types.
    The command now reads staged paths literally and rejects additions or updates involving executable files, symlinks, submodules, or mode changes before contacting GitHub. Staged changes remain intact; publish unsupported changes with native Git and a configured signing key. (#5863)

  • Deliver Slack DM thread replies posted with "Also send to direct message" to the agent.
    Thanks @dohooo for reporting this in #5774. (#5776)

  • Slack no longer copies a direct-message question's answer into the shared thread: once the request settles, the thread's Waiting on a response note says only who answered, while the DM card still shows the answer.
    Approval notes still name the decision, such as Answered: Approve. (#6041)

  • Keep an answered ephemeral Slack card in its thread instead of also showing it at the top of the channel. (#6381)

  • Remove a Slack sign-in prompt when its Cancel button is clicked after the held turn has already ended, and log when Slack refuses to delete the prompt. (#5995)

  • Drop the redundant "Only you can see this message" from the Slack sign-in card; Slack already labels ephemeral messages "Only visible to you". (#6002)

  • Send a Slack sign-in prompt to the person's DM when the session has no thread, instead of posting a status top-level in the channel.
    The DM names the channel the request came from, is edited in place with the outcome, and needs no Slack scope beyond chat:write. If the DM can't be sent, eve posts in the channel as before. Threaded sessions and code channels are unchanged. (#6007)

  • Steering no longer discards a model call that is streaming a tool call's input, so the model doesn't write a long input twice.
    The call finishes, the tool runs, and the new message applies at the next step boundary in the same turn.
    Thanks @zackleman for reporting this and proposing the fix in #5929. (#6257)

  • Ending a stranded session now writes the same checked commit as any other session end.
    A stranded stream that never recorded session.started, such as one an older deployment opened, gets it in the commit that ends the session. (#5638)

  • Fixed subagent approvals answered from Slack, or with any state on the response, failing the subagent with "Session delivery has no identity" instead of running the approved call.
    Thanks @Phelickz for reporting this in #5726. (#5728)

  • Keep the head of a task result line that overflows the 50 KB budget instead of replacing it with [truncated], so a one-line JSON result past the budget still reaches the model.
    Thanks @nsxdavid for reporting this in #5746. (#5748)

  • When eve__task_wait returns with one task's result while others are still working, the result now tells the model to wait again if its reply needs the rest, so it no longer sends a partial answer first. (#6380)

  • eve__task_wait now waits at most 30 minutes when a call omits timeoutSeconds, so a task that never reports can't hold a turn open indefinitely. (#5300)

  • AI SDK telemetry integrations no longer receive tool arguments, results, or raw errors for a call whose recordInputs or recordOutputs setting is off.
    eve runs agent tools itself, so the AI SDK does not filter their telemetry events. eve now removes the excluded content before it calls each integration, the same way the AI SDK filters the events it sends. Integrations that ignore the per-call settings, such as Sentry's eve integration, previously recorded tool arguments for private conversations. (#6238)

  • Make connection sign-ins countable in traces: each sign-in span names its agent, a failed sign-in records its reason, and a call a connection refused records which connection and why.
    agent.approval spans now carry gen_ai.agent.name and agent.name, so a query scoped to one agent no longer drops its sign-in prompts. A sign-in that fails with a reason code such as access_denied records it as agent.connection.authorization.reason; a sign-in that ends any other way, such as one a new message withdrew, records none. A tool call that fails with ConnectionAuthorizationFailedError, including one that never asked anyone to sign in, such as principal_required or sign_in_unavailable in a turn a schedule started, records eve.connection.name and agent.connection.authorization.reason on its execute_tool span. Only reason codes are recorded: a free-text reason or error message stays off the span whatever the trace policy records. (#6078)

  • Sessions recorded before eve 1.0 now read the way a current eve records them, and opening a subagent's stream through such a parent no longer re-reads the parent's whole history on every open and reconnect, which could make long sessions answer 404 descendant_unavailable.
    eve now verifies the child against only the parent's stored line at the requested position, whichever eve version wrote it.
    A question or approval that a subagent relayed before eve 1.0 now reads as a current relayed request: it names the task it came from when there is one, and carries the subagent's session, request, and the call it asks about. A relayed approval no longer reads as an approval of the parent's own subagent call.
    Turns recorded before eve 1.0 now keep their trace context when read: each converted turn.started carries the trace its stored line recorded, as a turn a current eve runs does. A malformed recorded trace reads as absent instead of failing the line's schema.
    Thanks @zackleman for reporting these in #5928, #5933, and #5934. (#6250)

  • Vercel builds without VERCEL_OIDC_TOKEN no longer fail for agents whose sandbox templates have nothing to prepare, such as a freshly scaffolded agent with no sandbox, skills, or workspace files.
    Templates with a prepare callback, managed workspace or skill files, or a Vercel source still require the token. Builds without it fail with the instruction to run vercel link and vercel pull. Unrelated provider preparation errors retain their original messages. (#6184)

  • Fixed a session on VercelSandbox failing every turn after its stopped sandbox's snapshot expired. eve now starts a fresh sandbox for the session, as it does when the sandbox is gone.
    Thanks @BilalAtique for reporting this in #4393 and @mahirhir for the reproduction. (#6182)

  • Vercel sandboxes refresh or replace expired and near-expiry VERCEL_OIDC_TOKEN credentials before template builds to avoid 403 invalidToken errors.
    When VERCEL_TEAM_ID (or VERCEL_ORG_ID) and VERCEL_PROJECT_ID were set, eve used VERCEL_OIDC_TOKEN directly without checking its expiry, so a build that started after the token expired failed while preparing sandbox templates. eve now resolves the OIDC token through the Vercel OIDC helper, which attempts refresh within five minutes of expiry, and falls back to VERCEL_TOKEN when it is set and the OIDC token can't be used. (#6188)

  • Vercel sandboxes created without a snapshot now receive their configured network policy at creation, so an interrupted first open cannot leave them with unrestricted network access.
    Base setup needs no network access. Reopening a sandbox preserves its live policy, including changes made through setNetworkPolicy(), rather than applying changed open options.
    Existing sandboxes are not migrated or reset. Recycle any sandbox that may have been left unrestricted by an interrupted initialization before this fix. (#6042)

  • Fix eve/react and eve/client throwing ReferenceError: e is not defined in production builds from custom webpack setups older than 5.90. (#5042)

  • Show workspace agents on the Vercel project overview card when vercel.ts composes them with withEve.
    withEve now writes the root .eve/agent-summary.json index that points Vercel at each member's summary, matching the hostless eve build path. Thanks @cnaccio for reporting this in #5706. (#5710)

  • defineWorkflowTool now types the output that endsTurn and toModelOutput receive the way eve produces it.
    A generator body's output includes its return value, not only its yields. A tool with an outputSchema gets that schema's output, as the definition defineWorkflowTool returns already does. (#6430)

  • Workflow and step modules can now embed files from node_modules with relative asset imports.
    Before, eve build failed with UNLOADABLE_DEPENDENCY for an import such as ../node_modules/pkg/README.md?raw, even though the same import worked in a tool. Thanks @mikestevenson-aries for reporting this in #5847. (#5849)

  • Throw a clear, non-retrying error when a defineState() handle is read or updated inside a workflow tool's "use step" function.
    A step runs outside the session that owns the state, so get() silently returned initial() and update() silently discarded its write. Code that relied on that now fails the step without a retry. Return the value from the workflow tool and update state in a call.settled hook instead; see the State docs. (#6201)

  • Self-hosted eve servers now close their Workflow world on shutdown, so a pending workflow sleep or delivery retry no longer holds the process open until the supervisor kills it.
    If closing the world fails or takes longer than 5 seconds, eve logs it and still runs the rest of its shutdown, including sandbox shutdown and the final trace flush. (#5879)

  • eve build, eve dev, and eve eval now build a workspace extension after the workspace extensions it depends on, so an extension whose subagent mounts another workspace extension builds from a clean checkout.
    Thanks @dretanacr for reporting this in #5837 and for the implementation plan. (#5839)