@maudecode/talaria-web 1.17.2 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (387) hide show
  1. package/_release.json +8 -8
  2. package/dist/api/auth-raw.d.ts +1 -1
  3. package/dist/api/auth-raw.js +4 -4
  4. package/dist/api/auth-raw.js.map +1 -1
  5. package/dist/api/automation-raw.d.ts +6 -0
  6. package/dist/api/automation-raw.js +53 -6
  7. package/dist/api/automation-raw.js.map +1 -1
  8. package/dist/api/automation-router.d.ts +26 -1
  9. package/dist/api/automation-router.js +16 -2
  10. package/dist/api/automation-router.js.map +1 -1
  11. package/dist/api/chat-router.d.ts +649 -15
  12. package/dist/api/chat-router.js +52 -50
  13. package/dist/api/chat-router.js.map +1 -1
  14. package/dist/api/git-router.d.ts +35 -1
  15. package/dist/api/git-router.js +18 -19
  16. package/dist/api/git-router.js.map +1 -1
  17. package/dist/api/raw-routes.d.ts +8 -0
  18. package/dist/api/raw-routes.js +247 -36
  19. package/dist/api/raw-routes.js.map +1 -1
  20. package/dist/api/router.d.ts +10 -0
  21. package/dist/api/router.js +10 -8
  22. package/dist/api/router.js.map +1 -1
  23. package/dist/api/sessions-router.d.ts +1492 -115
  24. package/dist/api/sessions-router.js +134 -8
  25. package/dist/api/sessions-router.js.map +1 -1
  26. package/dist/api/settings-router.d.ts +31 -0
  27. package/dist/api/settings-router.js +8 -3
  28. package/dist/api/settings-router.js.map +1 -1
  29. package/dist/api/sse-routes.d.ts +5 -0
  30. package/dist/api/sse-routes.js +50 -3
  31. package/dist/api/sse-routes.js.map +1 -1
  32. package/dist/api/tools-raw.js +6 -23
  33. package/dist/api/tools-raw.js.map +1 -1
  34. package/dist/api/tools-router.d.ts +356 -15
  35. package/dist/api/tools-router.js +148 -19
  36. package/dist/api/tools-router.js.map +1 -1
  37. package/dist/app.js +35 -15
  38. package/dist/app.js.map +1 -1
  39. package/dist/auth/gate.js +5 -2
  40. package/dist/auth/gate.js.map +1 -1
  41. package/dist/auth/oidc.d.ts +5 -2
  42. package/dist/auth/oidc.js +8 -7
  43. package/dist/auth/oidc.js.map +1 -1
  44. package/dist/bin/talaria-web.js +1 -1
  45. package/dist/bin/talaria-web.js.map +1 -1
  46. package/dist/cli/dotenv.js +1 -0
  47. package/dist/cli/dotenv.js.map +1 -1
  48. package/dist/config/agent-config.js +3 -2
  49. package/dist/config/agent-config.js.map +1 -1
  50. package/dist/config.d.ts +2 -0
  51. package/dist/config.js +5 -1
  52. package/dist/config.js.map +1 -1
  53. package/dist/http/context.d.ts +17 -3
  54. package/dist/http/context.js +31 -4
  55. package/dist/http/context.js.map +1 -1
  56. package/dist/http/csp.d.ts +2 -1
  57. package/dist/http/csp.js +3 -2
  58. package/dist/http/csp.js.map +1 -1
  59. package/dist/profiles/profiles.d.ts +10 -0
  60. package/dist/profiles/profiles.js +40 -2
  61. package/dist/profiles/profiles.js.map +1 -1
  62. package/dist/providers/catalog.d.ts +6 -2
  63. package/dist/providers/catalog.js +30 -11
  64. package/dist/providers/catalog.js.map +1 -1
  65. package/dist/raster-image.d.ts +7 -0
  66. package/dist/raster-image.js +267 -0
  67. package/dist/raster-image.js.map +1 -0
  68. package/dist/redact.js +327 -40
  69. package/dist/redact.js.map +1 -1
  70. package/dist/runtime.js +89 -23
  71. package/dist/runtime.js.map +1 -1
  72. package/dist/server.js +5 -0
  73. package/dist/server.js.map +1 -1
  74. package/dist/sessions/background-tasks.d.ts +2 -9
  75. package/dist/sessions/background-tasks.js +2 -12
  76. package/dist/sessions/background-tasks.js.map +1 -1
  77. package/dist/sessions/cli-sessions.d.ts +15 -4
  78. package/dist/sessions/cli-sessions.js +120 -29
  79. package/dist/sessions/cli-sessions.js.map +1 -1
  80. package/dist/sessions/completions.d.ts +48 -8
  81. package/dist/sessions/completions.js +222 -26
  82. package/dist/sessions/completions.js.map +1 -1
  83. package/dist/sessions/export.d.ts +5 -0
  84. package/dist/sessions/export.js +30 -0
  85. package/dist/sessions/export.js.map +1 -1
  86. package/dist/sessions/gateway-watcher.d.ts +7 -3
  87. package/dist/sessions/gateway-watcher.js +31 -19
  88. package/dist/sessions/gateway-watcher.js.map +1 -1
  89. package/dist/sessions/handoff.d.ts +32 -0
  90. package/dist/sessions/handoff.js +114 -0
  91. package/dist/sessions/handoff.js.map +1 -0
  92. package/dist/sessions/list.d.ts +7 -1
  93. package/dist/sessions/list.js +13 -5
  94. package/dist/sessions/list.js.map +1 -1
  95. package/dist/sessions/merge.d.ts +2 -4
  96. package/dist/sessions/merge.js +8 -15
  97. package/dist/sessions/merge.js.map +1 -1
  98. package/dist/sessions/recovery.d.ts +22 -0
  99. package/dist/sessions/recovery.js +506 -0
  100. package/dist/sessions/recovery.js.map +1 -0
  101. package/dist/sessions/relay.d.ts +21 -2
  102. package/dist/sessions/relay.js +156 -11
  103. package/dist/sessions/relay.js.map +1 -1
  104. package/dist/sessions/service.d.ts +108 -6
  105. package/dist/sessions/service.js +403 -29
  106. package/dist/sessions/service.js.map +1 -1
  107. package/dist/sessions/session.d.ts +6 -0
  108. package/dist/sessions/session.js +40 -2
  109. package/dist/sessions/session.js.map +1 -1
  110. package/dist/sessions/state-db-worker.d.ts +1 -0
  111. package/dist/sessions/state-db-worker.js +33 -0
  112. package/dist/sessions/state-db-worker.js.map +1 -0
  113. package/dist/sessions/state-db.d.ts +61 -0
  114. package/dist/sessions/state-db.js +291 -0
  115. package/dist/sessions/state-db.js.map +1 -1
  116. package/dist/sessions/store.d.ts +7 -0
  117. package/dist/sessions/store.js +31 -22
  118. package/dist/sessions/store.js.map +1 -1
  119. package/dist/sessions/titles.d.ts +2 -0
  120. package/dist/sessions/titles.js +4 -0
  121. package/dist/sessions/titles.js.map +1 -1
  122. package/dist/sessions/tool-display.d.ts +3 -3
  123. package/dist/sessions/tool-display.js +11 -37
  124. package/dist/sessions/tool-display.js.map +1 -1
  125. package/dist/sessions/turn-context.d.ts +1 -1
  126. package/dist/sessions/turn-context.js +11 -7
  127. package/dist/sessions/turn-context.js.map +1 -1
  128. package/dist/sessions/turn.d.ts +37 -2
  129. package/dist/sessions/turn.js +182 -49
  130. package/dist/sessions/turn.js.map +1 -1
  131. package/dist/sessions/wakeup-pause.d.ts +59 -0
  132. package/dist/sessions/wakeup-pause.js +181 -0
  133. package/dist/sessions/wakeup-pause.js.map +1 -0
  134. package/dist/settings.js +5 -7
  135. package/dist/settings.js.map +1 -1
  136. package/dist/sidecar/fake.d.ts +2 -2
  137. package/dist/sidecar/fake.js.map +1 -1
  138. package/dist/startup.d.ts +13 -5
  139. package/dist/startup.js +48 -0
  140. package/dist/startup.js.map +1 -1
  141. package/dist/test/ts-worker-hooks.d.ts +1 -0
  142. package/dist/test/ts-worker-hooks.js +24 -0
  143. package/dist/test/ts-worker-hooks.js.map +1 -0
  144. package/dist/text/diff.d.ts +9 -14
  145. package/dist/text/diff.js +74 -108
  146. package/dist/text/diff.js.map +1 -1
  147. package/dist/tools/crons.js +45 -8
  148. package/dist/tools/crons.js.map +1 -1
  149. package/dist/tools/dashboard-plugins.d.ts +53 -0
  150. package/dist/tools/dashboard-plugins.js +188 -0
  151. package/dist/tools/dashboard-plugins.js.map +1 -0
  152. package/dist/tools/extensions.d.ts +13 -1
  153. package/dist/tools/extensions.js +132 -60
  154. package/dist/tools/extensions.js.map +1 -1
  155. package/dist/tools/health.d.ts +32 -0
  156. package/dist/tools/health.js +111 -19
  157. package/dist/tools/health.js.map +1 -1
  158. package/dist/tools/mcp.d.ts +13 -0
  159. package/dist/tools/mcp.js +88 -0
  160. package/dist/tools/mcp.js.map +1 -1
  161. package/dist/tools/project-os.d.ts +11 -0
  162. package/dist/tools/project-os.js +267 -0
  163. package/dist/tools/project-os.js.map +1 -0
  164. package/dist/tools/skills.d.ts +5 -1
  165. package/dist/tools/skills.js +5 -3
  166. package/dist/tools/skills.js.map +1 -1
  167. package/dist/tools/updates.d.ts +27 -9
  168. package/dist/tools/updates.js +163 -51
  169. package/dist/tools/updates.js.map +1 -1
  170. package/dist/tools/wiki.d.ts +68 -0
  171. package/dist/tools/wiki.js +413 -0
  172. package/dist/tools/wiki.js.map +1 -0
  173. package/dist/workspace/escape.d.ts +61 -0
  174. package/dist/workspace/escape.js +149 -0
  175. package/dist/workspace/escape.js.map +1 -0
  176. package/dist/workspace/extract.d.ts +22 -0
  177. package/dist/workspace/extract.js +308 -0
  178. package/dist/workspace/extract.js.map +1 -0
  179. package/dist/workspace/fs.d.ts +12 -0
  180. package/dist/workspace/fs.js +92 -23
  181. package/dist/workspace/fs.js.map +1 -1
  182. package/dist/workspace/git.d.ts +18 -0
  183. package/dist/workspace/git.js +38 -25
  184. package/dist/workspace/git.js.map +1 -1
  185. package/dist/workspace/media.d.ts +4 -4
  186. package/dist/workspace/media.js +16 -45
  187. package/dist/workspace/media.js.map +1 -1
  188. package/dist/workspace/rollback.d.ts +34 -20
  189. package/dist/workspace/rollback.js +171 -265
  190. package/dist/workspace/rollback.js.map +1 -1
  191. package/dist/workspace/unzip.js +4 -1
  192. package/dist/workspace/unzip.js.map +1 -1
  193. package/dist/workspace/upload.d.ts +7 -4
  194. package/dist/workspace/upload.js +5 -2
  195. package/dist/workspace/upload.js.map +1 -1
  196. package/dist/workspace/worktrees.d.ts +2 -1
  197. package/dist/workspace/worktrees.js +14 -15
  198. package/dist/workspace/worktrees.js.map +1 -1
  199. package/package.json +4 -2
  200. package/sidecar/agent_dependency.json +4 -4
  201. package/sidecar/scripts/replay_sidecar.py +24 -0
  202. package/sidecar/talaria_sidecar/__init__.py +1 -1
  203. package/sidecar/talaria_sidecar/home.py +13 -2
  204. package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
  205. package/sidecar/talaria_sidecar/methods/aux.py +39 -5
  206. package/sidecar/talaria_sidecar/methods/chat.py +9 -5
  207. package/sidecar/talaria_sidecar/methods/checkpoints.py +89 -0
  208. package/sidecar/talaria_sidecar/methods/commands.py +81 -0
  209. package/sidecar/talaria_sidecar/methods/cron.py +29 -2
  210. package/sidecar/talaria_sidecar/methods/gateway.py +32 -15
  211. package/sidecar/talaria_sidecar/methods/kanban.py +28 -7
  212. package/sidecar/talaria_sidecar/methods/mcp.py +1 -1
  213. package/sidecar/talaria_sidecar/methods/process.py +58 -4
  214. package/sidecar/talaria_sidecar/methods/profiles.py +77 -7
  215. package/sidecar/talaria_sidecar/methods/providers.py +27 -8
  216. package/sidecar/talaria_sidecar/methods/state_db.py +39 -5
  217. package/sidecar/talaria_sidecar/runtime.py +17 -1
  218. package/static/dist/FILES.txt +127 -126
  219. package/static/dist/assets/AppShell-g3bkgnvt.js +1 -0
  220. package/static/dist/assets/ChatPage-oo7bdan6.js +25 -0
  221. package/static/dist/assets/Dialog-g355qxhp.js +1 -0
  222. package/static/dist/assets/ExtensionRoute-i2y9fvjm.js +1 -0
  223. package/static/dist/assets/HubRoute-lmkrbw47.js +2 -0
  224. package/static/dist/assets/{Markdown-mdwlvj3w.js → Markdown-j4kut4j2.js} +114 -114
  225. package/static/dist/assets/{RightPanel-ftvrjlcp.js → RightPanel-ohlsdzfl.js} +1 -1
  226. package/static/dist/assets/Select-kddq75qc.js +1 -0
  227. package/static/dist/assets/SessionListPanel-lu3oy0hw.js +1 -0
  228. package/static/dist/assets/{SettingsLayout-jonjefmj.js → SettingsLayout-o9bv4mgb.js} +1 -1
  229. package/static/dist/assets/{States-nmejrwrm.js → States-eq6fe29m.js} +1 -1
  230. package/static/dist/assets/Toaster-pc247u9f.js +1 -0
  231. package/static/dist/assets/{_app-gdidzd94.js → _app-f8n1i0m1.js} +1 -1
  232. package/static/dist/assets/{_app.ext._extensionId-opyh9y0v.js → _app.ext._extensionId-gfbzpoou.js} +1 -1
  233. package/static/dist/assets/_app.index-bzzv80hk.js +1 -0
  234. package/static/dist/assets/_app.insights-dzixbryi.js +1 -0
  235. package/static/dist/assets/_app.kanban-c6hep2us.js +1 -0
  236. package/static/dist/assets/_app.logs-i69qds98.js +1 -0
  237. package/static/dist/assets/_app.memory-kl4vf0gd.js +1 -0
  238. package/static/dist/assets/_app.profiles-b8zinmyp.js +1 -0
  239. package/static/dist/assets/{_app.session._sessionId-bfd4h3id.js → _app.session._sessionId-fn1bhde6.js} +1 -1
  240. package/static/dist/assets/_app.settings-cg8plwmf.js +1 -0
  241. package/static/dist/assets/_app.settings._section-bkwbi9zn.js +3 -0
  242. package/static/dist/assets/_app.skills-cs47sbvs.js +1 -0
  243. package/static/dist/assets/_app.tasks-dwvk64tc.js +1 -0
  244. package/static/dist/assets/_app.todos-c8xjm8p3.js +1 -0
  245. package/static/dist/assets/_app.workspaces-ehvd1gds.js +1 -0
  246. package/static/dist/assets/{abnfDiagram-VCTEODGH-b2x1lqot.js → abnfDiagram-VCTEODGH-c8kdixke.js} +1 -1
  247. package/static/dist/assets/architecture-7GRP2DOG-6crvnylg.js +1 -0
  248. package/static/dist/assets/{architectureDiagram-5GKGNRK7-h38o5l7b.js → architectureDiagram-5GKGNRK7-cku06x1p.js} +1 -1
  249. package/static/dist/assets/{back-bemaer09.js → back-h7aun7ew.js} +1 -1
  250. package/static/dist/assets/{blockDiagram-I7D4REHJ-bqquxv2u.js → blockDiagram-I7D4REHJ-jzthp1wa.js} +1 -1
  251. package/static/dist/assets/{c4Diagram-7LVT6UL2-f3fb8w6z.js → c4Diagram-7LVT6UL2-mwr67mt8.js} +1 -1
  252. package/static/dist/assets/{cancel-drd0g6d9.js → cancel-fhi0vcnu.js} +1 -1
  253. package/static/dist/assets/channel-b2zo73z1.js +1 -0
  254. package/static/dist/assets/{chunk-4HAMMTFA-bzfyyzp3.js → chunk-4HAMMTFA-gpq1y228.js} +1 -1
  255. package/static/dist/assets/{chunk-75Z2AOVW-ly99rfx5.js → chunk-75Z2AOVW-ktje58c4.js} +1 -1
  256. package/static/dist/assets/{chunk-DU6HZSFF-bg6ecfqf.js → chunk-DU6HZSFF-ofajdixh.js} +3 -3
  257. package/static/dist/assets/{chunk-F27PBJKO-e8k7mmqw.js → chunk-F27PBJKO-cmev85ti.js} +1 -1
  258. package/static/dist/assets/{chunk-GMAD6QVW-cmalnoaj.js → chunk-GMAD6QVW-htjgt22y.js} +1 -1
  259. package/static/dist/assets/{chunk-GVQU2GXP-gmif5o01.js → chunk-GVQU2GXP-qndvoxl7.js} +1 -1
  260. package/static/dist/assets/{chunk-IMKFNOWR-f1nwwh6u.js → chunk-IMKFNOWR-e5bkd5q6.js} +1 -1
  261. package/static/dist/assets/{chunk-L3NEJ4N5-oktfh5v7.js → chunk-L3NEJ4N5-mj1155r6.js} +1 -1
  262. package/static/dist/assets/{chunk-OSK3NFVY-b1sdx96z.js → chunk-OSK3NFVY-e7gkikcw.js} +1 -1
  263. package/static/dist/assets/{chunk-P2QGCYS3-fhu4nzxt.js → chunk-P2QGCYS3-f7t54xfm.js} +1 -1
  264. package/static/dist/assets/{chunk-POPQ4Y6H-em31rnef.js → chunk-POPQ4Y6H-i927v9oa.js} +1 -1
  265. package/static/dist/assets/{chunk-PWAF6VOD-bxhhyftw.js → chunk-PWAF6VOD-m84lmnyt.js} +1 -1
  266. package/static/dist/assets/{chunk-SHT3W25Y-fmrvwcav.js → chunk-SHT3W25Y-mi0tlcu9.js} +1 -1
  267. package/static/dist/assets/{chunk-SVP7TREG-lymukl2j.js → chunk-SVP7TREG-dnau702j.js} +1 -1
  268. package/static/dist/assets/{chunk-TICWLB2K-lmza6k23.js → chunk-TICWLB2K-edem1gkg.js} +1 -1
  269. package/static/dist/assets/classDiagram-ZZMXUADV-oe99st8x.js +1 -0
  270. package/static/dist/assets/classDiagram-v2-VYDZK3BY-oe99st8x.js +1 -0
  271. package/static/dist/assets/{copied-ima3pysb.js → copied-hcplv46p.js} +1 -1
  272. package/static/dist/assets/{copy-fw5b1pc6.js → copy-magtofyp.js} +1 -1
  273. package/static/dist/assets/{cynefin-OW5HDTMX-czlhbyhs.js → cynefin-OW5HDTMX-siqlulkl.js} +1 -1
  274. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-gq7mvswb.js → cynefinDiagram-5FMLGOSQ-i648tah9.js} +1 -1
  275. package/static/dist/assets/{dagre-GXQ25YYZ-cqdbf7dr.js → dagre-GXQ25YYZ-mwn6uc17.js} +1 -1
  276. package/static/dist/assets/{diagram-S7CK7UJ4-o6arxa58.js → diagram-S7CK7UJ4-l8abxaes.js} +1 -1
  277. package/static/dist/assets/{diagram-UQ7AKVKN-nhnd68tz.js → diagram-UQ7AKVKN-mekq7zgq.js} +1 -1
  278. package/static/dist/assets/{diagram-VSXAHHWV-dk2sclzn.js → diagram-VSXAHHWV-fnky6lvc.js} +1 -1
  279. package/static/dist/assets/{diagram-VX7I27RA-n3k5nyx3.js → diagram-VX7I27RA-xe6r5qfw.js} +1 -1
  280. package/static/dist/assets/{diagram-Z3DM3KII-m6q9cwdh.js → diagram-Z3DM3KII-nq07dg7k.js} +1 -1
  281. package/static/dist/assets/{ebnfDiagram-PWID7BFC-lsa5641p.js → ebnfDiagram-PWID7BFC-c62ipm3g.js} +1 -1
  282. package/static/dist/assets/endpoints-klbxod4t.js +64 -0
  283. package/static/dist/assets/{erDiagram-RLTQ6QDP-fo2ckbe6.js → erDiagram-RLTQ6QDP-h39kmnzy.js} +1 -1
  284. package/static/dist/assets/eventmodeling-NTZA5JFV-obfede4u.js +1 -0
  285. package/static/dist/assets/flowDiagram-HODETNUW-kdpsp1je.js +1 -0
  286. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-nzqz6x9g.js → ganttDiagram-EL5Y4UJY-ngbsyp37.js} +1 -1
  287. package/static/dist/assets/{gitGraph-4MIJSDKK-gukvcxe6.js → gitGraph-4MIJSDKK-fr2i7caa.js} +1 -1
  288. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-lqhdp8f0.js → gitGraphDiagram-WWUBYQGX-eravdti4.js} +1 -1
  289. package/static/dist/assets/{highlighted-body-KPVGNVTW-igw6cp39.js → highlighted-body-KPVGNVTW-jwpop9p8.js} +1 -1
  290. package/static/dist/assets/host-i828xuo7.js +1 -0
  291. package/static/dist/assets/index-eh8zilnv.css +2 -0
  292. package/static/dist/assets/{index-cxq58xb1.js → index-r648f4o1.js} +5 -5
  293. package/static/dist/assets/{info-A6RAGUB7-gvu7a93l.js → info-A6RAGUB7-h11x0dxo.js} +1 -1
  294. package/static/dist/assets/{infoDiagram-27XIBGKW-m8t8g6w1.js → infoDiagram-27XIBGKW-dfh47dw9.js} +1 -1
  295. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-l07vkbgj.js → ishikawaDiagram-5VMMS53U-i6ypq351.js} +1 -1
  296. package/static/dist/assets/{journeyDiagram-3NMN7TZE-hybkgj8l.js → journeyDiagram-3NMN7TZE-lduf1z95.js} +1 -1
  297. package/static/dist/assets/{kanban-definition-UXKFOSKX-by13uvtn.js → kanban-definition-UXKFOSKX-e18bu4pg.js} +1 -1
  298. package/static/dist/assets/{lazyRouteComponent-af0lvgjx.js → lazyRouteComponent-e1y4t2i9.js} +1 -1
  299. package/static/dist/assets/{line-osxq6fq7.js → line-meizqsvn.js} +1 -1
  300. package/static/dist/assets/{link-jyxicdhg.js → link-oot2yn73.js} +1 -1
  301. package/static/dist/assets/login-gu28l9ou.js +1 -0
  302. package/static/dist/assets/mermaid-HWGCJPDP-mtwrj8fn.js +1 -0
  303. package/static/dist/assets/{mermaid-parser.core-i91oxmou.js → mermaid-parser.core-ntne45i9.js} +3 -3
  304. package/static/dist/assets/{mindmap-definition-YA3MSWOX-m82mx8ww.js → mindmap-definition-YA3MSWOX-27b26eok.js} +1 -1
  305. package/static/dist/assets/onboarding-lkphzu1s.js +1 -0
  306. package/static/dist/assets/{onboarding_model_label-dp7xffoh.js → onboarding_model_label-ftpjdwqk.js} +1 -1
  307. package/static/dist/assets/{packet-AYTQ26CC-nbtgge2o.js → packet-AYTQ26CC-l6jdka8p.js} +1 -1
  308. package/static/dist/assets/{pegDiagram-XKGWAZYB-f1zxzga1.js → pegDiagram-XKGWAZYB-g1er3bxj.js} +1 -1
  309. package/static/dist/assets/{pie-WAS4IAKB-of8vuhxs.js → pie-WAS4IAKB-i0ylcrt9.js} +1 -1
  310. package/static/dist/assets/{pieDiagram-E7YTZNPT-o7y8ftio.js → pieDiagram-E7YTZNPT-fbz1e55z.js} +1 -1
  311. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-iqiwia1t.js → quadrantDiagram-AXDQQJYC-hhue7d8o.js} +1 -1
  312. package/static/dist/assets/{radar-RG4KPBEZ-delnsy2v.js → radar-RG4KPBEZ-f9b70aa4.js} +1 -1
  313. package/static/dist/assets/{railroad-74A4TZTK-nspnyq9u.js → railroad-74A4TZTK-lgsuoeda.js} +1 -1
  314. package/static/dist/assets/railroad-abnf-HS5TGJTU-nf9d6pdx.js +1 -0
  315. package/static/dist/assets/railroad-ebnf-LZEXJU2U-f7ummkt5.js +1 -0
  316. package/static/dist/assets/railroad-peg-WCYAUIDC-oczq5tqs.js +1 -0
  317. package/static/dist/assets/{railroadDiagram-O6MQD6OU-z41tqx5z.js → railroadDiagram-O6MQD6OU-eqpy9fnz.js} +1 -1
  318. package/static/dist/assets/{refresh-b4uams1i.js → refresh-abtu93ke.js} +1 -1
  319. package/static/dist/assets/{refresh-cw-nt1dtsx4.js → refresh-cw-hlwb02qv.js} +1 -1
  320. package/static/dist/assets/{requirementDiagram-BXWQKSXE-bdvif194.js → requirementDiagram-BXWQKSXE-ogf6puhi.js} +1 -1
  321. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-h73e0rol.js → sankeyDiagram-P5KCCOFB-fqb8xcjf.js} +1 -1
  322. package/static/dist/assets/{saved-kg52csy7.js → saved-girnabkf.js} +1 -1
  323. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-iv95mb1z.js → sequenceDiagram-WJ2MYXX4-dlcz6qjz.js} +1 -1
  324. package/static/dist/assets/{settings_section_extensions_title-ej0iapxe.js → settings_section_extensions_title-h14cwk6f.js} +1 -1
  325. package/static/dist/assets/share._token-kl0r7ido.js +2 -0
  326. package/static/dist/assets/{sliders-horizontal-fj18it47.js → sliders-horizontal-n1zm34qq.js} +1 -1
  327. package/static/dist/assets/sse-iwku0sjo.js +1 -0
  328. package/static/dist/assets/{stateDiagram-D77RDMKH-k417ixmf.js → stateDiagram-D77RDMKH-fyoznpcs.js} +1 -1
  329. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-ixhx8r46.js +1 -0
  330. package/static/dist/assets/{swimlanes-42K2YHIH-esola70w.js → swimlanes-42K2YHIH-oefldhfy.js} +1 -1
  331. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-h9ersk2e.js +8 -0
  332. package/static/dist/assets/{timeline-definition-24CTP7MA-getrz2y8.js → timeline-definition-24CTP7MA-b1vl2zil.js} +1 -1
  333. package/static/dist/assets/todoStore-jjr5yr78.js +1 -0
  334. package/static/dist/assets/{treeView-Q6P3EWNA-hc7ap1q7.js → treeView-Q6P3EWNA-f7hcci5o.js} +1 -1
  335. package/static/dist/assets/{treemap-WGGIJYW6-b7k1syy5.js → treemap-WGGIJYW6-nl85071a.js} +1 -1
  336. package/static/dist/assets/{tts-lxdxnmjd.js → units-kgxzxfhi.js} +1 -1
  337. package/static/dist/assets/{untitled-ovpfthg4.js → untitled-cikfjntn.js} +1 -1
  338. package/static/dist/assets/{useForm-bcblv1rx.js → useForm-kqoqg0k9.js} +1 -1
  339. package/static/dist/assets/useLocale-o59tbiea.js +1 -0
  340. package/static/dist/assets/{useParams-lhg566ew.js → useParams-b4dq6n4q.js} +1 -1
  341. package/static/dist/assets/{useSearch-lbrh6ejn.js → useSearch-ipfmv3he.js} +1 -1
  342. package/static/dist/assets/{vennDiagram-4TSXK5OY-n6pcy5qb.js → vennDiagram-4TSXK5OY-h5hzbk0n.js} +1 -1
  343. package/static/dist/assets/{wardley-WFR3VGLG-lpa18vz1.js → wardley-WFR3VGLG-jftvpm3e.js} +1 -1
  344. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-kpclwwg7.js → wardleyDiagram-VM6X3IG4-hedh85ge.js} +1 -1
  345. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-paa2n8y0.js → xychartDiagram-S5SC5T6Z-e49523ab.js} +1 -1
  346. package/static/dist/index.html +1 -1
  347. package/static/dist/sw.js +1 -1
  348. package/static/dist/assets/AppShell-fb2td9zi.js +0 -1
  349. package/static/dist/assets/ChatPage-cj96kiy9.js +0 -25
  350. package/static/dist/assets/Dialog-kxcg7ard.js +0 -1
  351. package/static/dist/assets/ExtensionRoute-jf7h0754.js +0 -1
  352. package/static/dist/assets/HubRoute-gmanpd5y.js +0 -2
  353. package/static/dist/assets/Select-bilaypej.js +0 -1
  354. package/static/dist/assets/SessionListPanel-og8n36qs.js +0 -1
  355. package/static/dist/assets/Toaster-nnl8zkt9.js +0 -1
  356. package/static/dist/assets/_app.index-hbarzbjx.js +0 -1
  357. package/static/dist/assets/_app.insights-luywlarz.js +0 -1
  358. package/static/dist/assets/_app.kanban-kincnbr8.js +0 -1
  359. package/static/dist/assets/_app.logs-oi2gr3gs.js +0 -1
  360. package/static/dist/assets/_app.memory-b6jfivt6.js +0 -1
  361. package/static/dist/assets/_app.profiles-lpvixmqp.js +0 -1
  362. package/static/dist/assets/_app.settings-vowx3iq0.js +0 -1
  363. package/static/dist/assets/_app.settings._section-cnntg1tu.js +0 -3
  364. package/static/dist/assets/_app.skills-fb57lpau.js +0 -1
  365. package/static/dist/assets/_app.tasks-eszpx1q7.js +0 -2
  366. package/static/dist/assets/_app.todos-nr05ac6w.js +0 -1
  367. package/static/dist/assets/_app.workspaces-d2luomu6.js +0 -1
  368. package/static/dist/assets/architecture-7GRP2DOG-hd0o7bde.js +0 -1
  369. package/static/dist/assets/channel-cpdgf867.js +0 -1
  370. package/static/dist/assets/classDiagram-ZZMXUADV-ko09sguk.js +0 -1
  371. package/static/dist/assets/classDiagram-v2-VYDZK3BY-ko09sguk.js +0 -1
  372. package/static/dist/assets/endpoints-d33siokx.js +0 -64
  373. package/static/dist/assets/eventmodeling-NTZA5JFV-emctlo64.js +0 -1
  374. package/static/dist/assets/flowDiagram-HODETNUW-bfi3moqa.js +0 -1
  375. package/static/dist/assets/index-hgtx08n5.css +0 -2
  376. package/static/dist/assets/login-ec21t39x.js +0 -1
  377. package/static/dist/assets/mermaid-HWGCJPDP-gfl8z3ep.js +0 -1
  378. package/static/dist/assets/onboarding-btnltvyz.js +0 -1
  379. package/static/dist/assets/railroad-abnf-HS5TGJTU-nst1qxyn.js +0 -1
  380. package/static/dist/assets/railroad-ebnf-LZEXJU2U-ci37x8qy.js +0 -1
  381. package/static/dist/assets/railroad-peg-WCYAUIDC-aimkk07z.js +0 -1
  382. package/static/dist/assets/share._token-f97e94r0.js +0 -2
  383. package/static/dist/assets/sse-fwpqtzbg.js +0 -1
  384. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hwn4apct.js +0 -1
  385. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-d1h97oyg.js +0 -8
  386. package/static/dist/assets/todoStore-eginf9h4.js +0 -1
  387. package/static/dist/assets/useLocale-fi5jb8ma.js +0 -1
