@inflexa-ai/harness 0.46.2 → 0.48.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 (279) hide show
  1. package/README.md +2 -2
  2. package/dist/agents/conversation-agent.d.ts +7 -6
  3. package/dist/agents/conversation-agent.js +26 -4
  4. package/dist/agents/report-session-agent.d.ts +14 -14
  5. package/dist/agents/report-session-agent.js +40 -26
  6. package/dist/agents/sandbox/shared.d.ts +18 -13
  7. package/dist/agents/sandbox/shared.js +42 -27
  8. package/dist/agents/sandbox/types.d.ts +1 -1
  9. package/dist/agents/sandbox-catalog.d.ts +2 -0
  10. package/dist/agents/sandbox-catalog.js +30 -1
  11. package/dist/app/synthesize-run.d.ts +10 -6
  12. package/dist/app/synthesize-run.js +4 -2
  13. package/dist/contracts/analogy-report.d.ts +46 -2
  14. package/dist/contracts/analogy-report.js +31 -25
  15. package/dist/contracts/chat-parts.d.ts +3 -14
  16. package/dist/contracts/report-reference.d.ts +2 -1
  17. package/dist/contracts/report-reference.js +2 -1
  18. package/dist/contracts/schemas/chat-parts.d.ts +0 -27
  19. package/dist/contracts/schemas/chat-parts.js +1 -3
  20. package/dist/execution/run-canceler.d.ts +2 -0
  21. package/dist/execution/run-canceler.js +9 -0
  22. package/dist/execution/run-synthesis.d.ts +36 -8
  23. package/dist/execution/run-synthesis.js +114 -32
  24. package/dist/index.d.ts +5 -6
  25. package/dist/index.js +5 -7
  26. package/dist/input-scan/enrich.d.ts +5 -10
  27. package/dist/input-scan/enrich.js +12 -8
  28. package/dist/lib/hooks.d.ts +1 -1
  29. package/dist/lib/markdown-pdf.d.ts +27 -0
  30. package/dist/lib/markdown-pdf.js +236 -0
  31. package/dist/lib/metrics.d.ts +31 -0
  32. package/dist/lib/metrics.js +64 -0
  33. package/dist/lib/pdf-text.d.ts +23 -0
  34. package/dist/lib/pdf-text.js +34 -0
  35. package/dist/lib/regulatory-corpus/fetch-fda-guidance.js +3 -5
  36. package/dist/lib/regulatory-corpus/fetch-ich.js +3 -5
  37. package/dist/loop/chat-stream.js +2 -1
  38. package/dist/loop/run-loop.d.ts +5 -0
  39. package/dist/loop/run-loop.js +30 -2
  40. package/dist/loop/tool-name-repair.d.ts +11 -0
  41. package/dist/loop/tool-name-repair.js +23 -0
  42. package/dist/loop/types.d.ts +19 -0
  43. package/dist/memory/card-builders.d.ts +1 -1
  44. package/dist/prompts/SOUL.d.ts +6 -6
  45. package/dist/prompts/SOUL.js +22 -121
  46. package/dist/prompts/analogical-reasoner.d.ts +1 -1
  47. package/dist/prompts/analogical-reasoner.js +35 -101
  48. package/dist/prompts/briefing.d.ts +20 -11
  49. package/dist/prompts/briefing.js +36 -19
  50. package/dist/prompts/conversation.d.ts +1 -1
  51. package/dist/prompts/conversation.js +103 -383
  52. package/dist/prompts/planner.d.ts +1 -5
  53. package/dist/prompts/planner.js +45 -128
  54. package/dist/prompts/report-session.d.ts +1 -1
  55. package/dist/prompts/report-session.js +29 -58
  56. package/dist/prompts/sandbox/bulk-transcriptomics-agent.d.ts +1 -1
  57. package/dist/prompts/sandbox/bulk-transcriptomics-agent.js +3 -3
  58. package/dist/prompts/sandbox/cheminformatics-agent.d.ts +1 -1
  59. package/dist/prompts/sandbox/cheminformatics-agent.js +12 -47
  60. package/dist/prompts/sandbox/chromatin-agent.d.ts +1 -1
  61. package/dist/prompts/sandbox/chromatin-agent.js +4 -5
  62. package/dist/prompts/sandbox/data-profiler.js +11 -34
  63. package/dist/prompts/sandbox/dna-methylation-agent.d.ts +1 -1
  64. package/dist/prompts/sandbox/dna-methylation-agent.js +3 -1
  65. package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
  66. package/dist/prompts/sandbox/drug-repurposing-agent.js +23 -73
  67. package/dist/prompts/sandbox/enrichment-agent.d.ts +1 -1
  68. package/dist/prompts/sandbox/enrichment-agent.js +3 -1
  69. package/dist/prompts/sandbox/genomic-variant-agent.d.ts +1 -1
  70. package/dist/prompts/sandbox/genomic-variant-agent.js +3 -4
  71. package/dist/prompts/sandbox/immune-profiling-agent.d.ts +1 -1
  72. package/dist/prompts/sandbox/immune-profiling-agent.js +5 -4
  73. package/dist/prompts/sandbox/metabolomics-agent.d.ts +1 -1
  74. package/dist/prompts/sandbox/metabolomics-agent.js +3 -1
  75. package/dist/prompts/sandbox/microbiome-agent.d.ts +1 -1
  76. package/dist/prompts/sandbox/microbiome-agent.js +3 -1
  77. package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
  78. package/dist/prompts/sandbox/multi-omics-integration-agent.js +3 -1
  79. package/dist/prompts/sandbox/multimodal-sc-agent.d.ts +1 -1
  80. package/dist/prompts/sandbox/multimodal-sc-agent.js +3 -1
  81. package/dist/prompts/sandbox/network-agent.d.ts +1 -1
  82. package/dist/prompts/sandbox/network-agent.js +3 -1
  83. package/dist/prompts/sandbox/pkpd-clinical-response-agent.d.ts +1 -1
  84. package/dist/prompts/sandbox/pkpd-clinical-response-agent.js +4 -7
  85. package/dist/prompts/sandbox/proteomics-agent.d.ts +1 -1
  86. package/dist/prompts/sandbox/proteomics-agent.js +3 -1
  87. package/dist/prompts/sandbox/scientific-executor.d.ts +1 -1
  88. package/dist/prompts/sandbox/scientific-executor.js +0 -12
  89. package/dist/prompts/sandbox/single-cell-agent.d.ts +1 -1
  90. package/dist/prompts/sandbox/single-cell-agent.js +3 -1
  91. package/dist/prompts/sandbox/spatial-omics-agent.d.ts +1 -1
  92. package/dist/prompts/sandbox/spatial-omics-agent.js +3 -1
  93. package/dist/prompts/sandbox/statistical-modeling-agent.d.ts +1 -1
  94. package/dist/prompts/sandbox/statistical-modeling-agent.js +4 -4
  95. package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
  96. package/dist/prompts/sandbox/translational-safety-agent.js +10 -29
  97. package/dist/prompts/sandbox-standards.d.ts +15 -18
  98. package/dist/prompts/sandbox-standards.js +96 -305
  99. package/dist/prompts/synthesis-agent.d.ts +1 -1
  100. package/dist/prompts/synthesis-agent.js +24 -90
  101. package/dist/provenance/collector.d.ts +2 -5
  102. package/dist/provenance/collector.js +2 -5
  103. package/dist/provenance/seam.d.ts +36 -1
  104. package/dist/provenance/workspace-reads.d.ts +36 -0
  105. package/dist/provenance/workspace-reads.js +33 -0
  106. package/dist/report-model/production-resolver.d.ts +22 -52
  107. package/dist/report-model/production-resolver.js +43 -112
  108. package/dist/report-render/chart-export.d.ts +9 -0
  109. package/dist/report-render/chart-export.js +1 -1
  110. package/dist/report-render/views/chart-view.d.ts +1 -0
  111. package/dist/report-render/views/chart-view.js +1 -0
  112. package/dist/report-render/views/lineage.d.ts +1 -0
  113. package/dist/report-render/views/page-view.d.ts +1 -0
  114. package/dist/report-render/views/page-view.js +1 -0
  115. package/dist/report-render/views/prose.d.ts +1 -0
  116. package/dist/report-render/views/prose.js +1 -0
  117. package/dist/report-render/views/references-view.d.ts +1 -0
  118. package/dist/report-render/views/values.d.ts +1 -0
  119. package/dist/report-render/views/values.js +1 -0
  120. package/dist/runtime/assemble.d.ts +32 -12
  121. package/dist/runtime/assemble.js +49 -38
  122. package/dist/sandbox/client.d.ts +5 -3
  123. package/dist/sandbox/create-sandbox.d.ts +7 -12
  124. package/dist/sandbox/create-sandbox.js +15 -37
  125. package/dist/sandbox/docker-client.d.ts +1 -3
  126. package/dist/sandbox/docker-client.js +3 -5
  127. package/dist/sandbox/exec-outcome.d.ts +11 -11
  128. package/dist/sandbox/exec-outcome.js +22 -22
  129. package/dist/sandbox/exec.d.ts +5 -0
  130. package/dist/sandbox/exec.js +9 -1
  131. package/dist/sandbox/identity.d.ts +4 -16
  132. package/dist/sandbox/identity.js +5 -21
  133. package/dist/sandbox/k8s-client.d.ts +0 -1
  134. package/dist/sandbox/k8s-client.js +8 -13
  135. package/dist/sandbox/lease-names.d.ts +6 -0
  136. package/dist/sandbox/lease-names.js +12 -0
  137. package/dist/sandbox/leases.d.ts +105 -0
  138. package/dist/sandbox/leases.js +519 -0
  139. package/dist/sandbox/liveness.d.ts +5 -2
  140. package/dist/sandbox/mount-plan.d.ts +10 -1
  141. package/dist/sandbox/mount-plan.js +7 -1
  142. package/dist/sandbox/reconciler.d.ts +58 -0
  143. package/dist/sandbox/reconciler.js +153 -0
  144. package/dist/sandbox/sandbox-step-translate.d.ts +1 -1
  145. package/dist/sandbox/types.d.ts +25 -18
  146. package/dist/sandbox/types.js +10 -4
  147. package/dist/schemas/plan-schemas.d.ts +0 -21
  148. package/dist/schemas/plan-schemas.js +2 -3
  149. package/dist/schemas/run-synthesis.d.ts +2 -2
  150. package/dist/schemas/run-synthesis.js +3 -3
  151. package/dist/schemas/validate-plan.d.ts +1 -14
  152. package/dist/schemas/validate-plan.js +5 -24
  153. package/dist/schemas/workflow-state.d.ts +3 -32
  154. package/dist/schemas/workflow-state.js +4 -13
  155. package/dist/state/index.d.ts +2 -3
  156. package/dist/state/index.js +1 -2
  157. package/dist/state/migrations/20261030120000_lease_the_sandboxes.d.ts +7 -0
  158. package/dist/state/migrations/20261030120000_lease_the_sandboxes.js +34 -0
  159. package/dist/state/migrations/20261030120100_drop_the_report_derivations.d.ts +5 -0
  160. package/dist/state/migrations/20261030120100_drop_the_report_derivations.js +9 -0
  161. package/dist/state/migrations/20261030120200_keep_the_report_derivations.d.ts +6 -0
  162. package/dist/state/migrations/20261030120200_keep_the_report_derivations.js +10 -0
  163. package/dist/state/migrations/index.js +6 -0
  164. package/dist/state/purge-analysis.d.ts +4 -2
  165. package/dist/state/purge-analysis.js +22 -11
  166. package/dist/state/sandbox-leases.d.ts +81 -0
  167. package/dist/state/sandbox-leases.js +247 -0
  168. package/dist/state/schema.d.ts +1 -13
  169. package/dist/state/schema.js +1 -6
  170. package/dist/state/step-executions.d.ts +13 -2
  171. package/dist/state/step-executions.js +23 -4
  172. package/dist/tasks/data-profile.d.ts +40 -2
  173. package/dist/tasks/data-profile.js +89 -87
  174. package/dist/tools/ad-hoc-router.d.ts +1 -6
  175. package/dist/tools/ad-hoc-router.js +5 -48
  176. package/dist/tools/bio/comptox.js +1 -1
  177. package/dist/tools/bio/drug-gene-interactions.js +1 -1
  178. package/dist/tools/bio/gene-disease-evidence.js +1 -1
  179. package/dist/tools/bio/keys.d.ts +1 -1
  180. package/dist/tools/bio/pubmed.js +31 -0
  181. package/dist/tools/bio/search-gene.js +17 -0
  182. package/dist/tools/bio/search-geo-datasets.js +13 -0
  183. package/dist/tools/bio/search-regulatory-approvals.js +1 -1
  184. package/dist/tools/define-tool.d.ts +25 -2
  185. package/dist/tools/define-tool.js +11 -1
  186. package/dist/tools/display/show-user.js +1 -1
  187. package/dist/tools/execute-analysis.d.ts +1 -3
  188. package/dist/tools/execute-analysis.js +5 -33
  189. package/dist/tools/report-authoring/authoring-tools.d.ts +2 -2
  190. package/dist/tools/report-authoring/authoring-tools.js +31 -6
  191. package/dist/tools/report-session/index.d.ts +0 -1
  192. package/dist/tools/report-session/index.js +0 -1
  193. package/dist/tools/report-session/script-tools.d.ts +33 -0
  194. package/dist/tools/report-session/script-tools.js +186 -0
  195. package/dist/tools/research/generate-analogy-report.d.ts +16 -9
  196. package/dist/tools/research/generate-analogy-report.js +111 -49
  197. package/dist/tools/research/generate-plan.d.ts +102 -7
  198. package/dist/tools/research/generate-plan.js +74 -43
  199. package/dist/tools/research/index.d.ts +4 -3
  200. package/dist/tools/research/index.js +4 -3
  201. package/dist/tools/research/inspect-run.d.ts +0 -1
  202. package/dist/tools/research/inspect-run.js +5 -10
  203. package/dist/tools/research/search-arxiv.js +15 -0
  204. package/dist/tools/research/search-github-repos.js +13 -0
  205. package/dist/tools/research/search-semantic-scholar.js +16 -0
  206. package/dist/tools/research/synthesis-lookups.d.ts +21 -0
  207. package/dist/tools/research/synthesis-lookups.js +29 -0
  208. package/dist/tools/research/web-fetch.d.ts +1 -1
  209. package/dist/tools/research/web-fetch.js +14 -12
  210. package/dist/tools/sandbox/lease-tools.d.ts +32 -0
  211. package/dist/tools/sandbox/lease-tools.js +60 -0
  212. package/dist/tools/script/archive.d.ts +34 -0
  213. package/dist/tools/script/archive.js +182 -0
  214. package/dist/tools/script/codemode-worker.d.ts +5 -0
  215. package/dist/tools/script/codemode-worker.js +5 -0
  216. package/dist/tools/script/file-tools.d.ts +106 -0
  217. package/dist/tools/script/file-tools.js +491 -0
  218. package/dist/tools/script/metrics.d.ts +30 -0
  219. package/dist/tools/script/metrics.js +53 -0
  220. package/dist/tools/script/quickjs.wasm +0 -0
  221. package/dist/tools/script/run-script.d.ts +76 -0
  222. package/dist/tools/script/run-script.js +413 -0
  223. package/dist/tools/script/scratch.d.ts +84 -0
  224. package/dist/tools/script/scratch.js +145 -0
  225. package/dist/tools/start-report-session.js +1 -1
  226. package/dist/tools/workspace/edit-file.js +2 -1
  227. package/dist/tools/workspace/execute-command.d.ts +9 -13
  228. package/dist/tools/workspace/execute-command.js +23 -19
  229. package/dist/tools/workspace/file-stat.js +1 -1
  230. package/dist/tools/workspace/grep.d.ts +5 -2
  231. package/dist/tools/workspace/grep.js +19 -10
  232. package/dist/tools/workspace/mutator.d.ts +51 -4
  233. package/dist/tools/workspace/mutator.js +54 -13
  234. package/dist/tools/workspace/read-file.d.ts +5 -2
  235. package/dist/tools/workspace/read-file.js +15 -11
  236. package/dist/tools/workspace/read-surface.d.ts +17 -0
  237. package/dist/tools/workspace/read-surface.js +17 -0
  238. package/dist/tools/workspace/result-bounds.d.ts +1 -0
  239. package/dist/tools/workspace/run-exec.d.ts +12 -13
  240. package/dist/tools/workspace/run-exec.js +13 -13
  241. package/dist/tools/workspace/scan-inputs.d.ts +2 -5
  242. package/dist/tools/workspace/scan-inputs.js +2 -3
  243. package/dist/tools/workspace/show-file.js +1 -1
  244. package/dist/tools/workspace/show-plan.js +4 -3
  245. package/dist/tools/workspace/write-file.js +2 -1
  246. package/dist/workflows/execute-analysis-scheduler.d.ts +0 -26
  247. package/dist/workflows/execute-analysis-scheduler.js +12 -32
  248. package/dist/workflows/execute-analysis.d.ts +17 -35
  249. package/dist/workflows/execute-analysis.js +13 -107
  250. package/dist/workflows/pause.js +29 -22
  251. package/dist/workflows/sandbox-step.d.ts +16 -31
  252. package/dist/workflows/sandbox-step.js +36 -71
  253. package/dist/workflows/test/sql-writes.d.ts +0 -1
  254. package/dist/workflows/test/sql-writes.js +0 -2
  255. package/dist/workspace/filesystem.d.ts +2 -2
  256. package/dist/workspace/filesystem.js +10 -5
  257. package/dist/workspace/paths.d.ts +19 -1
  258. package/dist/workspace/paths.js +22 -1
  259. package/dist/workspace/session-files.d.ts +35 -0
  260. package/dist/workspace/session-files.js +16 -0
  261. package/package.json +7 -3
  262. package/dist/prompts/literature-reviewer.d.ts +0 -1
  263. package/dist/prompts/literature-reviewer.js +0 -114
  264. package/dist/sandbox/reaper.d.ts +0 -81
  265. package/dist/sandbox/reaper.js +0 -161
  266. package/dist/sandbox/step-sandbox.d.ts +0 -47
  267. package/dist/sandbox/step-sandbox.js +0 -53
  268. package/dist/state/active-sandboxes.d.ts +0 -33
  269. package/dist/state/active-sandboxes.js +0 -65
  270. package/dist/tasks/extract-values-script.d.ts +0 -64
  271. package/dist/tasks/extract-values-script.js +0 -180
  272. package/dist/tasks/extract-values.d.ts +0 -77
  273. package/dist/tasks/extract-values.js +0 -146
  274. package/dist/tools/report-session/derive-table.d.ts +0 -164
  275. package/dist/tools/report-session/derive-table.js +0 -419
  276. package/dist/tools/research/literature-reviewer.d.ts +0 -42
  277. package/dist/tools/research/literature-reviewer.js +0 -107
  278. package/dist/workflows/metrics.d.ts +0 -23
  279. package/dist/workflows/metrics.js +0 -38
