@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
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Render an AnalysisStep into the user-content prompt the sandbox agent
|
|
3
|
-
* receives as its initial message.
|
|
4
|
-
*
|
|
5
|
-
* The planner writes the bulk of a step's instructions into structured
|
|
6
|
-
* fields (`constraints`, `acceptance_criteria`, `context`, `caveats`,
|
|
7
|
-
* `description`) alongside the one-line `question`. The execution path
|
|
8
|
-
* forwards a single `prompt` string to the sandbox agent, so every
|
|
9
|
-
* instruction-bearing field must be folded into that string here — otherwise
|
|
10
|
-
* the agent runs against the bare question and improvises the rest.
|
|
11
|
-
*
|
|
12
|
-
* `STEP_PROMPT_INSTRUCTION_FIELDS` / `STEP_PROMPT_NON_INSTRUCTION_FIELDS`
|
|
13
|
-
* partition every AnalysisStep field so the field-coverage guard test can
|
|
14
|
-
* fail when a new field is added to the schema without a deliberate decision
|
|
15
|
-
* about whether the agent needs to see it.
|
|
16
|
-
*/
|
|
17
|
-
/** Fields whose content is agent-facing and MUST appear in the rendered prompt. */
|
|
18
|
-
export const STEP_PROMPT_INSTRUCTION_FIELDS = [
|
|
19
|
-
"name",
|
|
20
|
-
"question",
|
|
21
|
-
"description",
|
|
22
|
-
"context",
|
|
23
|
-
"constraints",
|
|
24
|
-
"acceptance_criteria",
|
|
25
|
-
"caveats",
|
|
26
|
-
];
|
|
27
|
-
/**
|
|
28
|
-
* Fields deliberately excluded from the prompt: identity/DAG structure
|
|
29
|
-
* threaded separately through the workflow input, execution knobs, and
|
|
30
|
-
* result fields populated after the step runs.
|
|
31
|
-
*/
|
|
32
|
-
export const STEP_PROMPT_NON_INSTRUCTION_FIELDS = [
|
|
33
|
-
"id",
|
|
34
|
-
"track",
|
|
35
|
-
"step_type",
|
|
36
|
-
"depends_on",
|
|
37
|
-
"status",
|
|
38
|
-
"resources",
|
|
39
|
-
"agent",
|
|
40
|
-
"timeout",
|
|
41
|
-
"maxSteps",
|
|
42
|
-
"summary",
|
|
43
|
-
"artifactIds",
|
|
44
|
-
"error",
|
|
45
|
-
];
|
|
46
|
-
function section(heading, body) {
|
|
47
|
-
return `## ${heading}\n${body}`;
|
|
48
|
-
}
|
|
49
|
-
function bullets(items) {
|
|
50
|
-
return items.map((i) => `- ${i}`).join("\n");
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Compose the agent's initial prompt from a plan step. Only the `question`
|
|
54
|
-
* is guaranteed present; the remaining instruction fields are appended as
|
|
55
|
-
* dedicated sections when populated. Empty strings and empty arrays are
|
|
56
|
-
* skipped so a sparse step renders cleanly.
|
|
57
|
-
*/
|
|
58
|
-
export function renderStepPrompt(step) {
|
|
59
|
-
const parts = [`# ${step.name}`, section("Task", step.question)];
|
|
60
|
-
if (step.description?.trim()) {
|
|
61
|
-
parts.push(section("What this step produces", step.description.trim()));
|
|
62
|
-
}
|
|
63
|
-
if (step.context?.trim()) {
|
|
64
|
-
parts.push(section("Context", step.context.trim()));
|
|
65
|
-
}
|
|
66
|
-
if (step.constraints && step.constraints.length > 0) {
|
|
67
|
-
parts.push(section("Constraints (these are requirements, not suggestions — follow them exactly)", bullets(step.constraints)));
|
|
68
|
-
}
|
|
69
|
-
if (step.acceptance_criteria && step.acceptance_criteria.length > 0) {
|
|
70
|
-
parts.push(section("Acceptance criteria (the result must satisfy all of these)", bullets(step.acceptance_criteria)));
|
|
71
|
-
}
|
|
72
|
-
if (step.caveats && step.caveats.length > 0) {
|
|
73
|
-
parts.push(section("Caveats", bullets(step.caveats)));
|
|
74
|
-
}
|
|
75
|
-
return parts.join("\n\n");
|
|
76
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* findApprovalPrecedent — query openFDA / Drugs@FDA for prior approvals in a
|
|
3
|
-
* given indication.
|
|
4
|
-
*/
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
export declare const findApprovalPrecedentInputSchema: z.ZodObject<{
|
|
7
|
-
indication: z.ZodString;
|
|
8
|
-
modality: z.ZodOptional<z.ZodEnum<{
|
|
9
|
-
small_molecule: "small_molecule";
|
|
10
|
-
biologic: "biologic";
|
|
11
|
-
gene_therapy: "gene_therapy";
|
|
12
|
-
cell_therapy: "cell_therapy";
|
|
13
|
-
}>>;
|
|
14
|
-
mechanism: z.ZodOptional<z.ZodString>;
|
|
15
|
-
}, z.core.$strip>;
|
|
16
|
-
interface Precedent {
|
|
17
|
-
application_number: string;
|
|
18
|
-
brand_name?: string;
|
|
19
|
-
generic_name?: string;
|
|
20
|
-
approval_date?: string;
|
|
21
|
-
label_section_excerpts?: Record<string, string>;
|
|
22
|
-
}
|
|
23
|
-
export declare const findApprovalPrecedent: import("../define-tool.js").Tool<{
|
|
24
|
-
indication: string;
|
|
25
|
-
modality?: "small_molecule" | "biologic" | "gene_therapy" | "cell_therapy" | undefined;
|
|
26
|
-
mechanism?: string | undefined;
|
|
27
|
-
}, {
|
|
28
|
-
precedents: Precedent[];
|
|
29
|
-
}>;
|
|
30
|
-
/** Test-only — clears the in-memory cache to avoid cross-test bleed. */
|
|
31
|
-
export declare function __resetApprovalPrecedentCacheForTest(): void;
|
|
32
|
-
export {};
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* findApprovalPrecedent — query openFDA / Drugs@FDA for prior approvals in a
|
|
3
|
-
* given indication.
|
|
4
|
-
*/
|
|
5
|
-
import { ok } from "neverthrow";
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
import { defineTool } from "../define-tool.js";
|
|
8
|
-
export const findApprovalPrecedentInputSchema = z.object({
|
|
9
|
-
indication: z.string().min(1).describe("Indication / disease name — searched against openFDA label.indications_and_usage"),
|
|
10
|
-
modality: z
|
|
11
|
-
.enum(["small_molecule", "biologic", "gene_therapy", "cell_therapy"])
|
|
12
|
-
.optional()
|
|
13
|
-
.describe("Optional modality hint (advisory; not used for filtering today)"),
|
|
14
|
-
mechanism: z.string().optional().describe("Optional MoA / mechanism hint (advisory; not used for filtering today)"),
|
|
15
|
-
});
|
|
16
|
-
const cache = new Map();
|
|
17
|
-
const TTL_MS = 60 * 60 * 1000;
|
|
18
|
-
export const findApprovalPrecedent = defineTool({
|
|
19
|
-
id: "find_approval_precedent",
|
|
20
|
-
description: "Query openFDA / Drugs@FDA for prior approvals in a given indication. Returns NDA/BLA application numbers, generic and brand names, approval dates (effective time of the label), and label-section excerpts (boxed warning, warnings and precautions, contraindications). Use to ground class-precedent claims and disposition framing in the executive recommendation.",
|
|
21
|
-
inputSchema: findApprovalPrecedentInputSchema,
|
|
22
|
-
execute: async ({ indication, modality, mechanism }) => {
|
|
23
|
-
const key = JSON.stringify({
|
|
24
|
-
indication: indication.toLowerCase(),
|
|
25
|
-
modality,
|
|
26
|
-
mechanism,
|
|
27
|
-
});
|
|
28
|
-
const cached = cache.get(key);
|
|
29
|
-
if (cached && Date.now() - cached.ts < TTL_MS)
|
|
30
|
-
return ok(cached.value);
|
|
31
|
-
const term = indication.replace(/"/g, "");
|
|
32
|
-
const url = new URL("https://api.fda.gov/drug/label.json");
|
|
33
|
-
url.searchParams.set("search", `indications_and_usage:"${term}"`);
|
|
34
|
-
url.searchParams.set("limit", "10");
|
|
35
|
-
const res = await fetch(url);
|
|
36
|
-
// openFDA answers a zero-match search with 404 — an expected "no
|
|
37
|
-
// precedents" outcome, not a failure. It is returned uncached so a
|
|
38
|
-
// later, more specific query is not masked. Any other non-ok status
|
|
39
|
-
// (5xx, 429) is an unexpected failure and throws.
|
|
40
|
-
if (res.status === 404)
|
|
41
|
-
return ok({ precedents: [] });
|
|
42
|
-
if (!res.ok) {
|
|
43
|
-
throw new Error(`openFDA label query failed: HTTP ${res.status}`);
|
|
44
|
-
}
|
|
45
|
-
const json = (await res.json());
|
|
46
|
-
const precedents = (json.results ?? []).slice(0, 10).map((r) => {
|
|
47
|
-
const excerpts = {};
|
|
48
|
-
if (r.boxed_warning?.[0])
|
|
49
|
-
excerpts.boxed_warning = r.boxed_warning[0].slice(0, 1000);
|
|
50
|
-
if (r.warnings_and_precautions?.[0])
|
|
51
|
-
excerpts.warnings_and_precautions = r.warnings_and_precautions[0].slice(0, 1000);
|
|
52
|
-
else if (r.warnings?.[0])
|
|
53
|
-
excerpts.warnings = r.warnings[0].slice(0, 1000);
|
|
54
|
-
if (r.contraindications?.[0])
|
|
55
|
-
excerpts.contraindications = r.contraindications[0].slice(0, 1000);
|
|
56
|
-
return {
|
|
57
|
-
application_number: r.openfda?.application_number?.[0] ?? "(unknown)",
|
|
58
|
-
brand_name: r.openfda?.brand_name?.[0],
|
|
59
|
-
generic_name: r.openfda?.generic_name?.[0],
|
|
60
|
-
approval_date: r.effective_time,
|
|
61
|
-
label_section_excerpts: Object.keys(excerpts).length > 0 ? excerpts : undefined,
|
|
62
|
-
};
|
|
63
|
-
});
|
|
64
|
-
const value = { precedents };
|
|
65
|
-
cache.set(key, { ts: Date.now(), value });
|
|
66
|
-
return ok(value);
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
/** Test-only — clears the in-memory cache to avoid cross-test bleed. */
|
|
70
|
-
export function __resetApprovalPrecedentCacheForTest() {
|
|
71
|
-
cache.clear();
|
|
72
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getArticleDetails — fetch detailed metadata for PubMed articles.
|
|
3
|
-
*/
|
|
4
|
-
export declare function createGetArticleDetailsTool(deps: {
|
|
5
|
-
ncbiApiKey?: string;
|
|
6
|
-
}): import("../define-tool.js").Tool<{
|
|
7
|
-
pmids: string[];
|
|
8
|
-
}, {
|
|
9
|
-
articles: import("../lib/ncbi-utils.js").ArticleDetail[];
|
|
10
|
-
notFound: string[];
|
|
11
|
-
}>;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getArticleDetails — fetch detailed metadata for PubMed articles.
|
|
3
|
-
*/
|
|
4
|
-
import { ok } from "neverthrow";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { defineTool } from "../define-tool.js";
|
|
7
|
-
import { getArticleDetails } from "../lib/pubmed-client.js";
|
|
8
|
-
export function createGetArticleDetailsTool(deps) {
|
|
9
|
-
return defineTool({
|
|
10
|
-
id: "get_article_details",
|
|
11
|
-
description: "Fetch detailed metadata for PubMed articles by PMID. " +
|
|
12
|
-
"Returns title, full abstract, authors, journal, year, DOI, MeSH terms, " +
|
|
13
|
-
"and PMC ID (if open-access full text is available in PubMed Central). " +
|
|
14
|
-
"Accepts up to 20 PMIDs per call for batch retrieval.",
|
|
15
|
-
inputSchema: z.object({
|
|
16
|
-
pmids: z.array(z.string()).min(1).max(20).describe("PubMed IDs to fetch details for (max 20)"),
|
|
17
|
-
}),
|
|
18
|
-
execute: async ({ pmids }) => ok(await getArticleDetails(deps.ncbiApiKey, pmids)),
|
|
19
|
-
});
|
|
20
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getArticleFullText — fetch full text of open-access articles from PMC.
|
|
3
|
-
*/
|
|
4
|
-
import type { ArticleSection } from "../lib/ncbi-utils.js";
|
|
5
|
-
type FullTextResult = {
|
|
6
|
-
pmcId: string;
|
|
7
|
-
available: false;
|
|
8
|
-
} | {
|
|
9
|
-
pmcId: string;
|
|
10
|
-
available: true;
|
|
11
|
-
fullText: string;
|
|
12
|
-
sections: ArticleSection[];
|
|
13
|
-
};
|
|
14
|
-
export declare function createGetArticleFullTextTool(deps: {
|
|
15
|
-
ncbiApiKey?: string;
|
|
16
|
-
}): import("../define-tool.js").Tool<{
|
|
17
|
-
pmcId: string;
|
|
18
|
-
}, FullTextResult>;
|
|
19
|
-
export {};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getArticleFullText — fetch full text of open-access articles from PMC.
|
|
3
|
-
*/
|
|
4
|
-
import { ok } from "neverthrow";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { defineTool } from "../define-tool.js";
|
|
7
|
-
import { getArticleFullText } from "../lib/pubmed-client.js";
|
|
8
|
-
export function createGetArticleFullTextTool(deps) {
|
|
9
|
-
return defineTool({
|
|
10
|
-
id: "get_article_full_text",
|
|
11
|
-
description: "Fetch the full text of an open-access article from PubMed Central (PMC). " +
|
|
12
|
-
"Accepts a PMC ID (e.g., 'PMC1234567') as returned by getArticleDetails. " +
|
|
13
|
-
"Returns the article body as plain text with section headers preserved. " +
|
|
14
|
-
"Only works for open-access articles available in PMC — check the pmcId " +
|
|
15
|
-
"field from getArticleDetails before calling this tool.",
|
|
16
|
-
inputSchema: z.object({
|
|
17
|
-
pmcId: z.string().describe('PubMed Central ID (e.g., "PMC1234567")'),
|
|
18
|
-
}),
|
|
19
|
-
execute: async ({ pmcId }) => {
|
|
20
|
-
const parsed = await getArticleFullText(deps.ncbiApiKey, pmcId);
|
|
21
|
-
// "Not open-access" is an expected outcome — a data variant, not an error.
|
|
22
|
-
if (!parsed)
|
|
23
|
-
return ok({ pmcId, available: false });
|
|
24
|
-
return ok({
|
|
25
|
-
pmcId,
|
|
26
|
-
available: true,
|
|
27
|
-
fullText: parsed.fullText,
|
|
28
|
-
sections: parsed.sections,
|
|
29
|
-
});
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getBioactivity tool — retrieve bioactivity data (IC50, EC50, Ki) from ChEMBL.
|
|
3
|
-
*/
|
|
4
|
-
export declare const getBioactivityTool: import("../define-tool.js").Tool<{
|
|
5
|
-
chemblId: string;
|
|
6
|
-
type: "target" | "compound";
|
|
7
|
-
limit: number;
|
|
8
|
-
activityType?: string | undefined;
|
|
9
|
-
}, {
|
|
10
|
-
activities: import("../lib/chembl-client.js").ChemblActivity[];
|
|
11
|
-
}>;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getBioactivity tool — retrieve bioactivity data (IC50, EC50, Ki) from ChEMBL.
|
|
3
|
-
*/
|
|
4
|
-
import { ok } from "neverthrow";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { defineTool } from "../define-tool.js";
|
|
7
|
-
import { getBioactivity } from "../lib/chembl-client.js";
|
|
8
|
-
export const getBioactivityTool = defineTool({
|
|
9
|
-
id: "get_bioactivity",
|
|
10
|
-
description: "Get bioactivity data (IC50, EC50, Ki, etc.) from ChEMBL for a compound or target. " +
|
|
11
|
-
"Returns activity values, assay information, and pChEMBL values. " +
|
|
12
|
-
"Optionally filter by activity type (e.g. 'IC50', 'EC50', 'Ki').",
|
|
13
|
-
inputSchema: z.object({
|
|
14
|
-
chemblId: z.string().min(1).describe("ChEMBL ID (e.g. 'CHEMBL25' for aspirin, 'CHEMBL203' for EGFR target)"),
|
|
15
|
-
type: z.enum(["compound", "target"]).describe("Whether the ChEMBL ID refers to a compound or a target"),
|
|
16
|
-
activityType: z.string().optional().describe("Filter by standard_type (e.g. 'IC50', 'EC50', 'Ki')"),
|
|
17
|
-
limit: z.number().int().min(1).max(500).default(500).describe("Maximum number of activity records to return"),
|
|
18
|
-
}),
|
|
19
|
-
execute: async ({ chemblId, type, activityType, limit }) => {
|
|
20
|
-
const activities = await getBioactivity(chemblId, type, { activityType, limit });
|
|
21
|
-
return ok({ activities });
|
|
22
|
-
},
|
|
23
|
-
});
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getDrugInfo tool — search ChEMBL for approved drugs by indication or name.
|
|
3
|
-
*/
|
|
4
|
-
export declare const getDrugInfoTool: import("../define-tool.js").Tool<{
|
|
5
|
-
query: string;
|
|
6
|
-
limit: number;
|
|
7
|
-
}, {
|
|
8
|
-
drugs: import("../lib/chembl-client.js").ChemblDrug[];
|
|
9
|
-
}>;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getDrugInfo tool — search ChEMBL for approved drugs by indication or name.
|
|
3
|
-
*/
|
|
4
|
-
import { ok } from "neverthrow";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { defineTool } from "../define-tool.js";
|
|
7
|
-
import { getDrugInfo } from "../lib/chembl-client.js";
|
|
8
|
-
export const getDrugInfoTool = defineTool({
|
|
9
|
-
id: "get_drug_info",
|
|
10
|
-
description: "Search ChEMBL for approved drugs by indication or drug name. " +
|
|
11
|
-
"Returns drug metadata including approval phase, molecule type, " +
|
|
12
|
-
"first approval year, and indications. Falls back to molecule search " +
|
|
13
|
-
"filtered by max_phase >= 4 if the drug endpoint yields no results.",
|
|
14
|
-
inputSchema: z.object({
|
|
15
|
-
query: z.string().min(1).describe("Drug name or indication to search for (e.g. 'imatinib', 'breast cancer')"),
|
|
16
|
-
limit: z.number().int().min(1).max(25).default(25).describe("Maximum number of results to return"),
|
|
17
|
-
}),
|
|
18
|
-
execute: async ({ query, limit }) => {
|
|
19
|
-
const drugs = await getDrugInfo(query, limit);
|
|
20
|
-
return ok({ drugs });
|
|
21
|
-
},
|
|
22
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getMechanism tool — retrieve mechanism of action data from ChEMBL.
|
|
3
|
-
*/
|
|
4
|
-
import { ok } from "neverthrow";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { defineTool } from "../define-tool.js";
|
|
7
|
-
import { getMechanism } from "../lib/chembl-client.js";
|
|
8
|
-
export const getMechanismTool = defineTool({
|
|
9
|
-
id: "get_mechanism",
|
|
10
|
-
description: "Get mechanism of action for a compound from ChEMBL. " + "Returns mechanism descriptions, action types, and associated target information.",
|
|
11
|
-
inputSchema: z.object({
|
|
12
|
-
chemblId: z.string().min(1).describe("Compound ChEMBL ID (e.g. 'CHEMBL25' for aspirin)"),
|
|
13
|
-
}),
|
|
14
|
-
execute: async ({ chemblId }) => {
|
|
15
|
-
const mechanisms = await getMechanism(chemblId);
|
|
16
|
-
return ok({ mechanisms });
|
|
17
|
-
},
|
|
18
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getPubchemAssays tool — retrieve bioassay screening summaries for a PubChem CID.
|
|
3
|
-
*
|
|
4
|
-
* Returns per-assay activity outcomes (active/inactive/inconclusive),
|
|
5
|
-
* target names, and assay descriptions. Broader coverage than ChEMBL's
|
|
6
|
-
* curated bioactivity data.
|
|
7
|
-
*/
|
|
8
|
-
interface Assay {
|
|
9
|
-
aid: number;
|
|
10
|
-
assayName: string | null;
|
|
11
|
-
targetName: string | null;
|
|
12
|
-
activityOutcome: string | null;
|
|
13
|
-
activityValue: number | null;
|
|
14
|
-
}
|
|
15
|
-
export declare const getPubchemAssaysTool: import("../define-tool.js").Tool<{
|
|
16
|
-
cid: number;
|
|
17
|
-
activeOnly: boolean;
|
|
18
|
-
limit: number;
|
|
19
|
-
}, {
|
|
20
|
-
assays: Assay[];
|
|
21
|
-
}>;
|
|
22
|
-
export {};
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getPubchemAssays tool — retrieve bioassay screening summaries for a PubChem CID.
|
|
3
|
-
*
|
|
4
|
-
* Returns per-assay activity outcomes (active/inactive/inconclusive),
|
|
5
|
-
* target names, and assay descriptions. Broader coverage than ChEMBL's
|
|
6
|
-
* curated bioactivity data.
|
|
7
|
-
*/
|
|
8
|
-
import { ok } from "neverthrow";
|
|
9
|
-
import { z } from "zod";
|
|
10
|
-
import { defineTool } from "../define-tool.js";
|
|
11
|
-
import { apiFetchValidated, describeApiError } from "../lib/api-utils.js";
|
|
12
|
-
import { PUBCHEM_HEADERS as HEADERS, PUBCHEM_BASE } from "../lib/pubchem-config.js";
|
|
13
|
-
// The PUG-REST assay-summary wire shape (a table of columns + rows), validated
|
|
14
|
-
// at the fetch boundary; `parseAssaySummary` maps the heading-indexed cells into
|
|
15
|
-
// `Assay` records. Every field is optional — PubChem omits absent values.
|
|
16
|
-
const PugAssaySummarySchema = z.object({
|
|
17
|
-
Table: z
|
|
18
|
-
.object({
|
|
19
|
-
Columns: z
|
|
20
|
-
.object({
|
|
21
|
-
Column: z.array(z.object({ Heading: z.string().optional() })).optional(),
|
|
22
|
-
})
|
|
23
|
-
.optional(),
|
|
24
|
-
Row: z
|
|
25
|
-
.array(z.object({
|
|
26
|
-
Cell: z
|
|
27
|
-
.array(z.object({
|
|
28
|
-
intval: z.number().optional(),
|
|
29
|
-
fval: z.number().optional(),
|
|
30
|
-
sval: z.string().optional(),
|
|
31
|
-
}))
|
|
32
|
-
.optional(),
|
|
33
|
-
}))
|
|
34
|
-
.optional(),
|
|
35
|
-
})
|
|
36
|
-
.optional(),
|
|
37
|
-
});
|
|
38
|
-
function parseAssaySummary(data) {
|
|
39
|
-
const columns = data.Table?.Columns?.Column ?? [];
|
|
40
|
-
const rows = data.Table?.Row ?? [];
|
|
41
|
-
// Find column indices by heading
|
|
42
|
-
const headingIndex = new Map();
|
|
43
|
-
for (let i = 0; i < columns.length; i++) {
|
|
44
|
-
if (columns[i].Heading) {
|
|
45
|
-
headingIndex.set(columns[i].Heading, i);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
const aidIdx = headingIndex.get("AID");
|
|
49
|
-
const nameIdx = headingIndex.get("AssayName");
|
|
50
|
-
const targetIdx = headingIndex.get("TargetName");
|
|
51
|
-
const outcomeIdx = headingIndex.get("ActivityOutcome");
|
|
52
|
-
const valueIdx = headingIndex.get("ActivityValue");
|
|
53
|
-
const results = [];
|
|
54
|
-
for (const row of rows) {
|
|
55
|
-
const cells = row.Cell ?? [];
|
|
56
|
-
const getCellStr = (idx) => {
|
|
57
|
-
if (idx === undefined || idx >= cells.length)
|
|
58
|
-
return null;
|
|
59
|
-
return cells[idx]?.sval ?? null;
|
|
60
|
-
};
|
|
61
|
-
const getCellNum = (idx) => {
|
|
62
|
-
if (idx === undefined || idx >= cells.length)
|
|
63
|
-
return null;
|
|
64
|
-
const cell = cells[idx];
|
|
65
|
-
if (cell?.fval !== undefined)
|
|
66
|
-
return cell.fval;
|
|
67
|
-
if (cell?.intval !== undefined)
|
|
68
|
-
return cell.intval;
|
|
69
|
-
return null;
|
|
70
|
-
};
|
|
71
|
-
results.push({
|
|
72
|
-
aid: getCellNum(aidIdx) ?? 0,
|
|
73
|
-
assayName: getCellStr(nameIdx),
|
|
74
|
-
targetName: getCellStr(targetIdx),
|
|
75
|
-
activityOutcome: getCellStr(outcomeIdx),
|
|
76
|
-
activityValue: getCellNum(valueIdx),
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
return results;
|
|
80
|
-
}
|
|
81
|
-
export const getPubchemAssaysTool = defineTool({
|
|
82
|
-
id: "get_pubchem_assays",
|
|
83
|
-
description: "Get bioassay screening summaries for a PubChem CID. " +
|
|
84
|
-
"Returns per-assay activity outcomes (Active/Inactive/Inconclusive), target names, " +
|
|
85
|
-
"and activity values. Covers HTS screening data beyond ChEMBL's curated bioactivity. " +
|
|
86
|
-
"Use activeOnly=true to filter for active results only.",
|
|
87
|
-
inputSchema: z.object({
|
|
88
|
-
cid: z.number().int().positive().describe("PubChem Compound ID (CID)"),
|
|
89
|
-
activeOnly: z.boolean().default(false).describe("If true, return only assays where the compound was active"),
|
|
90
|
-
limit: z.number().int().min(1).max(500).default(50).describe("Maximum number of assay records to return"),
|
|
91
|
-
}),
|
|
92
|
-
execute: async ({ cid, activeOnly = false, limit = 50 }) => {
|
|
93
|
-
const url = `${PUBCHEM_BASE}/compound/cid/${cid}/assaysummary/JSON`;
|
|
94
|
-
const res = await apiFetchValidated(url, PugAssaySummarySchema, { headers: HEADERS });
|
|
95
|
-
if (res.isErr()) {
|
|
96
|
-
// PubChem returns 404 when the CID has no assay data — expected.
|
|
97
|
-
if (res.error.type === "http_status" && res.error.status === 404)
|
|
98
|
-
return ok({ assays: [] });
|
|
99
|
-
throw new Error(describeApiError(res.error));
|
|
100
|
-
}
|
|
101
|
-
let assays = parseAssaySummary(res.value);
|
|
102
|
-
if (activeOnly) {
|
|
103
|
-
assays = assays.filter((a) => a.activityOutcome?.toLowerCase() === "active");
|
|
104
|
-
}
|
|
105
|
-
return ok({ assays: assays.slice(0, limit) });
|
|
106
|
-
},
|
|
107
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getPubchemCrossRefs tool — retrieve external database identifiers for a PubChem CID.
|
|
3
|
-
*
|
|
4
|
-
* Bridges PubChem compounds to ChEMBL, DrugBank, KEGG, PDB, and other registries.
|
|
5
|
-
*/
|
|
6
|
-
interface CrossRefEntry {
|
|
7
|
-
source: string;
|
|
8
|
-
id: string;
|
|
9
|
-
}
|
|
10
|
-
export declare const getPubchemCrossRefsTool: import("../define-tool.js").Tool<{
|
|
11
|
-
cid: number;
|
|
12
|
-
}, {
|
|
13
|
-
crossRefs: CrossRefEntry[];
|
|
14
|
-
}>;
|
|
15
|
-
export {};
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getPubchemCrossRefs tool — retrieve external database identifiers for a PubChem CID.
|
|
3
|
-
*
|
|
4
|
-
* Bridges PubChem compounds to ChEMBL, DrugBank, KEGG, PDB, and other registries.
|
|
5
|
-
*/
|
|
6
|
-
import { ok } from "neverthrow";
|
|
7
|
-
import { z } from "zod";
|
|
8
|
-
import { defineTool } from "../define-tool.js";
|
|
9
|
-
import { apiFetchValidated, describeApiError } from "../lib/api-utils.js";
|
|
10
|
-
import { PUBCHEM_HEADERS as HEADERS, PUBCHEM_BASE } from "../lib/pubchem-config.js";
|
|
11
|
-
// The PUG-REST xrefs wire shape, validated at the fetch boundary: one
|
|
12
|
-
// `Information` entry per CID with parallel `RegistryID[]` / `SourceName[]`
|
|
13
|
-
// arrays. Every field is optional — PubChem omits absent values.
|
|
14
|
-
const PubChemXrefResponseSchema = z.object({
|
|
15
|
-
InformationList: z
|
|
16
|
-
.object({
|
|
17
|
-
Information: z
|
|
18
|
-
.array(z.object({
|
|
19
|
-
CID: z.number().optional(),
|
|
20
|
-
RegistryID: z.array(z.string()).optional(),
|
|
21
|
-
SourceName: z.array(z.string()).optional(),
|
|
22
|
-
}))
|
|
23
|
-
.optional(),
|
|
24
|
-
})
|
|
25
|
-
.optional(),
|
|
26
|
-
});
|
|
27
|
-
function mapCrossRef(raw) {
|
|
28
|
-
return {
|
|
29
|
-
source: raw.SourceName ?? "Unknown",
|
|
30
|
-
id: raw.RegistryID ?? "",
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
export const getPubchemCrossRefsTool = defineTool({
|
|
34
|
-
id: "get_pubchem_cross_refs",
|
|
35
|
-
description: "Get external database cross-references for a PubChem CID. " +
|
|
36
|
-
"Returns linked identifiers from ChEMBL, DrugBank, KEGG, PDB, and other registries. " +
|
|
37
|
-
"Use this to bridge PubChem compounds to other databases (e.g., get ChEMBL ID to then " +
|
|
38
|
-
"query bioactivity via ChEMBL tools).",
|
|
39
|
-
inputSchema: z.object({
|
|
40
|
-
cid: z.number().int().positive().describe("PubChem Compound ID (CID)"),
|
|
41
|
-
}),
|
|
42
|
-
execute: async ({ cid }) => {
|
|
43
|
-
const url = `${PUBCHEM_BASE}/compound/cid/${cid}/xrefs/RegistryID,SourceName/JSON`;
|
|
44
|
-
const res = await apiFetchValidated(url, PubChemXrefResponseSchema, { headers: HEADERS });
|
|
45
|
-
if (res.isErr()) {
|
|
46
|
-
// PubChem returns 404 when the CID has no cross-references — expected.
|
|
47
|
-
if (res.error.type === "http_status" && res.error.status === 404)
|
|
48
|
-
return ok({ crossRefs: [] });
|
|
49
|
-
throw new Error(describeApiError(res.error));
|
|
50
|
-
}
|
|
51
|
-
// PUG-REST xrefs returns an InformationList with one entry per CID.
|
|
52
|
-
// Each entry has parallel RegistryID[] and SourceName[] arrays.
|
|
53
|
-
const info = res.value.InformationList?.Information?.[0];
|
|
54
|
-
if (!info?.RegistryID?.length) {
|
|
55
|
-
return ok({ crossRefs: [] });
|
|
56
|
-
}
|
|
57
|
-
const crossRefs = [];
|
|
58
|
-
const registryIds = info.RegistryID;
|
|
59
|
-
const sourceNames = info.SourceName ?? [];
|
|
60
|
-
for (let i = 0; i < registryIds.length; i++) {
|
|
61
|
-
crossRefs.push(mapCrossRef({
|
|
62
|
-
RegistryID: registryIds[i],
|
|
63
|
-
SourceName: sourceNames[i],
|
|
64
|
-
}));
|
|
65
|
-
}
|
|
66
|
-
return ok({ crossRefs });
|
|
67
|
-
},
|
|
68
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getTargetSafety — fetch known safety liabilities for a target from
|
|
3
|
-
* Open Targets.
|
|
4
|
-
*/
|
|
5
|
-
import { getTargetSafetyLiabilities } from "../lib/opentargets-client.js";
|
|
6
|
-
type SafetyLiabilities = NonNullable<Awaited<ReturnType<typeof getTargetSafetyLiabilities>>>["safetyLiabilities"];
|
|
7
|
-
type GetTargetSafetyOutput = {
|
|
8
|
-
found: false;
|
|
9
|
-
ensemblId: string;
|
|
10
|
-
} | {
|
|
11
|
-
found: true;
|
|
12
|
-
targetSymbol: string;
|
|
13
|
-
safetyLiabilities: SafetyLiabilities;
|
|
14
|
-
};
|
|
15
|
-
export declare const getTargetSafetyTool: import("../define-tool.js").Tool<{
|
|
16
|
-
ensemblId: string;
|
|
17
|
-
}, GetTargetSafetyOutput>;
|
|
18
|
-
export {};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* getTargetSafety — fetch known safety liabilities for a target from
|
|
3
|
-
* Open Targets.
|
|
4
|
-
*/
|
|
5
|
-
import { ok } from "neverthrow";
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
import { defineTool } from "../define-tool.js";
|
|
8
|
-
import { getTargetSafetyLiabilities } from "../lib/opentargets-client.js";
|
|
9
|
-
export const getTargetSafetyTool = defineTool({
|
|
10
|
-
id: "get_target_safety",
|
|
11
|
-
description: "Get known safety liabilities for a target from Open Targets. Returns organ-specific toxicity signals, adverse events, and safety-related phenotypes linked to the target.",
|
|
12
|
-
inputSchema: z.object({
|
|
13
|
-
ensemblId: z.string().describe("Ensembl gene ID (e.g. ENSG00000141510)"),
|
|
14
|
-
}),
|
|
15
|
-
execute: async ({ ensemblId }) => {
|
|
16
|
-
const result = await getTargetSafetyLiabilities(ensemblId);
|
|
17
|
-
// "Target not found" is an expected outcome — a data variant, not an error.
|
|
18
|
-
if (!result)
|
|
19
|
-
return ok({ found: false, ensemblId });
|
|
20
|
-
return ok({
|
|
21
|
-
found: true,
|
|
22
|
-
targetSymbol: result.targetSymbol,
|
|
23
|
-
safetyLiabilities: result.safetyLiabilities,
|
|
24
|
-
});
|
|
25
|
-
},
|
|
26
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* searchCompounds tool — search ChEMBL for compounds by target, name, or SMILES.
|
|
3
|
-
*
|
|
4
|
-
* Supports three search modes:
|
|
5
|
-
* - "target": resolves target ChEMBL ID, fetches activities, extracts unique molecules
|
|
6
|
-
* - "compound": free-text search on molecule names
|
|
7
|
-
* - "smiles": flexmatch on canonical SMILES
|
|
8
|
-
*/
|
|
9
|
-
export declare const searchCompoundsTool: import("../define-tool.js").Tool<{
|
|
10
|
-
query: string;
|
|
11
|
-
searchType: "target" | "smiles" | "compound";
|
|
12
|
-
limit: number;
|
|
13
|
-
}, {
|
|
14
|
-
compounds: {
|
|
15
|
-
chemblId: string;
|
|
16
|
-
preferredCompoundName: string | null;
|
|
17
|
-
canonicalSmiles: string | null;
|
|
18
|
-
molecularWeight: number | null;
|
|
19
|
-
alogp: number | null;
|
|
20
|
-
molecularFormula: string | null;
|
|
21
|
-
}[];
|
|
22
|
-
}>;
|