@inflexa-ai/harness 0.1.1 → 0.2.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 (268) hide show
  1. package/dist/agents/conversation-agent.d.ts +12 -11
  2. package/dist/agents/conversation-agent.js +30 -33
  3. package/dist/agents/report-builder.js +2 -1
  4. package/dist/agents/sandbox/bulk-transcriptomics-agent.js +1 -1
  5. package/dist/agents/sandbox/cheminformatics-agent.js +1 -19
  6. package/dist/agents/sandbox/chromatin-agent.js +1 -10
  7. package/dist/agents/sandbox/dna-methylation-agent.js +1 -10
  8. package/dist/agents/sandbox/drug-repurposing-agent.js +4 -14
  9. package/dist/agents/sandbox/enrichment-agent.js +1 -10
  10. package/dist/agents/sandbox/ephemeral-executor.js +1 -10
  11. package/dist/agents/sandbox/genomic-variant-agent.js +1 -3
  12. package/dist/agents/sandbox/immune-profiling-agent.js +1 -13
  13. package/dist/agents/sandbox/metabolomics-agent.js +1 -1
  14. package/dist/agents/sandbox/microbiome-agent.js +1 -1
  15. package/dist/agents/sandbox/multi-omics-integration-agent.js +1 -12
  16. package/dist/agents/sandbox/multimodal-sc-agent.js +1 -1
  17. package/dist/agents/sandbox/network-agent.js +1 -10
  18. package/dist/agents/sandbox/pkpd-clinical-response-agent.js +2 -8
  19. package/dist/agents/sandbox/proteomics-agent.js +1 -1
  20. package/dist/agents/sandbox/scientific-executor.js +1 -10
  21. package/dist/agents/sandbox/shared.d.ts +17 -6
  22. package/dist/agents/sandbox/shared.js +49 -38
  23. package/dist/agents/sandbox/single-cell-agent.js +1 -1
  24. package/dist/agents/sandbox/spatial-omics-agent.js +1 -1
  25. package/dist/agents/sandbox/statistical-modeling-agent.js +1 -1
  26. package/dist/agents/sandbox/translational-safety-agent.js +3 -9
  27. package/dist/agents/sandbox/types.d.ts +1 -1
  28. package/dist/agents/system-prompt.d.ts +37 -11
  29. package/dist/agents/system-prompt.js +35 -12
  30. package/dist/app/data-profile-orientation.d.ts +34 -0
  31. package/dist/app/data-profile-orientation.js +117 -0
  32. package/dist/contracts/schemas/chat-parts.d.ts +9 -9
  33. package/dist/execution/artifact-metadata.js +2 -1
  34. package/dist/execution/ephemeral-runner.d.ts +13 -0
  35. package/dist/execution/ephemeral-runner.js +23 -1
  36. package/dist/execution/run-synthesis.js +20 -19
  37. package/dist/execution/step-summary.js +2 -1
  38. package/dist/index.d.ts +6 -2
  39. package/dist/index.js +19 -5
  40. package/dist/loop/__fixtures__/scripted-provider.d.ts +2 -2
  41. package/dist/loop/__fixtures__/scripted-provider.js +2 -1
  42. package/dist/loop/metrics.d.ts +33 -1
  43. package/dist/loop/metrics.js +56 -2
  44. package/dist/loop/run-agent.d.ts +13 -1
  45. package/dist/loop/run-agent.js +19 -4
  46. package/dist/memory/card-builders.d.ts +8 -1
  47. package/dist/memory/card-builders.js +20 -3
  48. package/dist/memory/reconstruct-cards.js +4 -3
  49. package/dist/memory/thread-history.d.ts +27 -2
  50. package/dist/memory/thread-history.js +45 -5
  51. package/dist/memory/working-memory.d.ts +93 -10
  52. package/dist/memory/working-memory.js +220 -84
  53. package/dist/prompts/SOUL.d.ts +22 -9
  54. package/dist/prompts/SOUL.js +56 -37
  55. package/dist/prompts/analogical-reasoner.d.ts +1 -1
  56. package/dist/prompts/analogical-reasoner.js +2 -2
  57. package/dist/prompts/briefing.d.ts +100 -0
  58. package/dist/prompts/briefing.js +166 -0
  59. package/dist/prompts/conversation.d.ts +1 -1
  60. package/dist/prompts/conversation.js +94 -440
  61. package/dist/prompts/literature-reviewer.d.ts +1 -1
  62. package/dist/prompts/literature-reviewer.js +10 -10
  63. package/dist/prompts/planner.js +28 -59
  64. package/dist/prompts/report-builder.d.ts +1 -1
  65. package/dist/prompts/report-builder.js +71 -24
  66. package/dist/prompts/sandbox/bulk-transcriptomics-agent.d.ts +1 -1
  67. package/dist/prompts/sandbox/bulk-transcriptomics-agent.js +2 -7
  68. package/dist/prompts/sandbox/cheminformatics-agent.d.ts +1 -1
  69. package/dist/prompts/sandbox/cheminformatics-agent.js +11 -15
  70. package/dist/prompts/sandbox/chromatin-agent.d.ts +1 -1
  71. package/dist/prompts/sandbox/chromatin-agent.js +3 -7
  72. package/dist/prompts/sandbox/data-profiler.d.ts +1 -1
  73. package/dist/prompts/sandbox/data-profiler.js +13 -8
  74. package/dist/prompts/sandbox/dna-methylation-agent.d.ts +1 -1
  75. package/dist/prompts/sandbox/dna-methylation-agent.js +2 -7
  76. package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
  77. package/dist/prompts/sandbox/drug-repurposing-agent.js +15 -16
  78. package/dist/prompts/sandbox/enrichment-agent.d.ts +1 -1
  79. package/dist/prompts/sandbox/enrichment-agent.js +2 -9
  80. package/dist/prompts/sandbox/genomic-variant-agent.d.ts +1 -1
  81. package/dist/prompts/sandbox/genomic-variant-agent.js +2 -6
  82. package/dist/prompts/sandbox/immune-profiling-agent.d.ts +1 -1
  83. package/dist/prompts/sandbox/immune-profiling-agent.js +3 -8
  84. package/dist/prompts/sandbox/metabolomics-agent.d.ts +1 -1
  85. package/dist/prompts/sandbox/metabolomics-agent.js +1 -7
  86. package/dist/prompts/sandbox/microbiome-agent.d.ts +1 -1
  87. package/dist/prompts/sandbox/microbiome-agent.js +2 -7
  88. package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
  89. package/dist/prompts/sandbox/multi-omics-integration-agent.js +2 -8
  90. package/dist/prompts/sandbox/multimodal-sc-agent.d.ts +1 -1
  91. package/dist/prompts/sandbox/multimodal-sc-agent.js +2 -7
  92. package/dist/prompts/sandbox/network-agent.d.ts +1 -1
  93. package/dist/prompts/sandbox/network-agent.js +2 -7
  94. package/dist/prompts/sandbox/proteomics-agent.d.ts +1 -1
  95. package/dist/prompts/sandbox/proteomics-agent.js +2 -9
  96. package/dist/prompts/sandbox/single-cell-agent.d.ts +1 -1
  97. package/dist/prompts/sandbox/single-cell-agent.js +2 -9
  98. package/dist/prompts/sandbox/spatial-omics-agent.d.ts +1 -1
  99. package/dist/prompts/sandbox/spatial-omics-agent.js +3 -6
  100. package/dist/prompts/sandbox/statistical-modeling-agent.d.ts +1 -1
  101. package/dist/prompts/sandbox/statistical-modeling-agent.js +2 -7
  102. package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
  103. package/dist/prompts/sandbox/translational-safety-agent.js +13 -14
  104. package/dist/prompts/sandbox-standards.d.ts +22 -14
  105. package/dist/prompts/sandbox-standards.js +91 -71
  106. package/dist/prompts/synthesis-agent.d.ts +1 -1
  107. package/dist/prompts/synthesis-agent.js +33 -131
  108. package/dist/provenance/collector.js +1 -1
  109. package/dist/providers/ai-sdk.js +31 -4
  110. package/dist/providers/prompt-cache.d.ts +74 -0
  111. package/dist/providers/prompt-cache.js +77 -0
  112. package/dist/providers/types.d.ts +33 -0
  113. package/dist/reference-data/catalog.d.ts +131 -0
  114. package/dist/reference-data/catalog.js +348 -0
  115. package/dist/reference-data/receipt.d.ts +41 -0
  116. package/dist/reference-data/receipt.js +40 -0
  117. package/dist/schemas/data-profile-schemas.js +5 -3
  118. package/dist/schemas/plan-schemas.d.ts +21 -21
  119. package/dist/schemas/plan-schemas.js +9 -3
  120. package/dist/schemas/run-synthesis.d.ts +8 -4
  121. package/dist/schemas/run-synthesis.js +92 -56
  122. package/dist/schemas/validate-plan.js +1 -1
  123. package/dist/schemas/workflow-state.d.ts +7 -1
  124. package/dist/schemas/workflow-state.js +33 -19
  125. package/dist/state/artifacts.d.ts +13 -0
  126. package/dist/state/artifacts.js +27 -0
  127. package/dist/state/data-profile.d.ts +64 -5
  128. package/dist/state/index.d.ts +3 -3
  129. package/dist/state/index.js +1 -1
  130. package/dist/tasks/data-profile.d.ts +20 -2
  131. package/dist/tasks/data-profile.js +71 -22
  132. package/dist/tools/bio/chembl.d.ts +38 -0
  133. package/dist/tools/bio/chembl.js +138 -0
  134. package/dist/tools/bio/comptox.d.ts +50 -0
  135. package/dist/tools/bio/comptox.js +149 -0
  136. package/dist/tools/bio/get-impc-ko-profile.js +9 -6
  137. package/dist/tools/bio/index.d.ts +5 -17
  138. package/dist/tools/bio/index.js +5 -17
  139. package/dist/tools/bio/keys.d.ts +14 -9
  140. package/dist/tools/bio/keys.js +16 -16
  141. package/dist/tools/bio/opentargets.d.ts +38 -0
  142. package/dist/tools/bio/opentargets.js +89 -0
  143. package/dist/tools/bio/pubchem.d.ts +29 -0
  144. package/dist/tools/bio/pubchem.js +92 -0
  145. package/dist/tools/bio/pubmed.d.ts +51 -0
  146. package/dist/tools/bio/pubmed.js +100 -0
  147. package/dist/tools/bio/search-bgee-expression.js +12 -6
  148. package/dist/tools/bio/search-clinical-trials.js +16 -5
  149. package/dist/tools/bio/search-faers.js +8 -4
  150. package/dist/tools/bio/search-geo-datasets.js +20 -6
  151. package/dist/tools/bio/search-gwas-catalog.d.ts +1 -1
  152. package/dist/tools/bio/search-pharmgkb.js +10 -4
  153. package/dist/tools/display/index.d.ts +1 -0
  154. package/dist/tools/display/index.js +1 -0
  155. package/dist/tools/display/normalize-echart-spec.d.ts +61 -0
  156. package/dist/tools/display/normalize-echart-spec.js +211 -0
  157. package/dist/tools/display/show-user.d.ts +6 -1
  158. package/dist/tools/display/show-user.js +25 -12
  159. package/dist/tools/execute-plan.js +5 -2
  160. package/dist/tools/iterate-report.d.ts +168 -118
  161. package/dist/tools/iterate-report.js +334 -96
  162. package/dist/tools/lib/chembl-client.d.ts +12 -0
  163. package/dist/tools/lib/chembl-client.js +127 -0
  164. package/dist/tools/lib/ctx-ops.d.ts +224 -0
  165. package/dist/tools/lib/ctx-ops.js +450 -0
  166. package/dist/tools/lib/iuphar-client.js +10 -1
  167. package/dist/tools/lib/openfda-client.js +11 -3
  168. package/dist/tools/lib/pathway-client.js +10 -4
  169. package/dist/tools/lib/pubchem-ops.d.ts +74 -0
  170. package/dist/tools/lib/pubchem-ops.js +224 -0
  171. package/dist/tools/memory/update-working-memory.d.ts +45 -7
  172. package/dist/tools/memory/update-working-memory.js +111 -41
  173. package/dist/tools/report/index.d.ts +3 -2
  174. package/dist/tools/report/index.js +3 -2
  175. package/dist/tools/research/generate-analogy-report.js +25 -12
  176. package/dist/tools/research/generate-plan.d.ts +12 -5
  177. package/dist/tools/research/generate-plan.js +168 -37
  178. package/dist/tools/research/index.d.ts +1 -0
  179. package/dist/tools/research/index.js +1 -0
  180. package/dist/tools/research/inspect-data-profile.d.ts +85 -0
  181. package/dist/tools/research/inspect-data-profile.js +161 -0
  182. package/dist/tools/research/literature-reviewer.js +3 -4
  183. package/dist/tools/sandbox/list-available-packages.d.ts +79 -5
  184. package/dist/tools/sandbox/list-available-packages.js +152 -10
  185. package/dist/tools/sandbox/list-available-refs.d.ts +141 -5
  186. package/dist/tools/sandbox/list-available-refs.js +647 -134
  187. package/dist/tools/sandbox/report-blocker.d.ts +39 -9
  188. package/dist/tools/sandbox/report-blocker.js +43 -20
  189. package/dist/tools/workspace/read-file.js +4 -5
  190. package/dist/tools/workspace/run-exec.d.ts +4 -4
  191. package/dist/tools/workspace/run-exec.js +4 -4
  192. package/dist/tools/workspace/show-file.js +10 -6
  193. package/dist/tools/workspace/show-plan.js +12 -6
  194. package/dist/tools/workspace/workspace-search.d.ts +1 -1
  195. package/dist/tools/workspace/workspace-search.js +11 -5
  196. package/dist/workflows/execute-analysis.d.ts +43 -4
  197. package/dist/workflows/execute-analysis.js +107 -6
  198. package/dist/workflows/target-assessment/lib/citation-validator.js +2 -2
  199. package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.js +2 -1
  200. package/dist/workspace/paths.d.ts +2 -2
  201. package/dist/workspace/paths.js +2 -2
  202. package/package.json +33 -33
  203. package/dist/execution/filesystem-artifact-registry.d.ts +0 -57
  204. package/dist/execution/filesystem-artifact-registry.js +0 -92
  205. package/dist/lib/identifiers.d.ts +0 -8
  206. package/dist/lib/identifiers.js +0 -10
  207. package/dist/lib/mime-detect.d.ts +0 -17
  208. package/dist/lib/mime-detect.js +0 -29
  209. package/dist/lib/streamed-download.d.ts +0 -28
  210. package/dist/lib/streamed-download.js +0 -111
  211. package/dist/lib/trace-context.d.ts +0 -11
  212. package/dist/lib/trace-context.js +0 -49
  213. package/dist/providers/llm-capabilities.d.ts +0 -33
  214. package/dist/providers/llm-capabilities.js +0 -58
  215. package/dist/schemas/render-step-prompt.d.ts +0 -32
  216. package/dist/schemas/render-step-prompt.js +0 -76
  217. package/dist/tools/bio/find-approval-precedent.d.ts +0 -32
  218. package/dist/tools/bio/find-approval-precedent.js +0 -72
  219. package/dist/tools/bio/get-article-details.d.ts +0 -11
  220. package/dist/tools/bio/get-article-details.js +0 -20
  221. package/dist/tools/bio/get-article-full-text.d.ts +0 -19
  222. package/dist/tools/bio/get-article-full-text.js +0 -32
  223. package/dist/tools/bio/get-bioactivity.d.ts +0 -11
  224. package/dist/tools/bio/get-bioactivity.js +0 -23
  225. package/dist/tools/bio/get-drug-info.d.ts +0 -9
  226. package/dist/tools/bio/get-drug-info.js +0 -22
  227. package/dist/tools/bio/get-mechanism.d.ts +0 -8
  228. package/dist/tools/bio/get-mechanism.js +0 -18
  229. package/dist/tools/bio/get-pubchem-assays.d.ts +0 -22
  230. package/dist/tools/bio/get-pubchem-assays.js +0 -107
  231. package/dist/tools/bio/get-pubchem-cross-refs.d.ts +0 -15
  232. package/dist/tools/bio/get-pubchem-cross-refs.js +0 -68
  233. package/dist/tools/bio/get-target-safety.d.ts +0 -18
  234. package/dist/tools/bio/get-target-safety.js +0 -26
  235. package/dist/tools/bio/search-compounds.d.ts +0 -22
  236. package/dist/tools/bio/search-compounds.js +0 -160
  237. package/dist/tools/bio/search-ctx-chemical.d.ts +0 -50
  238. package/dist/tools/bio/search-ctx-chemical.js +0 -130
  239. package/dist/tools/bio/search-ctx-exposure.d.ts +0 -55
  240. package/dist/tools/bio/search-ctx-exposure.js +0 -176
  241. package/dist/tools/bio/search-ctx-hazard.d.ts +0 -111
  242. package/dist/tools/bio/search-ctx-hazard.js +0 -178
  243. package/dist/tools/bio/search-opentargets.d.ts +0 -11
  244. package/dist/tools/bio/search-opentargets.js +0 -25
  245. package/dist/tools/bio/search-pubchem-compound.d.ts +0 -26
  246. package/dist/tools/bio/search-pubchem-compound.js +0 -110
  247. package/dist/tools/bio/search-pubmed.d.ts +0 -17
  248. package/dist/tools/bio/search-pubmed.js +0 -31
  249. package/dist/tools/bio/search-targets.d.ts +0 -9
  250. package/dist/tools/bio/search-targets.js +0 -20
  251. package/dist/tools/bio/search-toxcast.d.ts +0 -36
  252. package/dist/tools/bio/search-toxcast.js +0 -141
  253. package/dist/workflows/register-workflows.d.ts +0 -51
  254. package/dist/workflows/register-workflows.js +0 -48
  255. package/dist/workflows/resume-execute-analysis.d.ts +0 -70
  256. package/dist/workflows/resume-execute-analysis.js +0 -80
  257. package/dist/workflows/target-assessment/correction-loop.d.ts +0 -45
  258. package/dist/workflows/target-assessment/correction-loop.js +0 -62
  259. package/dist/workflows/target-assessment/steps/phase0-resolve.d.ts +0 -71
  260. package/dist/workflows/target-assessment/steps/phase0-resolve.js +0 -21
  261. package/dist/workflows/target-assessment/steps/phase1-aggregate.d.ts +0 -1018
  262. package/dist/workflows/target-assessment/steps/phase1-aggregate.js +0 -25
  263. package/dist/workspace/mount-strategy.d.ts +0 -50
  264. package/dist/workspace/mount-strategy.js +0 -67
  265. package/dist/workspace/provenance-collector.d.ts +0 -34
  266. package/dist/workspace/provenance-collector.js +0 -16
  267. package/dist/workspace/workspace-paths.d.ts +0 -26
  268. package/dist/workspace/workspace-paths.js +0 -31
