eve 0.69.0 → 0.70.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 (326) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/src/acp/adapter.js +1 -1
  3. package/dist/src/channel/task-card.d.ts +3 -3
  4. package/dist/src/channel/task-card.js +1 -1
  5. package/dist/src/channel/types.d.ts +18 -0
  6. package/dist/src/chunks/{use-eve-agent-Dab2MnT2.js → use-eve-agent-CJQeE7-t.js} +1873 -1236
  7. package/dist/src/chunks/{use-eve-agent-D_5129A9.js → use-eve-agent-DdemtY6C.js} +1874 -1234
  8. package/dist/src/cli/dev/command.js +1 -1
  9. package/dist/src/cli/dev/console-records-preload.d.ts +1 -0
  10. package/dist/src/cli/dev/console-records-preload.js +1 -0
  11. package/dist/src/cli/dev/console-records.d.ts +17 -0
  12. package/dist/src/cli/dev/console-records.js +3 -0
  13. package/dist/src/cli/dev/diagnostic-sink.d.ts +1 -0
  14. package/dist/src/cli/dev/local-server-process.js +1 -1
  15. package/dist/src/cli/dev/tui/blocks.d.ts +2 -1
  16. package/dist/src/cli/dev/tui/blocks.js +3 -3
  17. package/dist/src/cli/dev/tui/conversation-view.d.ts +54 -0
  18. package/dist/src/cli/dev/tui/conversation-view.js +1 -0
  19. package/dist/src/cli/dev/tui/flow-drawer.d.ts +5 -2
  20. package/dist/src/cli/dev/tui/flow-drawer.js +1 -1
  21. package/dist/src/cli/dev/tui/log-display-mode.d.ts +4 -10
  22. package/dist/src/cli/dev/tui/log-display-mode.js +1 -1
  23. package/dist/src/cli/dev/tui/message-queue.d.ts +7 -63
  24. package/dist/src/cli/dev/tui/message-queue.js +3 -1
  25. package/dist/src/cli/dev/tui/prompt-commands.js +1 -1
  26. package/dist/src/cli/dev/tui/question-panel.d.ts +3 -1
  27. package/dist/src/cli/dev/tui/question-panel.js +1 -1
  28. package/dist/src/cli/dev/tui/runner.d.ts +56 -193
  29. package/dist/src/cli/dev/tui/runner.js +3 -3
  30. package/dist/src/cli/dev/tui/task-activity.d.ts +11 -7
  31. package/dist/src/cli/dev/tui/task-activity.js +1 -1
  32. package/dist/src/cli/dev/tui/terminal-renderer.d.ts +15 -37
  33. package/dist/src/cli/dev/tui/terminal-renderer.js +10 -13
  34. package/dist/src/cli/dev/tui/terminal-tool-part.d.ts +2 -0
  35. package/dist/src/cli/dev/tui/terminal-tool-part.js +1 -0
  36. package/dist/src/cli/dev/tui/test/fake-eve-server.d.ts +34 -0
  37. package/dist/src/cli/dev/tui/test/fake-eve-server.js +1 -0
  38. package/dist/src/cli/dev/tui/test/index.d.ts +1 -0
  39. package/dist/src/cli/dev/tui/test/index.js +1 -1
  40. package/dist/src/cli/dev/tui/tool-block-groups.js +1 -1
  41. package/dist/src/cli/dev/tui/tool-presentation.d.ts +1 -0
  42. package/dist/src/cli/dev/tui/tool-presentation.js +1 -1
  43. package/dist/src/cli/dev/tui/tool-rows.d.ts +1 -0
  44. package/dist/src/cli/dev/tui/tool-rows.js +2 -2
  45. package/dist/src/cli/dev/tui/transcript-parts.d.ts +73 -0
  46. package/dist/src/cli/dev/tui/transcript-parts.js +3 -0
  47. package/dist/src/cli/dev/tui/transcript.d.ts +47 -0
  48. package/dist/src/cli/dev/tui/transcript.js +1 -0
  49. package/dist/src/cli/dev/tui/tui.js +1 -1
  50. package/dist/src/cli/dev/tui/turn-clock.d.ts +11 -26
  51. package/dist/src/cli/dev/tui/turn-clock.js +1 -1
  52. package/dist/src/cli/dev/tui/types.d.ts +2 -4
  53. package/dist/src/cli/dev/ui-options.js +1 -1
  54. package/dist/src/client/agent-stream-follower.d.ts +26 -0
  55. package/dist/src/client/agent-stream-follower.js +1 -0
  56. package/dist/src/client/authorization-message-parts.js +1 -1
  57. package/dist/src/client/conversation-client.d.ts +40 -0
  58. package/dist/src/client/conversation-client.js +1 -0
  59. package/dist/src/client/conversation-reducer.d.ts +29 -0
  60. package/dist/src/client/conversation-reducer.js +1 -0
  61. package/dist/src/client/conversation-state.d.ts +110 -0
  62. package/dist/src/client/conversation-state.js +1 -0
  63. package/dist/src/client/eve-agent-projection.d.ts +24 -7
  64. package/dist/src/client/eve-agent-projection.js +1 -1
  65. package/dist/src/client/eve-agent-store-helpers.d.ts +21 -2
  66. package/dist/src/client/eve-agent-store-helpers.js +2 -2
  67. package/dist/src/client/eve-agent-store-state.d.ts +15 -3
  68. package/dist/src/client/eve-agent-store.d.ts +10 -1
  69. package/dist/src/client/eve-agent-store.js +1 -1
  70. package/dist/src/client/index.d.ts +4 -1
  71. package/dist/src/client/index.js +1 -1
  72. package/dist/src/client/message-reducer-primitives.d.ts +1 -2
  73. package/dist/src/client/message-reducer-primitives.js +1 -1
  74. package/dist/src/client/message-reducer-types.d.ts +9 -2
  75. package/dist/src/client/message-reducer.js +1 -1
  76. package/dist/src/client/message-response.js +1 -1
  77. package/dist/src/client/message-run-parts.d.ts +10 -6
  78. package/dist/src/client/message-run-parts.js +1 -1
  79. package/dist/src/client/optimistic-message-submissions.d.ts +6 -4
  80. package/dist/src/client/optimistic-message-submissions.js +1 -1
  81. package/dist/src/client/reducer.d.ts +5 -1
  82. package/dist/src/client/session-turn-dispatch.d.ts +15 -0
  83. package/dist/src/client/session-turn-dispatch.js +1 -0
  84. package/dist/src/client/session-utils.d.ts +27 -10
  85. package/dist/src/client/session-utils.js +1 -1
  86. package/dist/src/client/session.js +1 -1
  87. package/dist/src/client/types.d.ts +2 -1
  88. package/dist/src/compiled/.vendor-stamp.json +1 -1
  89. package/dist/src/compiler/extension-compatibility.d.ts +18 -18
  90. package/dist/src/compiler/extension-compatibility.js +1 -1
  91. package/dist/src/compiler/load-binding-namespace.js +1 -1
  92. package/dist/src/context/keys.d.ts +5 -2
  93. package/dist/src/context/keys.js +1 -1
  94. package/dist/src/context/provider.d.ts +5 -9
  95. package/dist/src/context/run-step.d.ts +4 -4
  96. package/dist/src/context/run-step.js +1 -1
  97. package/dist/src/evals/runner/derive-run-facts.js +1 -1
  98. package/dist/src/evals/runner/execute-task.js +1 -1
  99. package/dist/src/evals/session.js +2 -2
  100. package/dist/src/evals/types.d.ts +16 -0
  101. package/dist/src/eve-channel/index.js +1 -1
  102. package/dist/src/execution/agent-sessions/context.d.ts +4 -2
  103. package/dist/src/execution/agent-sessions/context.js +1 -1
  104. package/dist/src/execution/agent-sessions/steps.js +1 -1
  105. package/dist/src/execution/cancelled-model-call-batch.js +1 -1
  106. package/dist/src/execution/coordination-dispatch-shared.d.ts +6 -4
  107. package/dist/src/execution/coordination-dispatch-shared.js +1 -1
  108. package/dist/src/execution/create-session-step.d.ts +4 -2
  109. package/dist/src/execution/create-session-step.js +1 -1
  110. package/dist/src/execution/durable-session-store.d.ts +10 -4
  111. package/dist/src/execution/durable-session-store.js +1 -1
  112. package/dist/src/execution/dynamic-workflow/tool.js +1 -1
  113. package/dist/src/execution/legacy-session/completion-step.d.ts +2 -0
  114. package/dist/src/execution/legacy-session/completion-step.js +1 -1
  115. package/dist/src/execution/legacy-session/interrupt-step.js +1 -1
  116. package/dist/src/execution/legacy-session/prepare-step.d.ts +1 -0
  117. package/dist/src/execution/legacy-session/prepare-step.js +1 -1
  118. package/dist/src/execution/legacy-session/snapshot.d.ts +8 -4
  119. package/dist/src/execution/legacy-session/snapshot.js +1 -1
  120. package/dist/src/execution/legacy-session/turn-workflow.js +1 -1
  121. package/dist/src/execution/proxied-deliver-step.js +1 -1
  122. package/dist/src/execution/publish-session-events.d.ts +27 -7
  123. package/dist/src/execution/publish-session-events.js +1 -1
  124. package/dist/src/execution/reconcile-session-continuation-token.d.ts +2 -2
  125. package/dist/src/execution/runtime-context.js +1 -1
  126. package/dist/src/execution/session/active-turn.d.ts +97 -0
  127. package/dist/src/execution/session/active-turn.js +1 -0
  128. package/dist/src/execution/session/entry.js +1 -1
  129. package/dist/src/execution/session/finalization.js +1 -1
  130. package/dist/src/execution/session/handoff.d.ts +5 -3
  131. package/dist/src/execution/session/handoff.js +1 -1
  132. package/dist/src/execution/session/input-queue.d.ts +19 -13
  133. package/dist/src/execution/session/input-queue.js +1 -1
  134. package/dist/src/execution/session/next-input.d.ts +2 -10
  135. package/dist/src/execution/session/next-input.js +1 -1
  136. package/dist/src/execution/session/program.d.ts +2 -0
  137. package/dist/src/execution/session/program.js +1 -1
  138. package/dist/src/execution/session/state-cursor.d.ts +22 -16
  139. package/dist/src/execution/session/state-cursor.js +1 -1
  140. package/dist/src/execution/session/state-delta.d.ts +8 -1
  141. package/dist/src/execution/session/state-delta.js +1 -1
  142. package/dist/src/execution/session/turn-event-handler.js +1 -1
  143. package/dist/src/execution/session/turn-step-result.js +1 -1
  144. package/dist/src/execution/session/turn-step-types.d.ts +13 -4
  145. package/dist/src/execution/session/turn-step.js +1 -1
  146. package/dist/src/execution/session/turn-waiting-step.js +1 -1
  147. package/dist/src/execution/session/turn.d.ts +8 -1
  148. package/dist/src/execution/session/turn.js +1 -1
  149. package/dist/src/execution/session.d.ts +5 -5
  150. package/dist/src/execution/session.js +2 -2
  151. package/dist/src/execution/settle-cancelled-turn-step.d.ts +5 -4
  152. package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
  153. package/dist/src/execution/tasks/start.d.ts +2 -2
  154. package/dist/src/execution/tasks/task-id-input.d.ts +1 -1
  155. package/dist/src/execution/tasks/task-id-input.js +1 -1
  156. package/dist/src/execution/terminal-session-completion-step.d.ts +2 -0
  157. package/dist/src/execution/terminal-session-completion-step.js +1 -1
  158. package/dist/src/execution/terminal-session-failure-step.d.ts +2 -0
  159. package/dist/src/execution/terminal-session-failure-step.js +1 -1
  160. package/dist/src/execution/tools/agent-router-workflow.js +1 -1
  161. package/dist/src/execution/tools/connection-target.d.ts +5 -0
  162. package/dist/src/execution/tools/connection-target.js +1 -1
  163. package/dist/src/execution/tools/connection-tools.js +2 -2
  164. package/dist/src/execution/tools/workflow/start.d.ts +3 -3
  165. package/dist/src/harness/authorization.d.ts +15 -2
  166. package/dist/src/harness/authorization.js +1 -1
  167. package/dist/src/harness/cancelled-turn-emission.d.ts +2 -1
  168. package/dist/src/harness/cancelled-turn-emission.js +1 -1
  169. package/dist/src/harness/coordination.d.ts +5 -3
  170. package/dist/src/harness/emission.d.ts +5 -2
  171. package/dist/src/harness/emission.js +1 -1
  172. package/dist/src/harness/held-requests.d.ts +18 -0
  173. package/dist/src/harness/held-requests.js +1 -0
  174. package/dist/src/harness/hitl/approval-input-requests.d.ts +16 -0
  175. package/dist/src/harness/hitl/approval-input-requests.js +1 -1
  176. package/dist/src/harness/input-extraction.js +1 -1
  177. package/dist/src/harness/input-requests.d.ts +0 -4
  178. package/dist/src/harness/input-requests.js +1 -1
  179. package/dist/src/harness/model-call-error.js +1 -1
  180. package/dist/src/harness/proxy-input-requests.d.ts +4 -4
  181. package/dist/src/harness/session-limit-enforcement.js +1 -1
  182. package/dist/src/harness/stale-input-responses.js +1 -1
  183. package/dist/src/harness/tool-loop.js +2 -2
  184. package/dist/src/harness/turn-tag-state.d.ts +2 -0
  185. package/dist/src/harness/turn-tag-state.js +1 -1
  186. package/dist/src/harness/types.d.ts +23 -11
  187. package/dist/src/instrumentation/channel-delivery.d.ts +1 -0
  188. package/dist/src/instrumentation/channel-delivery.js +1 -1
  189. package/dist/src/instrumentation/lifecycle.d.ts +4 -0
  190. package/dist/src/instrumentation/memory.d.ts +2 -0
  191. package/dist/src/instrumentation/memory.js +1 -1
  192. package/dist/src/instrumentation/native-events.d.ts +1 -0
  193. package/dist/src/instrumentation/native-events.js +1 -1
  194. package/dist/src/instrumentation/runtime.d.ts +4 -3
  195. package/dist/src/instrumentation/runtime.js +1 -1
  196. package/dist/src/instrumentation/session-init.js +1 -1
  197. package/dist/src/internal/application/package.js +1 -1
  198. package/dist/src/internal/authored-module-loader.d.ts +14 -6
  199. package/dist/src/internal/authored-module-loader.js +1 -1
  200. package/dist/src/internal/authored-package-boundary.d.ts +1 -1
  201. package/dist/src/internal/authored-package-boundary.js +1 -1
  202. package/dist/src/internal/bundler/extension-mount-plugin.js +1 -1
  203. package/dist/src/internal/workflow-bundle/dynamic-remote-agent-transform.js +1 -1
  204. package/dist/src/internal/workflow-bundle/dynamic-tool-ast-references.d.ts +27 -1
  205. package/dist/src/internal/workflow-bundle/dynamic-tool-ast-references.js +1 -1
  206. package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +2 -2
  207. package/dist/src/protocol/message.d.ts +41 -3
  208. package/dist/src/protocol/message.js +2 -2
  209. package/dist/src/public/channels/slack/action-status.d.ts +2 -2
  210. package/dist/src/public/channels/slack/action-status.js +1 -1
  211. package/dist/src/public/channels/slack/approval-cards.d.ts +15 -0
  212. package/dist/src/public/channels/slack/approval-cards.js +2 -0
  213. package/dist/src/public/channels/slack/auth.d.ts +2 -0
  214. package/dist/src/public/channels/slack/auth.js +1 -1
  215. package/dist/src/public/channels/slack/connections.d.ts +15 -11
  216. package/dist/src/public/channels/slack/connections.js +1 -1
  217. package/dist/src/public/channels/slack/defaults.d.ts +1 -15
  218. package/dist/src/public/channels/slack/defaults.js +3 -4
  219. package/dist/src/public/channels/slack/hitl.js +1 -1
  220. package/dist/src/public/channels/slack/inbound.d.ts +10 -2
  221. package/dist/src/public/channels/slack/inbound.js +1 -1
  222. package/dist/src/public/channels/slack/index.d.ts +2 -0
  223. package/dist/src/public/channels/slack/index.js +1 -1
  224. package/dist/src/public/channels/slack/input-response.js +1 -1
  225. package/dist/src/public/channels/slack/interaction-cards.js +1 -1
  226. package/dist/src/public/channels/slack/interactions.js +1 -1
  227. package/dist/src/public/channels/slack/limits.d.ts +5 -3
  228. package/dist/src/public/channels/slack/private-approval-delivery.js +1 -1
  229. package/dist/src/public/channels/slack/renderers.d.ts +1 -1
  230. package/dist/src/public/channels/slack/renderers.js +1 -1
  231. package/dist/src/public/channels/slack/reply-delivery.d.ts +72 -0
  232. package/dist/src/public/channels/slack/reply-delivery.js +1 -0
  233. package/dist/src/public/channels/slack/sign-in-cancel.d.ts +20 -0
  234. package/dist/src/public/channels/slack/sign-in-cancel.js +1 -0
  235. package/dist/src/public/channels/slack/slackChannel.d.ts +15 -0
  236. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  237. package/dist/src/public/channels/slack/task-card.js +1 -1
  238. package/dist/src/public/channels/teams/defaults.d.ts +1 -1
  239. package/dist/src/public/channels/teams/defaults.js +2 -2
  240. package/dist/src/public/definitions/channel.d.ts +1 -0
  241. package/dist/src/public/definitions/channel.js +1 -1
  242. package/dist/src/public/next/index.js +1 -1
  243. package/dist/src/public/next/server.d.ts +2 -0
  244. package/dist/src/public/next/server.js +1 -2
  245. package/dist/src/public/nuxt/module.d.ts +6 -0
  246. package/dist/src/public/nuxt/module.js +1 -1
  247. package/dist/src/react/index.d.ts +3 -0
  248. package/dist/src/react/index.js +1 -1
  249. package/dist/src/react/use-eve-agent.d.ts +7 -5
  250. package/dist/src/react/use-eve-agent.js +1 -1
  251. package/dist/src/runtime/connections/scoped-authorization.d.ts +2 -0
  252. package/dist/src/runtime/connections/scoped-authorization.js +1 -1
  253. package/dist/src/setup/boxes/deploy-project.js +1 -1
  254. package/dist/src/setup/integrations/web/setup.js +6 -2
  255. package/dist/src/setup/scaffold/create/project.js +1 -1
  256. package/dist/src/setup/scaffold/create/web-template.d.ts +2 -2
  257. package/dist/src/setup/scaffold/create/web-template.js +28 -9
  258. package/dist/src/setup/vercel-project-framework.js +1 -1
  259. package/dist/src/shared/display-name.d.ts +15 -0
  260. package/dist/src/shared/display-name.js +1 -0
  261. package/dist/src/shared/framework-eve-server.d.ts +43 -0
  262. package/dist/src/shared/framework-eve-server.js +2 -0
  263. package/dist/src/shared/token-usage.d.ts +2 -0
  264. package/dist/src/shared/token-usage.js +1 -1
  265. package/dist/src/shared/trace-root.d.ts +8 -0
  266. package/dist/src/shared/trace-root.js +1 -0
  267. package/dist/src/subagents/hitl-proxy.d.ts +3 -3
  268. package/dist/src/subagents/hitl-proxy.js +1 -1
  269. package/dist/src/subagents/invocation.d.ts +3 -1
  270. package/dist/src/subagents/tool.js +1 -1
  271. package/dist/src/svelte/index.d.ts +3 -0
  272. package/dist/src/svelte/index.js +2 -2
  273. package/dist/src/svelte/use-eve-agent.d.ts +7 -4
  274. package/dist/src/svelte/use-eve-agent.js +1 -1
  275. package/dist/src/tools/provided/ask-question-workflow.js +1 -1
  276. package/dist/src/tools/provided/load-skill.js +1 -1
  277. package/dist/src/tools/provided/sleep-workflow.js +1 -1
  278. package/dist/src/tracing/agent-action-instrumentation.js +1 -1
  279. package/dist/src/tracing/agent-approval-instrumentation.js +1 -1
  280. package/dist/src/tracing/agent-memory-instrumentation.js +1 -1
  281. package/dist/src/tracing/agent-otel-attributes.d.ts +6 -0
  282. package/dist/src/tracing/agent-otel-attributes.js +1 -1
  283. package/dist/src/tracing/agent-otel-provider.js +2 -2
  284. package/dist/src/tracing/agent-otel-runtime-context.d.ts +1 -1
  285. package/dist/src/tracing/agent-otel-runtime-context.js +1 -1
  286. package/dist/src/tracing/agent-otel-session-context.js +1 -1
  287. package/dist/src/tracing/agent-span-contract.js +1 -1
  288. package/dist/src/tracing/agent-tool-instrumentation.js +1 -1
  289. package/dist/src/tracing/agent-trace-context-codec.d.ts +4 -0
  290. package/dist/src/tracing/agent-trace-context-codec.js +1 -1
  291. package/dist/src/tracing/agent-trace-span-processor.js +1 -1
  292. package/dist/src/tracing/agent-trace-state.d.ts +3 -0
  293. package/dist/src/tracing/conversation-context.d.ts +10 -0
  294. package/dist/src/tracing/conversation-context.js +1 -1
  295. package/dist/src/tracing/otel-registration.js +1 -1
  296. package/dist/src/vue/index.d.ts +3 -0
  297. package/dist/src/vue/index.js +2 -2
  298. package/dist/src/vue/use-eve-agent.d.ts +7 -3
  299. package/dist/src/vue/use-eve-agent.js +1 -1
  300. package/docs/channels/slack.mdx +60 -13
  301. package/docs/concepts/built-in-tools.md +3 -2
  302. package/docs/concepts/sessions-runs-and-streaming.md +4 -4
  303. package/docs/connections/overview.mdx +9 -3
  304. package/docs/evals/reporters.mdx +4 -0
  305. package/docs/extensions.md +11 -0
  306. package/docs/guides/client/streaming.mdx +7 -6
  307. package/docs/guides/deployment/vercel.mdx +2 -1
  308. package/docs/guides/dev-tui.md +15 -15
  309. package/docs/guides/dynamic-capabilities.md +1 -1
  310. package/docs/guides/frontend/nuxt.mdx +24 -4
  311. package/docs/guides/frontend/overview.mdx +44 -38
  312. package/docs/guides/frontend/use-eve-agent-svelte.mdx +4 -10
  313. package/docs/guides/frontend/use-eve-agent-vue.mdx +4 -10
  314. package/docs/guides/instrumentation/otel.mdx +24 -6
  315. package/docs/guides/remote-agents.md +26 -8
  316. package/docs/reference/cli.md +4 -4
  317. package/docs/tools/human-in-the-loop.md +4 -4
  318. package/docs/tools/overview.mdx +1 -1
  319. package/docs/tools/tasks.md +8 -8
  320. package/package.json +1 -1
  321. package/dist/src/cli/dev/tui/steering-stream.d.ts +0 -15
  322. package/dist/src/cli/dev/tui/steering-stream.js +0 -1
  323. package/dist/src/cli/dev/tui/subagent-pump.d.ts +0 -134
  324. package/dist/src/cli/dev/tui/subagent-pump.js +0 -1
  325. package/dist/src/public/nuxt/dev-server.d.ts +0 -25
  326. package/dist/src/public/nuxt/dev-server.js +0 -1