@@ -5,13 +5,13 @@
5
5
  * The realization holds three layers. Layer one is identity: membership through `snapshotEntry`, and a
6
6
  * streamed hash compare with `computeSha256File`. A hash mismatch fails before any parse. Layer two is
7
7
  * the host fast path: an in-process parse of a CSV, a TSV, a JSON, or a parquet file at or under the cap.
8
- * Layer three is the fall-through: an over-cap file or a host parse fault goes to the extraction arm. On any
9
- * doubt the read falls through, thus correctness never depends on the host parser. An extension that names
10
- * no tabular format refuses here, because the host decides the format for both arms.
8
+ * Layer three is the fall-through: an over-cap file or a host parse fault fails as `extraction-unavailable`.
9
+ * On any doubt the read falls through, thus the host parser never gives a partial or guessed answer. An
10
+ * extension that names no tabular format refuses the same way.
11
11
  *
12
12
  * A read of the bytes is the expensive part, thus an optional `ArtifactReadCache` outlives one resolver. It
13
- * holds the streamed hash and the extracted rows against a stat signature. Two tool calls of one analysis
14
- * share one cache, and each call still binds its own extraction arm with its own auth.
13
+ * holds the streamed hash and the parsed rows against a stat signature. Two tool calls of one analysis
14
+ * share one cache.
15
15
  *
