@openma/common 0.0.0-stage → 0.9.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 (328) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +391 -2
  3. package/dist/acp-artifacts/binary.d.ts +35 -0
  4. package/dist/acp-artifacts/binary.d.ts.map +1 -0
  5. package/dist/acp-artifacts/binary.js +120 -0
  6. package/dist/acp-artifacts/binary.js.map +1 -0
  7. package/dist/acp-artifacts/index.d.ts +7 -0
  8. package/dist/acp-artifacts/index.d.ts.map +1 -0
  9. package/dist/acp-artifacts/index.js +7 -0
  10. package/dist/acp-artifacts/index.js.map +1 -0
  11. package/dist/acp-artifacts/node-abi.d.ts +3 -0
  12. package/dist/acp-artifacts/node-abi.d.ts.map +1 -0
  13. package/dist/acp-artifacts/node-abi.js +17 -0
  14. package/dist/acp-artifacts/node-abi.js.map +1 -0
  15. package/dist/acp-artifacts/npm-cli.d.ts +3 -0
  16. package/dist/acp-artifacts/npm-cli.d.ts.map +1 -0
  17. package/dist/acp-artifacts/npm-cli.js +9 -0
  18. package/dist/acp-artifacts/npm-cli.js.map +1 -0
  19. package/dist/acp-artifacts/npm.d.ts +37 -0
  20. package/dist/acp-artifacts/npm.d.ts.map +1 -0
  21. package/dist/acp-artifacts/npm.js +167 -0
  22. package/dist/acp-artifacts/npm.js.map +1 -0
  23. package/dist/acp-artifacts/registry.d.ts +45 -0
  24. package/dist/acp-artifacts/registry.d.ts.map +1 -0
  25. package/dist/acp-artifacts/registry.js +206 -0
  26. package/dist/acp-artifacts/registry.js.map +1 -0
  27. package/dist/acp-artifacts/shared.d.ts +45 -0
  28. package/dist/acp-artifacts/shared.d.ts.map +1 -0
  29. package/dist/acp-artifacts/shared.js +157 -0
  30. package/dist/acp-artifacts/shared.js.map +1 -0
  31. package/dist/acp-artifacts/uvx.d.ts +32 -0
  32. package/dist/acp-artifacts/uvx.d.ts.map +1 -0
  33. package/dist/acp-artifacts/uvx.js +95 -0
  34. package/dist/acp-artifacts/uvx.js.map +1 -0
  35. package/dist/acp-fork/index.d.ts +51 -0
  36. package/dist/acp-fork/index.d.ts.map +1 -0
  37. package/dist/acp-fork/index.js +116 -0
  38. package/dist/acp-fork/index.js.map +1 -0
  39. package/dist/acp-harnesses/agent-setup.d.ts +118 -0
  40. package/dist/acp-harnesses/agent-setup.d.ts.map +1 -0
  41. package/dist/acp-harnesses/agent-setup.js +717 -0
  42. package/dist/acp-harnesses/agent-setup.js.map +1 -0
  43. package/dist/acp-harnesses/custom-agents.d.ts +81 -0
  44. package/dist/acp-harnesses/custom-agents.d.ts.map +1 -0
  45. package/dist/acp-harnesses/custom-agents.js +361 -0
  46. package/dist/acp-harnesses/custom-agents.js.map +1 -0
  47. package/dist/acp-harnesses/headless-launch.d.ts +34 -0
  48. package/dist/acp-harnesses/headless-launch.d.ts.map +1 -0
  49. package/dist/acp-harnesses/headless-launch.js +67 -0
  50. package/dist/acp-harnesses/headless-launch.js.map +1 -0
  51. package/dist/acp-harnesses/index.d.ts +18 -0
  52. package/dist/acp-harnesses/index.d.ts.map +1 -0
  53. package/dist/acp-harnesses/index.js +58 -0
  54. package/dist/acp-harnesses/index.js.map +1 -0
  55. package/dist/acp-harnesses/install-state.d.ts +86 -0
  56. package/dist/acp-harnesses/install-state.d.ts.map +1 -0
  57. package/dist/acp-harnesses/install-state.js +322 -0
  58. package/dist/acp-harnesses/install-state.js.map +1 -0
  59. package/dist/acp-harnesses/installer.d.ts +145 -0
  60. package/dist/acp-harnesses/installer.d.ts.map +1 -0
  61. package/dist/acp-harnesses/installer.js +716 -0
  62. package/dist/acp-harnesses/installer.js.map +1 -0
  63. package/dist/acp-harnesses/known-agents.d.ts +154 -0
  64. package/dist/acp-harnesses/known-agents.d.ts.map +1 -0
  65. package/dist/acp-harnesses/known-agents.js +240 -0
  66. package/dist/acp-harnesses/known-agents.js.map +1 -0
  67. package/dist/acp-harnesses/launcher.d.ts +27 -0
  68. package/dist/acp-harnesses/launcher.d.ts.map +1 -0
  69. package/dist/acp-harnesses/launcher.js +64 -0
  70. package/dist/acp-harnesses/launcher.js.map +1 -0
  71. package/dist/acp-harnesses/registry-fetch.d.ts +42 -0
  72. package/dist/acp-harnesses/registry-fetch.d.ts.map +1 -0
  73. package/dist/acp-harnesses/registry-fetch.js +132 -0
  74. package/dist/acp-harnesses/registry-fetch.js.map +1 -0
  75. package/dist/acp-harnesses/registry.d.ts +36 -0
  76. package/dist/acp-harnesses/registry.d.ts.map +1 -0
  77. package/dist/acp-harnesses/registry.js +307 -0
  78. package/dist/acp-harnesses/registry.js.map +1 -0
  79. package/dist/acp-runtime/errors.d.ts +7 -0
  80. package/dist/acp-runtime/errors.d.ts.map +1 -0
  81. package/dist/acp-runtime/errors.js +17 -0
  82. package/dist/acp-runtime/errors.js.map +1 -0
  83. package/dist/acp-runtime/fork-support.d.ts +8 -0
  84. package/dist/acp-runtime/fork-support.d.ts.map +1 -0
  85. package/dist/acp-runtime/fork-support.js +20 -0
  86. package/dist/acp-runtime/fork-support.js.map +1 -0
  87. package/dist/acp-runtime/index.d.ts +11 -0
  88. package/dist/acp-runtime/index.d.ts.map +1 -0
  89. package/dist/acp-runtime/index.js +6 -0
  90. package/dist/acp-runtime/index.js.map +1 -0
  91. package/dist/acp-runtime/probe.d.ts +103 -0
  92. package/dist/acp-runtime/probe.d.ts.map +1 -0
  93. package/dist/acp-runtime/probe.js +872 -0
  94. package/dist/acp-runtime/probe.js.map +1 -0
  95. package/dist/acp-runtime/runtime.d.ts +7 -0
  96. package/dist/acp-runtime/runtime.d.ts.map +1 -0
  97. package/dist/acp-runtime/runtime.js +26 -0
  98. package/dist/acp-runtime/runtime.js.map +1 -0
  99. package/dist/acp-runtime/session.d.ts +87 -0
  100. package/dist/acp-runtime/session.d.ts.map +1 -0
  101. package/dist/acp-runtime/session.js +1071 -0
  102. package/dist/acp-runtime/session.js.map +1 -0
  103. package/dist/acp-runtime/spawners/node.d.ts +5 -0
  104. package/dist/acp-runtime/spawners/node.d.ts.map +1 -0
  105. package/dist/acp-runtime/spawners/node.js +244 -0
  106. package/dist/acp-runtime/spawners/node.js.map +1 -0
  107. package/dist/acp-runtime/types.d.ts +180 -0
  108. package/dist/acp-runtime/types.d.ts.map +1 -0
  109. package/dist/acp-runtime/types.js +2 -0
  110. package/dist/acp-runtime/types.js.map +1 -0
  111. package/dist/agent-contract/acp.d.ts +4 -0
  112. package/dist/agent-contract/acp.d.ts.map +1 -0
  113. package/dist/agent-contract/acp.js +273 -0
  114. package/dist/agent-contract/acp.js.map +1 -0
  115. package/dist/agent-contract/index.d.ts +125 -0
  116. package/dist/agent-contract/index.d.ts.map +1 -0
  117. package/dist/agent-contract/index.js +102 -0
  118. package/dist/agent-contract/index.js.map +1 -0
  119. package/dist/agent-contract/managed.d.ts +5 -0
  120. package/dist/agent-contract/managed.d.ts.map +1 -0
  121. package/dist/agent-contract/managed.js +242 -0
  122. package/dist/agent-contract/managed.js.map +1 -0
  123. package/dist/agent-ui/index.d.ts +170 -0
  124. package/dist/agent-ui/index.d.ts.map +1 -0
  125. package/dist/agent-ui/index.js +853 -0
  126. package/dist/agent-ui/index.js.map +1 -0
  127. package/dist/agent-ui/presentation.d.ts +30 -0
  128. package/dist/agent-ui/presentation.d.ts.map +1 -0
  129. package/dist/agent-ui/presentation.js +79 -0
  130. package/dist/agent-ui/presentation.js.map +1 -0
  131. package/dist/agent-ui/react.d.ts +50 -0
  132. package/dist/agent-ui/react.d.ts.map +1 -0
  133. package/dist/agent-ui/react.js +334 -0
  134. package/dist/agent-ui/react.js.map +1 -0
  135. package/dist/brand/index.d.ts +17 -0
  136. package/dist/brand/index.d.ts.map +1 -0
  137. package/dist/brand/index.js +119 -0
  138. package/dist/brand/index.js.map +1 -0
  139. package/dist/brand/openma-logo-mark.svg +7 -0
  140. package/dist/brand/tokens.css +77 -0
  141. package/dist/brand/website.css +67 -0
  142. package/dist/chat-ui/acp.d.ts +26 -0
  143. package/dist/chat-ui/acp.d.ts.map +1 -0
  144. package/dist/chat-ui/acp.js +166 -0
  145. package/dist/chat-ui/acp.js.map +1 -0
  146. package/dist/chat-ui/components.d.ts +230 -0
  147. package/dist/chat-ui/components.d.ts.map +1 -0
  148. package/dist/chat-ui/components.js +561 -0
  149. package/dist/chat-ui/components.js.map +1 -0
  150. package/dist/chat-ui/composer-drafts.d.ts +21 -0
  151. package/dist/chat-ui/composer-drafts.d.ts.map +1 -0
  152. package/dist/chat-ui/composer-drafts.js +58 -0
  153. package/dist/chat-ui/composer-drafts.js.map +1 -0
  154. package/dist/chat-ui/controller.d.ts +61 -0
  155. package/dist/chat-ui/controller.d.ts.map +1 -0
  156. package/dist/chat-ui/controller.js +218 -0
  157. package/dist/chat-ui/controller.js.map +1 -0
  158. package/dist/chat-ui/index.d.ts +8 -0
  159. package/dist/chat-ui/index.d.ts.map +1 -0
  160. package/dist/chat-ui/index.js +8 -0
  161. package/dist/chat-ui/index.js.map +1 -0
  162. package/dist/chat-ui/markdown.d.ts +37 -0
  163. package/dist/chat-ui/markdown.d.ts.map +1 -0
  164. package/dist/chat-ui/markdown.js +33 -0
  165. package/dist/chat-ui/markdown.js.map +1 -0
  166. package/dist/chat-ui/presentation.d.ts +34 -0
  167. package/dist/chat-ui/presentation.d.ts.map +1 -0
  168. package/dist/chat-ui/presentation.js +191 -0
  169. package/dist/chat-ui/presentation.js.map +1 -0
  170. package/dist/chat-ui/styles.css +815 -0
  171. package/dist/chat-ui/utils.d.ts +14 -0
  172. package/dist/chat-ui/utils.d.ts.map +1 -0
  173. package/dist/chat-ui/utils.js +71 -0
  174. package/dist/chat-ui/utils.js.map +1 -0
  175. package/dist/local-runtime/checkpoint.d.ts +28 -0
  176. package/dist/local-runtime/checkpoint.d.ts.map +1 -0
  177. package/dist/local-runtime/checkpoint.js +2 -0
  178. package/dist/local-runtime/checkpoint.js.map +1 -0
  179. package/dist/local-runtime/daemon-connection.d.ts +27 -0
  180. package/dist/local-runtime/daemon-connection.d.ts.map +1 -0
  181. package/dist/local-runtime/daemon-connection.js +161 -0
  182. package/dist/local-runtime/daemon-connection.js.map +1 -0
  183. package/dist/local-runtime/daemon-host.d.ts +39 -0
  184. package/dist/local-runtime/daemon-host.d.ts.map +1 -0
  185. package/dist/local-runtime/daemon-host.js +88 -0
  186. package/dist/local-runtime/daemon-host.js.map +1 -0
  187. package/dist/local-runtime/index.d.ts +6 -0
  188. package/dist/local-runtime/index.d.ts.map +1 -0
  189. package/dist/local-runtime/index.js +5 -0
  190. package/dist/local-runtime/index.js.map +1 -0
  191. package/dist/local-runtime/runtime.d.ts +36 -0
  192. package/dist/local-runtime/runtime.d.ts.map +1 -0
  193. package/dist/local-runtime/runtime.js +82 -0
  194. package/dist/local-runtime/runtime.js.map +1 -0
  195. package/dist/local-runtime/session-host.d.ts +62 -0
  196. package/dist/local-runtime/session-host.d.ts.map +1 -0
  197. package/dist/local-runtime/session-host.js +477 -0
  198. package/dist/local-runtime/session-host.js.map +1 -0
  199. package/dist/managed-runtime/acp-subagents.d.ts +14 -0
  200. package/dist/managed-runtime/acp-subagents.d.ts.map +1 -0
  201. package/dist/managed-runtime/acp-subagents.js +67 -0
  202. package/dist/managed-runtime/acp-subagents.js.map +1 -0
  203. package/dist/managed-runtime/claimed-environment-work.d.ts +61 -0
  204. package/dist/managed-runtime/claimed-environment-work.d.ts.map +1 -0
  205. package/dist/managed-runtime/claimed-environment-work.js +170 -0
  206. package/dist/managed-runtime/claimed-environment-work.js.map +1 -0
  207. package/dist/managed-runtime/contracts.d.ts +31 -0
  208. package/dist/managed-runtime/contracts.d.ts.map +1 -0
  209. package/dist/managed-runtime/contracts.js +2 -0
  210. package/dist/managed-runtime/contracts.js.map +1 -0
  211. package/dist/managed-runtime/http-control.d.ts +67 -0
  212. package/dist/managed-runtime/http-control.d.ts.map +1 -0
  213. package/dist/managed-runtime/http-control.js +465 -0
  214. package/dist/managed-runtime/http-control.js.map +1 -0
  215. package/dist/managed-runtime/index.d.ts +89 -0
  216. package/dist/managed-runtime/index.d.ts.map +1 -0
  217. package/dist/managed-runtime/index.js +215 -0
  218. package/dist/managed-runtime/index.js.map +1 -0
  219. package/dist/managed-runtime/input-identity.d.ts +2 -0
  220. package/dist/managed-runtime/input-identity.d.ts.map +1 -0
  221. package/dist/managed-runtime/input-identity.js +2 -0
  222. package/dist/managed-runtime/input-identity.js.map +1 -0
  223. package/dist/managed-runtime/managed-event-projector.d.ts +24 -0
  224. package/dist/managed-runtime/managed-event-projector.d.ts.map +1 -0
  225. package/dist/managed-runtime/managed-event-projector.js +333 -0
  226. package/dist/managed-runtime/managed-event-projector.js.map +1 -0
  227. package/dist/managed-runtime/semantic-recovery.d.ts +61 -0
  228. package/dist/managed-runtime/semantic-recovery.d.ts.map +1 -0
  229. package/dist/managed-runtime/semantic-recovery.js +167 -0
  230. package/dist/managed-runtime/semantic-recovery.js.map +1 -0
  231. package/dist/project-ui/CreateProjectDialog.d.ts +15 -0
  232. package/dist/project-ui/CreateProjectDialog.d.ts.map +1 -0
  233. package/dist/project-ui/CreateProjectDialog.js +87 -0
  234. package/dist/project-ui/CreateProjectDialog.js.map +1 -0
  235. package/dist/project-ui/ProjectComposer.d.ts +13 -0
  236. package/dist/project-ui/ProjectComposer.d.ts.map +1 -0
  237. package/dist/project-ui/ProjectComposer.js +70 -0
  238. package/dist/project-ui/ProjectComposer.js.map +1 -0
  239. package/dist/project-ui/ProjectConversation.d.ts +10 -0
  240. package/dist/project-ui/ProjectConversation.d.ts.map +1 -0
  241. package/dist/project-ui/ProjectConversation.js +28 -0
  242. package/dist/project-ui/ProjectConversation.js.map +1 -0
  243. package/dist/project-ui/ProjectMessageAttachments.d.ts +4 -0
  244. package/dist/project-ui/ProjectMessageAttachments.d.ts.map +1 -0
  245. package/dist/project-ui/ProjectMessageAttachments.js +28 -0
  246. package/dist/project-ui/ProjectMessageAttachments.js.map +1 -0
  247. package/dist/project-ui/ProjectSettings.d.ts +8 -0
  248. package/dist/project-ui/ProjectSettings.d.ts.map +1 -0
  249. package/dist/project-ui/ProjectSettings.js +65 -0
  250. package/dist/project-ui/ProjectSettings.js.map +1 -0
  251. package/dist/project-ui/Projects.d.ts +18 -0
  252. package/dist/project-ui/Projects.d.ts.map +1 -0
  253. package/dist/project-ui/Projects.js +377 -0
  254. package/dist/project-ui/Projects.js.map +1 -0
  255. package/dist/project-ui/client.d.ts +234 -0
  256. package/dist/project-ui/client.d.ts.map +1 -0
  257. package/dist/project-ui/client.js +42 -0
  258. package/dist/project-ui/client.js.map +1 -0
  259. package/dist/project-ui/controls.d.ts +15 -0
  260. package/dist/project-ui/controls.d.ts.map +1 -0
  261. package/dist/project-ui/controls.js +17 -0
  262. package/dist/project-ui/controls.js.map +1 -0
  263. package/dist/project-ui/index.d.ts +20 -0
  264. package/dist/project-ui/index.d.ts.map +1 -0
  265. package/dist/project-ui/index.js +17 -0
  266. package/dist/project-ui/index.js.map +1 -0
  267. package/dist/project-ui/project-coordinator.d.ts +3 -0
  268. package/dist/project-ui/project-coordinator.d.ts.map +1 -0
  269. package/dist/project-ui/project-coordinator.js +12 -0
  270. package/dist/project-ui/project-coordinator.js.map +1 -0
  271. package/dist/project-ui/project-goals.d.ts +48 -0
  272. package/dist/project-ui/project-goals.d.ts.map +1 -0
  273. package/dist/project-ui/project-goals.js +169 -0
  274. package/dist/project-ui/project-goals.js.map +1 -0
  275. package/dist/project-ui/projects-query.d.ts +19 -0
  276. package/dist/project-ui/projects-query.d.ts.map +1 -0
  277. package/dist/project-ui/projects-query.js +132 -0
  278. package/dist/project-ui/projects-query.js.map +1 -0
  279. package/dist/project-ui/styles.css +847 -0
  280. package/dist/protocol/acp/index.d.ts +52 -0
  281. package/dist/protocol/acp/index.d.ts.map +1 -0
  282. package/dist/protocol/acp/index.js +1056 -0
  283. package/dist/protocol/acp/index.js.map +1 -0
  284. package/dist/protocol/cursor-cloud/index.d.ts +74 -0
  285. package/dist/protocol/cursor-cloud/index.d.ts.map +1 -0
  286. package/dist/protocol/cursor-cloud/index.js +249 -0
  287. package/dist/protocol/cursor-cloud/index.js.map +1 -0
  288. package/dist/protocol/managed/index.d.ts +32 -0
  289. package/dist/protocol/managed/index.d.ts.map +1 -0
  290. package/dist/protocol/managed/index.js +646 -0
  291. package/dist/protocol/managed/index.js.map +1 -0
  292. package/dist/protocol/managed/input-identity.d.ts +3 -0
  293. package/dist/protocol/managed/input-identity.d.ts.map +1 -0
  294. package/dist/protocol/managed/input-identity.js +6 -0
  295. package/dist/protocol/managed/input-identity.js.map +1 -0
  296. package/dist/protocol/openai-agents/index.d.ts +102 -0
  297. package/dist/protocol/openai-agents/index.d.ts.map +1 -0
  298. package/dist/protocol/openai-agents/index.js +142 -0
  299. package/dist/protocol/openai-agents/index.js.map +1 -0
  300. package/dist/session-events/acp-system-notices.d.ts +10 -0
  301. package/dist/session-events/acp-system-notices.d.ts.map +1 -0
  302. package/dist/session-events/acp-system-notices.js +46 -0
  303. package/dist/session-events/acp-system-notices.js.map +1 -0
  304. package/dist/session-events/acp.d.ts +214 -0
  305. package/dist/session-events/acp.d.ts.map +1 -0
  306. package/dist/session-events/acp.js +956 -0
  307. package/dist/session-events/acp.js.map +1 -0
  308. package/dist/session-events/managed.d.ts +141 -0
  309. package/dist/session-events/managed.d.ts.map +1 -0
  310. package/dist/session-events/managed.js +324 -0
  311. package/dist/session-events/managed.js.map +1 -0
  312. package/dist/session-events/openma.d.ts +304 -0
  313. package/dist/session-events/openma.d.ts.map +1 -0
  314. package/dist/session-events/openma.js +438 -0
  315. package/dist/session-events/openma.js.map +1 -0
  316. package/dist/session-kernel/index.d.ts +118 -0
  317. package/dist/session-kernel/index.d.ts.map +1 -0
  318. package/dist/session-kernel/index.js +215 -0
  319. package/dist/session-kernel/index.js.map +1 -0
  320. package/dist/session-orchestrator/index.d.ts +71 -0
  321. package/dist/session-orchestrator/index.d.ts.map +1 -0
  322. package/dist/session-orchestrator/index.js +177 -0
  323. package/dist/session-orchestrator/index.js.map +1 -0
  324. package/dist/session-ui/index.d.ts +96 -0
  325. package/dist/session-ui/index.d.ts.map +1 -0
  326. package/dist/session-ui/index.js +277 -0
  327. package/dist/session-ui/index.js.map +1 -0
  328. package/package.json +222 -4
