@inflexa-ai/harness 0.1.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 (823) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +5 -0
  3. package/README.md +58 -0
  4. package/dist/agents/conversation-agent.d.ts +105 -0
  5. package/dist/agents/conversation-agent.js +140 -0
  6. package/dist/agents/report-builder.d.ts +32 -0
  7. package/dist/agents/report-builder.js +31 -0
  8. package/dist/agents/sandbox/__fixtures__/deps.d.ts +23 -0
  9. package/dist/agents/sandbox/__fixtures__/deps.js +96 -0
  10. package/dist/agents/sandbox/bulk-transcriptomics-agent.d.ts +8 -0
  11. package/dist/agents/sandbox/bulk-transcriptomics-agent.js +22 -0
  12. package/dist/agents/sandbox/cheminformatics-agent.d.ts +9 -0
  13. package/dist/agents/sandbox/cheminformatics-agent.js +62 -0
  14. package/dist/agents/sandbox/chromatin-agent.d.ts +8 -0
  15. package/dist/agents/sandbox/chromatin-agent.js +24 -0
  16. package/dist/agents/sandbox/data-profiler.d.ts +10 -0
  17. package/dist/agents/sandbox/data-profiler.js +24 -0
  18. package/dist/agents/sandbox/dna-methylation-agent.d.ts +8 -0
  19. package/dist/agents/sandbox/dna-methylation-agent.js +24 -0
  20. package/dist/agents/sandbox/drug-repurposing-agent.d.ts +8 -0
  21. package/dist/agents/sandbox/drug-repurposing-agent.js +54 -0
  22. package/dist/agents/sandbox/enrichment-agent.d.ts +8 -0
  23. package/dist/agents/sandbox/enrichment-agent.js +24 -0
  24. package/dist/agents/sandbox/ephemeral-executor.d.ts +9 -0
  25. package/dist/agents/sandbox/ephemeral-executor.js +29 -0
  26. package/dist/agents/sandbox/genomic-variant-agent.d.ts +8 -0
  27. package/dist/agents/sandbox/genomic-variant-agent.js +27 -0
  28. package/dist/agents/sandbox/immune-profiling-agent.d.ts +8 -0
  29. package/dist/agents/sandbox/immune-profiling-agent.js +43 -0
  30. package/dist/agents/sandbox/index.d.ts +31 -0
  31. package/dist/agents/sandbox/index.js +96 -0
  32. package/dist/agents/sandbox/metabolomics-agent.d.ts +8 -0
  33. package/dist/agents/sandbox/metabolomics-agent.js +15 -0
  34. package/dist/agents/sandbox/microbiome-agent.d.ts +8 -0
  35. package/dist/agents/sandbox/microbiome-agent.js +15 -0
  36. package/dist/agents/sandbox/multi-omics-integration-agent.d.ts +8 -0
  37. package/dist/agents/sandbox/multi-omics-integration-agent.js +33 -0
  38. package/dist/agents/sandbox/multimodal-sc-agent.d.ts +8 -0
  39. package/dist/agents/sandbox/multimodal-sc-agent.js +15 -0
  40. package/dist/agents/sandbox/network-agent.d.ts +8 -0
  41. package/dist/agents/sandbox/network-agent.js +25 -0
  42. package/dist/agents/sandbox/pkpd-clinical-response-agent.d.ts +8 -0
  43. package/dist/agents/sandbox/pkpd-clinical-response-agent.js +59 -0
  44. package/dist/agents/sandbox/proteomics-agent.d.ts +8 -0
  45. package/dist/agents/sandbox/proteomics-agent.js +15 -0
  46. package/dist/agents/sandbox/scientific-executor.d.ts +9 -0
  47. package/dist/agents/sandbox/scientific-executor.js +56 -0
  48. package/dist/agents/sandbox/shared.d.ts +100 -0
  49. package/dist/agents/sandbox/shared.js +195 -0
  50. package/dist/agents/sandbox/single-cell-agent.d.ts +8 -0
  51. package/dist/agents/sandbox/single-cell-agent.js +25 -0
  52. package/dist/agents/sandbox/spatial-omics-agent.d.ts +8 -0
  53. package/dist/agents/sandbox/spatial-omics-agent.js +15 -0
  54. package/dist/agents/sandbox/statistical-modeling-agent.d.ts +8 -0
  55. package/dist/agents/sandbox/statistical-modeling-agent.js +37 -0
  56. package/dist/agents/sandbox/translational-safety-agent.d.ts +8 -0
  57. package/dist/agents/sandbox/translational-safety-agent.js +59 -0
  58. package/dist/agents/sandbox/types.d.ts +34 -0
  59. package/dist/agents/sandbox/types.js +15 -0
  60. package/dist/agents/sandbox/validate-skills.d.ts +18 -0
  61. package/dist/agents/sandbox/validate-skills.js +40 -0
  62. package/dist/agents/sandbox-catalog.d.ts +33 -0
  63. package/dist/agents/sandbox-catalog.js +44 -0
  64. package/dist/agents/system-prompt.d.ts +25 -0
  65. package/dist/agents/system-prompt.js +23 -0
  66. package/dist/app/chat-turn.d.ts +35 -0
  67. package/dist/app/chat-turn.js +64 -0
  68. package/dist/app/data-profile-policy.d.ts +36 -0
  69. package/dist/app/data-profile-policy.js +37 -0
  70. package/dist/app/message-assembly.d.ts +65 -0
  71. package/dist/app/message-assembly.js +61 -0
  72. package/dist/app/synthesize-run.d.ts +57 -0
  73. package/dist/app/synthesize-run.js +103 -0
  74. package/dist/auth/local-auth-context.d.ts +19 -0
  75. package/dist/auth/local-auth-context.js +20 -0
  76. package/dist/auth/local-run-authorizer.d.ts +10 -0
  77. package/dist/auth/local-run-authorizer.js +23 -0
  78. package/dist/auth/types.d.ts +166 -0
  79. package/dist/auth/types.js +61 -0
  80. package/dist/billing/cached-resolver.d.ts +23 -0
  81. package/dist/billing/cached-resolver.js +61 -0
  82. package/dist/billing/noop-resolver.d.ts +6 -0
  83. package/dist/billing/noop-resolver.js +7 -0
  84. package/dist/billing/noop-run-charge.d.ts +6 -0
  85. package/dist/billing/noop-run-charge.js +10 -0
  86. package/dist/billing/resolver.d.ts +64 -0
  87. package/dist/billing/resolver.js +24 -0
  88. package/dist/billing/run-charge.d.ts +24 -0
  89. package/dist/billing/run-charge.js +9 -0
  90. package/dist/config/resource-limits.d.ts +76 -0
  91. package/dist/config/resource-limits.js +116 -0
  92. package/dist/contracts/analogy-report.d.ts +120 -0
  93. package/dist/contracts/analogy-report.js +50 -0
  94. package/dist/contracts/chat-events.d.ts +61 -0
  95. package/dist/contracts/chat-events.js +13 -0
  96. package/dist/contracts/chat-parts.d.ts +308 -0
  97. package/dist/contracts/chat-parts.js +13 -0
  98. package/dist/contracts/content-url.d.ts +49 -0
  99. package/dist/contracts/content-url.js +56 -0
  100. package/dist/contracts/index.d.ts +12 -0
  101. package/dist/contracts/index.js +5 -0
  102. package/dist/contracts/message.d.ts +36 -0
  103. package/dist/contracts/message.js +9 -0
  104. package/dist/contracts/part-registry.d.ts +18 -0
  105. package/dist/contracts/part-registry.js +28 -0
  106. package/dist/contracts/schemas/chat-events.d.ts +90 -0
  107. package/dist/contracts/schemas/chat-events.js +43 -0
  108. package/dist/contracts/schemas/chat-parts.d.ts +683 -0
  109. package/dist/contracts/schemas/chat-parts.js +295 -0
  110. package/dist/contracts/schemas/index.d.ts +2 -0
  111. package/dist/contracts/schemas/index.js +2 -0
  112. package/dist/contracts/target-assessment-row.d.ts +85 -0
  113. package/dist/contracts/target-assessment-row.js +37 -0
  114. package/dist/contracts/target-dossier.d.ts +16720 -0
  115. package/dist/contracts/target-dossier.js +1339 -0
  116. package/dist/data/clinical-benchmarks.json +108 -0
  117. package/dist/data/protein-family-modality.json +101 -0
  118. package/dist/data/safety-panel-schema.d.ts +64 -0
  119. package/dist/data/safety-panel-schema.js +34 -0
  120. package/dist/data/safety-panel.json +436 -0
  121. package/dist/execution/artifact-metadata.d.ts +74 -0
  122. package/dist/execution/artifact-metadata.js +203 -0
  123. package/dist/execution/artifact-record.d.ts +19 -0
  124. package/dist/execution/artifact-record.js +7 -0
  125. package/dist/execution/artifact-registration.d.ts +36 -0
  126. package/dist/execution/artifact-registration.js +61 -0
  127. package/dist/execution/artifact-registry.d.ts +82 -0
  128. package/dist/execution/artifact-registry.js +17 -0
  129. package/dist/execution/dbos-run-launcher.d.ts +7 -0
  130. package/dist/execution/dbos-run-launcher.js +38 -0
  131. package/dist/execution/ephemeral-runner.d.ts +81 -0
  132. package/dist/execution/ephemeral-runner.js +161 -0
  133. package/dist/execution/filesystem-artifact-registry.d.ts +57 -0
  134. package/dist/execution/filesystem-artifact-registry.js +92 -0
  135. package/dist/execution/noop-artifact-registry.d.ts +11 -0
  136. package/dist/execution/noop-artifact-registry.js +17 -0
  137. package/dist/execution/post-step-pipeline.d.ts +70 -0
  138. package/dist/execution/post-step-pipeline.js +207 -0
  139. package/dist/execution/post-step.d.ts +20 -0
  140. package/dist/execution/post-step.js +65 -0
  141. package/dist/execution/reconcile-manifest.d.ts +25 -0
  142. package/dist/execution/reconcile-manifest.js +132 -0
  143. package/dist/execution/report-render.d.ts +39 -0
  144. package/dist/execution/report-render.js +98 -0
  145. package/dist/execution/report-runner.d.ts +87 -0
  146. package/dist/execution/report-runner.js +227 -0
  147. package/dist/execution/run-authorizer.d.ts +43 -0
  148. package/dist/execution/run-authorizer.js +17 -0
  149. package/dist/execution/run-launcher.d.ts +36 -0
  150. package/dist/execution/run-launcher.js +15 -0
  151. package/dist/execution/run-synthesis.d.ts +107 -0
  152. package/dist/execution/run-synthesis.js +329 -0
  153. package/dist/execution/staged-input.d.ts +41 -0
  154. package/dist/execution/staged-input.js +15 -0
  155. package/dist/execution/step-summary-metrics.d.ts +10 -0
  156. package/dist/execution/step-summary-metrics.js +22 -0
  157. package/dist/execution/step-summary.d.ts +55 -0
  158. package/dist/execution/step-summary.js +106 -0
  159. package/dist/execution/topo-sort.d.ts +33 -0
  160. package/dist/execution/topo-sort.js +99 -0
  161. package/dist/index.d.ts +112 -0
  162. package/dist/index.js +157 -0
  163. package/dist/input-sanitization.d.ts +22 -0
  164. package/dist/input-sanitization.js +64 -0
  165. package/dist/lib/async-utils.d.ts +10 -0
  166. package/dist/lib/async-utils.js +24 -0
  167. package/dist/lib/chrome.d.ts +15 -0
  168. package/dist/lib/chrome.js +95 -0
  169. package/dist/lib/db-result.d.ts +93 -0
  170. package/dist/lib/db-result.js +197 -0
  171. package/dist/lib/fs-helpers.d.ts +74 -0
  172. package/dist/lib/fs-helpers.js +119 -0
  173. package/dist/lib/fs-result.d.ts +98 -0
  174. package/dist/lib/fs-result.js +137 -0
  175. package/dist/lib/host-concurrency.d.ts +16 -0
  176. package/dist/lib/host-concurrency.js +60 -0
  177. package/dist/lib/identifiers.d.ts +8 -0
  178. package/dist/lib/identifiers.js +10 -0
  179. package/dist/lib/metrics.d.ts +7 -0
  180. package/dist/lib/metrics.js +12 -0
  181. package/dist/lib/mime-detect.d.ts +17 -0
  182. package/dist/lib/mime-detect.js +29 -0
  183. package/dist/lib/otel.d.ts +30 -0
  184. package/dist/lib/otel.js +102 -0
  185. package/dist/lib/regulatory-corpus/fetch-fda-guidance.d.ts +35 -0
  186. package/dist/lib/regulatory-corpus/fetch-fda-guidance.js +107 -0
  187. package/dist/lib/regulatory-corpus/fetch-ich.d.ts +46 -0
  188. package/dist/lib/regulatory-corpus/fetch-ich.js +173 -0
  189. package/dist/lib/regulatory-corpus.d.ts +88 -0
  190. package/dist/lib/regulatory-corpus.js +141 -0
  191. package/dist/lib/result.d.ts +87 -0
  192. package/dist/lib/result.js +103 -0
  193. package/dist/lib/storage.d.ts +29 -0
  194. package/dist/lib/storage.js +37 -0
  195. package/dist/lib/streamed-download.d.ts +28 -0
  196. package/dist/lib/streamed-download.js +111 -0
  197. package/dist/lib/trace-context.d.ts +11 -0
  198. package/dist/lib/trace-context.js +49 -0
  199. package/dist/loop/__fixtures__/scripted-provider.d.ts +31 -0
  200. package/dist/loop/__fixtures__/scripted-provider.js +57 -0
  201. package/dist/loop/budget-exceeded.d.ts +22 -0
  202. package/dist/loop/budget-exceeded.js +41 -0
  203. package/dist/loop/metrics.d.ts +25 -0
  204. package/dist/loop/metrics.js +46 -0
  205. package/dist/loop/run-agent.d.ts +28 -0
  206. package/dist/loop/run-agent.js +204 -0
  207. package/dist/loop/run-step.d.ts +29 -0
  208. package/dist/loop/run-step.js +34 -0
  209. package/dist/loop/run-to-terminal.d.ts +46 -0
  210. package/dist/loop/run-to-terminal.js +51 -0
  211. package/dist/loop/types.d.ts +95 -0
  212. package/dist/loop/types.js +10 -0
  213. package/dist/memory/ai-sdk-message-storage.d.ts +20 -0
  214. package/dist/memory/ai-sdk-message-storage.js +114 -0
  215. package/dist/memory/card-builders.d.ts +114 -0
  216. package/dist/memory/card-builders.js +231 -0
  217. package/dist/memory/content-to-cortex.d.ts +42 -0
  218. package/dist/memory/content-to-cortex.js +85 -0
  219. package/dist/memory/count-tokens.d.ts +18 -0
  220. package/dist/memory/count-tokens.js +64 -0
  221. package/dist/memory/derive-thread-title.d.ts +14 -0
  222. package/dist/memory/derive-thread-title.js +26 -0
  223. package/dist/memory/message-backfill.d.ts +2 -0
  224. package/dist/memory/message-backfill.js +38 -0
  225. package/dist/memory/reconstruct-cards.d.ts +23 -0
  226. package/dist/memory/reconstruct-cards.js +64 -0
  227. package/dist/memory/thread-history.d.ts +80 -0
  228. package/dist/memory/thread-history.js +187 -0
  229. package/dist/memory/thread-store.d.ts +66 -0
  230. package/dist/memory/thread-store.js +88 -0
  231. package/dist/memory/working-memory.d.ts +135 -0
  232. package/dist/memory/working-memory.js +185 -0
  233. package/dist/prompts/SOUL.d.ts +17 -0
  234. package/dist/prompts/SOUL.js +173 -0
  235. package/dist/prompts/analogical-reasoner.d.ts +1 -0
  236. package/dist/prompts/analogical-reasoner.js +170 -0
  237. package/dist/prompts/conversation.d.ts +1 -0
  238. package/dist/prompts/conversation.js +697 -0
  239. package/dist/prompts/execute-analysis/step-summary.d.ts +1 -0
  240. package/dist/prompts/execute-analysis/step-summary.js +38 -0
  241. package/dist/prompts/literature-reviewer.d.ts +1 -0
  242. package/dist/prompts/literature-reviewer.js +107 -0
  243. package/dist/prompts/planner.d.ts +2 -0
  244. package/dist/prompts/planner.js +259 -0
  245. package/dist/prompts/report-builder.d.ts +1 -0
  246. package/dist/prompts/report-builder.js +127 -0
  247. package/dist/prompts/sandbox/bulk-transcriptomics-agent.d.ts +1 -0
  248. package/dist/prompts/sandbox/bulk-transcriptomics-agent.js +78 -0
  249. package/dist/prompts/sandbox/cheminformatics-agent.d.ts +1 -0
  250. package/dist/prompts/sandbox/cheminformatics-agent.js +224 -0
  251. package/dist/prompts/sandbox/chromatin-agent.d.ts +1 -0
  252. package/dist/prompts/sandbox/chromatin-agent.js +100 -0
  253. package/dist/prompts/sandbox/data-profiler.d.ts +1 -0
  254. package/dist/prompts/sandbox/data-profiler.js +291 -0
  255. package/dist/prompts/sandbox/dna-methylation-agent.d.ts +1 -0
  256. package/dist/prompts/sandbox/dna-methylation-agent.js +96 -0
  257. package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -0
  258. package/dist/prompts/sandbox/drug-repurposing-agent.js +144 -0
  259. package/dist/prompts/sandbox/enrichment-agent.d.ts +1 -0
  260. package/dist/prompts/sandbox/enrichment-agent.js +89 -0
  261. package/dist/prompts/sandbox/ephemeral-executor.d.ts +1 -0
  262. package/dist/prompts/sandbox/ephemeral-executor.js +66 -0
  263. package/dist/prompts/sandbox/genomic-variant-agent.d.ts +1 -0
  264. package/dist/prompts/sandbox/genomic-variant-agent.js +83 -0
  265. package/dist/prompts/sandbox/immune-profiling-agent.d.ts +1 -0
  266. package/dist/prompts/sandbox/immune-profiling-agent.js +101 -0
  267. package/dist/prompts/sandbox/metabolomics-agent.d.ts +1 -0
  268. package/dist/prompts/sandbox/metabolomics-agent.js +89 -0
  269. package/dist/prompts/sandbox/microbiome-agent.d.ts +1 -0
  270. package/dist/prompts/sandbox/microbiome-agent.js +109 -0
  271. package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -0
  272. package/dist/prompts/sandbox/multi-omics-integration-agent.js +122 -0
  273. package/dist/prompts/sandbox/multimodal-sc-agent.d.ts +1 -0
  274. package/dist/prompts/sandbox/multimodal-sc-agent.js +90 -0
  275. package/dist/prompts/sandbox/network-agent.d.ts +1 -0
  276. package/dist/prompts/sandbox/network-agent.js +95 -0
  277. package/dist/prompts/sandbox/pkpd-clinical-response-agent.d.ts +1 -0
  278. package/dist/prompts/sandbox/pkpd-clinical-response-agent.js +71 -0
  279. package/dist/prompts/sandbox/proteomics-agent.d.ts +1 -0
  280. package/dist/prompts/sandbox/proteomics-agent.js +93 -0
  281. package/dist/prompts/sandbox/scientific-executor.d.ts +1 -0
  282. package/dist/prompts/sandbox/scientific-executor.js +68 -0
  283. package/dist/prompts/sandbox/single-cell-agent.d.ts +1 -0
  284. package/dist/prompts/sandbox/single-cell-agent.js +129 -0
  285. package/dist/prompts/sandbox/spatial-omics-agent.d.ts +1 -0
  286. package/dist/prompts/sandbox/spatial-omics-agent.js +94 -0
  287. package/dist/prompts/sandbox/statistical-modeling-agent.d.ts +1 -0
  288. package/dist/prompts/sandbox/statistical-modeling-agent.js +112 -0
  289. package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -0
  290. package/dist/prompts/sandbox/translational-safety-agent.js +105 -0
  291. package/dist/prompts/sandbox-standards.d.ts +18 -0
  292. package/dist/prompts/sandbox-standards.js +358 -0
  293. package/dist/prompts/synthesis-agent.d.ts +1 -0
  294. package/dist/prompts/synthesis-agent.js +289 -0
  295. package/dist/prompts/target-assessment/briefs/executive-recommendation.d.ts +1 -0
  296. package/dist/prompts/target-assessment/briefs/executive-recommendation.js +85 -0
  297. package/dist/prompts/target-assessment/briefs/index.d.ts +4 -0
  298. package/dist/prompts/target-assessment/briefs/index.js +4 -0
  299. package/dist/prompts/target-assessment/briefs/liability-bullets.d.ts +1 -0
  300. package/dist/prompts/target-assessment/briefs/liability-bullets.js +114 -0
  301. package/dist/prompts/target-assessment/briefs/target-organ-liabilities.d.ts +1 -0
  302. package/dist/prompts/target-assessment/briefs/target-organ-liabilities.js +29 -0
  303. package/dist/prompts/target-assessment/briefs/translational-commentary.d.ts +1 -0
  304. package/dist/prompts/target-assessment/briefs/translational-commentary.js +23 -0
  305. package/dist/prompts/target-assessment/drugs-in-class.d.ts +1 -0
  306. package/dist/prompts/target-assessment/drugs-in-class.js +29 -0
  307. package/dist/prompts/target-assessment/modulator-triage.d.ts +1 -0
  308. package/dist/prompts/target-assessment/modulator-triage.js +31 -0
  309. package/dist/prompts/target-assessment/off-target-annotator.d.ts +1 -0
  310. package/dist/prompts/target-assessment/off-target-annotator.js +28 -0
  311. package/dist/prompts/target-assessment/tox-voice/core.d.ts +1 -0
  312. package/dist/prompts/target-assessment/tox-voice/core.js +74 -0
  313. package/dist/prompts/target-assessment/tox-voice/critique.d.ts +7 -0
  314. package/dist/prompts/target-assessment/tox-voice/critique.js +109 -0
  315. package/dist/prompts/target-assessment/tox-voice/exemplars.d.ts +8 -0
  316. package/dist/prompts/target-assessment/tox-voice/exemplars.js +24 -0
  317. package/dist/prompts/target-assessment/tox-voice/index.d.ts +4 -0
  318. package/dist/prompts/target-assessment/tox-voice/index.js +4 -0
  319. package/dist/prompts/target-assessment/tox-voice/vocabulary.d.ts +15 -0
  320. package/dist/prompts/target-assessment/tox-voice/vocabulary.js +72 -0
  321. package/dist/provenance/collector.d.ts +148 -0
  322. package/dist/provenance/collector.js +296 -0
  323. package/dist/provenance/exec-frame.d.ts +36 -0
  324. package/dist/provenance/exec-frame.js +49 -0
  325. package/dist/provenance/types.d.ts +95 -0
  326. package/dist/provenance/types.js +64 -0
  327. package/dist/providers/__fixtures__/session.d.ts +16 -0
  328. package/dist/providers/__fixtures__/session.js +20 -0
  329. package/dist/providers/ai-sdk.d.ts +47 -0
  330. package/dist/providers/ai-sdk.js +142 -0
  331. package/dist/providers/anthropic.d.ts +22 -0
  332. package/dist/providers/anthropic.js +26 -0
  333. package/dist/providers/embedding.d.ts +32 -0
  334. package/dist/providers/embedding.js +42 -0
  335. package/dist/providers/errors.d.ts +80 -0
  336. package/dist/providers/errors.js +137 -0
  337. package/dist/providers/llm-capabilities.d.ts +33 -0
  338. package/dist/providers/llm-capabilities.js +58 -0
  339. package/dist/providers/streaming-chat.d.ts +23 -0
  340. package/dist/providers/streaming-chat.js +61 -0
  341. package/dist/providers/types.d.ts +59 -0
  342. package/dist/providers/types.js +8 -0
  343. package/dist/runtime/assemble.d.ts +68 -0
  344. package/dist/runtime/assemble.js +46 -0
  345. package/dist/runtime/boot.d.ts +73 -0
  346. package/dist/runtime/boot.js +65 -0
  347. package/dist/runtime/connection-budget.d.ts +48 -0
  348. package/dist/runtime/connection-budget.js +57 -0
  349. package/dist/runtime/dbos.d.ts +94 -0
  350. package/dist/runtime/dbos.js +160 -0
  351. package/dist/runtime/lifecycle.d.ts +12 -0
  352. package/dist/runtime/lifecycle.js +19 -0
  353. package/dist/runtime/pools.d.ts +25 -0
  354. package/dist/runtime/pools.js +30 -0
  355. package/dist/runtime/shutdown.d.ts +33 -0
  356. package/dist/runtime/shutdown.js +39 -0
  357. package/dist/sandbox/await-exec.d.ts +143 -0
  358. package/dist/sandbox/await-exec.js +406 -0
  359. package/dist/sandbox/client.d.ts +82 -0
  360. package/dist/sandbox/client.js +23 -0
  361. package/dist/sandbox/create-sandbox.d.ts +105 -0
  362. package/dist/sandbox/create-sandbox.js +132 -0
  363. package/dist/sandbox/deliver-exec-event.d.ts +25 -0
  364. package/dist/sandbox/deliver-exec-event.js +29 -0
  365. package/dist/sandbox/docker-client.d.ts +75 -0
  366. package/dist/sandbox/docker-client.js +315 -0
  367. package/dist/sandbox/estimate-data-profile-resources.d.ts +5 -0
  368. package/dist/sandbox/estimate-data-profile-resources.js +73 -0
  369. package/dist/sandbox/exec-id.d.ts +12 -0
  370. package/dist/sandbox/exec-id.js +20 -0
  371. package/dist/sandbox/execution-id.d.ts +30 -0
  372. package/dist/sandbox/execution-id.js +47 -0
  373. package/dist/sandbox/hmac.d.ts +54 -0
  374. package/dist/sandbox/hmac.js +67 -0
  375. package/dist/sandbox/identity.d.ts +15 -0
  376. package/dist/sandbox/identity.js +22 -0
  377. package/dist/sandbox/ignored-dirs.d.ts +7 -0
  378. package/dist/sandbox/ignored-dirs.js +7 -0
  379. package/dist/sandbox/k8s-client.d.ts +71 -0
  380. package/dist/sandbox/k8s-client.js +488 -0
  381. package/dist/sandbox/liveness.d.ts +60 -0
  382. package/dist/sandbox/liveness.js +82 -0
  383. package/dist/sandbox/mount-plan.d.ts +77 -0
  384. package/dist/sandbox/mount-plan.js +84 -0
  385. package/dist/sandbox/notification-sweep.d.ts +42 -0
  386. package/dist/sandbox/notification-sweep.js +74 -0
  387. package/dist/sandbox/reaper.d.ts +70 -0
  388. package/dist/sandbox/reaper.js +124 -0
  389. package/dist/sandbox/sandbox-error.d.ts +105 -0
  390. package/dist/sandbox/sandbox-error.js +92 -0
  391. package/dist/sandbox/sandbox-step-translate.d.ts +35 -0
  392. package/dist/sandbox/sandbox-step-translate.js +76 -0
  393. package/dist/sandbox/submit-exec.d.ts +33 -0
  394. package/dist/sandbox/submit-exec.js +68 -0
  395. package/dist/sandbox/types.d.ts +277 -0
  396. package/dist/sandbox/types.js +147 -0
  397. package/dist/sandbox/watchdog.d.ts +71 -0
  398. package/dist/sandbox/watchdog.js +150 -0
  399. package/dist/schemas/artifact-manifest.d.ts +34 -0
  400. package/dist/schemas/artifact-manifest.js +36 -0
  401. package/dist/schemas/data-profile-schemas.d.ts +92 -0
  402. package/dist/schemas/data-profile-schemas.js +89 -0
  403. package/dist/schemas/file-metadata.d.ts +51 -0
  404. package/dist/schemas/file-metadata.js +39 -0
  405. package/dist/schemas/plan-schemas.d.ts +110 -0
  406. package/dist/schemas/plan-schemas.js +50 -0
  407. package/dist/schemas/render-step-prompt.d.ts +32 -0
  408. package/dist/schemas/render-step-prompt.js +76 -0
  409. package/dist/schemas/run-synthesis.d.ts +148 -0
  410. package/dist/schemas/run-synthesis.js +87 -0
  411. package/dist/schemas/step-summary.d.ts +18 -0
  412. package/dist/schemas/step-summary.js +20 -0
  413. package/dist/schemas/validate-plan.d.ts +39 -0
  414. package/dist/schemas/validate-plan.js +120 -0
  415. package/dist/schemas/workflow-state.d.ts +314 -0
  416. package/dist/schemas/workflow-state.js +139 -0
  417. package/dist/state/active-sandboxes.d.ts +58 -0
  418. package/dist/state/active-sandboxes.js +100 -0
  419. package/dist/state/analyses-metrics.d.ts +21 -0
  420. package/dist/state/analyses-metrics.js +59 -0
  421. package/dist/state/analyses.d.ts +58 -0
  422. package/dist/state/analyses.js +132 -0
  423. package/dist/state/artifacts.d.ts +53 -0
  424. package/dist/state/artifacts.js +175 -0
  425. package/dist/state/data-profile.d.ts +176 -0
  426. package/dist/state/data-profile.js +284 -0
  427. package/dist/state/db.d.ts +10 -0
  428. package/dist/state/db.js +9 -0
  429. package/dist/state/index.d.ts +29 -0
  430. package/dist/state/index.js +20 -0
  431. package/dist/state/init.d.ts +14 -0
  432. package/dist/state/init.js +406 -0
  433. package/dist/state/plans.d.ts +56 -0
  434. package/dist/state/plans.js +117 -0
  435. package/dist/state/runs.d.ts +69 -0
  436. package/dist/state/runs.js +206 -0
  437. package/dist/state/schema.d.ts +150 -0
  438. package/dist/state/schema.js +100 -0
  439. package/dist/state/step-executions.d.ts +77 -0
  440. package/dist/state/step-executions.js +175 -0
  441. package/dist/state/target-assessments.d.ts +68 -0
  442. package/dist/state/target-assessments.js +222 -0
  443. package/dist/state/vector-store.d.ts +53 -0
  444. package/dist/state/vector-store.js +89 -0
  445. package/dist/tasks/data-profile.d.ts +171 -0
  446. package/dist/tasks/data-profile.js +461 -0
  447. package/dist/tasks/refresh-regulatory-corpus.d.ts +59 -0
  448. package/dist/tasks/refresh-regulatory-corpus.js +146 -0
  449. package/dist/tasks/regulatory-corpus-boot-refresh.d.ts +55 -0
  450. package/dist/tasks/regulatory-corpus-boot-refresh.js +149 -0
  451. package/dist/tools/__fixtures__/tool-context.d.ts +13 -0
  452. package/dist/tools/__fixtures__/tool-context.js +18 -0
  453. package/dist/tools/bio/check-safety-panel.d.ts +35 -0
  454. package/dist/tools/bio/check-safety-panel.js +76 -0
  455. package/dist/tools/bio/find-approval-precedent.d.ts +32 -0
  456. package/dist/tools/bio/find-approval-precedent.js +72 -0
  457. package/dist/tools/bio/get-article-details.d.ts +11 -0
  458. package/dist/tools/bio/get-article-details.js +20 -0
  459. package/dist/tools/bio/get-article-full-text.d.ts +19 -0
  460. package/dist/tools/bio/get-article-full-text.js +32 -0
  461. package/dist/tools/bio/get-bioactivity.d.ts +11 -0
  462. package/dist/tools/bio/get-bioactivity.js +23 -0
  463. package/dist/tools/bio/get-drug-info.d.ts +9 -0
  464. package/dist/tools/bio/get-drug-info.js +22 -0
  465. package/dist/tools/bio/get-impc-ko-profile.d.ts +9 -0
  466. package/dist/tools/bio/get-impc-ko-profile.js +20 -0
  467. package/dist/tools/bio/get-mechanism.d.ts +8 -0
  468. package/dist/tools/bio/get-mechanism.js +18 -0
  469. package/dist/tools/bio/get-pubchem-assays.d.ts +22 -0
  470. package/dist/tools/bio/get-pubchem-assays.js +107 -0
  471. package/dist/tools/bio/get-pubchem-cross-refs.d.ts +15 -0
  472. package/dist/tools/bio/get-pubchem-cross-refs.js +68 -0
  473. package/dist/tools/bio/get-target-safety.d.ts +18 -0
  474. package/dist/tools/bio/get-target-safety.js +26 -0
  475. package/dist/tools/bio/index.d.ts +41 -0
  476. package/dist/tools/bio/index.js +48 -0
  477. package/dist/tools/bio/keys.d.ts +31 -0
  478. package/dist/tools/bio/keys.js +30 -0
  479. package/dist/tools/bio/lookup-go-term.d.ts +31 -0
  480. package/dist/tools/bio/lookup-go-term.js +116 -0
  481. package/dist/tools/bio/search-bgee-expression.d.ts +10 -0
  482. package/dist/tools/bio/search-bgee-expression.js +24 -0
  483. package/dist/tools/bio/search-clinical-trials.d.ts +12 -0
  484. package/dist/tools/bio/search-clinical-trials.js +21 -0
  485. package/dist/tools/bio/search-clinvar.d.ts +13 -0
  486. package/dist/tools/bio/search-clinvar.js +28 -0
  487. package/dist/tools/bio/search-compounds.d.ts +22 -0
  488. package/dist/tools/bio/search-compounds.js +160 -0
  489. package/dist/tools/bio/search-ctx-chemical.d.ts +50 -0
  490. package/dist/tools/bio/search-ctx-chemical.js +130 -0
  491. package/dist/tools/bio/search-ctx-exposure.d.ts +55 -0
  492. package/dist/tools/bio/search-ctx-exposure.js +176 -0
  493. package/dist/tools/bio/search-ctx-hazard.d.ts +111 -0
  494. package/dist/tools/bio/search-ctx-hazard.js +178 -0
  495. package/dist/tools/bio/search-dgidb.d.ts +43 -0
  496. package/dist/tools/bio/search-dgidb.js +199 -0
  497. package/dist/tools/bio/search-disgenet.d.ts +30 -0
  498. package/dist/tools/bio/search-disgenet.js +84 -0
  499. package/dist/tools/bio/search-drugbank.d.ts +38 -0
  500. package/dist/tools/bio/search-drugbank.js +109 -0
  501. package/dist/tools/bio/search-faers.d.ts +11 -0
  502. package/dist/tools/bio/search-faers.js +23 -0
  503. package/dist/tools/bio/search-gene.d.ts +11 -0
  504. package/dist/tools/bio/search-gene.js +19 -0
  505. package/dist/tools/bio/search-geo-datasets.d.ts +20 -0
  506. package/dist/tools/bio/search-geo-datasets.js +86 -0
  507. package/dist/tools/bio/search-gwas-catalog.d.ts +33 -0
  508. package/dist/tools/bio/search-gwas-catalog.js +172 -0
  509. package/dist/tools/bio/search-interactions.d.ts +17 -0
  510. package/dist/tools/bio/search-interactions.js +31 -0
  511. package/dist/tools/bio/search-opentargets.d.ts +11 -0
  512. package/dist/tools/bio/search-opentargets.js +25 -0
  513. package/dist/tools/bio/search-pathway.d.ts +12 -0
  514. package/dist/tools/bio/search-pathway.js +32 -0
  515. package/dist/tools/bio/search-pharmgkb.d.ts +17 -0
  516. package/dist/tools/bio/search-pharmgkb.js +46 -0
  517. package/dist/tools/bio/search-pubchem-compound.d.ts +26 -0
  518. package/dist/tools/bio/search-pubchem-compound.js +110 -0
  519. package/dist/tools/bio/search-pubmed.d.ts +17 -0
  520. package/dist/tools/bio/search-pubmed.js +31 -0
  521. package/dist/tools/bio/search-targets.d.ts +9 -0
  522. package/dist/tools/bio/search-targets.js +20 -0
  523. package/dist/tools/bio/search-toxcast.d.ts +36 -0
  524. package/dist/tools/bio/search-toxcast.js +141 -0
  525. package/dist/tools/define-tool.d.ts +80 -0
  526. package/dist/tools/define-tool.js +48 -0
  527. package/dist/tools/display/index.d.ts +4 -0
  528. package/dist/tools/display/index.js +4 -0
  529. package/dist/tools/display/show-user.d.ts +33 -0
  530. package/dist/tools/display/show-user.js +67 -0
  531. package/dist/tools/execute-plan.d.ts +64 -0
  532. package/dist/tools/execute-plan.js +208 -0
  533. package/dist/tools/iterate-report.d.ts +172 -0
  534. package/dist/tools/iterate-report.js +521 -0
  535. package/dist/tools/lib/api-utils.d.ts +80 -0
  536. package/dist/tools/lib/api-utils.js +128 -0
  537. package/dist/tools/lib/bgee-client.d.ts +36 -0
  538. package/dist/tools/lib/bgee-client.js +150 -0
  539. package/dist/tools/lib/cbioportal-client.d.ts +34 -0
  540. package/dist/tools/lib/cbioportal-client.js +159 -0
  541. package/dist/tools/lib/chembl-client.d.ts +123 -0
  542. package/dist/tools/lib/chembl-client.js +458 -0
  543. package/dist/tools/lib/chembl-config.d.ts +5 -0
  544. package/dist/tools/lib/chembl-config.js +3 -0
  545. package/dist/tools/lib/clinical-benchmarks-client.d.ts +33 -0
  546. package/dist/tools/lib/clinical-benchmarks-client.js +54 -0
  547. package/dist/tools/lib/clinical-trials-client.d.ts +216 -0
  548. package/dist/tools/lib/clinical-trials-client.js +339 -0
  549. package/dist/tools/lib/clinicaltrials-config.d.ts +4 -0
  550. package/dist/tools/lib/clinicaltrials-config.js +2 -0
  551. package/dist/tools/lib/clinvar-client.d.ts +25 -0
  552. package/dist/tools/lib/clinvar-client.js +126 -0
  553. package/dist/tools/lib/disgenet-config.d.ts +2 -0
  554. package/dist/tools/lib/disgenet-config.js +11 -0
  555. package/dist/tools/lib/drugbank-config.d.ts +2 -0
  556. package/dist/tools/lib/drugbank-config.js +12 -0
  557. package/dist/tools/lib/ema-client.d.ts +45 -0
  558. package/dist/tools/lib/ema-client.js +127 -0
  559. package/dist/tools/lib/ema-config.d.ts +7 -0
  560. package/dist/tools/lib/ema-config.js +7 -0
  561. package/dist/tools/lib/ensembl-client.d.ts +27 -0
  562. package/dist/tools/lib/ensembl-client.js +82 -0
  563. package/dist/tools/lib/gwas-catalog-config.d.ts +4 -0
  564. package/dist/tools/lib/gwas-catalog-config.js +2 -0
  565. package/dist/tools/lib/identifier-resolver.d.ts +85 -0
  566. package/dist/tools/lib/identifier-resolver.js +333 -0
  567. package/dist/tools/lib/impc-client.d.ts +44 -0
  568. package/dist/tools/lib/impc-client.js +239 -0
  569. package/dist/tools/lib/iuphar-client.d.ts +75 -0
  570. package/dist/tools/lib/iuphar-client.js +230 -0
  571. package/dist/tools/lib/iuphar-config.d.ts +5 -0
  572. package/dist/tools/lib/iuphar-config.js +3 -0
  573. package/dist/tools/lib/ncbi-utils.d.ts +58 -0
  574. package/dist/tools/lib/ncbi-utils.js +286 -0
  575. package/dist/tools/lib/openfda-client.d.ts +53 -0
  576. package/dist/tools/lib/openfda-client.js +192 -0
  577. package/dist/tools/lib/openfda-config.d.ts +2 -0
  578. package/dist/tools/lib/openfda-config.js +2 -0
  579. package/dist/tools/lib/opentargets-client.d.ts +64 -0
  580. package/dist/tools/lib/opentargets-client.js +290 -0
  581. package/dist/tools/lib/opentargets-config.d.ts +5 -0
  582. package/dist/tools/lib/opentargets-config.js +5 -0
  583. package/dist/tools/lib/path-validation.d.ts +14 -0
  584. package/dist/tools/lib/path-validation.js +26 -0
  585. package/dist/tools/lib/pathway-client.d.ts +27 -0
  586. package/dist/tools/lib/pathway-client.js +149 -0
  587. package/dist/tools/lib/pharmgkb-config.d.ts +4 -0
  588. package/dist/tools/lib/pharmgkb-config.js +2 -0
  589. package/dist/tools/lib/preview-lock.d.ts +20 -0
  590. package/dist/tools/lib/preview-lock.js +35 -0
  591. package/dist/tools/lib/protein-family-modality.d.ts +16 -0
  592. package/dist/tools/lib/protein-family-modality.js +42 -0
  593. package/dist/tools/lib/protein-family-normalize.d.ts +12 -0
  594. package/dist/tools/lib/protein-family-normalize.js +46 -0
  595. package/dist/tools/lib/pubchem-client.d.ts +40 -0
  596. package/dist/tools/lib/pubchem-client.js +128 -0
  597. package/dist/tools/lib/pubchem-config.d.ts +5 -0
  598. package/dist/tools/lib/pubchem-config.js +3 -0
  599. package/dist/tools/lib/pubmed-client.d.ts +28 -0
  600. package/dist/tools/lib/pubmed-client.js +91 -0
  601. package/dist/tools/lib/report-preflight.d.ts +39 -0
  602. package/dist/tools/lib/report-preflight.js +283 -0
  603. package/dist/tools/lib/string-client.d.ts +33 -0
  604. package/dist/tools/lib/string-client.js +93 -0
  605. package/dist/tools/lib/toxcast-config.d.ts +2 -0
  606. package/dist/tools/lib/toxcast-config.js +11 -0
  607. package/dist/tools/lib/uniprot-client.d.ts +28 -0
  608. package/dist/tools/lib/uniprot-client.js +103 -0
  609. package/dist/tools/lib/uniprot-config.d.ts +5 -0
  610. package/dist/tools/lib/uniprot-config.js +3 -0
  611. package/dist/tools/memory/index.d.ts +4 -0
  612. package/dist/tools/memory/index.js +4 -0
  613. package/dist/tools/memory/update-working-memory.d.ts +25 -0
  614. package/dist/tools/memory/update-working-memory.js +112 -0
  615. package/dist/tools/registry.d.ts +15 -0
  616. package/dist/tools/registry.js +26 -0
  617. package/dist/tools/report/build-report.d.ts +13 -0
  618. package/dist/tools/report/build-report.js +26 -0
  619. package/dist/tools/report/index.d.ts +14 -0
  620. package/dist/tools/report/index.js +14 -0
  621. package/dist/tools/report/mint-preview-url.d.ts +26 -0
  622. package/dist/tools/report/mint-preview-url.js +44 -0
  623. package/dist/tools/report/preview-publisher.d.ts +37 -0
  624. package/dist/tools/report/preview-publisher.js +25 -0
  625. package/dist/tools/report/preview-snapshot.d.ts +26 -0
  626. package/dist/tools/report/preview-snapshot.js +121 -0
  627. package/dist/tools/report/submit-report.d.ts +25 -0
  628. package/dist/tools/report/submit-report.js +126 -0
  629. package/dist/tools/report/version-fs.d.ts +15 -0
  630. package/dist/tools/report/version-fs.js +154 -0
  631. package/dist/tools/research/context7-docs.d.ts +31 -0
  632. package/dist/tools/research/context7-docs.js +61 -0
  633. package/dist/tools/research/generate-analogy-report.d.ts +60 -0
  634. package/dist/tools/research/generate-analogy-report.js +288 -0
  635. package/dist/tools/research/generate-plan.d.ts +39 -0
  636. package/dist/tools/research/generate-plan.js +393 -0
  637. package/dist/tools/research/index.d.ts +15 -0
  638. package/dist/tools/research/index.js +15 -0
  639. package/dist/tools/research/inspect-run.d.ts +54 -0
  640. package/dist/tools/research/inspect-run.js +85 -0
  641. package/dist/tools/research/literature-reviewer.d.ts +29 -0
  642. package/dist/tools/research/literature-reviewer.js +84 -0
  643. package/dist/tools/research/search-arxiv.d.ts +32 -0
  644. package/dist/tools/research/search-arxiv.js +123 -0
  645. package/dist/tools/research/search-github-repos.d.ts +32 -0
  646. package/dist/tools/research/search-github-repos.js +86 -0
  647. package/dist/tools/research/search-semantic-scholar.d.ts +33 -0
  648. package/dist/tools/research/search-semantic-scholar.js +93 -0
  649. package/dist/tools/run-ephemeral.d.ts +33 -0
  650. package/dist/tools/run-ephemeral.js +65 -0
  651. package/dist/tools/sandbox/index.d.ts +7 -0
  652. package/dist/tools/sandbox/index.js +7 -0
  653. package/dist/tools/sandbox/list-available-packages.d.ts +7 -0
  654. package/dist/tools/sandbox/list-available-packages.js +27 -0
  655. package/dist/tools/sandbox/list-available-refs.d.ts +7 -0
  656. package/dist/tools/sandbox/list-available-refs.js +147 -0
  657. package/dist/tools/sandbox/report-blocker.d.ts +23 -0
  658. package/dist/tools/sandbox/report-blocker.js +39 -0
  659. package/dist/tools/sandbox/skills.d.ts +72 -0
  660. package/dist/tools/sandbox/skills.js +144 -0
  661. package/dist/tools/workspace/edit-file.d.ts +46 -0
  662. package/dist/tools/workspace/edit-file.js +100 -0
  663. package/dist/tools/workspace/execute-command.d.ts +80 -0
  664. package/dist/tools/workspace/execute-command.js +95 -0
  665. package/dist/tools/workspace/file-stat.d.ts +24 -0
  666. package/dist/tools/workspace/file-stat.js +37 -0
  667. package/dist/tools/workspace/grep.d.ts +57 -0
  668. package/dist/tools/workspace/grep.js +154 -0
  669. package/dist/tools/workspace/index.d.ts +26 -0
  670. package/dist/tools/workspace/index.js +27 -0
  671. package/dist/tools/workspace/list-files.d.ts +24 -0
  672. package/dist/tools/workspace/list-files.js +38 -0
  673. package/dist/tools/workspace/mutator.d.ts +83 -0
  674. package/dist/tools/workspace/mutator.js +81 -0
  675. package/dist/tools/workspace/read-file.d.ts +39 -0
  676. package/dist/tools/workspace/read-file.js +93 -0
  677. package/dist/tools/workspace/result-bounds.d.ts +42 -0
  678. package/dist/tools/workspace/result-bounds.js +50 -0
  679. package/dist/tools/workspace/run-exec.d.ts +32 -0
  680. package/dist/tools/workspace/run-exec.js +34 -0
  681. package/dist/tools/workspace/show-file.d.ts +37 -0
  682. package/dist/tools/workspace/show-file.js +54 -0
  683. package/dist/tools/workspace/show-plan.d.ts +23 -0
  684. package/dist/tools/workspace/show-plan.js +44 -0
  685. package/dist/tools/workspace/workspace-search.d.ts +25 -0
  686. package/dist/tools/workspace/workspace-search.js +78 -0
  687. package/dist/tools/workspace/write-file.d.ts +16 -0
  688. package/dist/tools/workspace/write-file.js +33 -0
  689. package/dist/workflows/execute-analysis-scheduler.d.ts +94 -0
  690. package/dist/workflows/execute-analysis-scheduler.js +186 -0
  691. package/dist/workflows/execute-analysis.d.ts +271 -0
  692. package/dist/workflows/execute-analysis.js +746 -0
  693. package/dist/workflows/execute-target-assessment.d.ts +101 -0
  694. package/dist/workflows/execute-target-assessment.js +528 -0
  695. package/dist/workflows/metrics.d.ts +37 -0
  696. package/dist/workflows/metrics.js +55 -0
  697. package/dist/workflows/plan/level.d.ts +12 -0
  698. package/dist/workflows/plan/level.js +12 -0
  699. package/dist/workflows/register-workflows.d.ts +51 -0
  700. package/dist/workflows/register-workflows.js +48 -0
  701. package/dist/workflows/resume-execute-analysis.d.ts +70 -0
  702. package/dist/workflows/resume-execute-analysis.js +80 -0
  703. package/dist/workflows/sandbox-step.d.ts +243 -0
  704. package/dist/workflows/sandbox-step.js +573 -0
  705. package/dist/workflows/target-assessment/assemblers/index.d.ts +5 -0
  706. package/dist/workflows/target-assessment/assemblers/index.js +4 -0
  707. package/dist/workflows/target-assessment/assemblers/literature.d.ts +299 -0
  708. package/dist/workflows/target-assessment/assemblers/literature.js +987 -0
  709. package/dist/workflows/target-assessment/assemblers/orchestrator.d.ts +109 -0
  710. package/dist/workflows/target-assessment/assemblers/orchestrator.js +835 -0
  711. package/dist/workflows/target-assessment/assemblers/safety.d.ts +352 -0
  712. package/dist/workflows/target-assessment/assemblers/safety.js +985 -0
  713. package/dist/workflows/target-assessment/assemblers/trials.d.ts +30 -0
  714. package/dist/workflows/target-assessment/assemblers/trials.js +75 -0
  715. package/dist/workflows/target-assessment/collectors/index.d.ts +105 -0
  716. package/dist/workflows/target-assessment/collectors/index.js +468 -0
  717. package/dist/workflows/target-assessment/correction-loop.d.ts +45 -0
  718. package/dist/workflows/target-assessment/correction-loop.js +62 -0
  719. package/dist/workflows/target-assessment/coverage.d.ts +81 -0
  720. package/dist/workflows/target-assessment/coverage.js +82 -0
  721. package/dist/workflows/target-assessment/decisions/index.d.ts +86 -0
  722. package/dist/workflows/target-assessment/decisions/index.js +127 -0
  723. package/dist/workflows/target-assessment/fanout/index.d.ts +31 -0
  724. package/dist/workflows/target-assessment/fanout/index.js +155 -0
  725. package/dist/workflows/target-assessment/lib/approval-precedents.d.ts +52 -0
  726. package/dist/workflows/target-assessment/lib/approval-precedents.js +119 -0
  727. package/dist/workflows/target-assessment/lib/citation-validator.d.ts +46 -0
  728. package/dist/workflows/target-assessment/lib/citation-validator.js +316 -0
  729. package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.d.ts +62 -0
  730. package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.js +172 -0
  731. package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.d.ts +45 -0
  732. package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.js +156 -0
  733. package/dist/workflows/target-assessment/lib/compute-derived.d.ts +19 -0
  734. package/dist/workflows/target-assessment/lib/compute-derived.js +252 -0
  735. package/dist/workflows/target-assessment/lib/compute-selectivity.d.ts +15 -0
  736. package/dist/workflows/target-assessment/lib/compute-selectivity.js +18 -0
  737. package/dist/workflows/target-assessment/lib/dedup-modulators.d.ts +37 -0
  738. package/dist/workflows/target-assessment/lib/dedup-modulators.js +157 -0
  739. package/dist/workflows/target-assessment/lib/evidence-conflict-detector.d.ts +17 -0
  740. package/dist/workflows/target-assessment/lib/evidence-conflict-detector.js +100 -0
  741. package/dist/workflows/target-assessment/lib/expression-constants.d.ts +21 -0
  742. package/dist/workflows/target-assessment/lib/expression-constants.js +21 -0
  743. package/dist/workflows/target-assessment/lib/family-complex-supplement.d.ts +21 -0
  744. package/dist/workflows/target-assessment/lib/family-complex-supplement.js +37 -0
  745. package/dist/workflows/target-assessment/lib/heterodimer-filter.d.ts +39 -0
  746. package/dist/workflows/target-assessment/lib/heterodimer-filter.js +54 -0
  747. package/dist/workflows/target-assessment/lib/intended-polypharm-filter.d.ts +4 -0
  748. package/dist/workflows/target-assessment/lib/intended-polypharm-filter.js +24 -0
  749. package/dist/workflows/target-assessment/lib/llm-step.d.ts +77 -0
  750. package/dist/workflows/target-assessment/lib/llm-step.js +99 -0
  751. package/dist/workflows/target-assessment/lib/meddra-organ-map.d.ts +30 -0
  752. package/dist/workflows/target-assessment/lib/meddra-organ-map.js +126 -0
  753. package/dist/workflows/target-assessment/lib/recommendation-quality-gates.d.ts +17 -0
  754. package/dist/workflows/target-assessment/lib/recommendation-quality-gates.js +99 -0
  755. package/dist/workflows/target-assessment/lib/recommendation-sanitizer.d.ts +2 -0
  756. package/dist/workflows/target-assessment/lib/recommendation-sanitizer.js +51 -0
  757. package/dist/workflows/target-assessment/lib/regulatory-actions.d.ts +26 -0
  758. package/dist/workflows/target-assessment/lib/regulatory-actions.js +147 -0
  759. package/dist/workflows/target-assessment/lib/structured-llm.d.ts +58 -0
  760. package/dist/workflows/target-assessment/lib/structured-llm.js +101 -0
  761. package/dist/workflows/target-assessment/lib/target-identity-filter.d.ts +60 -0
  762. package/dist/workflows/target-assessment/lib/target-identity-filter.js +86 -0
  763. package/dist/workflows/target-assessment/lib/therapeutic-programs.d.ts +20 -0
  764. package/dist/workflows/target-assessment/lib/therapeutic-programs.js +68 -0
  765. package/dist/workflows/target-assessment/metrics.d.ts +21 -0
  766. package/dist/workflows/target-assessment/metrics.js +42 -0
  767. package/dist/workflows/target-assessment/phase4-assemble.d.ts +1841 -0
  768. package/dist/workflows/target-assessment/phase4-assemble.js +39 -0
  769. package/dist/workflows/target-assessment/phase5-persist.d.ts +57 -0
  770. package/dist/workflows/target-assessment/phase5-persist.js +461 -0
  771. package/dist/workflows/target-assessment/progress.d.ts +38 -0
  772. package/dist/workflows/target-assessment/progress.js +76 -0
  773. package/dist/workflows/target-assessment/schemas.d.ts +931 -0
  774. package/dist/workflows/target-assessment/schemas.js +293 -0
  775. package/dist/workflows/target-assessment/steps/collectors/pathways.d.ts +15 -0
  776. package/dist/workflows/target-assessment/steps/collectors/pathways.js +58 -0
  777. package/dist/workflows/target-assessment/steps/fanout/aes-for-one-class-drug-step.d.ts +34 -0
  778. package/dist/workflows/target-assessment/steps/fanout/aes-for-one-class-drug-step.js +31 -0
  779. package/dist/workflows/target-assessment/steps/fanout/aes-for-one-trial-step.d.ts +57 -0
  780. package/dist/workflows/target-assessment/steps/fanout/aes-for-one-trial-step.js +54 -0
  781. package/dist/workflows/target-assessment/steps/fanout/faers-for-one-modulator-step.d.ts +35 -0
  782. package/dist/workflows/target-assessment/steps/fanout/faers-for-one-modulator-step.js +32 -0
  783. package/dist/workflows/target-assessment/steps/fanout/index.d.ts +14 -0
  784. package/dist/workflows/target-assessment/steps/fanout/index.js +10 -0
  785. package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.d.ts +28 -0
  786. package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.js +27 -0
  787. package/dist/workflows/target-assessment/steps/phase0-resolve.d.ts +71 -0
  788. package/dist/workflows/target-assessment/steps/phase0-resolve.js +21 -0
  789. package/dist/workflows/target-assessment/steps/phase1-aggregate.d.ts +1018 -0
  790. package/dist/workflows/target-assessment/steps/phase1-aggregate.js +25 -0
  791. package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +696 -0
  792. package/dist/workflows/target-assessment/steps/phase2-aggregate.js +38 -0
  793. package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +936 -0
  794. package/dist/workflows/target-assessment/steps/phase3-aggregate.js +22 -0
  795. package/dist/workflows/target-assessment/steps/synthesis/diagnostics.d.ts +34 -0
  796. package/dist/workflows/target-assessment/steps/synthesis/diagnostics.js +45 -0
  797. package/dist/workflows/target-assessment/sub-workflows/index.d.ts +15 -0
  798. package/dist/workflows/target-assessment/sub-workflows/index.js +11 -0
  799. package/dist/workflows/target-assessment/sub-workflows/per-class-drug-aes.d.ts +41 -0
  800. package/dist/workflows/target-assessment/sub-workflows/per-class-drug-aes.js +12 -0
  801. package/dist/workflows/target-assessment/sub-workflows/per-modulator-faers.d.ts +41 -0
  802. package/dist/workflows/target-assessment/sub-workflows/per-modulator-faers.js +12 -0
  803. package/dist/workflows/target-assessment/sub-workflows/per-modulator-polypharm.d.ts +36 -0
  804. package/dist/workflows/target-assessment/sub-workflows/per-modulator-polypharm.js +12 -0
  805. package/dist/workflows/target-assessment/sub-workflows/per-trial-aes.d.ts +66 -0
  806. package/dist/workflows/target-assessment/sub-workflows/per-trial-aes.js +12 -0
  807. package/dist/workflows/target-assessment/synthesis/index.d.ts +560 -0
  808. package/dist/workflows/target-assessment/synthesis/index.js +351 -0
  809. package/dist/workflows/target-assessment/synthesis-probes.d.ts +56 -0
  810. package/dist/workflows/target-assessment/synthesis-probes.js +320 -0
  811. package/dist/workspace/filesystem.d.ts +117 -0
  812. package/dist/workspace/filesystem.js +304 -0
  813. package/dist/workspace/mount-strategy.d.ts +50 -0
  814. package/dist/workspace/mount-strategy.js +67 -0
  815. package/dist/workspace/paths.d.ts +185 -0
  816. package/dist/workspace/paths.js +219 -0
  817. package/dist/workspace/provenance-collector.d.ts +34 -0
  818. package/dist/workspace/provenance-collector.js +16 -0
  819. package/dist/workspace/search-config.d.ts +23 -0
  820. package/dist/workspace/search-config.js +43 -0
  821. package/dist/workspace/workspace-paths.d.ts +26 -0
  822. package/dist/workspace/workspace-paths.js +31 -0
  823. package/package.json +101 -0
