eve 0.83.0 → 0.83.2

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 (147) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/src/channel/types.d.ts +3 -2
  3. package/dist/src/chunks/{use-eve-agent-Ci5dr0aR.js → use-eve-agent-DnbG9c7c.js} +33 -9
  4. package/dist/src/chunks/{use-eve-agent-3-WRmJkd.js → use-eve-agent-ZY7NQ2VW.js} +33 -9
  5. package/dist/src/cli/run.js +1 -1
  6. package/dist/src/client/message-response.d.ts +18 -0
  7. package/dist/src/client/message-response.js +1 -1
  8. package/dist/src/client/session.js +1 -1
  9. package/dist/src/compiled/.vendor-stamp.json +2 -2
  10. package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
  11. package/dist/src/compiled/@eve/catalog/index.js +1 -1
  12. package/dist/src/context/build-dynamic-tools.js +1 -1
  13. package/dist/src/context/dynamic-skill-lifecycle.d.ts +2 -2
  14. package/dist/src/context/dynamic-skill-lifecycle.js +1 -1
  15. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  16. package/dist/src/context/prewarm.d.ts +27 -0
  17. package/dist/src/context/prewarm.js +1 -0
  18. package/dist/src/context/providers/sandbox.d.ts +7 -0
  19. package/dist/src/context/providers/sandbox.js +1 -1
  20. package/dist/src/context/run-step.js +1 -1
  21. package/dist/src/discover/lib.d.ts +4 -3
  22. package/dist/src/discover/lib.js +1 -1
  23. package/dist/src/discover/named-source-directory.d.ts +3 -2
  24. package/dist/src/evals/assertions/run.js +1 -1
  25. package/dist/src/evals/cli/eval.d.ts +2 -0
  26. package/dist/src/evals/cli/eval.js +2 -2
  27. package/dist/src/evals/define-eval-config.d.ts +5 -4
  28. package/dist/src/evals/define-eval-config.js +1 -1
  29. package/dist/src/evals/index.d.ts +1 -1
  30. package/dist/src/evals/runner/artifacts.js +2 -2
  31. package/dist/src/evals/runner/attempt-label.d.ts +2 -0
  32. package/dist/src/evals/runner/attempt-label.js +1 -0
  33. package/dist/src/evals/runner/derive-run-facts.d.ts +13 -0
  34. package/dist/src/evals/runner/derive-run-facts.js +1 -1
  35. package/dist/src/evals/runner/reporters/braintrust.js +1 -1
  36. package/dist/src/evals/runner/reporters/console.js +1 -1
  37. package/dist/src/evals/runner/reporters/datadog.js +1 -1
  38. package/dist/src/evals/runner/reporters/junit.js +2 -2
  39. package/dist/src/evals/runner/reporters/types.d.ts +2 -0
  40. package/dist/src/evals/runner/run-evals.d.ts +5 -0
  41. package/dist/src/evals/runner/run-evals.js +1 -1
  42. package/dist/src/evals/session-manager.js +1 -1
  43. package/dist/src/evals/session.d.ts +4 -1
  44. package/dist/src/evals/session.js +2 -2
  45. package/dist/src/evals/types.d.ts +37 -1
  46. package/dist/src/eve-channel/request.js +1 -1
  47. package/dist/src/execution/catalog/connection-entry.js +1 -1
  48. package/dist/src/execution/connections/callback-route.d.ts +3 -2
  49. package/dist/src/execution/connections/callback-route.js +1 -1
  50. package/dist/src/execution/dynamic-workflow/tool.js +1 -1
  51. package/dist/src/execution/node-step.d.ts +1 -0
  52. package/dist/src/execution/node-step.js +1 -1
  53. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  54. package/dist/src/execution/sandbox/ensure.d.ts +8 -0
  55. package/dist/src/execution/sandbox/ensure.js +1 -1
  56. package/dist/src/execution/sandbox/multiplexed-command.d.ts +9 -3
  57. package/dist/src/execution/sandbox/multiplexed-command.js +1 -1
  58. package/dist/src/execution/sandbox/read-file.js +1 -1
  59. package/dist/src/execution/session/handoff-steps.d.ts +1 -0
  60. package/dist/src/execution/session/handoff-steps.js +1 -1
  61. package/dist/src/execution/session/handoff.js +1 -1
  62. package/dist/src/execution/session/handover-tracing.d.ts +3 -0
  63. package/dist/src/execution/session/handover-tracing.js +1 -0
  64. package/dist/src/execution/session/prewarm-step.d.ts +13 -0
  65. package/dist/src/execution/session/prewarm-step.js +1 -0
  66. package/dist/src/execution/session/program.d.ts +4 -1
  67. package/dist/src/execution/session/program.js +1 -1
  68. package/dist/src/execution/session/state-cursor.d.ts +11 -0
  69. package/dist/src/execution/session/state-cursor.js +1 -1
  70. package/dist/src/execution/session/turn-step-types.d.ts +2 -0
  71. package/dist/src/execution/session/turn-step.js +1 -1
  72. package/dist/src/execution/session/turn.d.ts +1 -0
  73. package/dist/src/execution/session/turn.js +1 -1
  74. package/dist/src/execution/session-event-stream.d.ts +6 -0
  75. package/dist/src/execution/session-event-stream.js +1 -1
  76. package/dist/src/execution/session-inbox/inbox.d.ts +8 -0
  77. package/dist/src/execution/session-inbox/inbox.js +1 -1
  78. package/dist/src/execution/tools/agent-router-workflow.js +1 -1
  79. package/dist/src/execution/workflow-runtime.js +1 -1
  80. package/dist/src/extensions/git/extension/lib/gh-tool.d.ts +11 -2
  81. package/dist/src/extensions/git/extension/lib/gh-tool.js +1 -1
  82. package/dist/src/harness/attachment-staging.d.ts +3 -0
  83. package/dist/src/harness/attachment-staging.js +1 -1
  84. package/dist/src/harness/compaction/step.d.ts +7 -1
  85. package/dist/src/harness/compaction/step.js +1 -1
  86. package/dist/src/harness/hitl/approvals.d.ts +2 -0
  87. package/dist/src/harness/hitl/approvals.js +1 -1
  88. package/dist/src/harness/hitl/delivery.d.ts +1 -0
  89. package/dist/src/harness/hitl/delivery.js +1 -1
  90. package/dist/src/harness/hitl/intake.js +1 -1
  91. package/dist/src/harness/model-call/call.d.ts +2 -0
  92. package/dist/src/harness/model-call/call.js +1 -1
  93. package/dist/src/harness/model-call/request.d.ts +2 -1
  94. package/dist/src/harness/token-estimate.js +1 -1
  95. package/dist/src/harness/types.d.ts +6 -0
  96. package/dist/src/internal/application/stamped-package-version.js +1 -1
  97. package/dist/src/internal/attachments/media-metadata.d.ts +0 -2
  98. package/dist/src/internal/attachments/media-metadata.js +1 -1
  99. package/dist/src/internal/attachments/read-media-metadata.d.ts +7 -0
  100. package/dist/src/internal/attachments/read-media-metadata.js +2 -0
  101. package/dist/src/internal/authored-asset-import-plugin.d.ts +7 -0
  102. package/dist/src/internal/authored-asset-import-plugin.js +1 -1
  103. package/dist/src/internal/authored-module-build-options.js +1 -1
  104. package/dist/src/internal/authored-module-graph.js +1 -1
  105. package/dist/src/internal/authored-module-loader.d.ts +0 -1
  106. package/dist/src/internal/authored-module-loader.js +1 -1
  107. package/dist/src/internal/authored-package-boundary.d.ts +3 -0
  108. package/dist/src/internal/authored-package-boundary.js +1 -1
  109. package/dist/src/internal/input-text.d.ts +2 -1
  110. package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
  111. package/dist/src/internal/workflow-bundle/builder.js +2 -2
  112. package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +1 -1
  113. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  114. package/dist/src/runtime/connections/authorization-complete-page.d.ts +14 -2
  115. package/dist/src/runtime/connections/authorization-complete-page.js +5 -5
  116. package/dist/src/runtime/subagents/workflow.js +1 -1
  117. package/dist/src/sandbox/state.d.ts +17 -0
  118. package/dist/src/setup/scaffold/create/project.js +1 -1
  119. package/dist/src/svelte/index.js +1 -1
  120. package/dist/src/svelte/use-eve-agent.js +1 -1
  121. package/dist/src/tools/definition.js +1 -1
  122. package/dist/src/tools/durable-callbacks.d.ts +5 -1
  123. package/dist/src/tools/durable-callbacks.js +1 -1
  124. package/dist/src/tools/dynamic.d.ts +3 -3
  125. package/dist/src/tools/provided/ask-question-workflow.js +1 -1
  126. package/dist/src/tools/provided/sleep-workflow.js +1 -1
  127. package/dist/src/vue/index.js +1 -1
  128. package/dist/src/vue/use-eve-agent.js +1 -1
  129. package/docs/channels/custom.mdx +4 -0
  130. package/docs/channels/slack.mdx +2 -0
  131. package/docs/concepts/built-in-tools.md +1 -1
  132. package/docs/connections/mcp.mdx +1 -1
  133. package/docs/evals/overview.mdx +1 -1
  134. package/docs/evals/reporters.mdx +4 -4
  135. package/docs/evals/running.mdx +19 -1
  136. package/docs/guides/dynamic-capabilities.md +2 -2
  137. package/docs/guides/frontend/overview.mdx +7 -3
  138. package/docs/guides/instrumentation/otel.mdx +23 -0
  139. package/docs/meta.json +1 -0
  140. package/docs/reference/agent-files.md +1 -1
  141. package/docs/reference/cli.md +17 -15
  142. package/docs/sandbox/custom-providers.mdx +10 -10
  143. package/docs/sandbox/index.mdx +6 -4
  144. package/docs/tools/human-in-the-loop.md +3 -1
  145. package/docs/tools/overview.mdx +1 -1
  146. package/docs/use-cases.mdx +250 -0
  147. package/package.json +1 -1