@@ -0,0 +1,853 @@
1
+ import { reduceWorkItemEvent, } from "../session-events/openma.js";
2
+ export const AGENT_UI_STATE_VERSION = "oma.agent-ui.v1";
3
+ export function createAgentUIState(sessionId) {
4
+ return {
5
+ version: AGENT_UI_STATE_VERSION,
6
+ sessionId,
7
+ status: "unknown",
8
+ sessionInfo: {},
9
+ commands: [],
10
+ capabilities: {},
11
+ turnOrder: [],
12
+ turns: {},
13
+ workItemOrder: [],
14
+ workItems: {},
15
+ planOrder: [],
16
+ plans: {},
17
+ callbackOrder: [],
18
+ callbacks: {},
19
+ outcomeOrder: [],
20
+ outcomes: {},
21
+ seenEventIds: {},
22
+ };
23
+ }
24
+ function eventData(event) {
25
+ return event.data && typeof event.data === "object"
26
+ ? event.data
27
+ : {};
28
+ }
29
+ function cloneState(state) {
30
+ return {
31
+ ...state,
32
+ sessionInfo: { ...state.sessionInfo },
33
+ commands: [...state.commands],
34
+ capabilities: { ...state.capabilities },
35
+ turnOrder: [...state.turnOrder],
36
+ turns: Object.fromEntries(Object.entries(state.turns).map(([id, turn]) => [
37
+ id,
38
+ {
39
+ ...turn,
40
+ items: turn.items.map((item) => item.kind === "tool"
41
+ ? {
42
+ ...item,
43
+ outputs: item.outputs.map((output) => ({ ...output })),
44
+ ...(item.content ? { content: [...item.content] } : {}),
45
+ ...(item.locations
46
+ ? { locations: item.locations.map((location) => ({ ...location })) }
47
+ : {}),
48
+ ...(item.adapterMeta
49
+ ? { adapterMeta: { ...item.adapterMeta } }
50
+ : {}),
51
+ }
52
+ : { ...item }),
53
+ },
54
+ ])),
55
+ workItemOrder: [...state.workItemOrder],
56
+ workItems: Object.fromEntries(Object.entries(state.workItems).map(([id, item]) => [
57
+ id,
58
+ { ...item, output: [...item.output] },
59
+ ])),
60
+ planOrder: [...state.planOrder],
61
+ plans: Object.fromEntries(Object.entries(state.plans).map(([id, plan]) => [
62
+ id,
63
+ { ...plan, entries: plan.entries.map((entry) => ({ ...entry })) },
64
+ ])),
65
+ callbackOrder: [...state.callbackOrder],
66
+ callbacks: Object.fromEntries(Object.entries(state.callbacks).map(([id, callback]) => [
67
+ id,
68
+ { ...callback },
69
+ ])),
70
+ ...(state.usage ? { usage: { ...state.usage } } : {}),
71
+ outcomeOrder: [...state.outcomeOrder],
72
+ outcomes: Object.fromEntries(Object.entries(state.outcomes).map(([id, outcome]) => [id, { ...outcome }])),
73
+ seenEventIds: { ...state.seenEventIds },
74
+ };
75
+ }
76
+ function toWorkItemSnapshot(item) {
77
+ return {
78
+ id: item.id,
79
+ kind: item.kind,
80
+ status: item.status,
81
+ output: [...item.output],
82
+ ...(item.title !== undefined ? { title: item.title } : {}),
83
+ ...(item.progress !== undefined ? { progress: item.progress } : {}),
84
+ ...(item.result !== undefined ? { result: item.result } : {}),
85
+ ...(item.error !== undefined ? { error: item.error } : {}),
86
+ ...(item.reason !== undefined ? { reason: item.reason } : {}),
87
+ ...(item.startedAt !== undefined ? { started_at: item.startedAt } : {}),
88
+ ...(item.endedAt !== undefined ? { ended_at: item.endedAt } : {}),
89
+ ...(item.missingStart !== undefined ? { missing_start: item.missingStart } : {}),
90
+ ...(item.missingTerminal !== undefined
91
+ ? { missing_terminal: item.missingTerminal }
92
+ : {}),
93
+ };
94
+ }
95
+ function toAgentUIWorkItem(item) {
96
+ return {
97
+ id: item.id,
98
+ kind: item.kind,
99
+ status: item.status,
100
+ output: [...item.output],
101
+ ...(item.title !== undefined ? { title: item.title } : {}),
102
+ ...(item.progress !== undefined ? { progress: item.progress } : {}),
103
+ ...(item.result !== undefined ? { result: item.result } : {}),
104
+ ...(item.error !== undefined ? { error: item.error } : {}),
105
+ ...(item.reason !== undefined ? { reason: item.reason } : {}),
106
+ ...(item.started_at !== undefined ? { startedAt: item.started_at } : {}),
107
+ ...(item.ended_at !== undefined ? { endedAt: item.ended_at } : {}),
108
+ ...(item.missing_start !== undefined ? { missingStart: item.missing_start } : {}),
109
+ ...(item.missing_terminal !== undefined
110
+ ? { missingTerminal: item.missing_terminal }
111
+ : {}),
112
+ };
113
+ }
114
+ function applyWorkItemProjection(state, previous, event) {
115
+ const registry = reduceWorkItemEvent({
116
+ items: new Map(Object.entries(previous.workItems).map(([id, item]) => [
117
+ id,
118
+ toWorkItemSnapshot(item),
119
+ ])),
120
+ seen_event_ids: new Set(Object.keys(previous.seenEventIds)),
121
+ }, event);
122
+ const ids = [...registry.items.keys()];
123
+ const present = new Set(ids);
124
+ state.workItemOrder = previous.workItemOrder.filter((id) => present.has(id));
125
+ for (const id of ids) {
126
+ if (!state.workItemOrder.includes(id))
127
+ state.workItemOrder.push(id);
128
+ }
129
+ state.workItems = Object.fromEntries([...registry.items].map(([id, item]) => [id, toAgentUIWorkItem(item)]));
130
+ }
131
+ function planId(event) {
132
+ if (!event.data || typeof event.data !== "object")
133
+ return undefined;
134
+ const value = event.data.plan_id;
135
+ return typeof value === "string" && value.length > 0
136
+ ? value
137
+ : event.turn_id;
138
+ }
139
+ function mergePlanEntries(previous, incoming) {
140
+ const merged = previous.map((entry) => ({ ...entry }));
141
+ for (const entry of incoming) {
142
+ const index = entry.id
143
+ ? merged.findIndex((candidate) => candidate.id === entry.id)
144
+ : -1;
145
+ if (index >= 0)
146
+ merged[index] = { ...merged[index], ...entry };
147
+ else
148
+ merged.push({ ...entry });
149
+ }
150
+ return merged;
151
+ }
152
+ function applyPlanProjection(state, event) {
153
+ const id = planId(event);
154
+ if (!id)
155
+ return;
156
+ if (event.type === "plan.updated") {
157
+ const data = event.data;
158
+ if (data.representation !== "items"
159
+ && data.representation !== "markdown"
160
+ && data.representation !== "file") {
161
+ return;
162
+ }
163
+ const previous = state.plans[id];
164
+ const incoming = data.entries ?? [];
165
+ state.plans[id] = {
166
+ id,
167
+ representation: data.representation,
168
+ status: "active",
169
+ entries: data.update_mode === "merge" && previous
170
+ ? mergePlanEntries(previous.entries, incoming)
171
+ : incoming.map((entry) => ({ ...entry })),
172
+ };
173
+ if (!state.planOrder.includes(id))
174
+ state.planOrder.push(id);
175
+ }
176
+ else if (event.type === "plan.completed") {
177
+ const previous = state.plans[id];
178
+ if (previous)
179
+ state.plans[id] = { ...previous, status: "completed" };
180
+ }
181
+ else if (event.type === "plan.removed") {
182
+ delete state.plans[id];
183
+ state.planOrder = state.planOrder.filter((planId) => planId !== id);
184
+ }
185
+ }
186
+ function applyCallbackProjection(state, event) {
187
+ if (event.type !== "callback.requested"
188
+ && event.type !== "callback.completed"
189
+ && event.type !== "callback.failed"
190
+ && event.type !== "callback.notification") {
191
+ return;
192
+ }
193
+ if (!event.data || typeof event.data !== "object")
194
+ return;
195
+ const data = event.data;
196
+ const callbackId = (typeof data.callback_id === "string" && data.callback_id.length > 0) || typeof data.callback_id === "number"
197
+ ? String(data.callback_id)
198
+ : data.callback_id === null
199
+ ? "null"
200
+ : event.type === "callback.notification"
201
+ ? event.event_id
202
+ : undefined;
203
+ if (!callbackId) {
204
+ return;
205
+ }
206
+ if (typeof data.method !== "string" || data.method.length === 0)
207
+ return;
208
+ const id = callbackId;
209
+ const previous = state.callbacks[id];
210
+ const callback = {
211
+ id,
212
+ category: data.category,
213
+ method: data.method,
214
+ status: event.type === "callback.requested"
215
+ ? "pending"
216
+ : event.type === "callback.failed"
217
+ ? "failed"
218
+ : event.type === "callback.notification"
219
+ ? "notification"
220
+ : "completed",
221
+ ...(previous?.params !== undefined ? { params: previous.params } : {}),
222
+ ...(data.params !== undefined ? { params: data.params } : {}),
223
+ ...(data.result !== undefined ? { result: data.result } : {}),
224
+ ...(data.error !== undefined ? { error: data.error } : {}),
225
+ };
226
+ state.callbacks[id] = callback;
227
+ if (!state.callbackOrder.includes(id))
228
+ state.callbackOrder.push(id);
229
+ }
230
+ function applyOutcomeProjection(state, event) {
231
+ if (event.type !== "outcome.defined"
232
+ && event.type !== "outcome.evaluation_started"
233
+ && event.type !== "outcome.evaluation_progress"
234
+ && event.type !== "outcome.evaluation_completed") {
235
+ return;
236
+ }
237
+ if (!event.data || typeof event.data !== "object")
238
+ return;
239
+ const data = event.data;
240
+ const id = typeof data.outcome_id === "string" && data.outcome_id.length > 0
241
+ ? data.outcome_id
242
+ : event.event_id;
243
+ const previous = state.outcomes[id];
244
+ const status = event.type === "outcome.defined"
245
+ ? "defined"
246
+ : event.type === "outcome.evaluation_completed"
247
+ ? data.result ?? "completed"
248
+ : "evaluating";
249
+ state.outcomes[id] = {
250
+ id,
251
+ status,
252
+ ...(previous?.description !== undefined
253
+ ? { description: previous.description }
254
+ : {}),
255
+ ...(previous?.rubric !== undefined ? { rubric: previous.rubric } : {}),
256
+ ...(previous?.maxIterations !== undefined
257
+ ? { maxIterations: previous.maxIterations }
258
+ : {}),
259
+ ...(data.description !== undefined ? { description: data.description } : {}),
260
+ ...(data.rubric !== undefined ? { rubric: data.rubric } : {}),
261
+ ...(data.max_iterations !== undefined
262
+ ? { maxIterations: data.max_iterations }
263
+ : {}),
264
+ ...(data.iteration !== undefined ? { iteration: data.iteration } : {}),
265
+ ...(data.explanation !== undefined ? { explanation: data.explanation } : {}),
266
+ ...(data.usage !== undefined ? { usage: data.usage } : {}),
267
+ updatedAt: event.occurred_at,
268
+ };
269
+ if (!state.outcomeOrder.includes(id))
270
+ state.outcomeOrder.push(id);
271
+ }
272
+ function requireTurn(state, event) {
273
+ const turnId = event.turn_id;
274
+ if (!turnId)
275
+ return undefined;
276
+ const existing = state.turns[turnId];
277
+ if (existing)
278
+ return existing;
279
+ const created = {
280
+ id: turnId,
281
+ status: "unknown",
282
+ items: [],
283
+ };
284
+ state.turns[turnId] = created;
285
+ state.turnOrder.push(turnId);
286
+ return created;
287
+ }
288
+ function upsertMessage(turn, event, input) {
289
+ const data = eventData(event);
290
+ const id = typeof data.message_id === "string" && data.message_id.length > 0
291
+ ? data.message_id
292
+ : event.event_id;
293
+ const text = typeof data.text === "string" ? data.text : "";
294
+ const tail = turn.items.at(-1);
295
+ const existing = tail
296
+ && tail.kind !== "tool"
297
+ && tail.kind === input.kind
298
+ && tail.role === input.role
299
+ && (data.message_id === undefined
300
+ || (tail.messageId ?? tail.id) === data.message_id)
301
+ ? tail
302
+ : undefined;
303
+ if (existing) {
304
+ existing.kind = input.kind;
305
+ existing.role = input.role;
306
+ existing.text = input.streaming
307
+ ? mergeAgentUIStreamingText(existing.text, text)
308
+ : text;
309
+ existing.status = input.streaming ? "streaming" : "complete";
310
+ if (data.content !== undefined)
311
+ existing.content = data.content;
312
+ if (data.phase !== undefined)
313
+ existing.phase = data.phase;
314
+ return;
315
+ }
316
+ const segmentId = uniqueMessageItemId(turn, id);
317
+ turn.items.push({
318
+ id: segmentId,
319
+ ...(segmentId !== id ? { messageId: id } : {}),
320
+ kind: input.kind,
321
+ ...(input.kind === "thinking" ? { startedAt: event.occurred_at } : {}),
322
+ role: input.role,
323
+ text,
324
+ status: input.streaming ? "streaming" : "complete",
325
+ ...(data.content !== undefined ? { content: data.content } : {}),
326
+ ...(data.phase !== undefined ? { phase: data.phase } : {}),
327
+ });
328
+ }
329
+ function uniqueMessageItemId(turn, sourceId) {
330
+ if (!turn.items.some((item) => item.id === sourceId))
331
+ return sourceId;
332
+ let segment = 2;
333
+ while (turn.items.some((item) => item.id === `${sourceId}:segment:${segment}`)) {
334
+ segment += 1;
335
+ }
336
+ return `${sourceId}:segment:${segment}`;
337
+ }
338
+ function mergeAdapterMeta(current, incoming) {
339
+ const next = { ...(current ?? {}) };
340
+ for (const [key, value] of Object.entries(incoming)) {
341
+ const previous = next[key];
342
+ next[key] = value
343
+ && typeof value === "object"
344
+ && !Array.isArray(value)
345
+ && previous
346
+ && typeof previous === "object"
347
+ && !Array.isArray(previous)
348
+ ? mergeAdapterMeta(previous, value)
349
+ : value;
350
+ }
351
+ return next;
352
+ }
353
+ const MIN_STREAM_OVERLAP = 8;
354
+ export function mergeAgentUIStreamingText(accumulated, incoming) {
355
+ if (!accumulated)
356
+ return incoming;
357
+ if (!incoming || incoming === accumulated)
358
+ return accumulated;
359
+ if (incoming.startsWith(accumulated))
360
+ return incoming;
361
+ if (incoming.length >= MIN_STREAM_OVERLAP && accumulated.endsWith(incoming)) {
362
+ return accumulated;
363
+ }
364
+ const maxOverlap = Math.min(accumulated.length, incoming.length);
365
+ for (let size = maxOverlap; size >= MIN_STREAM_OVERLAP; size -= 1) {
366
+ if (accumulated.endsWith(incoming.slice(0, size))) {
367
+ return accumulated + incoming.slice(size);
368
+ }
369
+ }
370
+ return accumulated + incoming;
371
+ }
372
+ function upsertTool(turn, event, status) {
373
+ if (!event.data || typeof event.data !== "object")
374
+ return;
375
+ const data = event.data;
376
+ if (typeof data.tool_call_id !== "string" || data.tool_call_id.length === 0) {
377
+ return;
378
+ }
379
+ let item = turn.items.find((candidate) => candidate.kind === "tool" && candidate.id === data.tool_call_id);
380
+ if (!item) {
381
+ item = {
382
+ id: data.tool_call_id,
383
+ kind: "tool",
384
+ status,
385
+ outputs: [],
386
+ };
387
+ turn.items.push(item);
388
+ }
389
+ item.status = status;
390
+ if (data.tool_name !== undefined)
391
+ item.name = data.tool_name;
392
+ if (data.title !== undefined)
393
+ item.title = data.title;
394
+ if (data.kind !== undefined)
395
+ item.toolKind = data.kind;
396
+ if (data.raw_input !== undefined)
397
+ item.rawInput = data.raw_input;
398
+ if (data.raw_output !== undefined)
399
+ item.rawOutput = data.raw_output;
400
+ if (data.content !== undefined)
401
+ item.content = [...data.content];
402
+ if (data.locations !== undefined) {
403
+ item.locations = data.locations.map((location) => ({ ...location }));
404
+ }
405
+ if (data.adapter_meta !== undefined) {
406
+ item.adapterMeta = mergeAdapterMeta(item.adapterMeta, data.adapter_meta);
407
+ }
408
+ if (data.error !== undefined)
409
+ item.error = data.error;
410
+ if (data.reason !== undefined)
411
+ item.reason = data.reason;
412
+ if (data.output !== undefined) {
413
+ if (data.output.append)
414
+ item.outputs.push(data.output);
415
+ else
416
+ item.outputs = [data.output];
417
+ }
418
+ }
419
+ function errorMessage(event) {
420
+ if (!event.data || typeof event.data !== "object")
421
+ return undefined;
422
+ const data = event.data;
423
+ for (const value of [data.error, data.message, data.reason]) {
424
+ if (typeof value === "string" && value.length > 0)
425
+ return value;
426
+ }
427
+ return undefined;
428
+ }
429
+ function stopReasonType(event) {
430
+ if (!event.data || typeof event.data !== "object")
431
+ return undefined;
432
+ const stopReason = event.data.stop_reason;
433
+ if (typeof stopReason === "string")
434
+ return stopReason;
435
+ if (!stopReason || typeof stopReason !== "object")
436
+ return undefined;
437
+ const type = stopReason.type;
438
+ return typeof type === "string" ? type : undefined;
439
+ }
440
+ /** Match ACP chat projection: first thought chunk through the following
441
+ * activity (or turn termination), rounded up to whole seconds. Metadata and
442
+ * unrelated turns must not stop a thought's clock. */
443
+ function settleThoughtTiming(turn, event) {
444
+ if (!turn)
445
+ return;
446
+ const thought = [...turn.items].reverse().find((item) => item.kind === "thinking" && !item.endedAt);
447
+ if (!thought?.startedAt)
448
+ return;
449
+ const data = eventData(event);
450
+ const continuesThought = event.type === "agent.thinking"
451
+ && turn.items.at(-1) === thought
452
+ && (data.message_id === undefined || data.message_id === (thought.messageId ?? thought.id));
453
+ if (continuesThought)
454
+ return;
455
+ const boundary = event.type === "agent.thinking"
456
+ || event.type === "agent.message_chunk"
457
+ || event.type === "agent.message"
458
+ || event.type.startsWith("tool.")
459
+ || ["turn.completed", "turn.failed", "turn.cancelled", "session.error", "session.terminated"].includes(event.type)
460
+ || (event.type === "session.idle" && stopReasonType(event) === "end_turn");
461
+ if (!boundary)
462
+ return;
463
+ const elapsed = Date.parse(event.occurred_at) - Date.parse(thought.startedAt);
464
+ if (!Number.isFinite(elapsed))
465
+ return;
466
+ thought.endedAt = event.occurred_at;
467
+ thought.content = {
468
+ ...(thought.content && typeof thought.content === "object" && !Array.isArray(thought.content)
469
+ ? thought.content : {}),
470
+ durationSeconds: Math.max(1, Math.ceil(elapsed / 1_000)),
471
+ };
472
+ }
473
+ export function reduceAgentUIEvent(state, event) {
474
+ if (event.session_id !== state.sessionId || state.seenEventIds[event.event_id]) {
475
+ return state;
476
+ }
477
+ const next = cloneState(state);
478
+ applyWorkItemProjection(next, state, event);
479
+ applyPlanProjection(next, event);
480
+ applyCallbackProjection(next, event);
481
+ applyOutcomeProjection(next, event);
482
+ next.seenEventIds[event.event_id] = true;
483
+ const turn = requireTurn(next, event);
484
+ settleThoughtTiming(turn ?? (event.type.startsWith("session.") && next.activeTurnId ? next.turns[next.activeTurnId] : undefined), event);
485
+ switch (event.type) {
486
+ case "session.updated": {
487
+ const data = event.data;
488
+ next.sessionInfo = {
489
+ ...next.sessionInfo,
490
+ ...(Object.prototype.hasOwnProperty.call(data, "title")
491
+ ? { title: data.title }
492
+ : {}),
493
+ ...(Object.prototype.hasOwnProperty.call(data, "updated_at")
494
+ ? { updatedAt: data.updated_at }
495
+ : {}),
496
+ };
497
+ break;
498
+ }
499
+ case "command_catalog.updated": {
500
+ const data = event.data;
501
+ if (Array.isArray(data.commands))
502
+ next.commands = [...data.commands];
503
+ break;
504
+ }
505
+ case "capability.updated": {
506
+ const data = event.data;
507
+ if (typeof data.capability === "string" && data.capability.length > 0) {
508
+ next.capabilities[data.capability] = data.value;
509
+ }
510
+ break;
511
+ }
512
+ case "session.running":
513
+ next.status = "running";
514
+ if (turn) {
515
+ turn.status = "running";
516
+ turn.startedAt ??= event.occurred_at;
517
+ next.activeTurnId = turn.id;
518
+ }
519
+ break;
520
+ case "session.rescheduled":
521
+ next.status = "rescheduled";
522
+ break;
523
+ case "session.idle": {
524
+ next.status = "idle";
525
+ const idleTurn = turn
526
+ ?? (next.activeTurnId ? next.turns[next.activeTurnId] : undefined);
527
+ if (idleTurn && stopReasonType(event) === "end_turn") {
528
+ idleTurn.status = "completed";
529
+ idleTurn.endedAt = event.occurred_at;
530
+ }
531
+ next.activeTurnId = undefined;
532
+ break;
533
+ }
534
+ case "session.terminated":
535
+ next.status = "terminated";
536
+ next.activeTurnId = undefined;
537
+ break;
538
+ case "session.error": {
539
+ const message = errorMessage(event);
540
+ const failedTurn = turn
541
+ ?? (next.activeTurnId ? next.turns[next.activeTurnId] : undefined);
542
+ next.status = "error";
543
+ next.lastError = message;
544
+ if (failedTurn) {
545
+ failedTurn.status = "failed";
546
+ failedTurn.error = message;
547
+ failedTurn.endedAt = event.occurred_at;
548
+ }
549
+ next.activeTurnId = undefined;
550
+ break;
551
+ }
552
+ case "usage.updated": {
553
+ const data = event.data;
554
+ if (data.usage !== undefined) {
555
+ next.usage = {
556
+ snapshot: data.usage,
557
+ ...(data.budget !== undefined ? { budget: data.budget } : {}),
558
+ updatedAt: event.occurred_at,
559
+ };
560
+ }
561
+ break;
562
+ }
563
+ case "turn.queued":
564
+ if (turn)
565
+ turn.status = "queued";
566
+ break;
567
+ case "turn.completed":
568
+ if (turn) {
569
+ turn.status = "completed";
570
+ turn.endedAt = event.occurred_at;
571
+ }
572
+ if (next.activeTurnId === event.turn_id)
573
+ next.activeTurnId = undefined;
574
+ break;
575
+ case "turn.failed":
576
+ if (turn) {
577
+ turn.status = "failed";
578
+ turn.error = errorMessage(event);
579
+ turn.endedAt = event.occurred_at;
580
+ }
581
+ if (next.activeTurnId === event.turn_id)
582
+ next.activeTurnId = undefined;
583
+ break;
584
+ case "turn.cancelled":
585
+ if (turn) {
586
+ turn.status = "cancelled";
587
+ turn.reason = errorMessage(event);
588
+ turn.endedAt = event.occurred_at;
589
+ }
590
+ if (next.activeTurnId === event.turn_id)
591
+ next.activeTurnId = undefined;
592
+ break;
593
+ case "user.message_chunk":
594
+ if (turn) {
595
+ if (turn.status === "unknown")
596
+ turn.status = "queued";
597
+ upsertMessage(turn, event, {
598
+ kind: "message",
599
+ role: "user",
600
+ streaming: true,
601
+ });
602
+ }
603
+ break;
604
+ case "user.message":
605
+ if (turn) {
606
+ if (turn.status === "unknown")
607
+ turn.status = "queued";
608
+ upsertMessage(turn, event, {
609
+ kind: "message",
610
+ role: "user",
611
+ streaming: false,
612
+ });
613
+ }
614
+ break;
615
+ case "agent.message_chunk":
616
+ if (turn) {
617
+ if (turn.status === "unknown" || turn.status === "queued") {
618
+ turn.status = "running";
619
+ }
620
+ upsertMessage(turn, event, {
621
+ kind: "message",
622
+ role: "assistant",
623
+ streaming: true,
624
+ });
625
+ }
626
+ break;
627
+ case "agent.message":
628
+ if (turn) {
629
+ upsertMessage(turn, event, {
630
+ kind: "message",
631
+ role: "assistant",
632
+ streaming: false,
633
+ });
634
+ }
635
+ break;
636
+ case "agent.thinking":
637
+ if (turn) {
638
+ const data = eventData(event);
639
+ upsertMessage(turn, event, {
640
+ kind: "thinking",
641
+ role: "assistant",
642
+ streaming: typeof data.text === "string" && data.text.length > 0,
643
+ });
644
+ }
645
+ break;
646
+ case "system.message":
647
+ if (turn) {
648
+ upsertMessage(turn, event, {
649
+ kind: "message",
650
+ role: "system",
651
+ streaming: false,
652
+ });
653
+ }
654
+ break;
655
+ case "system.notice":
656
+ if (turn) {
657
+ upsertMessage(turn, event, {
658
+ kind: "notice",
659
+ role: "system",
660
+ streaming: false,
661
+ });
662
+ }
663
+ break;
664
+ case "tool.started":
665
+ if (turn)
666
+ upsertTool(turn, event, "in_progress");
667
+ break;
668
+ case "tool.progress":
669
+ if (turn)
670
+ upsertTool(turn, event, "in_progress");
671
+ break;
672
+ case "tool.completed":
673
+ if (turn)
674
+ upsertTool(turn, event, "completed");
675
+ break;
676
+ case "tool.failed":
677
+ if (turn)
678
+ upsertTool(turn, event, "failed");
679
+ break;
680
+ case "tool.cancelled":
681
+ if (turn)
682
+ upsertTool(turn, event, "cancelled");
683
+ break;
684
+ case "raw.event":
685
+ case "vendor.event":
686
+ if (turn)
687
+ turn.items.push({ id: event.event_id, kind: "raw", event });
688
+ break;
689
+ }
690
+ return next;
691
+ }
692
+ export function replayAgentUIEvents(sessionId, events) {
693
+ const ordered = events
694
+ .map((event, index) => ({ event, index }))
695
+ .sort((left, right) => {
696
+ if (left.event.seq === undefined && right.event.seq === undefined) {
697
+ return left.index - right.index;
698
+ }
699
+ if (left.event.seq === undefined)
700
+ return 1;
701
+ if (right.event.seq === undefined)
702
+ return -1;
703
+ return left.event.seq - right.event.seq || left.index - right.index;
704
+ });
705
+ return ordered.reduce((state, entry) => reduceAgentUIEvent(state, entry.event), createAgentUIState(sessionId));
706
+ }
707
+ /** Rebuild a live Agent UI store from persisted host events. Stable seq
708
+ * ordering and the store's event-id dedupe make repeated hydration safe. */
709
+ export function replayAgentUIEventLog(store, rows, decode) {
710
+ const ordered = rows
711
+ .map((row, index) => ({ row, index }))
712
+ .sort((left, right) => left.row.seq - right.row.seq || left.index - right.index);
713
+ for (const { row } of ordered) {
714
+ const decoded = decode(row);
715
+ if (!decoded)
716
+ continue;
717
+ for (const event of Array.isArray(decoded) ? decoded : [decoded]) {
718
+ store.dispatch(event);
719
+ }
720
+ }
721
+ return store.getState();
722
+ }
723
+ export function createAgentUISessionRegistry() {
724
+ const stores = new Map();
725
+ return {
726
+ get(sessionId) {
727
+ const existing = stores.get(sessionId);
728
+ if (existing)
729
+ return existing;
730
+ const created = createAgentUIStore(sessionId);
731
+ stores.set(sessionId, created);
732
+ return created;
733
+ },
734
+ has(sessionId) {
735
+ return stores.has(sessionId);
736
+ },
737
+ remove(sessionId) {
738
+ return stores.delete(sessionId);
739
+ },
740
+ clear() {
741
+ stores.clear();
742
+ },
743
+ };
744
+ }
745
+ export function createAgentUIStore(sessionId) {
746
+ let state = createAgentUIState(sessionId);
747
+ const listeners = new Set();
748
+ const streamSubscribers = new Map();
749
+ const getState = () => state;
750
+ return {
751
+ getState,
752
+ getSnapshot: getState,
753
+ dispatch: (event) => {
754
+ const stream = streamProjection(event);
755
+ const beforeText = stream
756
+ ? accumulatedTurnStream(state, event.turn_id, stream.kind)
757
+ : "";
758
+ const opensSegment = stream ? opensStreamSegment(state, event, stream.kind) : false;
759
+ const next = reduceAgentUIEvent(state, event);
760
+ if (next !== state) {
761
+ state = next;
762
+ if (stream) {
763
+ const afterText = accumulatedTurnStream(state, event.turn_id, stream.kind);
764
+ const delta = afterText.startsWith(beforeText)
765
+ ? afterText.slice(beforeText.length)
766
+ : "";
767
+ if (delta && event.turn_id) {
768
+ for (const subscriber of streamSubscribers.get(event.turn_id) ?? []) {
769
+ subscriber({ kind: stream.kind, text: delta });
770
+ }
771
+ }
772
+ }
773
+ if (!stream || opensSegment) {
774
+ for (const listener of listeners)
775
+ listener(state);
776
+ }
777
+ }
778
+ return state;
779
+ },
780
+ subscribe: (listener) => {
781
+ listeners.add(listener);
782
+ return () => listeners.delete(listener);
783
+ },
784
+ subscribeTurnStream: (turnId, listener) => {
785
+ let subscribers = streamSubscribers.get(turnId);
786
+ if (!subscribers) {
787
+ subscribers = new Set();
788
+ streamSubscribers.set(turnId, subscribers);
789
+ }
790
+ subscribers.add(listener);
791
+ const thought = accumulatedTurnStream(state, turnId, "thought");
792
+ if (thought)
793
+ listener({ kind: "thought", text: thought });
794
+ const assistant = accumulatedTurnStream(state, turnId, "assistant");
795
+ if (assistant)
796
+ listener({ kind: "assistant", text: assistant });
797
+ return () => {
798
+ const current = streamSubscribers.get(turnId);
799
+ if (!current)
800
+ return;
801
+ current.delete(listener);
802
+ if (current.size === 0)
803
+ streamSubscribers.delete(turnId);
804
+ };
805
+ },
806
+ };
807
+ }
808
+ function streamProjection(event) {
809
+ if (event.type === "agent.message_chunk")
810
+ return { kind: "assistant" };
811
+ if (event.type === "agent.thinking") {
812
+ const data = eventData(event);
813
+ return typeof data.text === "string" && data.text.length > 0
814
+ ? { kind: "thought" }
815
+ : undefined;
816
+ }
817
+ return undefined;
818
+ }
819
+ function accumulatedTurnStream(state, turnId, kind) {
820
+ if (!turnId)
821
+ return "";
822
+ const turn = state.turns[turnId];
823
+ if (!turn)
824
+ return "";
825
+ return turn.items.flatMap((item) => {
826
+ if (item.kind === "tool")
827
+ return [];
828
+ if (kind === "thought")
829
+ return item.kind === "thinking" ? [item.text] : [];
830
+ return item.kind === "message" && item.role === "assistant" ? [item.text] : [];
831
+ }).join("");
832
+ }
833
+ function opensStreamSegment(state, event, kind) {
834
+ if (!event.turn_id)
835
+ return false;
836
+ const tail = state.turns[event.turn_id]?.items.at(-1);
837
+ if (!tail || tail.kind === "tool")
838
+ return true;
839
+ if (kind === "thought") {
840
+ if (tail.kind !== "thinking")
841
+ return true;
842
+ }
843
+ else if (tail.kind !== "message" || tail.role !== "assistant") {
844
+ return true;
845
+ }
846
+ const data = eventData(event);
847
+ if (typeof data.message_id !== "string" || data.message_id.length === 0) {
848
+ return false;
849
+ }
850
+ return (tail.messageId ?? tail.id) !== data.message_id;
851
+ }
852
+ export * from "./presentation.js";
853
+ //# sourceMappingURL=index.js.map