@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
@@ -1,7 +1,81 @@
1
1
  /**
2
- * listAvailablePackages — list R/Python/CLI packages available in the sandbox.
2
+ * listAvailablePackages — query the R/Python/CLI/Node packages available in the
3
+ * sandbox.
4
+ *
5
+ * The data source is `/mnt/libs/current/packages.txt`, assembled by the
6
+ * library-store build (see the lib-store-build spec). Its shape is fixed by the
7
+ * producers (`scripts/lib-store-common.sh`, `images/sandbox-python/inflexa-libs-refresh`):
8
+ * two `#` advisory lines, then one `## <Section>` heading per language track
9
+ * followed by that track's packages as a single comma-separated line.
10
+ *
11
+ * # Available packages in the sandbox environment.
12
+ * # Do NOT attempt to install packages — ...
13
+ *
14
+ * ## R (CRAN)
15
+ * Seurat, dplyr, ggplot2, ...
16
+ *
17
+ * ## Python (pip)
18
+ * anndata, scanpy, ...
19
+ *
20
+ * The file carries **names only — there are no version strings in it**, so this
21
+ * tool reports presence and language track and cannot report a version.
3
22
  */
4
- export declare const listAvailablePackagesTool: import("../define-tool.js").Tool<Record<string, never>, {
5
- available: boolean;
6
- content: string;
7
- }>;
23
+ /** One language track of the store, in `packages.txt` section order. */
24
+ export interface Section {
25
+ /** The section heading verbatim, e.g. `R (CRAN)`, `Python (pip)`. */
26
+ readonly title: string;
27
+ readonly packages: readonly string[];
28
+ }
29
+ /** One `names` lookup: present + canonical spelling + track, or absent. */
30
+ export type CheckedPackage = {
31
+ readonly requested: string;
32
+ readonly present: true;
33
+ readonly name: string;
34
+ readonly section: string;
35
+ } | {
36
+ readonly requested: string;
37
+ readonly present: false;
38
+ };
39
+ /**
40
+ * Three shapes, one per call path: the store is unmounted; a `names` presence
41
+ * check; a (possibly filtered) listing bounded by `limit`, whose `total` and
42
+ * `hasMore` make truncation explicit.
43
+ */
44
+ export type PackagesResult = {
45
+ readonly available: false;
46
+ readonly content: string;
47
+ } | {
48
+ readonly available: true;
49
+ readonly checked: readonly CheckedPackage[];
50
+ } | {
51
+ readonly available: true;
52
+ readonly total: number;
53
+ readonly returned: number;
54
+ readonly hasMore: boolean;
55
+ readonly content: string;
56
+ };
57
+ /**
58
+ * Parse `packages.txt` into its sections. `#` lines are the advisory header,
59
+ * `## X` opens a section, and every other non-empty line contributes
60
+ * comma-separated package names to the open section. Unknown section headings
61
+ * are preserved as-is — a downstream image may add its own track.
62
+ */
63
+ export declare function parsePackagesFile(content: string): Section[];
64
+ /** The tool's input, as parsed from `inputSchema`. */
65
+ export interface PackagesQuery {
66
+ readonly names?: readonly string[];
67
+ readonly query?: string;
68
+ readonly language?: "r" | "python" | "cli" | "node";
69
+ readonly limit?: number;
70
+ }
71
+ /**
72
+ * Answer a packages query against a parsed catalog. Pure — the tool's `execute`
73
+ * is only the file read plus this call.
74
+ */
75
+ export declare function queryPackages(sections: readonly Section[], { names, query, language, limit }: PackagesQuery): PackagesResult;
76
+ export declare const listAvailablePackagesTool: import("../define-tool.js").Tool<{
77
+ names?: string[] | undefined;
78
+ query?: string | undefined;
79
+ language?: "r" | "python" | "cli" | "node" | undefined;
80
+ limit?: number | undefined;
81
+ }, PackagesResult>;
@@ -1,27 +1,169 @@
1
1
  /**
2
- * listAvailablePackages — list R/Python/CLI packages available in the sandbox.
2
+ * listAvailablePackages — query the R/Python/CLI/Node packages available in the
3
+ * sandbox.
4
+ *
5
+ * The data source is `/mnt/libs/current/packages.txt`, assembled by the
6
+ * library-store build (see the lib-store-build spec). Its shape is fixed by the
7
+ * producers (`scripts/lib-store-common.sh`, `images/sandbox-python/inflexa-libs-refresh`):
8
+ * two `#` advisory lines, then one `## <Section>` heading per language track
9
+ * followed by that track's packages as a single comma-separated line.
10
+ *
11
+ * # Available packages in the sandbox environment.
12
+ * # Do NOT attempt to install packages — ...
13
+ *
14
+ * ## R (CRAN)
15
+ * Seurat, dplyr, ggplot2, ...
16
+ *
17
+ * ## Python (pip)
18
+ * anndata, scanpy, ...
19
+ *
20
+ * The file carries **names only — there are no version strings in it**, so this
21
+ * tool reports presence and language track and cannot report a version.
3
22
  */
