eve 0.30.7 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +5 -6
  3. package/dist/src/acp/adapter.d.ts +10 -4
  4. package/dist/src/acp/adapter.js +1 -1
  5. package/dist/src/channel/adapter-context.d.ts +1 -1
  6. package/dist/src/channel/adapter.d.ts +2 -4
  7. package/dist/src/channel/adapter.js +1 -1
  8. package/dist/src/channel/channel-address.d.ts +58 -0
  9. package/dist/src/channel/channel-address.js +1 -0
  10. package/dist/src/channel/channel-operations.d.ts +72 -0
  11. package/dist/src/channel/channel-operations.js +1 -0
  12. package/dist/src/channel/compiled-channel.d.ts +10 -6
  13. package/dist/src/channel/cross-channel-receive.d.ts +13 -25
  14. package/dist/src/channel/cross-channel-receive.js +2 -2
  15. package/dist/src/channel/receive-target.d.ts +1 -2
  16. package/dist/src/channel/routes.d.ts +21 -149
  17. package/dist/src/channel/schedule.d.ts +1 -1
  18. package/dist/src/channel/schedule.js +1 -1
  19. package/dist/src/channel/send-input.d.ts +6 -0
  20. package/dist/src/channel/send-input.js +1 -0
  21. package/dist/src/channel/session.d.ts +44 -30
  22. package/dist/src/channel/session.js +1 -1
  23. package/dist/src/channel/types.d.ts +8 -35
  24. package/dist/src/chunks/{use-eve-agent-k-XHfrJT.js → use-eve-agent-CF5D6jSV.js} +361 -367
  25. package/dist/src/chunks/{use-eve-agent-BXMIf5fR.js → use-eve-agent-DbYZLG0h.js} +364 -368
  26. package/dist/src/cli/commands/agent-prompt/build-and-verify.md +1 -2
  27. package/dist/src/cli/commands/channel-add-conflicts.js +1 -1
  28. package/dist/src/cli/commands/info.d.ts +1 -1
  29. package/dist/src/cli/commands/info.js +1 -1
  30. package/dist/src/cli/commands/registry-metadata.d.ts +15 -0
  31. package/dist/src/cli/commands/registry-metadata.js +1 -0
  32. package/dist/src/cli/commands/registry-package.d.ts +46 -0
  33. package/dist/src/cli/commands/registry-package.js +1 -0
  34. package/dist/src/cli/commands/registry.d.ts +1 -1
  35. package/dist/src/cli/commands/registry.js +4 -4
  36. package/dist/src/cli/dev/tui/runner.d.ts +1 -1
  37. package/dist/src/cli/dev/tui/runner.js +1 -1
  38. package/dist/src/cli/dev/tui/subagent-pump.js +1 -1
  39. package/dist/src/cli/dev/tui/terminal-renderer.js +2 -2
  40. package/dist/src/cli/dev/tui/tui.js +1 -1
  41. package/dist/src/cli/invoke/invoke.d.ts +1 -1
  42. package/dist/src/cli/invoke/invoke.js +1 -1
  43. package/dist/src/cli/invoke/result.d.ts +0 -11
  44. package/dist/src/cli/invoke/result.js +1 -1
  45. package/dist/src/client/client-error.d.ts +2 -0
  46. package/dist/src/client/client-error.js +1 -1
  47. package/dist/src/client/client.d.ts +7 -14
  48. package/dist/src/client/client.js +1 -1
  49. package/dist/src/client/eve-agent-store.d.ts +4 -4
  50. package/dist/src/client/eve-agent-store.js +1 -1
  51. package/dist/src/client/index.d.ts +3 -2
  52. package/dist/src/client/index.js +1 -1
  53. package/dist/src/client/message-reducer-types.d.ts +3 -0
  54. package/dist/src/client/message-reducer.js +1 -1
  55. package/dist/src/client/message-response.d.ts +2 -7
  56. package/dist/src/client/message-response.js +1 -1
  57. package/dist/src/client/open-stream.js +1 -1
  58. package/dist/src/client/session-controls.d.ts +29 -0
  59. package/dist/src/client/session-controls.js +1 -0
  60. package/dist/src/client/session-utils.d.ts +0 -20
  61. package/dist/src/client/session-utils.js +1 -1
  62. package/dist/src/client/session.d.ts +26 -90
  63. package/dist/src/client/session.js +1 -1
  64. package/dist/src/client/sessions.d.ts +20 -0
  65. package/dist/src/client/sessions.js +1 -0
  66. package/dist/src/client/types.d.ts +26 -47
  67. package/dist/src/compiler/extension-compatibility.d.ts +10 -10
  68. package/dist/src/compiler/extension-compatibility.js +1 -1
  69. package/dist/src/compiler/normalize-subagent.js +1 -1
  70. package/dist/src/evals/cli/eval-client.js +1 -1
  71. package/dist/src/evals/context.js +1 -1
  72. package/dist/src/evals/session.d.ts +7 -6
  73. package/dist/src/evals/session.js +1 -1
  74. package/dist/src/evals/types.d.ts +9 -9
  75. package/dist/src/execution/agent-handle-dispatch.js +1 -1
  76. package/dist/src/execution/cancel-descendant-turns-step.js +1 -1
  77. package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
  78. package/dist/src/execution/remote-agent-dispatch.d.ts +1 -3
  79. package/dist/src/execution/remote-agent-dispatch.js +1 -1
  80. package/dist/src/execution/runtime-context.js +1 -1
  81. package/dist/src/execution/runtime-errors.d.ts +1 -1
  82. package/dist/src/execution/session-command-token.d.ts +2 -0
  83. package/dist/src/execution/session-command-token.js +1 -1
  84. package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
  85. package/dist/src/execution/subagent-hitl-proxy.js +1 -1
  86. package/dist/src/execution/tool-auth.d.ts +1 -1
  87. package/dist/src/execution/tool-auth.js +1 -1
  88. package/dist/src/execution/turn-control-receiver.d.ts +2 -2
  89. package/dist/src/execution/turn-workflow.js +1 -1
  90. package/dist/src/execution/workflow-entry.js +1 -1
  91. package/dist/src/execution/workflow-runtime.js +1 -1
  92. package/dist/src/harness/cancelled-turn-emission.d.ts +1 -1
  93. package/dist/src/harness/cancelled-turn-emission.js +1 -1
  94. package/dist/src/harness/emission-state.d.ts +25 -0
  95. package/dist/src/harness/emission-state.js +1 -0
  96. package/dist/src/harness/emission.d.ts +5 -37
  97. package/dist/src/harness/emission.js +1 -1
  98. package/dist/src/harness/handles/prompt.d.ts +22 -3
  99. package/dist/src/harness/handles/prompt.js +1 -1
  100. package/dist/src/harness/handles/store.d.ts +0 -5
  101. package/dist/src/harness/handles/store.js +1 -1
  102. package/dist/src/harness/ordered-stream-emitter.d.ts +3 -2
  103. package/dist/src/harness/ordered-stream-emitter.js +1 -1
  104. package/dist/src/harness/runtime-actions.js +1 -1
  105. package/dist/src/harness/session-limit-enforcement.js +1 -1
  106. package/dist/src/harness/tool-loop.js +1 -1
  107. package/dist/src/harness/tools.d.ts +1 -1
  108. package/dist/src/harness/tools.js +1 -1
  109. package/dist/src/internal/application/package.js +1 -1
  110. package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
  111. package/dist/src/internal/nitro/dev-runtime-source-snapshot-copy.js +1 -1
  112. package/dist/src/internal/nitro/dev-runtime-source-snapshot-local-roots.d.ts +15 -0
  113. package/dist/src/internal/nitro/dev-runtime-source-snapshot-local-roots.js +1 -0
  114. package/dist/src/internal/nitro/dev-runtime-source-snapshot.d.ts +14 -2
  115. package/dist/src/internal/nitro/dev-runtime-source-snapshot.js +1 -1
  116. package/dist/src/internal/nitro/host/dev-server-http.js +1 -1
  117. package/dist/src/internal/nitro/routes/channel-dispatch.d.ts +2 -5
  118. package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
  119. package/dist/src/internal/nitro/routes/channel-route-context.d.ts +4 -3
  120. package/dist/src/internal/nitro/routes/channel-route-context.js +1 -1
  121. package/dist/src/packages/eve-catalog/src/index.js +1 -1
  122. package/dist/src/protocol/cancel-turn.d.ts +9 -4
  123. package/dist/src/protocol/cancel-turn.js +1 -1
  124. package/dist/src/protocol/message.d.ts +27 -17
  125. package/dist/src/protocol/message.js +2 -2
  126. package/dist/src/protocol/reset-session.d.ts +1 -1
  127. package/dist/src/protocol/routes.d.ts +27 -47
  128. package/dist/src/protocol/routes.js +1 -1
  129. package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +19 -21
  130. package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
  131. package/dist/src/public/channels/discord/discordChannel.d.ts +5 -4
  132. package/dist/src/public/channels/discord/discordChannel.js +1 -1
  133. package/dist/src/public/channels/eve.d.ts +11 -10
  134. package/dist/src/public/channels/eve.js +1 -1
  135. package/dist/src/public/channels/github/dispatch.d.ts +8 -8
  136. package/dist/src/public/channels/github/dispatch.js +1 -1
  137. package/dist/src/public/channels/github/githubChannel.d.ts +4 -3
  138. package/dist/src/public/channels/github/githubChannel.js +1 -1
  139. package/dist/src/public/channels/github/pr-context.d.ts +1 -1
  140. package/dist/src/public/channels/index.d.ts +1 -1
  141. package/dist/src/public/channels/linear/linearChannel.d.ts +4 -3
  142. package/dist/src/public/channels/linear/linearChannel.js +1 -1
  143. package/dist/src/public/channels/slack/index.d.ts +1 -1
  144. package/dist/src/public/channels/slack/interactions.d.ts +3 -4
  145. package/dist/src/public/channels/slack/interactions.js +1 -1
  146. package/dist/src/public/channels/slack/session-operations.d.ts +37 -0
  147. package/dist/src/public/channels/slack/session-operations.js +1 -0
  148. package/dist/src/public/channels/slack/slackChannel.d.ts +56 -74
  149. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  150. package/dist/src/public/channels/teams/teamsChannel.d.ts +4 -3
  151. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  152. package/dist/src/public/channels/telegram/telegramChannel.d.ts +5 -4
  153. package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
  154. package/dist/src/public/channels/twilio/twilioChannel.d.ts +4 -3
  155. package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
  156. package/dist/src/public/definitions/callback-context.d.ts +1 -2
  157. package/dist/src/public/definitions/channel.d.ts +22 -86
  158. package/dist/src/public/definitions/channel.js +1 -1
  159. package/dist/src/public/definitions/hook.d.ts +1 -0
  160. package/dist/src/public/definitions/remote-agent.js +1 -1
  161. package/dist/src/public/definitions/schedule.d.ts +16 -16
  162. package/dist/src/public/definitions/tool.d.ts +5 -5
  163. package/dist/src/public/schedules/index.d.ts +1 -1
  164. package/dist/src/react/use-eve-agent.d.ts +7 -4
  165. package/dist/src/react/use-eve-agent.js +1 -1
  166. package/dist/src/runtime/agent/bootstrap-model-utils.d.ts +11 -0
  167. package/dist/src/runtime/agent/bootstrap-model-utils.js +1 -1
  168. package/dist/src/runtime/agent/mock-model-adapter.js +1 -1
  169. package/dist/src/runtime/agent/mock-model-fixtures.js +2 -2
  170. package/dist/src/runtime/prompt/compose.js +1 -1
  171. package/dist/src/runtime/subagents/dynamic-remote-agent-config.js +1 -1
  172. package/dist/src/runtime/types.d.ts +2 -2
  173. package/dist/src/services/inspect-application.d.ts +1 -1
  174. package/dist/src/services/inspect-application.js +1 -1
  175. package/dist/src/setup/channel-add-conflicts.js +1 -1
  176. package/dist/src/setup/integrations/linear/setup.js +1 -1
  177. package/dist/src/setup/scaffold/create/project.js +1 -1
  178. package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
  179. package/dist/src/setup/scaffold/create/web-template.js +29 -17
  180. package/dist/src/shared/async-iterable.d.ts +2 -0
  181. package/dist/src/shared/async-iterable.js +1 -0
  182. package/dist/src/shared/channel-definition.d.ts +7 -7
  183. package/dist/src/shared/schedule-definition.d.ts +2 -2
  184. package/dist/src/shared/tool-definition.d.ts +1 -1
  185. package/dist/src/svelte/index.js +1 -1
  186. package/dist/src/svelte/use-eve-agent.d.ts +8 -5
  187. package/dist/src/svelte/use-eve-agent.js +1 -1
  188. package/dist/src/vue/index.js +1 -1
  189. package/dist/src/vue/use-eve-agent.d.ts +8 -5
  190. package/dist/src/vue/use-eve-agent.js +1 -1
  191. package/docs/README.md +6 -6
  192. package/docs/channels/chat-sdk.mdx +5 -6
  193. package/docs/channels/custom.mdx +116 -144
  194. package/docs/channels/discord.mdx +1 -1
  195. package/docs/channels/eve.mdx +76 -30
  196. package/docs/channels/github.mdx +1 -1
  197. package/docs/channels/linear.mdx +10 -10
  198. package/docs/channels/overview.mdx +2 -2
  199. package/docs/channels/slack.mdx +46 -15
  200. package/docs/channels/telegram.mdx +1 -1
  201. package/docs/channels/twilio.mdx +1 -1
  202. package/docs/concepts/default-harness.md +11 -3
  203. package/docs/concepts/execution-model-and-durability.mdx +17 -5
  204. package/docs/concepts/sessions-runs-and-streaming.md +45 -16
  205. package/docs/evals/cases.mdx +3 -3
  206. package/docs/evals/targets.mdx +1 -1
  207. package/docs/guides/auth-and-route-protection.md +2 -1
  208. package/docs/guides/client/continuations.mdx +50 -77
  209. package/docs/guides/client/messages.mdx +29 -33
  210. package/docs/guides/client/output-schema.mdx +7 -14
  211. package/docs/guides/client/overview.mdx +40 -11
  212. package/docs/guides/client/streaming.mdx +18 -23
  213. package/docs/guides/frontend/nuxt.mdx +1 -1
  214. package/docs/guides/frontend/overview.mdx +40 -36
  215. package/docs/guides/frontend/sveltekit.mdx +1 -1
  216. package/docs/guides/frontend/use-eve-agent-svelte.mdx +19 -23
  217. package/docs/guides/frontend/use-eve-agent-vue.mdx +21 -25
  218. package/docs/guides/hooks.md +1 -1
  219. package/docs/guides/instrumentation.md +1 -1
  220. package/docs/install-integrations.mdx +4 -2
  221. package/docs/patterns/dynamic-scheduling.md +16 -15
  222. package/docs/reference/cli.md +4 -1
  223. package/docs/schedules.mdx +10 -11
  224. package/docs/subagents.mdx +1 -1
  225. package/docs/tools/human-in-the-loop.md +1 -1
  226. package/docs/tools/overview.mdx +26 -2
  227. package/docs/tutorial/ship-it.mdx +1 -1
  228. package/package.json +1 -1
  229. package/dist/src/channel/cancel.d.ts +0 -6
  230. package/dist/src/channel/cancel.js +0 -1
  231. package/dist/src/channel/clear-session.d.ts +0 -4
  232. package/dist/src/channel/clear-session.js +0 -1
  233. package/dist/src/channel/compact-session.d.ts +0 -4
  234. package/dist/src/channel/compact-session.js +0 -1
  235. package/dist/src/channel/reset-session.d.ts +0 -6
  236. package/dist/src/channel/reset-session.js +0 -1
  237. package/dist/src/channel/resolve-active-session.d.ts +0 -4
  238. package/dist/src/channel/resolve-active-session.js +0 -1
  239. package/dist/src/channel/send.d.ts +0 -6
  240. package/dist/src/channel/send.js +0 -1
