@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
|
@@ -42,6 +42,7 @@ export function createSubmitReportTool(state) {
|
|
|
42
42
|
"samples — the rest had no QC row'. " +
|
|
43
43
|
"Leave empty when the report shipped cleanly."),
|
|
44
44
|
}),
|
|
45
|
+
describeCall: "none",
|
|
45
46
|
execute: async (input) => {
|
|
46
47
|
const problems = [];
|
|
47
48
|
// 1. report.html.j2 exists — the report itself, as opposed to the
|
|
@@ -44,6 +44,7 @@ export function createVersionFsTools(state) {
|
|
|
44
44
|
path: z.string().min(1),
|
|
45
45
|
content: z.string(),
|
|
46
46
|
}),
|
|
47
|
+
describeCall: "none",
|
|
47
48
|
execute: async ({ path, content }) => {
|
|
48
49
|
const resolved = resolveAgentPath(path, state.versionDir);
|
|
49
50
|
if (resolved.kind === "out_of_scope") {
|
|
@@ -73,6 +74,7 @@ export function createVersionFsTools(state) {
|
|
|
73
74
|
oldText: z.string().min(1),
|
|
74
75
|
newText: z.string(),
|
|
75
76
|
}),
|
|
77
|
+
describeCall: "none",
|
|
76
78
|
execute: async ({ path, oldText, newText }) => {
|
|
77
79
|
const resolved = resolveAgentPath(path, state.versionDir);
|
|
78
80
|
if (resolved.kind === "out_of_scope") {
|
|
@@ -112,6 +114,7 @@ export function createVersionFsTools(state) {
|
|
|
112
114
|
inputSchema: z.object({
|
|
113
115
|
path: z.string().min(1),
|
|
114
116
|
}),
|
|
117
|
+
describeCall: "none",
|
|
115
118
|
execute: async ({ path }) => {
|
|
116
119
|
const resolved = resolveAgentPath(path, state.versionDir);
|
|
117
120
|
if (resolved.kind === "out_of_scope") {
|
|
@@ -148,6 +151,7 @@ export function createVersionFsTools(state) {
|
|
|
148
151
|
inputSchema: z.object({
|
|
149
152
|
path: z.string().min(1),
|
|
150
153
|
}),
|
|
154
|
+
describeCall: "none",
|
|
151
155
|
execute: async ({ path }) => {
|
|
152
156
|
const resolved = resolveAgentPath(path, state.versionDir);
|
|
153
157
|
if (resolved.kind === "out_of_scope") {
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The authoring tool surface over the draft operations.
|
|
3
|
+
*
|
|
4
|
+
* The factory closes over a private draft holder and the pinned snapshot. It gives eight tools and a
|
|
5
|
+
* read of the current draft. The tools read no ambient state, thus two factories hold two independent
|
|
6
|
+
* drafts.
|
|
7
|
+
*
|
|
8
|
+
* Each tool maps its flat input onto a core operation, and it applies the pure operation. The holder
|
|
9
|
+
* swaps only on a landed operation. A refused operation returns typed data in the ok channel, and the
|
|
10
|
+
* error channel stays for an unexpected failure.
|
|
11
|
+
*
|
|
12
|
+
* The primitive admits a flat object input only. Thus a destination is four optional fields, and not a
|
|
13
|
+
* nested union. A conflict between the flat fields refuses before the core runs.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
import { type DraftRefusal } from "../../report-model/draft-operations.js";
|
|
17
|
+
import { type OutlineEntry, type ReadableBlock } from "../../report-model/draft-read.js";
|
|
18
|
+
import { type FinishResult } from "../../report-model/draft-finish.js";
|
|
19
|
+
import { type DraftDocument } from "../../report-model/draft.js";
|
|
20
|
+
import type { ReportSnapshot } from "../../report-model/reference-resolver.js";
|
|
21
|
+
import { type Tool } from "../define-tool.js";
|
|
22
|
+
/** The flat destination fields. An anchor is `before` or `after`, and a place is `start` or `end`. */
|
|
23
|
+
declare const addBlockInput: z.ZodObject<{
|
|
24
|
+
block: z.ZodUnion<readonly [z.ZodType<import("../../report-model/draft.js").DraftBlock, unknown, z.core.$ZodTypeInternals<import("../../report-model/draft.js").DraftBlock, unknown>>, z.ZodUnknown]>;
|
|
25
|
+
parentId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
26
|
+
place: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
27
|
+
end: "end";
|
|
28
|
+
start: "start";
|
|
29
|
+
}>>>;
|
|
30
|
+
before: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
31
|
+
after: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
/**
|
|
34
|
+
* The change payload is a title for a section target, or a block for an atom target, and exactly one of
|
|
35
|
+
* the two. Both fields are absentable, because a section retitle names no block. Zod 4 treats a bare
|
|
36
|
+
* `z.unknown()` as a required key, thus an optional marker is what makes the retitle call representable.
|
|
37
|
+
*/
|
|
38
|
+
declare const changeBlockInput: z.ZodObject<{
|
|
39
|
+
targetId: z.ZodString;
|
|
40
|
+
title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
41
|
+
block: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<import("../../report-model/draft.js").DraftBlock, unknown, z.core.$ZodTypeInternals<import("../../report-model/draft.js").DraftBlock, unknown>>, z.ZodUnknown]>>;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
declare const removeBlockInput: z.ZodObject<{
|
|
44
|
+
targetId: z.ZodString;
|
|
45
|
+
}, z.core.$strip>;
|
|
46
|
+
declare const moveBlockInput: z.ZodObject<{
|
|
47
|
+
targetId: z.ZodString;
|
|
48
|
+
parentId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
49
|
+
place: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
50
|
+
end: "end";
|
|
51
|
+
start: "start";
|
|
52
|
+
}>>>;
|
|
53
|
+
before: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
54
|
+
after: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
55
|
+
}, z.core.$strip>;
|
|
56
|
+
declare const readOutlineInput: z.ZodObject<{}, z.core.$strip>;
|
|
57
|
+
/** The read names its target with the same field name as each mutation, thus one id key serves them all. */
|
|
58
|
+
declare const readBlockInput: z.ZodObject<{
|
|
59
|
+
targetId: z.ZodString;
|
|
60
|
+
}, z.core.$strip>;
|
|
61
|
+
declare const setTitleInput: z.ZodObject<{
|
|
62
|
+
title: z.ZodString;
|
|
63
|
+
}, z.core.$strip>;
|
|
64
|
+
declare const finishDraftInput: z.ZodObject<{}, z.core.$strip>;
|
|
65
|
+
export type AddBlockInput = z.infer<typeof addBlockInput>;
|
|
66
|
+
export type ChangeBlockInput = z.infer<typeof changeBlockInput>;
|
|
67
|
+
export type RemoveBlockInput = z.infer<typeof removeBlockInput>;
|
|
68
|
+
export type MoveBlockInput = z.infer<typeof moveBlockInput>;
|
|
69
|
+
export type ReadOutlineInput = z.infer<typeof readOutlineInput>;
|
|
70
|
+
export type ReadBlockInput = z.infer<typeof readBlockInput>;
|
|
71
|
+
export type SetTitleInput = z.infer<typeof setTitleInput>;
|
|
72
|
+
export type FinishDraftInput = z.infer<typeof finishDraftInput>;
|
|
73
|
+
/** One container that an operation changed, and the child order inside it after the operation. */
|
|
74
|
+
export interface ChangedContainer {
|
|
75
|
+
/** The section that holds the children. It is absent when the container is the root. */
|
|
76
|
+
parentId?: string;
|
|
77
|
+
children: OutlineEntry[];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The result of a mutation tool. A refusal carries the typed reason.
|
|
81
|
+
*
|
|
82
|
+
* A landing carries the child order of each container that it changed, and not the whole outline. A whole
|
|
83
|
+
* outline costs the size of the draft on every landing, thus composing a report of n blocks would spend
|
|
84
|
+
* n-squared outline entries of agent context to author it. Only the container that the operation touched
|
|
85
|
+
* can surprise the agent: it chose the id, and the rest of the tree did not move. `read_outline` stays
|
|
86
|
+
* the way to read the whole draft, and it costs one call when the agent wants one.
|
|
87
|
+
*
|
|
88
|
+
* A move across two containers reports both. An operation that changes no child order reports none.
|
|
89
|
+
*/
|
|
90
|
+
export type MutationResult = {
|
|
91
|
+
applied: true;
|
|
92
|
+
changed: ChangedContainer[];
|
|
93
|
+
} | {
|
|
94
|
+
applied: false;
|
|
95
|
+
refusal: DraftRefusal;
|
|
96
|
+
};
|
|
97
|
+
/** The result of `read_outline`. */
|
|
98
|
+
export interface OutlineResult {
|
|
99
|
+
outline: OutlineEntry[];
|
|
100
|
+
}
|
|
101
|
+
/** The result of `read_block`. An absent block is an expected outcome, thus it stays in the ok channel. */
|
|
102
|
+
export type ReadBlockResult = {
|
|
103
|
+
found: true;
|
|
104
|
+
block: ReadableBlock;
|
|
105
|
+
} | {
|
|
106
|
+
found: false;
|
|
107
|
+
};
|
|
108
|
+
/** The state that the factory closes over. */
|
|
109
|
+
export interface ReportAuthoringState {
|
|
110
|
+
readonly snapshot: ReportSnapshot;
|
|
111
|
+
/** The draft to start from. The default is an empty draft. */
|
|
112
|
+
readonly initialDraft?: DraftDocument;
|
|
113
|
+
}
|
|
114
|
+
/** The eight authoring tools, plus a read of the current draft. */
|
|
115
|
+
export interface ReportAuthoringTools {
|
|
116
|
+
readonly add_block: Tool<AddBlockInput, MutationResult>;
|
|
117
|
+
readonly change_block: Tool<ChangeBlockInput, MutationResult>;
|
|
118
|
+
readonly remove_block: Tool<RemoveBlockInput, MutationResult>;
|
|
119
|
+
readonly move_block: Tool<MoveBlockInput, MutationResult>;
|
|
120
|
+
readonly set_title: Tool<SetTitleInput, MutationResult>;
|
|
121
|
+
readonly read_outline: Tool<ReadOutlineInput, OutlineResult>;
|
|
122
|
+
readonly read_block: Tool<ReadBlockInput, ReadBlockResult>;
|
|
123
|
+
readonly finish_draft: Tool<FinishDraftInput, FinishResult>;
|
|
124
|
+
currentDraft(): DraftDocument;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Make the eight authoring tools over one draft.
|
|
128
|
+
*
|
|
129
|
+
* The holder is a private `let`. Each tool reads the holder at call time, thus a landing through one tool
|
|
130
|
+
* shows in the next call of every tool. The holder swaps only inside `land`, thus a refused operation
|
|
131
|
+
* leaves the draft as it was.
|
|
132
|
+
*/
|
|
133
|
+
export declare function createReportAuthoringTools(state: ReportAuthoringState): ReportAuthoringTools;
|
|
134
|
+
export {};
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The authoring tool surface over the draft operations.
|
|
3
|
+
*
|
|
4
|
+
* The factory closes over a private draft holder and the pinned snapshot. It gives eight tools and a
|
|
5
|
+
* read of the current draft. The tools read no ambient state, thus two factories hold two independent
|
|
6
|
+
* drafts.
|
|
7
|
+
*
|
|
8
|
+
* Each tool maps its flat input onto a core operation, and it applies the pure operation. The holder
|
|
9
|
+
* swaps only on a landed operation. A refused operation returns typed data in the ok channel, and the
|
|
10
|
+
* error channel stays for an unexpected failure.
|
|
11
|
+
*
|
|
12
|
+
* The primitive admits a flat object input only. Thus a destination is four optional fields, and not a
|
|
13
|
+
* nested union. A conflict between the flat fields refuses before the core runs.
|
|
14
|
+
*/
|
|
15
|
+
import { err, ok } from "neverthrow";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
import { addBlock, changeBlock, locate, moveBlock, removeBlock, setTitle, } from "../../report-model/draft-operations.js";
|
|
18
|
+
import { buildOutline, childOutline, readBlock } from "../../report-model/draft-read.js";
|
|
19
|
+
import { finishDraft } from "../../report-model/draft-finish.js";
|
|
20
|
+
import { DraftBlockSchema } from "../../report-model/draft.js";
|
|
21
|
+
import { defineTool } from "../define-tool.js";
|
|
22
|
+
/**
|
|
23
|
+
* The block payload.
|
|
24
|
+
*
|
|
25
|
+
* The published JSON Schema carries the whole draft grammar, because a tool is self-describing at attach
|
|
26
|
+
* time and the schema is the only place where the model learns the shape of the eight block kinds. A bare
|
|
27
|
+
* `z.unknown()` emits the empty schema, which tells the model nothing and leaves it to discover each
|
|
28
|
+
* required field through one refusal at a time.
|
|
29
|
+
*
|
|
30
|
+
* The `z.unknown()` member keeps the runtime parse permissive. Thus a malformed payload still reaches the
|
|
31
|
+
* core, which parses it with the same grammar and refuses `malformed-block` as typed data in the ok
|
|
32
|
+
* channel. A strict input schema would turn that designed refusal into a hard input-validation error from
|
|
33
|
+
* the loop.
|
|
34
|
+
*/
|
|
35
|
+
const blockPayload = z.union([DraftBlockSchema, z.unknown()]);
|
|
36
|
+
/**
|
|
37
|
+
* A flat field that the model can leave out.
|
|
38
|
+
*
|
|
39
|
+
* Nullish, and not optional. A model that must choose one of four destination fields routinely sends
|
|
40
|
+
* `null` for the three it does not use, and strict function calling requires every declared key to be
|
|
41
|
+
* present. Under `.optional()` each of those nulls fails the input parse, and the block never lands.
|
|
42
|
+
*/
|
|
43
|
+
const absentable = (schema) => schema.nullish();
|
|
44
|
+
/** The flat destination fields. An anchor is `before` or `after`, and a place is `start` or `end`. */
|
|
45
|
+
const addBlockInput = z.object({
|
|
46
|
+
block: blockPayload,
|
|
47
|
+
parentId: absentable(z.string()),
|
|
48
|
+
place: absentable(z.enum(["start", "end"])),
|
|
49
|
+
before: absentable(z.string()),
|
|
50
|
+
after: absentable(z.string()),
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* The change payload is a title for a section target, or a block for an atom target, and exactly one of
|
|
54
|
+
* the two. Both fields are absentable, because a section retitle names no block. Zod 4 treats a bare
|
|
55
|
+
* `z.unknown()` as a required key, thus an optional marker is what makes the retitle call representable.
|
|
56
|
+
*/
|
|
57
|
+
const changeBlockInput = z.object({
|
|
58
|
+
targetId: z.string(),
|
|
59
|
+
title: absentable(z.string()),
|
|
60
|
+
block: blockPayload.optional(),
|
|
61
|
+
});
|
|
62
|
+
const removeBlockInput = z.object({
|
|
63
|
+
targetId: z.string(),
|
|
64
|
+
});
|
|
65
|
+
const moveBlockInput = z.object({
|
|
66
|
+
targetId: z.string(),
|
|
67
|
+
parentId: absentable(z.string()),
|
|
68
|
+
place: absentable(z.enum(["start", "end"])),
|
|
69
|
+
before: absentable(z.string()),
|
|
70
|
+
after: absentable(z.string()),
|
|
71
|
+
});
|
|
72
|
+
const readOutlineInput = z.object({});
|
|
73
|
+
/** The read names its target with the same field name as each mutation, thus one id key serves them all. */
|
|
74
|
+
const readBlockInput = z.object({
|
|
75
|
+
targetId: z.string(),
|
|
76
|
+
});
|
|
77
|
+
const setTitleInput = z.object({
|
|
78
|
+
title: z.string().min(1),
|
|
79
|
+
});
|
|
80
|
+
const finishDraftInput = z.object({});
|
|
81
|
+
/** Read an absentable field. An explicit `null` and an omitted key both mean that the model gave no value. */
|
|
82
|
+
function given(value) {
|
|
83
|
+
return value ?? undefined;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Map the flat destination fields onto the core destination.
|
|
87
|
+
*
|
|
88
|
+
* Two anchors, or an anchor beside a place, name two places at one time. Thus the map refuses with
|
|
89
|
+
* `conflicting-destination`, and the detail names the conflict. An anchor implies its own parent, thus a
|
|
90
|
+
* place beside an anchor is a contradiction and not a refinement.
|
|
91
|
+
*
|
|
92
|
+
* The reason is not `unknown-target`, which means that no block holds a named id. A conflict is a fault in
|
|
93
|
+
* the shape of the call, and the repair is to drop one field. An agent that reads `unknown-target` instead
|
|
94
|
+
* goes back to the outline for a better id, finds the ids were already correct, and sends the same
|
|
95
|
+
* conflicting pair again.
|
|
96
|
+
*/
|
|
97
|
+
function toDestination(input) {
|
|
98
|
+
const parentId = given(input.parentId);
|
|
99
|
+
const place = given(input.place);
|
|
100
|
+
const before = given(input.before);
|
|
101
|
+
const after = given(input.after);
|
|
102
|
+
if (before !== undefined && after !== undefined) {
|
|
103
|
+
return err({ reason: "conflicting-destination", detail: "a destination names `before` or `after`, not both" });
|
|
104
|
+
}
|
|
105
|
+
const hasAnchor = before !== undefined || after !== undefined;
|
|
106
|
+
if (hasAnchor && place !== undefined) {
|
|
107
|
+
return err({ reason: "conflicting-destination", detail: "a destination names an anchor or a `place`, not both" });
|
|
108
|
+
}
|
|
109
|
+
let resolvedPlace;
|
|
110
|
+
if (before !== undefined) {
|
|
111
|
+
resolvedPlace = { before };
|
|
112
|
+
}
|
|
113
|
+
else if (after !== undefined) {
|
|
114
|
+
resolvedPlace = { after };
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
resolvedPlace = place;
|
|
118
|
+
}
|
|
119
|
+
return ok({ parentId, place: resolvedPlace });
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Map the flat change fields onto the core change operation.
|
|
123
|
+
*
|
|
124
|
+
* A change names a title or a block, and exactly one of the two. Neither field and both fields each name
|
|
125
|
+
* an ambiguous change. Thus the map refuses with `payload-kind-mismatch`.
|
|
126
|
+
*/
|
|
127
|
+
function toChangeOperation(input) {
|
|
128
|
+
const title = given(input.title);
|
|
129
|
+
const block = given(input.block);
|
|
130
|
+
if (title !== undefined && block !== undefined) {
|
|
131
|
+
return err({ reason: "payload-kind-mismatch", detail: "a change names a `title` or a `block`, not both" });
|
|
132
|
+
}
|
|
133
|
+
if (title !== undefined) {
|
|
134
|
+
return ok({ targetId: input.targetId, title });
|
|
135
|
+
}
|
|
136
|
+
if (block !== undefined) {
|
|
137
|
+
return ok({ targetId: input.targetId, block: decodeBlockPayload(block) });
|
|
138
|
+
}
|
|
139
|
+
return err({ reason: "payload-kind-mismatch", detail: "a change names a `title` or a `block`" });
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Give the block payload as the core expects it, and decode a double-encoded one.
|
|
143
|
+
*
|
|
144
|
+
* A model routinely sends a nested object as a `JSON.stringify` string. The loop repairs that at its own
|
|
145
|
+
* input boundary, but only for a schema that rejects the string, and this payload accepts any value so
|
|
146
|
+
* that a malformed block can come back as a typed refusal. Thus the decode happens here. A string that is
|
|
147
|
+
* not JSON passes through as it is, and the core refuses it as a malformed block.
|
|
148
|
+
*/
|
|
149
|
+
function decodeBlockPayload(block) {
|
|
150
|
+
if (typeof block !== "string") {
|
|
151
|
+
return block;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
return JSON.parse(block);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return block;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Read the `kind` of an untyped block payload, or `undefined` when the payload names none. */
|
|
161
|
+
function readKind(block) {
|
|
162
|
+
return readStringField(block, "kind");
|
|
163
|
+
}
|
|
164
|
+
/** Read the `id` of an untyped block payload, or `undefined` when the payload names none. */
|
|
165
|
+
function readId(block) {
|
|
166
|
+
return readStringField(block, "id");
|
|
167
|
+
}
|
|
168
|
+
function readStringField(block, field) {
|
|
169
|
+
if (block !== null && typeof block === "object") {
|
|
170
|
+
const value = block[field];
|
|
171
|
+
if (typeof value === "string") {
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The id of the section that holds a block, or `undefined` when the block sits at the root.
|
|
179
|
+
*
|
|
180
|
+
* The two cases are not distinguishable from the value alone, thus a caller that needs to tell "the root"
|
|
181
|
+
* from "no such block" tests the block itself first.
|
|
182
|
+
*/
|
|
183
|
+
function holderIdOf(document, blockId) {
|
|
184
|
+
return locate(document, blockId)?.parent?.id;
|
|
185
|
+
}
|
|
186
|
+
/** Read the child order of one container out of a document. */
|
|
187
|
+
function containerIn(document, parentId) {
|
|
188
|
+
if (parentId === undefined) {
|
|
189
|
+
return { children: childOutline(document.sections, 0) };
|
|
190
|
+
}
|
|
191
|
+
const located = locate(document, parentId);
|
|
192
|
+
// A parent id reaches here only from a landed operation, which already resolved it to a section. The
|
|
193
|
+
// empty fall-back keeps the read total rather than asserting that.
|
|
194
|
+
const children = located !== undefined && located.block.kind === "section" ? located.block.blocks : [];
|
|
195
|
+
return { parentId, children: childOutline(children, located?.path.length ?? 0) };
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Every tool of this surface runs inline.
|
|
199
|
+
*
|
|
200
|
+
* The draft is closure memory with no durable backing. A step-mode tool goes through `DBOS.runStep`, which
|
|
201
|
+
* caches the result of a step and replays it without running the body. A replay after a host restart would
|
|
202
|
+
* hand the agent the cached `applied: true` outline of each landed operation while the rebuilt closure
|
|
203
|
+
* holds an empty draft, and the finish would then report an empty document for a report that the
|
|
204
|
+
* transcript shows as complete. Inline mode keeps the tool result and the draft in one lifetime.
|
|
205
|
+
*/
|
|
206
|
+
const AUTHORING_EXECUTION_MODE = "inline";
|
|
207
|
+
/**
|
|
208
|
+
* Make the eight authoring tools over one draft.
|
|
209
|
+
*
|
|
210
|
+
* The holder is a private `let`. Each tool reads the holder at call time, thus a landing through one tool
|
|
211
|
+
* shows in the next call of every tool. The holder swaps only inside `land`, thus a refused operation
|
|
212
|
+
* leaves the draft as it was.
|
|
213
|
+
*/
|
|
214
|
+
export function createReportAuthoringTools(state) {
|
|
215
|
+
const snapshot = state.snapshot;
|
|
216
|
+
let draft = state.initialDraft ?? { title: "", sections: [] };
|
|
217
|
+
/**
|
|
218
|
+
* Swap the holder on a landing, and report the containers that the operation changed.
|
|
219
|
+
*
|
|
220
|
+
* `holders` names them by id, and it reads the draft as it was and the draft as it becomes, because a
|
|
221
|
+
* removed block has a holder only in the first and an added block has one only in the second. The
|
|
222
|
+
* child order comes out of `next` in either case.
|
|
223
|
+
*/
|
|
224
|
+
const land = (result, holders) => result.match((next) => {
|
|
225
|
+
const previous = draft;
|
|
226
|
+
draft = next;
|
|
227
|
+
// A move inside one container names the same holder two times.
|
|
228
|
+
const unique = [...new Set(holders(previous, next))];
|
|
229
|
+
return { applied: true, changed: unique.map((parentId) => containerIn(next, parentId)) };
|
|
230
|
+
}, (refusal) => ({ applied: false, refusal }));
|
|
231
|
+
const refuse = (refusal) => ({ applied: false, refusal });
|
|
232
|
+
const add_block = defineTool({
|
|
233
|
+
id: "add_block",
|
|
234
|
+
description: "Add one block to the draft. The `block` schema gives the eight kinds and the fields of each one. " +
|
|
235
|
+
"You choose the `id` of the block, and it must be unique in the draft. " +
|
|
236
|
+
"Name the destination with `parentId` and one of `place`, `before`, or `after`. " +
|
|
237
|
+
"The root admits a section only, and an atom needs a section as its parent.",
|
|
238
|
+
inputSchema: addBlockInput,
|
|
239
|
+
executionMode: AUTHORING_EXECUTION_MODE,
|
|
240
|
+
describeCall: (input) => {
|
|
241
|
+
const kind = readKind(decodeBlockPayload(input.block));
|
|
242
|
+
return kind !== undefined ? `add ${kind}` : "add a block";
|
|
243
|
+
},
|
|
244
|
+
execute: async (input) => {
|
|
245
|
+
const destination = toDestination(input);
|
|
246
|
+
if (destination.isErr()) {
|
|
247
|
+
return ok(refuse(destination.error));
|
|
248
|
+
}
|
|
249
|
+
const block = decodeBlockPayload(input.block);
|
|
250
|
+
const addedId = readId(block);
|
|
251
|
+
return ok(land(addBlock(draft, { block, destination: destination.value }, snapshot), (_previous, next) => [
|
|
252
|
+
addedId === undefined ? undefined : holderIdOf(next, addedId),
|
|
253
|
+
]));
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
const change_block = defineTool({
|
|
257
|
+
id: "change_block",
|
|
258
|
+
description: "Change one block by its id. Give a `title` to retitle a section, or a `block` to replace an atom, and never both. " +
|
|
259
|
+
"The change keeps the id of the target, thus the `id` of the payload does not matter. A kind change is permitted.",
|
|
260
|
+
inputSchema: changeBlockInput,
|
|
261
|
+
executionMode: AUTHORING_EXECUTION_MODE,
|
|
262
|
+
describeCall: (input) => `change ${input.targetId}`,
|
|
263
|
+
execute: async (input) => {
|
|
264
|
+
const operation = toChangeOperation(input);
|
|
265
|
+
if (operation.isErr()) {
|
|
266
|
+
return ok(refuse(operation.error));
|
|
267
|
+
}
|
|
268
|
+
return ok(land(changeBlock(draft, operation.value, snapshot), (_previous, next) => [holderIdOf(next, input.targetId)]));
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
const remove_block = defineTool({
|
|
272
|
+
id: "remove_block",
|
|
273
|
+
description: "Remove one block by its id. A removed section takes its whole subtree with it, and the id is free for a later add.",
|
|
274
|
+
inputSchema: removeBlockInput,
|
|
275
|
+
executionMode: AUTHORING_EXECUTION_MODE,
|
|
276
|
+
describeCall: (input) => `remove ${input.targetId}`,
|
|
277
|
+
execute: async (input) => ok(land(removeBlock(draft, { targetId: input.targetId }, snapshot), (previous) => [holderIdOf(previous, input.targetId)])),
|
|
278
|
+
});
|
|
279
|
+
const move_block = defineTool({
|
|
280
|
+
id: "move_block",
|
|
281
|
+
description: "Move one block by its id to a new destination. Name the destination with `parentId` and one of `place`, `before`, or `after`. " +
|
|
282
|
+
"A section cannot move into its own subtree.",
|
|
283
|
+
inputSchema: moveBlockInput,
|
|
284
|
+
executionMode: AUTHORING_EXECUTION_MODE,
|
|
285
|
+
describeCall: (input) => `move ${input.targetId}`,
|
|
286
|
+
execute: async (input) => {
|
|
287
|
+
const destination = toDestination(input);
|
|
288
|
+
if (destination.isErr()) {
|
|
289
|
+
return ok(refuse(destination.error));
|
|
290
|
+
}
|
|
291
|
+
return ok(land(moveBlock(draft, { targetId: input.targetId, destination: destination.value }, snapshot), (previous, next) => [
|
|
292
|
+
holderIdOf(previous, input.targetId),
|
|
293
|
+
holderIdOf(next, input.targetId),
|
|
294
|
+
]));
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
const set_title = defineTool({
|
|
298
|
+
id: "set_title",
|
|
299
|
+
description: "Set the title of the report document. A draft starts with no title, and a document needs one. " +
|
|
300
|
+
"The title names the whole report, and it is not the title of a section.",
|
|
301
|
+
inputSchema: setTitleInput,
|
|
302
|
+
executionMode: AUTHORING_EXECUTION_MODE,
|
|
303
|
+
describeCall: (input) => `title the report ${input.title}`,
|
|
304
|
+
// The title sits on the document, thus no container changes its child order.
|
|
305
|
+
execute: async (input) => ok(land(ok(setTitle(draft, input.title)), () => [])),
|
|
306
|
+
});
|
|
307
|
+
const read_outline = defineTool({
|
|
308
|
+
id: "read_outline",
|
|
309
|
+
description: "Read the outline of the draft. Each entry gives the id, the kind, the nesting depth, and a short label. " +
|
|
310
|
+
"A label that ends with the character … is clipped. Use the outline as the primary view of the draft, " +
|
|
311
|
+
"and read one block when the label is not enough.",
|
|
312
|
+
inputSchema: readOutlineInput,
|
|
313
|
+
executionMode: AUTHORING_EXECUTION_MODE,
|
|
314
|
+
// The input carries no field, thus a hook can only restate the name of the tool.
|
|
315
|
+
describeCall: "none",
|
|
316
|
+
execute: async () => ok({ outline: buildOutline(draft) }),
|
|
317
|
+
});
|
|
318
|
+
const read_block = defineTool({
|
|
319
|
+
id: "read_block",
|
|
320
|
+
description: "Read one block by its id. An atom gives the full block with its bindings. A section gives its title and the id of each child, " +
|
|
321
|
+
"because the outline already names every block under it. Use it when the outline label is not enough.",
|
|
322
|
+
inputSchema: readBlockInput,
|
|
323
|
+
executionMode: AUTHORING_EXECUTION_MODE,
|
|
324
|
+
describeCall: (input) => `read ${input.targetId}`,
|
|
325
|
+
execute: async (input) => {
|
|
326
|
+
const block = readBlock(draft, input.targetId);
|
|
327
|
+
const result = block !== undefined ? { found: true, block } : { found: false };
|
|
328
|
+
return ok(result);
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
const finish_draft = defineTool({
|
|
332
|
+
id: "finish_draft",
|
|
333
|
+
description: "Finish the draft. The result gives each completeness gap, or the valid report document, and each advisory warning. " +
|
|
334
|
+
"Use it to make sure that the draft passes the whole document schema, the id rule, and the structural tier.",
|
|
335
|
+
inputSchema: finishDraftInput,
|
|
336
|
+
executionMode: AUTHORING_EXECUTION_MODE,
|
|
337
|
+
// The input carries no field, thus a hook can only restate the name of the tool.
|
|
338
|
+
describeCall: "none",
|
|
339
|
+
execute: async () => ok(finishDraft(draft, snapshot)),
|
|
340
|
+
});
|
|
341
|
+
return {
|
|
342
|
+
add_block,
|
|
343
|
+
change_block,
|
|
344
|
+
remove_block,
|
|
345
|
+
move_block,
|
|
346
|
+
set_title,
|
|
347
|
+
read_outline,
|
|
348
|
+
read_block,
|
|
349
|
+
finish_draft,
|
|
350
|
+
currentDraft: () => draft,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
@@ -25,6 +25,7 @@ export const resolveLibraryIdTool = defineTool({
|
|
|
25
25
|
libraryName: z.string().describe("Package or library name to search for (e.g., 'scanpy', 'pysam', 'lifelines')."),
|
|
26
26
|
query: z.string().describe("What you need help with — used to rank results by relevance (e.g., 'how to run differential expression')."),
|
|
27
27
|
}),
|
|
28
|
+
describeCall: "none",
|
|
28
29
|
execute: async ({ libraryName, query }) => {
|
|
29
30
|
const result = await apiFetchValidated(`${CONTEXT7_BASE}/search?query=${encodeURIComponent(libraryName)}&topic=${encodeURIComponent(query)}`, Context7SearchResponseSchema, { maxRetries: 1 });
|
|
30
31
|
if (result.isErr())
|
|
@@ -48,6 +49,7 @@ export const queryDocsTool = defineTool({
|
|
|
48
49
|
libraryId: z.string().describe("Context7 library ID from resolve-library-id (e.g., '/scverse/scanpy')."),
|
|
49
50
|
query: z.string().describe("Specific question about the library (e.g., 'rank_genes_groups function parameters and usage')."),
|
|
50
51
|
}),
|
|
52
|
+
describeCall: "none",
|
|
51
53
|
execute: async ({ libraryId, query }) => {
|
|
52
54
|
const result = await apiFetchValidated(`${CONTEXT7_BASE}/docs?libraryId=${encodeURIComponent(libraryId)}&query=${encodeURIComponent(query)}`, Context7DocsResponseSchema, { maxRetries: 1 });
|
|
53
55
|
if (result.isErr())
|
|
@@ -23,7 +23,7 @@ import { finalText, runAgent } from "../../loop/run-agent.js";
|
|
|
23
23
|
import { passthroughStep } from "../../loop/run-step.js";
|
|
24
24
|
import { defineTool } from "../define-tool.js";
|
|
25
25
|
// Cross-domain search tools the analogical-reasoner uses.
|
|
26
|
-
import {
|
|
26
|
+
import { createSearchSemanticScholarTool } from "./search-semantic-scholar.js";
|
|
27
27
|
import { searchArxivTool } from "./search-arxiv.js";
|
|
28
28
|
import { createSearchGithubReposTool } from "./search-github-repos.js";
|
|
29
29
|
// Biology literature — reused for analogies that land back in biology.
|
|
@@ -156,7 +156,7 @@ function buildConversionPrompt(rawOutput) {
|
|
|
156
156
|
export function createGenerateAnalogyReportTool(deps) {
|
|
157
157
|
const ncbi = createNcbiTools(deps.bioKeys);
|
|
158
158
|
const reasonerTools = [
|
|
159
|
-
|
|
159
|
+
createSearchSemanticScholarTool({ ...(deps.bioKeys.semanticScholar === undefined ? {} : { apiKey: deps.bioKeys.semanticScholar }) }),
|
|
160
160
|
searchArxivTool,
|
|
161
161
|
createSearchGithubReposTool({ githubToken: deps.bioKeys.github }),
|
|
162
162
|
ncbi.pubmed,
|
|
@@ -193,6 +193,7 @@ export function createGenerateAnalogyReportTool(deps) {
|
|
|
193
193
|
"latency on the same failure). Surface the message and ask the user to " +
|
|
194
194
|
"narrow the problem.",
|
|
195
195
|
inputSchema: generateAnalogyReportInputSchema,
|
|
196
|
+
describeCall: "none",
|
|
196
197
|
execute: async (input, ctx) => {
|
|
197
198
|
const childSession = forSubAgent(ctx.session, AGENT_ID);
|
|
198
199
|
// Phase 1+2: drive the research agent over the cross-domain toolset.
|
|
@@ -344,6 +344,7 @@ function buildInnerTools(holder, trace, persistCtx, pool, resourcePolicy, logger
|
|
|
344
344
|
// structured issue reporting.
|
|
345
345
|
plan: z.union([PlannerPlanSchema, z.unknown()]).describe("Candidate plan; malformed values are reported in issues."),
|
|
346
346
|
}),
|
|
347
|
+
describeCall: "none",
|
|
347
348
|
execute: async (input) => {
|
|
348
349
|
if (holder.outcome !== null) {
|
|
349
350
|
trace.duplicateTerminalCalls++;
|
|
@@ -416,6 +417,7 @@ function buildInnerTools(holder, trace, persistCtx, pool, resourcePolicy, logger
|
|
|
416
417
|
question: z.string().min(1),
|
|
417
418
|
questionContext: z.string().optional(),
|
|
418
419
|
}),
|
|
420
|
+
describeCall: "none",
|
|
419
421
|
execute: async (input) => {
|
|
420
422
|
if (holder.outcome !== null) {
|
|
421
423
|
trace.duplicateTerminalCalls++;
|
|
@@ -670,6 +672,7 @@ export function createGeneratePlanTool(deps) {
|
|
|
670
672
|
.optional()
|
|
671
673
|
.describe("The planId of the prior plan being iterated on. Set only when " + "the user is asking for modifications to an existing plan."),
|
|
672
674
|
}),
|
|
675
|
+
describeCall: ({ researchQuestion }) => researchQuestion,
|
|
673
676
|
execute: async (input, ctx) => {
|
|
674
677
|
const analysisId = scopeResource(ctx.session.scope).resourceId;
|
|
675
678
|
// Bound per invocation: `analysisId` comes from the call-time session, not from
|
|
@@ -98,6 +98,10 @@ export function createInspectDataProfileTool(pool) {
|
|
|
98
98
|
.optional()
|
|
99
99
|
.describe(`Per-file records per page. Only used when scope is 'files'. Default ${DEFAULT_PAGE_SIZE}, max ${MAX_PAGE_SIZE}.`),
|
|
100
100
|
}),
|
|
101
|
+
// `execute` defaults both fields internally, and the hook applies the same
|
|
102
|
+
// defaults. Without them the ordinary call, which names no field at all,
|
|
103
|
+
// gives no detail. `page` acts only on the `files` scope, as in `execute`.
|
|
104
|
+
describeCall: ({ scope, page }) => ((scope ?? "overview") === "files" ? `files (page ${page ?? 1})` : "overview"),
|
|
101
105
|
execute: async (input, ctx) => {
|
|
102
106
|
const resourceId = scopeResource(ctx.session.scope).resourceId;
|
|
103
107
|
const status = unwrapOrThrow(await loadDataProfileStatus(pool, resourceId));
|
|
@@ -53,7 +53,7 @@ declare function formatRun(r: CortexRunRow, verbose: boolean, exposePaths?: bool
|
|
|
53
53
|
synthesisReason?: string | undefined;
|
|
54
54
|
runId: string;
|
|
55
55
|
workflowName: string;
|
|
56
|
-
status: "
|
|
56
|
+
status: "partial" | "running" | "completed" | "failed" | "canceled" | "suspended_insufficient_funds";
|
|
57
57
|
startedAt: string;
|
|
58
58
|
completedAt: string | null;
|
|
59
59
|
planId: string | null;
|
|
@@ -19,6 +19,7 @@ import { type Tool } from "../define-tool.js";
|
|
|
19
19
|
import { type BioToolKeys } from "../bio/keys.js";
|
|
20
20
|
import type { Logger } from "../../lib/logger.js";
|
|
21
21
|
import type { UsageRecorder } from "../../billing/usage-recorder.js";
|
|
22
|
+
import type { CitationResolver } from "../../citations/types.js";
|
|
22
23
|
export interface LiteratureReviewerDeps {
|
|
23
24
|
/** Operational logging seam; omitted falls back to no-op. */
|
|
24
25
|
readonly logger?: Logger;
|
|
@@ -30,6 +31,8 @@ export interface LiteratureReviewerDeps {
|
|
|
30
31
|
readonly bioKeys: BioToolKeys;
|
|
31
32
|
/** LLM usage-accounting seam for the child loop; omitted falls back to the no-op recorder. */
|
|
32
33
|
readonly usageRecorder?: UsageRecorder;
|
|
34
|
+
/** Shared bibliographic verification service; all agent surfaces share its pacing/cache. */
|
|
35
|
+
readonly citationResolver: CitationResolver;
|
|
33
36
|
}
|
|
34
37
|
/** Build the `literature_reviewer` delegation tool bound to its provider. */
|
|
35
38
|
export declare function createLiteratureReviewerTool(deps: LiteratureReviewerDeps): Tool;
|