eve 0.46.0 → 0.47.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 (166) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/src/channel/schedule.d.ts +1 -0
  3. package/dist/src/channel/schedule.js +1 -1
  4. package/dist/src/chunks/{use-eve-agent-DI2j5XK8.js → use-eve-agent-CacMaX4P.js} +91 -43
  5. package/dist/src/chunks/{use-eve-agent-BH7Z6SDu.js → use-eve-agent-kmlFdOBB.js} +91 -43
  6. package/dist/src/cli/commands/info.d.ts +2 -0
  7. package/dist/src/cli/commands/info.js +2 -2
  8. package/dist/src/cli/dev/tui/prompt-commands.d.ts +2 -0
  9. package/dist/src/cli/dev/tui/prompt-commands.js +1 -1
  10. package/dist/src/cli/dev/tui/runner.d.ts +3 -0
  11. package/dist/src/cli/dev/tui/runner.js +1 -1
  12. package/dist/src/client/message-reducer-primitives.d.ts +8 -0
  13. package/dist/src/client/message-reducer-primitives.js +1 -0
  14. package/dist/src/client/message-reducer-types.d.ts +2 -0
  15. package/dist/src/client/message-reducer.js +1 -1
  16. package/dist/src/compiled/.vendor-stamp.json +3 -2
  17. package/dist/src/compiled/@linqapp/chat-sdk-adapter/index.d.ts +2 -1
  18. package/dist/src/compiled/@linqapp/chat-sdk-adapter/index.js +3 -3
  19. package/dist/src/compiled/@vercel/sandbox/index.js +9 -15
  20. package/dist/src/compiled/@vercel/sandbox-delete/LICENSE +201 -0
  21. package/dist/src/compiled/@vercel/sandbox-delete/_async-retry.d.ts +8 -0
  22. package/dist/src/compiled/@vercel/sandbox-delete/_workflow-serde.d.ts +5 -0
  23. package/dist/src/compiled/@vercel/sandbox-delete/api-client/api-client.d.ts +1730 -0
  24. package/dist/src/compiled/@vercel/sandbox-delete/api-client/api-error.d.ts +29 -0
  25. package/dist/src/compiled/@vercel/sandbox-delete/api-client/base-client.d.ts +39 -0
  26. package/dist/src/compiled/@vercel/sandbox-delete/api-client/file-writer.d.ts +66 -0
  27. package/dist/src/compiled/@vercel/sandbox-delete/api-client/index.d.ts +2 -0
  28. package/dist/src/compiled/@vercel/sandbox-delete/api-client/validators.d.ts +907 -0
  29. package/dist/src/compiled/@vercel/sandbox-delete/api-client/with-retry.d.ts +10 -0
  30. package/dist/src/compiled/@vercel/sandbox-delete/auth/error.d.ts +15 -0
  31. package/dist/src/compiled/@vercel/sandbox-delete/auth/file.d.ts +18 -0
  32. package/dist/src/compiled/@vercel/sandbox-delete/auth/index.d.ts +6 -0
  33. package/dist/src/compiled/@vercel/sandbox-delete/auth/oauth.d.ts +111 -0
  34. package/dist/src/compiled/@vercel/sandbox-delete/auth/poll-for-token.d.ts +28 -0
  35. package/dist/src/compiled/@vercel/sandbox-delete/auth/project.d.ts +40 -0
  36. package/dist/src/compiled/@vercel/sandbox-delete/command.d.ts +292 -0
  37. package/dist/src/compiled/@vercel/sandbox-delete/constants.d.ts +15 -0
  38. package/dist/src/compiled/@vercel/sandbox-delete/execution-context.d.ts +116 -0
  39. package/dist/src/compiled/@vercel/sandbox-delete/filesystem.d.ts +258 -0
  40. package/dist/src/compiled/@vercel/sandbox-delete/index.d.ts +13 -0
  41. package/dist/src/compiled/@vercel/sandbox-delete/index.js +9 -0
  42. package/dist/src/compiled/@vercel/sandbox-delete/network-policy.d.ts +169 -0
  43. package/dist/src/compiled/@vercel/sandbox-delete/proxy.d.ts +55 -0
  44. package/dist/src/compiled/@vercel/sandbox-delete/sandbox-user.d.ts +211 -0
  45. package/dist/src/compiled/@vercel/sandbox-delete/sandbox.d.ts +1258 -0
  46. package/dist/src/compiled/@vercel/sandbox-delete/session.d.ts +435 -0
  47. package/dist/src/compiled/@vercel/sandbox-delete/snapshot.d.ts +238 -0
  48. package/dist/src/compiled/@vercel/sandbox-delete/utils/get-credentials.d.ts +21 -0
  49. package/dist/src/compiled/@vercel/sandbox-delete/utils/paginator.d.ts +16 -0
  50. package/dist/src/compiled/@vercel/sandbox-delete/utils/resolveSignal.d.ts +15 -0
  51. package/dist/src/compiled/@vercel/sandbox-delete/utils/sandbox-snapshot.d.ts +11 -0
  52. package/dist/src/compiled/@vercel/sandbox-delete/utils/types.d.ts +11 -0
  53. package/dist/src/compiled/_chunks/node/auth-DpzFWvTn.js +2 -0
  54. package/dist/src/compiled/_chunks/node/auth-QgeX8nBM.js +2 -0
  55. package/dist/src/compiled/_chunks/node/decode_jwt-Col8JOnf.js +7 -0
  56. package/dist/src/compiled/_chunks/node/version-DH6yRy-M.js +1 -0
  57. package/dist/src/compiled/_chunks/node/xdg-app-paths-Bys8q02u.js +1 -0
  58. package/dist/src/compiler/extension-compatibility.d.ts +20 -20
  59. package/dist/src/compiler/extension-compatibility.js +1 -1
  60. package/dist/src/compiler/model-catalog.js +1 -1
  61. package/dist/src/context/build-callback-context.js +1 -1
  62. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  63. package/dist/src/context/keys.d.ts +2 -0
  64. package/dist/src/context/keys.js +1 -1
  65. package/dist/src/context/memory-tools.js +1 -1
  66. package/dist/src/context/providers/sandbox.js +1 -1
  67. package/dist/src/evals/context.js +1 -1
  68. package/dist/src/evals/session-content.d.ts +5 -0
  69. package/dist/src/evals/session-content.js +3 -0
  70. package/dist/src/evals/session.d.ts +1 -0
  71. package/dist/src/evals/session.js +1 -1
  72. package/dist/src/evals/types.d.ts +5 -0
  73. package/dist/src/execution/dispatch-runtime-actions-shared.js +1 -1
  74. package/dist/src/execution/eve-workflow-attributes.d.ts +3 -0
  75. package/dist/src/execution/eve-workflow-attributes.js +1 -1
  76. package/dist/src/execution/runtime-context.js +1 -1
  77. package/dist/src/execution/sandbox/bindings/docker-base-setup.d.ts +4 -4
  78. package/dist/src/execution/sandbox/bindings/docker-base-setup.js +1 -1
  79. package/dist/src/execution/sandbox/bindings/docker-session.d.ts +1 -1
  80. package/dist/src/execution/sandbox/bindings/docker-session.js +1 -1
  81. package/dist/src/execution/sandbox/bindings/docker.js +1 -1
  82. package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
  83. package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
  84. package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
  85. package/dist/src/execution/sandbox/bindings/vercel-base-runtime.d.ts +4 -0
  86. package/dist/src/execution/sandbox/bindings/vercel-base-runtime.js +2 -2
  87. package/dist/src/execution/sandbox/bindings/vercel-lifecycle.d.ts +8 -0
  88. package/dist/src/execution/sandbox/bindings/vercel-lifecycle.js +1 -0
  89. package/dist/src/execution/sandbox/bindings/vercel-sdk-types.d.ts +3 -0
  90. package/dist/src/execution/sandbox/bindings/vercel.d.ts +2 -1
  91. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  92. package/dist/src/execution/sandbox/ensure.d.ts +2 -0
  93. package/dist/src/execution/sandbox/ensure.js +1 -1
  94. package/dist/src/execution/sandbox/require-sandbox.js +1 -1
  95. package/dist/src/execution/tasks/parent/tool-execution.js +1 -1
  96. package/dist/src/execution/tools/connection-search.js +2 -2
  97. package/dist/src/execution/tools/file-state.js +1 -1
  98. package/dist/src/execution/tools/load-skill.js +1 -1
  99. package/dist/src/execution/tools/subagent/local.js +1 -1
  100. package/dist/src/execution/workflow-steps.js +1 -1
  101. package/dist/src/harness/approval-delivery-coordinator.js +1 -1
  102. package/dist/src/harness/attachment-staging.js +1 -1
  103. package/dist/src/harness/authorization.js +1 -1
  104. package/dist/src/harness/current-messages.d.ts +15 -0
  105. package/dist/src/harness/current-messages.js +1 -0
  106. package/dist/src/harness/emission.d.ts +1 -8
  107. package/dist/src/harness/emission.js +1 -1
  108. package/dist/src/harness/instrumentation/runtime-context.js +1 -1
  109. package/dist/src/harness/instrumentation/state.js +1 -1
  110. package/dist/src/harness/ordered-stream-emitter.js +1 -1
  111. package/dist/src/harness/step-hooks.js +1 -1
  112. package/dist/src/harness/tool-loop.js +2 -2
  113. package/dist/src/harness/tools.js +1 -1
  114. package/dist/src/internal/application/package.js +1 -1
  115. package/dist/src/internal/model-catalog.js +1 -1
  116. package/dist/src/packages/eve-catalog/src/index.js +1 -1
  117. package/dist/src/protocol/message.d.ts +29 -2
  118. package/dist/src/protocol/message.js +2 -2
  119. package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
  120. package/dist/src/public/definitions/connections/tool-call.d.ts +2 -0
  121. package/dist/src/public/definitions/hook.d.ts +1 -0
  122. package/dist/src/public/definitions/sandbox-backend.d.ts +1 -1
  123. package/dist/src/public/sandbox/index.d.ts +1 -1
  124. package/dist/src/runtime/agent/resolve-model.js +1 -1
  125. package/dist/src/runtime/connections/mcp-client.d.ts +1 -1
  126. package/dist/src/runtime/connections/mcp-client.js +1 -1
  127. package/dist/src/runtime/connections/openapi-client.d.ts +1 -1
  128. package/dist/src/runtime/connections/openapi-client.js +1 -1
  129. package/dist/src/runtime/connections/principal.js +1 -1
  130. package/dist/src/runtime/connections/provided-arguments.d.ts +1 -0
  131. package/dist/src/runtime/connections/provided-arguments.js +1 -1
  132. package/dist/src/sandbox/state.d.ts +2 -0
  133. package/dist/src/setup/integrations/registry.js +1 -1
  134. package/dist/src/setup/integrations/shopify/setup.d.ts +20 -0
  135. package/dist/src/setup/integrations/shopify/setup.js +1 -0
  136. package/dist/src/setup/integrations/shopify/templates.d.ts +1 -0
  137. package/dist/src/setup/integrations/shopify/templates.js +88 -0
  138. package/dist/src/setup/scaffold/create/project.js +1 -1
  139. package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
  140. package/dist/src/setup/scaffold/create/web-template.js +4 -2
  141. package/dist/src/shared/connection-types.d.ts +3 -1
  142. package/dist/src/shared/sandbox-backend.d.ts +9 -0
  143. package/dist/src/shared/sandbox-definition.d.ts +5 -4
  144. package/dist/src/shared/sandbox-session.d.ts +4 -1
  145. package/dist/src/svelte/index.js +1 -1
  146. package/dist/src/svelte/use-eve-agent.js +1 -1
  147. package/dist/src/tasks/delivery-policy.d.ts +12 -0
  148. package/dist/src/tasks/delivery-policy.js +1 -0
  149. package/dist/src/tracing/agent-trace-context-store.js +1 -1
  150. package/dist/src/vue/index.js +1 -1
  151. package/dist/src/vue/use-eve-agent.js +1 -1
  152. package/docs/concepts/sessions-runs-and-streaming.md +5 -2
  153. package/docs/connections/mcp.mdx +1 -1
  154. package/docs/connections/openapi.mdx +1 -1
  155. package/docs/evals/cases.mdx +11 -2
  156. package/docs/evals/judge.mdx +15 -0
  157. package/docs/evals/overview.mdx +2 -2
  158. package/docs/guides/client/streaming.mdx +18 -15
  159. package/docs/guides/dev-tui.md +2 -1
  160. package/docs/guides/instrumentation.md +1 -0
  161. package/docs/guides/session-context.md +2 -2
  162. package/docs/sandbox.mdx +25 -2
  163. package/docs/schedules.mdx +2 -0
  164. package/docs/tools/overview.mdx +2 -0
  165. package/package.json +3 -2
  166. package/dist/src/compiled/_chunks/node/auth-BaNbsImr.js +0 -2