16
16
  * The realization calls the shared assert functions in `assert-rules.ts`, and it mirrors the locator walk
17
17
  * and the reason choices of `fixture-resolver.ts`. Thus one semantics exists, and the fixture stays the
@@ -22,7 +22,6 @@ import { readFile, stat } from "node:fs/promises";
22
22
  import { extname } from "node:path";
23
23
  import { parquetReadObjects } from "hyparquet";
24
24
  import { z } from "zod";
25
- import { isWorkflowCancellation } from "../runtime/dbos.js";
26
25
  import { allWithConcurrency } from "../lib/async-utils.js";
27
26
  import { computeSha256File } from "../lib/fs-helpers.js";
28
27
  import { parseJsonAs } from "../lib/parse-json.js";
@@ -92,6 +91,10 @@ export function createArtifactReadStore() {
92
91
  },
93
92
  };
94
93
  }
94
+ /** The cells of a fall-through. No reader outside the host exists, thus the reference fails as `extraction-unavailable`. */
95
+ function fallThroughCells(path, hostDetail) {
96
+ return { kind: "unavailable", detail: `the host read of the file at ${path} stopped because ${hostDetail}, and no other reader exists` };
97
+ }
95
98
  /** Build an `Err` that carries the unresolved reference. The `detail` key is present only when there is a detail to carry. */
