@maudecode/talaria-web 1.14.0 → 1.16.1

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 (348) hide show
  1. package/_release.json +4 -4
  2. package/dist/api/automation-router.d.ts +123 -7
  3. package/dist/api/automation-router.js +5 -0
  4. package/dist/api/automation-router.js.map +1 -1
  5. package/dist/api/chat-router.d.ts +728 -55
  6. package/dist/api/chat-router.js +122 -126
  7. package/dist/api/chat-router.js.map +1 -1
  8. package/dist/api/git-router.js +44 -32
  9. package/dist/api/git-router.js.map +1 -1
  10. package/dist/api/raw-routes.js +5 -58
  11. package/dist/api/raw-routes.js.map +1 -1
  12. package/dist/api/router.d.ts +6 -3
  13. package/dist/api/router.js +10 -8
  14. package/dist/api/router.js.map +1 -1
  15. package/dist/api/sessions-router.d.ts +2583 -297
  16. package/dist/api/sessions-router.js +92 -47
  17. package/dist/api/sessions-router.js.map +1 -1
  18. package/dist/api/settings-router.d.ts +188 -17
  19. package/dist/api/settings-router.js +75 -26
  20. package/dist/api/settings-router.js.map +1 -1
  21. package/dist/api/sse-routes.js +1 -1
  22. package/dist/api/sse-routes.js.map +1 -1
  23. package/dist/api/tools-router.d.ts +13 -1
  24. package/dist/api/tools-router.js +10 -8
  25. package/dist/api/tools-router.js.map +1 -1
  26. package/dist/app.d.ts +3620 -343
  27. package/dist/auth/gate.js +8 -4
  28. package/dist/auth/gate.js.map +1 -1
  29. package/dist/auth/oidc.d.ts +6 -2
  30. package/dist/auth/oidc.js +16 -11
  31. package/dist/auth/oidc.js.map +1 -1
  32. package/dist/auth/store.d.ts +14 -2
  33. package/dist/auth/store.js +26 -1
  34. package/dist/auth/store.js.map +1 -1
  35. package/dist/cli/dotenv.d.ts +1 -1
  36. package/dist/cli/dotenv.js +36 -3
  37. package/dist/cli/dotenv.js.map +1 -1
  38. package/dist/config/agent-config.js +20 -15
  39. package/dist/config/agent-config.js.map +1 -1
  40. package/dist/http/addresses.d.ts +6 -0
  41. package/dist/http/addresses.js +26 -0
  42. package/dist/http/addresses.js.map +1 -1
  43. package/dist/http/context.d.ts +7 -5
  44. package/dist/http/context.js.map +1 -1
  45. package/dist/links.d.ts +26 -0
  46. package/dist/links.js +60 -0
  47. package/dist/links.js.map +1 -0
  48. package/dist/onboarding.d.ts +1 -1
  49. package/dist/onboarding.js +28 -8
  50. package/dist/onboarding.js.map +1 -1
  51. package/dist/profiles/profiles.js +1 -1
  52. package/dist/profiles/profiles.js.map +1 -1
  53. package/dist/providers/catalog.d.ts +85 -1
  54. package/dist/providers/catalog.js +280 -43
  55. package/dist/providers/catalog.js.map +1 -1
  56. package/dist/providers/tables.d.ts +3 -1
  57. package/dist/providers/tables.js +9 -4
  58. package/dist/providers/tables.js.map +1 -1
  59. package/dist/redact.js +493 -13
  60. package/dist/redact.js.map +1 -1
  61. package/dist/runtime.js +104 -42
  62. package/dist/runtime.js.map +1 -1
  63. package/dist/sessions/anchor.d.ts +22 -3
  64. package/dist/sessions/anchor.js +87 -42
  65. package/dist/sessions/anchor.js.map +1 -1
  66. package/dist/sessions/background-tasks.d.ts +140 -0
  67. package/dist/sessions/background-tasks.js +352 -0
  68. package/dist/sessions/background-tasks.js.map +1 -0
  69. package/dist/sessions/background-updates.d.ts +56 -0
  70. package/dist/sessions/background-updates.js +152 -0
  71. package/dist/sessions/background-updates.js.map +1 -0
  72. package/dist/sessions/cli-sessions.d.ts +6 -0
  73. package/dist/sessions/cli-sessions.js +20 -7
  74. package/dist/sessions/cli-sessions.js.map +1 -1
  75. package/dist/sessions/completions.d.ts +17 -1
  76. package/dist/sessions/completions.js +84 -13
  77. package/dist/sessions/completions.js.map +1 -1
  78. package/dist/sessions/compress.d.ts +33 -0
  79. package/dist/sessions/compress.js +66 -0
  80. package/dist/sessions/compress.js.map +1 -0
  81. package/dist/sessions/list.d.ts +22 -4
  82. package/dist/sessions/list.js +113 -33
  83. package/dist/sessions/list.js.map +1 -1
  84. package/dist/sessions/merge.d.ts +81 -7
  85. package/dist/sessions/merge.js +391 -26
  86. package/dist/sessions/merge.js.map +1 -1
  87. package/dist/sessions/pending.d.ts +5 -0
  88. package/dist/sessions/pending.js +30 -10
  89. package/dist/sessions/pending.js.map +1 -1
  90. package/dist/sessions/relay.d.ts +7 -1
  91. package/dist/sessions/relay.js +17 -4
  92. package/dist/sessions/relay.js.map +1 -1
  93. package/dist/sessions/service.d.ts +118 -6
  94. package/dist/sessions/service.js +564 -65
  95. package/dist/sessions/service.js.map +1 -1
  96. package/dist/sessions/session.d.ts +22 -1
  97. package/dist/sessions/session.js +29 -2
  98. package/dist/sessions/session.js.map +1 -1
  99. package/dist/sessions/shares.js +11 -2
  100. package/dist/sessions/shares.js.map +1 -1
  101. package/dist/sessions/source-kind.d.ts +22 -0
  102. package/dist/sessions/source-kind.js +54 -0
  103. package/dist/sessions/source-kind.js.map +1 -0
  104. package/dist/sessions/state-db.d.ts +10 -1
  105. package/dist/sessions/state-db.js +48 -17
  106. package/dist/sessions/state-db.js.map +1 -1
  107. package/dist/sessions/store.d.ts +2 -0
  108. package/dist/sessions/store.js +24 -5
  109. package/dist/sessions/store.js.map +1 -1
  110. package/dist/sessions/streams.d.ts +3 -0
  111. package/dist/sessions/streams.js +0 -5
  112. package/dist/sessions/streams.js.map +1 -1
  113. package/dist/sessions/titles.d.ts +4 -0
  114. package/dist/sessions/titles.js +16 -0
  115. package/dist/sessions/titles.js.map +1 -1
  116. package/dist/sessions/turn-context.d.ts +1 -0
  117. package/dist/sessions/turn-context.js +3 -0
  118. package/dist/sessions/turn-context.js.map +1 -1
  119. package/dist/sessions/turn.d.ts +85 -7
  120. package/dist/sessions/turn.js +518 -170
  121. package/dist/sessions/turn.js.map +1 -1
  122. package/dist/settings.d.ts +2 -0
  123. package/dist/settings.js +13 -0
  124. package/dist/settings.js.map +1 -1
  125. package/dist/sidecar/fake.js +2 -0
  126. package/dist/sidecar/fake.js.map +1 -1
  127. package/dist/tools/commands.d.ts +15 -0
  128. package/dist/tools/commands.js +52 -0
  129. package/dist/tools/commands.js.map +1 -0
  130. package/dist/tools/crons.d.ts +38 -4
  131. package/dist/tools/crons.js +323 -36
  132. package/dist/tools/crons.js.map +1 -1
  133. package/dist/tools/mcp.js +5 -1
  134. package/dist/tools/mcp.js.map +1 -1
  135. package/dist/tools/update-notifications.d.ts +1 -1
  136. package/dist/tools/update-notifications.js +1 -1
  137. package/dist/tools/update-notifications.js.map +1 -1
  138. package/dist/tools/updates.d.ts +8 -3
  139. package/dist/tools/updates.js +133 -34
  140. package/dist/tools/updates.js.map +1 -1
  141. package/dist/workspace/git.d.ts +57 -10
  142. package/dist/workspace/git.js +302 -195
  143. package/dist/workspace/git.js.map +1 -1
  144. package/dist/workspace/media-refs.d.ts +13 -0
  145. package/dist/workspace/media-refs.js +165 -0
  146. package/dist/workspace/media-refs.js.map +1 -0
  147. package/dist/workspace/media.d.ts +19 -0
  148. package/dist/workspace/media.js +61 -2
  149. package/dist/workspace/media.js.map +1 -1
  150. package/dist/workspace/workspaces.d.ts +7 -1
  151. package/dist/workspace/workspaces.js +30 -21
  152. package/dist/workspace/workspaces.js.map +1 -1
  153. package/dist/workspace/worktrees.d.ts +2 -4
  154. package/dist/workspace/worktrees.js +28 -33
  155. package/dist/workspace/worktrees.js.map +1 -1
  156. package/package.json +4 -2
  157. package/sidecar/scripts/replay_sidecar.py +3 -1
  158. package/sidecar/talaria_sidecar/__init__.py +1 -1
  159. package/sidecar/talaria_sidecar/home.py +59 -2
  160. package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
  161. package/sidecar/talaria_sidecar/methods/aux.py +19 -3
  162. package/sidecar/talaria_sidecar/methods/chat.py +360 -27
  163. package/sidecar/talaria_sidecar/methods/commands.py +46 -31
  164. package/sidecar/talaria_sidecar/methods/config.py +14 -10
  165. package/sidecar/talaria_sidecar/methods/cron.py +22 -14
  166. package/sidecar/talaria_sidecar/methods/oauth.py +439 -0
  167. package/sidecar/talaria_sidecar/methods/process.py +318 -0
  168. package/sidecar/talaria_sidecar/methods/profiles.py +5 -4
  169. package/sidecar/talaria_sidecar/methods/providers.py +161 -1
  170. package/sidecar/talaria_sidecar/methods/runtime.py +2 -0
  171. package/sidecar/talaria_sidecar/methods/text.py +1 -20
  172. package/sidecar/talaria_sidecar/methods/usage.py +7 -1
  173. package/static/dist/FILES.txt +124 -119
  174. package/static/dist/assets/AppShell-ef3bhu32.js +1 -0
  175. package/static/dist/assets/Button-nx37f4u1.js +1 -0
  176. package/static/dist/assets/ChatPage-cdcpykcg.js +25 -0
  177. package/static/dist/assets/Dialog-mec42hvb.js +1 -0
  178. package/static/dist/assets/HubRoute-ecb65zpr.js +2 -0
  179. package/static/dist/assets/{Markdown-emii55o0.js → Markdown-jqrx5es0.js} +125 -125
  180. package/static/dist/assets/RightPanel-d1lgvk4s.js +1 -0
  181. package/static/dist/assets/Select-h4ivl9qf.js +1 -0
  182. package/static/dist/assets/SessionListPanel-ewib046b.js +1 -0
  183. package/static/dist/assets/SettingsLayout-lx654cup.js +1 -0
  184. package/static/dist/assets/States-ehsb6lzo.js +1 -0
  185. package/static/dist/assets/Toaster-mch1pa3t.js +1 -0
  186. package/static/dist/assets/_app-m8d961ef.js +1 -0
  187. package/static/dist/assets/_app.ext._extensionId-mp33hbzi.js +1 -0
  188. package/static/dist/assets/_app.index-dk6zp7e0.js +1 -0
  189. package/static/dist/assets/_app.insights-jt2fk4i1.js +1 -0
  190. package/static/dist/assets/_app.kanban-if4pubeu.js +1 -0
  191. package/static/dist/assets/_app.logs-mfaw9m6g.js +1 -0
  192. package/static/dist/assets/_app.memory-h3eaarb6.js +1 -0
  193. package/static/dist/assets/_app.profiles-ienktovs.js +1 -0
  194. package/static/dist/assets/{_app.session._sessionId-m6nx9g8t.js → _app.session._sessionId-hh27wwu2.js} +1 -1
  195. package/static/dist/assets/_app.settings-dpoe0bzf.js +1 -0
  196. package/static/dist/assets/_app.settings._section-l468ynag.js +3 -0
  197. package/static/dist/assets/_app.skills-kcbncc8i.js +1 -0
  198. package/static/dist/assets/_app.tasks-occdrqhw.js +2 -0
  199. package/static/dist/assets/_app.todos-nnke2rcc.js +1 -0
  200. package/static/dist/assets/_app.workspaces-cdlatvwj.js +1 -0
  201. package/static/dist/assets/{abnfDiagram-VCTEODGH-kejgxpil.js → abnfDiagram-VCTEODGH-oity9y4o.js} +1 -1
  202. package/static/dist/assets/architecture-7GRP2DOG-hj11333z.js +1 -0
  203. package/static/dist/assets/architectureDiagram-5GKGNRK7-ceaepnyr.js +36 -0
  204. package/static/dist/assets/back-eu64w89w.js +1 -0
  205. package/static/dist/assets/{blockDiagram-I7D4REHJ-l1466a7j.js → blockDiagram-I7D4REHJ-n79st4pj.js} +1 -1
  206. package/static/dist/assets/{c4Diagram-7LVT6UL2-gg3aq3sr.js → c4Diagram-7LVT6UL2-mi73akzk.js} +1 -1
  207. package/static/dist/assets/cancel-mzvkdjg8.js +1 -0
  208. package/static/dist/assets/channel-mbvmf2vv.js +1 -0
  209. package/static/dist/assets/{chunk-4HAMMTFA-oalgz5l8.js → chunk-4HAMMTFA-laat0g1q.js} +1 -1
  210. package/static/dist/assets/{chunk-75Z2AOVW-babmzhdg.js → chunk-75Z2AOVW-0psy1tr2.js} +1 -1
  211. package/static/dist/assets/{chunk-DU6HZSFF-lagu350c.js → chunk-DU6HZSFF-lw8uox8x.js} +3 -3
  212. package/static/dist/assets/{chunk-F27PBJKO-gjh2tqif.js → chunk-F27PBJKO-erassib3.js} +1 -1
  213. package/static/dist/assets/{chunk-GMAD6QVW-ipdgja5c.js → chunk-GMAD6QVW-fz7rx619.js} +1 -1
  214. package/static/dist/assets/{chunk-GVQU2GXP-j8wkn1at.js → chunk-GVQU2GXP-gdb0epb2.js} +1 -1
  215. package/static/dist/assets/{chunk-IMKFNOWR-k00laqyk.js → chunk-IMKFNOWR-ea8t26qw.js} +1 -1
  216. package/static/dist/assets/{chunk-L3NEJ4N5-fju6xqj4.js → chunk-L3NEJ4N5-mb1gu9kz.js} +1 -1
  217. package/static/dist/assets/{chunk-OSK3NFVY-bi6widqt.js → chunk-OSK3NFVY-eovmccvy.js} +1 -1
  218. package/static/dist/assets/{chunk-P2QGCYS3-czr4tebv.js → chunk-P2QGCYS3-bo55zjo5.js} +1 -1
  219. package/static/dist/assets/{chunk-POPQ4Y6H-ktdhn67w.js → chunk-POPQ4Y6H-ja7ohe4h.js} +1 -1
  220. package/static/dist/assets/{chunk-PWAF6VOD-ii4dsu0d.js → chunk-PWAF6VOD-e30g9nus.js} +1 -1
  221. package/static/dist/assets/{chunk-SHT3W25Y-fpwk3xxp.js → chunk-SHT3W25Y-gbb798f7.js} +3 -3
  222. package/static/dist/assets/{chunk-SVP7TREG-k0jrvhei.js → chunk-SVP7TREG-h2iw8urm.js} +1 -1
  223. package/static/dist/assets/{chunk-TICWLB2K-nkqv9ot0.js → chunk-TICWLB2K-fd2cottz.js} +1 -1
  224. package/static/dist/assets/classDiagram-ZZMXUADV-o8r05k0n.js +1 -0
  225. package/static/dist/assets/classDiagram-v2-VYDZK3BY-o8r05k0n.js +1 -0
  226. package/static/dist/assets/{copied-gpchexqu.js → copied-h65fc3cx.js} +1 -1
  227. package/static/dist/assets/copy-e6977uwq.js +1 -0
  228. package/static/dist/assets/{cynefin-OW5HDTMX-lqxt8rs3.js → cynefin-OW5HDTMX-lbltyl5j.js} +1 -1
  229. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-j9eqovf5.js → cynefinDiagram-5FMLGOSQ-lxhsqq4a.js} +1 -1
  230. package/static/dist/assets/{dagre-GXQ25YYZ-m9agobjm.js → dagre-GXQ25YYZ-gn4nnaln.js} +4 -4
  231. package/static/dist/assets/{diagram-S7CK7UJ4-itodc50c.js → diagram-S7CK7UJ4-pa3ij6q7.js} +3 -3
  232. package/static/dist/assets/{diagram-UQ7AKVKN-n1h2t4ah.js → diagram-UQ7AKVKN-zbipyz57.js} +1 -1
  233. package/static/dist/assets/{diagram-VSXAHHWV-lvtvm9bj.js → diagram-VSXAHHWV-d1kbpzgf.js} +1 -1
  234. package/static/dist/assets/{diagram-VX7I27RA-cgas58sy.js → diagram-VX7I27RA-i3ty14xl.js} +1 -1
  235. package/static/dist/assets/{diagram-Z3DM3KII-d0aeps1q.js → diagram-Z3DM3KII-m8xefqa7.js} +1 -1
  236. package/static/dist/assets/{ebnfDiagram-PWID7BFC-md345fyq.js → ebnfDiagram-PWID7BFC-nz7wj05l.js} +1 -1
  237. package/static/dist/assets/endpoints-k7yf25m0.js +64 -0
  238. package/static/dist/assets/{erDiagram-RLTQ6QDP-i4rua63b.js → erDiagram-RLTQ6QDP-fa41ib83.js} +1 -1
  239. package/static/dist/assets/eventmodeling-NTZA5JFV-kpbq09bx.js +1 -0
  240. package/static/dist/assets/flowDiagram-HODETNUW-lcz0kx14.js +1 -0
  241. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-geqx7zgl.js → ganttDiagram-EL5Y4UJY-n7zq01qu.js} +1 -1
  242. package/static/dist/assets/{gitGraph-4MIJSDKK-leoq0z8t.js → gitGraph-4MIJSDKK-c89emb07.js} +1 -1
  243. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-llrlxfha.js → gitGraphDiagram-WWUBYQGX-cz7cgr6w.js} +1 -1
  244. package/static/dist/assets/{highlighted-body-KPVGNVTW-kq2cnw6q.js → highlighted-body-KPVGNVTW-d9bapmni.js} +1 -1
  245. package/static/dist/assets/{index-f9bzglkn.js → index-h00usru2.js} +3 -3
  246. package/static/dist/assets/index-n73ijkv2.css +2 -0
  247. package/static/dist/assets/{info-A6RAGUB7-lkly4xj6.js → info-A6RAGUB7-ndddhhhh.js} +1 -1
  248. package/static/dist/assets/infoDiagram-27XIBGKW-ccxigcpf.js +2 -0
  249. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-hq6jf374.js → ishikawaDiagram-5VMMS53U-le0z9vtc.js} +1 -1
  250. package/static/dist/assets/{journeyDiagram-3NMN7TZE-is03ntb0.js → journeyDiagram-3NMN7TZE-ivsmb26o.js} +1 -1
  251. package/static/dist/assets/{kanban-definition-UXKFOSKX-jmerizqb.js → kanban-definition-UXKFOSKX-h6n2awt0.js} +1 -1
  252. package/static/dist/assets/lazyRouteComponent-m1rtyk4t.js +1 -0
  253. package/static/dist/assets/{line-laaa8h99.js → line-dmzlfe0u.js} +1 -1
  254. package/static/dist/assets/link-budeg5t9.js +1 -0
  255. package/static/dist/assets/login-kjhasvp8.js +1 -0
  256. package/static/dist/assets/mermaid-HWGCJPDP-jb5d211j.js +1 -0
  257. package/static/dist/assets/{mermaid-parser.core-ix4junux.js → mermaid-parser.core-gwyd5bnq.js} +3 -3
  258. package/static/dist/assets/{mindmap-definition-YA3MSWOX-o0e0adl1.js → mindmap-definition-YA3MSWOX-l68gg5h7.js} +1 -1
  259. package/static/dist/assets/onboarding-cdfrk0pj.js +1 -0
  260. package/static/dist/assets/{packet-AYTQ26CC-kl8pwsyg.js → packet-AYTQ26CC-gpv06065.js} +1 -1
  261. package/static/dist/assets/{pegDiagram-XKGWAZYB-bbqn9jo4.js → pegDiagram-XKGWAZYB-e52vs23u.js} +1 -1
  262. package/static/dist/assets/{pie-WAS4IAKB-cpyo8bkr.js → pie-WAS4IAKB-l6m7nz5s.js} +1 -1
  263. package/static/dist/assets/{pieDiagram-E7YTZNPT-pelug34f.js → pieDiagram-E7YTZNPT-b4is36bq.js} +3 -3
  264. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-jds4jmr5.js → quadrantDiagram-AXDQQJYC-m8vt2788.js} +1 -1
  265. package/static/dist/assets/{radar-RG4KPBEZ-e02oxnvd.js → radar-RG4KPBEZ-nxbrhiov.js} +1 -1
  266. package/static/dist/assets/{railroad-74A4TZTK-kz3delwo.js → railroad-74A4TZTK-222mu9hi.js} +1 -1
  267. package/static/dist/assets/railroad-abnf-HS5TGJTU-kdvgl6x8.js +1 -0
  268. package/static/dist/assets/railroad-ebnf-LZEXJU2U-itiqslby.js +1 -0
  269. package/static/dist/assets/railroad-peg-WCYAUIDC-go7kov78.js +1 -0
  270. package/static/dist/assets/{railroadDiagram-O6MQD6OU-jgroj2ew.js → railroadDiagram-O6MQD6OU-o8lldfzv.js} +1 -1
  271. package/static/dist/assets/{refresh-cw-k7yxjdn3.js → refresh-cw-kbcje1uy.js} +1 -1
  272. package/static/dist/assets/{requirementDiagram-BXWQKSXE-m4az5e0j.js → requirementDiagram-BXWQKSXE-ovyq38kv.js} +1 -1
  273. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-vlryqiv3.js → sankeyDiagram-P5KCCOFB-ou7lznor.js} +1 -1
  274. package/static/dist/assets/{saved-brdfjjnw.js → saved-bazmcup9.js} +1 -1
  275. package/static/dist/assets/search-jen74z4u.js +1 -0
  276. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-fr8hrpql.js → sequenceDiagram-WJ2MYXX4-ovckdzf2.js} +1 -1
  277. package/static/dist/assets/{settings_section_extensions_title-l0zodj0b.js → settings_section_extensions_title-ertwwhlx.js} +1 -1
  278. package/static/dist/assets/share._token-dan9hgvj.js +2 -0
  279. package/static/dist/assets/{sliders-horizontal-gcgscv8r.js → sliders-horizontal-f9cb3lh3.js} +1 -1
  280. package/static/dist/assets/{stateDiagram-D77RDMKH-bg548iyr.js → stateDiagram-D77RDMKH-fcrexkkv.js} +1 -1
  281. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-lcfraua2.js +1 -0
  282. package/static/dist/assets/{swimlanes-42K2YHIH-hk5z3efh.js → swimlanes-42K2YHIH-f7usu8fw.js} +1 -1
  283. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ogmanni0.js +8 -0
  284. package/static/dist/assets/{timeline-definition-24CTP7MA-olvknr62.js → timeline-definition-24CTP7MA-gp1hvz9f.js} +1 -1
  285. package/static/dist/assets/todoStore-eqtid4r4.js +1 -0
  286. package/static/dist/assets/{treeView-Q6P3EWNA-ovvjsxtf.js → treeView-Q6P3EWNA-gb9gf11u.js} +1 -1
  287. package/static/dist/assets/{treemap-WGGIJYW6-ggkipj59.js → treemap-WGGIJYW6-nuvfnvvi.js} +1 -1
  288. package/static/dist/assets/{untitled-c8ydw0bu.js → untitled-htelhc68.js} +1 -1
  289. package/static/dist/assets/useForm-h2t0u14e.js +1 -0
  290. package/static/dist/assets/useLocale-hcsb84pj.js +1 -0
  291. package/static/dist/assets/useNavigate-nwy70ztj.js +1 -0
  292. package/static/dist/assets/{useParams-katwvzil.js → useParams-dqd64jv7.js} +1 -1
  293. package/static/dist/assets/{useSearch-c70sgau1.js → useSearch-j30pvsy7.js} +1 -1
  294. package/static/dist/assets/{vennDiagram-4TSXK5OY-hzld7zt7.js → vennDiagram-4TSXK5OY-fzchbzaj.js} +1 -1
  295. package/static/dist/assets/{wardley-WFR3VGLG-hxkeoms8.js → wardley-WFR3VGLG-m47mhfbh.js} +1 -1
  296. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-ljh90mb1.js → wardleyDiagram-VM6X3IG4-odg6ct1z.js} +2 -2
  297. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-mnuaes03.js → xychartDiagram-S5SC5T6Z-mrhms5um.js} +1 -1
  298. package/static/dist/index.html +1 -1
  299. package/static/dist/sw.js +1 -1
  300. package/static/dist/assets/AppShell-haqi9qzu.js +0 -1
  301. package/static/dist/assets/ChatPage-hjyu2g64.js +0 -22
  302. package/static/dist/assets/HubRoute-gkd8o1vg.js +0 -2
  303. package/static/dist/assets/RightPanel-o73y98dn.js +0 -1
  304. package/static/dist/assets/Select-jld3yeni.js +0 -1
  305. package/static/dist/assets/SessionListPanel-d3qx4ric.js +0 -1
  306. package/static/dist/assets/SettingsLayout-lnn2wo2s.js +0 -1
  307. package/static/dist/assets/States-e5hv6gdh.js +0 -1
  308. package/static/dist/assets/Toaster-c4jq1i26.js +0 -1
  309. package/static/dist/assets/_app-bnip2pjg.js +0 -1
  310. package/static/dist/assets/_app.ext._extensionId-egptzrfy.js +0 -1
  311. package/static/dist/assets/_app.index-vdz13ul5.js +0 -1
  312. package/static/dist/assets/_app.insights-lgjshsba.js +0 -1
  313. package/static/dist/assets/_app.kanban-c18cjrpz.js +0 -1
  314. package/static/dist/assets/_app.logs-ezhojgeg.js +0 -1
  315. package/static/dist/assets/_app.memory-i00paisv.js +0 -1
  316. package/static/dist/assets/_app.profiles-kd02bwjx.js +0 -1
  317. package/static/dist/assets/_app.settings-giaudkuk.js +0 -1
  318. package/static/dist/assets/_app.settings._section-k4qtlexk.js +0 -1
  319. package/static/dist/assets/_app.skills-bby2uvl8.js +0 -1
  320. package/static/dist/assets/_app.tasks-1kz9bosm.js +0 -2
  321. package/static/dist/assets/_app.todos-izjdbkm2.js +0 -1
  322. package/static/dist/assets/_app.workspaces-lfh2kw7s.js +0 -1
  323. package/static/dist/assets/architecture-7GRP2DOG-b4u9z1w3.js +0 -1
  324. package/static/dist/assets/architectureDiagram-5GKGNRK7-hqnf84fc.js +0 -36
  325. package/static/dist/assets/channel-o77ioktg.js +0 -1
  326. package/static/dist/assets/classDiagram-ZZMXUADV-f5rvod26.js +0 -1
  327. package/static/dist/assets/classDiagram-v2-VYDZK3BY-f5rvod26.js +0 -1
  328. package/static/dist/assets/endpoints-e58saih3.js +0 -9
  329. package/static/dist/assets/eventmodeling-NTZA5JFV-bn3fjsaq.js +0 -1
  330. package/static/dist/assets/flowDiagram-HODETNUW-li70d120.js +0 -1
  331. package/static/dist/assets/index-gkh7kum4.css +0 -2
  332. package/static/dist/assets/infoDiagram-27XIBGKW-oo7kdyte.js +0 -2
  333. package/static/dist/assets/lazyRouteComponent-b1h2ykmb.js +0 -1
  334. package/static/dist/assets/link-d8f0788e.js +0 -1
  335. package/static/dist/assets/login-llkohrcg.js +0 -1
  336. package/static/dist/assets/mermaid-HWGCJPDP-id0ffk2r.js +0 -1
  337. package/static/dist/assets/onboarding-lx0d6b38.js +0 -1
  338. package/static/dist/assets/railroad-abnf-HS5TGJTU-l13ped2z.js +0 -1
  339. package/static/dist/assets/railroad-ebnf-LZEXJU2U-c7rg3g4g.js +0 -1
  340. package/static/dist/assets/railroad-peg-WCYAUIDC-od0b8niq.js +0 -1
  341. package/static/dist/assets/search-gt2ueyvg.js +0 -1
  342. package/static/dist/assets/share._token-oyjv046r.js +0 -2
  343. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-j5v40qih.js +0 -1
  344. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-grzefo9c.js +0 -8
  345. package/static/dist/assets/tabBuild-idliyw9f.js +0 -56
  346. package/static/dist/assets/todoStore-j4c2xq0b.js +0 -1
  347. package/static/dist/assets/useForm-kd759sjk.js +0 -1
  348. package/static/dist/assets/useLocale-hds4xmja.js +0 -1
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { buildActiveTurnToken } from '../redact.js';
7
7
  import { str } from '../util.js';
