@inflexa-ai/harness 0.12.0 → 0.14.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 (207) hide show
  1. package/dist/agents/conversation-agent.d.ts +9 -15
  2. package/dist/agents/conversation-agent.js +32 -31
  3. package/dist/agents/sandbox/cheminformatics-agent.js +1 -1
  4. package/dist/agents/sandbox/chromatin-agent.js +1 -1
  5. package/dist/agents/sandbox/dna-methylation-agent.js +1 -1
  6. package/dist/agents/sandbox/drug-repurposing-agent.js +5 -10
  7. package/dist/agents/sandbox/enrichment-agent.js +1 -1
  8. package/dist/agents/sandbox/genomic-variant-agent.js +1 -11
  9. package/dist/agents/sandbox/immune-profiling-agent.js +1 -1
  10. package/dist/agents/sandbox/index.js +0 -3
  11. package/dist/agents/sandbox/multi-omics-integration-agent.js +1 -1
  12. package/dist/agents/sandbox/network-agent.js +1 -1
  13. package/dist/agents/sandbox/pkpd-clinical-response-agent.js +3 -6
  14. package/dist/agents/sandbox/scientific-executor.js +1 -1
  15. package/dist/agents/sandbox/shared.d.ts +2 -2
  16. package/dist/agents/sandbox/shared.js +8 -14
  17. package/dist/agents/sandbox/translational-safety-agent.js +4 -7
  18. package/dist/agents/sandbox/types.d.ts +5 -5
  19. package/dist/agents/sandbox/types.js +4 -4
  20. package/dist/app/chat-turn.js +4 -1
  21. package/dist/app/message-assembly.d.ts +5 -2
  22. package/dist/app/message-assembly.js +7 -2
  23. package/dist/app/run-activity.d.ts +13 -0
  24. package/dist/app/run-activity.js +51 -0
  25. package/dist/config/resource-limits.d.ts +0 -7
  26. package/dist/config/resource-limits.js +0 -1
  27. package/dist/contracts/target-dossier.d.ts +10 -10
  28. package/dist/execution/dbos-run-launcher.js +1 -26
  29. package/dist/execution/report-runner.js +1 -1
  30. package/dist/execution/run-authorizer.d.ts +1 -1
  31. package/dist/execution/run-authorizer.js +1 -1
  32. package/dist/execution/run-event-parts.d.ts +44 -0
  33. package/dist/execution/run-event-parts.js +0 -0
  34. package/dist/execution/run-event-stream.d.ts +91 -0
  35. package/dist/execution/run-event-stream.js +212 -0
  36. package/dist/execution/run-launcher.d.ts +2 -18
  37. package/dist/execution/run-launcher.js +2 -4
  38. package/dist/execution/run-synthesis.js +1 -1
  39. package/dist/index.d.ts +7 -4
  40. package/dist/index.js +23 -6
  41. package/dist/input-sanitization.d.ts +14 -4
  42. package/dist/input-sanitization.js +27 -4
  43. package/dist/lib/storage.js +4 -1
  44. package/dist/loop/budget-exceeded.d.ts +18 -2
  45. package/dist/loop/budget-exceeded.js +49 -2
  46. package/dist/loop/run-agent.d.ts +22 -1
  47. package/dist/loop/run-agent.js +51 -5
  48. package/dist/loop/run-to-terminal.d.ts +0 -2
  49. package/dist/loop/run-to-terminal.js +8 -1
  50. package/dist/memory/ai-sdk-message-storage.d.ts +37 -4
  51. package/dist/memory/ai-sdk-message-storage.js +45 -4
  52. package/dist/memory/content-to-cortex.js +19 -3
  53. package/dist/memory/message-backfill.js +1 -1
  54. package/dist/memory/reconstruct-cards.d.ts +1 -1
  55. package/dist/memory/reconstruct-cards.js +7 -5
  56. package/dist/memory/thread-history.js +72 -8
  57. package/dist/prompts/conversation.d.ts +1 -1
  58. package/dist/prompts/conversation.js +41 -15
  59. package/dist/prompts/literature-reviewer.d.ts +1 -1
  60. package/dist/prompts/literature-reviewer.js +16 -14
  61. package/dist/prompts/planner.d.ts +3 -0
  62. package/dist/prompts/planner.js +16 -21
  63. package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
  64. package/dist/prompts/sandbox/drug-repurposing-agent.js +31 -22
  65. package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
  66. package/dist/prompts/sandbox/multi-omics-integration-agent.js +9 -10
  67. package/dist/prompts/sandbox/pkpd-clinical-response-agent.d.ts +1 -1
  68. package/dist/prompts/sandbox/pkpd-clinical-response-agent.js +8 -7
  69. package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
  70. package/dist/prompts/sandbox/translational-safety-agent.js +20 -14
  71. package/dist/prompts/sandbox-standards.d.ts +4 -4
  72. package/dist/prompts/sandbox-standards.js +5 -5
  73. package/dist/prompts/synthesis-agent.d.ts +1 -1
  74. package/dist/prompts/synthesis-agent.js +7 -7
  75. package/dist/providers/errors.d.ts +7 -0
  76. package/dist/providers/errors.js +88 -3
  77. package/dist/runtime/assemble.d.ts +5 -10
  78. package/dist/runtime/assemble.js +0 -4
  79. package/dist/runtime/boot.d.ts +2 -2
  80. package/dist/runtime/boot.js +1 -1
  81. package/dist/runtime/dbos.d.ts +4 -5
  82. package/dist/runtime/dbos.js +6 -7
  83. package/dist/runtime/pools.d.ts +15 -1
  84. package/dist/runtime/pools.js +15 -1
  85. package/dist/sandbox/mount-plan.d.ts +1 -1
  86. package/dist/sandbox/sandbox-error.d.ts +1 -1
  87. package/dist/sandbox/sandbox-error.js +1 -1
  88. package/dist/sandbox/sandbox-step-translate.d.ts +15 -2
  89. package/dist/sandbox/sandbox-step-translate.js +17 -2
  90. package/dist/sandbox/types.d.ts +1 -1
  91. package/dist/schemas/validate-plan.d.ts +1 -1
  92. package/dist/schemas/workflow-state.d.ts +2 -2
  93. package/dist/schemas/workflow-state.js +2 -2
  94. package/dist/state/data-profile.d.ts +53 -1
  95. package/dist/state/data-profile.js +66 -6
  96. package/dist/state/index.d.ts +6 -6
  97. package/dist/state/index.js +4 -4
  98. package/dist/state/init.js +37 -2
  99. package/dist/state/plans.js +1 -1
  100. package/dist/state/runs.d.ts +49 -0
  101. package/dist/state/runs.js +150 -0
  102. package/dist/tasks/data-profile-activity.d.ts +87 -0
  103. package/dist/tasks/data-profile-activity.js +56 -0
  104. package/dist/tasks/data-profile.js +66 -4
  105. package/dist/tools/__fixtures__/tool-context.js +1 -0
  106. package/dist/tools/ad-hoc-router.d.ts +31 -0
  107. package/dist/tools/ad-hoc-router.js +132 -0
  108. package/dist/tools/analysis-invocation.d.ts +4 -0
  109. package/dist/tools/analysis-invocation.js +17 -0
  110. package/dist/tools/bio/chembl.d.ts +1 -1
  111. package/dist/tools/bio/chembl.js +51 -54
  112. package/dist/tools/bio/comptox.js +35 -33
  113. package/dist/tools/bio/drug-gene-interactions.d.ts +76 -0
  114. package/dist/tools/bio/drug-gene-interactions.js +175 -0
  115. package/dist/tools/bio/gene-disease-evidence.d.ts +61 -0
  116. package/dist/tools/bio/gene-disease-evidence.js +187 -0
  117. package/dist/tools/bio/gene-preclinical-profile.d.ts +58 -0
  118. package/dist/tools/bio/gene-preclinical-profile.js +125 -0
  119. package/dist/tools/bio/index.d.ts +23 -16
  120. package/dist/tools/bio/index.js +29 -22
  121. package/dist/tools/bio/keys.d.ts +16 -9
  122. package/dist/tools/bio/keys.js +22 -13
  123. package/dist/tools/bio/lookup-annotation.d.ts +48 -0
  124. package/dist/tools/bio/lookup-annotation.js +173 -0
  125. package/dist/tools/bio/opentargets.d.ts +7 -11
  126. package/dist/tools/bio/opentargets.js +24 -35
  127. package/dist/tools/bio/pubchem.js +6 -4
  128. package/dist/tools/bio/pubmed.d.ts +15 -7
  129. package/dist/tools/bio/pubmed.js +79 -20
  130. package/dist/tools/bio/search-clinical-trials.d.ts +20 -1
  131. package/dist/tools/bio/search-clinical-trials.js +26 -5
  132. package/dist/tools/bio/search-faers.js +9 -3
  133. package/dist/tools/bio/search-gene.d.ts +0 -1
  134. package/dist/tools/bio/search-gene.js +4 -5
  135. package/dist/tools/bio/search-geo-datasets.js +10 -4
  136. package/dist/tools/bio/search-interactions.d.ts +8 -4
  137. package/dist/tools/bio/search-interactions.js +28 -12
  138. package/dist/tools/bio/target-safety.d.ts +59 -0
  139. package/dist/tools/bio/target-safety.js +191 -0
  140. package/dist/tools/define-tool.d.ts +6 -2
  141. package/dist/tools/define-tool.js +1 -1
  142. package/dist/tools/execute-analysis.d.ts +44 -0
  143. package/dist/tools/execute-analysis.js +252 -0
  144. package/dist/tools/iterate-report.js +7 -6
  145. package/dist/tools/lib/dgidb-client.d.ts +49 -0
  146. package/dist/tools/lib/dgidb-client.js +168 -0
  147. package/dist/tools/lib/disgenet-client.d.ts +56 -0
  148. package/dist/tools/lib/disgenet-client.js +59 -0
  149. package/dist/tools/lib/drugbank-client.d.ts +83 -0
  150. package/dist/tools/lib/drugbank-client.js +95 -0
  151. package/dist/tools/lib/ensembl-client.d.ts +4 -1
  152. package/dist/tools/lib/ensembl-client.js +5 -3
  153. package/dist/tools/lib/gwas-catalog-client.d.ts +60 -0
  154. package/dist/tools/lib/gwas-catalog-client.js +136 -0
  155. package/dist/tools/lib/pharmgkb-client.d.ts +22 -0
  156. package/dist/tools/lib/pharmgkb-client.js +32 -0
  157. package/dist/tools/lib/pubmed-client.d.ts +57 -4
  158. package/dist/tools/lib/pubmed-client.js +57 -3
  159. package/dist/tools/lib/string-client.d.ts +25 -4
  160. package/dist/tools/lib/string-client.js +22 -5
  161. package/dist/tools/research/generate-plan.d.ts +16 -9
  162. package/dist/tools/research/generate-plan.js +116 -70
  163. package/dist/tools/research/inspect-data-profile.d.ts +31 -6
  164. package/dist/tools/research/inspect-data-profile.js +23 -7
  165. package/dist/tools/research/inspect-run.d.ts +33 -15
  166. package/dist/tools/research/inspect-run.js +155 -66
  167. package/dist/tools/research/literature-reviewer.js +7 -11
  168. package/dist/workflows/execute-analysis.d.ts +68 -5
  169. package/dist/workflows/execute-analysis.js +76 -7
  170. package/dist/workflows/sandbox-step.js +1 -11
  171. package/dist/workflows/target-assessment/decisions/index.d.ts +1 -1
  172. package/dist/workflows/target-assessment/phase4-assemble.d.ts +1 -1
  173. package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +2 -2
  174. package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +1 -1
  175. package/package.json +1 -1
  176. package/dist/agents/sandbox/ephemeral-executor.d.ts +0 -9
  177. package/dist/agents/sandbox/ephemeral-executor.js +0 -20
  178. package/dist/execution/ephemeral-runner.d.ts +0 -98
  179. package/dist/execution/ephemeral-runner.js +0 -189
  180. package/dist/prompts/sandbox/ephemeral-executor.d.ts +0 -1
  181. package/dist/prompts/sandbox/ephemeral-executor.js +0 -66
  182. package/dist/tools/bio/check-safety-panel.d.ts +0 -35
  183. package/dist/tools/bio/check-safety-panel.js +0 -76
  184. package/dist/tools/bio/get-impc-ko-profile.d.ts +0 -9
  185. package/dist/tools/bio/get-impc-ko-profile.js +0 -23
  186. package/dist/tools/bio/lookup-go-term.d.ts +0 -31
  187. package/dist/tools/bio/lookup-go-term.js +0 -116
  188. package/dist/tools/bio/search-bgee-expression.d.ts +0 -10
  189. package/dist/tools/bio/search-bgee-expression.js +0 -30
  190. package/dist/tools/bio/search-clinvar.d.ts +0 -13
  191. package/dist/tools/bio/search-clinvar.js +0 -28
  192. package/dist/tools/bio/search-dgidb.d.ts +0 -53
  193. package/dist/tools/bio/search-dgidb.js +0 -213
  194. package/dist/tools/bio/search-disgenet.d.ts +0 -30
  195. package/dist/tools/bio/search-disgenet.js +0 -84
  196. package/dist/tools/bio/search-drugbank.d.ts +0 -38
  197. package/dist/tools/bio/search-drugbank.js +0 -109
  198. package/dist/tools/bio/search-gwas-catalog.d.ts +0 -33
  199. package/dist/tools/bio/search-gwas-catalog.js +0 -172
  200. package/dist/tools/bio/search-pathway.d.ts +0 -12
  201. package/dist/tools/bio/search-pathway.js +0 -32
  202. package/dist/tools/bio/search-pharmgkb.d.ts +0 -17
  203. package/dist/tools/bio/search-pharmgkb.js +0 -52
  204. package/dist/tools/execute-plan.d.ts +0 -64
  205. package/dist/tools/execute-plan.js +0 -211
  206. package/dist/tools/run-ephemeral.d.ts +0 -33
  207. package/dist/tools/run-ephemeral.js +0 -65
