@inflexa-ai/harness 0.1.1 → 0.3.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 (330) hide show
  1. package/README.md +48 -0
  2. package/dist/agents/conversation-agent.d.ts +15 -11
  3. package/dist/agents/conversation-agent.js +31 -34
  4. package/dist/agents/report-builder.js +2 -1
  5. package/dist/agents/sandbox/bulk-transcriptomics-agent.js +1 -1
  6. package/dist/agents/sandbox/cheminformatics-agent.js +1 -19
  7. package/dist/agents/sandbox/chromatin-agent.js +1 -10
  8. package/dist/agents/sandbox/dna-methylation-agent.js +1 -10
  9. package/dist/agents/sandbox/drug-repurposing-agent.js +4 -14
  10. package/dist/agents/sandbox/enrichment-agent.js +1 -10
  11. package/dist/agents/sandbox/ephemeral-executor.js +1 -10
  12. package/dist/agents/sandbox/genomic-variant-agent.js +1 -3
  13. package/dist/agents/sandbox/immune-profiling-agent.js +1 -13
  14. package/dist/agents/sandbox/metabolomics-agent.js +1 -1
  15. package/dist/agents/sandbox/microbiome-agent.js +1 -1
  16. package/dist/agents/sandbox/multi-omics-integration-agent.js +1 -12
  17. package/dist/agents/sandbox/multimodal-sc-agent.js +1 -1
  18. package/dist/agents/sandbox/network-agent.js +1 -10
  19. package/dist/agents/sandbox/pkpd-clinical-response-agent.js +2 -8
  20. package/dist/agents/sandbox/proteomics-agent.js +1 -1
  21. package/dist/agents/sandbox/scientific-executor.js +1 -10
  22. package/dist/agents/sandbox/shared.d.ts +20 -6
  23. package/dist/agents/sandbox/shared.js +50 -39
  24. package/dist/agents/sandbox/single-cell-agent.js +1 -1
  25. package/dist/agents/sandbox/spatial-omics-agent.js +1 -1
  26. package/dist/agents/sandbox/statistical-modeling-agent.js +1 -1
  27. package/dist/agents/sandbox/translational-safety-agent.js +3 -9
  28. package/dist/agents/sandbox/types.d.ts +1 -1
  29. package/dist/agents/system-prompt.d.ts +37 -11
  30. package/dist/agents/system-prompt.js +35 -12
  31. package/dist/app/chat-turn.d.ts +3 -0
  32. package/dist/app/chat-turn.js +3 -1
  33. package/dist/app/data-profile-orientation.d.ts +34 -0
  34. package/dist/app/data-profile-orientation.js +117 -0
  35. package/dist/app/synthesize-run.d.ts +3 -0
  36. package/dist/app/synthesize-run.js +3 -1
  37. package/dist/contracts/schemas/chat-parts.d.ts +9 -9
  38. package/dist/execution/artifact-metadata.d.ts +3 -0
  39. package/dist/execution/artifact-metadata.js +10 -3
  40. package/dist/execution/artifact-registration.d.ts +2 -1
  41. package/dist/execution/artifact-registration.js +8 -2
  42. package/dist/execution/ephemeral-runner.d.ts +16 -0
  43. package/dist/execution/ephemeral-runner.js +31 -5
  44. package/dist/execution/post-step-pipeline.d.ts +3 -0
  45. package/dist/execution/post-step-pipeline.js +24 -4
  46. package/dist/execution/reconcile-manifest.d.ts +7 -0
  47. package/dist/execution/reconcile-manifest.js +19 -5
  48. package/dist/execution/report-runner.d.ts +3 -0
  49. package/dist/execution/report-runner.js +4 -4
  50. package/dist/execution/run-synthesis.js +20 -19
  51. package/dist/execution/step-summary.d.ts +3 -0
  52. package/dist/execution/step-summary.js +6 -3
  53. package/dist/index.d.ts +9 -2
  54. package/dist/index.js +24 -5
  55. package/dist/lib/chrome.d.ts +4 -1
  56. package/dist/lib/chrome.js +10 -7
  57. package/dist/lib/console-logger.d.ts +19 -0
  58. package/dist/lib/console-logger.js +62 -0
  59. package/dist/lib/logger.d.ts +88 -0
  60. package/dist/lib/logger.js +37 -0
  61. package/dist/lib/otel.d.ts +2 -1
  62. package/dist/lib/otel.js +8 -3
  63. package/dist/loop/__fixtures__/scripted-provider.d.ts +2 -2
  64. package/dist/loop/__fixtures__/scripted-provider.js +2 -1
  65. package/dist/loop/metrics.d.ts +33 -1
  66. package/dist/loop/metrics.js +56 -2
  67. package/dist/loop/run-agent.d.ts +13 -1
  68. package/dist/loop/run-agent.js +19 -4
  69. package/dist/memory/card-builders.d.ts +8 -1
  70. package/dist/memory/card-builders.js +20 -3
  71. package/dist/memory/reconstruct-cards.js +4 -3
  72. package/dist/memory/thread-history.d.ts +27 -2
  73. package/dist/memory/thread-history.js +45 -5
  74. package/dist/memory/working-memory.d.ts +93 -10
  75. package/dist/memory/working-memory.js +220 -84
  76. package/dist/prompts/SOUL.d.ts +22 -9
  77. package/dist/prompts/SOUL.js +56 -37
  78. package/dist/prompts/analogical-reasoner.d.ts +1 -1
  79. package/dist/prompts/analogical-reasoner.js +2 -2
  80. package/dist/prompts/briefing.d.ts +100 -0
  81. package/dist/prompts/briefing.js +166 -0
  82. package/dist/prompts/conversation.d.ts +1 -1
  83. package/dist/prompts/conversation.js +94 -440
  84. package/dist/prompts/literature-reviewer.d.ts +1 -1
  85. package/dist/prompts/literature-reviewer.js +10 -10
  86. package/dist/prompts/planner.js +28 -59
  87. package/dist/prompts/report-builder.d.ts +1 -1
  88. package/dist/prompts/report-builder.js +71 -24
  89. package/dist/prompts/sandbox/bulk-transcriptomics-agent.d.ts +1 -1
  90. package/dist/prompts/sandbox/bulk-transcriptomics-agent.js +2 -7
  91. package/dist/prompts/sandbox/cheminformatics-agent.d.ts +1 -1
  92. package/dist/prompts/sandbox/cheminformatics-agent.js +11 -15
  93. package/dist/prompts/sandbox/chromatin-agent.d.ts +1 -1
  94. package/dist/prompts/sandbox/chromatin-agent.js +3 -7
  95. package/dist/prompts/sandbox/data-profiler.d.ts +1 -1
  96. package/dist/prompts/sandbox/data-profiler.js +13 -8
  97. package/dist/prompts/sandbox/dna-methylation-agent.d.ts +1 -1
  98. package/dist/prompts/sandbox/dna-methylation-agent.js +2 -7
  99. package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
  100. package/dist/prompts/sandbox/drug-repurposing-agent.js +15 -16
  101. package/dist/prompts/sandbox/enrichment-agent.d.ts +1 -1
  102. package/dist/prompts/sandbox/enrichment-agent.js +2 -9
  103. package/dist/prompts/sandbox/genomic-variant-agent.d.ts +1 -1
  104. package/dist/prompts/sandbox/genomic-variant-agent.js +2 -6
  105. package/dist/prompts/sandbox/immune-profiling-agent.d.ts +1 -1
  106. package/dist/prompts/sandbox/immune-profiling-agent.js +3 -8
  107. package/dist/prompts/sandbox/metabolomics-agent.d.ts +1 -1
  108. package/dist/prompts/sandbox/metabolomics-agent.js +1 -7
  109. package/dist/prompts/sandbox/microbiome-agent.d.ts +1 -1
  110. package/dist/prompts/sandbox/microbiome-agent.js +2 -7
  111. package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
  112. package/dist/prompts/sandbox/multi-omics-integration-agent.js +2 -8
  113. package/dist/prompts/sandbox/multimodal-sc-agent.d.ts +1 -1
  114. package/dist/prompts/sandbox/multimodal-sc-agent.js +2 -7
  115. package/dist/prompts/sandbox/network-agent.d.ts +1 -1
  116. package/dist/prompts/sandbox/network-agent.js +2 -7
  117. package/dist/prompts/sandbox/proteomics-agent.d.ts +1 -1
  118. package/dist/prompts/sandbox/proteomics-agent.js +2 -9
  119. package/dist/prompts/sandbox/single-cell-agent.d.ts +1 -1
  120. package/dist/prompts/sandbox/single-cell-agent.js +2 -9
  121. package/dist/prompts/sandbox/spatial-omics-agent.d.ts +1 -1
  122. package/dist/prompts/sandbox/spatial-omics-agent.js +3 -6
  123. package/dist/prompts/sandbox/statistical-modeling-agent.d.ts +1 -1
  124. package/dist/prompts/sandbox/statistical-modeling-agent.js +2 -7
  125. package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
  126. package/dist/prompts/sandbox/translational-safety-agent.js +13 -14
  127. package/dist/prompts/sandbox-standards.d.ts +22 -14
  128. package/dist/prompts/sandbox-standards.js +91 -71
  129. package/dist/prompts/synthesis-agent.d.ts +1 -1
  130. package/dist/prompts/synthesis-agent.js +33 -131
  131. package/dist/provenance/collector.js +1 -1
  132. package/dist/providers/ai-sdk.js +31 -4
  133. package/dist/providers/prompt-cache.d.ts +74 -0
  134. package/dist/providers/prompt-cache.js +77 -0
  135. package/dist/providers/types.d.ts +33 -0
  136. package/dist/reference-data/catalog.d.ts +131 -0
  137. package/dist/reference-data/catalog.js +348 -0
  138. package/dist/reference-data/receipt.d.ts +41 -0
  139. package/dist/reference-data/receipt.js +40 -0
  140. package/dist/runtime/boot.d.ts +2 -2
  141. package/dist/runtime/boot.js +1 -1
  142. package/dist/runtime/connection-budget.d.ts +2 -2
  143. package/dist/runtime/connection-budget.js +5 -3
  144. package/dist/runtime/dbos.d.ts +7 -7
  145. package/dist/runtime/dbos.js +14 -11
  146. package/dist/runtime/shutdown.d.ts +2 -2
  147. package/dist/runtime/shutdown.js +4 -3
  148. package/dist/sandbox/create-sandbox.d.ts +2 -2
  149. package/dist/sandbox/docker-client.d.ts +2 -2
  150. package/dist/sandbox/docker-client.js +4 -1
  151. package/dist/sandbox/k8s-client.d.ts +3 -0
  152. package/dist/sandbox/k8s-client.js +5 -4
  153. package/dist/sandbox/notification-sweep.d.ts +3 -3
  154. package/dist/sandbox/notification-sweep.js +4 -2
  155. package/dist/sandbox/reaper.d.ts +3 -3
  156. package/dist/sandbox/reaper.js +7 -4
  157. package/dist/sandbox/watchdog.d.ts +3 -3
  158. package/dist/sandbox/watchdog.js +8 -2
  159. package/dist/schemas/data-profile-schemas.js +5 -3
  160. package/dist/schemas/plan-schemas.d.ts +21 -21
  161. package/dist/schemas/plan-schemas.js +9 -3
  162. package/dist/schemas/run-synthesis.d.ts +8 -4
  163. package/dist/schemas/run-synthesis.js +92 -56
  164. package/dist/schemas/validate-plan.js +1 -1
  165. package/dist/schemas/workflow-state.d.ts +7 -1
  166. package/dist/schemas/workflow-state.js +33 -19
  167. package/dist/state/artifacts.d.ts +13 -0
  168. package/dist/state/artifacts.js +27 -0
  169. package/dist/state/data-profile.d.ts +64 -5
  170. package/dist/state/index.d.ts +3 -3
  171. package/dist/state/index.js +1 -1
  172. package/dist/state/init.d.ts +2 -1
  173. package/dist/state/init.js +5 -6
  174. package/dist/tasks/data-profile.d.ts +25 -2
  175. package/dist/tasks/data-profile.js +95 -39
  176. package/dist/tools/bio/chembl.d.ts +38 -0
  177. package/dist/tools/bio/chembl.js +138 -0
  178. package/dist/tools/bio/comptox.d.ts +50 -0
  179. package/dist/tools/bio/comptox.js +149 -0
  180. package/dist/tools/bio/get-impc-ko-profile.js +9 -6
  181. package/dist/tools/bio/index.d.ts +5 -17
  182. package/dist/tools/bio/index.js +5 -17
  183. package/dist/tools/bio/keys.d.ts +14 -9
  184. package/dist/tools/bio/keys.js +16 -16
  185. package/dist/tools/bio/opentargets.d.ts +38 -0
  186. package/dist/tools/bio/opentargets.js +89 -0
  187. package/dist/tools/bio/pubchem.d.ts +29 -0
  188. package/dist/tools/bio/pubchem.js +92 -0
  189. package/dist/tools/bio/pubmed.d.ts +51 -0
  190. package/dist/tools/bio/pubmed.js +100 -0
  191. package/dist/tools/bio/search-bgee-expression.js +12 -6
  192. package/dist/tools/bio/search-clinical-trials.js +16 -5
  193. package/dist/tools/bio/search-dgidb.d.ts +11 -1
  194. package/dist/tools/bio/search-dgidb.js +92 -78
  195. package/dist/tools/bio/search-faers.js +8 -4
  196. package/dist/tools/bio/search-geo-datasets.js +20 -6
  197. package/dist/tools/bio/search-gwas-catalog.d.ts +1 -1
  198. package/dist/tools/bio/search-pharmgkb.js +10 -4
  199. package/dist/tools/display/index.d.ts +1 -0
  200. package/dist/tools/display/index.js +1 -0
  201. package/dist/tools/display/normalize-echart-spec.d.ts +61 -0
  202. package/dist/tools/display/normalize-echart-spec.js +211 -0
  203. package/dist/tools/display/show-user.d.ts +6 -1
  204. package/dist/tools/display/show-user.js +25 -12
  205. package/dist/tools/execute-plan.js +5 -2
  206. package/dist/tools/iterate-report.d.ts +171 -118
  207. package/dist/tools/iterate-report.js +336 -96
  208. package/dist/tools/lib/chembl-client.d.ts +12 -0
  209. package/dist/tools/lib/chembl-client.js +127 -0
  210. package/dist/tools/lib/ctx-ops.d.ts +224 -0
  211. package/dist/tools/lib/ctx-ops.js +450 -0
  212. package/dist/tools/lib/iuphar-client.js +10 -1
  213. package/dist/tools/lib/openfda-client.js +11 -3
  214. package/dist/tools/lib/pathway-client.js +10 -4
  215. package/dist/tools/lib/pubchem-ops.d.ts +74 -0
  216. package/dist/tools/lib/pubchem-ops.js +224 -0
  217. package/dist/tools/memory/update-working-memory.d.ts +45 -7
  218. package/dist/tools/memory/update-working-memory.js +111 -41
  219. package/dist/tools/report/index.d.ts +3 -2
  220. package/dist/tools/report/index.js +3 -2
  221. package/dist/tools/research/generate-analogy-report.js +25 -12
  222. package/dist/tools/research/generate-plan.d.ts +12 -5
  223. package/dist/tools/research/generate-plan.js +168 -37
  224. package/dist/tools/research/index.d.ts +1 -0
  225. package/dist/tools/research/index.js +1 -0
  226. package/dist/tools/research/inspect-data-profile.d.ts +85 -0
  227. package/dist/tools/research/inspect-data-profile.js +161 -0
  228. package/dist/tools/research/literature-reviewer.d.ts +3 -0
  229. package/dist/tools/research/literature-reviewer.js +5 -6
  230. package/dist/tools/sandbox/list-available-packages.d.ts +79 -5
  231. package/dist/tools/sandbox/list-available-packages.js +152 -10
  232. package/dist/tools/sandbox/list-available-refs.d.ts +141 -5
  233. package/dist/tools/sandbox/list-available-refs.js +647 -134
  234. package/dist/tools/sandbox/report-blocker.d.ts +39 -9
  235. package/dist/tools/sandbox/report-blocker.js +43 -20
  236. package/dist/tools/workspace/execute-command.d.ts +3 -0
  237. package/dist/tools/workspace/execute-command.js +3 -1
  238. package/dist/tools/workspace/read-file.js +4 -5
  239. package/dist/tools/workspace/run-exec.d.ts +4 -4
  240. package/dist/tools/workspace/run-exec.js +4 -4
  241. package/dist/tools/workspace/show-file.js +10 -6
  242. package/dist/tools/workspace/show-plan.js +12 -6
  243. package/dist/tools/workspace/workspace-search.d.ts +1 -1
  244. package/dist/tools/workspace/workspace-search.js +11 -5
  245. package/dist/workflows/execute-analysis.d.ts +46 -4
  246. package/dist/workflows/execute-analysis.js +118 -13
  247. package/dist/workflows/execute-target-assessment.d.ts +3 -0
  248. package/dist/workflows/execute-target-assessment.js +19 -15
  249. package/dist/workflows/sandbox-step.d.ts +9 -0
  250. package/dist/workflows/sandbox-step.js +39 -17
  251. package/dist/workflows/target-assessment/lib/citation-validator.js +2 -2
  252. package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.js +2 -1
  253. package/dist/workflows/target-assessment/lib/llm-step.d.ts +3 -0
  254. package/dist/workflows/target-assessment/lib/llm-step.js +3 -1
  255. package/dist/workflows/target-assessment/lib/structured-llm.d.ts +3 -0
  256. package/dist/workflows/target-assessment/lib/structured-llm.js +1 -0
  257. package/dist/workflows/target-assessment/phase5-persist.d.ts +3 -0
  258. package/dist/workflows/target-assessment/phase5-persist.js +8 -3
  259. package/dist/workflows/target-assessment/progress.d.ts +2 -1
  260. package/dist/workflows/target-assessment/progress.js +4 -3
  261. package/dist/workspace/filesystem.js +163 -74
  262. package/dist/workspace/paths.d.ts +2 -2
  263. package/dist/workspace/paths.js +2 -2
  264. package/package.json +95 -96
  265. package/dist/execution/filesystem-artifact-registry.d.ts +0 -57
  266. package/dist/execution/filesystem-artifact-registry.js +0 -92
  267. package/dist/lib/identifiers.d.ts +0 -8
  268. package/dist/lib/identifiers.js +0 -10
  269. package/dist/lib/mime-detect.d.ts +0 -17
  270. package/dist/lib/mime-detect.js +0 -29
  271. package/dist/lib/streamed-download.d.ts +0 -28
  272. package/dist/lib/streamed-download.js +0 -111
  273. package/dist/lib/trace-context.d.ts +0 -11
  274. package/dist/lib/trace-context.js +0 -49
  275. package/dist/providers/llm-capabilities.d.ts +0 -33
  276. package/dist/providers/llm-capabilities.js +0 -58
  277. package/dist/schemas/render-step-prompt.d.ts +0 -32
  278. package/dist/schemas/render-step-prompt.js +0 -76
  279. package/dist/tools/bio/find-approval-precedent.d.ts +0 -32
  280. package/dist/tools/bio/find-approval-precedent.js +0 -72
  281. package/dist/tools/bio/get-article-details.d.ts +0 -11
  282. package/dist/tools/bio/get-article-details.js +0 -20
  283. package/dist/tools/bio/get-article-full-text.d.ts +0 -19
  284. package/dist/tools/bio/get-article-full-text.js +0 -32
  285. package/dist/tools/bio/get-bioactivity.d.ts +0 -11
  286. package/dist/tools/bio/get-bioactivity.js +0 -23
  287. package/dist/tools/bio/get-drug-info.d.ts +0 -9
  288. package/dist/tools/bio/get-drug-info.js +0 -22
  289. package/dist/tools/bio/get-mechanism.d.ts +0 -8
  290. package/dist/tools/bio/get-mechanism.js +0 -18
  291. package/dist/tools/bio/get-pubchem-assays.d.ts +0 -22
  292. package/dist/tools/bio/get-pubchem-assays.js +0 -107
  293. package/dist/tools/bio/get-pubchem-cross-refs.d.ts +0 -15
  294. package/dist/tools/bio/get-pubchem-cross-refs.js +0 -68
  295. package/dist/tools/bio/get-target-safety.d.ts +0 -18
  296. package/dist/tools/bio/get-target-safety.js +0 -26
  297. package/dist/tools/bio/search-compounds.d.ts +0 -22
  298. package/dist/tools/bio/search-compounds.js +0 -160
  299. package/dist/tools/bio/search-ctx-chemical.d.ts +0 -50
  300. package/dist/tools/bio/search-ctx-chemical.js +0 -130
  301. package/dist/tools/bio/search-ctx-exposure.d.ts +0 -55
  302. package/dist/tools/bio/search-ctx-exposure.js +0 -176
  303. package/dist/tools/bio/search-ctx-hazard.d.ts +0 -111
  304. package/dist/tools/bio/search-ctx-hazard.js +0 -178
  305. package/dist/tools/bio/search-opentargets.d.ts +0 -11
  306. package/dist/tools/bio/search-opentargets.js +0 -25
  307. package/dist/tools/bio/search-pubchem-compound.d.ts +0 -26
  308. package/dist/tools/bio/search-pubchem-compound.js +0 -110
  309. package/dist/tools/bio/search-pubmed.d.ts +0 -17
  310. package/dist/tools/bio/search-pubmed.js +0 -31
  311. package/dist/tools/bio/search-targets.d.ts +0 -9
  312. package/dist/tools/bio/search-targets.js +0 -20
  313. package/dist/tools/bio/search-toxcast.d.ts +0 -36
  314. package/dist/tools/bio/search-toxcast.js +0 -141
  315. package/dist/workflows/register-workflows.d.ts +0 -51
  316. package/dist/workflows/register-workflows.js +0 -48
  317. package/dist/workflows/resume-execute-analysis.d.ts +0 -70
  318. package/dist/workflows/resume-execute-analysis.js +0 -80
  319. package/dist/workflows/target-assessment/correction-loop.d.ts +0 -45
  320. package/dist/workflows/target-assessment/correction-loop.js +0 -62
  321. package/dist/workflows/target-assessment/steps/phase0-resolve.d.ts +0 -71
  322. package/dist/workflows/target-assessment/steps/phase0-resolve.js +0 -21
  323. package/dist/workflows/target-assessment/steps/phase1-aggregate.d.ts +0 -1018
  324. package/dist/workflows/target-assessment/steps/phase1-aggregate.js +0 -25
  325. package/dist/workspace/mount-strategy.d.ts +0 -50
  326. package/dist/workspace/mount-strategy.js +0 -67
  327. package/dist/workspace/provenance-collector.d.ts +0 -34
  328. package/dist/workspace/provenance-collector.js +0 -16
  329. package/dist/workspace/workspace-paths.d.ts +0 -26
  330. package/dist/workspace/workspace-paths.js +0 -31
