@bastani/atomic 0.8.27 → 0.8.28-alpha.2
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 +75 -0
- package/README.md +120 -118
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +2 -2
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +22 -0
- package/dist/builtin/workflows/README.md +11 -9
- package/dist/builtin/workflows/builtin/open-claude-design.ts +150 -13
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/authoring.d.ts +5 -2
- package/dist/builtin/workflows/src/extension/background-ui-adapter.ts +3 -1
- package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +17 -25
- package/dist/builtin/workflows/src/extension/index.ts +133 -18
- package/dist/builtin/workflows/src/extension/render-result.ts +22 -2
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +3 -3
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +210 -16
- package/dist/builtin/workflows/src/sdk-surface.ts +1 -1
- package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +42 -5
- package/dist/builtin/workflows/src/shared/store-types.ts +8 -2
- package/dist/builtin/workflows/src/shared/store.ts +51 -0
- package/dist/builtin/workflows/src/shared/types.ts +14 -4
- package/dist/builtin/workflows/src/tui/chat-surface.ts +32 -33
- package/dist/builtin/workflows/src/tui/graph-view.ts +4 -1
- package/dist/builtin/workflows/src/tui/prompt-card.ts +6 -0
- package/dist/builtin/workflows/src/tui/run-detail.ts +11 -4
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +11 -1
- package/dist/builtin/workflows/src/tui/status-list.ts +32 -2
- package/dist/cli/args.d.ts +4 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +35 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/project-trust.d.ts +10 -0
- package/dist/cli/project-trust.d.ts.map +1 -0
- package/dist/cli/project-trust.js +36 -0
- package/dist/cli/project-trust.js.map +1 -0
- package/dist/cli/startup-ui.d.ts +7 -0
- package/dist/cli/startup-ui.d.ts.map +1 -0
- package/dist/cli/startup-ui.js +57 -0
- package/dist/cli/startup-ui.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +24 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +3 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +1 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +2 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +2 -2
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +9 -5
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +205 -51
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-guidance.d.ts +10 -1
- package/dist/core/auth-guidance.d.ts.map +1 -1
- package/dist/core/auth-guidance.js +26 -1
- package/dist/core/auth-guidance.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -3
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +5 -3
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +16 -10
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +4 -84
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +20 -502
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/context-compaction.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction.js +39 -82
- package/dist/core/compaction/context-compaction.js.map +1 -1
- package/dist/core/compaction/index.d.ts +1 -1
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +1 -1
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/utils.d.ts +1 -1
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +1 -1
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/experimental.d.ts +2 -0
- package/dist/core/experimental.d.ts.map +1 -0
- package/dist/core/experimental.js +5 -0
- package/dist/core/experimental.js.map +1 -0
- package/dist/core/export-html/template.js +19 -6
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +6 -4
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +11 -4
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +53 -3
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +44 -12
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +2 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +27 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/messages.d.ts +1 -11
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +10 -25
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +64 -7
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +1 -0
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/output-guard.d.ts +1 -0
- package/dist/core/output-guard.d.ts.map +1 -1
- package/dist/core/output-guard.js +52 -22
- package/dist/core/output-guard.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +20 -8
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/project-trust.d.ts +15 -0
- package/dist/core/project-trust.d.ts.map +1 -0
- package/dist/core/project-trust.js +58 -0
- package/dist/core/project-trust.js.map +1 -0
- package/dist/core/prompt-templates.d.ts +5 -4
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +30 -29
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/provider-attribution.d.ts +4 -0
- package/dist/core/provider-attribution.d.ts.map +1 -0
- package/dist/core/provider-attribution.js +73 -0
- package/dist/core/provider-attribution.js.map +1 -0
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +3 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts +9 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +134 -11
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts +12 -2
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +108 -18
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +12 -42
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +11 -15
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +111 -111
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +15 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +69 -14
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +0 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +2 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +7 -10
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/oversized-tool-result.d.ts +53 -0
- package/dist/core/tools/oversized-tool-result.d.ts.map +1 -0
- package/dist/core/tools/oversized-tool-result.js +206 -0
- package/dist/core/tools/oversized-tool-result.js.map +1 -0
- package/dist/core/tools/read.d.ts +12 -0
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +99 -34
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +6 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +17 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts +6 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +2 -0
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/tool-limits.d.ts +25 -0
- package/dist/core/tools/tool-limits.d.ts.map +1 -0
- package/dist/core/tools/tool-limits.js +25 -0
- package/dist/core/tools/tool-limits.js.map +1 -0
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +1 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.d.ts +31 -0
- package/dist/core/trust-manager.d.ts.map +1 -0
- package/dist/core/trust-manager.js +196 -0
- package/dist/core/trust-manager.js.map +1 -0
- package/dist/index.d.ts +12 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +142 -30
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +3 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +325 -7
- package/dist/migrations.js.map +1 -1
- package/dist/modes/index.d.ts +1 -1
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +2 -2
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts +1 -5
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js +5 -9
- package/dist/modes/interactive/components/chat-message-renderer.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 +0 -3
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +6 -0
- package/dist/modes/interactive/components/footer.js.map +1 -1
- 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/login-dialog.d.ts +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +9 -16
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +20 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +22 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/trust-selector.d.ts +23 -0
- package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/trust-selector.js +85 -0
- package/dist/modes/interactive/components/trust-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +1 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +9 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +134 -36
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +10 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +1 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +4 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +52 -8
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +24 -5
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +1 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.d.ts +6 -2
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +104 -10
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/changelog.d.ts +1 -0
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js +72 -0
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/deprecation.d.ts +4 -0
- package/dist/utils/deprecation.d.ts.map +1 -0
- package/dist/utils/deprecation.js +13 -0
- package/dist/utils/deprecation.js.map +1 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +54 -22
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/json.d.ts +3 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +7 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/open-browser.d.ts +9 -0
- package/dist/utils/open-browser.d.ts.map +1 -0
- package/dist/utils/open-browser.js +22 -0
- package/dist/utils/open-browser.js.map +1 -0
- package/docs/compaction.md +210 -181
- package/docs/containerization.md +111 -0
- package/docs/custom-provider.md +9 -9
- package/docs/development.md +1 -1
- package/docs/docs.json +2 -0
- package/docs/extensions.md +71 -24
- package/docs/index.md +2 -0
- package/docs/json.md +3 -4
- package/docs/models.md +10 -10
- package/docs/packages.md +1 -1
- package/docs/prompt-templates.md +9 -2
- package/docs/providers.md +18 -5
- package/docs/quickstart.md +1 -0
- package/docs/rpc.md +3 -2
- package/docs/sdk.md +5 -0
- package/docs/security.md +56 -0
- package/docs/session-format.md +14 -23
- package/docs/sessions.md +11 -1
- package/docs/settings.md +23 -9
- package/docs/skills.md +1 -1
- package/docs/terminal-setup.md +44 -2
- package/docs/themes.md +1 -1
- package/docs/tmux.md +4 -2
- package/docs/tui.md +14 -5
- package/docs/usage.md +17 -3
- package/docs/workflows.md +11 -9
- package/examples/README.md +1 -1
- package/examples/extensions/README.md +9 -6
- package/examples/extensions/bash-spawn-hook.ts +1 -1
- package/examples/extensions/built-in-tool-renderer.ts +1 -1
- package/examples/extensions/claude-rules.ts +1 -1
- package/examples/extensions/commands.ts +1 -1
- package/examples/extensions/custom-compaction.ts +43 -106
- package/examples/extensions/custom-header.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +3 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +4 -4
- package/examples/extensions/custom-provider-anthropic/package.json +6 -6
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +55 -4
- package/examples/extensions/custom-provider-gitlab-duo/package.json +3 -3
- package/examples/extensions/doom-overlay/README.md +1 -1
- package/examples/extensions/doom-overlay/index.ts +2 -2
- package/examples/extensions/git-merge-and-resolve.ts +115 -0
- package/examples/extensions/gondolin/index.ts +523 -0
- package/examples/extensions/gondolin/package-lock.json +185 -0
- package/examples/extensions/gondolin/package.json +19 -0
- package/examples/extensions/handoff.ts +7 -45
- package/examples/extensions/hidden-thinking-label.ts +1 -1
- package/examples/extensions/inline-bash.ts +2 -2
- package/examples/extensions/input-transform-streaming.ts +39 -0
- package/examples/extensions/input-transform.ts +3 -3
- package/examples/extensions/interactive-shell.ts +2 -2
- package/examples/extensions/mac-system-theme.ts +2 -2
- package/examples/extensions/minimal-mode.ts +1 -1
- package/examples/extensions/modal-editor.ts +1 -1
- package/examples/extensions/model-status.ts +1 -1
- package/examples/extensions/overlay-qa-tests.ts +198 -179
- package/examples/extensions/overlay-test.ts +1 -1
- package/examples/extensions/pirate.ts +1 -1
- package/examples/extensions/preset.ts +14 -12
- package/examples/extensions/project-trust.ts +64 -0
- package/examples/extensions/prompt-customizer.ts +1 -1
- package/examples/extensions/qna.ts +1 -1
- package/examples/extensions/question.ts +1 -1
- package/examples/extensions/questionnaire.ts +1 -1
- package/examples/extensions/rainbow-editor.ts +1 -1
- package/examples/extensions/sandbox/index.ts +16 -14
- package/examples/extensions/sandbox/package-lock.json +90 -90
- package/examples/extensions/sandbox/package.json +17 -17
- package/examples/extensions/snake.ts +1 -1
- package/examples/extensions/space-invaders.ts +1 -1
- package/examples/extensions/ssh.ts +2 -2
- package/examples/extensions/subagent/README.md +13 -13
- package/examples/extensions/subagent/agents.ts +4 -2
- package/examples/extensions/subagent/index.ts +6 -6
- package/examples/extensions/summarize.ts +1 -1
- package/examples/extensions/tic-tac-toe.ts +1 -1
- package/examples/extensions/titlebar-spinner.ts +1 -1
- package/examples/extensions/todo.ts +1 -1
- package/examples/extensions/tool-override.ts +1 -1
- package/examples/extensions/tools.ts +6 -1
- package/examples/extensions/trigger-compact.ts +5 -4
- package/examples/extensions/with-deps/package-lock.json +4 -4
- package/examples/extensions/with-deps/package.json +7 -7
- package/examples/extensions/working-indicator.ts +4 -4
- package/examples/extensions/working-message-test.ts +1 -1
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/03-custom-prompt.ts +1 -1
- package/examples/sdk/04-skills.ts +1 -1
- package/examples/sdk/06-extensions.ts +2 -2
- package/examples/sdk/08-prompt-templates.ts +1 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
- package/examples/sdk/README.md +2 -2
- package/package.json +8 -8
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -16
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +0 -43
- package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
|
@@ -129,7 +129,7 @@ export const WORKFLOW_TOOL_DESCRIPTION =
|
|
|
129
129
|
"For large stage handoffs, write context to files/artifacts, pass paths via reads, and prompt downstream agents to 'Read the file at <path>...' instead of injecting large previous text. " +
|
|
130
130
|
"For transcripts, prefer status/stages/stage to get sessionFile/transcriptPath, " +
|
|
131
131
|
"quote the exact path without rewriting separators (Windows backslashes are valid), " +
|
|
132
|
-
"search it with rg/grep
|
|
132
|
+
"then search it with rg/grep and read small ranges; transcript is path-only by default when sessionFile/transcriptPath exists, explicit tail/limit returns bounded previews, and missing transcript paths fall back to a small preview.";
|
|
133
133
|
|
|
134
134
|
// ---------------------------------------------------------------------------
|
|
135
135
|
// Minimal ExtensionAPI structural types
|
|
@@ -644,8 +644,10 @@ function renderTranscriptToolContent(
|
|
|
644
644
|
if (result.transcriptPath) lines.push(`transcriptPathJson: ${JSON.stringify(result.transcriptPath)}`);
|
|
645
645
|
if (result.entryCount !== undefined) lines.push(`availableEntries: ${result.entryCount}`);
|
|
646
646
|
if (result.entryLimit !== undefined) lines.push(`entryLimit: ${result.entryLimit}`);
|
|
647
|
+
if (result.lazyReadPrompt) lines.push(`lazyReadPrompt: ${result.lazyReadPrompt}`);
|
|
648
|
+
if (result.fallbackNote) lines.push(`fallbackNote: ${result.fallbackNote}`);
|
|
647
649
|
if (result.entries.length === 0) {
|
|
648
|
-
lines.push("entries: none");
|
|
650
|
+
lines.push(result.inlineMode === "path_only" || result.lazyReadPrompt ? "entries: not inlined" : "entries: none");
|
|
649
651
|
return lines.join("\n");
|
|
650
652
|
}
|
|
651
653
|
lines.push("entries:");
|
|
@@ -702,6 +704,10 @@ function renderStagesToolContent(
|
|
|
702
704
|
lines.push("inputRequest:");
|
|
703
705
|
lines.push(JSON.stringify(stage.inputRequest, null, 2));
|
|
704
706
|
}
|
|
707
|
+
if (stage.promptFootprint !== undefined) {
|
|
708
|
+
lines.push("promptFootprint:");
|
|
709
|
+
lines.push(JSON.stringify(stage.promptFootprint, null, 2));
|
|
710
|
+
}
|
|
705
711
|
});
|
|
706
712
|
return lines.join("\n");
|
|
707
713
|
}
|
|
@@ -800,6 +806,7 @@ type WorkflowStageSummary = {
|
|
|
800
806
|
awaitingInputSince?: number;
|
|
801
807
|
pendingPrompt?: StageSnapshot["pendingPrompt"];
|
|
802
808
|
inputRequest?: StageSnapshot["inputRequest"];
|
|
809
|
+
promptFootprint?: StageSnapshot["promptFootprint"];
|
|
803
810
|
};
|
|
804
811
|
|
|
805
812
|
type WorkflowTranscriptEntry = {
|
|
@@ -842,6 +849,9 @@ function summarizeStage(stage: StageSnapshot): WorkflowStageSummary {
|
|
|
842
849
|
inputRequest: stage.inputRequest === undefined
|
|
843
850
|
? undefined
|
|
844
851
|
: structuredClone(stage.inputRequest),
|
|
852
|
+
promptFootprint: stage.promptFootprint === undefined
|
|
853
|
+
? undefined
|
|
854
|
+
: structuredClone(stage.promptFootprint),
|
|
845
855
|
};
|
|
846
856
|
}
|
|
847
857
|
|
|
@@ -854,6 +864,12 @@ type TranscriptEntrySelection = {
|
|
|
854
864
|
entryLimit?: number;
|
|
855
865
|
};
|
|
856
866
|
|
|
867
|
+
type WorkflowTranscriptResult = Extract<WorkflowToolResult, { action: "transcript" }>;
|
|
868
|
+
|
|
869
|
+
function isTranscriptPreviewExplicit(args: WorkflowToolArgs): boolean {
|
|
870
|
+
return args.tail !== undefined || args.limit !== undefined;
|
|
871
|
+
}
|
|
872
|
+
|
|
857
873
|
function requestedTranscriptEntryLimit(args: WorkflowToolArgs): number {
|
|
858
874
|
const raw = args.tail ?? args.limit;
|
|
859
875
|
if (raw === undefined) return DEFAULT_TRANSCRIPT_LIMIT;
|
|
@@ -891,6 +907,80 @@ function selectTranscriptEntries(
|
|
|
891
907
|
};
|
|
892
908
|
}
|
|
893
909
|
|
|
910
|
+
function transcriptLazyReadPrompt(path: string): string {
|
|
911
|
+
return `Transcript not inlined to protect context. Read it lazily from ${path} with your file read tools (read small ranges; rg/grep for targeted lookups).`;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
function transcriptFallbackNote(limit: number): string {
|
|
915
|
+
return `No transcript file path is available for this stage; falling back to a bounded inline preview of up to ${limit} recent ${limit === 1 ? "entry" : "entries"}.`;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Shape a transcript tool result, keeping the context-safe path-only default
|
|
920
|
+
* the cheap hot path for the large runs #1314 protects against.
|
|
921
|
+
*
|
|
922
|
+
* `buildEntries` is a thunk so the default case (a transcript file path exists
|
|
923
|
+
* and no explicit `tail`/`limit` was requested) never materializes entry bodies
|
|
924
|
+
* just to discard them. Only the caller-provided `entryCount` is needed for the
|
|
925
|
+
* advisory count, which matches what `buildEntries()` would yield. The thunk is
|
|
926
|
+
* invoked solely for the explicit-preview and no-path fallback branches.
|
|
927
|
+
*/
|
|
928
|
+
function shapeTranscriptResult(input: {
|
|
929
|
+
runId: string;
|
|
930
|
+
stageId: string;
|
|
931
|
+
source: "live" | "snapshot";
|
|
932
|
+
entryCount: number;
|
|
933
|
+
buildEntries: () => readonly WorkflowTranscriptEntry[];
|
|
934
|
+
args: WorkflowToolArgs;
|
|
935
|
+
sessionId?: string | undefined;
|
|
936
|
+
sessionFile?: string | undefined;
|
|
937
|
+
transcriptPath?: string | undefined;
|
|
938
|
+
}): WorkflowTranscriptResult {
|
|
939
|
+
// `transcriptPath` already falls back to `sessionFile`, so it is the single
|
|
940
|
+
// resolved path the agent should lazily read.
|
|
941
|
+
const transcriptPath = input.transcriptPath ?? input.sessionFile;
|
|
942
|
+
if (transcriptPath !== undefined && !isTranscriptPreviewExplicit(input.args)) {
|
|
943
|
+
const result: WorkflowTranscriptResult = {
|
|
944
|
+
action: "transcript",
|
|
945
|
+
runId: input.runId,
|
|
946
|
+
stageId: input.stageId,
|
|
947
|
+
source: input.source,
|
|
948
|
+
entries: [],
|
|
949
|
+
// `truncated` here means "more transcript exists on disk than was inlined"
|
|
950
|
+
// (everything, since the default inlines nothing), not "an explicit limit
|
|
951
|
+
// clipped results". It only drives the cosmetic "(truncated)" notice
|
|
952
|
+
// suffix; no consumer re-fetches on it.
|
|
953
|
+
truncated: input.entryCount > 0,
|
|
954
|
+
entryCount: input.entryCount,
|
|
955
|
+
entryLimit: 0,
|
|
956
|
+
lazyReadPrompt: transcriptLazyReadPrompt(transcriptPath),
|
|
957
|
+
inlineMode: "path_only",
|
|
958
|
+
};
|
|
959
|
+
if (input.sessionId !== undefined) result.sessionId = input.sessionId;
|
|
960
|
+
if (input.sessionFile !== undefined) result.sessionFile = input.sessionFile;
|
|
961
|
+
result.transcriptPath = transcriptPath;
|
|
962
|
+
return result;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
const limited = selectTranscriptEntries(input.buildEntries(), input.args);
|
|
966
|
+
const result: WorkflowTranscriptResult = {
|
|
967
|
+
action: "transcript",
|
|
968
|
+
runId: input.runId,
|
|
969
|
+
stageId: input.stageId,
|
|
970
|
+
source: input.source,
|
|
971
|
+
entries: limited.entries,
|
|
972
|
+
truncated: limited.truncated,
|
|
973
|
+
entryCount: limited.entryCount,
|
|
974
|
+
entryLimit: limited.entryLimit,
|
|
975
|
+
inlineMode: transcriptPath === undefined ? "fallback_preview" : "preview",
|
|
976
|
+
};
|
|
977
|
+
if (input.sessionId !== undefined) result.sessionId = input.sessionId;
|
|
978
|
+
if (input.sessionFile !== undefined) result.sessionFile = input.sessionFile;
|
|
979
|
+
if (transcriptPath !== undefined) result.transcriptPath = transcriptPath;
|
|
980
|
+
if (transcriptPath === undefined) result.fallbackNote = transcriptFallbackNote(limited.entryLimit ?? DEFAULT_TRANSCRIPT_LIMIT);
|
|
981
|
+
return result;
|
|
982
|
+
}
|
|
983
|
+
|
|
894
984
|
function messageText(content: MessageLike["content"]): string | undefined {
|
|
895
985
|
if (typeof content === "string") return content;
|
|
896
986
|
if (!Array.isArray(content)) return undefined;
|
|
@@ -1463,33 +1553,40 @@ export function makeExecuteWorkflowTool(
|
|
|
1463
1553
|
if (liveHandle !== undefined) {
|
|
1464
1554
|
const sessionFile = liveHandle.sessionFile ?? snapshot?.sessionFile;
|
|
1465
1555
|
const sessionId = liveHandle.sessionId ?? snapshot?.sessionId;
|
|
1466
|
-
|
|
1467
|
-
liveHandle.messages.map((m) => transcriptEntryFromMessage(m as MessageLike)),
|
|
1468
|
-
args,
|
|
1469
|
-
);
|
|
1470
|
-
return {
|
|
1471
|
-
action: "transcript",
|
|
1556
|
+
return shapeTranscriptResult({
|
|
1472
1557
|
runId: stageRunId,
|
|
1473
1558
|
stageId: stage.stageId,
|
|
1474
1559
|
source: "live",
|
|
1475
|
-
|
|
1560
|
+
entryCount: liveHandle.messages.length,
|
|
1561
|
+
buildEntries: () =>
|
|
1562
|
+
liveHandle.messages.map((m) => transcriptEntryFromMessage(m as MessageLike)),
|
|
1563
|
+
args,
|
|
1476
1564
|
sessionId,
|
|
1477
1565
|
sessionFile,
|
|
1478
1566
|
transcriptPath: sessionFile,
|
|
1479
|
-
};
|
|
1567
|
+
});
|
|
1480
1568
|
}
|
|
1481
|
-
const
|
|
1482
|
-
const
|
|
1483
|
-
|
|
1484
|
-
|
|
1569
|
+
const snapshotSessionFile = snapshot?.sessionFile;
|
|
1570
|
+
const includeSnapshotOutput = args.includeToolOutput === true && (
|
|
1571
|
+
isTranscriptPreviewExplicit(args) || snapshotSessionFile === undefined
|
|
1572
|
+
);
|
|
1573
|
+
// Cheap count matches `snapshotTranscriptEntries(...).length` (one entry
|
|
1574
|
+
// per tool event plus the optional terminal result/error entries)
|
|
1575
|
+
// without building bodies for the path-only default.
|
|
1576
|
+
const snapshotEntryCount = (snapshot?.toolEvents?.length ?? 0)
|
|
1577
|
+
+ (snapshot?.result !== undefined ? 1 : 0)
|
|
1578
|
+
+ (snapshot?.error !== undefined ? 1 : 0);
|
|
1579
|
+
return shapeTranscriptResult({
|
|
1485
1580
|
runId: stageRunId,
|
|
1486
1581
|
stageId: stage.stageId,
|
|
1487
1582
|
source: "snapshot",
|
|
1488
|
-
|
|
1583
|
+
entryCount: snapshotEntryCount,
|
|
1584
|
+
buildEntries: () => snapshotTranscriptEntries(snapshot, includeSnapshotOutput),
|
|
1585
|
+
args,
|
|
1489
1586
|
sessionId: snapshot?.sessionId,
|
|
1490
|
-
sessionFile:
|
|
1491
|
-
transcriptPath:
|
|
1492
|
-
};
|
|
1587
|
+
sessionFile: snapshotSessionFile,
|
|
1588
|
+
transcriptPath: snapshotSessionFile,
|
|
1589
|
+
});
|
|
1493
1590
|
}
|
|
1494
1591
|
|
|
1495
1592
|
case "send": {
|
|
@@ -1543,6 +1640,24 @@ export function makeExecuteWorkflowTool(
|
|
|
1543
1640
|
ok ? `Answered input request ${brokerPrompt.id}.` : `No matching pending input request ${brokerPrompt.id}.`,
|
|
1544
1641
|
);
|
|
1545
1642
|
}
|
|
1643
|
+
const customPrompt = snapshot?.status === "awaiting_input" && snapshot.promptFootprint?.kind === "custom"
|
|
1644
|
+
? snapshot.promptFootprint
|
|
1645
|
+
: undefined;
|
|
1646
|
+
const targetsCustomPrompt =
|
|
1647
|
+
customPrompt !== undefined &&
|
|
1648
|
+
(args.promptId === undefined || args.promptId === customPrompt.id) &&
|
|
1649
|
+
(requestedDelivery === "answer" ||
|
|
1650
|
+
args.promptId !== undefined ||
|
|
1651
|
+
requestedDelivery === "auto");
|
|
1652
|
+
if (targetsCustomPrompt && customPrompt !== undefined) {
|
|
1653
|
+
return workflowSendResult(
|
|
1654
|
+
stageRunId,
|
|
1655
|
+
stage.stageId,
|
|
1656
|
+
"answer",
|
|
1657
|
+
"noop",
|
|
1658
|
+
`Custom UI prompt ${customPrompt.id} requires the interactive workflow graph; arbitrary ctx.ui.custom<T> results cannot be answered through workflow send.`,
|
|
1659
|
+
);
|
|
1660
|
+
}
|
|
1546
1661
|
const targetsPrompt =
|
|
1547
1662
|
requestedDelivery === "answer" ||
|
|
1548
1663
|
args.promptId !== undefined ||
|
|
@@ -110,11 +110,13 @@ type StageListItem = {
|
|
|
110
110
|
awaitingInputSince?: number;
|
|
111
111
|
pendingPrompt?: PendingPrompt;
|
|
112
112
|
inputRequest?: StageInputRequest;
|
|
113
|
+
promptFootprint?: PendingPrompt;
|
|
113
114
|
};
|
|
114
115
|
type StageListResult = { action: "stages"; runId: string; filter: string; stages: StageListItem[]; error?: string };
|
|
115
116
|
type StageDetailItem = StageSnapshot & { transcriptPath?: string };
|
|
116
117
|
type StageDetailResult = { action: "stage"; runId: string; stage?: StageDetailItem; error?: string };
|
|
117
118
|
type TranscriptEntry = { role: string; text?: string; toolName?: string; output?: string; timestamp?: number };
|
|
119
|
+
type TranscriptInlineMode = "path_only" | "preview" | "fallback_preview";
|
|
118
120
|
type TranscriptResult = {
|
|
119
121
|
action: "transcript";
|
|
120
122
|
runId: string;
|
|
@@ -127,6 +129,9 @@ type TranscriptResult = {
|
|
|
127
129
|
sessionId?: string;
|
|
128
130
|
sessionFile?: string;
|
|
129
131
|
transcriptPath?: string;
|
|
132
|
+
lazyReadPrompt?: string;
|
|
133
|
+
fallbackNote?: string;
|
|
134
|
+
inlineMode?: TranscriptInlineMode;
|
|
130
135
|
};
|
|
131
136
|
type SendResult = { action: "send"; runId: string; stageId: string; delivery: string; status: "ok" | "noop"; message: string };
|
|
132
137
|
type PauseResult = { action: "pause"; runId: string; status: string; message: string };
|
|
@@ -213,7 +218,7 @@ function renderNotice(
|
|
|
213
218
|
const TRANSCRIPT_NOTICE_ENTRY_LIMIT = 5;
|
|
214
219
|
const TRANSCRIPT_NOTICE_CHAR_LIMIT = 240;
|
|
215
220
|
|
|
216
|
-
function
|
|
221
|
+
function transcriptEntriesNoticeText(entries: readonly TranscriptEntry[]): string {
|
|
217
222
|
if (entries.length === 0) return "no transcript entries";
|
|
218
223
|
const shown = entries.slice(0, TRANSCRIPT_NOTICE_ENTRY_LIMIT);
|
|
219
224
|
const text = shown
|
|
@@ -225,6 +230,21 @@ function transcriptNoticeText(entries: readonly TranscriptEntry[]): string {
|
|
|
225
230
|
return fitLine(`${text}${entrySuffix}`, TRANSCRIPT_NOTICE_CHAR_LIMIT);
|
|
226
231
|
}
|
|
227
232
|
|
|
233
|
+
function transcriptNoticeText(result: TranscriptResult): string {
|
|
234
|
+
if ((result.inlineMode === "path_only" || result.lazyReadPrompt !== undefined) && result.entries.length === 0) {
|
|
235
|
+
const path = result.transcriptPath ?? result.sessionFile ?? "transcript file";
|
|
236
|
+
const count = result.entryCount === undefined
|
|
237
|
+
? ""
|
|
238
|
+
: ` (${result.entryCount} ${result.entryCount === 1 ? "entry" : "entries"})`;
|
|
239
|
+
return fitLine(`not inlined; read ${path}${count}`, TRANSCRIPT_NOTICE_CHAR_LIMIT);
|
|
240
|
+
}
|
|
241
|
+
const entriesText = transcriptEntriesNoticeText(result.entries);
|
|
242
|
+
if (result.inlineMode === "fallback_preview" || result.fallbackNote !== undefined) {
|
|
243
|
+
return fitLine(`no session file; preview: ${entriesText}`, TRANSCRIPT_NOTICE_CHAR_LIMIT);
|
|
244
|
+
}
|
|
245
|
+
return entriesText;
|
|
246
|
+
}
|
|
247
|
+
|
|
228
248
|
export function renderResult(result: WorkflowToolResult, opts?: RenderResultOpts): string {
|
|
229
249
|
const partial = opts?.isPartial === true;
|
|
230
250
|
const themed = opts?.plain !== true;
|
|
@@ -350,7 +370,7 @@ export function renderResult(result: WorkflowToolResult, opts?: RenderResultOpts
|
|
|
350
370
|
|
|
351
371
|
case "transcript": {
|
|
352
372
|
const r = result as TranscriptResult;
|
|
353
|
-
const text = transcriptNoticeText(r
|
|
373
|
+
const text = transcriptNoticeText(r);
|
|
354
374
|
const suffix = r.truncated ? " (truncated)" : "";
|
|
355
375
|
return renderNotice("WORKFLOW TRANSCRIPT", `${r.runId}/${r.stageId.slice(0, 12)} ${r.source}: ${text}${suffix}`, opts, themed);
|
|
356
376
|
}
|
|
@@ -114,7 +114,7 @@ export const WorkflowParametersSchema = Type.Object({
|
|
|
114
114
|
Type.Literal("resume"),
|
|
115
115
|
Type.Literal("reload"),
|
|
116
116
|
], {
|
|
117
|
-
description: "Workflow action: run/list/get/inputs/status, inspect stage metadata, send messages or prompt answers, pause/resume/interrupt/kill runs, or reload workflow resources. For transcript inspection, prefer status/stages/stage first to get sessionFile/transcriptPath, quote the exact path without rewriting separators (Windows backslashes are valid), then search it with rg/grep and read small ranges; transcript
|
|
117
|
+
description: "Workflow action: run/list/get/inputs/status, inspect stage metadata, send messages or prompt answers, pause/resume/interrupt/kill runs, or reload workflow resources. For transcript inspection, prefer status/stages/stage first to get sessionFile/transcriptPath, quote the exact path without rewriting separators (Windows backslashes are valid), then search it with rg/grep and read small ranges; transcript is path-only by default when sessionFile/transcriptPath exists, explicit tail/limit returns bounded previews, and missing transcript paths fall back to a small preview.",
|
|
118
118
|
})),
|
|
119
119
|
runId: Type.Optional(Type.String({
|
|
120
120
|
description: "Run identifier or unique prefix for status/stages/stage/transcript/send/pause/resume/interrupt/kill. Use '--all' or all:true for supported bulk run-control actions.",
|
|
@@ -146,14 +146,14 @@ export const WorkflowParametersSchema = Type.Object({
|
|
|
146
146
|
})),
|
|
147
147
|
limit: Type.Optional(Type.Integer({
|
|
148
148
|
minimum: 0,
|
|
149
|
-
description: "Transcript-only: explicitly inline at most this many recent entries. Omit both limit and tail to use the
|
|
149
|
+
description: "Transcript-only: explicitly inline at most this many recent entries. Omit both limit and tail to use the path-only default when sessionFile/transcriptPath exists; prefer rg/grep on the exact quoted sessionFile/transcriptPath for targeted lookup without rewriting platform path separators.",
|
|
150
150
|
})),
|
|
151
151
|
tail: Type.Optional(Type.Integer({
|
|
152
152
|
minimum: 0,
|
|
153
153
|
description: "Transcript-only: explicitly inline the last N entries; overrides limit. Use for quick recent-context checks after status/stages/stage expose the transcript path.",
|
|
154
154
|
})),
|
|
155
155
|
includeToolOutput: Type.Optional(Type.Boolean({
|
|
156
|
-
description: "Transcript-only: include captured tool output entries when building
|
|
156
|
+
description: "Transcript-only: include captured tool output entries when building inlined snapshot previews; this does not bypass the path-only default. Prefer rg/grep on the exact quoted sessionFile/transcriptPath for large outputs. Live session transcripts may not expose tool output.",
|
|
157
157
|
})),
|
|
158
158
|
text: Type.Optional(Type.String({
|
|
159
159
|
description: "Text to send to a stage for prompt answers, steering, follow-ups, or resume messages.",
|
|
@@ -14,6 +14,8 @@ import type {
|
|
|
14
14
|
WorkflowRunContext,
|
|
15
15
|
WorkflowUIContext,
|
|
16
16
|
WorkflowUIAdapter,
|
|
17
|
+
WorkflowCustomUiFactory,
|
|
18
|
+
WorkflowCustomUiOptions,
|
|
17
19
|
WorkflowInputSchema,
|
|
18
20
|
StageContext,
|
|
19
21
|
StageOptions,
|
|
@@ -56,7 +58,7 @@ import type {
|
|
|
56
58
|
WorkflowFailureRecoverability,
|
|
57
59
|
WorkflowFailureDisposition,
|
|
58
60
|
PendingPrompt,
|
|
59
|
-
|
|
61
|
+
CustomPromptIdentitySource,
|
|
60
62
|
WorkflowChildReplaySnapshot,
|
|
61
63
|
WorkflowChildRunRef,
|
|
62
64
|
} from "../../shared/store-types.js";
|
|
@@ -108,7 +110,7 @@ export interface RunContinuationOpts {
|
|
|
108
110
|
readonly resumeFromStageId: string;
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
export interface RunOpts extends Omit<AuthoringContract.RunOpts, "adapters" | "store" | "cancellation" | "overlay" | "registry" | "stageControlRegistry" | "continuation" | "onRunStart" | "onStageStart" | "onStageEnd" | "onRunEnd"> {
|
|
113
|
+
export interface RunOpts extends Omit<AuthoringContract.RunOpts, "adapters" | "store" | "cancellation" | "overlay" | "registry" | "stageControlRegistry" | "continuation" | "onRunStart" | "onStageStart" | "onStageEnd" | "onRunEnd" | "ui"> {
|
|
112
114
|
adapters?: StageAdapters;
|
|
113
115
|
/** Invocation working directory exposed to workflow definitions as ctx.cwd. */
|
|
114
116
|
cwd?: string;
|
|
@@ -271,14 +273,28 @@ function resolveInputRuntimeDefaults(
|
|
|
271
273
|
// HIL unavailable fallback — rejects with precise per-primitive error
|
|
272
274
|
// ---------------------------------------------------------------------------
|
|
273
275
|
|
|
274
|
-
|
|
275
|
-
readonly kind:
|
|
276
|
+
type PrimitivePromptDescriptor =
|
|
277
|
+
| { readonly kind: "input"; readonly message: string; readonly initial?: string }
|
|
278
|
+
| { readonly kind: "confirm"; readonly message: string }
|
|
279
|
+
| { readonly kind: "select"; readonly message: string; readonly choices: readonly string[] }
|
|
280
|
+
| { readonly kind: "editor"; readonly message: string; readonly initial?: string };
|
|
281
|
+
|
|
282
|
+
interface CustomPromptDescriptor<T> {
|
|
283
|
+
readonly kind: "custom";
|
|
276
284
|
readonly message: string;
|
|
277
|
-
readonly
|
|
278
|
-
readonly
|
|
285
|
+
readonly factory: WorkflowCustomUiFactory<T>;
|
|
286
|
+
readonly options?: WorkflowCustomUiOptions;
|
|
287
|
+
readonly customIdentityHash: string;
|
|
288
|
+
readonly customIdentitySource: CustomPromptIdentitySource;
|
|
279
289
|
}
|
|
280
290
|
|
|
281
|
-
|
|
291
|
+
type PromptDescriptor<T = unknown> = PrimitivePromptDescriptor | CustomPromptDescriptor<T>;
|
|
292
|
+
|
|
293
|
+
function isCustomPromptDescriptor<T>(descriptor: PromptDescriptor<T>): descriptor is CustomPromptDescriptor<T> {
|
|
294
|
+
return descriptor.kind === "custom";
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function fallbackForPromptDescriptor(descriptor: PrimitivePromptDescriptor): unknown {
|
|
282
298
|
switch (descriptor.kind) {
|
|
283
299
|
case "input":
|
|
284
300
|
case "editor":
|
|
@@ -286,7 +302,7 @@ function fallbackForPromptDescriptor(descriptor: PromptDescriptor): unknown {
|
|
|
286
302
|
case "confirm":
|
|
287
303
|
return false;
|
|
288
304
|
case "select":
|
|
289
|
-
return descriptor.choices
|
|
305
|
+
return descriptor.choices[0] ?? "";
|
|
290
306
|
}
|
|
291
307
|
}
|
|
292
308
|
|
|
@@ -295,8 +311,12 @@ function makePrompt(descriptor: PromptDescriptor): PendingPrompt {
|
|
|
295
311
|
id: `hil-${crypto.randomUUID()}`,
|
|
296
312
|
kind: descriptor.kind,
|
|
297
313
|
message: descriptor.message,
|
|
298
|
-
...(descriptor.
|
|
299
|
-
...(descriptor.initial !== undefined ? { initial: descriptor.initial } : {}),
|
|
314
|
+
...(!isCustomPromptDescriptor(descriptor) && descriptor.kind === "select" ? { choices: descriptor.choices } : {}),
|
|
315
|
+
...(!isCustomPromptDescriptor(descriptor) && (descriptor.kind === "input" || descriptor.kind === "editor") && descriptor.initial !== undefined ? { initial: descriptor.initial } : {}),
|
|
316
|
+
...(isCustomPromptDescriptor(descriptor) ? {
|
|
317
|
+
customIdentityHash: descriptor.customIdentityHash,
|
|
318
|
+
customIdentitySource: descriptor.customIdentitySource,
|
|
319
|
+
} : {}),
|
|
300
320
|
createdAt: Date.now(),
|
|
301
321
|
};
|
|
302
322
|
}
|
|
@@ -307,13 +327,19 @@ function stableHash(value: unknown): string {
|
|
|
307
327
|
}
|
|
308
328
|
|
|
309
329
|
function promptDescriptorHash(descriptor: PromptDescriptor): string {
|
|
330
|
+
if (isCustomPromptDescriptor(descriptor)) {
|
|
331
|
+
return stableHash({
|
|
332
|
+
kind: "custom",
|
|
333
|
+
customIdentityHash: descriptor.customIdentityHash,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
310
336
|
return stableHash({
|
|
311
337
|
kind: descriptor.kind,
|
|
312
338
|
message: descriptor.message,
|
|
313
|
-
choices: descriptor.choices
|
|
339
|
+
choices: descriptor.kind === "select" ? descriptor.choices : [],
|
|
314
340
|
// Include input/editor initial text because it is visible prompt context;
|
|
315
341
|
// changing it should not replay a stale answer from the same callsite.
|
|
316
|
-
initial: descriptor.initial ?? null,
|
|
342
|
+
initial: descriptor.kind === "input" || descriptor.kind === "editor" ? descriptor.initial ?? null : null,
|
|
317
343
|
});
|
|
318
344
|
}
|
|
319
345
|
|
|
@@ -334,6 +360,80 @@ function hilAbortError(signal: AbortSignal): Error {
|
|
|
334
360
|
: new Error("atomic-workflows: HIL aborted");
|
|
335
361
|
}
|
|
336
362
|
|
|
363
|
+
function resolveCustomPromptIdentity<T>(
|
|
364
|
+
factory: WorkflowCustomUiFactory<T>,
|
|
365
|
+
options: WorkflowCustomUiOptions | undefined,
|
|
366
|
+
): Pick<CustomPromptDescriptor<T>, "customIdentityHash" | "customIdentitySource"> {
|
|
367
|
+
const replayIdentity = options?.replayIdentity?.trim();
|
|
368
|
+
if (replayIdentity !== undefined && replayIdentity.length > 0) {
|
|
369
|
+
return {
|
|
370
|
+
customIdentityHash: stableHash({ source: "caller", value: replayIdentity }),
|
|
371
|
+
customIdentitySource: "caller",
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
if (factory.name.trim().length > 0) {
|
|
375
|
+
return {
|
|
376
|
+
customIdentityHash: stableHash({ source: "factory", value: factory.name }),
|
|
377
|
+
customIdentitySource: "factory",
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
try {
|
|
381
|
+
const source = Function.prototype.toString.call(factory);
|
|
382
|
+
if (source.trim().length > 0) {
|
|
383
|
+
return {
|
|
384
|
+
customIdentityHash: stableHash({ source: "factory", value: source }),
|
|
385
|
+
customIdentitySource: "factory",
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
} catch {
|
|
389
|
+
// Fall through to callsite-only identity below.
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
customIdentityHash: stableHash({ source: "callsite" }),
|
|
393
|
+
customIdentitySource: "callsite",
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function customPromptDescriptor<T>(
|
|
398
|
+
factory: WorkflowCustomUiFactory<T>,
|
|
399
|
+
options: WorkflowCustomUiOptions | undefined,
|
|
400
|
+
): CustomPromptDescriptor<T> {
|
|
401
|
+
const label = options?.label?.trim();
|
|
402
|
+
return {
|
|
403
|
+
kind: "custom",
|
|
404
|
+
message: label && label.length > 0 ? label : "Custom TUI prompt",
|
|
405
|
+
factory,
|
|
406
|
+
...(options !== undefined ? { options } : {}),
|
|
407
|
+
...resolveCustomPromptIdentity(factory, options),
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
interface MergedHilSignal {
|
|
412
|
+
readonly signal: AbortSignal;
|
|
413
|
+
readonly dispose: () => void;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function mergeHilSignals(primary: AbortSignal, secondary: AbortSignal | undefined): MergedHilSignal {
|
|
417
|
+
if (secondary === undefined) return { signal: primary, dispose: () => undefined };
|
|
418
|
+
const controller = new AbortController();
|
|
419
|
+
const abortFrom = (source: AbortSignal): void => {
|
|
420
|
+
if (!controller.signal.aborted) controller.abort(source.reason);
|
|
421
|
+
};
|
|
422
|
+
const onPrimaryAbort = (): void => abortFrom(primary);
|
|
423
|
+
const onSecondaryAbort = (): void => abortFrom(secondary);
|
|
424
|
+
primary.addEventListener("abort", onPrimaryAbort, { once: true });
|
|
425
|
+
secondary.addEventListener("abort", onSecondaryAbort, { once: true });
|
|
426
|
+
if (primary.aborted) abortFrom(primary);
|
|
427
|
+
else if (secondary.aborted) abortFrom(secondary);
|
|
428
|
+
return {
|
|
429
|
+
signal: controller.signal,
|
|
430
|
+
dispose: () => {
|
|
431
|
+
primary.removeEventListener("abort", onPrimaryAbort);
|
|
432
|
+
secondary.removeEventListener("abort", onSecondaryAbort);
|
|
433
|
+
},
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
337
437
|
function makeUnavailableUIContext(): WorkflowUIContext {
|
|
338
438
|
const msg = (primitive: string): string =>
|
|
339
439
|
`atomic-workflows: HIL ctx.ui.${primitive} is unavailable because Atomic runtime did not provide a UI adapter`;
|
|
@@ -342,6 +442,31 @@ function makeUnavailableUIContext(): WorkflowUIContext {
|
|
|
342
442
|
confirm: () => Promise.reject(new Error(msg("confirm"))),
|
|
343
443
|
select: () => Promise.reject(new Error(msg("select"))),
|
|
344
444
|
editor: () => Promise.reject(new Error(msg("editor"))),
|
|
445
|
+
custom: () => Promise.reject(new Error(msg("custom"))),
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function normalizeUIContext(adapter: WorkflowUIAdapter | undefined): WorkflowUIContext {
|
|
450
|
+
const unavailable = makeUnavailableUIContext();
|
|
451
|
+
if (adapter === undefined) return unavailable;
|
|
452
|
+
return {
|
|
453
|
+
input(prompt) {
|
|
454
|
+
return adapter.input.call(adapter, prompt);
|
|
455
|
+
},
|
|
456
|
+
confirm(message) {
|
|
457
|
+
return adapter.confirm.call(adapter, message);
|
|
458
|
+
},
|
|
459
|
+
select<T extends string>(message: string, options: readonly T[]): Promise<T> {
|
|
460
|
+
return adapter.select.call(adapter, message, options) as Promise<T>;
|
|
461
|
+
},
|
|
462
|
+
editor(initial) {
|
|
463
|
+
return adapter.editor.call(adapter, initial);
|
|
464
|
+
},
|
|
465
|
+
custom<T>(factory: WorkflowCustomUiFactory<T>, options?: WorkflowCustomUiOptions): Promise<T> {
|
|
466
|
+
return adapter.custom !== undefined
|
|
467
|
+
? adapter.custom.call(adapter, factory, options) as Promise<T>
|
|
468
|
+
: unavailable.custom(factory, options);
|
|
469
|
+
},
|
|
345
470
|
};
|
|
346
471
|
}
|
|
347
472
|
|
|
@@ -1400,8 +1525,19 @@ export async function runChain(
|
|
|
1400
1525
|
return workflowDetailsFromRun("chain", runResult, results, options, validationWarnings);
|
|
1401
1526
|
}
|
|
1402
1527
|
|
|
1403
|
-
function raceAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {
|
|
1528
|
+
export function raceAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {
|
|
1404
1529
|
if (signal.aborted) {
|
|
1530
|
+
// Callers invoke `raceAbort(call(), signal)`, so `call()` is evaluated —
|
|
1531
|
+
// and the underlying work (e.g. a stage prompt) is already in flight —
|
|
1532
|
+
// before this function observes an already-aborted signal. Attach a no-op
|
|
1533
|
+
// rejection handler so that in-flight promise can never surface as an
|
|
1534
|
+
// unhandled rejection. Without this, killing a workflow mid-prompt orphans
|
|
1535
|
+
// the prompt promise; its eventual rejection (commonly
|
|
1536
|
+
// "No API key found for ...") escapes every workflow error boundary and is
|
|
1537
|
+
// raised as a process-level uncaught exception that crashes the whole CLI.
|
|
1538
|
+
// The run is being aborted, so the orphaned settlement is intentionally
|
|
1539
|
+
// discarded here.
|
|
1540
|
+
void promise.catch(() => {});
|
|
1405
1541
|
return Promise.reject(signal.reason ?? new DOMException("workflow killed", "AbortError"));
|
|
1406
1542
|
}
|
|
1407
1543
|
return new Promise<T>((resolve, reject) => {
|
|
@@ -2640,11 +2776,16 @@ export async function run<TInputs extends WorkflowInputValues>(
|
|
|
2640
2776
|
};
|
|
2641
2777
|
};
|
|
2642
2778
|
|
|
2643
|
-
const buildPromptNodeUiAdapter = ():
|
|
2644
|
-
const ask = async (descriptor: PromptDescriptor): Promise<unknown> => {
|
|
2779
|
+
const buildPromptNodeUiAdapter = (): WorkflowUIContext => {
|
|
2780
|
+
const ask = async <T>(descriptor: PromptDescriptor<T>): Promise<unknown> => {
|
|
2781
|
+
const isCustom = isCustomPromptDescriptor(descriptor);
|
|
2645
2782
|
if (ownController.signal.aborted) {
|
|
2783
|
+
if (isCustom) throw hilAbortError(ownController.signal);
|
|
2646
2784
|
return fallbackForPromptDescriptor(descriptor);
|
|
2647
2785
|
}
|
|
2786
|
+
if (isCustom && descriptor.options?.signal?.aborted) {
|
|
2787
|
+
throw hilAbortError(descriptor.options.signal);
|
|
2788
|
+
}
|
|
2648
2789
|
|
|
2649
2790
|
const prompt = makePrompt(descriptor);
|
|
2650
2791
|
const stageId = crypto.randomUUID();
|
|
@@ -2741,6 +2882,55 @@ export async function run<TInputs extends WorkflowInputValues>(
|
|
|
2741
2882
|
finalizePromptStage("completed");
|
|
2742
2883
|
return replayAnswer.value;
|
|
2743
2884
|
}
|
|
2885
|
+
|
|
2886
|
+
if (isCustom) {
|
|
2887
|
+
if (descriptor.options?.overlay === true) {
|
|
2888
|
+
const error = new Error("atomic-workflows: ctx.ui.custom overlay mode is unavailable in the workflow graph viewer");
|
|
2889
|
+
applyFailureToStage(stageSnapshot, classifyExecutorFailure(error));
|
|
2890
|
+
finalizePromptStage("failed");
|
|
2891
|
+
throw error;
|
|
2892
|
+
}
|
|
2893
|
+
|
|
2894
|
+
const mergedSignal = mergeHilSignals(ownController.signal, descriptor.options?.signal);
|
|
2895
|
+
try {
|
|
2896
|
+
if (mergedSignal.signal.aborted) throw hilAbortError(mergedSignal.signal);
|
|
2897
|
+
const accepted = activeStore.recordStageAwaitingInput(runId, stageId, true, prompt.createdAt);
|
|
2898
|
+
if (!accepted) {
|
|
2899
|
+
const error = new Error("atomic-workflows: ctx.ui.custom prompt node is unavailable");
|
|
2900
|
+
stageSnapshot.skippedReason = "prompt-unavailable";
|
|
2901
|
+
finalizePromptStage("skipped");
|
|
2902
|
+
throw error;
|
|
2903
|
+
}
|
|
2904
|
+
const response = await stageUiBroker.requestCustomUi(
|
|
2905
|
+
runId,
|
|
2906
|
+
stageId,
|
|
2907
|
+
descriptor.factory as unknown as Parameters<typeof stageUiBroker.requestCustomUi>[2],
|
|
2908
|
+
descriptor.options as Parameters<typeof stageUiBroker.requestCustomUi>[3],
|
|
2909
|
+
mergedSignal.signal,
|
|
2910
|
+
);
|
|
2911
|
+
activeStore.recordStagePromptAnswer(runId, stageId, prompt, response, {
|
|
2912
|
+
answerSource: "workflow_ui",
|
|
2913
|
+
});
|
|
2914
|
+
finalizePromptStage("completed");
|
|
2915
|
+
return response;
|
|
2916
|
+
} catch (err) {
|
|
2917
|
+
activeStore.recordStageAwaitingInput(runId, stageId, false);
|
|
2918
|
+
stageUiBroker.cancelStagePrompt(runId, stageId, err);
|
|
2919
|
+
if (mergedSignal.signal.aborted) {
|
|
2920
|
+
stageSnapshot.skippedReason = ownController.signal.aborted ? "run-aborted" : "prompt-aborted";
|
|
2921
|
+
finalizePromptStage("skipped");
|
|
2922
|
+
throw hilAbortError(mergedSignal.signal);
|
|
2923
|
+
}
|
|
2924
|
+
if (!finalized) {
|
|
2925
|
+
applyFailureToStage(stageSnapshot, classifyExecutorFailure(err));
|
|
2926
|
+
finalizePromptStage("failed");
|
|
2927
|
+
}
|
|
2928
|
+
throw err;
|
|
2929
|
+
} finally {
|
|
2930
|
+
mergedSignal.dispose();
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2744
2934
|
const accepted = activeStore.recordStagePendingPrompt(runId, stageId, prompt);
|
|
2745
2935
|
if (!accepted) {
|
|
2746
2936
|
stageSnapshot.skippedReason = "prompt-unavailable";
|
|
@@ -2818,6 +3008,10 @@ export async function run<TInputs extends WorkflowInputValues>(
|
|
|
2818
3008
|
});
|
|
2819
3009
|
return typeof response === "string" ? response : initial ?? "";
|
|
2820
3010
|
},
|
|
3011
|
+
async custom<T>(factory: WorkflowCustomUiFactory<T>, options?: WorkflowCustomUiOptions): Promise<T> {
|
|
3012
|
+
const response = await ask(customPromptDescriptor(factory, options));
|
|
3013
|
+
return response as T;
|
|
3014
|
+
},
|
|
2821
3015
|
};
|
|
2822
3016
|
};
|
|
2823
3017
|
|
|
@@ -2827,7 +3021,7 @@ export async function run<TInputs extends WorkflowInputValues>(
|
|
|
2827
3021
|
get cwd() { return resolveWorkflowCwd(); },
|
|
2828
3022
|
// Prompt nodes and caller-provided UI adapters are mutually exclusive;
|
|
2829
3023
|
// executor-owned prompt nodes intentionally take precedence when enabled.
|
|
2830
|
-
ui: opts.usePromptNodesForUi === true ? buildPromptNodeUiAdapter() : opts.ui
|
|
3024
|
+
ui: opts.usePromptNodesForUi === true ? buildPromptNodeUiAdapter() : normalizeUIContext(opts.ui),
|
|
2831
3025
|
|
|
2832
3026
|
stage(name: string, options?: StageOptions, stageFailFastScope?: ParallelFailFastScope) {
|
|
2833
3027
|
options = stageOptionsWithGitWorktree(stageOptionsWithInputDefaults(options, inputRuntimeDefaults), workflowInvocationCwd);
|
|
@@ -37,7 +37,7 @@ export type { StageNode } from "./runs/shared/graph-inference.js";
|
|
|
37
37
|
export { setupGitWorktree } from "./runs/shared/worktree.js";
|
|
38
38
|
export type { GitWorktreeSetupOptions, GitWorktreeSetupResult } from "./runs/shared/worktree.js";
|
|
39
39
|
export { createStore, store } from "./shared/store.js";
|
|
40
|
-
export type { RunStatus, StageStatus, ToolEvent, StageSnapshot, RunSnapshot, StoreSnapshot, WorkflowNotice, NoticeLevel, WorkflowOverlayAdapter, PromptKind, PendingPrompt } from "./shared/store-types.js";
|
|
40
|
+
export type { RunStatus, StageStatus, ToolEvent, StageSnapshot, RunSnapshot, StoreSnapshot, WorkflowNotice, NoticeLevel, WorkflowOverlayAdapter, PromptKind, CustomPromptIdentitySource, PendingPrompt } from "./shared/store-types.js";
|
|
41
41
|
|
|
42
42
|
// Phase D — cancellation registry
|
|
43
43
|
export { createCancellationRegistry, cancellationRegistry } from "./runs/background/cancellation-registry.js";
|