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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# eve
|
|
2
2
|
|
|
3
|
+
## 0.85.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 24c6b9f: Client requests now reject redirects by default, including session writes and event streams. Update redirecting base URLs to their final destination, use `redirect: "manual"` to stop at redirects, or explicitly opt into `"follow"` only when every redirect destination is trusted.
|
|
8
|
+
- c8328f8: Protected cross-project callbacks now require reciprocal Vercel Trusted Sources and an explicit `EVE_CALLBACK_TRUSTED_ORIGINS` allowlist on the remote deployment. Callback URLs no longer include the parent's deployment-wide bypass secret; listed origins instead receive the remote's short-lived OIDC credential.
|
|
9
|
+
- 5cfec0e: Slack renderers can restyle approval, question, and budget prompt cards with a new `interactionCard(card, next)` hook, while eve keeps routing, batching, action IDs, and card updates. Cards now update from the session for every request kind, so a question answered by a typed reply or withdrawn, or a settled budget prompt, no longer keeps live buttons.
|
|
10
|
+
|
|
11
|
+
Breaking changes:
|
|
12
|
+
|
|
13
|
+
- `SlackChannelState.pendingApprovalCards` is replaced by `interactionCards`. Cards posted before the upgrade keep their buttons.
|
|
14
|
+
- `SlackTaskCard` is renamed to `SlackCardMessage`, which both `taskCard` and `interactionCard` return.
|
|
15
|
+
- Clicking a question no longer rewrites its card from the webhook. The buttons stay until the session admits the answer, and apps that post eve's controls themselves no longer get that rewrite.
|
|
16
|
+
- An approval's buttons disappear once its answer is admitted, so a later click can't change it. A denied approval reads **Deny** instead of **Cancel**, and a direct-message request's thread note reports the same outcome as its card.
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- f20a7a1: Bind native Teams activities to the verified Bot Connector token's service URL before dispatch. Connector requests require HTTPS and reject redirects, keeping bearer credentials on the validated destination.
|
|
21
|
+
- 4f290a7: Sessions whose deployment runs eve 0.69 through 0.83 now move to a v27 deployment the next time they receive a message while idle, or earlier when a channel prepares them for the next message, instead of staying on their original deployment until they time out. eve compacts the earlier conversation as the session moves, so the model continues from a summary; the stored transcript stays intact, and new turns continue after it. Remembered tool approvals and usage limits start over.
|
|
22
|
+
- 0553a67: Keep continuation capabilities out of session lookup and child-interaction failure logs, including capability values embedded in error messages and causes. Failure diagnostics retain correlation fields and non-secret error details.
|
|
23
|
+
- e54f078: Render Teams mention display names and fallback IDs as literal text, preserving names that contain ampersands or angle brackets without changing mention identity.
|
|
24
|
+
- ba52da4: Remove the deprecated internal setup type alias `RunPnpmOptions`. Setup tooling should use `RunPackageManagerOptions`; package-manager command behavior is unchanged.
|
|
25
|
+
- 5b8a34b: `to(channel, target).send()`, Slack's `onEvent` `ctx.send()`, dynamic schedules' `to().send()`, and channel `receive` hooks now accept the same options as `from(address).send()`, including `history`, `idempotencyKey`, and `title`. Slack derives a threadless target's session from `idempotencyKey`, and a dynamic schedule's keyed send reaches the session its earlier attempt started, so a retried send no longer starts a second thread or session.
|
|
26
|
+
- 6ea94da: Set `codeChannels: true` on `slackChannel()` to serve Slack code channels as one session per channel. The agent answers un-mentioned messages, replies top-level or in the thread a person wrote in, and follows Slack's session status and stop. The option also adds the code channel scopes and events to the app manifest. A code channel session has no thread: `threadTs` is empty or `null`, and `ctx.slack.codeChannel` marks it. Address its session with `{ channelId, codeChannel: true }` in `onEvent` targets, or with `slackCodeChannelContinuationToken(channelId)`.
|
|
27
|
+
|
|
28
|
+
Two changes also reach agents that don't enable code channels: a cancelled turn now clears the Slack thread status by default, and `SlackSessionTarget` is now a union, so code that reads `target.threadTs` must handle the `{ channelId, codeChannel: true }` variant. `SlackHandle` also gains a required `codeChannel` field, which affects code that builds a handle by hand.
|
|
29
|
+
- 2764e1e: Add `openCodeChannel(ctx, slack, message, { name })` to `eve/channels/slack`, which a tool calls to move the Slack conversation it was called from into a new Slack code channel and continue the work there with the conversation so far. Wrap it in your own tool with your own description and inputs, and pass your Slack channel. It finds the conversation from `ctx.channel`, so it works when message hooks return their own auth. To write your own variant, Slack receive targets accept `codeChannel`. Message hooks can open a code channel without the model through `ctx.openCodeChannel()`.
|
|
30
|
+
- cb14c32: Reject framework-owned adapter attachment references in HTTP messages and restrict Linq attachment downloads to bounded public HTTPS destinations. Thanks to HackerOne researcher ryota for reporting the attachment-reference boundary issue.
|
|
31
|
+
- 412b077: Tools can start or reach sessions on the agent's channels with `ctx.to(channel, target).send(message, options)`, the same call route handlers and schedules use, such as forking a conversation into a new Slack thread. Ordinary tools call it directly, and workflow tools call it in a `"use step"` helper. Pass `` idempotencyKey: `${ctx.session.id}:${ctx.callId}` `` so a retried call reaches the same session once. `ctx.to()` throws in a subagent, a root copy, or a remote agent call. Tools also get `ctx.channel`, the calling session's channel `kind`, `continuationToken`, and `metadata`, as hooks and dynamic resolvers read it.
|
|
32
|
+
|
|
33
|
+
## 0.84.1
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- 41916a5: Dynamic models, dynamic subagent configs, and `ctx.agent(name, { model })` overrides now read context windows from the AI Gateway model catalog recorded at build time instead of downloading it at runtime; a model that catalog doesn't list fails until you return `modelContextWindowTokens` or rebuild. Builds no longer carry built-in limits for `anthropic/claude-opus-4.7`, `openai/gpt-5.4`, and `openai/gpt-5.4-mini`, so a static model needs the catalog, a cached copy, or `modelContextWindowTokens` to compile offline.
|
|
38
|
+
- b322096: A compaction that fails during a turn, for example on a provider 429 that outlasts its retries, now fails that turn with `MODEL_CALL_FAILED` and leaves the session waiting with its history uncompacted. Previously the error escaped the turn step, so eve replayed the step and then ended the session. Thanks @gshost1 for the report and reproduction in #5350.
|
|
39
|
+
- 4276727: Messages a route forwards with `ctx.to()` now carry the deployment and request that accepted them, so an idle session reached that way hands off to the new deployment like one reached with `from()`. Thanks @haydenbleasel for reporting this in #5408.
|
|
40
|
+
- bea10fd: Model calls that AI Gateway rejects with a 402 because it temporarily throttled the credit balance check now retry with backoff. They previously reported "AI Gateway credit balance exhausted", told users to add credits, and parked the session without retrying.
|
|
41
|
+
- 105bf60: `eve init apps/my-agent` now creates missing parent directories such as `apps/` instead of failing with `ENOENT` from `mkdtemp`. Thanks @otakusboy for reporting this in #5422.
|
|
42
|
+
- 5bb6d43: Nuxt apps that call the auto-imported `useEveAgent()` now hydrate in `nuxt dev`. The `eve/nuxt` module pre-bundles `eve/vue` with Vite, which previously served its CommonJS dependencies to the browser unbundled and failed with `does not provide an export named 'getContext'`.
|
|
43
|
+
- cb1db12: Sending a message from a web client served over plain HTTP on a host other than `localhost` no longer fails with `crypto.randomUUID is not a function`. Thanks @KingAmo for reporting this in #5415.
|
|
44
|
+
- 5458bc4: Reuse signed inbox routing information between client turns when the Workflow SDK and adapter support guarded resumes and `EVE_INBOX_HANDLE_SECRET` is configured. Refresh stale routing after a confirmed refusal without retrying uncertain deliveries.
|
|
45
|
+
- a5328b4: `sandbox.spawn({ stdin: true })` returns a process with a writable `stdin` stream; closing it sends EOF. The Vercel and Docker sandboxes support it, and just-bash and custom providers without stdin support reject the call.
|
|
46
|
+
- 66103be: `eve dev` on Windows no longer opens a console window for each Docker command, dev build process, or optional package install. Thanks @satish860 for reporting this in #5291.
|
|
47
|
+
- 040519a: The browser client no longer triggers a Content Security Policy `eval` violation on pages whose `script-src` omits `'unsafe-eval'`. eve's bundled Zod now skips its `Function("")` probe and always uses its interpreted parser. Your app's own Zod and `z.config()` are not affected. Thanks @wasimxyz for reporting this in #5365.
|
|
48
|
+
|
|
3
49
|
## 0.84.0
|
|
4
50
|
|
|
5
51
|
### Minor Changes
|
|
@@ -4,29 +4,13 @@ import type { ChannelAdapter } from "#channel/adapter.js";
|
|
|
4
4
|
import type { ChannelDeliverySource } from "#channel/delivery-metadata.js";
|
|
5
5
|
import { type ChannelCreateResult } from "#channel/channel-address.js";
|
|
6
6
|
export type { ChannelCreateResult } from "#channel/channel-address.js";
|
|
7
|
-
import type { Session } from "#channel/session.js";
|
|
7
|
+
import type { SessionSendOptions, Session } from "#channel/session.js";
|
|
8
8
|
import type { Runtime, SessionAuthContext, TurnPolicy, SessionControlOptions } from "#channel/types.js";
|
|
9
9
|
import { type Answer, type StrictAnswers } from "#shared/input.js";
|
|
10
10
|
import type { JsonObject } from "#shared/json.js";
|
|
11
11
|
import type { SessionHistoryMessage } from "#shared/session-history.js";
|
|
12
|
-
interface BaseChannelSendOptions {
|
|
13
|
-
/** Stable delivery identity, deduplicated within this session's recent-key window. */
|
|
14
|
-
readonly idempotencyKey?: string;
|
|
15
|
-
/**
|
|
16
|
-
* Prior conversation added as user and assistant turns before this
|
|
17
|
-
* message and its `context`. Seeds a session this send creates, or
|
|
18
|
-
* extends the history of the session that owns the address.
|
|
19
|
-
*/
|
|
20
|
-
readonly history?: readonly SessionHistoryMessage[];
|
|
21
|
-
readonly auth: SessionAuthContext | null;
|
|
22
|
-
readonly context?: readonly string[];
|
|
23
|
-
/** JSON Schema for a structured final answer, as on `Session.send()`. */
|
|
24
|
-
readonly outputSchema?: JsonObject;
|
|
25
|
-
readonly title?: string;
|
|
26
|
-
readonly turnPolicy?: TurnPolicy;
|
|
27
|
-
}
|
|
28
12
|
/** Options for sending a message from a channel-local continuation address. */
|
|
29
|
-
export type ChannelSendOptions<TState = undefined> =
|
|
13
|
+
export type ChannelSendOptions<TState = undefined> = SessionSendOptions & {
|
|
30
14
|
readonly state?: Partial<TState>;
|
|
31
15
|
};
|
|
32
16
|
interface BaseChannelRespondOptions<TState = undefined> {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ChannelAdapter } from "#channel/adapter.js";
|
|
2
|
-
import type { MessageContent } from "#shared/message-content.js";
|
|
3
2
|
import type { ChannelReceiveContext } from "#channel/channel-operations.js";
|
|
4
3
|
import type { NormalizedChannelCorsOptions } from "#channel/cors.js";
|
|
5
4
|
import type { TypedReceiveTarget } from "#channel/receive-target.js";
|
|
6
5
|
import type { RouteDefinition } from "#channel/routes.js";
|
|
7
6
|
import type { Delivery } from "#shared/delivery.js";
|
|
8
|
-
import type {
|
|
7
|
+
import type { TurnPolicy } from "#channel/types.js";
|
|
8
|
+
import type { GenericReceiveInput } from "#shared/channel-definition.js";
|
|
9
9
|
import type { JsonObject } from "#shared/json.js";
|
|
10
10
|
export declare const CHANNEL_SENTINEL: "eve:channel";
|
|
11
11
|
interface ChannelBuildMetadata {
|
|
@@ -22,11 +22,7 @@ export interface CompiledChannel<TState = undefined, TReceiveTarget = Record<str
|
|
|
22
22
|
readonly adapter: ChannelAdapter<any>;
|
|
23
23
|
readonly cors?: NormalizedChannelCorsOptions;
|
|
24
24
|
readonly __metadata?: TMetadata;
|
|
25
|
-
readonly receive?: (input:
|
|
26
|
-
readonly message: MessageContent;
|
|
27
|
-
readonly target: Readonly<TReceiveTarget>;
|
|
28
|
-
readonly auth: SessionAuthContext | null;
|
|
29
|
-
}, ctx: ChannelReceiveContext<TState>) => Promise<Delivery>;
|
|
25
|
+
readonly receive?: (input: GenericReceiveInput<TReceiveTarget>, ctx: ChannelReceiveContext<TState>) => Promise<Delivery>;
|
|
30
26
|
readonly turnPolicy?: TurnPolicy;
|
|
31
27
|
}
|
|
32
28
|
export declare function isCompiledChannel(value: unknown): value is CompiledChannel;
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import type { MessageContent } from "#shared/message-content.js";
|
|
2
2
|
import type { ChannelAdapter } from "#channel/adapter.js";
|
|
3
3
|
import { type ChannelReference, type CompiledChannel } from "#channel/compiled-channel.js";
|
|
4
|
+
import type { ChannelDeliverySource } from "#channel/delivery-metadata.js";
|
|
4
5
|
import type { InferReceiveTarget } from "#channel/receive-target.js";
|
|
6
|
+
import { type SessionSendOptions } from "#channel/session.js";
|
|
5
7
|
import type { Delivery } from "#shared/delivery.js";
|
|
6
|
-
import type { Runtime
|
|
8
|
+
import type { Runtime } from "#channel/types.js";
|
|
7
9
|
import type { ResolvedChannelDefinition } from "#runtime/types.js";
|
|
8
|
-
/**
|
|
9
|
-
* Options for sending a message to a channel selected with `ctx.to(...)`.
|
|
10
|
-
*/
|
|
11
|
-
interface CrossChannelSendOptions {
|
|
12
|
-
readonly auth: SessionAuthContext | null;
|
|
13
|
-
readonly turnPolicy?: TurnPolicy;
|
|
14
|
-
}
|
|
15
10
|
/** Message delivery bound to one channel-specific proactive target. */
|
|
16
11
|
export interface CrossChannelTargetHandle {
|
|
17
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Starts a session at the target, or continues the one that owns it. The
|
|
14
|
+
* channel's `receive()` hook gets `options` with the message and target.
|
|
15
|
+
*/
|
|
16
|
+
send(message: MessageContent, options: SessionSendOptions): Promise<Delivery>;
|
|
18
17
|
}
|
|
19
18
|
/** Selects another authored channel and one of its proactive targets. */
|
|
20
19
|
export type CrossChannelToFn = <TChannel extends ChannelReference<unknown>>(channel: TChannel, target: InferReceiveTarget<TChannel>) => CrossChannelTargetHandle;
|
|
@@ -30,6 +29,8 @@ export interface CrossChannelTarget {
|
|
|
30
29
|
readonly adapter?: ChannelAdapter;
|
|
31
30
|
readonly turnPolicy?: CompiledChannel["turnPolicy"];
|
|
32
31
|
}
|
|
32
|
+
/** What a forwarded delivery inherits from the caller; the target channel supplies its own name. */
|
|
33
|
+
type CrossChannelDeliverySource = Omit<ChannelDeliverySource, "channelKind" | "channelName">;
|
|
33
34
|
/**
|
|
34
35
|
* Projects an agent's resolved channels into the receiver-input shape.
|
|
35
36
|
*
|
|
@@ -39,7 +40,8 @@ export interface CrossChannelTarget {
|
|
|
39
40
|
*/
|
|
40
41
|
export declare function toCrossChannelTargets(channels: readonly ResolvedChannelDefinition[]): readonly CrossChannelTarget[];
|
|
41
42
|
/**
|
|
42
|
-
* Builds the `ctx.to(channel, target)` closure used by route and schedule
|
|
43
|
+
* Builds the `ctx.to(channel, target)` closure used by route and schedule
|
|
44
|
+
* handlers and tools.
|
|
43
45
|
*/
|
|
44
|
-
export declare function createCrossChannelToFn(runtime: Runtime, channels: readonly CrossChannelTarget[]): CrossChannelToFn;
|
|
46
|
+
export declare function createCrossChannelToFn(runtime: Runtime, channels: readonly CrossChannelTarget[], source?: CrossChannelDeliverySource): CrossChannelToFn;
|
|
45
47
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createChannelOperations}from"#channel/channel-operations.js";import{isCompiledChannel}from"#channel/compiled-channel.js";function toCrossChannelTargets(e){return e.flatMap(e=>e.definition===void 0?[]:[{name:e.name,definition:e.definition,receive:e.receive,adapter:e.adapter,turnPolicy:e.turnPolicy}])}function createCrossChannelToFn(e,t){return(
|
|
1
|
+
import{toSessionSendOptions}from"#channel/session.js";import{createChannelOperations}from"#channel/channel-operations.js";import{isCompiledChannel}from"#channel/compiled-channel.js";function toCrossChannelTargets(e){return e.flatMap(e=>e.definition===void 0?[]:[{name:e.name,definition:e.definition,receive:e.receive,adapter:e.adapter,turnPolicy:e.turnPolicy}])}function createCrossChannelToFn(e,t,n={}){return(r,i)=>{let a=resolveTargetByReference(r,t);return{async send(t,r){return await invokeChannelReceive({runtime:e,source:n,target:a,input:{...toSessionSendOptions(r),message:t,target:i},turnPolicy:r.turnPolicy})}}}}async function invokeChannelReceive(e){let{name:t}=e.target;if(!e.target.receive)throw Error(`ctx.to(): channel "${t}" does not implement receive(). Declare a receive hook on the channel to accept cross-channel sessions.`);if(!e.target.adapter)throw Error(`ctx.to(): channel "${t}" has no adapter — cannot build ctx.from().`);let n=createChannelOperations({adapter:e.target.adapter,channelName:t,metadata:{...e.source,channelKind:`channel:${t}`,channelName:t},runtime:e.runtime,turnPolicy:e.turnPolicy??e.target.turnPolicy});return await e.target.receive(e.input,n)}function resolveTargetByReference(e,t){for(let n of t)if(n.definition===e)return n;let n=resolveTargetByRouteFingerprint(e,t);if(n!==null)return n;throw Error(`ctx.to(): the channel passed as the first argument is not registered in this agent's channels/. Import the channel module's default export from agent/channels/<name>.ts and pass that value.`)}function resolveTargetByRouteFingerprint(e,t){if(!isCompiledChannel(e))return null;let n=createRouteFingerprint(e);if(n===null)return null;let r=new Map;for(let e of t)createRouteFingerprint(e.definition)===n&&r.set(e.name,e);if(r.size===1)return[...r.values()][0];if(r.size>1)throw Error(`ctx.to(): the channel passed as the first argument matches multiple registered channels by route shape. Import a channel with a unique route set from agent/channels/<name>.ts before passing it to ctx.to().`);return null}function createRouteFingerprint(e){return e.routes.length===0?null:e.routes.map(e=>`${e.method.toUpperCase()} ${e.path}`).sort().join(`
|
|
2
2
|
`)}export{createCrossChannelToFn,toCrossChannelTargets};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{SessionNotActiveError}from"#channel/session-not-active-error.js";import{StreamDelivery}from"#client/delivery.js";import{deliveryEvents}from"#client/delivery-events.js";function commandDelivery(e,t,n,r={}){if(t.status!==`accepted`&&t.status!==`reset`)throw new SessionNotActiveError({retryable:`retryable`in t&&t.retryable===!0});let i=t.status===`reset`?t.previousSessionId:t.sessionId;return new StreamDelivery({sessionId:i,deliveryId:n,createStream:async function*(t){yield*deliveryEvents(await e.getEventStream(i,{...r,signal:t?.signal}),n,t?.signal)}})}export{commandDelivery};
|
|
1
|
+
import{SessionNotActiveError}from"#channel/session-not-active-error.js";import{StreamDelivery}from"#client/delivery.js";import{deliveryEvents}from"#client/delivery-events.js";function commandDelivery(e,t,n,r={}){if(t.status!==`accepted`&&t.status!==`reset`)throw new SessionNotActiveError({retryable:`retryable`in t&&t.retryable===!0});let i=t.status===`reset`?t.previousSessionId:t.sessionId;return new StreamDelivery({inbox:`inbox`in t?t.inbox:void 0,sessionId:i,deliveryId:n,createStream:async function*(t){yield*deliveryEvents(await e.getEventStream(i,{...r,signal:t?.signal}),n,t?.signal)}})}export{commandDelivery};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID}from"node:crypto";import{commandDelivery}from"#channel/delivery.js";import{createChannelDeliveryMetadata}from"#channel/delivery-metadata.js";import{scheduleDisplayName}from"#runtime/schedules/record.js";import{SCHEDULE_APP_AUTH,SCHEDULE_APP_AUTH as SCHEDULE_APP_AUTH$1}from"#channel/schedule-auth.js";import{createCrossChannelToFn,toCrossChannelTargets}from"#channel/cross-channel-receive.js";import{ContextContainer,contextStorage}from"#context/container.js";import{AuthKey,OccurrenceIdKey,ScheduleIdKey,ScheduleInstanceKey}from"#context/keys.js";import{expectFunction}from"#internal/authored-module.js";import{parseSchedulePayload,validateSchedulePayload}from"#runtime/schedules/payload.js";const SCHEDULE_ADAPTER_KIND=`schedule`,SCHEDULE_ADAPTER={kind:SCHEDULE_ADAPTER_KIND};var ScheduleDispatcher=class{runtime;channels;constructor(e){this.runtime=e.runtime,this.channels=e.channels}async trigger(e){let t=new ContextContainer;return t.set(ScheduleIdKey,e.scheduleId),await contextStorage.run(t,()=>this.triggerInScope(e))}async triggerCollection(e){let{envelope:t}=parseSchedulePayload(e.payload,{application:e.payload.eve.application,collection:e.collectionId}),{definition:n}=e,r={...e.occurrence,displayName:scheduleDisplayName(e.occurrence.name)},i=n.preparePayload===void 0?await validateSchedulePayload(n.inputSchema,t.payload):t.payload;await e.verifyDelivery?.();let a=await n.auth({principal:t.principal,payload:i,occurrence:r});if(a===null)throw Error(`Scheduled execution is no longer authorized.`);if(a.principalId!==t.principal.principalId||a.principalType!==t.principal.type||a.authenticator!==t.principal.authenticator||a.issuer!==t.principal.issuer||a.subject!==t.principal.subject)throw Error(`Scheduled execution auth must resolve the schedule creator.`);let o=a,s=new ContextContainer;
|
|
1
|
+
import{createHash,randomUUID}from"node:crypto";import{commandDelivery}from"#channel/delivery.js";import{createChannelDeliveryMetadata}from"#channel/delivery-metadata.js";import{scheduleDisplayName}from"#runtime/schedules/record.js";import{SCHEDULE_APP_AUTH,SCHEDULE_APP_AUTH as SCHEDULE_APP_AUTH$1}from"#channel/schedule-auth.js";import{createCrossChannelToFn,toCrossChannelTargets}from"#channel/cross-channel-receive.js";import{ContextContainer,contextStorage}from"#context/container.js";import{AuthKey,OccurrenceIdKey,ScheduleIdKey,ScheduleInstanceKey}from"#context/keys.js";import{expectFunction}from"#internal/authored-module.js";import{parseSchedulePayload,validateSchedulePayload}from"#runtime/schedules/payload.js";const SCHEDULE_ADAPTER_KIND=`schedule`,SCHEDULE_ADAPTER={kind:SCHEDULE_ADAPTER_KIND};var ScheduleDispatcher=class{runtime;channels;constructor(e){this.runtime=e.runtime,this.channels=e.channels}async trigger(e){let t=new ContextContainer;return t.set(ScheduleIdKey,e.scheduleId),await contextStorage.run(t,()=>this.triggerInScope(e))}async triggerCollection(e){let{envelope:t}=parseSchedulePayload(e.payload,{application:e.payload.eve.application,collection:e.collectionId}),{definition:n}=e,r={...e.occurrence,displayName:scheduleDisplayName(e.occurrence.name)},i=n.preparePayload===void 0?await validateSchedulePayload(n.inputSchema,t.payload):t.payload;await e.verifyDelivery?.();let a=await n.auth({principal:t.principal,payload:i,occurrence:r});if(a===null)throw Error(`Scheduled execution is no longer authorized.`);if(a.principalId!==t.principal.principalId||a.principalType!==t.principal.type||a.authenticator!==t.principal.authenticator||a.issuer!==t.principal.issuer||a.subject!==t.principal.subject)throw Error(`Scheduled execution auth must resolve the schedule creator.`);let o=a,s=new ContextContainer;s.set(ScheduleIdKey,e.collectionId),s.set(AuthKey,o),s.set(OccurrenceIdKey,r.executionId),s.set(ScheduleInstanceKey,r.name);let scheduledToken=(e,t)=>t===void 0?`eve-scheduled-send:${randomUUID()}`:`eve-scheduled-send:${createHash(`sha256`).update(JSON.stringify([r.scheduleId,e,t])).digest(`hex`)}`,freshRun=e=>({...e,auth:o,initiatorAuth:o,capabilities:{requestInput:!1},continuationToken:scheduledToken(e.continuationToken,e.idempotencyKey),continuationConflictCommand:e.idempotencyKey===void 0?void 0:e.continuationConflictCommand});return await contextStorage.run(s,async()=>{let e={...this.runtime,resolveContinuation:async()=>void 0,dispatchContinuation:async e=>{let{command:t}=e;if(t.kind!==`send`)throw Error(`Scheduled channel receive can only start a fresh session.`);return t.idempotencyKey===void 0?{status:`session_not_active`}:await this.runtime.dispatchContinuation({command:t,continuationToken:scheduledToken(e.continuationToken,t.idempotencyKey),successor:e.successor&&freshRun(e.successor)})},createSession:async e=>await this.runtime.createSession(freshRun(e))},{args:t,sessions:a,waitUntilTasks:s}=this.createHandlerContext(e);return await n.run({payload:i,occurrence:r,auth:o,to:(e,n)=>({send:(r,i)=>t.to(e,n).send(r,{...i,auth:o})}),waitUntil:t.waitUntil}),await Promise.all(s),{sessions:a,waitUntilTasks:s}})}async triggerInScope(e){let{args:t,sessions:n,waitUntilTasks:r}=this.createHandlerContext();if(e.run)await e.run(t);else if(e.markdown!==void 0)n.push(await this.runMarkdown(e.markdown));else throw Error(`Schedule "${e.scheduleId}" has neither "run" nor "markdown" — at least one must be set.`);return{sessions:n,waitUntilTasks:r}}createHandlerContext(e=this.runtime){let t=[],n=[],r=createCrossChannelToFn(e,toCrossChannelTargets(this.channels));return{args:{appAuth:SCHEDULE_APP_AUTH$1,to(e,n){let i=r(e,n);return{async send(e,n){let r=await i.send(e,n);return t.push(r),r}}},waitUntil(e){n.push(e)}},sessions:t,waitUntilTasks:n}}async runMarkdown(e){let t=createChannelDeliveryMetadata({channelKind:`schedule`,channelName:`schedule`}),n=await this.runtime.createSession({delivery:t,adapter:SCHEDULE_ADAPTER,auth:SCHEDULE_APP_AUTH$1,input:{message:e}});return commandDelivery(this.runtime,{status:`accepted`,sessionId:n.sessionId},t.deliveryId)}};function expectScheduleRun(e,t,n){let r=e;if(typeof r!=`object`||!r)throw Error(`Schedule export "${n??`default`}" from "${t}" must be an object.`);return expectFunction(r.run,`Expected the schedule export "${n??`default`}" from "${t}" to export a \`run\` handler function.`)}export{SCHEDULE_ADAPTER,SCHEDULE_ADAPTER_KIND,SCHEDULE_APP_AUTH,ScheduleDispatcher,expectScheduleRun};
|
|
@@ -48,14 +48,36 @@ interface SessionDeliveryOptions {
|
|
|
48
48
|
readonly context?: readonly string[];
|
|
49
49
|
readonly outputSchema?: JsonObject;
|
|
50
50
|
}
|
|
51
|
-
/**
|
|
52
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Options every server-side message send accepts: `Session.send()`,
|
|
53
|
+
* `from(address).send()`, `to(channel, target).send()`, and the input a
|
|
54
|
+
* channel's `receive()` hook gets.
|
|
55
|
+
*/
|
|
56
|
+
export interface SessionSendOptions {
|
|
57
|
+
/** Who the session runs as. */
|
|
58
|
+
readonly auth: SessionAuthContext | null;
|
|
59
|
+
/** Strings added as user messages before the message, kept in session history. */
|
|
60
|
+
readonly context?: readonly string[];
|
|
53
61
|
/** Prior conversation added as user and assistant turns before this message and its `context`. */
|
|
54
62
|
readonly history?: readonly SessionHistoryMessage[];
|
|
55
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Stable delivery identity. Deduplicated within the receiving session's recent-key window, which
|
|
65
|
+
* every sender to that session shares, so make it unique across senders, for example by
|
|
66
|
+
* prefixing the source. A threadless Slack target also derives its session from it.
|
|
67
|
+
*/
|
|
68
|
+
readonly idempotencyKey?: string;
|
|
69
|
+
/** JSON Schema for a structured final answer. */
|
|
70
|
+
readonly outputSchema?: JsonObject;
|
|
71
|
+
/** Workflow run title for a session this send starts. Defaults to one derived from the message. */
|
|
56
72
|
readonly title?: string;
|
|
73
|
+
/** How the message treats a running turn. */
|
|
57
74
|
readonly turnPolicy?: TurnPolicy;
|
|
58
|
-
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Copies only the {@link SessionSendOptions} fields and validates the key. Callers can pass wider
|
|
78
|
+
* objects, which must not carry internal send fields such as `callback` across a channel boundary.
|
|
79
|
+
*/
|
|
80
|
+
export declare function toSessionSendOptions(options: SessionSendOptions): SessionSendOptions;
|
|
59
81
|
/** Options for answering pending input requests through a fixed session handle. */
|
|
60
82
|
export type SessionRespondOptions = SessionDeliveryOptions;
|
|
61
83
|
export declare function createSession(id: string, runtime: Runtime, metadata?: Partial<ChannelDeliverySource> & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{attachClientContext,readClientContext}from"#internal/client-context.js";import{commandDelivery}from"#channel/delivery.js";import{validateDeliveryIdempotencyKey}from"#channel/delivery-idempotency.js";import{createChannelDeliveryMetadata}from"#channel/delivery-metadata.js";import{serializeFilePartsInMessage}from"#channel/send-input.js";import{DEFAULT_TURN_POLICY,controlCommand}from"#channel/types.js";import{validateSessionHistory}from"#shared/session-history.js";import{parseAnswers}from"#shared/input.js";import{AuthKey,ContinuationHookTokensKey,ContinuationTokenKey,InitiatorAuthKey,SessionIdKey}from"#context/keys.js";import{toChannelLocalContinuationToken}from"#shared/continuation-token.js";function internalSession(e){return e}function createSession(e,t,n={}){return{id:e,async send(r,i){validateDeliveryIdempotencyKey(i.idempotencyKey);let a=createDelivery(n,i.deliveryId),o=sessionCallbackToTurnCaller(i.callback),s=validateSessionHistory(i.history),c=attachClientContext({message:serializeFilePartsInMessage(r)},readClientContext(i));i.context!==void 0&&(c.context=i.context),s!==void 0&&(c.history=s),i.outputSchema!==void 0&&(c.outputSchema=i.outputSchema);let l={idempotencyKey:i.idempotencyKey,auth:i.auth,delivery:a,kind:`send`,payload:c,requestId:n.requestId,turnPolicy:i.turnPolicy??n.turnPolicy??DEFAULT_TURN_POLICY,title:i.title},u=await t.dispatchSession({command:o===void 0?l:{...l,caller:o},sessionId:e});return commandDelivery(t,u,a.deliveryId)},async respond(r,i){if(validateDeliveryIdempotencyKey(i.idempotencyKey),r.length===0)throw Error(`respond() requires at least one answer.`);let a=parseAnswers(r),o=sessionCallbackToTurnCaller(i.callback),s=createDelivery(n,i.deliveryId),c=attachClientContext({answers:a},readClientContext(i));i.context!==void 0&&(c.context=i.context),i.outputSchema!==void 0&&(c.outputSchema=i.outputSchema);let l={idempotencyKey:i.idempotencyKey,auth:i.auth,delivery:s,kind:`send`,payload:c,requestId:n.requestId},u=await t.dispatchSession({command:o===void 0?l:{...l,caller:o},sessionId:e});return commandDelivery(t,u,s.deliveryId)},async cancel(n){let r=controlCommand({kind:`cancel`,turnId:n?.turnId},n),i=await t.dispatchSession({command:r,sessionId:e});return commandDelivery(t,i,r.deliveryId)},async prewarm(){return await t.dispatchSession({command:{kind:`prewarm`,targetDeploymentId:n.acceptedDeploymentId},sessionId:e})},async compact(n){let r=controlCommand({kind:`compact`},n),i=await t.dispatchSession({command:r,sessionId:e});return commandDelivery(t,i,r.deliveryId)},async clear(n){let r=controlCommand({kind:`clear`},n),i=await t.dispatchSession({command:r,sessionId:e});return commandDelivery(t,i,r.deliveryId)},async reset(n){let r=controlCommand({kind:`reset`,reason:n?.reason},n),i=await t.dispatchSession({command:r,sessionId:e});return commandDelivery(t,i,r.deliveryId,{follow:!1})},async*stream(n){yield*await t.getEventStream(e,n)},async getLineStream(n){return t.getLineStream(e,n)},async getStreamTailIndex(){return t.getStreamTailIndex(e)},async hasRunnableOwner(){return await t.hasRunnableOwner?.(e)??!0},async getChildBinding(n){return await t.readChildBinding?.(e,n)}}}function createAttachSessionFn(e,t={}){return n=>createSession(n,e,t)}function createDelivery(e,t){let n=createChannelDeliveryMetadata({channelKind:`http`,channelName:`http`,...e});return t===void 0?n:{...n,deliveryId:t}}function buildChannelContext(e){return{session:{get id(){return e.get(SessionIdKey)??``},get auth(){return{current:e.get(AuthKey)??null,initiator:e.get(InitiatorAuthKey)??null}}},get continuation(){let t=e.get(ContinuationTokenKey);if(t!==void 0&&t.length!==0)return{token:toChannelLocalContinuationToken(t),alias(n){if(n.length===0)throw Error(`A session alias requires a nonempty token.`);let r=namespaceContinuationToken(t,n);t!==r&&(e.set(ContinuationHookTokensKey,e=>{let n=e??[t];return n.includes(r)?n:[...n,r]}),e.set(ContinuationTokenKey,r))}}}}}function namespaceContinuationToken(e,t){let n=e.indexOf(`:`);if(n<=0)throw Error(`Cannot set session continuation token without an existing namespaced continuation token. Start the session with a placeholder continuationToken.`);return`${e.slice(0,n+1)}${t}`}function sessionCallbackToTurnCaller(e){return e===void 0?void 0:{callId:e.callId,replyTo:{kind:`callback`,token:e.token,url:e.url},subagentName:e.subagentName}}export{buildChannelContext,createAttachSessionFn,createSession,internalSession,sessionCallbackToTurnCaller};
|
|
1
|
+
import{attachClientContext,readClientContext}from"#internal/client-context.js";import{commandDelivery}from"#channel/delivery.js";import{validateDeliveryIdempotencyKey}from"#channel/delivery-idempotency.js";import{createChannelDeliveryMetadata}from"#channel/delivery-metadata.js";import{serializeFilePartsInMessage}from"#channel/send-input.js";import{DEFAULT_TURN_POLICY,controlCommand}from"#channel/types.js";import{validateSessionHistory}from"#shared/session-history.js";import{parseAnswers}from"#shared/input.js";import{AuthKey,ContinuationHookTokensKey,ContinuationTokenKey,InitiatorAuthKey,SessionIdKey}from"#context/keys.js";import{toChannelLocalContinuationToken}from"#shared/continuation-token.js";function internalSession(e){return e}const SESSION_SEND_OPTION_KEYS=Object.keys({auth:!0,context:!0,history:!0,idempotencyKey:!0,outputSchema:!0,title:!0,turnPolicy:!0});function toSessionSendOptions(e){validateDeliveryIdempotencyKey(e.idempotencyKey);let t={};for(let n of SESSION_SEND_OPTION_KEYS)e[n]!==void 0&&(t[n]=e[n]);return t}function createSession(e,t,n={}){return{id:e,async send(r,i){validateDeliveryIdempotencyKey(i.idempotencyKey);let a=createDelivery(n,i.deliveryId),o=sessionCallbackToTurnCaller(i.callback),s=validateSessionHistory(i.history),c=attachClientContext({message:serializeFilePartsInMessage(r)},readClientContext(i));i.context!==void 0&&(c.context=i.context),s!==void 0&&(c.history=s),i.outputSchema!==void 0&&(c.outputSchema=i.outputSchema);let l={idempotencyKey:i.idempotencyKey,auth:i.auth,delivery:a,kind:`send`,payload:c,requestId:n.requestId,turnPolicy:i.turnPolicy??n.turnPolicy??DEFAULT_TURN_POLICY,title:i.title},u=await t.dispatchSession({command:o===void 0?l:{...l,caller:o},sessionId:e,inbox:i.inbox});return commandDelivery(t,u,a.deliveryId)},async respond(r,i){if(validateDeliveryIdempotencyKey(i.idempotencyKey),r.length===0)throw Error(`respond() requires at least one answer.`);let a=parseAnswers(r),o=sessionCallbackToTurnCaller(i.callback),s=createDelivery(n,i.deliveryId),c=attachClientContext({answers:a},readClientContext(i));i.context!==void 0&&(c.context=i.context),i.outputSchema!==void 0&&(c.outputSchema=i.outputSchema);let l={idempotencyKey:i.idempotencyKey,auth:i.auth,delivery:s,kind:`send`,payload:c,requestId:n.requestId},u=await t.dispatchSession({command:o===void 0?l:{...l,caller:o},sessionId:e,inbox:i.inbox});return commandDelivery(t,u,s.deliveryId)},async cancel(n){let r=controlCommand({kind:`cancel`,turnId:n?.turnId},n),i=await t.dispatchSession({command:r,sessionId:e});return commandDelivery(t,i,r.deliveryId)},async prewarm(){return await t.dispatchSession({command:{kind:`prewarm`,targetDeploymentId:n.acceptedDeploymentId},sessionId:e})},async compact(n){let r=controlCommand({kind:`compact`},n),i=await t.dispatchSession({command:r,sessionId:e});return commandDelivery(t,i,r.deliveryId)},async clear(n){let r=controlCommand({kind:`clear`},n),i=await t.dispatchSession({command:r,sessionId:e});return commandDelivery(t,i,r.deliveryId)},async reset(n){let r=controlCommand({kind:`reset`,reason:n?.reason},n),i=await t.dispatchSession({command:r,sessionId:e});return commandDelivery(t,i,r.deliveryId,{follow:!1})},async*stream(n){yield*await t.getEventStream(e,n)},async getLineStream(n){return t.getLineStream(e,n)},async getStreamTailIndex(){return t.getStreamTailIndex(e)},async hasRunnableOwner(){return await t.hasRunnableOwner?.(e)??!0},async getChildBinding(n){return await t.readChildBinding?.(e,n)}}}function createAttachSessionFn(e,t={}){return n=>createSession(n,e,t)}function createDelivery(e,t){let n=createChannelDeliveryMetadata({channelKind:`http`,channelName:`http`,...e});return t===void 0?n:{...n,deliveryId:t}}function buildChannelContext(e){return{session:{get id(){return e.get(SessionIdKey)??``},get auth(){return{current:e.get(AuthKey)??null,initiator:e.get(InitiatorAuthKey)??null}}},get continuation(){let t=e.get(ContinuationTokenKey);if(t!==void 0&&t.length!==0)return{token:toChannelLocalContinuationToken(t),alias(n){if(n.length===0)throw Error(`A session alias requires a nonempty token.`);let r=namespaceContinuationToken(t,n);t!==r&&(e.set(ContinuationHookTokensKey,e=>{let n=e??[t];return n.includes(r)?n:[...n,r]}),e.set(ContinuationTokenKey,r))}}}}}function namespaceContinuationToken(e,t){let n=e.indexOf(`:`);if(n<=0)throw Error(`Cannot set session continuation token without an existing namespaced continuation token. Start the session with a placeholder continuationToken.`);return`${e.slice(0,n+1)}${t}`}function sessionCallbackToTurnCaller(e){return e===void 0?void 0:{callId:e.callId,replyTo:{kind:`callback`,token:e.token,url:e.url},subagentName:e.subagentName}}export{buildChannelContext,createAttachSessionFn,createSession,internalSession,sessionCallbackToTurnCaller,toSessionSendOptions};
|
|
@@ -199,6 +199,7 @@ export type SessionSendCommandResult = {
|
|
|
199
199
|
readonly status: "accepted";
|
|
200
200
|
readonly sessionId: string;
|
|
201
201
|
readonly deliveryId?: string;
|
|
202
|
+
readonly inbox?: string;
|
|
202
203
|
} | {
|
|
203
204
|
readonly status: "session_not_active";
|
|
204
205
|
/** The workflow exists but its inbox is not yet available; no delivery was accepted. */
|
|
@@ -232,6 +233,7 @@ export interface DispatchContinuationInput<TCommand extends SessionCommand = Ses
|
|
|
232
233
|
readonly successor?: RunInput;
|
|
233
234
|
}
|
|
234
235
|
export interface DispatchSessionInput<TCommand extends SessionCommand = SessionCommand> {
|
|
236
|
+
readonly inbox?: string;
|
|
235
237
|
readonly command: TCommand;
|
|
236
238
|
readonly sessionId: string;
|
|
237
239
|
}
|
|
@@ -2299,6 +2299,7 @@ async function openStreamBody(input) {
|
|
|
2299
2299
|
signal
|
|
2300
2300
|
});
|
|
2301
2301
|
} catch (error) {
|
|
2302
|
+
if (input.redirect === "error" && error instanceof Error && error.cause instanceof Error && error.cause.message === "unexpected redirect") throw new Error("The session stream refused a redirect. Use the final agent URL instead.", { cause: error });
|
|
2302
2303
|
if (input.signal?.aborted || !isStreamDisconnectError(error) || attempt === openRetryPolicy.maxAttempts - 1) throw error;
|
|
2303
2304
|
await sleep(retryDelayMs, input.signal);
|
|
2304
2305
|
retryDelayMs = Math.min(retryDelayMs * 2, openRetryPolicy.maxDelayMs);
|
|
@@ -2447,10 +2448,12 @@ const sendReceipts = /* @__PURE__ */ new WeakMap();
|
|
|
2447
2448
|
var StreamDelivery = class {
|
|
2448
2449
|
sessionId;
|
|
2449
2450
|
deliveryId;
|
|
2451
|
+
inbox;
|
|
2450
2452
|
#createStream;
|
|
2451
2453
|
#result;
|
|
2452
2454
|
constructor(input) {
|
|
2453
2455
|
this.sessionId = input.sessionId;
|
|
2456
|
+
this.inbox = input.inbox;
|
|
2454
2457
|
this.deliveryId = input.deliveryId;
|
|
2455
2458
|
if (input.receipt !== void 0) sendReceipts.set(this, input.receipt);
|
|
2456
2459
|
this.#createStream = input.createStream;
|
|
@@ -3010,9 +3013,13 @@ var ClientSession = class ClientSession {
|
|
|
3010
3013
|
async #send(input, retrySessionNotReady) {
|
|
3011
3014
|
const initialStreamIndex = this.#state.streamIndex;
|
|
3012
3015
|
const path = createEveSessionRoutePath(this.#state.sessionId);
|
|
3013
|
-
const { response, timing } = await postSessionSend(this.#context, path, input, retrySessionNotReady);
|
|
3014
|
-
const { sessionId: responseSessionId, deliveryId } = await readAcceptedMessage(response, this.#state.sessionId);
|
|
3016
|
+
const { response, timing } = await postSessionSend(this.#context, path, input, retrySessionNotReady, this.#state.inbox);
|
|
3017
|
+
const { sessionId: responseSessionId, deliveryId, inbox } = await readAcceptedMessage(response, this.#state.sessionId);
|
|
3015
3018
|
if (responseSessionId !== this.#state.sessionId) throw new Error("Message route returned a different session id.");
|
|
3019
|
+
this.#state = {
|
|
3020
|
+
...this.#state,
|
|
3021
|
+
inbox
|
|
3022
|
+
};
|
|
3016
3023
|
if (deliveryId === void 0) throw new Error("Message route did not return a delivery id. Update the server before sending with this client.");
|
|
3017
3024
|
return this.#messageResponse(response, input, initialStreamIndex, deliveryId, {
|
|
3018
3025
|
...timing,
|
|
@@ -3100,7 +3107,7 @@ var ClientSession = class ClientSession {
|
|
|
3100
3107
|
}
|
|
3101
3108
|
#advanceStreamIndex(streamIndex) {
|
|
3102
3109
|
this.#state = {
|
|
3103
|
-
|
|
3110
|
+
...this.#state,
|
|
3104
3111
|
streamIndex: Math.max(this.#state.streamIndex, streamIndex)
|
|
3105
3112
|
};
|
|
3106
3113
|
}
|
|
@@ -3122,7 +3129,7 @@ var ClientSession = class ClientSession {
|
|
|
3122
3129
|
function followClientSession(session, options) {
|
|
3123
3130
|
return session[followSession](options);
|
|
3124
3131
|
}
|
|
3125
|
-
async function postSessionSend(context, path, input, retrySessionNotReady) {
|
|
3132
|
+
async function postSessionSend(context, path, input, retrySessionNotReady, inbox) {
|
|
3126
3133
|
const startedAt = Date.now();
|
|
3127
3134
|
const readyDeadline = startedAt + SESSION_SEND_READY_TIMEOUT_MS;
|
|
3128
3135
|
let retryDelayMs = SESSION_SEND_RETRY_BASE_DELAY_MS;
|
|
@@ -3130,7 +3137,7 @@ async function postSessionSend(context, path, input, retrySessionNotReady) {
|
|
|
3130
3137
|
const attemptAt = Date.now();
|
|
3131
3138
|
try {
|
|
3132
3139
|
return {
|
|
3133
|
-
response: await postTurn(context, path, input, false),
|
|
3140
|
+
response: await postTurn(context, path, input, false, void 0, inbox),
|
|
3134
3141
|
timing: {
|
|
3135
3142
|
startedAt,
|
|
3136
3143
|
notReadyMs: attemptAt - startedAt,
|
|
@@ -3167,10 +3174,11 @@ async function postCreateSession(context, options) {
|
|
|
3167
3174
|
function isSessionNotReady(error) {
|
|
3168
3175
|
return SessionNotActiveError.is(error) && error.retryable;
|
|
3169
3176
|
}
|
|
3170
|
-
async function postTurn(context, path, input, requireMessage, stubs) {
|
|
3177
|
+
async function postTurn(context, path, input, requireMessage, stubs, inbox) {
|
|
3171
3178
|
const body = createMessageBody(input, requireMessage);
|
|
3172
3179
|
if (body === null) throw new Error(requireMessage ? "Creating a session requires a non-empty message." : "A session turn requires a non-empty message or answers.");
|
|
3173
3180
|
if (stubs !== void 0) body.stubs = stubs;
|
|
3181
|
+
if (inbox !== void 0) body.inbox = inbox;
|
|
3174
3182
|
const headers = await context.resolveHeaders(input.headers);
|
|
3175
3183
|
headers.set("content-type", "application/json");
|
|
3176
3184
|
const response = await fetch(createClientUrl(context.baseUrl, path), {
|
|
@@ -3192,6 +3200,7 @@ async function readAcceptedMessage(response, expected) {
|
|
|
3192
3200
|
if (!sessionId) throw new Error("Message route did not return a session id.");
|
|
3193
3201
|
return {
|
|
3194
3202
|
sessionId,
|
|
3203
|
+
inbox: typeof payload.inbox === "string" ? payload.inbox : void 0,
|
|
3195
3204
|
deliveryId: typeof payload.deliveryId === "string" && payload.deliveryId.length > 0 ? payload.deliveryId : void 0
|
|
3196
3205
|
};
|
|
3197
3206
|
}
|
|
@@ -3223,6 +3232,7 @@ var ClientSessions = class {
|
|
|
3223
3232
|
if (sessionId.length === 0) throw new Error("sessionId must be a non-empty string.");
|
|
3224
3233
|
return new ClientSession(this.#context, {
|
|
3225
3234
|
sessionId,
|
|
3235
|
+
inbox: options?.inbox,
|
|
3226
3236
|
streamIndex: options?.streamIndex ?? 0
|
|
3227
3237
|
});
|
|
3228
3238
|
}
|
|
@@ -3244,7 +3254,7 @@ var Client = class {
|
|
|
3244
3254
|
this.#baseUrl = options.baseUrl;
|
|
3245
3255
|
this.#auth = options.auth;
|
|
3246
3256
|
this.#headers = options.headers;
|
|
3247
|
-
this.#redirect = options.redirect;
|
|
3257
|
+
this.#redirect = options.redirect ?? "error";
|
|
3248
3258
|
this.sessions = new ClientSessions({
|
|
3249
3259
|
baseUrl: this.#baseUrl,
|
|
3250
3260
|
redirect: this.#redirect,
|
|
@@ -3341,7 +3351,7 @@ function headersInitToRecord(headers) {
|
|
|
3341
3351
|
return Object.fromEntries(new Headers(headers).entries());
|
|
3342
3352
|
}
|
|
3343
3353
|
function withRedirectPolicy(init, redirect) {
|
|
3344
|
-
return
|
|
3354
|
+
return {
|
|
3345
3355
|
...init,
|
|
3346
3356
|
redirect
|
|
3347
3357
|
};
|
|
@@ -3443,6 +3453,7 @@ function isAbortError(error) {
|
|
|
3443
3453
|
|
|
3444
3454
|
//#endregion
|
|
3445
3455
|
//#region src/client/optimistic-message-submissions.ts
|
|
3456
|
+
let submissionSequence = 0;
|
|
3446
3457
|
var OptimisticMessageSubmissions = class {
|
|
3447
3458
|
#optimistic;
|
|
3448
3459
|
#show;
|
|
@@ -3457,7 +3468,7 @@ var OptimisticMessageSubmissions = class {
|
|
|
3457
3468
|
}
|
|
3458
3469
|
submit(input, turnId) {
|
|
3459
3470
|
if (input.message === void 0) return void 0;
|
|
3460
|
-
const id = crypto.randomUUID()
|
|
3471
|
+
const id = crypto.randomUUID?.() ?? `submission_${(submissionSequence += 1).toString()}`;
|
|
3461
3472
|
this.#submissions.set(id, {
|
|
3462
3473
|
id,
|
|
3463
3474
|
message: summarizeMessage(input.message),
|
|
@@ -4494,7 +4505,10 @@ var SessionStore = class {
|
|
|
4494
4505
|
this.#conversationClient = new ConversationClient(() => this.#publish());
|
|
4495
4506
|
this.#events = (init.initialEvents ?? []).filter((event) => this.#conversationClient.hydrate(event));
|
|
4496
4507
|
this.#messageSubmissions = new OptimisticMessageSubmissions((submissions) => this.#conversationClient.showSubmissions(submissions), init.optimistic ?? true);
|
|
4497
|
-
this.#session = init.session ?? (init.initialSession === void 0 ? void 0 : this.#client?.sessions.attach(init.initialSession.sessionId, {
|
|
4508
|
+
this.#session = init.session ?? (init.initialSession === void 0 ? void 0 : this.#client?.sessions.attach(init.initialSession.sessionId, {
|
|
4509
|
+
streamIndex: init.initialSession.streamIndex,
|
|
4510
|
+
inbox: init.initialSession.inbox
|
|
4511
|
+
}));
|
|
4498
4512
|
this.#error = this.#recordedFailure();
|
|
4499
4513
|
this.#snapshot = this.#createSnapshot();
|
|
4500
4514
|
}
|
|
@@ -4569,6 +4583,7 @@ var SessionStore = class {
|
|
|
4569
4583
|
this.#messageSubmissions.correlate(submissionId, deliveryId);
|
|
4570
4584
|
}
|
|
4571
4585
|
this.#acceptReceipt(deliveryId);
|
|
4586
|
+
this.#callbacks.onSessionChange?.(this.#sessionState);
|
|
4572
4587
|
}
|
|
4573
4588
|
accepted.resolve(deliveryId);
|
|
4574
4589
|
return new StreamDelivery({
|
|
@@ -4901,9 +4916,11 @@ var SessionStore = class {
|
|
|
4901
4916
|
if (this.#session === void 0) return this.#observedSession = void 0;
|
|
4902
4917
|
const sessionId = this.#session.id;
|
|
4903
4918
|
const streamIndex = this.#conversationClient.view.position;
|
|
4904
|
-
|
|
4919
|
+
const { inbox } = this.#session.state;
|
|
4920
|
+
if (this.#observedSession?.sessionId !== sessionId || this.#observedSession.streamIndex !== streamIndex || this.#observedSession.inbox !== inbox) this.#observedSession = {
|
|
4905
4921
|
sessionId,
|
|
4906
|
-
streamIndex
|
|
4922
|
+
streamIndex,
|
|
4923
|
+
inbox
|
|
4907
4924
|
};
|
|
4908
4925
|
return this.#observedSession;
|
|
4909
4926
|
}
|
|
@@ -2300,6 +2300,7 @@ async function openStreamBody(input) {
|
|
|
2300
2300
|
signal
|
|
2301
2301
|
});
|
|
2302
2302
|
} catch (error) {
|
|
2303
|
+
if (input.redirect === "error" && error instanceof Error && error.cause instanceof Error && error.cause.message === "unexpected redirect") throw new Error("The session stream refused a redirect. Use the final agent URL instead.", { cause: error });
|
|
2303
2304
|
if (input.signal?.aborted || !isStreamDisconnectError(error) || attempt === openRetryPolicy.maxAttempts - 1) throw error;
|
|
2304
2305
|
await sleep(retryDelayMs, input.signal);
|
|
2305
2306
|
retryDelayMs = Math.min(retryDelayMs * 2, openRetryPolicy.maxDelayMs);
|
|
@@ -2448,10 +2449,12 @@ const sendReceipts = /* @__PURE__ */ new WeakMap();
|
|
|
2448
2449
|
var StreamDelivery = class {
|
|
2449
2450
|
sessionId;
|
|
2450
2451
|
deliveryId;
|
|
2452
|
+
inbox;
|
|
2451
2453
|
#createStream;
|
|
2452
2454
|
#result;
|
|
2453
2455
|
constructor(input) {
|
|
2454
2456
|
this.sessionId = input.sessionId;
|
|
2457
|
+
this.inbox = input.inbox;
|
|
2455
2458
|
this.deliveryId = input.deliveryId;
|
|
2456
2459
|
if (input.receipt !== void 0) sendReceipts.set(this, input.receipt);
|
|
2457
2460
|
this.#createStream = input.createStream;
|
|
@@ -3011,9 +3014,13 @@ var ClientSession = class ClientSession {
|
|
|
3011
3014
|
async #send(input, retrySessionNotReady) {
|
|
3012
3015
|
const initialStreamIndex = this.#state.streamIndex;
|
|
3013
3016
|
const path = createEveSessionRoutePath(this.#state.sessionId);
|
|
3014
|
-
const { response, timing } = await postSessionSend(this.#context, path, input, retrySessionNotReady);
|
|
3015
|
-
const { sessionId: responseSessionId, deliveryId } = await readAcceptedMessage(response, this.#state.sessionId);
|
|
3017
|
+
const { response, timing } = await postSessionSend(this.#context, path, input, retrySessionNotReady, this.#state.inbox);
|
|
3018
|
+
const { sessionId: responseSessionId, deliveryId, inbox } = await readAcceptedMessage(response, this.#state.sessionId);
|
|
3016
3019
|
if (responseSessionId !== this.#state.sessionId) throw new Error("Message route returned a different session id.");
|
|
3020
|
+
this.#state = {
|
|
3021
|
+
...this.#state,
|
|
3022
|
+
inbox
|
|
3023
|
+
};
|
|
3017
3024
|
if (deliveryId === void 0) throw new Error("Message route did not return a delivery id. Update the server before sending with this client.");
|
|
3018
3025
|
return this.#messageResponse(response, input, initialStreamIndex, deliveryId, {
|
|
3019
3026
|
...timing,
|
|
@@ -3101,7 +3108,7 @@ var ClientSession = class ClientSession {
|
|
|
3101
3108
|
}
|
|
3102
3109
|
#advanceStreamIndex(streamIndex) {
|
|
3103
3110
|
this.#state = {
|
|
3104
|
-
|
|
3111
|
+
...this.#state,
|
|
3105
3112
|
streamIndex: Math.max(this.#state.streamIndex, streamIndex)
|
|
3106
3113
|
};
|
|
3107
3114
|
}
|
|
@@ -3123,7 +3130,7 @@ var ClientSession = class ClientSession {
|
|
|
3123
3130
|
function followClientSession(session, options) {
|
|
3124
3131
|
return session[followSession](options);
|
|
3125
3132
|
}
|
|
3126
|
-
async function postSessionSend(context, path, input, retrySessionNotReady) {
|
|
3133
|
+
async function postSessionSend(context, path, input, retrySessionNotReady, inbox) {
|
|
3127
3134
|
const startedAt = Date.now();
|
|
3128
3135
|
const readyDeadline = startedAt + SESSION_SEND_READY_TIMEOUT_MS;
|
|
3129
3136
|
let retryDelayMs = SESSION_SEND_RETRY_BASE_DELAY_MS;
|
|
@@ -3131,7 +3138,7 @@ async function postSessionSend(context, path, input, retrySessionNotReady) {
|
|
|
3131
3138
|
const attemptAt = Date.now();
|
|
3132
3139
|
try {
|
|
3133
3140
|
return {
|
|
3134
|
-
response: await postTurn(context, path, input, false),
|
|
3141
|
+
response: await postTurn(context, path, input, false, void 0, inbox),
|
|
3135
3142
|
timing: {
|
|
3136
3143
|
startedAt,
|
|
3137
3144
|
notReadyMs: attemptAt - startedAt,
|
|
@@ -3168,10 +3175,11 @@ async function postCreateSession(context, options) {
|
|
|
3168
3175
|
function isSessionNotReady(error) {
|
|
3169
3176
|
return SessionNotActiveError.is(error) && error.retryable;
|
|
3170
3177
|
}
|
|
3171
|
-
async function postTurn(context, path, input, requireMessage, stubs) {
|
|
3178
|
+
async function postTurn(context, path, input, requireMessage, stubs, inbox) {
|
|
3172
3179
|
const body = createMessageBody(input, requireMessage);
|
|
3173
3180
|
if (body === null) throw new Error(requireMessage ? "Creating a session requires a non-empty message." : "A session turn requires a non-empty message or answers.");
|
|
3174
3181
|
if (stubs !== void 0) body.stubs = stubs;
|
|
3182
|
+
if (inbox !== void 0) body.inbox = inbox;
|
|
3175
3183
|
const headers = await context.resolveHeaders(input.headers);
|
|
3176
3184
|
headers.set("content-type", "application/json");
|
|
3177
3185
|
const response = await fetch(createClientUrl(context.baseUrl, path), {
|
|
@@ -3193,6 +3201,7 @@ async function readAcceptedMessage(response, expected) {
|
|
|
3193
3201
|
if (!sessionId) throw new Error("Message route did not return a session id.");
|
|
3194
3202
|
return {
|
|
3195
3203
|
sessionId,
|
|
3204
|
+
inbox: typeof payload.inbox === "string" ? payload.inbox : void 0,
|
|
3196
3205
|
deliveryId: typeof payload.deliveryId === "string" && payload.deliveryId.length > 0 ? payload.deliveryId : void 0
|
|
3197
3206
|
};
|
|
3198
3207
|
}
|
|
@@ -3224,6 +3233,7 @@ var ClientSessions = class {
|
|
|
3224
3233
|
if (sessionId.length === 0) throw new Error("sessionId must be a non-empty string.");
|
|
3225
3234
|
return new ClientSession(this.#context, {
|
|
3226
3235
|
sessionId,
|
|
3236
|
+
inbox: options?.inbox,
|
|
3227
3237
|
streamIndex: options?.streamIndex ?? 0
|
|
3228
3238
|
});
|
|
3229
3239
|
}
|
|
@@ -3245,7 +3255,7 @@ var Client = class {
|
|
|
3245
3255
|
this.#baseUrl = options.baseUrl;
|
|
3246
3256
|
this.#auth = options.auth;
|
|
3247
3257
|
this.#headers = options.headers;
|
|
3248
|
-
this.#redirect = options.redirect;
|
|
3258
|
+
this.#redirect = options.redirect ?? "error";
|
|
3249
3259
|
this.sessions = new ClientSessions({
|
|
3250
3260
|
baseUrl: this.#baseUrl,
|
|
3251
3261
|
redirect: this.#redirect,
|
|
@@ -3342,7 +3352,7 @@ function headersInitToRecord(headers) {
|
|
|
3342
3352
|
return Object.fromEntries(new Headers(headers).entries());
|
|
3343
3353
|
}
|
|
3344
3354
|
function withRedirectPolicy(init, redirect) {
|
|
3345
|
-
return
|
|
3355
|
+
return {
|
|
3346
3356
|
...init,
|
|
3347
3357
|
redirect
|
|
3348
3358
|
};
|
|
@@ -3444,6 +3454,7 @@ function isAbortError(error) {
|
|
|
3444
3454
|
|
|
3445
3455
|
//#endregion
|
|
3446
3456
|
//#region src/client/optimistic-message-submissions.ts
|
|
3457
|
+
let submissionSequence = 0;
|
|
3447
3458
|
var OptimisticMessageSubmissions = class {
|
|
3448
3459
|
#optimistic;
|
|
3449
3460
|
#show;
|
|
@@ -3458,7 +3469,7 @@ var OptimisticMessageSubmissions = class {
|
|
|
3458
3469
|
}
|
|
3459
3470
|
submit(input, turnId) {
|
|
3460
3471
|
if (input.message === void 0) return void 0;
|
|
3461
|
-
const id = crypto.randomUUID()
|
|
3472
|
+
const id = crypto.randomUUID?.() ?? `submission_${(submissionSequence += 1).toString()}`;
|
|
3462
3473
|
this.#submissions.set(id, {
|
|
3463
3474
|
id,
|
|
3464
3475
|
message: summarizeMessage(input.message),
|
|
@@ -4495,7 +4506,10 @@ var SessionStore = class {
|
|
|
4495
4506
|
this.#conversationClient = new ConversationClient(() => this.#publish());
|
|
4496
4507
|
this.#events = (init.initialEvents ?? []).filter((event) => this.#conversationClient.hydrate(event));
|
|
4497
4508
|
this.#messageSubmissions = new OptimisticMessageSubmissions((submissions) => this.#conversationClient.showSubmissions(submissions), init.optimistic ?? true);
|
|
4498
|
-
this.#session = init.session ?? (init.initialSession === void 0 ? void 0 : this.#client?.sessions.attach(init.initialSession.sessionId, {
|
|
4509
|
+
this.#session = init.session ?? (init.initialSession === void 0 ? void 0 : this.#client?.sessions.attach(init.initialSession.sessionId, {
|
|
4510
|
+
streamIndex: init.initialSession.streamIndex,
|
|
4511
|
+
inbox: init.initialSession.inbox
|
|
4512
|
+
}));
|
|
4499
4513
|
this.#error = this.#recordedFailure();
|
|
4500
4514
|
this.#snapshot = this.#createSnapshot();
|
|
4501
4515
|
}
|
|
@@ -4570,6 +4584,7 @@ var SessionStore = class {
|
|
|
4570
4584
|
this.#messageSubmissions.correlate(submissionId, deliveryId);
|
|
4571
4585
|
}
|
|
4572
4586
|
this.#acceptReceipt(deliveryId);
|
|
4587
|
+
this.#callbacks.onSessionChange?.(this.#sessionState);
|
|
4573
4588
|
}
|
|
4574
4589
|
accepted.resolve(deliveryId);
|
|
4575
4590
|
return new StreamDelivery({
|
|
@@ -4902,9 +4917,11 @@ var SessionStore = class {
|
|
|
4902
4917
|
if (this.#session === void 0) return this.#observedSession = void 0;
|
|
4903
4918
|
const sessionId = this.#session.id;
|
|
4904
4919
|
const streamIndex = this.#conversationClient.view.position;
|
|
4905
|
-
|
|
4920
|
+
const { inbox } = this.#session.state;
|
|
4921
|
+
if (this.#observedSession?.sessionId !== sessionId || this.#observedSession.streamIndex !== streamIndex || this.#observedSession.inbox !== inbox) this.#observedSession = {
|
|
4906
4922
|
sessionId,
|
|
4907
|
-
streamIndex
|
|
4923
|
+
streamIndex,
|
|
4924
|
+
inbox
|
|
4908
4925
|
};
|
|
4909
4926
|
return this.#observedSession;
|
|
4910
4927
|
}
|