@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.
- package/dist/agents/conversation-agent.d.ts +12 -11
- package/dist/agents/conversation-agent.js +30 -33
- package/dist/agents/report-builder.js +2 -1
- package/dist/agents/sandbox/bulk-transcriptomics-agent.js +1 -1
- package/dist/agents/sandbox/cheminformatics-agent.js +1 -19
- package/dist/agents/sandbox/chromatin-agent.js +1 -10
- package/dist/agents/sandbox/dna-methylation-agent.js +1 -10
- package/dist/agents/sandbox/drug-repurposing-agent.js +4 -14
- package/dist/agents/sandbox/enrichment-agent.js +1 -10
- package/dist/agents/sandbox/ephemeral-executor.js +1 -10
- package/dist/agents/sandbox/genomic-variant-agent.js +1 -3
- package/dist/agents/sandbox/immune-profiling-agent.js +1 -13
- package/dist/agents/sandbox/metabolomics-agent.js +1 -1
- package/dist/agents/sandbox/microbiome-agent.js +1 -1
- package/dist/agents/sandbox/multi-omics-integration-agent.js +1 -12
- package/dist/agents/sandbox/multimodal-sc-agent.js +1 -1
- package/dist/agents/sandbox/network-agent.js +1 -10
- package/dist/agents/sandbox/pkpd-clinical-response-agent.js +2 -8
- package/dist/agents/sandbox/proteomics-agent.js +1 -1
- package/dist/agents/sandbox/scientific-executor.js +1 -10
- package/dist/agents/sandbox/shared.d.ts +17 -6
- package/dist/agents/sandbox/shared.js +49 -38
- package/dist/agents/sandbox/single-cell-agent.js +1 -1
- package/dist/agents/sandbox/spatial-omics-agent.js +1 -1
- package/dist/agents/sandbox/statistical-modeling-agent.js +1 -1
- package/dist/agents/sandbox/translational-safety-agent.js +3 -9
- package/dist/agents/sandbox/types.d.ts +1 -1
- package/dist/agents/system-prompt.d.ts +37 -11
- package/dist/agents/system-prompt.js +35 -12
- package/dist/app/data-profile-orientation.d.ts +34 -0
- package/dist/app/data-profile-orientation.js +117 -0
- package/dist/contracts/schemas/chat-parts.d.ts +9 -9
- package/dist/execution/artifact-metadata.js +2 -1
- package/dist/execution/ephemeral-runner.d.ts +13 -0
- package/dist/execution/ephemeral-runner.js +23 -1
- package/dist/execution/run-synthesis.js +20 -19
- package/dist/execution/step-summary.js +2 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +19 -5
- package/dist/loop/__fixtures__/scripted-provider.d.ts +2 -2
- package/dist/loop/__fixtures__/scripted-provider.js +2 -1
- package/dist/loop/metrics.d.ts +33 -1
- package/dist/loop/metrics.js +56 -2
- package/dist/loop/run-agent.d.ts +13 -1
- package/dist/loop/run-agent.js +19 -4
- package/dist/memory/card-builders.d.ts +8 -1
- package/dist/memory/card-builders.js +20 -3
- package/dist/memory/reconstruct-cards.js +4 -3
- package/dist/memory/thread-history.d.ts +27 -2
- package/dist/memory/thread-history.js +45 -5
- package/dist/memory/working-memory.d.ts +93 -10
- package/dist/memory/working-memory.js +220 -84
- package/dist/prompts/SOUL.d.ts +22 -9
- package/dist/prompts/SOUL.js +56 -37
- package/dist/prompts/analogical-reasoner.d.ts +1 -1
- package/dist/prompts/analogical-reasoner.js +2 -2
- package/dist/prompts/briefing.d.ts +100 -0
- package/dist/prompts/briefing.js +166 -0
- package/dist/prompts/conversation.d.ts +1 -1
- package/dist/prompts/conversation.js +94 -440
- package/dist/prompts/literature-reviewer.d.ts +1 -1
- package/dist/prompts/literature-reviewer.js +10 -10
- package/dist/prompts/planner.js +28 -59
- package/dist/prompts/report-builder.d.ts +1 -1
- package/dist/prompts/report-builder.js +71 -24
- package/dist/prompts/sandbox/bulk-transcriptomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/bulk-transcriptomics-agent.js +2 -7
- package/dist/prompts/sandbox/cheminformatics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/cheminformatics-agent.js +11 -15
- package/dist/prompts/sandbox/chromatin-agent.d.ts +1 -1
- package/dist/prompts/sandbox/chromatin-agent.js +3 -7
- package/dist/prompts/sandbox/data-profiler.d.ts +1 -1
- package/dist/prompts/sandbox/data-profiler.js +13 -8
- package/dist/prompts/sandbox/dna-methylation-agent.d.ts +1 -1
- package/dist/prompts/sandbox/dna-methylation-agent.js +2 -7
- package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
- package/dist/prompts/sandbox/drug-repurposing-agent.js +15 -16
- package/dist/prompts/sandbox/enrichment-agent.d.ts +1 -1
- package/dist/prompts/sandbox/enrichment-agent.js +2 -9
- package/dist/prompts/sandbox/genomic-variant-agent.d.ts +1 -1
- package/dist/prompts/sandbox/genomic-variant-agent.js +2 -6
- package/dist/prompts/sandbox/immune-profiling-agent.d.ts +1 -1
- package/dist/prompts/sandbox/immune-profiling-agent.js +3 -8
- package/dist/prompts/sandbox/metabolomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/metabolomics-agent.js +1 -7
- package/dist/prompts/sandbox/microbiome-agent.d.ts +1 -1
- package/dist/prompts/sandbox/microbiome-agent.js +2 -7
- package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
- package/dist/prompts/sandbox/multi-omics-integration-agent.js +2 -8
- package/dist/prompts/sandbox/multimodal-sc-agent.d.ts +1 -1
- package/dist/prompts/sandbox/multimodal-sc-agent.js +2 -7
- package/dist/prompts/sandbox/network-agent.d.ts +1 -1
- package/dist/prompts/sandbox/network-agent.js +2 -7
- package/dist/prompts/sandbox/proteomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/proteomics-agent.js +2 -9
- package/dist/prompts/sandbox/single-cell-agent.d.ts +1 -1
- package/dist/prompts/sandbox/single-cell-agent.js +2 -9
- package/dist/prompts/sandbox/spatial-omics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/spatial-omics-agent.js +3 -6
- package/dist/prompts/sandbox/statistical-modeling-agent.d.ts +1 -1
- package/dist/prompts/sandbox/statistical-modeling-agent.js +2 -7
- package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
- package/dist/prompts/sandbox/translational-safety-agent.js +13 -14
- package/dist/prompts/sandbox-standards.d.ts +22 -14
- package/dist/prompts/sandbox-standards.js +91 -71
- package/dist/prompts/synthesis-agent.d.ts +1 -1
- package/dist/prompts/synthesis-agent.js +33 -131
- package/dist/provenance/collector.js +1 -1
- package/dist/providers/ai-sdk.js +31 -4
- package/dist/providers/prompt-cache.d.ts +74 -0
- package/dist/providers/prompt-cache.js +77 -0
- package/dist/providers/types.d.ts +33 -0
- package/dist/reference-data/catalog.d.ts +131 -0
- package/dist/reference-data/catalog.js +348 -0
- package/dist/reference-data/receipt.d.ts +41 -0
- package/dist/reference-data/receipt.js +40 -0
- package/dist/schemas/data-profile-schemas.js +5 -3
- package/dist/schemas/plan-schemas.d.ts +21 -21
- package/dist/schemas/plan-schemas.js +9 -3
- package/dist/schemas/run-synthesis.d.ts +8 -4
- package/dist/schemas/run-synthesis.js +92 -56
- package/dist/schemas/validate-plan.js +1 -1
- package/dist/schemas/workflow-state.d.ts +7 -1
- package/dist/schemas/workflow-state.js +33 -19
- package/dist/state/artifacts.d.ts +13 -0
- package/dist/state/artifacts.js +27 -0
- package/dist/state/data-profile.d.ts +64 -5
- package/dist/state/index.d.ts +3 -3
- package/dist/state/index.js +1 -1
- package/dist/tasks/data-profile.d.ts +20 -2
- package/dist/tasks/data-profile.js +71 -22
- package/dist/tools/bio/chembl.d.ts +38 -0
- package/dist/tools/bio/chembl.js +138 -0
- package/dist/tools/bio/comptox.d.ts +50 -0
- package/dist/tools/bio/comptox.js +149 -0
- package/dist/tools/bio/get-impc-ko-profile.js +9 -6
- package/dist/tools/bio/index.d.ts +5 -17
- package/dist/tools/bio/index.js +5 -17
- package/dist/tools/bio/keys.d.ts +14 -9
- package/dist/tools/bio/keys.js +16 -16
- package/dist/tools/bio/opentargets.d.ts +38 -0
- package/dist/tools/bio/opentargets.js +89 -0
- package/dist/tools/bio/pubchem.d.ts +29 -0
- package/dist/tools/bio/pubchem.js +92 -0
- package/dist/tools/bio/pubmed.d.ts +51 -0
- package/dist/tools/bio/pubmed.js +100 -0
- package/dist/tools/bio/search-bgee-expression.js +12 -6
- package/dist/tools/bio/search-clinical-trials.js +16 -5
- package/dist/tools/bio/search-faers.js +8 -4
- package/dist/tools/bio/search-geo-datasets.js +20 -6
- package/dist/tools/bio/search-gwas-catalog.d.ts +1 -1
- package/dist/tools/bio/search-pharmgkb.js +10 -4
- package/dist/tools/display/index.d.ts +1 -0
- package/dist/tools/display/index.js +1 -0
- package/dist/tools/display/normalize-echart-spec.d.ts +61 -0
- package/dist/tools/display/normalize-echart-spec.js +211 -0
- package/dist/tools/display/show-user.d.ts +6 -1
- package/dist/tools/display/show-user.js +25 -12
- package/dist/tools/execute-plan.js +5 -2
- package/dist/tools/iterate-report.d.ts +168 -118
- package/dist/tools/iterate-report.js +334 -96
- package/dist/tools/lib/chembl-client.d.ts +12 -0
- package/dist/tools/lib/chembl-client.js +127 -0
- package/dist/tools/lib/ctx-ops.d.ts +224 -0
- package/dist/tools/lib/ctx-ops.js +450 -0
- package/dist/tools/lib/iuphar-client.js +10 -1
- package/dist/tools/lib/openfda-client.js +11 -3
- package/dist/tools/lib/pathway-client.js +10 -4
- package/dist/tools/lib/pubchem-ops.d.ts +74 -0
- package/dist/tools/lib/pubchem-ops.js +224 -0
- package/dist/tools/memory/update-working-memory.d.ts +45 -7
- package/dist/tools/memory/update-working-memory.js +111 -41
- package/dist/tools/report/index.d.ts +3 -2
- package/dist/tools/report/index.js +3 -2
- package/dist/tools/research/generate-analogy-report.js +25 -12
- package/dist/tools/research/generate-plan.d.ts +12 -5
- package/dist/tools/research/generate-plan.js +168 -37
- package/dist/tools/research/index.d.ts +1 -0
- package/dist/tools/research/index.js +1 -0
- package/dist/tools/research/inspect-data-profile.d.ts +85 -0
- package/dist/tools/research/inspect-data-profile.js +161 -0
- package/dist/tools/research/literature-reviewer.js +3 -4
- package/dist/tools/sandbox/list-available-packages.d.ts +79 -5
- package/dist/tools/sandbox/list-available-packages.js +152 -10
- package/dist/tools/sandbox/list-available-refs.d.ts +141 -5
- package/dist/tools/sandbox/list-available-refs.js +647 -134
- package/dist/tools/sandbox/report-blocker.d.ts +39 -9
- package/dist/tools/sandbox/report-blocker.js +43 -20
- package/dist/tools/workspace/read-file.js +4 -5
- package/dist/tools/workspace/run-exec.d.ts +4 -4
- package/dist/tools/workspace/run-exec.js +4 -4
- package/dist/tools/workspace/show-file.js +10 -6
- package/dist/tools/workspace/show-plan.js +12 -6
- package/dist/tools/workspace/workspace-search.d.ts +1 -1
- package/dist/tools/workspace/workspace-search.js +11 -5
- package/dist/workflows/execute-analysis.d.ts +43 -4
- package/dist/workflows/execute-analysis.js +107 -6
- package/dist/workflows/target-assessment/lib/citation-validator.js +2 -2
- package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.js +2 -1
- package/dist/workspace/paths.d.ts +2 -2
- package/dist/workspace/paths.js +2 -2
- package/package.json +33 -33
- package/dist/execution/filesystem-artifact-registry.d.ts +0 -57
- package/dist/execution/filesystem-artifact-registry.js +0 -92
- package/dist/lib/identifiers.d.ts +0 -8
- package/dist/lib/identifiers.js +0 -10
- package/dist/lib/mime-detect.d.ts +0 -17
- package/dist/lib/mime-detect.js +0 -29
- package/dist/lib/streamed-download.d.ts +0 -28
- package/dist/lib/streamed-download.js +0 -111
- package/dist/lib/trace-context.d.ts +0 -11
- package/dist/lib/trace-context.js +0 -49
- package/dist/providers/llm-capabilities.d.ts +0 -33
- package/dist/providers/llm-capabilities.js +0 -58
- package/dist/schemas/render-step-prompt.d.ts +0 -32
- package/dist/schemas/render-step-prompt.js +0 -76
- package/dist/tools/bio/find-approval-precedent.d.ts +0 -32
- package/dist/tools/bio/find-approval-precedent.js +0 -72
- package/dist/tools/bio/get-article-details.d.ts +0 -11
- package/dist/tools/bio/get-article-details.js +0 -20
- package/dist/tools/bio/get-article-full-text.d.ts +0 -19
- package/dist/tools/bio/get-article-full-text.js +0 -32
- package/dist/tools/bio/get-bioactivity.d.ts +0 -11
- package/dist/tools/bio/get-bioactivity.js +0 -23
- package/dist/tools/bio/get-drug-info.d.ts +0 -9
- package/dist/tools/bio/get-drug-info.js +0 -22
- package/dist/tools/bio/get-mechanism.d.ts +0 -8
- package/dist/tools/bio/get-mechanism.js +0 -18
- package/dist/tools/bio/get-pubchem-assays.d.ts +0 -22
- package/dist/tools/bio/get-pubchem-assays.js +0 -107
- package/dist/tools/bio/get-pubchem-cross-refs.d.ts +0 -15
- package/dist/tools/bio/get-pubchem-cross-refs.js +0 -68
- package/dist/tools/bio/get-target-safety.d.ts +0 -18
- package/dist/tools/bio/get-target-safety.js +0 -26
- package/dist/tools/bio/search-compounds.d.ts +0 -22
- package/dist/tools/bio/search-compounds.js +0 -160
- package/dist/tools/bio/search-ctx-chemical.d.ts +0 -50
- package/dist/tools/bio/search-ctx-chemical.js +0 -130
- package/dist/tools/bio/search-ctx-exposure.d.ts +0 -55
- package/dist/tools/bio/search-ctx-exposure.js +0 -176
- package/dist/tools/bio/search-ctx-hazard.d.ts +0 -111
- package/dist/tools/bio/search-ctx-hazard.js +0 -178
- package/dist/tools/bio/search-opentargets.d.ts +0 -11
- package/dist/tools/bio/search-opentargets.js +0 -25
- package/dist/tools/bio/search-pubchem-compound.d.ts +0 -26
- package/dist/tools/bio/search-pubchem-compound.js +0 -110
- package/dist/tools/bio/search-pubmed.d.ts +0 -17
- package/dist/tools/bio/search-pubmed.js +0 -31
- package/dist/tools/bio/search-targets.d.ts +0 -9
- package/dist/tools/bio/search-targets.js +0 -20
- package/dist/tools/bio/search-toxcast.d.ts +0 -36
- package/dist/tools/bio/search-toxcast.js +0 -141
- package/dist/workflows/register-workflows.d.ts +0 -51
- package/dist/workflows/register-workflows.js +0 -48
- package/dist/workflows/resume-execute-analysis.d.ts +0 -70
- package/dist/workflows/resume-execute-analysis.js +0 -80
- package/dist/workflows/target-assessment/correction-loop.d.ts +0 -45
- package/dist/workflows/target-assessment/correction-loop.js +0 -62
- package/dist/workflows/target-assessment/steps/phase0-resolve.d.ts +0 -71
- package/dist/workflows/target-assessment/steps/phase0-resolve.js +0 -21
- package/dist/workflows/target-assessment/steps/phase1-aggregate.d.ts +0 -1018
- package/dist/workflows/target-assessment/steps/phase1-aggregate.js +0 -25
- package/dist/workspace/mount-strategy.d.ts +0 -50
- package/dist/workspace/mount-strategy.js +0 -67
- package/dist/workspace/provenance-collector.d.ts +0 -34
- package/dist/workspace/provenance-collector.js +0 -16
- package/dist/workspace/workspace-paths.d.ts +0 -26
- package/dist/workspace/workspace-paths.js +0 -31
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { ResultAsync } from "neverthrow";
|
|
7
7
|
import { type DbError } from "../lib/db-result.js";
|
|
8
|
+
import type { Organism } from "../schemas/data-profile-schemas.js";
|
|
8
9
|
import type { Querier } from "./db.js";
|
|
9
10
|
/**
|
|
10
11
|
* One profiled input file's **drift signature**. `fileId` is a path identity the
|
|
@@ -18,13 +19,53 @@ export interface DataProfileInputFile {
|
|
|
18
19
|
size: number;
|
|
19
20
|
mtimeMs: number;
|
|
20
21
|
}
|
|
21
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* One profiled file's persisted record.
|
|
24
|
+
*
|
|
25
|
+
* `path` + `description` are the original pair every snapshot carries. Everything
|
|
26
|
+
* below them is **optional on read** for the same reason `DataProfileResult.inputFiles`
|
|
27
|
+
* is: a snapshot written before the record was widened carries only the pair, and a
|
|
28
|
+
* reader must render that row rather than reject it. A writer fills in whatever the
|
|
29
|
+
* profiler reported.
|
|
30
|
+
*/
|
|
31
|
+
export interface DataProfileFile {
|
|
32
|
+
path: string;
|
|
33
|
+
description: string;
|
|
34
|
+
/** Semantic data type (count-matrix, variants, clinical-metadata, document, …). */
|
|
35
|
+
dataType?: string;
|
|
36
|
+
/** File format (CSV, h5ad, VCF, BAM, …). */
|
|
37
|
+
format?: string;
|
|
38
|
+
rows?: number | null;
|
|
39
|
+
cols?: number | null;
|
|
40
|
+
/** Searchable labels the profiler attached. */
|
|
41
|
+
tags?: string[];
|
|
42
|
+
/** Quality issues specific to this file. */
|
|
43
|
+
warnings?: string[];
|
|
44
|
+
/** Flat format-specific metrics (sparsity, medianLibrarySize, tiTvRatio, …). */
|
|
45
|
+
metrics?: Record<string, string | number | boolean>;
|
|
46
|
+
}
|
|
47
|
+
/** Dataset-wide quality findings the profiler recorded. */
|
|
48
|
+
export interface DataProfileQualityAssessment {
|
|
49
|
+
concerns: string[];
|
|
50
|
+
strengths: string[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The profile snapshot `completeDataProfile` persists and `loadDataProfileStatus` reads back.
|
|
54
|
+
*
|
|
55
|
+
* This row is the **only** durable home of the profile: the profiler's `runs/data-profile/`
|
|
56
|
+
* scratch tree is wiped when profiling completes, so there is no file to fall back on. It
|
|
57
|
+
* therefore carries the profiler's full finding, not a summary of it — anything dropped here
|
|
58
|
+
* is destroyed, and a downstream agent can only recover it by re-reading the raw input files.
|
|
59
|
+
*
|
|
60
|
+
* Every field past `summary` / `files` / `inputFileIds` / `profiledAt` is **optional on read**:
|
|
61
|
+
* a snapshot written before the record was widened carries only those four, and a reader must
|
|
62
|
+
* render it rather than throw. There is no parse at the read boundary (the jsonb column is cast
|
|
63
|
+
* straight to this type), so optionality *is* the compatibility mechanism — exactly as it
|
|
64
|
+
* already is for `inputFiles`.
|
|
65
|
+
*/
|
|
22
66
|
export interface DataProfileResult {
|
|
23
67
|
summary: string;
|
|
24
|
-
files:
|
|
25
|
-
path: string;
|
|
26
|
-
description: string;
|
|
27
|
-
}>;
|
|
68
|
+
files: DataProfileFile[];
|
|
28
69
|
/** Which files the profile covered — the audit record. */
|
|
29
70
|
inputFileIds: string[];
|
|
30
71
|
/**
|
|
@@ -35,6 +76,24 @@ export interface DataProfileResult {
|
|
|
35
76
|
*/
|
|
36
77
|
inputFiles?: DataProfileInputFile[];
|
|
37
78
|
profiledAt: string;
|
|
79
|
+
/** Scientific domain (transcriptomics, cheminformatics, clinical, …). */
|
|
80
|
+
domain?: string;
|
|
81
|
+
/** Specific subtype within the domain (bulk-rna-seq, single-cell, LC-MS/MS, …). */
|
|
82
|
+
subtype?: string;
|
|
83
|
+
/**
|
|
84
|
+
* Subject organism with its provenance and confidence. Explicit `null` is a real,
|
|
85
|
+
* distinct value — the profiler looked and no input identified an organism — as
|
|
86
|
+
* opposed to absent, which means the snapshot predates this field.
|
|
87
|
+
*/
|
|
88
|
+
organism?: Organism | null;
|
|
89
|
+
tissue?: string | null;
|
|
90
|
+
cellType?: string | null;
|
|
91
|
+
condition?: string | null;
|
|
92
|
+
/** Public dataset accessions found in any input (GSE/SRP/PRJNA/E-MTAB/phs/EGAS). */
|
|
93
|
+
accessions?: string[];
|
|
94
|
+
/** Conditions, groups, comparisons, replicates, pairing. */
|
|
95
|
+
experimentalDesign?: string;
|
|
96
|
+
qualityAssessment?: DataProfileQualityAssessment;
|
|
38
97
|
}
|
|
39
98
|
export interface DataProfileStatus {
|
|
40
99
|
status: "pending" | "running" | "completed" | "failed";
|
package/dist/state/index.d.ts
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
export { initCortexState } from "./init.js";
|
|
10
10
|
export type { Querier } from "./db.js";
|
|
11
11
|
export { upsertAnalysis, resolveAnalysisBilling, suspendAnalysis, resumeAnalysis, loadAnalysisStatus } from "./analyses.js";
|
|
12
|
-
export { upsertArtifact, upsertArtifacts, queryInputArtifacts, queryUnsyncedStepArtifacts, updateArtifactId, updateFileIds, countArtifactsForRun, } from "./artifacts.js";
|
|
13
|
-
export type { RegisterArtifactInput, InputArtifactMeta } from "./artifacts.js";
|
|
12
|
+
export { upsertArtifact, upsertArtifacts, queryInputArtifacts, queryStepArtifactPaths, queryUnsyncedStepArtifacts, updateArtifactId, updateFileIds, countArtifactsForRun, } from "./artifacts.js";
|
|
13
|
+
export type { RegisterArtifactInput, InputArtifactMeta, StepArtifactRef } from "./artifacts.js";
|
|
14
14
|
export { insertRun, RunDedupCollisionError, updateRunStatus, promoteFailedToPartial, setRunMandate, // oss-core-managed-ok: run-mandate ledger (nullable; OSS leaves null)
|
|
15
15
|
queryRun, queryActiveRun, queryRunsByAnalysis, queryRunsByThread, } from "./runs.js";
|
|
16
16
|
export type { InsertRunInput } from "./runs.js";
|
|
@@ -21,7 +21,7 @@ export type { ActiveSandboxRow } from "./active-sandboxes.js";
|
|
|
21
21
|
export { insertPlan, loadPlan } from "./plans.js";
|
|
22
22
|
export type { InsertPlanInput } from "./plans.js";
|
|
23
23
|
export { tryStartDataProfile, tryRetryDataProfile, tryRerunDataProfile, completeDataProfile, failDataProfile, expireStaleDataProfile, reconcileOrphanedDataProfile, clearDataProfile, loadDataProfileStatus, loadSeedInputFileIds, } from "./data-profile.js";
|
|
24
|
-
export type { DataProfileStatus, DataProfileResult, DataProfileInputFile } from "./data-profile.js";
|
|
24
|
+
export type { DataProfileStatus, DataProfileResult, DataProfileInputFile, DataProfileFile, DataProfileQualityAssessment } from "./data-profile.js";
|
|
25
25
|
export { queryRunCountsByAnalyses, queryThreadCountsByAnalyses, queryDataProfileStatusByAnalyses } from "./analyses-metrics.js";
|
|
26
26
|
export { AnalysisStateRowSchema, ArtifactRole, ArtifactRowSchema, RunStatus, StepExecutionStatus, CortexRunRowSchema, StepExecutionRowSchema, CortexPlanRowSchema, } from "./schema.js";
|
|
27
27
|
export type { AnalysisStateRow, ArtifactRow, CortexRunRow, StepExecutionRow, CortexPlanRow } from "./schema.js";
|
package/dist/state/index.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { initCortexState } from "./init.js";
|
|
10
10
|
export { upsertAnalysis, resolveAnalysisBilling, suspendAnalysis, resumeAnalysis, loadAnalysisStatus } from "./analyses.js";
|
|
11
|
-
export { upsertArtifact, upsertArtifacts, queryInputArtifacts, queryUnsyncedStepArtifacts, updateArtifactId, updateFileIds, countArtifactsForRun, } from "./artifacts.js";
|
|
11
|
+
export { upsertArtifact, upsertArtifacts, queryInputArtifacts, queryStepArtifactPaths, queryUnsyncedStepArtifacts, updateArtifactId, updateFileIds, countArtifactsForRun, } from "./artifacts.js";
|
|
12
12
|
export { insertRun, RunDedupCollisionError, updateRunStatus, promoteFailedToPartial, setRunMandate, // oss-core-managed-ok: run-mandate ledger (nullable; OSS leaves null)
|
|
13
13
|
queryRun, queryActiveRun, queryRunsByAnalysis, queryRunsByThread, } from "./runs.js";
|
|
14
14
|
export { insertStepExecution, seedStepExecutions, sweepPendingStepExecutions, updateStepExecution, queryStepsByRun } from "./step-executions.js";
|
|
@@ -24,8 +24,9 @@ import type { BioToolKeys } from "../tools/bio/keys.js";
|
|
|
24
24
|
import type { ChatProvider, EmbeddingProvider } from "../providers/types.js";
|
|
25
25
|
import type { SandboxClient } from "../sandbox/client.js";
|
|
26
26
|
import type { WorkspaceFilesystem } from "../workspace/filesystem.js";
|
|
27
|
-
import type
|
|
28
|
-
import { type
|
|
27
|
+
import { type ResolveWorkspaceRoot } from "../workspace/paths.js";
|
|
28
|
+
import { type ProfilerOutput } from "../schemas/data-profile-schemas.js";
|
|
29
|
+
import { type DataProfileInputFile, type DataProfileResult } from "../state/index.js";
|
|
29
30
|
/** The body's construction-time deps — closed over at registration. */
|
|
30
31
|
export interface DataProfileDeps {
|
|
31
32
|
readonly provider: ChatProvider;
|
|
@@ -93,6 +94,23 @@ export interface DataProfileWorkflowInput {
|
|
|
93
94
|
* The cast defeats the required-`number` type precisely to observe that legacy gap.
|
|
94
95
|
*/
|
|
95
96
|
export declare function buildDriftSignature(stagedInputs: readonly StagedInput[]): DataProfileInputFile[] | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* Project the profiler's structured output plus the staged manifest into the record
|
|
99
|
+
* persisted on `cortex_analysis_state`.
|
|
100
|
+
*
|
|
101
|
+
* That row is the profile's ONLY durable home — the profiler's `runs/data-profile/`
|
|
102
|
+
* scratch tree is deleted on completion, so nothing here is recoverable from a file
|
|
103
|
+
* later. The projection is therefore total: every field the profiler reported is
|
|
104
|
+
* carried through verbatim. A field this drops is not "summarized away", it is
|
|
105
|
+
* destroyed, and the next agent that needs it can only get it back by re-reading the
|
|
106
|
+
* raw inputs.
|
|
107
|
+
*
|
|
108
|
+
* `undefined` members are dropped by `JSON.stringify` on the way into the jsonb
|
|
109
|
+
* column, so an optional the profiler left unset simply does not appear in the row —
|
|
110
|
+
* indistinguishable from a legacy snapshot that predates the field, which is exactly
|
|
111
|
+
* the reading a consumer must already tolerate.
|
|
112
|
+
*/
|
|
113
|
+
export declare function buildDataProfileResult(profile: ProfilerOutput, stagedInputs: readonly StagedInput[], profiledAt: string): DataProfileResult;
|
|
96
114
|
/**
|
|
97
115
|
* Register the data-profile workflow with DBOS. Returns the registered
|
|
98
116
|
* callable so `triggerDataProfile` can dispatch via `DBOS.startWorkflow`.
|
|
@@ -25,6 +25,8 @@ import { runToTerminal } from "../loop/run-to-terminal.js";
|
|
|
25
25
|
import { durableStep } from "../loop/run-step.js";
|
|
26
26
|
import { unwrapOrThrow } from "../lib/result.js";
|
|
27
27
|
import { defineTool } from "../tools/define-tool.js";
|
|
28
|
+
import { renderWorkspace } from "../prompts/briefing.js";
|
|
29
|
+
import { toSandboxPath } from "../workspace/paths.js";
|
|
28
30
|
import { estimateDataProfileResources } from "../sandbox/estimate-data-profile-resources.js";
|
|
29
31
|
import { generateExecutionId } from "../sandbox/execution-id.js";
|
|
30
32
|
import { mintSandboxIdentity } from "../sandbox/identity.js";
|
|
@@ -69,6 +71,50 @@ export function buildDriftSignature(stagedInputs) {
|
|
|
69
71
|
return undefined;
|
|
70
72
|
return stagedInputs.map((f) => ({ fileId: f.fileId, size: f.size, mtimeMs: mtimeOf(f) }));
|
|
71
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Project the profiler's structured output plus the staged manifest into the record
|
|
76
|
+
* persisted on `cortex_analysis_state`.
|
|
77
|
+
*
|
|
78
|
+
* That row is the profile's ONLY durable home — the profiler's `runs/data-profile/`
|
|
79
|
+
* scratch tree is deleted on completion, so nothing here is recoverable from a file
|
|
80
|
+
* later. The projection is therefore total: every field the profiler reported is
|
|
81
|
+
* carried through verbatim. A field this drops is not "summarized away", it is
|
|
82
|
+
* destroyed, and the next agent that needs it can only get it back by re-reading the
|
|
83
|
+
* raw inputs.
|
|
84
|
+
*
|
|
85
|
+
* `undefined` members are dropped by `JSON.stringify` on the way into the jsonb
|
|
86
|
+
* column, so an optional the profiler left unset simply does not appear in the row —
|
|
87
|
+
* indistinguishable from a legacy snapshot that predates the field, which is exactly
|
|
88
|
+
* the reading a consumer must already tolerate.
|
|
89
|
+
*/
|
|
90
|
+
export function buildDataProfileResult(profile, stagedInputs, profiledAt) {
|
|
91
|
+
return {
|
|
92
|
+
summary: profile.analysisSummary,
|
|
93
|
+
files: profile.files.map((f) => ({
|
|
94
|
+
path: f.path,
|
|
95
|
+
description: f.description,
|
|
96
|
+
dataType: f.dataType,
|
|
97
|
+
format: f.format,
|
|
98
|
+
rows: f.rows,
|
|
99
|
+
cols: f.cols,
|
|
100
|
+
tags: f.tags,
|
|
101
|
+
warnings: f.warnings,
|
|
102
|
+
metrics: f.metrics,
|
|
103
|
+
})),
|
|
104
|
+
inputFileIds: stagedInputs.map((f) => f.fileId),
|
|
105
|
+
inputFiles: buildDriftSignature(stagedInputs),
|
|
106
|
+
profiledAt,
|
|
107
|
+
domain: profile.domain,
|
|
108
|
+
subtype: profile.subtype,
|
|
109
|
+
organism: profile.organism,
|
|
110
|
+
tissue: profile.tissue,
|
|
111
|
+
cellType: profile.cellType,
|
|
112
|
+
condition: profile.condition,
|
|
113
|
+
accessions: profile.accessions,
|
|
114
|
+
experimentalDesign: profile.experimentalDesign,
|
|
115
|
+
qualityAssessment: profile.qualityAssessment,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
72
118
|
/**
|
|
73
119
|
* Register the data-profile workflow with DBOS. Returns the registered
|
|
74
120
|
* callable so `triggerDataProfile` can dispatch via `DBOS.startWorkflow`.
|
|
@@ -108,15 +154,33 @@ export async function runDataProfileBody(input, deps) {
|
|
|
108
154
|
fileId: f.fileId,
|
|
109
155
|
})));
|
|
110
156
|
// 3. Run data-profiler sandbox agent
|
|
157
|
+
const executionId = generateExecutionId(DATA_PROFILE_AGENT_ID);
|
|
158
|
+
const workflowId = DBOS.workflowID ?? `${DATA_PROFILE_RUN_LITERAL}:${executionId}`;
|
|
159
|
+
const childSession = forSubAgent(runSession, DATA_PROFILE_AGENT_ID);
|
|
160
|
+
// A resolver throw fails the workflow loudly (workspace-root-resolution
|
|
161
|
+
// contract) — profiling an analysis whose root cannot be resolved is
|
|
162
|
+
// meaningless, so no softer handling is warranted.
|
|
163
|
+
const workspaceRoot = deps.resolveWorkspaceRoot(analysisId);
|
|
164
|
+
const profileWritePrefix = `${workspaceRoot}/runs/${DATA_PROFILE_RUN_LITERAL}/${DATA_PROFILE_STEP_LITERAL}`;
|
|
111
165
|
const fileList = stagedInputs.map((f) => inputArtifactPath(f));
|
|
166
|
+
// The profiler runs outside `executeAnalysis`, so no scheduler composes a
|
|
167
|
+
// briefing for it — this prompt IS its briefing, and the sandbox system
|
|
168
|
+
// prompt names no paths (it is static per agent type, for the prompt cache).
|
|
169
|
+
// Its workspace frame therefore has to be stated here, in the same words the
|
|
170
|
+
// step briefing uses.
|
|
112
171
|
const prompt = [
|
|
113
172
|
`Profile all input data files for this analysis.`,
|
|
114
173
|
``,
|
|
174
|
+
renderWorkspace({
|
|
175
|
+
analysisRoot: `/${analysisId}`,
|
|
176
|
+
workingDir: toSandboxPath(workspaceRoot, analysisId, profileWritePrefix),
|
|
177
|
+
}),
|
|
178
|
+
``,
|
|
115
179
|
`IMPORTANT: You MUST use execute_command to profile files before submitting results. Do NOT submit empty files or placeholder text.`,
|
|
116
180
|
``,
|
|
117
|
-
`CRITICAL: File and directory paths may contain spaces. You MUST always double-quote paths in shell commands (e.g. head "data/inputs/My Folder/file.csv"). Unquoted paths with spaces will silently break commands.`,
|
|
181
|
+
`CRITICAL: File and directory paths may contain spaces. You MUST always double-quote paths in shell commands (e.g. head "/${analysisId}/data/inputs/My Folder/file.csv"). Unquoted paths with spaces will silently break commands.`,
|
|
118
182
|
``,
|
|
119
|
-
`The following input files are available (paths relative to analysis root):`,
|
|
183
|
+
`The following input files are available (paths relative to the analysis root):`,
|
|
120
184
|
...fileList.map((f) => `- ${f}`),
|
|
121
185
|
``,
|
|
122
186
|
`Steps:`,
|
|
@@ -124,15 +188,8 @@ export async function runDataProfileBody(input, deps) {
|
|
|
124
188
|
`2. Write a Python script for detailed profiling — use pathlib or os.path for path handling (handles spaces natively)`,
|
|
125
189
|
`3. Call the \`submit_profile\` tool with structured metadata for EVERY file listed above`,
|
|
126
190
|
``,
|
|
127
|
-
`
|
|
191
|
+
`All file paths in your response must be relative to the analysis root and must EXACTLY match the paths listed above.`,
|
|
128
192
|
].join("\n");
|
|
129
|
-
const executionId = generateExecutionId(DATA_PROFILE_AGENT_ID);
|
|
130
|
-
const workflowId = DBOS.workflowID ?? `${DATA_PROFILE_RUN_LITERAL}:${executionId}`;
|
|
131
|
-
const childSession = forSubAgent(runSession, DATA_PROFILE_AGENT_ID);
|
|
132
|
-
// A resolver throw fails the workflow loudly (workspace-root-resolution
|
|
133
|
-
// contract) — profiling an analysis whose root cannot be resolved is
|
|
134
|
-
// meaningless, so no softer handling is warranted.
|
|
135
|
-
const workspaceRoot = deps.resolveWorkspaceRoot(analysisId);
|
|
136
193
|
console.log(`[data-profile] execution=${executionId} analysis=${analysisId} starting sandbox`);
|
|
137
194
|
const sandbox = await deps.sandboxClient.createSandbox({
|
|
138
195
|
runId: DATA_PROFILE_RUN_LITERAL,
|
|
@@ -168,7 +225,7 @@ export async function runDataProfileBody(input, deps) {
|
|
|
168
225
|
// The profiler writes Python scripts and intermediate artifacts under
|
|
169
226
|
// the synthetic step path; the post-agent `rm -rf runs/data-profile/`
|
|
170
227
|
// cleanup wipes them.
|
|
171
|
-
allowedWritePrefix:
|
|
228
|
+
allowedWritePrefix: profileWritePrefix,
|
|
172
229
|
nextFunctionId,
|
|
173
230
|
deadlineMs: () => deadlineAbs,
|
|
174
231
|
},
|
|
@@ -256,17 +313,9 @@ export async function runDataProfileBody(input, deps) {
|
|
|
256
313
|
console.warn(`[data-profile] ${fallbackCount}/${stagedInputs.length} input file(s) used a deterministic fallback description (analysis=${analysisId}) — profiler omitted them`);
|
|
257
314
|
}
|
|
258
315
|
console.log(`[data-profile] Indexed ${indexed} file(s) for ${analysisId}`);
|
|
259
|
-
// 5. Complete — store
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
files: profilerData.files.map((f) => ({
|
|
263
|
-
path: f.path,
|
|
264
|
-
description: f.description,
|
|
265
|
-
})),
|
|
266
|
-
inputFileIds: stagedInputs.map((f) => f.fileId),
|
|
267
|
-
inputFiles: buildDriftSignature(stagedInputs),
|
|
268
|
-
profiledAt: new Date().toISOString(),
|
|
269
|
-
}))) {
|
|
316
|
+
// 5. Complete — store the FULL profiler finding plus the input snapshot for
|
|
317
|
+
// staleness detection. The scratch tree is gone; this row is all that survives.
|
|
318
|
+
if (!unwrapOrThrow(await completeDataProfile(deps.pool, analysisId, buildDataProfileResult(profilerData, stagedInputs, new Date().toISOString())))) {
|
|
270
319
|
logTerminalNoop(analysisId, "completion");
|
|
271
320
|
}
|
|
272
321
|
await deps.runAuthorizer.revoke(authorization, "data-profile-completed");
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chembl — one tool over the five ChEMBL lookups: compounds, drugs, mechanisms,
|
|
3
|
+
* bioactivity, targets. "Which database" is the routing decision worth a tool
|
|
4
|
+
* boundary; "which ChEMBL endpoint" is mechanical, so it rides in `action`.
|
|
5
|
+
*
|
|
6
|
+
* The input is a flat object with an `action` discriminator — not a
|
|
7
|
+
* `z.discriminatedUnion`, which `defineTool` rejects (model tool calling needs a
|
|
8
|
+
* top-level `"type":"object"`). Every per-action parameter is therefore optional
|
|
9
|
+
* in the schema and made conditionally required by `.refine` instead: a
|
|
10
|
+
* malformed call (a `mechanism` with no `chemblId`, a `bioactivity` with no
|
|
11
|
+
* `idType`) fails validation at the loop boundary and comes back to the model as
|
|
12
|
+
* an `is_error` tool result naming the missing field, without reaching `execute`.
|
|
13
|
+
*
|
|
14
|
+
* All request logic is the shared ChEMBL client (`tools/lib/chembl-client.ts`);
|
|
15
|
+
* this file is the routing and the model-facing contract.
|
|
16
|
+
*/
|
|
17
|
+
import type { ChemblActivity, ChemblCompound, ChemblDrug, ChemblMechanism, ChemblTarget } from "../lib/chembl-client.js";
|
|
18
|
+
/** One result shape per action — the key names the records it carries. */
|
|
19
|
+
export type ChemblOutput = {
|
|
20
|
+
readonly compounds: ChemblCompound[];
|
|
21
|
+
} | {
|
|
22
|
+
readonly drugs: ChemblDrug[];
|
|
23
|
+
} | {
|
|
24
|
+
readonly mechanisms: ChemblMechanism[];
|
|
25
|
+
} | {
|
|
26
|
+
readonly activities: ChemblActivity[];
|
|
27
|
+
} | {
|
|
28
|
+
readonly targets: ChemblTarget[];
|
|
29
|
+
};
|
|
30
|
+
export declare const chemblTool: import("../define-tool.js").Tool<{
|
|
31
|
+
action: "targets" | "drug" | "compounds" | "mechanism" | "bioactivity";
|
|
32
|
+
query?: string | undefined;
|
|
33
|
+
searchType?: "target" | "smiles" | "compound" | undefined;
|
|
34
|
+
chemblId?: string | undefined;
|
|
35
|
+
idType?: "target" | "compound" | undefined;
|
|
36
|
+
activityType?: string | undefined;
|
|
37
|
+
limit?: number | undefined;
|
|
38
|
+
}, ChemblOutput>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chembl — one tool over the five ChEMBL lookups: compounds, drugs, mechanisms,
|
|
3
|
+
* bioactivity, targets. "Which database" is the routing decision worth a tool
|
|
4
|
+
* boundary; "which ChEMBL endpoint" is mechanical, so it rides in `action`.
|
|
5
|
+
*
|
|
6
|
+
* The input is a flat object with an `action` discriminator — not a
|
|
7
|
+
* `z.discriminatedUnion`, which `defineTool` rejects (model tool calling needs a
|
|
8
|
+
* top-level `"type":"object"`). Every per-action parameter is therefore optional
|
|
9
|
+
* in the schema and made conditionally required by `.refine` instead: a
|
|
10
|
+
* malformed call (a `mechanism` with no `chemblId`, a `bioactivity` with no
|
|
11
|
+
* `idType`) fails validation at the loop boundary and comes back to the model as
|
|
12
|
+
* an `is_error` tool result naming the missing field, without reaching `execute`.
|
|
13
|
+
*
|
|
14
|
+
* All request logic is the shared ChEMBL client (`tools/lib/chembl-client.ts`);
|
|
15
|
+
* this file is the routing and the model-facing contract.
|
|
16
|
+
*/
|
|
17
|
+
import { ok } from "neverthrow";
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
import { defineTool } from "../define-tool.js";
|
|
20
|
+
import { getBioactivity, getDrugInfo, getMechanism, searchCompounds, searchTargets } from "../lib/chembl-client.js";
|
|
21
|
+
/** Per-action record caps, preserved from the five tools this one replaces. */
|
|
22
|
+
const LIMITS = {
|
|
23
|
+
/** `compounds` / `bioactivity` — activity-scale reads. */
|
|
24
|
+
wide: 500,
|
|
25
|
+
/** `drug` / `targets` — resolution reads, where a long list is noise. */
|
|
26
|
+
narrow: 25,
|
|
27
|
+
};
|
|
28
|
+
const inputSchema = z
|
|
29
|
+
.object({
|
|
30
|
+
action: z
|
|
31
|
+
.enum(["compounds", "drug", "mechanism", "bioactivity", "targets"])
|
|
32
|
+
.describe("Which ChEMBL lookup to run — each names the params it needs and the fields it returns.\n" +
|
|
33
|
+
"'compounds' (query + searchType) — molecules by target, name, or SMILES; resolves a named compound to its ChEMBL ID " +
|
|
34
|
+
"and structure, or lists the compounds assayed against a target. Returns chemblId, preferredCompoundName, " +
|
|
35
|
+
"canonicalSmiles, molecularWeight, alogp, molecularFormula.\n" +
|
|
36
|
+
"'drug' (query) — the drug registry by drug name or disease indication: 'what drugs treat X?', 'is Y approved, and " +
|
|
37
|
+
"since when?'. Returns moleculeChemblId, preferredName, maxPhase (4 = approved), moleculeType (small molecule, " +
|
|
38
|
+
"antibody, …), firstApproval year, indication. When the drug endpoint is empty it falls back to a molecule search " +
|
|
39
|
+
"filtered to max_phase >= 4; rows from that fallback carry indication: null.\n" +
|
|
40
|
+
"'mechanism' (chemblId) — the curated mechanism of action of ONE molecule: 'how does drug X work?'. Returns " +
|
|
41
|
+
"mechanismOfAction (prose), actionType (INHIBITOR, AGONIST, ANTAGONIST, …), targetChemblId + the resolved targetName, " +
|
|
42
|
+
"moleculeChemblId. ChEMBL curates mechanisms mainly for clinical/approved molecules, so tool compounds often have none.\n" +
|
|
43
|
+
"'bioactivity' (chemblId + idType) — measured activity rows (IC50, EC50, Ki, Kd, …): the curated, quotable potency " +
|
|
44
|
+
"data for a compound or a target. Returns standardType, standardValue + standardUnits, pchemblValue (normalized " +
|
|
45
|
+
"-log10 potency), assayChemblId, assayType, compoundChemblId, targetChemblId.\n" +
|
|
46
|
+
"'targets' (query) — resolve a gene symbol or protein name to a ChEMBL target: the step that produces the target ID " +
|
|
47
|
+
"used by bioactivity (idType='target') and compounds (searchType='target'). Returns targetChemblId, preferredName, " +
|
|
48
|
+
"targetType (SINGLE PROTEIN, PROTEIN COMPLEX, …), organism, geneNames. Results span organisms — check `organism` " +
|
|
49
|
+
"before using an ID, since the top hit for a human gene symbol may be a non-human ortholog."),
|
|
50
|
+
query: z
|
|
51
|
+
.string()
|
|
52
|
+
.min(1)
|
|
53
|
+
.optional()
|
|
54
|
+
.describe("Required for 'compounds', 'drug', 'targets'. compounds: must match searchType — a target name/gene symbol or target " +
|
|
55
|
+
"ChEMBL ID, a compound name, or a SMILES string. drug: a drug name (e.g. 'imatinib') or a disease indication " +
|
|
56
|
+
"(e.g. 'melanoma'). targets: a gene symbol (e.g. 'EGFR', 'ABL1'), a protein name, or a ChEMBL target ID."),
|
|
57
|
+
searchType: z
|
|
58
|
+
.enum(["target", "compound", "smiles"])
|
|
59
|
+
.optional()
|
|
60
|
+
.describe("Required for 'compounds' — how to read `query`. 'target': resolve it to a ChEMBL target, then return the compounds " +
|
|
61
|
+
"assayed against that target. 'compound': free-text search over molecule names. 'smiles': flexible (flexmatch) " +
|
|
62
|
+
"structure search on canonical SMILES."),
|
|
63
|
+
chemblId: z
|
|
64
|
+
.string()
|
|
65
|
+
.min(1)
|
|
66
|
+
.optional()
|
|
67
|
+
.describe("Required for 'mechanism' and 'bioactivity'. A ChEMBL molecule ID (e.g. 'CHEMBL25' = aspirin) or — for bioactivity " +
|
|
68
|
+
"with idType='target' — a target ID (e.g. 'CHEMBL203' = EGFR). 'mechanism' takes a molecule ID only, never a target ID."),
|
|
69
|
+
idType: z
|
|
70
|
+
.enum(["compound", "target"])
|
|
71
|
+
.optional()
|
|
72
|
+
.describe("Required for 'bioactivity' — which side of the activity table `chemblId` indexes. 'compound': chemblId is a molecule " +
|
|
73
|
+
"ID; returns everything that molecule was assayed against. 'target': chemblId is a target ID; returns every compound " +
|
|
74
|
+
"assayed against that target."),
|
|
75
|
+
activityType: z
|
|
76
|
+
.string()
|
|
77
|
+
.optional()
|
|
78
|
+
.describe("'bioactivity' only. Exact ChEMBL standard_type filter, e.g. 'IC50', 'EC50', 'Ki', 'Kd'. Matched exactly " +
|
|
79
|
+
"(case-sensitive); omit to get all activity types."),
|
|
80
|
+
limit: z
|
|
81
|
+
.number()
|
|
82
|
+
.int()
|
|
83
|
+
.min(1)
|
|
84
|
+
.max(LIMITS.wide)
|
|
85
|
+
.optional()
|
|
86
|
+
.describe(`Max records. 'compounds'/'bioactivity': 1–${LIMITS.wide} (default ${LIMITS.wide}). 'drug'/'targets': 1–${LIMITS.narrow} ` +
|
|
87
|
+
`(default ${LIMITS.narrow}). Ignored by 'mechanism'. With searchType='target' it caps the activity rows scanned, so ` +
|
|
88
|
+
`fewer unique compounds usually come back.`),
|
|
89
|
+
})
|
|
90
|
+
.refine((d) => !(d.action === "compounds" || d.action === "drug" || d.action === "targets") || (d.query !== undefined && d.query.length > 0), {
|
|
91
|
+
message: "query is required when action is 'compounds', 'drug', or 'targets'",
|
|
92
|
+
path: ["query"],
|
|
93
|
+
})
|
|
94
|
+
.refine((d) => d.action !== "compounds" || d.searchType !== undefined, {
|
|
95
|
+
message: "searchType is required when action is 'compounds' — 'target', 'compound', or 'smiles', matching what `query` holds",
|
|
96
|
+
path: ["searchType"],
|
|
97
|
+
})
|
|
98
|
+
.refine((d) => !(d.action === "mechanism" || d.action === "bioactivity") || (d.chemblId !== undefined && d.chemblId.length > 0), {
|
|
99
|
+
message: "chemblId is required when action is 'mechanism' or 'bioactivity' — a ChEMBL ID, not a name. " +
|
|
100
|
+
"Resolve it first: action='compounds' or 'drug' for a molecule ID, action='targets' for a target ID.",
|
|
101
|
+
path: ["chemblId"],
|
|
102
|
+
})
|
|
103
|
+
.refine((d) => d.action !== "bioactivity" || d.idType !== undefined, {
|
|
104
|
+
message: "idType is required when action is 'bioactivity' — 'compound' if chemblId is a molecule ID, 'target' if it is a target ID",
|
|
105
|
+
path: ["idType"],
|
|
106
|
+
})
|
|
107
|
+
.refine((d) => !(d.action === "drug" || d.action === "targets") || d.limit === undefined || d.limit <= LIMITS.narrow, {
|
|
108
|
+
message: `limit is capped at ${LIMITS.narrow} for action 'drug' and 'targets' (only 'compounds' and 'bioactivity' reach ${LIMITS.wide})`,
|
|
109
|
+
path: ["limit"],
|
|
110
|
+
});
|
|
111
|
+
export const chemblTool = defineTool({
|
|
112
|
+
id: "chembl",
|
|
113
|
+
description: "ChEMBL — the manually curated database of drug-like bioactives (~2.4M compounds), the targets they were measured " +
|
|
114
|
+
"against, their mechanisms, and their approval status. One tool, five lookups; pick with `action` (its description gives " +
|
|
115
|
+
"each action's params and return fields).\n" +
|
|
116
|
+
"IDs are resolved, never guessed: a `chemblId` comes from a prior action='compounds'/'drug' (molecule IDs) or action='targets' " +
|
|
117
|
+
"(target IDs) call, or from pubchem action='crossrefs' — a compound or gene name is not a ChEMBL ID.\n" +
|
|
118
|
+
"ChEMBL is curated, so prefer it over PubChem for anything you will quote or build on: use action='bioactivity' rather than " +
|
|
119
|
+
"pubchem action='assays' whenever you will quote a number (PubChem assay summaries are broader HTS screening outcomes), and resolve " +
|
|
120
|
+
"compounds here first. If ChEMBL does not find the compound, resolve it in PubChem with pubchem action='compound' and bridge back " +
|
|
121
|
+
"to a ChEMBL ID via pubchem action='crossrefs'.\n" +
|
|
122
|
+
"An empty array is a valid 'no match' / no-data answer, not an error — do not retry the same call.",
|
|
123
|
+
inputSchema,
|
|
124
|
+
execute: async ({ action, query, searchType, chemblId, idType, activityType, limit }) => {
|
|
125
|
+
switch (action) {
|
|
126
|
+
case "compounds":
|
|
127
|
+
return ok({ compounds: await searchCompounds(query, searchType, limit ?? LIMITS.wide) });
|
|
128
|
+
case "drug":
|
|
129
|
+
return ok({ drugs: await getDrugInfo(query, limit ?? LIMITS.narrow) });
|
|
130
|
+
case "mechanism":
|
|
131
|
+
return ok({ mechanisms: await getMechanism(chemblId) });
|
|
132
|
+
case "bioactivity":
|
|
133
|
+
return ok({ activities: await getBioactivity(chemblId, idType, { activityType, limit: limit ?? LIMITS.wide }) });
|
|
134
|
+
case "targets":
|
|
135
|
+
return ok({ targets: await searchTargets(query, limit ?? LIMITS.narrow) });
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* comptox — the single EPA CompTox (CTX) tool: ToxCast/Tox21 bioactivity,
|
|
3
|
+
* in-vivo hazard, chemical identity + physchem, and exposure behind one
|
|
4
|
+
* `dataset` discriminator.
|
|
5
|
+
*
|
|
6
|
+
* All four datasets key off the same chemical resolution and the same
|
|
7
|
+
* EPA_CCTE_API_KEY, so the key contract is stated once in the description
|
|
8
|
+
* rather than four times.
|
|
9
|
+
*
|
|
10
|
+
* The input is a flat object with a `dataset` discriminator — not a
|
|
11
|
+
* `z.discriminatedUnion`, which `defineTool` rejects (the model needs a
|
|
12
|
+
* top-level `"type":"object"`). `dataType` and `limit` mean different things
|
|
13
|
+
* per dataset, so `.refine` guards reject a value that belongs to another
|
|
14
|
+
* dataset (a 'toxval' under dataset 'exposure' would otherwise silently fetch
|
|
15
|
+
* nothing) and a limit above the dataset's own ceiling.
|
|
16
|
+
*/
|
|
17
|
+
import { type ChemicalDetail, type CtxExposureData, type CtxHazardData, type PropertySummary, type ToxcastBioactivity } from "../lib/ctx-ops.js";
|
|
18
|
+
type ComptoxOutput = {
|
|
19
|
+
found: false;
|
|
20
|
+
query: string;
|
|
21
|
+
} | {
|
|
22
|
+
found: true;
|
|
23
|
+
chemical: {
|
|
24
|
+
dtxsid: string;
|
|
25
|
+
preferredName: string;
|
|
26
|
+
casrn: string | null;
|
|
27
|
+
} & ToxcastBioactivity;
|
|
28
|
+
} | ({
|
|
29
|
+
found: true;
|
|
30
|
+
dtxsid: string;
|
|
31
|
+
preferredName: string;
|
|
32
|
+
} & CtxHazardData) | {
|
|
33
|
+
found: true;
|
|
34
|
+
detail: ChemicalDetail;
|
|
35
|
+
properties?: PropertySummary[];
|
|
36
|
+
} | ({
|
|
37
|
+
found: true;
|
|
38
|
+
dtxsid: string;
|
|
39
|
+
} & CtxExposureData);
|
|
40
|
+
export declare function createComptoxTool(deps: {
|
|
41
|
+
apiKey: string;
|
|
42
|
+
}): import("../define-tool.js").Tool<{
|
|
43
|
+
dataset: "toxcast" | "hazard" | "chemical" | "exposure";
|
|
44
|
+
query: string;
|
|
45
|
+
dataType?: "toxval" | "genetox" | "cancer" | "all" | "seem" | "httk" | "functional-use" | "product-data" | undefined;
|
|
46
|
+
activeOnly?: boolean | undefined;
|
|
47
|
+
includeProperties?: boolean | undefined;
|
|
48
|
+
limit?: number | undefined;
|
|
49
|
+
}, ComptoxOutput>;
|
|
50
|
+
export {};
|