@inflexa-ai/harness 0.45.0 → 0.46.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 (802) hide show
  1. package/README.md +6 -3
  2. package/dist/agents/conversation-agent.d.ts +19 -3
  3. package/dist/agents/conversation-agent.js +49 -30
  4. package/dist/agents/report-session-agent.d.ts +15 -15
  5. package/dist/agents/report-session-agent.js +23 -15
  6. package/dist/agents/sandbox/index.d.ts +1 -1
  7. package/dist/agents/sandbox/index.js +1 -1
  8. package/dist/agents/sandbox/shared.d.ts +35 -16
  9. package/dist/agents/sandbox/shared.js +63 -24
  10. package/dist/agents/sandbox/translational-safety-agent.js +26 -0
  11. package/dist/agents/sandbox/types.d.ts +26 -3
  12. package/dist/agents/sandbox/validate-skills.d.ts +2 -2
  13. package/dist/agents/sandbox/validate-skills.js +3 -1
  14. package/dist/agents/sandbox-catalog.d.ts +16 -2
  15. package/dist/agents/sandbox-catalog.js +22 -3
  16. package/dist/agents/system-prompt.d.ts +2 -2
  17. package/dist/app/approve-plan.d.ts +5 -2
  18. package/dist/app/approve-plan.js +1 -1
  19. package/dist/app/chat-turn-workflow.d.ts +114 -0
  20. package/dist/app/chat-turn-workflow.js +307 -0
  21. package/dist/app/chat-turn.d.ts +85 -57
  22. package/dist/app/chat-turn.js +125 -99
  23. package/dist/app/data-profile-orientation.js +10 -8
  24. package/dist/app/data-profile-view.d.ts +4 -4
  25. package/dist/app/data-profile-view.js +9 -8
  26. package/dist/app/in-process-turn.d.ts +42 -0
  27. package/dist/app/in-process-turn.js +139 -0
  28. package/dist/app/message-assembly.d.ts +10 -4
  29. package/dist/app/message-assembly.js +13 -8
  30. package/dist/app/report-session-runtime.d.ts +4 -4
  31. package/dist/app/report-session-runtime.js +36 -21
  32. package/dist/app/spawn-report-session.d.ts +33 -28
  33. package/dist/app/spawn-report-session.js +25 -40
  34. package/dist/app/synthesize-run.d.ts +22 -16
  35. package/dist/app/synthesize-run.js +41 -35
  36. package/dist/app/work.d.ts +96 -0
  37. package/dist/app/work.js +147 -0
  38. package/dist/auth/local-auth-context.d.ts +1 -3
  39. package/dist/auth/local-auth-context.js +1 -3
  40. package/dist/auth/local-run-authorizer.d.ts +1 -1
  41. package/dist/auth/local-run-authorizer.js +5 -3
  42. package/dist/auth/types.d.ts +26 -26
  43. package/dist/billing/cached-resolver.d.ts +4 -4
  44. package/dist/billing/run-charge.d.ts +5 -8
  45. package/dist/billing/run-charge.js +2 -2
  46. package/dist/billing/usage-recorder.d.ts +9 -9
  47. package/dist/citations/aggregate.js +1 -1
  48. package/dist/citations/clients/arxiv.d.ts +2 -2
  49. package/dist/citations/clients/arxiv.js +12 -4
  50. package/dist/citations/clients/common.js +4 -2
  51. package/dist/citations/clients/crossref.d.ts +2 -2
  52. package/dist/citations/clients/crossref.js +37 -37
  53. package/dist/citations/clients/doi-registry.js +15 -16
  54. package/dist/citations/clients/pubmed.d.ts +2 -2
  55. package/dist/citations/clients/pubmed.js +20 -13
  56. package/dist/citations/clients/semantic-scholar.d.ts +2 -2
  57. package/dist/citations/clients/semantic-scholar.js +9 -9
  58. package/dist/citations/compare.js +2 -2
  59. package/dist/citations/match.d.ts +2 -2
  60. package/dist/citations/match.js +12 -7
  61. package/dist/citations/normalize.js +35 -26
  62. package/dist/citations/plan.js +6 -2
  63. package/dist/citations/resolve.d.ts +6 -6
  64. package/dist/citations/resolve.js +34 -25
  65. package/dist/citations/types.d.ts +77 -77
  66. package/dist/config/environment-stores.d.ts +10 -8
  67. package/dist/config/resource-limits.js +1 -3
  68. package/dist/contracts/analogy-report.d.ts +7 -7
  69. package/dist/contracts/analogy-report.js +2 -2
  70. package/dist/contracts/chat-events.d.ts +46 -22
  71. package/dist/contracts/chat-events.js +1 -1
  72. package/dist/contracts/chat-frame.d.ts +15 -5
  73. package/dist/contracts/chat-frame.js +67 -40
  74. package/dist/contracts/chat-parts.d.ts +130 -67
  75. package/dist/contracts/chat-parts.js +1 -0
  76. package/dist/contracts/content-url.js +16 -2
  77. package/dist/contracts/data-profile.d.ts +38 -38
  78. package/dist/contracts/index.d.ts +3 -3
  79. package/dist/contracts/index.js +1 -1
  80. package/dist/contracts/message.d.ts +6 -6
  81. package/dist/contracts/organ-system.d.ts +11 -11
  82. package/dist/contracts/part-registry.d.ts +5 -4
  83. package/dist/contracts/part-registry.js +5 -0
  84. package/dist/contracts/profile-vocabulary.d.ts +11 -10
  85. package/dist/contracts/profile-vocabulary.js +10 -3
  86. package/dist/contracts/report-blocks.d.ts +329 -329
  87. package/dist/contracts/report-reference.d.ts +105 -81
  88. package/dist/contracts/report-reference.js +30 -13
  89. package/dist/contracts/schemas/chat-events.d.ts +45 -6
  90. package/dist/contracts/schemas/chat-events.js +16 -0
  91. package/dist/contracts/schemas/chat-parts.d.ts +214 -102
  92. package/dist/contracts/schemas/chat-parts.js +50 -7
  93. package/dist/contracts/schemas/index.d.ts +1 -1
  94. package/dist/contracts/schemas/index.js +1 -1
  95. package/dist/contracts/severity.d.ts +1 -1
  96. package/dist/contracts/structure-source.d.ts +3 -3
  97. package/dist/contracts/structure-source.js +6 -2
  98. package/dist/contracts/subagent-activity.d.ts +2 -2
  99. package/dist/contracts/subagent-activity.js +5 -3
  100. package/dist/contracts/usage.d.ts +2 -2
  101. package/dist/data/safety-panel-schema.d.ts +25 -25
  102. package/dist/data/safety-panel-schema.js +13 -4
  103. package/dist/execution/artifact-metadata.d.ts +23 -15
  104. package/dist/execution/artifact-metadata.js +33 -10
  105. package/dist/execution/artifact-record.d.ts +2 -2
  106. package/dist/execution/artifact-registration.d.ts +5 -5
  107. package/dist/execution/artifact-registry.d.ts +8 -8
  108. package/dist/execution/dbos-run-launcher.d.ts +24 -4
  109. package/dist/execution/dbos-run-launcher.js +58 -4
  110. package/dist/execution/dbos-workflow-purger.d.ts +7 -6
  111. package/dist/execution/dbos-workflow-purger.js +29 -21
  112. package/dist/execution/input-signature.d.ts +2 -2
  113. package/dist/execution/post-step-pipeline.d.ts +9 -9
  114. package/dist/execution/post-step-pipeline.js +1 -1
  115. package/dist/execution/post-step.js +2 -2
  116. package/dist/execution/reconcile-manifest.d.ts +4 -4
  117. package/dist/execution/reconcile-manifest.js +3 -2
  118. package/dist/execution/run-authorizer.d.ts +46 -37
  119. package/dist/execution/run-authorizer.js +8 -8
  120. package/dist/execution/run-canceler.d.ts +39 -17
  121. package/dist/execution/run-canceler.js +137 -28
  122. package/dist/execution/run-end-record.d.ts +29 -0
  123. package/dist/execution/run-end-record.js +27 -0
  124. package/dist/execution/run-event-parts.d.ts +0 -8
  125. package/dist/execution/run-event-parts.js +29 -24
  126. package/dist/execution/run-event-stream.d.ts +8 -8
  127. package/dist/execution/run-event-stream.js +3 -4
  128. package/dist/execution/run-launcher.d.ts +4 -4
  129. package/dist/execution/run-synthesis.d.ts +49 -48
  130. package/dist/execution/run-synthesis.js +96 -255
  131. package/dist/execution/staged-input.d.ts +2 -2
  132. package/dist/execution/step-summary.d.ts +6 -6
  133. package/dist/execution/step-summary.js +4 -8
  134. package/dist/execution/topo-sort.js +4 -3
  135. package/dist/execution/workflow-purger.d.ts +2 -2
  136. package/dist/index.d.ts +25 -24
  137. package/dist/index.js +36 -37
  138. package/dist/input-sanitization.js +9 -2
  139. package/dist/input-scan/clustering.d.ts +6 -6
  140. package/dist/input-scan/clustering.js +11 -5
  141. package/dist/input-scan/companions.js +3 -2
  142. package/dist/input-scan/detect-sets.d.ts +2 -2
  143. package/dist/input-scan/detect-sets.js +25 -21
  144. package/dist/input-scan/enrich.d.ts +6 -6
  145. package/dist/input-scan/enrich.js +29 -12
  146. package/dist/input-scan/formats.d.ts +2 -2
  147. package/dist/input-scan/formats.js +8 -2
  148. package/dist/input-scan/markers.d.ts +2 -2
  149. package/dist/input-scan/markers.js +14 -5
  150. package/dist/input-scan/menu.d.ts +10 -10
  151. package/dist/input-scan/menu.js +0 -0
  152. package/dist/input-scan/quarantine.d.ts +2 -2
  153. package/dist/input-scan/quarantine.js +23 -18
  154. package/dist/input-scan/readout-budget.d.ts +2 -2
  155. package/dist/input-scan/readout-budget.js +1 -1
  156. package/dist/input-scan/readout.d.ts +2 -2
  157. package/dist/input-scan/readout.js +47 -34
  158. package/dist/input-scan/scan.d.ts +2 -2
  159. package/dist/input-scan/scan.js +7 -5
  160. package/dist/input-scan/set-types.d.ts +28 -28
  161. package/dist/input-scan/shapes.d.ts +4 -4
  162. package/dist/input-scan/shapes.js +0 -0
  163. package/dist/input-scan/templates.d.ts +10 -10
  164. package/dist/input-scan/templates.js +30 -22
  165. package/dist/input-scan/tokens.d.ts +6 -4
  166. package/dist/input-scan/tokens.js +100 -38
  167. package/dist/input-scan/types.d.ts +22 -22
  168. package/dist/lib/async-utils.d.ts +3 -7
  169. package/dist/lib/async-utils.js +5 -9
  170. package/dist/lib/cache.js +1 -1
  171. package/dist/lib/chrome.d.ts +46 -6
  172. package/dist/lib/console-logger.js +2 -2
  173. package/dist/lib/db-result.d.ts +22 -6
  174. package/dist/lib/db-result.js +9 -13
  175. package/dist/lib/eyes.d.ts +4 -4
  176. package/dist/lib/eyes.js +1 -1
  177. package/dist/lib/fs-helpers.js +18 -6
  178. package/dist/lib/fs-result.d.ts +1 -0
  179. package/dist/lib/fs-result.js +5 -6
  180. package/dist/lib/hooks.d.ts +23 -7
  181. package/dist/lib/hooks.js +17 -3
  182. package/dist/lib/host-concurrency.js +3 -2
  183. package/dist/lib/logger.d.ts +2 -2
  184. package/dist/lib/logger.js +2 -1
  185. package/dist/lib/metrics.d.ts +1 -1
  186. package/dist/lib/null-proto.d.ts +6 -0
  187. package/dist/lib/null-proto.js +17 -0
  188. package/dist/lib/otel-spans.d.ts +1 -1
  189. package/dist/lib/otel-spans.js +9 -5
  190. package/dist/lib/otel.d.ts +4 -2
  191. package/dist/lib/otel.js +10 -2
  192. package/dist/lib/page-capture.d.ts +8 -8
  193. package/dist/lib/page-capture.js +9 -4
  194. package/dist/lib/parse-json.d.ts +5 -0
  195. package/dist/lib/parse-json.js +12 -0
  196. package/dist/lib/present.d.ts +12 -0
  197. package/dist/lib/present.js +39 -0
  198. package/dist/lib/rate-limit.d.ts +4 -4
  199. package/dist/lib/rate-limit.js +12 -13
  200. package/dist/lib/regulatory-corpus/fetch-fda-guidance.d.ts +4 -4
  201. package/dist/lib/regulatory-corpus/fetch-fda-guidance.js +4 -10
  202. package/dist/lib/regulatory-corpus/fetch-ich.d.ts +4 -4
  203. package/dist/lib/regulatory-corpus/fetch-ich.js +18 -14
  204. package/dist/lib/regulatory-corpus/normalize-whitespace.d.ts +6 -0
  205. package/dist/lib/regulatory-corpus/normalize-whitespace.js +41 -0
  206. package/dist/lib/regulatory-corpus.d.ts +10 -10
  207. package/dist/lib/regulatory-corpus.js +3 -1
  208. package/dist/lib/result.d.ts +10 -11
  209. package/dist/lib/result.js +15 -13
  210. package/dist/lib/storage.d.ts +2 -2
  211. package/dist/lib/test/async-iterable.d.ts +9 -0
  212. package/dist/lib/test/async-iterable.js +28 -0
  213. package/dist/lib/test/request-url.d.ts +5 -0
  214. package/dist/lib/test/request-url.js +7 -0
  215. package/dist/lib/test/result-assert.d.ts +12 -0
  216. package/dist/lib/test/result-assert.js +17 -0
  217. package/dist/lib/test/text-shapes.d.ts +24 -0
  218. package/dist/lib/test/text-shapes.js +63 -0
  219. package/dist/lib/text.d.ts +22 -0
  220. package/dist/lib/text.js +68 -0
  221. package/dist/lib/thrown.d.ts +18 -0
  222. package/dist/lib/thrown.js +30 -0
  223. package/dist/lib/unknown-array.d.ts +6 -0
  224. package/dist/lib/unknown-array.js +8 -0
  225. package/dist/lib/unknown-containers.d.ts +14 -0
  226. package/dist/lib/unknown-containers.js +17 -0
  227. package/dist/lib/unknown-text.d.ts +8 -0
  228. package/dist/lib/unknown-text.js +28 -0
  229. package/dist/lib/zod-issue-shape.d.ts +1 -1
  230. package/dist/lib/zod-issue-shape.js +31 -31
  231. package/dist/lib/zod-issues.d.ts +3 -3
  232. package/dist/lib/zod-issues.js +30 -17
  233. package/dist/literature/sources/arxiv.d.ts +6 -6
  234. package/dist/literature/sources/arxiv.js +92 -35
  235. package/dist/literature/sources/http.d.ts +2 -2
  236. package/dist/literature/sources/http.js +16 -15
  237. package/dist/literature/sources/pubmed.d.ts +16 -16
  238. package/dist/literature/sources/pubmed.js +96 -61
  239. package/dist/literature/sources/semantic-scholar.d.ts +8 -8
  240. package/dist/literature/sources/semantic-scholar.js +22 -13
  241. package/dist/loop/accounting.d.ts +63 -0
  242. package/dist/loop/accounting.js +141 -0
  243. package/dist/loop/call-policy.d.ts +73 -0
  244. package/dist/loop/call-policy.js +109 -0
  245. package/dist/loop/chat-stream.d.ts +62 -0
  246. package/dist/loop/chat-stream.js +237 -0
  247. package/dist/loop/compaction.d.ts +14 -9
  248. package/dist/loop/compaction.js +17 -0
  249. package/dist/loop/metrics.d.ts +12 -15
  250. package/dist/loop/metrics.js +14 -26
  251. package/dist/loop/run-loop.d.ts +233 -0
  252. package/dist/loop/run-loop.js +770 -0
  253. package/dist/loop/sub-agent.d.ts +61 -0
  254. package/dist/loop/sub-agent.js +161 -0
  255. package/dist/loop/tool-adapter.d.ts +98 -0
  256. package/dist/loop/tool-adapter.js +364 -0
  257. package/dist/loop/tool-detail.d.ts +1 -1
  258. package/dist/loop/tool-detail.js +6 -5
  259. package/dist/loop/tool-outcome.d.ts +1 -1
  260. package/dist/loop/tool-output.d.ts +4 -4
  261. package/dist/loop/tool-output.js +2 -2
  262. package/dist/loop/turn-credentials.d.ts +34 -0
  263. package/dist/loop/turn-credentials.js +73 -0
  264. package/dist/loop/types.d.ts +34 -37
  265. package/dist/loop/types.js +2 -7
  266. package/dist/memory/ai-sdk-message-storage.d.ts +5 -5
  267. package/dist/memory/ai-sdk-message-storage.js +13 -11
  268. package/dist/memory/card-builders.d.ts +14 -14
  269. package/dist/memory/card-builders.js +19 -15
  270. package/dist/memory/conversation-display-recorder.d.ts +22 -6
  271. package/dist/memory/conversation-display-recorder.js +64 -20
  272. package/dist/memory/conversation-display-replay.js +3 -2
  273. package/dist/memory/conversation-display-storage.d.ts +15 -7
  274. package/dist/memory/conversation-display-storage.js +141 -36
  275. package/dist/memory/conversation-view.d.ts +4 -4
  276. package/dist/memory/conversation-view.js +5 -4
  277. package/dist/memory/count-tokens.js +10 -8
  278. package/dist/memory/derive-thread-title.d.ts +0 -13
  279. package/dist/memory/derive-thread-title.js +2 -1
  280. package/dist/memory/message-backfill.d.ts +12 -5
  281. package/dist/memory/message-backfill.js +5 -3
  282. package/dist/memory/thread-history.d.ts +66 -24
  283. package/dist/memory/thread-history.js +212 -79
  284. package/dist/memory/thread-store.d.ts +26 -17
  285. package/dist/memory/thread-store.js +15 -9
  286. package/dist/memory/tool-call-integrity.d.ts +2 -2
  287. package/dist/memory/tool-call-integrity.js +4 -3
  288. package/dist/memory/working-memory.d.ts +16 -12
  289. package/dist/memory/working-memory.js +72 -61
  290. package/dist/prompts/briefing.d.ts +63 -9
  291. package/dist/prompts/briefing.js +130 -3
  292. package/dist/prompts/planner.js +13 -2
  293. package/dist/prompts/synthesis-agent.d.ts +1 -1
  294. package/dist/prompts/synthesis-agent.js +6 -14
  295. package/dist/provenance/collector.d.ts +6 -6
  296. package/dist/provenance/collector.js +15 -8
  297. package/dist/provenance/exec-frame.d.ts +2 -2
  298. package/dist/provenance/exec-frame.js +6 -1
  299. package/dist/provenance/seam.d.ts +24 -19
  300. package/dist/provenance/seam.js +7 -5
  301. package/dist/provenance/types.d.ts +6 -6
  302. package/dist/providers/ai-sdk.d.ts +113 -62
  303. package/dist/providers/ai-sdk.js +303 -458
  304. package/dist/providers/embedding.d.ts +2 -2
  305. package/dist/providers/embedding.js +1 -1
  306. package/dist/providers/errors.d.ts +22 -2
  307. package/dist/providers/errors.js +98 -50
  308. package/dist/providers/prompt-cache.d.ts +8 -8
  309. package/dist/providers/prompt-cache.js +13 -11
  310. package/dist/providers/reasoning.d.ts +2 -2
  311. package/dist/providers/reasoning.js +2 -2
  312. package/dist/providers/types.d.ts +59 -92
  313. package/dist/reference-data/catalog.d.ts +2 -15
  314. package/dist/reference-data/catalog.js +166 -10
  315. package/dist/reference-data/receipt.d.ts +2 -2
  316. package/dist/report-model/assert-rules.js +1 -1
  317. package/dist/report-model/authoring-grammar.d.ts +209 -231
  318. package/dist/report-model/block-walk.d.ts +10 -10
  319. package/dist/report-model/block-walk.js +2 -0
  320. package/dist/report-model/draft-finish.d.ts +8 -8
  321. package/dist/report-model/draft-finish.js +1 -1
  322. package/dist/report-model/draft-hash.js +8 -7
  323. package/dist/report-model/draft-operations.d.ts +22 -10
  324. package/dist/report-model/draft-operations.js +48 -30
  325. package/dist/report-model/draft-read.d.ts +19 -7
  326. package/dist/report-model/draft-read.js +16 -6
  327. package/dist/report-model/draft.d.ts +844 -2
  328. package/dist/report-model/draft.js +3 -1
  329. package/dist/report-model/fixture-resolver.js +39 -16
  330. package/dist/report-model/pin-snapshot.d.ts +2 -2
  331. package/dist/report-model/pin-snapshot.js +15 -15
  332. package/dist/report-model/production-resolver.d.ts +18 -18
  333. package/dist/report-model/production-resolver.js +50 -42
  334. package/dist/report-model/reference-resolver.d.ts +26 -10
  335. package/dist/report-model/reference-resolver.js +68 -5
  336. package/dist/report-model/reference-stamp.js +30 -38
  337. package/dist/report-model/structural-validation.js +12 -4
  338. package/dist/report-model/validate.d.ts +7 -7
  339. package/dist/report-model/validate.js +6 -6
  340. package/dist/report-render/assets.d.ts +2 -2
  341. package/dist/report-render/assets.js +27 -3
  342. package/dist/report-render/chart-export.d.ts +10 -2
  343. package/dist/report-render/chart-export.js +37 -11
  344. package/dist/report-render/chart-presets.d.ts +8 -8
  345. package/dist/report-render/chart-presets.js +3 -3
  346. package/dist/report-render/chart-renderers.d.ts +23 -16
  347. package/dist/report-render/chart-renderers.js +74 -53
  348. package/dist/report-render/chart-toolbox.d.ts +2 -2
  349. package/dist/report-render/chart-toolbox.js +7 -6
  350. package/dist/report-render/chart.d.ts +15 -16
  351. package/dist/report-render/chart.js +369 -252
  352. package/dist/report-render/design.d.ts +36 -297
  353. package/dist/report-render/design.js +0 -12
  354. package/dist/report-render/figures/common.d.ts +12 -12
  355. package/dist/report-render/figures/common.js +42 -31
  356. package/dist/report-render/figures/dendrogram.d.ts +3 -3
  357. package/dist/report-render/figures/dendrogram.js +10 -10
  358. package/dist/report-render/figures/dense.js +15 -8
  359. package/dist/report-render/figures/dotplot.js +46 -33
  360. package/dist/report-render/figures/embedding.js +52 -43
  361. package/dist/report-render/figures/equal-units.d.ts +10 -10
  362. package/dist/report-render/figures/equal-units.js +27 -27
  363. package/dist/report-render/figures/forest.js +9 -7
  364. package/dist/report-render/figures/gsea.js +21 -11
  365. package/dist/report-render/figures/heatmap.js +13 -9
  366. package/dist/report-render/figures/index.d.ts +10 -10
  367. package/dist/report-render/figures/index.js +4 -2
  368. package/dist/report-render/figures/km.js +10 -9
  369. package/dist/report-render/figures/label-room.d.ts +12 -12
  370. package/dist/report-render/figures/label-room.js +7 -2
  371. package/dist/report-render/figures/locuszoom.d.ts +2 -2
  372. package/dist/report-render/figures/locuszoom.js +59 -31
  373. package/dist/report-render/figures/lollipop.js +3 -2
  374. package/dist/report-render/figures/ma.js +8 -4
  375. package/dist/report-render/figures/manhattan.d.ts +1 -2
  376. package/dist/report-render/figures/manhattan.js +52 -34
  377. package/dist/report-render/figures/oncoprint.js +4 -5
  378. package/dist/report-render/figures/pca.js +25 -11
  379. package/dist/report-render/figures/qq.js +20 -9
  380. package/dist/report-render/figures/roc.js +1 -1
  381. package/dist/report-render/figures/sankey.d.ts +2 -2
  382. package/dist/report-render/figures/sankey.js +11 -10
  383. package/dist/report-render/figures/upset.d.ts +6 -6
  384. package/dist/report-render/figures/upset.js +7 -4
  385. package/dist/report-render/figures/volcano.js +12 -10
  386. package/dist/report-render/hybrid-svg.d.ts +4 -4
  387. package/dist/report-render/hybrid-svg.js +7 -5
  388. package/dist/report-render/number-format.d.ts +4 -4
  389. package/dist/report-render/number-format.js +62 -27
  390. package/dist/report-render/page.js +2 -1
  391. package/dist/report-render/provenance-data.d.ts +2 -2
  392. package/dist/report-render/references.d.ts +4 -4
  393. package/dist/report-render/render.d.ts +2 -2
  394. package/dist/report-render/render.js +10 -11
  395. package/dist/report-render/script-json.js +1 -1
  396. package/dist/report-render/table-data.d.ts +6 -6
  397. package/dist/report-render/test/options.d.ts +49 -0
  398. package/dist/report-render/test/options.js +143 -0
  399. package/dist/report-render/test/page-function.d.ts +19 -0
  400. package/dist/report-render/test/page-function.js +33 -0
  401. package/dist/report-render/types.d.ts +10 -10
  402. package/dist/report-render/value-bridge.d.ts +4 -4
  403. package/dist/report-render/value-bridge.js +27 -14
  404. package/dist/report-render/views/chart-view.d.ts +2 -2
  405. package/dist/report-render/views/chart-view.js +2 -2
  406. package/dist/report-render/views/lineage.d.ts +6 -6
  407. package/dist/report-render/views/lineage.js +2 -0
  408. package/dist/report-render/views/page-view.d.ts +2 -2
  409. package/dist/report-render/views/page-view.js +1 -0
  410. package/dist/report-render/views/prose.js +25 -8
  411. package/dist/report-render/views/references-view.js +12 -1
  412. package/dist/report-render/views/values.js +1 -1
  413. package/dist/runtime/assemble.d.ts +53 -26
  414. package/dist/runtime/assemble.js +103 -56
  415. package/dist/runtime/boot.d.ts +8 -7
  416. package/dist/runtime/boot.js +1 -1
  417. package/dist/runtime/connection-budget.d.ts +6 -6
  418. package/dist/runtime/connection-budget.js +1 -1
  419. package/dist/runtime/dbos.d.ts +29 -19
  420. package/dist/runtime/dbos.js +35 -20
  421. package/dist/runtime/result-serialization.js +18 -5
  422. package/dist/runtime/shutdown.d.ts +2 -2
  423. package/dist/sandbox/client.d.ts +7 -3
  424. package/dist/sandbox/cpu-files.d.ts +2 -2
  425. package/dist/sandbox/cpu-files.js +21 -4
  426. package/dist/sandbox/create-sandbox.d.ts +7 -8
  427. package/dist/sandbox/create-sandbox.js +6 -12
  428. package/dist/sandbox/docker-client.d.ts +48 -3
  429. package/dist/sandbox/docker-client.js +10 -6
  430. package/dist/sandbox/estimate-data-profile-resources.js +2 -7
  431. package/dist/sandbox/exec-outcome.d.ts +2 -2
  432. package/dist/sandbox/exec-outcome.js +1 -1
  433. package/dist/sandbox/exec.d.ts +10 -6
  434. package/dist/sandbox/exec.js +27 -12
  435. package/dist/sandbox/execution-id.js +14 -6
  436. package/dist/sandbox/farm.d.ts +2 -2
  437. package/dist/sandbox/farm.js +22 -27
  438. package/dist/sandbox/identity.d.ts +7 -0
  439. package/dist/sandbox/identity.js +14 -3
  440. package/dist/sandbox/image-packages.d.ts +26 -4
  441. package/dist/sandbox/image-packages.js +29 -27
  442. package/dist/sandbox/k8s-client.d.ts +35 -8
  443. package/dist/sandbox/k8s-client.js +6 -5
  444. package/dist/sandbox/labels.js +1 -0
  445. package/dist/sandbox/liveness.js +3 -1
  446. package/dist/sandbox/mount-plan.d.ts +10 -10
  447. package/dist/sandbox/mount-plan.js +13 -14
  448. package/dist/sandbox/notification-sweep.d.ts +4 -4
  449. package/dist/sandbox/notification-sweep.js +4 -7
  450. package/dist/sandbox/package-identity.d.ts +6 -13
  451. package/dist/sandbox/package-identity.js +46 -28
  452. package/dist/sandbox/reaper.d.ts +10 -10
  453. package/dist/sandbox/reaper.js +4 -6
  454. package/dist/sandbox/sandbox-error.d.ts +2 -9
  455. package/dist/sandbox/sandbox-error.js +21 -8
  456. package/dist/sandbox/sandbox-step-translate.d.ts +8 -5
  457. package/dist/sandbox/sandbox-step-translate.js +22 -8
  458. package/dist/sandbox/step-sandbox.d.ts +47 -0
  459. package/dist/sandbox/step-sandbox.js +53 -0
  460. package/dist/sandbox/types.d.ts +18 -19
  461. package/dist/sandbox/types.js +1 -1
  462. package/dist/schemas/artifact-manifest.d.ts +4 -4
  463. package/dist/schemas/data-profile-schemas.d.ts +351 -306
  464. package/dist/schemas/file-metadata.js +2 -4
  465. package/dist/schemas/plan-schemas.d.ts +79 -25
  466. package/dist/schemas/plan-schemas.js +1 -1
  467. package/dist/schemas/run-synthesis.d.ts +95 -26
  468. package/dist/schemas/run-synthesis.js +3 -1
  469. package/dist/schemas/validate-plan.d.ts +4 -4
  470. package/dist/schemas/validate-plan.js +17 -5
  471. package/dist/schemas/workflow-state.d.ts +127 -14
  472. package/dist/schemas/workflow-state.js +56 -2
  473. package/dist/state/active-turns.d.ts +36 -0
  474. package/dist/state/active-turns.js +67 -0
  475. package/dist/state/analyses-metrics.d.ts +8 -8
  476. package/dist/state/analyses-metrics.js +4 -4
  477. package/dist/state/analyses.d.ts +0 -14
  478. package/dist/state/analyses.js +0 -32
  479. package/dist/state/artifacts.d.ts +47 -18
  480. package/dist/state/artifacts.js +48 -7
  481. package/dist/state/data-profile.d.ts +2 -2
  482. package/dist/state/db.d.ts +12 -2
  483. package/dist/state/db.js +5 -0
  484. package/dist/state/edit-intents.d.ts +4 -0
  485. package/dist/state/edit-intents.js +71 -0
  486. package/dist/state/index.d.ts +5 -5
  487. package/dist/state/index.js +3 -3
  488. package/dist/state/init.d.ts +2 -1
  489. package/dist/state/init.js +5 -2
  490. package/dist/state/migrations/20260927120000_baseline.js +3 -1
  491. package/dist/state/migrations/20261026120000_add_the_edit_intents.d.ts +7 -0
  492. package/dist/state/migrations/20261026120000_add_the_edit_intents.js +21 -0
  493. package/dist/state/migrations/20261027120000_record_the_applied_memory_edits.d.ts +7 -0
  494. package/dist/state/migrations/20261027120000_record_the_applied_memory_edits.js +16 -0
  495. package/dist/state/migrations/20261027120100_store_the_authoring_results.d.ts +8 -0
  496. package/dist/state/migrations/20261027120100_store_the_authoring_results.js +20 -0
  497. package/dist/state/migrations/20261027120200_key_the_groups_of_a_turn.d.ts +7 -0
  498. package/dist/state/migrations/20261027120200_key_the_groups_of_a_turn.js +12 -0
  499. package/dist/state/migrations/20261027120300_mark_the_active_turn_of_a_thread.d.ts +7 -0
  500. package/dist/state/migrations/20261027120300_mark_the_active_turn_of_a_thread.js +11 -0
  501. package/dist/state/migrations/20261028120000_record_the_paused_work.d.ts +7 -0
  502. package/dist/state/migrations/20261028120000_record_the_paused_work.js +25 -0
  503. package/dist/state/migrations/20261028120100_end_the_suspended_runs.d.ts +8 -0
  504. package/dist/state/migrations/20261028120100_end_the_suspended_runs.js +13 -0
  505. package/dist/state/migrations/20261029120000_reference_the_run_mandate.d.ts +7 -0
  506. package/dist/state/migrations/20261029120000_reference_the_run_mandate.js +23 -0
  507. package/dist/state/migrations/20261029120100_record_the_run_session_of_a_pause.d.ts +7 -0
  508. package/dist/state/migrations/20261029120100_record_the_run_session_of_a_pause.js +11 -0
  509. package/dist/state/migrations/index.js +18 -0
  510. package/dist/state/paused-work.d.ts +52 -0
  511. package/dist/state/paused-work.js +105 -0
  512. package/dist/state/plans.d.ts +27 -8
  513. package/dist/state/plans.js +14 -11
  514. package/dist/state/purge-analysis.d.ts +6 -6
  515. package/dist/state/purge-analysis.js +10 -2
  516. package/dist/state/report-session-state.d.ts +43 -18
  517. package/dist/state/report-session-state.js +43 -4
  518. package/dist/state/report-versions.d.ts +16 -11
  519. package/dist/state/report-versions.js +5 -3
  520. package/dist/state/runs.d.ts +70 -25
  521. package/dist/state/runs.js +127 -64
  522. package/dist/state/schema.d.ts +18 -21
  523. package/dist/state/schema.js +4 -5
  524. package/dist/state/snapshot-parse.d.ts +2 -2
  525. package/dist/state/snapshot-parse.js +14 -8
  526. package/dist/state/step-executions.d.ts +29 -8
  527. package/dist/state/step-executions.js +28 -4
  528. package/dist/state/tool-outputs.d.ts +2 -2
  529. package/dist/state/tool-outputs.js +2 -1
  530. package/dist/state/vector-store.d.ts +16 -16
  531. package/dist/state/vector-store.js +11 -7
  532. package/dist/tasks/data-profile-absorb.d.ts +3 -3
  533. package/dist/tasks/data-profile-absorb.js +21 -16
  534. package/dist/tasks/data-profile-activity.d.ts +5 -5
  535. package/dist/tasks/data-profile-activity.js +5 -5
  536. package/dist/tasks/data-profile-index.d.ts +4 -4
  537. package/dist/tasks/data-profile-index.js +32 -17
  538. package/dist/tasks/data-profile-resolve.d.ts +8 -8
  539. package/dist/tasks/data-profile-resolve.js +88 -62
  540. package/dist/tasks/data-profile.d.ts +40 -31
  541. package/dist/tasks/data-profile.js +138 -95
  542. package/dist/tasks/extract-values.d.ts +26 -79
  543. package/dist/tasks/extract-values.js +48 -108
  544. package/dist/tasks/refresh-regulatory-corpus.d.ts +4 -20
  545. package/dist/tasks/refresh-regulatory-corpus.js +12 -8
  546. package/dist/tasks/regulatory-corpus-boot-refresh.d.ts +2 -2
  547. package/dist/tasks/regulatory-corpus-boot-refresh.js +12 -10
  548. package/dist/testing.d.ts +60 -0
  549. package/dist/testing.js +96 -0
  550. package/dist/tools/ad-hoc-router.d.ts +11 -9
  551. package/dist/tools/ad-hoc-router.js +80 -51
  552. package/dist/tools/analysis-invocation.d.ts +7 -0
  553. package/dist/tools/analysis-invocation.js +29 -5
  554. package/dist/tools/approval/contract.d.ts +8 -52
  555. package/dist/tools/approval/contract.js +7 -36
  556. package/dist/tools/approval/gateway.d.ts +27 -28
  557. package/dist/tools/approval/gateway.js +33 -130
  558. package/dist/tools/approval/queries.d.ts +6 -11
  559. package/dist/tools/approval/queries.js +43 -29
  560. package/dist/tools/approval/uuidv7.js +2 -2
  561. package/dist/tools/bio/chembl.d.ts +3 -3
  562. package/dist/tools/bio/chembl.js +10 -0
  563. package/dist/tools/bio/comptox.d.ts +25 -8
  564. package/dist/tools/bio/comptox.js +4 -2
  565. package/dist/tools/bio/drug-gene-interactions.d.ts +27 -17
  566. package/dist/tools/bio/drug-gene-interactions.js +11 -8
  567. package/dist/tools/bio/gene-disease-evidence.d.ts +61 -15
  568. package/dist/tools/bio/gene-disease-evidence.js +10 -6
  569. package/dist/tools/bio/gene-preclinical-profile.d.ts +11 -11
  570. package/dist/tools/bio/keys.d.ts +2 -2
  571. package/dist/tools/bio/keys.js +3 -3
  572. package/dist/tools/bio/lookup-annotation.d.ts +5 -5
  573. package/dist/tools/bio/lookup-annotation.js +3 -0
  574. package/dist/tools/bio/opentargets.d.ts +1 -1
  575. package/dist/tools/bio/opentargets.js +6 -0
  576. package/dist/tools/bio/pubchem.d.ts +2 -2
  577. package/dist/tools/bio/pubchem.js +6 -0
  578. package/dist/tools/bio/pubmed.d.ts +26 -16
  579. package/dist/tools/bio/pubmed.js +9 -3
  580. package/dist/tools/bio/search-clinical-trials.d.ts +4 -4
  581. package/dist/tools/bio/search-clinical-trials.js +5 -1
  582. package/dist/tools/bio/search-faers.d.ts +2 -2
  583. package/dist/tools/bio/search-faers.js +1 -1
  584. package/dist/tools/bio/search-gene.d.ts +2 -2
  585. package/dist/tools/bio/search-gene.js +1 -0
  586. package/dist/tools/bio/search-geo-datasets.d.ts +4 -4
  587. package/dist/tools/bio/search-geo-datasets.js +5 -5
  588. package/dist/tools/bio/search-interactions.d.ts +1 -1
  589. package/dist/tools/bio/search-patents.d.ts +28 -22
  590. package/dist/tools/bio/search-patents.js +20 -17
  591. package/dist/tools/bio/search-protein.d.ts +2 -2
  592. package/dist/tools/bio/search-protein.js +1 -1
  593. package/dist/tools/bio/search-regulatory-approvals.d.ts +64 -18
  594. package/dist/tools/bio/search-regulatory-approvals.js +21 -16
  595. package/dist/tools/bio/target-safety.d.ts +8 -8
  596. package/dist/tools/bio/target-safety.js +11 -6
  597. package/dist/tools/capability-data.d.ts +40 -0
  598. package/dist/tools/capability-data.js +74 -0
  599. package/dist/tools/define-tool.d.ts +55 -46
  600. package/dist/tools/define-tool.js +39 -27
  601. package/dist/tools/display/normalize-echart-spec.d.ts +2 -2
  602. package/dist/tools/display/normalize-echart-spec.js +51 -27
  603. package/dist/tools/display/show-user.d.ts +2 -2
  604. package/dist/tools/display/show-user.js +1 -1
  605. package/dist/tools/execute-analysis.d.ts +54 -17
  606. package/dist/tools/execute-analysis.js +193 -62
  607. package/dist/tools/knowledge/check.d.ts +182 -0
  608. package/dist/tools/knowledge/check.js +94 -0
  609. package/dist/tools/knowledge/client.d.ts +351 -0
  610. package/dist/tools/knowledge/client.js +319 -0
  611. package/dist/tools/knowledge/environment.d.ts +78 -0
  612. package/dist/tools/knowledge/environment.js +116 -0
  613. package/dist/tools/knowledge/index.d.ts +49 -0
  614. package/dist/tools/knowledge/index.js +70 -0
  615. package/dist/tools/knowledge/local-slots.d.ts +62 -0
  616. package/dist/tools/knowledge/local-slots.js +184 -0
  617. package/dist/tools/knowledge/pin.d.ts +14 -0
  618. package/dist/tools/knowledge/pin.js +17 -0
  619. package/dist/tools/knowledge/recommend.d.ts +67 -0
  620. package/dist/tools/knowledge/recommend.js +106 -0
  621. package/dist/tools/knowledge/situation.d.ts +143 -0
  622. package/dist/tools/knowledge/situation.js +157 -0
  623. package/dist/tools/knowledge/skeleton.d.ts +69 -0
  624. package/dist/tools/knowledge/skeleton.js +201 -0
  625. package/dist/tools/knowledge/template.d.ts +139 -0
  626. package/dist/tools/knowledge/template.js +273 -0
  627. package/dist/tools/lib/alphafold-client.js +2 -1
  628. package/dist/tools/lib/amass-client.d.ts +28 -28
  629. package/dist/tools/lib/amass-client.js +20 -10
  630. package/dist/tools/lib/api-utils.d.ts +13 -3
  631. package/dist/tools/lib/api-utils.js +17 -3
  632. package/dist/tools/lib/bgee-client.d.ts +6 -6
  633. package/dist/tools/lib/bgee-client.js +16 -10
  634. package/dist/tools/lib/cbioportal-client.d.ts +4 -4
  635. package/dist/tools/lib/cbioportal-client.js +9 -8
  636. package/dist/tools/lib/chembl-client.d.ts +14 -14
  637. package/dist/tools/lib/chembl-client.js +11 -4
  638. package/dist/tools/lib/clinical-benchmarks-client.d.ts +4 -4
  639. package/dist/tools/lib/clinical-benchmarks-client.js +4 -7
  640. package/dist/tools/lib/clinical-trials-client.d.ts +18 -18
  641. package/dist/tools/lib/clinical-trials-client.js +10 -10
  642. package/dist/tools/lib/clinvar-client.d.ts +2 -2
  643. package/dist/tools/lib/clinvar-client.js +6 -6
  644. package/dist/tools/lib/ctx-ops.d.ts +23 -23
  645. package/dist/tools/lib/ctx-ops.js +13 -10
  646. package/dist/tools/lib/dgidb-client.d.ts +6 -6
  647. package/dist/tools/lib/dgidb-client.js +10 -12
  648. package/dist/tools/lib/disgenet-client.d.ts +4 -4
  649. package/dist/tools/lib/ema-client.d.ts +2 -2
  650. package/dist/tools/lib/ensembl-client.d.ts +4 -4
  651. package/dist/tools/lib/ensembl-client.js +5 -4
  652. package/dist/tools/lib/gwas-catalog-client.d.ts +4 -4
  653. package/dist/tools/lib/gwas-catalog-client.js +17 -17
  654. package/dist/tools/lib/html-text.d.ts +6 -0
  655. package/dist/tools/lib/html-text.js +9 -0
  656. package/dist/tools/lib/identifier-resolver.d.ts +4 -4
  657. package/dist/tools/lib/identifier-resolver.js +7 -3
  658. package/dist/tools/lib/impc-client.d.ts +8 -8
  659. package/dist/tools/lib/impc-client.js +46 -35
  660. package/dist/tools/lib/iuphar-client.d.ts +2 -2
  661. package/dist/tools/lib/iuphar-client.js +7 -16
  662. package/dist/tools/lib/monarch-client.d.ts +4 -4
  663. package/dist/tools/lib/openfda-client.d.ts +22 -22
  664. package/dist/tools/lib/openfda-client.js +23 -22
  665. package/dist/tools/lib/opentargets-client.d.ts +12 -12
  666. package/dist/tools/lib/pathway-client.d.ts +4 -4
  667. package/dist/tools/lib/pathway-client.js +15 -19
  668. package/dist/tools/lib/pharmgkb-client.d.ts +2 -2
  669. package/dist/tools/lib/pharmgkb-client.js +1 -1
  670. package/dist/tools/lib/protein-family-modality.d.ts +2 -2
  671. package/dist/tools/lib/protein-family-modality.js +0 -2
  672. package/dist/tools/lib/protein-family-normalize.js +7 -0
  673. package/dist/tools/lib/pubchem-client.d.ts +2 -2
  674. package/dist/tools/lib/pubchem-client.js +1 -0
  675. package/dist/tools/lib/pubchem-ops.d.ts +4 -4
  676. package/dist/tools/lib/pubchem-ops.js +8 -0
  677. package/dist/tools/lib/pubmed-client.d.ts +9 -9
  678. package/dist/tools/lib/pubmed-client.js +1 -1
  679. package/dist/tools/lib/string-client.d.ts +6 -6
  680. package/dist/tools/lib/uniprot-client.d.ts +8 -8
  681. package/dist/tools/lib/uniprot-client.js +5 -1
  682. package/dist/tools/memory/update-working-memory.d.ts +16 -13
  683. package/dist/tools/memory/update-working-memory.js +21 -3
  684. package/dist/tools/read-tool-output.js +8 -2
  685. package/dist/tools/registry.d.ts +2 -2
  686. package/dist/tools/report-authoring/authoring-tools.d.ts +54 -23
  687. package/dist/tools/report-authoring/authoring-tools.js +128 -62
  688. package/dist/tools/report-session/derive-table.d.ts +19 -59
  689. package/dist/tools/report-session/derive-table.js +120 -122
  690. package/dist/tools/report-session/examine-page.d.ts +6 -6
  691. package/dist/tools/report-session/examine-page.js +14 -12
  692. package/dist/tools/report-session/list-artifacts.d.ts +6 -6
  693. package/dist/tools/report-session/list-artifacts.js +5 -5
  694. package/dist/tools/report-session/page-faults.d.ts +6 -6
  695. package/dist/tools/report-session/page-faults.js +3 -1
  696. package/dist/tools/report-session/preview-report.d.ts +4 -3
  697. package/dist/tools/report-session/preview-report.js +26 -7
  698. package/dist/tools/report-session/record-version.d.ts +9 -4
  699. package/dist/tools/report-session/record-version.js +16 -9
  700. package/dist/tools/report-session/session-page-publisher.d.ts +6 -6
  701. package/dist/tools/research/generate-analogy-report.d.ts +14 -7
  702. package/dist/tools/research/generate-analogy-report.js +80 -76
  703. package/dist/tools/research/generate-plan.d.ts +39 -16
  704. package/dist/tools/research/generate-plan.js +565 -338
  705. package/dist/tools/research/guarded-address.d.ts +20 -0
  706. package/dist/tools/research/guarded-address.js +149 -0
  707. package/dist/tools/research/inspect-data-profile.d.ts +27 -20
  708. package/dist/tools/research/inspect-data-profile.js +26 -25
  709. package/dist/tools/research/inspect-run.d.ts +54 -27
  710. package/dist/tools/research/inspect-run.js +50 -40
  711. package/dist/tools/research/literature-reviewer.d.ts +8 -7
  712. package/dist/tools/research/literature-reviewer.js +29 -28
  713. package/dist/tools/research/search-arxiv.d.ts +1 -1
  714. package/dist/tools/research/search-arxiv.js +1 -1
  715. package/dist/tools/research/search-github-repos.d.ts +10 -7
  716. package/dist/tools/research/search-github-repos.js +25 -22
  717. package/dist/tools/research/search-semantic-scholar.js +1 -1
  718. package/dist/tools/research/searxng-engine.d.ts +40 -0
  719. package/dist/tools/research/searxng-engine.js +122 -0
  720. package/dist/tools/research/web-fetch.d.ts +127 -0
  721. package/dist/tools/research/web-fetch.js +618 -0
  722. package/dist/tools/research/web-search.d.ts +84 -0
  723. package/dist/tools/research/web-search.js +117 -0
  724. package/dist/tools/sandbox/link-packages.d.ts +11 -7
  725. package/dist/tools/sandbox/link-packages.js +11 -8
  726. package/dist/tools/sandbox/list-available-packages.d.ts +24 -12
  727. package/dist/tools/sandbox/list-available-packages.js +43 -29
  728. package/dist/tools/sandbox/list-available-refs.d.ts +38 -14
  729. package/dist/tools/sandbox/list-available-refs.js +119 -37
  730. package/dist/tools/sandbox/report-blocker.d.ts +30 -37
  731. package/dist/tools/sandbox/report-blocker.js +22 -68
  732. package/dist/tools/sandbox/skills.d.ts +16 -12
  733. package/dist/tools/sandbox/skills.js +16 -12
  734. package/dist/tools/sandbox/submit-file-metadata.d.ts +12 -9
  735. package/dist/tools/sandbox/submit-file-metadata.js +18 -21
  736. package/dist/tools/start-report-session.d.ts +13 -5
  737. package/dist/tools/start-report-session.js +35 -8
  738. package/dist/tools/terminal-text.d.ts +14 -0
  739. package/dist/tools/terminal-text.js +51 -0
  740. package/dist/tools/workspace/decision-record.d.ts +81 -0
  741. package/dist/tools/workspace/decision-record.js +127 -0
  742. package/dist/tools/workspace/edit-file.d.ts +59 -18
  743. package/dist/tools/workspace/edit-file.js +98 -15
  744. package/dist/tools/workspace/execute-command.d.ts +31 -12
  745. package/dist/tools/workspace/execute-command.js +37 -8
  746. package/dist/tools/workspace/file-stat.d.ts +6 -3
  747. package/dist/tools/workspace/grep.d.ts +10 -7
  748. package/dist/tools/workspace/grep.js +9 -3
  749. package/dist/tools/workspace/index.d.ts +1 -0
  750. package/dist/tools/workspace/index.js +1 -0
  751. package/dist/tools/workspace/list-files.d.ts +6 -3
  752. package/dist/tools/workspace/mutator.d.ts +28 -15
  753. package/dist/tools/workspace/mutator.js +107 -53
  754. package/dist/tools/workspace/read-file.d.ts +8 -5
  755. package/dist/tools/workspace/result-bounds.d.ts +5 -5
  756. package/dist/tools/workspace/result-bounds.js +4 -2
  757. package/dist/tools/workspace/run-exec.d.ts +2 -2
  758. package/dist/tools/workspace/run-exec.js +3 -3
  759. package/dist/tools/workspace/scan-inputs.d.ts +8 -5
  760. package/dist/tools/workspace/scan-inputs.js +17 -5
  761. package/dist/tools/workspace/show-file.d.ts +1 -1
  762. package/dist/tools/workspace/show-file.js +2 -1
  763. package/dist/tools/workspace/show-plan.d.ts +8 -5
  764. package/dist/tools/workspace/show-plan.js +9 -8
  765. package/dist/tools/workspace/workspace-search.d.ts +41 -13
  766. package/dist/tools/workspace/workspace-search.js +27 -14
  767. package/dist/tools/workspace/write-file.d.ts +9 -7
  768. package/dist/workflows/execute-analysis-scheduler.d.ts +9 -9
  769. package/dist/workflows/execute-analysis-scheduler.js +6 -3
  770. package/dist/workflows/execute-analysis.d.ts +100 -76
  771. package/dist/workflows/execute-analysis.js +380 -247
  772. package/dist/workflows/pause.d.ts +71 -0
  773. package/dist/workflows/pause.js +173 -0
  774. package/dist/workflows/sandbox-step.d.ts +50 -61
  775. package/dist/workflows/sandbox-step.js +99 -106
  776. package/dist/workflows/test/sql-writes.d.ts +21 -0
  777. package/dist/workflows/test/sql-writes.js +36 -0
  778. package/dist/workspace/filesystem.d.ts +6 -6
  779. package/dist/workspace/filesystem.js +10 -8
  780. package/dist/workspace/paths.d.ts +1 -1
  781. package/dist/workspace/paths.js +15 -4
  782. package/dist/workspace/search-config.d.ts +2 -2
  783. package/dist/workspace/search-config.js +1 -1
  784. package/package.json +25 -22
  785. package/dist/loop/continue-agent.d.ts +0 -40
  786. package/dist/loop/continue-agent.js +0 -38
  787. package/dist/loop/genai-spans.d.ts +0 -47
  788. package/dist/loop/genai-spans.js +0 -134
  789. package/dist/loop/run-agent.d.ts +0 -236
  790. package/dist/loop/run-agent.js +0 -1110
  791. package/dist/loop/run-step.d.ts +0 -29
  792. package/dist/loop/run-step.js +0 -34
  793. package/dist/loop/run-to-terminal.d.ts +0 -66
  794. package/dist/loop/run-to-terminal.js +0 -90
  795. package/dist/loop/tool-mask.d.ts +0 -23
  796. package/dist/loop/tool-mask.js +0 -46
  797. package/dist/providers/streaming-chat.d.ts +0 -32
  798. package/dist/providers/streaming-chat.js +0 -91
  799. package/dist/tasks/derive-table-exec.d.ts +0 -54
  800. package/dist/tasks/derive-table-exec.js +0 -86
  801. package/dist/workflows/suspension.d.ts +0 -32
  802. package/dist/workflows/suspension.js +0 -38
