@inflexa-ai/harness 0.35.8 → 0.36.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/dist/auth/types.d.ts +5 -14
  2. package/dist/auth/types.js +3 -10
  3. package/dist/billing/usage-recorder.d.ts +1 -1
  4. package/dist/contracts/analogy-report.d.ts +1 -1
  5. package/dist/contracts/analogy-report.js +1 -1
  6. package/dist/contracts/chat-parts.d.ts +2 -3
  7. package/dist/contracts/index.d.ts +0 -4
  8. package/dist/contracts/index.js +0 -2
  9. package/dist/index.d.ts +0 -7
  10. package/dist/index.js +0 -21
  11. package/dist/lib/metrics.d.ts +1 -1
  12. package/dist/lib/otel-spans.d.ts +0 -2
  13. package/dist/lib/otel-spans.js +0 -2
  14. package/dist/loop/genai-spans.d.ts +14 -0
  15. package/dist/loop/genai-spans.js +35 -0
  16. package/dist/loop/run-agent.d.ts +1 -1
  17. package/dist/loop/run-agent.js +37 -4
  18. package/dist/runtime/assemble.d.ts +0 -3
  19. package/dist/runtime/assemble.js +0 -3
  20. package/dist/state/index.d.ts +0 -2
  21. package/dist/state/index.js +0 -1
  22. package/dist/state/init.js +1 -60
  23. package/dist/state/purge-analysis.d.ts +1 -2
  24. package/dist/state/purge-analysis.js +1 -2
  25. package/dist/tasks/regulatory-corpus-boot-refresh.js +1 -1
  26. package/dist/tools/bio/gene-preclinical-profile.d.ts +1 -3
  27. package/dist/tools/bio/gene-preclinical-profile.js +1 -3
  28. package/dist/tools/lib/chembl-client.d.ts +1 -4
  29. package/dist/tools/lib/chembl-client.js +1 -4
  30. package/dist/tools/lib/clinical-benchmarks-client.d.ts +1 -1
  31. package/dist/tools/lib/clinical-benchmarks-client.js +1 -1
  32. package/dist/tools/lib/clinical-trials-client.d.ts +0 -3
  33. package/dist/tools/lib/clinical-trials-client.js +0 -3
  34. package/dist/tools/lib/identifier-resolver.d.ts +5 -7
  35. package/dist/tools/lib/identifier-resolver.js +5 -7
  36. package/dist/tools/lib/iuphar-client.d.ts +1 -3
  37. package/dist/tools/lib/iuphar-client.js +1 -3
  38. package/dist/tools/lib/opentargets-client.d.ts +1 -1
  39. package/dist/tools/lib/opentargets-client.js +1 -1
  40. package/dist/tools/lib/protein-family-normalize.d.ts +5 -7
  41. package/dist/tools/lib/protein-family-normalize.js +5 -7
  42. package/dist/tools/lib/uniprot-client.d.ts +0 -7
  43. package/dist/tools/lib/uniprot-client.js +2 -9
  44. package/package.json +1 -1
  45. package/dist/contracts/target-assessment-row.d.ts +0 -85
  46. package/dist/contracts/target-assessment-row.js +0 -37
  47. package/dist/contracts/target-dossier.d.ts +0 -12423
  48. package/dist/contracts/target-dossier.js +0 -1282
  49. package/dist/prompts/target-assessment/briefs/executive-recommendation.d.ts +0 -1
  50. package/dist/prompts/target-assessment/briefs/executive-recommendation.js +0 -85
  51. package/dist/prompts/target-assessment/briefs/index.d.ts +0 -4
  52. package/dist/prompts/target-assessment/briefs/index.js +0 -4
  53. package/dist/prompts/target-assessment/briefs/liability-bullets.d.ts +0 -1
  54. package/dist/prompts/target-assessment/briefs/liability-bullets.js +0 -114
  55. package/dist/prompts/target-assessment/briefs/target-organ-liabilities.d.ts +0 -1
  56. package/dist/prompts/target-assessment/briefs/target-organ-liabilities.js +0 -37
  57. package/dist/prompts/target-assessment/briefs/translational-commentary.d.ts +0 -1
  58. package/dist/prompts/target-assessment/briefs/translational-commentary.js +0 -23
  59. package/dist/prompts/target-assessment/drugs-in-class.d.ts +0 -1
  60. package/dist/prompts/target-assessment/drugs-in-class.js +0 -29
  61. package/dist/prompts/target-assessment/investigation/adversarial-critique.d.ts +0 -1
  62. package/dist/prompts/target-assessment/investigation/adversarial-critique.js +0 -67
  63. package/dist/prompts/target-assessment/investigation/claim-reverification.d.ts +0 -1
  64. package/dist/prompts/target-assessment/investigation/claim-reverification.js +0 -49
  65. package/dist/prompts/target-assessment/investigation/index.d.ts +0 -3
  66. package/dist/prompts/target-assessment/investigation/index.js +0 -3
  67. package/dist/prompts/target-assessment/investigation/mechanism-proposal.d.ts +0 -1
  68. package/dist/prompts/target-assessment/investigation/mechanism-proposal.js +0 -49
  69. package/dist/prompts/target-assessment/modulator-triage.d.ts +0 -1
  70. package/dist/prompts/target-assessment/modulator-triage.js +0 -31
  71. package/dist/prompts/target-assessment/off-target-annotator.d.ts +0 -1
  72. package/dist/prompts/target-assessment/off-target-annotator.js +0 -28
  73. package/dist/prompts/target-assessment/tox-voice/core.d.ts +0 -1
  74. package/dist/prompts/target-assessment/tox-voice/core.js +0 -74
  75. package/dist/prompts/target-assessment/tox-voice/critique.d.ts +0 -7
  76. package/dist/prompts/target-assessment/tox-voice/critique.js +0 -109
  77. package/dist/prompts/target-assessment/tox-voice/exemplars.d.ts +0 -8
  78. package/dist/prompts/target-assessment/tox-voice/exemplars.js +0 -24
  79. package/dist/prompts/target-assessment/tox-voice/index.d.ts +0 -4
  80. package/dist/prompts/target-assessment/tox-voice/index.js +0 -4
  81. package/dist/prompts/target-assessment/tox-voice/vocabulary.d.ts +0 -18
  82. package/dist/prompts/target-assessment/tox-voice/vocabulary.js +0 -61
  83. package/dist/state/target-assessments.d.ts +0 -68
  84. package/dist/state/target-assessments.js +0 -222
  85. package/dist/workflows/execute-target-assessment.d.ts +0 -118
  86. package/dist/workflows/execute-target-assessment.js +0 -631
  87. package/dist/workflows/target-assessment/assemblers/index.d.ts +0 -5
  88. package/dist/workflows/target-assessment/assemblers/index.js +0 -4
  89. package/dist/workflows/target-assessment/assemblers/literature.d.ts +0 -281
  90. package/dist/workflows/target-assessment/assemblers/literature.js +0 -971
  91. package/dist/workflows/target-assessment/assemblers/orchestrator.d.ts +0 -118
  92. package/dist/workflows/target-assessment/assemblers/orchestrator.js +0 -945
  93. package/dist/workflows/target-assessment/assemblers/safety.d.ts +0 -374
  94. package/dist/workflows/target-assessment/assemblers/safety.js +0 -1068
  95. package/dist/workflows/target-assessment/assemblers/trials.d.ts +0 -30
  96. package/dist/workflows/target-assessment/assemblers/trials.js +0 -75
  97. package/dist/workflows/target-assessment/collectors/index.d.ts +0 -114
  98. package/dist/workflows/target-assessment/collectors/index.js +0 -538
  99. package/dist/workflows/target-assessment/coverage.d.ts +0 -97
  100. package/dist/workflows/target-assessment/coverage.js +0 -86
  101. package/dist/workflows/target-assessment/decisions/index.d.ts +0 -86
  102. package/dist/workflows/target-assessment/decisions/index.js +0 -127
  103. package/dist/workflows/target-assessment/fanout/index.d.ts +0 -32
  104. package/dist/workflows/target-assessment/fanout/index.js +0 -156
  105. package/dist/workflows/target-assessment/investigation/index.d.ts +0 -97
  106. package/dist/workflows/target-assessment/investigation/index.js +0 -419
  107. package/dist/workflows/target-assessment/lib/approval-precedents.d.ts +0 -73
  108. package/dist/workflows/target-assessment/lib/approval-precedents.js +0 -185
  109. package/dist/workflows/target-assessment/lib/citation-validator.d.ts +0 -46
  110. package/dist/workflows/target-assessment/lib/citation-validator.js +0 -316
  111. package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.d.ts +0 -65
  112. package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.js +0 -174
  113. package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.d.ts +0 -44
  114. package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.js +0 -152
  115. package/dist/workflows/target-assessment/lib/compute-derived.d.ts +0 -20
  116. package/dist/workflows/target-assessment/lib/compute-derived.js +0 -261
  117. package/dist/workflows/target-assessment/lib/compute-selectivity.d.ts +0 -15
  118. package/dist/workflows/target-assessment/lib/compute-selectivity.js +0 -18
  119. package/dist/workflows/target-assessment/lib/dedup-modulators.d.ts +0 -37
  120. package/dist/workflows/target-assessment/lib/dedup-modulators.js +0 -157
  121. package/dist/workflows/target-assessment/lib/evidence-conflict-detector.d.ts +0 -17
  122. package/dist/workflows/target-assessment/lib/evidence-conflict-detector.js +0 -100
  123. package/dist/workflows/target-assessment/lib/expression-constants.d.ts +0 -21
  124. package/dist/workflows/target-assessment/lib/expression-constants.js +0 -21
  125. package/dist/workflows/target-assessment/lib/family-complex-supplement.d.ts +0 -20
  126. package/dist/workflows/target-assessment/lib/family-complex-supplement.js +0 -36
  127. package/dist/workflows/target-assessment/lib/fda-label-safety.d.ts +0 -72
  128. package/dist/workflows/target-assessment/lib/fda-label-safety.js +0 -166
  129. package/dist/workflows/target-assessment/lib/heterodimer-filter.d.ts +0 -30
  130. package/dist/workflows/target-assessment/lib/heterodimer-filter.js +0 -44
  131. package/dist/workflows/target-assessment/lib/hpo-organ-map.d.ts +0 -34
  132. package/dist/workflows/target-assessment/lib/hpo-organ-map.js +0 -63
  133. package/dist/workflows/target-assessment/lib/impc-organ-map.d.ts +0 -19
  134. package/dist/workflows/target-assessment/lib/impc-organ-map.js +0 -39
  135. package/dist/workflows/target-assessment/lib/intended-polypharm-filter.d.ts +0 -4
  136. package/dist/workflows/target-assessment/lib/intended-polypharm-filter.js +0 -24
  137. package/dist/workflows/target-assessment/lib/llm-step.d.ts +0 -80
  138. package/dist/workflows/target-assessment/lib/llm-step.js +0 -101
  139. package/dist/workflows/target-assessment/lib/meddra-organ-map.d.ts +0 -40
  140. package/dist/workflows/target-assessment/lib/meddra-organ-map.js +0 -138
  141. package/dist/workflows/target-assessment/lib/recommendation-quality-gates.d.ts +0 -17
  142. package/dist/workflows/target-assessment/lib/recommendation-quality-gates.js +0 -99
  143. package/dist/workflows/target-assessment/lib/recommendation-sanitizer.d.ts +0 -2
  144. package/dist/workflows/target-assessment/lib/recommendation-sanitizer.js +0 -51
  145. package/dist/workflows/target-assessment/lib/regulatory-actions.d.ts +0 -25
  146. package/dist/workflows/target-assessment/lib/regulatory-actions.js +0 -176
  147. package/dist/workflows/target-assessment/lib/safety-corroboration.d.ts +0 -44
  148. package/dist/workflows/target-assessment/lib/safety-corroboration.js +0 -273
  149. package/dist/workflows/target-assessment/lib/structured-llm.d.ts +0 -61
  150. package/dist/workflows/target-assessment/lib/structured-llm.js +0 -102
  151. package/dist/workflows/target-assessment/lib/target-identity-filter.d.ts +0 -59
  152. package/dist/workflows/target-assessment/lib/target-identity-filter.js +0 -95
  153. package/dist/workflows/target-assessment/lib/therapeutic-programs.d.ts +0 -20
  154. package/dist/workflows/target-assessment/lib/therapeutic-programs.js +0 -68
  155. package/dist/workflows/target-assessment/metrics.d.ts +0 -16
  156. package/dist/workflows/target-assessment/metrics.js +0 -30
  157. package/dist/workflows/target-assessment/phase4-assemble.d.ts +0 -3182
  158. package/dist/workflows/target-assessment/phase4-assemble.js +0 -39
  159. package/dist/workflows/target-assessment/phase5-persist.d.ts +0 -59
  160. package/dist/workflows/target-assessment/phase5-persist.js +0 -349
  161. package/dist/workflows/target-assessment/progress-stream.d.ts +0 -75
  162. package/dist/workflows/target-assessment/progress-stream.js +0 -110
  163. package/dist/workflows/target-assessment/progress.d.ts +0 -39
  164. package/dist/workflows/target-assessment/progress.js +0 -77
  165. package/dist/workflows/target-assessment/schemas.d.ts +0 -970
  166. package/dist/workflows/target-assessment/schemas.js +0 -318
  167. package/dist/workflows/target-assessment/steps/collectors/pathways.d.ts +0 -15
  168. package/dist/workflows/target-assessment/steps/collectors/pathways.js +0 -58
  169. package/dist/workflows/target-assessment/steps/fanout/aes-for-one-class-drug-step.d.ts +0 -34
  170. package/dist/workflows/target-assessment/steps/fanout/aes-for-one-class-drug-step.js +0 -31
  171. package/dist/workflows/target-assessment/steps/fanout/aes-for-one-trial-step.d.ts +0 -57
  172. package/dist/workflows/target-assessment/steps/fanout/aes-for-one-trial-step.js +0 -54
  173. package/dist/workflows/target-assessment/steps/fanout/faers-for-one-modulator-step.d.ts +0 -35
  174. package/dist/workflows/target-assessment/steps/fanout/faers-for-one-modulator-step.js +0 -32
  175. package/dist/workflows/target-assessment/steps/fanout/index.d.ts +0 -14
  176. package/dist/workflows/target-assessment/steps/fanout/index.js +0 -10
  177. package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.d.ts +0 -29
  178. package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.js +0 -29
  179. package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +0 -657
  180. package/dist/workflows/target-assessment/steps/phase2-aggregate.js +0 -34
  181. package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +0 -806
  182. package/dist/workflows/target-assessment/steps/phase3-aggregate.js +0 -16
  183. package/dist/workflows/target-assessment/steps/synthesis/diagnostics.d.ts +0 -28
  184. package/dist/workflows/target-assessment/steps/synthesis/diagnostics.js +0 -27
  185. package/dist/workflows/target-assessment/sub-workflows/index.d.ts +0 -15
  186. package/dist/workflows/target-assessment/sub-workflows/index.js +0 -11
  187. package/dist/workflows/target-assessment/sub-workflows/per-class-drug-aes.d.ts +0 -41
  188. package/dist/workflows/target-assessment/sub-workflows/per-class-drug-aes.js +0 -12
  189. package/dist/workflows/target-assessment/sub-workflows/per-modulator-faers.d.ts +0 -41
  190. package/dist/workflows/target-assessment/sub-workflows/per-modulator-faers.js +0 -12
  191. package/dist/workflows/target-assessment/sub-workflows/per-modulator-polypharm.d.ts +0 -37
  192. package/dist/workflows/target-assessment/sub-workflows/per-modulator-polypharm.js +0 -12
  193. package/dist/workflows/target-assessment/sub-workflows/per-trial-aes.d.ts +0 -66
  194. package/dist/workflows/target-assessment/sub-workflows/per-trial-aes.js +0 -12
  195. package/dist/workflows/target-assessment/synthesis/index.d.ts +0 -607
  196. package/dist/workflows/target-assessment/synthesis/index.js +0 -354
  197. package/dist/workflows/target-assessment/synthesis-probes.d.ts +0 -56
  198. package/dist/workflows/target-assessment/synthesis-probes.js +0 -320
