eve 0.74.0 → 0.75.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/src/channel/auth/result.d.ts +4 -0
  3. package/dist/src/channel/auth/result.js +1 -0
  4. package/dist/src/channel/types.d.ts +14 -2
  5. package/dist/src/chunks/{use-eve-agent-mP0M7SrL.js → use-eve-agent-B2Kne9z6.js} +7 -2
  6. package/dist/src/chunks/{use-eve-agent-DOOXadF0.js → use-eve-agent-DK_T88EP.js} +7 -2
  7. package/dist/src/cli/commands/deploy.js +1 -1
  8. package/dist/src/cli/commands/integration-connect.d.ts +2 -0
  9. package/dist/src/cli/commands/integration-connect.js +1 -1
  10. package/dist/src/cli/commands/integration-setup.js +1 -1
  11. package/dist/src/cli/commands/link.d.ts +2 -1
  12. package/dist/src/cli/commands/link.js +1 -1
  13. package/dist/src/cli/commands/registry-declared-setups.d.ts +19 -0
  14. package/dist/src/cli/commands/registry-declared-setups.js +1 -1
  15. package/dist/src/cli/commands/registry-recovery.d.ts +3 -1
  16. package/dist/src/cli/commands/registry-recovery.js +1 -1
  17. package/dist/src/cli/commands/registry.d.ts +12 -4
  18. package/dist/src/cli/commands/registry.js +1 -1
  19. package/dist/src/cli/commands/vercel-non-interactive.d.ts +6 -4
  20. package/dist/src/cli/commands/vercel-non-interactive.js +1 -1
  21. package/dist/src/cli/dev/tui/registry-result-message.js +1 -1
  22. package/dist/src/cli/dev/tui/setup-commands.d.ts +2 -0
  23. package/dist/src/cli/dev/tui/setup-commands.js +2 -2
  24. package/dist/src/client/index.d.ts +1 -0
  25. package/dist/src/client/session.d.ts +1 -1
  26. package/dist/src/client/session.js +1 -1
  27. package/dist/src/client/sessions.d.ts +1 -1
  28. package/dist/src/client/types.d.ts +6 -0
  29. package/dist/src/compiled/.vendor-stamp.json +8 -8
  30. package/dist/src/compiled/@eve/catalog/index.js +1 -1
  31. package/dist/src/compiled/@workflow/core/global.d.ts +10 -0
  32. package/dist/src/compiled/@workflow/core/index.js +1 -1
  33. package/dist/src/compiled/@workflow/core/private.d.ts +11 -0
  34. package/dist/src/compiled/@workflow/core/private.js +1 -1
  35. package/dist/src/compiled/@workflow/core/runtime/constants.d.ts +36 -8
  36. package/dist/src/compiled/@workflow/core/runtime/helpers.js +1 -1
  37. package/dist/src/compiled/@workflow/core/runtime/lifecycle-hooks.d.ts +10 -6
  38. package/dist/src/compiled/@workflow/core/runtime/out-of-band-observation.d.ts +159 -0
  39. package/dist/src/compiled/@workflow/core/runtime/vm-mode.d.ts +28 -4
  40. package/dist/src/compiled/@workflow/core/runtime.js +4 -4
  41. package/dist/src/compiled/@workflow/core/serialization.js +1 -1
  42. package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
  43. package/dist/src/compiled/@workflow/core/workflow.js +1 -1
  44. package/dist/src/compiled/@workflow/world-local/index.js +5 -5
  45. package/dist/src/compiled/@workflow/world-vercel/index.js +4 -4
  46. package/dist/src/compiled/_chunks/workflow/{attribute-changes-CSqvJx6j.js → attribute-changes-BW-kbMMn.js} +1 -1
  47. package/dist/src/compiled/_chunks/workflow/dist-CyBgVS7g.js +1 -0
  48. package/dist/src/compiled/_chunks/workflow/{helpers-BXCuoPUb.js → helpers-DlLD3ov_.js} +1 -1
  49. package/dist/src/compiled/_chunks/workflow/private-tQUuwBoQ.js +1 -0
  50. package/dist/src/compiled/_chunks/workflow/{resume-hook-CvENCrxc.js → resume-hook-DMsV_b4n.js} +1 -1
  51. package/dist/src/compiled/_chunks/workflow/{run-8pLWuR2U.js → run-DzdAqdb1.js} +1 -1
  52. package/dist/src/compiled/_chunks/workflow/{serialization-vDozzDhh.js → serialization-DPdYS_w2.js} +2 -2
  53. package/dist/src/compiled/_chunks/workflow/sleep-BY6leHh8.js +1 -0
  54. package/dist/src/compiled/_chunks/workflow/{token-BKeK6DmC.js → token-D5ugC3PI.js} +1 -1
  55. package/dist/src/compiled/_chunks/workflow/{token-util-CddTZ_ef.js → token-util-Bla5Z0G9.js} +1 -1
  56. package/dist/src/compiled/_chunks/workflow/undici-D-ILjOKD.js +95 -0
  57. package/dist/src/compiled/_chunks/workflow/{wait-until-A344L2AG.js → wait-until-xbRRDuUf.js} +1 -1
  58. package/dist/src/compiler/extension-compatibility.d.ts +18 -12
  59. package/dist/src/compiler/extension-compatibility.js +1 -1
  60. package/dist/src/context/dynamic-connection-lifecycle.d.ts +6 -0
  61. package/dist/src/context/dynamic-connection-lifecycle.js +1 -1
  62. package/dist/src/context/keys.d.ts +4 -1
  63. package/dist/src/context/keys.js +1 -1
  64. package/dist/src/context/providers/sandbox.js +1 -1
  65. package/dist/src/context/providers/tool-stubs-key.d.ts +8 -0
  66. package/dist/src/context/providers/tool-stubs-key.js +1 -0
  67. package/dist/src/context/providers/tool-stubs.d.ts +10 -0
  68. package/dist/src/context/providers/tool-stubs.js +1 -0
  69. package/dist/src/context/run-step.js +1 -1
  70. package/dist/src/evals/index.d.ts +1 -0
  71. package/dist/src/evals/runner/execute-task.js +1 -1
  72. package/dist/src/evals/session-manager.d.ts +2 -0
  73. package/dist/src/evals/session-manager.js +1 -1
  74. package/dist/src/eve-channel/create-request.d.ts +2 -0
  75. package/dist/src/eve-channel/index.js +1 -1
  76. package/dist/src/eve-channel/request.js +1 -1
  77. package/dist/src/execution/agent-sessions/context.d.ts +2 -0
  78. package/dist/src/execution/agent-sessions/context.js +1 -1
  79. package/dist/src/execution/agent-sessions/steps.js +1 -1
  80. package/dist/src/execution/cancelled-model-call-batch.js +1 -1
  81. package/dist/src/execution/dynamic-connection-recovery.d.ts +14 -0
  82. package/dist/src/execution/dynamic-connection-recovery.js +1 -0
  83. package/dist/src/execution/dynamic-workflow/tool.js +1 -1
  84. package/dist/src/execution/forward-session-input.js +1 -1
  85. package/dist/src/execution/legacy-session/authorization.js +1 -1
  86. package/dist/src/execution/legacy-session/completion-step.js +1 -1
  87. package/dist/src/execution/legacy-session/inbox.js +1 -1
  88. package/dist/src/execution/legacy-session/interrupt-step.js +1 -1
  89. package/dist/src/execution/ndjson-stream.d.ts +6 -6
  90. package/dist/src/execution/ndjson-stream.js +3 -3
  91. package/dist/src/execution/proxied-deliver-step.js +1 -1
  92. package/dist/src/execution/runtime-context.js +1 -1
  93. package/dist/src/execution/sandbox/bindings/docker.js +1 -1
  94. package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
  95. package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
  96. package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
  97. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  98. package/dist/src/execution/sandbox/ensure.d.ts +3 -1
  99. package/dist/src/execution/sandbox/ensure.js +1 -1
  100. package/dist/src/execution/session/active-turn.js +1 -1
  101. package/dist/src/execution/session/admission.js +1 -1
  102. package/dist/src/execution/session/checkpoint-migrations.js +1 -1
  103. package/dist/src/execution/session/end-sandbox-step.d.ts +12 -0
  104. package/dist/src/execution/session/end-sandbox-step.js +1 -0
  105. package/dist/src/execution/session/finalization.js +1 -1
  106. package/dist/src/execution/session/handoff-steps.js +1 -1
  107. package/dist/src/execution/session/handoff.d.ts +1 -1
  108. package/dist/src/execution/session/handoff.js +1 -1
  109. package/dist/src/execution/session/program.js +1 -1
  110. package/dist/src/execution/session/timeout-steps.js +1 -1
  111. package/dist/src/execution/session/turn-step.js +1 -1
  112. package/dist/src/execution/session-inbox/inbox.d.ts +6 -1
  113. package/dist/src/execution/session-inbox/inbox.js +1 -1
  114. package/dist/src/execution/session-inbox/release-step.js +1 -1
  115. package/dist/src/execution/session-inbox/resume.d.ts +2 -1
  116. package/dist/src/execution/session-inbox/resume.js +1 -1
  117. package/dist/src/execution/session-workflow-tool-run.js +1 -1
  118. package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
  119. package/dist/src/execution/tasks/model-step.js +1 -1
  120. package/dist/src/execution/tasks/steps.js +1 -1
  121. package/dist/src/execution/tasks/table.d.ts +7 -1
  122. package/dist/src/execution/tasks/table.js +1 -1
  123. package/dist/src/execution/tool-stubs/playback.d.ts +11 -0
  124. package/dist/src/execution/tool-stubs/playback.js +1 -0
  125. package/dist/src/execution/tool-stubs/steps.d.ts +18 -0
  126. package/dist/src/execution/tool-stubs/steps.js +1 -0
  127. package/dist/src/execution/tools/agent-router-workflow.js +1 -1
  128. package/dist/src/execution/tools/connection-tools.d.ts +0 -6
  129. package/dist/src/execution/tools/connection-tools.js +2 -2
  130. package/dist/src/execution/tools/workflow/authorization-completion.js +1 -1
  131. package/dist/src/execution/tools/workflow/body.js +1 -1
  132. package/dist/src/execution/tools/workflow/serve.js +1 -1
  133. package/dist/src/execution/tools/workflow/withdraw-step.js +1 -1
  134. package/dist/src/execution/workflow-runtime.js +1 -1
  135. package/dist/src/execution/workflow-webhook-route.js +1 -1
  136. package/dist/src/harness/compaction/engine.d.ts +8 -19
  137. package/dist/src/harness/compaction/engine.js +1 -1
  138. package/dist/src/harness/compaction/step.d.ts +7 -1
  139. package/dist/src/harness/compaction/step.js +1 -1
  140. package/dist/src/harness/coordination.js +1 -1
  141. package/dist/src/harness/emission.js +1 -1
  142. package/dist/src/harness/hitl/approved-calls.d.ts +2 -0
  143. package/dist/src/harness/hitl/approved-calls.js +1 -1
  144. package/dist/src/harness/hitl/index.d.ts +9 -1
  145. package/dist/src/harness/hitl/index.js +1 -1
  146. package/dist/src/harness/hitl/intake.js +1 -1
  147. package/dist/src/harness/model-call/call.d.ts +2 -3
  148. package/dist/src/harness/model-call/call.js +1 -1
  149. package/dist/src/harness/model-call/model.d.ts +4 -5
  150. package/dist/src/harness/model-call/model.js +1 -1
  151. package/dist/src/harness/model-call/request.d.ts +1 -2
  152. package/dist/src/harness/model-call/request.js +1 -1
  153. package/dist/src/harness/model-call/retry.d.ts +1 -1
  154. package/dist/src/harness/model-call/retry.js +1 -1
  155. package/dist/src/harness/model-call/run.js +1 -1
  156. package/dist/src/harness/model-call/tools.d.ts +3 -4
  157. package/dist/src/harness/model-call/tools.js +1 -1
  158. package/dist/src/harness/model-call/usage.js +1 -1
  159. package/dist/src/harness/model-profile.d.ts +23 -0
  160. package/dist/src/harness/model-profile.js +1 -0
  161. package/dist/src/harness/prompt-cache.d.ts +5 -53
  162. package/dist/src/harness/prompt-cache.js +1 -1
  163. package/dist/src/harness/provider-safety.d.ts +3 -5
  164. package/dist/src/harness/provider-safety.js +1 -1
  165. package/dist/src/harness/provider-tools.d.ts +5 -13
  166. package/dist/src/harness/provider-tools.js +1 -1
  167. package/dist/src/harness/proxy-input-requests.d.ts +17 -6
  168. package/dist/src/harness/proxy-input-requests.js +1 -1
  169. package/dist/src/harness/session-machine/current.d.ts +4 -0
  170. package/dist/src/harness/session-machine/current.js +1 -1
  171. package/dist/src/harness/step/after-model.js +1 -1
  172. package/dist/src/harness/step/context.d.ts +7 -2
  173. package/dist/src/harness/step/context.js +1 -1
  174. package/dist/src/harness/step-hooks.d.ts +2 -3
  175. package/dist/src/harness/step-hooks.js +1 -1
  176. package/dist/src/harness/tool-call-io.js +1 -1
  177. package/dist/src/harness/tool-loop.js +1 -1
  178. package/dist/src/harness/tools.d.ts +2 -3
  179. package/dist/src/harness/tools.js +1 -1
  180. package/dist/src/harness/turn-tag-state.d.ts +12 -0
  181. package/dist/src/harness/turn-tag-state.js +1 -1
  182. package/dist/src/internal/application/package.js +1 -1
  183. package/dist/src/internal/gateway.d.ts +0 -13
  184. package/dist/src/internal/gateway.js +1 -1
  185. package/dist/src/internal/invocation/workflow-execution.js +1 -1
  186. package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
  187. package/dist/src/internal/workflow/cancel-expired-development-run.js +1 -1
  188. package/dist/src/protocol/routes.d.ts +4 -0
  189. package/dist/src/protocol/routes.js +1 -1
  190. package/dist/src/public/channels/auth.d.ts +21 -4
  191. package/dist/src/public/channels/auth.js +1 -1
  192. package/dist/src/public/channels/mcp.js +1 -1
  193. package/dist/src/public/schedules/providers/in-memory.js +1 -1
  194. package/dist/src/public/schedules/providers/vercel.js +1 -1
  195. package/dist/src/public/schedules/subscription.d.ts +0 -1
  196. package/dist/src/sandbox/state.d.ts +1 -0
  197. package/dist/src/self-modification/extension/subagents/agent/instructions.js +1 -1
  198. package/dist/src/self-modification/extension/subagents/agent/tools/registry_add.js +1 -1
  199. package/dist/src/setup/flows/registry-session.d.ts +10 -2
  200. package/dist/src/setup/flows/registry-session.js +1 -1
  201. package/dist/src/setup/flows/registry.d.ts +2 -0
  202. package/dist/src/setup/flows/registry.js +1 -1
  203. package/dist/src/setup/integrations/shared/prerequisite.d.ts +8 -0
  204. package/dist/src/setup/integrations/shared/prerequisite.js +1 -1
  205. package/dist/src/setup/registry-setup-client.js +1 -1
  206. package/dist/src/setup/scaffold/create/project.js +1 -1
  207. package/dist/src/setup/scaffold/create/web-template.d.ts +3 -2
  208. package/dist/src/setup/scaffold/create/web-template.js +383 -411
  209. package/dist/src/setup/scaffold/index.js +1 -1
  210. package/dist/src/setup/vercel-project.d.ts +2 -3
  211. package/dist/src/setup/vercel-project.js +0 -0
  212. package/dist/src/shared/sandbox-provider.d.ts +9 -2
  213. package/dist/src/subagents/adapter.d.ts +3 -2
  214. package/dist/src/subagents/adapter.js +1 -1
  215. package/dist/src/subagents/callback-route.js +1 -1
  216. package/dist/src/subagents/hitl-proxy.d.ts +4 -3
  217. package/dist/src/subagents/hitl-proxy.js +1 -1
  218. package/dist/src/subagents/parent-notification.js +1 -1
  219. package/dist/src/svelte/index.js +1 -1
  220. package/dist/src/svelte/use-eve-agent.js +1 -1
  221. package/dist/src/tool-stubs/execute.d.ts +13 -0
  222. package/dist/src/tool-stubs/execute.js +1 -0
  223. package/dist/src/tool-stubs/output.d.ts +4 -0
  224. package/dist/src/tool-stubs/output.js +1 -0
  225. package/dist/src/tool-stubs/playback.d.ts +15 -0
  226. package/dist/src/tool-stubs/playback.js +1 -0
  227. package/dist/src/tool-stubs/rules.d.ts +3 -0
  228. package/dist/src/tool-stubs/rules.js +1 -0
  229. package/dist/src/tool-stubs/schema.d.ts +4 -0
  230. package/dist/src/tool-stubs/schema.js +1 -0
  231. package/dist/src/tool-stubs/target.d.ts +8 -0
  232. package/dist/src/tool-stubs/target.js +1 -0
  233. package/dist/src/tool-stubs/types.d.ts +56 -0
  234. package/dist/src/tool-stubs/types.js +1 -0
  235. package/dist/src/tool-stubs/validate-targets.d.ts +6 -0
  236. package/dist/src/tool-stubs/validate-targets.js +1 -0
  237. package/dist/src/tools/provided/ask-question-workflow.js +1 -1
  238. package/dist/src/tools/provided/sleep-workflow.js +1 -1
  239. package/dist/src/vue/index.js +1 -1
  240. package/dist/src/vue/use-eve-agent.js +1 -1
  241. package/docs/concepts/sessions-runs-and-streaming.md +2 -2
  242. package/docs/evals/meta.json +10 -1
  243. package/docs/evals/overview.mdx +2 -0
  244. package/docs/evals/tool-stubs.mdx +257 -0
  245. package/docs/extensions.md +1 -1
  246. package/docs/guides/auth-and-route-protection.md +25 -0
  247. package/docs/guides/dynamic-capabilities.md +10 -3
  248. package/docs/guides/frontend/nextjs.mdx +17 -4
  249. package/docs/sandbox/index.mdx +10 -2
  250. package/docs/subagents/index.mdx +1 -1
  251. package/docs/tools/human-in-the-loop.md +1 -1
  252. package/docs/tools/overview.mdx +8 -4
  253. package/docs/tools/workflows.mdx +15 -7
  254. package/package.json +6 -6
  255. package/dist/src/compiled/_chunks/workflow/dist-DmXynLVH.js +0 -1
  256. package/dist/src/compiled/_chunks/workflow/private-Dlf90Zvn.js +0 -1
  257. package/dist/src/compiled/_chunks/workflow/signal-exit-iIdjQcCK.js +0 -95
  258. package/dist/src/compiled/_chunks/workflow/sleep-BMqbraZM.js +0 -1