@@ -1,3 +1,3 @@
1
- import{isInputResponse}from"#shared/input.js";import{hasInternalRefScheme}from"#internal/attachments/url-refs.js";import{EVE_MESSAGE_STREAM_CONTENT_TYPE,EVE_MESSAGE_STREAM_FORMAT,EVE_MESSAGE_STREAM_VERSION,EVE_SESSION_ID_HEADER,EVE_STREAM_CONTROL_VERSION,EVE_STREAM_CONTROL_VERSION_QUERY,EVE_STREAM_FORMAT_HEADER,EVE_STREAM_LEASE_ENDED_CONTROL,EVE_STREAM_TAIL_INDEX_HEADER,EVE_STREAM_VERSION_HEADER}from"#protocol/message.js";import{parseJsonObject}from"#shared/json.js";import{LEGACY_REMOTE_AGENT_PROTOCOL_VERSION,splitLegacyTaskFields}from"#execution/legacy-remote-agent/protocol.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation}from"#public/channels/upload-policy.js";import{strandedSessionResponse}from"#eve-channel/support.js";import{parseToolStubs}from"#tool-stubs/rules.js";import{parseSessionCallback}from"#channel/session-callback.js";import{isExpiredWorkflowRunError,isMissingWorkflowRunError}from"#internal/workflow/is-inactive-workflow-run-error.js";import{REMOTE_AGENT_PROTOCOL_MISMATCH,REMOTE_AGENT_PROTOCOL_VERSION,readRemoteAgentProtocolVersion}from"#protocol/remote-agent-protocol.js";import{parseTurnPolicyField}from"#eve-channel/turn-policy-request.js";import{validateMessageFreeCreate}from"#eve-channel/create-request.js";async function deriveOperationContinuationToken(e){let t=JSON.stringify([`eve:create-session:v1`,e.auth.authenticator,e.auth.issuer??null,e.auth.principalType,e.auth.principalId,e.operationId]),n=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(t));return`eve:op:${Array.from(new Uint8Array(n),e=>e.toString(16).padStart(2,`0`)).join(``).slice(0,32)}`}function parseCreateBody(e){let t=splitLegacyTaskFields(e),{payload:n}=t;if(n.inputResponses!==void 0)return Response.json({error:`'inputResponses' is only accepted for an existing session.`,ok:!1},{status:400});let r=parseMessageField(n.message);if(r instanceof Response)return r;let i=parseClientContextField(n.clientContext);if(i instanceof Response)return i;let a=parseCallbackField(n.callback);if(a instanceof Response)return a;let o=a===void 0?void 0:parseProtocolVersionField(n.protocolVersion);if(o instanceof Response)return o;let s=parseCapabilitiesField(n.capabilities);if(s instanceof Response)return s;let c=parseOutputSchemaField(n.outputSchema);if(c instanceof Response)return c;let l=validateMessageFreeCreate({callback:a,hasClientContext:n.clientContext!==void 0,hasMessageField:`message`in n,message:r,outputSchema:c});if(l!==void 0)return l;let u=n.operationId;if(u!==void 0&&(typeof u!=`string`||!u))return Response.json({error:`Expected 'operationId' to be a non-empty string.`,ok:!1},{status:400});let d={callback:a,capabilities:s,context:i,outputSchema:c};if(n.stubs!==void 0)try{d.stubs=parseToolStubs(n.stubs)}catch(e){return Response.json({ok:!1,error:e instanceof Error?e.message:`Invalid tool stubs.`},{status:400})}return r!==void 0&&(d.message=r),typeof u==`string`&&(d.operationId=u),o!==void 0&&(d.protocolVersion=o),o===LEGACY_REMOTE_AGENT_PROTOCOL_VERSION&&(d.legacyRemoteAgentCaller=t.taskId===void 0?{}:{taskId:t.taskId}),d}function parseSessionMessageBody(e){let{payload:t}=splitLegacyTaskFields(e);if(Object.hasOwn(t,`stubs`))return Response.json({ok:!1,error:`Tool stubs are fixed at session creation.`},{status:400});let n=rejectSessionContinuationToken(t);if(n!==null)return n;let r=parseMessageField(t.message);if(r instanceof Response)return r;let i=parseCallbackField(t.callback);if(i instanceof Response)return i;let a=parseInputResponses$1(t.inputResponses);if(a instanceof Response)return a;let o=parseClientContextField(t.clientContext);if(o instanceof Response)return o;let s=parseOutputSchemaField(t.outputSchema);if(s instanceof Response)return s;let c=parseTurnPolicyField(t.turnPolicy);return c instanceof Response?c:r===void 0&&a===void 0?Response.json({error:`Expected a non-empty 'message' or a non-empty 'inputResponses' array.`,ok:!1},{status:400}):r!==void 0&&a!==void 0?Response.json({error:`'message' and 'inputResponses' are mutually exclusive.`,ok:!1},{status:400}):{callback:i,message:r,inputResponses:a,context:o,outputSchema:s,turnPolicy:c}}async function parseCancelTurnBody(e){let t=await parseOptionalJsonRequest(e);if(t instanceof Response)return t;let n=rejectSessionContinuationToken(t);if(n!==null)return n;let r=t.turnId;return r!==void 0&&(typeof r!=`string`||r.length===0)?Response.json({error:`Expected 'turnId' to be a non-empty string.`,ok:!1},{status:400}):typeof r==`string`?{turnId:r}:{}}async function parseResetBody(e){let t=await parseOptionalJsonRequest(e);if(t instanceof Response)return t;let n=rejectSessionContinuationToken(t);if(n!==null)return n;let r=t.reason;return r!==void 0&&(typeof r!=`string`||r.length===0)?Response.json({error:`Expected 'reason' to be a non-empty string.`,ok:!1},{status:400}):r===void 0?{}:{reason:r}}async function parseSessionControlBody(e){let t=await parseOptionalJsonRequest(e);return t instanceof Response?t:rejectSessionContinuationToken(t)??t}async function parseOptionalJsonRequest(e){let t;try{t=await e.text()}catch{return Response.json({error:`Unreadable request body.`,ok:!1},{status:400})}if(t.trim().length===0)return{};let n;try{n=JSON.parse(t)}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}return typeof n!=`object`||!n||Array.isArray(n)?Response.json({error:`Expected a JSON object.`,ok:!1},{status:400}):n}function rejectSessionContinuationToken(e){return`continuationToken`in e?Response.json({error:`Session-ID routes do not accept 'continuationToken'.`,ok:!1},{status:400}):null}function requireSessionId(e){return e.sessionId||Response.json({error:`Missing session id.`,ok:!1},{status:400})}async function createSessionStreamResponse(e,t){let n=parseStartIndex(e);if(n instanceof Response)return n;let r=parseFollow(e),i=!r||parseIncludeTailIndex(e);try{let a=t.getEventStream({follow:r,startIndex:n});a.catch(()=>{});let o;try{o=await t.getStreamTailIndex()}catch(e){throw a.then(e=>e.cancel()).catch(()=>{}),e}let s=await a,c=new URL(e.url).searchParams.get(EVE_STREAM_CONTROL_VERSION_QUERY)===EVE_STREAM_CONTROL_VERSION?EVE_STREAM_CONTROL_VERSION:void 0,l=new Headers({"cache-control":`no-store, no-transform`,"content-type":EVE_MESSAGE_STREAM_CONTENT_TYPE,"x-accel-buffering":`no`,[EVE_SESSION_ID_HEADER]:t.id,[EVE_STREAM_FORMAT_HEADER]:EVE_MESSAGE_STREAM_FORMAT,[EVE_STREAM_VERSION_HEADER]:EVE_MESSAGE_STREAM_VERSION});return i&&l.set(EVE_STREAM_TAIL_INDEX_HEADER,String(o)),new Response(serializeAsNdjson(s,e.signal,i?streamEventLimit(n,o):void 0,c!==void 0),{headers:l})}catch(e){let t=strandedSessionResponse(e);if(t!==void 0)return t;if(isExpiredWorkflowRunError(e))return Response.json({code:`session_expired`,error:`Session history is no longer available.`,ok:!1},{headers:{"cache-control":`no-store`},status:410});let n=isMissingWorkflowRunError(e);return Response.json({error:n?`Session not found.`:`Session stream unavailable.`,ok:!1},{status:n?404:503})}}function parseOutputSchemaField(e){if(e!==void 0)try{return parseJsonObject(e)}catch{return Response.json({error:`Expected 'outputSchema' to be a JSON-serializable object.`,ok:!1},{status:400})}}function parseCallbackField(e){if(e===void 0)return;let t=parseSessionCallback(e);return t.ok?t.callback:Response.json({error:t.message,ok:!1},{status:400})}function parseProtocolVersionField(e){if(e!==void 0&&typeof e!=`number`)return Response.json({error:`Expected 'protocolVersion' to be a number.`,ok:!1},{status:400});let t=readRemoteAgentProtocolVersion(e);return t===REMOTE_AGENT_PROTOCOL_VERSION||t===LEGACY_REMOTE_AGENT_PROTOCOL_VERSION?t:Response.json({code:REMOTE_AGENT_PROTOCOL_MISMATCH,error:`This deployment speaks eve remote agent protocol ${String(REMOTE_AGENT_PROTOCOL_VERSION)}, but the caller speaks protocol ${String(t)}. Upgrade both deployments to the same eve release.`,ok:!1,protocolVersion:REMOTE_AGENT_PROTOCOL_VERSION},{status:409})}function parseCapabilitiesField(e){if(e===void 0)return;if(typeof e!=`object`||!e||Array.isArray(e))return Response.json({error:`Expected 'capabilities' to be an object.`,ok:!1},{status:400});let t=Object.keys(e),n=Reflect.get(e,`requestInput`);return t.some(e=>e!==`requestInput`)||n!==void 0&&typeof n!=`boolean`?Response.json({error:`Expected 'capabilities.requestInput' to be a boolean when provided.`,ok:!1},{status:400}):n===void 0?{}:{requestInput:n}}function parseMessageField(e){if(e===void 0)return;if(typeof e==`string`)return e.length>0?e:void 0;if(!Array.isArray(e))return Response.json({error:`Expected 'message' to be a string or an array of text/file parts.`,ok:!1},{status:400});if(e.length===0)return;let t=[];for(let n of e){let e=parseMessagePart(n);if(e instanceof Response)return e;t.push(e)}return t}function parseMessagePart(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected each message part to be an object.`,ok:!1},{status:400});let t=e;if(t.type===`text`)return typeof t.text!=`string`||t.text.length===0?Response.json({error:`Text parts require a non-empty 'text' string.`,ok:!1},{status:400}):{type:`text`,text:t.text};if(t.type===`file`){if(typeof t.mediaType!=`string`||t.mediaType.length===0)return Response.json({error:`File parts require a non-empty 'mediaType' string.`,ok:!1},{status:400});if(typeof t.data!=`string`)return Response.json({error:`File parts require a 'data' string (base64, data URL, or URL).`,ok:!1},{status:400});if(hasInternalRefScheme(t.data))return Response.json({error:`File part 'data' must not use a framework-internal ref scheme.`,ok:!1},{status:400});let e={type:`file`,mediaType:t.mediaType,data:t.data};return typeof t.filename==`string`&&t.filename.length>0&&(e.filename=t.filename),e}return Response.json({error:`Unsupported message part type "${String(t.type)}". Use 'text' or 'file'.`,ok:!1},{status:400})}function checkUploadPolicy(e,t){if(!e.message)return null;let n=collectUploadPolicyViolations(e.message,t);if(n.length===0)return null;let[r]=n;if(!r)return null;let i=r.kind===`too-large`?413:415;return Response.json({error:formatUploadPolicyViolation(r),ok:!1,violations:n.map(e=>e.kind===`too-large`?{byteLength:e.byteLength,filename:e.filename,kind:e.kind,limit:e.limit,mediaType:e.mediaType}:{allowedMediaTypes:e.allowedMediaTypes,filename:e.filename,kind:e.kind,mediaType:e.mediaType})},{status:i})}function parseInputResponses$1(e){if(e===void 0)return;if(!Array.isArray(e)||e.length===0)return Response.json({error:`Expected 'inputResponses' to be a non-empty array.`,ok:!1},{status:400});let t=e.filter(isInputResponse);return t.length===e.length?t:Response.json({error:`Expected every 'inputResponses' entry to match the HITL response schema.`,ok:!1},{status:400})}function parseClientContextField(e){if(e!==void 0){if(typeof e==`string`)return e.length>0?e:void 0;if(Array.isArray(e))return e.length===0?void 0:e.every(e=>typeof e==`string`&&e.length>0)?e:Response.json({error:`Expected 'clientContext' array entries to be non-empty strings.`,ok:!1},{status:400});if(typeof e!=`object`||!e)return Response.json({error:`Expected 'clientContext' to be a string, string array, or JSON object.`,ok:!1},{status:400});try{return parseJsonObject(e)}catch{return Response.json({error:`Expected 'clientContext' to be a JSON-serializable object.`,ok:!1},{status:400})}}}function parseIncludeTailIndex(e){let t=new URL(e.url).searchParams.get(`includeTailIndex`);return t===`1`||t===`true`}function parseFollow(e){let t=new URL(e.url).searchParams.get(`follow`);return t!==`0`&&t!==`false`}function parseStartIndex(e){let t=new URL(e.url).searchParams.get(`startIndex`);if(t===null)return;let n=Number(t);return!/^-?\d+$/.test(t)||!Number.isSafeInteger(n)?Response.json({error:`Expected startIndex to be an integer.`,ok:!1},{status:400}):n}function streamEventLimit(e,t){if(t===void 0)return;let n=e===void 0?0:e<0?Math.max(0,t+1+e):e;return Math.max(0,t-n+1)}function serializeAsNdjson(e,t,n,r=!1){let i=new TextEncoder,a=0,o,s,clearTimers=()=>{clearTimeout(o),clearTimeout(s),o=void 0,s=void 0},scheduleHeartbeat=e=>{clearTimeout(o),o=setTimeout(()=>{try{e.enqueue(i.encode(`
1
+ import{isInputResponse}from"#shared/input.js";import{hasInternalRefScheme}from"#internal/attachments/url-refs.js";import{EVE_MESSAGE_STREAM_CONTENT_TYPE,EVE_MESSAGE_STREAM_FORMAT,EVE_MESSAGE_STREAM_VERSION,EVE_SESSION_ID_HEADER,EVE_STREAM_CONTROL_VERSION,EVE_STREAM_CONTROL_VERSION_QUERY,EVE_STREAM_FORMAT_HEADER,EVE_STREAM_LEASE_ENDED_CONTROL,EVE_STREAM_TAIL_INDEX_HEADER,EVE_STREAM_VERSION_HEADER}from"#protocol/message.js";import{parseJsonObject}from"#shared/json.js";import{LEGACY_REMOTE_AGENT_PROTOCOL_VERSION,splitLegacyTaskFields}from"#execution/legacy-remote-agent/protocol.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation}from"#public/channels/upload-policy.js";import{strandedSessionResponse}from"#eve-channel/support.js";import{parseToolStubs}from"#tool-stubs/rules.js";import{parseSessionCallback}from"#channel/session-callback.js";import{isExpiredWorkflowRunError,isMissingWorkflowRunError}from"#internal/workflow/is-inactive-workflow-run-error.js";import{REMOTE_AGENT_PROTOCOL_MISMATCH,REMOTE_AGENT_PROTOCOL_VERSION,readRemoteAgentProtocolVersion}from"#protocol/remote-agent-protocol.js";import{parseTurnPolicyField}from"#eve-channel/turn-policy-request.js";import{validateMessageFreeCreate}from"#eve-channel/create-request.js";async function deriveOperationContinuationToken(e){let t=JSON.stringify([`eve:create-session:v1`,e.auth.authenticator,e.auth.issuer??null,e.auth.principalType,e.auth.principalId,e.operationId]),n=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(t));return`eve:op:${Array.from(new Uint8Array(n),e=>e.toString(16).padStart(2,`0`)).join(``).slice(0,32)}`}function parseCreateBody(e){let t=splitLegacyTaskFields(e),{payload:n}=t;if(n.inputResponses!==void 0)return Response.json({error:`'inputResponses' is only accepted for an existing session.`,ok:!1},{status:400});let r=parseMessageField(n.message);if(r instanceof Response)return r;let i=parseClientContextField(n.clientContext);if(i instanceof Response)return i;let a=parseCallbackField(n.callback);if(a instanceof Response)return a;let o=a===void 0?void 0:parseProtocolVersionField(n.protocolVersion);if(o instanceof Response)return o;let s=parseCapabilitiesField(n.capabilities);if(s instanceof Response)return s;let c=parseOutputSchemaField(n.outputSchema);if(c instanceof Response)return c;let l=validateMessageFreeCreate({callback:a,hasClientContext:n.clientContext!==void 0,hasMessageField:`message`in n,message:r,outputSchema:c});if(l!==void 0)return l;let u=n.operationId;if(u!==void 0&&(typeof u!=`string`||!u))return Response.json({error:`Expected 'operationId' to be a non-empty string.`,ok:!1},{status:400});let d={callback:a,capabilities:s,context:i,outputSchema:c};if(n.stubs!==void 0)try{d.stubs=parseToolStubs(n.stubs)}catch(e){return Response.json({ok:!1,error:e instanceof Error?e.message:`Invalid tool stubs.`},{status:400})}return r!==void 0&&(d.message=r),typeof u==`string`&&(d.operationId=u),o!==void 0&&(d.protocolVersion=o),o===LEGACY_REMOTE_AGENT_PROTOCOL_VERSION&&(d.legacyRemoteAgentCaller=t.taskId===void 0?{}:{taskId:t.taskId}),d}function parseSessionMessageBody(e){let{payload:t}=splitLegacyTaskFields(e);if(Object.hasOwn(t,`stubs`))return Response.json({ok:!1,error:`Tool stubs are fixed at session creation.`},{status:400});let n=rejectSessionContinuationToken(t);if(n!==null)return n;let r=parseMessageField(t.message);if(r instanceof Response)return r;let i=parseCallbackField(t.callback);if(i instanceof Response)return i;let a=parseInputResponses$1(t.inputResponses);if(a instanceof Response)return a;let o=parseClientContextField(t.clientContext);if(o instanceof Response)return o;let s=parseOutputSchemaField(t.outputSchema);if(s instanceof Response)return s;let c=parseTurnPolicyField(t.turnPolicy);return c instanceof Response?c:r===void 0&&a===void 0?Response.json({error:`Expected a non-empty 'message' or a non-empty 'inputResponses' array.`,ok:!1},{status:400}):r!==void 0&&a!==void 0?Response.json({error:`'message' and 'inputResponses' are mutually exclusive.`,ok:!1},{status:400}):{callback:i,message:r,inputResponses:a,context:o,outputSchema:s,turnPolicy:c}}async function parseCancelTurnBody(e){let t=await parseOptionalJsonRequest(e);if(t instanceof Response)return t;let n=rejectSessionContinuationToken(t);if(n!==null)return n;let r=t.turnId;return r!==void 0&&(typeof r!=`string`||r.length===0)?Response.json({error:`Expected 'turnId' to be a non-empty string.`,ok:!1},{status:400}):typeof r==`string`?{turnId:r}:{}}async function parseResetBody(e){let t=await parseOptionalJsonRequest(e);if(t instanceof Response)return t;let n=rejectSessionContinuationToken(t);if(n!==null)return n;let r=t.reason;return r!==void 0&&(typeof r!=`string`||r.length===0)?Response.json({error:`Expected 'reason' to be a non-empty string.`,ok:!1},{status:400}):r===void 0?{}:{reason:r}}async function parseSessionControlBody(e){let t=await parseOptionalJsonRequest(e);return t instanceof Response?t:rejectSessionContinuationToken(t)??t}async function parseOptionalJsonRequest(e){let t;try{t=await e.text()}catch{return Response.json({error:`Unreadable request body.`,ok:!1},{status:400})}if(t.trim().length===0)return{};let n;try{n=JSON.parse(t)}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}return typeof n!=`object`||!n||Array.isArray(n)?Response.json({error:`Expected a JSON object.`,ok:!1},{status:400}):n}function rejectSessionContinuationToken(e){return`continuationToken`in e?Response.json({error:`Session-ID routes do not accept 'continuationToken'.`,ok:!1},{status:400}):null}function requireSessionId(e){return e.sessionId||Response.json({error:`Missing session id.`,ok:!1},{status:400})}async function createSessionStreamResponse(e,t){let n=parseStartIndex(e);if(n instanceof Response)return n;let r=parseFollow(e),i=!r||parseIncludeTailIndex(e);try{let a=t.getEventStream({follow:r,startIndex:n});a.catch(()=>{});let o;if(i)try{o=await t.getStreamTailIndex()}catch(e){throw a.then(e=>e.cancel()).catch(()=>{}),e}let s=await a,c=new URL(e.url).searchParams.get(EVE_STREAM_CONTROL_VERSION_QUERY)===EVE_STREAM_CONTROL_VERSION?EVE_STREAM_CONTROL_VERSION:void 0,l=new Headers({"cache-control":`no-store, no-transform`,"content-type":EVE_MESSAGE_STREAM_CONTENT_TYPE,"x-accel-buffering":`no`,[EVE_SESSION_ID_HEADER]:t.id,[EVE_STREAM_FORMAT_HEADER]:EVE_MESSAGE_STREAM_FORMAT,[EVE_STREAM_VERSION_HEADER]:EVE_MESSAGE_STREAM_VERSION});return o!==void 0&&l.set(EVE_STREAM_TAIL_INDEX_HEADER,String(o)),new Response(serializeAsNdjson(s,e.signal,o===void 0?void 0:streamEventLimit(n,o),c!==void 0),{headers:l})}catch(e){let t=strandedSessionResponse(e);if(t!==void 0)return t;if(isExpiredWorkflowRunError(e))return Response.json({code:`session_expired`,error:`Session history is no longer available.`,ok:!1},{headers:{"cache-control":`no-store`},status:410});let n=isMissingWorkflowRunError(e);return Response.json({error:n?`Session not found.`:`Session stream unavailable.`,ok:!1},{status:n?404:503})}}function parseOutputSchemaField(e){if(e!==void 0)try{return parseJsonObject(e)}catch{return Response.json({error:`Expected 'outputSchema' to be a JSON-serializable object.`,ok:!1},{status:400})}}function parseCallbackField(e){if(e===void 0)return;let t=parseSessionCallback(e);return t.ok?t.callback:Response.json({error:t.message,ok:!1},{status:400})}function parseProtocolVersionField(e){if(e!==void 0&&typeof e!=`number`)return Response.json({error:`Expected 'protocolVersion' to be a number.`,ok:!1},{status:400});let t=readRemoteAgentProtocolVersion(e);return t===REMOTE_AGENT_PROTOCOL_VERSION||t===LEGACY_REMOTE_AGENT_PROTOCOL_VERSION?t:Response.json({code:REMOTE_AGENT_PROTOCOL_MISMATCH,error:`This deployment speaks eve remote agent protocol ${String(REMOTE_AGENT_PROTOCOL_VERSION)}, but the caller speaks protocol ${String(t)}. Upgrade both deployments to the same eve release.`,ok:!1,protocolVersion:REMOTE_AGENT_PROTOCOL_VERSION},{status:409})}function parseCapabilitiesField(e){if(e===void 0)return;if(typeof e!=`object`||!e||Array.isArray(e))return Response.json({error:`Expected 'capabilities' to be an object.`,ok:!1},{status:400});let t=Object.keys(e),n=Reflect.get(e,`requestInput`);return t.some(e=>e!==`requestInput`)||n!==void 0&&typeof n!=`boolean`?Response.json({error:`Expected 'capabilities.requestInput' to be a boolean when provided.`,ok:!1},{status:400}):n===void 0?{}:{requestInput:n}}function parseMessageField(e){if(e===void 0)return;if(typeof e==`string`)return e.length>0?e:void 0;if(!Array.isArray(e))return Response.json({error:`Expected 'message' to be a string or an array of text/file parts.`,ok:!1},{status:400});if(e.length===0)return;let t=[];for(let n of e){let e=parseMessagePart(n);if(e instanceof Response)return e;t.push(e)}return t}function parseMessagePart(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected each message part to be an object.`,ok:!1},{status:400});let t=e;if(t.type===`text`)return typeof t.text!=`string`||t.text.length===0?Response.json({error:`Text parts require a non-empty 'text' string.`,ok:!1},{status:400}):{type:`text`,text:t.text};if(t.type===`file`){if(typeof t.mediaType!=`string`||t.mediaType.length===0)return Response.json({error:`File parts require a non-empty 'mediaType' string.`,ok:!1},{status:400});if(typeof t.data!=`string`)return Response.json({error:`File parts require a 'data' string (base64, data URL, or URL).`,ok:!1},{status:400});if(hasInternalRefScheme(t.data))return Response.json({error:`File part 'data' must not use a framework-internal ref scheme.`,ok:!1},{status:400});let e={type:`file`,mediaType:t.mediaType,data:t.data};return typeof t.filename==`string`&&t.filename.length>0&&(e.filename=t.filename),e}return Response.json({error:`Unsupported message part type "${String(t.type)}". Use 'text' or 'file'.`,ok:!1},{status:400})}function checkUploadPolicy(e,t){if(!e.message)return null;let n=collectUploadPolicyViolations(e.message,t);if(n.length===0)return null;let[r]=n;if(!r)return null;let i=r.kind===`too-large`?413:415;return Response.json({error:formatUploadPolicyViolation(r),ok:!1,violations:n.map(e=>e.kind===`too-large`?{byteLength:e.byteLength,filename:e.filename,kind:e.kind,limit:e.limit,mediaType:e.mediaType}:{allowedMediaTypes:e.allowedMediaTypes,filename:e.filename,kind:e.kind,mediaType:e.mediaType})},{status:i})}function parseInputResponses$1(e){if(e===void 0)return;if(!Array.isArray(e)||e.length===0)return Response.json({error:`Expected 'inputResponses' to be a non-empty array.`,ok:!1},{status:400});let t=e.filter(isInputResponse);return t.length===e.length?t:Response.json({error:`Expected every 'inputResponses' entry to match the HITL response schema.`,ok:!1},{status:400})}function parseClientContextField(e){if(e!==void 0){if(typeof e==`string`)return e.length>0?e:void 0;if(Array.isArray(e))return e.length===0?void 0:e.every(e=>typeof e==`string`&&e.length>0)?e:Response.json({error:`Expected 'clientContext' array entries to be non-empty strings.`,ok:!1},{status:400});if(typeof e!=`object`||!e)return Response.json({error:`Expected 'clientContext' to be a string, string array, or JSON object.`,ok:!1},{status:400});try{return parseJsonObject(e)}catch{return Response.json({error:`Expected 'clientContext' to be a JSON-serializable object.`,ok:!1},{status:400})}}}function parseIncludeTailIndex(e){let t=new URL(e.url).searchParams.get(`includeTailIndex`);return t===`1`||t===`true`}function parseFollow(e){let t=new URL(e.url).searchParams.get(`follow`);return t!==`0`&&t!==`false`}function parseStartIndex(e){let t=new URL(e.url).searchParams.get(`startIndex`);if(t===null)return;let n=Number(t);return!/^-?\d+$/.test(t)||!Number.isSafeInteger(n)?Response.json({error:`Expected startIndex to be an integer.`,ok:!1},{status:400}):n}function streamEventLimit(e,t){if(t===void 0)return;let n=e===void 0?0:e<0?Math.max(0,t+1+e):e;return Math.max(0,t-n+1)}function serializeAsNdjson(e,t,n,r=!1){let i=new TextEncoder,a=0,o,s,clearTimers=()=>{clearTimeout(o),clearTimeout(s),o=void 0,s=void 0},scheduleHeartbeat=e=>{clearTimeout(o),o=setTimeout(()=>{try{e.enqueue(i.encode(`
2
2
  `)),scheduleHeartbeat(e)}catch{clearTimers()}},1e4)},startLease=e=>{scheduleHeartbeat(e),s=setTimeout(()=>{clearTimers();try{e.enqueue(i.encode(`${JSON.stringify(EVE_STREAM_LEASE_ENDED_CONTROL)}\n`)),e.terminate()}catch{}},6e4)},c=new TransformStream({start(e){e.enqueue(i.encode(`