@@ -1 +1 @@
1
- import{normalizeChannelAudience}from"#shared/channel-audience.js";import{SessionTraceSeedKey}from"#context/keys.js";import{contextStorage,loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";const AgentTraceContextKey=new ContextKey(`eve.harness.agentTrace`,{codec:{deserialize:deserializeState,serialize:serializeState}});function preserveSerializedAgentTraceState(e,t){let n=t[AgentTraceContextKey.name];return n===void 0?e:{...e,[AgentTraceContextKey.name]:n}}function readSessionTraceContext(e,t){let n=e[AgentTraceContextKey.name];if(n===void 0)return;let r=deserializeState(n).sessions[t]?.context;return r===void 0?void 0:withTraceDecision(e,r)}function readActionTraceContext(e,t,n,r){let i=e[AgentTraceContextKey.name];if(i===void 0)return;let a=Object.values(deserializeState(i).actions).find(e=>e.sessionId===t&&e.turnId===n&&e.callId===r);if(a!==void 0)return withTraceDecision(e,{isRemote:!1,spanId:a.spanId,traceFlags:a.parent.traceFlags,traceId:a.parent.traceId})}function withTraceDecision(e,n){let r=e[SessionTraceSeedKey.name];return r?.decision===void 0?n:{...n,decision:r.decision}}var ContextAgentTraceStateStore=class{deleteAction(e){updateState(t=>{let n={...t.actions};return delete n[e],{...t,actions:n}})}deleteActions(e,t){updateState(n=>{let r={...n.actions};for(let[n,i]of Object.entries(r))i.sessionId===e&&(t===void 0||i.turnId===t)&&delete r[n];return{...n,actions:r}})}deleteSession(e){updateState(t=>{let n={...t.sessions};return delete n[e],{...t,sessions:n}})}deleteTurn(e,t){updateState(n=>{let r={...n.turns};return delete r[turnKey(e,t)],{...n,turns:r}})}findAction(e,t){return Object.values(contextStorage.getStore()?.get(AgentTraceContextKey)?.actions??{}).find(n=>n.sessionId===e&&n.callId===t)}getAction(e){return contextStorage.getStore()?.get(AgentTraceContextKey)?.actions[e]}getSession(e){return contextStorage.getStore()?.get(AgentTraceContextKey)?.sessions[e]}getTurn(e,t){return contextStorage.getStore()?.get(AgentTraceContextKey)?.turns[turnKey(e,t)]}setAction(e,t){updateState(n=>({...n,actions:{...n.actions,[e]:t}}))}setSession(e,t){updateState(n=>({...n,sessions:{...n.sessions,[e]:t}}))}setTurn(e,t,n){updateState(r=>({...r,turns:{...r.turns,[turnKey(e,t)]:n}}))}};function updateState(e){loadContext().set(AgentTraceContextKey,t=>e(t??{actions:{},sessions:{},turns:{}}))}function turnKey(e,t){return`${e}\0${t}`}function serializeState(e){return{actions:e.actions,sessions:Object.fromEntries(Object.entries(e.sessions).map(([e,t])=>[e,{...t,context:serializeSpanContext(t.context)}])),turns:Object.fromEntries(Object.entries(e.turns).map(([e,t])=>[e,{...t,context:serializeSpanContext(t.context),terminal:t.terminal===void 0?void 0:t.terminal.type===`turn.failed`?{error:serializeError(t.terminal.error),type:t.terminal.type}:{type:t.terminal.type}}]))}}function deserializeState(t){return isRecord(t)?{actions:deserializeRecord(t.actions,deserializeAction),sessions:deserializeRecord(t.sessions,t=>{if(!(!isRecord(t)||!isSpanContext(t.context)))return{agentName:typeof t.agentName==`string`?t.agentName:void 0,channelAudience:normalizeChannelAudience(t.channelAudience),channelKind:typeof t.channelKind==`string`?t.channelKind:void 0,context:t.context,rootSessionId:typeof t.rootSessionId==`string`?t.rootSessionId:``}}),turns:deserializeRecord(t.turns,e=>{if(!(!isRecord(e)||!isSpanContext(e.context))&&!(typeof e.parentSpanId!=`string`||typeof e.startTimeMs!=`number`))return{context:e.context,parentIsRemote:typeof e.parentIsRemote==`boolean`?e.parentIsRemote:void 0,parentSpanId:e.parentSpanId,rootSessionId:typeof e.rootSessionId==`string`?e.rootSessionId:``,sequence:typeof e.sequence==`number`?e.sequence:0,startTimeMs:e.startTimeMs,subagentName:typeof e.subagentName==`string`?e.subagentName:void 0,terminal:deserializeTerminal(e.terminal)}})}:{actions:{},sessions:{},turns:{}}}function deserializeAction(t){if(!(!isRecord(t)||typeof t.attemptIndex!=`number`||typeof t.callId!=`string`||!isActionKind(t.kind)||typeof t.name!=`string`||!isSpanContext(t.parent)||typeof t.rootSessionId!=`string`||typeof t.sessionId!=`string`||typeof t.spanId!=`string`||typeof t.startTimeMs!=`number`||typeof t.stepIndex!=`number`||typeof t.turnId!=`string`))return{attemptIndex:t.attemptIndex,callId:t.callId,channelAudience:normalizeChannelAudience(t.channelAudience),inputAttribute:typeof t.inputAttribute==`string`?t.inputAttribute:void 0,kind:t.kind,name:t.name,parent:t.parent,rootSessionId:t.rootSessionId,sessionId:t.sessionId,spanId:t.spanId,startTimeMs:t.startTimeMs,stepIndex:t.stepIndex,turnId:t.turnId}}function isActionKind(e){return e===`load-skill`||e===`remote-agent-call`||e===`subagent-call`||e===`tool-call`}function deserializeRecord(e,t){if(!isRecord(e))return{};let n={};for(let[r,i]of Object.entries(e)){let e=t(i);e!==void 0&&(n[r]=e)}return n}function deserializeTerminal(e){if(!isRecord(e)||typeof e.type!=`string`)return;let t=e.type;if(isTurnTerminalType(t))return t===`turn.failed`?{error:deserializeError(e.error),type:t}:{type:t}}function serializeSpanContext(e){return{isRemote:e.isRemote,spanId:e.spanId,traceFlags:e.traceFlags,traceId:e.traceId}}function isSpanContext(e){return isRecord(e)&&typeof e.spanId==`string`&&typeof e.traceFlags==`number`&&typeof e.traceId==`string`}function serializeError(e){return e instanceof Error?{message:e.message,name:e.name,stack:e.stack}:void 0}function deserializeError(e){if(!isRecord(e)||typeof e.message!=`string`)return;let t=Error(e.message);return typeof e.name==`string`&&(t.name=e.name),typeof e.stack==`string`&&(t.stack=e.stack),t}function isTurnTerminalType(e){return e===`turn.cancelled`||e===`turn.completed`||e===`turn.failed`}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}export{ContextAgentTraceStateStore,preserveSerializedAgentTraceState,readActionTraceContext,readSessionTraceContext};
1
+ import{normalizeChannelAudience}from"#shared/channel-audience.js";import{contextStorage,loadContext}from"#context/container.js";import{SessionTraceSeedKey}from"#context/keys.js";import{ContextKey}from"#context/key.js";const AgentTraceContextKey=new ContextKey(`eve.harness.agentTrace`,{codec:{deserialize:deserializeState,serialize:serializeState}});function preserveSerializedAgentTraceState(e,t){let n=t[AgentTraceContextKey.name];return n===void 0?e:{...e,[AgentTraceContextKey.name]:n}}function readSessionTraceContext(e,t){let n=e[AgentTraceContextKey.name];if(n===void 0)return;let r=deserializeState(n).sessions[t]?.context;return r===void 0?void 0:withTraceDecision(e,r)}function readActionTraceContext(e,t,n,r){let i=e[AgentTraceContextKey.name];if(i===void 0)return;let a=Object.values(deserializeState(i).actions).find(e=>e.sessionId===t&&e.turnId===n&&e.callId===r);if(a!==void 0)return withTraceDecision(e,{isRemote:!1,spanId:a.spanId,traceFlags:a.parent.traceFlags,traceId:a.parent.traceId})}function withTraceDecision(e,t){let n=e[SessionTraceSeedKey.name];return n?.decision===void 0?t:{...t,decision:n.decision}}var ContextAgentTraceStateStore=class{deleteAction(e){updateState(t=>{let n={...t.actions};return delete n[e],{...t,actions:n}})}deleteActions(e,t){updateState(n=>{let r={...n.actions};for(let[n,i]of Object.entries(r))i.sessionId===e&&(t===void 0||i.turnId===t)&&delete r[n];return{...n,actions:r}})}deleteSession(e){updateState(t=>{let n={...t.sessions};return delete n[e],{...t,sessions:n}})}deleteTurn(e,t){updateState(n=>{let r={...n.turns};return delete r[turnKey(e,t)],{...n,turns:r}})}findAction(e,n){return Object.values(contextStorage.getStore()?.get(AgentTraceContextKey)?.actions??{}).find(t=>t.sessionId===e&&t.callId===n)}getAction(e){return contextStorage.getStore()?.get(AgentTraceContextKey)?.actions[e]}getSession(e){return contextStorage.getStore()?.get(AgentTraceContextKey)?.sessions[e]}getTurn(e,n){return contextStorage.getStore()?.get(AgentTraceContextKey)?.turns[turnKey(e,n)]}setAction(e,t){updateState(n=>({...n,actions:{...n.actions,[e]:t}}))}setSession(e,t){updateState(n=>({...n,sessions:{...n.sessions,[e]:t}}))}setTurn(e,t,n){updateState(r=>({...r,turns:{...r.turns,[turnKey(e,t)]:n}}))}};function updateState(e){loadContext().set(AgentTraceContextKey,t=>e(t??{actions:{},sessions:{},turns:{}}))}function turnKey(e,t){return`${e}\0${t}`}function serializeState(e){return{actions:e.actions,sessions:Object.fromEntries(Object.entries(e.sessions).map(([e,t])=>[e,{...t,context:serializeSpanContext(t.context)}])),turns:Object.fromEntries(Object.entries(e.turns).map(([e,t])=>[e,{...t,context:serializeSpanContext(t.context),terminal:t.terminal===void 0?void 0:t.terminal.type===`turn.failed`?{error:serializeError(t.terminal.error),type:t.terminal.type}:{type:t.terminal.type}}]))}}function deserializeState(t){return isRecord(t)?{actions:deserializeRecord(t.actions,deserializeAction),sessions:deserializeRecord(t.sessions,t=>{if(!(!isRecord(t)||!isSpanContext(t.context)))return{agentName:typeof t.agentName==`string`?t.agentName:void 0,channelAudience:normalizeChannelAudience(t.channelAudience),channelKind:typeof t.channelKind==`string`?t.channelKind:void 0,context:t.context,rootSessionId:typeof t.rootSessionId==`string`?t.rootSessionId:``}}),turns:deserializeRecord(t.turns,e=>{if(!(!isRecord(e)||!isSpanContext(e.context))&&!(typeof e.parentSpanId!=`string`||typeof e.startTimeMs!=`number`))return{context:e.context,parentIsRemote:typeof e.parentIsRemote==`boolean`?e.parentIsRemote:void 0,parentSpanId:e.parentSpanId,rootSessionId:typeof e.rootSessionId==`string`?e.rootSessionId:``,sequence:typeof e.sequence==`number`?e.sequence:0,startTimeMs:e.startTimeMs,subagentName:typeof e.subagentName==`string`?e.subagentName:void 0,terminal:deserializeTerminal(e.terminal)}})}:{actions:{},sessions:{},turns:{}}}function deserializeAction(t){if(!(!isRecord(t)||typeof t.attemptIndex!=`number`||typeof t.callId!=`string`||!isActionKind(t.kind)||typeof t.name!=`string`||!isSpanContext(t.parent)||typeof t.rootSessionId!=`string`||typeof t.sessionId!=`string`||typeof t.spanId!=`string`||typeof t.startTimeMs!=`number`||typeof t.stepIndex!=`number`||typeof t.turnId!=`string`))return{attemptIndex:t.attemptIndex,callId:t.callId,channelAudience:normalizeChannelAudience(t.channelAudience),inputAttribute:typeof t.inputAttribute==`string`?t.inputAttribute:void 0,kind:t.kind,name:t.name,parent:t.parent,rootSessionId:t.rootSessionId,sessionId:t.sessionId,spanId:t.spanId,startTimeMs:t.startTimeMs,stepIndex:t.stepIndex,turnId:t.turnId}}function isActionKind(e){return e===`load-skill`||e===`remote-agent-call`||e===`subagent-call`||e===`tool-call`}function deserializeRecord(e,t){if(!isRecord(e))return{};let n={};for(let[r,i]of Object.entries(e)){let e=t(i);e!==void 0&&(n[r]=e)}return n}function deserializeTerminal(e){if(!isRecord(e)||typeof e.type!=`string`)return;let t=e.type;if(isTurnTerminalType(t))return t===`turn.failed`?{error:deserializeError(e.error),type:t}:{type:t}}function serializeSpanContext(e){return{isRemote:e.isRemote,spanId:e.spanId,traceFlags:e.traceFlags,traceId:e.traceId}}function isSpanContext(e){return isRecord(e)&&typeof e.spanId==`string`&&typeof e.traceFlags==`number`&&typeof e.traceId==`string`}function serializeError(e){return e instanceof Error?{message:e.message,name:e.name,stack:e.stack}:void 0}function deserializeError(e){if(!isRecord(e)||typeof e.message!=`string`)return;let t=Error(e.message);return typeof e.name==`string`&&(t.name=e.name),typeof e.stack==`string`&&(t.stack=e.stack),t}function isTurnTerminalType(e){return e===`turn.cancelled`||e===`turn.completed`||e===`turn.failed`}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}export{ContextAgentTraceStateStore,preserveSerializedAgentTraceState,readActionTraceContext,readSessionTraceContext};
@@ -1,3 +1,3 @@
1
- import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-DI2j5XK8.js";
1
+ import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-CacMaX4P.js";
2
2
 
