eve 0.30.7 → 0.31.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 (240) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +5 -6
  3. package/dist/src/acp/adapter.d.ts +10 -4
  4. package/dist/src/acp/adapter.js +1 -1
  5. package/dist/src/channel/adapter-context.d.ts +1 -1
  6. package/dist/src/channel/adapter.d.ts +2 -4
  7. package/dist/src/channel/adapter.js +1 -1
  8. package/dist/src/channel/channel-address.d.ts +58 -0
  9. package/dist/src/channel/channel-address.js +1 -0
  10. package/dist/src/channel/channel-operations.d.ts +72 -0
  11. package/dist/src/channel/channel-operations.js +1 -0
  12. package/dist/src/channel/compiled-channel.d.ts +10 -6
  13. package/dist/src/channel/cross-channel-receive.d.ts +13 -25
  14. package/dist/src/channel/cross-channel-receive.js +2 -2
  15. package/dist/src/channel/receive-target.d.ts +1 -2
  16. package/dist/src/channel/routes.d.ts +21 -149
  17. package/dist/src/channel/schedule.d.ts +1 -1
  18. package/dist/src/channel/schedule.js +1 -1
  19. package/dist/src/channel/send-input.d.ts +6 -0
  20. package/dist/src/channel/send-input.js +1 -0
  21. package/dist/src/channel/session.d.ts +44 -30
  22. package/dist/src/channel/session.js +1 -1
  23. package/dist/src/channel/types.d.ts +8 -35
  24. package/dist/src/chunks/{use-eve-agent-k-XHfrJT.js → use-eve-agent-CF5D6jSV.js} +361 -367
  25. package/dist/src/chunks/{use-eve-agent-BXMIf5fR.js → use-eve-agent-DbYZLG0h.js} +364 -368
  26. package/dist/src/cli/commands/agent-prompt/build-and-verify.md +1 -2
  27. package/dist/src/cli/commands/channel-add-conflicts.js +1 -1
  28. package/dist/src/cli/commands/info.d.ts +1 -1
  29. package/dist/src/cli/commands/info.js +1 -1
  30. package/dist/src/cli/commands/registry-metadata.d.ts +15 -0
  31. package/dist/src/cli/commands/registry-metadata.js +1 -0
  32. package/dist/src/cli/commands/registry-package.d.ts +46 -0
  33. package/dist/src/cli/commands/registry-package.js +1 -0
  34. package/dist/src/cli/commands/registry.d.ts +1 -1
  35. package/dist/src/cli/commands/registry.js +4 -4
  36. package/dist/src/cli/dev/tui/runner.d.ts +1 -1
  37. package/dist/src/cli/dev/tui/runner.js +1 -1
  38. package/dist/src/cli/dev/tui/subagent-pump.js +1 -1
  39. package/dist/src/cli/dev/tui/terminal-renderer.js +2 -2
  40. package/dist/src/cli/dev/tui/tui.js +1 -1
  41. package/dist/src/cli/invoke/invoke.d.ts +1 -1
  42. package/dist/src/cli/invoke/invoke.js +1 -1
  43. package/dist/src/cli/invoke/result.d.ts +0 -11
  44. package/dist/src/cli/invoke/result.js +1 -1
  45. package/dist/src/client/client-error.d.ts +2 -0
  46. package/dist/src/client/client-error.js +1 -1
  47. package/dist/src/client/client.d.ts +7 -14
  48. package/dist/src/client/client.js +1 -1
  49. package/dist/src/client/eve-agent-store.d.ts +4 -4
  50. package/dist/src/client/eve-agent-store.js +1 -1
  51. package/dist/src/client/index.d.ts +3 -2
  52. package/dist/src/client/index.js +1 -1
  53. package/dist/src/client/message-reducer-types.d.ts +3 -0
  54. package/dist/src/client/message-reducer.js +1 -1
  55. package/dist/src/client/message-response.d.ts +2 -7
  56. package/dist/src/client/message-response.js +1 -1
  57. package/dist/src/client/open-stream.js +1 -1
  58. package/dist/src/client/session-controls.d.ts +29 -0
  59. package/dist/src/client/session-controls.js +1 -0
  60. package/dist/src/client/session-utils.d.ts +0 -20
  61. package/dist/src/client/session-utils.js +1 -1
  62. package/dist/src/client/session.d.ts +26 -90
  63. package/dist/src/client/session.js +1 -1
  64. package/dist/src/client/sessions.d.ts +20 -0
  65. package/dist/src/client/sessions.js +1 -0
  66. package/dist/src/client/types.d.ts +26 -47
  67. package/dist/src/compiler/extension-compatibility.d.ts +10 -10
  68. package/dist/src/compiler/extension-compatibility.js +1 -1
  69. package/dist/src/compiler/normalize-subagent.js +1 -1
  70. package/dist/src/evals/cli/eval-client.js +1 -1
  71. package/dist/src/evals/context.js +1 -1
  72. package/dist/src/evals/session.d.ts +7 -6
  73. package/dist/src/evals/session.js +1 -1
  74. package/dist/src/evals/types.d.ts +9 -9
  75. package/dist/src/execution/agent-handle-dispatch.js +1 -1
  76. package/dist/src/execution/cancel-descendant-turns-step.js +1 -1
  77. package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
  78. package/dist/src/execution/remote-agent-dispatch.d.ts +1 -3
  79. package/dist/src/execution/remote-agent-dispatch.js +1 -1
  80. package/dist/src/execution/runtime-context.js +1 -1
  81. package/dist/src/execution/runtime-errors.d.ts +1 -1
  82. package/dist/src/execution/session-command-token.d.ts +2 -0
  83. package/dist/src/execution/session-command-token.js +1 -1
  84. package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
  85. package/dist/src/execution/subagent-hitl-proxy.js +1 -1
  86. package/dist/src/execution/tool-auth.d.ts +1 -1
  87. package/dist/src/execution/tool-auth.js +1 -1
  88. package/dist/src/execution/turn-control-receiver.d.ts +2 -2
  89. package/dist/src/execution/turn-workflow.js +1 -1
  90. package/dist/src/execution/workflow-entry.js +1 -1
  91. package/dist/src/execution/workflow-runtime.js +1 -1
  92. package/dist/src/harness/cancelled-turn-emission.d.ts +1 -1
  93. package/dist/src/harness/cancelled-turn-emission.js +1 -1
  94. package/dist/src/harness/emission-state.d.ts +25 -0
  95. package/dist/src/harness/emission-state.js +1 -0
  96. package/dist/src/harness/emission.d.ts +5 -37
  97. package/dist/src/harness/emission.js +1 -1
  98. package/dist/src/harness/handles/prompt.d.ts +22 -3
  99. package/dist/src/harness/handles/prompt.js +1 -1
  100. package/dist/src/harness/handles/store.d.ts +0 -5
  101. package/dist/src/harness/handles/store.js +1 -1
  102. package/dist/src/harness/ordered-stream-emitter.d.ts +3 -2
  103. package/dist/src/harness/ordered-stream-emitter.js +1 -1
  104. package/dist/src/harness/runtime-actions.js +1 -1
  105. package/dist/src/harness/session-limit-enforcement.js +1 -1
  106. package/dist/src/harness/tool-loop.js +1 -1
  107. package/dist/src/harness/tools.d.ts +1 -1
  108. package/dist/src/harness/tools.js +1 -1
  109. package/dist/src/internal/application/package.js +1 -1
  110. package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
  111. package/dist/src/internal/nitro/dev-runtime-source-snapshot-copy.js +1 -1
  112. package/dist/src/internal/nitro/dev-runtime-source-snapshot-local-roots.d.ts +15 -0
  113. package/dist/src/internal/nitro/dev-runtime-source-snapshot-local-roots.js +1 -0
  114. package/dist/src/internal/nitro/dev-runtime-source-snapshot.d.ts +14 -2
  115. package/dist/src/internal/nitro/dev-runtime-source-snapshot.js +1 -1
  116. package/dist/src/internal/nitro/host/dev-server-http.js +1 -1
  117. package/dist/src/internal/nitro/routes/channel-dispatch.d.ts +2 -5
  118. package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
  119. package/dist/src/internal/nitro/routes/channel-route-context.d.ts +4 -3
  120. package/dist/src/internal/nitro/routes/channel-route-context.js +1 -1
  121. package/dist/src/packages/eve-catalog/src/index.js +1 -1
  122. package/dist/src/protocol/cancel-turn.d.ts +9 -4
  123. package/dist/src/protocol/cancel-turn.js +1 -1
  124. package/dist/src/protocol/message.d.ts +27 -17
  125. package/dist/src/protocol/message.js +2 -2
  126. package/dist/src/protocol/reset-session.d.ts +1 -1
  127. package/dist/src/protocol/routes.d.ts +27 -47
  128. package/dist/src/protocol/routes.js +1 -1
  129. package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +19 -21
  130. package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
  131. package/dist/src/public/channels/discord/discordChannel.d.ts +5 -4
  132. package/dist/src/public/channels/discord/discordChannel.js +1 -1
  133. package/dist/src/public/channels/eve.d.ts +11 -10
  134. package/dist/src/public/channels/eve.js +1 -1
  135. package/dist/src/public/channels/github/dispatch.d.ts +8 -8
  136. package/dist/src/public/channels/github/dispatch.js +1 -1
  137. package/dist/src/public/channels/github/githubChannel.d.ts +4 -3
  138. package/dist/src/public/channels/github/githubChannel.js +1 -1
  139. package/dist/src/public/channels/github/pr-context.d.ts +1 -1
  140. package/dist/src/public/channels/index.d.ts +1 -1
  141. package/dist/src/public/channels/linear/linearChannel.d.ts +4 -3
  142. package/dist/src/public/channels/linear/linearChannel.js +1 -1
  143. package/dist/src/public/channels/slack/index.d.ts +1 -1
  144. package/dist/src/public/channels/slack/interactions.d.ts +3 -4
  145. package/dist/src/public/channels/slack/interactions.js +1 -1
  146. package/dist/src/public/channels/slack/session-operations.d.ts +37 -0
  147. package/dist/src/public/channels/slack/session-operations.js +1 -0
  148. package/dist/src/public/channels/slack/slackChannel.d.ts +56 -74
  149. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  150. package/dist/src/public/channels/teams/teamsChannel.d.ts +4 -3
  151. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  152. package/dist/src/public/channels/telegram/telegramChannel.d.ts +5 -4
  153. package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
  154. package/dist/src/public/channels/twilio/twilioChannel.d.ts +4 -3
  155. package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
  156. package/dist/src/public/definitions/callback-context.d.ts +1 -2
  157. package/dist/src/public/definitions/channel.d.ts +22 -86
  158. package/dist/src/public/definitions/channel.js +1 -1
  159. package/dist/src/public/definitions/hook.d.ts +1 -0
  160. package/dist/src/public/definitions/remote-agent.js +1 -1
  161. package/dist/src/public/definitions/schedule.d.ts +16 -16
  162. package/dist/src/public/definitions/tool.d.ts +5 -5
  163. package/dist/src/public/schedules/index.d.ts +1 -1
  164. package/dist/src/react/use-eve-agent.d.ts +7 -4
  165. package/dist/src/react/use-eve-agent.js +1 -1
  166. package/dist/src/runtime/agent/bootstrap-model-utils.d.ts +11 -0
  167. package/dist/src/runtime/agent/bootstrap-model-utils.js +1 -1
  168. package/dist/src/runtime/agent/mock-model-adapter.js +1 -1
  169. package/dist/src/runtime/agent/mock-model-fixtures.js +2 -2
  170. package/dist/src/runtime/prompt/compose.js +1 -1
  171. package/dist/src/runtime/subagents/dynamic-remote-agent-config.js +1 -1
  172. package/dist/src/runtime/types.d.ts +2 -2
  173. package/dist/src/services/inspect-application.d.ts +1 -1
  174. package/dist/src/services/inspect-application.js +1 -1
  175. package/dist/src/setup/channel-add-conflicts.js +1 -1
  176. package/dist/src/setup/integrations/linear/setup.js +1 -1
  177. package/dist/src/setup/scaffold/create/project.js +1 -1
  178. package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
  179. package/dist/src/setup/scaffold/create/web-template.js +29 -17
  180. package/dist/src/shared/async-iterable.d.ts +2 -0
  181. package/dist/src/shared/async-iterable.js +1 -0
  182. package/dist/src/shared/channel-definition.d.ts +7 -7
  183. package/dist/src/shared/schedule-definition.d.ts +2 -2
  184. package/dist/src/shared/tool-definition.d.ts +1 -1
  185. package/dist/src/svelte/index.js +1 -1
  186. package/dist/src/svelte/use-eve-agent.d.ts +8 -5
  187. package/dist/src/svelte/use-eve-agent.js +1 -1
  188. package/dist/src/vue/index.js +1 -1
  189. package/dist/src/vue/use-eve-agent.d.ts +8 -5
  190. package/dist/src/vue/use-eve-agent.js +1 -1
  191. package/docs/README.md +6 -6
  192. package/docs/channels/chat-sdk.mdx +5 -6
  193. package/docs/channels/custom.mdx +116 -144
  194. package/docs/channels/discord.mdx +1 -1
  195. package/docs/channels/eve.mdx +76 -30
  196. package/docs/channels/github.mdx +1 -1
  197. package/docs/channels/linear.mdx +10 -10
  198. package/docs/channels/overview.mdx +2 -2
  199. package/docs/channels/slack.mdx +46 -15
  200. package/docs/channels/telegram.mdx +1 -1
  201. package/docs/channels/twilio.mdx +1 -1
  202. package/docs/concepts/default-harness.md +11 -3
  203. package/docs/concepts/execution-model-and-durability.mdx +17 -5
  204. package/docs/concepts/sessions-runs-and-streaming.md +45 -16
  205. package/docs/evals/cases.mdx +3 -3
  206. package/docs/evals/targets.mdx +1 -1
  207. package/docs/guides/auth-and-route-protection.md +2 -1
  208. package/docs/guides/client/continuations.mdx +50 -77
  209. package/docs/guides/client/messages.mdx +29 -33
  210. package/docs/guides/client/output-schema.mdx +7 -14
  211. package/docs/guides/client/overview.mdx +40 -11
  212. package/docs/guides/client/streaming.mdx +18 -23
  213. package/docs/guides/frontend/nuxt.mdx +1 -1
  214. package/docs/guides/frontend/overview.mdx +40 -36
  215. package/docs/guides/frontend/sveltekit.mdx +1 -1
  216. package/docs/guides/frontend/use-eve-agent-svelte.mdx +19 -23
  217. package/docs/guides/frontend/use-eve-agent-vue.mdx +21 -25
  218. package/docs/guides/hooks.md +1 -1
  219. package/docs/guides/instrumentation.md +1 -1
  220. package/docs/install-integrations.mdx +4 -2
  221. package/docs/patterns/dynamic-scheduling.md +16 -15
  222. package/docs/reference/cli.md +4 -1
  223. package/docs/schedules.mdx +10 -11
  224. package/docs/subagents.mdx +1 -1
  225. package/docs/tools/human-in-the-loop.md +1 -1
  226. package/docs/tools/overview.mdx +26 -2
  227. package/docs/tutorial/ship-it.mdx +1 -1
  228. package/package.json +1 -1
  229. package/dist/src/channel/cancel.d.ts +0 -6
  230. package/dist/src/channel/cancel.js +0 -1
  231. package/dist/src/channel/clear-session.d.ts +0 -4
  232. package/dist/src/channel/clear-session.js +0 -1
  233. package/dist/src/channel/compact-session.d.ts +0 -4
  234. package/dist/src/channel/compact-session.js +0 -1
  235. package/dist/src/channel/reset-session.d.ts +0 -6
  236. package/dist/src/channel/reset-session.js +0 -1
  237. package/dist/src/channel/resolve-active-session.d.ts +0 -4
  238. package/dist/src/channel/resolve-active-session.js +0 -1
  239. package/dist/src/channel/send.d.ts +0 -6
  240. package/dist/src/channel/send.js +0 -1