@@ -1,137 +1,110 @@
1
1
  ---
2
- title: "Continuations"
3
- description: "Persist and resume eve client sessions with continuation tokens, session IDs, and stream cursors."
2
+ title: "Session State"
3
+ description: "Persist and resume eve client sessions with durable session IDs and stream cursors."
4
4
  ---
5
5
 
6
- Every eve client turn returns two handles, and mixing them up is a common mistake. The TypeScript client tracks both for you:
7
-
8
- - `continuationToken`: the resume handle. Use it to send the next user turn.
9
- - `sessionId`: the stream-and-inspect handle. Use it to attach to event history.
10
-
11
- `ClientSession` also tracks `streamIndex`, the count of events already consumed. Together these three fields make a `SessionState`.
6
+ The TypeScript client uses one durable session ID for messages, controls, and
7
+ streams. A `ClientSession` adds a local `streamIndex` cursor so reconnects do not
8
+ replay events already consumed by that handle.
12
9
 
13
10
  ## Read and persist state
14
11
 
15
- After a streamed turn finishes, read `session.state`:
12
+ Create the session with its first turn, then persist `session.state` after
13
+ consuming the response:
16
14
 
17
15
  ```ts
18
- const session = client.session();
16
+ const { session, response } = await client.sessions.create({
17
+ message: "Create a launch checklist.",
18
+ });
19
19
 
20
- const response = await session.send("Create a launch checklist.");
21
20
  await response.result();
22
-
23
21
  await saveSessionState(session.state);
24
22
  ```