3
3
  export { defaultMessageReducer, useEveAgent };
@@ -1,3 +1,3 @@
1
- import { t as useEveAgent } from "../chunks/use-eve-agent-DI2j5XK8.js";
1
+ import { t as useEveAgent } from "../chunks/use-eve-agent-CacMaX4P.js";
2
2
 
3
3
  export { useEveAgent };
@@ -49,6 +49,7 @@ The stream is newline-delimited JSON (NDJSON), one event per line:
49
49
  | `turn.started` | A new turn began; carries the active `trace` when the runtime is traced. |
50
50
  | `message.received` | An inbound user message was accepted; carries flattened text plus structured text/file parts. |
51
51
  | `step.started` | A model step began. |
52
+ | `action.input.appended` | A raw tool-input text delta, its character offset, and tool-call identity. |
52
53
  | `actions.requested` | The model requested one or more actions, including tool calls; calls stream before execution. |
53
54
  | `action.partial` | A locally executed tool generator yielded a preliminary output snapshot. |
54
55
  | `action.result` | A tool call returned. |
@@ -76,7 +77,9 @@ The stream is newline-delimited JSON (NDJSON), one event per line:
76
77
 
77
78
  The optional `data.trace` on session and turn starts contains eve-owned W3C trace coordinates: `traceId`, `spanId`, and `traceFlags`. Use it to correlate stream consumers such as eval reporters with an observability backend. An uninstrumented target omits it.
