@inflexa-ai/harness 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/dist/agents/conversation-agent.d.ts +3 -0
  2. package/dist/agents/conversation-agent.js +5 -2
  3. package/dist/agents/report-builder.d.ts +2 -0
  4. package/dist/agents/report-builder.js +2 -0
  5. package/dist/agents/sandbox/shared.d.ts +3 -0
  6. package/dist/agents/sandbox/shared.js +5 -0
  7. package/dist/agents/sandbox/types.d.ts +1 -1
  8. package/dist/app/chat-turn.d.ts +2 -0
  9. package/dist/app/chat-turn.js +11 -2
  10. package/dist/app/spawn-report-session.d.ts +85 -0
  11. package/dist/app/spawn-report-session.js +83 -0
  12. package/dist/app/synthesize-run.d.ts +3 -0
  13. package/dist/app/synthesize-run.js +2 -1
  14. package/dist/citations/__fixtures__/resolver.d.ts +3 -0
  15. package/dist/citations/__fixtures__/resolver.js +9 -0
  16. package/dist/citations/aggregate.d.ts +3 -0
  17. package/dist/citations/aggregate.js +44 -0
  18. package/dist/citations/clients/arxiv.d.ts +6 -0
  19. package/dist/citations/clients/arxiv.js +34 -0
  20. package/dist/citations/clients/common.d.ts +11 -0
  21. package/dist/citations/clients/common.js +43 -0
  22. package/dist/citations/clients/crossref.d.ts +8 -0
  23. package/dist/citations/clients/crossref.js +98 -0
  24. package/dist/citations/clients/doi-registry.d.ts +3 -0
  25. package/dist/citations/clients/doi-registry.js +95 -0
  26. package/dist/citations/clients/pubmed.d.ts +6 -0
  27. package/dist/citations/clients/pubmed.js +83 -0
  28. package/dist/citations/clients/semantic-scholar.d.ts +6 -0
  29. package/dist/citations/clients/semantic-scholar.js +60 -0
  30. package/dist/citations/compare.d.ts +9 -0
  31. package/dist/citations/compare.js +72 -0
  32. package/dist/citations/match.d.ts +11 -0
  33. package/dist/citations/match.js +173 -0
  34. package/dist/citations/normalize.d.ts +31 -0
  35. package/dist/citations/normalize.js +187 -0
  36. package/dist/citations/plan.d.ts +2 -0
  37. package/dist/citations/plan.js +59 -0
  38. package/dist/citations/resolve.d.ts +28 -0
  39. package/dist/citations/resolve.js +238 -0
  40. package/dist/citations/types.d.ts +583 -0
  41. package/dist/citations/types.js +129 -0
  42. package/dist/contracts/chat-events.d.ts +9 -0
  43. package/dist/contracts/index.d.ts +6 -2
  44. package/dist/contracts/index.js +3 -1
  45. package/dist/contracts/organ-system.d.ts +49 -0
  46. package/dist/contracts/organ-system.js +67 -0
  47. package/dist/contracts/report-blocks.d.ts +564 -0
  48. package/dist/contracts/report-blocks.js +117 -0
  49. package/dist/contracts/report-reference.d.ts +459 -0
  50. package/dist/contracts/report-reference.js +256 -0
  51. package/dist/contracts/schemas/chat-events.d.ts +2 -0
  52. package/dist/contracts/schemas/chat-events.js +2 -0
  53. package/dist/contracts/schemas/chat-parts.d.ts +8 -8
  54. package/dist/contracts/severity.d.ts +15 -0
  55. package/dist/contracts/severity.js +10 -0
  56. package/dist/contracts/target-dossier.d.ts +8673 -12970
  57. package/dist/contracts/target-dossier.js +534 -591
  58. package/dist/data/safety-panel-schema.d.ts +18 -5
  59. package/dist/data/safety-panel-schema.js +4 -4
  60. package/dist/execution/artifact-metadata.js +1 -0
  61. package/dist/execution/report-runner.js +1 -3
  62. package/dist/execution/run-synthesis.d.ts +3 -0
  63. package/dist/execution/run-synthesis.js +3 -0
  64. package/dist/index.d.ts +12 -1
  65. package/dist/index.js +22 -0
  66. package/dist/lib/async-utils.d.ts +16 -4
  67. package/dist/lib/async-utils.js +20 -15
  68. package/dist/lib/cache.d.ts +8 -0
  69. package/dist/lib/cache.js +35 -0
  70. package/dist/lib/host-concurrency.js +1 -0
  71. package/dist/lib/rate-limit.d.ts +35 -0
  72. package/dist/lib/rate-limit.js +121 -0
  73. package/dist/literature/sources/arxiv.d.ts +22 -0
  74. package/dist/literature/sources/arxiv.js +103 -0
  75. package/dist/literature/sources/http.d.ts +28 -0
  76. package/dist/literature/sources/http.js +97 -0
  77. package/dist/literature/sources/pubmed.d.ts +68 -0
  78. package/dist/literature/sources/pubmed.js +266 -0
  79. package/dist/literature/sources/semantic-scholar.d.ts +24 -0
  80. package/dist/literature/sources/semantic-scholar.js +71 -0
  81. package/dist/loop/__fixtures__/scripted-provider.js +23 -2
  82. package/dist/loop/run-agent.js +58 -10
  83. package/dist/loop/tool-detail.d.ts +40 -0
  84. package/dist/loop/tool-detail.js +35 -3
  85. package/dist/loop/types.d.ts +13 -0
  86. package/dist/memory/thread-history.d.ts +10 -0
  87. package/dist/memory/thread-history.js +12 -1
  88. package/dist/memory/thread-store.d.ts +142 -25
  89. package/dist/memory/thread-store.js +228 -40
  90. package/dist/prompts/literature-reviewer.d.ts +1 -1
  91. package/dist/prompts/literature-reviewer.js +2 -0
  92. package/dist/prompts/target-assessment/briefs/executive-recommendation.d.ts +1 -1
  93. package/dist/prompts/target-assessment/briefs/executive-recommendation.js +5 -5
  94. package/dist/prompts/target-assessment/briefs/liability-bullets.d.ts +1 -1
  95. package/dist/prompts/target-assessment/briefs/liability-bullets.js +1 -1
  96. package/dist/prompts/target-assessment/briefs/target-organ-liabilities.d.ts +1 -1
  97. package/dist/prompts/target-assessment/briefs/target-organ-liabilities.js +11 -3
  98. package/dist/prompts/target-assessment/investigation/adversarial-critique.d.ts +1 -0
  99. package/dist/prompts/target-assessment/investigation/adversarial-critique.js +67 -0
  100. package/dist/prompts/target-assessment/investigation/claim-reverification.d.ts +1 -0
  101. package/dist/prompts/target-assessment/investigation/claim-reverification.js +49 -0
  102. package/dist/prompts/target-assessment/investigation/index.d.ts +3 -0
  103. package/dist/prompts/target-assessment/investigation/index.js +3 -0
  104. package/dist/prompts/target-assessment/investigation/mechanism-proposal.d.ts +1 -0
  105. package/dist/prompts/target-assessment/investigation/mechanism-proposal.js +49 -0
  106. package/dist/prompts/target-assessment/tox-voice/index.d.ts +1 -1
  107. package/dist/prompts/target-assessment/tox-voice/vocabulary.d.ts +8 -5
  108. package/dist/prompts/target-assessment/tox-voice/vocabulary.js +9 -20
  109. package/dist/providers/__fixtures__/session.d.ts +5 -4
  110. package/dist/providers/__fixtures__/session.js +4 -4
  111. package/dist/report-model/block-walk.d.ts +56 -0
  112. package/dist/report-model/block-walk.js +89 -0
  113. package/dist/report-model/draft-finish.d.ts +60 -0
  114. package/dist/report-model/draft-finish.js +56 -0
  115. package/dist/report-model/draft-operations.d.ts +125 -0
  116. package/dist/report-model/draft-operations.js +341 -0
  117. package/dist/report-model/draft-read.d.ts +59 -0
  118. package/dist/report-model/draft-read.js +109 -0
  119. package/dist/report-model/draft.d.ts +51 -0
  120. package/dist/report-model/draft.js +32 -0
  121. package/dist/report-model/fixture-resolver.d.ts +8 -0
  122. package/dist/report-model/fixture-resolver.js +252 -0
  123. package/dist/report-model/mint-snapshot.d.ts +30 -0
  124. package/dist/report-model/mint-snapshot.js +40 -0
  125. package/dist/report-model/reference-resolver.d.ts +113 -0
  126. package/dist/report-model/reference-resolver.js +60 -0
  127. package/dist/report-model/structural-validation.d.ts +22 -0
  128. package/dist/report-model/structural-validation.js +68 -0
  129. package/dist/report-model/validate.d.ts +40 -0
  130. package/dist/report-model/validate.js +80 -0
  131. package/dist/report-render/chart.d.ts +33 -0
  132. package/dist/report-render/chart.js +538 -0
  133. package/dist/report-render/page.d.ts +127 -0
  134. package/dist/report-render/page.js +307 -0
  135. package/dist/report-render/references.d.ts +32 -0
  136. package/dist/report-render/references.js +44 -0
  137. package/dist/report-render/render.d.ts +25 -0
  138. package/dist/report-render/render.js +125 -0
  139. package/dist/report-render/script-json.d.ts +13 -0
  140. package/dist/report-render/script-json.js +15 -0
  141. package/dist/report-render/types.d.ts +39 -0
  142. package/dist/report-render/types.js +10 -0
  143. package/dist/report-render/views/chart-view.d.ts +11 -0
  144. package/dist/report-render/views/chart-view.js +23 -0
  145. package/dist/report-render/views/page-view.d.ts +20 -0
  146. package/dist/report-render/views/page-view.js +49 -0
  147. package/dist/report-render/views/prose.d.ts +28 -0
  148. package/dist/report-render/views/prose.js +75 -0
  149. package/dist/report-render/views/references-view.d.ts +20 -0
  150. package/dist/report-render/views/references-view.js +64 -0
  151. package/dist/report-render/views/values.d.ts +42 -0
  152. package/dist/report-render/views/values.js +43 -0
  153. package/dist/runtime/assemble.d.ts +50 -4
  154. package/dist/runtime/assemble.js +47 -3
  155. package/dist/runtime/boot.d.ts +3 -3
  156. package/dist/runtime/boot.js +22 -5
  157. package/dist/runtime/dbos.d.ts +4 -4
  158. package/dist/state/artifacts.d.ts +16 -0
  159. package/dist/state/artifacts.js +18 -0
  160. package/dist/state/init.js +77 -1
  161. package/dist/state/purge-analysis.js +1 -0
  162. package/dist/state/report-versions.d.ts +132 -0
  163. package/dist/state/report-versions.js +194 -0
  164. package/dist/state/schema.d.ts +2 -2
  165. package/dist/tasks/data-profile.js +1 -0
  166. package/dist/tools/bio/chembl.js +1 -0
  167. package/dist/tools/bio/comptox.js +1 -0
  168. package/dist/tools/bio/drug-gene-interactions.js +1 -0
  169. package/dist/tools/bio/gene-disease-evidence.js +1 -0
  170. package/dist/tools/bio/gene-preclinical-profile.d.ts +1 -1
  171. package/dist/tools/bio/gene-preclinical-profile.js +1 -0
  172. package/dist/tools/bio/keys.d.ts +4 -2
  173. package/dist/tools/bio/keys.js +3 -2
  174. package/dist/tools/bio/lookup-annotation.js +1 -0
  175. package/dist/tools/bio/opentargets.d.ts +3 -3
  176. package/dist/tools/bio/opentargets.js +4 -3
  177. package/dist/tools/bio/pubchem.js +1 -0
  178. package/dist/tools/bio/pubmed.js +4 -4
  179. package/dist/tools/bio/search-clinical-trials.js +1 -0
  180. package/dist/tools/bio/search-faers.js +1 -0
  181. package/dist/tools/bio/search-geo-datasets.js +1 -0
  182. package/dist/tools/bio/search-interactions.js +1 -0
  183. package/dist/tools/bio/target-safety.d.ts +4 -6
  184. package/dist/tools/bio/target-safety.js +7 -6
  185. package/dist/tools/define-tool.d.ts +19 -12
  186. package/dist/tools/define-tool.js +4 -2
  187. package/dist/tools/display/show-user.js +1 -0
  188. package/dist/tools/iterate-report.js +2 -0
  189. package/dist/tools/lib/chembl-client.d.ts +2 -0
  190. package/dist/tools/lib/chembl-client.js +1 -0
  191. package/dist/tools/lib/monarch-client.d.ts +42 -0
  192. package/dist/tools/lib/monarch-client.js +100 -0
  193. package/dist/tools/lib/ncbi-utils.d.ts +3 -58
  194. package/dist/tools/lib/ncbi-utils.js +2 -286
  195. package/dist/tools/lib/pubmed-client.d.ts +5 -12
  196. package/dist/tools/lib/pubmed-client.js +20 -79
  197. package/dist/tools/report/build-report.js +1 -0
  198. package/dist/tools/report/mint-preview-url.js +1 -0
  199. package/dist/tools/report/preview-snapshot.js +1 -0
  200. package/dist/tools/report/submit-report.js +1 -0
  201. package/dist/tools/report/version-fs.js +4 -0
  202. package/dist/tools/report-authoring/authoring-tools.d.ts +134 -0
  203. package/dist/tools/report-authoring/authoring-tools.js +352 -0
  204. package/dist/tools/research/context7-docs.js +2 -0
  205. package/dist/tools/research/generate-analogy-report.js +3 -2
  206. package/dist/tools/research/generate-plan.js +3 -0
  207. package/dist/tools/research/index.d.ts +1 -0
  208. package/dist/tools/research/index.js +1 -0
  209. package/dist/tools/research/inspect-data-profile.js +4 -0
  210. package/dist/tools/research/inspect-run.d.ts +1 -1
  211. package/dist/tools/research/literature-reviewer.d.ts +3 -0
  212. package/dist/tools/research/literature-reviewer.js +3 -0
  213. package/dist/tools/research/resolve-citation.d.ts +3 -0
  214. package/dist/tools/research/resolve-citation.js +15 -0
  215. package/dist/tools/research/search-arxiv.d.ts +3 -19
  216. package/dist/tools/research/search-arxiv.js +10 -105
  217. package/dist/tools/research/search-github-repos.js +1 -0
  218. package/dist/tools/research/search-semantic-scholar.d.ts +8 -33
  219. package/dist/tools/research/search-semantic-scholar.js +30 -88
  220. package/dist/tools/sandbox/list-available-packages.js +23 -0
  221. package/dist/tools/sandbox/list-available-refs.js +37 -2
  222. package/dist/tools/sandbox/report-blocker.js +1 -0
  223. package/dist/tools/sandbox/skills.js +2 -0
  224. package/dist/tools/workspace/file-stat.js +1 -0
  225. package/dist/tools/workspace/show-file.js +2 -0
  226. package/dist/tools/workspace/show-plan.js +1 -0
  227. package/dist/workflows/execute-analysis.d.ts +8 -1
  228. package/dist/workflows/execute-analysis.js +6 -5
  229. package/dist/workflows/execute-target-assessment.d.ts +13 -2
  230. package/dist/workflows/execute-target-assessment.js +78 -16
  231. package/dist/workflows/sandbox-step.d.ts +5 -0
  232. package/dist/workflows/sandbox-step.js +1 -0
  233. package/dist/workflows/target-assessment/assemblers/index.d.ts +1 -1
  234. package/dist/workflows/target-assessment/assemblers/index.js +1 -1
  235. package/dist/workflows/target-assessment/assemblers/literature.d.ts +9 -27
  236. package/dist/workflows/target-assessment/assemblers/literature.js +32 -48
  237. package/dist/workflows/target-assessment/assemblers/orchestrator.d.ts +17 -9
  238. package/dist/workflows/target-assessment/assemblers/orchestrator.js +195 -85
  239. package/dist/workflows/target-assessment/assemblers/safety.d.ts +70 -48
  240. package/dist/workflows/target-assessment/assemblers/safety.js +125 -42
  241. package/dist/workflows/target-assessment/collectors/index.d.ts +5 -2
  242. package/dist/workflows/target-assessment/collectors/index.js +48 -5
  243. package/dist/workflows/target-assessment/coverage.d.ts +43 -27
  244. package/dist/workflows/target-assessment/coverage.js +33 -29
  245. package/dist/workflows/target-assessment/fanout/index.js +1 -0
  246. package/dist/workflows/target-assessment/investigation/index.d.ts +97 -0
  247. package/dist/workflows/target-assessment/investigation/index.js +419 -0
  248. package/dist/workflows/target-assessment/lib/approval-precedents.d.ts +26 -5
  249. package/dist/workflows/target-assessment/lib/approval-precedents.js +95 -29
  250. package/dist/workflows/target-assessment/lib/citation-validator.js +1 -1
  251. package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.d.ts +2 -2
  252. package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.d.ts +2 -3
  253. package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.js +0 -4
  254. package/dist/workflows/target-assessment/lib/compute-derived.d.ts +6 -5
  255. package/dist/workflows/target-assessment/lib/compute-derived.js +14 -5
  256. package/dist/workflows/target-assessment/lib/family-complex-supplement.d.ts +5 -6
  257. package/dist/workflows/target-assessment/lib/family-complex-supplement.js +2 -3
  258. package/dist/workflows/target-assessment/lib/fda-label-safety.d.ts +72 -0
  259. package/dist/workflows/target-assessment/lib/fda-label-safety.js +166 -0
  260. package/dist/workflows/target-assessment/lib/heterodimer-filter.d.ts +0 -9
  261. package/dist/workflows/target-assessment/lib/heterodimer-filter.js +0 -10
  262. package/dist/workflows/target-assessment/lib/hpo-organ-map.d.ts +34 -0
  263. package/dist/workflows/target-assessment/lib/hpo-organ-map.js +63 -0
  264. package/dist/workflows/target-assessment/lib/impc-organ-map.d.ts +19 -0
  265. package/dist/workflows/target-assessment/lib/impc-organ-map.js +39 -0
  266. package/dist/workflows/target-assessment/lib/meddra-organ-map.d.ts +24 -14
  267. package/dist/workflows/target-assessment/lib/meddra-organ-map.js +59 -47
  268. package/dist/workflows/target-assessment/lib/recommendation-sanitizer.js +1 -1
  269. package/dist/workflows/target-assessment/lib/regulatory-actions.d.ts +2 -3
  270. package/dist/workflows/target-assessment/lib/regulatory-actions.js +33 -4
  271. package/dist/workflows/target-assessment/lib/safety-corroboration.d.ts +44 -0
  272. package/dist/workflows/target-assessment/lib/safety-corroboration.js +273 -0
  273. package/dist/workflows/target-assessment/lib/target-identity-filter.d.ts +5 -7
  274. package/dist/workflows/target-assessment/lib/target-identity-filter.js +5 -7
  275. package/dist/workflows/target-assessment/metrics.d.ts +1 -6
  276. package/dist/workflows/target-assessment/metrics.js +1 -13
  277. package/dist/workflows/target-assessment/phase4-assemble.d.ts +2149 -809
  278. package/dist/workflows/target-assessment/phase4-assemble.js +19 -19
  279. package/dist/workflows/target-assessment/phase5-persist.d.ts +20 -21
  280. package/dist/workflows/target-assessment/phase5-persist.js +56 -173
  281. package/dist/workflows/target-assessment/schemas.d.ts +48 -3
  282. package/dist/workflows/target-assessment/schemas.js +19 -0
  283. package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.d.ts +1 -0
  284. package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.js +2 -0
  285. package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +27 -63
  286. package/dist/workflows/target-assessment/steps/phase2-aggregate.js +0 -4
  287. package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +28 -155
  288. package/dist/workflows/target-assessment/steps/phase3-aggregate.js +0 -6
  289. package/dist/workflows/target-assessment/steps/synthesis/diagnostics.d.ts +0 -6
  290. package/dist/workflows/target-assessment/steps/synthesis/diagnostics.js +0 -18
  291. package/dist/workflows/target-assessment/sub-workflows/per-modulator-polypharm.d.ts +1 -0
  292. package/dist/workflows/target-assessment/synthesis/index.d.ts +52 -5
  293. package/dist/workflows/target-assessment/synthesis/index.js +4 -1
  294. package/dist/workflows/target-assessment/synthesis-probes.d.ts +3 -3
  295. package/package.json +4 -1