@@ -685,28 +685,22 @@ function isTurnFailureEvent(event) {
685
685
  //#endregion
686
686
  //#region src/client/session-utils.ts
687
687
  function summarizeTurnEvents(events) {
688
+ const segment = new TurnSegment();
688
689
  let boundary;
689
690
  let failure;
690
691
  let message;
691
- const inputRequests = [];
692
- const pendingInputRequests = /* @__PURE__ */ new Set();
693
- const pendingAuthorizations = /* @__PURE__ */ new Map();
694
692
  for (const event of events) {
695
- updatePendingInputRequests(pendingInputRequests, event);
696
- if (isTurnSegmentBoundary(event, pendingInputRequests)) boundary = event;
693
+ if (segment.observe(event)) boundary = event;
697
694
  if (isTurnFailureEvent(event)) failure = event;
698
695
  if (isFinalMessageCompleted(event)) message = event.data.message ?? void 0;
699
696
  if (event.type === "turn.waiting") message = void 0;
700
- if (event.type === "input.requested") inputRequests.push(...event.data.requests);
701
- if (event.type === "authorization.required") pendingAuthorizations.set(event.data.name, event.data);
702
- if (event.type === "authorization.completed") pendingAuthorizations.delete(event.data.name);
703
697
  }
704
698
  return {
705
699
  boundary,
706
700
  failure,
707
- inputRequests,
701
+ inputRequests: segment.inputRequests,
708
702
  message,
709
- pendingAuthorizations: [...pendingAuthorizations.values()],
703
+ pendingAuthorizations: segment.pendingAuthorizations,
710
704
  status: summarizeBoundaryStatus(boundary)
711
705
  };
712
706
  }
@@ -715,20 +709,50 @@ function summarizeBoundaryStatus(boundary) {
715
709
  if (boundary?.type === "session.failed") return "failed";
716
710
  return "completed";
717
711
  }
718
- function isTurnSegmentBoundary(event, pendingInputRequests) {
719
- if (event.type === "turn.waiting") return pendingInputRequests.size > 0;
720
- return isCurrentTurnBoundaryEvent(event);
721
- }
722
- function updatePendingInputRequests(pending, event) {
723
- if (event.type === "input.requested") for (const request of event.data.requests) pending.add(request.requestId);
724
- else if (event.type === "input.resolved") for (const resolution of event.data.resolutions) pending.delete(resolution.requestId);
712
+ function endsTurnSegment(event, open) {
713
+ if (event.type === "turn.waiting") return open.requests || event.data.on === "input" && !open.callbacks;
714
+ return isCurrentTurnBoundaryEvent(event) && (event.type !== "session.waiting" || !open.callbacks);
725
715
  }
716
+ var TurnSegment = class {
717
+ #authorizations = /* @__PURE__ */ new Map();
718
+ #followCallbacks;
719
+ #requests = /* @__PURE__ */ new Map();
720
+ constructor(options = {}) {
721
+ this.#followCallbacks = options.followCallbacks === true;
722
+ }
723
+ get inputRequests() {
724
+ return [...this.#requests.values()];
725
+ }
726
+ get pendingAuthorizations() {
727
+ return [...this.#authorizations.values()];
728
+ }
729
+ observe(event) {
730
+ switch (event.type) {
731
+ case "input.requested":
732
+ for (const request of event.data.requests) this.#requests.set(request.requestId, request);
733
+ break;
734
+ case "approval.settled":
735
+ this.#requests.delete(event.data.requestId);
736
+ break;
737
+ case "input.resolved":
738
+ for (const resolution of event.data.resolutions) this.#requests.delete(resolution.requestId);
739
+ break;
740
+ case "authorization.required":
741
+ this.#authorizations.set(authorizationKey(event.data), event.data);
742
+ break;
743
+ case "authorization.completed": this.#authorizations.delete(authorizationKey(event.data));
744
+ }
745
+ return endsTurnSegment(event, {
746
+ callbacks: this.#followCallbacks && [...this.#authorizations.values()].some((authorization) => authorization.webhookUrl !== void 0),
747
+ requests: this.#requests.size > 0
748
+ });
749
+ }
750
+ };
726
751
  function isFinalMessageCompleted(event) {
727
752
  return event.type === "message.completed" && event.data.finishReason !== "tool-calls";
728
753
  }
729
- function updatePendingAuthorizations(pending, event) {
730
- if (event.type === "authorization.required" && event.data.webhookUrl !== void 0) pending.add(event.data.name);
731
- else if (event.type === "authorization.completed") pending.delete(event.data.name);
754
+ function authorizationKey(data) {
755
+ return data.attemptId === void 0 ? `name:${data.name}` : `attempt:${data.attemptId}`;
732
756
  }
733
757
 
734
758
  //#endregion
@@ -1891,8 +1915,7 @@ var ClientSession = class ClientSession {
1891
1915
  let eventCount = 0;
1892
1916
  let started = deliveryId === void 0;
1893
1917
  let reachedBoundary = false;
1894
- const pendingAuthorizations = /* @__PURE__ */ new Set();
1895
- const pendingInputRequests = /* @__PURE__ */ new Set();
1918
+ const segment = new TurnSegment({ followCallbacks: true });
1896
1919
  try {
1897
1920
  for await (const event of source ?? this.#readStream({
1898
1921
  headers: input.headers,
@@ -1910,9 +1933,7 @@ var ClientSession = class ClientSession {
1910
1933
  if (!terminal && event.meta?.deliveryIds !== void 0 && !matches) continue;
1911
1934
  started = true;
1912
1935
  }
1913
- updatePendingAuthorizations(pendingAuthorizations, event);
1914
- updatePendingInputRequests(pendingInputRequests, event);
1915
- reachedBoundary = isTurnSegmentBoundary(event, pendingInputRequests) && (event.type !== "session.waiting" || pendingAuthorizations.size === 0);
1936
+ reachedBoundary = segment.observe(event);
1916
1937
  yield event;
1917
1938
  if (reachedBoundary) break;
1918
1939
  }
@@ -2177,117 +2198,6 @@ function withRedirectPolicy(init, redirect) {
2177
2198
  };
2178
2199
  }
2179
2200
 
2180
- //#endregion
2181
- //#region src/client/session-event-stream.ts
2182
- var SessionEventStream = class {
2183
- #controller = new AbortController();
2184
- #readers = /* @__PURE__ */ new Set();
2185
- #caughtUp = Promise.withResolvers();
2186
- caughtUp = this.#caughtUp.promise;
2187
- #ended = false;
2188
- #error;
2189
- #headers;
2190
- #reconnectPolicy;
2191
- constructor(session, options) {
2192
- this.setOptions(options);
2193
- this.caughtUp.catch(() => {});
2194
- if (!options.catchUp) this.#caughtUp.resolve();
2195
- (async () => {
2196
- try {
2197
- for await (const event of followClientSession(session, {
2198
- signal: this.#controller.signal,
2199
- resolveHeaders: () => this.#headers,
2200
- resolveReconnectPolicy: () => this.#reconnectPolicy,
2201
- startIndex: options.startIndex,
2202
- onCaughtUp: options.catchUp ? () => this.#caughtUp.resolve() : void 0
2203
- })) {
2204
- if (this.#controller.signal.aborted) return;
2205
- options.onEvent(event);
2206
- for (const reader of this.#readers) reader.push(event);
2207
- if (event.type === "session.completed" || event.type === "session.failed") break;
2208
- }
2209
- this.#caughtUp.resolve();
2210
- this.#finish();
2211
- } catch (error) {
2212
- this.#caughtUp.reject(error);
2213
- this.#finish(error);
2214
- if (!this.#controller.signal.aborted) options.onError(error);
2215
- }
2216
- })();
2217
- }
2218
- subscribe(signal) {
2219
- const reader = new SessionEventReader(() => this.#readers.delete(reader), signal);
2220
- if (this.#ended) reader.end(this.#error);
2221
- else this.#readers.add(reader);
2222
- return reader;
2223
- }
2224
- get ended() {
2225
- return this.#ended;
2226
- }
2227
- setOptions(options) {
2228
- if ("headers" in options) this.#headers = options.headers;
2229
- if ("streamReconnectPolicy" in options) this.#reconnectPolicy = options.streamReconnectPolicy;
2230
- }
2231
- close() {
2232
- const error = new DOMException("Session stream was detached.", "AbortError");
2233
- this.#controller.abort(error);
2234
- this.#caughtUp.reject(error);
2235
- this.#finish(error);
2236
- }
2237
- #finish(error) {
2238
- if (this.#ended) return;
2239
- this.#ended = true;
2240
- this.#error = error;
2241
- for (const reader of this.#readers) reader.end(error);
2242
- }
2243
- };
2244
- var SessionEventReader = class {
2245
- #events = [];
2246
- #wake = Promise.withResolvers();
2247
- #ended = false;
2248
- #error;
2249
- #dispose;
2250
- constructor(unsubscribe, signal) {
2251
- const abort = () => this.end(signal?.reason);
2252
- signal?.addEventListener("abort", abort, { once: true });
2253
- this.#dispose = () => {
2254
- signal?.removeEventListener("abort", abort);
2255
- unsubscribe();
2256
- };
2257
- if (signal?.aborted) abort();
2258
- }
2259
- push(event) {
2260
- if (this.#ended) return;
2261
- this.#events.push(event);
2262
- this.#wake.resolve();
2263
- }
2264
- end(error) {
2265
- if (this.#ended) return;
2266
- this.#ended = true;
2267
- this.#error = error;
2268
- this.#wake.resolve();
2269
- }
2270
- [Symbol.dispose]() {
2271
- this.end();
2272
- this.#events = [];
2273
- this.#dispose();
2274
- }
2275
- discard() {
2276
- this.#events = [];
2277
- }
2278
- async *[Symbol.asyncIterator]() {
2279
- for (;;) {
2280
- while (this.#events.length > 0) yield this.#events.shift();
2281
- if (this.#ended) {
2282
- if (this.#error !== void 0) throw this.#error;
2283
- return;
2284
- }
2285
- this.#wake = Promise.withResolvers();
2286
- await this.#wake.promise;
2287
- }
2288
- }
2289
- };
2290
-
2291
2201
  //#endregion
2292
2202
  //#region src/client/eve-agent-projection.ts
2293
2203
  var EveAgentProjection = class {
@@ -2296,18 +2206,21 @@ var EveAgentProjection = class {
2296
2206
  #data;
2297
2207
  constructor(reducer, events) {
2298
2208
  this.#reducer = reducer;
2299
- this.#events = events;
2209
+ this.#events = [...events];
2300
2210
  this.#data = this.#reduce();
2301
2211
  }
2302
2212
  get data() {
2303
2213
  return this.#data;
2304
2214
  }
2215
+ get reducer() {
2216
+ return this.#reducer;
2217
+ }
2305
2218
  reset() {
2306
2219
  this.#events = [];
2307
2220
  this.#data = this.#reducer.initial();
2308
2221
  }
2309
2222
  append(event) {
2310
- this.#events = [...this.#events, event];
2223
+ this.#events.push(event);
2311
2224
  this.#data = this.#reducer.reduce(this.#data, event);
2312
2225
  }
2313
2226
  remove(predicate) {
@@ -2316,7 +2229,8 @@ var EveAgentProjection = class {
2316
2229
  }
2317
2230
  replace(predicate, replacement) {
2318
2231
  const index = this.#events.findIndex(predicate);
2319
- this.#events = index === -1 ? [...this.#events, replacement] : this.#events.map((event, i) => i === index ? replacement : event);
2232
+ if (index === -1) this.#events.push(replacement);
2233
+ else this.#events[index] = replacement;
2320
2234
  this.#data = this.#reduce();
2321
2235
  }
2322
2236
  #reduce() {
@@ -2326,18 +2240,68 @@ var EveAgentProjection = class {
2326
2240
  }
2327
2241
  };
2328
2242
 
2243
+ //#endregion
2244
+ //#region src/client/conversation-state.ts
2245
+ function openConversationInputs(state) {
2246
+ return Object.values(state.inputs).filter((input) => input.status === "open");
2247
+ }
2248
+ function conversationAuthorizations(state) {
2249
+ return state.messages.flatMap((message) => message.role === "assistant" ? message.parts.filter((part) => part.type === "authorization") : []);
2250
+ }
2251
+ function hasPendingAuthorizations(state) {
2252
+ return conversationAuthorizations(state).some((part) => part.state === "required" && part.awaitsCallback === true);
2253
+ }
2254
+ function agentToolTask(state, agent) {
2255
+ const task = agent.taskId === void 0 ? void 0 : state.tasks[agent.taskId];
2256
+ return task?.kind === "agent" ? task : void 0;
2257
+ }
2258
+ function isAgentSessionCaughtUp(state, agent) {
2259
+ if (agent.observation.status !== "following" && agent.observation.status !== "idle") return false;
2260
+ const task = agentToolTask(state, agent);
2261
+ if (task === void 0) return false;
2262
+ const calls = Object.values(task.calls);
2263
+ if (calls.some((call) => call.status === "working")) return false;
2264
+ const child = agent.observation.conversation;
2265
+ if (child.activeTurnId !== void 0) return false;
2266
+ if (Object.values(child.inputs).some((input) => input.status !== "settled")) return false;
2267
+ if (hasPendingAuthorizations(child)) return false;
2268
+ return child.messages.filter((message) => message.role === "user").length >= calls.filter((call) => call.status === "completed").length;
2269
+ }
2270
+
2329
2271
  //#endregion
2330
2272
  //#region src/client/eve-agent-store-helpers.ts
2331
- function isSettledSessionTail(events) {
2273
+ function activeTurnForOptimisticFollowUp(events) {
2274
+ const lastTurn = events.findLast((event) => event.type === "turn.started" || event.type === "turn.completed" || event.type === "turn.failed" || event.type === "turn.cancelled" || isCurrentTurnBoundaryEvent(event));
2275
+ return lastTurn?.type === "turn.started" ? lastTurn.data.turnId : void 0;
2276
+ }
2277
+ function isResponseBoundary(event, conversation) {
2278
+ return endsTurnSegment(event, {
2279
+ callbacks: hasPendingAuthorizations(conversation),
2280
+ requests: Object.values(conversation.inputs).some((input) => input.status !== "settled")
2281
+ });
2282
+ }
2283
+ function settledStatus(error, conversation) {
2284
+ if (error !== void 0) return "error";
2285
+ return conversation.activeTurnId === void 0 ? "ready" : "streaming";
2286
+ }
2287
+ function isSettledSessionTail(events, conversation) {
2332
2288
  const tail = events.at(-1);
2333
- if (tail === void 0) return false;
2334
- const pendingAuthorizations = /* @__PURE__ */ new Set();
2335
- const pendingInputRequests = /* @__PURE__ */ new Set();
2336
- for (const event of events) {
2337
- updatePendingAuthorizations(pendingAuthorizations, event);
2338
- updatePendingInputRequests(pendingInputRequests, event);
2289
+ return tail !== void 0 && isResponseBoundary(tail, conversation);
2290
+ }
2291
+ function assertAnswerable(input, conversation) {
2292
+ for (const { requestId } of input.inputResponses ?? []) {
2293
+ const status = conversation.inputs[requestId]?.status;
2294
+ if (status !== void 0 && status !== "open") throw new Error(`Input request ${requestId} was already answered.`);
2339
2295
  }
2340
- return isTurnSegmentBoundary(tail, pendingInputRequests) && (tail.type !== "session.waiting" || pendingAuthorizations.size === 0);
2296
+ }
2297
+ function assertInFlightFollowUp(input) {
2298
+ if (input.inputResponses !== void 0) return;
2299
+ if (input.message === void 0 || input.turnPolicy !== "steer") throw new Error("eve session is already processing a turn. Send a message with turnPolicy: \"steer\" to guide it at the next boundary, or answer an open input request.");
2300
+ }
2301
+ function validateFollowUp(input) {
2302
+ assertExclusiveTurnInput(input);
2303
+ assertInFlightFollowUp(input);
2304
+ return input;
2341
2305
  }
2342
2306
  function assertExclusiveTurnInput(input) {
2343
2307
  if (input.message !== void 0 === (input.inputResponses !== void 0)) throw new Error("A turn requires exactly one of message or inputResponses.");
@@ -2386,16 +2350,25 @@ function createActiveTurn(cancel) {
2386
2350
  };
2387
2351
  return turn;
2388
2352
  }
2353
+ function countFollowUpDeliveries(turn, reconciliation) {
2354
+ let followed = 0;
2355
+ for (const id of reconciliation.ids) if (turn.followUpSubmissionIds.delete(id)) followed += 1;
2356
+ if (followed === 0) return;
2357
+ if (reconciliation.alreadyProjected) turn.receivedFollowUps += followed;
2358
+ else {
2359
+ const previous = turn.receivedFollowUpEvents.get(reconciliation.event) ?? 0;
2360
+ turn.receivedFollowUpEvents.set(reconciliation.event, previous + followed);
2361
+ }
2362
+ }
2389
2363
  async function followSteeredTurns(turn, events, isActive) {
2390
2364
  while (turn.followUpDispatches.size > 0) await Promise.allSettled(turn.followUpDispatches);
2391
2365
  if (turn.receivedFollowUps >= turn.acceptedFollowUps) return;
2392
- const pendingInputRequests = /* @__PURE__ */ new Set();
2366
+ const segment = new TurnSegment({ followCallbacks: true });
2393
2367
  for await (const event of events) {
2394
2368
  if (!isActive()) return;
2395
2369
  turn.receivedFollowUps += turn.receivedFollowUpEvents.get(event) ?? 0;
2396
2370
  turn.receivedFollowUpEvents.delete(event);
2397
- updatePendingInputRequests(pendingInputRequests, event);
2398
- if (isTurnSegmentBoundary(event, pendingInputRequests)) {
2371
+ if (segment.observe(event)) {
2399
2372
  while (turn.followUpDispatches.size > 0) await Promise.allSettled(turn.followUpDispatches);
2400
2373
  if (turn.receivedFollowUps >= turn.acceptedFollowUps) return;
2401
2374
  }
@@ -2418,43 +2391,52 @@ async function waitWithSignal(promise, signal) {
2418
2391
  //#region src/client/optimistic-message-submissions.ts
2419
2392
  var OptimisticMessageSubmissions = class {
2420
2393
  #optimistic;
2421
- #projection;
2394
+ #projections;
2422
2395
  #pending = [];
2423
- constructor(projection, optimistic) {
2424
- this.#projection = projection;
2396
+ constructor(projections, optimistic) {
2397
+ this.#projections = projections;
2425
2398
  this.#optimistic = optimistic;
2426
2399
  }
2427
2400
  reset() {
2428
2401
  this.#pending = [];
2429
2402
  }
2430
- submit(input, eventStartIndex) {
2403
+ submit(input, eventStartIndex, turnId) {
2431
2404
  if (input.message === void 0) return void 0;
2432
2405
  const pending = {
2433
2406
  createdAt: Date.now(),
2434
2407
  eventStartIndex,
2435
2408
  id: createSubmissionId(),
2436
2409
  message: summarizeUserContent(input.message),
2410
+ turnId,
2437
2411
  requiresDeliveryId: true
2438
2412
  };
2439
2413
  this.#pending = [...this.#pending, pending];
2440
- if (this.#optimistic) this.#projection.append({
2414
+ if (this.#optimistic) for (const projection of this.#projections) projection.append({
2441
2415
  data: {
2442
2416
  createdAt: pending.createdAt,
2443
2417
  message: pending.message,
2444
- submissionId: pending.id
2418
+ submissionId: pending.id,
2419
+ turnId
2445
2420
  },
2446
2421
  type: "client.message.submitted"
2447
2422
  });
2448
2423
  return pending.id;
2449
2424
  }
2425
+ resubmit(submissionId, input) {
2426
+ const pending = this.#pending.find((candidate) => candidate.id === submissionId);
2427
+ const message = input.message === void 0 ? void 0 : summarizeUserContent(input.message);
2428
+ if (pending?.message === message) return submissionId;
2429
+ if (pending !== void 0) this.#withdraw([pending.id]);
2430
+ return this.submit(input, pending?.eventStartIndex ?? 0, pending?.turnId);
2431
+ }
2450
2432
  apply(event) {
2451
2433
  if (event.type !== "message.received") {
2452
- this.#projection.append(event);
2434
+ for (const projection of this.#projections) projection.append(event);
2453
2435
  return;
2454
2436
  }
2455
2437
  const matching = this.#matching(event);
2456
2438
  if (matching.length === 0) {
2457
- this.#projection.append(event);
2439
+ for (const projection of this.#projections) projection.append(event);
2458
2440
  return;
2459
2441
  }
2460
2442
  return this.#reconcile(matching, event, false);
@@ -2478,12 +2460,13 @@ var OptimisticMessageSubmissions = class {
2478
2460
  const pending = submissionId === void 0 ? this.#pending[0] : this.#pending.find((candidate) => candidate.id === submissionId);
2479
2461
  if (pending === void 0) return;
2480
2462
  this.#pending = this.#pending.filter((candidate) => candidate.id !== pending.id);
2481
- this.#projection.replace((event) => event.type === "client.message.submitted" && event.data.submissionId === pending.id, {
2463
+ for (const projection of this.#projections) projection.replace((event) => event.type === "client.message.submitted" && event.data.submissionId === pending.id, {
2482
2464
  data: {
2483
2465
  createdAt: pending.createdAt,
2484
2466
  error: { message: error.message },
2485
2467
  message: pending.message,
2486
- submissionId: pending.id
2468
+ submissionId: pending.id,
2469
+ turnId: pending.turnId
2487
2470
  },
2488
2471
  type: "client.message.failed"
2489
2472
  });
@@ -2496,1181 +2479,1833 @@ var OptimisticMessageSubmissions = class {
2496
2479
  }
2497
2480
  #reconcile(submissions, event, alreadyProjected) {
2498
2481
  const ids = submissions.map((pending) => pending.id);
2499
- const idSet = new Set(ids);
2500
- this.#pending = this.#pending.filter((pending) => !idSet.has(pending.id));
2501
- if (alreadyProjected) this.#projection.remove((candidate) => candidate.type === "client.message.submitted" && idSet.has(candidate.data.submissionId));
2502
- else {
2503
- this.#projection.replace((candidate) => candidate.type === "client.message.submitted" && candidate.data.submissionId === ids[0], event);
2504
- this.#projection.remove((candidate) => candidate.type === "client.message.submitted" && idSet.has(candidate.data.submissionId));
2505
- }
2482
+ this.#withdraw(ids);
2483
+ if (!alreadyProjected) for (const projection of this.#projections) projection.append(event);
2506
2484
  return {
2507
2485
  alreadyProjected,
2508
2486
  event,
2509
2487
  ids
2510
2488
  };
2511
2489
  }
2490
+ #withdraw(ids) {
2491
+ const idSet = new Set(ids);
2492
+ this.#pending = this.#pending.filter((pending) => !idSet.has(pending.id));
2493
+ for (const projection of this.#projections) projection.remove((candidate) => candidate.type === "client.message.submitted" && idSet.has(candidate.data.submissionId));
2494
+ }
2512
2495
  };
2513
2496
 
2514
2497
  //#endregion
2515
- //#region src/protocol/event-dedupe.ts
2516
- function createEventDeduper() {
2517
- const seen = /* @__PURE__ */ new Set();
2518
- return {
2519
- admit(event) {
2520
- const id = event.meta?.id;
2521
- if (id === void 0) return true;
2522
- if (seen.has(id)) return false;
2523
- seen.add(id);
2524
- return true;
2525
- },
2526
- get size() {
2527
- return seen.size;
2498
+ //#region src/client/agent-stream-follower.ts
2499
+ const agentStreamReconnectPolicy = {
2500
+ streamIdleReconnectPolicy: { maxAttempts: Infinity },
2501
+ streamOpenReconnectPolicy: { maxAttempts: Infinity }
2502
+ };
2503
+ var AgentStreamFollower = class {
2504
+ #options;
2505
+ #started = /* @__PURE__ */ new Map();
2506
+ #controllers = /* @__PURE__ */ new Map();
2507
+ #failed = /* @__PURE__ */ new Set();
2508
+ #disposed = false;
2509
+ constructor(options) {
2510
+ this.#options = options;
2511
+ }
2512
+ acceptParentEvent(event) {
2513
+ if (event.type === "agent.started") this.#started.set(event.data.sessionId, event);
2514
+ }
2515
+ reconcile() {
2516
+ if (this.#disposed) return;
2517
+ const state = this.#options.getState();
2518
+ for (const agent of Object.values(state.agents)) {
2519
+ if (agentToolTask(state, agent) === void 0) continue;
2520
+ const controller = this.#controllers.get(agent.sessionId);
2521
+ const caughtUp = isAgentSessionCaughtUp(state, agent);
2522
+ if (controller !== void 0 && caughtUp) {
2523
+ this.#controllers.delete(agent.sessionId);
2524
+ controller.abort();
2525
+ this.#options.onIdle(agent.sessionId);
2526
+ } else if (controller === void 0 && !caughtUp && !this.#failed.has(agent.sessionId)) this.#follow(agent.sessionId);
2528
2527
  }
2529
- };
2530
- }
2531
-
2532
- //#endregion
2533
- //#region src/client/eve-agent-store.ts
2534
- const detachStore = Symbol("detachEveAgentStore");
2535
- const attachStore = Symbol("attachEveAgentStore");
2536
- var EveAgentStore = class {
2537
- #client;
2538
- #autoPrewarm;
2539
- #attached = false;
2540
- #stream;
2541
- #pendingAuthorizations = /* @__PURE__ */ new Set();
2542
- #pendingInputRequests = /* @__PURE__ */ new Set();
2543
- #externalSession;
2544
- #optimistic;
2545
- #projection;
2546
- #subscribers = /* @__PURE__ */ new Set();
2547
- #seenEvents = createEventDeduper();
2548
- #activeTurn;
2549
- #callbacks = {};
2550
- #error;
2551
- #events;
2552
- #messageSubmissions;
2553
- #prewarmGeneration = 0;
2554
- #prewarmPromise;
2555
- #prewarmController;
2556
- #resumePromise;
2557
- #session;
2558
- #snapshot;
2559
- #status = "ready";
2560
- constructor(init) {
2561
- this.#autoPrewarm = init.prewarm ?? false;
2562
- this.#externalSession = init.session !== void 0;
2563
- this.#client = this.#externalSession ? void 0 : new Client({
2564
- auth: init.auth,
2565
- headers: init.headers,
2566
- host: init.host ?? ""
2567
- });
2568
- const initialEvents = [];
2569
- for (const event of init.initialEvents ?? []) {
2570
- if (this.#seenEvents.admit(event)) initialEvents.push(event);
2571
- this.#trackPendingRequests(event);
2572
- }
2573
- this.#events = initialEvents;
2574
- this.#projection = new EveAgentProjection(init.reducer, this.#events);
2575
- this.#optimistic = init.optimistic ?? true;
2576
- this.#messageSubmissions = new OptimisticMessageSubmissions(this.#projection, this.#optimistic);
2577
- this.#session = init.session ?? (init.initialSession === void 0 ? void 0 : this.#client?.sessions.attach(init.initialSession.sessionId, { streamIndex: init.initialSession.streamIndex }));
2578
- this.#snapshot = this.#createSnapshot();
2579
- }
2580
- get snapshot() {
2581
- return this.#snapshot;
2582
2528
  }
2583
- setCallbacks(callbacks) {
2584
- this.#callbacks = callbacks;
2585
- }
2586
- subscribe(callback) {
2587
- this.#subscribers.add(callback);
2588
- return () => {
2589
- this.#subscribers.delete(callback);
2590
- };
2529
+ abortAll() {
2530
+ this.#disposed = true;
2531
+ for (const controller of this.#controllers.values()) controller.abort();
2532
+ this.#controllers.clear();
2591
2533
  }
2592
- prewarm() {
2593
- if (this.#prewarmPromise !== void 0) return this.#prewarmPromise;
2594
- if (this.#session !== void 0 || this.#externalSession) return Promise.resolve();
2595
- if (this.#activeTurn !== void 0) return this.#activeTurn.response.then((response) => {
2596
- if (response === void 0) throw this.#error ?? new DOMException("Session creation was aborted.", "AbortError");
2597
- });
2598
- const client = this.#client;
2599
- if (client === void 0) return Promise.reject(/* @__PURE__ */ new Error("This eve agent store does not own a session client."));
2600
- const generation = this.#prewarmGeneration;
2534
+ #follow(sessionId) {
2535
+ const started = this.#started.get(sessionId);
2536
+ if (started === void 0) return;
2601
2537
  const controller = new AbortController();
2602
- this.#prewarmController = controller;
2603
- const promise = (async () => {
2538
+ this.#controllers.set(sessionId, controller);
2539
+ this.#options.onFollowing(sessionId);
2540
+ const { cursors } = this.#options;
2541
+ (async () => {
2542
+ let cursor = cursors.get(sessionId) ?? 0;
2604
2543
  try {
2605
- const created = await client.sessions.create({ signal: controller.signal });
2606
- if (generation !== this.#prewarmGeneration) return;
2607
- this.#session = created.session;
2608
- this.#error = void 0;
2609
- if (this.#status === "error") this.#status = "ready";
2610
- this.#callbacks.onSessionChange?.(created.session.state);
2611
- this.#publish();
2612
- this.#ensureStream();
2613
- } catch (error) {
2614
- if (generation === this.#prewarmGeneration && this.#activeTurn === void 0 && this.#error === void 0) {
2615
- this.#error = toError(error);
2616
- this.#status = "error";
2617
- this.#callbacks.onError?.(this.#error);
2618
- this.#publish();
2544
+ for await (const event of this.#options.session.agent(started).stream({
2545
+ signal: controller.signal,
2546
+ startIndex: cursor,
2547
+ streamReconnectPolicy: agentStreamReconnectPolicy
2548
+ })) {
2549
+ if (controller.signal.aborted) return;
2550
+ cursors.set(sessionId, ++cursor);
2551
+ this.#options.onEvent(sessionId, event);
2552
+ this.reconcile();
2619
2553
  }
2620
- throw error;
2621
- }
2554
+ } catch {}
2555
+ if (controller.signal.aborted || this.#controllers.get(sessionId) !== controller) return;
2556
+ this.#controllers.delete(sessionId);
2557
+ this.#failed.add(sessionId);
2558
+ this.#options.onUnavailable(sessionId);
2622
2559
  })();
2623
- this.#prewarmPromise = promise;
2624
- const clear = () => {
2625
- if (this.#prewarmPromise === promise) {
2626
- this.#prewarmPromise = void 0;
2627
- this.#prewarmController = void 0;
2628
- }
2629
- };
2630
- promise.then(clear, clear);
2631
- return promise;
2632
- }
2633
- async send(input) {
2634
- return await this.#submit(input, this.#callbacks.prepareSend);
2635
2560
  }
2636
- async #submit(input, prepareSend) {
2637
- if (this.#activeTurn !== void 0) {
2638
- if (this.#status === "resuming") throw new Error("eve session is resuming.");
2639
- return await this.#sendFollowUp(this.#activeTurn, input, prepareSend);
2640
- }
2641
- const turn = createActiveTurn((turn) => turn.acceptedFollowUps > 0 && this.#session !== void 0 ? this.#session.cancel() : turn.response.then((response) => response === void 0 ? { status: "no_active_turn" } : response.cancel()));
2642
- this.#activeTurn = turn;
2643
- this.#error = void 0;
2644
- this.#status = "submitted";
2645
- this.#publish();
2646
- let reader;
2647
- try {
2648
- const preparedInput = await (prepareSend === void 0 ? input : waitWithSignal(Promise.resolve(prepareSend(input)), createAbortSignal(input.signal, turn.abortController.signal)));
2649
- assertExclusiveTurnInput(preparedInput);
2650
- if (!this.#isActiveTurn(turn)) return;
2651
- const submissionId = this.#messageSubmissions.submit(preparedInput, this.#events.length);
2652
- this.#projectInputResponses(preparedInput);
2653
- this.#publish();
2654
- const turnInput = {
2655
- ...preparedInput,
2656
- signal: createAbortSignal(preparedInput.signal, turn.abortController.signal)
2657
- };
2658
- const dispatched = await this.#dispatchTurn(turnInput);
2659
- const response = dispatched.response;
2660
- reader = dispatched.reader;
2661
- if (!this.#isActiveTurn(turn)) return;
2662
- turn.resolveResponse(response);
2663
- if (this.#handleReconciliation(this.#messageSubmissions.correlate(submissionId, getMessageResponseDeliveryId(response), this.#events))) this.#publish();
2664
- for await (const event of consumeMessageResponse(response, reader)) {
2665
- if (!this.#isActiveTurn(turn)) return;
2666
- turn.receivedFollowUps += turn.receivedFollowUpEvents.get(event) ?? 0;
2667
- turn.receivedFollowUpEvents.delete(event);
2668
- }
2669
- if (!this.#isActiveTurn(turn)) return;
2670
- await followSteeredTurns(turn, reader, () => this.#isActiveTurn(turn));
2671
- if (!this.#isActiveTurn(turn)) return;
2672
- this.#status = this.#error === void 0 ? "ready" : "error";
2673
- } catch (error) {
2674
- if (!this.#isActiveTurn(turn)) return;
2675
- if (isAbortError(error)) {
2676
- this.#status = "ready";
2677
- this.#messageSubmissions.fail(toError(error));
2678
- } else {
2679
- const reported = this.#error !== void 0;
2680
- this.#error ??= toError(error);
2681
- this.#status = "error";
2682
- this.#messageSubmissions.fail(this.#error);
2683
- if (!reported) this.#callbacks.onError?.(this.#error);
2684
- }
2685
- } finally {
2686
- reader?.[Symbol.dispose]();
2687
- this.#finishTurn(turn);
2688
- }
2561
+ };
2562
+
2563
+ //#endregion
2564
+ //#region src/client/authorization-message-parts.ts
2565
+ function createAuthorizationRequiredPart(event) {
2566
+ const displayName = event.data.authorization?.displayName ?? formatAuthorizationDisplayName(event.data.name);
2567
+ const part = {
2568
+ authorization: event.data.authorization,
2569
+ description: normalizeAuthorizationDescription(event.data.description, event.data.name, displayName),
2570
+ displayName,
2571
+ name: event.data.name,
2572
+ state: "required",
2573
+ stepIndex: event.data.stepIndex,
2574
+ turnId: event.data.turnId,
2575
+ type: "authorization"
2576
+ };
2577
+ if (event.data.attemptId !== void 0) part.attemptId = event.data.attemptId;
2578
+ if (event.data.webhookUrl !== void 0) part.awaitsCallback = true;
2579
+ return part;
2580
+ }
2581
+ function createAuthorizationCompletedPart(event, existing) {
2582
+ const displayName = event.data.authorization?.displayName ?? existing?.displayName ?? formatAuthorizationDisplayName(event.data.name);
2583
+ const part = {
2584
+ authorization: existing?.authorization || event.data.authorization ? {
2585
+ ...existing?.authorization,
2586
+ ...event.data.authorization
2587
+ } : void 0,
2588
+ description: existing?.description ?? buildCompletedAuthorizationDescription(displayName, event.data.outcome, event.data.reason),
2589
+ displayName,
2590
+ name: event.data.name,
2591
+ outcome: event.data.outcome,
2592
+ state: "completed",
2593
+ stepIndex: existing?.stepIndex ?? event.data.stepIndex,
2594
+ turnId: existing?.turnId ?? event.data.turnId,
2595
+ type: "authorization"
2596
+ };
2597
+ const attemptId = event.data.attemptId ?? existing?.attemptId;
2598
+ if (attemptId !== void 0) part.attemptId = attemptId;
2599
+ if (existing?.awaitsCallback) part.awaitsCallback = true;
2600
+ if (event.data.reason !== void 0) part.reason = event.data.reason;
2601
+ return part;
2602
+ }
2603
+ function buildCompletedAuthorizationDescription(displayName, outcome, reason) {
2604
+ if (outcome === "authorized") return `${displayName} connected.`;
2605
+ return `${displayName} authorization ${outcome}${reason !== void 0 ? ` (${reason})` : ""}.`;
2606
+ }
2607
+ function normalizeAuthorizationDescription(description, name, displayName) {
2608
+ if (description === `Authorization required for ${name}`) return `Authorization required for ${displayName}`;
2609
+ return description;
2610
+ }
2611
+ function formatAuthorizationDisplayName(name) {
2612
+ if (name.length === 0) return name;
2613
+ return `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
2614
+ }
2615
+
2616
+ //#endregion
2617
+ //#region src/shared/action-request-name.ts
2618
+ function actionRequestName(action) {
2619
+ switch (action.kind) {
2620
+ case "load-skill": return "load_skill";
2621
+ case "subagent-call": return action.subagentName;
2622
+ case "remote-agent-call": return action.remoteAgentName;
2623
+ case "tool-call":
2624
+ case "workflow-tool-call": return action.toolName;
2689
2625
  }
2690
- resume() {
2691
- if (this.#resumePromise !== void 0) return this.#resumePromise;
2692
- const promise = this.#resume();
2693
- this.#resumePromise = promise;
2694
- const clear = () => {
2695
- if (this.#resumePromise === promise) this.#resumePromise = void 0;
2626
+ }
2627
+
2628
+ //#endregion
2629
+ //#region src/client/message-action-parts.ts
2630
+ function toMessageInputRequest(request) {
2631
+ return {
2632
+ allowFreeform: request.allowFreeform,
2633
+ display: request.display,
2634
+ kind: request.kind,
2635
+ options: request.options,
2636
+ prompt: request.prompt,
2637
+ requestId: request.requestId
2638
+ };
2639
+ }
2640
+ function createToolMetadata(descriptor, extra) {
2641
+ return { eve: {
2642
+ inputRequest: extra?.inputRequest,
2643
+ kind: descriptor.kind,
2644
+ name: descriptor.name
2645
+ } };
2646
+ }
2647
+ function mergeToolMetadata(current, next) {
2648
+ const kind = next.eve?.kind ?? current?.eve?.kind ?? "unknown";
2649
+ const name = next.eve?.name ?? current?.eve?.name ?? "unknown";
2650
+ return { eve: {
2651
+ ...current?.eve,
2652
+ ...next.eve,
2653
+ inputRequest: next.eve?.inputRequest ?? current?.eve?.inputRequest,
2654
+ inputResponse: next.eve?.inputResponse ?? current?.eve?.inputResponse,
2655
+ kind,
2656
+ name
2657
+ } };
2658
+ }
2659
+ function approvedApproval(part) {
2660
+ if (!part?.approval?.id) return;
2661
+ return {
2662
+ approved: true,
2663
+ id: part.approval.id,
2664
+ isAutomatic: part.approval.isAutomatic,
2665
+ reason: part.approval.reason
2666
+ };
2667
+ }
2668
+ function normalizeActionRequest(action) {
2669
+ const name = actionRequestName(action);
2670
+ switch (action.kind) {
2671
+ case "load-skill": return {
2672
+ kind: "load-skill",
2673
+ name,
2674
+ toolName: "eve:load-skill"
2675
+ };
2676
+ case "tool-call":
2677
+ case "workflow-tool-call": return {
2678
+ kind: "tool-call",
2679
+ name,
2680
+ toolName: name
2681
+ };
2682
+ case "subagent-call":
2683
+ case "remote-agent-call": return {
2684
+ kind: "subagent-call",
2685
+ name,
2686
+ toolName: `eve:subagent:${name}`
2696
2687
  };
2697
- promise.then(clear, clear);
2698
- return promise;
2699
- }
2700
- async #resume() {
2701
- if (this.#status === "resuming" || this.#status === "streaming" || this.#status === "submitted") throw new Error("eve session is already processing a turn.");
2702
- if (this.#session === void 0) throw new Error("An eve session is required before resuming.");
2703
- const session = this.#session;
2704
- const turn = createActiveTurn(() => session.cancel());
2705
- this.#activeTurn = turn;
2706
- turn.resolveResponse(void 0);
2707
- this.#error = void 0;
2708
- this.#status = "resuming";
2709
- this.#publish();
2710
- let reader;
2711
- try {
2712
- const stream = this.#ensureStream({
2713
- catchUp: true,
2714
- startIndex: this.#events.length === session.state.streamIndex ? session.state.streamIndex : 0
2715
- });
2716
- reader = stream.subscribe(turn.abortController.signal);
2717
- await stream.caughtUp;
2718
- if (!this.#isActiveTurn(turn)) return;
2719
- reader.discard();
2720
- const tail = this.#events.at(-1);
2721
- if (tail !== void 0) this.#applyTerminalStreamFailure(tail);
2722
- if (tail !== void 0 && this.#error === void 0 && !isSettledSessionTail(this.#events)) {
2723
- this.#status = "streaming";
2724
- this.#publish();
2725
- for await (const event of reader) {
2726
- if (!this.#isActiveTurn(turn)) return;
2727
- turn.receivedFollowUps += turn.receivedFollowUpEvents.get(event) ?? 0;
2728
- turn.receivedFollowUpEvents.delete(event);
2729
- if (this.#isSettledAt(event)) break;
2730
- }
2731
- }
2732
- await followSteeredTurns(turn, reader, () => this.#isActiveTurn(turn));
2733
- if (this.#isActiveTurn(turn)) this.#status = this.#error === void 0 ? "ready" : "error";
2734
- } catch (error) {
2735
- if (!this.#isActiveTurn(turn)) return;
2736
- if (isAbortError(error)) this.#status = "ready";
2737
- else {
2738
- this.#error = toError(error);
2739
- this.#status = "error";
2740
- this.#callbacks.onError?.(this.#error);
2741
- }
2742
- } finally {
2743
- reader?.[Symbol.dispose]();
2744
- this.#finishTurn(turn);
2745
- }
2746
- }
2747
- cancel() {
2748
- const turn = this.#activeTurn;
2749
- if (turn === void 0) return this.#status === "streaming" && this.#session !== void 0 ? this.#session.cancel() : Promise.resolve({ status: "no_active_turn" });
2750
- return turn.cancel();
2751
- }
2752
- [attachStore]() {
2753
- this.#attached = true;
2754
- if (this.#autoPrewarm && this.#session === void 0) this.prewarm().catch(() => {});
2755
2688
  }
2756
- [detachStore]() {
2757
- this.#attached = false;
2758
- this.#stream?.close();
2759
- this.#stream = void 0;
2760
- this.#activeTurn?.abortController.abort();
2761
- this.#resetPrewarm();
2762
- this.#resumePromise = void 0;
2689
+ }
2690
+ function normalizeActionResult(result) {
2691
+ switch (result.kind) {
2692
+ case "load-skill-result": return {
2693
+ kind: "load-skill",
2694
+ name: result.name ?? "load_skill",
2695
+ toolName: "eve:load-skill"
2696
+ };
2697
+ case "tool-result": return {
2698
+ kind: "tool-call",
2699
+ name: result.toolName,
2700
+ toolName: result.toolName
2701
+ };
2702
+ case "subagent-result": return {
2703
+ kind: "subagent-call",
2704
+ name: result.subagentName,
2705
+ toolName: `eve:subagent:${result.subagentName}`
2706
+ };
2763
2707
  }
2764
- reset() {
2765
- this.#stream?.close();
2766
- this.#stream = void 0;
2767
- this.#pendingAuthorizations.clear();
2768
- this.#pendingInputRequests.clear();
2769
- const turn = this.#activeTurn;
2770
- this.#activeTurn = void 0;
2771
- turn?.resolveResponse(void 0);
2772
- turn?.resolveCompletion();
2773
- turn?.abortController.abort();
2774
- this.#resetPrewarm();
2775
- this.#resumePromise = void 0;
2776
- if (!this.#externalSession) this.#session = void 0;
2777
- this.#events = [];
2778
- this.#seenEvents = createEventDeduper();
2779
- this.#messageSubmissions.reset();
2780
- this.#projection.reset();
2781
- this.#error = void 0;
2782
- this.#status = "ready";
2783
- this.#callbacks.onSessionChange?.(this.#session?.state);
2784
- this.#publish();
2785
- if (this.#autoPrewarm && this.#attached) this.prewarm().catch(() => {});
2708
+ }
2709
+ function stringifyUnknown(value) {
2710
+ if (typeof value === "string") return value;
2711
+ try {
2712
+ return JSON.stringify(value);
2713
+ } catch {
2714
+ return "Action failed.";
2786
2715
  }
2787
- async #sendFollowUp(turn, input, prepareSend) {
2788
- if (input.message === void 0 || input.turnPolicy !== "steer") throw new Error("eve session is already processing a turn. Send a message with turnPolicy: \"steer\" to guide it at the next boundary.");
2789
- const generation = this.#prewarmGeneration;
2790
- const signal = createAbortSignal(input.signal, turn.abortController.signal);
2791
- const preparedInput = await waitWithSignal(Promise.resolve(prepareSend?.(input)), signal) ?? input;
2792
- if (generation !== this.#prewarmGeneration) return;
2793
- assertExclusiveTurnInput(preparedInput);
2794
- if (preparedInput.message === void 0 || preparedInput.turnPolicy !== "steer") throw new Error("An in-flight follow-up requires a message with turnPolicy: \"steer\".");
2795
- if (!this.#isActiveTurn(turn)) return await this.#submit(preparedInput);
2796
- const submissionId = this.#messageSubmissions.submit(preparedInput, this.#events.length);
2797
- if (submissionId !== void 0) turn.followUpSubmissionIds.add(submissionId);
2798
- this.#publish();
2799
- this.#ensureStream({
2800
- headers: preparedInput.headers,
2801
- streamReconnectPolicy: preparedInput.streamReconnectPolicy
2802
- });
2803
- let dispatch;
2804
- dispatch = (async () => {
2805
- try {
2806
- const signal = createAbortSignal(preparedInput.signal, turn.abortController.signal);
2807
- await waitWithSignal(turn.response, signal);
2808
- if (!this.#isActiveTurn(turn) || this.#session === void 0) throw new Error("The active eve turn ended before the follow-up could be sent.");
2809
- const { message, ...options } = preparedInput;
2810
- const response = await this.#session.send(message, {
2811
- ...options,
2812
- signal
2813
- });
2814
- turn.acceptedFollowUps += 1;
2815
- if (this.#handleReconciliation(this.#messageSubmissions.correlate(submissionId, getMessageResponseDeliveryId(response), this.#events))) this.#publish();
2816
- } catch (error) {
2817
- if (this.#isActiveTurn(turn)) {
2818
- this.#messageSubmissions.fail(toError(error), submissionId);
2819
- this.#publish();
2820
- }
2821
- throw error;
2822
- } finally {
2823
- turn.followUpDispatches.delete(dispatch);
2824
- }
2825
- })();
2826
- turn.followUpDispatches.add(dispatch);
2827
- await dispatch;
2828
- await turn.completion;
2716
+ }
2717
+
2718
+ //#endregion
2719
+ //#region src/client/message-reducer-primitives.ts
2720
+ function projectReceivedParts(parts, message) {
2721
+ return parts?.map((part) => part.type === "text" ? {
2722
+ state: "done",
2723
+ text: part.text,
2724
+ type: "text"
2725
+ } : {
2726
+ filename: part.filename,
2727
+ mediaType: part.mediaType,
2728
+ size: part.size,
2729
+ type: "file",
2730
+ url: part.url
2731
+ }) ?? [{
2732
+ state: "done",
2733
+ text: message,
2734
+ type: "text"
2735
+ }];
2736
+ }
2737
+ function partKey(part) {
2738
+ switch (part.type) {
2739
+ case "text": return `text:${part.stepIndex ?? 0}`;
2740
+ case "reasoning": return `reasoning:${part.stepIndex ?? 0}`;
2741
+ case "file": return `file:${part.stepIndex ?? 0}:${part.filename ?? part.url ?? part.mediaType}`;
2742
+ case "step-start": return "step-start";
2743
+ case "authorization": return part.attemptId === void 0 ? `authorization:${part.turnId}:${part.stepIndex}:${part.name}` : `authorization:${part.attemptId}`;
2744
+ case "dynamic-tool": return `dynamic-tool:${part.toolCallId}`;
2829
2745
  }
2830
- async #dispatchTurn(input) {
2831
- const streamOptions = {
2832
- headers: input.headers,
2833
- streamReconnectPolicy: input.streamReconnectPolicy
2746
+ }
2747
+ function upsertMessage(data, next, beforeAssistantTurnId) {
2748
+ const index = data.messages.findIndex((message) => message.id === next.id);
2749
+ if (index !== -1) return {
2750
+ ...data,
2751
+ messages: [
2752
+ ...data.messages.slice(0, index),
2753
+ next,
2754
+ ...data.messages.slice(index + 1)
2755
+ ]
2756
+ };
2757
+ const before = beforeAssistantTurnId === void 0 ? -1 : data.messages.findIndex((message) => message.role === "assistant" && message.metadata?.turnId === beforeAssistantTurnId);
2758
+ if (before === -1) return {
2759
+ ...data,
2760
+ messages: [...data.messages, next]
2761
+ };
2762
+ return {
2763
+ ...data,
2764
+ messages: [
2765
+ ...data.messages.slice(0, before),
2766
+ next,
2767
+ ...data.messages.slice(before)
2768
+ ]
2769
+ };
2770
+ }
2771
+ function optimisticUserMessageId(submissionId) {
2772
+ return `optimistic:${submissionId}:user`;
2773
+ }
2774
+
2775
+ //#endregion
2776
+ //#region src/client/message-run-parts.ts
2777
+ function transition(message, input) {
2778
+ const index = message.parts.findLastIndex((part) => part.type === input.type && part.stepIndex === input.stepIndex);
2779
+ const previous = index === -1 ? void 0 : message.parts[index];
2780
+ if (input.kind === "append" && !input.delta) return message;
2781
+ const current = previous?.state === "streaming" ? previous : void 0;
2782
+ const part = {
2783
+ id: current?.id ?? input.id ?? `${message.id}:${input.type}:${message.parts.length}`,
2784
+ state: input.kind === "append" ? "streaming" : "done",
2785
+ stepIndex: input.stepIndex,
2786
+ text: input.kind === "append" ? (current?.text ?? "") + input.delta : input.text,
2787
+ type: input.type
2788
+ };
2789
+ const parts = current ? [
2790
+ ...message.parts.slice(0, index),
2791
+ part,
2792
+ ...message.parts.slice(index + 1)
2793
+ ] : [...message.parts, part];
2794
+ return {
2795
+ ...message,
2796
+ metadata: {
2797
+ ...message.metadata,
2798
+ status: input.type === "text" && part.state === "done" ? "complete" : "streaming"
2799
+ },
2800
+ parts
2801
+ };
2802
+ }
2803
+ const messageRun = { transition };
2804
+
2805
+ //#endregion
2806
+ //#region src/client/message-task-parts.ts
2807
+ function createSettledTaskPart(existing, event) {
2808
+ const settledPartBase = {
2809
+ approval: approvedApproval(existing),
2810
+ input: existing.input,
2811
+ stepIndex: existing.stepIndex,
2812
+ toolCallId: existing.toolCallId,
2813
+ toolMetadata: existing.toolMetadata,
2814
+ toolName: existing.toolName,
2815
+ type: "dynamic-tool"
2816
+ };
2817
+ switch (event.data.status) {
2818
+ case "completed": return {
2819
+ ...settledPartBase,
2820
+ output: event.data.output,
2821
+ state: "output-available"
2834
2822
  };
2835
- if (this.#prewarmPromise !== void 0) {
2836
- await waitWithSignal(this.#prewarmPromise.catch((error) => {
2837
- if (this.#session !== void 0) throw error;
2838
- }), input.signal);
2839
- input.signal?.throwIfAborted();
2823
+ case "failed": return {
2824
+ ...settledPartBase,
2825
+ errorText: event.data.error?.message ?? "Task failed.",
2826
+ state: "output-error"
2827
+ };
2828
+ case "cancelled": return {
2829
+ ...settledPartBase,
2830
+ errorText: "Task was cancelled.",
2831
+ state: "output-error"
2832
+ };
2833
+ }
2834
+ }
2835
+
2836
+ //#endregion
2837
+ //#region src/client/message-reducer.ts
2838
+ function receivedMessageEventId(event) {
2839
+ return event.meta.id ?? `${event.data.turnId}:${event.data.sequence}`;
2840
+ }
2841
+ function defaultMessageReducer() {
2842
+ return {
2843
+ initial() {
2844
+ return { messages: [] };
2845
+ },
2846
+ reduce(data, event) {
2847
+ return reduceMessageData(data, event);
2840
2848
  }
2841
- if (this.#session === void 0) {
2842
- if (this.#client === void 0) throw new Error("An external eve session is required before sending.");
2843
- if (input.message === void 0) throw new Error("Cannot answer an input request before the session starts.");
2844
- const created = await this.#client.sessions.create({
2845
- ...input,
2846
- message: input.message
2847
- });
2848
- input.signal?.throwIfAborted();
2849
- this.#session = created.session;
2850
- this.#callbacks.onSessionChange?.(created.session.state);
2851
- this.#publish();
2852
- return {
2853
- response: created.response,
2854
- reader: this.#ensureStream(streamOptions).subscribe(input.signal)
2849
+ };
2850
+ }
2851
+ function reduceMessageData(data, event) {
2852
+ switch (event.type) {
2853
+ case "client.message.submitted":
2854
+ case "client.message.failed": return upsertMessage(data, {
2855
+ id: optimisticUserMessageId(event.data.submissionId),
2856
+ metadata: {
2857
+ optimistic: true,
2858
+ status: event.type === "client.message.failed" ? "failed" : "submitted"
2859
+ },
2860
+ parts: [{
2861
+ type: "text",
2862
+ text: event.data.message
2863
+ }],
2864
+ role: "user"
2865
+ }, event.data.turnId);
2866
+ case "input.resolved": {
2867
+ let next = data;
2868
+ for (const resolution of event.data.resolutions) next = resolveInputRequest(next, resolution);
2869
+ return next;
2870
+ }
2871
+ case "message.received": return upsertMessage(data, {
2872
+ id: `${receivedMessageEventId(event)}:user`,
2873
+ metadata: {
2874
+ status: "complete",
2875
+ turnId: event.data.turnId
2876
+ },
2877
+ parts: projectReceivedParts(event.data.parts, event.data.message),
2878
+ role: "user"
2879
+ }, event.data.turnId);
2880
+ case "step.started": return updateAssistantMessage(data, event.data.turnId, (message) => ensureStepStartPart(message, event.data.stepIndex));
2881
+ case "step.completed":
2882
+ if (data.messages.find((message) => message.role === "assistant" && message.metadata?.turnId === event.data.turnId) === void 0) return data;
2883
+ return updateAssistantMessage(data, event.data.turnId, (message) => ({
2884
+ ...message,
2885
+ parts: closeStreamingRuns(message.parts, event.data.stepIndex)
2886
+ }));
2887
+ case "reasoning.appended": return updateAssistantMessage(data, event.data.turnId, (message) => messageRun.transition(ensureStepStartPart(message, event.data.stepIndex), {
2888
+ kind: "append",
2889
+ delta: event.data.reasoningDelta,
2890
+ id: event.meta?.id,
2891
+ stepIndex: event.data.stepIndex,
2892
+ type: "reasoning"
2893
+ }));
2894
+ case "reasoning.completed": return updateAssistantMessage(data, event.data.turnId, (message) => messageRun.transition(ensureStepStartPart(message, event.data.stepIndex), {
2895
+ kind: "complete",
2896
+ stepIndex: event.data.stepIndex,
2897
+ text: event.data.reasoning,
2898
+ id: event.meta?.id,
2899
+ type: "reasoning"
2900
+ }));
2901
+ case "action.input.appended": {
2902
+ const existing = findToolPart(data, event.data.callId);
2903
+ if (existing !== void 0 && existing.state !== "input-streaming") return data;
2904
+ const nextPart = {
2905
+ input: void 0,
2906
+ inputText: (existing?.state === "input-streaming" ? existing.inputText : "") + event.data.inputTextDelta,
2907
+ state: "input-streaming",
2908
+ stepIndex: event.data.stepIndex,
2909
+ toolCallId: event.data.callId,
2910
+ toolMetadata: existing?.toolMetadata ?? { eve: {
2911
+ kind: "unknown",
2912
+ name: event.data.toolName
2913
+ } },
2914
+ toolName: event.data.toolName,
2915
+ type: "dynamic-tool"
2855
2916
  };
2917
+ return upsertToolPart(data, event.data.turnId, event.data.stepIndex, nextPart);
2856
2918
  }
2857
- const reader = this.#ensureStream(streamOptions).subscribe(input.signal);
2858
- try {
2859
- if (input.inputResponses === void 0) {
2860
- const { message, ...options } = input;
2861
- return {
2862
- response: await this.#session.send(message, options),
2863
- reader
2864
- };
2919
+ case "actions.requested": {
2920
+ let next = data;
2921
+ for (const action of event.data.actions) {
2922
+ const existing = findToolPart(next, action.callId);
2923
+ if (existing !== void 0 && existing.state !== "input-streaming") continue;
2924
+ const descriptor = normalizeActionRequest(action);
2925
+ next = updateAssistantMessage(next, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
2926
+ input: "input" in action ? action.input : void 0,
2927
+ state: "input-available",
2928
+ stepIndex: event.data.stepIndex,
2929
+ toolCallId: action.callId,
2930
+ toolMetadata: createToolMetadata(descriptor),
2931
+ toolName: descriptor.toolName,
2932
+ type: "dynamic-tool"
2933
+ }));
2865
2934
  }
2866
- const { inputResponses, ...options } = input;
2867
- return {
2868
- response: await this.#session.respond(inputResponses, options),
2869
- reader
2870
- };
2871
- } catch (error) {
2872
- reader[Symbol.dispose]();
2873
- throw error;
2935
+ return next;
2874
2936
  }
2875
- }
2876
- #ensureStream(options = {}) {
2877
- if (this.#stream !== void 0 && !this.#stream.ended) {
2878
- this.#stream.setOptions(options);
2879
- return this.#stream;
2937
+ case "input.requested": {
2938
+ let next = data;
2939
+ for (const request of event.data.requests) {
2940
+ const existing = findToolPart(next, request.action.callId);
2941
+ if (existing?.approval?.id === request.requestId || existing !== void 0 && isSettledToolPart(existing)) continue;
2942
+ const descriptor = normalizeActionRequest(request.action);
2943
+ next = updateAssistantMessage(next, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
2944
+ approval: { id: request.requestId },
2945
+ input: request.action.input,
2946
+ state: "approval-requested",
2947
+ stepIndex: event.data.stepIndex,
2948
+ toolCallId: request.action.callId,
2949
+ toolMetadata: createToolMetadata(descriptor, { inputRequest: toMessageInputRequest(request) }),
2950
+ toolName: descriptor.toolName,
2951
+ type: "dynamic-tool"
2952
+ }));
2953
+ }
2954
+ return next;
2880
2955
  }
2881
- if (this.#session === void 0) throw new Error("A session is required before opening its stream.");
2882
- const session = this.#session;
2883
- const generation = this.#prewarmGeneration;
2884
- this.#stream = new SessionEventStream(session, {
2885
- ...options,
2886
- onEvent: (event) => {
2887
- if (generation === this.#prewarmGeneration) this.#acceptServerEvent(event);
2888
- },
2889
- onError: (error) => {
2890
- if (generation !== this.#prewarmGeneration) return;
2891
- this.#stream = void 0;
2892
- if (this.#activeTurn !== void 0) return;
2893
- this.#error = toError(error);
2894
- this.#status = "error";
2895
- this.#callbacks.onError?.(this.#error);
2896
- this.#publish();
2956
+ case "approval.candidate": return data;
2957
+ case "approval.settled": {
2958
+ const existing = findToolPartByApprovalId(data, event.data.requestId);
2959
+ if (existing === void 0) return data;
2960
+ if (event.data.outcome === "approved") {
2961
+ const approval = {
2962
+ approved: true,
2963
+ id: event.data.requestId,
2964
+ reason: void 0
2965
+ };
2966
+ return updateToolPart(data, existing.toolCallId, existing.state === "output-available" ? {
2967
+ ...existing,
2968
+ approval
2969
+ } : {
2970
+ ...toolPartIdentity(existing),
2971
+ approval,
2972
+ state: "approval-responded"
2973
+ });
2897
2974
  }
2898
- });
2899
- return this.#stream;
2900
- }
2901
- #resetPrewarm() {
2902
- this.#prewarmGeneration += 1;
2903
- this.#prewarmController?.abort();
2904
- this.#prewarmController = void 0;
2905
- this.#prewarmPromise = void 0;
2906
- }
2907
- #finishTurn(turn) {
2908
- if (!this.#isActiveTurn(turn)) return;
2909
- turn.resolveResponse(void 0);
2910
- this.#activeTurn = void 0;
2911
- try {
2912
- this.#callbacks.onSessionChange?.(this.#session?.state);
2913
- this.#publish();
2914
- this.#callbacks.onFinish?.(this.#snapshot);
2915
- } finally {
2916
- turn.resolveCompletion();
2975
+ if (existing.state === "output-available") return data;
2976
+ return updateToolPart(data, existing.toolCallId, {
2977
+ ...toolPartIdentity(existing),
2978
+ approval: {
2979
+ approved: false,
2980
+ id: event.data.requestId,
2981
+ reason: "Tool execution was cancelled."
2982
+ },
2983
+ state: "output-denied"
2984
+ });
2917
2985
  }
2918
- }
2919
- #isActiveTurn(turn) {
2920
- return this.#activeTurn === turn;
2921
- }
2922
- #projectInputResponses(input) {
2923
- if (input.inputResponses === void 0 || input.inputResponses.length === 0) return;
2924
- this.#projection.append({
2925
- data: {
2926
- createdAt: Date.now(),
2927
- responses: input.inputResponses
2928
- },
2929
- type: "client.input.responded"
2930
- });
2931
- }
2932
- #acceptServerEvent(event) {
2933
- if (!this.#seenEvents.admit(event)) return;
2934
- const wasStreaming = this.#status === "streaming";
2935
- this.#trackPendingRequests(event);
2936
- this.#events = [...this.#events, event];
2937
- this.#handleReconciliation(this.#messageSubmissions.apply(event));
2938
- this.#callbacks.onEvent?.(event);
2939
- this.#applyTerminalStreamFailure(event);
2940
- const settled = this.#isSettledAt(event);
2941
- if (this.#status !== "resuming" && this.#error === void 0) {
2942
- if ("data" in event && "turnId" in event.data) this.#status = "streaming";
2943
- if (this.#activeTurn === void 0 && settled) this.#status = "ready";
2986
+ case "action.result": {
2987
+ const descriptor = normalizeActionResult(event.data.result);
2988
+ const existing = findToolPart(data, event.data.result.callId);
2989
+ const denied = event.data.status === "rejected" || event.data.error?.code === "TOOL_EXECUTION_DENIED";
2990
+ const failed = event.data.status === "failed" && !denied;
2991
+ const approvalId = existing?.approval?.id ?? event.data.result.callId;
2992
+ const toolMetadata = mergeToolMetadata(existing?.toolMetadata, createToolMetadata(descriptor));
2993
+ const resultPartBase = {
2994
+ input: existing?.input,
2995
+ stepIndex: event.data.stepIndex,
2996
+ toolCallId: event.data.result.callId,
2997
+ toolMetadata,
2998
+ toolName: existing?.toolName ?? descriptor.toolName,
2999
+ type: "dynamic-tool"
3000
+ };
3001
+ let nextPart;
3002
+ if (denied) nextPart = {
3003
+ ...resultPartBase,
3004
+ approval: {
3005
+ approved: false,
3006
+ id: approvalId,
3007
+ reason: event.data.error?.message
3008
+ },
3009
+ state: "output-denied"
3010
+ };
3011
+ else if (failed) nextPart = {
3012
+ ...resultPartBase,
3013
+ approval: approvedApproval(existing),
3014
+ errorText: event.data.error?.message ?? stringifyUnknown(event.data.result.output),
3015
+ state: "output-error"
3016
+ };
3017
+ else nextPart = {
3018
+ ...resultPartBase,
3019
+ approval: approvedApproval(existing),
3020
+ output: event.data.result.output,
3021
+ state: "output-available"
3022
+ };
3023
+ return upsertToolPart(data, event.data.turnId, event.data.stepIndex, nextPart);
2944
3024
  }
2945
- this.#callbacks.onSessionChange?.(this.#session?.state);
2946
- if (this.#status !== "resuming") this.#publish();
2947
- if (this.#activeTurn === void 0 && wasStreaming && settled) this.#callbacks.onFinish?.(this.#snapshot);
2948
- }
2949
- #trackPendingRequests(event) {
2950
- updatePendingAuthorizations(this.#pendingAuthorizations, event);
2951
- updatePendingInputRequests(this.#pendingInputRequests, event);
2952
- }
2953
- #isSettledAt(event) {
2954
- return isTurnSegmentBoundary(event, this.#pendingInputRequests) && this.#pendingAuthorizations.size === 0;
2955
- }
2956
- #handleReconciliation(reconciliation) {
2957
- if (reconciliation === void 0) return false;
2958
- let followed = 0;
2959
- for (const id of reconciliation.ids) if (this.#activeTurn?.followUpSubmissionIds.delete(id)) followed += 1;
2960
- if (followed > 0 && this.#activeTurn !== void 0) {
2961
- if (reconciliation.alreadyProjected) this.#activeTurn.receivedFollowUps += followed;
2962
- else {
2963
- const previous = this.#activeTurn.receivedFollowUpEvents.get(reconciliation.event) ?? 0;
2964
- this.#activeTurn.receivedFollowUpEvents.set(reconciliation.event, previous + followed);
2965
- }
3025
+ case "action.partial": {
3026
+ const existing = findToolPart(data, event.data.result.callId);
3027
+ if (existing !== void 0 && isSettledToolPart(existing)) return data;
3028
+ const descriptor = normalizeActionResult(event.data.result);
3029
+ const nextPart = {
3030
+ approval: approvedApproval(existing),
3031
+ input: existing?.input,
3032
+ output: event.data.result.output,
3033
+ partial: true,
3034
+ state: "output-available",
3035
+ stepIndex: event.data.stepIndex,
3036
+ toolCallId: event.data.result.callId,
3037
+ toolMetadata: mergeToolMetadata(existing?.toolMetadata, createToolMetadata(descriptor)),
3038
+ toolName: existing?.toolName ?? descriptor.toolName,
3039
+ type: "dynamic-tool"
3040
+ };
3041
+ return upsertToolPart(data, event.data.turnId, event.data.stepIndex, nextPart);
2966
3042
  }
2967
- return true;
2968
- }
2969
- #applyTerminalStreamFailure(event) {
2970
- const error = toTerminalStreamFailureError(event);
2971
- if (error === void 0) return;
2972
- this.#status = "error";
2973
- this.#messageSubmissions.failAll(error);
2974
- if (this.#error === void 0) {
2975
- this.#error = error;
2976
- this.#callbacks.onError?.(error);
3043
+ case "task.settled": {
3044
+ const existing = findToolPart(data, event.data.callId);
3045
+ if (existing === void 0) return data;
3046
+ return replaceToolPart(data, createSettledTaskPart(existing, event));
2977
3047
  }
3048
+ case "authorization.required": return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), createAuthorizationRequiredPart(event)));
3049
+ case "authorization.completed": return completeAuthorization(data, event);
3050
+ case "message.appended": return updateAssistantMessage(data, event.data.turnId, (message) => messageRun.transition(ensureStepStartPart(message, event.data.stepIndex), {
3051
+ kind: "append",
3052
+ delta: event.data.messageDelta,
3053
+ id: event.meta?.id,
3054
+ stepIndex: event.data.stepIndex,
3055
+ type: "text"
3056
+ }));
3057
+ case "message.completed": return updateAssistantMessage(data, event.data.turnId, (message) => messageRun.transition(ensureStepStartPart(message, event.data.stepIndex), {
3058
+ kind: "complete",
3059
+ stepIndex: event.data.stepIndex,
3060
+ text: event.data.message,
3061
+ id: event.meta?.id,
3062
+ type: "text"
3063
+ }));
3064
+ case "result.completed": return updateAssistantMessage(data, event.data.turnId, (message) => ({
3065
+ ...message,
3066
+ metadata: {
3067
+ ...message.metadata,
3068
+ result: event.data.result
3069
+ }
3070
+ }));
3071
+ case "turn.completed": return updateAssistantMessage(data, event.data.turnId, (message) => ({
3072
+ ...message,
3073
+ metadata: {
3074
+ ...message.metadata,
3075
+ status: "complete"
3076
+ },
3077
+ parts: removeStreamingToolParts(closeStreamingRuns(message.parts))
3078
+ }));
3079
+ case "turn.cancelled": return updateAssistantMessage(data, event.data.turnId, (message) => ({
3080
+ ...message,
3081
+ metadata: {
3082
+ ...message.metadata,
3083
+ status: "complete"
3084
+ },
3085
+ parts: removeStreamingToolParts(closeStreamingRuns(message.parts))
3086
+ }));
3087
+ case "turn.failed":
3088
+ if (data.messages.find((message) => message.role === "assistant" && message.metadata?.turnId === event.data.turnId) === void 0) return data;
3089
+ return updateAssistantMessage(data, event.data.turnId, (message) => ({
3090
+ ...message,
3091
+ metadata: {
3092
+ ...message.metadata,
3093
+ status: "complete"
3094
+ },
3095
+ parts: removeStreamingToolParts(closeStreamingRuns(message.parts))
3096
+ }));
3097
+ case "session.failed": return data;
3098
+ default: return data;
2978
3099
  }
2979
- #createSnapshot() {
2980
- return {
2981
- data: this.#projection.data,
2982
- error: this.#error,
2983
- events: this.#events,
2984
- session: this.#session?.state,
2985
- status: this.#status
2986
- };
2987
- }
2988
- #publish() {
2989
- this.#snapshot = this.#createSnapshot();
2990
- for (const subscriber of this.#subscribers) subscriber();
2991
- }
2992
- };
2993
- function detachEveAgentStore(store) {
2994
- store[detachStore]();
2995
3100
  }
2996
- function attachEveAgentStore(store) {
2997
- store[attachStore]();
3101
+ function closeStreamingRuns(parts, stepIndex) {
3102
+ return parts.map((part) => (part.type === "text" || part.type === "reasoning") && part.state === "streaming" && (stepIndex === void 0 || part.stepIndex === stepIndex) ? {
3103
+ ...part,
3104
+ state: "done"
3105
+ } : part);
2998
3106
  }
2999
-
3000
- //#endregion
3001
- //#region src/client/agent-host.ts
3002
- const AGENT_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]*$/;
3003
- const EVE_NAMED_AGENT_ROUTE_PREFIX = "/eve";
3004
- function resolveEveAgentHost(input) {
3005
- if (input.agent === void 0) return input.host ?? "";
3006
- if (input.host !== void 0) throw new Error("useEveAgent cannot combine agent and host. Use one target option.");
3007
- assertValidAgentName(input.agent);
3008
- return `${EVE_NAMED_AGENT_ROUTE_PREFIX}/${input.agent}`;
3107
+ function removeStreamingToolParts(parts) {
3108
+ return parts.filter((part) => part.type !== "dynamic-tool" || part.state !== "input-streaming");
3009
3109
  }
3010
- function assertValidAgentName(name) {
3011
- if (!AGENT_NAME_PATTERN.test(name)) throw new Error(`eve agent name ${JSON.stringify(name)} is invalid. Use lowercase letters, numbers, underscores, or hyphens, starting with a letter or number.`);
3110
+ function respondToInputRequest(data, response) {
3111
+ const existing = findToolPartByApprovalId(data, response.requestId);
3112
+ if (!existing) return data;
3113
+ const approval = { id: response.requestId };
3114
+ if (response.text !== void 0) approval.reason = response.text;
3115
+ const toolMetadata = mergeToolMetadata(existing.toolMetadata, { eve: {
3116
+ inputResponse: response,
3117
+ kind: existing.toolMetadata?.eve?.kind ?? "unknown",
3118
+ name: existing.toolMetadata?.eve?.name ?? existing.toolName
3119
+ } });
3120
+ return updateToolPart(data, existing.toolCallId, existing.state === "output-available" ? {
3121
+ ...existing,
3122
+ approval: {
3123
+ ...approval,
3124
+ approved: true
3125
+ },
3126
+ toolMetadata
3127
+ } : {
3128
+ ...toolPartIdentity(existing),
3129
+ approval,
3130
+ state: "approval-responded",
3131
+ toolMetadata
3132
+ });
3012
3133
  }
3013
-
3014
- //#endregion
3015
- //#region src/client/authorization-message-parts.ts
3016
- function createAuthorizationRequiredPart(event) {
3017
- const displayName = event.data.authorization?.displayName ?? formatAuthorizationDisplayName(event.data.name);
3134
+ function resolveInputRequest(data, resolution) {
3135
+ if (resolution.response !== void 0) return findToolPartByApprovalId(data, resolution.requestId)?.approval?.approved === void 0 ? respondToInputRequest(data, resolution.response) : data;
3136
+ const existing = findToolPartByApprovalId(data, resolution.requestId);
3137
+ if (!existing) return data;
3138
+ return updateToolPart(data, existing.toolCallId, {
3139
+ ...toolPartIdentity(existing),
3140
+ output: { status: resolution.outcome },
3141
+ state: "output-available"
3142
+ });
3143
+ }
3144
+ function toolPartIdentity(part) {
3018
3145
  return {
3019
- authorization: event.data.authorization,
3020
- description: normalizeAuthorizationDescription(event.data.description, event.data.name, displayName),
3021
- displayName,
3022
- name: event.data.name,
3023
- state: "required",
3024
- stepIndex: event.data.stepIndex,
3025
- turnId: event.data.turnId,
3026
- type: "authorization"
3146
+ input: part.input,
3147
+ stepIndex: part.stepIndex,
3148
+ toolCallId: part.toolCallId,
3149
+ toolMetadata: part.toolMetadata,
3150
+ toolName: part.toolName,
3151
+ type: part.type
3027
3152
  };
3028
3153
  }
3029
- function createAuthorizationCompletedPart(event, existing) {
3030
- const displayName = event.data.authorization?.displayName ?? existing?.displayName ?? formatAuthorizationDisplayName(event.data.name);
3154
+ function updateAssistantMessage(data, turnId, update) {
3155
+ const message = data.messages.find((message) => message.role === "assistant" && message.metadata?.turnId === turnId) ?? createAssistantMessage(turnId);
3156
+ return upsertMessage(data, update(message));
3157
+ }
3158
+ function createAssistantMessage(turnId) {
3031
3159
  return {
3032
- authorization: existing?.authorization || event.data.authorization ? {
3033
- ...existing?.authorization,
3034
- ...event.data.authorization
3035
- } : void 0,
3036
- description: existing?.description ?? buildCompletedAuthorizationDescription(displayName, event.data.outcome, event.data.reason),
3037
- displayName,
3038
- name: event.data.name,
3039
- outcome: event.data.outcome,
3040
- reason: event.data.reason,
3041
- state: "completed",
3042
- stepIndex: existing?.stepIndex ?? event.data.stepIndex,
3043
- turnId: existing?.turnId ?? event.data.turnId,
3044
- type: "authorization"
3160
+ id: `${turnId}:assistant`,
3161
+ metadata: {
3162
+ status: "streaming",
3163
+ turnId
3164
+ },
3165
+ parts: [],
3166
+ role: "assistant"
3045
3167
  };
3046
3168
  }
3047
- function buildCompletedAuthorizationDescription(displayName, outcome, reason) {
3048
- if (outcome === "authorized") return `${displayName} connected.`;
3049
- return `${displayName} authorization ${outcome}${reason !== void 0 ? ` (${reason})` : ""}.`;
3169
+ function ensureStepStartPart(message, stepIndex) {
3170
+ const stepStartCount = message.parts.filter((part) => part.type === "step-start").length;
3171
+ if (stepStartCount > stepIndex) return message;
3172
+ const missingCount = stepIndex - stepStartCount + 1;
3173
+ return {
3174
+ ...message,
3175
+ parts: [...message.parts, ...Array.from({ length: missingCount }, () => ({ type: "step-start" }))]
3176
+ };
3050
3177
  }
3051
- function normalizeAuthorizationDescription(description, name, displayName) {
3052
- if (description === `Authorization required for ${name}`) return `Authorization required for ${displayName}`;
3053
- return description;
3178
+ function upsertPart(message, next) {
3179
+ const index = message.parts.findIndex((part) => partKey(part) === partKey(next));
3180
+ const parts = index === -1 ? [...message.parts, next] : [
3181
+ ...message.parts.slice(0, index),
3182
+ next,
3183
+ ...message.parts.slice(index + 1)
3184
+ ];
3185
+ return {
3186
+ ...message,
3187
+ metadata: {
3188
+ ...message.metadata,
3189
+ status: next.type === "text" && next.state === "done" ? "complete" : "streaming"
3190
+ },
3191
+ parts
3192
+ };
3054
3193
  }
3055
- function formatAuthorizationDisplayName(name) {
3056
- if (name.length === 0) return name;
3057
- return `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
3194
+ function upsertToolPart(data, turnId, stepIndex, part) {
3195
+ const updated = updateToolPart(data, part.toolCallId, part);
3196
+ return updated !== data ? updated : updateAssistantMessage(data, turnId, (message) => upsertPart(ensureStepStartPart(message, stepIndex), part));
3058
3197
  }
3059
-
3060
- //#endregion
3061
- //#region src/shared/action-request-name.ts
3062
- function actionRequestName(action) {
3063
- switch (action.kind) {
3064
- case "load-skill": return "load_skill";
3065
- case "subagent-call": return action.subagentName;
3066
- case "remote-agent-call": return action.remoteAgentName;
3067
- case "tool-call":
3068
- case "workflow-tool-call": return action.toolName;
3198
+ function updateToolPart(data, toolCallId, next) {
3199
+ const message = data.messages.find((candidate) => candidate.role === "assistant" && candidate.parts.some((part) => part.type === "dynamic-tool" && part.toolCallId === toolCallId));
3200
+ if (!message) return data;
3201
+ return upsertMessage(data, upsertPart(message, next));
3202
+ }
3203
+ function replaceToolPart(data, next) {
3204
+ const message = data.messages.find((candidate) => candidate.parts.some((part) => part.type === "dynamic-tool" && part.toolCallId === next.toolCallId));
3205
+ if (message === void 0) return data;
3206
+ return upsertMessage(data, {
3207
+ ...message,
3208
+ parts: message.parts.map((part) => partKey(part) === partKey(next) ? next : part)
3209
+ });
3210
+ }
3211
+ function completeAuthorization(data, event) {
3212
+ const existing = findPendingAuthorizationPart(data, event.data.name, event.data.attemptId);
3213
+ const next = createAuthorizationCompletedPart(event, existing);
3214
+ return updateAssistantMessage(data, existing?.turnId ?? event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, next.stepIndex), next));
3215
+ }
3216
+ function findToolPart(data, toolCallId) {
3217
+ for (const message of data.messages) for (const part of message.parts) if (part.type === "dynamic-tool" && part.toolCallId === toolCallId) return part;
3218
+ }
3219
+ function isSettledToolPart(part) {
3220
+ return part.state === "output-denied" || part.state === "output-error" || part.state === "output-available" && part.partial !== true;
3221
+ }
3222
+ function findPendingAuthorizationPart(data, name, attemptId) {
3223
+ for (let messageIndex = data.messages.length - 1; messageIndex >= 0; messageIndex -= 1) {
3224
+ const message = data.messages[messageIndex];
3225
+ if (message?.role !== "assistant") continue;
3226
+ for (let partIndex = message.parts.length - 1; partIndex >= 0; partIndex -= 1) {
3227
+ const part = message.parts[partIndex];
3228
+ if (part?.type === "authorization" && part.state === "required" && (attemptId === void 0 ? part.attemptId === void 0 && part.name === name : part.attemptId === attemptId)) return part;
3229
+ }
3069
3230
  }
3070
3231
  }
3232
+ function findToolPartByApprovalId(data, approvalId) {
3233
+ for (const message of data.messages) for (const part of message.parts) if (part.type === "dynamic-tool" && part.approval?.id === approvalId) return part;
3234
+ }
3071
3235
 
3072
3236
  //#endregion
3073
- //#region src/client/message-action-parts.ts
3074
- function toMessageInputRequest(request) {
3237
+ //#region src/client/conversation-reducer.ts
3238
+ function initialConversationState() {
3075
3239
  return {
3076
- allowFreeform: request.allowFreeform,
3077
- display: request.display,
3078
- kind: request.kind,
3079
- options: request.options,
3080
- prompt: request.prompt,
3081
- requestId: request.requestId
3082
- };
3083
- }
3084
- function createToolMetadata(descriptor, extra) {
3085
- return { eve: {
3086
- inputRequest: extra?.inputRequest,
3087
- kind: descriptor.kind,
3088
- name: descriptor.name
3089
- } };
3240
+ messages: [],
3241
+ turns: {},
3242
+ inputs: {},
3243
+ tasks: {},
3244
+ agents: {}
3245
+ };
3090
3246
  }
3091
- function mergeToolMetadata(current, next) {
3092
- const kind = next.eve?.kind ?? current?.eve?.kind ?? "unknown";
3093
- const name = next.eve?.name ?? current?.eve?.name ?? "unknown";
3094
- return { eve: {
3095
- ...current?.eve,
3096
- ...next.eve,
3097
- inputRequest: next.eve?.inputRequest ?? current?.eve?.inputRequest,
3098
- inputResponse: next.eve?.inputResponse ?? current?.eve?.inputResponse,
3099
- kind,
3100
- name
3101
- } };
3247
+ function updateTurn(state, turnId, update) {
3248
+ const turn = state.turns[turnId];
3249
+ if (turn === void 0) return state;
3250
+ const next = update(turn);
3251
+ return next === turn ? state : {
3252
+ ...state,
3253
+ turns: {
3254
+ ...state.turns,
3255
+ [turnId]: next
3256
+ }
3257
+ };
3102
3258
  }
3103
- function approvedApproval(part) {
3104
- if (!part?.approval?.id) return;
3259
+ function updateTask(state, taskId, update) {
3260
+ const task = state.tasks[taskId];
3261
+ if (task === void 0) return state;
3262
+ const next = update(task);
3263
+ return next === task ? state : {
3264
+ ...state,
3265
+ tasks: {
3266
+ ...state.tasks,
3267
+ [taskId]: next
3268
+ }
3269
+ };
3270
+ }
3271
+ function updateObservation(state, sessionId, update) {
3272
+ const agent = state.agents[sessionId];
3273
+ if (agent === void 0) return state;
3274
+ const observation = update(agent.observation);
3275
+ if (observation === agent.observation) return state;
3105
3276
  return {
3106
- approved: true,
3107
- id: part.approval.id,
3108
- isAutomatic: part.approval.isAutomatic,
3109
- reason: part.approval.reason
3277
+ ...state,
3278
+ agents: {
3279
+ ...state.agents,
3280
+ [sessionId]: {
3281
+ ...agent,
3282
+ observation
3283
+ }
3284
+ }
3110
3285
  };
3111
3286
  }
3112
- function normalizeActionRequest(action) {
3113
- const name = actionRequestName(action);
3114
- switch (action.kind) {
3115
- case "load-skill": return {
3116
- kind: "load-skill",
3117
- name,
3118
- toolName: "eve:load-skill"
3119
- };
3120
- case "tool-call":
3121
- case "workflow-tool-call": return {
3122
- kind: "tool-call",
3123
- name,
3124
- toolName: name
3125
- };
3126
- case "subagent-call":
3127
- case "remote-agent-call": return {
3128
- kind: "subagent-call",
3129
- name,
3130
- toolName: `eve:subagent:${name}`
3131
- };
3132
- }
3287
+ function observedConversation(observation) {
3288
+ return observation.status === "not-followed" ? void 0 : observation.conversation;
3133
3289
  }
3134
- function normalizeActionResult(result) {
3135
- switch (result.kind) {
3136
- case "load-skill-result": return {
3137
- kind: "load-skill",
3138
- name: result.name ?? "load_skill",
3139
- toolName: "eve:load-skill"
3140
- };
3141
- case "tool-result": return {
3142
- kind: "tool-call",
3143
- name: result.toolName,
3144
- toolName: result.toolName
3290
+ function reduceConversationLifecycle(state, event) {
3291
+ switch (event.type) {
3292
+ case "turn.started": return {
3293
+ ...state,
3294
+ activeTurnId: event.data.turnId,
3295
+ turns: {
3296
+ ...state.turns,
3297
+ [event.data.turnId]: {
3298
+ turnId: event.data.turnId,
3299
+ status: "active"
3300
+ }
3301
+ }
3145
3302
  };
3146
- case "subagent-result": return {
3147
- kind: "subagent-call",
3148
- name: result.subagentName,
3149
- toolName: `eve:subagent:${result.subagentName}`
3303
+ case "turn.waiting": return updateTurn(state, event.data.turnId, (turn) => turn.status === "active" && !turn.waiting ? {
3304
+ ...turn,
3305
+ waiting: true
3306
+ } : turn);
3307
+ case "step.started": return updateTurn(state, event.data.turnId, (turn) => turn.waiting ? {
3308
+ turnId: turn.turnId,
3309
+ status: turn.status
3310
+ } : turn);
3311
+ case "turn.completed":
3312
+ case "turn.cancelled":
3313
+ case "turn.failed": {
3314
+ const { turnId } = event.data;
3315
+ return {
3316
+ ...state,
3317
+ activeTurnId: state.activeTurnId === turnId ? void 0 : state.activeTurnId,
3318
+ turns: {
3319
+ ...state.turns,
3320
+ [turnId]: {
3321
+ turnId,
3322
+ status: event.type === "turn.completed" ? "completed" : event.type === "turn.failed" ? "failed" : "cancelled"
3323
+ }
3324
+ }
3325
+ };
3326
+ }
3327
+ case "session.waiting":
3328
+ case "session.completed":
3329
+ case "session.failed": return state.activeTurnId === void 0 ? state : {
3330
+ ...state,
3331
+ activeTurnId: void 0
3150
3332
  };
3333
+ case "task.started": {
3334
+ const { callId, kind, name, taskId, turnId } = event.data;
3335
+ const task = state.tasks[taskId] ?? {
3336
+ taskId,
3337
+ name,
3338
+ kind,
3339
+ calls: {}
3340
+ };
3341
+ if (task.calls[callId] !== void 0) return state;
3342
+ return {
3343
+ ...state,
3344
+ tasks: {
3345
+ ...state.tasks,
3346
+ [taskId]: {
3347
+ ...task,
3348
+ calls: {
3349
+ ...task.calls,
3350
+ [callId]: {
3351
+ callId,
3352
+ turnId,
3353
+ status: "working"
3354
+ }
3355
+ }
3356
+ }
3357
+ }
3358
+ };
3359
+ }
3360
+ case "task.settled": {
3361
+ const { callId, error, output, status, taskId } = event.data;
3362
+ return updateTask(state, taskId, (task) => {
3363
+ const call = task.calls[callId];
3364
+ if (call === void 0 || call.status !== "working") return task;
3365
+ const settled = {
3366
+ callId,
3367
+ turnId: call.turnId,
3368
+ status
3369
+ };
3370
+ return {
3371
+ ...task,
3372
+ calls: {
3373
+ ...task.calls,
3374
+ [callId]: status === "completed" && output !== void 0 ? {
3375
+ ...settled,
3376
+ output
3377
+ } : status === "failed" && error !== void 0 ? {
3378
+ ...settled,
3379
+ error
3380
+ } : settled
3381
+ }
3382
+ };
3383
+ });
3384
+ }
3385
+ case "agent.started": {
3386
+ const { callId, name, sessionId, taskId, turnId } = event.data;
3387
+ if (state.agents[sessionId] !== void 0) return state;
3388
+ const agent = {
3389
+ sessionId,
3390
+ name,
3391
+ callId,
3392
+ turnId,
3393
+ observation: { status: "not-followed" }
3394
+ };
3395
+ if (taskId !== void 0) agent.taskId = taskId;
3396
+ return {
3397
+ ...state,
3398
+ agents: {
3399
+ ...state.agents,
3400
+ [sessionId]: agent
3401
+ }
3402
+ };
3403
+ }
3404
+ case "input.requested": {
3405
+ const inputs = { ...state.inputs };
3406
+ for (const request of event.data.requests) {
3407
+ if (inputs[request.requestId] !== void 0) continue;
3408
+ const input = {
3409
+ request,
3410
+ turnId: event.data.turnId,
3411
+ stepIndex: event.data.stepIndex,
3412
+ status: "open"
3413
+ };
3414
+ if (event.data.taskId !== void 0) input.taskId = event.data.taskId;
3415
+ inputs[request.requestId] = input;
3416
+ }
3417
+ return {
3418
+ ...state,
3419
+ inputs
3420
+ };
3421
+ }
3422
+ case "client.input.responded": {
3423
+ const inputs = { ...state.inputs };
3424
+ for (const response of event.data.responses) {
3425
+ const current = inputs[response.requestId];
3426
+ if (current?.status !== "open") continue;
3427
+ inputs[response.requestId] = {
3428
+ ...current,
3429
+ response,
3430
+ status: "responded"
3431
+ };
3432
+ }
3433
+ return {
3434
+ ...state,
3435
+ inputs
3436
+ };
3437
+ }
3438
+ case "approval.candidate": {
3439
+ const current = state.inputs[event.data.requestId];
3440
+ if (current === void 0 || current.status === "settled") return state;
3441
+ if (event.data.outcome === "pending") return state;
3442
+ return {
3443
+ ...state,
3444
+ inputs: {
3445
+ ...state.inputs,
3446
+ [event.data.requestId]: {
3447
+ ...current,
3448
+ status: "open",
3449
+ response: void 0
3450
+ }
3451
+ }
3452
+ };
3453
+ }
3454
+ case "approval.settled": {
3455
+ const current = state.inputs[event.data.requestId];
3456
+ if (current === void 0 || current.status === "settled") return state;
3457
+ return {
3458
+ ...state,
3459
+ inputs: {
3460
+ ...state.inputs,
3461
+ [event.data.requestId]: {
3462
+ ...current,
3463
+ status: "settled",
3464
+ outcome: event.data.outcome
3465
+ }
3466
+ }
3467
+ };
3468
+ }
3469
+ case "input.resolved": {
3470
+ const inputs = { ...state.inputs };
3471
+ for (const resolution of event.data.resolutions) {
3472
+ const current = inputs[resolution.requestId];
3473
+ if (current === void 0 || current.status === "settled") continue;
3474
+ inputs[resolution.requestId] = {
3475
+ ...current,
3476
+ status: "settled",
3477
+ outcome: resolution.outcome,
3478
+ response: resolution.response ?? current.response
3479
+ };
3480
+ }
3481
+ return {
3482
+ ...state,
3483
+ inputs
3484
+ };
3485
+ }
3486
+ default: return state;
3151
3487
  }
3152
3488
  }
3153
- function stringifyUnknown(value) {
3154
- if (typeof value === "string") return value;
3155
- try {
3156
- return JSON.stringify(value);
3157
- } catch {
3158
- return "Action failed.";
3489
+ const messageReducer = defaultMessageReducer();
3490
+ function reduceConversation(state, event) {
3491
+ switch (event.type) {
3492
+ case "client.agent.following": return updateObservation(state, event.data.sessionId, (observation) => observation.status === "following" ? observation : {
3493
+ status: "following",
3494
+ conversation: observedConversation(observation) ?? initialConversationState()
3495
+ });
3496
+ case "client.agent.observed": return updateObservation(state, event.data.sessionId, (observation) => observation.status === "following" ? {
3497
+ status: "following",
3498
+ conversation: reduceConversation(observation.conversation, event.data.event)
3499
+ } : observation);
3500
+ case "client.agent.idle": return updateObservation(state, event.data.sessionId, (observation) => observation.status === "following" ? {
3501
+ status: "idle",
3502
+ conversation: observation.conversation
3503
+ } : observation);
3504
+ case "client.agent.unavailable": return updateObservation(state, event.data.sessionId, (observation) => {
3505
+ const conversation = observedConversation(observation);
3506
+ return conversation === void 0 ? { status: "unavailable" } : {
3507
+ status: "unavailable",
3508
+ conversation
3509
+ };
3510
+ });
3511
+ default: {
3512
+ const projected = messageReducer.reduce(state, event);
3513
+ return reduceConversationLifecycle({
3514
+ ...state,
3515
+ ...projected
3516
+ }, event);
3517
+ }
3159
3518
  }
3160
3519
  }
3520
+ const canonicalConversationReducer = {
3521
+ initial: initialConversationState,
3522
+ reduce: reduceConversation
3523
+ };
3524
+ const conversationReducer = canonicalConversationReducer;
3161
3525
 
3162
3526
  //#endregion
3163
- //#region src/client/message-reducer-primitives.ts
3164
- function projectReceivedParts(parts, message) {
3165
- return parts?.map((part) => part.type === "text" ? {
3166
- state: "done",
3167
- text: part.text,
3168
- type: "text"
3169
- } : {
3170
- filename: part.filename,
3171
- mediaType: part.mediaType,
3172
- size: part.size,
3173
- type: "file",
3174
- url: part.url
3175
- }) ?? [{
3176
- state: "done",
3177
- text: message,
3178
- type: "text"
3179
- }];
3527
+ //#region src/protocol/event-dedupe.ts
3528
+ function createEventDeduper() {
3529
+ const seen = /* @__PURE__ */ new Set();
3530
+ return {
3531
+ admit(event) {
3532
+ const id = event.meta?.id;
3533
+ if (id === void 0) return true;
3534
+ if (seen.has(id)) return false;
3535
+ seen.add(id);
3536
+ return true;
3537
+ },
3538
+ get size() {
3539
+ return seen.size;
3540
+ }
3541
+ };
3180
3542
  }
3181
- function partKey(part) {
3182
- switch (part.type) {
3183
- case "text": return `text:${part.stepIndex ?? 0}`;
3184
- case "reasoning": return `reasoning:${part.stepIndex ?? 0}`;
3185
- case "file": return `file:${part.stepIndex ?? 0}:${part.filename ?? part.url ?? part.mediaType}`;
3186
- case "step-start": return "step-start";
3187
- case "authorization": return `authorization:${part.turnId}:${part.stepIndex}:${part.name}`;
3188
- case "dynamic-tool": return `dynamic-tool:${part.toolCallId}`;
3543
+
3544
+ //#endregion
3545
+ //#region src/client/session-event-stream.ts
3546
+ var SessionEventStream = class {
3547
+ #controller = new AbortController();
3548
+ #readers = /* @__PURE__ */ new Set();
3549
+ #caughtUp = Promise.withResolvers();
3550
+ caughtUp = this.#caughtUp.promise;
3551
+ #ended = false;
3552
+ #error;
3553
+ #headers;
3554
+ #reconnectPolicy;
3555
+ constructor(session, options) {
3556
+ this.setOptions(options);
3557
+ this.caughtUp.catch(() => {});
3558
+ if (!options.catchUp) this.#caughtUp.resolve();
3559
+ (async () => {
3560
+ try {
3561
+ for await (const event of followClientSession(session, {
3562
+ signal: this.#controller.signal,
3563
+ resolveHeaders: () => this.#headers,
3564
+ resolveReconnectPolicy: () => this.#reconnectPolicy,
3565
+ startIndex: options.startIndex,
3566
+ onCaughtUp: options.catchUp ? () => this.#caughtUp.resolve() : void 0
3567
+ })) {
3568
+ if (this.#controller.signal.aborted) return;
3569
+ options.onEvent(event);
3570
+ for (const reader of this.#readers) reader.push(event);
3571
+ if (event.type === "session.completed" || event.type === "session.failed") break;
3572
+ }
3573
+ this.#caughtUp.resolve();
3574
+ this.#finish();
3575
+ } catch (error) {
3576
+ this.#caughtUp.reject(error);
3577
+ this.#finish(error);
3578
+ if (!this.#controller.signal.aborted) options.onError(error);
3579
+ }
3580
+ })();
3581
+ }
3582
+ subscribe(signal) {
3583
+ const reader = new SessionEventReader(() => this.#readers.delete(reader), signal);
3584
+ if (this.#ended) reader.end(this.#error);
3585
+ else this.#readers.add(reader);
3586
+ return reader;
3587
+ }
3588
+ get ended() {
3589
+ return this.#ended;
3590
+ }
3591
+ setOptions(options) {
3592
+ if ("headers" in options) this.#headers = options.headers;
3593
+ if ("streamReconnectPolicy" in options) this.#reconnectPolicy = options.streamReconnectPolicy;
3594
+ }
3595
+ close() {
3596
+ const error = new DOMException("Session stream was detached.", "AbortError");
3597
+ this.#controller.abort(error);
3598
+ this.#caughtUp.reject(error);
3599
+ this.#finish(error);
3600
+ }
3601
+ #finish(error) {
3602
+ if (this.#ended) return;
3603
+ this.#ended = true;
3604
+ this.#error = error;
3605
+ for (const reader of this.#readers) reader.end(error);
3606
+ }
3607
+ };
3608
+ var SessionEventReader = class {
3609
+ #events = [];
3610
+ #wake = Promise.withResolvers();
3611
+ #ended = false;
3612
+ #error;
3613
+ #dispose;
3614
+ constructor(unsubscribe, signal) {
3615
+ const abort = () => this.end(signal?.reason);
3616
+ signal?.addEventListener("abort", abort, { once: true });
3617
+ this.#dispose = () => {
3618
+ signal?.removeEventListener("abort", abort);
3619
+ unsubscribe();
3620
+ };
3621
+ if (signal?.aborted) abort();
3622
+ }
3623
+ push(event) {
3624
+ if (this.#ended) return;
3625
+ this.#events.push(event);
3626
+ this.#wake.resolve();
3627
+ }
3628
+ end(error) {
3629
+ if (this.#ended) return;
3630
+ this.#ended = true;
3631
+ this.#error = error;
3632
+ this.#wake.resolve();
3633
+ }
3634
+ [Symbol.dispose]() {
3635
+ this.end();
3636
+ this.#events = [];
3637
+ this.#dispose();
3189
3638
  }
3190
- }
3191
- function upsertMessage(data, next) {
3192
- const index = data.messages.findIndex((message) => message.id === next.id);
3193
- if (index === -1) return { messages: [...data.messages, next] };
3194
- return { messages: [
3195
- ...data.messages.slice(0, index),
3196
- next,
3197
- ...data.messages.slice(index + 1)
3198
- ] };
3199
- }
3200
- function removeStreamingToolPartsForTurn(data, turnId) {
3201
- const index = data.messages.findIndex((message) => message.role === "assistant" && message.metadata?.turnId === turnId);
3202
- const message = data.messages[index];
3203
- if (message === void 0) return data;
3204
- return upsertMessage(data, {
3205
- ...message,
3206
- parts: message.parts.filter((part) => part.type !== "dynamic-tool" || part.state !== "input-streaming")
3207
- });
3208
- }
3209
- function optimisticUserMessageId(submissionId) {
3210
- return `optimistic:${submissionId}:user`;
3211
- }
3639
+ discard() {
3640
+ this.#events = [];
3641
+ }
3642
+ async *[Symbol.asyncIterator]() {
3643
+ for (;;) {
3644
+ while (this.#events.length > 0) yield this.#events.shift();
3645
+ if (this.#ended) {
3646
+ if (this.#error !== void 0) throw this.#error;
3647
+ return;
3648
+ }
3649
+ this.#wake = Promise.withResolvers();
3650
+ await this.#wake.promise;
3651
+ }
3652
+ }
3653
+ };
3212
3654
 
3213
3655
  //#endregion
3214
- //#region src/client/message-run-parts.ts
3215
- function append(message, append) {
3216
- const current = latestStreamingRun(message, append.type, append.stepIndex);
3217
- return upsert(message, {
3218
- state: "streaming",
3219
- stepIndex: append.stepIndex,
3220
- text: (current?.text ?? "") + append.delta,
3221
- type: append.type
3222
- });
3223
- }
3224
- function latestStreamingRun(message, type, stepIndex) {
3225
- for (let index = message.parts.length - 1; index >= 0; index -= 1) {
3226
- const part = message.parts[index];
3227
- if (part?.type === type && part.stepIndex === stepIndex) return part.state === "streaming" ? part : void 0;
3656
+ //#region src/client/conversation-client.ts
3657
+ var ConversationClient = class {
3658
+ projection;
3659
+ #conversation;
3660
+ #cursors = /* @__PURE__ */ new Map();
3661
+ #seenEvents = createEventDeduper();
3662
+ #follower;
3663
+ #stream;
3664
+ #onChange;
3665
+ #onConversationChange;
3666
+ constructor(projection, onChange, onConversationChange) {
3667
+ this.projection = projection;
3668
+ this.#conversation = projection.reducer === conversationReducer ? projection : new EveAgentProjection(canonicalConversationReducer, []);
3669
+ this.#onChange = onChange;
3670
+ this.#onConversationChange = onConversationChange;
3228
3671
  }
3229
- }
3230
- function upsert(message, next) {
3231
- let lastIndex = -1;
3232
- for (let index = message.parts.length - 1; index >= 0; index -= 1) {
3233
- const part = message.parts[index];
3234
- if (part?.type === next.type && part.stepIndex === next.stepIndex) {
3235
- lastIndex = index;
3236
- break;
3672
+ get data() {
3673
+ return this.projection.data;
3674
+ }
3675
+ get conversation() {
3676
+ return this.#conversation.data;
3677
+ }
3678
+ get projections() {
3679
+ return this.#conversation === this.projection ? [this.projection] : [this.#conversation, this.projection];
3680
+ }
3681
+ get following() {
3682
+ return this.#follower !== void 0;
3683
+ }
3684
+ append(event) {
3685
+ const previous = this.data;
3686
+ const previousConversation = this.conversation;
3687
+ this.#appendRoot(event);
3688
+ if (previous !== this.data) this.#onChange(this.data, previous);
3689
+ else if (previousConversation !== this.conversation) this.#onConversationChange?.(this.conversation, previousConversation);
3690
+ }
3691
+ projectResponses(responses) {
3692
+ if (!responses?.length) return void 0;
3693
+ const event = {
3694
+ data: {
3695
+ createdAt: Date.now(),
3696
+ responses
3697
+ },
3698
+ type: "client.input.responded"
3699
+ };
3700
+ this.append(event);
3701
+ return () => this.#retract(event);
3702
+ }
3703
+ replaceResponses(retract, input) {
3704
+ retract?.();
3705
+ assertAnswerable(input, this.conversation);
3706
+ return this.projectResponses(input.inputResponses);
3707
+ }
3708
+ #retract(event) {
3709
+ const previous = this.data;
3710
+ const previousConversation = this.conversation;
3711
+ for (const projection of this.projections) projection.remove((entry) => entry === event);
3712
+ if (previous !== this.data) this.#onChange(this.data, previous);
3713
+ else if (previousConversation !== this.conversation) this.#onConversationChange?.(this.conversation, previousConversation);
3714
+ }
3715
+ observe(event, options = {}) {
3716
+ if (!this.#seenEvents.admit(event)) return false;
3717
+ options.onAccepted?.(event);
3718
+ const previous = this.data;
3719
+ const previousConversation = this.conversation;
3720
+ if (options.project) options.project(event);
3721
+ else this.#appendRoot(event);
3722
+ if (options.notify !== false) {
3723
+ if (previous !== this.data) this.#onChange(this.data, previous);
3724
+ else if (previousConversation !== this.conversation) this.#onConversationChange?.(this.conversation, previousConversation);
3237
3725
  }
3726
+ this.#follower?.acceptParentEvent(event);
3727
+ this.#follower?.reconcile();
3728
+ return true;
3729
+ }
3730
+ hydrate(event) {
3731
+ if (!this.#seenEvents.admit(event)) return false;
3732
+ this.#appendRoot(event);
3733
+ return true;
3734
+ }
3735
+ follow(session, events = []) {
3736
+ this.#follower?.abortAll();
3737
+ const follower = new AgentStreamFollower({
3738
+ session,
3739
+ cursors: this.#cursors,
3740
+ getState: () => this.conversation,
3741
+ onFollowing: (sessionId) => this.#appendChild({
3742
+ type: "client.agent.following",
3743
+ data: { sessionId }
3744
+ }),
3745
+ onEvent: (sessionId, event) => this.#appendChild({
3746
+ type: "client.agent.observed",
3747
+ data: {
3748
+ sessionId,
3749
+ event
3750
+ }
3751
+ }),
3752
+ onIdle: (sessionId) => this.#appendChild({
3753
+ type: "client.agent.idle",
3754
+ data: { sessionId }
3755
+ }),
3756
+ onUnavailable: (sessionId) => this.#appendChild({
3757
+ type: "client.agent.unavailable",
3758
+ data: { sessionId }
3759
+ })
3760
+ });
3761
+ this.#follower = follower;
3762
+ for (const event of events) follower.acceptParentEvent(event);
3763
+ follower.reconcile();
3764
+ }
3765
+ #appendRoot(event) {
3766
+ for (const projection of this.projections) projection.append(event);
3767
+ }
3768
+ #appendChild(event) {
3769
+ const previous = this.data;
3770
+ const previousConversation = this.conversation;
3771
+ this.#conversation.append(event);
3772
+ if (previous !== this.data) this.#onChange(this.data, previous);
3773
+ else if (previousConversation !== this.conversation) this.#onConversationChange?.(this.conversation, previousConversation);
3774
+ }
3775
+ stream(session, options) {
3776
+ if (this.#stream !== void 0 && !this.#stream.ended) {
3777
+ this.#stream.setOptions(options);
3778
+ return this.#stream;
3779
+ }
3780
+ this.#stream = new SessionEventStream(session, options);
3781
+ return this.#stream;
3782
+ }
3783
+ stop() {
3784
+ this.#follower?.abortAll();
3785
+ this.#follower = void 0;
3786
+ this.#stream?.close();
3787
+ this.#stream = void 0;
3788
+ }
3789
+ reset() {
3790
+ this.stop();
3791
+ this.#cursors.clear();
3792
+ this.#seenEvents = createEventDeduper();
3793
+ for (const projection of this.projections) projection.reset();
3238
3794
  }
3239
- const parts = lastIndex !== -1 && message.parts[lastIndex].state === "streaming" ? [
3240
- ...message.parts.slice(0, lastIndex),
3241
- next,
3242
- ...message.parts.slice(lastIndex + 1)
3243
- ] : [...message.parts, next];
3244
- return {
3245
- ...message,
3246
- metadata: {
3247
- ...message.metadata,
3248
- status: next.type === "text" && next.state === "done" ? "complete" : "streaming"
3249
- },
3250
- parts
3251
- };
3252
- }
3253
- const messageRun = {
3254
- append,
3255
- upsert
3256
3795
  };
3257
3796
 
3258
3797
  //#endregion
3259
- //#region src/client/message-task-parts.ts
3260
- function createSettledTaskPart(existing, event) {
3261
- const settledPartBase = {
3262
- approval: approvedApproval(existing),
3263
- input: existing.input,
3264
- stepIndex: existing.stepIndex,
3265
- toolCallId: existing.toolCallId,
3266
- toolMetadata: existing.toolMetadata,
3267
- toolName: existing.toolName,
3268
- type: "dynamic-tool"
3269
- };
3270
- switch (event.data.status) {
3271
- case "completed": return {
3272
- ...settledPartBase,
3273
- output: event.data.output,
3274
- state: "output-available"
3275
- };
3276
- case "failed": return {
3277
- ...settledPartBase,
3278
- errorText: event.data.error?.message ?? "Task failed.",
3279
- state: "output-error"
3798
+ //#region src/client/session-turn-dispatch.ts
3799
+ async function dispatchSessionTurn(input) {
3800
+ const { client, session, turn, beforeSend } = input;
3801
+ if (session === void 0) {
3802
+ if (client === void 0) throw new Error("An external eve session is required before sending.");
3803
+ if (turn.message === void 0) throw new Error("Cannot answer an input request before the session starts.");
3804
+ const created = await client.sessions.create({
3805
+ ...turn,
3806
+ message: turn.message
3807
+ });
3808
+ turn.signal?.throwIfAborted();
3809
+ return {
3810
+ ...created,
3811
+ created: true
3280
3812
  };
3281
- case "cancelled": return {
3282
- ...settledPartBase,
3283
- errorText: "Task was cancelled.",
3284
- state: "output-error"
3813
+ }
3814
+ beforeSend?.();
3815
+ if (turn.inputResponses === void 0) {
3816
+ const { message, ...options } = turn;
3817
+ return {
3818
+ session,
3819
+ response: await session.send(message, options),
3820
+ created: false
3285
3821
  };
3286
3822
  }
3287
- }
3288
-
3289
- //#endregion
3290
- //#region src/client/message-reducer.ts
3291
- function receivedMessageEventId(event) {
3292
- return event.meta.id ?? `${event.data.turnId}:${event.data.sequence}`;
3293
- }
3294
- function defaultMessageReducer() {
3823
+ const { inputResponses, ...options } = turn;
3295
3824
  return {
3296
- initial() {
3297
- return { messages: [] };
3298
- },
3299
- reduce(data, event) {
3300
- return reduceMessageData(data, event);
3301
- }
3825
+ session,
3826
+ response: await session.respond(inputResponses, options),
3827
+ created: false
3302
3828
  };
3303
3829
  }
3304
- function reduceMessageData(data, event) {
3305
- switch (event.type) {
3306
- case "client.message.submitted": return upsertMessage(data, {
3307
- id: optimisticUserMessageId(event.data.submissionId),
3308
- metadata: {
3309
- optimistic: true,
3310
- status: "submitted"
3311
- },
3312
- parts: [{
3313
- type: "text",
3314
- text: event.data.message
3315
- }],
3316
- role: "user"
3317
- });
3318
- case "client.message.failed": return upsertMessage(data, {
3319
- id: optimisticUserMessageId(event.data.submissionId),
3320
- metadata: {
3321
- optimistic: true,
3322
- status: "failed"
3323
- },
3324
- parts: [{
3325
- type: "text",
3326
- text: event.data.message
3327
- }],
3328
- role: "user"
3830
+
3831
+ //#endregion
3832
+ //#region src/client/eve-agent-store.ts
3833
+ const detachStore = Symbol("detachEveAgentStore");
3834
+ const attachStore = Symbol("attachEveAgentStore");
3835
+ var EveAgentStore = class {
3836
+ #client;
3837
+ #autoPrewarm;
3838
+ #attached = false;
3839
+ #conversationClient;
3840
+ #followChildStreams;
3841
+ #externalSession;
3842
+ #subscribers = /* @__PURE__ */ new Set();
3843
+ #activeTurn;
3844
+ #callbacks = {};
3845
+ #error;
3846
+ #events;
3847
+ #messageSubmissions;
3848
+ #prewarmGeneration = 0;
3849
+ #prewarmPromise;
3850
+ #prewarmController;
3851
+ #resumePromise;
3852
+ #session;
3853
+ #snapshot;
3854
+ #status = "ready";
3855
+ constructor(init) {
3856
+ this.#autoPrewarm = init.prewarm ?? false;
3857
+ this.#followChildStreams = init.followSubagents ?? false;
3858
+ this.#externalSession = init.session !== void 0;
3859
+ this.#client = this.#externalSession ? void 0 : init.client ?? new Client({
3860
+ auth: init.auth,
3861
+ headers: init.headers,
3862
+ host: init.host ?? ""
3329
3863
  });
3330
- case "input.resolved": {
3331
- let next = data;
3332
- for (const resolution of event.data.resolutions) next = resolveInputRequest(next, resolution);
3333
- return next;
3334
- }
3335
- case "message.received": return upsertMessage(data, {
3336
- id: `${receivedMessageEventId(event)}:user`,
3337
- metadata: {
3338
- status: "complete",
3339
- turnId: event.data.turnId
3340
- },
3341
- parts: projectReceivedParts(event.data.parts, event.data.message),
3342
- role: "user"
3864
+ this.#conversationClient = new ConversationClient(new EveAgentProjection(init.reducer, []), () => this.#publish(), () => this.#publish());
3865
+ this.#events = (init.initialEvents ?? []).filter((event) => this.#conversationClient.hydrate(event));
3866
+ this.#messageSubmissions = new OptimisticMessageSubmissions(this.#conversationClient.projections, init.optimistic ?? true);
3867
+ this.#session = init.session ?? (init.initialSession === void 0 ? void 0 : this.#client?.sessions.attach(init.initialSession.sessionId, { streamIndex: init.initialSession.streamIndex }));
3868
+ this.#snapshot = this.#createSnapshot();
3869
+ }
3870
+ get snapshot() {
3871
+ return this.#snapshot;
3872
+ }
3873
+ setCallbacks(callbacks) {
3874
+ this.#callbacks = callbacks;
3875
+ }
3876
+ subscribe(callback) {
3877
+ this.#subscribers.add(callback);
3878
+ return () => void this.#subscribers.delete(callback);
3879
+ }
3880
+ prewarm() {
3881
+ if (this.#prewarmPromise !== void 0) return this.#prewarmPromise;
3882
+ if (this.#session !== void 0 || this.#externalSession) return Promise.resolve();
3883
+ if (this.#activeTurn !== void 0) return this.#activeTurn.response.then((response) => {
3884
+ if (response === void 0) throw this.#error ?? new DOMException("Session creation was aborted.", "AbortError");
3343
3885
  });
3344
- case "step.started": return updateAssistantMessage(data, event.data.turnId, (message) => ensureStepStartPart(message, event.data.stepIndex));
3345
- case "reasoning.appended": return updateAssistantMessage(data, event.data.turnId, (message) => messageRun.append(ensureStepStartPart(message, event.data.stepIndex), {
3346
- delta: event.data.reasoningDelta,
3347
- stepIndex: event.data.stepIndex,
3348
- type: "reasoning"
3349
- }));
3350
- case "reasoning.completed": return updateAssistantMessage(data, event.data.turnId, (message) => messageRun.upsert(ensureStepStartPart(message, event.data.stepIndex), {
3351
- state: "done",
3352
- stepIndex: event.data.stepIndex,
3353
- text: event.data.reasoning,
3354
- type: "reasoning"
3355
- }));
3356
- case "action.input.appended": {
3357
- const existing = findToolPart(data, event.data.callId);
3358
- if (existing !== void 0 && existing.state !== "input-streaming") return data;
3359
- const nextPart = {
3360
- input: void 0,
3361
- inputText: (existing?.state === "input-streaming" ? existing.inputText : "") + event.data.inputTextDelta,
3362
- state: "input-streaming",
3363
- stepIndex: event.data.stepIndex,
3364
- toolCallId: event.data.callId,
3365
- toolMetadata: existing?.toolMetadata ?? { eve: {
3366
- kind: "unknown",
3367
- name: event.data.toolName
3368
- } },
3369
- toolName: event.data.toolName,
3370
- type: "dynamic-tool"
3371
- };
3372
- if (existing !== void 0) return updateToolPart(data, event.data.callId, nextPart);
3373
- return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), nextPart));
3374
- }
3375
- case "actions.requested": {
3376
- let next = data;
3377
- for (const action of event.data.actions) {
3378
- const descriptor = normalizeActionRequest(action);
3379
- next = updateAssistantMessage(next, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
3380
- input: "input" in action ? action.input : void 0,
3381
- state: "input-available",
3382
- stepIndex: event.data.stepIndex,
3383
- toolCallId: action.callId,
3384
- toolMetadata: createToolMetadata(descriptor),
3385
- toolName: descriptor.toolName,
3386
- type: "dynamic-tool"
3387
- }));
3886
+ const client = this.#client;
3887
+ if (client === void 0) return Promise.reject(/* @__PURE__ */ new Error("This eve agent store does not own a session client."));
3888
+ const generation = this.#prewarmGeneration;
3889
+ const controller = new AbortController();
3890
+ this.#prewarmController = controller;
3891
+ const promise = (async () => {
3892
+ try {
3893
+ const created = await client.sessions.create({ signal: controller.signal });
3894
+ if (generation !== this.#prewarmGeneration) return;
3895
+ this.#error = void 0;
3896
+ if (this.#status === "error") this.#status = "ready";
3897
+ this.#adoptSession(created.session);
3898
+ this.#ensureStream();
3899
+ } catch (error) {
3900
+ if (generation === this.#prewarmGeneration && this.#activeTurn === void 0 && this.#error === void 0) this.#fail(error);
3901
+ throw error;
3902
+ }
3903
+ })();
3904
+ this.#prewarmPromise = promise;
3905
+ const clear = () => {
3906
+ if (this.#prewarmPromise === promise) {
3907
+ this.#prewarmPromise = void 0;
3908
+ this.#prewarmController = void 0;
3388
3909
  }
3389
- return next;
3910
+ };
3911
+ promise.then(clear, clear);
3912
+ return promise;
3913
+ }
3914
+ async send(input) {
3915
+ return await this.#submit(input, this.#callbacks.prepareSend);
3916
+ }
3917
+ async #submit(input, prepareSend) {
3918
+ assertAnswerable(input, this.#conversationClient.conversation);
3919
+ if (this.#activeTurn !== void 0) {
3920
+ if (this.#status === "resuming") throw new Error("eve session is resuming.");
3921
+ return await this.#sendFollowUp(this.#activeTurn, input, prepareSend);
3390
3922
  }
3391
- case "input.requested": {
3392
- let next = data;
3393
- for (const request of event.data.requests) {
3394
- const descriptor = normalizeActionRequest(request.action);
3395
- next = updateAssistantMessage(next, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
3396
- approval: { id: request.requestId },
3397
- input: request.action.input,
3398
- state: "approval-requested",
3399
- stepIndex: event.data.stepIndex,
3400
- toolCallId: request.action.callId,
3401
- toolMetadata: createToolMetadata(descriptor, { inputRequest: toMessageInputRequest(request) }),
3402
- toolName: descriptor.toolName,
3403
- type: "dynamic-tool"
3404
- }));
3923
+ const turn = createActiveTurn((turn) => turn.acceptedFollowUps > 0 && this.#session !== void 0 ? this.#session.cancel() : turn.response.then((response) => response === void 0 ? { status: "no_active_turn" } : response.cancel()));
3924
+ this.#activeTurn = turn;
3925
+ this.#error = void 0;
3926
+ this.#status = "submitted";
3927
+ let reader;
3928
+ let submissionId;
3929
+ let retractResponses;
3930
+ try {
3931
+ assertExclusiveTurnInput(input);
3932
+ submissionId = this.#messageSubmissions.submit(input, this.#events.length);
3933
+ retractResponses = this.#conversationClient.projectResponses(input.inputResponses);
3934
+ this.#publish();
3935
+ const preparedInput = await (prepareSend === void 0 ? input : waitWithSignal(Promise.resolve(prepareSend(input)), createAbortSignal(input.signal, turn.abortController.signal)));
3936
+ assertExclusiveTurnInput(preparedInput);
3937
+ if (!this.#isActiveTurn(turn)) return;
3938
+ if (preparedInput !== input) {
3939
+ submissionId = this.#messageSubmissions.resubmit(submissionId, preparedInput);
3940
+ retractResponses = this.#conversationClient.replaceResponses(retractResponses, preparedInput);
3941
+ this.#publish();
3405
3942
  }
3406
- return next;
3943
+ const turnInput = {
3944
+ ...preparedInput,
3945
+ signal: createAbortSignal(preparedInput.signal, turn.abortController.signal)
3946
+ };
3947
+ const dispatched = await this.#dispatchTurn(turnInput);
3948
+ retractResponses = void 0;
3949
+ const response = dispatched.response;
3950
+ reader = dispatched.reader;
3951
+ if (!this.#isActiveTurn(turn)) return;
3952
+ turn.resolveResponse(response);
3953
+ this.#correlate(submissionId, response);
3954
+ for await (const event of consumeMessageResponse(response, reader)) {
3955
+ if (!this.#isActiveTurn(turn)) return;
3956
+ turn.receivedFollowUps += turn.receivedFollowUpEvents.get(event) ?? 0;
3957
+ turn.receivedFollowUpEvents.delete(event);
3958
+ }
3959
+ if (!this.#isActiveTurn(turn)) return;
3960
+ await followSteeredTurns(turn, reader, () => this.#isActiveTurn(turn));
3961
+ if (!this.#isActiveTurn(turn)) return;
3962
+ this.#status = settledStatus(this.#error, this.#conversationClient.conversation);
3963
+ } catch (error) {
3964
+ if (!this.#isActiveTurn(turn)) return;
3965
+ retractResponses?.();
3966
+ if (isAbortError(error)) {
3967
+ this.#status = "ready";
3968
+ this.#messageSubmissions.fail(toError(error), submissionId);
3969
+ } else {
3970
+ const reported = this.#error !== void 0;
3971
+ this.#error ??= toError(error);
3972
+ this.#status = "error";
3973
+ this.#messageSubmissions.fail(this.#error, submissionId);
3974
+ if (!reported) this.#callbacks.onError?.(this.#error);
3975
+ }
3976
+ } finally {
3977
+ reader?.[Symbol.dispose]();
3978
+ this.#finishTurn(turn);
3407
3979
  }
3408
- case "approval.candidate": return data;
3409
- case "approval.settled": {
3410
- const existing = findToolPartByApprovalId(data, event.data.requestId);
3411
- if (existing === void 0) return data;
3412
- if (event.data.outcome === "approved") return updateToolPart(data, existing.toolCallId, {
3413
- approval: {
3414
- approved: true,
3415
- id: event.data.requestId,
3416
- reason: void 0
3417
- },
3418
- input: existing.input,
3419
- state: "approval-responded",
3420
- stepIndex: existing.stepIndex,
3421
- toolCallId: existing.toolCallId,
3422
- toolMetadata: existing.toolMetadata,
3423
- toolName: existing.toolName,
3424
- type: "dynamic-tool"
3425
- });
3426
- return updateToolPart(data, existing.toolCallId, {
3427
- approval: {
3428
- approved: false,
3429
- id: event.data.requestId,
3430
- reason: "Tool execution was cancelled."
3431
- },
3432
- input: existing.input,
3433
- state: "output-denied",
3434
- stepIndex: existing.stepIndex,
3435
- toolCallId: existing.toolCallId,
3436
- toolMetadata: existing.toolMetadata,
3437
- toolName: existing.toolName,
3438
- type: "dynamic-tool"
3980
+ }
3981
+ resume() {
3982
+ if (this.#resumePromise !== void 0) return this.#resumePromise;
3983
+ const promise = this.#resume();
3984
+ this.#resumePromise = promise;
3985
+ const clear = () => {
3986
+ if (this.#resumePromise === promise) this.#resumePromise = void 0;
3987
+ };
3988
+ promise.then(clear, clear);
3989
+ return promise;
3990
+ }
3991
+ async #resume() {
3992
+ if (this.#status !== "ready" && this.#status !== "error") throw new Error("eve session is already processing a turn.");
3993
+ if (this.#session === void 0) throw new Error("An eve session is required before resuming.");
3994
+ const session = this.#session;
3995
+ const turn = createActiveTurn(() => session.cancel());
3996
+ this.#activeTurn = turn;
3997
+ turn.resolveResponse(void 0);
3998
+ this.#error = void 0;
3999
+ this.#status = "resuming";
4000
+ this.#publish();
4001
+ let reader;
4002
+ try {
4003
+ const stream = this.#ensureStream({
4004
+ catchUp: true,
4005
+ startIndex: this.#events.length === session.state.streamIndex ? session.state.streamIndex : 0
3439
4006
  });
4007
+ reader = stream.subscribe(turn.abortController.signal);
4008
+ await stream.caughtUp;
4009
+ if (!this.#isActiveTurn(turn)) return;
4010
+ reader.discard();
4011
+ const tail = this.#events.at(-1);
4012
+ if (tail !== void 0) this.#applyTerminalStreamFailure(tail);
4013
+ if (tail && !this.#error && !isSettledSessionTail(this.#events, this.#conversationClient.conversation)) {
4014
+ this.#status = "streaming";
4015
+ this.#publish();
4016
+ for await (const event of reader) {
4017
+ if (!this.#isActiveTurn(turn)) return;
4018
+ turn.receivedFollowUps += turn.receivedFollowUpEvents.get(event) ?? 0;
4019
+ turn.receivedFollowUpEvents.delete(event);
4020
+ if (isResponseBoundary(event, this.#conversationClient.conversation)) break;
4021
+ }
4022
+ }
4023
+ await followSteeredTurns(turn, reader, () => this.#isActiveTurn(turn));
4024
+ if (this.#isActiveTurn(turn)) this.#status = settledStatus(this.#error, this.#conversationClient.conversation);
4025
+ } catch (error) {
4026
+ if (!this.#isActiveTurn(turn)) return;
4027
+ if (isAbortError(error)) this.#status = "ready";
4028
+ else {
4029
+ this.#error = toError(error);
4030
+ this.#status = "error";
4031
+ this.#callbacks.onError?.(this.#error);
4032
+ }
4033
+ } finally {
4034
+ reader?.[Symbol.dispose]();
4035
+ this.#finishTurn(turn);
3440
4036
  }
3441
- case "action.result": {
3442
- const descriptor = normalizeActionResult(event.data.result);
3443
- const existing = findToolPart(data, event.data.result.callId);
3444
- const denied = event.data.error?.code === "TOOL_EXECUTION_DENIED";
3445
- const failed = event.data.status === "failed" && !denied;
3446
- const approvalId = existing?.approval?.id ?? event.data.result.callId;
3447
- const toolMetadata = mergeToolMetadata(existing?.toolMetadata, createToolMetadata(descriptor));
3448
- const resultPartBase = {
3449
- input: existing?.input,
3450
- stepIndex: event.data.stepIndex,
3451
- toolCallId: event.data.result.callId,
3452
- toolMetadata,
3453
- toolName: existing?.toolName ?? descriptor.toolName,
3454
- type: "dynamic-tool"
3455
- };
3456
- let nextPart;
3457
- if (denied) nextPart = {
3458
- ...resultPartBase,
3459
- approval: {
3460
- approved: false,
3461
- id: approvalId,
3462
- reason: event.data.error?.message
3463
- },
3464
- state: "output-denied"
3465
- };
3466
- else if (failed) nextPart = {
3467
- ...resultPartBase,
3468
- approval: approvedApproval(existing),
3469
- errorText: event.data.error?.message ?? stringifyUnknown(event.data.result.output),
3470
- state: "output-error"
3471
- };
3472
- else nextPart = {
3473
- ...resultPartBase,
3474
- approval: approvedApproval(existing),
3475
- output: event.data.result.output,
3476
- state: "output-available"
3477
- };
3478
- if (existing !== void 0) return updateToolPart(data, event.data.result.callId, nextPart);
3479
- return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), nextPart));
4037
+ }
4038
+ cancel() {
4039
+ const turn = this.#activeTurn;
4040
+ if (turn === void 0) return this.#status === "streaming" && this.#session !== void 0 ? this.#session.cancel() : Promise.resolve({ status: "no_active_turn" });
4041
+ return turn.cancel();
4042
+ }
4043
+ async compact() {
4044
+ return await this.#session?.compact() ?? { status: "no_active_session" };
4045
+ }
4046
+ async clear() {
4047
+ return await this.#session?.clear() ?? { status: "no_active_session" };
4048
+ }
4049
+ async retire() {
4050
+ if (this.#externalSession) throw new Error("retire() needs a store-owned session. Call reset() on the session you supplied, then create a new store for the next session.");
4051
+ const result = await this.#session?.reset() ?? { status: "no_active_session" };
4052
+ this.reset();
4053
+ return result;
4054
+ }
4055
+ [attachStore]() {
4056
+ this.#attached = true;
4057
+ if (this.#followChildStreams && !this.#conversationClient.following) this.#followSubagents();
4058
+ if (this.#autoPrewarm && this.#session === void 0) this.prewarm().catch(() => {});
4059
+ }
4060
+ [detachStore]() {
4061
+ this.#attached = false;
4062
+ this.#conversationClient.stop();
4063
+ this.#activeTurn?.abortController.abort();
4064
+ this.#resetPrewarm();
4065
+ this.#resumePromise = void 0;
4066
+ }
4067
+ reset() {
4068
+ this.#conversationClient.stop();
4069
+ const turn = this.#activeTurn;
4070
+ this.#activeTurn = void 0;
4071
+ turn?.resolveResponse(void 0);
4072
+ turn?.resolveCompletion();
4073
+ turn?.abortController.abort();
4074
+ this.#resetPrewarm();
4075
+ this.#resumePromise = void 0;
4076
+ if (!this.#externalSession) this.#session = void 0;
4077
+ this.#events = [];
4078
+ this.#conversationClient.reset();
4079
+ this.#messageSubmissions.reset();
4080
+ if (this.#followChildStreams && this.#attached) this.#followSubagents();
4081
+ this.#error = void 0;
4082
+ this.#status = "ready";
4083
+ this.#callbacks.onSessionChange?.(this.#session?.state);
4084
+ this.#publish();
4085
+ if (this.#autoPrewarm && this.#attached) this.prewarm().catch(() => {});
4086
+ }
4087
+ async #sendFollowUp(turn, input, prepareSend) {
4088
+ assertInFlightFollowUp(input);
4089
+ const generation = this.#prewarmGeneration;
4090
+ const signal = createAbortSignal(input.signal, turn.abortController.signal);
4091
+ let retractResponses = this.#conversationClient.projectResponses(input.inputResponses);
4092
+ const preparedInput = await waitWithSignal(Promise.resolve(prepareSend?.(input)), signal).then((prepared) => {
4093
+ const next = validateFollowUp(prepared ?? input);
4094
+ if (next === input) return next;
4095
+ retractResponses = this.#conversationClient.replaceResponses(retractResponses, next);
4096
+ return next;
4097
+ }).catch((error) => {
4098
+ retractResponses?.();
4099
+ throw error;
4100
+ });
4101
+ if (generation !== this.#prewarmGeneration) return;
4102
+ if (!this.#isActiveTurn(turn)) {
4103
+ retractResponses?.();
4104
+ return await this.#submit(preparedInput);
4105
+ }
4106
+ const submissionId = this.#messageSubmissions.submit(preparedInput, this.#events.length, activeTurnForOptimisticFollowUp(this.#events));
4107
+ if (submissionId !== void 0) turn.followUpSubmissionIds.add(submissionId);
4108
+ this.#publish();
4109
+ let dispatch;
4110
+ dispatch = (async () => {
4111
+ try {
4112
+ const signal = createAbortSignal(preparedInput.signal, turn.abortController.signal);
4113
+ await waitWithSignal(turn.response, signal);
4114
+ if (!this.#isActiveTurn(turn) || this.#session === void 0) throw new Error("The active eve turn ended before the follow-up could be sent.");
4115
+ this.#ensureStream({
4116
+ headers: preparedInput.headers,
4117
+ streamReconnectPolicy: preparedInput.streamReconnectPolicy
4118
+ });
4119
+ const response = (await dispatchSessionTurn({
4120
+ session: this.#session,
4121
+ turn: {
4122
+ ...preparedInput,
4123
+ signal
4124
+ }
4125
+ })).response;
4126
+ retractResponses = void 0;
4127
+ if (preparedInput.message === void 0) return;
4128
+ turn.acceptedFollowUps += 1;
4129
+ this.#correlate(submissionId, response);
4130
+ } catch (error) {
4131
+ if (this.#isActiveTurn(turn)) {
4132
+ this.#messageSubmissions.fail(toError(error), submissionId);
4133
+ retractResponses?.();
4134
+ this.#publish();
4135
+ }
4136
+ throw error;
4137
+ } finally {
4138
+ turn.followUpDispatches.delete(dispatch);
4139
+ }
4140
+ })();
4141
+ turn.followUpDispatches.add(dispatch);
4142
+ await dispatch;
4143
+ await turn.completion;
4144
+ }
4145
+ async #dispatchTurn(input) {
4146
+ const streamOptions = {
4147
+ headers: input.headers,
4148
+ streamReconnectPolicy: input.streamReconnectPolicy
4149
+ };
4150
+ if (this.#prewarmPromise !== void 0) {
4151
+ await waitWithSignal(this.#prewarmPromise.catch((error) => {
4152
+ if (this.#session !== void 0) throw error;
4153
+ }), input.signal);
4154
+ input.signal?.throwIfAborted();
3480
4155
  }
3481
- case "action.partial": {
3482
- const existing = findToolPart(data, event.data.result.callId);
3483
- if (existing !== void 0 && isSettledToolPart(existing)) return data;
3484
- const descriptor = normalizeActionResult(event.data.result);
3485
- const nextPart = {
3486
- approval: approvedApproval(existing),
3487
- input: existing?.input,
3488
- output: event.data.result.output,
3489
- partial: true,
3490
- state: "output-available",
3491
- stepIndex: event.data.stepIndex,
3492
- toolCallId: event.data.result.callId,
3493
- toolMetadata: mergeToolMetadata(existing?.toolMetadata, createToolMetadata(descriptor)),
3494
- toolName: existing?.toolName ?? descriptor.toolName,
3495
- type: "dynamic-tool"
4156
+ const session = this.#session;
4157
+ let reader;
4158
+ try {
4159
+ const dispatched = await dispatchSessionTurn({
4160
+ client: this.#client,
4161
+ session,
4162
+ turn: input,
4163
+ beforeSend: () => {
4164
+ reader = this.#ensureStream(streamOptions).subscribe(input.signal);
4165
+ }
4166
+ });
4167
+ if (dispatched.created) {
4168
+ this.#adoptSession(dispatched.session);
4169
+ reader = this.#ensureStream(streamOptions).subscribe(input.signal);
4170
+ }
4171
+ return {
4172
+ response: dispatched.response,
4173
+ reader
3496
4174
  };
3497
- if (existing !== void 0) return updateToolPart(data, event.data.result.callId, nextPart);
3498
- return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), nextPart));
3499
- }
3500
- case "task.settled": {
3501
- const existing = findToolPart(data, event.data.callId);
3502
- if (existing === void 0) return data;
3503
- return replaceToolPart(data, createSettledTaskPart(existing, event));
4175
+ } catch (error) {
4176
+ reader?.[Symbol.dispose]();
4177
+ throw error;
3504
4178
  }
3505
- case "authorization.required": return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), createAuthorizationRequiredPart(event)));
3506
- case "authorization.completed": return completeAuthorization(data, event);
3507
- case "message.appended": return updateAssistantMessage(data, event.data.turnId, (message) => messageRun.append(ensureStepStartPart(message, event.data.stepIndex), {
3508
- delta: event.data.messageDelta,
3509
- stepIndex: event.data.stepIndex,
3510
- type: "text"
3511
- }));
3512
- case "message.completed": return updateAssistantMessage(data, event.data.turnId, (message) => {
3513
- return messageRun.upsert(ensureStepStartPart(message, event.data.stepIndex), {
3514
- state: "done",
3515
- stepIndex: event.data.stepIndex,
3516
- text: event.data.message,
3517
- type: "text"
3518
- });
4179
+ }
4180
+ #ensureStream(options = {}) {
4181
+ if (this.#session === void 0) throw new Error("A session is required before opening its stream.");
4182
+ const generation = this.#prewarmGeneration;
4183
+ if (this.#followChildStreams && !this.#conversationClient.following) this.#followSubagents();
4184
+ return this.#conversationClient.stream(this.#session, {
4185
+ ...options,
4186
+ onEvent: (event) => {
4187
+ if (generation === this.#prewarmGeneration) this.#acceptServerEvent(event);
4188
+ },
4189
+ onError: (error) => {
4190
+ if (generation !== this.#prewarmGeneration || this.#activeTurn !== void 0) return;
4191
+ this.#fail(error);
4192
+ }
3519
4193
  });
3520
- case "result.completed": return updateAssistantMetadata(data, event.data.turnId, { result: event.data.result });
3521
- case "turn.completed": return updateAssistantMessage(data, event.data.turnId, (message) => ({
3522
- ...message,
3523
- metadata: {
3524
- ...message.metadata,
3525
- status: "complete"
4194
+ }
4195
+ #adoptSession(session) {
4196
+ this.#session = session;
4197
+ if (this.#followChildStreams && this.#attached) this.#followSubagents();
4198
+ this.#callbacks.onSessionChange?.(session.state);
4199
+ this.#publish();
4200
+ }
4201
+ #fail(error) {
4202
+ this.#error = toError(error);
4203
+ this.#status = "error";
4204
+ this.#callbacks.onError?.(this.#error);
4205
+ this.#publish();
4206
+ }
4207
+ #followSubagents() {
4208
+ if (this.#session) this.#conversationClient.follow(this.#session, this.#events);
4209
+ }
4210
+ #resetPrewarm() {
4211
+ this.#prewarmGeneration += 1;
4212
+ this.#prewarmController?.abort();
4213
+ this.#prewarmController = void 0;
4214
+ this.#prewarmPromise = void 0;
4215
+ }
4216
+ #finishTurn(turn) {
4217
+ if (!this.#isActiveTurn(turn)) return;
4218
+ turn.resolveResponse(void 0);
4219
+ this.#activeTurn = void 0;
4220
+ try {
4221
+ this.#callbacks.onSessionChange?.(this.#session?.state);
4222
+ this.#publish();
4223
+ this.#callbacks.onFinish?.(this.#snapshot);
4224
+ } finally {
4225
+ turn.resolveCompletion();
4226
+ }
4227
+ }
4228
+ #isActiveTurn(turn) {
4229
+ return this.#activeTurn === turn;
4230
+ }
4231
+ #acceptServerEvent(event) {
4232
+ const wasStreaming = this.#status === "streaming";
4233
+ if (!this.#conversationClient.observe(event, {
4234
+ onAccepted: () => {
4235
+ this.#events = [...this.#events, event];
3526
4236
  },
3527
- parts: removeStreamingToolParts(message.parts)
3528
- }));
3529
- case "turn.cancelled": return updateAssistantMessage(data, event.data.turnId, (message) => ({
3530
- ...message,
3531
- metadata: {
3532
- ...message.metadata,
3533
- status: "complete"
4237
+ project: (accepted) => {
4238
+ this.#handleReconciliation(this.#messageSubmissions.apply(accepted));
3534
4239
  },
3535
- parts: removeStreamingToolParts(message.parts.map((part) => (part.type === "text" || part.type === "reasoning") && part.state === "streaming" ? {
3536
- ...part,
3537
- state: "done"
3538
- } : part))
3539
- }));
3540
- case "turn.failed": return removeStreamingToolPartsForTurn(data, event.data.turnId);
3541
- case "session.failed": return data;
3542
- default: return data;
4240
+ notify: false
4241
+ })) return false;
4242
+ this.#callbacks.onEvent?.(event);
4243
+ this.#applyTerminalStreamFailure(event);
4244
+ const { conversation } = this.#conversationClient;
4245
+ const settled = isSettledSessionTail(this.#events, conversation) && conversation.activeTurnId === void 0;
4246
+ if (this.#status !== "resuming" && this.#error === void 0) {
4247
+ if ("data" in event && event.data !== void 0 && "turnId" in event.data) this.#status = "streaming";
4248
+ if (this.#activeTurn === void 0 && settled) this.#status = "ready";
4249
+ }
4250
+ this.#callbacks.onSessionChange?.(this.#session?.state);
4251
+ if (this.#status !== "resuming") this.#publish();
4252
+ if (this.#activeTurn === void 0 && wasStreaming && settled) this.#callbacks.onFinish?.(this.#snapshot);
4253
+ return true;
3543
4254
  }
3544
- }
3545
- function removeStreamingToolParts(parts) {
3546
- return parts.filter((part) => part.type !== "dynamic-tool" || part.state !== "input-streaming");
3547
- }
3548
- function respondToInputRequest(data, response) {
3549
- const existing = findToolPartByApprovalId(data, response.requestId);
3550
- if (!existing) return data;
3551
- const approval = { id: response.requestId };
3552
- if (response.text !== void 0) approval.reason = response.text;
3553
- return updateToolPart(data, existing.toolCallId, {
3554
- approval,
3555
- input: existing.input,
3556
- state: "approval-responded",
3557
- stepIndex: existing.stepIndex,
3558
- toolCallId: existing.toolCallId,
3559
- toolMetadata: mergeToolMetadata(existing.toolMetadata, { eve: {
3560
- inputResponse: response,
3561
- kind: existing.toolMetadata?.eve?.kind ?? "unknown",
3562
- name: existing.toolMetadata?.eve?.name ?? existing.toolName
3563
- } }),
3564
- toolName: existing.toolName,
3565
- type: "dynamic-tool"
3566
- });
3567
- }
3568
- function resolveInputRequest(data, resolution) {
3569
- if (resolution.response !== void 0) return respondToInputRequest(data, resolution.response);
3570
- const existing = findToolPartByApprovalId(data, resolution.requestId);
3571
- if (!existing) return data;
3572
- return updateToolPart(data, existing.toolCallId, {
3573
- input: existing.input,
3574
- output: { status: resolution.outcome },
3575
- state: "output-available",
3576
- stepIndex: existing.stepIndex,
3577
- toolCallId: existing.toolCallId,
3578
- toolMetadata: existing.toolMetadata,
3579
- toolName: existing.toolName,
3580
- type: "dynamic-tool"
3581
- });
3582
- }
3583
- function updateAssistantMessage(data, turnId, update) {
3584
- const message = data.messages.find((message) => message.role === "assistant" && message.metadata?.turnId === turnId) ?? createAssistantMessage(turnId);
3585
- return upsertMessage(data, update(message));
3586
- }
3587
- function updateAssistantMetadata(data, turnId, metadata) {
3588
- return updateAssistantMessage(data, turnId, (message) => ({
3589
- ...message,
3590
- metadata: {
3591
- ...message.metadata,
3592
- ...metadata
4255
+ #correlate(submissionId, response) {
4256
+ const deliveryId = getMessageResponseDeliveryId(response);
4257
+ const reconciled = this.#messageSubmissions.correlate(submissionId, deliveryId, this.#events);
4258
+ if (this.#handleReconciliation(reconciled)) this.#publish();
4259
+ }
4260
+ #handleReconciliation(reconciliation) {
4261
+ if (reconciliation === void 0) return false;
4262
+ if (this.#activeTurn !== void 0) countFollowUpDeliveries(this.#activeTurn, reconciliation);
4263
+ return true;
4264
+ }
4265
+ #applyTerminalStreamFailure(event) {
4266
+ const error = toTerminalStreamFailureError(event);
4267
+ if (error === void 0) return;
4268
+ this.#status = "error";
4269
+ this.#messageSubmissions.failAll(error);
4270
+ if (this.#error === void 0) {
4271
+ this.#error = error;
4272
+ this.#callbacks.onError?.(error);
3593
4273
  }
3594
- }));
3595
- }
3596
- function createAssistantMessage(turnId) {
3597
- return {
3598
- id: `${turnId}:assistant`,
3599
- metadata: {
3600
- status: "streaming",
3601
- turnId
3602
- },
3603
- parts: [],
3604
- role: "assistant"
3605
- };
3606
- }
3607
- function ensureStepStartPart(message, stepIndex) {
3608
- const stepStartCount = message.parts.filter((part) => part.type === "step-start").length;
3609
- if (stepStartCount > stepIndex) return message;
3610
- const missingCount = stepIndex - stepStartCount + 1;
3611
- return {
3612
- ...message,
3613
- parts: [...message.parts, ...Array.from({ length: missingCount }, () => ({ type: "step-start" }))]
3614
- };
3615
- }
3616
- function upsertPart(message, next) {
3617
- const index = message.parts.findIndex((part) => partKey(part) === partKey(next));
3618
- const parts = index === -1 ? [...message.parts, next] : [
3619
- ...message.parts.slice(0, index),
3620
- next,
3621
- ...message.parts.slice(index + 1)
3622
- ];
3623
- return {
3624
- ...message,
3625
- metadata: {
3626
- ...message.metadata,
3627
- status: next.type === "text" && next.state === "done" ? "complete" : "streaming"
3628
- },
3629
- parts
3630
- };
3631
- }
3632
- function updateToolPart(data, toolCallId, next) {
3633
- const message = data.messages.find((candidate) => candidate.role === "assistant" && candidate.parts.some((part) => part.type === "dynamic-tool" && part.toolCallId === toolCallId));
3634
- if (!message) return data;
3635
- return upsertMessage(data, upsertPart(message, next));
3636
- }
3637
- function replaceToolPart(data, next) {
3638
- const message = data.messages.find((candidate) => candidate.parts.some((part) => part.type === "dynamic-tool" && part.toolCallId === next.toolCallId));
3639
- if (message === void 0) return data;
3640
- return upsertMessage(data, {
3641
- ...message,
3642
- parts: message.parts.map((part) => partKey(part) === partKey(next) ? next : part)
3643
- });
3644
- }
3645
- function completeAuthorization(data, event) {
3646
- const existing = findLatestPendingAuthorizationPart(data, event.data.name);
3647
- const next = createAuthorizationCompletedPart(event, existing);
3648
- if (existing !== void 0) return updateAuthorizationPart(data, existing, next);
3649
- return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), next));
3650
- }
3651
- function updateAuthorizationPart(data, existing, next) {
3652
- const message = data.messages.find((candidate) => candidate.role === "assistant" && candidate.parts.some((part) => part === existing));
3653
- if (!message) return data;
3654
- return upsertMessage(data, upsertPart(message, next));
3655
- }
3656
- function findToolPart(data, toolCallId) {
3657
- for (const message of data.messages) for (const part of message.parts) if (part.type === "dynamic-tool" && part.toolCallId === toolCallId) return part;
4274
+ }
4275
+ #createSnapshot() {
4276
+ return {
4277
+ data: this.#conversationClient.data,
4278
+ conversation: this.#conversationClient.conversation,
4279
+ error: this.#error,
4280
+ events: this.#events,
4281
+ session: this.#session?.state,
4282
+ status: this.#status
4283
+ };
4284
+ }
4285
+ #publish() {
4286
+ this.#snapshot = this.#createSnapshot();
4287
+ for (const subscriber of this.#subscribers) subscriber();
4288
+ }
4289
+ };
4290
+ function detachEveAgentStore(store) {
4291
+ store[detachStore]();
3658
4292
  }
3659
- function isSettledToolPart(part) {
3660
- return part.state === "output-denied" || part.state === "output-error" || part.state === "output-available" && part.partial !== true;
4293
+ function attachEveAgentStore(store) {
4294
+ store[attachStore]();
3661
4295
  }
3662
- function findLatestPendingAuthorizationPart(data, name) {
3663
- for (let messageIndex = data.messages.length - 1; messageIndex >= 0; messageIndex -= 1) {
3664
- const message = data.messages[messageIndex];
3665
- if (message?.role !== "assistant") continue;
3666
- for (let partIndex = message.parts.length - 1; partIndex >= 0; partIndex -= 1) {
3667
- const part = message.parts[partIndex];
3668
- if (part?.type === "authorization" && part.state === "required" && part.name === name) return part;
3669
- }
3670
- }
4296
+
4297
+ //#endregion
4298
+ //#region src/client/agent-host.ts
4299
+ const AGENT_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]*$/;
4300
+ const EVE_NAMED_AGENT_ROUTE_PREFIX = "/eve";
4301
+ function resolveEveAgentHost(input) {
4302
+ if (input.agent === void 0) return input.host ?? "";
4303
+ if (input.host !== void 0) throw new Error("useEveAgent cannot combine agent and host. Use one target option.");
4304
+ assertValidAgentName(input.agent);
4305
+ return `${EVE_NAMED_AGENT_ROUTE_PREFIX}/${input.agent}`;
3671
4306
  }
3672
- function findToolPartByApprovalId(data, approvalId) {
3673
- for (const message of data.messages) for (const part of message.parts) if (part.type === "dynamic-tool" && part.approval?.id === approvalId) return part;
4307
+ function assertValidAgentName(name) {
4308
+ if (!AGENT_NAME_PATTERN.test(name)) throw new Error(`eve agent name ${JSON.stringify(name)} is invalid. Use lowercase letters, numbers, underscores, or hyphens, starting with a letter or number.`);
3674
4309
  }
3675
4310
 
3676
4311
  //#endregion
@@ -3697,6 +4332,10 @@ var SvelteEveAgent = class {
3697
4332
  this.#subscribe();
3698
4333
  return this.#snapshot.data;
3699
4334
  }
4335
+ get conversation() {
4336
+ this.#subscribe();
4337
+ return this.#snapshot.conversation;
4338
+ }
3700
4339
  get error() {
3701
4340
  this.#subscribe();
3702
4341
  return this.#snapshot.error;
@@ -3740,7 +4379,7 @@ var SvelteEveAgent = class {
3740
4379
  };
3741
4380
  function useEveAgent(options = {}) {
3742
4381
  if (options.resume && options.initialSession === void 0 && options.session === void 0) throw new Error("useEveAgent({ resume: true }) requires initialSession or session.");
3743
- const reducer = options.reducer ?? defaultMessageReducer();
4382
+ const reducer = options.reducer ?? conversationReducer;
3744
4383
  const store = new EveAgentStore({
3745
4384
  auth: options.auth,
3746
4385
  headers: options.headers,
@@ -3751,6 +4390,7 @@ function useEveAgent(options = {}) {
3751
4390
  initialEvents: options.initialEvents,
3752
4391
  initialSession: options.initialSession,
3753
4392
  optimistic: options.optimistic,
4393
+ followSubagents: options.followSubagents,
3754
4394
  prewarm: options.prewarm,
3755
4395
  reducer,
3756
4396
  session: options.session
@@ -3771,4 +4411,4 @@ function useEveAgent(options = {}) {
3771
4411
  }
3772
4412
 
3773
4413
  //#endregion
3774
- export { defaultMessageReducer as n, useEveAgent as t };
4414
+ export { openConversationInputs as i, conversationReducer as n, defaultMessageReducer as r, useEveAgent as t };