eve 0.51.1 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/src/cli/dev/boot-progress.d.ts +3 -0
  3. package/dist/src/cli/dev/boot-progress.js +1 -0
  4. package/dist/src/cli/run.d.ts +4 -0
  5. package/dist/src/cli/run.js +3 -3
  6. package/dist/src/cli/telemetry/command.d.ts +9 -0
  7. package/dist/src/cli/telemetry/command.js +1 -0
  8. package/dist/src/cli/telemetry/flush.d.ts +2 -0
  9. package/dist/src/cli/telemetry/flush.js +1 -0
  10. package/dist/src/cli/telemetry/identity.d.ts +13 -0
  11. package/dist/src/cli/telemetry/identity.js +1 -0
  12. package/dist/src/cli/telemetry/index.d.ts +25 -0
  13. package/dist/src/cli/telemetry/index.js +3 -0
  14. package/dist/src/cli/telemetry/preference.d.ts +9 -0
  15. package/dist/src/cli/telemetry/preference.js +1 -0
  16. package/dist/src/client/types.d.ts +3 -2
  17. package/dist/src/compiled/.vendor-stamp.json +2 -2
  18. package/dist/src/compiled/@eve/catalog/index.js +1 -1
  19. package/dist/src/compiled/@modelcontextprotocol/server/index.d.ts +1 -0
  20. package/dist/src/compiler/extension-compatibility.d.ts +22 -4
  21. package/dist/src/compiler/extension-compatibility.js +1 -1
  22. package/dist/src/compiler/manifest.js +1 -1
  23. package/dist/src/compiler/normalize-channel.js +1 -1
  24. package/dist/src/compiler/normalize-schedule.js +1 -1
  25. package/dist/src/compiler/normalize-tool.js +1 -1
  26. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  27. package/dist/src/execution/activity-collector.js +1 -1
  28. package/dist/src/execution/continuation-conflict-step.js +1 -1
  29. package/dist/src/execution/coordination-dispatch-shared.d.ts +2 -2
  30. package/dist/src/execution/coordination-dispatch-step.js +1 -1
  31. package/dist/src/execution/durable-session-migrations/turn-workflow.d.ts +1 -1
  32. package/dist/src/execution/inline-turn.d.ts +2 -2
  33. package/dist/src/execution/inline-turn.js +1 -1
  34. package/dist/src/execution/tasks/child/steps.d.ts +11 -1
  35. package/dist/src/execution/tasks/child/steps.js +1 -1
  36. package/dist/src/execution/tasks/child/workflow.js +1 -1
  37. package/dist/src/execution/tasks/parent/tool-execution.js +1 -1
  38. package/dist/src/execution/tools/sleep-workflow.js +1 -1
  39. package/dist/src/execution/tools/subagent/invoke-agent.d.ts +1 -7
  40. package/dist/src/execution/tools/subagent/invoke-agent.js +1 -1
  41. package/dist/src/execution/tools/workflow/ask.d.ts +1 -2
  42. package/dist/src/execution/tools/workflow/ask.js +1 -1
  43. package/dist/src/execution/tools/workflow/body.d.ts +6 -1
  44. package/dist/src/execution/tools/workflow/body.js +1 -1
  45. package/dist/src/execution/tools/workflow/cancel.js +1 -1
  46. package/dist/src/execution/tools/workflow/messages.d.ts +9 -8
  47. package/dist/src/execution/tools/workflow/messages.js +1 -1
  48. package/dist/src/execution/tools/workflow/owner-inbox.d.ts +2 -2
  49. package/dist/src/execution/tools/workflow/owner-inbox.js +1 -1
  50. package/dist/src/execution/tools/workflow/owner.d.ts +5 -11
  51. package/dist/src/execution/tools/workflow/owner.js +1 -1
  52. package/dist/src/execution/tools/workflow/run-control.d.ts +0 -4
  53. package/dist/src/execution/tools/workflow/run-control.js +1 -1
  54. package/dist/src/execution/tools/workflow/start.d.ts +5 -14
  55. package/dist/src/execution/tools/workflow/start.js +1 -1
  56. package/dist/src/execution/tools/workflow/workflow.d.ts +1 -1
  57. package/dist/src/execution/tools/workflow/workflow.js +1 -1
  58. package/dist/src/execution/turn-dispatch.js +1 -1
  59. package/dist/src/execution/turn-workflow-tool-run.d.ts +2 -8
  60. package/dist/src/execution/turn-workflow-tool-run.js +1 -1
  61. package/dist/src/execution/turn-workflow.d.ts +1 -0
  62. package/dist/src/execution/turn-workflow.js +1 -1
  63. package/dist/src/execution/wire/session-inbox-resume.js +1 -1
  64. package/dist/src/execution/workflow-runtime.js +1 -1
  65. package/dist/src/execution/workflow-steps.js +1 -1
  66. package/dist/src/harness/emission-state.js +1 -1
  67. package/dist/src/harness/tool-loop.js +2 -2
  68. package/dist/src/harness/turn-client-context.d.ts +9 -0
  69. package/dist/src/harness/turn-client-context.js +1 -0
  70. package/dist/src/harness/workflow-tool-runs.d.ts +0 -1
  71. package/dist/src/harness/workflow-tool-runs.js +1 -1
  72. package/dist/src/internal/application/package.js +1 -1
  73. package/dist/src/internal/authored-definition/schema-backed.js +1 -1
  74. package/dist/src/internal/invocation/workflow-execution.js +1 -1
  75. package/dist/src/internal/mcp/streamable-http-server.d.ts +29 -1
  76. package/dist/src/internal/mcp/streamable-http-server.js +1 -1
  77. package/dist/src/internal/nitro/host/build-application.js +1 -1
  78. package/dist/src/internal/workflow/runtime.d.ts +6 -0
  79. package/dist/src/internal/workflow/runtime.js +1 -1
  80. package/dist/src/internal/workflow-bundle/authored-workflow-directives.d.ts +1 -3
  81. package/dist/src/internal/workflow-bundle/authored-workflow-directives.js +1 -1
  82. package/dist/src/internal/workflow-bundle/authored-workflow-modules.d.ts +1 -2
  83. package/dist/src/internal/workflow-bundle/authored-workflow-modules.js +1 -1
  84. package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +1 -1
  85. package/dist/src/internal/workflow-bundle/workflow-builders.d.ts +0 -2
  86. package/dist/src/internal/workflow-bundle/workflow-builders.js +1 -1
  87. package/dist/src/internal/workflow-bundle/workflow-transformer.js +1 -1
  88. package/dist/src/protocol/message.d.ts +3 -2
  89. package/dist/src/public/channels/mcp.js +1 -1
  90. package/dist/src/public/models/openai/chatgpt/model.js +2 -2
  91. package/dist/src/public/models/openai/chatgpt/transport.js +1 -1
  92. package/dist/src/public/tools/index.d.ts +3 -1
  93. package/dist/src/public/tools/index.js +1 -1
  94. package/dist/src/setup/scaffold/create/project.js +1 -1
  95. package/dist/src/shared/workflow-tool-context.d.ts +2 -0
  96. package/dist/src/shared/workflow-tool-context.js +1 -0
  97. package/dist/src/tasks/types.d.ts +17 -1
  98. package/dist/src/tasks/types.js +1 -1
  99. package/dist/src/tools/behavior.d.ts +5 -0
  100. package/dist/src/tools/definition.d.ts +16 -12
  101. package/dist/src/tools/definition.js +1 -1
  102. package/dist/src/tools/dynamic.d.ts +2 -2
  103. package/dist/src/tools/provided/sleep.d.ts +2 -2
  104. package/dist/src/tools/provided/sleep.js +1 -1
  105. package/dist/src/tools/task.d.ts +28 -80
  106. package/dist/src/tools/task.js +1 -1
  107. package/dist/src/tools/workflow-definition.d.ts +60 -0
  108. package/dist/src/tools/workflow-definition.js +1 -0
  109. package/docs/channels/mcp.mdx +25 -3
  110. package/docs/concepts/execution-model-and-durability.mdx +13 -2
  111. package/docs/guides/client/messages.mdx +1 -1
  112. package/docs/guides/deployment/vercel.mdx +2 -0
  113. package/docs/guides/frontend/overview.mdx +1 -1
  114. package/docs/memory/overview.mdx +40 -11
  115. package/docs/reference/cli.md +31 -33
  116. package/docs/reference/meta.json +1 -4
  117. package/docs/reference/telemetry.md +56 -0
  118. package/docs/reference/typescript-api.md +38 -35
  119. package/docs/tools/overview.mdx +59 -18
  120. package/docs/tools/workflows.mdx +146 -70
  121. package/package.json +1 -7
  122. package/dist/src/public/workflow/index.d.ts +0 -5
  123. package/dist/src/public/workflow/index.js +0 -1