@@ -0,0 +1,257 @@
1
+ ---
2
+ title: "Tool Stubs"
3
+ description: "Define tool outcomes and outcome sequences in your evals."
4
+ ---
5
+
6
+ Pass `stubs` when creating an eval session to replace selected tool executions with JSON responses. The same rules work against local and deployed agents, without deploying mock functions or keeping the runner connected to answer tool calls.
7
+
8
+ Stubs specify what tools return. [Assertions](./assertions) check what the agent does and tells the user. Unused stubs produce a warning without failing the eval.
9
+
10
+ ## Author an eval
11
+
12
+ ```ts title="evals/complete-task.eval.ts"
13
+ import { defineEval } from "eve/evals";
14
+
15
+ export default defineEval({
16
+ async test(t) {
17
+ const session = await t.session({
18
+ stubs: [
19
+ {
20
+ id: "tasks",
21
+ tool: "list_tasks",
22
+ outcomes: [
23
+ {
24
+ response: {
25
+ tasks: [
26
+ { id: "milk", title: "Buy milk" },
27
+ { id: "dog", title: "Walk dog" },
28
+ { id: "rent", title: "Pay rent" },
29
+ ],
30
+ },
31
+ },
32
+ {
33
+ response: {
34
+ tasks: [
35
+ { id: "dog", title: "Walk dog" },
36
+ { id: "rent", title: "Pay rent" },
37
+ ],
38
+ },
39
+ },
40
+ ],
41
+ },
42
+ {
43
+ id: "complete-milk",
44
+ tool: "complete_task",
45
+ match: { task_id: { const: "milk" } },
46
+ outcome: { response: { success: true } },
47
+ },
48
+ ],
49
+ });
50
+
51
+ const first = await session.send("What tasks do I have?");
52
+ first.expectOk();
53
+ first.calledTool("list_tasks", { count: 1 });
54
+ first.messageIncludes("Buy milk");
55
+
56
+ const second = await session.send("Complete Buy milk, then list my remaining tasks.");
57
+ second.expectOk();
58
+ second.calledTool("complete_task", { input: { task_id: "milk" }, count: 1 });
59
+ second.toolOrder(["complete_task", "list_tasks"]);
60
+ second.messageIncludes("Walk dog");
61
+ second.messageIncludes("Pay rent");
62
+ },
63
+ });
64
+ ```
65
+
66
+ Use your agent's actual tool names and response shapes. The client accepts the same option on `client.sessions.create({ stubs })` or `client.sessions.create({ message, stubs })`.
67
+
68
+ These responses describe a sequence, not a simulated task database. The second `list_tasks` call returns two tasks even if `complete_task` was never called. The completion and order assertions check that the agent actually requested the write; testing a real database update requires the real tool.
69
+
70
+ ## Stub fields
71
+
72
+ | Field | Meaning |
73
+ | ---------- | -------------------------------------------------------------------------------------------------------------------------------------- |
74
+ | `id` | Your session-unique rule identifier. eve uses it to track this rule's response sequence. It is neither a tool name nor a tool-call ID. |
75
+ | `tool` | The existing tool's name, optionally qualified by its local subagent path. |
76
+ | `match` | Optional input-property constraints, expressed as JSON Schema. Omit it or use `{}` to match any valid input. |
77
+ | `outcome` | One outcome repeated on every matching call, such as `{ response: { tasks: [] } }`. |
78
+ | `outcomes` | A nonempty array of outcomes returned in sequence. Use exactly one of `outcome` or `outcomes`. |
79
+
80
+ Each outcome contains exactly one of `response` or `throw`. `response` holds the JSON returned by the tool; `throw` describes an error raised immediately instead. The enclosing outcome is not part of the tool's response. Top-level `response` and `responses` are not accepted.
81
+
82
+ Exposing rule IDs and response positions in traces is a follow-up: [AX-5157](https://linear.app/vercel/issue/AX-5157).
83
+
84
+ Stubs are plain JSON and can be shared between evals:
85
+
86
+ ```ts title="evals/fixtures/tasks.ts"
87
+ import type { ToolStub } from "eve/evals";
88
+
89
+ export const taskStubs = [
90
+ { id: "tasks", tool: "list_tasks", outcome: { response: { tasks: [] } } },
91
+ ] satisfies readonly ToolStub[];
92
+ ```
93
+
94
+ Pass the fixture to `t.session({ stubs: taskStubs })`. Each session has its own sequence position. Both `eve/evals` and `eve/client` export `ToolStub` and `ToolStubOutcome`. These types check the JSON contract; they do not infer the response type from your tool definition.
95
+
96
+ ## Match tool arguments
97
+
98
+ **Rules are evaluated from top to bottom. The first matching stub wins.** Put specific rules before an unconditional fallback:
99
+
100
+ ```ts
101
+ const stubs = [
102
+ {
103
+ id: "milk",
104
+ tool: "complete_task",
105
+ match: { task_id: { const: "milk" } },
106
+ outcome: { response: { success: true } },
107
+ },
108
+ { id: "other-tasks", tool: "complete_task", outcome: { response: { success: false } } },
109
+ ];
110
+ ```
111
+
112
+ A call for milk receives success; other valid calls receive the fallback. Reversing these rules makes the unconditional rule win every time. If no rule matches, eve executes the real tool. A broken stub or failure processing its response fails the eval, even if the agent recovers. An intentional `throw` outcome is a normal tool failure that the eval can assert on. Neither falls back to real execution.
113
+
114
+ If eve cannot record an output-processing failure, it cancels the workflow serving stubs. The original tool error or fallback is preserved, but verification rejects the eval. Failed or cancelled stub sessions cannot pass verification.
115
+
116
+ Every property listed in `match` must exist and satisfy its constraint. Extra top-level properties are allowed:
117
+
118
+ ```json
119
+ {
120
+ "id": "open-tasks",
121
+ "tool": "search_tasks",
122
+ "match": {
123
+ "filter": {
124
+ "type": "object",
125
+ "properties": { "status": { "const": "open" } },
126
+ "required": ["status"]
127
+ },
128
+ "query": { "type": "string", "pattern": "\\b(?i:milk)\\b" },
129
+ "tags": { "type": "array", "contains": { "const": "urgent" } }
130
+ },
131
+ "outcome": { "response": { "tasks": ["Buy milk"] } }
132
+ }
133
+ ```
134
+
135
+ Nested properties are optional unless listed in `required`. Matching does not coerce values, apply defaults, or change arguments. The real tool schema validates input before replacement; normal approvals and output processing still apply.
136
+
137
+ Constraints use a reference-free subset of JSON Schema 2020-12: types, scalar `const` and `enum`, string patterns and bounds, numeric bounds, array items/contains, object properties/required/additionalProperties, and logical/conditional schemas. `pattern` uses JavaScript regular expressions. Schema validation, regex syntax checks, and validator initialization run before session creation.
138
+
139
+ Unsupported constraints fail setup: `patternProperties`, references, formats, `multipleOf`, `minContains`, `maxContains`, `uniqueItems`, dependencies, and object/array values in `const` or `enum`. Nested `properties` and `required` cannot use inherited property names such as `constructor` or `toString`. Use nested properties or array items to match structured values.
140
+
141
+ Unknown static tool names, invalid local-agent paths, and paths into remote agents fail session creation. Dynamic names and connection operations are checked where possible; unresolved names are allowed. After the eval, unused rule IDs are reported as warnings. Use tool assertions when a call must happen.
142
+
143
+ Configuration is limited to 100 rules, 20,000 JSON nodes, nesting depth 32, and approximately one million characters. The `__proto__` property name is reserved.
144
+
145
+ ## Sequences and session scope
146
+
147
+ `outcome` repeats on every matching call. `outcomes` advances on each new matching call, then repeats its final entry. For example, `outcomes: [{ response: "pending" }, { response: "completed" }]` returns `"pending"` once and `"completed"` thereafter. Only the selected rule advances; exhaustion never selects a later rule.
148
+
149
+ Two calls within one agent turn consume two entries. Later turns continue the same sequence. Calls awaiting or denied approval do not consume entries. Each session supports up to 10,000 recorded calls.
150
+
151
+ Choose the rules at session creation; they stay fixed for that session. Local subagents share playback through explicit tool paths, and deployment handoffs preserve it. An independent session starts at the first response.
152
+
153
+ eve's transparent internal workflow replay reuses the recorded outcome without consuming another entry.
154
+
155
+ Parallel calls consume responses in arrival order, which can vary. Use separate argument matchers when particular arguments must receive particular responses.
156
+
157
+ ## Permit tool replacement
158
+
159
+ Tool replacement is denied by default, including in development. With [Vercel OIDC](../guides/auth-and-route-protection#verceloidc), put the permission on the eval runner's verified subject:
160
+
161
+ ```ts title="agent/channels/eve.ts"
162
+ import { vercelOidc, vercelSubject } from "eve/channels/auth";
163
+ import { eveChannel } from "eve/channels/eve";
164
+
165
+ export default eveChannel({
166
+ auth: [
167
+ vercelOidc({
168
+ subjects: [
169
+ vercelSubject({ teamSlug: "acme", projectName: "app" }),
170
+ {
171
+ subject: vercelSubject({ teamSlug: "acme", projectName: "eval-runner" }),
172
+ allowToolStubs: true,
173
+ },
174
+ ],
175
+ }),
176
+ ],
177
+ });
178
+ ```
179
+
180
+ Both projects can authenticate; only the eval runner receives replacement permission. `vercelSubject` defaults to production; pass `environment: "*"` to include all environments. The target's server configuration supplies the grant after token verification. Request JSON cannot grant permission, and user principals do not inherit project grants.
181
+
182
+ Custom authenticators can return the same `allowToolStubs: true` after verifying the caller. See [authentication and route protection](../guides/auth-and-route-protection#tool-replacement-permission) for the grant rules and a local development example.
183
+
184
+ Permission is checked at session creation before identity projection. Later messages and result reads use normal channel authentication. Anyone your channel admits to an existing session can use its stubs. Your application's session-access policy must provide the required isolation; an isolated eval deployment can use the same agent code.
185
+
186
+ The stub verification endpoint also requires `allowToolStubs`, checked before reading workflow status.
187
+
188
+ ## Supported tools and subagents
189
+
190
+ Stubs replace execution of existing ordinary, dynamic, and workflow tools. They retain the real tool's input schema, approvals, and output processing. A stub does not register a new tool or make it visible to the model.
191
+
192
+ Ordinary tools with configured stub rules can emit an extra `action.partial` containing the final response. This also applies when no rule matches and the real tool returns a non-streaming result. The final `action.result` remains correct, and real streaming still delivers progress. Use `action.result` for final-result assertions. Removing the extra event is tracked in [AX-5164](https://linear.app/vercel/issue/AX-5164).
193
+
194
+ ### Subagents
195
+
196
+ Stubbing a delegation tool returns its configured result without starting the subagent. Persistent tools implemented with `serve`, including the built-in `agent`, require an unconditional stub: omit `match` or use `{}`. Mixing real and mocked calls to the same persistent tool is unsupported.
197
+
198
+ To let a local subagent run but replace its tools, use `/` to qualify the delegation path:
199
+
200
+ ```ts
201
+ const stubs = [
202
+ { id: "root-tasks", tool: "list_tasks", outcome: { response: ["Root task"] } },
203
+ { id: "research-tasks", tool: "researcher/list_tasks", outcome: { response: ["Research task"] } },
204
+ { id: "nested-tasks", tool: "researcher/assistant/list_tasks", outcome: { response: [] } },
205
+ ];
206
+ ```
207
+
208
+ `researcher` replaces the whole delegation; `researcher/list_tasks` replaces only that subagent's list tool. The built-in `agent` uses `agent/list_tasks`. Model-visible names stay unchanged. A root rule never implicitly matches a subagent's same-named tool.
209
+
210
+ Repeated subagent sessions at the same path share that rule's sequence. Different paths use different rules. Remote agents do not receive the configuration; replace their whole delegation tool instead.
211
+
212
+ ### Connections and provider tools
213
+
214
+ Use the qualified operation name, such as `linear__list_issues` or `researcher/linear__list_issues`. Put operation arguments in `match` and its JSON result in `outcome.response`, or in each sequence entry's `response`.
215
+
216
+ Connection authentication and discovery stay live so eve can validate the operation and its arguments. Stubs do not provide an offline connection. The framework's `connection_search` and `connection_execute` tools cannot themselves be replaced.
217
+
218
+ Tools executed by the model provider, such as provider-hosted web search, have no eve executor to replace. A search tool implemented in your own agent can be stubbed.
219
+
220
+ ## Inject tool errors
221
+
222
+ Use `throw` to test how the agent handles a failed tool call. Mix errors and responses to test recovery:
223
+
224
+ ```ts
225
+ const stubs = [
226
+ {
227
+ id: "tasks",
228
+ tool: "list_tasks",
229
+ outcomes: [
230
+ { throw: { name: "TimeoutError", message: "Task service timed out" } },
231
+ { response: { tasks: [] } },
232
+ ],
233
+ },
234
+ ];
235
+ ```
236
+
237
+ `throw.message` is required. `throw.name` is optional and defaults to `"Error"`. eve creates an ordinary JavaScript `Error` with that name and message; it does not instantiate custom error classes. `TimeoutError` reports a timeout immediately, without delaying the call or testing an actual deadline.
238
+
239
+ Ordinary tools and connection operations expose the error message to the model, without the error name. Workflow task errors also retain the name. Put any details the model needs to act on in `message`.
240
+
241
+ Use `outcome: { throw: { message: "Service unavailable" } }` to fail every matching call. A sequence consumes one entry per new call, whether it returns or throws, and repeats its final entry. Workflow replay reuses the same recorded outcome.
242
+
243
+ An injected exception follows the tool's normal error handling. Ordinary and blocking workflow calls are recorded as failed; background tasks report failure when they settle. The model can report the failure or try again. Assert the failed call explicitly:
244
+
245
+ ```ts
246
+ const turn = await session.send(
247
+ "List my tasks once. If the service fails, explain the failure and wait for me to retry.",
248
+ );
249
+ turn.expectOk();
250
+ turn.calledTool("list_tasks", { status: "failed", count: 1 });
251
+ ```
252
+
253
+ The eval can pass when the agent handles the failure correctly. `noFailedActions()` still rejects the failed call, so use explicit assertions for expected failures. Stub infrastructure and response-processing failures still fail verification.
254
+
255
+ This works for ordinary tools, workflow tools, whole-agent replacements, and qualified connection operations. An exception in a persistent workflow tool ends that task; retry with a new call, rather than its failed task ID. Normal approvals apply before an outcome is consumed.
256
+
257
+ Returning `{ response: { error: "timeout" } }` remains ordinary JSON. Only `throw` raises an exception.
@@ -178,7 +178,7 @@ A mount gives the extension's contributions a namespace. Updating the package up
178
178
 
179
179
  ### Install the package
180
180
 
181
- Install the extension with the package manager already used by the consumer's agent project. Fresh eve projects use pnpm:
181
+ Install the extension with the package manager already used by the consumer's agent project. For example, in a pnpm project:
182
182
 
183
183
  ```bash
184
184
  pnpm add @acme/crm
@@ -113,6 +113,8 @@ Verifies a bearer JWT against the [Vercel OIDC issuer](https://vercel.com/docs/o
113
113
 
114
114
  Auth fails closed: routes reject unauthenticated traffic by default, and the OIDC user branch verifies `external_sub` against `VERCEL_PROJECT_ID` and the deployment environment, returning `false` when either is unset. An external-subject token cannot authenticate on a deployment that hasn't pinned its project.
115
115
 
116
+ Subject entries can also be objects: `{ subject: vercelSubject({ teamSlug: "acme", projectName: "eval-runner" }), allowToolStubs: true }`. This explicitly permits that verified service/runtime caller to create [stubbed eval sessions](../evals/tool-stubs). Plain subject strings and implicit current-project acceptance grant ordinary access only. Custom authenticators can return the same permission in their authentication result; it is not part of persisted or forwarded session identity.
117
+
116
118
  #### `subjects` patterns and `vercelSubject(...)`
117
119
 
118
120
  Each `subjects` entry is matched against the token's `sub` claim, which Vercel shapes as `owner:<team>:project:<name>:environment:<env>`. Hand-writing that string is a footgun: a typo silently rejects every caller, and an over-broad `*` wildcard silently lets unrelated ones in. Build the pattern with `vercelSubject(...)` instead. It rejects malformed input at construction time, and defaults `environment` to `"production"` when you omit it, so an unspecified environment cannot silently accept preview or development tokens:
@@ -298,6 +300,29 @@ Use the principal on `auth.current` (or `auth.initiator`) to scope tools, resolv
298
300
 
299
301
  Route auth does not enforce session ownership. If multiple users or tenants can reach the same route, you must implement the per-user, per-tenant, or per-session authorization your application requires.
300
302
 
303
+ ## Tool replacement permission
304
+
305
+ Creating a [stubbed eval session](../evals/tool-stubs) requires an explicit `allowToolStubs: true` in the verified route authentication result. The target's server configuration grants permission; request JSON cannot. With `vercelOidc`, put the grant on a `subjects` entry as shown above. Any matching entry with the grant permits replacement; other entries do not revoke it. Implicit current-project acceptance and user principals do not inherit project grants.
306
+
307
+ Custom authenticators return the same grant after verifying their caller. For example, this alternative channel permits stubs only in local development:
308
+
309
+ ```ts
310
+ import { localDev } from "eve/channels/auth";
311
+ import { eveChannel } from "eve/channels/eve";
312
+
313
+ const authenticate = localDev();
314
+ export default eveChannel({
315
+ auth: async (request) => {
316
+ const caller = await authenticate(request);
317
+ return caller ? { ...caller, allowToolStubs: true } : null;
318
+ },
319
+ });
320
+ ```
321
+
322
+ The channel checks the grant before forwarded-principal handling or `onMessage` projection. It removes the grant before using the identity for forwarding, audience classification, or session persistence. This is an authentication-result permission, not a session attribute.
323
+
324
+ Later messages, approvals, controls, and result reads use normal channel authentication. There is no additional creator-only rule or replacement-permission recheck. Anyone your channel admits to an existing session can use its configured stubs; apply the same application-specific session-access policy you need for ordinary sessions.
325
+
301
326
  ## Tool and connection auth
302
327
 
303
328
  Tool and connection auth is how your agent reaches an external service that wants an interactive sign-in, like an OAuth MCP server. Connections declare `auth` on the connection definition. Tools should resolve providers inline with `ctx.getToken(provider)` and call `ctx.requireAuth(provider)` only when a downstream service rejects a token; eve drives the sign-in, caches the token per step, and re-runs the call once the caller authorizes.
@@ -221,9 +221,16 @@ same name; namespace one map key to remove the ambiguity.
221
221
 
222
222
  Dynamic connections support `session.started` and `turn.started`. A turn result
223
223
  replaces that file's session result for the turn, including when the turn
224
- handler returns `null`. A throwing or invalid handler fails the lifecycle
225
- without rebuilding the registry, so a static connection shadowed by the
226
- dynamic result cannot reappear as a fallback.
224
+ handler returns `null`. A throwing or invalid handler fails the current turn
225
+ and parks the session, so a later message can retry after the dependency
226
+ recovers. The failed lifecycle does not rebuild the registry, so a static
227
+ connection shadowed by the dynamic result cannot reappear as a fallback.
228
+
229
+ Recovery needs another message. eve does not keep the input from the failed
230
+ turn or replay it, so the caller must send it again once the dependency is
231
+ back. This applies to the first message of a session too. A scheduled run
232
+ whose resolver fails is not retried; the session stays idle until the next
233
+ scheduled run or message arrives.
227
234
 
228
235
  eve may run the active session and turn handlers again when a parked turn
229
236
  resumes or a durable step retries. This rebuilds live auth, header, approval,
@@ -11,21 +11,34 @@ Use this integration when Next.js owns the application's development and deploym
11
11
 
12
12
  - The `eve` package installed in your project (`npm install eve@latest`).
13
13
  - An existing eve agent directory. If you don't have one, start from [Getting Started](../../getting-started).
14
- - A Next.js app, or a single-agent project where you want to generate one below.
14
+ - A Next.js app, or an eve project where you want to generate one below.
15
15
 
16
16
  ## Add the generated Web Chat app
17
17
 
18
- For a single-agent project, install the generated Next.js Web Chat app:
18
+ Install the generated Next.js Web Chat app from a standalone agent project:
19
19
 
20
20
  ```bash
21
21
  eve add channel/web
22
22
  ```
23
23
 
24
- The installer adds a Next.js application and wraps `next.config.ts` with `withEve()`. The generated chat calls the unnamed agent through same-origin `/eve/v1/*` routes.
24
+ For an agent workspace, select the member the chat should call:
25
+
26
+ ```bash
27
+ eve add channel/web --agent support
28
+ ```
29
+
30
+ The installer configures the chat for the selected agent. By default, it adds a shared Next.js
31
+ application under `apps/web`; if a root Web Chat app already exists, it configures that app instead.
32
+ For Next.js hosting, the installer wraps `next.config.ts` with `withEve()`. When setting up a new
33
+ app, choose **Next.js** to host the integration. The generated chat uses same-origin `/eve/v1/*`
34
+ routes for a standalone agent or `/eve/<name>/v1/*` routes for a workspace member. Running the
35
+ installer from a workspace root without selecting a member is not supported.
25
36
 
26
37
  Before accepting production browser traffic, replace the generated placeholder authorization policy. See [Authenticate browser requests](./overview#authenticate-browser-requests).
27
38
 
28
- The Web Chat installer does not support eve agent workspaces. If you want Next.js to host the integration, create a root Next.js application and follow the steps below; `withEve(nextConfig)` discovers workspace members but does not generate a chat UI. To keep the frontend as a peer application instead, follow the [workspace layout guidance](/docs/concepts/project-structure#configure-a-web-deployment).
39
+ To integrate an existing Next.js application without generating a chat UI, follow the steps below.
40
+ To deploy the frontend and agents as separate Vercel services, choose **Vercel services** during
41
+ setup instead; see the [workspace layout guidance](/docs/concepts/project-structure#configure-a-web-deployment).
29
42
 
30
43
  ## Wrap the Next.js config
31
44
 
@@ -182,6 +182,10 @@ export const AcmeSandbox = defineSandboxProvider<
182
182
  const client = createAcmeClient(options);
183
183
 
184
184
  return {
185
+ async onSessionEnd(_ctx, _artifact, state, { reason }) {
186
+ await client.delete({ id: state.remoteId, reason });
187
+ },
188
+
185
189
  async prepare(ctx) {
186
190
  const temporary = await client.createTemporary({
187
191
  files: await ctx.files.list(),
@@ -213,7 +217,11 @@ export const AcmeSandbox = defineSandboxProvider<
213
217
  });
214
218
  ```
215
219
 
216
- `prepare()` returns the complete JSON-serializable artifact. Core calls `start()` once for a new durable sandbox session and persists its minimal JSON-compatible state. Process restarts call `resume()` with only the current context, that state, and the target deployment's exact artifact. Provider handles implement `onSessionStop()`, `onRuntimeShutdown()`, and `onSessionDelete()`.
220
+ `prepare()` returns the complete JSON-serializable artifact. Core calls `start()` once for a new durable sandbox session and persists its minimal JSON-compatible state. Process restarts call `resume()` with only the current context, that state, and the target deployment's exact artifact.
221
+
222
+ `onSessionEnd()` is invoked when the durable session reaches a completed, expired, or failed terminal outcome. It receives the exact prepared artifact, persisted provider state, and a `reason` of `"completed"`, `"expired"`, or `"failed"`. Implement idempotent permanent cleanup from those values rather than depending on a live handle. eve retries the cleanup step and logs an exhausted failure without replacing the session's terminal outcome. A session that never opened a sandbox and a child that borrows its parent's sandbox do not call the hook.
223
+
224
+ Provider handles implement `onSandboxStop()`, `onRuntimeShutdown()`, and `onSandboxDelete()`. These handle-level methods cover authored stop or delete calls, process shutdown, and failed initialization; `onSessionEnd()` is the single provider hook for durable terminal session cleanup.
217
225
 
218
226
  Open options belong to `start()` and are not serialized or passed to `resume()`. A provider must put any immutable option-derived data needed for reconnection in its session state. With the current immutable-state contract, `resume()` reconnects existing native state and fails if it is gone rather than recreating callback side effects. A custom provider may define start-only callback fields, but built-in providers initialize the sandbox in `defineSandbox()` after `open()`.
219
227
 
@@ -231,7 +239,7 @@ Preparation discovers authored files through `ctx.files`; core keeps project lay
231
239
 
232
240
  ## Lifecycle
233
241
 
234
- Session-owned sandboxes persist across turns and deployments while their provider state remains available. `sandbox.stop()` stops compute without deleting persisted state; a later access resumes that state directly. `sandbox.delete()` clears provider state, so the next `ctx.getSandbox()` reruns the selector and starts a fresh sandbox from the current environment.
242
+ Session-owned sandboxes persist across turns and deployments while their provider state remains available. `sandbox.stop()` stops compute without deleting persisted state; a later access resumes that state directly. `sandbox.delete()` clears provider state, so the next `ctx.getSandbox()` reruns the selector and starts a fresh sandbox from the current environment. When the durable session reaches a terminal outcome, eve calls the provider's `onSessionEnd()` hook to release any remaining session-owned resources.
235
243
 
236
244
  Changing sandbox source, preparation code, Dockerfile content, environment options, workspace resources, or skills produces a new environment generation. Existing durable sessions retain their recorded sandbox state; new sessions use the current generation.
237
245
 
@@ -229,7 +229,7 @@ By default, a subagent named `researcher` collides with an authored tool named `
229
229
 
230
230
  Do not rely on subagent delegation by itself as an approval boundary. Put sensitive tools behind `approval`, connection approval, route/session authorization, or other controls wherever those tools can be called.
231
231
 
232
- Each delegated subagent spins up its own child session and stream. The parent stream carries the call's `task.started` and `task.settled` events, `agent.started` when the child session opens, plus interactive `input.requested`, `authorization.required`, and `authorization.completed` events proxied from descendants so the root channel can prompt the user. The parent emits `input.resolved` when it routes an answer back down to the descendant that asked. `task.settled` carries the child's reply as `output` when the call completes, or `error.message` when it fails, along with the same tool `name` and `kind: "agent"` as the call's `task.started`. To follow the child's other progress, pass the `agent.started` event to [`session.agent()`](./guides/client/streaming#follow-a-subagent) on a client session attached to the parent and follow the child with `stream()`. It reads `agent.started.data.streamPath`: the child's own session stream for a local child, or a parent-origin proxy for a remote child, which the parent authenticates to the remote deployment.
232
+ Each delegated subagent spins up its own child session and stream. The parent stream carries the call's `task.started` and `task.settled` events, `agent.started` when the child session opens, plus interactive `input.requested`, `authorization.required`, and `authorization.completed` events proxied from descendants so the root channel can prompt the user. The parent emits `input.resolved` when it routes an answer back down to the descendant that asked. A tool approval is the exception: the descendant decides it, since its response policy can refuse the person who answered, so the approval stays open on the parent until the descendant settles or resolves it. The parent relays the descendant's `approval.settled` and `input.resolved` for it. On text-only channels, a typed reply that matches an option of the first open prompt, such as `approve` for a tool approval or `continue` for a session limit, answers it as the person who typed it, so a person answers several proxied prompts one message at a time. `task.settled` carries the child's reply as `output` when the call completes, or `error.message` when it fails, along with the same tool `name` and `kind: "agent"` as the call's `task.started`. To follow the child's other progress, pass the `agent.started` event to [`session.agent()`](./guides/client/streaming#follow-a-subagent) on a client session attached to the parent and follow the child with `stream()`. It reads `agent.started.data.streamPath`: the child's own session stream for a local child, or a parent-origin proxy for a remote child, which the parent authenticates to the remote deployment.
233
233
 
234
234
  `agent.started` carries the `callId` and `turnId` of the call that opened the session, the call's `taskId`, the agent `name`, and the child's `sessionId`. Later calls with the same `taskId` reach the same session and do not announce it again, so match a child to its calls by `taskId`. A session an authored workflow tool opens with `ctx.agent` is announced the same way, with its `taskId` only when the workflow tool call runs as a task.
235
235
 
@@ -219,7 +219,7 @@ Approvals and questions share one protocol:
219
219
  3. The run parks durably, for as long as it takes. The turn stays open: the stream emits `turn.waiting`, and after the answer the turn resumes under the same `turnId`. That `turn.waiting` carries `on: "input"`, since a person must act.
220
220
  4. The client answers with `inputResponses` (structured, keyed by `requestId`) or a normal follow-up `message`. A follow-up whose text matches an option ID, option label, or numeric option index resolves automatically, including approval options such as `approve` and `cancel`.
221
221
 
222
- For `ctx.ask()` questions from tools, a follow-up message answers the first open request, as described in [Several requests at once](#several-requests-at-once). The message must match an option, or the question must allow free text. Otherwise the message follows the session's `turnPolicy`. A steering message, the default, aborts the `ctx.abortSignal` of each `execute` workflow tool call the turn waits on, so a question such a call asked, such as `ask_question`'s, is withdrawn and resolves as `cancelled`. The model reads the message once those calls settle. Questions from subagents need a structured response.
222
+ For `ctx.ask()` questions from tools and prompts proxied from subagents, a follow-up message answers the first open request, as described in [Several requests at once](#several-requests-at-once). The message must match an option, or the question must allow free text. Otherwise the message follows the session's `turnPolicy`. A steering message, the default, aborts the `ctx.abortSignal` of each `execute` workflow tool call the turn waits on, so a question such a call asked, such as `ask_question`'s, is withdrawn and resolves as `cancelled`. The model reads the message once those calls settle.
223
223
 
224
224
  Each request includes a `kind` discriminator: `tool-approval`, `question`, or
225
225
  `session-limit`. Clients should use `kind` to choose behavior and presentation.
@@ -176,8 +176,8 @@ receive only the projected text.
176
176
 
177
177
  ### Durable waits
178
178
 
179
- Every tool call finishes before its turn continues. The definition decides whether the executor
180
- can wait durably while the call is pending:
179
+ A tool call with an `execute` entry point finishes before the model continues. The definition
180
+ decides whether the executor can wait durably while the call is pending:
181
181
 
182
182
  | Definition | Durable waits inside `execute` | Result delivered to the model |
183
183
  | -------------------- | -------------------------------------------------------- | ---------------------------------- |
@@ -191,11 +191,15 @@ the call returns a receipt at once, and the workflow's output reaches the model
191
191
  [resumable task](/docs/tools/workflows#resumable-tasks-serve), which the model can send more calls
192
192
  by its `taskId`.
193
193
 
194
+ Built-in, declared local, and remote subagent tools run as resumable tasks: each call returns a
195
+ receipt at once, and the child's reply reaches the model later in a `task.result` message.
196
+ Inside an authored workflow, awaiting a [`ctx.agent` session's `response.result()`](/docs/tools/workflows#delegate-work-ctxagent)
197
+ waits for the child's turn to end instead.
198
+
194
199
  The `TaskExec` argument and `task.postMessage` have been removed. Return the result. In a workflow
195
200
  body, keep values needed after a wait in local variables; workflow replay reconstructs them across
196
201
  durable waits. Use [`ctx.ask`](/docs/tools/workflows#ask-a-human-ctxask) when the body needs an
197
- answer from the human. Built-in, declared local, and remote subagent calls also block: each call
198
- returns the child's reply as its tool result.
202
+ answer from the human.
199
203
 
200
204
  ### Yield and return
201
205
 
@@ -347,10 +347,14 @@ described in [Tasks](/docs/tools/tasks). What differs:
347
347
  share one identity, so don't keep per-person data for them. Any caller in the session can
348
348
  continue or cancel the task; see [Tasks](/docs/tools/tasks#ownership-and-limits).
349
349
  - **Agents belong to the call that opened them:** a session the body opens with `ctx.agent` while
350
- serving a call is that call's child. Its `session.parent` names the call's `callId` and turn, and
351
- its trace continues from the call's tool span. The session keeps that lineage for its later
352
- messages, even after the task receives another call. Auth belongs to each message instead: a
353
- message carries the auth of the call being served when it's sent.
350
+ serving a call is that call's child. Its `session.parent` names the call's `callId` and turn.
351
+ The first turn of a local child uses the call's tool span as its parent when trace context is
352
+ available. A remote child starts its own trace; its first turn links to the call's tool span
353
+ with `eve.link.type=agent.dispatch` when trace context is available. Later child turns start new
354
+ traces. Parent session lineage stays tied to the opening call, even after the task receives
355
+ another call; a remote receiver accepts that lineage only from a trusted forwarder. Each message
356
+ uses the auth of the call being served; remote identity follows the
357
+ [forwarding rules](../guides/remote-agents#forwarding-the-caller-identity).
354
358
  - **Results:** `ctx.reply(output)` settles every call received so far with `output`, all at once.
355
359
  Each settled call reports its own `task.settled`, and the model receives the reply once. The task
356
360
  then goes idle until its next call. A reply with
@@ -541,9 +545,13 @@ client's `MessageResult` fields, plus `error` when the turn failed:
541
545
  | `error` | `{ message }` with the reason the turn failed, present only when `status` is `"failed"`. |
542
546
 
543
547
  Every `ctx.agent(name)` call returns a new session that only the workflow run can address. The model
544
- does not see it; it sees what the tool returns. The session runs as the caller's principal with the
545
- caller's capabilities, and a person answers its questions and sign-ins at the root session, as for
546
- any subagent. The session ends when the run finishes, which cancels any turn still running.
548
+ does not see it; it sees what the tool returns. A local child runs as the caller's principal with the
549
+ caller's capabilities. A remote child does not inherit the caller's session principal by default;
550
+ the receiving deployment determines its identity from the outbound request. To forward the caller's
551
+ identity, set `forwardPrincipal: true` on the remote agent and configure the receiver's
552
+ `trustedForwarders` (see [Forwarding the caller identity](../guides/remote-agents#forwarding-the-caller-identity)).
553
+ A person answers the child's questions and sign-ins at the root session, as for any subagent.
554
+ The session ends when the run finishes, which cancels any turn still running.
547
555
 
548
556
  The parent stream announces each session with `agent.started`, which carries the `callId` and
549
557
  `turnId` of the tool call the run is serving when it opens the session (for a `serve` task, the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve",
3
- "version": "0.74.0",
3
+ "version": "0.75.1",
4
4
  "private": false,
5
5
  "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
6
6
  "keywords": [
@@ -580,12 +580,12 @@
580
580
  "@vercel/sandbox": "3.3.0",
581
581
  "@vercel/schedules": "0.0.0-alpha.11",
582
582
  "@vercel/sdk": "1.28.8",
583
- "@workflow/core": "5.1.0",
584
- "@workflow/errors": "5.0.2",
583
+ "@workflow/core": "5.2.0",
584
+ "@workflow/errors": "5.0.3",
585
585
  "@workflow/serde": "5.0.0",
586
- "@workflow/world": "5.0.2",
587
- "@workflow/world-local": "5.0.2",
588
- "@workflow/world-vercel": "5.1.0",
586
+ "@workflow/world": "5.0.3",
587
+ "@workflow/world-local": "5.1.0",
588
+ "@workflow/world-vercel": "5.2.0",
589
589
  "ai": "^7.0.128",
590
590
  "chat": "4.41.0",
591
591
  "chokidar": "5.0.0",
@@ -1 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-B_knIduE.js";import*as t from"#compiled/zod/index.js";import{z as n}from"#compiled/zod/index.js";import r from"node:crypto";function i(e,t,n){let r=Symbol.for(`${e}/v${t}`),i=globalThis,a=i[r];if(a!==void 0)return a;let o=n();return i[r]=o,o}const a=Symbol.for(`@workflow/world//warnedEnvValues/v1`),o=globalThis,s=o[a]??=new Set;function c(e,t){s.has(e)||(s.add(e),console.warn(`[workflow] ${t}`))}function l(e,t,n={}){let r=process.env[e];if(r===void 0||r===``)return t;let{min:i=0,max:a,integer:o=!1}=n,s=Number(r);return!Number.isFinite(s)||o&&!Number.isInteger(s)?(c(`${e}=${r}`,`Ignoring ${e}: not a ${o?`finite integer`:`finite number`}; using default ${t}`),t):s<i?(c(`${e}=${r}`,`${e} below minimum ${i}; clamped`),i):a!==void 0&&s>a?(c(`${e}=${r}`,`${e} above maximum ${a}; clamped`),a):s}function u(e,t,n=process.env){let r=n[e];if(r===void 0||r===``)return t;let i=r.toLowerCase();return i===`0`||i===`false`?!1:i===`1`||i===`true`||(c(`${e}=${r}`,`Ignoring ${e}: expected 0/1/true/false; using default ${t}`),t)}const d=25e3;function ee(){let e=l(`WORKFLOW_MAX_EVENTS`,d,{integer:!0});return e>0?e:d}const f=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`;var p;(function(e){e.Base32IncorrectEncoding=`B32_ENC_INVALID`,e.DecodeTimeInvalidCharacter=`DEC_TIME_CHAR`,e.DecodeTimeValueMalformed=`DEC_TIME_MALFORMED`,e.EncodeTimeNegative=`ENC_TIME_NEG`,e.EncodeTimeSizeExceeded=`ENC_TIME_SIZE_EXCEED`,e.EncodeTimeValueMalformed=`ENC_TIME_MALFORMED`,e.PRNGDetectFailure=`PRNG_DETECT`,e.ULIDInvalid=`ULID_INVALID`,e.Unexpected=`UNEXPECTED`,e.UUIDInvalid=`UUID_INVALID`})(p||={});var m=class extends Error{constructor(e,t){super(`${t} (${e})`),this.name=`ULIDError`,this.code=e}};function te(e){let t=Math.floor(e()*32)%32;return f.charAt(t)}function h(e,t,n){return t>e.length-1?e:e.substr(0,t)+n+e.substr(t+1)}function ne(e){let t,n=e.length,r,i,a=e;for(;!t&&n-->=0;){if(r=a[n],i=f.indexOf(r),i===-1)throw new m(p.Base32IncorrectEncoding,`Incorrectly encoded string`);if(i===31){a=h(a,n,f[0]);continue}t=h(a,n,f[i+1])}if(typeof t==`string`)return t;throw new m(p.Base32IncorrectEncoding,`Failed incrementing string`)}function re(e){if(e.length!==26)throw new m(p.DecodeTimeValueMalformed,`Malformed ULID`);let t=e.substr(0,10).toUpperCase().split(``).reverse().reduce((e,t,n)=>{let r=f.indexOf(t);if(r===-1)throw new m(p.DecodeTimeInvalidCharacter,`Time decode error: Invalid character: ${t}`);return e+=r*32**n},0);if(t>0xffffffffffff)throw new m(p.DecodeTimeValueMalformed,`Malformed ULID: timestamp too large: ${t}`);return t}function ie(e){let t=ae(),n=t&&(t.crypto||t.msCrypto)||(r===void 0?null:r);if(typeof n?.getRandomValues==`function`)return()=>{let e=new Uint8Array(1);return n.getRandomValues(e),e[0]/256};if(typeof n?.randomBytes==`function`)return()=>n.randomBytes(1).readUInt8()/256;if(r?.randomBytes)return()=>r.randomBytes(1).readUInt8()/256;throw new m(p.PRNGDetectFailure,`Failed to find a reliable PRNG`)}function ae(){return se()?self:typeof window<`u`?window:typeof global<`u`?global:typeof globalThis<`u`?globalThis:null}function oe(e,t){let n=``;for(;e>0;e--)n=te(t)+n;return n}function g(e,t=10){if(isNaN(e))throw new m(p.EncodeTimeValueMalformed,`Time must be a number: ${e}`);if(e>0xffffffffffff)throw new m(p.EncodeTimeSizeExceeded,`Cannot encode a time larger than 281474976710655: ${e}`);if(e<0)throw new m(p.EncodeTimeNegative,`Time must be positive: ${e}`);if(Number.isInteger(e)===!1)throw new m(p.EncodeTimeValueMalformed,`Time must be an integer: ${e}`);let n,r=``;for(let i=t;i>0;i--)n=e%32,r=f.charAt(n)+r,e=(e-n)/32;return r}function se(){return typeof WorkerGlobalScope<`u`&&self instanceof WorkerGlobalScope}function ce(e){let t=e||ie(),n=0,r;return function(e){let i=!e||isNaN(e)?Date.now():e;if(i<=n){let e=r=ne(r);return g(n,10)+e}n=i;let a=r=oe(16,t);return g(i,10)+a}}function le(e,t){let n=t||ie();return g(!e||isNaN(e)?Date.now():e,10)+oe(16,n)}const ue=`$rootRunId`,de=`$parentRunId`,_=`$retention`,v=`default`,fe=/^(?:0|[1-9]\d*)$/;function pe(e){let t=e?.[_];return t===void 0?{mode:`default`,wellFormed:!1,unsupported:!1}:fe.test(t)?t===`0`?{mode:`none`,raw:t,wellFormed:!0,unsupported:!1}:{mode:`default`,raw:t,wellFormed:!0,unsupported:!0}:{mode:`default`,raw:t,wellFormed:!1,unsupported:t!==v}}const y=8192,b=new TextEncoder;var x=class extends Error{constructor(e){super(e),this.name=`AttributeValidationError`}};function me(e){let t=b.encode(JSON.stringify(e)).length;if(t>8192)throw new x(`Attribute eventData exceeds limit ${y} UTF-8 JSON bytes (received ${t} bytes). Split the changes into smaller setAttributes() calls.`)}function he(e,t){if(typeof e!=`string`)throw new x(`Attribute key must be a string, got ${typeof e}`);if(e.length===0)throw new x(`Attribute key must not be empty`);if(e.length>256)throw new x(`Attribute key length ${e.length} exceeds limit 256: ${JSON.stringify(e.slice(0,32))}…`);if(!t&&e.startsWith(`$`))throw new x(`Attribute key ${JSON.stringify(e)} starts with reserved prefix "\$" — that namespace is reserved for framework/library code. Set { allowReservedAttributes: true } only if your caller is framework-level.`)}function ge(e){if(e!==null&&typeof e!=`string`)throw new x(`Attribute value must be a string or null, got ${typeof e}`);if(e===null)return;let t=b.encode(e).length;if(t>256)throw new x(`Attribute value byte length ${t} exceeds limit 256`)}function _e(e,t,n){return t===null?n?.has(e)?-1:0:+(n===void 0||!n.has(e))}function S(e,t={}){let n=new Set,r=t.existingKeys===void 0?void 0:t.existingKeys instanceof Set?t.existingKeys:new Set(t.existingKeys),i=r?.size??0;for(let{key:t,value:a}of e){if(n.has(t))throw new x(`Attribute key ${JSON.stringify(t)} appears more than once in the same batch`);n.add(t),i+=_e(t,a,r)}if(i>64)throw new x(`Run attribute count would exceed limit 64 (post-merge ${i})`)}function ve(e,t={}){for(let{key:n,value:r}of e)he(n,t.allowReservedAttributes===!0),ge(r);S(e,t)}function ye(e,t){let n={...e??{}};for(let{key:e,value:r}of t)r===null?delete n[e]:n[e]=r;return n}const be=new TextEncoder,C=t.compile(t.string().min(1,{error:`Attribute key must not be empty`}).max(256,{error:`Attribute key exceeds limit 256`})),w=t.compile(t.string().refine(e=>be.encode(e).length<=256,{error:`Attribute value exceeds limit 256 UTF-8 bytes`}).nullable()),xe=t.compile(t.object({key:C,value:w})),Se=t.compile(t.array(xe).superRefine((e,t)=>{try{S(e)}catch(n){if(!(n instanceof x))throw n;t.addIssue({code:`custom`,message:n.message,input:e})}}));function T(e,t){return Object.hasOwn(e,t)?e[t]:void 0}function Ce(e){return e.eventType===`noop`}const we={attr_set:`attr_set`,step_created:`step_created`,step_started:`step_started`,step_retrying:`step_retrying`,step_completed:`step_terminal`,step_failed:`step_terminal`,wait_created:`wait_created`,wait_completed:`wait_completed`,hook_created:`hook_created`,hook_disposed:`hook_disposed`,run_started:`run_started`};function Te(e){return T(we,e)}function Ee(e){let t=Te(e.eventType);if(t!==void 0)return t===`run_started`?{eventClass:t,entity:``}:e.correlationId?{eventClass:t,entity:e.correlationId}:void 0}const De={run_created:[`input`],run_started:[`input`],run_completed:[`output`],run_failed:[`error`],step_created:[`input`],step_started:[`input`],step_completed:[`result`],step_failed:[`error`],step_retrying:[`error`],hook_created:[`metadata`],hook_received:[`payload`]},Oe=[];function E(e){return T(De,e)??Oe}function ke(e){return E(e)[0]}const Ae=n.compile(n.instanceof(Uint8Array)),je=n.compile(n.any()),D=n.compile(n.union([Ae,je])),O=n.compile(n.enum([`run_created`,`run_started`,`run_completed`,`run_failed`,`run_cancelled`,`attr_set`,`step_created`,`step_completed`,`step_failed`,`step_retrying`,`step_started`,`hook_created`,`hook_received`,`hook_disposed`,`hook_conflict`,`wait_created`,`wait_completed`,`noop`]));n.compile(O.extract([`run_created`,`run_started`,`run_completed`,`run_failed`,`run_cancelled`])).options;const Me=n.compile(O.extract([`run_completed`,`run_failed`,`run_cancelled`])).options;function Ne(e){return Me.includes(e)}const Pe=n.compile(O.extract([`step_created`,`step_completed`,`step_failed`,`step_retrying`,`step_started`])).options;function Fe(e){return Pe.includes(e)}n.compile(O.extract([`step_completed`,`step_failed`])).options;const Ie=n.compile(O.extract([`hook_created`,`hook_received`,`hook_disposed`])).options;function Le(e){return Ie.includes(e)}const Re=n.compile(O.extract([`hook_disposed`,`hook_received`])).options;function ze(e){return Re.includes(e)}n.compile(O.extract([`wait_created`,`wait_completed`])).options;const Be=n.compile(O.extract([`step_created`,`hook_created`,`wait_created`])).options;function Ve(e){return Be.includes(e)}function He(e,t){if(t!==`none`||!(`eventData`in e))return e;let n=e.eventData;if(!n||typeof n!=`object`){let{eventData:t,...n}=e;return n}let r=E(e.eventType);if(r.length===0)return e;let i={...n};for(let e of r)delete i[e];let{eventData:a,...o}=e;return{...o,...Object.keys(i).length>0?{eventData:i}:{}}}const k=n.compile(n.object({eventType:O,correlationId:n.string().optional(),specVersion:n.number().optional()})),A={ttfs:n.number().optional(),stso:n.number().optional(),stepCount:n.number().int().positive().optional(),eventCount:n.number().int().positive().optional(),rsfs:n.number().optional(),finalSchedulingReplay:n.number().optional(),optimizations:n.array(n.string()).optional()},j=n.compile(k.extend({eventType:n.literal(`step_completed`),correlationId:n.string(),eventData:n.object({stepName:n.string().optional(),workflowName:n.string().optional(),result:D,...A})})),M=n.compile(k.extend({eventType:n.literal(`step_failed`),correlationId:n.string(),eventData:n.object({stepName:n.string().optional(),error:D,...A})})),N=n.compile(k.extend({eventType:n.literal(`step_retrying`),correlationId:n.string(),eventData:n.object({stepName:n.string().optional(),error:D,retryAfter:n.coerce.date().optional()})})),P=n.compile(k.extend({eventType:n.literal(`step_started`),correlationId:n.string(),eventData:n.object({stepName:n.string().optional(),attempt:n.number().optional(),workflowName:n.string().optional(),input:D.optional(),ownerMessageId:n.string().optional()}).optional()})),F=n.compile(k.extend({eventType:n.literal(`step_created`),correlationId:n.string(),eventData:n.object({stepName:n.string(),workflowName:n.string().optional(),input:D})})),I=n.compile(k.extend({eventType:n.literal(`hook_created`),correlationId:n.string(),eventData:n.object({token:n.string(),tokenRetentionUntil:n.coerce.date().optional(),metadata:D.optional(),isWebhook:n.boolean().optional(),isSystem:n.boolean().optional(),force:n.boolean().optional(),forceClaimedFrom:n.object({runId:n.string(),hookId:n.string(),workflowName:n.string().optional(),deploymentId:n.string().optional(),runSpecVersion:n.number().optional()}).optional()})})),L=n.compile(k.extend({eventType:n.literal(`hook_received`),correlationId:n.string(),eventData:n.object({token:n.string().optional(),payload:D})})),Ue=n.compile(k.extend({eventType:n.literal(`hook_disposed`),correlationId:n.string(),eventData:n.object({token:n.string().optional(),forceClaimedBy:n.object({runId:n.string(),hookId:n.string()}).optional()}).optional()})),We=n.compile(k.extend({eventType:n.literal(`hook_conflict`),correlationId:n.string(),eventData:n.object({token:n.string(),conflictingRunId:n.string().optional(),forceRefusedReason:n.literal(`victim-spec-version`).optional()})})),Ge=n.compile(k.extend({eventType:n.literal(`noop`),eventData:n.object({sealed:n.boolean().optional()}).passthrough().optional()})),R=n.compile(k.extend({eventType:n.literal(`wait_created`),correlationId:n.string(),eventData:n.object({resumeAt:n.coerce.date()})})),z=n.compile(k.extend({eventType:n.literal(`wait_completed`),correlationId:n.string(),eventData:n.object({resumeAt:n.coerce.date().optional()}).optional()})),Ke=n.compile(n.discriminatedUnion(`type`,[n.object({type:n.literal(`workflow`)}),n.object({type:n.literal(`step`),stepId:n.string(),attempt:n.number()})])),B=n.compile(k.extend({eventType:n.literal(`attr_set`),correlationId:n.string().optional(),eventData:n.object({changes:Se,writer:Ke,allowReservedAttributes:n.literal(!0).optional()})})),V=n.compile(k.extend({eventType:n.literal(`run_created`),eventData:n.object({deploymentId:n.string(),workflowName:n.string(),input:D,executionContext:n.record(n.string(),n.any()).optional(),attributes:n.record(n.string(),n.string()).optional(),allowReservedAttributes:n.literal(!0).optional(),dynamicWorkflowCode:D.optional(),dynamicWorkflowCodeRef:n.string().optional(),encryptionPublicKey:n.string().optional()}).refine(e=>e.dynamicWorkflowCode===void 0||e.dynamicWorkflowCodeRef===void 0,{path:[`dynamicWorkflowCodeRef`],message:`dynamicWorkflowCode and dynamicWorkflowCodeRef are mutually exclusive`})})),H=n.compile(k.extend({eventType:n.literal(`run_started`),eventData:n.object({input:D.optional(),deploymentId:n.string().optional(),workflowName:n.string().optional(),executionContext:n.record(n.string(),n.any()).optional(),attributes:n.record(n.string(),n.string()).optional(),allowReservedAttributes:n.literal(!0).optional(),encryptionPublicKey:n.string().optional(),dynamicWorkflowCode:D.optional(),dynamicWorkflowCodeRef:n.string().optional()}).refine(e=>e.dynamicWorkflowCode===void 0||e.dynamicWorkflowCodeRef===void 0,{path:[`dynamicWorkflowCodeRef`],message:`dynamicWorkflowCode and dynamicWorkflowCodeRef are mutually exclusive`}).optional()})),U=n.compile(k.extend({eventType:n.literal(`run_completed`),eventData:n.object({output:D.optional()})})),W=n.compile(k.extend({eventType:n.literal(`run_failed`),eventData:n.object({error:D,errorCode:n.string().optional()})})),qe=n.compile(k.extend({eventType:n.literal(`run_cancelled`),eventData:n.object({cancelReason:n.string().max(512).optional()}).optional()}));n.compile(n.discriminatedUnion(`eventType`,[V,H,U,W,qe,B,F,j,M,N,P,I,L,Ue,R,z]));const Je=n.compile(n.discriminatedUnion(`eventType`,[V,H,U,W,qe,B,F,j,M,N,P,I,L,Ue,We,R,z,Ge])),Ye=n.compile(Je.and(n.object({runId:n.string(),eventId:n.string(),createdAt:n.coerce.date(),occurredAt:n.coerce.date().optional(),specVersion:n.number().optional(),resumeId:n.string().optional()})));function Xe(e){return Ve(e.eventType)?!0:e.eventType===`step_started`&&typeof e.eventData?.stepName==`string`&&e.eventData.input!==void 0}const G=n.compile(n.enum([`pending`,`running`,`completed`,`failed`,`cancelled`])),Ze=n.compile(G.extract([`completed`,`failed`,`cancelled`])).options;function Qe(e){return Ze.includes(e)}const K=n.compile(n.object({runId:n.string(),status:G,deploymentId:n.string(),workflowName:n.string(),specVersion:n.number().optional(),executionContext:n.record(n.string(),n.any()).optional(),input:D.optional(),output:D.optional(),dynamicWorkflowCode:D.optional(),error:D.optional(),errorCode:n.string().optional(),attributes:n.record(n.string(),n.string()).default({}),encryptionPublicKey:n.string().optional(),expiredAt:n.coerce.date().optional(),startedAt:n.coerce.date().optional(),completedAt:n.coerce.date().optional(),createdAt:n.coerce.date(),updatedAt:n.coerce.date()})),$e=n.compile(n.discriminatedUnion(`status`,[K.extend({status:n.enum([`pending`,`running`]),output:n.undefined().optional(),error:n.undefined().optional(),completedAt:n.undefined().optional()}),K.extend({status:n.literal(`cancelled`),output:n.undefined().optional(),error:n.undefined().optional(),completedAt:n.coerce.date()}),K.extend({status:n.literal(`completed`),output:D.optional(),error:n.undefined().optional(),completedAt:n.coerce.date()}),K.extend({status:n.literal(`failed`),output:n.undefined().optional(),error:D.optional(),completedAt:n.coerce.date()})])),et=n.compile(n.object({runIds:n.array(n.string()).min(1).max(500).refine(e=>new Set(e).size===e.length,{message:`runIds must not contain duplicates`}),cancelReason:n.string().max(512).optional()})),tt=n.compile(n.discriminatedUnion(`outcome`,[n.object({runId:n.string(),outcome:n.literal(`cancelled`)}),n.object({runId:n.string(),outcome:n.literal(`already_cancelled`)}),n.object({runId:n.string(),outcome:n.literal(`not_cancellable`),status:n.string()}),n.object({runId:n.string(),outcome:n.literal(`not_found`)}),n.object({runId:n.string(),outcome:n.literal(`failed`),code:n.string(),retryable:n.boolean()})])),nt=n.compile(n.object({summary:n.object({requested:n.number(),cancelled:n.number(),alreadyCancelled:n.number(),notCancellable:n.number(),notFound:n.number(),failed:n.number()}),results:n.array(tt)})),q=n.compile(n.enum([`pending`,`running`,`completed`,`failed`,`cancelled`])),rt=n.compile(n.object({runId:n.string(),stepId:n.string(),stepName:n.string(),status:q,input:D.optional(),output:D.optional(),error:D.optional(),attempt:n.number(),startedAt:n.coerce.date().optional(),completedAt:n.coerce.date().optional(),createdAt:n.coerce.date(),updatedAt:n.coerce.date(),retryAfter:n.coerce.date().optional(),specVersion:n.number().optional()})),it=n.compile(q.extract([`completed`,`failed`,`cancelled`])).options;function at(e){return it.includes(e)}const ot=n.compile(n.enum([`waiting`,`completed`])),st=n.compile(n.object({waitId:n.string(),runId:n.string(),status:ot,resumeAt:n.coerce.date().optional(),completedAt:n.coerce.date().optional(),createdAt:n.coerce.date(),updatedAt:n.coerce.date(),specVersion:n.number().optional()})),ct=/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?$/,J=n.compile(n.preprocess(e=>typeof e==`string`&&ct.test(e)?`${e.replace(` `,`T`)}Z`:e,n.coerce.date())),Y=n.compile(J.nullable().optional()),X=n.compile(n.string().nullable().optional()),Z=n.compile(n.boolean().nullable().optional()),lt=n.compile(n.object({runId:n.string(),status:G,deploymentId:n.string(),workflowName:n.string(),specVersion:n.coerce.number().optional(),attributes:n.record(n.string(),n.string()).default({}),createdAt:J,updatedAt:J,startedAt:Y,completedAt:Y,errorCode:X,workflowCoreVersion:X,workflowEncryptionEnabled:Z})),ut=n.compile(n.object({runId:n.string(),stepId:n.string(),stepName:X,status:q,attempt:n.number().optional(),createdAt:J,updatedAt:J,startedAt:Y,completedAt:Y,retryAfter:Y,errorCode:X,workflowCoreVersion:X,workflowEncryptionEnabled:Z,computeInstanceId:X})),dt=n.compile(n.object({runId:n.string(),eventId:n.string(),eventType:O,correlationId:X,entityId:X,stepName:X,workflowName:n.string(),deploymentId:n.string(),specVersion:n.coerce.number().optional(),runCreatedAt:J,createdAt:J,region:X,vercelId:X,requestId:X,computeInstanceId:X,resumeAt:Y,retryAfter:Y,errorCode:X,workflowCoreVersion:X,isWebhook:Z,isSystem:Z,workflowEncryptionEnabled:Z})),ft=n.compile(n.object({runId:n.string(),hookId:n.string(),status:n.enum([`created`,`received`,`disposed`,`conflict`]),createdAt:J,updatedAt:J,receivedAt:Y,disposedAt:Y,isWebhook:Z,isSystem:Z,workflowCoreVersion:X,workflowEncryptionEnabled:Z})),pt=n.compile(n.object({runId:n.string(),waitId:n.string(),status:ot,resumeAt:Y,createdAt:J,updatedAt:J,completedAt:Y,workflowCoreVersion:X,workflowEncryptionEnabled:Z})),mt=n.compile(n.object({key:n.string(),runCount:n.coerce.number(),firstSeenAt:J,lastSeenAt:J})),ht=1e3,gt=n.compile(n.string().regex(/^__(?:[a-z][a-z0-9]*_)?wkf_workflow_$/,`Must match __wkf_workflow_ or __{namespace}_wkf_workflow_`)),_t=n.compile(n.string().regex(/^__(?:[a-z][a-z0-9]*_)?wkf_workflow_.+$/,`Must be a valid queue name with a recognized prefix`)),vt=n.compile(n.string().regex(/^[a-z][a-z0-9]*$/,`Must be lowercase alphanumeric, starting with a letter`));function yt(e){return e??process.env.WORKFLOW_QUEUE_NAMESPACE??void 0}function bt(e,t){if(e!==`workflow`)throw Error(`Unsupported queue kind: ${e}`);return t===void 0?`__wkf_workflow_`:(vt.parse(t),`__${t}_wkf_workflow_`)}function xt(e){let t=e.match(/^(__(?:[a-z][a-z0-9]*_)?wkf_workflow_)(.+)$/);if(!t)throw Error(`Invalid queue name: ${e}`);return{prefix:gt.parse(t[1]),id:t[2]}}const St=n.compile(n.string().brand().describe(`A stored queue message ID`)),Ct=n.compile(n.record(n.string(),n.string())),wt=n.compile(n.object({input:n.unknown(),deploymentId:n.string(),workflowName:n.string(),specVersion:n.number(),executionContext:n.record(n.string(),n.any()).optional(),dynamicWorkflowCode:D.optional(),dynamicWorkflowCodeRef:n.string().optional(),attributes:n.record(n.string(),n.string()).optional(),allowReservedAttributes:n.literal(!0).optional(),environment:n.string().optional()}).refine(e=>e.dynamicWorkflowCode===void 0||e.dynamicWorkflowCodeRef===void 0,{path:[`dynamicWorkflowCodeRef`],message:`dynamicWorkflowCode and dynamicWorkflowCodeRef are mutually exclusive`})),Tt=n.compile(n.object({input:n.custom(e=>e instanceof Uint8Array,{message:`stepInput.input must be a Uint8Array`})})),Et=n.compile(n.object({deploymentId:n.string(),specVersion:n.number(),startedAt:n.number().optional(),rootRunId:n.string().optional()})),Dt=n.compile(n.object({resumeId:n.string(),hookId:n.string(),token:n.string(),payload:n.unknown(),payloadDigest:n.string(),deploymentId:n.string().optional()})),Ot=n.compile(n.object({resumeRequestedAtMs:n.number(),queuePublishRequestedAtMs:n.number(),strategy:n.string().optional(),consumerStartedAtMs:n.number().optional(),replayStartedAtMs:n.number().optional(),nextStepEncounteredAtMs:n.number().optional(),setupSource:n.string().optional()})),kt=n.compile(n.object({runId:n.string(),invoke:n.literal(!0).optional(),requestId:n.string().optional(),input:n.unknown().optional(),traceCarrier:Ct.optional(),requestedAt:n.coerce.date().optional(),replayDivergence:n.object({eventId:n.string(),count:n.number().int().positive(),eventIds:n.array(n.string()).optional().catch(void 0)}).optional(),preconditionReinvocations:n.number().int().positive().optional(),serverErrorRetryCount:n.number().int().optional(),deploymentMismatchRetryCount:n.number().int().nonnegative().optional(),waitContinuation:n.object({correlationId:n.string(),attempt:n.number().int().nonnegative()}).optional().catch(void 0),stepId:n.string().optional(),stepName:n.string().optional(),runInput:wt.optional(),hookInput:Dt.optional(),stepInput:Tt.optional(),runContext:Et.optional(),hookResumeTiming:Ot.optional().catch(void 0)})),At=n.compile(n.object({__healthCheck:n.literal(!0),correlationId:n.string(),runId:n.string().optional()})),jt=n.compile(n.union([At,kt])),Mt=n.compile(n.object({deploymentId:n.string(),workflowName:n.string(),runSpecVersion:n.number().optional(),workflowCoreVersion:n.string().optional(),nodeVersion:n.string().optional(),traceCarrier:Ct.optional(),encryptionPublicKey:n.string().optional(),hookResumeInputVersion:n.number().optional()})),Nt=n.compile(n.object({hookResumeDedupVersion:n.number()})),Pt=n.compile(n.object({runId:n.string(),hookId:n.string(),workflowName:n.string().optional(),deploymentId:n.string().optional(),runSpecVersion:n.number().optional()})),Ft=n.compile(n.object({runId:n.string(),hookId:n.string(),token:n.string(),ownerId:n.string(),projectId:n.string(),environment:n.string(),metadata:D.optional(),createdAt:n.coerce.date(),specVersion:n.number().optional(),isWebhook:n.boolean().optional(),isSystem:n.boolean().optional(),tokenRetentionUntil:n.coerce.date().optional(),resumeContext:Mt.optional(),resumeCapabilities:Nt.optional(),claimedFrom:Pt.optional()})),It=`WORKFLOW_NODE_HTTP`;function Lt(e=process.env){return u(It,!1,e)}async function Rt(e,t,n,r){let i=bt(`workflow`,yt(r)),a=0,o,s=!0;for(;s;){let r=await e.list({status:[`pending`,`running`],resolveData:`none`,pagination:{cursor:o}});for(let e of r.data)try{await t(`${i}${e.workflowName}`,{runId:e.runId}),a++}catch(t){console.warn(`[${n}] Failed to re-enqueue run ${e.runId}: ${t}`)}s=r.hasMore,o=r.cursor??void 0}a>0&&zt()&&console.debug(`[${n}] Re-enqueued ${a} active run(s) on startup`)}function zt(){let e=typeof process<`u`?process.env.DEBUG:void 0;return typeof e==`string`?e.includes(`workflow:`)||e===`*`:!1}const Bt=n.lazy(()=>n.union([n.string(),n.number(),n.boolean(),n.null(),n.array(Bt),n.record(n.string(),Bt)])),Vt=n.compile(n.object({currentLookbackDays:n.number(),maxLookbackDays:n.number(),currentWindowStart:n.coerce.date(),maxWindowStart:n.coerce.date(),upgradeAvailable:n.boolean()})),Ht=e=>n.compile(n.object({data:n.array(e),cursor:n.string().nullable(),hasMore:n.boolean(),pageInfo:Vt.optional()}));function Ut(e){return e===`skip-step-inputs`?`all`:e}const Wt=n.compile(n.object({message:n.string(),stack:n.string().optional(),code:n.string().optional()})),Gt=`evnt_`;function Q(e){if(e.length!==26)return!1;for(let t=0;t<10;t++)if(e[t]!==`0`)return!1;for(let t=10;t<26;t++){let n=e.charCodeAt(t);if(n<48||n>57)return!1}return!0}function Kt(e){let t=e.indexOf(`_`);return t===-1?e:e.slice(t+1)}function qt(e){return Q(Kt(e))}function Jt(e){if(!Number.isSafeInteger(e)||e<1)throw RangeError(`Invalid event slot: ${e}`);return`${Gt}${String(e).padStart(26,`0`)}`}function Yt(e){let t=Kt(e);if(!Q(t))return null;let n=Number(t);return Number.isSafeInteger(n)&&n>=1?n:null}function Xt(e){let t=Yt(e);if(t===null)throw Error(`Event id is not slot-numbered: ${e}. This World allocates event positions the runtime cannot read.`);return t}const Zt=n.object({eventsCursor:n.string().nullable(),createdAt:n.coerce.date(),eventCount:n.number().int().nonnegative().optional(),rngDraws:n.number().int().nonnegative().optional(),serdeRootPtr:n.number().int().optional(),lastUlid:n.string().optional(),engineVersion:n.string().optional(),clockMs:n.number().optional(),formatVersion:n.number().int().optional()}),$=[87,83,78,80];function Qt(e,t){let n=new TextEncoder().encode(JSON.stringify(e)),r=new Uint8Array(9+n.length+t.length);return r.set($,0),r[4]=1,new DataView(r.buffer).setUint32(5,n.length,!0),r.set(n,9),r.set(t,9+n.length),r}function $t(e){if(e.length<9)return null;for(let t=0;t<$.length;t++)if(e[t]!==$[t])return null;if(e[4]!==1)return null;let t=new DataView(e.buffer,e.byteOffset,e.byteLength).getUint32(5,!0);if(9+t>e.length)return null;try{let n=new TextDecoder().decode(e.subarray(9,9+t));return{metadata:Zt.passthrough().parse(JSON.parse(n)),data:e.subarray(9+t)}}catch{return null}}function en(e=process.env){return u(`WORKFLOW_SEALED_LOG`,!0,e)?8:6}function tn(e){return e==null||e<=1}function nn(e){return e!=null&&e>8}const rn=n.compile(n.string().ulid()),an=n.compile(n.templateLiteral([`wrun_`,n.ulid()])),on=864e5,sn=3e5;function cn(e){if(Q(e))return null;let t=rn.safeParse(e);return t.success?new Date(re(t.data)):null}function ln(e,t,n=on,r=sn){let i=cn(e.startsWith(t)?e.slice(t.length):e);if(!i)return`Invalid runId: "${e}" is not a valid ULID`;let a=new Date().getTime()-i.getTime();return a>0&&a<=n||a<=0&&-a<=r?null:`Invalid runId timestamp: embedded timestamp is ${Math.round(Math.abs(a)/1e3)}s in the ${a>0?`past`:`future`} (threshold: ${Math.round((a>0?n:r)/1e3)}s)`}var un=e({ANALYTICS_EVENTS_GET_MANY_LIMIT:()=>100,ANALYTICS_MAX_ATTRIBUTE_FILTERS:()=>8,ANALYTICS_PAGE_LIMIT:()=>100,ANALYTICS_RUN_SCOPED_PAGE_LIMIT:()=>ht,ATTRIBUTE_EVENT_DATA_MAX_BYTES:()=>y,ATTRIBUTE_KEY_MAX_LENGTH:()=>256,ATTRIBUTE_MAX_PER_RUN:()=>64,ATTRIBUTE_VALUE_MAX_BYTES:()=>256,BULK_CANCEL_MAX_RUN_IDS:()=>500,DEFAULT_TIMESTAMP_THRESHOLD_FUTURE_MS:()=>sn,DEFAULT_TIMESTAMP_THRESHOLD_MS:()=>DEFAULT_TIMESTAMP_THRESHOLD_MS,DEFAULT_TIMESTAMP_THRESHOLD_PAST_MS:()=>on,EVENT_ID_BODY_LENGTH:()=>26,EVENT_ID_PREFIX:()=>Gt,FIRST_EVENT_SLOT:()=>1,HOOK_RESUME_DEDUP_VERSION:()=>1,HOOK_RESUME_INPUT_VERSION:()=>1,HookSchema:()=>Ft,NODE_HTTP_DEFAULT:()=>!1,NODE_HTTP_ENV_VAR:()=>It,RESERVED_ATTRIBUTE_KEY_PREFIX:()=>`$`,RETENTION_DEFAULT:()=>v,RETENTION_ZERO:()=>`0`,RUN_ENTITY_KEY:()=>``,SEALED_LOG_ENV_VAR:()=>`WORKFLOW_SEALED_LOG`,SNAPSHOT_FORMAT_VERSION:()=>3,SPEC_VERSION_CURRENT:()=>8,SPEC_VERSION_LEGACY:()=>1,SPEC_VERSION_MAX_SUPPORTED:()=>8,SPEC_VERSION_SUPPORTS_ATTRIBUTES:()=>4,SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT:()=>3,SPEC_VERSION_SUPPORTS_COMPRESSION:()=>5,SPEC_VERSION_SUPPORTS_EVENT_SOURCING:()=>2,SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM:()=>8,SPEC_VERSION_SUPPORTS_SEALED_LOG:()=>7,SPEC_VERSION_SUPPORTS_SLOT_IDENTITY:()=>6});export{ke as $,dt as A,K as B,_t as C,yt as D,xt as E,st as F,Xe as G,Qe as H,rt as I,Fe as J,ze as K,at as L,lt as M,ut as N,ht as O,pt as P,Ee as Q,et as R,jt as S,bt as T,Ye as U,$e as V,O as W,He as X,Ne as Y,D as Z,Rt as _,i as _t,tn as a,de as at,At as b,$t as c,ye as ct,qt as d,me as dt,E as et,Xt as f,re as ft,Ut as g,ee as gt,Wt as h,l as ht,an as i,x as it,ft as j,mt as k,Qt as l,pe as lt,Ht as m,le as mt,cn as n,C as nt,en as o,_ as ot,Jt as p,ce as pt,Le as q,ln as r,w as rt,nn as s,ue as st,un as t,Ce as tt,Yt as u,ve as ut,Lt as v,kt as w,St as x,Ft as y,nt as z};
@@ -1 +0,0 @@
1
- import{A as e,F as t}from"./dist-T5NnW-0k.js";function n(){let e,t;return{promise:new Promise((n,r)=>{e=n,t=r}),resolve:e,reject:t}}function r(e){let t={get value(){let n=e();return Object.defineProperty(t,"value",{value:n}),n}};return t}var i=class e extends Error{items;steps;globalThis;stepCount;hookCount;waitCount;attributeCount;hookDisposedCount;abortCount;constructor(e,n){let r=[...e.values()],i=0,a=0,o=0,s=0,c=0,l=0;for(let e of r)e.type===`step`?i++:e.type===`hook`?e.disposed?c++:e.abortRequested?l++:a++:e.type===`wait`?o++:e.type===`attribute`&&s++;let u=[];i>0&&u.push(`${i} ${t(`step`,`steps`,i)}`),a>0&&u.push(`${a} ${t(`hook`,`hooks`,a)}`),o>0&&u.push(`${o} ${t(`wait`,`waits`,o)}`),s>0&&u.push(`${s} ${t(`attribute write`,`attribute writes`,s)}`),c>0&&u.push(`${c} hook ${t(`disposal`,`disposals`,c)}`);let d=i+a+o+s+c,f=t(`has`,`have`,d),p=+(i>0)+ +(a>0)+ +(o>0)+ +(s>0)+ +(c>0),m;m=p>1?`processed`:i>0?`run`:a>0||o>0?`created`:s>0?`written`:c>0?`processed`:`received`;let h=u.length>0?`${u.join(` and `)} ${f} not been ${m} yet`:`0 steps have not been run yet`;super(h),this.name=`WorkflowSuspension`,this.items=r,this.steps=r,this.globalThis=n,this.stepCount=i,this.hookCount=a,this.waitCount=o,this.attributeCount=s,this.hookDisposedCount=c,this.abortCount=l}static is(t){return t instanceof e}};function a(){throw new e(`This API is not available inside a workflow function. Workflow functions run in a deterministic VM; move the call to a step function for full Node.js access.`)}const o=Symbol.for(`@workflow/core//registeredSteps`),s=globalThis,c=s[o]??=new Map,l=new Set([`__builtin_response_array_buffer`,`__builtin_response_json`,`__builtin_response_text`]);function u(e){let t=e.split(`//`);if(t.length!==3||t[0]!==`step`)return[];let n=t[1],r=t[2],i=new Set,a=e=>{e!==n&&i.add(e)};if(n.startsWith(`./workflows/`)){let e=n.slice(2);a(`./example/${e}`),a(`./src/${e}`)}else if(n.startsWith(`./example/workflows/`)){let e=n.slice(10);a(`./${e}`),a(`./src/${e}`)}else if(n.startsWith(`./src/workflows/`)){let e=n.slice(6);a(`./${e}`),a(`./example/${e}`)}return Array.from(i,e=>`step//${e}//${r}`)}function d(e){if(l.has(e)){for(let[t,n]of c.entries())if(t.endsWith(`//${e}`))return n}}function f(e,t){c.set(e,t),t.stepId=e}function p(e){let t=c.get(e);if(t)return t;for(let t of u(e)){let e=c.get(t);if(e)return e}let n=d(e);if(n)return n}const m={hook:[`hook`,`wait`,`step`],wait:[`hook`,`step`],step:[`wait`,`hook`,`step`]};function h(e,t,n,r){return n>=t||!m[e].includes(r.kind)?!1:!(e===`step`&&!r.armed)}function g(e,t,n,r){let i=r.get(t);if(i!==void 0)return i;let a=_(e,t,n,r);return r.set(t,a),a}function _(e,t,n,r){if(!n.armed)return!1;for(let[i,a]of e)if(h(n.kind,t,i,a)&&!g(e,i,a,r))return!1;return!0}function v(){return process.env.WORKFLOW_LOG_ORDER_DRAWS!==`0`}function y(e){return e===0&&typeof setImmediate==`function`?new Promise(e=>setImmediate(e)):new Promise(t=>setTimeout(t,e))}async function b(e,t){for(;;){let n=e.mintCount??0,r=e.pendingDeliveries;if(await y(await e.promiseQueue.then(()=>!1,()=>!0)?50:0),(e.mintCount??0)!==n||r!==0||e.pendingDeliveries!==0)continue;let i=!1;for(let[n,r]of e.pendingDeliveryBarriers??[])if(n<t&&r.armed){i=!0;break}if(!i)return}}async function x(e,t,n){if(t===void 0||!e.pendingDeliveryBarriers)return;let r=e.pendingDeliveryBarriers,i=[];for(let[e,a]of r)h(n,t,e,a)&&i.push(a.released);if(i.length>0&&await Promise.all(i),v()){await b(e,t);return}i.length>0&&await new Promise(e=>setTimeout(e,0))}function S(t,r,i,a){let o=!1,s=()=>!o&&(o=!0,t.advanceClock?.(a.deliveredAt),!0),c=t.pendingDeliveryBarriers;if(!c||r===void 0)return{markDelivered:()=>{s()},arm:()=>{}};let l=a=>{if(c.has(r))throw new e(`Delivery barrier already registered at event index ${r}`);let{promise:o,resolve:s}=n(),l={kind:i,released:o,armed:a,retired:!1,retire:()=>{l.retired||(l.retired=!0,c.get(r)===l&&c.delete(r),s())}};return c.set(r,l),w(t),l},u=l(a.armed??!0);return{markDelivered:()=>{s()&&u.retire()},arm:()=>{if(!o){if(u.retired){u=l(!0);return}if(c.get(r)!==u)throw new e(`Delivery barrier lost ownership of event index ${r}`);u.armed=!0}}}}const C=new WeakSet;function w(e){let t=e.pendingDeliveryBarriers;if(!t||C.has(e))return;C.add(e);let n=()=>{setTimeout(i,0)},r=()=>{setTimeout(i,50)},i=()=>{if(t.size===0){C.delete(e);return}if(!T(e)){e.promiseQueue.then(n,r);return}for(;t.size>0&&T(e);){let e,n;for(let[r,i]of t)(e===void 0||r<e)&&(e=r,n=i);n?.retire()}setTimeout(i,0)};setTimeout(i,0)}function T(e){return e.pendingDeliveries===0&&!E(e)}function E(e){let t=e.pendingDeliveryBarriers;if(!t||t.size===0)return!1;let n=new Map;for(let[e,r]of t)if(g(t,e,r,n))return!0;return!1}function D(e){return e.pendingDeliveries===0&&(!e.pendingDeliveryBarriers||e.pendingDeliveryBarriers.size===0)}function O(e,t){let n=()=>{D(e)?t():e.promiseQueue.then(()=>{setTimeout(n,0)})};setTimeout(n,0)}function k(e){let t=e.suspensionGeneration;O(e,()=>{t===e.suspensionGeneration&&e.onWorkflowError(new i(e.invocationsQueue,e.globalThis))})}export{S as a,k as c,r as d,n as f,D as i,a as l,p as n,f as o,E as r,O as s,x as t,i as u};