eve 0.29.4 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/src/channel/clear-session.d.ts +4 -0
  3. package/dist/src/channel/clear-session.js +1 -0
  4. package/dist/src/channel/compact-session.d.ts +4 -0
  5. package/dist/src/channel/compact-session.js +1 -0
  6. package/dist/src/channel/routes.d.ts +34 -6
  7. package/dist/src/channel/types.d.ts +61 -9
  8. package/dist/src/chunks/{use-eve-agent-8mofdZcO.js → use-eve-agent-BXMIf5fR.js} +85 -1
  9. package/dist/src/chunks/{use-eve-agent-bKJbH0k4.js → use-eve-agent-k-XHfrJT.js} +85 -1
  10. package/dist/src/cli/dev/tui/message-queue.d.ts +12 -16
  11. package/dist/src/cli/dev/tui/message-queue.js +1 -1
  12. package/dist/src/cli/dev/tui/prompt-commands.d.ts +13 -5
  13. package/dist/src/cli/dev/tui/prompt-commands.js +1 -1
  14. package/dist/src/cli/dev/tui/runner.d.ts +7 -7
  15. package/dist/src/cli/dev/tui/runner.js +1 -1
  16. package/dist/src/cli/dev/tui/setup-panel.js +4 -1
  17. package/dist/src/cli/dev/tui/subagent-pump.d.ts +5 -5
  18. package/dist/src/cli/dev/tui/terminal-renderer.js +12 -12
  19. package/dist/src/client/agent-info-schema.d.ts +2 -2
  20. package/dist/src/client/agent-info-schema.js +1 -1
  21. package/dist/src/client/index.d.ts +1 -1
  22. package/dist/src/client/session.d.ts +15 -1
  23. package/dist/src/client/session.js +1 -1
  24. package/dist/src/client/types.d.ts +20 -0
  25. package/dist/src/compiled/.vendor-stamp.json +6 -6
  26. package/dist/src/compiled/@workflow/core/_devalue.d.ts +8 -0
  27. package/dist/src/compiled/@workflow/core/capabilities.d.ts +5 -0
  28. package/dist/src/compiled/@workflow/core/index.js +2 -2
  29. package/dist/src/compiled/@workflow/core/replay-payload-cache.d.ts +11 -0
  30. package/dist/src/compiled/@workflow/core/runtime/compute-instance.d.ts +12 -0
  31. package/dist/src/compiled/@workflow/core/runtime/constants.d.ts +18 -0
  32. package/dist/src/compiled/@workflow/core/runtime/helpers.d.ts +103 -31
  33. package/dist/src/compiled/@workflow/core/runtime/replay-recovery-reporter.d.ts +36 -0
  34. package/dist/src/compiled/@workflow/core/runtime/resume-hook.d.ts +22 -2
  35. package/dist/src/compiled/@workflow/core/runtime/step-executor.d.ts +17 -13
  36. package/dist/src/compiled/@workflow/core/runtime/suspension-handler.d.ts +13 -8
  37. package/dist/src/compiled/@workflow/core/runtime.d.ts +1 -1
  38. package/dist/src/compiled/@workflow/core/runtime.js +3 -3
  39. package/dist/src/compiled/@workflow/core/serialization/codec.d.ts +17 -0
  40. package/dist/src/compiled/@workflow/core/serialization/hardened.d.ts +155 -0
  41. package/dist/src/compiled/@workflow/core/serialization/index.d.ts +2 -1
  42. package/dist/src/compiled/@workflow/core/serialization/reducers/common.d.ts +1 -1
  43. package/dist/src/compiled/@workflow/core/serialization.d.ts +13 -9
  44. package/dist/src/compiled/@workflow/core/step/context-storage.d.ts +1 -1
  45. package/dist/src/compiled/@workflow/core/telemetry/semantic-conventions.d.ts +41 -0
  46. package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
  47. package/dist/src/compiled/@workflow/core/workflow.js +1 -1
  48. package/dist/src/compiled/@workflow/errors/index.d.ts +16 -8
  49. package/dist/src/compiled/@workflow/errors/index.js +1 -1
  50. package/dist/src/compiled/@workflow/world/analytics.d.ts +2 -0
  51. package/dist/src/compiled/@workflow/world/events.d.ts +87 -0
  52. package/dist/src/compiled/@workflow/world/hooks.d.ts +39 -0
  53. package/dist/src/compiled/@workflow/world/index.d.ts +1 -1
  54. package/dist/src/compiled/@workflow/world/interfaces.d.ts +61 -0
  55. package/dist/src/compiled/@workflow/world/queue.d.ts +40 -0
  56. package/dist/src/compiled/@workflow/world-local/index.js +3 -3
  57. package/dist/src/compiled/@workflow/world-vercel/index.js +14 -14
  58. package/dist/src/compiled/_chunks/workflow/{attribute-changes-1LmTKuTT.js → attribute-changes-DROfGk6l.js} +3 -3
  59. package/dist/src/compiled/_chunks/workflow/{dist-WjtNsOyf.js → dist-D5bR13zs.js} +1 -1
  60. package/dist/src/compiled/_chunks/workflow/{dist-BeQ_csYA.js → dist-dNxTT6nO.js} +2 -2
  61. package/dist/src/compiled/_chunks/workflow/resume-hook-bc-OQVI0.js +1 -0
  62. package/dist/src/compiled/_chunks/workflow/run-DM3ouA3U.js +1 -0
  63. package/dist/src/compiled/_chunks/workflow/sleep-D5iWly6-.js +1 -0
  64. package/dist/src/compiled/_chunks/workflow/wait-until-DoW76jdb.js +15 -0
  65. package/dist/src/compiler/extension-compatibility.d.ts +8 -8
  66. package/dist/src/compiler/extension-compatibility.js +1 -1
  67. package/dist/src/compiler/manifest.d.ts +11 -22
  68. package/dist/src/compiler/manifest.js +1 -1
  69. package/dist/src/compiler/normalize-agent-config.d.ts +3 -1
  70. package/dist/src/compiler/normalize-agent-config.js +1 -1
  71. package/dist/src/compiler/normalize-manifest.js +1 -1
  72. package/dist/src/compiler/normalize-subagent.d.ts +1 -0
  73. package/dist/src/compiler/normalize-subagent.js +1 -1
  74. package/dist/src/compiler/remote-agent-node.d.ts +3 -0
  75. package/dist/src/context/dynamic-subagent-lifecycle.d.ts +22 -0
  76. package/dist/src/context/dynamic-subagent-lifecycle.js +1 -0
  77. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  78. package/dist/src/context/keys.d.ts +21 -2
  79. package/dist/src/context/keys.js +1 -1
  80. package/dist/src/context/run-step.js +1 -1
  81. package/dist/src/execution/cancel-descendant-turns-step.js +1 -1
  82. package/dist/src/execution/create-session-step.d.ts +2 -0
  83. package/dist/src/execution/create-session-step.js +1 -1
  84. package/dist/src/execution/delegation-tool.d.ts +3 -0
  85. package/dist/src/execution/delegation-tool.js +1 -0
  86. package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
  87. package/dist/src/execution/dispatch-workflow-runtime-actions-step.js +1 -1
  88. package/dist/src/execution/effective-agent-config.d.ts +12 -0
  89. package/dist/src/execution/effective-agent-config.js +1 -0
  90. package/dist/src/execution/node-step.d.ts +4 -0
  91. package/dist/src/execution/node-step.js +1 -1
  92. package/dist/src/execution/remote-agent-dispatch.d.ts +3 -1
  93. package/dist/src/execution/remote-agent-dispatch.js +1 -1
  94. package/dist/src/execution/runtime-context.d.ts +2 -0
  95. package/dist/src/execution/runtime-context.js +1 -1
  96. package/dist/src/execution/session-callback-request.d.ts +5 -0
  97. package/dist/src/execution/session-callback-request.js +1 -0
  98. package/dist/src/execution/session-delivery-hook.d.ts +1 -0
  99. package/dist/src/execution/session-delivery-hook.js +1 -1
  100. package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
  101. package/dist/src/execution/subagent-event-proxy-step.js +1 -1
  102. package/dist/src/execution/workflow-entry.js +1 -1
  103. package/dist/src/execution/workflow-runtime.d.ts +2 -0
  104. package/dist/src/execution/workflow-runtime.js +1 -1
  105. package/dist/src/execution/workflow-steps.js +1 -1
  106. package/dist/src/harness/agent-handles.d.ts +238 -0
  107. package/dist/src/harness/agent-handles.js +2 -0
  108. package/dist/src/harness/compaction.d.ts +1 -1
  109. package/dist/src/harness/compaction.js +1 -1
  110. package/dist/src/harness/tool-loop.js +2 -2
  111. package/dist/src/harness/types.d.ts +16 -0
  112. package/dist/src/internal/application/package.js +1 -1
  113. package/dist/src/internal/authored-definition/core.js +1 -1
  114. package/dist/src/internal/authored-module-loader.js +1 -1
  115. package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
  116. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response-from-manifest.js +1 -1
  117. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.d.ts +1 -1
  118. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.js +1 -1
  119. package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
  120. package/dist/src/internal/vercel-agent-summary.d.ts +1 -1
  121. package/dist/src/internal/workflow-bundle/dynamic-capability-transform-plugin.d.ts +10 -0
  122. package/dist/src/internal/workflow-bundle/dynamic-capability-transform-plugin.js +1 -0
  123. package/dist/src/internal/workflow-bundle/dynamic-remote-agent-transform.d.ts +7 -0
  124. package/dist/src/internal/workflow-bundle/dynamic-remote-agent-transform.js +3 -0
  125. package/dist/src/internal/workflow-bundle/dynamic-tool-ast-references.d.ts +2 -0
  126. package/dist/src/internal/workflow-bundle/dynamic-tool-ast-references.js +1 -1
  127. package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +2 -2
  128. package/dist/src/protocol/clear-session.d.ts +14 -0
  129. package/dist/src/protocol/clear-session.js +1 -0
  130. package/dist/src/protocol/compact-session.d.ts +14 -0
  131. package/dist/src/protocol/compact-session.js +1 -0
  132. package/dist/src/protocol/message.d.ts +19 -1
  133. package/dist/src/protocol/message.js +1 -1
  134. package/dist/src/protocol/routes.d.ts +10 -0
  135. package/dist/src/protocol/routes.js +1 -1
  136. package/dist/src/public/channels/auth.d.ts +11 -25
  137. package/dist/src/public/channels/auth.js +1 -1
  138. package/dist/src/public/channels/eve.js +1 -1
  139. package/dist/src/public/channels/index.d.ts +1 -1
  140. package/dist/src/public/definitions/agent.d.ts +35 -1
  141. package/dist/src/public/definitions/agent.js +1 -1
  142. package/dist/src/public/definitions/channel.d.ts +5 -2
  143. package/dist/src/public/definitions/channel.js +1 -1
  144. package/dist/src/public/definitions/hook.d.ts +1 -0
  145. package/dist/src/public/definitions/tool.d.ts +4 -1
  146. package/dist/src/public/index.d.ts +1 -2
  147. package/dist/src/public/index.js +1 -1
  148. package/dist/src/runtime/framework-channels/index.js +1 -1
  149. package/dist/src/runtime/framework-tools/connection-search-dynamic.d.ts +2 -18
  150. package/dist/src/runtime/framework-tools/connection-search-dynamic.js +2 -2
  151. package/dist/src/runtime/framework-tools/index.d.ts +7 -2
  152. package/dist/src/runtime/framework-tools/index.js +1 -1
  153. package/dist/src/runtime/resolve-agent-graph.js +1 -1
  154. package/dist/src/runtime/resolve-agent.js +1 -1
  155. package/dist/src/runtime/resolve-dynamic-subagent.d.ts +12 -0
  156. package/dist/src/runtime/resolve-dynamic-subagent.js +1 -0
  157. package/dist/src/runtime/resolve-dynamic-tool.d.ts +15 -0
  158. package/dist/src/runtime/resolve-dynamic-tool.js +1 -1
  159. package/dist/src/runtime/subagents/dynamic-agent-config.d.ts +22 -0
  160. package/dist/src/runtime/subagents/dynamic-agent-config.js +1 -0
  161. package/dist/src/runtime/subagents/dynamic-remote-agent-config.d.ts +13 -0
  162. package/dist/src/runtime/subagents/dynamic-remote-agent-config.js +1 -0
  163. package/dist/src/runtime/subagents/registry.d.ts +10 -2
  164. package/dist/src/runtime/subagents/registry.js +1 -1
  165. package/dist/src/runtime/types.d.ts +11 -2
  166. package/dist/src/setup/flows/registry.js +1 -1
  167. package/dist/src/setup/scaffold/channels-catalog.d.ts +2 -2
  168. package/dist/src/setup/scaffold/channels-catalog.js +1 -1
  169. package/dist/src/setup/scaffold/connections/catalog.d.ts +2 -2
  170. package/dist/src/setup/scaffold/create/project.js +1 -1
  171. package/dist/src/shared/agent-definition.d.ts +7 -0
  172. package/dist/src/shared/agent-turn-outcome.d.ts +47 -0
  173. package/dist/src/shared/agent-turn-outcome.js +1 -0
  174. package/dist/src/shared/dynamic-tool-definition.d.ts +1 -5
  175. package/dist/src/shared/dynamic-tool-definition.js +1 -1
  176. package/dist/src/svelte/index.js +1 -1
  177. package/dist/src/svelte/use-eve-agent.js +1 -1
  178. package/dist/src/vue/index.js +1 -1
  179. package/dist/src/vue/use-eve-agent.js +1 -1
  180. package/docs/channels/custom.mdx +41 -1
  181. package/docs/channels/eve.mdx +27 -2
  182. package/docs/concepts/default-harness.md +4 -0
  183. package/docs/concepts/sessions-runs-and-streaming.md +1 -1
  184. package/docs/guides/auth-and-route-protection.md +13 -13
  185. package/docs/guides/client/streaming.mdx +14 -0
  186. package/docs/guides/dev-tui.md +12 -9
  187. package/docs/guides/dynamic-capabilities.md +74 -6
  188. package/docs/guides/frontend/nextjs.mdx +1 -1
  189. package/docs/guides/frontend/nuxt.mdx +1 -1
  190. package/docs/guides/frontend/sveltekit.mdx +1 -1
  191. package/docs/guides/remote-agents.md +33 -0
  192. package/docs/reference/project-layout.md +1 -1
  193. package/docs/reference/typescript-api.md +48 -48
  194. package/docs/subagents.mdx +32 -2
  195. package/package.json +8 -8
  196. package/dist/src/compiled/_chunks/workflow/resume-hook-D1_5NCZ6.js +0 -1
  197. package/dist/src/compiled/_chunks/workflow/run-C240Ctf4.js +0 -1
  198. package/dist/src/compiled/_chunks/workflow/sleep-De802yfX.js +0 -1
  199. package/dist/src/compiled/_chunks/workflow/wait-until-z48sPUjU.js +0 -15