@@ -156,6 +156,7 @@ export declare const DagStatePartSchema: z.ZodObject<{
156
156
  }, z.core.$strict>;
157
157
  export declare const StepPhaseSchema: z.ZodEnum<{
158
158
  failed: "failed";
159
+ warning: "warning";
159
160
  "sandbox-init": "sandbox-init";
160
161
  executing: "executing";
161
162
  "generating-metadata": "generating-metadata";
@@ -164,7 +165,6 @@ export declare const StepPhaseSchema: z.ZodEnum<{
164
165
  persisting: "persisting";
165
166
  complete: "complete";
166
167
  retrying: "retrying";
167
- warning: "warning";
168
168
  }>;
169
169
  export declare const StepActivityPartSchema: z.ZodObject<{
170
170
  type: z.ZodLiteral<"data-step-activity">;
@@ -173,6 +173,7 @@ export declare const StepActivityPartSchema: z.ZodObject<{
173
173
  stepId: z.ZodString;
174
174
  phase: z.ZodEnum<{
175
175
  failed: "failed";
176
+ warning: "warning";
176
177
  "sandbox-init": "sandbox-init";
177
178
  executing: "executing";
178
179
  "generating-metadata": "generating-metadata";
@@ -181,7 +182,6 @@ export declare const StepActivityPartSchema: z.ZodObject<{
181
182
  persisting: "persisting";
182
183
  complete: "complete";
183
184
  retrying: "retrying";
184
- warning: "warning";
185
185
  }>;
186
186
  activity: z.ZodString;
187
187
  }, z.core.$strip>;
@@ -212,11 +212,11 @@ export declare const StepOutputFileSchema: z.ZodObject<{
212
212
  size: z.ZodNumber;
213
213
  fileType: z.ZodEnum<{
214
214
  output: "output";
215
+ summary: "summary";
215
216
  script: "script";
216
217
  figure: "figure";
217
218
  log: "log";
218
219
  notebook: "notebook";
219
- summary: "summary";
220
220
  }>;
221
221
  description: z.ZodString;
222
222
  }, z.core.$strip>;
@@ -231,11 +231,11 @@ export declare const StepOutputPartSchema: z.ZodObject<{
231
231
  size: z.ZodNumber;
232
232
  fileType: z.ZodEnum<{
233
233
  output: "output";
234
+ summary: "summary";
234
235
  script: "script";
235
236
  figure: "figure";
236
237
  log: "log";
237
238
  notebook: "notebook";
238
- summary: "summary";
239
239
  }>;
240
240
  description: z.ZodString;
241
241
  }, z.core.$strip>>;
@@ -298,11 +298,11 @@ export declare const SynthesizedFindingSchema: z.ZodObject<{
298
298
  low: "low";
299
299
  }>;
300
300
  noveltyStatus: z.ZodEnum<{
301
- expected: "expected";
302
301
  novel: "novel";
303
302
  confirmed: "confirmed";
304
303
  partially_confirmed: "partially_confirmed";
305
304
  contradicted: "contradicted";
305
+ expected: "expected";
306
306
  }>;
307
307
  literatureInterpretation: z.ZodString;
308
308
  }, z.core.$strip>;
@@ -330,11 +330,11 @@ export declare const RunSynthesisPartSchema: z.ZodObject<{
330
330
  low: "low";
331
331
  }>;
332
332
  noveltyStatus: z.ZodEnum<{
333
- expected: "expected";
334
333
  novel: "novel";
335
334
  confirmed: "confirmed";
336
335
  partially_confirmed: "partially_confirmed";
337
336
  contradicted: "contradicted";
337
+ expected: "expected";
338
338
  }>;
339
339
  literatureInterpretation: z.ZodString;
340
340
  }, z.core.$strip>>;
@@ -512,6 +512,7 @@ export declare const CortexChatPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
512
512
  stepId: z.ZodString;
513
513
  phase: z.ZodEnum<{
514
514
  failed: "failed";
515
+ warning: "warning";
515
516
  "sandbox-init": "sandbox-init";
516
517
  executing: "executing";
517
518
  "generating-metadata": "generating-metadata";
@@ -520,7 +521,6 @@ export declare const CortexChatPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
520
521
  persisting: "persisting";
521
522
  complete: "complete";
522
523
  retrying: "retrying";
523
- warning: "warning";
524
524
  }>;
525
525
  activity: z.ZodString;
526
526
  }, z.core.$strip>, z.ZodObject<{
@@ -547,11 +547,11 @@ export declare const CortexChatPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
547
547
  size: z.ZodNumber;
548
548
  fileType: z.ZodEnum<{
549
549
  output: "output";
550
+ summary: "summary";
550
551
  script: "script";
551
552
  figure: "figure";
552
553
  log: "log";
553
554
  notebook: "notebook";
554
- summary: "summary";
555
555
  }>;
556
556
  description: z.ZodString;
557
557
  }, z.core.$strip>>;