@@ -15,7 +15,7 @@ import { StreamRegistry, SessionChannels } from './streams.js';
15
15
  import { ChatUsageSchema } from '@maudecode/talaria-web-contracts';
16
16
  import { PendingPrompts, clarifyReply } from './pending.js';
17
17
  import { RunJournal } from './journal.js';
18
- import { CONTEXT_USAGE_FIELDS, Session, contextUsage, titleFrom } from './session.js';
18
+ import { COMPRESSION_RECOVERY_ACTION_START_FOCUSED, COMPRESSION_RECOVERY_TERMINAL_STATE, CONTEXT_USAGE_FIELDS, Session, contextUsage, titleFrom } from './session.js';
19
19
  import { anchorMessageKey, compressionReference, markerSummary, visibleMessagesForAnchor } from './compress.js';
20
20
  import { buildActiveTurnToken, completedToolIndex, publicToolFrame, redactNestedMessageContainers, redactSessionData, redactString, withToolId } from '../redact.js';
21
21
  import { dict } from '../config/agent-config.js';
@@ -26,12 +26,14 @@ import { withSessionWireFlags } from './list.js';
26
26
  import { hydrateAnchorActivityScenes, turnTerminalState, withTurnIds } from './anchor.js';
27
27
  import { persistentStateChanges, persistentStateSnapshot } from './state-saved.js';
