@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.
Files changed (221) hide show
  1. package/dist/agents/report-builder.d.ts +2 -0
  2. package/dist/agents/report-builder.js +2 -0
  3. package/dist/app/spawn-report-session.d.ts +85 -0
  4. package/dist/app/spawn-report-session.js +83 -0
  5. package/dist/contracts/chat-events.d.ts +9 -0
  6. package/dist/contracts/index.d.ts +6 -2
  7. package/dist/contracts/index.js +3 -1
  8. package/dist/contracts/organ-system.d.ts +49 -0
  9. package/dist/contracts/organ-system.js +67 -0
  10. package/dist/contracts/report-blocks.d.ts +564 -0
  11. package/dist/contracts/report-blocks.js +117 -0
  12. package/dist/contracts/report-reference.d.ts +459 -0
  13. package/dist/contracts/report-reference.js +256 -0
  14. package/dist/contracts/schemas/chat-events.d.ts +2 -0
  15. package/dist/contracts/schemas/chat-events.js +2 -0
  16. package/dist/contracts/severity.d.ts +15 -0
  17. package/dist/contracts/severity.js +10 -0
  18. package/dist/contracts/target-dossier.d.ts +8675 -12972
  19. package/dist/contracts/target-dossier.js +534 -591
  20. package/dist/data/safety-panel-schema.d.ts +18 -5
  21. package/dist/data/safety-panel-schema.js +4 -4
  22. package/dist/execution/artifact-metadata.js +1 -0
  23. package/dist/execution/report-runner.js +1 -3
  24. package/dist/execution/run-synthesis.js +2 -0
  25. package/dist/index.d.ts +6 -0
  26. package/dist/index.js +19 -0
  27. package/dist/lib/async-utils.d.ts +16 -4
  28. package/dist/lib/async-utils.js +20 -15
  29. package/dist/lib/host-concurrency.js +1 -0
  30. package/dist/loop/__fixtures__/scripted-provider.js +23 -2
  31. package/dist/loop/run-agent.js +58 -10
  32. package/dist/loop/tool-detail.d.ts +40 -0
  33. package/dist/loop/tool-detail.js +35 -3
  34. package/dist/loop/types.d.ts +13 -0
  35. package/dist/memory/thread-history.d.ts +10 -0
  36. package/dist/memory/thread-history.js +12 -1
  37. package/dist/prompts/target-assessment/briefs/executive-recommendation.d.ts +1 -1
  38. package/dist/prompts/target-assessment/briefs/executive-recommendation.js +5 -5
  39. package/dist/prompts/target-assessment/briefs/liability-bullets.d.ts +1 -1
  40. package/dist/prompts/target-assessment/briefs/liability-bullets.js +1 -1
  41. package/dist/prompts/target-assessment/briefs/target-organ-liabilities.d.ts +1 -1
  42. package/dist/prompts/target-assessment/briefs/target-organ-liabilities.js +11 -3
  43. package/dist/prompts/target-assessment/investigation/adversarial-critique.d.ts +1 -0
  44. package/dist/prompts/target-assessment/investigation/adversarial-critique.js +67 -0
  45. package/dist/prompts/target-assessment/investigation/claim-reverification.d.ts +1 -0
  46. package/dist/prompts/target-assessment/investigation/claim-reverification.js +49 -0
  47. package/dist/prompts/target-assessment/investigation/index.d.ts +3 -0
  48. package/dist/prompts/target-assessment/investigation/index.js +3 -0
  49. package/dist/prompts/target-assessment/investigation/mechanism-proposal.d.ts +1 -0
  50. package/dist/prompts/target-assessment/investigation/mechanism-proposal.js +49 -0
  51. package/dist/prompts/target-assessment/tox-voice/index.d.ts +1 -1
  52. package/dist/prompts/target-assessment/tox-voice/vocabulary.d.ts +8 -5
  53. package/dist/prompts/target-assessment/tox-voice/vocabulary.js +9 -20
  54. package/dist/providers/__fixtures__/session.d.ts +5 -4
  55. package/dist/providers/__fixtures__/session.js +4 -4
  56. package/dist/report-model/block-walk.d.ts +56 -0
  57. package/dist/report-model/block-walk.js +89 -0
  58. package/dist/report-model/draft-finish.d.ts +60 -0
  59. package/dist/report-model/draft-finish.js +56 -0
  60. package/dist/report-model/draft-operations.d.ts +125 -0
  61. package/dist/report-model/draft-operations.js +341 -0
  62. package/dist/report-model/draft-read.d.ts +59 -0
  63. package/dist/report-model/draft-read.js +109 -0
  64. package/dist/report-model/draft.d.ts +51 -0
  65. package/dist/report-model/draft.js +32 -0
  66. package/dist/report-model/fixture-resolver.d.ts +8 -0
  67. package/dist/report-model/fixture-resolver.js +252 -0
  68. package/dist/report-model/mint-snapshot.d.ts +30 -0
  69. package/dist/report-model/mint-snapshot.js +40 -0
  70. package/dist/report-model/reference-resolver.d.ts +113 -0
  71. package/dist/report-model/reference-resolver.js +60 -0
  72. package/dist/report-model/structural-validation.d.ts +22 -0
  73. package/dist/report-model/structural-validation.js +68 -0
  74. package/dist/report-model/validate.d.ts +40 -0
  75. package/dist/report-model/validate.js +80 -0
  76. package/dist/report-render/chart.d.ts +33 -0
  77. package/dist/report-render/chart.js +538 -0
  78. package/dist/report-render/page.d.ts +127 -0
  79. package/dist/report-render/page.js +307 -0
  80. package/dist/report-render/references.d.ts +32 -0
  81. package/dist/report-render/references.js +44 -0
  82. package/dist/report-render/render.d.ts +25 -0
  83. package/dist/report-render/render.js +125 -0
  84. package/dist/report-render/script-json.d.ts +13 -0
  85. package/dist/report-render/script-json.js +15 -0
  86. package/dist/report-render/types.d.ts +39 -0
  87. package/dist/report-render/types.js +10 -0
  88. package/dist/report-render/views/chart-view.d.ts +11 -0
  89. package/dist/report-render/views/chart-view.js +23 -0
  90. package/dist/report-render/views/page-view.d.ts +20 -0
  91. package/dist/report-render/views/page-view.js +49 -0
  92. package/dist/report-render/views/prose.d.ts +28 -0
  93. package/dist/report-render/views/prose.js +75 -0
  94. package/dist/report-render/views/references-view.d.ts +20 -0
  95. package/dist/report-render/views/references-view.js +64 -0
  96. package/dist/report-render/views/values.d.ts +42 -0
  97. package/dist/report-render/views/values.js +43 -0
  98. package/dist/runtime/boot.d.ts +3 -3
  99. package/dist/runtime/boot.js +15 -4
  100. package/dist/runtime/dbos.d.ts +4 -4
  101. package/dist/state/artifacts.d.ts +16 -0
  102. package/dist/state/artifacts.js +18 -0
  103. package/dist/state/init.js +31 -0
  104. package/dist/state/purge-analysis.js +1 -0
  105. package/dist/state/report-versions.d.ts +132 -0
  106. package/dist/state/report-versions.js +194 -0
  107. package/dist/tasks/data-profile.js +1 -0
  108. package/dist/tools/bio/chembl.js +1 -0
  109. package/dist/tools/bio/comptox.js +1 -0
  110. package/dist/tools/bio/drug-gene-interactions.js +1 -0
  111. package/dist/tools/bio/gene-disease-evidence.js +1 -0
  112. package/dist/tools/bio/gene-preclinical-profile.js +1 -0
  113. package/dist/tools/bio/keys.d.ts +3 -2
  114. package/dist/tools/bio/keys.js +3 -2
  115. package/dist/tools/bio/lookup-annotation.js +1 -0
  116. package/dist/tools/bio/opentargets.d.ts +3 -3
  117. package/dist/tools/bio/opentargets.js +4 -3
  118. package/dist/tools/bio/pubchem.js +1 -0
  119. package/dist/tools/bio/search-clinical-trials.js +1 -0
  120. package/dist/tools/bio/search-faers.js +1 -0
  121. package/dist/tools/bio/search-geo-datasets.js +1 -0
  122. package/dist/tools/bio/search-interactions.js +1 -0
  123. package/dist/tools/bio/target-safety.d.ts +4 -6
  124. package/dist/tools/bio/target-safety.js +7 -6
  125. package/dist/tools/define-tool.d.ts +19 -12
  126. package/dist/tools/define-tool.js +4 -2
  127. package/dist/tools/display/show-user.js +1 -0
  128. package/dist/tools/iterate-report.js +2 -0
  129. package/dist/tools/lib/chembl-client.d.ts +2 -0
  130. package/dist/tools/lib/chembl-client.js +1 -0
  131. package/dist/tools/lib/monarch-client.d.ts +42 -0
  132. package/dist/tools/lib/monarch-client.js +100 -0
  133. package/dist/tools/report/build-report.js +1 -0
  134. package/dist/tools/report/mint-preview-url.js +1 -0
  135. package/dist/tools/report/preview-snapshot.js +1 -0
  136. package/dist/tools/report/submit-report.js +1 -0
  137. package/dist/tools/report/version-fs.js +4 -0
  138. package/dist/tools/report-authoring/authoring-tools.d.ts +134 -0
  139. package/dist/tools/report-authoring/authoring-tools.js +352 -0
  140. package/dist/tools/research/context7-docs.js +2 -0
  141. package/dist/tools/research/generate-analogy-report.js +1 -0
  142. package/dist/tools/research/generate-plan.js +3 -0
  143. package/dist/tools/research/inspect-data-profile.js +4 -0
  144. package/dist/tools/research/literature-reviewer.js +1 -0
  145. package/dist/tools/research/search-arxiv.js +1 -0
  146. package/dist/tools/research/search-github-repos.js +1 -0
  147. package/dist/tools/research/search-semantic-scholar.js +1 -0
  148. package/dist/tools/sandbox/list-available-packages.js +23 -0
  149. package/dist/tools/sandbox/list-available-refs.js +36 -0
  150. package/dist/tools/sandbox/report-blocker.js +1 -0
  151. package/dist/tools/sandbox/skills.js +2 -0
  152. package/dist/tools/workspace/file-stat.js +1 -0
  153. package/dist/tools/workspace/show-file.js +2 -0
  154. package/dist/tools/workspace/show-plan.js +1 -0
  155. package/dist/workflows/execute-analysis.d.ts +5 -1
  156. package/dist/workflows/execute-analysis.js +5 -5
  157. package/dist/workflows/execute-target-assessment.d.ts +13 -2
  158. package/dist/workflows/execute-target-assessment.js +78 -16
  159. package/dist/workflows/target-assessment/assemblers/index.d.ts +1 -1
  160. package/dist/workflows/target-assessment/assemblers/index.js +1 -1
  161. package/dist/workflows/target-assessment/assemblers/literature.d.ts +9 -27
  162. package/dist/workflows/target-assessment/assemblers/literature.js +32 -48
  163. package/dist/workflows/target-assessment/assemblers/orchestrator.d.ts +17 -9
  164. package/dist/workflows/target-assessment/assemblers/orchestrator.js +195 -85
  165. package/dist/workflows/target-assessment/assemblers/safety.d.ts +70 -48
  166. package/dist/workflows/target-assessment/assemblers/safety.js +125 -42
  167. package/dist/workflows/target-assessment/collectors/index.d.ts +5 -2
  168. package/dist/workflows/target-assessment/collectors/index.js +48 -5
  169. package/dist/workflows/target-assessment/coverage.d.ts +43 -27
  170. package/dist/workflows/target-assessment/coverage.js +33 -29
  171. package/dist/workflows/target-assessment/fanout/index.js +1 -0
  172. package/dist/workflows/target-assessment/investigation/index.d.ts +97 -0
  173. package/dist/workflows/target-assessment/investigation/index.js +419 -0
  174. package/dist/workflows/target-assessment/lib/approval-precedents.d.ts +26 -5
  175. package/dist/workflows/target-assessment/lib/approval-precedents.js +95 -29
  176. package/dist/workflows/target-assessment/lib/citation-validator.js +1 -1
  177. package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.d.ts +2 -2
  178. package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.d.ts +2 -3
  179. package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.js +0 -4
  180. package/dist/workflows/target-assessment/lib/compute-derived.d.ts +6 -5
  181. package/dist/workflows/target-assessment/lib/compute-derived.js +14 -5
  182. package/dist/workflows/target-assessment/lib/family-complex-supplement.d.ts +5 -6
  183. package/dist/workflows/target-assessment/lib/family-complex-supplement.js +2 -3
  184. package/dist/workflows/target-assessment/lib/fda-label-safety.d.ts +72 -0
  185. package/dist/workflows/target-assessment/lib/fda-label-safety.js +166 -0
  186. package/dist/workflows/target-assessment/lib/heterodimer-filter.d.ts +0 -9
  187. package/dist/workflows/target-assessment/lib/heterodimer-filter.js +0 -10
  188. package/dist/workflows/target-assessment/lib/hpo-organ-map.d.ts +34 -0
  189. package/dist/workflows/target-assessment/lib/hpo-organ-map.js +63 -0
  190. package/dist/workflows/target-assessment/lib/impc-organ-map.d.ts +19 -0
  191. package/dist/workflows/target-assessment/lib/impc-organ-map.js +39 -0
  192. package/dist/workflows/target-assessment/lib/meddra-organ-map.d.ts +24 -14
  193. package/dist/workflows/target-assessment/lib/meddra-organ-map.js +59 -47
  194. package/dist/workflows/target-assessment/lib/recommendation-sanitizer.js +1 -1
  195. package/dist/workflows/target-assessment/lib/regulatory-actions.d.ts +2 -3
  196. package/dist/workflows/target-assessment/lib/regulatory-actions.js +33 -4
  197. package/dist/workflows/target-assessment/lib/safety-corroboration.d.ts +44 -0
  198. package/dist/workflows/target-assessment/lib/safety-corroboration.js +273 -0
  199. package/dist/workflows/target-assessment/lib/target-identity-filter.d.ts +5 -7
  200. package/dist/workflows/target-assessment/lib/target-identity-filter.js +5 -7
  201. package/dist/workflows/target-assessment/metrics.d.ts +1 -6
  202. package/dist/workflows/target-assessment/metrics.js +1 -13
  203. package/dist/workflows/target-assessment/phase4-assemble.d.ts +2147 -807
  204. package/dist/workflows/target-assessment/phase4-assemble.js +19 -19
  205. package/dist/workflows/target-assessment/phase5-persist.d.ts +20 -21
  206. package/dist/workflows/target-assessment/phase5-persist.js +56 -173
  207. package/dist/workflows/target-assessment/schemas.d.ts +46 -1
  208. package/dist/workflows/target-assessment/schemas.js +19 -0
  209. package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.d.ts +1 -0
  210. package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.js +2 -0
  211. package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +26 -62
  212. package/dist/workflows/target-assessment/steps/phase2-aggregate.js +0 -4
  213. package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +27 -154
  214. package/dist/workflows/target-assessment/steps/phase3-aggregate.js +0 -6
  215. package/dist/workflows/target-assessment/steps/synthesis/diagnostics.d.ts +0 -6
  216. package/dist/workflows/target-assessment/steps/synthesis/diagnostics.js +0 -18
  217. package/dist/workflows/target-assessment/sub-workflows/per-modulator-polypharm.d.ts +1 -0
  218. package/dist/workflows/target-assessment/synthesis/index.d.ts +52 -5
  219. package/dist/workflows/target-assessment/synthesis/index.js +4 -1
  220. package/dist/workflows/target-assessment/synthesis-probes.d.ts +3 -3
  221. package/package.json +4 -1