@@ -0,0 +1,985 @@
1
+ /**
2
+ * Phase-4 deterministic assemblers — safety sections.
3
+ *
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
+ * when an upstream came back `queried_no_data` or the derived row set is
7
+ * empty, the section is marked `queried_no_data` / `not_loaded` rather
8
+ * than fabricated. Aggregate rows preserve their contributing evidence
9
+ * under `evidence: [...]` arrays.
10
+ */
11
+ import { expectedOrgansFromBody } from "../lib/compute-derived.js";
12
+ import { inferTherapeuticArea } from "../../../tools/lib/clinical-benchmarks-client.js";
13
+ import { SafetyPanelFileSchema } from "../../../data/safety-panel-schema.js";
14
+ import safetyPanelData from "../../../data/safety-panel.json" with { type: "json" };
15
+ import { isOnTargetChemblId } from "../lib/target-identity-filter.js";
16
+ import { isIntendedCoTarget } from "../lib/intended-polypharm-filter.js";
17
+ import { makeHeterodimerOfAssessmentFilter } from "../lib/heterodimer-filter.js";
18
+ import { buildFamilyComplexSupplement } from "../lib/family-complex-supplement.js";
19
+ import { computeSelectivity } from "../lib/compute-selectivity.js";
20
+ import { classifyOrgan, classifyPolypharmOrgan, classifyTrialAe } from "../lib/meddra-organ-map.js";
21
+ import { HIGH_EXPRESSION_TPM_THRESHOLD, CNS_REGION_TPM_FLOOR, MUSCULOSKELETAL_TPM_FLOOR } from "../lib/expression-constants.js";
22
+ export { HIGH_EXPRESSION_TPM_THRESHOLD };
23
+ // ── Safety panel lookup ─────────────────────────────────────────────
24
+ const SAFETY_PANEL = SafetyPanelFileSchema.parse(safetyPanelData);
25
+ const SAFETY_BY_CHEMBL = new Map(SAFETY_PANEL.targets.map((t) => [t.chembl_id, t]));
26
+ const SAFETY_BY_GENE = new Map(SAFETY_PANEL.targets.map((t) => [t.gene_symbol.toUpperCase(), t]));
27
+ function lookupSafetyPanel(opts) {
28
+ if (opts.chemblId) {
29
+ const hit = SAFETY_BY_CHEMBL.get(opts.chemblId);
30
+ if (hit)
31
+ return hit;
32
+ }
33
+ if (opts.geneSymbol) {
34
+ const hit = SAFETY_BY_GENE.get(opts.geneSymbol.toUpperCase());
35
+ if (hit)
36
+ return hit;
37
+ }
38
+ return null;
39
+ }
40
+ // ── Safety-relevant tissues and expression thresholds ───────────────
41
+ export const SAFETY_RELEVANT_ORGANS = new Set([
42
+ "heart",
43
+ "liver",
44
+ "kidney",
45
+ "brain",
46
+ "bone marrow",
47
+ "lung",
48
+ "thyroid",
49
+ "pancreas",
50
+ "adrenal",
51
+ "gonad",
52
+ "ovary",
53
+ "testis",
54
+ "stomach",
55
+ "intestine",
56
+ "spleen",
57
+ "lymph node",
58
+ "retina",
59
+ "cochlea",
60
+ // Reproductive — ovary/testis/gonad already above; add remaining reproductive tissues
61
+ "placenta",
62
+ "uterus",
63
+ "endometrium",
64
+ "fallopian tube",
65
+ "epididymis",
66
+ "prostate",
67
+ "seminal vesicle",
68
+ // Bone — bone marrow already above; add cortical/trabecular bone and named bones
69
+ "bone",
70
+ "tibia",
71
+ "femur",
72
+ "vertebra",
73
+ ]);
74
+ export function isSafetyRelevant(tissue, organ) {
75
+ const t = tissue.toLowerCase();
76
+ const o = (organ ?? "").toLowerCase();
77
+ for (const safe of SAFETY_RELEVANT_ORGANS) {
78
+ if (t.includes(safe) || o.includes(safe))
79
+ return true;
80
+ }
81
+ return false;
82
+ }
83
+ // Reproductive/germ-cell and bone tissues often express targets at 20-80 nTPM
84
+ // in non-pathological states — applying the default 100 nTPM floor silences
85
+ // genuine tox signals. Use a lower floor for these tissues.
86
+ export const REPRODUCTIVE_TOX_TISSUES = new Set([
87
+ // Reproductive and germ-cell
88
+ "placenta",
89
+ "uterus",
90
+ "endometrium",
91
+ "fallopian tube",
92
+ "epididymis",
93
+ "prostate",
94
+ "seminal vesicle",
95
+ "ovary",
96
+ "testis",
97
+ // Bone — canonical target sites (e.g. CALCR in tibia) express 50-100 nTPM
98
+ "bone",
99
+ "tibia",
100
+ "femur",
101
+ "vertebra",
102
+ ]);
103
+ export const REPRODUCTIVE_TOX_TPM_FLOOR = 20;
104
+ export const DEFAULT_TPM_FLOOR = 100;
105
+ // Compound HPA tissue labels that share a leading token with a
106
+ // REPRODUCTIVE_TOX_TISSUES entry but refer to anatomically distinct
107
+ // structures that should keep the default 100 nTPM floor.
108
+ // "bone marrow" shares the token "bone" with the bone entry but is
109
+ // haematopoietic tissue, not skeletal — it must not inherit the lower floor.
110
+ const REPRODUCTIVE_TOX_EXCLUDED_LABELS = new Set(["bone marrow"]);
111
+ // CNS subregions carry biologically meaningful peptide-GPCR expression at
112
+ // single-digit nTPM; the default 100 floor produces audit failures for CNS
113
+ // bullets the recommendation asserts. Hypothalamus is absent — it consistently
114
+ // clears the default floor for CALCR (217 nTPM) and needs no special case.
115
+ const CNS_REGION_TISSUES = new Set([
116
+ "amygdala",
117
+ "caudate nucleus",
118
+ "cerebellum",
119
+ "cerebral cortex",
120
+ "corpus callosum",
121
+ "frontal cortex",
122
+ "hippocampus",
123
+ "hippocampus proper",
124
+ "nucleus accumbens",
125
+ "prefrontal cortex",
126
+ "putamen",
127
+ "substantia nigra",
128
+ "temporal lobe",
129
+ "thalamus",
130
+ "basal ganglia",
131
+ "white matter",
132
+ "spinal cord",
133
+ "c1 segment of cervical spinal cord",
134
+ "brodmann (1909) area 24",
135
+ ]);
136
+ // Skeletal muscle and smooth muscle surfaces routinely show 20-80 nTPM for
137
+ // GPCRs whose ligands affect mineral and muscle metabolism.
138
+ const MUSCULOSKELETAL_TISSUES = new Set([
139
+ "skeletal muscle",
140
+ "skeletal muscle tissue",
141
+ "smooth muscle",
142
+ "smooth muscle tissue",
143
+ "cartilage",
144
+ "synovial membrane",
145
+ ]);
146
+ export function meetsTpmFloor(tissue, value) {
147
+ const t = tissue.toLowerCase();
148
+ // REPRODUCTIVE_TOX_EXCLUDED_LABELS must be checked first — "bone marrow"
149
+ // shares a prefix with "bone" but is haematopoietic and keeps the default floor.
150
+ if (REPRODUCTIVE_TOX_EXCLUDED_LABELS.has(t))
151
+ return value > DEFAULT_TPM_FLOOR;
152
+ if (CNS_REGION_TISSUES.has(t))
153
+ return value > CNS_REGION_TPM_FLOOR;
154
+ if (MUSCULOSKELETAL_TISSUES.has(t))
155
+ return value > MUSCULOSKELETAL_TPM_FLOOR;
156
+ for (const repro of REPRODUCTIVE_TOX_TISSUES) {
157
+ if (t === repro || t.startsWith(repro + " ") || t.startsWith(repro + "-")) {
158
+ return value > REPRODUCTIVE_TOX_TPM_FLOOR;
159
+ }
160
+ }
161
+ return value > DEFAULT_TPM_FLOOR;
162
+ }
163
+ const CANONICAL_ORGANS = [
164
+ "cardiac",
165
+ "hepatic",
166
+ "cns",
167
+ "renal",
168
+ "gi",
169
+ "pancreas",
170
+ "endocrine_thyroid",
171
+ "metabolic",
172
+ "hematologic",
173
+ "immune",
174
+ "respiratory",
175
+ "reproductive",
176
+ "dermatologic",
177
+ "musculoskeletal",
178
+ ];
179
+ // ── Liability summary ───────────────────────────────────────────────
180
+ export function assembleLiabilitySummary(phase2, context) {
181
+ const ot = phase2.phase1.collectors.opentargets;
182
+ const drugsInClass = phase2.decisions.drugsInClass;
183
+ const indications = ot.coverage === "available" ? ot.data.associations.map((a) => a.diseaseName) : [];
184
+ const ta = inferTherapeuticArea(indications);
185
+ const safetySources = [
186
+ phase2.phase1.collectors.faersByTarget.coverage === "available" ? 1 : 0,
187
+ phase2.phase1.collectors.ctgov.coverage === "available" ? 1 : 0,
188
+ (context.offTargetRows ?? []).length > 0 ? 1 : 0,
189
+ drugsInClass.coverage === "available" ? 1 : 0,
190
+ ].reduce((a, b) => a + b, 0);
191
+ const sameClass = drugsInClass.coverage === "available" ? drugsInClass.data.total : 0;
192
+ const noLiabilitiesDisclosure = safetySources === 0 ? "insufficient safety data to assess (0 of 4 sources returned data)" : `${safetySources} of 4 safety data sources returned data`;
193
+ return {
194
+ liability_bullets: [],
195
+ modality_recommendation: context.preferredModality,
196
+ same_class_drug_count: sameClass,
197
+ inferred_therapeutic_area: ta,
198
+ no_liabilities_disclosure: noLiabilitiesDisclosure,
199
+ };
200
+ }
201
+ export function aggregateFaersAcrossModulators(fanout) {
202
+ if (!fanout)
203
+ return null;
204
+ const items = fanout.perModulatorFaers.results;
205
+ const available = items.filter((i) => i.coverage === "available");
206
+ if (available.length === 0)
207
+ return null;
208
+ let totalReports = 0;
209
+ let fatal = 0;
210
+ let hospitalization = 0;
211
+ let lifeT = 0;
212
+ let disabling = 0;
213
+ let congenital = 0;
214
+ let otherSerious = 0;
215
+ const reactionMap = new Map();
216
+ const reactionOrgan = new Map();
217
+ const perModulator = [];
218
+ for (const item of items) {
219
+ if (item.coverage === "available") {
220
+ const d = item.data;
221
+ totalReports += d.totalReports ?? 0;
222
+ if (d.seriousness) {
223
+ fatal += d.seriousness.fatalCount;
224
+ hospitalization += d.seriousness.hospitalizationCount;
225
+ lifeT += d.seriousness.lifeThreateningCount;
226
+ disabling += d.seriousness.disablingCount;
227
+ congenital += d.seriousness.congenitalAnomalyCount ?? 0;
228
+ otherSerious += d.seriousness.otherSeriousCount ?? 0;
229
+ }
230
+ for (const r of d.topReactions) {
231
+ reactionMap.set(r.reaction, (reactionMap.get(r.reaction) ?? 0) + r.count);
232
+ if (!reactionOrgan.has(r.reaction)) {
233
+ reactionOrgan.set(r.reaction, classifyOrgan(r.reaction));
234
+ }
235
+ }
236
+ perModulator.push({
237
+ modulator: d.preferredName,
238
+ modulator_id: d.moleculeChemblId,
239
+ report_count: d.totalReports ?? 0,
240
+ coverage: "available",
241
+ });
242
+ }
243
+ else {
244
+ perModulator.push({
245
+ modulator: "unknown",
246
+ modulator_id: null,
247
+ report_count: 0,
248
+ coverage: item.coverage,
249
+ });
250
+ }
251
+ }
252
+ const top_signals = [...reactionMap.entries()]
253
+ .sort((a, b) => b[1] - a[1])
254
+ .slice(0, 25)
255
+ .map(([term, count]) => ({
256
+ meddra_term: term,
257
+ organ: reactionOrgan.get(term) ?? undefined,
258
+ report_count: count,
259
+ }));
260
+ const totalSeriousnessSum = fatal + hospitalization + lifeT + disabling + congenital + otherSerious;
261
+ const haveAnySeriousness = totalSeriousnessSum > 0;
262
+ const seriousness = haveAnySeriousness
263
+ ? {
264
+ coverage: "available",
265
+ total_reports: totalReports,
266
+ by_seriousness: {
267
+ death: fatal,
268
+ life_threatening: lifeT,
269
+ hospitalization,
270
+ disabling,
271
+ other_serious: otherSerious,
272
+ congenital_anomaly: congenital,
273
+ },
274
+ fatal_report_count: fatal,
275
+ }
276
+ : {
277
+ coverage: "queried_no_data",
278
+ total_reports: totalReports,
279
+ };
280
+ return {
281
+ total_reports: totalReports,
282
+ seriousness,
283
+ top_signals,
284
+ per_modulator: perModulator,
285
+ };
286
+ }
287
+ export function aggregateTrialAes(fanout) {
288
+ if (!fanout)
289
+ return null;
290
+ const items = fanout.perTrialAes.results;
291
+ const available = items.filter((i) => i.coverage === "available");
292
+ if (available.length === 0)
293
+ return null;
294
+ const serious = new Map();
295
+ const non = new Map();
296
+ // Pick the worst-rate arm per (term, trial); aggregate per arm to avoid mixing denominators.
297
+ for (const item of available) {
298
+ for (const ev of item.data.events) {
299
+ let bestAffected = 0;
300
+ let bestAtRisk = 0;
301
+ let bestRate = -1;
302
+ for (const c of ev.counts) {
303
+ const affected = c.numAffected ?? 0;
304
+ const atRisk = c.numAtRisk ?? 0;
305
+ if (atRisk <= 0)
306
+ continue;
307
+ const rate = affected / atRisk;
308
+ if (rate > bestRate) {
309
+ bestRate = rate;
310
+ bestAffected = affected;
311
+ bestAtRisk = atRisk;
312
+ }
313
+ }
314
+ if (bestAtRisk === 0) {
315
+ for (const c of ev.counts) {
316
+ const affected = c.numAffected ?? 0;
317
+ if (affected > bestAffected)
318
+ bestAffected = affected;
319
+ }
320
+ }
321
+ const target = ev.serious ? serious : non;
322
+ const cur = target.get(ev.term) ?? {
323
+ affected: 0,
324
+ atRisk: 0,
325
+ ncts: new Set(),
326
+ organ: ev.organSystem ?? undefined,
327
+ };
328
+ cur.affected += bestAffected;
329
+ cur.atRisk += bestAtRisk;
330
+ cur.ncts.add(item.data.nctId);
331
+ target.set(ev.term, cur);
332
+ }
333
+ }
334
+ function shape(map, floorPct) {
335
+ let dropped = 0;
336
+ const rows = [...map.entries()]
337
+ .map(([term, v]) => ({
338
+ term,
339
+ incidence_pct: v.atRisk > 0 ? Math.round((v.affected / v.atRisk) * 1000) / 10 : 0,
340
+ organ: v.organ,
341
+ nct_ids: [...v.ncts],
342
+ }))
343
+ .filter((row) => {
344
+ if (row.term === "Other") {
345
+ dropped += 1;
346
+ return false;
347
+ }
348
+ if (row.organ && row.term === row.organ) {
349
+ dropped += 1;
350
+ return false;
351
+ }
352
+ return row.incidence_pct >= floorPct;
353
+ })
354
+ .sort((a, b) => b.incidence_pct - a.incidence_pct)
355
+ .slice(0, 50);
356
+ return { rows, dropped };
357
+ }
358
+ const seriousShape = shape(serious, 0);
359
+ const nonShape = shape(non, 2);
360
+ const trials_queried = available.length;
361
+ const trials_with_ae_data = available.filter((i) => i.data.events.length > 0).length;
362
+ return {
363
+ serious: seriousShape.rows,
364
+ non_serious: nonShape.rows,
365
+ non_serious_floor_pct: 2,
366
+ dropped_uninformative_count: seriousShape.dropped + nonShape.dropped,
367
+ coverage_qualifier: {
368
+ trials_queried,
369
+ trials_with_ae_data,
370
+ serious_floor_applied: 0,
371
+ non_serious_floor_pct_applied: 2,
372
+ },
373
+ };
374
+ }
375
+ // ── Off-target panel filter/dedup ───────────────────────────────────────────
376
+ /** Fold below this threshold → selectivity window is insufficient. */
377
+ export const SELECTIVITY_FOLD_THRESHOLD = 30;
378
+ const SENTINEL_OFF_TARGET_NAMES = new Set(["unchecked", "unknown", "n/a"]);
379
+ /**
380
+ * Common cell-line names that appear in ChEMBL polypharm hits but are not
381
+ * biological targets. Filtered out before panel assembly.
382
+ */
383
+ const CELL_LINE_NAME_PATTERNS = /\b(hek293|hek-293|cho|hela|3t3|293t|293|jurkat|raw264|raw\s*264|cos-7|cos7|mcf-7|mcf7|pc-3|pc3|lncap|a549|u2os|ht-29|ht29|sk-ov-3|skov3|t47d|mda-mb|nih3t3)\b/i;
384
+ /**
385
+ * Filter and deduplicate raw off-target rows before panel assembly.
386
+ *
387
+ * Removes: on-target self-rows, cell-line entries, sentinel/unresolved names.
388
+ * Deduplicates: by UniProt accession when present, otherwise by normalized name;
389
+ * keeps the highest-pchembl row as the winner and records merged ChEMBL ids.
390
+ * Computes: `selectivity_window_below_threshold`, `clinical_consequence`,
391
+ * `is_safety_panel_target` (via the existing safety-panel lookup).
392
+ */
393
+ export function filterAndDedupOffTargetRows(rows, ctx) {
394
+ const filtered = rows.filter((r) => {
395
+ // Self-row: the primary target appearing in its own off-target panel.
396
+ const selfId = r.off_target_id ?? r.target_chembl_id;
397
+ if (ctx.assessmentTargetChemblId && selfId === ctx.assessmentTargetChemblId)
398
+ return false;
399
+ // Cell-line entries by target_type flag or by name pattern.
400
+ if ((r.target_type ?? "").toUpperCase() === "CELL-LINE")
401
+ return false;
402
+ const name = (r.off_target_name ?? "").trim();
403
+ if (CELL_LINE_NAME_PATTERNS.test(name))
404
+ return false;
405
+ // Sentinel / unresolved names.
406
+ const nameLower = name.toLowerCase();
407
+ if (!nameLower || SENTINEL_OFF_TARGET_NAMES.has(nameLower))
408
+ return false;
409
+ return true;
410
+ });
411
+ // Group by accession when present; otherwise by normalized name.
412
+ const groups = new Map();
413
+ for (const r of filtered) {
414
+ const key = r.accession ? `accession:${r.accession}` : `name:${(r.off_target_name ?? "").trim().toLowerCase()}`;
415
+ const arr = groups.get(key) ?? [];
416
+ arr.push(r);
417
+ groups.set(key, arr);
418
+ }
419
+ const out = [];
420
+ for (const group of groups.values()) {
421
+ const sorted = [...group].sort((a, b) => b.pchembl - a.pchembl);
422
+ const winner = sorted[0];
423
+ const merged_chembl_ids = sorted
424
+ .slice(1)
425
+ .filter((r) => r.off_target_id)
426
+ .map((r) => r.off_target_id);
427
+ // `clinical_consequence` comes from the safety-panel lookup when the
428
+ // off-target is on that panel; otherwise it is left null here and the
429
+ // post-pass LLM annotator (annotateOffTargetPanel) fills it in.
430
+ const { target_chembl_id: _tcid, target_type: _tt, accession: _acc, ...rest } = winner;
431
+ out.push({
432
+ ...rest,
433
+ off_target_id: winner.off_target_id ?? null,
434
+ off_target_name: (winner.off_target_name ?? winner.off_target_id ?? "").trim(),
435
+ organ_system: winner.organ_system ?? null,
436
+ evidence: winner.evidence ?? [],
437
+ selectivity_window_below_threshold: winner.selectivity.fold < SELECTIVITY_FOLD_THRESHOLD,
438
+ clinical_consequence: winner.clinical_consequence ?? null,
439
+ is_safety_panel_target: winner.is_safety_panel_target ?? false,
440
+ metadata: { ...(winner.metadata ?? {}), merged_chembl_ids },
441
+ });
442
+ }
443
+ return out;
444
+ }
445
+ // ── Off-target panel assembly ───────────────────────────────────────
446
+ /**
447
+ * V4 off-target panel row split. Each clean off-target row is classified as:
448
+ * - `on_target_self_hit`: alternate ChEMBL ID for the assessment target itself
449
+ * - `intended_co_target`: every modulator that hits this target intends it
450
+ * (e.g., GLP1R + GIPR for tirzepatide); not an off-target liability
451
+ * - `off_target`: real off-target — selectivity computed vs primary potency
452
+ */
453
+ export function aggregateOffTargetPanel(phase2, fanout, assessmentUniprot, assessmentGeneSymbol = "", familyComplexes = null, onTargetChemblIds = []) {
454
+ const accessoryProteinNames = familyComplexes?.accessoryProteinNames ?? [];
455
+ const isHeterodimer = makeHeterodimerOfAssessmentFilter({
456
+ assessmentGeneSymbol,
457
+ accessoryProteinNames,
458
+ });
459
+ const polypharm = fanout?.perModulatorPolypharm.results ?? [];
460
+ if (polypharm.length === 0)
461
+ return null;
462
+ const haveAny = polypharm.some((p) => p.coverage === "available");
463
+ if (!haveAny)
464
+ return null;
465
+ const primaryChemblId = phase2.phase1.collectors.chemblModulators.coverage === "available" ? phase2.phase1.collectors.chemblModulators.data.targetChemblId : null;
466
+ // Build a lookup of primaryPchembl per modulator from the fanout results so
467
+ // computeSelectivity can produce real fold values for off-target rows.
468
+ const primaryPchemblByModulator = new Map();
469
+ for (const item of polypharm) {
470
+ if (item.coverage !== "available")
471
+ continue;
472
+ primaryPchemblByModulator.set(item.data.moleculeChemblId, item.data.primaryPchembl);
473
+ }
474
+ const byTarget = new Map();
475
+ for (const item of polypharm) {
476
+ if (item.coverage !== "available")
477
+ continue;
478
+ for (const hit of item.data.hits) {
479
+ if (primaryChemblId && hit.targetChemblId === primaryChemblId)
480
+ continue;
481
+ const pch = hit.pchemblValue ?? 0;
482
+ const cur = byTarget.get(hit.targetChemblId);
483
+ if (!cur || pch > cur.pchembl) {
484
+ byTarget.set(hit.targetChemblId, {
485
+ chemblId: hit.targetChemblId,
486
+ name: hit.targetName ?? hit.targetChemblId,
487
+ pchembl: pch,
488
+ modulatorPrimaryPchembl: primaryPchemblByModulator.get(item.data.moleculeChemblId) ?? null,
489
+ modulators: cur?.modulators ?? new Set(),
490
+ });
491
+ }
492
+ byTarget.get(hit.targetChemblId).modulators.add(item.data.moleculeChemblId);
493
+ }
494
+ }
495
+ // Map off-target ChEMBL ID → primaryPchembl of the winner modulator so the
496
+ // relationship loop can pass it to computeSelectivity without threading it
497
+ // through the filter/dedup pipeline.
498
+ const primaryPchemblByOffTarget = new Map([...byTarget.values()].map((v) => [v.chemblId, v.modulatorPrimaryPchembl]));
499
+ const rawRows = [...byTarget.values()]
500
+ .map((v) => {
501
+ const safetyHit = lookupSafetyPanel({
502
+ chemblId: v.chemblId,
503
+ geneSymbol: v.name,
504
+ });
505
+ const onPanel = safetyHit !== null;
506
+ if (!onPanel && v.pchembl < 5)
507
+ return null;
508
+ if (onPanel && v.pchembl < 4)
509
+ return null;
510
+ return {
511
+ off_target_id: v.chemblId,
512
+ off_target_name: v.name ?? v.chemblId,
513
+ target_class: undefined,
514
+ pchembl: v.pchembl,
515
+ is_safety_panel_target: onPanel,
516
+ organ_system: safetyHit?.organ_system ?? null,
517
+ // Safety-panel clinical_consequence is a fallback; the curated lookup
518
+ // in filterAndDedupOffTargetRows takes precedence when available.
519
+ clinical_consequence: safetyHit?.clinical_consequence ?? null,
520
+ selectivity: { log_units: 0, fold: 1 },
521
+ selectivity_window_below_threshold: false,
522
+ modulators: [...v.modulators],
523
+ evidence: [...v.modulators].map((m) => ({
524
+ source: "chembl:polypharm",
525
+ predicate: "binds",
526
+ score: v.pchembl,
527
+ metadata: { off_target_id: v.chemblId, modulator: m },
528
+ })),
529
+ };
530
+ })
531
+ .filter((r) => r !== null);
532
+ // Preserve modulator membership across dedup so the v4 relationship
533
+ // classifier (intended co-target / on-target self-hit) can see which
534
+ // molecules actually hit each off-target.
535
+ const modulatorsByKey = new Map();
536
+ for (const r of rawRows) {
537
+ const key = `${r.off_target_id ?? ""}::${(r.off_target_name ?? "").trim().toLowerCase()}`;
538
+ const set = modulatorsByKey.get(key) ?? new Set();
539
+ for (const m of r.modulators)
540
+ set.add(m);
541
+ modulatorsByKey.set(key, set);
542
+ }
543
+ const cleanRows = filterAndDedupOffTargetRows(rawRows, {
544
+ assessmentTargetChemblId: primaryChemblId,
545
+ });
546
+ cleanRows.sort((a, b) => {
547
+ if (a.is_safety_panel_target !== b.is_safety_panel_target) {
548
+ return a.is_safety_panel_target ? -1 : 1;
549
+ }
550
+ return b.pchembl - a.pchembl;
551
+ });
552
+ // Helper: project a clean row onto the V4 base shape (no relationship yet).
553
+ const toBaseRow = (r) => ({
554
+ off_target_id: r.off_target_id,
555
+ off_target_name: r.off_target_name,
556
+ target_class: r.target_class,
557
+ pchembl: r.pchembl,
558
+ is_safety_panel_target: r.is_safety_panel_target,
559
+ organ_system: r.organ_system,
560
+ clinical_consequence: r.clinical_consequence,
561
+ evidence: r.evidence,
562
+ metadata: r.metadata,
563
+ });
564
+ const rows = [];
565
+ const excludedRows = [];
566
+ for (const r of cleanRows.slice(0, 50)) {
567
+ const base = toBaseRow(r);
568
+ const key = `${r.off_target_id ?? ""}::${r.off_target_name.trim().toLowerCase()}`;
569
+ const modulators = [...(modulatorsByKey.get(key) ?? new Set())];
570
+ // 0. Obligate cofactor — same protein heterodimerized with a different
571
+ // accessory (e.g., CALCR/RAMP3 = AMY3 for a CALCR assessment).
572
+ // Selectivity is not pharmacologically attainable across partners.
573
+ if (assessmentGeneSymbol && isHeterodimer(r.off_target_name)) {
574
+ excludedRows.push({
575
+ ...base,
576
+ relationship: "obligate_cofactor",
577
+ reason: `${r.off_target_name} is ${assessmentGeneSymbol} heterodimerised with a different obligate cofactor; selectivity is not pharmacologically attainable.`,
578
+ selectivity: { selectivity_unknown: true, reason: "obligate cofactor (same protein, different RAMP/accessory)" },
579
+ selectivity_window_below_threshold: false,
580
+ });
581
+ continue;
582
+ }
583
+ // 1. On-target self-hit (alternate ChEMBL ID for the same protein).
584
+ if (r.off_target_id && assessmentUniprot && isOnTargetChemblId(r.off_target_id, onTargetChemblIds)) {
585
+ excludedRows.push({
586
+ ...base,
587
+ relationship: "on_target_self_hit",
588
+ reason: `${r.off_target_id} is an alternate ChEMBL ID for the on-target`,
589
+ selectivity: { selectivity_unknown: true, reason: "on-target self-hit" },
590
+ selectivity_window_below_threshold: false,
591
+ });
592
+ continue;
593
+ }
594
+ // 2. Intended co-target — every contributing modulator marks this target
595
+ // as part of the marketed mechanism (dual/triple agonist case).
596
+ const intendedHits = modulators.map((m) => ({ m, hit: isIntendedCoTarget(m, r.off_target_id ?? "") })).filter((x) => x.hit.intended);
597
+ if (modulators.length > 0 && intendedHits.length === modulators.length) {
598
+ excludedRows.push({
599
+ ...base,
600
+ relationship: "intended_co_target",
601
+ reason: intendedHits[0].hit.reason,
602
+ selectivity: { selectivity_unknown: true, reason: "intended co-target" },
603
+ selectivity_window_below_threshold: false,
604
+ });
605
+ continue;
606
+ }
607
+ // 3. Real off-target — compute selectivity against primary potency.
608
+ // primaryPchemblByOffTarget carries the median on-target pChEMBL fetched
609
+ // by the polypharm fanout step. When absent (null), computeSelectivity
610
+ // returns selectivity_unknown with a clear reason.
611
+ const modulatorPrimaryPchembl = r.off_target_id != null ? (primaryPchemblByOffTarget.get(r.off_target_id) ?? null) : null;
612
+ const selectivity = computeSelectivity({
613
+ primary_pchembl: modulatorPrimaryPchembl,
614
+ off_target_pchembl: r.pchembl,
615
+ });
616
+ const below = "selectivity_unknown" in selectivity ? true : selectivity.vs_primary_potency.fold < SELECTIVITY_FOLD_THRESHOLD;
617
+ rows.push({
618
+ ...base,
619
+ relationship: "off_target",
620
+ selectivity,
621
+ selectivity_window_below_threshold: below,
622
+ });
623
+ }
624
+ // Append the IUPHAR-driven obligate-cofactor supplement for receptor-
625
+ // accessory family complexes (e.g., CALCR → AMY1/AMY2/AMY3). The ChEMBL
626
+ // polypharm panel may surface only some of these complexes; IUPHAR is
627
+ // exhaustive for the registered family. Dedup against existing
628
+ // excludedRows by off_target_name to avoid duplicate entries.
629
+ if (familyComplexes && familyComplexes.complexes.length > 0) {
630
+ const supplementRows = buildFamilyComplexSupplement(familyComplexes);
631
+ const norm = (name) => name.trim().toLowerCase();
632
+ const existingNames = new Set(excludedRows.map((r) => norm(r.off_target_name)));
633
+ for (const supp of supplementRows) {
634
+ if (!existingNames.has(norm(supp.off_target_name))) {
635
+ excludedRows.push(supp);
636
+ }
637
+ }
638
+ }
639
+ return { rows, excluded_rows: excludedRows };
640
+ }
641
+ // ── Class-precedent drug-count helpers ─────────────────────────────────────
642
+ /** Minimum distinct active substances required for class-liability designation. */
643
+ export const CLASS_MIN_DRUGS = 3;
644
+ // Signal fraction at or above which an organ is treated as a structural class
645
+ // liability rather than an idiosyncratic AE. 0.30 ≈ 1/3 of marketed class members
646
+ // — calibrated against GLP-1R (GI 6/17 = 35% must flag) and AKT1 / non-class
647
+ // targets (sparse signals must not flag). Originally 0.50; lowered after
648
+ // dossier 9ad29ba5 review surfaced false negatives on the GLP-1R class.
649
+ export const CLASS_LIABILITY_FRACTION = 0.3;
650
+ /**
651
+ * Deduplicates a list of drugs by active substance (parent_chembl_id, falling
652
+ * back to drug_id when parent is absent), then derives the count and suppression
653
+ * reason used consistently across drugs_in_class and per_organ rollups.
654
+ *
655
+ * Dedup winner per group: highest max_phase; ties broken by drug_id lexicographic
656
+ * order so the result is deterministic.
657
+ */
658
+ export function computeClassPrecedentCounts(drugs) {
659
+ const groups = new Map();
660
+ for (const d of drugs) {
661
+ const key = d.parent_chembl_id ?? d.drug_id;
662
+ const arr = groups.get(key) ?? [];
663
+ arr.push(d);
664
+ groups.set(key, arr);
665
+ }
666
+ const deduped = [];
667
+ for (const group of groups.values()) {
668
+ const winner = [...group].sort((a, b) => {
669
+ if ((b.max_phase ?? 0) !== (a.max_phase ?? 0))
670
+ return (b.max_phase ?? 0) - (a.max_phase ?? 0);
671
+ return a.drug_id.localeCompare(b.drug_id);
672
+ })[0];
673
+ deduped.push(winner);
674
+ }
675
+ const drug_count_in_class = deduped.length;
676
+ const suppressed_reason = drug_count_in_class < CLASS_MIN_DRUGS ? `class size ${drug_count_in_class} below ${CLASS_MIN_DRUGS}-drug minimum` : null;
677
+ return { drug_count_in_class, drugs_in_class: deduped, suppressed_reason };
678
+ }
679
+ export function aggregateClassPrecedent(phase2, fanout) {
680
+ const dic = phase2.decisions.drugsInClass;
681
+ if (dic.coverage !== "available" || dic.data.drugs.length === 0)
682
+ return null;
683
+ // Build a lookup from moleculeChemblId -> parentChemblId using the modulator
684
+ // collector data. The LLM drugsInClass output does not carry parentChemblId,
685
+ // but the collector does — this join is the deterministic backstop for
686
+ // dedup-by-active-substance.
687
+ const modCollector = phase2.phase1.collectors.chemblModulators;
688
+ const parentMap = new Map();
689
+ if (modCollector.coverage === "available") {
690
+ for (const m of modCollector.data.modulators) {
691
+ parentMap.set(m.moleculeChemblId, m.parentChemblId);
692
+ }
693
+ }
694
+ const rawDrugs = dic.data.drugs.map((d) => ({
695
+ drug_id: d.moleculeChemblId,
696
+ parent_chembl_id: parentMap.has(d.moleculeChemblId) ? (parentMap.get(d.moleculeChemblId) ?? null) : null,
697
+ drug_name: d.preferredName,
698
+ max_phase: Math.round(d.maxPhase ?? 0),
699
+ }));
700
+ const { drug_count_in_class, drugs_in_class } = computeClassPrecedentCounts(rawDrugs);
701
+ if (!fanout)
702
+ return { drugs_in_class, per_organ: [] };
703
+ const items = fanout.perClassDrugAes.results;
704
+ // Map FAERS results back to their deduped representative drug_id so signals
705
+ // from both CHEMBL3989767 and CHEMBL4594242 (same active substance) count as
706
+ // one drug in the denominator.
707
+ const dedupKeyForFaersDrug = (moleculeChemblId) => {
708
+ const parent = parentMap.get(moleculeChemblId);
709
+ return parent ?? moleculeChemblId;
710
+ };
711
+ const organMap = new Map();
712
+ const totalDedupKeys = new Set();
713
+ for (const item of items) {
714
+ if (item.coverage !== "available")
715
+ continue;
716
+ const dedupKey = dedupKeyForFaersDrug(item.data.moleculeChemblId);
717
+ totalDedupKeys.add(dedupKey);
718
+ const totalReports = item.data.totalReports ?? 0;
719
+ for (const r of item.data.topReactions) {
720
+ const organ = classifyOrgan(r.reaction);
721
+ if (!organ)
722
+ continue;
723
+ const cur = organMap.get(organ) ??
724
+ {
725
+ dedupKeys: new Set(),
726
+ dedupKeysWithSignal: new Set(),
727
+ aes: new Map(),
728
+ };
729
+ cur.dedupKeys.add(dedupKey);
730
+ if (totalReports > 0)
731
+ cur.dedupKeysWithSignal.add(dedupKey);
732
+ cur.aes.set(r.reaction, (cur.aes.get(r.reaction) ?? 0) + r.count);
733
+ organMap.set(organ, cur);
734
+ }
735
+ }
736
+ // Use drug_count_in_class from the deduped drugs_in_class list as the
737
+ // authoritative denominator. Fall back to FAERS-observed distinct drugs if
738
+ // the deduped list is empty (shouldn't happen in practice).
739
+ const denominator = drug_count_in_class > 0 ? drug_count_in_class : totalDedupKeys.size;
740
+ const per_organ = [...organMap.entries()].map(([organ, v]) => {
741
+ const drugsWithSignal = v.dedupKeysWithSignal.size;
742
+ const fraction = denominator > 0 ? drugsWithSignal / denominator : 0;
743
+ const isLiability = denominator >= CLASS_MIN_DRUGS && fraction >= CLASS_LIABILITY_FRACTION;
744
+ const suppressed_reason = !isLiability && denominator < CLASS_MIN_DRUGS ? `class size ${denominator} below ${CLASS_MIN_DRUGS}-drug minimum` : null;
745
+ return {
746
+ organ,
747
+ drug_count_in_class: denominator,
748
+ drugs_with_signal: drugsWithSignal,
749
+ signal_fraction: fraction,
750
+ is_class_liability: isLiability,
751
+ suppressed_reason,
752
+ top_aes: [...v.aes.entries()]
753
+ .sort((a, b) => b[1] - a[1])
754
+ .slice(0, 10)
755
+ .map(([term, count]) => ({ term, report_count: count })),
756
+ };
757
+ });
758
+ return { drugs_in_class, per_organ };
759
+ }
760
+ // ── Organ rollup ────────────────────────────────────────────────────
761
+ /**
762
+ * Build the minimal synthetic body shape that expectedOrgansFromBody needs
763
+ * from the assembler's intermediate aggregates (before the full body is
764
+ * assembled). This ensures the assembler's organ_rollup gap-fill uses the
765
+ * same `classifyTrialAe` + `classifyOrgan` logic as the derived validator —
766
+ * preventing derived-invariant-violation at persist time.
767
+ */
768
+ function syntheticBodyForExpectedOrgans(faers, trialAes, offTarget) {
769
+ return {
770
+ safety_profile: {
771
+ faers: { data: { top_signals: faers?.top_signals ?? [] } },
772
+ trial_aes: { data: { serious: trialAes?.serious ?? [] } },
773
+ off_target_panel: { data: { rows: offTarget ?? [] } },
774
+ },
775
+ };
776
+ }
777
+ const MALIGNANCY_RE = /malignan|cancer|carcinoma|neoplasm/i;
778
+ export function buildOrganRollup(faers, trialAes, offTarget, classP, regulatoryActions) {
779
+ if (!faers && !trialAes && !offTarget && !classP && !regulatoryActions?.length)
780
+ return null;
781
+ const rows = CANONICAL_ORGANS.map((organ) => {
782
+ // off_target_panel.organ_system is the curated safety-panel canonical
783
+ // string (`cardiac` | `hepatic` | `cns` | `renal` | `gi` |
784
+ // `hematologic` | `immune` | `metabolic` | `respiratory`). Use direct
785
+ // string equality first; `classifyOrgan` falls back if a future
786
+ // collector emits a non-canonical string.
787
+ const polypharmHits = (offTarget ?? []).filter((r) => classifyPolypharmOrgan(r.organ_system) === organ);
788
+ const polypharmCount = polypharmHits.length;
789
+ const faersHits = (faers?.top_signals ?? []).filter((s) => s.organ === organ);
790
+ const faersCount = faersHits.length;
791
+ // trial_aes.serious rows carry the CT.gov SOC string in `.organ`
792
+ // (e.g. "Gastrointestinal disorders") and the MedDRA PT in `.term`
793
+ // (e.g. "nausea"). `classifyTrialAe` maps the SOC first, then falls
794
+ // back to PT classification — the same logic the derived-completeness
795
+ // validator uses, so the assembler and validator agree on the
796
+ // expected organ set.
797
+ const trialHits = (trialAes?.serious ?? []).filter((e) => classifyTrialAe(e) === organ);
798
+ const trialCount = trialHits.length;
799
+ const classOrgan = (classP?.per_organ ?? []).find((o) => o.organ === organ);
800
+ const classLiability = !!classOrgan?.is_class_liability;
801
+ // Trial AEs are weighted as half a signal for risk classification
802
+ // because they lack drug attribution and comparator-arm handling.
803
+ // FAERS, off-target, and class-liability are full signals.
804
+ const signalScore = (polypharmCount > 0 ? 1 : 0) + (faersCount > 0 ? 1 : 0) + (trialCount > 0 ? 0.5 : 0) + (classLiability ? 1 : 0);
805
+ const signalTypeCount = (polypharmCount > 0 ? 1 : 0) + (faersCount > 0 ? 1 : 0) + (trialCount > 0 ? 1 : 0) + (classLiability ? 1 : 0);
806
+ const risk = signalScore >= 2.5 ? "high" : signalScore >= 1.5 ? "medium" : "low";
807
+ const evidence = [
808
+ ...polypharmHits.map((h) => ({
809
+ source: "chembl:polypharm",
810
+ predicate: "off_target_binding",
811
+ score: h.pchembl,
812
+ metadata: { off_target_id: h.off_target_id, organ_system: h.organ_system },
813
+ })),
814
+ ...faersHits.map((s) => ({
815
+ source: "openfda:faers",
816
+ predicate: "post_market_signal",
817
+ metadata: { meddra_term: s.meddra_term, count: s.report_count },
818
+ })),
819
+ ...trialHits.map((t) => ({
820
+ source: "ctgov:trial_aes",
821
+ predicate: "trial_adverse_event",
822
+ is_clinical: true,
823
+ metadata: {
824
+ term: t.term,
825
+ incidence_pct: t.incidence_pct,
826
+ nct_ids: t.nct_ids,
827
+ },
828
+ })),
829
+ ...(classOrgan
830
+ ? [
831
+ {
832
+ source: "class_precedent",
833
+ predicate: "class_liability",
834
+ metadata: {
835
+ drug_count_in_class: classOrgan.drug_count_in_class,
836
+ drugs_with_signal: classOrgan.drugs_with_signal,
837
+ signal_fraction: classOrgan.signal_fraction,
838
+ },
839
+ },
840
+ ]
841
+ : []),
842
+ ];
843
+ return {
844
+ organ,
845
+ risk_level: risk,
846
+ signal_type_count: signalTypeCount,
847
+ signals: {
848
+ chembl_polypharm_count: polypharmCount,
849
+ faers_count: faersCount,
850
+ trial_ae_count: trialCount,
851
+ class_liability_present: classLiability,
852
+ },
853
+ evidence,
854
+ };
855
+ });
856
+ // Drop rows with no signals, then guarantee every expected organ has a row.
857
+ const filtered = rows.filter((r) => r.signal_type_count > 0);
858
+ const presentOrgans = new Set(filtered.map((r) => r.organ));
859
+ const expected = expectedOrgansFromBody(syntheticBodyForExpectedOrgans(faers, trialAes, offTarget));
860
+ for (const organ of expected) {
861
+ if (presentOrgans.has(organ))
862
+ continue;
863
+ const matchingFaers = (faers?.top_signals ?? []).filter((s) => classifyOrgan(s.meddra_term) === organ);
864
+ const matchingAes = (trialAes?.serious ?? []).filter((a) => classifyTrialAe(a) === organ);
865
+ filtered.push({
866
+ organ,
867
+ risk_level: matchingAes.length > 0 ? "high" : "medium",
868
+ signal_type_count: (matchingFaers.length > 0 ? 1 : 0) + (matchingAes.length > 0 ? 1 : 0),
869
+ signals: {
870
+ chembl_polypharm_count: 0,
871
+ faers_count: matchingFaers.length,
872
+ trial_ae_count: matchingAes.length,
873
+ class_liability_present: false,
874
+ },
875
+ evidence: [
876
+ ...matchingFaers.slice(0, 3).map((s) => ({
877
+ source: "openfda:faers",
878
+ predicate: "post_market_signal",
879
+ metadata: { count: s.report_count, meddra_term: s.meddra_term },
880
+ })),
881
+ ...matchingAes.slice(0, 3).map((a) => ({
882
+ source: "ctgov:trial_aes",
883
+ predicate: "trial_adverse_event",
884
+ is_clinical: true,
885
+ metadata: {
886
+ term: a.term,
887
+ nct_ids: a.nct_ids,
888
+ incidence_pct: a.incidence_pct,
889
+ },
890
+ })),
891
+ ],
892
+ });
893
+ presentOrgans.add(organ);
894
+ }
895
+ // Oncology synthesis: when regulatory_actions carries malignancy-keyword
896
+ // findings, emit an oncology rollup row. This is ADDITIVE — it does not
897
+ // replace any row produced by the main CANONICAL_ORGANS loop above.
898
+ if (!presentOrgans.has("oncology") && regulatoryActions?.length) {
899
+ const malignancyRows = regulatoryActions.filter((r) => MALIGNANCY_RE.test(r.finding));
900
+ if (malignancyRows.length > 0) {
901
+ filtered.push({
902
+ organ: "oncology",
903
+ risk_level: "high",
904
+ signal_type_count: 1,
905
+ signals: {
906
+ chembl_polypharm_count: 0,
907
+ faers_count: 0,
908
+ trial_ae_count: 0,
909
+ class_liability_present: true,
910
+ },
911
+ evidence: malignancyRows.map((r) => ({
912
+ source: "regulatory_actions",
913
+ predicate: "malignancy_signal",
914
+ metadata: {
915
+ agency: r.agency,
916
+ action_kind: r.action_kind,
917
+ action_date: r.action_date,
918
+ drug_name: r.drug_name,
919
+ },
920
+ })),
921
+ });
922
+ }
923
+ }
924
+ return filtered;
925
+ }
926
+ /**
927
+ * Testable wrapper around `buildOrganRollup` that accepts named parameters.
928
+ * Exported for unit tests; production code calls `buildOrganRollup` directly
929
+ * inside `assembleDossier`.
930
+ */
931
+ export function assembleOrganRollupRows(opts) {
932
+ const regRows = opts.regulatoryActions?.coverage === "available" ? (opts.regulatoryActions.data?.rows ?? null) : null;
933
+ return buildOrganRollup(null, null, null, opts.classPrecedent ?? null, regRows) ?? [];
934
+ }
935
+ // ── §2.4 Drug Interactions ──────────────────────────────────────────
936
+ export function assembleDrugInteractions(phase2, enrichedModulators) {
937
+ const mods = phase2.phase1.collectors.chemblModulators;
938
+ if (mods.coverage !== "available" || mods.data.modulators.length === 0) {
939
+ return null;
940
+ }
941
+ const modulatorList = enrichedModulators ?? mods.data.modulators;
942
+ if (modulatorList.length === 0) {
943
+ return null;
944
+ }
945
+ const triage = phase2.decisions.modulatorTriage;
946
+ const triageRationales = new Map();
947
+ if (triage.coverage === "available") {
948
+ for (const t of triage.data.shortlist) {
949
+ triageRationales.set(t.moleculeChemblId, t.rationale);
950
+ }
951
+ }
952
+ const rows = modulatorList.slice(0, 50).map((m) => {
953
+ const phase = Math.round(m.maxPhase ?? 0);
954
+ const score = phase >= 4 ? 1 : phase >= 1 ? phase / 4 : 0;
955
+ const hasClinical = phase >= 1;
956
+ return {
957
+ drug_id: m.moleculeChemblId,
958
+ drug_name: m.preferredName ?? m.moleculeChemblId,
959
+ best_score: score,
960
+ predicates: ["modulates"],
961
+ sources: ["chembl"],
962
+ paper_count: 0,
963
+ dominant_direction: "unknown",
964
+ has_human_evidence: hasClinical,
965
+ has_clinical_evidence: hasClinical,
966
+ evidence: [
967
+ {
968
+ source: "chembl:modulator",
969
+ predicate: "modulates",
970
+ score,
971
+ is_clinical: hasClinical,
972
+ is_human: hasClinical,
973
+ metadata: {
974
+ chembl_id: m.moleculeChemblId,
975
+ max_phase: phase,
976
+ molecule_type: m.moleculeType,
977
+ first_approval: m.firstApproval,
978
+ triage_rationale: triageRationales.get(m.moleculeChemblId),
979
+ },
980
+ },
981
+ ],
982
+ };
983
+ });
984
+ return rows.sort((a, b) => b.best_score - a.best_score);
985
+ }