eve 0.30.8 → 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.
- package/CHANGELOG.md +29 -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/normalize-subagent.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/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-token.d.ts +2 -0
- package/dist/src/execution/session-command-token.js +1 -1
- 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-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/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-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/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/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/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
|
@@ -3,7 +3,7 @@ title: "Messages"
|
|
|
3
3
|
description: "Send text, full turn payloads, client context, attachments, and HITL responses with eve/client."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Create a session with its first turn, then use the returned `ClientSession` for follow-ups. Each handle targets one durable session ID.
|
|
7
7
|
|
|
8
8
|
## Send text
|
|
9
9
|
|
|
@@ -13,12 +13,12 @@ Pass a string to `send()` for plain text:
|
|
|
13
13
|
import { Client } from "eve/client";
|
|
14
14
|
|
|
15
15
|
const client = new Client({ host: "http://127.0.0.1:2000" });
|
|
16
|
-
const session = client.
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const { session, response } = await client.sessions.create({
|
|
17
|
+
message: "What is the weather in Brooklyn?",
|
|
18
|
+
});
|
|
19
19
|
|
|
20
20
|
// Metadata is available as soon as the POST succeeds.
|
|
21
|
-
console.log(response.sessionId
|
|
21
|
+
console.log(response.sessionId);
|
|
22
22
|
|
|
23
23
|
const result = await response.result();
|
|
24
24
|
console.log(result.status, result.message);
|
|
@@ -38,10 +38,10 @@ When the stream includes `session.failed`, the turn returns `status: "failed"` r
|
|
|
38
38
|
|
|
39
39
|
## Send a full turn payload
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Pass the full payload to `create()` for the first turn or `send()` for a follow-up:
|
|
42
42
|
|
|
43
43
|
```ts
|
|
44
|
-
const response = await
|
|
44
|
+
const { session, response } = await client.sessions.create({
|
|
45
45
|
message: "What should I do on this screen?",
|
|
46
46
|
clientContext: {
|
|
47
47
|
route: "/billing",
|
|
@@ -60,17 +60,15 @@ await response.result();
|
|
|
60
60
|
`send()` accepts AI SDK `UserContent`, so a message can mix text and file parts:
|
|
61
61
|
|
|
62
62
|
```ts
|
|
63
|
-
const response = await session.send(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
],
|
|
73
|
-
});
|
|
63
|
+
const response = await session.send([
|
|
64
|
+
{ type: "text", text: "Summarize this report." },
|
|
65
|
+
{
|
|
66
|
+
type: "file",
|
|
67
|
+
data: reportDataUrl,
|
|
68
|
+
mediaType: "application/pdf",
|
|
69
|
+
filename: "report.pdf",
|
|
70
|
+
},
|
|
71
|
+
]);
|
|
74
72
|
|
|
75
73
|
await response.result();
|
|
76
74
|
```
|
|
@@ -83,17 +81,15 @@ import { readFile } from "node:fs/promises";
|
|
|
83
81
|
const bytes = await readFile("report.pdf");
|
|
84
82
|
const reportDataUrl = `data:application/pdf;base64,${bytes.toString("base64")}`;
|
|
85
83
|
|
|
86
|
-
const response = await session.send(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
],
|
|
96
|
-
});
|
|
84
|
+
const response = await session.send([
|
|
85
|
+
{ type: "text", text: "Summarize this report." },
|
|
86
|
+
{
|
|
87
|
+
type: "file",
|
|
88
|
+
data: reportDataUrl,
|
|
89
|
+
mediaType: "application/pdf",
|
|
90
|
+
filename: "report.pdf",
|
|
91
|
+
},
|
|
92
|
+
]);
|
|
97
93
|
|
|
98
94
|
await response.result();
|
|
99
95
|
```
|
|
@@ -119,17 +115,17 @@ for await (const event of response) {
|
|
|
119
115
|
}
|
|
120
116
|
}
|
|
121
117
|
|
|
122
|
-
const resumed = await session.
|
|
123
|
-
|
|
118
|
+
const resumed = await session.respond(
|
|
119
|
+
pendingRequests.map((request) => ({
|
|
124
120
|
requestId: request.requestId,
|
|
125
121
|
optionId: "approve",
|
|
126
122
|
})),
|
|
127
|
-
|
|
123
|
+
);
|
|
128
124
|
|
|
129
125
|
await resumed.result();
|
|
130
126
|
```
|
|
131
127
|
|
|
132
|
-
|
|
128
|
+
`send(message, options)` and `respond(inputResponses, options)` are separate operations. Put `clientContext`, `outputSchema`, headers, or stream options in the second argument to either method.
|
|
133
129
|
|
|
134
130
|
## Single-use responses
|
|
135
131
|
|
|
@@ -27,9 +27,7 @@ const outputSchema = {
|
|
|
27
27
|
} as const;
|
|
28
28
|
|
|
29
29
|
const client = new Client({ host: "http://127.0.0.1:2000" });
|
|
30
|
-
const session = client.
|
|
31
|
-
|
|
32
|
-
const response = await session.send<Summary>({
|
|
30
|
+
const { session, response } = await client.sessions.create<Summary>({
|
|
33
31
|
message: "Summarize this turn.",
|
|
34
32
|
outputSchema,
|
|
35
33
|
});
|
|
@@ -56,8 +54,7 @@ const summarySchema = z.object({
|
|
|
56
54
|
|
|
57
55
|
type Summary = z.infer<typeof summarySchema>;
|
|
58
56
|
|
|
59
|
-
const response = await session.send<Summary>({
|
|
60
|
-
message: "Summarize this turn.",
|
|
57
|
+
const response = await session.send<Summary>("Summarize this turn.", {
|
|
61
58
|
outputSchema: summarySchema,
|
|
62
59
|
});
|
|
63
60
|
|
|
@@ -71,8 +68,7 @@ The server is authoritative for validation. The client types `MessageResult.data
|
|
|
71
68
|
If you consume events manually, read `result.completed`:
|
|
72
69
|
|
|
73
70
|
```ts
|
|
74
|
-
const response = await session.send<Summary>({
|
|
75
|
-
message: "Summarize this turn.",
|
|
71
|
+
const response = await session.send<Summary>("Summarize this turn.", {
|
|
76
72
|
outputSchema,
|
|
77
73
|
});
|
|
78
74
|
|
|
@@ -88,11 +84,10 @@ If more than one `result.completed` appears in the consumed event list, `result(
|
|
|
88
84
|
|
|
89
85
|
## Send payloads with output schema
|
|
90
86
|
|
|
91
|
-
`outputSchema`
|
|
87
|
+
Pass `outputSchema` in the second argument to `send()` or `respond()` alongside headers, signal, or client context:
|
|
92
88
|
|
|
93
89
|
```ts
|
|
94
|
-
const response = await session.send<Summary>({
|
|
95
|
-
message: "Summarize this PDF.",
|
|
90
|
+
const response = await session.send<Summary>("Summarize this PDF.", {
|
|
96
91
|
clientContext: { reportId: "rpt_123" },
|
|
97
92
|
outputSchema,
|
|
98
93
|
});
|
|
@@ -103,9 +98,7 @@ const result = await response.result();
|
|
|
103
98
|
It also works on follow-up turns and HITL response turns:
|
|
104
99
|
|
|
105
100
|
```ts
|
|
106
|
-
const response = await session.
|
|
107
|
-
inputResponses: [{ requestId, optionId: "approve" }],
|
|
108
|
-
message: "Return the approved action as structured output.",
|
|
101
|
+
const response = await session.respond([{ requestId, optionId: "approve" }], {
|
|
109
102
|
outputSchema,
|
|
110
103
|
});
|
|
111
104
|
|
|
@@ -117,7 +110,7 @@ const result = await response.result();
|
|
|
117
110
|
Client `outputSchema` is scoped to the turn that sends it. It doesn't become a permanent setting for the conversation:
|
|
118
111
|
|
|
119
112
|
```ts
|
|
120
|
-
const response = await session.send(
|
|
113
|
+
const response = await session.send("Return a structured summary.", { outputSchema });
|
|
121
114
|
await response.result();
|
|
122
115
|
|
|
123
116
|
const followUpResponse = await session.send("Now answer normally.");
|
|
@@ -100,8 +100,7 @@ Set `redirect` to `"manual"` or `"error"` on credential-bearing clients so fetch
|
|
|
100
100
|
Per-request headers can be attached to an individual turn:
|
|
101
101
|
|
|
102
102
|
```ts
|
|
103
|
-
const response = await session.send({
|
|
104
|
-
message: "Run the check.",
|
|
103
|
+
const response = await session.send("Run the check.", {
|
|
105
104
|
headers: { "x-request-id": requestId },
|
|
106
105
|
});
|
|
107
106
|
|
|
@@ -112,23 +111,53 @@ Per-request headers override client-level values with the same name. For example
|
|
|
112
111
|
|
|
113
112
|
## Sessions
|
|
114
113
|
|
|
115
|
-
|
|
114
|
+
For an ID-addressed session, create it explicitly with the first message:
|
|
116
115
|
|
|
117
116
|
```ts
|
|
118
|
-
const session = client.
|
|
117
|
+
const { session, response } = await client.sessions.create({ message: "Summarize account A." });
|
|
118
|
+
await response.result();
|
|
119
|
+
|
|
120
|
+
await (await session.send("Now list the risks.")).result();
|
|
121
|
+
await session.compact();
|
|
122
|
+
await session.clear();
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
If you already know the durable ID, attach a fixed handle without performing I/O:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const session = client.sessions.attach("wrun_A");
|
|
119
129
|
```
|
|
120
130
|
|
|
121
|
-
|
|
131
|
+
The fixed client handle exposes the full lifecycle around that ID. The calls below show the available shapes independently:
|
|
122
132
|
|
|
123
133
|
```ts
|
|
124
|
-
const
|
|
125
|
-
|
|
134
|
+
const response = await session.send("Continue the analysis.");
|
|
135
|
+
await response.result();
|
|
136
|
+
|
|
137
|
+
await session.cancel({ turnId: "turn_123" });
|
|
138
|
+
await session.compact();
|
|
139
|
+
await session.clear();
|
|
126
140
|
|
|
127
|
-
const
|
|
128
|
-
|
|
141
|
+
for await (const event of session.stream({ follow: false })) {
|
|
142
|
+
console.log(event.type);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
await session.reset({ reason: "User requested a fresh session" });
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`client.sessions` stores only the session ID and stream cursor. Every method calls an ID-addressed `/eve/v1/session/:sessionId/...` route. Sending through a handle for an unknown or terminal ID fails instead of creating a replacement, and reset leaves the handle pinned to the retired ID.
|
|
149
|
+
|
|
150
|
+
A client can own many independent fixed sessions at once:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
const { session: alice, response: aliceResponse } = await client.sessions.create({
|
|
154
|
+
message: "Summarize account A.",
|
|
155
|
+
});
|
|
156
|
+
const { session: bob, response: bobResponse } = await client.sessions.create({
|
|
157
|
+
message: "Summarize account B.",
|
|
158
|
+
});
|
|
129
159
|
|
|
130
|
-
|
|
131
|
-
await bobResponse.result();
|
|
160
|
+
await Promise.all([aliceResponse.result(), bobResponse.result()]);
|
|
132
161
|
```
|
|
133
162
|
|
|
134
163
|
The next pages cover the session lifecycle:
|
|
@@ -5,18 +5,22 @@ description: "Consume eve client stream events live, reconnect by event index, a
|
|
|
5
5
|
|
|
6
6
|
Every `ClientSession.send()` call posts the turn, then reads the session's NDJSON (newline-delimited JSON) event stream. `MessageResponse` gives you two ways to consume that stream, aggregating it with `result()` or iterating it live.
|
|
7
7
|
|
|
8
|
-
Once `send()` is accepted, the session exposes its assigned `sessionId` and can request cooperative cancellation with `session.cancel()`, even while the response stream is still running. The result status is `accepted` when the
|
|
8
|
+
Once `send()` is accepted, the session exposes its assigned `sessionId` and can request cooperative cancellation with `session.cancel()`, even while the response stream is still running. The result status is `accepted` when the live session durably queued the command, including when a parked session consumes it as a no-op. An unknown or terminal session returns `no_active_turn`:
|
|
9
9
|
|
|
10
10
|
```ts
|
|
11
|
-
const session = client.
|
|
12
|
-
const response = await session.send("Run the long operation.");
|
|
11
|
+
const { session, response } = await client.sessions.create({ message: "Run the long operation." });
|
|
13
12
|
|
|
14
13
|
const cancellation = await session.cancel();
|
|
15
|
-
|
|
14
|
+
if (cancellation.status === "accepted") {
|
|
15
|
+
console.log(cancellation.sessionId);
|
|
16
|
+
}
|
|
16
17
|
|
|
17
18
|
const result = await response.result();
|
|
18
19
|
```
|
|
19
20
|
|
|
21
|
+
The cancellation result is discriminated by `status`: only `accepted` includes
|
|
22
|
+
`sessionId`; `no_active_turn` has no session identity field.
|
|
23
|
+
|
|
20
24
|
Cancellation does not replace stream consumption. Continue reading the response to observe its terminal `turn.cancelled` and `session.waiting` boundary and to advance the client session cursor normally.
|
|
21
25
|
|
|
22
26
|
Between turns, `session.compact()` queues context compaction without sending model input. An accepted request reports the session id; consume the durable stream through the following `session.waiting` boundary before sending the next turn. `compaction.completed` confirms that summarization succeeded; without it, eve preserves the previous history. A never-started session returns `no_active_session` as a successful no-op.
|
|
@@ -103,7 +107,7 @@ The most common UI events are:
|
|
|
103
107
|
| `action.result` | Show tool call results. |
|
|
104
108
|
| `input.requested` | Pause the UI for approval or a question answer. |
|
|
105
109
|
| `result.completed` | Read structured output from an [output schema](./output-schema). |
|
|
106
|
-
| `session.waiting` | Enable the composer
|
|
110
|
+
| `session.waiting` | Enable the composer; the same fixed session handle accepts the next message. |
|
|
107
111
|
| `session.completed` | Mark the conversation terminal. |
|
|
108
112
|
| `session.failed` | Mark the conversation failed. |
|
|
109
113
|
|
|
@@ -129,8 +133,7 @@ If your consumer persists events, key on `event.meta.id`. It is stable across re
|
|
|
129
133
|
Set `streamReconnectPolicy: { reconnect: false }` when a relay or proxy owns the cursor and reconnection policy. This makes a single stream GET attempt and returns when that connection ends; it does not stop the server-side turn:
|
|
130
134
|
|
|
131
135
|
```ts
|
|
132
|
-
const response = await session.send({
|
|
133
|
-
message: "Run the long operation.",
|
|
136
|
+
const response = await session.send("Run the long operation.", {
|
|
134
137
|
streamReconnectPolicy: { reconnect: false },
|
|
135
138
|
});
|
|
136
139
|
|
|
@@ -146,9 +149,7 @@ The same option is available on manual attachments as `session.stream({ streamRe
|
|
|
146
149
|
Use `session.stream()` when you already have a session cursor and only need to attach to the existing stream:
|
|
147
150
|
|
|
148
151
|
```ts
|
|
149
|
-
const session = client.
|
|
150
|
-
continuationToken: "eve:6c8b1f2e-3d4a-4b9c-8e21-9f0a1b2c3d4e",
|
|
151
|
-
sessionId: "wrun_01ARYZ6S41TSV4RRFFQ69G5FAV",
|
|
152
|
+
const session = client.sessions.attach("wrun_01ARYZ6S41TSV4RRFFQ69G5FAV", {
|
|
152
153
|
streamIndex: 10,
|
|
153
154
|
});
|
|
154
155
|
|
|
@@ -169,9 +170,7 @@ Nonnegative values are absolute event indexes. Negative values read relative to
|
|
|
169
170
|
|
|
170
171
|
```ts
|
|
171
172
|
for await (const event of session.stream({ startIndex: -1 })) {
|
|
172
|
-
|
|
173
|
-
console.log(event.data.continuationToken);
|
|
174
|
-
}
|
|
173
|
+
console.log(event.type);
|
|
175
174
|
break;
|
|
176
175
|
}
|
|
177
176
|
```
|
|
@@ -193,15 +192,13 @@ The first connection pins the bound to the tail the server reports at open time;
|
|
|
193
192
|
|
|
194
193
|
Because a tail-relative cursor cannot be bounded, `follow: false` throws when combined with a negative `startIndex`. It also fails if the server does not report the durable tail (an agent running an older eve version).
|
|
195
194
|
|
|
196
|
-
`stream()` throws if the session has no `sessionId`, because there's no stream to attach to before the first send.
|
|
197
|
-
|
|
198
195
|
## Snapshot a session
|
|
199
196
|
|
|
200
197
|
Use `snapshot()` when you need the complete event prefix and its matching cursor
|
|
201
198
|
as one value, such as when hydrating a server-rendered chat:
|
|
202
199
|
|
|
203
200
|
```ts
|
|
204
|
-
const session = client.
|
|
201
|
+
const session = client.sessions.attach(sessionId);
|
|
205
202
|
const snapshot = await session.snapshot();
|
|
206
203
|
|
|
207
204
|
// snapshot.events contains event indexes 0 through snapshot.session.streamIndex - 1.
|
|
@@ -213,11 +210,9 @@ The read pins the durable tail when it opens, just like
|
|
|
213
210
|
continue. `snapshot()` always reads from index `0`; use a bounded stream directly
|
|
214
211
|
when you only need the unread suffix from an existing cursor.
|
|
215
212
|
|
|
216
|
-
Unlike `stream()`, `snapshot()` does not advance
|
|
217
|
-
`ClientSession`. Its returned
|
|
218
|
-
the captured prefix
|
|
219
|
-
explicitly preserved by the client. Active and terminal snapshots remain
|
|
220
|
-
inspectable at their returned stream cursor but cannot accept another turn.
|
|
213
|
+
Unlike `stream()`, `snapshot()` does not advance the originating
|
|
214
|
+
`ClientSession`. Its returned cursor contains the fixed session ID and the exact
|
|
215
|
+
stream index after the captured prefix.
|
|
221
216
|
|
|
222
217
|
## Abort a request
|
|
223
218
|
|
|
@@ -229,8 +224,7 @@ Arm the timeout before awaiting `send()` so it covers the POST as well as the st
|
|
|
229
224
|
const controller = new AbortController();
|
|
230
225
|
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
231
226
|
|
|
232
|
-
const response = await session.send({
|
|
233
|
-
message: "Run a long analysis.",
|
|
227
|
+
const response = await session.send("Run a long analysis.", {
|
|
234
228
|
signal: controller.signal,
|
|
235
229
|
});
|
|
236
230
|
|
|
@@ -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(
|
|
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`, `
|
|
71
|
-
| `send` | Send text or
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
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
|
|
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(
|
|
85
|
-
|
|
86
|
-
await agent.send(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
|
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 `
|
|
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.
|
|
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
|
|
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 {
|
|
229
|
+
import type { ClientSessionState, MessageStreamEvent } from "eve/client";
|
|
230
230
|
|
|
231
231
|
type SavedEveChat = {
|
|
232
232
|
events?: readonly MessageStreamEvent[];
|
|
233
|
-
session?:
|
|
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`, `
|
|
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
|
|
|
@@ -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
|
|
27
|
-
| --------- |
|
|
28
|
-
| `data` | `TData`
|
|
29
|
-
| `status` | `UseEveAgentStatus`
|
|
30
|
-
| `error` | `Error \| undefined`
|
|
31
|
-
| `events` | `readonly MessageStreamEvent[]`
|
|
32
|
-
| `session` | `
|
|
33
|
-
| `send` | `(
|
|
34
|
-
| `
|
|
35
|
-
| `
|
|
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(
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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.
|
|
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.
|
|
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
|
```
|