28
28
  import { maxIterationsFromConfig, maxTokensFromConfig, processWakeupMaxIterations, reasoningConfigFromConfig, webuiEphemeralSystemPrompt, workspaceSystemMessage } from './turn-context.js';
29
- import { agentSteerText, assistantReplyAddedAfterCurrentTurn, attachedFilesPrompt, buildPartialMessage, dedupeContext, checkpointTurnStart, extractToolCallsFromMessages, hasNativeImages, injectMaxIterationSummaryFallback, isDict, mergeDisplayMessagesAfterAgentResult, messageIdentity, messageText, pendingUserRow, sanitizeMessagesForApi, sessionLacksFinalAssistantAnswer, splitDisplayText, stateDbSeenId, joinReasoning, reasoningFieldsText, stoppedTurnContext, toolOutcome, withAttachmentObjects, withBodyExcerpts, withDisplayMedia, withMarkerKinds, withToolCallOutcomes, workspaceContextPrefix, withoutMaxIterationSummaryRequest, withNativeImagesRestored, withoutNativeImages, withoutToolImages } from './merge.js';
29
+ import { agentSteerText, assistantReplyAddedAfterCurrentTurn, attachedFilesPrompt, buildPartialMessage, dedupeContext, checkpointTurnStart, extractToolCallsFromMessages, hasNativeImages, injectMaxIterationSummaryFallback, isDict, mergeDisplayMessagesAfterAgentResult, messageIdentity, messageText, pendingUserRow, sanitizeMessagesForApi, sessionLacksFinalAssistantAnswer, splitDisplayText, stateDbSeenId, joinReasoning, reasoningFieldsText, toolOutcome, withAttachmentObjects, withBodyExcerpts, withDisplayMedia, withMarkerKinds, withToolCallOutcomes, withoutMaxIterationSummaryRequest, withNativeImagesRestored, withoutNativeImages, withoutToolImages } from './merge.js';
30
30
  import { mayBecomeSilentReply, turnOrigin, withBackgroundUpdates } from './background-updates.js';