3
3
  `)),n===0?e.terminate():r&&startLease(e)},transform(e,t){t.enqueue(i.encode(`${JSON.stringify(e)}\n`)),a+=1,a===n?(clearTimers(),t.terminate()):r&&scheduleHeartbeat(t)},flush(){clearTimers()}});return e.pipeTo(c.writable,{signal:t}).catch(()=>{}).finally(clearTimers),c.readable}export{checkUploadPolicy,createSessionStreamResponse,deriveOperationContinuationToken,parseCancelTurnBody,parseCreateBody,parseIncludeTailIndex,parseOptionalJsonRequest,parseResetBody,parseSessionControlBody,parseSessionMessageBody,parseStartIndex,rejectSessionContinuationToken,requireSessionId};
@@ -1 +1 @@
1
- import{completeConnectionSignIn,listConnectionTools,listToolMetadata,listingFailureMessage}from"./connection-auth.js";import{closestNames}from"./rank.js";import{connectionToolSignature}from"./signatures.js";import{isObject}from"#shared/guards.js";import{loadContext}from"#context/container.js";import{displayProperName,displayTitle}from"#shared/display-name.js";import{SEARCH_TOOL_NAME}from"#protocol/catalog-tools.js";import{defineJsonSchema,refineJsonSchema}from"#tools/schema.js";import{connectionToolName}from"#connections/ownership.js";import{ContextKey}from"#context/key.js";import{resolveApprovalPolicy}from"#approval/definition.js";import{isApprovalRecheck,markApprovalRecheck}from"#harness/approval-recheck.js";import{isConnectionAuthorizationRequiredError}from"#connections/errors.js";import{connectionToolModelOutput,toConnectionToolResult}from"#runtime/connections/tool-result.js";const CONNECTION_CHANGED_MESSAGE=`The connection for this tool call changed or is unavailable. Request a new tool call and approval.`,ConnectionApprovalPinsKey=new ContextKey(`eve.connectionApprovalPins`);function instanceKey(e){return e.instanceId??``}function connectionEntry(e,t,n){let r=`${displayProperName(t.connectionName)}: ${displayTitle(n)}`;return{approval:connectionApproval(e,t,n),deferred:!0,description:``,execute:(r,i)=>callConnectionTool(e,t,n,r,i),inputSchema:refineJsonSchema({},r=>checkInput(e,t,n,r)),label:{start:()=>r},name:connectionToolName(t.connectionName,n),toModelOutput:connectionToolModelOutput}}function connectionSignInEntry(e,t){let n=displayProperName(t.connectionName),r=`Sign in to use the ${n} tools`;return{deferred:!0,description:t.description===``?`${r}.`:`${r}: ${t.description}`,execute:()=>connect(e,t),inputSchema:defineJsonSchema({type:`object`,properties:{},additionalProperties:!1}),label:{start:()=>`Sign in to ${n}`},name:t.connectionName}}async function connect(e,t){let n=await completeConnectionSignIn(e,t),r=await listConnectionTools(t,n);if(`failure`in r)throw Error(r.failure);if(`authorization`in r)return await n.auth.handleError(r.error,r.authorization);let i=displayProperName(t.connectionName),a=`${SEARCH_TOOL_NAME}({ query: "${t.connectionName}__" })`;return n.scoped!==void 0&&n.auth.isJustAuthorized(n.scoped)?`Signed in to ${i}. Find the ${i} tools with ${a}.`:`The ${i} tools are available. Find them with ${a}.`}async function callConnectionTool(e,t,n,r,i){releaseApprovalPin(i.toolCallId,t);let a=await completeConnectionSignIn(e,t),{auth:o,client:s,scoped:c}=a,l=await listConnectionTools(t,a);if(`failure`in l)throw Error(l.failure);if(`authorization`in l)return await o.handleError(l.error,l.authorization);let u=s.eventActions?.ownsName(n)===!0,d=await checkCall(t,l.tools,n,r,!u);if(`issues`in d)throw Error(issuesMessage(d.issues));let{input:f,tool:p}=d,m;try{if(u)return await s.eventActions.execute(p.name,f,{abortSignal:i.abortSignal,callId:i.toolCallId});m=await s.executeTool(p.name,f,{abortSignal:i.abortSignal,callId:i.toolCallId})}catch(e){if(isConnectionAuthorizationRequiredError(e))return await o.handleError(e,c);throw e}let h=toConnectionToolResult(t.protocol,p,m);if(!h.ok)throw Error(h.error);return h.value}async function checkInput(e,t,n,r){let i=e.getClient(t.connectionName),a;try{a=await listToolMetadata(t,i)}catch(e){return isConnectionAuthorizationRequiredError(e)?{value:r}:{issues:[{message:listingFailureMessage(t.connectionName,e)}]}}let o=await checkCall(t,a,n,r,i.eventActions?.ownsName(n)!==!0);return`issues`in o?{issues:o.issues}:{value:o.input}}async function checkCall(e,t,n,r,i=!0){let a=t.find(e=>e.name===n);if(a===void 0)return{issues:[{message:unknownToolMessage(e,n,t)}]};let o=i?e.toolCall?.providedArguments??{}:{},s=Object.fromEntries(Object.entries(isObject(r)?r:{}).filter(([e])=>!Object.hasOwn(o,e))),c=await defineJsonSchema(a.inputSchema)[`~standard`].validate(s);return c.issues===void 0?{input:c.value,tool:a}:{issues:[...c.issues,{message:`Signature: ${connectionToolSignature(e,a)}`}]}}function issuesMessage(e){return e.map(({message:e,path:t=[]})=>{let n=t.map(e=>String(typeof e==`object`?e.key:e)).join(`.`);return n.length>0?`${n}: ${e}`:e}).join(` `)}function unknownToolMessage(e,t,n){let{connectionName:r}=e,i=closestNames(t,n).map(e=>connectionToolName(r,e));return`Connection "${r}" has no tool named "${t}".${i.length>0?` Closest tools: ${i.join(`, `)}.`:` Find its tools with ${SEARCH_TOOL_NAME}({ query: "${r}__" }).`}`}function connectionApproval(e,t,n){let{approval:r}=t;if(r===void 0)return;let i=resolveApprovalPolicy(r),request=async r=>requestApproval(t,i,withToolAnnotations(r,await toolAnnotations(e,t,n))),a=typeof r==`function`?void 0:r.response;return a===void 0?request:{request,response:e=>authorizeApprovalResponse(t,a,e)}}async function requestApproval(e,t,n){isApprovalRecheck(n)&&!matchesApprovalPin(n.callId,e)&&markApprovalPinChanged(n.callId);let r=await t(n);return!isApprovalRecheck(n)&&parksForApproval(r)&&pinApprovedInstance(n.callId,e),r}async function toolAnnotations(e,t,n){try{return(await listToolMetadata(t,e.getClient(t.connectionName))).find(e=>e.name===n)?.annotations}catch{return}}function withToolAnnotations(e,t){if(t===void 0)return e;let n={...e,toolAnnotations:t};return isApprovalRecheck(e)?markApprovalRecheck(n):n}function parksForApproval(e){return e===!0||e===`user-approval`||typeof e==`object`&&e.type===`user-approval`}async function authorizeApprovalResponse(e,t,n){return matchesApprovalPin(n.request.callId,e)?await t(n):{reason:CONNECTION_CHANGED_MESSAGE,status:`rejected`}}function pinApprovedInstance(e,t){let n=loadContext();n.get(ConnectionApprovalPinsKey)?.[e]===void 0&&n.set(ConnectionApprovalPinsKey,(n={})=>Object.fromEntries([...Object.entries(n).slice(-49),[e,instanceKey(t)]]))}function matchesApprovalPin(e,t){let n=loadContext().get(ConnectionApprovalPinsKey)?.[e];return n!==void 0&&n===instanceKey(t)}function markApprovalPinChanged(e){loadContext().set(ConnectionApprovalPinsKey,(t={})=>({...t,[e]:`\0changed`}))}function releaseApprovalPin(e,t){let n=loadContext(),r=n.get(ConnectionApprovalPinsKey);if(r?.[e]===void 0)return;let{[e]:i,...a}=r;if(n.set(ConnectionApprovalPinsKey,a),i!==instanceKey(t))throw Error(CONNECTION_CHANGED_MESSAGE)}export{connectionEntry,connectionSignInEntry};
1
+ import{completeConnectionSignIn,listConnectionTools,listToolMetadata,listingFailureMessage}from"./connection-auth.js";import{closestNames}from"./rank.js";import{connectionToolSignature}from"./signatures.js";import{isObject}from"#shared/guards.js";import{loadContext}from"#context/container.js";import{displayProperName,displayTitle}from"#shared/display-name.js";import{SEARCH_TOOL_NAME}from"#protocol/catalog-tools.js";import{defineJsonSchema,refineJsonSchema}from"#tools/schema.js";import{connectionToolName}from"#connections/ownership.js";import{ContextKey}from"#context/key.js";import{resolveApprovalPolicy}from"#approval/definition.js";import{isApprovalRecheck,markApprovalRecheck}from"#harness/approval-recheck.js";import{isConnectionAuthorizationRequiredError}from"#connections/errors.js";import{connectionToolModelOutput,toConnectionToolResult}from"#runtime/connections/tool-result.js";const CONNECTION_CHANGED_MESSAGE=`The connection for this tool call changed or is unavailable. Request a new tool call and approval.`,ConnectionApprovalPinsKey=new ContextKey(`eve.connectionApprovalPins`);function instanceKey(e){return e.instanceId??``}function connectionEntry(e,t,n){let r=`${displayProperName(t.connectionName)}: ${displayTitle(n)}`;return{approval:connectionApproval(e,t,n),deferred:!0,description:``,execute:(r,i)=>callConnectionTool(e,t,n,r,i),inputSchema:refineJsonSchema({},r=>checkInput(e,t,n,r)),label:{start:()=>r},name:connectionToolName(t.connectionName,n),toModelOutput:connectionToolModelOutput}}function connectionSignInEntry(e,t){let n=displayProperName(t.connectionName),r=`Sign in to use the ${n} tools`;return{deferred:!0,description:t.description===``?`${r}.`:`${r}: ${t.description}`,execute:()=>connect(e,t),inputSchema:defineJsonSchema({type:`object`,properties:{},additionalProperties:!1}),label:{start:()=>`Sign in to ${n}`},name:t.connectionName}}async function connect(e,t){let n=await completeConnectionSignIn(e,t),r=await listConnectionTools(t,n);if(`failure`in r)throw Error(r.failure);if(`authorization`in r)return await n.auth.handleError(r.error,r.authorization);let i=displayProperName(t.connectionName),a=`${SEARCH_TOOL_NAME}({ query: "${t.connectionName}__" })`;return n.scoped!==void 0&&n.auth.isJustAuthorized(n.scoped)?`Signed in to ${i}. Find the ${i} tools with ${a}.`:`The ${i} tools are available. Find them with ${a}.`}async function callConnectionTool(e,t,n,r,i){releaseApprovalPin(i.toolCallId,t);let a=await completeConnectionSignIn(e,t),{auth:o,client:s,scoped:c}=a,l=await listConnectionTools(t,a);if(`failure`in l)throw Error(l.failure);if(`authorization`in l)return await o.handleError(l.error,l.authorization);let u=s.eventActions?.ownsName(n)===!0,d=await checkCall(t,l.tools,n,r,!u);if(`issues`in d)throw Error(issuesMessage(d.issues));let{input:f,tool:p}=d,m;try{if(u)return await s.eventActions.execute(p.name,f,{abortSignal:i.abortSignal,callId:i.toolCallId});m=await executeWithDeadline(t.connectionName,s,p.name,f,i)}catch(e){if(isConnectionAuthorizationRequiredError(e))return await o.handleError(e,c);throw e}let h=toConnectionToolResult(t.protocol,p,m);if(!h.ok)throw Error(h.error);return h.value}const CALL_TIMEOUT_MS=3e5;async function executeWithDeadline(e,t,n,r,i){let a=i.abortSignal,o=new AbortController,s=setTimeout(()=>o.abort(),CALL_TIMEOUT_MS);try{return await t.executeTool(n,r,{abortSignal:a===void 0?o.signal:AbortSignal.any([a,o.signal]),callId:i.toolCallId})}catch(t){throw!o.signal.aborted||a?.aborted===!0?t:Error(`"${e}" did not answer ${n} within ${CALL_TIMEOUT_MS/6e4} minutes. It may still have run, so check before you retry.`,{cause:t})}finally{clearTimeout(s)}}async function checkInput(e,t,n,r){let i=e.getClient(t.connectionName),a;try{a=await listToolMetadata(t,i)}catch(e){return isConnectionAuthorizationRequiredError(e)?{value:r}:{issues:[{message:listingFailureMessage(t.connectionName,e)}]}}let o=await checkCall(t,a,n,r,i.eventActions?.ownsName(n)!==!0);return`issues`in o?{issues:o.issues}:{value:o.input}}async function checkCall(e,t,n,r,i=!0){let a=t.find(e=>e.name===n);if(a===void 0)return{issues:[{message:unknownToolMessage(e,n,t)}]};let o=i?e.toolCall?.providedArguments??{}:{},s=Object.fromEntries(Object.entries(isObject(r)?r:{}).filter(([e])=>!Object.hasOwn(o,e))),c=await defineJsonSchema(a.inputSchema)[`~standard`].validate(s);return c.issues===void 0?{input:c.value,tool:a}:{issues:[...c.issues,{message:`Signature: ${connectionToolSignature(e,a)}`}]}}function issuesMessage(e){return e.map(({message:e,path:t=[]})=>{let n=t.map(e=>String(typeof e==`object`?e.key:e)).join(`.`);return n.length>0?`${n}: ${e}`:e}).join(` `)}function unknownToolMessage(e,t,n){let{connectionName:r}=e,i=closestNames(t,n).map(e=>connectionToolName(r,e));return`Connection "${r}" has no tool named "${t}".${i.length>0?` Closest tools: ${i.join(`, `)}.`:` Find its tools with ${SEARCH_TOOL_NAME}({ query: "${r}__" }).`}`}function connectionApproval(e,t,n){let{approval:r}=t;if(r===void 0)return;let i=resolveApprovalPolicy(r),request=async r=>requestApproval(t,i,withToolAnnotations(r,await toolAnnotations(e,t,n))),a=typeof r==`function`?void 0:r.response;return a===void 0?request:{request,response:e=>authorizeApprovalResponse(t,a,e)}}async function requestApproval(e,t,n){isApprovalRecheck(n)&&!matchesApprovalPin(n.callId,e)&&markApprovalPinChanged(n.callId);let r=await t(n);return!isApprovalRecheck(n)&&parksForApproval(r)&&pinApprovedInstance(n.callId,e),r}async function toolAnnotations(e,t,n){try{return(await listToolMetadata(t,e.getClient(t.connectionName))).find(e=>e.name===n)?.annotations}catch{return}}function withToolAnnotations(e,t){if(t===void 0)return e;let n={...e,toolAnnotations:t};return isApprovalRecheck(e)?markApprovalRecheck(n):n}function parksForApproval(e){return e===!0||e===`user-approval`||typeof e==`object`&&e.type===`user-approval`}async function authorizeApprovalResponse(e,t,n){return matchesApprovalPin(n.request.callId,e)?await t(n):{reason:CONNECTION_CHANGED_MESSAGE,status:`rejected`}}function pinApprovedInstance(e,t){let n=loadContext();n.get(ConnectionApprovalPinsKey)?.[e]===void 0&&n.set(ConnectionApprovalPinsKey,(n={})=>Object.fromEntries([...Object.entries(n).slice(-49),[e,instanceKey(t)]]))}function matchesApprovalPin(e,t){let n=loadContext().get(ConnectionApprovalPinsKey)?.[e];return n!==void 0&&n===instanceKey(t)}function markApprovalPinChanged(e){loadContext().set(ConnectionApprovalPinsKey,(t={})=>({...t,[e]:`\0changed`}))}function releaseApprovalPin(e,t){let n=loadContext(),r=n.get(ConnectionApprovalPinsKey);if(r?.[e]===void 0)return;let{[e]:i,...a}=r;if(n.set(ConnectionApprovalPinsKey,a),i!==instanceKey(t))throw Error(CONNECTION_CHANGED_MESSAGE)}export{connectionEntry,connectionSignInEntry};
@@ -11,8 +11,9 @@
11
11
  * 1. Parses the inbound request into a JSON-serializable
12
12
  * {@link AuthorizationCallback} (params only — never request headers).
13
13
  * 2. Calls `resumeHook(token, payload)` to wake the suspended workflow.
14
- * 3. Renders the standard "Authorization complete" landing page so the
15
- * user sees a friendly UI instead of an empty `202 Accepted`.
14
+ * 3. Renders a static landing page so the user sees a friendly UI
15
+ * instead of an empty `202 Accepted`: "Authorization complete", or
16
+ * "Authorization not completed" when the IdP returned an OAuth `error`.
16
17
  *
17
18
  * Owning this route in the framework - instead of routing the IdP at the
18
19
  * workflow runtime's raw `/.well-known/workflow/v1/webhook/:token` -
@@ -1 +1 @@
1
- import{resumeAuthorizationCallback}from"#execution/legacy-session/authorization.js";import{buildAuthorizationCompletePage}from"#runtime/connections/authorization-complete-page.js";async function handleConnectionCallbackRequest(e,t){let n=t.params.name,r=t.params.attemptId,i=t.params.token;if(typeof n!=`string`||n.length===0)return Response.json({error:`Missing connection name.`,ok:!1},{status:400});if(typeof i!=`string`||i.length===0)return Response.json({error:`Missing callback token.`,ok:!1},{status:400});if(typeof r!=`string`||r.length===0)return Response.json({error:`Missing authorization attempt ID.`,ok:!1},{status:400});let a=await projectAuthorizationCallback(e);try{await resumeAuthorizationCallback(i,{kind:`authorization-callback`,payloads:[{authorizationCallback:{attemptId:r,callback:a,connectionName:n}}]})}catch{return Response.json({error:`Connection callback not pending.`,ok:!1},{status:404})}return buildAuthorizationCompletePage()}async function projectAuthorizationCallback(e){let t={};for(let[n,r]of new URL(e.url).searchParams)t[n]=r;let n;if(e.method!==`GET`&&e.method!==`HEAD`){try{n=await e.text()}catch{n=void 0}let r=e.headers.get(`content-type`)??``;if(n&&r.includes(`application/x-www-form-urlencoded`))for(let[e,r]of new URLSearchParams(n))t[e]=r}return n===void 0?{params:t,method:e.method}:{params:t,method:e.method,body:n}}export{handleConnectionCallbackRequest};
1
+ import{resumeAuthorizationCallback}from"#execution/legacy-session/authorization.js";import{buildAuthorizationCompletePage}from"#runtime/connections/authorization-complete-page.js";async function handleConnectionCallbackRequest(e,t){let n=t.params.name,r=t.params.attemptId,i=t.params.token;if(typeof n!=`string`||n.length===0)return Response.json({error:`Missing connection name.`,ok:!1},{status:400});if(typeof i!=`string`||i.length===0)return Response.json({error:`Missing callback token.`,ok:!1},{status:400});if(typeof r!=`string`||r.length===0)return Response.json({error:`Missing authorization attempt ID.`,ok:!1},{status:400});let a=await projectAuthorizationCallback(e);try{await resumeAuthorizationCallback(i,{kind:`authorization-callback`,payloads:[{authorizationCallback:{attemptId:r,callback:a,connectionName:n}}]})}catch{return Response.json({error:`Connection callback not pending.`,ok:!1},{status:404})}return buildAuthorizationCompletePage(a.params.error===void 0?`authorized`:`failed`)}async function projectAuthorizationCallback(e){let t={};for(let[n,r]of new URL(e.url).searchParams)t[n]=r;let n;if(e.method!==`GET`&&e.method!==`HEAD`){try{n=await e.text()}catch{n=void 0}let r=e.headers.get(`content-type`)??``;if(n&&r.includes(`application/x-www-form-urlencoded`))for(let[e,r]of new URLSearchParams(n))t[e]=r}return n===void 0?{params:t,method:e.method}:{params:t,method:e.method,body:n}}export{handleConnectionCallbackRequest};
@@ -1 +1 @@
1
- import{runJsProgram}from"#execution/dynamic-workflow/workflow.js";async function runWorkflowProgramTask(e,t){"use workflow";return runJsProgram(e.js,t,{maxSubagents:e.maxSubagents??0})}runWorkflowProgramTask.workflowId=`workflow//eve@0.83.0//runWorkflowProgramTask`;export{runWorkflowProgramTask};
1
+ import{runJsProgram}from"#execution/dynamic-workflow/workflow.js";async function runWorkflowProgramTask(e,t){"use workflow";return runJsProgram(e.js,t,{maxSubagents:e.maxSubagents??0})}runWorkflowProgramTask.workflowId=`workflow//eve@0.83.2//runWorkflowProgramTask`;export{runWorkflowProgramTask};
@@ -44,6 +44,7 @@ interface CreateExecutionNodeStepInput {
44
44
  readonly turnId: string;
45
45
  }) => Promise<void>;
46
46
  readonly signInCompletions?: ToolLoopHarnessConfig["signInCompletions"];
47
+ readonly typedAnswers?: ToolLoopHarnessConfig["typedAnswers"];
47
48
  readonly historyProjector?: HistoryViewProjector;
48
49
  readonly historyView?: PreparedHistoryView;