@@ -4,19 +4,20 @@ description: "Define durable workflow tools that wait for people, webhooks, or t
4
4
  url: /tools/workflows
5
5
  ---
6
6
 
7
- A workflow tool is an authored tool whose `execute` function starts with `"use workflow"`. Each
8
- call starts a durable Workflow run. Use one when a tool must wait for a person, webhook, or timer,
7
+ A workflow tool is a static tool defined with `defineWorkflowTool` from `eve/tools`, with
8
+ `"use workflow"` as the first statement of its executor. Each call starts a durable Workflow run. Use one when a tool must wait for a person, webhook, or timer,
9
9
  delegate work to subagents, or coordinate retryable steps over a long period.
10
10
 
11
- By default, the model's tool call waits for the run's return value. While the run is suspended, the
12
- turn is parked and holds no compute. Set `execution: "background"` when the conversation should
13
- continue; the model receives a task receipt, and eve wakes the agent with the result when the run
14
- ends.
11
+ Durable suspension and background execution are independent. `defineWorkflowTool` lets the body
12
+ suspend at durable waits without holding compute. `execution: "background"` determines whether
13
+ the parent agent receives a task receipt and continues before the body finishes. A workflow can
14
+ suspend in either execution mode; running in the background does not require a suspension.
15
15
 