@@ -589,11 +589,11 @@ export declare const CortexChatPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
589
589
  low: "low";
590
590
  }>;
591
591
  noveltyStatus: z.ZodEnum<{
592
- expected: "expected";
593
592
  novel: "novel";
594
593
  confirmed: "confirmed";
595
594
  partially_confirmed: "partially_confirmed";
596
595
  contradicted: "contradicted";
596
+ expected: "expected";
597
597
  }>;
598
598
  literatureInterpretation: z.ZodString;
599
599
  }, z.core.$strip>>;
@@ -24,6 +24,7 @@ import type { AgentSession } from "../auth/types.js";
24
24
  import type { LoopMessage } from "../loop/types.js";
25
25
  import type { AgentChat } from "../providers/types.js";
26
26
  import type { WorkspaceFilesystem } from "../workspace/filesystem.js";
27
+ import type { Logger } from "../lib/logger.js";
27
28
  export interface ArtifactForMetadata {
28
29
  /** Path used to update `cortex_artifacts` after metadata generation. */
29
30
  readonly dbPath: string;
@@ -33,6 +34,8 @@ export interface ArtifactForMetadata {
33
34
  readonly sizeBytes?: number;
34
35
  }
35
36
  export interface GenerateFileMetadataOptions {
37
+ /** Operational logging seam; omitted falls back to no-op. */
38
+ readonly logger?: Logger;
36
39
  readonly provider: AgentChat;
37
40
  readonly session: AgentSession;
38
41
  readonly artifacts: readonly ArtifactForMetadata[];
@@ -26,8 +26,10 @@ import { runAgent } from "../loop/run-agent.js";
26
26
  import { passthroughStep } from "../loop/run-step.js";
27
27
  import { defineTool } from "../tools/define-tool.js";
28
28
  import { createReadFileTool } from "../tools/workspace/read-file.js";
29
+ import { composeSystemPrompt } from "../agents/system-prompt.js";
29
30
  import { inferArtifactType } from "../schemas/artifact-manifest.js";
30
31
  import { SubmitFileMetadataInputSchema } from "../schemas/file-metadata.js";
32
+ import { createNoopLogger } from "../lib/console-logger.js";
31
33
  /** Sub-agent identity for the describer loop — provenance only. */
32
34
  const DESCRIBER_AGENT_ID = "file-metadata-describer";
33
35
  /**
@@ -155,6 +157,7 @@ function fallbackEntry(artifact, extra) {
155
157
  * result always carries exactly one entry per input artifact.
156
158
  */
157
159
  export async function generateFileMetadata(opts) {
160
+ const logger = (opts.logger ?? createNoopLogger()).named("artifact-metadata").with({ resourceId: opts.resourceId });
158
161
  if (opts.artifacts.length === 0) {
159
162
  return { indexed: 0, entries: [] };
160
163
  }
@@ -166,7 +169,7 @@ export async function generateFileMetadata(opts) {
166
169
  }
167
170
  const describer = {
168
171
  id: DESCRIBER_AGENT_ID,
169
- systemPrompt: SYSTEM_PROMPT,
172
+ systemPrompt: composeSystemPrompt(SYSTEM_PROMPT),
170
173
  model: opts.modelId,
171
174
  tools,
172
175
  maxIterations: opts.maxIterations ?? DEFAULT_MAX_ITERATIONS,
@@ -182,7 +185,7 @@ export async function generateFileMetadata(opts) {
182
185
  });
183
186
  }
184
187
  catch (err) {
185
- console.warn(`[artifact-metadata] describer loop failed (resource=${opts.resourceId}); using fallbacks: ${err instanceof Error ? err.message : err}`);
188
+ logger.warn("describer loop failed; using fallbacks", logger.errorFields(err));
186
189
  }
187
190
  const entries = [];
188
191
  const fallbackPaths = [];
@@ -197,7 +200,11 @@ export async function generateFileMetadata(opts) {
197
200
  }
198
201
  }
199
202
  if (fallbackPaths.length > 0) {
200
- console.warn(`[artifact-metadata] ${fallbackPaths.length}/${opts.artifacts.length} file(s) used a deterministic fallback description (resource=${opts.resourceId}): ${fallbackPaths.join(", ")}`);
203
+ logger.warn("file(s) used a deterministic fallback description", {
204
+ fallbackCount: fallbackPaths.length,
205
+ artifactCount: opts.artifacts.length,
206
+ fallbackPaths,
207
+ });
201
208
  }
202
209
  return { indexed: holder.size, entries };
203
210
  }
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import type { Pool, PoolClient } from "pg";
13
13
  import type { AgentSession } from "../auth/types.js";