49
50
  readonly instrumentation: ExecutionInstrumentation | undefined;
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{UNSPECIFIED_INPUT_SCHEMA}from"#tools/schema.js";import{createToolExecuteWithAuth}from"#execution/tool-auth.js";import{resolveRuntimeModelReference}from"#runtime/agent/resolve-model.js";import{createPreparedWorkflowToolHarnessDefinition,createWorkflowToolHarnessDefinition}from"#execution/tools/workflow/harness-definition.js";import{isFrameworkTool}from"#tools/provided/framework-tool.js";import{workflowIdForHandling}from"#runtime/subagents/workflow-reference.js";import{dispatchDynamicModelEvent}from"#context/dynamic-model-lifecycle.js";import{preparePersistedStepDynamicToolMetadata}from"#context/dynamic-tool-lifecycle.js";import{createToolLoopHarness}from"#harness/tool-loop.js";import{findRegisteredRuntimeTool}from"#runtime/tools/registry.js";import{WEB_SEARCH_TOOL_NAME,resolveWebSearchActivityLabel}from"#harness/provider-tool-schemas.js";const log=createLogger(`execution.node-step`);function createExecutionNodeStep(e){let t=createRuntimeModelResolver(e.modelResolutionScope),n=e.node.turnAgent.dynamicModel===void 0?void 0:createRuntimeDynamicModelEventDispatcher(e.modelResolutionScope,e.node.turnAgent.dynamicModel,e.abortSignal),r=createNodeHarnessTools({node:e.node}),i=e.instrumentation,a=i?.prepareExecution(),o=createToolLoopHarness({steeringSignal:e.steeringSignal,abortSignal:e.abortSignal,capabilities:e.capabilities,clearOnly:e.clearOnly,compactOnly:e.compactOnly,handleEvent:e.handleEvent,historyProjector:e.historyProjector,historyView:e.historyView,instrumentation:a,prepareApprovalTurn:e.prepareApprovalTurn,signInCompletions:e.signInCompletions,resolveStepDynamicTools:t=>preparePersistedStepDynamicToolMetadata({...t,resolvers:e.node.agent.dynamicToolResolvers??[]}),dispatchDynamicModelEvent:n,resolveModel:t,runtimeIdentity:buildRuntimeIdentity(e.node),sessionUsageLimit:e.sessionUsageLimit,tools:r,titleAttributeWrite:e.titleAttributeWrite});return i===void 0?o:async(e,t)=>{try{return await o(e,t)}finally{await i.flush()}}}function buildRuntimeIdentity(e){let t=resolveInstalledPackageInfo(),n={agentId:e.turnAgent.id,agentName:e.agent.config?.name,eveVersion:t.version},r=process.env.VERCEL_GIT_COMMIT_SHA?.trim(),i=process.env.VERCEL_GIT_COMMIT_REF?.trim(),a=process.env.VERCEL_DEPLOYMENT_CREATED_AT?.trim();return r||i||a?{...n,build:{deployedAt:a||void 0,gitBranch:i||void 0,gitSha:r||void 0}}:n}function createRuntimeModelResolver(e){return t=>resolveRuntimeModelReference(t,e)}function createRuntimeDynamicModelEventDispatcher(e,t,n){return r=>dispatchDynamicModelEvent({abortSignal:n,ctx:r.ctx,dynamicModel:t,event:r.event,messages:r.messages,scope:e})}function createNodeHarnessTools(e){let t=new Map;for(let n of e.node.turnAgent.tools){let r=resolveHarnessToolDefinition({node:e.node,tool:n});r!==null&&t.set(n.name,r)}return t}function resolveHarnessToolDefinition(e){let t=findRegisteredRuntimeTool(e.node.toolRegistry,e.tool.name),n=workflowIdForHandling(e.tool.behavior?.handling);return n===void 0?t===null?(log.warn(`declared tool is not registered — omitting from toolset`,{toolName:e.tool.name,nodeId:e.node.nodeId}),null):createRegisteredHarnessToolDefinition({behavior:e.tool.behavior,definition:t.definition,rootOnly:e.tool.rootOnly}):t===null?createPreparedWorkflowToolHarnessDefinition(e.tool):createWorkflowToolHarnessDefinition({executeInput:t.definition.executeInput,definition:createRegisteredHarnessToolDefinition({behavior:e.tool.behavior,definition:t.definition,rootOnly:e.tool.rootOnly}),workflowId:n})}function createRegisteredHarnessToolDefinition(e){let t=e.definition,n=t.execute;return{availableInSubagents:t.availableInSubagents,label:t.label??(t.owner.kind===`framework`&&t.name===WEB_SEARCH_TOOL_NAME?{start:resolveWebSearchActivityLabel}:void 0),approvalKey:t.approvalKey,behavior:e.behavior,deferred:t.deferred,description:t.description,endsTurn:t.endsTurn,executeInput:t.executeInput,execute:resolveAuthoredExecute({rawExecute:n,scope:t.name}),frameworkTool:isFrameworkTool(t)||t.owner.kind===`framework`,inputSchema:t.inputSchema??UNSPECIFIED_INPUT_SCHEMA,name:t.name,approval:t.approval,outputSchema:t.outputSchema,rootOnly:e.rootOnly,toModelOutput:t.toModelOutput}}function resolveAuthoredExecute(e){let{rawExecute:t,scope:n}=e;return t===void 0?void 0:createToolExecuteWithAuth({execute:t,scope:n})}export{buildRuntimeIdentity,createExecutionNodeStep,createNodeHarnessTools};
1
+ import{createLogger}from"#internal/logging.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{UNSPECIFIED_INPUT_SCHEMA}from"#tools/schema.js";import{createToolExecuteWithAuth}from"#execution/tool-auth.js";import{resolveRuntimeModelReference}from"#runtime/agent/resolve-model.js";import{createPreparedWorkflowToolHarnessDefinition,createWorkflowToolHarnessDefinition}from"#execution/tools/workflow/harness-definition.js";import{isFrameworkTool}from"#tools/provided/framework-tool.js";import{workflowIdForHandling}from"#runtime/subagents/workflow-reference.js";import{dispatchDynamicModelEvent}from"#context/dynamic-model-lifecycle.js";import{preparePersistedStepDynamicToolMetadata}from"#context/dynamic-tool-lifecycle.js";import{createToolLoopHarness}from"#harness/tool-loop.js";import{findRegisteredRuntimeTool}from"#runtime/tools/registry.js";import{WEB_SEARCH_TOOL_NAME,resolveWebSearchActivityLabel}from"#harness/provider-tool-schemas.js";const log=createLogger(`execution.node-step`);function createExecutionNodeStep(e){let t=createRuntimeModelResolver(e.modelResolutionScope),n=e.node.turnAgent.dynamicModel===void 0?void 0:createRuntimeDynamicModelEventDispatcher(e.modelResolutionScope,e.node.turnAgent.dynamicModel,e.abortSignal),r=createNodeHarnessTools({node:e.node}),i=e.instrumentation,a=i?.prepareExecution(),o=createToolLoopHarness({steeringSignal:e.steeringSignal,abortSignal:e.abortSignal,capabilities:e.capabilities,clearOnly:e.clearOnly,compactOnly:e.compactOnly,handleEvent:e.handleEvent,historyProjector:e.historyProjector,historyView:e.historyView,instrumentation:a,prepareApprovalTurn:e.prepareApprovalTurn,signInCompletions:e.signInCompletions,typedAnswers:e.typedAnswers,resolveStepDynamicTools:t=>preparePersistedStepDynamicToolMetadata({...t,resolvers:e.node.agent.dynamicToolResolvers??[]}),dispatchDynamicModelEvent:n,resolveModel:t,runtimeIdentity:buildRuntimeIdentity(e.node),sessionUsageLimit:e.sessionUsageLimit,tools:r,titleAttributeWrite:e.titleAttributeWrite});return i===void 0?o:async(e,t)=>{try{return await o(e,t)}finally{await i.flush()}}}function buildRuntimeIdentity(e){let t=resolveInstalledPackageInfo(),n={agentId:e.turnAgent.id,agentName:e.agent.config?.name,eveVersion:t.version},r=process.env.VERCEL_GIT_COMMIT_SHA?.trim(),i=process.env.VERCEL_GIT_COMMIT_REF?.trim(),a=process.env.VERCEL_DEPLOYMENT_CREATED_AT?.trim();return r||i||a?{...n,build:{deployedAt:a||void 0,gitBranch:i||void 0,gitSha:r||void 0}}:n}function createRuntimeModelResolver(e){return t=>resolveRuntimeModelReference(t,e)}function createRuntimeDynamicModelEventDispatcher(e,t,n){return r=>dispatchDynamicModelEvent({abortSignal:n,ctx:r.ctx,dynamicModel:t,event:r.event,messages:r.messages,scope:e})}function createNodeHarnessTools(e){let t=new Map;for(let n of e.node.turnAgent.tools){let r=resolveHarnessToolDefinition({node:e.node,tool:n});r!==null&&t.set(n.name,r)}return t}function resolveHarnessToolDefinition(e){let t=findRegisteredRuntimeTool(e.node.toolRegistry,e.tool.name),n=workflowIdForHandling(e.tool.behavior?.handling);return n===void 0?t===null?(log.warn(`declared tool is not registered — omitting from toolset`,{toolName:e.tool.name,nodeId:e.node.nodeId}),null):createRegisteredHarnessToolDefinition({behavior:e.tool.behavior,definition:t.definition,rootOnly:e.tool.rootOnly}):t===null?createPreparedWorkflowToolHarnessDefinition(e.tool):createWorkflowToolHarnessDefinition({executeInput:t.definition.executeInput,definition:createRegisteredHarnessToolDefinition({behavior:e.tool.behavior,definition:t.definition,rootOnly:e.tool.rootOnly}),workflowId:n})}function createRegisteredHarnessToolDefinition(e){let t=e.definition,n=t.execute;return{availableInSubagents:t.availableInSubagents,label:t.label??(t.owner.kind===`framework`&&t.name===WEB_SEARCH_TOOL_NAME?{start:resolveWebSearchActivityLabel}:void 0),approvalKey:t.approvalKey,behavior:e.behavior,deferred:t.deferred,description:t.description,endsTurn:t.endsTurn,executeInput:t.executeInput,execute:resolveAuthoredExecute({rawExecute:n,scope:t.name}),frameworkTool:isFrameworkTool(t)||t.owner.kind===`framework`,inputSchema:t.inputSchema??UNSPECIFIED_INPUT_SCHEMA,name:t.name,approval:t.approval,outputSchema:t.outputSchema,rootOnly:e.rootOnly,toModelOutput:t.toModelOutput}}function resolveAuthoredExecute(e){let{rawExecute:t,scope:n}=e;return t===void 0?void 0:createToolExecuteWithAuth({execute:t,scope:n})}export{buildRuntimeIdentity,createExecutionNodeStep,createNodeHarnessTools};
@@ -1 +1 @@
1
- import{randomBytes}from"node:crypto";import{isObject}from"#shared/guards.js";import{SANDBOX_AGENT_ENV,SandboxSessionGoneError,SandboxTemplateNotProvisionedError}from"#public/sandbox/provider.js";import{VERCEL_EVE_SANDBOX_IMAGE}from"#execution/sandbox/bindings/eve-image.js";import{createSandboxProviderIdentity}from"#execution/sandbox/provider-identity.js";import{invalidPreparedSandboxArtifactError,invalidSandboxSessionStateError}from"#shared/sandbox-recorded-data-error.js";import{adaptMultiplexedCommandToSandboxProcess}from"#execution/sandbox/multiplexed-command.js";import{isVercelSandboxMissingError,isVercelSandboxNameConflictError,isVercelSnapshotNotFoundError,isVercelSnapshotUnavailableError}from"#execution/sandbox/bindings/vercel-errors.js";import{getNamedVercelSandbox,isVercelSnapshotCreated}from"#execution/sandbox/bindings/vercel-lookup.js";import{ensureVercelSandboxTags,errorMessage,resolveVercelSandboxTags}from"#execution/sandbox/bindings/vercel-options.js";import{applyInitialVercelNetworkPolicy,createVercelNetworkPolicySetter,ensureVercelSandboxBaseRuntime,withBaseSetupNetworkPolicy}from"#execution/sandbox/bindings/vercel-base-runtime.js";import{createVercelEveImageSandbox}from"#execution/sandbox/bindings/vercel-create-sdk.js";import{deleteNamedVercelSandbox,deleteUnusableVercelSandbox,stopVercelSandbox}from"#execution/sandbox/bindings/vercel-lifecycle.js";import{normalizeVercelReadStream}from"#execution/sandbox/bindings/vercel-read-stream.js";import{withToolSessionRetention}from"#execution/sandbox/bindings/vercel-tool-sessions.js";function createVercelSandbox(e={}){let t=e.loadSandboxModule??(async()=>await import(`#compiled/@vercel/sandbox/index.js`)),n={...e.createOptions,env:{...SANDBOX_AGENT_ENV,...e.createOptions?.env},timeout:e.createOptions?.timeout??DEFAULT_SANDBOX_TIMEOUT_MS},r=e.createSandbox??createVercelEveImageSandbox,i=n.source===void 0&&(n.image??VERCEL_EVE_SANDBOX_IMAGE)===VERCEL_EVE_SANDBOX_IMAGE;return{async onSessionEnd(e,r,{abortSignal:i}){await deleteNamedVercelSandbox({createOptions:n,sandboxModule:await t(),sandboxName:r?.sandboxName??vercelSessionName(e.session.id),signal:i})},async prepare(e){if(e.isEmpty&&n.source===void 0)return{};try{let i=`eve-sbx-tpl-vercel-${e.templateKey({createOptions:vercelIdentityOptions(n),resolvedImage:n.source===void 0?n.image??VERCEL_EVE_SANDBOX_IMAGE:void 0,version:4}).slice(0,32)}`;return{snapshotId:await ensureTemplate({context:e,createOptions:n,createSandbox:r,loadSandboxModule:t,templateKey:i})}}catch(e){throw Error(`Failed to prepare Vercel sandbox snapshot: ${errorMessage(e)}`,{cause:e})}},async resume(e,r,i){requirePreparedVercelTemplate(r);let a=requireVercelSessionState(i),o=await t(),s=await getNamedVercelSandbox({createOptions:n,sandboxModule:o,sandboxName:a.sandboxName});if(s===null)throw new SandboxSessionGoneError(`Vercel sandbox session "${a.sandboxName}" no longer exists.`);return await ensureVercelSandboxBaseRuntime(s),createVercelConnection(s)},async start(e,t,n){let r=vercelSessionName(e.session.id);return{connection:createVercelConnection(await openSession(e,t,n,r)),state:{sandboxName:r,version:3}}},toolSessions:!0};async function openSession(e,a,o,s){let c=requirePreparedVercelTemplate(o),{mounts:l,...u}=a??{},d=e.kind===`tool-session`,f={...n,...u,env:{...SANDBOX_AGENT_ENV,...u.env??n.env}},p=d?withToolSessionRetention(f):f,m=resolveVercelSandboxTags(p.tags,{sessionId:e.session.id}),h=await t(),g={createOptions:p,createSandbox:r,mounts:l===void 0?void 0:toVercelMounts(l),sandboxModule:h,sessionKey:s,snapshotId:c.snapshotId,tags:m};try{let t=await ensureUsableSession({expired:d?isVercelSnapshotNotFoundError:isVercelSnapshotUnavailableError,inheritsBaseRuntime:c.snapshotId!==void 0&&l===void 0&&i,input:g,session:await ensureSession(g)}),r=u.networkPolicy??n.networkPolicy;if(t.created&&c.snapshotId===void 0&&r!==void 0)try{await applyInitialVercelNetworkPolicy(t.sandbox,r)}catch(n){try{await deleteNamedVercelSandbox({createOptions:p,sandboxModule:h,sandboxName:t.sandbox.name})}catch(t){throw AggregateError([n,t],`Failed to apply network policy and discard Vercel sandbox session "${e.session.id}".`,{cause:n})}throw n}return t.sandbox}catch(t){throw isVercelSnapshotUnavailableError(t)&&c.snapshotId!==void 0?new SandboxTemplateNotProvisionedError({providerName:`vercel`,reason:`The Vercel Sandbox snapshot expired or was deleted.`,templateKey:c.snapshotId}):Error(`Failed to open Vercel sandbox session "${e.session.id}": ${errorMessage(t)}`,{cause:t})}}}function vercelSessionName(e){return`eve-sbx-vercel-${createSandboxProviderIdentity({sessionId:e,version:2}).slice(0,32)}`}function vercelIdentityOptions(e){if(e===void 0)return;let t=new Set([`fetch`,`projectId`,`signal`,`teamId`,`token`]);return Object.fromEntries(Object.entries(e).filter(([e])=>!t.has(e)))}function requireVercelSessionState(e){if(!isObject(e)||e.version!==3||typeof e.sandboxName!=`string`)throw invalidSandboxSessionStateError(`Vercel sandbox`);return{sandboxName:e.sandboxName,version:3}}function requirePreparedVercelTemplate(e){if(!isObject(e)||e.snapshotId!==void 0&&typeof e.snapshotId!=`string`)throw invalidPreparedSandboxArtifactError(`Vercel sandbox`);return e.snapshotId===void 0?{}:{snapshotId:e.snapshotId}}function toVercelMounts(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,`mode`in t?{drive:t.drive,mode:t.mode}:{drive:t.name,mode:`read-write`}]))}async function ensureTemplate(e){let t=await e.loadSandboxModule(),n=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:t,sandboxName:e.templateKey}),r=n?.sourceSnapshotId;if(r!==void 0&&await isVercelSnapshotCreated({createOptions:e.createOptions,sandboxModule:t,snapshotId:r}))return e.context.log(`reusing prepared sandbox template`),r;let i=await prepareTemplateSnapshot(e,t);return await publishTemplatePointer(e,t,n,i).catch(t=>{e.context.log(`could not publish sandbox template: ${errorMessage(t)}`)}),i}async function prepareTemplateSnapshot(e,t){let n=await e.createSandbox({sandboxModule:t,createOptions:withBaseSetupNetworkPolicy({...e.createOptions,name:`${e.templateKey}-${randomBytes(4).toString(`hex`)}`,persistent:!1})});try{return e.context.log(`preparing base runtime inside sandbox`),await ensureVercelSandboxBaseRuntime(n),await applyInitialVercelNetworkPolicy(n,e.createOptions.networkPolicy),await e.context.populate(createVercelConnection(n)),await ensureVercelSandboxBaseRuntime(n),(await n.snapshot()).snapshotId}finally{await n.delete().catch(t=>{e.context.log(`could not delete sandbox ${n.name}: ${errorMessage(t)}`)})}}async function publishTemplatePointer(e,t,n,r){if(n!==null)try{await n.delete()}catch(e){if(!isVercelSandboxMissingError(e))throw e}let{image:i,runtime:a,source:o,...s}=e.createOptions,c;try{c=await e.createSandbox({sandboxModule:t,createOptions:{...s,name:e.templateKey,persistent:!1,source:{snapshotId:r,type:`snapshot`}}})}catch(e){if(isVercelSandboxNameConflictError(e))return;throw e}await stopVercelSandbox(c)}async function ensureUsableSession(e){let ensureBaseRuntime=async t=>{t.created&&e.inheritsBaseRuntime||await ensureVercelSandboxBaseRuntime(t.sandbox)};try{return await ensureBaseRuntime(e.session),e.session}catch(t){if(e.session.created||!e.expired(t))throw t}try{await deleteUnusableVercelSandbox({createOptions:e.input.createOptions,sandboxModule:e.input.sandboxModule,sandboxName:e.session.sandbox.name})}catch(e){if(!isVercelSandboxMissingError(e))throw e}let t=await ensureSession(e.input);return await ensureBaseRuntime(t),t}async function ensureSession(e){let t=e.sessionKey,n=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:e.sandboxModule,sandboxName:t});if(n!==null)return await ensureVercelSandboxTags(n,e.tags),{created:!1,sandbox:n};let r=createSessionCreateParams(e,t);e.tags!==void 0&&(r.tags=e.tags);try{return{created:!0,sandbox:await e.createSandbox({createOptions:r,sandboxModule:e.sandboxModule})}}catch(n){if(!isVercelSandboxNameConflictError(n))throw n;let r=await getNamedVercelSandbox({...e,sandboxName:t});if(r===null)throw n;return{created:!1,sandbox:r}}}function createSessionCreateParams(e,t){let n={...e.createOptions};if(e.mounts!==void 0&&(n.mounts=e.mounts),e.snapshotId===void 0)return withBaseSetupNetworkPolicy({...n,name:t,persistent:!0});let{image:r,runtime:i,source:a,...o}=n;return{...o,name:t,persistent:!0,source:{snapshotId:e.snapshotId,type:`snapshot`}}}function createVercelConnection(e){return{extensions:{name:e.name,setNetworkPolicy:createVercelNetworkPolicySetter(e)},async readFile(t){return normalizeVercelReadStream(await e.readFile({path:t.path}))},async removePath(t){await e.fs.rm(t.path,{force:t.force,recursive:t.recursive,signal:t.abortSignal})},async spawn(t){let n=await e.runCommand({args:[`-lc`,t.command],cmd:`bash`,cwd:t.workingDirectory,detached:!0,env:t.env,signal:t.abortSignal});return adaptMultiplexedCommandToSandboxProcess({command:n,getOutput:e=>e.stream})},async stop(){await stopVercelSandbox(e)},async writeFiles(t){t.files.length!==0&&await e.writeFiles(await resolveVercelWriteFiles(e,t.files,t.abortSignal),{signal:t.abortSignal})}}}async function resolveVercelWriteFiles(e,t,n){let r=[],i=[],a=0;for(let o of t){let t=Buffer.byteLength(o.path)+1;i.length>0&&a+t>65536&&(r.push(...await resolveVercelPaths(e,i,n)),i=[],a=0),i.push(o.path),a+=t}return r.push(...await resolveVercelPaths(e,i,n)),t.map((e,t)=>{let n=r[t];if(n===void 0||!n.startsWith(`/`))throw Error(`Failed to resolve Vercel Sandbox write path: ${e.path}`);return{content:e.content,path:n}})}async function resolveVercelPaths(e,t,n){let r=await e.runCommand({args:[`-m`,`-z`,`--`,...t],cmd:`realpath`,signal:n});if(r.exitCode!==0){let e=(await r.stderr()).trim();throw Error(`Failed to resolve Vercel Sandbox write paths with realpath: ${e}`)}let i=(await r.stdout()).split(`\0`).slice(0,-1);if(i.length!==t.length)throw Error(`Failed to resolve Vercel Sandbox write paths: realpath printed ${i.length} paths for ${t.length} files.`);return i}const DEFAULT_SANDBOX_TIMEOUT_MS=18e5;export{createVercelSandbox};
1
+ import{randomBytes}from"node:crypto";import{isObject}from"#shared/guards.js";import{SANDBOX_AGENT_ENV,SandboxSessionGoneError,SandboxTemplateNotProvisionedError}from"#public/sandbox/provider.js";import{VERCEL_EVE_SANDBOX_IMAGE}from"#execution/sandbox/bindings/eve-image.js";import{createSandboxProviderIdentity}from"#execution/sandbox/provider-identity.js";import{invalidPreparedSandboxArtifactError,invalidSandboxSessionStateError}from"#shared/sandbox-recorded-data-error.js";import{adaptMultiplexedCommandToSandboxProcess}from"#execution/sandbox/multiplexed-command.js";import{isVercelSandboxMissingError,isVercelSandboxNameConflictError,isVercelSnapshotNotFoundError,isVercelSnapshotUnavailableError}from"#execution/sandbox/bindings/vercel-errors.js";import{getNamedVercelSandbox,isVercelSnapshotCreated}from"#execution/sandbox/bindings/vercel-lookup.js";import{ensureVercelSandboxTags,errorMessage,resolveVercelSandboxTags}from"#execution/sandbox/bindings/vercel-options.js";import{applyInitialVercelNetworkPolicy,createVercelNetworkPolicySetter,ensureVercelSandboxBaseRuntime,withBaseSetupNetworkPolicy}from"#execution/sandbox/bindings/vercel-base-runtime.js";import{createVercelEveImageSandbox}from"#execution/sandbox/bindings/vercel-create-sdk.js";import{deleteNamedVercelSandbox,deleteUnusableVercelSandbox,stopVercelSandbox}from"#execution/sandbox/bindings/vercel-lifecycle.js";import{normalizeVercelReadStream}from"#execution/sandbox/bindings/vercel-read-stream.js";import{withToolSessionRetention}from"#execution/sandbox/bindings/vercel-tool-sessions.js";function createVercelSandbox(e={}){let t=e.loadSandboxModule??(async()=>await import(`#compiled/@vercel/sandbox/index.js`)),n={...e.createOptions,env:{...SANDBOX_AGENT_ENV,...e.createOptions?.env},timeout:e.createOptions?.timeout??DEFAULT_SANDBOX_TIMEOUT_MS},r=e.createSandbox??createVercelEveImageSandbox,i=n.source===void 0&&(n.image??VERCEL_EVE_SANDBOX_IMAGE)===VERCEL_EVE_SANDBOX_IMAGE;return{async onSessionEnd(e,r,{abortSignal:i}){await deleteNamedVercelSandbox({createOptions:n,sandboxModule:await t(),sandboxName:r?.sandboxName??vercelSessionName(e.session.id),signal:i})},async prepare(e){if(e.isEmpty&&n.source===void 0)return{};try{let i=`eve-sbx-tpl-vercel-${e.templateKey({createOptions:vercelIdentityOptions(n),resolvedImage:n.source===void 0?n.image??VERCEL_EVE_SANDBOX_IMAGE:void 0,version:4}).slice(0,32)}`;return{snapshotId:await ensureTemplate({context:e,createOptions:n,createSandbox:r,loadSandboxModule:t,templateKey:i})}}catch(e){throw Error(`Failed to prepare Vercel sandbox snapshot: ${errorMessage(e)}`,{cause:e})}},async resume(e,r,i){requirePreparedVercelTemplate(r);let a=requireVercelSessionState(i),o=await t(),s=await getNamedVercelSandbox({createOptions:n,sandboxModule:o,sandboxName:a.sandboxName});if(s===null)throw new SandboxSessionGoneError(`Vercel sandbox session "${a.sandboxName}" no longer exists.`);return await ensureVercelSandboxBaseRuntime(s),createVercelConnection(s)},async start(e,t,n){let r=vercelSessionName(e.session.id);return{connection:createVercelConnection(await openSession(e,t,n,r)),state:{sandboxName:r,version:3}}},toolSessions:!0};async function openSession(e,a,o,s){let c=requirePreparedVercelTemplate(o),{mounts:l,...u}=a??{},d=e.kind===`tool-session`,f={...n,...u,env:{...SANDBOX_AGENT_ENV,...u.env??n.env}},p=d?withToolSessionRetention(f):f,m=resolveVercelSandboxTags(p.tags,{sessionId:e.session.id}),h=await t(),g={createOptions:p,createSandbox:r,mounts:l===void 0?void 0:toVercelMounts(l),sandboxModule:h,sessionKey:s,snapshotId:c.snapshotId,tags:m};try{let t=await ensureUsableSession({expired:d?isVercelSnapshotNotFoundError:isVercelSnapshotUnavailableError,inheritsBaseRuntime:c.snapshotId!==void 0&&l===void 0&&i,input:g,session:await ensureSession(g)}),r=u.networkPolicy??n.networkPolicy;if(t.created&&c.snapshotId===void 0&&r!==void 0)try{await applyInitialVercelNetworkPolicy(t.sandbox,r)}catch(n){try{await deleteNamedVercelSandbox({createOptions:p,sandboxModule:h,sandboxName:t.sandbox.name})}catch(t){throw AggregateError([n,t],`Failed to apply network policy and discard Vercel sandbox session "${e.session.id}".`,{cause:n})}throw n}return t.sandbox}catch(t){throw isVercelSnapshotUnavailableError(t)&&c.snapshotId!==void 0?new SandboxTemplateNotProvisionedError({providerName:`vercel`,reason:`The Vercel Sandbox snapshot expired or was deleted.`,templateKey:c.snapshotId}):Error(`Failed to open Vercel sandbox session "${e.session.id}": ${errorMessage(t)}`,{cause:t})}}}function vercelSessionName(e){return`eve-sbx-vercel-${createSandboxProviderIdentity({sessionId:e,version:2}).slice(0,32)}`}function vercelIdentityOptions(e){if(e===void 0)return;let t=new Set([`fetch`,`projectId`,`signal`,`teamId`,`token`]);return Object.fromEntries(Object.entries(e).filter(([e])=>!t.has(e)))}function requireVercelSessionState(e){if(!isObject(e)||e.version!==3||typeof e.sandboxName!=`string`)throw invalidSandboxSessionStateError(`Vercel sandbox`);return{sandboxName:e.sandboxName,version:3}}function requirePreparedVercelTemplate(e){if(!isObject(e)||e.snapshotId!==void 0&&typeof e.snapshotId!=`string`)throw invalidPreparedSandboxArtifactError(`Vercel sandbox`);return e.snapshotId===void 0?{}:{snapshotId:e.snapshotId}}function toVercelMounts(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,`mode`in t?{drive:t.drive,mode:t.mode}:{drive:t.name,mode:`read-write`}]))}async function ensureTemplate(e){let t=await e.loadSandboxModule(),n=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:t,sandboxName:e.templateKey}),r=n?.sourceSnapshotId;if(r!==void 0&&await isVercelSnapshotCreated({createOptions:e.createOptions,sandboxModule:t,snapshotId:r}))return e.context.log(`reusing prepared sandbox template`),r;let i=await prepareTemplateSnapshot(e,t);return await publishTemplatePointer(e,t,n,i).catch(t=>{e.context.log(`could not publish sandbox template: ${errorMessage(t)}`)}),i}async function prepareTemplateSnapshot(e,t){let n=await e.createSandbox({sandboxModule:t,createOptions:withBaseSetupNetworkPolicy({...e.createOptions,name:`${e.templateKey}-${randomBytes(4).toString(`hex`)}`,persistent:!1})});try{return e.context.log(`preparing base runtime inside sandbox`),await ensureVercelSandboxBaseRuntime(n),await applyInitialVercelNetworkPolicy(n,e.createOptions.networkPolicy),await e.context.populate(createVercelConnection(n)),await ensureVercelSandboxBaseRuntime(n),(await n.snapshot()).snapshotId}finally{await n.delete().catch(t=>{e.context.log(`could not delete sandbox ${n.name}: ${errorMessage(t)}`)})}}async function publishTemplatePointer(e,t,n,r){if(n!==null)try{await n.delete()}catch(e){if(!isVercelSandboxMissingError(e))throw e}let{image:i,runtime:a,source:o,...s}=e.createOptions,c;try{c=await e.createSandbox({sandboxModule:t,createOptions:{...s,name:e.templateKey,persistent:!1,source:{snapshotId:r,type:`snapshot`}}})}catch(e){if(isVercelSandboxNameConflictError(e))return;throw e}await stopVercelSandbox(c)}async function ensureUsableSession(e){let ensureBaseRuntime=async t=>{t.created&&e.inheritsBaseRuntime||await ensureVercelSandboxBaseRuntime(t.sandbox)};try{return await ensureBaseRuntime(e.session),e.session}catch(t){if(e.session.created||!e.expired(t))throw t}try{await deleteUnusableVercelSandbox({createOptions:e.input.createOptions,sandboxModule:e.input.sandboxModule,sandboxName:e.session.sandbox.name})}catch(e){if(!isVercelSandboxMissingError(e))throw e}let t=await ensureSession(e.input);return await ensureBaseRuntime(t),t}async function ensureSession(e){let t=e.sessionKey,n=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:e.sandboxModule,sandboxName:t});if(n!==null)return await ensureVercelSandboxTags(n,e.tags),{created:!1,sandbox:n};let r=createSessionCreateParams(e,t);e.tags!==void 0&&(r.tags=e.tags);try{return{created:!0,sandbox:await e.createSandbox({createOptions:r,sandboxModule:e.sandboxModule})}}catch(n){if(!isVercelSandboxNameConflictError(n))throw n;let r=await getNamedVercelSandbox({...e,sandboxName:t});if(r===null)throw n;return{created:!1,sandbox:r}}}function createSessionCreateParams(e,t){let n={...e.createOptions};if(e.mounts!==void 0&&(n.mounts=e.mounts),e.snapshotId===void 0)return withBaseSetupNetworkPolicy({...n,name:t,persistent:!0});let{image:r,runtime:i,source:a,...o}=n;return{...o,name:t,persistent:!0,source:{snapshotId:e.snapshotId,type:`snapshot`}}}function createVercelConnection(e){return{extensions:{name:e.name,setNetworkPolicy:createVercelNetworkPolicySetter(e)},async readFile(t){return normalizeVercelReadStream(await e.readFile({path:t.path}))},async removePath(t){await e.fs.rm(t.path,{force:t.force,recursive:t.recursive,signal:t.abortSignal})},async spawn(t){let n=await e.runCommand({args:[`-lc`,t.command],cmd:`bash`,cwd:t.workingDirectory,detached:!0,env:t.env,signal:t.abortSignal});return adaptMultiplexedCommandToSandboxProcess({abortSignal:t.abortSignal,command:n,getOutput:e=>e.stream})},async stop(){await stopVercelSandbox(e)},async writeFiles(t){t.files.length!==0&&await e.writeFiles(await resolveVercelWriteFiles(e,t.files,t.abortSignal),{signal:t.abortSignal})}}}async function resolveVercelWriteFiles(e,t,n){let r=[],i=[],a=0;for(let o of t){let t=Buffer.byteLength(o.path)+1;i.length>0&&a+t>65536&&(r.push(...await resolveVercelPaths(e,i,n)),i=[],a=0),i.push(o.path),a+=t}return r.push(...await resolveVercelPaths(e,i,n)),t.map((e,t)=>{let n=r[t];if(n===void 0||!n.startsWith(`/`))throw Error(`Failed to resolve Vercel Sandbox write path: ${e.path}`);return{content:e.content,path:n}})}async function resolveVercelPaths(e,t,n){let r=await e.runCommand({args:[`-m`,`-z`,`--`,...t],cmd:`realpath`,signal:n});if(r.exitCode!==0){let e=(await r.stderr()).trim();throw Error(`Failed to resolve Vercel Sandbox write paths with realpath: ${e}`)}let i=(await r.stdout()).split(`\0`).slice(0,-1);if(i.length!==t.length)throw Error(`Failed to resolve Vercel Sandbox write paths: realpath printed ${i.length} paths for ${t.length} files.`);return i}const DEFAULT_SANDBOX_TIMEOUT_MS=18e5;export{createVercelSandbox};
@@ -35,6 +35,14 @@ export interface EnsuredSandboxAccess extends SandboxAccess {
35
35
  * leaves that connection behind.
36
36
  */
37
37
  release(): Promise<void>;
38
+ /**
39
+ * Resumes the sandbox the session recorded, in the background, so a turn
40
+ * that needs it waits only for the rest. Never starts one: does nothing
41
+ * when nothing is recorded, and leaves a gone sandbox for `get()`.
42
+ */
43
+ resumeRecorded(): void;
44
+ /** Waits for the work `prepare()` and `resumeRecorded()` queued; never throws. */
45
+ settle(): Promise<void>;
38
46
  }
