@maudecode/talaria-web 1.18.0 → 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 (567) hide show
  1. package/_release.json +8 -8
  2. package/dist/api/auth-raw.js +16 -16
  3. package/dist/api/auth-raw.js.map +1 -1
  4. package/dist/api/automation-raw.d.ts +2 -2
  5. package/dist/api/automation-raw.js +32 -32
  6. package/dist/api/automation-raw.js.map +1 -1
  7. package/dist/api/automation-router.d.ts +102 -22
  8. package/dist/api/automation-router.js +15 -13
  9. package/dist/api/automation-router.js.map +1 -1
  10. package/dist/api/chat-router.d.ts +1205 -34
  11. package/dist/api/chat-router.js +158 -78
  12. package/dist/api/chat-router.js.map +1 -1
  13. package/dist/api/git-router.d.ts +2 -2
  14. package/dist/api/git-router.js +29 -29
  15. package/dist/api/git-router.js.map +1 -1
  16. package/dist/api/raw-routes.d.ts +3 -3
  17. package/dist/api/raw-routes.js +63 -61
  18. package/dist/api/raw-routes.js.map +1 -1
  19. package/dist/api/router.d.ts +6 -6
  20. package/dist/api/router.js +22 -22
  21. package/dist/api/router.js.map +1 -1
  22. package/dist/api/session-visibility.d.ts +4 -4
  23. package/dist/api/session-visibility.js +26 -16
  24. package/dist/api/session-visibility.js.map +1 -1
  25. package/dist/api/sessions-router.d.ts +1928 -124
  26. package/dist/api/sessions-router.js +177 -173
  27. package/dist/api/sessions-router.js.map +1 -1
  28. package/dist/api/settings-router.d.ts +427 -9
  29. package/dist/api/settings-router.js +48 -32
  30. package/dist/api/settings-router.js.map +1 -1
  31. package/dist/api/sse-routes.d.ts +2 -2
  32. package/dist/api/sse-routes.js +63 -63
  33. package/dist/api/sse-routes.js.map +1 -1
  34. package/dist/api/tools-raw.d.ts +5 -0
  35. package/dist/api/tools-raw.js +58 -33
  36. package/dist/api/tools-raw.js.map +1 -1
  37. package/dist/api/tools-router.d.ts +663 -91
  38. package/dist/api/tools-router.js +309 -52
  39. package/dist/api/tools-router.js.map +1 -1
  40. package/dist/api/transcribe-stream.d.ts +16 -0
  41. package/dist/api/transcribe-stream.js +172 -0
  42. package/dist/api/transcribe-stream.js.map +1 -0
  43. package/dist/app.d.ts +4 -1
  44. package/dist/app.js +66 -47
  45. package/dist/app.js.map +1 -1
  46. package/dist/auth/gate.js +10 -9
  47. package/dist/auth/gate.js.map +1 -1
  48. package/dist/auth/passkeys.d.ts +15 -14
  49. package/dist/auth/passkeys.js +89 -91
  50. package/dist/auth/passkeys.js.map +1 -1
  51. package/dist/auth/store.d.ts +17 -7
  52. package/dist/auth/store.js +93 -52
  53. package/dist/auth/store.js.map +1 -1
  54. package/dist/bin/talaria-web.js +12 -81
  55. package/dist/bin/talaria-web.js.map +1 -1
  56. package/dist/cli/ctl.js +2 -1
  57. package/dist/cli/ctl.js.map +1 -1
  58. package/dist/cli/dotenv.d.ts +5 -0
  59. package/dist/cli/dotenv.js +14 -2
  60. package/dist/cli/dotenv.js.map +1 -1
  61. package/dist/cli/launcher.js +5 -5
  62. package/dist/cli/launcher.js.map +1 -1
  63. package/dist/cli/main.d.ts +1 -0
  64. package/dist/cli/main.js +85 -0
  65. package/dist/cli/main.js.map +1 -0
  66. package/dist/cli/supervise.d.ts +2 -0
  67. package/dist/cli/supervise.js +67 -4
  68. package/dist/cli/supervise.js.map +1 -1
  69. package/dist/config/agent-config.d.ts +34 -11
  70. package/dist/config/agent-config.js +113 -58
  71. package/dist/config/agent-config.js.map +1 -1
  72. package/dist/config.d.ts +2 -0
  73. package/dist/config.js +14 -5
  74. package/dist/config.js.map +1 -1
  75. package/dist/fs/atomic.d.ts +1 -0
  76. package/dist/fs/atomic.js +4 -1
  77. package/dist/fs/atomic.js.map +1 -1
  78. package/dist/fs/stat.d.ts +1 -0
  79. package/dist/fs/stat.js +11 -0
  80. package/dist/fs/stat.js.map +1 -0
  81. package/dist/http/context.d.ts +14 -9
  82. package/dist/http/context.js +29 -20
  83. package/dist/http/context.js.map +1 -1
  84. package/dist/onboarding.d.ts +2 -2
  85. package/dist/onboarding.js +10 -8
  86. package/dist/onboarding.js.map +1 -1
  87. package/dist/profiles/profiles.d.ts +10 -4
  88. package/dist/profiles/profiles.js +77 -30
  89. package/dist/profiles/profiles.js.map +1 -1
  90. package/dist/projects.d.ts +15 -6
  91. package/dist/projects.js +55 -47
  92. package/dist/projects.js.map +1 -1
  93. package/dist/providers/catalog.d.ts +78 -12
  94. package/dist/providers/catalog.js +445 -141
  95. package/dist/providers/catalog.js.map +1 -1
  96. package/dist/providers/env-file.d.ts +10 -3
  97. package/dist/providers/env-file.js +24 -75
  98. package/dist/providers/env-file.js.map +1 -1
  99. package/dist/providers/runtime-env.d.ts +4 -2
  100. package/dist/providers/runtime-env.js +9 -6
  101. package/dist/providers/runtime-env.js.map +1 -1
  102. package/dist/providers/tables.d.ts +3 -1
  103. package/dist/providers/tables.js +4 -2
  104. package/dist/providers/tables.js.map +1 -1
  105. package/dist/redact.js +18 -9
  106. package/dist/redact.js.map +1 -1
  107. package/dist/release.d.ts +7 -0
  108. package/dist/release.js +14 -0
  109. package/dist/release.js.map +1 -1
  110. package/dist/runtime.d.ts +5 -1
  111. package/dist/runtime.js +233 -90
  112. package/dist/runtime.js.map +1 -1
  113. package/dist/server.js +10 -0
  114. package/dist/server.js.map +1 -1
  115. package/dist/sessions/anchor.d.ts +9 -3
  116. package/dist/sessions/anchor.js +28 -36
  117. package/dist/sessions/anchor.js.map +1 -1
  118. package/dist/sessions/background-events.d.ts +2 -0
  119. package/dist/sessions/background-events.js +10 -0
  120. package/dist/sessions/background-events.js.map +1 -0
  121. package/dist/sessions/background-tasks.d.ts +26 -20
  122. package/dist/sessions/background-tasks.js +88 -86
  123. package/dist/sessions/background-tasks.js.map +1 -1
  124. package/dist/sessions/background-updates.d.ts +15 -8
  125. package/dist/sessions/background-updates.js +101 -25
  126. package/dist/sessions/background-updates.js.map +1 -1
  127. package/dist/sessions/cli-sessions.d.ts +15 -5
  128. package/dist/sessions/cli-sessions.js +62 -43
  129. package/dist/sessions/cli-sessions.js.map +1 -1
  130. package/dist/sessions/completions.d.ts +30 -2
  131. package/dist/sessions/completions.js +294 -53
  132. package/dist/sessions/completions.js.map +1 -1
  133. package/dist/sessions/compress.d.ts +8 -0
  134. package/dist/sessions/compress.js +2 -2
  135. package/dist/sessions/compress.js.map +1 -1
  136. package/dist/sessions/drafts.d.ts +14 -10
  137. package/dist/sessions/drafts.js +38 -43
  138. package/dist/sessions/drafts.js.map +1 -1
  139. package/dist/sessions/gateway-sessions.d.ts +46 -0
  140. package/dist/sessions/gateway-sessions.js +378 -0
  141. package/dist/sessions/gateway-sessions.js.map +1 -0
  142. package/dist/sessions/goals.d.ts +31 -0
  143. package/dist/sessions/goals.js +75 -0
  144. package/dist/sessions/goals.js.map +1 -0
  145. package/dist/sessions/journal.d.ts +5 -79
  146. package/dist/sessions/journal.js +15 -606
  147. package/dist/sessions/journal.js.map +1 -1
  148. package/dist/sessions/list.d.ts +27 -18
  149. package/dist/sessions/list.js +133 -131
  150. package/dist/sessions/list.js.map +1 -1
  151. package/dist/sessions/merge.d.ts +68 -10
  152. package/dist/sessions/merge.js +259 -51
  153. package/dist/sessions/merge.js.map +1 -1
  154. package/dist/sessions/notices.d.ts +22 -0
  155. package/dist/sessions/notices.js +72 -0
  156. package/dist/sessions/notices.js.map +1 -0
  157. package/dist/sessions/pending.d.ts +10 -4
  158. package/dist/sessions/pending.js +83 -7
  159. package/dist/sessions/pending.js.map +1 -1
  160. package/dist/sessions/prefix-index.d.ts +82 -0
  161. package/dist/sessions/prefix-index.js +232 -0
  162. package/dist/sessions/prefix-index.js.map +1 -0
  163. package/dist/sessions/recovery.d.ts +4 -7
  164. package/dist/sessions/recovery.js +97 -281
  165. package/dist/sessions/recovery.js.map +1 -1
  166. package/dist/sessions/relay.d.ts +20 -20
  167. package/dist/sessions/relay.js +205 -127
  168. package/dist/sessions/relay.js.map +1 -1
  169. package/dist/sessions/service.d.ts +162 -59
  170. package/dist/sessions/service.js +1133 -521
  171. package/dist/sessions/service.js.map +1 -1
  172. package/dist/sessions/session.d.ts +18 -2
  173. package/dist/sessions/session.js +29 -5
  174. package/dist/sessions/session.js.map +1 -1
  175. package/dist/sessions/shares.d.ts +7 -6
  176. package/dist/sessions/shares.js +22 -45
  177. package/dist/sessions/shares.js.map +1 -1
  178. package/dist/sessions/source-kind.js +1 -0
  179. package/dist/sessions/source-kind.js.map +1 -1
  180. package/dist/sessions/state-db-identity.d.ts +18 -0
  181. package/dist/sessions/state-db-identity.js +67 -0
  182. package/dist/sessions/state-db-identity.js.map +1 -0
  183. package/dist/sessions/state-db-worker.js +3 -1
  184. package/dist/sessions/state-db-worker.js.map +1 -1
  185. package/dist/sessions/state-db.d.ts +53 -8
  186. package/dist/sessions/state-db.js +576 -50
  187. package/dist/sessions/state-db.js.map +1 -1
  188. package/dist/sessions/storage/backend.d.ts +162 -0
  189. package/dist/sessions/storage/backend.js +19 -0
  190. package/dist/sessions/storage/backend.js.map +1 -0
  191. package/dist/sessions/storage/conformance.d.ts +20 -0
  192. package/dist/sessions/storage/conformance.js +237 -0
  193. package/dist/sessions/storage/conformance.js.map +1 -0
  194. package/dist/sessions/storage/document.d.ts +16 -0
  195. package/dist/sessions/storage/document.js +44 -0
  196. package/dist/sessions/storage/document.js.map +1 -0
  197. package/dist/sessions/storage/json-documents.d.ts +23 -0
  198. package/dist/sessions/storage/json-documents.js +233 -0
  199. package/dist/sessions/storage/json-documents.js.map +1 -0
  200. package/dist/sessions/storage/json-files.d.ts +12 -0
  201. package/dist/sessions/storage/json-files.js +124 -0
  202. package/dist/sessions/storage/json-files.js.map +1 -0
  203. package/dist/sessions/storage/json-installation.d.ts +3 -0
  204. package/dist/sessions/storage/json-installation.js +31 -0
  205. package/dist/sessions/storage/json-installation.js.map +1 -0
  206. package/dist/sessions/storage/json-journal.d.ts +114 -0
  207. package/dist/sessions/storage/json-journal.js +686 -0
  208. package/dist/sessions/storage/json-journal.js.map +1 -0
  209. package/dist/sessions/storage/json-recovery.d.ts +4 -0
  210. package/dist/sessions/storage/json-recovery.js +195 -0
  211. package/dist/sessions/storage/json-recovery.js.map +1 -0
  212. package/dist/sessions/storage/json.d.ts +68 -0
  213. package/dist/sessions/storage/json.js +258 -0
  214. package/dist/sessions/storage/json.js.map +1 -0
  215. package/dist/sessions/storage/row.d.ts +6 -0
  216. package/dist/sessions/storage/row.js +49 -0
  217. package/dist/sessions/storage/row.js.map +1 -0
  218. package/dist/sessions/storage/search-text.d.ts +4 -0
  219. package/dist/sessions/storage/search-text.js +16 -0
  220. package/dist/sessions/storage/search-text.js.map +1 -0
  221. package/dist/sessions/store.d.ts +63 -73
  222. package/dist/sessions/store.js +305 -611
  223. package/dist/sessions/store.js.map +1 -1
  224. package/dist/sessions/streams.d.ts +4 -0
  225. package/dist/sessions/streams.js +9 -1
  226. package/dist/sessions/streams.js.map +1 -1
  227. package/dist/sessions/titles.js +1 -1
  228. package/dist/sessions/titles.js.map +1 -1
  229. package/dist/sessions/todo.d.ts +5 -0
  230. package/dist/sessions/todo.js +28 -21
  231. package/dist/sessions/todo.js.map +1 -1
  232. package/dist/sessions/tool-display.d.ts +5 -4
  233. package/dist/sessions/tool-display.js +22 -16
  234. package/dist/sessions/tool-display.js.map +1 -1
  235. package/dist/sessions/turn-context.d.ts +10 -1
  236. package/dist/sessions/turn-context.js +7 -4
  237. package/dist/sessions/turn-context.js.map +1 -1
  238. package/dist/sessions/turn.d.ts +87 -17
  239. package/dist/sessions/turn.js +795 -347
  240. package/dist/sessions/turn.js.map +1 -1
  241. package/dist/sessions/wakeup-pause.d.ts +8 -13
  242. package/dist/sessions/wakeup-pause.js +31 -49
  243. package/dist/sessions/wakeup-pause.js.map +1 -1
  244. package/dist/sessions/window.js +13 -12
  245. package/dist/sessions/window.js.map +1 -1
  246. package/dist/settings.d.ts +19 -7
  247. package/dist/settings.js +179 -183
  248. package/dist/settings.js.map +1 -1
  249. package/dist/sidecar/client.d.ts +17 -3
  250. package/dist/sidecar/client.js +78 -8
  251. package/dist/sidecar/client.js.map +1 -1
  252. package/dist/sidecar/discover.d.ts +2 -1
  253. package/dist/sidecar/discover.js +93 -10
  254. package/dist/sidecar/discover.js.map +1 -1
  255. package/dist/sidecar/env.d.ts +4 -0
  256. package/dist/sidecar/env.js +3 -0
  257. package/dist/sidecar/env.js.map +1 -0
  258. package/dist/sidecar/fake.js +19 -2
  259. package/dist/sidecar/fake.js.map +1 -1
  260. package/dist/test/env-file.d.ts +5 -0
  261. package/dist/test/env-file.js +88 -0
  262. package/dist/test/env-file.js.map +1 -0
  263. package/dist/test/harness.d.ts +1 -0
  264. package/dist/test/harness.js +1 -1
  265. package/dist/test/harness.js.map +1 -1
  266. package/dist/test/passkeys.d.ts +22 -0
  267. package/dist/test/passkeys.js +62 -0
  268. package/dist/test/passkeys.js.map +1 -0
  269. package/dist/test/storage.d.ts +15 -0
  270. package/dist/test/storage.js +26 -0
  271. package/dist/test/storage.js.map +1 -0
  272. package/dist/tools/commands.d.ts +6 -1
  273. package/dist/tools/commands.js +8 -2
  274. package/dist/tools/commands.js.map +1 -1
  275. package/dist/tools/connectors.d.ts +33 -0
  276. package/dist/tools/connectors.js +121 -0
  277. package/dist/tools/connectors.js.map +1 -0
  278. package/dist/tools/crons.d.ts +38 -1
  279. package/dist/tools/crons.js +82 -15
  280. package/dist/tools/crons.js.map +1 -1
  281. package/dist/tools/dashboard-plugins.d.ts +5 -5
  282. package/dist/tools/dashboard-plugins.js +14 -14
  283. package/dist/tools/dashboard-plugins.js.map +1 -1
  284. package/dist/tools/extensions.d.ts +5 -4
  285. package/dist/tools/extensions.js +213 -207
  286. package/dist/tools/extensions.js.map +1 -1
  287. package/dist/tools/gateway-restart.d.ts +62 -0
  288. package/dist/tools/gateway-restart.js +142 -0
  289. package/dist/tools/gateway-restart.js.map +1 -0
  290. package/dist/tools/health.d.ts +15 -3
  291. package/dist/tools/health.js +97 -34
  292. package/dist/tools/health.js.map +1 -1
  293. package/dist/tools/hygiene.d.ts +4 -3
  294. package/dist/tools/hygiene.js +23 -9
  295. package/dist/tools/hygiene.js.map +1 -1
  296. package/dist/tools/kanban.d.ts +4 -2
  297. package/dist/tools/kanban.js +28 -19
  298. package/dist/tools/kanban.js.map +1 -1
  299. package/dist/tools/memory-masks.d.ts +5 -0
  300. package/dist/tools/memory-masks.js +256 -0
  301. package/dist/tools/memory-masks.js.map +1 -0
  302. package/dist/tools/memory.d.ts +29 -3
  303. package/dist/tools/memory.js +69 -27
  304. package/dist/tools/memory.js.map +1 -1
  305. package/dist/tools/plugin-settings.d.ts +15 -0
  306. package/dist/tools/plugin-settings.js +90 -0
  307. package/dist/tools/plugin-settings.js.map +1 -0
  308. package/dist/tools/skills.d.ts +9 -4
  309. package/dist/tools/skills.js +44 -13
  310. package/dist/tools/skills.js.map +1 -1
  311. package/dist/tools/update-notifications.d.ts +34 -15
  312. package/dist/tools/update-notifications.js +141 -57
  313. package/dist/tools/update-notifications.js.map +1 -1
  314. package/dist/tools/update-rollback.d.ts +11 -0
  315. package/dist/tools/update-rollback.js +28 -0
  316. package/dist/tools/update-rollback.js.map +1 -0
  317. package/dist/tools/updates.d.ts +93 -33
  318. package/dist/tools/updates.js +1051 -345
  319. package/dist/tools/updates.js.map +1 -1
  320. package/dist/util.d.ts +2 -0
  321. package/dist/util.js +5 -0
  322. package/dist/util.js.map +1 -1
  323. package/dist/workspace/git.d.ts +16 -1
  324. package/dist/workspace/git.js +291 -11
  325. package/dist/workspace/git.js.map +1 -1
  326. package/dist/workspace/media.d.ts +12 -9
  327. package/dist/workspace/media.js +31 -20
  328. package/dist/workspace/media.js.map +1 -1
  329. package/dist/workspace/rollback.d.ts +2 -2
  330. package/dist/workspace/rollback.js +5 -5
  331. package/dist/workspace/rollback.js.map +1 -1
  332. package/dist/workspace/workspaces.d.ts +15 -19
  333. package/dist/workspace/workspaces.js +55 -127
  334. package/dist/workspace/workspaces.js.map +1 -1
  335. package/dist/workspace/worktrees.js +170 -32
  336. package/dist/workspace/worktrees.js.map +1 -1
  337. package/package.json +5 -3
  338. package/sidecar/agent_dependency.json +4 -4
  339. package/sidecar/agent_support.json +26 -0
  340. package/sidecar/scripts/record-fixtures.py +12 -3
  341. package/sidecar/scripts/replay_sidecar.py +8 -0
  342. package/sidecar/scripts/suite_runner.py +302 -0
  343. package/sidecar/scripts/test.sh +12 -4
  344. package/sidecar/talaria_sidecar/__init__.py +6 -1
  345. package/sidecar/talaria_sidecar/__main__.py +4 -2
  346. package/sidecar/talaria_sidecar/agent_mutation.py +975 -0
  347. package/sidecar/talaria_sidecar/agent_services.py +1053 -0
  348. package/sidecar/talaria_sidecar/dependency_sync.py +85 -0
  349. package/sidecar/talaria_sidecar/home.py +43 -1
  350. package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
  351. package/sidecar/talaria_sidecar/methods/aux.py +139 -31
  352. package/sidecar/talaria_sidecar/methods/chat.py +847 -134
  353. package/sidecar/talaria_sidecar/methods/commands.py +213 -4
  354. package/sidecar/talaria_sidecar/methods/config.py +123 -4
  355. package/sidecar/talaria_sidecar/methods/connectors.py +343 -0
  356. package/sidecar/talaria_sidecar/methods/cron.py +366 -34
  357. package/sidecar/talaria_sidecar/methods/cron_execution.py +284 -0
  358. package/sidecar/talaria_sidecar/methods/gateway.py +194 -54
  359. package/sidecar/talaria_sidecar/methods/gateway_sessions.py +234 -0
  360. package/sidecar/talaria_sidecar/methods/goals.py +81 -41
  361. package/sidecar/talaria_sidecar/methods/kanban.py +80 -27
  362. package/sidecar/talaria_sidecar/methods/memory.py +84 -0
  363. package/sidecar/talaria_sidecar/methods/oauth.py +5 -2
  364. package/sidecar/talaria_sidecar/methods/process.py +160 -11
  365. package/sidecar/talaria_sidecar/methods/profiles.py +44 -6
  366. package/sidecar/talaria_sidecar/methods/providers.py +196 -26
  367. package/sidecar/talaria_sidecar/methods/runtime.py +69 -1
  368. package/sidecar/talaria_sidecar/methods/skills.py +67 -4
  369. package/sidecar/talaria_sidecar/methods/state_db.py +277 -70
  370. package/sidecar/talaria_sidecar/methods/stt.py +159 -78
  371. package/sidecar/talaria_sidecar/methods/text.py +14 -1
  372. package/sidecar/talaria_sidecar/methods/toolsets.py +49 -0
  373. package/sidecar/talaria_sidecar/methods/usage.py +113 -14
  374. package/sidecar/talaria_sidecar/methods/worktree.py +26 -19
  375. package/sidecar/talaria_sidecar/methods/write_approval.py +181 -0
  376. package/sidecar/talaria_sidecar/rpc.py +45 -4
  377. package/sidecar/talaria_sidecar/runtime.py +81 -12
  378. package/sidecar/talaria_sidecar/speed.py +35 -0
  379. package/static/dist/FILES.txt +126 -127
  380. package/static/dist/assets/AppShell-cey33v9s.js +8 -0
  381. package/static/dist/assets/ChatPage-i8wnugr7.js +18 -0
  382. package/static/dist/assets/ConnectTargets-hg19553x.js +1 -0
  383. package/static/dist/assets/ExtensionRoute-cly4apm5.js +1 -0
  384. package/static/dist/assets/Field-j8uqoigz.js +9 -0
  385. package/static/dist/assets/HubRoute-e4bgz41j.js +2 -0
  386. package/static/dist/assets/Markdown-lahuichm.js +598 -0
  387. package/static/dist/assets/RightPanel-lbo4i0fn.js +1 -0
  388. package/static/dist/assets/Select-gqatm2e0.js +1 -0
  389. package/static/dist/assets/SessionListPanel-mfqayfjh.js +1 -0
  390. package/static/dist/assets/SettingsLayout-b8980u7k.js +1 -0
  391. package/static/dist/assets/States-e7dkgtxf.js +1 -0
  392. package/static/dist/assets/Toaster-bfqqy786.js +1 -0
  393. package/static/dist/assets/_app-n1n6pfx1.js +1 -0
  394. package/static/dist/assets/{_app.ext._extensionId-gfbzpoou.js → _app.ext._extensionId-buxjxav3.js} +1 -1
  395. package/static/dist/assets/_app.index-jt8zwiu2.js +1 -0
  396. package/static/dist/assets/_app.insights-cv76ml71.js +1 -0
  397. package/static/dist/assets/_app.kanban-h6ts53j7.js +1 -0
  398. package/static/dist/assets/_app.logs-dm873z90.js +1 -0
  399. package/static/dist/assets/_app.memory-glk5y6m8.js +1 -0
  400. package/static/dist/assets/_app.profiles-ka6zpstq.js +1 -0
  401. package/static/dist/assets/{_app.session._sessionId-fn1bhde6.js → _app.session._sessionId-g2vzghvc.js} +1 -1
  402. package/static/dist/assets/_app.settings-hgjdhzcd.js +1 -0
  403. package/static/dist/assets/_app.settings._section-jf2kmhae.js +3 -0
  404. package/static/dist/assets/_app.skills-cii852yq.js +1 -0
  405. package/static/dist/assets/_app.tasks-fp9q7atm.js +1 -0
  406. package/static/dist/assets/_app.todos-dw94qzue.js +1 -0
  407. package/static/dist/assets/_app.workspaces-inyygzze.js +1 -0
  408. package/static/dist/assets/{abnfDiagram-VCTEODGH-c8kdixke.js → abnfDiagram-VCTEODGH-gjayq3ra.js} +1 -1
  409. package/static/dist/assets/architecture-7GRP2DOG-lp56972r.js +1 -0
  410. package/static/dist/assets/{architectureDiagram-5GKGNRK7-cku06x1p.js → architectureDiagram-5GKGNRK7-nwb3xovn.js} +1 -1
  411. package/static/dist/assets/archive-b1j004vn.js +1 -0
  412. package/static/dist/assets/back-g74gkozu.js +1 -0
  413. package/static/dist/assets/{blockDiagram-I7D4REHJ-jzthp1wa.js → blockDiagram-I7D4REHJ-joedghi3.js} +1 -1
  414. package/static/dist/assets/{c4Diagram-7LVT6UL2-mwr67mt8.js → c4Diagram-7LVT6UL2-hyrjrohe.js} +1 -1
  415. package/static/dist/assets/channel-es95o4y8.js +1 -0
  416. package/static/dist/assets/{chunk-4HAMMTFA-gpq1y228.js → chunk-4HAMMTFA-koouqbut.js} +1 -1
  417. package/static/dist/assets/{chunk-75Z2AOVW-ktje58c4.js → chunk-75Z2AOVW-bl4bhdnt.js} +1 -1
  418. package/static/dist/assets/{chunk-DU6HZSFF-ofajdixh.js → chunk-DU6HZSFF-gpedttsp.js} +3 -3
  419. package/static/dist/assets/{chunk-F27PBJKO-cmev85ti.js → chunk-F27PBJKO-d8xxi0zi.js} +1 -1
  420. package/static/dist/assets/{chunk-GMAD6QVW-htjgt22y.js → chunk-GMAD6QVW-jro0hl73.js} +1 -1
  421. package/static/dist/assets/{chunk-GVQU2GXP-qndvoxl7.js → chunk-GVQU2GXP-djn6gbyu.js} +1 -1
  422. package/static/dist/assets/{chunk-IMKFNOWR-e5bkd5q6.js → chunk-IMKFNOWR-vw4p5p7o.js} +1 -1
  423. package/static/dist/assets/{chunk-L3NEJ4N5-mj1155r6.js → chunk-L3NEJ4N5-n1hj77q8.js} +1 -1
  424. package/static/dist/assets/{chunk-OSK3NFVY-e7gkikcw.js → chunk-OSK3NFVY-oy0gwn2n.js} +1 -1
  425. package/static/dist/assets/{chunk-P2QGCYS3-f7t54xfm.js → chunk-P2QGCYS3-onf1hz6c.js} +1 -1
  426. package/static/dist/assets/{chunk-POPQ4Y6H-i927v9oa.js → chunk-POPQ4Y6H-m8sqn7cs.js} +1 -1
  427. package/static/dist/assets/{chunk-PWAF6VOD-m84lmnyt.js → chunk-PWAF6VOD-ek4smc8x.js} +1 -1
  428. package/static/dist/assets/{chunk-SHT3W25Y-mi0tlcu9.js → chunk-SHT3W25Y-g9gfvefo.js} +3 -3
  429. package/static/dist/assets/{chunk-SVP7TREG-dnau702j.js → chunk-SVP7TREG-f9nfv2cu.js} +1 -1
  430. package/static/dist/assets/{chunk-TICWLB2K-edem1gkg.js → chunk-TICWLB2K-bnk3m1mq.js} +1 -1
  431. package/static/dist/assets/classDiagram-ZZMXUADV-kmihoqxh.js +1 -0
  432. package/static/dist/assets/classDiagram-v2-VYDZK3BY-kmihoqxh.js +1 -0
  433. package/static/dist/assets/copied-bli9tbcx.js +1 -0
  434. package/static/dist/assets/{copy-magtofyp.js → copy-jamtd1pf.js} +1 -1
  435. package/static/dist/assets/{cynefin-OW5HDTMX-siqlulkl.js → cynefin-OW5HDTMX-f8xfdd3f.js} +1 -1
  436. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-i648tah9.js → cynefinDiagram-5FMLGOSQ-n9lb99h9.js} +1 -1
  437. package/static/dist/assets/{dagre-GXQ25YYZ-mwn6uc17.js → dagre-GXQ25YYZ-dgailddi.js} +4 -4
  438. package/static/dist/assets/{diagram-S7CK7UJ4-l8abxaes.js → diagram-S7CK7UJ4-m6aeoe7c.js} +1 -1
  439. package/static/dist/assets/{diagram-UQ7AKVKN-mekq7zgq.js → diagram-UQ7AKVKN-jall3j0x.js} +1 -1
  440. package/static/dist/assets/{diagram-VSXAHHWV-fnky6lvc.js → diagram-VSXAHHWV-hbawi7hn.js} +1 -1
  441. package/static/dist/assets/{diagram-VX7I27RA-xe6r5qfw.js → diagram-VX7I27RA-hendl2tt.js} +1 -1
  442. package/static/dist/assets/{diagram-Z3DM3KII-nq07dg7k.js → diagram-Z3DM3KII-igwc35p3.js} +1 -1
  443. package/static/dist/assets/{ebnfDiagram-PWID7BFC-c62ipm3g.js → ebnfDiagram-PWID7BFC-c64knz08.js} +1 -1
  444. package/static/dist/assets/{erDiagram-RLTQ6QDP-h39kmnzy.js → erDiagram-RLTQ6QDP-brdu9lcm.js} +1 -1
  445. package/static/dist/assets/eventmodeling-NTZA5JFV-njk1j8wl.js +1 -0
  446. package/static/dist/assets/flowDiagram-HODETNUW-nma6f0ga.js +1 -0
  447. package/static/dist/assets/folder-plus-lvt9kudb.js +1 -0
  448. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-ngbsyp37.js → ganttDiagram-EL5Y4UJY-ma6jxj5i.js} +1 -1
  449. package/static/dist/assets/{gitGraph-4MIJSDKK-fr2i7caa.js → gitGraph-4MIJSDKK-naa9w6xa.js} +1 -1
  450. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-eravdti4.js → gitGraphDiagram-WWUBYQGX-hzltvsod.js} +1 -1
  451. package/static/dist/assets/{highlighted-body-KPVGNVTW-jwpop9p8.js → highlighted-body-KPVGNVTW-ghoavj8d.js} +1 -1
  452. package/static/dist/assets/host-hzm8n85n.js +1 -0
  453. package/static/dist/assets/index-drdcaqeq.css +2 -0
  454. package/static/dist/assets/index-jzm844he.js +11 -0
  455. package/static/dist/assets/{info-A6RAGUB7-h11x0dxo.js → info-A6RAGUB7-mn2ut5ko.js} +1 -1
  456. package/static/dist/assets/{infoDiagram-27XIBGKW-dfh47dw9.js → infoDiagram-27XIBGKW-h6kuqvsb.js} +1 -1
  457. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-i6ypq351.js → ishikawaDiagram-5VMMS53U-e7bnwq7h.js} +1 -1
  458. package/static/dist/assets/{journeyDiagram-3NMN7TZE-lduf1z95.js → journeyDiagram-3NMN7TZE-etd1bi6p.js} +1 -1
  459. package/static/dist/assets/{kanban-definition-UXKFOSKX-e18bu4pg.js → kanban-definition-UXKFOSKX-emb1g9dz.js} +4 -4
  460. package/static/dist/assets/lazyRouteComponent-o816ytzl.js +1 -0
  461. package/static/dist/assets/{line-meizqsvn.js → line-h0ojzsvs.js} +1 -1
  462. package/static/dist/assets/link-k01ryaf9.js +1 -0
  463. package/static/dist/assets/login-bsae49ew.js +1 -0
  464. package/static/dist/assets/mermaid-HWGCJPDP-ihl34s74.js +1 -0
  465. package/static/dist/assets/{mermaid-parser.core-ntne45i9.js → mermaid-parser.core-bnre27u8.js} +3 -3
  466. package/static/dist/assets/{mindmap-definition-YA3MSWOX-27b26eok.js → mindmap-definition-YA3MSWOX-o1vathns.js} +1 -1
  467. package/static/dist/assets/onboarding-c65tysya.js +1 -0
  468. package/static/dist/assets/onboarding_model_label-gpn28uix.js +1 -0
  469. package/static/dist/assets/{packet-AYTQ26CC-l6jdka8p.js → packet-AYTQ26CC-hatq7m2e.js} +1 -1
  470. package/static/dist/assets/pcmTap.worklet-74EKjWAZ.js +1 -0
  471. package/static/dist/assets/{pegDiagram-XKGWAZYB-g1er3bxj.js → pegDiagram-XKGWAZYB-gwisz8jv.js} +1 -1
  472. package/static/dist/assets/{pie-WAS4IAKB-i0ylcrt9.js → pie-WAS4IAKB-fpftf0mk.js} +1 -1
  473. package/static/dist/assets/{pieDiagram-E7YTZNPT-fbz1e55z.js → pieDiagram-E7YTZNPT-khm1o9a6.js} +1 -1
  474. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-hhue7d8o.js → quadrantDiagram-AXDQQJYC-owqc4uqn.js} +1 -1
  475. package/static/dist/assets/{radar-RG4KPBEZ-f9b70aa4.js → radar-RG4KPBEZ-cntfwjpq.js} +1 -1
  476. package/static/dist/assets/{railroad-74A4TZTK-lgsuoeda.js → railroad-74A4TZTK-a7t5eibp.js} +1 -1
  477. package/static/dist/assets/railroad-abnf-HS5TGJTU-ol8cdktf.js +1 -0
  478. package/static/dist/assets/railroad-ebnf-LZEXJU2U-i8vzd429.js +1 -0
  479. package/static/dist/assets/railroad-peg-WCYAUIDC-nw3ulewz.js +1 -0
  480. package/static/dist/assets/{railroadDiagram-O6MQD6OU-eqpy9fnz.js → railroadDiagram-O6MQD6OU-etuh0qa0.js} +1 -1
  481. package/static/dist/assets/{refresh-cw-hlwb02qv.js → refresh-cw-mqbkv2a3.js} +1 -1
  482. package/static/dist/assets/refresh-l29ljp76.js +1 -0
  483. package/static/dist/assets/{requirementDiagram-BXWQKSXE-ogf6puhi.js → requirementDiagram-BXWQKSXE-oq2ulk22.js} +1 -1
  484. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-fqb8xcjf.js → sankeyDiagram-P5KCCOFB-iqc02emv.js} +1 -1
  485. package/static/dist/assets/saved-ndd4t2xb.js +1 -0
  486. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-dlcz6qjz.js → sequenceDiagram-WJ2MYXX4-i0v116q0.js} +2 -2
  487. package/static/dist/assets/settings_section_extensions_title-jhfo6o8z.js +1 -0
  488. package/static/dist/assets/share._token-c1ri0hy1.js +2 -0
  489. package/static/dist/assets/sliders-horizontal-j3jjt9tv.js +1 -0
  490. package/static/dist/assets/{stateDiagram-D77RDMKH-fyoznpcs.js → stateDiagram-D77RDMKH-dnpt1ato.js} +1 -1
  491. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-bxjacpk6.js +1 -0
  492. package/static/dist/assets/{swimlanes-42K2YHIH-oefldhfy.js → swimlanes-42K2YHIH-loqbdazb.js} +1 -1
  493. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-id62p9hz.js +8 -0
  494. package/static/dist/assets/{timeline-definition-24CTP7MA-b1vl2zil.js → timeline-definition-24CTP7MA-ol2hnvma.js} +1 -1
  495. package/static/dist/assets/toast-i3h34v6o.js +64 -0
  496. package/static/dist/assets/{treeView-Q6P3EWNA-f7hcci5o.js → treeView-Q6P3EWNA-idrj6iox.js} +1 -1
  497. package/static/dist/assets/{treemap-WGGIJYW6-nl85071a.js → treemap-WGGIJYW6-lzr49vv5.js} +1 -1
  498. package/static/dist/assets/untitled-oaoya4qj.js +1 -0
  499. package/static/dist/assets/useForm-nfaxgmsk.js +1 -0
  500. package/static/dist/assets/{useParams-b4dq6n4q.js → useParams-gjc70qru.js} +1 -1
  501. package/static/dist/assets/{useSearch-ipfmv3he.js → useSearch-e6ae539u.js} +1 -1
  502. package/static/dist/assets/{vennDiagram-4TSXK5OY-h5hzbk0n.js → vennDiagram-4TSXK5OY-bvwr9o2z.js} +1 -1
  503. package/static/dist/assets/{wardley-WFR3VGLG-jftvpm3e.js → wardley-WFR3VGLG-31ui8tma.js} +1 -1
  504. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-hedh85ge.js → wardleyDiagram-VM6X3IG4-k5wqtx4b.js} +1 -1
  505. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-e49523ab.js → xychartDiagram-S5SC5T6Z-aqbgvujg.js} +1 -1
  506. package/static/dist/index.html +1 -1
  507. package/static/dist/sw.js +1 -1
  508. package/static/dist/assets/AppShell-g3bkgnvt.js +0 -1
  509. package/static/dist/assets/ChatPage-oo7bdan6.js +0 -25
  510. package/static/dist/assets/Dialog-g355qxhp.js +0 -1
  511. package/static/dist/assets/ExtensionRoute-i2y9fvjm.js +0 -1
  512. package/static/dist/assets/HubRoute-lmkrbw47.js +0 -2
  513. package/static/dist/assets/Markdown-j4kut4j2.js +0 -598
  514. package/static/dist/assets/RightPanel-ohlsdzfl.js +0 -1
  515. package/static/dist/assets/Select-kddq75qc.js +0 -1
  516. package/static/dist/assets/SessionListPanel-lu3oy0hw.js +0 -1
  517. package/static/dist/assets/SettingsLayout-o9bv4mgb.js +0 -1
  518. package/static/dist/assets/States-eq6fe29m.js +0 -1
  519. package/static/dist/assets/Toaster-pc247u9f.js +0 -1
  520. package/static/dist/assets/_app-f8n1i0m1.js +0 -1
  521. package/static/dist/assets/_app.index-bzzv80hk.js +0 -1
  522. package/static/dist/assets/_app.insights-dzixbryi.js +0 -1
  523. package/static/dist/assets/_app.kanban-c6hep2us.js +0 -1
  524. package/static/dist/assets/_app.logs-i69qds98.js +0 -1
  525. package/static/dist/assets/_app.memory-kl4vf0gd.js +0 -1
  526. package/static/dist/assets/_app.profiles-b8zinmyp.js +0 -1
  527. package/static/dist/assets/_app.settings-cg8plwmf.js +0 -1
  528. package/static/dist/assets/_app.settings._section-bkwbi9zn.js +0 -3
  529. package/static/dist/assets/_app.skills-cs47sbvs.js +0 -1
  530. package/static/dist/assets/_app.tasks-dwvk64tc.js +0 -1
  531. package/static/dist/assets/_app.todos-c8xjm8p3.js +0 -1
  532. package/static/dist/assets/_app.workspaces-ehvd1gds.js +0 -1
  533. package/static/dist/assets/architecture-7GRP2DOG-6crvnylg.js +0 -1
  534. package/static/dist/assets/back-h7aun7ew.js +0 -1
  535. package/static/dist/assets/cancel-fhi0vcnu.js +0 -1
  536. package/static/dist/assets/channel-b2zo73z1.js +0 -1
  537. package/static/dist/assets/classDiagram-ZZMXUADV-oe99st8x.js +0 -1
  538. package/static/dist/assets/classDiagram-v2-VYDZK3BY-oe99st8x.js +0 -1
  539. package/static/dist/assets/copied-hcplv46p.js +0 -1
  540. package/static/dist/assets/endpoints-klbxod4t.js +0 -64
  541. package/static/dist/assets/eventmodeling-NTZA5JFV-obfede4u.js +0 -1
  542. package/static/dist/assets/flowDiagram-HODETNUW-kdpsp1je.js +0 -1
  543. package/static/dist/assets/host-i828xuo7.js +0 -1
  544. package/static/dist/assets/index-eh8zilnv.css +0 -2
  545. package/static/dist/assets/index-r648f4o1.js +0 -11
  546. package/static/dist/assets/lazyRouteComponent-e1y4t2i9.js +0 -1
  547. package/static/dist/assets/link-oot2yn73.js +0 -1
  548. package/static/dist/assets/login-gu28l9ou.js +0 -1
  549. package/static/dist/assets/mermaid-HWGCJPDP-mtwrj8fn.js +0 -1
  550. package/static/dist/assets/onboarding-lkphzu1s.js +0 -1
  551. package/static/dist/assets/onboarding_model_label-ftpjdwqk.js +0 -1
  552. package/static/dist/assets/railroad-abnf-HS5TGJTU-nf9d6pdx.js +0 -1
  553. package/static/dist/assets/railroad-ebnf-LZEXJU2U-f7ummkt5.js +0 -1
  554. package/static/dist/assets/railroad-peg-WCYAUIDC-oczq5tqs.js +0 -1
  555. package/static/dist/assets/refresh-abtu93ke.js +0 -1
  556. package/static/dist/assets/saved-girnabkf.js +0 -1
  557. package/static/dist/assets/settings_section_extensions_title-h14cwk6f.js +0 -1
  558. package/static/dist/assets/share._token-kl0r7ido.js +0 -2
  559. package/static/dist/assets/sliders-horizontal-n1zm34qq.js +0 -1
  560. package/static/dist/assets/sse-iwku0sjo.js +0 -1
  561. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-ixhx8r46.js +0 -1
  562. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-h9ersk2e.js +0 -8
  563. package/static/dist/assets/todoStore-jjr5yr78.js +0 -1
  564. package/static/dist/assets/units-kgxzxfhi.js +0 -1
  565. package/static/dist/assets/untitled-cikfjntn.js +0 -1
  566. package/static/dist/assets/useForm-kqoqg0k9.js +0 -1
  567. package/static/dist/assets/useLocale-o59tbiea.js +0 -1
