@inflexa-ai/harness 0.29.0 → 0.30.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 +7 -4
- package/dist/agents/report-session-agent.js +1 -1
- package/dist/agents/sandbox/data-profiler.js +0 -1
- package/dist/agents/sandbox/immune-profiling-agent.js +3 -1
- package/dist/agents/sandbox/network-agent.js +0 -1
- package/dist/agents/sandbox/types.d.ts +1 -1
- package/dist/agents/sandbox/types.js +1 -1
- package/dist/config/resource-limits.d.ts +1 -1
- package/dist/config/resource-limits.js +1 -1
- package/dist/contracts/schemas/chat-parts.d.ts +12 -12
- package/dist/contracts/severity.d.ts +2 -2
- package/dist/contracts/target-dossier.d.ts +70 -70
- package/dist/data/safety-panel-schema.d.ts +4 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.js +9 -0
- package/dist/loop/run-agent.d.ts +14 -1
- package/dist/loop/run-agent.js +6 -1
- package/dist/prompts/SOUL.d.ts +2 -2
- package/dist/prompts/SOUL.js +17 -1
- package/dist/prompts/conversation.d.ts +1 -1
- package/dist/prompts/conversation.js +43 -71
- package/dist/prompts/planner.js +57 -10
- package/dist/prompts/sandbox/bulk-transcriptomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/bulk-transcriptomics-agent.js +3 -1
- package/dist/prompts/sandbox/dna-methylation-agent.d.ts +1 -1
- package/dist/prompts/sandbox/dna-methylation-agent.js +18 -12
- package/dist/prompts/sandbox/immune-profiling-agent.d.ts +1 -1
- package/dist/prompts/sandbox/immune-profiling-agent.js +6 -2
- package/dist/prompts/sandbox/metabolomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/metabolomics-agent.js +8 -4
- package/dist/prompts/sandbox/microbiome-agent.d.ts +1 -1
- package/dist/prompts/sandbox/microbiome-agent.js +12 -6
- package/dist/prompts/sandbox/network-agent.d.ts +1 -1
- package/dist/prompts/sandbox/network-agent.js +9 -6
- package/dist/prompts/sandbox/spatial-omics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/spatial-omics-agent.js +4 -2
- package/dist/providers/ai-sdk.js +4 -0
- package/dist/providers/reasoning.d.ts +35 -0
- package/dist/providers/reasoning.js +34 -0
- package/dist/providers/types.d.ts +26 -0
- package/dist/schemas/data-profile-schemas.d.ts +4 -4
- package/dist/schemas/run-synthesis.d.ts +4 -4
- package/dist/tools/bio/chembl.d.ts +1 -1
- package/dist/tools/bio/chembl.js +15 -10
- package/dist/tools/bio/comptox.js +5 -1
- package/dist/tools/bio/drug-gene-interactions.js +5 -2
- package/dist/tools/bio/gene-disease-evidence.d.ts +19 -9
- package/dist/tools/bio/gene-disease-evidence.js +78 -22
- package/dist/tools/bio/gene-preclinical-profile.d.ts +33 -13
- package/dist/tools/bio/gene-preclinical-profile.js +63 -22
- package/dist/tools/bio/lookup-annotation.d.ts +1 -0
- package/dist/tools/bio/lookup-annotation.js +28 -10
- package/dist/tools/bio/opentargets.d.ts +10 -2
- package/dist/tools/bio/opentargets.js +42 -13
- package/dist/tools/bio/pubchem.js +5 -2
- package/dist/tools/bio/pubmed.js +9 -3
- package/dist/tools/bio/search-clinical-trials.d.ts +25 -25
- package/dist/tools/bio/search-clinical-trials.js +56 -18
- package/dist/tools/bio/search-faers.d.ts +26 -6
- package/dist/tools/bio/search-faers.js +70 -18
- package/dist/tools/bio/search-gene.d.ts +19 -3
- package/dist/tools/bio/search-gene.js +69 -12
- package/dist/tools/bio/search-geo-datasets.js +4 -1
- package/dist/tools/bio/search-interactions.js +6 -2
- package/dist/tools/bio/target-safety.d.ts +2 -2
- package/dist/tools/bio/target-safety.js +3 -2
- package/dist/tools/lib/cbioportal-client.js +25 -6
- package/dist/tools/lib/chembl-client.d.ts +3 -1
- package/dist/tools/lib/chembl-client.js +6 -1
- package/dist/tools/lib/gwas-catalog-client.d.ts +7 -6
- package/dist/tools/lib/gwas-catalog-client.js +18 -6
- package/dist/tools/lib/openfda-client.d.ts +7 -5
- package/dist/tools/lib/openfda-client.js +17 -9
- package/dist/tools/lib/opentargets-client.d.ts +20 -0
- package/dist/tools/lib/opentargets-client.js +45 -0
- package/dist/tools/lib/pathway-client.d.ts +7 -0
- package/dist/tools/lib/pathway-client.js +68 -1
- package/dist/tools/research/context7-docs.js +3 -3
- package/dist/tools/research/generate-analogy-report.js +2 -2
- package/dist/tools/research/generate-plan.d.ts +3 -0
- package/dist/tools/research/generate-plan.js +64 -5
- package/dist/tools/research/resolve-citation.js +8 -3
- package/dist/tools/research/search-arxiv.js +8 -3
- package/dist/tools/research/search-semantic-scholar.js +10 -4
- package/dist/workflows/sandbox-step.d.ts +6 -0
- package/dist/workflows/sandbox-step.js +31 -14
- package/dist/workflows/target-assessment/assemblers/safety.d.ts +1 -1
- package/dist/workflows/target-assessment/phase4-assemble.d.ts +17 -17
- package/dist/workflows/target-assessment/schemas.d.ts +12 -12
- package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +6 -6
- package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +6 -6
- package/dist/workflows/target-assessment/synthesis/index.d.ts +12 -12
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* geneDiseaseEvidence — one tool over the
|
|
3
|
-
* the NHGRI-EBI GWAS Catalog, DisGeNET,
|
|
2
|
+
* geneDiseaseEvidence — one tool over the four gene↔disease evidence corpora:
|
|
3
|
+
* the NHGRI-EBI GWAS Catalog, DisGeNET, NCBI ClinVar, and cBioPortal.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* The first three were three tools with the same input skeleton (`query` + a
|
|
6
6
|
* gene/disease/variant discriminator + a strength threshold + `limit`)
|
|
7
7
|
* answering the same question — what genetic evidence links this gene to this
|
|
8
8
|
* disease or trait. Picking between them was never a routing decision an agent
|
|
@@ -10,19 +10,28 @@
|
|
|
10
10
|
* defaults to all of them. `search_pathway`'s `source: kegg | reactome | both`
|
|
11
11
|
* is the same shape.
|
|
12
12
|
*
|
|
13
|
+
* cBioPortal joins them as the somatic half of the same question, and it is the
|
|
14
|
+
* one source that is NOT in the default set: it scans every curated study, thus
|
|
15
|
+
* it costs several large requests that a routine gene query must not pay.
|
|
16
|
+
*
|
|
13
17
|
* Each source runs independently and reports its own outcome in `perSource`: a
|
|
14
18
|
* missing DisGeNET key or a GWAS Catalog outage degrades that one corpus to
|
|
15
|
-
* `unavailable` instead of failing a call the
|
|
19
|
+
* `unavailable` instead of failing a call the others could have answered.
|
|
16
20
|
*
|
|
17
21
|
* The input is a flat object with a `queryType` discriminator — not a
|
|
18
22
|
* `z.discriminatedUnion`, which `defineTool` rejects (model tool calling needs
|
|
19
|
-
* a top-level `"type":"object"`).
|
|
23
|
+
* a top-level `"type":"object"`). A `queryType` that only one corpus can serve
|
|
24
|
+
* — an accession of that corpus — marks the others `not_applicable` rather
|
|
25
|
+
* than sending them a query they cannot read.
|
|
20
26
|
*/
|
|
27
|
+
import { type MutationFrequency } from "../lib/cbioportal-client.js";
|
|
21
28
|
import { type ClinvarVariant } from "../lib/clinvar-client.js";
|
|
22
29
|
import { type Gda } from "../lib/disgenet-client.js";
|
|
23
30
|
import { type GwasAssociation } from "../lib/gwas-catalog-client.js";
|
|
24
|
-
declare const SOURCES: readonly ["gwas", "disgenet", "clinvar"];
|
|
31
|
+
declare const SOURCES: readonly ["gwas", "disgenet", "clinvar", "cbioportal"];
|
|
25
32
|
type Source = (typeof SOURCES)[number];
|
|
33
|
+
declare const QUERY_TYPES: readonly ["gene", "disease", "variant", "gwas_study", "clinvar_accession"];
|
|
34
|
+
type QueryType = (typeof QUERY_TYPES)[number];
|
|
26
35
|
/**
|
|
27
36
|
* Per-source outcome. `unavailable` (key absent, corpus erroring) and
|
|
28
37
|
* `not_applicable` (the corpus has no lookup for this queryType) are both
|
|
@@ -38,19 +47,20 @@ interface SourceOutcome {
|
|
|
38
47
|
}
|
|
39
48
|
interface GeneDiseaseEvidenceOutput {
|
|
40
49
|
query: string;
|
|
41
|
-
queryType:
|
|
50
|
+
queryType: QueryType;
|
|
42
51
|
perSource: SourceOutcome[];
|
|
43
52
|
gwas?: GwasAssociation[];
|
|
44
53
|
disgenet?: Gda[];
|
|
45
54
|
clinvar?: ClinvarVariant[];
|
|
55
|
+
cbioportal?: MutationFrequency[];
|
|
46
56
|
}
|
|
47
57
|
export declare function createGeneDiseaseEvidenceTool(deps: {
|
|
48
58
|
ncbiApiKey?: string;
|
|
49
59
|
disgenetApiKey: string;
|
|
50
60
|
}): import("../define-tool.js").Tool<{
|
|
51
61
|
query: string;
|
|
52
|
-
queryType: "gene" | "disease" | "variant";
|
|
53
|
-
sources?: ("clinvar" | "gwas" | "disgenet")[] | undefined;
|
|
62
|
+
queryType: "gene" | "disease" | "variant" | "gwas_study" | "clinvar_accession";
|
|
63
|
+
sources?: ("clinvar" | "gwas" | "disgenet" | "cbioportal")[] | undefined;
|
|
54
64
|
limit?: number | undefined;
|
|
55
65
|
pValueThreshold?: number | undefined;
|
|
56
66
|
minScore?: number | undefined;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* geneDiseaseEvidence — one tool over the
|
|
3
|
-
* the NHGRI-EBI GWAS Catalog, DisGeNET,
|
|
2
|
+
* geneDiseaseEvidence — one tool over the four gene↔disease evidence corpora:
|
|
3
|
+
* the NHGRI-EBI GWAS Catalog, DisGeNET, NCBI ClinVar, and cBioPortal.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* The first three were three tools with the same input skeleton (`query` + a
|
|
6
6
|
* gene/disease/variant discriminator + a strength threshold + `limit`)
|
|
7
7
|
* answering the same question — what genetic evidence links this gene to this
|
|
8
8
|
* disease or trait. Picking between them was never a routing decision an agent
|
|
@@ -10,45 +10,87 @@
|
|
|
10
10
|
* defaults to all of them. `search_pathway`'s `source: kegg | reactome | both`
|
|
11
11
|
* is the same shape.
|
|
12
12
|
*
|
|
13
|
+
* cBioPortal joins them as the somatic half of the same question, and it is the
|
|
14
|
+
* one source that is NOT in the default set: it scans every curated study, thus
|
|
15
|
+
* it costs several large requests that a routine gene query must not pay.
|
|
16
|
+
*
|
|
13
17
|
* Each source runs independently and reports its own outcome in `perSource`: a
|
|
14
18
|
* missing DisGeNET key or a GWAS Catalog outage degrades that one corpus to
|
|
15
|
-
* `unavailable` instead of failing a call the
|
|
19
|
+
* `unavailable` instead of failing a call the others could have answered.
|
|
16
20
|
*
|
|
17
21
|
* The input is a flat object with a `queryType` discriminator — not a
|
|
18
22
|
* `z.discriminatedUnion`, which `defineTool` rejects (model tool calling needs
|
|
19
|
-
* a top-level `"type":"object"`).
|
|
23
|
+
* a top-level `"type":"object"`). A `queryType` that only one corpus can serve
|
|
24
|
+
* — an accession of that corpus — marks the others `not_applicable` rather
|
|
25
|
+
* than sending them a query they cannot read.
|
|
20
26
|
*/
|
|
21
27
|
import { ok } from "neverthrow";
|
|
22
28
|
import { z } from "zod";
|
|
23
29
|
import { defineTool } from "../define-tool.js";
|
|
30
|
+
import { getSomaticMutationFrequencies } from "../lib/cbioportal-client.js";
|
|
24
31
|
import { filterInformative, searchClinvar } from "../lib/clinvar-client.js";
|
|
25
32
|
import { searchDisgenet } from "../lib/disgenet-client.js";
|
|
26
33
|
import { searchGwasCatalog } from "../lib/gwas-catalog-client.js";
|
|
27
|
-
const SOURCES = ["gwas", "disgenet", "clinvar"];
|
|
34
|
+
const SOURCES = ["gwas", "disgenet", "clinvar", "cbioportal"];
|
|
35
|
+
const QUERY_TYPES = ["gene", "disease", "variant", "gwas_study", "clinvar_accession"];
|
|
28
36
|
const DEFAULT_LIMIT = 10;
|
|
29
37
|
const MAX_LIMIT = 100;
|
|
30
|
-
/**
|
|
38
|
+
/** Which query types each corpus can read. An accession is readable by one corpus only. */
|
|
39
|
+
const SOURCE_QUERY_TYPES = {
|
|
40
|
+
gwas: ["gene", "disease", "variant", "gwas_study"],
|
|
41
|
+
disgenet: ["gene", "disease"],
|
|
42
|
+
clinvar: ["gene", "disease", "variant", "clinvar_accession"],
|
|
43
|
+
cbioportal: ["gene"],
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* cBioPortal stays out of the default set. It scans every curated study, thus
|
|
47
|
+
* a caller opts into it by naming it in `sources`.
|
|
48
|
+
*/
|
|
49
|
+
const OPT_IN_SOURCES = ["cbioportal"];
|
|
31
50
|
function applicableSources(queryType) {
|
|
32
|
-
return
|
|
51
|
+
return SOURCES.filter((source) => SOURCE_QUERY_TYPES[source].includes(queryType));
|
|
33
52
|
}
|
|
53
|
+
/** The corpora a call queries when it names none. */
|
|
54
|
+
function defaultSources(queryType) {
|
|
55
|
+
return applicableSources(queryType).filter((source) => !OPT_IN_SOURCES.includes(source));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The GWAS Catalog name for each query type it serves. `clinvar_accession` is
|
|
59
|
+
* absent because `applicableSources` never selects the GWAS Catalog for it.
|
|
60
|
+
*/
|
|
61
|
+
const GWAS_SEARCH_TYPES = {
|
|
62
|
+
gene: "gene",
|
|
63
|
+
disease: "trait",
|
|
64
|
+
variant: "variant",
|
|
65
|
+
gwas_study: "study",
|
|
66
|
+
};
|
|
34
67
|
const inputSchema = z.object({
|
|
35
68
|
query: z
|
|
36
69
|
.string()
|
|
37
70
|
.min(1)
|
|
38
|
-
.describe("The entity, matching `queryType`. gene: a HUGO symbol ('PCSK9'); DisGeNET also takes an Entrez ID
|
|
39
|
-
"('LDL cholesterol'); DisGeNET also takes a UMLS CUI ('C0006142'). variant: a dbSNP rsID
|
|
71
|
+
.describe("The entity, matching `queryType`. gene: a HUGO symbol ('PCSK9'); DisGeNET also takes an Entrez ID, and cBioPortal takes the symbol " +
|
|
72
|
+
"directly. disease: a disease or trait name ('LDL cholesterol'); DisGeNET also takes a UMLS CUI ('C0006142'). variant: a dbSNP rsID " +
|
|
73
|
+
"('rs11591147'). gwas_study: a GWAS Catalog study accession ('GCST000392'). clinvar_accession: a ClinVar accession ('VCV000012345', " +
|
|
74
|
+
"'RCV000009910') or a bare variation ID."),
|
|
40
75
|
queryType: z
|
|
41
|
-
.enum(
|
|
76
|
+
.enum(QUERY_TYPES)
|
|
42
77
|
.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."
|
|
78
|
+
"trait; this value covers both). 'variant' — one rsID; DisGeNET is skipped, having no variant-level lookup. 'gwas_study' — every " +
|
|
79
|
+
"association reported by ONE GWAS Catalog study, read back from the studyAccession that a gwas record carries; GWAS Catalog only. " +
|
|
80
|
+
"'clinvar_accession' — one ClinVar record, read back from the accession that a clinvar record carries; ClinVar only."),
|
|
44
81
|
sources: z
|
|
45
82
|
.array(z.enum(SOURCES))
|
|
46
83
|
.min(1)
|
|
47
84
|
.optional()
|
|
48
|
-
.describe("Corpora to query in parallel. Default ALL applicable — they carry different evidence types, and disagreement between them
|
|
49
|
-
"
|
|
85
|
+
.describe("Corpora to query in parallel. Default ALL applicable EXCEPT cbioportal — they carry different evidence types, and disagreement between them " +
|
|
86
|
+
"is itself informative. " +
|
|
87
|
+
"'gwas': the NHGRI-EBI GWAS Catalog — population SNP-trait associations with effect sizes and p-values (common-variant / MR support). " +
|
|
50
88
|
"'disgenet': curated + text-mined gene-disease associations scored 0–1, broadest coverage; needs DISGENET_API_KEY. " +
|
|
51
|
-
"'clinvar': clinically classified germline variants
|
|
89
|
+
"'clinvar': NCBI ClinVar — clinically classified germline variants, pathogenicity and review status; rare/Mendelian rather than " +
|
|
90
|
+
"common-variant. " +
|
|
91
|
+
"'cbioportal': the somatic half — how often the gene is mutated in each cancer type across every curated cBioPortal study, as " +
|
|
92
|
+
"cancerTypeName, mutatedSamples/totalSamples, frequency and the contributing studies. OPT IN by naming it: it scans every study, so it is " +
|
|
93
|
+
"several seconds slower than the rest, and it applies to queryType 'gene' only."),
|
|
52
94
|
limit: z
|
|
53
95
|
.number()
|
|
54
96
|
.int()
|
|
@@ -110,18 +152,22 @@ async function runSource(source, fetch) {
|
|
|
110
152
|
export function createGeneDiseaseEvidenceTool(deps) {
|
|
111
153
|
return defineTool({
|
|
112
154
|
id: "gene_disease_evidence",
|
|
113
|
-
description: "Genetic evidence linking a gene to a disease or trait, across the GWAS Catalog, DisGeNET
|
|
114
|
-
"support for this target in this indication?'. See `sources` for what each corpus carries.\n" +
|
|
155
|
+
description: "Genetic evidence linking a gene to a disease or trait, across the NHGRI-EBI GWAS Catalog, DisGeNET, NCBI ClinVar and cBioPortal in one call " +
|
|
156
|
+
"— 'is there human genetic support for this target in this indication?'. See `sources` for what each corpus carries.\n" +
|
|
115
157
|
"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
|
|
158
|
+
"and the drug landscape. Reach here for the underlying records: actual SNPs, effect sizes, scores, pathogenicity calls and somatic mutation " +
|
|
159
|
+
"frequencies with their studies and PMIDs.\n" +
|
|
160
|
+
"ACCEPTED IDENTIFIERS, each named by its `queryType`: a HUGO gene symbol or an Entrez ID ('PCSK9', '5008'); a disease or trait name or a UMLS " +
|
|
161
|
+
"CUI ('LDL cholesterol', 'C0006142'); a dbSNP rsID ('rs11591147'); a GWAS Catalog study accession ('GCST000392'); and a ClinVar accession " +
|
|
162
|
+
"('VCV000012345'). The last two read one record back by the accession that an earlier result of this same tool reported.\n" +
|
|
117
163
|
"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
|
|
164
|
+
"could not be reached (a missing DISGENET_API_KEY lands here — tell the user and proceed with the others); 'not_applicable' means that " +
|
|
119
165
|
"corpus has no lookup for this queryType. Only 'no_data' is evidence of absence, and none is worth retrying unchanged.",
|
|
120
166
|
inputSchema,
|
|
121
167
|
describeCall: "none",
|
|
122
168
|
execute: async (input) => {
|
|
123
169
|
const applicable = applicableSources(input.queryType);
|
|
124
|
-
const requested = input.sources ??
|
|
170
|
+
const requested = input.sources ?? defaultSources(input.queryType);
|
|
125
171
|
const selected = requested.filter((s) => applicable.includes(s));
|
|
126
172
|
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
127
173
|
const output = {
|
|
@@ -136,10 +182,10 @@ export function createGeneDiseaseEvidenceTool(deps) {
|
|
|
136
182
|
detail: `${source} has no lookup for queryType '${input.queryType}'`,
|
|
137
183
|
})),
|
|
138
184
|
};
|
|
139
|
-
const [gwas, disgenet, clinvar] = await Promise.all([
|
|
185
|
+
const [gwas, disgenet, clinvar, cbioportal] = await Promise.all([
|
|
140
186
|
selected.includes("gwas")
|
|
141
187
|
? runSource("gwas", async () => {
|
|
142
|
-
const searchType = input.queryType
|
|
188
|
+
const searchType = GWAS_SEARCH_TYPES[input.queryType];
|
|
143
189
|
const res = await searchGwasCatalog(input.query, searchType, {
|
|
144
190
|
limit,
|
|
145
191
|
...(input.pValueThreshold !== undefined ? { pValueThreshold: input.pValueThreshold } : {}),
|
|
@@ -169,6 +215,12 @@ export function createGeneDiseaseEvidenceTool(deps) {
|
|
|
169
215
|
return { records: variants, totalFound: res.totalFound };
|
|
170
216
|
})
|
|
171
217
|
: null,
|
|
218
|
+
selected.includes("cbioportal")
|
|
219
|
+
? runSource("cbioportal", async () => {
|
|
220
|
+
const res = await getSomaticMutationFrequencies(input.query);
|
|
221
|
+
return { records: res.rows.slice(0, limit), totalFound: res.rows.length };
|
|
222
|
+
})
|
|
223
|
+
: null,
|
|
172
224
|
]);
|
|
173
225
|
if (gwas) {
|
|
174
226
|
output.perSource.push(gwas.outcome);
|
|
@@ -182,6 +234,10 @@ export function createGeneDiseaseEvidenceTool(deps) {
|
|
|
182
234
|
output.perSource.push(clinvar.outcome);
|
|
183
235
|
output.clinvar = clinvar.records;
|
|
184
236
|
}
|
|
237
|
+
if (cbioportal) {
|
|
238
|
+
output.perSource.push(cbioportal.outcome);
|
|
239
|
+
output.cbioportal = cbioportal.records;
|
|
240
|
+
}
|
|
185
241
|
return ok(output);
|
|
186
242
|
},
|
|
187
243
|
});
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* genePreclinicalProfile — the in-vivo
|
|
3
|
-
*
|
|
4
|
-
* (
|
|
2
|
+
* genePreclinicalProfile — the in-vivo picture of one gene: where it is
|
|
3
|
+
* expressed at baseline (Bgee), what removing it does to a mouse (IMPC), and
|
|
4
|
+
* what people who carry variation in it present with (Monarch, HPO), behind
|
|
5
|
+
* one `include`.
|
|
5
6
|
*
|
|
6
|
-
* The
|
|
7
|
-
* per-species orthologs resolved internally — and answer one
|
|
8
|
-
* them: is this target expressed where it needs to act,
|
|
9
|
-
* a fair surrogate for it
|
|
7
|
+
* The three halves share an input exactly — ONE human gene symbol, with the
|
|
8
|
+
* per-species orthologs and the gene curie resolved internally — and answer one
|
|
9
|
+
* question between them: is this target expressed where it needs to act, is a
|
|
10
|
+
* model organism a fair surrogate for it, and what does losing it do to a
|
|
11
|
+
* person. The first two were two tools that were called as a pair.
|
|
10
12
|
*
|
|
11
|
-
*
|
|
12
|
-
* species
|
|
13
|
-
* here rather than in the clients — the
|
|
14
|
-
* same clients and legitimately want full
|
|
13
|
+
* No source caps its own output: Bgee returns every annotated tissue per
|
|
14
|
+
* species, IMPC every significant phenotype term, and Monarch every curated
|
|
15
|
+
* HPO annotation, so each half is trimmed here rather than in the clients — the
|
|
16
|
+
* target-assessment collectors read the same clients and legitimately want full
|
|
17
|
+
* fidelity for the dossier.
|
|
15
18
|
*/
|
|
16
19
|
import { type SupportedSpecies, type TissueRow } from "../lib/bgee-client.js";
|
|
17
20
|
import { type MpTerm, type ViabilityCall, type ViabilityCategory } from "../lib/impc-client.js";
|
|
21
|
+
import { type MonarchPhenotypeAssociation } from "../lib/monarch-client.js";
|
|
18
22
|
interface BoundedSpeciesEntry {
|
|
19
23
|
species: SupportedSpecies;
|
|
20
24
|
taxonId: number;
|
|
@@ -30,6 +34,21 @@ interface ExpressionHalf {
|
|
|
30
34
|
bySpecies: BoundedSpeciesEntry[];
|
|
31
35
|
notFound: string[];
|
|
32
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* One curated human phenotype. The HPO ancestor closure of the source record
|
|
39
|
+
* is dropped here: it exists so a dossier collector can resolve an organ system
|
|
40
|
+
* by identifier, and it runs to hundreds of ids that a reader never uses.
|
|
41
|
+
*/
|
|
42
|
+
type HumanPhenotypeTerm = Omit<MonarchPhenotypeAssociation, "ancestorIds">;
|
|
43
|
+
interface HumanPhenotypeHalf {
|
|
44
|
+
/** The curie Monarch was queried by, e.g. `HGNC:1100`; null when the symbol did not anchor on HGNC. */
|
|
45
|
+
geneCurie: string | null;
|
|
46
|
+
hpoTerms: HumanPhenotypeTerm[];
|
|
47
|
+
/** Curated HPO annotations before `phenotypeLimit`. */
|
|
48
|
+
phenotypeCount: number;
|
|
49
|
+
/** True when `phenotypeLimit` trimmed `hpoTerms`; `phenotypeCount` is the real total. */
|
|
50
|
+
phenotypesTrimmed: boolean;
|
|
51
|
+
}
|
|
33
52
|
interface KnockoutHalf {
|
|
34
53
|
mouseMarkerSymbol: string | null;
|
|
35
54
|
mgiAccessionId: string | null;
|
|
@@ -46,12 +65,13 @@ type PreclinicalOutput = {
|
|
|
46
65
|
geneSymbol: string;
|
|
47
66
|
expression?: ExpressionHalf;
|
|
48
67
|
knockout?: KnockoutHalf;
|
|
68
|
+
phenotypes?: HumanPhenotypeHalf;
|
|
49
69
|
};
|
|
50
70
|
export declare const genePreclinicalProfileTool: import("../define-tool.js").Tool<{
|
|
51
71
|
geneSymbol: string;
|
|
52
|
-
include?: ("expression" | "knockout")[] | undefined;
|
|
72
|
+
include?: ("phenotypes" | "expression" | "knockout")[] | undefined;
|
|
53
73
|
species?: ("homo_sapiens" | "mus_musculus" | "rattus_norvegicus" | "canis_lupus_familiaris" | "macaca_mulatta")[] | undefined;
|
|
54
|
-
minRank?: "
|
|
74
|
+
minRank?: "low" | "medium" | "high" | "absent" | undefined;
|
|
55
75
|
tissueLimit?: number | undefined;
|
|
56
76
|
phenotypeLimit?: number | undefined;
|
|
57
77
|
}, PreclinicalOutput>;
|
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* genePreclinicalProfile — the in-vivo
|
|
3
|
-
*
|
|
4
|
-
* (
|
|
2
|
+
* genePreclinicalProfile — the in-vivo picture of one gene: where it is
|
|
3
|
+
* expressed at baseline (Bgee), what removing it does to a mouse (IMPC), and
|
|
4
|
+
* what people who carry variation in it present with (Monarch, HPO), behind
|
|
5
|
+
* one `include`.
|
|
5
6
|
*
|
|
6
|
-
* The
|
|
7
|
-
* per-species orthologs resolved internally — and answer one
|
|
8
|
-
* them: is this target expressed where it needs to act,
|
|
9
|
-
* a fair surrogate for it
|
|
7
|
+
* The three halves share an input exactly — ONE human gene symbol, with the
|
|
8
|
+
* per-species orthologs and the gene curie resolved internally — and answer one
|
|
9
|
+
* question between them: is this target expressed where it needs to act, is a
|
|
10
|
+
* model organism a fair surrogate for it, and what does losing it do to a
|
|
11
|
+
* person. The first two were two tools that were called as a pair.
|
|
10
12
|
*
|
|
11
|
-
*
|
|
12
|
-
* species
|
|
13
|
-
* here rather than in the clients — the
|
|
14
|
-
* same clients and legitimately want full
|
|
13
|
+
* No source caps its own output: Bgee returns every annotated tissue per
|
|
14
|
+
* species, IMPC every significant phenotype term, and Monarch every curated
|
|
15
|
+
* HPO annotation, so each half is trimmed here rather than in the clients — the
|
|
16
|
+
* target-assessment collectors read the same clients and legitimately want full
|
|
17
|
+
* fidelity for the dossier.
|
|
15
18
|
*/
|
|
16
19
|
import { ok } from "neverthrow";
|
|
17
20
|
import { z } from "zod";
|
|
18
21
|
import { defineTool } from "../define-tool.js";
|
|
19
22
|
import { SUPPORTED_SPECIES, getMultiSpeciesExpression } from "../lib/bgee-client.js";
|
|
23
|
+
import { resolveTarget } from "../lib/identifier-resolver.js";
|
|
20
24
|
import { getKoPhenotypeProfile } from "../lib/impc-client.js";
|
|
25
|
+
import { getGenePhenotypeProfile } from "../lib/monarch-client.js";
|
|
21
26
|
/** Ordered weakest → strongest so `minRank` can be a numeric floor. */
|
|
22
27
|
const RANK_ORDER = { absent: 0, low: 1, medium: 2, high: 3 };
|
|
23
28
|
/** Human + mouse: the pairing that answers "is the mouse a fair surrogate?". */
|
|
@@ -30,11 +35,13 @@ const inputSchema = z.object({
|
|
|
30
35
|
.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
36
|
"orthologs are resolved for you."),
|
|
32
37
|
include: z
|
|
33
|
-
.array(z.enum(["expression", "knockout"]))
|
|
38
|
+
.array(z.enum(["expression", "knockout", "phenotypes"]))
|
|
34
39
|
.min(1)
|
|
35
40
|
.optional()
|
|
36
|
-
.describe("Default
|
|
37
|
-
"tissue. 'knockout': IMPC mouse loss-of-function phenotype."
|
|
41
|
+
.describe("Default ['expression','knockout'] — two sides of one judgement, one request each. 'expression': Bgee baseline (healthy, untreated) " +
|
|
42
|
+
"expression per species and tissue. 'knockout': IMPC mouse loss-of-function phenotype. 'phenotypes': the HUMAN counterpart — the curated " +
|
|
43
|
+
"HPO phenotypes that Monarch attributes to variation in this gene, from HPOA, OMIM and Orphanet, each with its PMIDs and the disease it " +
|
|
44
|
+
"was annotated under. Ask for it explicitly, and pair it with 'knockout' when the question is whether the mouse recapitulates the person."),
|
|
38
45
|
species: z
|
|
39
46
|
.array(z.enum(SUPPORTED_SPECIES))
|
|
40
47
|
.min(1)
|
|
@@ -60,8 +67,9 @@ const inputSchema = z.object({
|
|
|
60
67
|
.min(1)
|
|
61
68
|
.max(200)
|
|
62
69
|
.optional()
|
|
63
|
-
.describe(`'knockout'
|
|
64
|
-
|
|
70
|
+
.describe(`'knockout' and 'phenotypes'. Max phenotype terms per half — MP terms best p-value first, HPO terms in curation order (default ` +
|
|
71
|
+
`${DEFAULTS.phenotypeLimit}, max 200). Each half reports its own \`phenotypeCount\` for the true total; \`organSystems\` is never ` +
|
|
72
|
+
"trimmed, so the top-line knockout picture survives."),
|
|
65
73
|
});
|
|
66
74
|
function boundExpression(raw, minRank, tissueLimit) {
|
|
67
75
|
const floor = RANK_ORDER[minRank];
|
|
@@ -95,31 +103,64 @@ function boundKnockout(raw, phenotypeLimit) {
|
|
|
95
103
|
phenotypesTrimmed: raw.mpTerms.length > phenotypeLimit,
|
|
96
104
|
};
|
|
97
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Anchor the symbol on HGNC and read the curated human phenotypes. A symbol
|
|
108
|
+
* that anchors on no HGNC id gives a null curie and an empty term list, which
|
|
109
|
+
* is absence and not a failure.
|
|
110
|
+
*/
|
|
111
|
+
async function fetchHumanPhenotypes(geneSymbol, phenotypeLimit) {
|
|
112
|
+
let geneCurie;
|
|
113
|
+
try {
|
|
114
|
+
geneCurie = (await resolveTarget(geneSymbol)).ids.hgnc;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
geneCurie = null;
|
|
118
|
+
}
|
|
119
|
+
if (!geneCurie)
|
|
120
|
+
return { geneCurie: null, hpoTerms: [], phenotypeCount: 0, phenotypesTrimmed: false };
|
|
121
|
+
const profile = await getGenePhenotypeProfile(geneCurie);
|
|
122
|
+
return {
|
|
123
|
+
geneCurie: profile.geneCurie,
|
|
124
|
+
hpoTerms: profile.phenotypes.slice(0, phenotypeLimit).map(({ ancestorIds: _ancestorIds, ...term }) => term),
|
|
125
|
+
phenotypeCount: profile.phenotypes.length,
|
|
126
|
+
phenotypesTrimmed: profile.phenotypes.length > phenotypeLimit,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
98
129
|
export const genePreclinicalProfileTool = defineTool({
|
|
99
130
|
id: "gene_preclinical_profile",
|
|
100
|
-
description: "The in-vivo
|
|
101
|
-
"
|
|
102
|
-
"
|
|
131
|
+
description: "The in-vivo profile of ONE human gene across three corpora in one call — baseline expression from Bgee, the mouse-knockout phenotype from IMPC " +
|
|
132
|
+
"(the International Mouse Phenotyping Consortium), and the curated human phenotypes from the Monarch Initiative (HPO terms sourced from HPOA, " +
|
|
133
|
+
"OMIM and Orphanet). Answers tissue-of-action ('where does this target act?'), model-organism suitability ('is the mouse a fair surrogate?'), " +
|
|
134
|
+
"essentiality ('what happens when this gene is lost?') and the human read-out ('what do people carrying variation in it present with?').\n" +
|
|
103
135
|
"Expression is BASELINE (healthy, untreated) only — differential expression between conditions is the analysis pipeline's job, never this tool.\n" +
|
|
136
|
+
"ACCEPTED IDENTIFIERS: one HUMAN gene symbol, e.g. 'BRCA1'. The ENSG, the per-species orthologs and the HGNC curie are resolved for you; an " +
|
|
137
|
+
"Ensembl ID, a mouse symbol and an MGI ID are not accepted here — put those through search_gene first.\n" +
|
|
104
138
|
"Output is trimmed by default (see `minRank`, `tissueLimit`, `phenotypeLimit`); the accompanying counts distinguish a trimmed list from a sparse one.\n" +
|
|
105
139
|
"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
|
|
140
|
+
"with no phenotype terms means the gene has not been IMPC-phenotyped, which is common; an empty hpoTerms list means Monarch curates no human " +
|
|
141
|
+
"phenotype for the gene, and a null geneCurie means the symbol anchored on no HGNC id.",
|
|
107
142
|
inputSchema,
|
|
108
143
|
describeCall: "none",
|
|
109
144
|
execute: async ({ geneSymbol, include, species, minRank, tissueLimit, phenotypeLimit }) => {
|
|
110
145
|
const halves = include ?? ["expression", "knockout"];
|
|
111
146
|
const wantExpression = halves.includes("expression");
|
|
112
147
|
const wantKnockout = halves.includes("knockout");
|
|
113
|
-
const
|
|
148
|
+
const wantPhenotypes = halves.includes("phenotypes");
|
|
149
|
+
const termLimit = phenotypeLimit ?? DEFAULTS.phenotypeLimit;
|
|
150
|
+
const [expressionRaw, knockoutRaw, phenotypesHalf] = await Promise.all([
|
|
114
151
|
wantExpression ? getMultiSpeciesExpression(geneSymbol, [...(species ?? DEFAULT_SPECIES)]) : Promise.resolve(null),
|
|
115
152
|
wantKnockout ? getKoPhenotypeProfile(geneSymbol) : Promise.resolve(null),
|
|
153
|
+
wantPhenotypes ? fetchHumanPhenotypes(geneSymbol, termLimit) : Promise.resolve(null),
|
|
116
154
|
]);
|
|
117
155
|
const output = { geneSymbol };
|
|
118
156
|
if (expressionRaw) {
|
|
119
157
|
output.expression = boundExpression(expressionRaw, minRank ?? DEFAULTS.minRank, tissueLimit ?? DEFAULTS.tissueLimit);
|
|
120
158
|
}
|
|
121
159
|
if (knockoutRaw) {
|
|
122
|
-
output.knockout = boundKnockout(knockoutRaw,
|
|
160
|
+
output.knockout = boundKnockout(knockoutRaw, termLimit);
|
|
161
|
+
}
|
|
162
|
+
if (phenotypesHalf) {
|
|
163
|
+
output.phenotypes = phenotypesHalf;
|
|
123
164
|
}
|
|
124
165
|
return ok(output);
|
|
125
166
|
},
|
|
@@ -38,6 +38,7 @@ type AnnotationOutput = {
|
|
|
38
38
|
export declare const lookupAnnotationTool: import("../define-tool.js").Tool<{
|
|
39
39
|
vocabulary: "kegg" | "reactome" | "go" | "pathways";
|
|
40
40
|
query?: string | undefined;
|
|
41
|
+
pathwayId?: string | undefined;
|
|
41
42
|
goId?: string | undefined;
|
|
42
43
|
geneProductId?: string | undefined;
|
|
43
44
|
taxonId?: number | undefined;
|
|
@@ -18,7 +18,7 @@ import { ok } from "neverthrow";
|
|
|
18
18
|
import { z } from "zod";
|
|
19
19
|
import { defineTool } from "../define-tool.js";
|
|
20
20
|
import { apiFetchValidated, describeApiError } from "../lib/api-utils.js";
|
|
21
|
-
import { searchPathways } from "../lib/pathway-client.js";
|
|
21
|
+
import { getPathwayById, searchPathways } from "../lib/pathway-client.js";
|
|
22
22
|
const QUICKGO_BASE = "https://www.ebi.ac.uk/QuickGO/services";
|
|
23
23
|
const HEADERS = { Accept: "application/json" };
|
|
24
24
|
const DEFAULT_LIMIT = 10;
|
|
@@ -70,13 +70,20 @@ const inputSchema = z
|
|
|
70
70
|
.enum(["go", "kegg", "reactome", "pathways"])
|
|
71
71
|
.describe("'go' — Gene Ontology via QuickGO (EBI); needs ONE of goId, query, or geneProductId. Returns terms[] { id, name, definition, aspect } " +
|
|
72
72
|
"and/or annotations[] { geneProductId, goId, goName, aspect, evidenceCode, qualifier }. " +
|
|
73
|
-
"'kegg' / 'reactome' — one pathway database; needs query. 'pathways' — both, in parallel; needs query. " +
|
|
74
|
-
"Returns pathways[] { id, name, source, url, genes? }."),
|
|
73
|
+
"'kegg' / 'reactome' — one pathway database; needs query or pathwayId. 'pathways' — both, in parallel; needs query or pathwayId. " +
|
|
74
|
+
"Returns pathways[] { id, name, source, url, description?, genes? }."),
|
|
75
75
|
query: z
|
|
76
76
|
.string()
|
|
77
77
|
.min(1)
|
|
78
78
|
.optional()
|
|
79
|
-
.describe("Free-text term. Required for the pathway vocabularies ('apoptosis', 'MAPK signaling'); for 'go' it is one of
|
|
79
|
+
.describe("Free-text term. Required for the pathway vocabularies ('apoptosis', 'MAPK signaling') unless pathwayId is given; for 'go' it is one of " +
|
|
80
|
+
"the three accepted inputs."),
|
|
81
|
+
pathwayId: z
|
|
82
|
+
.string()
|
|
83
|
+
.min(1)
|
|
84
|
+
.optional()
|
|
85
|
+
.describe("Pathway vocabularies only. ONE pathway identifier, read back exactly as a search returned it — a Reactome stable ID ('R-HSA-109581') " +
|
|
86
|
+
"or a KEGG pathway ID ('hsa04010'). The prefix picks the database, so `vocabulary` and `organism` are ignored for it."),
|
|
80
87
|
goId: z
|
|
81
88
|
.string()
|
|
82
89
|
.regex(/^GO:\d{7}$/)
|
|
@@ -98,9 +105,13 @@ const inputSchema = z
|
|
|
98
105
|
.optional()
|
|
99
106
|
.describe(`Max records per vocabulary queried (default ${DEFAULT_LIMIT}, max 100); with 'pathways' it applies to KEGG and Reactome separately.`),
|
|
100
107
|
})
|
|
101
|
-
.refine((d) => d.vocabulary === "go" || (d.query !== undefined && d.query.trim().length > 0), {
|
|
102
|
-
message: "
|
|
108
|
+
.refine((d) => d.vocabulary === "go" || (d.query !== undefined && d.query.trim().length > 0) || (d.pathwayId !== undefined && d.pathwayId.length > 0), {
|
|
109
|
+
message: "vocabulary 'kegg', 'reactome' and 'pathways' need query (the pathway term to search for) or pathwayId (one 'R-HSA-…' or 'hsa…' identifier)",
|
|
103
110
|
path: ["query"],
|
|
111
|
+
})
|
|
112
|
+
.refine((d) => d.vocabulary !== "go" || d.pathwayId === undefined, {
|
|
113
|
+
message: "pathwayId belongs to the pathway vocabularies — vocabulary 'go' takes goId instead",
|
|
114
|
+
path: ["pathwayId"],
|
|
104
115
|
})
|
|
105
116
|
.refine((d) => d.vocabulary !== "go" || d.goId !== undefined || d.query !== undefined || d.geneProductId !== undefined, {
|
|
106
117
|
message: "vocabulary 'go' needs at least one of goId (term by ID), query (free-text term search), or geneProductId (a protein's annotations)",
|
|
@@ -116,16 +127,23 @@ const inputSchema = z
|
|
|
116
127
|
});
|
|
117
128
|
export const lookupAnnotationTool = defineTool({
|
|
118
129
|
id: "lookup_annotation",
|
|
119
|
-
description: "Functional annotation for a gene, protein or term — Gene Ontology (QuickGO) and the pathway databases
|
|
120
|
-
"Names what a gene is known to do, resolves a GO or pathway identifier, or finds the pathways a term belongs to.\n" +
|
|
130
|
+
description: "Functional annotation for a gene, protein or term — the Gene Ontology (through EBI QuickGO) and the pathway databases KEGG and Reactome, behind " +
|
|
131
|
+
"one `vocabulary`. Names what a gene is known to do, resolves a GO or pathway identifier, or finds the pathways a term belongs to.\n" +
|
|
132
|
+
"ACCEPTED IDENTIFIERS: a GO term ID ('GO:0008150'), a UniProt accession for a protein's annotations ('P04637'), an NCBI Taxon ID ('9606'), a " +
|
|
133
|
+
"Reactome stable ID ('R-HSA-109581'), a KEGG pathway ID ('hsa04010'), and free text for any of the vocabularies ('apoptosis').\n" +
|
|
121
134
|
"This is annotation LOOKUP, not enrichment: to test whether a gene SET is over-represented in GO/KEGG/Reactome terms use " +
|
|
122
135
|
"search_interactions({action:'enrichment'}), which does the statistics.\n" +
|
|
123
|
-
"An empty terms / annotations / pathways array is valid no-data — do not retry the same input."
|
|
136
|
+
"An empty terms / annotations / pathways array is valid no-data — report it and continue, do not retry the same input. An empty pathways array " +
|
|
137
|
+
"for a pathwayId means neither database holds that identifier.",
|
|
124
138
|
inputSchema,
|
|
125
139
|
describeCall: "none",
|
|
126
|
-
execute: async ({ vocabulary, query, goId, geneProductId, taxonId, organism, includeGenes, limit }) => {
|
|
140
|
+
execute: async ({ vocabulary, query, pathwayId, goId, geneProductId, taxonId, organism, includeGenes, limit, }) => {
|
|
127
141
|
const cap = limit ?? DEFAULT_LIMIT;
|
|
128
142
|
if (vocabulary !== "go") {
|
|
143
|
+
if (pathwayId) {
|
|
144
|
+
const pathway = await getPathwayById(pathwayId);
|
|
145
|
+
return ok({ pathways: pathway ? [pathway] : [] });
|
|
146
|
+
}
|
|
129
147
|
const pathways = await searchPathways(query, {
|
|
130
148
|
source: vocabulary === "pathways" ? "both" : vocabulary,
|
|
131
149
|
organism: organism ?? "hsa",
|
|
@@ -17,18 +17,26 @@
|
|
|
17
17
|
* gene ID or an EFO disease ID, and a gene symbol silently returns an empty
|
|
18
18
|
* result rather than an error. Naming the two identifiers apart is what makes
|
|
19
19
|
* that contract visible at the call site.
|
|
20
|
+
*
|
|
21
|
+
* `resolve_disease` closes that contract. It takes the plain disease name a
|
|
22
|
+
* user supplies and returns the disease ids of the same corpus, thus the
|
|
23
|
+
* caller never has to know an ontology id before it can ask a question.
|
|
20
24
|
*/
|
|
21
|
-
import { type Association, type TargetInfo } from "../lib/opentargets-client.js";
|
|
25
|
+
import { type Association, type DiseaseCandidate, type TargetInfo } from "../lib/opentargets-client.js";
|
|
22
26
|
type OpenTargetsOutput = {
|
|
23
27
|
targetInfo: TargetInfo | null;
|
|
24
28
|
associations: Association[];
|
|
25
29
|
} | {
|
|
26
30
|
associations: Association[];
|
|
31
|
+
} | {
|
|
32
|
+
totalFound: number;
|
|
33
|
+
candidates: DiseaseCandidate[];
|
|
27
34
|
};
|
|
28
35
|
export declare const openTargetsTool: import("../define-tool.js").Tool<{
|
|
29
|
-
action: "target" | "disease";
|
|
36
|
+
action: "target" | "disease" | "resolve_disease";
|
|
30
37
|
ensemblId?: string | undefined;
|
|
31
38
|
efoId?: string | undefined;
|
|
39
|
+
diseaseName?: string | undefined;
|
|
32
40
|
limit?: number | undefined;
|
|
33
41
|
}, OpenTargetsOutput>;
|
|
34
42
|
export {};
|