@@ -1,8 +1,4 @@
1
1
  import { z } from "zod";
2
- export declare const ORGAN_SYSTEMS: readonly ["cardiac", "hepatic", "renal", "cns", "hematologic", "gi", "respiratory", "metabolic", "immune"];
3
- export declare const SEVERITIES: readonly ["high", "medium", "low"];
4
- export type OrganSystem = (typeof ORGAN_SYSTEMS)[number];
5
- export type Severity = (typeof SEVERITIES)[number];
6
2
  export declare const CHEMBL_RE: RegExp;
7
3
  export declare const UNIPROT_RE: RegExp;
8
4
  export declare const SafetyTargetSchema: z.ZodObject<{
@@ -16,11 +12,20 @@ export declare const SafetyTargetSchema: z.ZodObject<{
16
12
  metabolic: "metabolic";
17
13
  immune: "immune";
18
14
  hepatic: "hepatic";
15
+ musculoskeletal: "musculoskeletal";
19
16
  cns: "cns";
20
17
  renal: "renal";
18
+ reproductive: "reproductive";
21
19
  respiratory: "respiratory";
22
20
  cardiac: "cardiac";
21
+ vascular: "vascular";
22
+ pns: "pns";
23
23
  gi: "gi";
24
+ pancreas: "pancreas";
25
+ endocrine_thyroid: "endocrine_thyroid";
26
+ dermatologic: "dermatologic";
27
+ ocular: "ocular";
28
+ oncology: "oncology";
24
29
  }>;
25
30
  clinical_consequence: z.ZodString;
26
31
  severity: z.ZodEnum<{
@@ -46,11 +51,20 @@ export declare const SafetyPanelFileSchema: z.ZodObject<{
46
51
  metabolic: "metabolic";
47
52
  immune: "immune";
48
53
  hepatic: "hepatic";
54
+ musculoskeletal: "musculoskeletal";
49
55
  cns: "cns";
50
56
  renal: "renal";
57
+ reproductive: "reproductive";
51
58
  respiratory: "respiratory";
52
59
  cardiac: "cardiac";
60
+ vascular: "vascular";
61
+ pns: "pns";
53
62
  gi: "gi";
63
+ pancreas: "pancreas";
64
+ endocrine_thyroid: "endocrine_thyroid";
65
+ dermatologic: "dermatologic";
66
+ ocular: "ocular";
67
+ oncology: "oncology";
54
68
  }>;
55
69
  clinical_consequence: z.ZodString;
56
70
  severity: z.ZodEnum<{
@@ -61,4 +75,3 @@ export declare const SafetyPanelFileSchema: z.ZodObject<{
61
75
  references: z.ZodArray<z.ZodString>;
62
76
  }, z.core.$strip>>;
63
77
  }, z.core.$strip>;
64
- export type SafetyPanelFile = z.infer<typeof SafetyPanelFileSchema>;
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
- export const ORGAN_SYSTEMS = ["cardiac", "hepatic", "renal", "cns", "hematologic", "gi", "respiratory", "metabolic", "immune"];
3
- export const SEVERITIES = ["high", "medium", "low"];
2
+ import { OrganSystemSchema } from "../contracts/organ-system.js";
3
+ import { SeveritySchema } from "../contracts/severity.js";
4
4
  export const CHEMBL_RE = /^CHEMBL\d+$/;
5
5
  // UniProt 6-char accession: letter (any A-Z, covering A-N, O, P, Q, R-Z sub-families),
6
6
  // followed by a digit, three alphanumerics, and a final digit.
@@ -21,9 +21,9 @@ export const SafetyTargetSchema = z.object({
21
21
  uniprot: UniprotSchema,
22
22
  ensembl_gene_id: EnsemblGeneSchema.optional(),
23
23
  name: z.string().min(1).max(120),
24
- organ_system: z.enum(ORGAN_SYSTEMS),
24
+ organ_system: OrganSystemSchema,
25
25
  clinical_consequence: z.string().min(1).max(200),
26
- severity: z.enum(SEVERITIES),
26
+ severity: SeveritySchema,
27
27
  references: z.array(ReferenceSchema).min(1),
28
28
  });
29
29
  export const SafetyPanelFileSchema = z.object({
@@ -95,6 +95,7 @@ function buildSubmitTool(holder, knownPaths) {
95
95
  "remaining}: accepted=true means every file now has metadata — STOP. " +
96
96
  "Otherwise drop the unknownPaths and describe the remaining files.",
97
97
  inputSchema: SubmitFileMetadataInputSchema,
98
+ describeCall: "none",
98
99
  execute: async (input) => {
99
100
  const unknownPaths = [];
100
101
  for (const entry of input.files) {
@@ -39,11 +39,9 @@ import { passthroughStep } from "../loop/run-step.js";
39
39
  import { previewVersionDir, previewDir, latestPreviewVersion } from "../workspace/paths.js";
40
40
  import { withPreviewLock } from "../tools/lib/preview-lock.js";
41
41
  import { createBuildReportTool, createSubmitReportTool, createMintPreviewUrlTool, createPreviewSnapshotTool, createVersionFsTools, } from "../tools/report/index.js";
42
- import { createReportBuilderAgent, REPORT_BUILDER_AGENT_ID } from "../agents/report-builder.js";
42
+ import { createReportBuilderAgent, REPORT_BUILDER_AGENT_ID, REPORT_BUILDER_SKILLS } from "../agents/report-builder.js";
43
43
  import { createSkillTools } from "../tools/sandbox/skills.js";
44
44
  import { createNoopLogger } from "../lib/console-logger.js";
45
- /** Skill pack the report-builder prompt directs the model to read (design-system reference). */
46
- const REPORT_BUILDER_SKILLS = ["report-html"];
47
45
  const REPORT_AGENT_MAX_STEPS = 75;
48
46
  export async function runReportIteration(deps, opts) {
49
47
  const logger = (deps.logger ?? createNoopLogger()).named("report-runner").with({ previewId: opts.previewId });
@@ -31,6 +31,7 @@ import type { UsageRecorder } from "../billing/usage-recorder.js";
31
31
  import type { RunSession } from "../auth/types.js";
32
32
  import { type Tool } from "../tools/define-tool.js";
33
33
  import type { BioToolKeys } from "../tools/bio/keys.js";
34
+ import type { CitationResolver } from "../citations/types.js";
34
35
  /**
35
36
  * The synthesizer's agent identity — the `source.agentId` on its loop events
36
37
  * and the `agent_id` of the run-phase `synthesis` row `executeAnalysis` writes
@@ -67,6 +68,8 @@ export interface GenerateRunSynthesisInput {
67
68
  readonly model: string;
68
69
  /** API keys for the bio/chem tools the embedded literature reviewer uses. */
69
70
  readonly bioKeys: BioToolKeys;
71
+ /** Shared resolver used by the embedded literature reviewer. */
72
+ readonly citationResolver: CitationResolver;
70
73
  /** LLM usage-accounting seam for the synthesizer + reviewer loops; omitted falls back to the no-op recorder. */
71
74
  readonly usageRecorder?: UsageRecorder;
72
75
  /** Step summaries from the completed run. Non-empty. */
@@ -270,6 +270,7 @@ function buildValidateTool(ctx) {
270
270
  inputSchema: z.object({
271
271
  synthesis: z.unknown().describe("The candidate synthesis, in any shape. Field-by-field schema: see submit_synthesis."),
272
272
  }),
273
+ describeCall: "none",
273
274
  execute: async (input) => {
274
275
  const result = fullyValidate(input.synthesis, ctx);
275
276
  return ok(result.valid ? { valid: true, issues: [] } : { valid: false, issues: result.issues });
@@ -289,6 +290,7 @@ function buildSubmitTool(holder, ctx) {
289
290
  "already-accepted synthesis untouched; a later accepted submission " +
290
291
  "supersedes an earlier one.",
291
292
  inputSchema: z.object({ synthesis: RunSynthesisSchema }),
293
+ describeCall: "none",
292
294
  execute: async (input) => {
293
295
  const result = fullyValidate(input.synthesis, ctx);
294
296
  if (!result.valid) {
@@ -349,6 +351,7 @@ export async function generateRunSynthesis(input) {
349
351
  provider: input.provider,
350
352
  model: input.model,
351
353
  bioKeys: input.bioKeys,
354
+ citationResolver: input.citationResolver,
352
355
  usageRecorder: input.usageRecorder,
353
356
  });
354
357
  const validateTool = buildValidateTool(innerCtx);
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
  export { assembleCoreRuntime } from "./runtime/assemble.js";
8
8
  export type { CoreRuntime, CoreRuntimeDeps, CoreWorkflowDeps, RegisteredWorkflows, ConversationAssemblyDeps, SandboxStepCallable } from "./runtime/assemble.js";
9
+ export type { ThreadAgentResolver, UnregisteredThreadType } from "./runtime/assemble.js";
9
10
  export { bootHarness } from "./runtime/boot.js";
10
11
  export type { BootHarnessDeps, BootedHarness } from "./runtime/boot.js";
11
12
  export { createConversationAgent } from "./agents/conversation-agent.js";
@@ -31,6 +32,11 @@ export type { DbosWorkflowPurgerDeps } from "./execution/dbos-workflow-purger.js
31
32
  export type { WorkflowPurger } from "./execution/workflow-purger.js";
32
33
  export { defineTool, isToolError } from "./tools/define-tool.js";
33
34
  export type { Tool, ToolDefinition, ToolContext, ToolError } from "./tools/define-tool.js";
35
+ export { normalizeDetail, DETAIL_MAX_LENGTH } from "./loop/tool-detail.js";
36
+ export { createCitationResolver } from "./citations/resolve.js";
37
+ export type { CitationResolverConfig, CitationResolverDependencies, CitationResolverSourceConfig } from "./citations/resolve.js";
38
+ export { CitationKindSchema, CitationInputSchema, CitationSourceSchema, CitationSourceStatusSchema, CitationResolutionResultSchema, CitationVerdictSchema, CitationCoverageSchema, ComparisonStatusSchema, CitationFieldSchema, UnsupportedWorkKindSchema, CitationIdentifiersSchema, NormalizedCitationMetadataSchema, NormalizedCitationSchema, CitationRecordSchema, IdentifierEvidenceSchema, CitationSourceOutcomeSchema, CitationFieldComparisonSchema, CitationConflictSchema, CitationCandidateClusterSchema, CitationClusterRelationSchema, CitationSourceOperationSchema, CitationSourcePlanItemSchema, } from "./citations/types.js";
39
+ export type { CitationKind, CitationInput, CitationSource, CitationSourceStatus, CitationResolver, CitationResolveOptions, CitationResolutionResult, CitationVerdict, CitationCoverage, ComparisonStatus, CitationField, UnsupportedWorkKind, CitationIdentifiers, NormalizedCitationMetadata, NormalizedCitation, CitationSourceOutcome, CitationRecord, IdentifierEvidence, CitationFieldComparison, CitationConflict, CitationCandidateCluster, CitationSourceClient, CitationSourceRequest, CitationSourceOperation, CitationSourcePlanItem, RegistrationAgencyEvidence, } from "./citations/types.js";
34
40
  export { createAskGateway } from "./tools/approval/gateway.js";
35
41
  export type { AskGateway, AskGatewayDeps, AskContext, AnswerOutcome, PendingAsk } from "./tools/approval/gateway.js";
36
42
  export { UnavailableAsk, AskRejectedError } from "./tools/approval/contract.js";
@@ -56,7 +62,7 @@ export { createStreamingChat } from "./providers/streaming-chat.js";
56
62
  export { prepareChatTurn } from "./app/chat-turn.js";
57
63
  export type { PrepareChatTurnDeps, PrepareChatTurnParams, PrepareChatTurnResult } from "./app/chat-turn.js";
58
64
  export { createThreadStore } from "./memory/thread-store.js";
59
- export type { ThreadStore, Thread, CreateThreadInput, ListThreadsInput, ThreadPage } from "./memory/thread-store.js";
65
+ export type { ThreadStore, Thread, ThreadType, ThreadInputError, CreateThreadInput, ListThreadsInput, ThreadPage } from "./memory/thread-store.js";
60
66
  export { createThreadHistory, conversationRecordTurn } from "./memory/thread-history.js";
61
67
  export type { ThreadHistory, StoredMessage, MessagePage, RetractOutcome, ConversationTurn } from "./memory/thread-history.js";
62
68
  export { syntheticUserMessage, syntheticRecordMessage, isSyntheticUserMessage, isSyntheticRecordMessage } from "./memory/ai-sdk-message-storage.js";
@@ -72,6 +78,9 @@ export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./cont
72
78
  export type { CortexChatPartType, PartDescriptor, PartEmitter, PartConsumer } from "./contracts/part-registry.js";
73
79
  export { launchDbos, shutdownDbos, sweepEphemeralWorkflows } from "./runtime/dbos.js";
74
80
  export type { DbosConfig } from "./runtime/dbos.js";
81
+ export { dbosState } from "./runtime/dbos.js";
82
+ export type { DbosState } from "./runtime/dbos.js";
83
+ export { isDraining } from "./runtime/lifecycle.js";
75
84
  export { StatusString } from "@dbos-inc/dbos-sdk";
76
85
  export type { WorkflowStatusString } from "@dbos-inc/dbos-sdk";
77
86
  export { createPool } from "./lib/storage.js";
@@ -113,6 +122,8 @@ export { registerExecuteAnalysis } from "./workflows/execute-analysis.js";
113
122
  export type { ExecuteAnalysisDeps, ExecuteAnalysisInput, ExecuteAnalysisResult, RunObservation, RunProvenanceEvent, RunStepObservation, StepRuntimeStatus, } from "./workflows/execute-analysis.js";
114
123
  export { registerSandboxStep } from "./workflows/sandbox-step.js";
115
124
  export type { SandboxStepDeps, SandboxStepInput, SandboxStepResult, SandboxAgentBuildContext } from "./workflows/sandbox-step.js";
125
+ export { DEFAULT_CLAIM_INVESTIGATION_CONFIG } from "./workflows/target-assessment/investigation/index.js";
126
+ export type { ClaimInvestigationConfig } from "./workflows/target-assessment/investigation/index.js";
116
127
  export { createRunEventStream } from "./execution/run-event-stream.js";
117
128
  export type { RunEventStream, RunEventStreamDeps, RunEventSubscribeOptions, RunEventPartHandler } from "./execution/run-event-stream.js";
118
129
  export { createSandboxAgents, SANDBOX_AGENT_META } from "./agents/sandbox/index.js";
package/dist/index.js CHANGED
@@ -33,6 +33,18 @@ export { createDbosRunLauncher } from "./execution/dbos-run-launcher.js";
33
33
  export { createDbosWorkflowPurger } from "./execution/dbos-workflow-purger.js";
34
34
  // Tool primitive.
35
35
  export { defineTool, isToolError } from "./tools/define-tool.js";
36
+ // Tool-call-detail authoring aids for an embedder that contributes a host tool.
37
+ // A `describeCall` hook that pre-empts truncation — a count in place of a
38
+ // mid-value cut that would name a file that does not exist — must gate on the
39
+ // SAME bound the harness enforces at the emit site. Thus `DETAIL_MAX_LENGTH`
40
+ // rides the curated surface, so a host reads the one number rather than copying
41
+ // it and drifting when the harness retunes the cap. `normalizeDetail` is that
42
+ // emit-site transform, exported so a host can assert a hook's output against
43
+ // exactly what the harness will render.
44
+ export { normalizeDetail, DETAIL_MAX_LENGTH } from "./loop/tool-detail.js";
45
+ // Host-agnostic citation verification service and its public contracts.
46
+ export { createCitationResolver } from "./citations/resolve.js";
47
+ export { CitationKindSchema, CitationInputSchema, CitationSourceSchema, CitationSourceStatusSchema, CitationResolutionResultSchema, CitationVerdictSchema, CitationCoverageSchema, ComparisonStatusSchema, CitationFieldSchema, UnsupportedWorkKindSchema, CitationIdentifiersSchema, NormalizedCitationMetadataSchema, NormalizedCitationSchema, CitationRecordSchema, IdentifierEvidenceSchema, CitationSourceOutcomeSchema, CitationFieldComparisonSchema, CitationConflictSchema, CitationCandidateClusterSchema, CitationClusterRelationSchema, CitationSourceOperationSchema, CitationSourcePlanItemSchema, } from "./citations/types.js";
36
48
  // Seam: tool approval (`ctx.ask`). `createAskGateway` realizes the `Ask` seam
37
49
  // over the injected `Pool` and carries the outward `answer`/`pending` API plus
38
50
  // the boot-time `sweepExpired`; `UnavailableAsk` is the shipped deny-by-default
@@ -117,6 +129,12 @@ export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./cont
117
129
  // older releases could leave PENDING `ephemeral:*` rows that recovery would
118
130
  // otherwise re-dispatch. No current workflow creates that prefix.
119
131
  export { launchDbos, shutdownDbos, sweepEphemeralWorkflows } from "./runtime/dbos.js";
132
+ // The readiness pair. Both flags are mutated by harness-owned code an embedder
133
+ // does not call itself — `launchDbos` flips the DBOS state, and the `shutdown`
134
+ // handle `bootHarness` returns marks draining — so the reads have to come from
135
+ // here for a host's own probe to reflect them at all.
136
+ export { dbosState } from "./runtime/dbos.js";
137
+ export { isDraining } from "./runtime/lifecycle.js";
120
138
  // DBOS workflow-status vocabulary. An embedder that reads its own
121
139
  // `dbos.workflow_status` rows must classify them against the SDK's status set,
122
140
  // but must never depend on `@dbos-inc/dbos-sdk` directly — the SDK is
@@ -176,6 +194,10 @@ export { ExecEventMessageSchema } from "./sandbox/types.js";
176
194
  // these, but an embedder running only the run engine registers them directly.
177
195
  export { registerExecuteAnalysis } from "./workflows/execute-analysis.js";
178
196
  export { registerSandboxStep } from "./workflows/sandbox-step.js";
197
+ // Target assessment — the bounds its claim-investigation phase runs under. An
198
+ // embedder wiring `executeTargetAssessment` sets these at its composition root;
199
+ // the dossier reports whichever values were in force.
200
+ export { DEFAULT_CLAIM_INVESTIGATION_CONFIG } from "./workflows/target-assessment/investigation/index.js";
179
201
  // Run-event read seam — the fine-grained durable channel beside `observeRun`.
180
202
  // The two are a deliberate pair, not a duplication: `observeRun` is the coarse,
181
203
  // in-process run/step snapshot a workflow hands its host synchronously, and it
@@ -1,10 +1,22 @@
1
1
  /**
2
- * Shared async utilities — sleep and bounded-concurrency map.
2
+ * Shared async utilities — sleep and a bounded-concurrency `Promise.all`.
3
3
  */
4
4
  /** Promise-based delay. */
5
5
  export declare function sleep(ms: number): Promise<void>;
6
6
  /**
7
- * Map over items with bounded concurrency.
8
- * At most `concurrency` items are processed simultaneously.
7
+ * Run each task with a cap on how many run at the same time, and give back the results in the order of
8
+ * the input.
9
+ *
10
+ * The signature mirrors `Promise.all`. The mapped return type is element-wise, thus a tuple of thunks
11
+ * with different return types keeps each one, and a plain array of thunks gives a plain array. The input
12
+ * is an array of thunks and not an array of promises, because a promise is already running when it is
13
+ * made, and a cap over a set of started promises caps nothing.
14
+ *
15
+ * `concurrency` must be a number at or above 1. p-queue throws a `TypeError` for any other value.
16
+ *
17
+ * The failure behavior is that of `Promise.all`. The first rejection rejects the whole call, and each
18
+ * task that the queue already started still runs to completion.
9
19
  */
10
- export declare function mapConcurrent<T, R>(items: T[], concurrency: number, fn: (item: T, index: number) => Promise<R>): Promise<R[]>;
20
+ export declare function allWithConcurrency<T extends readonly (() => unknown)[] | []>(tasks: T, concurrency: number): Promise<{
21
+ -readonly [P in keyof T]: Awaited<T[P] extends () => infer R ? R : never>;
22
+ }>;
@@ -1,24 +1,29 @@
1
1
  /**
2
- * Shared async utilities — sleep and bounded-concurrency map.
2
+ * Shared async utilities — sleep and a bounded-concurrency `Promise.all`.
3
3
  */
4
+ import PQueue from "p-queue";
4
5
  /** Promise-based delay. */
5
6
  export function sleep(ms) {
6
7
  return new Promise((resolve) => setTimeout(resolve, ms));
7
8
  }
8
9
  /**
9
- * Map over items with bounded concurrency.
10
- * At most `concurrency` items are processed simultaneously.
10
+ * Run each task with a cap on how many run at the same time, and give back the results in the order of
11
+ * the input.
12
+ *
13
+ * The signature mirrors `Promise.all`. The mapped return type is element-wise, thus a tuple of thunks
14
+ * with different return types keeps each one, and a plain array of thunks gives a plain array. The input
15
+ * is an array of thunks and not an array of promises, because a promise is already running when it is
16
+ * made, and a cap over a set of started promises caps nothing.
17
+ *
18
+ * `concurrency` must be a number at or above 1. p-queue throws a `TypeError` for any other value.
19
+ *
20
+ * The failure behavior is that of `Promise.all`. The first rejection rejects the whole call, and each
21
+ * task that the queue already started still runs to completion.
11
22
  */
12
- export async function mapConcurrent(items, concurrency, fn) {
13
- const results = new Array(items.length);
14
- let nextIndex = 0;
15
- async function worker() {
16
- while (nextIndex < items.length) {
17
- const i = nextIndex++;
18
- results[i] = await fn(items[i], i);
19
- }
20
- }
21
- const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker());
22
- await Promise.all(workers);
23
- return results;
23
+ export function allWithConcurrency(tasks, concurrency) {
24
+ const queue = new PQueue({ concurrency });
25
+ // `addAll` collapses every task onto one result type, thus it cannot express the element-wise type
26
+ // above. The cast is sound because `addAll` maps the input array through `Promise.all`, which keeps
27
+ // the position of each task, and each element is the awaited return of the task at that position.
28
+ return queue.addAll(tasks);
24
29
  }
@@ -0,0 +1,8 @@
1
+ export declare class BoundedTtlCache<Value> {
2
+ private readonly maximum;
3
+ private readonly now;
4
+ private readonly entries;
5
+ constructor(maximum: number, now?: () => number);
6
+ get(key: string): Value | undefined;
7
+ set(key: string, value: Value, ttlMs: number): void;
8
+ }
@@ -0,0 +1,35 @@
1
+ export class BoundedTtlCache {
2
+ maximum;
3
+ now;
4
+ entries = new Map();
5
+ constructor(maximum, now = Date.now) {
6
+ this.maximum = maximum;
7
+ this.now = now;
8
+ if (!Number.isInteger(maximum) || maximum < 0)
9
+ throw new Error("cache maximum must be a non-negative integer");
10
+ }
11
+ get(key) {
12
+ const entry = this.entries.get(key);
13
+ if (entry === undefined)
14
+ return undefined;
15
+ if (entry.expiresAt <= this.now()) {
16
+ this.entries.delete(key);
17
+ return undefined;
18
+ }
19
+ this.entries.delete(key);
20
+ this.entries.set(key, entry);
21
+ return entry.value;
22
+ }
23
+ set(key, value, ttlMs) {
24
+ if (this.maximum === 0 || ttlMs <= 0)
25
+ return;
26
+ this.entries.delete(key);
27
+ this.entries.set(key, { value, expiresAt: this.now() + ttlMs });
28
+ while (this.entries.size > this.maximum) {
29
+ const oldest = this.entries.keys().next().value;
30
+ if (oldest === undefined)
31
+ break;
32
+ this.entries.delete(oldest);
33
+ }
34
+ }
35
+ }
@@ -27,6 +27,7 @@ const DEFAULT_LIMITS = {
27
27
  hgnc: 6,
28
28
  uniprot: 6,
29
29
  iuphar: 4,
30
+ monarch: 3,
30
31
  ema: 2,
31
32
  pubchem: 4,
32
33
  "annotation-llm": 4,
@@ -0,0 +1,35 @@
1
+ export interface RateLimitConfig {
2
+ readonly maxConcurrency: number;
3
+ readonly requestsPerSecond: number;
4
+ /**
5
+ * Retry policy for the source's HTTP layer. Retries re-enter the limiter as
6
+ * fresh attempts, so they are paced like any other request; the limiter
7
+ * itself does not read these two fields.
8
+ */
9
+ readonly maxRetries: number;
10
+ readonly maxRetryDelayMs: number;
11
+ }
12
+ export interface RateLimitRuntime {
13
+ readonly now?: () => number;
14
+ readonly sleep?: (milliseconds: number, signal?: AbortSignal) => Promise<void>;
15
+ }
16
+ export declare function sleepWithSignal(milliseconds: number, signal?: AbortSignal): Promise<void>;
17
+ export declare class BoundedRateLimiter {
18
+ private readonly config;
19
+ private readonly semaphore;
20
+ private readonly now;
21
+ private readonly sleep;
22
+ private reservationTail;
23
+ private nextStartAt;
24
+ constructor(config: RateLimitConfig, runtime?: RateLimitRuntime);
25
+ private reserveStart;
26
+ run<T>(operation: () => Promise<T>, signal?: AbortSignal): Promise<T>;
27
+ }
28
+ /**
29
+ * Admission gate for a source's HTTP layer (`SourceHttpOptions.schedule`).
30
+ *
31
+ * It gates the network call alone: the caller arms its request timeout inside
32
+ * the admitted operation, so a request held behind pacing or a concurrency
33
+ * ceiling cannot be reported as a timeout before it ever reaches the network.
34
+ */
35
+ export declare function createRateLimitSchedule(config: RateLimitConfig, runtime?: RateLimitRuntime): <T>(operation: () => Promise<T>, signal?: AbortSignal) => Promise<T>;
@@ -0,0 +1,121 @@
1
+ function abortReason(signal) {
2
+ return signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted", "AbortError");
3
+ }
4
+ export function sleepWithSignal(milliseconds, signal) {
5
+ if (milliseconds <= 0)
6
+ return Promise.resolve();
7
+ if (signal?.aborted)
8
+ return Promise.reject(abortReason(signal));
9
+ return new Promise((resolve, reject) => {
10
+ const timeout = setTimeout(() => {
11
+ signal?.removeEventListener("abort", onAbort);
12
+ resolve();
13
+ }, milliseconds);
14
+ const onAbort = () => {
15
+ clearTimeout(timeout);
16
+ reject(abortReason(signal));
17
+ };
18
+ signal?.addEventListener("abort", onAbort, { once: true });
19
+ });
20
+ }
21
+ class Semaphore {
22
+ maximum;
23
+ active = 0;
24
+ waiters = [];
25
+ constructor(maximum) {
26
+ this.maximum = maximum;
27
+ }
28
+ async acquire(signal) {
29
+ if (signal?.aborted)
30
+ throw abortReason(signal);
31
+ if (this.active < this.maximum) {
32
+ this.active += 1;
33
+ return;
34
+ }
35
+ await new Promise((resolve, reject) => {
36
+ const waiter = { resolve, reject, ...(signal === undefined ? {} : { signal }) };
37
+ if (signal !== undefined) {
38
+ waiter.onAbort = () => {
39
+ const index = this.waiters.indexOf(waiter);
40
+ if (index >= 0)
41
+ this.waiters.splice(index, 1);
42
+ reject(abortReason(signal));
43
+ };
44
+ signal.addEventListener("abort", waiter.onAbort, { once: true });
45
+ }
46
+ this.waiters.push(waiter);
47
+ });
48
+ }
49
+ release() {
50
+ const waiter = this.waiters.shift();
51
+ if (waiter === undefined) {
52
+ this.active -= 1;
53
+ return;
54
+ }
55
+ if (waiter.signal !== undefined && waiter.onAbort !== undefined)
56
+ waiter.signal.removeEventListener("abort", waiter.onAbort);
57
+ waiter.resolve();
58
+ }
59
+ }
60
+ export class BoundedRateLimiter {
61
+ config;
62
+ semaphore;
63
+ now;
64
+ sleep;
65
+ reservationTail = Promise.resolve();
66
+ nextStartAt = 0;
67
+ constructor(config, runtime = {}) {
68
+ this.config = config;
69
+ if (!Number.isInteger(config.maxConcurrency) || config.maxConcurrency < 1)
70
+ throw new Error("maxConcurrency must be a positive integer");
71
+ if (!(config.requestsPerSecond > 0))
72
+ throw new Error("requestsPerSecond must be positive");
73
+ this.semaphore = new Semaphore(config.maxConcurrency);
74
+ this.now = runtime.now ?? Date.now;
75
+ this.sleep = runtime.sleep ?? sleepWithSignal;
76
+ }
77
+ async reserveStart(signal) {
78
+ let release;
79
+ const predecessor = this.reservationTail;
80
+ this.reservationTail = new Promise((resolve) => {
81
+ release = resolve;
82
+ });
83
+ if (signal?.aborted) {
84
+ release();
85
+ throw abortReason(signal);
86
+ }
87
+ await predecessor;
88
+ try {
89
+ if (signal?.aborted)
90
+ throw abortReason(signal);
91
+ const startAt = Math.max(this.now(), this.nextStartAt);
92
+ this.nextStartAt = startAt + 1000 / this.config.requestsPerSecond;
93
+ return startAt;
94
+ }
95
+ finally {
96
+ release();
97
+ }
98
+ }
99
+ async run(operation, signal) {
100
+ const startAt = await this.reserveStart(signal);
101
+ await this.sleep(Math.max(0, startAt - this.now()), signal);
102
+ await this.semaphore.acquire(signal);
103
+ try {
104
+ return await operation();
105
+ }
106
+ finally {
107
+ this.semaphore.release();
108
+ }
109
+ }
110
+ }
111
+ /**
112
+ * Admission gate for a source's HTTP layer (`SourceHttpOptions.schedule`).
113
+ *
114
+ * It gates the network call alone: the caller arms its request timeout inside
115
+ * the admitted operation, so a request held behind pacing or a concurrency
116
+ * ceiling cannot be reported as a timeout before it ever reaches the network.
117
+ */
118
+ export function createRateLimitSchedule(config, runtime = {}) {
119
+ const limiter = new BoundedRateLimiter(config, runtime);
120
+ return (operation, signal) => limiter.run(operation, signal);
121
+ }
@@ -0,0 +1,22 @@
1
+ import { type SourceHttpOptions, type SourceHttpResult } from "./http.js";
2
+ export interface ArxivPaper {
3
+ id: string;
4
+ title: string;
5
+ abstract: string;
6
+ authors: string[];
7
+ published: string;
8
+ categories: string[];
9
+ url: string;
10
+ pdfUrl?: string;
11
+ }
12
+ export interface ArxivSearchInput {
13
+ readonly query: string;
14
+ readonly categories?: readonly string[];
15
+ readonly limit: number;
16
+ }
17
+ export interface ArxivSource {
18
+ search(input: ArxivSearchInput, signal?: AbortSignal): Promise<SourceHttpResult<ArxivPaper[]>>;
19
+ lookupExact(id: string, limit: number, signal?: AbortSignal): Promise<SourceHttpResult<ArxivPaper[]>>;
20
+ }
21
+ export declare function parseArxivAtom(xml: string): ArxivPaper[];
22
+ export declare function createArxivSource(options?: SourceHttpOptions): ArxivSource;
@@ -0,0 +1,103 @@
1
+ import { requestText } from "./http.js";
2
+ const BASE_URL = "https://export.arxiv.org/api/query";
3
+ const stripCdata = (value) => value.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, "$1");
4
+ const decodeXmlEntities = (value) => value
5
+ .replace(/&lt;/g, "<")
6
+ .replace(/&gt;/g, ">")
7
+ .replace(/&quot;/g, '"')
8
+ .replace(/&apos;/g, "'")
9
+ .replace(/&#x([0-9a-fA-F]+);/g, (_, hexadecimal) => String.fromCodePoint(parseInt(hexadecimal, 16)))
10
+ .replace(/&#(\d+);/g, (_, decimal) => String.fromCodePoint(parseInt(decimal, 10)))
11
+ .replace(/&amp;/g, "&");
12
+ const collapseWhitespace = (value) => decodeXmlEntities(stripCdata(value)).replace(/\s+/g, " ").trim();
13
+ function extractEntries(xml) {
14
+ const expression = /<entry\b[^>]*>([\s\S]*?)<\/entry>/g;
15
+ const entries = [];
16
+ let match;
17
+ while ((match = expression.exec(xml)) !== null)
18
+ entries.push(match[1]);
19
+ return entries;
20
+ }
21
+ function firstMatch(entry, tag) {
22
+ return entry.match(new RegExp(`<${tag}\\b[^>]*>([\\s\\S]*?)</${tag}>`))?.[1];
23
+ }
24
+ function allMatches(entry, tag) {
25
+ const expression = new RegExp(`<${tag}\\b[^>]*>([\\s\\S]*?)</${tag}>`, "g");
26
+ const values = [];
27
+ let match;
28
+ while ((match = expression.exec(entry)) !== null)
29
+ values.push(match[1]);
30
+ return values;
31
+ }
32
+ function linkAttribute(entry, predicate) {
33
+ const expression = /<link\b([^>]*)\/>/g;
34
+ let match;
35
+ while ((match = expression.exec(entry)) !== null) {
36
+ const attributes = match[1];
37
+ if (predicate(attributes))
38
+ return attributes.match(/href="([^"]+)"/)?.[1];
39
+ }
40
+ return undefined;
41
+ }
42
+ function categoryTerms(entry) {
43
+ const expression = /<category\b([^>]*)\/>/g;
44
+ const terms = [];
45
+ let match;
46
+ while ((match = expression.exec(entry)) !== null) {
47
+ const term = match[1].match(/term="([^"]+)"/)?.[1];
48
+ if (term !== undefined)
49
+ terms.push(term);
50
+ }
51
+ return terms;
52
+ }
53
+ export function parseArxivAtom(xml) {
54
+ return extractEntries(xml).flatMap((entry) => {
55
+ const rawId = firstMatch(entry, "id");
56
+ const title = firstMatch(entry, "title");
57
+ if (rawId === undefined || title === undefined)
58
+ return [];
59
+ const idMatch = rawId.match(/abs\/(.+)$/);
60
+ const authors = allMatches(entry, "author")
61
+ .map((author) => firstMatch(author, "name"))
62
+ .filter((name) => name !== undefined)
63
+ .map(collapseWhitespace);
64
+ const htmlUrl = linkAttribute(entry, (attributes) => /rel="alternate"/.test(attributes) && /type="text\/html"/.test(attributes));
65
+ const pdfUrl = linkAttribute(entry, (attributes) => /title="pdf"/.test(attributes));
66
+ return [
67
+ {
68
+ id: idMatch?.[1] ?? collapseWhitespace(rawId),
69
+ title: collapseWhitespace(title),
70
+ abstract: collapseWhitespace(firstMatch(entry, "summary") ?? ""),
71
+ authors,
72
+ published: collapseWhitespace(firstMatch(entry, "published") ?? ""),
73
+ categories: categoryTerms(entry),
74
+ url: htmlUrl ?? collapseWhitespace(rawId),
75
+ ...(pdfUrl === undefined ? {} : { pdfUrl }),
76
+ },
77
+ ];
78
+ });
79
+ }
80
+ export function createArxivSource(options = {}) {
81
+ async function fetchPapers(params, signal) {
82
+ const result = await requestText(`${BASE_URL}?${params}`, options, signal);
83
+ if (result.status !== "ok")
84
+ return result;
85
+ if (!/<feed\b/.test(result.value))
86
+ return { status: "unavailable", detail: "response schema mismatch: missing Atom feed" };
87
+ return { status: "ok", value: parseArxivAtom(result.value) };
88
+ }
89
+ return {
90
+ search: (input, signal) => {
91
+ const categoryQuery = input.categories !== undefined && input.categories.length > 0
92
+ ? ` AND (${input.categories.map((category) => `cat:${category}`).join(" OR ")})`
93
+ : "";
94
+ return fetchPapers(new URLSearchParams({
95
+ search_query: `all:${input.query}${categoryQuery}`,
96
+ max_results: String(input.limit),
97
+ sortBy: "relevance",
98
+ sortOrder: "descending",
99
+ }), signal);
100
+ },
101
+ lookupExact: (id, limit, signal) => fetchPapers(new URLSearchParams({ id_list: id, max_results: String(limit) }), signal),
102
+ };
103
+ }