@@ -4,11 +4,13 @@
4
4
  * `_extract_tool_calls_from_messages`, `_build_partial_message`).
5
5
  */
6
6
  import { buildActiveTurnToken, completedToolIndex } from '../redact.js';
7
- import { RunJournal } from './journal.js';
7
+ import { selectAuthoritativeTerminalEvent } from './journal.js';
8
8
  import { str } from '../util.js';
9
+ import { stateDbMessageKey, stateDbMessageFingerprint, stateDbRowId, stateDbIdentityKeys, stateDbMessageRepresented } from './state-db-identity.js';
9
10
  import { stripAttachedFilesMarker, stripWorkspacePrefix } from './session.js';
10
11
  export { WORKSPACE_PREFIX_RE, stripWorkspacePrefix } from './session.js';
11
12
  import { decidedEditDiff, toolEditDiff, toolName } from './tool-display.js';
13
+ import { sourceKind } from './source-kind.js';
12
14
  const TOOL_RESULT_SNIPPET_MAX = 4000;
13
15
  // Python `_TOOL_ARG_CONTENT_KEYS`: file bodies, commands, and patch text keep up to the content cap; incidental args cut at 120.
14
16
  export const TOOL_ARG_CONTENT_KEYS = new Set(['command', 'cmd', 'script', 'code', 'patch', 'diff', 'old_string', 'new_string', 'content', 'path', 'file_path']);
