@maudecode/talaria-web 1.17.2 → 1.19.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 (623) 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 +20 -20
  4. package/dist/api/auth-raw.js.map +1 -1
  5. package/dist/api/automation-raw.d.ts +7 -1
  6. package/dist/api/automation-raw.js +74 -27
  7. package/dist/api/automation-raw.js.map +1 -1
  8. package/dist/api/automation-router.d.ts +128 -23
  9. package/dist/api/automation-router.js +29 -13
  10. package/dist/api/automation-router.js.map +1 -1
  11. package/dist/api/chat-router.d.ts +1845 -40
  12. package/dist/api/chat-router.js +196 -114
  13. package/dist/api/chat-router.js.map +1 -1
  14. package/dist/api/git-router.d.ts +37 -3
  15. package/dist/api/git-router.js +47 -48
  16. package/dist/api/git-router.js.map +1 -1
  17. package/dist/api/raw-routes.d.ts +9 -1
  18. package/dist/api/raw-routes.js +286 -73
  19. package/dist/api/raw-routes.js.map +1 -1
  20. package/dist/api/router.d.ts +16 -6
  21. package/dist/api/router.js +28 -26
  22. package/dist/api/router.js.map +1 -1
  23. package/dist/api/session-visibility.d.ts +4 -4
  24. package/dist/api/session-visibility.js +26 -16
  25. package/dist/api/session-visibility.js.map +1 -1
  26. package/dist/api/sessions-router.d.ts +3312 -131
  27. package/dist/api/sessions-router.js +287 -157
  28. package/dist/api/sessions-router.js.map +1 -1
  29. package/dist/api/settings-router.d.ts +457 -8
  30. package/dist/api/settings-router.js +54 -33
  31. package/dist/api/settings-router.js.map +1 -1
  32. package/dist/api/sse-routes.d.ts +7 -2
  33. package/dist/api/sse-routes.js +109 -62
  34. package/dist/api/sse-routes.js.map +1 -1
  35. package/dist/api/tools-raw.d.ts +5 -0
  36. package/dist/api/tools-raw.js +63 -55
  37. package/dist/api/tools-raw.js.map +1 -1
  38. package/dist/api/tools-router.d.ts +998 -85
  39. package/dist/api/tools-router.js +447 -61
  40. package/dist/api/tools-router.js.map +1 -1
  41. package/dist/api/transcribe-stream.d.ts +16 -0
  42. package/dist/api/transcribe-stream.js +172 -0
  43. package/dist/api/transcribe-stream.js.map +1 -0
  44. package/dist/app.d.ts +4 -1
  45. package/dist/app.js +98 -59
  46. package/dist/app.js.map +1 -1
  47. package/dist/auth/gate.js +15 -11
  48. package/dist/auth/gate.js.map +1 -1
  49. package/dist/auth/oidc.d.ts +5 -2
  50. package/dist/auth/oidc.js +8 -7
  51. package/dist/auth/oidc.js.map +1 -1
  52. package/dist/auth/passkeys.d.ts +15 -14
  53. package/dist/auth/passkeys.js +89 -91
  54. package/dist/auth/passkeys.js.map +1 -1
  55. package/dist/auth/store.d.ts +17 -7
  56. package/dist/auth/store.js +93 -52
  57. package/dist/auth/store.js.map +1 -1
  58. package/dist/bin/talaria-web.js +12 -81
  59. package/dist/bin/talaria-web.js.map +1 -1
  60. package/dist/cli/ctl.js +2 -1
  61. package/dist/cli/ctl.js.map +1 -1
  62. package/dist/cli/dotenv.d.ts +5 -0
  63. package/dist/cli/dotenv.js +15 -2
  64. package/dist/cli/dotenv.js.map +1 -1
  65. package/dist/cli/launcher.js +5 -5
  66. package/dist/cli/launcher.js.map +1 -1
  67. package/dist/cli/main.d.ts +1 -0
  68. package/dist/cli/main.js +85 -0
  69. package/dist/cli/main.js.map +1 -0
  70. package/dist/cli/supervise.d.ts +2 -0
  71. package/dist/cli/supervise.js +67 -4
  72. package/dist/cli/supervise.js.map +1 -1
  73. package/dist/config/agent-config.d.ts +34 -11
  74. package/dist/config/agent-config.js +116 -60
  75. package/dist/config/agent-config.js.map +1 -1
  76. package/dist/config.d.ts +4 -0
  77. package/dist/config.js +19 -6
  78. package/dist/config.js.map +1 -1
  79. package/dist/fs/atomic.d.ts +1 -0
  80. package/dist/fs/atomic.js +4 -1
  81. package/dist/fs/atomic.js.map +1 -1
  82. package/dist/fs/stat.d.ts +1 -0
  83. package/dist/fs/stat.js +11 -0
  84. package/dist/fs/stat.js.map +1 -0
  85. package/dist/http/context.d.ts +31 -12
  86. package/dist/http/context.js +60 -24
  87. package/dist/http/context.js.map +1 -1
  88. package/dist/http/csp.d.ts +2 -1
  89. package/dist/http/csp.js +3 -2
  90. package/dist/http/csp.js.map +1 -1
  91. package/dist/onboarding.d.ts +2 -2
  92. package/dist/onboarding.js +10 -8
  93. package/dist/onboarding.js.map +1 -1
  94. package/dist/profiles/profiles.d.ts +20 -4
  95. package/dist/profiles/profiles.js +115 -30
  96. package/dist/profiles/profiles.js.map +1 -1
  97. package/dist/projects.d.ts +15 -6
  98. package/dist/projects.js +55 -47
  99. package/dist/projects.js.map +1 -1
  100. package/dist/providers/catalog.d.ts +84 -14
  101. package/dist/providers/catalog.js +474 -151
  102. package/dist/providers/catalog.js.map +1 -1
  103. package/dist/providers/env-file.d.ts +10 -3
  104. package/dist/providers/env-file.js +24 -75
  105. package/dist/providers/env-file.js.map +1 -1
  106. package/dist/providers/runtime-env.d.ts +4 -2
  107. package/dist/providers/runtime-env.js +9 -6
  108. package/dist/providers/runtime-env.js.map +1 -1
  109. package/dist/providers/tables.d.ts +3 -1
  110. package/dist/providers/tables.js +4 -2
  111. package/dist/providers/tables.js.map +1 -1
  112. package/dist/raster-image.d.ts +7 -0
  113. package/dist/raster-image.js +267 -0
  114. package/dist/raster-image.js.map +1 -0
  115. package/dist/redact.js +342 -46
  116. package/dist/redact.js.map +1 -1
  117. package/dist/release.d.ts +7 -0
  118. package/dist/release.js +14 -0
  119. package/dist/release.js.map +1 -1
  120. package/dist/runtime.d.ts +5 -1
  121. package/dist/runtime.js +305 -96
  122. package/dist/runtime.js.map +1 -1
  123. package/dist/server.js +15 -0
  124. package/dist/server.js.map +1 -1
  125. package/dist/sessions/anchor.d.ts +9 -3
  126. package/dist/sessions/anchor.js +28 -36
  127. package/dist/sessions/anchor.js.map +1 -1
  128. package/dist/sessions/background-events.d.ts +2 -0
  129. package/dist/sessions/background-events.js +10 -0
  130. package/dist/sessions/background-events.js.map +1 -0
  131. package/dist/sessions/background-tasks.d.ts +26 -27
  132. package/dist/sessions/background-tasks.js +89 -97
  133. package/dist/sessions/background-tasks.js.map +1 -1
  134. package/dist/sessions/background-updates.d.ts +15 -8
  135. package/dist/sessions/background-updates.js +101 -25
  136. package/dist/sessions/background-updates.js.map +1 -1
  137. package/dist/sessions/cli-sessions.d.ts +27 -6
  138. package/dist/sessions/cli-sessions.js +152 -42
  139. package/dist/sessions/cli-sessions.js.map +1 -1
  140. package/dist/sessions/completions.d.ts +77 -9
  141. package/dist/sessions/completions.js +482 -45
  142. package/dist/sessions/completions.js.map +1 -1
  143. package/dist/sessions/compress.d.ts +8 -0
  144. package/dist/sessions/compress.js +2 -2
  145. package/dist/sessions/compress.js.map +1 -1
  146. package/dist/sessions/drafts.d.ts +14 -10
  147. package/dist/sessions/drafts.js +38 -43
  148. package/dist/sessions/drafts.js.map +1 -1
  149. package/dist/sessions/export.d.ts +5 -0
  150. package/dist/sessions/export.js +30 -0
  151. package/dist/sessions/export.js.map +1 -1
  152. package/dist/sessions/gateway-sessions.d.ts +46 -0
  153. package/dist/sessions/gateway-sessions.js +378 -0
  154. package/dist/sessions/gateway-sessions.js.map +1 -0
  155. package/dist/sessions/gateway-watcher.d.ts +7 -3
  156. package/dist/sessions/gateway-watcher.js +31 -19
  157. package/dist/sessions/gateway-watcher.js.map +1 -1
  158. package/dist/sessions/goals.d.ts +31 -0
  159. package/dist/sessions/goals.js +75 -0
  160. package/dist/sessions/goals.js.map +1 -0
  161. package/dist/sessions/handoff.d.ts +32 -0
  162. package/dist/sessions/handoff.js +114 -0
  163. package/dist/sessions/handoff.js.map +1 -0
  164. package/dist/sessions/journal.d.ts +5 -79
  165. package/dist/sessions/journal.js +15 -606
  166. package/dist/sessions/journal.js.map +1 -1
  167. package/dist/sessions/list.d.ts +31 -16
  168. package/dist/sessions/list.js +139 -129
  169. package/dist/sessions/list.js.map +1 -1
  170. package/dist/sessions/merge.d.ts +69 -13
  171. package/dist/sessions/merge.js +265 -64
  172. package/dist/sessions/merge.js.map +1 -1
  173. package/dist/sessions/notices.d.ts +22 -0
  174. package/dist/sessions/notices.js +72 -0
  175. package/dist/sessions/notices.js.map +1 -0
  176. package/dist/sessions/pending.d.ts +10 -4
  177. package/dist/sessions/pending.js +83 -7
  178. package/dist/sessions/pending.js.map +1 -1
  179. package/dist/sessions/prefix-index.d.ts +82 -0
  180. package/dist/sessions/prefix-index.js +232 -0
  181. package/dist/sessions/prefix-index.js.map +1 -0
  182. package/dist/sessions/recovery.d.ts +19 -0
  183. package/dist/sessions/recovery.js +322 -0
  184. package/dist/sessions/recovery.js.map +1 -0
  185. package/dist/sessions/relay.d.ts +38 -19
  186. package/dist/sessions/relay.js +302 -79
  187. package/dist/sessions/relay.js.map +1 -1
  188. package/dist/sessions/service.d.ts +260 -55
  189. package/dist/sessions/service.js +1448 -462
  190. package/dist/sessions/service.js.map +1 -1
  191. package/dist/sessions/session.d.ts +24 -2
  192. package/dist/sessions/session.js +69 -7
  193. package/dist/sessions/session.js.map +1 -1
  194. package/dist/sessions/shares.d.ts +7 -6
  195. package/dist/sessions/shares.js +22 -45
  196. package/dist/sessions/shares.js.map +1 -1
  197. package/dist/sessions/source-kind.js +1 -0
  198. package/dist/sessions/source-kind.js.map +1 -1
  199. package/dist/sessions/state-db-identity.d.ts +18 -0
  200. package/dist/sessions/state-db-identity.js +67 -0
  201. package/dist/sessions/state-db-identity.js.map +1 -0
  202. package/dist/sessions/state-db-worker.d.ts +1 -0
  203. package/dist/sessions/state-db-worker.js +35 -0
  204. package/dist/sessions/state-db-worker.js.map +1 -0
  205. package/dist/sessions/state-db.d.ts +113 -7
  206. package/dist/sessions/state-db.js +861 -44
  207. package/dist/sessions/state-db.js.map +1 -1
  208. package/dist/sessions/storage/backend.d.ts +162 -0
  209. package/dist/sessions/storage/backend.js +19 -0
  210. package/dist/sessions/storage/backend.js.map +1 -0
  211. package/dist/sessions/storage/conformance.d.ts +20 -0
  212. package/dist/sessions/storage/conformance.js +237 -0
  213. package/dist/sessions/storage/conformance.js.map +1 -0
  214. package/dist/sessions/storage/document.d.ts +16 -0
  215. package/dist/sessions/storage/document.js +44 -0
  216. package/dist/sessions/storage/document.js.map +1 -0
  217. package/dist/sessions/storage/json-documents.d.ts +23 -0
  218. package/dist/sessions/storage/json-documents.js +233 -0
  219. package/dist/sessions/storage/json-documents.js.map +1 -0
  220. package/dist/sessions/storage/json-files.d.ts +12 -0
  221. package/dist/sessions/storage/json-files.js +124 -0
  222. package/dist/sessions/storage/json-files.js.map +1 -0
  223. package/dist/sessions/storage/json-installation.d.ts +3 -0
  224. package/dist/sessions/storage/json-installation.js +31 -0
  225. package/dist/sessions/storage/json-installation.js.map +1 -0
  226. package/dist/sessions/storage/json-journal.d.ts +114 -0
  227. package/dist/sessions/storage/json-journal.js +686 -0
  228. package/dist/sessions/storage/json-journal.js.map +1 -0
  229. package/dist/sessions/storage/json-recovery.d.ts +4 -0
  230. package/dist/sessions/storage/json-recovery.js +195 -0
  231. package/dist/sessions/storage/json-recovery.js.map +1 -0
  232. package/dist/sessions/storage/json.d.ts +68 -0
  233. package/dist/sessions/storage/json.js +258 -0
  234. package/dist/sessions/storage/json.js.map +1 -0
  235. package/dist/sessions/storage/row.d.ts +6 -0
  236. package/dist/sessions/storage/row.js +49 -0
  237. package/dist/sessions/storage/row.js.map +1 -0
  238. package/dist/sessions/storage/search-text.d.ts +4 -0
  239. package/dist/sessions/storage/search-text.js +16 -0
  240. package/dist/sessions/storage/search-text.js.map +1 -0
  241. package/dist/sessions/store.d.ts +65 -68
  242. package/dist/sessions/store.js +305 -602
  243. package/dist/sessions/store.js.map +1 -1
  244. package/dist/sessions/streams.d.ts +4 -0
  245. package/dist/sessions/streams.js +9 -1
  246. package/dist/sessions/streams.js.map +1 -1
  247. package/dist/sessions/titles.d.ts +2 -0
  248. package/dist/sessions/titles.js +5 -1
  249. package/dist/sessions/titles.js.map +1 -1
  250. package/dist/sessions/todo.d.ts +5 -0
  251. package/dist/sessions/todo.js +28 -21
  252. package/dist/sessions/todo.js.map +1 -1
  253. package/dist/sessions/tool-display.d.ts +5 -4
  254. package/dist/sessions/tool-display.js +30 -50
  255. package/dist/sessions/tool-display.js.map +1 -1
  256. package/dist/sessions/turn-context.d.ts +11 -2
  257. package/dist/sessions/turn-context.js +18 -11
  258. package/dist/sessions/turn-context.js.map +1 -1
  259. package/dist/sessions/turn.d.ts +122 -17
  260. package/dist/sessions/turn.js +939 -358
  261. package/dist/sessions/turn.js.map +1 -1
  262. package/dist/sessions/wakeup-pause.d.ts +54 -0
  263. package/dist/sessions/wakeup-pause.js +163 -0
  264. package/dist/sessions/wakeup-pause.js.map +1 -0
  265. package/dist/sessions/window.js +13 -12
  266. package/dist/sessions/window.js.map +1 -1
  267. package/dist/settings.d.ts +19 -7
  268. package/dist/settings.js +178 -184
  269. package/dist/settings.js.map +1 -1
  270. package/dist/sidecar/client.d.ts +17 -3
  271. package/dist/sidecar/client.js +78 -8
  272. package/dist/sidecar/client.js.map +1 -1
  273. package/dist/sidecar/discover.d.ts +2 -1
  274. package/dist/sidecar/discover.js +93 -10
  275. package/dist/sidecar/discover.js.map +1 -1
  276. package/dist/sidecar/env.d.ts +4 -0
  277. package/dist/sidecar/env.js +3 -0
  278. package/dist/sidecar/env.js.map +1 -0
  279. package/dist/sidecar/fake.d.ts +2 -2
  280. package/dist/sidecar/fake.js +19 -2
  281. package/dist/sidecar/fake.js.map +1 -1
  282. package/dist/startup.d.ts +13 -5
  283. package/dist/startup.js +48 -0
  284. package/dist/startup.js.map +1 -1
  285. package/dist/test/env-file.d.ts +5 -0
  286. package/dist/test/env-file.js +88 -0
  287. package/dist/test/env-file.js.map +1 -0
  288. package/dist/test/harness.d.ts +1 -0
  289. package/dist/test/harness.js +1 -1
  290. package/dist/test/harness.js.map +1 -1
  291. package/dist/test/passkeys.d.ts +22 -0
  292. package/dist/test/passkeys.js +62 -0
  293. package/dist/test/passkeys.js.map +1 -0
  294. package/dist/test/storage.d.ts +15 -0
  295. package/dist/test/storage.js +26 -0
  296. package/dist/test/storage.js.map +1 -0
  297. package/dist/test/ts-worker-hooks.d.ts +1 -0
  298. package/dist/test/ts-worker-hooks.js +24 -0
  299. package/dist/test/ts-worker-hooks.js.map +1 -0
  300. package/dist/text/diff.d.ts +9 -14
  301. package/dist/text/diff.js +74 -108
  302. package/dist/text/diff.js.map +1 -1
  303. package/dist/tools/commands.d.ts +6 -1
  304. package/dist/tools/commands.js +8 -2
  305. package/dist/tools/commands.js.map +1 -1
  306. package/dist/tools/connectors.d.ts +33 -0
  307. package/dist/tools/connectors.js +121 -0
  308. package/dist/tools/connectors.js.map +1 -0
  309. package/dist/tools/crons.d.ts +38 -1
  310. package/dist/tools/crons.js +122 -18
  311. package/dist/tools/crons.js.map +1 -1
  312. package/dist/tools/dashboard-plugins.d.ts +53 -0
  313. package/dist/tools/dashboard-plugins.js +188 -0
  314. package/dist/tools/dashboard-plugins.js.map +1 -0
  315. package/dist/tools/extensions.d.ts +18 -5
  316. package/dist/tools/extensions.js +344 -266
  317. package/dist/tools/extensions.js.map +1 -1
  318. package/dist/tools/gateway-restart.d.ts +62 -0
  319. package/dist/tools/gateway-restart.js +142 -0
  320. package/dist/tools/gateway-restart.js.map +1 -0
  321. package/dist/tools/health.d.ts +44 -0
  322. package/dist/tools/health.js +201 -46
  323. package/dist/tools/health.js.map +1 -1
  324. package/dist/tools/hygiene.d.ts +4 -3
  325. package/dist/tools/hygiene.js +23 -9
  326. package/dist/tools/hygiene.js.map +1 -1
  327. package/dist/tools/kanban.d.ts +4 -2
  328. package/dist/tools/kanban.js +28 -19
  329. package/dist/tools/kanban.js.map +1 -1
  330. package/dist/tools/mcp.d.ts +13 -0
  331. package/dist/tools/mcp.js +88 -0
  332. package/dist/tools/mcp.js.map +1 -1
  333. package/dist/tools/memory-masks.d.ts +5 -0
  334. package/dist/tools/memory-masks.js +256 -0
  335. package/dist/tools/memory-masks.js.map +1 -0
  336. package/dist/tools/memory.d.ts +29 -3
  337. package/dist/tools/memory.js +69 -27
  338. package/dist/tools/memory.js.map +1 -1
  339. package/dist/tools/plugin-settings.d.ts +15 -0
  340. package/dist/tools/plugin-settings.js +90 -0
  341. package/dist/tools/plugin-settings.js.map +1 -0
  342. package/dist/tools/project-os.d.ts +11 -0
  343. package/dist/tools/project-os.js +267 -0
  344. package/dist/tools/project-os.js.map +1 -0
  345. package/dist/tools/skills.d.ts +14 -5
  346. package/dist/tools/skills.js +49 -16
  347. package/dist/tools/skills.js.map +1 -1
  348. package/dist/tools/update-notifications.d.ts +34 -15
  349. package/dist/tools/update-notifications.js +141 -57
  350. package/dist/tools/update-notifications.js.map +1 -1
  351. package/dist/tools/update-rollback.d.ts +11 -0
  352. package/dist/tools/update-rollback.js +28 -0
  353. package/dist/tools/update-rollback.js.map +1 -0
  354. package/dist/tools/updates.d.ts +110 -32
  355. package/dist/tools/updates.js +1112 -294
  356. package/dist/tools/updates.js.map +1 -1
  357. package/dist/tools/wiki.d.ts +68 -0
  358. package/dist/tools/wiki.js +413 -0
  359. package/dist/tools/wiki.js.map +1 -0
  360. package/dist/util.d.ts +2 -0
  361. package/dist/util.js +5 -0
  362. package/dist/util.js.map +1 -1
  363. package/dist/workspace/escape.d.ts +61 -0
  364. package/dist/workspace/escape.js +149 -0
  365. package/dist/workspace/escape.js.map +1 -0
  366. package/dist/workspace/extract.d.ts +22 -0
  367. package/dist/workspace/extract.js +308 -0
  368. package/dist/workspace/extract.js.map +1 -0
  369. package/dist/workspace/fs.d.ts +12 -0
  370. package/dist/workspace/fs.js +92 -23
  371. package/dist/workspace/fs.js.map +1 -1
  372. package/dist/workspace/git.d.ts +34 -1
  373. package/dist/workspace/git.js +328 -35
  374. package/dist/workspace/git.js.map +1 -1
  375. package/dist/workspace/media.d.ts +16 -13
  376. package/dist/workspace/media.js +43 -61
  377. package/dist/workspace/media.js.map +1 -1
  378. package/dist/workspace/rollback.d.ts +36 -22
  379. package/dist/workspace/rollback.js +178 -272
  380. package/dist/workspace/rollback.js.map +1 -1
  381. package/dist/workspace/unzip.js +4 -1
  382. package/dist/workspace/unzip.js.map +1 -1
  383. package/dist/workspace/upload.d.ts +7 -4
  384. package/dist/workspace/upload.js +5 -2
  385. package/dist/workspace/upload.js.map +1 -1
  386. package/dist/workspace/workspaces.d.ts +15 -19
  387. package/dist/workspace/workspaces.js +55 -127
  388. package/dist/workspace/workspaces.js.map +1 -1
  389. package/dist/workspace/worktrees.d.ts +2 -1
  390. package/dist/workspace/worktrees.js +179 -42
  391. package/dist/workspace/worktrees.js.map +1 -1
  392. package/package.json +7 -3
  393. package/sidecar/agent_dependency.json +4 -4
  394. package/sidecar/agent_support.json +26 -0
  395. package/sidecar/scripts/record-fixtures.py +12 -3
  396. package/sidecar/scripts/replay_sidecar.py +32 -0
  397. package/sidecar/scripts/suite_runner.py +302 -0
  398. package/sidecar/scripts/test.sh +12 -4
  399. package/sidecar/talaria_sidecar/__init__.py +6 -1
  400. package/sidecar/talaria_sidecar/__main__.py +4 -2
  401. package/sidecar/talaria_sidecar/agent_mutation.py +975 -0
  402. package/sidecar/talaria_sidecar/agent_services.py +1053 -0
  403. package/sidecar/talaria_sidecar/dependency_sync.py +85 -0
  404. package/sidecar/talaria_sidecar/home.py +56 -3
  405. package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
  406. package/sidecar/talaria_sidecar/methods/aux.py +166 -24
  407. package/sidecar/talaria_sidecar/methods/chat.py +852 -135
  408. package/sidecar/talaria_sidecar/methods/checkpoints.py +89 -0
  409. package/sidecar/talaria_sidecar/methods/commands.py +294 -4
  410. package/sidecar/talaria_sidecar/methods/config.py +123 -4
  411. package/sidecar/talaria_sidecar/methods/connectors.py +343 -0
  412. package/sidecar/talaria_sidecar/methods/cron.py +395 -36
  413. package/sidecar/talaria_sidecar/methods/cron_execution.py +284 -0
  414. package/sidecar/talaria_sidecar/methods/gateway.py +212 -55
  415. package/sidecar/talaria_sidecar/methods/gateway_sessions.py +234 -0
  416. package/sidecar/talaria_sidecar/methods/goals.py +81 -41
  417. package/sidecar/talaria_sidecar/methods/kanban.py +108 -34
  418. package/sidecar/talaria_sidecar/methods/mcp.py +1 -1
  419. package/sidecar/talaria_sidecar/methods/memory.py +84 -0
  420. package/sidecar/talaria_sidecar/methods/oauth.py +5 -2
  421. package/sidecar/talaria_sidecar/methods/process.py +218 -15
  422. package/sidecar/talaria_sidecar/methods/profiles.py +121 -13
  423. package/sidecar/talaria_sidecar/methods/providers.py +217 -28
  424. package/sidecar/talaria_sidecar/methods/runtime.py +69 -1
  425. package/sidecar/talaria_sidecar/methods/skills.py +67 -4
  426. package/sidecar/talaria_sidecar/methods/state_db.py +316 -75
  427. package/sidecar/talaria_sidecar/methods/stt.py +159 -78
  428. package/sidecar/talaria_sidecar/methods/text.py +14 -1
  429. package/sidecar/talaria_sidecar/methods/toolsets.py +49 -0
  430. package/sidecar/talaria_sidecar/methods/usage.py +113 -14
  431. package/sidecar/talaria_sidecar/methods/worktree.py +26 -19
  432. package/sidecar/talaria_sidecar/methods/write_approval.py +181 -0
  433. package/sidecar/talaria_sidecar/rpc.py +45 -4
  434. package/sidecar/talaria_sidecar/runtime.py +98 -13
  435. package/sidecar/talaria_sidecar/speed.py +35 -0
  436. package/static/dist/FILES.txt +126 -126
  437. package/static/dist/assets/AppShell-cey33v9s.js +8 -0
  438. package/static/dist/assets/ChatPage-i8wnugr7.js +18 -0
  439. package/static/dist/assets/ConnectTargets-hg19553x.js +1 -0
  440. package/static/dist/assets/ExtensionRoute-cly4apm5.js +1 -0
  441. package/static/dist/assets/Field-j8uqoigz.js +9 -0
  442. package/static/dist/assets/HubRoute-e4bgz41j.js +2 -0
  443. package/static/dist/assets/Markdown-lahuichm.js +598 -0
  444. package/static/dist/assets/RightPanel-lbo4i0fn.js +1 -0
  445. package/static/dist/assets/Select-gqatm2e0.js +1 -0
  446. package/static/dist/assets/SessionListPanel-mfqayfjh.js +1 -0
  447. package/static/dist/assets/SettingsLayout-b8980u7k.js +1 -0
  448. package/static/dist/assets/States-e7dkgtxf.js +1 -0
  449. package/static/dist/assets/Toaster-bfqqy786.js +1 -0
  450. package/static/dist/assets/_app-n1n6pfx1.js +1 -0
  451. package/static/dist/assets/{_app.ext._extensionId-opyh9y0v.js → _app.ext._extensionId-buxjxav3.js} +1 -1
  452. package/static/dist/assets/_app.index-jt8zwiu2.js +1 -0
  453. package/static/dist/assets/_app.insights-cv76ml71.js +1 -0
  454. package/static/dist/assets/_app.kanban-h6ts53j7.js +1 -0
  455. package/static/dist/assets/_app.logs-dm873z90.js +1 -0
  456. package/static/dist/assets/_app.memory-glk5y6m8.js +1 -0
  457. package/static/dist/assets/_app.profiles-ka6zpstq.js +1 -0
  458. package/static/dist/assets/{_app.session._sessionId-bfd4h3id.js → _app.session._sessionId-g2vzghvc.js} +1 -1
  459. package/static/dist/assets/_app.settings-hgjdhzcd.js +1 -0
  460. package/static/dist/assets/_app.settings._section-jf2kmhae.js +3 -0
  461. package/static/dist/assets/_app.skills-cii852yq.js +1 -0
  462. package/static/dist/assets/_app.tasks-fp9q7atm.js +1 -0
  463. package/static/dist/assets/_app.todos-dw94qzue.js +1 -0
  464. package/static/dist/assets/_app.workspaces-inyygzze.js +1 -0
  465. package/static/dist/assets/{abnfDiagram-VCTEODGH-b2x1lqot.js → abnfDiagram-VCTEODGH-gjayq3ra.js} +1 -1
  466. package/static/dist/assets/architecture-7GRP2DOG-lp56972r.js +1 -0
  467. package/static/dist/assets/{architectureDiagram-5GKGNRK7-h38o5l7b.js → architectureDiagram-5GKGNRK7-nwb3xovn.js} +1 -1
  468. package/static/dist/assets/archive-b1j004vn.js +1 -0
  469. package/static/dist/assets/back-g74gkozu.js +1 -0
  470. package/static/dist/assets/{blockDiagram-I7D4REHJ-bqquxv2u.js → blockDiagram-I7D4REHJ-joedghi3.js} +1 -1
  471. package/static/dist/assets/{c4Diagram-7LVT6UL2-f3fb8w6z.js → c4Diagram-7LVT6UL2-hyrjrohe.js} +1 -1
  472. package/static/dist/assets/channel-es95o4y8.js +1 -0
  473. package/static/dist/assets/{chunk-4HAMMTFA-bzfyyzp3.js → chunk-4HAMMTFA-koouqbut.js} +1 -1
  474. package/static/dist/assets/{chunk-75Z2AOVW-ly99rfx5.js → chunk-75Z2AOVW-bl4bhdnt.js} +1 -1
  475. package/static/dist/assets/{chunk-DU6HZSFF-bg6ecfqf.js → chunk-DU6HZSFF-gpedttsp.js} +3 -3
  476. package/static/dist/assets/{chunk-F27PBJKO-e8k7mmqw.js → chunk-F27PBJKO-d8xxi0zi.js} +1 -1
  477. package/static/dist/assets/{chunk-GMAD6QVW-cmalnoaj.js → chunk-GMAD6QVW-jro0hl73.js} +1 -1
  478. package/static/dist/assets/{chunk-GVQU2GXP-gmif5o01.js → chunk-GVQU2GXP-djn6gbyu.js} +1 -1
  479. package/static/dist/assets/{chunk-IMKFNOWR-f1nwwh6u.js → chunk-IMKFNOWR-vw4p5p7o.js} +1 -1
  480. package/static/dist/assets/{chunk-L3NEJ4N5-oktfh5v7.js → chunk-L3NEJ4N5-n1hj77q8.js} +1 -1
  481. package/static/dist/assets/{chunk-OSK3NFVY-b1sdx96z.js → chunk-OSK3NFVY-oy0gwn2n.js} +1 -1
  482. package/static/dist/assets/{chunk-P2QGCYS3-fhu4nzxt.js → chunk-P2QGCYS3-onf1hz6c.js} +1 -1
  483. package/static/dist/assets/{chunk-POPQ4Y6H-em31rnef.js → chunk-POPQ4Y6H-m8sqn7cs.js} +1 -1
  484. package/static/dist/assets/{chunk-PWAF6VOD-bxhhyftw.js → chunk-PWAF6VOD-ek4smc8x.js} +1 -1
  485. package/static/dist/assets/{chunk-SHT3W25Y-fmrvwcav.js → chunk-SHT3W25Y-g9gfvefo.js} +3 -3
  486. package/static/dist/assets/{chunk-SVP7TREG-lymukl2j.js → chunk-SVP7TREG-f9nfv2cu.js} +1 -1
  487. package/static/dist/assets/{chunk-TICWLB2K-lmza6k23.js → chunk-TICWLB2K-bnk3m1mq.js} +1 -1
  488. package/static/dist/assets/classDiagram-ZZMXUADV-kmihoqxh.js +1 -0
  489. package/static/dist/assets/classDiagram-v2-VYDZK3BY-kmihoqxh.js +1 -0
  490. package/static/dist/assets/copied-bli9tbcx.js +1 -0
  491. package/static/dist/assets/{copy-fw5b1pc6.js → copy-jamtd1pf.js} +1 -1
  492. package/static/dist/assets/{cynefin-OW5HDTMX-czlhbyhs.js → cynefin-OW5HDTMX-f8xfdd3f.js} +1 -1
  493. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-gq7mvswb.js → cynefinDiagram-5FMLGOSQ-n9lb99h9.js} +1 -1
  494. package/static/dist/assets/{dagre-GXQ25YYZ-cqdbf7dr.js → dagre-GXQ25YYZ-dgailddi.js} +4 -4
  495. package/static/dist/assets/{diagram-S7CK7UJ4-o6arxa58.js → diagram-S7CK7UJ4-m6aeoe7c.js} +1 -1
  496. package/static/dist/assets/{diagram-UQ7AKVKN-nhnd68tz.js → diagram-UQ7AKVKN-jall3j0x.js} +1 -1
  497. package/static/dist/assets/{diagram-VSXAHHWV-dk2sclzn.js → diagram-VSXAHHWV-hbawi7hn.js} +1 -1
  498. package/static/dist/assets/{diagram-VX7I27RA-n3k5nyx3.js → diagram-VX7I27RA-hendl2tt.js} +1 -1
  499. package/static/dist/assets/{diagram-Z3DM3KII-m6q9cwdh.js → diagram-Z3DM3KII-igwc35p3.js} +1 -1
  500. package/static/dist/assets/{ebnfDiagram-PWID7BFC-lsa5641p.js → ebnfDiagram-PWID7BFC-c64knz08.js} +1 -1
  501. package/static/dist/assets/{erDiagram-RLTQ6QDP-fo2ckbe6.js → erDiagram-RLTQ6QDP-brdu9lcm.js} +1 -1
  502. package/static/dist/assets/eventmodeling-NTZA5JFV-njk1j8wl.js +1 -0
  503. package/static/dist/assets/flowDiagram-HODETNUW-nma6f0ga.js +1 -0
  504. package/static/dist/assets/folder-plus-lvt9kudb.js +1 -0
  505. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-nzqz6x9g.js → ganttDiagram-EL5Y4UJY-ma6jxj5i.js} +1 -1
  506. package/static/dist/assets/{gitGraph-4MIJSDKK-gukvcxe6.js → gitGraph-4MIJSDKK-naa9w6xa.js} +1 -1
  507. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-lqhdp8f0.js → gitGraphDiagram-WWUBYQGX-hzltvsod.js} +1 -1
  508. package/static/dist/assets/{highlighted-body-KPVGNVTW-igw6cp39.js → highlighted-body-KPVGNVTW-ghoavj8d.js} +1 -1
  509. package/static/dist/assets/host-hzm8n85n.js +1 -0
  510. package/static/dist/assets/index-drdcaqeq.css +2 -0
  511. package/static/dist/assets/index-jzm844he.js +11 -0
  512. package/static/dist/assets/{info-A6RAGUB7-gvu7a93l.js → info-A6RAGUB7-mn2ut5ko.js} +1 -1
  513. package/static/dist/assets/{infoDiagram-27XIBGKW-m8t8g6w1.js → infoDiagram-27XIBGKW-h6kuqvsb.js} +1 -1
  514. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-l07vkbgj.js → ishikawaDiagram-5VMMS53U-e7bnwq7h.js} +1 -1
  515. package/static/dist/assets/{journeyDiagram-3NMN7TZE-hybkgj8l.js → journeyDiagram-3NMN7TZE-etd1bi6p.js} +1 -1
  516. package/static/dist/assets/{kanban-definition-UXKFOSKX-by13uvtn.js → kanban-definition-UXKFOSKX-emb1g9dz.js} +4 -4
  517. package/static/dist/assets/lazyRouteComponent-o816ytzl.js +1 -0
  518. package/static/dist/assets/{line-osxq6fq7.js → line-h0ojzsvs.js} +1 -1
  519. package/static/dist/assets/link-k01ryaf9.js +1 -0
  520. package/static/dist/assets/login-bsae49ew.js +1 -0
  521. package/static/dist/assets/mermaid-HWGCJPDP-ihl34s74.js +1 -0
  522. package/static/dist/assets/{mermaid-parser.core-i91oxmou.js → mermaid-parser.core-bnre27u8.js} +3 -3
  523. package/static/dist/assets/{mindmap-definition-YA3MSWOX-m82mx8ww.js → mindmap-definition-YA3MSWOX-o1vathns.js} +1 -1
  524. package/static/dist/assets/onboarding-c65tysya.js +1 -0
  525. package/static/dist/assets/onboarding_model_label-gpn28uix.js +1 -0
  526. package/static/dist/assets/{packet-AYTQ26CC-nbtgge2o.js → packet-AYTQ26CC-hatq7m2e.js} +1 -1
  527. package/static/dist/assets/pcmTap.worklet-74EKjWAZ.js +1 -0
  528. package/static/dist/assets/{pegDiagram-XKGWAZYB-f1zxzga1.js → pegDiagram-XKGWAZYB-gwisz8jv.js} +1 -1
  529. package/static/dist/assets/{pie-WAS4IAKB-of8vuhxs.js → pie-WAS4IAKB-fpftf0mk.js} +1 -1
  530. package/static/dist/assets/{pieDiagram-E7YTZNPT-o7y8ftio.js → pieDiagram-E7YTZNPT-khm1o9a6.js} +1 -1
  531. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-iqiwia1t.js → quadrantDiagram-AXDQQJYC-owqc4uqn.js} +1 -1
  532. package/static/dist/assets/{radar-RG4KPBEZ-delnsy2v.js → radar-RG4KPBEZ-cntfwjpq.js} +1 -1
  533. package/static/dist/assets/{railroad-74A4TZTK-nspnyq9u.js → railroad-74A4TZTK-a7t5eibp.js} +1 -1
  534. package/static/dist/assets/railroad-abnf-HS5TGJTU-ol8cdktf.js +1 -0
  535. package/static/dist/assets/railroad-ebnf-LZEXJU2U-i8vzd429.js +1 -0
  536. package/static/dist/assets/railroad-peg-WCYAUIDC-nw3ulewz.js +1 -0
  537. package/static/dist/assets/{railroadDiagram-O6MQD6OU-z41tqx5z.js → railroadDiagram-O6MQD6OU-etuh0qa0.js} +1 -1
  538. package/static/dist/assets/{refresh-cw-nt1dtsx4.js → refresh-cw-mqbkv2a3.js} +1 -1
  539. package/static/dist/assets/refresh-l29ljp76.js +1 -0
  540. package/static/dist/assets/{requirementDiagram-BXWQKSXE-bdvif194.js → requirementDiagram-BXWQKSXE-oq2ulk22.js} +1 -1
  541. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-h73e0rol.js → sankeyDiagram-P5KCCOFB-iqc02emv.js} +1 -1
  542. package/static/dist/assets/saved-ndd4t2xb.js +1 -0
  543. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-iv95mb1z.js → sequenceDiagram-WJ2MYXX4-i0v116q0.js} +2 -2
  544. package/static/dist/assets/settings_section_extensions_title-jhfo6o8z.js +1 -0
  545. package/static/dist/assets/share._token-c1ri0hy1.js +2 -0
  546. package/static/dist/assets/sliders-horizontal-j3jjt9tv.js +1 -0
  547. package/static/dist/assets/{stateDiagram-D77RDMKH-k417ixmf.js → stateDiagram-D77RDMKH-dnpt1ato.js} +1 -1
  548. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-bxjacpk6.js +1 -0
  549. package/static/dist/assets/{swimlanes-42K2YHIH-esola70w.js → swimlanes-42K2YHIH-loqbdazb.js} +1 -1
  550. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-id62p9hz.js +8 -0
  551. package/static/dist/assets/{timeline-definition-24CTP7MA-getrz2y8.js → timeline-definition-24CTP7MA-ol2hnvma.js} +1 -1
  552. package/static/dist/assets/toast-i3h34v6o.js +64 -0
  553. package/static/dist/assets/{treeView-Q6P3EWNA-hc7ap1q7.js → treeView-Q6P3EWNA-idrj6iox.js} +1 -1
  554. package/static/dist/assets/{treemap-WGGIJYW6-b7k1syy5.js → treemap-WGGIJYW6-lzr49vv5.js} +1 -1
  555. package/static/dist/assets/untitled-oaoya4qj.js +1 -0
  556. package/static/dist/assets/useForm-nfaxgmsk.js +1 -0
  557. package/static/dist/assets/{useParams-lhg566ew.js → useParams-gjc70qru.js} +1 -1
  558. package/static/dist/assets/{useSearch-lbrh6ejn.js → useSearch-e6ae539u.js} +1 -1
  559. package/static/dist/assets/{vennDiagram-4TSXK5OY-n6pcy5qb.js → vennDiagram-4TSXK5OY-bvwr9o2z.js} +1 -1
  560. package/static/dist/assets/{wardley-WFR3VGLG-lpa18vz1.js → wardley-WFR3VGLG-31ui8tma.js} +1 -1
  561. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-kpclwwg7.js → wardleyDiagram-VM6X3IG4-k5wqtx4b.js} +1 -1
  562. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-paa2n8y0.js → xychartDiagram-S5SC5T6Z-aqbgvujg.js} +1 -1
  563. package/static/dist/index.html +1 -1
  564. package/static/dist/sw.js +1 -1
  565. package/static/dist/assets/AppShell-fb2td9zi.js +0 -1
  566. package/static/dist/assets/ChatPage-cj96kiy9.js +0 -25
  567. package/static/dist/assets/Dialog-kxcg7ard.js +0 -1
  568. package/static/dist/assets/ExtensionRoute-jf7h0754.js +0 -1
  569. package/static/dist/assets/HubRoute-gmanpd5y.js +0 -2
  570. package/static/dist/assets/Markdown-mdwlvj3w.js +0 -598
  571. package/static/dist/assets/RightPanel-ftvrjlcp.js +0 -1
  572. package/static/dist/assets/Select-bilaypej.js +0 -1
  573. package/static/dist/assets/SessionListPanel-og8n36qs.js +0 -1
  574. package/static/dist/assets/SettingsLayout-jonjefmj.js +0 -1
  575. package/static/dist/assets/States-nmejrwrm.js +0 -1
  576. package/static/dist/assets/Toaster-nnl8zkt9.js +0 -1
  577. package/static/dist/assets/_app-gdidzd94.js +0 -1
  578. package/static/dist/assets/_app.index-hbarzbjx.js +0 -1
  579. package/static/dist/assets/_app.insights-luywlarz.js +0 -1
  580. package/static/dist/assets/_app.kanban-kincnbr8.js +0 -1
  581. package/static/dist/assets/_app.logs-oi2gr3gs.js +0 -1
  582. package/static/dist/assets/_app.memory-b6jfivt6.js +0 -1
  583. package/static/dist/assets/_app.profiles-lpvixmqp.js +0 -1
  584. package/static/dist/assets/_app.settings-vowx3iq0.js +0 -1
  585. package/static/dist/assets/_app.settings._section-cnntg1tu.js +0 -3
  586. package/static/dist/assets/_app.skills-fb57lpau.js +0 -1
  587. package/static/dist/assets/_app.tasks-eszpx1q7.js +0 -2
  588. package/static/dist/assets/_app.todos-nr05ac6w.js +0 -1
  589. package/static/dist/assets/_app.workspaces-d2luomu6.js +0 -1
  590. package/static/dist/assets/architecture-7GRP2DOG-hd0o7bde.js +0 -1
  591. package/static/dist/assets/back-bemaer09.js +0 -1
  592. package/static/dist/assets/cancel-drd0g6d9.js +0 -1
  593. package/static/dist/assets/channel-cpdgf867.js +0 -1
  594. package/static/dist/assets/classDiagram-ZZMXUADV-ko09sguk.js +0 -1
  595. package/static/dist/assets/classDiagram-v2-VYDZK3BY-ko09sguk.js +0 -1
  596. package/static/dist/assets/copied-ima3pysb.js +0 -1
  597. package/static/dist/assets/endpoints-d33siokx.js +0 -64
  598. package/static/dist/assets/eventmodeling-NTZA5JFV-emctlo64.js +0 -1
  599. package/static/dist/assets/flowDiagram-HODETNUW-bfi3moqa.js +0 -1
  600. package/static/dist/assets/index-cxq58xb1.js +0 -11
  601. package/static/dist/assets/index-hgtx08n5.css +0 -2
  602. package/static/dist/assets/lazyRouteComponent-af0lvgjx.js +0 -1
  603. package/static/dist/assets/link-jyxicdhg.js +0 -1
  604. package/static/dist/assets/login-ec21t39x.js +0 -1
  605. package/static/dist/assets/mermaid-HWGCJPDP-gfl8z3ep.js +0 -1
  606. package/static/dist/assets/onboarding-btnltvyz.js +0 -1
  607. package/static/dist/assets/onboarding_model_label-dp7xffoh.js +0 -1
  608. package/static/dist/assets/railroad-abnf-HS5TGJTU-nst1qxyn.js +0 -1
  609. package/static/dist/assets/railroad-ebnf-LZEXJU2U-ci37x8qy.js +0 -1
  610. package/static/dist/assets/railroad-peg-WCYAUIDC-aimkk07z.js +0 -1
  611. package/static/dist/assets/refresh-b4uams1i.js +0 -1
  612. package/static/dist/assets/saved-kg52csy7.js +0 -1
  613. package/static/dist/assets/settings_section_extensions_title-ej0iapxe.js +0 -1
  614. package/static/dist/assets/share._token-f97e94r0.js +0 -2
  615. package/static/dist/assets/sliders-horizontal-fj18it47.js +0 -1
  616. package/static/dist/assets/sse-fwpqtzbg.js +0 -1
  617. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hwn4apct.js +0 -1
  618. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-d1h97oyg.js +0 -8
  619. package/static/dist/assets/todoStore-eginf9h4.js +0 -1
  620. package/static/dist/assets/tts-lxdxnmjd.js +0 -1
  621. package/static/dist/assets/untitled-ovpfthg4.js +0 -1
  622. package/static/dist/assets/useForm-bcblv1rx.js +0 -1
  623. package/static/dist/assets/useLocale-fi5jb8ma.js +0 -1
