@blade-hq/agent-kit 1.0.25 → 1.0.28

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 (287) hide show
  1. package/dist/chunk-7LEKQI47.js +32 -0
  2. package/dist/chunk-7LEKQI47.js.map +1 -0
  3. package/dist/{chunk-3I4ZURKH.js → chunk-BGNKHPCD.js} +223 -50
  4. package/dist/chunk-BGNKHPCD.js.map +1 -0
  5. package/dist/{chunk-4D4EXLVT.js → chunk-DQCXSPHP.js} +2 -2
  6. package/dist/chunk-HCQDDDOX.js +23 -0
  7. package/dist/chunk-HCQDDDOX.js.map +1 -0
  8. package/dist/{chunk-QODAKTG5.js → chunk-JCJFFJ42.js} +2 -31
  9. package/dist/chunk-JCJFFJ42.js.map +1 -0
  10. package/dist/{chunk-XCIDE3JW.js → chunk-OGHUIKCY.js} +7 -7
  11. package/dist/{chunk-WPLEMYL7.js → chunk-PYYDXV2A.js} +2 -2
  12. package/dist/{chunk-VJY6RLYU.js → chunk-TVWC3PED.js} +2 -2
  13. package/dist/{chunk-WVXXQ3KM.js → chunk-UWNQ4PXK.js} +134 -1201
  14. package/dist/chunk-UWNQ4PXK.js.map +1 -0
  15. package/dist/{chunk-M45K3554.js → chunk-YJ6BX3FU.js} +1382 -32
  16. package/dist/chunk-YJ6BX3FU.js.map +1 -0
  17. package/dist/client/auth.d.ts +8 -0
  18. package/dist/client/blade-client.d.ts +82 -0
  19. package/dist/client/index.d.ts +23 -15348
  20. package/dist/client/index.js +3 -1
  21. package/dist/client/resources/api-keys.d.ts +28 -0
  22. package/dist/client/resources/app-dev-templates.d.ts +93 -0
  23. package/dist/client/resources/auth.d.ts +26 -0
  24. package/dist/client/resources/env-buckets.d.ts +20 -0
  25. package/dist/client/resources/gis.d.ts +8 -0
  26. package/dist/client/resources/headless.d.ts +33 -0
  27. package/dist/client/resources/memories.d.ts +63 -0
  28. package/dist/client/resources/models.d.ts +26 -0
  29. package/dist/client/resources/published-apps.d.ts +8 -0
  30. package/dist/client/resources/registry.d.ts +58 -0
  31. package/dist/client/resources/runs.d.ts +8 -0
  32. package/dist/client/resources/scenarios.d.ts +49 -0
  33. package/dist/client/resources/sessions.d.ts +253 -0
  34. package/dist/client/resources/skills.d.ts +38 -0
  35. package/dist/client/resources/solutions.d.ts +31 -0
  36. package/dist/client/resources/user-preferences.d.ts +26 -0
  37. package/dist/client/rest.d.ts +19 -0
  38. package/dist/client/shared/projection/builder.d.ts +59 -0
  39. package/dist/client/shared/projection/helpers.d.ts +34 -0
  40. package/dist/client/shared/projection/history.d.ts +12 -0
  41. package/dist/client/shared/projection/index.d.ts +3 -0
  42. package/dist/client/shared/projection/state.d.ts +22 -0
  43. package/dist/client/socket.d.ts +9 -0
  44. package/dist/client/types/index.d.ts +8 -0
  45. package/dist/client/types/rest.d.ts +16316 -0
  46. package/dist/client/types/sdk-profile.d.ts +47 -0
  47. package/dist/client/types/socket-events.d.ts +389 -0
  48. package/dist/react/api/api-keys.d.ts +6 -0
  49. package/dist/react/api/app-dev-templates.d.ts +5 -0
  50. package/dist/react/api/auth.d.ts +7 -0
  51. package/dist/react/api/client.d.ts +8 -0
  52. package/dist/react/api/env-buckets.d.ts +10 -0
  53. package/dist/react/api/gis-api.d.ts +4 -0
  54. package/dist/react/api/memories.d.ts +14 -0
  55. package/dist/react/api/model-config.d.ts +68 -0
  56. package/dist/react/api/models.d.ts +13 -0
  57. package/dist/react/api/partner-skill.d.ts +2 -0
  58. package/dist/react/api/prod-solution.d.ts +456 -0
  59. package/dist/react/api/published-apps.d.ts +21 -0
  60. package/dist/react/api/published-apps.js +14 -0
  61. package/dist/react/api/published-apps.js.map +1 -0
  62. package/dist/react/api/registry.d.ts +46 -0
  63. package/dist/react/api/scenarios.d.ts +9 -0
  64. package/dist/react/api/scheduled-tasks.d.ts +24 -0
  65. package/dist/react/api/session-skill.d.ts +2 -0
  66. package/dist/react/api/sessions.d.ts +109 -0
  67. package/dist/react/api/sessions.js +93 -0
  68. package/dist/react/api/sessions.js.map +1 -0
  69. package/dist/react/api/skills.d.ts +27 -0
  70. package/dist/react/api/socket.d.ts +5 -0
  71. package/dist/react/api/solutions.d.ts +11 -0
  72. package/dist/react/api/user-preferences.d.ts +8 -0
  73. package/dist/react/asr/VoiceWaveform.d.ts +10 -0
  74. package/dist/react/asr/use-tiptap-voice-input.d.ts +29 -0
  75. package/dist/react/asr/use-voice-input.d.ts +17 -0
  76. package/dist/react/asr/voice-input-support.d.ts +5 -0
  77. package/dist/react/bootstrap.d.ts +4 -0
  78. package/dist/react/cards/register.d.ts +1 -2
  79. package/dist/react/cards/register.js +3 -2
  80. package/dist/react/cards/register.js.map +1 -1
  81. package/dist/react/components/ai-elements/file-tree.d.ts +26 -0
  82. package/dist/react/components/ai-elements/reasoning.d.ts +32 -0
  83. package/dist/react/components/ai-elements/shimmer.d.ts +11 -0
  84. package/dist/react/components/card/CardCodeBlock.d.ts +5 -0
  85. package/dist/react/components/card/CardContext.d.ts +7 -0
  86. package/dist/react/components/card/CardRenderer.d.ts +7 -0
  87. package/dist/react/components/card/CardStates.d.ts +8 -0
  88. package/dist/react/components/card/cards/attraction-card.d.ts +2 -0
  89. package/dist/react/components/card/cards/cite-card.d.ts +10 -0
  90. package/dist/react/components/card/cards/comprehensive-analysis-card.d.ts +2 -0
  91. package/dist/react/components/card/cards/conflict-detection-card.d.ts +4 -0
  92. package/dist/react/components/card/cards/counter.d.ts +2 -0
  93. package/dist/react/components/card/cards/damage-effect-card.d.ts +4 -0
  94. package/dist/react/components/card/cards/destination-card.d.ts +2 -0
  95. package/dist/react/components/card/cards/diff-card.d.ts +2 -0
  96. package/dist/react/components/card/cards/execution-order-card.d.ts +2 -0
  97. package/dist/react/components/card/cards/experience-card-with-options.d.ts +4 -0
  98. package/dist/react/components/card/cards/flight-card.d.ts +2 -0
  99. package/dist/react/components/card/cards/hotel-card.d.ts +2 -0
  100. package/dist/react/components/card/cards/kill-chain-card.d.ts +2 -0
  101. package/dist/react/components/card/cards/kill-chain-types.d.ts +157 -0
  102. package/dist/react/components/card/cards/map-card.d.ts +2 -0
  103. package/dist/react/components/card/cards/order-status-card.d.ts +2 -0
  104. package/dist/react/components/card/cards/patch-card.d.ts +15 -0
  105. package/dist/react/components/card/cards/product-recommendation-card.d.ts +2 -0
  106. package/dist/react/components/card/cards/reflection-optimization-card.d.ts +2 -0
  107. package/dist/react/components/card/cards/resolution-modifications-card.d.ts +2 -0
  108. package/dist/react/components/card/cards/resolution-summary-card.d.ts +2 -0
  109. package/dist/react/components/card/cards/restaurant-card.d.ts +2 -0
  110. package/dist/react/components/card/cards/shopping-list-card.d.ts +2 -0
  111. package/dist/react/components/card/cards/simulation-event-card.d.ts +4 -0
  112. package/dist/react/components/card/cards/survival-effect-card.d.ts +4 -0
  113. package/dist/react/components/card/cards/travel-itinerary-card.d.ts +2 -0
  114. package/dist/react/components/card/register.d.ts +1 -0
  115. package/dist/react/components/chat/AgentLoopBlock.d.ts +8 -0
  116. package/dist/react/components/chat/AskUserQuestionBlock.d.ts +32 -0
  117. package/dist/react/components/chat/AssistantTurnBlock.d.ts +28 -0
  118. package/dist/react/components/chat/AttachmentPreviewDialog.d.ts +26 -0
  119. package/dist/react/components/chat/BackgroundTasksPill.d.ts +3 -0
  120. package/dist/react/components/chat/ChatInput.d.ts +94 -0
  121. package/dist/react/components/chat/ChatView.d.ts +18 -0
  122. package/dist/react/components/chat/CompactionCard.d.ts +6 -0
  123. package/dist/react/components/chat/ConnectionBanner.d.ts +1 -0
  124. package/dist/react/components/chat/FileCompletionMenu.d.ts +13 -0
  125. package/dist/react/components/chat/FileSizeLimitDialog.d.ts +9 -0
  126. package/dist/react/components/chat/ImageLightbox.d.ts +11 -0
  127. package/dist/react/components/chat/MessageActions.d.ts +6 -0
  128. package/dist/react/components/chat/MessageContextPills.d.ts +6 -0
  129. package/dist/react/components/chat/MessageFileAttachmentList.d.ts +13 -0
  130. package/dist/react/components/chat/MessageList.d.ts +15 -0
  131. package/dist/react/components/chat/ProgressCircle.d.ts +12 -0
  132. package/dist/react/components/chat/RenderErrorBoundary.d.ts +19 -0
  133. package/dist/react/components/chat/ResourceIframe.d.ts +5 -0
  134. package/dist/react/components/chat/Shimmer.d.ts +6 -0
  135. package/dist/react/components/chat/SkillCompletionMenu.d.ts +9 -0
  136. package/dist/react/components/chat/SkillStatusBar.d.ts +8 -0
  137. package/dist/react/components/chat/StickyStatusBar.d.ts +10 -0
  138. package/dist/react/components/chat/TextAttachmentPills.d.ts +10 -0
  139. package/dist/react/components/chat/ThinkingToggle.d.ts +7 -0
  140. package/dist/react/components/chat/ToolCallBlock.d.ts +18 -0
  141. package/dist/react/components/chat/TurnNavRail.d.ts +11 -0
  142. package/dist/react/components/chat/UserMessageBubble.d.ts +20 -0
  143. package/dist/react/components/chat/WhatIfUserBubble.d.ts +13 -0
  144. package/dist/react/components/chat/customization.d.ts +82 -0
  145. package/dist/react/components/chat/display-utils.d.ts +35 -0
  146. package/dist/react/components/chat/extensions/file-mention.d.ts +12 -0
  147. package/dist/react/components/chat/extensions/skill-mention.d.ts +25 -0
  148. package/dist/react/components/chat/index.d.ts +16 -115
  149. package/dist/react/components/chat/index.js +8 -7
  150. package/dist/react/components/chat/scroll-anchor.d.ts +8 -0
  151. package/dist/react/components/chat/tool-renderers/BashRenderer.d.ts +2 -0
  152. package/dist/react/components/chat/tool-renderers/FileEditRenderer.d.ts +2 -0
  153. package/dist/react/components/chat/tool-renderers/FileReadRenderer.d.ts +2 -0
  154. package/dist/react/components/chat/tool-renderers/SearchRenderer.d.ts +2 -0
  155. package/dist/react/components/chat/tool-renderers/SubmitResultRenderer.d.ts +2 -0
  156. package/dist/react/components/chat/tool-renderers/registry.d.ts +9 -0
  157. package/dist/react/components/chat/tool-renderers/shared.d.ts +26 -0
  158. package/dist/react/components/chat/whatif-quote-context.d.ts +15 -0
  159. package/dist/react/components/markdown/ExternalLinkDialog.d.ts +8 -0
  160. package/dist/react/components/markdown/FileCardComponent.d.ts +10 -0
  161. package/dist/react/components/markdown/MarkdownContent.d.ts +19 -0
  162. package/dist/react/components/model/ModelSelector.d.ts +9 -0
  163. package/dist/react/components/plan/PlanSummaryCard.d.ts +8 -0
  164. package/dist/react/components/plan/PlanVisualization.d.ts +13 -0
  165. package/dist/react/components/plan/debug-log.d.ts +21 -0
  166. package/dist/react/components/plan/extract-plan-messages.d.ts +2 -0
  167. package/dist/react/components/plan/index.d.ts +6 -110
  168. package/dist/react/components/plan/index.js +7 -6
  169. package/dist/react/components/plan/index.js.map +1 -1
  170. package/dist/react/components/plan/parse-plan-messages.d.ts +10 -0
  171. package/dist/react/components/plan/parse-plan-tree.d.ts +16 -0
  172. package/dist/react/components/plan/phases/PlanMindMap.d.ts +8 -0
  173. package/dist/react/components/plan/phases/PlanStatusIcon.d.ts +5 -0
  174. package/dist/react/components/plan/phases/PlanTree.d.ts +8 -0
  175. package/dist/react/components/plan/phases/SkillAnalysis.d.ts +7 -0
  176. package/dist/react/components/plan/phases/SkillDiscovery.d.ts +10 -0
  177. package/dist/react/components/plan/types.d.ts +56 -0
  178. package/dist/react/components/session/SessionDetail.d.ts +8 -0
  179. package/dist/react/components/session/SessionList.d.ts +9 -0
  180. package/dist/react/components/session/SessionListItem.d.ts +8 -0
  181. package/dist/react/components/session/StatusBadge.d.ts +3 -0
  182. package/dist/react/components/session/index.d.ts +5 -53
  183. package/dist/react/components/session/index.js +6 -5
  184. package/dist/react/components/session/index.js.map +1 -1
  185. package/dist/react/components/session/session-utils.d.ts +19 -0
  186. package/dist/react/components/ui/collapsible.d.ts +5 -0
  187. package/dist/react/components/workspace/FileTree.d.ts +21 -0
  188. package/dist/react/components/workspace/WorkspaceFilesPanel.d.ts +30 -0
  189. package/dist/react/components/workspace/file-icon-assets.d.ts +3 -0
  190. package/dist/react/components/workspace/index.d.ts +2 -59
  191. package/dist/react/components/workspace/index.js +6 -5
  192. package/dist/react/components/workspace/index.js.map +1 -1
  193. package/dist/react/context.d.ts +2 -0
  194. package/dist/react/devtools/bridge-devtools/BridgeDevtoolsFab.d.ts +1 -0
  195. package/dist/react/devtools/bridge-devtools/index.d.ts +3 -36
  196. package/dist/react/devtools/bridge-devtools/mount.d.ts +1 -0
  197. package/dist/react/devtools/bridge-devtools/store.d.ts +15 -0
  198. package/dist/react/devtools/bridge-devtools/tap.d.ts +5 -0
  199. package/dist/react/devtools/bridge-devtools/types.d.ts +29 -0
  200. package/dist/react/hooks/use-background-tasks.d.ts +7 -0
  201. package/dist/react/hooks/use-card-state.d.ts +1 -0
  202. package/dist/react/hooks/use-chat.d.ts +13 -0
  203. package/dist/react/hooks/use-check-skill-file.d.ts +4 -0
  204. package/dist/react/hooks/use-check-solution-file.d.ts +4 -0
  205. package/dist/react/hooks/use-context-stats.d.ts +7 -0
  206. package/dist/react/hooks/use-gis.d.ts +17 -0
  207. package/dist/react/hooks/use-global-skill-stats.d.ts +6 -0
  208. package/dist/react/hooks/use-input-history.d.ts +7 -0
  209. package/dist/react/hooks/use-model-preferences.d.ts +18 -0
  210. package/dist/react/hooks/use-registry.d.ts +53 -0
  211. package/dist/react/hooks/use-resolved-model.d.ts +6 -0
  212. package/dist/react/hooks/use-session.d.ts +10 -0
  213. package/dist/react/hooks/use-skill-stats.d.ts +7 -0
  214. package/dist/react/hooks/use-skills.d.ts +6 -0
  215. package/dist/react/hooks/use-token-pressure.d.ts +6 -0
  216. package/dist/react/index.d.ts +124 -2034
  217. package/dist/react/index.js +125 -50
  218. package/dist/react/index.js.map +1 -1
  219. package/dist/react/lib/analytics.d.ts +7 -0
  220. package/dist/react/lib/attachment-upload.d.ts +10 -0
  221. package/dist/react/lib/card-registry.d.ts +35 -0
  222. package/dist/react/lib/chat.d.ts +48 -0
  223. package/dist/react/lib/code-highlight.d.ts +9 -0
  224. package/dist/react/lib/html-element-selection.d.ts +140 -0
  225. package/dist/react/lib/html-source-locator.d.ts +16 -0
  226. package/dist/react/lib/open-session-file.d.ts +2 -0
  227. package/dist/react/lib/parent-bridge.d.ts +22 -0
  228. package/dist/react/lib/preview-dispatch.d.ts +24 -0
  229. package/dist/react/lib/resource-bridge.d.ts +11 -0
  230. package/dist/react/lib/session-file-preview.d.ts +8 -0
  231. package/dist/react/lib/step-ranges.d.ts +42 -0
  232. package/dist/react/lib/tool-preview.d.ts +2 -0
  233. package/dist/react/lib/ui-meta.d.ts +9 -0
  234. package/dist/react/lib/utils.d.ts +3 -0
  235. package/dist/react/lib/whatif-prompt.d.ts +45 -0
  236. package/dist/react/provider.d.ts +8 -0
  237. package/dist/react/routes.d.ts +1 -0
  238. package/dist/react/schemas/background.d.ts +16 -0
  239. package/dist/react/schemas/event.d.ts +51 -0
  240. package/dist/react/schemas/gis.d.ts +50 -0
  241. package/dist/{AskUserQuestionBlock---kOTouk.d.ts → react/schemas/message.d.ts} +15 -48
  242. package/dist/react/schemas/partner-skill.d.ts +46 -0
  243. package/dist/{projection-BWYEFYNn.d.ts → react/schemas/projection.d.ts} +12 -10
  244. package/dist/react/schemas/published-apps.d.ts +38 -0
  245. package/dist/react/schemas/scheduled-task.d.ts +32 -0
  246. package/dist/react/schemas/session.d.ts +121 -0
  247. package/dist/react/schemas/skill.d.ts +50 -0
  248. package/dist/react/schemas/studio/agent.d.ts +12 -0
  249. package/dist/react/schemas/studio/database.d.ts +39 -0
  250. package/dist/react/schemas/studio/env.d.ts +7 -0
  251. package/dist/react/schemas/studio/knowledge.d.ts +18 -0
  252. package/dist/react/schemas/studio/resource-base.d.ts +7 -0
  253. package/dist/react/schemas/studio/scene.d.ts +12 -0
  254. package/dist/react/schemas/studio/tool.d.ts +25 -0
  255. package/dist/react/schemas/task.d.ts +12 -0
  256. package/dist/react/sockets/event-bridge.d.ts +115 -0
  257. package/dist/react/sockets/socket-state.d.ts +4 -0
  258. package/dist/react/stores/answer-callback-store.d.ts +9 -0
  259. package/dist/react/stores/auth-store.d.ts +38 -0
  260. package/dist/react/stores/background-store.d.ts +13 -0
  261. package/dist/react/stores/card-state-store.d.ts +10 -0
  262. package/dist/react/stores/chat-store.d.ts +34 -0
  263. package/dist/react/stores/client-aware.d.ts +7 -0
  264. package/dist/react/stores/connection-store.d.ts +14 -0
  265. package/dist/react/stores/gis-store.d.ts +19 -0
  266. package/dist/react/stores/index.d.ts +14 -0
  267. package/dist/react/stores/runtime-features-store.d.ts +21 -0
  268. package/dist/react/stores/runtime-store.d.ts +18 -0
  269. package/dist/react/stores/session-store.d.ts +44 -0
  270. package/dist/react/stores/task-store.d.ts +9 -0
  271. package/dist/react/stores/ui-bridge-store.d.ts +32 -0
  272. package/dist/react/stores/ui-store.d.ts +69 -0
  273. package/dist/react/types/index.d.ts +7 -0
  274. package/dist/react/types/solution.d.ts +101 -0
  275. package/package.json +41 -11
  276. package/dist/SkillStatusBar-U6fbQxMu.d.ts +0 -340
  277. package/dist/blade-client-qTOovekU.d.ts +0 -1609
  278. package/dist/chunk-3I4ZURKH.js.map +0 -1
  279. package/dist/chunk-M45K3554.js.map +0 -1
  280. package/dist/chunk-QODAKTG5.js.map +0 -1
  281. package/dist/chunk-WVXXQ3KM.js.map +0 -1
  282. package/dist/session-CNnotR90.d.ts +0 -227
  283. package/dist/sessions-BvfLGbjw.d.ts +0 -177
  284. /package/dist/{chunk-4D4EXLVT.js.map → chunk-DQCXSPHP.js.map} +0 -0
  285. /package/dist/{chunk-XCIDE3JW.js.map → chunk-OGHUIKCY.js.map} +0 -0
  286. /package/dist/{chunk-WPLEMYL7.js.map → chunk-PYYDXV2A.js.map} +0 -0
  287. /package/dist/{chunk-VJY6RLYU.js.map → chunk-TVWC3PED.js.map} +0 -0
