@inflexa-ai/harness 0.30.3 → 0.31.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/contracts/target-dossier.d.ts +61 -61
- package/dist/execution/run-synthesis.js +7 -2
- package/dist/lib/zod-issues.d.ts +8 -0
- package/dist/lib/zod-issues.js +13 -0
- package/dist/literature/sources/semantic-scholar.d.ts +34 -0
- package/dist/literature/sources/semantic-scholar.js +15 -4
- package/dist/prompts/briefing.d.ts +12 -1
- package/dist/prompts/briefing.js +27 -1
- package/dist/prompts/sandbox-standards.d.ts +1 -1
- package/dist/prompts/sandbox-standards.js +27 -0
- package/dist/sandbox/thread-env.d.ts +18 -12
- package/dist/sandbox/thread-env.js +36 -25
- package/dist/tools/bio/chembl.js +4 -3
- package/dist/tools/bio/drug-gene-interactions.d.ts +2 -14
- package/dist/tools/bio/drug-gene-interactions.js +10 -18
- package/dist/tools/bio/gene-disease-evidence.d.ts +3 -1
- package/dist/tools/bio/gene-disease-evidence.js +12 -9
- package/dist/tools/bio/keys.js +1 -0
- package/dist/tools/bio/lookup-annotation.d.ts +43 -0
- package/dist/tools/bio/lookup-annotation.js +19 -4
- package/dist/tools/bio/pubchem.js +5 -3
- package/dist/tools/bio/search-clinical-trials.js +5 -4
- package/dist/tools/bio/search-geo-datasets.d.ts +39 -9
- package/dist/tools/bio/search-geo-datasets.js +38 -20
- package/dist/tools/lib/api-utils.d.ts +27 -2
- package/dist/tools/lib/api-utils.js +43 -3
- package/dist/tools/lib/bgee-client.d.ts +16 -0
- package/dist/tools/lib/bgee-client.js +16 -5
- package/dist/tools/lib/cbioportal-client.d.ts +20 -0
- package/dist/tools/lib/cbioportal-client.js +16 -8
- package/dist/tools/lib/chembl-client.d.ts +105 -3
- package/dist/tools/lib/chembl-client.js +196 -84
- package/dist/tools/lib/clinical-benchmarks-client.d.ts +5 -0
- package/dist/tools/lib/clinical-benchmarks-client.js +5 -0
- package/dist/tools/lib/clinical-trials-client.d.ts +131 -2
- package/dist/tools/lib/clinical-trials-client.js +32 -6
- package/dist/tools/lib/clinvar-client.d.ts +35 -0
- package/dist/tools/lib/clinvar-client.js +34 -28
- package/dist/tools/lib/ctx-ops.d.ts +106 -35
- package/dist/tools/lib/ctx-ops.js +135 -69
- package/dist/tools/lib/dgidb-client.d.ts +73 -0
- package/dist/tools/lib/dgidb-client.js +25 -13
- package/dist/tools/lib/disgenet-client.d.ts +117 -24
- package/dist/tools/lib/disgenet-client.js +127 -34
- package/dist/tools/lib/disgenet-config.d.ts +1 -1
- package/dist/tools/lib/disgenet-config.js +5 -3
- package/dist/tools/lib/drugbank-client.d.ts +57 -58
- package/dist/tools/lib/drugbank-client.js +69 -64
- package/dist/tools/lib/drugbank-config.d.ts +6 -1
- package/dist/tools/lib/drugbank-config.js +6 -1
- package/dist/tools/lib/ema-client.d.ts +53 -0
- package/dist/tools/lib/ema-client.js +19 -7
- package/dist/tools/lib/ensembl-client.d.ts +4 -0
- package/dist/tools/lib/ensembl-client.js +4 -0
- package/dist/tools/lib/gwas-catalog-client.d.ts +64 -1
- package/dist/tools/lib/gwas-catalog-client.js +21 -6
- package/dist/tools/lib/identifier-resolver.d.ts +17 -1
- package/dist/tools/lib/identifier-resolver.js +13 -4
- package/dist/tools/lib/impc-client.d.ts +4 -0
- package/dist/tools/lib/impc-client.js +4 -0
- package/dist/tools/lib/iuphar-client.d.ts +10 -5
- package/dist/tools/lib/iuphar-client.js +49 -13
- package/dist/tools/lib/monarch-client.d.ts +4 -0
- package/dist/tools/lib/monarch-client.js +4 -0
- package/dist/tools/lib/openfda-client.d.ts +34 -0
- package/dist/tools/lib/openfda-client.js +22 -8
- package/dist/tools/lib/opentargets-client.d.ts +99 -4
- package/dist/tools/lib/opentargets-client.js +97 -37
- package/dist/tools/lib/pathway-client.d.ts +45 -0
- package/dist/tools/lib/pathway-client.js +88 -8
- package/dist/tools/lib/pharmgkb-client.d.ts +35 -1
- package/dist/tools/lib/pharmgkb-client.js +22 -6
- package/dist/tools/lib/pharmgkb-config.d.ts +8 -1
- package/dist/tools/lib/pharmgkb-config.js +8 -1
- package/dist/tools/lib/pubchem-client.d.ts +22 -0
- package/dist/tools/lib/pubchem-client.js +36 -33
- package/dist/tools/lib/pubchem-ops.d.ts +85 -5
- package/dist/tools/lib/pubchem-ops.js +96 -68
- package/dist/tools/lib/pubmed-client.d.ts +4 -0
- package/dist/tools/lib/pubmed-client.js +4 -0
- package/dist/tools/lib/string-client.d.ts +52 -0
- package/dist/tools/lib/string-client.js +12 -7
- package/dist/tools/lib/uniprot-client.d.ts +4 -0
- package/dist/tools/lib/uniprot-client.js +4 -0
- package/dist/tools/research/context7-docs.d.ts +23 -0
- package/dist/tools/research/context7-docs.js +49 -9
- package/dist/tools/research/search-github-repos.d.ts +4 -0
- package/dist/tools/research/search-github-repos.js +4 -0
- package/dist/workflows/execute-target-assessment.js +4 -4
- package/dist/workflows/target-assessment/assemblers/orchestrator.d.ts +2 -1
- package/dist/workflows/target-assessment/assemblers/orchestrator.js +3 -3
- package/dist/workflows/target-assessment/collectors/index.d.ts +8 -2
- package/dist/workflows/target-assessment/collectors/index.js +37 -10
- package/dist/workflows/target-assessment/fanout/index.d.ts +2 -1
- package/dist/workflows/target-assessment/fanout/index.js +2 -2
- package/dist/workflows/target-assessment/lib/safety-corroboration.js +2 -2
- package/dist/workflows/target-assessment/lib/target-identity-filter.d.ts +3 -2
- package/dist/workflows/target-assessment/lib/target-identity-filter.js +16 -5
- package/dist/workflows/target-assessment/phase4-assemble.d.ts +61 -60
- package/dist/workflows/target-assessment/phase4-assemble.js +2 -2
- package/dist/workflows/target-assessment/schemas.d.ts +2 -8
- package/dist/workflows/target-assessment/schemas.js +8 -2
- package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +1 -4
- package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +1 -4
- package/package.json +1 -1
- package/dist/agents/sandbox/__fixtures__/deps.d.ts +0 -23
- package/dist/agents/sandbox/__fixtures__/deps.js +0 -102
- package/dist/citations/__fixtures__/resolver.d.ts +0 -3
- package/dist/citations/__fixtures__/resolver.js +0 -9
- package/dist/loop/__fixtures__/scripted-provider.d.ts +0 -31
- package/dist/loop/__fixtures__/scripted-provider.js +0 -81
- package/dist/providers/__fixtures__/session.d.ts +0 -17
- package/dist/providers/__fixtures__/session.js +0 -20
- package/dist/tools/__fixtures__/tool-context.d.ts +0 -13
- package/dist/tools/__fixtures__/tool-context.js +0 -22
|
@@ -4,14 +4,20 @@
|
|
|
4
4
|
* One home for the wire schemas, the URL construction, and the "PubChem 404
|
|
5
5
|
* means no data" contract, so a caller cannot drift from it: every function
|
|
6
6
|
* returns an empty collection for a 404 and throws on any other API failure.
|
|
7
|
+
*
|
|
8
|
+
* Absence policy: PubChem omits the key of an absent value, per `minOccurs=0`
|
|
9
|
+
* in its XSD, and it never sends an explicit `null`. Thus a maybe-absent field
|
|
10
|
+
* carries `.optional()`, not `.nullable()`.
|
|
7
11
|
*/
|
|
8
12
|
import { z } from "zod";
|
|
9
|
-
import { apiFetchValidated, describeApiError } from "./api-utils.js";
|
|
13
|
+
import { apiFetchValidated, describeApiError, parseWireNumber, zWireNumber } from "./api-utils.js";
|
|
10
14
|
import { PUBCHEM_HEADERS as HEADERS, PUBCHEM_BASE } from "./pubchem-config.js";
|
|
11
15
|
const PROPERTY_LIST = [
|
|
12
16
|
"MolecularFormula",
|
|
13
17
|
"MolecularWeight",
|
|
14
|
-
|
|
18
|
+
// PubChem retired the response key `CanonicalSMILES`, and it answers a request
|
|
19
|
+
// for that name with `ConnectivitySMILES`. Thus the request names the live key.
|
|
20
|
+
"ConnectivitySMILES",
|
|
15
21
|
"InChI",
|
|
16
22
|
"InChIKey",
|
|
17
23
|
"IUPACName",
|
|
@@ -31,12 +37,11 @@ const PROPERTY_LIST = [
|
|
|
31
37
|
const PugPropertyRowSchema = z
|
|
32
38
|
.object({
|
|
33
39
|
CID: z.number().optional(),
|
|
34
|
-
|
|
40
|
+
ConnectivitySMILES: z.string().optional(),
|
|
35
41
|
MolecularFormula: z.string().optional(),
|
|
36
42
|
// PUG-REST serializes MolecularWeight as a string (e.g. "180.16") to
|
|
37
|
-
// preserve significant figures
|
|
38
|
-
|
|
39
|
-
MolecularWeight: z.union([z.number(), z.string()]).optional(),
|
|
43
|
+
// preserve significant figures, thus it reads through the wire-number helper.
|
|
44
|
+
MolecularWeight: zWireNumber.optional(),
|
|
40
45
|
IUPACName: z.string().optional(),
|
|
41
46
|
InChI: z.string().optional(),
|
|
42
47
|
InChIKey: z.string().optional(),
|
|
@@ -49,9 +54,9 @@ const PugPropertyRowSchema = z
|
|
|
49
54
|
})
|
|
50
55
|
.transform((raw) => ({
|
|
51
56
|
cid: raw.CID ?? 0,
|
|
52
|
-
canonicalSmiles: raw.
|
|
57
|
+
canonicalSmiles: raw.ConnectivitySMILES ?? null,
|
|
53
58
|
molecularFormula: raw.MolecularFormula ?? null,
|
|
54
|
-
molecularWeight: raw.MolecularWeight
|
|
59
|
+
molecularWeight: raw.MolecularWeight ?? null,
|
|
55
60
|
iupacName: raw.IUPACName ?? null,
|
|
56
61
|
inchi: raw.InChI ?? null,
|
|
57
62
|
inchiKey: raw.InChIKey ?? null,
|
|
@@ -62,50 +67,77 @@ const PugPropertyRowSchema = z
|
|
|
62
67
|
rotatableBondCount: raw.RotatableBondCount ?? null,
|
|
63
68
|
complexity: raw.Complexity ?? null,
|
|
64
69
|
}));
|
|
65
|
-
const PubChemPropertyResponseSchema = z.object({
|
|
70
|
+
export const PubChemPropertyResponseSchema = z.object({
|
|
66
71
|
PropertyTable: z.object({ Properties: z.array(PugPropertyRowSchema).optional() }).optional(),
|
|
67
72
|
});
|
|
68
73
|
// The PUG-REST xrefs wire shape, validated at the fetch boundary: one
|
|
69
|
-
// `Information` entry per CID with
|
|
70
|
-
//
|
|
71
|
-
const PubChemXrefResponseSchema = z.object({
|
|
74
|
+
// `Information` entry per CID with its `RegistryID[]` list. Every field is
|
|
75
|
+
// optional — PubChem omits absent values.
|
|
76
|
+
export const PubChemXrefResponseSchema = z.object({
|
|
72
77
|
InformationList: z
|
|
73
78
|
.object({
|
|
74
79
|
Information: z
|
|
75
80
|
.array(z.object({
|
|
76
81
|
CID: z.number().optional(),
|
|
77
82
|
RegistryID: z.array(z.string()).optional(),
|
|
78
|
-
SourceName: z.array(z.string()).optional(),
|
|
79
83
|
}))
|
|
80
84
|
.optional(),
|
|
81
85
|
})
|
|
82
86
|
.optional(),
|
|
83
87
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
/**
|
|
89
|
+
* The registry of each identifier pattern that PubChem serves in `RegistryID`.
|
|
90
|
+
*
|
|
91
|
+
* The `RegistryID` and `SourceName` lists of the endpoint are not parallel and
|
|
92
|
+
* they hold a different number of entries, thus an index cannot pair them. The
|
|
93
|
+
* identifier itself carries the registry, and the pattern reads it.
|
|
94
|
+
*
|
|
95
|
+
* A loose pattern runs last, thus a specific registry claims its own id first.
|
|
96
|
+
*/
|
|
97
|
+
const REGISTRY_PATTERNS = [
|
|
98
|
+
["ChEMBL", /^CHEMBL\d+$/],
|
|
99
|
+
["ChEBI", /^CHEBI:\d+$/],
|
|
100
|
+
["DrugBank", /^DB\d{5}$/],
|
|
101
|
+
["KEGG", /^[CD]\d{5}$/],
|
|
102
|
+
["HMDB", /^HMDB\d+$/],
|
|
103
|
+
["CAS", /^\d{2,7}-\d{2}-\d$/],
|
|
104
|
+
// A PDB id is four characters that start with a digit. The lookahead demands a
|
|
105
|
+
// letter as well, thus a plain registry number does not read as a structure.
|
|
106
|
+
["PDB", /^[1-9](?=.*[A-Za-z])[0-9A-Za-z]{3}$/],
|
|
107
|
+
// A UNII is ten alphanumeric characters, and the lookahead demands a letter
|
|
108
|
+
// among them. A plain ten-digit registry number, such as `0000050782`, matches
|
|
109
|
+
// the pattern without it, and the row then names the wrong registry.
|
|
110
|
+
["UNII", /^(?=.*[A-Z])[A-Z0-9]{10}$/],
|
|
111
|
+
];
|
|
112
|
+
/** The registry of one identifier, or `null` when no pattern matches it. */
|
|
113
|
+
export function classifyRegistryId(id) {
|
|
114
|
+
for (const [source, pattern] of REGISTRY_PATTERNS) {
|
|
115
|
+
if (pattern.test(id))
|
|
116
|
+
return source;
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
// The PUG-REST assay-summary wire shape, validated at the fetch boundary: one
|
|
121
|
+
// `Column` list of plain heading strings, and one `Cell` list of plain strings
|
|
122
|
+
// for each row, with an entry for each column. An empty cell is the empty
|
|
123
|
+
// string. `parseAssaySummary` maps the heading-indexed cells into `PubChemAssay`
|
|
124
|
+
// records. Every field is optional — PubChem omits absent values.
|
|
125
|
+
export const PugAssaySummarySchema = z.object({
|
|
88
126
|
Table: z
|
|
89
127
|
.object({
|
|
90
|
-
Columns: z
|
|
91
|
-
|
|
92
|
-
Column: z.array(z.object({ Heading: z.string().optional() })).optional(),
|
|
93
|
-
})
|
|
94
|
-
.optional(),
|
|
95
|
-
Row: z
|
|
96
|
-
.array(z.object({
|
|
97
|
-
Cell: z
|
|
98
|
-
.array(z.object({
|
|
99
|
-
intval: z.number().optional(),
|
|
100
|
-
fval: z.number().optional(),
|
|
101
|
-
sval: z.string().optional(),
|
|
102
|
-
}))
|
|
103
|
-
.optional(),
|
|
104
|
-
}))
|
|
105
|
-
.optional(),
|
|
128
|
+
Columns: z.object({ Column: z.array(z.string()).optional() }).optional(),
|
|
129
|
+
Row: z.array(z.object({ Cell: z.array(z.string()).optional() })).optional(),
|
|
106
130
|
})
|
|
107
131
|
.optional(),
|
|
108
132
|
});
|
|
133
|
+
/** The wire headings that the assay summary carries. They hold spaces and a unit. */
|
|
134
|
+
const ASSAY_HEADINGS = {
|
|
135
|
+
aid: "AID",
|
|
136
|
+
assayName: "Assay Name",
|
|
137
|
+
targetAccession: "Target Accession",
|
|
138
|
+
activityOutcome: "Activity Outcome",
|
|
139
|
+
activityValue: "Activity Value [uM]",
|
|
140
|
+
};
|
|
109
141
|
/** Build the PUG-REST URL path segment for the given search type. */
|
|
110
142
|
function buildNamespace(searchBy, query) {
|
|
111
143
|
switch (searchBy) {
|
|
@@ -135,11 +167,21 @@ export async function fetchPubchemCompounds(query, searchBy) {
|
|
|
135
167
|
throw new Error(describeApiError(res.error));
|
|
136
168
|
}
|
|
137
169
|
// Already validated + normalized by PugPropertyRowSchema's transform.
|
|
138
|
-
return res.value.PropertyTable?.Properties ?? [];
|
|
170
|
+
return (res.value.PropertyTable?.Properties ?? []).filter(carriesProperties);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Does the row hold a property?
|
|
174
|
+
*
|
|
175
|
+
* PubChem answers HTTP 200 for a CID that does not exist, with one row that
|
|
176
|
+
* carries the `CID` alone. Thus a row with no property is an absence, and a
|
|
177
|
+
* caller must not read it as a compound.
|
|
178
|
+
*/
|
|
179
|
+
function carriesProperties(row) {
|
|
180
|
+
return Object.entries(row).some(([key, value]) => key !== "cid" && value !== null);
|
|
139
181
|
}
|
|
140
182
|
/** External registry ids for a CID. Empty array = the CID is in no external registry. */
|
|
141
183
|
export async function fetchPubchemCrossRefs(cid) {
|
|
142
|
-
const url = `${PUBCHEM_BASE}/compound/cid/${cid}/xrefs/RegistryID
|
|
184
|
+
const url = `${PUBCHEM_BASE}/compound/cid/${cid}/xrefs/RegistryID/JSON`;
|
|
143
185
|
const res = await apiFetchValidated(url, PubChemXrefResponseSchema, { headers: HEADERS });
|
|
144
186
|
if (res.isErr()) {
|
|
145
187
|
// PubChem returns 404 when the CID has no cross-references — expected.
|
|
@@ -148,20 +190,10 @@ export async function fetchPubchemCrossRefs(cid) {
|
|
|
148
190
|
throw new Error(describeApiError(res.error));
|
|
149
191
|
}
|
|
150
192
|
// PUG-REST xrefs returns an InformationList with one entry per CID.
|
|
151
|
-
// Each entry has parallel RegistryID[] and SourceName[] arrays.
|
|
152
193
|
const info = res.value.InformationList?.Information?.[0];
|
|
153
194
|
if (!info?.RegistryID?.length)
|
|
154
195
|
return [];
|
|
155
|
-
|
|
156
|
-
const registryIds = info.RegistryID;
|
|
157
|
-
const sourceNames = info.SourceName ?? [];
|
|
158
|
-
for (let i = 0; i < registryIds.length; i++) {
|
|
159
|
-
crossRefs.push({
|
|
160
|
-
source: sourceNames[i] ?? "Unknown",
|
|
161
|
-
id: registryIds[i] ?? "",
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
return crossRefs;
|
|
196
|
+
return info.RegistryID.map((id) => ({ source: classifyRegistryId(id), id }));
|
|
165
197
|
}
|
|
166
198
|
/** Bioassay screening summaries for a CID. Empty array = never screened. */
|
|
167
199
|
export async function fetchPubchemAssays(cid, opts) {
|
|
@@ -179,39 +211,35 @@ export async function fetchPubchemAssays(cid, opts) {
|
|
|
179
211
|
}
|
|
180
212
|
return assays.slice(0, opts.limit);
|
|
181
213
|
}
|
|
182
|
-
|
|
214
|
+
/**
|
|
215
|
+
* Read the assay table by its wire headings.
|
|
216
|
+
*
|
|
217
|
+
* The `targetName` of a record is the target accession, because the table names
|
|
218
|
+
* no protein. The accession resolves against UniProt or against a ChEMBL target.
|
|
219
|
+
*/
|
|
220
|
+
export function parseAssaySummary(data) {
|
|
183
221
|
const columns = data.Table?.Columns?.Column ?? [];
|
|
184
222
|
const rows = data.Table?.Row ?? [];
|
|
185
|
-
// Find column indices by heading
|
|
186
223
|
const headingIndex = new Map();
|
|
187
|
-
for (
|
|
188
|
-
|
|
189
|
-
headingIndex.set(columns[i].Heading, i);
|
|
190
|
-
}
|
|
224
|
+
for (const [index, heading] of columns.entries()) {
|
|
225
|
+
headingIndex.set(heading, index);
|
|
191
226
|
}
|
|
192
|
-
const aidIdx = headingIndex.get(
|
|
193
|
-
const nameIdx = headingIndex.get(
|
|
194
|
-
const targetIdx = headingIndex.get(
|
|
195
|
-
const outcomeIdx = headingIndex.get(
|
|
196
|
-
const valueIdx = headingIndex.get(
|
|
227
|
+
const aidIdx = headingIndex.get(ASSAY_HEADINGS.aid);
|
|
228
|
+
const nameIdx = headingIndex.get(ASSAY_HEADINGS.assayName);
|
|
229
|
+
const targetIdx = headingIndex.get(ASSAY_HEADINGS.targetAccession);
|
|
230
|
+
const outcomeIdx = headingIndex.get(ASSAY_HEADINGS.activityOutcome);
|
|
231
|
+
const valueIdx = headingIndex.get(ASSAY_HEADINGS.activityValue);
|
|
197
232
|
const results = [];
|
|
198
233
|
for (const row of rows) {
|
|
199
234
|
const cells = row.Cell ?? [];
|
|
235
|
+
// An empty cell is the empty string, which carries no value.
|
|
200
236
|
const getCellStr = (idx) => {
|
|
201
|
-
if (idx === undefined
|
|
202
|
-
return null;
|
|
203
|
-
return cells[idx]?.sval ?? null;
|
|
204
|
-
};
|
|
205
|
-
const getCellNum = (idx) => {
|
|
206
|
-
if (idx === undefined || idx >= cells.length)
|
|
237
|
+
if (idx === undefined)
|
|
207
238
|
return null;
|
|
208
239
|
const cell = cells[idx];
|
|
209
|
-
|
|
210
|
-
return cell.fval;
|
|
211
|
-
if (cell?.intval !== undefined)
|
|
212
|
-
return cell.intval;
|
|
213
|
-
return null;
|
|
240
|
+
return cell !== undefined && cell !== "" ? cell : null;
|
|
214
241
|
};
|
|
242
|
+
const getCellNum = (idx) => parseWireNumber(getCellStr(idx));
|
|
215
243
|
results.push({
|
|
216
244
|
aid: getCellNum(aidIdx) ?? 0,
|
|
217
245
|
assayName: getCellStr(nameIdx),
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Used by §3.11 (Key Papers), §3.10.4 (Preclinical literature), and the
|
|
5
5
|
* pubmed-index Phase-1 collector.
|
|
6
|
+
*
|
|
7
|
+
* Absence policy: NCBI E-utilities omits the key of an absent value, and it
|
|
8
|
+
* never sends an explicit `null`. Thus a maybe-absent field carries
|
|
9
|
+
* `.optional()`, not `.nullable()`.
|
|
6
10
|
*/
|
|
7
11
|
import { type ArticleDetail, type ArticleSection, type FullTextResult, type PubmedSearchOptions, type PubMedSummary } from "../../literature/sources/pubmed.js";
|
|
8
12
|
export type { PubMedSummary, ArticleDetail, ArticleSection, FullTextResult };
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Used by §3.11 (Key Papers), §3.10.4 (Preclinical literature), and the
|
|
5
5
|
* pubmed-index Phase-1 collector.
|
|
6
|
+
*
|
|
7
|
+
* Absence policy: NCBI E-utilities omits the key of an absent value, and it
|
|
8
|
+
* never sends an explicit `null`. Thus a maybe-absent field carries
|
|
9
|
+
* `.optional()`, not `.nullable()`.
|
|
6
10
|
*/
|
|
7
11
|
import { createPubmedSource, } from "../../literature/sources/pubmed.js";
|
|
8
12
|
function pubmedSource(ncbiApiKey) {
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
* Pure async client functions for STRING DB protein-protein interactions.
|
|
3
3
|
*
|
|
4
4
|
* Used by §3.8 (PPI Network).
|
|
5
|
+
*
|
|
6
|
+
* Absence policy: STRING omits the key of an absent value, and it never sends
|
|
7
|
+
* an explicit `null`. Thus a maybe-absent field carries `.optional()`, not
|
|
8
|
+
* `.nullable()`.
|
|
5
9
|
*/
|
|
10
|
+
import { z } from "zod";
|
|
6
11
|
export interface StringInteraction {
|
|
7
12
|
proteinA: string;
|
|
8
13
|
proteinB: string;
|
|
@@ -25,6 +30,53 @@ export interface InteractionOptions {
|
|
|
25
30
|
minScore?: number;
|
|
26
31
|
limit?: number;
|
|
27
32
|
}
|
|
33
|
+
export declare const StringInteractionSchema: z.ZodPipe<z.ZodObject<{
|
|
34
|
+
preferredName_A: z.ZodOptional<z.ZodString>;
|
|
35
|
+
preferredName_B: z.ZodOptional<z.ZodString>;
|
|
36
|
+
score: z.ZodOptional<z.ZodNumber>;
|
|
37
|
+
escore: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
dscore: z.ZodOptional<z.ZodNumber>;
|
|
39
|
+
tscore: z.ZodOptional<z.ZodNumber>;
|
|
40
|
+
}, z.core.$strip>, z.ZodTransform<{
|
|
41
|
+
proteinA: string;
|
|
42
|
+
proteinB: string;
|
|
43
|
+
score: number;
|
|
44
|
+
experimentalScore: number | undefined;
|
|
45
|
+
databaseScore: number | undefined;
|
|
46
|
+
textminingScore: number | undefined;
|
|
47
|
+
}, {
|
|
48
|
+
preferredName_A?: string | undefined;
|
|
49
|
+
preferredName_B?: string | undefined;
|
|
50
|
+
score?: number | undefined;
|
|
51
|
+
escore?: number | undefined;
|
|
52
|
+
dscore?: number | undefined;
|
|
53
|
+
tscore?: number | undefined;
|
|
54
|
+
}>>;
|
|
55
|
+
export declare const StringEnrichmentSchema: z.ZodPipe<z.ZodObject<{
|
|
56
|
+
category: z.ZodOptional<z.ZodString>;
|
|
57
|
+
term: z.ZodOptional<z.ZodString>;
|
|
58
|
+
description: z.ZodOptional<z.ZodString>;
|
|
59
|
+
p_value: z.ZodOptional<z.ZodNumber>;
|
|
60
|
+
fdr: z.ZodOptional<z.ZodNumber>;
|
|
61
|
+
number_of_genes: z.ZodOptional<z.ZodNumber>;
|
|
62
|
+
preferredNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
63
|
+
}, z.core.$strip>, z.ZodTransform<{
|
|
64
|
+
category: string;
|
|
65
|
+
term: string;
|
|
66
|
+
description: string;
|
|
67
|
+
pValue: number;
|
|
68
|
+
fdr: number;
|
|
69
|
+
geneCount: number;
|
|
70
|
+
genes: string[];
|
|
71
|
+
}, {
|
|
72
|
+
category?: string | undefined;
|
|
73
|
+
term?: string | undefined;
|
|
74
|
+
description?: string | undefined;
|
|
75
|
+
p_value?: number | undefined;
|
|
76
|
+
fdr?: number | undefined;
|
|
77
|
+
number_of_genes?: number | undefined;
|
|
78
|
+
preferredNames?: string[] | undefined;
|
|
79
|
+
}>>;
|
|
28
80
|
/** Fetch interaction partners (one-hop) for the given identifiers. */
|
|
29
81
|
export declare function getInteractionPartners(identifiers: string[], options?: InteractionOptions): Promise<StringInteraction[]>;
|
|
30
82
|
/**
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Pure async client functions for STRING DB protein-protein interactions.
|
|
3
3
|
*
|
|
4
4
|
* Used by §3.8 (PPI Network).
|
|
5
|
+
*
|
|
6
|
+
* Absence policy: STRING omits the key of an absent value, and it never sends
|
|
7
|
+
* an explicit `null`. Thus a maybe-absent field carries `.optional()`, not
|
|
8
|
+
* `.nullable()`.
|
|
5
9
|
*/
|
|
6
10
|
import { z } from "zod";
|
|
7
11
|
import { apiFetchValidated, describeApiError } from "./api-utils.js";
|
|
@@ -23,7 +27,7 @@ function buildParams(identifiers, species, extra = {}) {
|
|
|
23
27
|
// `.transform(...)` half normalizes it into the `StringInteraction` we return. Parsing IS
|
|
24
28
|
// the validation: `apiFetchValidated` runs this over the JSON, so a field whose type drifts
|
|
25
29
|
// is rejected as `invalid_response` rather than silently mis-mapped.
|
|
26
|
-
const StringInteractionSchema = z
|
|
30
|
+
export const StringInteractionSchema = z
|
|
27
31
|
.object({
|
|
28
32
|
preferredName_A: z.string().optional(),
|
|
29
33
|
preferredName_B: z.string().optional(),
|
|
@@ -40,10 +44,11 @@ const StringInteractionSchema = z
|
|
|
40
44
|
databaseScore: d.dscore ?? undefined,
|
|
41
45
|
textminingScore: d.tscore ?? undefined,
|
|
42
46
|
}));
|
|
43
|
-
// One STRING enrichment row. `preferredNames`
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
+
// One STRING enrichment row. The `/api/json` renderer sends `preferredNames` as a
|
|
48
|
+
// JSON array of gene names on every row, thus the schema declares an array. A
|
|
49
|
+
// comma-joined string is a form of the tsv renderer, which this client never
|
|
50
|
+
// calls.
|
|
51
|
+
export const StringEnrichmentSchema = z
|
|
47
52
|
.object({
|
|
48
53
|
category: z.string().optional(),
|
|
49
54
|
term: z.string().optional(),
|
|
@@ -51,7 +56,7 @@ const StringEnrichmentSchema = z
|
|
|
51
56
|
p_value: z.number().optional(),
|
|
52
57
|
fdr: z.number().optional(),
|
|
53
58
|
number_of_genes: z.number().optional(),
|
|
54
|
-
preferredNames: z.
|
|
59
|
+
preferredNames: z.array(z.string()).optional(),
|
|
55
60
|
})
|
|
56
61
|
.transform((d) => ({
|
|
57
62
|
category: d.category ?? "",
|
|
@@ -60,7 +65,7 @@ const StringEnrichmentSchema = z
|
|
|
60
65
|
pValue: d.p_value ?? 1,
|
|
61
66
|
fdr: d.fdr ?? 1,
|
|
62
67
|
geneCount: d.number_of_genes ?? 0,
|
|
63
|
-
genes:
|
|
68
|
+
genes: d.preferredNames ?? [],
|
|
64
69
|
}));
|
|
65
70
|
/** Fetch interaction partners (one-hop) for the given identifiers. */
|
|
66
71
|
export async function getInteractionPartners(identifiers, options = {}) {
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
* - Protein family text — used together with IUPHAR family-target
|
|
9
9
|
* resolution to identify sibling receptors in the same pharmacological
|
|
10
10
|
* family (replaces the hand-curated RELATED_FAMILY_UNIPROTS map).
|
|
11
|
+
*
|
|
12
|
+
* Absence policy: the OpenAPI document of UniProt marks no field as required,
|
|
13
|
+
* and the API omits the key of an absent value. Thus a maybe-absent field
|
|
14
|
+
* carries `.optional()`, not `.nullable()`.
|
|
11
15
|
*/
|
|
12
16
|
export interface UniProtRecord {
|
|
13
17
|
primaryAccession: string;
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
* - Protein family text — used together with IUPHAR family-target
|
|
9
9
|
* resolution to identify sibling receptors in the same pharmacological
|
|
10
10
|
* family (replaces the hand-curated RELATED_FAMILY_UNIPROTS map).
|
|
11
|
+
*
|
|
12
|
+
* Absence policy: the OpenAPI document of UniProt marks no field as required,
|
|
13
|
+
* and the API omits the key of an absent value. Thus a maybe-absent field
|
|
14
|
+
* carries `.optional()`, not `.nullable()`.
|
|
11
15
|
*/
|
|
12
16
|
import { z } from "zod";
|
|
13
17
|
import { apiFetchValidated, describeApiError } from "./api-utils.js";
|
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
* documentation and code examples at runtime. Two-step flow:
|
|
6
6
|
* 1. resolveLibraryId — find the Context7 library ID for a package name
|
|
7
7
|
* 2. queryDocs — query documentation for a resolved library
|
|
8
|
+
*
|
|
9
|
+
* Absence policy: the OpenAPI document of Context7 marks no field as nullable,
|
|
10
|
+
* and the sampled payloads carry no explicit `null`. Thus an absent value is an
|
|
11
|
+
* omitted key, and a maybe-absent field carries `.optional()`.
|
|
8
12
|
*/
|
|
13
|
+
import { z } from "zod";
|
|
9
14
|
type ResolveLibraryIdOutput = {
|
|
10
15
|
found: false;
|
|
11
16
|
} | {
|
|
@@ -20,6 +25,24 @@ type QueryDocsOutput = {
|
|
|
20
25
|
found: true;
|
|
21
26
|
documentation: string;
|
|
22
27
|
};
|
|
28
|
+
export declare const Context7SearchResponseSchema: z.ZodObject<{
|
|
29
|
+
results: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
30
|
+
id: z.ZodString;
|
|
31
|
+
title: z.ZodString;
|
|
32
|
+
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
33
|
+
}, z.core.$strip>>>;
|
|
34
|
+
}, z.core.$strip>;
|
|
35
|
+
export declare const Context7DocsResponseSchema: z.ZodObject<{
|
|
36
|
+
snippets: z.ZodArray<z.ZodObject<{
|
|
37
|
+
codeTitle: z.ZodString;
|
|
38
|
+
codeDescription: z.ZodString;
|
|
39
|
+
codeId: z.ZodString;
|
|
40
|
+
codeList: z.ZodArray<z.ZodObject<{
|
|
41
|
+
language: z.ZodString;
|
|
42
|
+
code: z.ZodString;
|
|
43
|
+
}, z.core.$strip>>;
|
|
44
|
+
}, z.core.$strip>>;
|
|
45
|
+
}, z.core.$strip>;
|
|
23
46
|
export declare const resolveLibraryIdTool: import("../define-tool.js").Tool<{
|
|
24
47
|
libraryName: string;
|
|
25
48
|
query: string;
|
|
@@ -5,19 +5,42 @@
|
|
|
5
5
|
* documentation and code examples at runtime. Two-step flow:
|
|
6
6
|
* 1. resolveLibraryId — find the Context7 library ID for a package name
|
|
7
7
|
* 2. queryDocs — query documentation for a resolved library
|
|
8
|
+
*
|
|
9
|
+
* Absence policy: the OpenAPI document of Context7 marks no field as nullable,
|
|
10
|
+
* and the sampled payloads carry no explicit `null`. Thus an absent value is an
|
|
11
|
+
* omitted key, and a maybe-absent field carries `.optional()`.
|
|
8
12
|
*/
|
|
9
13
|
import { ok } from "neverthrow";
|
|
10
14
|
import { z } from "zod";
|
|
11
15
|
import { defineTool } from "../define-tool.js";
|
|
12
16
|
import { apiFetchValidated, describeApiError } from "../lib/api-utils.js";
|
|
13
17
|
const CONTEXT7_BASE = "https://context7.com/api/v1";
|
|
14
|
-
// Raw Context7 wire shapes, validated at the fetch boundary. `id`/`
|
|
18
|
+
// Raw Context7 wire shapes, validated at the fetch boundary. `id`/`title` stay
|
|
15
19
|
// required — they are read without a guard — while genuinely-optional fields
|
|
16
20
|
// carry `.optional()` so a partial-but-valid response still parses.
|
|
17
|
-
const Context7SearchResponseSchema = z.object({
|
|
18
|
-
results: z.array(z.object({ id: z.string(),
|
|
21
|
+
export const Context7SearchResponseSchema = z.object({
|
|
22
|
+
results: z.array(z.object({ id: z.string(), title: z.string(), description: z.string().nullable().optional() })).optional(),
|
|
23
|
+
});
|
|
24
|
+
// The docs route answers one `snippets` array, and each snippet holds its code in
|
|
25
|
+
// `codeList`. There is no single documentation text on the wire, thus the tool
|
|
26
|
+
// composes one from the snippets below.
|
|
27
|
+
export const Context7DocsResponseSchema = z.object({
|
|
28
|
+
snippets: z.array(z.object({
|
|
29
|
+
codeTitle: z.string(),
|
|
30
|
+
codeDescription: z.string(),
|
|
31
|
+
codeId: z.string(),
|
|
32
|
+
codeList: z.array(z.object({ language: z.string(), code: z.string() })),
|
|
33
|
+
})),
|
|
19
34
|
});
|
|
20
|
-
|
|
35
|
+
/** Render the snippets of one docs answer as a single text, in the layout of the Context7 text route. */
|
|
36
|
+
function renderSnippets(snippets) {
|
|
37
|
+
return snippets
|
|
38
|
+
.map((snippet) => {
|
|
39
|
+
const code = snippet.codeList.map((example) => `\`\`\`${example.language}\n${example.code}\n\`\`\``).join("\n\n");
|
|
40
|
+
return `### ${snippet.codeTitle}\n\nSource: ${snippet.codeId}\n\n${snippet.codeDescription}\n\n${code}`;
|
|
41
|
+
})
|
|
42
|
+
.join("\n\n--------------------------------\n\n");
|
|
43
|
+
}
|
|
21
44
|
export const resolveLibraryIdTool = defineTool({
|
|
22
45
|
id: "resolve_library_id",
|
|
23
46
|
description: "Resolve a package name (e.g., 'scanpy', 'DESeq2', 'scikit-learn') to a Context7 library ID. Call this BEFORE `query_docs` to get the library ID needed for documentation lookup. Returns matching libraries ranked by relevance.",
|
|
@@ -37,7 +60,9 @@ export const resolveLibraryIdTool = defineTool({
|
|
|
37
60
|
return ok({
|
|
38
61
|
found: true,
|
|
39
62
|
libraryId: best.id,
|
|
40
|
-
name
|
|
63
|
+
// The display name of a library is `title` on the wire. The output keeps
|
|
64
|
+
// the `name` key, because that key is the contract that a caller reads.
|
|
65
|
+
name: best.title,
|
|
41
66
|
description: best.description ?? "",
|
|
42
67
|
});
|
|
43
68
|
},
|
|
@@ -46,15 +71,30 @@ export const queryDocsTool = defineTool({
|
|
|
46
71
|
id: "query_docs",
|
|
47
72
|
description: "Query up-to-date documentation and code examples for a library. You must call `resolve_library_id` first to get the libraryId. Use this to verify function signatures, parameters, and usage patterns before writing code.",
|
|
48
73
|
inputSchema: z.object({
|
|
49
|
-
libraryId: z.string().describe("Context7 library ID
|
|
74
|
+
libraryId: z.string().describe("Context7 library ID exactly as `resolve_library_id` gave it — an owner and a library, for example '/scverse/scanpy'."),
|
|
50
75
|
query: z.string().describe("Specific question about the library (e.g., 'rank_genes_groups function parameters and usage')."),
|
|
51
76
|
}),
|
|
52
77
|
describeCall: "none",
|
|
53
78
|
execute: async ({ libraryId, query }) => {
|
|
54
|
-
|
|
55
|
-
|
|
79
|
+
// The library id is the path of the route, not a query parameter. Each
|
|
80
|
+
// segment is encoded on its own, thus the separators of the id survive and
|
|
81
|
+
// a leading or trailing slash makes no difference.
|
|
82
|
+
const path = libraryId
|
|
83
|
+
.split("/")
|
|
84
|
+
.filter((segment) => segment !== "")
|
|
85
|
+
.map((segment) => encodeURIComponent(segment))
|
|
86
|
+
.join("/");
|
|
87
|
+
const result = await apiFetchValidated(`${CONTEXT7_BASE}/${path}?type=json&topic=${encodeURIComponent(query)}`, Context7DocsResponseSchema, {
|
|
88
|
+
maxRetries: 1,
|
|
89
|
+
});
|
|
90
|
+
if (result.isErr()) {
|
|
91
|
+
// Context7 answers 404 for a library that it does not hold. A stale id is
|
|
92
|
+
// an expected outcome, thus it becomes a data variant.
|
|
93
|
+
if (result.error.type === "http_status" && result.error.status === 404)
|
|
94
|
+
return ok({ found: false });
|
|
56
95
|
throw new Error(`Context7 query failed: ${describeApiError(result.error)}`);
|
|
57
|
-
|
|
96
|
+
}
|
|
97
|
+
const documentation = renderSnippets(result.value.snippets);
|
|
58
98
|
// No documentation for the query is an expected outcome.
|
|
59
99
|
if (!documentation)
|
|
60
100
|
return ok({ found: false });
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* (lower rate limit); `GITHUB_TOKEN` raises the limit.
|
|
5
5
|
*
|
|
6
6
|
* Same wire call and envelope as the legacy tool. Stateless HTTP; no deps.
|
|
7
|
+
*
|
|
8
|
+
* Absence policy: the OpenAPI document of GitHub marks `description` and
|
|
9
|
+
* `language` as required and nullable, thus an absent value is an explicit
|
|
10
|
+
* `null`. The OpenAPI document gives the modifier of each field.
|
|
7
11
|
*/
|
|
8
12
|
type SearchGithubReposOutput = {
|
|
9
13
|
success: false;
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* (lower rate limit); `GITHUB_TOKEN` raises the limit.
|
|
5
5
|
*
|
|
6
6
|
* Same wire call and envelope as the legacy tool. Stateless HTTP; no deps.
|
|
7
|
+
*
|
|
8
|
+
* Absence policy: the OpenAPI document of GitHub marks `description` and
|
|
9
|
+
* `language` as required and nullable, thus an absent value is an explicit
|
|
10
|
+
* `null`. The OpenAPI document gives the modifier of each field.
|
|
7
11
|
*/
|
|
8
12
|
import { ok } from "neverthrow";
|
|
9
13
|
import { z } from "zod";
|
|
@@ -149,7 +149,7 @@ export async function runExecuteTargetAssessmentBody(input, deps) {
|
|
|
149
149
|
// terminal block dispatches `markFailed({kind: "target-unresolved"})`.
|
|
150
150
|
await emitProgress(deps.pool, logger, input.assessmentId, "resolving");
|
|
151
151
|
const resolved = await DBOS.runStep(async () => {
|
|
152
|
-
const r = await resolveTarget(input.target);
|
|
152
|
+
const r = await resolveTarget(input.target, logger);
|
|
153
153
|
return {
|
|
154
154
|
assessmentId: input.assessmentId,
|
|
155
155
|
goal: input.goal ?? null,
|
|
@@ -166,7 +166,7 @@ export async function runExecuteTargetAssessmentBody(input, deps) {
|
|
|
166
166
|
// and `Phase1Bundle` is reconstructed by manifest key below.
|
|
167
167
|
await emitProgress(deps.pool, logger, input.assessmentId, "collecting");
|
|
168
168
|
const manifest = COLLECTOR_MANIFEST;
|
|
169
|
-
const collectorCtx = { ncbiApiKey: deps.ncbiApiKey };
|
|
169
|
+
const collectorCtx = { ncbiApiKey: deps.ncbiApiKey, logger };
|
|
170
170
|
const collectorPairs = await Promise.all(manifest.map((entry) => DBOS.runStep(() => entry.run(resolved, collectorCtx), {
|
|
171
171
|
name: `ta-collector:${entry.id}`,
|
|
172
172
|
})
|
|
@@ -285,7 +285,7 @@ export async function runExecuteTargetAssessmentBody(input, deps) {
|
|
|
285
285
|
const [perModulatorFaersResults, perTrialAesResults, perModulatorPolypharmResults, perClassDrugAesResults] = await Promise.all([
|
|
286
286
|
runFanoutBlock(triageShortlist, "modulator-faers", (item) => item.moleculeChemblId, faersForOneModulator),
|
|
287
287
|
runFanoutBlock(trialItems, "trial-aes", (item) => item.nctId, aesForOneTrial),
|
|
288
|
-
runFanoutBlock(polypharmItems, "modulator-polypharm", (item) => item.moleculeChemblId, polypharmForOneModulator),
|
|
288
|
+
runFanoutBlock(polypharmItems, "modulator-polypharm", (item) => item.moleculeChemblId, (item) => polypharmForOneModulator(item, logger)),
|
|
289
289
|
runFanoutBlock(classDrugItems, "class-drug-aes", (item) => item.moleculeChemblId, aesForOneClassDrug),
|
|
290
290
|
]);
|
|
291
291
|
const phase3 = {
|
|
@@ -307,7 +307,7 @@ export async function runExecuteTargetAssessmentBody(input, deps) {
|
|
|
307
307
|
model: deps.decisionModel,
|
|
308
308
|
...(deps.usageRecorder ? { usageRecorder: deps.usageRecorder } : {}),
|
|
309
309
|
};
|
|
310
|
-
const phase4 = await DBOS.runStep(() => phase4Assemble(deps.pool, phase3, annotatorDeps), {
|
|
310
|
+
const phase4 = await DBOS.runStep(() => phase4Assemble(deps.pool, phase3, annotatorDeps, logger), {
|
|
311
311
|
name: "ta-phase4-assemble",
|
|
312
312
|
});
|
|
313
313
|
// (§5.8-pre) Approval-precedent grounding — one deterministic openFDA
|
|
@@ -21,6 +21,7 @@ import type { Phase2Bundle } from "../steps/phase2-aggregate.js";
|
|
|
21
21
|
import type { Phase3Bundle } from "../steps/phase3-aggregate.js";
|
|
22
22
|
import type { ResolvedTarget } from "../schemas.js";
|
|
23
23
|
import type { Pool } from "pg";
|
|
24
|
+
import type { Logger } from "../../../lib/logger.js";
|
|
24
25
|
import type { ClinicalConsequenceAnnotatorDeps } from "../lib/clinical-consequence-annotator.js";
|
|
25
26
|
import { HIGH_EXPRESSION_TPM_THRESHOLD } from "../lib/expression-constants.js";
|
|
26
27
|
export { HIGH_EXPRESSION_TPM_THRESHOLD };
|
|
@@ -52,7 +53,7 @@ export declare function assembleTractability(resolved: ResolvedTarget, ot: OpenT
|
|
|
52
53
|
* attached here — phase5-persist computes it after synthesis is stamped
|
|
53
54
|
* so the final derived values reflect liability bullets and safety flags.
|
|
54
55
|
*/
|
|
55
|
-
export declare function assembleDossier(pool: Pool, phase2: Phase2Bundle, phase3?: Phase3Bundle, annotatorDeps?: ClinicalConsequenceAnnotatorDeps): Promise<DossierBody>;
|
|
56
|
+
export declare function assembleDossier(pool: Pool, phase2: Phase2Bundle, phase3?: Phase3Bundle, annotatorDeps?: ClinicalConsequenceAnnotatorDeps, logger?: Logger): Promise<DossierBody>;
|
|
56
57
|
type ReconcileFaersClassPrecedent = {
|
|
57
58
|
coverage?: "available" | "queried_no_data" | "not_loaded";
|
|
58
59
|
data?: {
|
|
@@ -223,7 +223,7 @@ export function assembleTractability(resolved, ot, drugs) {
|
|
|
223
223
|
* attached here — phase5-persist computes it after synthesis is stamped
|
|
224
224
|
* so the final derived values reflect liability bullets and safety flags.
|
|
225
225
|
*/
|
|
226
|
-
export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
226
|
+
export async function assembleDossier(pool, phase2, phase3, annotatorDeps, logger) {
|
|
227
227
|
const fanout = phase3?.fanout;
|
|
228
228
|
const faersAgg = aggregateFaersAcrossModulators(fanout);
|
|
229
229
|
const trialAesAgg = aggregateTrialAes(fanout);
|
|
@@ -235,8 +235,8 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
235
235
|
const familyComplexesCollector = phase2.phase1.collectors.familyComplexes;
|
|
236
236
|
const familyComplexesBundle = familyComplexesCollector.coverage === "available" ? familyComplexesCollector.data : null;
|
|
237
237
|
const [onTargetChemblIds, familySiblingUniprots] = await Promise.all([
|
|
238
|
-
resolveOnTargetChemblIds(assessmentUniprot),
|
|
239
|
-
resolveFamilySiblingUniprots(assessmentUniprot || geneSymbol),
|
|
238
|
+
resolveOnTargetChemblIds(assessmentUniprot, logger),
|
|
239
|
+
resolveFamilySiblingUniprots(assessmentUniprot || geneSymbol, logger),
|
|
240
240
|
]);
|
|
241
241
|
const offTargetPanel = aggregateOffTargetPanel(phase2, fanout, assessmentUniprot, geneSymbol, familyComplexesBundle, onTargetChemblIds);
|
|
242
242
|
if (offTargetPanel) {
|