@@ -8,8 +8,8 @@
8
8
  * the workspace mutate trio (`execute_command`, `write_file`, `edit_file`)
9
9
  * bound to the shared `SandboxClient` and the step's `allowedWritePrefix`,
10
10
  * the workspace read tools (`read_file`, `grep`) over the shared
11
- * `WorkspaceFilesystem`, and the bio/literature/context7/run-inspection
12
- * tools its `meta.tools` allowlist names.
11
+ * `WorkspaceFilesystem`, `inspect_data_profile` over the shared `Pool`, and the
12
+ * bio/literature/context7/run-inspection tools its `meta.tools` allowlist names.
13
13
  *
14
14
  * Tool resolution is a single registry lookup — every name in `meta.tools`
15
15
  * must map to a concrete `Tool`; unknown names throw at composition time
@@ -18,13 +18,15 @@
18
18
  import { sandboxOrientCorePrompt, sandboxAnalysisStepStandardsPrompt } from "../../prompts/sandbox-standards.js";
19
19
  import { composeSystemPrompt } from "../system-prompt.js";
20
20
  // Sandbox-environment introspection.
21
- import { listAvailablePackagesTool, listAvailableRefsTool } from "../../tools/sandbox/index.js";
21
+ import { createListAvailableRefsTool, listAvailablePackagesTool } from "../../tools/sandbox/index.js";
22
22
  // Context7 docs (pure leaves).