@@ -11,13 +11,10 @@
11
11
  * The system prompt is static composition — SOUL kernel + SOUL conversational
12
12
  * + the conversation prompt — with no processor pipeline.
13
13
  *
14
- * `executePlan` is wired here — it launches the DBOS `executeAnalysis` parent
14
+ * `execute_analysis` is wired here — it launches the DBOS `executeAnalysis` parent
15
15
  * workflow under `workflowId = runId` (the bare run UUID) through the
16
16
  * `RunLauncher` seam and returns the runId (results are pull-only via
17
- * `inspectRun` on a later turn). `run_ephemeral`
18
- * is wired here too — it mints a run authorization, starts the turn-scoped DBOS
19
- * `ephemeral` workflow, and awaits the result inline; chat disconnect cancels
20
- * the workflow and it is never recovered. Report authoring is wired here as the
17
+ * `inspectRun` on a later turn). Report authoring is wired here as the
21
18
  * pair `plan_report` (returns the report-brief schema + authoring rules
22
19
  * just-in-time as its result) + `submit_report` (validates the composed brief
23
20
  * and drives in-process Nunjucks rendering via the `report-builder` agent, no
@@ -42,7 +39,6 @@ import type { EnvironmentStorePaths } from "../config/environment-stores.js";
42
39
  import type { RunAuthorizer } from "../execution/run-authorizer.js";
43
40
  import type { RunLauncher } from "../execution/run-launcher.js";
44
41
  import { type SubmitReportDeps } from "../tools/iterate-report.js";
45
- import type { EphemeralWorkflowInput, EphemeralResult } from "../execution/ephemeral-runner.js";
46
42
  import type { Logger } from "../lib/logger.js";
47
43
  /** Canonical agent id — the single source of truth. */
48
44
  export declare const CONVERSATION_AGENT_ID: "conversation-agent";
@@ -65,28 +61,26 @@ export interface ConversationAgentDeps extends EnvironmentStorePaths {
65
61
  readonly workspaceFs: WorkspaceFilesystem;
66
62
  /** Model id — provenance / metric label; the provider owns the wire model. */
67
63
  readonly model: string;
64
+ /** Dedicated lower-cost model/provider for ad hoc specialist routing. */
65
+ readonly utilityProvider: ChatProvider;
66
+ readonly utilityModel: string;
68
67
  /**
69
68
  * Registered `executeAnalysis` workflow callable — produced by
70
- * `registerExecuteAnalysis` (wired by `assembleCoreRuntime`). `executePlan`
69
+ * `registerExecuteAnalysis` (wired by `assembleCoreRuntime`). `execute_analysis`
71
70
  * launches it through the `RunLauncher` seam to start the run.
72
71
  */
73
72
  readonly executeAnalysisWorkflow: (input: ExecuteAnalysisInput) => Promise<ExecuteAnalysisResult>;
74
- /**
75
- * Registered `ephemeral` workflow — `run_ephemeral` mints a run authorization,
76
- * starts it, and awaits the result inline within the chat turn.
77
- */
78
- readonly ephemeralWorkflow: (input: EphemeralWorkflowInput) => Promise<EphemeralResult>;
79
73
  /** Workspace-root resolution seam (see workspace/paths.ts). */
80
74
  readonly resolveWorkspaceRoot: ResolveWorkspaceRoot;
81
75
  /**
82
76
  * Async-edge run-authorization seam — injected, not constructed here.
83
- * `execute_plan` and `run_ephemeral` turn the caller's opaque auth into a
77
+ * `execute_analysis` turns the caller's opaque auth into a
84
78
  * durable `RunSession` through it. The managed root injects the platform
85
79
  * realization; the OSS root injects the local one.
86
80
  */
87
81
  readonly runAuthorizer: RunAuthorizer;
88
82
  /**
89
- * Durable-run launch seam — `execute_plan` and `run_ephemeral` start their
83
+ * Durable-run launch seam — `execute_analysis` starts its
90
84
  * workflows through it so the durability engine stays out of the tools.
91
85
  */
92
86
  readonly runLauncher: RunLauncher;
@@ -107,7 +101,7 @@ export interface ConversationAgentDeps extends EnvironmentStorePaths {
107
101
  /**
108
102
  * Host resource policy — per-step ceilings + machine budget. `generate_plan`
109
103
  * states the ceilings to the planner and validates against them;
110
- * `execute_plan` snapshots the budget into the workflow input. Absent,
104
+ * `execute_analysis` snapshots the budget into the workflow input. Absent,
111
105
  * planning guidance and scheduling keep their legacy behavior.
112
106
  */
113
107
  readonly resourcePolicy?: ResourcePolicy;
@@ -11,13 +11,10 @@
11
11
  * The system prompt is static composition — SOUL kernel + SOUL conversational
12
12
  * + the conversation prompt — with no processor pipeline.
13
13
  *
14
- * `executePlan` is wired here — it launches the DBOS `executeAnalysis` parent
14
+ * `execute_analysis` is wired here — it launches the DBOS `executeAnalysis` parent
15
15
  * workflow under `workflowId = runId` (the bare run UUID) through the
16
16
  * `RunLauncher` seam and returns the runId (results are pull-only via
17
- * `inspectRun` on a later turn). `run_ephemeral`
18
- * is wired here too — it mints a run authorization, starts the turn-scoped DBOS
19
- * `ephemeral` workflow, and awaits the result inline; chat disconnect cancels
20
- * the workflow and it is never recovered. Report authoring is wired here as the
17
+ * `inspectRun` on a later turn). Report authoring is wired here as the
21
18
  * pair `plan_report` (returns the report-brief schema + authoring rules
22
19
  * just-in-time as its result) + `submit_report` (validates the composed brief
23
20
  * and drives in-process Nunjucks rendering via the `report-builder` agent, no
@@ -32,7 +29,7 @@ import { createWorkingMemory } from "../memory/working-memory.js";
32
29
  import { conversationPrompt } from "../prompts/conversation.js";
33
30
  import { composeSystemPrompt } from "./system-prompt.js";
34
31
  // Bio-lookup leaf tools (pure — no dependencies).
35
- import { searchGeneTool, searchPathwayTool, lookupGoTermTool, searchInteractionsTool, chemblTool, pubchemTool, openTargetsTool, searchGwasCatalogTool, searchPharmgkbTool, searchFaersTool, searchClinicalTrialsTool, searchGeoDatasetsTool, createSearchDgidbTool, searchBgeeExpressionTool, getImpcKoProfileTool, checkSafetyPanelTool, } from "../tools/bio/index.js";
32
+ import { searchGeneTool, lookupAnnotationTool, searchInteractionsTool, chemblTool, pubchemTool, openTargetsTool, searchFaersTool, searchClinicalTrialsTool, searchGeoDatasetsTool, genePreclinicalProfileTool, targetSafetyTool, } from "../tools/bio/index.js";
36
33
  import { createNcbiTools, createChemDbTools } from "../tools/bio/keys.js";
37
34
  // Dependency-bearing tool factories.
38
35
  import { createGeneratePlanTool, createLiteratureReviewerTool, createInspectRunTool, createInspectDataProfileTool, createGenerateAnalogyReportTool, } from "../tools/research/index.js";
@@ -41,8 +38,7 @@ import { showUserTool } from "../tools/display/index.js";
41
38
  import { createUpdateWorkingMemoryTool } from "../tools/memory/index.js";
42
39
  import { createListAvailablePackagesTool } from "../tools/sandbox/list-available-packages.js";
43
40
  import { createListAvailableRefsTool } from "../tools/sandbox/list-available-refs.js";
44
- import { createExecutePlanTool } from "../tools/execute-plan.js";
45
- import { createRunEphemeralTool } from "../tools/run-ephemeral.js";
41
+ import { createExecuteAnalysisTool } from "../tools/execute-analysis.js";
46
42
  import { planReportTool, createReportSubmitTool } from "../tools/iterate-report.js";
47
43
  /** Canonical agent id — the single source of truth. */
48
44
  export const CONVERSATION_AGENT_ID = "conversation-agent";
@@ -50,15 +46,16 @@ export const CONVERSATION_AGENT_ID = "conversation-agent";
50
46
  const CONVERSATION_MAX_ITERATIONS = 50;
51
47
  /** Build the conversation `AgentDefinition` with every tool fully dep-bound. */
52
48
  export function createConversationAgent(deps) {
53
- const { provider, pool, embedding, workspaceFs, model, executeAnalysisWorkflow, ephemeralWorkflow, resolveWorkspaceRoot, runAuthorizer, runLauncher, createPreviewPublisher, bioKeys, templatesDir, skillsDir, chrome, resourcePolicy, hostTools, refStorePath, packagesFile, } = deps;
49
+ const { provider, pool, embedding, workspaceFs, model, utilityProvider, utilityModel, executeAnalysisWorkflow, resolveWorkspaceRoot, runAuthorizer, runLauncher, createPreviewPublisher, bioKeys, templatesDir, skillsDir, chrome, resourcePolicy, hostTools, refStorePath, packagesFile, } = deps;
54
50
  const workingMemory = createWorkingMemory(pool);
55
51
  const ncbi = createNcbiTools(bioKeys);
56
- const chemDb = createChemDbTools(bioKeys);
52
+ const chemDb = createChemDbTools(bioKeys, { ...(deps.logger ? { logger: deps.logger } : {}) });
57
53
  const tools = [
58
- // Bio-lookup.
54
+ // Identifier resolution — the ENSG most other bio tools key off.
59
55
  searchGeneTool,
60
- searchPathwayTool,
61
- lookupGoTermTool,
56
+ // Functional annotation (GO / KEGG / Reactome behind one vocabulary) and
57
+ // STRING networks + gene-set enrichment.
58
+ lookupAnnotationTool,
62
59
  searchInteractionsTool,
63
60
  // Literature (search / details / fulltext behind one action).
64
61
  ncbi.pubmed,
@@ -66,20 +63,19 @@ export function createConversationAgent(deps) {
66
63
  chemblTool,
67
64
  // PubChem (compound / crossrefs / assays behind one action).
68
65
  pubchemTool,
69
- // Translational medicine.
66
+ // Target assessment: the integrated scored view, then the underlying records.
70
67
  openTargetsTool,
71
- // Genetic evidence — SNP-trait associations for target validation / MR support.
72
- searchGwasCatalogTool,
73
- searchPharmgkbTool,
68
+ // Genetic evidence — GWAS Catalog + DisGeNET + ClinVar behind one `sources`.
69
+ chemDb.geneDiseaseEvidence,
70
+ // Drug↔gene interactions — DGIdb + DrugBank + PharmGKB behind one `sources`.
71
+ chemDb.drugGeneInteractions,
74
72
  searchFaersTool,
75
73
  searchClinicalTrialsTool,
76
74
  searchGeoDatasetsTool,
77
- createSearchDgidbTool({ ...(deps.logger ? { logger: deps.logger } : {}) }),
78
- // Preclinical.
79
- searchBgeeExpressionTool,
80
- getImpcKoProfileTool,
81
- // Off-target liability.
82
- checkSafetyPanelTool,
75
+ // Preclinical — baseline expression + mouse knockout in one call.
76
+ genePreclinicalProfileTool,
77
+ // Target-level safety — the curated panel + Open Targets liabilities.
78
+ targetSafetyTool,
83
79
  // EPA CompTox (toxcast / hazard / chemical / exposure behind one dataset).
84
80
  chemDb.comptox,
85
81
  // What reference data this install actually holds. The conversation agent is
@@ -90,24 +86,29 @@ export function createConversationAgent(deps) {
90
86
  createListAvailableRefsTool({ ...(refStorePath ? { refStorePath } : {}) }),
91
87
  // What is importable inside a sandbox. Reads the same manifest a sandbox agent
92
88
  // reads, host-side — so "is scanpy available?" is a manifest lookup here rather
93
- // than a whole ephemeral container spun up to run one import.
89
+ // than launching analysis computation to run one import.
94
90
  createListAvailablePackagesTool({ ...(packagesFile ? { packagesFile } : {}) }),
95
91
  // Execution.
96
92
  createInspectRunTool(pool),
97
93
  // The dataset's own record. No file backs it — the DB row is the only copy.
98
94
  createInspectDataProfileTool(pool),
99
- createGeneratePlanTool({ provider, pool, model, resourcePolicy, ...(refStorePath ? { refStorePath } : {}), ...(packagesFile ? { packagesFile } : {}) }),
100
- createExecutePlanTool({
95
+ createGeneratePlanTool({
96
+ conversation: { provider, model },
101
97
  pool,
102
- executeAnalysisWorkflow,
103
- runAuthorizer,
104
- runLauncher,
105
98
  resourcePolicy,
99
+ ...(refStorePath ? { refStorePath } : {}),
100
+ ...(packagesFile ? { packagesFile } : {}),
101
+ ...(deps.logger ? { logger: deps.logger } : {}),
106
102
  }),
107
- createRunEphemeralTool({
108
- workflow: ephemeralWorkflow,
103
+ createExecuteAnalysisTool({
104
+ pool,
105
+ executeAnalysisWorkflow,
109
106
  runAuthorizer,
110
107
  runLauncher,
108
+ resourcePolicy,
109
+ utilityProvider,
110
+ utilityModel,
111
+ ...(deps.logger ? { logger: deps.logger } : {}),
111
112
  }),
112
113
  // Report authoring: the always-on `plan_report` trigger delivers the
113
114
  // heavy brief schema + rules just-in-time as its result; `submit_report`
@@ -37,7 +37,7 @@ export const meta = {
37
37
  "perturbation-signatures",
38
38
  ],
39
39
  skills: ["cheminformatics", "shared/omics-general"],
40
- tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "searchPathway", "lookupGoTerm", "searchInteractions", "chembl", "searchDgidb", "pubchem"],
40
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "lookupAnnotation", "searchInteractions", "chembl", "drugGeneInteractions", "pubchem"],
41
41
  };
42
42
  export function createCheminformaticsAgent(deps) {
43
43
  return createSandboxAgent(deps, meta, cheminformaticsAgentPrompt);
@@ -8,7 +8,7 @@ export const meta = {
8
8
  capabilities: ["peak calling", "differential binding", "differential accessibility", "motif analysis", "footprinting", "signal visualization"],
9
9
  suitableFor: ["atac-seq", "chip-seq", "cut-and-tag", "cut-and-run", "scatac-seq"],
10
10
  skills: ["chromatin-regulation", "shared/omics-general"],
11
- tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "searchPathway", "lookupGoTerm", "searchInteractions"],
11
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "lookupAnnotation", "searchInteractions"],
12
12
  };
13
13
  export function createChromatinAgent(deps) {
14
14
  return createSandboxAgent(deps, meta, chromatinAgentPrompt);
@@ -8,7 +8,7 @@ export const meta = {
8
8
  capabilities: ["methylation array analysis", "bisulfite-seq analysis", "DMP detection", "DMR detection", "methylation clocks", "cell type deconvolution"],
9
9
  suitableFor: ["methylation-array", "wgbs", "rrbs", "epic", "450k"],
10
10
  skills: ["dna-methylation", "shared/omics-general"],
11
- tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "searchPathway", "lookupGoTerm", "searchInteractions"],
11
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "lookupAnnotation", "searchInteractions"],
12
12
  };
13
13
  export function createDnaMethylationAgent(deps) {
14
14
  return createSandboxAgent(deps, meta, dnaMethylationAgentPrompt);
@@ -19,23 +19,18 @@ export const meta = {
19
19
  skills: ["drug-repurposing", "cheminformatics", "shared/omics-general"],
20
20
  tools: [
21
21
  ...BASE_SANDBOX_TOOLS,
22
- "checkSafetyPanel",
22
+ "targetSafety",
23
23
  "pubmed",
24
24
  "searchGene",
25
- "searchPathway",
26
- "lookupGoTerm",
25
+ "lookupAnnotation",
27
26
  "searchInteractions",
28
27
  "chembl",
29
28
  "opentargets",
30
29
  "searchClinicalTrials",
31
30
  "searchFaers",
32
- "searchGwasCatalog",
33
- "searchClinvar",
34
- "searchDisgenet",
35
- "searchDrugbank",
36
- "searchDgidb",
37
- "searchBgeeExpression",
38
- "getImpcKoProfile",
31
+ "geneDiseaseEvidence",
32
+ "drugGeneInteractions",
33
+ "genePreclinicalProfile",
39
34
  "comptox",
40
35
  ],
41
36
  };
@@ -8,7 +8,7 @@ export const meta = {
8
8
  capabilities: ["pathway enrichment", "gene set enrichment", "GO analysis", "functional annotation"],
9
9
  suitableFor: ["gene-lists", "ranked-lists", "score-matrices", "general-omics"],
10
10
  skills: ["enrichment", "shared/omics-general"],
11
- tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "searchPathway", "lookupGoTerm", "searchInteractions"],
11
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "lookupAnnotation", "searchInteractions"],
12
12
  };
13
13
  export function createEnrichmentAgent(deps) {
14
14
  return createSandboxAgent(deps, meta, enrichmentAgentPrompt);
@@ -8,17 +8,7 @@ export const meta = {
8
8
  capabilities: ["variant calling", "variant annotation", "GWAS", "CNV detection", "structural variant detection", "variant filtering"],
9
9
  suitableFor: ["wgs", "wes", "gwas", "cnv-sv", "targeted-panels"],
10
10
  skills: ["genomic-variants", "shared/omics-general"],
11
- tools: [
12
- ...BASE_SANDBOX_TOOLS,
13
- "pubmed",
14
- "searchGene",
15
- "searchPathway",
16
- "lookupGoTerm",
17
- "searchInteractions",
18
- "searchClinvar",
19
- "searchDgidb",
20
- "searchGwasCatalog",
21
- ],
11
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "lookupAnnotation", "searchInteractions", "geneDiseaseEvidence", "drugGeneInteractions"],
22
12
  };
23
13
  export function createGenomicVariantAgent(deps) {
24
14
  return createSandboxAgent(deps, meta, genomicVariantAgentPrompt);
@@ -24,7 +24,7 @@ export const meta = {
24
24
  "immune-cell-composition",
25
25
  ],
26
26
  skills: ["immune-profiling", "shared/omics-general"],
27
- tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "searchPathway", "lookupGoTerm", "searchInteractions", "searchGeoDatasets", "opentargets"],
27
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "lookupAnnotation", "searchInteractions", "searchGeoDatasets", "opentargets"],
28
28
  };
29
29
  export function createImmuneProfilingAgent(deps) {
30
30
  return createSandboxAgent(deps, meta, immuneProfilingAgentPrompt);
@@ -18,7 +18,6 @@ import { createDataProfilerAgent, meta as dataProfilerMeta } from "./data-profil
18
18
  import { createDnaMethylationAgent, meta as dnaMethylationMeta } from "./dna-methylation-agent.js";
19
19
  import { createDrugRepurposingAgent, meta as drugRepurposingMeta } from "./drug-repurposing-agent.js";
20
20
  import { createEnrichmentAgent, meta as enrichmentMeta } from "./enrichment-agent.js";
21
- import { createEphemeralExecutorAgent, meta as ephemeralExecutorMeta } from "./ephemeral-executor.js";
22
21
  import { createGenomicVariantAgent, meta as genomicVariantMeta } from "./genomic-variant-agent.js";
23
22
  import { createImmuneProfilingAgent, meta as immuneProfilingMeta } from "./immune-profiling-agent.js";
24
23
  import { createMetabolomicsAgent, meta as metabolomicsMeta } from "./metabolomics-agent.js";
@@ -62,7 +61,6 @@ export const SANDBOX_AGENT_META = {
62
61
  [immuneProfilingMeta.id]: immuneProfilingMeta,
63
62
  [drugRepurposingMeta.id]: drugRepurposingMeta,
64
63
  [scientificExecutorMeta.id]: scientificExecutorMeta,
65
- [ephemeralExecutorMeta.id]: ephemeralExecutorMeta,
66
64
  };
67
65
  /**
68
66
  * Build every sandbox `AgentDefinition` from the shared deps. The returned
@@ -91,6 +89,5 @@ export function createSandboxAgents(deps) {
91
89
  [immuneProfilingMeta.id]: createImmuneProfilingAgent(deps),
92
90
  [drugRepurposingMeta.id]: createDrugRepurposingAgent(deps),
93
91
  [scientificExecutorMeta.id]: createScientificExecutorAgent(deps),
94
- [ephemeralExecutorMeta.id]: createEphemeralExecutorAgent(deps),
95
92
  };
96
93
  }
@@ -15,7 +15,7 @@ export const meta = {
15
15
  ],
16
16
  suitableFor: ["multi-omics", "cross-modality-integration"],
17
17
  skills: ["multi-omics-integration", "shared/omics-general"],
18
- tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "searchPathway", "lookupGoTerm", "searchInteractions", "searchBgeeExpression", "getImpcKoProfile"],
18
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "lookupAnnotation", "searchInteractions", "genePreclinicalProfile"],
19
19
  };
20
20
  export function createMultiOmicsIntegrationAgent(deps) {
21
21
  return createSandboxAgent(deps, meta, multiOmicsIntegrationAgentPrompt);
@@ -8,7 +8,7 @@ export const meta = {
8
8
  capabilities: ["network analysis", "co-expression networks", "regulatory analysis", "module detection", "TF activity inference"],
9
9
  suitableFor: ["expression-matrices", "correlation-matrices", "general-omics"],
10
10
  skills: ["network-regulatory", "shared/omics-general"],
11
- tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "searchPathway", "lookupGoTerm", "searchInteractions"],
11
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "lookupAnnotation", "searchInteractions"],
12
12
  defaultMaxSteps: 35,
13
13
  };
14
14
  export function createNetworkAgent(deps) {
@@ -36,16 +36,13 @@ export const meta = {
36
36
  ...BASE_SANDBOX_TOOLS,
37
37
  "pubmed",
38
38
  "searchGene",
39
- "searchPathway",
40
- "lookupGoTerm",
39
+ "lookupAnnotation",
41
40
  "searchInteractions",
42
41
  "searchClinicalTrials",
43
42
  "searchFaers",
44
- "searchPharmgkb",
43
+ "drugGeneInteractions",
45
44
  "chembl",
46
- "searchDgidb",
47
- "searchBgeeExpression",
48
- "getImpcKoProfile",
45
+ "genePreclinicalProfile",
49
46
  ],
50
47
  };
51
48
  export function createPkpdClinicalResponseAgent(deps) {
@@ -39,7 +39,7 @@ export const meta = {
39
39
  "drug-repurposing",
40
40
  "shared/omics-general",
41
41
  ],
42
- tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "searchPathway", "lookupGoTerm", "searchInteractions"],
42
+ tools: [...BASE_SANDBOX_TOOLS, "pubmed", "searchGene", "lookupAnnotation", "searchInteractions"],
43
43
  plannable: false,
44
44
  };
45
45
  export function createScientificExecutorAgent(deps) {
@@ -78,7 +78,7 @@ export interface SandboxAgentDeps extends EnvironmentStorePaths {
78
78
  * Per-run blocker cell (see the harness-sandbox-agents spec). When present, the agent gets a
79
79
  * `report_blocker` tool that records `{ kind: "blocker", reason }` into it;
80
80
  * the sandbox-step body reads `holder.outcome` after the loop. Omit for
81
- * agents that have no terminal status to declare (ephemeral, data profiler).
81
+ * agents that have no terminal status to declare (such as the data profiler).
82
82
  */
83
83
  readonly blockerHolder?: BlockerHolder;
84
84
  }
@@ -89,7 +89,7 @@ export interface SandboxAgentPromptOptions {
89
89
  /**
90
90
  * Enforced read-only: omit `write_file` + `edit_file` from the workspace
91
91
  * surface. `execute_command` and all read tools stay. Pair with a sandbox
92
- * provisioned with no read-write mount (ephemeral) so no writable location
92
+ * provisioned with no read-write mount so no writable location
93
93
  * exists outside container-local `/tmp`. Defaults to false.
94
94
  */
95
95
  readonly readOnly?: boolean;
@@ -26,7 +26,7 @@ import { createInspectRunTool } from "../../tools/research/inspect-run.js";
26
26
  // Data-profile retrieval (dependency-bearing) — always-on, see `createSandboxAgent`.
27
27
  import { createInspectDataProfileTool } from "../../tools/research/inspect-data-profile.js";
28
28
  // Bio leaf tools.
29
- import { checkSafetyPanelTool, chemblTool, getImpcKoProfileTool, lookupGoTermTool, openTargetsTool, pubchemTool, searchBgeeExpressionTool, searchClinicalTrialsTool, createSearchDgidbTool, searchFaersTool, searchGeneTool, searchGeoDatasetsTool, searchGwasCatalogTool, searchInteractionsTool, searchPathwayTool, searchPharmgkbTool, } from "../../tools/bio/index.js";
29
+ import { chemblTool, genePreclinicalProfileTool, lookupAnnotationTool, openTargetsTool, pubchemTool, searchClinicalTrialsTool, searchFaersTool, searchGeneTool, searchGeoDatasetsTool, searchInteractionsTool, targetSafetyTool, } from "../../tools/bio/index.js";
30
30
  import { createNcbiTools, createChemDbTools } from "../../tools/bio/keys.js";
31
31
  // Workspace read surface.
32
32
  import { createFileStatTool, createGrepTool, createListFilesTool, createReadFileTool, createWorkspaceSearchTool } from "../../tools/workspace/index.js";
@@ -52,7 +52,7 @@ export const BASE_SANDBOX_TOOLS = ["listAvailablePackages", "listAvailableRefs",
52
52
  */
53
53
  function resolveSandboxTools(deps, tools) {
54
54
  const ncbi = createNcbiTools(deps.bioKeys);
55
- const chemDb = createChemDbTools(deps.bioKeys);
55
+ const chemDb = createChemDbTools(deps.bioKeys, { ...(deps.logger ? { logger: deps.logger } : {}) });
56
56
  const registry = {
57
57
  listAvailablePackages: createListAvailablePackagesTool({ ...(deps.packagesFile ? { packagesFile: deps.packagesFile } : {}) }),
58
58
  listAvailableRefs: createListAvailableRefsTool({ ...(deps.refStorePath ? { refStorePath: deps.refStorePath } : {}) }),
@@ -61,24 +61,18 @@ function resolveSandboxTools(deps, tools) {
61
61
  inspectRun: createInspectRunTool(deps.pool),
62
62
  pubmed: ncbi.pubmed,
63
63
  searchGene: searchGeneTool,
64
- searchPathway: searchPathwayTool,
65
- lookupGoTerm: lookupGoTermTool,
64
+ lookupAnnotation: lookupAnnotationTool,
66
65
  searchInteractions: searchInteractionsTool,
67
66
  chembl: chemblTool,
68
67
  pubchem: pubchemTool,
69
68
  opentargets: openTargetsTool,
70
- searchPharmgkb: searchPharmgkbTool,
69
+ geneDiseaseEvidence: chemDb.geneDiseaseEvidence,
70
+ drugGeneInteractions: chemDb.drugGeneInteractions,
71
+ genePreclinicalProfile: genePreclinicalProfileTool,
71
72
  searchFaers: searchFaersTool,
72
73
  searchClinicalTrials: searchClinicalTrialsTool,
73
74
  searchGeoDatasets: searchGeoDatasetsTool,
74
- searchClinvar: ncbi.searchClinvar,
75
- searchDgidb: createSearchDgidbTool({ ...(deps.logger ? { logger: deps.logger } : {}) }),
76
- searchGwasCatalog: searchGwasCatalogTool,
77
- searchDisgenet: chemDb.searchDisgenet,
78
- searchDrugbank: chemDb.searchDrugbank,
79
- searchBgeeExpression: searchBgeeExpressionTool,
80
- getImpcKoProfile: getImpcKoProfileTool,
81
- checkSafetyPanel: checkSafetyPanelTool,
75
+ targetSafety: targetSafetyTool,
82
76
  comptox: chemDb.comptox,
83
77
  };
84
78
  const seen = new Set();
@@ -111,7 +105,7 @@ function buildWorkspaceTools(deps, readOnly) {
111
105
  // writes are confined here. `allowedWritePrefix` is its host path; the
112
106
  // in-sandbox path (the `execute_command` default cwd, see the harness-workspace-tools spec) is the same
113
107
  // location under the `/{analysisId}` mount — derived from the host path so
114
- // it is correct for non-step agents (data profiler, ephemeral) too.
108
+ // it is correct for non-step agents such as the data profiler too.
115
109
  const hostWorkingDir = step.allowedWritePrefix;
116
110
  const sandboxWorkingDir = toSandboxPath(step.workspaceRoot, step.analysisId, hostWorkingDir);
117
111
  const mutateTools = readOnly
@@ -33,19 +33,16 @@ export const meta = {
33
33
  skills: ["translational-safety", "cheminformatics", "shared/omics-general"],
34
34
  tools: [
35
35
  ...BASE_SANDBOX_TOOLS,
36
- "checkSafetyPanel",
36
+ "targetSafety",
37
37
  "pubmed",
38
38
  "searchGene",
39
- "searchPathway",
40
- "lookupGoTerm",
39
+ "lookupAnnotation",
41
40
  "searchInteractions",
42
41
  "opentargets",
43
42
  "searchFaers",
44
- "searchPharmgkb",
45
- "searchDgidb",
43
+ "drugGeneInteractions",
46
44
  "comptox",
47
- "searchBgeeExpression",
48
- "getImpcKoProfile",
45
+ "genePreclinicalProfile",
49
46
  ],
50
47
  };
51
48
  export function createTranslationalSafetyAgent(deps) {
@@ -6,13 +6,13 @@
6
6
  * each name to a concrete `Tool` (pure leaf or fully dep-bound factory
7
7
  * output) — unknown names throw at composition time, not at first LLM call.
8
8
  *
9
- * `searchDisgenet` and `searchDrugbank` require keys (`DISGENET_API_KEY`,
10
- * `DRUGBANK_API_KEY`); without the key the underlying header builder
11
- * throws on first call, which the harness surfaces as a tool `is_error`
12
- * envelope. `searchGwasCatalog` is fully public.
9
+ * `geneDiseaseEvidence`, `drugGeneInteractions` and `comptox` each span several
10
+ * corpora, some of which need a key (`DISGENET_API_KEY`, `DRUGBANK_API_KEY`,
11
+ * `EPA_CCTE_API_KEY`). A missing key degrades that ONE corpus to `unavailable`
12
+ * in the tool's `perSource` report; the rest of the call still answers.
13
13
  */
14
14
  /** Closed allowlist of tools any sandbox agent may declare. */
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";
15
+ export type SandboxToolName = "listAvailablePackages" | "listAvailableRefs" | "resolveLibraryId" | "queryDocs" | "inspectRun" | "pubmed" | "searchGene" | "lookupAnnotation" | "searchInteractions" | "chembl" | "pubchem" | "opentargets" | "geneDiseaseEvidence" | "drugGeneInteractions" | "genePreclinicalProfile" | "searchFaers" | "searchClinicalTrials" | "searchGeoDatasets" | "targetSafety" | "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`. */
@@ -6,10 +6,10 @@
6
6
  * each name to a concrete `Tool` (pure leaf or fully dep-bound factory
7
7
  * output) — unknown names throw at composition time, not at first LLM call.
8
8
  *
9
- * `searchDisgenet` and `searchDrugbank` require keys (`DISGENET_API_KEY`,
10
- * `DRUGBANK_API_KEY`); without the key the underlying header builder
11
- * throws on first call, which the harness surfaces as a tool `is_error`
12
- * envelope. `searchGwasCatalog` is fully public.
9
+ * `geneDiseaseEvidence`, `drugGeneInteractions` and `comptox` each span several
10
+ * corpora, some of which need a key (`DISGENET_API_KEY`, `DRUGBANK_API_KEY`,
11
+ * `EPA_CCTE_API_KEY`). A missing key degrades that ONE corpus to `unavailable`
12
+ * in the tool's `perSource` report; the rest of the call still answers.
13
13
  */
14
14
  /** Default runaway-guard for sandbox agents. */
15
15
  export const SANDBOX_AGENT_DEFAULT_MAX_ITERATIONS = 50;
@@ -17,8 +17,9 @@ import { deriveThreadTitle } from "../memory/derive-thread-title.js";
17
17
  import { createThreadHistory } from "../memory/thread-history.js";
18
18
  import { createThreadStore } from "../memory/thread-store.js";
19
19
  import { createWorkingMemory } from "../memory/working-memory.js";
20
- import { loadAnalysisStatus } from "../state/index.js";
20
+ import { loadAnalysisStatus, queryNonTerminalRunsByAnalysis } from "../state/index.js";
21
21
  import { assembleMessages } from "./message-assembly.js";
22
+ import { renderRunActivity, renderRunActivityUnavailable, RUN_ACTIVITY_DETAIL_LIMIT } from "./run-activity.js";
22
23
  import { createNoopLogger } from "../lib/console-logger.js";
23
24
  /**
24
25
  * Prepare one chat turn: resolve thread ownership, seed the title, load
@@ -53,12 +54,14 @@ export async function prepareChatTurn(deps, params) {
53
54
  logger.warn("title-seed failed (non-fatal)", logger.errorFields(err));
54
55
  }
55
56
  const analysisState = await loadAnalysisStatus(pool, analysisId).unwrapOr(null);
57
+ const runActivityContext = await queryNonTerminalRunsByAnalysis(pool, analysisId, RUN_ACTIVITY_DETAIL_LIMIT).match((activity) => renderRunActivity(activity), () => renderRunActivityUnavailable());
56
58
  const history = createThreadHistory(pool);
57
59
  const { messages, userMessage } = await assembleMessages({
58
60
  threadId,
59
61
  analysisId,
60
62
  userInput,
61
63
  analysisContext: analysisState?.context ?? null,
64
+ runActivityContext,
62
65
  history,
63
66
  workingMemory: createWorkingMemory(pool),
64
67
  });
@@ -5,12 +5,13 @@
5
5
  *
6
6
  * [ ...loadRecent(threadId, budget) ← stable, cacheable prefix
7
7
  * {user: cortex_analysis_state.context}, ← tail
8
+ * {user: runActivityContext}, ← tail
8
9
  * {user: render(workingMemory)}, ← tail
9
10
  * {user: normalizeUnicode(redactSecrets(input))} ] ← tail
10
11
  *
11
12
  * `system + tools + history` is the cacheable prefix — it only extends
12
- * turn-to-turn. Working memory and analysis context go in the **tail** as
13
- * `user` messages: working memory changes every turn, so a system-message
13
+ * turn-to-turn. Run activity, working memory, and analysis context go in the
14
+ * **tail** as `user` messages: they change every turn, so a system-message
14
15
  * placement would bust the Anthropic cache prefix.
15
16
  *
16
17
  * Sanitization (`redactSecrets`, `normalizeUnicode`) is applied **once**, to
@@ -41,6 +42,8 @@ export interface AssembleMessagesArgs {
41
42
  readonly userInput: string;
42
43
  /** `cortex_analysis_state.context`, already read by the route. `null` when absent. */
43
44
  readonly analysisContext: string | null;
45
+ /** Fresh, non-persisted analysis-wide run activity rendered by chat-turn preparation. */
46
+ readonly runActivityContext: string;
44
47
  /** The conversation message store — supplies the history window. */
45
48
  readonly history: ThreadHistory;
46
49
  /** The working-memory store — rendered into the tail. */
@@ -5,12 +5,13 @@
5
5
  *
6
6
  * [ ...loadRecent(threadId, budget) ← stable, cacheable prefix
7
7
  * {user: cortex_analysis_state.context}, ← tail
8
+ * {user: runActivityContext}, ← tail
8
9
  * {user: render(workingMemory)}, ← tail
9
10
  * {user: normalizeUnicode(redactSecrets(input))} ] ← tail
10
11
  *
11
12
  * `system + tools + history` is the cacheable prefix — it only extends
12
- * turn-to-turn. Working memory and analysis context go in the **tail** as
13
- * `user` messages: working memory changes every turn, so a system-message
13
+ * turn-to-turn. Run activity, working memory, and analysis context go in the
14
+ * **tail** as `user` messages: they change every turn, so a system-message
14
15
  * placement would bust the Anthropic cache prefix.
15
16
  *
16
17
  * Sanitization (`redactSecrets`, `normalizeUnicode`) is applied **once**, to
@@ -50,6 +51,10 @@ export async function assembleMessages(args) {
50
51
  content: `[Analysis Context]\n${args.analysisContext}`,
51
52
  });
52
53
  }
54
+ tail.push({
55
+ role: "user",
56
+ content: args.runActivityContext,
57
+ });
53
58
  // Working memory — agent-authored, trusted. Always injected (its rendered
54
59
  // form names the sections even when empty).
55
60
  tail.push({
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Ephemeral conversation-tail projection of non-terminal analysis runs.
3
+ *
4
+ * This is derived operational state, not memory: callers render it afresh for
5
+ * each turn and never persist it to the thread.
6
+ */
7
+ import type { RunPage } from "../state/runs.js";
8
+ /** Maximum detailed run rows paid into every conversation turn. */
9
+ export declare const RUN_ACTIVITY_DETAIL_LIMIT = 20;
10
+ /** Render the bounded run-activity snapshot injected into a conversation tail. */
11
+ export declare function renderRunActivity(activity: RunPage, nowMs?: number): string;
12
+ /** Render an honest degraded state when the activity projection cannot be read. */
13
+ export declare function renderRunActivityUnavailable(): string;