@@ -1,86 +0,0 @@
1
- /**
2
- * Shared coverage discriminator for target-assessment workflow steps.
3
- *
4
- * Per design §6, every collector / decision / fan-out / synthesis step
5
- * MUST wrap its body in try/catch and return a `{ coverage, ... }` shape
6
- * instead of throwing. Only Phase 0 (target resolution) is allowed to
7
- * throw — that legitimately aborts the workflow.
8
- *
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.
14
- */
15
- import { z } from "zod";
16
- export const SerializedErrorSchema = z.object({
17
- message: z.string(),
18
- name: z.string().optional(),
19
- stack: z.string().optional(),
20
- });
21
- /**
22
- * Build the schema for a `{ coverage, data, error? }` step output.
23
- *
24
- * Use as: `outputSchema: withCoverage(MyDataSchema)` where `MyDataSchema`
25
- * is the shape of the Phase-1 / Phase-2 / etc. payload for this step.
26
- */
27
- export function withCoverage(dataSchema) {
28
- return z.discriminatedUnion("coverage", [
29
- z.object({
30
- coverage: z.literal("available"),
31
- data: dataSchema,
32
- }),
33
- z.object({
34
- coverage: z.literal("queried_no_data"),
35
- error: SerializedErrorSchema.optional(),
36
- }),
37
- z.object({
38
- coverage: z.literal("not_loaded"),
39
- reason: z.string().optional(),
40
- }),
41
- ]);
42
- }
43
- /**
44
- * Convenience wrapper for `{ rows: T[] }` payloads. Maps an empty rows
45
- * array to `coverage: "queried_no_data"` so the dossier discriminator's
46
- * "available ≡ we have data" invariant holds without per-callsite
47
- * length checks. Use at any assembler callsite that emits a `rows`
48
- * shape from a query that may legitimately return zero items.
49
- */
50
- export function coverageFromRows(rows, opts) {
51
- if (rows.length === 0) {
52
- return {
53
- coverage: "queried_no_data",
54
- error: { message: opts?.reason ?? "no rows returned" },
55
- };
56
- }
57
- return { coverage: "available", data: { rows } };
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
- }
@@ -1,86 +0,0 @@
1
- /**
2
- * Phase-2 decision functions for the harness DBOS workflow.
3
- *
4
- * `modulatorTriage` selects up to 8 ChEMBL modulators for downstream
5
- * fan-out; `drugsInClass` identifies clinically-advanced drugs in the
6
- * class. Both are single-shot, structured-output LLM calls — no tools,
7
- * no multi-step reasoning. Each function is `(input, deps) => Promise<CoverageEnvelope<...>>`.
8
- *
9
- * Coverage envelope is the failure mode: an LLM throw (non-402) → the
10
- * function returns `coverage: "queried_no_data"`. A billing-gateway 402 reaches
11
- * here as a `RunLlmStepResult` with `kind: "budget-exceeded"`; the caller
12
- * stops scheduling because the workflow has self-cancelled.
13
- */
14
- import { z } from "zod";
15
- import type { AgentSession } from "../../../auth/types.js";
16
- import type { AgentChat } from "../../../providers/types.js";
17
- import type { Phase1Bundle } from "../schemas.js";
18
- import { BUDGET_EXCEEDED_SENTINEL } from "../lib/llm-step.js";
19
- export declare const ModulatorTriageOutputSchema: z.ZodObject<{
20
- shortlist: z.ZodArray<z.ZodObject<{
21
- moleculeChemblId: z.ZodString;
22
- preferredName: z.ZodString;
23
- maxPhase: z.ZodNullable<z.ZodNumber>;
24
- firstApproval: z.ZodNullable<z.ZodNumber>;
25
- rationale: z.ZodString;
26
- }, z.core.$strip>>;
27
- notes: z.ZodString;
28
- dropped_synonyms: z.ZodDefault<z.ZodArray<z.ZodObject<{
29
- chemblId: z.ZodString;
30
- reason: z.ZodEnum<{
31
- same_active_substance: "same_active_substance";
32
- ambiguous_name_synonym: "ambiguous_name_synonym";
33
- }>;
34
- keptId: z.ZodNullable<z.ZodString>;
35
- }, z.core.$strip>>>;
36
- }, z.core.$strip>;
37
- export type ModulatorTriageOutput = z.infer<typeof ModulatorTriageOutputSchema>;
38
- export declare const DrugsInClassOutputSchema: z.ZodObject<{
39
- drugs: z.ZodArray<z.ZodObject<{
40
- moleculeChemblId: z.ZodString;
41
- preferredName: z.ZodString;
42
- maxPhase: z.ZodNullable<z.ZodNumber>;
43
- firstApproval: z.ZodNullable<z.ZodNumber>;
44
- moleculeType: z.ZodNullable<z.ZodString>;
45
- sources: z.ZodArray<z.ZodEnum<{
46
- dgidb: "dgidb";
47
- drugbank: "drugbank";
48
- chembl: "chembl";
49
- }>>;
50
- }, z.core.$strip>>;
51
- total: z.ZodNumber;
52
- truncated: z.ZodBoolean;
53
- }, z.core.$strip>;
54
- export type DrugsInClassOutput = z.infer<typeof DrugsInClassOutputSchema>;
55
- interface CoverageAvailable<T> {
56
- readonly coverage: "available";
57
- readonly data: T;
58
- }
59
- interface CoverageQueriedNoData {
60
- readonly coverage: "queried_no_data";
61
- readonly error?: {
62
- message: string;
63
- };
64
- }
65
- type CoverageEnvelope<T> = CoverageAvailable<T> | CoverageQueriedNoData;
66
- export interface DecisionAgentDeps {
67
- readonly chatProvider: AgentChat;
68
- readonly session: AgentSession;
69
- /** Billing-gateway model id — e.g. `env.TARGET_ASSESSMENT_DECISION_MODEL`. */
70
- readonly model: string;
71
- /** Attempt counter — bumped on resume so a 402-cancelled call lands a fresh DBOS step slot. */
72
- readonly attempt: number;
73
- }
74
- export type ModulatorTriageResult = CoverageEnvelope<ModulatorTriageOutput & {
75
- dropped_synonyms?: unknown;
76
- }> | {
77
- readonly kind: "budget-exceeded";
78
- readonly sentinel: typeof BUDGET_EXCEEDED_SENTINEL;
79
- };
80
- export declare function modulatorTriage(input: Phase1Bundle, deps: DecisionAgentDeps): Promise<ModulatorTriageResult>;
81
- export type DrugsInClassResult = CoverageEnvelope<DrugsInClassOutput> | {
82
- readonly kind: "budget-exceeded";
83
- readonly sentinel: typeof BUDGET_EXCEEDED_SENTINEL;
84
- };
85
- export declare function drugsInClass(input: Phase1Bundle, deps: DecisionAgentDeps): Promise<DrugsInClassResult>;
86
- export {};
@@ -1,127 +0,0 @@
1
- /**
2
- * Phase-2 decision functions for the harness DBOS workflow.
3
- *
4
- * `modulatorTriage` selects up to 8 ChEMBL modulators for downstream
5
- * fan-out; `drugsInClass` identifies clinically-advanced drugs in the
6
- * class. Both are single-shot, structured-output LLM calls — no tools,
7
- * no multi-step reasoning. Each function is `(input, deps) => Promise<CoverageEnvelope<...>>`.
8
- *
9
- * Coverage envelope is the failure mode: an LLM throw (non-402) → the
10
- * function returns `coverage: "queried_no_data"`. A billing-gateway 402 reaches
11
- * here as a `RunLlmStepResult` with `kind: "budget-exceeded"`; the caller
12
- * stops scheduling because the workflow has self-cancelled.
13
- */
14
- import { z } from "zod";
15
- import { drugsInClassPrompt } from "../../../prompts/target-assessment/drugs-in-class.js";
16
- import { modulatorTriagePrompt } from "../../../prompts/target-assessment/modulator-triage.js";
17
- import { dedupModulatorsByParent } from "../lib/dedup-modulators.js";
18
- import { structuredLlmCall } from "../lib/structured-llm.js";
19
- // ── Output schemas ────────────────────────────────────────────────────
20
- export const ModulatorTriageOutputSchema = z.object({
21
- shortlist: z.array(z.object({
22
- moleculeChemblId: z.string(),
23
- preferredName: z.string(),
24
- maxPhase: z.number().nullable(),
25
- firstApproval: z.number().nullable(),
26
- rationale: z.string(),
27
- })),
28
- notes: z.string(),
29
- dropped_synonyms: z
30
- .array(z.object({
31
- chemblId: z.string(),
32
- reason: z.enum(["same_active_substance", "ambiguous_name_synonym"]),
33
- keptId: z.string().nullable(),
34
- }))
35
- .default([]),
36
- });
37
- export const DrugsInClassOutputSchema = z.object({
38
- drugs: z.array(z.object({
39
- moleculeChemblId: z.string(),
40
- preferredName: z.string(),
41
- maxPhase: z.number().nullable(),
42
- firstApproval: z.number().nullable(),
43
- moleculeType: z.string().nullable(),
44
- sources: z.array(z.enum(["chembl", "dgidb", "drugbank"])),
45
- })),
46
- total: z.number(),
47
- truncated: z.boolean(),
48
- });
49
- function fail(message) {
50
- return { coverage: "queried_no_data", error: { message } };
51
- }
52
- function failFromErr(err) {
53
- return fail(err instanceof Error ? err.message : String(err));
54
- }
55
- export async function modulatorTriage(input, deps) {
56
- const modulators = input.collectors.chemblModulators;
57
- if (modulators.coverage !== "available" || modulators.data.modulators.length === 0) {
58
- return fail("no modulators to triage");
59
- }
60
- const { kept, dropped } = dedupModulatorsByParent(modulators.data.modulators);
61
- if (kept.length === 0) {
62
- return fail("no modulators after dedup");
63
- }
64
- const prompt = [
65
- `Target: ${input.resolved.geneSymbol} (${input.resolved.canonicalId})`,
66
- `ChEMBL target id: ${modulators.data.targetChemblId ?? "unknown"}`,
67
- ``,
68
- `Modulators (${kept.length}, deduped from ${modulators.data.modulators.length}):`,
69
- JSON.stringify(kept, null, 2),
70
- ].join("\n");
71
- try {
72
- const result = await structuredLlmCall({
73
- stepName: `ta-decision:modulator-triage:${deps.attempt}`,
74
- agentId: "modulator-triage",
75
- provider: deps.chatProvider,
76
- session: deps.session,
77
- system: modulatorTriagePrompt,
78
- prompt,
79
- schema: ModulatorTriageOutputSchema,
80
- model: deps.model,
81
- });
82
- if (result.kind === "budget-exceeded") {
83
- return { kind: "budget-exceeded", sentinel: result.sentinel };
84
- }
85
- return {
86
- coverage: "available",
87
- data: { ...result.value, dropped_synonyms: dropped },
88
- };
89
- }
90
- catch (err) {
91
- return failFromErr(err);
92
- }
93
- }
94
- export async function drugsInClass(input, deps) {
95
- const modulators = input.collectors.chemblModulators;
96
- if (modulators.coverage !== "available" || modulators.data.modulators.length === 0) {
97
- return fail("no modulators in class");
98
- }
99
- const { kept } = dedupModulatorsByParent(modulators.data.modulators);
100
- if (kept.length === 0) {
101
- return fail("no modulators after dedup");
102
- }
103
- const prompt = [
104
- `Target: ${input.resolved.geneSymbol}`,
105
- `ChEMBL modulators (max_phase ≥ 2, deduped by active substance):`,
106
- JSON.stringify(kept, null, 2),
107
- ].join("\n");
108
- try {
109
- const result = await structuredLlmCall({
110
- stepName: `ta-decision:drugs-in-class:${deps.attempt}`,
111
- agentId: "drugs-in-class",
112
- provider: deps.chatProvider,
113
- session: deps.session,
114
- system: drugsInClassPrompt,
115
- prompt,
116
- schema: DrugsInClassOutputSchema,
117
- model: deps.model,
118
- });
119
- if (result.kind === "budget-exceeded") {
120
- return { kind: "budget-exceeded", sentinel: result.sentinel };
121
- }
122
- return { coverage: "available", data: result.value };
123
- }
124
- catch (err) {
125
- return failFromErr(err);
126
- }
127
- }
@@ -1,32 +0,0 @@
1
- /**
2
- * Phase-3 fan-out item functions for the harness DBOS workflow.
3
- *
4
- * Each function operates on one item (one modulator, one trial, one class
5
- * drug) and returns a coverage envelope. The DBOS workflow body iterates
6
- * the item list and dispatches each via `DBOS.runStep` with a deterministic
7
- * step name `"ta-fanout:{kind}:{itemKey}"`. The `withHost` semaphore inside
8
- * each body caps openFDA / ChEMBL / ctgov in-flight at 4.
9
- *
10
- * No throws — coverage envelope is the failure mode. Recovery replays the
11
- * cached envelope from the DBOS step cache.
12
- */
13
- import type { Logger } from "../../../lib/logger.js";
14
- import type { SerializedError } from "../coverage.js";
15
- import type { ClassDrugItem, PerClassDrugAEsItem } from "../steps/fanout/aes-for-one-class-drug-step.js";
16
- import type { PerTrialAEsItem, TrialItem } from "../steps/fanout/aes-for-one-trial-step.js";
17
- import type { ModulatorItem, PerModulatorFaersItem } from "../steps/fanout/faers-for-one-modulator-step.js";
18
- import type { PerModulatorPolypharmItem, PolypharmInputItem } from "../steps/fanout/polypharm-for-one-modulator-step.js";
19
- export type { ClassDrugItem, ModulatorItem, PerClassDrugAEsItem, PerModulatorFaersItem, PerModulatorPolypharmItem, PerTrialAEsItem, PolypharmInputItem, TrialItem, };
20
- type CoverageAvailable<T> = {
21
- coverage: "available";
22
- data: T;
23
- };
24
- type CoverageQueriedNoData = {
25
- coverage: "queried_no_data";
26
- error?: SerializedError;
27
- };
28
- type CoverageEnvelope<T> = CoverageAvailable<T> | CoverageQueriedNoData;
29
- export declare function faersForOneModulator(item: ModulatorItem): Promise<CoverageEnvelope<PerModulatorFaersItem>>;
30
- export declare function polypharmForOneModulator(item: PolypharmInputItem, logger?: Logger): Promise<CoverageEnvelope<PerModulatorPolypharmItem>>;
31
- export declare function aesForOneTrial(item: TrialItem): Promise<CoverageEnvelope<PerTrialAEsItem>>;
32
- export declare function aesForOneClassDrug(item: ClassDrugItem): Promise<CoverageEnvelope<PerClassDrugAEsItem>>;
@@ -1,156 +0,0 @@
1
- /**
2
- * Phase-3 fan-out item functions for the harness DBOS workflow.
3
- *
4
- * Each function operates on one item (one modulator, one trial, one class
5
- * drug) and returns a coverage envelope. The DBOS workflow body iterates
6
- * the item list and dispatches each via `DBOS.runStep` with a deterministic
7
- * step name `"ta-fanout:{kind}:{itemKey}"`. The `withHost` semaphore inside
8
- * each body caps openFDA / ChEMBL / ctgov in-flight at 4.
9
- *
10
- * No throws — coverage envelope is the failure mode. Recovery replays the
11
- * cached envelope from the DBOS step cache.
12
- */
13
- import { withHost } from "../../../lib/host-concurrency.js";
14
- import { getModulatorOnTargetPchembl, getModulatorPolypharmacology } from "../../../tools/lib/chembl-client.js";
15
- import { getTrialDetails } from "../../../tools/lib/clinical-trials-client.js";
16
- import { getFaersByDrug, getFaersSeriousness } from "../../../tools/lib/openfda-client.js";
17
- function fail(message) {
18
- return { coverage: "queried_no_data", error: { message } };
19
- }
20
- function failFromErr(err) {
21
- return fail(err instanceof Error ? err.message : String(err));
22
- }
23
- // ── Per-modulator FAERS ──────────────────────────────────────────────
24
- export async function faersForOneModulator(item) {
25
- const probe = item.preferredName;
26
- if (!probe) {
27
- return fail(`no preferred name for ${item.moleculeChemblId}`);
28
- }
29
- try {
30
- const [byDrug, seriousness] = await Promise.all([
31
- withHost("openfda", () => getFaersByDrug(probe, { limit: 10 })),
32
- withHost("openfda", () => getFaersSeriousness(probe)),
33
- ]);
34
- const total = byDrug.totalReports ?? 0;
35
- if (total === 0 && byDrug.adverseEvents.length === 0) {
36
- return fail(`FAERS returned no reports for ${probe}`);
37
- }
38
- if (seriousness !== null &&
39
- seriousness.totalReports >= 1000 &&
40
- seriousness.fatalCount === 0 &&
41
- seriousness.hospitalizationCount === 0 &&
42
- seriousness.lifeThreateningCount === 0 &&
43
- seriousness.disablingCount === 0 &&
44
- seriousness.congenitalAnomalyCount === 0 &&
45
- seriousness.otherSeriousCount === 0) {
46
- return fail(`FAERS seriousness all-zero across ${seriousness.totalReports} reports for ${probe}; openFDA seriousness fields not reliably populated`);
47
- }
48
- return {
49
- coverage: "available",
50
- data: {
51
- moleculeChemblId: item.moleculeChemblId,
52
- preferredName: probe,
53
- totalReports: byDrug.totalReports ?? null,
54
- topReactions: byDrug.adverseEvents,
55
- seriousness,
56
- },
57
- };
58
- }
59
- catch (err) {
60
- return failFromErr(err);
61
- }
62
- }
63
- // ── Per-modulator polypharmacology ──────────────────────────────────
64
- export async function polypharmForOneModulator(item, logger) {
65
- try {
66
- const [hits, primaryPchembl] = await Promise.all([
67
- withHost("chembl", () => getModulatorPolypharmacology(item.moleculeChemblId, {
68
- minPchembl: 5,
69
- excludeTargetChemblId: item.primaryTargetChemblId ?? undefined,
70
- limit: 200,
71
- })),
72
- item.primaryTargetChemblId
73
- ? withHost("chembl", () => getModulatorOnTargetPchembl(item.moleculeChemblId, item.primaryTargetChemblId, logger))
74
- : Promise.resolve(null),
75
- ]);
76
- if (hits.length === 0) {
77
- return fail(`no polypharm hits for ${item.moleculeChemblId}`);
78
- }
79
- return {
80
- coverage: "available",
81
- data: {
82
- moleculeChemblId: item.moleculeChemblId,
83
- preferredName: item.preferredName,
84
- primaryPchembl,
85
- hits: hits.map((h) => ({
86
- targetChemblId: h.targetChemblId,
87
- targetName: h.targetName,
88
- assayChemblId: h.assayChemblId,
89
- pchemblValue: h.pchemblValue,
90
- standardType: h.standardType,
91
- standardValue: h.standardValue,
92
- standardUnits: h.standardUnits,
93
- })),
94
- },
95
- };
96
- }
97
- catch (err) {
98
- return failFromErr(err);
99
- }
100
- }
101
- // ── Per-trial AEs ────────────────────────────────────────────────────
102
- export async function aesForOneTrial(item) {
103
- try {
104
- const details = await withHost("ctgov", () => getTrialDetails(item.nctId));
105
- if (!details) {
106
- return fail(`no details for ${item.nctId}`);
107
- }
108
- if (details.adverseEvents.length === 0 && details.outcomes.length === 0) {
109
- return fail(`no AE/outcome rows for ${item.nctId}`);
110
- }
111
- return {
112
- coverage: "available",
113
- data: {
114
- nctId: item.nctId,
115
- title: item.title,
116
- whyStopped: details.whyStopped,
117
- outcomes: details.outcomes,
118
- groups: details.adverseEventGroups,
119
- events: details.adverseEvents,
120
- },
121
- };
122
- }
123
- catch (err) {
124
- return failFromErr(err);
125
- }
126
- }
127
- // ── Per-class-drug AEs ───────────────────────────────────────────────
128
- export async function aesForOneClassDrug(item) {
129
- const probe = item.preferredName;
130
- if (!probe) {
131
- return fail(`no preferred name for ${item.moleculeChemblId}`);
132
- }
133
- try {
134
- const [byDrug, seriousness] = await Promise.all([
135
- withHost("openfda", () => getFaersByDrug(probe, { limit: 10 })),
136
- withHost("openfda", () => getFaersSeriousness(probe)),
137
- ]);
138
- const total = byDrug.totalReports ?? 0;
139
- if (total === 0 && byDrug.adverseEvents.length === 0) {
140
- return fail(`FAERS returned no reports for ${probe}`);
141
- }
142
- return {
143
- coverage: "available",
144
- data: {
145
- moleculeChemblId: item.moleculeChemblId,
146
- preferredName: probe,
147
- totalReports: byDrug.totalReports ?? null,
148
- topReactions: byDrug.adverseEvents,
149
- seriousness,
150
- },
151
- };
152
- }
153
- catch (err) {
154
- return failFromErr(err);
155
- }
156
- }
@@ -1,97 +0,0 @@
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 };