@@ -232,10 +232,15 @@ export interface ResolvedChannelDefinition extends ResolvedModuleSourceRef {
232
232
  * subagent package.
233
233
  */
234
234
  export type ResolvedRuntimeSubagentNode = Readonly<ModuleSourceRef & Node & {
235
- description: string;
236
235
  kind: "subagent";
237
236
  name: string;
238
- }>;
237
+ } & ({
238
+ description: string;
239
+ dynamic?: never;
240
+ } | {
241
+ description?: never;
242
+ dynamic: ResolvedDynamicSubagentDefinition;
243
+ })>;
239
244
  /**
240
245
  * Runtime-owned remote subagent entry resolved from one module-backed remote
241
246
  * definition in the parent node's compiled manifest.
@@ -255,6 +260,10 @@ export type ResolvedRuntimeRemoteAgentNode = Readonly<ModuleSourceRef & Node & {
255
260
  * Runtime-owned delegation entry exposed to the model as a subagent-shaped tool.
256
261
  */
257
262
  export type ResolvedRuntimeDelegationNode = ResolvedRuntimeRemoteAgentNode | ResolvedRuntimeSubagentNode;
263
+ export interface ResolvedDynamicSubagentDefinition extends Readonly<ModuleSourceRef> {
264
+ readonly eventNames: readonly string[];
265
+ readonly events: Readonly<Record<string, (event: unknown, ctx: unknown) => unknown | Promise<unknown>>>;
266
+ }
258
267
  /**
259
268
  * Runtime-owned additive agent configuration resolved from `agent.ts`.
260
269
  */