@@ -22,15 +22,15 @@
22
22
  */
23
23
  import type { ModelMessage } from "ai";
24
24
  import { ResultAsync } from "neverthrow";
25
- import type { Pool } from "pg";
26
25
  import type { TokenUsageRollup } from "../contracts/usage.js";
27
- import { type DbError } from "../lib/db-result.js";
26
+ import { type Connectable, type DbError, type TransactionQuerier } from "../lib/db-result.js";
28
27
  import type { Logger } from "../lib/logger.js";
28
+ import type { Querier } from "../state/db.js";
29
29
  import { type StoredMessageEnvelope } from "./ai-sdk-message-storage.js";
30
30
  import type { MessagePart } from "../contracts/message.js";
31
31
  import { type ConversationUIMessage, type StoredDisplayEnvelope } from "./conversation-display-storage.js";
32
- /** One stored message, as returned by the display read (`loadAll`). */
33
- export interface StoredMessage {
32
+ /** One stored message, as returned by the display reads (`loadAll` and `loadPage`). */
33
+ export type StoredMessage = {
34
34
  readonly seq: number;
35
35
  readonly envelope: StoredMessageEnvelope;
36
36
  readonly message: ModelMessage;
@@ -69,7 +69,7 @@ export interface StoredMessage {
69
69
  * behind it.
70
70
  */
71
71
  readonly createdAt?: Date;
72
- }
72
+ };
73
73
  /**
74
74
  * One atomic group of rows: the exact provider-facing history, and the display
75
75
  * projection of what the user was shown.
@@ -79,7 +79,7 @@ export interface StoredMessage {
79
79
  * what the transcript replays. Neither is derived from the other, and a failed
80
80
  * write commits neither.
81
81
  */
82
- export interface ConversationTurn {
82
+ export type ConversationTurn = {
83
83
  /** Exact provider-facing history; token accounting and model reads use only this projection. */
84
84
  readonly modelMessages: readonly ModelMessage[];
85
85
  /** Complete ordered AI SDK UI messages recorded from the live display event stream. */
@@ -94,7 +94,12 @@ export interface ConversationTurn {
94
94
  * envelope, because a `text` parameter carrying 0x00 fails the statement.
95
95
  */
96
96
  readonly author?: string;
97
- }
97
+ /**
98
+ * The key of the group in its turn, stored on its first row. A turn workflow gives each group a key, thus a
99
+ * write that runs again after its commit finds the key and stores nothing.
100
+ */
101
+ readonly key?: string;
102
+ };
98
103
  /**
99
104
  * The append a host uses to record out-of-band work in a thread — an analysis
100
105
  * run's outcome, typically.
@@ -116,7 +121,7 @@ export declare function conversationRecordTurn(text: string, displayParts?: read
116
121
  /** The status of a chat turn: `open` while it runs, then its outcome. */
117
122
  export type TurnStatus = "open" | "done" | "aborted" | "failed";
118
123
  /** The close of a chat turn. It sets the outcome on the turn record, one time. */
119
- export interface TurnClose {
124
+ export type TurnClose = {
120
125
  readonly status: Exclude<TurnStatus, "open">;
121
126
  /** The reason of a failure. */
122
127
  readonly reason?: string;
@@ -125,7 +130,7 @@ export interface TurnClose {
125
130
  readonly turnDurationMs?: number;
126
131
  /** The note of a failure or of an abort, stored after the rounds. */
127
132
  readonly note?: ConversationTurn;
128
- }
133
+ };
129
134
  /**
130
135
  * One write of a chat turn. The opening adds the turn record, and a later write names the turn by
131
136
  * `startSeq`. The `never` members make a write with both keys fail to compile.
@@ -141,17 +146,17 @@ export type TurnWrite = {
141
146
  readonly rounds: readonly ConversationTurn[];
142
147
  readonly close?: TurnClose;
143
148
  };
144
- export interface TurnWriteResult {
149
+ export type TurnWriteResult = {
145
150
  /** The `seq` of the user row that opens the turn, which keys its turn record. */
146
151
  readonly startSeq: number;
147
- }
152
+ };
148
153
  /** The turn record of a chat turn, as the display read gives it. */
149
- export interface StoredTurnRecord {
154
+ export type StoredTurnRecord = {
150
155
  readonly status: TurnStatus;
151
156
  readonly reason?: string;
152
157
  readonly usage?: TokenUsageRollup;
153
158
  readonly durationMs?: number;
154
- }
159
+ };
155
160
  /**
156
161
  * The result of `retractLastTurn`. `retracted` carries `messages` — the number
157
162
  * of rows removed — so a caller can assert exactly what came off the tail. The
@@ -168,15 +173,34 @@ export type RetractOutcome = {
168
173
  kind: "no-user-turn";
169
174
  };
170
175
  /** The read options of {@link ThreadHistory.loadRecent}. */
171
- export interface LoadRecentOptions {
176
+ export type LoadRecentOptions = {
172
177
  /** Keep the first turn of the thread, the seed of a report thread, in front of the latest summary. */
173
178
  readonly keepFirstTurn?: boolean;
174
- }
179
+ /**
180
+ * Read the rows up to this `seq` only. A row never changes after its write, thus a turn workflow that reads up
181
+ * to the last row before its turn reads the same view on a replay.
182
+ */
183
+ readonly throughSeq?: number;
184
+ };
185
+ /** The options of {@link ThreadHistory.loadPage}. */
186
+ export type LoadPageOptions = {
187
+ /** The cursor that the previous page gave. Absent for the newest page. */
188
+ readonly before?: number;
189
+ /** The maximum count of turns in the page. */
190
+ readonly limit: number;
191
+ };
192
+ /** One page of the display read, as {@link ThreadHistory.loadPage} gives it. */
193
+ export type TurnPage = {
194
+ /** The whole turns of the page, oldest-first. */
195
+ readonly turns: StoredMessage[][];
196
+ /** The cursor of the next older page, or `null` when the page holds the oldest row of the thread. */
197
+ readonly before: number | null;
198
+ };
175
199
  /**
176
200
  * The conversation message store. Two methods, by design — no generic row
177
201
  * insert (see the harness-thread-store spec). `threadId` is the conversation scope — one UI thread.
178
202
  */
179
- export interface ThreadHistory {
203
+ export type ThreadHistory = {
180
204
  /**
181
205
  * Append one group, for example a record of a host — every message written in a
182
206
  * single transaction with a `seq` monotonically increasing per thread.
@@ -195,12 +219,8 @@ export interface ThreadHistory {
195
219
  /**
196
220
  * Return a thread's messages oldest-first for UI display, grouped into turns.
197
221
  * It gives each row, and the view of the agent loop is `loadRecent`'s job.
198
- *
199
- * There is no paginated form, because a page could never cost less: the read
200
- * selects and parses every row of the thread and would slice only afterwards,
201
- * so a page saves no query and no parse. It would only truncate the answer,
202
- * which is a way to lose turns and not a way to save work. A reader wanting a
203
- * window takes one here, where it knows what it is bounding.
222
+ * It selects and parses every row of the thread, thus its work grows with the
223
+ * thread. {@link ThreadHistory.loadPage} bounds that work.
204
224
  *
205
225
  * Grouped rather than flat because the grouping is what the read computes and
206
226
  * what a turn count means, and `.flat()` recovers the rows in `seq` order for
@@ -209,6 +229,23 @@ export interface ThreadHistory {
209
229
  * this read already found.
210
230
  */
211
231
  loadAll(threadId: string): ResultAsync<StoredMessage[][], DbError>;
232
+ /**
233
+ * Return the newest whole turns of a thread for UI display, up to `limit` turns, oldest-first.
234
+ * With `before`, it returns the newest whole turns below the turn that the cursor names.
235
+ * The rows are the same as the rows of {@link ThreadHistory.loadAll}.
236
+ *
237
+ * The read selects and parses only the rows of its page, thus its work does not grow with
238
+ * the turns before the page. The page edges inside the thread are turn starts, so the read
239
+ * never truncates a turn, also for a cursor that is not a turn start: the turn of the cursor
240
+ * row is then the newest turn of the page, and it is whole. The rows before the first turn
241
+ * start make one group, and the group counts as a turn.
242
+ *
243
+ * The cursor is the `seq` of the opening row of the oldest turn of the page. A `seq` never
244
+ * moves and a retract removes only the tail, thus a cursor stays correct across a later
245
+ * append and a later retract. A `limit` that is not finite reads as 1, and each other
246
+ * `limit` reads as its integer part with a minimum of 1.
247
+ */
248
+ loadPage(threadId: string, options: LoadPageOptions): ResultAsync<TurnPage, DbError>;
212
249
  /**
213
250
  * Remove the thread's most recent turn — every row from the last
214
251
  * genuine-user-start `seq` onward, and its turn record — in a single transaction.
@@ -259,7 +296,7 @@ export interface ThreadHistory {
259
296
  * one adds to the count.
260
297
  */
261
298
  countUserTurnsAfter(threadId: string, seq: number): ResultAsync<number, DbError>;
262
- }
299
+ };
263
300
  /**
264
301
  * Drop the memoized instruments so the next `loadRecent` rebinds to a
265
302
  * freshly-registered `MeterProvider`. Test-only.
@@ -275,4 +312,9 @@ export declare function __resetThreadHistoryMetricsForTest(): void;
275
312
  * same messages either way — the drop reports a deploy, not a failed read — and
276
313
  * requiring it would break every call site over a diagnostic.
277
314
  */
278
- export declare function createThreadHistory(pool: Pool, logger?: Logger): ThreadHistory;
315
+ /** What this module reads of the pool: the direct `query` plus the transactional `connect`. */
316
+ type ThreadHistoryPool = Querier & Connectable;
317
+ /** `appendTurn` inside the transaction of the caller, thus another write of the caller commits with the turn or not at all. */
318
+ export declare function appendTurnIn(client: TransactionQuerier, threadId: string, turn: ConversationTurn): ResultAsync<void, DbError>;
319
+ export declare function createThreadHistory(pool: ThreadHistoryPool, logger?: Logger): ThreadHistory;
320
+ export {};
@@ -25,11 +25,12 @@ import { metrics } from "@opentelemetry/api";
25
25
  import { ResultAsync, ok, okAsync } from "neverthrow";
26
26
  import { stripNulCharacters } from "../input-sanitization.js";
27
27
  import { tryMutation, tryQuery, withTransaction } from "../lib/db-result.js";
28
+ import { presentFirst } from "../lib/present.js";
28
29
  import { hasReportedUsage } from "../loop/metrics.js";
29
30
  import { countTokens } from "./count-tokens.js";
30
31
  import { conversationView, groupTurns, isGenuineUserStart } from "./conversation-view.js";
31
32
  import { HARNESS_PROVIDER_NAMESPACE, SYNTHETIC_MESSAGE_KEY, envelopeMessage, parseStoredMessageEnvelope, syntheticRecordMessage, } from "./ai-sdk-message-storage.js";
32
- import { conversationDisplayPart, envelopeDisplayMessages, parseStoredDisplayEnvelope, } from "./conversation-display-storage.js";
33
+ import { conversationDisplayPart, envelopeDisplayMessages, isStoredSourcePart, parseStoredDisplayEnvelope, } from "./conversation-display-storage.js";
33
34
  /** A resolved `ok(undefined)` ResultAsync — the empty/seed transaction step. */
34
35
  function okVoid() {
35
36
  return new ResultAsync(Promise.resolve(ok(undefined)));
@@ -56,7 +57,9 @@ export function conversationRecordTurn(text, displayParts) {
56
57
  {
57
58
  id: randomUUID(),
58
59
  role: "system",
59
- parts: displayParts !== undefined && displayParts.length > 0 ? displayParts.map(conversationDisplayPart) : [{ type: "text", text, state: "done" }],
60
+ parts: displayParts !== undefined && displayParts.length > 0
61
+ ? displayParts.filter(isStoredSourcePart).map(conversationDisplayPart)
62
+ : [{ type: "text", text, state: "done" }],
60
63
  },
61
64
  ],
62
65
  };
@@ -128,12 +131,12 @@ function nextSeq(client, threadId, op) {
128
131
  const { rows } = await client.query("SELECT COALESCE(MAX(seq), -1)::text AS max_seq FROM messages WHERE thread_id = $1", [
129
132
  threadId,
130
133
  ]);
131
- return Number(rows[0].max_seq) + 1;
134
+ return Number(presentFirst(rows, "the max-seq row").max_seq) + 1;
132
135
  });