@@ -1,14 +1,18 @@
1
1
  /** Chat turn admission, control, approvals, clarify, goals, background tasks, and side questions. */
2
2
  import { GATEWAY_APPROVAL_RELAY_UNAVAILABLE, isGenericContinuationIntent } from '../sessions/turn.js';
3
3
  import { implement } from '@orpc/server';
4
- import { chatContract, MAX_CHAT_ATTACHMENTS } from '@maudecode/talaria-web-contracts';
4
+ import { chatContract, MAX_CHAT_ATTACHMENTS, RPC_ERROR_CODES } from '@maudecode/talaria-web-contracts';
5
5
  import { randomUUID } from 'node:crypto';
6
6
  import { HttpError } from './router.js';
7
7
  import { requestSessionIdGuard, streamOwnerSessionId, streamVisibleToRequest } from './session-visibility.js';
8
8
  import { ensureAgentRuntimeCurrent, HttpFailure } from '../sessions/service.js';
9
9
  import { SessionNotFound } from '../sessions/store.js';
10
- import { isSafeSessionId } from '../sessions/session.js';
10
+ import { compressionRecoveryPayload, isSafeSessionId } from '../sessions/session.js';
11
+ import { messageText } from '../sessions/merge.js';
11
12
  import { str } from '../util.js';
