@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
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ import { ReferenceArtifactPathSchema, ReferenceDatasetSchema, ReferenceSha256Schema } from "./catalog.js";
3
+ /** Schema version for installation receipts shared by all embedders. */
4
+ export const REFERENCE_INSTALL_RECEIPT_VERSION = 1;
5
+ /**
6
+ * What was actually written to disk for one artifact. The size and digest are
7
+ * *observed at install*, never copied from the catalog — for a `pinned`
8
+ * artifact they equal the catalog's (the install would have failed otherwise),
9
+ * and for an `unpinned` one they are the only record of what the mutable
10
+ * upstream served, which is what `verify` later checks the files against.
11
+ */
12
+ const ReferenceReceiptArtifactSchema = z.object({
13
+ path: ReferenceArtifactPathSchema,
14
+ bytes: z.number().int().nonnegative(),
15
+ sha256: ReferenceSha256Schema,
16
+ integrity: z.enum(["pinned", "unpinned"]),
17
+ });
18
+ /** Optional metadata describing one activated reference dataset version. */
19
+ export const ReferenceInstallReceiptSchema = z
20
+ .object({
21
+ version: z.literal(REFERENCE_INSTALL_RECEIPT_VERSION),
22
+ datasetId: ReferenceDatasetSchema.shape.id,
23
+ datasetVersion: ReferenceDatasetSchema.shape.version,
24
+ activatedAt: z.iso.datetime({ offset: true }),
25
+ artifacts: z.array(ReferenceReceiptArtifactSchema).min(1),
26
+ })
27
+ .superRefine((receipt, ctx) => {
28
+ const paths = new Set();
29
+ for (const [index, artifact] of receipt.artifacts.entries()) {
30
+ if (paths.has(artifact.path)) {
31
+ ctx.addIssue({ code: "custom", message: `Duplicate receipt artifact path: ${artifact.path}`, path: ["artifacts", index, "path"] });
32
+ }
33
+ paths.add(artifact.path);
34
+ }
35
+ });
36
+ /** Parse optional/untrusted receipt metadata; invalid receipts are ignored. */
37
+ export function parseReferenceInstallReceipt(input) {
38
+ const result = ReferenceInstallReceiptSchema.safeParse(input);
39
+ return result.success ? result.data : undefined;
40
+ }
@@ -31,7 +31,7 @@
31
31
  * once shutdown starts, exiting takes precedence (see `runShutdownSequence`).
32
32
  */
33
33
  import type { Pool } from "pg";
34
- import type pino from "pino";
34
+ import type { Logger } from "../lib/logger.js";
35
35
  import { type CoreRuntime, type CoreRuntimeDeps } from "./assemble.js";
36
36
  import { type ConnectionBudgetConfig } from "./connection-budget.js";
37
37
  import { type DbosConfig } from "./dbos.js";