133
136
  }
134
137
  /** Insert the rows of one group, from `startSeq` on. */
135
138
  function insertGroup(client, threadId, startSeq, group, op) {
136
- const { modelMessages: messages, displayMessages, author } = group;
139
+ const { modelMessages: messages, displayMessages, author, key } = group;
137
140
  // The display projection rides the group's FIRST row, so one SELECT of a
138
141
  // thread's rows yields every envelope in order with no join and no grouping.
139
142
  // Whichever row that is — a genuine user message opening a turn, or the lone
@@ -154,19 +157,21 @@ function insertGroup(client, threadId, startSeq, group, op) {
154
157
  return messages.reduce((chain, message, i) => chain.andThen(() => tryMutation(`${op}.insert`, () => client.query(
155
158
  // `message_envelope::json`, never `::jsonb`; `display_envelope::jsonb`,
156
159
  // never `::json` — see the column comments in the state-init DDL.
157
- `INSERT INTO messages (thread_id, seq, message_envelope, display_envelope, tokens, author)
158
- VALUES ($1, $2, $3::json, $4::jsonb, $5, $6)
160
+ `INSERT INTO messages (thread_id, seq, message_envelope, display_envelope, tokens, author, round_key)
161
+ VALUES ($1, $2, $3::json, $4::jsonb, $5, $6, $7)
159
162
  ON CONFLICT (thread_id, seq) DO UPDATE
160
163
  SET message_envelope = EXCLUDED.message_envelope,
161
164
  display_envelope = EXCLUDED.display_envelope,
162
165
  tokens = EXCLUDED.tokens,
163
- author = EXCLUDED.author`, [
166
+ author = EXCLUDED.author,
167
+ round_key = EXCLUDED.round_key`, [
164
168
  threadId,
165
169
  startSeq + i,
166
170
  serializeEnvelope(message),
167
171
  i === 0 ? displayEnvelope : null,
168
172
  countTokens(message.content),
169
173
  i === authorRow ? turnAuthor : null,
174
+ i === 0 ? (key ?? null) : null,
170
175
  ])).map(() => undefined)), okVoid());
171
176
  }
172
177
  /** Move `cortex_analysis_threads.updated_at` forward inside the write transaction. */
@@ -209,6 +214,16 @@ function touchThread(client, threadId, op) {
209
214
  .map(() => undefined)
210
215
  .orElse(() => okVoid()));
211
216
  }