@@ -27,6 +27,7 @@ import { searchFailedTrials, searchTrialsForTarget } from "../../../tools/lib/cl
27
27
  import { filterInformative, searchClinvar } from "../../../tools/lib/clinvar-client.js";
28
28
  import { getKoPhenotypeProfile } from "../../../tools/lib/impc-client.js";
29
29
  import { getFamilyHeterodimers } from "../../../tools/lib/iuphar-client.js";
30
+ import { getGenePhenotypeProfile } from "../../../tools/lib/monarch-client.js";
30
31
  import { getFaersByDrug, getFaersSeriousness } from "../../../tools/lib/openfda-client.js";
31
32
  import { getBaselineExpression, getTargetSafetyLiabilities, searchTargetAssociations } from "../../../tools/lib/opentargets-client.js";
32
33
  import { getPathwayMemberships } from "../../../tools/lib/pathway-client.js";
@@ -316,7 +317,48 @@ export async function collectImpc(input) {
316
317
  return fail(err);
317
318
  }
318
319
  }
319
- // ── 10. Open Targets ─────────────────────────────────────────────────
320
+ // ── 10. Monarch Initiative ───────────────────────────────────────────
321
+ export async function collectMonarch(input) {
322
+ // Monarch resolves prefixed identifiers; HGNC is its native gene namespace
323
+ // and NCBI Gene is the fallback it also indexes.
324
+ const geneCurie = input.ids.hgnc ?? (input.ids.entrez ? `NCBIGene:${input.ids.entrez}` : null);
325
+ if (!geneCurie) {
326
+ return {
327
+ coverage: "not_loaded",
328
+ reason: "no HGNC or NCBI Gene id resolved",
329
+ };
330
+ }
331
+ try {
332
+ const profile = await withHost("monarch", () => getGenePhenotypeProfile(geneCurie));
333
+ if (profile.phenotypes.length === 0) {
334
+ return {
335
+ coverage: "queried_no_data",
336
+ error: {
337
+ message: `Monarch holds no human phenotype associations for ${geneCurie}`,
338
+ },
339
+ };
340
+ }
341
+ return {
342
+ coverage: "available",
343
+ data: {
344
+ geneCurie: profile.geneCurie,
345
+ phenotypes: profile.phenotypes.map((p) => ({
346
+ hpoId: p.hpoId,
347
+ label: p.label,
348
+ ancestorIds: p.ancestorIds,
349
+ publications: p.publications,
350
+ diseaseContext: p.diseaseContext,
351
+ frequencyPercent: p.frequencyPercent,
352
+ primaryKnowledgeSource: p.primaryKnowledgeSource,
353
+ })),
354
+ },
355
+ };
356
+ }
357
+ catch (err) {
358
+ return fail(err);
359
+ }
360
+ }
361
+ // ── 11. Open Targets ─────────────────────────────────────────────────
320
362
  export async function collectOpenTargets(input) {
321
363
  const ensemblId = input.ids.ensembl;
322
364
  if (!ensemblId) {
@@ -351,7 +393,7 @@ export async function collectOpenTargets(input) {
351
393
  return fail(err);
352
394
  }
353
395
  }
354
- // ── 11. Pathways (Reactome + KEGG via the unified client) ────────────
396
+ // ── 12. Pathways (Reactome + KEGG via the unified client) ────────────
355
397
  export async function collectPathways(input) {
356
398
  try {
357
399
  const raw = await withHost("reactome", () => getPathwayMemberships(input.geneSymbol));
@@ -380,7 +422,7 @@ export async function collectPathways(input) {
380
422
  return fail(err);
381
423
  }
382
424
  }
383
- // ── 12. PubMed index ─────────────────────────────────────────────────
425
+ // ── 13. PubMed index ─────────────────────────────────────────────────
384
426
  export async function collectPubmedIndex(input, ctx) {
385
427
  const query = `"${input.geneSymbol}"[Gene]`;
386
428
  try {
@@ -407,7 +449,7 @@ export async function collectPubmedIndex(input, ctx) {
407
449
  return fail(err);
408
450
  }
409
451
  }
410
- // ── 13. STRING PPI ───────────────────────────────────────────────────
452
+ // ── 14. STRING PPI ───────────────────────────────────────────────────
411
453
  export async function collectStringPpi(input) {
412
454
  try {
413
455
  const partners = await withHost("string", () => getInteractionPartners([input.geneSymbol], {
@@ -429,7 +471,7 @@ export async function collectStringPpi(input) {
429
471
  return fail(err);
430
472
  }
431
473
  }
432
- // ── 14. Therapeutic programs (non-ChEMBL curated set) ────────────────
474
+ // ── 15. Therapeutic programs (non-ChEMBL curated set) ────────────────
433
475
  export async function collectTherapeuticPrograms(input) {
434
476
  const programs = findTherapeuticProgramsForTarget({
435
477
  geneSymbol: input.geneSymbol,
@@ -460,6 +502,7 @@ export const COLLECTOR_MANIFEST = [
460
502
  { id: "faers-by-target", run: collectFaersByTarget },
461
503
  { id: "family-complexes", run: collectFamilyComplexes },
462
504
  { id: "impc", run: collectImpc },
505
+ { id: "monarch", run: collectMonarch },
463
506
  { id: "opentargets", run: collectOpenTargets },
464
507
  { id: "pathways", run: collectPathways },
465
508
  { id: "pubmed-index", run: collectPubmedIndex },
@@ -6,29 +6,19 @@
6
6
  * instead of throwing. Only Phase 0 (target resolution) is allowed to
7
7
  * throw — that legitimately aborts the workflow.
8
8
  *
9
- * Coverage states:
10
- * - "available" — the upstream returned data; payload is present.
11
- * - "queried_no_data" — the upstream was queried but came back empty
12
- * (no rows / 404 / etc.) OR threw an error which
13
- * we serialized into `error` instead of bubbling.
14
- * - "not_loaded" — the upstream was never queried (feature flag,
15
- * config disable, or upstream skipped because a
16
- * precondition was not met).
9
+ * `CoverageSchema` in `contracts/target-dossier.ts` is the one enumeration of
10
+ * the coverage states, and the helpers below emit its members. A step envelope
11
+ * carries the three states a step can reach on its own; `filtered` is a
12
+ * judgement one of our own filters makes, so only the assembler helpers below
13
+ * produce it.
17
14
  */
18
15
  import { z } from "zod";
19
- export declare const CoverageSchema: z.ZodEnum<{
20
- available: "available";
21
- queried_no_data: "queried_no_data";
22
- not_loaded: "not_loaded";
23
- }>;
24
- export type Coverage = z.infer<typeof CoverageSchema>;
25
16
  export declare const SerializedErrorSchema: z.ZodObject<{
26
17
  message: z.ZodString;
27
18
  name: z.ZodOptional<z.ZodString>;
28
19
  stack: z.ZodOptional<z.ZodString>;
29
20
  }, z.core.$strip>;
30
21
  export type SerializedError = z.infer<typeof SerializedErrorSchema>;
31
- export declare function serializeError(err: unknown): SerializedError;
32
22
  /**
33
23
  * Build the schema for a `{ coverage, data, error? }` step output.
34
24
  *
@@ -49,18 +39,6 @@ export declare function withCoverage<TData extends z.ZodTypeAny>(dataSchema: TDa
49
39
  coverage: z.ZodLiteral<"not_loaded">;
50
40
  reason: z.ZodOptional<z.ZodString>;
51
41
  }, z.core.$strip>], "coverage">;
52
- /**
53
- * Run a step body with the standard try/catch envelope. If the body
54
- * resolves, returns `{ coverage: "available", data }`. If it throws,
55
- * returns `{ coverage: "queried_no_data", error: serializeError(err) }`.
56
- */
57
- export declare function runWithCoverage<T>(body: () => Promise<T>): Promise<{
58
- coverage: "available";
59
- data: T;
60
- } | {
61
- coverage: "queried_no_data";
62
- error: SerializedError;
63
- }>;
64
42
  /**
65
43
  * Convenience wrapper for `{ rows: T[] }` payloads. Maps an empty rows
66
44
  * array to `coverage: "queried_no_data"` so the dossier discriminator's
@@ -79,3 +57,41 @@ export declare function coverageFromRows<T>(rows: T[], opts?: {
79
57
  coverage: "queried_no_data";
80
58
  error: SerializedError;
81
59
  };
60
+ /**
61
+ * Build a dossier-section envelope for a row list one of our own filters
62
+ * narrowed.
63
+ *
64
+ * A filter is not the same as an empty upstream, and the difference is the
65
+ * whole point of the four-state contract. Deciding coverage from the source
66
+ * and then filtering the payload loses it: a section whose every row our
67
+ * threshold discarded reports a clean `available` holding nothing, which reads
68
+ * as "the source had nothing to say".
69
+ *
70
+ * So the decision is made once, from both counts:
71
+ * - nothing survived and something was dropped → `filtered`, naming the
72
+ * filter and the count it discarded, with no `data`;
73
+ * - some survived and some were dropped → `available` carrying
74
+ * `dropped_count`, so the section does not overstate its completeness;
75
+ * - nothing survived and nothing was dropped → `queried_no_data`: the list
76
+ * was empty before any filter of ours ran.
77
+ */
78
+ export declare function coverageFromFilteredRows<TData>(args: {
79
+ data: TData;
80
+ retainedCount: number;
81
+ droppedCount: number;
82
+ /** What ran, in a reader's terms — carried verbatim on the `filtered` branch. */
83
+ filter: string;
84
+ /** Why the source itself held nothing, used only when no filter dropped anything. */
85
+ emptyReason: string;
86
+ }): {
87
+ coverage: "available";
88
+ data: TData;
89
+ dropped_count?: number;
90
+ } | {
91
+ coverage: "filtered";
92
+ filter: string;
93
+ dropped_count: number;
94
+ } | {
95
+ coverage: "queried_no_data";
96
+ error: SerializedError;
97
+ };
@@ -6,28 +6,18 @@
6
6
  * instead of throwing. Only Phase 0 (target resolution) is allowed to
7
7
  * throw — that legitimately aborts the workflow.
8
8
  *
9
- * Coverage states:
10
- * - "available" — the upstream returned data; payload is present.
11
- * - "queried_no_data" — the upstream was queried but came back empty
12
- * (no rows / 404 / etc.) OR threw an error which
13
- * we serialized into `error` instead of bubbling.
14
- * - "not_loaded" — the upstream was never queried (feature flag,
15
- * config disable, or upstream skipped because a
16
- * precondition was not met).
9
+ * `CoverageSchema` in `contracts/target-dossier.ts` is the one enumeration of
10
+ * the coverage states, and the helpers below emit its members. A step envelope
11
+ * carries the three states a step can reach on its own; `filtered` is a
12
+ * judgement one of our own filters makes, so only the assembler helpers below
13
+ * produce it.
17
14
  */
18
15
  import { z } from "zod";
19
- export const CoverageSchema = z.enum(["available", "queried_no_data", "not_loaded"]);
20
16
  export const SerializedErrorSchema = z.object({
21
17
  message: z.string(),
22
18
  name: z.string().optional(),
23
19
  stack: z.string().optional(),
24
20
  });
25
- export function serializeError(err) {
26
- if (err instanceof Error) {
27
- return { message: err.message, name: err.name, stack: err.stack };
28
- }
29
- return { message: String(err) };
30
- }
31
21
  /**
32
22
  * Build the schema for a `{ coverage, data, error? }` step output.
33
23
  *
@@ -50,20 +40,6 @@ export function withCoverage(dataSchema) {
50
40
  }),
51
41
  ]);
52
42
  }
53
- /**
54
- * Run a step body with the standard try/catch envelope. If the body
55
- * resolves, returns `{ coverage: "available", data }`. If it throws,
56
- * returns `{ coverage: "queried_no_data", error: serializeError(err) }`.
57
- */
58
- export async function runWithCoverage(body) {
59
- try {
60
- const data = await body();
61
- return { coverage: "available", data };
62
- }
63
- catch (err) {
64
- return { coverage: "queried_no_data", error: serializeError(err) };
65
- }
66
- }
67
43
  /**
68
44
  * Convenience wrapper for `{ rows: T[] }` payloads. Maps an empty rows
69
45
  * array to `coverage: "queried_no_data"` so the dossier discriminator's
@@ -80,3 +56,31 @@ export function coverageFromRows(rows, opts) {
80
56
  }
81
57
  return { coverage: "available", data: { rows } };
82
58
  }
59
+ /**
60
+ * Build a dossier-section envelope for a row list one of our own filters
61
+ * narrowed.
62
+ *
63
+ * A filter is not the same as an empty upstream, and the difference is the
64
+ * whole point of the four-state contract. Deciding coverage from the source
65
+ * and then filtering the payload loses it: a section whose every row our
66
+ * threshold discarded reports a clean `available` holding nothing, which reads
67
+ * as "the source had nothing to say".
68
+ *
69
+ * So the decision is made once, from both counts:
70
+ * - nothing survived and something was dropped → `filtered`, naming the
71
+ * filter and the count it discarded, with no `data`;
72
+ * - some survived and some were dropped → `available` carrying
73
+ * `dropped_count`, so the section does not overstate its completeness;
74
+ * - nothing survived and nothing was dropped → `queried_no_data`: the list
75
+ * was empty before any filter of ours ran.
76
+ */
77
+ export function coverageFromFilteredRows(args) {
78
+ const { data, retainedCount, droppedCount, filter, emptyReason } = args;
79
+ if (retainedCount > 0) {
80
+ return droppedCount > 0 ? { coverage: "available", data, dropped_count: droppedCount } : { coverage: "available", data };
81
+ }
82
+ if (droppedCount > 0) {
83
+ return { coverage: "filtered", filter, dropped_count: droppedCount };
84
+ }
85
+ return { coverage: "queried_no_data", error: { message: emptyReason } };
86
+ }
@@ -85,6 +85,7 @@ export async function polypharmForOneModulator(item) {
85
85
  hits: hits.map((h) => ({
86
86
  targetChemblId: h.targetChemblId,
87
87
  targetName: h.targetName,
88
+ assayChemblId: h.assayChemblId,
88
89
  pchemblValue: h.pchemblValue,
89
90
  standardType: h.standardType,
90
91
  standardValue: h.standardValue,
@@ -0,0 +1,97 @@
1
+ /**
2
+ * The claim-investigation phase.
3
+ *
4
+ * Corroboration says which organs several sources agree on. Agreement is not
5
+ * adjudication: sources that all re-import one curation agree perfectly and are
6
+ * wrong together. This phase interrogates each corroborated organ claim —
7
+ * propose a mechanism, argue against it, re-verify, converge — and records what
8
+ * survived, plus every candidate it did not get to and why.
9
+ *
10
+ * Three LLM steps per round, chosen per step rather than uniformly:
11
+ *
12
+ * - **propose** and **re-verify** are single-shot structured extractions
13
+ * (`structuredLlmCall`). Everything they reason over is already in the
14
+ * prompt; a retrieval surface would only let them ground an answer in
15
+ * something the run never collected.
16
+ * - **critique** is a real agent loop (`runToTerminal` over `runAgent`) with a
17
+ * literature tool and a `defineTool` terminal recorder. Disconfirmation is a
18
+ * search task: the dossier is assembled to state what the run found, not to
19
+ * refute it, so a critic confined to it can only observe that the evidence
20
+ * is thin — which is the rubber stamp this step exists to avoid.
21
+ *
22
+ * Nothing here scores a claim. The verdict is a four-word vocabulary the model
23
+ * states, no threshold decides survival, and no claim is removed from the
24
+ * dossier by anything this phase concludes.
25
+ *
26
+ * Durability arrives through the injected `runStep` seam and through
27
+ * `structuredLlmCall`'s own attempt-named steps; this module imports no
28
+ * durability engine.
29
+ */
30
+ import type { ClaimInvestigation, DossierBody, SafetyCorroboration } from "@inflexa-ai/harness/contracts/target-dossier.js";
31
+ import type { AgentSession } from "../../../auth/types.js";
32
+ import type { UsageRecorder } from "../../../billing/usage-recorder.js";
33
+ import type { Logger } from "../../../lib/logger.js";
34
+ import type { RunStep } from "../../../loop/types.js";
35
+ import type { AgentChat } from "../../../providers/types.js";
36
+ import { type Tool } from "../../../tools/define-tool.js";
37
+ import { BUDGET_EXCEEDED_SENTINEL } from "../lib/llm-step.js";
38
+ /**
39
+ * The bounds the phase runs under.
40
+ *
41
+ * These are configuration with stated defaults, not clinical constants: nothing
42
+ * about biology says six claims or two rounds. They exist to bound cost and to
43
+ * guarantee termination, the section reports the values in force, and an
44
+ * embedder that wants a deeper pass sets its own.
45
+ */
46
+ export interface ClaimInvestigationConfig {
47
+ /** Corroborated organ claims investigated per run; the rest are reported as budget-cut. */
48
+ readonly claimBudget: number;
49
+ /** Propose → critique → re-verify rounds a single claim may run. */
50
+ readonly roundBound: number;
51
+ /** Iteration budget for the adversarial critic's tool-using loop. */
52
+ readonly criticMaxIterations: number;
53
+ }
54
+ export declare const DEFAULT_CLAIM_INVESTIGATION_CONFIG: ClaimInvestigationConfig;
55
+ export interface ClaimInvestigationDeps {
56
+ /** Operational logging seam; omitted falls back to no-op. */
57
+ readonly logger?: Logger;
58
+ readonly chatProvider: AgentChat;
59
+ /** Session for the phase; each step derives its own sub-agent session from it. */
60
+ readonly session: AgentSession;
61
+ readonly model: string;
62
+ /** Attempt counter — bumped on resume so a cancelled call lands a fresh durable slot. */
63
+ readonly attempt: number;
64
+ /** Durability seam for the critic's agent loop. */
65
+ readonly runStep: RunStep;
66
+ /** Retrieval surface the adversarial critic searches for disconfirming records. */
67
+ readonly critiqueTools: readonly Tool[];
68
+ /** Overrides for {@link DEFAULT_CLAIM_INVESTIGATION_CONFIG}. */
69
+ readonly config?: Partial<ClaimInvestigationConfig>;
70
+ /** LLM usage-accounting seam for the critic loop; omitted falls back to the no-op recorder. */
71
+ readonly usageRecorder?: UsageRecorder;
72
+ readonly signal?: AbortSignal;
73
+ }
74
+ export interface ClaimInvestigationInput {
75
+ /** The run's corroboration record — the source of candidate claims. */
76
+ readonly corroboration: SafetyCorroboration;
77
+ /** The assembled dossier body, read for per-organ risk context and completeness. */
78
+ readonly dossier: DossierBody;
79
+ }
80
+ /** The sentinel an LLM step returns once it has self-cancelled the workflow on a 402. */
81
+ export interface BudgetExceeded {
82
+ readonly kind: "budget-exceeded";
83
+ readonly sentinel: typeof BUDGET_EXCEEDED_SENTINEL;
84
+ }
85
+ export type ClaimInvestigationResult = ClaimInvestigation | BudgetExceeded;
86
+ declare function isBudgetCancel<T>(value: T | BudgetExceeded): value is BudgetExceeded;
87
+ /**
88
+ * Interrogate the run's corroborated organ claims.
89
+ *
90
+ * Coverage is the honest account of what happened: `not_loaded` when there was
91
+ * no corroboration record to work from, `queried_no_data` when the fold produced
92
+ * no corroborated organ, and `available` once at least one candidate reached the
93
+ * phase — including when every one of them ended up in `not_investigated`, since
94
+ * that list is what the section has to say in that case.
95
+ */
96
+ export declare function investigateClaims(input: ClaimInvestigationInput, deps: ClaimInvestigationDeps): Promise<ClaimInvestigationResult>;
97
+ export { isBudgetCancel as isClaimInvestigationBudgetExceeded };