4
23
  import { readFile } from "node:fs/promises";
5
24
  import { ok } from "neverthrow";
6
25
  import { z } from "zod";
7
26
  import { defineTool } from "../define-tool.js";
8
27
  const PACKAGES_FILE = "/mnt/libs/current/packages.txt";
28
+ /** Default number of packages a filtered/unfiltered listing returns. */
29
+ const DEFAULT_LIMIT = 100;
30
+ const UNAVAILABLE_NOTE = "Package list not available. The library store may not be mounted. Assume standard bioinformatics packages (numpy, pandas, scanpy, DESeq2, etc.) are available, but do not attempt to install anything.";
31
+ /** The `language` filter values, mapped onto the concrete section headings. */
32
+ const LANGUAGE_MATCHERS = {
33
+ // The R triple: `R (CRAN)`, `R (Bioconductor)`, `R (GitHub)`.
34
+ r: (t) => /^r\b/i.test(t),
35
+ python: (t) => /^python\b/i.test(t),
36
+ // `System tools (CLI)` — the conda-installed bioinformatics executables.
37
+ cli: (t) => /system tools|\bcli\b/i.test(t),
38
+ node: (t) => /^node\b/i.test(t),
39
+ };
40
+ /**
41
+ * Parse `packages.txt` into its sections. `#` lines are the advisory header,
42
+ * `## X` opens a section, and every other non-empty line contributes
43
+ * comma-separated package names to the open section. Unknown section headings
44
+ * are preserved as-is — a downstream image may add its own track.
45
+ */
46
+ export function parsePackagesFile(content) {
47
+ const sections = [];
48
+ for (const line of content.split("\n")) {
49
+ const trimmed = line.trim();
50
+ if (!trimmed)
51
+ continue;
52
+ if (trimmed.startsWith("##")) {
53
+ sections.push({ title: trimmed.slice(2).trim(), packages: [] });
54
+ continue;
55
+ }
56
+ if (trimmed.startsWith("#"))
57
+ continue;
58
+ const open = sections.at(-1);
59
+ if (!open)
60
+ continue;
61
+ for (const name of trimmed.split(",")) {
62
+ const pkg = name.trim();
63
+ if (pkg)
64
+ open.packages.push(pkg);
65
+ }
66
+ }
67
+ return sections;
68
+ }
69
+ /** Render sections to the agent-facing listing, bounded at `limit` packages. */
70
+ function renderListing(sections, limit) {
71
+ const lines = [];
72
+ let returned = 0;
73
+ for (const section of sections) {
74
+ if (section.packages.length === 0)
75
+ continue;
76
+ const room = limit - returned;
77
+ if (room <= 0) {
78
+ lines.push(`\n## ${section.title}`, ` ${section.packages.length} package(s) — not shown (limit reached).`);
79
+ continue;
80
+ }
81
+ const shown = section.packages.slice(0, room);
82
+ returned += shown.length;
83
+ lines.push(`\n## ${section.title}`, ` ${shown.join(", ")}`);
84
+ const hidden = section.packages.length - shown.length;
85
+ if (hidden > 0)
86
+ lines.push(` … and ${hidden} more in this section (raise \`limit\` or narrow with \`query\`).`);
87
+ }
88
+ return { content: lines.join("\n").trim(), returned };
89
+ }
90
+ /**
91
+ * Answer a packages query against a parsed catalog. Pure — the tool's `execute`
92
+ * is only the file read plus this call.
93
+ */
94
+ export function queryPackages(sections, { names, query, language, limit }) {
95
+ // Presence check — the cheap, targeted path. Answers "is X available, and in
96
+ // which track" without returning the catalog.
97
+ if (names && names.length > 0) {
98
+ const index = new Map();
99
+ for (const section of sections) {
100
+ for (const pkg of section.packages) {
101
+ // First writer wins: `packages.txt` sections are ordered, so a name
102
+ // colliding across tracks resolves to the earliest one.
103
+ if (!index.has(pkg.toLowerCase()))
104
+ index.set(pkg.toLowerCase(), { name: pkg, section: section.title });
105
+ }
106
+ }
107
+ const checked = names.map((requested) => {
108
+ const hit = index.get(requested.trim().toLowerCase());
109
+ // `name` echoes the catalog's canonical spelling — R package names are
110
+ // case-sensitive at `library()`, so the exact one is what the caller needs.
111
+ return hit ? { requested, present: true, name: hit.name, section: hit.section } : { requested, present: false };
112
+ });
113
+ return { available: true, checked };
114
+ }
115
+ const matchesLanguage = language ? LANGUAGE_MATCHERS[language] : () => true;
116
+ const needle = query?.trim().toLowerCase();
117
+ const filtered = sections
118
+ .filter((s) => matchesLanguage(s.title))
119
+ .map((s) => ({
120
+ title: s.title,
121
+ packages: needle ? s.packages.filter((p) => p.toLowerCase().includes(needle)) : s.packages,
122
+ }))
123
+ .filter((s) => s.packages.length > 0);
124
+ const total = filtered.reduce((n, s) => n + s.packages.length, 0);
125
+ if (total === 0) {
126
+ const scope = [language ? `language: ${language}` : null, query ? `query: "${query}"` : null].filter(Boolean).join(", ");
127
+ return {
128
+ available: true,
129
+ total: 0,
130
+ returned: 0,
131
+ hasMore: false,
132
+ content: `No packages match this filter${scope ? ` (${scope})` : ""}. Nothing can be installed at runtime.`,
133
+ };
134
+ }
135
+ const { content, returned } = renderListing(filtered, limit ?? DEFAULT_LIMIT);
136
+ return { available: true, total, returned, hasMore: returned < total, content };
137
+ }
9
138
  export const listAvailablePackagesTool = defineTool({
10
139
  id: "list_available_packages",
11
- description: "List all R, Python, and CLI packages available in the sandbox environment. Use this before writing analysis scripts to verify which packages you can import. No packages can be installed at runtime — only what this tool returns is available.",
12
- inputSchema: z.object({}),
13
- execute: async () => {
140
+ description: "Query the R, Python, CLI, and Node packages installed in the sandbox. No packages can be installed at runtime — only what this tool reports is importable. " +
141
+ "Results are ALWAYS bounded; prefer a targeted query over a full listing. " +
142
+ '`names`: check specific packages (e.g. ["Seurat", "scanpy"]) — returns present/absent plus the language track for each, case-insensitively; this is the cheapest call and the right one for \'is X available?\'. ' +
143
+ "`query`: case-insensitive substring filter over package names. " +
144
+ "`language`: restrict to one track (r | python | cli | node). " +
145
+ "`limit`: max packages listed (default 100); the response always carries the true `total` and a `hasMore` flag, so truncation is never silent. " +
146
+ 'The package list carries NO version numbers — this tool cannot report a package\'s version. Check a version at runtime instead (e.g. `python -c "import scanpy; print(scanpy.__version__)"`).',
147
+ inputSchema: z.object({
148
+ names: z
149
+ .array(z.string())
150
+ .max(100)
151
+ .optional()
152
+ .describe("Check these exact package names for presence (case-insensitive). Returns one entry per name: present/absent + the language track it lives in."),
153
+ query: z.string().optional().describe("Case-insensitive substring filter over package names."),
154
+ language: z.enum(["r", "python", "cli", "node"]).optional().describe("Restrict results to one language track."),
155
+ limit: z.number().int().min(1).max(2000).optional().describe(`Max packages to list (default ${DEFAULT_LIMIT}). Ignored when \`names\` is given.`),
156
+ }),
157
+ execute: async (input) => {
14
158
  // A missing library-store mount is an expected environment state — model
15
159
  // it as an `available: false` data variant with a helpful fallback note.
160
+ let raw;
16
161
  try {
17
- const content = await readFile(PACKAGES_FILE, "utf-8");
18
- return ok({ available: true, content });
162
+ raw = await readFile(PACKAGES_FILE, "utf-8");
19
163
  }
20
164
  catch {
21
- return ok({
22
- available: false,
23
- content: "Package list not available. The library store may not be mounted. Assume standard bioinformatics packages (numpy, pandas, scanpy, DESeq2, etc.) are available, but do not attempt to install anything.",
24
- });
165
+ return ok({ available: false, content: UNAVAILABLE_NOTE });
25
166
  }
167
+ return ok(queryPackages(parsePackagesFile(raw), input));
26
168
  },
27
169
  });
@@ -1,7 +1,143 @@
1
1
  /**
2
- * listAvailableRefs — list reference data available in the sandbox.
2
+ * Reference-store discovery — two coordinated surfaces over the read-only
3
+ * store at /mnt/refs:
4
+ *
5
+ * - `createListAvailableRefsTool` — the wired sandbox tool. A bounded, no-follow
6
+ * inventory of what is ACTUALLY mounted (managed installs, user-added files),
7
+ * scanned live inside the sandbox. Narrow with `path`/`category`, filter with
8
+ * `query`, cap with `limit`; every response carries `returned`/`total`/
9
+ * `hasMore` and the `categories` present, so a listing is never an unbounded
10
+ * dump. Symlinks are never followed; nothing can be downloaded at runtime.
11
+ * - `queryRefs` — a pure query over a parsed `/mnt/refs/registry.json` manifest
12
+ * (`files.by_category`), filtering on fields the registry carries: `local_path`,
13
+ * `category`, `subtype`, `organism`, `tax_id`, `dataset`, `rows`.
3
14
  */
4
- export declare const listAvailableRefsTool: import("../define-tool.js").Tool<Record<string, never>, {
5
- available: boolean;
6
- content: string;
7
- }>;
15
+ import type { SandboxClient } from "../../sandbox/client.js";
16
+ import type { SandboxRef } from "../../sandbox/types.js";
17
+ export interface ListAvailableRefsDeps {
18
+ readonly sandboxClient: SandboxClient;
19
+ readonly sandbox: SandboxRef;
20
+ readonly workflowId: string;
21
+ readonly stepId: string;
22
+ readonly nextFunctionId: () => string;
23
+ readonly deadlineMs: () => number;
24
+ readonly markExecActive?: (execId: string) => Promise<void>;
25
+ /** Filesystem root used by the scanner; production callers omit this. */
26
+ readonly scanRoot?: string;
27
+ }
28
+ export interface ReferenceInventoryMetadata {
29
+ readonly datasetId?: string;
30
+ readonly version?: string;
31
+ readonly title?: string;
32
+ readonly description?: string;
33
+ readonly sourceUrl?: string;
34
+ readonly license?: string;
35
+ readonly category?: string;
36
+ readonly subtype?: string;
37
+ readonly organism?: string;
38
+ readonly rows?: number;
39
+ readonly endpoint?: string;
40
+ }
41
+ interface ReferenceInventoryEntryBase {
42
+ readonly path: string;
43
+ readonly metadata?: ReferenceInventoryMetadata;
44
+ }
45
+ /** A bounded, no-follow observation from the live reference mount. */
46
+ export type ReferenceInventoryEntry = (ReferenceInventoryEntryBase & {
47
+ readonly kind: "file";
48
+ readonly bytes: number;
49
+ }) | (ReferenceInventoryEntryBase & {
50
+ readonly kind: "symlink";
51
+ readonly bytes: 0;
52
+ }) | (ReferenceInventoryEntryBase & {
53
+ readonly kind: "directory";
54
+ readonly bytes: number;
55
+ readonly fileCount: number;
56
+ readonly fileTypes: readonly string[];
57
+ readonly truncated: boolean;
58
+ });
59
+ /**
60
+ * Structured result returned for every expected reference-store state. Bounding
61
+ * is explicit: `returned`/`total`/`hasMore` describe how much of the match set
62
+ * this response carries, and `categories` is the drill-in index.
63
+ */
64
+ export interface ReferenceInventoryResult {
65
+ readonly available: boolean;
66
+ readonly state: RawScan["state"] | "out_of_scope";
67
+ readonly path: string;
68
+ readonly entries: readonly ReferenceInventoryEntry[];
69
+ readonly scannedEntries: number;
70
+ readonly returned: number;
71
+ readonly total: number;
72
+ readonly truncated: boolean;
73
+ readonly hasMore: boolean;
74
+ readonly categories: readonly string[];
75
+ readonly content: string;
76
+ }
77
+ interface RawScan {
78
+ readonly state: "unavailable" | "empty" | "populated" | "not_found" | "not_a_directory" | "symlink";
79
+ readonly entries: ReferenceInventoryEntry[];
80
+ readonly scannedEntries: number;
81
+ readonly truncated: boolean;
82
+ readonly receipts?: unknown[];
83
+ readonly legacyEntries?: unknown[];
84
+ }
85
+ /** Create replay-safe reference discovery bound to the active sandbox. */
86
+ export declare function createListAvailableRefsTool(deps: ListAvailableRefsDeps): import("../define-tool.js").Tool<{
87
+ path?: string | undefined;
88
+ category?: string | undefined;
89
+ query?: string | undefined;
90
+ limit?: number | undefined;
91
+ }, ReferenceInventoryResult>;
92
+ export interface RegistryEntry {
93
+ local_path: string;
94
+ sha256: string;
95
+ bytes: number;
96
+ rows: number | null;
97
+ category: string | null;
98
+ subtype: string | null;
99
+ organism: string | null;
100
+ tax_id: string | null;
101
+ dataset: string | null;
102
+ endpoint: string | null;
103
+ }
104
+ export interface Registry {
105
+ registry_version: string;
106
+ build_id: string;
107
+ generated_at: string;
108
+ files: {
109
+ by_category: Record<string, RegistryEntry[]>;
110
+ };
111
+ summary: {
112
+ total_output_files: number;
113
+ categories: string[];
114
+ };
115
+ }
116
+ /**
117
+ * Either the store is unmounted, or a bounded listing: `categories` always names
118
+ * the full valid set (the drill-in index), and `total`/`hasMore` make truncation
119
+ * explicit.
120
+ */
121
+ export type RefsResult = {
122
+ readonly available: false;
123
+ readonly content: string;
124
+ } | {
125
+ readonly available: true;
126
+ readonly total: number;
127
+ readonly returned: number;
128
+ readonly hasMore: boolean;
129
+ readonly categories: readonly string[];
130
+ readonly content: string;
131
+ };
132
+ /** The tool's input, as parsed from `inputSchema`. */
133
+ export interface RefsQuery {
134
+ readonly category?: string;
135
+ readonly query?: string;
136
+ readonly limit?: number;
137
+ }
138
+ /**
139
+ * Answer a refs query against a parsed registry. Pure — the tool's `execute` is
140
+ * only the file read plus this call.
141
+ */
142
+ export declare function queryRefs(registry: Registry, { category, query, limit }: RefsQuery): RefsResult;
143
+ export {};