217
+ /** The `seq` of the first row of a group that a write stored before, by the key of the group. */
218
+ function storedGroupSeq(client, threadId, key, op) {
219
+ if (key === undefined)
220
+ return okAsync(undefined);
221
+ return tryQuery(`${op}.storedKey`, async () => {
222
+ const { rows } = await client.query("SELECT seq::text AS seq FROM messages WHERE thread_id = $1 AND round_key = $2", [threadId, key]);
223
+ const row = rows[0];
224
+ return row === undefined ? undefined : Number(row.seq);
225
+ });
226
+ }
212
227
  /** Add the `open` record of a turn. The upsert replaces a record whose rows are gone, because the opening row holds its key now. */
213
228
  function openTurnRecord(client, threadId, startSeq) {
214
229
  return tryMutation("thread-history.writeTurn.openRecord", () => client.query(`INSERT INTO cortex_thread_turns (thread_id, start_seq, status)
@@ -224,46 +239,146 @@ function closeTurnRecord(client, threadId, startSeq, close) {
224
239
  SET status = $3, reason = $4, reported_usage = $5::jsonb, turn_duration_ms = $6, closed_at = NOW()
225
240
  WHERE thread_id = $1 AND start_seq = $2 AND status = 'open'`, [threadId, startSeq, close.status, close.reason === undefined ? null : stripNulCharacters(close.reason), rollup, close.turnDurationMs ?? null])).map(() => undefined);
226
241
  }
