eve 0.30.8 → 0.31.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 (231) hide show
  1. package/CHANGELOG.md +38 -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-DDoDDmJ2.js → use-eve-agent-CF5D6jSV.js} +339 -367
  25. package/dist/src/chunks/{use-eve-agent-Bx-ONuyb.js → use-eve-agent-DbYZLG0h.js} +342 -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/dev/tui/runner.d.ts +1 -1
  31. package/dist/src/cli/dev/tui/runner.js +1 -1
  32. package/dist/src/cli/dev/tui/subagent-pump.js +1 -1
  33. package/dist/src/cli/dev/tui/tui.js +1 -1
  34. package/dist/src/cli/invoke/invoke.d.ts +1 -1
  35. package/dist/src/cli/invoke/invoke.js +1 -1
  36. package/dist/src/cli/invoke/result.d.ts +0 -11
  37. package/dist/src/cli/invoke/result.js +1 -1
  38. package/dist/src/client/client-error.d.ts +2 -0
  39. package/dist/src/client/client-error.js +1 -1
  40. package/dist/src/client/client.d.ts +7 -14
  41. package/dist/src/client/client.js +1 -1
  42. package/dist/src/client/eve-agent-store.d.ts +4 -4
  43. package/dist/src/client/eve-agent-store.js +1 -1
  44. package/dist/src/client/index.d.ts +2 -1
  45. package/dist/src/client/index.js +1 -1
  46. package/dist/src/client/message-response.d.ts +2 -7
  47. package/dist/src/client/message-response.js +1 -1
  48. package/dist/src/client/open-stream.js +1 -1
  49. package/dist/src/client/session-controls.d.ts +29 -0
  50. package/dist/src/client/session-controls.js +1 -0
  51. package/dist/src/client/session-utils.d.ts +0 -20
  52. package/dist/src/client/session-utils.js +1 -1
  53. package/dist/src/client/session.d.ts +26 -90
  54. package/dist/src/client/session.js +1 -1
  55. package/dist/src/client/sessions.d.ts +20 -0
  56. package/dist/src/client/sessions.js +1 -0
  57. package/dist/src/client/types.d.ts +26 -47
  58. package/dist/src/compiler/extension-compatibility.d.ts +2 -2
  59. package/dist/src/compiler/extension-compatibility.js +1 -1
  60. package/dist/src/compiler/normalize-subagent.js +1 -1
  61. package/dist/src/context/container.d.ts +3 -0
  62. package/dist/src/context/container.js +1 -1
  63. package/dist/src/discover/filesystem.js +1 -1
  64. package/dist/src/evals/cli/eval-client.js +1 -1
  65. package/dist/src/evals/context.js +1 -1
  66. package/dist/src/evals/session.d.ts +7 -6
  67. package/dist/src/evals/session.js +1 -1
  68. package/dist/src/evals/types.d.ts +9 -9
  69. package/dist/src/execution/agent-handle-dispatch.js +1 -1
  70. package/dist/src/execution/cancel-descendant-turns-step.js +1 -1
  71. package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
  72. package/dist/src/execution/parked-delivery-wait.js +1 -1
  73. package/dist/src/execution/remote-agent-dispatch.d.ts +1 -3
  74. package/dist/src/execution/remote-agent-dispatch.js +1 -1
  75. package/dist/src/execution/runtime-context.js +1 -1
  76. package/dist/src/execution/runtime-errors.d.ts +1 -1
  77. package/dist/src/execution/session-command-inbox.d.ts +11 -3
  78. package/dist/src/execution/session-command-token.d.ts +2 -0
  79. package/dist/src/execution/session-command-token.js +1 -1
  80. package/dist/src/execution/session-command-wire.d.ts +24 -0
  81. package/dist/src/execution/session-command-wire.js +1 -0
  82. package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
  83. package/dist/src/execution/subagent-hitl-proxy.js +1 -1
  84. package/dist/src/execution/turn-control-receiver.d.ts +2 -2
  85. package/dist/src/execution/turn-control-receiver.js +1 -1
  86. package/dist/src/execution/turn-workflow.js +1 -1
  87. package/dist/src/execution/workflow-entry.js +1 -1
  88. package/dist/src/execution/workflow-runtime.js +1 -1
  89. package/dist/src/execution/workflow-steps.js +1 -1
  90. package/dist/src/harness/authorization.d.ts +8 -0
  91. package/dist/src/harness/authorization.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.d.ts +1 -1
  95. package/dist/src/harness/emission.js +1 -1
  96. package/dist/src/harness/handles/prompt.d.ts +22 -3
  97. package/dist/src/harness/handles/prompt.js +1 -1
  98. package/dist/src/harness/handles/store.d.ts +0 -5
  99. package/dist/src/harness/handles/store.js +1 -1
  100. package/dist/src/harness/runtime-actions.js +1 -1
  101. package/dist/src/harness/session-limit-enforcement.js +1 -1
  102. package/dist/src/harness/tool-loop.js +1 -1
  103. package/dist/src/internal/application/package.js +1 -1
  104. package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
  105. package/dist/src/internal/nitro/dev-runtime-source-snapshot-copy.js +1 -1
  106. package/dist/src/internal/nitro/dev-runtime-source-snapshot-local-roots.d.ts +15 -0
  107. package/dist/src/internal/nitro/dev-runtime-source-snapshot-local-roots.js +1 -0
  108. package/dist/src/internal/nitro/dev-runtime-source-snapshot.d.ts +14 -2
  109. package/dist/src/internal/nitro/dev-runtime-source-snapshot.js +1 -1
  110. package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
  111. package/dist/src/internal/nitro/host/dev-server-http.js +1 -1
  112. package/dist/src/internal/nitro/routes/channel-dispatch.d.ts +2 -5
  113. package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
  114. package/dist/src/internal/nitro/routes/channel-route-context.d.ts +4 -3
  115. package/dist/src/internal/nitro/routes/channel-route-context.js +1 -1
  116. package/dist/src/packages/eve-catalog/src/index.js +1 -1
  117. package/dist/src/protocol/cancel-turn.d.ts +9 -4
  118. package/dist/src/protocol/cancel-turn.js +1 -1
  119. package/dist/src/protocol/message.d.ts +4 -14
  120. package/dist/src/protocol/message.js +2 -2
  121. package/dist/src/protocol/reset-session.d.ts +1 -1
  122. package/dist/src/protocol/routes.d.ts +27 -47
  123. package/dist/src/protocol/routes.js +1 -1
  124. package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +19 -21
  125. package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
  126. package/dist/src/public/channels/discord/discordChannel.d.ts +4 -4
  127. package/dist/src/public/channels/discord/discordChannel.js +1 -1
  128. package/dist/src/public/channels/eve.d.ts +11 -10
  129. package/dist/src/public/channels/eve.js +1 -1
  130. package/dist/src/public/channels/github/dispatch.d.ts +8 -8
  131. package/dist/src/public/channels/github/dispatch.js +1 -1
  132. package/dist/src/public/channels/github/githubChannel.d.ts +3 -3
  133. package/dist/src/public/channels/github/githubChannel.js +1 -1
  134. package/dist/src/public/channels/github/pr-context.d.ts +1 -1
  135. package/dist/src/public/channels/index.d.ts +1 -1
  136. package/dist/src/public/channels/linear/linearChannel.d.ts +3 -3
  137. package/dist/src/public/channels/linear/linearChannel.js +1 -1
  138. package/dist/src/public/channels/slack/index.d.ts +1 -1
  139. package/dist/src/public/channels/slack/interactions.d.ts +3 -4
  140. package/dist/src/public/channels/slack/interactions.js +1 -1
  141. package/dist/src/public/channels/slack/session-operations.d.ts +37 -0
  142. package/dist/src/public/channels/slack/session-operations.js +1 -0
  143. package/dist/src/public/channels/slack/slackChannel.d.ts +55 -74
  144. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  145. package/dist/src/public/channels/teams/teamsChannel.d.ts +3 -3
  146. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  147. package/dist/src/public/channels/telegram/telegramChannel.d.ts +4 -4
  148. package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
  149. package/dist/src/public/channels/twilio/twilioChannel.d.ts +3 -3
  150. package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
  151. package/dist/src/public/definitions/callback-context.d.ts +1 -2
  152. package/dist/src/public/definitions/channel.d.ts +21 -86
  153. package/dist/src/public/definitions/channel.js +1 -1
  154. package/dist/src/public/definitions/remote-agent.js +1 -1
  155. package/dist/src/public/definitions/schedule.d.ts +16 -16
  156. package/dist/src/public/definitions/tool.d.ts +18 -14
  157. package/dist/src/public/schedules/index.d.ts +1 -1
  158. package/dist/src/react/use-eve-agent.d.ts +7 -4
  159. package/dist/src/react/use-eve-agent.js +1 -1
  160. package/dist/src/runtime/agent/bootstrap-model-utils.d.ts +11 -0
  161. package/dist/src/runtime/agent/bootstrap-model-utils.js +1 -1
  162. package/dist/src/runtime/agent/mock-model-adapter.js +1 -1
  163. package/dist/src/runtime/agent/mock-model-fixtures.js +2 -2
  164. package/dist/src/runtime/connections/scoped-authorization.js +1 -1
  165. package/dist/src/runtime/framework-tools/connection-search-dynamic.js +2 -2
  166. package/dist/src/runtime/prompt/compose.js +1 -1
  167. package/dist/src/runtime/subagents/dynamic-remote-agent-config.js +1 -1
  168. package/dist/src/runtime/types.d.ts +2 -2
  169. package/dist/src/services/inspect-application.d.ts +1 -1
  170. package/dist/src/services/inspect-application.js +1 -1
  171. package/dist/src/setup/channel-add-conflicts.js +1 -1
  172. package/dist/src/setup/scaffold/create/project.js +1 -1
  173. package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
  174. package/dist/src/setup/scaffold/create/web-template.js +29 -17
  175. package/dist/src/shared/channel-definition.d.ts +7 -7
  176. package/dist/src/shared/schedule-definition.d.ts +2 -2
  177. package/dist/src/svelte/index.js +1 -1
  178. package/dist/src/svelte/use-eve-agent.d.ts +8 -5
  179. package/dist/src/svelte/use-eve-agent.js +1 -1
  180. package/dist/src/vue/index.js +1 -1
  181. package/dist/src/vue/use-eve-agent.d.ts +8 -5
  182. package/dist/src/vue/use-eve-agent.js +1 -1
  183. package/docs/README.md +6 -6
  184. package/docs/channels/chat-sdk.mdx +5 -6
  185. package/docs/channels/custom.mdx +116 -144
  186. package/docs/channels/discord.mdx +1 -1
  187. package/docs/channels/eve.mdx +76 -30
  188. package/docs/channels/github.mdx +1 -1
  189. package/docs/channels/linear.mdx +6 -8
  190. package/docs/channels/overview.mdx +2 -2
  191. package/docs/channels/slack.mdx +46 -15
  192. package/docs/channels/telegram.mdx +1 -1
  193. package/docs/channels/twilio.mdx +1 -1
  194. package/docs/concepts/default-harness.md +11 -3
  195. package/docs/concepts/execution-model-and-durability.mdx +17 -5
  196. package/docs/concepts/sessions-runs-and-streaming.md +42 -16
  197. package/docs/evals/cases.mdx +3 -3
  198. package/docs/evals/targets.mdx +1 -1
  199. package/docs/guides/auth-and-route-protection.md +2 -1
  200. package/docs/guides/client/continuations.mdx +50 -77
  201. package/docs/guides/client/messages.mdx +29 -33
  202. package/docs/guides/client/output-schema.mdx +7 -14
  203. package/docs/guides/client/overview.mdx +40 -11
  204. package/docs/guides/client/streaming.mdx +17 -23
  205. package/docs/guides/frontend/nuxt.mdx +1 -1
  206. package/docs/guides/frontend/overview.mdx +40 -36
  207. package/docs/guides/frontend/sveltekit.mdx +1 -1
  208. package/docs/guides/frontend/use-eve-agent-svelte.mdx +19 -23
  209. package/docs/guides/frontend/use-eve-agent-vue.mdx +21 -25
  210. package/docs/guides/instrumentation.md +1 -1
  211. package/docs/guides/meta.json +2 -1
  212. package/docs/guides/remote-agents.md +6 -4
  213. package/docs/guides/ucp.mdx +181 -0
  214. package/docs/patterns/dynamic-scheduling.md +16 -15
  215. package/docs/schedules.mdx +10 -11
  216. package/docs/subagents.mdx +1 -1
  217. package/docs/tools/human-in-the-loop.md +1 -1
  218. package/docs/tutorial/ship-it.mdx +1 -1
  219. package/package.json +1 -1
  220. package/dist/src/channel/cancel.d.ts +0 -6
  221. package/dist/src/channel/cancel.js +0 -1
  222. package/dist/src/channel/clear-session.d.ts +0 -4
  223. package/dist/src/channel/clear-session.js +0 -1
  224. package/dist/src/channel/compact-session.d.ts +0 -4
  225. package/dist/src/channel/compact-session.js +0 -1
  226. package/dist/src/channel/reset-session.d.ts +0 -6
  227. package/dist/src/channel/reset-session.js +0 -1
  228. package/dist/src/channel/resolve-active-session.d.ts +0 -4
  229. package/dist/src/channel/resolve-active-session.js +0 -1
  230. package/dist/src/channel/send.d.ts +0 -6
  231. package/dist/src/channel/send.js +0 -1