23
23
  import { queryDocsTool, resolveLibraryIdTool } from "../../tools/research/context7-docs.js";
24
24
  // Run-inspection (dependency-bearing).
25
25
  import { createInspectRunTool } from "../../tools/research/inspect-run.js";
26
+ // Data-profile retrieval (dependency-bearing) — always-on, see `createSandboxAgent`.
27
+ import { createInspectDataProfileTool } from "../../tools/research/inspect-data-profile.js";
26
28
  // Bio leaf tools.
27
- import { checkSafetyPanelTool, getBioactivityTool, getDrugInfoTool, getImpcKoProfileTool, getMechanismTool, getPubchemAssaysTool, getPubchemCrossRefsTool, getTargetSafetyTool, lookupGoTermTool, searchBgeeExpressionTool, searchClinicalTrialsTool, searchCompoundsTool, searchDgidbTool, searchFaersTool, searchGeneTool, searchGeoDatasetsTool, searchGwasCatalogTool, searchInteractionsTool, searchOpenTargetsTool, searchPathwayTool, searchPharmgkbTool, searchPubchemCompoundTool, searchTargetsTool, } from "../../tools/bio/index.js";
29
+ import { checkSafetyPanelTool, chemblTool, getImpcKoProfileTool, lookupGoTermTool, openTargetsTool, pubchemTool, searchBgeeExpressionTool, searchClinicalTrialsTool, searchDgidbTool, searchFaersTool, searchGeneTool, searchGeoDatasetsTool, searchGwasCatalogTool, searchInteractionsTool, searchPathwayTool, searchPharmgkbTool, } from "../../tools/bio/index.js";
28
30
  import { createNcbiTools, createChemDbTools } from "../../tools/bio/keys.js";
