eve 0.84.0 → 0.85.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/dist/src/channel/channel-operations.d.ts +2 -18
- package/dist/src/channel/compiled-channel.d.ts +3 -7
- package/dist/src/channel/cross-channel-receive.d.ts +13 -11
- package/dist/src/channel/cross-channel-receive.js +1 -1
- package/dist/src/channel/delivery.js +1 -1
- package/dist/src/channel/schedule.js +1 -1
- package/dist/src/channel/session.d.ts +26 -4
- package/dist/src/channel/session.js +1 -1
- package/dist/src/channel/types.d.ts +2 -0
- package/dist/src/chunks/{use-eve-agent-BbbguIdB.js → use-eve-agent-B2jCfcnG.js} +29 -12
- package/dist/src/chunks/{use-eve-agent-DWjyzplb.js → use-eve-agent-DCLFi26P.js} +29 -12
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/client/client.js +1 -1
- package/dist/src/client/delivery.d.ts +2 -0
- package/dist/src/client/delivery.js +1 -1
- package/dist/src/client/open-stream.js +1 -1
- package/dist/src/client/optimistic-message-submissions.js +1 -1
- package/dist/src/client/session-store.js +1 -1
- package/dist/src/client/session.js +1 -1
- package/dist/src/client/sessions.d.ts +1 -0
- package/dist/src/client/sessions.js +1 -1
- package/dist/src/client/types.d.ts +7 -4
- package/dist/src/compiled/.vendor-stamp.json +2 -2
- package/dist/src/compiled/@chat-adapter/slack/index.js +13 -13
- package/dist/src/compiled/@vercel/sandbox/api-client/api-client.d.ts +75 -0
- package/dist/src/compiled/@vercel/sandbox/api-client/validators.d.ts +4 -0
- package/dist/src/compiled/@vercel/sandbox/command.d.ts +78 -0
- package/dist/src/compiled/@vercel/sandbox/drive.d.ts +41 -1
- package/dist/src/compiled/@vercel/sandbox/index.js +13 -13
- package/dist/src/compiled/@vercel/sandbox/network-policy.d.ts +35 -4
- package/dist/src/compiled/@vercel/sandbox/sandbox.d.ts +18 -4
- package/dist/src/compiled/@vercel/sandbox/session.d.ts +29 -3
- package/dist/src/compiled/@vercel/sandbox/utils/pipe-stdin.d.ts +19 -0
- package/dist/src/compiled/_chunks/client/{core-CspsxXR-.js → core-BsvaaMUJ.js} +1 -1
- package/dist/src/compiled/_chunks/node/{auth-Dztlx9pE.js → auth-v5pS3mLo.js} +1 -1
- package/dist/src/compiled/_chunks/node/is-stream-DsuQX_bd.js +1 -0
- package/dist/src/compiled/_chunks/node/token-DHGH-jVc.js +1 -0
- package/dist/src/compiled/_chunks/node/token-util-BH2pw9Qm.js +25 -0
- package/dist/src/compiled/_chunks/node/token-util-CcvxNv76.js +1 -0
- package/dist/src/compiled/_chunks/node/version-C2PfNyEv.js +1 -0
- package/dist/src/compiled/zod/index.js +1 -1
- package/dist/src/compiled/zod/v4/core.js +1 -1
- package/dist/src/compiled/zod-validation-error/index.js +1 -1
- package/dist/src/compiler/artifacts.d.ts +1 -0
- package/dist/src/compiler/artifacts.js +1 -1
- package/dist/src/compiler/manifest.d.ts +2 -2
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/model-catalog.d.ts +8 -18
- package/dist/src/compiler/model-catalog.js +1 -1
- package/dist/src/compiler/normalize-agent-config.js +1 -1
- package/dist/src/compiler/normalize-manifest-types.d.ts +3 -0
- package/dist/src/compiler/normalize-manifest.js +1 -1
- package/dist/src/context/keys.d.ts +7 -8
- package/dist/src/context/keys.js +1 -1
- package/dist/src/eve-channel/index.js +1 -1
- package/dist/src/eve-channel/request.d.ts +1 -0
- package/dist/src/eve-channel/request.js +1 -1
- package/dist/src/eve-channel/support.js +1 -1
- package/dist/src/execution/agent-sessions/context.d.ts +5 -1
- package/dist/src/execution/agent-sessions/context.js +1 -1
- package/dist/src/execution/agent-sessions/steps.js +1 -1
- package/dist/src/execution/dynamic-workflow/tool.js +1 -1
- package/dist/src/execution/legacy-session/snapshot.d.ts +1 -2
- package/dist/src/execution/legacy-session/snapshot.js +1 -1
- package/dist/src/execution/proxied-deliver-step.js +1 -1
- package/dist/src/execution/public-destination.d.ts +3 -0
- package/dist/src/execution/public-destination.js +1 -1
- package/dist/src/execution/publish-session-events.js +1 -1
- package/dist/src/execution/sandbox/bindings/docker-cli.d.ts +2 -0
- package/dist/src/execution/sandbox/bindings/docker-cli.js +1 -1
- package/dist/src/execution/sandbox/bindings/docker-connection.js +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
- package/dist/src/execution/sandbox/multiplexed-command.d.ts +11 -1
- package/dist/src/execution/sandbox/multiplexed-command.js +1 -1
- package/dist/src/execution/sandbox/session.js +1 -1
- package/dist/src/execution/session/checkpoint-migrations.d.ts +16 -5
- package/dist/src/execution/session/checkpoint-migrations.js +1 -1
- package/dist/src/execution/session/checkpoint-refusal.d.ts +4 -0
- package/dist/src/execution/session/checkpoint-refusal.js +1 -0
- package/dist/src/execution/session/entry.js +1 -1
- package/dist/src/execution/session/handoff-steps.d.ts +7 -1
- package/dist/src/execution/session/handoff-steps.js +1 -1
- package/dist/src/execution/session/imported-conversation.d.ts +2 -0
- package/dist/src/execution/session/imported-conversation.js +1 -0
- package/dist/src/execution/session/interrupted-step.js +1 -1
- package/dist/src/execution/session/pre-v27-checkpoint.d.ts +36 -0
- package/dist/src/execution/session/pre-v27-checkpoint.js +1 -0
- package/dist/src/execution/session/program.d.ts +2 -0
- package/dist/src/execution/session/program.js +1 -1
- package/dist/src/execution/session/turn-step.js +1 -1
- package/dist/src/execution/session-callback-request.js +1 -1
- package/dist/src/execution/session-inbox/address.d.ts +1 -0
- package/dist/src/execution/session-inbox/handle.d.ts +7 -0
- package/dist/src/execution/session-inbox/handle.js +1 -0
- package/dist/src/execution/session-inbox/owner.d.ts +4 -4
- package/dist/src/execution/session-inbox/owner.js +1 -1
- package/dist/src/execution/session-inbox/resume.d.ts +1 -0
- package/dist/src/execution/session-inbox/resume.js +1 -1
- package/dist/src/execution/tool-auth.js +1 -1
- package/dist/src/execution/tools/agent-router-workflow.js +1 -1
- package/dist/src/execution/tools/channel-to.d.ts +12 -0
- package/dist/src/execution/tools/channel-to.js +1 -0
- package/dist/src/execution/tools/workflow/body.d.ts +3 -0
- package/dist/src/execution/tools/workflow/body.js +1 -1
- package/dist/src/execution/tools/workflow/step-context.d.ts +5 -0
- package/dist/src/execution/tools/workflow/step-execution.js +1 -1
- package/dist/src/execution/tools/workflow/step.js +1 -1
- package/dist/src/execution/workflow-callback-url.d.ts +2 -3
- package/dist/src/execution/workflow-callback-url.js +1 -1
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/harness/compaction/step.js +1 -1
- package/dist/src/harness/model-call/call.d.ts +3 -1
- package/dist/src/harness/model-call/call.js +1 -1
- package/dist/src/harness/model-call/run.js +1 -1
- package/dist/src/harness/semantic-errors/rules/gateway.js +1 -1
- package/dist/src/harness/session-machine/transitions.js +1 -1
- package/dist/src/internal/application/compiled-artifacts.d.ts +2 -0
- package/dist/src/internal/application/compiled-artifacts.js +2 -2
- package/dist/src/internal/application/optional-package-install.js +1 -1
- package/dist/src/internal/application/stamped-package-version.js +1 -1
- package/dist/src/internal/attachments/limited-read.d.ts +2 -0
- package/dist/src/internal/attachments/limited-read.js +1 -1
- package/dist/src/internal/attachments/url-refs.js +1 -1
- package/dist/src/internal/capability-error.d.ts +3 -0
- package/dist/src/internal/capability-error.js +1 -0
- package/dist/src/internal/model-catalog.d.ts +39 -16
- package/dist/src/internal/model-catalog.js +1 -1
- package/dist/src/internal/nitro/host/dev-build-host.js +1 -1
- package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
- package/dist/src/protocol/delivery.d.ts +1 -0
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +1 -1
- package/dist/src/public/channels/discord/discordChannel.js +1 -1
- package/dist/src/public/channels/github/githubChannel.js +1 -1
- package/dist/src/public/channels/linear/linearChannel.js +1 -1
- package/dist/src/public/channels/linq/inboundContent.js +1 -1
- package/dist/src/public/channels/slack/answers.d.ts +2 -3
- package/dist/src/public/channels/slack/answers.js +1 -1
- package/dist/src/public/channels/slack/api.d.ts +23 -3
- package/dist/src/public/channels/slack/api.js +1 -1
- package/dist/src/public/channels/slack/app-manifest.d.ts +2 -0
- package/dist/src/public/channels/slack/app-manifest.js +1 -1
- package/dist/src/public/channels/slack/auth.d.ts +2 -1
- package/dist/src/public/channels/slack/auth.js +1 -1
- package/dist/src/public/channels/slack/code-channel.d.ts +42 -0
- package/dist/src/public/channels/slack/code-channel.js +1 -0
- package/dist/src/public/channels/slack/defaults.d.ts +7 -3
- package/dist/src/public/channels/slack/defaults.js +3 -3
- package/dist/src/public/channels/slack/hitl.d.ts +7 -17
- package/dist/src/public/channels/slack/hitl.js +1 -1
- package/dist/src/public/channels/slack/index.d.ts +4 -3
- package/dist/src/public/channels/slack/index.js +1 -1
- package/dist/src/public/channels/slack/interaction-cards.d.ts +0 -2
- package/dist/src/public/channels/slack/interaction-cards.js +1 -1
- package/dist/src/public/channels/slack/interactions.js +1 -1
- package/dist/src/public/channels/slack/open-code-channel.d.ts +30 -0
- package/dist/src/public/channels/slack/open-code-channel.js +1 -0
- package/dist/src/public/channels/slack/private-approval-delivery.d.ts +16 -4
- package/dist/src/public/channels/slack/private-approval-delivery.js +1 -1
- package/dist/src/public/channels/slack/renderers.d.ts +58 -6
- package/dist/src/public/channels/slack/renderers.js +1 -1
- package/dist/src/public/channels/slack/reply-delivery.d.ts +4 -0
- package/dist/src/public/channels/slack/reply-delivery.js +1 -1
- package/dist/src/public/channels/slack/request-card-render.d.ts +45 -0
- package/dist/src/public/channels/slack/request-card-render.js +1 -0
- package/dist/src/public/channels/slack/request-cards.d.ts +35 -0
- package/dist/src/public/channels/slack/request-cards.js +3 -0
- package/dist/src/public/channels/slack/sign-in-cancel.d.ts +3 -5
- package/dist/src/public/channels/slack/sign-in-cancel.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.d.ts +109 -22
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/channels/slack/task-card.d.ts +3 -3
- package/dist/src/public/channels/slack/task-card.js +1 -1
- package/dist/src/public/channels/slack/thread-status.js +1 -1
- package/dist/src/public/channels/teams/api.js +1 -1
- package/dist/src/public/channels/teams/defaults.js +1 -1
- package/dist/src/public/channels/teams/teamsChannel.js +1 -1
- package/dist/src/public/channels/teams/verify.d.ts +9 -5
- package/dist/src/public/channels/teams/verify.js +1 -1
- package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
- package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
- package/dist/src/public/nuxt/module.js +1 -1
- package/dist/src/public/schedules/subscription.d.ts +10 -1
- package/dist/src/reactions/kinds/model.js +1 -1
- package/dist/src/reactions/kinds/subagent.js +1 -1
- package/dist/src/runtime/agent/resolve-model.d.ts +3 -4
- package/dist/src/runtime/agent/resolve-model.js +1 -1
- package/dist/src/runtime/loaders/artifact-paths.d.ts +1 -0
- package/dist/src/runtime/loaders/artifact-paths.js +1 -1
- package/dist/src/runtime/loaders/bundled-artifacts.d.ts +2 -0
- package/dist/src/runtime/loaders/bundled-artifacts.js +1 -1
- package/dist/src/runtime/loaders/model-metadata.d.ts +4 -0
- package/dist/src/runtime/loaders/model-metadata.js +1 -0
- package/dist/src/runtime/resolve-agent.js +1 -1
- package/dist/src/runtime/sessions/compiled-agent-cache.d.ts +3 -0
- package/dist/src/runtime/sessions/compiled-agent-cache.js +1 -1
- package/dist/src/runtime/subagents/dynamic-agent-config.d.ts +2 -2
- package/dist/src/runtime/subagents/dynamic-agent-config.js +1 -1
- package/dist/src/runtime/subagents/workflow.js +1 -1
- package/dist/src/sandbox/provider.d.ts +2 -0
- package/dist/src/setup/flows/model-source-change.js +1 -1
- package/dist/src/setup/index.d.ts +1 -1
- package/dist/src/setup/primitives/index.d.ts +1 -1
- package/dist/src/setup/primitives/pm/run.d.ts +0 -2
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/shared/agent-definition.d.ts +0 -1
- package/dist/src/shared/channel-definition.d.ts +4 -4
- package/dist/src/shared/sandbox-session.d.ts +4 -0
- package/dist/src/subagents/adapter.js +1 -1
- package/dist/src/subagents/parent-notification.js +1 -1
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/tools/definition.d.ts +21 -0
- package/dist/src/tools/provided/ask-question-workflow.js +1 -1
- package/dist/src/tools/provided/sleep-workflow.js +1 -1
- package/dist/src/tools/workflow-definition.d.ts +4 -4
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/agent-config.md +5 -4
- package/docs/channels/custom.mdx +16 -3
- package/docs/channels/eve.mdx +2 -0
- package/docs/channels/linq.mdx +1 -1
- package/docs/channels/slack.mdx +185 -18
- package/docs/channels/teams.mdx +6 -2
- package/docs/concepts/default-harness.md +6 -0
- package/docs/concepts/upgrade-to-v27-events.md +2 -2
- package/docs/evals/judge.mdx +13 -0
- package/docs/experimental/dynamic-schedules.mdx +2 -2
- package/docs/guides/client/overview.mdx +24 -2
- package/docs/guides/remote-agents.md +8 -0
- package/docs/patterns/fork-conversations-into-new-threads.md +159 -0
- package/docs/patterns/meta.json +1 -0
- package/docs/reference/cli.md +1 -1
- package/docs/sandbox/custom-providers.mdx +1 -1
- package/docs/sandbox/index.mdx +1 -1
- package/docs/schedules.mdx +1 -1
- package/docs/tools/overview.mdx +34 -0
- package/docs/tools/workflows.mdx +51 -5
- package/package.json +2 -2
- package/dist/src/compiled/_chunks/node/token-Bedbhv5z.js +0 -1
- package/dist/src/compiled/_chunks/node/token-util-DpJNusVS.js +0 -1
- package/dist/src/compiled/_chunks/node/token-util-DwHQ2a3c.js +0 -1
- package/dist/src/compiled/_chunks/node/version-C__MqbLM.js +0 -1
- package/dist/src/public/channels/slack/approval-cards.d.ts +0 -25
- package/dist/src/public/channels/slack/approval-cards.js +0 -2
- package/dist/src/runtime/agent/model-catalog.d.ts +0 -10
- package/dist/src/runtime/agent/model-catalog.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{internalSession}from"#channel/session.js";import{MAX_DELIVERY_IDEMPOTENCY_KEY_LENGTH}from"#channel/delivery-idempotency.js";import{isAnswer}from"#shared/input.js";import{hasInternalRefScheme}from"#internal/attachments/url-refs.js";import{HEARTBEAT_RECORD,LEASE_ENDED_RECORD,STREAM_ENDED_RECORD}from"#protocol/session-events/envelope.js";import{EVE_MESSAGE_STREAM_CONTENT_TYPE,EVE_MESSAGE_STREAM_FORMAT,EVE_MESSAGE_STREAM_VERSION,EVE_SESSION_ID_HEADER,EVE_STREAM_FORMAT_HEADER,EVE_STREAM_TAIL_INDEX_HEADER,EVE_STREAM_VERSION_HEADER}from"#protocol/session-http.js";import{isV26Line}from"#protocol/v26-lines.js";import{parseJsonObject}from"#shared/json.js";import{sessionCommandErrorResponse}from"#eve-channel/support.js";import{isExpiredWorkflowRunError,isMissingWorkflowRunError}from"#internal/workflow/is-inactive-workflow-run-error.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation}from"#public/channels/upload-policy.js";import{REMOTE_AGENT_PROTOCOL_MISMATCH,REMOTE_AGENT_PROTOCOL_VERSION,readRemoteAgentProtocolVersion,servesRemoteAgentCaller}from"#protocol/remote-agent-protocol.js";import{parseToolStubs}from"#tool-stubs/rules.js";import{MAX_MESSAGE_PARTS}from"#shared/message-content.js";import{v26LineStream}from"#execution/v26-history.js";import{parseSessionCallback}from"#channel/session-callback.js";import{parseTurnPolicyField}from"#eve-channel/turn-policy-request.js";import{validateMessageFreeCreate}from"#eve-channel/create-request.js";function rejectUnknownFields(e,t){let n=[];for(let r in e)if(Object.hasOwn(e,r)&&!t.includes(r)&&(n.push(r.length>128?`${r.slice(0,128)}…`:r),n.length===9))break;if(n.length===0)return;let r=n.slice(0,8).sort().map(e=>`'${JSON.stringify(e).slice(1,-1).replaceAll(`'`,`\\'`)}'`),i=n.length>8?` (additional unknown fields omitted)`:``;return Response.json({ok:!1,error:`Unknown field${n.length===1?``:`s`} ${r.join(`, `)}${i}. Accepted fields: ${t.length===0?`(none)`:t.join(`, `)}.`},{status:400})}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=e.callback===void 0?void 0:parseProtocolVersionField(e.protocolVersion);if(t instanceof Response)return t;let n=[`message`,`clientContext`,`outputSchema`,`operationId`,`callback`,`protocolVersion`,`capabilities`,`stubs`,`forwardedPrincipal`];e.callback!==void 0&&n.push(`activityObserver`);let r=rejectUnknownFields(e,n);if(r!==void 0)return r;let i=e,a=parseMessageField(i.message);if(a instanceof Response)return a;let o=parseClientContextField(i.clientContext);if(o instanceof Response)return o;let s=parseCallbackField(i.callback);if(s instanceof Response)return s;let c=parseCapabilitiesField(i.capabilities);if(c instanceof Response)return c;let l=parseOutputSchemaField(i.outputSchema);if(l instanceof Response)return l;let u=validateMessageFreeCreate({callback:s,hasClientContext:i.clientContext!==void 0,hasMessageField:`message`in i,message:a,outputSchema:l});if(u!==void 0)return u;let d=i.operationId;if(d!==void 0&&(typeof d!=`string`||!d))return Response.json({error:`Expected 'operationId' to be a non-empty string.`,ok:!1},{status:400});let f={callback:s,capabilities:c,context:o,outputSchema:l};if(i.stubs!==void 0)try{f.stubs=parseToolStubs(i.stubs)}catch(e){return Response.json({ok:!1,error:e instanceof Error?e.message:`Invalid tool stubs.`},{status:400})}return a!==void 0&&(f.message=a),typeof d==`string`&&(f.operationId=d),t!==void 0&&(f.protocolVersion=t),f}function parseSessionMessageBody(e){let t=[`message`,`answers`,`clientContext`,`outputSchema`,`turnPolicy`,`callback`,`forwardedPrincipal`,`idempotencyKey`];e.callback!==void 0&&t.push(`activityObserver`);let n=rejectUnknownFields(e,t);if(n!==void 0)return n;let r=e,i=parseIdempotencyKeyField(r.idempotencyKey);if(i instanceof Response)return i;let a=parseMessageField(r.message);if(a instanceof Response)return a;let o=parseCallbackField(r.callback);if(o instanceof Response)return o;let s=parseAnswers$1(r.answers);if(s instanceof Response)return s;let c=parseClientContextField(r.clientContext);if(c instanceof Response)return c;let l=parseOutputSchemaField(r.outputSchema);if(l instanceof Response)return l;let u=parseTurnPolicyField(r.turnPolicy);return u instanceof Response?u:a===void 0&&s===void 0?Response.json({error:`Expected a non-empty 'message' or a non-empty 'answers' array.`,ok:!1},{status:400}):a!==void 0&&s!==void 0?Response.json({error:`'message' and 'answers' are mutually exclusive.`,ok:!1},{status:400}):{callback:o,message:a,answers:s,context:c,outputSchema:l,turnPolicy:u,...i!==void 0&&{idempotencyKey:i}}}function parseIdempotencyKeyField(e){if(e!==void 0)return typeof e!=`string`||e.length===0||e.length>MAX_DELIVERY_IDEMPOTENCY_KEY_LENGTH?Response.json({error:`Expected 'idempotencyKey' to be a nonempty string of at most ${String(MAX_DELIVERY_IDEMPOTENCY_KEY_LENGTH)} characters.`,ok:!1},{status:400}):e}async function parseCancelTurnBody(e){let t=await parseOptionalJsonRequest(e);if(t instanceof Response)return t;let n=rejectUnknownFields(t,[`turnId`]);if(n!==void 0)return n;let r=t.turnId;return r!=null&&(typeof r!=`string`||r.length===0)?Response.json({error:`Expected 'turnId' to be a non-empty string or null.`,ok:!1},{status:400}):r===null||typeof r==`string`?{turnId:r}:{}}async function parseResetBody(e){let t=await parseOptionalJsonRequest(e);if(t instanceof Response)return t;let n=rejectUnknownFields(t,[`reason`]);if(n!==void 0)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:rejectUnknownFields(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 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=n===void 0||n>=0?internalSession(t).getLineStream({follow:r,startIndex:n??0}):void 0;a?.catch(()=>{});let o=startedOnEarlierEve(t),s;if(i||a===void 0)try{s=await internalSession(t).getStreamTailIndex()}catch(e){throw a?.then(e=>e.cancel()).catch(()=>{}),e}let c=a===void 0?Math.max(0,(s??-1)+1+(n??0)):n??0,l,u=i&&s!==void 0?Math.max(0,s-c+1):void 0;if(await o){a?.then(e=>e.cancel()).catch(()=>{});let e=r&&await internalSession(t).hasRunnableOwner();r&&!e&&(u=void 0),l=v26LineStream(await internalSession(t).getLineStream({follow:e,startIndex:0}),c)}else l=await(a??internalSession(t).getLineStream({follow:r,startIndex:c}));let d=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&&s!==void 0&&d.set(EVE_STREAM_TAIL_INDEX_HEADER,String(s)),new Response(serializeLines(l,e.signal,u),{headers:d})}catch(e){let t=sessionCommandErrorResponse(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})}}async function startedOnEarlierEve(e){let t,n,r=(async()=>{n=(await internalSession(e).getLineStream({follow:!1,startIndex:0})).getReader();let{done:t,value:r}=await n.read();return!t&&isV26Line(r)})(),i=new Promise(e=>{t=setTimeout(()=>e(!1),5e3)});try{return await Promise.race([r,i])}catch{return!1}finally{clearTimeout(t),r.finally(()=>n?.cancel().catch(()=>{})).catch(()=>{})}}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 servesRemoteAgentCaller(t)?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;if(e.length>MAX_MESSAGE_PARTS)return Response.json({ok:!1,error:`Expected at most ${MAX_MESSAGE_PARTS} message parts. Combine text or reduce attachments.`},{status:400});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 parseAnswers$1(e){if(e===void 0)return;if(!Array.isArray(e)||e.length===0)return Response.json({error:`Expected 'answers' to be a non-empty array.`,ok:!1},{status:400});let t=e.filter(isAnswer);return t.length===e.length?t:Response.json({error:`Expected every 'answers' 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 serializeLines(e,t,n){let r=new TextEncoder,record=e=>r.encode(`${JSON.stringify(e)}\n`),i=0,a,o,clearTimers=()=>{clearTimeout(a),clearTimeout(o),a=void 0,o=void 0},scheduleHeartbeat=e=>{clearTimeout(a),a=setTimeout(()=>{try{e.enqueue(record(HEARTBEAT_RECORD)),scheduleHeartbeat(e)}catch{clearTimers()}},1e4)},s=new TransformStream({start(e){if(e.enqueue(record(HEARTBEAT_RECORD)),n===0){e.terminate();return}scheduleHeartbeat(e),o=setTimeout(()=>{clearTimers();try{e.enqueue(record(LEASE_ENDED_RECORD)),e.terminate()}catch{}},6e4)},transform(e,t){t.enqueue(record(e)),i+=1,i===n?(clearTimers(),t.terminate()):scheduleHeartbeat(t)},flush(e){clearTimers(),e.enqueue(record(STREAM_ENDED_RECORD))}});return e.pipeTo(s.writable,{signal:t}).catch(()=>{}).finally(clearTimers),s.readable}export{checkUploadPolicy,createSessionStreamResponse,deriveOperationContinuationToken,parseCancelTurnBody,parseCreateBody,parseIncludeTailIndex,parseOptionalJsonRequest,parseResetBody,parseSessionControlBody,parseSessionMessageBody,parseStartIndex,requireSessionId};
|
|
1
|
+
import{internalSession}from"#channel/session.js";import{MAX_DELIVERY_IDEMPOTENCY_KEY_LENGTH}from"#channel/delivery-idempotency.js";import{isAnswer}from"#shared/input.js";import{hasInternalRefScheme}from"#internal/attachments/url-refs.js";import{HEARTBEAT_RECORD,LEASE_ENDED_RECORD,STREAM_ENDED_RECORD}from"#protocol/session-events/envelope.js";import{EVE_MESSAGE_STREAM_CONTENT_TYPE,EVE_MESSAGE_STREAM_FORMAT,EVE_MESSAGE_STREAM_VERSION,EVE_SESSION_ID_HEADER,EVE_STREAM_FORMAT_HEADER,EVE_STREAM_TAIL_INDEX_HEADER,EVE_STREAM_VERSION_HEADER}from"#protocol/session-http.js";import{isV26Line}from"#protocol/v26-lines.js";import{parseJsonObject}from"#shared/json.js";import{sessionCommandErrorResponse}from"#eve-channel/support.js";import{isExpiredWorkflowRunError,isMissingWorkflowRunError}from"#internal/workflow/is-inactive-workflow-run-error.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation}from"#public/channels/upload-policy.js";import{REMOTE_AGENT_PROTOCOL_MISMATCH,REMOTE_AGENT_PROTOCOL_VERSION,readRemoteAgentProtocolVersion,servesRemoteAgentCaller}from"#protocol/remote-agent-protocol.js";import{parseToolStubs}from"#tool-stubs/rules.js";import{MAX_MESSAGE_PARTS}from"#shared/message-content.js";import{v26LineStream}from"#execution/v26-history.js";import{parseSessionCallback}from"#channel/session-callback.js";import{parseTurnPolicyField}from"#eve-channel/turn-policy-request.js";import{validateMessageFreeCreate}from"#eve-channel/create-request.js";function rejectUnknownFields(e,t){let n=[];for(let r in e)if(Object.hasOwn(e,r)&&!t.includes(r)&&(n.push(r.length>128?`${r.slice(0,128)}…`:r),n.length===9))break;if(n.length===0)return;let r=n.slice(0,8).sort().map(e=>`'${JSON.stringify(e).slice(1,-1).replaceAll(`'`,`\\'`)}'`),i=n.length>8?` (additional unknown fields omitted)`:``;return Response.json({ok:!1,error:`Unknown field${n.length===1?``:`s`} ${r.join(`, `)}${i}. Accepted fields: ${t.length===0?`(none)`:t.join(`, `)}.`},{status:400})}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=e.callback===void 0?void 0:parseProtocolVersionField(e.protocolVersion);if(t instanceof Response)return t;let n=[`message`,`clientContext`,`outputSchema`,`operationId`,`callback`,`protocolVersion`,`capabilities`,`stubs`,`forwardedPrincipal`];e.callback!==void 0&&n.push(`activityObserver`);let r=rejectUnknownFields(e,n);if(r!==void 0)return r;let i=e,a=parseMessageField(i.message);if(a instanceof Response)return a;let o=parseClientContextField(i.clientContext);if(o instanceof Response)return o;let s=parseCallbackField(i.callback);if(s instanceof Response)return s;let c=parseCapabilitiesField(i.capabilities);if(c instanceof Response)return c;let l=parseOutputSchemaField(i.outputSchema);if(l instanceof Response)return l;let u=validateMessageFreeCreate({callback:s,hasClientContext:i.clientContext!==void 0,hasMessageField:`message`in i,message:a,outputSchema:l});if(u!==void 0)return u;let d=i.operationId;if(d!==void 0&&(typeof d!=`string`||!d))return Response.json({error:`Expected 'operationId' to be a non-empty string.`,ok:!1},{status:400});let f={callback:s,capabilities:c,context:o,outputSchema:l};if(i.stubs!==void 0)try{f.stubs=parseToolStubs(i.stubs)}catch(e){return Response.json({ok:!1,error:e instanceof Error?e.message:`Invalid tool stubs.`},{status:400})}return a!==void 0&&(f.message=a),typeof d==`string`&&(f.operationId=d),t!==void 0&&(f.protocolVersion=t),f}function parseSessionMessageBody(e){let t=[`inbox`,`message`,`answers`,`clientContext`,`outputSchema`,`turnPolicy`,`callback`,`forwardedPrincipal`,`idempotencyKey`];e.callback!==void 0&&t.push(`activityObserver`);let n=rejectUnknownFields(e,t);if(n!==void 0)return n;let r=e,i=parseIdempotencyKeyField(r.idempotencyKey);if(i instanceof Response)return i;let a=parseMessageField(r.message);if(a instanceof Response)return a;let o=parseCallbackField(r.callback);if(o instanceof Response)return o;let s=parseAnswers$1(r.answers);if(s instanceof Response)return s;let c=parseClientContextField(r.clientContext);if(c instanceof Response)return c;let l=parseOutputSchemaField(r.outputSchema);if(l instanceof Response)return l;let u=parseTurnPolicyField(r.turnPolicy);return u instanceof Response?u:a===void 0&&s===void 0?Response.json({error:`Expected a non-empty 'message' or a non-empty 'answers' array.`,ok:!1},{status:400}):a!==void 0&&s!==void 0?Response.json({error:`'message' and 'answers' are mutually exclusive.`,ok:!1},{status:400}):{inbox:typeof r.inbox==`string`?r.inbox:void 0,callback:o,message:a,answers:s,context:c,outputSchema:l,turnPolicy:u,...i!==void 0&&{idempotencyKey:i}}}function parseIdempotencyKeyField(e){if(e!==void 0)return typeof e!=`string`||e.length===0||e.length>MAX_DELIVERY_IDEMPOTENCY_KEY_LENGTH?Response.json({error:`Expected 'idempotencyKey' to be a nonempty string of at most ${String(MAX_DELIVERY_IDEMPOTENCY_KEY_LENGTH)} characters.`,ok:!1},{status:400}):e}async function parseCancelTurnBody(e){let t=await parseOptionalJsonRequest(e);if(t instanceof Response)return t;let n=rejectUnknownFields(t,[`turnId`]);if(n!==void 0)return n;let r=t.turnId;return r!=null&&(typeof r!=`string`||r.length===0)?Response.json({error:`Expected 'turnId' to be a non-empty string or null.`,ok:!1},{status:400}):r===null||typeof r==`string`?{turnId:r}:{}}async function parseResetBody(e){let t=await parseOptionalJsonRequest(e);if(t instanceof Response)return t;let n=rejectUnknownFields(t,[`reason`]);if(n!==void 0)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:rejectUnknownFields(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 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=n===void 0||n>=0?internalSession(t).getLineStream({follow:r,startIndex:n??0}):void 0;a?.catch(()=>{});let o=startedOnEarlierEve(t),s;if(i||a===void 0)try{s=await internalSession(t).getStreamTailIndex()}catch(e){throw a?.then(e=>e.cancel()).catch(()=>{}),e}let c=a===void 0?Math.max(0,(s??-1)+1+(n??0)):n??0,l,u=i&&s!==void 0?Math.max(0,s-c+1):void 0;if(await o){a?.then(e=>e.cancel()).catch(()=>{});let e=r&&await internalSession(t).hasRunnableOwner();r&&!e&&(u=void 0),l=v26LineStream(await internalSession(t).getLineStream({follow:e,startIndex:0}),c)}else l=await(a??internalSession(t).getLineStream({follow:r,startIndex:c}));let d=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&&s!==void 0&&d.set(EVE_STREAM_TAIL_INDEX_HEADER,String(s)),new Response(serializeLines(l,e.signal,u),{headers:d})}catch(e){let t=sessionCommandErrorResponse(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})}}async function startedOnEarlierEve(e){let t,n,r=(async()=>{n=(await internalSession(e).getLineStream({follow:!1,startIndex:0})).getReader();let{done:t,value:r}=await n.read();return!t&&isV26Line(r)})(),i=new Promise(e=>{t=setTimeout(()=>e(!1),5e3)});try{return await Promise.race([r,i])}catch{return!1}finally{clearTimeout(t),r.finally(()=>n?.cancel().catch(()=>{})).catch(()=>{})}}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 servesRemoteAgentCaller(t)?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;if(e.length>MAX_MESSAGE_PARTS)return Response.json({ok:!1,error:`Expected at most ${MAX_MESSAGE_PARTS} message parts. Combine text or reduce attachments.`},{status:400});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 parseAnswers$1(e){if(e===void 0)return;if(!Array.isArray(e)||e.length===0)return Response.json({error:`Expected 'answers' to be a non-empty array.`,ok:!1},{status:400});let t=e.filter(isAnswer);return t.length===e.length?t:Response.json({error:`Expected every 'answers' 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 serializeLines(e,t,n){let r=new TextEncoder,record=e=>r.encode(`${JSON.stringify(e)}\n`),i=0,a,o,clearTimers=()=>{clearTimeout(a),clearTimeout(o),a=void 0,o=void 0},scheduleHeartbeat=e=>{clearTimeout(a),a=setTimeout(()=>{try{e.enqueue(record(HEARTBEAT_RECORD)),scheduleHeartbeat(e)}catch{clearTimers()}},1e4)},s=new TransformStream({start(e){if(e.enqueue(record(HEARTBEAT_RECORD)),n===0){e.terminate();return}scheduleHeartbeat(e),o=setTimeout(()=>{clearTimers();try{e.enqueue(record(LEASE_ENDED_RECORD)),e.terminate()}catch{}},6e4)},transform(e,t){t.enqueue(record(e)),i+=1,i===n?(clearTimers(),t.terminate()):scheduleHeartbeat(t)},flush(e){clearTimers(),e.enqueue(record(STREAM_ENDED_RECORD))}});return e.pipeTo(s.writable,{signal:t}).catch(()=>{}).finally(clearTimers),s.readable}export{checkUploadPolicy,createSessionStreamResponse,deriveOperationContinuationToken,parseCancelTurnBody,parseCreateBody,parseIncludeTailIndex,parseOptionalJsonRequest,parseResetBody,parseSessionControlBody,parseSessionMessageBody,parseStartIndex,requireSessionId};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{SessionNotActiveError}from"#channel/session-not-active-error.js";import{SessionStrandedError}from"#channel/session-stranded-error.js";import{EVE_SESSION_ID_HEADER}from"#protocol/session-http.js";import{defaultEveAuth}from"#eve-channel/types.js";import{workflowEntryReference}from"#execution/workflow-runtime.js";const log=createLogger(`eve.channel`);function healthResponse(){return Response.json({ok:!0,status:`ready`,workflowId:workflowEntryReference.workflowId})}function sessionCommandErrorResponse(e){if(SessionNotActiveError.is(e))return Response.json({ok:!1,code:e.retryable?`session_not_ready`:`session_not_active`,error:e.retryable?`The session is not ready to accept messages yet.`:`The session is no longer active.`},{headers:{"cache-control":`no-store`},status:409});if(!SessionStrandedError.is(e))return;let t={code:`session_stranded`,error:`This session is no longer available.`,ok:!1};return e.owner.eveVersion!==void 0&&(t.eveVersion=e.owner.eveVersion),Response.json(t,{headers:{"cache-control":`no-store`},status:409})}function deliveryResponse(e){return Response.json({ok:!0,sessionId:e.sessionId,deliveryId:e.deliveryId},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:e.sessionId},status:202})}async function findRemoteAgentBinding(e){let t=await e.parent.getChildBinding?.(e.childSessionId);if(t===void 0||t.callId!==e.callId||t.streamPath!==e.childStreamPath)return;let n={name:t.name,url:t.url};return t.resolverId!==void 0&&(n.resolverId=t.resolverId),t.dynamicBinding!==void 0&&(n.dynamicBinding=t.dynamicBinding),t.earlierProtocol!==void 0&&(n.earlierProtocol=t.earlierProtocol),n}async function resolveOnMessage(e){let t=e.config.onMessage??defaultOnMessage,n;try{let r={caller:e.auth,clientContext:e.clientContext,request:e.request};if(n=await t({eve:e.sessionId===void 0?e.invocation===void 0?r:{...r,invocation:e.invocation}:{...r,sessionId:e.sessionId}},e.message),n==null)throw TypeError(`eveChannel onMessage must return an auth result.`)}catch(t){let n=logError(log,`onMessage handler failed`,t,{sessionId:e.sessionId});return Response.json({error:`onMessage handler failed.`,errorId:n,ok:!1},{status:500})}return{auth:n.auth,clientContext:resolveTurnClientContext(n.clientContext,e.clientContext),context:n.context,history:n.history,title:n.title}}function resolveTurnClientContext(e,t){let n=e===void 0?toContextEntries(t).map(e=>`Client context:
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{SessionNotActiveError}from"#channel/session-not-active-error.js";import{SessionStrandedError}from"#channel/session-stranded-error.js";import{EVE_SESSION_ID_HEADER}from"#protocol/session-http.js";import{defaultEveAuth}from"#eve-channel/types.js";import{workflowEntryReference}from"#execution/workflow-runtime.js";const log=createLogger(`eve.channel`);function healthResponse(){return Response.json({ok:!0,status:`ready`,workflowId:workflowEntryReference.workflowId})}function sessionCommandErrorResponse(e){if(SessionNotActiveError.is(e))return Response.json({ok:!1,code:e.retryable?`session_not_ready`:`session_not_active`,error:e.retryable?`The session is not ready to accept messages yet.`:`The session is no longer active.`},{headers:{"cache-control":`no-store`},status:409});if(!SessionStrandedError.is(e))return;let t={code:`session_stranded`,error:`This session is no longer available.`,ok:!1};return e.owner.eveVersion!==void 0&&(t.eveVersion=e.owner.eveVersion),Response.json(t,{headers:{"cache-control":`no-store`},status:409})}function deliveryResponse(e){return Response.json({ok:!0,sessionId:e.sessionId,deliveryId:e.deliveryId,inbox:e.inbox},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:e.sessionId},status:202})}async function findRemoteAgentBinding(e){let t=await e.parent.getChildBinding?.(e.childSessionId);if(t===void 0||t.callId!==e.callId||t.streamPath!==e.childStreamPath)return;let n={name:t.name,url:t.url};return t.resolverId!==void 0&&(n.resolverId=t.resolverId),t.dynamicBinding!==void 0&&(n.dynamicBinding=t.dynamicBinding),t.earlierProtocol!==void 0&&(n.earlierProtocol=t.earlierProtocol),n}async function resolveOnMessage(e){let t=e.config.onMessage??defaultOnMessage,n;try{let r={caller:e.auth,clientContext:e.clientContext,request:e.request};if(n=await t({eve:e.sessionId===void 0?e.invocation===void 0?r:{...r,invocation:e.invocation}:{...r,sessionId:e.sessionId}},e.message),n==null)throw TypeError(`eveChannel onMessage must return an auth result.`)}catch(t){let n=logError(log,`onMessage handler failed`,t,{sessionId:e.sessionId});return Response.json({error:`onMessage handler failed.`,errorId:n,ok:!1},{status:500})}return{auth:n.auth,clientContext:resolveTurnClientContext(n.clientContext,e.clientContext),context:n.context,history:n.history,title:n.title}}function resolveTurnClientContext(e,t){let n=e===void 0?toContextEntries(t).map(e=>`Client context:
|
|
2
2
|
${e}`):toContextEntries(e);return n.length===0?void 0:n}function toContextEntries(e){return e===void 0||e===``?[]:typeof e==`string`?[e]:Array.isArray(e)?e:[JSON.stringify(e)]}function defaultOnMessage(e){return{auth:defaultEveAuth(e)}}export{deliveryResponse,findRemoteAgentBinding,healthResponse,resolveOnMessage,resolveTurnClientContext,sessionCommandErrorResponse};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ChannelInstrumentationProjection, SessionCapabilities, SessionParent, SessionTraceRoot } from "#channel/types.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type LocalDevRequestProvenance } from "#context/keys.js";
|
|
3
3
|
import { type StubScope } from "#tool-stubs/types.js";
|
|
4
4
|
import { type SessionSchedule } from "#context/session-schedule.js";
|
|
5
5
|
import type { DynamicSubagentSelections } from "#execution/agent-sessions/target.js";
|
|
@@ -28,9 +28,13 @@ export interface AgentSessionContext {
|
|
|
28
28
|
readonly capabilities?: SessionCapabilities;
|
|
29
29
|
readonly schedule?: SessionSchedule;
|
|
30
30
|
readonly channelMetadata?: ChannelInstrumentationProjection;
|
|
31
|
+
/** The calling session's address on its channel, which `ctx.channel.continuationToken` reads. */
|
|
32
|
+
readonly continuationToken?: string;
|
|
31
33
|
readonly conversation?: ConversationContext;
|
|
32
34
|
/** Dynamic agents the calling turn selected, by node id. */
|
|
33
35
|
readonly dynamicSelections: DynamicSubagentSelections;
|
|
36
|
+
/** Whether a parent, local or remote, delegated the calling session. */
|
|
37
|
+
readonly delegated?: boolean;
|
|
34
38
|
readonly localDevRequest?: LocalDevRequestProvenance;
|
|
35
39
|
/** The calling session, turn, and tool call, recorded as each session's lineage. */
|
|
36
40
|
readonly parent: SessionParent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readSerializedSessionSchedule}from"#context/session-schedule.js";import{STUB_CONTEXT_KEY}from"#tool-stubs/types.js";import{serializeDurableCompiledArtifactsSource}from"#runtime/durable-compiled-artifacts-source.js";import{resolveToolCallAgentTrace}from"#tracing/eve/agent-invocation-coordinator.js";function captureAgentSessionContext(e,t){let{batch:n,session:r}=e;return{agents:e.workflowAgents,toolStubs:e.serializedContext[STUB_CONTEXT_KEY],bundle:{nodeId:e.bundle.nodeId,source:serializeDurableCompiledArtifactsSource(e.bundle.compiledArtifactsSource)},capabilities:e.capabilities,schedule:readSerializedSessionSchedule(e.serializedContext),channelMetadata:e.channelMetadata,conversation:e.inheritedConversation,dynamicSelections:e.dynamicSubagentSelections,localDevRequest:e.localDevRequest,parent:{callId:t,rootSessionId:r.rootSessionId??r.sessionId,sessionId:r.sessionId,turn:{id:n.event.turnId,sequence:n.event.sequence}},sandbox:{sessionId:e.sandboxSessionId,state:e.sandboxState},traceRoot:e.traceRoot,trace:resolveToolCallAgentTrace({callId:t,conversation:e.inheritedConversation,serializedContext:e.serializedContext,sessionId:r.sessionId,turnId:n.event.turnId})}}export{captureAgentSessionContext};
|
|
1
|
+
import{ContinuationTokenKey}from"#context/keys.js";import{readSerializedSessionSchedule}from"#context/session-schedule.js";import{STUB_CONTEXT_KEY}from"#tool-stubs/types.js";import{hasDelegatedSessionContext}from"#execution/delegated-session-context.js";import{serializeDurableCompiledArtifactsSource}from"#runtime/durable-compiled-artifacts-source.js";import{resolveToolCallAgentTrace}from"#tracing/eve/agent-invocation-coordinator.js";function captureAgentSessionContext(e,t){let{batch:n,session:r}=e;return{agents:e.workflowAgents,toolStubs:e.serializedContext[STUB_CONTEXT_KEY],bundle:{nodeId:e.bundle.nodeId,source:serializeDurableCompiledArtifactsSource(e.bundle.compiledArtifactsSource)},capabilities:e.capabilities,schedule:readSerializedSessionSchedule(e.serializedContext),channelMetadata:e.channelMetadata,continuationToken:e.serializedContext[ContinuationTokenKey.name],conversation:e.inheritedConversation,dynamicSelections:e.dynamicSubagentSelections,delegated:hasDelegatedSessionContext(e.serializedContext),localDevRequest:e.localDevRequest,parent:{callId:t,rootSessionId:r.rootSessionId??r.sessionId,sessionId:r.sessionId,turn:{id:n.event.turnId,sequence:n.event.sequence}},sandbox:{sessionId:e.sandboxSessionId,state:e.sandboxState},traceRoot:e.traceRoot,trace:resolveToolCallAgentTrace({callId:t,conversation:e.inheritedConversation,serializedContext:e.serializedContext,sessionId:r.sessionId,turnId:n.event.turnId})}}export{captureAgentSessionContext};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{SessionStrandedError}from"#channel/session-stranded-error.js";import{sessionCommandHookToken,sessionInboxHookToken}from"#execution/session-inbox/address.js";import{ContextContainer,contextStorage}from"#context/container.js";import{createEveCallbackRoutePath}from"#protocol/routes.js";import{toErrorMessage}from"#shared/errors.js";import{resumeHook}from"#internal/workflow/runtime.js";import{agentDelegation}from"#tracing/eve/delegation.js";import{createWorkflowRuntime,dispatchWorkflowSessionCommand,resolveContinuation,waitForCommandHookOwner,waitForSessionInbox}from"#execution/workflow-runtime.js";import{resolveDurableCompiledArtifactsSource}from"#runtime/durable-compiled-artifacts-source.js";import{FatalError,getStepMetadata,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{createWorkflowCallbackUrl,resolveWorkflowCallbackBaseUrl}from"#execution/workflow-callback-url.js";import{remoteAgentCredentials}from"#execution/agent-sessions/remote-credentials.js";import{resolveAgentAction,resolveAgentStartTarget}from"#execution/agent-sessions/target.js";import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{InvalidRuntimeModelSelectionError,resolveRuntimeModelSelection}from"#runtime/agent/resolve-model.js";import{cancelRemoteAgentTurn,continueRemoteAgentSession,resetRemoteAgentSession,resolveRemoteAgentForAction,startRemoteAgentSession}from"#execution/agent-sessions/remote.js";import{buildSubagentRunInput}from"#subagents/tool.js";import{resolveConversationId}from"#shared/conversation-identity.js";import{stubToolPath}from"#tool-stubs/target.js";const log=createLogger(`execution.agent-sessions`),RUN_FINISHED_REASON=`The workflow run that opened this session finished.`;async function openAgentSessionStep(e){"use step";let{context:t}=e,n=await loadAgentSessionBundle(t),r=resolveAgentAction({bundle:n,callId:t.parent.callId,dynamicSelections:t.dynamicSelections,input:{message:e.message,outputSchema:e.outputSchema,target:e.name}}),i=resolveAgentStartTarget({action:r,bundle:n,dynamicSelections:t.dynamicSelections,isRootSession:t.parent.rootSessionId===t.parent.sessionId});if(e.model!==void 0&&i.kind===`remote`)throw new FatalError(`ctx.agent("${e.name}", { model }) cannot override a remote agent's model. Configure the model on the receiving agent.`);let a=e.model===void 0?void 0:await normalizeRuntimeOverrides(e.name
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{SessionStrandedError}from"#channel/session-stranded-error.js";import{sessionCommandHookToken,sessionInboxHookToken}from"#execution/session-inbox/address.js";import{ContextContainer,contextStorage}from"#context/container.js";import{createEveCallbackRoutePath}from"#protocol/routes.js";import{toErrorMessage}from"#shared/errors.js";import{resumeHook}from"#internal/workflow/runtime.js";import{agentDelegation}from"#tracing/eve/delegation.js";import{createWorkflowRuntime,dispatchWorkflowSessionCommand,resolveContinuation,waitForCommandHookOwner,waitForSessionInbox}from"#execution/workflow-runtime.js";import{resolveDurableCompiledArtifactsSource}from"#runtime/durable-compiled-artifacts-source.js";import{FatalError,getStepMetadata,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{createWorkflowCallbackUrl,resolveWorkflowCallbackBaseUrl}from"#execution/workflow-callback-url.js";import{remoteAgentCredentials}from"#execution/agent-sessions/remote-credentials.js";import{resolveAgentAction,resolveAgentStartTarget}from"#execution/agent-sessions/target.js";import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{InvalidRuntimeModelSelectionError,resolveRuntimeModelSelection}from"#runtime/agent/resolve-model.js";import{cancelRemoteAgentTurn,continueRemoteAgentSession,resetRemoteAgentSession,resolveRemoteAgentForAction,startRemoteAgentSession}from"#execution/agent-sessions/remote.js";import{buildSubagentRunInput}from"#subagents/tool.js";import{resolveConversationId}from"#shared/conversation-identity.js";import{stubToolPath}from"#tool-stubs/target.js";const log=createLogger(`execution.agent-sessions`),RUN_FINISHED_REASON=`The workflow run that opened this session finished.`;async function openAgentSessionStep(e){"use step";let{context:t}=e,n=await loadAgentSessionBundle(t),r=resolveAgentAction({bundle:n,callId:t.parent.callId,dynamicSelections:t.dynamicSelections,input:{message:e.message,outputSchema:e.outputSchema,target:e.name}}),i=resolveAgentStartTarget({action:r,bundle:n,dynamicSelections:t.dynamicSelections,isRootSession:t.parent.rootSessionId===t.parent.sessionId});if(e.model!==void 0&&i.kind===`remote`)throw new FatalError(`ctx.agent("${e.name}", { model }) cannot override a remote agent's model. Configure the model on the receiving agent.`);let a=e.model===void 0?void 0:await normalizeRuntimeOverrides({bundle:n,model:e.model,name:e.name}),o={auth:e.auth,bundle:n,context:t,key:e.key,replyTo:e.replyTo,runtimeOverrides:a};return await agentDelegation.resume({context:t,agentName:r.name},()=>i.kind===`remote`?startRemoteSession({...o,target:i}):startLocalSession({...o,target:i}))}async function normalizeRuntimeOverrides({bundle:e,model:t,name:n}){try{return{model:(await resolveRuntimeModelSelection({durability:`durable`,modelMetadata:e.modelMetadata,selection:t})).reference}}catch(e){throw e instanceof InvalidRuntimeModelSelectionError?new FatalError(`ctx.agent("${n}", { model }) could not resolve the model selection: ${toErrorMessage(e)}`):e}}async function sendAgentSessionMessageStep(e){"use step";let{address:t,context:n}=e;if(t.kind===`remote`){let r=await resolveSessionRemote(n,t);return await continueRemoteAgentSession({auth:e.auth.current,callback:{callId:n.parent.callId,subagentName:t.name,token:e.replyTo,url:createWorkflowCallbackUrl(t.callbackBaseUrl,createEveCallbackRoutePath(e.replyTo))},earlierProtocol:t.earlierProtocol,idempotencyKey:agentDeliveryId(`send`,t.sessionId),message:e.message,outputSchema:e.outputSchema,remote:r,sessionId:t.sessionId})}let r=agentDeliveryId(`send`,t.sessionId),i=await commandLocalSession({...e,address:t},{auth:e.auth.current,schedule:n.schedule,caller:{callId:n.parent.callId,replyTo:{kind:`hook`,token:e.replyTo},subagentName:t.name},kind:`send`,delivery:{channelKind:`subagent`,channelName:`subagent`,deliveryId:r},payload:{message:e.message,outputSchema:e.outputSchema}}).catch(e=>{throw SessionStrandedError.is(e)?Error(`Agent "${t.name}" can no longer receive messages: ${e.message}`,{cause:e}):e});if(i.status!==`accepted`)throw Error(`Agent "${t.name}" can no longer receive messages; its session ended.`);return{deliveryId:r,sessionId:i.sessionId}}async function cancelAgentSessionTurnStep(e){"use step";let{address:t}=e;try{if(t.kind===`remote`){let n=await resolveSessionRemote(e.context,t);await cancelRemoteAgentTurn({remote:n,sessionId:t.sessionId});return}await commandLocalSession({...e,address:t},{kind:`cancel`,deliveryId:agentDeliveryId(`cancel`,t.sessionId)})}catch(e){logError(log,`failed to cancel an agent session turn`,e,{name:t.name,sessionId:t.sessionId})}}async function endAgentSessionsStep(e){"use step";await Promise.all(e.sessions.map(endAgentSession))}async function stopLateAgentSessionStep(e){"use step";if(e.address.kind===`remote`){await endAgentSession(e);return}let{sessionId:t}=e.address;try{await resumeHook(sessionInboxHookToken(sessionCommandHookToken(t)),{kind:`reset`,reason:RUN_FINISHED_REASON,deliveryId:agentDeliveryId(`reset`,t)})}catch(e){logError(log,`could not stop late child; cleanup is best effort`,e,{sessionId:t})}}async function endAgentSession(e){let{address:t,context:n}=e;try{if(t.kind===`remote`){let e=await resolveSessionRemote(n,t);await resetRemoteAgentSession({reason:RUN_FINISHED_REASON,remote:e,sessionId:t.sessionId});return}await commandLocalSession({...e,address:t},{kind:`reset`,reason:RUN_FINISHED_REASON,deliveryId:agentDeliveryId(`reset`,t.sessionId)})}catch(e){logError(log,`failed to end an agent session`,e,{name:t.name,sessionId:t.sessionId})}}async function commandLocalSession(e,t){let{continuationToken:n,sessionId:r}=e.address,i=await dispatchWorkflowSessionCommand({command:t,sessionId:r});if(i.status===`accepted`||i.status===`reset`)return i;let a=await waitForSessionInbox(r)?r:(await resolveContinuation(n))?.sessionId;return a===void 0?i:await dispatchWorkflowSessionCommand({command:t,sessionId:a})}async function startLocalSession(e){let{auth:t,bundle:n,context:r,target:i}=e,{action:a}=i,{childContinuationToken:o,runInput:s}=buildSubagentRunInput({action:a,auth:t.current,capabilities:r.capabilities,schedule:r.schedule,channelMetadata:r.channelMetadata,continuationKey:e.key,graph:n.graph,inheritedConversation:r.conversation,initiatorAuth:t.initiator,parent:createParentContext(r,e.replyTo),sandboxSessionId:r.sandbox.sessionId,selfAgent:i.source.type===`runtime`,session:{continuationToken:e.replyTo,sandboxState:r.sandbox.state,sessionId:r.parent.sessionId},source:i.source}),c=createWorkflowRuntime({agentSessionRuntimeOverrides:e.runtimeOverrides,compiledArtifactsSource:n.compiledArtifactsSource,dynamicSubagentAgentConfig:i.dynamicSubagentAgentConfig,nodeId:a.nodeId}),l=r.toolStubs;l!==void 0&&(l={...l,agentPath:stubToolPath(l,a.name)});let u=`agent-session:${e.key}:initial`,d=(await contextStorage.run(new ContextContainer({localDevRequest:r.localDevRequest}),()=>c.createSession({...s,delivery:{channelKind:`subagent`,channelName:`subagent`,deliveryId:u},toolStubs:l}))).sessionId;return getStepMetadata().attempt>1&&({runId:d}=await waitForCommandHookOwner(sessionInboxHookToken(o))),{address:{continuationToken:o,kind:`local`,name:a.name,nodeId:a.nodeId,sessionId:d},deliveryId:u}}async function startRemoteSession(e){let{auth:t,bundle:n,context:r,target:i}=e,{action:a}=i,o=bindingFor(r,a.nodeId),s=resolveRemoteAgentForAction({credentials:i.dynamicRemoteAgent===void 0?void 0:await credentialsOf(n,a.nodeId,o,{name:a.remoteAgentName,url:i.dynamicRemoteAgent.url}),dynamicRemoteAgent:i.dynamicRemoteAgent,nodeId:a.nodeId,registry:n.subagentRegistry.subagentsByNodeId,remoteAgentName:a.remoteAgentName}),c=resolveWorkflowCallbackBaseUrl(getWorkflowMetadata().url),l=await startRemoteAgentSession({action:a,auth:t.current,callbackBaseUrl:c,capabilities:r.capabilities,initiatorAuth:t.initiator,operationId:`agent-session:${e.key}`,originAudience:r.trace.originAudience,parent:createParentContext(r,e.replyTo),remote:s,session:{continuationToken:e.replyTo}}),u={callbackBaseUrl:c,kind:`remote`,forwardPrincipal:s.forwardPrincipal,name:a.remoteAgentName,nodeId:a.nodeId,resolverId:a.nodeId,sessionId:l.sessionId,url:s.url};return o!==void 0&&(u.dynamicBinding=o),l.earlierProtocol!==void 0&&(u.earlierProtocol=l.earlierProtocol),l.deliveryId===void 0?{address:u}:{address:u,deliveryId:l.deliveryId}}function createParentContext(e,t){return{continuationToken:t,conversationId:e.trace.conversationId??resolveConversationId(e.parent.rootSessionId),lineage:e.parent,originAudience:e.trace.originAudience,traceContext:e.trace.parentTraceContext,traceRoot:e.traceRoot}}async function resolveSessionRemote(e,t){let n=await loadAgentSessionBundle(e),r=e.dynamicSelections[t.nodeId];return{...resolveRemoteAgentForAction({credentials:await credentialsOf(n,t.nodeId,t.dynamicBinding,t),dynamicRemoteAgent:r?.kind===`remote`?r.remoteAgent:void 0,nodeId:t.nodeId,registry:n.subagentRegistry.subagentsByNodeId,remoteAgentName:t.name}),url:t.url}}function bindingFor(e,t){let n=e.dynamicSelections[t];return n?.kind===`remote`&&n.remoteAgent.credentials===!0?n.binding:void 0}async function credentialsOf(e,t,n,r){if(n!==void 0)return await remoteAgentCredentials({binding:n,destination:r,nodeId:t,resolvers:e.subagentRegistry.dynamicResolvers})}async function loadAgentSessionBundle(e){return await getCompiledRuntimeAgentBundle({compiledArtifactsSource:resolveDurableCompiledArtifactsSource(e.bundle.source),nodeId:e.bundle.nodeId})}function agentDeliveryId(e,t){return`agent-session:${getWorkflowMetadata().workflowRunId}:${getStepMetadata().stepId}:${t}:${e}`}export{cancelAgentSessionTurnStep,endAgentSessionsStep,openAgentSessionStep,sendAgentSessionMessageStep,stopLateAgentSessionStep};
|
|
@@ -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.
|
|
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.85.0//runWorkflowProgramTask`;export{runWorkflowProgramTask};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ModelMessage } from "ai";
|
|
2
2
|
import { type SessionProjection } from "#protocol/session-projection.js";
|
|
3
|
-
import {
|
|
3
|
+
import type { DurableSession, DurableSessionState } from "#execution/durable-session-store.js";
|
|
4
4
|
import type { HarnessModelMessage } from "#harness/messages.js";
|
|
5
5
|
export type LegacySession = DurableSession & {
|
|
6
6
|
readonly history: ModelMessage[];
|
|
@@ -19,4 +19,3 @@ export declare function importConversation(session: LegacySession): {
|
|
|
19
19
|
* counted the session spent as the view's usage, so the session's limits keep counting.
|
|
20
20
|
*/
|
|
21
21
|
export declare function importProjection(session: LegacySession): SessionProjection;
|
|
22
|
-
export declare function normalizeHistory(messages: readonly ModelMessage[]): HarnessModelMessage[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isObject}from"#shared/guards.js";import{SESSION_PROJECTION_STATE_KEY}from"#harness/session-machine/view.js";import{DURABLE_SESSION_VERSION}from"#execution/durable-session-
|
|
1
|
+
import{isObject}from"#shared/guards.js";import{SESSION_PROJECTION_STATE_KEY}from"#harness/session-machine/view.js";import{DURABLE_SESSION_VERSION}from"#execution/durable-session-read.js";import{withModelUsage}from"#harness/session-usage.js";import{initialSessionProjection}from"#protocol/session-projection.js";import{normalizeHistory}from"#execution/session/imported-conversation.js";import{usageOf}from"#harness/facts.js";const PRESERVED_FRAMEWORK_STATE=new Set([`eve.harness.sessionRuntimeTokenLimit`]),LEGACY_USAGE_KEY=`eve.harness.turnUsage`,REPORTED_USAGE_KEY=`eve.harness.reportedSessionUsage`;function readLegacySnapshot(e){let t=e.snapshot;if(!isObject(t)||t.version!==1||!isObject(t.session)||t.session.sessionId!==e.sessionId||!Array.isArray(t.session.history))throw Error(`Unsupported legacy session snapshot.`);return t.session}function importConversation(e){let{history:t,...n}=e,r=Object.fromEntries(Object.entries(e.state??{}).filter(([e])=>!e.startsWith(`eve.`)||PRESERVED_FRAMEWORK_STATE.has(e))),i=legacyUsage(e.state?.[REPORTED_USAGE_KEY]);return i!==void 0&&(r[REPORTED_USAGE_KEY]=i),{history:normalizeHistory(t),sessionState:{version:DURABLE_SESSION_VERSION,sessionId:e.sessionId,continuationToken:e.continuationToken,hasProxyInputRequests:!1,snapshot:{session:{...n,state:{...r,[SESSION_PROJECTION_STATE_KEY]:importProjection(e)}}}}}}function importProjection(e){let t=e.state?.[`eve.harness.emission`],n=initialSessionProjection(),r=legacyUsage(isObject(e.state?.[LEGACY_USAGE_KEY])?e.state[LEGACY_USAGE_KEY].session:void 0),i=r===void 0?n:{...n,view:withModelUsage(n.view,r)};if(!isObject(t)||typeof t.sequence!=`number`)return i;let{view:a}=i,o=t.sessionStarted===!0?`open`:`new`,s=typeof t.turnId==`string`?t.turnId:``;if(s===``)return{...i,view:{...a,session:{status:o,turnCount:t.sequence}}};let c=typeof t.stepIndex==`number`?t.stepIndex:0,l={cause:{hook:`legacy`},follows:null,introducedAt:0,startedAt:new Date(0).toISOString(),status:`running`,turnId:s,...c>0&&{runs:c}};return{...i,view:{...a,session:{latestTurnId:s,status:o,turnCount:t.sequence+1},turns:{[s]:l}}}}function legacyUsage(e){if(!isObject(e))return;let count=t=>typeof e[t]==`number`?e[t]:0;return usageOf({cacheReadTokens:count(`cacheReadTokens`),cacheWriteTokens:count(`cacheWriteTokens`),costUsd:e.sawCost===!0&&typeof e.costUsd==`number`?e.costUsd:void 0,inputTokens:count(`inputTokens`),outputTokens:count(`outputTokens`)})}export{importConversation,importProjection,readLegacySnapshot};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{activeTurn,interactionOwner,waiting}from"#protocol/session-projection/selectors.js";import{AuthKey,TurnDeliveryIdsKey}from"#context/keys.js";import{BundleKey,ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{storedProjection}from"#harness/session-machine/view.js";import{V26_INPUT_REMOTE_AGENT_PROTOCOL}from"#protocol/remote-agent-protocol.js";import{resolveRemoteAgentStreamHeaders,respondToRemoteAgentSession}from"#execution/agent-sessions/remote.js";import{deserializeContext,serializeContext}from"#context/serialize.js";import{readDurableSession}from"#execution/durable-session-store.js";import{readHitlState}from"#harness/hitl/index.js";import{selectDeliveryPayloads}from"#harness/messages.js";import{resumeSessionInbox}from"#execution/session-inbox/resume.js";import{buildAdapterContext}from"#channel/adapter-context.js";import{commitSessionStep,publishSessionEvents}from"#execution/publish-session-events.js";import"#execution/session/state-delta.js";import{withSessionStateDelta}from"#execution/session/step-state-delta.js";import{routeAnswer}from"#harness/session-machine/transitions.js";import{coalesceDeliverPayloads}from"#execution/deliver-payloads.js";import{fact}from"#harness/facts.js";import{userPartsOf}from"#harness/user-parts.js";import{principalOf}from"#execution/session/delivery-facts.js";import{
|
|
1
|
+
import{activeTurn,interactionOwner,waiting}from"#protocol/session-projection/selectors.js";import{AuthKey,TurnDeliveryIdsKey}from"#context/keys.js";import{BundleKey,ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{storedProjection}from"#harness/session-machine/view.js";import{V26_INPUT_REMOTE_AGENT_PROTOCOL}from"#protocol/remote-agent-protocol.js";import{hasDelegatedSessionContext}from"#execution/delegated-session-context.js";import{resolveRemoteAgentStreamHeaders,respondToRemoteAgentSession}from"#execution/agent-sessions/remote.js";import{deserializeContext,serializeContext}from"#context/serialize.js";import{readDurableSession}from"#execution/durable-session-store.js";import{readHitlState}from"#harness/hitl/index.js";import{selectDeliveryPayloads}from"#harness/messages.js";import{resumeSessionInbox}from"#execution/session-inbox/resume.js";import{buildAdapterContext}from"#channel/adapter-context.js";import{commitSessionStep,publishSessionEvents}from"#execution/publish-session-events.js";import"#execution/session/state-delta.js";import{withSessionStateDelta}from"#execution/session/step-state-delta.js";import{routeAnswer}from"#harness/session-machine/transitions.js";import{coalesceDeliverPayloads}from"#execution/deliver-payloads.js";import{fact}from"#harness/facts.js";import{userPartsOf}from"#harness/user-parts.js";import{principalOf}from"#execution/session/delivery-facts.js";import{setChannelContext}from"#execution/channel-context.js";import{routeDeliverPayload}from"#subagents/hitl-proxy.js";import{protocolTwoAnswersSettledOnForward}from"#subagents/protocol-two-callback.js";import{sendWorkflowAskAnswers}from"#execution/tools/workflow/answer.js";async function routeProxiedDeliverStep(e){"use step";return await withSessionStateDelta(e,routeProxiedDeliver)}async function routeProxiedDeliver(e){let t=readHitlState(readDurableSession(e.sessionState).state).relays,{delivery:n,serializedContext:r}=await deliverChannelAnswers({...e,routable:e=>t.has(e.interactionId)}),i=readDurableSession(e.sessionState),a=new Map,o=new Map,s,c=!hasDelegatedSessionContext(r)&&n.caller===void 0,l=new Set,u=[],d=storedProjection(i.state).view,f=activeTurn(d),p=f===void 0?void 0:waiting(d,f.turnId),askedTurn=e=>{let t=interactionOwner(d,e).turnId;return t!==void 0&&d.turns[t]?.status===`running`?t:p?.on===`interaction`&&p.interactions.some(t=>t.interactionId===e.interactionId)?f?.turnId:void 0},m=[],h=[];for(let[e,t]of n.payloads.entries()){let r=routeDeliverPayload({allowRoute:e=>!l.has(e),payload:t,resolveMessage:c,state:i.state});s??=r.parentAction,r.forSelf!==void 0&&a.set(e,r.forSelf);let f=(n.deliveryMetadata??[]).filter(t=>t.payloadIndex===e),p=f[0]?.deliveryId;if(r.forChildren.length>0&&p!==void 0){let e=r.forChildren.find(e=>e.message!==void 0),i=r.forChildren.flatMap(e=>e.payload.answers).map(e=>d.interactions[e.interactionId]).find(e=>e!==void 0&&askedTurn(e)!==void 0),a=i===void 0?void 0:askedTurn(i);r.forSelf===void 0&&a!==void 0&&u.push(...f.map(e=>e.deliveryId));for(let t of f)m.push({consumed:r.forSelf===void 0&&a!==void 0?{parts:e?.message===void 0?[]:userPartsOf(e.message),turnId:a}:void 0,continues:r.forSelf!==void 0||void 0,deliveryId:t.deliveryId,principal:principalOf(n.auth),source:t.channelKind===void 0?void 0:{channel:t.channelKind}});for(let e of r.forChildren)for(let n of e.payload.answers){let e=(t.answers??[]).indexOf(n),r={};n.optionId!==void 0&&(r.optionId=n.optionId),n.text!==void 0&&(r.text=n.text),h.push({deliveryId:p,interactionId:n.interactionId,responseId:`response_${p}_forwarded_${e===-1?`typed_0`:String(e)}`,value:r})}}for(let[t,i]of r.forChildren.entries()){if(i.workflowAsk!==void 0||i.message!==void 0)for(let{interactionId:e}of i.payload.answers)l.add(e);let a=JSON.stringify([i.childContinuationToken,i.childSessionInbox?.sessionId??``,i.remote?.sessionId??``,i.inputSource??null,i.workflowAsk?.control??null]),s=o.get(a)??{workflowAsk:i.workflowAsk,remote:i.remote,childContinuationToken:i.childContinuationToken,childSessionInbox:i.childSessionInbox,metadata:[],payloads:[]},c=s.payloads.length;if(s.payloads.push(i.payload),r.forSelf===void 0&&t===0)for(let t of n.deliveryMetadata??[])t.payloadIndex===e&&s.metadata.push({...t,payloadIndex:c});o.set(a,s)}}let g={serializedContext:joinTurnDeliveryIds(r,u),sessionState:e.sessionState},_=!1,v=m.filter(e=>e.consumed!==void 0),y=v.length===0?g:await commitSessionStep({...g,sessionWritable:e.sessionWritable},e=>[routeAnswer(e,{deliveries:v,forwarded:[],decided:[]})],{origin:`own`,cancelTurn:()=>{_=!0}});if(_){let t=storedProjection(readDurableSession(y.sessionState).state).view,r=(n.deliveryMetadata??[]).filter(({deliveryId:e,payloadIndex:n})=>a.has(n)&&t.deliveries[e]?.status!==`settled`);if(r.length===0)return{...y,kind:`cancel-turn`};let i=await publishSessionEvents({...y,sessionWritable:e.sessionWritable},r.flatMap(({channelKind:e,deliveryId:r})=>[...t.deliveries[r]===void 0?[fact(`delivery.admitted`,{deliveryId:r,principal:principalOf(n.auth),source:e===void 0?void 0:{channel:e}})]:[],fact(`delivery.settled`,{deliveryId:r,outcome:`ignored`})]));return{kind:`cancel-turn`,serializedContext:i.serializedContext,sessionState:i.sessionState}}let b=[];for(let[e,t]of o)if(t.workflowAsk!==void 0){let e=coalesceDeliverPayloads(t.payloads).answers??[];b.push(...e.map(e=>({answer:e,outcome:`accepted`}))),await sendWorkflowAskAnswers(t.workflowAsk,e,principalOf(n.auth))}else{let i={...n,deliveryMetadata:t.metadata.length===0?void 0:t.metadata,payloads:t.payloads},a=t.remote;if(a!==void 0){let i=await deserializeContext(r),o=await resolveRemoteAgentStreamHeaders({bundle:i.require(BundleKey),name:a.name,dynamicBinding:a.dynamicBinding,resolverId:a.resolverId,url:a.url}),c=coalesceDeliverPayloads(t.payloads).answers??[];if(await respondToRemoteAgentSession({remote:a,headers:o,auth:n.auth,idempotencyKey:await answersIdempotencyKey(n,e),responses:c}),a.earlierProtocol===V26_INPUT_REMOTE_AGENT_PROTOCOL)for(let e of protocolTwoAnswersSettledOnForward({answers:c,decidedHere:s?.answer.interactionId,kindOf:e=>d.interactions[e]?.request.kind}))b.push({answer:e,outcome:`accepted`})}else await resumeSessionInbox(t.childSessionInbox??t.childContinuationToken,i)}let x=await commitSessionStep({...y,sessionWritable:e.sessionWritable},e=>[routeAnswer(e,{decided:s===void 0?b:[...b,{answer:s.answer,outcome:`declined`}],deliveries:m,forwarded:h})],{origin:`relayed`});if(s!==void 0)return{...x,kind:s.kind};let S=[...a].sort(([e],[t])=>e-t),C=S.length===0?void 0:selectDeliveryPayloads(n,S.map(([e,t])=>({index:e,payload:t})));return{...x,kind:`continue`,remainder:C}}async function answersIdempotencyKey(e,t){let n=(e.deliveryMetadata??[]).map(e=>e.deliveryId);if(n.length===0)return;let r=JSON.stringify([n,t]),i=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(r));return`eve-answers:${Array.from(new Uint8Array(i),e=>e.toString(16).padStart(2,`0`)).join(``)}`}function joinTurnDeliveryIds(e,t){if(t.length===0)return e;let n=e[TurnDeliveryIdsKey.name]??[];return{...e,[TurnDeliveryIdsKey.name]:[...new Set([...n,...t])]}}async function mapHeldAnswersStep(e){"use step";return await withSessionStateDelta(e,async()=>{let t=new Set(e.requestIds),n=await deliverChannelAnswers({...e,routable:e=>t.has(e.interactionId)});return n.delivery===e.delivery?{delivery:void 0}:{delivery:n.delivery,serializedContext:n.serializedContext}})}async function deliverChannelAnswers(e){let{routable:t}=e;if(!e.delivery.payloads.some(e=>e.answers?.some(e=>!t(e))===!0))return e;let n=await deserializeContext(e.serializedContext),r=n.require(ChannelKey);if(r.deliver===void 0)return e;e.delivery.auth!==void 0&&n.set(AuthKey,e.delivery.auth??null);let i=r.state??{},a=!1,o=[];for(let s of e.delivery.payloads){if(s.answers===void 0){o.push(s);continue}let e=[];for(let o of s.answers){if(t(o)){e.push(o);continue}let c=buildAdapterContext({...r,state:structuredClone(i)},n),l=(await r.deliver({...s,answers:[o],message:void 0},c))?.answers?.filter(t)??[];if(l.length===0){e.push(o);continue}a=!0,i=c.state,e.push(...l)}o.push({...s,answers:e})}if(!a)return e;let s=await deserializeContext(e.serializedContext);return setChannelContext(s,{...r,state:i}),{delivery:{...e.delivery,payloads:o},serializedContext:serializeContext(s)}}export{answersIdempotencyKey,mapHeldAnswersStep,routeProxiedDeliverStep};
|
|
@@ -31,4 +31,7 @@ export declare function fetchWithDispatcher(url: string | URL, init: DispatcherR
|
|
|
31
31
|
*/
|
|
32
32
|
export declare function readBoundedResponse(response: Response, maxResponseSize: number): Promise<Response>;
|
|
33
33
|
export declare function cancelResponseBody(response: Response): Promise<void>;
|
|
34
|
+
export declare class ResponseTooLargeError extends Error {
|
|
35
|
+
constructor(maxResponseSize: number);
|
|
36
|
+
}
|
|
34
37
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isBlockedDestinationHost}from"#shared/network-address.js";import{lookup}from"node:dns";var UnsafeDestinationError=class extends Error{constructor(e=`URL must not target localhost, private, link-local, or reserved IP addresses.`){super(e),this.name=`UnsafeDestinationError`}};function assertPublicHostname(e,t){if(isBlockedDestinationHost(e,t))throw new UnsafeDestinationError}async function createPublicDispatcher(e){let{Agent:t,Dispatcher1Wrapper:n}=await import(`undici`);return new n(new t({connect:{lookup:createPublicLookup(e)}}))}function findUnsafeDestinationError(e){return e instanceof UnsafeDestinationError?e:e instanceof Error&&e.cause instanceof UnsafeDestinationError?e.cause:void 0}function fetchWithDispatcher(e,t){return fetch(e,t)}function createPublicLookup(e){return(t,n,r)=>{lookup(t,{all:!0,verbatim:!0},(i,a)=>{if(i!==null){r(i,``,0);return}if(a.some(({address:t})=>isBlockedDestinationHost(t,e))){r(new UnsafeDestinationError,``,0);return}let o=n.family===void 0||n.family===0?a:a.filter(({family:e})=>e===n.family);if(o.length===0){let e=Error(`Unable to resolve URL hostname "${t}" in the requested IP family.`);Object.assign(e,{code:`ENOTFOUND`}),r(e,``,0);return}if(n.all===!0){r(null,o);return}let s=o[0];r(null,s.address,s.family)})}}async function readBoundedResponse(e,t){let n=parseContentLength(e.headers.get(`content-length`));if(n!==void 0&&n>t)throw await cancelResponseBody(e),
|
|
1
|
+
import{isBlockedDestinationHost}from"#shared/network-address.js";import{lookup}from"node:dns";var UnsafeDestinationError=class extends Error{constructor(e=`URL must not target localhost, private, link-local, or reserved IP addresses.`){super(e),this.name=`UnsafeDestinationError`}};function assertPublicHostname(e,t){if(isBlockedDestinationHost(e,t))throw new UnsafeDestinationError}async function createPublicDispatcher(e){let{Agent:t,Dispatcher1Wrapper:n}=await import(`undici`);return new n(new t({connect:{lookup:createPublicLookup(e)}}))}function findUnsafeDestinationError(e){return e instanceof UnsafeDestinationError?e:e instanceof Error&&e.cause instanceof UnsafeDestinationError?e.cause:void 0}function fetchWithDispatcher(e,t){return fetch(e,t)}function createPublicLookup(e){return(t,n,r)=>{lookup(t,{all:!0,verbatim:!0},(i,a)=>{if(i!==null){r(i,``,0);return}if(a.some(({address:t})=>isBlockedDestinationHost(t,e))){r(new UnsafeDestinationError,``,0);return}let o=n.family===void 0||n.family===0?a:a.filter(({family:e})=>e===n.family);if(o.length===0){let e=Error(`Unable to resolve URL hostname "${t}" in the requested IP family.`);Object.assign(e,{code:`ENOTFOUND`}),r(e,``,0);return}if(n.all===!0){r(null,o);return}let s=o[0];r(null,s.address,s.family)})}}async function readBoundedResponse(e,t){let n=parseContentLength(e.headers.get(`content-length`));if(n!==void 0&&n>t)throw await cancelResponseBody(e),new ResponseTooLargeError(t);let r=await readBoundedBody(e,t),i=r.byteLength===0?null:Uint8Array.from(r).buffer;return new Response(i,{headers:e.headers,status:e.status,statusText:e.statusText})}function parseContentLength(e){if(e===null)return;let t=Number.parseInt(e,10);return Number.isFinite(t)&&t>=0?t:void 0}async function readBoundedBody(e,t){if(e.body===null)return new Uint8Array;let n=e.body.getReader(),r=[],i=0;try{for(;;){let{done:e,value:a}=await n.read();if(e)break;if(i+=a.byteLength,i>t)throw await n.cancel(),new ResponseTooLargeError(t);r.push(a)}}finally{n.releaseLock()}let a=new Uint8Array(i),o=0;for(let e of r)a.set(e,o),o+=e.byteLength;return a}async function cancelResponseBody(e){try{await e.body?.cancel()}catch{}}var ResponseTooLargeError=class extends Error{constructor(e){super(`Response too large (exceeds ${e} bytes).`),this.name=`ResponseTooLargeError`}};export{ResponseTooLargeError,UnsafeDestinationError,assertPublicHostname,cancelResponseBody,createPublicDispatcher,fetchWithDispatcher,findUnsafeDestinationError,readBoundedResponse};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{FACT_CATALOG,isFactType}from"#protocol/session-events/catalog.js";import{copyView}from"#protocol/session-projection/fold.js";import{createLogger}from"#internal/logging.js";import{callAdapterEventHandler}from"#channel/adapter.js";import{contextStorage}from"#context/container.js";import{AuthKey,InitiatorAuthKey,ParentSessionKey,SessionKey}from"#context/keys.js";import{encodeLineBytes}from"#protocol/session-events/envelope.js";import{eventsOfLine,linesOf}from"#protocol/session-lines.js";import{BundleKey,ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{SESSION_PROJECTION_STATE_KEY,storedProjection}from"#harness/session-machine/view.js";import{advance,currentProjection,currentView,enterSessionProjection,enterSessionProjectionAt,nextLinePosition,recordPublishedLine,saveSessionProjection}from"#harness/session-machine/current.js";import{readSessionStreamTailIndex,streamSessionLines}from"#execution/session-event-stream.js";import{getStepMetadata}from"#compiled/@workflow/core/index.js";import{withContextScope}from"#context/run-step.js";import{deserializeContext,serializeContext}from"#context/serialize.js";import{createDurableSessionState,readDurableSession,replaceDurableSessionSnapshot}from"#execution/durable-session-store.js";import{validateHarnessModelMessages}from"#harness/messages.js";import{buildAdapterContext}from"#channel/adapter-context.js";import{hydrateDurableSession}from"#execution/session.js";import{resolveEffectiveAgentRuntime}from"#execution/effective-agent-config.js";import{dropClosedRecords,saveTransition,sessionView}from"#harness/session-machine/commit.js";import{sessionEndedFacts}from"#harness/facts.js";import{initialSessionProjection}from"#protocol/session-projection.js";import{setChannelContext}from"#execution/channel-context.js";import{runReactions}from"#reactions/runner.js";import{forwardSessionInput}from"#execution/forward-session-input.js";import{reconcileSessionContinuationToken}from"#execution/reconcile-session-continuation-token.js";import{announceWaiting}from"#harness/session-machine/waiting.js";import{cascade}from"#harness/session-machine/cascade.js";import{eventsOf}from"#harness/publication.js";import{bindSessionInstrumentation}from"#instrumentation/runtime.js";import{createStreamChecker}from"#protocol/session-events/checker.js";const log=createLogger(`execution.publish-session-events`);async function publishSessionEvents(e,t,n){let r=!1;return{...await publishEventsFromStep(e,`own`,t,n?.canCancelTurn?()=>{r=!0}:void 0),cancelled:r}}async function publishEventsFromStep(e,t,n,r){if(n.length===0)return{serializedContext:e.serializedContext,sessionState:e.sessionState};let{published:i}=await publishFromSessionStep(await restoreSessionStep(e),{cancelTurn:r,origin:t,async publish(e){await e(n)}});return i}async function restoreSessionStep(e){return{ctx:await deserializeContext(e.serializedContext),durableSession:readDurableSession(e.sessionState),sessionWritable:e.sessionWritable}}async function publishFromSessionStep(e,t){let{ctx:n}=e,r=await publishInSessionScope(e,t),i=t.updateSession?.(r.session,r.result)??{session:r.session},a=readSessionProjection(n),o=reconcileSessionContinuationToken(n,saveSessionProjection(dropClosedRecords(i.session,a),n));return{published:{serializedContext:serializeContext(n),sessionState:createDurableSessionState({session:o}),...`history`in o&&{history:o.history}},result:i.result}}async function publishInSessionScope(e,t){let{ctx:n}=e;enterSessionProjection(n,e.durableSession.state);let r=await readOrphanedLines({sessionId:e.durableSession.sessionId,position:nextLinePosition(n),sessionWritable:e.sessionWritable}),i=resolveEffectiveAgentRuntime(n.require(BundleKey),n),a=hydrateDurableSession({compactionOverrides:{thresholdPercent:i.thresholdPercent},durable:e.durableSession,turnAgent:i.turnAgent}),o=e.history===void 0?a:{...a,history:validateHarnessModelMessages(e.history)},s=t.origin===`own`?bindSessionInstrumentation({agentName:i.turnAgent.id,ctx:n,rootSessionId:o.rootSessionId??o.sessionId,sessionId:o.sessionId}):void 0,c=openSessionEventPublisher({cancelTurn:t.cancelTurn,ctx:n,inputSource:t.inputSource,orphaned:r,origin:t.origin,sessionWritable:e.sessionWritable});try{return await withContextScope(n,o,async e=>{let n=s?.createHandleEvent({handleEvent:c.publish})??c.publish,r=await t.publish(n,e);return await c.finish(),{result:r,session:e}})}finally{await s?.flush(),c.writer.release()}}function checksSessionEvents(){let e=process.env.EVE_CHECK_SESSION_EVENTS;return e===`1`||e!==`0`&&process.env.EVE_DEV===`1`}const interruptedAttempts=new WeakMap;async function readOrphanedLines(e){if(e.always!==!0&&!isRetriedStep())return[];let{sessionId:t,sessionWritable:n,position:r}=e,i=interruptedAttempts.get(n);return i===void 0&&(i=await readLinesFrom(t,r),interruptedAttempts.set(n,i)),i.filter(({position:e})=>e>=r)}function followInterruptedAttempt(e,t){let n=readDurableSession(t),r=storedProjection(n.state),i=(interruptedAttempts.get(e)??[]).filter(({position:e})=>e>=r.view.position);return i.length===0?t:(log.error(`a retried step wrote less than its interrupted attempt; the session follows the stream`,{lines:i.length,sessionId:t.sessionId}),replaceDurableSessionSnapshot({session:{...n,state:{...n.state,[SESSION_PROJECTION_STATE_KEY]:foldOrphanedLines(r,i)}},state:t}))}function isRetriedStep(){try{return getStepMetadata().attempt>1}catch(e){if(e instanceof Error&&e.name===`NotInStepContextError`)return!1;throw e}}async function readLinesFrom(e,t){let n=await readSessionStreamTailIndex(e);if(n+1<t)throw Error(`Session checkpoint is ahead of its stream.`);let r=[];if(n<t)return r;let i=t;for await(let a of streamSessionLines(e,{follow:!1,startIndex:t})){if(a.position>n)break;if(a.line===void 0||a.position!==i)throw Error(`Cannot reconcile an unreadable or missing session line.`);r.push({line:a.line,position:i++})}if(i!==n+1)throw Error(`Session stream ended before its reported tail.`);return r}function foldOrphanedLines(e,t){let n=e;for(let{line:e,position:r}of t){let t=`facts`in e?eventsOfLine(e,r,e.at):[];n=advance(n,e,r,t)}return n}async function reconcilePublishedSessionLines(e,t){let n=e??initialSessionProjection();return foldOrphanedLines(n,await readLinesFrom(t,n.view.position))}function sameLine(e,t){if(`progress`in t||`progress`in e)return`progress`in t&&`progress`in e&&JSON.stringify(e.progress)===JSON.stringify(t.progress);let identity=e=>{let{data:t,type:n}=e;if(!isFactType(n))return String(n);let r=t[FACT_CATALOG[n].idField];return`${n}:${String(r)}`};return e.facts.length===t.facts.length&&e.facts.every((e,n)=>identity(e)===identity(t.facts[n]))}function openSessionEventPublisher(e){let{ctx:t}=e,n=[...e.orphaned??[]],r=createSessionEventDispatcher(e),i=openSessionEventWriter(e.sessionWritable),a,o,emitOne=async e=>{if(a===void 0&&checksSessionEvents()){let{schemaViolation:e}=await import(`#protocol/session-events/schemas.js`);a=createStreamChecker({seed:currentProjection(t).view,validate:e})}o===void 0&&(o=copyView(currentView(t)));let s=cascade(currentView(t),eventsOf(e)),c=new Date().toISOString(),l=[],u=linesOf(s,c).map(e=>({line:e,bytes:encodeLineBytes(e)}));u.forEach(({line:e},n)=>{let r=a?.check(e,nextLinePosition(t)+n);if(r!==void 0&&r.length>0)throw a=void 0,Error(`Session event contract: ${r.map(e=>`${e.rule} at ${e.position}:${e.index??`progress`}: ${e.message}`).join(`; `)}`)});for(let{line:e,bytes:r}of u){let o=nextLinePosition(t),s=n[0];if(s!==void 0){if(s.position!==o||!sameLine(s.line,e))throw Error(`A retried step published differently from its interrupted attempt.`);n.shift();let r=`facts`in s.line?s.line.at:c;recordPublishedLine(t,s.line,o,eventsOfLine(s.line,o,r));continue}await i.write(r).catch(e=>{throw a=void 0,e});let u=eventsOfLine(e,o,c);recordPublishedLine(t,e,o,u);let d=`progress`in e,f=currentView(t);u.forEach(e=>l.push({event:e,position:e.meta.position,progress:d,view:f}))}return await r.deliver(l),l},s=Promise.resolve(),emit=e=>{let t=s.then(()=>emitOne(e));return s=t.then(()=>void 0,()=>void 0),t},publish=async t=>{let n=e.cancelTurn;await r.react(await emit(t),n===void 0?void 0:{cancelTurn:()=>n()})};return{dispatcher:r,writer:i,emit,publish,async finish(e){if(o===void 0)return;let n=e?.announce===!1?[]:announceWaiting(o,currentView(t));o=void 0,n.length>0&&await publish(n)}}}function createSessionEventDispatcher(e){let{ctx:t,inputSource:n}=e,r=t.require(ChannelKey),i=buildAdapterContext(r,t),a=n===void 0?i:{...i,inputSource:n},o=Promise.resolve();return{adapterCtx:i,async deliver(e){if(e.length===0)return;let o,committed=async()=>{if(o===void 0)return;let{facts:e,position:t,view:n}=o;o=void 0,await callAdapterEventHandler(r,{facts:e,position:t.line},{...a,position:t,scope:void 0,view:n})};for(let{event:i,position:s,progress:c,view:l}of e){if(o!==void 0&&o.position.line!==s.line&&await committed(),await forwardSessionInput(t,i,n))continue;c||(o??={facts:[],position:s,view:l}).facts.push(i);let e=`scope`in i?i.scope:void 0;await callAdapterEventHandler(r,i,{...a,position:s,scope:e,view:l})}await committed(),setChannelContext(t,{...r,state:{...i.state}})},react(e,n){if(e.length===0)return Promise.resolve();let r=o.then(()=>runReactions(t,{...n,written:e}));return o=r.catch(()=>void 0),r}}}function openSessionEventWriter(e){let t=e.getWriter(),n=!1,release=()=>{n||(n=!0,t.releaseLock())};return{async write(e){await t.write(e)},close:async()=>{try{await t.close()}finally{release()}},release}}function readSessionProjection(e){return currentProjection(e)}async function publishTerminalSessionEvent(e){let t=e.serializedContext[`eve.sessionId`]??``,n={errorId:e.errorId,sessionId:t},r=`session.ended`,i=e.projection??(e.sessionState===void 0?void 0:storedProjection(readDurableSession(e.sessionState).state));try{i=await reconcilePublishedSessionLines(i,t)}catch(e){throw log.error(`failed to fold the published tail for terminal ${r} event`,{...n,error:e}),e}let a,o;try{a=await deserializeContext(e.serializedContext),enterSessionProjectionAt(a,i),o=openSessionEventPublisher({ctx:a,origin:`own`,sessionWritable:e.sessionWritable})}catch(t){if(log.error(`failed to restore context for terminal ${r} event`,{...n,error:t}),i.view.session.status===`ended`){try{await openSessionEventWriter(e.sessionWritable).close()}catch{}return}let a=cascade(i.view,sessionEndedFacts(i,e.ending));await writeUnroutedSessionEvent(e.sessionWritable,a).catch(e=>log.error(`failed to write terminal ${r} event`,{...n,error:e}));return}if(i.view.session.status===`ended`){try{await o.writer.close()}catch{}finally{o.writer.release()}return}let s=a.get(AuthKey)??null;a.setVirtualContext(SessionKey,{auth:{current:s,initiator:a.get(InitiatorAuthKey)??s},parent:a.get(ParentSessionKey),sessionId:t,turn:e.turn??{id:`turn_0`,sequence:0}});let publish=async e=>{await o.emit(e),await o.writer.close()},c;try{c=bindSessionInstrumentation({agentName:a.require(BundleKey).turnAgent.id,ctx:a,rootSessionId:a.get(ParentSessionKey)?.rootSessionId??t,sessionId:t})}catch(e){log.error(`failed to bind instrumentation for terminal ${r} event`,{...n,error:e})}let l=c?.createHandleEvent({handleEvent:publish})??publish;try{await contextStorage.run(a,()=>l(sessionEndedFacts(i,e.ending)))}catch(e){log.error(`failed to publish terminal ${r} event`,{...n,error:e})}finally{o.writer.release();try{await c?.flush()}catch(e){log.error(`failed to flush instrumentation after terminal ${r} event`,{...n,error:e})}}}async function writeUnroutedSessionEvent(e,t){let n=openSessionEventWriter(e);try{let e=linesOf(t,new Date().toISOString()).map(encodeLineBytes);for(let t of e)await n.write(t);await n.close()}finally{n.release()}}async function commitSessionStep(e,t,n){let{state:r}=`ctx`in e?e.durableSession:readDurableSession(e.sessionState),i=sessionView(storedProjection(r),r),a=t(i);if(a.length>1&&a.some(e=>e.turn!==i.turn)||a.filter(e=>e.signIns!==void 0).length>1)throw Error(`A transition batch must not overlap turn or sign-in snapshots.`);return`ctx`in e?await commit(e,a,n):a.every(e=>changesNothing(i,e))?{serializedContext:e.serializedContext,sessionState:e.sessionState}:await commit(await restoreSessionStep(e),a,n)}async function commit(e,t,n){let{published:r}=await publishFromSessionStep(e,{inputSource:n.inputSource,cancelTurn:n.cancelTurn,origin:n.origin,async publish(e){let n=t.flatMap(e=>e.events);n.length>0&&await e(n)},updateSession:e=>({session:t.reduce((e,t)=>saveTransition(e,t),e)})});return r}function changesNothing(e,t){return t.turn===e.turn&&t.events.length===0&&t.signIns===void 0&&t.relays===void 0&&t.commit===void 0&&t.clearsHistory===void 0}export{checksSessionEvents,commitSessionStep,foldOrphanedLines,followInterruptedAttempt,openSessionEventPublisher,publishFromSessionStep,publishSessionEvents,publishTerminalSessionEvent,readOrphanedLines,readSessionProjection,restoreSessionStep};
|
|
1
|
+
import{FACT_CATALOG,isFactType}from"#protocol/session-events/catalog.js";import{copyView}from"#protocol/session-projection/fold.js";import{createLogger}from"#internal/logging.js";import{callAdapterEventHandler}from"#channel/adapter.js";import{contextStorage}from"#context/container.js";import{AuthKey,InitiatorAuthKey,ParentSessionKey,SessionKey}from"#context/keys.js";import{encodeLineBytes}from"#protocol/session-events/envelope.js";import{eventsOfLine,linesOf}from"#protocol/session-lines.js";import{BundleKey,ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{SESSION_PROJECTION_STATE_KEY,storedProjection}from"#harness/session-machine/view.js";import{advance,currentProjection,currentView,enterSessionProjection,enterSessionProjectionAt,nextLinePosition,recordPublishedLine,saveSessionProjection}from"#harness/session-machine/current.js";import{readSessionStreamTailIndex,streamSessionLines}from"#execution/session-event-stream.js";import{getStepMetadata}from"#compiled/@workflow/core/index.js";import{withContextScope}from"#context/run-step.js";import{deserializeContext,serializeContext}from"#context/serialize.js";import{createDurableSessionState,readDurableSession,replaceDurableSessionSnapshot}from"#execution/durable-session-store.js";import{validateHarnessModelMessages}from"#harness/messages.js";import{buildAdapterContext}from"#channel/adapter-context.js";import{hydrateDurableSession}from"#execution/session.js";import{resolveEffectiveAgentRuntime}from"#execution/effective-agent-config.js";import{dropClosedRecords,saveTransition,sessionView}from"#harness/session-machine/commit.js";import{initialSessionProjection}from"#protocol/session-projection.js";import{sessionEndedFacts}from"#harness/facts.js";import{setChannelContext}from"#execution/channel-context.js";import{runReactions}from"#reactions/runner.js";import{forwardSessionInput}from"#execution/forward-session-input.js";import{reconcileSessionContinuationToken}from"#execution/reconcile-session-continuation-token.js";import{announceWaiting}from"#harness/session-machine/waiting.js";import{cascade}from"#harness/session-machine/cascade.js";import{eventsOf}from"#harness/publication.js";import{bindSessionInstrumentation}from"#instrumentation/runtime.js";import{createStreamChecker}from"#protocol/session-events/checker.js";const log=createLogger(`execution.publish-session-events`);async function publishSessionEvents(e,t,n){let r=!1;return{...await publishEventsFromStep(e,`own`,t,n?.canCancelTurn?()=>{r=!0}:void 0),cancelled:r}}async function publishEventsFromStep(e,t,n,r){if(n.length===0)return{serializedContext:e.serializedContext,sessionState:e.sessionState};let{published:i}=await publishFromSessionStep(await restoreSessionStep(e),{cancelTurn:r,origin:t,async publish(e){await e(n)}});return i}async function restoreSessionStep(e){return{ctx:await deserializeContext(e.serializedContext),durableSession:readDurableSession(e.sessionState),sessionWritable:e.sessionWritable}}async function publishFromSessionStep(e,t){let{ctx:n}=e,r=await publishInSessionScope(e,t),i=t.updateSession?.(r.session,r.result)??{session:r.session},a=readSessionProjection(n),o=reconcileSessionContinuationToken(n,saveSessionProjection(dropClosedRecords(i.session,a),n));return{published:{serializedContext:serializeContext(n),sessionState:createDurableSessionState({session:o}),...`history`in o&&{history:o.history}},result:i.result}}async function publishInSessionScope(e,t){let{ctx:n}=e;enterSessionProjection(n,e.durableSession.state);let r=await readOrphanedLines({sessionId:e.durableSession.sessionId,position:nextLinePosition(n),sessionWritable:e.sessionWritable}),i=resolveEffectiveAgentRuntime(n.require(BundleKey),n),a=hydrateDurableSession({compactionOverrides:{thresholdPercent:i.thresholdPercent},durable:e.durableSession,turnAgent:i.turnAgent}),o=e.history===void 0?a:{...a,history:validateHarnessModelMessages(e.history)},s=t.origin===`own`?bindSessionInstrumentation({agentName:i.turnAgent.id,ctx:n,rootSessionId:o.rootSessionId??o.sessionId,sessionId:o.sessionId}):void 0,c=openSessionEventPublisher({cancelTurn:t.cancelTurn,ctx:n,inputSource:t.inputSource,orphaned:r,origin:t.origin,sessionWritable:e.sessionWritable});try{return await withContextScope(n,o,async e=>{let n=s?.createHandleEvent({handleEvent:c.publish})??c.publish,r=await t.publish(n,e);return await c.finish(),{result:r,session:e}})}finally{await s?.flush(),c.writer.release()}}function checksSessionEvents(){let e=process.env.EVE_CHECK_SESSION_EVENTS;return e===`1`||e!==`0`&&process.env.EVE_DEV===`1`}const interruptedAttempts=new WeakMap;async function readOrphanedLines(e){if(e.always!==!0&&!isRetriedStep())return[];let{sessionId:t,sessionWritable:n,position:r}=e,i=interruptedAttempts.get(n);return i===void 0&&(i=await readLinesFrom(t,r),interruptedAttempts.set(n,i)),i.filter(({position:e})=>e>=r)}function followInterruptedAttempt(e,t){let n=readDurableSession(t),r=storedProjection(n.state),i=(interruptedAttempts.get(e)??[]).filter(({position:e})=>e>=r.view.position);return i.length===0?t:(log.error(`a retried step wrote less than its interrupted attempt; the session follows the stream`,{lines:i.length,sessionId:t.sessionId}),replaceDurableSessionSnapshot({session:{...n,state:{...n.state,[SESSION_PROJECTION_STATE_KEY]:foldOrphanedLines(r,i)}},state:t}))}function isRetriedStep(){try{return getStepMetadata().attempt>1}catch(e){if(e instanceof Error&&e.name===`NotInStepContextError`)return!1;throw e}}async function readLinesFrom(e,t){let n=await readSessionStreamTailIndex(e);if(n+1<t)throw Error(`Session checkpoint is ahead of its stream.`);let r=[];if(n<t)return r;let i=t;for await(let a of streamSessionLines(e,{follow:!1,startIndex:t})){if(a.position>n)break;if(a.line===void 0||a.position!==i)throw Error(`Cannot reconcile an unreadable or missing session line.`);r.push({line:a.line,position:i++})}if(i!==n+1)throw Error(`Session stream ended before its reported tail.`);return r}function foldOrphanedLines(e,t){let n=e;for(let{line:e,position:r}of t){let t=`facts`in e?eventsOfLine(e,r,e.at):[];n=advance(n,e,r,t)}return n}async function reconcilePublishedSessionLines(e,t){let n=e??initialSessionProjection();return foldOrphanedLines(n,await readLinesFrom(t,n.view.position))}function sameLine(e,t){if(`progress`in t||`progress`in e)return`progress`in t&&`progress`in e&&JSON.stringify(e.progress)===JSON.stringify(t.progress);let identity=e=>{let{data:t,type:n}=e;if(!isFactType(n))return String(n);let r=t[FACT_CATALOG[n].idField];return`${n}:${String(r)}`};return e.facts.length===t.facts.length&&e.facts.every((e,n)=>identity(e)===identity(t.facts[n]))}function openSessionEventPublisher(e){let{ctx:t}=e,n=[...e.orphaned??[]],r=createSessionEventDispatcher(e),i=openSessionEventWriter(e.sessionWritable),a,o,emitOne=async e=>{if(a===void 0&&checksSessionEvents()){let{schemaViolation:e}=await import(`#protocol/session-events/schemas.js`);a=createStreamChecker({seed:currentProjection(t).view,validate:e})}o===void 0&&(o=copyView(currentView(t)));let s=cascade(currentView(t),eventsOf(e)),c=new Date().toISOString(),l=[],u=linesOf(s,c).map(e=>({line:e,bytes:encodeLineBytes(e)}));u.forEach(({line:e},n)=>{let r=a?.check(e,nextLinePosition(t)+n);if(r!==void 0&&r.length>0)throw a=void 0,Error(`Session event contract: ${r.map(e=>`${e.rule} at ${e.position}:${e.index??`progress`}: ${e.message}`).join(`; `)}`)});for(let{line:e,bytes:r}of u){let o=nextLinePosition(t),s=n[0];if(s!==void 0){if(s.position!==o||!sameLine(s.line,e))throw Error(`A retried step published differently from its interrupted attempt.`);n.shift();let r=`facts`in s.line?s.line.at:c;recordPublishedLine(t,s.line,o,eventsOfLine(s.line,o,r));continue}await i.write(r).catch(e=>{throw a=void 0,e});let u=eventsOfLine(e,o,c);recordPublishedLine(t,e,o,u);let d=`progress`in e,f=currentView(t);u.forEach(e=>l.push({event:e,position:e.meta.position,progress:d,view:f}))}return await r.deliver(l),l},s=Promise.resolve(),emit=e=>{let t=s.then(()=>emitOne(e));return s=t.then(()=>void 0,()=>void 0),t},publish=async t=>{let n=e.cancelTurn;await r.react(await emit(t),n===void 0?void 0:{cancelTurn:()=>n()})};return{dispatcher:r,writer:i,emit,publish,async finish(e){if(o===void 0)return;let n=e?.announce===!1?[]:announceWaiting(o,currentView(t));o=void 0,n.length>0&&await publish(n)}}}function createSessionEventDispatcher(e){let{ctx:t,inputSource:n}=e,r=t.require(ChannelKey),i=buildAdapterContext(r,t),a=n===void 0?i:{...i,inputSource:n},o=Promise.resolve();return{adapterCtx:i,async deliver(e){if(e.length===0)return;let o,committed=async()=>{if(o===void 0)return;let{facts:e,position:t,view:n}=o;o=void 0,await callAdapterEventHandler(r,{facts:e,position:t.line},{...a,position:t,scope:void 0,view:n})};for(let{event:i,position:s,progress:c,view:l}of e){if(o!==void 0&&o.position.line!==s.line&&await committed(),await forwardSessionInput(t,i,n))continue;c||(o??={facts:[],position:s,view:l}).facts.push(i);let e=`scope`in i?i.scope:void 0;await callAdapterEventHandler(r,i,{...a,position:s,scope:e,view:l})}await committed(),setChannelContext(t,{...r,state:{...i.state}})},react(e,n){if(e.length===0)return Promise.resolve();let r=o.then(()=>runReactions(t,{...n,written:e}));return o=r.catch(()=>void 0),r}}}function openSessionEventWriter(e){let t=e.getWriter(),n=!1,release=()=>{n||(n=!0,t.releaseLock())};return{async write(e){await t.write(e)},close:async()=>{try{await t.close()}finally{release()}},release}}function readSessionProjection(e){return currentProjection(e)}async function publishTerminalSessionEvent(e){let t=e.serializedContext[`eve.sessionId`]??``,n={errorId:e.errorId,sessionId:t},r=`session.ended`,i=e.projection??(e.sessionState===void 0?void 0:storedProjection(readDurableSession(e.sessionState).state));try{i=await reconcilePublishedSessionLines(i,t)}catch(e){throw log.error(`failed to fold the published tail for terminal ${r} event`,{...n,error:e}),e}let a,o;try{a=await deserializeContext(e.serializedContext),enterSessionProjectionAt(a,i),o=openSessionEventPublisher({ctx:a,origin:`own`,sessionWritable:e.sessionWritable})}catch(t){if(log.error(`failed to restore context for terminal ${r} event`,{...n,error:t}),i.view.session.status===`ended`){try{await openSessionEventWriter(e.sessionWritable).close()}catch{}return}let a=cascade(i.view,sessionEndedFacts(i,e.ending));await writeUnroutedSessionEvent(e.sessionWritable,a).catch(e=>log.error(`failed to write terminal ${r} event`,{...n,error:e}));return}if(i.view.session.status===`ended`){try{await o.writer.close()}catch{}finally{o.writer.release()}return}let s=a.get(AuthKey)??null;a.setVirtualContext(SessionKey,{auth:{current:s,initiator:a.get(InitiatorAuthKey)??s},parent:a.get(ParentSessionKey),sessionId:t,turn:e.turn??{id:`turn_0`,sequence:0}});let publish=async e=>{await o.emit(e),await o.writer.close()},c;try{c=bindSessionInstrumentation({agentName:a.require(BundleKey).turnAgent.id,ctx:a,rootSessionId:a.get(ParentSessionKey)?.rootSessionId??t,sessionId:t})}catch(e){log.error(`failed to bind instrumentation for terminal ${r} event`,{...n,error:e})}let l=c?.createHandleEvent({handleEvent:publish})??publish;try{await contextStorage.run(a,()=>l(sessionEndedFacts(i,e.ending)))}catch(e){log.error(`failed to publish terminal ${r} event`,{...n,error:e})}finally{o.writer.release();try{await c?.flush()}catch(e){log.error(`failed to flush instrumentation after terminal ${r} event`,{...n,error:e})}}}async function writeUnroutedSessionEvent(e,t){let n=openSessionEventWriter(e);try{let e=linesOf(t,new Date().toISOString()).map(encodeLineBytes);for(let t of e)await n.write(t);await n.close()}finally{n.release()}}async function commitSessionStep(e,t,n){let{state:r}=`ctx`in e?e.durableSession:readDurableSession(e.sessionState),i=sessionView(storedProjection(r),r),a=t(i);if(a.length>1&&a.some(e=>e.turn!==i.turn)||a.filter(e=>e.signIns!==void 0).length>1)throw Error(`A transition batch must not overlap turn or sign-in snapshots.`);return`ctx`in e?await commit(e,a,n):a.every(e=>changesNothing(i,e))?{serializedContext:e.serializedContext,sessionState:e.sessionState}:await commit(await restoreSessionStep(e),a,n)}async function commit(e,t,n){let{published:r}=await publishFromSessionStep(e,{inputSource:n.inputSource,cancelTurn:n.cancelTurn,origin:n.origin,async publish(e){let n=t.flatMap(e=>e.events);n.length>0&&await e(n)},updateSession:e=>({session:t.reduce((e,t)=>saveTransition(e,t),e)})});return r}function changesNothing(e,t){return t.turn===e.turn&&t.events.length===0&&t.signIns===void 0&&t.relays===void 0&&t.commit===void 0&&t.clearsHistory===void 0}export{checksSessionEvents,commitSessionStep,foldOrphanedLines,followInterruptedAttempt,openSessionEventPublisher,publishFromSessionStep,publishSessionEvents,publishTerminalSessionEvent,readOrphanedLines,readSessionProjection,restoreSessionStep};
|
|
@@ -24,6 +24,7 @@ export interface DockerRunOptions {
|
|
|
24
24
|
* shape so the sandbox engine can adapt it directly.
|
|
25
25
|
*/
|
|
26
26
|
export interface DockerProcess {
|
|
27
|
+
readonly stdin?: WritableStream<Uint8Array>;
|
|
27
28
|
readonly stdout: ReadableStream<Uint8Array>;
|
|
28
29
|
readonly stderr: ReadableStream<Uint8Array>;
|
|
29
30
|
wait(): Promise<{
|
|
@@ -42,6 +43,7 @@ export interface DockerCli {
|
|
|
42
43
|
/** Spawns `docker <args>` with streaming stdout/stderr. */
|
|
43
44
|
stream(args: readonly string[], options?: {
|
|
44
45
|
readonly signal?: AbortSignal;
|
|
46
|
+
readonly stdin?: boolean;
|
|
45
47
|
}): DockerProcess;
|
|
46
48
|
}
|
|
47
49
|
/**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Readable}from"node:stream";import{spawn,spawnSync}from"node:child_process";var DockerUnavailableError=class extends Error{hint="Install and start Docker Desktop, OrbStack, Colima, or another runtime exposing a Docker-compatible `docker` CLI (or point EVE_DOCKER_PATH at one, e.g. Podman). Alternatively use the dependency-free JustBashSandbox, VercelSandbox, or DefaultSandbox to pick by availability.";constructor(e){super("The Docker sandbox provider requires Docker, but the `docker` CLI was not found.",{cause:e}),this.name=`DockerUnavailableError`}},DockerDaemonUnavailableError=class extends Error{hint="Start Docker Desktop (or your Docker-compatible runtime) and retry. Alternatively use the dependency-free JustBashSandbox (installed automatically by `eve dev`, or `pnpm add -D just-bash`), VercelSandbox, or DefaultSandbox to pick by availability.";constructor(e){super(`The Docker sandbox provider requires a running Docker daemon, but it is not reachable. Docker reported: ${e}`),this.name=`DockerDaemonUnavailableError`}};async function assertDockerDaemonAvailable(e){let t=await e.run([`version`,`--format`,`{{.Server.Version}}`]);if(t.exitCode!==0)throw new DockerDaemonUnavailableError(firstLine(t.stderr)||`exit ${t.exitCode}`)}function resolveDockerExecutable(){let e=process.env.EVE_DOCKER_PATH?.trim();return e!==void 0&&e.length>0?e:`docker`}let cachedLinuxDockerAvailability;const LINUX_DOCKER_AVAILABILITY_ENV=`EVE_DEVELOPMENT_LINUX_DOCKER_AVAILABLE`;function isLinuxDockerDaemonAvailableSync(){return cachedLinuxDockerAvailability??=readAdoptedAvailability()??probeLinuxDockerDaemonSync(),cachedLinuxDockerAvailability}function peekLinuxDockerDaemonAvailability(){return cachedLinuxDockerAvailability}function readAdoptedAvailability(){let e=process.env[LINUX_DOCKER_AVAILABILITY_ENV];return e===`1`||e!==`0`&&void 0}function probeLinuxDockerDaemonSync(){try{let e=spawnSync(resolveDockerExecutable(),[`version`,`--format`,`{{.Server.Os}}`],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`],timeout:5e3});return e.status===0&&e.stdout.trim().toLowerCase()===`linux`}catch{return!1}}function createDockerCli(){return{async run(e,t={}){throwIfAborted(t.signal);let n=spawn(resolveDockerExecutable(),e,{signal:t.signal,stdio:[t.stdin===void 0?`ignore`:`pipe`,`pipe`,`pipe`]}),r=[],i=[];n.stdout?.on(`data`,e=>r.push(e)),n.stderr?.on(`data`,e=>i.push(e)),t.stdin!==void 0&&n.stdin?.end(t.stdin);let a=await new Promise((e,t)=>{n.on(`error`,e=>t(adaptSpawnError(e))),n.on(`close`,t=>e(t??1))}),o=Buffer.concat(r);return{exitCode:a,stderr:Buffer.concat(i).toString(`utf8`),stdout:o.toString(`utf8`),stdoutBytes:o}},stream(e,t={}){throwIfAborted(t.signal);let n=spawn(resolveDockerExecutable(),e,{signal:t.signal,stdio:[`
|
|
1
|
+
import{Readable,Writable}from"node:stream";import{spawn,spawnSync}from"node:child_process";var DockerUnavailableError=class extends Error{hint="Install and start Docker Desktop, OrbStack, Colima, or another runtime exposing a Docker-compatible `docker` CLI (or point EVE_DOCKER_PATH at one, e.g. Podman). Alternatively use the dependency-free JustBashSandbox, VercelSandbox, or DefaultSandbox to pick by availability.";constructor(e){super("The Docker sandbox provider requires Docker, but the `docker` CLI was not found.",{cause:e}),this.name=`DockerUnavailableError`}},DockerDaemonUnavailableError=class extends Error{hint="Start Docker Desktop (or your Docker-compatible runtime) and retry. Alternatively use the dependency-free JustBashSandbox (installed automatically by `eve dev`, or `pnpm add -D just-bash`), VercelSandbox, or DefaultSandbox to pick by availability.";constructor(e){super(`The Docker sandbox provider requires a running Docker daemon, but it is not reachable. Docker reported: ${e}`),this.name=`DockerDaemonUnavailableError`}};async function assertDockerDaemonAvailable(e){let t=await e.run([`version`,`--format`,`{{.Server.Version}}`]);if(t.exitCode!==0)throw new DockerDaemonUnavailableError(firstLine(t.stderr)||`exit ${t.exitCode}`)}function resolveDockerExecutable(){let e=process.env.EVE_DOCKER_PATH?.trim();return e!==void 0&&e.length>0?e:`docker`}let cachedLinuxDockerAvailability;const LINUX_DOCKER_AVAILABILITY_ENV=`EVE_DEVELOPMENT_LINUX_DOCKER_AVAILABLE`;function isLinuxDockerDaemonAvailableSync(){return cachedLinuxDockerAvailability??=readAdoptedAvailability()??probeLinuxDockerDaemonSync(),cachedLinuxDockerAvailability}function peekLinuxDockerDaemonAvailability(){return cachedLinuxDockerAvailability}function readAdoptedAvailability(){let e=process.env[LINUX_DOCKER_AVAILABILITY_ENV];return e===`1`||e!==`0`&&void 0}function probeLinuxDockerDaemonSync(){try{let e=spawnSync(resolveDockerExecutable(),[`version`,`--format`,`{{.Server.Os}}`],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`],timeout:5e3,windowsHide:!0});return e.status===0&&e.stdout.trim().toLowerCase()===`linux`}catch{return!1}}function createDockerCli(){return{async run(e,t={}){throwIfAborted(t.signal);let n=spawn(resolveDockerExecutable(),e,{signal:t.signal,stdio:[t.stdin===void 0?`ignore`:`pipe`,`pipe`,`pipe`],windowsHide:!0}),r=[],i=[];n.stdout?.on(`data`,e=>r.push(e)),n.stderr?.on(`data`,e=>i.push(e)),t.stdin!==void 0&&n.stdin?.end(t.stdin);let a=await new Promise((e,t)=>{n.on(`error`,e=>t(adaptSpawnError(e))),n.on(`close`,t=>e(t??1))}),o=Buffer.concat(r);return{exitCode:a,stderr:Buffer.concat(i).toString(`utf8`),stdout:o.toString(`utf8`),stdoutBytes:o}},stream(e,t={}){throwIfAborted(t.signal);let n=spawn(resolveDockerExecutable(),e,{signal:t.signal,stdio:[`pipe`,`pipe`,`pipe`],windowsHide:!0});t.stdin!==!0&&n.stdin.end();let r=new Promise((e,t)=>{n.on(`error`,e=>t(adaptSpawnError(e))),n.on(`close`,t=>e(t??1))});return r.catch(()=>{}),{stdin:t.stdin===!0?Writable.toWeb(n.stdin):void 0,stdout:Readable.toWeb(n.stdout),stderr:Readable.toWeb(n.stderr),async wait(){return{exitCode:await r}},async kill(){n.kill(`SIGKILL`),await r.catch(()=>{})}}}}}function adaptSpawnError(e){return e.code===`ENOENT`?new DockerUnavailableError(e):e.code===`ABORT_ERR`?new DOMException(`The operation was aborted.`,`AbortError`):e}function throwIfAborted(e){if(e?.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`)}function firstLine(e){return e.split(`
|
|
2
2
|
`,1)[0]?.trim()??``}export{DockerDaemonUnavailableError,DockerUnavailableError,LINUX_DOCKER_AVAILABILITY_ENV,assertDockerDaemonAvailable,createDockerCli,isLinuxDockerDaemonAvailableSync,peekLinuxDockerDaemonAvailability};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{randomUUID}from"node:crypto";import{shellQuote}from"#execution/sandbox/shell-quote.js";import{dirname}from"node:path/posix";import{stopDockerContainerIfRunning}from"#execution/sandbox/bindings/docker-container.js";import{setDockerNetworkPolicy}from"#execution/sandbox/bindings/docker-network.js";import{expectDockerSuccess}from"#execution/sandbox/bindings/docker-utils.js";const DOCKER_KILL_TREE_SCRIPT=[`pid_file="$1"`,`target="$(cat "$pid_file" 2>/dev/null)" || exit 0`,`[ -n "$target" ] || exit 0`,`kill_tree() {`,` local parent="$1" dir child ppid line`,` for dir in /proc/[0-9]*; do`,' child="${dir#/proc/}"',` ppid=""`,` while IFS= read -r line; do`,` case "$line" in`,' PPid:*) ppid="${line#PPid:}"; ppid="${ppid//[^0-9]/}"; break ;;',` esac`,` done < "$dir/status" 2>/dev/null`,` [ "$ppid" = "$parent" ] && kill_tree "$child"`,` done`,` kill -9 "$parent" 2>/dev/null`,`}`,`kill_tree "$target"`,`rm -f "$pid_file"`,`exit 0`].join(`
|
|
2
|
-
`);function createDockerConnection(e){let{cli:t,containerIdentity:n}=e;async function killSpawnTree(e){await t.run([`exec`,n,`bash`,`-c`,DOCKER_KILL_TREE_SCRIPT,`eve-kill-tree`,e]).catch(()=>{})}return{extensions:{setNetworkPolicy:e=>setDockerNetworkPolicy(t,n,e)},async spawn(e){let r=[`exec
|
|
2
|
+
`);function createDockerConnection(e){let{cli:t,containerIdentity:n}=e;async function killSpawnTree(e){await t.run([`exec`,n,`bash`,`-c`,DOCKER_KILL_TREE_SCRIPT,`eve-kill-tree`,e]).catch(()=>{})}return{extensions:{setNetworkPolicy:e=>setDockerNetworkPolicy(t,n,e)},async spawn(e){let r=[`exec`,...e.stdin===!0?[`-i`]:[],`-w`,e.workingDirectory];for(let[t,n]of Object.entries(e.env))r.push(`-e`,`${t}=${n}`);let i=`/tmp/.eve-sbx-spawn-${randomUUID()}.pid`,a=`echo "$$" > ${shellQuote(i)}; bash -lc ${shellQuote(e.command)}; status=$?; rm -f ${shellQuote(i)}; exit $status`;r.push(n,`bash`,`-c`,a);let o=t.stream(r,{signal:e.signal,stdin:e.stdin});return e.signal?.addEventListener(`abort`,()=>void killSpawnTree(i),{once:!0}),{stdin:o.stdin,stdout:o.stdout,stderr:o.stderr,async wait(){return await o.wait()},async kill(){await killSpawnTree(i),await o.kill()}}},async readFile(e){let r=shellQuote(e.path),i=await t.run([`exec`,n,`bash`,`-lc`,`if [ -e ${r} ]; then exec cat ${r}; else exit 43; fi`],{signal:e.signal});return i.exitCode===43?null:(expectDockerSuccess(i,`read "${e.path}" from sandbox container`),i.stdoutBytes)},async removePath(e){let r=`${e.recursive===!0?`r`:``}${e.force===!0?`f`:``}`,i=[`exec`,n,`rm`,...r.length>0?[`-${r}`]:[],`--`,e.path],a=await t.run(i,{signal:e.signal});expectDockerSuccess(a,`remove "${e.path}" from sandbox container`)},stop:()=>stopDockerContainerIfRunning(t,n),async writeFiles(e){for(let r of e.files){let i=await t.run([`exec`,`-i`,n,`bash`,`-lc`,`mkdir -p ${shellQuote(dirname(r.path))} && cat > ${shellQuote(r.path)}`],{signal:e.signal,stdin:r.content});expectDockerSuccess(i,`write "${r.path}" into sandbox container`)}}}}export{createDockerConnection};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mkdir,readFile,writeFile}from"node:fs/promises";import{isObject}from"#shared/guards.js";import{dirname}from"node:path";import{loadOptionalEnginePackage}from"#internal/application/optional-package-install.js";import{shellQuote}from"#execution/sandbox/shell-quote.js";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";import{SANDBOX_AGENT_ENV}from"#public/sandbox/provider.js";import{pathExists}from"#execution/sandbox/bindings/local-provider-utils.js";import{adaptMultiplexedCommandToSandboxProcess}from"#execution/sandbox/multiplexed-command.js";import{importOptionalEnginePackage}from"#internal/application/optional-package-import.js";const JUST_BASH_PACKAGE={importModule:async()=>await import(`just-bash`),missingMessage:"The just-bash sandbox provider requires the `just-bash` package, which is not bundled with eve. Install it in your application (for example `pnpm add -D just-bash`), or use DockerSandbox or DefaultSandbox instead.",packageName:`just-bash`};async function installJustBashModule(e){return await loadOptionalEnginePackage({...JUST_BASH_PACKAGE,appRoot:e.appRoot,autoInstall:e.autoInstall,ignoredOptionalDependencies:[`@mongodb-js/zstd`,`node-liblzma`]})}async function importJustBashModule(e){return await importOptionalEnginePackage({...JUST_BASH_PACKAGE,appRoot:e})}async function createBashSandbox(e){let{justBash:t}=e,n=resolveLocalSandboxFilesystemRootPath(e.rootPath),r=resolveLocalSandboxMetadataPath(e.rootPath),i=await readLocalMetadata(r);await mkdir(n,{recursive:!0});let a=new t.ReadWriteFs({allowSymlinks:!0,maxFileReadSize:2**53-1,root:n}),o=a;if(e.filesystem!==void 0)try{o=await e.filesystem({defaultFilesystem:a,resolveProjectPath:t=>e.resolveProjectPath(t),storagePath:e.storagePath,justBash:t})}catch(e){throw Error(`Failed to create the custom just-bash filesystem.`,{cause:e})}await o.mkdir(WORKSPACE_ROOT,{recursive:!0});let s=await t.Sandbox.create({cwd:WORKSPACE_ROOT,customCommands:[t.defineCommand(`realpath`,async(e,t)=>{let n=e.at(-1);if(e.length!==4||e[0]!==`-e`||e[1]!==`-z`||e[2]!==`--`||!n)return{stdout:``,stderr:`realpath: expected -e -z -- path`,exitCode:2};try{let e=await t.fs.realpath(n);return await t.fs.stat(e),{stdout:e+`\0`,stderr:``,exitCode:0}}catch(e){return{stdout:``,stderr:`realpath: ${String(e)}`,exitCode:1}}}),...e.customCommands??[]],env:i===null?void 0:{...i.env},fs:o,network:{dangerouslyAllowFullInternetAccess:!0}});return{async captureState(){await writeLocalMetadata(r,{env:{...s.bashEnvInstance.getEnv()},version:1})},async readFile({path:e}){try{return await o.readFileBuffer(e)}catch(t){if(!await o.exists(e))return null;throw t}},async removePath(e){await o.rm(e.path,{force:e.force,recursive:e.recursive})},async spawn(e){if(e.signal?.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`);let t=`( cd ${shellQuote(e.workingDirectory)} && {\n${e.command}\n} )`,n=await s.runCommand({args:[t],cmd:`eval`,detached:!0,env:{...SANDBOX_AGENT_ENV,...e.env},signal:e.signal});return adaptMultiplexedCommandToSandboxProcess({command:n,getOutput:e=>e.type})},async stop(){await s.stop()},async writeFiles({files:e}){for(let t of e)await o.mkdir(dirname(t.path),{recursive:!0}),await o.writeFile(t.path,t.content)}}}function resolveLocalSandboxFilesystemRootPath(e){return`${e}/fs`}function resolveLocalSandboxMetadataPath(e){return`${e}/metadata.json`}async function readLocalMetadata(e){if(!await pathExists(e))return null;let t=JSON.parse(await readFile(e,`utf8`));return!isObject(t)||t.version!==1||!isStringRecord(t.env)?null:{env:t.env,version:1}}async function writeLocalMetadata(e,t){await mkdir(dirname(e),{recursive:!0}),await writeFile(e,`${JSON.stringify(t,null,2)}\n`)}function isStringRecord(e){return isObject(e)&&Object.values(e).every(e=>typeof e==`string`)}export{createBashSandbox,importJustBashModule,installJustBashModule};
|
|
1
|
+
import{mkdir,readFile,writeFile}from"node:fs/promises";import{isObject}from"#shared/guards.js";import{dirname}from"node:path";import{loadOptionalEnginePackage}from"#internal/application/optional-package-install.js";import{shellQuote}from"#execution/sandbox/shell-quote.js";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";import{SANDBOX_AGENT_ENV}from"#public/sandbox/provider.js";import{pathExists}from"#execution/sandbox/bindings/local-provider-utils.js";import{adaptMultiplexedCommandToSandboxProcess}from"#execution/sandbox/multiplexed-command.js";import{importOptionalEnginePackage}from"#internal/application/optional-package-import.js";const JUST_BASH_PACKAGE={importModule:async()=>await import(`just-bash`),missingMessage:"The just-bash sandbox provider requires the `just-bash` package, which is not bundled with eve. Install it in your application (for example `pnpm add -D just-bash`), or use DockerSandbox or DefaultSandbox instead.",packageName:`just-bash`};async function installJustBashModule(e){return await loadOptionalEnginePackage({...JUST_BASH_PACKAGE,appRoot:e.appRoot,autoInstall:e.autoInstall,ignoredOptionalDependencies:[`@mongodb-js/zstd`,`node-liblzma`]})}async function importJustBashModule(e){return await importOptionalEnginePackage({...JUST_BASH_PACKAGE,appRoot:e})}async function createBashSandbox(e){let{justBash:t}=e,n=resolveLocalSandboxFilesystemRootPath(e.rootPath),r=resolveLocalSandboxMetadataPath(e.rootPath),i=await readLocalMetadata(r);await mkdir(n,{recursive:!0});let a=new t.ReadWriteFs({allowSymlinks:!0,maxFileReadSize:2**53-1,root:n}),o=a;if(e.filesystem!==void 0)try{o=await e.filesystem({defaultFilesystem:a,resolveProjectPath:t=>e.resolveProjectPath(t),storagePath:e.storagePath,justBash:t})}catch(e){throw Error(`Failed to create the custom just-bash filesystem.`,{cause:e})}await o.mkdir(WORKSPACE_ROOT,{recursive:!0});let s=await t.Sandbox.create({cwd:WORKSPACE_ROOT,customCommands:[t.defineCommand(`realpath`,async(e,t)=>{let n=e.at(-1);if(e.length!==4||e[0]!==`-e`||e[1]!==`-z`||e[2]!==`--`||!n)return{stdout:``,stderr:`realpath: expected -e -z -- path`,exitCode:2};try{let e=await t.fs.realpath(n);return await t.fs.stat(e),{stdout:e+`\0`,stderr:``,exitCode:0}}catch(e){return{stdout:``,stderr:`realpath: ${String(e)}`,exitCode:1}}}),...e.customCommands??[]],env:i===null?void 0:{...i.env},fs:o,network:{dangerouslyAllowFullInternetAccess:!0}});return{async captureState(){await writeLocalMetadata(r,{env:{...s.bashEnvInstance.getEnv()},version:1})},async readFile({path:e}){try{return await o.readFileBuffer(e)}catch(t){if(!await o.exists(e))return null;throw t}},async removePath(e){await o.rm(e.path,{force:e.force,recursive:e.recursive})},async spawn(e){if(e.signal?.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`);if(e.stdin===!0)throw Error("The just-bash sandbox does not support `stdin` on spawn yet.");let t=`( cd ${shellQuote(e.workingDirectory)} && {\n${e.command}\n} )`,n=await s.runCommand({args:[t],cmd:`eval`,detached:!0,env:{...SANDBOX_AGENT_ENV,...e.env},signal:e.signal});return adaptMultiplexedCommandToSandboxProcess({command:n,getOutput:e=>e.type})},async stop(){await s.stop()},async writeFiles({files:e}){for(let t of e)await o.mkdir(dirname(t.path),{recursive:!0}),await o.writeFile(t.path,t.content)}}}function resolveLocalSandboxFilesystemRootPath(e){return`${e}/fs`}function resolveLocalSandboxMetadataPath(e){return`${e}/metadata.json`}async function readLocalMetadata(e){if(!await pathExists(e))return null;let t=JSON.parse(await readFile(e,`utf8`));return!isObject(t)||t.version!==1||!isStringRecord(t.env)?null:{env:t.env,version:1}}async function writeLocalMetadata(e,t){await mkdir(dirname(e),{recursive:!0}),await writeFile(e,`${JSON.stringify(t,null,2)}\n`)}function isStringRecord(e){return isObject(e)&&Object.values(e).every(e=>typeof e==`string`)}export{createBashSandbox,importJustBashModule,installJustBashModule};
|
|
@@ -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,toVercelNetworkPolicy,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,{signal: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,networkPolicy:u,...d}=a??{},f=e.kind===`tool-session`,p={...n,...d,...u===void 0?{}:{networkPolicy:toVercelNetworkPolicy(u)},env:{...SANDBOX_AGENT_ENV,...d.env??n.env}},m=f?withToolSessionRetention(p):p,h=resolveVercelSandboxTags(m.tags,{sessionId:e.session.id}),g=await t(),_={createOptions:m,createSandbox:r,mounts:l===void 0?void 0:toVercelMounts(l),sandboxModule:g,sessionKey:s,snapshotId:c.snapshotId,tags:h};try{let t=await ensureUsableSession({expired:f?isVercelSnapshotNotFoundError:isVercelSnapshotUnavailableError,inheritsBaseRuntime:c.snapshotId!==void 0&&l===void 0&&i,input:_,session:await ensureSession(_)}),n=m.networkPolicy;if(t.created&&c.snapshotId===void 0&&n!==void 0)try{await applyInitialVercelNetworkPolicy(t.sandbox,n)}catch(n){try{await deleteNamedVercelSandbox({createOptions:m,sandboxModule:g,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.signal})},async spawn(t){let n=await e.runCommand({args:[`-lc`,t.command],cmd:`bash`,cwd:t.workingDirectory,detached:!0,env:t.env,signal:t.signal});return adaptMultiplexedCommandToSandboxProcess({abortSignal:t.signal,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.signal),{signal:t.signal})}}}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,toVercelNetworkPolicy,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,{signal: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,networkPolicy:u,...d}=a??{},f=e.kind===`tool-session`,p={...n,...d,...u===void 0?{}:{networkPolicy:toVercelNetworkPolicy(u)},env:{...SANDBOX_AGENT_ENV,...d.env??n.env}},m=f?withToolSessionRetention(p):p,h=resolveVercelSandboxTags(m.tags,{sessionId:e.session.id}),g=await t(),_={createOptions:m,createSandbox:r,mounts:l===void 0?void 0:toVercelMounts(l),sandboxModule:g,sessionKey:s,snapshotId:c.snapshotId,tags:h};try{let t=await ensureUsableSession({expired:f?isVercelSnapshotNotFoundError:isVercelSnapshotUnavailableError,inheritsBaseRuntime:c.snapshotId!==void 0&&l===void 0&&i,input:_,session:await ensureSession(_)}),n=m.networkPolicy;if(t.created&&c.snapshotId===void 0&&n!==void 0)try{await applyInitialVercelNetworkPolicy(t.sandbox,n)}catch(n){try{await deleteNamedVercelSandbox({createOptions:m,sandboxModule:g,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.signal})},async spawn(t){let n=await e.runCommand({args:[`-lc`,t.command],cmd:`bash`,cwd:t.workingDirectory,detached:!0,env:t.env,signal:t.signal,stdin:t.stdin});return adaptMultiplexedCommandToSandboxProcess({abortSignal:t.signal,command:n,getOutput:e=>e.stream,stdin:t.stdin===!0?n:void 0})},async stop(){await stopVercelSandbox(e)},async writeFiles(t){t.files.length!==0&&await e.writeFiles(await resolveVercelWriteFiles(e,t.files,t.signal),{signal:t.signal})}}}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};
|
|
@@ -13,10 +13,19 @@ interface MultiplexedCommand<Log extends {
|
|
|
13
13
|
readonly exitCode: number;
|
|
14
14
|
}>;
|
|
15
15
|
}
|
|
16
|
+
interface StdinCommand {
|
|
17
|
+
closeStdin(options: {
|
|
18
|
+
readonly abortSignal?: AbortSignal;
|
|
19
|
+
}): PromiseLike<void>;
|
|
20
|
+
writeStdin(data: Uint8Array, options: {
|
|
21
|
+
readonly abortSignal?: AbortSignal;
|
|
22
|
+
}): PromiseLike<void>;
|
|
23
|
+
}
|
|
16
24
|
/**
|
|
17
25
|
* Adapts a detached command with one tagged log iterator to a sandbox process
|
|
18
26
|
* with independent stdout and stderr streams. Aborting `abortSignal` kills the
|
|
19
|
-
* command and rejects `wait()` and both streams.
|
|
27
|
+
* command and rejects `wait()` and both streams. `stdin`, when given, backs
|
|
28
|
+
* the process's writable `stdin` stream.
|
|
20
29
|
*/
|
|
21
30
|
export declare function adaptMultiplexedCommandToSandboxProcess<Log extends {
|
|
22
31
|
readonly data: string;
|
|
@@ -24,5 +33,6 @@ export declare function adaptMultiplexedCommandToSandboxProcess<Log extends {
|
|
|
24
33
|
readonly abortSignal?: AbortSignal;
|
|
25
34
|
readonly command: MultiplexedCommand<Log>;
|
|
26
35
|
readonly getOutput: (log: Log) => OutputName;
|
|
36
|
+
readonly stdin?: StdinCommand;
|
|
27
37
|
}): SandboxProcess;
|
|
28
38
|
export {};
|
|
@@ -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{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
|
+
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 createStdinStream(e,t){let n;return new WritableStream({start(e){n=AbortSignal.any([...t,e.signal])},async write(t){await e.writeStdin(t,{abortSignal:n})},async close(){await e.closeStdin({abortSignal:n})},async abort(){let n=AbortSignal.any([...t]);n.aborted||await e.closeStdin({abortSignal: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,u=new AbortController,kill=()=>(u.abort(),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),{stdin:e.stdin===void 0?void 0:createStdinStream(e.stdin,t===void 0?[u.signal]:[u.signal,t]),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{bufferToStream,streamToBuffer}from"./stream-utils.js";import{posix}from"node:path";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";const SANDBOX_AGENT_ENV={AI_AGENT:`eve`};function createConnectionSession(e){let t=e.workspaceRoot??WORKSPACE_ROOT;if(!posix.isAbsolute(t))throw Error(`Sandbox connection workspaceRoot must be an absolute path, but received "${t}".`);let resolveSandboxPath=e=>posix.resolve(t,e);async function read(t){return await e.readFile({signal:t.signal,path:resolveSandboxPath(t.path)})}async function readBytes(e){let t=await read(e);return t===null?null:ArrayBuffer.isView(t)?Buffer.from(t):await streamToBuffer(t)}async function write(t,n){await e.writeFiles({signal:t.signal,files:[{content:n,path:resolveSandboxPath(t.path)}]})}async function spawn(t){
|
|
1
|
+
import{bufferToStream,streamToBuffer}from"./stream-utils.js";import{posix}from"node:path";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";const SANDBOX_AGENT_ENV={AI_AGENT:`eve`};function createConnectionSession(e){let t=e.workspaceRoot??WORKSPACE_ROOT;if(!posix.isAbsolute(t))throw Error(`Sandbox connection workspaceRoot must be an absolute path, but received "${t}".`);let resolveSandboxPath=e=>posix.resolve(t,e);async function read(t){return await e.readFile({signal:t.signal,path:resolveSandboxPath(t.path)})}async function readBytes(e){let t=await read(e);return t===null?null:ArrayBuffer.isView(t)?Buffer.from(t):await streamToBuffer(t)}async function write(t,n){await e.writeFiles({signal:t.signal,files:[{content:n,path:resolveSandboxPath(t.path)}]})}async function spawn(t){let n=await e.spawn({signal:t.signal,stdin:t.stdin,command:t.command,env:t.env??{},workingDirectory:resolveSandboxPath(t.workingDirectory??`.`)});if(t.stdin===!0&&n.stdin===void 0)throw await Promise.resolve(n.kill()).catch(()=>void 0),Error("This sandbox provider does not support `stdin` on spawn.");return n}let n={resolvePath:resolveSandboxPath,async run(e){let t=await spawn(e),[n,r,{exitCode:i}]=await Promise.all([collectStreamToString(t.stdout),collectStreamToString(t.stderr),t.wait()]);return{exitCode:i,stderr:r,stdout:n}},spawn,async readFile(e){let t=await read(e);return t===null||!ArrayBuffer.isView(t)?t:bufferToStream(new Uint8Array(t.buffer,t.byteOffset,t.byteLength))},readBinaryFile:e=>readBytes(e),async readTextFile(e){validateReadTextFileOptions(e);let t=await readBytes(e);return t===null?null:applyLineRange(decodeBytes(t,e.encoding??`utf-8`),e)},async writeFile(e){await write(e,await streamToBuffer(e.content))},async writeBinaryFile(e){await write(e,Buffer.from(e.content))},async writeTextFile(e){let t=e.encoding??`utf-8`;await write(e,Buffer.from(e.content,t))},async writeFiles(t){await e.writeFiles({signal:t.signal,files:t.files.map(e=>({content:e.content,path:resolveSandboxPath(e.path)}))})},async removePath(t){await e.removePath({signal:t.signal,force:t.force,path:resolveSandboxPath(t.path),recursive:t.recursive})}},r=e.extensions??{},i=Object.keys(r).filter(e=>Object.hasOwn(n,e)||e===`delete`||e===`stop`);if(i.length>0)throw Error(`Sandbox connection extensions cannot replace the session members eve provides: ${i.join(`, `)}. Rename them.`);return{...r,...n}}async function collectStreamToString(e){let t=await streamToBuffer(e);return new TextDecoder().decode(t)}function validateReadTextFileOptions(e){let{startLine:t,endLine:n}=e;if(t!==void 0&&(!Number.isInteger(t)||t<1))throw Error(`startLine must be a positive integer (1-based).`);if(n!==void 0&&(!Number.isInteger(n)||n<1))throw Error(`endLine must be a positive integer (1-based).`);if(t!==void 0&&n!==void 0&&t>n)throw Error(`startLine must not be greater than endLine.`)}function splitLinesPreservingEndings(e){let t=[],n=0;for(let r=0;r<e.length;r++)e[r]===`\r`?r+1<e.length&&e[r+1]===`
|
|
2
2
|
`?(t.push(e.slice(n,r+2)),n=r+2,r++):(t.push(e.slice(n,r+1)),n=r+1):e[r]===`
|
|
3
3
|
`&&(t.push(e.slice(n,r+1)),n=r+1);return n<e.length&&t.push(e.slice(n)),t}function applyLineRange(e,t){if(t.startLine===void 0&&t.endLine===void 0)return e;let n=splitLinesPreservingEndings(e),r=n.length,i=t.startLine??1,a=Math.min(t.endLine??r,r);return i>r?``:n.slice(i-1,a).join(``)}function decodeBytes(e,t){return t===`utf-8`||t===`utf8`?new TextDecoder(`utf-8`,{fatal:!0}).decode(e):Buffer.from(e.buffer,e.byteOffset,e.byteLength).toString(t)}export{SANDBOX_AGENT_ENV,createConnectionSession};
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import { type SessionCheckpoint } from "#execution/session/handoff.js";
|
|
2
|
+
import { type PreV27Checkpoint } from "#execution/session/pre-v27-checkpoint.js";
|
|
2
3
|
/**
|
|
3
|
-
* Oldest checkpoint a successor
|
|
4
|
-
*
|
|
5
|
-
* stream's lines, projection, and private records of running work changed shape together
|
|
4
|
+
* Oldest checkpoint a successor upgrades in place: the first that writes v27 session events.
|
|
5
|
+
* Older ones, from an owner before v27, are imported instead (`pre-v27-checkpoint.ts`): their
|
|
6
|
+
* stream's lines, projection, and private records of running work changed shape together, so the
|
|
7
|
+
* successor also folds their stream before it continues.
|
|
6
8
|
*/
|
|
7
9
|
export declare const MIN_SESSION_CHECKPOINT_VERSION = 18;
|
|
8
10
|
export type SessionCheckpointMigration = {
|
|
9
11
|
readonly kind: "current";
|
|
10
12
|
readonly checkpoint: SessionCheckpoint;
|
|
13
|
+
}
|
|
14
|
+
/** A checkpoint from an owner before v27, still without the projection its stream holds. */
|
|
15
|
+
| {
|
|
16
|
+
readonly kind: "pre-v27";
|
|
17
|
+
readonly imported: PreV27Checkpoint;
|
|
18
|
+
}
|
|
19
|
+
/** An owner before v27 still runs work for the session; a later delivery can move it. */
|
|
20
|
+
| {
|
|
21
|
+
readonly kind: "busy";
|
|
22
|
+
readonly detail: string;
|
|
11
23
|
} | {
|
|
12
24
|
readonly kind: "incompatible";
|
|
13
25
|
readonly detail: string;
|
|
@@ -15,7 +27,6 @@ export type SessionCheckpointMigration = {
|
|
|
15
27
|
/**
|
|
16
28
|
* Upgrades a checkpoint written by an older eve build to the current shape.
|
|
17
29
|
* Pure, so the session workflow can run it before validation. Newer
|
|
18
|
-
* checkpoints and those older than
|
|
19
|
-
* incompatible.
|
|
30
|
+
* checkpoints and those older than eve 0.69 are incompatible.
|
|
20
31
|
*/
|
|
21
32
|
export declare function migrateSessionCheckpoint(checkpoint: unknown): SessionCheckpointMigration;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isObject}from"#shared/guards.js";import{DELIVERY_IDEMPOTENCY_WINDOW,MAX_DELIVERY_IDEMPOTENCY_KEY_LENGTH}from"#channel/delivery-idempotency.js";import{SESSION_CHECKPOINT_VERSION}from"#execution/session/handoff.js";const MIN_SESSION_CHECKPOINT_VERSION=18,CHECKPOINT_UPGRADES={};function migrateSessionCheckpoint(e){if(!isObject(e))return{kind:`incompatible`,detail:`checkpoint is not an object`};let{version:t}=e;if(
|
|
1
|
+
import{isObject}from"#shared/guards.js";import{DELIVERY_IDEMPOTENCY_WINDOW,MAX_DELIVERY_IDEMPOTENCY_KEY_LENGTH}from"#channel/delivery-idempotency.js";import{SESSION_CHECKPOINT_VERSION}from"#execution/session/handoff.js";import{importPreV27Checkpoint,isPreV27CheckpointVersion}from"#execution/session/pre-v27-checkpoint.js";import{CheckpointRefusal,refuse}from"#execution/session/checkpoint-refusal.js";const MIN_SESSION_CHECKPOINT_VERSION=18,CHECKPOINT_UPGRADES={};function migrateSessionCheckpoint(e){if(!isObject(e))return{kind:`incompatible`,detail:`checkpoint is not an object`};let{version:t}=e;if(isPreV27CheckpointVersion(t)){let n=importPreV27Checkpoint({...e,version:t});if(n.kind!==`pre-v27`)return n;let{imported:r}=n;return isCurrentCheckpoint(r.checkpoint)?{kind:`pre-v27`,imported:{...r,checkpoint:r.checkpoint}}:{kind:`incompatible`,detail:`checkpoint version ${t} is incomplete`}}if(typeof t!=`number`||!Number.isSafeInteger(t)||t<18||t>SESSION_CHECKPOINT_VERSION)return{kind:`incompatible`,detail:`checkpoint version ${JSON.stringify(t)} is outside the supported ranges: 10-17 import, 18-${SESSION_CHECKPOINT_VERSION} upgrade`};let n=e;try{for(let e=t;e<SESSION_CHECKPOINT_VERSION;e++){let t=CHECKPOINT_UPGRADES[e];t===void 0&&refuse(`no upgrade from checkpoint version ${e}`),n={...t(n),version:e+1}}}catch(e){if(!(e instanceof CheckpointRefusal))throw e;return{kind:`incompatible`,detail:`checkpoint version ${t}: ${e.message}`}}return isCurrentCheckpoint(n)?{kind:`current`,checkpoint:n}:{kind:`incompatible`,detail:`checkpoint version ${t} is incomplete`}}function isCurrentCheckpoint(e){return isObject(e)&&e.version===SESSION_CHECKPOINT_VERSION&&Array.isArray(e.admittedDeliveryKeys)&&e.admittedDeliveryKeys.length<=DELIVERY_IDEMPOTENCY_WINDOW&&e.admittedDeliveryKeys.every(e=>typeof e==`string`&&e.length>0&&e.length<=MAX_DELIVERY_IDEMPOTENCY_KEY_LENGTH)&&Array.isArray(e.history)&&isObject(e.serializedContext)&&isObject(e.sessionState)}export{MIN_SESSION_CHECKPOINT_VERSION,migrateSessionCheckpoint};
|