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.
- package/CHANGELOG.md +38 -0
- package/README.md +5 -6
- package/dist/src/acp/adapter.d.ts +10 -4
- package/dist/src/acp/adapter.js +1 -1
- package/dist/src/channel/adapter-context.d.ts +1 -1
- package/dist/src/channel/adapter.d.ts +2 -4
- package/dist/src/channel/adapter.js +1 -1
- package/dist/src/channel/channel-address.d.ts +58 -0
- package/dist/src/channel/channel-address.js +1 -0
- package/dist/src/channel/channel-operations.d.ts +72 -0
- package/dist/src/channel/channel-operations.js +1 -0
- package/dist/src/channel/compiled-channel.d.ts +10 -6
- package/dist/src/channel/cross-channel-receive.d.ts +13 -25
- package/dist/src/channel/cross-channel-receive.js +2 -2
- package/dist/src/channel/receive-target.d.ts +1 -2
- package/dist/src/channel/routes.d.ts +21 -149
- package/dist/src/channel/schedule.d.ts +1 -1
- package/dist/src/channel/schedule.js +1 -1
- package/dist/src/channel/send-input.d.ts +6 -0
- package/dist/src/channel/send-input.js +1 -0
- package/dist/src/channel/session.d.ts +44 -30
- package/dist/src/channel/session.js +1 -1
- package/dist/src/channel/types.d.ts +8 -35
- package/dist/src/chunks/{use-eve-agent-DDoDDmJ2.js → use-eve-agent-CF5D6jSV.js} +339 -367
- package/dist/src/chunks/{use-eve-agent-Bx-ONuyb.js → use-eve-agent-DbYZLG0h.js} +342 -368
- package/dist/src/cli/commands/agent-prompt/build-and-verify.md +1 -2
- package/dist/src/cli/commands/channel-add-conflicts.js +1 -1
- package/dist/src/cli/commands/info.d.ts +1 -1
- package/dist/src/cli/commands/info.js +1 -1
- package/dist/src/cli/dev/tui/runner.d.ts +1 -1
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/subagent-pump.js +1 -1
- package/dist/src/cli/dev/tui/tui.js +1 -1
- package/dist/src/cli/invoke/invoke.d.ts +1 -1
- package/dist/src/cli/invoke/invoke.js +1 -1
- package/dist/src/cli/invoke/result.d.ts +0 -11
- package/dist/src/cli/invoke/result.js +1 -1
- package/dist/src/client/client-error.d.ts +2 -0
- package/dist/src/client/client-error.js +1 -1
- package/dist/src/client/client.d.ts +7 -14
- package/dist/src/client/client.js +1 -1
- package/dist/src/client/eve-agent-store.d.ts +4 -4
- package/dist/src/client/eve-agent-store.js +1 -1
- package/dist/src/client/index.d.ts +2 -1
- package/dist/src/client/index.js +1 -1
- package/dist/src/client/message-response.d.ts +2 -7
- package/dist/src/client/message-response.js +1 -1
- package/dist/src/client/open-stream.js +1 -1
- package/dist/src/client/session-controls.d.ts +29 -0
- package/dist/src/client/session-controls.js +1 -0
- package/dist/src/client/session-utils.d.ts +0 -20
- package/dist/src/client/session-utils.js +1 -1
- package/dist/src/client/session.d.ts +26 -90
- package/dist/src/client/session.js +1 -1
- package/dist/src/client/sessions.d.ts +20 -0
- package/dist/src/client/sessions.js +1 -0
- package/dist/src/client/types.d.ts +26 -47
- package/dist/src/compiler/extension-compatibility.d.ts +2 -2
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/compiler/normalize-subagent.js +1 -1
- package/dist/src/context/container.d.ts +3 -0
- package/dist/src/context/container.js +1 -1
- package/dist/src/discover/filesystem.js +1 -1
- package/dist/src/evals/cli/eval-client.js +1 -1
- package/dist/src/evals/context.js +1 -1
- package/dist/src/evals/session.d.ts +7 -6
- package/dist/src/evals/session.js +1 -1
- package/dist/src/evals/types.d.ts +9 -9
- package/dist/src/execution/agent-handle-dispatch.js +1 -1
- package/dist/src/execution/cancel-descendant-turns-step.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
- package/dist/src/execution/parked-delivery-wait.js +1 -1
- package/dist/src/execution/remote-agent-dispatch.d.ts +1 -3
- package/dist/src/execution/remote-agent-dispatch.js +1 -1
- package/dist/src/execution/runtime-context.js +1 -1
- package/dist/src/execution/runtime-errors.d.ts +1 -1
- package/dist/src/execution/session-command-inbox.d.ts +11 -3
- package/dist/src/execution/session-command-token.d.ts +2 -0
- package/dist/src/execution/session-command-token.js +1 -1
- package/dist/src/execution/session-command-wire.d.ts +24 -0
- package/dist/src/execution/session-command-wire.js +1 -0
- package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
- package/dist/src/execution/subagent-hitl-proxy.js +1 -1
- package/dist/src/execution/turn-control-receiver.d.ts +2 -2
- package/dist/src/execution/turn-control-receiver.js +1 -1
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/authorization.d.ts +8 -0
- package/dist/src/harness/authorization.js +1 -1
- package/dist/src/harness/cancelled-turn-emission.d.ts +1 -1
- package/dist/src/harness/cancelled-turn-emission.js +1 -1
- package/dist/src/harness/emission.d.ts +1 -1
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/handles/prompt.d.ts +22 -3
- package/dist/src/harness/handles/prompt.js +1 -1
- package/dist/src/harness/handles/store.d.ts +0 -5
- package/dist/src/harness/handles/store.js +1 -1
- package/dist/src/harness/runtime-actions.js +1 -1
- package/dist/src/harness/session-limit-enforcement.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
- package/dist/src/internal/nitro/dev-runtime-source-snapshot-copy.js +1 -1
- package/dist/src/internal/nitro/dev-runtime-source-snapshot-local-roots.d.ts +15 -0
- package/dist/src/internal/nitro/dev-runtime-source-snapshot-local-roots.js +1 -0
- package/dist/src/internal/nitro/dev-runtime-source-snapshot.d.ts +14 -2
- package/dist/src/internal/nitro/dev-runtime-source-snapshot.js +1 -1
- package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
- package/dist/src/internal/nitro/host/dev-server-http.js +1 -1
- package/dist/src/internal/nitro/routes/channel-dispatch.d.ts +2 -5
- package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
- package/dist/src/internal/nitro/routes/channel-route-context.d.ts +4 -3
- package/dist/src/internal/nitro/routes/channel-route-context.js +1 -1
- package/dist/src/packages/eve-catalog/src/index.js +1 -1
- package/dist/src/protocol/cancel-turn.d.ts +9 -4
- package/dist/src/protocol/cancel-turn.js +1 -1
- package/dist/src/protocol/message.d.ts +4 -14
- package/dist/src/protocol/message.js +2 -2
- package/dist/src/protocol/reset-session.d.ts +1 -1
- package/dist/src/protocol/routes.d.ts +27 -47
- package/dist/src/protocol/routes.js +1 -1
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +19 -21
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
- package/dist/src/public/channels/discord/discordChannel.d.ts +4 -4
- package/dist/src/public/channels/discord/discordChannel.js +1 -1
- package/dist/src/public/channels/eve.d.ts +11 -10
- package/dist/src/public/channels/eve.js +1 -1
- package/dist/src/public/channels/github/dispatch.d.ts +8 -8
- package/dist/src/public/channels/github/dispatch.js +1 -1
- package/dist/src/public/channels/github/githubChannel.d.ts +3 -3
- package/dist/src/public/channels/github/githubChannel.js +1 -1
- package/dist/src/public/channels/github/pr-context.d.ts +1 -1
- package/dist/src/public/channels/index.d.ts +1 -1
- package/dist/src/public/channels/linear/linearChannel.d.ts +3 -3
- package/dist/src/public/channels/linear/linearChannel.js +1 -1
- package/dist/src/public/channels/slack/index.d.ts +1 -1
- package/dist/src/public/channels/slack/interactions.d.ts +3 -4
- package/dist/src/public/channels/slack/interactions.js +1 -1
- package/dist/src/public/channels/slack/session-operations.d.ts +37 -0
- package/dist/src/public/channels/slack/session-operations.js +1 -0
- package/dist/src/public/channels/slack/slackChannel.d.ts +55 -74
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/channels/teams/teamsChannel.d.ts +3 -3
- package/dist/src/public/channels/teams/teamsChannel.js +1 -1
- package/dist/src/public/channels/telegram/telegramChannel.d.ts +4 -4
- package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
- package/dist/src/public/channels/twilio/twilioChannel.d.ts +3 -3
- package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
- package/dist/src/public/definitions/callback-context.d.ts +1 -2
- package/dist/src/public/definitions/channel.d.ts +21 -86
- package/dist/src/public/definitions/channel.js +1 -1
- package/dist/src/public/definitions/remote-agent.js +1 -1
- package/dist/src/public/definitions/schedule.d.ts +16 -16
- package/dist/src/public/definitions/tool.d.ts +18 -14
- package/dist/src/public/schedules/index.d.ts +1 -1
- package/dist/src/react/use-eve-agent.d.ts +7 -4
- package/dist/src/react/use-eve-agent.js +1 -1
- package/dist/src/runtime/agent/bootstrap-model-utils.d.ts +11 -0
- package/dist/src/runtime/agent/bootstrap-model-utils.js +1 -1
- package/dist/src/runtime/agent/mock-model-adapter.js +1 -1
- package/dist/src/runtime/agent/mock-model-fixtures.js +2 -2
- package/dist/src/runtime/connections/scoped-authorization.js +1 -1
- package/dist/src/runtime/framework-tools/connection-search-dynamic.js +2 -2
- package/dist/src/runtime/prompt/compose.js +1 -1
- package/dist/src/runtime/subagents/dynamic-remote-agent-config.js +1 -1
- package/dist/src/runtime/types.d.ts +2 -2
- package/dist/src/services/inspect-application.d.ts +1 -1
- package/dist/src/services/inspect-application.js +1 -1
- package/dist/src/setup/channel-add-conflicts.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
- package/dist/src/setup/scaffold/create/web-template.js +29 -17
- package/dist/src/shared/channel-definition.d.ts +7 -7
- package/dist/src/shared/schedule-definition.d.ts +2 -2
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.d.ts +8 -5
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.d.ts +8 -5
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/README.md +6 -6
- package/docs/channels/chat-sdk.mdx +5 -6
- package/docs/channels/custom.mdx +116 -144
- package/docs/channels/discord.mdx +1 -1
- package/docs/channels/eve.mdx +76 -30
- package/docs/channels/github.mdx +1 -1
- package/docs/channels/linear.mdx +6 -8
- package/docs/channels/overview.mdx +2 -2
- package/docs/channels/slack.mdx +46 -15
- package/docs/channels/telegram.mdx +1 -1
- package/docs/channels/twilio.mdx +1 -1
- package/docs/concepts/default-harness.md +11 -3
- package/docs/concepts/execution-model-and-durability.mdx +17 -5
- package/docs/concepts/sessions-runs-and-streaming.md +42 -16
- package/docs/evals/cases.mdx +3 -3
- package/docs/evals/targets.mdx +1 -1
- package/docs/guides/auth-and-route-protection.md +2 -1
- package/docs/guides/client/continuations.mdx +50 -77
- package/docs/guides/client/messages.mdx +29 -33
- package/docs/guides/client/output-schema.mdx +7 -14
- package/docs/guides/client/overview.mdx +40 -11
- package/docs/guides/client/streaming.mdx +17 -23
- package/docs/guides/frontend/nuxt.mdx +1 -1
- package/docs/guides/frontend/overview.mdx +40 -36
- package/docs/guides/frontend/sveltekit.mdx +1 -1
- package/docs/guides/frontend/use-eve-agent-svelte.mdx +19 -23
- package/docs/guides/frontend/use-eve-agent-vue.mdx +21 -25
- package/docs/guides/instrumentation.md +1 -1
- package/docs/guides/meta.json +2 -1
- package/docs/guides/remote-agents.md +6 -4
- package/docs/guides/ucp.mdx +181 -0
- package/docs/patterns/dynamic-scheduling.md +16 -15
- package/docs/schedules.mdx +10 -11
- package/docs/subagents.mdx +1 -1
- package/docs/tools/human-in-the-loop.md +1 -1
- package/docs/tutorial/ship-it.mdx +1 -1
- package/package.json +1 -1
- package/dist/src/channel/cancel.d.ts +0 -6
- package/dist/src/channel/cancel.js +0 -1
- package/dist/src/channel/clear-session.d.ts +0 -4
- package/dist/src/channel/clear-session.js +0 -1
- package/dist/src/channel/compact-session.d.ts +0 -4
- package/dist/src/channel/compact-session.js +0 -1
- package/dist/src/channel/reset-session.d.ts +0 -6
- package/dist/src/channel/reset-session.js +0 -1
- package/dist/src/channel/resolve-active-session.d.ts +0 -4
- package/dist/src/channel/resolve-active-session.js +0 -1
- package/dist/src/channel/send.d.ts +0 -6
- 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
|
|
29
|
-
| --------- |
|
|
30
|
-
| `data` | `ComputedRef<TData>`
|
|
31
|
-
| `status` | `ComputedRef<UseEveAgentStatus>`
|
|
32
|
-
| `error` | `ComputedRef<Error \| undefined>`
|
|
33
|
-
| `events` | `ComputedRef<readonly MessageStreamEvent[]>`
|
|
34
|
-
| `session` | `ComputedRef<
|
|
35
|
-
| `send` | `(
|
|
36
|
-
| `
|
|
37
|
-
| `
|
|
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(
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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 `
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
package/docs/guides/meta.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Remote Agents"
|
|
3
|
-
description: "Call another eve deployment as a subagent with defineRemoteAgent: same
|
|
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.
|
|
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
|
-
##
|
|
81
|
+
## Calling a remote agent
|
|
82
82
|
|
|
83
|
-
|
|
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({
|
|
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
|
|
51
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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. `
|
|
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
|
|
package/docs/schedules.mdx
CHANGED
|
@@ -19,7 +19,7 @@ interface ScheduleDefinition {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
interface ScheduleHandlerArgs {
|
|
22
|
-
|
|
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
|
|
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({
|
|
68
|
+
async run({ to, waitUntil, appAuth }) {
|
|
69
69
|
waitUntil(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
- `
|
|
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 `
|
|
84
|
-
- `appAuth`: the app principal (`{ authenticator: "app", principalId: "eve:app", principalType: "runtime" }`). Pass it as `
|
|
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
|
|
package/docs/subagents.mdx
CHANGED
|
@@ -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
|
-
|
|
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 `
|
|
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(
|
|
46
|
+
if (message) void agent.send(message);
|
|
47
47
|
}}
|
|
48
48
|
>
|
|
49
49
|
{agent.data.messages.map((message) => (
|
package/package.json
CHANGED
|
@@ -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 +0,0 @@
|
|
|
1
|
-
function createClearFn(e,t){return async n=>await e.dispatchContinuation({command:{kind:`clear`},continuationToken:`${t}:${n.continuationToken}`})}export{createClearFn};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function createCompactFn(e,t){return async n=>await e.dispatchContinuation({command:{kind:`compact`},continuationToken:`${t}:${n.continuationToken}`})}export{createCompactFn};
|
|
@@ -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>;
|
package/dist/src/channel/send.js
DELETED
|
@@ -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};
|