25
23
 
26
- As soon as `send()` returns, `session.state.sessionId` identifies the accepted in-flight turn for cancellation or stream reconnection. Consume the response before saving a fully advanced cursor: the continuation token and `streamIndex` update as events reach the turn boundary.
27
-
28
- Store the full state object:
24
+ The state is deliberately small:
29
25
 
30
26
  ```ts
31
- interface SessionState {
32
- continuationToken?: string;
33
- sessionId?: string;
27
+ interface ClientSessionState {
28
+ sessionId: string;
34
29
  streamIndex: number;
35
30
  }
36
31
  ```
37
32
 
38
- The continuation token resumes the conversation. The session ID and stream index let the client reconnect to the right stream position without replaying events it already consumed.
39
-
40
- `SessionState` is a cursor, not a chat transcript. If your app shows historical messages, persist the stream events separately and store them under your own chat or thread ID. On reload, pass the saved `SessionState` back to `client.session(savedState)` or `useEveAgent({ initialSession })`, and pass the saved events to your renderer or `useEveAgent({ initialEvents })`.
33
+ It is a remote stream cursor, not a transcript. Persist events separately when
34
+ your application renders chat history.
41
35
 
42
36
  ## Resume a saved session
43
37
 
44
- Pass the saved state back into `client.session()`:
38
+ Attach a fixed handle to the saved ID and restore its cursor:
45
39
 
