@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
|
@@ -39,69 +39,72 @@
|
|
|
39
39
|
* `partial`).
|
|
40
40
|
* - the halt cascade (cancel in-flight via
|
|
41
41
|
* `Promise.allSettled(handles.map(h => DBOS.cancelWorkflow(h.workflowID)))`,
|
|
42
|
-
* stop scheduling) survives only for
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* - a
|
|
50
|
-
* the
|
|
51
|
-
* - a `suspend` error of a synthesis model request suspends the run in
|
|
52
|
-
* place of the synthesis failure
|
|
53
|
-
* - the run row and the analysis flip to `suspended_insufficient_funds` in
|
|
54
|
-
* `collectAndComplete`. The run status is terminal and does not block a
|
|
55
|
-
* new run of the plan. The paused parent lands in `CANCELLED`, a
|
|
56
|
-
* durably reschedulable state; re-driving it is a future enhancement,
|
|
57
|
-
* not yet wired here. The reason of the host rides to the run row, the
|
|
58
|
-
* charge close, the metric, and the terminal part, unread.
|
|
42
|
+
* stop scheduling) survives only for the `neverFits` plan-validation guard.
|
|
43
|
+
* 4. Pause (work-pause spec)
|
|
44
|
+
* - a step pauses in its own workflow, and the parent waits for its result as
|
|
45
|
+
* for a step that runs. The other steps go on, and the run row stays
|
|
46
|
+
* `running`
|
|
47
|
+
* - a refusal of the `RunCharge.open` gate with the suspend flag pauses the
|
|
48
|
+
* run before any step starts, and the charge opens again after the resume
|
|
49
|
+
* - a failed model request of the synthesis with a cause of a pause waits in
|
|
50
|
+
* the loop of the synthesizer
|
|
59
51
|
* 5. `synthesizeFindings` (single sequential block, no sandbox)
|
|
60
52
|
* 6. `collectAndComplete` (terminal — runs on ALL paths)
|
|
61
53
|
* - determine final status from completed/cancelled/failed counts
|
|
62
|
-
* - update `cortex_runs.status` + `error
|
|
63
|
-
* the
|
|
64
|
-
*
|
|
65
|
-
* died before
|
|
66
|
-
*
|
|
67
|
-
*
|
|
54
|
+
* - update `cortex_runs.status` + `error`. When the write changes the row,
|
|
55
|
+
* the same step emits `run_completed` before the commit, records the run
|
|
56
|
+
* outcome metric plus the outcome of every settled step whose child never
|
|
57
|
+
* wrote its own terminal row (a cancelled child, or one that died before
|
|
58
|
+
* `failStep`), closes the running charge with the matching outcome, and
|
|
59
|
+
* revokes the run authorization through the injected `runAuthorizer`
|
|
60
|
+
* - the write retries with backoff on a failed transaction. When the write is
|
|
61
|
+
* refused, or fails on each attempt, close and revoke in their own steps, then
|
|
62
|
+
* emit `run_completed`. After a failed write the row stays `running`, so the
|
|
63
|
+
* body records its run end as a workflow event for the run canceler
|
|
68
64
|
* - emit terminal stream part
|
|
69
65
|
* - WRITES NOTHING to the conversation thread (results are pull-only
|
|
70
66
|
* via `inspectRun`)
|
|
71
67
|
*/
|
|
72
|
-
import {
|
|
68
|
+
import { errorMessageOf } from "../lib/thrown.js";
|
|
69
|
+
import { textOf } from "../lib/unknown-text.js";
|
|
70
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
71
|
+
import { isWorkflowCancellation } from "../runtime/dbos.js";
|
|
73
72
|
import { err, ok } from "neverthrow";
|
|
74
73
|
import { mkdir } from "node:fs/promises";
|
|
75
74
|
import { join } from "node:path";
|
|
76
75
|
import { forStep } from "../auth/types.js";
|
|
76
|
+
import { RUN_END_EVENT_KEY } from "../execution/run-end-record.js";
|
|
77
77
|
import { createNoopLogger } from "../lib/console-logger.js";
|
|
78
78
|
import { deliverNotice, passGate } from "../lib/hooks.js";
|
|
79
79
|
import { ATTR_INFLEXA_STEP_ID, stableSpan } from "../lib/otel-spans.js";
|
|
80
80
|
import { recordRunCompleted, recordStepCompleted, stepOutcomeOf } from "../lib/metrics.js";
|
|
81
|
-
import { describeDbError } from "../lib/db-result.js";
|
|
81
|
+
import { describeDbError, withTransaction } from "../lib/db-result.js";
|
|
82
82
|
import { unwrapOrThrow } from "../lib/result.js";
|
|
83
|
-
import { countArtifactsByRuns, insertStepExecution, loadDataProfileStatus, queryActiveRun, queryStepArtifactPaths, queryStepsByRun, seedStepExecutions, setRunSynthesisOutcome,
|
|
83
|
+
import { countArtifactsByRuns, insertStepExecution, loadDataProfileStatus, queryActiveRun, queryStepArtifactPaths, queryStepsByRun, seedStepExecutions, setRunSynthesisOutcome, sweepPendingStepExecutions, updateRunStatus, updateStepExecution, } from "../state/index.js";
|
|
84
|
+
import { clearPausesOfWork } from "../state/paused-work.js";
|
|
84
85
|
import { addChatUsage, hasReportedUsage } from "../loop/metrics.js";
|
|
85
86
|
import { flattenDataPart } from "../contracts/chat-frame.js";
|
|
86
87
|
import { SYNTHESIS_AGENT_ID, loadStepSummariesFromDisk } from "../execution/run-synthesis.js";
|
|
87
|
-
import { MAX_UPSTREAM_ARTIFACTS, composeStepBriefing, emptyStepMemory } from "../prompts/briefing.js";
|
|
88
|
+
import { MAX_UPSTREAM_ARTIFACTS, composeStepBriefing, emptyStepMemory, } from "../prompts/briefing.js";
|
|
88
89
|
import { SYNTHESIS_STEP_ID, runDir, runStepDir, stepSubdir, stepWritePrefix, toSandboxPath } from "../workspace/paths.js";
|
|
89
90
|
import { isChatDataPart, synthesisEmission } from "../sandbox/sandbox-step-translate.js";
|
|
90
91
|
import { synthesizeRun } from "../app/synthesize-run.js";
|
|
91
92
|
import { computeTopologicalLevels, scheduleReady, validatePlanDag } from "./execute-analysis-scheduler.js";
|
|
92
93
|
import { recordCancelledChild } from "./metrics.js";
|
|
93
|
-
import {
|
|
94
|
-
import {
|
|
94
|
+
import { pauseAtGate, workPause } from "./pause.js";
|
|
95
|
+
import { presentGet } from "../lib/present.js";
|
|
95
96
|
// ── In-body orchestration helpers ────────────────────────────────────
|
|
96
97
|
/** Emit a chat data part on the parent's DBOS stream. */
|
|
97
98
|
function emitStreamPart(part) {
|
|
98
99
|
return DBOS.writeStream("events", part);
|
|
99
100
|
}
|
|
100
101
|
/**
|
|
101
|
-
* A failed write rolls back no side effect that succeeded
|
|
102
|
-
*
|
|
102
|
+
* A failed write rolls back no side effect that succeeded. The step body logs
|
|
103
|
+
* its own failure and never throws. A DBOS exception passes through with no
|
|
104
|
+
* change.
|
|
103
105
|
*/
|
|
104
106
|
async function ledgerStep(log, name, write) {
|
|
107
|
+
// typecheck-disable-next-line must-use-result -- a ledger miss must not fail the run
|
|
105
108
|
await DBOS.runStep(async () => {
|
|
106
109
|
const written = await write();
|
|
107
110
|
if (written.isOk())
|
|
@@ -151,8 +154,8 @@ function buildRunObservation(args) {
|
|
|
151
154
|
agent: input.agentByStepId[s.id] ?? "unknown",
|
|
152
155
|
// A step absent from the map has not been reached yet; `pending` is its honest state.
|
|
153
156
|
status: rt?.status ?? "pending",
|
|
154
|
-
|
|
155
|
-
|
|
157
|
+
durationMs: rt?.durationMs,
|
|
158
|
+
error: rt?.error,
|
|
156
159
|
};
|
|
157
160
|
}),
|
|
158
161
|
};
|
|
@@ -183,7 +186,7 @@ function observeRunGuarded(deps, observation) {
|
|
|
183
186
|
* projection/timeout-propagation tests.
|
|
184
187
|
*/
|
|
185
188
|
export function buildChildInput(args) {
|
|
186
|
-
const { input, stepId, level, runId,
|
|
189
|
+
const { input, stepId, level, runId, prompt, templateBinding } = args;
|
|
187
190
|
const resources = input.resourcesByStepId[stepId];
|
|
188
191
|
if (!resources) {
|
|
189
192
|
throw new Error(`executeAnalysis: step "${stepId}" missing from resourcesByStepId — every step must declare resources`);
|
|
@@ -205,9 +208,11 @@ export function buildChildInput(args) {
|
|
|
205
208
|
// genuinely declared nothing, and it silently deletes every same-run edge
|
|
206
209
|
// the step was entitled to.
|
|
207
210
|
dependsOn: planStep.depends_on,
|
|
211
|
+
// Composed beside the seed, thus the same checkpoint carries both and a
|
|
212
|
+
// replay hands the child the binding its briefing describes.
|
|
213
|
+
templateBinding,
|
|
208
214
|
level,
|
|
209
215
|
prompt,
|
|
210
|
-
parentWorkflowId: workflowId,
|
|
211
216
|
resources,
|
|
212
217
|
timeoutSeconds: input.timeoutByStepId?.[stepId],
|
|
213
218
|
};
|
|
@@ -222,13 +227,18 @@ export function buildChildInput(args) {
|
|
|
222
227
|
* rendered any earlier (at plan submission, say) cannot mention them, and the
|
|
223
228
|
* agent is left to rediscover its own upstream.
|
|
224
229
|
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
230
|
+
* The template contract of a grounded step is read with the package, and the
|
|
231
|
+
* plan settings are bound to it: the seed describes the binding, and the child
|
|
232
|
+
* input carries it, from one checkpoint. The child fetches nothing.
|
|
233
|
+
*
|
|
234
|
+
* REPLAY: the caller wraps this in a `DBOS.runStep`, so the composed seed is
|
|
235
|
+
* checkpointed and a replay returns it verbatim — the DB, the disk, and the
|
|
236
|
+
* knowledge service are not read again and cannot drift the seed under a
|
|
237
|
+
* recovered run. Never call it unwrapped from the workflow body.
|
|
229
238
|
*/
|
|
230
239
|
export async function composeStepSeed(args) {
|
|
231
|
-
|
|
240
|
+
const { briefing, templateBinding } = await gatherStepPackage(args);
|
|
241
|
+
return { prompt: composeStepBriefing(briefing), templateBinding };
|
|
232
242
|
}
|
|
233
243
|
/**
|
|
234
244
|
* Do every read of one step's package and give the data its seed is rendered
|
|
@@ -242,6 +252,9 @@ export async function composeStepSeed(args) {
|
|
|
242
252
|
* so an edit during a run reaches each later step, and two steps of one run
|
|
243
253
|
* can carry different copies.
|
|
244
254
|
*
|
|
255
|
+
* The contract of the template a grounded step renders is read here too, from
|
|
256
|
+
* the knowledge client, and the plan settings are bound to it.
|
|
257
|
+
*
|
|
245
258
|
* A read failure throws (house rules): a swallowed error would be frozen into
|
|
246
259
|
* the checkpointed seed and served to every replay of this step.
|
|
247
260
|
*/
|
|
@@ -282,12 +295,149 @@ export async function gatherStepPackage(args) {
|
|
|
282
295
|
agentByStepId: input.agentByStepId,
|
|
283
296
|
pool: deps.pool,
|
|
284
297
|
});
|
|
298
|
+
const contract = await resolveTemplateContract(step, deps.knowledge);
|
|
299
|
+
return {
|
|
300
|
+
briefing: {
|
|
301
|
+
step,
|
|
302
|
+
workspace,
|
|
303
|
+
profile: profile?.result ?? null,
|
|
304
|
+
upstream,
|
|
305
|
+
memory: { goal: memory.goal, constraints: memory.constraints },
|
|
306
|
+
...contract.briefing,
|
|
307
|
+
},
|
|
308
|
+
templateBinding: contract.binding,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
/** A served contract carries no `match`; the two refusals do. */
|
|
312
|
+
function isTemplateContract(answer) {
|
|
313
|
+
return !("match" in answer);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Fetch the contract of the template a step grounds on, and bind the plan
|
|
317
|
+
* settings to it. A step without a template has no template part. A step
|
|
318
|
+
* with one and no way to read it (no client, no answer, or an unknown
|
|
319
|
+
* template) gets the reason, thus the seed reports the absence rather than
|
|
320
|
+
* hiding it, and no binding.
|
|
321
|
+
*/
|
|
322
|
+
async function resolveTemplateContract(step, client) {
|
|
323
|
+
const ref = step.grounding?.template;
|
|
324
|
+
if (!ref)
|
|
325
|
+
return { briefing: {} };
|
|
326
|
+
if (!client)
|
|
327
|
+
return { briefing: { templateNotRetrieved: "no knowledge client is bound" } };
|
|
328
|
+
const answer = await client.contract(ref);
|
|
329
|
+
if (!isTemplateContract(answer)) {
|
|
330
|
+
const reason = answer.match === "unavailable"
|
|
331
|
+
? `the knowledge service did not answer: ${answer.reason}`
|
|
332
|
+
: `the knowledge service refused the lookup: ${answer.message}`;
|
|
333
|
+
return { briefing: { templateNotRetrieved: reason } };
|
|
334
|
+
}
|
|
335
|
+
return bindTemplateContract(ref, answer, step.grounding?.settings ?? [], {
|
|
336
|
+
stepId: step.id,
|
|
337
|
+
claims: step.grounding?.claims ?? [],
|
|
338
|
+
snapshot: step.grounding?.snapshot && step.grounding.snapshot !== "none" ? step.grounding.snapshot : undefined,
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
/** The version of a template reference (`tpl-x@1.0.0` gives `1.0.0`), or `undefined` when the reference has none. */
|
|
342
|
+
function versionOfRef(ref) {
|
|
343
|
+
const at = ref.indexOf("@");
|
|
344
|
+
return at < 0 ? undefined : ref.slice(at + 1);
|
|
345
|
+
}
|
|
346
|
+
/** Two setting values agree when their JSON agrees: the values are scalars or lists of strings. */
|
|
347
|
+
function sameSettingValue(a, b) {
|
|
348
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Whether a plan value is a value of the slot, and not a policy word. A
|
|
352
|
+
* procedure parameter and a template slot share a name, but not always a
|
|
353
|
+
* value domain: `min_samples = smallest_group_size` names a rule the agent
|
|
354
|
+
* applies, and the slot takes the resulting integer. Only a member of the
|
|
355
|
+
* enum of the slot, a number for a number slot, or a boolean for a boolean
|
|
356
|
+
* slot binds. A free-text slot never binds, because the host cannot tell a
|
|
357
|
+
* policy word from a value there.
|
|
358
|
+
*/
|
|
359
|
+
function fitsSlot(slot, value) {
|
|
360
|
+
if (slot.enum)
|
|
361
|
+
return typeof value === "string" && slot.enum.includes(value);
|
|
362
|
+
if (slot.type === "integer" || slot.type === "number")
|
|
363
|
+
return typeof value === "number";
|
|
364
|
+
if (slot.type === "boolean")
|
|
365
|
+
return typeof value === "boolean";
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
function bindTemplateContract(ref, contract, settings, grounding) {
|
|
369
|
+
const refVersion = versionOfRef(ref);
|
|
370
|
+
const versionMatches = refVersion === undefined || refVersion === contract.version;
|
|
371
|
+
const adaptable = contract.parameters.filter((slot) => slot.adaptable);
|
|
372
|
+
const adaptableNames = new Set(adaptable.map((slot) => slot.name));
|
|
373
|
+
const pinnedByName = new Map(contract.parameters.filter((slot) => !slot.adaptable).map((slot) => [slot.name, slot]));
|
|
374
|
+
const bound = [];
|
|
375
|
+
const unbound = [];
|
|
376
|
+
const slots = {};
|
|
377
|
+
const sources = {};
|
|
378
|
+
for (const setting of settings) {
|
|
379
|
+
const shown = `\`${setting.name}\` = ${JSON.stringify(setting.value)} (${setting.step})`;
|
|
380
|
+
if (!versionMatches) {
|
|
381
|
+
unbound.push(`${shown}: not bound, because the served version differs from the plan`);
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
if (adaptableNames.has(setting.name)) {
|
|
385
|
+
const slot = adaptable.find((candidate) => candidate.name === setting.name);
|
|
386
|
+
if (slot && !fitsSlot(slot, setting.value)) {
|
|
387
|
+
unbound.push(`${shown}: a policy of the plan, not a value of the \`${setting.name}\` slot (${slot.type}); state the value it gives`);
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
const prior = slots[setting.name];
|
|
391
|
+
if (prior !== undefined) {
|
|
392
|
+
if (!sameSettingValue(prior, setting.value))
|
|
393
|
+
unbound.push(`${shown}: differs from the bound value ${JSON.stringify(prior)} of the same slot`);
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
slots[setting.name] = setting.value;
|
|
397
|
+
if (setting.source)
|
|
398
|
+
sources[setting.name] = setting.source;
|
|
399
|
+
bound.push({ name: setting.name, value: setting.value, source: setting.source ?? "plan" });
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
const pinned = pinnedByName.get(setting.name);
|
|
403
|
+
if (pinned) {
|
|
404
|
+
const pinnedValue = pinned.default === undefined ? "a fixed value" : JSON.stringify(pinned.default);
|
|
405
|
+
unbound.push(sameSettingValue(pinned.default, setting.value)
|
|
406
|
+
? `${shown}: pinned by the template at the same value`
|
|
407
|
+
: `${shown}: the template pins \`${setting.name}\` at ${pinnedValue}, and the plan value cannot be sent`);
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
unbound.push(`${shown}: no slot of the template carries it`);
|
|
411
|
+
}
|
|
285
412
|
return {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
413
|
+
briefing: {
|
|
414
|
+
template: {
|
|
415
|
+
ref,
|
|
416
|
+
version_served: contract.version,
|
|
417
|
+
slots: adaptable,
|
|
418
|
+
inputs: (contract.inputs ?? []).map((input) => ({
|
|
419
|
+
name: input.name,
|
|
420
|
+
path: input.path,
|
|
421
|
+
description: input.description,
|
|
422
|
+
})),
|
|
423
|
+
bound,
|
|
424
|
+
unbound_settings: unbound,
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
binding: versionMatches
|
|
428
|
+
? {
|
|
429
|
+
template: ref,
|
|
430
|
+
slots,
|
|
431
|
+
sources,
|
|
432
|
+
step: grounding.stepId,
|
|
433
|
+
claims: grounding.claims,
|
|
434
|
+
snapshot: grounding.snapshot,
|
|
435
|
+
// The local slots of the contract, thus the tool binds a path or a column name on the machine
|
|
436
|
+
// without a second read of the contract.
|
|
437
|
+
local: contract.parameters.filter((slot) => slot.local === true),
|
|
438
|
+
adaptable: adaptable.map((slot) => slot.name),
|
|
439
|
+
}
|
|
440
|
+
: undefined,
|
|
291
441
|
};
|
|
292
442
|
}
|
|
293
443
|
/**
|
|
@@ -330,13 +480,10 @@ async function collectUpstreamHandoffs(args) {
|
|
|
330
480
|
* its reason in `blockedReason` — an honest agent-declared blocker, not an
|
|
331
481
|
* error — and a failure carries the same reason string
|
|
332
482
|
* `persist-synthesis-outcome` writes to `cortex_runs.synthesis_reason`, so the
|
|
333
|
-
* two ledgers cannot disagree about why synthesis died.
|
|
334
|
-
*
|
|
335
|
-
* the projection tests (the `buildChildInput` pattern).
|
|
483
|
+
* two ledgers cannot disagree about why synthesis died. Exported for the
|
|
484
|
+
* projection tests (the `buildChildInput` pattern).
|
|
336
485
|
*/
|
|
337
486
|
export function synthesisRowUpdate(outcome, durationMs) {
|
|
338
|
-
if ("kind" in outcome)
|
|
339
|
-
return { status: "canceled", durationMs, error: outcome.reason };
|
|
340
487
|
switch (outcome.status) {
|
|
341
488
|
case "produced":
|
|
342
489
|
return { status: "completed", durationMs };
|
|
@@ -355,9 +502,11 @@ export function synthesisRowUpdate(outcome, durationMs) {
|
|
|
355
502
|
/**
|
|
356
503
|
* Run-level literature-grounded synthesis (no sandbox). Returns the
|
|
357
504
|
* quick-display findings for the run-completed card; empty when synthesis is
|
|
358
|
-
* skipped or produced no synthesizable content. A genuine failure re-throws
|
|
359
|
-
*
|
|
360
|
-
*
|
|
505
|
+
* skipped or produced no synthesizable content. A genuine failure re-throws,
|
|
506
|
+
* failing the run (D10). It runs in the body of the run workflow: each read and
|
|
507
|
+
* write is a step, each model call is a step, and each reviewer call starts a
|
|
508
|
+
* child workflow. Exported so integration tests can drive the wired synthesis
|
|
509
|
+
* without a full parent body.
|
|
361
510
|
*/
|
|
362
511
|
export function synthesizeFindings(args) {
|
|
363
512
|
const { analysisId, runId, completedSteps, session, deps } = args;
|
|
@@ -388,10 +537,9 @@ export function synthesizeFindings(args) {
|
|
|
388
537
|
embedding: deps.embedding,
|
|
389
538
|
resolveWorkspaceRoot: deps.resolveWorkspaceRoot,
|
|
390
539
|
synthesisModel: deps.synthesisModel,
|
|
391
|
-
|
|
392
|
-
citationResolver: deps.citationResolver,
|
|
540
|
+
literatureReviewer: deps.literatureReviewer,
|
|
393
541
|
usageRecorder: deps.usageRecorder,
|
|
394
|
-
|
|
542
|
+
toolOutputStore: deps.toolOutputStore,
|
|
395
543
|
}, {
|
|
396
544
|
analysisId,
|
|
397
545
|
runId,
|
|
@@ -408,9 +556,10 @@ export function synthesizeFindings(args) {
|
|
|
408
556
|
// call path.
|
|
409
557
|
session: forStep(session, SYNTHESIS_STEP_ID),
|
|
410
558
|
emit,
|
|
559
|
+
pause: args.pause?.afterFailure,
|
|
560
|
+
durably: (name, run) => DBOS.runStep(run, { name }),
|
|
411
561
|
onProgress: async (phase, activity, extra = {}) => {
|
|
412
|
-
//
|
|
413
|
-
// the step after a crash writes its entries again under the same ids. A reader dedups an entry by id.
|
|
562
|
+
// The body checkpoints the clock and each write, thus a replay writes no entry again.
|
|
414
563
|
const seq = progressSeq++;
|
|
415
564
|
const at = new Date(await DBOS.now()).toISOString();
|
|
416
565
|
const parts = synthesisEmission(runId, SYNTHESIS_STEP_ID, seq, phase, activity, at, extra);
|
|
@@ -448,7 +597,17 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
448
597
|
// the run authorization is already minted and rides in `input.runSession`.
|
|
449
598
|
const runId = input.runSession.runFrame.runId;
|
|
450
599
|
const workflowId = runId;
|
|
451
|
-
const
|
|
600
|
+
const pause = workPause({
|
|
601
|
+
pool: deps.pool,
|
|
602
|
+
workId: runId,
|
|
603
|
+
workKind: "run",
|
|
604
|
+
analysisId: input.analysisId,
|
|
605
|
+
emit: emitStreamPart,
|
|
606
|
+
retryDelaysMs: deps.pauseRetryDelaysMs,
|
|
607
|
+
run: { session: input.runSession, authorizer: deps.runAuthorizer },
|
|
608
|
+
logger,
|
|
609
|
+
});
|
|
610
|
+
const init = await validateAndInit(input, runId, deps, pause);
|
|
452
611
|
if (init.kind === "joined-existing") {
|
|
453
612
|
return {
|
|
454
613
|
runId: init.runId,
|
|
@@ -460,7 +619,6 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
460
619
|
};
|
|
461
620
|
}
|
|
462
621
|
if (init.kind === "charge-refused") {
|
|
463
|
-
const suspension = suspensionOfRefusal(init.refusal) ?? null;
|
|
464
622
|
const refusedAtMs = await DBOS.now();
|
|
465
623
|
const refused = await collectAndComplete({
|
|
466
624
|
input,
|
|
@@ -470,16 +628,13 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
470
628
|
completed: new Set(),
|
|
471
629
|
failed: new Set(),
|
|
472
630
|
canceled: new Set(),
|
|
473
|
-
suspension,
|
|
474
631
|
failureReason: init.refusal.reason,
|
|
475
|
-
forceFailed:
|
|
632
|
+
forceFailed: true,
|
|
476
633
|
findings: [],
|
|
477
634
|
synthesisOutcome: null,
|
|
478
635
|
deps,
|
|
479
636
|
});
|
|
480
637
|
observeRunGuarded(deps, buildRunObservation({ input, runId, status: refused.status, stepStates: new Map() }));
|
|
481
|
-
if (suspension !== null)
|
|
482
|
-
return cancelSelf("self-cancel-suspended");
|
|
483
638
|
return refused;
|
|
484
639
|
}
|
|
485
640
|
// Seed the full DAG as `pending` rows so ledger readers see every step from
|
|
@@ -550,12 +705,11 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
550
705
|
// still run the terminal block (close charge + revoke run authorization), and re-throw
|
|
551
706
|
// after so the workflow record goes to ERROR.
|
|
552
707
|
let synthesisError = null;
|
|
553
|
-
let
|
|
708
|
+
let synthesisMessage;
|
|
554
709
|
let synthesisFindings = [];
|
|
555
710
|
// Null when synthesis never ran (disabled or no completed steps): the ledger
|
|
556
711
|
// columns stay NULL — "unknown", not a recorded skip — and the seeded
|
|
557
|
-
// `synthesis` row (if any) stays `pending` for the terminal sweep.
|
|
558
|
-
// when synthesis suspended: a resume of the run gives the outcome.
|
|
712
|
+
// `synthesis` row (if any) stays `pending` for the terminal sweep.
|
|
559
713
|
let synthesisOutcome = null;
|
|
560
714
|
if (synthesisEnabled && final.completed.size > 0) {
|
|
561
715
|
// Bracketing clock reads for the row's duration_ms — checkpointed, so a
|
|
@@ -575,13 +729,14 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
575
729
|
}));
|
|
576
730
|
let rowOutcome;
|
|
577
731
|
try {
|
|
578
|
-
const synthOut = await
|
|
732
|
+
const synthOut = await synthesizeFindings({
|
|
579
733
|
analysisId: input.analysisId,
|
|
580
734
|
runId,
|
|
581
735
|
completedSteps: [...final.completed],
|
|
582
736
|
session: input.runSession,
|
|
583
737
|
deps,
|
|
584
|
-
|
|
738
|
+
pause,
|
|
739
|
+
});
|
|
585
740
|
synthesisFindings = synthOut.findings;
|
|
586
741
|
synthesisOutcome = { status: synthOut.synthesisStatus, reason: synthOut.synthesisReason };
|
|
587
742
|
rowOutcome = synthesisOutcome;
|
|
@@ -594,20 +749,14 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
594
749
|
// this path either, so the run row is equally non-terminal and the pair
|
|
595
750
|
// stays consistent — the pre-existing cancelled-mid-flight wedge shape
|
|
596
751
|
// `inflexa run` already detects via its DBOS-status cross-check.
|
|
597
|
-
if (err
|
|
752
|
+
if (isWorkflowCancellation(err))
|
|
598
753
|
throw err;
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
}
|
|
605
|
-
else {
|
|
606
|
-
synthesisError = err;
|
|
607
|
-
synthesisOutcome = { status: "failed", reason: err instanceof Error ? err.message : String(err) };
|
|
608
|
-
rowOutcome = synthesisOutcome;
|
|
609
|
-
logger.error("synthesizeFindings failed — failing the run", { runId, ...logger.errorFields(err) });
|
|
610
|
-
}
|
|
754
|
+
// A failure with a cause of a pause waited in the loop of the synthesizer, thus this one fails the run.
|
|
755
|
+
synthesisError = err;
|
|
756
|
+
synthesisMessage = errorMessageOf(err);
|
|
757
|
+
synthesisOutcome = { status: "failed", reason: errorMessageOf(err) ?? textOf(err) };
|
|
758
|
+
rowOutcome = synthesisOutcome;
|
|
759
|
+
logger.error("synthesizeFindings failed — failing the run", { runId, ...logger.errorFields(err) });
|
|
611
760
|
}
|
|
612
761
|
// Terminal stamp for the `synthesis` row — deliberately BEFORE
|
|
613
762
|
// `collectAndComplete` writes the run row's terminal status, so no reader
|
|
@@ -627,7 +776,6 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
627
776
|
// (6) collectAndComplete — terminal block. Runs on EVERY path. When synthesis
|
|
628
777
|
// failed, force a failed terminal status so the charge/run-authorization close correctly
|
|
629
778
|
// and the run row + stream report the failure before we re-throw.
|
|
630
|
-
const suspension = final.suspension ?? synthesisSuspension;
|
|
631
779
|
const result = await collectAndComplete({
|
|
632
780
|
input,
|
|
633
781
|
runId,
|
|
@@ -636,15 +784,8 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
636
784
|
completed: final.completed,
|
|
637
785
|
failed: final.failed,
|
|
638
786
|
canceled: final.canceled,
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
failureReason: synthesisError
|
|
642
|
-
? synthesisError instanceof Error
|
|
643
|
-
? `synthesis-failed: ${synthesisError.message}`
|
|
644
|
-
: "synthesis-failed"
|
|
645
|
-
: final.suspension === null && synthesisSuspension !== null
|
|
646
|
-
? synthesisSuspension.reason
|
|
647
|
-
: final.failureReason,
|
|
787
|
+
usage: final.usage,
|
|
788
|
+
failureReason: synthesisError === null ? final.failureReason : synthesisMessage === undefined ? "synthesis-failed" : `synthesis-failed: ${synthesisMessage}`,
|
|
648
789
|
forceFailed: synthesisError !== null,
|
|
649
790
|
findings: synthesisFindings,
|
|
650
791
|
synthesisOutcome,
|
|
@@ -652,20 +793,15 @@ export async function runExecuteAnalysisBody(input, deps) {
|
|
|
652
793
|
});
|
|
653
794
|
// Terminal snapshot, fired here rather than inside `collectAndComplete` because this is the
|
|
654
795
|
// first point where BOTH the derived final status and the scheduler's final step map are in
|
|
655
|
-
// hand.
|
|
656
|
-
// body, so an observer placed after it would never see a suspended run's last state.
|
|
796
|
+
// hand.
|
|
657
797
|
observeRunGuarded(deps, buildRunObservation({ input, runId, status: result.status, stepStates: final.stepStates }));
|
|
658
|
-
// Synthesis failure takes priority over the suspension cascade: a run whose
|
|
659
|
-
// synthesis threw is definitively failed (ERROR), not a resumable
|
|
660
|
-
// suspension. Only self-cancel when synthesis did not throw a failure.
|
|
661
|
-
if (suspension !== null && synthesisError === null)
|
|
662
|
-
return cancelSelf("self-cancel-suspended");
|
|
663
798
|
// Re-throw after the terminal block so the workflow record goes to ERROR.
|
|
799
|
+
// oxlint-disable-next-line typescript/only-throw-error -- the caught synthesis failure rides as-is so the workflow record fails with the original cause; a wrapper would erase its identity.
|
|
664
800
|
if (synthesisError !== null)
|
|
665
801
|
throw synthesisError;
|
|
666
802
|
return result;
|
|
667
803
|
}
|
|
668
|
-
async function validateAndInit(input, runId, deps) {
|
|
804
|
+
async function validateAndInit(input, runId, deps, pause) {
|
|
669
805
|
// The cortex_runs row already exists (inserted by `executePlan`). Sanity-
|
|
670
806
|
// check that no other active run for the same plan won the race — the
|
|
671
807
|
// partial-unique index would have rejected the insert if so, so this is
|
|
@@ -682,11 +818,17 @@ async function validateAndInit(input, runId, deps) {
|
|
|
682
818
|
recursive: true,
|
|
683
819
|
});
|
|
684
820
|
}, { name: "init-run-filesystem" });
|
|
685
|
-
const
|
|
821
|
+
const openCharge = () => DBOS.runStep(async () => await passGate("RunCharge.open", deps.runCharge.open({
|
|
686
822
|
analysisId: input.analysisId,
|
|
687
823
|
runId,
|
|
688
824
|
session: input.runSession,
|
|
689
825
|
})), { name: "open-running-charge" });
|
|
826
|
+
let opened = await openCharge();
|
|
827
|
+
// A refusal with the suspend flag waits in a pause, and the charge opens again after the resume.
|
|
828
|
+
while (opened.isErr() && opened.error.kind === "suspended") {
|
|
829
|
+
await pauseAtGate(pause, opened.error.reason);
|
|
830
|
+
opened = await openCharge();
|
|
831
|
+
}
|
|
690
832
|
if (opened.isErr())
|
|
691
833
|
return { kind: "charge-refused", refusal: opened.error };
|
|
692
834
|
return { kind: "fresh" };
|
|
@@ -697,14 +839,13 @@ async function runSchedulerLoop(args) {
|
|
|
697
839
|
const failed = new Set();
|
|
698
840
|
const canceled = new Set();
|
|
699
841
|
const inFlight = new Map();
|
|
700
|
-
const childSuspensions = new Map();
|
|
701
842
|
// Run-level usage aggregate, folded from the children's own durable results.
|
|
702
843
|
// `getResult` IS the replay-safe source: a recovered parent reads back the
|
|
703
844
|
// identical value from each child's workflow record, so the sum reproduces
|
|
704
845
|
// exactly without a second channel. A child that settled by throwing carries
|
|
705
846
|
// no result and therefore contributes nothing — same rule as its duration.
|
|
706
847
|
const runUsage = {};
|
|
707
|
-
// Child workflow ids the parent itself cancelled (
|
|
848
|
+
// Child workflow ids the parent itself cancelled (the neverFits halt cascade). Their `getResult`
|
|
708
849
|
// rejects with a DBOS cancellation error and lands in the settlement error branch — but the step was
|
|
709
850
|
// CANCELED by us, not failed on its own merits. Keyed here (deterministic: `cancelInFlight` runs the
|
|
710
851
|
// same way on a replay) so that branch records it as canceled everywhere, matching how a child that
|
|
@@ -738,26 +879,18 @@ async function runSchedulerLoop(args) {
|
|
|
738
879
|
const stack = [...(dependentsByStepId.get(failedStepId) ?? [])];
|
|
739
880
|
while (stack.length > 0) {
|
|
740
881
|
const id = stack.pop();
|
|
741
|
-
if (
|
|
882
|
+
if (id === undefined)
|
|
883
|
+
break;
|
|
884
|
+
if (presentGet(stepRuntime, id, "the runtime of the step").status === "pending") {
|
|
742
885
|
stepRuntime.set(id, { status: "skipped" });
|
|
743
886
|
stack.push(...(dependentsByStepId.get(id) ?? []));
|
|
744
887
|
}
|
|
745
888
|
}
|
|
746
889
|
};
|
|
747
|
-
// Halts scheduling entirely — reserved for
|
|
748
|
-
//
|
|
749
|
-
// only that step's transitive dependents.
|
|
890
|
+
// Halts scheduling entirely — reserved for the `neverFits` guard. An ordinary
|
|
891
|
+
// step failure does NOT set it: it dooms only that step's transitive dependents.
|
|
750
892
|
let halted = false;
|
|
751
|
-
let suspension = null;
|
|
752
893
|
let failureReason = null;
|
|
753
|
-
const haltForSuspension = async (child) => {
|
|
754
|
-
if (suspension === null) {
|
|
755
|
-
suspension = { kind: "suspended", reason: child.reason };
|
|
756
|
-
halted = true;
|
|
757
|
-
failureReason = child.reason;
|
|
758
|
-
}
|
|
759
|
-
await cancelInFlight(inFlight, child.reason, canceledByParent);
|
|
760
|
-
};
|
|
761
894
|
const stepIndexById = new Map(input.steps.map((s, i) => [s.id, i]));
|
|
762
895
|
const emitDagSnapshot = async () => {
|
|
763
896
|
await emitStreamPart({
|
|
@@ -765,7 +898,7 @@ async function runSchedulerLoop(args) {
|
|
|
765
898
|
id: `dag-${runId}`,
|
|
766
899
|
runId,
|
|
767
900
|
steps: input.steps.map((s) => {
|
|
768
|
-
const rt = stepRuntime
|
|
901
|
+
const rt = presentGet(stepRuntime, s.id, "the runtime of the step");
|
|
769
902
|
const entry = {
|
|
770
903
|
id: s.id,
|
|
771
904
|
// `input.steps` is the SCHEDULER's projection — `{id, depends_on}` and nothing
|
|
@@ -798,7 +931,6 @@ async function runSchedulerLoop(args) {
|
|
|
798
931
|
// the body once `collectAndComplete` has derived the final status.
|
|
799
932
|
observeRunGuarded(deps, buildRunObservation({ input, runId, status: "running", stepStates: stepRuntime }));
|
|
800
933
|
};
|
|
801
|
-
const dbosParentId = DBOS.workflowID ?? workflowId;
|
|
802
934
|
const dispatchReady = async () => {
|
|
803
935
|
if (halted)
|
|
804
936
|
return;
|
|
@@ -832,13 +964,13 @@ async function runSchedulerLoop(args) {
|
|
|
832
964
|
});
|
|
833
965
|
}
|
|
834
966
|
halted = true;
|
|
835
|
-
failureReason = `step "${scheduled.neverFits[0]}" exceeds the machine resource budget`;
|
|
967
|
+
failureReason = `step "${String(scheduled.neverFits[0])}" exceeds the machine resource budget`;
|
|
836
968
|
await cancelInFlight(inFlight, "fail_fast", canceledByParent);
|
|
837
969
|
await emitDagSnapshot();
|
|
838
970
|
return;
|
|
839
971
|
}
|
|
840
972
|
for (const stepId of scheduled.heldForCapacity) {
|
|
841
|
-
if (stepRuntime
|
|
973
|
+
if (presentGet(stepRuntime, stepId, "the runtime of the step").status !== "queued") {
|
|
842
974
|
stepRuntime.set(stepId, { status: "queued" });
|
|
843
975
|
queuedChanged = true;
|
|
844
976
|
}
|
|
@@ -854,33 +986,35 @@ async function runSchedulerLoop(args) {
|
|
|
854
986
|
return;
|
|
855
987
|
}
|
|
856
988
|
for (const stepId of admit) {
|
|
857
|
-
const idx = stepIndexById
|
|
989
|
+
const idx = presentGet(stepIndexById, stepId, "the index of the step");
|
|
858
990
|
const childWorkflowId = `${workflowId}-${idx}`;
|
|
859
991
|
// Compose the seed HERE — the dependencies of `stepId` are all in
|
|
860
992
|
// `completed`, so this is the first (and only) moment their results
|
|
861
993
|
// can be named. Checkpointed so a replay re-dispatches the child
|
|
862
994
|
// with a byte-identical prompt instead of re-reading the DB/disk.
|
|
863
995
|
const seedStepName = `compose-step-seed:${stepId}`;
|
|
864
|
-
const
|
|
996
|
+
const checkpointed = await DBOS.runStep(() => {
|
|
865
997
|
stableSpan(seedStepName, "compose-step-seed", { [ATTR_INFLEXA_STEP_ID]: stepId });
|
|
866
998
|
return composeStepSeed({ input, stepId, runId, deps });
|
|
867
999
|
}, { name: seedStepName });
|
|
1000
|
+
// A run recovered from a checkpoint written when this step returned the
|
|
1001
|
+
// bare seed string replays that string: it carries no binding.
|
|
1002
|
+
const seed = typeof checkpointed === "string" ? { prompt: checkpointed } : checkpointed;
|
|
868
1003
|
const baseChildInput = buildChildInput({
|
|
869
1004
|
input,
|
|
870
1005
|
stepId,
|
|
871
1006
|
level: levels.get(stepId) ?? 0,
|
|
872
1007
|
runId,
|
|
873
|
-
|
|
874
|
-
|
|
1008
|
+
prompt: seed.prompt,
|
|
1009
|
+
templateBinding: seed.templateBinding,
|
|
875
1010
|
});
|
|
876
1011
|
const childInput = {
|
|
877
1012
|
...baseChildInput,
|
|
878
|
-
parentWorkflowId: dbosParentId,
|
|
879
1013
|
runSession: forStep(input.runSession, stepId),
|
|
880
1014
|
};
|
|
881
|
-
const handle =
|
|
1015
|
+
const handle = await DBOS.startWorkflow(deps.sandboxStepCallable, {
|
|
882
1016
|
workflowID: childWorkflowId,
|
|
883
|
-
})(childInput)
|
|
1017
|
+
})(childInput);
|
|
884
1018
|
inFlight.set(childWorkflowId, { stepId, handle });
|
|
885
1019
|
stepRuntime.set(stepId, { status: "running" });
|
|
886
1020
|
}
|
|
@@ -894,7 +1028,7 @@ async function runSchedulerLoop(args) {
|
|
|
894
1028
|
// function-ID-consuming ops and diverge the counter on replay.
|
|
895
1029
|
const winner = await DBOS.waitFirst([...inFlight.values()].map((e) => e.handle));
|
|
896
1030
|
const childId = winner.workflowID;
|
|
897
|
-
const entry = inFlight
|
|
1031
|
+
const entry = presentGet(inFlight, childId, "the in-flight entry of the winning child");
|
|
898
1032
|
inFlight.delete(childId);
|
|
899
1033
|
let settled;
|
|
900
1034
|
try {
|
|
@@ -904,8 +1038,6 @@ async function runSchedulerLoop(args) {
|
|
|
904
1038
|
catch (err) {
|
|
905
1039
|
settled = { childId, stepId: entry.stepId, kind: "error", err };
|
|
906
1040
|
}
|
|
907
|
-
await drainChildSuspensions(childSuspensions);
|
|
908
|
-
const childSuspension = childSuspensions.get(settled.childId);
|
|
909
1041
|
// Terminal step status + duration for the provenance emission below. Every
|
|
910
1042
|
// settlement branch assigns both, so the emission fires exactly once per
|
|
911
1043
|
// settled child with the mapped status.
|
|
@@ -918,24 +1050,22 @@ async function runSchedulerLoop(args) {
|
|
|
918
1050
|
completed.add(settled.stepId);
|
|
919
1051
|
stepRuntime.set(settled.stepId, {
|
|
920
1052
|
status: "completed",
|
|
921
|
-
durationMs: r.durationMs
|
|
1053
|
+
durationMs: r.durationMs,
|
|
922
1054
|
});
|
|
923
1055
|
stepStatus = "completed";
|
|
924
|
-
stepDurationMs = r.durationMs
|
|
1056
|
+
stepDurationMs = r.durationMs;
|
|
925
1057
|
await emitDagSnapshot();
|
|
926
1058
|
await dispatchReady();
|
|
927
1059
|
}
|
|
928
1060
|
else if (r.status === "canceled") {
|
|
929
1061
|
canceled.add(settled.stepId);
|
|
930
|
-
if (childSuspension !== undefined)
|
|
931
|
-
await haltForSuspension(childSuspension);
|
|
932
1062
|
stepRuntime.set(settled.stepId, {
|
|
933
1063
|
status: "failed",
|
|
934
|
-
durationMs: r.durationMs
|
|
1064
|
+
durationMs: r.durationMs,
|
|
935
1065
|
error: r.error ?? "canceled",
|
|
936
1066
|
});
|
|
937
1067
|
stepStatus = "canceled";
|
|
938
|
-
stepDurationMs = r.durationMs
|
|
1068
|
+
stepDurationMs = r.durationMs;
|
|
939
1069
|
await emitDagSnapshot();
|
|
940
1070
|
}
|
|
941
1071
|
else {
|
|
@@ -948,18 +1078,18 @@ async function runSchedulerLoop(args) {
|
|
|
948
1078
|
failureReason ??= r.error ?? (r.status === "blocked" ? "step_blocked" : "step_failed");
|
|
949
1079
|
stepRuntime.set(settled.stepId, {
|
|
950
1080
|
status: "failed",
|
|
951
|
-
durationMs: r.durationMs
|
|
1081
|
+
durationMs: r.durationMs,
|
|
952
1082
|
error: r.error ?? (r.status === "blocked" ? "step_blocked" : "step_failed"),
|
|
953
1083
|
});
|
|
954
1084
|
markDependentsSkipped(settled.stepId);
|
|
955
1085
|
stepStatus = "failed";
|
|
956
|
-
stepDurationMs = r.durationMs
|
|
1086
|
+
stepDurationMs = r.durationMs;
|
|
957
1087
|
await emitDagSnapshot();
|
|
958
1088
|
await dispatchReady();
|
|
959
1089
|
}
|
|
960
1090
|
}
|
|
961
1091
|
else if (canceledByParent.has(settled.childId)) {
|
|
962
|
-
// The child threw because the PARENT cancelled it (
|
|
1092
|
+
// The child threw because the PARENT cancelled it (the neverFits halt cascade), not
|
|
963
1093
|
// because it failed on its own — its `getResult` rejects with a DBOS cancellation error.
|
|
964
1094
|
// Record it as canceled, mirroring the graceful `{status:"canceled"}` branch above so the
|
|
965
1095
|
// `canceled` set, the terminal result, and the `step_completed` provenance all agree. No
|
|
@@ -969,34 +1099,22 @@ async function runSchedulerLoop(args) {
|
|
|
969
1099
|
// `stepRuntime` (the DAG snapshot) has no canceled tier; the graceful-cancel branch above
|
|
970
1100
|
// likewise renders canceled steps as "failed", so this stays consistent with it.
|
|
971
1101
|
status: "failed",
|
|
972
|
-
error: settled.err
|
|
1102
|
+
error: errorMessageOf(settled.err) ?? textOf(settled.err),
|
|
973
1103
|
});
|
|
974
1104
|
stepStatus = "canceled";
|
|
975
1105
|
stepDurationMs = undefined;
|
|
976
1106
|
await emitDagSnapshot();
|
|
977
1107
|
}
|
|
978
|
-
else if (childSuspension !== undefined) {
|
|
979
|
-
// The child suspended: it sent its typed suspension, then cancelled
|
|
980
|
-
// itself, thus `getResult` rejects with a DBOS cancellation. The
|
|
981
|
-
// suspension halts the run — the cascade is a decision of the host,
|
|
982
|
-
// not a DAG one — and it dooms no dependent: the resumed run needs them.
|
|
983
|
-
canceled.add(settled.stepId);
|
|
984
|
-
await haltForSuspension(childSuspension);
|
|
985
|
-
stepRuntime.set(settled.stepId, { status: "failed", error: childSuspension.reason });
|
|
986
|
-
stepStatus = "canceled";
|
|
987
|
-
stepDurationMs = undefined;
|
|
988
|
-
await emitDagSnapshot();
|
|
989
|
-
}
|
|
990
1108
|
else {
|
|
991
|
-
// The child threw on its own (not a parent-driven cancel
|
|
992
|
-
//
|
|
1109
|
+
// The child threw on its own (not a parent-driven cancel). A throw is
|
|
1110
|
+
// treated exactly like a step failure:
|
|
993
1111
|
// dependents doomed, siblings continue.
|
|
994
1112
|
failed.add(settled.stepId);
|
|
995
|
-
failureReason ??= settled.err
|
|
1113
|
+
failureReason ??= errorMessageOf(settled.err) ?? textOf(settled.err);
|
|
996
1114
|
markDependentsSkipped(settled.stepId);
|
|
997
1115
|
stepRuntime.set(settled.stepId, {
|
|
998
1116
|
status: "failed",
|
|
999
|
-
error: settled.err
|
|
1117
|
+
error: errorMessageOf(settled.err) ?? textOf(settled.err),
|
|
1000
1118
|
});
|
|
1001
1119
|
stepStatus = "failed";
|
|
1002
1120
|
// A child that settled by throwing carries no durable duration.
|
|
@@ -1017,30 +1135,19 @@ async function runSchedulerLoop(args) {
|
|
|
1017
1135
|
runId,
|
|
1018
1136
|
stepId: settled.stepId,
|
|
1019
1137
|
status: stepStatus,
|
|
1020
|
-
|
|
1138
|
+
durationMs: stepDurationMs,
|
|
1021
1139
|
atMs: settledAtMs,
|
|
1022
1140
|
}, input.runSession);
|
|
1023
1141
|
}
|
|
1024
|
-
await drainChildSuspensions(childSuspensions);
|
|
1025
1142
|
return {
|
|
1026
1143
|
completed,
|
|
1027
1144
|
failed,
|
|
1028
1145
|
canceled,
|
|
1029
|
-
suspension,
|
|
1030
1146
|
failureReason,
|
|
1031
1147
|
stepStates: stepRuntime,
|
|
1032
|
-
|
|
1148
|
+
usage: hasReportedUsage(runUsage) ? { ...runUsage } : undefined,
|
|
1033
1149
|
};
|
|
1034
1150
|
}
|
|
1035
|
-
async function drainChildSuspensions(suspensions) {
|
|
1036
|
-
while (true) {
|
|
1037
|
-
const msg = await DBOS.recv(CHILD_SUSPENDED_TOPIC, 0);
|
|
1038
|
-
if (!msg)
|
|
1039
|
-
return;
|
|
1040
|
-
if (msg.kind === "suspended" && !suspensions.has(msg.childWorkflowId))
|
|
1041
|
-
suspensions.set(msg.childWorkflowId, msg);
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
1151
|
async function cancelInFlight(inFlight, cause, canceledByParent) {
|
|
1045
1152
|
const ids = [...inFlight.keys()];
|
|
1046
1153
|
// Record every id BEFORE the cancel so the settlement loop classifies the resulting
|
|
@@ -1052,10 +1159,11 @@ async function cancelInFlight(inFlight, cause, canceledByParent) {
|
|
|
1052
1159
|
recordCancelledChild({ cause });
|
|
1053
1160
|
}
|
|
1054
1161
|
}
|
|
1162
|
+
// ── (6) collectAndComplete ────────────────────────────────────────────
|
|
1163
|
+
/** The waits between the attempts are 1, 2, 4, and 8 seconds. */
|
|
1164
|
+
const FINAL_STATUS_WRITE_RETRY = { retriesAllowed: true, maxAttempts: 5, intervalSeconds: 1, backoffRate: 2 };
|
|
1055
1165
|
async function collectAndComplete(args) {
|
|
1056
|
-
const { input, runId, workflowId, startedAtMs, completed, failed, canceled,
|
|
1057
|
-
// A forced failure is terminal and never a resumable suspension.
|
|
1058
|
-
const suspended = suspension !== null && !forceFailed ? suspension : null;
|
|
1166
|
+
const { input, runId, workflowId, startedAtMs, completed, failed, canceled, failureReason, forceFailed, deps } = args;
|
|
1059
1167
|
const logger = (deps.logger ?? createNoopLogger()).named("executeAnalysis").with({ runId, analysisId: input.analysisId });
|
|
1060
1168
|
const status = forceFailed
|
|
1061
1169
|
? "failed"
|
|
@@ -1064,34 +1172,12 @@ async function collectAndComplete(args) {
|
|
|
1064
1172
|
completed,
|
|
1065
1173
|
failed,
|
|
1066
1174
|
canceled,
|
|
1067
|
-
suspended: suspended !== null,
|
|
1068
1175
|
});
|
|
1069
|
-
const chargeOutcome = status === "completed" || status === "partial"
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
? { kind: "error" }
|
|
1073
|
-
: suspended !== null
|
|
1074
|
-
? { kind: "suspended", reason: suspended.reason }
|
|
1075
|
-
: { kind: "canceled" };
|
|
1076
|
-
const revokeReason = status === "completed" || status === "partial"
|
|
1077
|
-
? "workflow-completed"
|
|
1078
|
-
: status === "failed"
|
|
1079
|
-
? "workflow-failed"
|
|
1080
|
-
: suspended !== null
|
|
1081
|
-
? "workflow-suspended"
|
|
1082
|
-
: "workflow-canceled";
|
|
1083
|
-
// Terminal clock read + run-completion provenance, emitted BEFORE the `cortex_runs`
|
|
1084
|
-
// status write below — and thus before any of the terminal cleanup steps. The CLI
|
|
1085
|
-
// watches the run by POLLING that row (`run.ts` `waitForRunTerminal`) and shuts down
|
|
1086
|
-
// the instant it leaves `running`, flushing provenance and then `process.exit()`ing;
|
|
1087
|
-
// emitting the record only after the status write races that shutdown and can drop
|
|
1088
|
-
// the run's terminal provenance entirely. Emitting first makes the record dirty
|
|
1089
|
-
// (synchronously, via the bus) before the row can be observed terminal, so the CLI's
|
|
1090
|
-
// flush always captures it. Not step-wrapped — a DBOS recovery replay must re-fire it;
|
|
1091
|
-
// `DBOS.now()` is checkpointed, so the span stays replay-stable (see `RunProvenanceEvent`).
|
|
1092
|
-
// The duration measures from the `run_started` read threaded in as `startedAtMs`.
|
|
1176
|
+
const chargeOutcome = status === "completed" || status === "partial" ? { kind: "ok" } : status === "failed" ? { kind: "error" } : { kind: "canceled" };
|
|
1177
|
+
const revokeReason = status === "completed" || status === "partial" ? "workflow-completed" : status === "failed" ? "workflow-failed" : "workflow-canceled";
|
|
1178
|
+
const finalError = failureReason ?? (status === "canceled" ? "external_cancel" : null);
|
|
1093
1179
|
const terminalAtMs = await DBOS.now();
|
|
1094
|
-
emitProvenanceGuarded(deps, {
|
|
1180
|
+
const emitRunEnd = () => emitProvenanceGuarded(deps, {
|
|
1095
1181
|
type: "run_completed",
|
|
1096
1182
|
analysisId: input.analysisId,
|
|
1097
1183
|
runId,
|
|
@@ -1099,12 +1185,53 @@ async function collectAndComplete(args) {
|
|
|
1099
1185
|
atMs: terminalAtMs,
|
|
1100
1186
|
durationMs: terminalAtMs - startedAtMs,
|
|
1101
1187
|
}, input.runSession);
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1188
|
+
const closeCharge = () => deliverNotice(logger.with({ chargeOutcome: chargeOutcome.kind }), "RunCharge.close", deps.runCharge.close({
|
|
1189
|
+
analysisId: input.analysisId,
|
|
1190
|
+
runId,
|
|
1191
|
+
outcome: chargeOutcome,
|
|
1192
|
+
session: input.runSession,
|
|
1193
|
+
}));
|
|
1194
|
+
const revokeAuthorization = () => deliverNotice(logger.with({ revokeReason }), "RunAuthorizer.revoke", deps.runAuthorizer.revoke(input.runSession, revokeReason));
|
|
1195
|
+
// The writer that wins the row owns the run end: the `run_completed` emit, the charge close,
|
|
1196
|
+
// and the revoke. The step does all three when its write changes the row. An engine cancel
|
|
1197
|
+
// cannot stop a step that started, so a won write is never cut before these acts.
|
|
1198
|
+
//
|
|
1199
|
+
// The emit rides inside the transaction of the write. The update holds the row lock until the
|
|
1200
|
+
// commit, so the run canceler waits and then loses, and no reader sees the terminal row before
|
|
1201
|
+
// the emit. The cli polls the row and flushes the provenance when it leaves `running`; an emit
|
|
1202
|
+
// after the commit can miss that flush. `emitRunEvent` returns `void`, so the emit completes before the commit.
|
|
1203
|
+
//
|
|
1204
|
+
// DBOS retries only a thrown error, so an attempt before the last throws on a failed transaction.
|
|
1205
|
+
// The last attempt returns "failed" instead: the body takes the failed path with no `try`, and a
|
|
1206
|
+
// failure of DBOS to record a won step cannot be mistaken for a failed write. A commit can fail
|
|
1207
|
+
// after the emit, so `emittedInStep` keeps the later attempts from emitting again.
|
|
1208
|
+
// The `undefined` in the annotation exists only because control-flow analysis cannot see the closure assignment; no code may depend on the initial state.
|
|
1209
|
+
let emittedInStep;
|
|
1210
|
+
const finalWrite = await DBOS.runStep(async () => {
|
|
1211
|
+
const stepLog = logger.with({ status }).named("persist-final-status");
|
|
1212
|
+
const written = await withTransaction(deps.pool, "runs.persistFinalStatus", (client) => updateRunStatus(client, runId, status, finalError).map((changed) => {
|
|
1213
|
+
if (changed && !emittedInStep) {
|
|
1214
|
+
emitRunEnd();
|
|
1215
|
+
emittedInStep = true;
|
|
1216
|
+
}
|
|
1217
|
+
return changed;
|
|
1218
|
+
}));
|
|
1219
|
+
if (written.isErr()) {
|
|
1220
|
+
const attempt = DBOS.stepStatus;
|
|
1221
|
+
const isLastAttempt = attempt?.currentAttempt === undefined || attempt.maxAttempts === undefined || attempt.currentAttempt >= attempt.maxAttempts;
|
|
1222
|
+
const failure = { error: describeDbError(written.error), ...stepLog.errorFields(written.error.cause) };
|
|
1223
|
+
if (isLastAttempt) {
|
|
1224
|
+
stepLog.error("ledger write failed", failure);
|
|
1225
|
+
return "failed";
|
|
1226
|
+
}
|
|
1227
|
+
stepLog.warn("ledger write failed, the step retries", { ...failure, attempt: attempt.currentAttempt });
|
|
1228
|
+
throw new Error(`ledger write failed: ${describeDbError(written.error)}`, { cause: written.error.cause });
|
|
1229
|
+
}
|
|
1230
|
+
// A refused write means an earlier write already set a terminal status: the run
|
|
1231
|
+
// canceler's, or an earlier run of this step before a crash. That writer owns the run end.
|
|
1232
|
+
if (!written.value)
|
|
1233
|
+
return "refused";
|
|
1234
|
+
// DBOS caches the step, so a recovered body records nothing again. A step's own terminal
|
|
1108
1235
|
// row already carried its metric; the residue counted here is every settled step
|
|
1109
1236
|
// without one — a child the cancel cut before `mark-canceled` (the cancel check runs
|
|
1110
1237
|
// before a step body), or one that died before `failStep`. The ledger read is kept
|
|
@@ -1121,8 +1248,41 @@ async function collectAndComplete(args) {
|
|
|
1121
1248
|
recordStepCompleted({ agentId: row.agentId, status: "failed" });
|
|
1122
1249
|
}
|
|
1123
1250
|
recordRunCompleted({ workflow: "analysis", status, durationMs: terminalAtMs - startedAtMs });
|
|
1124
|
-
|
|
1125
|
-
|
|
1251
|
+
await closeCharge();
|
|
1252
|
+
await revokeAuthorization();
|
|
1253
|
+
return "won";
|
|
1254
|
+
}, { name: "persist-final-status", ...FINAL_STATUS_WRITE_RETRY });
|
|
1255
|
+
// A refused write leaves two owners. When the canceler won, its engine cancel came before its
|
|
1256
|
+
// write, so `close-running-charge` throws the cancel and the body does no act of the run end.
|
|
1257
|
+
// When a recovery runs the status step again after its own write landed, no cancel occurred and
|
|
1258
|
+
// the body completes the run end here. A failed write leaves the row `running` with no owner,
|
|
1259
|
+
// and the body still closes and revokes.
|
|
1260
|
+
let closed = false;
|
|
1261
|
+
let revoked = false;
|
|
1262
|
+
if (finalWrite !== "won") {
|
|
1263
|
+
closed = await DBOS.runStep(closeCharge, { name: "close-running-charge" });
|
|
1264
|
+
revoked = await DBOS.runStep(revokeAuthorization, { name: "revoke-run-auth" });
|
|
1265
|
+
}
|
|
1266
|
+
// The step emits only in the execution that ran it. A won step that DBOS gives from the cache
|
|
1267
|
+
// did not run, and a refused or failed write did not emit; the body fires the run end here
|
|
1268
|
+
// with the same checkpointed values. It is not step-wrapped, so a recovery replay fires it again.
|
|
1269
|
+
if (!emittedInStep)
|
|
1270
|
+
emitRunEnd();
|
|
1271
|
+
// After a failed write the row is not terminal, so the body records its run end for the run
|
|
1272
|
+
// canceler. The record comes after the acts: a cancel before it stops the body and the canceler
|
|
1273
|
+
// then owns the run end. A cancel is the only error that goes back to DBOS; a failed record must
|
|
1274
|
+
// not undo an otherwise-complete run, like the sibling terminal steps.
|
|
1275
|
+
if (finalWrite === "failed") {
|
|
1276
|
+
const recorded = { status, error: finalError, closed, revoked };
|
|
1277
|
+
try {
|
|
1278
|
+
await DBOS.setEvent(RUN_END_EVENT_KEY, recorded);
|
|
1279
|
+
}
|
|
1280
|
+
catch (error) {
|
|
1281
|
+
if (isWorkflowCancellation(error))
|
|
1282
|
+
throw error;
|
|
1283
|
+
logger.error("run end record failed, the run canceler acts as for a run with no record", { status, ...logger.errorFields(error) });
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1126
1286
|
// Record the run's synthesis outcome AFTER the status write — a reader that
|
|
1127
1287
|
// sees a terminal status then also sees whether (and why) synthesis ran. A
|
|
1128
1288
|
// null outcome means synthesis never ran; leave the columns NULL ("unknown").
|
|
@@ -1132,40 +1292,17 @@ async function collectAndComplete(args) {
|
|
|
1132
1292
|
if (outcome !== null) {
|
|
1133
1293
|
await ledgerStep(logger.with({ synthesisStatus: outcome.status }), "persist-synthesis-outcome", () => setRunSynthesisOutcome(deps.pool, runId, outcome.status, outcome.reason));
|
|
1134
1294
|
}
|
|
1135
|
-
// Sweep never-started steps to `skipped
|
|
1136
|
-
|
|
1137
|
-
//
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
await ledgerStep(logger, "sweep-pending-steps", () => sweepPendingStepExecutions(deps.pool, runId));
|
|
1141
|
-
}
|
|
1142
|
-
if (suspended !== null) {
|
|
1143
|
-
await ledgerStep(logger, "suspend-analysis", () => suspendAnalysisQuery(deps.pool, input.analysisId));
|
|
1144
|
-
}
|
|
1145
|
-
await DBOS.runStep(() => deliverNotice(logger.with({ chargeOutcome: chargeOutcome.kind }), "RunCharge.close", deps.runCharge.close({
|
|
1146
|
-
analysisId: input.analysisId,
|
|
1147
|
-
runId,
|
|
1148
|
-
outcome: chargeOutcome,
|
|
1149
|
-
session: input.runSession,
|
|
1150
|
-
})), { name: "close-running-charge" });
|
|
1151
|
-
// Revoke the run authorization for the terminal run state. Ownership
|
|
1152
|
-
// defaults to true for inputs persisted before the field existed (a
|
|
1153
|
-
// workflow recovered across this deploy) — those were always Cortex-owned.
|
|
1154
|
-
const authorization = {
|
|
1155
|
-
runSession: input.runSession,
|
|
1156
|
-
ownsMandate: input.ownsMandate ?? true, // oss-core-managed-ok
|
|
1157
|
-
};
|
|
1158
|
-
await DBOS.runStep(() => deliverNotice(logger.with({ revokeReason }), "RunAuthorizer.revoke", deps.runAuthorizer.revoke(authorization, revokeReason)), {
|
|
1159
|
-
name: "revoke-run-auth",
|
|
1160
|
-
});
|
|
1161
|
-
// The `run_completed` provenance was already emitted above (before the status write, to
|
|
1162
|
-
// beat the CLI's poll-and-shutdown). These branches only fan out the UI stream part, whose
|
|
1295
|
+
// Sweep never-started steps to `skipped`. Log-don't-rollback, like every other finalisation step here.
|
|
1296
|
+
await ledgerStep(logger, "sweep-pending-steps", () => sweepPendingStepExecutions(deps.pool, runId));
|
|
1297
|
+
// A step that the neverFits halt canceled in its pause leaves its row, thus the end of the run clears each row of the run.
|
|
1298
|
+
await ledgerStep(logger, "clear-run-pauses", () => clearPausesOfWork(deps.pool, runId));
|
|
1299
|
+
// The run end was emitted above. These branches only fan out the UI stream part, whose
|
|
1163
1300
|
// completed/failed shapes genuinely differ — the provenance record does not.
|
|
1164
1301
|
if (status === "completed" || status === "partial") {
|
|
1165
1302
|
const artifactCount = await DBOS.runStep(async () => await countArtifactsByRuns(deps.pool, input.analysisId, [runId])
|
|
1166
1303
|
.map((counts) => counts[0]?.count ?? 0)
|
|
1167
1304
|
.unwrapOr(0), { name: "count-run-artifacts" });
|
|
1168
|
-
|
|
1305
|
+
const runCompleted = {
|
|
1169
1306
|
type: "data-run-completed",
|
|
1170
1307
|
runId,
|
|
1171
1308
|
status,
|
|
@@ -1176,20 +1313,18 @@ async function collectAndComplete(args) {
|
|
|
1176
1313
|
title: f.title,
|
|
1177
1314
|
confidence: f.confidence,
|
|
1178
1315
|
})),
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
});
|
|
1316
|
+
};
|
|
1317
|
+
if (status === "partial")
|
|
1318
|
+
runCompleted.note = `${completed.size} of ${input.steps.length} steps completed; results are partial.`;
|
|
1319
|
+
if (args.usage)
|
|
1320
|
+
runCompleted.usage = args.usage;
|
|
1321
|
+
await emitStreamPart(runCompleted);
|
|
1186
1322
|
}
|
|
1187
1323
|
else {
|
|
1188
1324
|
await emitStreamPart({
|
|
1189
1325
|
type: "data-run-failed",
|
|
1190
1326
|
runId,
|
|
1191
|
-
error: failureReason ??
|
|
1192
|
-
...(suspended !== null ? { reason: suspended.reason } : {}),
|
|
1327
|
+
error: failureReason ?? "Run canceled before completion",
|
|
1193
1328
|
});
|
|
1194
1329
|
}
|
|
1195
1330
|
return {
|
|
@@ -1208,9 +1343,7 @@ async function collectAndComplete(args) {
|
|
|
1208
1343
|
* status vocabulary without a cast.
|
|
1209
1344
|
*/
|
|
1210
1345
|
function deriveFinalStatus(args) {
|
|
1211
|
-
const { totalSteps, completed, failed, canceled
|
|
1212
|
-
if (suspended)
|
|
1213
|
-
return "suspended_insufficient_funds";
|
|
1346
|
+
const { totalSteps, completed, failed, canceled } = args;
|
|
1214
1347
|
if (failed.size > 0) {
|
|
1215
1348
|
return completed.size > 0 ? "partial" : "failed";
|
|
1216
1349
|
}
|