@@ -46,11 +48,33 @@ export function messageText(content) {
46
48
  }
47
49
  return str(content);
48
50
  }
51
+ /** Agent-injected memory is model context, never typed user text. Match the Agent's fence, including an unclosed tail. */
52
+ function withoutMemoryContext(text) {
53
+ const stripped = text.replace(/(?:\r?\n)?<memory-context>[\s\S]*?(?:<\/memory-context>|$)/gi, '');
54
+ // Remove the fence's line separator, not the prompt's indentation or trailing whitespace.
55
+ return stripped !== text && !stripped.trim() ? '' : stripped;
56
+ }
57
+ /** Display-only user projection shared by transcript hydration and turn identity; model history stays untouched. */
58
+ export function normalizeUserDisplay(message) {
59
+ if (!isDict(message) || message.role !== 'user')
60
+ return message;
61
+ const content = message.content;
62
+ if (typeof content === 'string')
63
+ return { ...message, content: withoutMemoryContext(content) };
64
+ if (!Array.isArray(content))
65
+ return message;
66
+ return { ...message, content: content.flatMap((part) => {
67
+ if (!isDict(part) || part.type !== 'text' || typeof part.text !== 'string')
68
+ return [part];
69
+ const text = withoutMemoryContext(part.text);
70
+ return text === part.text ? [part] : text ? [{ ...part, text }] : [];
71
+ }) };
72
+ }
49
73
  export function messageIdentity(msg, textLimit = 500) {
50
74
  if (!isDict(msg))
51
75
  return null;
52
76
  const role = str(msg.role);
53
- let text = messageText(msg.content);
77
+ let text = messageText(normalizeUserDisplay(msg).content);
54
78
  if (role === 'user') {
55
79
  const typed = userPromptText(text);
56
80
  // An attachment-only prompt has no typed text; its whole attached-files line (never truncated) tells one such turn
@@ -110,15 +134,77 @@ export function markerKind(msg) {
110
134
  export function isContextCompressionMarker(msg) {
111
135
  return markerKind(msg) === 'context_compaction';
112
136
  }
137
+ // The Agent's failed-turn boundary copy (`agent/turn_failure_copy.py`): an older row carries it without its kind.
138
+ const FAILED_TURN_NOTICES = new Set([
139
+ 'Your request was not processed. Send it again if you still want me to carry it out.',
140
+ 'This turn did not complete. Some actions may already have run; verify their effects before resending.',
141
+ ]);
142
+ /**
143
+ * TAL-815: rows the Agent writes outside the conversation, by its `display_kind` and its own read-side rules.
144
+ * `failed_turn`: the assistant boundary closing a turn that failed, never the model's reply. `hidden`: a row the Agent
145
+ * never renders, such as the empty interrupt placeholder or an untyped `[System:` scaffold notice in a user row.
146
+ */
147
+ export function agentRowKind(msg) {
148
+ if (!isDict(msg))
149
+ return null;
150
+ if (msg.display_kind === 'hidden')
151
+ return 'hidden';
152
+ if (msg.role === 'assistant' && (msg.display_kind === 'failed_turn' || (!msg.display_kind && typeof msg.content === 'string' && FAILED_TURN_NOTICES.has(msg.content.trim()))))
153
+ return 'failed_turn';
154
+ return msg.role === 'user' && !msg.display_kind && typeof msg.content === 'string' && msg.content.trimStart().startsWith('[System:') ? 'hidden' : null;
155
+ }
156
+ const DELIVERY_PREFIXES = [['webhook', '[Webhook delivery: '], ['cron', '[Cron delivery: ']];
157
+ /**
158
+ * TAL-816: the user row the Agent's gateway mirrors into a chat's transcript after a webhook or cron delivery
159
+ * (`gateway/mirror.py` callers): exactly `[Webhook delivery: <route>]` or `[Cron delivery: <job>]`, a newline, then the
160
+ * delivered text. Only meaningful in a messaging session; anyone can type the same prefix elsewhere.
161
+ */
162
+ export function deliveryNotice(msg) {
163
+ if (!isDict(msg) || msg.role !== 'user' || typeof msg.content !== 'string')
164
+ return null;
165
+ const newline = msg.content.indexOf('\n');
166
+ const label = newline < 0 ? '' : msg.content.slice(0, newline);
167
+ const match = DELIVERY_PREFIXES.find(([, prefix]) => label.startsWith(prefix));
168
+ if (!match || !label.endsWith(']') || label.length <= match[1].length + 1)
169
+ return null;
170
+ return { kind: match[0], name: label.slice(match[1].length, -1), body: msg.content.slice(newline + 1) };
171
+ }
172
+ /**
173
+ * TAL-816: `session`'s rows for a copy that is no longer a messaging session (duplicate, branch), each mirrored delivery
174
+ * marked with the Agent's own mirror metadata (`mirror_source`, which it drops at the SQLite boundary) so the copy still
175
+ * shows it as a delivery. Returns copies; stored rows are untouched.
176
+ */
177
+ export function withMirrorSources(messages, session) {
178
+ if (sourceKind(session) !== 'messaging')
179
+ return messages;
180
+ return messages.map((m) => {
181
+ const delivery = deliveryNotice(m);
182
+ return delivery ? { ...m, mirror_source: delivery.kind } : m;
183
+ });
184
+ }
113
185
  /**
114
186
  * TAL-305: stamps `_marker_kind` on marker rows, and `_marker_body` (the list without its marker line) on a preserved
115
- * task list, so clients render a marker card instead of a message. Returns copies; stored rows are untouched.
187
+ * task list, so clients render a marker card instead of a message. TAL-815: a failed turn's boundary gets
188
+ * `_notice_kind`, unless the turn (`_turn_id`) already carries Web's own error row; that copy and every other row the
189
+ * Agent hides leave as `display_kind: 'hidden'`. TAL-816: a mirrored delivery in a messaging `session`, or one a copy
190
+ * marked with its `mirror_source`, gets `_delivery`. Returns copies; stored rows are untouched.
116
191
  */
117
- export function withMarkerKinds(messages) {
192
+ export function withMarkerKinds(messages, session) {
193
+ const erroredTurns = new Set(messages.flatMap((m) => (isDict(m) && m._error ? [str(m._turn_id)] : [])));
194
+ const messaging = sourceKind(session) === 'messaging';
118
195
  return messages.map((m) => {
119
- const kind = markerKind(m);
120
- if (!kind || !isDict(m))
196
+ if (!isDict(m))
121
197
  return m;
198
+ const delivery = deliveryNotice(m);
199
+ if (delivery && (messaging || m.mirror_source === delivery.kind))
200
+ return { ...m, _delivery: delivery };
201
+ const kind = markerKind(m);
202
+ if (!kind) {
203
+ const agentKind = agentRowKind(m);
204
+ if (!agentKind)
205
+ return m;
206
+ return agentKind === 'failed_turn' && !erroredTurns.has(str(m._turn_id)) ? { ...m, _notice_kind: agentKind } : { ...m, display_kind: 'hidden' };
207
+ }
122
208
  if (kind === 'context_compaction')
123
209
  return { ...m, _marker_kind: kind };
124
210
  const body = messageText(m.content).trim().slice(PRESERVED_TASK_LIST_PREFIX.length).trim();
@@ -132,7 +218,7 @@ export function looksLikeCurrentUserTurn(msg, msgText) {
132
218
  // A persisted steer is display-only: it is never the prompt that opened a turn.
133
219
  if (!isDict(msg) || str(msg.role) !== 'user' || isDict(msg._steer))
134
220
  return false;
135
- const candidate = normalizeUserText(messageText(msg.content));
221
+ const candidate = normalizeUserText(messageText(normalizeUserDisplay(msg).content));
136
222
  const target = normalizeUserText(msgText);
137
223
  // An attachment-only prompt (TAL-276) has no text: the Agent's row for it carries none either.
138
224
  if (!target)
@@ -169,7 +255,8 @@ export function findCurrentUserTurn(messages, msgText) {
169
255
  /** Python `_merge_display_messages_after_agent_result` (append-only display merge). */
170
256
  /** Python `_assistant_message_has_final_visible_text`: a non-error assistant row carrying visible answer text. */
171
257
  function assistantHasFinalVisibleText(msg) {
172
- if (msg.role !== 'assistant' || msg._error)
258
+ // The Agent's failed-turn boundary is no answer (TAL-815).
259
+ if (msg.role !== 'assistant' || msg._error || agentRowKind(msg))
173
260
  return false;
174
261
  return messageText(msg.content).trim().length > 0;
175
262
  }
@@ -603,7 +690,7 @@ export function extractToolCallsFromMessages(messages, liveToolCalls = [], recor
603
690
  * (recorded live, else `null`), `result` (the result snippet, else `null`) and `result_view` (its display sections, TAL-315,
604
691
  * else `null`). Returns copies; stored rows are untouched.
605
692
  */
606
- export function withToolCallOutcomes(messages, sessionToolCalls, activeTurnId) {
693
+ export function withToolCallOutcomes(messages, sessionToolCalls, activeTurnId, baseIndex = 0) {
607
694
  // Every identifier a stored call may carry (`ToolCallSchema`).
608
695
  const callId = (tc) => (isDict(tc) ? toolCallId(tc) || str(tc.tool_call_id) : '');
609
696
  // Providers may reuse an id (`call_1` in every response), so a reply answers the latest earlier assistant row that
@@ -620,7 +707,7 @@ export function withToolCallOutcomes(messages, sessionToolCalls, activeTurnId) {
620
707
  if (!isDict(m))
621
708
  return;
622
709
  if (m.role === 'tool')
623
- answer(str(m.tool_call_id) || str(m.tool_use_id), { content: m.content, is_error: false });
710
+ answer(str(m.tool_call_id) || str(m.tool_use_id), { content: m.content, is_error: false, display_metadata: m.display_metadata });
624
711
  else if (m.role === 'user' && Array.isArray(m.content)) {
625
712
  // Anthropic-style results: `tool_result` blocks in a user row, each naming its call.
626
713
  for (const part of m.content)
@@ -657,7 +744,7 @@ export function withToolCallOutcomes(messages, sessionToolCalls, activeTurnId) {
657
744
  // Calls known only from a record: the session-level list's, and the live calls a failed or cancelled turn's partial
658
745
  // snapshot kept (`_partial_tool_calls`).
659
746
  const records = [];
660
- const rowRecords = recordedByRow.get(index) ?? [];
747
+ const rowRecords = recordedByRow.get(baseIndex + index) ?? [];
661
748
  const recorded = new Map(rowRecords.filter((tc) => str(tc.tid)).map((tc) => [str(tc.tid), tc]));
662
749
  for (const tc of [...rowRecords, ...(Array.isArray(m._partial_tool_calls) ? m._partial_tool_calls : [])]) {
663
750
  if (!isDict(tc))
@@ -676,7 +763,7 @@ export function withToolCallOutcomes(messages, sessionToolCalls, activeTurnId) {
676
763
  const reply = id ? replies.get(key(index, id)) : undefined;
677
764
  const outcome = reply ? { ...toolOutcome(reply.content), flagged: reply.is_error } : null;
678
765
  // TAL-448: a file edit's change, from its full reply, else the one its live record decided.
679
- const editDiff = reply ? toolEditDiff(name, reply.content) : decidedEditDiff(rec?.edit_diff);
766
+ const editDiff = reply ? toolEditDiff(name, reply.content, reply.display_metadata) : decidedEditDiff(rec?.edit_diff);
680
767
  return {
681
768
  ...(editDiff ? { edit_diff: editDiff } : {}),
682
769
  done: Boolean(reply) || answered || !running, is_error: outcome ? outcome.flagged || outcome.is_error : rec?.is_error === true,
@@ -800,7 +887,7 @@ export function journalOutputRows(events, turnId) {
800
887
  at = e.created_at || at;
801
888
  }
802
889
  flush();
803
- const done = RunJournal.selectAuthoritativeTerminalEvent(events);
890
+ const done = selectAuthoritativeTerminalEvent(events);
804
891
  if (done?.event !== 'done')
805
892
  return { rows, answered: false };
806
893
  // The last row answers only with visible prose and no calls after it (a reasoning-only segment is no answer).
@@ -945,8 +1032,7 @@ export function normalizeAssistantDisplay(message) {
945
1032
  * TAL-493: once a boundary or settled turn recorded the highest state.db id it read (`stateDbSeenId`) and the rows carry
946
1033
  * ids, identity replaces the timestamp rules: rows up to that id are covered, and every newer row not already in the
947
1034
  * sidecar is appended, even one a writer stamped before the newest local row or the watermark but committed later.
948
- * ponytail: the Python identity memo (api_content sidecars, message ids, workspace-prefix normalisation) is not ported;
949
- * add it if a mixed WebUI/CLI transcript shows duplicated turns.
1035
+ * Direct and absorbed durable identities cover merged Agent prompts even when their text and timestamp changed.
950
1036
  */
951
1037
  export function mergeSessionMessagesAppendOnly(sidecar, state, opts = {}) {
952
1038
  const watermark = Number(opts.truncationWatermark);
@@ -954,32 +1040,43 @@ export function mergeSessionMessagesAppendOnly(sidecar, state, opts = {}) {
954
1040
  if (!state.length)
955
1041
  return sidecar;
956
1042
  const ts = (m) => { const n = Number(m.timestamp); return Number.isFinite(n) ? n : null; };
957
- const key = (m) => `${String(m.role)}\0${String(ts(m) ?? '')}\0${typeof m.content === 'string' ? m.content : JSON.stringify(m.content ?? null)}`;
1043
+ const key = stateDbMessageKey;
958
1044
  const seenId = opts.stateDbSeenId;
1045
+ const generation = opts.stateDbGeneration ?? null;
1046
+ const includeUids = state.some((m) => stateDbIdentityKeys(m).some((id) => id.startsWith('uid:')));
1047
+ const identities = (m) => stateDbIdentityKeys(m, includeUids, generation);
1048
+ const representedIds = new Set(sidecar.flatMap((m) => identities(m)));
1049
+ const isRepresented = (m) => stateDbMessageRepresented(m, representedIds, includeUids, generation);
1050
+ const rememberIds = (m) => { for (const id of identities(m))
1051
+ representedIds.add(id); };
959
1052
  if (typeof seenId === 'number' && Number.isFinite(seenId) && state.some((m) => stateDbRowId(m) !== null)) {
960
- // Each local row stands for at most one new state.db row: a persisted copy by its id, any other by its key.
961
- const localIds = new Set(sidecar.map(stateDbRowId));
962
1053
  const localKeys = new Map();
963
1054
  for (const m of sidecar)
964
- if (stateDbRowId(m) === null)
1055
+ if (!identities(m).length)
965
1056
  localKeys.set(key(m), (localKeys.get(key(m)) ?? 0) + 1);
966
- const merged = [...sidecar];
967
- for (const m of state) {
968
- const id = stateDbRowId(m);
969
- if (id !== null && localIds.has(id))
970
- continue;
971
- // In state.db order, so a covered row matches its own local copy before a newer duplicate can.
972
- const left = localKeys.get(key(m)) ?? 0;
973
- if (left > 0) {
974
- localKeys.set(key(m), left - 1);
975
- continue;
976
- }
977
- if (id === null || id <= seenId)
978
- continue;
979
- merged.push(m);
980
- }
981
- return merged;
1057
+ return [...sidecar, ...appendStateDbIdentityRows(state, seenId, representedIds, localKeys, generation, includeUids)];
982
1058
  }
1059
+ // Legacy sidecars may have no seen marker or row IDs. A verified copy can still match its archived
1060
+ // source's exact role/timestamp/content key. This only removes represented copies; the timestamp
1061
+ // and truncate/compress gates below continue to decide which remaining rows may be appended.
1062
+ const represented = new Set();
1063
+ const remember = (message) => {
1064
+ represented.add(stateDbMessageFingerprint(message));
1065
+ if (typeof message._state_db_source_key === 'string')
1066
+ represented.add(message._state_db_source_key);
1067
+ };
1068
+ for (const message of sidecar)
1069
+ remember(message);
1070
+ state = state.filter((message) => {
1071
+ if (isRepresented(message))
1072
+ return false;
1073
+ const sourceKey = message._state_db_source_key;
1074
+ if (typeof sourceKey === 'string' && represented.has(sourceKey))
1075
+ return false;
1076
+ remember(message);
1077
+ rememberIds(message);
1078
+ return true;
1079
+ });
983
1080
  if (!sidecar.length) {
984
1081
  if (!hasWatermark) {
985
1082
  const seen = new Set();
@@ -1014,10 +1111,28 @@ export function mergeSessionMessagesAppendOnly(sidecar, state, opts = {}) {
1014
1111
  }
1015
1112
  return merged;
1016
1113
  }
1017
- /** The state.db row id a row was read with (a compaction copy reads as the row it copies; TAL-709), or null for a database without the column. */
1018
- function stateDbRowId(m) {
1019
- const id = m._state_db_row_id;
1020
- return typeof id === 'number' && Number.isFinite(id) ? id : null;
1114
+ /** Shared identity-mode append step; an indexed prefix supplies the same witnesses without visiting its rows. */
1115
+ export function appendStateDbIdentityRows(state, seenId, represented, localKeys, generation, includeUids) {
1116
+ const added = new Set();
1117
+ const consumed = new Map();
1118
+ const witnesses = { has: (id) => represented.has(id) || added.has(id) };
1119
+ const appended = [];
1120
+ for (const m of state) {
1121
+ if (stateDbMessageRepresented(m, witnesses, includeUids, generation))
1122
+ continue;
1123
+ const id = stateDbRowId(m), key = stateDbMessageKey(m);
1124
+ const used = consumed.get(key) ?? 0;
1125
+ const left = (localKeys.get(key) ?? 0) - used;
1126
+ if (left > 0 && (m._state_db_authored_change !== true || id === null || id <= seenId))
1127
+ consumed.set(key, used + 1);
1128
+ else if (id !== null && id > seenId)
1129
+ appended.push(m);
1130
+ else
1131
+ continue;
1132
+ for (const identity of stateDbIdentityKeys(m, includeUids, generation))
1133
+ added.add(identity);
1134
+ }
1135
+ return appended;
1021
1136
  }
1022
1137
  /** TAL-493: the `state_db_seen_id` after reading `rows`: their highest id, or null when they carry none. */
1023
1138
  export function stateDbSeenId(rows) {
@@ -1103,6 +1218,44 @@ export function withDisplayMedia(messages, project) {
1103
1218
  return out;
1104
1219
  });
1105
1220
  }
1221
+ /** Anthropic-style tool calls: `tool_use` blocks in the content array, interleaved with the text around them. */
1222
+ export function hasToolUseBlocks(message) {
1223
+ return Array.isArray(message.content) && message.content.some((part) => isDict(part) && part.type === 'tool_use');
1224
+ }
1225
+ /**
1226
+ * The final answer rule: the turn's last assistant row, with visible content, no tool calls, not interim or partial.
1227
+ * A Stop row is no answer: its outcome is the status (TAL-364; older rows still carry English copy).
1228
+ */
1229
+ export function finalAnswerOf(last) {
1230
+ if ((Array.isArray(last.tool_calls) && last.tool_calls.length > 0) || hasToolUseBlocks(last) || last._interim === true || last._partial === true)
1231
+ return '';
1232
+ if (last._error === true && (last._terminal_state === 'cancelled' || last.provider_details_label === 'Cancellation details'))
1233
+ return '';
1234
+ return splitDisplayText(messageText(last.content))[0];
1235
+ }
1236
+ /** Conversation classification shared by the indexed selector and the hydrated projection. */
1237
+ export function isConversationalAssistant(message) {
1238
+ return isDict(message) && message.role === 'assistant' && !agentRowKind(message) && !markerKind(message)
1239
+ && !message._marker_kind && !message._notice_kind && !message._background_silent && !message._background_update && !message._delivery;
1240
+ }
1241
+ /** Absolute coordinate of the newest settled visible answer; running and answerless turns never displace it. */
1242
+ export function newestSettledReply(messages, activeTurnId, offset = 0) {
1243
+ const visited = new Set();
1244
+ for (let i = messages.length - 1; i >= 0; i -= 1) {
1245
+ const m = messages[i];
1246
+ if (!isConversationalAssistant(m))
1247
+ continue;
1248
+ const turn = typeof m._turn_id === 'string' ? m._turn_id : `row:${offset + i}`;
1249
+ if (turn === activeTurnId || visited.has(turn))
1250
+ continue;
1251
+ visited.add(turn);
1252
+ const scene = m._anchor_activity_scene;
1253
+ const answer = isDict(scene) ? str(scene.final_answer) : finalAnswerOf(m);
1254
+ if (!m._error && !m._partial && !m._interim && splitDisplayText(answer)[0].trim())
1255
+ return offset + i;
1256
+ }
1257
+ return null;
1258
+ }
1106
1259
  /** TAL-456: a settled user or assistant body longer than this ships a collapsed excerpt for clients to render. */
1107
1260
  export const BODY_EXCERPT_LIMIT = 3000;
1108
1261
  const graphemes = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
@@ -1124,20 +1277,28 @@ function bodyExcerpt(text) {
1124
1277
  /**
1125
1278
  * TAL-456: stamps `_display_excerpt` and `_display_truncated` on settled user and assistant rows whose display text is longer than
1126
1279
  * `BODY_EXCERPT_LIMIT`, and `final_answer_excerpt` on a settled scene whose final answer is, so clients render a bounded
1127
- * excerpt instead of laying out the whole body. Full text stays for copy and edit; the running turn's rows are left alone.
1280
+ * excerpt instead of laying out the whole body. The newest settled answer and running turn stay full; copy and edit retain full text.
1128
1281
  * Runs after scene hydration. Returns copies; stored rows are untouched.
1129
1282
  */
1130
- export function withBodyExcerpts(messages, activeTurnId) {
1131
- return messages.map((m) => {
1283
+ export function withBodyExcerpts(messages, activeTurnId, newestReplyIndex = newestSettledReply(messages, activeTurnId), offset = 0) {
1284
+ return messages.map((m, index) => {
1132
1285
  if (!isDict(m) || (m.role !== 'user' && m.role !== 'assistant'))
1133
1286
  return m;
1134
- if (activeTurnId && m._turn_id === activeTurnId)
1135
- return m;
1136
- let out = m;
1137
- const text = typeof m._display_content === 'string' ? m._display_content : messageText(m.content);
1287
+ let out = { ...m };
1288
+ delete out._display_excerpt;
1289
+ delete out._display_truncated;
1290
+ if (isDict(out._anchor_activity_scene)) {
1291
+ const scene = { ...out._anchor_activity_scene };
1292
+ delete scene.final_answer_excerpt;
1293
+ out._anchor_activity_scene = scene;
1294
+ }
1295
+ if ((activeTurnId && m._turn_id === activeTurnId) || index + offset === newestReplyIndex)
1296
+ return out;
1297
+ // A delivery shows its body under its own label (TAL-816), so the excerpt is the body's.
1298
+ const text = isDict(m._delivery) ? str(m._delivery.body) : typeof m._display_content === 'string' ? m._display_content : messageText(m.content);
1138
1299
  if (text.length > BODY_EXCERPT_LIMIT)
1139
1300
  out = { ...out, _display_excerpt: bodyExcerpt(text), _display_truncated: true };
1140
- const scene = m._anchor_activity_scene;
1301
+ const scene = out._anchor_activity_scene;
1141
1302
  const finalAnswer = isDict(scene) ? (typeof scene.final_answer_display === 'string' ? scene.final_answer_display : scene.final_answer) : null;
1142
1303
  if (isDict(scene) && typeof finalAnswer === 'string' && finalAnswer.length > BODY_EXCERPT_LIMIT) {
1143
1304
  out = { ...out, _anchor_activity_scene: { ...scene, final_answer_excerpt: bodyExcerpt(finalAnswer) } };
@@ -1232,6 +1393,11 @@ function toolCallId(tc) {
1232
1393
  return str(tc.id) || str(tc.call_id);
1233
1394
  }
1234
1395
  const API_SAFE_MSG_KEYS = new Set(['role', 'content', 'tool_calls', 'tool_call_id', 'tool_use_id', 'name', 'refusal', 'reasoning_content']);
1396
+ // TAL-927: the Agent's reload projection (`_rows_to_conversation`) restores these on assistant rows so prior reasoning
1397
+ // replays and keeps its signatures; turn history keeps them too. Persistence-only: the Agent strips them per route.
1398
+ const AGENT_ASSISTANT_REPLAY_KEYS = new Set(['reasoning', 'reasoning_details', 'codex_reasoning_items', 'codex_message_items', 'finish_reason']);
1399
+ // The opaque ones are bound to the provider that issued them.
1400
+ const PROVIDER_ISSUED_REASONING_KEYS = new Set(['reasoning_details', 'codex_reasoning_items', 'codex_message_items']);
1235
1401
  const OOB_USER_MESSAGE_BLOCK_RE = /\[OUT-OF-BAND\s+USER\s+MESSAGE(?:\s*(?:—|-)\s*[\s\S]*?)?\]\s*?[\s\S]*?\[\/OUT-OF-BAND\s+USER\s+MESSAGE\]/gi;
1236
1402
  const OOB_DELIVERY_RE = /^\s*\[OUT-OF-BAND\s+USER\s+MESSAGE[^\]]*\]\s*([\s\S]*?)\s*\[\/OUT-OF-BAND\s+USER\s+MESSAGE\]\s*$/i;
1237
1403
  /** The Agent's own record of a steer it delivered (`display_kind: 'steer'`, an out-of-band block): its text, else null. */
@@ -1273,9 +1439,11 @@ function stripOobBlocks(content) {
1273
1439
  * out-of-band blocks, and keeps a cancelled (`_recovered`) user prompt only where it separates two assistant turns —
1274
1440
  * otherwise the neighbours fuse cleanly or the prompt is stale, and replaying it would answer it again.
1275
1441
  * `preserveApiContent` (Python `_sanitize_messages_for_agent`) keeps the Agent's `api_content` replay sidecar on
1276
- * user/assistant rows and every row's `timestamp` for turn history; compression and other projections strip both.
1442
+ * user/assistant rows, every row's `timestamp`, and the assistant reasoning carriers the Agent replays (TAL-927) for
1443
+ * turn history; compression and other projections strip them all. Provider-issued carriers stay only on rows stamped at
1444
+ * or after `issuedReasoningSince`, the turn provider's start; without one they stay home too.
1277
1445
  */
1278
- export function sanitizeMessagesForApi(messages, { preserveApiContent = false } = {}) {
1446
+ export function sanitizeMessagesForApi(messages, { preserveApiContent = false, issuedReasoningSince = null, maxMessages = Infinity } = {}) {
1279
1447
  // Calls are OpenAI `tool_calls` or Anthropic-style `tool_use` content blocks; results name them by `tool_call_id`,
1280
1448
  // `tool_use_id`, or a user row's `tool_result` blocks.
1281
1449
  const toolUseIds = (msg) => (Array.isArray(msg.content) ? msg.content.flatMap((part) => (isDict(part) && part.type === 'tool_use' && str(part.id) ? [str(part.id)] : [])) : []);
@@ -1300,7 +1468,7 @@ export function sanitizeMessagesForApi(messages, { preserveApiContent = false }
1300
1468
  if (isReasoningOnlyAssistant(msg) && !replay)
1301
1469
  continue;
1302
1470
  // The Agent already received a steer mid-turn; its persisted row is display-only.
1303
- if (msg._error || isDict(msg._steer))
1471
+ if (msg._error || isDict(msg._steer) || msg._notice_kind === 'session_finalize')
1304
1472
  continue;
1305
1473
  if (msg._partial && !messageText(msg.content).trim())
1306
1474
  continue;
@@ -1310,7 +1478,10 @@ export function sanitizeMessagesForApi(messages, { preserveApiContent = false }
1310
1478
  if (!tid || !validToolCallIds.has(tid))
1311
1479
  continue;
1312
1480
  }
1313
- const sanitized = Object.fromEntries(Object.entries(msg).filter(([k]) => API_SAFE_MSG_KEYS.has(k)));
1481
+ const replayCarriers = preserveApiContent && msg.role === 'assistant';
1482
+ const issuedHere = issuedReasoningSince !== null && Number(msg.timestamp) >= issuedReasoningSince;
1483
+ const replayKey = (k) => replayCarriers && AGENT_ASSISTANT_REPLAY_KEYS.has(k) && (issuedHere || !PROVIDER_ISSUED_REASONING_KEYS.has(k));
1484
+ const sanitized = Object.fromEntries(Object.entries(msg).filter(([k]) => API_SAFE_MSG_KEYS.has(k) || replayKey(k)));
1314
1485
  if (Array.isArray(sanitized.tool_calls) && !sanitized.tool_calls.length)
1315
1486
  Reflect.deleteProperty(sanitized, 'tool_calls');
1316
1487
  if (replay)
@@ -1367,9 +1538,46 @@ export function sanitizeMessagesForApi(messages, { preserveApiContent = false }
1367
1538
  msg = Object.fromEntries(Object.entries(msg).filter(([k]) => k !== '_recovered'));
1368
1539
  }
1369
1540
  final.push(msg);
1541
+ if (final.length >= maxMessages)
1542
+ break;
1370
1543
  }
1371
1544
  return final;
1372
1545
  }
1546
+ /** A revision's compression threshold, using the sanitizer itself and stopping once four retained rows prove it. */
1547
+ export class ApiMessageSummary {
1548
+ excludeTurn;
1549
+ displayHistory;
1550
+ rows = [];
1551
+ unidentified = [new Map(), new Map()];
1552
+ enough = false;
1553
+ marker = false;
1554
+ nextCheck = 4;
1555
+ constructor(excludeTurn = null, displayHistory = true) {
1556
+ this.excludeTurn = excludeTurn;
1557
+ this.displayHistory = displayHistory;
1558
+ }
1559
+ add(row) {
1560
+ if (this.enough)
1561
+ return;
1562
+ if (this.displayHistory && (row._error || row._partial))
1563
+ return;
1564
+ this.marker ||= isContextCompressionMarker(row);
1565
+ if (this.enough || (this.excludeTurn && row._turn_id === this.excludeTurn))
1566
+ return;
1567
+ this.rows.push(row);
1568
+ for (const [mode, includeUids] of [false, true].entries())
1569
+ if (!stateDbIdentityKeys(row, includeUids).length) {
1570
+ const key = stateDbMessageKey(row);
1571
+ this.unidentified[mode].set(key, (this.unidentified[mode].get(key) ?? 0) + 1);
1572
+ }
1573
+ if (this.rows.length >= this.nextCheck) {
1574
+ this.finish();
1575
+ this.nextCheck *= 2;
1576
+ }
1577
+ }
1578
+ finish() { if (!this.enough)
1579
+ this.enough = sanitizeMessagesForApi(this.rows, { maxMessages: 4 }).length >= 4; }
1580
+ }
1373
1581
  const isNativeImagePart = (part) => isDict(part) && (part.type === 'image_url' || 'image_url' in part);
1374
1582
  /** True when any row's content carries a native `image_url` part. */
1375
1583
  export function hasNativeImages(messages) {