@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
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export const claimReverificationBrief = `# Task: re-verify one organ liability claim
|
|
2
|
+
|
|
3
|
+
You are given a corroborated organ liability claim, the mechanism proposed for
|
|
4
|
+
it, the objection raised against it, and the evidence the assessment collected
|
|
5
|
+
for that organ. Decide what survives.
|
|
6
|
+
|
|
7
|
+
You are adjudicating, not summarising. Weigh the objection against the evidence
|
|
8
|
+
and say which of them the record actually supports.
|
|
9
|
+
|
|
10
|
+
## The verdict vocabulary
|
|
11
|
+
|
|
12
|
+
- \`upheld\` — the objection was answered by the evidence, and the claim stands as
|
|
13
|
+
proposed.
|
|
14
|
+
- \`weakened\` — the objection lands, but the claim is not eliminated: it holds in
|
|
15
|
+
a narrower form, or with lower confidence in its mechanism.
|
|
16
|
+
- \`overturned\` — the objection is decisive; the evidence does not support the
|
|
17
|
+
claim as stated.
|
|
18
|
+
- \`undetermined\` — the record settles neither side. This is a real verdict, not a
|
|
19
|
+
refusal to answer, and it is correct whenever the evidence is genuinely silent.
|
|
20
|
+
|
|
21
|
+
The verdict is your read of the record in words. There is no score, no
|
|
22
|
+
threshold, and no arithmetic — do not attempt to derive one, and do not describe
|
|
23
|
+
the claim as passing or failing a bar.
|
|
24
|
+
|
|
25
|
+
Nothing you return removes a claim from the assessment. An \`overturned\` verdict
|
|
26
|
+
is recorded and read; it does not delete the organ, and you should therefore
|
|
27
|
+
never soften a verdict to protect a liability from disappearing.
|
|
28
|
+
|
|
29
|
+
## Support for the verdict
|
|
30
|
+
|
|
31
|
+
Cite the records that carry your verdict — the ones you actually relied on, from
|
|
32
|
+
the evidence you were given or from the objection's counter-evidence.
|
|
33
|
+
|
|
34
|
+
If nothing in the record carries the verdict, return support state \`unknown\`
|
|
35
|
+
with a one-line reason. That is a complete answer, expected often, and always
|
|
36
|
+
preferable to a locator you are not certain of. The verdict itself is still
|
|
37
|
+
recorded.
|
|
38
|
+
|
|
39
|
+
## Do NOT
|
|
40
|
+
|
|
41
|
+
- Do NOT cite a publication identifier, accession, or regulatory reference that
|
|
42
|
+
was not in the material you were given.
|
|
43
|
+
- Do NOT report support as \`scored\` while noting the evidence is thin. Thin is
|
|
44
|
+
\`unknown\` with that as the reason.
|
|
45
|
+
- Do NOT restate the objection as the verdict. Say what the record supports.
|
|
46
|
+
- Do NOT return \`upheld\` merely because the claim was corroborated by several
|
|
47
|
+
sources — whether those sources are independent is exactly what the objection
|
|
48
|
+
may be contesting.
|
|
49
|
+
- Do NOT assume anything about what ran before you or what will run after.`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const mechanismProposalBrief: string;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ORGAN_SYSTEMS } from "../../../contracts/organ-system.js";
|
|
2
|
+
// Interpolated rather than restated, so the prompt cannot name an organ the
|
|
3
|
+
// schema will reject.
|
|
4
|
+
const organTokens = ORGAN_SYSTEMS.join(", ");
|
|
5
|
+
export const mechanismProposalBrief = `# Task: propose a mechanism for one organ liability
|
|
6
|
+
|
|
7
|
+
You are given ONE canonical organ token and the evidence this assessment has
|
|
8
|
+
already collected about that organ — the sources that raised a signal for it,
|
|
9
|
+
what each of them said, and the record each signal came from. Propose how the
|
|
10
|
+
assessed target could produce a liability in that organ.
|
|
11
|
+
|
|
12
|
+
The organ is supplied to you and is already one of: ${organTokens}. You are not
|
|
13
|
+
asked to choose an organ and you must not reassign the claim to another one.
|
|
14
|
+
|
|
15
|
+
## What a proposal is
|
|
16
|
+
|
|
17
|
+
- One mechanism, stated plainly: what the target does, in which cells or tissue,
|
|
18
|
+
and how that becomes the observed liability.
|
|
19
|
+
- Grounded in the evidence you were handed. Every record you were given carries
|
|
20
|
+
a locator; cite the locators of the records your mechanism actually rests on.
|
|
21
|
+
- Scaled to the observation. A mechanism must operate at the same biological
|
|
22
|
+
scale as the signal it explains — do not explain a clinical adverse-event
|
|
23
|
+
signal with developmental or tissue-homeostasis biology.
|
|
24
|
+
|
|
25
|
+
## Reporting no mechanism costs you nothing
|
|
26
|
+
|
|
27
|
+
If the evidence supports no mechanism, say so: return no mechanism statement and
|
|
28
|
+
a support reason explaining what was missing. That is a complete, correct answer
|
|
29
|
+
and it is preferred over a plausible-sounding story.
|
|
30
|
+
|
|
31
|
+
If you can state a mechanism but cannot point at a record that supports it,
|
|
32
|
+
return the statement with support state \`unknown\` and a one-line reason. An
|
|
33
|
+
unknown support is a normal outcome, not a penalty, and it is always cheaper
|
|
34
|
+
than a citation you are not certain of.
|
|
35
|
+
|
|
36
|
+
## Do NOT
|
|
37
|
+
|
|
38
|
+
- Do NOT cite a publication identifier, accession, or regulatory reference that
|
|
39
|
+
was not in the evidence you were given. A locator you produced from memory is
|
|
40
|
+
a fabrication even when the paper exists.
|
|
41
|
+
- Do NOT report support as \`scored\` while explaining in prose that the evidence
|
|
42
|
+
is weak or indirect. Weak or indirect support is \`unknown\` with that as the
|
|
43
|
+
reason.
|
|
44
|
+
- Do NOT restate the evidence back as the mechanism. "Several sources report
|
|
45
|
+
hepatic signals" is an observation; a mechanism says why.
|
|
46
|
+
- Do NOT propose a mechanism for a different organ, a different target, or a
|
|
47
|
+
drug class rather than the target.
|
|
48
|
+
- Do NOT assume anything about what ran before you or what will run after. Work
|
|
49
|
+
from what you were handed.`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { toxVoiceCore } from "./core.js";
|
|
2
2
|
export { toxVoiceExemplars, type SectionType } from "./exemplars.js";
|
|
3
|
-
export { toxVoiceVocabulary, type
|
|
3
|
+
export { toxVoiceVocabulary, type LiabilityFraming, type HedgePhrase, type BannedTerm } from "./vocabulary.js";
|
|
4
4
|
export { buildVoiceCritique, type VoiceProbe } from "./critique.js";
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tox-voice canon.
|
|
3
|
-
* minimum surface the deterministic voice probe enforces
|
|
4
|
-
* judgment in the agent prompts covers the long tail.
|
|
2
|
+
* Tox-voice canon. The stylistic lists are intentionally not exhaustive —
|
|
3
|
+
* they are the minimum surface the deterministic voice probe enforces, and
|
|
4
|
+
* editorial judgment in the agent prompts covers the long tail.
|
|
5
|
+
*
|
|
6
|
+
* `organSystems` is the exception: it is closed, because it is a projection
|
|
7
|
+
* of the canonical organ vocabulary rather than a list of its own. Prose and
|
|
8
|
+
* structured fields must name the same organs.
|
|
5
9
|
*/
|
|
6
10
|
export declare const toxVoiceVocabulary: {
|
|
7
|
-
readonly organSystems:
|
|
11
|
+
readonly organSystems: string[];
|
|
8
12
|
readonly liabilityFraming: readonly ["on-target liability", "off-target liability", "secondary pharmacology", "class liability", "mechanism-related", "exaggerated pharmacology", "target-organ toxicity"];
|
|
9
13
|
readonly hedgePhrases: readonly ["the data are consistent with", "the data suggest", "human relevance is uncertain", "human relevance remains to be established", "interpretation is limited by", "no causal inference is supported", "the available evidence is consistent with", "the available evidence does not support", "translatability to humans is unclear", "species differences"];
|
|
10
14
|
readonly banned: readonly ["groundbreaking", "cutting-edge", "state-of-the-art", "best-in-class", "first-in-class", "revolutionary", "leverages", "leveraging", "robust", "powerful", "seamlessly", "cleanly", "elegant", "unparalleled", "demonstrates the power of", "showcases", "unlocks", "enables breakthrough", "very promising", "extremely", "incredibly", "highly innovative"];
|
|
11
15
|
};
|
|
12
|
-
export type OrganSystem = (typeof toxVoiceVocabulary.organSystems)[number];
|
|
13
16
|
export type LiabilityFraming = (typeof toxVoiceVocabulary.liabilityFraming)[number];
|
|
14
17
|
export type HedgePhrase = (typeof toxVoiceVocabulary.hedgePhrases)[number];
|
|
15
18
|
export type BannedTerm = (typeof toxVoiceVocabulary.banned)[number];
|
|
@@ -1,26 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tox-voice canon.
|
|
3
|
-
* minimum surface the deterministic voice probe enforces
|
|
4
|
-
* judgment in the agent prompts covers the long tail.
|
|
2
|
+
* Tox-voice canon. The stylistic lists are intentionally not exhaustive —
|
|
3
|
+
* they are the minimum surface the deterministic voice probe enforces, and
|
|
4
|
+
* editorial judgment in the agent prompts covers the long tail.
|
|
5
|
+
*
|
|
6
|
+
* `organSystems` is the exception: it is closed, because it is a projection
|
|
7
|
+
* of the canonical organ vocabulary rather than a list of its own. Prose and
|
|
8
|
+
* structured fields must name the same organs.
|
|
5
9
|
*/
|
|
10
|
+
import { ORGAN_SYSTEMS, ORGAN_SYSTEM_LABELS } from "../../../contracts/organ-system.js";
|
|
6
11
|
export const toxVoiceVocabulary = {
|
|
7
|
-
organSystems: [
|
|
8
|
-
"hepatobiliary",
|
|
9
|
-
"renal",
|
|
10
|
-
"cardiac",
|
|
11
|
-
"vascular",
|
|
12
|
-
"haematologic",
|
|
13
|
-
"central nervous system",
|
|
14
|
-
"peripheral nervous system",
|
|
15
|
-
"respiratory",
|
|
16
|
-
"gastrointestinal",
|
|
17
|
-
"reproductive",
|
|
18
|
-
"endocrine",
|
|
19
|
-
"musculoskeletal",
|
|
20
|
-
"dermatologic",
|
|
21
|
-
"ocular",
|
|
22
|
-
"immunologic",
|
|
23
|
-
],
|
|
12
|
+
organSystems: ORGAN_SYSTEMS.map((organ) => ORGAN_SYSTEM_LABELS[organ]),
|
|
24
13
|
liabilityFraming: [
|
|
25
14
|
"on-target liability",
|
|
26
15
|
"off-target liability",
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test-only harness `RequestSession` builder. Not a `*.test.ts` file, so the test
|
|
3
3
|
* runner ignores it; imported by harness unit tests that need a session but never
|
|
4
|
-
* read its (opaque) auth.
|
|
5
|
-
* inspects
|
|
6
|
-
*
|
|
4
|
+
* read its (opaque) auth. `auth` defaults to the trivial local value the harness
|
|
5
|
+
* never inspects; an embedder whose adapters downcast `auth` to a concrete type
|
|
6
|
+
* overrides it rather than re-declaring the whole session shape.
|
|
7
7
|
*/
|
|
8
|
-
import type { RequestSession, Scope } from "../../auth/types.js";
|
|
8
|
+
import type { AuthContext, RequestSession, Scope } from "../../auth/types.js";
|
|
9
9
|
export interface SessionOverrides {
|
|
10
10
|
user?: string;
|
|
11
11
|
scope?: Scope;
|
|
12
12
|
agentId?: string;
|
|
13
13
|
callPath?: readonly string[];
|
|
14
|
+
auth?: AuthContext;
|
|
14
15
|
}
|
|
15
16
|
/** Build a fully-populated harness `RequestSession` for tests, with per-field overrides. */
|
|
16
17
|
export declare function makeSession(overrides?: SessionOverrides): RequestSession;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test-only harness `RequestSession` builder. Not a `*.test.ts` file, so the test
|
|
3
3
|
* runner ignores it; imported by harness unit tests that need a session but never
|
|
4
|
-
* read its (opaque) auth.
|
|
5
|
-
* inspects
|
|
6
|
-
*
|
|
4
|
+
* read its (opaque) auth. `auth` defaults to the trivial local value the harness
|
|
5
|
+
* never inspects; an embedder whose adapters downcast `auth` to a concrete type
|
|
6
|
+
* overrides it rather than re-declaring the whole session shape.
|
|
7
7
|
*/
|
|
8
8
|
import { makeLocalAuth } from "../../auth/local-auth-context.js";
|
|
9
9
|
/** Build a fully-populated harness `RequestSession` for tests, with per-field overrides. */
|
|
@@ -15,6 +15,6 @@ export function makeSession(overrides = {}) {
|
|
|
15
15
|
agentId: overrides.agentId ?? "conversation-agent",
|
|
16
16
|
callPath: overrides.callPath ?? ["conversation-agent"],
|
|
17
17
|
},
|
|
18
|
-
auth: makeLocalAuth(),
|
|
18
|
+
auth: overrides.auth ?? makeLocalAuth(),
|
|
19
19
|
};
|
|
20
20
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one walk over a block tree.
|
|
3
|
+
*
|
|
4
|
+
* A block kind decides where a reference sits, which prose carries a free numeral, and whether the block
|
|
5
|
+
* holds children. Three consumers need that same knowledge: the mechanical validator, the draft finish,
|
|
6
|
+
* and the draft operations. A switch for each consumer is a switch that a ninth block kind can miss in
|
|
7
|
+
* silence, because each arm returns and none of them fails to build. Thus the walk lives here one time.
|
|
8
|
+
*
|
|
9
|
+
* The walk reads a finished `Block` tree and a relaxed `DraftBlock` tree alike. The two differ only in the
|
|
10
|
+
* section rules, and the section arm reads the children of either one.
|
|
11
|
+
*
|
|
12
|
+
* The walk resolves nothing and it opens no file. It reports what the tree holds, and a caller decides
|
|
13
|
+
* which part it needs.
|
|
14
|
+
*/
|
|
15
|
+
import type { Block } from "../contracts/report-blocks.js";
|
|
16
|
+
import type { Reference } from "../contracts/report-reference.js";
|
|
17
|
+
import type { DraftBlock } from "./draft.js";
|
|
18
|
+
/** A block of a finished report, or a block of a draft. The atoms are the same shape in both. */
|
|
19
|
+
export type AnyBlock = Block | DraftBlock;
|
|
20
|
+
/**
|
|
21
|
+
* One reference that the walk met, tied to the block that carries it.
|
|
22
|
+
*
|
|
23
|
+
* `encodingColumns` is present for a `chart` only. A chart names its axes as free strings, thus the names
|
|
24
|
+
* must be matched against the table that the binding resolves to. Nothing else can catch a chart that
|
|
25
|
+
* plots a column which does not exist. The match needs the resolved rows, thus only a value-tier consumer
|
|
26
|
+
* reads this field.
|
|
27
|
+
*/
|
|
28
|
+
export interface CollectedReference {
|
|
29
|
+
blockId: string;
|
|
30
|
+
reference: Reference;
|
|
31
|
+
encodingColumns?: string[];
|
|
32
|
+
}
|
|
33
|
+
/** An advisory warning about the content of one block. A warning never makes a report invalid. */
|
|
34
|
+
export interface ReportWarning {
|
|
35
|
+
blockId: string;
|
|
36
|
+
kind: "free-numeral";
|
|
37
|
+
detail: string;
|
|
38
|
+
}
|
|
39
|
+
/** What one walk over a block tree found. */
|
|
40
|
+
export interface BlockWalk {
|
|
41
|
+
/** Each reference, in document order, tied to the block that carries it. */
|
|
42
|
+
references: CollectedReference[];
|
|
43
|
+
/** Each id that more than one block holds, named one time, in sorted order. */
|
|
44
|
+
repeatedIds: string[];
|
|
45
|
+
/** Each free numeral that prose carries. */
|
|
46
|
+
warnings: ReportWarning[];
|
|
47
|
+
}
|
|
48
|
+
/** Warn for each free-standing numeral that the prose of one block carries. */
|
|
49
|
+
export declare function numeralWarnings(blockId: string, prose: string): ReportWarning[];
|
|
50
|
+
/**
|
|
51
|
+
* Walk a block tree, and report each reference, each repeated id, and each free numeral.
|
|
52
|
+
*
|
|
53
|
+
* An id is what makes a block addressable, thus an amend by id is well defined only while each id belongs
|
|
54
|
+
* to one block. The walk is pre-order, thus the references follow the document order.
|
|
55
|
+
*/
|
|
56
|
+
export declare function walkBlocks(blocks: readonly AnyBlock[]): BlockWalk;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one walk over a block tree.
|
|
3
|
+
*
|
|
4
|
+
* A block kind decides where a reference sits, which prose carries a free numeral, and whether the block
|
|
5
|
+
* holds children. Three consumers need that same knowledge: the mechanical validator, the draft finish,
|
|
6
|
+
* and the draft operations. A switch for each consumer is a switch that a ninth block kind can miss in
|
|
7
|
+
* silence, because each arm returns and none of them fails to build. Thus the walk lives here one time.
|
|
8
|
+
*
|
|
9
|
+
* The walk reads a finished `Block` tree and a relaxed `DraftBlock` tree alike. The two differ only in the
|
|
10
|
+
* section rules, and the section arm reads the children of either one.
|
|
11
|
+
*
|
|
12
|
+
* The walk resolves nothing and it opens no file. It reports what the tree holds, and a caller decides
|
|
13
|
+
* which part it needs.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* A free-standing token that looks like a number, with an optional decimal part and an optional percent
|
|
17
|
+
* sign.
|
|
18
|
+
*
|
|
19
|
+
* The left boundary keeps the digits of a name out of the warnings. The domain prose is dense with a
|
|
20
|
+
* symbol such as `TP53`, `CD8`, or `IL6`, and without the boundary each one warns for its digits and
|
|
21
|
+
* buries the real free figures.
|
|
22
|
+
*
|
|
23
|
+
* The check is advisory only. A natural-language numeral is brittle to police, because a numeral in prose
|
|
24
|
+
* can be a real free-standing figure or a harmless part of a name. Thus a hit warns, and it never fails
|
|
25
|
+
* the report.
|
|
26
|
+
*/
|
|
27
|
+
const NUMERAL_PATTERN = /(?<![A-Za-z0-9])-?\d+(?:\.\d+)?%?/g;
|
|
28
|
+
/** Warn for each free-standing numeral that the prose of one block carries. */
|
|
29
|
+
export function numeralWarnings(blockId, prose) {
|
|
30
|
+
const warnings = [];
|
|
31
|
+
for (const match of prose.matchAll(NUMERAL_PATTERN)) {
|
|
32
|
+
warnings.push({ blockId, kind: "free-numeral", detail: match[0] });
|
|
33
|
+
}
|
|
34
|
+
return warnings;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Walk a block tree, and report each reference, each repeated id, and each free numeral.
|
|
38
|
+
*
|
|
39
|
+
* An id is what makes a block addressable, thus an amend by id is well defined only while each id belongs
|
|
40
|
+
* to one block. The walk is pre-order, thus the references follow the document order.
|
|
41
|
+
*/
|
|
42
|
+
export function walkBlocks(blocks) {
|
|
43
|
+
const references = [];
|
|
44
|
+
const warnings = [];
|
|
45
|
+
const seenIds = new Set();
|
|
46
|
+
const repeated = new Set();
|
|
47
|
+
const visit = (block) => {
|
|
48
|
+
if (seenIds.has(block.id)) {
|
|
49
|
+
repeated.add(block.id);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
seenIds.add(block.id);
|
|
53
|
+
}
|
|
54
|
+
switch (block.kind) {
|
|
55
|
+
case "section":
|
|
56
|
+
for (const child of block.blocks) {
|
|
57
|
+
visit(child);
|
|
58
|
+
}
|
|
59
|
+
return;
|
|
60
|
+
case "text":
|
|
61
|
+
warnings.push(...numeralWarnings(block.id, block.content.prose));
|
|
62
|
+
return;
|
|
63
|
+
case "claim":
|
|
64
|
+
warnings.push(...numeralWarnings(block.id, block.content.prose));
|
|
65
|
+
for (const binding of block.bindings) {
|
|
66
|
+
references.push({ blockId: block.id, reference: binding });
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
case "metric":
|
|
70
|
+
references.push({ blockId: block.id, reference: block.value });
|
|
71
|
+
return;
|
|
72
|
+
case "chart": {
|
|
73
|
+
const encoding = block.encoding;
|
|
74
|
+
const encodingColumns = [encoding.x, encoding.y, encoding.group, encoding.value].filter((column) => column !== undefined);
|
|
75
|
+
references.push({ blockId: block.id, reference: block.binding, encodingColumns });
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
case "table":
|
|
79
|
+
case "figure":
|
|
80
|
+
case "citation":
|
|
81
|
+
references.push({ blockId: block.id, reference: block.binding });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
for (const block of blocks) {
|
|
86
|
+
visit(block);
|
|
87
|
+
}
|
|
88
|
+
return { references, repeatedIds: [...repeated].sort(), warnings };
|
|
89
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The finish of a draft.
|
|
3
|
+
*
|
|
4
|
+
* An edit refuses what is wrong. The finish refuses what is missing. Thus the finish gates the whole
|
|
5
|
+
* draft one time: the full document schema, the unique ids, and the structural tier over every reference.
|
|
6
|
+
*
|
|
7
|
+
* The finish opens no file, and it reads the snapshot alone. Thus it runs the structural tier only, and
|
|
8
|
+
* the value tier stays in the gate of the report pipeline. The chart encoding-column match needs the rows
|
|
9
|
+
* behind a binding, thus it stays with the value tier.
|
|
10
|
+
*
|
|
11
|
+
* The free-numeral scan needs no file, thus the finish runs it and reports each hit as a warning. A
|
|
12
|
+
* warning never makes a draft invalid, and it rides beside the outcome in either case. Without the
|
|
13
|
+
* channel a caller could not read the one signal that catches a figure typed into prose with no metric
|
|
14
|
+
* block behind it.
|
|
15
|
+
*
|
|
16
|
+
* The result is plain data. A gap is an expected outcome, not an error, thus the finish never throws. On
|
|
17
|
+
* a pass the finish gives the valid document, and it does not change the draft.
|
|
18
|
+
*/
|
|
19
|
+
import { type ReportDocument } from "../contracts/report-blocks.js";
|
|
20
|
+
import type { UnresolvedReference } from "../contracts/report-reference.js";
|
|
21
|
+
import { type ReportWarning } from "./block-walk.js";
|
|
22
|
+
import type { DraftDocument } from "./draft.js";
|
|
23
|
+
import type { ReportSnapshot } from "./reference-resolver.js";
|
|
24
|
+
/** A schema conformance gap, reduced to a path and a message. */
|
|
25
|
+
export interface SchemaGap {
|
|
26
|
+
kind: "schema";
|
|
27
|
+
path: string;
|
|
28
|
+
message: string;
|
|
29
|
+
}
|
|
30
|
+
/** A duplicate id gap. More than one block holds the id. */
|
|
31
|
+
export interface DuplicateIdGap {
|
|
32
|
+
kind: "duplicate-id";
|
|
33
|
+
id: string;
|
|
34
|
+
}
|
|
35
|
+
/** An unresolved reference gap. It ties the block that carries the reference to the reason it did not resolve. */
|
|
36
|
+
export interface UnresolvedReferenceGap {
|
|
37
|
+
kind: "unresolved-reference";
|
|
38
|
+
blockId: string;
|
|
39
|
+
failure: UnresolvedReference;
|
|
40
|
+
}
|
|
41
|
+
/** One completeness gap of a draft. The kind set is closed. */
|
|
42
|
+
export type FinishGap = SchemaGap | DuplicateIdGap | UnresolvedReferenceGap;
|
|
43
|
+
/**
|
|
44
|
+
* The finish result. On a pass it gives the valid document. On a fail it gives each gap. The warnings
|
|
45
|
+
* ride along in either case, because a warning is advisory and it never decides the outcome.
|
|
46
|
+
*/
|
|
47
|
+
export type FinishResult = {
|
|
48
|
+
valid: true;
|
|
49
|
+
document: ReportDocument;
|
|
50
|
+
warnings: ReportWarning[];
|
|
51
|
+
} | {
|
|
52
|
+
valid: false;
|
|
53
|
+
gaps: FinishGap[];
|
|
54
|
+
warnings: ReportWarning[];
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Finish a draft. The finish validates the schema, the unique ids, and the structural resolution of each
|
|
58
|
+
* reference, and it reports each gap as data. It warns about each free numeral in prose.
|
|
59
|
+
*/
|
|
60
|
+
export declare function finishDraft(draft: DraftDocument, snapshot: ReportSnapshot): FinishResult;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The finish of a draft.
|
|
3
|
+
*
|
|
4
|
+
* An edit refuses what is wrong. The finish refuses what is missing. Thus the finish gates the whole
|
|
5
|
+
* draft one time: the full document schema, the unique ids, and the structural tier over every reference.
|
|
6
|
+
*
|
|
7
|
+
* The finish opens no file, and it reads the snapshot alone. Thus it runs the structural tier only, and
|
|
8
|
+
* the value tier stays in the gate of the report pipeline. The chart encoding-column match needs the rows
|
|
9
|
+
* behind a binding, thus it stays with the value tier.
|
|
10
|
+
*
|
|
11
|
+
* The free-numeral scan needs no file, thus the finish runs it and reports each hit as a warning. A
|
|
12
|
+
* warning never makes a draft invalid, and it rides beside the outcome in either case. Without the
|
|
13
|
+
* channel a caller could not read the one signal that catches a figure typed into prose with no metric
|
|
14
|
+
* block behind it.
|
|
15
|
+
*
|
|
16
|
+
* The result is plain data. A gap is an expected outcome, not an error, thus the finish never throws. On
|
|
17
|
+
* a pass the finish gives the valid document, and it does not change the draft.
|
|
18
|
+
*/
|
|
19
|
+
import { ReportDocumentSchema } from "../contracts/report-blocks.js";
|
|
20
|
+
import { walkBlocks } from "./block-walk.js";
|
|
21
|
+
import { validateReferenceStructure } from "./structural-validation.js";
|
|
22
|
+
/**
|
|
23
|
+
* Finish a draft. The finish validates the schema, the unique ids, and the structural resolution of each
|
|
24
|
+
* reference, and it reports each gap as data. It warns about each free numeral in prose.
|
|
25
|
+
*/
|
|
26
|
+
export function finishDraft(draft, snapshot) {
|
|
27
|
+
const gaps = [];
|
|
28
|
+
const parsed = ReportDocumentSchema.safeParse(draft);
|
|
29
|
+
if (!parsed.success) {
|
|
30
|
+
for (const issue of parsed.error.issues) {
|
|
31
|
+
gaps.push({
|
|
32
|
+
kind: "schema",
|
|
33
|
+
path: issue.path.map((segment) => String(segment)).join("."),
|
|
34
|
+
message: issue.message,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// The walk reads the draft tree, not the parse result. The draft is already typed, thus the walk stays
|
|
39
|
+
// well-defined even when the schema parse fails, and a caller still gets the id and reference gaps.
|
|
40
|
+
const { references, repeatedIds, warnings } = walkBlocks(draft.sections);
|
|
41
|
+
for (const id of repeatedIds) {
|
|
42
|
+
gaps.push({ kind: "duplicate-id", id });
|
|
43
|
+
}
|
|
44
|
+
for (const entry of references) {
|
|
45
|
+
const result = validateReferenceStructure(entry.reference, snapshot);
|
|
46
|
+
if (result.isErr()) {
|
|
47
|
+
gaps.push({ kind: "unresolved-reference", blockId: entry.blockId, failure: result.error });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// A schema failure always pushes a gap. Thus an empty gap list means the parse passed. The
|
|
51
|
+
// `parsed.success` test also narrows the type for the document return.
|
|
52
|
+
if (!parsed.success || gaps.length > 0) {
|
|
53
|
+
return { valid: false, gaps, warnings };
|
|
54
|
+
}
|
|
55
|
+
return { valid: true, document: parsed.data, warnings };
|
|
56
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pure operations that compose a draft report document.
|
|
3
|
+
*
|
|
4
|
+
* An operation takes the draft, an operation value, and the pinned snapshot. It gives a new draft, or a
|
|
5
|
+
* typed refusal in the error channel. It mutates nothing. Thus a refused operation leaves the input draft
|
|
6
|
+
* as it was.
|
|
7
|
+
*
|
|
8
|
+
* An operation validates the delta only. It parses the new payload with the draft grammar. It scans the
|
|
9
|
+
* ids that the payload brings, and it resolves each new reference against the snapshot with the
|
|
10
|
+
* structural tier. The completeness rules gate one time, at the finish.
|
|
11
|
+
*
|
|
12
|
+
* The candidate shares each untouched branch with the input draft. An operation rebuilds only the path to
|
|
13
|
+
* the edit. Thus the input stays intact, and the memory cost stays small.
|
|
14
|
+
*
|
|
15
|
+
* A destination names an anchor, not an index. An index breaks when the tree changes under the agent, and
|
|
16
|
+
* an anchor id stays stable.
|
|
17
|
+
*/
|
|
18
|
+
import { type Result } from "neverthrow";
|
|
19
|
+
import type { UnresolvedReference } from "../contracts/report-reference.js";
|
|
20
|
+
import { type DraftBlock, type DraftDocument, type DraftSectionBlock } from "./draft.js";
|
|
21
|
+
import type { ReportSnapshot } from "./reference-resolver.js";
|
|
22
|
+
/**
|
|
23
|
+
* The closed set of refusal reasons. Each operation gives a subset of these.
|
|
24
|
+
*
|
|
25
|
+
* `unknown-target` means that no block holds an id that the operation named. `conflicting-destination`
|
|
26
|
+
* means that the destination named two places at one time. The two are separate because the repair
|
|
27
|
+
* differs: the first sends the agent to the outline for a correct id, and the second tells it to drop one
|
|
28
|
+
* of the fields it gave.
|
|
29
|
+
*/
|
|
30
|
+
export type DraftRefusalReason = "malformed-block" | "duplicate-id" | "unknown-target" | "conflicting-destination" | "unresolved-reference" | "cycle" | "atom-at-root" | "not-a-section" | "payload-kind-mismatch";
|
|
31
|
+
/**
|
|
32
|
+
* A typed refusal. It carries the reason and a prose detail. The `unresolved-reference` reason also
|
|
33
|
+
* carries each reference that the snapshot does not resolve.
|
|
34
|
+
*/
|
|
35
|
+
export type DraftRefusal = {
|
|
36
|
+
reason: Exclude<DraftRefusalReason, "unresolved-reference">;
|
|
37
|
+
detail: string;
|
|
38
|
+
} | {
|
|
39
|
+
reason: "unresolved-reference";
|
|
40
|
+
detail: string;
|
|
41
|
+
unresolved: UnresolvedReference[];
|
|
42
|
+
};
|
|
43
|
+
/** The place inside a parent. The default place is `end`. An anchor names a sibling id. */
|
|
44
|
+
export type DraftPlace = "start" | "end" | {
|
|
45
|
+
before: string;
|
|
46
|
+
} | {
|
|
47
|
+
after: string;
|
|
48
|
+
};
|
|
49
|
+
/** The destination of an add or a move. `parentId` names a section, or the root when it is absent. */
|
|
50
|
+
export interface DraftDestination {
|
|
51
|
+
parentId?: string;
|
|
52
|
+
place?: DraftPlace;
|
|
53
|
+
}
|
|
54
|
+
/** The add operation value. The payload can be an atom, or a section that carries children. */
|
|
55
|
+
export interface AddOperation {
|
|
56
|
+
block: unknown;
|
|
57
|
+
destination?: DraftDestination;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The change operation value. A `title` retitles a section target. A `block` replaces an atom target.
|
|
61
|
+
* The operation stamps the target id on the block, thus an id mismatch is unrepresentable.
|
|
62
|
+
*/
|
|
63
|
+
export type ChangeOperation = {
|
|
64
|
+
targetId: string;
|
|
65
|
+
} & ({
|
|
66
|
+
title: string;
|
|
67
|
+
} | {
|
|
68
|
+
block: unknown;
|
|
69
|
+
});
|
|
70
|
+
/** The remove operation value. It names one block by its id. */
|
|
71
|
+
export interface RemoveOperation {
|
|
72
|
+
targetId: string;
|
|
73
|
+
}
|
|
74
|
+
/** The move operation value. It names one block, and a destination with the shape of the add destination. */
|
|
75
|
+
export interface MoveOperation {
|
|
76
|
+
targetId: string;
|
|
77
|
+
destination?: DraftDestination;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Set the title of the document.
|
|
81
|
+
*
|
|
82
|
+
* A title carries no id and no reference, thus it needs none of the shared checks and it cannot refuse.
|
|
83
|
+
* The document schema requires a non-empty title, and the finish reports an empty one as a gap.
|
|
84
|
+
*/
|
|
85
|
+
export declare function setTitle(draft: DraftDocument, title: string): DraftDocument;
|
|
86
|
+
/**
|
|
87
|
+
* Add a block at a destination.
|
|
88
|
+
*
|
|
89
|
+
* The root admits a section only, thus an atom at the root refuses. The validation covers the payload and
|
|
90
|
+
* each of its descendants.
|
|
91
|
+
*/
|
|
92
|
+
export declare function addBlock(draft: DraftDocument, operation: AddOperation, snapshot: ReportSnapshot): Result<DraftDocument, DraftRefusal>;
|
|
93
|
+
/**
|
|
94
|
+
* Change one block by its id.
|
|
95
|
+
*
|
|
96
|
+
* A section target takes a title, and its children stay as they are. An atom target takes a full block,
|
|
97
|
+
* and a kind change is permitted. A payload that does not match the target kind refuses.
|
|
98
|
+
*/
|
|
99
|
+
export declare function changeBlock(draft: DraftDocument, operation: ChangeOperation, snapshot: ReportSnapshot): Result<DraftDocument, DraftRefusal>;
|
|
100
|
+
/**
|
|
101
|
+
* Remove one block by its id.
|
|
102
|
+
*
|
|
103
|
+
* A removed section takes its whole subtree. A removed id is free for a later add.
|
|
104
|
+
*/
|
|
105
|
+
export declare function removeBlock(draft: DraftDocument, operation: RemoveOperation, snapshot: ReportSnapshot): Result<DraftDocument, DraftRefusal>;
|
|
106
|
+
/**
|
|
107
|
+
* Move one block to a destination.
|
|
108
|
+
*
|
|
109
|
+
* The moved block keeps its subtree. A section must not move into its own subtree, thus a move into the
|
|
110
|
+
* subtree refuses with a cycle. A move with the moved block as its own anchor refuses.
|
|
111
|
+
*/
|
|
112
|
+
export declare function moveBlock(draft: DraftDocument, operation: MoveOperation, snapshot: ReportSnapshot): Result<DraftDocument, DraftRefusal>;
|
|
113
|
+
/** One block, the path of child indices from the root to the block, and the section that holds it. */
|
|
114
|
+
export interface Located {
|
|
115
|
+
block: DraftBlock;
|
|
116
|
+
path: number[];
|
|
117
|
+
/** The section that holds the block, or `undefined` when the block sits at the root. */
|
|
118
|
+
parent?: DraftSectionBlock;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Find a block by its id, with the path from the root. The search visits each block one time.
|
|
122
|
+
*
|
|
123
|
+
* The read surface needs the same search, thus this is the one find-by-id in the draft model.
|
|
124
|
+
*/
|
|
125
|
+
export declare function locate(document: DraftDocument, id: string): Located | undefined;
|