242
+ /** The columns of a display-read row, and the join that the turn record needs. Both display reads select them. */
243
+ const STORED_ROW_COLUMNS = `messages.seq::text AS seq, messages.message_envelope, messages.display_envelope, messages.reported_usage,
244
+ messages.turn_duration_ms::text AS turn_duration_ms, messages.author, messages.created_at,
245
+ turns.status AS turn_status, turns.reason AS turn_reason, turns.reported_usage AS turn_usage,
246
+ turns.turn_duration_ms::text AS turn_record_duration_ms`;
247
+ function storedRowFrom(turnJoinBounds = "") {
248
+ return `FROM messages
249
+ LEFT JOIN cortex_thread_turns turns ON turns.thread_id = messages.thread_id AND turns.start_seq = messages.seq${turnJoinBounds}`;
250
+ }
251
+ /** The largest `bigint`, the bound of a cursor that the caller did not give. */
252
+ const MAX_SEQ = "9223372036854775807";
253
+ /** The smallest `bigint`, below every `seq`. */
254
+ const MIN_SEQ = "'-9223372036854775808'";
255
+ const PAGE_LOWER_BOUND = `COALESCE((SELECT seq FROM page_lower), ${MIN_SEQ}::bigint)`;
256
+ const PAGE_UPPER_BOUND = `COALESCE((SELECT seq FROM page_upper), ${MAX_SEQ}::bigint)`;
227
257
  /**
228
- * Create a `ThreadHistory` bound to a Postgres pool — a factory closure
229
- * capturing `pool` (dependency injection per the harness-durable-runtime spec). The `messages` table is
230
- * provisioned by the project's state-init DDL.
258
+ * The statement of one page of the display read (`$1` thread, `$2` cursor or `NULL`, `$3` limit).
259
+ *
260
+ * One statement reads one snapshot, thus an append or a retract cannot add a turn between the
261
+ * read of the page edges and the read of the rows. The parts:
231
262
  *
232
- * `logger` serves exactly one purpose: reporting a stored display part the
233
- * current vocabulary had to drop. It is optional because the read returns the
234
- * same messages either way — the drop reports a deploy, not a failed read — and
235
- * requiring it would break every call site over a diagnostic.
263
+ * - `page_walk`: a walk down from the cursor, one row for each step, that counts the turn starts
264
+ * and stops at the `$3`-th. Each step is a `LIMIT 1` read of the primary key `(thread_id, seq)`
265
+ * that evaluates the start predicate in the select list.
266
+ * - `page_lower`: the row where the walk reached `$3` starts, else `NULL`. A page that is not
267
+ * full reaches the start of the thread and holds the rows before the first turn start.
268
+ * - `page_climb` and `page_upper`: a walk up from the cursor to the first turn start at or above
269
+ * it, else `NULL`. For a cursor that a page gave this is the cursor row. For a cursor inside a
270
+ * turn it is the start of the next turn, thus the turn of the cursor stays whole.
271
+ * - `page_next`: `page_lower` when a row lies below it. The `EXISTS` reads no envelope.
272
+ *
273
+ * The start predicate is never a `WHERE` condition of a scan that has an `ORDER BY` and a `LIMIT`.
274
+ * The planner has no statistics for a JSON path, so it estimates that very few rows match. It then
275
+ * chooses a bitmap scan and a sort of each row of the thread, and it evaluates the predicate on the
276
+ * envelope of each row (a tool result can be many KB). A walk of `LIMIT 1` reads of the key does
277
+ * not depend on that estimate, and its work grows with the rows of the page.
278
+ *
279
+ * An absent cursor, `page_lower`, and `page_upper` each become a `bigint` extreme through
280
+ * `COALESCE`, never a `NULL` in a comparison: `seq >= NULL` matches no row, and a form such as
281
+ * `($2 IS NULL OR seq < $2)` is a filter, which would visit each newer row. Each bound is an
282
+ * index condition on `(thread_id, seq)`. The join to the turn records carries the same bounds,
283
+ * because the planner estimates a bounded range as a fixed fraction of the thread and then reads
284
+ * each turn record of the thread through a hash join.
236
285
  */
