@inflexa-ai/harness 0.13.0 → 0.14.1
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.js +23 -16
- 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/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.js +7 -13
- 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/contracts/target-dossier.d.ts +10 -10
- package/dist/execution/report-runner.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-synthesis.js +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +20 -1
- 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 +91 -25
- package/dist/loop/run-to-terminal.d.ts +22 -4
- package/dist/loop/run-to-terminal.js +20 -4
- 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/thread-history.js +34 -8
- package/dist/prompts/conversation.d.ts +1 -1
- package/dist/prompts/conversation.js +15 -6
- package/dist/prompts/literature-reviewer.d.ts +1 -1
- package/dist/prompts/literature-reviewer.js +16 -14
- package/dist/prompts/planner.js +15 -20
- 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/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/pools.d.ts +15 -1
- package/dist/runtime/pools.js +15 -1
- package/dist/sandbox/sandbox-step-translate.d.ts +15 -2
- package/dist/sandbox/sandbox-step-translate.js +17 -2
- 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 +3 -3
- package/dist/state/index.js +2 -2
- package/dist/state/init.js +37 -2
- package/dist/state/runs.d.ts +39 -0
- package/dist/state/runs.js +103 -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/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/execute-analysis.d.ts +1 -0
- package/dist/tools/execute-analysis.js +5 -5
- 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 +405 -85
- 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 +63 -0
- package/dist/workflows/execute-analysis.js +73 -2
- 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/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
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* geneDiseaseEvidence — one tool over the three gene↔disease evidence corpora:
|
|
3
|
+
* the NHGRI-EBI GWAS Catalog, DisGeNET, and NCBI ClinVar.
|
|
4
|
+
*
|
|
5
|
+
* These were three tools with the same input skeleton (`query` + a
|
|
6
|
+
* gene/disease/variant discriminator + a strength threshold + `limit`)
|
|
7
|
+
* answering the same question — what genetic evidence links this gene to this
|
|
8
|
+
* disease or trait. Picking between them was never a routing decision an agent
|
|
9
|
+
* should spend a turn on; it is corpus coverage, so it rides in `sources` and
|
|
10
|
+
* defaults to all of them. `search_pathway`'s `source: kegg | reactome | both`
|
|
11
|
+
* is the same shape.
|
|
12
|
+
*
|
|
13
|
+
* Each source runs independently and reports its own outcome in `perSource`: a
|
|
14
|
+
* missing DisGeNET key or a GWAS Catalog outage degrades that one corpus to
|
|
15
|
+
* `unavailable` instead of failing a call the other two could have answered.
|
|
16
|
+
*
|
|
17
|
+
* The input is a flat object with a `queryType` discriminator — not a
|
|
18
|
+
* `z.discriminatedUnion`, which `defineTool` rejects (model tool calling needs
|
|
19
|
+
* a top-level `"type":"object"`).
|
|
20
|
+
*/
|
|
21
|
+
import { ok } from "neverthrow";
|
|
22
|
+
import { z } from "zod";
|
|
23
|
+
import { defineTool } from "../define-tool.js";
|
|
24
|
+
import { filterInformative, searchClinvar } from "../lib/clinvar-client.js";
|
|
25
|
+
import { searchDisgenet } from "../lib/disgenet-client.js";
|
|
26
|
+
import { searchGwasCatalog } from "../lib/gwas-catalog-client.js";
|
|
27
|
+
const SOURCES = ["gwas", "disgenet", "clinvar"];
|
|
28
|
+
const DEFAULT_LIMIT = 10;
|
|
29
|
+
const MAX_LIMIT = 100;
|
|
30
|
+
/** DisGeNET has no variant-level lookup; the other two do. */
|
|
31
|
+
function applicableSources(queryType) {
|
|
32
|
+
return queryType === "variant" ? ["gwas", "clinvar"] : [...SOURCES];
|
|
33
|
+
}
|
|
34
|
+
const inputSchema = z.object({
|
|
35
|
+
query: z
|
|
36
|
+
.string()
|
|
37
|
+
.min(1)
|
|
38
|
+
.describe("The entity, matching `queryType`. gene: a HUGO symbol ('PCSK9'); DisGeNET also takes an Entrez ID. disease: a disease or trait name " +
|
|
39
|
+
"('LDL cholesterol'); DisGeNET also takes a UMLS CUI ('C0006142'). variant: a dbSNP rsID ('rs11591147')."),
|
|
40
|
+
queryType: z
|
|
41
|
+
.enum(["gene", "disease", "variant"])
|
|
42
|
+
.describe("'gene' — the diseases/traits associated with a gene. 'disease' — the genes associated with a disease or trait (the GWAS Catalog calls it a " +
|
|
43
|
+
"trait; this value covers both). 'variant' — one rsID; DisGeNET is skipped, having no variant-level lookup."),
|
|
44
|
+
sources: z
|
|
45
|
+
.array(z.enum(SOURCES))
|
|
46
|
+
.min(1)
|
|
47
|
+
.optional()
|
|
48
|
+
.describe("Corpora to query in parallel. Default ALL applicable — they carry different evidence types, and disagreement between them is itself informative. " +
|
|
49
|
+
"'gwas': population SNP-trait associations with effect sizes and p-values (common-variant / MR support). " +
|
|
50
|
+
"'disgenet': curated + text-mined gene-disease associations scored 0–1, broadest coverage; needs DISGENET_API_KEY. " +
|
|
51
|
+
"'clinvar': clinically classified germline variants — pathogenicity and review status; rare/Mendelian rather than common-variant."),
|
|
52
|
+
limit: z
|
|
53
|
+
.number()
|
|
54
|
+
.int()
|
|
55
|
+
.min(1)
|
|
56
|
+
.max(MAX_LIMIT)
|
|
57
|
+
.optional()
|
|
58
|
+
.describe(`Max records PER SOURCE (default ${DEFAULT_LIMIT}, max ${MAX_LIMIT}); all three sources at the default return at most ` +
|
|
59
|
+
`${DEFAULT_LIMIT * 3} records. Check each source's \`totalFound\` before raising it.`),
|
|
60
|
+
pValueThreshold: z
|
|
61
|
+
.number()
|
|
62
|
+
.positive()
|
|
63
|
+
.optional()
|
|
64
|
+
.describe("'gwas' only. P-value ceiling; default 5e-8 (genome-wide significance). Raise for suggestive hits."),
|
|
65
|
+
minScore: z.number().min(0).max(1).optional().describe("'disgenet' only. Minimum GDA score 0–1; default 0.1. Higher = stronger evidence."),
|
|
66
|
+
disgenetSource: z
|
|
67
|
+
.enum(["ALL", "CURATED", "ANIMAL_MODELS", "BEFREE"])
|
|
68
|
+
.optional()
|
|
69
|
+
.describe("'disgenet' only. Provenance filter; default 'ALL'. Prefer 'CURATED' for anything you will quote — 'BEFREE' is text-mined and noisy."),
|
|
70
|
+
clinicalSignificance: z
|
|
71
|
+
.enum(["pathogenic", "likely-pathogenic", "benign", "likely-benign", "uncertain"])
|
|
72
|
+
.optional()
|
|
73
|
+
.describe("'clinvar' only. Restrict to one pathogenicity classification; omit for all."),
|
|
74
|
+
informativeOnly: z
|
|
75
|
+
.boolean()
|
|
76
|
+
.optional()
|
|
77
|
+
.describe("'clinvar' only. Default TRUE — drop variants classified 'not provided', 'not specified' or 'reclassified', which carry no clinical signal."),
|
|
78
|
+
});
|
|
79
|
+
/**
|
|
80
|
+
* Run one corpus, folding its failure into an `unavailable` outcome. A source
|
|
81
|
+
* that throws must not take the others down — that is the whole reason three
|
|
82
|
+
* tools could become one without losing the ability to say "this corpus was
|
|
83
|
+
* not reachable" as distinct from "this corpus knows nothing".
|
|
84
|
+
*/
|
|
85
|
+
async function runSource(source, fetch) {
|
|
86
|
+
try {
|
|
87
|
+
const { records, totalFound } = await fetch();
|
|
88
|
+
return {
|
|
89
|
+
outcome: {
|
|
90
|
+
source,
|
|
91
|
+
status: records.length > 0 ? "ok" : "no_data",
|
|
92
|
+
returned: records.length,
|
|
93
|
+
...(totalFound !== undefined ? { totalFound } : {}),
|
|
94
|
+
},
|
|
95
|
+
records,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
return {
|
|
100
|
+
outcome: {
|
|
101
|
+
source,
|
|
102
|
+
status: "unavailable",
|
|
103
|
+
returned: 0,
|
|
104
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
105
|
+
},
|
|
106
|
+
records: [],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export function createGeneDiseaseEvidenceTool(deps) {
|
|
111
|
+
return defineTool({
|
|
112
|
+
id: "gene_disease_evidence",
|
|
113
|
+
description: "Genetic evidence linking a gene to a disease or trait, across the GWAS Catalog, DisGeNET and ClinVar in one call — 'is there human genetic " +
|
|
114
|
+
"support for this target in this indication?'. See `sources` for what each corpus carries.\n" +
|
|
115
|
+
"For the integrated, pre-scored view prefer opentargets({action:'target'}) FIRST — it folds genetic association together with tractability " +
|
|
116
|
+
"and the drug landscape. Reach here for the underlying records: actual SNPs, effect sizes, scores and pathogenicity calls with their studies and PMIDs.\n" +
|
|
117
|
+
"ALWAYS read `perSource` before concluding anything is absent. 'no_data' means that corpus genuinely has nothing; 'unavailable' means it " +
|
|
118
|
+
"could not be reached (a missing DISGENET_API_KEY lands here — tell the user and proceed with the other two); 'not_applicable' means that " +
|
|
119
|
+
"corpus has no lookup for this queryType. Only 'no_data' is evidence of absence, and none is worth retrying unchanged.",
|
|
120
|
+
inputSchema,
|
|
121
|
+
execute: async (input) => {
|
|
122
|
+
const applicable = applicableSources(input.queryType);
|
|
123
|
+
const requested = input.sources ?? applicable;
|
|
124
|
+
const selected = requested.filter((s) => applicable.includes(s));
|
|
125
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
126
|
+
const output = {
|
|
127
|
+
query: input.query,
|
|
128
|
+
queryType: input.queryType,
|
|
129
|
+
perSource: requested
|
|
130
|
+
.filter((s) => !applicable.includes(s))
|
|
131
|
+
.map((source) => ({
|
|
132
|
+
source,
|
|
133
|
+
status: "not_applicable",
|
|
134
|
+
returned: 0,
|
|
135
|
+
detail: `${source} has no lookup for queryType '${input.queryType}'`,
|
|
136
|
+
})),
|
|
137
|
+
};
|
|
138
|
+
const [gwas, disgenet, clinvar] = await Promise.all([
|
|
139
|
+
selected.includes("gwas")
|
|
140
|
+
? runSource("gwas", async () => {
|
|
141
|
+
const searchType = input.queryType === "gene" ? "gene" : input.queryType === "disease" ? "trait" : "variant";
|
|
142
|
+
const res = await searchGwasCatalog(input.query, searchType, {
|
|
143
|
+
limit,
|
|
144
|
+
...(input.pValueThreshold !== undefined ? { pValueThreshold: input.pValueThreshold } : {}),
|
|
145
|
+
});
|
|
146
|
+
return { records: res.associations, totalFound: res.totalFound };
|
|
147
|
+
})
|
|
148
|
+
: null,
|
|
149
|
+
selected.includes("disgenet")
|
|
150
|
+
? runSource("disgenet", async () => {
|
|
151
|
+
if (!deps.disgenetApiKey)
|
|
152
|
+
throw new Error("DISGENET_API_KEY is not configured");
|
|
153
|
+
const records = await searchDisgenet(deps.disgenetApiKey, input.query, input.queryType === "gene" ? "gene" : "disease", {
|
|
154
|
+
limit,
|
|
155
|
+
...(input.minScore !== undefined ? { minScore: input.minScore } : {}),
|
|
156
|
+
...(input.disgenetSource !== undefined ? { source: input.disgenetSource } : {}),
|
|
157
|
+
});
|
|
158
|
+
return { records };
|
|
159
|
+
})
|
|
160
|
+
: null,
|
|
161
|
+
selected.includes("clinvar")
|
|
162
|
+
? runSource("clinvar", async () => {
|
|
163
|
+
const res = await searchClinvar(deps.ncbiApiKey, input.query, {
|
|
164
|
+
limit,
|
|
165
|
+
...(input.clinicalSignificance !== undefined ? { clinicalSignificance: input.clinicalSignificance } : {}),
|
|
166
|
+
});
|
|
167
|
+
const variants = (input.informativeOnly ?? true) ? filterInformative(res.variants) : res.variants;
|
|
168
|
+
return { records: variants, totalFound: res.totalFound };
|
|
169
|
+
})
|
|
170
|
+
: null,
|
|
171
|
+
]);
|
|
172
|
+
if (gwas) {
|
|
173
|
+
output.perSource.push(gwas.outcome);
|
|
174
|
+
output.gwas = gwas.records;
|
|
175
|
+
}
|
|
176
|
+
if (disgenet) {
|
|
177
|
+
output.perSource.push(disgenet.outcome);
|
|
178
|
+
output.disgenet = disgenet.records;
|
|
179
|
+
}
|
|
180
|
+
if (clinvar) {
|
|
181
|
+
output.perSource.push(clinvar.outcome);
|
|
182
|
+
output.clinvar = clinvar.records;
|
|
183
|
+
}
|
|
184
|
+
return ok(output);
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* genePreclinicalProfile — the in-vivo preclinical picture of one gene: where
|
|
3
|
+
* it is expressed at baseline (Bgee) and what removing it does to a mouse
|
|
4
|
+
* (IMPC), behind one `include`.
|
|
5
|
+
*
|
|
6
|
+
* The two halves share an input exactly — ONE human gene symbol, with the
|
|
7
|
+
* per-species orthologs resolved internally — and answer one question between
|
|
8
|
+
* them: is this target expressed where it needs to act, and is a model organism
|
|
9
|
+
* a fair surrogate for it. They were two tools that were called as a pair.
|
|
10
|
+
*
|
|
11
|
+
* Neither source caps its own output: Bgee returns every annotated tissue per
|
|
12
|
+
* species and IMPC every significant phenotype term, so both halves are trimmed
|
|
13
|
+
* here rather than in the clients — the target-assessment collectors read the
|
|
14
|
+
* same clients and legitimately want full fidelity for the dossier.
|
|
15
|
+
*/
|
|
16
|
+
import { type SupportedSpecies, type TissueRow } from "../lib/bgee-client.js";
|
|
17
|
+
import { type MpTerm, type ViabilityCall, type ViabilityCategory } from "../lib/impc-client.js";
|
|
18
|
+
interface BoundedSpeciesEntry {
|
|
19
|
+
species: SupportedSpecies;
|
|
20
|
+
taxonId: number;
|
|
21
|
+
ensemblId: string;
|
|
22
|
+
tissues: TissueRow[];
|
|
23
|
+
/** Tissues Bgee annotated for this species, before `minRank` and `tissueLimit`. */
|
|
24
|
+
tissueCount: number;
|
|
25
|
+
/** Tissues that passed `minRank`, before `tissueLimit`. */
|
|
26
|
+
tissuesAboveMinRank: number;
|
|
27
|
+
}
|
|
28
|
+
interface ExpressionHalf {
|
|
29
|
+
humanEnsemblId: string | null;
|
|
30
|
+
bySpecies: BoundedSpeciesEntry[];
|
|
31
|
+
notFound: string[];
|
|
32
|
+
}
|
|
33
|
+
interface KnockoutHalf {
|
|
34
|
+
mouseMarkerSymbol: string | null;
|
|
35
|
+
mgiAccessionId: string | null;
|
|
36
|
+
viability: ViabilityCategory;
|
|
37
|
+
viabilityCalls: ViabilityCall[];
|
|
38
|
+
mpTerms: MpTerm[];
|
|
39
|
+
organSystems: string[];
|
|
40
|
+
sexDimorphic: boolean;
|
|
41
|
+
phenotypeCount: number;
|
|
42
|
+
/** True when `phenotypeLimit` trimmed `mpTerms`; `phenotypeCount` is the real total. */
|
|
43
|
+
phenotypesTrimmed: boolean;
|
|
44
|
+
}
|
|
45
|
+
type PreclinicalOutput = {
|
|
46
|
+
geneSymbol: string;
|
|
47
|
+
expression?: ExpressionHalf;
|
|
48
|
+
knockout?: KnockoutHalf;
|
|
49
|
+
};
|
|
50
|
+
export declare const genePreclinicalProfileTool: import("../define-tool.js").Tool<{
|
|
51
|
+
geneSymbol: string;
|
|
52
|
+
include?: ("expression" | "knockout")[] | undefined;
|
|
53
|
+
species?: ("homo_sapiens" | "mus_musculus" | "rattus_norvegicus" | "canis_lupus_familiaris" | "macaca_mulatta")[] | undefined;
|
|
54
|
+
minRank?: "high" | "medium" | "low" | "absent" | undefined;
|
|
55
|
+
tissueLimit?: number | undefined;
|
|
56
|
+
phenotypeLimit?: number | undefined;
|
|
57
|
+
}, PreclinicalOutput>;
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* genePreclinicalProfile — the in-vivo preclinical picture of one gene: where
|
|
3
|
+
* it is expressed at baseline (Bgee) and what removing it does to a mouse
|
|
4
|
+
* (IMPC), behind one `include`.
|
|
5
|
+
*
|
|
6
|
+
* The two halves share an input exactly — ONE human gene symbol, with the
|
|
7
|
+
* per-species orthologs resolved internally — and answer one question between
|
|
8
|
+
* them: is this target expressed where it needs to act, and is a model organism
|
|
9
|
+
* a fair surrogate for it. They were two tools that were called as a pair.
|
|
10
|
+
*
|
|
11
|
+
* Neither source caps its own output: Bgee returns every annotated tissue per
|
|
12
|
+
* species and IMPC every significant phenotype term, so both halves are trimmed
|
|
13
|
+
* here rather than in the clients — the target-assessment collectors read the
|
|
14
|
+
* same clients and legitimately want full fidelity for the dossier.
|
|
15
|
+
*/
|
|
16
|
+
import { ok } from "neverthrow";
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
import { defineTool } from "../define-tool.js";
|
|
19
|
+
import { SUPPORTED_SPECIES, getMultiSpeciesExpression } from "../lib/bgee-client.js";
|
|
20
|
+
import { getKoPhenotypeProfile } from "../lib/impc-client.js";
|
|
21
|
+
/** Ordered weakest → strongest so `minRank` can be a numeric floor. */
|
|
22
|
+
const RANK_ORDER = { absent: 0, low: 1, medium: 2, high: 3 };
|
|
23
|
+
/** Human + mouse: the pairing that answers "is the mouse a fair surrogate?". */
|
|
24
|
+
const DEFAULT_SPECIES = ["homo_sapiens", "mus_musculus"];
|
|
25
|
+
const DEFAULTS = { tissueLimit: 15, phenotypeLimit: 20, minRank: "low" };
|
|
26
|
+
const inputSchema = z.object({
|
|
27
|
+
geneSymbol: z
|
|
28
|
+
.string()
|
|
29
|
+
.min(1)
|
|
30
|
+
.describe("HUMAN gene symbol, e.g. 'BRCA1' — one gene per call. Ensembl IDs, mouse symbols and MGI IDs are NOT accepted; the ENSG and the per-species " +
|
|
31
|
+
"orthologs are resolved for you."),
|
|
32
|
+
include: z
|
|
33
|
+
.array(z.enum(["expression", "knockout"]))
|
|
34
|
+
.min(1)
|
|
35
|
+
.optional()
|
|
36
|
+
.describe("Default BOTH — two sides of one judgement, one request each. 'expression': Bgee baseline (healthy, untreated) expression per species and " +
|
|
37
|
+
"tissue. 'knockout': IMPC mouse loss-of-function phenotype."),
|
|
38
|
+
species: z
|
|
39
|
+
.array(z.enum(SUPPORTED_SPECIES))
|
|
40
|
+
.min(1)
|
|
41
|
+
.optional()
|
|
42
|
+
.describe("'expression' only. Default ['homo_sapiens','mus_musculus'] — the surrogate question. Add rat/dog/macaque when the cross-species comparison " +
|
|
43
|
+
"is the point; dog and macaque coverage is thin, so expect empty entries."),
|
|
44
|
+
minRank: z
|
|
45
|
+
.enum(["absent", "low", "medium", "high"])
|
|
46
|
+
.optional()
|
|
47
|
+
.describe("'expression' only. Drop tissues below this bucketed rank; default 'low' (drops only not-expressed). Use 'medium'/'high' for just the tissues " +
|
|
48
|
+
"where the gene is abundant — the usual tissue-of-action question."),
|
|
49
|
+
tissueLimit: z
|
|
50
|
+
.number()
|
|
51
|
+
.int()
|
|
52
|
+
.min(1)
|
|
53
|
+
.max(100)
|
|
54
|
+
.optional()
|
|
55
|
+
.describe(`'expression' only. Max tissues per species after minRank, highest expression first (default ${DEFAULTS.tissueLimit}, max 100). ` +
|
|
56
|
+
"`tissueCount`/`tissuesAboveMinRank` give the pre-trim counts."),
|
|
57
|
+
phenotypeLimit: z
|
|
58
|
+
.number()
|
|
59
|
+
.int()
|
|
60
|
+
.min(1)
|
|
61
|
+
.max(200)
|
|
62
|
+
.optional()
|
|
63
|
+
.describe(`'knockout' only. Max MP phenotype terms, best p-value first (default ${DEFAULTS.phenotypeLimit}, max 200). \`phenotypeCount\` gives the ` +
|
|
64
|
+
"true total; `organSystems` is never trimmed, so the top-line picture survives."),
|
|
65
|
+
});
|
|
66
|
+
function boundExpression(raw, minRank, tissueLimit) {
|
|
67
|
+
const floor = RANK_ORDER[minRank];
|
|
68
|
+
return {
|
|
69
|
+
humanEnsemblId: raw.humanEnsemblId,
|
|
70
|
+
bySpecies: raw.bySpecies.map((entry) => {
|
|
71
|
+
const aboveFloor = entry.tissues.filter((t) => RANK_ORDER[t.rank] >= floor);
|
|
72
|
+
const ranked = [...aboveFloor].sort((a, b) => (b.expressionScore ?? 0) - (a.expressionScore ?? 0));
|
|
73
|
+
return {
|
|
74
|
+
species: entry.species,
|
|
75
|
+
taxonId: entry.taxonId,
|
|
76
|
+
ensemblId: entry.ensemblId,
|
|
77
|
+
tissues: ranked.slice(0, tissueLimit),
|
|
78
|
+
tissueCount: entry.tissues.length,
|
|
79
|
+
tissuesAboveMinRank: aboveFloor.length,
|
|
80
|
+
};
|
|
81
|
+
}),
|
|
82
|
+
notFound: raw.notFound,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function boundKnockout(raw, phenotypeLimit) {
|
|
86
|
+
return {
|
|
87
|
+
mouseMarkerSymbol: raw.mouseMarkerSymbol,
|
|
88
|
+
mgiAccessionId: raw.mgiAccessionId,
|
|
89
|
+
viability: raw.viability,
|
|
90
|
+
viabilityCalls: raw.viabilityCalls,
|
|
91
|
+
mpTerms: raw.mpTerms.slice(0, phenotypeLimit),
|
|
92
|
+
organSystems: raw.organSystems,
|
|
93
|
+
sexDimorphic: raw.sexDimorphic,
|
|
94
|
+
phenotypeCount: raw.phenotypeCount,
|
|
95
|
+
phenotypesTrimmed: raw.mpTerms.length > phenotypeLimit,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export const genePreclinicalProfileTool = defineTool({
|
|
99
|
+
id: "gene_preclinical_profile",
|
|
100
|
+
description: "The in-vivo preclinical profile of ONE human gene — baseline expression (Bgee) and mouse-knockout phenotype (IMPC) in one call. Answers " +
|
|
101
|
+
"tissue-of-action ('where does this target act?'), model-organism suitability ('is the mouse a fair surrogate?') and essentiality ('what happens " +
|
|
102
|
+
"when this gene is lost?').\n" +
|
|
103
|
+
"Expression is BASELINE (healthy, untreated) only — differential expression between conditions is the analysis pipeline's job, never this tool.\n" +
|
|
104
|
+
"Output is trimmed by default (see `minRank`, `tissueLimit`, `phenotypeLimit`); the accompanying counts distinguish a trimmed list from a sparse one.\n" +
|
|
105
|
+
"SPARSE OUTPUT IS VALID NO-DATA, not an error — do not retry. A null humanEnsemblId means the symbol did not resolve; a null mouseMarkerSymbol " +
|
|
106
|
+
"with no phenotype terms means the gene has not been IMPC-phenotyped, which is common.",
|
|
107
|
+
inputSchema,
|
|
108
|
+
execute: async ({ geneSymbol, include, species, minRank, tissueLimit, phenotypeLimit }) => {
|
|
109
|
+
const halves = include ?? ["expression", "knockout"];
|
|
110
|
+
const wantExpression = halves.includes("expression");
|
|
111
|
+
const wantKnockout = halves.includes("knockout");
|
|
112
|
+
const [expressionRaw, knockoutRaw] = await Promise.all([
|
|
113
|
+
wantExpression ? getMultiSpeciesExpression(geneSymbol, [...(species ?? DEFAULT_SPECIES)]) : Promise.resolve(null),
|
|
114
|
+
wantKnockout ? getKoPhenotypeProfile(geneSymbol) : Promise.resolve(null),
|
|
115
|
+
]);
|
|
116
|
+
const output = { geneSymbol };
|
|
117
|
+
if (expressionRaw) {
|
|
118
|
+
output.expression = boundExpression(expressionRaw, minRank ?? DEFAULTS.minRank, tissueLimit ?? DEFAULTS.tissueLimit);
|
|
119
|
+
}
|
|
120
|
+
if (knockoutRaw) {
|
|
121
|
+
output.knockout = boundKnockout(knockoutRaw, phenotypeLimit ?? DEFAULTS.phenotypeLimit);
|
|
122
|
+
}
|
|
123
|
+
return ok(output);
|
|
124
|
+
},
|
|
125
|
+
});
|
|
@@ -1,29 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bio barrel — pure external-API bioinformatics & cheminformatics lookups.
|
|
3
3
|
*
|
|
4
|
-
* Leaf tools with no harness dependencies: each wraps
|
|
5
|
-
* (Ensembl, ChEMBL, PubChem, Open Targets, PubMed, EPA CompTox, …)
|
|
6
|
-
* `defineTool`. Grouped here so the conversation agent imports one
|
|
7
|
-
* rather than
|
|
4
|
+
* Leaf tools with no harness dependencies: each wraps one or more external data
|
|
5
|
+
* sources (Ensembl, ChEMBL, PubChem, Open Targets, PubMed, EPA CompTox, …)
|
|
6
|
+
* behind a `defineTool`. Grouped here so the conversation agent imports one
|
|
7
|
+
* barrel rather than a file per tool.
|
|
8
|
+
*
|
|
9
|
+
* The boundary is the QUESTION, not the database. Where several corpora answer
|
|
10
|
+
* the same question, the corpus is a `sources` parameter and the tool fans out
|
|
11
|
+
* (`gene_disease_evidence`, `drug_gene_interactions`, `target_safety`,
|
|
12
|
+
* `lookup_annotation`, `gene_preclinical_profile`); where one database answers
|
|
13
|
+
* several questions, the endpoint is an `action` parameter (`chembl`,
|
|
14
|
+
* `pubchem`, `pubmed`, `comptox`, `opentargets`, `search_interactions`).
|
|
15
|
+
*
|
|
16
|
+
* Every tool returns a BOUNDED result by default. A default call is sized to be
|
|
17
|
+
* read, not to be complete: limits are small, verbose fields are opt-in, and
|
|
18
|
+
* each result carries the true totals (`totalFound`, `totalInteractions`,
|
|
19
|
+
* `tissueCount`, `outline`, …) so a caller can tell a trimmed answer from a
|
|
20
|
+
* sparse one and widen deliberately.
|
|
8
21
|
*/
|
|
9
22
|
export * from "./search-gene.js";
|
|
10
|
-
export * from "./
|
|
11
|
-
export * from "./lookup-go-term.js";
|
|
23
|
+
export * from "./lookup-annotation.js";
|
|
12
24
|
export * from "./search-interactions.js";
|
|
13
25
|
export * from "./pubmed.js";
|
|
14
26
|
export * from "./chembl.js";
|
|
15
27
|
export * from "./pubchem.js";
|
|
16
28
|
export * from "./opentargets.js";
|
|
17
|
-
export * from "./
|
|
18
|
-
export * from "./
|
|
29
|
+
export * from "./gene-disease-evidence.js";
|
|
30
|
+
export * from "./drug-gene-interactions.js";
|
|
31
|
+
export * from "./gene-preclinical-profile.js";
|
|
19
32
|
export * from "./search-clinical-trials.js";
|
|
20
33
|
export * from "./search-geo-datasets.js";
|
|
21
|
-
export * from "./search-
|
|
22
|
-
export * from "./
|
|
23
|
-
export * from "./search-disgenet.js";
|
|
24
|
-
export * from "./search-drugbank.js";
|
|
25
|
-
export * from "./search-gwas-catalog.js";
|
|
26
|
-
export * from "./search-bgee-expression.js";
|
|
27
|
-
export * from "./get-impc-ko-profile.js";
|
|
28
|
-
export * from "./check-safety-panel.js";
|
|
34
|
+
export * from "./search-faers.js";
|
|
35
|
+
export * from "./target-safety.js";
|
|
29
36
|
export * from "./comptox.js";
|
package/dist/tools/bio/index.js
CHANGED
|
@@ -1,36 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bio barrel — pure external-API bioinformatics & cheminformatics lookups.
|
|
3
3
|
*
|
|
4
|
-
* Leaf tools with no harness dependencies: each wraps
|
|
5
|
-
* (Ensembl, ChEMBL, PubChem, Open Targets, PubMed, EPA CompTox, …)
|
|
6
|
-
* `defineTool`. Grouped here so the conversation agent imports one
|
|
7
|
-
* rather than
|
|
4
|
+
* Leaf tools with no harness dependencies: each wraps one or more external data
|
|
5
|
+
* sources (Ensembl, ChEMBL, PubChem, Open Targets, PubMed, EPA CompTox, …)
|
|
6
|
+
* behind a `defineTool`. Grouped here so the conversation agent imports one
|
|
7
|
+
* barrel rather than a file per tool.
|
|
8
|
+
*
|
|
9
|
+
* The boundary is the QUESTION, not the database. Where several corpora answer
|
|
10
|
+
* the same question, the corpus is a `sources` parameter and the tool fans out
|
|
11
|
+
* (`gene_disease_evidence`, `drug_gene_interactions`, `target_safety`,
|
|
12
|
+
* `lookup_annotation`, `gene_preclinical_profile`); where one database answers
|
|
13
|
+
* several questions, the endpoint is an `action` parameter (`chembl`,
|
|
14
|
+
* `pubchem`, `pubmed`, `comptox`, `opentargets`, `search_interactions`).
|
|
15
|
+
*
|
|
16
|
+
* Every tool returns a BOUNDED result by default. A default call is sized to be
|
|
17
|
+
* read, not to be complete: limits are small, verbose fields are opt-in, and
|
|
18
|
+
* each result carries the true totals (`totalFound`, `totalInteractions`,
|
|
19
|
+
* `tissueCount`, `outline`, …) so a caller can tell a trimmed answer from a
|
|
20
|
+
* sparse one and widen deliberately.
|
|
8
21
|
*/
|
|
9
|
-
//
|
|
22
|
+
// Identifier resolution
|
|
10
23
|
export * from "./search-gene.js";
|
|
11
|
-
|
|
12
|
-
export * from "./lookup-
|
|
24
|
+
// Functional annotation / networks
|
|
25
|
+
export * from "./lookup-annotation.js";
|
|
13
26
|
export * from "./search-interactions.js";
|
|
14
27
|
// Literature
|
|
15
28
|
export * from "./pubmed.js";
|
|
16
|
-
//
|
|
29
|
+
// Cheminformatics
|
|
17
30
|
export * from "./chembl.js";
|
|
18
|
-
// PubChem
|
|
19
31
|
export * from "./pubchem.js";
|
|
20
|
-
//
|
|
32
|
+
// Target assessment
|
|
21
33
|
export * from "./opentargets.js";
|
|
22
|
-
export * from "./
|
|
23
|
-
export * from "./
|
|
34
|
+
export * from "./gene-disease-evidence.js";
|
|
35
|
+
export * from "./drug-gene-interactions.js";
|
|
36
|
+
export * from "./gene-preclinical-profile.js";
|
|
37
|
+
// Clinical / public-data landscape
|
|
24
38
|
export * from "./search-clinical-trials.js";
|
|
25
39
|
export * from "./search-geo-datasets.js";
|
|
26
|
-
export * from "./search-
|
|
27
|
-
|
|
28
|
-
export * from "./
|
|
29
|
-
export * from "./search-drugbank.js";
|
|
30
|
-
export * from "./search-gwas-catalog.js";
|
|
31
|
-
// Preclinical
|
|
32
|
-
export * from "./search-bgee-expression.js";
|
|
33
|
-
export * from "./get-impc-ko-profile.js";
|
|
34
|
-
// Off-target liability / EPA CompTox
|
|
35
|
-
export * from "./check-safety-panel.js";
|
|
40
|
+
export * from "./search-faers.js";
|
|
41
|
+
// Safety / toxicology
|
|
42
|
+
export * from "./target-safety.js";
|
|
36
43
|
export * from "./comptox.js";
|
package/dist/tools/bio/keys.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Logger } from "../../lib/logger.js";
|
|
1
2
|
import type { Tool } from "../define-tool.js";
|
|
2
3
|
/**
|
|
3
4
|
* API keys for the external bio/chem data sources. Threaded from the
|
|
@@ -14,23 +15,29 @@ export interface BioToolKeys {
|
|
|
14
15
|
readonly github?: string;
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
|
-
* The NCBI-backed literature
|
|
18
|
+
* The NCBI-backed literature tool, built from the shared key slice.
|
|
18
19
|
*
|
|
19
20
|
* `pubmed` is the consolidated literature tool (search / details / fulltext
|
|
20
|
-
* behind one `action`)
|
|
21
|
+
* behind one `action`). ClinVar is no longer its own tool — it is one of the
|
|
22
|
+
* corpora behind `gene_disease_evidence`, which also needs the NCBI key.
|
|
21
23
|
*/
|
|
22
24
|
export declare function createNcbiTools(keys: BioToolKeys): {
|
|
23
25
|
pubmed: Tool;
|
|
24
|
-
searchClinvar: Tool;
|
|
25
26
|
};
|
|
26
27
|
/**
|
|
27
|
-
* The
|
|
28
|
+
* The keyed multi-source tools.
|
|
28
29
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
30
|
+
* Each of these fans out over several corpora and needs more than one key, so
|
|
31
|
+
* they are built together from the whole slice rather than per source:
|
|
32
|
+
* `geneDiseaseEvidence` spans the GWAS Catalog (public), DisGeNET (keyed) and
|
|
33
|
+
* ClinVar (NCBI key), and `drugGeneInteractions` spans DGIdb (public), DrugBank
|
|
34
|
+
* (keyed) and PharmGKB (public). A tool whose key is absent degrades that one
|
|
35
|
+
* corpus to `unavailable` in its `perSource` report rather than failing.
|
|
31
36
|
*/
|
|
32
|
-
export declare function createChemDbTools(keys: BioToolKeys
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
export declare function createChemDbTools(keys: BioToolKeys, deps?: {
|
|
38
|
+
readonly logger?: Logger;
|
|
39
|
+
}): {
|
|
40
|
+
geneDiseaseEvidence: Tool;
|
|
41
|
+
drugGeneInteractions: Tool;
|
|
35
42
|
comptox: Tool;
|
|
36
43
|
};
|
package/dist/tools/bio/keys.js
CHANGED
|
@@ -1,30 +1,39 @@
|
|
|
1
|
-
import { createPubMedTool } from "./pubmed.js";
|
|
2
|
-
import { createSearchClinvarTool } from "./search-clinvar.js";
|
|
3
|
-
import { createSearchDrugbankTool } from "./search-drugbank.js";
|
|
4
|
-
import { createSearchDisgenetTool } from "./search-disgenet.js";
|
|
5
1
|
import { createComptoxTool } from "./comptox.js";
|
|
2
|
+
import { createDrugGeneInteractionsTool } from "./drug-gene-interactions.js";
|
|
3
|
+
import { createGeneDiseaseEvidenceTool } from "./gene-disease-evidence.js";
|
|
4
|
+
import { createPubMedTool } from "./pubmed.js";
|
|
6
5
|
/**
|
|
7
|
-
* The NCBI-backed literature
|
|
6
|
+
* The NCBI-backed literature tool, built from the shared key slice.
|
|
8
7
|
*
|
|
9
8
|
* `pubmed` is the consolidated literature tool (search / details / fulltext
|
|
10
|
-
* behind one `action`)
|
|
9
|
+
* behind one `action`). ClinVar is no longer its own tool — it is one of the
|
|
10
|
+
* corpora behind `gene_disease_evidence`, which also needs the NCBI key.
|
|
11
11
|
*/
|
|
12
12
|
export function createNcbiTools(keys) {
|
|
13
13
|
return {
|
|
14
14
|
pubmed: createPubMedTool({ ncbiApiKey: keys.ncbi }),
|
|
15
|
-
searchClinvar: createSearchClinvarTool({ ncbiApiKey: keys.ncbi }),
|
|
16
15
|
};
|
|
17
16
|
}
|
|
18
17
|
/**
|
|
19
|
-
* The
|
|
18
|
+
* The keyed multi-source tools.
|
|
20
19
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* Each of these fans out over several corpora and needs more than one key, so
|
|
21
|
+
* they are built together from the whole slice rather than per source:
|
|
22
|
+
* `geneDiseaseEvidence` spans the GWAS Catalog (public), DisGeNET (keyed) and
|
|
23
|
+
* ClinVar (NCBI key), and `drugGeneInteractions` spans DGIdb (public), DrugBank
|
|
24
|
+
* (keyed) and PharmGKB (public). A tool whose key is absent degrades that one
|
|
25
|
+
* corpus to `unavailable` in its `perSource` report rather than failing.
|
|
23
26
|
*/
|
|
24
|
-
export function createChemDbTools(keys) {
|
|
27
|
+
export function createChemDbTools(keys, deps = {}) {
|
|
25
28
|
return {
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
geneDiseaseEvidence: createGeneDiseaseEvidenceTool({
|
|
30
|
+
disgenetApiKey: keys.disgenet,
|
|
31
|
+
...(keys.ncbi ? { ncbiApiKey: keys.ncbi } : {}),
|
|
32
|
+
}),
|
|
33
|
+
drugGeneInteractions: createDrugGeneInteractionsTool({
|
|
34
|
+
drugbankApiKey: keys.drugbank,
|
|
35
|
+
...(deps.logger ? { logger: deps.logger } : {}),
|
|
36
|
+
}),
|
|
28
37
|
comptox: createComptoxTool({ apiKey: keys.epaCcte }),
|
|
29
38
|
};
|
|
30
39
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lookupAnnotation — one tool over the functional-annotation vocabularies:
|
|
3
|
+
* Gene Ontology (QuickGO) and the pathway databases (KEGG, Reactome).
|
|
4
|
+
*
|
|
5
|
+
* These were two tools asking one question — "what is this gene or term known
|
|
6
|
+
* to do?" — against different vocabularies. `search_pathway` already treated
|
|
7
|
+
* the corpus as a parameter (`source: kegg | reactome | both`) rather than a
|
|
8
|
+
* tool boundary; this extends the same shape to GO.
|
|
9
|
+
*
|
|
10
|
+
* The input is a flat object with a `vocabulary` discriminator — not a
|
|
11
|
+
* `z.discriminatedUnion`, which `defineTool` rejects (model tool calling needs
|
|
12
|
+
* a top-level `"type":"object"`). Per-vocabulary parameters are optional in the
|
|
13
|
+
* schema and made conditionally required by `.refine`, so a malformed call
|
|
14
|
+
* fails at the loop boundary naming the missing field instead of reaching an
|
|
15
|
+
* API request that cannot be built.
|
|
16
|
+
*/
|
|
17
|
+
import { type Pathway } from "../lib/pathway-client.js";
|
|
18
|
+
interface GoTerm {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
definition?: string;
|
|
22
|
+
aspect?: string;
|
|
23
|
+
}
|
|
24
|
+
interface GoAnnotation {
|
|
25
|
+
geneProductId: string;
|
|
26
|
+
goId: string;
|
|
27
|
+
goName: string;
|
|
28
|
+
aspect?: string;
|
|
29
|
+
evidenceCode?: string;
|
|
30
|
+
qualifier?: string;
|
|
31
|
+
}
|
|
32
|
+
type AnnotationOutput = {
|
|
33
|
+
terms?: GoTerm[];
|
|
34
|
+
annotations?: GoAnnotation[];
|
|
35
|
+
} | {
|
|
36
|
+
pathways: Pathway[];
|
|
37
|
+
};
|
|
38
|
+
export declare const lookupAnnotationTool: import("../define-tool.js").Tool<{
|
|
39
|
+
vocabulary: "kegg" | "reactome" | "go" | "pathways";
|
|
40
|
+
query?: string | undefined;
|
|
41
|
+
goId?: string | undefined;
|
|
42
|
+
geneProductId?: string | undefined;
|
|
43
|
+
taxonId?: number | undefined;
|
|
44
|
+
organism?: string | undefined;
|
|
45
|
+
includeGenes?: boolean | undefined;
|
|
46
|
+
limit?: number | undefined;
|
|
47
|
+
}, AnnotationOutput>;
|
|
48
|
+
export {};
|