78
79
 
79
- `reasoning.appended` and `message.appended` stream incremental output as it arrives. When the durable stream writer is busy, eve may coalesce adjacent deltas of the same type; the text remains in source order, and any other event forms an ordering barrier. Each append carries both the new delta and the cumulative text for the current block. The finalized block shows up on `message.completed` and `reasoning.completed`, which is the compatibility path for clients that don't render incremental streaming.
80
+ `reasoning.appended`, `message.appended`, and `action.input.appended` stream incremental output as it arrives. When the durable stream writer is busy, eve may coalesce adjacent deltas for the same text block or tool call; the text remains in source order, and a different event type, tool `callId`, or stream coordinate forms an ordering barrier. Text and reasoning appends carry both the new delta and the cumulative text for the current block. The finalized blocks show up on `message.completed` and `reasoning.completed`, which is the compatibility path for clients that don't render incremental streaming.
81
+
82
+ When a streamed tool input becomes a validated call, its `action.input.appended` events precede the matching `actions.requested` event. Each append carries `callId`, `toolName`, `inputTextDelta`, and `inputTextOffset`; the offset is the zero-based UTF-16 code-unit position where the delta begins. Storing only the delta and offset avoids repeating the cumulative input in every durable event. The default client reducer starts or restarts accumulation at offset `0`, ignores a nonzero offset that is not contiguous, and projects the potentially incomplete JSON as a `dynamic-tool` part with `state: "input-streaming"` and cumulative text in `inputText`. `actions.requested` replaces that part with `state: "input-available"` and the validated `input`. Excluded internal actions never publish their input stream.
80
83
 
81
84
  `action.partial` carries one complete preliminary output snapshot from an authored async-generator tool. A later partial for the same `callId` replaces it, and `action.result` is the final snapshot. When the durable writer is busy, eve may keep only the newest adjacent partial for a call. Treat partials as last-write-wins: a durable step can retry and replay overlapping event runs. Provider-executed tool progress and MCP progress notifications are not projected as `action.partial` events.
82
85
 
@@ -111,7 +114,7 @@ Alongside `type` and `data`, every event carries a `meta` envelope:
111
114
 
112
115
  `meta.id` is stable. eve mints it once, when the event is written to the durable stream, and stores it with the event. Reconnecting from a cursor, rewinding to `startIndex=0`, or replaying a finished session all return the same id for the same event.
113
116
 
114
- `meta.at` has always been there; `meta.id` arrived in stream version 20. Events written by an earlier version are stored with the envelope but no id inside it, so rewinding into the part of a session that ran before you upgraded yields events whose `meta.id` is absent, even though the type says it is always a string. eve passes those events through rather than dropping them, and they cannot be deduplicated. The exposure ends when the sessions that predate your upgrade do.
117
+ `meta.at` has always been there; `meta.id` arrived in stream version 20, and `action.input.appended` arrived in version 24. Events written by an earlier version are stored with the envelope but no id inside it, so rewinding into the part of a session that ran before you upgraded yields events whose `meta.id` is absent, even though the type says it is always a string. eve passes those events through rather than dropping them, and they cannot be deduplicated. The exposure ends when the sessions that predate your upgrade do.
115
118
 
116
119
  That makes it the key for ingesting a stream into a database without duplicating rows when you re-read it:
117
120
 
@@ -58,7 +58,7 @@ export default defineMcpClientConnection({
58
58
  });
59
59
  ```
60
60
 
61
- Values may be JSON values, promises, or callbacks. Callbacks receive the active session context plus the bare remote `toolName`.
61
+ Values may be JSON values, promises, or callbacks. Callbacks receive the active session context, the bare remote `toolName`, and a replay-stable `callId` that is unique to the tool call. Use `callId` when the remote server needs an idempotency key.
62
62
 
63
63
  eve treats configured keys as application-owned: it removes them from every remote tool's model-facing input schema and adds their resolved values immediately before execution. They apply to every tool call on the connection and replace any conflicting model value. Approval policies continue to receive only the model-authored input.
64
64
 
@@ -86,7 +86,7 @@ export default defineOpenAPIConnection({
86
86
  });
87
87
  ```
88
88
 
89
- Values may be JSON values, promises, or callbacks. Callbacks receive the active session context plus the bare operation `toolName`.
89
+ Values may be JSON values, promises, or callbacks. Callbacks receive the active session context, the bare operation `toolName`, and a replay-stable `callId` that is unique to the tool call. Use `callId` when the API needs an idempotency key.
90
90
 
91
91
  eve removes configured keys from every operation's model-facing input schema and adds their resolved values immediately before constructing the HTTP request. Values apply to every operation on the connection and replace any conflicting model value. The keys correspond to the generated top-level operation inputs: path, query, header, and cookie parameter names, plus `body` for a request body.
92
92
 
@@ -88,11 +88,17 @@ export default defineEval({
88
88
  async test(t) {
89
89
  const first = await t.send("My favorite word is marigold.");
90
90
 
91
- const second = await t.send("Thanks for remembering.");
91
+ const second = await t.send("What is my favorite word?");
92
92
  await t.require(second.sessionId, equals(first.sessionId));
93
93
 
94
94
  t.succeeded();
95
- second.messageIncludes("Thanks for remembering.");
95
+ second.messageIncludes("marigold");
96
+
97
+ t.judge.autoevals
98
+ .closedQA("The assistant remembers the user's favorite word across turns", {
99
+ on: t.transcript,
100
+ })
101
+ .atLeast(0.8);
96
102
  },
97
103
  });
98
104
  ```
@@ -109,6 +115,9 @@ export default defineEval({
109
115
  - `t.respond(responses, options?)` answers specific pending input requests and sends them as the next turn.
110
116
  - `t.respondAll(optionId)` answers every pending input request with the same option and sends the responses as the next turn.
111
117
  - `t.reply` is the last assistant message (or `null`); `t.sessionId` is the current session id; `t.events` is the full typed event stream captured so far.
118
+ - `t.transcript` formats the primary session's observed user and assistant messages in turn order. Pass it as a judge's `on` value to grade the complete conversation. An independent session returned by `t.newSession()` exposes its own `session.transcript`.
119
+
120
+ The transcript uses `User:` and `Assistant:` labels separated by blank lines. It excludes reasoning, tool calls, tool results, and messages from other sessions. It updates after each turn settles, so read it after `await t.send(...)`, `await t.respond(...)`, or `await live.result()`.
112
121
 
113
122
  Each `send` (and `respond`/`respondAll`) resolves to an immutable turn with `.message`, `.data`, `.events`, `.inputRequests`, `.toolCalls`, `.sessionId`, `.status`, and `.expectOk()`. Use `.sessionId` to relate turns or attach follow-up work to the session that produced a specific turn. `expectOk()` throws only when the turn ended failed; a session left open for a next message is the normal end state of a successful turn.
114
123
 
@@ -48,6 +48,21 @@ const draft = await t.send("Draft the welcome email.");
48
48
  t.judge.autoevals.closedQA("professional tone", { on: draft.message }).atLeast(0.6);
49
49
  ```
50
50
 
51
+ For a multi-turn eval, pass `t.transcript` to grade the primary session's complete observed conversation instead of only its final reply:
52
+
53
+ ```ts
54
+ await t.send("My favorite word is marigold. Remember it.");
55
+ await t.send("What is my favorite word?");
56
+
57
+ t.judge.autoevals
58
+ .closedQA("The assistant remembers the user's favorite word across turns", {
59
+ on: t.transcript,
60
+ })
61
+ .atLeast(0.8);
62
+ ```
63
+
64
+ `t.transcript` contains the session's user and assistant messages in turn order. It excludes reasoning, tool calls, and tool results. See [Multi-turn evals](./cases#multi-turn-evals) for the transcript format and independent sessions.
65
+
51
66
  ## Soft scoring and thresholds
52
67
 
53
68
  Judge assertions are soft, so the threshold rides on the assertion handle. There is no separate thresholds map:
@@ -100,7 +100,7 @@ model: mockModel({
100
100
 
101
101
  `t` is both the driver and the assertion surface. There are no separate `input`, `run`, `checks`, or `scores` fields. You write ordinary control flow, sending turns and asserting inline.
102
102
 
103
- - **Drive** the agent: `t.send(...)`, `t.start(...)`, `t.cancel()`, `t.respond(...)`, `t.respondAll(...)`, `t.sendFile(...)`, `t.requireInputRequest(...)`, `t.newSession()`. Live turns returned by `start()` can wait for typed mid-turn events before cancellation or settlement. Read what came back with `t.reply` (the last assistant message), `t.sessionId`, and `t.events`. See [Cases](./cases).
103
+ - **Drive** the agent: `t.send(...)`, `t.start(...)`, `t.cancel()`, `t.respond(...)`, `t.respondAll(...)`, `t.sendFile(...)`, `t.requireInputRequest(...)`, `t.newSession()`. Live turns returned by `start()` can wait for typed mid-turn events before cancellation or settlement. Read what came back with `t.reply` (the last assistant message), `t.transcript` (the primary session's user and assistant messages), `t.sessionId`, and `t.events`. See [Cases](./cases).
104
104
  - **Assert** with three surfaces, covered next.
105
105
 
106
106
  ## Three assertion surfaces
@@ -109,7 +109,7 @@ Each surface matches a genuinely different kind of judgment:
109
109
 
110
110
  - **Scoped methods** read the final whole run on `t`, snapshot one independent session when invoked there, or inspect one immutable `EveEvalTurn`. See [Assertions](./assertions).
111
111
  - **`t.check(value, assertion)`** grades an explicit value with a deterministic builder from `eve/evals/expect`, such as `t.check(t.reply, includes("sunny"))`. Grade `t.reply`, an intermediate draft, parsed JSON, or anything else. See [Assertions](./assertions).
112
- - **`t.judge.autoevals.*`** is the LLM-as-judge surface, like `t.judge.autoevals.closedQA("cites a source")`. It grades `t.reply` by default and uses the configured judge model, never the agent under test. See [Judge](./judge).
112
+ - **`t.judge.autoevals.*`** is the LLM-as-judge surface, like `t.judge.autoevals.closedQA("cites a source")`. It grades `t.reply` by default; pass `{ on: t.transcript }` to grade a multi-turn conversation. The judge uses the configured judge model, never the agent under test. See [Judge](./judge).
113
113
 
114
114
  ## Gate vs soft
115
115
 
@@ -75,7 +75,7 @@ for await (const event of response) {
75
75
  }
76
76
  ```
77
77
 
78
- `message.appended` and `reasoning.appended` are incremental delta events. eve may combine adjacent deltas of the same type while a durable stream write is in flight, but preserves their text and event ordering; any different event is a barrier. Their completed forms, `message.completed` and `reasoning.completed`, are the compatibility path for clients that don't render deltas.
78
+ `message.appended`, `reasoning.appended`, and `action.input.appended` are incremental delta events. eve may combine adjacent deltas for the same text block or tool call while a durable stream write is in flight, but preserves their text and event ordering. A different event type, tool `callId`, or stream coordinate is a barrier. The completed text forms, `message.completed` and `reasoning.completed`, are the compatibility path for clients that don't render deltas. A streamed tool input is complete when the matching validated call arrives in `actions.requested`.
79
79
 
80
80
  ## Handle event types
81
81
 
@@ -98,23 +98,26 @@ function handleEvent(event: MessageStreamEvent) {
98
98
 
99
99
  The most common UI events are:
100
100
 
101
- | Event | Use |
102
- | -------------------- | ------------------------------------------------------------------------------ |
103
- | `message.received` | Confirm the user message landed; `data.parts` includes text and file metadata. |
104
- | `reasoning.appended` | Render reasoning deltas when the model provides them. |
105
- | `message.appended` | Render assistant text deltas. |
106
- | `actions.requested` | Show tool calls as the model requests them, before execution. |
107
- | `action.partial` | Update a generator tool's provisional output snapshot. |
108
- | `action.result` | Show tool call results. |
109
- | `input.requested` | Pause the UI for approval or a question answer. |
110
- | `input.resolved` | Record the server-accepted outcome and response for each human-input request. |
111
- | `result.completed` | Read structured output from an [output schema](./output-schema). |
112
- | `session.waiting` | Enable the composer; the same fixed session handle accepts the next message. |
113
- | `session.completed` | Mark the conversation terminal. |
114
- | `session.failed` | Mark the conversation failed. |
101
+ | Event | Use |
102
+ | ----------------------- | ------------------------------------------------------------------------------ |
103
+ | `message.received` | Confirm the user message landed; `data.parts` includes text and file metadata. |
104
+ | `reasoning.appended` | Render reasoning deltas when the model provides them. |
105
+ | `message.appended` | Render assistant text deltas. |
106
+ | `action.input.appended` | Accumulate raw tool-input deltas before validation completes. |
107
+ | `actions.requested` | Show tool calls as the model requests them, before execution. |
108
+ | `action.partial` | Update a generator tool's provisional output snapshot. |
109
+ | `action.result` | Show tool call results. |
110
+ | `input.requested` | Pause the UI for approval or a question answer. |
111
+ | `input.resolved` | Record the server-accepted outcome and response for each human-input request. |
112
+ | `result.completed` | Read structured output from an [output schema](./output-schema). |
113
+ | `session.waiting` | Enable the composer; the same fixed session handle accepts the next message. |
114
+ | `session.completed` | Mark the conversation terminal. |
115
+ | `session.failed` | Mark the conversation failed. |
115
116
 
116
117
  For the complete event table, see [Sessions, runs & streaming](../../concepts/sessions-runs-and-streaming).
117
118
 
119
+ Each `action.input.appended` event stores `inputTextDelta` and its zero-based UTF-16 code-unit `inputTextOffset`, so consumers can reject a gap instead of concatenating corrupt input. The default message reducer starts or restarts at offset `0` and ignores a nonzero offset that is not contiguous. It accumulates accepted deltas into a `dynamic-tool` part with `state: "input-streaming"`; its `inputText` field contains cumulative raw text that may be incomplete JSON. The matching `actions.requested` event upgrades the same `toolCallId` to `state: "input-available"` and puts the validated value in `input`.
120
+
118
121
  When a submitted message includes attachments, `message.received.data.message` stays the
119
122
  flattened compatibility summary, while `message.received.data.parts` carries renderable text and
120
123
  file metadata. File parts never include raw bytes or internal sandbox paths; `url` appears only for
@@ -20,6 +20,7 @@ The transcript remains in your terminal scrollback after you exit. Run `/help` i
20
20
  | `/deploy` | Deploy the agent to Vercel production. Links the directory first if needed. |
21
21
  | `/vc:install` | Install the Vercel CLI. |
22
22
  | `/vc:login` | Log in to Vercel or restore access to a remote deployment. |
23
+ | `/info` | Show the resolved application, compiled artifacts, discovery diagnostics, and messaging routes. |
23
24
  | `/loglevel` | Choose which server and agent logs appear in the transcript. |
24
25
  | `/traces` | Open the local trace viewer. Pass a trace ID prefix to open a specific trace. |
25
26
  | `/reset` | Start a fresh session. |
@@ -29,7 +30,7 @@ The transcript remains in your terminal scrollback after you exit. Run `/help` i
29
30
  | `/exit` | Quit the UI. |
30
31
  | `/help` | List available commands. |
31
32
 
32
- `/model`, `/add`, `/deploy`, and `/traces` are available when `eve dev` runs locally. They are unavailable when the UI connects to a server with `--url`.
33
+ `/model`, `/add`, `/deploy`, `/info`, and `/traces` are available when `eve dev` runs locally. They are unavailable when the UI connects to a server with `--url`.
33
34
 
34
35
  ## Add an integration
35
36
 
@@ -163,6 +163,7 @@ Structural tags describe each run's place in the tree:
163
163
  - `$eve.root`: session id of the root session in the chain (group a whole tree with `$eve.root=<id>`)
164
164
  - `$eve.subagent`: compiled graph node id (subagent runs only)
165
165
  - `$eve.trigger`: the channel kind that started the run
166
+ - `$eve.schedule`: the authored schedule that created the session, including sessions started through a target channel
166
167
  - `$eve.title`: truncated title derived from the first user message
167
168
  - `$eve.trace_id`: trace id of the sampled agent trace containing the run, written on session, subagent, and turn rows so a dashboard run can be joined to its OpenTelemetry trace. Present only when the trace is sampled; absence means no exported OTEL trace exists.
168
169
 
@@ -59,7 +59,7 @@ const sandbox = await ctx.getSandbox();
59
59
  const result = await sandbox.run({ command: "npm test" });
60
60
  ```
61
61
 
62
- The accessor is asynchronous because eve may need to bind or restore the sandbox. A subagent sees its own sandbox, not its parent's. The returned runtime handle can also stop compute while preserving the durable sandbox state. See [Sandbox](../sandbox#using-the-sandbox) for the I/O API and lifecycle.
62
+ The accessor is asynchronous because eve may need to bind or restore the sandbox. A subagent sees its own sandbox, not its parent's. The returned handle also exposes `stop()` and `delete()`; see [Sandbox lifecycle](../sandbox#lifecycle) for their behavior.
63
63
 
64
64
  ## `ctx.getSkill(identifier)`
65
65
 
@@ -82,7 +82,7 @@ Runtime context is available:
82
82
 
83
83
  - inside `defineTool(...).execute(input, ctx)`;
84
84
  - inside connection `auth` and `headers` resolvers;
85
- - inside channel and hook callbacks that receive `ctx`;
85
+ - inside channel and agent hook callbacks that receive the full runtime `ctx`;
86
86
  - after asynchronous boundaries within the same authored execution chain.
87
87
 
88
88
  Runtime context is not available during top-level module evaluation, build scripts, or discovery. Declare reusable definitions and state handles at module scope, but call their context-dependent methods only from an eve-managed callback.
package/docs/sandbox.mdx CHANGED
@@ -202,14 +202,14 @@ export default defineSandbox({
202
202
 
203
203
  Custom commands are registered on live and reopened sessions, not during template prewarming. They run trusted host application code and create an explicit bridge from the sandbox to that code. Adapters can use this extension point to expose application APIs such as a Capable App's CLI; the outer eve `bash` tool does not automatically provide per-command Capable approvals.
204
204
 
205
- You can also write your own backend. A `SandboxBackend` is an adapter object with a `name`, a `create`, and an optional `prewarm`. It can point at your own container runner, VM pool, internal sandbox service, or another isolation layer, as long as it returns the `SandboxSession` operations eve needs. Handles returned by `create` implement `shutdown()`, which stops the underlying compute at server shutdown. See the `SandboxBackend*` types on `eve/sandbox`.
205
+ You can also write your own backend. A `SandboxBackend` is an adapter object with a `name`, a `create`, and an optional `prewarm`. It can point at your own container runner, VM pool, internal sandbox service, or another isolation layer, as long as it returns the `SandboxSession` operations eve needs. Handles returned by `create` implement `delete()`, `stop()`, and `shutdown()`. See the `SandboxBackend*` types on `eve/sandbox`.
206
206
 
207
207
  ## Lifecycle
208
208
 
209
209
  There are two hooks, scoped differently:
210
210
 
211
211
  - **`bootstrap({ use })`** is template-scoped and runs once when the template is built. Put reusable setup here that every later session inherits, such as cloning a baseline repo, installing dependencies, or seeding files. Call `use()` to get a `SandboxSession`. Only template filesystem state and supported backend metadata carry into later sessions; config like network policy does not. If external inputs affect what bootstrap produces, set `revalidationKey: () => string` so eve knows when to rebuild the template (authored sandbox source and seed contents are already tracked for you).
212
- - **`onSession({ use, ctx })`** is durable-session-scoped and runs once per session (and again if a sandbox definition change replaces the session's sandbox). Put per-session setup here, including network policy, resources, timeout, per-user credentials, and one-time markers. Because it runs inside the active runtime context, it can read `ctx.session` and derive the current principal without baking credentials into the template. Call `use(opts?)` to get a `SandboxSession`; `opts` flow to the backend's update path after create.
212
+ - **`onSession({ use, ctx })`** is durable-session-scoped and runs once per session (and again if a sandbox definition change replaces the session's sandbox). Put per-session setup here, including network policy, resources, timeout, per-user credentials, and one-time markers. `ctx` contains only the active session metadata, so it can identify the current principal without exposing runtime lifecycle operations while the sandbox is initializing. Call `use(opts?)` to get a `SandboxSession`; `opts` flow to the backend's update path after create.
213
213
 
214
214
  If you require a network policy or other configuration for every session, configure it on the backend factory or in `onSession`; do not rely on bootstrap-only configuration.
215
215
 
@@ -248,6 +248,29 @@ stop-specific state is needed. Lifecycle `use()` calls return the I/O-only
248
248
  `SandboxSession` because bootstrap and session initialization do not own runtime
249
249
  teardown.
250
250
 
251
+ ### Delete a sandbox
252
+
253
+ Permanently delete the current session sandbox from an authored runtime callback:
254
+
255
+ ```ts
256
+ const sandbox = await ctx.getSandbox();
257
+ await sandbox.delete();
258
+ ```
259
+
260
+ eve stops compute first, deletes the physical sandbox and its disposable backend state, and clears the saved reconnect state. It preserves reusable template state that contains `bootstrap` and seeded workspace files.
261
+
262
+ The durable eve session remains active. The next call to `ctx.getSandbox()` provisions a fresh workspace from the current sandbox definition and runs `onSession` again. Files and other workspace changes from the deleted sandbox are not restored.
263
+
264
+ Backend behavior differs:
265
+
266
+ - **Vercel Sandbox**: stops the persistent sandbox, deletes its record, and asks Vercel to delete snapshots that no other sandbox uses. Snapshot cleanup runs asynchronously.
267
+ - **microsandbox**: stops and removes the session VM and its persisted state snapshot
268
+ - **Docker and just-bash**: stop compute and discard their session runtime state
269
+
270
+ Only the session that owns a shared sandbox can delete it. Deleting the owner's sandbox affects every parent or child currently using it. If the backend rejects deletion, eve preserves the current reconnect state so you can retry.
271
+
272
+ Custom backend handles implement the same boundary in `delete()`: remove the session runtime and disposable persisted state without deleting reusable templates.
273
+
251
274
  Session sandboxes are keyed per durable session, not per deployment, so redeploying your app does not by itself discard them. A definition change to the authored sandbox source, workspace seed content, or `revalidationKey` replaces the sandbox on the next turn and runs `onSession` again.
252
275
 
253
276
  Reattachment still depends on the backend retaining its physical sandbox state. If a persisted Vercel sandbox is no longer available, eve creates a replacement, using the current template when one is configured. Files and other changes made after the original sandbox was created are not restored automatically. Because the durable session still has the same sandbox key, `onSession` does not run again for this replacement. Persist important artifacts outside the sandbox, and do not rely on `onSession` as the only place that applies security-critical configuration.
@@ -84,6 +84,8 @@ The agent does not have to deliver a message on every run. When a prompt makes d
84
84
  - `waitUntil(promise)`: extends the cron task's lifetime so the parked session and any in-flight fetches settle before the task ends. Wrap the `send` call in it.
85
85
  - `appAuth`: the app principal (`{ authenticator: "app", principalId: "eve:app", principalType: "runtime" }`). Pass it as `to(...).send(..., { auth: appAuth })` for work the agent does on its own behalf.
86
86
 
87
+ The `auth` option controls which principal the session runs as. A handler may instead supply a user principal when scheduled work needs that user's grants; a session created by that dispatch still retains schedule provenance and conditional delivery behavior.
88
+
87
89
  A handler-form session runs on the same durable runtime engine as any other session, so it can park (durably suspend), for instance when the channel handoff is waiting for a Slack reply. Only markdown task mode is barred from waiting.
88
90
 
89
91
  ## Session continuity
@@ -72,6 +72,8 @@ framework-owned and is not yet a stable authored-tool API.
72
72
 
73
73
  After the initiating turn accepts background tasks, eve supplies runtime-authored state for that
74
74
  cohort and instructs the model to acknowledge that the work started without waiting for results.
75
+ [Schedule](/docs/schedules)-initiated turns are the exception: no user prompted them, so their
76
+ launches keep conditional delivery and send no acknowledgement.
75
77
  Later task-triggered parent turns receive fresh state for the same cohort. The model is instructed
76
78
  to keep related intermediate results silent while any task remains pending. Once every related
77
79
  task is terminal, the state includes their outputs so the model can combine the useful results.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve",
3
- "version": "0.46.0",
3
+ "version": "0.47.0",
4
4
  "private": false,
5
5
  "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
6
6
  "keywords": [
@@ -390,7 +390,7 @@
390
390
  "@chat-adapter/state-memory": "4.34.0",
391
391
  "@chat-adapter/twilio": "4.34.0",
392
392
  "@clack/core": "1.3.1",
393
- "@linqapp/chat-sdk-adapter": "^0.3.0",
393
+ "@linqapp/chat-sdk-adapter": "^0.5.1",
394
394
  "@modelcontextprotocol/server": "2.0.0",
395
395
  "@nuxt/kit": "^4.0.0",
396
396
  "@opentelemetry/context-async-hooks": "2.6.1",
@@ -408,6 +408,7 @@
408
408
  "@vercel/oidc": "3.8.0",
409
409
  "@vercel/otel": "2.1.3",
410
410
  "@vercel/sandbox": "2.8.0",
411
+ "@vercel/sandbox-delete": "npm:@vercel/sandbox@3.2.0",
411
412
  "@vercel/sandbox-drives": "npm:@vercel/sandbox@2.10.0-beta.0",
412
413
  "@vercel/sdk": "1.28.8",
413
414
  "@workflow/core": "5.0.0-beta.43",
@@ -1,2 +0,0 @@
1
- import{i as e,o as t,t as n}from"./rolldown-runtime-DaDcL9Zw.js";import{Et as r,Rn as i,Tn as a,Zn as o,_r as s,dn as c,wc as l,wn as u,yt as d}from"./schemas-DtQwuPdM.js";import{n as f}from"./compat-Dm2n85Mx.js";import{t as p}from"./version-BYHw-SDY.js";import*as m from"node:path";import h from"node:path";import{homedir as g}from"node:os";import _ from"node:fs";import*as ee from"node:fs/promises";import v from"os";import{setTimeout as y}from"node:timers/promises";const b=i().transform((e,t)=>{try{return JSON.parse(e)}catch(e){return t.addIssue({code:f.custom,message:`Invalid JSON: ${e.message}`}),l}});var x=n(((t,n)=>{let r=e(`os`),i=e(`path`),a=/^win/i.test(process.platform);function o(e){return i.normalize(i.join(e,`.`))}let s=()=>{let{env:e}=process,t={};return t.home=()=>o(r.homedir?r.homedir():e.HOME),t.temp=()=>o(r.tmpdir?r.tmpdir():e.TMPDIR||e.TEMP||e.TMP),t},c=()=>{let{env:e}=process,t={};return t.home=()=>o(r.homedir?r.homedir():e.USERPROFILE||i.join(e.HOMEDRIVE,e.HOMEPATH)||e.HOME),t.temp=()=>o(r.tmpdir?r.tmpdir():e.TEMP||e.TMP||i.join(e.LOCALAPPDATA||e.SystemRoot||e.windir,`Temp`)),t};n.exports=new class e{constructor(){let t=function(){return new e};this._fn=t;let n=a?c():s();return Object.keys(n).forEach(e=>{this._fn[e]=n[e]}),this._fn}}})),S=n(((t,n)=>{let r=e(`path`),i=x(),a=()=>{let e={};return e.cache=()=>process.env.XDG_CACHE_HOME||r.join(i.home()||i.temp(),`.cache`),e.config=()=>process.env.XDG_CONFIG_HOME||r.join(i.home()||i.temp(),`.config`),e.data=()=>process.env.XDG_DATA_HOME||r.join(i.home()||i.temp(),`.local`,`share`),e.runtime=()=>process.env.XDG_RUNTIME_DIR||void 0,e.state=()=>process.env.XDG_STATE_HOME||r.join(i.home()||i.temp(),`.local`,`state`),e},o=()=>{let e={};return e.cache=()=>process.env.XDG_CACHE_HOME||r.join(r.join(i.home()||i.temp(),`Library`),`Caches`),e.config=()=>process.env.XDG_CONFIG_HOME||r.join(r.join(i.home()||i.temp(),`Library`),`Preferences`),e.data=()=>process.env.XDG_DATA_HOME||r.join(r.join(i.home()||i.temp(),`Library`),`Application Support`),e.runtime=()=>process.env.XDG_RUNTIME_DIR||void 0,e.state=()=>process.env.XDG_STATE_HOME||r.join(r.join(i.home()||i.temp(),`Library`),`State`),e},s=()=>{let e={};return e.cache=()=>{let e=process.env.LOCALAPPDATA||r.join(i.home()||i.temp(),`AppData`,`Local`);return process.env.XDG_CACHE_HOME||r.join(e,`xdg.cache`)},e.config=()=>{let e=process.env.APPDATA||r.join(i.home()||i.temp(),`AppData`,`Roaming`);return process.env.XDG_CONFIG_HOME||r.join(e,`xdg.config`)},e.data=()=>{let e=process.env.APPDATA||r.join(i.home()||i.temp(),`AppData`,`Roaming`);return process.env.XDG_DATA_HOME||r.join(e,`xdg.data`)},e.runtime=()=>process.env.XDG_RUNTIME_DIR||void 0,e.state=()=>{let e=process.env.LOCALAPPDATA||r.join(i.home()||i.temp(),`AppData`,`Local`);return process.env.XDG_STATE_HOME||r.join(e,`xdg.state`)},e},c=()=>{let e=function(){return c()},t={};return t=/^darwin$/i.test(process.platform)?o():/^win/i.test(process.platform)?s():a(),t.configDirs=()=>{let e=[];return e.push(t.config()),process.env.XDG_CONFIG_DIRS&&e.push(...process.env.XDG_CONFIG_DIRS.split(r.delimiter)),e},t.dataDirs=()=>{let e=[];return e.push(t.data()),process.env.XDG_DATA_DIRS&&e.push(...process.env.XDG_DATA_DIRS.split(r.delimiter)),e},Object.keys(t).forEach(n=>{e[n]=t[n]}),e};n.exports=c()})),C=t(n(((t,n)=>{let r=e(`path`),i=e(`os`),a=S(),o=/^win/i.test(process.platform);function s(e,t){if(e||={},typeof e!=`object`&&(e={isolated:e}),e.isolated=e.isolated===void 0||e.isolated===null?t:e.isolated,typeof e.isolated!=`boolean`)throw TypeError(`Expected boolean for "isolated" argument, got ${typeof e.isolated}`);return e}let c=(e,t)=>{let n={};return n.cache=(n={isolated:null})=>(n=s(n,t),r.join(a.cache(),n.isolated?e:``)),n.config=(n={isolated:null})=>(n=s(n,t),r.join(a.config(),n.isolated?e:``)),n.data=(n={isolated:null})=>(n=s(n,t),r.join(a.data(),n.isolated?e:``)),n.runtime=(n={isolated:null})=>(n=s(n,t),a.runtime()?r.join(a.runtime(),n.isolated?e:``):void 0),n.state=(n={isolated:null})=>(n=s(n,t),r.join(a.state(),n.isolated?e:``)),n.configDirs=(n={isolated:null})=>(n=s(n,t),a.configDirs().map(t=>r.join(t,n.isolated?e:``))),n.dataDirs=(n={isolated:null})=>(n=s(n,t),a.dataDirs().map(t=>r.join(t,n.isolated?e:``))),n},l=(e,t)=>{let{env:n}=process,o=i.homedir(),c=i.tmpdir(),l=n.APPDATA||r.join(o||c,`AppData`,`Roaming`),u=n.LOCALAPPDATA||r.join(o||c,`AppData`,`Local`),d={};return d.cache=(i={isolated:null})=>(i=s(i,t),!i.isolated||n.XDG_CACHE_HOME?r.join(a.cache(),i.isolated?e:``):r.join(u,i.isolated?e:``,`Cache`)),d.config=(i={isolated:null})=>(i=s(i,t),!i.isolated||n.XDG_CONFIG_HOME?r.join(a.config(),i.isolated?e:``):r.join(l,i.isolated?e:``,`Config`)),d.data=(i={isolated:null})=>(i=s(i,t),!i.isolated||n.XDG_DATA_HOME?r.join(a.data(),i.isolated?e:``):r.join(l,i.isolated?e:``,`Data`)),d.runtime=(n={isolated:null})=>(n=s(n,t),a.runtime()?r.join(a.runtime(),n.isolated?e:``):void 0),d.state=(i={isolated:null})=>(i=s(i,t),!i.isolated||n.XDG_STATE_HOME?r.join(a.state(),i.isolated?e:``):r.join(u,i.isolated?e:``,`State`)),d.configDirs=(i={isolated:null})=>{i=s(i,t);let a=[d.config(i)];return n.XDG_CONFIG_DIRS&&a.push(...n.XDG_CONFIG_DIRS.split(r.delimiter).map(t=>r.join(t,i.isolated?e:``))),a},d.dataDirs=(i={isolated:null})=>{i=s(i,t);let a=[d.data(i)];return n.XDG_DATA_DIRS&&a.push(...n.XDG_DATA_DIRS.split(r.delimiter).map(t=>r.join(t,i.isolated?e:``))),a},d};n.exports=new class t{constructor(n={name:null,suffix:null,isolated:!0}){let i=function(e={name:null,suffix:null,isolated:!0}){return new t(e)};this._fn=i,n||={},typeof n!=`object`&&(n={name:n});let a=n.name||``;if(typeof a!=`string`)throw TypeError(`Expected string for "name" argument, got ${typeof a}`);let s=n.suffix||``;if(typeof s!=`string`)throw TypeError(`Expected string for "suffix" argument, got ${typeof s}`);let u=n.isolated===void 0||n.isolated===null||n.isolated;if(typeof u!=`boolean`)throw TypeError(`Expected boolean for "isolated" argument, got ${typeof u}`);a||=r.parse(process.pkg?process.execPath:e.main?e.main.filename:process.argv[0]).name,s&&(a+=s),this._fn.$name=()=>a,this._fn.$isolated=()=>u;let d=o?l(a,u):c(a,u);return Object.keys(d).forEach(e=>{this._fn[e]=d[e]}),this._fn}}}))(),1);const w=u().transform(e=>new Date(e*1e3)),T=a({token:i().min(1).optional(),refreshToken:i().min(1).optional(),expiresAt:w.optional()}),E=b.pipe(T),te=e=>{try{return _.lstatSync(e).isDirectory()}catch{return!1}},D=()=>{if(process.env.VERCEL_AUTH_CONFIG_DIR)return process.env.VERCEL_AUTH_CONFIG_DIR;let e=(0,C.default)(`com.vercel.cli`).dataDirs();return[...e,h.join(g(),`.now`),...(0,C.default)(`now`).dataDirs()].find(e=>te(e))||e[0]},ne=()=>{try{let e=h.join(D(),`auth.json`);return E.parse(_.readFileSync(e,`utf8`))}catch{return null}};function O(e){let t=h.join(D(),`auth.json`);_.mkdirSync(h.dirname(t),{recursive:!0});let n={token:e.token,expiresAt:e.expiresAt&&Math.round(e.expiresAt.getTime()/1e3),refreshToken:e.refreshToken};_.writeFileSync(t,JSON.stringify(n)+`
2
- `)}const k=`${v.hostname()} @ vercel/sandbox/${p} node-${process.version} ${v.platform()} (${v.arch()})`,A=new URL(`https://vercel.com`),j=`cl_HYyOPBNtFMfHhaUn9L4QPfTZz6TP47bp`,M=a({issuer:i().url(),device_authorization_endpoint:i().url(),token_endpoint:i().url(),revocation_endpoint:i().url(),jwks_uri:i().url(),introspection_endpoint:i().url()});let N;const P=a({device_code:i(),user_code:i(),verification_uri:i().url(),verification_uri_complete:i().url(),expires_in:u(),interval:u()}),F=a({active:c(!0),client_id:i(),session_id:i()}).or(a({active:c(!1)}));async function I(){if(N)return N;let e=await fetch(new URL(`.well-known/openid-configuration`,A),{headers:{"Content-Type":`application/json`,"user-agent":k}});return N=M.parse(await e.json()),N}async function L(){let e=await I();return{async deviceAuthorizationRequest(){let t=await(await fetch(e.device_authorization_endpoint,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`,"user-agent":k},body:new URLSearchParams({client_id:j,scope:`openid offline_access`})})).json(),n=P.safeParse(t);if(!n.success)throw new V(`Failed to parse device authorization response from the Vercel authorization server.`,t);return{device_code:n.data.device_code,user_code:n.data.user_code,verification_uri:n.data.verification_uri,verification_uri_complete:n.data.verification_uri_complete,expiresAt:Date.now()+n.data.expires_in*1e3,interval:n.data.interval}},async deviceAccessTokenRequest(t){try{return[null,await fetch(e.token_endpoint,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`,"user-agent":k},body:new URLSearchParams({client_id:j,grant_type:`urn:ietf:params:oauth:grant-type:device_code`,device_code:t}),signal:AbortSignal.timeout(10*1e3)})]}catch(e){return e instanceof Error?[e]:[Error(`An unknown error occurred. See the logs for details.`,{cause:e})]}},async processTokenResponse(e){let t=await e.json(),n=R.safeParse(t);return n.success?[null,n.data]:[new V(`Failed to parse token response from the Vercel authorization server.`,t)]},async revokeToken(t){let n=await fetch(e.revocation_endpoint,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`,"user-agent":k},body:new URLSearchParams({token:t,client_id:j})});if(!n.ok)return new V(`Revocation request failed`,await n.json())},async refreshToken(t){let n=await fetch(e.token_endpoint,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`,"user-agent":k},body:new URLSearchParams({client_id:j,grant_type:`refresh_token`,refresh_token:t})}),[r,i]=await this.processTokenResponse(n);if(r)throw r;return i},async introspectToken(t){let n=await(await fetch(e.introspection_endpoint,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`,"user-agent":k},body:new URLSearchParams({token:t})})).json(),r=F.safeParse(n);if(!r.success)throw new V(`Failed to parse introspection response from the Vercel authorization server.`,n);return r.data}}}const R=a({access_token:i(),token_type:c(`Bearer`),expires_in:u(),refresh_token:i().optional(),scope:i().optional()}),z=a({error:d([`invalid_request`,`invalid_client`,`invalid_grant`,`unauthorized_client`,`unsupported_grant_type`,`invalid_scope`,`server_error`,`authorization_pending`,`slow_down`,`access_denied`,`expired_token`,`unsupported_token_type`]),error_description:i().optional(),error_uri:i().optional()});function B(e){try{return z.parse(e)}catch(e){return e instanceof s?TypeError(`Invalid OAuth error response: ${e.message}`):TypeError(`Failed to parse OAuth error response`)}}var V=class extends Error{constructor(e,t){super(e),this.name=`OAuthError`;let n=B(t);if(n instanceof TypeError){this.cause=Error(`Unexpected response from the Vercel authorization server.`),this.code=`server_error`;return}let r=n.error;n.error_description&&(r+=`: ${n.error_description}`),n.error_uri&&(r+=` (${n.error_uri})`),this.cause=Error(r),this.code=n.error}};function H(e){return e instanceof V}async function*U({request:e,oauth:t}){let n=new AbortController;try{let r=e.interval*1e3;for(;Date.now()<e.expiresAt;){let[i,a]=await t.deviceAccessTokenRequest(e.device_code);if(i){if(i.message.includes(`timeout`)){r*=2,yield{_tag:`Timeout`,newInterval:r},await y(r,{signal:n.signal});continue}yield{_tag:`Error`,error:i};return}yield{_tag:`Response`,response:a.clone()};let[o,s]=await t.processTokenResponse(a);if(H(o)){let{code:e}=o;switch(e){case`authorization_pending`:await y(r,{signal:n.signal});continue;case`slow_down`:r+=5*1e3,yield{_tag:`SlowDown`,newInterval:r},await y(r,{signal:n.signal});continue;default:yield{_tag:`Error`,error:o.cause};return}}if(o){yield{_tag:`Error`,error:o};return}O({token:s.access_token,expiresAt:new Date(Date.now()+s.expires_in*1e3),refreshToken:s.refresh_token});return}yield{_tag:`Error`,error:Error(`Timed out waiting for authentication. Please try again.`)};return}finally{n.abort()}}var W=class extends Error{constructor(e){super(`HTTP ${e.statusCode}: ${e.responseText}`),this.name=`NotOk`,this.response=e}};async function G(e){let t=await fetch(`https://vercel.com/api${e.endpoint}`,{method:e.method,body:e.body,headers:{Authorization:`Bearer ${e.token}`,"Content-Type":`application/json`}});if(!t.ok){let e=await t.text();try{let{error:t}=JSON.parse(e);e=`${t.code.toUpperCase()}: ${t.message}`}catch{}throw new W({responseText:e,statusCode:t.status})}return await t.json()}const K=b.pipe(a({projectId:i(),orgId:i()}));async function q(e){let t=m.join(e,`.vercel`,`project.json`),n;try{n=await ee.readFile(t,`utf-8`)}catch{return null}let r=K.safeParse(n);return r.success?{projectId:r.data.projectId,teamId:r.data.orgId}:null}const J=a({user:a({defaultTeamId:i().nullable(),username:i()})}),Y=a({id:i(),slug:i(),updatedAt:u().optional(),membership:a({role:i()}),billing:a({plan:i()})}),X=a({teams:r(o()).transform(e=>e.flatMap(e=>{let t=Y.safeParse(e);return t.success?[t.data]:[]})),pagination:a({count:u(),next:u().nullable()})}),Z=`vercel-sandbox-default-project`;function Q(e){return e instanceof W&&(e.response.statusCode===402||e.response.statusCode===403)}async function re(e){let t=await q(e.cwd??process.cwd());if(t){let n=await ie(e.token,t.teamId,t.projectId);return{...t,created:!1,...n}}if(e.teamId)return $(e.token,e.teamId);let{defaultTeamId:n,username:r}=(await G({token:e.token,endpoint:`/v2/user`}).then(J.parse)).user;if(n)try{let t=await $(e.token,n);try{let r=await G({token:e.token,endpoint:`/v2/teams/${encodeURIComponent(n)}`}).then(a({slug:i()}).parse);return{...t,teamSlug:r.slug}}catch{return t}}catch(e){if(!Q(e))throw e}let o=null;do{let t=o===null?`/v2/teams?limit=20`:`/v2/teams?limit=20&until=${o}`,i=await G({token:e.token,endpoint:t}).then(X.parse);o=i.pagination.next;let a=i.teams.filter(e=>e.membership.role===`OWNER`&&e.billing.plan===`hobby`);if(a.length===0)continue;let s=a.find(e=>e.slug===r)??a.sort((e,t)=>(t.updatedAt??0)-(e.updatedAt??0))[0];if(s&&s.id!==n)try{return{...await $(e.token,s.id),teamSlug:s.slug}}catch(e){if(!Q(e))throw e}}while(o!==null);try{return{...await $(e.token,r),teamSlug:r}}catch(e){if(!Q(e))throw e}throw new W({statusCode:403,responseText:`Authenticated as "${r}" but none of the available teams allow sandbox creation.`})}async function $(e,t){let n=t.startsWith(`team_`)?`teamId=${encodeURIComponent(t)}`:`slug=${encodeURIComponent(t)}`,r=!1;try{await G({token:e,endpoint:`/v2/projects/vercel-sandbox-default-project?${n}`})}catch(t){if(!(t instanceof W)||t.response.statusCode!==404)throw t;await G({token:e,endpoint:`/v11/projects?${n}`,method:`POST`,body:JSON.stringify({name:Z})}),r=!0}return{projectId:Z,teamId:t,created:r}}async function ie(e,t,n){try{let r=t.startsWith(`team_`)?`teamId=${encodeURIComponent(t)}`:`slug=${encodeURIComponent(t)}`,[o,s]=await Promise.all([G({token:e,endpoint:`/v2/teams/${encodeURIComponent(t)}`}).then(a({slug:i()}).parse),G({token:e,endpoint:`/v2/projects/${encodeURIComponent(n)}?${r}`}).then(a({name:i()}).parse)]);return{teamSlug:o.slug,projectSlug:s.name}}catch{return{}}}export{W as NotOk,L as OAuth,ne as getAuth,re as inferScope,H as isOAuthError,U as pollForToken,O as updateAuthConfig};