13
+ import { activeProfileName } from '../auth/gate.js';
14
+ import { SidecarError } from '../sidecar/client.js';
15
+ import { unsupportedPromptMessage } from '../tools/commands.js';
12
16
  const os = implement(chatContract).$context().use(requestSessionIdGuard);
13
17
  const STEER_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
14
18
  const PROFILE_ID_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
@@ -26,14 +30,14 @@ async function run(fn) {
26
30
  }
27
31
  }
28
32
  /** A session this request's profile may see (TAL-372 background work never crosses owners). */
29
- function visibleSession(ctx, sid) {
30
- if (!ctx.deps.sessions.sessionIdVisible(sid))
33
+ async function visibleSession(ctx, sid) {
34
+ if (!(await ctx.deps.sessions.sessionIdVisible(sid)))
31
35
  throw new HttpError(404, 'Session not found');
32
- return getSession(ctx, sid, true);
36
+ return (await getSession(ctx, sid, true));
33
37
  }
34
- function getSession(ctx, sid, metadataOnly = false) {
38
+ async function getSession(ctx, sid, metadataOnly = false) {
35
39
  try {
36
- return ctx.deps.sessionStore.get(sid, { metadataOnly });
40
+ return (await ctx.deps.sessionStore.get(sid, { metadataOnly }));
37
41
  }
38
42
  catch {
39
43
  throw new HttpError(404, 'Session not found');
@@ -87,38 +91,42 @@ function visibleOrRetag(ctx, s, requestedProfile) {
87
91
  }
88
92
  throw new HttpError(404, 'Session not found');
89
93
  }
90
- function resolveWorkspace(ctx, s, requested) {
91
- const ws = ctx.deps.workspaces;
92
- if (requested !== undefined && requested !== null && requested !== '') {
93
- try {
94
- return ws.resolveTrusted(str(requested), s.profile);
95
- }
96
- catch (error) {
97
- throw new HttpError(400, error.message);
98
- }
94
+ /**
95
+ * TAL-817: what the model gets for a typed Agent prompt built-in (`/plan`, `/initiate-setup`, …): the Agent's own expansion
96
+ * of it for this session's profile, workspace and toolsets, while the transcript keeps the typed text; null when `msg` is
97
+ * not one. One the Agent cannot expand is
98
+ * refused with the catalog's message instead of reaching the model raw. Without a sidecar the turn reports that itself.
99
+ */
100
+ async function expandPromptBuiltin(ctx, s, msg, workspace) {
101
+ const sidecar = ctx.deps.sidecar();
102
+ if (!msg.startsWith('/') || !sidecar)
103
+ return null;
104
+ // Only `/init` reads the workspace, and the sidecar refuses it without one; the turn reports a bad workspace itself.
105
+ let cwd = '';
106
+ try {
107
+ cwd = (await ctx.deps.sessions.turnWorkspace(s, workspace));
108
+ }
109
+ catch {
110
+ cwd = '';
99
111
  }
112
+ let expanded;
100
113
  try {
101
- const [workspace, recovered] = ws.resolveImplicitWithRecovery(s.workspace, (p) => ws.lastWorkspace(p), s.profile);
102
- if (recovered)
103
- s.workspace = workspace;
104
- return workspace;
114
+ expanded = await sidecar.call('commands.expand_prompt', {
115
+ profile_home: ctx.deps.profileHome(s.profile ?? activeProfileName(ctx)), command: msg, workspace: cwd, enabled_toolsets: s.enabled_toolsets,
116
+ }, { timeoutMs: 120_000 });
105
117
  }
106
118
  catch (error) {
107
- throw new HttpError(400, error.message);
119
+ if (!(error instanceof SidecarError))
120
+ throw error;
121
+ const invalid = error.condition === 'invalid_params' || error.code === RPC_ERROR_CODES.invalidParams;
122
+ throw new HttpError(invalid ? 400 : error.condition === 'sidecar_unavailable' ? 503 : 502, error.message);
108
123
  }
109
- }
110
- /** A `@provider:` id is split; any other model an explicit pick did not just choose is checked against the catalog (TAL-542). */
111
- function modelState(ctx, s, body) {
112
- const requestedModel = str(body.model) || s.model;
113
- const requestedProvider = 'model_provider' in body ? body.model_provider : s.model_provider;
114
- const [model, provider] = ctx.deps.sessions.deps.modelStateFromRequest(requestedModel, requestedProvider, s.model_provider);
115
- if (model !== requestedModel || !model || body.explicit_model_pick === true)
116
- return [model, provider, model !== requestedModel];
117
- const repaired = ctx.deps.sessions.deps.repairSessionModel?.(s.profile ?? null, model, provider);
118
- return repaired ? [repaired[0], repaired[1], true] : [model, provider, false];
124
+ if (expanded.name !== null && expanded.message === null)
125
+ throw new HttpError(400, unsupportedPromptMessage(expanded.name));
126
+ return expanded.message;
119
127
  }
120
128
  /** `chat.start`; a `chat.steer` sent while a background turn runs starts the user's turn through it too (TAL-460). */
121
- async function startChat(ctx, body) {
129
+ async function startChat(ctx, body, settle = {}) {
122
130
  requireField(body, 'session_id');
123
131
  if (str(body.message).trim() === '[SILENT]')
124
132
  return { status: 'suppressed', reason: 'silent_control_message' };
@@ -128,26 +136,31 @@ async function startChat(ctx, body) {
128
136
  // Python `_agent_runtime_barrier_response`: a stale local Agent checkout is refused with a typed 409 before any
129
137
  // session state is materialised, claimed, or mutated.
130
138
  await ensureAgentRuntimeCurrent(ctx.deps.sidecar());
139
+ if (ctx.deps.sessions.owner?.isOwned(sid)) {
140
+ if (!(await ctx.deps.sessions.sessionIdVisible(sid)))
141
+ throw new HttpError(404, 'Session not found');
142
+ return (await ctx.deps.sessions.owner.submit(sid, body));
143
+ }
131
144
  // TAL-542: the stale-model check reads this catalog; it is built before the session is read so no await follows that read.
132
145
  await ctx.deps.sessions.deps.warmSessionModelRepair?.();
133
146
  let s;
134
147
  try {
135
- s = ctx.deps.sessionStore.get(sid);
148
+ s = (await ctx.deps.sessionStore.get(sid));
136
149
  }
137
150
  catch {
138
151
  // Python `_claim_or_synthesize_cli_session` on the POST path: a claimable foreign (CLI/TUI/Desktop) session is
139
152
  // materialised as a WebUI sidecar before its first turn; an owned foreign store answers 403, nothing → 404.
140
- const synth = ctx.deps.sessions.claimOrSynthesizeCliSession(sid);
153
+ const synth = (await ctx.deps.sessions.claimOrSynthesizeCliSession(sid));
141
154
  if (!synth.session)
142
155
  throw new HttpError(404, 'Session not found');
143
156
  if (synth.reason === 'not_claimable')
144
157
  throw new HttpError(403, 'session is read-only in its foreign store; cannot be claimed writeable in WebUI');
145
- ctx.deps.sessionStore.save(synth.session);
146
- s = ctx.deps.sessionStore.get(sid);
158
+ await ctx.deps.sessionStore.save(synth.session);
159
+ s = (await ctx.deps.sessionStore.get(sid));
147
160
  }
148
161
  // Python `_get_or_materialize_session` raised PermissionError for both: a read-only import and a delegated
149
162
  // subagent child (by sidecar tag or state.db row), which chat start answered with the same 403.
150
- if (ctx.deps.sessions.isReadOnly(s) || s.branchSourceReadonly || ctx.deps.sessions.isSubagentViewOnly(sid))
163
+ if ((await ctx.deps.sessions.isReadOnly(s)) || s.branchSourceReadonly || (await ctx.deps.sessions.isSubagentViewOnly(sid)))
151
164
  throw new HttpError(403, 'Read-only imported sessions cannot be continued from WebUI');
152
165
  const requestedProfile = str(body.profile).trim();
153
166
  if (requestedProfile && requestedProfile !== 'default' && !PROFILE_ID_RE.test(requestedProfile))
@@ -158,29 +171,84 @@ async function startChat(ctx, body) {
158
171
  // TAL-276: an attached file alone makes a turn; one with neither text nor a file path is refused.
159
172
  if (!msg && !attachments.some((att) => str(att.path)))
160
173
  throw new HttpError(400, 'message is required');
174
+ const prompt = await expandPromptBuiltin(ctx, s, msg, body.workspace);
161
175
  // TAL-460: the user's message never joins a background turn; that turn stops quietly and this one takes its place.
162
- if (await ctx.deps.turns.yieldBackgroundTurn(sid)) {
176
+ const yielded = await ctx.deps.turns.yieldBackgroundTurn(sid);
177
+ if (prompt !== null || yielded) {
163
178
  await ctx.deps.sessions.deps.warmSessionModelRepair?.();
164
- s = ctx.deps.sessionStore.get(sid);
179
+ s = (await ctx.deps.sessionStore.get(sid));
180
+ visibleOrRetag(ctx, s, requestedProfile);
165
181
  }
166
182
  // Python `compression_recovery_payload_for_session` + `is_generic_continuation_intent`.
167
- const recovery = s.compression_recovery;
168
- const recoveryLive = recovery.terminal_state === 'compression_exhausted' && str(recovery.recommended_action || s.recommended_recovery_action) === 'start_focused_continuation';
169
- if (recoveryLive && !attachments.length && isGenericContinuationIntent(msg)) {
183
+ if (compressionRecoveryPayload(s) && !attachments.length && isGenericContinuationIntent(msg)) {
170
184
  throw new HttpError(409, 'This session exhausted context compression. Start a focused continuation, then describe the next narrow task.', { type: 'compression_recovery_required', compression_recovery: s.compression_recovery, session_id: s.session_id });
171
185
  }
172
- const workspace = resolveWorkspace(ctx, s, body.workspace);
173
- const [model, provider, normalized] = modelState(ctx, s, body);
186
+ const workspace = (await ctx.deps.sessions.turnWorkspace(s, body.workspace));
187
+ const [model, provider, normalized] = ctx.deps.sessions.turnModel(s, body);
174
188
  if (body.moa_config)
175
189
  throw new HttpError(503, 'MoA overrides need the Agent command registry (checkpoint 7).');
176
- const response = ctx.deps.turns.start(s, { msg, attachments, workspace, model, modelProvider: provider, normalizedModel: normalized, source: 'webui' });
190
+ const response = (await ctx.deps.turns.start(s, { msg, ...(prompt === null ? {} : { prompt }), attachments, workspace, model, modelProvider: provider, normalizedModel: normalized, source: 'webui', voiceTurn: body.voice_turn === true, connectCard: body.connect_card === true, skillSecret: body.skill_secret === true, ...settle }));
177
191
  if (response._status !== undefined && response._status >= 400)
178
192
  throw new HttpError(response._status, response.error ?? 'chat start failed', response.active_stream_id ? { active_stream_id: response.active_stream_id } : {});
179
193
  return startPayload(response);
180
194
  }
195
+ /**
196
+ * Legacy `POST /api/chat`: the `chat.start` admission, then the turn awaited to its end. A turn that was cancelled, or
197
+ * failed after streaming text, answers `partial` with that text; any other failure answers with its error frame.
198
+ */
199
+ async function syncChat(ctx, body) {
200
+ if (ctx.deps.sessions.owner?.isOwned(str(body.session_id)))
201
+ throw new HttpError(409, 'This owner requires the asynchronous chat stream', { code: 'owner_requires_streaming' });
202
+ if ((await ctx.deps.sessions.isSubagentViewOnly(str(body.session_id))))
203
+ throw new HttpError(400, 'Subagent sessions are view-only and cannot be written from WebUI');
204
+ if (!str(body.message).trim())
205
+ throw new HttpError(400, 'empty message');
206
+ let outcome = null;
207
+ const started = await startChat(ctx, { session_id: body.session_id, message: body.message, workspace: body.workspace, model: body.model, ...('model_provider' in body ? { model_provider: body.model_provider } : {}) }, {
208
+ onDone: (answer) => { outcome = { answer }; },
209
+ onFailed: (failure) => { outcome = failure; },
210
+ });
211
+ const streamId = str(started.stream_id);
212
+ if (streamId)
213
+ await ctx.deps.turns.finished(streamId);
214
+ const s = (await getSession(ctx, str(body.session_id)));
215
+ const session = (await ctx.deps.turns.publicTerminalSession(s));
216
+ const ended = outcome;
217
+ // A `[SILENT]` control message starts no turn.
218
+ if (!streamId || (ended && 'answer' in ended)) {
219
+ const answer = ended && 'answer' in ended ? ended.answer : '';
220
+ return { answer, status: 'done', session, result: { final_response: answer, completed: true, interrupted: false } };
221
+ }
222
+ const partial = s.messages.filter((m) => m._turn_id === streamId && m._partial).map((m) => messageText(m.content)).join('').trim();
223
+ const cancelled = ended?.cancelled ?? false;
224
+ if (cancelled || (ended?.apperror && partial))
225
+ return { answer: partial, status: 'partial', session, result: { final_response: partial, completed: false, interrupted: cancelled } };
226
+ if (ended?.apperror) {
227
+ const { message, ...rest } = ended.apperror;
228
+ const type = str(rest.type);
229
+ throw new HttpError(type === 'agent_runtime_stale' ? 409 : type === 'sidecar_unavailable' ? 503 : 500, str(message) || 'chat failed', rest);
230
+ }
231
+ // Python `_chat_writeback_timeout_response`: the turn ended but another stream owned the session at writeback.
232
+ throw new HttpError(503, 'response persistence is uncertain', { code: 'chat_writeback_timeout', message: 'The response finished but could not be persisted because this session remained busy. Do not retry automatically; refresh the session first.', retryable: false, outcome_unknown: true });
233
+ }
181
234
  export const chatRouter = os.router({
182
235
  chat: {
183
- start: os.chat.start.handler(({ input, context: { ctx } }) => run(() => startChat(ctx, input))),
236
+ ownerAction: os.chat.ownerAction.handler(({ input, context: { ctx } }) => run(async () => {
237
+ if (!(await ctx.deps.sessions.sessionIdVisible(input.session_id)))
238
+ throw new HttpError(404, 'Session not found');
239
+ const owner = ctx.deps.sessions.owner;
240
+ if (!owner)
241
+ throw new HttpError(503, 'Native session controls are unavailable');
242
+ let draft;
243
+ if (input.action === 'retry') {
244
+ draft = await owner.retry(input.session_id, input.admission_id, input.execution_generation);
245
+ }
246
+ else
247
+ await owner.action(input.session_id, input);
248
+ return { ok: true, session: await ctx.deps.sessions.detail(input.session_id, {}), ...(draft === undefined ? {} : { draft }) };
249
+ })),
250
+ sync: os.chat.sync.handler(({ input, context: { ctx } }) => run(async () => (await syncChat(ctx, input)))),
251
+ start: os.chat.start.handler(({ input, context: { ctx } }) => run(async () => (await startChat(ctx, input)))),
184
252
  steer: os.chat.steer.handler(({ input, context: { ctx } }) => run(async () => {
185
253
  const sid = str(input.session_id).trim();
186
254
  const text = str(input.text).trim();
@@ -194,43 +262,52 @@ export const chatRouter = os.router({
194
262
  throw new HttpError(400, 'steer_id must be 1-128 URL-safe characters');
195
263
  if (!steerId)
196
264
  steerId = `steer-${randomUUID()}`;
197
- if (!ctx.deps.sessions.sessionIdVisible(sid))
265
+ if (!(await ctx.deps.sessions.sessionIdVisible(sid)))
198
266
  throw new HttpError(404, 'Session not found');
199
267
  const active = ctx.deps.registry.activeRunStreamForSession(sid);
200
268
  if (active && ctx.deps.registry.activeRuns.get(active)?.origin === 'background') {
201
269
  const started = await startChat(ctx, { session_id: sid, message: text });
202
270
  return { accepted: true, fallback: null, stream_id: started.stream_id ? str(started.stream_id) : null, steer_id: steerId, started_turn: started };
203
271
  }
204
- return ctx.deps.turns.steer(sid, text, display, steerId);
272
+ // TAL-817: a prompt built-in steers with its expansion; the steer still shows as typed. A missing session is the steer's to report.
273
+ let target = null;
274
+ try {
275
+ target = (await ctx.deps.sessionStore.get(sid, { metadataOnly: true }));
276
+ }
277
+ catch {
278
+ target = null;
279
+ }
280
+ const prompt = target ? await expandPromptBuiltin(ctx, target, text, undefined) : null;
281
+ return (await ctx.deps.turns.steer(sid, prompt ?? text, display || (prompt === null ? '' : text), steerId));
205
282
  })),
206
283
  // TAL-424: Edit, Cancel and Send now on a pending steer; unknown or already-taken steers answer false.
207
284
  steerWithdraw: os.chat.steerWithdraw.handler(({ input, context: { ctx } }) => run(async () => {
208
- if (!ctx.deps.sessions.sessionIdVisible(input.session_id))
285
+ if (!(await ctx.deps.sessions.sessionIdVisible(input.session_id)))
209
286
  throw new HttpError(404, 'Session not found');
210
- return ctx.deps.turns.withdrawSteer(input.session_id, input.steer_id, input.reason);
287
+ return (await ctx.deps.turns.withdrawSteer(input.session_id, input.steer_id, input.reason));
211
288
  })),
212
289
  steerSendNow: os.chat.steerSendNow.handler(({ input, context: { ctx } }) => run(async () => {
213
- if (!ctx.deps.sessions.sessionIdVisible(input.session_id))
290
+ if (!(await ctx.deps.sessions.sessionIdVisible(input.session_id)))
214
291
  throw new HttpError(404, 'Session not found');
215
- return ctx.deps.turns.sendSteerNow(input.session_id, input.steer_id);
292
+ return (await ctx.deps.turns.sendSteerNow(input.session_id, input.steer_id));
216
293
  })),
217
294
  cancel: os.chat.cancel.handler(({ input, context: { ctx } }) => run(async () => {
218
295
  const streamId = str(input.stream_id);
219
296
  if (!streamId)
220
297
  throw new HttpError(400, 'stream_id required');
221
- if (!streamVisibleToRequest(ctx, streamId))
298
+ if (!(await streamVisibleToRequest(ctx, streamId)))
222
299
  throw new HttpError(404, 'Session not found');
223
300
  const { cancelled, withdrawn } = await ctx.deps.turns.cancel(streamId);
224
301
  return { ok: true, cancelled, stream_id: streamId, withdrawn_steers: withdrawn };
225
302
  })),
226
- streamStatus: os.chat.streamStatus.handler(({ input, context: { ctx } }) => run(() => {
303
+ streamStatus: os.chat.streamStatus.handler(({ input, context: { ctx } }) => run(async () => {
227
304
  const streamId = str(input.stream_id);
228
- if (!streamVisibleToRequest(ctx, streamId))
305
+ if (!(await streamVisibleToRequest(ctx, streamId)))
229
306
  throw new HttpError(404, 'Session not found');
230
307
  const active = ctx.deps.registry.liveIds.has(streamId);
231
- const owner = streamOwnerSessionId(ctx, streamId);
232
- const payload = { active, stream_id: streamId, replay_available: false, blocking_stream_id: owner ? ctx.deps.sessions.activeRunBlocking(owner) : null };
233
- const summary = streamId ? ctx.deps.journal.findRunSummary(streamId) : null;
308
+ const owner = (await streamOwnerSessionId(ctx, streamId));
309
+ const payload = { active, stream_id: streamId, replay_available: false, blocking_stream_id: owner ? (await ctx.deps.sessions.activeRunBlocking(owner)) : null };
310
+ const summary = streamId ? (await ctx.deps.journal.findRunSummary(streamId)) : null;
234
311
  if (summary) {
235
312
  payload.replay_available = true;
236
313
  const terminal = summary.terminal;
@@ -240,7 +317,7 @@ export const chatRouter = os.router({
240
317
  })),
241
318
  },
242
319
  approval: {
243
- pending: os.approval.pending.handler(({ input, context: { ctx } }) => run(() => ctx.deps.pending.approvalPending(str(input.session_id)))),
320
+ pending: os.approval.pending.handler(({ input, context: { ctx } }) => run(() => ctx.deps.sessions.owner?.isOwned(str(input.session_id)) ? ctx.deps.sessions.owner.pending(str(input.session_id), 'approval') : ctx.deps.pending.approvalPending(str(input.session_id)))),
244
321
  respond: os.approval.respond.handler(({ input, context: { ctx } }) => run(async () => {
245
322
  const sid = str(input.session_id);
246
323
  if (!sid)
@@ -261,14 +338,15 @@ export const chatRouter = os.router({
261
338
  })),
262
339
  },
263
340
  clarify: {
264
- pending: os.clarify.pending.handler(({ input, context: { ctx } }) => run(() => ctx.deps.pending.clarifyPending(str(input.session_id)))),
341
+ pending: os.clarify.pending.handler(({ input, context: { ctx } }) => run(() => ctx.deps.sessions.owner?.isOwned(str(input.session_id)) ? ctx.deps.sessions.owner.pending(str(input.session_id), 'clarify') : ctx.deps.pending.clarifyPending(str(input.session_id)))),
265
342
  respond: os.clarify.respond.handler(({ input, context: { ctx } }) => run(async () => {
266
343
  const sid = str(input.session_id);
267
344
  if (!sid)
268
345
  throw new HttpError(400, 'session_id is required');
269
- // Keyed step answers are shaped by the server; a raw `response` is relayed as-is for older clients.
270
- const reply = input.answers ?? str(input.response ?? input.answer ?? input.choice).trim();
271
- if (!reply)
346
+ // Both keyed answers and older clients' raw replies are shaped against the pending prompt; only a vault prompt
347
+ // takes a decline (TAL-887).
348
+ const reply = input.decline === true ? null : input.answers ?? str(input.response ?? input.answer ?? input.choice).trim();
349
+ if (reply === '')
272
350
  throw new HttpError(400, 'response is required');
273
351
  const result = await ctx.deps.turns.respondClarify(sid, str(input.clarify_id), reply);
274
352
  if (result.stale)
@@ -277,7 +355,8 @@ export const chatRouter = os.router({
277
355
  throw new HttpError(400, 'answers must answer every question of the pending clarification', { ok: false });
278
356
  if (!result.ok)
279
357
  throw new HttpError(503, result.error ?? 'clarify relay failed', { ok: false });
280
- return { ok: true, response: str(result.response) };
358
+ // A vault answer is never echoed back.
359
+ return result.response === undefined ? { ok: true } : { ok: true, response: result.response };
281
360
  })),
282
361
  },
283
362
  goal: os.goal.handler(({ input, context: { ctx } }) => run(async () => {
@@ -288,10 +367,10 @@ export const chatRouter = os.router({
288
367
  return { status: 'suppressed', reason: 'silent_control_message' };
289
368
  const sid = str(body.session_id);
290
369
  // Python: a delegated subagent child is view-only; its goal state is never mutated and no turn starts on it.
291
- if (ctx.deps.sessions.isSubagentViewOnly(sid))
370
+ if ((await ctx.deps.sessions.isSubagentViewOnly(sid)))
292
371
  throw new HttpError(400, 'Subagent sessions are view-only and cannot run /goal from WebUI');
293
- const s = getSession(ctx, sid);
294
- if (ctx.deps.sessions.isReadOnly(s) || s.branchSourceReadonly)
372
+ const s = (await getSession(ctx, sid));
373
+ if ((await ctx.deps.sessions.isReadOnly(s)) || s.branchSourceReadonly)
295
374
  throw new HttpError(403, 'Read-only imported sessions cannot be continued from WebUI');
296
375
  const requestedProfile = str(body.profile).trim();
297
376
  if (requestedProfile && requestedProfile !== 'default' && !PROFILE_ID_RE.test(requestedProfile))
@@ -302,7 +381,7 @@ export const chatRouter = os.router({
302
381
  if (s.active_stream_id) {
303
382
  streamRunning = ctx.deps.registry.liveIds.has(s.active_stream_id);
304
383
  if (!streamRunning)
305
- ctx.deps.sessions.clearStaleStreamState(s);
384
+ (await ctx.deps.sessions.clearStaleStreamState(s));
306
385
  }
307
386
  const sidecar = ctx.deps.sidecar();
308
387
  if (!sidecar)
@@ -322,21 +401,29 @@ export const chatRouter = os.router({
322
401
  defaultMaxTurns = 20;
323
402
  }
324
403
  const snapshot = await sidecar.call('goals.snapshot', { session_id: sid, profile_home: profileHome, default_max_turns: defaultMaxTurns });
325
- const payload = await sidecar.call('goals.command', { session_id: sid, profile_home: profileHome, args, stream_running: streamRunning, default_max_turns: defaultMaxTurns });
326
- if (payload.ok === false)
327
- throw new HttpError(payload.error === 'agent_running' ? 409 : 400, str(payload.message || payload.error || 'goal command failed'), payload);
404
+ ctx.deps.sessions.assertWritable(s);
405
+ const payload = await sidecar.call('goals.command', { session_id: sid, profile_home: profileHome, args, stream_running: streamRunning, default_max_turns: defaultMaxTurns, workspace: str(s.workspace) || undefined });
406
+ // TAL-808: the session `goal` follows the command before the client reloads the session.
407
+ await ctx.deps.turns.refreshGoal(s);
408
+ if (payload.ok === false) {
409
+ // Clients show the body's `error`, so the Agent's reason replaces the sidecar's code there.
410
+ const reason = str(payload.message || payload.error || 'goal command failed');
411
+ throw new HttpError(payload.error === 'agent_running' ? 409 : 400, reason, { ...payload, error: reason });
412
+ }
328
413
  const kickoff = str(payload.kickoff_prompt).trim();
329
414
  if (kickoff) {
330
415
  // TAL-542: after the goal RPCs, so the stale-model check reads a catalog for the profile the session now runs under.
331
416
  await ctx.deps.sessions.deps.warmSessionModelRepair?.(s.profile);
332
- const workspace = resolveWorkspace(ctx, s, body.workspace);
333
- const [model, provider, normalized] = modelState(ctx, s, body);
334
- const started = ctx.deps.turns.start(s, { msg: kickoff, attachments: [], workspace, model, modelProvider: provider, normalizedModel: normalized, source: 'webui', goalRelated: true });
417
+ const workspace = (await ctx.deps.sessions.turnWorkspace(s, body.workspace));
418
+ const [model, provider, normalized] = ctx.deps.sessions.turnModel(s, body);
419
+ const started = (await ctx.deps.turns.start(s, { msg: kickoff, attachments: [], workspace, model, modelProvider: provider, normalizedModel: normalized, source: 'webui', goalRelated: true }));
335
420
  if (started._status !== undefined && started._status >= 400) {
336
421
  try {
422
+ (ctx.deps.sessions.assertWritable(s));
337
423
  await sidecar.call('goals.restore', { session_id: sid, profile_home: profileHome, snapshot: snapshot.snapshot });
338
424
  }
339
425
  catch { /* best effort */ }
426
+ await ctx.deps.turns.refreshGoal(s);
340
427
  throw new HttpError(started._status, started.error ?? 'goal kickoff failed', { ...payload, ok: false });
341
428
  }
342
429
  Object.assign(payload, startPayload(started));
@@ -348,74 +435,69 @@ export const chatRouter = os.router({
348
435
  const body = input;
349
436
  requireField(body, 'session_id', 'prompt');
350
437
  // A subagent child's profile/workspace/context must never seed a runnable background session.
351
- if (ctx.deps.sessions.isSubagentViewOnly(str(body.session_id)))
438
+ if ((await ctx.deps.sessions.isSubagentViewOnly(str(body.session_id))))
352
439
  throw new HttpError(400, 'Subagent sessions are view-only and cannot run background tasks from WebUI');
353
440
  // TAL-542: the background turn starts on the parent's repaired pair; the catalog is built before the parent is read.
354
441
  await ctx.deps.sessions.deps.warmSessionModelRepair?.();
355
- const parent = getSession(ctx, str(body.session_id));
356
- if (ctx.deps.sessions.isReadOnly(parent) || parent.branchSourceReadonly)
442
+ const parent = (await getSession(ctx, str(body.session_id)));
443
+ if ((await ctx.deps.sessions.isReadOnly(parent)) || parent.branchSourceReadonly)
357
444
  throw new HttpError(403, 'Read-only imported sessions cannot be continued from WebUI');
358
445
  const prompt = str(body.prompt).trim();
359
446
  if (!prompt)
360
447
  throw new HttpError(400, 'prompt is required');
361
- const [model, modelProvider] = modelState(ctx, parent, {});
362
- const bg = ctx.deps.sessionStore.newSession({ workspace: parent.workspace, model, modelProvider, profile: parent.profile });
448
+ const [model, modelProvider] = ctx.deps.sessions.turnModel(parent, {});
449
+ const bg = (await ctx.deps.sessionStore.newSession({ workspace: parent.workspace, model, modelProvider, profile: parent.profile }));
363
450
  bg.title = `bg: ${prompt.slice(0, 60)}`;
364
- ctx.deps.sessionStore.save(bg);
365
- // Python: `uuid.uuid4().hex[:8]`; a failed run still completes the task so `/api/background/status` can report it,
451
+ await ctx.deps.sessionStore.save(bg);
452
+ // Python: `uuid.uuid4().hex[:8]`; a failed run still completes the task so `/api/background/tasks` reports it,
366
453
  // and the hidden bg session file is removed afterwards.
367
454
  const taskId = randomUUID().replace(/-/g, '').slice(0, 8);
368
455
  // TAL-372: the parent session keeps the task's record and result, so every client and a restart see it.
369
- ctx.deps.background.trackCommand(parent.session_id, taskId, prompt);
370
- const cleanup = () => { try {
371
- ctx.deps.sessionStore.deleteFiles(bg.session_id, { tombstone: false });
456
+ await ctx.deps.background.trackCommand(parent.session_id, taskId, prompt);
457
+ const cleanup = async () => { try {
458
+ (await ctx.deps.sessionStore.delete(bg.session_id, { tombstone: false }));
372
459
  }
373
460
  catch { /* best effort */ } };
374
- const started = ctx.deps.turns.start(bg, {
461
+ const started = (await ctx.deps.turns.start(bg, {
375
462
  msg: prompt, attachments: [], workspace: parent.workspace, model, modelProvider, source: 'webui',
376
- onDone: (answer) => { ctx.deps.background.settleCommand(parent.session_id, taskId, 'completed', answer); cleanup(); },
377
- onFailed: () => { ctx.deps.background.settleCommand(parent.session_id, taskId, 'failed', '(background task failed)'); cleanup(); },
378
- });
463
+ // Python: the last non-error assistant reply with content, else "(no answer produced)".
464
+ onDone: async (answer) => { (await ctx.deps.background.settleCommand(parent.session_id, taskId, 'completed', answer || '(no answer produced)')); (await cleanup()); },
465
+ onFailed: async () => { (await ctx.deps.background.settleCommand(parent.session_id, taskId, 'failed', '(background task failed)')); (await cleanup()); },
466
+ }));
379
467
  if (started._status !== undefined && started._status >= 400) {
380
468
  // Admission refused (profile deleting, session busy…): nothing runs, so the tracked task and hidden
381
469
  // session must not linger as "running".
382
- ctx.deps.background.forgetCommand(parent.session_id, taskId);
383
- cleanup();
470
+ await ctx.deps.background.forgetCommand(parent.session_id, taskId);
471
+ await cleanup();
384
472
  throw new HttpError(started._status, started.error ?? 'background start failed');
385
473
  }
386
- ctx.deps.background.setCommandStream(parent.session_id, taskId, str(started.stream_id));
474
+ await ctx.deps.background.setCommandStream(parent.session_id, taskId, str(started.stream_id));
387
475
  return { ok: true, task_id: taskId, stream_id: str(started.stream_id), session_id: bg.session_id };
388
476
  })),
389
- status: os.background.status.handler(({ input, context: { ctx } }) => run(() => {
390
- const sid = str(input.session_id);
391
- if (!sid)
392
- throw new HttpError(400, 'Missing session_id');
393
- return { results: ctx.deps.background.legacyResults(sid) };
394
- })),
395
477
  tasks: os.background.tasks.handler(({ input, context: { ctx } }) => run(async () => {
396
- const s = visibleSession(ctx, input.session_id);
478
+ const s = (await visibleSession(ctx, input.session_id));
397
479
  const snapshot = await ctx.deps.background.snapshot(s.session_id, s.profile);
398
480
  return { session_id: s.session_id, ...snapshot, tasks: input.kind ? snapshot.tasks.filter((t) => t.kind === input.kind) : snapshot.tasks };
399
481
  })),
400
482
  result: os.background.result.handler(({ input, context: { ctx } }) => run(async () => {
401
- const s = visibleSession(ctx, input.session_id);
483
+ const s = (await visibleSession(ctx, input.session_id));
402
484
  const text = await ctx.deps.background.result(s.session_id, s.profile, input.task_id);
403
485
  if (text === null)
404
486
  throw new HttpError(404, 'No result for this background task');
405
487
  return { task_id: input.task_id, text };
406
488
  })),
407
- dismiss: os.background.dismiss.handler(({ input, context: { ctx } }) => run(() => {
408
- const s = visibleSession(ctx, input.session_id);
409
- const task = ctx.deps.background.dismiss(s.session_id, input.task_id);
489
+ dismiss: os.background.dismiss.handler(({ input, context: { ctx } }) => run(async () => {
490
+ const s = (await visibleSession(ctx, input.session_id));
491
+ const task = (await ctx.deps.background.dismiss(s.session_id, input.task_id));
410
492
  if (!task)
411
493
  throw new HttpError(404, 'Background task not found');
412
494
  return { ok: true, task };
413
495
  })),
414
- ack: os.background.ack.handler(({ input, context: { ctx } }) => run(() => {
496
+ ack: os.background.ack.handler(({ input, context: { ctx } }) => run(async () => {
415
497
  const body = input;
416
498
  requireField(body, 'session_id');
417
499
  const sid = str(body.session_id).trim();
418
- const s = getSession(ctx, sid, true);
500
+ const s = (await getSession(ctx, sid, true));
419
501
  const pid = str(body.task_id || body.process_id).trim();
420
502
  if (str(body.process_id).trim())
421
503
  ctx.extraResponseHeaders = { deprecation: 'true' };
@@ -429,31 +511,31 @@ export const chatRouter = os.router({
429
511
  if (!isSafeSessionId(sid))
430
512
  throw new HttpError(404, 'Session not found');
431
513
  // Python: a subagent child's context must not be cloned into a runnable ephemeral session.
432
- if (ctx.deps.sessions.isSubagentViewOnly(sid))
514
+ if ((await ctx.deps.sessions.isSubagentViewOnly(sid)))
433
515
  throw new HttpError(400, 'Subagent sessions are view-only and cannot be used for /btw from WebUI');
434
516
  // TAL-542: the side question starts on the chat's repaired pair; the catalog is built before the chat is read.
435
517
  await ctx.deps.sessions.deps.warmSessionModelRepair?.();
436
- const s = getSession(ctx, sid);
437
- if (ctx.deps.sessions.isReadOnly(s) || s.branchSourceReadonly)
518
+ const s = (await getSession(ctx, sid));
519
+ if ((await ctx.deps.sessions.isReadOnly(s)) || s.branchSourceReadonly)
438
520
  throw new HttpError(403, 'Read-only imported sessions cannot be continued from WebUI');
439
521
  const question = str(body.question).trim();
440
522
  if (!question)
441
523
  throw new HttpError(400, 'question is required');
442
524
  // TAL-518: a side question runs in its own hidden session, so the chat's running turn does not block it.
443
- const [model, modelProvider] = modelState(ctx, s, {});
444
- const ephemeral = ctx.deps.sessionStore.newSession({ workspace: s.workspace, model, modelProvider, profile: s.profile });
525
+ const [model, modelProvider] = ctx.deps.sessions.turnModel(s, {});
526
+ const ephemeral = (await ctx.deps.sessionStore.newSession({ workspace: s.workspace, model, modelProvider, profile: s.profile }));
445
527
  ephemeral.messages = structuredClone(s.messages);
446
528
  ephemeral.context_messages = ctx.deps.sessions.sideQuestionContext(s);
447
529
  ephemeral.title = `btw: ${question.slice(0, 60)}`;
448
- ctx.deps.sessionStore.save(ephemeral);
530
+ await ctx.deps.sessionStore.save(ephemeral);
449
531
  // TAL-512: a failed or refused btw turn must not leave its copy of the parent conversation behind.
450
- const cleanup = () => { try {
451
- ctx.deps.sessionStore.deleteFiles(ephemeral.session_id, { tombstone: false });
532
+ const cleanup = async () => { try {
533
+ (await ctx.deps.sessionStore.delete(ephemeral.session_id, { tombstone: false }));
452
534
  }
453
535
  catch { /* best effort */ } };
454
- const started = ctx.deps.turns.start(ephemeral, { msg: question, attachments: [], workspace: s.workspace, model, modelProvider, source: 'webui', ephemeral: true, onFailed: cleanup });
536
+ const started = (await ctx.deps.turns.start(ephemeral, { msg: question, attachments: [], workspace: s.workspace, model, modelProvider, source: 'webui', ephemeral: true, onFailed: cleanup }));
455
537
  if (started._status !== undefined && started._status >= 400) {
456
- cleanup();
538
+ await cleanup();
457
539
  throw new HttpError(started._status, started.error ?? 'btw start failed');
458
540
  }
459
541
  return { stream_id: str(started.stream_id), session_id: ephemeral.session_id, parent_session_id: sid };