@inflexa-ai/harness 0.17.0 → 0.19.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/agents/report-session-agent.d.ts +56 -0
- package/dist/agents/report-session-agent.js +72 -0
- package/dist/app/report-session-runtime.d.ts +72 -0
- package/dist/app/report-session-runtime.js +157 -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/memory/thread-store.d.ts +4 -4
- package/dist/memory/thread-store.js +18 -9
- package/dist/prompts/report-session.d.ts +1 -0
- package/dist/prompts/report-session.js +89 -0
- 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/providers/ai-sdk.d.ts +77 -0
- package/dist/providers/ai-sdk.js +149 -19
- package/dist/providers/errors.d.ts +14 -0
- package/dist/providers/errors.js +103 -18
- package/dist/providers/types.d.ts +16 -0
- package/dist/providers/types.js +10 -1
- 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/pin-snapshot.d.ts +30 -0
- package/dist/report-model/pin-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 +72 -0
- package/dist/report-model/validate.js +95 -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/value-bridge.d.ts +62 -0
- package/dist/report-render/value-bridge.js +82 -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/assemble.d.ts +15 -0
- package/dist/runtime/assemble.js +28 -6
- 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 +54 -0
- package/dist/state/purge-analysis.js +2 -0
- package/dist/state/report-session-state.d.ts +112 -0
- package/dist/state/report-session-state.js +150 -0
- package/dist/state/report-versions.d.ts +129 -0
- package/dist/state/report-versions.js +167 -0
- package/dist/state/snapshot-parse.d.ts +34 -0
- package/dist/state/snapshot-parse.js +82 -0
- package/dist/tasks/data-profile.js +1 -0
- package/dist/tools/ad-hoc-router.d.ts +7 -2
- package/dist/tools/ad-hoc-router.js +2 -1
- 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 +241 -0
- package/dist/tools/report-authoring/authoring-tools.js +460 -0
- package/dist/tools/report-session/index.d.ts +8 -0
- package/dist/tools/report-session/index.js +8 -0
- package/dist/tools/report-session/preview-report.d.ts +90 -0
- package/dist/tools/report-session/preview-report.js +245 -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 +7 -2
- 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
|
@@ -2,28 +2,46 @@
|
|
|
2
2
|
* Phase-4 deterministic assemblers.
|
|
3
3
|
*
|
|
4
4
|
* Each assembler maps Phase-1 / Phase-2 / Phase-3 outputs onto the
|
|
5
|
-
* corresponding dossier section schema. Coverage is honored end-to-end:
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* corresponding dossier section schema. Coverage is honored end-to-end: an
|
|
6
|
+
* upstream that came back empty or was never consulted yields
|
|
7
|
+
* `queried_no_data` / `not_loaded` rather than a fabricated section.
|
|
8
|
+
*
|
|
9
|
+
* Where a section applies a threshold of its own, the decision runs through
|
|
10
|
+
* `coverageFromFilteredRows` over both counts — what survived and what the
|
|
11
|
+
* threshold discarded — so a section our own filter emptied reports
|
|
12
|
+
* `filtered` rather than an `available` section holding nothing. Deciding
|
|
13
|
+
* coverage first and filtering the payload afterwards is the shape that loses
|
|
14
|
+
* that distinction.
|
|
15
|
+
*
|
|
16
|
+
* Aggregate rows preserve their contributing evidence under `evidence: [...]`
|
|
17
|
+
* arrays.
|
|
10
18
|
*/
|
|
19
|
+
import { classifyClinicalEvidenceTrial, } from "../lib/clinical-evidence-attribution.js";
|
|
11
20
|
import { inferTherapeuticArea, getBenchmarks, getDatasetAttribution } from "../../../tools/lib/clinical-benchmarks-client.js";
|
|
12
21
|
import { inferModalityFromFamily } from "../../../tools/lib/protein-family-modality.js";
|
|
13
22
|
import { resolveFamilySiblingUniprots, resolveOnTargetChemblIds } from "../lib/target-identity-filter.js";
|
|
14
23
|
import { getDrugPrimaryTargetUniprots } from "../../../tools/lib/chembl-client.js";
|
|
15
24
|
import { annotateOffTargetPanel } from "../lib/clinical-consequence-annotator.js";
|
|
16
|
-
import { coverageFromRows } from "../coverage.js";
|
|
25
|
+
import { coverageFromFilteredRows, coverageFromRows } from "../coverage.js";
|
|
26
|
+
import { toOrganSystems } from "../lib/impc-organ-map.js";
|
|
17
27
|
import { fetchRegulatoryActions } from "../lib/regulatory-actions.js";
|
|
18
28
|
import { HIGH_EXPRESSION_TPM_THRESHOLD } from "../lib/expression-constants.js";
|
|
19
29
|
export { HIGH_EXPRESSION_TPM_THRESHOLD };
|
|
20
30
|
import { resolveModulatorMoleculeType } from "../lib/dedup-modulators.js";
|
|
21
31
|
import { searchFailedTrialsForDrugNames } from "../../../tools/lib/clinical-trials-client.js";
|
|
22
|
-
import { aggregateFaersAcrossModulators, aggregateTrialAes, aggregateOffTargetPanel, aggregateClassPrecedent, buildOrganRollup, assembleDrugInteractions, assembleLiabilitySummary, meetsTpmFloor, isSafetyRelevant, } from "./safety.js";
|
|
32
|
+
import { aggregateFaersAcrossModulators, aggregateTrialAes, aggregateOffTargetPanel, aggregateClassPrecedent, buildOrganRollup, assembleDrugInteractions, assembleLiabilitySummary, claimSupportEvidence, meetsTpmFloor, isSafetyRelevant, resolveTissueOrganSystem, } from "./safety.js";
|
|
23
33
|
import { assemblePreclinicalLiterature, assembleKoSupportingLiterature, tallyInternalReferences, assembleKeyPapers, assembleEvidenceTimeline, assembleTranslationalChain, assembleMolecularInteractions, assembleBiomarkerPotential, assembleResistanceEvidence, assembleCombinationEvidence, assembleEvidenceConflicts, assembleAdditionalEvidence, isSelfReference, isClinicalMeasurement, indicationCompositeScore, partitionTrialsByAttribution, classifyClinicalTrialConfidence, assembleDiscoveryTrials, dedupePpiPartners, } from "./literature.js";
|
|
24
34
|
import { buildTrialOutcomeFilter, aggregateTrialOutcomes } from "./trials.js";
|
|
25
35
|
import { buildFailureCategoryDiscriminated } from "./literature.js";
|
|
26
36
|
const NOT_LOADED_PHASE5 = "Phase 5 synthesis not yet implemented";
|
|
37
|
+
/** What emptied `clinical_development.trials` when nothing survived. */
|
|
38
|
+
const ACTIVE_TRIALS_FILTER = "text match confidence below medium, attribution not eligible for toxicology aggregation, or attributed to a related family receptor";
|
|
39
|
+
/** What emptied the two failed-trial sections when nothing survived. */
|
|
40
|
+
const FAILED_TRIALS_FILTER = "attribution not eligible for toxicology aggregation, or attributed to a related family receptor";
|
|
41
|
+
/** What emptied the two association sections when nothing survived. */
|
|
42
|
+
const INDICATIONS_FILTER = "association restates the target itself, names a clinical measurement rather than a disease, or carries no scored evidence source";
|
|
43
|
+
/** Sections the workflow body stamps between assembly and synthesis. */
|
|
44
|
+
const NOT_LOADED_POST_ASSEMBLY = "assembled after Phase 4, from the segmented regulatory label signals";
|
|
27
45
|
// Order matches evidence-priority rank: genetic > known_drug > animal_model > somatic > literature.
|
|
28
46
|
function makeAssociationEvidence(a) {
|
|
29
47
|
const out = [];
|
|
@@ -186,7 +204,7 @@ export function assembleTractability(resolved, ot, drugs) {
|
|
|
186
204
|
];
|
|
187
205
|
const preferred = t.smallMolecule ? "small_molecule" : t.antibody ? "antibody" : t.otherModalities ? "other_clinical" : null;
|
|
188
206
|
const modalitiesEnriched = enrichTractabilityModalitiesWithApprovals(modalities, drugs);
|
|
189
|
-
// Collect molecule types from approved/clinical drugs for the
|
|
207
|
+
// Collect molecule types from approved/clinical drugs for the tractability field.
|
|
190
208
|
const drugMoleculeTypes = [...new Set(drugs.map((d) => d.molecule_type).filter((m) => !!m))];
|
|
191
209
|
return {
|
|
192
210
|
coverage: "available",
|
|
@@ -241,7 +259,7 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
241
259
|
const internalRefCounts = tallyInternalReferences([
|
|
242
260
|
koSupportingLiterature,
|
|
243
261
|
...(organRollupRows ?? []).map((r) => r.evidence),
|
|
244
|
-
...(offTargetRows ?? []).map((r) => r.
|
|
262
|
+
...(offTargetRows ?? []).map((r) => claimSupportEvidence(r.support)),
|
|
245
263
|
]);
|
|
246
264
|
const keyPapersRows = assembleKeyPapers(phase2, internalRefCounts);
|
|
247
265
|
const evidenceTimeline = assembleEvidenceTimeline(phase2);
|
|
@@ -262,7 +280,6 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
262
280
|
// receptor rather than the assessment target.
|
|
263
281
|
const trialOutcomeFilter = await buildTrialOutcomeFilter(phase2, attrCtx, knownClassDrugNames, phase2.phase1.resolved.geneSymbol);
|
|
264
282
|
const trialOutcomesRows = aggregateTrialOutcomes(fanout, trialOutcomeFilter);
|
|
265
|
-
const discoveryTrialData = await assembleDiscoveryTrials(phase2, phase2.phase1.resolved.geneSymbol, attrCtx, knownClassDrugNames);
|
|
266
283
|
const resolved = phase2.phase1.resolved;
|
|
267
284
|
const ot = phase2.phase1.collectors.opentargets;
|
|
268
285
|
const ctgov = phase2.phase1.collectors.ctgov;
|
|
@@ -274,20 +291,99 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
274
291
|
const pubmed = phase2.phase1.collectors.pubmedIndex;
|
|
275
292
|
const pathways = phase2.phase1.collectors.pathways;
|
|
276
293
|
const ppi = phase2.phase1.collectors.stringPpi;
|
|
294
|
+
// Every trial row carries its attribution from assembly onward: the
|
|
295
|
+
// evidence role decides whether a row supports the target or is context.
|
|
296
|
+
const knownClassDrugs = await Promise.all((drugInteractionRows ?? []).map(async (d) => {
|
|
297
|
+
const resolvedTargets = d.drug_id ? await getDrugPrimaryTargetUniprots(d.drug_id).catch(() => []) : [];
|
|
298
|
+
return {
|
|
299
|
+
name: d.drug_name,
|
|
300
|
+
moleculeChemblId: d.drug_id,
|
|
301
|
+
targetUniprots: resolvedTargets.length > 0 ? resolvedTargets : assessmentUniprot ? [assessmentUniprot] : [],
|
|
302
|
+
};
|
|
303
|
+
}));
|
|
304
|
+
const programsCollector = phase2.phase1.collectors.therapeuticPrograms;
|
|
305
|
+
const therapeuticPrograms = programsCollector?.coverage === "available"
|
|
306
|
+
? programsCollector.data.programs.map((program) => ({
|
|
307
|
+
programId: program.programId,
|
|
308
|
+
name: program.name,
|
|
309
|
+
targetSymbol: program.targetSymbol,
|
|
310
|
+
targetUniprot: program.targetUniprot,
|
|
311
|
+
modality: program.modality,
|
|
312
|
+
nctIds: program.nctIds,
|
|
313
|
+
}))
|
|
314
|
+
: [];
|
|
315
|
+
const evidenceAttribution = {
|
|
316
|
+
assessmentSymbol: geneSymbol,
|
|
317
|
+
assessmentUniprot,
|
|
318
|
+
familyUniprots: familySiblingUniprots,
|
|
319
|
+
knownClassDrugs,
|
|
320
|
+
therapeuticPrograms,
|
|
321
|
+
};
|
|
322
|
+
const trialSourceByNct = new Map();
|
|
323
|
+
if (ctgov.coverage === "available") {
|
|
324
|
+
for (const t of [...ctgov.data.active, ...ctgov.data.failed])
|
|
325
|
+
trialSourceByNct.set(t.nctId, t);
|
|
326
|
+
}
|
|
327
|
+
const attachTrialAttribution = (row) => {
|
|
328
|
+
const source = trialSourceByNct.get(row.nct_id);
|
|
329
|
+
const classified = source
|
|
330
|
+
? classifyClinicalEvidenceTrial(source, evidenceAttribution)
|
|
331
|
+
: {
|
|
332
|
+
attribution: {
|
|
333
|
+
relationship: "unknown",
|
|
334
|
+
evidence_role: "excluded",
|
|
335
|
+
basis: [{ kind: "text_match", source: "ctgov" }],
|
|
336
|
+
resolved_interventions: [],
|
|
337
|
+
exclusion_reason: "no CT.gov record was available to attribute this trial to the assessed target",
|
|
338
|
+
},
|
|
339
|
+
eligible_for_toxicology_aggregation: false,
|
|
340
|
+
};
|
|
341
|
+
return {
|
|
342
|
+
...row,
|
|
343
|
+
attribution: classified.attribution,
|
|
344
|
+
eligible_for_toxicology_aggregation: classified.eligible_for_toxicology_aggregation,
|
|
345
|
+
};
|
|
346
|
+
};
|
|
347
|
+
const discoveryTrials = await assembleDiscoveryTrials(phase2, phase2.phase1.resolved.geneSymbol, attrCtx, knownClassDrugNames, attachTrialAttribution);
|
|
277
348
|
const indicationsRaw = ot.coverage === "available" ? ot.data.associations : [];
|
|
278
349
|
const filteredIndications = indicationsRaw.filter((a) => !isSelfReference(resolved.canonicalId, a.diseaseId, resolved.geneSymbol, a.diseaseName) && !isClinicalMeasurement(a.diseaseName));
|
|
279
350
|
const ta = inferTherapeuticArea(filteredIndications.map((a) => a.diseaseName));
|
|
280
351
|
const benchmarks = getBenchmarks(ta);
|
|
281
352
|
const datasetAttr = getDatasetAttribution();
|
|
282
|
-
const
|
|
283
|
-
? expression.data.tissues
|
|
284
|
-
.filter((t) => meetsTpmFloor(t.tissueLabel, t.value ?? 0) && isSafetyRelevant(t.tissueLabel, t.organSystem))
|
|
285
|
-
.map((t) => ({
|
|
286
|
-
tissue: t.tissueLabel,
|
|
287
|
-
organ: t.organSystem ?? "unspecified",
|
|
288
|
-
tpm: t.value ?? 0,
|
|
289
|
-
}))
|
|
353
|
+
const offTissueCandidates = expression.coverage === "available"
|
|
354
|
+
? expression.data.tissues.filter((t) => meetsTpmFloor(t.tissueLabel, t.value ?? 0) && isSafetyRelevant(t.tissueLabel, t.organSystem))
|
|
290
355
|
: [];
|
|
356
|
+
// A tissue whose anatomy does not resolve onto an organ system is dropped
|
|
357
|
+
// rather than filed under a neighbouring organ; the count is reported so
|
|
358
|
+
// the section does not overstate its own completeness.
|
|
359
|
+
const offTissueRows = offTissueCandidates.flatMap((t) => {
|
|
360
|
+
const organ = resolveTissueOrganSystem(t.tissueLabel, t.organSystem);
|
|
361
|
+
if (!organ)
|
|
362
|
+
return [];
|
|
363
|
+
const support = {
|
|
364
|
+
state: "unknown",
|
|
365
|
+
reason: `${t.tissueLabel} expression is a measured value from the expression atlas, not a citable per-tissue record`,
|
|
366
|
+
};
|
|
367
|
+
return [{ tissue: t.tissueLabel, organ, tpm: t.value ?? 0, support }];
|
|
368
|
+
});
|
|
369
|
+
const offTissueDroppedCount = offTissueCandidates.length - offTissueRows.length;
|
|
370
|
+
// Candidates that all failed to resolve leave the section empty for a
|
|
371
|
+
// reason of our own making, not because the atlas held nothing.
|
|
372
|
+
const offTissueSection = expression.coverage !== "available"
|
|
373
|
+
? { coverage: "queried_no_data" }
|
|
374
|
+
: offTissueRows.length > 0
|
|
375
|
+
? {
|
|
376
|
+
coverage: "available",
|
|
377
|
+
data: { rows: offTissueRows },
|
|
378
|
+
...(offTissueDroppedCount > 0 ? { dropped_count: offTissueDroppedCount } : {}),
|
|
379
|
+
}
|
|
380
|
+
: offTissueDroppedCount > 0
|
|
381
|
+
? {
|
|
382
|
+
coverage: "filtered",
|
|
383
|
+
filter: "tissue anatomy did not resolve onto an organ system",
|
|
384
|
+
dropped_count: offTissueDroppedCount,
|
|
385
|
+
}
|
|
386
|
+
: { coverage: "queried_no_data" };
|
|
291
387
|
const drugsForTractability = enrichedModulators.map((m) => ({
|
|
292
388
|
drug_id: m.moleculeChemblId,
|
|
293
389
|
drug_name: m.preferredName,
|
|
@@ -334,6 +430,9 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
334
430
|
// cannot fire and all trials land in primary — off-target detection activates
|
|
335
431
|
// only when ChEMBL IDs are available downstream.
|
|
336
432
|
const activeTrialsPartitioned = ctgov.coverage === "available" ? await partitionTrialsByAttribution(ctgov.data.active, attrCtx) : null;
|
|
433
|
+
// Everything CT.gov offered before any threshold of ours ran — the baseline
|
|
434
|
+
// the trials section measures its own drops against.
|
|
435
|
+
const activeTrialCandidateCount = (activeTrialsPartitioned?.primary.length ?? 0) + (activeTrialsPartitioned?.related.length ?? 0);
|
|
337
436
|
// Map ctgov active trials to clinical-trial row shape with text-based confidence,
|
|
338
437
|
// then remove rows identified as off-target by the attribution filter.
|
|
339
438
|
// Drug-in-class matches (calcitonin drugs for CALCR, GLP-1 drugs for GLP1R, etc.)
|
|
@@ -418,17 +517,37 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
418
517
|
failure_category: t.failure_category,
|
|
419
518
|
classifier: t.classifier,
|
|
420
519
|
})) ?? [];
|
|
520
|
+
const attributedFailedRows = failedTrialRows.map(attachTrialAttribution);
|
|
521
|
+
const attributedFailedRelatedRows = failedRelatedRows.map(attachTrialAttribution);
|
|
522
|
+
// The same partition the clinical-development section reports, shared with the
|
|
523
|
+
// safety lens: a related-receptor failure is context for both, and it must be
|
|
524
|
+
// told apart from a target-attributed one in both.
|
|
525
|
+
const eligibleFailedRows = attributedFailedRows.filter((r) => r.eligible_for_toxicology_aggregation);
|
|
526
|
+
const excludedFailedRows = [...attributedFailedRows.filter((r) => !r.eligible_for_toxicology_aggregation), ...attributedFailedRelatedRows];
|
|
527
|
+
// `clinical_development.failed_trials` and `safety_profile.failed_trials_safety_lens`
|
|
528
|
+
// report the same partition under two headings, so the section is decided once.
|
|
529
|
+
// Two constructions of it would let the same condition report two coverages.
|
|
530
|
+
const failedTrialsSection = ctgov.coverage === "available"
|
|
531
|
+
? coverageFromFilteredRows({
|
|
532
|
+
data: {
|
|
533
|
+
rows: eligibleFailedRows,
|
|
534
|
+
excluded_rows: excludedFailedRows,
|
|
535
|
+
},
|
|
536
|
+
retainedCount: eligibleFailedRows.length,
|
|
537
|
+
droppedCount: excludedFailedRows.length,
|
|
538
|
+
filter: FAILED_TRIALS_FILTER,
|
|
539
|
+
emptyReason: "ClinicalTrials.gov returned no terminated or withdrawn trials for the assessment target",
|
|
540
|
+
})
|
|
541
|
+
: { coverage: "queried_no_data", error: { message: "ClinicalTrials.gov unavailable" } };
|
|
421
542
|
// Typed explicitly so literal string coverage values narrow correctly.
|
|
422
543
|
// Phase-5 persist attaches the derived sub-tree after synthesis is stamped.
|
|
423
544
|
const dossierBody = {
|
|
424
|
-
schema_version: "4",
|
|
425
545
|
generated_at: new Date().toISOString(),
|
|
426
546
|
entity: assembleEntity(resolved),
|
|
427
547
|
liability_summary: liabilitySummary,
|
|
428
548
|
tractability: tractabilitySection,
|
|
429
549
|
indications: ot.coverage === "available"
|
|
430
|
-
? {
|
|
431
|
-
coverage: "available",
|
|
550
|
+
? coverageFromFilteredRows({
|
|
432
551
|
data: {
|
|
433
552
|
rows: indicationRows,
|
|
434
553
|
excluded_unsupported_count: unsupportedCandidates.length,
|
|
@@ -441,7 +560,13 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
441
560
|
}
|
|
442
561
|
: {}),
|
|
443
562
|
},
|
|
444
|
-
|
|
563
|
+
retainedCount: indicationRows.length,
|
|
564
|
+
// The head cap is a carrying limit rather than a judgement, so
|
|
565
|
+
// only the two content filters count against completeness.
|
|
566
|
+
droppedCount: indicationsRaw.length - filteredIndications.length + unsupportedCandidates.length,
|
|
567
|
+
filter: INDICATIONS_FILTER,
|
|
568
|
+
emptyReason: "Open Targets returned no disease associations for the target",
|
|
569
|
+
})
|
|
445
570
|
: {
|
|
446
571
|
coverage: "queried_no_data",
|
|
447
572
|
error: {
|
|
@@ -455,55 +580,43 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
455
580
|
trials: clinicalTrialRows === null
|
|
456
581
|
? { coverage: "queried_no_data", error: { message: "ClinicalTrials.gov unavailable" } }
|
|
457
582
|
: (() => {
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
583
|
+
const attributed = clinicalTrialRows.map(attachTrialAttribution);
|
|
584
|
+
const relatedTargetTrials = (activeTrialsPartitioned?.related ?? []).map((t) => attachTrialAttribution({
|
|
585
|
+
nct_id: t.nctId,
|
|
586
|
+
title: t.title,
|
|
587
|
+
phase: t.phase,
|
|
588
|
+
status: t.status,
|
|
589
|
+
conditions: t.conditions,
|
|
590
|
+
start_date: t.startDate,
|
|
591
|
+
completion_date: t.primaryCompletionDate,
|
|
592
|
+
match_confidence: "off_target",
|
|
593
|
+
}));
|
|
594
|
+
const rows = attributed.filter((r) => r.eligible_for_toxicology_aggregation);
|
|
595
|
+
return coverageFromFilteredRows({
|
|
463
596
|
data: {
|
|
464
|
-
rows
|
|
597
|
+
rows,
|
|
598
|
+
excluded_rows: [...attributed.filter((r) => !r.eligible_for_toxicology_aggregation), ...relatedTargetTrials],
|
|
465
599
|
selection_criteria: {
|
|
466
600
|
derived_from: "analytics.discovery_trials",
|
|
467
601
|
min_confidence: "medium",
|
|
468
602
|
excluded_off_target_count: activeTrialsPartitioned?.related.length ?? 0,
|
|
469
603
|
},
|
|
470
|
-
...(activeTrialsPartitioned && activeTrialsPartitioned.related.length > 0
|
|
471
|
-
? {
|
|
472
|
-
related_target_trials: activeTrialsPartitioned.related.map((t) => ({
|
|
473
|
-
nct_id: t.nctId,
|
|
474
|
-
title: t.title,
|
|
475
|
-
phase: t.phase,
|
|
476
|
-
status: t.status,
|
|
477
|
-
conditions: t.conditions,
|
|
478
|
-
start_date: t.startDate,
|
|
479
|
-
completion_date: t.primaryCompletionDate,
|
|
480
|
-
match_confidence: "off_target",
|
|
481
|
-
})),
|
|
482
|
-
related_receptor: activeTrialsPartitioned.related_receptor,
|
|
483
|
-
}
|
|
484
|
-
: {}),
|
|
485
604
|
},
|
|
486
|
-
|
|
605
|
+
retainedCount: rows.length,
|
|
606
|
+
// Everything CT.gov returned for the target, against what survived:
|
|
607
|
+
// the low-confidence cut, the attribution cut, and the related-receptor
|
|
608
|
+
// partition are all filters of ours.
|
|
609
|
+
droppedCount: activeTrialCandidateCount - rows.length,
|
|
610
|
+
filter: ACTIVE_TRIALS_FILTER,
|
|
611
|
+
emptyReason: "ClinicalTrials.gov returned no trials for the assessment target",
|
|
612
|
+
});
|
|
487
613
|
})(),
|
|
488
614
|
outcomes: trialOutcomesRows
|
|
489
|
-
? { coverage: "available", data: { rows: trialOutcomesRows } }
|
|
615
|
+
? { coverage: "available", data: { rows: trialOutcomesRows.map(attachTrialAttribution) } }
|
|
490
616
|
: phase3
|
|
491
617
|
? { coverage: "queried_no_data", error: { message: "no per-trial outcomes available" } }
|
|
492
618
|
: { coverage: "not_loaded", reason: "Phase-3 fan-out not run" },
|
|
493
|
-
failed_trials:
|
|
494
|
-
? {
|
|
495
|
-
coverage: "available",
|
|
496
|
-
data: {
|
|
497
|
-
rows: failedTrialRows,
|
|
498
|
-
...(failedRelatedRows.length > 0
|
|
499
|
-
? {
|
|
500
|
-
related_target_trials: failedRelatedRows,
|
|
501
|
-
related_receptor: failedTrialsPartitioned?.related_receptor,
|
|
502
|
-
}
|
|
503
|
-
: {}),
|
|
504
|
-
},
|
|
505
|
-
}
|
|
506
|
-
: { coverage: "queried_no_data" },
|
|
619
|
+
failed_trials: failedTrialsSection,
|
|
507
620
|
benchmarks: {
|
|
508
621
|
therapeutic_area: benchmarks.therapeutic_area,
|
|
509
622
|
fallback_to_all_areas: benchmarks.source === "fallback",
|
|
@@ -541,33 +654,28 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
541
654
|
: phase3
|
|
542
655
|
? { coverage: "queried_no_data", error: { message: "no off-target data" } }
|
|
543
656
|
: { coverage: "not_loaded", reason: "Phase-3 fan-out not run" },
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
...(failedRelatedRows.length > 0
|
|
550
|
-
? {
|
|
551
|
-
related_target_trials: failedRelatedRows,
|
|
552
|
-
related_receptor: failedTrialsPartitioned?.related_receptor,
|
|
553
|
-
}
|
|
554
|
-
: {}),
|
|
555
|
-
},
|
|
556
|
-
}
|
|
557
|
-
: ctgov.coverage === "available"
|
|
558
|
-
? { coverage: "queried_no_data", error: { message: "no failed trials" } }
|
|
559
|
-
: { coverage: "queried_no_data", error: { message: "ClinicalTrials.gov unavailable" } },
|
|
657
|
+
// The safety lens carries the same two buckets as
|
|
658
|
+
// `clinical_development.failed_trials`. Merging them would put a
|
|
659
|
+
// related-receptor termination in the same list as a target-attributed
|
|
660
|
+
// one, and the reader has no other way to tell them apart.
|
|
661
|
+
failed_trials_safety_lens: failedTrialsSection,
|
|
560
662
|
class_precedent: classP
|
|
561
663
|
? { coverage: "available", data: classP }
|
|
562
664
|
: phase3
|
|
563
665
|
? { coverage: "queried_no_data", error: { message: "no class precedent data" } }
|
|
564
666
|
: { coverage: "not_loaded", reason: "Phase-3 fan-out not run" },
|
|
565
|
-
|
|
667
|
+
// Stamped by Phase 5 after the safety-flags-trail agent runs.
|
|
668
|
+
target_organ_liabilities: { coverage: "not_loaded", reason: NOT_LOADED_PHASE5 },
|
|
566
669
|
regulatory_actions: regulatoryActionRows.length > 0
|
|
567
670
|
? { coverage: "available", data: { rows: regulatoryActionRows } }
|
|
568
671
|
: { coverage: "queried_no_data" },
|
|
569
672
|
},
|
|
570
|
-
|
|
673
|
+
// The corroboration fold reads the FDA label signals segmented after
|
|
674
|
+
// Phase 4, and the claim investigation reads the fold, so both are
|
|
675
|
+
// stamped by the workflow body before synthesis runs.
|
|
676
|
+
safety_corroboration: { coverage: "not_loaded", reason: NOT_LOADED_POST_ASSEMBLY },
|
|
677
|
+
claim_investigation: { coverage: "not_loaded", reason: "the claim investigation runs after Phase 4, over the corroborated organ claims" },
|
|
678
|
+
off_tissue_risk: offTissueSection,
|
|
571
679
|
off_target_panel: offTargetPanel
|
|
572
680
|
? { coverage: "available", data: offTargetPanel }
|
|
573
681
|
: phase3
|
|
@@ -575,8 +683,7 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
575
683
|
: { coverage: "not_loaded", reason: "Phase-3 fan-out not run" },
|
|
576
684
|
reference_biology: {
|
|
577
685
|
therapeutic_area_associations: ot.coverage === "available"
|
|
578
|
-
? {
|
|
579
|
-
coverage: "available",
|
|
686
|
+
? coverageFromFilteredRows({
|
|
580
687
|
data: {
|
|
581
688
|
rows: filteredIndications.slice(0, 200).map((a) => {
|
|
582
689
|
const evidence = makeAssociationEvidence(a);
|
|
@@ -603,7 +710,11 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
603
710
|
};
|
|
604
711
|
}),
|
|
605
712
|
},
|
|
606
|
-
|
|
713
|
+
retainedCount: Math.min(filteredIndications.length, 200),
|
|
714
|
+
droppedCount: indicationsRaw.length - filteredIndications.length,
|
|
715
|
+
filter: INDICATIONS_FILTER,
|
|
716
|
+
emptyReason: "Open Targets returned no disease associations for the target",
|
|
717
|
+
})
|
|
607
718
|
: { coverage: "queried_no_data" },
|
|
608
719
|
molecular_interactions: (() => {
|
|
609
720
|
const rows = assembleMolecularInteractions(phase2, fanout);
|
|
@@ -695,7 +806,7 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
695
806
|
marker_symbol: impc.data.mouseMarkerSymbol,
|
|
696
807
|
viability: impc.data.viability,
|
|
697
808
|
sex_dimorphism: impc.data.sexDimorphic,
|
|
698
|
-
organ_systems_with_phenotype: impc.data.organSystems,
|
|
809
|
+
organ_systems_with_phenotype: toOrganSystems(impc.data.organSystems),
|
|
699
810
|
top_mp_terms: impc.data.mpTerms.slice(0, 25).map((m) => m.term),
|
|
700
811
|
total_phenotype_count: impc.data.phenotypeCount,
|
|
701
812
|
pre_weaning_lethal: impc.data.viability === "lethal_pre_weaning",
|
|
@@ -769,11 +880,10 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
769
880
|
const data = assembleAdditionalEvidence(phase2);
|
|
770
881
|
return data ? { coverage: "available", data } : { coverage: "queried_no_data" };
|
|
771
882
|
})(),
|
|
772
|
-
discovery_trials:
|
|
773
|
-
? { coverage: "available", data: discoveryTrialData }
|
|
774
|
-
: { coverage: "queried_no_data", error: { message: "no medium/low-confidence trials" } },
|
|
883
|
+
discovery_trials: discoveryTrials,
|
|
775
884
|
// Stamped by Phase 5 after synthesis agents run; not available at assembly time.
|
|
776
885
|
synthesis_diagnostics: { coverage: "not_loaded", reason: "Phase-5 synthesis not yet run" },
|
|
886
|
+
quality_gates: { coverage: "not_loaded", reason: "Phase-5 synthesis not yet run" },
|
|
777
887
|
},
|
|
778
888
|
// Stamped by Phase 5 after the dossier-recommendation agent runs.
|
|
779
889
|
executive_recommendation: { coverage: "not_loaded", reason: "Phase-5 synthesis not yet run" },
|
|
@@ -785,7 +895,7 @@ export async function assembleDossier(pool, phase2, phase3, annotatorDeps) {
|
|
|
785
895
|
*
|
|
786
896
|
* When target-level FAERS has data (coverage: "available"), pass through
|
|
787
897
|
* unchanged. When class_precedent has FAERS-derived reports in per_organ,
|
|
788
|
-
* fold them into a class-scoped
|
|
898
|
+
* fold them into a class-scoped FAERS summary payload with
|
|
789
899
|
* coverage: "available" and inference_path tagged — rather than leaving
|
|
790
900
|
* the section as queried_no_data, which creates an evidence conflict
|
|
791
901
|
* that the conflict-detector flags. When neither has data, return
|