@@ -71,6 +71,30 @@ async function readErrorDetail(response) {
71
71
  }
72
72
  }
73
73
 
74
+ // src/client/resources/app-dev-templates.ts
75
+ var AppDevTemplatesResource = class {
76
+ constructor(client) {
77
+ this.client = client;
78
+ }
79
+ client;
80
+ list(params) {
81
+ const query = new URLSearchParams();
82
+ if (typeof params?.offset === "number") query.set("offset", String(params.offset));
83
+ if (typeof params?.limit === "number") query.set("limit", String(params.limit));
84
+ const suffix = query.toString() ? `?${query.toString()}` : "";
85
+ return this.client.json("GET", `/api/app-dev/templates${suffix}`);
86
+ }
87
+ get(slug) {
88
+ return this.client.json("GET", `/api/app-dev/templates/${encodeURIComponent(slug)}`);
89
+ }
90
+ getMediaUrl(slug, path) {
91
+ const encodedPath = path.split("/").map((part) => encodeURIComponent(part)).join("/");
92
+ return this.client.buildAuthedUrl(
93
+ `/api/app-dev/templates/${encodeURIComponent(slug)}/media/${encodedPath}`
94
+ );
95
+ }
96
+ };
97
+
74
98
  // src/client/resources/auth.ts