286
+ const PAGE_SQL = `WITH RECURSIVE page_walk(seq, starts) AS (
287
+ SELECT COALESCE($2::bigint, ${MAX_SEQ}::bigint), 0::bigint
288
+ UNION ALL
289
+ SELECT below.seq, page_walk.starts + below.is_start::int
290
+ FROM page_walk
291
+ CROSS JOIN LATERAL (
292
+ SELECT messages.seq, COALESCE(${GENUINE_USER_START_SQL}, false) AS is_start FROM messages
293
+ WHERE messages.thread_id = $1 AND messages.seq < page_walk.seq
294
+ ORDER BY messages.seq DESC
295
+ LIMIT 1
296
+ ) below
297
+ WHERE page_walk.starts < $3::bigint
298
+ ),
299
+ page_lower AS (
300
+ SELECT (SELECT page_walk.seq FROM page_walk WHERE page_walk.starts = $3::bigint) AS seq
301
+ ),
302
+ page_climb(seq, is_start) AS (
303
+ SELECT above.seq, above.is_start FROM (
304
+ SELECT messages.seq, COALESCE(${GENUINE_USER_START_SQL}, false) AS is_start FROM messages
305
+ WHERE messages.thread_id = $1 AND messages.seq >= COALESCE($2::bigint, ${MAX_SEQ}::bigint)
306
+ ORDER BY messages.seq ASC
307
+ LIMIT 1
308
+ ) above
309
+ UNION ALL
310
+ SELECT above.seq, above.is_start
311
+ FROM page_climb
312
+ CROSS JOIN LATERAL (
313
+ SELECT messages.seq, COALESCE(${GENUINE_USER_START_SQL}, false) AS is_start FROM messages
314
+ WHERE messages.thread_id = $1 AND messages.seq > page_climb.seq
315
+ ORDER BY messages.seq ASC
316
+ LIMIT 1
317
+ ) above
318
+ WHERE NOT page_climb.is_start
319
+ ),
320
+ page_upper AS (
321
+ SELECT page_climb.seq FROM page_climb WHERE page_climb.is_start
322
+ ),
323
+ page_next AS (
324
+ SELECT page_lower.seq FROM page_lower
325
+ WHERE page_lower.seq IS NOT NULL
326
+ AND EXISTS (SELECT 1 FROM messages WHERE thread_id = $1 AND seq < page_lower.seq)
327
+ )
328
+ SELECT ${STORED_ROW_COLUMNS}, (SELECT seq::text FROM page_next) AS next_before
329
+ ${storedRowFrom(` AND turns.start_seq >= ${PAGE_LOWER_BOUND} AND turns.start_seq < ${PAGE_UPPER_BOUND}`)}
330
+ WHERE messages.thread_id = $1
331
+ AND messages.seq >= ${PAGE_LOWER_BOUND}
332
+ AND messages.seq < ${PAGE_UPPER_BOUND}
333
+ ORDER BY messages.seq ASC`;
334
+ /** The limit that the page statement receives: an integer, at least 1, and a bigint-safe size. */
335
+ function pageLimit(limit) {
336
+ return Number.isFinite(limit) ? Math.min(Math.max(1, Math.trunc(limit)), Number.MAX_SAFE_INTEGER) : 1;
337
+ }
338
+ /** `appendTurn` inside the transaction of the caller, thus another write of the caller commits with the turn or not at all. */
339
+ export function appendTurnIn(client, threadId, turn) {
340
+ if (turn.modelMessages.length === 0)
341
+ return okVoid();
342
+ return lockThread(client, threadId, "thread-history.appendTurn")
343
+ .andThen(() => nextSeq(client, threadId, "thread-history.appendTurn"))
344
+ .andThen((startSeq) => insertGroup(client, threadId, startSeq, turn, "thread-history.appendTurn"))
345
+ .andThen(() => touchThread(client, threadId, "thread-history.appendTurn"));
346
+ }
237
347
  export function createThreadHistory(pool, logger) {
238
348
  function appendTurn(threadId, turn) {
239
349
  if (turn.modelMessages.length === 0)
240
350
  return okVoid();
241
- return withTransaction(pool, "thread-history.appendTurn", (client) => lockThread(client, threadId, "thread-history.appendTurn")
242
- .andThen(() => nextSeq(client, threadId, "thread-history.appendTurn"))
243
- .andThen((startSeq) => insertGroup(client, threadId, startSeq, turn, "thread-history.appendTurn"))
244
- .andThen(() => touchThread(client, threadId, "thread-history.appendTurn")));
351
+ return withTransaction(pool, "thread-history.appendTurn", (client) => appendTurnIn(client, threadId, turn));
245
352
  }
246
353
  function writeTurn(threadId, write) {
247
354
  const { close } = write;
248
355
  const groups = [...(write.opening === undefined ? [] : [write.opening]), ...write.rounds, ...(close?.note === undefined ? [] : [close.note])];
249
356
  return withTransaction(pool, "thread-history.writeTurn", (client) => lockThread(client, threadId, "thread-history.writeTurn")
250
- .andThen(() => nextSeq(client, threadId, "thread-history.writeTurn"))
251
- .andThen((firstSeq) => {
252
- const startSeq = write.opening === undefined ? write.startSeq : firstSeq;
253
- const steps = [];
254
- let seq = firstSeq;
255
- for (const [index, group] of groups.entries()) {
256
- const groupSeq = seq;
257
- seq += group.modelMessages.length;
258
- steps.push(() => insertGroup(client, threadId, groupSeq, group, "thread-history.writeTurn"));
259
- if (index === 0 && write.opening !== undefined)
260
- steps.push(() => openTurnRecord(client, threadId, startSeq));
261
- }
262
- if (close !== undefined)
263
- steps.push(() => closeTurnRecord(client, threadId, startSeq, close));
264
- steps.push(() => touchThread(client, threadId, "thread-history.writeTurn"));
265
- return steps.reduce((chain, step) => chain.andThen(step), okVoid()).map(() => ({ startSeq }));
357
+ // One transaction stores each group of a write, thus a stored first group means a stored write.
358
+ .andThen(() => storedGroupSeq(client, threadId, groups[0]?.key, "thread-history.writeTurn"))
359
+ .andThen((storedSeq) => {
360
+ if (storedSeq === undefined)
361
+ return writeGroups(client);
362
+ return okAsync({ startSeq: write.opening === undefined ? write.startSeq : storedSeq });
266
363
  }));
364
+ function writeGroups(client) {
365
+ return nextSeq(client, threadId, "thread-history.writeTurn").andThen((firstSeq) => {
366
+ const startSeq = write.opening === undefined ? write.startSeq : firstSeq;
367
+ const steps = [];
368
+ let seq = firstSeq;
369
+ for (const [index, group] of groups.entries()) {
370
+ const groupSeq = seq;
371
+ seq += group.modelMessages.length;
372
+ steps.push(() => insertGroup(client, threadId, groupSeq, group, "thread-history.writeTurn"));
373
+ if (index === 0 && write.opening !== undefined)
374
+ steps.push(() => openTurnRecord(client, threadId, startSeq));
375
+ }
376
+ if (close !== undefined)
377
+ steps.push(() => closeTurnRecord(client, threadId, startSeq, close));
378
+ steps.push(() => touchThread(client, threadId, "thread-history.writeTurn"));
379
+ return steps.reduce((chain, step) => chain.andThen(step), okVoid()).map(() => ({ startSeq }));
380
+ });
381
+ }
267
382
  }
268
383
  function loadRecent(threadId, options) {
269
384
  return tryQuery("thread-history.loadRecent", async () => {
@@ -279,7 +394,7 @@ export function createThreadHistory(pool, logger) {
279
394
  // nothing has no rollup at all. The two are different measurements
280
395
  // sharing a unit; see the column comments.
281
396
  `SELECT seq::text AS seq, message_envelope, tokens
282
- FROM messages WHERE thread_id = $1 ORDER BY messages.seq ASC`, [threadId]);
397
+ FROM messages WHERE thread_id = $1 AND ($2::bigint IS NULL OR messages.seq <= $2::bigint) ORDER BY messages.seq ASC`, [threadId, options?.throughSeq ?? null]);
283
398
  const parsed = rows.map((row, index) => ({
284
399
  index,
285
400
  message: parseStoredMessageEnvelope(row.message_envelope, `${threadId}/${row.seq}`).message,
@@ -296,59 +411,77 @@ export function createThreadHistory(pool, logger) {
296
411
  return view.messages;
297
412
  });
298
413
  }
299
- // Display reads are turn-bounded, not row-bounded. A serial-tool assistant
300
- // turn is persisted as one row per step (plus its tool_result `user` rows),
301
- // so a row-windowed page could split a turn — truncating the trailing
302
- // report card/text out of the page the UI fetches. Read the thread and group
303
- // into turns, so a turn always reloads intact. Threads are conversation-scoped
304
- // and bounded, so reading every row here matches `loadRecent`'s existing
414
+ // A display read is turn-bounded, not row-bounded. A serial-tool assistant
415
+ // turn is persisted as one row per step (plus its tool_result rows), so a
416
+ // row-windowed read could split a turn and truncate the trailing report
417
+ // card or text out of what the UI fetches. Both reads group rows into turns,
418
+ // so a turn always reloads intact.
419
+ // Spread rather than `usage: r.reported_usage ?? undefined`, so a row with
420
+ // no rollup carries no `usage` KEY at all — absent, not present-and-undefined.
421
+ // The duration and the author obey the same rule, each from its own column.
422
+ // The creation time is unconditional: its column is NOT NULL, thus it has no
423
+ // absence to represent.
424
+ async function toStoredMessage(threadId, r) {
425
+ const envelope = parseStoredMessageEnvelope(r.message_envelope, `${threadId}/${r.seq}`);
426
+ const displayEnvelope = r.display_envelope == null ? undefined : await parseStoredDisplayEnvelope(r.display_envelope, `${threadId}/${r.seq}/display`, logger);
427
+ const row = {
428
+ seq: Number(r.seq),
429
+ envelope,
430
+ message: envelope.message,
431
+ displayEnvelope,
432
+ createdAt: r.created_at,
433
+ };
434
+ if (r.reported_usage !== null)
435
+ row.usage = r.reported_usage;
436
+ if (r.turn_duration_ms !== null)
437
+ row.durationMs = Number(r.turn_duration_ms);
438
+ if (r.author !== null)
439
+ row.author = r.author;
440
+ if (r.turn_status !== null) {
441
+ const turn = { status: r.turn_status };
442
+ if (r.turn_reason !== null)
443
+ turn.reason = r.turn_reason;
444
+ if (r.turn_usage !== null)
445
+ turn.usage = r.turn_usage;
446
+ if (r.turn_record_duration_ms !== null)
447
+ turn.durationMs = Number(r.turn_record_duration_ms);
448
+ row.turn = turn;
449
+ }
450
+ return row;
451
+ }
452
+ async function toTurns(threadId, rows) {
453
+ const stored = await Promise.all(rows.map((row) => toStoredMessage(threadId, row)));
454
+ return groupTurns(stored, (row) => isGenuineUserStart(row.message));
455
+ }
305
456
  async function readTurns(threadId) {
306
457
  const { rows } = await pool.query(
307
458
  // ORDER BY must qualify `messages.seq` — a bare `seq` would bind to the
308
459
  // `seq::text AS seq` output alias (Postgres resolves an unqualified
309
460
  // ORDER BY name to the output column), sorting the bigint as text:
310
461
  // "10" before "2". The qualified name forces the bigint column.
311
- `SELECT messages.seq::text AS seq, messages.message_envelope, messages.display_envelope, messages.reported_usage,
312
- messages.turn_duration_ms::text AS turn_duration_ms, messages.author, messages.created_at,
313
- turns.status AS turn_status, turns.reason AS turn_reason, turns.reported_usage AS turn_usage,
314
- turns.turn_duration_ms::text AS turn_record_duration_ms
315
- FROM messages
316
- LEFT JOIN cortex_thread_turns turns ON turns.thread_id = messages.thread_id AND turns.start_seq = messages.seq
462
+ `SELECT ${STORED_ROW_COLUMNS}
463
+ ${storedRowFrom()}
317
464
  WHERE messages.thread_id = $1
318
465
  ORDER BY messages.seq ASC`, [threadId]);
319
- // Spread rather than `usage: r.reported_usage ?? undefined`, so a row with
320
- // no rollup carries no `usage` KEY at all — absent, not present-and-undefined.
321
- // The duration and the author obey the same rule, each from its own column.
322
- // The creation time is unconditional: its column is NOT NULL, thus it has no
323
- // absence to represent.
324
- const stored = await Promise.all(rows.map(async (r) => {
325
- const envelope = parseStoredMessageEnvelope(r.message_envelope, `${threadId}/${r.seq}`);
326
- const displayEnvelope = r.display_envelope == null ? undefined : await parseStoredDisplayEnvelope(r.display_envelope, `${threadId}/${r.seq}/display`, logger);
327
- const turn = r.turn_status === null
328
- ? undefined
329
- : {
330
- status: r.turn_status,
331
- ...(r.turn_reason === null ? {} : { reason: r.turn_reason }),
332
- ...(r.turn_usage === null ? {} : { usage: r.turn_usage }),
333
- ...(r.turn_record_duration_ms === null ? {} : { durationMs: Number(r.turn_record_duration_ms) }),
334
- };
335
- return {
336
- seq: Number(r.seq),
337
- envelope,
338
- message: envelope.message,
339
- ...(displayEnvelope ? { displayEnvelope } : {}),
340
- ...(r.reported_usage === null ? {} : { usage: r.reported_usage }),
341
- ...(r.turn_duration_ms === null ? {} : { durationMs: Number(r.turn_duration_ms) }),
342
- ...(turn === undefined ? {} : { turn }),
343
- ...(r.author === null ? {} : { author: r.author }),
344
- createdAt: r.created_at,
345
- };
346
- }));
347
- return groupTurns(stored, (row) => isGenuineUserStart(row.message));
466
+ return toTurns(threadId, rows);
467
+ }
468
+ async function readPage(threadId, options) {
469
+ const { rows } = await pool.query(PAGE_SQL, [
470
+ threadId,
471
+ options.before === undefined ? null : String(options.before),
472
+ pageLimit(options.limit),
473
+ ]);
474
+ // The cursor rides each row, and an empty page has no row. An empty page has no cursor either:
475
+ // `page_lower` is set only when its row is in the page.
476
+ const next = rows[0]?.next_before ?? null;
477
+ return { turns: await toTurns(threadId, rows), before: next === null ? null : Number(next) };
348
478
  }
349
479
  function loadAll(threadId) {
350
480
  return tryQuery("thread-history.loadAll", () => readTurns(threadId));
351
481
  }
482
+ function loadPage(threadId, options) {
483
+ return tryQuery("thread-history.loadPage", () => readPage(threadId, options));
484
+ }
352
485
  function retractLastTurn(threadId) {
353
486
  return withTransaction(pool, "thread-history.retractLastTurn", (client) =>
354
487
  // Take the SAME per-thread advisory lock `appendTurn` takes, and take it
@@ -379,7 +512,7 @@ export function createThreadHistory(pool, logger) {
379
512
  (SELECT MAX(seq)::text FROM messages
380
513
  WHERE thread_id = $1
381
514
  AND ${GENUINE_USER_START_SQL}) AS boundary`, [threadId]);
382
- return rows[0];
515
+ return presentFirst(rows, "the thread boundary row");
383
516
  }))
384
517
  .andThen(({ has_rows, boundary }) => {
385
518
  if (!has_rows)
@@ -424,7 +557,7 @@ export function createThreadHistory(pool, logger) {
424
557
  return tryQuery("thread-history.countUserTurnsAfter", () => pool.query(`SELECT COUNT(*)::text AS turns FROM messages
425
558
  WHERE thread_id = $1
426
559
  AND seq > $2::bigint
427
- AND ${GENUINE_USER_START_SQL}`, [threadId, seq])).map(({ rows }) => Number(rows[0].turns));
560
+ AND ${GENUINE_USER_START_SQL}`, [threadId, seq])).map(({ rows }) => Number(presentFirst(rows, "the user-turn count row").turns));
428
561
  }
429
- return { appendTurn, writeTurn, loadRecent, loadAll, retractLastTurn, latestSeq, latestTurnAt, countUserTurnsAfter };
562
+ return { appendTurn, writeTurn, loadRecent, loadAll, loadPage, retractLastTurn, latestSeq, latestTurnAt, countUserTurnsAfter };
430
563
  }