39
47
  export declare function ensureSandboxAccess(input: EnsureSandboxAccessInput): Promise<EnsuredSandboxAccess>;
40
48
  export {};
@@ -1 +1 @@
1
- import{randomUUID}from"node:crypto";import{createLogger}from"#internal/logging.js";import{getRuntimeCompiledArtifactsSandboxAppRoot}from"#runtime/compiled-artifacts-source.js";import{contextStorage}from"#context/container.js";import{resolve}from"node:path";import{resolveSandboxCacheDirectory}from"#internal/application/paths.js";import{getSandboxEnvironmentRuntime,runWithSandboxConstructorRuntime}from"#shared/sandbox-environment.js";import{buildCallbackContext,withRuntimeSandboxLifecycle}from"#context/build-callback-context.js";import{isEveDevEnvironment}from"#internal/application/dev-environment.js";import{trackActiveSandboxConnection,untrackActiveSandboxConnection}from"#execution/sandbox/active-connections.js";import{isToolSessionId}from"#execution/tool-session/id.js";import{ToolSessionSandboxUnsupportedError}from"#shared/sandbox-tool-session-error.js";import{loadSandboxPreparedArtifact}from"#runtime/sandbox/prepared-artifacts.js";import{createConnectionSession}from"#execution/sandbox/session.js";import{ensureDevelopmentSandboxesPrepared}from"#execution/sandbox/development-lazy-prewarm.js";import{owningSandboxDefinition}from"#runtime/sandbox/registry.js";import{getSessionEndWithArtifact,resolvePersistedSandboxSessionState}from"#sandbox/state.js";import{isSandboxPreparedArtifact}from"#shared/sandbox-provider.js";import{SandboxSessionGoneError}from"#shared/sandbox-session-gone-error.js";import{SandboxTemplateNotProvisionedError}from"#shared/sandbox-template-error.js";const pendingSandboxStarts=new Map,log=createLogger(`execution.sandbox`);async function ensureSandboxAccess(e){let t=e.registry.sandbox,n=t===null?void 0:owningSandboxDefinition(t),r=resolvePersistedSandboxSessionState(e.state?.session,n?.kind===`independent`?getSandboxEnvironmentRuntime(n.environment):void 0),i,a,o,s,c=e.shutdownTracking??`session`,l=getRuntimeCompiledArtifactsSandboxAppRoot(e.compiledArtifactsSource)??process.cwd(),captured=()=>({session:r});if(t===null)return{async captureState(){return captured()},async end(){},async get(){return null},async release(){},async stop(){}};let u=owningSandboxDefinition(t),d=t.inheritance?.nodeId??e.nodeId;function providerContext(t){let n=contextStorage.getStore()===void 0?{auth:{current:null,initiator:null},id:e.sessionId,turn:{id:t,sequence:0}}:buildCallbackContext().session;return{kind:isToolSessionId(e.sessionId)?`tool-session`:`session`,resolveProjectPath:e=>resolve(l,e),session:{...n,id:e.sessionId},storagePath:resolveSandboxCacheDirectory(l)}}function activeDefinition(){if(u.kind!==`independent`)throw Error(`Sandbox "${u.logicalPath}" uses defineParentSandbox(), but this agent has no parent sandbox to share. Only a declared subagent can share its parent's sandbox. Give this agent its own sandbox with defineSandbox() and an exported environment.`);return u}async function loadArtifact(t){let n=await loadSandboxPreparedArtifact({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:d,providerName:t.providerName});if(n===void 0)throw new SandboxTemplateNotProvisionedError({nodeId:d,providerName:t.providerName});return n}async function open(e,t,n,a){if(o!==void 0)throw Error("A sandbox definition can open only one sandbox. Call `environment.open()` once in the defineSandbox() selector and return that sandbox.");let s=activeDefinition();if(n!==s.environment)throw Error(`Sandbox "${s.logicalPath}" opened an environment other than the one it exports as \`environment\`. Call \`open()\` on the exported environment. A selector cannot open an environment created inside the selector or exported by another sandbox file.`);if(e!==getSandboxEnvironmentRuntime(s.environment))throw Error(`Sandbox "${s.logicalPath}" selected a different provider.`);if(r!==null)throw Error(`Sandbox "${s.logicalPath}" already opened this session's sandbox. Call \`environment.open()\` once in the defineSandbox() selector and return that sandbox.`);let c=await loadArtifact(e);return o=(async()=>{let n=await e.implementation.start(a,t,c);if(!isSandboxPreparedArtifact(n.state))throw Error(`Sandbox provider "${e.providerName}" returned non-serializable session state.`);let i=await openSandbox(e,a,n.connection,n.state);return r={generation:randomUUID(),providerName:e.providerName,state:n.state,stateProtocolVersion:e.stateProtocolVersion},i})().catch(e=>{throw o=void 0,e}),i=await o,i.sandbox}async function resumePersisted(e){if(r===null)throw Error(`Sandbox session state is missing.`);let t=getSandboxEnvironmentRuntime(activeDefinition().environment);if(r.providerName!==t.providerName)throw new SandboxSessionGoneError(`This session's sandbox was created by provider "${r.providerName}", but the agent now selects provider "${t.providerName}". eve cannot move a sandbox between providers, so the session continues in a fresh sandbox without the old sandbox's files.`);if(r.stateProtocolVersion!==t.stateProtocolVersion)throw new SandboxSessionGoneError(`Sandbox session state protocol ${r.stateProtocolVersion} is incompatible with provider "${t.providerName}" protocol ${t.stateProtocolVersion}.`);let n=await loadArtifact(t),a=r.state;return o=t.implementation.resume(e,n,a).then(n=>openSandbox(t,e,n,a)).catch(e=>{throw o=void 0,e}),i=await o,track(i),i}async function resolveOpened(){let t=activeDefinition(),n=getSandboxEnvironmentRuntime(t.environment),i=providerContext(`sandbox-initialization`);if(i.kind===`tool-session`&&n.implementation.toolSessions!==!0)throw new ToolSessionSandboxUnsupportedError(n.providerName);if(isEveDevEnvironment()&&e.compiledArtifactsSource.kind===`disk`&&await ensureDevelopmentSandboxesPrepared({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:d,providerName:n.providerName}),r!==null)try{return await resumePersisted(i)}catch(t){if(!SandboxSessionGoneError.is(t))throw t;log.warn(`session sandbox is gone, starting a fresh one`,{error:t,providerName:r.providerName,sessionId:e.sessionId}),r=null}let a=[l,d,e.sessionId].join(`\0`),o=pendingSandboxStarts.get(a);for(;o!==void 0;){if(r=await o,r!==null)return await resumePersisted(i);o=pendingSandboxStarts.get(a)}let s=startOpened(i),c=s.then(()=>r,()=>null);pendingSandboxStarts.set(a,c);try{return await s}finally{pendingSandboxStarts.get(a)===c&&pendingSandboxStarts.delete(a)}}async function startOpened(e){let t=activeDefinition();try{let n=await runWithSandboxConstructorRuntime({open:({environment:t,options:n,provider:r})=>open(r,n,t,e)},async()=>t.selector({session:e.session}));if(i===void 0||n!==i.sandbox)throw Error(`Sandbox "${t.logicalPath}" must return the sandbox it opens.`)}catch(e){throw await i?.close().catch(()=>void 0),i=void 0,o=void 0,r=null,e}return track(i),i}function requireOpened(){return s===void 0&&(s=resolveOpened().catch(e=>{throw s=void 0,e})),s}function track(t){c!==`none`&&trackActiveSandboxConnection({connection:t,providerName:t.providerName,sessionId:e.sessionId})}function forgetOpened(){let e=i;return i=void 0,o=void 0,s=void 0,e}function forgetSandbox(t){forgetOpened(),a=void 0,untrackActiveSandboxConnection({providerName:t,sessionId:e.sessionId}),r=null}return{environment:u.kind===`independent`?u.environment:void 0,async captureState(){return o!==void 0&&await o,captured()},async delete(t){if(e.ownsSandbox===!1)throw Error(`Only the owning session can delete this sandbox.`);let n=await requireOpened();await n.delete(t),forgetSandbox(n.providerName)},async end(t){if(e.ownsSandbox===!1)return;s!==void 0&&await s.catch(()=>void 0),await i?.close().catch(t=>{log.warn(`failed to close a sandbox connection at session end`,{error:t,sessionId:e.sessionId})});let n=getSandboxEnvironmentRuntime(activeDefinition().environment),a=r?.providerName===n.providerName&&r.stateProtocolVersion===n.stateProtocolVersion?r.state:null,o=providerContext(`sandbox-cleanup`),c=getSessionEndWithArtifact(n.implementation);c===void 0?await n.implementation.onSessionEnd(o,a,{reason:t}):await c(o,a,{artifact:await loadSandboxPreparedArtifact({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:d,providerName:n.providerName}),reason:t}),forgetSandbox(n.providerName)},async get(){return(await requireOpened()).sandbox},async release(){s!==void 0&&await s.catch(()=>void 0);let t=forgetOpened();a!==void 0&&c!==`session`&&(untrackActiveSandboxConnection({connection:a,providerName:a.providerName,sessionId:e.sessionId}),a=void 0),!(t===void 0||c===`session`&&!t.closable)&&(untrackActiveSandboxConnection({connection:t,providerName:t.providerName,sessionId:e.sessionId}),await t.close())},async stop(){let t=await requireOpened();if(await t.stop(),forgetOpened(),!t.closable){a=t;return}untrackActiveSandboxConnection({connection:t,providerName:t.providerName,sessionId:e.sessionId})}};async function openSandbox(t,n,r,i){let a;try{a=createConnectionSession(r)}catch(t){throw await r.close?.().catch(t=>{log.warn(`failed to close a sandbox connection eve could not use`,{error:t,sessionId:e.sessionId})}),t}let o=shared(()=>r.stop()),s=once(async()=>await r.close?.()),c={closable:r.close!==void 0,close:s,async delete(e){try{await s()}finally{await t.implementation.onSessionEnd(n,i,{abortSignal:e?.abortSignal,reason:`deleted`})}},providerName:t.providerName,sandbox:withRuntimeSandboxLifecycle(a,e=>c.delete(e),()=>c.stop()),async stop(){try{await o()}finally{await s()}}};return c}}function shared(e){let t;return()=>t??=e().finally(()=>{t=void 0})}function once(e){let t;return()=>t??=e().catch(e=>{throw t=void 0,e})}export{ensureSandboxAccess};
1
+ import{randomUUID}from"node:crypto";import{createLogger}from"#internal/logging.js";import{getRuntimeCompiledArtifactsSandboxAppRoot}from"#runtime/compiled-artifacts-source.js";import{contextStorage}from"#context/container.js";import{resolve}from"node:path";import{resolveSandboxCacheDirectory}from"#internal/application/paths.js";import{getSandboxEnvironmentRuntime,runWithSandboxConstructorRuntime}from"#shared/sandbox-environment.js";import{buildCallbackContext,withRuntimeSandboxLifecycle}from"#context/build-callback-context.js";import{isEveDevEnvironment}from"#internal/application/dev-environment.js";import{trackActiveSandboxConnection,untrackActiveSandboxConnection}from"#execution/sandbox/active-connections.js";import{isToolSessionId}from"#execution/tool-session/id.js";import{ToolSessionSandboxUnsupportedError}from"#shared/sandbox-tool-session-error.js";import{loadSandboxPreparedArtifact}from"#runtime/sandbox/prepared-artifacts.js";import{createConnectionSession}from"#execution/sandbox/session.js";import{ensureDevelopmentSandboxesPrepared}from"#execution/sandbox/development-lazy-prewarm.js";import{owningSandboxDefinition}from"#runtime/sandbox/registry.js";import{getSessionEndWithArtifact,resolvePersistedSandboxSessionState}from"#sandbox/state.js";import{isSandboxPreparedArtifact}from"#shared/sandbox-provider.js";import{SandboxSessionGoneError}from"#shared/sandbox-session-gone-error.js";import{SandboxTemplateNotProvisionedError}from"#shared/sandbox-template-error.js";const pendingSandboxStarts=new Map,log=createLogger(`execution.sandbox`);async function ensureSandboxAccess(e){let t=e.registry.sandbox,n=t===null?void 0:owningSandboxDefinition(t),r=resolvePersistedSandboxSessionState(e.state?.session,n?.kind===`independent`?getSandboxEnvironmentRuntime(n.environment):void 0),i,a,o,s,c=e.shutdownTracking??`session`,l=getRuntimeCompiledArtifactsSandboxAppRoot(e.compiledArtifactsSource)??process.cwd(),captured=()=>({session:r});if(t===null)return{async captureState(){return captured()},async end(){},async get(){return null},async open(){return null},prepare(){},async release(){},resumeRecorded(){},async settle(){},async stop(){}};let u=owningSandboxDefinition(t),d=t.inheritance?.nodeId??e.nodeId;function providerContext(t){let n=contextStorage.getStore()===void 0?{auth:{current:null,initiator:null},id:e.sessionId,turn:{id:t,sequence:0}}:buildCallbackContext().session;return{kind:isToolSessionId(e.sessionId)?`tool-session`:`session`,resolveProjectPath:e=>resolve(l,e),session:{...n,id:e.sessionId},storagePath:resolveSandboxCacheDirectory(l)}}function activeDefinition(){if(u.kind!==`independent`)throw Error(`Sandbox "${u.logicalPath}" uses defineParentSandbox(), but this agent has no parent sandbox to share. Only a declared subagent can share its parent's sandbox. Give this agent its own sandbox with defineSandbox() and an exported environment.`);return u}async function loadArtifact(t){let n=await loadSandboxPreparedArtifact({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:d,providerName:t.providerName});if(n===void 0)throw new SandboxTemplateNotProvisionedError({nodeId:d,providerName:t.providerName});return n}async function open(e,t,n,a){if(o!==void 0)throw Error("A sandbox definition can open only one sandbox. Call `environment.open()` once in the defineSandbox() selector and return that sandbox.");let s=activeDefinition();if(n!==s.environment)throw Error(`Sandbox "${s.logicalPath}" opened an environment other than the one it exports as \`environment\`. Call \`open()\` on the exported environment. A selector cannot open an environment created inside the selector or exported by another sandbox file.`);if(e!==getSandboxEnvironmentRuntime(s.environment))throw Error(`Sandbox "${s.logicalPath}" selected a different provider.`);if(r!==null)throw Error(`Sandbox "${s.logicalPath}" already opened this session's sandbox. Call \`environment.open()\` once in the defineSandbox() selector and return that sandbox.`);let c=await loadArtifact(e);return o=(async()=>{let n=await e.implementation.start(a,t,c);if(!isSandboxPreparedArtifact(n.state))throw Error(`Sandbox provider "${e.providerName}" returned non-serializable session state.`);let i=await openSandbox(e,a,n.connection,n.state);return r={generation:randomUUID(),providerName:e.providerName,state:n.state,stateProtocolVersion:e.stateProtocolVersion},i})().catch(e=>{throw o=void 0,e}),i=await o,i.sandbox}async function resumePersisted(e){if(r===null)throw Error(`Sandbox session state is missing.`);let t=getSandboxEnvironmentRuntime(activeDefinition().environment);if(r.providerName!==t.providerName)throw new SandboxSessionGoneError(`This session's sandbox was created by provider "${r.providerName}", but the agent now selects provider "${t.providerName}". eve cannot move a sandbox between providers, so the session continues in a fresh sandbox without the old sandbox's files.`);if(r.stateProtocolVersion!==t.stateProtocolVersion)throw new SandboxSessionGoneError(`Sandbox session state protocol ${r.stateProtocolVersion} is incompatible with provider "${t.providerName}" protocol ${t.stateProtocolVersion}.`);let n=await loadArtifact(t),a=r.state;return o=t.implementation.resume(e,n,a).then(n=>openSandbox(t,e,n,a)).catch(e=>{throw o=void 0,e}),i=await o,track(i),i}async function resolveOpened(t){let n=activeDefinition(),i=getSandboxEnvironmentRuntime(n.environment),a=providerContext(`sandbox-initialization`);if(a.kind===`tool-session`&&i.implementation.toolSessions!==!0)throw new ToolSessionSandboxUnsupportedError(i.providerName);if(isEveDevEnvironment()&&e.compiledArtifactsSource.kind===`disk`&&await ensureDevelopmentSandboxesPrepared({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:d,providerName:i.providerName}),r===null&&t.resumeOnly)throw Error(`This session has not recorded a sandbox to resume.`);if(r!==null)try{return await resumePersisted(a)}catch(n){if(!SandboxSessionGoneError.is(n)||t.resumeOnly)throw n;log.warn(`session sandbox is gone, starting a fresh one`,{error:n,providerName:r.providerName,sessionId:e.sessionId}),r=null}let o=[l,d,e.sessionId].join(`\0`),s=pendingSandboxStarts.get(o);for(;s!==void 0;){if(r=await s,r!==null)return await resumePersisted(a);s=pendingSandboxStarts.get(o)}let c=startOpened(a),u=c.then(()=>r,()=>null);pendingSandboxStarts.set(o,u);try{return await c}finally{pendingSandboxStarts.get(o)===u&&pendingSandboxStarts.delete(o)}}async function startOpened(e){let t=activeDefinition();try{let n=await runWithSandboxConstructorRuntime({open:({environment:t,options:n,provider:r})=>open(r,n,t,e)},async()=>t.selector({session:e.session}));if(i===void 0||n!==i.sandbox)throw Error(`Sandbox "${t.logicalPath}" must return the sandbox it opens.`)}catch(e){throw await i?.close().catch(()=>void 0),i=void 0,o=void 0,r=null,e}return track(i),i}function requireOpened(e={resumeOnly:!1}){return s===void 0&&(s=resolveOpened(e).catch(e=>{throw s=void 0,e})),s}async function openSession(){try{return(await requireOpened()).sandbox}catch(e){if(!SandboxSessionGoneError.is(e))throw e;return(await requireOpened()).sandbox}}let f=Promise.resolve();function enqueue(t,n={retry:!0}){let report=t=>{log.warn(`background sandbox preparation failed; it runs again when it is needed`,{error:t,sessionId:e.sessionId})};f=f.then(async()=>{try{await t()}catch(e){n.retry?await t().catch(report):report(e)}})}function track(t){c!==`none`&&trackActiveSandboxConnection({connection:t,providerName:t.providerName,sessionId:e.sessionId})}function forgetOpened(){let e=i;return i=void 0,o=void 0,s=void 0,e}function forgetSandbox(t){forgetOpened(),a=void 0,untrackActiveSandboxConnection({providerName:t,sessionId:e.sessionId}),r=null}return{environment:u.kind===`independent`?u.environment:void 0,async captureState(){return o!==void 0&&await o,captured()},async delete(t){if(e.ownsSandbox===!1)throw Error(`Only the owning session can delete this sandbox.`);await f;let n=await requireOpened();await n.delete(t),forgetSandbox(n.providerName)},async end(t){if(e.ownsSandbox===!1)return;await f,s!==void 0&&await s.catch(()=>void 0),await i?.close().catch(t=>{log.warn(`failed to close a sandbox connection at session end`,{error:t,sessionId:e.sessionId})});let n=getSandboxEnvironmentRuntime(activeDefinition().environment),a=r?.providerName===n.providerName&&r.stateProtocolVersion===n.stateProtocolVersion?r.state:null,o=providerContext(`sandbox-cleanup`),c=getSessionEndWithArtifact(n.implementation);c===void 0?await n.implementation.onSessionEnd(o,a,{reason:t}):await c(o,a,{artifact:await loadSandboxPreparedArtifact({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:d,providerName:n.providerName}),reason:t}),forgetSandbox(n.providerName)},async get(){return await f,await openSession()},open:openSession,prepare(e){enqueue(e===void 0?requireOpened:()=>e(openSession))},resumeRecorded(){r!==null&&enqueue(()=>requireOpened({resumeOnly:!0}),{retry:!1})},async settle(){await f},async release(){await f,s!==void 0&&await s.catch(()=>void 0);let t=forgetOpened();a!==void 0&&c!==`session`&&(untrackActiveSandboxConnection({connection:a,providerName:a.providerName,sessionId:e.sessionId}),a=void 0),!(t===void 0||c===`session`&&!t.closable)&&(untrackActiveSandboxConnection({connection:t,providerName:t.providerName,sessionId:e.sessionId}),await t.close())},async stop(){await f;let t=await requireOpened();if(await t.stop(),forgetOpened(),!t.closable){a=t;return}untrackActiveSandboxConnection({connection:t,providerName:t.providerName,sessionId:e.sessionId})}};async function openSandbox(t,n,r,i){let a;try{a=createConnectionSession(r)}catch(t){throw await r.close?.().catch(t=>{log.warn(`failed to close a sandbox connection eve could not use`,{error:t,sessionId:e.sessionId})}),t}let o=shared(()=>r.stop()),s=once(async()=>await r.close?.()),c={closable:r.close!==void 0,close:s,async delete(e){try{await s()}finally{await t.implementation.onSessionEnd(n,i,{abortSignal:e?.abortSignal,reason:`deleted`})}},providerName:t.providerName,sandbox:withRuntimeSandboxLifecycle(a,e=>c.delete(e),()=>c.stop()),async stop(){try{await o()}finally{await s()}}};return c}}function shared(e){let t;return()=>t??=e().finally(()=>{t=void 0})}function once(e){let t;return()=>t??=e().catch(e=>{throw t=void 0,e})}export{ensureSandboxAccess};
@@ -4,18 +4,24 @@ interface MultiplexedCommand<Log extends {
4
4
  readonly data: string;
5
5
  }> {
6
6
  kill(): PromiseLike<void>;
7
- logs(): AsyncIterable<Log>;
8
- wait(): PromiseLike<{
7
+ logs(options: {
8
+ readonly signal?: AbortSignal;
9
+ }): AsyncIterable<Log>;
10
+ wait(options: {
11
+ readonly signal?: AbortSignal;
12
+ }): PromiseLike<{
9
13
  readonly exitCode: number;
10
14
  }>;
11
15
  }
12
16
  /**
13
17
  * Adapts a detached command with one tagged log iterator to a sandbox process
14
- * with independent stdout and stderr streams.
18
+ * with independent stdout and stderr streams. Aborting `abortSignal` kills the
19
+ * command and rejects `wait()` and both streams.
15
20
  */
16
21
  export declare function adaptMultiplexedCommandToSandboxProcess<Log extends {
17
22
  readonly data: string;
18
23
  }>(input: {
24
+ readonly abortSignal?: AbortSignal;
19
25
  readonly command: MultiplexedCommand<Log>;
20
26
  readonly getOutput: (log: Log) => OutputName;
21
27
  }): SandboxProcess;
@@ -1 +1 @@
1
- function createOutputChannel(){let e=!1,t;return{stream:new ReadableStream({cancel(){e=!0},start(e){t=e}}),close(){e||t.close()},enqueue(n){e||t.enqueue(n)},error(n){e||t.error(n)}}}function adaptMultiplexedCommandToSandboxProcess(e){let t=new TextEncoder,n=createOutputChannel(),r=createOutputChannel(),i={stderr:r,stdout:n},a=(async()=>{try{for await(let n of e.command.logs())i[e.getOutput(n)].enqueue(t.encode(n.data));n.close(),r.close()}catch(e){throw n.error(e),r.error(e),e}})();a.catch(()=>void 0);let o,s;return{stderr:r.stream,stdout:n.stream,wait(){return o??=Promise.resolve().then(async()=>{let t=await e.command.wait();return await a,{exitCode:t.exitCode}})},kill(){return s??=Promise.resolve().then(()=>e.command.kill())}}}export{adaptMultiplexedCommandToSandboxProcess};
1
+ function createOutputChannel(){let e=!1,t;return{stream:new ReadableStream({cancel(){e=!0},start(e){t=e}}),close(){e||t.close()},enqueue(n){e||t.enqueue(n)},error(n){e||t.error(n)}}}function adaptMultiplexedCommandToSandboxProcess(e){let{abortSignal:t,command:n}=e,r=new TextEncoder,i=createOutputChannel(),a=createOutputChannel(),o={stderr:a,stdout:i},s=(async()=>{try{for await(let i of n.logs({signal:t}))o[e.getOutput(i)].enqueue(r.encode(i.data));i.close(),a.close()}catch(e){let n=t?.aborted?t.reason:e;throw i.error(n),a.error(n),n}})(),c,l,kill=()=>l??=Promise.resolve().then(()=>n.kill()),killOnAbort=()=>void kill().catch(()=>void 0),disarmKill=()=>t?.removeEventListener(`abort`,killOnAbort);return t?.aborted&&killOnAbort(),t?.addEventListener(`abort`,killOnAbort,{once:!0}),s.then(disarmKill,()=>void 0),{stderr:a.stream,stdout:i.stream,wait(){return c??=Promise.resolve().then(async()=>{let e=await n.wait({signal:t});return disarmKill(),await s,{exitCode:e.exitCode}})},kill}}export{adaptMultiplexedCommandToSandboxProcess};
@@ -1,3 +1,3 @@
1
- import{loadContext}from"#context/container.js";import{MAX_OUTPUT_BYTES,capLineLength}from"#execution/sandbox/truncate-output.js";import{buildReadFileTargetKey,createReadFileStamp,normalizeModelPath,setReadFileStamp}from"#execution/tools/file-state.js";import{resolveAbsoluteFilePath}from"#execution/sandbox/require-sandbox.js";import{detectImageMediaType,hasPdfHeader,readMediaMetadata}from"#internal/attachments/media-metadata.js";import{inlinesSandboxRefAsBytes}from"#internal/attachments/sandbox-refs.js";async function executeReadFileOnSandbox(e,t){let{filePath:n,offset:r,limit:i}=t,a=await resolveAbsoluteFilePath(e,n),o=normalizeModelPath(a),s=await e.readBinaryFile({path:a});if(s===null)throw Error(`File not found: ${o}. Verify the path exists and is accessible in the sandbox.`);if(hasPdfHeader(s))return buildFileReadResult(s,o,`application/pdf`);let c=decodeUtf8(s);if(c===void 0||c.includes(`\0`)){let e=detectImageMediaType(s);if(e!==void 0)return buildFileReadResult(s,o,e);throw Error(`File "${o}" appears to be a binary file. read_file only supports text files, PNG, JPEG, GIF, or WebP images, and PDFs.`)}let l=r??1,u=i??2e3;if(l<1)throw Error(`offset must be >= 1. Received: ${l}.`);let d=c.split(`
1
+ import{loadContext}from"#context/container.js";import{MAX_OUTPUT_BYTES,capLineLength}from"#execution/sandbox/truncate-output.js";import{buildReadFileTargetKey,createReadFileStamp,normalizeModelPath,setReadFileStamp}from"#execution/tools/file-state.js";import{resolveAbsoluteFilePath}from"#execution/sandbox/require-sandbox.js";import{detectImageMediaType,hasPdfHeader}from"#internal/attachments/media-metadata.js";import{readMediaMetadata}from"#internal/attachments/read-media-metadata.js";import{inlinesSandboxRefAsBytes}from"#internal/attachments/sandbox-refs.js";async function executeReadFileOnSandbox(e,t){let{filePath:n,offset:r,limit:i}=t,a=await resolveAbsoluteFilePath(e,n),o=normalizeModelPath(a),s=await e.readBinaryFile({path:a});if(s===null)throw Error(`File not found: ${o}. Verify the path exists and is accessible in the sandbox.`);if(hasPdfHeader(s))return buildFileReadResult(s,o,`application/pdf`);let c=decodeUtf8(s);if(c===void 0||c.includes(`\0`)){let e=detectImageMediaType(s);if(e!==void 0)return buildFileReadResult(s,o,e);throw Error(`File "${o}" appears to be a binary file. read_file only supports text files, PNG, JPEG, GIF, or WebP images, and PDFs.`)}let l=r??1,u=i??2e3;if(l<1)throw Error(`offset must be >= 1. Received: ${l}.`);let d=c.split(`
2
2
  `),f=d.length>0&&d[d.length-1]===``?d.length-1:d.length;if(f===0){if(l>1)throw Error(`offset ${l} is past the end of the file (0 lines). Use the default offset to read an empty file.`)}else if(l>f)throw Error(`offset ${l} is past the end of the file (${f} lines).`);let p=createReadFileStamp({content:c,filePath:o}),m=buildReadFileTargetKey(o);if(setReadFileStamp(loadContext(),m,p),f===0)return{content:``,path:o,totalLines:0,truncated:!1};let h=l-1,g=Math.min(h+u,f),_=d.slice(h,g),v=[],y=0,b=!1;for(let e=0;e<_.length;e++){let t=`${l+e}: ${capLineLength(_[e]??``)}`,n=Buffer.byteLength(t,`utf8`)+1;if(y+n>MAX_OUTPUT_BYTES&&v.length>0){b=!0;break}v.push(t),y+=n}let x=v.join(`
3
3
  `),S=l+v.length-1;return S<f||b?{content:x,nextOffset:S+1,path:o,totalLines:f,truncated:!0}:{content:x,path:o,totalLines:f,truncated:!1}}function decodeUtf8(e){try{return new TextDecoder(`utf-8`,{fatal:!0}).decode(e)}catch{return}}function buildFileReadResult(e,t,n){let r=readMediaMetadata(e,n),i=n===`application/pdf`;if(!inlinesSandboxRefAsBytes({...r,path:t}))throw Error(i?`PDF "${t}" is ${e.byteLength} bytes; read_file shows PDFs up to 20 MiB. Split it or extract its text in the sandbox first.`:`Image "${t}" is ${describeImage(r)}; read_file shows images up to 3 MiB and 8000 pixels per side. Resize or crop it in the sandbox first.`);let a=r.pages===void 0?``:`, ${r.pages} ${r.pages===1?`page`:`pages`}`;return{content:`${i?`PDF`:`Image`} ${t} (${n}, ${e.byteLength} bytes${a}).`,file:r,path:t,totalLines:0,truncated:!1}}function describeImage(e){let t=`${e.size} bytes`;return e.width===void 0?t:`${e.width}x${e.height} pixels, ${t}`}export{executeReadFileOnSandbox};
@@ -111,6 +111,7 @@ export declare function reportHandoverPartStuckStep(input: {
111
111
  * for the caller to retry until it is delivered.
112
112
  */
113
113
  export declare function sendSessionHandoverPartStep(input: {
114
+ readonly bufferedPayloadCount: number;
114
115
  readonly part: Omit<SessionHandoverPayload, "kind">;
115
116
  readonly sessionId: string;
116
117
  }): Promise<"delivered" | "session-ended">;
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{sessionCommandHookToken,sessionInboxHookToken}from"#execution/session-inbox/address.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{walkCauseChain}from"#shared/errors.js";import{getSandboxEnvironmentRuntime}from"#shared/sandbox-environment.js";import{BundleKey}from"#runtime/sessions/runtime-context-keys.js";import{cancelRun,getRun,getWorld,resumeHook}from"#internal/workflow/runtime.js";import{hasRunEnded,startWorkflowOnDeployment,workflowEntryReference}from"#execution/workflow-runtime.js";import{getResolvedRuntimeAgentNode}from"#runtime/graph.js";import{IncompatibleStateLayoutError,deserializeContext}from"#context/serialize.js";import{readDurableSession}from"#execution/durable-session-read.js";import{EntityConflictError,HookNotFoundError,RunExpiredError,WorkflowRunNotFoundError}from"#compiled/@workflow/errors/index.js";import{findSessionHookHolder}from"#execution/session-inbox/owner.js";import{EVE_PREWARM_ATTRIBUTE,EVE_SESSION_ATTRIBUTE,EVE_VERSION_ATTRIBUTE}from"#execution/eve-workflow-attributes.js";import{owningSandboxDefinition}from"#runtime/sandbox/registry.js";import{isRetiredSandboxSessionState,resolvePersistedSandboxSessionState}from"#sandbox/state.js";import{SESSION_CHECKPOINT_VERSION}from"#execution/session/handoff.js";import{mapWithConcurrency}from"#shared/map-with-concurrency.js";import{isSessionStateIdleForHandoff}from"#execution/session/handoff-state.js";import{SESSION_HANDOFF_VERSION}from"#execution/session/entry-input.js";const log=createLogger(`execution.handoff`);async function startSuccessorStep(e){"use step";let{activationToken:t,anchorRunId:n,checkpoint:r,targetDeploymentId:i,...a}=e,{capabilities:o}=await getWorld();if(o?.hookForceClaim!==!0||o.hookRetention?.active!==!0)return log.warn(`session handoff unavailable: the Workflow world cannot force-claim hooks`,{sessionId:n}),{kind:`unsupported`};if(!isSessionStateIdleForHandoff(r))return{kind:`not-idle`};let s={...a,activationToken:t,checkpoint:r,handoffVersion:SESSION_HANDOFF_VERSION,kind:`handoff`,ownerDeploymentId:i,sessionWritable:getRun(n).getWritable(),sessionId:n};return{kind:`started`,runId:(await startWorkflowOnDeployment(workflowEntryReference,[s],i,r.retention===void 0?void 0:{experimental_retention:r.retention})).runId}}async function hasRunEndedStep(e){"use step";return await hasRunEnded(e.runId)}async function prepareSuccessorStep(e){"use step";let{migration:t}=e,unreadable=t=>(log.warn(`session handoff refused: this deployment cannot read the checkpoint`,{detail:t,readableCheckpointVersion:SESSION_CHECKPOINT_VERSION,sessionId:e.sessionId}),{kind:`incompatible`,reason:`checkpoint-version`});if(t.kind===`incompatible`)return unreadable(t.detail);let{checkpoint:n}=t,r=n.sessionTimeoutMs;if(r!==!1&&(typeof r!=`number`||!Number.isFinite(r)||r<0))throw Error(`Session checkpoint contains an invalid timeout duration.`);let i;try{i=await deserializeContext(n.serializedContext)}catch(e){if(e instanceof IncompatibleStateLayoutError)return unreadable(e.message);throw e}let a=i.require(BundleKey),o=readDurableSession(n.sessionState).sandboxState?.session;if(o!=null&&!isRetiredSandboxSessionState(o)){let e=owningSandboxDefinition(getResolvedRuntimeAgentNode(a.graph,a.nodeId).sandboxRegistry.sandbox);if(e.kind!==`independent`)throw Error(`Session checkpoint sandbox has no resolved provider.`);let t=getSandboxEnvironmentRuntime(e.environment),n=resolvePersistedSandboxSessionState(o,t);if(n?.providerName!==t.providerName||n.stateProtocolVersion!==t.stateProtocolVersion)throw Error(`Session checkpoint sandbox provider state is incompatible.`)}if(!isSessionStateIdleForHandoff(n))throw Error(`Session checkpoint contains pending work and cannot be handed off.`);return e.source!==void 0&&!await holdsEveryAddress(e.source)?{kind:`source-gone`}:(await recordSessionOwner(e.sessionId),(e.handoffVersion??1)<SESSION_HANDOFF_VERSION&&log.info(`session moved from an owner that releases its addresses first`,{handoffVersion:e.handoffVersion??1,sessionId:e.sessionId}),{kind:`valid`})}async function holdsEveryAddress(e){return(await mapWithConcurrency(e.hookTokens,16,e=>findSessionHookHolder(sessionInboxHookToken(e)))).every(t=>t?.runId===e.runId)}async function stopUntrackedChildSessionsStep(e){"use step";let t=await getWorld();for(let n of e.runIds)if(n!==e.sessionId)try{await cancelRun(t,n,{cancelReason:`Session upgraded`})}catch(t){[...walkCauseChain(t)].some(e=>EntityConflictError.is(e)||RunExpiredError.is(e)||WorkflowRunNotFoundError.is(e))||logError(log,`could not stop a subagent session after handoff`,t,{childRunId:n,sessionId:e.sessionId})}}async function reportSessionHandoffRetainedStep(e){"use step";log.warn(`session handoff failed; the current owner keeps the session`,{...e,checkpointVersion:SESSION_CHECKPOINT_VERSION})}async function recordSessionOwnerStep(e){"use step";await recordSessionOwner(e.sessionId)}async function recordSessionOwner(e){let{setAttributes:t}=await import(`#compiled/@workflow/core/index.js`);await t({[EVE_SESSION_ATTRIBUTE]:e,[EVE_PREWARM_ATTRIBUTE]:`1`,[EVE_VERSION_ATTRIBUTE]:resolveInstalledPackageInfo().version},{allowReservedAttributes:!0})}async function signalSessionOwnerActivationStep(e){"use step";try{await resumeHook(e.token,e.activation)}catch(e){if(!HookNotFoundError.is(e))throw e}}async function reportSessionTakenOverOutsideAttemptStep(e){"use step";log.error(`session taken over with no handoff attempt open; this run leaves without finalizing`,{sessionId:e.sessionId})}async function reportHandoverPartStuckStep(e){"use step";log.warn(`session handover part keeps failing; the previous owner keeps retrying`,e)}async function sendSessionHandoverPartStep(e){"use step";try{return await resumeHook(sessionInboxHookToken(sessionCommandHookToken(e.sessionId)),{...e.part,kind:`handover`}),`delivered`}catch(e){if(HookNotFoundError.is(e))return`session-ended`;throw e}}async function signalSessionAnchorStep(e){"use step";await resumeHook(e.token,e.result)}export{hasRunEndedStep,prepareSuccessorStep,recordSessionOwnerStep,reportHandoverPartStuckStep,reportSessionHandoffRetainedStep,reportSessionTakenOverOutsideAttemptStep,sendSessionHandoverPartStep,signalSessionAnchorStep,signalSessionOwnerActivationStep,startSuccessorStep,stopUntrackedChildSessionsStep};
1
+ import{createLogger,logError}from"#internal/logging.js";import{sessionCommandHookToken,sessionInboxHookToken}from"#execution/session-inbox/address.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{walkCauseChain}from"#shared/errors.js";import{getSandboxEnvironmentRuntime}from"#shared/sandbox-environment.js";import{BundleKey}from"#runtime/sessions/runtime-context-keys.js";import{cancelRun,getRun,getWorld,resumeHook}from"#internal/workflow/runtime.js";import{hasRunEnded,startWorkflowOnDeployment,workflowEntryReference}from"#execution/workflow-runtime.js";import{getResolvedRuntimeAgentNode}from"#runtime/graph.js";import{IncompatibleStateLayoutError,deserializeContext}from"#context/serialize.js";import{readDurableSession}from"#execution/durable-session-read.js";import{EntityConflictError,HookNotFoundError,RunExpiredError,WorkflowRunNotFoundError}from"#compiled/@workflow/errors/index.js";import{findSessionHookHolder}from"#execution/session-inbox/owner.js";import{EVE_PREWARM_ATTRIBUTE,EVE_SESSION_ATTRIBUTE,EVE_VERSION_ATTRIBUTE}from"#execution/eve-workflow-attributes.js";import{owningSandboxDefinition}from"#runtime/sandbox/registry.js";import{isRetiredSandboxSessionState,resolvePersistedSandboxSessionState}from"#sandbox/state.js";import{SESSION_CHECKPOINT_VERSION}from"#execution/session/handoff.js";import{mapWithConcurrency}from"#shared/map-with-concurrency.js";import{isSessionStateIdleForHandoff}from"#execution/session/handoff-state.js";import{SESSION_HANDOFF_VERSION}from"#execution/session/entry-input.js";import{traceSessionHandover}from"#execution/session/handover-tracing.js";const log=createLogger(`execution.handoff`);async function startSuccessorStep(e){"use step";let{activationToken:t,anchorRunId:n,checkpoint:r,targetDeploymentId:i,...a}=e,{capabilities:o}=await getWorld();if(o?.hookForceClaim!==!0||o.hookRetention?.active!==!0)return log.warn(`session handoff unavailable: the Workflow world cannot force-claim hooks`,{sessionId:n}),{kind:`unsupported`};if(!isSessionStateIdleForHandoff(r))return{kind:`not-idle`};let s={...a,activationToken:t,checkpoint:r,handoffVersion:SESSION_HANDOFF_VERSION,kind:`handoff`,ownerDeploymentId:i,sessionWritable:getRun(n).getWritable(),sessionId:n};return{kind:`started`,runId:(await startWorkflowOnDeployment(workflowEntryReference,[s],i,r.retention===void 0?void 0:{experimental_retention:r.retention})).runId}}async function hasRunEndedStep(e){"use step";return await hasRunEnded(e.runId)}async function prepareSuccessorStep(e){"use step";let{migration:t}=e,unreadable=t=>(log.warn(`session handoff refused: this deployment cannot read the checkpoint`,{detail:t,readableCheckpointVersion:SESSION_CHECKPOINT_VERSION,sessionId:e.sessionId}),{kind:`incompatible`,reason:`checkpoint-version`});if(t.kind===`incompatible`)return unreadable(t.detail);let{checkpoint:n}=t,r=n.sessionTimeoutMs;if(r!==!1&&(typeof r!=`number`||!Number.isFinite(r)||r<0))throw Error(`Session checkpoint contains an invalid timeout duration.`);let i;try{i=await deserializeContext(n.serializedContext)}catch(e){if(e instanceof IncompatibleStateLayoutError)return unreadable(e.message);throw e}let a=i.require(BundleKey),o=readDurableSession(n.sessionState).sandboxState?.session;if(o!=null&&!isRetiredSandboxSessionState(o)){let e=owningSandboxDefinition(getResolvedRuntimeAgentNode(a.graph,a.nodeId).sandboxRegistry.sandbox);if(e.kind!==`independent`)throw Error(`Session checkpoint sandbox has no resolved provider.`);let t=getSandboxEnvironmentRuntime(e.environment),n=resolvePersistedSandboxSessionState(o,t);if(n?.providerName!==t.providerName||n.stateProtocolVersion!==t.stateProtocolVersion)throw Error(`Session checkpoint sandbox provider state is incompatible.`)}if(!isSessionStateIdleForHandoff(n))throw Error(`Session checkpoint contains pending work and cannot be handed off.`);return e.source!==void 0&&!await holdsEveryAddress(e.source)?{kind:`source-gone`}:(await recordSessionOwner(e.sessionId),(e.handoffVersion??1)<SESSION_HANDOFF_VERSION&&log.info(`session moved from an owner that releases its addresses first`,{handoffVersion:e.handoffVersion??1,sessionId:e.sessionId}),{kind:`valid`})}async function holdsEveryAddress(e){return(await mapWithConcurrency(e.hookTokens,16,e=>findSessionHookHolder(sessionInboxHookToken(e)))).every(t=>t?.runId===e.runId)}async function stopUntrackedChildSessionsStep(e){"use step";let t=await getWorld();for(let n of e.runIds)if(n!==e.sessionId)try{await cancelRun(t,n,{cancelReason:`Session upgraded`})}catch(t){[...walkCauseChain(t)].some(e=>EntityConflictError.is(e)||RunExpiredError.is(e)||WorkflowRunNotFoundError.is(e))||logError(log,`could not stop a subagent session after handoff`,t,{childRunId:n,sessionId:e.sessionId})}}async function reportSessionHandoffRetainedStep(e){"use step";log.warn(`session handoff failed; the current owner keeps the session`,{...e,checkpointVersion:SESSION_CHECKPOINT_VERSION})}async function recordSessionOwnerStep(e){"use step";await recordSessionOwner(e.sessionId)}async function recordSessionOwner(e){let{setAttributes:t}=await import(`#compiled/@workflow/core/index.js`);await t({[EVE_SESSION_ATTRIBUTE]:e,[EVE_PREWARM_ATTRIBUTE]:`1`,[EVE_VERSION_ATTRIBUTE]:resolveInstalledPackageInfo().version},{allowReservedAttributes:!0})}async function signalSessionOwnerActivationStep(e){"use step";try{await resumeHook(e.token,e.activation)}catch(e){if(!HookNotFoundError.is(e))throw e}}async function reportSessionTakenOverOutsideAttemptStep(e){"use step";log.error(`session taken over with no handoff attempt open; this run leaves without finalizing`,{sessionId:e.sessionId})}async function reportHandoverPartStuckStep(e){"use step";log.warn(`session handover part keeps failing; the previous owner keeps retrying`,e)}async function sendSessionHandoverPartStep(e){"use step";let t={"eve.handoff.buffered_payload_count":e.bufferedPayloadCount,"eve.handoff.part_index":e.part.index};e.part.index===0&&traceSessionHandover(`forwarding_started`,e.sessionId,e.part.attemptKey,t);try{let n=await resumeHook(sessionInboxHookToken(sessionCommandHookToken(e.sessionId)),{...e.part,kind:`handover`});return traceSessionHandover(e.part.final===!0?`final_submitted`:`part_submitted`,e.sessionId,e.part.attemptKey,{...t,"eve.handoff.destination_run_id":n.runId}),`delivered`}catch(e){if(HookNotFoundError.is(e))return`session-ended`;throw e}}async function signalSessionAnchorStep(e){"use step";await resumeHook(e.token,e.result)}export{hasRunEndedStep,prepareSuccessorStep,recordSessionOwnerStep,reportHandoverPartStuckStep,reportSessionHandoffRetainedStep,reportSessionTakenOverOutsideAttemptStep,sendSessionHandoverPartStep,signalSessionAnchorStep,signalSessionOwnerActivationStep,startSuccessorStep,stopUntrackedChildSessionsStep};
@@ -1 +1 @@
1
- import{isObject}from"#shared/guards.js";import{createHook,getWorkflowMetadata,sleep}from"#compiled/@workflow/core/index.js";import{claimHookOwnership,disposeHook,isHookConflictError}from"#execution/hook-ownership.js";import{hasRunEndedStep,reportHandoverPartStuckStep,reportSessionHandoffRetainedStep,reportSessionTakenOverOutsideAttemptStep,sendSessionHandoverPartStep,startSuccessorStep}from"#execution/session/handoff-steps.js";import{abandonHandoverIfRunEnds,watchRunEnd}from"#execution/session/run-watch.js";import{isSessionStateIdleForHandoff}from"#execution/session/handoff-state.js";import{readAcceptedDeploymentId}from"#execution/session/accepted-deployment.js";const SESSION_CHECKPOINT_VERSION=17;function sessionAnchorToken(e){return`${e}:anchor`}function handoffLeaseToken(e){return`eve:handoff:lease:${e}`}const HANDOFF_LEASE_RETENTION=`7d`;function verdictRunId(e){return e.kind===`verdict`&&e.verdict.kind!==`active`?e.verdict.runId:void 0}async function sendSessionHandover(e){let{attemptKey:t,sessionId:n}=e,r=e.payloads.filter(e=>e.kind!==`handover`);for(let[e,i]of r.entries())if(await sendHandoverPart({attemptKey:t,index:e,payloads:[i]},n)===`session-ended`)return;await sendHandoverPart({attemptKey:t,final:!0,index:r.length,payloads:[]},n)}async function sendHandoverPart(e,t){for(let n=1,r=1;;n++)try{return await sendSessionHandoverPartStep({part:e,sessionId:t})}catch(i){n===HANDOVER_PART_FAILURES_BEFORE_REPORT&&await reportHandoverPartStuckStep({attemptKey:e.attemptKey,error:isObject(i)&&typeof i.message==`string`?i.message:void 0,failures:n,index:e.index,sessionId:t}).catch(()=>{}),await sleep(r*1e3),r=Math.min(r*2,60)}}const HANDOVER_PART_FAILURES_BEFORE_REPORT=5;var SessionHandoff=class{input;anchor;incompatibleTargetDeploymentIds=new Set;attempts=0;worldUnsupported=!1;constructor(e){this.input=e}async tryTransfer(e,t){let{delivery:n}=e,r=readAcceptedDeploymentId(n);return r===void 0?{kind:`retained`,reason:`missing-deployment`}:r===this.input.deploymentId?{kind:`retained`,reason:`same-deployment`}:this.incompatibleTargetDeploymentIds.has(r)?{kind:`retained`,reason:`known-incompatible`}:e.handoffEligible?await this.transfer(t,r,{delivery:n}):{kind:`retained`,reason:`busy`}}async tryCompactionTransfer(e){let{deploymentId:t}=this.input;return this.incompatibleTargetDeploymentIds.has(t)?{kind:`retained`,reason:`known-incompatible`}:await this.transfer(e,t,{reason:`compaction`})}async tryPrewarmTransfer(e,t,n){return t===this.input.deploymentId?{kind:`retained`,reason:`same-deployment`}:this.incompatibleTargetDeploymentIds.has(t)?{kind:`retained`,reason:`known-incompatible`}:await this.transfer(e,t,{reason:`prewarm`,sessionTimeoutDeadline:n})}async transfer(e,t,n){let{inbox:r}=this.input;if(this.worldUnsupported)return{kind:`retained`,reason:`unsupported-world`};if(r.awaitingHandover)return{kind:`retained`,reason:`busy`};if(!isSessionStateIdleForHandoff(e))return{kind:`retained`,reason:`not-idle`};let i=getWorkflowMetadata().workflowRunId,a=this.attempts++,o=`${i}:${String(a)}`,s=r.claimedTokens,c=createHook({token:`${i}:handoff:${String(a)}`});this.ensureAnchor();let l=new AbortController,u=Date.now();try{let a;try{let r=await startSuccessorStep({...n,activationToken:c.token,anchorRunId:this.input.sessionId,attemptKey:o,checkpoint:{...this.input.checkpoint,...e,version:17},hookTokens:s,sourceRunId:i,targetDeploymentId:t});if(r.kind===`not-idle`)return{kind:`retained`,reason:`not-idle`};if(r.kind===`unsupported`)return this.worldUnsupported=!0,{kind:`retained`,reason:`unsupported-world`};a=r.runId}catch(e){let n=await this.fenceAttempt(o);if(n.kind!==`live`)return n.kind===`done`&&await this.holdEveryToken(s),await this.reportRetained(`activation-failed`,t,e),{kind:`retained`,reason:`activation-failed`};a=n.runId}let d=r.whenTakenOver(l.signal).then(()=>({kind:`taken-over`})),f,p;for(;;){if(f===void 0&&p===void 0&&r.hasPending()){let e=u+3e5-Date.now();p=sleep(Math.max(0,e)).then(()=>({kind:`deadline`}))}let e;try{e=await Promise.race([d,c.then(e=>({kind:`verdict`,verdict:e})),f===void 0?p??r.whenArrival().then(()=>({kind:`arrival`})):f.ended.then(()=>({kind:`candidate-ended`}))])}finally{f?.stop()}if(e.kind===`taken-over`)return await this.handOver(o);if(e.kind===`arrival`)continue;let n=e.kind===`candidate-ended`?a:verdictRunId(e),i=await this.fenceAttempt(o,n);if(i.kind===`live`){a=i.runId,f=watchRunEnd(a);continue}i.kind===`done`&&i.runId!==verdictRunId(e)&&await this.holdEveryToken(s);let l=e.kind===`verdict`?await this.recover(e.verdict,{attemptKey:o,candidateRunId:a,hookTokens:s,targetDeploymentId:t}):this.recoverFromSilentCandidate(e.kind);return await this.reportRetained(l.reason,t,l.error),{kind:`retained`,reason:l.reason}}}finally{l.abort(),await disposeHook(c)}}async adoptTakeover(){return await reportSessionTakenOverOutsideAttemptStep({sessionId:this.input.sessionId}),this.ensureAnchor(),{kind:`transferred`}}async fenceAttempt(e,t){let n=createHook({experimental_minRetention:`7d`,token:handoffLeaseToken(e)});try{await claimHookOwnership(n)}catch(e){if(!isHookConflictError(e)||typeof e.conflictingRunId!=`string`)throw e;let n=e.conflictingRunId;return n===t||await hasRunEndedStep({runId:n})?{kind:`done`,runId:n}:{kind:`live`,runId:n}}return{kind:`won`}}async handOver(e){return await sendSessionHandover({attemptKey:e,payloads:this.input.inbox.drain(),sessionId:this.input.sessionId}),{kind:`transferred`}}async holdEveryToken(e){await this.input.inbox.claimSessionHooks(e,{force:!0})}recoverFromSilentCandidate(e){return{error:Error(e===`deadline`?`The successor run did not report within 5 minutes.`:`The successor run ended before the handoff settled.`),reason:`activation-failed`}}async recover(e,t){let{inbox:n}=this.input;switch(e.kind){case`active`:return{error:Error(`Successor reported active without a takeover.`),reason:`activation-failed`};case`incompatible`:return this.incompatibleTargetDeploymentIds.add(t.targetDeploymentId),e.payloads.length>0&&n.restore(e.payloads),{reason:`checkpoint-incompatible`};case`failed`:return e.claimedHooks===!0?(await n.claimSessionHooks(t.hookTokens,{force:!0,handover:t.attemptKey}),abandonHandoverIfRunEnds(n,{attemptKey:t.attemptKey,sourceRunId:e.runId??t.candidateRunId})):isHookConflictError(e.error)&&this.incompatibleTargetDeploymentIds.add(t.targetDeploymentId),e.payloads.length>0&&n.restore(e.payloads),{error:e.error,reason:`activation-failed`}}}ensureAnchor(){this.input.isInitialOwner&&this.anchor===void 0&&(this.anchor=createHook({token:sessionAnchorToken(this.input.sessionId)}))}async awaitAnchoredResult(){if(this.anchor===void 0)throw Error(`Session anchor was never claimed.`);try{return await this.anchor}finally{await this.disposeAnchor()}}async disposeAnchor(){if(this.anchor===void 0)return;let e=this.anchor;this.anchor=void 0,await disposeHook(e)}async reportRetained(e,t,n){let r=isObject(n)&&typeof n.message==`string`?n.message:void 0;await reportSessionHandoffRetainedStep({error:r,reason:e,sessionId:this.input.sessionId,sourceDeploymentId:this.input.deploymentId,targetDeploymentId:t})}};export{HANDOFF_LEASE_RETENTION,SESSION_CHECKPOINT_VERSION,SessionHandoff,handoffLeaseToken,sendSessionHandover,sessionAnchorToken};
1
+ import{isObject}from"#shared/guards.js";import{createHook,getWorkflowMetadata,sleep}from"#compiled/@workflow/core/index.js";import{claimHookOwnership,disposeHook,isHookConflictError}from"#execution/hook-ownership.js";import{hasRunEndedStep,reportHandoverPartStuckStep,reportSessionHandoffRetainedStep,reportSessionTakenOverOutsideAttemptStep,sendSessionHandoverPartStep,startSuccessorStep}from"#execution/session/handoff-steps.js";import{abandonHandoverIfRunEnds,watchRunEnd}from"#execution/session/run-watch.js";import{isSessionStateIdleForHandoff}from"#execution/session/handoff-state.js";import{readAcceptedDeploymentId}from"#execution/session/accepted-deployment.js";const SESSION_CHECKPOINT_VERSION=17;function sessionAnchorToken(e){return`${e}:anchor`}function handoffLeaseToken(e){return`eve:handoff:lease:${e}`}const HANDOFF_LEASE_RETENTION=`7d`;function verdictRunId(e){return e.kind===`verdict`&&e.verdict.kind!==`active`?e.verdict.runId:void 0}async function sendSessionHandover(e){let{attemptKey:t,sessionId:n}=e,r=e.payloads.filter(e=>e.kind!==`handover`);for(let[e,i]of r.entries())if(await sendHandoverPart({attemptKey:t,index:e,payloads:[i]},n,r.length)===`session-ended`)return;await sendHandoverPart({attemptKey:t,final:!0,index:r.length,payloads:[]},n,r.length)}async function sendHandoverPart(e,t,n){for(let r=1,i=1;;r++)try{return await sendSessionHandoverPartStep({bufferedPayloadCount:n,part:e,sessionId:t})}catch(n){r===HANDOVER_PART_FAILURES_BEFORE_REPORT&&await reportHandoverPartStuckStep({attemptKey:e.attemptKey,error:isObject(n)&&typeof n.message==`string`?n.message:void 0,failures:r,index:e.index,sessionId:t}).catch(()=>{}),await sleep(i*1e3),i=Math.min(i*2,60)}}const HANDOVER_PART_FAILURES_BEFORE_REPORT=5;var SessionHandoff=class{input;anchor;incompatibleTargetDeploymentIds=new Set;attempts=0;worldUnsupported=!1;constructor(e){this.input=e}async tryTransfer(e,t){let{delivery:n}=e,r=readAcceptedDeploymentId(n);return r===void 0?{kind:`retained`,reason:`missing-deployment`}:r===this.input.deploymentId?{kind:`retained`,reason:`same-deployment`}:this.incompatibleTargetDeploymentIds.has(r)?{kind:`retained`,reason:`known-incompatible`}:e.handoffEligible?await this.transfer(t,r,{delivery:n}):{kind:`retained`,reason:`busy`}}async tryCompactionTransfer(e){let{deploymentId:t}=this.input;return this.incompatibleTargetDeploymentIds.has(t)?{kind:`retained`,reason:`known-incompatible`}:await this.transfer(e,t,{reason:`compaction`})}async tryPrewarmTransfer(e,t,n){return t===this.input.deploymentId?{kind:`retained`,reason:`same-deployment`}:this.incompatibleTargetDeploymentIds.has(t)?{kind:`retained`,reason:`known-incompatible`}:await this.transfer(e,t,{reason:`prewarm`,sessionTimeoutDeadline:n})}async transfer(e,t,n){let{inbox:r}=this.input;if(this.worldUnsupported)return{kind:`retained`,reason:`unsupported-world`};if(r.awaitingHandover)return{kind:`retained`,reason:`busy`};if(!isSessionStateIdleForHandoff(e))return{kind:`retained`,reason:`not-idle`};let i=getWorkflowMetadata().workflowRunId,a=this.attempts++,o=`${i}:${String(a)}`,s=r.claimedTokens,c=createHook({token:`${i}:handoff:${String(a)}`});this.ensureAnchor();let l=new AbortController,u=Date.now();try{let a;try{let r=await startSuccessorStep({...n,activationToken:c.token,anchorRunId:this.input.sessionId,attemptKey:o,checkpoint:{...this.input.checkpoint,...e,version:17},hookTokens:s,sourceRunId:i,targetDeploymentId:t});if(r.kind===`not-idle`)return{kind:`retained`,reason:`not-idle`};if(r.kind===`unsupported`)return this.worldUnsupported=!0,{kind:`retained`,reason:`unsupported-world`};a=r.runId}catch(e){let n=await this.fenceAttempt(o);if(n.kind!==`live`)return n.kind===`done`&&await this.holdEveryToken(s),await this.reportRetained(`activation-failed`,t,e),{kind:`retained`,reason:`activation-failed`};a=n.runId}let d=r.whenTakenOver(l.signal).then(()=>({kind:`taken-over`})),f,p;for(;;){if(f===void 0&&p===void 0&&r.hasPending()){let e=u+3e5-Date.now();p=sleep(Math.max(0,e)).then(()=>({kind:`deadline`}))}let e;try{e=await Promise.race([d,c.then(e=>({kind:`verdict`,verdict:e})),f===void 0?p??r.whenArrival().then(()=>({kind:`arrival`})):f.ended.then(()=>({kind:`candidate-ended`}))])}finally{f?.stop()}if(e.kind===`taken-over`)return await this.handOver(o);if(e.kind===`arrival`)continue;let n=e.kind===`candidate-ended`?a:verdictRunId(e),i=await this.fenceAttempt(o,n);if(i.kind===`live`){a=i.runId,f=watchRunEnd(a);continue}i.kind===`done`&&i.runId!==verdictRunId(e)&&await this.holdEveryToken(s);let l=e.kind===`verdict`?await this.recover(e.verdict,{attemptKey:o,candidateRunId:a,hookTokens:s,targetDeploymentId:t}):this.recoverFromSilentCandidate(e.kind);return await this.reportRetained(l.reason,t,l.error),{kind:`retained`,reason:l.reason}}}finally{l.abort(),await disposeHook(c)}}async adoptTakeover(){return await reportSessionTakenOverOutsideAttemptStep({sessionId:this.input.sessionId}),this.ensureAnchor(),{kind:`transferred`}}async fenceAttempt(e,t){let n=createHook({experimental_minRetention:`7d`,token:handoffLeaseToken(e)});try{await claimHookOwnership(n)}catch(e){if(!isHookConflictError(e)||typeof e.conflictingRunId!=`string`)throw e;let n=e.conflictingRunId;return n===t||await hasRunEndedStep({runId:n})?{kind:`done`,runId:n}:{kind:`live`,runId:n}}return{kind:`won`}}async handOver(e){return await sendSessionHandover({attemptKey:e,payloads:this.input.inbox.drain(),sessionId:this.input.sessionId}),{kind:`transferred`}}async holdEveryToken(e){await this.input.inbox.claimSessionHooks(e,{force:!0})}recoverFromSilentCandidate(e){return{error:Error(e===`deadline`?`The successor run did not report within 5 minutes.`:`The successor run ended before the handoff settled.`),reason:`activation-failed`}}async recover(e,t){let{inbox:n}=this.input;switch(e.kind){case`active`:return{error:Error(`Successor reported active without a takeover.`),reason:`activation-failed`};case`incompatible`:return this.incompatibleTargetDeploymentIds.add(t.targetDeploymentId),e.payloads.length>0&&n.restore(e.payloads),{reason:`checkpoint-incompatible`};case`failed`:return e.claimedHooks===!0?(await n.claimSessionHooks(t.hookTokens,{force:!0,handover:t.attemptKey}),abandonHandoverIfRunEnds(n,{attemptKey:t.attemptKey,sourceRunId:e.runId??t.candidateRunId})):isHookConflictError(e.error)&&this.incompatibleTargetDeploymentIds.add(t.targetDeploymentId),e.payloads.length>0&&n.restore(e.payloads),{error:e.error,reason:`activation-failed`}}}ensureAnchor(){this.input.isInitialOwner&&this.anchor===void 0&&(this.anchor=createHook({token:sessionAnchorToken(this.input.sessionId)}))}async awaitAnchoredResult(){if(this.anchor===void 0)throw Error(`Session anchor was never claimed.`);try{return await this.anchor}finally{await this.disposeAnchor()}}async disposeAnchor(){if(this.anchor===void 0)return;let e=this.anchor;this.anchor=void 0,await disposeHook(e)}async reportRetained(e,t,n){let r=isObject(n)&&typeof n.message==`string`?n.message:void 0;await reportSessionHandoffRetainedStep({error:r,reason:e,sessionId:this.input.sessionId,sourceDeploymentId:this.input.deploymentId,targetDeploymentId:t})}};export{HANDOFF_LEASE_RETENTION,SESSION_CHECKPOINT_VERSION,SessionHandoff,handoffLeaseToken,sendSessionHandover,sessionAnchorToken};
@@ -0,0 +1,3 @@
1
+ import { type Attributes } from "#compiled/@opentelemetry/api/index.js";
2
+ /** Called only from existing host steps; workflow bodies cannot export host spans. */
3
+ export declare function traceSessionHandover(phase: "forwarding_started" | "part_submitted" | "final_submitted" | "inbox_unblocked", sessionId: string, attemptKey: string, attributes: Attributes): void;
@@ -0,0 +1 @@
1
+ import{getStepMetadata,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{trace}from"#compiled/@opentelemetry/api/index.js";function traceSessionHandover(e,t,n,r){try{let i=trace.getActiveSpan();if(i===void 0)return;let a=getStepMetadata(),o={"eve.session.id":t,"eve.handoff.attempt_key":n,"workflow.run.id":getWorkflowMetadata().workflowRunId,"workflow.step.id":a.stepId,"eve.handoff.step_attempt":a.attempt,...r};for(let[e,t]of Object.entries(o))t!==void 0&&i.setAttribute(e,t);i.addEvent(`eve.session.handover.${e}`,o)}catch{}}export{traceSessionHandover};
@@ -0,0 +1,13 @@
1
+ import { type DurableSessionState } from "#execution/durable-session-store.js";
2
+ import { type SessionStateTransition } from "#execution/session/state-delta.js";
3
+ interface SessionPrewarmInput {
4
+ readonly serializedContext: Record<string, unknown>;
5
+ readonly sessionState: DurableSessionState;
6
+ }
7
+ /**
8
+ * Starts the session prewarmers for a session started without a message and
9
+ * records what they prepared, such as the sandbox state, once their work
10
+ * settles. Runs beside the wait for the first message and never fails.
11
+ */
12
+ export declare function prewarmSessionStep(input: SessionPrewarmInput): Promise<SessionStateTransition>;
13
+ export {};
@@ -0,0 +1 @@
1
+ import{createLogger}from"#internal/logging.js";import{BundleKey}from"#runtime/sessions/runtime-context-keys.js";import{readDurableSession,replaceDurableSessionSnapshot}from"#execution/durable-session-store.js";import{withContextScope}from"#context/run-step.js";import{deserializeContext,serializeContext}from"#context/serialize.js";import{hydrateDurableSession,projectToDurableSession}from"#execution/session.js";import{resolveEffectiveAgentRuntime}from"#execution/effective-agent-config.js";import{withSessionStateDelta}from"#execution/session/state-delta.js";import{startSessionPrewarmers}from"#context/prewarm.js";const log=createLogger(`execution.session.prewarm`);async function prewarmSessionStep(e){"use step";return await withSessionStateDelta(e,prewarmSession)}async function prewarmSession(e){try{let t=await deserializeContext(e.serializedContext),n=resolveEffectiveAgentRuntime(t.require(BundleKey),t),r=hydrateDurableSession({compactionOverrides:{thresholdPercent:n.thresholdPercent},durable:readDurableSession(e.sessionState),turnAgent:n.turnAgent}),i=await withContextScope(t,r,async e=>(startSessionPrewarmers(t,`session`),{result:void 0,session:e}));return{serializedContext:serializeContext(t),sessionState:replaceDurableSessionSnapshot({session:projectToDurableSession(i.session),state:e.sessionState})}}catch(t){return log.warn(`session prewarm failed; the first turn does this work instead`,{error:t,sessionId:e.sessionState.sessionId}),{}}}export{prewarmSessionStep};
@@ -25,7 +25,10 @@ export type SessionStart =
25
25
  readonly kind: "turn";
26
26
  readonly input: DeliverHookPayload | undefined;
27
27
  }
28
- /** A prewarmed session parks on the inbox before any session-scoped lifecycle work. */
28
+ /**
29
+ * A prewarmed session parks on the inbox before any turn, session event, or
30
+ * session hook, while its session prewarmers run beside the wait.
31
+ */
29
32
  | {
30
33
  readonly kind: "first-message";
31
34
  }
@@ -1 +1 @@
1
- import{STUB_CONTEXT_KEY}from"#tool-stubs/types.js";import{workingTasks}from"#execution/tasks/table.js";import{settleCancelledTurnStep}from"#execution/settle-cancelled-turn-step.js";import"#execution/session-inbox/inbox.js";import{signalSessionAnchorStep}from"#execution/session/handoff-steps.js";import{SessionInputQueue}from"#execution/session/input-queue.js";import{createTurnControl}from"#execution/session/turn-control.js";import{SessionHandoff,sessionAnchorToken}from"#execution/session/handoff.js";import{notifyCancelledTaskCallerStep,notifyTurnCallerStep,resolveInitialTurnCallerStep}from"#subagents/parent-notification.js";import{withStubPlayback}from"#execution/tool-stubs/playback.js";import{nextTurnDelivery}from"#execution/session/next-input.js";import{SessionExecution}from"#execution/session/turn.js";import{SessionStateCursor}from"#execution/session/state-cursor.js";import{cancelWorkingTasks,sessionTaskTable}from"#execution/tasks/session.js";import{finalizeSession}from"#execution/session/finalization.js";function createSafeOuterWorkflowError(){let e=Error(`Agent workflow failed. Inspect the private session trace for details.`);return e.name=`EveWorkflowFailure`,e}async function runPreparedSession(e,t){let n=e.serializedContext[STUB_CONTEXT_KEY];n!==void 0&&n.rootSessionId===void 0&&(e.serializedContext[STUB_CONTEXT_KEY]={...n,rootSessionId:e.sessionId});let r=new SessionStateCursor({history:e.history,inbox:t,sessionWritable:e.sessionWritable,serializedContext:e.serializedContext,sessionState:e.sessionState}),i={caller:e.caller,terminalEmitted:!1},a=new SessionHandoff({checkpoint:{capabilities:e.capabilities,retention:e.retention,sessionTimeoutMs:e.sessionTimeoutMs},deploymentId:e.deploymentId,inbox:t,isInitialOwner:e.anchor.kind===`self`,sessionId:e.sessionId}),o={output:``,isError:!0},s;try{return o=await withStubPlayback(n,e.sessionId,async()=>{try{s=await runSessionLoop(e,{cursor:r,handoff:a,inbox:t,progress:i})}finally{await t.dispose()}return s.kind===`transferred`?e.anchor.kind===`self`?(o=await a.awaitAnchoredResult(),o):{output:``}:(o=await finalizeSession(s.outcome,{caller:i.caller,cursor:r,sessionWritable:e.sessionWritable}),i.terminalEmitted=!0,o)}),o}catch(t){throw i.terminalEmitted||await finalizeSession({error:t,kind:`failed`,turnId:i.turnId},{caller:i.caller,cursor:r,sessionWritable:e.sessionWritable}),createSafeOuterWorkflowError()}finally{await t.dispose(),await reportResultToAnchor(e,o,a,s)}}async function failSession(e){let t;try{t=await resolveInitialTurnCallerStep({serializedContext:e.serializedContext})}catch{}throw await finalizeSession({error:e.error,kind:`failed`},{caller:t,cursor:{serializedContext:e.serializedContext,sessionState:e.sessionState},sessionWritable:e.sessionWritable}),createSafeOuterWorkflowError()}async function reportResultToAnchor(e,t,n,r){switch(e.anchor.kind){case`self`:await n.disposeAnchor(),await e.anchor.notify?.(t);return;case`successor`:if(r?.kind===`transferred`)return;await signalSessionAnchorStep({result:t,token:sessionAnchorToken(e.sessionId)});return}}async function runSessionLoop(e,t){let{cursor:n,handoff:r,inbox:i,progress:a}=t,o=new SessionInputQueue(e.admittedDeliveryKeys),s=new SessionExecution({capabilities:e.capabilities,cursor:n,inbox:i,queue:o,sessionId:e.sessionId}),c=e.sessionTimeoutControl,nextParkedActivity=async()=>{for(;;){let e=await nextTurnDelivery({cursor:n,hasWorkingTasks:()=>workingTasks(sessionTaskTable(n)).length>0,inbox:i,queue:o});if(e.kind===`prewarm`){if(a.caller===void 0&&workingTasks(sessionTaskTable(n)).length===0&&o.pendingCount===0&&!i.hasPending()){let t=c?.getDeadline(),n=await r.tryPrewarmTransfer(transferState(),e.targetDeploymentId,t);if(n.kind===`transferred`)return n}continue}if(e.kind===`workflow`){await s.handleWorkflowMessage(e.message);continue}if(e.kind===`cancel-working-tasks`){await cancelWorkingTasks(n,`turn_cancelled`);continue}if(!(e.kind===`expired`&&c!==void 0&&((o.pendingCount>0||i.hasPending())&&c.recordActivity(),await c.handleTimerElapsed()===`extended`)))return e}},l=e.initialTurnControl??(e.anchor.kind===`self`?createTurnControl():void 0),u=0,d=!1,runTurn=async e=>{let t=a.caller,n=l;l=void 0,a.turnId=`turn_${String(u++)}`;let r=await s.runTurn(e,{caller:t,control:n});return c?.recordActivity(),r.caller!==void 0&&(a.caller=r.caller),r.compacted===!0&&(d=!0),r},transferState=()=>({admittedDeliveryKeys:o.admittedDeliveryKeys,history:n.history,serializedContext:n.serializedContext,sessionState:n.sessionState}),compactionHandoffReady=()=>d&&a.caller===void 0&&workingTasks(sessionTaskTable(n)).length===0,tryCompactionHandoff=async()=>{if(!compactionHandoffReady()||o.pendingCount>0||i.hasPending())return;let e=await r.tryCompactionTransfer(transferState());return e.kind===`transferred`?e:void 0},runDeliveredTurn=async e=>{let t=await r.tryTransfer(e,transferState());return t.kind===`transferred`?t:(e.delivery.caller!==void 0&&(a.caller=e.delivery.caller),{action:await runTurn({delivery:e.delivery}),kind:`action`})},settleCancelledTurn=async e=>{let t=await n.advanceWithHistory(t=>settleCancelledTurnStep({...t,reportUsage:e}));return a.caller=void 0,t},awaitPrewarmedAction=async()=>{for(;;){let e=await nextParkedActivity();switch(e.kind){case`closed`:return i.takenOver?await r.adoptTakeover():{kind:`terminal`,outcome:{kind:`expired`}};case`transferred`:return e;case`expired`:case`reset`:return{kind:`terminal`,outcome:{kind:`expired`}};case`clear`:case`compact`:continue;case`turn`:return await runDeliveredTurn(e);case`cancel-turn`:continue}}},runInitialAction=async()=>{switch(e.start.kind){case`first-message`:return await awaitPrewarmedAction();case`parked`:return{action:{kind:`park`},kind:`action`};case`turn`:{let{input:t}=e.start;return{action:await runTurn(t===void 0?void 0:{delivery:t}),kind:`action`}}}};try{let[t,n]=await Promise.allSettled([runInitialAction(),c?.start()]);if(n.status===`rejected`)throw n.reason;if(t.status===`rejected`)throw t.reason;let o=t.value;if(o.kind!==`action`)return o;let u=o.action;for(;;){if(u.kind===`done`)return{kind:`terminal`,outcome:{action:u,kind:`done`}};if(u.cancelled===!0){let{caller:t}=a,n=await settleCancelledTurn(t!==void 0);if(t!==void 0){let r={caller:t,sessionId:e.sessionId};await notifyCancelledTaskCallerStep(n.usage===void 0?r:{...r,usage:n.usage})}}else u.settled!==void 0&&(a.caller!==void 0&&await notifyTurnCallerStep({caller:a.caller,lifecycle:`parked`,sessionId:e.sessionId,settled:u.settled}),a.caller=void 0);let t=await tryCompactionHandoff();if(t!==void 0)return t;l??=createTurnControl();let n=await nextParkedActivity();switch(n.kind){case`closed`:return i.takenOver?await r.adoptTakeover():{kind:`terminal`,outcome:{kind:`expired`}};case`transferred`:return n;case`expired`:case`reset`:return{kind:`terminal`,outcome:{kind:`expired`}};case`clear`:case`compact`:u=await runTurn({control:n.kind});continue;case`cancel-turn`:await s.cancelTurnWork(),await settleCancelledTurn(!1),c?.recordActivity(),u={...u,settled:void 0};continue;case`turn`:{let e=await runDeliveredTurn(n);if(e.kind!==`action`)return e;u=e.action;continue}}}}finally{await c?.dispose()}}export{failSession,runPreparedSession};
1
+ import{STUB_CONTEXT_KEY}from"#tool-stubs/types.js";import{workingTasks}from"#execution/tasks/table.js";import{settleCancelledTurnStep}from"#execution/settle-cancelled-turn-step.js";import"#execution/session-inbox/inbox.js";import{signalSessionAnchorStep}from"#execution/session/handoff-steps.js";import{SessionInputQueue}from"#execution/session/input-queue.js";import{createTurnControl}from"#execution/session/turn-control.js";import{SessionHandoff,sessionAnchorToken}from"#execution/session/handoff.js";import{notifyCancelledTaskCallerStep,notifyTurnCallerStep,resolveInitialTurnCallerStep}from"#subagents/parent-notification.js";import{withStubPlayback}from"#execution/tool-stubs/playback.js";import{nextTurnDelivery}from"#execution/session/next-input.js";import{SessionExecution}from"#execution/session/turn.js";import{SessionStateCursor}from"#execution/session/state-cursor.js";import{cancelWorkingTasks,sessionTaskTable}from"#execution/tasks/session.js";import{finalizeSession}from"#execution/session/finalization.js";import{prewarmSessionStep}from"#execution/session/prewarm-step.js";function createSafeOuterWorkflowError(){let e=Error(`Agent workflow failed. Inspect the private session trace for details.`);return e.name=`EveWorkflowFailure`,e}async function runPreparedSession(e,t){let n=e.serializedContext[STUB_CONTEXT_KEY];n!==void 0&&n.rootSessionId===void 0&&(e.serializedContext[STUB_CONTEXT_KEY]={...n,rootSessionId:e.sessionId});let r=new SessionStateCursor({history:e.history,inbox:t,sessionWritable:e.sessionWritable,serializedContext:e.serializedContext,sessionState:e.sessionState}),i={caller:e.caller},a=new SessionHandoff({checkpoint:{capabilities:e.capabilities,retention:e.retention,sessionTimeoutMs:e.sessionTimeoutMs},deploymentId:e.deploymentId,inbox:t,isInitialOwner:e.anchor.kind===`self`,sessionId:e.sessionId}),o={output:``,isError:!0},s,c=!1;try{return o=await withStubPlayback(n,e.sessionId,async()=>{try{s=await runSessionLoop(e,{cursor:r,handoff:a,inbox:t,progress:i})}finally{await t.dispose()}return s.kind===`transferred`?e.anchor.kind===`self`?(o=await a.awaitAnchoredResult(),o):{output:``}:(c=!0,o=await finalizeSession(s.outcome,{caller:i.caller,cursor:r,sessionWritable:e.sessionWritable}),o)}),o}catch(t){throw c||await finalizeSession({error:t,kind:`failed`,turnId:i.turnId},{caller:i.caller,cursor:r,sessionWritable:e.sessionWritable}),createSafeOuterWorkflowError()}finally{await t.dispose(),await reportResultToAnchor(e,o,a,s)}}async function failSession(e){let t;try{t=await resolveInitialTurnCallerStep({serializedContext:e.serializedContext})}catch{}throw await finalizeSession({error:e.error,kind:`failed`},{caller:t,cursor:{serializedContext:e.serializedContext,sessionState:e.sessionState},sessionWritable:e.sessionWritable}),createSafeOuterWorkflowError()}async function reportResultToAnchor(e,t,n,r){switch(e.anchor.kind){case`self`:await n.disposeAnchor(),await e.anchor.notify?.(t);return;case`successor`:if(r?.kind===`transferred`)return;await signalSessionAnchorStep({result:t,token:sessionAnchorToken(e.sessionId)});return}}async function runSessionLoop(e,t){let{cursor:n,handoff:r,inbox:i,progress:a}=t,o=new SessionInputQueue(e.admittedDeliveryKeys),s=new SessionExecution({capabilities:e.capabilities,cursor:n,inbox:i,queue:o,sessionId:e.sessionId}),c=e.sessionTimeoutControl,l=Promise.resolve(),u=!0,d=!1,nextParkedActivity=async()=>{for(;;){let e=await nextTurnDelivery({cursor:n,hasWorkingTasks:()=>workingTasks(sessionTaskTable(n)).length>0,inbox:i,queue:o});if(e.kind===`prewarm`){if(u&&a.caller===void 0&&workingTasks(sessionTaskTable(n)).length===0&&o.pendingCount===0&&!i.hasPending()){let t=c?.getDeadline(),n=await r.tryPrewarmTransfer(transferState(),e.targetDeploymentId,t);if(n.kind===`transferred`)return n}continue}if(e.kind===`workflow`){await s.handleWorkflowMessage(e.message);continue}if(e.kind===`cancel-working-tasks`){await cancelWorkingTasks(n,`turn_cancelled`);continue}if(!(e.kind===`expired`&&c!==void 0&&((o.pendingCount>0||i.hasPending())&&c.recordActivity(),await c.handleTimerElapsed()===`extended`)))return e}},f=e.initialTurnControl??(e.anchor.kind===`self`?createTurnControl():void 0),p=0,m=!1,runTurn=async e=>{let t=a.caller,n=f;f=void 0,a.turnId=`turn_${String(p++)}`;let r=await s.runTurn(e,{caller:t,control:n});return c?.recordActivity(),r.caller!==void 0&&(a.caller=r.caller),r.compacted===!0&&(m=!0),r},transferState=()=>({admittedDeliveryKeys:o.admittedDeliveryKeys,history:n.history,serializedContext:n.serializedContext,sessionState:n.sessionState}),compactionHandoffReady=()=>m&&a.caller===void 0&&workingTasks(sessionTaskTable(n)).length===0,tryCompactionHandoff=async()=>{if(!compactionHandoffReady()||o.pendingCount>0||i.hasPending())return;let e=await r.tryCompactionTransfer(transferState());return e.kind===`transferred`?e:void 0},runDeliveredTurn=async e=>{let t=await r.tryTransfer(e,transferState());return t.kind===`transferred`?t:(e.delivery.caller!==void 0&&(a.caller=e.delivery.caller),{action:await runTurn({delivery:e.delivery}),kind:`action`})},settleCancelledTurn=async e=>{let t=await n.advanceWithHistory(t=>settleCancelledTurnStep({...t,reportUsage:e}));return a.caller=void 0,t},awaitPrewarmedAction=async()=>{for(;;){let e=await nextParkedActivity();switch(d=!1,e.kind){case`closed`:return i.takenOver?await r.adoptTakeover():{kind:`terminal`,outcome:{kind:`expired`}};case`transferred`:return e;case`expired`:case`reset`:return{kind:`terminal`,outcome:{kind:`expired`}};case`clear`:case`compact`:continue;case`turn`:return await runDeliveredTurn(e);case`cancel-turn`:continue}}},runInitialAction=async()=>{switch(e.start.kind){case`first-message`:return d=!0,u=!1,l=n.advanceBeside(({serializedContext:e,sessionState:t})=>prewarmSessionStep({serializedContext:e,sessionState:t}),()=>d).then(()=>void 0,()=>void 0).finally(()=>{u=!0}),await awaitPrewarmedAction();case`parked`:return{action:{kind:`park`},kind:`action`};case`turn`:{let{input:t}=e.start;return{action:await runTurn(t===void 0?void 0:{delivery:t}),kind:`action`}}}};try{let[t,n]=await Promise.allSettled([runInitialAction(),c?.start()]);if(n.status===`rejected`)throw n.reason;if(t.status===`rejected`)throw t.reason;let o=t.value;if(o.kind!==`action`)return o;let l=o.action;for(;;){if(l.kind===`done`)return{kind:`terminal`,outcome:{action:l,kind:`done`}};if(l.cancelled===!0){let{caller:t}=a,n=await settleCancelledTurn(t!==void 0);if(t!==void 0){let r={caller:t,sessionId:e.sessionId};await notifyCancelledTaskCallerStep(n.usage===void 0?r:{...r,usage:n.usage})}}else l.settled!==void 0&&(a.caller!==void 0&&await notifyTurnCallerStep({caller:a.caller,lifecycle:`parked`,sessionId:e.sessionId,settled:l.settled}),a.caller=void 0);let t=await tryCompactionHandoff();if(t!==void 0)return t;f??=createTurnControl();let n=await nextParkedActivity();switch(n.kind){case`closed`:return i.takenOver?await r.adoptTakeover():{kind:`terminal`,outcome:{kind:`expired`}};case`transferred`:return n;case`expired`:case`reset`:return{kind:`terminal`,outcome:{kind:`expired`}};case`clear`:case`compact`:l=await runTurn({control:n.kind});continue;case`cancel-turn`:await s.cancelTurnWork(),await settleCancelledTurn(!1),c?.recordActivity(),l={...l,settled:void 0};continue;case`turn`:{let e=await runDeliveredTurn(n);if(e.kind!==`action`)return e;l=e.action;continue}}}}finally{d=!1,await l,await c?.dispose()}}export{failSession,runPreparedSession};
@@ -14,6 +14,9 @@ export declare class SessionStateCursor {
14
14
  readonly sessionWritable: WritableStream<Uint8Array>;
15
15
  private readonly inbox;
16
16
  private values;
17
+ /** Session steps adopted so far, and those still running. */
18
+ private adopted;
19
+ private running;
17
20
  constructor(input: SessionStateValues & {
18
21
  readonly inbox: Pick<SessionInboxOwnership, "claimSessionHooks">;
19
22
  readonly sessionWritable: WritableStream<Uint8Array>;
@@ -30,6 +33,14 @@ export declare class SessionStateCursor {
30
33
  advance<T extends SessionStateTransition>(step: (state: SessionStepState) => Promise<T>): Promise<T>;
31
34
  /** {@link advance} for a step that reads or changes the history, such as a turn. */
32
35
  advanceWithHistory<T extends SessionStateTransition>(step: (state: SessionHistoryStepState) => Promise<T>): Promise<T>;
36
+ /**
37
+ * Runs a step beside the session's own steps, which do not wait for it.
38
+ * Its delta applies only while `wanted()` holds, no other step ran or is
39
+ * running meanwhile, and it adds no session address; otherwise it is
40
+ * dropped and this returns `false`. A step run this way must leave nothing
41
+ * that dropping its delta would lose for good.
42
+ */
43
+ advanceBeside<T extends SessionStateTransition>(step: (state: SessionStepState) => Promise<T>, wanted: () => boolean): Promise<boolean>;
33
44
  /**
34
45
  * A delta describes a change to exactly the values its step was given, so
35
46
  * values that another step changed in the meantime are a sequencing bug,
@@ -1 +1 @@
1
- import{applySessionStateDelta}from"#execution/session/state-delta.js";import{sessionHookTokens}from"#execution/session/hook-tokens.js";var SessionStateCursor=class{sessionWritable;inbox;values;constructor(e){this.inbox=e.inbox,this.sessionWritable=e.sessionWritable,this.values={history:e.history,serializedContext:e.serializedContext,sessionState:e.sessionState}}get serializedContext(){return this.values.serializedContext}get sessionState(){return this.values.sessionState}get history(){return this.values.history}async advance(e){let{serializedContext:t,sessionState:n}=this.values;return await this.adopt(()=>e({serializedContext:t,sessionState:n,sessionWritable:this.sessionWritable}),{withHistory:!1})}async advanceWithHistory(e){return await this.adopt(()=>e({...this.values,sessionWritable:this.sessionWritable}),{withHistory:!0})}async adopt(e,t){let n=this.values,r=await e();if(!t.withHistory&&r.stateDelta.history!==void 0)throw Error(`A session step that was not given the history cannot change it.`);let i=applySessionStateDelta(n,r.stateDelta);if(await this.inbox.claimSessionHooks(sessionHookTokens(i)),this.values!==n)throw Error(`Session state changed while a step ran, so its state delta cannot apply.`);return this.values=i,r}};export{SessionStateCursor};
1
+ import{applySessionStateDelta}from"#execution/session/state-delta.js";import{sessionHookTokens}from"#execution/session/hook-tokens.js";var SessionStateCursor=class{sessionWritable;inbox;values;adopted=0;running=0;constructor(e){this.inbox=e.inbox,this.sessionWritable=e.sessionWritable,this.values={history:e.history,serializedContext:e.serializedContext,sessionState:e.sessionState}}get serializedContext(){return this.values.serializedContext}get sessionState(){return this.values.sessionState}get history(){return this.values.history}async advance(e){let{serializedContext:t,sessionState:n}=this.values;return await this.adopt(()=>e({serializedContext:t,sessionState:n,sessionWritable:this.sessionWritable}),{withHistory:!1})}async advanceWithHistory(e){return await this.adopt(()=>e({...this.values,sessionWritable:this.sessionWritable}),{withHistory:!0})}async advanceBeside(e,t){let n=this.values,r=this.adopted,i=await e({serializedContext:n.serializedContext,sessionState:n.sessionState,sessionWritable:this.sessionWritable});if(!t()||this.adopted!==r||this.running>0)return!1;if(i.stateDelta.history!==void 0)throw Error(`A session step that was not given the history cannot change it.`);let a=applySessionStateDelta(n,i.stateDelta),o=new Set(sessionHookTokens(n));return!sessionHookTokens(a).some(e=>!o.has(e))&&(this.values=a,this.adopted++,!0)}async adopt(e,t){let n=this.values;this.running++;try{let r=await e();if(!t.withHistory&&r.stateDelta.history!==void 0)throw Error(`A session step that was not given the history cannot change it.`);let i=applySessionStateDelta(n,r.stateDelta);if(await this.inbox.claimSessionHooks(sessionHookTokens(i)),this.values!==n)throw Error(`Session state changed while a step ran, so its state delta cannot apply.`);return this.values=i,this.adopted++,r}finally{this.running--}}};export{SessionStateCursor};
@@ -6,6 +6,7 @@ import type { HarnessModelMessage } from "#harness/messages.js";
6
6
  import type { SettledTurn } from "#harness/types.js";
7
7
  import type { RuntimeActionResult } from "#shared/action-types.js";
8
8
  import type { TokenUsage } from "#shared/token-usage.js";
9
+ import type { SessionHandoverObservation } from "#execution/session-inbox/inbox.js";
9
10
  /** Trusted runtime-action results collected by the session owner. */
10
11
  export interface RuntimeActionResultStepInput {
11
12
  readonly acceptedAtMsByCallId?: Readonly<Record<string, number>>;
@@ -25,6 +26,7 @@ export interface TurnStepPayload {
25
26
  }
26
27
  /** Input for one atomic, session-owner-executed turn step. */
27
28
  export interface TurnStepInput {
29
+ readonly handover?: SessionHandoverObservation;
28
30
  readonly abortSignal?: AbortSignal;
29
31
  /** The delegated caller to bind into the context before the step runs; sent on a turn's first step. */
30
32
  readonly caller?: TurnCaller;