@@ -46,7 +46,7 @@ export interface BootHarnessDeps {
46
46
  readonly dbos: DbosConfig;
47
47
  /** Connection-budget guard config. */
48
48
  readonly connectionBudget: ConnectionBudgetConfig;
49
- readonly logger: pino.Logger;
49
+ readonly logger: Logger;
50
50
  /**
51
51
  * Host-specific work that must run AFTER workflow registration and BEFORE
52
52
  * DBOS launch (scheduled sweeps, ephemeral reap, agent-switch install). The
@@ -49,7 +49,7 @@ export async function bootHarness(deps) {
49
49
  const runtime = assembleCoreRuntime(core);
50
50
  await deps.beforeLaunch?.();
51
51
  await launchDbos({ config: deps.dbos, logger });
52
- logger.info({ executorId: deps.dbos.executorId }, "[boot] harness booted");
52
+ logger.named("boot").info("harness booted", { executorId: deps.dbos.executorId });
53
53
  const shutdown = (signal) => runShutdownSequence({
54
54
  signal,
55
55
  logger,
@@ -21,7 +21,7 @@
21
21
  * misconfigured pod fails boot loudly instead of degrading under load.
22
22
  */
23
23
  import type { Pool } from "pg";
24
- import type pino from "pino";
24
+ import type { Logger } from "../lib/logger.js";
25
25
  /**
26
26
  * Narrow config slice the budget guard reads — only the optional app-pool
27
27
  * size override. Composition roots map `Env.DB_POOL_MAX` onto this.
@@ -31,7 +31,7 @@ export interface ConnectionBudgetConfig {
31
31
  }
32
32
  export interface AssertConnectionBudgetOptions {
33
33
  pool: Pool;
34
- logger: pino.Logger;
34
+ logger: Logger;
35
35
  config: ConnectionBudgetConfig;
36
36
  }
37
37
  /**
@@ -38,15 +38,17 @@ export async function assertConnectionBudget({ pool, logger, config }) {
38
38
  `Lower DB_POOL_MAX or raise max_connections.`);
39
39
  }
40
40
  const supportedReplicas = Math.floor((maxConnections - SAFETY_MARGIN) / podFootprint);
41
- logger.info({
41
+ logger
42
+ .named("boot")
43
+ .info(`postgres connection budget OK — this cluster's max_connections ` +
44
+ `supports ~${supportedReplicas} cortex replicas; size replicas/pooler accordingly`, {
42
45
  maxConnections,
43
46
  appPoolSize,
44
47
  dbosPoolSize,
45
48
  podFootprint,
46
49
  safetyMargin: SAFETY_MARGIN,
47
50
  supportedReplicas,
48
- }, `[boot] postgres connection budget OK — this cluster's max_connections ` +
49
- `supports ~${supportedReplicas} cortex replicas; size replicas/pooler accordingly`);
51
+ });
50
52
  return {
51
53
  maxConnections,
52
54
  appPoolSize,
@@ -12,8 +12,8 @@
12
12
  *
13
13
  * See `openspec/changes/harness-dbos-runtime`.
14
14
  */
15
- import type pino from "pino";
16
15
  import type { Pool } from "pg";
16
+ import type { Logger } from "../lib/logger.js";
17
17
  /**
18
18
  * Narrow config slice the DBOS bootstrap reads. Composition roots map their
19
19
  * validated `Env` onto this and pass the executor id in (the harness reads no env).
@@ -50,9 +50,9 @@ interface State {
50
50
  * must resolve before the HTTP listener accepts traffic (otherwise the
51
51
  * readiness probe could 200 against a runtime that can't own workflows).
52
52
  */
53
- export declare function launchDbos({ config, logger }: {
53
+ export declare function launchDbos({ config, logger: injected }: {
54
54
  config: DbosConfig;
55
- logger: pino.Logger;
55
+ logger: Logger;
56
56
  }): Promise<void>;
57
57
  /**
58
58
  * Shut DBOS down. In-flight workflows are marked recoverable so another
@@ -63,8 +63,8 @@ export declare function launchDbos({ config, logger }: {
63
63
  * Must run after HTTP has drained (so no inbound request is orphaned) and
64
64
  * before the application pool closes (DBOS needs the system DB).
65
65
  */
66
- export declare function shutdownDbos({ logger }: {
67
- logger: pino.Logger;
66
+ export declare function shutdownDbos({ logger: injected }: {
67
+ logger: Logger;
68
68
  }): Promise<void>;
69
69
  /**
70
70
  * Cancel any `ephemeral:`-prefixed PENDING workflow this executor owns —
@@ -79,9 +79,9 @@ export declare function shutdownDbos({ logger }: {
79
79
  * pre-launch timing, and this is the sole module that owns DBOS. The system
80
80
  * DB is the same database as the app pool, so the pool reaches it directly.
81
81
  */
82
- export declare function sweepEphemeralWorkflows({ pool, logger, executorId, }: {
82
+ export declare function sweepEphemeralWorkflows({ pool, logger: injectedLogger, executorId, }: {
83
83
  pool: Pool;
84
- logger: pino.Logger;
84
+ logger: Logger;
85
85
  /** Stable per-pod executor id — must match `launchDbos`'s `executorId`. */
86
86
  executorId: string;
87
87
  }): Promise<void>;
@@ -53,9 +53,10 @@ function systemDatabaseUrl(config) {
53
53
  * must resolve before the HTTP listener accepts traffic (otherwise the
54
54
  * readiness probe could 200 against a runtime that can't own workflows).
55
55
  */
56
- export async function launchDbos({ config, logger }) {
56
+ export async function launchDbos({ config, logger: injected }) {
57
57
  if (state.launched)
58
58
  return;
59
+ const logger = injected.named("dbos");
59
60
  const executorID = config.executorId;
60
61
  const adminPort = parseInt(config.adminPort, 10);
61
62
  DBOS.setConfig({
@@ -71,12 +72,12 @@ export async function launchDbos({ config, logger }) {
71
72
  await DBOS.launch();
72
73
  state.launched = true;
73
74
  state.recoveryStarted = true;
74
- logger.info({
75
+ logger.info("launched", {
75
76
  executorID,
76
77
  applicationVersion: config.applicationVersion,
77
78
  adminPort,
78
79
  durationMs: Math.round(performance.now() - start),
79
- }, "[dbos] launched");
80
+ });
80
81
  }
81
82
  /**
82
83
  * Shut DBOS down. In-flight workflows are marked recoverable so another
@@ -87,19 +88,20 @@ export async function launchDbos({ config, logger }) {
87
88
  * Must run after HTTP has drained (so no inbound request is orphaned) and
88
89
  * before the application pool closes (DBOS needs the system DB).
89
90
  */
90
- export async function shutdownDbos({ logger }) {
91
+ export async function shutdownDbos({ logger: injected }) {
91
92
  if (!state.launched)
92
93
  return;
94
+ const logger = injected.named("dbos");
93
95
  const start = performance.now();
94
96
  try {
95
97
  await DBOS.shutdown();
96
- logger.info({ durationMs: Math.round(performance.now() - start) }, "[dbos] shutdown");
98
+ logger.info("shutdown", { durationMs: Math.round(performance.now() - start) });
97
99
  }
98
100
  catch (err) {
99
- logger.error({
100
- err: err instanceof Error ? err.message : String(err),
101
+ logger.error("shutdown failed", {
102
+ ...logger.errorFields(err),
101
103
  durationMs: Math.round(performance.now() - start),
102
- }, "[dbos] shutdown failed");
104
+ });
103
105
  }
104
106
  finally {
105
107
  state.launched = false;
@@ -119,7 +121,8 @@ export async function shutdownDbos({ logger }) {
119
121
  * pre-launch timing, and this is the sole module that owns DBOS. The system
120
122
  * DB is the same database as the app pool, so the pool reaches it directly.
121
123
  */
122
- export async function sweepEphemeralWorkflows({ pool, logger, executorId, }) {
124
+ export async function sweepEphemeralWorkflows({ pool, logger: injectedLogger, executorId, }) {
125
+ const logger = injectedLogger.named("dbos");
123
126
  const executorID = executorId;
124
127
  try {
125
128
  const { rowCount } = await pool.query({
@@ -131,7 +134,7 @@ export async function sweepEphemeralWorkflows({ pool, logger, executorId, }) {
131
134
  values: [Date.now(), executorID],
132
135
  });
133
136
  if (rowCount && rowCount > 0) {
134
- logger.info({ executorID, swept: rowCount }, "[dbos] swept orphaned ephemeral workflows");
137
+ logger.info("swept orphaned ephemeral workflows", { executorID, swept: rowCount });
135
138
  }
136
139
  }
137
140
  catch (err) {
@@ -139,7 +142,7 @@ export async function sweepEphemeralWorkflows({ pool, logger, executorId, }) {
139
142
  if (err && typeof err === "object" && "code" in err && err.code === "42P01") {
140
143
  return;
141
144
  }
142
- logger.error({ executorID, err: err instanceof Error ? err.message : String(err) }, "[dbos] ephemeral sweep failed");
145
+ logger.error("ephemeral sweep failed", { executorID, ...logger.errorFields(err) });
143
146
  }
144
147
  }
145
148
  /** Snapshot of DBOS lifecycle state — read by the readiness probe. */
@@ -18,10 +18,10 @@
18
18
  * swallowed — once shutdown has started, exiting takes precedence over
19
19
  * any single step's failure.
20
20
  */
21
- import type pino from "pino";
21
+ import type { Logger } from "../lib/logger.js";
22
22
  export interface ShutdownDeps {
23
23
  signal: string;
24
- logger: pino.Logger;
24
+ logger: Logger;
25
25
  markDraining: () => void;
26
26
  closeHttpServer: () => Promise<void>;
27
27
  shutdownDbos: () => Promise<void>;
@@ -23,12 +23,13 @@ async function safely(logger, step, fn) {
23
23
  await fn();
24
24
  }
25
25
  catch (err) {
26
- logger.error({ err: err instanceof Error ? err.message : String(err), step }, `[shutdown] ${step} failed`);
26
+ logger.error(`${step} failed`, { ...logger.errorFields(err), step });
27
27
  }
28
28
  }
29
29
  export async function runShutdownSequence(deps) {
30
- const { logger, signal } = deps;
31
- logger.info({ signal }, "[shutdown] requested");
30
+ const { signal } = deps;
31
+ const logger = deps.logger.named("shutdown");
32
+ logger.info("requested", { signal });
32
33
  deps.markDraining();
33
34
  await safely(logger, "http-drain", deps.closeHttpServer);
34
35
  await safely(logger, "dbos-shutdown", deps.shutdownDbos);
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import type { V1Toleration } from "@kubernetes/client-node";
15
15
  import type { Pool } from "pg";
16
- import type pino from "pino";
16
+ import type { Logger } from "../lib/logger.js";
17
17
  import { type ResourceLimits } from "../config/resource-limits.js";
18
18
  import { type ResolveWorkspaceRoot } from "../workspace/paths.js";
19
19
  import { clearSandboxRef } from "../state/index.js";
@@ -87,7 +87,7 @@ export interface CreateSandboxClientConfig {
87
87
  * (a configured store whose `current` vanished/went incomplete mid-session) is
88
88
  * observable rather than a silent mount drop. No-op when unset.
89
89
  */
90
- logger?: Pick<pino.Logger, "info" | "warn" | "error">;
90
+ logger?: Logger;
91
91
  /** Dependency seams (fetch, durable step/sleep, clock, recv, warn sink) forwarded to submit/await. */
92
92
  submitDeps?: SubmitExecDeps;
93
93
  awaitOptions?: AwaitExecOptions;
@@ -29,8 +29,8 @@
29
29
  * effective capabilities.
30
30
  */
31
31
  import Docker from "dockerode";
32
- import type pino from "pino";
33
32
  import { ResultAsync } from "neverthrow";
33
+ import type { Logger } from "../lib/logger.js";
34
34
  import { type ResolveWorkspaceRoot } from "../workspace/paths.js";
35
35
  import { type SandboxError } from "./sandbox-error.js";
36
36
  import type { CreateSandboxMeta, ManagedSandbox, SandboxIdentity, SandboxLiveness, SandboxRef, SandboxTransport } from "./types.js";
@@ -62,7 +62,7 @@ export interface DockerClientConfig {
62
62
  * vanished or went incomplete by sandbox-create time) is observable instead of a
63
63
  * silent libs-mount drop. Matches the `reaper`/`watchdog` logger seam.
64
64
  */
65
- logger?: Pick<pino.Logger, "info" | "warn" | "error">;
65
+ logger?: Logger;
66
66
  /** Hook called after the registry row is written. */
67
67
  registerSandbox: (meta: CreateSandboxMeta, ref: SandboxRef) => Promise<void>;
68
68
  }
@@ -32,6 +32,7 @@ import { existsSync, statSync } from "node:fs";
32
32
  import { join } from "node:path";
33
33
  import Docker from "dockerode";
34
34
  import { ResultAsync, err, ok } from "neverthrow";
35
+ import { createNoopLogger } from "../lib/console-logger.js";
35
36
  import { stepWritePrefix } from "../workspace/paths.js";
36
37
  import { trySandbox } from "./sandbox-error.js";
37
38
  import { buildMountPlan } from "./mount-plan.js";
@@ -158,7 +159,9 @@ export function createDockerSandboxOps(config) {
158
159
  // since an otherwise-silent libs-mount drop is invisible to operators.
159
160
  const libsMounted = !!config.libStorePath && libStoreUsable(config.libStorePath);
160
161
  if (config.libStorePath && !libsMounted) {
161
- config.logger?.warn({ libStorePath: config.libStorePath, sandboxId }, "[docker-client] lib store configured but `current` is missing or incomplete at sandbox creation — mounting no library store (sandbox degrades to available:false)");
162
+ (config.logger ?? createNoopLogger())
163
+ .named("docker-client")
164
+ .warn("lib store configured but `current` is missing or incomplete at sandbox creation — mounting no library store (sandbox degrades to available:false)", { libStorePath: config.libStorePath, sandboxId });
162
165
  }
163
166
  const plan = buildMountPlan(meta, {
164
167
  libs: libsMounted,
@@ -16,6 +16,7 @@ import { ResultAsync } from "neverthrow";
16
16
  import type { ResolveWorkspaceRoot } from "../workspace/paths.js";
17
17
  import { type SandboxError } from "./sandbox-error.js";
18
18
  import type { CreateSandboxMeta, ManagedSandbox, SandboxIdentity, SandboxLiveness, SandboxRef, SandboxTransport } from "./types.js";
19
+ import type { Logger } from "../lib/logger.js";
19
20
  /**
20
21
  * Coerce an arbitrary identifier into a valid K8s label value:
21
22
  * ≤63 chars, `[A-Za-z0-9._-]` only, starting and ending alphanumeric.
@@ -27,6 +28,8 @@ import type { CreateSandboxMeta, ManagedSandbox, SandboxIdentity, SandboxLivenes
27
28
  */
28
29
  export declare function sanitizeLabelValue(value: string): string;
29
30
  export interface K8sClientConfig {
31
+ /** Operational logging seam; omitted falls back to no-op. */
32
+ readonly logger?: Logger;
30
33
  image: string;
31
34
  cortexBaseUrl: string;
32
35
  /**
@@ -16,6 +16,7 @@ import { BatchV1Api, CoreV1Api, KubeConfig } from "@kubernetes/client-node";
16
16
  import { ResultAsync, err, ok } from "neverthrow";
17
17
  import { trySandbox } from "./sandbox-error.js";
18
18
  import { buildMountPlan, buildSessionSubPaths } from "./mount-plan.js";
19
+ import { createNoopLogger } from "../lib/console-logger.js";
19
20
  /** Read the originating HTTP status off any `SandboxError` variant that carries one. */
20
21
  function statusOf(e) {
21
22
  return "status" in e ? e.status : undefined;
@@ -410,12 +411,12 @@ export function createK8sSandboxOps(config) {
410
411
  cause,
411
412
  }));
412
413
  if (registered.isErr()) {
413
- await cleanupFailedJob(batchApi, config.namespace, sandboxId);
414
+ await cleanupFailedJob(batchApi, config.namespace, sandboxId, config.logger ?? createNoopLogger());
414
415
  return err(registered.error);
415
416
  }
416
417
  return ok(ref);
417
418
  }
418
- await cleanupFailedJob(batchApi, config.namespace, sandboxId);
419
+ await cleanupFailedJob(batchApi, config.namespace, sandboxId, config.logger ?? createNoopLogger());
419
420
  return err(ready.error);
420
421
  })());
421
422
  },
@@ -480,9 +481,9 @@ export function createK8sSandboxOps(config) {
480
481
  * matters; a delete error here is logged and swallowed so it never masks the
481
482
  * create error returned to the caller.
482
483
  */
483
- async function cleanupFailedJob(batchApi, namespace, sandboxId) {
484
+ async function cleanupFailedJob(batchApi, namespace, sandboxId, logger) {
484
485
  const deleted = await deleteJobIgnoreMissing(batchApi, namespace, sandboxId);
485
486
  if (deleted.isErr()) {
486
- console.error(`K8sSandbox: failed to delete Job ${sandboxId} after startup failure`, deleted.error);
487
+ logger.named("k8s-client").error("failed to delete Job after startup failure", { sandboxId, err: deleted.error });
487
488
  }
488
489
  }
@@ -17,14 +17,14 @@
17
17
  * injectable so tests can drive the sweep against a stub.
18
18
  */
19
19
  import type { Pool } from "pg";
20
- import type pino from "pino";
20
+ import type { Logger } from "../lib/logger.js";
21
21
  export interface SweepDeps {
22
22
  /**
23
23
  * Execute the bounded DELETE. Returns the row count cleared. Injected
24
24
  * for tests; production wires the app pool.
25
25
  */
26
26
  deleteStale: (limit: number) => Promise<number>;
27
- logger?: Pick<pino.Logger, "info" | "warn" | "error">;
27
+ logger?: Logger;
28
28
  }
29
29
  export declare function sweepStaleNotifications(deps: SweepDeps): Promise<number>;
30
30
  /**
@@ -35,7 +35,7 @@ export declare function sweepStaleNotifications(deps: SweepDeps): Promise<number
35
35
  export declare function makeDefaultDeleteStale(pool: Pool): (limit: number) => Promise<number>;
36
36
  export interface RegisterNotificationSweepDeps {
37
37
  pool: Pool;
38
- logger?: Pick<pino.Logger, "info" | "warn" | "error">;
38
+ logger?: Logger;
39
39
  /** Override the DELETE driver — production defaults to the app pool. */
40
40
  deleteStale?: (limit: number) => Promise<number>;
41
41
  }
@@ -17,16 +17,18 @@
17
17
  * injectable so tests can drive the sweep against a stub.
18
18
  */
19
19
  import { DBOS } from "@dbos-inc/dbos-sdk";
20
+ import { createNoopLogger } from "../lib/console-logger.js";
20
21
  const SWEEP_CRON = "0 */5 * * * *";
21
22
  const DELETE_BATCH_LIMIT = 10_000;
22
23
  export async function sweepStaleNotifications(deps) {
24
+ const logger = (deps.logger ?? createNoopLogger()).named("notification-sweep");
23
25
  try {
24
26
  const cleared = await deps.deleteStale(DELETE_BATCH_LIMIT);
25
- deps.logger?.info({ rowsCleared: cleared }, "[notification-sweep] cleared stale notifications");
27
+ logger.info("cleared stale notifications", { rowsCleared: cleared });
26
28
  return cleared;
27
29
  }
28
30
  catch (err) {
29
- deps.logger?.error({ err: err instanceof Error ? err.message : String(err) }, "[notification-sweep] sweep failed");
31
+ logger.error("sweep failed", logger.errorFields(err));
30
32
  throw err;
31
33
  }
32
34
  }
@@ -18,8 +18,8 @@
18
18
  * hoisted for unit testing without a DBOS runtime; `registerSandboxReaper` is
19
19
  * the thin production wiring.
20
20
  */
21
- import type pino from "pino";
22
21
  import type { Pool } from "pg";
22
+ import type { Logger } from "../lib/logger.js";
23
23
  import type { SandboxClient } from "./client.js";
24
24
  import type { ManagedSandbox } from "./types.js";
25
25
  export type ReapDecision = "leave" | "reap";
@@ -46,7 +46,7 @@ export interface ReaperDeps {
46
46
  graceMs?: number;
47
47
  /** Wall-clock ms; injected for tests. */
48
48
  nowMs?: () => number;
49
- logger?: Pick<pino.Logger, "info" | "warn" | "error">;
49
+ logger?: Logger;
50
50
  }
51
51
  export interface ReapSummary {
52
52
  managedCount: number;
@@ -64,7 +64,7 @@ export interface RegisterReaperDeps {
64
64
  pool: Pool;
65
65
  sandboxClient: Pick<SandboxClient, "listManagedSandboxes" | "teardownById">;
66
66
  graceMs?: number;
67
- logger?: Pick<pino.Logger, "info" | "warn" | "error">;
67
+ logger?: Logger;
68
68
  }
69
69
  /** Production registration: a single (unsharded) `@DBOS.scheduled` workflow. */
70
70
  export declare function registerSandboxReaper(deps: RegisterReaperDeps): void;
@@ -19,6 +19,7 @@
19
19
  * the thin production wiring.
20
20
  */
21
21
  import { DBOS } from "@dbos-inc/dbos-sdk";
22
+ import { createNoopLogger } from "../lib/console-logger.js";
22
23
  import { unwrapOrThrow } from "../lib/result.js";
23
24
  import { reconcileReapedSandbox } from "../state/active-sandboxes.js";
24
25
  const REAPER_CRON = "0 */5 * * * *";
@@ -65,6 +66,7 @@ export function terminalStepStatus(workflowStatus) {
65
66
  * failure on one machine is logged and skipped — the next sweep retries.
66
67
  */
67
68
  export async function reapOnce(deps) {
69
+ const logger = (deps.logger ?? createNoopLogger()).named("sandbox-reaper");
68
70
  const nowMs = (deps.nowMs ?? (() => Date.now()))();
69
71
  const graceMs = deps.graceMs ?? DEFAULT_GRACE_MS;
70
72
  const managed = await deps.sandboxClient.listManagedSandboxes();
@@ -85,10 +87,10 @@ export async function reapOnce(deps) {
85
87
  rowsReconciled++;
86
88
  }
87
89
  catch (err) {
88
- deps.logger?.warn({
90
+ logger.warn("reap failed — skipping this round", {
89
91
  sandboxId: sb.sandboxId,
90
- err: err instanceof Error ? err.message : String(err),
91
- }, "[sandbox-reaper] reap failed — skipping this round");
92
+ ...logger.errorFields(err),
93
+ });
92
94
  }
93
95
  }
94
96
  const summary = {
@@ -97,7 +99,8 @@ export async function reapOnce(deps) {
97
99
  rowsReconciled,
98
100
  leftCount,
99
101
  };
100
- deps.logger?.info(summary, "[sandbox-reaper] sweep completed");
102
+ // Spread: an interface has no implicit index signature, so it needs widening to `LogFields`.
103
+ logger.info("sweep completed", { ...summary });
101
104
  return summary;
102
105
  }
103
106
  /** Production registration: a single (unsharded) `@DBOS.scheduled` workflow. */
@@ -18,8 +18,8 @@
18
18
  * without spinning a DBOS runtime; `registerWatchdog` is the thin
19
19
  * production wiring.
20
20
  */
21
- import type pino from "pino";
22
21
  import type { ResultAsync } from "neverthrow";
22
+ import type { Logger } from "../lib/logger.js";
23
23
  import type { DbError } from "../lib/db-result.js";
24
24
  import type { ActiveSandboxRow } from "../state/index.js";
25
25
  import type { SandboxClient } from "./client.js";
@@ -39,7 +39,7 @@ export interface CheckShardDeps {
39
39
  * this is `DBOS.send`; injected here for testability.
40
40
  */
41
41
  sendSynthetic: (workflowId: string, execId: string, failure: ExecResult, reason: string) => Promise<void>;
42
- logger?: Pick<pino.Logger, "info" | "warn" | "error">;
42
+ logger?: Logger;
43
43
  }
44
44
  export interface CheckShardSummary {
45
45
  activeCount: number;
@@ -61,7 +61,7 @@ export interface WatchdogDeps {
61
61
  queryActiveSandboxes: () => ResultAsync<ActiveSandboxRow[], DbError>;
62
62
  sandboxClient: SandboxClient;
63
63
  shardCount?: number;
64
- logger?: Pick<pino.Logger, "info" | "warn" | "error">;
64
+ logger?: Logger;
65
65
  }
66
66
  /**
67
67
  * Production registration. Builds the parent + child registered workflows
@@ -20,6 +20,7 @@
20
20
  */
21
21
  import { createHash } from "node:crypto";
22
22
  import { DBOS } from "@dbos-inc/dbos-sdk";
23
+ import { createNoopLogger } from "../lib/console-logger.js";
23
24
  import { unwrapOrThrow } from "../lib/result.js";
24
25
  import { workflowIdFromExec } from "./exec-id.js";
25
26
  import { syntheticFailureReason, syntheticFailureResult } from "./liveness.js";
@@ -48,6 +49,7 @@ const ACTIVE_WORKFLOW_STATUSES = new Set(["PENDING", "ENQUEUED"]);
48
49
  * notification.
49
50
  */
50
51
  export async function checkShard(rows, deps) {
52
+ const logger = (deps.logger ?? createNoopLogger()).named("sandbox-watchdog");
51
53
  let deadCount = 0;
52
54
  let syntheticSends = 0;
53
55
  let liveWorkflowsSkipped = 0;
@@ -64,7 +66,10 @@ export async function checkShard(rows, deps) {
64
66
  liveness = await deps.isAlive(ref);
65
67
  }
66
68
  catch (err) {
67
- deps.logger?.warn({ sandboxId: row.sandboxRef.sandboxId, err: err instanceof Error ? err.message : String(err) }, "[sandbox-watchdog] isAlive threw — skipping this round");
69
+ logger.warn("isAlive threw — skipping this round", {
70
+ sandboxId: row.sandboxRef.sandboxId,
71
+ ...logger.errorFields(err),
72
+ });
68
73
  continue;
69
74
  }
70
75
  if (liveness.alive)
@@ -92,7 +97,8 @@ export async function checkShard(rows, deps) {
92
97
  syntheticSends,
93
98
  liveWorkflowsSkipped,
94
99
  };
95
- deps.logger?.info(summary, "[sandbox-watchdog] shard check completed");
100
+ // Spread: an interface has no implicit index signature, so it needs widening to `LogFields`.
101
+ logger.info("shard check completed", { ...summary });
96
102
  return summary;
97
103
  }
98
104
  /** Encodes the synthetic-failure marker on the per-exec topic envelope. */
@@ -15,7 +15,7 @@ export const ProfilerFileSchema = z.object({
15
15
  .describe("Semantic data type: count-matrix, normalized-expression, variants, alignments, " +
16
16
  "clinical-metadata, clinical-sdtm, clinical-adam, clinical-response, " +
17
17
  "pharmacokinetic-data, adverse-events, safety-labs, " +
18
- "molecular-structures, annotations"),
18
+ "molecular-structures, annotations, document (paper PDF, README, methods doc)"),
19
19
  format: z.string().describe("File format (e.g. CSV, TSV, h5ad, MTX, VCF, BAM, SDF, FASTQ)"),
20
20
  rows: z.number().nullish(),
21
21
  cols: z.number().nullish(),
@@ -43,7 +43,7 @@ export const OrganismSchema = z.object({
43
43
  source: SubjectSourceEnum,
44
44
  confidence: z
45
45
  .enum(["high", "medium", "low"])
46
- .describe("high: explicit organism column or paper/README statement. " +
46
+ .describe("high: explicit user-context statement, an organism column, or a paper/README statement. " +
47
47
  "medium: filename convention or accession lookup. " +
48
48
  "low: inferred from gene IDs or other indirect signals, OR sources disagree (in which case also record the conflict in qualityAssessment.concerns)."),
49
49
  notes: z.string().optional().describe("Brief note when source is 'inferred' or confidence is 'low' (one sentence)."),
@@ -51,7 +51,9 @@ export const OrganismSchema = z.object({
51
51
  export const ProfilerOutputSchema = z.object({
52
52
  files: z.array(ProfilerFileSchema),
53
53
  analysisSummary: z.string().describe("Narrative overview of the dataset — structure, content, analytical potential, and limitations"),
54
- domain: z.string().describe("Scientific domain (e.g. transcriptomics, proteomics, genomics, chemistry, clinical, imaging, metabolomics, multi-omics)"),
54
+ domain: z
55
+ .string()
56
+ .describe("Scientific domain (e.g. transcriptomics, proteomics, genomics, cheminformatics, clinical, imaging, metabolomics, multi-omics)"),
55
57
  subtype: z.string().optional().describe("Specific subtype within domain (e.g. bulk-rna-seq, single-cell, LC-MS/MS, whole-genome-sequencing)"),
56
58
  organism: OrganismSchema.nullable().describe("Subject organism, identified from any input (metadata files, paper PDFs, READMEs, filenames, accession patterns). " +
57
59
  "Set to null ONLY when no input identifies the organism — never guess. " +