46
40
  ```ts
47
- import type { SessionState } from "eve/client";
41
+ import type { ClientSessionState } from "eve/client";
48
42
 
49
- const saved = (await loadSessionState()) as SessionState;
50
- const session = client.session(saved);
43
+ const saved = (await loadSessionState()) as ClientSessionState;
44
+ const session = client.sessions.attach(saved.sessionId, {
45
+ streamIndex: saved.streamIndex,
46
+ });
51
47
 
52
48
  const response = await session.send("Now shorten it.");
53
- const result = await response.result();
54
- console.log(result.message);
55
- ```
56
-
57
- If all you have is a continuation token, pass it as shorthand:
58
-
59
- ```ts
60
- const session = client.session(continuationToken);
61
- const response = await session.send("Continue where we left off.");
62
- await response.result();
49
+ console.log((await response.result()).message);
63
50
  ```
64
51
 
65
- The shorthand can send a follow-up, but it doesn't know the previous stream cursor. Prefer full `SessionState` when you control persistence.
66
-
67
- ## Waiting, completed, and failed sessions
52
+ `attach()` performs no request. Every later operation targets exactly
53
+ `saved.sessionId`; it never follows or creates a replacement.
68
54
 
69
- When a turn ends with `session.waiting`, the event carries the current channel-owned `data.continuationToken` and the client preserves the state so the next send continues the conversation.
55
+ ## Waiting, completed, and reset sessions
70
56
 