16
- Workflow tools use the [Workflow SDK](https://workflow-sdk.dev): `"use workflow"`, `"use step"`,
17
- `createHook`, `createWebhook`, `sleep`, retries, and replay. eve adds `ask` from `eve/workflow` for
18
- questions answered through the session's channel and `agent` for durable subagent delegation. Each
19
- `yield` becomes a durable progress report.
16
+ Workflow tools use the [Workflow SDK](https://workflow-sdk.dev): `"use workflow"`, `"use step"`, `createHook`,
17
+ `createWebhook`, `sleep`, retries, and replay. eve provides `ctx.ask` for questions answered through
18
+ the session's channel and `ctx.agent` for durable subagent delegation. Use `yield` to report
19
+ progress and `await` on a workflow operation to wait durably. Values needed after a durable wait
20
+ stay in local variables in the workflow body.
20
21
 
21
22
  A workflow tool runs code you wrote and appears to the model under its path-derived tool name, such
22
23
  as `deploy`.
@@ -24,19 +25,17 @@ as `deploy`.
24
25
  ## Define a workflow tool
25
26
 
26
27
  ```ts title="agent/tools/deploy.ts"
27
- import { defineTool } from "eve/tools";
28
- import { ask } from "eve/workflow";
28
+ import { defineWorkflowTool } from "eve/tools";
29
29
  import { z } from "zod";
30
30
  import { computePlan, runDeploy, type DeployPlan } from "../lib/deploy";
31
31
 
32
- export default defineTool({
32
+ export default defineWorkflowTool({
33
33
  description: "Deploy a service to production. Pauses for a human to approve the plan.",
34
34
  inputSchema: z.object({ service: z.string() }),
35
35
  async execute({ service }, ctx) {
36
36
  "use workflow";
37
-
38
37
  const plan = await planDeploy(service);
39
- const answer = await ask(ctx, {
38
+ const answer = await ctx.ask({
40
39
  prompt: `Deploy ${service}?\n\n${plan.summary}`,
41
40
  display: "confirmation",
42
41
  options: [
@@ -68,39 +67,91 @@ or days later, the run resumes, deploys, and returns. The model sees one tool re
68
67
 
69
68
  ### Rules
70
69
 
71
- - `"use workflow"` goes on its own line as the first statement of `execute`, or of a top-level
72
- `async function` you reference as `execute: deploy`.
70
+ - Export `defineWorkflowTool({ ... })` as the default export. Its `execute` must be an async
71
+ function or async generator, written inline or referenced as a top-level `async function` in
72
+ the same module or an imported application module. Start the executor with `"use workflow"`
73
+ as its first statement. A missing
74
+ directive is a build error, even if another function in the module has one.
73
75
  - `"use step"` marks a top-level `async function` in the tool module, or any module it imports, as a
74
76
  step. Side effects, clocks, randomness, `process.env`, and Node.js APIs belong in steps; the body
75
77
  is replayed and must stay deterministic.
76
78
  - Import `createHook`, `createWebhook`, `sleep`, and `FatalError` from `workflow` in the body.
77
79
  `start`, `getRun`, and `resumeHook` from `workflow/api` belong in steps. Your app does not install
78
80
  the SDK; for types, new projects list `eve/workflow-modules` in the tsconfig `types`.
79
- - In the body, `ctx` has `session`, `callId`, `toolName`, and `abortSignal`. `getSandbox`,
80
- `getSkill`, `getToken`, and `requireAuth` throw there; read credentials in a step instead.
81
+ - In the body, `ctx` has `session`, `callId`, `toolName`, `abortSignal`, `agent`, and `ask`.
82
+ `getSandbox`, `getSkill`, `getToken`, and `requireAuth` are not part of `WorkflowToolContext`.
83
+ Read credentials from `process.env` in a step; session-scoped workflow authorization is not yet available.
81
84
  - The tool's input must be a JSON object. Workflow bodies are for static tools under `agent/tools/`,
82
85
  not tools returned from `defineDynamic` resolvers.
83
86
 
87
+ `ctx.agent` and `ctx.ask` are available only on `WorkflowToolContext`. Ordinary tools, channel
88
+ handlers, and schedule handlers do not receive these methods. A shared helper may accept
89
+ `WorkflowToolContext` from `eve/tools` and use the context supplied by a workflow tool body.
90
+
91
+ Workflow executors require `defineWorkflowTool`. Adding `"use workflow"` to `defineTool`, a bare
92
+ tool object, a channel handler, or a schedule handler fails the build. To start a session from a
93
+ channel or schedule, use the [channel operations](/docs/channels/custom#channel-operations-and-session-handles)
94
+ or [schedule handler](/docs/schedules#handler-form-run) APIs.
95
+
96
+ ### Migrate an existing workflow tool
97
+
98
+ Replace `defineTool` with `defineWorkflowTool`, keep the executor's `"use workflow"` directive,
99
+ and replace `agent(ctx, input)` and `ask(ctx, request)` with `ctx.agent(input)` and `ctx.ask(request)`.
100
+ The `eve/workflow` entry point has been removed. Import `WorkflowToolContext`, `AgentInput`,
101
+ `ToolInputRequest`, and `ToolInputResponse` from `eve/tools` when you need explicit types.
102
+
84
103
  ## Wait or run in the background
85
104
 
86
- | | default | `execution: "background"` |
87
- | ------------------------ | ----------------------------------- | ------------------------------------------- |
88
- | tool result | the run's return value | `{ status: "working", taskId }` |
89
- | turn while the run lives | parked | continues |
90
- | when the run ends | result lands in the tool call | agent is woken with the result or the error |
91
- | progress (`yield`) | `action.partial` on the turn | wakes the agent with a note |
92
- | cancel | cancelling the turn cancels the run | `task_cancel`, or the session ending |
105
+ Both modes support the same durable waits. Choose the execution mode based on when the parent
106
+ agent should receive a tool result:
93
107
 
94
- Wait when the model needs the answer to continue. Go background when the wait may outlive the
95
- conversation or the user should keep talking in the meantime. Background tools need no root-agent
96
- flag.
108
+ | | Default execution | `execution: "background"` |
109
+ | ---------------------------- | --------------------------------------------------- | -------------------------------------------------------------------- |
110
+ | Tool result | The workflow's output after it finishes. | `{ status: "working", taskId }` before the body finishes. |
111
+ | Parent turn | Waits for this tool call to finish. | Continues after receiving the receipt. |
112
+ | Durable wait inside the body | Suspends the workflow; the tool call stays pending. | Suspends the workflow; the parent can continue independently. |
113
+ | When the run ends | Settles the pending tool call. | Sends a task completion or failure notification to the parent agent. |
114
+ | Cancel | Cancelling the turn cancels the run. | `task_cancel`, or the session ending. |
97
115
 
98
- ## Ask a human: `ask`
116
+ Use default execution when the model needs the answer to continue. Use background execution when
117
+ the conversation should continue while the task is pending. Background tools need no root-agent
118
+ flag. Ordinary `defineTool` also accepts `execution: "background"`, but its executor still runs
119
+ inside the initiating step and cannot suspend at workflow waits. See the
120
+ [tool execution comparison](/docs/tools#background-execution).
121
+
122
+ ### How suspension works
123
+
124
+ Suspension happens when a workflow must wait for an unresolved durable operation, such as
125
+ `ctx.ask`, an awaited hook or webhook, or `sleep`. The runtime persists the wait and releases the
126
+ workflow's compute. When the answer, event, or timer arrives, the runtime replays the workflow,
127
+ reuses recorded step results, and continues past the wait. Put side effects in `"use step"`
128
+ functions so replay does not repeat completed effects.
129
+
130
+ Consider a body that reports progress and then asks for approval:
99
131
 
100
132
  ```ts
101
- import { ask } from "eve/workflow";
133
+ async *execute(input, ctx) {
134
+ "use workflow";
135
+ yield { status: "awaiting approval" };
136
+ const answer = await ctx.ask({ prompt: "Continue?", display: "confirmation" });
137
+ return { answer };
138
+ }
139
+ ```
140
+
141
+ The yield reports a snapshot, and eve advances the generator to `ctx.ask`. Awaiting the unanswered
142
+ request is the durable wait. In default execution, the original tool call remains pending until
143
+ the answer arrives and the body returns. With `execution: "background"`, the original call has
144
+ already returned a task receipt, and the workflow can suspend while the conversation continues.
145
+ Answering resumes the body in either mode.
146
+
147
+ `yield` itself does not wait for approval or switch a tool into background execution. An ordinary
148
+ Promise or Node.js timer inside a step also does not create a durable workflow suspension; use
149
+ the workflow operations for waits that must survive a restart.
150
+
151
+ ## Ask a human: `ctx.ask`
102
152
 
103
- const answer = await ask(ctx, {
153
+ ```ts
154
+ const answer = await ctx.ask({
104
155
  prompt: string,
105
156
  display?: "confirmation" | "select" | "text",
106
157
  options?: { id: string; label: string; description?: string; style?: "primary" | "danger" | "default" }[],
@@ -108,13 +159,12 @@ const answer = await ask(ctx, {
108
159
  }); // { optionId?: string; text?: string }
109
160
  ```
110
161
 
111
- `ask` publishes an `input.requested` event on the session — rendered the way channels render
112
- `ask_question` and tool approvals — and returns the hook the answer resumes, the way `createHook`
113
- returns one. Awaiting it suspends the run until a response arrives. Because it is a hook, it composes
114
- with the SDK's own constructs; race it against a deadline:
162
+ `ctx.ask` publishes an `input.requested` event on the session — rendered the way channels render
163
+ `ask_question` and tool approvals — and returns an awaitable answer. Awaiting it suspends the run until a response arrives.
164
+ It composes with the SDK's own constructs; race it against a deadline:
115
165
 
116
166
  ```ts
117
- const pending = ask(ctx, { prompt: `Deploy ${service}?`, options: APPROVE_OR_CANCEL });
167
+ const pending = ctx.ask({ prompt: `Deploy ${service}?`, options: APPROVE_OR_CANCEL });
118
168
  const answer = await Promise.race([pending, sleep("4h")]);
119
169
  if (answer === undefined) return { deployed: false, reason: "timed out" };
120
170
  ```
@@ -128,16 +178,14 @@ if (answer === undefined) return { deployed: false, reason: "timed out" };
128
178
  normal `turnPolicy`.
129
179
 
130
180
  Compare the [`approval`](/docs/human-in-the-loop) policy, which gates the call before `execute` runs
131
- and can only show the model's input. Both compose: `approval` before the run, `ask` inside it.
181
+ and can only show the model's input. Both compose: `approval` before the run, `ctx.ask` inside it.
132
182
 
133
- ## Delegate work: `agent`
183
+ ## Delegate work: `ctx.agent`
134
184
 
135
185
  Workflow tools can call a visible subagent and wait for its result:
136
186
 
137
187
  ```ts
138
- import { agent } from "eve/workflow";
139
-
140
- const result = await agent(ctx, {
188
+ const result = await ctx.agent({
141
189
  key: "security-review",
142
190
  target: "reviewer",
143
191
  message: "Review the deployment plan for security risks.",
@@ -151,23 +199,49 @@ keys. `target` is the model-visible subagent name; pass `agentId` to continue an
151
199
 
152
200
  ## Report progress: `yield`
153
201
 
154
- A workflow body may be an async generator. Each `yield` is a durable progress snapshot; the return
155
- value is the result, or the last `yield` when the body returns nothing.
202
+ A workflow body may be an async generator. Ordinary yields report progress in both execution
203
+ modes. After processing a yield, eve advances the generator; use an awaited workflow operation
204
+ when the body needs to suspend.
156
205
 
157
- ```ts
158
- async *execute({ service }, ctx) {
159
- "use workflow";
160
- yield { status: "planning" };
161
- const plan = await planDeploy(service);
162
- yield { status: "deploying" };
163
- return { deployed: true, url: await applyDeploy(plan) };
164
- }
206
+ | Operation | Default execution | `execution: "background"` |
207
+ | --------------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------- |
208
+ | `yield value` | Emits an `action.partial` snapshot for the pending tool call. | Emits stream-only task progress; does not request a parent-agent turn. |
209
+ | `yield task.postMessage(message)` | Unavailable; there is no `task` argument. | Sends a message requesting a parent-agent turn; the task stays open. |
210
+ | `return value` | Settles the tool call with its output. | Completes the task and delivers its output in a later notification. |
211
+ | No return value | Uses the last yield as output, or `null` if there were no yields. | Completes with `null`; yielded progress is not the task output. |
212
+
213
+ For default execution, an explicit `return null` also falls back to the last yield. Prefer an
214
+ explicit object return when progress snapshots and the final result have different shapes.
215
+ Progress snapshots are last-write-wins by tool call id and do not enter model history as
216
+ intermediate tool results. A snapshot used as the final output does enter history as the tool result.
217
+
218
+ This background workflow reports progress, sends the parent one message, and then suspends:
219
+
220
+ ```ts title="agent/tools/remind_with_progress.ts"
221
+ import { defineWorkflowTool } from "eve/tools";
222
+ import { sleep } from "workflow";
223
+ import { z } from "zod";
224
+
225
+ export default defineWorkflowTool({
226
+ description: "Schedule a reminder and report progress before waiting.",
227
+ inputSchema: z.object({ note: z.string(), delay: z.string() }),
228
+ execution: "background",
229
+ async *execute({ note, delay }, ctx, task) {
230
+ "use workflow";
231
+ yield { status: "preparing reminder" }; // Stream-only progress.
232
+ yield task.postMessage(`Reminder scheduled for ${delay}.`); // Parent-agent message.
233
+ await sleep(delay); // Durable suspension while the timer is pending.
234
+ return { reminder: note }; // Task completion notification.
235
+ },
236
+ });
165
237
  ```
166
238
 
167
- For a waiting tool each `yield` streams as an `action.partial` event, last-write-wins by tool call
168
- id, and never enters model history — the same contract as an in-process generator tool. For a
169
- background tool each `yield` wakes the owning agent with a note. Returning ends the run with the
170
- result; throwing ends it with the failure.
239
+ Calling `task.postMessage` constructs a descriptor; yielding it sends the message. It does not
240
+ wait for a reply. Use [`ctx.ask`](#ask-a-human-ctxask) when the workflow needs a human answer.
241
+ Removing `execution: "background"` requires removing the `task` argument and message yield; the
242
+ ordinary progress yield and `await sleep(delay)` still work, but the model waits for the final
243
+ reminder as the tool result. See [yield and return](/docs/tools#yield-and-return) for the different
244
+ final-output rules of ordinary `defineTool` generators.
171
245
 
172
246
  ## Cancel and clean up: `ctx.abortSignal`
173
247
 
@@ -200,9 +274,8 @@ first.
200
274
  ```ts
201
275
  async execute({ service }, ctx) {
202
276
  "use workflow";
203
-
204
277
  const plan = await planDeploy(service);
205
- const pending = ask(ctx, { prompt: `Deploy ${service}?`, display: "confirmation", options: APPROVE_OR_CANCEL });
278
+ const pending = ctx.ask({ prompt: `Deploy ${service}?`, display: "confirmation", options: APPROVE_OR_CANCEL });
206
279
 
207
280
  let answer = await Promise.race([pending, sleep("4h")]);
208
281
  if (answer === undefined) {
@@ -222,17 +295,16 @@ and returning withdraws the request.
222
295
  ### Wait for an external system to call back
223
296
 
224
297
  ```ts title="agent/tools/render_video.ts"
225
- import { defineTool } from "eve/tools";
298
+ import { defineWorkflowTool } from "eve/tools";
226
299
  import { createWebhook, FatalError } from "workflow";
227
300
  import { z } from "zod";
228
301
  import { submitRender } from "../lib/render";
229
302
 
230
- export default defineTool({
303
+ export default defineWorkflowTool({
231
304
  description: "Render a video. Returns the URL once the render farm finishes.",
232
305
  inputSchema: z.object({ projectId: z.string() }),
233
306
  async execute({ projectId }) {
234
307
  "use workflow";
235
-
236
308
  const done = createWebhook();
237
309
  const jobId = await submitRender(projectId, done.url);
238
310
  const callback = await done;
@@ -250,19 +322,17 @@ system posts to it when it is done. Nothing runs in between.
250
322
  ### Ask now, act when answered
251
323
 
252
324
  ```ts title="agent/tools/refund_order.ts"
253
- import { defineTool } from "eve/tools";
254
- import { ask } from "eve/workflow";
325
+ import { defineWorkflowTool } from "eve/tools";
255
326
  import { z } from "zod";
256
327
  import { issueRefund } from "../lib/refunds";
257
328
 
258
- export default defineTool({
329
+ export default defineWorkflowTool({
259
330
  description: "Request approval to refund an order, then issue the refund once approved.",
260
331
  inputSchema: z.object({ orderId: z.string(), amount: z.number() }),
261
332
  execution: "background",
262
333
  async execute({ orderId, amount }, ctx) {
263
334
  "use workflow";
264
-
265
- const decision = await ask(ctx, {
335
+ const decision = await ctx.ask({
266
336
  prompt: `Refund $${amount} on order ${orderId}?`,
267
337
  display: "confirmation",
268
338
  options: [
@@ -283,11 +353,11 @@ on the channel. When it is answered, the refund runs and the agent is woken with
283
353
  ### Remind me later
284
354
 
285
355
  ```ts title="agent/tools/remind.ts"
286
- import { defineTool } from "eve/tools";
356
+ import { defineWorkflowTool } from "eve/tools";
287
357
  import { sleep } from "workflow";
288
358
  import { z } from "zod";
289
359
 
290
- export default defineTool({
360
+ export default defineWorkflowTool({
291
361
  description: "Remind the user about something after a delay.",
292
362
  inputSchema: z.object({ note: z.string(), delay: z.string() }),
293
363
  execution: "background",
@@ -317,6 +387,12 @@ session's task index, can be cancelled with `task_cancel`, and are cancelled whe
317
387
  Errors follow the SDK. A thrown error in a step retries per the step's policy; `FatalError` does
318
388
  not. An error that escapes the body fails the run.
319
389
 
320
- Identity follows the tool. The workflow id derives from the tool's path, so renaming or moving the
321
- file creates a new workflow. Runs in flight finish on the deployment that started them; a run that
390
+ Starting a waiting workflow tool can also be retried. If dispatch is interrupted after starting a
391
+ run, its retry starts another run, and both may execute. The parent tracks the run returned by the
392
+ successful dispatch attempt. Use an application idempotency key for side effects that must happen
393
+ only once.
394
+
395
+ The workflow id derives from the executor's module path and function name. Inline executors use
396
+ the tool module and the name `execute`; imported executors use their declaring module and name.
397
+ Renaming or moving that function creates a new workflow. Runs in flight finish on the deployment that started them; a run that
322
398
  resumes on a deployment without its tool fails with an error naming the missing workflow.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve",
3
- "version": "0.51.1",
3
+ "version": "0.52.0",
4
4
  "private": false,
5
5
  "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
6
6
  "keywords": [
@@ -181,12 +181,6 @@
181
181
  "import": "./dist/src/public/tools/workflow.js",
182
182
  "default": "./dist/src/public/tools/workflow.js"
183
183
  },
184
- "./workflow": {
185
- "eve-source": "./src/public/workflow/index.ts",
186
- "types": "./dist/src/public/workflow/index.d.ts",
187
- "import": "./dist/src/public/workflow/index.js",
188
- "default": "./dist/src/public/workflow/index.js"
189
- },
190
184
  "./workflow-modules": {
191
185
  "eve-source": "./src/public/workflow-modules.d.ts",
192
186
  "types": "./dist/src/public/workflow-modules.d.ts"
@@ -1,5 +0,0 @@
1
- /** `eve/workflow`: what eve adds inside a workflow tool body. The SDK's own constructs come from `workflow`. */
2
- export { ask } from "#execution/tools/workflow/ask.js";
3
- export { agent } from "#execution/tools/subagent/invoke-agent.js";
4
- export type { AgentInput } from "#execution/tools/subagent/invoke-agent.js";
5
- export type { ToolInputRequest, ToolInputResponse } from "#tools/definition.js";
@@ -1 +0,0 @@
1
- import{ask}from"#execution/tools/workflow/ask.js";import{agent}from"#execution/tools/subagent/invoke-agent.js";export{agent,ask};