29
31
  // Workspace read surface.
30
32
  import { createFileStatTool, createGrepTool, createListFilesTool, createReadFileTool, createWorkspaceSearchTool } from "../../tools/workspace/index.js";
@@ -44,36 +46,35 @@ import { SANDBOX_AGENT_DEFAULT_MAX_ITERATIONS } from "./types.js";
44
46
  */
45
47
  export const BASE_SANDBOX_TOOLS = ["listAvailablePackages", "listAvailableRefs", "resolveLibraryId", "queryDocs", "inspectRun"];
46
48
  /**
47
- * Resolve `meta.tools` into the bio/research tools record. Workspace
48
- * read/mutate tools are added by `createSandboxAgent` regardless of meta
49
- * — they are the always-on substrate, not in the allowlist.
49
+ * Resolve `meta.tools` into the bio/research tools record. The workspace
50
+ * read/mutate tools and `inspect_data_profile` are added by `createSandboxAgent`
51
+ * regardless of meta — they are the always-on substrate, not in the allowlist.
50
52
  */
51
53
  function resolveSandboxTools(deps, tools) {
52
54
  const ncbi = createNcbiTools(deps.bioKeys);
53
55
  const chemDb = createChemDbTools(deps.bioKeys);
54
56
  const registry = {
55
57
  listAvailablePackages: listAvailablePackagesTool,
56
- listAvailableRefs: listAvailableRefsTool,
58
+ listAvailableRefs: createListAvailableRefsTool({
59
+ sandboxClient: deps.sandboxClient,
60
+ sandbox: deps.step.sandbox,
61
+ workflowId: deps.step.workflowId,
62
+ stepId: deps.step.stepId,
63
+ nextFunctionId: deps.step.nextFunctionId,
64
+ deadlineMs: deps.step.deadlineMs,
65
+ markExecActive: createMarkExecActive(deps),
66
+ }),
57
67
  resolveLibraryId: resolveLibraryIdTool,
58
68
  queryDocs: queryDocsTool,
59
69
  inspectRun: createInspectRunTool(deps.pool),
60
- searchPubMed: ncbi.searchPubMed,
61
- getArticleDetails: ncbi.getArticleDetails,
62
- getArticleFullText: ncbi.getArticleFullText,
70
+ pubmed: ncbi.pubmed,
63
71
  searchGene: searchGeneTool,
64
72
  searchPathway: searchPathwayTool,
65
73
  lookupGoTerm: lookupGoTermTool,
66
74
  searchInteractions: searchInteractionsTool,
67
- searchCompounds: searchCompoundsTool,
68
- getBioactivity: getBioactivityTool,
69
- searchTargets: searchTargetsTool,
70
- getMechanism: getMechanismTool,
71
- getDrugInfo: getDrugInfoTool,
72
- searchPubchemCompound: searchPubchemCompoundTool,
73
- getPubchemCrossRefs: getPubchemCrossRefsTool,
74
- getPubchemAssays: getPubchemAssaysTool,
75
- searchOpenTargets: searchOpenTargetsTool,
76
- getTargetSafety: getTargetSafetyTool,
75
+ chembl: chemblTool,
76
+ pubchem: pubchemTool,
77
+ opentargets: openTargetsTool,
77
78
  searchPharmgkb: searchPharmgkbTool,
78
79
  searchFaers: searchFaersTool,
79
80
  searchClinicalTrials: searchClinicalTrialsTool,
@@ -86,10 +87,7 @@ function resolveSandboxTools(deps, tools) {
86
87
  searchBgeeExpression: searchBgeeExpressionTool,
87
88
  getImpcKoProfile: getImpcKoProfileTool,
88
89
  checkSafetyPanel: checkSafetyPanelTool,
89
- searchToxcast: chemDb.searchToxcast,
90
- searchCtxHazard: chemDb.searchCtxHazard,
91
- searchCtxChemical: chemDb.searchCtxChemical,
92
- searchCtxExposure: chemDb.searchCtxExposure,
90
+ comptox: chemDb.comptox,
93
91
  };
94
92
  const seen = new Set();
95
93
  const resolved = [];
@@ -105,6 +103,9 @@ function resolveSandboxTools(deps, tools) {
105
103
  }
106
104
  return resolved;
107
105
  }
106
+ function createMarkExecActive(deps) {
107
+ return (execId) => setActiveExecId(deps.pool, deps.step.runId, deps.step.stepId, execId).match(() => { }, () => { });
108
+ }
108
109
  /** Build the workspace mutate + read tools every sandbox agent receives. In
109
110
  * `readOnly` mode the write_file/edit_file pair is omitted; execute_command
110
111
  * and the read tools stay. */
@@ -113,7 +114,7 @@ function buildWorkspaceTools(deps, readOnly) {
113
114
  // Registry tagging is a best-effort watchdog backstop (`run-exec.ts` already
114
115
  // swallows a throw here); fold a `DbError` into a no-op so a registry write
115
116
  // failure neither fails the exec nor surfaces as an unhandled rejection.
116
- const markExecActive = (execId) => setActiveExecId(pool, step.runId, step.stepId, execId).match(() => { }, () => { });
117
+ const markExecActive = createMarkExecActive(deps);
117
118
  // The agent's writable working directory: relative paths resolve here, and
118
119
  // writes are confined here. `allowedWritePrefix` is its host path; the
119
120
  // in-sandbox path (the `execute_command` default cwd, see the harness-workspace-tools spec) is the same
@@ -161,26 +162,36 @@ function buildWorkspaceTools(deps, readOnly) {
161
162
  }
162
163
  /**
163
164
  * Build one sandbox `AgentDefinition`. The system prompt is composed once
164
- * (SOUL kernel + agent body + sandbox standards) — no processors, no
165
- * conversational layer (sandbox agents are not user-facing). Tools are
166
- * resolved against the closed allowlist; the workspace surface is always
167
- * wired regardless of meta.
165
+ * (SOUL execution core + agent body + sandbox standards) — no processors, and
166
+ * neither human-facing SOUL layer: a sandbox agent is headless, so the identity
167
+ * and conversational layers are dead weight in its context while every hard
168
+ * guardrail it does need rides in the execution core. Tools are resolved
169
+ * against the closed allowlist; the workspace surface is always wired
170
+ * regardless of meta.
171
+ *
172
+ * The composed `systemPrompt` is a **pure function of the agent type** — nothing
173
+ * from `deps.step` reaches it, so two steps of one run, and two runs of one
174
+ * analysis, send a byte-identical ~20k-char prefix that the provider's prompt
175
+ * cache can actually reuse. Keep it that way: a single interpolated id or path
176
+ * makes every step's prefix unique again, and each step pays a full cache write
177
+ * and reads nothing back. Per-step values belong in the step's briefing (its
178
+ * first user message — see `prompts/briefing.ts`), which names the working
179
+ * directory, the analysis root, the dataset, and what each dependency produced.
168
180
  */
169
181
  export function createSandboxAgent(deps, meta, body, opts = {}) {
170
182
  const appendStandards = opts.appendAnalysisStepStandards ?? true;
171
183
  const sandboxLayer = appendStandards ? [sandboxOrientCorePrompt, sandboxAnalysisStepStandardsPrompt] : [sandboxOrientCorePrompt];
172
184
  const agentBody = [body, ...sandboxLayer].map((s) => s.trim()).join("\n\n");
173
- // Substitute the concrete in-sandbox paths the agent sees so the orient-core
174
- // path model is accurate per step (see the harness-workspace-tools spec), not boilerplate prose.
175
- const analysisRoot = `/${deps.step.analysisId}`;
176
- const workingDir = toSandboxPath(deps.step.workspaceRoot, deps.step.analysisId, deps.step.allowedWritePrefix);
177
- const resolvedBody = agentBody.split("{{WORKING_DIR}}").join(workingDir).split("{{ANALYSIS_ROOT}}").join(analysisRoot);
178
- const systemPrompt = composeSystemPrompt(resolvedBody, {
179
- includeConversationalStyle: false,
180
- });
185
+ const systemPrompt = composeSystemPrompt(agentBody);
181
186
  const skillTools = deps.skillsDir ? Object.values(createSkillTools({ skillsDir: deps.skillsDir, skills: meta.skills })) : [];
182
187
  const tools = [
183
188
  ...buildWorkspaceTools(deps, opts.readOnly ?? false),
189
+ // Always-on, not in the `meta.tools` allowlist: the data profile is the only
190
+ // record of what the analysis's input dataset IS, and no file carries it (the
191
+ // profiler's scratch tree is deleted on completion). An agent that cannot pull
192
+ // it has no fallback but to re-derive organism, dimensions, and format from the
193
+ // raw bytes — so every sandbox agent gets it, whatever its meta declares.
194
+ createInspectDataProfileTool(deps.pool),
184
195
  ...skillTools,
185
196
  ...resolveSandboxTools(deps, meta.tools),
186
197
  ...(deps.blockerHolder ? [createReportBlockerTool(deps.blockerHolder)] : []),
@@ -18,7 +18,7 @@ export const meta = {
18
18
  ],
19
19
  suitableFor: ["scrna-seq", "snrna-seq", "cytof", "mass-cytometry"],
20
20
  skills: ["single-cell", "shared/omics-general"],
21
- tools: [...BASE_SANDBOX_TOOLS, "searchPubMed", "getArticleDetails", "getArticleFullText", "searchGeoDatasets"],
21
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGeoDatasets"],
22
22
  };
23
23
  export function createSingleCellAgent(deps) {
24
24
  return createSandboxAgent(deps, meta, singleCellAgentPrompt);
@@ -8,7 +8,7 @@ export const meta = {
8
8
  capabilities: ["spatial statistics", "spatial domain detection", "deconvolution", "niche analysis", "spatial autocorrelation", "ligand-receptor spatial"],
9
9
  suitableFor: ["visium", "merfish", "slide-seq", "codex", "xenium", "mibi", "imc"],
10
10
  skills: ["spatial-omics", "shared/omics-general"],
11
- tools: [...BASE_SANDBOX_TOOLS, "searchPubMed", "getArticleDetails", "getArticleFullText", "searchGeoDatasets"],
11
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGeoDatasets"],
12
12
  };
13
13
  export function createSpatialOmicsAgent(deps) {
14
14
  return createSandboxAgent(deps, meta, spatialOmicsAgentPrompt);
@@ -30,7 +30,7 @@ export const meta = {
30
30
  "patient-stratification",
31
31
  ],
32
32
  skills: ["statistical-modeling", "shared/omics-general"],
33
- tools: [...BASE_SANDBOX_TOOLS, "searchPubMed", "getArticleDetails", "getArticleFullText"],
33
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed"],
34
34
  };
35
35
  export function createStatisticalModelingAgent(deps) {
36
36
  return createSandboxAgent(deps, meta, statisticalModelingAgentPrompt);
@@ -34,22 +34,16 @@ export const meta = {
34
34
  tools: [
35
35
  ...BASE_SANDBOX_TOOLS,
36
36
  "checkSafetyPanel",
37
- "searchPubMed",
38
- "getArticleDetails",
39
- "getArticleFullText",
37
+ "pubmed",
40
38
  "searchGene",
41
39
  "searchPathway",
42
40
  "lookupGoTerm",
43
41
  "searchInteractions",
44
- "searchOpenTargets",
45
- "getTargetSafety",
42
+ "opentargets",
46
43
  "searchFaers",
47
44
  "searchPharmgkb",
48
45
  "searchDgidb",
49
- "searchToxcast",
50
- "searchCtxHazard",
51
- "searchCtxChemical",
52
- "searchCtxExposure",
46
+ "comptox",
53
47
  "searchBgeeExpression",
54
48
  "getImpcKoProfile",
55
49
  ],
@@ -12,7 +12,7 @@
12
12
  * envelope. `searchGwasCatalog` is fully public.
13
13
  */
14
14
  /** Closed allowlist of tools any sandbox agent may declare. */
15
- export type SandboxToolName = "listAvailablePackages" | "listAvailableRefs" | "resolveLibraryId" | "queryDocs" | "inspectRun" | "searchPubMed" | "getArticleDetails" | "getArticleFullText" | "searchGene" | "searchPathway" | "lookupGoTerm" | "searchInteractions" | "searchCompounds" | "getBioactivity" | "searchTargets" | "getMechanism" | "getDrugInfo" | "searchPubchemCompound" | "getPubchemCrossRefs" | "getPubchemAssays" | "searchOpenTargets" | "getTargetSafety" | "searchPharmgkb" | "searchFaers" | "searchClinicalTrials" | "searchGeoDatasets" | "searchClinvar" | "searchDgidb" | "searchGwasCatalog" | "searchDisgenet" | "searchDrugbank" | "searchBgeeExpression" | "getImpcKoProfile" | "checkSafetyPanel" | "searchToxcast" | "searchCtxHazard" | "searchCtxChemical" | "searchCtxExposure";
15
+ export type SandboxToolName = "listAvailablePackages" | "listAvailableRefs" | "resolveLibraryId" | "queryDocs" | "inspectRun" | "pubmed" | "searchGene" | "searchPathway" | "lookupGoTerm" | "searchInteractions" | "chembl" | "pubchem" | "opentargets" | "searchPharmgkb" | "searchFaers" | "searchClinicalTrials" | "searchGeoDatasets" | "searchClinvar" | "searchDgidb" | "searchGwasCatalog" | "searchDisgenet" | "searchDrugbank" | "searchBgeeExpression" | "getImpcKoProfile" | "checkSafetyPanel" | "comptox";
16
16
  /** Planner-facing metadata + tool allowlist for one sandbox agent. */
17
17
  export interface AgentMeta {
18
18
  /** Stable agent id — also the key in the catalog and the `AgentDefinition.id`. */
@@ -2,24 +2,50 @@
2
2
  * Harness system-prompt composition.
3
3
  *
4
4
  * SOUL is static text — there is no processor pipeline. `composeSystemPrompt`
5
- * concatenates the SOUL kernel, the optional SOUL conversational layer, and an
6
- * agent's own prompt into the single `AgentDefinition.systemPrompt` string the
7
- * loop sends as the cacheable prefix.
5
+ * concatenates the SOUL layers an agent declares with the agent's own prompt
6
+ * into the single `AgentDefinition.systemPrompt` string the loop sends as the
7
+ * cacheable prefix. It is the only place SOUL is applied, and every agent is
8
+ * built through it — an unguarded agent is not constructible.
8
9
  *
9
- * `includeConversationalStyle` toggles the conversational block: the
10
- * user-facing conversation agent keeps it; internal tool-only specialists
11
- * (planner, run-synthesizer) and sandbox agents omit it — their tight tool
12
- * loops compete with conversational discipline.
10
+ * The layer policy:
11
+ *
12
+ * - `SOULExecutionCore` is **always** included; there is no opt-out. The
13
+ * scientific stance and the hard guardrails (never fabricate, never oversell,
14
+ * never hide uncertainty, confidentiality, prompt-injection defense) bind a
15
+ * headless agent exactly as they bind the user-facing one. The run
16
+ * synthesizer and the report builder author user-facing scientific claims
17
+ * without a human in their loop — they are the last agents that should be
18
+ * free to fabricate.
19
+ *
20
+ * - `identity` (default `false`) adds `SOULIdentity` — the Inflexa name, the
21
+ * scope, and the human-facing refusal / impersonation / external-action
22
+ * guardrails. Only the conversation agent faces a human, so only it opts in.
23
+ *
24
+ * - `conversational` (default `false`) adds `SOULConversationalPrompt` —
25
+ * personality, response policy, and the 7-step reasoning cadence. Conversation
26
+ * agent only: a tool-only specialist's tight loop competes with conversational
27
+ * discipline.
28
+ *
29
+ * Both flags default off, so the zero-argument call yields a fully guarded
30
+ * headless agent — the safe default is also the shortest one to write.
13
31
  */
14
32
  export interface ComposeSystemPromptOptions {
33
+ /**
34
+ * Include the SOUL identity layer (name, scope, refusal of harmful
35
+ * requests, impersonation and external-action guardrails). Default `false`
36
+ * — opt in only for an agent a human talks to.
37
+ */
38
+ readonly identity?: boolean;
15
39
  /**
16
40
  * Include the SOUL conversational layer (personality, response policy,
17
- * 7-step reasoning). Default `true` — opt out for internal specialists.
41
+ * 7-step reasoning). Default `false` — opt in only for the conversation
42
+ * agent.
18
43
  */
19
- readonly includeConversationalStyle?: boolean;
44
+ readonly conversational?: boolean;
20
45
  }
21
46
  /**
22
- * Compose an agent's full system prompt: SOUL kernel, the optional SOUL
23
- * conversational layer, then the agent's own prompt — joined by blank lines.
47
+ * Compose an agent's full system prompt: the always-on SOUL execution core, the
48
+ * layers the agent opted into, then the agent's own prompt — joined by blank
49
+ * lines.
24
50
  */
25
51
  export declare function composeSystemPrompt(agentPrompt: string, options?: ComposeSystemPromptOptions): string;
@@ -2,22 +2,45 @@
2
2
  * Harness system-prompt composition.
3
3
  *
4
4
  * SOUL is static text — there is no processor pipeline. `composeSystemPrompt`
5
- * concatenates the SOUL kernel, the optional SOUL conversational layer, and an
6
- * agent's own prompt into the single `AgentDefinition.systemPrompt` string the
7
- * loop sends as the cacheable prefix.
5
+ * concatenates the SOUL layers an agent declares with the agent's own prompt
6
+ * into the single `AgentDefinition.systemPrompt` string the loop sends as the
7
+ * cacheable prefix. It is the only place SOUL is applied, and every agent is
8
+ * built through it — an unguarded agent is not constructible.
8
9
  *
9
- * `includeConversationalStyle` toggles the conversational block: the
10
- * user-facing conversation agent keeps it; internal tool-only specialists
11
- * (planner, run-synthesizer) and sandbox agents omit it — their tight tool
12
- * loops compete with conversational discipline.
10
+ * The layer policy:
11
+ *
12
+ * - `SOULExecutionCore` is **always** included; there is no opt-out. The
13
+ * scientific stance and the hard guardrails (never fabricate, never oversell,
14
+ * never hide uncertainty, confidentiality, prompt-injection defense) bind a
15
+ * headless agent exactly as they bind the user-facing one. The run
16
+ * synthesizer and the report builder author user-facing scientific claims
17
+ * without a human in their loop — they are the last agents that should be
18
+ * free to fabricate.
19
+ *
20
+ * - `identity` (default `false`) adds `SOULIdentity` — the Inflexa name, the
21
+ * scope, and the human-facing refusal / impersonation / external-action
22
+ * guardrails. Only the conversation agent faces a human, so only it opts in.
23
+ *
24
+ * - `conversational` (default `false`) adds `SOULConversationalPrompt` —
25
+ * personality, response policy, and the 7-step reasoning cadence. Conversation
26
+ * agent only: a tool-only specialist's tight loop competes with conversational
27
+ * discipline.
28
+ *
29
+ * Both flags default off, so the zero-argument call yields a fully guarded
30
+ * headless agent — the safe default is also the shortest one to write.
13
31
  */
14
- import { SOULKernelPrompt, SOULConversationalPrompt } from "../prompts/SOUL.js";
32
+ import { SOULExecutionCore, SOULIdentity, SOULConversationalPrompt } from "../prompts/SOUL.js";
15
33
  /**
16
- * Compose an agent's full system prompt: SOUL kernel, the optional SOUL
17
- * conversational layer, then the agent's own prompt — joined by blank lines.
34
+ * Compose an agent's full system prompt: the always-on SOUL execution core, the
35
+ * layers the agent opted into, then the agent's own prompt — joined by blank
36
+ * lines.
18
37
  */
19
38
  export function composeSystemPrompt(agentPrompt, options = {}) {
20
- const includeConversational = options.includeConversationalStyle ?? true;
21
- const sections = includeConversational ? [SOULKernelPrompt, SOULConversationalPrompt, agentPrompt] : [SOULKernelPrompt, agentPrompt];
39
+ const sections = [SOULExecutionCore];
40
+ if (options.identity ?? false)
41
+ sections.push(SOULIdentity);
42
+ if (options.conversational ?? false)
43
+ sections.push(SOULConversationalPrompt);
44
+ sections.push(agentPrompt);
22
45
  return sections.map((s) => s.trim()).join("\n\n");
23
46
  }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Data-profile orientation — the bounded projection of a persisted
3
+ * `DataProfileResult` into the few hundred characters an agent needs to know
4
+ * WHAT DATASET IT IS HOLDING before it does anything else.
5
+ *
6
+ * The persisted profile is deliberately rich (per-file metrics, warnings, tags,
7
+ * the full narrative summary) because the DB row is its only durable home — the
8
+ * profiler's scratch tree is deleted on completion. That richness is right for a
9
+ * pull-on-demand tool (`inspect_data_profile`) and wrong for anything injected
10
+ * unconditionally into a context window, which is what a step seed does. This is
11
+ * the lossy half of that pair: a hard character budget, a fixed field order, and
12
+ * visible truncation counts, so an agent that needs more knows to go pull it.
13
+ *
14
+ * A pure function over the record — no I/O, no LLM, no pipeline. It is the whole
15
+ * mechanism.
16
+ */
17
+ import type { DataProfileResult } from "../state/data-profile.js";
18
+ /** The character budget the projection guarantees it will not exceed. */
19
+ export declare const DATA_PROFILE_ORIENTATION_MAX_CHARS = 1200;
20
+ /**
21
+ * Project a persisted profile into an orientation blurb of at most `maxChars`
22
+ * characters. The bound is a guarantee, not a target: the assembled text is
23
+ * hard-clamped, so no profile — however verbose — can blow a caller's budget.
24
+ *
25
+ * Field order is fixed and reflects what an agent must know first: what the
26
+ * dataset IS, how it was designed, what is wrong with it, then what files carry
27
+ * it. Both list sections state their true total, so an elided tail is visible
28
+ * rather than silent.
29
+ *
30
+ * A snapshot written before the record was widened carries none of the structured
31
+ * fields. Rather than emit a bare file list, that case falls back to the narrative
32
+ * summary — the one orientation a legacy row does have.
33
+ */
34
+ export declare function buildDataProfileOrientation(result: DataProfileResult, maxChars?: number): string;
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Data-profile orientation — the bounded projection of a persisted
3
+ * `DataProfileResult` into the few hundred characters an agent needs to know
4
+ * WHAT DATASET IT IS HOLDING before it does anything else.
5
+ *
6
+ * The persisted profile is deliberately rich (per-file metrics, warnings, tags,
7
+ * the full narrative summary) because the DB row is its only durable home — the
8
+ * profiler's scratch tree is deleted on completion. That richness is right for a
9
+ * pull-on-demand tool (`inspect_data_profile`) and wrong for anything injected
10
+ * unconditionally into a context window, which is what a step seed does. This is
11
+ * the lossy half of that pair: a hard character budget, a fixed field order, and
12
+ * visible truncation counts, so an agent that needs more knows to go pull it.
13
+ *
14
+ * A pure function over the record — no I/O, no LLM, no pipeline. It is the whole
15
+ * mechanism.
16
+ */
17
+ /** The character budget the projection guarantees it will not exceed. */
18
+ export const DATA_PROFILE_ORIENTATION_MAX_CHARS = 1200;
19
+ /** Files listed before the tail is elided (the count still reports the total). */
20
+ const MAX_FILES = 8;
21
+ /** Quality concerns listed — the profiler orders them, so these are the top ones. */
22
+ const MAX_CONCERNS = 3;
23
+ const MAX_DESIGN_CHARS = 200;
24
+ const MAX_CONCERN_CHARS = 120;
25
+ const MAX_FILE_DESCRIPTION_CHARS = 100;
26
+ const MAX_SUMMARY_FALLBACK_CHARS = 300;
27
+ /**
28
+ * Clamp to `max` chars, marking any elision with an ellipsis. Whitespace is left
29
+ * alone, so the assembled line structure survives the final bound.
30
+ */
31
+ function clamp(text, max) {
32
+ if (text.length <= max)
33
+ return text;
34
+ if (max <= 1)
35
+ return "";
36
+ return text.slice(0, max - 1).trimEnd() + "…";
37
+ }
38
+ /**
39
+ * Collapse a free-text field to one line and clamp it. Profiler prose (a summary, a
40
+ * design note, a file description) may contain newlines; folding them out is what
41
+ * keeps one record on one line.
42
+ */
43
+ function clip(text, max) {
44
+ return clamp(text.replace(/\s+/g, " ").trim(), max);
45
+ }
46
+ /** Non-empty, whitespace-collapsed value, or `undefined` — nulls and blanks read the same. */
47
+ function present(value) {
48
+ const flat = value?.replace(/\s+/g, " ").trim();
49
+ return flat ? flat : undefined;
50
+ }
51
+ /** `Homo sapiens (taxon 9606)`, plus a confidence marker when the profiler was unsure. */
52
+ function formatOrganism(organism) {
53
+ if (!organism)
54
+ return undefined;
55
+ const name = present(organism.scientificName);
56
+ if (!name)
57
+ return undefined;
58
+ const taxon = present(organism.taxonId);
59
+ const qualifier = organism.confidence === "high" ? "" : ` [${organism.confidence} confidence]`;
60
+ return taxon ? `${name} (taxon ${taxon})${qualifier}` : `${name}${qualifier}`;
61
+ }
62
+ /** `(20000 x 24, CSV)` — whichever of dimensions / format the profiler recorded. */
63
+ function formatFileFacts(file) {
64
+ const dims = typeof file.rows === "number" && typeof file.cols === "number" ? `${file.rows} x ${file.cols}` : undefined;
65
+ const facts = [dims, present(file.format)].filter((f) => f !== undefined);
66
+ return facts.length > 0 ? ` (${facts.join(", ")})` : "";
67
+ }
68
+ /**
69
+ * Project a persisted profile into an orientation blurb of at most `maxChars`
70
+ * characters. The bound is a guarantee, not a target: the assembled text is
71
+ * hard-clamped, so no profile — however verbose — can blow a caller's budget.
72
+ *
73
+ * Field order is fixed and reflects what an agent must know first: what the
74
+ * dataset IS, how it was designed, what is wrong with it, then what files carry
75
+ * it. Both list sections state their true total, so an elided tail is visible
76
+ * rather than silent.
77
+ *
78
+ * A snapshot written before the record was widened carries none of the structured
79
+ * fields. Rather than emit a bare file list, that case falls back to the narrative
80
+ * summary — the one orientation a legacy row does have.
81
+ */
82
+ export function buildDataProfileOrientation(result, maxChars = DATA_PROFILE_ORIENTATION_MAX_CHARS) {
83
+ const lines = [];
84
+ const identity = [
85
+ [present(result.domain), present(result.subtype)].filter((f) => f !== undefined).join(" / ") || undefined,
86
+ formatOrganism(result.organism),
87
+ present(result.tissue) ? `tissue: ${present(result.tissue)}` : undefined,
88
+ present(result.cellType) ? `cells: ${present(result.cellType)}` : undefined,
89
+ present(result.condition) ? `condition: ${present(result.condition)}` : undefined,
90
+ ].filter((f) => f !== undefined);
91
+ if (identity.length > 0) {
92
+ lines.push(`Dataset: ${identity.join(" — ")}`);
93
+ }
94
+ else {
95
+ // A legacy snapshot has no structured identity at all; the summary is the
96
+ // only orientation it carries, so it stands in for the whole header.
97
+ lines.push(`Dataset: ${clip(result.summary, MAX_SUMMARY_FALLBACK_CHARS)}`);
98
+ }
99
+ const design = present(result.experimentalDesign);
100
+ if (design)
101
+ lines.push(`Design: ${clip(design, MAX_DESIGN_CHARS)}`);
102
+ const concerns = (result.qualityAssessment?.concerns ?? []).map((c) => present(c)).filter((c) => c !== undefined);
103
+ if (concerns.length > 0) {
104
+ const shown = concerns.slice(0, MAX_CONCERNS).map((c) => clip(c, MAX_CONCERN_CHARS));
105
+ const more = concerns.length > shown.length ? ` (+${concerns.length - shown.length} more)` : "";
106
+ lines.push(`Concerns: ${shown.join("; ")}${more}`);
107
+ }
108
+ if (result.files.length > 0) {
109
+ const shown = result.files.slice(0, MAX_FILES);
110
+ const header = shown.length < result.files.length ? `Files (${shown.length} of ${result.files.length}):` : `Files (${result.files.length}):`;
111
+ lines.push(header);
112
+ for (const file of shown) {
113
+ lines.push(`- ${file.path} — ${clip(file.description, MAX_FILE_DESCRIPTION_CHARS)}${formatFileFacts(file)}`);
114
+ }
115
+ }
116
+ return clamp(lines.join("\n"), maxChars);
117
+ }
@@ -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>>;
@@ -26,6 +26,7 @@ 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";
31
32
  /** Sub-agent identity for the describer loop — provenance only. */
@@ -166,7 +167,7 @@ export async function generateFileMetadata(opts) {
166
167
  }
167
168
  const describer = {
168
169
  id: DESCRIBER_AGENT_ID,
169
- systemPrompt: SYSTEM_PROMPT,
170
+ systemPrompt: composeSystemPrompt(SYSTEM_PROMPT),
170
171
  model: opts.modelId,
171
172
  tools,
172
173
  maxIterations: opts.maxIterations ?? DEFAULT_MAX_ITERATIONS,