@inflexa-ai/harness 0.45.0 → 0.46.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/README.md +6 -3
- package/dist/agents/conversation-agent.d.ts +19 -3
- package/dist/agents/conversation-agent.js +49 -30
- package/dist/agents/report-session-agent.d.ts +15 -15
- package/dist/agents/report-session-agent.js +23 -15
- package/dist/agents/sandbox/index.d.ts +1 -1
- package/dist/agents/sandbox/index.js +1 -1
- package/dist/agents/sandbox/shared.d.ts +35 -16
- package/dist/agents/sandbox/shared.js +63 -24
- package/dist/agents/sandbox/translational-safety-agent.js +26 -0
- package/dist/agents/sandbox/types.d.ts +26 -3
- package/dist/agents/sandbox/validate-skills.d.ts +2 -2
- package/dist/agents/sandbox/validate-skills.js +3 -1
- package/dist/agents/sandbox-catalog.d.ts +16 -2
- package/dist/agents/sandbox-catalog.js +22 -3
- package/dist/agents/system-prompt.d.ts +2 -2
- package/dist/app/approve-plan.d.ts +5 -2
- package/dist/app/approve-plan.js +1 -1
- package/dist/app/chat-turn-workflow.d.ts +114 -0
- package/dist/app/chat-turn-workflow.js +307 -0
- package/dist/app/chat-turn.d.ts +85 -57
- package/dist/app/chat-turn.js +125 -99
- package/dist/app/data-profile-orientation.js +10 -8
- package/dist/app/data-profile-view.d.ts +4 -4
- package/dist/app/data-profile-view.js +9 -8
- package/dist/app/in-process-turn.d.ts +42 -0
- package/dist/app/in-process-turn.js +139 -0
- package/dist/app/message-assembly.d.ts +10 -4
- package/dist/app/message-assembly.js +13 -8
- package/dist/app/report-session-runtime.d.ts +4 -4
- package/dist/app/report-session-runtime.js +36 -21
- package/dist/app/spawn-report-session.d.ts +33 -28
- package/dist/app/spawn-report-session.js +25 -40
- package/dist/app/synthesize-run.d.ts +22 -16
- package/dist/app/synthesize-run.js +41 -35
- package/dist/app/work.d.ts +96 -0
- package/dist/app/work.js +147 -0
- package/dist/auth/local-auth-context.d.ts +1 -3
- package/dist/auth/local-auth-context.js +1 -3
- package/dist/auth/local-run-authorizer.d.ts +1 -1
- package/dist/auth/local-run-authorizer.js +5 -3
- package/dist/auth/types.d.ts +26 -26
- package/dist/billing/cached-resolver.d.ts +4 -4
- package/dist/billing/run-charge.d.ts +5 -8
- package/dist/billing/run-charge.js +2 -2
- package/dist/billing/usage-recorder.d.ts +9 -9
- package/dist/citations/aggregate.js +1 -1
- package/dist/citations/clients/arxiv.d.ts +2 -2
- package/dist/citations/clients/arxiv.js +12 -4
- package/dist/citations/clients/common.js +4 -2
- package/dist/citations/clients/crossref.d.ts +2 -2
- package/dist/citations/clients/crossref.js +37 -37
- package/dist/citations/clients/doi-registry.js +15 -16
- package/dist/citations/clients/pubmed.d.ts +2 -2
- package/dist/citations/clients/pubmed.js +20 -13
- package/dist/citations/clients/semantic-scholar.d.ts +2 -2
- package/dist/citations/clients/semantic-scholar.js +9 -9
- package/dist/citations/compare.js +2 -2
- package/dist/citations/match.d.ts +2 -2
- package/dist/citations/match.js +12 -7
- package/dist/citations/normalize.js +35 -26
- package/dist/citations/plan.js +6 -2
- package/dist/citations/resolve.d.ts +6 -6
- package/dist/citations/resolve.js +34 -25
- package/dist/citations/types.d.ts +77 -77
- package/dist/config/environment-stores.d.ts +10 -8
- package/dist/config/resource-limits.js +1 -3
- package/dist/contracts/analogy-report.d.ts +7 -7
- package/dist/contracts/analogy-report.js +2 -2
- package/dist/contracts/chat-events.d.ts +46 -22
- package/dist/contracts/chat-events.js +1 -1
- package/dist/contracts/chat-frame.d.ts +15 -5
- package/dist/contracts/chat-frame.js +67 -40
- package/dist/contracts/chat-parts.d.ts +130 -67
- package/dist/contracts/chat-parts.js +1 -0
- package/dist/contracts/content-url.js +16 -2
- package/dist/contracts/data-profile.d.ts +38 -38
- package/dist/contracts/index.d.ts +3 -3
- package/dist/contracts/index.js +1 -1
- package/dist/contracts/message.d.ts +6 -6
- package/dist/contracts/organ-system.d.ts +11 -11
- package/dist/contracts/part-registry.d.ts +5 -4
- package/dist/contracts/part-registry.js +5 -0
- package/dist/contracts/profile-vocabulary.d.ts +11 -10
- package/dist/contracts/profile-vocabulary.js +10 -3
- package/dist/contracts/report-blocks.d.ts +329 -329
- package/dist/contracts/report-reference.d.ts +105 -81
- package/dist/contracts/report-reference.js +30 -13
- package/dist/contracts/schemas/chat-events.d.ts +45 -6
- package/dist/contracts/schemas/chat-events.js +16 -0
- package/dist/contracts/schemas/chat-parts.d.ts +214 -102
- package/dist/contracts/schemas/chat-parts.js +50 -7
- package/dist/contracts/schemas/index.d.ts +1 -1
- package/dist/contracts/schemas/index.js +1 -1
- package/dist/contracts/severity.d.ts +1 -1
- package/dist/contracts/structure-source.d.ts +3 -3
- package/dist/contracts/structure-source.js +6 -2
- package/dist/contracts/subagent-activity.d.ts +2 -2
- package/dist/contracts/subagent-activity.js +5 -3
- package/dist/contracts/usage.d.ts +2 -2
- package/dist/data/safety-panel-schema.d.ts +25 -25
- package/dist/data/safety-panel-schema.js +13 -4
- package/dist/execution/artifact-metadata.d.ts +23 -15
- package/dist/execution/artifact-metadata.js +33 -10
- package/dist/execution/artifact-record.d.ts +2 -2
- package/dist/execution/artifact-registration.d.ts +5 -5
- package/dist/execution/artifact-registry.d.ts +8 -8
- package/dist/execution/dbos-run-launcher.d.ts +24 -4
- package/dist/execution/dbos-run-launcher.js +58 -4
- package/dist/execution/dbos-workflow-purger.d.ts +7 -6
- package/dist/execution/dbos-workflow-purger.js +29 -21
- package/dist/execution/input-signature.d.ts +2 -2
- package/dist/execution/post-step-pipeline.d.ts +9 -9
- package/dist/execution/post-step-pipeline.js +1 -1
- package/dist/execution/post-step.js +2 -2
- package/dist/execution/reconcile-manifest.d.ts +4 -4
- package/dist/execution/reconcile-manifest.js +3 -2
- package/dist/execution/run-authorizer.d.ts +46 -37
- package/dist/execution/run-authorizer.js +8 -8
- package/dist/execution/run-canceler.d.ts +39 -17
- package/dist/execution/run-canceler.js +137 -28
- package/dist/execution/run-end-record.d.ts +29 -0
- package/dist/execution/run-end-record.js +27 -0
- package/dist/execution/run-event-parts.d.ts +0 -8
- package/dist/execution/run-event-parts.js +29 -24
- package/dist/execution/run-event-stream.d.ts +8 -8
- package/dist/execution/run-event-stream.js +3 -4
- package/dist/execution/run-launcher.d.ts +4 -4
- package/dist/execution/run-synthesis.d.ts +49 -48
- package/dist/execution/run-synthesis.js +96 -255
- package/dist/execution/staged-input.d.ts +2 -2
- package/dist/execution/step-summary.d.ts +6 -6
- package/dist/execution/step-summary.js +4 -8
- package/dist/execution/topo-sort.js +4 -3
- package/dist/execution/workflow-purger.d.ts +2 -2
- package/dist/index.d.ts +25 -24
- package/dist/index.js +36 -37
- package/dist/input-sanitization.js +9 -2
- package/dist/input-scan/clustering.d.ts +6 -6
- package/dist/input-scan/clustering.js +11 -5
- package/dist/input-scan/companions.js +3 -2
- package/dist/input-scan/detect-sets.d.ts +2 -2
- package/dist/input-scan/detect-sets.js +25 -21
- package/dist/input-scan/enrich.d.ts +6 -6
- package/dist/input-scan/enrich.js +29 -12
- package/dist/input-scan/formats.d.ts +2 -2
- package/dist/input-scan/formats.js +8 -2
- package/dist/input-scan/markers.d.ts +2 -2
- package/dist/input-scan/markers.js +14 -5
- package/dist/input-scan/menu.d.ts +10 -10
- package/dist/input-scan/menu.js +0 -0
- package/dist/input-scan/quarantine.d.ts +2 -2
- package/dist/input-scan/quarantine.js +23 -18
- package/dist/input-scan/readout-budget.d.ts +2 -2
- package/dist/input-scan/readout-budget.js +1 -1
- package/dist/input-scan/readout.d.ts +2 -2
- package/dist/input-scan/readout.js +47 -34
- package/dist/input-scan/scan.d.ts +2 -2
- package/dist/input-scan/scan.js +7 -5
- package/dist/input-scan/set-types.d.ts +28 -28
- package/dist/input-scan/shapes.d.ts +4 -4
- package/dist/input-scan/shapes.js +0 -0
- package/dist/input-scan/templates.d.ts +10 -10
- package/dist/input-scan/templates.js +30 -22
- package/dist/input-scan/tokens.d.ts +6 -4
- package/dist/input-scan/tokens.js +100 -38
- package/dist/input-scan/types.d.ts +22 -22
- package/dist/lib/async-utils.d.ts +3 -7
- package/dist/lib/async-utils.js +5 -9
- package/dist/lib/cache.js +1 -1
- package/dist/lib/chrome.d.ts +46 -6
- package/dist/lib/console-logger.js +2 -2
- package/dist/lib/db-result.d.ts +22 -6
- package/dist/lib/db-result.js +9 -13
- package/dist/lib/eyes.d.ts +4 -4
- package/dist/lib/eyes.js +1 -1
- package/dist/lib/fs-helpers.js +18 -6
- package/dist/lib/fs-result.d.ts +1 -0
- package/dist/lib/fs-result.js +5 -6
- package/dist/lib/hooks.d.ts +23 -7
- package/dist/lib/hooks.js +17 -3
- package/dist/lib/host-concurrency.js +3 -2
- package/dist/lib/logger.d.ts +2 -2
- package/dist/lib/logger.js +2 -1
- package/dist/lib/metrics.d.ts +1 -1
- package/dist/lib/null-proto.d.ts +6 -0
- package/dist/lib/null-proto.js +17 -0
- package/dist/lib/otel-spans.d.ts +1 -1
- package/dist/lib/otel-spans.js +9 -5
- package/dist/lib/otel.d.ts +4 -2
- package/dist/lib/otel.js +10 -2
- package/dist/lib/page-capture.d.ts +8 -8
- package/dist/lib/page-capture.js +9 -4
- package/dist/lib/parse-json.d.ts +5 -0
- package/dist/lib/parse-json.js +12 -0
- package/dist/lib/present.d.ts +12 -0
- package/dist/lib/present.js +39 -0
- package/dist/lib/rate-limit.d.ts +4 -4
- package/dist/lib/rate-limit.js +12 -13
- package/dist/lib/regulatory-corpus/fetch-fda-guidance.d.ts +4 -4
- package/dist/lib/regulatory-corpus/fetch-fda-guidance.js +4 -10
- package/dist/lib/regulatory-corpus/fetch-ich.d.ts +4 -4
- package/dist/lib/regulatory-corpus/fetch-ich.js +18 -14
- package/dist/lib/regulatory-corpus/normalize-whitespace.d.ts +6 -0
- package/dist/lib/regulatory-corpus/normalize-whitespace.js +41 -0
- package/dist/lib/regulatory-corpus.d.ts +10 -10
- package/dist/lib/regulatory-corpus.js +3 -1
- package/dist/lib/result.d.ts +10 -11
- package/dist/lib/result.js +15 -13
- package/dist/lib/storage.d.ts +2 -2
- package/dist/lib/test/async-iterable.d.ts +9 -0
- package/dist/lib/test/async-iterable.js +28 -0
- package/dist/lib/test/request-url.d.ts +5 -0
- package/dist/lib/test/request-url.js +7 -0
- package/dist/lib/test/result-assert.d.ts +12 -0
- package/dist/lib/test/result-assert.js +17 -0
- package/dist/lib/test/text-shapes.d.ts +24 -0
- package/dist/lib/test/text-shapes.js +63 -0
- package/dist/lib/text.d.ts +22 -0
- package/dist/lib/text.js +68 -0
- package/dist/lib/thrown.d.ts +18 -0
- package/dist/lib/thrown.js +30 -0
- package/dist/lib/unknown-array.d.ts +6 -0
- package/dist/lib/unknown-array.js +8 -0
- package/dist/lib/unknown-containers.d.ts +14 -0
- package/dist/lib/unknown-containers.js +17 -0
- package/dist/lib/unknown-text.d.ts +8 -0
- package/dist/lib/unknown-text.js +28 -0
- package/dist/lib/zod-issue-shape.d.ts +1 -1
- package/dist/lib/zod-issue-shape.js +31 -31
- package/dist/lib/zod-issues.d.ts +3 -3
- package/dist/lib/zod-issues.js +30 -17
- package/dist/literature/sources/arxiv.d.ts +6 -6
- package/dist/literature/sources/arxiv.js +92 -35
- package/dist/literature/sources/http.d.ts +2 -2
- package/dist/literature/sources/http.js +16 -15
- package/dist/literature/sources/pubmed.d.ts +16 -16
- package/dist/literature/sources/pubmed.js +96 -61
- package/dist/literature/sources/semantic-scholar.d.ts +8 -8
- package/dist/literature/sources/semantic-scholar.js +22 -13
- package/dist/loop/accounting.d.ts +63 -0
- package/dist/loop/accounting.js +141 -0
- package/dist/loop/call-policy.d.ts +73 -0
- package/dist/loop/call-policy.js +109 -0
- package/dist/loop/chat-stream.d.ts +62 -0
- package/dist/loop/chat-stream.js +237 -0
- package/dist/loop/compaction.d.ts +14 -9
- package/dist/loop/compaction.js +17 -0
- package/dist/loop/metrics.d.ts +12 -15
- package/dist/loop/metrics.js +14 -26
- package/dist/loop/run-loop.d.ts +233 -0
- package/dist/loop/run-loop.js +770 -0
- package/dist/loop/sub-agent.d.ts +61 -0
- package/dist/loop/sub-agent.js +161 -0
- package/dist/loop/tool-adapter.d.ts +98 -0
- package/dist/loop/tool-adapter.js +364 -0
- package/dist/loop/tool-detail.d.ts +1 -1
- package/dist/loop/tool-detail.js +6 -5
- package/dist/loop/tool-outcome.d.ts +1 -1
- package/dist/loop/tool-output.d.ts +4 -4
- package/dist/loop/tool-output.js +2 -2
- package/dist/loop/turn-credentials.d.ts +34 -0
- package/dist/loop/turn-credentials.js +73 -0
- package/dist/loop/types.d.ts +34 -37
- package/dist/loop/types.js +2 -7
- package/dist/memory/ai-sdk-message-storage.d.ts +5 -5
- package/dist/memory/ai-sdk-message-storage.js +13 -11
- package/dist/memory/card-builders.d.ts +14 -14
- package/dist/memory/card-builders.js +19 -15
- package/dist/memory/conversation-display-recorder.d.ts +22 -6
- package/dist/memory/conversation-display-recorder.js +64 -20
- package/dist/memory/conversation-display-replay.js +3 -2
- package/dist/memory/conversation-display-storage.d.ts +15 -7
- package/dist/memory/conversation-display-storage.js +141 -36
- package/dist/memory/conversation-view.d.ts +4 -4
- package/dist/memory/conversation-view.js +5 -4
- package/dist/memory/count-tokens.js +10 -8
- package/dist/memory/derive-thread-title.d.ts +0 -13
- package/dist/memory/derive-thread-title.js +2 -1
- package/dist/memory/message-backfill.d.ts +12 -5
- package/dist/memory/message-backfill.js +5 -3
- package/dist/memory/thread-history.d.ts +66 -24
- package/dist/memory/thread-history.js +212 -79
- package/dist/memory/thread-store.d.ts +26 -17
- package/dist/memory/thread-store.js +15 -9
- package/dist/memory/tool-call-integrity.d.ts +2 -2
- package/dist/memory/tool-call-integrity.js +4 -3
- package/dist/memory/working-memory.d.ts +16 -12
- package/dist/memory/working-memory.js +72 -61
- package/dist/prompts/briefing.d.ts +63 -9
- package/dist/prompts/briefing.js +130 -3
- package/dist/prompts/planner.js +13 -2
- package/dist/prompts/synthesis-agent.d.ts +1 -1
- package/dist/prompts/synthesis-agent.js +6 -14
- package/dist/provenance/collector.d.ts +6 -6
- package/dist/provenance/collector.js +15 -8
- package/dist/provenance/exec-frame.d.ts +2 -2
- package/dist/provenance/exec-frame.js +6 -1
- package/dist/provenance/seam.d.ts +24 -19
- package/dist/provenance/seam.js +7 -5
- package/dist/provenance/types.d.ts +6 -6
- package/dist/providers/ai-sdk.d.ts +113 -62
- package/dist/providers/ai-sdk.js +303 -458
- package/dist/providers/embedding.d.ts +2 -2
- package/dist/providers/embedding.js +1 -1
- package/dist/providers/errors.d.ts +22 -2
- package/dist/providers/errors.js +98 -50
- package/dist/providers/prompt-cache.d.ts +8 -8
- package/dist/providers/prompt-cache.js +13 -11
- package/dist/providers/reasoning.d.ts +2 -2
- package/dist/providers/reasoning.js +2 -2
- package/dist/providers/types.d.ts +59 -92
- package/dist/reference-data/catalog.d.ts +2 -15
- package/dist/reference-data/catalog.js +166 -10
- package/dist/reference-data/receipt.d.ts +2 -2
- package/dist/report-model/assert-rules.js +1 -1
- package/dist/report-model/authoring-grammar.d.ts +209 -231
- package/dist/report-model/block-walk.d.ts +10 -10
- package/dist/report-model/block-walk.js +2 -0
- package/dist/report-model/draft-finish.d.ts +8 -8
- package/dist/report-model/draft-finish.js +1 -1
- package/dist/report-model/draft-hash.js +8 -7
- package/dist/report-model/draft-operations.d.ts +22 -10
- package/dist/report-model/draft-operations.js +48 -30
- package/dist/report-model/draft-read.d.ts +19 -7
- package/dist/report-model/draft-read.js +16 -6
- package/dist/report-model/draft.d.ts +844 -2
- package/dist/report-model/draft.js +3 -1
- package/dist/report-model/fixture-resolver.js +39 -16
- package/dist/report-model/pin-snapshot.d.ts +2 -2
- package/dist/report-model/pin-snapshot.js +15 -15
- package/dist/report-model/production-resolver.d.ts +18 -18
- package/dist/report-model/production-resolver.js +50 -42
- package/dist/report-model/reference-resolver.d.ts +26 -10
- package/dist/report-model/reference-resolver.js +68 -5
- package/dist/report-model/reference-stamp.js +30 -38
- package/dist/report-model/structural-validation.js +12 -4
- package/dist/report-model/validate.d.ts +7 -7
- package/dist/report-model/validate.js +6 -6
- package/dist/report-render/assets.d.ts +2 -2
- package/dist/report-render/assets.js +27 -3
- package/dist/report-render/chart-export.d.ts +10 -2
- package/dist/report-render/chart-export.js +37 -11
- package/dist/report-render/chart-presets.d.ts +8 -8
- package/dist/report-render/chart-presets.js +3 -3
- package/dist/report-render/chart-renderers.d.ts +23 -16
- package/dist/report-render/chart-renderers.js +74 -53
- package/dist/report-render/chart-toolbox.d.ts +2 -2
- package/dist/report-render/chart-toolbox.js +7 -6
- package/dist/report-render/chart.d.ts +15 -16
- package/dist/report-render/chart.js +369 -252
- package/dist/report-render/design.d.ts +36 -297
- package/dist/report-render/design.js +0 -12
- package/dist/report-render/figures/common.d.ts +12 -12
- package/dist/report-render/figures/common.js +42 -31
- package/dist/report-render/figures/dendrogram.d.ts +3 -3
- package/dist/report-render/figures/dendrogram.js +10 -10
- package/dist/report-render/figures/dense.js +15 -8
- package/dist/report-render/figures/dotplot.js +46 -33
- package/dist/report-render/figures/embedding.js +52 -43
- package/dist/report-render/figures/equal-units.d.ts +10 -10
- package/dist/report-render/figures/equal-units.js +27 -27
- package/dist/report-render/figures/forest.js +9 -7
- package/dist/report-render/figures/gsea.js +21 -11
- package/dist/report-render/figures/heatmap.js +13 -9
- package/dist/report-render/figures/index.d.ts +10 -10
- package/dist/report-render/figures/index.js +4 -2
- package/dist/report-render/figures/km.js +10 -9
- package/dist/report-render/figures/label-room.d.ts +12 -12
- package/dist/report-render/figures/label-room.js +7 -2
- package/dist/report-render/figures/locuszoom.d.ts +2 -2
- package/dist/report-render/figures/locuszoom.js +59 -31
- package/dist/report-render/figures/lollipop.js +3 -2
- package/dist/report-render/figures/ma.js +8 -4
- package/dist/report-render/figures/manhattan.d.ts +1 -2
- package/dist/report-render/figures/manhattan.js +52 -34
- package/dist/report-render/figures/oncoprint.js +4 -5
- package/dist/report-render/figures/pca.js +25 -11
- package/dist/report-render/figures/qq.js +20 -9
- package/dist/report-render/figures/roc.js +1 -1
- package/dist/report-render/figures/sankey.d.ts +2 -2
- package/dist/report-render/figures/sankey.js +11 -10
- package/dist/report-render/figures/upset.d.ts +6 -6
- package/dist/report-render/figures/upset.js +7 -4
- package/dist/report-render/figures/volcano.js +12 -10
- package/dist/report-render/hybrid-svg.d.ts +4 -4
- package/dist/report-render/hybrid-svg.js +7 -5
- package/dist/report-render/number-format.d.ts +4 -4
- package/dist/report-render/number-format.js +62 -27
- package/dist/report-render/page.js +2 -1
- package/dist/report-render/provenance-data.d.ts +2 -2
- package/dist/report-render/references.d.ts +4 -4
- package/dist/report-render/render.d.ts +2 -2
- package/dist/report-render/render.js +10 -11
- package/dist/report-render/script-json.js +1 -1
- package/dist/report-render/table-data.d.ts +6 -6
- package/dist/report-render/test/options.d.ts +49 -0
- package/dist/report-render/test/options.js +143 -0
- package/dist/report-render/test/page-function.d.ts +19 -0
- package/dist/report-render/test/page-function.js +33 -0
- package/dist/report-render/types.d.ts +10 -10
- package/dist/report-render/value-bridge.d.ts +4 -4
- package/dist/report-render/value-bridge.js +27 -14
- package/dist/report-render/views/chart-view.d.ts +2 -2
- package/dist/report-render/views/chart-view.js +2 -2
- package/dist/report-render/views/lineage.d.ts +6 -6
- package/dist/report-render/views/lineage.js +2 -0
- package/dist/report-render/views/page-view.d.ts +2 -2
- package/dist/report-render/views/page-view.js +1 -0
- package/dist/report-render/views/prose.js +25 -8
- package/dist/report-render/views/references-view.js +12 -1
- package/dist/report-render/views/values.js +1 -1
- package/dist/runtime/assemble.d.ts +53 -26
- package/dist/runtime/assemble.js +103 -56
- package/dist/runtime/boot.d.ts +8 -7
- package/dist/runtime/boot.js +1 -1
- package/dist/runtime/connection-budget.d.ts +6 -6
- package/dist/runtime/connection-budget.js +1 -1
- package/dist/runtime/dbos.d.ts +29 -19
- package/dist/runtime/dbos.js +35 -20
- package/dist/runtime/result-serialization.js +18 -5
- package/dist/runtime/shutdown.d.ts +2 -2
- package/dist/sandbox/client.d.ts +7 -3
- package/dist/sandbox/cpu-files.d.ts +2 -2
- package/dist/sandbox/cpu-files.js +21 -4
- package/dist/sandbox/create-sandbox.d.ts +7 -8
- package/dist/sandbox/create-sandbox.js +6 -12
- package/dist/sandbox/docker-client.d.ts +48 -3
- package/dist/sandbox/docker-client.js +10 -6
- package/dist/sandbox/estimate-data-profile-resources.js +2 -7
- package/dist/sandbox/exec-outcome.d.ts +2 -2
- package/dist/sandbox/exec-outcome.js +1 -1
- package/dist/sandbox/exec.d.ts +10 -6
- package/dist/sandbox/exec.js +27 -12
- package/dist/sandbox/execution-id.js +14 -6
- package/dist/sandbox/farm.d.ts +2 -2
- package/dist/sandbox/farm.js +22 -27
- package/dist/sandbox/identity.d.ts +7 -0
- package/dist/sandbox/identity.js +14 -3
- package/dist/sandbox/image-packages.d.ts +26 -4
- package/dist/sandbox/image-packages.js +29 -27
- package/dist/sandbox/k8s-client.d.ts +35 -8
- package/dist/sandbox/k8s-client.js +6 -5
- package/dist/sandbox/labels.js +1 -0
- package/dist/sandbox/liveness.js +3 -1
- package/dist/sandbox/mount-plan.d.ts +10 -10
- package/dist/sandbox/mount-plan.js +13 -14
- package/dist/sandbox/notification-sweep.d.ts +4 -4
- package/dist/sandbox/notification-sweep.js +4 -7
- package/dist/sandbox/package-identity.d.ts +6 -13
- package/dist/sandbox/package-identity.js +46 -28
- package/dist/sandbox/reaper.d.ts +10 -10
- package/dist/sandbox/reaper.js +4 -6
- package/dist/sandbox/sandbox-error.d.ts +2 -9
- package/dist/sandbox/sandbox-error.js +21 -8
- package/dist/sandbox/sandbox-step-translate.d.ts +8 -5
- package/dist/sandbox/sandbox-step-translate.js +22 -8
- package/dist/sandbox/step-sandbox.d.ts +47 -0
- package/dist/sandbox/step-sandbox.js +53 -0
- package/dist/sandbox/types.d.ts +18 -19
- package/dist/sandbox/types.js +1 -1
- package/dist/schemas/artifact-manifest.d.ts +4 -4
- package/dist/schemas/data-profile-schemas.d.ts +351 -306
- package/dist/schemas/file-metadata.js +2 -4
- package/dist/schemas/plan-schemas.d.ts +79 -25
- package/dist/schemas/plan-schemas.js +1 -1
- package/dist/schemas/run-synthesis.d.ts +95 -26
- package/dist/schemas/run-synthesis.js +3 -1
- package/dist/schemas/validate-plan.d.ts +4 -4
- package/dist/schemas/validate-plan.js +17 -5
- package/dist/schemas/workflow-state.d.ts +127 -14
- package/dist/schemas/workflow-state.js +56 -2
- package/dist/state/active-turns.d.ts +36 -0
- package/dist/state/active-turns.js +67 -0
- package/dist/state/analyses-metrics.d.ts +8 -8
- package/dist/state/analyses-metrics.js +4 -4
- package/dist/state/analyses.d.ts +0 -14
- package/dist/state/analyses.js +0 -32
- package/dist/state/artifacts.d.ts +47 -18
- package/dist/state/artifacts.js +48 -7
- package/dist/state/data-profile.d.ts +2 -2
- package/dist/state/db.d.ts +12 -2
- package/dist/state/db.js +5 -0
- package/dist/state/edit-intents.d.ts +4 -0
- package/dist/state/edit-intents.js +71 -0
- package/dist/state/index.d.ts +5 -5
- package/dist/state/index.js +3 -3
- package/dist/state/init.d.ts +2 -1
- package/dist/state/init.js +5 -2
- package/dist/state/migrations/20260927120000_baseline.js +3 -1
- package/dist/state/migrations/20261026120000_add_the_edit_intents.d.ts +7 -0
- package/dist/state/migrations/20261026120000_add_the_edit_intents.js +21 -0
- package/dist/state/migrations/20261027120000_record_the_applied_memory_edits.d.ts +7 -0
- package/dist/state/migrations/20261027120000_record_the_applied_memory_edits.js +16 -0
- package/dist/state/migrations/20261027120100_store_the_authoring_results.d.ts +8 -0
- package/dist/state/migrations/20261027120100_store_the_authoring_results.js +20 -0
- package/dist/state/migrations/20261027120200_key_the_groups_of_a_turn.d.ts +7 -0
- package/dist/state/migrations/20261027120200_key_the_groups_of_a_turn.js +12 -0
- package/dist/state/migrations/20261027120300_mark_the_active_turn_of_a_thread.d.ts +7 -0
- package/dist/state/migrations/20261027120300_mark_the_active_turn_of_a_thread.js +11 -0
- package/dist/state/migrations/20261028120000_record_the_paused_work.d.ts +7 -0
- package/dist/state/migrations/20261028120000_record_the_paused_work.js +25 -0
- package/dist/state/migrations/20261028120100_end_the_suspended_runs.d.ts +8 -0
- package/dist/state/migrations/20261028120100_end_the_suspended_runs.js +13 -0
- package/dist/state/migrations/20261029120000_reference_the_run_mandate.d.ts +7 -0
- package/dist/state/migrations/20261029120000_reference_the_run_mandate.js +23 -0
- package/dist/state/migrations/20261029120100_record_the_run_session_of_a_pause.d.ts +7 -0
- package/dist/state/migrations/20261029120100_record_the_run_session_of_a_pause.js +11 -0
- package/dist/state/migrations/index.js +18 -0
- package/dist/state/paused-work.d.ts +52 -0
- package/dist/state/paused-work.js +105 -0
- package/dist/state/plans.d.ts +27 -8
- package/dist/state/plans.js +14 -11
- package/dist/state/purge-analysis.d.ts +6 -6
- package/dist/state/purge-analysis.js +10 -2
- package/dist/state/report-session-state.d.ts +43 -18
- package/dist/state/report-session-state.js +43 -4
- package/dist/state/report-versions.d.ts +16 -11
- package/dist/state/report-versions.js +5 -3
- package/dist/state/runs.d.ts +70 -25
- package/dist/state/runs.js +127 -64
- package/dist/state/schema.d.ts +18 -21
- package/dist/state/schema.js +4 -5
- package/dist/state/snapshot-parse.d.ts +2 -2
- package/dist/state/snapshot-parse.js +14 -8
- package/dist/state/step-executions.d.ts +29 -8
- package/dist/state/step-executions.js +28 -4
- package/dist/state/tool-outputs.d.ts +2 -2
- package/dist/state/tool-outputs.js +2 -1
- package/dist/state/vector-store.d.ts +16 -16
- package/dist/state/vector-store.js +11 -7
- package/dist/tasks/data-profile-absorb.d.ts +3 -3
- package/dist/tasks/data-profile-absorb.js +21 -16
- package/dist/tasks/data-profile-activity.d.ts +5 -5
- package/dist/tasks/data-profile-activity.js +5 -5
- package/dist/tasks/data-profile-index.d.ts +4 -4
- package/dist/tasks/data-profile-index.js +32 -17
- package/dist/tasks/data-profile-resolve.d.ts +8 -8
- package/dist/tasks/data-profile-resolve.js +88 -62
- package/dist/tasks/data-profile.d.ts +40 -31
- package/dist/tasks/data-profile.js +138 -95
- package/dist/tasks/extract-values.d.ts +26 -79
- package/dist/tasks/extract-values.js +48 -108
- package/dist/tasks/refresh-regulatory-corpus.d.ts +4 -20
- package/dist/tasks/refresh-regulatory-corpus.js +12 -8
- package/dist/tasks/regulatory-corpus-boot-refresh.d.ts +2 -2
- package/dist/tasks/regulatory-corpus-boot-refresh.js +12 -10
- package/dist/testing.d.ts +60 -0
- package/dist/testing.js +96 -0
- package/dist/tools/ad-hoc-router.d.ts +11 -9
- package/dist/tools/ad-hoc-router.js +80 -51
- package/dist/tools/analysis-invocation.d.ts +7 -0
- package/dist/tools/analysis-invocation.js +29 -5
- package/dist/tools/approval/contract.d.ts +8 -52
- package/dist/tools/approval/contract.js +7 -36
- package/dist/tools/approval/gateway.d.ts +27 -28
- package/dist/tools/approval/gateway.js +33 -130
- package/dist/tools/approval/queries.d.ts +6 -11
- package/dist/tools/approval/queries.js +43 -29
- package/dist/tools/approval/uuidv7.js +2 -2
- package/dist/tools/bio/chembl.d.ts +3 -3
- package/dist/tools/bio/chembl.js +10 -0
- package/dist/tools/bio/comptox.d.ts +25 -8
- package/dist/tools/bio/comptox.js +4 -2
- package/dist/tools/bio/drug-gene-interactions.d.ts +27 -17
- package/dist/tools/bio/drug-gene-interactions.js +11 -8
- package/dist/tools/bio/gene-disease-evidence.d.ts +61 -15
- package/dist/tools/bio/gene-disease-evidence.js +10 -6
- package/dist/tools/bio/gene-preclinical-profile.d.ts +11 -11
- package/dist/tools/bio/keys.d.ts +2 -2
- package/dist/tools/bio/keys.js +3 -3
- package/dist/tools/bio/lookup-annotation.d.ts +5 -5
- package/dist/tools/bio/lookup-annotation.js +3 -0
- package/dist/tools/bio/opentargets.d.ts +1 -1
- package/dist/tools/bio/opentargets.js +6 -0
- package/dist/tools/bio/pubchem.d.ts +2 -2
- package/dist/tools/bio/pubchem.js +6 -0
- package/dist/tools/bio/pubmed.d.ts +26 -16
- package/dist/tools/bio/pubmed.js +9 -3
- package/dist/tools/bio/search-clinical-trials.d.ts +4 -4
- package/dist/tools/bio/search-clinical-trials.js +5 -1
- package/dist/tools/bio/search-faers.d.ts +2 -2
- package/dist/tools/bio/search-faers.js +1 -1
- package/dist/tools/bio/search-gene.d.ts +2 -2
- package/dist/tools/bio/search-gene.js +1 -0
- package/dist/tools/bio/search-geo-datasets.d.ts +4 -4
- package/dist/tools/bio/search-geo-datasets.js +5 -5
- package/dist/tools/bio/search-interactions.d.ts +1 -1
- package/dist/tools/bio/search-patents.d.ts +28 -22
- package/dist/tools/bio/search-patents.js +20 -17
- package/dist/tools/bio/search-protein.d.ts +2 -2
- package/dist/tools/bio/search-protein.js +1 -1
- package/dist/tools/bio/search-regulatory-approvals.d.ts +64 -18
- package/dist/tools/bio/search-regulatory-approvals.js +21 -16
- package/dist/tools/bio/target-safety.d.ts +8 -8
- package/dist/tools/bio/target-safety.js +11 -6
- package/dist/tools/capability-data.d.ts +40 -0
- package/dist/tools/capability-data.js +74 -0
- package/dist/tools/define-tool.d.ts +55 -46
- package/dist/tools/define-tool.js +39 -27
- package/dist/tools/display/normalize-echart-spec.d.ts +2 -2
- package/dist/tools/display/normalize-echart-spec.js +51 -27
- package/dist/tools/display/show-user.d.ts +2 -2
- package/dist/tools/display/show-user.js +1 -1
- package/dist/tools/execute-analysis.d.ts +54 -17
- package/dist/tools/execute-analysis.js +193 -62
- package/dist/tools/knowledge/check.d.ts +182 -0
- package/dist/tools/knowledge/check.js +94 -0
- package/dist/tools/knowledge/client.d.ts +351 -0
- package/dist/tools/knowledge/client.js +319 -0
- package/dist/tools/knowledge/environment.d.ts +78 -0
- package/dist/tools/knowledge/environment.js +116 -0
- package/dist/tools/knowledge/index.d.ts +49 -0
- package/dist/tools/knowledge/index.js +70 -0
- package/dist/tools/knowledge/local-slots.d.ts +62 -0
- package/dist/tools/knowledge/local-slots.js +184 -0
- package/dist/tools/knowledge/pin.d.ts +14 -0
- package/dist/tools/knowledge/pin.js +17 -0
- package/dist/tools/knowledge/recommend.d.ts +67 -0
- package/dist/tools/knowledge/recommend.js +106 -0
- package/dist/tools/knowledge/situation.d.ts +143 -0
- package/dist/tools/knowledge/situation.js +157 -0
- package/dist/tools/knowledge/skeleton.d.ts +69 -0
- package/dist/tools/knowledge/skeleton.js +201 -0
- package/dist/tools/knowledge/template.d.ts +139 -0
- package/dist/tools/knowledge/template.js +273 -0
- package/dist/tools/lib/alphafold-client.js +2 -1
- package/dist/tools/lib/amass-client.d.ts +28 -28
- package/dist/tools/lib/amass-client.js +20 -10
- package/dist/tools/lib/api-utils.d.ts +13 -3
- package/dist/tools/lib/api-utils.js +17 -3
- package/dist/tools/lib/bgee-client.d.ts +6 -6
- package/dist/tools/lib/bgee-client.js +16 -10
- package/dist/tools/lib/cbioportal-client.d.ts +4 -4
- package/dist/tools/lib/cbioportal-client.js +9 -8
- package/dist/tools/lib/chembl-client.d.ts +14 -14
- package/dist/tools/lib/chembl-client.js +11 -4
- package/dist/tools/lib/clinical-benchmarks-client.d.ts +4 -4
- package/dist/tools/lib/clinical-benchmarks-client.js +4 -7
- package/dist/tools/lib/clinical-trials-client.d.ts +18 -18
- package/dist/tools/lib/clinical-trials-client.js +10 -10
- package/dist/tools/lib/clinvar-client.d.ts +2 -2
- package/dist/tools/lib/clinvar-client.js +6 -6
- package/dist/tools/lib/ctx-ops.d.ts +23 -23
- package/dist/tools/lib/ctx-ops.js +13 -10
- package/dist/tools/lib/dgidb-client.d.ts +6 -6
- package/dist/tools/lib/dgidb-client.js +10 -12
- package/dist/tools/lib/disgenet-client.d.ts +4 -4
- package/dist/tools/lib/ema-client.d.ts +2 -2
- package/dist/tools/lib/ensembl-client.d.ts +4 -4
- package/dist/tools/lib/ensembl-client.js +5 -4
- package/dist/tools/lib/gwas-catalog-client.d.ts +4 -4
- package/dist/tools/lib/gwas-catalog-client.js +17 -17
- package/dist/tools/lib/html-text.d.ts +6 -0
- package/dist/tools/lib/html-text.js +9 -0
- package/dist/tools/lib/identifier-resolver.d.ts +4 -4
- package/dist/tools/lib/identifier-resolver.js +7 -3
- package/dist/tools/lib/impc-client.d.ts +8 -8
- package/dist/tools/lib/impc-client.js +46 -35
- package/dist/tools/lib/iuphar-client.d.ts +2 -2
- package/dist/tools/lib/iuphar-client.js +7 -16
- package/dist/tools/lib/monarch-client.d.ts +4 -4
- package/dist/tools/lib/openfda-client.d.ts +22 -22
- package/dist/tools/lib/openfda-client.js +23 -22
- package/dist/tools/lib/opentargets-client.d.ts +12 -12
- package/dist/tools/lib/pathway-client.d.ts +4 -4
- package/dist/tools/lib/pathway-client.js +15 -19
- package/dist/tools/lib/pharmgkb-client.d.ts +2 -2
- package/dist/tools/lib/pharmgkb-client.js +1 -1
- package/dist/tools/lib/protein-family-modality.d.ts +2 -2
- package/dist/tools/lib/protein-family-modality.js +0 -2
- package/dist/tools/lib/protein-family-normalize.js +7 -0
- package/dist/tools/lib/pubchem-client.d.ts +2 -2
- package/dist/tools/lib/pubchem-client.js +1 -0
- package/dist/tools/lib/pubchem-ops.d.ts +4 -4
- package/dist/tools/lib/pubchem-ops.js +8 -0
- package/dist/tools/lib/pubmed-client.d.ts +9 -9
- package/dist/tools/lib/pubmed-client.js +1 -1
- package/dist/tools/lib/string-client.d.ts +6 -6
- package/dist/tools/lib/uniprot-client.d.ts +8 -8
- package/dist/tools/lib/uniprot-client.js +5 -1
- package/dist/tools/memory/update-working-memory.d.ts +16 -13
- package/dist/tools/memory/update-working-memory.js +21 -3
- package/dist/tools/read-tool-output.js +8 -2
- package/dist/tools/registry.d.ts +2 -2
- package/dist/tools/report-authoring/authoring-tools.d.ts +54 -23
- package/dist/tools/report-authoring/authoring-tools.js +128 -62
- package/dist/tools/report-session/derive-table.d.ts +19 -59
- package/dist/tools/report-session/derive-table.js +120 -122
- package/dist/tools/report-session/examine-page.d.ts +6 -6
- package/dist/tools/report-session/examine-page.js +14 -12
- package/dist/tools/report-session/list-artifacts.d.ts +6 -6
- package/dist/tools/report-session/list-artifacts.js +5 -5
- package/dist/tools/report-session/page-faults.d.ts +6 -6
- package/dist/tools/report-session/page-faults.js +3 -1
- package/dist/tools/report-session/preview-report.d.ts +4 -3
- package/dist/tools/report-session/preview-report.js +26 -7
- package/dist/tools/report-session/record-version.d.ts +9 -4
- package/dist/tools/report-session/record-version.js +16 -9
- package/dist/tools/report-session/session-page-publisher.d.ts +6 -6
- package/dist/tools/research/generate-analogy-report.d.ts +14 -7
- package/dist/tools/research/generate-analogy-report.js +80 -76
- package/dist/tools/research/generate-plan.d.ts +39 -16
- package/dist/tools/research/generate-plan.js +565 -338
- package/dist/tools/research/guarded-address.d.ts +20 -0
- package/dist/tools/research/guarded-address.js +149 -0
- package/dist/tools/research/inspect-data-profile.d.ts +27 -20
- package/dist/tools/research/inspect-data-profile.js +26 -25
- package/dist/tools/research/inspect-run.d.ts +54 -27
- package/dist/tools/research/inspect-run.js +50 -40
- package/dist/tools/research/literature-reviewer.d.ts +8 -7
- package/dist/tools/research/literature-reviewer.js +29 -28
- package/dist/tools/research/search-arxiv.d.ts +1 -1
- package/dist/tools/research/search-arxiv.js +1 -1
- package/dist/tools/research/search-github-repos.d.ts +10 -7
- package/dist/tools/research/search-github-repos.js +25 -22
- package/dist/tools/research/search-semantic-scholar.js +1 -1
- package/dist/tools/research/searxng-engine.d.ts +40 -0
- package/dist/tools/research/searxng-engine.js +122 -0
- package/dist/tools/research/web-fetch.d.ts +127 -0
- package/dist/tools/research/web-fetch.js +618 -0
- package/dist/tools/research/web-search.d.ts +84 -0
- package/dist/tools/research/web-search.js +117 -0
- package/dist/tools/sandbox/link-packages.d.ts +11 -7
- package/dist/tools/sandbox/link-packages.js +11 -8
- package/dist/tools/sandbox/list-available-packages.d.ts +24 -12
- package/dist/tools/sandbox/list-available-packages.js +43 -29
- package/dist/tools/sandbox/list-available-refs.d.ts +38 -14
- package/dist/tools/sandbox/list-available-refs.js +119 -37
- package/dist/tools/sandbox/report-blocker.d.ts +30 -37
- package/dist/tools/sandbox/report-blocker.js +22 -68
- package/dist/tools/sandbox/skills.d.ts +16 -12
- package/dist/tools/sandbox/skills.js +16 -12
- package/dist/tools/sandbox/submit-file-metadata.d.ts +12 -9
- package/dist/tools/sandbox/submit-file-metadata.js +18 -21
- package/dist/tools/start-report-session.d.ts +13 -5
- package/dist/tools/start-report-session.js +35 -8
- package/dist/tools/terminal-text.d.ts +14 -0
- package/dist/tools/terminal-text.js +51 -0
- package/dist/tools/workspace/decision-record.d.ts +81 -0
- package/dist/tools/workspace/decision-record.js +127 -0
- package/dist/tools/workspace/edit-file.d.ts +59 -18
- package/dist/tools/workspace/edit-file.js +98 -15
- package/dist/tools/workspace/execute-command.d.ts +31 -12
- package/dist/tools/workspace/execute-command.js +37 -8
- package/dist/tools/workspace/file-stat.d.ts +6 -3
- package/dist/tools/workspace/grep.d.ts +10 -7
- package/dist/tools/workspace/grep.js +9 -3
- package/dist/tools/workspace/index.d.ts +1 -0
- package/dist/tools/workspace/index.js +1 -0
- package/dist/tools/workspace/list-files.d.ts +6 -3
- package/dist/tools/workspace/mutator.d.ts +28 -15
- package/dist/tools/workspace/mutator.js +107 -53
- package/dist/tools/workspace/read-file.d.ts +8 -5
- package/dist/tools/workspace/result-bounds.d.ts +5 -5
- package/dist/tools/workspace/result-bounds.js +4 -2
- package/dist/tools/workspace/run-exec.d.ts +2 -2
- package/dist/tools/workspace/run-exec.js +3 -3
- package/dist/tools/workspace/scan-inputs.d.ts +8 -5
- package/dist/tools/workspace/scan-inputs.js +17 -5
- package/dist/tools/workspace/show-file.d.ts +1 -1
- package/dist/tools/workspace/show-file.js +2 -1
- package/dist/tools/workspace/show-plan.d.ts +8 -5
- package/dist/tools/workspace/show-plan.js +9 -8
- package/dist/tools/workspace/workspace-search.d.ts +41 -13
- package/dist/tools/workspace/workspace-search.js +27 -14
- package/dist/tools/workspace/write-file.d.ts +9 -7
- package/dist/workflows/execute-analysis-scheduler.d.ts +9 -9
- package/dist/workflows/execute-analysis-scheduler.js +6 -3
- package/dist/workflows/execute-analysis.d.ts +100 -76
- package/dist/workflows/execute-analysis.js +380 -247
- package/dist/workflows/pause.d.ts +71 -0
- package/dist/workflows/pause.js +173 -0
- package/dist/workflows/sandbox-step.d.ts +50 -61
- package/dist/workflows/sandbox-step.js +99 -106
- package/dist/workflows/test/sql-writes.d.ts +21 -0
- package/dist/workflows/test/sql-writes.js +36 -0
- package/dist/workspace/filesystem.d.ts +6 -6
- package/dist/workspace/filesystem.js +10 -8
- package/dist/workspace/paths.d.ts +1 -1
- package/dist/workspace/paths.js +15 -4
- package/dist/workspace/search-config.d.ts +2 -2
- package/dist/workspace/search-config.js +1 -1
- package/package.json +25 -22
- package/dist/loop/continue-agent.d.ts +0 -40
- package/dist/loop/continue-agent.js +0 -38
- package/dist/loop/genai-spans.d.ts +0 -47
- package/dist/loop/genai-spans.js +0 -134
- package/dist/loop/run-agent.d.ts +0 -236
- package/dist/loop/run-agent.js +0 -1110
- package/dist/loop/run-step.d.ts +0 -29
- package/dist/loop/run-step.js +0 -34
- package/dist/loop/run-to-terminal.d.ts +0 -66
- package/dist/loop/run-to-terminal.js +0 -90
- package/dist/loop/tool-mask.d.ts +0 -23
- package/dist/loop/tool-mask.js +0 -46
- package/dist/providers/streaming-chat.d.ts +0 -32
- package/dist/providers/streaming-chat.js +0 -91
- package/dist/tasks/derive-table-exec.d.ts +0 -54
- package/dist/tasks/derive-table-exec.js +0 -86
- package/dist/workflows/suspension.d.ts +0 -32
- package/dist/workflows/suspension.js +0 -38
|
@@ -0,0 +1,770 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The agent loop: one conversation of one agent with a model and its tools.
|
|
3
|
+
*
|
|
4
|
+
* The AI SDK drives each request series with `streamText`. Inside a DBOS
|
|
5
|
+
* workflow, `durableCalls` makes each model call a step, and the tool adapter
|
|
6
|
+
* makes each tool call a step, thus a recovery replays each completed call
|
|
7
|
+
* from its checkpoint. Outside a workflow, each call runs directly. The same
|
|
8
|
+
* loop serves a chat turn, a workflow step, and a sub-agent.
|
|
9
|
+
*
|
|
10
|
+
* The loop keeps the transcript itself, and each request sends its view of
|
|
11
|
+
* the transcript. This gives the loop the work that the SDK does not do: the
|
|
12
|
+
* append-only record of each round, the round sink, the compaction, the
|
|
13
|
+
* follow-up request, the salvage, the not-run answer of each unanswered call
|
|
14
|
+
* at an exit, and the finish record.
|
|
15
|
+
*/
|
|
16
|
+
import { randomUUID } from "node:crypto";
|
|
17
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
18
|
+
import { durableCalls } from "@dbos-inc/vercel-ai";
|
|
19
|
+
import { streamText, wrapLanguageModel, } from "ai";
|
|
20
|
+
import { forSubAgent } from "../auth/types.js";
|
|
21
|
+
import { createNoopUsageRecorder } from "../billing/noop-usage-recorder.js";
|
|
22
|
+
import { createNoopLogger } from "../lib/console-logger.js";
|
|
23
|
+
import { toThrowable } from "../lib/result.js";
|
|
24
|
+
import { errorNameOf } from "../lib/thrown.js";
|
|
25
|
+
import { contextRecordOf, markCompactionExchange, markInterruptedMessage, summaryMarkerMessage, syntheticUserMessage, withRequestInputTokens, } from "../memory/ai-sdk-message-storage.js";
|
|
26
|
+
import { conversationView, lastRequestInputTokens, withoutReasoning } from "../memory/conversation-view.js";
|
|
27
|
+
import { answerUnansweredToolCalls } from "../memory/tool-call-integrity.js";
|
|
28
|
+
import { fallbackModelOf } from "../providers/ai-sdk.js";
|
|
29
|
+
import { extractStatus, findProviderError } from "../providers/errors.js";
|
|
30
|
+
import { DEFAULT_PROMPT_CACHE, withPromptCacheBreakpoint, withSystemPromptBreakpoint } from "../providers/prompt-cache.js";
|
|
31
|
+
import { accountingMiddleware, rollupMiddleware } from "./accounting.js";
|
|
32
|
+
import { createCallPolicy } from "./call-policy.js";
|
|
33
|
+
import { COMPACTION_MAX_REQUESTS } from "./compaction.js";
|
|
34
|
+
import { addChatUsage, hasReportedUsage, recordAgentRun } from "./metrics.js";
|
|
35
|
+
import { adaptTools, deniedReason, foldCallRecords, isFatalToolError, modelViewOf, recordedInputOf, ToolCallOutputSchema, } from "./tool-adapter.js";
|
|
36
|
+
import { READ_TOOL_OUTPUT_TOOL_ID } from "./tool-output.js";
|
|
37
|
+
/** The reason of a call that asks for approval in a loop where no surface can answer. */
|
|
38
|
+
const NO_APPROVER_REASON = "This action needs the approval of the user, and no one can answer here. Thus it did not run.";
|
|
39
|
+
/** The harness request after a reply that a failed request cut. The model reads its partial reply, and continues it. */
|
|
40
|
+
export const CONTINUE_REQUEST = "[The model request failed during your reply above. Continue the reply from where it stopped.]";
|
|
41
|
+
/** A run that receives no turn accumulator is the turn's root. See `LoopOptions.turnUsage`. */
|
|
42
|
+
export const isTurnRoot = (opts) => opts.turnUsage === undefined;
|
|
43
|
+
/** The name of the durable step of each model call. It holds no model id, thus a change of the model never breaks a replay. */
|
|
44
|
+
function modelStepName(agentId) {
|
|
45
|
+
return `${agentId}.model`;
|
|
46
|
+
}
|
|
47
|
+
/** Run an agent over `initial` until its reply ends the run. */
|
|
48
|
+
export async function runLoop(agent, initial, session, opts) {
|
|
49
|
+
const conversation = openConversation(agent, initial, session, opts, agent.id);
|
|
50
|
+
return conversation.guard(async () => {
|
|
51
|
+
if (opts.turnInput !== undefined) {
|
|
52
|
+
const ended = await conversation.startTurn(opts.turnInput);
|
|
53
|
+
if (ended !== undefined)
|
|
54
|
+
return ended;
|
|
55
|
+
}
|
|
56
|
+
return conversation.run({ mask: opts.policy?.mask, maxRequests: agent.maxIterations, checksBudget: true });
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Continue a finished conversation with one harness request. `agent` and `opts`
|
|
61
|
+
* must match the conversation's own, since each request extends its cached
|
|
62
|
+
* prefix. `conversation` itself is never changed. The result holds only the new
|
|
63
|
+
* messages, starting with the request.
|
|
64
|
+
*/
|
|
65
|
+
export async function continueLoop(agent, conversation, request, session, opts) {
|
|
66
|
+
const accountingAgentId = request.accountingAgentId;
|
|
67
|
+
const runSession = accountingAgentId === undefined ? session : forSubAgent(session, accountingAgentId);
|
|
68
|
+
const { onRound: _onRound, compaction: _compaction, turnInput: _turnInput, stopWhen: _stopWhen, capWhen: _capWhen, ...followUp } = opts;
|
|
69
|
+
const open = openConversation(agent, conversation, runSession, followUp, accountingAgentId ?? agent.id);
|
|
70
|
+
const result = await open.guard(() => open.run({
|
|
71
|
+
mask: request.mask,
|
|
72
|
+
maxRequests: request.maxRequests,
|
|
73
|
+
requestText: request.text,
|
|
74
|
+
endsOnRequestRefusal: request.endOnRequestRefusal === true,
|
|
75
|
+
}));
|
|
76
|
+
return { ...result, messages: result.messages.slice(conversation.length) };
|
|
77
|
+
}
|
|
78
|
+
/** Default salvage budget: one submit plus a fix of a refused submission or two. */
|
|
79
|
+
export const DEFAULT_SALVAGE_REQUESTS = 3;
|
|
80
|
+
/**
|
|
81
|
+
* Run an agent that has an outcome, and send one salvage request when the run
|
|
82
|
+
* ends with none and was not aborted. The salvage request lets only the
|
|
83
|
+
* terminal tools of the agent run. A salvaged result carries both runs'
|
|
84
|
+
* messages and steps and the summed rollups, with the finish of the salvage.
|
|
85
|
+
*/
|
|
86
|
+
export async function runWithSalvage(agent, initial, session, opts, salvage) {
|
|
87
|
+
const undeclared = salvage.tools.find((id) => !agent.tools.some((tool) => tool.id === id));
|
|
88
|
+
if (undeclared !== undefined) {
|
|
89
|
+
throw new Error(`The terminal tool "${undeclared}" is not a declared tool of the agent "${agent.id}", thus the salvage mask cannot let it run.`);
|
|
90
|
+
}
|
|
91
|
+
const first = await runLoop(agent, initial, session, opts);
|
|
92
|
+
if (salvage.hasOutcome(first.steps) || first.finish.reason === "aborted" || opts.signal.aborted)
|
|
93
|
+
return { ...first, salvage: null };
|
|
94
|
+
const maxRequests = salvage.maxRequests ?? DEFAULT_SALVAGE_REQUESTS;
|
|
95
|
+
(opts.logger ?? createNoopLogger()).named("loop").warn("salvaging a run that ended with no outcome", {
|
|
96
|
+
agentId: agent.id,
|
|
97
|
+
callPath: session.provenance.callPath,
|
|
98
|
+
firstFinishReason: first.finish.reason,
|
|
99
|
+
firstCappedOut: first.finish.cappedOut,
|
|
100
|
+
salvageTools: salvage.tools,
|
|
101
|
+
salvageMaxRequests: maxRequests,
|
|
102
|
+
});
|
|
103
|
+
const salvaged = await continueLoop(agent, first.messages, { text: salvage.nudge, mask: { allow: salvage.tools }, maxRequests }, session, opts);
|
|
104
|
+
return {
|
|
105
|
+
messages: [...first.messages, ...salvaged.messages],
|
|
106
|
+
steps: [...first.steps, ...salvaged.steps],
|
|
107
|
+
finish: {
|
|
108
|
+
...salvaged.finish,
|
|
109
|
+
...sumUsage("usage", first.finish, salvaged.finish),
|
|
110
|
+
...sumUsage("turnUsage", first.finish, salvaged.finish),
|
|
111
|
+
},
|
|
112
|
+
salvage: { firstFinish: first.finish, finish: salvaged.finish },
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function sumUsage(field, first, second) {
|
|
116
|
+
const a = first[field];
|
|
117
|
+
const b = second[field];
|
|
118
|
+
if (a === undefined && b === undefined)
|
|
119
|
+
return {};
|
|
120
|
+
const total = {};
|
|
121
|
+
addChatUsage(total, a);
|
|
122
|
+
addChatUsage(total, b);
|
|
123
|
+
return { [field]: total };
|
|
124
|
+
}
|
|
125
|
+
export function finalText(messages) {
|
|
126
|
+
const last = messages.at(-1);
|
|
127
|
+
if (last === undefined || last.role !== "assistant")
|
|
128
|
+
return "";
|
|
129
|
+
if (typeof last.content === "string")
|
|
130
|
+
return last.content;
|
|
131
|
+
return last.content
|
|
132
|
+
.filter((block) => block.type === "text")
|
|
133
|
+
.map((block) => block.text)
|
|
134
|
+
.join("");
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Open the loop over one conversation. `metricAgentId` is the id that usage
|
|
138
|
+
* and run metrics count under, which is not always `agent.id`.
|
|
139
|
+
*/
|
|
140
|
+
function openConversation(agent, initial, session, opts, metricAgentId) {
|
|
141
|
+
const { provider, emit } = opts;
|
|
142
|
+
if (agent.tools.length > 0 && !provider.capabilities.toolCalling) {
|
|
143
|
+
throw new Error(`Provider/model cannot run tool-required agent "${agent.id}"`);
|
|
144
|
+
}
|
|
145
|
+
const messages = [...initial];
|
|
146
|
+
// The loop never changes a message before `givenCount`, because the sink can hold it already.
|
|
147
|
+
let givenCount = initial.length;
|
|
148
|
+
// Stays true when the sink rejects, thus the throw path does not call the sink again.
|
|
149
|
+
let sinkPending = false;
|
|
150
|
+
const giveRound = async () => {
|
|
151
|
+
if (opts.onRound === undefined || messages.length === givenCount)
|
|
152
|
+
return;
|
|
153
|
+
sinkPending = true;
|
|
154
|
+
await opts.onRound({ messages: messages.slice(givenCount) });
|
|
155
|
+
sinkPending = false;
|
|
156
|
+
givenCount = messages.length;
|
|
157
|
+
};
|
|
158
|
+
const log = (opts.logger ?? createNoopLogger()).named("loop").with({ agentId: session.provenance.agentId, callPath: session.provenance.callPath });
|
|
159
|
+
const policy = opts.compaction;
|
|
160
|
+
const viewOptions = { keepFirstTurn: policy?.keepFirstTurn === true };
|
|
161
|
+
const viewOf = (from) => (policy === undefined ? [...from] : conversationView(from, viewOptions).messages);
|
|
162
|
+
// A run handed no accumulator is the turn's root: it creates the one every
|
|
163
|
+
// descendant loop folds into, and it is the only loop entitled to report a
|
|
164
|
+
// turn total. Descendants receive the root's object and mutate it in place.
|
|
165
|
+
const turnUsage = opts.turnUsage ?? {};
|
|
166
|
+
const turnRoot = isTurnRoot(opts);
|
|
167
|
+
const usage = {};
|
|
168
|
+
const steps = [];
|
|
169
|
+
const calls = createCallPolicy(opts.policy ?? {});
|
|
170
|
+
let compactionStopped = false;
|
|
171
|
+
// The first request after a summary shows if the summary brought the conversation under the budget.
|
|
172
|
+
let summarizedLast = false;
|
|
173
|
+
/**
|
|
174
|
+
* Run one series, and wait out a failure that pauses. After the wait, the series runs again with the requests
|
|
175
|
+
* that it did not use. A partial reply of the failed request stays as an interrupted reply, and one harness
|
|
176
|
+
* request asks the model to continue it. A failure with no partial reply changes no message, thus the next
|
|
177
|
+
* request sends the same view.
|
|
178
|
+
*/
|
|
179
|
+
const series = async (target, spec) => {
|
|
180
|
+
let current = spec;
|
|
181
|
+
let attempt = 0;
|
|
182
|
+
for (;;) {
|
|
183
|
+
const stepsBefore = target.steps.length;
|
|
184
|
+
const ended = await runSeries(agent, opts, calls, log, target, current);
|
|
185
|
+
if (ended.kind !== "failed")
|
|
186
|
+
return ended;
|
|
187
|
+
const used = target.steps.length - stepsBefore;
|
|
188
|
+
// A request that completed ends the outage, thus the timer of the next pause starts again.
|
|
189
|
+
if (used > 0)
|
|
190
|
+
attempt = 0;
|
|
191
|
+
const pauseEnd = opts.pause === undefined ? undefined : await opts.pause(ended.failure, attempt, opts.signal);
|
|
192
|
+
if (pauseEnd === undefined)
|
|
193
|
+
throw toThrowable(ended.failure);
|
|
194
|
+
const [reply, ...results] = ended.partial;
|
|
195
|
+
if (reply !== undefined) {
|
|
196
|
+
const from = target.messages.length;
|
|
197
|
+
target.messages.push(markInterruptedMessage(reply), ...results);
|
|
198
|
+
answerUnansweredToolCalls(target.messages, from);
|
|
199
|
+
}
|
|
200
|
+
if (pauseEnd === "abort")
|
|
201
|
+
return { kind: "aborted" };
|
|
202
|
+
attempt = pauseEnd === "retry" ? attempt + 1 : 0;
|
|
203
|
+
current = { ...current, maxRequests: current.maxRequests - used, requestText: reply === undefined ? undefined : CONTINUE_REQUEST };
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
const finishUsage = () => {
|
|
207
|
+
const rollups = {};
|
|
208
|
+
if (hasReportedUsage(usage))
|
|
209
|
+
rollups.usage = { ...usage };
|
|
210
|
+
if (turnRoot && hasReportedUsage(turnUsage))
|
|
211
|
+
rollups.turnUsage = { ...turnUsage };
|
|
212
|
+
return rollups;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Settle the transcript on the way out. A reply can carry a complete tool
|
|
216
|
+
* call beside any finish reason, and a call this run never ran gets a
|
|
217
|
+
* not-run result instead of being executed or dropped: every tool call
|
|
218
|
+
* needs a result, or the provider refuses the transcript on the next turn.
|
|
219
|
+
* The fix only appends. It never edits or removes a message.
|
|
220
|
+
*/
|
|
221
|
+
const settleTranscript = () => {
|
|
222
|
+
const answered = answerUnansweredToolCalls(messages, initial.length);
|
|
223
|
+
if (answered.length === 0)
|
|
224
|
+
return;
|
|
225
|
+
log.warn("unanswered tool calls answered at run exit", { toolCallIds: answered.map((d) => d.toolCallId), tools: answered.map((d) => d.toolName) });
|
|
226
|
+
};
|
|
227
|
+
const end = async (seriesEnd) => {
|
|
228
|
+
settleTranscript();
|
|
229
|
+
const toolCalls = steps.reduce((n, step) => n + step.calls.length, 0);
|
|
230
|
+
const toolErrors = steps.reduce((n, step) => n + step.calls.filter((call) => call.refused || (call.output !== undefined && call.output.outcome !== "ok")).length, 0);
|
|
231
|
+
const finish = finishOf(seriesEnd, finishUsage());
|
|
232
|
+
recordAgentRun({ agentId: metricAgentId, iterations: steps.length, cappedOut: finish.cappedOut });
|
|
233
|
+
const level = finish.cappedOut || finish.reason === "denied" || seriesEnd.kind === "refused" ? "warn" : "info";
|
|
234
|
+
log[level]("run finished", { iterations: steps.length, reason: finish.reason, cappedOut: finish.cappedOut, toolCalls, toolErrors, usage });
|
|
235
|
+
await giveRound();
|
|
236
|
+
return { messages, finish, steps, refusal: seriesEnd.kind === "refused" ? seriesEnd.refusal : undefined };
|
|
237
|
+
};
|
|
238
|
+
const mainTarget = (beforeRequest) => ({
|
|
239
|
+
messages,
|
|
240
|
+
session,
|
|
241
|
+
metricAgentId,
|
|
242
|
+
rollups: [usage, turnUsage],
|
|
243
|
+
viewOf,
|
|
244
|
+
beforeRequest,
|
|
245
|
+
onText: opts.onText,
|
|
246
|
+
textStream: opts.chatStream,
|
|
247
|
+
steps,
|
|
248
|
+
stopWhen: opts.stopWhen,
|
|
249
|
+
capWhen: opts.capWhen,
|
|
250
|
+
});
|
|
251
|
+
/** The result of the run when an abort ends the exchange, or `undefined` when the run continues. */
|
|
252
|
+
const compact = async (active, tokensBefore, trigger) => {
|
|
253
|
+
// The body of a workflow records the id, thus a replay of the exchange gives the same id.
|
|
254
|
+
const id = DBOS.isInWorkflow() ? await DBOS.randomUUID() : randomUUID();
|
|
255
|
+
const startedAt = performance.now();
|
|
256
|
+
const source = sourceOf(session, opts.invocationId);
|
|
257
|
+
const emitPart = (data) => emit({ type: "data-compaction", source, data: { ...data, trigger } });
|
|
258
|
+
await emitPart({ id, status: "running", tokensBefore });
|
|
259
|
+
let settled = false;
|
|
260
|
+
try {
|
|
261
|
+
const exchangeAgentId = `${agent.id}-compaction`;
|
|
262
|
+
const view = viewOf(messages);
|
|
263
|
+
const exchange = [...view];
|
|
264
|
+
const exchangeEnd = await series({
|
|
265
|
+
messages: exchange,
|
|
266
|
+
session: forSubAgent(session, exchangeAgentId),
|
|
267
|
+
metricAgentId: exchangeAgentId,
|
|
268
|
+
rollups: [turnUsage],
|
|
269
|
+
viewOf: (from) => [...from],
|
|
270
|
+
steps: [],
|
|
271
|
+
}, { mask: active.mask, maxRequests: COMPACTION_MAX_REQUESTS, requestText: active.request, endsOnRequestRefusal: true });
|
|
272
|
+
const exchangeMessages = exchange.slice(view.length);
|
|
273
|
+
answerUnansweredToolCalls(exchangeMessages);
|
|
274
|
+
messages.push(...exchangeMessages.map((message) => markCompactionExchange(message, id)));
|
|
275
|
+
await giveRound();
|
|
276
|
+
if (exchangeEnd.kind === "aborted") {
|
|
277
|
+
settled = true;
|
|
278
|
+
await emitPart({ id, status: "failed", tokensBefore, durationMs: Math.round(performance.now() - startedAt) });
|
|
279
|
+
return "aborted";
|
|
280
|
+
}
|
|
281
|
+
const summary = exchangeEnd.kind === "reply" && exchangeEnd.finishReason === "stop" ? finalText(exchangeMessages).trim() : "";
|
|
282
|
+
if (summary.length === 0) {
|
|
283
|
+
settled = true;
|
|
284
|
+
const durationMs = Math.round(performance.now() - startedAt);
|
|
285
|
+
await emitPart({ id, status: "failed", tokensBefore, durationMs });
|
|
286
|
+
const refusal = exchangeEnd.kind === "refused" ? { status: exchangeEnd.refusal.status, providerError: exchangeEnd.refusal.message } : {};
|
|
287
|
+
log.error("compaction gave no summary, thus the run compacts no more", { compactionId: id, trigger, tokensBefore, durationMs, ...refusal });
|
|
288
|
+
compactionStopped = true;
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
const markerOf = (durationMs) => summaryMarkerMessage(summary, { kind: "summary", id, tokensBefore, durationMs, trigger });
|
|
292
|
+
// The figures of a marker do not change the view, thus a draft marker gives the view of the real one.
|
|
293
|
+
const records = await active.recordsAfter(conversationView([...messages, markerOf(0)], viewOptions).messages);
|
|
294
|
+
const durationMs = Math.round(performance.now() - startedAt);
|
|
295
|
+
messages.push(markerOf(durationMs), ...records);
|
|
296
|
+
settled = true;
|
|
297
|
+
// The `done` part goes out before the marker round: a chat turn gives the rounds after a marker a new
|
|
298
|
+
// assistant message, and the `running` and `done` parts of one compaction must stream into the same message.
|
|
299
|
+
await emitPart({ id, status: "done", tokensBefore, durationMs });
|
|
300
|
+
await giveRound();
|
|
301
|
+
log.info("conversation compacted", { compactionId: id, trigger, tokensBefore, durationMs });
|
|
302
|
+
summarizedLast = true;
|
|
303
|
+
return undefined;
|
|
304
|
+
}
|
|
305
|
+
finally {
|
|
306
|
+
if (!settled)
|
|
307
|
+
await emitPart({ id, status: "failed", tokensBefore, durationMs: Math.round(performance.now() - startedAt) });
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
const compactOverBudget = async () => {
|
|
311
|
+
if (policy === undefined || compactionStopped)
|
|
312
|
+
return;
|
|
313
|
+
const tokens = lastRequestInputTokens(messages);
|
|
314
|
+
if (tokens === undefined)
|
|
315
|
+
return;
|
|
316
|
+
const afterSummary = summarizedLast;
|
|
317
|
+
summarizedLast = false;
|
|
318
|
+
if (tokens <= policy.budget)
|
|
319
|
+
return;
|
|
320
|
+
if (afterSummary) {
|
|
321
|
+
log.warn("the first request after the summary still exceeds the budget, thus the run compacts no more", { tokens, budget: policy.budget });
|
|
322
|
+
compactionStopped = true;
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
// An abort during the exchange aborts the request that follows it, thus the run ends as aborted.
|
|
326
|
+
await compact(policy, tokens, "mid-turn");
|
|
327
|
+
};
|
|
328
|
+
return {
|
|
329
|
+
async startTurn(input) {
|
|
330
|
+
const budget = policy?.turnStartBudget;
|
|
331
|
+
const tokens = lastRequestInputTokens(messages);
|
|
332
|
+
if (policy === undefined || budget === undefined || tokens === undefined || tokens <= budget) {
|
|
333
|
+
messages.push(...input);
|
|
334
|
+
return undefined;
|
|
335
|
+
}
|
|
336
|
+
const ended = await compact(policy, tokens, "turn-start");
|
|
337
|
+
if (ended === "aborted")
|
|
338
|
+
return end({ kind: "aborted" });
|
|
339
|
+
// The records after a summary give the current context, thus a record of the input would only repeat one.
|
|
340
|
+
messages.push(...(summarizedLast ? input.filter((message) => contextRecordOf(message) === undefined) : input));
|
|
341
|
+
return undefined;
|
|
342
|
+
},
|
|
343
|
+
async run(spec) {
|
|
344
|
+
const beforeRequest = async () => {
|
|
345
|
+
await giveRound();
|
|
346
|
+
if (spec.checksBudget === true)
|
|
347
|
+
await compactOverBudget();
|
|
348
|
+
};
|
|
349
|
+
return end(await series(mainTarget(beforeRequest), spec));
|
|
350
|
+
},
|
|
351
|
+
// A throw keeps the open round, and the not-run results keep that stored round valid on the wire.
|
|
352
|
+
async guard(body) {
|
|
353
|
+
try {
|
|
354
|
+
return await body();
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
log.error("run failed", { iterations: steps.length, ...log.errorFields(err) });
|
|
358
|
+
if (opts.onRound === undefined || sinkPending)
|
|
359
|
+
throw err;
|
|
360
|
+
answerUnansweredToolCalls(messages, givenCount);
|
|
361
|
+
// A rejection of this call must not hide the error of the run.
|
|
362
|
+
await giveRound().catch(() => undefined);
|
|
363
|
+
throw err;
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function finishOf(seriesEnd, rollups) {
|
|
369
|
+
switch (seriesEnd.kind) {
|
|
370
|
+
case "reply":
|
|
371
|
+
return { reason: seriesEnd.finishReason, rawFinishReason: seriesEnd.rawFinishReason, cappedOut: false, ...rollups };
|
|
372
|
+
case "capped":
|
|
373
|
+
case "early-cap":
|
|
374
|
+
return { reason: "max_iterations", cappedOut: true, ...rollups };
|
|
375
|
+
case "stopped":
|
|
376
|
+
return { reason: "stop", cappedOut: false, ...rollups };
|
|
377
|
+
case "denied":
|
|
378
|
+
return { reason: "denied", cappedOut: false, ...rollups };
|
|
379
|
+
case "aborted":
|
|
380
|
+
return { reason: "aborted", cappedOut: false, ...rollups };
|
|
381
|
+
case "refused":
|
|
382
|
+
return { reason: "error", cappedOut: false, ...rollups };
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function sourceOf(session, invocationId) {
|
|
386
|
+
const source = {
|
|
387
|
+
agentId: session.provenance.agentId,
|
|
388
|
+
callPath: session.provenance.callPath,
|
|
389
|
+
};
|
|
390
|
+
if (invocationId !== undefined)
|
|
391
|
+
source.invocationId = invocationId;
|
|
392
|
+
return source;
|
|
393
|
+
}
|
|
394
|
+
/** The statuses of a request that the provider refuses for its content, for example a request past the context window. */
|
|
395
|
+
const REFUSAL_STATUSES = new Set([400, 413]);
|
|
396
|
+
function requestRefusalOf(failure) {
|
|
397
|
+
const error = findProviderError(failure);
|
|
398
|
+
if (error?.type !== "provider")
|
|
399
|
+
return undefined;
|
|
400
|
+
const status = extractStatus(error);
|
|
401
|
+
return status !== undefined && REFUSAL_STATUSES.has(status) ? { status, message: error.message } : undefined;
|
|
402
|
+
}
|
|
403
|
+
/** Whether the loop asks the model again after this step: each call of the reply has a result. */
|
|
404
|
+
function continuesAfter(step) {
|
|
405
|
+
return step.calls.length > 0 && step.calls.every((call) => call.answered);
|
|
406
|
+
}
|
|
407
|
+
function deniedByUser(step) {
|
|
408
|
+
return step.calls.some((call) => call.output?.outcome === "denied");
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Run one series of model requests with `streamText`, and say how it ended.
|
|
412
|
+
* A failed request ends the series as `failed`, and a fatal tool error leaves as a throw.
|
|
413
|
+
*/
|
|
414
|
+
async function runSeries(agent, opts, calls, log, target, spec) {
|
|
415
|
+
const { messages, session } = target;
|
|
416
|
+
const startIndex = messages.length;
|
|
417
|
+
if (spec.requestText !== undefined)
|
|
418
|
+
messages.push(syntheticUserMessage(spec.requestText));
|
|
419
|
+
const promptCache = opts.promptCache ?? DEFAULT_PROMPT_CACHE;
|
|
420
|
+
const source = sourceOf(session, opts.invocationId);
|
|
421
|
+
const bound = opts.provider.bind({
|
|
422
|
+
session,
|
|
423
|
+
reasoning: opts.reasoning,
|
|
424
|
+
live: target.onText !== undefined,
|
|
425
|
+
// A reader sees the retries of a request, thus a wait of the envelope is no silence. The part is transient,
|
|
426
|
+
// and a failed write of it changes nothing of the request.
|
|
427
|
+
onRetry: (retry) => {
|
|
428
|
+
const part = {
|
|
429
|
+
id: retry.requestId,
|
|
430
|
+
attempt: retry.attempt,
|
|
431
|
+
maxRetries: retry.maxRetries,
|
|
432
|
+
retryAt: new Date(Date.now() + retry.delayMs).toISOString(),
|
|
433
|
+
status: retry.status,
|
|
434
|
+
};
|
|
435
|
+
void Promise.resolve(opts.emit({ type: "data-model-retry", source, data: part })).catch(() => undefined);
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
const model = wrapLanguageModel({
|
|
439
|
+
model: bound.model,
|
|
440
|
+
middleware: [
|
|
441
|
+
rollupMiddleware(target.rollups),
|
|
442
|
+
durableCalls({ name: modelStepName(agent.id), retriesAllowed: false, durableStream: target.textStream }),
|
|
443
|
+
accountingMiddleware({
|
|
444
|
+
session,
|
|
445
|
+
agentId: target.metricAgentId,
|
|
446
|
+
invocationId: opts.invocationId,
|
|
447
|
+
usageRecorder: opts.usageRecorder ?? createNoopUsageRecorder(),
|
|
448
|
+
logger: log,
|
|
449
|
+
}),
|
|
450
|
+
...(opts.modelMiddleware ?? []),
|
|
451
|
+
],
|
|
452
|
+
});
|
|
453
|
+
// The work before the current request, which an abort of the stream does not wait for.
|
|
454
|
+
let preparing;
|
|
455
|
+
// The first fatal error of a tool call or of an approval ends the series, and the series throws it.
|
|
456
|
+
let fatal;
|
|
457
|
+
const fatalController = new AbortController();
|
|
458
|
+
const failRun = (err) => {
|
|
459
|
+
if (fatal !== undefined)
|
|
460
|
+
return;
|
|
461
|
+
fatal = err;
|
|
462
|
+
fatalController.abort(err);
|
|
463
|
+
};
|
|
464
|
+
const tools = adaptTools(agent.tools, {
|
|
465
|
+
session,
|
|
466
|
+
source,
|
|
467
|
+
emit: opts.emit,
|
|
468
|
+
turnUsage: target.rollups.at(-1) ?? {},
|
|
469
|
+
capabilities: opts.provider.capabilities,
|
|
470
|
+
// Only the read tool of the agent can read a kept text, thus an agent without it keeps nothing.
|
|
471
|
+
store: agent.tools.some((tool) => tool.id === READ_TOOL_OUTPUT_TOOL_ID) ? opts.toolOutputStore : undefined,
|
|
472
|
+
invocationId: opts.invocationId,
|
|
473
|
+
log,
|
|
474
|
+
writer: opts.toolWriter,
|
|
475
|
+
fail: failRun,
|
|
476
|
+
});
|
|
477
|
+
const toolsById = new Map(agent.tools.map((tool) => [tool.id, tool]));
|
|
478
|
+
// The calls that the user denied, with the reason that the model reads. A replay asks again, and the same answer
|
|
479
|
+
// comes back from the checkpoints of the turn.
|
|
480
|
+
const deniedByTheUser = new Map();
|
|
481
|
+
/** The reason of a denial of the user, or `undefined` for a call that runs. */
|
|
482
|
+
const userDenialOf = async (toolCall) => {
|
|
483
|
+
const tool = toolsById.get(toolCall.toolName);
|
|
484
|
+
if (tool?.approval === undefined)
|
|
485
|
+
return undefined;
|
|
486
|
+
// An input that does not parse needs no approval: `execute` gives the model its error.
|
|
487
|
+
const input = recordedInputOf(tool.inputSchema, toolCall.input);
|
|
488
|
+
if (input === undefined)
|
|
489
|
+
return undefined;
|
|
490
|
+
const request = await tool.approval(input, { invocationId: toolCall.toolCallId, session });
|
|
491
|
+
if (request === undefined)
|
|
492
|
+
return undefined;
|
|
493
|
+
if (opts.approve === undefined)
|
|
494
|
+
return NO_APPROVER_REASON;
|
|
495
|
+
const decision = await opts.approve(request, { toolCallId: toolCall.toolCallId, toolName: toolCall.toolName });
|
|
496
|
+
return decision.kind === "approved" ? undefined : deniedReason(decision.feedback);
|
|
497
|
+
};
|
|
498
|
+
const seriesSteps = [];
|
|
499
|
+
let open = openStep();
|
|
500
|
+
let failure;
|
|
501
|
+
const requestView = () => [...withPromptCacheBreakpoint(sanitizeMessages(target.viewOf(messages)), promptCache)];
|
|
502
|
+
const stops = () => seriesSteps.length >= spec.maxRequests ||
|
|
503
|
+
deniedByUser(seriesSteps.at(-1) ?? { finishReason: "", calls: [] }) ||
|
|
504
|
+
target.stopWhen?.(target.steps) === true ||
|
|
505
|
+
target.capWhen?.() === true;
|
|
506
|
+
const result = streamText({
|
|
507
|
+
model,
|
|
508
|
+
instructions: withSystemPromptBreakpoint(agent.systemPrompt, promptCache),
|
|
509
|
+
messages: requestView(),
|
|
510
|
+
tools,
|
|
511
|
+
toolChoice: "auto",
|
|
512
|
+
maxOutputTokens: bound.settings.maxOutputTokens,
|
|
513
|
+
reasoning: bound.settings.reasoning,
|
|
514
|
+
providerOptions: mergeProviderOptions(bound.settings.providerOptions, agent.providerOptions),
|
|
515
|
+
// The retry envelope of the provider owns the retries, inside the step of the call.
|
|
516
|
+
maxRetries: 0,
|
|
517
|
+
abortSignal: AbortSignal.any([opts.signal, fatalController.signal]),
|
|
518
|
+
telemetry: bound.telemetry,
|
|
519
|
+
toolApproval: async ({ toolCall }) => {
|
|
520
|
+
const refusal = calls.refusalOf({ toolName: toolCall.toolName, input: toolCall.input }, spec.mask);
|
|
521
|
+
if (refusal !== undefined) {
|
|
522
|
+
// A refused call does not run, thus its two events come from here.
|
|
523
|
+
await opts.emit({ type: "tool-started", source, toolUseId: toolCall.toolCallId, name: toolCall.toolName, input: toolCall.input });
|
|
524
|
+
await opts.emit({ type: "tool-finished", source, toolUseId: toolCall.toolCallId, name: toolCall.toolName, outcome: "error" });
|
|
525
|
+
return { type: "denied", reason: refusal };
|
|
526
|
+
}
|
|
527
|
+
let denial;
|
|
528
|
+
try {
|
|
529
|
+
denial = await userDenialOf(toolCall);
|
|
530
|
+
}
|
|
531
|
+
catch (err) {
|
|
532
|
+
// The SDK keeps a failed approval to itself, thus a cancel or an abort reaches the series here.
|
|
533
|
+
if (isFatalToolError(err))
|
|
534
|
+
failRun(err);
|
|
535
|
+
throw err;
|
|
536
|
+
}
|
|
537
|
+
if (denial === undefined)
|
|
538
|
+
return undefined;
|
|
539
|
+
deniedByTheUser.set(toolCall.toolCallId, denial);
|
|
540
|
+
await opts.emit({ type: "tool-started", source, toolUseId: toolCall.toolCallId, name: toolCall.toolName, input: toolCall.input });
|
|
541
|
+
await opts.emit({ type: "tool-finished", source, toolUseId: toolCall.toolCallId, name: toolCall.toolName, outcome: "denied" });
|
|
542
|
+
return { type: "denied", reason: denial };
|
|
543
|
+
},
|
|
544
|
+
stopWhen: () => stops(),
|
|
545
|
+
prepareStep: async () => {
|
|
546
|
+
open = openStep();
|
|
547
|
+
const before = target.beforeRequest?.();
|
|
548
|
+
preparing = before;
|
|
549
|
+
await before;
|
|
550
|
+
return { messages: requestView() };
|
|
551
|
+
},
|
|
552
|
+
onChunk: async ({ chunk }) => {
|
|
553
|
+
switch (chunk.type) {
|
|
554
|
+
case "text-delta":
|
|
555
|
+
open.text += chunk.text;
|
|
556
|
+
await target.onText?.(chunk.text);
|
|
557
|
+
return;
|
|
558
|
+
case "tool-call":
|
|
559
|
+
if (chunk.providerExecuted !== true)
|
|
560
|
+
open.calls.push({ type: "tool-call", toolCallId: chunk.toolCallId, toolName: chunk.toolName, input: chunk.input });
|
|
561
|
+
return;
|
|
562
|
+
case "tool-result": {
|
|
563
|
+
const output = ToolCallOutputSchema.safeParse(chunk.output);
|
|
564
|
+
if (output.success)
|
|
565
|
+
open.results.push({ type: "tool-result", toolCallId: chunk.toolCallId, toolName: chunk.toolName, output: modelViewOf(output.data) });
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
default:
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
onError: ({ error }) => {
|
|
573
|
+
failure ??= error;
|
|
574
|
+
},
|
|
575
|
+
onStepEnd: async (step) => {
|
|
576
|
+
open = openStep();
|
|
577
|
+
const loopStep = loopStepOf(step, deniedByTheUser);
|
|
578
|
+
messages.push(...recordedMessagesOf(step, loopStep));
|
|
579
|
+
foldCallRecords(agent.tools, loopStep.calls, log);
|
|
580
|
+
seriesSteps.push(loopStep);
|
|
581
|
+
target.steps.push(loopStep);
|
|
582
|
+
if (loopStep.calls.length > 0)
|
|
583
|
+
log.debug("iteration", { iteration: seriesSteps.length - 1, tools: loopStep.calls.map((call) => call.toolName) });
|
|
584
|
+
await opts.emit({ type: "iteration", source, index: seriesSteps.length - 1, final: !continuesAfter(loopStep) || stops() });
|
|
585
|
+
},
|
|
586
|
+
});
|
|
587
|
+
await result.consumeStream({
|
|
588
|
+
onError: (error) => {
|
|
589
|
+
failure ??= error;
|
|
590
|
+
},
|
|
591
|
+
});
|
|
592
|
+
// An abort ends the stream while the work before a request can still run, for example a compaction that
|
|
593
|
+
// writes its round. The series ends after that work, thus the run never writes a round beside it.
|
|
594
|
+
await preparing?.catch(() => undefined);
|
|
595
|
+
const callerAborted = opts.signal.aborted;
|
|
596
|
+
if (fatal !== undefined && !(callerAborted && errorNameOf(fatal) === "AbortError")) {
|
|
597
|
+
messages.push(...openStepMessages(open));
|
|
598
|
+
answerUnansweredToolCalls(messages, startIndex);
|
|
599
|
+
throw toThrowable(fatal);
|
|
600
|
+
}
|
|
601
|
+
if (callerAborted) {
|
|
602
|
+
// An interrupted turn keeps whatever the model wrote before the cut, but never an empty shell.
|
|
603
|
+
const [reply, ...results] = openStepMessages(open);
|
|
604
|
+
if (reply !== undefined)
|
|
605
|
+
messages.push(markInterruptedMessage(reply), ...results);
|
|
606
|
+
answerUnansweredToolCalls(messages, startIndex);
|
|
607
|
+
return { kind: "aborted" };
|
|
608
|
+
}
|
|
609
|
+
if (failure !== undefined && !isFatalToolError(failure)) {
|
|
610
|
+
const refusal = spec.endsOnRequestRefusal === true ? requestRefusalOf(failure) : undefined;
|
|
611
|
+
answerUnansweredToolCalls(messages, startIndex);
|
|
612
|
+
if (refusal !== undefined)
|
|
613
|
+
return { kind: "refused", refusal };
|
|
614
|
+
return { kind: "failed", failure, partial: openStepMessages(open) };
|
|
615
|
+
}
|
|
616
|
+
const last = seriesSteps.at(-1);
|
|
617
|
+
if (last === undefined)
|
|
618
|
+
throw new Error(`The run of the agent "${agent.id}" ended with no completed request.`);
|
|
619
|
+
if (!continuesAfter(last))
|
|
620
|
+
return { kind: "reply", finishReason: last.finishReason, rawFinishReason: last.rawFinishReason };
|
|
621
|
+
if (deniedByUser(last))
|
|
622
|
+
return { kind: "denied" };
|
|
623
|
+
if (target.stopWhen?.(target.steps) === true)
|
|
624
|
+
return { kind: "stopped" };
|
|
625
|
+
if (target.capWhen?.() === true) {
|
|
626
|
+
log.warn("run stopped early by the host policy", { iterations: seriesSteps.length });
|
|
627
|
+
return { kind: "early-cap" };
|
|
628
|
+
}
|
|
629
|
+
return { kind: "capped" };
|
|
630
|
+
}
|
|
631
|
+
function openStep() {
|
|
632
|
+
return { text: "", calls: [], results: [] };
|
|
633
|
+
}
|
|
634
|
+
/** The reply of a cut step and the results of its calls that completed. A step with no text and no call gives nothing. */
|
|
635
|
+
function openStepMessages(open) {
|
|
636
|
+
if (open.text.length === 0 && open.calls.length === 0)
|
|
637
|
+
return [];
|
|
638
|
+
if (open.calls.length === 0)
|
|
639
|
+
return [{ role: "assistant", content: open.text }];
|
|
640
|
+
const text = open.text.length > 0 ? [{ type: "text", text: open.text }] : [];
|
|
641
|
+
const messages = [{ role: "assistant", content: [...text, ...open.calls] }];
|
|
642
|
+
const results = open.results.filter((result) => open.calls.some((call) => call.toolCallId === result.toolCallId));
|
|
643
|
+
if (results.length > 0)
|
|
644
|
+
messages.push({ role: "tool", content: results });
|
|
645
|
+
return messages;
|
|
646
|
+
}
|
|
647
|
+
/** The harness view of one completed step: each tool call of the reply, with its output when it ran. */
|
|
648
|
+
function loopStepOf(step, deniedByTheUser) {
|
|
649
|
+
const outputs = new Map();
|
|
650
|
+
for (const result of step.toolResults)
|
|
651
|
+
outputs.set(result.toolCallId, result.output);
|
|
652
|
+
const answered = new Set(outputs.keys());
|
|
653
|
+
const refused = new Set();
|
|
654
|
+
for (const part of step.content) {
|
|
655
|
+
if (part.type === "tool-error")
|
|
656
|
+
answered.add(part.toolCallId);
|
|
657
|
+
if (part.type === "tool-approval-response" && !part.approved) {
|
|
658
|
+
answered.add(part.toolCall.toolCallId);
|
|
659
|
+
if (!deniedByTheUser.has(part.toolCall.toolCallId))
|
|
660
|
+
refused.add(part.toolCall.toolCallId);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
const calls = step.toolCalls
|
|
664
|
+
.filter((call) => call.providerExecuted !== true)
|
|
665
|
+
.map((call) => {
|
|
666
|
+
const parsed = outputs.has(call.toolCallId) ? ToolCallOutputSchema.safeParse(outputs.get(call.toolCallId)) : undefined;
|
|
667
|
+
const denial = deniedByTheUser.get(call.toolCallId);
|
|
668
|
+
return {
|
|
669
|
+
toolCallId: call.toolCallId,
|
|
670
|
+
toolName: call.toolName,
|
|
671
|
+
input: call.input,
|
|
672
|
+
output: denial === undefined ? (parsed?.success === true ? parsed.data : undefined) : { outcome: "denied", reason: denial },
|
|
673
|
+
refused: refused.has(call.toolCallId),
|
|
674
|
+
answered: answered.has(call.toolCallId),
|
|
675
|
+
};
|
|
676
|
+
});
|
|
677
|
+
return { finishReason: step.finishReason, rawFinishReason: step.rawFinishReason, calls };
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* The messages of one step as the transcript records them. The request after
|
|
681
|
+
* them sends them as they are recorded, thus the record is the prefix of the
|
|
682
|
+
* next request.
|
|
683
|
+
*
|
|
684
|
+
* - The assistant message holds the input tokens of its request, which the
|
|
685
|
+
* budget checks read, and it holds no thinking after a fallback hop.
|
|
686
|
+
* - A refusal of the policy reads as the error result of the call. A denial
|
|
687
|
+
* reads as a decision of the user, and the reload of a thread reports the
|
|
688
|
+
* outcome of each call from its result.
|
|
689
|
+
* - The approval parts go: they describe the approval, and the wire drops them.
|
|
690
|
+
*/
|
|
691
|
+
function recordedMessagesOf(step, loopStep) {
|
|
692
|
+
const refused = new Set(loopStep.calls.filter((call) => call.refused).map((call) => call.toolCallId));
|
|
693
|
+
const servedByFallback = fallbackModelOf(step.providerMetadata) !== undefined;
|
|
694
|
+
const inputTokens = step.usage.inputTokens;
|
|
695
|
+
const recorded = [];
|
|
696
|
+
for (const message of step.response.messages) {
|
|
697
|
+
if (message.role === "assistant") {
|
|
698
|
+
const content = typeof message.content === "string" ? message.content : message.content.filter((part) => part.type !== "tool-approval-request");
|
|
699
|
+
let assistant = { ...message, content };
|
|
700
|
+
if (servedByFallback) {
|
|
701
|
+
const stripped = withoutReasoning(assistant);
|
|
702
|
+
assistant = stripped?.role === "assistant" ? stripped : undefined;
|
|
703
|
+
}
|
|
704
|
+
if (assistant === undefined)
|
|
705
|
+
continue;
|
|
706
|
+
recorded.push(inputTokens === undefined ? assistant : withRequestInputTokens(assistant, inputTokens));
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
const content = message.content.flatMap((part) => {
|
|
710
|
+
if (part.type === "tool-approval-response")
|
|
711
|
+
return [];
|
|
712
|
+
if (part.output.type === "execution-denied" && refused.has(part.toolCallId)) {
|
|
713
|
+
return [{ ...part, output: { type: "error-text", value: part.output.reason ?? "" } }];
|
|
714
|
+
}
|
|
715
|
+
return [part];
|
|
716
|
+
});
|
|
717
|
+
if (content.length > 0)
|
|
718
|
+
recorded.push({ role: "tool", content });
|
|
719
|
+
}
|
|
720
|
+
return recorded;
|
|
721
|
+
}
|
|
722
|
+
function mergeProviderOptions(base, extra) {
|
|
723
|
+
if (extra === undefined)
|
|
724
|
+
return base;
|
|
725
|
+
if (base === undefined)
|
|
726
|
+
return extra;
|
|
727
|
+
const merged = { ...base };
|
|
728
|
+
for (const [namespace, options] of Object.entries(extra))
|
|
729
|
+
merged[namespace] = { ...base[namespace], ...options };
|
|
730
|
+
return merged;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Drop empty text parts — and messages left with no content at all — before
|
|
734
|
+
* the request. The Anthropic Messages API rejects any request containing an
|
|
735
|
+
* empty text block, and a stored thread can hold one.
|
|
736
|
+
*/
|
|
737
|
+
function sanitizeMessages(messages) {
|
|
738
|
+
const out = [];
|
|
739
|
+
for (const m of messages) {
|
|
740
|
+
if (typeof m.content === "string") {
|
|
741
|
+
if (m.content !== "")
|
|
742
|
+
out.push(m);
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
// The filtered parts are a subset of this message's own content, so the
|
|
746
|
+
// switch recovers the role-to-content correlation that `filter` loses.
|
|
747
|
+
switch (m.role) {
|
|
748
|
+
case "assistant": {
|
|
749
|
+
const parts = m.content.filter((p) => p.type !== "text" || p.text !== "");
|
|
750
|
+
if (parts.length > 0)
|
|
751
|
+
out.push({ ...m, content: parts });
|
|
752
|
+
break;
|
|
753
|
+
}
|
|
754
|
+
case "user": {
|
|
755
|
+
const parts = m.content.filter((p) => p.type !== "text" || p.text !== "");
|
|
756
|
+
if (parts.length > 0)
|
|
757
|
+
out.push({ ...m, content: parts });
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
case "tool": {
|
|
761
|
+
if (m.content.length > 0)
|
|
762
|
+
out.push(m);
|
|
763
|
+
break;
|
|
764
|
+
}
|
|
765
|
+
case "system":
|
|
766
|
+
break;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
return out;
|
|
770
|
+
}
|