71
- When a turn ends with `session.completed` or `session.failed`, the client resets its local state. The next send starts a fresh durable session:
57
+ A session that emits `session.waiting` accepts another message through the same
58
+ handle. A terminal or reset session does not. Start a fresh conversation
59
+ explicitly with another `client.sessions.create(firstTurn)` call.
72
60
 
73
61
  ```ts
74
- const response = await session.send("Do this one-shot task.");
75
- const result = await response.result();
76
-
77
- if (result.status === "completed") {
78
- // session.state is now a fresh cursor: { streamIndex: 0 }
79
- }
62
+ const reset = await session.reset({ reason: "Start over" });
63
+ const { session: fresh, response } = await client.sessions.create({ message: "Begin again." });
80
64
  ```
81
65
 
82
- This matches the runtime contract, where only waiting sessions can accept the next user input.
66
+ The old `session` remains pinned to its retired ID; `fresh` owns a different ID.
83
67
 
84
68
  ## Multiple sessions
85
69
 
86
- Create a separate `ClientSession` per conversation:
70
+ Create one handle per conversation:
87
71
 
88
72
  ```ts
89
- const research = client.session();
90
- const support = client.session();
91
-
92
- const researchResponse = await research.send("Research competitors.");
93
- await researchResponse.result();
94
-
95
- const supportResponse = await support.send("Draft a support reply.");
96
- await supportResponse.result();
97
-
73
+ const { session: research, response: researchResponse } = await client.sessions.create({
74
+ message: "Research competitors.",
75
+ });
76
+ const { session: support, response: supportResponse } = await client.sessions.create({
77
+ message: "Draft a support reply.",
78
+ });
79
+
80
+ await Promise.all([researchResponse.result(), supportResponse.result()]);
98
81
  await save("research", research.state);
99
82
  await save("support", support.state);
100
83
  ```