14
+ import type { Logger } from "../lib/logger.js";
14
15
  import type { ArtifactRegistry, ArtifactRegistrationInput } from "./artifact-registry.js";
15
16
  export type { ArtifactRegistrationInput };
16
17
  export interface ArtifactRegistrationResult {
@@ -33,4 +34,4 @@ export interface ArtifactRegistrationResult {
33
34
  * delegates external provenance registration to the injected `ArtifactRegistry`
34
35
  * and applies any returned external ids back onto the local rows.
35
36
  */
36
- export declare function registerStepArtifacts(db: Pool | PoolClient, registry: ArtifactRegistry, input: ArtifactRegistrationInput, session: AgentSession): Promise<ArtifactRegistrationResult>;
37
+ export declare function registerStepArtifacts(db: Pool | PoolClient, registry: ArtifactRegistry, input: ArtifactRegistrationInput, session: AgentSession, logger?: Logger): Promise<ArtifactRegistrationResult>;
@@ -9,6 +9,7 @@
9
9
  * (an external provenance ledger, or a filesystem index) is a composition-root
10
10
  * decision — this module never names one.
11
11
  */
12
+ import { createNoopLogger } from "../lib/console-logger.js";
12
13
  import { upsertArtifacts, updateArtifactId } from "../state/index.js";
13
14
  // ── Registration ─────────────────────────────────────────────────────
14
15
  /**
@@ -18,8 +19,13 @@ import { upsertArtifacts, updateArtifactId } from "../state/index.js";
18
19
  * delegates external provenance registration to the injected `ArtifactRegistry`
19
20
  * and applies any returned external ids back onto the local rows.
20
21
  */
21
- export async function registerStepArtifacts(db, registry, input, session) {
22
+ export async function registerStepArtifacts(db, registry, input, session,
23
+ // A parameter rather than a field on `ArtifactRegistrationInput`: that type is
24
+ // the seam's payload, handed verbatim to `registry.register`, and an
25
+ // embedder's registry has no business receiving the host's logger.
26
+ logger = createNoopLogger()) {
22
27
  const { resourceId, runId, stepId, artifacts } = input;
28
+ const log = logger.named("artifact-registration").with({ runId, stepId });
23
29
  if (artifacts.length === 0) {
24
30
  return { localCount: 0, externalRegistered: 0, externalFailed: 0, failureDetails: [] };
25
31
  }
@@ -27,7 +33,7 @@ export async function registerStepArtifacts(db, registry, input, session) {
27
33
  const emptyHash = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
28
34
  const localEntries = artifacts.map((a) => {
29
35
  if (a.size === 0 || a.hash === emptyHash) {
30
- console.warn(`[artifact-registration] empty artifact: path=${dbPathPrefix}${a.path} hash=${a.hash?.slice(0, 16)} size=${a.size} runId=${runId} stepId=${stepId}`);
36
+ log.warn("empty artifact", { path: `${dbPathPrefix}${a.path}`, hash: a.hash?.slice(0, 16), size: a.size });
31
37
  }
32
38
  return {
33
39
  resourceId,
@@ -29,12 +29,15 @@ import type { SandboxClient } from "../sandbox/client.js";
29
29
  import type { BioToolKeys } from "../tools/bio/keys.js";
30
30
  import type { WorkspaceFilesystem } from "../workspace/filesystem.js";
31
31
  import type { ResolveWorkspaceRoot } from "../workspace/paths.js";
32
+ import type { Logger } from "../lib/logger.js";
32
33
  /** Sub-agent identity — appended to `callPath`, set as `agentId`. */
33
34
  export declare const EPHEMERAL_AGENT_ID = "ephemeral-executor";
34
35
  /** Workflow-id prefix — the boot-time never-recover sweep matches on it. */
35
36
  export declare const EPHEMERAL_WORKFLOW_PREFIX: "ephemeral:";
36
37
  /** The body's construction-time deps — closed over at registration. */
37
38
  export interface EphemeralDeps {
39
+ /** Operational logging seam; omitted falls back to no-op. */
40
+ readonly logger?: Logger;
38
41
  readonly provider: ChatProvider;
39
42
  readonly pool: Pool;
40
43
  readonly sandboxClient: SandboxClient;
@@ -72,6 +75,19 @@ export interface EphemeralResult {
72
75
  * so the `run_ephemeral` tool can dispatch via `DBOS.startWorkflow`.
73
76
  */
74
77
  export declare function registerEphemeralWorkflow(deps: EphemeralDeps): (input: EphemeralWorkflowInput) => Promise<EphemeralResult>;
78
+ /**
79
+ * The executor's seed: its workspace frame, then the caller's ask.
80
+ *
81
+ * An ephemeral run is not scheduled by `executeAnalysis`, so no step briefing is
82
+ * composed for it — and the sandbox system prompt names no paths (it is static
83
+ * per agent type, so the provider's prompt cache can reuse it). The analysis
84
+ * root would otherwise reach the agent nowhere: `run_ephemeral`'s `prompt` is
85
+ * free text authored by the conversation agent.
86
+ *
87
+ * The frame differs from a step's, so this does not reuse `renderWorkspace`:
88
+ * there is no writable directory to name. The read-only tree IS the cwd.
89
+ */
90
+ export declare function ephemeralSeed(analysisId: string, prompt: string): string;
75
91
  /**
76
92
  * Run the ephemeral-executor agent against a fresh read-only sandbox.
77
93
  * Throws on sandbox start failure; otherwise returns the agent's final
@@ -28,6 +28,7 @@ import { durableStep } from "../loop/run-step.js";
28
28
  import { generateExecutionId } from "../sandbox/execution-id.js";
29
29
  import { mintSandboxIdentity } from "../sandbox/identity.js";
30
30
  import { createEphemeralExecutorAgent } from "../agents/sandbox/ephemeral-executor.js";
31
+ import { createNoopLogger } from "../lib/console-logger.js";
31
32
  /** Sub-agent identity — appended to `callPath`, set as `agentId`. */
32
33
  export const EPHEMERAL_AGENT_ID = "ephemeral-executor";
33
34
  /**
@@ -51,6 +52,28 @@ const EPHEMERAL_SANDBOX_RESOURCES = { cpu: 4, memoryGb: 8 };
51
52
  export function registerEphemeralWorkflow(deps) {
52
53
  return DBOS.registerWorkflow((input) => runEphemeralBody(input, deps), { name: "ephemeral" });
53
54
  }
55
+ /**
56
+ * The executor's seed: its workspace frame, then the caller's ask.
57
+ *
58
+ * An ephemeral run is not scheduled by `executeAnalysis`, so no step briefing is
59
+ * composed for it — and the sandbox system prompt names no paths (it is static
60
+ * per agent type, so the provider's prompt cache can reuse it). The analysis
61
+ * root would otherwise reach the agent nowhere: `run_ephemeral`'s `prompt` is
62
+ * free text authored by the conversation agent.
63
+ *
64
+ * The frame differs from a step's, so this does not reuse `renderWorkspace`:
65
+ * there is no writable directory to name. The read-only tree IS the cwd.
66
+ */
67
+ export function ephemeralSeed(analysisId, prompt) {
68
+ const root = `/${analysisId}`;
69
+ return [
70
+ "## Workspace",
71
+ `- Analysis root (read-only): \`${root}\` — inputs at \`${root}/data/inputs/\`, prior runs at \`${root}/runs/\`.`,
72
+ `- The analysis root is also your cwd, and what relative paths resolve against. The sandbox is read-only: there is nowhere to write, so return every result inline.`,
73
+ "",
74
+ prompt,
75
+ ].join("\n");
76
+ }
54
77
  /**
55
78
  * Run the ephemeral-executor agent against a fresh read-only sandbox.
56
79
  * Throws on sandbox start failure; otherwise returns the agent's final
@@ -63,13 +86,16 @@ export async function runEphemeralBody(input, deps) {
63
86
  throw new Error(`runEphemeralBody requires an analysis-scoped session — got ${runSession.scope.kind}`);
64
87
  }
65
88
  const analysisId = runSession.scope.analysisId;
89
+ // Bound after the scope guard: `analysisId` comes off the session's scope,
90
+ // not the workflow input.
91
+ const logger = (deps.logger ?? createNoopLogger()).named("ephemeral").with({ analysisId });
66
92
  const startedAt = performance.now();
67
93
  const executionId = generateExecutionId(EPHEMERAL_AGENT_ID);
68
94
  const workflowId = DBOS.workflowID ?? `${EPHEMERAL_WORKFLOW_PREFIX}${executionId}`;
69
95
  const childSession = forSubAgent(runSession, EPHEMERAL_AGENT_ID);
70
96
  // Resolver throw = loud workflow failure, per the workspace-root-resolution contract.
71
97
  const workspaceRoot = deps.resolveWorkspaceRoot(analysisId);
72
- console.log(`[ephemeral] execution=${executionId} analysis=${analysisId} starting sandbox`);
98
+ logger.info("starting sandbox", { executionId });
73
99
  const sandbox = await deps.sandboxClient.createSandbox({
74
100
  runId: EPHEMERAL_RUN_LITERAL,
75
101
  stepId: EPHEMERAL_RUN_LITERAL,
@@ -116,7 +142,7 @@ export async function runEphemeralBody(input, deps) {
116
142
  const agentDef = createEphemeralExecutorAgent(sandboxAgentDeps);
117
143
  const agent = input.maxIterations !== undefined ? { ...agentDef, maxIterations: input.maxIterations } : agentDef;
118
144
  const signal = new AbortController().signal;
119
- const { messages: finalMessages } = await runAgent(agent, [{ role: "user", content: input.prompt }], childSession, {
145
+ const { messages: finalMessages } = await runAgent(agent, [{ role: "user", content: ephemeralSeed(analysisId, input.prompt) }], childSession, {
120
146
  provider: deps.provider,
121
147
  signal,
122
148
  emit: () => { },
@@ -126,12 +152,12 @@ export async function runEphemeralBody(input, deps) {
126
152
  const text = finalText(finalMessages);
127
153
  const stepsUsed = countAssistantTurns(finalMessages);
128
154
  const durationMs = Math.round(performance.now() - startedAt);
129
- console.log(`[ephemeral] execution=${executionId} completed stepsUsed=${stepsUsed} durationMs=${durationMs}`);
155
+ logger.info("completed", { executionId, stepsUsed, durationMs });
130
156
  return { text, stepsUsed, durationMs };
131
157
  }
132
158
  catch (err) {
133
159
  const message = err instanceof Error ? err.message : String(err);
134
- console.error(`[ephemeral] execution=${executionId} failed: ${message}`);
160
+ logger.error("failed", { executionId, err: message });
135
161
  throw err;
136
162
  }
137
163
  finally {
@@ -141,7 +167,7 @@ export async function runEphemeralBody(input, deps) {
141
167
  catch (teardownErr) {
142
168
  // Teardown is idempotent — "already gone" is success. A failure here
143
169
  // is best-effort logged so the chat turn doesn't fail on cleanup.
144
- console.warn(`[ephemeral] execution=${executionId} teardown failed (non-fatal): ${teardownErr instanceof Error ? teardownErr.message : teardownErr}`);
170
+ logger.warn("teardown failed (non-fatal)", { executionId, ...logger.errorFields(teardownErr) });
145
171
  }
146
172
  }
147
173
  }
@@ -16,6 +16,7 @@ import type { WorkspaceFilesystem } from "../workspace/filesystem.js";
16
16
  import type { ResolveWorkspaceRoot } from "../workspace/paths.js";
17
17
  import type { ArtifactManifestEntry } from "../schemas/artifact-manifest.js";
18
18
  import type { StepSummary } from "../schemas/step-summary.js";
19
+ import type { Logger } from "../lib/logger.js";
19
20
  import type { ArtifactRegistry } from "./artifact-registry.js";
20
21
  import { type FileMetadataEntry } from "./artifact-metadata.js";
21
22
  import type { PostStepArtifacts, PostStepContext, StepOutputs } from "../workflows/sandbox-step.js";
@@ -25,6 +26,8 @@ import type { PostStepArtifacts, PostStepContext, StepOutputs } from "../workflo
25
26
  */
26
27
  export interface PostStepPipelineDeps {
27
28
  readonly pool: Pool;
29
+ /** Operational logging seam; omitted falls back to no-op. */
30
+ readonly logger?: Logger;
28
31
  /** Non-streaming chat — the metadata + summary sub-agent loops. */
29
32
  readonly provider: AgentChat;
30
33
  /** Write-side embedder for the vector index. */
@@ -12,6 +12,7 @@
12
12
  */
13
13
  import { join } from "node:path";
14
14
  import { unwrapOrThrow } from "../lib/result.js";
15
+ import { createNoopLogger } from "../lib/console-logger.js";
15
16
  import { writeFileWithinRoot } from "../lib/fs-helpers.js";
16
17
  import { registerStepArtifacts } from "./artifact-registration.js";
17
18
  import { reconcileManifestWithDisk } from "./reconcile-manifest.js";
@@ -79,7 +80,12 @@ export async function generateStepSummaryAndWrite(deps, postCtx, manifest) {
79
80
  await writeFileWithinRoot(writePrefix, join(writePrefix, "output", "summary.md"), summary.markdown);
80
81
  }
81
82
  catch (err) {
82
- console.warn(`[post-step.summary] writeFile output/summary.md failed for ${input.stepId}: ${err instanceof Error ? err.message : err}`);
83
+ const logger = (deps.logger ?? createNoopLogger()).named("post-step").named("summary");
84
+ logger.warn("writeFile output/summary.md failed", {
85
+ runId: input.runId,
86
+ stepId: input.stepId,
87
+ ...logger.errorFields(err),
88
+ });
83
89
  }
84
90
  }
85
91
  return summary;
@@ -102,6 +108,7 @@ export async function reconcileAndRegisterStepArtifacts(deps, postCtx, manifest)
102
108
  agentId: input.agentId,
103
109
  manifest: [...manifest],
104
110
  collector: lineageCollector,
111
+ ...(deps.logger ? { logger: deps.logger } : {}),
105
112
  });
106
113
  if (reconciled.manifest.length === 0)
107
114
  return reconciled.manifest;
@@ -111,7 +118,7 @@ export async function reconcileAndRegisterStepArtifacts(deps, postCtx, manifest)
111
118
  stepId: input.stepId,
112
119
  artifacts: reconciled.manifest,
113
120
  collector: lineageCollector,
114
- }, session);
121
+ }, session, deps.logger);
115
122
  if (reg.externalFailed > 0) {
116
123
  const wholeActivityFailed = reg.externalRegistered === 0;
117
124
  const detail = reg.failureDetails.map((f) => `${f.path}: ${f.error}`).join("\n ");
@@ -119,7 +126,19 @@ export async function reconcileAndRegisterStepArtifacts(deps, postCtx, manifest)
119
126
  `${reg.externalFailed} row(s) rejected, ${reg.externalRegistered}/${reg.localCount} local artifact(s) registered` +
120
127
  (wholeActivityFailed ? " (WHOLE ACTIVITY ROLLED BACK — outputs orphaned)" : "") +
121
128
  (detail ? `\n ${detail}` : "");
122
- console.error(msg);
129
+ // Logged as fields as well as thrown: the throw reaches `failStep` as one
130
+ // opaque string, so the per-path rejections are only queryable from here.
131
+ // This is what distinguishes a registry rejection from the attestation
132
+ // throws in `reconcileManifestWithDisk` when a step dies.
133
+ (deps.logger ?? createNoopLogger()).named("post-step").named("reconcile").error("external registration failed", {
134
+ runId: input.runId,
135
+ stepId: input.stepId,
136
+ externalFailed: reg.externalFailed,
137
+ externalRegistered: reg.externalRegistered,
138
+ localCount: reg.localCount,
139
+ wholeActivityFailed,
140
+ failures: reg.failureDetails,
141
+ });
123
142
  throw new Error(msg);
124
143
  }
125
144
  return reconciled.manifest;
@@ -176,7 +195,8 @@ export async function vectorIndexStepOutputs(deps, postCtx, artifacts) {
176
195
  }
177
196
  }
178
197
  catch (err) {
179
- console.warn(`[post-step.vector-index] indexing failed for ${input.stepId}: ${err instanceof Error ? err.message : err}`);
198
+ const logger = (deps.logger ?? createNoopLogger()).named("post-step").named("vector-index");
199
+ logger.warn("indexing failed", { runId: input.runId, stepId: input.stepId, ...logger.errorFields(err) });
180
200
  }
181
201
  }
182
202
  /**
@@ -1,5 +1,6 @@
1
1
  import type { ArtifactManifestEntry } from "../schemas/artifact-manifest.js";
2
2
  import type { ProvenanceCollector } from "../provenance/collector.js";
3
+ import type { Logger } from "../lib/logger.js";
3
4
  export interface ReconcileManifestInput {
4
5
  /** Absolute host root of the analysis's workspace tree. */
5
6
  workspaceRoot: string;
@@ -15,6 +16,12 @@ export interface ReconcileManifestInput {
15
16
  manifest: ArtifactManifestEntry[];
16
17
  /** Collector backing the manifest; mutated to reflect drops/rehashes. */
17
18
  collector: ProvenanceCollector;
19
+ /**
20
+ * Operational logging seam; omitted falls back to no-op. Attestation is
21
+ * fail-fast, so what this records — which entry was dropped, which input
22
+ * could not be hashed — is the account of why a step died.
23
+ */
24
+ logger?: Logger;
18
25
  }
19
26
  export interface ReconcileManifestResult {
20
27
  /** Reconciled manifest — phantoms removed, every entry rehashed from disk. */
@@ -21,10 +21,12 @@
21
21
  */
22
22
  import { stat } from "node:fs/promises";
23
23
  import path from "node:path";
24
+ import { createNoopLogger } from "../lib/console-logger.js";
24
25
  import { computeSha256File, hasValidContentHash } from "../lib/fs-helpers.js";
25
26
  import { artifactReconcileDropped } from "../lib/metrics.js";
26
27
  export async function reconcileManifestWithDisk(input) {
27
28
  const { workspaceRoot, resourceId, runId, stepId, agentId, manifest, collector } = input;
29
+ const logger = (input.logger ?? createNoopLogger()).named("reconcile-manifest").with({ runId, stepId, agentId });
28
30
  const stepRoot = path.join(workspaceRoot, "runs", runId, stepId);
29
31
  const reconciled = [];
30
32
  let droppedCount = 0;
@@ -36,7 +38,7 @@ export async function reconcileManifestWithDisk(input) {
36
38
  // ENOENT and silently drop a real artifact, or — worse — succeed
37
39
  // against a host file the step never produced.
38
40
  if (!absPath.startsWith(stepRoot + path.sep) && absPath !== stepRoot) {
39
- console.warn(`[reconcile-manifest] skipping out-of-bounds path=${entry.path} stepId=${stepId} runId=${runId}`);
41
+ logger.warn("skipping out-of-bounds entry", { path: entry.path });
40
42
  continue;
41
43
  }
42
44
  let info;
@@ -45,7 +47,7 @@ export async function reconcileManifestWithDisk(input) {
45
47
  }
46
48
  catch (err) {
47
49
  if (err.code === "ENOENT") {
48
- console.debug(`[reconcile-manifest] dropping phantom path=${entry.path} stepId=${stepId} runId=${runId}`);
50
+ logger.debug("dropping phantom entry", { path: entry.path });
49
51
  collector.removeRecord(entry.path);
50
52
  droppedCount++;
51
53
  artifactReconcileDropped.add(1, { agent_id: agentId, step_id: stepId });
@@ -58,7 +60,7 @@ export async function reconcileManifestWithDisk(input) {
58
60
  // uses `createReadStream`, which throws `EISDIR` on directories and would
59
61
  // fail the whole step's reconciliation.
60
62
  if (!info.isFile()) {
61
- console.debug(`[reconcile-manifest] dropping non-file path=${entry.path} stepId=${stepId} runId=${runId}`);
63
+ logger.debug("dropping non-file entry", { path: entry.path });
62
64
  collector.removeRecord(entry.path);
63
65
  droppedCount++;
64
66
  artifactReconcileDropped.add(1, { agent_id: agentId, step_id: stepId });
@@ -72,7 +74,7 @@ export async function reconcileManifestWithDisk(input) {
72
74
  const hash = await computeSha256File(absPath);
73
75
  reconciled.push({ ...entry, hash, size: info.size });
74
76
  }
75
- await fillInputHashesFromDisk(collector, workspaceRoot, resourceId, runId, stepId);
77
+ await fillInputHashesFromDisk(collector, workspaceRoot, resourceId, runId, stepId, logger);
76
78
  return { manifest: reconciled, droppedCount };
77
79
  }
78
80
  /**
@@ -88,22 +90,31 @@ export async function reconcileManifestWithDisk(input) {
88
90
  * Lineage attestation is fail-fast: an input we cannot hash (gone, or resolving
89
91
  * outside the analysis tree) throws rather than registering a hashless edge.
90
92
  */
91
- async function fillInputHashesFromDisk(collector, workspaceRoot, resourceId, runId, stepId) {
93
+ async function fillInputHashesFromDisk(collector, workspaceRoot, resourceId, runId, stepId, logger) {
92
94
  const resourceRoot = path.resolve(workspaceRoot);
93
95
  for (const ref of collector.getTrackedInputs()) {
94
96
  if (ref.source === "artifacts")
95
97
  continue;
96
98
  if (hasValidContentHash(ref.hash))
97
99
  continue;
100
+ // Each throw below is logged before it is raised. The thrown message reaches
101
+ // `failStep` as one opaque string and everything downstream of that is
102
+ // scrubbed, so naming the site and the offending ref HERE is what makes a
103
+ // fail-fast attestation distinguishable from a registry rejection after the
104
+ // fact — the read's `source` in particular says whether the step declared
105
+ // this input at all.
106
+ const attestation = { path: ref.path, source: ref.source, refRunId: ref.runId, refStepId: ref.stepId };
98
107
  // `ref.path` is the absolute container path `/{resourceId}/...`; strip the
99
108
  // mount segment and map the tail onto the host workspace root. `path.join`
100
109
  // normalizes any `..`, and the bound confines the read to the analysis tree.
101
110
  const containerPrefix = `/${resourceId}`;
102
111
  if (ref.path !== containerPrefix && !ref.path.startsWith(containerPrefix + "/")) {
112
+ logger.error("input read resolves outside the analysis tree", { ...attestation, throwSite: "container-prefix-bound" });
103
113
  throw new Error(`[reconcile-manifest] input read resolves outside the analysis tree: path=${ref.path} stepId=${stepId} runId=${runId}`);
104
114
  }
105
115
  const hostPath = path.join(resourceRoot, ref.path.slice(containerPrefix.length + 1));
106
116
  if (hostPath !== resourceRoot && !hostPath.startsWith(resourceRoot + path.sep)) {
117
+ logger.error("input read resolves outside the analysis tree", { ...attestation, hostPath, throwSite: "workspace-root-bound" });
107
118
  throw new Error(`[reconcile-manifest] input read resolves outside the analysis tree: path=${ref.path} stepId=${stepId} runId=${runId}`);
108
119
  }
109
120
  let info;
@@ -112,10 +123,12 @@ async function fillInputHashesFromDisk(collector, workspaceRoot, resourceId, run
112
123
  }
113
124
  catch (err) {
114
125
  if (err.code === "ENOENT") {
126
+ logger.error("cannot attest input — not present at reconcile", { ...attestation, hostPath, throwSite: "input-enoent" });
115
127
  throw new Error(`[reconcile-manifest] cannot attest input ${ref.path}: not present at reconcile (stepId=${stepId} runId=${runId})`, {
116
128
  cause: err,
117
129
  });
118
130
  }
131
+ logger.error("cannot attest input — stat failed", { ...attestation, hostPath, throwSite: "input-stat", ...logger.errorFields(err) });
119
132
  throw err;
120
133
  }
121
134
  if (!info.isFile()) {
@@ -124,6 +137,7 @@ async function fillInputHashesFromDisk(collector, workspaceRoot, resourceId, run
124
137
  // it from lineage rather than failing the step — mirrors the output-side
125
138
  // non-file drop above. A genuinely missing FILE (ENOENT) still fails fast
126
139
  // as drift; a directory is not drift.
140
+ logger.debug("dropping non-file input from lineage", attestation);
127
141
  collector.dropInput(ref);
128
142
  continue;
129
143
  }
@@ -37,7 +37,10 @@ import type { EmitFn } from "../loop/types.js";
37
37
  import type { ChatProvider } from "../providers/types.js";
38
38
  import type { PreviewPublisher } from "../tools/report/preview-publisher.js";
39
39
  import type { ChromeConfig } from "../lib/chrome.js";
40
+ import type { Logger } from "../lib/logger.js";
40
41
  export interface ReportRunnerDeps {
42
+ /** Operational logging seam; omitted falls back to no-op. */
43
+ readonly logger?: Logger;
41
44
  readonly provider: ChatProvider;
42
45
  readonly pool: Pool;
43
46
  /** Model id — provenance / metric label; provider owns the wire model. */
@@ -41,10 +41,12 @@ import { withPreviewLock } from "../tools/lib/preview-lock.js";
41
41
  import { createBuildReportTool, createSubmitReportTool, createMintPreviewUrlTool, createPreviewSnapshotTool, createVersionFsTools, } from "../tools/report/index.js";
42
42
  import { createReportBuilderAgent, REPORT_BUILDER_AGENT_ID } from "../agents/report-builder.js";
43
43
  import { createSkillTools } from "../tools/sandbox/skills.js";
44
+ import { createNoopLogger } from "../lib/console-logger.js";
44
45
  /** Skill pack the report-builder prompt directs the model to read (design-system reference). */
45
46
  const REPORT_BUILDER_SKILLS = ["report-html"];
46
47
  const REPORT_AGENT_MAX_STEPS = 75;
47
48
  export async function runReportIteration(deps, opts) {
49
+ const logger = (deps.logger ?? createNoopLogger()).named("report-runner").with({ previewId: opts.previewId });
48
50
  const startTime = performance.now();
49
51
  return withPreviewLock(opts.previewId, async () => {
50
52
  // ── Resolve version directories ───────────────────────────────
@@ -169,9 +171,7 @@ export async function runReportIteration(deps, opts) {
169
171
  }
170
172
  }
171
173
  if (!outcome || agentError || phantomSuccess) {
172
- console.warn(`[report-runner] event=report.agent.finish preview=${opts.previewId} v${newVersion} ` +
173
- `submitted=${outcome?.ok === true} phantom=${phantomSuccess} ` +
174
- `agentError=${agentError ?? "null"}`);
174
+ logger.warn("report.agent.finish", { version: newVersion, submitted: outcome?.ok === true, phantom: phantomSuccess, agentError });
175
175
  const { reason, errorKind } = classifyFailure({
176
176
  phantomSuccess,
177
177
  agentError,
@@ -182,7 +182,7 @@ export async function runReportIteration(deps, opts) {
182
182
  await rm(versionDirAbs, { recursive: true, force: true });
183
183
  }
184
184
  catch (err) {
185
- console.error(`[report-runner] rollback failed for ${versionDirAbs}:`, err instanceof Error ? err.message : err);
185
+ logger.error("rollback failed", { versionDirAbs, ...logger.errorFields(err) });
186
186
  }
187
187
  return failure(opts.previewId, newVersion, reason, errorKind, startTime);
188
188
  }