75
99
  var AuthResource = class {
76
100
  constructor(client) {
@@ -273,7 +297,7 @@ var HeadlessResource = class {
273
297
  socket.on("chat:start", onChatStart);
274
298
  socket.on("chat:end", onChatEnd);
275
299
  socket.on("system:error", onSystemError);
276
- socket.emit("session:subscribe", { session_id });
300
+ socket.emit("session:subscribe", { session_id, event_format: "raw" });
277
301
  socket.emit("chat:send", {
278
302
  session_id,
279
303
  message: prompt,
@@ -382,10 +406,12 @@ var ModelOption = type({
382
406
  id: "string",
383
407
  label: "string",
384
408
  "inputModalities?": "string[]",
385
- "supportsImage?": "boolean"
409
+ "supportsImage?": "boolean",
410
+ "thinkingAvailable?": "boolean"
386
411
  });
387
412
  var ModelsConfig = type({
388
413
  default: "string",
414
+ "thinkingAvailable?": "boolean",
389
415
  models: ModelOption.array()
390
416
  });
391
417
  var ModelsResource = class {
@@ -506,6 +532,1326 @@ var RegistryResource = class {
506
532
  }
507
533
  };
508
534
 
535
+ // src/client/shared/projection/helpers.ts
536
+ function upsertToolCall(state, toolCallId, toolName, displayName, args) {
537
+ if (!toolCallId) return;
538
+ let found = false;
539
+ for (let i = 0; i < state.toolCalls.length; i++) {
540
+ if (state.toolCalls[i].id !== toolCallId) continue;
541
+ const tc = state.toolCalls[i];
542
+ state.toolCalls[i] = {
543
+ ...tc,
544
+ tool_name: toolName || tc.tool_name,
545
+ display_name: displayName || tc.display_name,
546
+ arguments: args || tc.arguments
547
+ };
548
+ found = true;
549
+ break;
550
+ }
551
+ if (!found) {
552
+ state.toolCalls.push({
553
+ id: toolCallId,
554
+ tool_name: toolName,
555
+ display_name: displayName,
556
+ arguments: args,
557
+ status: "pending"
558
+ });
559
+ }
560
+ let blockFound = false;
561
+ for (let i = 0; i < state.blocks.length; i++) {
562
+ const b = state.blocks[i];
563
+ if (b.type !== "tool_use" || b.tool_call_id !== toolCallId) continue;
564
+ state.blocks[i] = {
565
+ ...b,
566
+ content: args || b.content,
567
+ tool_name: toolName || b.tool_name,
568
+ display_name: displayName || b.display_name
569
+ };
570
+ blockFound = true;
571
+ break;
572
+ }
573
+ if (!blockFound) {
574
+ state.blocks.push({
575
+ type: "tool_use",
576
+ content: args,
577
+ tool_call_id: toolCallId,
578
+ tool_name: toolName || null,
579
+ display_name: displayName || null
580
+ });
581
+ }
582
+ }
583
+ function applyToolResult(state, toolCallId, result, status, durationMs, sourceLoop) {
584
+ let toolName = "";
585
+ let displayName = "";
586
+ let finalResult = result;
587
+ for (let i = 0; i < state.toolCalls.length; i++) {
588
+ const tc = state.toolCalls[i];
589
+ if (tc.id !== toolCallId) continue;
590
+ if (typeof result === "string") {
591
+ finalResult = maybeEnrichAskUserResult(tc.tool_name, result, sourceLoop);
592
+ }
593
+ const update = { status, result: finalResult };
594
+ if (durationMs != null) update.duration_ms = durationMs;
595
+ state.toolCalls[i] = { ...tc, ...update };
596
+ toolName = tc.tool_name;
597
+ displayName = tc.display_name;
598
+ break;
599
+ }
600
+ upsertToolResultBlock(state, toolCallId, finalResult, toolName, displayName);
601
+ }
602
+ function appendToolResultDelta(state, toolCallId, delta) {
603
+ if (!toolCallId || !delta) return;
604
+ let toolName = "";
605
+ let displayName = "";
606
+ let currentResult = "";
607
+ for (let i = 0; i < state.toolCalls.length; i++) {
608
+ const tc = state.toolCalls[i];
609
+ if (tc.id !== toolCallId) continue;
610
+ toolName = tc.tool_name;
611
+ displayName = tc.display_name;
612
+ if (typeof tc.result === "string") currentResult = tc.result;
613
+ state.toolCalls[i] = { ...tc, result: currentResult + delta };
614
+ break;
615
+ }
616
+ for (const block of state.blocks) {
617
+ if (block.type !== "tool_result" || block.tool_call_id !== toolCallId) continue;
618
+ if (typeof block.content === "string") currentResult = block.content;
619
+ break;
620
+ }
621
+ upsertToolResultBlock(state, toolCallId, currentResult + delta, toolName, displayName);
622
+ }
623
+ function upsertToolResultBlock(state, toolCallId, content, toolName, displayName) {
624
+ for (let i = 0; i < state.blocks.length; i++) {
625
+ const block = state.blocks[i];
626
+ if (block.type !== "tool_result" || block.tool_call_id !== toolCallId) continue;
627
+ state.blocks[i] = {
628
+ ...block,
629
+ content,
630
+ tool_name: toolName || block.tool_name,
631
+ display_name: displayName || block.display_name
632
+ };
633
+ return;
634
+ }
635
+ state.blocks.push({
636
+ type: "tool_result",
637
+ content,
638
+ tool_call_id: toolCallId,
639
+ tool_name: toolName || null,
640
+ display_name: displayName || null
641
+ });
642
+ }
643
+ function appendTextBlock(state, blockType, content) {
644
+ if (content == null || content === "") return;
645
+ const text = String(content);
646
+ const lastBlock = state.blocks[state.blocks.length - 1];
647
+ if (lastBlock && lastBlock.type === blockType && typeof lastBlock.content === "string") {
648
+ state.blocks[state.blocks.length - 1] = {
649
+ ...lastBlock,
650
+ content: lastBlock.content + text
651
+ };
652
+ return;
653
+ }
654
+ state.blocks.push({ type: blockType, content: text });
655
+ }
656
+ function appendToolCallArguments(state, toolCallId, delta) {
657
+ let newArgs = "";
658
+ for (let i = 0; i < state.toolCalls.length; i++) {
659
+ const tc = state.toolCalls[i];
660
+ if (tc.id === toolCallId) {
661
+ newArgs = tc.arguments + delta;
662
+ state.toolCalls[i] = { ...tc, arguments: newArgs };
663
+ break;
664
+ }
665
+ }
666
+ if (!newArgs) return;
667
+ for (let i = 0; i < state.blocks.length; i++) {
668
+ const b = state.blocks[i];
669
+ if (b.type === "tool_use" && b.tool_call_id === toolCallId) {
670
+ state.blocks[i] = { ...b, content: newArgs };
671
+ break;
672
+ }
673
+ }
674
+ }
675
+ function maybeEnrichAskUserResult(toolName, result, sourceLoop) {
676
+ if (!sourceLoop) return result;
677
+ const normalized = toolName.includes(":") ? toolName.split(":").pop() : toolName;
678
+ if (normalized !== "AskUserQuestion") return result;
679
+ try {
680
+ const payload = JSON.parse(result);
681
+ if (typeof payload !== "object" || payload === null) return result;
682
+ payload.source_loop = sourceLoop;
683
+ return JSON.stringify(payload);
684
+ } catch {
685
+ return result;
686
+ }
687
+ }
688
+ function buildSystemNotificationTurn(sequence, turnId, loopId, notificationType, status, title, detail, metadata) {
689
+ return {
690
+ id: turnId,
691
+ sequence,
692
+ turn_id: turnId,
693
+ loop_id: loopId,
694
+ kind: "message",
695
+ role: "system",
696
+ status: "completed",
697
+ blocks: [
698
+ {
699
+ type: "system_notification",
700
+ content: {
701
+ notification_type: notificationType,
702
+ status,
703
+ title,
704
+ detail,
705
+ metadata
706
+ }
707
+ }
708
+ ],
709
+ tool_calls: [],
710
+ model: null,
711
+ usage: null,
712
+ duration_ms: 0
713
+ };
714
+ }
715
+ function buildSystemNotificationBlock(notificationType, status, title, detail, metadata) {
716
+ return {
717
+ type: "system_notification",
718
+ content: {
719
+ notification_type: notificationType,
720
+ status,
721
+ title,
722
+ detail,
723
+ metadata
724
+ }
725
+ };
726
+ }
727
+ function buildMarkerTurn(sequence, turnId, loopId, blockType, content) {
728
+ return {
729
+ id: turnId,
730
+ sequence,
731
+ turn_id: turnId,
732
+ loop_id: loopId,
733
+ kind: "message",
734
+ role: "assistant",
735
+ status: "completed",
736
+ blocks: [{ type: blockType, content }],
737
+ tool_calls: [],
738
+ model: null,
739
+ usage: null,
740
+ duration_ms: 0
741
+ };
742
+ }
743
+ function buildCompactionTurn(sequence, compactionId, loopId, status, data) {
744
+ const tokensBefore = asInt(data.tokens_before);
745
+ const tokensAfter = asInt(data.tokens_after);
746
+ let savedRatio = null;
747
+ if (tokensBefore && tokensBefore > 0 && tokensAfter != null) {
748
+ savedRatio = 1 - tokensAfter / tokensBefore;
749
+ } else {
750
+ savedRatio = asFloat(data.saved_ratio);
751
+ }
752
+ let archivedCount = asInt(data.archived_count);
753
+ if (archivedCount == null && Array.isArray(data.archived_files)) {
754
+ archivedCount = data.archived_files.length;
755
+ }
756
+ const content = data.content;
757
+ const summaryFull = compactionSummaryFull(content);
758
+ const summaryPreview = summaryFull ? summaryFull.split("\n").map((l) => l.trim()).filter(Boolean).join(" ").slice(0, 200) : null;
759
+ return {
760
+ id: `compaction:${compactionId}`,
761
+ sequence,
762
+ turn_id: `compaction:${compactionId}`,
763
+ loop_id: loopId,
764
+ kind: "compaction",
765
+ role: "system",
766
+ status,
767
+ blocks: [],
768
+ tool_calls: [],
769
+ model: null,
770
+ usage: null,
771
+ duration_ms: 0,
772
+ compaction_id: compactionId,
773
+ summary_preview: summaryPreview,
774
+ summary_full: summaryFull,
775
+ archived_count: archivedCount,
776
+ tokens_before: tokensBefore,
777
+ tokens_after: tokensAfter,
778
+ saved_ratio: savedRatio,
779
+ trigger: asTrigger(data.trigger),
780
+ failure_reason: typeof data.reason === "string" && data.reason ? data.reason : null,
781
+ fallback_applied: typeof data.fallback_applied === "boolean" ? data.fallback_applied : null
782
+ };
783
+ }
784
+ function compactionSummaryFull(content) {
785
+ const text = String(content ?? "");
786
+ if (!text) return null;
787
+ const cleaned = text.replace("<compaction-summary>", "").replace("</compaction-summary>", "").replace(/\r\n/g, "\n").replace(/\r/g, "\n").trim();
788
+ return cleaned || null;
789
+ }
790
+ function asInt(value) {
791
+ if (typeof value === "boolean") return null;
792
+ if (typeof value === "number") return Math.trunc(value);
793
+ return null;
794
+ }
795
+ function asFloat(value) {
796
+ if (typeof value === "boolean") return null;
797
+ if (typeof value === "number") return value;
798
+ return null;
799
+ }
800
+ function asTrigger(value) {
801
+ if (value === "auto" || value === "manual" || value === "forced_retry") return value;
802
+ return null;
803
+ }
804
+ function setToolCallStatus(turn, toolCallId, status, result, pendingQuestionRef) {
805
+ if (!turn || !toolCallId) return;
806
+ const toolCalls = "toolCalls" in turn ? turn.toolCalls : turn.tool_calls;
807
+ for (let i = 0; i < toolCalls.length; i++) {
808
+ if (toolCalls[i].id !== toolCallId) continue;
809
+ toolCalls[i] = {
810
+ ...toolCalls[i],
811
+ status,
812
+ result,
813
+ pending_question_ref: pendingQuestionRef
814
+ };
815
+ return;
816
+ }
817
+ }
818
+ function applyAskUserPauseToTurn(turn, pauseToolData, toolCallId, childLoopName, description, displayNameResolver) {
819
+ if (!turn || !toolCallId) return;
820
+ const sourceLoop = childLoopName ? { loop_name: childLoopName, description } : null;
821
+ const toolName = String(pauseToolData.name ?? "AskUserQuestion");
822
+ const args = JSON.stringify(pauseToolData.arguments ?? {});
823
+ const result = askUserResultFromPausePayload(pauseToolData, sourceLoop);
824
+ const isTurnState = "toolCalls" in turn;
825
+ const toolCalls = isTurnState ? turn.toolCalls : turn.tool_calls;
826
+ const blocks = turn.blocks;
827
+ const displayName = displayNameResolver(toolName);
828
+ let found = false;
829
+ for (let i = 0; i < toolCalls.length; i++) {
830
+ if (toolCalls[i].id !== toolCallId) continue;
831
+ toolCalls[i] = {
832
+ ...toolCalls[i],
833
+ tool_name: toolName || toolCalls[i].tool_name,
834
+ display_name: displayName || toolCalls[i].display_name,
835
+ arguments: args || toolCalls[i].arguments
836
+ };
837
+ found = true;
838
+ break;
839
+ }
840
+ if (!found) {
841
+ toolCalls.push({
842
+ id: toolCallId,
843
+ tool_name: toolName,
844
+ display_name: displayName,
845
+ arguments: args,
846
+ status: "pending"
847
+ });
848
+ }
849
+ let blockFound = false;
850
+ for (let i = 0; i < blocks.length; i++) {
851
+ if (blocks[i].type !== "tool_use" || blocks[i].tool_call_id !== toolCallId) continue;
852
+ blocks[i] = { ...blocks[i], content: args, tool_name: toolName, display_name: displayName };
853
+ blockFound = true;
854
+ break;
855
+ }
856
+ if (!blockFound) {
857
+ blocks.push({
858
+ type: "tool_use",
859
+ content: args,
860
+ tool_call_id: toolCallId,
861
+ tool_name: toolName,
862
+ display_name: displayName
863
+ });
864
+ }
865
+ setToolCallStatus(turn, toolCallId, "awaiting_answer", result, null);
866
+ let resultBlockFound = false;
867
+ for (let i = 0; i < blocks.length; i++) {
868
+ if (blocks[i].type !== "tool_result" || blocks[i].tool_call_id !== toolCallId) continue;
869
+ blocks[i] = { ...blocks[i], content: result };
870
+ resultBlockFound = true;
871
+ break;
872
+ }
873
+ if (!resultBlockFound) {
874
+ blocks.push({
875
+ type: "tool_result",
876
+ content: result,
877
+ tool_call_id: toolCallId,
878
+ tool_name: toolName,
879
+ display_name: displayName
880
+ });
881
+ }
882
+ }
883
+ function applyChildPauseToParent(parentTurn, parentToolCallId, childLoopName, childToolCallId, description, displayNameResolver) {
884
+ if (!parentTurn || !parentToolCallId) return;
885
+ const toolCalls = "toolCalls" in parentTurn ? parentTurn.toolCalls : parentTurn.tool_calls;
886
+ const blocks = parentTurn.blocks;
887
+ const displayName = displayNameResolver("Agent");
888
+ let found = false;
889
+ for (let i = 0; i < toolCalls.length; i++) {
890
+ if (toolCalls[i].id !== parentToolCallId) continue;
891
+ toolCalls[i] = {
892
+ ...toolCalls[i],
893
+ tool_name: "Agent",
894
+ display_name: displayName || toolCalls[i].display_name
895
+ };
896
+ found = true;
897
+ break;
898
+ }
899
+ if (!found) {
900
+ toolCalls.push({
901
+ id: parentToolCallId,
902
+ tool_name: "Agent",
903
+ display_name: displayName,
904
+ arguments: "",
905
+ status: "pending"
906
+ });
907
+ }
908
+ let blockFound = false;
909
+ for (let i = 0; i < blocks.length; i++) {
910
+ if (blocks[i].type !== "tool_use" || blocks[i].tool_call_id !== parentToolCallId) continue;
911
+ blockFound = true;
912
+ break;
913
+ }
914
+ if (!blockFound) {
915
+ blocks.push({
916
+ type: "tool_use",
917
+ content: "",
918
+ tool_call_id: parentToolCallId,
919
+ tool_name: "Agent",
920
+ display_name: displayName
921
+ });
922
+ }
923
+ setToolCallStatus(parentTurn, parentToolCallId, "awaiting_answer", null, {
924
+ child_loop_name: childLoopName,
925
+ child_tool_call_id: childToolCallId,
926
+ description: description || null
927
+ });
928
+ }
929
+ function askUserResultFromPausePayload(pauseToolData, sourceLoop) {
930
+ const args = typeof pauseToolData.arguments === "object" && pauseToolData.arguments !== null ? pauseToolData.arguments : {};
931
+ const payload = { questions: args.questions ?? [] };
932
+ if (sourceLoop) payload.source_loop = sourceLoop;
933
+ return JSON.stringify(payload);
934
+ }
935
+ function sourceLoopFor(loopId, loopDescriptions) {
936
+ if (loopId === "root") return null;
937
+ const description = loopDescriptions.get(loopId);
938
+ if (!description) return null;
939
+ return { loop_name: loopId, description };
940
+ }
941
+ function normalizeChildPause(pausePayload) {
942
+ const rawPtd = pausePayload.pause_tool_data;
943
+ const pauseToolData = typeof rawPtd === "object" && rawPtd !== null ? { ...rawPtd } : { ...pausePayload };
944
+ let sourceLoop = pauseToolData.source_loop;
945
+ if (typeof sourceLoop !== "object" || sourceLoop === null) {
946
+ sourceLoop = pausePayload.source_loop;
947
+ }
948
+ const childLoopName = String(pausePayload.child_loop_name ?? "") || (typeof sourceLoop === "object" && sourceLoop ? String(sourceLoop.name ?? "") : "");
949
+ const childToolCallId = String(
950
+ pausePayload.child_pause_tool_call_id ?? pauseToolData.tool_call_id ?? ""
951
+ );
952
+ const description = typeof sourceLoop === "object" && sourceLoop ? String(sourceLoop.description ?? "") : "";
953
+ if (childLoopName && description) {
954
+ pauseToolData.source_loop = { name: childLoopName, description };
955
+ }
956
+ return { pauseToolData, childLoopName, childToolCallId, description };
957
+ }
958
+
959
+ // src/react/schemas/message.ts
960
+ function inferToolStatus(resultStr) {
961
+ if (resultStr.includes('"Cancelled by user"')) return "cancelled";
962
+ try {
963
+ const parsed = JSON.parse(resultStr);
964
+ if (typeof parsed === "object" && parsed !== null) {
965
+ if ("error" in parsed && parsed.error) return "error";
966
+ const nested = parsed.result;
967
+ if (typeof nested === "object" && nested !== null && "error" in nested && nested.error) {
968
+ return "error";
969
+ }
970
+ }
971
+ } catch {
972
+ }
973
+ return "done";
974
+ }
975
+
976
+ // src/client/shared/projection/state.ts
977
+ function createTurnState(turnId, loopId, opts = {}) {
978
+ return {
979
+ turnId,
980
+ loopId,
981
+ role: "assistant",
982
+ model: opts.model ?? null,
983
+ startedAt: Date.now(),
984
+ contextWindow: opts.contextWindow ?? 0,
985
+ blocks: [],
986
+ toolCalls: [],
987
+ usage: null,
988
+ memoryRefs: opts.memoryRefs ?? null,
989
+ parentForkToolCallId: null
990
+ };
991
+ }
992
+ function snapshot(state, sequence, status) {
993
+ return {
994
+ id: state.turnId,
995
+ sequence,
996
+ turn_id: state.turnId,
997
+ loop_id: state.loopId,
998
+ kind: "message",
999
+ role: state.role,
1000
+ status,
1001
+ blocks: [...state.blocks],
1002
+ tool_calls: [...state.toolCalls],
1003
+ model: state.model,
1004
+ usage: state.usage ? { ...state.usage } : null,
1005
+ duration_ms: Math.max(0, Date.now() - state.startedAt),
1006
+ started_at: new Date(state.startedAt).toISOString(),
1007
+ context_window: state.contextWindow,
1008
+ memory_refs: state.memoryRefs,
1009
+ parent_fork_tool_call_id: state.parentForkToolCallId
1010
+ };
1011
+ }
1012
+ var PAUSE_TOOL_NAMES = /* @__PURE__ */ new Set(["AskUserQuestion", "ExitPlanMode"]);
1013
+ function toolStatusFromResult(result) {
1014
+ const text = typeof result === "string" ? result : Array.isArray(result) ? result.filter(
1015
+ (p) => typeof p === "object" && p !== null && p.type === "text"
1016
+ ).map((p) => p.text ?? "").join("\n") : String(result ?? "");
1017
+ return inferToolStatus(text);
1018
+ }
1019
+
1020
+ // src/client/shared/projection/builder.ts
1021
+ var ClientProjectionBuilder = class {
1022
+ activeTurns = /* @__PURE__ */ new Map();
1023
+ lastTurnIds = /* @__PURE__ */ new Map();
1024
+ latestTurns = /* @__PURE__ */ new Map();
1025
+ loopDescriptions = /* @__PURE__ */ new Map();
1026
+ pendingChildPauses = /* @__PURE__ */ new Map();
1027
+ pendingMemoryRefs = /* @__PURE__ */ new Map();
1028
+ activeCompactions = /* @__PURE__ */ new Map();
1029
+ seq = 0;
1030
+ syntheticCounter = 0;
1031
+ displayNameResolver;
1032
+ constructor(displayNameResolver) {
1033
+ this.displayNameResolver = displayNameResolver ?? ((n) => n);
1034
+ }
1035
+ processBatch(events) {
1036
+ const lastUpsertByTurn = /* @__PURE__ */ new Map();
1037
+ const nonUpserts = [];
1038
+ for (const event of events) {
1039
+ const updates = this.processEvent(event);
1040
+ if (!updates) continue;
1041
+ for (const u of updates) {
1042
+ if (u.kind === "upsert") {
1043
+ lastUpsertByTurn.set(u.turn.turn_id, u);
1044
+ } else {
1045
+ nonUpserts.push(u);
1046
+ }
1047
+ }
1048
+ }
1049
+ return [...nonUpserts, ...lastUpsertByTurn.values()];
1050
+ }
1051
+ processEvent(event) {
1052
+ const payload = event.payload;
1053
+ const loopId = String(payload.loop_name ?? "root");
1054
+ switch (event.type) {
1055
+ case "memory:inject:done":
1056
+ return this.onMemoryInject(loopId, payload);
1057
+ case "memory:inject:none":
1058
+ return null;
1059
+ case "loop:turn":
1060
+ return this.onLoopTurn(loopId, payload);
1061
+ case "mode:change":
1062
+ return this.onModeChange(loopId, payload);
1063
+ case "plan:status:update":
1064
+ return this.onPlanStatusUpdate(loopId, payload);
1065
+ case "workspace:changed":
1066
+ return this.onWorkspaceChanged(loopId, payload);
1067
+ case "agent:start":
1068
+ return this.onAgentStart(loopId, payload);
1069
+ case "bg:started":
1070
+ return this.onBgStarted(loopId, payload);
1071
+ case "bg:tasks_completed":
1072
+ return this.onBgTasksCompleted(loopId, payload);
1073
+ case "loop:ask_user_answer":
1074
+ return this.onAskUserAnswer(loopId, payload);
1075
+ case "user:message":
1076
+ return this.onUserMessage(loopId, payload);
1077
+ }
1078
+ if (event.type.startsWith("compaction:"))
1079
+ return this.onCompaction(event.type, loopId, payload);
1080
+ const state = this.activeTurns.get(loopId);
1081
+ if (!state) {
1082
+ if (event.type === "chat:end") {
1083
+ this.pendingMemoryRefs.delete(loopId);
1084
+ return null;
1085
+ }
1086
+ if (event.type === "agent:end") return this.onAgentEnd(null, loopId, payload);
1087
+ return null;
1088
+ }
1089
+ switch (event.type) {
1090
+ case "llm:thinking:delta":
1091
+ return this.onDelta(state, "thinking", "", String(payload.content ?? ""));
1092
+ case "llm:content:delta":
1093
+ return this.onDelta(state, "text", "", String(payload.content ?? ""));
1094
+ case "llm:tool_call:created":
1095
+ return this.onToolCallCreated(state, payload);
1096
+ case "llm:response:done":
1097
+ return this.onResponseDone(state, loopId, payload);
1098
+ case "tool:result:delta":
1099
+ return this.onToolResultDelta(state, payload);
1100
+ case "tool:result:done":
1101
+ return this.onToolResultDone(state, loopId, payload);
1102
+ case "loop:tool_ui":
1103
+ return this.onToolUi(state, payload);
1104
+ case "loop:tool_bridge":
1105
+ return this.onToolBridge(state, payload);
1106
+ case "tool:approval:required":
1107
+ return this.onToolApprovalRequired(state, payload);
1108
+ case "loop:child_pause":
1109
+ return this.onChildPause(state, loopId, payload);
1110
+ case "chat:end":
1111
+ return this.onChatEnd(state, loopId, payload);
1112
+ case "agent:end":
1113
+ return this.onAgentEnd(state, loopId, payload);
1114
+ default:
1115
+ return null;
1116
+ }
1117
+ }
1118
+ reset() {
1119
+ this.activeTurns.clear();
1120
+ this.lastTurnIds.clear();
1121
+ this.latestTurns.clear();
1122
+ this.loopDescriptions.clear();
1123
+ this.pendingChildPauses.clear();
1124
+ this.pendingMemoryRefs.clear();
1125
+ this.activeCompactions.clear();
1126
+ this.seq = 0;
1127
+ this.syntheticCounter = 0;
1128
+ }
1129
+ seedSequence(maxSeq) {
1130
+ if (maxSeq > this.seq) {
1131
+ this.seq = maxSeq;
1132
+ }
1133
+ }
1134
+ // --- Event handlers ---
1135
+ onMemoryInject(loopId, payload) {
1136
+ const refs = payload.memory_refs;
1137
+ const turnId = String(payload.turn_id ?? "");
1138
+ if (Array.isArray(refs) && refs.length > 0) {
1139
+ this.pendingMemoryRefs.set(loopId, {
1140
+ turnId,
1141
+ refs: refs.map((r) => ({
1142
+ id: Number(r.id),
1143
+ content_preview: String(r.content_preview ?? ""),
1144
+ skill_name: r.skill_name != null ? String(r.skill_name) : null
1145
+ }))
1146
+ });
1147
+ }
1148
+ return null;
1149
+ }
1150
+ onLoopTurn(loopId, payload) {
1151
+ let turnId = String(payload.turn_id ?? this.nextTurnId(`turn:${loopId}`));
1152
+ let memoryRefs = null;
1153
+ const pending = this.pendingMemoryRefs.get(loopId);
1154
+ if (pending) {
1155
+ this.pendingMemoryRefs.delete(loopId);
1156
+ if (pending.turnId) turnId = pending.turnId;
1157
+ memoryRefs = pending.refs;
1158
+ }
1159
+ const rawCw = payload.context_window;
1160
+ const contextWindow = typeof rawCw === "number" && rawCw > 0 ? Math.trunc(rawCw) : 0;
1161
+ const state = createTurnState(turnId, loopId, {
1162
+ model: optStr(payload.model),
1163
+ contextWindow,
1164
+ memoryRefs
1165
+ });
1166
+ this.activeTurns.set(loopId, state);
1167
+ this.lastTurnIds.set(loopId, turnId);
1168
+ const turn = snapshot(state, this.nextSeq(), "streaming");
1169
+ this.latestTurns.set(loopId, turn);
1170
+ return [{ kind: "upsert", turn }];
1171
+ }
1172
+ onModeChange(loopId, payload) {
1173
+ const content = {};
1174
+ if (payload.from != null && payload.from !== "") content.from = String(payload.from);
1175
+ if (payload.to != null && payload.to !== "") content.to = String(payload.to);
1176
+ const turn = buildMarkerTurn(
1177
+ this.nextSeq(),
1178
+ this.nextTurnId("mode_change"),
1179
+ loopId,
1180
+ "mode_change",
1181
+ content
1182
+ );
1183
+ return [{ kind: "upsert", turn }];
1184
+ }
1185
+ onPlanStatusUpdate(loopId, payload) {
1186
+ let statuses = payload.statuses;
1187
+ if (typeof statuses !== "object" || statuses === null) {
1188
+ statuses = payload._statuses ?? {};
1189
+ }
1190
+ const turn = buildMarkerTurn(
1191
+ this.nextSeq(),
1192
+ this.nextTurnId("plan_status"),
1193
+ loopId,
1194
+ "plan_status",
1195
+ { plan_yaml: payload.plan_yaml ?? "", statuses }
1196
+ );
1197
+ return [{ kind: "upsert", turn }];
1198
+ }
1199
+ onWorkspaceChanged(loopId, payload) {
1200
+ const updates = [
1201
+ {
1202
+ kind: "workspace_changed",
1203
+ loopId,
1204
+ toolCallId: optStr(payload.tool_call_id) ?? void 0,
1205
+ toolName: toolNameFromPayload(payload) ?? void 0
1206
+ }
1207
+ ];
1208
+ const state = this.activeTurns.get(loopId);
1209
+ if (state) {
1210
+ const turn = snapshot(state, this.nextSeq(), "streaming");
1211
+ this.latestTurns.set(loopId, turn);
1212
+ this.lastTurnIds.set(loopId, turn.turn_id);
1213
+ updates.push({ kind: "upsert", turn });
1214
+ }
1215
+ return updates;
1216
+ }
1217
+ onAgentStart(loopId, payload) {
1218
+ const description = optStr(payload.description);
1219
+ if (description) this.loopDescriptions.set(loopId, description);
1220
+ const turn = buildSystemNotificationTurn(
1221
+ this.nextSeq(),
1222
+ this.nextTurnId("agent:start"),
1223
+ loopId,
1224
+ "agent:start",
1225
+ "running",
1226
+ `Agent: ${payload.description ?? payload.skill_id ?? "agent"}`,
1227
+ optStr(payload.prompt),
1228
+ {
1229
+ skill_id: optStr(payload.skill_id),
1230
+ description: optStr(payload.description),
1231
+ parent_fork_tool_call_id: optStr(payload.parent_fork_tool_call_id)
1232
+ }
1233
+ );
1234
+ return [{ kind: "upsert", turn }];
1235
+ }
1236
+ onBgStarted(loopId, payload) {
1237
+ const taskId = optStr(payload.task_id) ?? "";
1238
+ const command = optStr(payload.command);
1239
+ const description = optStr(payload.description);
1240
+ const turn = buildSystemNotificationTurn(
1241
+ this.nextSeq(),
1242
+ this.nextTurnId("bg:started"),
1243
+ loopId,
1244
+ "bg:started",
1245
+ "running",
1246
+ description ?? `Background: ${taskId || "task"}`,
1247
+ command,
1248
+ { task_id: taskId, command, description }
1249
+ );
1250
+ return [{ kind: "upsert", turn }];
1251
+ }
1252
+ onBgTasksCompleted(loopId, payload) {
1253
+ const taskIds = Array.isArray(payload.task_ids) ? payload.task_ids : [];
1254
+ const count = typeof payload.count === "number" ? payload.count : taskIds.length;
1255
+ const detail = taskIds.map(String).join(", ");
1256
+ const turn = buildSystemNotificationTurn(
1257
+ this.nextSeq(),
1258
+ this.nextTurnId("bg:tasks_completed"),
1259
+ loopId,
1260
+ "bg:tasks_completed",
1261
+ "done",
1262
+ `Background tasks completed (${count})`,
1263
+ detail || null,
1264
+ { task_ids: taskIds, count }
1265
+ );
1266
+ return [{ kind: "upsert", turn }];
1267
+ }
1268
+ onAskUserAnswer(loopId, payload) {
1269
+ const toolCallId = String(payload.tool_call_id ?? "");
1270
+ const pending = this.pendingChildPauses.get(toolCallId);
1271
+ const parentLoopId = pending?.parentLoopName;
1272
+ if (pending) {
1273
+ this.pendingChildPauses.delete(toolCallId);
1274
+ const childTurn = this.activeTurns.get(pending.childLoopName) ?? this.latestTurns.get(pending.childLoopName);
1275
+ setToolCallStatus(childTurn, pending.childToolCallId, "done", null, null);
1276
+ const parentTurn = this.activeTurns.get(pending.parentLoopName) ?? this.latestTurns.get(pending.parentLoopName);
1277
+ setToolCallStatus(parentTurn, pending.parentToolCallId, "done", null, null);
1278
+ }
1279
+ const directTurn = this.activeTurns.get(loopId) ?? this.latestTurns.get(loopId);
1280
+ setToolCallStatus(directTurn, toolCallId, "done", null, null);
1281
+ return this.collectLoopUpdates(loopId, parentLoopId);
1282
+ }
1283
+ onUserMessage(_loopId, payload) {
1284
+ const entryId = String(payload.entry_id ?? this.nextTurnId("user"));
1285
+ const displayContent = payload.display_content ?? payload.content ?? "";
1286
+ const turn = {
1287
+ id: entryId,
1288
+ sequence: this.nextSeq(),
1289
+ turn_id: entryId,
1290
+ loop_id: "root",
1291
+ kind: "message",
1292
+ role: "user",
1293
+ status: "completed",
1294
+ blocks: [{ type: "text", content: displayContent }],
1295
+ tool_calls: [],
1296
+ model: null,
1297
+ usage: null,
1298
+ duration_ms: 0
1299
+ };
1300
+ return [{ kind: "upsert", turn }];
1301
+ }
1302
+ // --- Delta / streaming events ---
1303
+ onDelta(state, blockType, _toolCallId, content) {
1304
+ if (!content) return null;
1305
+ appendTextBlock(state, blockType, content);
1306
+ return this.syncPatch(state);
1307
+ }
1308
+ onToolCallCreated(state, payload) {
1309
+ if ("arguments_delta" in payload) {
1310
+ const delta = String(payload.arguments_delta ?? "");
1311
+ const toolCallId2 = String(payload.id ?? "");
1312
+ if (delta && toolCallId2) {
1313
+ appendToolCallArguments(state, toolCallId2, delta);
1314
+ return this.syncPatch(state);
1315
+ }
1316
+ return null;
1317
+ }
1318
+ const toolCallId = String(payload.id ?? "");
1319
+ const toolName = toolNameFromPayload(payload);
1320
+ const displayName = String(payload.display_name ?? "") || this.displayNameResolver(toolName);
1321
+ const args = toolArgsFromPayload(payload);
1322
+ upsertToolCall(state, toolCallId, toolName, displayName, args);
1323
+ return this.syncPatch(state);
1324
+ }
1325
+ onResponseDone(state, loopId, payload) {
1326
+ const model = optStr(payload.model);
1327
+ if (model) state.model = model;
1328
+ if (typeof payload.usage === "object" && payload.usage !== null) {
1329
+ state.usage = { ...payload.usage };
1330
+ }
1331
+ const toolCalls = payload.tool_calls;
1332
+ if (Array.isArray(toolCalls)) {
1333
+ for (const raw of toolCalls) {
1334
+ if (typeof raw !== "object" || raw === null) continue;
1335
+ const tc = raw;
1336
+ const fn = tc.function ?? {};
1337
+ const toolName = String(fn.name ?? "");
1338
+ const displayName = String(tc.display_name ?? "") || this.displayNameResolver(toolName);
1339
+ upsertToolCall(
1340
+ state,
1341
+ String(tc.id ?? ""),
1342
+ toolName,
1343
+ displayName,
1344
+ String(fn.arguments ?? "")
1345
+ );
1346
+ }
1347
+ }
1348
+ if (state.toolCalls.length === 0) {
1349
+ return this.finalize(loopId, "completed");
1350
+ }
1351
+ return this.syncPatch(state);
1352
+ }
1353
+ onToolResultDone(state, loopId, payload) {
1354
+ const toolCallId = String(payload.tool_call_id ?? "");
1355
+ const content = payload.content ?? "";
1356
+ const status = toolStatusFromResult(content);
1357
+ const rawDuration = payload.duration_ms;
1358
+ const durationMs = typeof rawDuration === "number" && rawDuration >= 0 ? Math.round(rawDuration) : null;
1359
+ const sl = sourceLoopFor(state.loopId, this.loopDescriptions);
1360
+ applyToolResult(state, toolCallId, content, status, durationMs, sl);
1361
+ if (this.shouldFinalizeAfterToolResults(state)) {
1362
+ return this.finalize(loopId, "completed");
1363
+ }
1364
+ return this.syncPatch(state);
1365
+ }
1366
+ onToolResultDelta(state, payload) {
1367
+ appendToolResultDelta(
1368
+ state,
1369
+ String(payload.tool_call_id ?? ""),
1370
+ String(payload.content ?? "")
1371
+ );
1372
+ return this.syncPatch(state);
1373
+ }
1374
+ onToolUi(state, payload) {
1375
+ const toolCallId = String(payload.tool_call_id ?? "");
1376
+ const ui = payload.ui;
1377
+ if (toolCallId && typeof ui === "object" && ui !== null) {
1378
+ state.blocks.push({
1379
+ type: "tool_ui",
1380
+ content: ui,
1381
+ tool_call_id: toolCallId
1382
+ });
1383
+ }
1384
+ return this.syncPatch(state);
1385
+ }
1386
+ onToolBridge(state, payload) {
1387
+ const bridge = payload.bridge;
1388
+ if (typeof bridge !== "object" || bridge === null) return null;
1389
+ state.blocks.push({
1390
+ type: "tool_bridge",
1391
+ content: bridge,
1392
+ tool_call_id: String(payload.tool_call_id ?? "") || null
1393
+ });
1394
+ return this.syncPatch(state);
1395
+ }
1396
+ onToolApprovalRequired(state, payload) {
1397
+ const toolCallId = String(payload.tool_call_id ?? "");
1398
+ const toolName = String(payload.tool_name ?? "");
1399
+ const displayName = this.displayNameResolver(toolName);
1400
+ upsertToolCall(state, toolCallId, toolName, displayName, "");
1401
+ return this.syncPatch(state);
1402
+ }
1403
+ onChildPause(state, loopId, payload) {
1404
+ const pauseToolData = payload.pause_tool_data;
1405
+ if (typeof pauseToolData !== "object" || pauseToolData === null)
1406
+ return this.syncPatch(state);
1407
+ const ptd = pauseToolData;
1408
+ const sourceLoop = ptd.source_loop;
1409
+ if (typeof sourceLoop === "object" && sourceLoop) {
1410
+ const slName = String(sourceLoop.name ?? "");
1411
+ const slDesc = optStr(sourceLoop.description);
1412
+ if (slName && slDesc) this.loopDescriptions.set(slName, slDesc);
1413
+ }
1414
+ const { childLoopName, childToolCallId, description } = normalizeChildPause(payload);
1415
+ if (!childToolCallId) return this.syncPatch(state);
1416
+ const existing = this.pendingChildPauses.get(childToolCallId);
1417
+ const parentLoopName = String(
1418
+ payload.parent_loop_name ?? existing?.parentLoopName ?? "root"
1419
+ );
1420
+ const parentToolCallId = String(
1421
+ payload.parent_fork_tool_call_id ?? existing?.parentToolCallId ?? ""
1422
+ );
1423
+ const resolvedChildLoopName = String(payload.child_loop_name ?? "") || existing?.childLoopName || childLoopName || loopId;
1424
+ this.pendingChildPauses.set(childToolCallId, {
1425
+ parentLoopName,
1426
+ parentToolCallId,
1427
+ childLoopName: resolvedChildLoopName,
1428
+ childToolCallId,
1429
+ description: description || existing?.description || ""
1430
+ });
1431
+ applyAskUserPauseToTurn(
1432
+ state,
1433
+ ptd,
1434
+ childToolCallId,
1435
+ resolvedChildLoopName,
1436
+ this.pendingChildPauses.get(childToolCallId).description,
1437
+ this.displayNameResolver
1438
+ );
1439
+ const parentTurn = this.activeTurns.get(parentLoopName) ?? this.latestTurns.get(parentLoopName);
1440
+ if (parentTurn) {
1441
+ applyChildPauseToParent(
1442
+ parentTurn,
1443
+ parentToolCallId,
1444
+ resolvedChildLoopName,
1445
+ childToolCallId,
1446
+ this.pendingChildPauses.get(childToolCallId).description,
1447
+ this.displayNameResolver
1448
+ );
1449
+ }
1450
+ return this.collectLoopUpdates(loopId, parentLoopName);
1451
+ }
1452
+ onChatEnd(state, loopId, payload) {
1453
+ const status = String(payload.status ?? "completed");
1454
+ const pauseToolData = payload.pause_tool_data;
1455
+ if (typeof pauseToolData === "object" && pauseToolData !== null) {
1456
+ const ptd = pauseToolData;
1457
+ const pauseToolName = String(ptd.name ?? "");
1458
+ const normalized = pauseToolName.includes(":") ? pauseToolName.split(":").pop() : pauseToolName;
1459
+ const sourceLoop = ptd.source_loop;
1460
+ if (typeof sourceLoop === "object" && sourceLoop) {
1461
+ const slName = String(sourceLoop.name ?? "");
1462
+ const slDesc = optStr(sourceLoop.description);
1463
+ if (slName && slDesc) this.loopDescriptions.set(slName, slDesc);
1464
+ if (status === "paused" && slName) {
1465
+ applyChildPauseToParent(
1466
+ state,
1467
+ String(ptd.parent_fork_tool_call_id ?? ""),
1468
+ slName,
1469
+ String(ptd.tool_call_id ?? ""),
1470
+ slDesc ?? "",
1471
+ this.displayNameResolver
1472
+ );
1473
+ const childTurn = this.activeTurns.get(slName);
1474
+ if (childTurn) {
1475
+ applyAskUserPauseToTurn(
1476
+ childTurn,
1477
+ ptd,
1478
+ String(ptd.tool_call_id ?? ""),
1479
+ slName,
1480
+ slDesc ?? "",
1481
+ this.displayNameResolver
1482
+ );
1483
+ }
1484
+ }
1485
+ } else if (status === "paused" && normalized === "AskUserQuestion") {
1486
+ applyAskUserPauseToTurn(
1487
+ state,
1488
+ ptd,
1489
+ String(ptd.tool_call_id ?? ""),
1490
+ "",
1491
+ "",
1492
+ this.displayNameResolver
1493
+ );
1494
+ }
1495
+ }
1496
+ const finalStatus = { completed: "completed", paused: "paused", failed: "failed", interrupted: "interrupted" }[status];
1497
+ if (!finalStatus) return null;
1498
+ if (!this.activeTurns.has(loopId)) {
1499
+ this.pendingMemoryRefs.delete(loopId);
1500
+ }
1501
+ return this.finalize(loopId, finalStatus);
1502
+ }
1503
+ onAgentEnd(state, loopId, payload) {
1504
+ const ok = payload.ok !== false;
1505
+ const status = ok ? "done" : "error";
1506
+ const title = `Agent: ${payload.description ?? payload.skill_id ?? "agent"}`;
1507
+ const detail = optStr(payload.error);
1508
+ const metadata = {
1509
+ skill_id: optStr(payload.skill_id),
1510
+ description: optStr(payload.description),
1511
+ parent_fork_tool_call_id: optStr(payload.parent_fork_tool_call_id),
1512
+ ok
1513
+ };
1514
+ if (state) {
1515
+ state.blocks.push(buildSystemNotificationBlock("agent:end", status, title, detail, metadata));
1516
+ return this.finalize(loopId, ok ? "completed" : "failed");
1517
+ }
1518
+ const turn = buildSystemNotificationTurn(
1519
+ this.nextSeq(),
1520
+ this.nextTurnId("agent:end"),
1521
+ loopId,
1522
+ "agent:end",
1523
+ status,
1524
+ title,
1525
+ detail,
1526
+ metadata
1527
+ );
1528
+ return [{ kind: "upsert", turn }];
1529
+ }
1530
+ onCompaction(eventType, loopId, payload) {
1531
+ const compactionId = String(payload.compaction_id ?? "");
1532
+ if (!compactionId) return null;
1533
+ const current = {
1534
+ ...this.activeCompactions.get(compactionId) ?? {},
1535
+ ...payload,
1536
+ loop_id: loopId
1537
+ };
1538
+ let status;
1539
+ switch (eventType) {
1540
+ case "compaction:start":
1541
+ status = "streaming";
1542
+ this.activeCompactions.set(compactionId, current);
1543
+ break;
1544
+ case "compaction:end":
1545
+ status = "completed";
1546
+ this.activeCompactions.delete(compactionId);
1547
+ break;
1548
+ case "compaction:abort":
1549
+ status = "interrupted";
1550
+ this.activeCompactions.delete(compactionId);
1551
+ break;
1552
+ case "compaction:error":
1553
+ status = "failed";
1554
+ this.activeCompactions.delete(compactionId);
1555
+ break;
1556
+ default:
1557
+ status = "streaming";
1558
+ this.activeCompactions.set(compactionId, current);
1559
+ }
1560
+ const turn = buildCompactionTurn(this.nextSeq(), compactionId, loopId, status, current);
1561
+ return [{ kind: "upsert", turn }];
1562
+ }
1563
+ // --- Internal helpers ---
1564
+ syncPatch(state) {
1565
+ const turn = snapshot(state, this.nextSeq(), "streaming");
1566
+ this.latestTurns.set(state.loopId, turn);
1567
+ this.lastTurnIds.set(state.loopId, turn.turn_id);
1568
+ return [{ kind: "upsert", turn }];
1569
+ }
1570
+ finalize(loopId, status) {
1571
+ const state = this.activeTurns.get(loopId);
1572
+ if (!state) return null;
1573
+ this.activeTurns.delete(loopId);
1574
+ const turn = snapshot(state, this.nextSeq(), status);
1575
+ this.lastTurnIds.set(loopId, turn.turn_id);
1576
+ this.latestTurns.set(loopId, turn);
1577
+ return [{ kind: "upsert", turn }];
1578
+ }
1579
+ shouldFinalizeAfterToolResults(state) {
1580
+ if (state.toolCalls.length === 0) return true;
1581
+ if (state.toolCalls.some((tc) => tc.status === "pending")) return false;
1582
+ return !state.toolCalls.some((tc) => {
1583
+ const normalized = tc.tool_name.includes(":") ? tc.tool_name.split(":").pop() : tc.tool_name;
1584
+ return PAUSE_TOOL_NAMES.has(normalized);
1585
+ });
1586
+ }
1587
+ collectLoopUpdates(...loopIds) {
1588
+ const updates = [];
1589
+ for (const loopId of loopIds) {
1590
+ if (!loopId) continue;
1591
+ const state = this.activeTurns.get(loopId);
1592
+ if (state) {
1593
+ updates.push(...this.syncPatch(state));
1594
+ continue;
1595
+ }
1596
+ const proj = this.latestTurns.get(loopId);
1597
+ if (proj) {
1598
+ const updated = { ...proj, sequence: this.nextSeq() };
1599
+ this.latestTurns.set(loopId, updated);
1600
+ updates.push({ kind: "upsert", turn: updated });
1601
+ }
1602
+ }
1603
+ return updates;
1604
+ }
1605
+ nextSeq() {
1606
+ return ++this.seq;
1607
+ }
1608
+ nextTurnId(prefix) {
1609
+ this.syntheticCounter++;
1610
+ const hex = Math.random().toString(16).slice(2, 10);
1611
+ return `${prefix}:${this.syntheticCounter}:${hex}`;
1612
+ }
1613
+ };
1614
+ function optStr(value) {
1615
+ if (value == null || value === "") return null;
1616
+ return String(value);
1617
+ }
1618
+ function toolNameFromPayload(payload) {
1619
+ const fn = payload.function;
1620
+ if (typeof fn === "object" && fn !== null) {
1621
+ return String(fn.name ?? "");
1622
+ }
1623
+ return String(payload.tool_name ?? "");
1624
+ }
1625
+ function toolArgsFromPayload(payload) {
1626
+ const fn = payload.function;
1627
+ if (typeof fn === "object" && fn !== null) {
1628
+ return String(fn.arguments ?? "");
1629
+ }
1630
+ return "";
1631
+ }
1632
+
1633
+ // src/client/shared/projection/history.ts
1634
+ function projectHistory(entries) {
1635
+ const turns = [];
1636
+ const toolOwners = /* @__PURE__ */ new Map();
1637
+ const latestAssistantByLoop = /* @__PURE__ */ new Map();
1638
+ const pendingChildPauses = /* @__PURE__ */ new Map();
1639
+ let sequence = 0;
1640
+ for (const entry of entries) {
1641
+ const kind = String(entry.kind ?? "");
1642
+ const loopId = String(entry.loop_name ?? "root");
1643
+ const id = String(entry.id ?? `history-${sequence + 1}`);
1644
+ if (kind === "message" && isRecord2(entry.message)) {
1645
+ const message = entry.message;
1646
+ const role = String(message.role ?? "");
1647
+ if (role === "tool") {
1648
+ const toolCallId = String(message.tool_call_id ?? "");
1649
+ const owner = toolOwners.get(toolCallId);
1650
+ const toolCall = owner?.tool_calls.find((item) => item.id === toolCallId);
1651
+ if (owner && toolCall) {
1652
+ toolCall.status = message._error ? "error" : inferToolStatus(String(message.content ?? ""));
1653
+ toolCall.result = message.content ?? "";
1654
+ owner.blocks.push({
1655
+ type: "tool_result",
1656
+ content: message.content ?? "",
1657
+ tool_call_id: toolCallId
1658
+ });
1659
+ }
1660
+ continue;
1661
+ }
1662
+ if (role !== "user" && role !== "assistant" && role !== "system") continue;
1663
+ const toolCalls = role === "assistant" ? buildToolCalls(message.tool_calls) : [];
1664
+ const blocks = buildBlocks(message, toolCalls);
1665
+ const turn = {
1666
+ id,
1667
+ sequence: ++sequence,
1668
+ turn_id: id,
1669
+ loop_id: loopId,
1670
+ kind: "message",
1671
+ role,
1672
+ status: message._error ? "failed" : "completed",
1673
+ blocks,
1674
+ tool_calls: toolCalls,
1675
+ model: stringOrNull(message.model),
1676
+ usage: isRecord2(message._usage) ? { ...message._usage } : null,
1677
+ duration_ms: numberOrZero(message._duration_ms),
1678
+ started_at: typeof entry.timestamp === "string" ? entry.timestamp : void 0
1679
+ };
1680
+ turns.push(turn);
1681
+ if (role === "assistant") latestAssistantByLoop.set(loopId, turn);
1682
+ for (const toolCall of toolCalls) toolOwners.set(toolCall.id, turn);
1683
+ continue;
1684
+ }
1685
+ if (kind === "mode_change") {
1686
+ turns.push(markerTurn(id, ++sequence, loopId, "mode_change", entry.data ?? {}));
1687
+ } else if (kind === "plan_status") {
1688
+ const data = entry.data ?? {};
1689
+ turns.push(
1690
+ markerTurn(id, ++sequence, loopId, "plan_status", {
1691
+ plan_yaml: data.plan_yaml ?? "",
1692
+ statuses: data.statuses ?? data._statuses ?? {}
1693
+ })
1694
+ );
1695
+ } else if (kind === "tool_ui" || kind === "tool_bridge") {
1696
+ const data = entry.data ?? {};
1697
+ const toolCallId = String(data.tool_call_id ?? "");
1698
+ const owner = toolOwners.get(toolCallId) ?? findLatestAssistant(turns, loopId);
1699
+ const content = kind === "tool_ui" ? data.ui : data.bridge;
1700
+ if (owner && content !== void 0) {
1701
+ owner.blocks.push({
1702
+ type: kind,
1703
+ content,
1704
+ tool_call_id: toolCallId || null
1705
+ });
1706
+ }
1707
+ } else if (kind === "compaction" || kind === "tool_result_archive") {
1708
+ const data = entry.data ?? {};
1709
+ const compactionId = String(data.compaction_id ?? entry.id ?? `history-${sequence + 1}`);
1710
+ let content = isRecord2(entry.message) ? entry.message.content : void 0;
1711
+ if (kind === "tool_result_archive") {
1712
+ const archivedCount = Array.isArray(data.archived_files) ? data.archived_files.length : 0;
1713
+ content = `<compaction-summary>
1714
+ \u5DF2\u5F52\u6863 ${archivedCount} \u4E2A\u5927\u578B\u5DE5\u5177\u7ED3\u679C\u3002
1715
+ </compaction-summary>`;
1716
+ }
1717
+ turns.push(
1718
+ buildCompactionTurn(++sequence, compactionId, loopId, "completed", {
1719
+ ...data,
1720
+ content
1721
+ })
1722
+ );
1723
+ } else if (kind === "child_pause") {
1724
+ const data = entry.data ?? {};
1725
+ const sourceLoop = isRecord2(data.source_loop) ? data.source_loop : {};
1726
+ const childLoopId = String(data.child_loop_name ?? sourceLoop.name ?? "");
1727
+ const childToolCallId = String(data.child_pause_tool_call_id ?? "");
1728
+ const parentToolCallId = String(data.parent_fork_tool_call_id ?? "");
1729
+ const pauseToolData = isRecord2(data.pause_tool_data) ? data.pause_tool_data : {};
1730
+ const description = String(sourceLoop.description ?? "");
1731
+ applyAskUserPauseToTurn(
1732
+ latestAssistantByLoop.get(childLoopId),
1733
+ pauseToolData,
1734
+ childToolCallId,
1735
+ childLoopId,
1736
+ description,
1737
+ (name) => name
1738
+ );
1739
+ applyChildPauseToParent(
1740
+ latestAssistantByLoop.get(loopId),
1741
+ parentToolCallId,
1742
+ childLoopId,
1743
+ childToolCallId,
1744
+ description,
1745
+ (name) => name
1746
+ );
1747
+ if (childToolCallId) {
1748
+ pendingChildPauses.set(childToolCallId, {
1749
+ childLoopId,
1750
+ parentLoopId: loopId,
1751
+ parentToolCallId
1752
+ });
1753
+ }
1754
+ } else if (kind === "ask_user_answer") {
1755
+ const data = entry.data ?? {};
1756
+ const toolCallId = String(data.tool_call_id ?? "");
1757
+ const pending = pendingChildPauses.get(toolCallId);
1758
+ if (pending) {
1759
+ setToolCallStatus(latestAssistantByLoop.get(pending.childLoopId), toolCallId, "done", null, null);
1760
+ setToolCallStatus(
1761
+ latestAssistantByLoop.get(pending.parentLoopId),
1762
+ pending.parentToolCallId,
1763
+ "done",
1764
+ null,
1765
+ null
1766
+ );
1767
+ pendingChildPauses.delete(toolCallId);
1768
+ } else {
1769
+ setToolCallStatus(latestAssistantByLoop.get(loopId), toolCallId, "done", null, null);
1770
+ }
1771
+ turns.push(
1772
+ markerTurn(
1773
+ id,
1774
+ ++sequence,
1775
+ loopId,
1776
+ "ask_user_answer",
1777
+ data,
1778
+ toolCallId || null
1779
+ )
1780
+ );
1781
+ }
1782
+ }
1783
+ return turns;
1784
+ }
1785
+ function buildToolCalls(value) {
1786
+ if (!Array.isArray(value)) return [];
1787
+ return value.filter(isRecord2).map((raw) => {
1788
+ const fn = isRecord2(raw.function) ? raw.function : {};
1789
+ const name = String(fn.name ?? "");
1790
+ return {
1791
+ id: String(raw.id ?? ""),
1792
+ tool_name: name,
1793
+ display_name: String(raw.display_name ?? name),
1794
+ arguments: typeof fn.arguments === "string" ? fn.arguments : JSON.stringify(fn.arguments ?? {}),
1795
+ status: "running",
1796
+ result: null
1797
+ };
1798
+ });
1799
+ }
1800
+ function buildBlocks(message, toolCalls) {
1801
+ const stored = message._blocks;
1802
+ const blocks = [];
1803
+ if (Array.isArray(stored)) {
1804
+ for (const raw of stored) {
1805
+ if (!isRecord2(raw)) continue;
1806
+ const type3 = String(raw.type ?? "");
1807
+ if (type3 === "thinking") blocks.push({ type: type3, content: raw.thinking ?? raw.content ?? "" });
1808
+ if (type3 === "text") blocks.push({ type: type3, content: raw.text ?? raw.content ?? "" });
1809
+ }
1810
+ } else if (message.content !== void 0 && message.content !== "") {
1811
+ blocks.push({ type: "text", content: message.content });
1812
+ }
1813
+ for (const toolCall of toolCalls) {
1814
+ blocks.push({
1815
+ type: "tool_use",
1816
+ content: { name: toolCall.tool_name, arguments: toolCall.arguments },
1817
+ tool_call_id: toolCall.id
1818
+ });
1819
+ }
1820
+ return blocks;
1821
+ }
1822
+ function markerTurn(id, sequence, loopId, type3, content, toolCallId = null) {
1823
+ return {
1824
+ id,
1825
+ sequence,
1826
+ turn_id: id,
1827
+ loop_id: loopId,
1828
+ kind: type3,
1829
+ role: "system",
1830
+ status: "completed",
1831
+ blocks: [{ type: type3, content, tool_call_id: toolCallId }],
1832
+ tool_calls: [],
1833
+ model: null,
1834
+ usage: null,
1835
+ duration_ms: 0
1836
+ };
1837
+ }
1838
+ function isRecord2(value) {
1839
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1840
+ }
1841
+ function stringOrNull(value) {
1842
+ return typeof value === "string" ? value : null;
1843
+ }
1844
+ function numberOrZero(value) {
1845
+ return typeof value === "number" ? value : 0;
1846
+ }
1847
+ function findLatestAssistant(turns, loopId) {
1848
+ for (let index = turns.length - 1; index >= 0; index -= 1) {
1849
+ const turn = turns[index];
1850
+ if (turn?.role === "assistant" && turn.loop_id === loopId) return turn;
1851
+ }
1852
+ return void 0;
1853
+ }
1854
+
509
1855
  // src/client/resources/runs.ts
510
1856
  var SYSTEM_ERROR_CHAT_END_GRACE_MS2 = 1e3;
511
1857
  var RunsResource = class {
@@ -524,6 +1870,7 @@ var RunsResource = class {
524
1870
  let started = false;
525
1871
  let chatRunId;
526
1872
  let systemErrorTimeout = null;
1873
+ const projectionBuilder = new ClientProjectionBuilder();
527
1874
  const timeout = setTimeout(() => {
528
1875
  fail(new Error(`run timed out after ${timeoutMs}ms`));
529
1876
  }, timeoutMs);
@@ -534,9 +1881,7 @@ var RunsResource = class {
534
1881
  systemErrorTimeout = null;
535
1882
  }
536
1883
  socket.off("chat:start", onChatStart);
537
- socket.off("turn:start", onTurnStart);
538
- socket.off("turn:patch", onTurnPatch);
539
- socket.off("turn:end", onTurnEnd);
1884
+ socket.off("turn:events", onTurnEvents);
540
1885
  socket.off("chat:end", onChatEnd);
541
1886
  socket.off("system:error", onSystemError);
542
1887
  if (sendStop && !stopSent) {
@@ -574,17 +1919,13 @@ var RunsResource = class {
574
1919
  started = true;
575
1920
  events.push({ type: "chat:start", payload });
576
1921
  }
577
- function onTurnStart(payload) {
578
- if (!isSessionEvent(payload, sessionId)) return;
579
- events.push({ type: "turn:start", payload });
580
- }
581
- function onTurnPatch(payload) {
582
- if (!isSessionEvent(payload, sessionId)) return;
583
- events.push({ type: "turn:patch", payload });
584
- }
585
- function onTurnEnd(payload) {
586
- if (!isSessionEvent(payload, sessionId)) return;
587
- events.push({ type: "turn:end", payload });
1922
+ function onTurnEvents(payload) {
1923
+ if (!isSessionEvent(payload, sessionId) || !payload.events?.length) return;
1924
+ for (const update of projectionBuilder.processBatch(payload.events)) {
1925
+ if (update.kind === "upsert") {
1926
+ events.push({ type: "turn:end", payload: { ...update.turn, session_id: sessionId } });
1927
+ }
1928
+ }
588
1929
  }
589
1930
  function onSystemError(payload) {
590
1931
  if (!isSessionEvent(payload, sessionId)) return;
@@ -613,12 +1954,10 @@ var RunsResource = class {
613
1954
  finish(payload);
614
1955
  }
615
1956
  socket.on("chat:start", onChatStart);
616
- socket.on("turn:start", onTurnStart);
617
- socket.on("turn:patch", onTurnPatch);
618
- socket.on("turn:end", onTurnEnd);
1957
+ socket.on("turn:events", onTurnEvents);
619
1958
  socket.on("chat:end", onChatEnd);
620
1959
  socket.on("system:error", onSystemError);
621
- socket.emit("session:subscribe", { session_id: sessionId });
1960
+ socket.emit("session:subscribe", { session_id: sessionId, event_format: "raw" });
622
1961
  socket.emit("chat:send", buildChatSendPayload(sessionId, message, options));
623
1962
  });
624
1963
  }
@@ -645,16 +1984,16 @@ function buildChatSendPayload(sessionId, message, options) {
645
1984
  }
646
1985
  function collectConfigSnapshot(events) {
647
1986
  const chatStart = events.find((event) => {
648
- if (!isRecord2(event) || event.type !== "chat:start") return false;
649
- return isRecord2(event.payload);
1987
+ if (!isRecord3(event) || event.type !== "chat:start") return false;
1988
+ return isRecord3(event.payload);
650
1989
  });
651
- if (!isRecord2(chatStart) || !isRecord2(chatStart.payload)) {
1990
+ if (!isRecord3(chatStart) || !isRecord3(chatStart.payload)) {
652
1991
  return {};
653
1992
  }
654
1993
  return chatStart.payload;
655
1994
  }
656
1995
  function errorMessageFromResult2(result) {
657
- if (isRecord2(result) && typeof result.err_msg === "string" && result.err_msg) {
1996
+ if (isRecord3(result) && typeof result.err_msg === "string" && result.err_msg) {
658
1997
  return result.err_msg;
659
1998
  }
660
1999
  return null;
@@ -662,7 +2001,7 @@ function errorMessageFromResult2(result) {
662
2001
  function isSessionEvent(payload, sessionId) {
663
2002
  return !payload.session_id || payload.session_id === sessionId;
664
2003
  }
665
- function isRecord2(value) {
2004
+ function isRecord3(value) {
666
2005
  return typeof value === "object" && value !== null && !Array.isArray(value);
667
2006
  }
668
2007
  function ensureSocketConnected2(socket, timeoutMs, detail) {
@@ -834,17 +2173,22 @@ var SessionsResource = class {
834
2173
  revokeShare(sessionId, token) {
835
2174
  return this.client.json("DELETE", `/api/sessions/${sessionId}/share/${encodeURIComponent(token)}`);
836
2175
  }
837
- getSharedSession(token) {
838
- return this.client.jsonFromInit(`/api/share/${encodeURIComponent(token)}`, {
2176
+ async getSharedSession(token) {
2177
+ const entries = await this.client.jsonFromInit(`/api/share/${encodeURIComponent(token)}`, {
839
2178
  credentials: "omit",
840
2179
  headers: { Accept: "application/json" }
841
2180
  });
2181
+ return projectHistory(entries);
842
2182
  }
843
2183
  getSessionTasks(sessionId) {
844
2184
  return this.client.json("GET", `/api/sessions/${sessionId}/tasks`);
845
2185
  }
846
- getSessionTurns(sessionId) {
847
- return this.client.json("GET", `/api/sessions/${sessionId}/messages`);
2186
+ async getSessionTurns(sessionId) {
2187
+ const entries = await this.client.json(
2188
+ "GET",
2189
+ `/api/sessions/${sessionId}/messages`
2190
+ );
2191
+ return projectHistory(entries);
848
2192
  }
849
2193
  getSessionContextStats(sessionId, init) {
850
2194
  return this.client.jsonFromInit(`/api/sessions/${sessionId}/context-stats`, init);
@@ -1113,7 +2457,7 @@ var SolutionsResource = class {
1113
2457
  }
1114
2458
  };
1115
2459
  function toPreparedSolution(payload) {
1116
- const data = isRecord3(payload) ? payload : {};
2460
+ const data = isRecord4(payload) ? payload : {};
1117
2461
  const roles = Array.isArray(data.roles) ? data.roles.filter((role) => typeof role === "string") : [];
1118
2462
  return {
1119
2463
  kind: "prepared",
@@ -1127,7 +2471,7 @@ function stringField(data, key) {
1127
2471
  const value = data[key];
1128
2472
  return typeof value === "string" ? value : null;
1129
2473
  }
1130
- function isRecord3(value) {
2474
+ function isRecord4(value) {
1131
2475
  return typeof value === "object" && value !== null && !Array.isArray(value);
1132
2476
  }
1133
2477
  function parseContentDispositionFilename(header) {
@@ -1214,9 +2558,11 @@ function resolveAuthToken(options) {
1214
2558
  // src/client/socket.ts
1215
2559
  function createSocket(options) {
1216
2560
  const auth = buildSocketAuth(options);
2561
+ const token = resolveAuthToken(options);
1217
2562
  return io(options.baseUrl, {
1218
2563
  path: options.path ?? "/socket.io",
1219
2564
  withCredentials: true,
2565
+ query: token ? { token } : void 0,
1220
2566
  auth: typeof options.token === "function" ? (cb) => cb(buildSocketAuth(options) ?? {}) : auth,
1221
2567
  autoConnect: false
1222
2568
  });
@@ -1231,6 +2577,7 @@ var BladeClient = class {
1231
2577
  storeSocketTokenResolver = null;
1232
2578
  options;
1233
2579
  apiKeys;
2580
+ appDevTemplates;
1234
2581
  auth;
1235
2582
  envBuckets;
1236
2583
  gis;
@@ -1251,6 +2598,7 @@ var BladeClient = class {
1251
2598
  baseUrl: normalizeBaseUrl(options.baseUrl)
1252
2599
  };
1253
2600
  this.apiKeys = new ApiKeysResource(this);
2601
+ this.appDevTemplates = new AppDevTemplatesResource(this);
1254
2602
  this.auth = new AuthResource(this);
1255
2603
  this.envBuckets = new EnvBucketsResource(this);
1256
2604
  this.gis = new GisResource(this);
@@ -1530,6 +2878,7 @@ function parseXhrHeaders(rawHeaders) {
1530
2878
  export {
1531
2879
  BladeApiError,
1532
2880
  ApiKeysResource,
2881
+ AppDevTemplatesResource,
1533
2882
  AuthResource,
1534
2883
  GisResource,
1535
2884
  HeadlessError,
@@ -1542,6 +2891,7 @@ export {
1542
2891
  REGISTRY_PREFIX,
1543
2892
  normalizeResource,
1544
2893
  RegistryResource,
2894
+ ClientProjectionBuilder,
1545
2895
  RunsResource,
1546
2896
  ScenariosResource,
1547
2897
  SessionsResource,
@@ -1551,4 +2901,4 @@ export {
1551
2901
  createSocket,
1552
2902
  BladeClient
1553
2903
  };
1554
- //# sourceMappingURL=chunk-M45K3554.js.map
2904
+ //# sourceMappingURL=chunk-YJ6BX3FU.js.map