101
84
 
102
- The shared `Client` only owns host, auth, headers, and reconnect settings. Conversation state lives on each `ClientSession`.
103
-
104
- For a multi-chat UI, this usually means one application row per chat with two eve fields: the latest `SessionState` and the ordered event log for rendering. Do not reuse one `ClientSession` across sidebar conversations, and do not treat `streamIndex` as your database row index; it is only the remote stream cursor for that eve session.
85
+ The shared `Client` owns host, auth, headers, and redirect policy. Each
86
+ `ClientSession` owns its fixed ID and stream cursor.
105
87
 
106
88
  ## Reconnect an existing stream
107
89
 
108
- When a session already has a `sessionId`, `session.stream()` reattaches to its stream from the saved cursor. Resuming a saved `SessionState` after a restart is the common reason to do this:
90
+ `stream()` starts from the handle's saved cursor and advances it as events are
91
+ read:
109
92
 
110
93
  ```ts
111
- const session = client.session(savedState);
94
+ const session = client.sessions.attach(saved.sessionId, {
95
+ streamIndex: saved.streamIndex,
96
+ });
112
97
 
113
98
  for await (const event of session.stream()) {
114
99
  console.log(event.type);
115
100
  }
116
101
  ```
117
102
 
118
- `stream()` attaches to an existing run; to send new user input, use `send()`. For overriding the cursor with `startIndex` and the full reconnection model, see [Streaming](./streaming#open-a-stream-manually).
119
-
120
- If you only persisted `sessionId`, read the latest durable event to recover the current token from a waiting session:
121
-
122
- ```ts
123
- const session = client.session({ sessionId, streamIndex: 0 });
124
-
125
- for await (const event of session.stream({ startIndex: -1 })) {
126
- if (event.type === "session.waiting") {
127
- await saveContinuationToken(event.data.continuationToken);
128
- }
129
- break;
130
- }
131
- ```
103
+ Use `send()` for new input. For explicit cursors, tail-relative reads, and
104
+ bounded catch-up, see [Streaming](./streaming#open-a-stream-manually).
132
105
 
133
106
  ## What to read next
134
107
 
135
108
  - [Streaming](./streaming): stream events and reconnect by index
136
109
  - [Sessions, runs & streaming](../../concepts/sessions-runs-and-streaming): the raw HTTP contract
137
- - [eve channel](../../channels/eve): where continuation tokens come from
110
+ - [eve channel](../../channels/eve): the ID-addressed routes
@@ -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
- `ClientSession` sends one turn at a time. A fresh session starts on the first send; later sends continue the same conversation as long as the previous turn left the session waiting.
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.session();
17
-
18
- const response = await session.send("What is the weather in Brooklyn?");
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, response.continuationToken);
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
- Use `send()` when you need more than plain text:
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 session.send({
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
- message: [
65
- { type: "text", text: "Summarize this report." },
66
- {
67
- type: "file",
68
- data: reportDataUrl,
69
- mediaType: "application/pdf",
70
- filename: "report.pdf",
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
- message: [
88
- { type: "text", text: "Summarize this report." },
89
- {
90
- type: "file",
91
- data: reportDataUrl,
92
- mediaType: "application/pdf",
93
- filename: "report.pdf",
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.send({
123
- inputResponses: pendingRequests.map((request) => ({
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
- You can send `message`, `inputResponses`, and `clientContext` together when the resumed turn needs both a human answer and follow-up text.
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.session();
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` works with string shorthand and object-form sends. Use object form when you need schema, headers, signal, context, attachments, or HITL responses:
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.send({
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({ message: "Return a structured summary.", outputSchema });
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
- Create a `ClientSession` for each conversation:
114
+ For an ID-addressed session, create it explicitly with the first message:
116
115
 
117
116
  ```ts
118
- const session = client.session();
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
- A client can own many sessions at once. Each session tracks its own `sessionId`, `continuationToken`, and stream cursor:
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 alice = client.session();
125
- const bob = client.session();
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 aliceResponse = await alice.send("Summarize account A.");
128
- await aliceResponse.result();
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
- const bobResponse = await bob.send("Summarize account B.");
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 active turn accepted the signal or `no_active_turn` when it already settled:
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.session();
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
- console.log(cancellation.status);
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.
@@ -99,10 +103,11 @@ The most common UI events are:
99
103
  | `reasoning.appended` | Render reasoning deltas when the model provides them. |
100
104
  | `message.appended` | Render assistant text deltas. |
101
105
  | `actions.requested` | Show tool calls as the model requests them, before execution. |
106
+ | `action.partial` | Update a generator tool's provisional output snapshot. |
102
107
  | `action.result` | Show tool call results. |
103
108
  | `input.requested` | Pause the UI for approval or a question answer. |
104
109
  | `result.completed` | Read structured output from an [output schema](./output-schema). |
105
- | `session.waiting` | Enable the composer and read the current `data.continuationToken`. |
110
+ | `session.waiting` | Enable the composer; the same fixed session handle accepts the next message. |
106
111
  | `session.completed` | Mark the conversation terminal. |
107
112
  | `session.failed` | Mark the conversation failed. |
108
113
 
@@ -128,8 +133,7 @@ If your consumer persists events, key on `event.meta.id`. It is stable across re
128
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:
129
134
 
130
135
  ```ts
131
- const response = await session.send({
132
- message: "Run the long operation.",
136
+ const response = await session.send("Run the long operation.", {
133
137
  streamReconnectPolicy: { reconnect: false },
134
138
  });
135
139
 
@@ -145,9 +149,7 @@ The same option is available on manual attachments as `session.stream({ streamRe
145
149
  Use `session.stream()` when you already have a session cursor and only need to attach to the existing stream:
146
150
 
147
151
  ```ts
148
- const session = client.session({
149
- continuationToken: "eve:6c8b1f2e-3d4a-4b9c-8e21-9f0a1b2c3d4e",
150
- sessionId: "wrun_01ARYZ6S41TSV4RRFFQ69G5FAV",
152
+ const session = client.sessions.attach("wrun_01ARYZ6S41TSV4RRFFQ69G5FAV", {
151
153
  streamIndex: 10,
152
154
  });
153
155
 
@@ -168,9 +170,7 @@ Nonnegative values are absolute event indexes. Negative values read relative to
168
170
 
169
171
  ```ts
170
172
  for await (const event of session.stream({ startIndex: -1 })) {
171
- if (event.type === "session.waiting") {
172
- console.log(event.data.continuationToken);
173
- }
173
+ console.log(event.type);
174
174
  break;
175
175
  }
176
176
  ```
@@ -192,15 +192,13 @@ The first connection pins the bound to the tail the server reports at open time;
192
192
 
193
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).
194
194
 
195
- `stream()` throws if the session has no `sessionId`, because there's no stream to attach to before the first send.
196
-
197
195
  ## Snapshot a session
198
196
 
199
197
  Use `snapshot()` when you need the complete event prefix and its matching cursor
200
198
  as one value, such as when hydrating a server-rendered chat:
201
199
 
202
200
  ```ts
203
- const session = client.session({ sessionId, streamIndex: 0 });
201
+ const session = client.sessions.attach(sessionId);
204
202
  const snapshot = await session.snapshot();
205
203
 
206
204
  // snapshot.events contains event indexes 0 through snapshot.session.streamIndex - 1.
@@ -212,11 +210,9 @@ The read pins the durable tail when it opens, just like
212
210
  continue. `snapshot()` always reads from index `0`; use a bounded stream directly
213
211
  when you only need the unread suffix from an existing cursor.
214
212
 
215
- Unlike `stream()`, `snapshot()` does not advance or reset the originating
216
- `ClientSession`. Its returned session includes a continuation token only when
217
- the captured prefix ends in `session.waiting`, or when completed sessions are
218
- explicitly preserved by the client. Active and terminal snapshots remain
219
- 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.
220
216
 
221
217
  ## Abort a request
222
218
 
@@ -228,8 +224,7 @@ Arm the timeout before awaiting `send()` so it covers the POST as well as the st
228
224
  const controller = new AbortController();
229
225
  const timeout = setTimeout(() => controller.abort(), 10_000);
230
226
 
231
- const response = await session.send({
232
- message: "Run a long analysis.",
227
+ const response = await session.send("Run a long analysis.", {
233
228
  signal: controller.signal,
234
229
  });
235
230
 
@@ -48,7 +48,7 @@ async function handleSubmit() {
48
48
  const text = message.value.trim();
49
49
  if (!text || isBusy.value) return;
50
50
  message.value = "";
51
- await send({ message: text });
51
+ await send(text);
52
52
  }
53
53
  </script>
54
54