@@ -1 +1 @@
1
- import{WizardCancelledError}from"#setup/step.js";import{withSpinner}from"#setup/with-spinner.js";const ADDRESS_PREFIX=`address:`,BACK=`action:back`,DONE=`action:done`,ALL=`category:all`,REGISTRY_CATEGORIES=[{value:`category:channel`,prefix:`channel/`,label:`Chat channels`,hint:`Web, Slack, Discord, Teams`},{value:`category:connection`,prefix:`connection/`,label:`Tools & data`,hint:`Linear, Notion, GitHub, Vercel`},{value:`category:extension`,prefix:`extension/`,label:`Capabilities`,hint:`Browser automation, memory, developer tools`},{value:`category:instrumentation`,prefix:`instrumentation/`,label:`Observability`,hint:`Sentry, Braintrust, Honeycomb`}];function itemLabel(e){return e.title===void 0?(e.name.split(`/`).at(-1)??e.name).split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `):e.title}function itemRows(e){return e.map((e,t)=>({value:`item:${t}`,label:itemLabel(e),hint:e.description??e.type}))}function categoryRows(){return[...REGISTRY_CATEGORIES.map(e=>({value:e.value,label:e.label,hint:e.hint})),{value:ALL,label:`All integrations`,hint:`Search by name or enter an item address`},{value:DONE,label:`Back to chat`,trailingAction:!0}]}function itemsForCategory(e,t){if(t===ALL)return e;let n=REGISTRY_CATEGORIES.find(e=>e.value===t);return n===void 0?e:e.filter(e=>e.address.startsWith(n.prefix)||e.name.startsWith(n.prefix))}function stringArray(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`):[]}function itemSource(e){if(e.startsWith(`@`))return e.split(`/`)[0]??e;if(/^https?:\/\//u.test(e))try{return new URL(e).host}catch{return e}return`Vercel`}function manifestRecord(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:{}}function summarizeDetails(e,t=3){let n=e.slice(0,t),r=e.length-n.length;return r>0?`${n.join(`, `)} … (+${r} more)`:n.join(`, `)}function itemDetails(e,t){let n=[{label:`Source`,value:e.source}],r=[...stringArray(t.dependencies),...stringArray(t.devDependencies),...stringArray(t.registryDependencies)];r.length>0&&n.push({label:`Packages`,value:summarizeDetails(r)});let i=t.envVars;if(typeof i==`object`&&i&&!Array.isArray(i)){let e=Object.keys(i);e.length>0&&n.push({label:`Environment`,value:summarizeDetails(e)})}let a=(Array.isArray(t.files)?t.files:[]).flatMap(e=>{if(typeof e!=`object`||!e||Array.isArray(e))return[];let t=e.target;return typeof t==`string`?[t]:[]});return a.length>0&&n.push({label:`Files`,value:summarizeDetails(a)}),n}async function inspectItem(e,n,r,i,a,o){let s=a??manifestRecord(await withSpinner(e,`Loading registry item…`,()=>n.getRegistryItemManifest(r,i.address)));for(;;){let t={message:typeof s.title==`string`?s.title:i.name,metadata:itemDetails(i,s),options:[{value:`add`,label:`Add to project`},{value:`back`,label:`Back`}]},a=typeof s.description==`string`?s.description:i.description;if(a!==void 0&&(t.description=a),await e.select(t)===`back`)return{kind:`back`};let c=e.log.spinner?.(`Installing ${itemLabel(i)} and dependencies…`);try{c?.stop();let install=()=>n.installRegistryItem(r,i.address,{silent:!0,prompter:e,signal:o});return{kind:`added`,output:await(e.withExclusiveTerminal?.(install)??install())}}finally{c?.stop()}}}async function resolveAddressItem(e,n,r,i){let a=manifestRecord(await withSpinner(e,`Loading registry item…`,()=>n.getRegistryItemManifest(r,i))),o={address:i,name:typeof a.name==`string`?a.name:i,source:itemSource(i)};return typeof a.type==`string`&&(o.type=a.type),typeof a.description==`string`&&(o.description=a.description),{item:o,manifest:a}}async function runRegistryFlow(a){let o;(a.deps?.browseRegistryCatalog===void 0||a.deps.getRegistryItemManifest===void 0||a.deps.installRegistryItem===void 0)&&(o=await import(`#cli/commands/registry.js`));let s={browseRegistryCatalog:a.deps?.browseRegistryCatalog??o.browseRegistryCatalog,getRegistryItemManifest:a.deps?.getRegistryItemManifest??o.getRegistryItemManifest,installRegistryItem:a.deps?.installRegistryItem??o.installRegistryItem},c=[];try{for(;;){a.signal?.throwIfAborted();let e=await withSpinner(a.prompter,`Loading registry…`,()=>s.browseRegistryCatalog(a.appRoot));c=[...c,...e.errors.map(e=>({tone:`warning`,text:`${e.registry}: ${e.message}`}))];let o=await a.prompter.select({message:``,options:categoryRows(),hintLayout:`inline`,notices:c});if(c=[],o===DONE)return{kind:`done`,addedItems:[]};let l=itemsForCategory(e.items,o),u=itemRows(l);u.push({value:BACK,label:`Back`,trailingAction:!0});let d=await a.prompter.select({message:`Browse registry integrations`,options:u,search:!0,placeholder:`Search or enter an item address`,searchAction:{label:e=>`Add “${e}”`,value:e=>`${ADDRESS_PREFIX}${e.trim()}`},hintLayout:`inline`});if(d===BACK)continue;let f=d.startsWith(ADDRESS_PREFIX)?await resolveAddressItem(a.prompter,s,a.appRoot,d.slice(8)):{item:l[Number(d.slice(5))]};if(f.item===void 0)throw Error(`The selected registry item is no longer available.`);let p=await inspectItem(a.prompter,s,a.appRoot,f.item,`manifest`in f?f.manifest:void 0,a.signal);if(p.kind===`added`)return p.output.length===0?{kind:`done`,addedItems:[f.item.address]}:{kind:`done`,addedItems:[f.item.address],output:p.output}}}catch(t){if(t instanceof WizardCancelledError)return{kind:`cancelled`};throw t}}export{runRegistryFlow};
1
+ import{WizardCancelledError}from"#setup/step.js";import{withSpinner}from"#setup/with-spinner.js";const ADDRESS_PREFIX=`address:`,BACK=`action:back`,DONE=`action:done`,ALL=`category:all`,REGISTRY_CATEGORIES=[{value:`category:channel`,prefix:`channel/`,label:`Channels`,hint:`Where people talk to your agent — Web, Slack, Discord, Teams`,browseLabel:`Browse channels`},{value:`category:connection`,prefix:`connection/`,label:`MCP connections`,hint:`Connect services like Linear, Notion, GitHub, and Vercel`,browseLabel:`Browse MCP connections`},{value:`category:extension`,prefix:`extension/`,label:`Extensions`,hint:`Add browser automation, memory, and developer tools`,browseLabel:`Browse extensions`},{value:`category:instrumentation`,prefix:`instrumentation/`,label:`Observability`,hint:`Trace, evaluate, and monitor your agent`,browseLabel:`Browse observability integrations`}];function itemLabel(e){return e.title===void 0?(e.name.split(`/`).at(-1)??e.name).split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `):e.title}function itemRows(e){return e.map((e,t)=>({value:`item:${t}`,label:itemLabel(e),hint:e.description??e.type}))}function categoryRows(){return[...REGISTRY_CATEGORIES.map(e=>({value:e.value,label:e.label,hint:e.hint})),{value:ALL,label:`Browse all`,hint:`Search every integration or enter an item address`},{value:DONE,label:`Return to chat`,trailingAction:!0}]}function categoryFor(e){return REGISTRY_CATEGORIES.find(t=>t.value===e)}function itemsForCategory(e,t){if(t===ALL)return e;let n=categoryFor(t);return n===void 0?e:e.filter(e=>e.address.startsWith(n.prefix)||e.name.startsWith(n.prefix))}function stringArray(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`):[]}function itemSource(e){if(e.startsWith(`@`))return e.split(`/`)[0]??e;if(/^https?:\/\//u.test(e))try{return new URL(e).host}catch{return e}return`Vercel`}function manifestRecord(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:{}}function summarizeDetails(e,t=3){let n=e.slice(0,t),r=e.length-n.length;return r>0?`${n.join(`, `)} … (+${r} more)`:n.join(`, `)}function itemDetails(e,t){let n=[{label:`Source`,value:e.source}],r=[...stringArray(t.dependencies),...stringArray(t.devDependencies),...stringArray(t.registryDependencies)];r.length>0&&n.push({label:`Packages`,value:summarizeDetails(r)});let i=t.envVars;if(typeof i==`object`&&i&&!Array.isArray(i)){let e=Object.keys(i);e.length>0&&n.push({label:`Environment`,value:summarizeDetails(e)})}let a=(Array.isArray(t.files)?t.files:[]).flatMap(e=>{if(typeof e!=`object`||!e||Array.isArray(e))return[];let t=e.target;return typeof t==`string`?[t]:[]});return a.length>0&&n.push({label:`Files`,value:summarizeDetails(a)}),n}async function inspectItem(e,n,r,i,a,o){let s=a??manifestRecord(await withSpinner(e,`Loading registry item…`,()=>n.getRegistryItemManifest(r,i.address)));for(;;){let t={message:typeof s.title==`string`?s.title:i.name,metadata:itemDetails(i,s),options:[{value:`add`,label:`Add to project`},{value:`back`,label:`Back`}]},a=typeof s.description==`string`?s.description:i.description;if(a!==void 0&&(t.description=a),await e.select(t)===`back`)return{kind:`back`};let c=e.log.spinner?.(`Installing ${itemLabel(i)} and dependencies…`);try{c?.stop();let install=()=>n.installRegistryItem(r,i.address,{silent:!0,prompter:e,signal:o});return{kind:`added`,output:await(e.withExclusiveTerminal?.(install)??install())}}finally{c?.stop()}}}async function resolveAddressItem(e,n,r,i){let a=manifestRecord(await withSpinner(e,`Loading registry item…`,()=>n.getRegistryItemManifest(r,i))),o={address:i,name:typeof a.name==`string`?a.name:i,source:itemSource(i)};return typeof a.type==`string`&&(o.type=a.type),typeof a.description==`string`&&(o.description=a.description),{item:o,manifest:a}}async function runRegistryFlow(a){let o;(a.deps?.browseRegistryCatalog===void 0||a.deps.getRegistryItemManifest===void 0||a.deps.installRegistryItem===void 0)&&(o=await import(`#cli/commands/registry.js`));let s={browseRegistryCatalog:a.deps?.browseRegistryCatalog??o.browseRegistryCatalog,getRegistryItemManifest:a.deps?.getRegistryItemManifest??o.getRegistryItemManifest,installRegistryItem:a.deps?.installRegistryItem??o.installRegistryItem},c=[];try{for(;;){a.signal?.throwIfAborted();let e=await withSpinner(a.prompter,`Loading registry…`,()=>s.browseRegistryCatalog(a.appRoot));c=[...c,...e.errors.map(e=>({tone:`warning`,text:`${e.registry}: ${e.message}`}))];let o=await a.prompter.select({message:`Add an integration`,options:categoryRows(),hintLayout:`inline`,notices:c});if(c=[],o===DONE)return{kind:`done`,addedItems:[]};let l=itemsForCategory(e.items,o),u=itemRows(l);u.push({value:BACK,label:`Back`,trailingAction:!0});let d=await a.prompter.select({message:categoryFor(o)?.browseLabel??`Browse integrations`,options:u,search:!0,placeholder:`Search integrations or enter an item address`,searchAction:{label:e=>`Add “${e}”`,value:e=>`${ADDRESS_PREFIX}${e.trim()}`},hintLayout:`inline`});if(d===BACK)continue;let f=d.startsWith(ADDRESS_PREFIX)?await resolveAddressItem(a.prompter,s,a.appRoot,d.slice(8)):{item:l[Number(d.slice(5))]};if(f.item===void 0)throw Error(`The selected registry item is no longer available.`);let p=await inspectItem(a.prompter,s,a.appRoot,f.item,`manifest`in f?f.manifest:void 0,a.signal);if(p.kind===`added`)return p.output.length===0?{kind:`done`,addedItems:[f.item.address]}:{kind:`done`,addedItems:[f.item.address],output:p.output}}}catch(t){if(t instanceof WizardCancelledError)return{kind:`cancelled`};throw t}}export{runRegistryFlow};
@@ -3,7 +3,7 @@
3
3
  * `eve add channel/slack`.
4
4
  *
5
5
  * Channel *identity* (slug, name, and whether it is scaffoldable) is owned by
6
- * `@vercel/eve-catalog`, the cross-surface source of truth shared with the docs
6
+ * `@eve/catalog`, the cross-surface source of truth shared with the docs
7
7
  * gallery. This module overlays the scaffolder-only concerns — the internal
8
8
  * {@link ChannelKind} (the catalog's `eve` web-chat channel is surfaced to users
9
9
  * as `web`), the picker copy, and the picker order — and validates that the
@@ -25,7 +25,7 @@ export interface ScaffoldableChannel {
25
25
  }
26
26
  /**
27
27
  * Channels the CLI can scaffold, in picker order. Derived from
28
- * `@vercel/eve-catalog` (`surfaces.scaffoldable`) overlaid with
28
+ * `@eve/catalog` (`surfaces.scaffoldable`) overlaid with
29
29
  * {@link CHANNEL_SCAFFOLDS}. Throws at module load if the two disagree.
30
30
  */
31
31
  export declare const SCAFFOLDABLE_CHANNELS: readonly ScaffoldableChannel[];
@@ -1 +1 @@
1
- import{channelEntries}from"../../packages/eve-catalog/src/index.js";const CHANNEL_SCAFFOLDS=[{slug:`eve`,kind:`web`,registryItem:`channel/web`,label:`Web Chat`,hint:`Next.js app`},{slug:`slack`,kind:`slack`,registryItem:`channel/slack`,label:`Slack`,hint:`Slack app mentions and DMs`}];function buildScaffoldableChannels(){let n=new Set(channelEntries().filter(e=>e.surfaces.scaffoldable).map(e=>e.slug)),r=[];for(let e of CHANNEL_SCAFFOLDS){if(!n.delete(e.slug))throw Error(`Channel overlay "${e.slug}" is not a scaffoldable channel in @vercel/eve-catalog.`);let t={slug:e.slug,kind:e.kind,registryItem:e.registryItem,label:e.label};e.hint!==void 0&&(t.hint=e.hint),r.push(t)}if(n.size>0){let e=[...n].sort().join(`, `);throw Error(`Scaffoldable catalog channels missing a scaffolder overlay: ${e}.`)}return r}const SCAFFOLDABLE_CHANNELS=buildScaffoldableChannels();export{SCAFFOLDABLE_CHANNELS};
1
+ import{channelEntries}from"../../packages/eve-catalog/src/index.js";const CHANNEL_SCAFFOLDS=[{slug:`eve`,kind:`web`,registryItem:`channel/web`,label:`Web Chat`,hint:`Next.js app`},{slug:`slack`,kind:`slack`,registryItem:`channel/slack`,label:`Slack`,hint:`Slack app mentions and DMs`}];function buildScaffoldableChannels(){let n=new Set(channelEntries().filter(e=>e.surfaces.scaffoldable).map(e=>e.slug)),r=[];for(let e of CHANNEL_SCAFFOLDS){if(!n.delete(e.slug))throw Error(`Channel overlay "${e.slug}" is not a scaffoldable channel in @eve/catalog.`);let t={slug:e.slug,kind:e.kind,registryItem:e.registryItem,label:e.label};e.hint!==void 0&&(t.hint=e.hint),r.push(t)}if(n.size>0){let e=[...n].sort().join(`, `);throw Error(`Scaffoldable catalog channels missing a scaffolder overlay: ${e}.`)}return r}const SCAFFOLDABLE_CHANNELS=buildScaffoldableChannels();export{SCAFFOLDABLE_CHANNELS};
@@ -3,7 +3,7 @@
3
3
  * `eve connections add` picker and the per-entry scaffold template.
4
4
  *
5
5
  * Connection *identity* (slug, label, transport, description) is owned by
6
- * `@vercel/eve-catalog`, the cross-surface source of truth shared with the
6
+ * `@eve/catalog`, the cross-surface source of truth shared with the
7
7
  * docs gallery. This module overlays the scaffolder-only concern — the Connect
8
8
  * auth spec to emit — and shapes the result into {@link ConnectionCatalogEntry}.
9
9
  *
@@ -11,7 +11,7 @@
11
11
  * entries can be scaffolded later by widening {@link SUPPORTED_PROTOCOLS}, with
12
12
  * no command-surface change.
13
13
  */
14
- import { type ConnectionProtocol } from "@vercel/eve-catalog";
14
+ import { type ConnectionProtocol } from "@eve/catalog";
15
15
  /** Wire protocol a connection speaks at runtime. */
16
16
  export type { ConnectionProtocol };
17
17
  /** Protocols the scaffolder can currently emit. */
@@ -1,4 +1,4 @@
1
- import{pinnedNodeEngineMajor}from"../../node-engine.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.38`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.4.3`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.29.4`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
1
+ import{pinnedNodeEngineMajor}from"../../node-engine.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.38`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.4.3`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.30.0`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
2
2
 
3
3
  export default defineAgent({
4
4
  model: "__EVE_INIT_MODEL__",
@@ -165,6 +165,13 @@ export interface AgentLimitsDefinition {
165
165
  * These options are unstable and may change or be removed in any release.
166
166
  */
167
167
  export interface AgentExperimentalDefinition {
168
+ /**
169
+ * Keeps this agent's delegated subagent sessions alive after they answer.
170
+ * The model can pass `agentId` to a subagent tool to continue a previous
171
+ * delegation, and the system prompt documents the `<agents>` listing.
172
+ * When unset, delegated children run as one-shot tasks.
173
+ */
174
+ readonly subagentPersistentSessions?: boolean;
168
175
  /**
169
176
  * Durable Workflow runtime configuration. Root agents may use this to select
170
177
  * the Workflow world backing sessions and runs.
@@ -0,0 +1,47 @@
1
+ import { z } from "#compiled/zod/index.js";
2
+ import type { JsonValue } from "#shared/json.js";
3
+ import { type TokenUsage } from "#shared/token-usage.js";
4
+ /**
5
+ * What one delegated child turn produced, independent of whether the child
6
+ * session survived it.
7
+ */
8
+ export type AgentTurnResult = {
9
+ readonly kind: "succeeded";
10
+ readonly output: JsonValue;
11
+ } | {
12
+ readonly kind: "failed";
13
+ readonly error: JsonValue;
14
+ } | {
15
+ readonly kind: "cancelled";
16
+ };
17
+ /**
18
+ * How one delegated child turn settled.
19
+ *
20
+ * `parked` means the child session survived the turn and can accept another
21
+ * delivery; `terminal` means the child session ended with this turn. The
22
+ * lifecycle is carried explicitly: a failed turn can leave the child parked,
23
+ * and a succeeded turn can be terminal (task mode). Consumers must never
24
+ * infer lifecycle from success or error codes.
25
+ *
26
+ * `usageDelta` is the provider-reported usage this turn added to the child's
27
+ * session subtree: the child captures its session totals at turn entry and
28
+ * reports final-minus-entry when the turn settles. The parent folds each
29
+ * delta exactly once, so repeated turns of a persistent child never re-report
30
+ * earlier turns.
31
+ */
32
+ export type AgentTurnOutcome = {
33
+ readonly kind: "parked";
34
+ readonly result: AgentTurnResult;
35
+ readonly usageDelta: TokenUsage;
36
+ } | {
37
+ readonly kind: "terminal";
38
+ readonly result: AgentTurnResult;
39
+ readonly usageDelta: TokenUsage;
40
+ };
41
+ /**
42
+ * Zod schema for {@link AgentTurnOutcome}.
43
+ *
44
+ * Validates outcomes crossing the process boundary (remote session
45
+ * callbacks). Local notification paths construct the type directly.
46
+ */
47
+ export declare const agentTurnOutcomeSchema: z.ZodType<AgentTurnOutcome>;
@@ -0,0 +1 @@
1
+ import{z}from"#compiled/zod/index.js";import{tokenUsageSchema}from"#shared/token-usage.js";const jsonValueSchema=z.lazy(()=>z.union([z.null(),z.boolean(),z.number(),z.string(),z.array(jsonValueSchema),z.record(z.string(),jsonValueSchema)])),agentTurnResultSchema=z.discriminatedUnion(`kind`,[z.strictObject({kind:z.literal(`succeeded`),output:jsonValueSchema}),z.strictObject({error:jsonValueSchema,kind:z.literal(`failed`)}),z.strictObject({kind:z.literal(`cancelled`)})]),agentTurnOutcomeSchema=z.discriminatedUnion(`kind`,[z.strictObject({kind:z.literal(`parked`),result:agentTurnResultSchema,usageDelta:tokenUsageSchema}),z.strictObject({kind:z.literal(`terminal`),result:agentTurnResultSchema,usageDelta:tokenUsageSchema})]);export{agentTurnOutcomeSchema};
@@ -116,7 +116,7 @@ export declare const DYNAMIC_SENTINEL_KIND: "eve:dynamic";
116
116
  /**
117
117
  * Return value of `defineDynamic`: the runtime shape of a dynamic export,
118
118
  * stamped with a sentinel kind the compiler/normalizer detects. `TFallback`
119
- * is `never` except for dynamic agent models, the only slot with a fallback.
119
+ * is used by dynamic agent models.
120
120
  */
121
121
  export type DynamicSentinel<TResult = unknown, TFallback = never> = {
122
122
  readonly kind: typeof DYNAMIC_SENTINEL_KIND;
@@ -124,10 +124,6 @@ export type DynamicSentinel<TResult = unknown, TFallback = never> = {
124
124
  } & ([TFallback] extends [never] ? object : {
125
125
  readonly fallback: TFallback;
126
126
  });
127
- /**
128
- * Throws when a dynamic sentinel outside the agent `model` slot carries a
129
- * `fallback` — anywhere else it would be silently dead configuration.
130
- */
131
127
  export declare function rejectDynamicSentinelFallback(sentinel: DynamicSentinel, message: string): void;
132
128
  export declare function isDynamicSentinel(value: unknown): value is DynamicSentinel;
133
129
  /**
@@ -1 +1 @@
1
- const ALLOWED_DYNAMIC_TOOL_EVENTS=new Set([`session.started`,`turn.started`,`step.started`]),ALLOWED_DYNAMIC_INSTRUCTION_EVENTS=new Set([`session.started`,`turn.started`]),ALLOWED_DYNAMIC_SKILL_EVENTS=new Set([`session.started`,`turn.started`]),DYNAMIC_SENTINEL_KIND=`eve:dynamic`;function rejectDynamicSentinelFallback(e,t){if(`fallback`in e)throw Error(`${t} "fallback" is only supported on a dynamic agent model (the "model" field in agent.ts). For dynamic tools, skills, and instructions, author a static entry as the default or return null.`)}function isDynamicSentinel(e){return typeof e==`object`&&!!e&&e.kind===`eve:dynamic`}const TOOL_BRAND=Symbol.for(`eve:tool-brand`);function isBrandedToolEntry(e){return typeof e==`object`&&!!e&&e[TOOL_BRAND]===!0}const INSTRUCTIONS_BRAND=Symbol.for(`eve:instructions-brand`);function isBrandedInstructionsEntry(e){return typeof e==`object`&&!!e&&e[INSTRUCTIONS_BRAND]===!0}const SKILL_BRAND=Symbol.for(`eve:skill-brand`);function isBrandedSkillEntry(e){return typeof e==`object`&&!!e&&e[SKILL_BRAND]===!0}export{ALLOWED_DYNAMIC_INSTRUCTION_EVENTS,ALLOWED_DYNAMIC_SKILL_EVENTS,ALLOWED_DYNAMIC_TOOL_EVENTS,DYNAMIC_SENTINEL_KIND,INSTRUCTIONS_BRAND,SKILL_BRAND,TOOL_BRAND,isBrandedInstructionsEntry,isBrandedSkillEntry,isBrandedToolEntry,isDynamicSentinel,rejectDynamicSentinelFallback};
1
+ const ALLOWED_DYNAMIC_TOOL_EVENTS=new Set([`session.started`,`turn.started`,`step.started`]),ALLOWED_DYNAMIC_INSTRUCTION_EVENTS=new Set([`session.started`,`turn.started`]),ALLOWED_DYNAMIC_SKILL_EVENTS=new Set([`session.started`,`turn.started`]),DYNAMIC_SENTINEL_KIND=`eve:dynamic`;function rejectDynamicSentinelFallback(e,t){if(`fallback`in e)throw Error(`${t} "fallback" is only supported on a dynamic agent model. For dynamic tools, skills, instructions, and subagents, return null when the capability should be omitted.`)}function isDynamicSentinel(e){return typeof e==`object`&&!!e&&e.kind===`eve:dynamic`}const TOOL_BRAND=Symbol.for(`eve:tool-brand`);function isBrandedToolEntry(e){return typeof e==`object`&&!!e&&e[TOOL_BRAND]===!0}const INSTRUCTIONS_BRAND=Symbol.for(`eve:instructions-brand`);function isBrandedInstructionsEntry(e){return typeof e==`object`&&!!e&&e[INSTRUCTIONS_BRAND]===!0}const SKILL_BRAND=Symbol.for(`eve:skill-brand`);function isBrandedSkillEntry(e){return typeof e==`object`&&!!e&&e[SKILL_BRAND]===!0}export{ALLOWED_DYNAMIC_INSTRUCTION_EVENTS,ALLOWED_DYNAMIC_SKILL_EVENTS,ALLOWED_DYNAMIC_TOOL_EVENTS,DYNAMIC_SENTINEL_KIND,INSTRUCTIONS_BRAND,SKILL_BRAND,TOOL_BRAND,isBrandedInstructionsEntry,isBrandedSkillEntry,isBrandedToolEntry,isDynamicSentinel,rejectDynamicSentinelFallback};
@@ -1,3 +1,3 @@
1
- import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-8mofdZcO.js";
1
+ import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-BXMIf5fR.js";
2
2
 
3
3
  export { defaultMessageReducer, useEveAgent };
@@ -1,3 +1,3 @@
1
- import { t as useEveAgent } from "../chunks/use-eve-agent-8mofdZcO.js";
1
+ import { t as useEveAgent } from "../chunks/use-eve-agent-BXMIf5fR.js";
2
2
 
3
3
  export { useEveAgent };
@@ -1,3 +1,3 @@
1
- import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-bKJbH0k4.js";
1
+ import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-k-XHfrJT.js";
2
2
 
3
3
  export { defaultMessageReducer, useEveAgent };
@@ -1,3 +1,3 @@
1
- import { t as useEveAgent } from "../chunks/use-eve-agent-bKJbH0k4.js";
1
+ import { t as useEveAgent } from "../chunks/use-eve-agent-k-XHfrJT.js";
2
2
 
3
3
  export { useEveAgent };
@@ -48,6 +48,8 @@ Declare routes with the `POST()` and `GET()` helpers. Each route handler receive
48
48
 
49
49
  - `send(message, { auth, continuationToken, state?, title? })` starts or resumes a session. `title` overrides the new workflow session's display title without changing the model message. Returns a `Session`.
50
50
  - `cancel({ continuationToken, turnId? })` requests cancellation of the active turn on the session that owns the token. See [Cancel a turn](#cancel-a-turn).
51
+ - `clear({ continuationToken })` removes the model-message history while preserving the session and its durable resources. See [Clear session context](#clear-session-context).
52
+ - `compact({ continuationToken })` queues context compaction for the session that owns the token without sending model input. See [Compact a session](#compact-a-session).
51
53
  - `reset({ continuationToken, reason? })` retires the session that owns the token so the next `send()` starts a fresh session. See [Reset a session](#reset-a-session).
52
54
  - `getSession(sessionId)` looks up an existing session. The returned `Session` exposes `getEventStream({ startIndex? })` for streaming, `getStreamTailIndex()` for resolving the durable tail when a route wants to serve bounded reads, and `cancel({ turnId? })` for session-id-addressed cancellation.
53
55
  - `receive(channel, ...)` hands inbound work to a different channel for cross-channel hand-off.
@@ -86,6 +88,44 @@ Semantics:
86
88
 
87
89
  When you already hold a `Session` — returned by `send()` or `getSession(sessionId)` — call `session.cancel({ turnId? })` to request the same cancellation addressed by session id.
88
90
 
91
+ ## Clear session context
92
+
93
+ Call `clear` with the channel-local continuation token to remove a session's durable model-message history without replacing the session:
94
+
95
+ ```ts
96
+ import { defineChannel, POST } from "eve/channels";
97
+
98
+ export default defineChannel({
99
+ routes: [
100
+ POST("/threads/:threadId/clear", async (_req, { clear, params }) => {
101
+ const result = await clear({ continuationToken: params.threadId });
102
+ return Response.json(result);
103
+ }),
104
+ ],
105
+ });
106
+ ```
107
+
108
+ `"accepted"` means the clear was queued. The stream emits `context.cleared` followed by `session.waiting`, after which the next ordinary message resumes the same session with no prior model messages. The system prompt, configured tools and skills, durable state, limits, continuation-token ownership, and session-scoped sandbox remain. `"no_active_session"` means the token has no current owner.
109
+
110
+ ## Compact a session
111
+
112
+ Call `compact` with the channel-local continuation token to summarize durable conversation history without delivering a command to the model:
113
+
114
+ ```ts
115
+ import { defineChannel, POST } from "eve/channels";
116
+
117
+ export default defineChannel({
118
+ routes: [
119
+ POST("/threads/:threadId/compact", async (_req, { compact, params }) => {
120
+ const result = await compact({ continuationToken: params.threadId });
121
+ return Response.json(result);
122
+ }),
123
+ ],
124
+ });
125
+ ```
126
+
127
+ `"accepted"` means the durable session queued the operation. A successful compaction emits `compaction.requested` followed by `compaction.completed`, then the operation returns through `session.waiting`. If summarization fails, the stream returns through `session.waiting` without `compaction.completed` and preserves the previous history. If a turn is active, eve runs the compaction after that turn settles; it does not cancel the turn. `"no_active_session"` means the token has no current owner. Both outcomes are successful, and compaction never starts a session or appends a synthetic user message.
128
+
89
129
  ## Reset a session
90
130
 
91
131
  Identity-addressed channels can consume commands such as `/new` in their route, without sending the command to the model. Call `reset` with the same channel-local continuation token used by `send()`:
@@ -160,7 +200,7 @@ export default defineChannel({
160
200
  });
161
201
  ```
162
202
 
163
- `WS()` handlers receive the same helpers as HTTP route handlers: `send`, `cancel`, `reset`, `getSession`, `receive`, `params`, `waitUntil`, and `requestIp`. The returned hooks are eve-owned structural types compatible with Nitro/H3 websocket routing, including `upgrade`, `open`, `message`, `close`, and `error`.
203
+ `WS()` handlers receive the same helpers as HTTP route handlers: `send`, `cancel`, `clear`, `compact`, `reset`, `getSession`, `receive`, `params`, `waitUntil`, and `requestIp`. The returned hooks are eve-owned structural types compatible with Nitro/H3 websocket routing, including `upgrade`, `open`, `message`, `close`, and `error`.
164
204
 
165
205
  ### Node upgrade server escape hatch
166
206
 
@@ -18,13 +18,16 @@ export default eveChannel({
18
18
 
19
19
  ## Routes
20
20
 
21
- The application exposes a health route plus eve channel routes that inspect the agent, create sessions, send follow-ups, cancel turns, and stream events:
21
+ The application exposes a health route plus eve channel routes that inspect the agent, create sessions, send follow-ups, cancel turns, compact or reset sessions, and stream events:
22
22
 
23
23
  - `GET /eve/v1/health`
24
24
  - `GET /eve/v1/info`
25
25
  - `POST /eve/v1/session` (start a session)
26
26
  - `POST /eve/v1/session/:sessionId` (send a follow-up)
27
27
  - `POST /eve/v1/session/:sessionId/cancel` (cancel the in-flight turn)
28
+ - `POST /eve/v1/session/clear` (clear the continuation owner's model history)
29
+ - `POST /eve/v1/session/compact` (compact the continuation owner's context)
30
+ - `POST /eve/v1/session/reset` (retire the continuation owner)
28
31
  - `GET /eve/v1/session/:sessionId/stream` (stream events, NDJSON)
29
32
 
30
33
  Start a session with a minimal body. The response returns `sessionId` and the `continuationToken` you reuse for follow-ups:
@@ -54,6 +57,28 @@ curl -X POST https://<deployment>/eve/v1/session/ses_01h.../cancel
54
57
 
55
58
  Cancellation is asynchronous: `"accepted"` means a cancellation hook accepted the request. Confirm the effective outcome on the stream as `turn.cancelled` followed by `session.waiting` — never as a failure. Active local and remote subagents are cancelled recursively before the parent settles; their own streams carry their cancellation boundaries, and cancelled work does not emit `subagent.completed` on the parent. Content emitted before the cancel stays on the event stream, while durable model history keeps only content that had already settled. The session accepts the next message normally. When there is no resumable cancellation target (including an unknown session, a settled turn, or a duplicate cancel), the route responds with `"no_active_turn"` — also a success, so a stop button can fire and forget. A `turnId` naming any other turn is accepted and consumed as a no-op, so a guarded cancel racing a turn boundary cannot stop a turn the caller never saw.
56
59
 
60
+ Clear the model-message history of the session that owns a continuation token:
61
+
62
+ ```bash
63
+ curl -X POST https://<deployment>/eve/v1/session/clear \
64
+ -H "Content-Type: application/json" \
65
+ -d '{"continuationToken":"eve:7f3c..."}'
66
+ # {"ok":true,"sessionId":"ses_01h...","status":"accepted"}
67
+ ```
68
+
69
+ An accepted clear emits `context.cleared` followed by `session.waiting`. The next message resumes the same session without prior model messages; the system prompt, tools and skills, durable state, limits, and session-scoped sandbox remain.
70
+
71
+ Compact the session that owns a continuation token without sending a message:
72
+
73
+ ```bash
74
+ curl -X POST https://<deployment>/eve/v1/session/compact \
75
+ -H "Content-Type: application/json" \
76
+ -d '{"continuationToken":"eve:7f3c..."}'
77
+ # {"ok":true,"sessionId":"ses_01h...","status":"accepted"}
78
+ ```
79
+
80
+ Compaction is asynchronous. A successful operation emits `compaction.requested` and `compaction.completed`, then returns through `session.waiting`; when a turn is active, the operation waits for it to settle. If summarization fails, the session still returns to `session.waiting` with its previous history. `"no_active_session"` is the successful no-op response when the token has no owner.
81
+
57
82
  See [Sessions, runs & streaming](../concepts/sessions-runs-and-streaming) for the full request and stream flow, including the complete event set.
58
83
 
59
84
  ## CORS
@@ -88,7 +113,7 @@ The `auth` option decides who can call `/eve/v1/info` and the session routes. Th
88
113
 
89
114
  Neither admits browser users or external clients in production. For a public app, wire the channel to your own auth (Clerk, Auth.js, your own OIDC/JWT verification, an API-key verifier, or any custom `AuthFn`). Vercel OIDC is optional; use it only when Vercel-issued deployment tokens are part of your trust model.
90
115
 
91
- `eve init` scaffolds an `agent/channels/eve.ts` with a production placeholder so you replace it before going live. The generated channel checks Vercel OIDC before falling back to localhost access, and includes `placeholderAuth()`, which returns a setup-focused 401 in production until you swap it for real auth. Delete the file and eve falls back to `[vercelOidc(), localDev()]`, which still does not admit browser users in production.
116
+ `eve init` scaffolds an `agent/channels/eve.ts` with a production placeholder so you replace it before going live. The generated channel checks Vercel OIDC before falling back to localhost access, and includes `placeholderAuth()`, which returns a setup-focused 401 in production until you swap it for real auth. Delete the file and eve falls back to `[vercelOidc(), localDev(), placeholderAuth()]`, which rejects all production traffic.
92
117
 
93
118
  For the full auth model and helper list, see [Auth & route protection](../guides/auth-and-route-protection).
94
119
 
@@ -20,6 +20,10 @@ export default defineAgent({
20
20
 
21
21
  Compaction also preserves the framework's own tool state automatically. It resets read-before-write tracking (so a write afterward re-reads the file whose read evidence was summarized away) and re-injects the active todo list, so the model keeps its task list across the summary. There is no per-tool hook to configure.
22
22
 
23
+ Clients and channels can also request compaction between turns. Call `ClientSession.compact()` or a custom route's `compact({ continuationToken })` helper. The request does not append a user message; if a turn is running, eve queues it until that turn settles. A successful manual compaction emits the same `compaction.requested` and `compaction.completed` events as automatic compaction, followed by `session.waiting`.
24
+
25
+ To discard model-message history instead of summarizing it, call `ClientSession.clear()` or a custom route's `clear({ continuationToken })` helper. Clearing preserves the session identity, system prompt, configured tools and skills, durable state, limits, and sandbox. Its stream boundary is `context.cleared` followed by `session.waiting`.
26
+
23
27
  ## Built-in tools
24
28
 
25
29
  Built-in tools require no imports. The exact set depends on the agent and session. `agent` is available only in the root session; `load_skill` and `connection_search` appear only when the agent declares the corresponding resources; `ask_question` requires a session that can request user input; and `web_search` requires a supported model provider. The harness advertises only the tools available to the current session.
@@ -208,7 +208,7 @@ Start with the [TypeScript SDK](../guides/client/overview) guide. It covers basi
208
208
  curl http://127.0.0.1:2000/eve/v1/info
209
209
  ```
210
210
 
211
- With the default auth chain (`[vercelOidc(), localDev()]`), a local Vercel OIDC bearer takes precedence and other local requests fall back to development access. A deployed Vercel target requires a valid OIDC bearer, with a same-project bypass for in-deployment callers. See [auth & route protection](../guides/auth-and-route-protection).
211
+ With the default auth chain (`[vercelOidc(), localDev(), placeholderAuth()]`), a Vercel OIDC bearer takes precedence, an `eve dev` or `vercel dev` server authenticates local requests, and everything else is rejected. A deployed Vercel target requires a valid OIDC bearer, with a same-project bypass for in-deployment callers. See [auth & route protection](../guides/auth-and-route-protection).
212
212
 
213
213
  ## Dispatch order
214
214
 
@@ -18,7 +18,7 @@ The route-auth policy lives on the HTTP channel factory (`agent/channels/eve.ts`
18
18
  - `POST /eve/v1/session/:sessionId`
19
19
  - `GET /eve/v1/session/:sessionId/stream`
20
20
 
21
- These routes are protected by the channel's auth policy. eve fails closed by default: production browser traffic is rejected unless you configure an authenticator that accepts it, and anonymous access requires an explicit `none()`.
21
+ These routes are protected by the channel's auth policy. eve fails closed by default: production traffic is rejected unless you configure an authenticator that accepts it, and anonymous access requires an explicit `none()`.
22
22
 
23
23
  `GET /eve/v1/health` is always public and skips the walk entirely, so load balancers and uptime monitors can probe it without credentials.
24
24
 
@@ -86,15 +86,15 @@ Any other thrown error follows the normal channel failure path. When building a
86
86
 
87
87
  `eve/channels/auth` ships these channel-auth helpers:
88
88
 
89
- | Helper | Use when |
90
- | ---------------- | ------------------------------------------------------------------------- |
91
- | `localDev()` | Local development. Accepts requests addressed to a loopback hostname. |
92
- | `vercelOidc()` | The common Vercel deployment path. Verifies a Vercel OIDC bearer JWT. |
93
- | `none()` | You want to accept anonymous traffic explicitly (use as the final entry). |
94
- | `httpBasic(...)` | Operator or service access via a shared username/password. |
95
- | `jwtHmac(...)` | You control a shared-secret JWT signer. |
96
- | `jwtEcdsa(...)` | You verify asymmetric JWTs minted by another system. |
97
- | `oidc(...)` | You want eve to verify OIDC-issued tokens from an arbitrary issuer. |
89
+ | Helper | Use when |
90
+ | ---------------- | -------------------------------------------------------------------------------------------------- |
91
+ | `localDev()` | Local development. Accepts requests only while the process is an `eve dev` or `vercel dev` server. |
92
+ | `vercelOidc()` | The common Vercel deployment path. Verifies a Vercel OIDC bearer JWT. |
93
+ | `none()` | You want to accept anonymous traffic explicitly (use as the final entry). |
94
+ | `httpBasic(...)` | Operator or service access via a shared username/password. |
95
+ | `jwtHmac(...)` | You control a shared-secret JWT signer. |
96
+ | `jwtEcdsa(...)` | You verify asymmetric JWTs minted by another system. |
97
+ | `oidc(...)` | You want eve to verify OIDC-issued tokens from an arbitrary issuer. |
98
98
 
99
99
  `httpBasic(credentials, { realm })` accepts an optional `realm`, rendered on the `WWW-Authenticate: Basic` challenge (e.g. `Basic realm="agent", charset="UTF-8"`) so browsers label their native login prompt. It defaults to `"eve"`, ensuring every Basic challenge includes the required realm. Usernames and passwords are normalized to Unicode NFC before comparison, matching the advertised UTF-8 credential encoding.
100
100
 
@@ -102,9 +102,9 @@ Exercise caution for agents that process non-public, sensitive, regulated, or pr
102
102
 
103
103
  ### `localDev()`
104
104
 
105
- Authenticates a synthetic `local-dev` principal, but only when the inbound request is addressed to a loopback hostname (`localhost`, `*.localhost`, `127.0.0.0/8`, or `::1`). The check keys off the request URL's hostname rather than the bare `process.env.VERCEL` flag, and that's deliberate: a deployment outside Vercel leaves `VERCEL` unset, so sniffing that flag alone would wave through all public traffic. There's one process-level exception. `vercel dev`, detected by `VERCEL=1` and `VERCEL_ENV=development` together, opens the local dev server even when it serves over a non-loopback host. Every other non-loopback request returns `null` and falls through.
105
+ Authenticates a synthetic `local-dev` principal, but only while the process is a local development server: `eve dev` (which sets `EVE_DEV=1`) or `vercel dev` (detected by `VERCEL=1` and `VERCEL_ENV=development` together). This is a property of the deployment, not the request, so no request header can flip it. A production deployment (`eve start`, a Vercel deployment, or any container host) sets neither flag, so `localDev()` authenticates nothing there and every request falls through to the next entry.
106
106
 
107
- `localDev()` trusts the advertised hostname, so an attacker who can inject a `Host` header (no normalizing proxy in front of your origin) can spoof it. Always layer a real authenticator on top; never run on `localDev()` alone.
107
+ Because it never opens a production deployment, `localDev()` is safe to leave in the walk. Still put a real authenticator ahead of it so production traffic has something to match.
108
108
 
109
109
  ### `vercelOidc()`
110
110
 
@@ -214,7 +214,7 @@ export default eveChannel({
214
214
  });
215
215
  ```
216
216
 
217
- In production, `placeholderAuth()` returns a structured `401` so a generated web chat app can say "auth isn't configured yet" instead of throwing an internal error. Replace it before a browser caller submits a production request: swap in your app's `AuthFn` or one of the shipped helpers. Delete the authored channel file entirely and eve falls back to the framework default `[vercelOidc(), localDev()]`, which also rejects production browser traffic.
217
+ In production, `placeholderAuth()` returns a structured `401` so a generated web chat app can say "auth isn't configured yet" instead of throwing an internal error. Replace it before a browser caller submits a production request: swap in your app's `AuthFn` or one of the shipped helpers. Delete the authored channel file entirely and eve falls back to the framework default `[vercelOidc(), localDev(), placeholderAuth()]`, which also rejects production traffic.
218
218
 
219
219
  You do not have to keep `vercelOidc()` in the final policy. For a self-hosted app, an app-embedded frontend, or any deployment that uses a non-Vercel identity system, use `httpBasic()`, `jwtHmac()`, `jwtEcdsa()`, generic `oidc()`, or a custom `AuthFn` that maps your verified user/session/API key into a `SessionAuthContext`.
220
220
 
@@ -19,6 +19,20 @@ const result = await response.result();
19
19
 
20
20
  Cancellation does not replace stream consumption. Continue reading the response to observe its terminal `turn.cancelled` and `session.waiting` boundary and to advance the client session cursor normally.
21
21
 
22
+ Between turns, `session.compact()` queues context compaction without sending model input. An accepted request reports the session id; consume the durable stream through the following `session.waiting` boundary before sending the next turn. `compaction.completed` confirms that summarization succeeded; without it, eve preserves the previous history. A never-started session returns `no_active_session` as a successful no-op.
23
+
24
+ ```ts
25
+ const compaction = await session.compact();
26
+ console.log(compaction.status);
27
+ ```
28
+
29
+ Use `session.clear()` to remove model-message history while retaining the session and its durable resources. Consume `context.cleared` and the following `session.waiting` before sending the next turn.
30
+
31
+ ```ts
32
+ const cleared = await session.clear();
33
+ console.log(cleared.status);
34
+ ```
35
+
22
36
  ## Aggregate a turn
23
37
 
24
38
  Use `result()` when you only need the final turn summary:
@@ -35,13 +35,16 @@ Each command echoes as an invocation line, asks through a bordered panel that ta
35
35
  | Command | Does |
36
36
  | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
37
37
  | `/model` | Opens a configure menu that loops until Done (or Esc). See [Configure the model and provider](#configure-the-model-and-provider). |
38
- | `/add` | Searches registry integrations or adds an item address entered directly. |
38
+ | `/add` | Adds an integration from the registry or an item address entered directly. |
39
39
  | `/deploy` | Ships the agent to Vercel production, linking the directory first when it is unlinked. |
40
40
  | `/vc:install` | Installs the Vercel CLI. Available locally and on a remote session. |
41
41
  | `/vc:login` | Logs in to Vercel locally. On a remote session, resolves the deployment's project, refreshes its OIDC token, and confirms any required Trusted Sources rule. |
42
42
  | `/loglevel` | Switches which logs the transcript shows. See [Control what logs show](#control-what-logs-show). |
43
43
  | `/traces` | Opens the full-screen local trace viewer. See [Inspect traces](#inspect-traces). |
44
- | `/new` | Starts a fresh session. |
44
+ | `/reset` | Starts a fresh session. |
45
+ | `/cancel` | Cooperatively cancels the running turn while preserving the session and settled context. |
46
+ | `/clear` | Clears model-message history while preserving the current session and its durable resources. `/new` is an alias. |
47
+ | `/compact` | Queues context compaction for the current session without sending a message. |
45
48
  | `/exit` | Quits the TUI. |
46
49
  | `/help` | Lists the commands available for the current local or remote session. |
47
50
 
@@ -55,11 +58,11 @@ The provider row opens one menu: AI Gateway via a project, AI Gateway via `AI_GA
55
58
 
56
59
  The provider row demands attention (a bold yellow "Configure model access" with a yellow "Not configured" hint that dims when unselected and uses the terminal foreground when selected) until a link or gateway credential is detected, then names the connection afterward (for example "AI Gateway (Linked to my-project in my-team)"). Setup menus mark the cursor row with a padded, filled-arrow inverse label that inherits the row's accent: blue normally and yellow for warning rows. In stacked menus, the selected row's description appears directly beneath that option. The completed command's outcome stays in the transcript after the panel closes. When a turn fails because AI Gateway authentication is missing or stale, the error points you at `/model` directly.
57
60
 
58
- ### Browse registry integrations
61
+ ### Add registry integrations
59
62
 
60
- `/add` first organizes integrations by what they add: a way to chat, tools and data, capabilities, or observability. Pick a category to open its searchable catalog from the official eve registry and the registry namespaces configured in `package.json`, or browse everything. Each integration shows its source beside its name, such as `Vercel` or a configured registry namespace. Select a result to review its source, packages, environment variables, and target files before adding it, or type an official item path, configured namespace address, or HTTP(S) URL directly into the search bar. After an add attempt finishes, the panel closes instead of returning to the catalog.
63
+ `/add` groups integrations by their role: **Channels** for where people talk to your agent, **MCP connections** for external services and data, **Extensions** for reusable capabilities, and **Observability** for tracing and evaluation. Pick a category to open its searchable catalog from the official eve registry and the registry namespaces configured in `package.json`, or browse every integration. Each result shows its source beside its name, such as `Vercel` or a configured registry namespace. Select a result to review its source, packages, environment variables, and target files before adding it, or enter an official item path, configured namespace address, or HTTP(S) URL directly in the search bar. After an add attempt finishes, the panel closes instead of returning to the catalog.
61
64
 
62
- Connection registry items install their definition and then configure Vercel Connect through the same `/add` flow. If the directory is unlinked, setup first offers to create or link a project. Run `eve add connection/<name>` for the equivalent CLI flow.
65
+ MCP connection registry items install their definition and then configure Vercel Connect through the same `/add` flow. If the directory is unlinked, setup first offers to create or link a project. Run `eve add connection/<name>` for the equivalent CLI flow.
63
66
 
64
67
  ## Keyboard shortcuts
65
68
 
@@ -68,9 +71,9 @@ Chat and freeform `ask_question` inputs behave like a shell line editor.
68
71
  | Key | Action |
69
72
  | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
70
73
  | `Enter` | Submit the message or question response. While a turn is running, queue the message for the next turn. |
71
- | `Esc` | While a turn runs: pop the oldest queued message and steer with it; with nothing queued, press twice to cancel. |
74
+ | `Esc` | While a turn runs: pop the oldest queued message and steer with it; with nothing queued, cancel the turn. |
72
75
  | `Shift+Enter` | Insert a newline without sending (needs a terminal that reports modified keys). |
73
- | `Ctrl+C` | Interrupt a running turn. At the chat or freeform-question prompt, clear non-empty input; when empty, quit. |
76
+ | `Ctrl+C` | While a turn runs, behave like Esc. At the idle chat prompt, clear input and arm exit; press again to quit. |
74
77
  | `↑` / `↓` | Move between input lines; at a chat-buffer edge, navigate messages you have sent this session. |
75
78
  | `←` / `→`, `Home` / `End`, `Ctrl+A` / `Ctrl+E` | Move the caret; Home/End stay within the current line. |
76
79
  | `Ctrl+U` / `Ctrl+K` / `Ctrl+W` | Delete to the start of the line, to its end, or through the previous word. |
@@ -81,9 +84,9 @@ In terminals that support bracketed paste, pasting multi-line text into chat or
81
84
 
82
85
  ### Queue and steer while the agent works
83
86
 
84
- Sending a message while a turn is still running does not interrupt it — the message joins a queue of up to five, pinned in a panel directly above the input with one line per message. When the turn ends, the queued messages coalesce into the next turn's message.
87
+ Sending a message while a turn is still running does not interrupt it — the message joins a queue of up to five, pinned in a panel directly above the input with one line per message. When the turn ends, the queued messages coalesce into the next turn's message. Submit `/cancel` during a turn to cancel it immediately without queueing the command as model input; `/cancel` also works from the idle prompt when a prior stream disconnected while its server turn may still be running.
85
88
 
86
- `Esc` steers instead of waiting: it pops the oldest queued message, cancels the running turn cooperatively, and submits the popped message as the replacement turn. In the transcript, a steered message carries an accent `↑` on its own line above its gutter bar; a queued message that waited for the boundary carries it below. Any remaining messages stay queued behind it. With nothing queued, the first `Esc` arms cancellation and a second `Esc` cancels the turn. Unlike `Ctrl+C` — which drops the stream client-side — a cancelled turn ends cleanly on the server and the session keeps its context; the conversation picks up at the next prompt.
89
+ `Esc` and `Ctrl+C` steer instead of waiting: either key pops the oldest queued message, cancels the running turn cooperatively, and submits the popped message as the replacement turn. In the transcript, a steered message carries an accent `↑` on its own line above its gutter bar; a queued message that waited for the boundary carries it below. Any remaining messages stay queued behind it. With nothing queued, either key cancels the turn immediately. A cancelled turn ends cleanly on the server and the session keeps its context; the conversation picks up at the next prompt.
87
90
 
88
91
  If a turn fails terminally (the server session dies or the connection drops), the TUI starts a fresh session and notes it inline so you can keep going. Server-side context resets with the old session. Messages still queued when a turn is interrupted or fails are restored into the next prompt's input instead of being sent blind.
89
92