31
- import { fallbackTitleFromExchange, firstExchangeSnippets, isGenericFallbackTitle, latestExchangeSnippets, looksInvalidGeneratedTitle, looksLikeDefaultCliTitle, sanitizeGeneratedTitle, titleLanguageMismatch, titlePrompts } from './titles.js';
31
+ import { countExchanges, fallbackTitleFromExchange, firstExchangeSnippets, isGenericFallbackTitle, latestExchangeSnippets, looksInvalidGeneratedTitle, looksLikeDefaultCliTitle, sanitizeGeneratedTitle, titleLanguageMismatch, titlePrompts } from './titles.js';
32
32
  import { WORKSPACE_BUSY_MESSAGE } from '../workspace/git.js';
33
+ import { CHECKPOINT_STORE_BUSY_MESSAGE } from '../workspace/rollback.js';
33
34
  import { str } from '../util.js';
34
35
  import { toolEditDiff } from './tool-display.js';
36
+ import { recordWakeupPause } from './wakeup-pause.js';
35
37
  export const CHAT_LOCK_WAIT_SECONDS = 2;
36
38
  const IMAGE_MODE_TIMEOUT_MS = 15_000;
37
39
  const TERMINAL_SSE_VISIBLE_MESSAGE_LIMIT = 80;
@@ -71,7 +73,7 @@ export function classifyProviderError(errStr, opts = {}) {
71
73
  if (['interrupted by user', 'response interrupted', 'operation interrupted', 'operation was interrupted', 'operation aborted', 'request was aborted', 'aborterror'].some((k) => lower.includes(k))) {
72
74
  return { label: 'Response interrupted', type: 'interrupted', hint: 'The run stopped before a provider response completed. If you did not cancel it, try again.' };
73
75
  }
74
- const quota = ['insufficient_quota', 'insufficient credits', 'out of credits', 'credits exhausted', 'quota exceeded', 'usage limit', 'plan limit', 'billing'].some((k) => lower.includes(k));
76
+ const quota = ['insufficient_quota', 'insufficient credits', 'out of credits', 'credits exhausted', 'quota exceeded', 'usage limit', 'plan limit', 'billing', 'more credits', 'can only afford', 'fewer max_tokens', 'credit balance', 'exceeded your current quota', 'usage_limit_exceeded', 'reached the limit of messages', 'used up your usage'].some((k) => lower.includes(k));
75
77
  const poolEmpty = lower.includes('credential(s) exhausted') || lower.includes('credentials exhausted') || (lower.includes('credential') && lower.includes('exhausted'));
76
78
  const auth = !quota && !poolEmpty && (errStr.includes('401') || lower.includes('authentication') || lower.includes('unauthorized') || lower.includes('invalid api key') || lower.includes('invalid_api_key') || lower.includes('no cookie auth credentials'));
77
79
  const notFound = errStr.includes('404') || lower.includes('not found') || lower.includes('does not exist') || lower.includes('model_not_found') || lower.includes('invalid model') || lower.includes('does not match any known model') || lower.includes('unknown model');
@@ -125,8 +127,6 @@ export function sniffImageMime(bytes, declared = '') {
125
127
  return 'image/bmp';
126
128
  return null;
127
129
  }
128
- const COMPRESSION_RECOVERY_TERMINAL_STATE = 'compression_exhausted';
129
- const COMPRESSION_RECOVERY_ACTION_START_FOCUSED = 'start_focused_continuation';
130
130
  /** Python `build_compression_recovery_payload` + `stamp_compression_exhausted_recovery`. */
131
131
  export function stampCompressionExhaustedRecovery(s, message, details) {
132
132
  const positive = (v) => { const n = Math.trunc(Number(v) || 0); return n > 0 ? n : 0; };
@@ -211,6 +211,8 @@ export class TurnRunner {
211
211
  liveTodos = new Map();
212
212
  /** Streams whose run completed (`done` emitted) and only await title work; a late cancel is a no-op for these. */
213
213
  settledStreams = new Set();
214
+ /** The last adaptive title refresh per session; a successor turn's refresh runs after it (TAL-589). */
215
+ titleRefreshes = new Map();
214
216
  /**
215
217
  * TAL-364: what a Stop needs to write the turn's model context: its starting context, the prompt the Agent got, and
216
218
  * whether a settlement already used a canonical checkpoint (which marks the stop boundary; later work never replaces it).
@@ -234,6 +236,8 @@ export class TurnRunner {
234
236
  return { error: `Profile '${str(s.profile)}' is being deleted.`, _status: 409 };
235
237
  if (this.deps.workspaceBusy?.(opts.workspace))
236
238
  return { error: WORKSPACE_BUSY_MESSAGE, _status: 409 };
239
+ if (this.deps.checkpointStoreBusy?.(s.profile ?? null))
240
+ return { error: CHECKPOINT_STORE_BUSY_MESSAGE, _status: 409 };
237
241
  const locked = s.active_stream_id;
238
242
  if (locked) {
239
243
  if (this.registry.liveIds.has(locked) || this.registry.activeRuns.has(locked))
@@ -291,6 +295,10 @@ export class TurnRunner {
291
295
  response.effective_model_provider = opts.modelProvider;
292
296
  return response;
293
297
  }
298
+ /** Resolves once the stream's worker has ended (settled, failed, or torn down); it never rejects. */
299
+ finished(streamId) {
300
+ return this.workers.get(streamId) ?? Promise.resolve();
301
+ }
294
302
  /** Python `_checkpoint_user_message_for_eager_session_save`. */
295
303
  checkpointUserMessage(s, msg, attachments, startedAt, source, turnId) {
296
304
  const latest = s.messages[s.messages.length - 1];
@@ -309,7 +317,12 @@ export class TurnRunner {
309
317
  catch (error) {
310
318
  deps.log(`[webui] WARNING: run journal degraded for stream ${streamId}: ${error.message}`);
311
319
  }
320
+ const failure = { apperror: null, cancelled: false };
312
321
  const put = (event, data, meta = {}) => {
322
+ if (event === 'apperror')
323
+ failure.apperror = data;
324
+ else if (event === 'cancel')
325
+ failure.cancelled = true;
313
326
  for (const steerEvent of this.takeSteerEventsBefore(streamId, event))
314
327
  put(steerEvent[0], steerEvent[1]);
315
328
  if (this.registry.cancelled.has(streamId) && !['cancel', 'apperror', 'steer_consumed', 'steer_withdrawn'].includes(event))
@@ -358,14 +371,14 @@ export class TurnRunner {
358
371
  const previousMessages = structuredClone(s.messages);
359
372
  // TAL-493: one state.db read builds the history and marks where this turn's own rows begin.
360
373
  const startRead = deps.service().stateDbRead(s);
361
- const previousContext = structuredClone(deps.service().modelContext(s, startRead.rows));
374
+ // TAL-578: an eager save already put this turn's prompt in the transcript; `user_message` carries it, so the history
375
+ // leaves it out.
376
+ const previousContext = structuredClone(deps.service().modelContext(s, startRead.rows)).filter((m) => m._turn_id !== streamId);
362
377
  // Python `_sanitize_messages_for_agent`: the model never sees display-only rows or a replayed cancelled prompt, and
363
378
  // the Agent gets back the exact bytes it sent (TAL-541).
364
379
  const apiHistory = sanitizeMessagesForApi(previousContext, { preserveApiContent: true });
365
- const workspaceCtx = workspaceContextPrefix(opts.workspace);
366
380
  // Before the first await: a Stop can land at any point after admission.
367
- // An eager save already put this turn's prompt in the transcript; the Stop fallback appends it once itself.
368
- this.stopContexts.set(streamId, { previousContext: previousContext.filter((m) => m._turn_id !== streamId), historyLength: apiHistory.length, prompt: workspaceCtx + msgText, msgText, checkpointed: false, stateDbStartId: startRead.ok ? stateDbSeenId(startRead.rows) ?? 0 : null });
381
+ this.stopContexts.set(streamId, { previousContext, historyLength: apiHistory.length, prompt: msgText, msgText, checkpointed: false, stateDbStartId: startRead.ok ? stateDbSeenId(startRead.rows) ?? 0 : null });
369
382
  const activeTurnToken = buildActiveTurnToken(streamId, s.pending_started_at);
370
383
  const sidecar = deps.sidecar();
371
384
  const partialText = this.registry.partialText.get(streamId) ?? [];
@@ -411,7 +424,7 @@ export class TurnRunner {
411
424
  // TAL-545: one image mode decides both this turn's upload and the replayed history, which a text-mode turn sends
412
425
  // without native images; only a turn with an image on either side asks for it.
413
426
  const imageMode = attachments.some(isImageAttachment) || hasNativeImages(apiHistory) ? await this.imageInputMode(sessionId, s, opts, controller.signal) : null;
414
- const userMessage = this.buildUserMessage(workspaceCtx, msgText, attachments, opts.workspace, sessionId, imageMode);
427
+ const userMessage = this.buildUserMessage(msgText, attachments, opts.workspace, sessionId, imageMode);
415
428
  const conversationHistory = imageMode === 'text' ? withoutNativeImages(apiHistory) : apiHistory;
416
429
  // The prompt the Agent actually gets, native image parts included.
417
430
  const stop = this.stopContexts.get(streamId);
@@ -420,14 +433,15 @@ export class TurnRunner {
420
433
  if (activeRun)
421
434
  activeRun.phase = 'running';
422
435
  const settledAt = { value: false };
423
- let failed = false;
436
+ let succeeded = false;
424
437
  // TAL-424: steers an errored turn ended without taking, sent as one follow-up turn once this one is torn down.
425
438
  let followUp = [];
426
439
  try {
427
440
  if (!sidecar)
428
441
  throw new SidecarError('The Agent sidecar is not running; chat is unavailable until it starts.', { condition: 'sidecar_unavailable' });
429
442
  // Python: budgets, reasoning config, personality and delivery context come from the profile's config.yaml; the
430
- // system message carries the frozen session workspace, the WebUI guidance rides as the ephemeral prompt.
443
+ // system message carries the frozen session workspace, the WebUI guidance rides as the ephemeral prompt with this
444
+ // turn's workspace (TAL-710: never a tag on the user's message, which the Agent can persist from memory).
431
445
  const cfg = (await deps.profileConfig?.(s.profile ?? null)) ?? {};
432
446
  // The sidecar's per-session YOLO state does not survive its restarts: push the local flag (either way) before
433
447
  // the turn so a stale sidecar-side enable cannot auto-approve a session the UI reports as guarded.
@@ -442,10 +456,9 @@ export class TurnRunner {
442
456
  put('cancel', this.cancelFrame(sessionId));
443
457
  return;
444
458
  }
445
- const frozenWorkspace = str(s.created_workspace) || str(s.workspace);
446
459
  const turnContext = {
447
- system_message: workspaceSystemMessage(frozenWorkspace),
448
- ephemeral_system_prompt: webuiEphemeralSystemPrompt({ config: cfg, personality: str(s.personality) || null, sessionId, profile: s.profile ?? null, workspace: frozenWorkspace, hermesHome: deps.profileHome(s.profile), homeDisplay: deps.homeDisplay?.() ?? '~/.hermes', background: turnOrigin(opts.source) === 'background' }),
460
+ system_message: workspaceSystemMessage(str(s.created_workspace) || str(s.workspace)),
461
+ ephemeral_system_prompt: webuiEphemeralSystemPrompt({ config: cfg, personality: str(s.personality) || null, sessionId, profile: s.profile ?? null, workspace: opts.workspace, hermesHome: deps.profileHome(s.profile), homeDisplay: deps.homeDisplay?.() ?? '~/.hermes', background: turnOrigin(opts.source) === 'background' }),
449
462
  max_iterations: processWakeupMaxIterations(maxIterationsFromConfig(cfg), opts.source ?? 'webui', deps.env ?? {}),
450
463
  max_tokens: maxTokensFromConfig(cfg),
451
464
  reasoning_config: reasoningConfigFromConfig(cfg, opts.modelProvider ?? s.model_provider ?? null),
@@ -641,16 +654,15 @@ export class TurnRunner {
641
654
  await this.steerRewrites.get(streamId);
642
655
  const { events: steerEvents, leftovers } = this.finalizeSteers(streamId, str(result.pending_steer), 'followup');
643
656
  followUp = leftovers;
644
- this.persistError(s, streamId, classification.label, payload, activeTurnToken, resultMessages);
657
+ this.persistError(s, streamId, classification.label, payload, activeTurnToken, resultMessages, result.provider);
645
658
  // TAL-512: a btw error carries no session: its journaled frame must not keep a copy of the parent conversation.
646
659
  if (!opts.ephemeral)
647
- payload.session = redactSessionData(this.terminalSessionPayload(s), deps.redactEnabled());
660
+ payload.session = this.publicTerminalSession(s);
648
661
  payload.session_id = s.session_id;
649
662
  payload.old_session_id = sessionId;
650
663
  for (const [event, data] of steerEvents)
651
664
  put(event, data);
652
665
  put('apperror', payload);
653
- failed = true;
654
666
  return;
655
667
  }
656
668
  // TAL-512: a btw turn passes the failure check above first, so its last assistant row is this turn's reply.
@@ -663,6 +675,7 @@ export class TurnRunner {
663
675
  break;
664
676
  }
665
677
  }
678
+ succeeded = true;
666
679
  opts.onDone?.(answer);
667
680
  // Python `_ephemeral_session_payload`: only role and content leave the server for a btw turn.
668
681
  put('done', { session: { session_id: sessionId, messages: resultMessages.map((m) => ({ role: m.role, content: m.content })) }, usage: { input_tokens: 0, output_tokens: 0 }, ephemeral: true, answer, terminal_state: answer.trim() ? 'completed' : 'no_response' });
@@ -734,6 +747,8 @@ export class TurnRunner {
734
747
  s.pending_attachments = [];
735
748
  s.pending_started_at = null;
736
749
  s.pending_user_source = null;
750
+ // TAL-576: a turn that ran means the provider has usable credentials again.
751
+ s.process_wakeup_pause = null;
737
752
  const attachments = opts.attachments ?? [];
738
753
  if (attachments.length) {
739
754
  for (let i = s.messages.length - 1; i >= 0; i -= 1) {
@@ -813,7 +828,7 @@ export class TurnRunner {
813
828
  cache_hit_percent: cacheHit(cacheReadTokens, inputTokens), turn_cache_hit_percent: cacheHit(turnCacheRead, turnInput), duration_seconds: Math.round(duration * 1000) / 1000,
814
829
  context_length: s.context_length ?? 0, threshold_tokens: s.threshold_tokens ?? 0, last_prompt_tokens: s.last_prompt_tokens ?? 0,
815
830
  };
816
- const doneSession = redactSessionData(this.terminalSessionPayload(s), deps.redactEnabled());
831
+ const doneSession = this.publicTerminalSession(s);
817
832
  // TAL-299: the ring's figures match the terminal session's (and a detail reload's).
818
833
  for (const key of CONTEXT_USAGE_FIELDS)
819
834
  doneUsage[key] = doneSession[key];
@@ -850,14 +865,13 @@ export class TurnRunner {
850
865
  for (const r of work)
851
866
  if (r.status === 'rejected')
852
867
  throw r.reason;
853
- // Python: the last non-error assistant reply with content, else "(no answer produced)".
854
- opts.onDone?.(lastAnswer(s.messages) || '(no answer produced)');
868
+ succeeded = true;
869
+ opts.onDone?.(lastAnswer(s.messages));
855
870
  }
856
871
  catch (error) {
857
872
  if (settledAt.value && !(error instanceof SidecarError)) {
858
873
  deps.log(`[webui] ERROR settling turn ${streamId}\n${error instanceof Error ? (error.stack ?? error.message) : String(error)}`);
859
874
  }
860
- failed = true;
861
875
  if (this.registry.cancelled.has(streamId)) {
862
876
  this.finalizeCancelled(s, streamId, opts.ephemeral);
863
877
  put('cancel', this.cancelFrame(sessionId));
@@ -884,7 +898,7 @@ export class TurnRunner {
884
898
  put(event, data);
885
899
  this.persistError(current, streamId, classification.label, payload, activeTurnToken);
886
900
  if (!opts.ephemeral)
887
- payload.session = redactSessionData(this.terminalSessionPayload(current), deps.redactEnabled());
901
+ payload.session = this.publicTerminalSession(current);
888
902
  }
889
903
  }
890
904
  catch (persistError) {
@@ -898,8 +912,8 @@ export class TurnRunner {
898
912
  this.teardown(sessionId, streamId);
899
913
  // After persistence and teardown: a background route's failure cleanup deletes the hidden session, which must
900
914
  // not race the error writeback above (a re-saved session would resurface in the sidebar).
901
- if (failed)
902
- opts.onFailed?.();
915
+ if (!succeeded)
916
+ opts.onFailed?.(failure);
903
917
  this.startSteerFollowUp(sessionId, followUp);
904
918
  }
905
919
  }
@@ -941,9 +955,8 @@ export class TurnRunner {
941
955
  * after the text (TAL-276), so an attachment-only turn still gives the model a request and its transcript row a
942
956
  * distinct identity.
943
957
  */
944
- buildUserMessage(workspaceCtx, msgText, attachments, workspace, sessionId, imageMode) {
945
- const text = workspaceCtx + msgText;
946
- const withFiles = () => attachedFilesPrompt(text, attachments);
958
+ buildUserMessage(msgText, attachments, workspace, sessionId, imageMode) {
959
+ const withFiles = () => attachedFilesPrompt(msgText, attachments);
947
960
  const candidates = attachments.filter(isImageAttachment);
948
961
  if (!candidates.length || imageMode !== 'native')
949
962
  return withFiles();
@@ -981,6 +994,10 @@ export class TurnRunner {
981
994
  }
982
995
  return images ? [{ type: 'text', text: withFiles() }, ...parts] : withFiles();
983
996
  }
997
+ /** The settled session as a terminal frame carries it: the display window, redacted. */
998
+ publicTerminalSession(s) {
999
+ return redactSessionData(this.terminalSessionPayload(s), this.deps.redactEnabled());
1000
+ }
984
1001
  /**
985
1002
  * Python `_session_payload_with_terminal_window`: the same visible-message window contract as `GET /api/session?
986
1003
  * msg_limit=` (renderable rows, limited payload shape, windowed tool calls, todo state) with the full count.
@@ -1003,8 +1020,22 @@ export class TurnRunner {
1003
1020
  return payload;
1004
1021
  }
1005
1022
  /** Python `_materialize_pending_user_turn_before_error` + error message append + save. */
1006
- persistError(s, streamId, label, payload, activeTurnToken, agentRows = []) {
1023
+ /** `runtimeProvider`: the provider the Agent resolved for the turn, when it reported one. */
1024
+ persistError(s, streamId, label, payload, activeTurnToken, agentRows = [], runtimeProvider = '') {
1007
1025
  const startedAt = s.pending_started_at;
1026
+ // TAL-576: an automatic wakeup with no usable credentials pauses the next ones instead of failing each.
1027
+ if (s.pending_user_source === 'process_wakeup' && payload.type === 'credential_pool_empty') {
1028
+ // A profile whose home now escapes the profiles root (`profileHome` throws) records no pause; the error still persists.
1029
+ let home = null;
1030
+ try {
1031
+ home = this.deps.profileHome(s.profile);
1032
+ }
1033
+ catch {
1034
+ home = null;
1035
+ }
1036
+ if (home !== null)
1037
+ recordWakeupPause(s, home, this.deps.now(), runtimeProvider, this.deps.configPath?.(home));
1038
+ }
1008
1039
  this.materializePendingUserTurn(s, activeTurnToken, streamId);
1009
1040
  const duration = typeof startedAt === 'number' && startedAt > 0 ? Math.max(0, this.deps.now() - startedAt) : null;
1010
1041
  s.active_stream_id = null;
@@ -1035,8 +1066,14 @@ export class TurnRunner {
1035
1066
  s.messages.push(errorMessage);
1036
1067
  this.keepLiveState(s, streamId);
1037
1068
  this.persistConsumedSteers(s, streamId, startedAt, this.deps.now());
1069
+ // TAL-921: the next prompt remembers the turn's work; an exhausted compression's work would only overflow again. One
1070
+ // read builds the context and settles, so a row committed in between is never covered without reaching either.
1071
+ const read = this.deps.service().stateDbRead(s);
1072
+ const context = payload.type === 'compression_exhausted' ? null : this.unsettledContext(streamId, agentRows, read);
1073
+ if (context)
1074
+ s.context_messages = context;
1038
1075
  const stop = this.stopContexts.get(streamId);
1039
- this.deps.service().settleStateDb(s, { turnId: streamId, previousContext: stop?.previousContext ?? [], agentRows, startId: stop?.stateDbStartId ?? null });
1076
+ this.deps.service().settleStateDb(s, { turnId: streamId, previousContext: stop?.previousContext ?? [], agentRows, startId: stop?.stateDbStartId ?? null, read });
1040
1077
  try {
1041
1078
  this.deps.store.save(s);
1042
1079
  }
@@ -1049,6 +1086,18 @@ export class TurnRunner {
1049
1086
  this.deps.pending.clearClarifies(s.session_id);
1050
1087
  this.deps.events.publish('session_error', { profile: s.profile, sessionId: s.session_id });
1051
1088
  }
1089
+ /**
1090
+ * TAL-921: the model context a turn that ends without its settled result leaves: the work its Agent reported, else the
1091
+ * rows it committed past its starting read in `read`, the read its settlement uses.
1092
+ */
1093
+ unsettledContext(streamId, agentRows, read) {
1094
+ const stop = this.stopContexts.get(streamId);
1095
+ if (!stop)
1096
+ return null;
1097
+ const after = stop.stateDbStartId;
1098
+ const stateRows = after === null ? [] : read.rows.filter((m) => typeof m._state_db_row_id === 'number' && m._state_db_row_id > after);
1099
+ return this.deps.service().unsettledTurnContext({ ...stop, streamedText: (this.registry.partialText.get(streamId) ?? []).join(''), agentRows, stateRows });
1100
+ }
1052
1101
  materializePendingUserTurn(s, activeTurnToken, turnId) {
1053
1102
  const pendingText = str(s.pending_user_message);
1054
1103
  if (!s.hasPendingPrompt)
@@ -1098,7 +1147,7 @@ export class TurnRunner {
1098
1147
  let snapshot = null;
1099
1148
  if (sessionId)
1100
1149
  try {
1101
- snapshot = redactSessionData(this.terminalSessionPayload(this.deps.store.get(sessionId)), this.deps.redactEnabled());
1150
+ snapshot = this.publicTerminalSession(this.deps.store.get(sessionId));
1102
1151
  }
1103
1152
  catch {
1104
1153
  snapshot = null;
@@ -1148,24 +1197,26 @@ export class TurnRunner {
1148
1197
  }
1149
1198
  const stop = this.stopContexts.get(streamId);
1150
1199
  const canonical = stop !== undefined && checkpoint !== null && checkpointTurnStart(checkpoint, stop.msgText, stop.historyLength) !== null;
1151
- const settle = () => {
1200
+ // TAL-921: one state.db read builds the context and settles the turn.
1201
+ const settle = (read) => {
1152
1202
  if (!stop)
1153
1203
  return null;
1154
1204
  if (canonical)
1155
1205
  stop.checkpointed = true;
1156
- return stoppedTurnContext(stop.previousContext, checkpoint, stop.prompt, stop.msgText, (this.registry.partialText.get(streamId) ?? []).join(''), stop.historyLength);
1206
+ return this.unsettledContext(streamId, checkpoint, read);
1157
1207
  };
1158
1208
  if (current.messages.some((m) => isCancelMarker(m)) && current.active_stream_id === null && !current.pending_user_message) {
1159
1209
  // The worker's canonical result can arrive after cancel() settled without a checkpoint (the interrupt reply failed
1160
1210
  // or timed out): it replaces this stream's context and never adds a second Stop row. A settlement that already had
1161
1211
  // one keeps it, so work the Agent finished after the Stop stays out.
1162
1212
  const ownStop = current.messages.some((m) => isCancelMarker(m) && m._turn_id === streamId);
1163
- const late = canonical && !stop.checkpointed && ownStop ? settle() : null;
1164
- if (late)
1165
- current.context_messages = dedupeContext(late);
1166
1213
  // TAL-493: the worker's rows committed after the first settlement are covered by what it reports; others are kept.
1167
- if (late || (ownStop && checkpoint)) {
1168
- this.deps.service().settleStateDb(current, { turnId: streamId, previousContext: stop?.previousContext ?? [], agentRows: checkpoint, startId: stop?.stateDbStartId ?? null });
1214
+ if (ownStop && checkpoint) {
1215
+ const read = this.deps.service().stateDbRead(current);
1216
+ const late = canonical && !stop.checkpointed ? settle(read) : null;
1217
+ if (late)
1218
+ current.context_messages = dedupeContext(late);
1219
+ this.deps.service().settleStateDb(current, { turnId: streamId, previousContext: stop?.previousContext ?? [], agentRows: checkpoint, startId: stop?.stateDbStartId ?? null, read });
1169
1220
  try {
1170
1221
  this.deps.store.save(current);
1171
1222
  }
@@ -1177,7 +1228,8 @@ export class TurnRunner {
1177
1228
  }
1178
1229
  const startedAt = current.pending_started_at;
1179
1230
  this.materializePendingUserTurn(current, buildActiveTurnToken(streamId, current.pending_started_at), streamId);
1180
- const context = settle();
1231
+ const read = this.deps.service().stateDbRead(current);
1232
+ const context = settle(read);
1181
1233
  if (context)
1182
1234
  current.context_messages = dedupeContext(context);
1183
1235
  current.active_stream_id = null;
@@ -1191,7 +1243,7 @@ export class TurnRunner {
1191
1243
  }
1192
1244
  this.keepLiveState(current, streamId);
1193
1245
  this.persistConsumedSteers(current, streamId, startedAt, this.deps.now());
1194
- this.deps.service().settleStateDb(current, { turnId: streamId, previousContext: stop?.previousContext ?? [], agentRows: checkpoint, startId: stop?.stateDbStartId ?? null });
1246
+ this.deps.service().settleStateDb(current, { turnId: streamId, previousContext: stop?.previousContext ?? [], agentRows: checkpoint, startId: stop?.stateDbStartId ?? null, read });
1195
1247
  try {
1196
1248
  this.deps.store.save(current);
1197
1249
  }
@@ -1307,6 +1359,15 @@ export class TurnRunner {
1307
1359
  return { title: fallback, status: `local_summary:${llmStatus}`, rawPreview };
1308
1360
  return { title: null, status: llmStatus || 'empty_title', rawPreview };
1309
1361
  }
1362
+ /**
1363
+ * TAL-591 (Python `_queue_generated_title_for_imported_session`): a CLI session a mutation claims while it still
1364
+ * carries its default title gets the background title job at once instead of after its first WebUI turn.
1365
+ */
1366
+ async titleClaimed(s) {
1367
+ if (!looksLikeDefaultCliTitle({ title: s.title, source_tag: s.source_tag, raw_source: s.raw_source, session_source: s.session_source, source_label: s.source_label }))
1368
+ return;
1369
+ await this.backgroundTitle(s, () => undefined).catch((error) => { this.deps.log(`[webui] imported session title failed for ${s.session_id}: ${error.message}`); });
1370
+ }
1310
1371
  /** Python `_run_background_title_update` (spawned only when `_background_title_generation_inputs` is eligible). */
1311
1372
  async backgroundTitle(s, put) {
1312
1373
  const sessionId = s.session_id;
@@ -1320,8 +1381,11 @@ export class TurnRunner {
1320
1381
  const status = (status, reason = '', title = '', rawPreview = '') => {
1321
1382
  put('title_status', { session_id: sessionId, status, ...(reason ? { reason } : {}), ...(title ? { title } : {}), ...(rawPreview ? { raw_preview: rawPreview } : {}) });
1322
1383
  };
1323
- if (!eligible || (s.llm_title_generated && !invalidExisting) || !userText || !assistantText)
1384
+ // Python ran the adaptive refresh only when the first-title job was not eligible.
1385
+ if (!eligible || (s.llm_title_generated && !invalidExisting) || !userText || !assistantText) {
1386
+ await this.refreshTitle(s, put, status);
1324
1387
  return;
1388
+ }
1325
1389
  if (s.manual_title) {
1326
1390
  status('skipped', 'manual_title', placeholder);
1327
1391
  return;
@@ -1353,6 +1417,9 @@ export class TurnRunner {
1353
1417
  current = this.deps.store.get(sessionId);
1354
1418
  }
1355
1419
  catch {
1420
+ // A session deleted while the title prompt ran stays deleted.
1421
+ if (this.deps.store.wasDeleted(sessionId))
1422
+ return;
1356
1423
  current = s;
1357
1424
  }
1358
1425
  let effective = str(current.title).trim();
@@ -1381,6 +1448,71 @@ export class TurnRunner {
1381
1448
  else
1382
1449
  status('skipped', source || 'unchanged', effective, rawPreview);
1383
1450
  }
1451
+ /**
1452
+ * Python `_maybe_schedule_title_refresh` + `_run_background_title_refresh`: every N exchanges a generated title is
1453
+ * regenerated from the latest exchange; a manual title is never touched.
1454
+ */
1455
+ async refreshTitle(s, put, status) {
1456
+ const every = this.deps.titleRefreshEvery?.() ?? 0;
1457
+ const exchanges = countExchanges(s.messages);
1458
+ if (every <= 0 || exchanges <= 0 || exchanges % every !== 0)
1459
+ return;
1460
+ const [userText, assistantText] = latestExchangeSnippets(s.messages);
1461
+ if (!userText || !assistantText)
1462
+ return;
1463
+ // Admission is released before title work, so an earlier turn's refresh may still be running: refreshes apply in
1464
+ // turn order and each reads the title its predecessor wrote.
1465
+ const sessionId = s.session_id;
1466
+ const run = (this.titleRefreshes.get(sessionId) ?? Promise.resolve()).catch(() => undefined).then(() => this.applyTitleRefresh(sessionId, s, userText, assistantText, put, status));
1467
+ this.titleRefreshes.set(sessionId, run);
1468
+ try {
1469
+ await run;
1470
+ }
1471
+ finally {
1472
+ if (this.titleRefreshes.get(sessionId) === run)
1473
+ this.titleRefreshes.delete(sessionId);
1474
+ }
1475
+ }
1476
+ async applyTitleRefresh(sessionId, s, userText, assistantText, put, status) {
1477
+ const read = () => { try {
1478
+ return this.deps.store.get(sessionId);
1479
+ }
1480
+ catch {
1481
+ return s;
1482
+ } };
1483
+ const latest = read();
1484
+ const placeholder = str(latest.title).trim();
1485
+ if (['Untitled', 'New Chat', ''].includes(placeholder) || latest.manual_title || !latest.llm_title_generated)
1486
+ return;
1487
+ const cfg = await this.deps.profileConfig?.(latest.profile ?? null);
1488
+ if (!cfg || !titleGenerationEnabled(cfg)) {
1489
+ status('refresh_skipped', cfg ? 'title_generation_disabled' : 'config_unavailable', placeholder);
1490
+ return;
1491
+ }
1492
+ const { title: next, status: llmStatus, rawPreview } = await this.llmTitle(latest, userText, assistantText);
1493
+ if (!next) {
1494
+ status('refresh_skipped', llmStatus || 'empty', placeholder, rawPreview);
1495
+ return;
1496
+ }
1497
+ const normalize = (value) => value.replace(/\s+/g, ' ').trim().toLowerCase();
1498
+ if (normalize(next) === normalize(placeholder)) {
1499
+ status('refresh_skipped', 'same_title', placeholder, rawPreview);
1500
+ return;
1501
+ }
1502
+ const current = read();
1503
+ // The user may have renamed the session while the title prompt ran.
1504
+ if (current.manual_title || str(current.title).trim() !== placeholder) {
1505
+ status('skipped', 'manual_title', str(current.title).trim());
1506
+ return;
1507
+ }
1508
+ current.title = next;
1509
+ markSessionTitleGenerated(current);
1510
+ this.deps.store.save(current, { touchUpdatedAt: false });
1511
+ await this.deps.syncTitle?.(current);
1512
+ this.deps.events.publish('title', { profile: current.profile, sessionId });
1513
+ status('refreshed', llmStatus, next, rawPreview);
1514
+ put('title', { session_id: sessionId, title: next });
1515
+ }
1384
1516
  // ── cancel / steer ───────────────────────────────────────────────────────
1385
1517
  /**
1386
1518
  * Python `cancel_stream`: persist the partial, mark cancelled, interrupt the Agent, release admission. `withdrawn` is the
@@ -1658,12 +1790,6 @@ export class TurnRunner {
1658
1790
  return { events, leftovers: [...(unmatched ? [unmatched] : []), ...left.map((r) => r.text)] };
1659
1791
  if (unmatched)
1660
1792
  events.push(['steer_withdrawn', { steer_id: null, reason: 'stopped', text: unmatched }]);
1661
- // ponytail: legacy `pending_steer_leftover` keeps today's Web and App from losing a stopped steer (they requeue it);
1662
- // drop it once TAL-425 / TAL-426 put `steer_withdrawn` text back in the composer.
1663
- for (const r of left)
1664
- events.push(['pending_steer_leftover', { steer_id: r.steer_id, stream_id: streamId, text: r.text, display_text: r.display_text, leftover_at: this.deps.now() }]);
1665
- if (unmatched)
1666
- events.push(['pending_steer_leftover', { stream_id: streamId, text: unmatched }]);
1667
1793
  return { events, leftovers: [] };
1668
1794
  }
1669
1795
  /**
@@ -1890,7 +2016,9 @@ export class TurnRunner {
1890
2016
  const profileHome = this.deps.profileHome(s?.profile ?? null);
1891
2017
  let resolved = false;
1892
2018
  let withdrawn = false;
1893
- if (entry) {
2019
+ if (entry?._injected === true)
2020
+ resolved = Boolean(this.deps.pending.resolveApproval(sessionId, str(entry.approval_id)).entry);
2021
+ else if (entry) {
1894
2022
  if (!sidecar)
1895
2023
  return relayFailure('not running');
1896
2024
  try {
@@ -1992,6 +2120,11 @@ export class TurnRunner {
1992
2120
  const response = typeof reply === 'string' ? reply : clarifyReply(entry, reply);
1993
2121
  if (response === null)
1994
2122
  return { ok: false, invalid: true };
2123
+ // A test-hook prompt has no parked Agent waiter: it is answered here.
2124
+ if (entry._injected === true) {
2125
+ this.deps.pending.resolveClarify(sessionId, str(entry.clarify_id));
2126
+ return { ok: true, response };
2127
+ }
1995
2128
  const sidecar = this.deps.sidecar();
1996
2129
  if (!sidecar)
1997
2130
  return { ok: false, error: 'The Agent sidecar is not running; retry in a moment.' };