@@ -36,7 +36,7 @@ export function Chat() {
36
36
  const form = new FormData(event.currentTarget);
37
37
  const message = String(form.get("message") ?? "").trim();
38
38
  if (message.length > 0) {
39
- void agent.send({ message });
39
+ void agent.send(message);
40
40
  }
41
41
  }}
42
42
  >
@@ -61,16 +61,17 @@ export function Chat() {
61
61
 
62
62
  `useEveAgent()` returns the current UI state plus commands:
63
63
 
64
- | Field | What it is |
65
- | --------- | ------------------------------------------------------------------------------ |
66
- | `data` | Projected UI state from the reducer. Defaults to `{ messages }`. |
67
- | `status` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"`. Drives the composer. |
68
- | `error` | The last `Error` thrown, if any. |
69
- | `events` | Raw eve stream events for this session. |
70
- | `session` | Serializable session cursor (`sessionId`, `continuationToken`, `streamIndex`). |
71
- | `send` | Send text or the full turn payload (multi-part messages, HITL responses). |
72
- | `stop` | Abort the client's in-flight stream. The server-side turn keeps running. |
73
- | `reset` | Clear local events, data, errors, and the local session cursor. |
64
+ | Field | What it is |
65
+ | --------- | --------------------------------------------------------------------------- |
66
+ | `data` | Projected UI state from the reducer. Defaults to `{ messages }`. |
67
+ | `status` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"`. Drives the composer. |
68
+ | `error` | The last `Error` thrown, if any. |
69
+ | `events` | Raw eve stream events for this session. |
70
+ | `session` | Serializable fixed session cursor (`sessionId`, `streamIndex`). |
71
+ | `send` | Send text or a multi-part message, with per-turn options. |
72
+ | `respond` | Answer pending HITL input requests, with per-turn options. |
73
+ | `stop` | Abort the client's in-flight stream. The server-side turn keeps running. |
74
+ | `reset` | Clear local events, data, errors, and the local session cursor. |
74
75
 
75
76
  Most chat UIs only need `data.messages` and `status`. Drop down to `events` when you need the authoritative wire events directly, for example to persist an audit log or build a custom projection.
76
77
 
@@ -78,29 +79,31 @@ Most chat UIs only need `data.messages` and `status`. Drop down to `events` when
78
79
 
79
80
  ## Sending and streaming
80
81
 
81
- Pass an object to `send()` for text, multi-part messages, attachments, HITL responses, and per-turn context:
82
+ Pass the message first and optional per-turn settings second. Use `respond()` for HITL answers:
82
83
 
83
84
  ```tsx
84
- await agent.send({ message: "Summarize this session." });
85
-
86
- await agent.send({
87
- message: [
88
- { type: "text", text: "What is in this file?" },
89
- {
90
- type: "file",
91
- data: fileDataUrl, // base64 data URL
92
- mediaType: "application/pdf",
93
- filename: "report.pdf",
94
- },
95
- ],
96
- });
85
+ await agent.send("Summarize this session.");
86
+
87
+ await agent.send([
88
+ { type: "text", text: "What is in this file?" },
89
+ {
90
+ type: "file",
91
+ data: fileDataUrl, // base64 data URL
92
+ mediaType: "application/pdf",
93
+ filename: "report.pdf",
94
+ },
95
+ ]);
97
96
  ```
98
97
 
99
98
  Assistant text, reasoning, tool calls, and tool results stream into `data` as they arrive, and `status` moves from `ready` to `submitted` to `streaming` and back. Call `stop()` to abort the client's in-flight stream, and `reset()` to clear local state so the next send starts a fresh durable session.
100
99
 
101
100
  `stop()` is local: turns are resumable across disconnects, so detaching the stream never cancels the work — the turn keeps running and billing on the server. To stop the turn itself, POST the session's [cancel route](../../channels/eve#routes); the turn then settles on the stream as `turn.cancelled` followed by `session.waiting`.
102
101
 
103
- A chat UI with a Stop button should own the `ClientSession` passed to `useEveAgent`, create it with `preserveCompletedSessions: true`, and call `session.cancel({ turnId })` after observing that turn's `turn.started` event. The `turnId` guard makes a late click a harmless no-op instead of cancelling a newer turn. Keep the stream open until the cancellation boundary arrives; do not use `stop()` for this interaction.
102
+ A chat UI with a server-side Cancel button can use the `sessionId` exposed by the
103
+ hook, attach a fixed `ClientSession`, and call `session.cancel({ turnId })` after
104
+ observing that turn's `turn.started` event. The `turnId` guard makes a late click
105
+ a harmless no-op instead of cancelling a newer turn. Keep the stream open until
106
+ the cancellation boundary arrives; do not use `stop()` for this interaction.
104
107
 
105
108
  After eve confirms an attachment turn with `message.received`, the default reducer projects each
106
109
  received attachment as a `file` part on the user message. The part includes `mediaType`, optional
@@ -108,7 +111,7 @@ received attachment as a `file` part on the user message. The part includes `med
108
111
 
109
112
  ## Human-in-the-loop prompts
110
113
 
111
- Tools opt into approval with `approval`, and the model can also ask a question with `ask_question` — see [Human-in-the-loop](/docs/human-in-the-loop) for the server-side model. Either way the stream emits an `input.requested` event, and the pending request rides on a `dynamic-tool` part of the latest message at `part.toolMetadata?.eve?.inputRequest`. Read it, then answer through the same session with `send()`:
114
+ Tools opt into approval with `approval`, and the model can also ask a question with `ask_question` — see [Human-in-the-loop](/docs/human-in-the-loop) for the server-side model. Either way the stream emits an `input.requested` event, and the pending request rides on a `dynamic-tool` part of the latest message at `part.toolMetadata?.eve?.inputRequest`. Read it, then answer through the same session with `respond()`:
112
115
 
113
116
  ```tsx
114
117
  const request = agent.data.messages
@@ -117,9 +120,7 @@ const request = agent.data.messages
117
120
  ?.toolMetadata?.eve?.inputRequest;
118
121
 
119
122
  if (request) {
120
- await agent.send({
121
- inputResponses: [{ requestId: request.requestId, optionId: "approve" }],
122
- });
123
+ await agent.respond([{ requestId: request.requestId, optionId: "approve" }]);
123
124
  }
124
125
  ```
125
126
 
@@ -159,11 +160,10 @@ For fully custom state machines, `authorization.required` and `authorization.com
159
160
 
160
161
  ## Attach page context per turn
161
162
 
162
- `clientContext` adds ephemeral context for the next model call only. Strings (or an array of strings) become user-role context messages; an object is JSON-serialized into one. It rides along with a message or HITL response, so it never dispatches a turn on its own and never lands in durable session history. Pass it directly to `send()`:
163
+ `clientContext` adds ephemeral context for the next model call only. Strings (or an array of strings) become user-role context messages; an object is JSON-serialized into one. It rides along with a message or HITL response, so it never dispatches a turn on its own and never lands in durable session history. Pass it in the second argument to `send()` or `respond()`:
163
164
 
164
165
  ```tsx
165
- await agent.send({
166
- message: "What should I do on this screen?",
166
+ await agent.send("What should I do on this screen?", {
167
167
  clientContext: { route: "/billing", plan: "pro", seatsUsed: 4 },
168
168
  });
169
169
  ```
@@ -226,11 +226,11 @@ const agent = useEveAgent({ reducer: toolCounter });
226
226
  The browser conversation lives durably on the server. Persist both the rendered event log and the `session` cursor to pick it back up after a reload:
227
227
 
228
228
  ```tsx
229
- import type { SessionState, MessageStreamEvent } from "eve/client";
229
+ import type { ClientSessionState, MessageStreamEvent } from "eve/client";
230
230
 
231
231
  type SavedEveChat = {
232
232
  events?: readonly MessageStreamEvent[];
233
- session?: SessionState;
233
+ session?: ClientSessionState;
234
234
  };
235
235
 
236
236
  const [saved] = useState<SavedEveChat>(() => {
@@ -253,7 +253,11 @@ const agent = useEveAgent({
253
253
  });
254
254
  ```
255
255
 
256
- Store the full `session` object (`sessionId`, `continuationToken`, `streamIndex`), not a single field. The session cursor lets eve continue the durable conversation; the event log lets your UI render historical messages without replaying the whole stream. A database-backed chat app should usually persist stream events as they arrive with `onEvent` and then save a final snapshot in `onFinish`.
256
+ Store the full `session` object (`sessionId`, `streamIndex`). The session cursor
257
+ lets eve continue the exact durable conversation; the event log lets your UI
258
+ render historical messages without replaying the whole stream. A database-backed
259
+ chat app should usually persist stream events as they arrive with `onEvent` and
260
+ then save a final snapshot in `onFinish`.
257
261
 
258
262
  `initialEvents` must be an ordered prefix of the same session's stream, but its endpoint does not have to line up exactly with where the stream resumes. Every event carries a stable [`meta.id`](/docs/concepts/sessions-runs-and-streaming#the-event-envelope), and the store drops any event whose id it has already applied — so a saved log that overlaps the replayed prefix renders once, and `onEvent` only fires for events your UI has not seen.
259
263
 
@@ -56,7 +56,7 @@ With the plugin in `vite.config.ts`, components call [`useEveAgent`](./use-eve-a
56
56
  const text = message.trim();
57
57
  if (!text || isBusy) return;
58
58
  message = "";
59
- await agent.send({ message: text });
59
+ await agent.send(text);
60
60
  }
61
61
  </script>
62
62
 
@@ -23,16 +23,17 @@ Import from `eve/svelte` and read the reactive getters directly. No `$` prefix:
23
23
 
24
24
  ## What it returns
25
25
 
26
- | Property | Type | Description |
27
- | --------- | ------------------------------------------- | ------------------------------------------------------------------------- |
28
- | `data` | `TData` | Projected state. With the default reducer, `EveMessageData` (`messages`). |
29
- | `status` | `UseEveAgentStatus` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"`. |
30
- | `error` | `Error \| undefined` | Last transport-level error. |
31
- | `events` | `readonly MessageStreamEvent[]` | Raw server events for this session. |
32
- | `session` | `SessionState` | Snapshot of session state. |
33
- | `send` | `(input: SendTurnPayload) => Promise<void>` | Send text or a full turn (multi-part, attachments, HITL responses). |
34
- | `stop` | `() => void` | Abort the client's in-flight stream. |
35
- | `reset` | `() => void` | Clear state and start a new session. |
26
+ | Property | Type | Description |
27
+ | --------- | --------------------------------------------- | ------------------------------------------------------------------------- |
28
+ | `data` | `TData` | Projected state. With the default reducer, `EveMessageData` (`messages`). |
29
+ | `status` | `UseEveAgentStatus` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"`. |
30
+ | `error` | `Error \| undefined` | Last transport-level error. |
31
+ | `events` | `readonly MessageStreamEvent[]` | Raw server events for this session. |
32
+ | `session` | `ClientSessionState \| undefined` | Fixed session ID and stream cursor. |
33
+ | `send` | `(message, options?) => Promise<void>` | Send text or a multi-part message. |
34
+ | `respond` | `(inputResponses, options?) => Promise<void>` | Answer pending HITL input requests. |
35
+ | `stop` | `() => void` | Abort the client's in-flight stream. |
36
+ | `reset` | `() => void` | Clear state and start a new session. |
36
37
 
37
38
  These state fields are reactive getters, so read them straight from templates, `$derived`, or `$effect`. They are not stores, so don't prefix them with `$`.
38
39
 
@@ -49,7 +50,7 @@ These state fields are reactive getters, so read them straight from templates, `
49
50
  const text = message.trim();
50
51
  if (!text) return;
51
52
  message = "";
52
- await agent.send({ message: text });
53
+ await agent.send(text);
53
54
  }
54
55
  </script>
55
56
 
@@ -68,17 +69,15 @@ When a turn is more than plain text, reach for `send()`. Attachments follow the
68
69
  const bytes = new Uint8Array(await file.arrayBuffer());
69
70
  const base64 = btoa(String.fromCodePoint(...bytes));
70
71
 
71
- await agent.send({
72
- message: [
73
- { type: "text", text: "Describe this image." },
74
- { type: "file", data: `data:${file.type};base64,${base64}`, mediaType: file.type },
75
- ],
76
- });
72
+ await agent.send([
73
+ { type: "text", text: "Describe this image." },
74
+ { type: "file", data: `data:${file.type};base64,${base64}`, mediaType: file.type },
75
+ ]);
77
76
  ```
78
77
 
79
78
  ## Human-in-the-loop prompts
80
79
 
81
- A tool opts into approval with `approval` ([Tools](../../tools)). When one fires, the pending request rides along on a `dynamic-tool` part of the latest message at `part.toolMetadata?.eve?.inputRequest`. Read it, then answer through the same session with `agent.send({ inputResponses })`:
80
+ A tool opts into approval with `approval` ([Tools](../../tools)). When one fires, the pending request rides along on a `dynamic-tool` part of the latest message at `part.toolMetadata?.eve?.inputRequest`. Read it, then answer through the same session with `agent.respond(inputResponses)`:
82
81
 
83
82
  ```ts
84
83
  import type { EveDynamicToolPart, EveMessagePart } from "eve/svelte";
@@ -93,9 +92,7 @@ const request = agent.data.messages
93
92
  .find((value) => value !== undefined);
94
93
 
95
94
  if (request) {
96
- await agent.send({
97
- inputResponses: [{ requestId: request.requestId, optionId: "approve" }],
98
- });
95
+ await agent.respond([{ requestId: request.requestId, optionId: "approve" }]);
99
96
  }
100
97
  ```
101
98
 
@@ -133,8 +130,7 @@ const agent = useEveAgent({
133
130
  `clientContext` adds ephemeral context for the next model call and nothing more. Strings (or an array of strings) become user-role context messages; an object is JSON-serialized into one. It rides along with a message or HITL response, never dispatches a turn on its own, and never lands in durable session history. Pass it to `send()`:
134
131
 
135
132
  ```ts
136
- await agent.send({
137
- message: "What should I do on this screen?",
133
+ await agent.send("What should I do on this screen?", {
138
134
  clientContext: { route: "/billing", plan: "pro", seatsUsed: 4 },
139
135
  });
140
136
  ```
@@ -25,16 +25,17 @@ const { data } = useEveAgent();
25
25
 
26
26
  ## What it returns
27
27
 
28
- | Property | Type | Description |
29
- | --------- | -------------------------------------------- | ------------------------------------------------------------------------- |
30
- | `data` | `ComputedRef<TData>` | Projected state. With the default reducer, `EveMessageData` (`messages`). |
31
- | `status` | `ComputedRef<UseEveAgentStatus>` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"`. |
32
- | `error` | `ComputedRef<Error \| undefined>` | Last transport-level error. |
33
- | `events` | `ComputedRef<readonly MessageStreamEvent[]>` | Raw server events for this session. |
34
- | `session` | `ComputedRef<SessionState>` | Snapshot of session state. |
35
- | `send` | `(input: SendTurnPayload) => Promise<void>` | Send text or a full turn (multi-part, attachments, HITL responses). |
36
- | `stop` | `() => void` | Abort the client's in-flight stream. |
37
- | `reset` | `() => void` | Clear state and start a new session. |
28
+ | Property | Type | Description |
29
+ | --------- | ---------------------------------------------- | ------------------------------------------------------------------------- |
30
+ | `data` | `ComputedRef<TData>` | Projected state. With the default reducer, `EveMessageData` (`messages`). |
31
+ | `status` | `ComputedRef<UseEveAgentStatus>` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"`. |
32
+ | `error` | `ComputedRef<Error \| undefined>` | Last transport-level error. |
33
+ | `events` | `ComputedRef<readonly MessageStreamEvent[]>` | Raw server events for this session. |
34
+ | `session` | `ComputedRef<ClientSessionState \| undefined>` | Fixed session ID and stream cursor. |
35
+ | `send` | `(message, options?) => Promise<void>` | Send text or a multi-part message. |
36
+ | `respond` | `(inputResponses, options?) => Promise<void>` | Answer pending HITL input requests. |
37
+ | `stop` | `() => void` | Abort the client's in-flight stream. |
38
+ | `reset` | `() => void` | Clear state and start a new session. |
38
39
 
39
40
  The first five are `ComputedRef`s; the rest are methods. Destructure whatever you need, since refs keep their reactivity through destructuring. Read them with `.value` in `<script>`, and unwrapped in `<template>`.
40
41
 
@@ -52,7 +53,7 @@ async function handleSubmit() {
52
53
  const text = message.value.trim();
53
54
  if (!text) return;
54
55
  message.value = "";
55
- await send({ message: text });
56
+ await send(text);
56
57
  }
57
58
  </script>
58
59
 
@@ -77,24 +78,22 @@ async function onFileChange(event: Event) {
77
78
  if (!file) return;
78
79
  const bytes = new Uint8Array(await file.arrayBuffer());
79
80
  const base64 = btoa(String.fromCodePoint(...bytes));
80
- await send({
81
- message: [
82
- { type: "text", text: "Describe this image." },
83
- { type: "file", data: `data:${file.type};base64,${base64}`, mediaType: file.type },
84
- ],
85
- });
81
+ await send([
82
+ { type: "text", text: "Describe this image." },
83
+ { type: "file", data: `data:${file.type};base64,${base64}`, mediaType: file.type },
84
+ ]);
86
85
  }
87
86
  </script>
88
87
  ```
89
88
 
90
89
  ## Human-in-the-loop prompts
91
90
 
92
- A tool opts into approval with `approval` ([Tools](../../tools)). When it triggers, the pending request shows up as a `dynamic-tool` part on the latest message at `part.toolMetadata?.eve?.inputRequest`. Read it, then answer through the same session with `send({ inputResponses })`:
91
+ A tool opts into approval with `approval` ([Tools](../../tools)). When it triggers, the pending request shows up as a `dynamic-tool` part on the latest message at `part.toolMetadata?.eve?.inputRequest`. Read it, then answer through the same session with `respond(inputResponses)`:
93
92
 
94
93
  ```ts
95
94
  import type { EveDynamicToolPart, EveMessagePart } from "eve/vue";
96
95
 
97
- const { data, send } = useEveAgent();
96
+ const { data, respond } = useEveAgent();
98
97
 
99
98
  const isDynamicToolPart = (part: EveMessagePart): part is EveDynamicToolPart =>
100
99
  part.type === "dynamic-tool";
@@ -106,9 +105,7 @@ const request = data.value.messages
106
105
  .find((value) => value !== undefined);
107
106
 
108
107
  if (request) {
109
- await send({
110
- inputResponses: [{ requestId: request.requestId, optionId: "approve" }],
111
- });
108
+ await respond([{ requestId: request.requestId, optionId: "approve" }]);
112
109
  }
113
110
  ```
114
111
 
@@ -143,11 +140,10 @@ const agent = useEveAgent({
143
140
 
144
141
  ## Attach page context per turn
145
142
 
146
- `clientContext` adds ephemeral context for the next model call and nothing more. Strings (or an array of strings) become user-role context messages; an object is JSON-serialized into one. It rides along with a message or HITL response, never dispatches a turn on its own, and never lands in durable session history. Pass it to `send()`:
143
+ `clientContext` adds ephemeral context for the next model call and nothing more. Strings (or an array of strings) become user-role context messages; an object is JSON-serialized into one. It rides along with a message or HITL response, never dispatches a turn on its own, and never lands in durable session history. Pass it in the second argument to `send()` or `respond()`:
147
144
 
148
145
  ```ts
149
- await send({
150
- message: "What should I do on this screen?",
146
+ await send("What should I do on this screen?", {
151
147
  clientContext: { route: "/billing", plan: "pro", seatsUsed: 4 },
152
148
  });
153
149
  ```
@@ -26,7 +26,7 @@ The slug is the path-relative basename. `agent/hooks/audit.ts` becomes `"audit"`
26
26
 
27
27
  `defineHook`, `HookDefinition`, and `HookContext` live on `eve/hooks`.
28
28
 
29
- A hook file declares stream-event subscribers under the `events` map, keyed by event type, with `*` matching every event. Subscribe to any event in the runtime stream vocabulary documented in [Sessions, runs and streaming](../concepts/sessions-runs-and-streaming), including the lifecycle events `session.started`, `turn.completed`, `message.completed`, and `action.result`. Handlers are observe-only. They cannot inject model context. To contribute runtime model messages, use `defineDynamic` and `defineInstructions` in `agent/instructions/`.
29
+ A hook file declares stream-event subscribers under the `events` map, keyed by event type, with `*` matching every event. Subscribe to any event in the runtime stream vocabulary documented in [Sessions, runs and streaming](../concepts/sessions-runs-and-streaming), including the lifecycle events `session.started`, `turn.completed`, `message.completed`, `action.partial`, and `action.result`. Handlers are observe-only. They cannot inject model context. To contribute runtime model messages, use `defineDynamic` and `defineInstructions` in `agent/instructions/`.
30
30
 
31
31
  ## Hook structure and context
32
32
 
@@ -181,7 +181,7 @@ When `eve build` fails on discovery errors, the CLI prints the full diagnostics
181
181
  | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
182
182
  | Tool not discovered (the model never sees it) | Run `eve info`. Confirm the file is in the right slot (`agent/tools/<name>.ts`) and default-exports `defineTool(...)`, and check `.eve/diagnostics.json` for shape errors. `schedules/` are root-only. |
183
183
  | Model won't call a tool it should | Tighten the tool `description` and `inputSchema`; put procedural guidance in a [skill](../skills), not the description. Confirm it's in the active set with `eve info`. |
184
- | Stuck on `session.waiting` | The turn is parked on an approval, a question, or a connection sign-in. Answer it, or POST a follow-up with the `continuationToken` (a stale token is rejected). |
184
+ | Stuck on `session.waiting` | The turn is parked for input. Answer the pending approval or question, or POST a follow-up to `/eve/v1/session/:sessionId`. |
185
185
  | 401 on production routes | Expected: auth fails closed. Replace `placeholderAuth()` with your route policy. Use `vercelOidc()` only for Vercel-issued tokens; otherwise configure `httpBasic()`, JWT/OIDC helpers, or a custom `AuthFn`. See [Auth and route protection](./auth-and-route-protection). |
186
186
  | Build fails with discovery errors | Read the printed diagnostics and `.eve/diagnostics.json`; confirm the root-vs-subagent boundary is valid and secrets come from env vars. |
187
187
 
@@ -12,13 +12,15 @@ Run `eve add` from an eve agent project. This installs the integration's depende
12
12
 
13
13
  ```bash
14
14
  eve add extension/agent-browser
15
- eve add connection/linear
15
+ eve add linear
16
16
  eve add instrumentation/braintrust
17
17
  ```
18
18
 
19
19
  Extensions may create a mount under `agent/extensions/`. Connections write their initial definition under `agent/connections/` and install `@vercel/connect` when required. Instrumentation providers write `agent/instrumentation.ts`; because an agent has one instrumentation file, compose multiple exporters there by hand. Configure generated files and required environment variables before running your agent.
20
20
 
21
- When an official item has an interactive setup flow, eve asks whether to run it after installation. Run the printed `eve add <item> --skip-install` command to resume a skipped or cancelled setup later.
21
+ Some integrations package several independently installable components. For example, `eve add linear` lets you choose the Linear Channel, Linear MCP, or both; both are selected by default. The specific `eve add channel/linear-agent` and `eve add connection/linear` commands remain available.
22
+
23
+ When an official item declares an interactive setup flow or flows, eve asks whether to run them after installation and runs multiple flows in declaration order. Run the printed `eve add <item> --skip-install` command to resume a skipped or cancelled setup later; it reruns the selected components' declared flows from the beginning.
22
24
 
23
25
  ## Find an integration
24
26
 
@@ -35,7 +35,7 @@ import { scheduleStore } from "../lib/schedule-store";
35
35
 
36
36
  export default defineSchedule({
37
37
  cron: "* * * * *",
38
- run({ receive, waitUntil }) {
38
+ run({ to, waitUntil }) {
39
39
  waitUntil(
40
40
  (async () => {
41
41
  const jobs = await scheduleStore.claimDue({
@@ -47,25 +47,26 @@ export default defineSchedule({
47
47
  await Promise.all(
48
48
  jobs.map(async (job) => {
49
49
  try {
50
- await receive(slack, {
51
- message: [
50
+ await to(slack, { channelId: job.channelId }).send(
51
+ [
52
52
  `Run dynamic schedule ${job.id}.`,
53
53
  "Complete this tenant-owned task:",
54
54
  job.prompt,
55
55
  ].join("\n\n"),
56
- target: { channelId: job.channelId },
57
- auth: {
58
- attributes: {
59
- tenantId: job.tenantId,
60
- role: job.ownerRole,
61
- scheduleId: job.id,
56
+ {
57
+ auth: {
58
+ attributes: {
59
+ tenantId: job.tenantId,
60
+ role: job.ownerRole,
61
+ scheduleId: job.id,
62
+ },
63
+ authenticator: job.authenticator,
64
+ ...(job.issuer ? { issuer: job.issuer } : {}),
65
+ principalId: job.ownerId,
66
+ principalType: "user",
62
67
  },
63
- authenticator: job.authenticator,
64
- ...(job.issuer ? { issuer: job.issuer } : {}),
65
- principalId: job.ownerId,
66
- principalType: "user",
67
68
  },
68
- });
69
+ );
69
70
  await scheduleStore.complete(job);
70
71
  } catch (error) {
71
72
  await scheduleStore.release(job, { error, retryAt: new Date(Date.now() + 300_000) });
@@ -78,7 +79,7 @@ export default defineSchedule({
78
79
  });
79
80
  ```
80
81
 
81
- `waitUntil` keeps the cron invocation alive until claiming and handoff settle. `receive` starts the same durable runtime used by inbound channel messages.
82
+ `waitUntil` keeps the cron invocation alive until claiming and handoff settle. `to(...).send(...)` starts the same durable runtime used by inbound channel messages.
82
83
 
83
84
  This example uses Slack because it has a proactive target of `{ channelId }`. Any channel that implements `receive` can replace it.
84
85
 
@@ -87,6 +87,7 @@ Commands for installing and discovering [shadcn registry](https://ui.shadcn.com/
87
87
 
88
88
  ```bash
89
89
  eve add extension/agent-browser
90
+ eve add linear
90
91
  eve add channel/slack --skip-install
91
92
  eve add https://example.com/r/my-extension.json --overwrite
92
93
  eve registry add @acme=https://example.com/r/{name}.json
@@ -97,7 +98,9 @@ eve registry view @acme/my-extension
97
98
  eve add @acme/my-extension
98
99
  ```
99
100
 
100
- `eve add` asks before running setup declared by an official item and prints the matching `eve add <item> --skip-install` command when setup is skipped or cancelled. `--skip-install` reruns setup without reinstalling the item.
101
+ `eve add` asks before running setup declared by an official item and runs multiple declared flows in declaration order. Product-level packages can offer independently installable components: `eve add linear` lets you select the Linear Channel, Linear MCP, or both, with both selected by default. `--yes` installs a package's default components.
102
+
103
+ When setup is skipped or cancelled, eve prints the matching `eve add <item> --skip-install` command. `--skip-install` reruns the selected components' declared flows from the beginning without reinstalling them.
101
104
 
102
105
  `eve registry add` records configured sources in `package.json#registries`. `eve registry list` aggregates the official catalog and all configured sources by default. `eve registry search` also includes [skills.sh](https://skills.sh), available without configuration at `@skills`, and groups results by source with each source's available result count. Search returns up to 10 matches per source by default; pass `--limit <count>` to request between 1 and 100. Either command can browse one supplied URL or namespace. Official and other universal items with explicit file targets do not require shadcn project configuration.
103
106
 
@@ -19,7 +19,7 @@ interface ScheduleDefinition {
19
19
  }
20
20
 
21
21
  interface ScheduleHandlerArgs {
22
- receive: CrossChannelReceiveFn; // hand the work off to a channel
22
+ to: ScheduleToFn; // select a channel target, then send
23
23
  waitUntil: (task: Promise<unknown>) => void; // keep the cron task alive past return
24
24
  appAuth: SessionAuthContext; // pre-built app principal
25
25
  }
@@ -56,7 +56,7 @@ Sweep stale workflow state.
56
56
 
57
57
  ## Handler form (`run`)
58
58
 
59
- Use a handler when the schedule needs to deliver to a channel, branch on conditions, or compute its arguments at fire time. The handler is in full control. It has no channel of its own, so it passes the work to one with `receive`.
59
+ Use a handler when the schedule needs to deliver to a channel, branch on conditions, or compute its arguments at fire time. The handler is in full control. It has no channel of its own, so it selects a channel target with `to(...)` and sends through the returned handle.
60
60
 
61
61
  ```ts title="agent/schedules/critical-alerts.ts"
62
62
  import { defineSchedule } from "eve/schedules";
@@ -65,13 +65,12 @@ import slack from "../channels/slack";
65
65
 
66
66
  export default defineSchedule({
67
67
  cron: "* * * * *",
68
- async run({ receive, waitUntil, appAuth }) {
68
+ async run({ to, waitUntil, appAuth }) {
69
69
  waitUntil(
70
- receive(slack, {
71
- message: "Check for new critical alerts. Report only when there are any.",
72
- target: { channelId: "C0123ABC" },
73
- auth: appAuth,
74
- }),
70
+ to(slack, { channelId: "C0123ABC" }).send(
71
+ "Check for new critical alerts. Report only when there are any.",
72
+ { auth: appAuth },
73
+ ),
75
74
  );
76
75
  },
77
76
  });
@@ -79,9 +78,9 @@ export default defineSchedule({
79
78
 
80
79
  The agent does not have to deliver a message on every run. When a prompt makes delivery conditional, as in the alert check above, eve tells the agent how to finish successfully without sending anything to the channel. Frequent polling schedules do not need a separate filter or delivery setting.
81
80
 
82
- - `receive(channel, { message, target, auth })`: starts a session on another channel. Same contract as a route handler's `args.receive`.
83
- - `waitUntil(promise)`: extends the cron task's lifetime so the parked session and any in-flight fetches settle before the task ends. Wrap the `receive` call in it.
84
- - `appAuth`: the app principal (`{ authenticator: "app", principalId: "eve:app", principalType: "runtime" }`). Pass it as `receive(..., { auth: appAuth })` for work the agent does on its own behalf.
81
+ - `to(channel, target).send(message, { auth })`: starts a session on another channel. It has the same contract as a route handler's `ctx.to(...)` handle.
82
+ - `waitUntil(promise)`: extends the cron task's lifetime so the parked session and any in-flight fetches settle before the task ends. Wrap the `send` call in it.
83
+ - `appAuth`: the app principal (`{ authenticator: "app", principalId: "eve:app", principalType: "runtime" }`). Pass it as `to(...).send(..., { auth: appAuth })` for work the agent does on its own behalf.
85
84
 
86
85
  A handler-form session runs on the same durable runtime engine as any other session, so it can park (durably suspend), for instance when the channel handoff is waiting for a Slack reply. Only markdown task mode is barred from waiting.
87
86
 
@@ -192,7 +192,7 @@ Without the opt-in, delegated children run as one-shot tasks: they answer once a
192
192
 
193
193
  With it enabled, a child parks after answering instead of terminating, keeping its session and conversation history alive. A failed child turn can also leave the child parked — its latest status shows the error and the parent may message it again. Pass a parked child's `agentId` to the same subagent tool with a new `message` to continue that session. Omitting `agentId` (or passing an empty string or `null`) always starts a new child, and an `agentId` that matches no known agent falls back to starting a new child rather than failing. Passing a known `agentId` through a different subagent tool fails with `AGENT_MISMATCH`, and messaging a child that is still starting or working on its previous request fails with `AGENT_BUSY` — wait for its result before continuing it.
194
194
 
195
- On every model call, eve injects a system message containing an `<agents>` block listing the currently parked (resumable) children — each entry carries the `agentId`, name, and latest status. It is a per-call injection, not part of the conversation history: it always reflects the current state, never accumulates stale copies, and children that are starting or running do not appear until they park again.
195
+ Whenever the set of parked (resumable) children changes, eve appends a framework-injected note to the conversation — labeled `[Agents]` and carrying an `<agents>` block — listing each child's `agentId`, name, and latest status. The static system prompt tells the model the note is injected by eve, not written by the user. The note is appended only when the listing changes (an append-only design that preserves the provider prompt cache), the most recent note is authoritative, and children that are starting or running do not appear until they park again.
196
196
 
197
197
  The parent holds agent handles only for its session lifetime. When the parent session ends, eve terminates its local children. Remote children are not terminated on parent shutdown — that is a known gap: a parked remote child stays alive on its own deployment until that deployment's own lifecycle ends it. For [remote agents](./guides/remote-agents), both deployments must run the same eve version to use agent messaging.
198
198
 
@@ -58,7 +58,7 @@ Gating a side effect on approval is also how you make non-idempotent work safe a
58
58
 
59
59
  ### Skipping approval for schedule-dispatched turns
60
60
 
61
- `session.auth.current` identifies the caller of this turn. Markdown schedules use the app principal (`authenticator: "app"`, `principalId: "eve:app"`, `principalType: "runtime"`) automatically. A `run` schedule must pass its `appAuth` to `receive(...)` for the child session to use that principal. Match all three fields to skip approval for automated turns while still prompting when a person calls the same tool:
61
+ `session.auth.current` identifies the caller of this turn. Markdown schedules use the app principal (`authenticator: "app"`, `principalId: "eve:app"`, `principalType: "runtime"`) automatically. A `run` schedule must pass its `appAuth` to `send(...)` for the child session to use that principal. Match all three fields to skip approval for automated turns while still prompting when a person calls the same tool:
62
62
 
63
63
  ```ts title="agent/tools/refund_charge.ts"
64
64
  import { defineTool } from "eve/tools";
@@ -28,10 +28,34 @@ A tool definition needs:
28
28
  - a filename slug under `agent/tools/`, the model-facing name.
29
29
  - a `description`: what the tool does, written for the model.
30
30
  - an `inputSchema`: a Zod schema (or any Standard Schema, or a plain JSON Schema object). Required. For no input, pass `z.object({})`. Zod and Standard Schema infer the `input` type in `execute`. Plain JSON Schema types it as `Record<string, unknown>`.
31
- - an `execute(input, ctx)`: the implementation. May be sync or async.
31
+ - an `execute(input, ctx)`: the implementation. May be sync, async, or an async generator.
32
32
 
33
33
  When a tool returns structured data, add an optional `outputSchema`. With Zod or Standard Schema it also types the `execute` return.
34
34
 
35
+ ### Stream preliminary tool results
36
+
37
+ An async generator lets a long-running tool stream complete output snapshots
38
+ before it finishes. Each `yield` replaces the previous snapshot; the final
39
+ yield is the normal tool result the model receives:
40
+
41
+ ```ts title="agent/tools/build_report.ts"
42
+ export default defineTool({
43
+ description: "Build a project report.",
44
+ inputSchema: z.object({ project: z.string() }),
45
+ async *execute({ project }) {
46
+ yield { phase: "collecting", report: null };
47
+ const report = await buildReport(project);
48
+ yield { phase: "complete", report };
49
+ },
50
+ });
51
+ ```
52
+
53
+ eve publishes every earlier yield as an `action.partial` stream event. The
54
+ snapshot is visible to channels, hooks, and clients but never enters model
55
+ history or `toModelOutput`; only the final yield does. Treat snapshots as
56
+ last-write-wins by tool call id, not append-only progress. The durable runtime
57
+ can retry a step and replay overlapping snapshots.
58
+
35
59
  ### The `ctx` parameter
36
60
 
37
61
  `execute` gets a `ctx` carrying the runtime accessors:
@@ -78,7 +102,7 @@ toModelOutput(output) {
78
102
  },
79
103
  ```
80
104
 
81
- `toModelOutput` receives the full, typed `execute` return and only affects the model. Channel event handlers and hooks still get the full output on `action.result`, so a channel can render rich platform output (Slack Block Kit, say) the model never sees. Return `{ type: "text", value }` for a summary, or `{ type: "json", value }` for a smaller object.
105
+ `toModelOutput` receives the final, typed `execute` return and only affects the model. Channel event handlers and hooks still get the full output on `action.result`, so a channel can render rich platform output (Slack Block Kit, say) the model never sees. Return `{ type: "text", value }` for a summary, or `{ type: "json", value }` for a smaller object.
82
106
 
83
107
  Tool outputs must be JSON-serializable. Return plain objects, arrays, strings, numbers, booleans, or `null`; convert values like `Date`, `Map`, `Set`, `NaN`, and cyclic objects before returning them from `execute` or from a `{ type: "json" }` `toModelOutput`.
84
108
 
@@ -43,7 +43,7 @@ export function AgentChat() {
43
43
  event.preventDefault();
44
44
  const data = new FormData(event.currentTarget);
45
45
  const message = String(data.get("q") ?? "").trim();
46
- if (message) void agent.send({ message });
46
+ if (message) void agent.send(message);
47
47
  }}
48
48
  >
49
49
  {agent.data.messages.map((message) => (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve",
3
- "version": "0.30.7",
3
+ "version": "0.31.0",
4
4
  "private": false,
5
5
  "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
6
6
  "keywords": [
@@ -1,6 +0,0 @@
1
- import type { CancelFn } from "#channel/routes.js";
2
- import type { Runtime } from "#channel/types.js";
3
- /**
4
- * Builds the route-handler `cancel` helper for one channel.
5
- */
6
- export declare function createCancelFn(runtime: Runtime, channelName: string): CancelFn;
@@ -1 +0,0 @@
1
- function createCancelFn(e,t){return async n=>await e.dispatchContinuation({command:{kind:`cancel`,turnId:n.turnId},continuationToken:`${t}:${n.continuationToken}`})}export{createCancelFn};
@@ -1,4 +0,0 @@
1
- import type { ClearFn } from "#channel/routes.js";
2
- import type { Runtime } from "#channel/types.js";
3
- /** Builds a channel-scoped context-clear helper. */
4
- export declare function createClearFn(runtime: Runtime, channelName: string): ClearFn;
@@ -1 +0,0 @@
1
- function createClearFn(e,t){return async n=>await e.dispatchContinuation({command:{kind:`clear`},continuationToken:`${t}:${n.continuationToken}`})}export{createClearFn};