@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.
- package/dist/agents/conversation-agent.d.ts +3 -0
- package/dist/agents/conversation-agent.js +5 -2
- package/dist/agents/report-builder.d.ts +2 -0
- package/dist/agents/report-builder.js +2 -0
- package/dist/agents/sandbox/shared.d.ts +3 -0
- package/dist/agents/sandbox/shared.js +5 -0
- package/dist/agents/sandbox/types.d.ts +1 -1
- package/dist/app/chat-turn.d.ts +2 -0
- package/dist/app/chat-turn.js +11 -2
- package/dist/app/spawn-report-session.d.ts +85 -0
- package/dist/app/spawn-report-session.js +83 -0
- package/dist/app/synthesize-run.d.ts +3 -0
- package/dist/app/synthesize-run.js +2 -1
- package/dist/citations/__fixtures__/resolver.d.ts +3 -0
- package/dist/citations/__fixtures__/resolver.js +9 -0
- package/dist/citations/aggregate.d.ts +3 -0
- package/dist/citations/aggregate.js +44 -0
- package/dist/citations/clients/arxiv.d.ts +6 -0
- package/dist/citations/clients/arxiv.js +34 -0
- package/dist/citations/clients/common.d.ts +11 -0
- package/dist/citations/clients/common.js +43 -0
- package/dist/citations/clients/crossref.d.ts +8 -0
- package/dist/citations/clients/crossref.js +98 -0
- package/dist/citations/clients/doi-registry.d.ts +3 -0
- package/dist/citations/clients/doi-registry.js +95 -0
- package/dist/citations/clients/pubmed.d.ts +6 -0
- package/dist/citations/clients/pubmed.js +83 -0
- package/dist/citations/clients/semantic-scholar.d.ts +6 -0
- package/dist/citations/clients/semantic-scholar.js +60 -0
- package/dist/citations/compare.d.ts +9 -0
- package/dist/citations/compare.js +72 -0
- package/dist/citations/match.d.ts +11 -0
- package/dist/citations/match.js +173 -0
- package/dist/citations/normalize.d.ts +31 -0
- package/dist/citations/normalize.js +187 -0
- package/dist/citations/plan.d.ts +2 -0
- package/dist/citations/plan.js +59 -0
- package/dist/citations/resolve.d.ts +28 -0
- package/dist/citations/resolve.js +238 -0
- package/dist/citations/types.d.ts +583 -0
- package/dist/citations/types.js +129 -0
- package/dist/contracts/chat-events.d.ts +9 -0
- package/dist/contracts/index.d.ts +6 -2
- package/dist/contracts/index.js +3 -1
- package/dist/contracts/organ-system.d.ts +49 -0
- package/dist/contracts/organ-system.js +67 -0
- package/dist/contracts/report-blocks.d.ts +564 -0
- package/dist/contracts/report-blocks.js +117 -0
- package/dist/contracts/report-reference.d.ts +459 -0
- package/dist/contracts/report-reference.js +256 -0
- package/dist/contracts/schemas/chat-events.d.ts +2 -0
- package/dist/contracts/schemas/chat-events.js +2 -0
- package/dist/contracts/schemas/chat-parts.d.ts +8 -8
- package/dist/contracts/severity.d.ts +15 -0
- package/dist/contracts/severity.js +10 -0
- package/dist/contracts/target-dossier.d.ts +8673 -12970
- package/dist/contracts/target-dossier.js +534 -591
- package/dist/data/safety-panel-schema.d.ts +18 -5
- package/dist/data/safety-panel-schema.js +4 -4
- package/dist/execution/artifact-metadata.js +1 -0
- package/dist/execution/report-runner.js +1 -3
- package/dist/execution/run-synthesis.d.ts +3 -0
- package/dist/execution/run-synthesis.js +3 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.js +22 -0
- package/dist/lib/async-utils.d.ts +16 -4
- package/dist/lib/async-utils.js +20 -15
- package/dist/lib/cache.d.ts +8 -0
- package/dist/lib/cache.js +35 -0
- package/dist/lib/host-concurrency.js +1 -0
- package/dist/lib/rate-limit.d.ts +35 -0
- package/dist/lib/rate-limit.js +121 -0
- package/dist/literature/sources/arxiv.d.ts +22 -0
- package/dist/literature/sources/arxiv.js +103 -0
- package/dist/literature/sources/http.d.ts +28 -0
- package/dist/literature/sources/http.js +97 -0
- package/dist/literature/sources/pubmed.d.ts +68 -0
- package/dist/literature/sources/pubmed.js +266 -0
- package/dist/literature/sources/semantic-scholar.d.ts +24 -0
- package/dist/literature/sources/semantic-scholar.js +71 -0
- package/dist/loop/__fixtures__/scripted-provider.js +23 -2
- package/dist/loop/run-agent.js +58 -10
- package/dist/loop/tool-detail.d.ts +40 -0
- package/dist/loop/tool-detail.js +35 -3
- package/dist/loop/types.d.ts +13 -0
- package/dist/memory/thread-history.d.ts +10 -0
- package/dist/memory/thread-history.js +12 -1
- package/dist/memory/thread-store.d.ts +142 -25
- package/dist/memory/thread-store.js +228 -40
- package/dist/prompts/literature-reviewer.d.ts +1 -1
- package/dist/prompts/literature-reviewer.js +2 -0
- package/dist/prompts/target-assessment/briefs/executive-recommendation.d.ts +1 -1
- package/dist/prompts/target-assessment/briefs/executive-recommendation.js +5 -5
- package/dist/prompts/target-assessment/briefs/liability-bullets.d.ts +1 -1
- package/dist/prompts/target-assessment/briefs/liability-bullets.js +1 -1
- package/dist/prompts/target-assessment/briefs/target-organ-liabilities.d.ts +1 -1
- package/dist/prompts/target-assessment/briefs/target-organ-liabilities.js +11 -3
- package/dist/prompts/target-assessment/investigation/adversarial-critique.d.ts +1 -0
- package/dist/prompts/target-assessment/investigation/adversarial-critique.js +67 -0
- package/dist/prompts/target-assessment/investigation/claim-reverification.d.ts +1 -0
- package/dist/prompts/target-assessment/investigation/claim-reverification.js +49 -0
- package/dist/prompts/target-assessment/investigation/index.d.ts +3 -0
- package/dist/prompts/target-assessment/investigation/index.js +3 -0
- package/dist/prompts/target-assessment/investigation/mechanism-proposal.d.ts +1 -0
- package/dist/prompts/target-assessment/investigation/mechanism-proposal.js +49 -0
- package/dist/prompts/target-assessment/tox-voice/index.d.ts +1 -1
- package/dist/prompts/target-assessment/tox-voice/vocabulary.d.ts +8 -5
- package/dist/prompts/target-assessment/tox-voice/vocabulary.js +9 -20
- package/dist/providers/__fixtures__/session.d.ts +5 -4
- package/dist/providers/__fixtures__/session.js +4 -4
- package/dist/report-model/block-walk.d.ts +56 -0
- package/dist/report-model/block-walk.js +89 -0
- package/dist/report-model/draft-finish.d.ts +60 -0
- package/dist/report-model/draft-finish.js +56 -0
- package/dist/report-model/draft-operations.d.ts +125 -0
- package/dist/report-model/draft-operations.js +341 -0
- package/dist/report-model/draft-read.d.ts +59 -0
- package/dist/report-model/draft-read.js +109 -0
- package/dist/report-model/draft.d.ts +51 -0
- package/dist/report-model/draft.js +32 -0
- package/dist/report-model/fixture-resolver.d.ts +8 -0
- package/dist/report-model/fixture-resolver.js +252 -0
- package/dist/report-model/mint-snapshot.d.ts +30 -0
- package/dist/report-model/mint-snapshot.js +40 -0
- package/dist/report-model/reference-resolver.d.ts +113 -0
- package/dist/report-model/reference-resolver.js +60 -0
- package/dist/report-model/structural-validation.d.ts +22 -0
- package/dist/report-model/structural-validation.js +68 -0
- package/dist/report-model/validate.d.ts +40 -0
- package/dist/report-model/validate.js +80 -0
- package/dist/report-render/chart.d.ts +33 -0
- package/dist/report-render/chart.js +538 -0
- package/dist/report-render/page.d.ts +127 -0
- package/dist/report-render/page.js +307 -0
- package/dist/report-render/references.d.ts +32 -0
- package/dist/report-render/references.js +44 -0
- package/dist/report-render/render.d.ts +25 -0
- package/dist/report-render/render.js +125 -0
- package/dist/report-render/script-json.d.ts +13 -0
- package/dist/report-render/script-json.js +15 -0
- package/dist/report-render/types.d.ts +39 -0
- package/dist/report-render/types.js +10 -0
- package/dist/report-render/views/chart-view.d.ts +11 -0
- package/dist/report-render/views/chart-view.js +23 -0
- package/dist/report-render/views/page-view.d.ts +20 -0
- package/dist/report-render/views/page-view.js +49 -0
- package/dist/report-render/views/prose.d.ts +28 -0
- package/dist/report-render/views/prose.js +75 -0
- package/dist/report-render/views/references-view.d.ts +20 -0
- package/dist/report-render/views/references-view.js +64 -0
- package/dist/report-render/views/values.d.ts +42 -0
- package/dist/report-render/views/values.js +43 -0
- package/dist/runtime/assemble.d.ts +50 -4
- package/dist/runtime/assemble.js +47 -3
- package/dist/runtime/boot.d.ts +3 -3
- package/dist/runtime/boot.js +22 -5
- package/dist/runtime/dbos.d.ts +4 -4
- package/dist/state/artifacts.d.ts +16 -0
- package/dist/state/artifacts.js +18 -0
- package/dist/state/init.js +77 -1
- package/dist/state/purge-analysis.js +1 -0
- package/dist/state/report-versions.d.ts +132 -0
- package/dist/state/report-versions.js +194 -0
- package/dist/state/schema.d.ts +2 -2
- package/dist/tasks/data-profile.js +1 -0
- package/dist/tools/bio/chembl.js +1 -0
- package/dist/tools/bio/comptox.js +1 -0
- package/dist/tools/bio/drug-gene-interactions.js +1 -0
- package/dist/tools/bio/gene-disease-evidence.js +1 -0
- package/dist/tools/bio/gene-preclinical-profile.d.ts +1 -1
- package/dist/tools/bio/gene-preclinical-profile.js +1 -0
- package/dist/tools/bio/keys.d.ts +4 -2
- package/dist/tools/bio/keys.js +3 -2
- package/dist/tools/bio/lookup-annotation.js +1 -0
- package/dist/tools/bio/opentargets.d.ts +3 -3
- package/dist/tools/bio/opentargets.js +4 -3
- package/dist/tools/bio/pubchem.js +1 -0
- package/dist/tools/bio/pubmed.js +4 -4
- package/dist/tools/bio/search-clinical-trials.js +1 -0
- package/dist/tools/bio/search-faers.js +1 -0
- package/dist/tools/bio/search-geo-datasets.js +1 -0
- package/dist/tools/bio/search-interactions.js +1 -0
- package/dist/tools/bio/target-safety.d.ts +4 -6
- package/dist/tools/bio/target-safety.js +7 -6
- package/dist/tools/define-tool.d.ts +19 -12
- package/dist/tools/define-tool.js +4 -2
- package/dist/tools/display/show-user.js +1 -0
- package/dist/tools/iterate-report.js +2 -0
- package/dist/tools/lib/chembl-client.d.ts +2 -0
- package/dist/tools/lib/chembl-client.js +1 -0
- package/dist/tools/lib/monarch-client.d.ts +42 -0
- package/dist/tools/lib/monarch-client.js +100 -0
- package/dist/tools/lib/ncbi-utils.d.ts +3 -58
- package/dist/tools/lib/ncbi-utils.js +2 -286
- package/dist/tools/lib/pubmed-client.d.ts +5 -12
- package/dist/tools/lib/pubmed-client.js +20 -79
- package/dist/tools/report/build-report.js +1 -0
- package/dist/tools/report/mint-preview-url.js +1 -0
- package/dist/tools/report/preview-snapshot.js +1 -0
- package/dist/tools/report/submit-report.js +1 -0
- package/dist/tools/report/version-fs.js +4 -0
- package/dist/tools/report-authoring/authoring-tools.d.ts +134 -0
- package/dist/tools/report-authoring/authoring-tools.js +352 -0
- package/dist/tools/research/context7-docs.js +2 -0
- package/dist/tools/research/generate-analogy-report.js +3 -2
- package/dist/tools/research/generate-plan.js +3 -0
- package/dist/tools/research/index.d.ts +1 -0
- package/dist/tools/research/index.js +1 -0
- package/dist/tools/research/inspect-data-profile.js +4 -0
- package/dist/tools/research/inspect-run.d.ts +1 -1
- package/dist/tools/research/literature-reviewer.d.ts +3 -0
- package/dist/tools/research/literature-reviewer.js +3 -0
- package/dist/tools/research/resolve-citation.d.ts +3 -0
- package/dist/tools/research/resolve-citation.js +15 -0
- package/dist/tools/research/search-arxiv.d.ts +3 -19
- package/dist/tools/research/search-arxiv.js +10 -105
- package/dist/tools/research/search-github-repos.js +1 -0
- package/dist/tools/research/search-semantic-scholar.d.ts +8 -33
- package/dist/tools/research/search-semantic-scholar.js +30 -88
- package/dist/tools/sandbox/list-available-packages.js +23 -0
- package/dist/tools/sandbox/list-available-refs.js +37 -2
- package/dist/tools/sandbox/report-blocker.js +1 -0
- package/dist/tools/sandbox/skills.js +2 -0
- package/dist/tools/workspace/file-stat.js +1 -0
- package/dist/tools/workspace/show-file.js +2 -0
- package/dist/tools/workspace/show-plan.js +1 -0
- package/dist/workflows/execute-analysis.d.ts +8 -1
- package/dist/workflows/execute-analysis.js +6 -5
- package/dist/workflows/execute-target-assessment.d.ts +13 -2
- package/dist/workflows/execute-target-assessment.js +78 -16
- package/dist/workflows/sandbox-step.d.ts +5 -0
- package/dist/workflows/sandbox-step.js +1 -0
- package/dist/workflows/target-assessment/assemblers/index.d.ts +1 -1
- package/dist/workflows/target-assessment/assemblers/index.js +1 -1
- package/dist/workflows/target-assessment/assemblers/literature.d.ts +9 -27
- package/dist/workflows/target-assessment/assemblers/literature.js +32 -48
- package/dist/workflows/target-assessment/assemblers/orchestrator.d.ts +17 -9
- package/dist/workflows/target-assessment/assemblers/orchestrator.js +195 -85
- package/dist/workflows/target-assessment/assemblers/safety.d.ts +70 -48
- package/dist/workflows/target-assessment/assemblers/safety.js +125 -42
- package/dist/workflows/target-assessment/collectors/index.d.ts +5 -2
- package/dist/workflows/target-assessment/collectors/index.js +48 -5
- package/dist/workflows/target-assessment/coverage.d.ts +43 -27
- package/dist/workflows/target-assessment/coverage.js +33 -29
- package/dist/workflows/target-assessment/fanout/index.js +1 -0
- package/dist/workflows/target-assessment/investigation/index.d.ts +97 -0
- package/dist/workflows/target-assessment/investigation/index.js +419 -0
- package/dist/workflows/target-assessment/lib/approval-precedents.d.ts +26 -5
- package/dist/workflows/target-assessment/lib/approval-precedents.js +95 -29
- package/dist/workflows/target-assessment/lib/citation-validator.js +1 -1
- package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.d.ts +2 -2
- package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.d.ts +2 -3
- package/dist/workflows/target-assessment/lib/clinical-evidence-attribution.js +0 -4
- package/dist/workflows/target-assessment/lib/compute-derived.d.ts +6 -5
- package/dist/workflows/target-assessment/lib/compute-derived.js +14 -5
- package/dist/workflows/target-assessment/lib/family-complex-supplement.d.ts +5 -6
- package/dist/workflows/target-assessment/lib/family-complex-supplement.js +2 -3
- package/dist/workflows/target-assessment/lib/fda-label-safety.d.ts +72 -0
- package/dist/workflows/target-assessment/lib/fda-label-safety.js +166 -0
- package/dist/workflows/target-assessment/lib/heterodimer-filter.d.ts +0 -9
- package/dist/workflows/target-assessment/lib/heterodimer-filter.js +0 -10
- package/dist/workflows/target-assessment/lib/hpo-organ-map.d.ts +34 -0
- package/dist/workflows/target-assessment/lib/hpo-organ-map.js +63 -0
- package/dist/workflows/target-assessment/lib/impc-organ-map.d.ts +19 -0
- package/dist/workflows/target-assessment/lib/impc-organ-map.js +39 -0
- package/dist/workflows/target-assessment/lib/meddra-organ-map.d.ts +24 -14
- package/dist/workflows/target-assessment/lib/meddra-organ-map.js +59 -47
- package/dist/workflows/target-assessment/lib/recommendation-sanitizer.js +1 -1
- package/dist/workflows/target-assessment/lib/regulatory-actions.d.ts +2 -3
- package/dist/workflows/target-assessment/lib/regulatory-actions.js +33 -4
- package/dist/workflows/target-assessment/lib/safety-corroboration.d.ts +44 -0
- package/dist/workflows/target-assessment/lib/safety-corroboration.js +273 -0
- package/dist/workflows/target-assessment/lib/target-identity-filter.d.ts +5 -7
- package/dist/workflows/target-assessment/lib/target-identity-filter.js +5 -7
- package/dist/workflows/target-assessment/metrics.d.ts +1 -6
- package/dist/workflows/target-assessment/metrics.js +1 -13
- package/dist/workflows/target-assessment/phase4-assemble.d.ts +2149 -809
- package/dist/workflows/target-assessment/phase4-assemble.js +19 -19
- package/dist/workflows/target-assessment/phase5-persist.d.ts +20 -21
- package/dist/workflows/target-assessment/phase5-persist.js +56 -173
- package/dist/workflows/target-assessment/schemas.d.ts +48 -3
- package/dist/workflows/target-assessment/schemas.js +19 -0
- package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.d.ts +1 -0
- package/dist/workflows/target-assessment/steps/fanout/polypharm-for-one-modulator-step.js +2 -0
- package/dist/workflows/target-assessment/steps/phase2-aggregate.d.ts +27 -63
- package/dist/workflows/target-assessment/steps/phase2-aggregate.js +0 -4
- package/dist/workflows/target-assessment/steps/phase3-aggregate.d.ts +28 -155
- package/dist/workflows/target-assessment/steps/phase3-aggregate.js +0 -6
- package/dist/workflows/target-assessment/steps/synthesis/diagnostics.d.ts +0 -6
- package/dist/workflows/target-assessment/steps/synthesis/diagnostics.js +0 -18
- package/dist/workflows/target-assessment/sub-workflows/per-modulator-polypharm.d.ts +1 -0
- package/dist/workflows/target-assessment/synthesis/index.d.ts +52 -5
- package/dist/workflows/target-assessment/synthesis/index.js +4 -1
- package/dist/workflows/target-assessment/synthesis-probes.d.ts +3 -3
- package/package.json +4 -1
|
@@ -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
|
-
|
|
3
|
-
|
|
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:
|
|
24
|
+
organ_system: OrganSystemSchema,
|
|
25
25
|
clinical_consequence: z.string().min(1).max(200),
|
|
26
|
-
severity:
|
|
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
|
|
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
|
-
*
|
|
8
|
-
*
|
|
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
|
|
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
|
+
}>;
|
package/dist/lib/async-utils.js
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared async utilities — sleep and bounded-concurrency
|
|
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
|
-
*
|
|
10
|
-
*
|
|
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
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
+
}
|
|
@@ -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(/</g, "<")
|
|
6
|
+
.replace(/>/g, ">")
|
|
7
|
+
.replace(/"/g, '"')
|
|
8
|
+
.replace(/'/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(/&/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
|
+
}
|