8
+ import { stripAttachedFilesMarker } from './session.js';
8
9
  export const WORKSPACE_PREFIX_RE = /^\s*\[Workspace::v1:\s*(?:\\.|[^\]\\])+\]\s*/;
9
10
  const LEGACY_WORKSPACE_PREFIX_RE = /^\s*\[Workspace:[^\]]+\]\s*/;
10
11
  const TOOL_RESULT_SNIPPET_MAX = 4000;
@@ -59,8 +60,15 @@ export function messageIdentity(msg) {
59
60
  return null;
60
61
  const role = str(msg.role);
61
62
  let text = messageText(msg.content);
62
- if (role === 'user')
63
- text = stripWorkspacePrefix(text, true);
63
+ if (role === 'user') {
64
+ const typed = userPromptText(text);
65
+ // An attachment-only prompt has no typed text; its whole attached-files line (never truncated) tells one such turn
66
+ // from the next.
67
+ const line = typed ? '' : stripWorkspacePrefix(text, true);
68
+ if (line)
69
+ return JSON.stringify([role, line, '', '[]']);
70
+ text = typed;
71
+ }
64
72
  if (!text && !msg.tool_call_id && !msg.tool_calls) {
65
73
  if (msg._partial)
66
74
  return JSON.stringify([role, '', '', `__partial__${str(msg.reasoning).split(/\s+/).join(' ').slice(0, 200)}`]);
@@ -88,22 +96,57 @@ export function messagesHavePrefix(messages, prefix) {
88
96
  return false;
89
97
  return true;
90
98
  }
91
- export function isContextCompressionMarker(msg) {
99
+ const PRESERVED_TASK_LIST_PREFIX = '[your active task list was preserved across context compression]';
100
+ const hasPrefix = (text, prefix) => text.slice(0, prefix.length).toLowerCase() === prefix;
101
+ /**
102
+ * TAL-305: the one rule for the marker rows the Agent writes around context compaction. A flagged row, or a user or
103
+ * assistant row starting `[context compaction`, is a compaction summary; a user row starting with the preserved-task-list
104
+ * line is that list. Both ignore case and leading whitespace; prose that merely mentions compaction is no marker.
105
+ */
106
+ export function markerKind(msg) {
92
107
  if (!isDict(msg))
93
- return false;
108
+ return null;
94
109
  if (msg._context_compression_marker || msg._compression_marker || msg._compaction_marker)
95
- return true;
96
- const text = messageText(msg.content);
97
- return str(msg.role) === 'user' && text.startsWith('[CONTEXT COMPACTION]');
110
+ return 'context_compaction';
111
+ const role = str(msg.role);
112
+ const text = messageText(msg.content).trimStart();
113
+ if (role === 'user' && hasPrefix(text, PRESERVED_TASK_LIST_PREFIX))
114
+ return 'preserved_task_list';
115
+ if ((role === 'user' || role === 'assistant') && hasPrefix(text, '[context compaction'))
116
+ return 'context_compaction';
117
+ return null;
118
+ }
119
+ export function isContextCompressionMarker(msg) {
120
+ return markerKind(msg) === 'context_compaction';
98
121
  }
99
- const normalizeUserText = (text) => stripWorkspacePrefix(text, true).split(/\s+/).join(' ').trim();
122
+ /**
123
+ * TAL-305: stamps `_marker_kind` on marker rows, and `_marker_body` (the list without its marker line) on a preserved
124
+ * task list, so clients render a marker card instead of a message. Returns copies; stored rows are untouched.
125
+ */
126
+ export function withMarkerKinds(messages) {
127
+ return messages.map((m) => {
128
+ const kind = markerKind(m);
129
+ if (!kind || !isDict(m))
130
+ return m;
131
+ if (kind === 'context_compaction')
132
+ return { ...m, _marker_kind: kind };
133
+ const body = messageText(m.content).trim().slice(PRESERVED_TASK_LIST_PREFIX.length).trim();
134
+ return { ...m, _marker_kind: kind, _marker_body: body };
135
+ });
136
+ }
137
+ /** A user prompt as the user typed it: without the workspace prefix and the attached-files line the server adds. */
138
+ const userPromptText = (text) => stripWorkspacePrefix(stripAttachedFilesMarker(text), true);
139
+ const normalizeUserText = (text) => userPromptText(text).split(/\s+/).join(' ').trim();
100
140
  export function looksLikeCurrentUserTurn(msg, msgText) {
101
141
  // A persisted steer is display-only: it is never the prompt that opened a turn.
102
142
  if (!isDict(msg) || str(msg.role) !== 'user' || isDict(msg._steer))
103
143
  return false;
104
144
  const candidate = normalizeUserText(messageText(msg.content));
105
145
  const target = normalizeUserText(msgText);
106
- if (!candidate || !target)
146
+ // An attachment-only prompt (TAL-276) has no text: the Agent's row for it carries none either.
147
+ if (!target)
148
+ return !candidate;
149
+ if (!candidate)
107
150
  return false;
108
151
  return candidate === target || candidate.startsWith(`${target}\n`) || candidate.endsWith(target);
109
152
  }
@@ -222,10 +265,13 @@ export function mergeDisplayMessagesAfterAgentResult(previousDisplay, previousCo
222
265
  const merged = [...prev];
223
266
  const seen = new Set(merged.map(messageIdentity).filter((k) => k !== null));
224
267
  const currentUserKey = messageIdentity({ role: 'user', content: msgText });
225
- const currentUserIn = candidates.some((m) => messageIdentity(m) === currentUserKey || looksLikeCurrentUserTurn(m, msgText));
268
+ const currentUserIn = candidates.some((m) => (currentUserKey !== null && messageIdentity(m) === currentUserKey) || looksLikeCurrentUserTurn(m, msgText));
226
269
  const alreadyCheckpointed = Boolean(opts.activeTurnToken) && merged.some((m) => isDict(m) && m.role === 'user' && m._active_turn_token === opts.activeTurnToken);
227
- if (currentUserKey !== null && !currentUserIn && !alreadyCheckpointed && candidates.some((m) => isDict(m) && (m.role === 'assistant' || m.role === 'tool'))) {
270
+ const promptless = currentUserKey === null && Boolean(opts.attachments?.length);
271
+ if ((currentUserKey !== null || promptless) && !currentUserIn && !alreadyCheckpointed && candidates.some((m) => isDict(m) && (m.role === 'assistant' || m.role === 'tool'))) {
228
272
  const user = { role: 'user', content: msgText, timestamp: opts.now ?? Date.now() / 1000 };
273
+ if (promptless)
274
+ user.attachments = [...opts.attachments];
229
275
  if (opts.activeTurnToken)
230
276
  user._active_turn_token = opts.activeTurnToken;
231
277
  if (opts.turnId)
@@ -243,7 +289,7 @@ export function mergeDisplayMessagesAfterAgentResult(previousDisplay, previousCo
243
289
  const key = messageIdentity(msg);
244
290
  const isCurrentUser = looksLikeCurrentUserTurn(msg, msgText);
245
291
  const last = merged[merged.length - 1];
246
- if (((key !== null && key === currentUserKey) || isCurrentUser) && last && (messageIdentity(last) === currentUserKey || looksLikeCurrentUserTurn(last, msgText))) {
292
+ if (((key !== null && key === currentUserKey) || isCurrentUser) && last && ((currentUserKey !== null && messageIdentity(last) === currentUserKey) || looksLikeCurrentUserTurn(last, msgText))) {
247
293
  if (isDict(msg) && msg.id !== undefined && isDict(last) && last.id === undefined)
248
294
  last.id = msg.id;
249
295
  continue;
@@ -298,10 +344,134 @@ function presentError(v) {
298
344
  return v.length > 0;
299
345
  return isDict(v) ? Object.keys(v).length > 0 : v === true;
300
346
  }
347
+ const RESULT_TEXT_KEYS = ['result', 'results', 'preview', 'content', 'text', 'message', 'summary', 'data', 'items'];
348
+ const RESULT_VIEW_MAX_DEPTH = 8;
349
+ const tryJson = (text) => { try {
350
+ return JSON.parse(text);
351
+ }
352
+ catch {
353
+ return undefined;
354
+ } };
355
+ const prettyJson = (value) => { try {
356
+ return JSON.stringify(value, null, 2);
357
+ }
358
+ catch {
359
+ return str(value);
360
+ } };
361
+ /** Line breaks and tabs a JSON-encoded result left escaped (`\n`, `\\n`), as the characters they stand for. */
362
+ const unescapeResultText = (text) => text.replace(/\r\n/g, '\n').replace(/\\{1,2}r\\{1,2}n|\\{1,2}n/g, '\n').replace(/\\{1,2}t/g, '\t');
363
+ /** The JSON a result string holds: as written, else with its escaped quotes undone; nested JSON strings unwrap three levels. */
364
+ function resultJson(text) {
365
+ const trimmed = text.trim();
366
+ let value = tryJson(trimmed);
367
+ if (value === undefined && trimmed.includes('\\"'))
368
+ value = tryJson(trimmed.replaceAll('\\"', '"'));
369
+ for (let i = 0; i < 3 && typeof value === 'string'; i += 1) {
370
+ const inner = tryJson(value.trim());
371
+ if (inner === undefined)
372
+ break;
373
+ value = inner;
374
+ }
375
+ return value;
376
+ }
377
+ /** A section's text: a string unescaped, a scalar as written, a structure as pretty JSON; `undefined` when blank. */
378
+ function sectionText(value) {
379
+ const text = typeof value === 'string' ? unescapeResultText(value) : typeof value === 'number' || typeof value === 'boolean' ? String(value) : value === null || value === undefined ? '' : prettyJson(value);
380
+ return text.trim() || undefined;
381
+ }
382
+ /** An exit code: an integer, or a string of one; anything else is dropped. */
383
+ function exitCodeOf(value) {
384
+ const n = typeof value === 'number' ? Math.trunc(value) : typeof value === 'string' && /^\s*[+-]?\d+\s*$/.test(value) ? Number(value) : NaN;
385
+ return Number.isSafeInteger(n) ? n : undefined;
386
+ }
387
+ /** A terminal result's sections; the exit code only when it is non-zero or nothing else would show. */
388
+ function terminalView(data) {
389
+ const view = {};
390
+ const stdout = sectionText(data.output) ?? sectionText(data.stdout);
391
+ const stderr = sectionText(data.stderr);
392
+ const error = sectionText(data.error);
393
+ if (stdout)
394
+ view.stdout = stdout;
395
+ if (stderr)
396
+ view.stderr = stderr;
397
+ if (error)
398
+ view.error = error;
399
+ const exit = exitCodeOf(data.exit_code ?? data.exitCode);
400
+ if (exit !== undefined && (exit !== 0 || !Object.keys(view).length))
401
+ view.exit_code = exit;
402
+ return view;
403
+ }
404
+ /** Every item of a list is a text part (`text`, `content` or `message`): their texts, one per line. */
405
+ function textParts(items) {
406
+ const texts = items.map((item) => (isDict(item) ? sectionText(item.text) ?? sectionText(item.content) ?? sectionText(item.message) : undefined));
407
+ return texts.length && texts.every(Boolean) ? texts.join('\n') : undefined;
408
+ }
409
+ const isEmptyView = (view) => Object.keys(view).length === 0;
410
+ function resultView(value, depth) {
411
+ if (typeof value === 'string') {
412
+ const parsed = depth < RESULT_VIEW_MAX_DEPTH ? resultJson(value) : undefined;
413
+ if (parsed !== undefined && typeof parsed !== 'string') {
414
+ const view = resultView(parsed, depth + 1);
415
+ if (!isEmptyView(view))
416
+ return view;
417
+ }
418
+ // Top-level text that is not JSON shows exactly as written; strings inside JSON are unescaped.
419
+ const text = depth === 0 && parsed === undefined ? value.trim() : sectionText(typeof parsed === 'string' ? parsed : value);
420
+ return text ? { text } : {};
421
+ }
422
+ if (Array.isArray(value)) {
423
+ const text = textParts(value) ?? sectionText(value);
424
+ return text ? { text } : {};
425
+ }
426
+ if (!isDict(value)) {
427
+ const text = sectionText(value);
428
+ return text ? { text } : {};
429
+ }
430
+ if (depth >= RESULT_VIEW_MAX_DEPTH)
431
+ return { text: prettyJson(value) };
432
+ // A process result: its output streams, error and exit code.
433
+ if (sectionText(value.output) ?? sectionText(value.stdout) ?? sectionText(value.stderr))
434
+ return terminalView(value);
435
+ for (const key of RESULT_TEXT_KEYS) {
436
+ const view = resultView(value[key], depth + 1);
437
+ if (!isEmptyView(view))
438
+ return view;
439
+ }
440
+ const terminal = terminalView(value);
441
+ if (!isEmptyView(terminal))
442
+ return terminal;
443
+ return Object.keys(value).length ? { text: prettyJson(value) } : {};
444
+ }
445
+ /**
446
+ * The server's one result view rule (TAL-315), ported from the iOS formatter so every client renders the same sections:
447
+ * a JSON result (nested JSON strings unwrapped, escaped line breaks undone) with `output`/`stdout`/`stderr` maps to its
448
+ * terminal sections; any other object shows the first readable `result`, `results`, `preview`, `content`, `text`,
449
+ * `message`, `summary`, `data` or `items`, else its `error` and exit code, else pretty JSON. A list of text parts joins
450
+ * by line; a scalar shows as text, and a result that is not JSON exactly as written. Each field is capped like the snippet
451
+ * (`limit`; TAL-331's whole-result read passes `Infinity`).
452
+ */
453
+ export function toolResultView(raw, limit = TOOL_RESULT_SNIPPET_MAX) {
454
+ // Content parts read as their text; a list with no text (`[{ title }]`) is the result itself.
455
+ const flat = Array.isArray(raw) ? messageText(raw) : raw;
456
+ const view = resultView(Array.isArray(raw) && !str(flat).trim() ? raw : flat, 0);
457
+ return Object.fromEntries(Object.entries(view).map(([key, field]) => [key, typeof field === 'string' ? toolResultSnippet(field, limit) : field]));
458
+ }
459
+ /** A view the server already decided (a built scene row, or one stored with its scene): its known fields, capped. */
460
+ export function decidedResultView(value) {
461
+ const view = {};
462
+ for (const key of ['text', 'stdout', 'stderr', 'error']) {
463
+ const field = value[key];
464
+ if (typeof field === 'string' && field)
465
+ view[key] = toolResultSnippet(field);
466
+ }
467
+ if (typeof value.exit_code === 'number' && Number.isSafeInteger(value.exit_code))
468
+ view.exit_code = value.exit_code;
469
+ return view;
470
+ }
301
471
  /**
302
472
  * The server's one tool outcome rule (TAL-313), for a live `raw_result` and a persisted tool-role content alike: a result
303
473
  * is an error when it parses to an object with a non-empty `error`, a non-zero numeric `exit_code` / `exitCode`, or
304
- * `success: false`. `result_text` is the result's display snippet.
474
+ * `success: false`. `result_text` is the result's display snippet; `result_view` its display sections (TAL-315).
305
475
  */
306
476
  export function toolOutcome(raw) {
307
477
  const value = Array.isArray(raw) ? messageText(raw) : raw;
@@ -316,7 +486,7 @@ export function toolOutcome(raw) {
316
486
  }
317
487
  const exit = isDict(data) ? data.exit_code ?? data.exitCode : undefined;
318
488
  const isError = isDict(data) && (presentError(data.error) || (typeof exit === 'number' && exit !== 0) || data.success === false);
319
- return { is_error: isError, result_text: toolResultSnippet(value) };
489
+ return { is_error: isError, result_text: toolResultSnippet(value), result_view: toolResultView(raw) };
320
490
  }
321
491
  const finiteOrNull = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : null);
322
492
  function nearestAssistantIdx(messages, msgIdx) {
@@ -428,7 +598,8 @@ export function extractToolCallsFromMessages(messages, liveToolCalls = [], recor
428
598
  * a call only the session-level list recorded joins the row at its `assistant_msg_idx`, a failed or cancelled turn's
429
599
  * partial snapshot shows the live calls it kept, and every call carries `done`
430
600
  * (answered, or outside the running turn), `is_error` (`toolOutcome` of its result, else the recorded value), `duration`
431
- * (recorded live, else `null`) and `result` (the result snippet, else `null`). Returns copies; stored rows are untouched.
601
+ * (recorded live, else `null`), `result` (the result snippet, else `null`) and `result_view` (its display sections, TAL-315,
602
+ * else `null`). Returns copies; stored rows are untouched.
432
603
  */
433
604
  export function withToolCallOutcomes(messages, sessionToolCalls, activeTurnId) {
434
605
  // Every identifier a stored call may carry (`ToolCallSchema`).
@@ -505,6 +676,7 @@ export function withToolCallOutcomes(messages, sessionToolCalls, activeTurnId) {
505
676
  return {
506
677
  done: Boolean(reply) || answered || !running, is_error: outcome ? outcome.flagged || outcome.is_error : rec?.is_error === true,
507
678
  duration: finiteOrNull(rec?.duration), result: outcome ? outcome.result_text : typeof rec?.snippet === 'string' ? rec.snippet : null,
679
+ result_view: outcome ? outcome.result_view : isDict(rec?.result_view) ? decidedResultView(rec.result_view) : typeof rec?.snippet === 'string' ? toolResultView(rec.snippet) : null,
508
680
  };
509
681
  };
510
682
  const projected = [
@@ -537,21 +709,130 @@ export function buildPartialMessage(contentText, reasoningText, toolCalls, now =
537
709
  msg._partial_tool_calls = [...toolCalls];
538
710
  return msg;
539
711
  }
540
- export function stripXmlToolCalls(text) {
541
- return text.replace(/<function_calls>[\s\S]*?<\/function_calls>/gi, '').replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, '').trimEnd();
712
+ const DSML = '(?:\\s*|\\s*DSML\\s*[||]\\s*)?';
713
+ /** Markdown code (fenced blocks, an unclosed one running to the end, and inline spans): markup written there is literal. */
714
+ function codeRanges(text) {
715
+ const code = /^ {0,3}(`{3,}|~{3,})[^\n]*(?:\n[\s\S]*?(?:\n {0,3}\1[^\n]*(?=\n|$)|(?![\s\S]))|(?![\s\S]))|(`+)(?!`)(?:[^\n]|\n(?!\n))*?(?<!`)\2(?!`)/gm;
716
+ return [...text.matchAll(code)].map((m) => [m.index, m.index + m[0].length]);
717
+ }
718
+ const inCode = (code, at) => code.some(([from, to]) => at >= from && at < to);
719
+ /** `re` matches removed, except the ones that start inside Markdown code. */
720
+ function removeOutsideCode(text, re) {
721
+ const code = codeRanges(text);
722
+ return text.replace(re, (match, ...rest) => (inCode(code, rest.find((x) => typeof x === 'number') ?? 0) ? match : ''));
542
723
  }
543
- /** Split inline `<think>` blocks out of assistant content (Python `_split_thinking_from_content`, reduced). */
544
- export function splitThinkingFromContent(content, existingReasoning = '') {
545
- const parts = [];
546
- const cleaned = content.replace(/<think(?:ing)?\b[^>]*>([\s\S]*?)<\/think(?:ing)?>/gi, (_m, inner) => { parts.push(inner.trim()); return ''; });
547
- const reasoning = [existingReasoning.trim(), ...parts].filter(Boolean).join('\n\n');
548
- return [cleaned.replace(/^\s+/, '').trimEnd(), reasoning];
724
+ /** Remove provider tool-call XML (`<function_calls>…`, DSML variants, `<tool_call>`), closed or cut off, that leaks into text. */
725
+ export function stripToolCallXml(text) {
726
+ const lo = text.toLowerCase();
727
+ if (!lo.includes('function_calls') && !lo.includes('dsml') && !lo.includes('<tool_call'))
728
+ return text;
729
+ return [
730
+ new RegExp(`<${DSML}function_calls>[\\s\\S]*?<\\/${DSML}function_calls>`, 'gi'),
731
+ new RegExp(`<${DSML}function_calls(?:>|$)[\\s\\S]*$`, 'i'),
732
+ /<tool_call>[\s\S]*?<\/tool_call>/gi,
733
+ /<tool_call>[\s\S]*$/i,
734
+ /<\s*|\s*DSML\s*[||]\s*/gi,
735
+ ].reduce(removeOutsideCode, text).replace(/^\s+/, '').trimEnd();
736
+ }
737
+ /** Inline thinking openers: `<think>`/`<thinking>` in any case and with attributes (as the Agent's own split), and the channel forms. */
738
+ const THINK_OPEN = /<think(?:ing)?(?:\s[^>]*)?>|<\|channel\|>thought|<\|turn\|>thinking/gi;
739
+ function thinkClose(open) {
740
+ if (open.toLowerCase().startsWith('<|channel|>'))
741
+ return /<channel\|>/gi;
742
+ if (open.toLowerCase().startsWith('<|turn|>'))
743
+ return /<turn\|>/gi;
744
+ return /<\/think(?:ing)?\s*>/gi;
745
+ }
746
+ /**
747
+ * Split assistant text into its visible prose and its inline thinking: every `<think>`, `<thinking>`,
748
+ * `<|channel|>thought` and `<|turn|>thinking` block anywhere in the text, an unterminated one running to the end.
749
+ * A tag written inside Markdown code is prose. Tool-call XML leaves both halves; both come back trimmed.
750
+ */
751
+ export function splitDisplayText(text) {
752
+ const code = codeRanges(text);
753
+ let content = '';
754
+ const reasoning = [];
755
+ let cursor = 0;
756
+ while (cursor < text.length) {
757
+ THINK_OPEN.lastIndex = cursor;
758
+ let open = THINK_OPEN.exec(text);
759
+ while (open && inCode(code, open.index))
760
+ open = THINK_OPEN.exec(text);
761
+ if (!open) {
762
+ content += text.slice(cursor);
763
+ break;
764
+ }
765
+ content += text.slice(cursor, open.index);
766
+ const body = open.index + open[0].length;
767
+ const closer = thinkClose(open[0]);
768
+ closer.lastIndex = body;
769
+ const close = closer.exec(text);
770
+ reasoning.push(text.slice(body, close?.index));
771
+ if (!close)
772
+ break;
773
+ cursor = close.index + close[0].length;
774
+ }
775
+ return [stripToolCallXml(content).replace(/^\s+/, '').trimEnd(), joinReasoning(reasoning)];
776
+ }
777
+ /**
778
+ * Reasoning parts as one display string: tool-call XML removed, blank-line joined, each part once. A part that is
779
+ * whole paragraphs of another (a settled row's `reasoning` that already took in its `reasoning_content`) is dropped.
780
+ */
781
+ export function joinReasoning(parts) {
782
+ const clean = parts.map((part) => stripToolCallXml(part).trim()).filter(Boolean);
783
+ const within = (outer, inner) => `\n\n${outer}\n\n`.includes(`\n\n${inner}\n\n`);
784
+ return clean.filter((p, i) => !clean.some((q, j) => j !== i && (q === p ? j < i : within(q, p)))).join('\n\n');
785
+ }
786
+ /** A message's reasoning fields as one string: `reasoning_content`, `reasoning` (text or a list of text parts), `thinking`. */
787
+ export function reasoningFieldsText(m) {
788
+ const listed = Array.isArray(m.reasoning) ? m.reasoning.map((part) => (isDict(part) ? reasoningBlockText(part) : str(part))) : [str(m.reasoning)];
789
+ return joinReasoning([str(m.reasoning_content), ...listed, str(m.thinking)]);
790
+ }
791
+ /**
792
+ * The one display shape of an assistant row: `content` without inline thinking or tool-call XML (typed `thinking` /
793
+ * `reasoning` parts leave a list), and every piece of reasoning in one `reasoning` string. `reasoning_content` and
794
+ * `thinking` are not sent. Idempotent; other rows pass through. A copy: stored rows and model history are untouched.
795
+ */
796
+ export function normalizeAssistantDisplay(message) {
797
+ if (!isDict(message) || message.role !== 'assistant')
798
+ return message;
799
+ const m = { ...message };
800
+ delete m.reasoning_content;
801
+ delete m.thinking;
802
+ delete m.reasoning;
803
+ const parts = [reasoningFieldsText(message)];
804
+ if (typeof m.content === 'string') {
805
+ const [content, inline] = splitDisplayText(m.content);
806
+ // Only text something was taken out of is rewritten: plain prose keeps its exact whitespace (an indented code block).
807
+ if (content !== m.content.trim())
808
+ m.content = content;
809
+ parts.push(inline);
810
+ }
811
+ else if (Array.isArray(m.content)) {
812
+ m.content = m.content.flatMap((part) => {
813
+ if (!isDict(part))
814
+ return [part];
815
+ if (isReasoningBlock(part)) {
816
+ parts.push(reasoningBlockText(part));
817
+ return [];
818
+ }
819
+ if (typeof part.text !== 'string')
820
+ return [part];
821
+ const [text, inline] = splitDisplayText(part.text);
822
+ parts.push(inline);
823
+ return text === part.text.trim() ? [part] : text ? [{ ...part, text }] : [];
824
+ });
825
+ }
826
+ const reasoning = joinReasoning(parts);
827
+ return (reasoning ? { ...m, reasoning } : m);
549
828
  }
550
829
  /**
551
830
  * Python `merge_session_messages_append_only`, bounded to its load-bearing rules: state.db rows never delete a local
552
831
  * row; rows that replay the sidecar (same role, timestamp, and content) are skipped; rows at or before the sidecar's
553
832
  * newest timestamp are already represented locally; a truncation watermark hides rows the user cut (0 blocks every
554
- * replay). Rows past the sidecar tail (a conversation continued from the CLI) are appended in state.db order.
833
+ * replay): rows at or before it, and, for a truncation cut, rows after it until the sidecar advances past it (TAL-504).
834
+ * A compression watermark only covers the compressed rows. Rows past the sidecar tail (a conversation continued from the
835
+ * CLI) are appended in state.db order.
555
836
  * ponytail: the Python identity memo (api_content sidecars, message ids, workspace-prefix normalisation) is not ported;
556
837
  * add it if a mixed WebUI/CLI transcript shows duplicated turns.
557
838
  */
@@ -570,7 +851,7 @@ export function mergeSessionMessagesAppendOnly(sidecar, state, opts = {}) {
570
851
  }
571
852
  if (watermark === 0)
572
853
  return [];
573
- return state.filter((m) => { const t = ts(m); return t !== null && t > watermark; });
854
+ return state.filter((m) => { const t = ts(m); return t !== null && (opts.compressedWatermark === true ? t > watermark : t <= watermark); });
574
855
  }
575
856
  const seen = new Set(sidecar.map(key));
576
857
  let maxSidecar = null;
@@ -579,6 +860,8 @@ export function mergeSessionMessagesAppendOnly(sidecar, state, opts = {}) {
579
860
  if (t !== null && (maxSidecar === null || t > maxSidecar))
580
861
  maxSidecar = t;
581
862
  }
863
+ // Until a new turn lands in the sidecar, every state.db row past the watermark is the deleted suffix.
864
+ const advanced = !hasWatermark || opts.compressedWatermark === true || (maxSidecar !== null && maxSidecar > watermark);
582
865
  const merged = [...sidecar];
583
866
  for (const m of state) {
584
867
  const k = key(m);
@@ -587,7 +870,7 @@ export function mergeSessionMessagesAppendOnly(sidecar, state, opts = {}) {
587
870
  const t = ts(m);
588
871
  if (maxSidecar !== null && t !== null && t <= maxSidecar)
589
872
  continue;
590
- if (hasWatermark && t !== null && t <= watermark)
873
+ if (hasWatermark && t !== null && (t <= watermark || !advanced))
591
874
  continue;
592
875
  seen.add(k);
593
876
  merged.push(m);
@@ -628,6 +911,88 @@ export function attachmentObjects(items) {
628
911
  export function withAttachmentObjects(messages) {
629
912
  return messages.map((m) => (isDict(m) && Array.isArray(m.attachments) && m.attachments.some((a) => typeof a === 'string') ? { ...m, attachments: attachmentObjects(m.attachments) } : m));
630
913
  }
914
+ /** A scene's prose rows with `display_text` and `media` where `project` rewrites their text; the same array when none does. */
915
+ export function withSceneRowMedia(rows, project) {
916
+ if (!Array.isArray(rows))
917
+ return rows;
918
+ let changed = false;
919
+ const out = rows.map((row) => {
920
+ if (!isDict(row) || row.role !== 'prose' || typeof row.text !== 'string')
921
+ return row;
922
+ const projected = project(row.text);
923
+ if (!projected)
924
+ return row;
925
+ changed = true;
926
+ return { ...row, display_text: projected.text, media: projected.media };
927
+ });
928
+ return changed ? out : rows;
929
+ }
930
+ /**
931
+ * TAL-186: assistant rows with `_display_content` and `_media`, and their scenes with `final_answer_display` /
932
+ * `final_answer_media` and prose rows' `display_text` / `media`, wherever `project` rewrites media references in the
933
+ * text. Runs after scene hydration and before body excerpts, which are cut from the display text. Returns copies.
934
+ */
935
+ export function withDisplayMedia(messages, project) {
936
+ return messages.map((m) => {
937
+ if (!isDict(m) || m.role !== 'assistant')
938
+ return m;
939
+ let out = m;
940
+ const projected = project(messageText(m.content));
941
+ if (projected)
942
+ out = { ...out, _display_content: projected.text, _media: projected.media };
943
+ const scene = m._anchor_activity_scene;
944
+ if (isDict(scene)) {
945
+ const final = typeof scene.final_answer === 'string' ? project(scene.final_answer) : null;
946
+ const rows = withSceneRowMedia(scene.activity_rows, project);
947
+ if (final || rows !== scene.activity_rows) {
948
+ out = { ...out, _anchor_activity_scene: { ...scene, activity_rows: rows, ...(final ? { final_answer_display: final.text, final_answer_media: final.media } : {}) } };
949
+ }
950
+ }
951
+ return out;
952
+ });
953
+ }
954
+ /** TAL-456: a settled user or assistant body longer than this ships a collapsed excerpt for clients to render. */
955
+ export const BODY_EXCERPT_LIMIT = 3000;
956
+ const graphemes = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
957
+ /** The first `BODY_EXCERPT_LIMIT` characters, never splitting a grapheme, cut back to a line break (else a space) in the second half. */
958
+ function bodyExcerpt(text) {
959
+ let end = 0;
960
+ for (const { segment } of graphemes.segment(text.slice(0, BODY_EXCERPT_LIMIT + 16))) {
961
+ if (end + segment.length > BODY_EXCERPT_LIMIT)
962
+ break;
963
+ end += segment.length;
964
+ }
965
+ const head = text.slice(0, end);
966
+ const floor = BODY_EXCERPT_LIMIT / 2;
967
+ const lineBreak = head.lastIndexOf('\n');
968
+ const space = head.lastIndexOf(' ');
969
+ const cut = lineBreak >= floor ? lineBreak : space >= floor ? space : end;
970
+ return head.slice(0, cut).trimEnd();
971
+ }
972
+ /**
973
+ * TAL-456: stamps `_display_excerpt` and `_display_truncated` on settled user and assistant rows whose display text is longer than
974
+ * `BODY_EXCERPT_LIMIT`, and `final_answer_excerpt` on a settled scene whose final answer is, so clients render a bounded
975
+ * excerpt instead of laying out the whole body. Full text stays for copy and edit; the running turn's rows are left alone.
976
+ * Runs after scene hydration. Returns copies; stored rows are untouched.
977
+ */
978
+ export function withBodyExcerpts(messages, activeTurnId) {
979
+ return messages.map((m) => {
980
+ if (!isDict(m) || (m.role !== 'user' && m.role !== 'assistant'))
981
+ return m;
982
+ if (activeTurnId && m._turn_id === activeTurnId)
983
+ return m;
984
+ let out = m;
985
+ const text = typeof m._display_content === 'string' ? m._display_content : messageText(m.content);
986
+ if (text.length > BODY_EXCERPT_LIMIT)
987
+ out = { ...out, _display_excerpt: bodyExcerpt(text), _display_truncated: true };
988
+ const scene = m._anchor_activity_scene;
989
+ const finalAnswer = isDict(scene) ? (typeof scene.final_answer_display === 'string' ? scene.final_answer_display : scene.final_answer) : null;
990
+ if (isDict(scene) && typeof finalAnswer === 'string' && finalAnswer.length > BODY_EXCERPT_LIMIT) {
991
+ out = { ...out, _anchor_activity_scene: { ...scene, final_answer_excerpt: bodyExcerpt(finalAnswer) } };
992
+ }
993
+ return out;
994
+ });
995
+ }
631
996
  /** The running turn's prompt as eager save checkpoints it (Python `_checkpoint_user_message_for_eager_session_save`). */
632
997
  export function pendingUserRow(msg, attachments, startedAt, source, turnId) {
633
998
  const user = { role: 'user', content: msg, _turn_id: turnId };