96
99
  function fail(reference, reason, detail) {
97
100
  const failure = detail !== undefined ? { reference, reason, detail } : { reference, reason };
@@ -104,10 +107,9 @@ function describeReference(reference) {
104
107
  /**
105
108
  * Map a file extension to the format that the host arm reads. An unknown extension gives back `undefined`.
106
109
  *
107
- * This is the one format decision of the report path. The extraction request carries the answer, thus the
108
- * sandbox arm never repeats the mapping and the two arms hold no second table between them.
110
+ * This is the one format decision of the report path.
109
111
  */
110
- function detectFormat(path) {
112
+ export function detectFormat(path) {
111
113
  switch (extname(path).toLowerCase()) {
112
114
  case ".csv":
113
115
  return "csv";
@@ -130,8 +132,7 @@ function detectFormat(path) {
130
132
  * where the caller detects the loss.
131
133
  *
132
134
  * A non-finite number is not a cell either. A parquet float column holds a `NaN` or an `Infinity`, thus the
133
- * coercion drops it and the row omits the key. The extraction script (`tasks/extract-values-script.ts`)
134
- * drops the same value to `None`, thus the host arm and the sandbox arm read the same bytes the same way.
135
+ * coercion drops it and the row omits the key.
135
136
  */
136
137
  export function coerceCell(value) {
137
138
  if (value === null || value === undefined) {
@@ -339,10 +340,7 @@ async function parseParquet(bytes) {
339
340
  }
340
341
  /**
341
342
  * Read the cells of one artifact through the host fast path. An over-cap file and a parse fault each give
342
- * back a fall-through, thus the arm reads them out of process.
343
- *
344
- * An extension that names no tabular format stops here. The arm reads a file by a decided format, and no
345
- * format is decided, thus the arm has nothing to obey and the read is unavailable.
343
+ * back a fall-through. An extension that names no tabular format stops here.
346
344
  */
347
345
  async function hostReadCells(cap, path, identity) {
348
346
  const format = detectFormat(path);
@@ -350,26 +348,33 @@ async function hostReadCells(cap, path, identity) {
350
348
  return { kind: "unsupported-format", detail: `the file at ${path} has no supported tabular format, thus no reader is decided for it` };
351
349
  }
352
350
  if (identity.size > cap) {
353
- return { kind: "fall-through", format, detail: `the file size of ${identity.size} bytes is over the ${cap}-byte cap` };
351
+ return { kind: "fall-through", detail: `the file size of ${identity.size} bytes is over the ${cap}-byte cap` };
354
352
  }
355
353
  let bytes;
356
354
  try {
357
355
  bytes = await readFile(identity.absolute);
358
356
  }
359
357
  catch {
360
- return { kind: "fall-through", format, detail: "the file could not be read" };
361
- }
362
- if (format === "parquet") {
363
- const rows = await parseParquet(bytes);
364
- return rows === undefined ? { kind: "fall-through", format, detail: "the parquet read did not succeed" } : { kind: "rows", rows };
358
+ return { kind: "fall-through", detail: "the file could not be read" };
365
359
  }
360
+ const rows = await parseTable(format, bytes);
361
+ return rows === undefined ? { kind: "fall-through", detail: PARSE_FAULT_DETAIL[format] } : { kind: "rows", rows };
362
+ }
363
+ /** The detail of a parse fault, for each format. */
364
+ const PARSE_FAULT_DETAIL = {
365
+ csv: "the delimited parse did not succeed",
366
+ tsv: "the delimited parse did not succeed",
367
+ json: "the JSON parse did not succeed",
368
+ parquet: "the parquet read did not succeed",
369
+ };
370
+ /** Parse the bytes of one table in a decided format. A parse fault gives back `undefined`. */
371
+ export async function parseTable(format, bytes) {
372
+ if (format === "parquet")
373
+ return parseParquet(bytes);
366
374
  const text = bytes.toString("utf8");
367
- if (format === "json") {
368
- const rows = parseJsonTable(text);
369
- return rows === undefined ? { kind: "fall-through", format, detail: "the JSON parse did not succeed" } : { kind: "rows", rows };
370
- }
371
- const rows = parseDelimited(text, format === "tsv" ? "\t" : ",");
372
- return rows === undefined ? { kind: "fall-through", format, detail: "the delimited parse did not succeed" } : { kind: "rows", rows };
375
+ if (format === "json")
376
+ return parseJsonTable(text);
377
+ return parseDelimited(text, format === "tsv" ? "\t" : ",");
373
378
  }
374
379
  /**
375
380
  * Compute the identity of one artifact: membership, containment, and the on-disk hash.
@@ -417,58 +422,6 @@ async function computeIdentity(workspaceRoot, analysisId, path, snapshot, readCa
417
422
  readCache?.set(resolved.absolute, { signature, hash: onDiskHash });
418
423
  return { kind: "ready", onDiskHash, fileType: entry.fileType, absolute: resolved.absolute, size, signature };
419
424
  }
420
- /**
421
- * Resolve each fall-through artifact through the extraction arm. One call covers the whole batch. An
422
- * absent arm gives back `unavailable`, and the detail names the absent arm. An arm that gives no answer
423
- * for a path gives back `unreadable`.
424
- */
425
- async function extractFallThrough(arm, requests) {
426
- const out = new Map();
427
- if (requests.length === 0) {
428
- return out;
429
- }
430
- if (arm === undefined) {
431
- for (const request of requests) {
432
- out.set(request.path, {
433
- kind: "unavailable",
434
- detail: `the extraction arm is not wired, and the file at ${request.path} needs it because ${request.hostDetail}`,
435
- });
436
- }
437
- return out;
438
- }
439
- let answered;
440
- try {
441
- answered = await arm.extract(requests.map((request) => ({ path: request.path, hash: request.hash, format: request.format })));
442
- }
443
- catch (cause) {
444
- // The arm speaks the throw protocol for a genuine infrastructure fault. This boundary turns the
445
- // throw into a value, thus each reference on the batch reads a failure as data. A cancel of the
446
- // workflow is not a fault of the read, thus it leaves to DBOS with no change.
447
- if (isWorkflowCancellation(cause))
448
- throw cause;
449
- for (const request of requests) {
450
- out.set(request.path, { kind: "unreadable", detail: `the extraction arm did not read the file at ${request.path}` });
451
- }
452
- return out;
453
- }
454
- if (answered.isErr()) {
455
- for (const request of requests) {
456
- out.set(request.path, {
457
- kind: "unavailable",
458
- detail: `the host refused the sandbox (${answered.error.reason}), thus the file at ${request.path} was not read`,
459
- });
460
- }
461
- return out;
462
- }
463
- const answers = answered.value;
464
- for (const request of requests) {
465
- const answer = answers.get(request.path);
466
- out.set(request.path, answer === undefined
467
- ? { kind: "unreadable", detail: `the extraction arm did not read the file at ${request.path}` }
468
- : { kind: "rows", rows: answer.rows });
469
- }
470
- return out;
471
- }
472
425
  /**
473
426
  * Give back the rows that an earlier pass read for these exact bytes, or `undefined` when nothing shared
474
427
  * them. The signature compare is the whole guard: a file that changed on disk holds a different signature,
@@ -479,8 +432,8 @@ function sharedRows(readCache, identity) {
479
432
  return held !== undefined && held.signature === identity.signature && held.rows !== undefined ? held.rows : undefined;
480
433
  }
481
434
  /**
482
- * Share the rows of one clean read, thus the next pass over the same bytes starts no second container and
483
- * parses nothing again. A failed read is transient, thus only rows enter the cache.
435
+ * Share the rows of one clean read, thus the next pass over the same bytes parses nothing again. A failed
436
+ * read is transient, thus only rows enter the cache.
484
437
  */
485
438
  function shareRows(readCache, identity, rows) {
486
439
  readCache?.set(identity.absolute, { signature: identity.signature, hash: identity.onDiskHash, rows });
@@ -500,7 +453,7 @@ function accessesOf(reference) {
500
453
  }
501
454
  }
502
455
  /**
503
- * Make the production resolver over the workspace root and the optional extraction arm.
456
+ * Make the production resolver over the workspace root.
504
457
  *
505
458
  * The resolver holds a per-pass cache. `prepare` groups the references by artifact, reads each file one
506
459
  * time, and fills the cache. `resolve` then answers from the cache. A `resolve` with no prior `prepare`
@@ -508,7 +461,7 @@ function accessesOf(reference) {
508
461
  * artifact on both paths, and never one read for each reference.
509
462
  */
510
463
  export function createProductionResolver(deps) {
511
- const { workspaceRoot, analysisId, extractionArm, readCache } = deps;
464
+ const { workspaceRoot, analysisId, readCache } = deps;
512
465
  const cap = deps.cap ?? DEFAULT_CAP_BYTES;
513
466
  // The per-pass caches. `prepare` clears and refills them, thus a later pass reads the artifacts again.
514
467
  const idCache = new Map();
@@ -528,8 +481,8 @@ export function createProductionResolver(deps) {
528
481
  }
529
482
  /**
530
483
  * Give back the cells of one path, from the cache after a prepare, or by a fresh read. A fresh read
531
- * runs the host fast path, and it resolves a fall-through through the arm as a batch of one. The
532
- * outcome enters the cache, thus a second reference at one path opens no second batch.
484
+ * runs the host fast path. The outcome enters the cache, thus a second reference at one path reads
485
+ * nothing again.
533
486
  */
534
487
  async function getCells(path, identity) {
535
488
  const cached = cellsCache.get(path);
@@ -549,18 +502,9 @@ export function createProductionResolver(deps) {
549
502
  cellsCache.set(path, parsed);
550
503
  return parsed;
551
504
  }
552
- if (read.kind === "unsupported-format") {
553
- const unavailable = { kind: "unavailable", detail: read.detail };
554
- cellsCache.set(path, unavailable);
555
- return unavailable;
556
- }
557
- const resolved = await extractFallThrough(extractionArm, [{ path, hash: identity.onDiskHash, format: read.format, hostDetail: read.detail }]);
558
- const cells = resolved.get(path) ?? { kind: "unreadable", detail: `the extraction arm did not read the file at ${path}` };
559
- if (cells.kind === "rows") {
560
- shareRows(readCache, identity, cells.rows);
561
- }
562
- cellsCache.set(path, cells);
563
- return cells;
505
+ const unavailable = read.kind === "unsupported-format" ? { kind: "unavailable", detail: read.detail } : fallThroughCells(path, read.detail);
506
+ cellsCache.set(path, unavailable);
507
+ return unavailable;
564
508
  }
565
509
  /**
566
510
  * The identity gate that a cell-reading reference passes before a read of cells.
@@ -788,7 +732,7 @@ export function createProductionResolver(deps) {
788
732
  }
789
733
  }
790
734
  // An earlier pass over these exact bytes already paid for the rows. Take them, thus the second pass
791
- // of one analysis parses nothing again and starts no second container.
735
+ // of one analysis parses nothing again.
792
736
  const pending = [];
793
737
  for (const target of cellTargets) {
794
738
  const shared = sharedRows(readCache, target.identity);
@@ -800,10 +744,6 @@ export function createProductionResolver(deps) {
800
744
  }
801
745
  }
802
746
  const reads = await allWithConcurrency(pending.map((target) => async () => ({ target, read: await hostReadCells(cap, target.path, target.identity) })), PREPARE_CONCURRENCY);
803
- // Split the clean reads from the fall-throughs, then resolve every fall-through in one arm call. An
804
- // unsupported format reaches no arm, because no reader is decided for it.
805
- const fallThrough = [];
806
- const identityByPath = new Map();
807
747
  for (const { target, read } of reads) {
808
748
  if (read.kind === "rows") {
809
749
  cellsCache.set(target.path, { kind: "rows", rows: read.rows });
@@ -813,16 +753,7 @@ export function createProductionResolver(deps) {
813
753
  cellsCache.set(target.path, { kind: "unavailable", detail: read.detail });
814
754
  }
815
755
  else {
816
- identityByPath.set(target.path, target.identity);
817
- fallThrough.push({ path: target.path, hash: target.identity.onDiskHash, format: read.format, hostDetail: read.detail });
818
- }
819
- }
820
- const resolved = await extractFallThrough(extractionArm, fallThrough);
821
- for (const [path, cells] of resolved) {
822
- cellsCache.set(path, cells);
823
- const identity = identityByPath.get(path);
824
- if (cells.kind === "rows" && identity !== undefined) {
825
- shareRows(readCache, identity, cells.rows);
756
+ cellsCache.set(target.path, fallThroughCells(target.path, read.detail));
826
757
  }
827
758
  }
828
759
  }
@@ -46,6 +46,15 @@ export declare function rendererApi(api: Echarts.CustomSeriesRenderItemAPI): Ren
46
46
  * behind.
47
47
  */
48
48
  export declare function renderChartSvg(echarts: ChartRuntime, option: EchartOption, size: ChartExportSize): Result<string, string>;
49
+ /**
50
+ * The count of coordinates that one option draws, summed over its series.
51
+ *
52
+ * The count bounds the export. A cloud of many thousands of points gives an SVG of many megabytes, two times,
53
+ * thus the page builds the SVG of such a chart on a click, with the points as one raster layer. An empty slot draws nothing, thus it counts nothing. A radar
54
+ * polygon draws one coordinate for each indicator, and a violin outline draws two vertices for each grid
55
+ * point, thus each counts every coordinate that it draws.
56
+ */
57
+ export declare function plottedPoints(option: EchartOption): number;
49
58
  /**
50
59
  * The two SVG files of one chart, or `undefined` for a chart past the export bound.
51
60
  *
@@ -138,7 +138,7 @@ function finishedSvg(svg, size) {
138
138
  * polygon draws one coordinate for each indicator, and a violin outline draws two vertices for each grid
139
139
  * point, thus each counts every coordinate that it draws.
140
140
  */
141
- function plottedPoints(option) {
141
+ export function plottedPoints(option) {
142
142
  const series = option.series;
143
143
  if (!Array.isArray(series))
144
144
  return 0;
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource hono/jsx */
1
2
  /**
2
3
  * The chart card markup.
3
4
  *
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
2
+ /** @jsxImportSource hono/jsx */
2
3
  /**
3
4
  * The chart card markup.
4
5
  *
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource hono/jsx */
1
2
  /**
2
3
  * The lineage keys of a grounded block, and the control that opens the chain of one key.
3
4
  *
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource hono/jsx */
1
2
  /**
2
3
  * The page assembly: the hero, the bands, the appendix band, and the footer.
3
4
  *
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
2
+ /** @jsxImportSource hono/jsx */
2
3
  /**
3
4
  * The page assembly: the hero, the bands, the appendix band, and the footer.
4
5
  *
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource hono/jsx */
1
2
  /**
2
3
  * The prose markup: the text block, the claim block, the section wrapper, and the page navigation.
3
4
  *
@@ -1,4 +1,5 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
2
+ /** @jsxImportSource hono/jsx */
2
3
  /**
3
4
  * The prose markup: the text block, the claim block, the section wrapper, and the page navigation.
4
5
  *
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource hono/jsx */
1
2
  /**
2
3
  * The reference markup: the one evidence marker, and the one appendix list under it.
3
4
  *
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource hono/jsx */
1
2
  /**
2
3
  * The value markup: the metric card, the data table, the figure, and the citation card.
3
4
  *
@@ -1,4 +1,5 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
2
+ /** @jsxImportSource hono/jsx */
2
3
  /**
3
4
  * The value markup: the metric card, the data table, the figure, and the citation card.
4
5
  *
@@ -19,6 +19,7 @@ import { type ConversationAgentDeps } from "../agents/conversation-agent.js";
19
19
  import { type ApprovePlanInput, type ApprovePlanRefusal, type PlanApproval } from "../app/approve-plan.js";
20
20
  import { type ChatTurns } from "../app/chat-turn-workflow.js";
21
21
  import { type WorkSurface } from "../app/work.js";
22
+ import { type RunCanceler } from "../execution/run-canceler.js";
22
23
  import { type ReportSessionRuntime } from "../app/report-session-runtime.js";
23
24
  import type { UsageRecorder } from "../billing/usage-recorder.js";
24
25
  import type { ResourcePolicy } from "../config/resource-limits.js";
@@ -27,6 +28,7 @@ import { type ChromeConfig } from "../lib/chrome.js";
27
28
  import { type AcquireEyes } from "../lib/eyes.js";
28
29
  import type { ThreadType } from "../memory/thread-store.js";
29
30
  import { type ExecuteAnalysisDeps, type ExecuteAnalysisInput, type ExecuteAnalysisResult } from "../workflows/execute-analysis.js";
31
+ import type { SandboxClient } from "../sandbox/client.js";
30
32
  import { type SandboxStepDeps, type SandboxStepInput, type SandboxStepResult } from "../workflows/sandbox-step.js";
31
33
  import { type DataProfileDeps, type DataProfileWorkflowInput } from "../tasks/data-profile.js";
32
34
  import { type CitationResolverConfig } from "../citations/resolve.js";
@@ -34,6 +36,7 @@ import type { CitationResolver } from "../citations/types.js";
34
36
  import type { AuthContext, Identity } from "../auth/types.js";
35
37
  import type { ReferenceResolver } from "../report-model/reference-resolver.js";
36
38
  import type { ProvenanceSeam } from "../provenance/seam.js";
39
+ import type { SyncSessionFile } from "../workspace/session-files.js";
37
40
  import { type AskGateway } from "../tools/approval/gateway.js";
38
41
  import type { MakeSessionPagePublisher, ResolvePageAsset, ResolvePageUrl } from "../tools/report-session/index.js";
39
42
  import type { BioToolKeys } from "../tools/bio/keys.js";
@@ -56,12 +59,19 @@ export type SandboxStepCallable = (input: SandboxStepInput) => Promise<SandboxSt
56
59
  * the same memory that the conversation agent writes.
57
60
  */
58
61
  export type CoreWorkflowDeps = {
59
- readonly sandboxStep: Omit<SandboxStepDeps, "usageRecorder" | "citationResolver" | "toolOutputStore" | "runAuthorizer">;
60
- readonly buildExecuteAnalysis: (sandboxStep: SandboxStepCallable) => Omit<ExecuteAnalysisDeps, "usageRecorder" | "literatureReviewer" | "toolOutputStore" | "workingMemory"> & {
61
- /** API keys for the bio/chem tools of the literature reviewer of the synthesis. */
62
+ readonly sandboxStep: Omit<SandboxStepDeps, "usageRecorder" | "citationResolver" | "toolOutputStore" | "runAuthorizer" | "leases">;
63
+ readonly buildExecuteAnalysis: (sandboxStep: SandboxStepCallable) => Omit<ExecuteAnalysisDeps, "usageRecorder" | "synthesisLookups" | "toolOutputStore" | "workingMemory" | "workspaceFs"> & {
64
+ /** API keys for the bio/chem tools of the lookups of the synthesis. */
62
65
  readonly bioKeys: BioToolKeys;
63
66
  };
64
- readonly dataProfile: Omit<DataProfileDeps, "usageRecorder" | "toolOutputStore">;
67
+ readonly dataProfile: Omit<DataProfileDeps, "usageRecorder" | "toolOutputStore" | "leases">;
68
+ };
69
+ /** The sandboxes of the runtime. The assembly builds the one sandbox module over the client. */
70
+ export type CoreSandboxDeps = {
71
+ /** The backend client that the embedder made. Only the sandbox module calls it. */
72
+ readonly client: SandboxClient;
73
+ /** How long a lease can go unused before it loses its machine. Absent: 15 minutes. */
74
+ readonly idlePeriodMs?: number;
65
75
  };
66
76
  /** The registered, callable workflow handles. */
67
77
  export type RegisteredWorkflows = {
@@ -71,9 +81,9 @@ export type RegisteredWorkflows = {
71
81
  };
72
82
  /**
73
83
  * Conversation-agent deps minus the workflow callable, the resource policy, the
74
- * usage recorder, the report-session anchor, the eyes, and the tool output store.
75
- * `assembleCoreRuntime` supplies each of those itself. Thus a caller cannot wire
76
- * one of these six values:
84
+ * usage recorder, the report-session anchor, the eyes, the tool output store, and the
85
+ * file sync. `assembleCoreRuntime` supplies each of those itself. Thus a caller cannot wire
86
+ * one of these values:
77
87
  *
78
88
  * - a stale callable
79
89
  * - a policy that diverges from the one the workflows see
@@ -81,12 +91,13 @@ export type RegisteredWorkflows = {
81
91
  * - an anchor over a different session runtime
82
92
  * - a seam that only half the agent tree looks through
83
93
  * - a store that only half the agent tree keeps its texts in
94
+ * - a file sync that only half the agent tree writes through
84
95
  *
85
96
  * The assembly resolves the eyes one time, from `CoreRuntimeDeps.eyes` and the
86
97
  * chrome config. A caller that bound the eyes here would give the conversation
87
98
  * agent a seam that the report agent never sees.
88
99
  */
89
- export type ConversationAssemblyDeps = Omit<ConversationAgentDeps, "executeAnalysisWorkflow" | "resourcePolicy" | "usageRecorder" | "citationResolver" | "anchorReportSession" | "eyes" | "toolOutputStore" | "registerSubAgent">;
100
+ export type ConversationAssemblyDeps = Omit<ConversationAgentDeps, "executeAnalysisWorkflow" | "usageRecorder" | "citationResolver" | "anchorReportSession" | "eyes" | "toolOutputStore" | "registerSubAgent" | "syncSessionFile">;
90
101
  /**
91
102
  * What binds one reference resolver: the analysis whose pinned artifacts it reads, and the identity and the
92
103
  * auth of the tool call that reads them. A resolver serves one analysis, thus the report tools build one for
@@ -105,9 +116,9 @@ export type MakeReportReferenceResolver = (scope: ReportResolverScope) => Promis
105
116
  export type CoreRuntimeDeps = {
106
117
  readonly conversation: ConversationAssemblyDeps;
107
118
  readonly workflows: CoreWorkflowDeps;
119
+ readonly sandbox: CoreSandboxDeps;
108
120
  /**
109
- * Host resource policy — per-step ceilings and machine budget. One supply
110
- * point for planner/routing guidance and workflow-input budget snapshots.
121
+ * Host resource policy — the per-step ceilings and the budget of the sandbox lease grant.
111
122
  */
112
123
  readonly resourcePolicy?: ResourcePolicy;
113
124
  /**
@@ -121,7 +132,7 @@ export type CoreRuntimeDeps = {
121
132
  readonly citationResolverConfig?: CitationResolverConfig;
122
133
  /**
123
134
  * The byte cap on the in-process host read of a report reference. A file over the
124
- * cap falls through to the extraction arm. Absent, the resolver uses its 16 MiB
135
+ * cap falls through, and its reference fails as `extraction-unavailable`. Absent, the resolver uses its 16 MiB
125
136
  * default. The embedder tunes it here, thus a host changes it with no harness change.
126
137
  */
127
138
  readonly reportHostReadCapBytes?: number;
@@ -129,7 +140,7 @@ export type CoreRuntimeDeps = {
129
140
  * The report reference resolver of an embedder. A managed host reads its pinned
130
141
  * artifacts from its own store, thus it binds a realization of the seam here and the
131
142
  * report tools resolve through it. Absent, the harness wires the production resolver
132
- * over the workspace tree and the extraction arm, which is the whole OSS path. A bound
143
+ * over the workspace tree, which is the whole OSS path. A bound
133
144
  * factory replaces that wiring, thus `reportHostReadCapBytes` then governs nothing.
134
145
  */
135
146
  readonly makeReportReferenceResolver?: MakeReportReferenceResolver;
@@ -188,6 +199,13 @@ export type CoreRuntimeDeps = {
188
199
  * which an embedder calls on its own. Thus that composition binds the seam there as well.
189
200
  */
190
201
  readonly provenance?: ProvenanceSeam;
202
+ /**
203
+ * The host copy of each file that a chat thread or a report session writes outside a run. A host that keeps the
204
+ * files of an analysis in its own store binds it, and each write reaches it with its bytes and its owner: the
205
+ * thread for the scratch files of a session, and the analysis for a `write_file` or `edit_file` write. Absent,
206
+ * the files stay in the workspace tree alone, which is the whole local path.
207
+ */
208
+ readonly syncSessionFile?: SyncSessionFile;
191
209
  /**
192
210
  * The credential of a chat turn that this process did not open, for example a turn that a recovery runs after a
193
211
  * restart. The workflow input of a turn holds no credential. Absent, or `undefined` for a turn: the turn pauses
@@ -263,6 +281,8 @@ export type CoreRuntime = {
263
281
  * ends one work in each state, and `resume` and `hold` reach the waits of one work. Only a client resumes paused work.
264
282
  */
265
283
  readonly work: WorkSurface;
284
+ /** The run canceler of `work`. It also ends the sandbox leases of the canceled workflows at once. */
285
+ readonly runCanceler: RunCanceler;
266
286
  /**
267
287
  * Approve a stored plan by its id and start its run with no model call. It runs over the deps that
268
288
  * reach the `execute_analysis` tool of the conversation agent, thus the approval and the tool launch