@bastani/atomic 0.9.5-alpha.7 → 0.9.5-alpha.9
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/CHANGELOG.md +33 -2
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/CHANGELOG.md +17 -0
- package/dist/builtin/intercom/README.md +27 -21
- package/dist/builtin/intercom/broker/broker.ts +3 -6
- package/dist/builtin/intercom/broker/paths.ts +42 -5
- package/dist/builtin/intercom/broker/spawn.ts +78 -10
- package/dist/builtin/intercom/config.ts +6 -3
- package/dist/builtin/intercom/contact-supervisor-tool.ts +6 -4
- package/dist/builtin/intercom/index-heavy.ts +1 -1
- package/dist/builtin/intercom/index.ts +162 -130
- package/dist/builtin/intercom/intercom-tool.ts +9 -3
- package/dist/builtin/intercom/package.json +10 -1
- package/dist/builtin/intercom/result-renderers.ts +1 -1
- package/dist/builtin/intercom/ui/compose.ts +2 -2
- package/dist/builtin/intercom/ui/inline-message.ts +2 -2
- package/dist/builtin/intercom/ui/session-list.ts +2 -2
- package/dist/builtin/mcp/CHANGELOG.md +11 -0
- package/dist/builtin/mcp/README.md +6 -6
- package/dist/builtin/mcp/direct-tools.ts +41 -23
- package/dist/builtin/mcp/index.ts +31 -4
- package/dist/builtin/mcp/init.ts +4 -43
- package/dist/builtin/mcp/metadata-hydration.ts +37 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/mcp/proxy-info-modes.ts +67 -14
- package/dist/builtin/mcp/startup-warmup.ts +98 -0
- package/dist/builtin/mcp/tool-result-renderer.ts +3 -3
- package/dist/builtin/subagents/CHANGELOG.md +18 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.ts +14 -25
- package/dist/builtin/subagents/src/extension/startup-maintenance.ts +89 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +23 -18
- package/dist/builtin/subagents/src/runs/background/result-watcher.ts +20 -10
- package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +13 -3
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +10 -2
- package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +28 -1
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +15 -48
- package/dist/builtin/subagents/src/tui/render-layout.ts +9 -0
- package/dist/builtin/subagents/src/tui/render-widget-graph.ts +27 -25
- package/dist/builtin/subagents/src/tui/render-widget.ts +72 -66
- package/dist/builtin/subagents/src/tui/render.ts +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +29 -0
- package/dist/builtin/workflows/README.md +4 -2
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +3 -1
- package/dist/builtin/workflows/builtin/goal-prompts.ts +23 -2
- package/dist/builtin/workflows/builtin/goal-reducer.ts +21 -0
- package/dist/builtin/workflows/builtin/goal-review.ts +60 -6
- package/dist/builtin/workflows/builtin/goal-runner.ts +71 -22
- package/dist/builtin/workflows/builtin/goal-types.ts +7 -1
- package/dist/builtin/workflows/builtin/ralph-core.ts +52 -4
- package/dist/builtin/workflows/builtin/ralph-review-gate.ts +10 -3
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +23 -2
- package/dist/builtin/workflows/builtin/ralph-runner.ts +38 -16
- package/dist/builtin/workflows/builtin/review-convergence.ts +111 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/create-spec/SKILL.md +2 -0
- package/dist/builtin/workflows/skills/impeccable/SKILL.md +16 -13
- package/dist/builtin/workflows/skills/impeccable/reference/adapt.md +1 -0
- package/dist/builtin/workflows/skills/impeccable/reference/adapt.native.md +58 -0
- package/dist/builtin/workflows/skills/impeccable/reference/android.md +40 -0
- package/dist/builtin/workflows/skills/impeccable/reference/animate.md +2 -0
- package/dist/builtin/workflows/skills/impeccable/reference/audit.md +2 -0
- package/dist/builtin/workflows/skills/impeccable/reference/audit.native.md +139 -0
- package/dist/builtin/workflows/skills/impeccable/reference/bolder.md +69 -62
- package/dist/builtin/workflows/skills/impeccable/reference/critique.md +21 -7
- package/dist/builtin/workflows/skills/impeccable/reference/document.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +92 -0
- package/dist/builtin/workflows/skills/impeccable/reference/init.md +29 -7
- package/dist/builtin/workflows/skills/impeccable/reference/ios.md +45 -0
- package/dist/builtin/workflows/skills/impeccable/reference/layout.md +25 -1
- package/dist/builtin/workflows/skills/impeccable/reference/typeset.md +23 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/context-signals.mjs +2 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/context.mjs +75 -14
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/browser/injected/index.mjs +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/cli/main.mjs +31 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/design-system.mjs +64 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +118 -11
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +16 -11
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/registry/antipatterns.mjs +66 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/rules/checks.mjs +42 -10
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/fonts.mjs +30 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/page.mjs +4 -6
- package/dist/builtin/workflows/skills/impeccable/scripts/hook-admin.mjs +660 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/hook-before-edit.mjs +516 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/hook-lib.mjs +1764 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/hook.mjs +61 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/impeccable-config.mjs +4 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/is-generated.mjs +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/live/svelte-component.mjs +13 -16
- package/dist/builtin/workflows/skills/impeccable/scripts/live-accept.mjs +17 -11
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +104 -37
- package/dist/builtin/workflows/skills/impeccable/scripts/live-wrap.mjs +9 -0
- package/dist/builtin/workflows/src/durable/backend.ts +12 -0
- package/dist/builtin/workflows/src/durable/child-primitive.ts +12 -8
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +63 -2
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +28 -0
- package/dist/builtin/workflows/src/durable/resume-catalog.ts +12 -0
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +5 -2
- package/dist/builtin/workflows/src/durable/stage-primitive.ts +165 -27
- package/dist/builtin/workflows/src/durable/types.ts +30 -1
- package/dist/builtin/workflows/src/engine/primitives/task.ts +1 -0
- package/dist/builtin/workflows/src/engine/run-durable-finalize.ts +1 -2
- package/dist/builtin/workflows/src/engine/run-returned-status.ts +50 -16
- package/dist/builtin/workflows/src/engine/run.ts +32 -32
- package/dist/builtin/workflows/src/engine/runtime.ts +5 -0
- package/dist/builtin/workflows/src/extension/extension-factory.ts +3 -0
- package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +9 -2
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +137 -27
- package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +22 -6
- package/dist/builtin/workflows/src/extension/public-types.ts +1 -1
- package/dist/builtin/workflows/src/extension/workflow-command-completions.ts +13 -1
- package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +19 -4
- package/dist/builtin/workflows/src/extension/workflow-command-surfaces.ts +9 -0
- package/dist/builtin/workflows/src/extension/workflow-prompts.ts +2 -0
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +48 -23
- package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +20 -8
- package/dist/builtin/workflows/src/extension/workflow-tool.ts +24 -8
- package/dist/builtin/workflows/src/runs/background/status.ts +4 -3
- package/dist/builtin/workflows/src/runs/foreground/executor-continuation.ts +13 -3
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +29 -8
- package/dist/builtin/workflows/src/runs/foreground/executor-hil.ts +2 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +4 -3
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +18 -19
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-unresolved-overflow.ts +38 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +155 -20
- package/dist/builtin/workflows/src/runs/shared/worktree-types.ts +6 -0
- package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -1
- package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +18 -1
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +23 -5
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
- package/dist/builtin/workflows/src/shared/returned-run-status.ts +116 -0
- package/dist/builtin/workflows/src/shared/workflow-failures-decisions.ts +2 -0
- package/dist/builtin/workflows/src/tui/graph-view-render-helpers.ts +21 -3
- package/dist/builtin/workflows/src/tui/graph-view-state.ts +3 -0
- package/dist/builtin/workflows/src/tui/graph-view-types.ts +3 -0
- package/dist/builtin/workflows/src/tui/status-list.ts +22 -15
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +4 -4
- package/dist/bun/internal-intercom-broker.d.ts +6 -0
- package/dist/bun/internal-intercom-broker.d.ts.map +1 -0
- package/dist/bun/internal-intercom-broker.js +39 -0
- package/dist/bun/internal-intercom-broker.js.map +1 -0
- package/dist/bun/split-loader.d.ts.map +1 -1
- package/dist/bun/split-loader.js +21 -8
- package/dist/bun/split-loader.js.map +1 -1
- package/dist/core/agent-session-auto-compaction.d.ts +21 -2
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +163 -11
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +10 -1
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +12 -3
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-models.d.ts +2 -2
- package/dist/core/agent-session-models.d.ts.map +1 -1
- package/dist/core/agent-session-models.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +1 -0
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-retry.d.ts +2 -0
- package/dist/core/agent-session-retry.d.ts.map +1 -1
- package/dist/core/agent-session-retry.js +152 -4
- package/dist/core/agent-session-retry.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +15 -1
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +6 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +6 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/context-compaction-runner.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-runner.js +36 -20
- package/dist/core/compaction/context-compaction-runner.js.map +1 -1
- package/dist/core/copilot-anthropic-sse-repair.d.ts +23 -0
- package/dist/core/copilot-anthropic-sse-repair.d.ts.map +1 -0
- package/dist/core/copilot-anthropic-sse-repair.js +340 -0
- package/dist/core/copilot-anthropic-sse-repair.js.map +1 -0
- package/dist/core/copilot-gemini-reasoning.d.ts +16 -8
- package/dist/core/copilot-gemini-reasoning.d.ts.map +1 -1
- package/dist/core/copilot-gemini-reasoning.js +27 -22
- package/dist/core/copilot-gemini-reasoning.js.map +1 -1
- package/dist/core/copilot-hosts.d.ts +12 -0
- package/dist/core/copilot-hosts.d.ts.map +1 -0
- package/dist/core/copilot-hosts.js +33 -0
- package/dist/core/copilot-hosts.js.map +1 -0
- package/dist/core/extensions/agent-events.d.ts +1 -1
- package/dist/core/extensions/agent-events.d.ts.map +1 -1
- package/dist/core/extensions/agent-events.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts +8 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +2 -1
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +6 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +72 -29
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +5 -5
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/openai-responses-payload-sanitizer.d.ts +1 -0
- package/dist/core/openai-responses-payload-sanitizer.d.ts.map +1 -1
- package/dist/core/openai-responses-payload-sanitizer.js +24 -9
- package/dist/core/openai-responses-payload-sanitizer.js.map +1 -1
- package/dist/core/sdk-types.d.ts +2 -0
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +1 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +6 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/slash-commands.d.ts +2 -0
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +141 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/index-extensions.d.ts +1 -1
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/main-deferred-startup.d.ts +12 -0
- package/dist/main-deferred-startup.d.ts.map +1 -1
- package/dist/main-deferred-startup.js +23 -2
- package/dist/main-deferred-startup.js.map +1 -1
- package/dist/main-early-input.d.ts +41 -0
- package/dist/main-early-input.d.ts.map +1 -0
- package/dist/main-early-input.js +154 -0
- package/dist/main-early-input.js.map +1 -0
- package/dist/main.d.ts +0 -6
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +20 -14
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.js +0 -1
- package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.js +15 -0
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.js +25 -0
- package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +21 -9
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.js +41 -28
- package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.js +1 -0
- package/dist/modes/interactive/interactive-hotkeys-debug.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +318 -185
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts +12 -0
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +39 -0
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.js +1 -1
- package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +6 -2
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-types.d.ts +3 -0
- package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-types.js.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.js +3 -1
- package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-process-lifecycle.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-process-lifecycle.js +0 -3
- package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.js +36 -10
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.js +5 -1
- package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +26 -22
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/global-theme.js +26 -2
- package/dist/modes/interactive/theme/global-theme.js.map +1 -1
- package/dist/utils/fs-watch.d.ts +24 -1
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/fs-watch.js +60 -5
- package/dist/utils/fs-watch.js.map +1 -1
- package/docs/compaction.md +8 -0
- package/docs/development.md +4 -0
- package/docs/extensions.md +5 -0
- package/docs/json.md +3 -1
- package/docs/providers.md +1 -0
- package/docs/quickstart.md +1 -1
- package/docs/rpc.md +3 -1
- package/docs/settings.md +27 -1
- package/docs/subagents.md +4 -0
- package/docs/terminal-setup.md +4 -0
- package/docs/usage.md +2 -2
- package/docs/windows.md +4 -0
- package/docs/workflows.md +21 -9
- package/npm-shrinkwrap.json +513 -23
- package/package.json +3 -2
|
@@ -359,6 +359,10 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
359
359
|
...(entry.label !== undefined ? { label: entry.label } : {}),
|
|
360
360
|
...(entry.rootWorkflowId !== undefined ? { rootWorkflowId: entry.rootWorkflowId } : {}),
|
|
361
361
|
...(entry.resumable !== undefined ? { resumable: entry.resumable } : {}),
|
|
362
|
+
...(entry.invocationCwd !== undefined ? { invocationCwd: entry.invocationCwd } : {}),
|
|
363
|
+
...(entry.workflowCwd !== undefined ? { workflowCwd: entry.workflowCwd } : {}),
|
|
364
|
+
...(entry.repositoryRoot !== undefined ? { repositoryRoot: entry.repositoryRoot } : {}),
|
|
365
|
+
...(entry.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: entry.gitWorktreeRoot } : {}),
|
|
362
366
|
});
|
|
363
367
|
}
|
|
364
368
|
}
|
|
@@ -377,7 +381,7 @@ function isMetadataStep(stepName: string): boolean {
|
|
|
377
381
|
interface DbosMetadataEnvelope {
|
|
378
382
|
readonly __atomicDurableMetadata: true;
|
|
379
383
|
readonly version: 1;
|
|
380
|
-
readonly entry:
|
|
384
|
+
readonly entry: WorkflowSerializableValue;
|
|
381
385
|
}
|
|
382
386
|
|
|
383
387
|
function encodeMetadata(entry: DurableCheckpointEntry): WorkflowSerializableValue {
|
|
@@ -395,6 +399,10 @@ function encodeMetadata(entry: DurableCheckpointEntry): WorkflowSerializableValu
|
|
|
395
399
|
...(entry.label !== undefined ? { label: entry.label } : {}),
|
|
396
400
|
...(entry.rootWorkflowId !== undefined ? { rootWorkflowId: entry.rootWorkflowId } : {}),
|
|
397
401
|
...(entry.resumable !== undefined ? { resumable: entry.resumable } : {}),
|
|
402
|
+
...(entry.invocationCwd !== undefined ? { invocationCwd: entry.invocationCwd } : {}),
|
|
403
|
+
...(entry.workflowCwd !== undefined ? { workflowCwd: entry.workflowCwd } : {}),
|
|
404
|
+
...(entry.repositoryRoot !== undefined ? { repositoryRoot: entry.repositoryRoot } : {}),
|
|
405
|
+
...(entry.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: entry.gitWorktreeRoot } : {}),
|
|
398
406
|
ts: entry.ts,
|
|
399
407
|
},
|
|
400
408
|
};
|
|
@@ -404,7 +412,60 @@ function decodeMetadata(value: WorkflowSerializableValue): DurableCheckpointEntr
|
|
|
404
412
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
|
|
405
413
|
const raw = value as Partial<DbosMetadataEnvelope>;
|
|
406
414
|
if (raw.__atomicDurableMetadata !== true || raw.version !== METADATA_VERSION) return undefined;
|
|
407
|
-
|
|
415
|
+
const entry = raw.entry;
|
|
416
|
+
if (entry === undefined) return undefined;
|
|
417
|
+
return parseDurableCheckpointEntry(entry);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function parseDurableCheckpointEntry(value: WorkflowSerializableValue): DurableCheckpointEntry | undefined {
|
|
421
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
|
|
422
|
+
const entry = value as Partial<DurableCheckpointEntry>;
|
|
423
|
+
if (entry.type !== "workflow.durable.checkpoint"
|
|
424
|
+
|| typeof entry.workflowId !== "string"
|
|
425
|
+
|| typeof entry.name !== "string"
|
|
426
|
+
|| typeof entry.inputs !== "object"
|
|
427
|
+
|| entry.inputs === null
|
|
428
|
+
|| Array.isArray(entry.inputs)
|
|
429
|
+
|| typeof entry.status !== "string"
|
|
430
|
+
|| !isDurableWorkflowStatus(entry.status)
|
|
431
|
+
|| typeof entry.completedCheckpoints !== "number"
|
|
432
|
+
|| typeof entry.pendingPrompts !== "number"
|
|
433
|
+
|| typeof entry.ts !== "number"
|
|
434
|
+
|| (entry.label !== undefined && typeof entry.label !== "string")
|
|
435
|
+
|| (entry.rootWorkflowId !== undefined && typeof entry.rootWorkflowId !== "string")
|
|
436
|
+
|| (entry.resumable !== undefined && typeof entry.resumable !== "boolean")
|
|
437
|
+
|| (entry.invocationCwd !== undefined && typeof entry.invocationCwd !== "string")
|
|
438
|
+
|| (entry.workflowCwd !== undefined && typeof entry.workflowCwd !== "string")
|
|
439
|
+
|| (entry.repositoryRoot !== undefined && typeof entry.repositoryRoot !== "string")
|
|
440
|
+
|| (entry.gitWorktreeRoot !== undefined && typeof entry.gitWorktreeRoot !== "string")) {
|
|
441
|
+
return undefined;
|
|
442
|
+
}
|
|
443
|
+
return {
|
|
444
|
+
type: "workflow.durable.checkpoint",
|
|
445
|
+
workflowId: entry.workflowId,
|
|
446
|
+
name: entry.name,
|
|
447
|
+
inputs: entry.inputs,
|
|
448
|
+
status: entry.status,
|
|
449
|
+
completedCheckpoints: entry.completedCheckpoints,
|
|
450
|
+
pendingPrompts: entry.pendingPrompts,
|
|
451
|
+
ts: entry.ts,
|
|
452
|
+
...(entry.label !== undefined ? { label: entry.label } : {}),
|
|
453
|
+
...(entry.rootWorkflowId !== undefined ? { rootWorkflowId: entry.rootWorkflowId } : {}),
|
|
454
|
+
...(entry.resumable !== undefined ? { resumable: entry.resumable } : {}),
|
|
455
|
+
...(entry.invocationCwd !== undefined ? { invocationCwd: entry.invocationCwd } : {}),
|
|
456
|
+
...(entry.workflowCwd !== undefined ? { workflowCwd: entry.workflowCwd } : {}),
|
|
457
|
+
...(entry.repositoryRoot !== undefined ? { repositoryRoot: entry.repositoryRoot } : {}),
|
|
458
|
+
...(entry.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: entry.gitWorktreeRoot } : {}),
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function isDurableWorkflowStatus(value: string): value is DurableWorkflowStatus {
|
|
463
|
+
return value === "running"
|
|
464
|
+
|| value === "paused"
|
|
465
|
+
|| value === "completed"
|
|
466
|
+
|| value === "failed"
|
|
467
|
+
|| value === "cancelled"
|
|
468
|
+
|| value === "blocked";
|
|
408
469
|
}
|
|
409
470
|
|
|
410
471
|
function dbosStatusToDurable(status: string): DurableWorkflowStatus {
|
|
@@ -51,6 +51,14 @@ export interface DbosCheckpointEnvelope extends WorkflowSerializableObject {
|
|
|
51
51
|
readonly sessionId?: string;
|
|
52
52
|
readonly sessionFile?: string;
|
|
53
53
|
readonly completedAt: number;
|
|
54
|
+
readonly startedAt?: number;
|
|
55
|
+
readonly endedAt?: number;
|
|
56
|
+
readonly durationMs?: number;
|
|
57
|
+
readonly result?: string;
|
|
58
|
+
readonly model?: string;
|
|
59
|
+
readonly fastMode?: boolean;
|
|
60
|
+
readonly attemptedModels?: WorkflowSerializableValue;
|
|
61
|
+
readonly modelAttempts?: WorkflowSerializableValue;
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
/**
|
|
@@ -82,6 +90,14 @@ export function encodeCheckpoint(cp: DurableCheckpoint): DbosCheckpointEnvelope
|
|
|
82
90
|
replayKey: s.replayKey,
|
|
83
91
|
...(s.sessionId !== undefined ? { sessionId: s.sessionId } : {}),
|
|
84
92
|
...(s.sessionFile !== undefined ? { sessionFile: s.sessionFile } : {}),
|
|
93
|
+
...(s.startedAt !== undefined ? { startedAt: s.startedAt } : {}),
|
|
94
|
+
...(s.endedAt !== undefined ? { endedAt: s.endedAt } : {}),
|
|
95
|
+
...(s.durationMs !== undefined ? { durationMs: s.durationMs } : {}),
|
|
96
|
+
...(s.result !== undefined ? { result: s.result } : {}),
|
|
97
|
+
...(s.model !== undefined ? { model: s.model } : {}),
|
|
98
|
+
...(s.fastMode !== undefined ? { fastMode: s.fastMode } : {}),
|
|
99
|
+
...(s.attemptedModels !== undefined ? { attemptedModels: [...s.attemptedModels] } : {}),
|
|
100
|
+
...(s.modelAttempts !== undefined ? { modelAttempts: s.modelAttempts as WorkflowSerializableValue } : {}),
|
|
85
101
|
};
|
|
86
102
|
}
|
|
87
103
|
|
|
@@ -144,9 +160,21 @@ function decodeEnvelope(workflowId: string, env: DbosCheckpointEnvelope): Durabl
|
|
|
144
160
|
...(env.hasOutput !== false && env.output !== undefined ? { output: env.output } : {}),
|
|
145
161
|
...(env.sessionId !== undefined ? { sessionId: env.sessionId } : {}),
|
|
146
162
|
...(env.sessionFile !== undefined ? { sessionFile: env.sessionFile } : {}),
|
|
163
|
+
...(typeof env.startedAt === "number" ? { startedAt: env.startedAt } : {}),
|
|
164
|
+
...(typeof env.endedAt === "number" ? { endedAt: env.endedAt } : {}),
|
|
165
|
+
...(typeof env.durationMs === "number" ? { durationMs: env.durationMs } : {}),
|
|
166
|
+
...(typeof env.result === "string" ? { result: env.result } : {}),
|
|
167
|
+
...(typeof env.model === "string" ? { model: env.model } : {}),
|
|
168
|
+
...(typeof env.fastMode === "boolean" ? { fastMode: env.fastMode } : {}),
|
|
169
|
+
...(isStringArray(env.attemptedModels) ? { attemptedModels: env.attemptedModels } : {}),
|
|
170
|
+
...(Array.isArray(env.modelAttempts) ? { modelAttempts: env.modelAttempts as DurableStageCheckpoint["modelAttempts"] } : {}),
|
|
147
171
|
} as DurableStageCheckpoint;
|
|
148
172
|
}
|
|
149
173
|
|
|
174
|
+
|
|
175
|
+
function isStringArray(value: WorkflowSerializableValue | undefined): value is readonly string[] {
|
|
176
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
177
|
+
}
|
|
150
178
|
function decodeLegacy(
|
|
151
179
|
workflowId: string,
|
|
152
180
|
stepName: string,
|
|
@@ -107,6 +107,10 @@ function parseDurableEntry(raw: Record<string, unknown>): DurableCheckpointEntry
|
|
|
107
107
|
...(typeof raw["label"] === "string" ? { label: raw["label"] } : {}),
|
|
108
108
|
...(typeof raw["rootWorkflowId"] === "string" ? { rootWorkflowId: raw["rootWorkflowId"] } : {}),
|
|
109
109
|
...(typeof raw["resumable"] === "boolean" ? { resumable: raw["resumable"] } : {}),
|
|
110
|
+
...(typeof raw["invocationCwd"] === "string" ? { invocationCwd: raw["invocationCwd"] } : {}),
|
|
111
|
+
...(typeof raw["workflowCwd"] === "string" ? { workflowCwd: raw["workflowCwd"] } : {}),
|
|
112
|
+
...(typeof raw["repositoryRoot"] === "string" ? { repositoryRoot: raw["repositoryRoot"] } : {}),
|
|
113
|
+
...(typeof raw["gitWorktreeRoot"] === "string" ? { gitWorktreeRoot: raw["gitWorktreeRoot"] } : {}),
|
|
110
114
|
ts,
|
|
111
115
|
};
|
|
112
116
|
}
|
|
@@ -142,6 +146,10 @@ function entryToResumable(entry: DurableCheckpointEntry, sessionFile: string): R
|
|
|
142
146
|
...(entry.label !== undefined ? { label: entry.label } : {}),
|
|
143
147
|
...(entry.rootWorkflowId !== undefined ? { rootWorkflowId: entry.rootWorkflowId } : {}),
|
|
144
148
|
...(entry.resumable !== undefined ? { resumable: entry.resumable } : {}),
|
|
149
|
+
...(entry.invocationCwd !== undefined ? { invocationCwd: entry.invocationCwd } : {}),
|
|
150
|
+
...(entry.workflowCwd !== undefined ? { workflowCwd: entry.workflowCwd } : {}),
|
|
151
|
+
...(entry.repositoryRoot !== undefined ? { repositoryRoot: entry.repositoryRoot } : {}),
|
|
152
|
+
...(entry.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: entry.gitWorktreeRoot } : {}),
|
|
145
153
|
createdAt: entry.ts,
|
|
146
154
|
updatedAt: entry.ts,
|
|
147
155
|
};
|
|
@@ -197,6 +205,10 @@ export function persistDurableCacheEntry(
|
|
|
197
205
|
...(entry.label !== undefined ? { label: entry.label } : {}),
|
|
198
206
|
...(entry.rootWorkflowId !== undefined ? { rootWorkflowId: entry.rootWorkflowId } : {}),
|
|
199
207
|
...(entry.resumable !== undefined ? { resumable: entry.resumable } : {}),
|
|
208
|
+
...(entry.invocationCwd !== undefined ? { invocationCwd: entry.invocationCwd } : {}),
|
|
209
|
+
...(entry.workflowCwd !== undefined ? { workflowCwd: entry.workflowCwd } : {}),
|
|
210
|
+
...(entry.repositoryRoot !== undefined ? { repositoryRoot: entry.repositoryRoot } : {}),
|
|
211
|
+
...(entry.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: entry.gitWorktreeRoot } : {}),
|
|
200
212
|
ts: entry.ts,
|
|
201
213
|
});
|
|
202
214
|
}
|
|
@@ -167,11 +167,14 @@ export function resumeDurableWorkflow(
|
|
|
167
167
|
// ORIGINAL workflow id as the run id so durable checkpoints replay.
|
|
168
168
|
backend.setWorkflowStatus(resolved.workflowId, "running");
|
|
169
169
|
|
|
170
|
-
const
|
|
170
|
+
const resumeRunOpts: RunOpts = {
|
|
171
171
|
...deps.baseRunOpts,
|
|
172
|
+
...(handle.invocationCwd !== undefined ? { cwd: handle.invocationCwd } : {}),
|
|
172
173
|
runId: resolved.workflowId,
|
|
173
174
|
durableBackend: backend,
|
|
174
|
-
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const accepted: DetachedAccepted = runDetached(def, inputs, resumeRunOpts);
|
|
175
178
|
|
|
176
179
|
return {
|
|
177
180
|
ok: true,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Durable `ctx.stage` / `ctx.task` replay and checkpoint helpers. */
|
|
2
2
|
|
|
3
|
-
import type { StageContext, StageOptions, WorkflowTaskOptions, WorkflowTaskResult } from "../shared/types.js";
|
|
3
|
+
import type { StageContext, StageOptions, WorkflowChildResult, WorkflowOutputValues, WorkflowTaskOptions, WorkflowTaskResult } from "../shared/types.js";
|
|
4
4
|
import type { StageSnapshot } from "../shared/store-types.js";
|
|
5
5
|
import type { WorkflowSerializableValue } from "../shared/types.js";
|
|
6
6
|
import type { DurableWorkflowBackend } from "./backend.js";
|
|
@@ -8,6 +8,7 @@ import type { ParallelFailFastScope } from "../runs/foreground/executor-types.js
|
|
|
8
8
|
import { durableHash } from "./backend.js";
|
|
9
9
|
import { recordCheckpointDurably } from "./tool-primitive.js";
|
|
10
10
|
import type { DurableStageCheckpoint } from "./types.js";
|
|
11
|
+
export type DurableCompletedStageCheckpoint = DurableStageCheckpoint & { readonly output: WorkflowSerializableValue };
|
|
11
12
|
|
|
12
13
|
export interface DurableStageDeps {
|
|
13
14
|
readonly workflowId: string;
|
|
@@ -20,16 +21,28 @@ export interface DurableStageDeps {
|
|
|
20
21
|
export async function recordStageCheckpoint(deps: DurableStageDeps, stage: StageSnapshot): Promise<boolean> {
|
|
21
22
|
if (stage.status !== "completed") return false;
|
|
22
23
|
const replayKey = deps.replayKeyForCompletedStage?.(stage) ?? stage.replayKey ?? deps.nextReplayKey(stage.name);
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
const metadata = checkpointMetadata(stage);
|
|
25
|
+
const hasExistingOutput = deps.backend.getStageOutput(deps.workflowId, replayKey) !== undefined;
|
|
26
|
+
const checkpoint: DurableStageCheckpoint = hasExistingOutput
|
|
27
|
+
? {
|
|
28
|
+
kind: "stage",
|
|
29
|
+
workflowId: deps.workflowId,
|
|
30
|
+
checkpointId: stageMetadataCheckpointId(replayKey, stage),
|
|
31
|
+
name: stage.name,
|
|
32
|
+
replayKey,
|
|
33
|
+
completedAt: stage.endedAt ?? Date.now(),
|
|
34
|
+
...metadata,
|
|
35
|
+
}
|
|
36
|
+
: {
|
|
37
|
+
kind: "stage",
|
|
38
|
+
workflowId: deps.workflowId,
|
|
39
|
+
checkpointId: stableCheckpointId("stage", replayKey),
|
|
40
|
+
name: stage.name,
|
|
41
|
+
replayKey,
|
|
42
|
+
output: stageOutput(stage),
|
|
43
|
+
completedAt: stage.endedAt ?? Date.now(),
|
|
44
|
+
...metadata,
|
|
45
|
+
};
|
|
33
46
|
await recordCheckpointDurably(deps.backend, checkpoint);
|
|
34
47
|
return true;
|
|
35
48
|
}
|
|
@@ -79,14 +92,14 @@ export function createDurableStagePrimitive(input: {
|
|
|
79
92
|
readonly backend: DurableWorkflowBackend;
|
|
80
93
|
readonly nextReplayKey: (stageName: string) => string;
|
|
81
94
|
readonly stage: (name: string, options: StageOptions | undefined, replayKey: string) => StageContext;
|
|
82
|
-
readonly recordCachedStage?: (name: string, replayKey: string,
|
|
95
|
+
readonly recordCachedStage?: (name: string, replayKey: string, checkpoint: DurableCompletedStageCheckpoint) => void;
|
|
83
96
|
}): (name: string, options?: StageOptions) => StageContext {
|
|
84
97
|
return (name: string, options?: StageOptions): StageContext => {
|
|
85
98
|
const replayKey = input.nextReplayKey(name);
|
|
86
|
-
const cached = input.backend
|
|
99
|
+
const cached = stageCheckpointWithOutput(input.backend, input.workflowId, replayKey);
|
|
87
100
|
if (cached !== undefined) {
|
|
88
101
|
input.recordCachedStage?.(name, replayKey, cached);
|
|
89
|
-
return createCachedStageContext(name, cached);
|
|
102
|
+
return createCachedStageContext(name, cached.output, cached.result);
|
|
90
103
|
}
|
|
91
104
|
const session = input.backend.getStageSession(input.workflowId, replayKey);
|
|
92
105
|
const isMidSessionResume = session?.sessionFile !== undefined;
|
|
@@ -112,14 +125,14 @@ export function createDurableTaskPrimitive(input: {
|
|
|
112
125
|
readonly backend: DurableWorkflowBackend;
|
|
113
126
|
readonly nextReplayKey: (stageName: string) => string;
|
|
114
127
|
readonly task: (name: string, options: WorkflowTaskOptions, stageFailFastScope?: ParallelFailFastScope) => Promise<WorkflowTaskResult>;
|
|
115
|
-
readonly recordCachedTask?: (name: string, replayKey: string,
|
|
128
|
+
readonly recordCachedTask?: (name: string, replayKey: string, checkpoint: DurableCompletedStageCheckpoint, stageFailFastScope?: ParallelFailFastScope) => void;
|
|
116
129
|
}): (name: string, options: WorkflowTaskOptions) => Promise<WorkflowTaskResult> {
|
|
117
130
|
return async (name: string, options: WorkflowTaskOptions, stageFailFastScope?: ParallelFailFastScope): Promise<WorkflowTaskResult> => {
|
|
118
131
|
const replayKey = input.nextReplayKey(`task:${name}`);
|
|
119
|
-
const cached = input.backend
|
|
120
|
-
if (cached !== undefined && isWorkflowTaskResult(cached)) {
|
|
121
|
-
input.recordCachedTask?.(name, replayKey, cached);
|
|
122
|
-
return cached;
|
|
132
|
+
const cached = stageCheckpointWithOutput(input.backend, input.workflowId, replayKey, isWorkflowTaskResult);
|
|
133
|
+
if (cached !== undefined && isWorkflowTaskResult(cached.output)) {
|
|
134
|
+
input.recordCachedTask?.(name, replayKey, cached, stageFailFastScope);
|
|
135
|
+
return cached.output;
|
|
123
136
|
}
|
|
124
137
|
const session = input.backend.getStageSession(input.workflowId, replayKey);
|
|
125
138
|
const taskOptions: WorkflowTaskOptions = {
|
|
@@ -136,6 +149,7 @@ export function createDurableTaskPrimitive(input: {
|
|
|
136
149
|
replayKey,
|
|
137
150
|
output: result,
|
|
138
151
|
completedAt: Date.now(),
|
|
152
|
+
...taskCheckpointMetadata(result),
|
|
139
153
|
});
|
|
140
154
|
return result;
|
|
141
155
|
};
|
|
@@ -174,8 +188,8 @@ function wrapSchemaStageForDurability(input: {
|
|
|
174
188
|
return wrapped;
|
|
175
189
|
}
|
|
176
190
|
|
|
177
|
-
function createCachedStageContext(name: string, output: WorkflowSerializableValue): StageContext {
|
|
178
|
-
const text = typeof output === "string" ? output : JSON.stringify(output);
|
|
191
|
+
function createCachedStageContext(name: string, output: WorkflowSerializableValue, result?: string): StageContext {
|
|
192
|
+
const text = result ?? (typeof output === "string" ? output : JSON.stringify(output));
|
|
179
193
|
const unsupported = async (): Promise<never> => { throw new Error(`Stage "${name}" was replayed from a durable checkpoint; live session operations are unavailable.`); };
|
|
180
194
|
const cached = {
|
|
181
195
|
name,
|
|
@@ -213,6 +227,82 @@ function stageOutput(stage: StageSnapshot): WorkflowSerializableValue {
|
|
|
213
227
|
return { status: stage.status, stageId: stage.id };
|
|
214
228
|
}
|
|
215
229
|
|
|
230
|
+
function checkpointMetadata(stage: StageSnapshot): Partial<DurableStageCheckpoint> {
|
|
231
|
+
return {
|
|
232
|
+
...(stage.startedAt !== undefined ? { startedAt: stage.startedAt } : {}),
|
|
233
|
+
...(stage.endedAt !== undefined ? { endedAt: stage.endedAt } : {}),
|
|
234
|
+
...(stage.durationMs !== undefined ? { durationMs: stage.durationMs } : {}),
|
|
235
|
+
...(stage.result !== undefined ? { result: stage.result } : {}),
|
|
236
|
+
...(stage.sessionId !== undefined ? { sessionId: stage.sessionId } : {}),
|
|
237
|
+
...(stage.sessionFile !== undefined ? { sessionFile: stage.sessionFile } : {}),
|
|
238
|
+
...(stage.model !== undefined ? { model: stage.model } : {}),
|
|
239
|
+
...(stage.fastMode !== undefined ? { fastMode: stage.fastMode } : {}),
|
|
240
|
+
...(stage.attemptedModels !== undefined ? { attemptedModels: [...stage.attemptedModels] } : {}),
|
|
241
|
+
...(stage.modelAttempts !== undefined ? { modelAttempts: [...stage.modelAttempts] } : {}),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function taskCheckpointMetadata(result: WorkflowTaskResult): Partial<DurableStageCheckpoint> {
|
|
246
|
+
return {
|
|
247
|
+
result: result.text,
|
|
248
|
+
...(result.sessionId !== undefined ? { sessionId: result.sessionId } : {}),
|
|
249
|
+
...(result.sessionFile !== undefined ? { sessionFile: result.sessionFile } : {}),
|
|
250
|
+
...(result.model !== undefined ? { model: result.model } : {}),
|
|
251
|
+
...(result.fastMode !== undefined ? { fastMode: result.fastMode } : {}),
|
|
252
|
+
...(result.attemptedModels !== undefined ? { attemptedModels: [...result.attemptedModels] } : {}),
|
|
253
|
+
...(result.modelAttempts !== undefined ? { modelAttempts: [...result.modelAttempts] } : {}),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export function stageCheckpointWithOutput(
|
|
258
|
+
backend: DurableWorkflowBackend,
|
|
259
|
+
workflowId: string,
|
|
260
|
+
replayKey: string,
|
|
261
|
+
matchesOutput?: (value: WorkflowSerializableValue) => boolean,
|
|
262
|
+
): DurableCompletedStageCheckpoint | undefined {
|
|
263
|
+
const checkpoints = backend.listCheckpoints(workflowId)
|
|
264
|
+
.filter((checkpoint): checkpoint is DurableStageCheckpoint =>
|
|
265
|
+
checkpoint.kind === "stage" && checkpoint.replayKey === replayKey,
|
|
266
|
+
);
|
|
267
|
+
const outputCheckpoints = checkpoints.filter((checkpoint): checkpoint is DurableCompletedStageCheckpoint =>
|
|
268
|
+
checkpoint.output !== undefined,
|
|
269
|
+
);
|
|
270
|
+
const replayValueCheckpoint = matchesOutput === undefined
|
|
271
|
+
? outputCheckpoints[0]
|
|
272
|
+
: outputCheckpoints.find((checkpoint) => matchesOutput(checkpoint.output));
|
|
273
|
+
if (replayValueCheckpoint === undefined) return undefined;
|
|
274
|
+
return mergeCheckpointHydrationMetadata(replayValueCheckpoint, checkpoints);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function mergeCheckpointHydrationMetadata(
|
|
278
|
+
replayValueCheckpoint: DurableCompletedStageCheckpoint,
|
|
279
|
+
checkpoints: readonly DurableStageCheckpoint[],
|
|
280
|
+
): DurableCompletedStageCheckpoint {
|
|
281
|
+
if (checkpoints.length === 0) return replayValueCheckpoint;
|
|
282
|
+
return {
|
|
283
|
+
...replayValueCheckpoint,
|
|
284
|
+
...(replayValueCheckpoint.startedAt === undefined ? metadataValue(checkpoints, "startedAt") : {}),
|
|
285
|
+
...(replayValueCheckpoint.endedAt === undefined ? metadataValue(checkpoints, "endedAt") : {}),
|
|
286
|
+
...(replayValueCheckpoint.durationMs === undefined ? metadataValue(checkpoints, "durationMs") : {}),
|
|
287
|
+
...(replayValueCheckpoint.result === undefined ? metadataValue(checkpoints, "result") : {}),
|
|
288
|
+
...(replayValueCheckpoint.sessionId === undefined ? metadataValue(checkpoints, "sessionId") : {}),
|
|
289
|
+
...(replayValueCheckpoint.sessionFile === undefined ? metadataValue(checkpoints, "sessionFile") : {}),
|
|
290
|
+
...(replayValueCheckpoint.model === undefined ? metadataValue(checkpoints, "model") : {}),
|
|
291
|
+
...(replayValueCheckpoint.fastMode === undefined ? metadataValue(checkpoints, "fastMode") : {}),
|
|
292
|
+
...(replayValueCheckpoint.attemptedModels === undefined ? metadataValue(checkpoints, "attemptedModels") : {}),
|
|
293
|
+
...(replayValueCheckpoint.modelAttempts === undefined ? metadataValue(checkpoints, "modelAttempts") : {}),
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function metadataValue<K extends keyof DurableStageCheckpoint>(
|
|
298
|
+
checkpoints: readonly DurableStageCheckpoint[],
|
|
299
|
+
key: K,
|
|
300
|
+
): Pick<DurableStageCheckpoint, K> | Record<string, never> {
|
|
301
|
+
const value = checkpoints.find((checkpoint) => checkpoint[key] !== undefined)?.[key];
|
|
302
|
+
return value === undefined ? {} : { [key]: value } as Pick<DurableStageCheckpoint, K>;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
|
|
216
306
|
export function createStageReplayKeyGenerator(_workflowId: string): (stageName: string, stageId?: string) => string {
|
|
217
307
|
const counts = new Map<string, number>();
|
|
218
308
|
return (stageName: string, _stageId?: string): string => {
|
|
@@ -236,6 +326,15 @@ function stageSessionCheckpointId(replayKey: string, stage: StageSnapshot): stri
|
|
|
236
326
|
export function cachedStageId(runId: string, replayKey: string): string {
|
|
237
327
|
return `durable-${durableHash({ runId, replayKey })}`;
|
|
238
328
|
}
|
|
329
|
+
function stageMetadataCheckpointId(replayKey: string, stage: StageSnapshot): string {
|
|
330
|
+
return `${stableCheckpointId("stage-meta", replayKey)}:${durableHash({
|
|
331
|
+
stageId: stage.id,
|
|
332
|
+
endedAt: stage.endedAt ?? 0,
|
|
333
|
+
durationMs: stage.durationMs ?? 0,
|
|
334
|
+
result: stage.result ?? "",
|
|
335
|
+
})}`;
|
|
336
|
+
}
|
|
337
|
+
|
|
239
338
|
|
|
240
339
|
export function recordCachedStageIntoStore(
|
|
241
340
|
store: import("../shared/store.js").Store,
|
|
@@ -245,13 +344,24 @@ export function recordCachedStageIntoStore(
|
|
|
245
344
|
output: WorkflowSerializableValue,
|
|
246
345
|
completedStageReplayKeys: Map<string, string>,
|
|
247
346
|
parentIds?: readonly string[],
|
|
347
|
+
checkpoint?: DurableCompletedStageCheckpoint,
|
|
248
348
|
): void {
|
|
249
349
|
const now = Date.now();
|
|
250
350
|
const stageId = cachedStageId(runId, replayKey);
|
|
251
|
-
const result = typeof output === "string" ? output : JSON.stringify(output);
|
|
351
|
+
const result = checkpoint?.result ?? (typeof output === "string" ? output : JSON.stringify(output));
|
|
352
|
+
const endedAt = checkpoint?.endedAt ?? checkpoint?.completedAt ?? now;
|
|
353
|
+
const workflowChild = isWorkflowChildResult(output) ? workflowChildSnapshotFromResult(output) : undefined;
|
|
252
354
|
const snapshot: StageSnapshot = {
|
|
253
|
-
id: stageId, name, status: "completed", parentIds: parentIds !== undefined ? Object.freeze([...parentIds]) : [],
|
|
355
|
+
id: stageId, name, status: "completed", parentIds: parentIds !== undefined ? Object.freeze([...parentIds]) : [],
|
|
356
|
+
startedAt: checkpoint?.startedAt ?? endedAt, endedAt, durationMs: checkpoint?.durationMs ?? 0, result,
|
|
254
357
|
replayKey, replayed: true, skippedReason: "durable checkpoint replay", toolEvents: [], attachable: false,
|
|
358
|
+
...(workflowChild !== undefined ? { workflowChild } : {}),
|
|
359
|
+
...(checkpoint?.sessionId !== undefined ? { sessionId: checkpoint.sessionId } : {}),
|
|
360
|
+
...(checkpoint?.sessionFile !== undefined ? { sessionFile: checkpoint.sessionFile } : {}),
|
|
361
|
+
...(checkpoint?.model !== undefined ? { model: checkpoint.model } : {}),
|
|
362
|
+
...(checkpoint?.fastMode !== undefined ? { fastMode: checkpoint.fastMode } : {}),
|
|
363
|
+
...(checkpoint?.attemptedModels !== undefined ? { attemptedModels: checkpoint.attemptedModels } : {}),
|
|
364
|
+
...(checkpoint?.modelAttempts !== undefined ? { modelAttempts: checkpoint.modelAttempts } : {}),
|
|
255
365
|
};
|
|
256
366
|
store.recordStageStart(runId, snapshot);
|
|
257
367
|
store.recordStageEnd(runId, snapshot);
|
|
@@ -269,16 +379,44 @@ export function recordCachedStageWithTracker(
|
|
|
269
379
|
runId: string,
|
|
270
380
|
name: string,
|
|
271
381
|
replayKey: string,
|
|
272
|
-
|
|
382
|
+
checkpoint: DurableCompletedStageCheckpoint,
|
|
273
383
|
completedStageReplayKeys: Map<string, string>,
|
|
384
|
+
stageFailFastScope?: ParallelFailFastScope,
|
|
274
385
|
): void {
|
|
275
386
|
const stageId = cachedStageId(runId, replayKey);
|
|
276
|
-
|
|
277
|
-
|
|
387
|
+
let parentIds = tracker.onSpawn(stageId, name);
|
|
388
|
+
const scopeParentIds = stageFailFastScope?.parentIds ?? [];
|
|
389
|
+
if (stageFailFastScope !== undefined) {
|
|
390
|
+
tracker.replaceParents(stageId, scopeParentIds);
|
|
391
|
+
parentIds = [...scopeParentIds];
|
|
392
|
+
}
|
|
393
|
+
recordCachedStageIntoStore(store, runId, name, replayKey, checkpoint.output, completedStageReplayKeys, parentIds, checkpoint);
|
|
278
394
|
tracker.onSettle(stageId);
|
|
279
395
|
}
|
|
280
|
-
|
|
281
396
|
function isWorkflowTaskResult(value: WorkflowSerializableValue): value is WorkflowTaskResult {
|
|
282
397
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
283
398
|
return typeof (value as Record<string, WorkflowSerializableValue>)["text"] === "string";
|
|
284
399
|
}
|
|
400
|
+
|
|
401
|
+
function isWorkflowChildResult(value: WorkflowSerializableValue): value is WorkflowChildResult<WorkflowOutputValues> {
|
|
402
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
403
|
+
const objectValue = value as Record<string, WorkflowSerializableValue | undefined>;
|
|
404
|
+
return typeof objectValue["workflow"] === "string"
|
|
405
|
+
&& typeof objectValue["runId"] === "string"
|
|
406
|
+
&& typeof objectValue["status"] === "string"
|
|
407
|
+
&& typeof objectValue["outputs"] === "object"
|
|
408
|
+
&& objectValue["outputs"] !== null
|
|
409
|
+
&& !Array.isArray(objectValue["outputs"]);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function workflowChildSnapshotFromResult(result: WorkflowChildResult<WorkflowOutputValues>): StageSnapshot["workflowChild"] {
|
|
413
|
+
return {
|
|
414
|
+
alias: result.workflow,
|
|
415
|
+
workflow: result.workflow,
|
|
416
|
+
runId: result.runId,
|
|
417
|
+
status: result.status,
|
|
418
|
+
...(result.exited !== undefined ? { exited: result.exited } : {}),
|
|
419
|
+
outputs: result.outputs,
|
|
420
|
+
...(typeof result.exitReason === "string" ? { exitReason: result.exitReason } : {}),
|
|
421
|
+
};
|
|
422
|
+
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* cross-ref: issue #1498
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type { WorkflowSerializableValue } from "../shared/types.js";
|
|
12
|
+
import type { WorkflowModelAttempt, WorkflowSerializableValue } from "../shared/types.js";
|
|
13
13
|
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
// Top-level workflow identity
|
|
@@ -32,6 +32,14 @@ export interface DurableWorkflowHandle {
|
|
|
32
32
|
readonly updatedAt: number;
|
|
33
33
|
/** Current durable status. */
|
|
34
34
|
readonly status: DurableWorkflowStatus;
|
|
35
|
+
/** Original invocation cwd used to resolve repo-relative workflow defaults on resume. */
|
|
36
|
+
readonly invocationCwd?: string;
|
|
37
|
+
/** Resolved workflow cwd when an input-bound reusable worktree was set up. */
|
|
38
|
+
readonly workflowCwd?: string;
|
|
39
|
+
/** Invoking repository root used for reusable worktree validation. */
|
|
40
|
+
readonly repositoryRoot?: string;
|
|
41
|
+
/** Resolved reusable git worktree root, when setup happened at workflow start. */
|
|
42
|
+
readonly gitWorktreeRoot?: string;
|
|
35
43
|
/** Session file path that caches this workflow's durable metadata. */
|
|
36
44
|
readonly sessionFile?: string;
|
|
37
45
|
/** Number of completed durable checkpoints. */
|
|
@@ -113,6 +121,19 @@ export interface DurableStageCheckpoint {
|
|
|
113
121
|
readonly sessionId?: string;
|
|
114
122
|
readonly sessionFile?: string;
|
|
115
123
|
readonly completedAt: number;
|
|
124
|
+
/** Original stage start timestamp, when available. */
|
|
125
|
+
readonly startedAt?: number;
|
|
126
|
+
/** Original stage end timestamp, when available. */
|
|
127
|
+
readonly endedAt?: number;
|
|
128
|
+
/** Original stage duration, when available. */
|
|
129
|
+
readonly durationMs?: number;
|
|
130
|
+
/** Display/result text recorded for the completed stage. */
|
|
131
|
+
readonly result?: string;
|
|
132
|
+
/** Completed stage/task model metadata used to hydrate replayed snapshots. */
|
|
133
|
+
readonly model?: string;
|
|
134
|
+
readonly fastMode?: boolean;
|
|
135
|
+
readonly attemptedModels?: readonly string[];
|
|
136
|
+
readonly modelAttempts?: readonly WorkflowModelAttempt[];
|
|
116
137
|
}
|
|
117
138
|
|
|
118
139
|
export type UiPromptKind = "input" | "confirm" | "select" | "editor" | "custom";
|
|
@@ -145,6 +166,10 @@ export interface DurableCheckpointEntry {
|
|
|
145
166
|
readonly label?: string;
|
|
146
167
|
readonly rootWorkflowId?: string;
|
|
147
168
|
readonly resumable?: boolean;
|
|
169
|
+
readonly invocationCwd?: string;
|
|
170
|
+
readonly workflowCwd?: string;
|
|
171
|
+
readonly repositoryRoot?: string;
|
|
172
|
+
readonly gitWorktreeRoot?: string;
|
|
148
173
|
readonly ts: number;
|
|
149
174
|
}
|
|
150
175
|
|
|
@@ -163,6 +188,10 @@ export interface ResumableWorkflowEntry {
|
|
|
163
188
|
readonly label?: string;
|
|
164
189
|
readonly rootWorkflowId?: string;
|
|
165
190
|
readonly resumable?: boolean;
|
|
191
|
+
readonly invocationCwd?: string;
|
|
192
|
+
readonly workflowCwd?: string;
|
|
193
|
+
readonly repositoryRoot?: string;
|
|
194
|
+
readonly gitWorktreeRoot?: string;
|
|
166
195
|
readonly createdAt: number;
|
|
167
196
|
readonly updatedAt: number;
|
|
168
197
|
}
|
|
@@ -41,6 +41,7 @@ function createTaskPrimitive(runtime: EngineRuntime): WorkflowTaskPrimitive {
|
|
|
41
41
|
const resolvedTaskOptions = stageOptionsWithGitWorktree(
|
|
42
42
|
stageOptionsWithInputDefaults(taskOptions, runtime.inputRuntimeDefaults),
|
|
43
43
|
runtime.workflowInvocationCwd,
|
|
44
|
+
runtime.gitWorktreeSetupCache,
|
|
44
45
|
) ?? taskOptions;
|
|
45
46
|
const stageOptions = taskStageOptions(resolvedTaskOptions);
|
|
46
47
|
const stageHandle = runtime.spawnStage(name, {
|
|
@@ -38,8 +38,7 @@ export async function finalizeDurableTerminalStatus(input: DurableTerminalFinali
|
|
|
38
38
|
|
|
39
39
|
const durableStatus = toDurableStatus(status);
|
|
40
40
|
if (durableStatus !== undefined) {
|
|
41
|
-
|
|
42
|
-
input.durableBackend.setWorkflowStatus(input.runId, durableStatus, undefined, resumable);
|
|
41
|
+
input.durableBackend.setWorkflowStatus(input.runId, durableStatus, undefined, input.runSnapshot.resumable);
|
|
43
42
|
}
|
|
44
43
|
try {
|
|
45
44
|
await input.durableBackend.flush?.();
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { RunEndMetadata } from "../shared/store-public-types.js";
|
|
2
2
|
import type { WorkflowOutputValues } from "../shared/types.js";
|
|
3
|
+
import type { RunSnapshot } from "../shared/store-types.js";
|
|
4
|
+
import {
|
|
5
|
+
actionableReturnedStatusText,
|
|
6
|
+
isReturnedBlockedWorkflowStatus,
|
|
7
|
+
isReturnedResumableBlockedWorkflowStatus,
|
|
8
|
+
normalizeReturnedWorkflowStatus,
|
|
9
|
+
structuredRecoverableWorkflowFailure,
|
|
10
|
+
} from "../shared/returned-run-status.js";
|
|
3
11
|
|
|
4
12
|
export interface ReturnedRunStatus {
|
|
5
13
|
readonly status: "completed" | "failed" | "blocked";
|
|
@@ -7,23 +15,44 @@ export interface ReturnedRunStatus {
|
|
|
7
15
|
readonly metadata?: RunEndMetadata;
|
|
8
16
|
}
|
|
9
17
|
|
|
10
|
-
export function classifyReturnedRunStatus(result: WorkflowOutputValues | undefined): ReturnedRunStatus {
|
|
11
|
-
const
|
|
12
|
-
if (
|
|
18
|
+
export function classifyReturnedRunStatus(result: WorkflowOutputValues | undefined, runSnapshot?: RunSnapshot): ReturnedRunStatus {
|
|
19
|
+
const structuredFailure = runSnapshot !== undefined ? structuredRecoverableWorkflowFailure(runSnapshot) : undefined;
|
|
20
|
+
if (structuredFailure !== undefined) {
|
|
21
|
+
return {
|
|
22
|
+
status: "blocked",
|
|
23
|
+
error: structuredFailure.error,
|
|
24
|
+
metadata: structuredFailure.metadata,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const returnedStatus = normalizeReturnedWorkflowStatus(result?.["status"]);
|
|
28
|
+
if (returnedStatus === undefined || returnedStatus === "completed" || returnedStatus === "complete") {
|
|
13
29
|
return { status: "completed" };
|
|
14
30
|
}
|
|
15
31
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
const error = returnedStatusError(result, returnedStatus);
|
|
33
|
+
if (returnedStatus === "failed") {
|
|
34
|
+
return {
|
|
35
|
+
status: "failed",
|
|
36
|
+
error,
|
|
37
|
+
metadata: returnedFailureMetadata(error),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (isReturnedBlockedWorkflowStatus(returnedStatus)) {
|
|
41
|
+
const metadata = isReturnedResumableBlockedWorkflowStatus(returnedStatus)
|
|
42
|
+
? returnedRecoverableBlockedMetadata(error)
|
|
43
|
+
: { resumable: false };
|
|
44
|
+
return {
|
|
45
|
+
status: "blocked",
|
|
46
|
+
error,
|
|
47
|
+
metadata,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { status: "completed" };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function returnedStatusError(result: WorkflowOutputValues | undefined, returnedStatus: string): string {
|
|
55
|
+
return actionableReturnedStatusText(result) ?? `Workflow returned status ${JSON.stringify(returnedStatus)}.`;
|
|
27
56
|
}
|
|
28
57
|
|
|
29
58
|
function returnedFailureMetadata(error: string): RunEndMetadata {
|
|
@@ -36,6 +65,11 @@ function returnedFailureMetadata(error: string): RunEndMetadata {
|
|
|
36
65
|
};
|
|
37
66
|
}
|
|
38
67
|
|
|
39
|
-
function
|
|
40
|
-
return {
|
|
68
|
+
function returnedRecoverableBlockedMetadata(error: string): RunEndMetadata {
|
|
69
|
+
return {
|
|
70
|
+
failureRecoverability: "recoverable",
|
|
71
|
+
failureDisposition: "active_blocked",
|
|
72
|
+
failureMessage: error,
|
|
73
|
+
resumable: true,
|
|
74
|
+
};
|
|
41
75
|
}
|