@inflexa-ai/harness 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/conversation-agent.d.ts +9 -15
- package/dist/agents/conversation-agent.js +32 -31
- package/dist/agents/sandbox/cheminformatics-agent.js +1 -1
- package/dist/agents/sandbox/chromatin-agent.js +1 -1
- package/dist/agents/sandbox/dna-methylation-agent.js +1 -1
- package/dist/agents/sandbox/drug-repurposing-agent.js +5 -10
- package/dist/agents/sandbox/enrichment-agent.js +1 -1
- package/dist/agents/sandbox/genomic-variant-agent.js +1 -11
- package/dist/agents/sandbox/immune-profiling-agent.js +1 -1
- package/dist/agents/sandbox/index.js +0 -3
- package/dist/agents/sandbox/multi-omics-integration-agent.js +1 -1
- package/dist/agents/sandbox/network-agent.js +1 -1
- package/dist/agents/sandbox/pkpd-clinical-response-agent.js +3 -6
- package/dist/agents/sandbox/scientific-executor.js +1 -1
- package/dist/agents/sandbox/shared.d.ts +2 -2
- package/dist/agents/sandbox/shared.js +8 -14
- package/dist/agents/sandbox/translational-safety-agent.js +4 -7
- package/dist/agents/sandbox/types.d.ts +5 -5
- package/dist/agents/sandbox/types.js +4 -4
- package/dist/app/chat-turn.js +4 -1
- package/dist/app/message-assembly.d.ts +5 -2
- package/dist/app/message-assembly.js +7 -2
- package/dist/app/run-activity.d.ts +13 -0
- package/dist/app/run-activity.js +51 -0
- package/dist/config/resource-limits.d.ts +0 -7
- package/dist/config/resource-limits.js +0 -1
- package/dist/contracts/target-dossier.d.ts +10 -10
- package/dist/execution/dbos-run-launcher.js +1 -26
- package/dist/execution/report-runner.js +1 -1
- package/dist/execution/run-authorizer.d.ts +1 -1
- package/dist/execution/run-authorizer.js +1 -1
- package/dist/execution/run-event-parts.d.ts +44 -0
- package/dist/execution/run-event-parts.js +0 -0
- package/dist/execution/run-event-stream.d.ts +91 -0
- package/dist/execution/run-event-stream.js +212 -0
- package/dist/execution/run-launcher.d.ts +2 -18
- package/dist/execution/run-launcher.js +2 -4
- package/dist/execution/run-synthesis.js +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.js +23 -6
- package/dist/input-sanitization.d.ts +14 -4
- package/dist/input-sanitization.js +27 -4
- package/dist/lib/storage.js +4 -1
- package/dist/loop/budget-exceeded.d.ts +18 -2
- package/dist/loop/budget-exceeded.js +49 -2
- package/dist/loop/run-agent.d.ts +22 -1
- package/dist/loop/run-agent.js +51 -5
- package/dist/loop/run-to-terminal.d.ts +0 -2
- package/dist/loop/run-to-terminal.js +8 -1
- package/dist/memory/ai-sdk-message-storage.d.ts +37 -4
- package/dist/memory/ai-sdk-message-storage.js +45 -4
- package/dist/memory/content-to-cortex.js +19 -3
- package/dist/memory/message-backfill.js +1 -1
- package/dist/memory/reconstruct-cards.d.ts +1 -1
- package/dist/memory/reconstruct-cards.js +7 -5
- package/dist/memory/thread-history.js +72 -8
- package/dist/prompts/conversation.d.ts +1 -1
- package/dist/prompts/conversation.js +41 -15
- package/dist/prompts/literature-reviewer.d.ts +1 -1
- package/dist/prompts/literature-reviewer.js +16 -14
- package/dist/prompts/planner.d.ts +3 -0
- package/dist/prompts/planner.js +16 -21
- package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
- package/dist/prompts/sandbox/drug-repurposing-agent.js +31 -22
- package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
- package/dist/prompts/sandbox/multi-omics-integration-agent.js +9 -10
- package/dist/prompts/sandbox/pkpd-clinical-response-agent.d.ts +1 -1
- package/dist/prompts/sandbox/pkpd-clinical-response-agent.js +8 -7
- package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
- package/dist/prompts/sandbox/translational-safety-agent.js +20 -14
- package/dist/prompts/sandbox-standards.d.ts +4 -4
- package/dist/prompts/sandbox-standards.js +5 -5
- package/dist/prompts/synthesis-agent.d.ts +1 -1
- package/dist/prompts/synthesis-agent.js +7 -7
- package/dist/providers/errors.d.ts +7 -0
- package/dist/providers/errors.js +88 -3
- package/dist/runtime/assemble.d.ts +5 -10
- package/dist/runtime/assemble.js +0 -4
- package/dist/runtime/boot.d.ts +2 -2
- package/dist/runtime/boot.js +1 -1
- package/dist/runtime/dbos.d.ts +4 -5
- package/dist/runtime/dbos.js +6 -7
- package/dist/runtime/pools.d.ts +15 -1
- package/dist/runtime/pools.js +15 -1
- package/dist/sandbox/mount-plan.d.ts +1 -1
- package/dist/sandbox/sandbox-error.d.ts +1 -1
- package/dist/sandbox/sandbox-error.js +1 -1
- package/dist/sandbox/sandbox-step-translate.d.ts +15 -2
- package/dist/sandbox/sandbox-step-translate.js +17 -2
- package/dist/sandbox/types.d.ts +1 -1
- package/dist/schemas/validate-plan.d.ts +1 -1
- package/dist/schemas/workflow-state.d.ts +2 -2
- package/dist/schemas/workflow-state.js +2 -2
- package/dist/state/data-profile.d.ts +53 -1
- package/dist/state/data-profile.js +66 -6
- package/dist/state/index.d.ts +6 -6
- package/dist/state/index.js +4 -4
- package/dist/state/init.js +37 -2
- package/dist/state/plans.js +1 -1
- package/dist/state/runs.d.ts +49 -0
- package/dist/state/runs.js +150 -0
- package/dist/tasks/data-profile-activity.d.ts +87 -0
- package/dist/tasks/data-profile-activity.js +56 -0
- package/dist/tasks/data-profile.js +66 -4
- package/dist/tools/__fixtures__/tool-context.js +1 -0
- package/dist/tools/ad-hoc-router.d.ts +31 -0
- package/dist/tools/ad-hoc-router.js +132 -0
- package/dist/tools/analysis-invocation.d.ts +4 -0
- package/dist/tools/analysis-invocation.js +17 -0
- package/dist/tools/bio/chembl.d.ts +1 -1
- package/dist/tools/bio/chembl.js +51 -54
- package/dist/tools/bio/comptox.js +35 -33
- package/dist/tools/bio/drug-gene-interactions.d.ts +76 -0
- package/dist/tools/bio/drug-gene-interactions.js +175 -0
- package/dist/tools/bio/gene-disease-evidence.d.ts +61 -0
- package/dist/tools/bio/gene-disease-evidence.js +187 -0
- package/dist/tools/bio/gene-preclinical-profile.d.ts +58 -0
- package/dist/tools/bio/gene-preclinical-profile.js +125 -0
- package/dist/tools/bio/index.d.ts +23 -16
- package/dist/tools/bio/index.js +29 -22
- package/dist/tools/bio/keys.d.ts +16 -9
- package/dist/tools/bio/keys.js +22 -13
- package/dist/tools/bio/lookup-annotation.d.ts +48 -0
- package/dist/tools/bio/lookup-annotation.js +173 -0
- package/dist/tools/bio/opentargets.d.ts +7 -11
- package/dist/tools/bio/opentargets.js +24 -35
- package/dist/tools/bio/pubchem.js +6 -4
- package/dist/tools/bio/pubmed.d.ts +15 -7
- package/dist/tools/bio/pubmed.js +79 -20
- package/dist/tools/bio/search-clinical-trials.d.ts +20 -1
- package/dist/tools/bio/search-clinical-trials.js +26 -5
- package/dist/tools/bio/search-faers.js +9 -3
- package/dist/tools/bio/search-gene.d.ts +0 -1
- package/dist/tools/bio/search-gene.js +4 -5
- package/dist/tools/bio/search-geo-datasets.js +10 -4
- package/dist/tools/bio/search-interactions.d.ts +8 -4
- package/dist/tools/bio/search-interactions.js +28 -12
- package/dist/tools/bio/target-safety.d.ts +59 -0
- package/dist/tools/bio/target-safety.js +191 -0
- package/dist/tools/define-tool.d.ts +6 -2
- package/dist/tools/define-tool.js +1 -1
- package/dist/tools/execute-analysis.d.ts +44 -0
- package/dist/tools/execute-analysis.js +252 -0
- package/dist/tools/iterate-report.js +7 -6
- package/dist/tools/lib/dgidb-client.d.ts +49 -0
- package/dist/tools/lib/dgidb-client.js +168 -0
- package/dist/tools/lib/disgenet-client.d.ts +56 -0
- package/dist/tools/lib/disgenet-client.js +59 -0
- package/dist/tools/lib/drugbank-client.d.ts +83 -0
- package/dist/tools/lib/drugbank-client.js +95 -0
- package/dist/tools/lib/ensembl-client.d.ts +4 -1
- package/dist/tools/lib/ensembl-client.js +5 -3
- package/dist/tools/lib/gwas-catalog-client.d.ts +60 -0
- package/dist/tools/lib/gwas-catalog-client.js +136 -0
- package/dist/tools/lib/pharmgkb-client.d.ts +22 -0
- package/dist/tools/lib/pharmgkb-client.js +32 -0
- package/dist/tools/lib/pubmed-client.d.ts +57 -4
- package/dist/tools/lib/pubmed-client.js +57 -3
- package/dist/tools/lib/string-client.d.ts +25 -4
- package/dist/tools/lib/string-client.js +22 -5
- package/dist/tools/research/generate-plan.d.ts +16 -9
- package/dist/tools/research/generate-plan.js +116 -70
- package/dist/tools/research/inspect-data-profile.d.ts +31 -6
- package/dist/tools/research/inspect-data-profile.js +23 -7
- package/dist/tools/research/inspect-run.d.ts +33 -15
- package/dist/tools/research/inspect-run.js +155 -66
- package/dist/tools/research/literature-reviewer.js +7 -11
- package/dist/workflows/execute-analysis.d.ts +68 -5
- package/dist/workflows/execute-analysis.js +76 -7
- package/dist/workflows/sandbox-step.js +1 -11
- package/dist/workflows/target-assessment/decisions/index.d.ts +1 -1
- package/dist/workflows/target-assessment/phase4-assemble.d.ts +1 -1
- package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +2 -2
- package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +1 -1
- package/package.json +1 -1
- package/dist/agents/sandbox/ephemeral-executor.d.ts +0 -9
- package/dist/agents/sandbox/ephemeral-executor.js +0 -20
- package/dist/execution/ephemeral-runner.d.ts +0 -98
- package/dist/execution/ephemeral-runner.js +0 -189
- package/dist/prompts/sandbox/ephemeral-executor.d.ts +0 -1
- package/dist/prompts/sandbox/ephemeral-executor.js +0 -66
- package/dist/tools/bio/check-safety-panel.d.ts +0 -35
- package/dist/tools/bio/check-safety-panel.js +0 -76
- package/dist/tools/bio/get-impc-ko-profile.d.ts +0 -9
- package/dist/tools/bio/get-impc-ko-profile.js +0 -23
- package/dist/tools/bio/lookup-go-term.d.ts +0 -31
- package/dist/tools/bio/lookup-go-term.js +0 -116
- package/dist/tools/bio/search-bgee-expression.d.ts +0 -10
- package/dist/tools/bio/search-bgee-expression.js +0 -30
- package/dist/tools/bio/search-clinvar.d.ts +0 -13
- package/dist/tools/bio/search-clinvar.js +0 -28
- package/dist/tools/bio/search-dgidb.d.ts +0 -53
- package/dist/tools/bio/search-dgidb.js +0 -213
- package/dist/tools/bio/search-disgenet.d.ts +0 -30
- package/dist/tools/bio/search-disgenet.js +0 -84
- package/dist/tools/bio/search-drugbank.d.ts +0 -38
- package/dist/tools/bio/search-drugbank.js +0 -109
- package/dist/tools/bio/search-gwas-catalog.d.ts +0 -33
- package/dist/tools/bio/search-gwas-catalog.js +0 -172
- package/dist/tools/bio/search-pathway.d.ts +0 -12
- package/dist/tools/bio/search-pathway.js +0 -32
- package/dist/tools/bio/search-pharmgkb.d.ts +0 -17
- package/dist/tools/bio/search-pharmgkb.js +0 -52
- package/dist/tools/execute-plan.d.ts +0 -64
- package/dist/tools/execute-plan.js +0 -211
- package/dist/tools/run-ephemeral.d.ts +0 -33
- package/dist/tools/run-ephemeral.js +0 -65
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lookupGoTerm — look up Gene Ontology terms via the QuickGO API (EBI).
|
|
3
|
-
*
|
|
4
|
-
* Supports direct ID lookup, keyword search, and gene annotation retrieval.
|
|
5
|
-
* Multiple modes can be combined in a single call.
|
|
6
|
-
*/
|
|
7
|
-
import { ok } from "neverthrow";
|
|
8
|
-
import { z } from "zod";
|
|
9
|
-
import { defineTool } from "../define-tool.js";
|
|
10
|
-
import { apiFetchValidated, describeApiError } from "../lib/api-utils.js";
|
|
11
|
-
const QUICKGO_BASE = "https://www.ebi.ac.uk/QuickGO/services";
|
|
12
|
-
const HEADERS = { Accept: "application/json" };
|
|
13
|
-
// QuickGO term response, validated at the fetch boundary. The `.transform`
|
|
14
|
-
// carries the (context-free) rename from the raw wire fields to the `GoTerm[]`
|
|
15
|
-
// we return, so parsing IS both the validation and the normalization — there
|
|
16
|
-
// is no separate raw interface or mapper to keep in sync.
|
|
17
|
-
const GoTermResponseSchema = z
|
|
18
|
-
.object({
|
|
19
|
-
results: z
|
|
20
|
-
.array(z.object({
|
|
21
|
-
id: z.string().optional(),
|
|
22
|
-
name: z.string().optional(),
|
|
23
|
-
definition: z.object({ text: z.string().optional() }).nullable().optional(),
|
|
24
|
-
aspect: z.string().optional(),
|
|
25
|
-
}))
|
|
26
|
-
.optional(),
|
|
27
|
-
})
|
|
28
|
-
.transform((res) => (res.results ?? []).map((t) => ({
|
|
29
|
-
id: t.id ?? "",
|
|
30
|
-
name: t.name ?? "",
|
|
31
|
-
definition: t.definition?.text ?? undefined,
|
|
32
|
-
aspect: t.aspect ?? undefined,
|
|
33
|
-
})));
|
|
34
|
-
const GoAnnotationResponseSchema = z
|
|
35
|
-
.object({
|
|
36
|
-
results: z
|
|
37
|
-
.array(z.object({
|
|
38
|
-
geneProductId: z.string().optional(),
|
|
39
|
-
goId: z.string().optional(),
|
|
40
|
-
goName: z.string().optional(),
|
|
41
|
-
goAspect: z.string().optional(),
|
|
42
|
-
goEvidence: z.string().optional(),
|
|
43
|
-
qualifier: z.string().optional(),
|
|
44
|
-
}))
|
|
45
|
-
.optional(),
|
|
46
|
-
})
|
|
47
|
-
.transform((res) => (res.results ?? []).map((a) => ({
|
|
48
|
-
geneProductId: a.geneProductId ?? "",
|
|
49
|
-
goId: a.goId ?? "",
|
|
50
|
-
goName: a.goName ?? "",
|
|
51
|
-
aspect: a.goAspect ?? undefined,
|
|
52
|
-
evidenceCode: a.goEvidence ?? undefined,
|
|
53
|
-
qualifier: a.qualifier ?? undefined,
|
|
54
|
-
})));
|
|
55
|
-
export const lookupGoTermTool = defineTool({
|
|
56
|
-
id: "lookup_go_term",
|
|
57
|
-
description: "Look up Gene Ontology terms from QuickGO (EBI). " +
|
|
58
|
-
"Can look up a term by GO ID, search by keyword, or retrieve GO annotations " +
|
|
59
|
-
"for a specific gene/protein. At least one of goId, query, or geneProductId must be provided.",
|
|
60
|
-
inputSchema: z
|
|
61
|
-
.object({
|
|
62
|
-
goId: z
|
|
63
|
-
.string()
|
|
64
|
-
.regex(/^GO:\d{7}$/)
|
|
65
|
-
.optional()
|
|
66
|
-
.describe("Specific GO term ID (e.g. 'GO:0008150')"),
|
|
67
|
-
query: z.string().optional().describe("Free-text search for GO terms (e.g. 'apoptotic process')"),
|
|
68
|
-
limit: z.number().int().min(1).max(100).default(10).describe("Maximum number of results per query type"),
|
|
69
|
-
geneProductId: z.string().optional().describe("UniProt ID to get annotations for (e.g. 'P04637')"),
|
|
70
|
-
taxonId: z.number().int().optional().describe("NCBI Taxon ID to filter annotations (9606 = human, 10090 = mouse)"),
|
|
71
|
-
})
|
|
72
|
-
.refine((d) => d.goId || d.query || d.geneProductId, {
|
|
73
|
-
message: "At least one of goId, query, or geneProductId is required",
|
|
74
|
-
}),
|
|
75
|
-
execute: async ({ goId, query, limit, geneProductId, taxonId }) => {
|
|
76
|
-
const tasks = [];
|
|
77
|
-
let terms;
|
|
78
|
-
let annotations;
|
|
79
|
-
if (goId) {
|
|
80
|
-
tasks.push((async () => {
|
|
81
|
-
const res = await apiFetchValidated(`${QUICKGO_BASE}/ontology/go/terms/${encodeURIComponent(goId)}`, GoTermResponseSchema, {
|
|
82
|
-
headers: HEADERS,
|
|
83
|
-
});
|
|
84
|
-
if (res.isErr())
|
|
85
|
-
throw new Error(`GO lookup: ${describeApiError(res.error)}`);
|
|
86
|
-
terms = res.value;
|
|
87
|
-
})());
|
|
88
|
-
}
|
|
89
|
-
if (query) {
|
|
90
|
-
tasks.push((async () => {
|
|
91
|
-
const params = new URLSearchParams({ query, limit: String(limit) });
|
|
92
|
-
const res = await apiFetchValidated(`${QUICKGO_BASE}/ontology/go/search?${params}`, GoTermResponseSchema, { headers: HEADERS });
|
|
93
|
-
if (res.isErr())
|
|
94
|
-
throw new Error(`GO search: ${describeApiError(res.error)}`);
|
|
95
|
-
const searchTerms = res.value;
|
|
96
|
-
terms = terms ? [...terms, ...searchTerms] : searchTerms;
|
|
97
|
-
})());
|
|
98
|
-
}
|
|
99
|
-
if (geneProductId) {
|
|
100
|
-
tasks.push((async () => {
|
|
101
|
-
const params = new URLSearchParams({
|
|
102
|
-
geneProductId,
|
|
103
|
-
limit: String(limit),
|
|
104
|
-
});
|
|
105
|
-
if (taxonId)
|
|
106
|
-
params.set("taxonId", String(taxonId));
|
|
107
|
-
const res = await apiFetchValidated(`${QUICKGO_BASE}/annotation/search?${params}`, GoAnnotationResponseSchema, { headers: HEADERS });
|
|
108
|
-
if (res.isErr())
|
|
109
|
-
throw new Error(`Annotations: ${describeApiError(res.error)}`);
|
|
110
|
-
annotations = res.value;
|
|
111
|
-
})());
|
|
112
|
-
}
|
|
113
|
-
await Promise.all(tasks);
|
|
114
|
-
return ok({ terms, annotations });
|
|
115
|
-
},
|
|
116
|
-
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* searchBgeeExpression tool — cross-species baseline gene expression.
|
|
3
|
-
*/
|
|
4
|
-
import { SUPPORTED_SPECIES, bucketRank, parseExpressionResponse } from "../lib/bgee-client.js";
|
|
5
|
-
export type { SupportedSpecies } from "../lib/bgee-client.js";
|
|
6
|
-
export { SUPPORTED_SPECIES, bucketRank, parseExpressionResponse };
|
|
7
|
-
export declare const searchBgeeExpressionTool: import("../define-tool.js").Tool<{
|
|
8
|
-
geneSymbol: string;
|
|
9
|
-
species: ("homo_sapiens" | "mus_musculus" | "rattus_norvegicus" | "canis_lupus_familiaris" | "macaca_mulatta")[];
|
|
10
|
-
}, import("../lib/bgee-client.js").MultiSpeciesExpression>;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* searchBgeeExpression tool — cross-species baseline gene expression.
|
|
3
|
-
*/
|
|
4
|
-
import { ok } from "neverthrow";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { defineTool } from "../define-tool.js";
|
|
7
|
-
import { SUPPORTED_SPECIES, bucketRank, getMultiSpeciesExpression, parseExpressionResponse } from "../lib/bgee-client.js";
|
|
8
|
-
export { SUPPORTED_SPECIES, bucketRank, parseExpressionResponse };
|
|
9
|
-
export const searchBgeeExpressionTool = defineTool({
|
|
10
|
-
id: "search_bgee_expression",
|
|
11
|
-
description: "Get BASELINE (healthy, untreated) gene expression across species from Bgee — use it to judge tissue-of-action ('where is this target expressed?') and model-organism " +
|
|
12
|
-
"suitability ('is the mouse a fair surrogate for this gene?'). " +
|
|
13
|
-
"NOT for differential expression between conditions — that is the analysis pipeline's job, never this tool. " +
|
|
14
|
-
"Takes a human gene symbol and resolves the per-species orthologs itself, returning a per-species tissue table: each tissue carries an expression score, a gold/silver confidence, " +
|
|
15
|
-
"an expressed / not-expressed state, and a bucketed rank (absent | low | medium | high). Species with no ortholog are listed in notFound. " +
|
|
16
|
-
"Sparse output is valid no-data: dog and macaque coverage is thin, and a null humanEnsemblId means the symbol did not resolve. Do NOT retry on empty output.",
|
|
17
|
-
inputSchema: z.object({
|
|
18
|
-
geneSymbol: z
|
|
19
|
-
.string()
|
|
20
|
-
.min(1)
|
|
21
|
-
.describe("HUMAN gene symbol, e.g. 'BRCA1' — one gene per call. Ensembl IDs and non-human symbols are not accepted; the human symbol is resolved to an ENSG and orthologs are looked up per species."),
|
|
22
|
-
species: z
|
|
23
|
-
.array(z.enum(SUPPORTED_SPECIES))
|
|
24
|
-
.min(1)
|
|
25
|
-
.default([...SUPPORTED_SPECIES])
|
|
26
|
-
.describe("Species to fetch, any subset of: homo_sapiens, mus_musculus, rattus_norvegicus, canis_lupus_familiaris, macaca_mulatta. " +
|
|
27
|
-
"Defaults to all five — narrow it only when the cross-species comparison is not needed."),
|
|
28
|
-
}),
|
|
29
|
-
execute: async ({ geneSymbol, species }) => ok(await getMultiSpeciesExpression(geneSymbol, species)),
|
|
30
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* searchClinvar — search NCBI ClinVar for clinical significance of variants.
|
|
3
|
-
*/
|
|
4
|
-
export declare function createSearchClinvarTool(deps: {
|
|
5
|
-
ncbiApiKey?: string;
|
|
6
|
-
}): import("../define-tool.js").Tool<{
|
|
7
|
-
query: string;
|
|
8
|
-
limit: number;
|
|
9
|
-
clinicalSignificance?: "pathogenic" | "likely-pathogenic" | "benign" | "likely-benign" | "uncertain" | undefined;
|
|
10
|
-
}, {
|
|
11
|
-
totalFound: number;
|
|
12
|
-
variants: import("../lib/clinvar-client.js").ClinvarVariant[];
|
|
13
|
-
}>;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* searchClinvar — search NCBI ClinVar for clinical significance of variants.
|
|
3
|
-
*/
|
|
4
|
-
import { ok } from "neverthrow";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { defineTool } from "../define-tool.js";
|
|
7
|
-
import { searchClinvar } from "../lib/clinvar-client.js";
|
|
8
|
-
export function createSearchClinvarTool(deps) {
|
|
9
|
-
return defineTool({
|
|
10
|
-
id: "search_clinvar",
|
|
11
|
-
description: "Search NCBI ClinVar for clinical significance of genetic variants. Returns pathogenicity classifications, associated conditions, and review status. Use to assess whether variants identified in omics data have known clinical significance.",
|
|
12
|
-
inputSchema: z.object({
|
|
13
|
-
query: z.string().describe("Gene symbol (e.g. BRCA1), variant (e.g. NM_007294.4:c.5266dupC), dbSNP rsID (e.g. rs80357906), or condition name"),
|
|
14
|
-
clinicalSignificance: z
|
|
15
|
-
.enum(["pathogenic", "likely-pathogenic", "benign", "likely-benign", "uncertain"])
|
|
16
|
-
.optional()
|
|
17
|
-
.describe("Filter by clinical significance"),
|
|
18
|
-
limit: z.number().int().min(1).max(100).default(20).describe("Max results to return"),
|
|
19
|
-
}),
|
|
20
|
-
execute: async ({ query, clinicalSignificance, limit = 20 }) => {
|
|
21
|
-
const { totalFound, variants } = await searchClinvar(deps.ncbiApiKey, query, {
|
|
22
|
-
clinicalSignificance,
|
|
23
|
-
limit,
|
|
24
|
-
});
|
|
25
|
-
return ok({ totalFound, variants });
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* searchDgidb tool — query drug-gene interactions via DGIdb GraphQL.
|
|
3
|
-
*
|
|
4
|
-
* DGIdb aggregates interactions from 30+ sources (ChEMBL, DrugBank, TTD,
|
|
5
|
-
* PharmGKB, GuideToPharmacology, CIViC, etc.). Free, no API key required.
|
|
6
|
-
*
|
|
7
|
-
* Two directions:
|
|
8
|
-
* - searchType="gene": input HUGO symbols, returns drugs interacting with each.
|
|
9
|
-
* - searchType="drug": input drug names/concept IDs, returns genes each acts on.
|
|
10
|
-
*/
|
|
11
|
-
import type { Logger } from "../../lib/logger.js";
|
|
12
|
-
interface Interaction {
|
|
13
|
-
geneName: string;
|
|
14
|
-
drugName: string;
|
|
15
|
-
drugConceptId?: string;
|
|
16
|
-
interactionTypes: {
|
|
17
|
-
type: string;
|
|
18
|
-
directionality?: string;
|
|
19
|
-
}[];
|
|
20
|
-
interactionScore?: number;
|
|
21
|
-
sourceCount: number;
|
|
22
|
-
sources: string[];
|
|
23
|
-
publicationCount: number;
|
|
24
|
-
pmids: string[];
|
|
25
|
-
attributes: {
|
|
26
|
-
name: string;
|
|
27
|
-
value: string;
|
|
28
|
-
}[];
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* A factory rather than a bare const (unlike its bio-leaf siblings) because it
|
|
32
|
-
* logs: DGIdb answers GraphQL partial errors alongside usable data, and an
|
|
33
|
-
* operator debugging odd interaction results needs to see them. `ToolContext`
|
|
34
|
-
* carries no deps by design, so a tool that logs is dep-bearing — the same
|
|
35
|
-
* reason `createSearchClinvarTool` takes its key that way.
|
|
36
|
-
*/
|
|
37
|
-
export declare function createSearchDgidbTool(deps?: {
|
|
38
|
-
readonly logger?: Logger;
|
|
39
|
-
}): import("../define-tool.js").Tool<{
|
|
40
|
-
query: string | string[];
|
|
41
|
-
searchType: "drug" | "gene";
|
|
42
|
-
minSources: number;
|
|
43
|
-
limit: number;
|
|
44
|
-
interactionTypes?: string[] | undefined;
|
|
45
|
-
sources?: string[] | undefined;
|
|
46
|
-
}, {
|
|
47
|
-
results: {
|
|
48
|
-
input: string;
|
|
49
|
-
found: boolean;
|
|
50
|
-
interactions: Interaction[];
|
|
51
|
-
}[];
|
|
52
|
-
}>;
|
|
53
|
-
export {};
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* searchDgidb tool — query drug-gene interactions via DGIdb GraphQL.
|
|
3
|
-
*
|
|
4
|
-
* DGIdb aggregates interactions from 30+ sources (ChEMBL, DrugBank, TTD,
|
|
5
|
-
* PharmGKB, GuideToPharmacology, CIViC, etc.). Free, no API key required.
|
|
6
|
-
*
|
|
7
|
-
* Two directions:
|
|
8
|
-
* - searchType="gene": input HUGO symbols, returns drugs interacting with each.
|
|
9
|
-
* - searchType="drug": input drug names/concept IDs, returns genes each acts on.
|
|
10
|
-
*/
|
|
11
|
-
import { ok } from "neverthrow";
|
|
12
|
-
import { z } from "zod";
|
|
13
|
-
import { defineTool } from "../define-tool.js";
|
|
14
|
-
import { createNoopLogger } from "../../lib/console-logger.js";
|
|
15
|
-
import { apiFetchValidated, describeApiError } from "../lib/api-utils.js";
|
|
16
|
-
const DGIDB_GRAPHQL_URL = "https://dgidb.org/api/graphql";
|
|
17
|
-
const GENE_INTERACTIONS_QUERY = `query($genes: [String!]!) {
|
|
18
|
-
genes(names: $genes) {
|
|
19
|
-
nodes {
|
|
20
|
-
name
|
|
21
|
-
interactions {
|
|
22
|
-
interactionScore
|
|
23
|
-
interactionTypes { type directionality }
|
|
24
|
-
drug { name conceptId }
|
|
25
|
-
interactionAttributes { name value }
|
|
26
|
-
publications { pmid }
|
|
27
|
-
sources { sourceDbName }
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}`;
|
|
32
|
-
const DRUG_INTERACTIONS_QUERY = `query($drugs: [String!]!) {
|
|
33
|
-
drugs(names: $drugs) {
|
|
34
|
-
nodes {
|
|
35
|
-
name
|
|
36
|
-
conceptId
|
|
37
|
-
interactions {
|
|
38
|
-
interactionScore
|
|
39
|
-
interactionTypes { type directionality }
|
|
40
|
-
gene { name }
|
|
41
|
-
interactionAttributes { name value }
|
|
42
|
-
publications { pmid }
|
|
43
|
-
sources { sourceDbName }
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}`;
|
|
48
|
-
// Shape of the DGIdb GraphQL payload as it arrives on the wire. Validated at
|
|
49
|
-
// the fetch boundary; `mapInteraction` normalizes each record into the
|
|
50
|
-
// `Interaction` we return. Most fields are optional/nullable to match GraphQL's
|
|
51
|
-
// per-field nullability — but `RawNode.name` is required because we key the
|
|
52
|
-
// node map on `name.toLowerCase()`; a node missing it is a contract break we
|
|
53
|
-
// surface as an `invalid_response` error rather than a runtime TypeError.
|
|
54
|
-
const RawInteractionSchema = z.object({
|
|
55
|
-
interactionScore: z.number().nullable().optional(),
|
|
56
|
-
interactionTypes: z.array(z.object({ type: z.string().optional(), directionality: z.string().nullable().optional() })).optional(),
|
|
57
|
-
drug: z.object({ name: z.string().optional(), conceptId: z.string().nullable().optional() }).nullable().optional(),
|
|
58
|
-
gene: z.object({ name: z.string().optional() }).nullable().optional(),
|
|
59
|
-
interactionAttributes: z.array(z.object({ name: z.string().optional(), value: z.string().optional() })).optional(),
|
|
60
|
-
publications: z.array(z.object({ pmid: z.union([z.string(), z.number()]).optional() })).optional(),
|
|
61
|
-
sources: z.array(z.object({ sourceDbName: z.string().optional() })).optional(),
|
|
62
|
-
});
|
|
63
|
-
const RawNodeSchema = z.object({
|
|
64
|
-
name: z.string(),
|
|
65
|
-
conceptId: z.string().nullable().optional(),
|
|
66
|
-
interactions: z.array(RawInteractionSchema).optional(),
|
|
67
|
-
});
|
|
68
|
-
const DgidbResponseSchema = z.object({
|
|
69
|
-
data: z
|
|
70
|
-
.object({
|
|
71
|
-
genes: z.object({ nodes: z.array(RawNodeSchema).optional() }).optional(),
|
|
72
|
-
drugs: z.object({ nodes: z.array(RawNodeSchema).optional() }).optional(),
|
|
73
|
-
})
|
|
74
|
-
.optional(),
|
|
75
|
-
errors: z.array(z.object({ message: z.string().optional() })).optional(),
|
|
76
|
-
});
|
|
77
|
-
function mapInteraction(raw, perspective, inputSide) {
|
|
78
|
-
const sources = (raw.sources ?? []).map((s) => s.sourceDbName ?? "").filter(Boolean);
|
|
79
|
-
const pmids = (raw.publications ?? []).map((p) => (p.pmid != null ? String(p.pmid) : "")).filter(Boolean);
|
|
80
|
-
const types = (raw.interactionTypes ?? []).map((t) => ({
|
|
81
|
-
type: t.type ?? "",
|
|
82
|
-
...(t.directionality ? { directionality: t.directionality } : {}),
|
|
83
|
-
}));
|
|
84
|
-
const attributes = (raw.interactionAttributes ?? []).slice(0, 20).map((a) => ({
|
|
85
|
-
name: a.name ?? "",
|
|
86
|
-
value: (a.value ?? "").slice(0, 200),
|
|
87
|
-
}));
|
|
88
|
-
const geneName = perspective === "gene" ? (inputSide.geneName ?? "") : (raw.gene?.name ?? "");
|
|
89
|
-
const drugName = perspective === "drug" ? (inputSide.drugName ?? "") : (raw.drug?.name ?? "");
|
|
90
|
-
const drugConceptId = perspective === "drug" ? inputSide.drugConceptId : (raw.drug?.conceptId ?? undefined);
|
|
91
|
-
return {
|
|
92
|
-
geneName,
|
|
93
|
-
drugName,
|
|
94
|
-
...(drugConceptId ? { drugConceptId } : {}),
|
|
95
|
-
interactionTypes: types,
|
|
96
|
-
...(raw.interactionScore != null ? { interactionScore: raw.interactionScore } : {}),
|
|
97
|
-
sourceCount: sources.length,
|
|
98
|
-
sources,
|
|
99
|
-
publicationCount: pmids.length,
|
|
100
|
-
pmids: pmids.slice(0, 10),
|
|
101
|
-
attributes,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
function applyFilters(interactions, filters) {
|
|
105
|
-
let out = interactions;
|
|
106
|
-
if (filters.interactionTypes?.length) {
|
|
107
|
-
const needles = filters.interactionTypes.map((s) => s.toLowerCase());
|
|
108
|
-
out = out.filter((i) => i.interactionTypes.some((t) => needles.some((n) => t.type.toLowerCase().includes(n))));
|
|
109
|
-
}
|
|
110
|
-
if (filters.sources?.length) {
|
|
111
|
-
const needles = filters.sources.map((s) => s.toLowerCase());
|
|
112
|
-
out = out.filter((i) => i.sources.some((s) => needles.some((n) => s.toLowerCase().includes(n))));
|
|
113
|
-
}
|
|
114
|
-
if (filters.minSources > 0) {
|
|
115
|
-
out = out.filter((i) => i.sourceCount >= filters.minSources);
|
|
116
|
-
}
|
|
117
|
-
return out;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* A factory rather than a bare const (unlike its bio-leaf siblings) because it
|
|
121
|
-
* logs: DGIdb answers GraphQL partial errors alongside usable data, and an
|
|
122
|
-
* operator debugging odd interaction results needs to see them. `ToolContext`
|
|
123
|
-
* carries no deps by design, so a tool that logs is dep-bearing — the same
|
|
124
|
-
* reason `createSearchClinvarTool` takes its key that way.
|
|
125
|
-
*/
|
|
126
|
-
export function createSearchDgidbTool(deps = {}) {
|
|
127
|
-
const logger = (deps.logger ?? createNoopLogger()).named("search_dgidb");
|
|
128
|
-
return defineTool({
|
|
129
|
-
id: "search_dgidb",
|
|
130
|
-
description: "Query the Drug-Gene Interaction Database (DGIdb) for drug-gene interactions. " +
|
|
131
|
-
"DGIdb aggregates 30+ sources (ChEMBL, DrugBank, TTD, PharmGKB, GuideToPharmacology, CIViC, etc.) " +
|
|
132
|
-
"and returns source counts as a confidence signal. " +
|
|
133
|
-
"searchType='gene' returns drugs interacting with input HUGO gene symbols (most common: 'what drugs hit my gene set?'). " +
|
|
134
|
-
"searchType='drug' returns the genes each input drug is known to act on. " +
|
|
135
|
-
"Free, no API key required. Sorted by source count desc.",
|
|
136
|
-
inputSchema: z.object({
|
|
137
|
-
query: z
|
|
138
|
-
.union([z.string(), z.array(z.string()).max(50)])
|
|
139
|
-
.describe("Single identifier or list of up to 50. For searchType='gene': HUGO symbols. For searchType='drug': drug names or DGIdb concept IDs."),
|
|
140
|
-
searchType: z.enum(["gene", "drug"]).default("gene"),
|
|
141
|
-
interactionTypes: z
|
|
142
|
-
.array(z.string())
|
|
143
|
-
.optional()
|
|
144
|
-
.describe("Case-insensitive substring filter on interaction type. e.g. ['inhibitor', 'antagonist']"),
|
|
145
|
-
sources: z.array(z.string()).optional().describe("Restrict to interactions from these source DBs (case-insensitive substring)."),
|
|
146
|
-
minSources: z.number().int().min(1).default(1).describe("Drop interactions supported by fewer than this many sources."),
|
|
147
|
-
limit: z.number().int().min(1).max(200).default(50).describe("Max interactions per input gene/drug after filtering."),
|
|
148
|
-
}),
|
|
149
|
-
execute: async ({ query, searchType = "gene", interactionTypes, sources, minSources = 1, limit = 50 }) => {
|
|
150
|
-
const inputs = typeof query === "string" ? [query] : query;
|
|
151
|
-
if (inputs.length === 0 || inputs.every((s) => !s.trim())) {
|
|
152
|
-
throw new Error("query must contain at least one identifier");
|
|
153
|
-
}
|
|
154
|
-
const isGene = searchType === "gene";
|
|
155
|
-
const variableName = isGene ? "genes" : "drugs";
|
|
156
|
-
const queryString = isGene ? GENE_INTERACTIONS_QUERY : DRUG_INTERACTIONS_QUERY;
|
|
157
|
-
const res = await apiFetchValidated(DGIDB_GRAPHQL_URL, DgidbResponseSchema, {
|
|
158
|
-
method: "POST",
|
|
159
|
-
headers: { "Content-Type": "application/json" },
|
|
160
|
-
body: JSON.stringify({
|
|
161
|
-
query: queryString,
|
|
162
|
-
variables: { [variableName]: inputs },
|
|
163
|
-
}),
|
|
164
|
-
});
|
|
165
|
-
if (res.isErr())
|
|
166
|
-
throw new Error(describeApiError(res.error));
|
|
167
|
-
const body = res.value;
|
|
168
|
-
if (!body || !body.data)
|
|
169
|
-
throw new Error("DGIdb returned no data");
|
|
170
|
-
if (body.errors?.length) {
|
|
171
|
-
logger.warn("dgidb partial errors alongside data", { errors: body.errors.slice(0, 3) });
|
|
172
|
-
}
|
|
173
|
-
const nodes = (isGene ? body.data.genes?.nodes : body.data.drugs?.nodes) ?? [];
|
|
174
|
-
const nodeMap = new Map();
|
|
175
|
-
for (const node of nodes) {
|
|
176
|
-
nodeMap.set(node.name.toLowerCase(), node);
|
|
177
|
-
if (!isGene && node.conceptId) {
|
|
178
|
-
nodeMap.set(node.conceptId.toLowerCase(), node);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
const results = inputs.map((input) => {
|
|
182
|
-
const node = nodeMap.get(input.toLowerCase());
|
|
183
|
-
if (!node) {
|
|
184
|
-
return { input, found: false, interactions: [] };
|
|
185
|
-
}
|
|
186
|
-
const inputSide = isGene
|
|
187
|
-
? { geneName: node.name }
|
|
188
|
-
: {
|
|
189
|
-
drugName: node.name,
|
|
190
|
-
drugConceptId: node.conceptId ?? undefined,
|
|
191
|
-
};
|
|
192
|
-
const mapped = (node.interactions ?? []).map((raw) => mapInteraction(raw, searchType, inputSide));
|
|
193
|
-
const filtered = applyFilters(mapped, {
|
|
194
|
-
interactionTypes,
|
|
195
|
-
sources,
|
|
196
|
-
minSources,
|
|
197
|
-
});
|
|
198
|
-
const sorted = filtered.sort((a, b) => {
|
|
199
|
-
if (b.sourceCount !== a.sourceCount) {
|
|
200
|
-
return b.sourceCount - a.sourceCount;
|
|
201
|
-
}
|
|
202
|
-
return (b.interactionScore ?? 0) - (a.interactionScore ?? 0);
|
|
203
|
-
});
|
|
204
|
-
return {
|
|
205
|
-
input,
|
|
206
|
-
found: true,
|
|
207
|
-
interactions: sorted.slice(0, limit),
|
|
208
|
-
};
|
|
209
|
-
});
|
|
210
|
-
return ok({ results });
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* searchDisgenet — search DisGeNET for gene-disease associations (GDAs).
|
|
3
|
-
*
|
|
4
|
-
* Requires `DISGENET_API_KEY`. Without the key, `getDisgenetHeaders` throws
|
|
5
|
-
* on first call; the harness surfaces that as a tool `is_error` envelope.
|
|
6
|
-
*/
|
|
7
|
-
export declare function createSearchDisgenetTool(deps: {
|
|
8
|
-
apiKey: string;
|
|
9
|
-
}): import("../define-tool.js").Tool<{
|
|
10
|
-
query: string;
|
|
11
|
-
searchType: "gene" | "disease";
|
|
12
|
-
minScore: number;
|
|
13
|
-
source: "ALL" | "CURATED" | "ANIMAL_MODELS" | "BEFREE";
|
|
14
|
-
limit: number;
|
|
15
|
-
}, {
|
|
16
|
-
associations: {
|
|
17
|
-
geneSymbol: string;
|
|
18
|
-
geneName: string;
|
|
19
|
-
geneId: number;
|
|
20
|
-
diseaseName: string;
|
|
21
|
-
diseaseId: string;
|
|
22
|
-
diseaseType: string;
|
|
23
|
-
score: number;
|
|
24
|
-
evidenceIndex: number;
|
|
25
|
-
yearInitial: number | null;
|
|
26
|
-
yearFinal: number | null;
|
|
27
|
-
nPmids: number;
|
|
28
|
-
source: string;
|
|
29
|
-
}[];
|
|
30
|
-
}>;
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* searchDisgenet — search DisGeNET for gene-disease associations (GDAs).
|
|
3
|
-
*
|
|
4
|
-
* Requires `DISGENET_API_KEY`. Without the key, `getDisgenetHeaders` throws
|
|
5
|
-
* on first call; the harness surfaces that as a tool `is_error` envelope.
|
|
6
|
-
*/
|
|
7
|
-
import { ok } from "neverthrow";
|
|
8
|
-
import { z } from "zod";
|
|
9
|
-
import { defineTool } from "../define-tool.js";
|
|
10
|
-
import { apiFetchValidated, describeApiError } from "../lib/api-utils.js";
|
|
11
|
-
import { DISGENET_BASE, getDisgenetHeaders } from "../lib/disgenet-config.js";
|
|
12
|
-
// A single schema that both validates and normalizes one DisGeNET GDA record:
|
|
13
|
-
// the `.object(...)` half is the snake_case wire shape (every field optional —
|
|
14
|
-
// the API omits absent values), the `.transform(...)` half maps it to the
|
|
15
|
-
// camelCase `Gda` we return. Parsing IS the validation (`apiFetchValidated`
|
|
16
|
-
// runs it over the JSON), and because the transform rides on the schema,
|
|
17
|
-
// `z.infer` below is the OUTPUT type — no separate raw interface or mapper.
|
|
18
|
-
const GdaSchema = z
|
|
19
|
-
.object({
|
|
20
|
-
gene_symbol: z.string().nullable().optional(),
|
|
21
|
-
gene_name: z.string().nullable().optional(),
|
|
22
|
-
geneid: z.number().nullable().optional(),
|
|
23
|
-
disease_name: z.string().nullable().optional(),
|
|
24
|
-
diseaseid: z.string().nullable().optional(),
|
|
25
|
-
disease_type: z.string().nullable().optional(),
|
|
26
|
-
score: z.number().nullable().optional(),
|
|
27
|
-
ei: z.number().nullable().optional(),
|
|
28
|
-
year_initial: z.number().nullable().optional(),
|
|
29
|
-
year_final: z.number().nullable().optional(),
|
|
30
|
-
pmid_count: z.number().nullable().optional(),
|
|
31
|
-
source: z.string().nullable().optional(),
|
|
32
|
-
})
|
|
33
|
-
.transform((gda) => ({
|
|
34
|
-
geneSymbol: gda.gene_symbol ?? "",
|
|
35
|
-
geneName: gda.gene_name ?? "",
|
|
36
|
-
geneId: gda.geneid ?? 0,
|
|
37
|
-
diseaseName: gda.disease_name ?? "",
|
|
38
|
-
diseaseId: gda.diseaseid ?? "",
|
|
39
|
-
diseaseType: gda.disease_type ?? "",
|
|
40
|
-
score: gda.score ?? 0,
|
|
41
|
-
evidenceIndex: gda.ei ?? 0,
|
|
42
|
-
yearInitial: gda.year_initial ?? null,
|
|
43
|
-
yearFinal: gda.year_final ?? null,
|
|
44
|
-
nPmids: gda.pmid_count ?? 0,
|
|
45
|
-
source: gda.source ?? "",
|
|
46
|
-
}));
|
|
47
|
-
const GdaListSchema = z.array(GdaSchema);
|
|
48
|
-
export function createSearchDisgenetTool(deps) {
|
|
49
|
-
return defineTool({
|
|
50
|
-
id: "search_disgenet",
|
|
51
|
-
description: "Search DisGeNET for gene-disease associations (GDAs). Returns association scores, " +
|
|
52
|
-
"evidence counts, and disease classifications. Requires DISGENET_API_KEY. " +
|
|
53
|
-
"Use for target validation — high-scoring GDAs provide genetic support for a " +
|
|
54
|
-
"therapeutic target's disease relevance.",
|
|
55
|
-
inputSchema: z.object({
|
|
56
|
-
query: z.string().describe("Gene symbol (e.g. TP53), Entrez gene ID (e.g. 7157), or disease name/UMLS CUI (e.g. C0006142 for breast cancer)"),
|
|
57
|
-
searchType: z.enum(["gene", "disease"]).describe("'gene' to find diseases for a gene, 'disease' to find genes for a disease"),
|
|
58
|
-
minScore: z.number().min(0).max(1).default(0.1).describe("Minimum GDA score (0–1). Higher = stronger evidence"),
|
|
59
|
-
source: z.enum(["ALL", "CURATED", "ANIMAL_MODELS", "BEFREE"]).default("ALL").describe("Evidence source filter"),
|
|
60
|
-
limit: z.number().int().min(1).max(100).default(25).describe("Max results to return"),
|
|
61
|
-
}),
|
|
62
|
-
execute: async ({ query, searchType, minScore = 0.1, source = "ALL", limit = 25 }) => {
|
|
63
|
-
const headers = getDisgenetHeaders(deps.apiKey);
|
|
64
|
-
let url;
|
|
65
|
-
if (searchType === "gene") {
|
|
66
|
-
const isNumeric = /^\d+$/.test(query);
|
|
67
|
-
const param = isNumeric ? `gene/${query}` : `gene/${encodeURIComponent(query)}`;
|
|
68
|
-
url = `${DISGENET_BASE}/gda/${param}?min_score=${minScore}&limit=${limit}`;
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
url = `${DISGENET_BASE}/gda/disease/${encodeURIComponent(query)}?min_score=${minScore}&limit=${limit}`;
|
|
72
|
-
}
|
|
73
|
-
if (source !== "ALL") {
|
|
74
|
-
url += `&source=${source}`;
|
|
75
|
-
}
|
|
76
|
-
const res = await apiFetchValidated(url, GdaListSchema, { headers });
|
|
77
|
-
if (res.isErr())
|
|
78
|
-
throw new Error(describeApiError(res.error));
|
|
79
|
-
// Already validated + normalized to camelCase by GdaSchema's transform.
|
|
80
|
-
const associations = res.value;
|
|
81
|
-
return ok({ associations });
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* searchDrugbank — search DrugBank for drug records and target-driven lookups.
|
|
3
|
-
*
|
|
4
|
-
* Requires `DRUGBANK_API_KEY`. Without the key, `getDrugbankHeaders` throws
|
|
5
|
-
* on first call; the harness surfaces that as a tool `is_error` envelope.
|
|
6
|
-
*/
|
|
7
|
-
export declare function createSearchDrugbankTool(deps: {
|
|
8
|
-
apiKey: string;
|
|
9
|
-
}): import("../define-tool.js").Tool<{
|
|
10
|
-
query: string;
|
|
11
|
-
searchType: "target" | "drug";
|
|
12
|
-
limit: number;
|
|
13
|
-
}, {
|
|
14
|
-
drugs: {
|
|
15
|
-
drugbankId: string;
|
|
16
|
-
name: string;
|
|
17
|
-
description: string;
|
|
18
|
-
type: string;
|
|
19
|
-
groups: string[];
|
|
20
|
-
categories: string[];
|
|
21
|
-
indication: string;
|
|
22
|
-
pharmacodynamics: string;
|
|
23
|
-
mechanismOfAction: string;
|
|
24
|
-
toxicity: string;
|
|
25
|
-
halfLife: string;
|
|
26
|
-
targets: {
|
|
27
|
-
name: string;
|
|
28
|
-
geneSymbol: string;
|
|
29
|
-
actions: string[];
|
|
30
|
-
knownAction: string;
|
|
31
|
-
}[];
|
|
32
|
-
interactions: {
|
|
33
|
-
drugbankId: string;
|
|
34
|
-
name: string;
|
|
35
|
-
description: string;
|
|
36
|
-
}[];
|
|
37
|
-
}[];
|
|
38
|
-
}>;
|