@@ -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
  ```
@@ -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
 
@@ -13,6 +13,7 @@
13
13
  "dev-tui",
14
14
  "acp",
15
15
  "frontend",
16
- "client"
16
+ "client",
17
+ "ucp"
17
18
  ]
18
19
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: "Remote Agents"
3
- description: "Call another eve deployment as a subagent with defineRemoteAgent: same lowered tool shape, outbound auth, durable callback dispatch."
3
+ description: "Call another eve deployment as a subagent with defineRemoteAgent: same tool call as a local subagent, outbound auth, durable callback dispatch."
4
4
  ---
5
5
 
6
6
  `defineRemoteAgent` calls a separately deployed eve agent as if it were a local subagent. Reach for it when the specialist you delegate to is a separately owned agent behind its own URL rather than a directory in your repo.
@@ -28,7 +28,7 @@ export default defineRemoteAgent({
28
28
  | `forwardPrincipal` | `boolean` | No | `false` | Forward the dispatching turn's session principal to the remote deployment (see [Forwarding the caller identity](#forwarding-the-caller-identity)). |
29
29
  | `headers` | `HeadersValue` | No | none | Static or lazily resolved request headers. |
30
30
  | `path` | `string` | No | `/eve/v1/session` | Route appended to `url` for the create-session request. |
31
- | `outputSchema` | `StandardSchema \| JSON Schema` | No | none | Structured return type the caller requires. Lowered to JSON Schema at compile time and enforced by the remote like any task-mode output schema. |
31
+ | `outputSchema` | `StandardSchema \| JSON Schema` | No | none | Structured return type the caller requires. Enforced by the remote agent like any task-mode output schema. Set it on the definition to apply to every call, or override it per call. |
32
32
 
33
33
  ## Dynamic remote agents
34
34
 
@@ -78,9 +78,11 @@ export default defineRemoteAgent({
78
78
 
79
79
  The function may be async and must return a non-empty string. `auth` and `headers` are resolved at runtime the same way.
80
80
 
81
- ## The lowered tool
81
+ ## Calling a remote agent
82
82
 
83
- A remote agent lowers to the same `{ message, outputSchema? }` tool shape as a local subagent. The parent packs everything the remote needs into `message`. The remote never sees the parent's history. Set `outputSchema` (here or per call) and the remote runs in task mode (a single-shot delegation that returns one structured result instead of an open conversation; see [Subagents](../subagents)), returning structured output as the tool result.
83
+ To the model, a remote agent is another subagent tool. You call it the same way you call a local subagent, with a `message` and an optional `outputSchema`. The message must carry the full task, including any context the remote agent needs, because it never receives the parent's conversation history.
84
+
85
+ To get one structured result back instead of an open-ended reply, set an `outputSchema` on the agent definition or on an individual call. The remote agent then runs in task mode, a single-shot delegation that returns structured output as the tool result. See [Subagents](../subagents) for how task mode works.
84
86
 
85
87
  ## Outbound auth
86
88
 
@@ -0,0 +1,181 @@
1
+ ---
2
+ title: "Universal Commerce Protocol (UCP)"
3
+ description: "Serve a UCP profile at /.well-known/ucp from a custom eve channel."
4
+ ---
5
+
6
+ The [Universal Commerce Protocol](https://ucp.dev/) (UCP) is an open standard for agentic commerce. A business declares its UCP support by serving a JSON **profile** from the `/.well-known/ucp` path. This is a document listing the spec versions it supports, its services and capabilities, its payment handlers, and the public keys agents use to verify signed responses.
7
+
8
+ With eve, you can support UCP in three steps:
9
+
10
+ 1. [Author the profile](#author-the-profile)
11
+ 2. [Serve it from a channel](#serve-it-from-a-channel)
12
+ 3. [Add your commerce endpoints](#add-your-commerce-endpoints)
13
+
14
+ ## Author the profile
15
+
16
+ Your profile is a plain JSON object that follows the [UCP spec](https://ucp.dev/). This spec outlines the `version`, `services`, `payment_handlers` and `capabilities` of your business. It also includes `signing_keys`, the public keys agents use to verify your business's signed messages.
17
+
18
+ ```ts
19
+ // agent/ucp-profile.ts
20
+ export const profile = {
21
+ ucp: {
22
+ version: "2026-04-08",
23
+ services: {
24
+ "dev.ucp.shopping": [
25
+ {
26
+ version: "2026-04-08",
27
+ spec: "https://ucp.dev/2026-04-08/specification/overview",
28
+ transport: "rest",
29
+ schema: "https://ucp.dev/2026-04-08/services/shopping/rest.openapi.json",
30
+ endpoint: "https://your_deployment_url_here/ucp/shopping",
31
+ },
32
+ ],
33
+ },
34
+ capabilities: {
35
+ "dev.ucp.shopping.checkout": [
36
+ {
37
+ version: "2026-04-08",
38
+ spec: "https://ucp.dev/2026-04-08/specification/checkout",
39
+ schema: "https://ucp.dev/2026-04-08/schemas/shopping/checkout.json",
40
+ },
41
+ ],
42
+ },
43
+ payment_handlers: {
44
+ "dev.shopify.shop_pay": [
45
+ {
46
+ id: "shop_pay_1234",
47
+ version: "2026-04-08",
48
+ spec: "https://shopify.dev/ucp/shop-pay-handler",
49
+ schema: "https://shopify.dev/ucp/schemas/shop-pay-config.json",
50
+ available_instruments: [
51
+ {
52
+ type: "shop_pay",
53
+ },
54
+ ],
55
+ },
56
+ ],
57
+ "com.example.processor_tokenizer": [
58
+ {
59
+ id: "processor_tokenizer",
60
+ version: "2026-04-08",
61
+ spec: "https://example.com/specs/payments/processor_tokenizer-payment",
62
+ schema: "https://example.com/schemas/payments/delegate-payment.json",
63
+ available_instruments: [
64
+ {
65
+ type: "card",
66
+ constraints: {
67
+ brands: ["visa", "mastercard"],
68
+ },
69
+ },
70
+ ],
71
+ },
72
+ ],
73
+ },
74
+ },
75
+ signing_keys: [
76
+ {
77
+ kid: "business_2025",
78
+ kty: "EC",
79
+ crv: "P-256",
80
+ x: "...",
81
+ y: "...",
82
+ use: "sig",
83
+ alg: "ES256",
84
+ },
85
+ ],
86
+ };
87
+ ```
88
+
89
+ ## Serve it from a channel
90
+
91
+ Use a custom channel to serve the profile from the `/.well-known/ucp` endpoint.
92
+
93
+ ```ts
94
+ // agent/channels/ucp.ts
95
+ import { defineChannel, GET } from "eve/channels";
96
+ import { profile } from "../ucp-profile";
97
+
98
+ const body = JSON.stringify(profile);
99
+
100
+ export default defineChannel({
101
+ cors: true,
102
+ routes: [
103
+ GET("/.well-known/ucp", async () => {
104
+ return new Response(body, {
105
+ headers: {
106
+ "content-type": "application/json",
107
+ "cache-control": "public, max-age=300",
108
+ },
109
+ });
110
+ }),
111
+ ],
112
+ });
113
+ ```
114
+
115
+ - **Caching**: The spec requires `public` and a `max-age` of at least 60 seconds, and forbids `private`, `no-store`, and `no-cache`. See [Profile Requirements](https://ucp.dev/2026-04-08/specification/overview#hosting).
116
+ - **CORS**: `cors: true` suits public discovery metadata. Pass a `cors` options object to narrow origins. See [CORS](../channels/custom#cors).
117
+ - **HTTPS, no redirects**: The spec requires HTTPS and forbids 3xx responses on the profile endpoint.
118
+
119
+ ## Add your commerce endpoints
120
+
121
+ The URLs in `services[].endpoint` must point at endpoints you serve. You can use a custom channel for these endpoints:
122
+
123
+ ```ts
124
+ // agent/channels/ucp-shopping.ts
125
+ import { defineChannel, POST } from "eve/channels";
126
+
127
+ export default defineChannel({
128
+ routes: [
129
+ POST("/ucp/shopping/checkout-sessions", async (req) => {
130
+ const request = await req.json();
131
+ // Create a checkout session per your published schema. Every UCP
132
+ // response must carry the `ucp` envelope with the negotiated
133
+ // version and the capabilities active for this response.
134
+ return Response.json({
135
+ ucp: {
136
+ version: "2026-04-08",
137
+ capabilities: {
138
+ "dev.ucp.shopping.checkout": [{ version: "2026-04-08" }],
139
+ },
140
+ },
141
+ id: "checkout_123",
142
+ status: "incomplete",
143
+ // ...other checkout fields per the checkout schema
144
+ });
145
+ }),
146
+ ],
147
+ });
148
+ ```
149
+
150
+ Routes are relative to the `endpoint` base in your profile, per the service's OpenAPI schema. Keep them in sync with the paths you mount here.
151
+
152
+ ## Verify
153
+
154
+ Start the dev server with `eve dev` and fetch the well-known document locally:
155
+
156
+ ```sh
157
+ curl -i http://localhost:2000/.well-known/ucp
158
+ ```
159
+
160
+ Then fetch it from your deployment:
161
+
162
+ ```sh
163
+ curl -i https://your_deployment_url_here/.well-known/ucp
164
+ ```
165
+
166
+ Expect a `200` with the profile JSON:
167
+
168
+ ```http
169
+ HTTP/2 200
170
+ content-type: application/json
171
+ cache-control: public, max-age=300
172
+ ```
173
+
174
+ ## What's not covered
175
+
176
+ Commerce operation semantics are author-owned: the checkout, cart, and order state machines; payment-handler execution; and request signing and verification.
177
+
178
+ ## Read next
179
+
180
+ - [Channels overview](../channels/overview): The channel contract this builds on.
181
+ - [Custom channels](../channels/custom): The route helpers, CORS, and metadata this page uses.
@@ -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
 
@@ -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";
@@ -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.8",
3
+ "version": "0.31.1",
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};
@@ -1,4 +0,0 @@
1
- import type { CompactFn } from "#channel/routes.js";
2
- import type { Runtime } from "#channel/types.js";
3
- /** Builds a channel-scoped manual compaction helper. */
4
- export declare function createCompactFn(runtime: Runtime, channelName: string): CompactFn;
@@ -1 +0,0 @@
1
- function createCompactFn(e,t){return async n=>await e.dispatchContinuation({command:{kind:`compact`},continuationToken:`${t}:${n.continuationToken}`})}export{createCompactFn};
@@ -1,6 +0,0 @@
1
- import type { ResetFn } from "#channel/routes.js";
2
- import type { Runtime } from "#channel/types.js";
3
- /**
4
- * Builds a channel-scoped session reset helper.
5
- */
6
- export declare function createResetFn(runtime: Runtime, channelName: string): ResetFn;
@@ -1 +0,0 @@
1
- function createResetFn(e,t){return async n=>{let r=`${t}:${n.continuationToken}`;return await e.dispatchContinuation({command:{kind:`reset`,reason:n.reason},continuationToken:r})}}export{createResetFn};
@@ -1,4 +0,0 @@
1
- import type { ResolveActiveSessionFn } from "#channel/routes.js";
2
- import type { Runtime } from "#channel/types.js";
3
- /** Builds a channel-scoped lookup for the active owner of a continuation token. */
4
- export declare function createResolveActiveSessionFn(runtime: Runtime, channelName: string): ResolveActiveSessionFn;
@@ -1 +0,0 @@
1
- function createResolveActiveSessionFn(e,t){return({continuationToken:n})=>e.resolveContinuation(`${t}:${n}`)}export{createResolveActiveSessionFn};
@@ -1,6 +0,0 @@
1
- import type { ChannelAdapter } from "#channel/adapter.js";
2
- import type { Runtime } from "#channel/types.js";
3
- import type { SendFn } from "#channel/routes.js";
4
- export declare function createSendFn<TState = undefined>(runtime: Runtime, adapter: ChannelAdapter<any>, channelName: string, metadata?: {
5
- readonly requestId?: string;
6
- }): SendFn<TState>;
@@ -1 +0,0 @@
1
- import{createSession}from"#channel/session.js";import{RuntimeNoActiveSessionError,isRuntimeSessionOwnershipConflictError}from"#execution/runtime-errors.js";import{serializeUrlFilePart}from"#internal/attachments/url-refs.js";function createSendFn(r,i,a,o={}){return async(s,c)=>{let l=c,{auth:u,callback:d,caller:f,capabilities:p,initiatorAuth:m,state:h,title:g}=l,_=l.intent??`resume-or-start`,v=l.mode??`conversation`,y=l.continuationToken,b=`${a}:${y}`,{message:x,inputResponses:S,context:C,outputSchema:w}=normalizeSendInput(s),T=serializeUrlFilePartsInMessage(x),E={auth:u,caller:f,kind:`send`,payload:{inputResponses:S,message:T,context:C,outputSchema:w},requestId:o.requestId},dispatch=async()=>{let t=await r.dispatchContinuation({command:E,continuationToken:b});return t.status===`accepted`?createSession(t.sessionId,y,r):void 0},D=await dispatch();if(D!==void 0)return D;if(_===`resume`)throw new RuntimeNoActiveSessionError(b);if(S&&S.length>0)throw Error(`Cannot deliver inputResponses — the target session was not found via continuation token.`);let O={adapter:h?{...i,state:{...i.state,...h}}:i,auth:u,capabilities:p??(v===`conversation`?{requestInput:!0}:void 0),channelName:a,callback:d,continuationToken:b,input:{message:T??``,context:C,outputSchema:w},mode:v,requestId:o.requestId,title:g};m!==void 0&&(O.initiatorAuth=m);try{return createSession((await r.createSession(O)).sessionId,y,r)}catch(e){if(!isRuntimeSessionOwnershipConflictError(e))throw e;let t=await dispatch();if(t!==void 0)return t;throw e}}}function serializeUrlFilePartsInMessage(e){if(e===void 0||typeof e==`string`)return e;let t=!1,n=e.map(e=>e.type===`file`&&e.data instanceof URL&&e.data.protocol!==`data:`?(t=!0,{...e,data:serializeUrlFilePart(e.data)}):e);return t?n:e}function normalizeSendInput(e){return typeof e==`string`||Array.isArray(e)?{message:e}:e}export{createSendFn};