@inflexa-ai/harness 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/report-builder.d.ts +2 -0
- package/dist/agents/report-builder.js +2 -0
- package/dist/app/spawn-report-session.d.ts +85 -0
- package/dist/app/spawn-report-session.js +83 -0
- package/dist/contracts/chat-events.d.ts +9 -0
- package/dist/contracts/index.d.ts +6 -2
- package/dist/contracts/index.js +3 -1
- package/dist/contracts/organ-system.d.ts +49 -0
- package/dist/contracts/organ-system.js +67 -0
- package/dist/contracts/report-blocks.d.ts +564 -0
- package/dist/contracts/report-blocks.js +117 -0
- package/dist/contracts/report-reference.d.ts +459 -0
- package/dist/contracts/report-reference.js +256 -0
- package/dist/contracts/schemas/chat-events.d.ts +2 -0
- package/dist/contracts/schemas/chat-events.js +2 -0
- package/dist/contracts/severity.d.ts +15 -0
- package/dist/contracts/severity.js +10 -0
- package/dist/contracts/target-dossier.d.ts +8675 -12972
- package/dist/contracts/target-dossier.js +534 -591
- package/dist/data/safety-panel-schema.d.ts +18 -5
- package/dist/data/safety-panel-schema.js +4 -4
- package/dist/execution/artifact-metadata.js +1 -0
- package/dist/execution/report-runner.js +1 -3
- package/dist/execution/run-synthesis.js +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +19 -0
- package/dist/lib/async-utils.d.ts +16 -4
- package/dist/lib/async-utils.js +20 -15
- package/dist/lib/host-concurrency.js +1 -0
- package/dist/loop/__fixtures__/scripted-provider.js +23 -2
- package/dist/loop/run-agent.js +58 -10
- package/dist/loop/tool-detail.d.ts +40 -0
- package/dist/loop/tool-detail.js +35 -3
- package/dist/loop/types.d.ts +13 -0
- package/dist/memory/thread-history.d.ts +10 -0
- package/dist/memory/thread-history.js +12 -1
- package/dist/prompts/target-assessment/briefs/executive-recommendation.d.ts +1 -1
- package/dist/prompts/target-assessment/briefs/executive-recommendation.js +5 -5
- package/dist/prompts/target-assessment/briefs/liability-bullets.d.ts +1 -1
- package/dist/prompts/target-assessment/briefs/liability-bullets.js +1 -1
- package/dist/prompts/target-assessment/briefs/target-organ-liabilities.d.ts +1 -1
- package/dist/prompts/target-assessment/briefs/target-organ-liabilities.js +11 -3
- package/dist/prompts/target-assessment/investigation/adversarial-critique.d.ts +1 -0
- package/dist/prompts/target-assessment/investigation/adversarial-critique.js +67 -0
- package/dist/prompts/target-assessment/investigation/claim-reverification.d.ts +1 -0
- package/dist/prompts/target-assessment/investigation/claim-reverification.js +49 -0
- package/dist/prompts/target-assessment/investigation/index.d.ts +3 -0
- package/dist/prompts/target-assessment/investigation/index.js +3 -0
- package/dist/prompts/target-assessment/investigation/mechanism-proposal.d.ts +1 -0
- package/dist/prompts/target-assessment/investigation/mechanism-proposal.js +49 -0
- package/dist/prompts/target-assessment/tox-voice/index.d.ts +1 -1
- package/dist/prompts/target-assessment/tox-voice/vocabulary.d.ts +8 -5
- package/dist/prompts/target-assessment/tox-voice/vocabulary.js +9 -20
- package/dist/providers/__fixtures__/session.d.ts +5 -4
- package/dist/providers/__fixtures__/session.js +4 -4
- package/dist/report-model/block-walk.d.ts +56 -0
- package/dist/report-model/block-walk.js +89 -0
- package/dist/report-model/draft-finish.d.ts +60 -0
- package/dist/report-model/draft-finish.js +56 -0
- package/dist/report-model/draft-operations.d.ts +125 -0
- package/dist/report-model/draft-operations.js +341 -0
- package/dist/report-model/draft-read.d.ts +59 -0
- package/dist/report-model/draft-read.js +109 -0
- package/dist/report-model/draft.d.ts +51 -0
- package/dist/report-model/draft.js +32 -0
- package/dist/report-model/fixture-resolver.d.ts +8 -0
- package/dist/report-model/fixture-resolver.js +252 -0
- package/dist/report-model/mint-snapshot.d.ts +30 -0
- package/dist/report-model/mint-snapshot.js +40 -0
- package/dist/report-model/reference-resolver.d.ts +113 -0
- package/dist/report-model/reference-resolver.js +60 -0
- package/dist/report-model/structural-validation.d.ts +22 -0
- package/dist/report-model/structural-validation.js +68 -0
- package/dist/report-model/validate.d.ts +40 -0
- package/dist/report-model/validate.js +80 -0
- package/dist/report-render/chart.d.ts +33 -0
- package/dist/report-render/chart.js +538 -0
- package/dist/report-render/page.d.ts +127 -0
- package/dist/report-render/page.js +307 -0
- package/dist/report-render/references.d.ts +32 -0
- package/dist/report-render/references.js +44 -0
- package/dist/report-render/render.d.ts +25 -0
- package/dist/report-render/render.js +125 -0
- package/dist/report-render/script-json.d.ts +13 -0
- package/dist/report-render/script-json.js +15 -0
- package/dist/report-render/types.d.ts +39 -0
- package/dist/report-render/types.js +10 -0
- package/dist/report-render/views/chart-view.d.ts +11 -0
- package/dist/report-render/views/chart-view.js +23 -0
- package/dist/report-render/views/page-view.d.ts +20 -0
- package/dist/report-render/views/page-view.js +49 -0
- package/dist/report-render/views/prose.d.ts +28 -0
- package/dist/report-render/views/prose.js +75 -0
- package/dist/report-render/views/references-view.d.ts +20 -0
- package/dist/report-render/views/references-view.js +64 -0
- package/dist/report-render/views/values.d.ts +42 -0
- package/dist/report-render/views/values.js +43 -0
- package/dist/runtime/boot.d.ts +3 -3
- package/dist/runtime/boot.js +15 -4
- package/dist/runtime/dbos.d.ts +4 -4
- package/dist/state/artifacts.d.ts +16 -0
- package/dist/state/artifacts.js +18 -0
- package/dist/state/init.js +31 -0
- package/dist/state/purge-analysis.js +1 -0
- package/dist/state/report-versions.d.ts +132 -0
- package/dist/state/report-versions.js +194 -0
- package/dist/tasks/data-profile.js +1 -0
- package/dist/tools/bio/chembl.js +1 -0
- package/dist/tools/bio/comptox.js +1 -0
- package/dist/tools/bio/drug-gene-interactions.js +1 -0
- package/dist/tools/bio/gene-disease-evidence.js +1 -0
- package/dist/tools/bio/gene-preclinical-profile.js +1 -0
- package/dist/tools/bio/keys.d.ts +3 -2
- package/dist/tools/bio/keys.js +3 -2
- package/dist/tools/bio/lookup-annotation.js +1 -0
- package/dist/tools/bio/opentargets.d.ts +3 -3
- package/dist/tools/bio/opentargets.js +4 -3
- package/dist/tools/bio/pubchem.js +1 -0
- package/dist/tools/bio/search-clinical-trials.js +1 -0
- package/dist/tools/bio/search-faers.js +1 -0
- package/dist/tools/bio/search-geo-datasets.js +1 -0
- package/dist/tools/bio/search-interactions.js +1 -0
- package/dist/tools/bio/target-safety.d.ts +4 -6
- package/dist/tools/bio/target-safety.js +7 -6
- package/dist/tools/define-tool.d.ts +19 -12
- package/dist/tools/define-tool.js +4 -2
- package/dist/tools/display/show-user.js +1 -0
- package/dist/tools/iterate-report.js +2 -0
- package/dist/tools/lib/chembl-client.d.ts +2 -0
- package/dist/tools/lib/chembl-client.js +1 -0
- package/dist/tools/lib/monarch-client.d.ts +42 -0
- package/dist/tools/lib/monarch-client.js +100 -0
- package/dist/tools/report/build-report.js +1 -0
- package/dist/tools/report/mint-preview-url.js +1 -0
- package/dist/tools/report/preview-snapshot.js +1 -0
- package/dist/tools/report/submit-report.js +1 -0
- package/dist/tools/report/version-fs.js +4 -0
- package/dist/tools/report-authoring/authoring-tools.d.ts +134 -0
- package/dist/tools/report-authoring/authoring-tools.js +352 -0
- package/dist/tools/research/context7-docs.js +2 -0
- package/dist/tools/research/generate-analogy-report.js +1 -0
- package/dist/tools/research/generate-plan.js +3 -0
- package/dist/tools/research/inspect-data-profile.js +4 -0
- package/dist/tools/research/literature-reviewer.js +1 -0
- package/dist/tools/research/search-arxiv.js +1 -0
- package/dist/tools/research/search-github-repos.js +1 -0
- package/dist/tools/research/search-semantic-scholar.js +1 -0
- package/dist/tools/sandbox/list-available-packages.js +23 -0
- package/dist/tools/sandbox/list-available-refs.js +36 -0
- package/dist/tools/sandbox/report-blocker.js +1 -0
- package/dist/tools/sandbox/skills.js +2 -0
- package/dist/tools/workspace/file-stat.js +1 -0
- package/dist/tools/workspace/show-file.js +2 -0
- package/dist/tools/workspace/show-plan.js +1 -0
- package/dist/workflows/execute-analysis.d.ts +5 -1
- package/dist/workflows/execute-analysis.js +5 -5
- package/dist/workflows/execute-target-assessment.d.ts +13 -2
- package/dist/workflows/execute-target-assessment.js +78 -16
- package/dist/workflows/target-assessment/assemblers/index.d.ts +1 -1
- package/dist/workflows/target-assessment/assemblers/index.js +1 -1
- package/dist/workflows/target-assessment/assemblers/literature.d.ts +9 -27
- package/dist/workflows/target-assessment/assemblers/literature.js +32 -48
- package/dist/workflows/target-assessment/assemblers/orchestrator.d.ts +17 -9
- package/dist/workflows/target-assessment/assemblers/orchestrator.js +195 -85
- package/dist/workflows/target-assessment/assemblers/safety.d.ts +70 -48
- package/dist/workflows/target-assessment/assemblers/safety.js +125 -42
- package/dist/workflows/target-assessment/collectors/index.d.ts +5 -2
- package/dist/workflows/target-assessment/collectors/index.js +48 -5
- package/dist/workflows/target-assessment/coverage.d.ts +43 -27
- package/dist/workflows/target-assessment/coverage.js +33 -29
- package/dist/workflows/target-assessment/fanout/index.js +1 -0
- package/dist/workflows/target-assessment/investigation/index.d.ts +97 -0
- package/dist/workflows/target-assessment/investigation/index.js +419 -0
- package/dist/workflows/target-assessment/lib/approval-precedents.d.ts +26 -5
- package/dist/workflows/target-assessment/lib/approval-precedents.js +95 -29
- package/dist/workflows/target-assessment/lib/citation-validator.js +1 -1
- package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.d.ts +2 -2
- package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.d.ts +2 -3
- package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.js +0 -4
- package/dist/workflows/target-assessment/lib/compute-derived.d.ts +6 -5
- package/dist/workflows/target-assessment/lib/compute-derived.js +14 -5
- package/dist/workflows/target-assessment/lib/family-complex-supplement.d.ts +5 -6
- package/dist/workflows/target-assessment/lib/family-complex-supplement.js +2 -3
- package/dist/workflows/target-assessment/lib/fda-label-safety.d.ts +72 -0
- package/dist/workflows/target-assessment/lib/fda-label-safety.js +166 -0
- package/dist/workflows/target-assessment/lib/heterodimer-filter.d.ts +0 -9
- package/dist/workflows/target-assessment/lib/heterodimer-filter.js +0 -10
- package/dist/workflows/target-assessment/lib/hpo-organ-map.d.ts +34 -0
- package/dist/workflows/target-assessment/lib/hpo-organ-map.js +63 -0
- package/dist/workflows/target-assessment/lib/impc-organ-map.d.ts +19 -0
- package/dist/workflows/target-assessment/lib/impc-organ-map.js +39 -0
- package/dist/workflows/target-assessment/lib/meddra-organ-map.d.ts +24 -14
- package/dist/workflows/target-assessment/lib/meddra-organ-map.js +59 -47
- package/dist/workflows/target-assessment/lib/recommendation-sanitizer.js +1 -1
- package/dist/workflows/target-assessment/lib/regulatory-actions.d.ts +2 -3
- package/dist/workflows/target-assessment/lib/regulatory-actions.js +33 -4
- package/dist/workflows/target-assessment/lib/safety-corroboration.d.ts +44 -0
- package/dist/workflows/target-assessment/lib/safety-corroboration.js +273 -0
- package/dist/workflows/target-assessment/lib/target-identity-filter.d.ts +5 -7
- package/dist/workflows/target-assessment/lib/target-identity-filter.js +5 -7
- package/dist/workflows/target-assessment/metrics.d.ts +1 -6
- package/dist/workflows/target-assessment/metrics.js +1 -13
- package/dist/workflows/target-assessment/phase4-assemble.d.ts +2147 -807
- package/dist/workflows/target-assessment/phase4-assemble.js +19 -19
- package/dist/workflows/target-assessment/phase5-persist.d.ts +20 -21
- package/dist/workflows/target-assessment/phase5-persist.js +56 -173
- package/dist/workflows/target-assessment/schemas.d.ts +46 -1
- package/dist/workflows/target-assessment/schemas.js +19 -0
- package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.d.ts +1 -0
- package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.js +2 -0
- package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +26 -62
- package/dist/workflows/target-assessment/steps/phase2-aggregate.js +0 -4
- package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +27 -154
- package/dist/workflows/target-assessment/steps/phase3-aggregate.js +0 -6
- package/dist/workflows/target-assessment/steps/synthesis/diagnostics.d.ts +0 -6
- package/dist/workflows/target-assessment/steps/synthesis/diagnostics.js +0 -18
- package/dist/workflows/target-assessment/sub-workflows/per-modulator-polypharm.d.ts +1 -0
- package/dist/workflows/target-assessment/synthesis/index.d.ts +52 -5
- package/dist/workflows/target-assessment/synthesis/index.js +4 -1
- package/dist/workflows/target-assessment/synthesis-probes.d.ts +3 -3
- package/package.json +4 -1
|
@@ -8,15 +8,23 @@
|
|
|
8
8
|
* than fabricated. Aggregate rows preserve their contributing evidence
|
|
9
9
|
* under `evidence: [...]` arrays.
|
|
10
10
|
*/
|
|
11
|
-
import type { EvidenceItem, RegulatoryActionRow } from "@inflexa-ai/harness/contracts/target-dossier.js";
|
|
11
|
+
import type { ClaimSupport, EvidenceItem, RegulatoryActionRow, RegulatoryOrganSignals } from "@inflexa-ai/harness/contracts/target-dossier.js";
|
|
12
|
+
import { type OrganSignalProjection } from "../lib/fda-label-safety.js";
|
|
13
|
+
import { type OrganSystem } from "../../../contracts/organ-system.js";
|
|
12
14
|
import type { Phase2Bundle } from "../steps/phase2-aggregate.js";
|
|
13
15
|
import type { Phase3Bundle } from "../steps/phase3-aggregate.js";
|
|
14
16
|
import type { FamilyComplexesBundle } from "../schemas.js";
|
|
15
|
-
import { type CanonicalOrgan } from "../lib/meddra-organ-map.js";
|
|
16
17
|
import { HIGH_EXPRESSION_TPM_THRESHOLD } from "../lib/expression-constants.js";
|
|
17
18
|
export { HIGH_EXPRESSION_TPM_THRESHOLD };
|
|
18
19
|
import type { ChemblModulator } from "../../../tools/lib/chembl-client.js";
|
|
19
20
|
export declare const SAFETY_RELEVANT_ORGANS: Set<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a tissue (and its atlas organ label, when present) onto the
|
|
23
|
+
* canonical organ vocabulary. Returns null when the anatomy has no organ
|
|
24
|
+
* system to belong to — the caller drops the row rather than filing it
|
|
25
|
+
* under a neighbouring organ.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveTissueOrganSystem(tissue: string, organ?: string | null): OrganSystem | null;
|
|
20
28
|
export declare function isSafetyRelevant(tissue: string, organ?: string | null): boolean;
|
|
21
29
|
export declare const REPRODUCTIVE_TOX_TISSUES: Set<string>;
|
|
22
30
|
export declare const REPRODUCTIVE_TOX_TPM_FLOOR = 20;
|
|
@@ -55,7 +63,7 @@ export declare function aggregateFaersAcrossModulators(fanout: FanoutResults | u
|
|
|
55
63
|
};
|
|
56
64
|
top_signals: {
|
|
57
65
|
meddra_term: string;
|
|
58
|
-
organ:
|
|
66
|
+
organ: "hematologic" | "metabolic" | "immune" | "hepatic" | "musculoskeletal" | "cns" | "renal" | "reproductive" | "respiratory" | "cardiac" | "vascular" | "pns" | "gi" | "pancreas" | "endocrine_thyroid" | "dermatologic" | "ocular" | "oncology" | undefined;
|
|
59
67
|
report_count: number;
|
|
60
68
|
}[];
|
|
61
69
|
per_modulator: {
|
|
@@ -102,7 +110,7 @@ export type RawOffTargetRow = {
|
|
|
102
110
|
};
|
|
103
111
|
selectivity_window_below_threshold?: boolean;
|
|
104
112
|
evidence?: EvidenceItem[];
|
|
105
|
-
organ_system?:
|
|
113
|
+
organ_system?: OrganSystem | null;
|
|
106
114
|
target_class?: string | undefined;
|
|
107
115
|
is_safety_panel_target?: boolean;
|
|
108
116
|
clinical_consequence?: string | null;
|
|
@@ -113,7 +121,7 @@ export type RawOffTargetRow = {
|
|
|
113
121
|
export type CleanOffTargetRow = Omit<RawOffTargetRow, "target_chembl_id" | "target_type" | "accession" | "off_target_id" | "organ_system" | "evidence"> & {
|
|
114
122
|
off_target_id: string | null;
|
|
115
123
|
off_target_name: string;
|
|
116
|
-
organ_system:
|
|
124
|
+
organ_system: OrganSystem | null;
|
|
117
125
|
evidence: EvidenceItem[];
|
|
118
126
|
selectivity_window_below_threshold: boolean;
|
|
119
127
|
clinical_consequence: string | null;
|
|
@@ -123,20 +131,39 @@ export type CleanOffTargetRow = Omit<RawOffTargetRow, "target_chembl_id" | "targ
|
|
|
123
131
|
};
|
|
124
132
|
};
|
|
125
133
|
/**
|
|
126
|
-
*
|
|
134
|
+
* Off-target row shape after relationship classification. Used by the
|
|
127
135
|
* organ-rollup builder, evidence tally, and liability-summary signal count —
|
|
128
136
|
* the typed members all rely on `relationship`, `organ_system`, `pchembl`,
|
|
129
|
-
* `
|
|
137
|
+
* `support`, and `is_safety_panel_target` only.
|
|
130
138
|
*/
|
|
131
139
|
export type OffTargetPanelRows = Array<{
|
|
132
140
|
off_target_id: string | null;
|
|
133
141
|
off_target_name: string;
|
|
134
142
|
pchembl: number;
|
|
135
143
|
is_safety_panel_target: boolean;
|
|
136
|
-
organ_system:
|
|
137
|
-
|
|
144
|
+
organ_system: OrganSystem | null;
|
|
145
|
+
support: ClaimSupport;
|
|
138
146
|
relationship: "off_target";
|
|
139
147
|
}>;
|
|
148
|
+
/**
|
|
149
|
+
* Partition evidence into what a claim can stand on: an item resolves to a
|
|
150
|
+
* record a reader can check, or it does not. A claim with nothing checkable
|
|
151
|
+
* says so rather than presenting provenance labels as citations.
|
|
152
|
+
*/
|
|
153
|
+
export declare function claimSupportFrom(evidence: EvidenceItem[], reasonWhenUnsupported: string): ClaimSupport;
|
|
154
|
+
/** The evidence behind a claim, or nothing when the claim states it has none. */
|
|
155
|
+
export declare function claimSupportEvidence(support: ClaimSupport): EvidenceItem[];
|
|
156
|
+
/**
|
|
157
|
+
* Turn segmented FDA label warnings into the dossier's per-organ regulatory
|
|
158
|
+
* signal section.
|
|
159
|
+
*
|
|
160
|
+
* The organ-resolution filter can legitimately empty this section: a set of
|
|
161
|
+
* labels whose every warning fragment names no canonical organ produces no
|
|
162
|
+
* rows. That is `filtered` with the count it discarded, never an `available`
|
|
163
|
+
* section with an empty list — the difference is whether a reader learns that
|
|
164
|
+
* signals existed and did not survive attribution.
|
|
165
|
+
*/
|
|
166
|
+
export declare function assembleRegulatoryOrganSignals(projection: OrganSignalProjection | null): RegulatoryOrganSignals;
|
|
140
167
|
/**
|
|
141
168
|
* Filter and deduplicate raw off-target rows before panel assembly.
|
|
142
169
|
*
|
|
@@ -150,7 +177,7 @@ export declare function filterAndDedupOffTargetRows(rows: RawOffTargetRow[], ctx
|
|
|
150
177
|
assessmentTargetChemblId: string | null;
|
|
151
178
|
}): CleanOffTargetRow[];
|
|
152
179
|
/**
|
|
153
|
-
*
|
|
180
|
+
* Off-target panel row split. Each clean off-target row is classified as:
|
|
154
181
|
* - `on_target_self_hit`: alternate ChEMBL ID for the assessment target itself
|
|
155
182
|
* - `intended_co_target`: every modulator that hits this target intends it
|
|
156
183
|
* (e.g., GLP1R + GIPR for tirzepatide); not an off-target liability
|
|
@@ -162,7 +189,7 @@ export declare function aggregateOffTargetPanel(phase2: Phase2Bundle, fanout: Fa
|
|
|
162
189
|
off_target_name: string;
|
|
163
190
|
pchembl: number;
|
|
164
191
|
is_safety_panel_target: boolean;
|
|
165
|
-
organ_system:
|
|
192
|
+
organ_system: "hematologic" | "metabolic" | "immune" | "hepatic" | "musculoskeletal" | "cns" | "renal" | "reproductive" | "respiratory" | "cardiac" | "vascular" | "pns" | "gi" | "pancreas" | "endocrine_thyroid" | "dermatologic" | "ocular" | "oncology" | null;
|
|
166
193
|
clinical_consequence: string | null;
|
|
167
194
|
selectivity: {
|
|
168
195
|
vs_primary_potency: {
|
|
@@ -176,25 +203,32 @@ export declare function aggregateOffTargetPanel(phase2: Phase2Bundle, fanout: Fa
|
|
|
176
203
|
reason: string;
|
|
177
204
|
};
|
|
178
205
|
selectivity_window_below_threshold: boolean;
|
|
179
|
-
evidence: {
|
|
180
|
-
source: string;
|
|
181
|
-
pmid?: string | undefined;
|
|
182
|
-
doi?: string | undefined;
|
|
183
|
-
predicate?: string | undefined;
|
|
184
|
-
score?: number | undefined;
|
|
185
|
-
strength?: string | undefined;
|
|
186
|
-
is_human?: boolean | undefined;
|
|
187
|
-
is_clinical?: boolean | undefined;
|
|
188
|
-
excerpt?: string | undefined;
|
|
189
|
-
metadata?: Record<string, unknown> | undefined;
|
|
190
|
-
regulatory_reference?: {
|
|
191
|
-
document: string;
|
|
192
|
-
section?: string | undefined;
|
|
193
|
-
doc_id?: string | undefined;
|
|
194
|
-
doc_url?: string | undefined;
|
|
195
|
-
} | undefined;
|
|
196
|
-
}[];
|
|
197
206
|
relationship: "off_target";
|
|
207
|
+
support: {
|
|
208
|
+
state: "scored";
|
|
209
|
+
evidence: {
|
|
210
|
+
source: string;
|
|
211
|
+
pmid?: string | undefined;
|
|
212
|
+
doi?: string | undefined;
|
|
213
|
+
accession?: string | undefined;
|
|
214
|
+
predicate?: string | undefined;
|
|
215
|
+
score?: number | undefined;
|
|
216
|
+
strength?: string | undefined;
|
|
217
|
+
is_human?: boolean | undefined;
|
|
218
|
+
is_clinical?: boolean | undefined;
|
|
219
|
+
excerpt?: string | undefined;
|
|
220
|
+
metadata?: Record<string, unknown> | undefined;
|
|
221
|
+
regulatory_reference?: {
|
|
222
|
+
document: string;
|
|
223
|
+
section?: string | undefined;
|
|
224
|
+
doc_id?: string | undefined;
|
|
225
|
+
doc_url?: string | undefined;
|
|
226
|
+
} | undefined;
|
|
227
|
+
}[];
|
|
228
|
+
} | {
|
|
229
|
+
state: "unknown";
|
|
230
|
+
reason: string;
|
|
231
|
+
};
|
|
198
232
|
target_class?: string | undefined;
|
|
199
233
|
metadata?: {
|
|
200
234
|
merged_chembl_ids?: string[] | undefined;
|
|
@@ -205,7 +239,7 @@ export declare function aggregateOffTargetPanel(phase2: Phase2Bundle, fanout: Fa
|
|
|
205
239
|
off_target_name: string;
|
|
206
240
|
pchembl: number;
|
|
207
241
|
is_safety_panel_target: boolean;
|
|
208
|
-
organ_system:
|
|
242
|
+
organ_system: "hematologic" | "metabolic" | "immune" | "hepatic" | "musculoskeletal" | "cns" | "renal" | "reproductive" | "respiratory" | "cardiac" | "vascular" | "pns" | "gi" | "pancreas" | "endocrine_thyroid" | "dermatologic" | "ocular" | "oncology" | null;
|
|
209
243
|
clinical_consequence: string | null;
|
|
210
244
|
selectivity: {
|
|
211
245
|
vs_primary_potency: {
|
|
@@ -219,10 +253,13 @@ export declare function aggregateOffTargetPanel(phase2: Phase2Bundle, fanout: Fa
|
|
|
219
253
|
reason: string;
|
|
220
254
|
};
|
|
221
255
|
selectivity_window_below_threshold: boolean;
|
|
256
|
+
relationship: "intended_co_target" | "on_target_self_hit" | "obligate_cofactor";
|
|
257
|
+
reason: string;
|
|
222
258
|
evidence: {
|
|
223
259
|
source: string;
|
|
224
260
|
pmid?: string | undefined;
|
|
225
261
|
doi?: string | undefined;
|
|
262
|
+
accession?: string | undefined;
|
|
226
263
|
predicate?: string | undefined;
|
|
227
264
|
score?: number | undefined;
|
|
228
265
|
strength?: string | undefined;
|
|
@@ -237,8 +274,6 @@ export declare function aggregateOffTargetPanel(phase2: Phase2Bundle, fanout: Fa
|
|
|
237
274
|
doc_url?: string | undefined;
|
|
238
275
|
} | undefined;
|
|
239
276
|
}[];
|
|
240
|
-
relationship: "intended_co_target" | "on_target_self_hit" | "obligate_cofactor";
|
|
241
|
-
reason: string;
|
|
242
277
|
target_class?: string | undefined;
|
|
243
278
|
metadata?: {
|
|
244
279
|
merged_chembl_ids?: string[] | undefined;
|
|
@@ -270,7 +305,7 @@ export declare function computeClassPrecedentCounts(drugs: ClassDrug[]): {
|
|
|
270
305
|
export declare function aggregateClassPrecedent(phase2: Phase2Bundle, fanout: FanoutResults | undefined): {
|
|
271
306
|
drugs_in_class: ClassDrug[];
|
|
272
307
|
per_organ: {
|
|
273
|
-
organ:
|
|
308
|
+
organ: "hematologic" | "metabolic" | "immune" | "hepatic" | "musculoskeletal" | "cns" | "renal" | "reproductive" | "respiratory" | "cardiac" | "vascular" | "pns" | "gi" | "pancreas" | "endocrine_thyroid" | "dermatologic" | "ocular" | "oncology";
|
|
274
309
|
drug_count_in_class: number;
|
|
275
310
|
drugs_with_signal: number;
|
|
276
311
|
signal_fraction: number;
|
|
@@ -283,7 +318,7 @@ export declare function aggregateClassPrecedent(phase2: Phase2Bundle, fanout: Fa
|
|
|
283
318
|
}[];
|
|
284
319
|
} | null;
|
|
285
320
|
export declare function buildOrganRollup(faers: ReturnType<typeof aggregateFaersAcrossModulators>, trialAes: ReturnType<typeof aggregateTrialAes>, offTarget: OffTargetPanelRows | null, classP: ReturnType<typeof aggregateClassPrecedent>, regulatoryActions?: RegulatoryActionRow[] | null): {
|
|
286
|
-
organ:
|
|
321
|
+
organ: "hematologic" | "metabolic" | "immune" | "hepatic" | "musculoskeletal" | "cns" | "renal" | "reproductive" | "respiratory" | "cardiac" | "vascular" | "pns" | "gi" | "pancreas" | "endocrine_thyroid" | "dermatologic" | "ocular" | "oncology";
|
|
287
322
|
risk_level: "high" | "medium" | "low";
|
|
288
323
|
signal_type_count: number;
|
|
289
324
|
signals: {
|
|
@@ -296,6 +331,7 @@ export declare function buildOrganRollup(faers: ReturnType<typeof aggregateFaers
|
|
|
296
331
|
source: string;
|
|
297
332
|
pmid?: string | undefined;
|
|
298
333
|
doi?: string | undefined;
|
|
334
|
+
accession?: string | undefined;
|
|
299
335
|
predicate?: string | undefined;
|
|
300
336
|
score?: number | undefined;
|
|
301
337
|
strength?: string | undefined;
|
|
@@ -311,20 +347,6 @@ export declare function buildOrganRollup(faers: ReturnType<typeof aggregateFaers
|
|
|
311
347
|
} | undefined;
|
|
312
348
|
}[];
|
|
313
349
|
}[] | null;
|
|
314
|
-
/**
|
|
315
|
-
* Testable wrapper around `buildOrganRollup` that accepts named parameters.
|
|
316
|
-
* Exported for unit tests; production code calls `buildOrganRollup` directly
|
|
317
|
-
* inside `assembleDossier`.
|
|
318
|
-
*/
|
|
319
|
-
export declare function assembleOrganRollupRows(opts: {
|
|
320
|
-
classPrecedent?: ReturnType<typeof aggregateClassPrecedent> | null;
|
|
321
|
-
regulatoryActions?: {
|
|
322
|
-
coverage: string;
|
|
323
|
-
data?: {
|
|
324
|
-
rows: RegulatoryActionRow[];
|
|
325
|
-
};
|
|
326
|
-
} | null;
|
|
327
|
-
}): ReturnType<typeof buildOrganRollup> extends null ? never[] : NonNullable<ReturnType<typeof buildOrganRollup>>;
|
|
328
350
|
export declare function assembleDrugInteractions(phase2: Phase2Bundle, enrichedModulators?: ChemblModulator[]): {
|
|
329
351
|
drug_id: string;
|
|
330
352
|
drug_name: string;
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
* than fabricated. Aggregate rows preserve their contributing evidence
|
|
9
9
|
* under `evidence: [...]` arrays.
|
|
10
10
|
*/
|
|
11
|
+
import { ORGAN_RESOLUTION_FILTER } from "../lib/fda-label-safety.js";
|
|
12
|
+
import { ORGAN_SYSTEMS } from "../../../contracts/organ-system.js";
|
|
11
13
|
import { expectedOrgansFromBody } from "../lib/compute-derived.js";
|
|
12
14
|
import { inferTherapeuticArea } from "../../../tools/lib/clinical-benchmarks-client.js";
|
|
13
15
|
import { SafetyPanelFileSchema } from "../../../data/safety-panel-schema.js";
|
|
@@ -17,7 +19,7 @@ import { isIntendedCoTarget } from "../lib/intended-polypharm-filter.js";
|
|
|
17
19
|
import { makeHeterodimerOfAssessmentFilter } from "../lib/heterodimer-filter.js";
|
|
18
20
|
import { buildFamilyComplexSupplement } from "../lib/family-complex-supplement.js";
|
|
19
21
|
import { computeSelectivity } from "../lib/compute-selectivity.js";
|
|
20
|
-
import { classifyOrgan,
|
|
22
|
+
import { classifyOrgan, classifyTrialAe } from "../lib/meddra-organ-map.js";
|
|
21
23
|
import { HIGH_EXPRESSION_TPM_THRESHOLD, CNS_REGION_TPM_FLOOR, MUSCULOSKELETAL_TPM_FLOOR } from "../lib/expression-constants.js";
|
|
22
24
|
export { HIGH_EXPRESSION_TPM_THRESHOLD };
|
|
23
25
|
// ── Safety panel lookup ─────────────────────────────────────────────
|
|
@@ -71,6 +73,54 @@ export const SAFETY_RELEVANT_ORGANS = new Set([
|
|
|
71
73
|
"femur",
|
|
72
74
|
"vertebra",
|
|
73
75
|
]);
|
|
76
|
+
/**
|
|
77
|
+
* Anatomical tissue and organ labels from the expression atlases onto the
|
|
78
|
+
* canonical organ vocabulary. Longest keys first so "bone marrow" is read as
|
|
79
|
+
* haematopoietic tissue rather than as skeleton.
|
|
80
|
+
*/
|
|
81
|
+
const TISSUE_ORGAN_SYSTEMS = [
|
|
82
|
+
["bone marrow", "hematologic"],
|
|
83
|
+
["lymph node", "immune"],
|
|
84
|
+
["seminal vesicle", "reproductive"],
|
|
85
|
+
["fallopian tube", "reproductive"],
|
|
86
|
+
["endometrium", "reproductive"],
|
|
87
|
+
["epididymis", "reproductive"],
|
|
88
|
+
["placenta", "reproductive"],
|
|
89
|
+
["prostate", "reproductive"],
|
|
90
|
+
["intestine", "gi"],
|
|
91
|
+
["vertebra", "musculoskeletal"],
|
|
92
|
+
["stomach", "gi"],
|
|
93
|
+
["thyroid", "endocrine_thyroid"],
|
|
94
|
+
["pancreas", "pancreas"],
|
|
95
|
+
["spleen", "immune"],
|
|
96
|
+
["retina", "ocular"],
|
|
97
|
+
["kidney", "renal"],
|
|
98
|
+
["uterus", "reproductive"],
|
|
99
|
+
["testis", "reproductive"],
|
|
100
|
+
["gonad", "reproductive"],
|
|
101
|
+
["ovary", "reproductive"],
|
|
102
|
+
["heart", "cardiac"],
|
|
103
|
+
["liver", "hepatic"],
|
|
104
|
+
["brain", "cns"],
|
|
105
|
+
["femur", "musculoskeletal"],
|
|
106
|
+
["tibia", "musculoskeletal"],
|
|
107
|
+
["lung", "respiratory"],
|
|
108
|
+
["bone", "musculoskeletal"],
|
|
109
|
+
];
|
|
110
|
+
/**
|
|
111
|
+
* Resolve a tissue (and its atlas organ label, when present) onto the
|
|
112
|
+
* canonical organ vocabulary. Returns null when the anatomy has no organ
|
|
113
|
+
* system to belong to — the caller drops the row rather than filing it
|
|
114
|
+
* under a neighbouring organ.
|
|
115
|
+
*/
|
|
116
|
+
export function resolveTissueOrganSystem(tissue, organ) {
|
|
117
|
+
const haystack = `${tissue} ${organ ?? ""}`.toLowerCase();
|
|
118
|
+
for (const [label, system] of TISSUE_ORGAN_SYSTEMS) {
|
|
119
|
+
if (haystack.includes(label))
|
|
120
|
+
return system;
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
74
124
|
export function isSafetyRelevant(tissue, organ) {
|
|
75
125
|
const t = tissue.toLowerCase();
|
|
76
126
|
const o = (organ ?? "").toLowerCase();
|
|
@@ -160,22 +210,6 @@ export function meetsTpmFloor(tissue, value) {
|
|
|
160
210
|
}
|
|
161
211
|
return value > DEFAULT_TPM_FLOOR;
|
|
162
212
|
}
|
|
163
|
-
const CANONICAL_ORGANS = [
|
|
164
|
-
"cardiac",
|
|
165
|
-
"hepatic",
|
|
166
|
-
"cns",
|
|
167
|
-
"renal",
|
|
168
|
-
"gi",
|
|
169
|
-
"pancreas",
|
|
170
|
-
"endocrine_thyroid",
|
|
171
|
-
"metabolic",
|
|
172
|
-
"hematologic",
|
|
173
|
-
"immune",
|
|
174
|
-
"respiratory",
|
|
175
|
-
"reproductive",
|
|
176
|
-
"dermatologic",
|
|
177
|
-
"musculoskeletal",
|
|
178
|
-
];
|
|
179
213
|
// ── Liability summary ───────────────────────────────────────────────
|
|
180
214
|
export function assembleLiabilitySummary(phase2, context) {
|
|
181
215
|
const ot = phase2.phase1.collectors.opentargets;
|
|
@@ -381,6 +415,53 @@ const SENTINEL_OFF_TARGET_NAMES = new Set(["unchecked", "unknown", "n/a"]);
|
|
|
381
415
|
* biological targets. Filtered out before panel assembly.
|
|
382
416
|
*/
|
|
383
417
|
const CELL_LINE_NAME_PATTERNS = /\b(hek293|hek-293|cho|hela|3t3|293t|293|jurkat|raw264|raw\s*264|cos-7|cos7|mcf-7|mcf7|pc-3|pc3|lncap|a549|u2os|ht-29|ht29|sk-ov-3|skov3|t47d|mda-mb|nih3t3)\b/i;
|
|
418
|
+
/**
|
|
419
|
+
* Partition evidence into what a claim can stand on: an item resolves to a
|
|
420
|
+
* record a reader can check, or it does not. A claim with nothing checkable
|
|
421
|
+
* says so rather than presenting provenance labels as citations.
|
|
422
|
+
*/
|
|
423
|
+
export function claimSupportFrom(evidence, reasonWhenUnsupported) {
|
|
424
|
+
const locatable = evidence.filter((e) => Boolean(e.pmid ?? e.doi ?? e.accession ?? e.regulatory_reference));
|
|
425
|
+
if (locatable.length === 0)
|
|
426
|
+
return { state: "unknown", reason: reasonWhenUnsupported };
|
|
427
|
+
return { state: "scored", evidence: locatable };
|
|
428
|
+
}
|
|
429
|
+
/** The evidence behind a claim, or nothing when the claim states it has none. */
|
|
430
|
+
export function claimSupportEvidence(support) {
|
|
431
|
+
return support.state === "scored" ? support.evidence : [];
|
|
432
|
+
}
|
|
433
|
+
// ── Per-organ regulatory signals ────────────────────────────────────
|
|
434
|
+
/**
|
|
435
|
+
* Turn segmented FDA label warnings into the dossier's per-organ regulatory
|
|
436
|
+
* signal section.
|
|
437
|
+
*
|
|
438
|
+
* The organ-resolution filter can legitimately empty this section: a set of
|
|
439
|
+
* labels whose every warning fragment names no canonical organ produces no
|
|
440
|
+
* rows. That is `filtered` with the count it discarded, never an `available`
|
|
441
|
+
* section with an empty list — the difference is whether a reader learns that
|
|
442
|
+
* signals existed and did not survive attribution.
|
|
443
|
+
*/
|
|
444
|
+
export function assembleRegulatoryOrganSignals(projection) {
|
|
445
|
+
if (projection === null) {
|
|
446
|
+
return { coverage: "not_loaded", reason: "no indication resolved, so no FDA label was queried" };
|
|
447
|
+
}
|
|
448
|
+
const rows = projection.signals.map((s) => ({
|
|
449
|
+
organ: s.organ,
|
|
450
|
+
drug_name: s.drug_name,
|
|
451
|
+
agency: "FDA",
|
|
452
|
+
application_number: s.application_number,
|
|
453
|
+
label_section: s.label_section,
|
|
454
|
+
excerpt: s.excerpt,
|
|
455
|
+
support: claimSupportFrom([s.evidence], `the ${s.label_section} warning for ${s.drug_name} carries no citable label reference`),
|
|
456
|
+
}));
|
|
457
|
+
if (rows.length === 0) {
|
|
458
|
+
if (projection.dropped_count > 0) {
|
|
459
|
+
return { coverage: "filtered", filter: ORGAN_RESOLUTION_FILTER, dropped_count: projection.dropped_count };
|
|
460
|
+
}
|
|
461
|
+
return { coverage: "queried_no_data", error: { message: "the FDA label query returned no attributable warning prose" } };
|
|
462
|
+
}
|
|
463
|
+
return { coverage: "available", data: { rows }, dropped_count: projection.dropped_count };
|
|
464
|
+
}
|
|
384
465
|
/**
|
|
385
466
|
* Filter and deduplicate raw off-target rows before panel assembly.
|
|
386
467
|
*
|
|
@@ -444,7 +525,7 @@ export function filterAndDedupOffTargetRows(rows, ctx) {
|
|
|
444
525
|
}
|
|
445
526
|
// ── Off-target panel assembly ───────────────────────────────────────
|
|
446
527
|
/**
|
|
447
|
-
*
|
|
528
|
+
* Off-target panel row split. Each clean off-target row is classified as:
|
|
448
529
|
* - `on_target_self_hit`: alternate ChEMBL ID for the assessment target itself
|
|
449
530
|
* - `intended_co_target`: every modulator that hits this target intends it
|
|
450
531
|
* (e.g., GLP1R + GIPR for tirzepatide); not an off-target liability
|
|
@@ -486,10 +567,10 @@ export function aggregateOffTargetPanel(phase2, fanout, assessmentUniprot, asses
|
|
|
486
567
|
name: hit.targetName ?? hit.targetChemblId,
|
|
487
568
|
pchembl: pch,
|
|
488
569
|
modulatorPrimaryPchembl: primaryPchemblByModulator.get(item.data.moleculeChemblId) ?? null,
|
|
489
|
-
|
|
570
|
+
assayByModulator: cur?.assayByModulator ?? new Map(),
|
|
490
571
|
});
|
|
491
572
|
}
|
|
492
|
-
byTarget.get(hit.targetChemblId).
|
|
573
|
+
byTarget.get(hit.targetChemblId).assayByModulator.set(item.data.moleculeChemblId, hit.assayChemblId);
|
|
493
574
|
}
|
|
494
575
|
}
|
|
495
576
|
// Map off-target ChEMBL ID → primaryPchembl of the winner modulator so the
|
|
@@ -519,9 +600,15 @@ export function aggregateOffTargetPanel(phase2, fanout, assessmentUniprot, asses
|
|
|
519
600
|
clinical_consequence: safetyHit?.clinical_consequence ?? null,
|
|
520
601
|
selectivity: { log_units: 0, fold: 1 },
|
|
521
602
|
selectivity_window_below_threshold: false,
|
|
522
|
-
modulators: [...v.
|
|
523
|
-
|
|
603
|
+
modulators: [...v.assayByModulator.keys()],
|
|
604
|
+
// The locator is the assay the binding was measured in — the
|
|
605
|
+
// record a reader can open to check the asserted activity. The
|
|
606
|
+
// off-target's own ChEMBL id names the protein, not the
|
|
607
|
+
// measurement, so an activity ChEMBL did not attribute to an
|
|
608
|
+
// assay carries no locator and the claim states it has none.
|
|
609
|
+
evidence: [...v.assayByModulator].map(([m, assayChemblId]) => ({
|
|
524
610
|
source: "chembl:polypharm",
|
|
611
|
+
...(assayChemblId ? { accession: assayChemblId } : {}),
|
|
525
612
|
predicate: "binds",
|
|
526
613
|
score: v.pchembl,
|
|
527
614
|
metadata: { off_target_id: v.chemblId, modulator: m },
|
|
@@ -529,7 +616,7 @@ export function aggregateOffTargetPanel(phase2, fanout, assessmentUniprot, asses
|
|
|
529
616
|
};
|
|
530
617
|
})
|
|
531
618
|
.filter((r) => r !== null);
|
|
532
|
-
// Preserve modulator membership across dedup so the
|
|
619
|
+
// Preserve modulator membership across dedup so the relationship
|
|
533
620
|
// classifier (intended co-target / on-target self-hit) can see which
|
|
534
621
|
// molecules actually hit each off-target.
|
|
535
622
|
const modulatorsByKey = new Map();
|
|
@@ -549,7 +636,7 @@ export function aggregateOffTargetPanel(phase2, fanout, assessmentUniprot, asses
|
|
|
549
636
|
}
|
|
550
637
|
return b.pchembl - a.pchembl;
|
|
551
638
|
});
|
|
552
|
-
// Helper: project a clean row onto the
|
|
639
|
+
// Helper: project a clean row onto the shared body shape (no relationship yet).
|
|
553
640
|
const toBaseRow = (r) => ({
|
|
554
641
|
off_target_id: r.off_target_id,
|
|
555
642
|
off_target_name: r.off_target_name,
|
|
@@ -558,7 +645,6 @@ export function aggregateOffTargetPanel(phase2, fanout, assessmentUniprot, asses
|
|
|
558
645
|
is_safety_panel_target: r.is_safety_panel_target,
|
|
559
646
|
organ_system: r.organ_system,
|
|
560
647
|
clinical_consequence: r.clinical_consequence,
|
|
561
|
-
evidence: r.evidence,
|
|
562
648
|
metadata: r.metadata,
|
|
563
649
|
});
|
|
564
650
|
const rows = [];
|
|
@@ -573,6 +659,7 @@ export function aggregateOffTargetPanel(phase2, fanout, assessmentUniprot, asses
|
|
|
573
659
|
if (assessmentGeneSymbol && isHeterodimer(r.off_target_name)) {
|
|
574
660
|
excludedRows.push({
|
|
575
661
|
...base,
|
|
662
|
+
evidence: r.evidence,
|
|
576
663
|
relationship: "obligate_cofactor",
|
|
577
664
|
reason: `${r.off_target_name} is ${assessmentGeneSymbol} heterodimerised with a different obligate cofactor; selectivity is not pharmacologically attainable.`,
|
|
578
665
|
selectivity: { selectivity_unknown: true, reason: "obligate cofactor (same protein, different RAMP/accessory)" },
|
|
@@ -584,6 +671,7 @@ export function aggregateOffTargetPanel(phase2, fanout, assessmentUniprot, asses
|
|
|
584
671
|
if (r.off_target_id && assessmentUniprot && isOnTargetChemblId(r.off_target_id, onTargetChemblIds)) {
|
|
585
672
|
excludedRows.push({
|
|
586
673
|
...base,
|
|
674
|
+
evidence: r.evidence,
|
|
587
675
|
relationship: "on_target_self_hit",
|
|
588
676
|
reason: `${r.off_target_id} is an alternate ChEMBL ID for the on-target`,
|
|
589
677
|
selectivity: { selectivity_unknown: true, reason: "on-target self-hit" },
|
|
@@ -597,6 +685,7 @@ export function aggregateOffTargetPanel(phase2, fanout, assessmentUniprot, asses
|
|
|
597
685
|
if (modulators.length > 0 && intendedHits.length === modulators.length) {
|
|
598
686
|
excludedRows.push({
|
|
599
687
|
...base,
|
|
688
|
+
evidence: r.evidence,
|
|
600
689
|
relationship: "intended_co_target",
|
|
601
690
|
reason: intendedHits[0].hit.reason,
|
|
602
691
|
selectivity: { selectivity_unknown: true, reason: "intended co-target" },
|
|
@@ -619,6 +708,7 @@ export function aggregateOffTargetPanel(phase2, fanout, assessmentUniprot, asses
|
|
|
619
708
|
relationship: "off_target",
|
|
620
709
|
selectivity,
|
|
621
710
|
selectivity_window_below_threshold: below,
|
|
711
|
+
support: claimSupportFrom(r.evidence, `${r.off_target_name} was surfaced by ChEMBL polypharmacology with no citable binding record`),
|
|
622
712
|
});
|
|
623
713
|
}
|
|
624
714
|
// Append the IUPHAR-driven obligate-cofactor supplement for receptor-
|
|
@@ -778,13 +868,15 @@ const MALIGNANCY_RE = /malignan|cancer|carcinoma|neoplasm/i;
|
|
|
778
868
|
export function buildOrganRollup(faers, trialAes, offTarget, classP, regulatoryActions) {
|
|
779
869
|
if (!faers && !trialAes && !offTarget && !classP && !regulatoryActions?.length)
|
|
780
870
|
return null;
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
871
|
+
// The rollup walks the canonical vocabulary itself, so the organs it can
|
|
872
|
+
// emit, the organs `expectedOrgansFromBody` can expect, and the organs a
|
|
873
|
+
// producer can attribute are one set. A row with no signal is dropped
|
|
874
|
+
// below, so widening the vocabulary widens the rollup rather than opening
|
|
875
|
+
// a gap between expected and present organs.
|
|
876
|
+
const rows = ORGAN_SYSTEMS.map((organ) => {
|
|
877
|
+
// off_target_panel.organ_system is a canonical token, so the match is
|
|
878
|
+
// equality on the vocabulary rather than a comparison of prose.
|
|
879
|
+
const polypharmHits = (offTarget ?? []).filter((r) => r.organ_system === organ);
|
|
788
880
|
const polypharmCount = polypharmHits.length;
|
|
789
881
|
const faersHits = (faers?.top_signals ?? []).filter((s) => s.organ === organ);
|
|
790
882
|
const faersCount = faersHits.length;
|
|
@@ -894,7 +986,7 @@ export function buildOrganRollup(faers, trialAes, offTarget, classP, regulatoryA
|
|
|
894
986
|
}
|
|
895
987
|
// Oncology synthesis: when regulatory_actions carries malignancy-keyword
|
|
896
988
|
// findings, emit an oncology rollup row. This is ADDITIVE — it does not
|
|
897
|
-
// replace any row produced by the
|
|
989
|
+
// replace any row produced by the vocabulary loop above.
|
|
898
990
|
if (!presentOrgans.has("oncology") && regulatoryActions?.length) {
|
|
899
991
|
const malignancyRows = regulatoryActions.filter((r) => MALIGNANCY_RE.test(r.finding));
|
|
900
992
|
if (malignancyRows.length > 0) {
|
|
@@ -923,15 +1015,6 @@ export function buildOrganRollup(faers, trialAes, offTarget, classP, regulatoryA
|
|
|
923
1015
|
}
|
|
924
1016
|
return filtered;
|
|
925
1017
|
}
|
|
926
|
-
/**
|
|
927
|
-
* Testable wrapper around `buildOrganRollup` that accepts named parameters.
|
|
928
|
-
* Exported for unit tests; production code calls `buildOrganRollup` directly
|
|
929
|
-
* inside `assembleDossier`.
|
|
930
|
-
*/
|
|
931
|
-
export function assembleOrganRollupRows(opts) {
|
|
932
|
-
const regRows = opts.regulatoryActions?.coverage === "available" ? (opts.regulatoryActions.data?.rows ?? null) : null;
|
|
933
|
-
return buildOrganRollup(null, null, null, opts.classPrecedent ?? null, regRows) ?? [];
|
|
934
|
-
}
|
|
935
1018
|
// ── §2.4 Drug Interactions ──────────────────────────────────────────
|
|
936
1019
|
export function assembleDrugInteractions(phase2, enrichedModulators) {
|
|
937
1020
|
const mods = phase2.phase1.collectors.chemblModulators;
|
|
@@ -24,7 +24,7 @@ export interface CollectorCtx {
|
|
|
24
24
|
readonly ncbiApiKey?: string;
|
|
25
25
|
}
|
|
26
26
|
import type { SerializedError } from "../coverage.js";
|
|
27
|
-
import type { CbioportalBundle, ChemblModulatorsBundle, ClinvarBundle, CtgovBundle, ExpressionHumanBundle, ExpressionMultiSpeciesBundle, FaersByTargetBundle, FamilyComplexesBundle, ImpcBundle, OpenTargetsBundle, PathwaysBundle, PubmedIndexBundle, ResolvedTarget, StringPpiBundle, TherapeuticProgramsBundle } from "../schemas.js";
|
|
27
|
+
import type { CbioportalBundle, ChemblModulatorsBundle, ClinvarBundle, CtgovBundle, ExpressionHumanBundle, ExpressionMultiSpeciesBundle, FaersByTargetBundle, FamilyComplexesBundle, ImpcBundle, MonarchBundle, OpenTargetsBundle, PathwaysBundle, PubmedIndexBundle, ResolvedTarget, StringPpiBundle, TherapeuticProgramsBundle } from "../schemas.js";
|
|
28
28
|
type CoverageAvailable<T> = {
|
|
29
29
|
coverage: "available";
|
|
30
30
|
data: T;
|
|
@@ -47,6 +47,7 @@ export declare function collectExpressionMultiSpecies(input: ResolvedTarget): Pr
|
|
|
47
47
|
export declare function collectFaersByTarget(input: ResolvedTarget): Promise<CoverageEnvelope<FaersByTargetBundle>>;
|
|
48
48
|
export declare function collectFamilyComplexes(input: ResolvedTarget): Promise<CoverageEnvelope<FamilyComplexesBundle>>;
|
|
49
49
|
export declare function collectImpc(input: ResolvedTarget): Promise<CoverageEnvelope<ImpcBundle>>;
|
|
50
|
+
export declare function collectMonarch(input: ResolvedTarget): Promise<CoverageEnvelope<MonarchBundle>>;
|
|
50
51
|
export declare function collectOpenTargets(input: ResolvedTarget): Promise<CoverageEnvelope<OpenTargetsBundle>>;
|
|
51
52
|
export declare function collectPathways(input: ResolvedTarget): Promise<CoverageEnvelope<PathwaysBundle>>;
|
|
52
53
|
export declare function collectPubmedIndex(input: ResolvedTarget, ctx: CollectorCtx): Promise<CoverageEnvelope<PubmedIndexBundle>>;
|
|
@@ -85,6 +86,9 @@ export declare const COLLECTOR_MANIFEST: readonly [{
|
|
|
85
86
|
}, {
|
|
86
87
|
readonly id: "impc";
|
|
87
88
|
readonly run: typeof collectImpc;
|
|
89
|
+
}, {
|
|
90
|
+
readonly id: "monarch";
|
|
91
|
+
readonly run: typeof collectMonarch;
|
|
88
92
|
}, {
|
|
89
93
|
readonly id: "opentargets";
|
|
90
94
|
readonly run: typeof collectOpenTargets;
|
|
@@ -101,5 +105,4 @@ export declare const COLLECTOR_MANIFEST: readonly [{
|
|
|
101
105
|
readonly id: "therapeutic-programs";
|
|
102
106
|
readonly run: typeof collectTherapeuticPrograms;
|
|
103
107
|
}];
|
|
104
|
-
export type CollectorId = (typeof COLLECTOR_MANIFEST)[number]["id"];
|
|
105
108
|
export {};
|