@bastani/atomic 0.9.8-alpha.1 → 0.9.9-alpha.1
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 +42 -0
- package/dist/builtin/cursor/CHANGELOG.md +12 -0
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/CHANGELOG.md +12 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +12 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +13 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +2 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +7 -1
- package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +2 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +8 -2
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +2 -1
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +2 -0
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +6 -0
- package/dist/builtin/subagents/src/shared/types-config.ts +4 -0
- package/dist/builtin/subagents/src/shared/types-depth.ts +29 -2
- package/dist/builtin/web-access/CHANGELOG.md +12 -0
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +34 -0
- package/dist/builtin/workflows/README.md +17 -8
- package/dist/builtin/workflows/builtin/goal-prompts.ts +8 -2
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +26 -9
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +1 -1
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +8 -3
- package/dist/builtin/workflows/builtin/ralph-runner.ts +2 -0
- package/dist/builtin/workflows/builtin/shared-prompts.ts +24 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/backend.ts +53 -15
- package/dist/builtin/workflows/src/durable/completed-catalog.ts +245 -0
- package/dist/builtin/workflows/src/durable/completed-inspection.ts +213 -0
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +120 -170
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +84 -8
- package/dist/builtin/workflows/src/durable/dbos-metadata.ts +98 -0
- package/dist/builtin/workflows/src/durable/dbos-tombstone.ts +27 -0
- package/dist/builtin/workflows/src/durable/factory.ts +1 -1
- package/dist/builtin/workflows/src/durable/file-backend.ts +247 -241
- package/dist/builtin/workflows/src/durable/file-lock.ts +153 -0
- package/dist/builtin/workflows/src/durable/file-state.ts +104 -0
- package/dist/builtin/workflows/src/durable/format-version.ts +12 -0
- package/dist/builtin/workflows/src/durable/index.ts +12 -0
- package/dist/builtin/workflows/src/durable/resume-catalog.ts +16 -27
- package/dist/builtin/workflows/src/durable/resume-eligibility.ts +20 -0
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +29 -29
- package/dist/builtin/workflows/src/durable/scoped-backend.ts +20 -3
- package/dist/builtin/workflows/src/durable/stage-primitive.ts +29 -8
- package/dist/builtin/workflows/src/durable/types.ts +3 -0
- package/dist/builtin/workflows/src/engine/primitives/task.ts +1 -0
- package/dist/builtin/workflows/src/engine/run.ts +14 -14
- package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +39 -9
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +10 -0
- package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +133 -0
- package/dist/builtin/workflows/src/extension/runtime.ts +15 -40
- package/dist/builtin/workflows/src/extension/wiring.ts +9 -6
- package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +226 -0
- package/dist/builtin/workflows/src/extension/workflow-prompts.ts +1 -0
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +66 -112
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +5 -5
- package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +16 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +50 -43
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-output.ts +91 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-direct.ts +95 -46
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +3 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +3 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-options.ts +36 -7
- package/dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts +25 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-cwd.ts +103 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-generation.ts +57 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +134 -8
- package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -0
- package/dist/builtin/workflows/src/shared/resumable-workflow-notices.ts +43 -0
- package/dist/builtin/workflows/src/shared/timing.ts +4 -0
- package/dist/builtin/workflows/src/shared/types.ts +5 -3
- package/dist/builtin/workflows/src/tui/graph-view-constants.ts +1 -0
- package/dist/builtin/workflows/src/tui/graph-view-input.ts +24 -14
- package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +43 -13
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +5 -7
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-compaction.d.ts +6 -34
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +95 -233
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-message-queue.d.ts +0 -4
- package/dist/core/agent-session-message-queue.d.ts.map +1 -1
- package/dist/core/agent-session-message-queue.js +1 -5
- package/dist/core/agent-session-message-queue.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +5 -6
- 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-types.d.ts +2 -12
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -2
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction-boundary.d.ts +9 -0
- package/dist/core/compaction/compaction-boundary.d.ts.map +1 -0
- package/dist/core/compaction/compaction-boundary.js +115 -0
- package/dist/core/compaction/compaction-boundary.js.map +1 -0
- package/dist/core/compaction/compaction-parameters.d.ts +5 -0
- package/dist/core/compaction/compaction-parameters.d.ts.map +1 -0
- package/dist/core/compaction/compaction-parameters.js +27 -0
- package/dist/core/compaction/compaction-parameters.js.map +1 -0
- package/dist/core/compaction/compaction-runner.d.ts +14 -0
- package/dist/core/compaction/compaction-runner.d.ts.map +1 -0
- package/dist/core/compaction/compaction-runner.js +29 -0
- package/dist/core/compaction/compaction-runner.js.map +1 -0
- package/dist/core/compaction/compaction-types.d.ts +79 -0
- package/dist/core/compaction/compaction-types.d.ts.map +1 -0
- package/dist/core/compaction/compaction-types.js +6 -0
- package/dist/core/compaction/compaction-types.js.map +1 -0
- package/dist/core/compaction/deleted-ranges.d.ts +6 -0
- package/dist/core/compaction/deleted-ranges.d.ts.map +1 -0
- package/dist/core/compaction/deleted-ranges.js +134 -0
- package/dist/core/compaction/deleted-ranges.js.map +1 -0
- package/dist/core/compaction/index.d.ts +7 -1
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +7 -1
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/range-planner.d.ts +21 -0
- package/dist/core/compaction/range-planner.d.ts.map +1 -0
- package/dist/core/compaction/range-planner.js +145 -0
- package/dist/core/compaction/range-planner.js.map +1 -0
- package/dist/core/compaction/transcript-serialization.d.ts +11 -0
- package/dist/core/compaction/transcript-serialization.d.ts.map +1 -0
- package/dist/core/compaction/transcript-serialization.js +104 -0
- package/dist/core/compaction/transcript-serialization.js.map +1 -0
- package/dist/core/extensions/context-types.d.ts +2 -2
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/event-results.d.ts +2 -2
- package/dist/core/extensions/event-results.d.ts.map +1 -1
- package/dist/core/extensions/event-results.js.map +1 -1
- package/dist/core/extensions/session-events.d.ts +7 -7
- package/dist/core/extensions/session-events.d.ts.map +1 -1
- package/dist/core/extensions/session-events.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/messages.d.ts +4 -0
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +11 -0
- package/dist/core/messages.js.map +1 -1
- package/dist/core/provider-context-usage.d.ts.map +1 -1
- package/dist/core/provider-context-usage.js +1 -2
- package/dist/core/provider-context-usage.js.map +1 -1
- package/dist/core/session-manager-archive.d.ts +2 -1
- package/dist/core/session-manager-archive.d.ts.map +1 -1
- package/dist/core/session-manager-archive.js +2 -2
- package/dist/core/session-manager-archive.js.map +1 -1
- package/dist/core/session-manager-classification.d.ts +9 -0
- package/dist/core/session-manager-classification.d.ts.map +1 -0
- package/dist/core/session-manager-classification.js +37 -0
- package/dist/core/session-manager-classification.js.map +1 -0
- package/dist/core/session-manager-core.d.ts +4 -4
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +13 -8
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-entries.d.ts +4 -3
- package/dist/core/session-manager-entries.d.ts.map +1 -1
- package/dist/core/session-manager-entries.js +12 -10
- package/dist/core/session-manager-entries.js.map +1 -1
- package/dist/core/session-manager-history.d.ts +6 -23
- package/dist/core/session-manager-history.d.ts.map +1 -1
- package/dist/core/session-manager-history.js +23 -256
- package/dist/core/session-manager-history.js.map +1 -1
- package/dist/core/session-manager-list.d.ts.map +1 -1
- package/dist/core/session-manager-list.js +3 -3
- package/dist/core/session-manager-list.js.map +1 -1
- package/dist/core/session-manager-storage.d.ts +1 -1
- package/dist/core/session-manager-storage.d.ts.map +1 -1
- package/dist/core/session-manager-storage.js +3 -2
- package/dist/core/session-manager-storage.js.map +1 -1
- package/dist/core/session-manager-types.d.ts +14 -15
- package/dist/core/session-manager-types.d.ts.map +1 -1
- package/dist/core/session-manager-types.js.map +1 -1
- package/dist/core/session-manager.d.ts +3 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/main-session.d.ts +1 -0
- package/dist/main-session.d.ts.map +1 -1
- package/dist/main-session.js +7 -0
- package/dist/main-session.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts +4 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js +12 -22
- package/dist/modes/interactive/components/chat-message-renderer.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 +5 -11
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.js +3 -0
- package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.d.ts +1 -0
- package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.js +1 -0
- package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-utils.js +1 -1
- package/dist/modes/interactive/components/chat-session-host-utils.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +1 -0
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/compaction-boundary-message.d.ts +20 -0
- package/dist/modes/interactive/components/compaction-boundary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/compaction-boundary-message.js +48 -0
- package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -0
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-list.js +3 -0
- package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.js +3 -47
- package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts +2 -2
- 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 +5 -3
- 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-render-chat.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.js +21 -12
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +3 -5
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +1 -6
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +0 -4
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +2 -11
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/compaction.md +97 -772
- package/docs/extensions.md +25 -29
- package/docs/json.md +2 -2
- package/docs/rpc.md +32 -24
- package/docs/sdk.md +3 -3
- package/docs/session-format.md +49 -30
- package/docs/sessions.md +5 -3
- package/docs/settings.md +14 -4
- package/docs/usage.md +1 -1
- package/docs/workflows.md +30 -15
- package/examples/extensions/custom-compaction.ts +14 -58
- package/examples/extensions/handoff.ts +2 -3
- package/npm-shrinkwrap.json +23 -23
- package/package.json +2 -2
- package/dist/core/compaction/context-assistant-turns.d.ts +0 -42
- package/dist/core/compaction/context-assistant-turns.d.ts.map +0 -1
- package/dist/core/compaction/context-assistant-turns.js +0 -87
- package/dist/core/compaction/context-assistant-turns.js.map +0 -1
- package/dist/core/compaction/context-compaction-critical.d.ts +0 -15
- package/dist/core/compaction/context-compaction-critical.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-critical.js +0 -57
- package/dist/core/compaction/context-compaction-critical.js.map +0 -1
- package/dist/core/compaction/context-compaction-eviction-alternates.d.ts +0 -18
- package/dist/core/compaction/context-compaction-eviction-alternates.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-eviction-alternates.js +0 -186
- package/dist/core/compaction/context-compaction-eviction-alternates.js.map +0 -1
- package/dist/core/compaction/context-compaction-eviction.d.ts +0 -12
- package/dist/core/compaction/context-compaction-eviction.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-eviction.js +0 -222
- package/dist/core/compaction/context-compaction-eviction.js.map +0 -1
- package/dist/core/compaction/context-compaction-metrics.d.ts +0 -28
- package/dist/core/compaction/context-compaction-metrics.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-metrics.js +0 -107
- package/dist/core/compaction/context-compaction-metrics.js.map +0 -1
- package/dist/core/compaction/context-compaction-prompt.d.ts +0 -9
- package/dist/core/compaction/context-compaction-prompt.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-prompt.js +0 -163
- package/dist/core/compaction/context-compaction-prompt.js.map +0 -1
- package/dist/core/compaction/context-compaction-runner.d.ts +0 -11
- package/dist/core/compaction/context-compaction-runner.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-runner.js +0 -273
- package/dist/core/compaction/context-compaction-runner.js.map +0 -1
- package/dist/core/compaction/context-compaction-strategy.d.ts +0 -5
- package/dist/core/compaction/context-compaction-strategy.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-strategy.js +0 -27
- package/dist/core/compaction/context-compaction-strategy.js.map +0 -1
- package/dist/core/compaction/context-compaction-types.d.ts +0 -75
- package/dist/core/compaction/context-compaction-types.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-types.js +0 -6
- package/dist/core/compaction/context-compaction-types.js.map +0 -1
- package/dist/core/compaction/context-compaction.d.ts +0 -10
- package/dist/core/compaction/context-compaction.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction.js +0 -8
- package/dist/core/compaction/context-compaction.js.map +0 -1
- package/dist/core/compaction/context-deletion-application.d.ts +0 -14
- package/dist/core/compaction/context-deletion-application.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-application.js +0 -261
- package/dist/core/compaction/context-deletion-application.js.map +0 -1
- package/dist/core/compaction/context-deletion-store.d.ts +0 -78
- package/dist/core/compaction/context-deletion-store.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-store.js +0 -162
- package/dist/core/compaction/context-deletion-store.js.map +0 -1
- package/dist/core/compaction/context-deletion-targets.d.ts +0 -43
- package/dist/core/compaction/context-deletion-targets.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-targets.js +0 -292
- package/dist/core/compaction/context-deletion-targets.js.map +0 -1
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts +0 -193
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-tool-definitions.js +0 -98
- package/dist/core/compaction/context-deletion-tool-definitions.js.map +0 -1
- package/dist/core/compaction/context-deletion-tool-helpers.d.ts +0 -19
- package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-tool-helpers.js +0 -210
- package/dist/core/compaction/context-deletion-tool-helpers.js.map +0 -1
- package/dist/core/compaction/context-deletion-tools.d.ts +0 -4
- package/dist/core/compaction/context-deletion-tools.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-tools.js +0 -403
- package/dist/core/compaction/context-deletion-tools.js.map +0 -1
- package/dist/core/compaction/context-transcript-analysis.d.ts +0 -11
- package/dist/core/compaction/context-transcript-analysis.d.ts.map +0 -1
- package/dist/core/compaction/context-transcript-analysis.js +0 -228
- package/dist/core/compaction/context-transcript-analysis.js.map +0 -1
- package/dist/core/session-manager-tool-dependencies.d.ts +0 -10
- package/dist/core/session-manager-tool-dependencies.d.ts.map +0 -1
- package/dist/core/session-manager-tool-dependencies.js +0 -133
- package/dist/core/session-manager-tool-dependencies.js.map +0 -1
- package/dist/modes/interactive/components/context-compaction-summary-message.d.ts +0 -17
- package/dist/modes/interactive/components/context-compaction-summary-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/context-compaction-summary-message.js +0 -83
- package/dist/modes/interactive/components/context-compaction-summary-message.js.map +0 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/** DBOS-backed durable backend adapter, loaded only when configured. */
|
|
2
2
|
|
|
3
|
-
import type { DurableCheckpoint,
|
|
3
|
+
import type { DurableCheckpoint, DurableWorkflowHandle, DurableWorkflowStatus, ResumableWorkflowEntry } from "./types.js";
|
|
4
4
|
import type { WorkflowSerializableValue } from "../shared/types.js";
|
|
5
5
|
import type { WorkflowSerializableObject as DurableInputs } from "./types.js";
|
|
6
6
|
import { InMemoryDurableBackend, type DurableWorkflowBackend, type WorkflowRegistrationInput } from "./backend.js";
|
|
7
|
-
import { encodeCheckpoint,
|
|
7
|
+
import { encodeCheckpoint, classifyCheckpointPayload } from "./dbos-envelope.js";
|
|
8
|
+
import { classifyLatestMetadata, encodeMetadata, isMetadataStep, metadataStepName } from "./dbos-metadata.js";
|
|
9
|
+
import { DBOS_DELETION_STEP, classifyDbosDeletionTombstone, encodeDbosDeletionTombstone } from "./dbos-tombstone.js";
|
|
8
10
|
|
|
9
11
|
// ---------------------------------------------------------------------------
|
|
10
12
|
// SDK abstraction
|
|
@@ -28,6 +30,8 @@ export interface DbosSdkHandle {
|
|
|
28
30
|
readonly listStepRecords: (workflowId: string) => Promise<readonly DbosStepRecord[]>;
|
|
29
31
|
/** Record a checkpoint step output (envelope) to DBOS. */
|
|
30
32
|
readonly recordStepOutput: (workflowId: string, stepName: string, output: WorkflowSerializableValue) => Promise<void>;
|
|
33
|
+
/** Permanently delete a root workflow and all prefix checkpoint records. */
|
|
34
|
+
readonly deleteWorkflowData: (workflowId: string) => Promise<void>;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
export interface DbosWorkflowInfo {
|
|
@@ -81,6 +85,7 @@ interface DbosStatic {
|
|
|
81
85
|
resumeWorkflow(workflowId: string): Promise<DbosWorkflowHandle>;
|
|
82
86
|
cancelWorkflow(workflowId: string, options?: { readonly cancelChildren?: boolean }): Promise<void>;
|
|
83
87
|
listWorkflows(input: Record<string, WorkflowSerializableValue>): Promise<readonly DbosStatus[]>;
|
|
88
|
+
deleteWorkflows(workflowIds: string[], deleteChildren?: boolean): Promise<void>;
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
export function isDbosConfigured(): boolean {
|
|
@@ -158,6 +163,17 @@ function createRealDbosHandle(
|
|
|
158
163
|
async recordStepOutput(workflowId, stepName, output) {
|
|
159
164
|
await dbos.startWorkflow(checkpointWorkflow, { workflowID: checkpointId(workflowId, stepName) })(workflowId, stepName, output);
|
|
160
165
|
},
|
|
166
|
+
async deleteWorkflowData(workflowId) {
|
|
167
|
+
const prefix = `${workflowId}:checkpoint:`;
|
|
168
|
+
const checkpointIds: string[] = [];
|
|
169
|
+
const pageSize = 1_000;
|
|
170
|
+
for (let offset = 0;; offset += pageSize) {
|
|
171
|
+
const page = await dbos.listWorkflows({ workflow_id_prefix: prefix, limit: pageSize, offset });
|
|
172
|
+
checkpointIds.push(...page.map((status) => status.workflowID ?? status.workflowId ?? "").filter((id) => id.length > 0));
|
|
173
|
+
if (page.length < pageSize) break;
|
|
174
|
+
}
|
|
175
|
+
await dbos.deleteWorkflows([...new Set([workflowId, ...checkpointIds])], true);
|
|
176
|
+
},
|
|
161
177
|
};
|
|
162
178
|
}
|
|
163
179
|
|
|
@@ -202,6 +218,9 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
202
218
|
private readonly mem = new InMemoryDurableBackend();
|
|
203
219
|
private readonly sdk: DbosSdkHandle;
|
|
204
220
|
private readonly hydrated = new Set<string>();
|
|
221
|
+
private readonly incompatible = new Set<string>();
|
|
222
|
+
private readonly compatible = new Set<string>();
|
|
223
|
+
private readonly locallyRegistered = new Set<string>();
|
|
205
224
|
private writeQueue: Promise<void> = Promise.resolve();
|
|
206
225
|
private writeErrors: Error[] = [];
|
|
207
226
|
|
|
@@ -210,6 +229,9 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
210
229
|
}
|
|
211
230
|
|
|
212
231
|
registerWorkflow(handle: WorkflowRegistrationInput): void {
|
|
232
|
+
this.incompatible.delete(handle.workflowId);
|
|
233
|
+
this.compatible.add(handle.workflowId);
|
|
234
|
+
this.locallyRegistered.add(handle.workflowId);
|
|
213
235
|
this.mem.registerWorkflow(handle);
|
|
214
236
|
this.enqueueWrite(async () => {
|
|
215
237
|
await this.sdk.startWorkflow(handle.workflowId, handle.name, handle.inputs);
|
|
@@ -218,12 +240,15 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
218
240
|
}
|
|
219
241
|
|
|
220
242
|
recordCheckpoint(checkpoint: DurableCheckpoint): void {
|
|
243
|
+
if (!this.isWorkflowLoadable(checkpoint.workflowId)) return;
|
|
221
244
|
this.mem.recordCheckpoint(checkpoint);
|
|
222
245
|
this.enqueueWrite(() => this.persistCheckpoint(checkpoint));
|
|
223
246
|
}
|
|
224
247
|
|
|
225
248
|
async recordCheckpointAsync(checkpoint: DurableCheckpoint): Promise<void> {
|
|
249
|
+
if (!this.isWorkflowLoadable(checkpoint.workflowId)) return;
|
|
226
250
|
await this.enqueueWrite(async () => {
|
|
251
|
+
if (!this.isWorkflowLoadable(checkpoint.workflowId)) return;
|
|
227
252
|
await this.persistCheckpointRecord(checkpoint);
|
|
228
253
|
this.mem.recordCheckpoint(checkpoint);
|
|
229
254
|
await this.writeMetadata(checkpoint.workflowId);
|
|
@@ -247,17 +272,48 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
247
272
|
getWorkflow(workflowId: string): DurableWorkflowHandle | undefined { return this.mem.getWorkflow(workflowId); }
|
|
248
273
|
|
|
249
274
|
setWorkflowStatus(workflowId: string, status: DurableWorkflowStatus, pendingPrompts?: number, resumable?: boolean): void {
|
|
275
|
+
if (!this.isWorkflowLoadable(workflowId)) return;
|
|
250
276
|
this.mem.setWorkflowStatus(workflowId, status, pendingPrompts, resumable);
|
|
251
277
|
this.enqueueWrite(async () => {
|
|
278
|
+
if (!this.isWorkflowLoadable(workflowId)) return;
|
|
252
279
|
if (status === "cancelled") await this.sdk.cancelWorkflow(workflowId);
|
|
253
280
|
else if (status === "running") await this.sdk.resumeWorkflow(workflowId);
|
|
254
281
|
await this.writeMetadata(workflowId);
|
|
255
282
|
});
|
|
256
283
|
}
|
|
257
284
|
|
|
258
|
-
listResumableWorkflows(): readonly ResumableWorkflowEntry[] {
|
|
259
|
-
|
|
260
|
-
|
|
285
|
+
listResumableWorkflows(): readonly ResumableWorkflowEntry[] {
|
|
286
|
+
return this.mem.listResumableWorkflows().filter((entry) => !this.incompatible.has(entry.workflowId));
|
|
287
|
+
}
|
|
288
|
+
listCompletedWorkflows(): readonly ResumableWorkflowEntry[] {
|
|
289
|
+
return this.mem.listCompletedWorkflows().filter((entry) => !this.incompatible.has(entry.workflowId));
|
|
290
|
+
}
|
|
291
|
+
toCacheEntry(workflowId: string) { return this.incompatible.has(workflowId) ? undefined : this.mem.toCacheEntry(workflowId); }
|
|
292
|
+
async deleteWorkflow(workflowId: string): Promise<void> {
|
|
293
|
+
this.incompatible.add(workflowId);
|
|
294
|
+
this.compatible.delete(workflowId);
|
|
295
|
+
this.locallyRegistered.delete(workflowId);
|
|
296
|
+
this.hydrated.delete(workflowId);
|
|
297
|
+
await this.mem.deleteWorkflow(workflowId);
|
|
298
|
+
await this.enqueueWrite(async () => {
|
|
299
|
+
await this.sdk.deleteWorkflowData(workflowId);
|
|
300
|
+
await this.sdk.recordStepOutput(workflowId, DBOS_DELETION_STEP, encodeDbosDeletionTombstone(workflowId));
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
isWorkflowLoadable(workflowId: string): boolean {
|
|
304
|
+
return !this.incompatible.has(workflowId)
|
|
305
|
+
&& (this.locallyRegistered.has(workflowId) || this.compatible.has(workflowId));
|
|
306
|
+
}
|
|
307
|
+
reset(): void {
|
|
308
|
+
this.mem.reset();
|
|
309
|
+
this.hydrated.clear();
|
|
310
|
+
this.incompatible.clear();
|
|
311
|
+
this.compatible.clear();
|
|
312
|
+
this.locallyRegistered.clear();
|
|
313
|
+
this.writeQueue = Promise.resolve();
|
|
314
|
+
this.writeErrors = [];
|
|
315
|
+
}
|
|
316
|
+
|
|
261
317
|
async flush(): Promise<void> {
|
|
262
318
|
await this.writeQueue;
|
|
263
319
|
if (this.writeErrors.length === 0) return;
|
|
@@ -266,63 +322,76 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
266
322
|
throw first;
|
|
267
323
|
}
|
|
268
324
|
|
|
269
|
-
/**
|
|
270
|
-
* Hydrate a single workflow's handle and checkpoints from DBOS into the
|
|
271
|
-
* in-memory mirror. Idempotent: skips workflows already hydrated with
|
|
272
|
-
* checkpoints. Safe to call before synchronous replay reads.
|
|
273
|
-
*/
|
|
274
325
|
async hydrateWorkflow(workflowId: string): Promise<void> {
|
|
275
|
-
if (this.
|
|
326
|
+
if (this.locallyRegistered.has(workflowId)) return;
|
|
276
327
|
const info = await this.sdk.retrieveWorkflow(workflowId);
|
|
277
|
-
if (info !== undefined
|
|
278
|
-
this.
|
|
279
|
-
|
|
280
|
-
name: info.name,
|
|
281
|
-
inputs: info.inputs ?? {},
|
|
282
|
-
createdAt: info.createdAt,
|
|
283
|
-
status: dbosStatusToDurable(info.status),
|
|
284
|
-
});
|
|
328
|
+
if (info !== undefined) {
|
|
329
|
+
await this.hydrateInfo(info);
|
|
330
|
+
return;
|
|
285
331
|
}
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
if (isMetadataStep(rec.stepName)) continue;
|
|
290
|
-
const cp = decodeToCheckpoint(workflowId, rec.stepName, rec.output);
|
|
291
|
-
if (cp !== undefined) this.mem.recordCheckpoint(cp);
|
|
292
|
-
}
|
|
293
|
-
this.hydrated.add(workflowId);
|
|
332
|
+
const records = await this.sdk.listStepRecords(workflowId);
|
|
333
|
+
const deletion = classifyDbosDeletionTombstone(records, workflowId);
|
|
334
|
+
if (deletion !== "absent") await this.suppressWorkflow(workflowId);
|
|
294
335
|
}
|
|
295
336
|
|
|
296
|
-
/**
|
|
297
|
-
* Hydrate all resumable workflows from DBOS into the in-memory mirror.
|
|
298
|
-
* Called by the resume/list path before enumerating resumable entries so
|
|
299
|
-
* a fresh process discovers workflows persisted by a prior session.
|
|
300
|
-
*/
|
|
301
337
|
async hydrateResumableWorkflows(): Promise<void> {
|
|
302
338
|
const all = await this.sdk.listAllWorkflows();
|
|
303
339
|
for (const info of all) {
|
|
304
|
-
if (this.
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
340
|
+
if (this.locallyRegistered.has(info.workflowId)) continue;
|
|
341
|
+
await this.hydrateInfo(info);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
private async hydrateInfo(info: DbosWorkflowInfo): Promise<void> {
|
|
346
|
+
const records = await this.sdk.listStepRecords(info.workflowId);
|
|
347
|
+
const metadata = classifyLatestMetadata(records, info.workflowId);
|
|
348
|
+
if (metadata.kind === "legacy") {
|
|
349
|
+
await this.cleanupLegacyWorkflow(info.workflowId);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (metadata.kind !== "current") {
|
|
353
|
+
await this.suppressWorkflow(info.workflowId);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
const checkpoints: DurableCheckpoint[] = [];
|
|
357
|
+
for (const record of records) {
|
|
358
|
+
if (isMetadataStep(record.stepName) || record.stepName === DBOS_DELETION_STEP) continue;
|
|
359
|
+
const classified = classifyCheckpointPayload(info.workflowId, record.stepName, record.output);
|
|
360
|
+
if (classified.kind === "legacy") {
|
|
361
|
+
await this.cleanupLegacyWorkflow(info.workflowId);
|
|
362
|
+
return;
|
|
312
363
|
}
|
|
313
|
-
if (
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
for (const rec of stepRecords) {
|
|
317
|
-
if (isMetadataStep(rec.stepName)) continue;
|
|
318
|
-
const cp = decodeToCheckpoint(info.workflowId, rec.stepName, rec.output);
|
|
319
|
-
if (cp !== undefined) this.mem.recordCheckpoint(cp);
|
|
320
|
-
}
|
|
321
|
-
this.hydrated.add(info.workflowId);
|
|
364
|
+
if (classified.kind === "unknown") {
|
|
365
|
+
await this.suppressWorkflow(info.workflowId);
|
|
366
|
+
return;
|
|
322
367
|
}
|
|
368
|
+
checkpoints.push(classified.checkpoint);
|
|
369
|
+
}
|
|
370
|
+
await this.mem.deleteWorkflow(info.workflowId);
|
|
371
|
+
this.incompatible.delete(info.workflowId);
|
|
372
|
+
this.compatible.add(info.workflowId);
|
|
373
|
+
this.applyMetadata(info.workflowId, metadata.entry);
|
|
374
|
+
checkpoints.forEach((checkpoint) => this.mem.recordCheckpoint(checkpoint));
|
|
375
|
+
this.hydrated.add(info.workflowId);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
private async cleanupLegacyWorkflow(workflowId: string): Promise<void> {
|
|
379
|
+
try {
|
|
380
|
+
await this.deleteWorkflow(workflowId);
|
|
381
|
+
} catch {
|
|
382
|
+
// deleteWorkflow marks the in-memory mirror incompatible before durable
|
|
383
|
+
// cleanup. Its write queue records/logs the error, while hydration must
|
|
384
|
+
// still return a filtered catalog and allow later discovery to retry.
|
|
323
385
|
}
|
|
324
386
|
}
|
|
325
387
|
|
|
388
|
+
private async suppressWorkflow(workflowId: string): Promise<void> {
|
|
389
|
+
this.incompatible.add(workflowId);
|
|
390
|
+
this.compatible.delete(workflowId);
|
|
391
|
+
this.hydrated.delete(workflowId);
|
|
392
|
+
await this.mem.deleteWorkflow(workflowId);
|
|
393
|
+
}
|
|
394
|
+
|
|
326
395
|
private enqueueWrite(fn: () => Promise<void>): Promise<void> {
|
|
327
396
|
const next = this.writeQueue.then(fn, fn);
|
|
328
397
|
this.writeQueue = next.catch((err) => {
|
|
@@ -339,14 +408,7 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
339
408
|
await this.sdk.recordStepOutput(workflowId, metadataStepName(entry.ts), encodeMetadata(entry));
|
|
340
409
|
}
|
|
341
410
|
|
|
342
|
-
private applyMetadata(workflowId: string,
|
|
343
|
-
const entries = records
|
|
344
|
-
.filter((r) => isMetadataStep(r.stepName))
|
|
345
|
-
.map((r) => decodeMetadata(r.output))
|
|
346
|
-
.filter((entry): entry is DurableCheckpointEntry => entry !== undefined)
|
|
347
|
-
.sort((a, b) => a.ts - b.ts);
|
|
348
|
-
const entry = entries.at(-1);
|
|
349
|
-
if (entry === undefined) return;
|
|
411
|
+
private applyMetadata(workflowId: string, entry: import("./types.js").DurableCheckpointEntry): void {
|
|
350
412
|
this.mem.registerWorkflow({
|
|
351
413
|
workflowId,
|
|
352
414
|
name: entry.name,
|
|
@@ -367,116 +429,4 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
|
|
|
367
429
|
}
|
|
368
430
|
}
|
|
369
431
|
|
|
370
|
-
|
|
371
|
-
const METADATA_VERSION = 1;
|
|
372
|
-
|
|
373
|
-
function metadataStepName(ts: number): string {
|
|
374
|
-
return `${METADATA_STEP_PREFIX}:${ts}:${crypto.randomUUID()}`;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
function isMetadataStep(stepName: string): boolean {
|
|
378
|
-
return stepName === METADATA_STEP_PREFIX || stepName.startsWith(`${METADATA_STEP_PREFIX}:`);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
interface DbosMetadataEnvelope {
|
|
382
|
-
readonly __atomicDurableMetadata: true;
|
|
383
|
-
readonly version: 1;
|
|
384
|
-
readonly entry: WorkflowSerializableValue;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
function encodeMetadata(entry: DurableCheckpointEntry): WorkflowSerializableValue {
|
|
388
|
-
return {
|
|
389
|
-
__atomicDurableMetadata: true,
|
|
390
|
-
version: METADATA_VERSION,
|
|
391
|
-
entry: {
|
|
392
|
-
type: entry.type,
|
|
393
|
-
workflowId: entry.workflowId,
|
|
394
|
-
name: entry.name,
|
|
395
|
-
inputs: entry.inputs,
|
|
396
|
-
status: entry.status,
|
|
397
|
-
completedCheckpoints: entry.completedCheckpoints,
|
|
398
|
-
pendingPrompts: entry.pendingPrompts,
|
|
399
|
-
...(entry.label !== undefined ? { label: entry.label } : {}),
|
|
400
|
-
...(entry.rootWorkflowId !== undefined ? { rootWorkflowId: entry.rootWorkflowId } : {}),
|
|
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 } : {}),
|
|
406
|
-
ts: entry.ts,
|
|
407
|
-
},
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
function decodeMetadata(value: WorkflowSerializableValue): DurableCheckpointEntry | undefined {
|
|
412
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
|
|
413
|
-
const raw = value as Partial<DbosMetadataEnvelope>;
|
|
414
|
-
if (raw.__atomicDurableMetadata !== true || raw.version !== METADATA_VERSION) return undefined;
|
|
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";
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
function dbosStatusToDurable(status: string): DurableWorkflowStatus {
|
|
472
|
-
switch (status) {
|
|
473
|
-
case "SUCCESS": return "completed";
|
|
474
|
-
case "ERROR": return "failed";
|
|
475
|
-
case "CANCELLED": return "cancelled";
|
|
476
|
-
case "PENDING":
|
|
477
|
-
case "ENQUEUED":
|
|
478
|
-
case "DELAYED":
|
|
479
|
-
return "running";
|
|
480
|
-
default: return "running";
|
|
481
|
-
}
|
|
482
|
-
}
|
|
432
|
+
// Metadata encoding/classification lives in dbos-metadata.ts to keep this adapter focused.
|
|
@@ -23,9 +23,10 @@ import type {
|
|
|
23
23
|
DurableUiCheckpoint,
|
|
24
24
|
UiPromptKind,
|
|
25
25
|
} from "./types.js";
|
|
26
|
+
import { classifyDurableFormatVersion, DURABLE_FORMAT_VERSION } from "./format-version.js";
|
|
26
27
|
|
|
27
28
|
/** Envelope schema version. */
|
|
28
|
-
export const DBOS_ENVELOPE_VERSION =
|
|
29
|
+
export const DBOS_ENVELOPE_VERSION = DURABLE_FORMAT_VERSION;
|
|
29
30
|
|
|
30
31
|
/** Marker key present on every envelope payload. */
|
|
31
32
|
const ENVELOPE_MARKER = "__dbos_checkpoint__";
|
|
@@ -105,9 +106,35 @@ export function encodeCheckpoint(cp: DurableCheckpoint): DbosCheckpointEnvelope
|
|
|
105
106
|
* Type guard: is this value a checkpoint envelope?
|
|
106
107
|
*/
|
|
107
108
|
export function isCheckpointEnvelope(value: WorkflowSerializableValue | undefined): value is DbosCheckpointEnvelope {
|
|
109
|
+
if (!hasCheckpointEnvelopeMarker(value)) return false;
|
|
110
|
+
return value.v === DBOS_ENVELOPE_VERSION;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function hasCheckpointEnvelopeMarker(value: WorkflowSerializableValue | undefined): value is Record<string, WorkflowSerializableValue> {
|
|
108
114
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
109
|
-
|
|
110
|
-
|
|
115
|
+
return (value as Record<string, WorkflowSerializableValue>)[ENVELOPE_MARKER] === ENVELOPE_MARKER;
|
|
116
|
+
}
|
|
117
|
+
export type DbosCheckpointCompatibility =
|
|
118
|
+
| { readonly kind: "current"; readonly checkpoint: DurableCheckpoint }
|
|
119
|
+
| { readonly kind: "legacy" }
|
|
120
|
+
| { readonly kind: "unknown" };
|
|
121
|
+
|
|
122
|
+
/** Classify and decode one DBOS checkpoint payload without reinterpreting marked formats. */
|
|
123
|
+
export function classifyCheckpointPayload(
|
|
124
|
+
workflowId: string,
|
|
125
|
+
stepName: string,
|
|
126
|
+
value: WorkflowSerializableValue,
|
|
127
|
+
): DbosCheckpointCompatibility {
|
|
128
|
+
if (!hasCheckpointEnvelopeMarker(value)) return { kind: "current", checkpoint: decodeLegacy(workflowId, stepName, value) };
|
|
129
|
+
const compatibility = classifyDurableFormatVersion(value.v);
|
|
130
|
+
if (compatibility !== "current") return { kind: compatibility };
|
|
131
|
+
const hasOutput = value["hasOutput"];
|
|
132
|
+
const containsOutput = value["output"] !== undefined;
|
|
133
|
+
if (value["checkpointId"] !== stepName || typeof hasOutput !== "boolean" || hasOutput !== containsOutput) {
|
|
134
|
+
return { kind: "unknown" };
|
|
135
|
+
}
|
|
136
|
+
const checkpoint = decodeEnvelope(workflowId, value as DbosCheckpointEnvelope);
|
|
137
|
+
return checkpoint === undefined ? { kind: "unknown" } : { kind: "current", checkpoint };
|
|
111
138
|
}
|
|
112
139
|
|
|
113
140
|
/**
|
|
@@ -124,15 +151,18 @@ export function decodeToCheckpoint(
|
|
|
124
151
|
stepName: string,
|
|
125
152
|
value: WorkflowSerializableValue,
|
|
126
153
|
): DurableCheckpoint | undefined {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return decodeLegacy(workflowId, stepName, value);
|
|
154
|
+
const classified = classifyCheckpointPayload(workflowId, stepName, value);
|
|
155
|
+
return classified.kind === "current" ? classified.checkpoint : undefined;
|
|
130
156
|
}
|
|
131
157
|
|
|
132
158
|
function decodeEnvelope(workflowId: string, env: DbosCheckpointEnvelope): DurableCheckpoint | undefined {
|
|
159
|
+
if (typeof env.checkpointId !== "string" || env.checkpointId.length === 0
|
|
160
|
+
|| typeof env.completedAt !== "number" || !Number.isFinite(env.completedAt)
|
|
161
|
+
|| (env.name !== undefined && typeof env.name !== "string")
|
|
162
|
+
|| (env.hasOutput !== undefined && typeof env.hasOutput !== "boolean")) return undefined;
|
|
133
163
|
const common = { workflowId, checkpointId: env.checkpointId, completedAt: env.completedAt };
|
|
134
164
|
if (env.kind === "tool") {
|
|
135
|
-
if (env.argsHash
|
|
165
|
+
if (typeof env.argsHash !== "string" || env.output === undefined) return undefined;
|
|
136
166
|
return {
|
|
137
167
|
kind: "tool",
|
|
138
168
|
...common,
|
|
@@ -142,7 +172,8 @@ function decodeEnvelope(workflowId: string, env: DbosCheckpointEnvelope): Durabl
|
|
|
142
172
|
} as DurableToolCheckpoint;
|
|
143
173
|
}
|
|
144
174
|
if (env.kind === "ui") {
|
|
145
|
-
if (env.promptHash
|
|
175
|
+
if (typeof env.promptHash !== "string" || !isUiPromptKind(env.promptKind) || env.output === undefined
|
|
176
|
+
|| (env.message !== undefined && typeof env.message !== "string")) return undefined;
|
|
146
177
|
return {
|
|
147
178
|
kind: "ui",
|
|
148
179
|
...common,
|
|
@@ -152,6 +183,18 @@ function decodeEnvelope(workflowId: string, env: DbosCheckpointEnvelope): Durabl
|
|
|
152
183
|
response: env.output,
|
|
153
184
|
} as DurableUiCheckpoint;
|
|
154
185
|
}
|
|
186
|
+
if (env.kind !== "stage"
|
|
187
|
+
|| (env.replayKey !== undefined && typeof env.replayKey !== "string")
|
|
188
|
+
|| (env.sessionId !== undefined && typeof env.sessionId !== "string")
|
|
189
|
+
|| (env.sessionFile !== undefined && typeof env.sessionFile !== "string")
|
|
190
|
+
|| !isOptionalFiniteNumber(env.startedAt)
|
|
191
|
+
|| !isOptionalFiniteNumber(env.endedAt)
|
|
192
|
+
|| !isOptionalFiniteNumber(env.durationMs)
|
|
193
|
+
|| (env.result !== undefined && typeof env.result !== "string")
|
|
194
|
+
|| (env.model !== undefined && typeof env.model !== "string")
|
|
195
|
+
|| (env.fastMode !== undefined && typeof env.fastMode !== "boolean")
|
|
196
|
+
|| (env.attemptedModels !== undefined && !isStringArray(env.attemptedModels))
|
|
197
|
+
|| (env.modelAttempts !== undefined && !isModelAttempts(env.modelAttempts))) return undefined;
|
|
155
198
|
return {
|
|
156
199
|
kind: "stage",
|
|
157
200
|
...common,
|
|
@@ -172,6 +215,39 @@ function decodeEnvelope(workflowId: string, env: DbosCheckpointEnvelope): Durabl
|
|
|
172
215
|
}
|
|
173
216
|
|
|
174
217
|
|
|
218
|
+
function isModelAttempts(value: WorkflowSerializableValue | undefined): boolean {
|
|
219
|
+
return Array.isArray(value) && value.every((attempt) => {
|
|
220
|
+
if (typeof attempt !== "object" || attempt === null || Array.isArray(attempt)) return false;
|
|
221
|
+
const record = attempt as Record<string, WorkflowSerializableValue>;
|
|
222
|
+
return typeof record["model"] === "string"
|
|
223
|
+
&& typeof record["success"] === "boolean"
|
|
224
|
+
&& (record["reasoningLevel"] === undefined || isReasoningLevel(record["reasoningLevel"]))
|
|
225
|
+
&& (record["error"] === undefined || typeof record["error"] === "string")
|
|
226
|
+
&& (record["usage"] === undefined || isModelUsage(record["usage"]));
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function isReasoningLevel(value: WorkflowSerializableValue): boolean {
|
|
231
|
+
return value === "off" || value === "minimal" || value === "low" || value === "medium"
|
|
232
|
+
|| value === "high" || value === "xhigh" || value === "max";
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function isModelUsage(value: WorkflowSerializableValue): boolean {
|
|
236
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
237
|
+
const usage = value as Record<string, WorkflowSerializableValue>;
|
|
238
|
+
return ["input", "output", "cacheRead", "cacheWrite", "cost", "turns"]
|
|
239
|
+
.every((key) => usage[key] === undefined || (typeof usage[key] === "number" && Number.isFinite(usage[key])));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function isUiPromptKind(value: WorkflowSerializableValue | undefined): value is UiPromptKind {
|
|
243
|
+
return value === "input" || value === "confirm" || value === "select"
|
|
244
|
+
|| value === "editor" || value === "custom";
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function isOptionalFiniteNumber(value: WorkflowSerializableValue | undefined): boolean {
|
|
248
|
+
return value === undefined || (typeof value === "number" && Number.isFinite(value));
|
|
249
|
+
}
|
|
250
|
+
|
|
175
251
|
function isStringArray(value: WorkflowSerializableValue | undefined): value is readonly string[] {
|
|
176
252
|
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
177
253
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { WorkflowSerializableValue } from "../shared/types.js";
|
|
2
|
+
import type { DbosStepRecord } from "./dbos-backend.js";
|
|
3
|
+
import { classifyDurableFormatVersion, DURABLE_FORMAT_VERSION } from "./format-version.js";
|
|
4
|
+
import type { DurableCheckpointEntry, DurableWorkflowStatus } from "./types.js";
|
|
5
|
+
|
|
6
|
+
const METADATA_STEP_PREFIX = "__atomic_metadata";
|
|
7
|
+
|
|
8
|
+
export type DbosMetadataCompatibility =
|
|
9
|
+
| { readonly kind: "current"; readonly entry: DurableCheckpointEntry }
|
|
10
|
+
| { readonly kind: "legacy" }
|
|
11
|
+
| { readonly kind: "unknown" }
|
|
12
|
+
| { readonly kind: "unavailable" };
|
|
13
|
+
|
|
14
|
+
export function metadataStepName(ts: number): string {
|
|
15
|
+
return `${METADATA_STEP_PREFIX}:${ts}:${crypto.randomUUID()}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function isMetadataStep(stepName: string): boolean {
|
|
19
|
+
return stepName === METADATA_STEP_PREFIX || stepName.startsWith(`${METADATA_STEP_PREFIX}:`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function encodeMetadata(entry: DurableCheckpointEntry): WorkflowSerializableValue {
|
|
23
|
+
return {
|
|
24
|
+
__atomicDurableMetadata: true,
|
|
25
|
+
version: DURABLE_FORMAT_VERSION,
|
|
26
|
+
entry: {
|
|
27
|
+
formatVersion: entry.formatVersion,
|
|
28
|
+
type: entry.type,
|
|
29
|
+
workflowId: entry.workflowId,
|
|
30
|
+
name: entry.name,
|
|
31
|
+
inputs: entry.inputs,
|
|
32
|
+
status: entry.status,
|
|
33
|
+
completedCheckpoints: entry.completedCheckpoints,
|
|
34
|
+
pendingPrompts: entry.pendingPrompts,
|
|
35
|
+
...(entry.label !== undefined ? { label: entry.label } : {}),
|
|
36
|
+
...(entry.rootWorkflowId !== undefined ? { rootWorkflowId: entry.rootWorkflowId } : {}),
|
|
37
|
+
...(entry.resumable !== undefined ? { resumable: entry.resumable } : {}),
|
|
38
|
+
...(entry.invocationCwd !== undefined ? { invocationCwd: entry.invocationCwd } : {}),
|
|
39
|
+
...(entry.workflowCwd !== undefined ? { workflowCwd: entry.workflowCwd } : {}),
|
|
40
|
+
...(entry.repositoryRoot !== undefined ? { repositoryRoot: entry.repositoryRoot } : {}),
|
|
41
|
+
...(entry.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: entry.gitWorktreeRoot } : {}),
|
|
42
|
+
ts: entry.ts,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function classifyLatestMetadata(records: readonly DbosStepRecord[], workflowId: string): DbosMetadataCompatibility {
|
|
48
|
+
const metadata = records.filter((record) => isMetadataStep(record.stepName));
|
|
49
|
+
if (metadata.length === 0) return { kind: "unavailable" };
|
|
50
|
+
const latest = metadata.reduce((selected, record) => metadataTimestamp(record) >= metadataTimestamp(selected) ? record : selected);
|
|
51
|
+
if (typeof latest.output !== "object" || latest.output === null || Array.isArray(latest.output)) return { kind: "unknown" };
|
|
52
|
+
const raw = latest.output as Record<string, WorkflowSerializableValue>;
|
|
53
|
+
if (raw["__atomicDurableMetadata"] !== true) return { kind: "unknown" };
|
|
54
|
+
const compatibility = classifyDurableFormatVersion(raw["version"]);
|
|
55
|
+
if (compatibility !== "current") return { kind: compatibility };
|
|
56
|
+
const entry = parseDurableCheckpointEntry(raw["entry"], workflowId);
|
|
57
|
+
return entry === undefined ? { kind: "unknown" } : { kind: "current", entry };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function metadataTimestamp(record: DbosStepRecord): number {
|
|
61
|
+
const segment = record.stepName.split(":")[1];
|
|
62
|
+
const fromName = segment === undefined ? Number.NaN : Number(segment);
|
|
63
|
+
return Number.isFinite(fromName) ? fromName : (record.completedAt ?? 0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function parseDurableCheckpointEntry(
|
|
67
|
+
value: WorkflowSerializableValue | undefined,
|
|
68
|
+
workflowId: string,
|
|
69
|
+
): DurableCheckpointEntry | undefined {
|
|
70
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
|
|
71
|
+
const entry = value as Partial<DurableCheckpointEntry>;
|
|
72
|
+
if (entry.workflowId !== workflowId
|
|
73
|
+
|| entry.formatVersion !== DURABLE_FORMAT_VERSION
|
|
74
|
+
|| entry.type !== "workflow.durable.checkpoint"
|
|
75
|
+
|| typeof entry.workflowId !== "string"
|
|
76
|
+
|| typeof entry.name !== "string"
|
|
77
|
+
|| typeof entry.inputs !== "object"
|
|
78
|
+
|| entry.inputs === null
|
|
79
|
+
|| Array.isArray(entry.inputs)
|
|
80
|
+
|| typeof entry.status !== "string"
|
|
81
|
+
|| !isDurableWorkflowStatus(entry.status)
|
|
82
|
+
|| typeof entry.completedCheckpoints !== "number"
|
|
83
|
+
|| typeof entry.pendingPrompts !== "number"
|
|
84
|
+
|| typeof entry.ts !== "number"
|
|
85
|
+
|| (entry.label !== undefined && typeof entry.label !== "string")
|
|
86
|
+
|| (entry.rootWorkflowId !== undefined && typeof entry.rootWorkflowId !== "string")
|
|
87
|
+
|| (entry.resumable !== undefined && typeof entry.resumable !== "boolean")
|
|
88
|
+
|| (entry.invocationCwd !== undefined && typeof entry.invocationCwd !== "string")
|
|
89
|
+
|| (entry.workflowCwd !== undefined && typeof entry.workflowCwd !== "string")
|
|
90
|
+
|| (entry.repositoryRoot !== undefined && typeof entry.repositoryRoot !== "string")
|
|
91
|
+
|| (entry.gitWorktreeRoot !== undefined && typeof entry.gitWorktreeRoot !== "string")) return undefined;
|
|
92
|
+
return entry as DurableCheckpointEntry;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function isDurableWorkflowStatus(value: string): value is DurableWorkflowStatus {
|
|
96
|
+
return value === "running" || value === "paused" || value === "completed"
|
|
97
|
+
|| value === "failed" || value === "cancelled" || value === "blocked";
|
|
98
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { WorkflowSerializableValue } from "../shared/types.js";
|
|
2
|
+
import type { DbosStepRecord } from "./dbos-backend.js";
|
|
3
|
+
import { classifyDurableFormatVersion, DURABLE_FORMAT_VERSION } from "./format-version.js";
|
|
4
|
+
|
|
5
|
+
export const DBOS_DELETION_STEP = "__atomic_deleted";
|
|
6
|
+
|
|
7
|
+
export type DbosDeletionCompatibility = "current" | "unknown" | "absent";
|
|
8
|
+
|
|
9
|
+
export function encodeDbosDeletionTombstone(workflowId: string): WorkflowSerializableValue {
|
|
10
|
+
return {
|
|
11
|
+
__atomicDurableDeleted: true,
|
|
12
|
+
version: DURABLE_FORMAT_VERSION,
|
|
13
|
+
workflowId,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function classifyDbosDeletionTombstone(
|
|
18
|
+
records: readonly DbosStepRecord[],
|
|
19
|
+
workflowId: string,
|
|
20
|
+
): DbosDeletionCompatibility {
|
|
21
|
+
const record = records.find((candidate) => candidate.stepName === DBOS_DELETION_STEP);
|
|
22
|
+
if (record === undefined) return "absent";
|
|
23
|
+
if (typeof record.output !== "object" || record.output === null || Array.isArray(record.output)) return "unknown";
|
|
24
|
+
const raw = record.output as Record<string, WorkflowSerializableValue>;
|
|
25
|
+
if (raw["__atomicDurableDeleted"] !== true || raw["workflowId"] !== workflowId) return "unknown";
|
|
26
|
+
return classifyDurableFormatVersion(raw["version"]) === "current" ? "current" : "unknown";
|
|
27
|
+
}
|
|
@@ -87,7 +87,7 @@ export function createDefaultFileBackend(): DurableWorkflowBackend {
|
|
|
87
87
|
export function createWorkflowFileBackend(workflowId: string): DurableWorkflowBackend {
|
|
88
88
|
const dir = defaultDurableStateDir();
|
|
89
89
|
if (dir === undefined) return createInMemoryBackend();
|
|
90
|
-
return new FileDurableBackend(durableStateFileFor(dir, workflowId));
|
|
90
|
+
return new FileDurableBackend(durableStateFileFor(dir, workflowId), workflowId);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
function isDurabilityOptedOut(): boolean {
|