@bastani/atomic 0.9.19-alpha.1 → 0.9.19-alpha.3
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 +108 -0
- package/dist/builtin/intercom/CHANGELOG.md +23 -0
- package/dist/builtin/intercom/README.md +21 -11
- package/dist/builtin/intercom/broker/broker.ts +81 -9
- package/dist/builtin/intercom/broker/client.ts +22 -0
- package/dist/builtin/intercom/broker/framing.ts +5 -2
- package/dist/builtin/intercom/broker/group-membership.ts +4 -2
- package/dist/builtin/intercom/broker/presence-handler.ts +14 -0
- package/dist/builtin/intercom/broker/send-handler.ts +43 -5
- package/dist/builtin/intercom/broker/terminal-questions.ts +29 -0
- package/dist/builtin/intercom/index.bundle.mjs +978 -742
- package/dist/builtin/intercom/package.json +2 -2
- package/dist/builtin/intercom/recipient-purpose.ts +9 -0
- package/dist/builtin/intercom/recoverable-disconnect.ts +2 -3
- package/dist/builtin/intercom/retry-policy.ts +4 -2
- package/dist/builtin/intercom/skills/intercom/SKILL.md +5 -4
- package/dist/builtin/intercom/types.ts +18 -3
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/README.md +2 -0
- package/dist/builtin/mcp/index.bundle.mjs +2201 -12000
- package/dist/builtin/mcp/package.json +2 -2
- package/dist/builtin/subagents/CHANGELOG.md +33 -0
- package/dist/builtin/subagents/README.md +35 -14
- package/dist/builtin/subagents/agents/code-simplifier.md +1 -1
- package/dist/builtin/subagents/agents/codebase-analyzer.md +1 -1
- package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +1 -1
- package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
- package/dist/builtin/subagents/agents/codebase-research-analyzer.md +1 -1
- package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
- package/dist/builtin/subagents/agents/debugger.md +1 -1
- package/dist/builtin/subagents/agents/worker.md +1 -1
- package/dist/builtin/subagents/package.json +2 -2
- package/dist/builtin/subagents/skills/herdr/LICENSE +201 -0
- package/dist/builtin/subagents/skills/herdr/SKILL.md +202 -0
- package/dist/builtin/subagents/skills/subagent/SKILL.md +14 -10
- package/dist/builtin/subagents/skills/tmux/SKILL.md +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +1286 -611
- package/dist/builtin/web-access/index.bundle.mjs +26280 -26274
- package/dist/builtin/web-access/package.json +2 -2
- package/dist/builtin/workflows/CHANGELOG.md +51 -0
- package/dist/builtin/workflows/README.md +1 -1
- package/dist/builtin/workflows/builtin/adversarial-verification.js +5 -7
- package/dist/builtin/workflows/builtin/{chunk-reqr3sr3.js → chunk-1kx4aggw.js} +22 -22
- package/dist/builtin/workflows/builtin/{chunk-42s7sw0b.js → chunk-62v3gg9f.js} +9 -9
- package/dist/builtin/workflows/builtin/{chunk-wgccch41.js → chunk-6w6cvk6b.js} +16 -16
- package/dist/builtin/workflows/builtin/{chunk-zbekjqew.js → chunk-a2kdsqn8.js} +4 -4
- package/dist/builtin/workflows/builtin/{chunk-ze5x3d1r.js → chunk-fg9esgkj.js} +7 -7
- package/dist/builtin/workflows/builtin/{chunk-n8h4yyew.js → chunk-g0csgs7w.js} +11 -11
- package/dist/builtin/workflows/builtin/{chunk-79fjkcvh.js → chunk-hbnwv56f.js} +17 -17
- package/dist/builtin/workflows/builtin/{chunk-ed4jfn5t.js → chunk-mygmtz6e.js} +43 -43
- package/dist/builtin/workflows/builtin/{chunk-7430zyas.js → chunk-p8jjwfg6.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-hqpe2cyx.js → chunk-r9qq7xfj.js} +49 -49
- package/dist/builtin/workflows/builtin/{chunk-k3w87x8y.js → chunk-t6x2d78s.js} +10 -10
- package/dist/builtin/workflows/builtin/{chunk-6fqs7c01.js → chunk-z0d03ktm.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-b0v2xab1.js → chunk-zggjyg5z.js} +221 -23
- package/dist/builtin/workflows/builtin/classify-and-act.js +5 -6
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +3 -4
- package/dist/builtin/workflows/builtin/generate-and-filter.js +5 -6
- package/dist/builtin/workflows/builtin/goal.js +7 -8
- package/dist/builtin/workflows/builtin/index.js +20 -22
- package/dist/builtin/workflows/builtin/loop-until-done.js +5 -6
- package/dist/builtin/workflows/builtin/open-claude-design.js +3 -3
- package/dist/builtin/workflows/builtin/ralph.js +7 -8
- package/dist/builtin/workflows/builtin/steering-context.js +3 -3
- package/dist/builtin/workflows/builtin/tournament.js +5 -7
- package/dist/builtin/workflows/package.json +2 -2
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +26708 -25862
- package/dist/builtin/workflows/src/index.js +921 -477
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/startup-ui.d.ts +1 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +5 -4
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-bash.d.ts +1 -1
- package/dist/core/agent-session-bash.d.ts.map +1 -1
- package/dist/core/agent-session-bash.js +5 -1
- package/dist/core/agent-session-bash.js.map +1 -1
- package/dist/core/agent-session-compaction.d.ts +1 -1
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-custom-message-commit.d.ts +1 -1
- package/dist/core/agent-session-custom-message-commit.js.map +1 -1
- package/dist/core/agent-session-delivery-forwarding.d.ts +1 -1
- package/dist/core/agent-session-delivery-forwarding.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +5 -0
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-export.d.ts +1 -1
- package/dist/core/agent-session-export.js.map +1 -1
- package/dist/core/agent-session-extension-bindings.d.ts +8 -1
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
- package/dist/core/agent-session-extension-bindings.js +45 -3
- package/dist/core/agent-session-extension-bindings.js.map +1 -1
- package/dist/core/agent-session-message-queue.d.ts +1 -1
- package/dist/core/agent-session-message-queue.d.ts.map +1 -1
- package/dist/core/agent-session-message-queue.js +2 -2
- package/dist/core/agent-session-message-queue.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +17 -7
- 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-prompt.d.ts +2 -2
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +22 -18
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-runtime-auth.d.ts +1 -1
- package/dist/core/agent-session-runtime-auth.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +13 -4
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +27 -4
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +5 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +44 -34
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session-state.d.ts +1 -1
- package/dist/core/agent-session-state.js.map +1 -1
- package/dist/core/agent-session-tasks.d.ts +14 -0
- package/dist/core/agent-session-tasks.d.ts.map +1 -0
- package/dist/core/agent-session-tasks.js +120 -0
- package/dist/core/agent-session-tasks.js.map +1 -0
- package/dist/core/agent-session-tool-registry.d.ts +1 -0
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
- package/dist/core/agent-session-tool-registry.js +30 -5
- package/dist/core/agent-session-tool-registry.js.map +1 -1
- package/dist/core/agent-session-tree.d.ts.map +1 -1
- package/dist/core/agent-session-tree.js +3 -0
- package/dist/core/agent-session-tree.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +2 -2
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +4 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +7 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts +1 -1
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts +1 -1
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extension-session-state.js.map +1 -1
- package/dist/core/extensions/agent-events.d.ts +4 -4
- package/dist/core/extensions/agent-events.d.ts.map +1 -1
- package/dist/core/extensions/agent-events.js.map +1 -1
- package/dist/core/extensions/api-types.d.ts +8 -2
- package/dist/core/extensions/api-types.d.ts.map +1 -1
- package/dist/core/extensions/api-types.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +9 -0
- 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 +1 -1
- package/dist/core/extensions/event-results.js.map +1 -1
- package/dist/core/extensions/event-types.d.ts +2 -1
- package/dist/core/extensions/event-types.d.ts.map +1 -1
- package/dist/core/extensions/event-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +2 -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-api.d.ts +1 -1
- package/dist/core/extensions/loader-api.d.ts.map +1 -1
- package/dist/core/extensions/loader-api.js +10 -0
- package/dist/core/extensions/loader-api.js.map +1 -1
- package/dist/core/extensions/loader-core.d.ts +1 -1
- package/dist/core/extensions/loader-core.js.map +1 -1
- package/dist/core/extensions/loader-discovery.d.ts +1 -1
- package/dist/core/extensions/loader-discovery.js.map +1 -1
- package/dist/core/extensions/loader-host-modules.d.ts +1 -1
- package/dist/core/extensions/loader-host-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-host-modules.js +2 -1
- package/dist/core/extensions/loader-host-modules.js.map +1 -1
- package/dist/core/extensions/loader-runtime.d.ts.map +1 -1
- package/dist/core/extensions/loader-runtime.js +3 -0
- package/dist/core/extensions/loader-runtime.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +4 -1
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +1 -1
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/message-types.d.ts +1 -1
- package/dist/core/extensions/message-types.js.map +1 -1
- package/dist/core/extensions/runner-context.d.ts +11 -1
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.js +41 -2
- package/dist/core/extensions/runner-context.js.map +1 -1
- package/dist/core/extensions/runner-events.d.ts +1 -1
- package/dist/core/extensions/runner-events.d.ts.map +1 -1
- package/dist/core/extensions/runner-events.js +17 -2
- package/dist/core/extensions/runner-events.js.map +1 -1
- package/dist/core/extensions/runner-ui.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +17 -2
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +68 -18
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/runtime-types.d.ts +4 -1
- package/dist/core/extensions/runtime-types.d.ts.map +1 -1
- package/dist/core/extensions/runtime-types.js.map +1 -1
- package/dist/core/extensions/tool-types.d.ts +1 -1
- package/dist/core/extensions/tool-types.js.map +1 -1
- package/dist/core/extensions/types.d.ts +1 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/ui-types.d.ts +5 -1
- package/dist/core/extensions/ui-types.d.ts.map +1 -1
- package/dist/core/extensions/ui-types.js.map +1 -1
- package/dist/core/extensions/workflow-activity-hub.d.ts +25 -0
- package/dist/core/extensions/workflow-activity-hub.d.ts.map +1 -0
- package/dist/core/extensions/workflow-activity-hub.js +183 -0
- package/dist/core/extensions/workflow-activity-hub.js.map +1 -0
- package/dist/core/extensions/workflow-events.d.ts +118 -0
- package/dist/core/extensions/workflow-events.d.ts.map +1 -0
- package/dist/core/extensions/workflow-events.js +2 -0
- package/dist/core/extensions/workflow-events.js.map +1 -0
- package/dist/core/footer-data-provider.d.ts +8 -4
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +97 -11
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +27 -2
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +7 -2
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/mandatory-runtime-tools.d.ts +1 -1
- package/dist/core/mandatory-runtime-tools.js.map +1 -1
- package/dist/core/model-fallback-failures.js +2 -2
- package/dist/core/model-fallback-failures.js.map +1 -1
- package/dist/core/model-registry.d.ts +5 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +8 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver-defaults.js +1 -1
- package/dist/core/model-resolver-defaults.js.map +1 -1
- package/dist/core/resource-loader-assets.js.map +1 -1
- package/dist/core/resource-loader-core.d.ts +1 -1
- package/dist/core/resource-loader-core.js.map +1 -1
- package/dist/core/resource-loader-internals.d.ts +2 -2
- package/dist/core/resource-loader-internals.js.map +1 -1
- package/dist/core/resource-loader-reload.d.ts +2 -0
- package/dist/core/resource-loader-reload.d.ts.map +1 -1
- package/dist/core/resource-loader-reload.js +231 -191
- package/dist/core/resource-loader-reload.js.map +1 -1
- package/dist/core/resource-loader-types.d.ts +4 -2
- package/dist/core/resource-loader-types.d.ts.map +1 -1
- package/dist/core/resource-loader-types.js.map +1 -1
- package/dist/core/retry-policy.d.ts +1 -0
- package/dist/core/retry-policy.d.ts.map +1 -1
- package/dist/core/retry-policy.js +2 -1
- package/dist/core/retry-policy.js.map +1 -1
- package/dist/core/sdk-exports.d.ts +2 -2
- package/dist/core/sdk-exports.js.map +1 -1
- package/dist/core/sdk-types.d.ts +2 -2
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +1 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +2 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-manager-core.d.ts.map +1 -1
- package/dist/core/settings-manager-core.js +10 -4
- package/dist/core/settings-manager-core.js.map +1 -1
- package/dist/core/settings-storage.d.ts +1 -0
- package/dist/core/settings-storage.d.ts.map +1 -1
- package/dist/core/settings-storage.js +18 -0
- package/dist/core/settings-storage.js.map +1 -1
- package/dist/core/settings-types.d.ts +12 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -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 +5 -6
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tasks/agent-adapter.d.ts +41 -0
- package/dist/core/tasks/agent-adapter.d.ts.map +1 -0
- package/dist/core/tasks/agent-adapter.js +105 -0
- package/dist/core/tasks/agent-adapter.js.map +1 -0
- package/dist/core/tasks/command-output.d.ts +15 -0
- package/dist/core/tasks/command-output.d.ts.map +1 -0
- package/dist/core/tasks/command-output.js +29 -0
- package/dist/core/tasks/command-output.js.map +1 -0
- package/dist/core/tasks/completion-ordering.d.ts +11 -0
- package/dist/core/tasks/completion-ordering.d.ts.map +1 -0
- package/dist/core/tasks/completion-ordering.js +19 -0
- package/dist/core/tasks/completion-ordering.js.map +1 -0
- package/dist/core/tasks/completion.d.ts +36 -0
- package/dist/core/tasks/completion.d.ts.map +1 -0
- package/dist/core/tasks/completion.js +115 -0
- package/dist/core/tasks/completion.js.map +1 -0
- package/dist/core/tasks/contracts.d.ts +404 -0
- package/dist/core/tasks/contracts.d.ts.map +1 -0
- package/dist/core/tasks/contracts.js +2 -0
- package/dist/core/tasks/contracts.js.map +1 -0
- package/dist/core/tasks/execution-scope.d.ts +10 -0
- package/dist/core/tasks/execution-scope.d.ts.map +1 -0
- package/dist/core/tasks/execution-scope.js +27 -0
- package/dist/core/tasks/execution-scope.js.map +1 -0
- package/dist/core/tasks/owner-store.d.ts +53 -0
- package/dist/core/tasks/owner-store.d.ts.map +1 -0
- package/dist/core/tasks/owner-store.js +155 -0
- package/dist/core/tasks/owner-store.js.map +1 -0
- package/dist/core/tasks/pause.d.ts +4 -0
- package/dist/core/tasks/pause.d.ts.map +1 -0
- package/dist/core/tasks/pause.js +49 -0
- package/dist/core/tasks/pause.js.map +1 -0
- package/dist/core/tasks/supervisor.d.ts +123 -0
- package/dist/core/tasks/supervisor.d.ts.map +1 -0
- package/dist/core/tasks/supervisor.js +942 -0
- package/dist/core/tasks/supervisor.js.map +1 -0
- package/dist/core/tasks/transcript.d.ts +23 -0
- package/dist/core/tasks/transcript.d.ts.map +1 -0
- package/dist/core/tasks/transcript.js +74 -0
- package/dist/core/tasks/transcript.js.map +1 -0
- package/dist/core/tools/ask-user-question/ask-user-question.d.ts +2 -2
- package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/ask-user-question.js +8 -4
- package/dist/core/tools/ask-user-question/ask-user-question.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/build-questionnaire.d.ts +1 -1
- package/dist/core/tools/ask-user-question/state/build-questionnaire.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts +1 -1
- package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/multi-select-view.d.ts +1 -1
- package/dist/core/tools/ask-user-question/view/components/multi-select-view.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.d.ts +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/submit-picker.d.ts +1 -1
- package/dist/core/tools/ask-user-question/view/components/submit-picker.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/tab-bar.d.ts +1 -1
- package/dist/core/tools/ask-user-question/view/components/tab-bar.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts +1 -1
- package/dist/core/tools/ask-user-question/view/dialog-builder.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/tab-content-strategy.d.ts +1 -1
- package/dist/core/tools/ask-user-question/view/tab-content-strategy.js.map +1 -1
- package/dist/core/tools/bash-pty-native.d.ts +18 -3
- package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
- package/dist/core/tools/bash-pty-native.js +116 -1
- package/dist/core/tools/bash-pty-native.js.map +1 -1
- package/dist/core/tools/bash.d.ts +13 -4
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +53 -9
- 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 +1 -2
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +2 -2
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/powershell.d.ts +20 -10
- package/dist/core/tools/powershell.d.ts.map +1 -1
- package/dist/core/tools/powershell.js +33 -7
- package/dist/core/tools/powershell.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +1 -2
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/resource-selectors.d.ts +1 -1
- package/dist/core/tools/resource-selectors.d.ts.map +1 -1
- package/dist/core/tools/resource-selectors.js +21 -10
- package/dist/core/tools/resource-selectors.js.map +1 -1
- package/dist/core/tools/search.js.map +1 -1
- package/dist/core/tools/todos-render.d.ts +1 -1
- package/dist/core/tools/todos-render.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +1 -2
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/workflow-stage-admission.d.ts +10 -0
- package/dist/core/workflow-stage-admission.d.ts.map +1 -1
- package/dist/core/workflow-stage-admission.js +24 -0
- package/dist/core/workflow-stage-admission.js.map +1 -1
- package/dist/extensions/herdr/activity.d.ts +15 -0
- package/dist/extensions/herdr/activity.d.ts.map +1 -0
- package/dist/extensions/herdr/activity.js +24 -0
- package/dist/extensions/herdr/activity.js.map +1 -0
- package/dist/extensions/herdr/environment.d.ts +7 -0
- package/dist/extensions/herdr/environment.d.ts.map +1 -0
- package/dist/extensions/herdr/environment.js +6 -0
- package/dist/extensions/herdr/environment.js.map +1 -0
- package/dist/extensions/herdr/index.d.ts +9 -0
- package/dist/extensions/herdr/index.d.ts.map +1 -0
- package/dist/extensions/herdr/index.js +225 -0
- package/dist/extensions/herdr/index.js.map +1 -0
- package/dist/extensions/herdr/pane-owner.d.ts +30 -0
- package/dist/extensions/herdr/pane-owner.d.ts.map +1 -0
- package/dist/extensions/herdr/pane-owner.js +111 -0
- package/dist/extensions/herdr/pane-owner.js.map +1 -0
- package/dist/extensions/herdr/transport.d.ts +8 -0
- package/dist/extensions/herdr/transport.d.ts.map +1 -0
- package/dist/extensions/herdr/transport.js +28 -0
- package/dist/extensions/herdr/transport.js.map +1 -0
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/index.js +2 -0
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/llama/huggingface-ui.d.ts +1 -1
- package/dist/extensions/llama/huggingface-ui.js.map +1 -1
- package/dist/extensions/llama/ui.js.map +1 -1
- package/dist/index-extensions.d.ts +3 -2
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/main-session.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +149 -69
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/atomic-banner.d.ts +1 -1
- package/dist/modes/interactive/components/atomic-banner.js.map +1 -1
- package/dist/modes/interactive/components/atomic-working-status.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts +12 -0
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js +44 -0
- package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.js +43 -8
- package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts +1 -1
- package/dist/modes/interactive/components/chat-session-host-editor.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts +2 -2
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.d.ts +2 -2
- package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.js +12 -3
- package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-runtime.d.ts +4 -5
- package/dist/modes/interactive/components/chat-session-host-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-runtime.js +8 -6
- package/dist/modes/interactive/components/chat-session-host-runtime.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.d.ts +7 -2
- 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-terminal-cleanup.d.ts +1 -1
- package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-types.d.ts +8 -3
- package/dist/modes/interactive/components/chat-session-host-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-types.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-utils.d.ts +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 +2 -0
- package/dist/modes/interactive/components/chat-session-host-utils.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts +17 -2
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +100 -3
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/chat-transcript.d.ts +1 -0
- package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-transcript.js +1 -1
- package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
- package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector-list.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +12 -0
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts +1 -1
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +7 -6
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +27 -9
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/host-input-form-mount.js.map +1 -1
- package/dist/modes/interactive/components/host-input-form.d.ts +1 -1
- package/dist/modes/interactive/components/host-input-form.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +2 -2
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/mermaid.d.ts +1 -1
- package/dist/modes/interactive/components/mermaid.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/reserved-bottom-overlay.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-header.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-items.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-submenus.d.ts +1 -1
- package/dist/modes/interactive/components/settings-selector-submenus.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-types.d.ts +1 -1
- package/dist/modes/interactive/components/settings-selector-types.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/task-completion-message.d.ts +13 -0
- package/dist/modes/interactive/components/task-completion-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/task-completion-message.js +65 -0
- package/dist/modes/interactive/components/task-completion-message.js.map +1 -0
- package/dist/modes/interactive/components/task-detail.d.ts +27 -0
- package/dist/modes/interactive/components/task-detail.d.ts.map +1 -0
- package/dist/modes/interactive/components/task-detail.js +107 -0
- package/dist/modes/interactive/components/task-detail.js.map +1 -0
- package/dist/modes/interactive/components/task-inspector.d.ts +50 -0
- package/dist/modes/interactive/components/task-inspector.d.ts.map +1 -0
- package/dist/modes/interactive/components/task-inspector.js +599 -0
- package/dist/modes/interactive/components/task-inspector.js.map +1 -0
- package/dist/modes/interactive/components/task-list.d.ts +18 -0
- package/dist/modes/interactive/components/task-list.d.ts.map +1 -0
- package/dist/modes/interactive/components/task-list.js +59 -0
- package/dist/modes/interactive/components/task-list.js.map +1 -0
- package/dist/modes/interactive/components/task-live-transcript.d.ts +17 -0
- package/dist/modes/interactive/components/task-live-transcript.d.ts.map +1 -0
- package/dist/modes/interactive/components/task-live-transcript.js +33 -0
- package/dist/modes/interactive/components/task-live-transcript.js.map +1 -0
- package/dist/modes/interactive/components/task-navigation.d.ts +38 -0
- package/dist/modes/interactive/components/task-navigation.d.ts.map +1 -0
- package/dist/modes/interactive/components/task-navigation.js +93 -0
- package/dist/modes/interactive/components/task-navigation.js.map +1 -0
- package/dist/modes/interactive/components/task-row.d.ts +34 -0
- package/dist/modes/interactive/components/task-row.d.ts.map +1 -0
- package/dist/modes/interactive/components/task-row.js +158 -0
- package/dist/modes/interactive/components/task-row.js.map +1 -0
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/transcript-follow-indicator.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-component.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-help.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-label-input.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-list.js.map +1 -1
- package/dist/modes/interactive/components/trust-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/working-status.js.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.js +8 -2
- package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
- package/dist/modes/interactive/interactive-auth-login.js +3 -1
- package/dist/modes/interactive/interactive-auth-login.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +9 -30
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.js +2 -1
- package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-context.js +14 -4
- package/dist/modes/interactive/interactive-extension-context.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-custom-ui.js +52 -4
- package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-runtime.js +1 -0
- package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-widgets.js +9 -1
- package/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +19 -0
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts +6 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +4 -1
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts +6 -6
- package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +3 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/interactive-process-lifecycle.js +4 -1
- package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.js +2 -0
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.js +33 -23
- package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-session-runtime.js +1 -0
- package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-slash-commands.js.map +1 -1
- package/dist/modes/interactive/interactive-summarization-retry-events.js +2 -2
- package/dist/modes/interactive/interactive-summarization-retry-events.js.map +1 -1
- package/dist/modes/interactive/interactive-task-projection.d.ts +13 -0
- package/dist/modes/interactive/interactive-task-projection.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-task-projection.js +72 -0
- package/dist/modes/interactive/interactive-task-projection.js.map +1 -0
- package/dist/modes/interactive/interactive-tui.js.map +1 -1
- package/dist/modes/interactive/interactive-windows-subshell.d.ts +17 -0
- package/dist/modes/interactive/interactive-windows-subshell.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-windows-subshell.js +92 -0
- package/dist/modes/interactive/interactive-windows-subshell.js.map +1 -0
- package/dist/modes/interactive/skill-command-autocomplete.d.ts +12 -0
- package/dist/modes/interactive/skill-command-autocomplete.d.ts.map +1 -0
- package/dist/modes/interactive/skill-command-autocomplete.js +69 -0
- package/dist/modes/interactive/skill-command-autocomplete.js.map +1 -0
- package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-class.js +4 -1
- package/dist/modes/interactive/theme/theme-class.js.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +1 -1
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive-engine/create-isolated-runtime.d.ts +1 -1
- package/dist/modes/interactive-engine/create-isolated-runtime.js.map +1 -1
- package/dist/modes/interactive-engine/engine-custom-ui.d.ts +5 -9
- package/dist/modes/interactive-engine/engine-custom-ui.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-custom-ui.js +14 -5
- package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
- package/dist/modes/interactive-engine/engine-dialog-host.d.ts +2 -2
- package/dist/modes/interactive-engine/engine-dialog-host.js.map +1 -1
- package/dist/modes/interactive-engine/engine-project-trust.d.ts +10 -0
- package/dist/modes/interactive-engine/engine-project-trust.d.ts.map +1 -0
- package/dist/modes/interactive-engine/engine-project-trust.js +28 -0
- package/dist/modes/interactive-engine/engine-project-trust.js.map +1 -0
- package/dist/modes/interactive-engine/engine-render-service.d.ts +1 -1
- package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
- package/dist/modes/interactive-engine/extension-ui-bridge.d.ts +3 -1
- package/dist/modes/interactive-engine/extension-ui-bridge.d.ts.map +1 -1
- package/dist/modes/interactive-engine/extension-ui-bridge.js +6 -0
- package/dist/modes/interactive-engine/extension-ui-bridge.js.map +1 -1
- package/dist/modes/interactive-engine/input-form-host.d.ts +2 -2
- package/dist/modes/interactive-engine/input-form-host.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-auth.d.ts +1 -1
- package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts +5 -2
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +40 -3
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/interactive-engine/protocol.d.ts +9 -0
- package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
- package/dist/modes/interactive-engine/protocol.js +8 -0
- package/dist/modes/interactive-engine/protocol.js.map +1 -1
- package/dist/modes/interactive-engine/remote-component.d.ts +2 -2
- package/dist/modes/interactive-engine/remote-component.d.ts.map +1 -1
- package/dist/modes/interactive-engine/remote-component.js +3 -2
- package/dist/modes/interactive-engine/remote-component.js.map +1 -1
- package/dist/modes/interactive-engine/remote-model-catalog.d.ts +1 -1
- package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
- package/dist/modes/interactive-engine/remote-renderer.d.ts +1 -1
- package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
- package/dist/modes/interactive-engine/session-picker-host.d.ts +2 -2
- package/dist/modes/interactive-engine/session-picker-host.js.map +1 -1
- package/dist/modes/json-event.d.ts +1 -1
- package/dist/modes/json-event.js.map +1 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-bash-request-owners.d.ts +2 -2
- package/dist/modes/rpc/rpc-bash-request-owners.js.map +1 -1
- package/dist/modes/rpc/rpc-client-api.d.ts +2 -2
- package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-api.js +2 -2
- package/dist/modes/rpc/rpc-client-api.js.map +1 -1
- package/dist/modes/rpc/rpc-client-waits.d.ts +1 -1
- package/dist/modes/rpc/rpc-client-waits.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +3 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +20 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts +4 -2
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +12 -4
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-extension-ui.d.ts +1 -1
- package/dist/modes/rpc/rpc-extension-ui.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +11 -2
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-provider-auth.d.ts +1 -1
- package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
- package/dist/modes/rpc/rpc-session-binding.d.ts +4 -1
- package/dist/modes/rpc/rpc-session-binding.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-session-binding.js +35 -1
- package/dist/modes/rpc/rpc-session-binding.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +13 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/rpc/task-ui-bridge.d.ts +9 -0
- package/dist/modes/rpc/task-ui-bridge.d.ts.map +1 -0
- package/dist/modes/rpc/task-ui-bridge.js +146 -0
- package/dist/modes/rpc/task-ui-bridge.js.map +1 -0
- package/dist/self-update-plan.js.map +1 -1
- package/docs/background-tasks.md +205 -0
- package/docs/compaction.md +2 -0
- package/docs/development.md +23 -72
- package/docs/docs.json +2 -0
- package/docs/environment-variables.md +1 -1
- package/docs/extensions.md +112 -6
- package/docs/herdr.md +53 -0
- package/docs/intercom.md +42 -35
- package/docs/keybindings.md +19 -2
- package/docs/models/evals.md +224 -147
- package/docs/models/model-selection.md +28 -19
- package/docs/models/pareto-efficiency.md +2 -2
- package/docs/providers.md +48 -46
- package/docs/quickstart.md +1 -1
- package/docs/sdk.md +244 -0
- package/docs/settings.md +19 -3
- package/docs/skills.md +23 -1
- package/docs/subagents.md +74 -10
- package/docs/themes.md +4 -0
- package/docs/tools.md +29 -0
- package/docs/tui.md +29 -2
- package/docs/usage.md +4 -0
- package/docs/windows.md +4 -4
- package/docs/workflows/api-reference.md +14 -5
- package/docs/workflows/operations.md +49 -3
- package/docs/workflows/reliable-design.md +35 -4
- package/docs/workflows/verification.md +21 -4
- package/docs/workflows.md +3 -1
- package/npm-shrinkwrap.json +797 -677
- package/package.json +10 -10
- /package/dist/builtin/workflows/builtin/{chunk-cg9tmks0.js → chunk-n1910xc4.js} +0 -0
- /package/dist/builtin/workflows/builtin/{chunk-wpckd35c.js → chunk-rc5ec5xx.js} +0 -0
- /package/dist/builtin/workflows/builtin/{chunk-7at6dnkr.js → chunk-tgt0s5e5.js} +0 -0
- /package/dist/builtin/workflows/builtin/{chunk-bfkmzv9h.js → chunk-xtxcq5tj.js} +0 -0
|
@@ -12,7 +12,17 @@ var __export = (target, all) => {
|
|
|
12
12
|
set: __exportSetter.bind(all, name)
|
|
13
13
|
});
|
|
14
14
|
};
|
|
15
|
-
var __esm = (fn, res) => () =>
|
|
15
|
+
var __esm = (fn, res, err) => () => {
|
|
16
|
+
if (fn)
|
|
17
|
+
try {
|
|
18
|
+
res = fn(fn = 0);
|
|
19
|
+
} catch (e) {
|
|
20
|
+
err = [e];
|
|
21
|
+
}
|
|
22
|
+
if (err)
|
|
23
|
+
throw err[0];
|
|
24
|
+
return res;
|
|
25
|
+
};
|
|
16
26
|
|
|
17
27
|
// dist/builtin/intercom/result-renderers.ts
|
|
18
28
|
import { Text } from "@earendil-works/pi-tui";
|
|
@@ -80,7 +90,7 @@ function isRecoverableIntercomDisconnect(error) {
|
|
|
80
90
|
}
|
|
81
91
|
return false;
|
|
82
92
|
}
|
|
83
|
-
var RECOVERABLE_DISCONNECT_MESSAGE = "Client disconnected
|
|
93
|
+
var RECOVERABLE_DISCONNECT_MESSAGE = "Client disconnected", MAX_CAUSE_DEPTH = 8, IntercomClientDisconnectedError;
|
|
84
94
|
var init_recoverable_disconnect = __esm(() => {
|
|
85
95
|
IntercomClientDisconnectedError = class IntercomClientDisconnectedError extends Error {
|
|
86
96
|
intercomRecoverableDisconnect = true;
|
|
@@ -91,6 +101,16 @@ var init_recoverable_disconnect = __esm(() => {
|
|
|
91
101
|
};
|
|
92
102
|
});
|
|
93
103
|
|
|
104
|
+
// dist/builtin/intercom/retry-policy.ts
|
|
105
|
+
var ASK_REPLY_TIMEOUT_MS, RETRY_IDENTITY_RETRY_OPPORTUNITY_MS, RETRY_IDENTITY_TTL_MS, DELIVERED_MESSAGE_TTL_MS, RECONNECT_DELAYS_MS;
|
|
106
|
+
var init_retry_policy = __esm(() => {
|
|
107
|
+
ASK_REPLY_TIMEOUT_MS = 10 * 60 * 1000;
|
|
108
|
+
RETRY_IDENTITY_RETRY_OPPORTUNITY_MS = 60 * 1000;
|
|
109
|
+
RETRY_IDENTITY_TTL_MS = ASK_REPLY_TIMEOUT_MS + RETRY_IDENTITY_RETRY_OPPORTUNITY_MS;
|
|
110
|
+
DELIVERED_MESSAGE_TTL_MS = RETRY_IDENTITY_TTL_MS + RETRY_IDENTITY_RETRY_OPPORTUNITY_MS;
|
|
111
|
+
RECONNECT_DELAYS_MS = [1000, 2000, 5000];
|
|
112
|
+
});
|
|
113
|
+
|
|
94
114
|
// dist/builtin/intercom/reconnect-backoff.ts
|
|
95
115
|
function reconnectDelayMs(attempt) {
|
|
96
116
|
return BACKOFF_MS[Math.min(attempt, BACKOFF_MS.length - 1)];
|
|
@@ -100,6 +120,37 @@ var init_reconnect_backoff = __esm(() => {
|
|
|
100
120
|
BACKOFF_MS = [1000, 2000, 5000, 1e4, 30000];
|
|
101
121
|
});
|
|
102
122
|
|
|
123
|
+
// dist/builtin/intercom/subagent-reply-capability.ts
|
|
124
|
+
function registerSubagentReplyCapability(pi, client) {
|
|
125
|
+
let signal;
|
|
126
|
+
let unbind;
|
|
127
|
+
const capability = () => {
|
|
128
|
+
if (!signal)
|
|
129
|
+
return;
|
|
130
|
+
return signal.aborted ? "terminal" : "live";
|
|
131
|
+
};
|
|
132
|
+
pi.on("session_start", (_event, ctx) => {
|
|
133
|
+
unbind?.();
|
|
134
|
+
signal = ctx.subagentPolicy?.executionEnded;
|
|
135
|
+
const current = signal;
|
|
136
|
+
const terminal = () => {
|
|
137
|
+
if (signal !== current)
|
|
138
|
+
return;
|
|
139
|
+
client()?.updatePresence({ replyCapability: "terminal" });
|
|
140
|
+
};
|
|
141
|
+
current?.addEventListener("abort", terminal, { once: true });
|
|
142
|
+
unbind = () => current?.removeEventListener("abort", terminal);
|
|
143
|
+
if (current?.aborted)
|
|
144
|
+
terminal();
|
|
145
|
+
});
|
|
146
|
+
pi.on("session_shutdown", () => {
|
|
147
|
+
unbind?.();
|
|
148
|
+
unbind = undefined;
|
|
149
|
+
signal = undefined;
|
|
150
|
+
});
|
|
151
|
+
return capability;
|
|
152
|
+
}
|
|
153
|
+
|
|
103
154
|
// dist/builtin/intercom/broker/framing.ts
|
|
104
155
|
function writeMessage(socket, msg, callback) {
|
|
105
156
|
const json = JSON.stringify(msg);
|
|
@@ -472,6 +523,7 @@ var init_client = __esm(() => {
|
|
|
472
523
|
_supervisorSessionId = null;
|
|
473
524
|
_messageSource;
|
|
474
525
|
pendingSends = new PendingSendRegistry;
|
|
526
|
+
pendingReplyTargets = new Map;
|
|
475
527
|
pendingGroupLists = new Map;
|
|
476
528
|
pendingLists = new Map;
|
|
477
529
|
pendingPresence = new Map;
|
|
@@ -679,6 +731,16 @@ var init_client = __esm(() => {
|
|
|
679
731
|
this.emit("_registration_failed", new Error(brokerMessage.reason));
|
|
680
732
|
break;
|
|
681
733
|
}
|
|
734
|
+
case "question_target": {
|
|
735
|
+
const { messageId, attemptId, sessionId } = brokerMessage;
|
|
736
|
+
if (typeof messageId !== "string" || typeof attemptId !== "string" || typeof sessionId !== "string") {
|
|
737
|
+
throw new Error("Invalid question_target message");
|
|
738
|
+
}
|
|
739
|
+
const pending = this.pendingReplyTargets.get(attemptId);
|
|
740
|
+
if (pending?.messageId === messageId)
|
|
741
|
+
pending.bind(sessionId);
|
|
742
|
+
break;
|
|
743
|
+
}
|
|
682
744
|
case "sessions": {
|
|
683
745
|
const { requestId, sessions, workflowStages, workflowFutureStages } = brokerMessage;
|
|
684
746
|
if (typeof requestId !== "string" || !Array.isArray(sessions) || !sessions.every(isSessionInfo) || workflowStages !== undefined && !isWorkflowStageRosterEntries(workflowStages) || workflowFutureStages !== undefined && !isWorkflowFutureStageRosterEntries(workflowFutureStages)) {
|
|
@@ -1096,14 +1158,15 @@ var init_client = __esm(() => {
|
|
|
1096
1158
|
}
|
|
1097
1159
|
});
|
|
1098
1160
|
}
|
|
1099
|
-
registerPendingStageRoute(runId, group, capability, stages, possibleStages) {
|
|
1161
|
+
registerPendingStageRoute(runId, group, capability, stages, possibleStages, parent) {
|
|
1100
1162
|
writeMessage(this.requireActiveSocket(), {
|
|
1101
1163
|
type: "register_pending_stage_route",
|
|
1102
1164
|
runId,
|
|
1103
1165
|
group,
|
|
1104
1166
|
capability,
|
|
1105
1167
|
stages,
|
|
1106
|
-
possibleStages
|
|
1168
|
+
possibleStages,
|
|
1169
|
+
...parent === undefined ? {} : { parent }
|
|
1107
1170
|
});
|
|
1108
1171
|
}
|
|
1109
1172
|
registerLiveWorkflowStageRoute(runId, stageKeys, capability) {
|
|
@@ -1194,12 +1257,16 @@ var init_client = __esm(() => {
|
|
|
1194
1257
|
source: this._messageSource,
|
|
1195
1258
|
content: { text: options.text, attachments: options.attachments }
|
|
1196
1259
|
};
|
|
1260
|
+
if (options.onReplyTarget !== undefined) {
|
|
1261
|
+
this.pendingReplyTargets.set(acquired.attempt.attemptId, { messageId, bind: options.onReplyTarget });
|
|
1262
|
+
}
|
|
1197
1263
|
try {
|
|
1198
1264
|
writeMessage(socket, {
|
|
1199
1265
|
type,
|
|
1200
1266
|
to,
|
|
1201
1267
|
...options.logicalTarget === undefined ? {} : { logicalTarget: options.logicalTarget },
|
|
1202
1268
|
...options.requirePendingReply === undefined ? {} : { requirePendingReply: options.requirePendingReply },
|
|
1269
|
+
...options.onReplyTarget === undefined ? {} : { resolveReplyTarget: true },
|
|
1203
1270
|
message,
|
|
1204
1271
|
attemptId: acquired.attempt.attemptId,
|
|
1205
1272
|
...extra
|
|
@@ -1207,6 +1274,10 @@ var init_client = __esm(() => {
|
|
|
1207
1274
|
} catch (error) {
|
|
1208
1275
|
this.pendingSends.reject(acquired.attempt, toError(error));
|
|
1209
1276
|
}
|
|
1277
|
+
const clearReplyTarget = () => {
|
|
1278
|
+
this.pendingReplyTargets.delete(acquired.attempt.attemptId);
|
|
1279
|
+
};
|
|
1280
|
+
acquired.attempt.promise.then(clearReplyTarget, clearReplyTarget);
|
|
1210
1281
|
return acquired.attempt.promise;
|
|
1211
1282
|
}
|
|
1212
1283
|
updatePresence(updates) {
|
|
@@ -1676,15 +1747,6 @@ class InlineMessageComponent {
|
|
|
1676
1747
|
}
|
|
1677
1748
|
var init_inline_message = () => {};
|
|
1678
1749
|
|
|
1679
|
-
// dist/builtin/intercom/retry-policy.ts
|
|
1680
|
-
var ASK_REPLY_TIMEOUT_MS, RETRY_IDENTITY_RETRY_OPPORTUNITY_MS, RETRY_IDENTITY_TTL_MS, DELIVERED_MESSAGE_TTL_MS;
|
|
1681
|
-
var init_retry_policy = __esm(() => {
|
|
1682
|
-
ASK_REPLY_TIMEOUT_MS = 10 * 60 * 1000;
|
|
1683
|
-
RETRY_IDENTITY_RETRY_OPPORTUNITY_MS = 60 * 1000;
|
|
1684
|
-
RETRY_IDENTITY_TTL_MS = ASK_REPLY_TIMEOUT_MS + RETRY_IDENTITY_RETRY_OPPORTUNITY_MS;
|
|
1685
|
-
DELIVERED_MESSAGE_TTL_MS = RETRY_IDENTITY_TTL_MS + RETRY_IDENTITY_RETRY_OPPORTUNITY_MS;
|
|
1686
|
-
});
|
|
1687
|
-
|
|
1688
1750
|
// dist/builtin/intercom/reply-waiter.ts
|
|
1689
1751
|
class ReplyWaiterRegistry {
|
|
1690
1752
|
timeoutMs;
|
|
@@ -1756,6 +1818,10 @@ class ReplyWaiterRegistry {
|
|
|
1756
1818
|
ok: true,
|
|
1757
1819
|
wait: {
|
|
1758
1820
|
promise,
|
|
1821
|
+
bindSender: (sender) => {
|
|
1822
|
+
if (this.waiters.get(replyTo) === record)
|
|
1823
|
+
record.from = sender;
|
|
1824
|
+
},
|
|
1759
1825
|
cancel: (error) => record.reject(error)
|
|
1760
1826
|
}
|
|
1761
1827
|
};
|
|
@@ -2264,32 +2330,32 @@ function validateSupervisorInterviewReply(value, interview) {
|
|
|
2264
2330
|
if (!Object.hasOwn(raw, "value")) {
|
|
2265
2331
|
throw new Error(`responses[${index}].value is required`);
|
|
2266
2332
|
}
|
|
2267
|
-
const
|
|
2333
|
+
const value = raw.value;
|
|
2268
2334
|
if (question.type === "single") {
|
|
2269
|
-
if (typeof
|
|
2335
|
+
if (typeof value !== "string")
|
|
2270
2336
|
throw new Error(`responses[${index}].value must be a string for single questions`);
|
|
2271
2337
|
const optionLabels = new Set(question.options?.map(interviewOptionLabel));
|
|
2272
|
-
if (!optionLabels.has(
|
|
2338
|
+
if (!optionLabels.has(value.trim()))
|
|
2273
2339
|
throw new Error(`responses[${index}].value must match one of the question options`);
|
|
2274
|
-
responses.push({ id, value:
|
|
2340
|
+
responses.push({ id, value: value.trim() });
|
|
2275
2341
|
continue;
|
|
2276
2342
|
}
|
|
2277
2343
|
if (question.type === "multi") {
|
|
2278
|
-
if (!Array.isArray(
|
|
2344
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
2279
2345
|
throw new Error(`responses[${index}].value must be an array of strings for multi questions`);
|
|
2280
2346
|
}
|
|
2281
2347
|
const optionLabels = new Set(question.options?.map(interviewOptionLabel));
|
|
2282
|
-
const selected =
|
|
2348
|
+
const selected = value.map((item) => item.trim());
|
|
2283
2349
|
const invalid = selected.find((item) => !optionLabels.has(item));
|
|
2284
2350
|
if (invalid)
|
|
2285
2351
|
throw new Error(`responses[${index}].value contains an option that is not in the question options: ${invalid}`);
|
|
2286
2352
|
responses.push({ id, value: selected });
|
|
2287
2353
|
continue;
|
|
2288
2354
|
}
|
|
2289
|
-
if (typeof
|
|
2355
|
+
if (typeof value !== "string") {
|
|
2290
2356
|
throw new Error(`responses[${index}].value must be a string for ${question.type} questions`);
|
|
2291
2357
|
}
|
|
2292
|
-
responses.push({ id, value
|
|
2358
|
+
responses.push({ id, value });
|
|
2293
2359
|
}
|
|
2294
2360
|
return { responses };
|
|
2295
2361
|
}
|
|
@@ -2371,7 +2437,8 @@ function formatSessionListRow(session, currentCwd, isSelf) {
|
|
|
2371
2437
|
const name = session.name || "Unnamed session";
|
|
2372
2438
|
const normalizedGroup = normalizeGroup(session.group);
|
|
2373
2439
|
const groupTag = normalizedGroup !== DEFAULT_GROUP ? `group: ${normalizedGroup}` : undefined;
|
|
2374
|
-
const
|
|
2440
|
+
const capabilityTag = session.replyCapability === undefined ? undefined : `replyCapability: ${session.replyCapability}`;
|
|
2441
|
+
const tags = [isSelf ? "self" : session.cwd === currentCwd ? "same cwd" : undefined, session.status, capabilityTag, groupTag].filter((tag) => Boolean(tag));
|
|
2375
2442
|
const suffix = tags.length ? ` [${tags.join(", ")}]` : "";
|
|
2376
2443
|
return `• ${name} (${session.id}) — ${session.cwd} (${session.model})${suffix}`;
|
|
2377
2444
|
}
|
|
@@ -2395,7 +2462,7 @@ import { randomUUID as randomUUID3 } from "crypto";
|
|
|
2395
2462
|
import { Type } from "typebox";
|
|
2396
2463
|
import { Text as Text2 } from "@earendil-works/pi-tui";
|
|
2397
2464
|
function registerContactSupervisorTool(pi, deps) {
|
|
2398
|
-
const { childOrchestratorMetadata, ensureConnected, syncPresenceIdentity, resolveSessionTarget
|
|
2465
|
+
const { childOrchestratorMetadata, ensureConnected, syncPresenceIdentity, resolveSessionTarget, beginReplyWait } = deps;
|
|
2399
2466
|
const getMetadata = typeof childOrchestratorMetadata === "function" ? childOrchestratorMetadata : () => childOrchestratorMetadata;
|
|
2400
2467
|
let supervisorWaitActive = false;
|
|
2401
2468
|
let supervisorHandoffClaimed = false;
|
|
@@ -2508,13 +2575,6 @@ function registerContactSupervisorTool(pi, deps) {
|
|
|
2508
2575
|
details: { yielded: true }
|
|
2509
2576
|
};
|
|
2510
2577
|
}
|
|
2511
|
-
if (reason === "need_decision" && typeof params.message !== "string") {
|
|
2512
|
-
return {
|
|
2513
|
-
content: [{ type: "text", text: `Missing 'message' parameter for reason '${reason}'.` }],
|
|
2514
|
-
isError: true,
|
|
2515
|
-
details: { error: true }
|
|
2516
|
-
};
|
|
2517
|
-
}
|
|
2518
2578
|
let connectedClient;
|
|
2519
2579
|
try {
|
|
2520
2580
|
connectedClient = await ensureConnected("tool");
|
|
@@ -2538,7 +2598,7 @@ function registerContactSupervisorTool(pi, deps) {
|
|
|
2538
2598
|
sendTo = connectedClient.supervisorSessionId ?? metadata.supervisor.supervisorSessionId;
|
|
2539
2599
|
} else {
|
|
2540
2600
|
try {
|
|
2541
|
-
sendTo = await
|
|
2601
|
+
sendTo = await resolveSessionTarget(connectedClient, metadata.orchestratorTarget) ?? metadata.orchestratorTarget;
|
|
2542
2602
|
} catch (error) {
|
|
2543
2603
|
return {
|
|
2544
2604
|
content: [{ type: "text", text: `Failed to resolve supervisor target: ${getErrorMessage(error)}` }],
|
|
@@ -2607,7 +2667,7 @@ function registerContactSupervisorTool(pi, deps) {
|
|
|
2607
2667
|
};
|
|
2608
2668
|
}
|
|
2609
2669
|
wait = admission.wait;
|
|
2610
|
-
const requestText = reason === "interview_request" ? formatChildOrchestratorMessage("interview", metadata, formatSupervisorInterviewRequest(supervisorInterview, typeof params.message === "string" ? params.message : undefined)) : formatChildOrchestratorMessage("ask", metadata, params.message);
|
|
2670
|
+
const requestText = reason === "interview_request" ? formatChildOrchestratorMessage("interview", metadata, formatSupervisorInterviewRequest(supervisorInterview, typeof params.message === "string" ? params.message : undefined)) : formatChildOrchestratorMessage("ask", metadata, typeof params.message === "string" ? params.message : "");
|
|
2611
2671
|
const sendResult = await connectedClient.sendToSupervisor(sendTo, {
|
|
2612
2672
|
messageId: questionId,
|
|
2613
2673
|
text: requestText,
|
|
@@ -2808,6 +2868,11 @@ class RetryIdentityReservations {
|
|
|
2808
2868
|
}
|
|
2809
2869
|
this.finishRetained(reservation, "settled");
|
|
2810
2870
|
}
|
|
2871
|
+
discard(retryToken) {
|
|
2872
|
+
const reservation = this.tokenReservations.get(retryToken);
|
|
2873
|
+
if (reservation !== undefined)
|
|
2874
|
+
this.expire(reservation);
|
|
2875
|
+
}
|
|
2811
2876
|
remainingRetries(attempt) {
|
|
2812
2877
|
const reservation = this.currentReservation(attempt);
|
|
2813
2878
|
return reservation === undefined ? 0 : Math.max(0, this.maxReuses - reservation.reuseCount);
|
|
@@ -2961,14 +3026,73 @@ var init_retry_identity = __esm(() => {
|
|
|
2961
3026
|
};
|
|
2962
3027
|
});
|
|
2963
3028
|
|
|
3029
|
+
// dist/builtin/intercom/tool-retry.ts
|
|
3030
|
+
import { setTimeout as delay2 } from "node:timers/promises";
|
|
3031
|
+
async function runIntercomOperation(attempt, release, signal) {
|
|
3032
|
+
const deadline = new AbortController;
|
|
3033
|
+
const timer = setTimeout(() => deadline.abort(), RETRY_IDENTITY_TTL_MS);
|
|
3034
|
+
const operationSignal = signal === undefined ? deadline.signal : AbortSignal.any([signal, deadline.signal]);
|
|
3035
|
+
let token;
|
|
3036
|
+
let recovering = false;
|
|
3037
|
+
let retries = 0;
|
|
3038
|
+
let last = {
|
|
3039
|
+
content: [{ type: "text", text: "Cancelled" }],
|
|
3040
|
+
isError: true,
|
|
3041
|
+
details: { error: true }
|
|
3042
|
+
};
|
|
3043
|
+
try {
|
|
3044
|
+
for (;; ) {
|
|
3045
|
+
if (operationSignal.aborted)
|
|
3046
|
+
break;
|
|
3047
|
+
last = await attempt(token, operationSignal);
|
|
3048
|
+
const { retryToken, retryable, deliveryUncertain, ...details } = last.details;
|
|
3049
|
+
last = { ...last, details };
|
|
3050
|
+
if (!last.isError)
|
|
3051
|
+
return last;
|
|
3052
|
+
recovering ||= deliveryUncertain === true || retryable === true;
|
|
3053
|
+
const nextToken = typeof retryToken === "string" ? retryToken : undefined;
|
|
3054
|
+
const canRetry = nextToken !== undefined || token === undefined && retryable === true;
|
|
3055
|
+
token = nextToken ?? token;
|
|
3056
|
+
if (!canRetry) {
|
|
3057
|
+
if (!recovering && retryable !== true)
|
|
3058
|
+
return last;
|
|
3059
|
+
break;
|
|
3060
|
+
}
|
|
3061
|
+
recovering = true;
|
|
3062
|
+
if (retries >= RETRY_IDENTITY_MAX_REUSES || operationSignal.aborted)
|
|
3063
|
+
break;
|
|
3064
|
+
try {
|
|
3065
|
+
await delay2(RECONNECT_DELAYS_MS[retries], undefined, { signal: operationSignal });
|
|
3066
|
+
} catch {
|
|
3067
|
+
break;
|
|
3068
|
+
}
|
|
3069
|
+
retries += 1;
|
|
3070
|
+
}
|
|
3071
|
+
const reason = operationSignal.aborted ? "Cancelled" : last.content.map(({ text }) => text).join(`
|
|
3072
|
+
`);
|
|
3073
|
+
return {
|
|
3074
|
+
content: [{
|
|
3075
|
+
type: "text",
|
|
3076
|
+
text: recovering ? `${reason}
|
|
3077
|
+
Intercom recovery stopped after ${retries} automatic retries. Delivery may already have occurred. Do not repeat this operation automatically; check with the recipient before intentionally sending a new message.` : reason
|
|
3078
|
+
}],
|
|
3079
|
+
isError: true,
|
|
3080
|
+
details: { error: true, terminal: true, automaticRetries: retries, ...recovering ? { outcome: "unknown" } : {} }
|
|
3081
|
+
};
|
|
3082
|
+
} finally {
|
|
3083
|
+
clearTimeout(timer);
|
|
3084
|
+
if (token !== undefined)
|
|
3085
|
+
release(token);
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
var init_tool_retry = __esm(() => {
|
|
3089
|
+
init_retry_identity();
|
|
3090
|
+
init_retry_policy();
|
|
3091
|
+
});
|
|
3092
|
+
|
|
2964
3093
|
// dist/builtin/intercom/intercom-tool.ts
|
|
2965
3094
|
import { Type as Type2 } from "typebox";
|
|
2966
3095
|
import { Text as Text3 } from "@earendil-works/pi-tui";
|
|
2967
|
-
function retryTokenGuidance(retryToken, remainingRetries) {
|
|
2968
|
-
if (retryToken === undefined)
|
|
2969
|
-
return "";
|
|
2970
|
-
return ` Retry this exact operation with retryToken \`${retryToken}\` (${remainingRetries} claimed ${remainingRetries === 1 ? "attempt" : "attempts"} remain; the original deadline is unchanged).`;
|
|
2971
|
-
}
|
|
2972
3096
|
function retryErrorDetails(retryToken) {
|
|
2973
3097
|
return retryToken === undefined ? { error: true } : { error: true, retryToken };
|
|
2974
3098
|
}
|
|
@@ -3086,7 +3210,7 @@ A valid target outside the known set queues speculatively with a \`notInKnownSet
|
|
|
3086
3210
|
undeliverable at terminal only if never delivered. Use \`ask\` only for a live, reply-capable target.
|
|
3087
3211
|
Stage paths win over same-named owned subgroups for send/ask; \`list\` with \`group\` continues to
|
|
3088
3212
|
select the group.
|
|
3089
|
-
|
|
3213
|
+
For send/ask/reply, Intercom retries recoverable disconnects internally up to three times with the same operation identity. Each new tool call is a new operation. If recovery ends with an unknown delivery outcome, do not repeat it automatically.
|
|
3090
3214
|
|
|
3091
3215
|
Usage:
|
|
3092
3216
|
intercom({ action: "list" }) → List sessions visible through your groups
|
|
@@ -3098,14 +3222,13 @@ Usage:
|
|
|
3098
3222
|
intercom({ action: "send", to: "session-name", message: "..." }) → Send message (shared group only)
|
|
3099
3223
|
intercom({ action: "ask", to: "session-name", message: "..." }) → Ask and wait for reply
|
|
3100
3224
|
intercom({ action: "reply", message: "..." }) → Reply to the active or exact pending ask
|
|
3101
|
-
intercom({ action: "send", to: "session-name", message: "...", retryToken: "..." }) → Claim the exact retry returned by a retryable failure
|
|
3102
3225
|
intercom({ action: "pending" }) → List unresolved inbound asks
|
|
3103
3226
|
intercom({ action: "status" }) → Show connection status and all your groups
|
|
3104
3227
|
|
|
3105
3228
|
The "join" action is additive. "default" is the shared default group; "true" and
|
|
3106
3229
|
"auto" are reserved for subagent auto-groups. Ordinary delivery requires at least
|
|
3107
3230
|
one shared membership; contact_supervisor remains the only cross-group path.`,
|
|
3108
|
-
promptSnippet: "Use to coordinate with other local agent sessions that share an intercom group.
|
|
3231
|
+
promptSnippet: "Use to coordinate with other local agent sessions that share an intercom group. Send/ask/reply retry reconnects internally; do not automatically repeat an unknown delivery outcome.",
|
|
3109
3232
|
parameters: Type2.Object({
|
|
3110
3233
|
action: Type2.String({
|
|
3111
3234
|
description: "Action: 'list', 'groups', 'join', 'leave', 'send', 'ask', 'reply', 'pending', or 'status'"
|
|
@@ -3125,78 +3248,25 @@ one shared membership; contact_supervisor remains the only cross-group path.`,
|
|
|
3125
3248
|
replyTo: Type2.Optional(Type2.String({
|
|
3126
3249
|
description: "Exact pending-ask message ID; disambiguates concurrent asks, including asks from one sender"
|
|
3127
3250
|
})),
|
|
3128
|
-
retryToken: Type2.Optional(Type2.String({
|
|
3129
|
-
minLength: 1,
|
|
3130
|
-
maxLength: 128,
|
|
3131
|
-
description: "Opaque token returned after a retryable send/ask/reply failure. Repeat the exact same action and arguments with this token; omit it for every fresh operation."
|
|
3132
|
-
})),
|
|
3133
3251
|
group: Type2.Optional(Type2.String({
|
|
3134
3252
|
description: "Group name for 'join' or optional targeted 'leave'; read-only group filter for 'list'/'status'. 'send'/'ask' use shared memberships."
|
|
3135
3253
|
}))
|
|
3136
3254
|
}),
|
|
3137
|
-
async execute(_toolCallId, params,
|
|
3138
|
-
|
|
3139
|
-
const { action, to, message, attachments, replyTo, retryToken, group } = params;
|
|
3140
|
-
let retryPreflightRemaining;
|
|
3141
|
-
if (retryToken !== undefined) {
|
|
3142
|
-
if (action !== "send" && action !== "ask" && action !== "reply") {
|
|
3143
|
-
const error = new RetryTokenError("mismatch");
|
|
3144
|
-
return {
|
|
3145
|
-
content: [{ type: "text", text: getErrorMessage(error) }],
|
|
3146
|
-
isError: true,
|
|
3147
|
-
details: { error: true }
|
|
3148
|
-
};
|
|
3149
|
-
}
|
|
3150
|
-
try {
|
|
3151
|
-
retryPreflightRemaining = retryIdentities.validateRetryToken(retryToken, toolSessionId, action);
|
|
3152
|
-
} catch (error) {
|
|
3153
|
-
return {
|
|
3154
|
-
content: [{ type: "text", text: getErrorMessage(error) }],
|
|
3155
|
-
isError: true,
|
|
3156
|
-
details: { error: true }
|
|
3157
|
-
};
|
|
3158
|
-
}
|
|
3159
|
-
}
|
|
3160
|
-
let connectedClient;
|
|
3161
|
-
try {
|
|
3162
|
-
connectedClient = await ensureConnected("tool");
|
|
3163
|
-
} catch (error) {
|
|
3164
|
-
const retainedToken = retryToken !== undefined && isRecoverableIntercomDisconnect(error) ? retryToken : undefined;
|
|
3255
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
3256
|
+
if ("retryToken" in params) {
|
|
3165
3257
|
return {
|
|
3166
|
-
content: [{
|
|
3167
|
-
type: "text",
|
|
3168
|
-
text: `Intercom not connected: ${getErrorMessage(error)}${retryTokenGuidance(retainedToken, retryPreflightRemaining ?? 0)}`
|
|
3169
|
-
}],
|
|
3258
|
+
content: [{ type: "text", text: "Intercom manages retries internally. Caller-supplied retry tokens are not supported; this call was not sent." }],
|
|
3170
3259
|
isError: true,
|
|
3171
|
-
details:
|
|
3260
|
+
details: { error: true }
|
|
3172
3261
|
};
|
|
3173
3262
|
}
|
|
3174
|
-
|
|
3175
|
-
const
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
};
|
|
3182
|
-
const isOnlyOwnGroup = (candidate, ownGroups) => candidate !== undefined && ownGroups.length === 1 && ownGroups[0] === candidate;
|
|
3183
|
-
const requestedGroup = typeof group === "string" && group.trim() ? normalizeGroup(group) : undefined;
|
|
3184
|
-
if ((action === "send" || action === "ask") && requestedGroup) {
|
|
3185
|
-
const ownGroups = resolveOwnGroups();
|
|
3186
|
-
if (!ownGroups.includes(requestedGroup)) {
|
|
3187
|
-
return {
|
|
3188
|
-
content: [{ type: "text", text: `The 'group' parameter is read-only for 'list'/'status'. '${action}' is always locked to your groups (${ownGroups.join(", ")}); it cannot target group "${requestedGroup}".` }],
|
|
3189
|
-
isError: true,
|
|
3190
|
-
details: { error: true }
|
|
3191
|
-
};
|
|
3192
|
-
}
|
|
3193
|
-
}
|
|
3194
|
-
switch (action) {
|
|
3195
|
-
case "join": {
|
|
3196
|
-
let targetGroup;
|
|
3197
|
-
try {
|
|
3198
|
-
targetGroup = validateRuntimeGroup(group);
|
|
3199
|
-
} catch (error) {
|
|
3263
|
+
const toolSessionId = ctx.sessionManager.getSessionId();
|
|
3264
|
+
const { action, to, message, replyTo, group } = params;
|
|
3265
|
+
const attachments = params.attachments?.map((attachment) => ({ ...attachment }));
|
|
3266
|
+
const executeAttempt = async (retryToken, _signal) => {
|
|
3267
|
+
if (retryToken !== undefined) {
|
|
3268
|
+
if (action !== "send" && action !== "ask" && action !== "reply") {
|
|
3269
|
+
const error = new RetryTokenError("mismatch");
|
|
3200
3270
|
return {
|
|
3201
3271
|
content: [{ type: "text", text: getErrorMessage(error) }],
|
|
3202
3272
|
isError: true,
|
|
@@ -3204,174 +3274,256 @@ one shared membership; contact_supervisor remains the only cross-group path.`,
|
|
|
3204
3274
|
};
|
|
3205
3275
|
}
|
|
3206
3276
|
try {
|
|
3207
|
-
|
|
3208
|
-
deps.setJoinedGroups(groups);
|
|
3209
|
-
return {
|
|
3210
|
-
content: [{ type: "text", text: `Joined intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.` }],
|
|
3211
|
-
isError: false,
|
|
3212
|
-
details: { group: targetGroup, groups }
|
|
3213
|
-
};
|
|
3277
|
+
retryIdentities.validateRetryToken(retryToken, toolSessionId, action);
|
|
3214
3278
|
} catch (error) {
|
|
3215
3279
|
return {
|
|
3216
|
-
content: [{ type: "text", text:
|
|
3280
|
+
content: [{ type: "text", text: getErrorMessage(error) }],
|
|
3217
3281
|
isError: true,
|
|
3218
3282
|
details: { error: true }
|
|
3219
3283
|
};
|
|
3220
3284
|
}
|
|
3221
3285
|
}
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3286
|
+
let connectedClient;
|
|
3287
|
+
try {
|
|
3288
|
+
connectedClient = await ensureConnected("tool");
|
|
3289
|
+
} catch (error) {
|
|
3290
|
+
const retainedToken = retryToken !== undefined && isRecoverableIntercomDisconnect(error) ? retryToken : undefined;
|
|
3291
|
+
return {
|
|
3292
|
+
content: [{
|
|
3293
|
+
type: "text",
|
|
3294
|
+
text: `Intercom not connected: ${getErrorMessage(error)}`
|
|
3295
|
+
}],
|
|
3296
|
+
isError: true,
|
|
3297
|
+
details: { ...retryErrorDetails(retainedToken), retryable: isRecoverableIntercomDisconnect(error) }
|
|
3298
|
+
};
|
|
3299
|
+
}
|
|
3300
|
+
syncPresenceIdentity(toolSessionId);
|
|
3301
|
+
const resolveOwnGroups = (sessions) => {
|
|
3302
|
+
if (Array.isArray(connectedClient.groups)) {
|
|
3303
|
+
return connectedClient.groups.map((membership) => normalizeGroup(membership));
|
|
3304
|
+
}
|
|
3305
|
+
const self = sessions?.find((session) => session.id === connectedClient.sessionId);
|
|
3306
|
+
return [...normalizeGroups(self?.groups, self?.group)];
|
|
3307
|
+
};
|
|
3308
|
+
const isOnlyOwnGroup = (candidate, ownGroups) => candidate !== undefined && ownGroups.length === 1 && ownGroups[0] === candidate;
|
|
3309
|
+
const requestedGroup = typeof group === "string" && group.trim() ? normalizeGroup(group) : undefined;
|
|
3310
|
+
if ((action === "send" || action === "ask") && requestedGroup) {
|
|
3311
|
+
const ownGroups = resolveOwnGroups();
|
|
3312
|
+
if (!ownGroups.includes(requestedGroup)) {
|
|
3230
3313
|
return {
|
|
3231
|
-
content: [{ type: "text", text: `
|
|
3314
|
+
content: [{ type: "text", text: `The 'group' parameter is read-only for 'list'/'status'. '${action}' is always locked to your groups (${ownGroups.join(", ")}); it cannot target group "${requestedGroup}".` }],
|
|
3232
3315
|
isError: true,
|
|
3233
3316
|
details: { error: true }
|
|
3234
3317
|
};
|
|
3235
3318
|
}
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3319
|
+
}
|
|
3320
|
+
switch (action) {
|
|
3321
|
+
case "join": {
|
|
3322
|
+
let targetGroup;
|
|
3323
|
+
try {
|
|
3324
|
+
targetGroup = validateRuntimeGroup(group);
|
|
3325
|
+
} catch (error) {
|
|
3326
|
+
return {
|
|
3327
|
+
content: [{ type: "text", text: getErrorMessage(error) }],
|
|
3328
|
+
isError: true,
|
|
3329
|
+
details: { error: true }
|
|
3330
|
+
};
|
|
3331
|
+
}
|
|
3332
|
+
try {
|
|
3333
|
+
const groups = await connectedClient.joinGroup(targetGroup);
|
|
3246
3334
|
deps.setJoinedGroups(groups);
|
|
3335
|
+
return {
|
|
3336
|
+
content: [{ type: "text", text: `Joined intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.` }],
|
|
3337
|
+
isError: false,
|
|
3338
|
+
details: { group: targetGroup, groups }
|
|
3339
|
+
};
|
|
3340
|
+
} catch (error) {
|
|
3341
|
+
return {
|
|
3342
|
+
content: [{ type: "text", text: `Failed to join group: ${getErrorMessage(error)}` }],
|
|
3343
|
+
isError: true,
|
|
3344
|
+
details: { error: true }
|
|
3345
|
+
};
|
|
3247
3346
|
}
|
|
3248
|
-
const text = targetGroup === undefined ? `Returned to home intercom membership. Memberships: ${groups.join(", ")}.` : `Left intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.`;
|
|
3249
|
-
return {
|
|
3250
|
-
content: [{ type: "text", text }],
|
|
3251
|
-
isError: false,
|
|
3252
|
-
details: targetGroup === undefined ? { group: homeGroup, groups } : { groups }
|
|
3253
|
-
};
|
|
3254
|
-
} catch (error) {
|
|
3255
|
-
return {
|
|
3256
|
-
content: [{ type: "text", text: `Failed to leave group: ${getErrorMessage(error)}` }],
|
|
3257
|
-
isError: true,
|
|
3258
|
-
details: { error: true }
|
|
3259
|
-
};
|
|
3260
3347
|
}
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3348
|
+
case "leave": {
|
|
3349
|
+
let targetGroup;
|
|
3350
|
+
let homeGroup;
|
|
3351
|
+
try {
|
|
3352
|
+
targetGroup = typeof group === "string" && group.trim().length > 0 ? validateRuntimeGroup(group) : undefined;
|
|
3353
|
+
if (targetGroup === undefined)
|
|
3354
|
+
homeGroup = validateRuntimeGroup(deps.homeGroup());
|
|
3355
|
+
} catch (error) {
|
|
3356
|
+
return {
|
|
3357
|
+
content: [{ type: "text", text: `Cannot leave intercom group: ${getErrorMessage(error)}` }],
|
|
3358
|
+
isError: true,
|
|
3359
|
+
details: { error: true }
|
|
3360
|
+
};
|
|
3361
|
+
}
|
|
3362
|
+
try {
|
|
3363
|
+
let groups;
|
|
3364
|
+
if (targetGroup === undefined) {
|
|
3365
|
+
if (homeGroup === undefined)
|
|
3366
|
+
throw new Error("Intercom home group is unavailable");
|
|
3367
|
+
await connectedClient.updatePresenceAcked({ groups: [homeGroup] });
|
|
3368
|
+
groups = connectedClient.groups;
|
|
3369
|
+
deps.clearJoinedGroups();
|
|
3370
|
+
} else {
|
|
3371
|
+
groups = await connectedClient.leaveGroup(targetGroup);
|
|
3372
|
+
deps.setJoinedGroups(groups);
|
|
3373
|
+
}
|
|
3374
|
+
const text = targetGroup === undefined ? `Returned to home intercom membership. Memberships: ${groups.join(", ")}.` : `Left intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.`;
|
|
3375
|
+
return {
|
|
3376
|
+
content: [{ type: "text", text }],
|
|
3377
|
+
isError: false,
|
|
3378
|
+
details: targetGroup === undefined ? { group: homeGroup, groups } : { groups }
|
|
3379
|
+
};
|
|
3380
|
+
} catch (error) {
|
|
3381
|
+
return {
|
|
3382
|
+
content: [{ type: "text", text: `Failed to leave group: ${getErrorMessage(error)}` }],
|
|
3383
|
+
isError: true,
|
|
3384
|
+
details: { error: true }
|
|
3385
|
+
};
|
|
3386
|
+
}
|
|
3387
|
+
}
|
|
3388
|
+
case "groups": {
|
|
3389
|
+
try {
|
|
3390
|
+
const groups = await connectedClient.listGroups();
|
|
3391
|
+
const lines = groups.map(({ group: groupName, sessionCount, member }) => `- ${groupName} — ${sessionCount} session${sessionCount === 1 ? "" : "s"}${member ? " [member]" : ""}`);
|
|
3392
|
+
return {
|
|
3393
|
+
content: [{ type: "text", text: `**Intercom groups:**
|
|
3268
3394
|
${lines.join(`
|
|
3269
3395
|
`)}` }],
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
return {
|
|
3275
|
-
content: [{ type: "text", text: `Failed to list groups: ${getErrorMessage(error)}` }],
|
|
3276
|
-
isError: true,
|
|
3277
|
-
details: { error: true }
|
|
3278
|
-
};
|
|
3279
|
-
}
|
|
3280
|
-
}
|
|
3281
|
-
case "list": {
|
|
3282
|
-
try {
|
|
3283
|
-
const mySessionId = connectedClient.sessionId;
|
|
3284
|
-
const ownDirectory = await listDirectory(connectedClient);
|
|
3285
|
-
const ownSessions = ownDirectory.sessions;
|
|
3286
|
-
const currentSession = ownSessions.find((session) => session.id === mySessionId);
|
|
3287
|
-
if (!currentSession) {
|
|
3396
|
+
isError: false,
|
|
3397
|
+
details: { groups }
|
|
3398
|
+
};
|
|
3399
|
+
} catch (error) {
|
|
3288
3400
|
return {
|
|
3289
|
-
content: [{ type: "text", text:
|
|
3401
|
+
content: [{ type: "text", text: `Failed to list groups: ${getErrorMessage(error)}` }],
|
|
3290
3402
|
isError: true,
|
|
3291
3403
|
details: { error: true }
|
|
3292
3404
|
};
|
|
3293
3405
|
}
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
const
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3406
|
+
}
|
|
3407
|
+
case "list": {
|
|
3408
|
+
try {
|
|
3409
|
+
const mySessionId = connectedClient.sessionId;
|
|
3410
|
+
const ownDirectory = await listDirectory(connectedClient);
|
|
3411
|
+
const ownSessions = ownDirectory.sessions;
|
|
3412
|
+
const currentSession = ownSessions.find((session) => session.id === mySessionId);
|
|
3413
|
+
if (!currentSession) {
|
|
3414
|
+
return {
|
|
3415
|
+
content: [{ type: "text", text: "Current session is missing from intercom session list." }],
|
|
3416
|
+
isError: true,
|
|
3417
|
+
details: { error: true }
|
|
3418
|
+
};
|
|
3419
|
+
}
|
|
3420
|
+
const ownGroups = resolveOwnGroups(ownSessions);
|
|
3421
|
+
if (requestedGroup && !isOnlyOwnGroup(requestedGroup, ownGroups)) {
|
|
3422
|
+
const peeked = await listDirectory(connectedClient, requestedGroup);
|
|
3423
|
+
const rows = [
|
|
3424
|
+
...peeked.sessions.map((session) => formatSessionListRow(session, currentSession.cwd, session.id === mySessionId)),
|
|
3425
|
+
...peeked.workflowStages.map(formatWorkflowStageRow),
|
|
3426
|
+
...(peeked.workflowFutureStages ?? []).map(formatWorkflowFutureStageRow)
|
|
3427
|
+
];
|
|
3428
|
+
const section = rows.length === 0 ? `**Group [${requestedGroup}] (read-only peek):**
|
|
3303
3429
|
No sessions or workflow stages in this group.` : `**Group [${requestedGroup}] (read-only peek):**
|
|
3304
3430
|
${rows.join(`
|
|
3305
3431
|
`)}`;
|
|
3306
|
-
|
|
3307
|
-
|
|
3432
|
+
return {
|
|
3433
|
+
content: [{ type: "text", text: `Your groups: ${ownGroups.join(", ")}
|
|
3308
3434
|
|
|
3309
3435
|
${section}` }],
|
|
3436
|
+
isError: false,
|
|
3437
|
+
details: {
|
|
3438
|
+
group: ownGroups.at(-1),
|
|
3439
|
+
groups: ownGroups,
|
|
3440
|
+
peekGroup: requestedGroup,
|
|
3441
|
+
workflowStages: peeked.workflowStages,
|
|
3442
|
+
...(peeked.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: peeked.workflowFutureStages }
|
|
3443
|
+
}
|
|
3444
|
+
};
|
|
3445
|
+
}
|
|
3446
|
+
const otherSessions = ownSessions.filter((session) => session.id !== mySessionId);
|
|
3447
|
+
const currentSection = `**Current session** (groups: ${ownGroups.join(", ")}):
|
|
3448
|
+
${formatSessionListRow(currentSession, currentSession.cwd, true)}`;
|
|
3449
|
+
const visibleRows = [
|
|
3450
|
+
...otherSessions.map((session) => formatSessionListRow(session, currentSession.cwd, false)),
|
|
3451
|
+
...ownDirectory.workflowStages.map(formatWorkflowStageRow),
|
|
3452
|
+
...(ownDirectory.workflowFutureStages ?? []).map(formatWorkflowFutureStageRow)
|
|
3453
|
+
];
|
|
3454
|
+
const otherSection = visibleRows.length === 0 ? `**Other sessions and workflow stages:**
|
|
3455
|
+
No other sessions or workflow stages share any of your groups.` : `**Other visible sessions and workflow stages:**
|
|
3456
|
+
${visibleRows.join(`
|
|
3457
|
+
`)}`;
|
|
3458
|
+
return {
|
|
3459
|
+
content: [{ type: "text", text: `${currentSection}
|
|
3460
|
+
|
|
3461
|
+
${otherSection}` }],
|
|
3310
3462
|
isError: false,
|
|
3311
3463
|
details: {
|
|
3312
3464
|
group: ownGroups.at(-1),
|
|
3313
3465
|
groups: ownGroups,
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
...(peeked.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: peeked.workflowFutureStages }
|
|
3466
|
+
...ownDirectory.workflowStages.length === 0 ? {} : { workflowStages: ownDirectory.workflowStages },
|
|
3467
|
+
...(ownDirectory.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: ownDirectory.workflowFutureStages }
|
|
3317
3468
|
}
|
|
3318
3469
|
};
|
|
3470
|
+
} catch (error) {
|
|
3471
|
+
return {
|
|
3472
|
+
content: [{ type: "text", text: `Failed to list sessions: ${getErrorMessage(error)}` }],
|
|
3473
|
+
isError: true,
|
|
3474
|
+
details: { error: true }
|
|
3475
|
+
};
|
|
3319
3476
|
}
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3477
|
+
}
|
|
3478
|
+
case "send": {
|
|
3479
|
+
if (!to || !message) {
|
|
3480
|
+
const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
|
|
3481
|
+
return {
|
|
3482
|
+
content: [{ type: "text", text: errorText }],
|
|
3483
|
+
isError: true,
|
|
3484
|
+
details: { error: true }
|
|
3485
|
+
};
|
|
3486
|
+
}
|
|
3487
|
+
if (_signal?.aborted) {
|
|
3488
|
+
return {
|
|
3489
|
+
content: [{
|
|
3490
|
+
type: "text",
|
|
3491
|
+
text: "Cancelled"
|
|
3492
|
+
}],
|
|
3493
|
+
isError: true,
|
|
3494
|
+
details: retryErrorDetails(retryToken)
|
|
3495
|
+
};
|
|
3496
|
+
}
|
|
3497
|
+
let retryIdentity;
|
|
3498
|
+
try {
|
|
3499
|
+
if (retryToken === undefined) {
|
|
3500
|
+
retryIdentity = retryIdentities.begin({
|
|
3501
|
+
sessionId: toolSessionId,
|
|
3502
|
+
action: "send",
|
|
3503
|
+
target: to,
|
|
3504
|
+
text: message,
|
|
3505
|
+
attachments,
|
|
3506
|
+
replyTo,
|
|
3507
|
+
expectsReply: false
|
|
3508
|
+
});
|
|
3509
|
+
}
|
|
3510
|
+
if (retryToken === undefined && !replyTo && deps.confirmSend && ctx.hasUI) {
|
|
3511
|
+
const attachmentText = attachments?.length ? formatAttachments(attachments) : "";
|
|
3512
|
+
const confirmed = await ctx.ui.confirm("Send Message", `Send to "${to}":
|
|
3334
3513
|
|
|
3335
|
-
${
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3514
|
+
${message}${attachmentText}`);
|
|
3515
|
+
if (!confirmed) {
|
|
3516
|
+
if (retryIdentity !== undefined)
|
|
3517
|
+
retryIdentities.release(retryIdentity);
|
|
3518
|
+
retryIdentity = undefined;
|
|
3519
|
+
return {
|
|
3520
|
+
content: [{ type: "text", text: "Message cancelled by user" }],
|
|
3521
|
+
isError: false,
|
|
3522
|
+
details: {}
|
|
3523
|
+
};
|
|
3524
|
+
}
|
|
3342
3525
|
}
|
|
3343
|
-
|
|
3344
|
-
} catch (error) {
|
|
3345
|
-
return {
|
|
3346
|
-
content: [{ type: "text", text: `Failed to list sessions: ${getErrorMessage(error)}` }],
|
|
3347
|
-
isError: true,
|
|
3348
|
-
details: { error: true }
|
|
3349
|
-
};
|
|
3350
|
-
}
|
|
3351
|
-
}
|
|
3352
|
-
case "send": {
|
|
3353
|
-
if (!to || !message) {
|
|
3354
|
-
const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
|
|
3355
|
-
return {
|
|
3356
|
-
content: [{ type: "text", text: errorText }],
|
|
3357
|
-
isError: true,
|
|
3358
|
-
details: { error: true }
|
|
3359
|
-
};
|
|
3360
|
-
}
|
|
3361
|
-
if (_signal?.aborted) {
|
|
3362
|
-
return {
|
|
3363
|
-
content: [{
|
|
3364
|
-
type: "text",
|
|
3365
|
-
text: `Cancelled${retryTokenGuidance(retryToken, retryPreflightRemaining ?? 0)}`
|
|
3366
|
-
}],
|
|
3367
|
-
isError: true,
|
|
3368
|
-
details: retryErrorDetails(retryToken)
|
|
3369
|
-
};
|
|
3370
|
-
}
|
|
3371
|
-
let retryIdentity;
|
|
3372
|
-
try {
|
|
3373
|
-
if (retryToken === undefined) {
|
|
3374
|
-
retryIdentity = retryIdentities.begin({
|
|
3526
|
+
retryIdentity ??= retryIdentities.begin({
|
|
3375
3527
|
sessionId: toolSessionId,
|
|
3376
3528
|
action: "send",
|
|
3377
3529
|
target: to,
|
|
@@ -3379,63 +3531,79 @@ ${otherSection}` }],
|
|
|
3379
3531
|
attachments,
|
|
3380
3532
|
replyTo,
|
|
3381
3533
|
expectsReply: false
|
|
3534
|
+
}, retryToken);
|
|
3535
|
+
const sendTo = await resolveTarget(connectedClient, to) ?? to;
|
|
3536
|
+
if (_signal?.aborted) {
|
|
3537
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3538
|
+
retryIdentity = undefined;
|
|
3539
|
+
return {
|
|
3540
|
+
content: [{ type: "text", text: "Cancelled" }],
|
|
3541
|
+
isError: true,
|
|
3542
|
+
details: retryErrorDetails(retained.retryToken)
|
|
3543
|
+
};
|
|
3544
|
+
}
|
|
3545
|
+
if (sendTo === connectedClient.sessionId) {
|
|
3546
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3547
|
+
retryIdentity = undefined;
|
|
3548
|
+
return {
|
|
3549
|
+
content: [{
|
|
3550
|
+
type: "text",
|
|
3551
|
+
text: "Cannot message the current session"
|
|
3552
|
+
}],
|
|
3553
|
+
isError: true,
|
|
3554
|
+
details: retryErrorDetails(retained.retryToken)
|
|
3555
|
+
};
|
|
3556
|
+
}
|
|
3557
|
+
const result = await connectedClient.send(sendTo, {
|
|
3558
|
+
messageId: retryIdentity.messageId,
|
|
3559
|
+
logicalTarget: to,
|
|
3560
|
+
text: message,
|
|
3561
|
+
attachments,
|
|
3562
|
+
replyTo
|
|
3382
3563
|
});
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
const attachmentText = attachments?.length ? formatAttachments(attachments) : "";
|
|
3386
|
-
const confirmed = await ctx.ui.confirm("Send Message", `Send to "${to}":
|
|
3387
|
-
|
|
3388
|
-
${message}${attachmentText}`);
|
|
3389
|
-
if (!confirmed) {
|
|
3390
|
-
if (retryIdentity !== undefined)
|
|
3391
|
-
retryIdentities.release(retryIdentity);
|
|
3564
|
+
if (result.queued === true) {
|
|
3565
|
+
retryIdentities.release(retryIdentity);
|
|
3392
3566
|
retryIdentity = undefined;
|
|
3567
|
+
pi.appendEntry("intercom_sent", {
|
|
3568
|
+
to,
|
|
3569
|
+
message: { text: message, attachments, replyTo },
|
|
3570
|
+
messageId: result.id,
|
|
3571
|
+
timestamp: Date.now()
|
|
3572
|
+
});
|
|
3573
|
+
const notInKnownSet = result.notInKnownSet === true;
|
|
3393
3574
|
return {
|
|
3394
|
-
content: [{
|
|
3575
|
+
content: [{
|
|
3576
|
+
type: "text",
|
|
3577
|
+
text: notInKnownSet ? `Message queued for ${to} (not in the workflow's known stage set; it will be delivered to every matching stage that starts before the run terminates)` : `Message queued for ${to}`
|
|
3578
|
+
}],
|
|
3395
3579
|
isError: false,
|
|
3396
|
-
details: {
|
|
3580
|
+
details: {
|
|
3581
|
+
messageId: result.id,
|
|
3582
|
+
delivered: false,
|
|
3583
|
+
queued: true,
|
|
3584
|
+
target: result.target,
|
|
3585
|
+
position: result.position,
|
|
3586
|
+
...notInKnownSet ? { notInKnownSet: true } : {}
|
|
3587
|
+
}
|
|
3588
|
+
};
|
|
3589
|
+
}
|
|
3590
|
+
if (!result.delivered) {
|
|
3591
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3592
|
+
retryIdentity = undefined;
|
|
3593
|
+
const errorText = result.reason ?? "Session may not exist or has disconnected.";
|
|
3594
|
+
return {
|
|
3595
|
+
content: [{
|
|
3596
|
+
type: "text",
|
|
3597
|
+
text: `Message to "${to}" was not delivered: ${errorText}`
|
|
3598
|
+
}],
|
|
3599
|
+
isError: true,
|
|
3600
|
+
details: retryToken === undefined ? { messageId: result.id, delivered: false, reason: result.reason } : {
|
|
3601
|
+
delivered: false,
|
|
3602
|
+
reason: result.reason,
|
|
3603
|
+
...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
|
|
3604
|
+
}
|
|
3397
3605
|
};
|
|
3398
3606
|
}
|
|
3399
|
-
}
|
|
3400
|
-
retryIdentity ??= retryIdentities.begin({
|
|
3401
|
-
sessionId: toolSessionId,
|
|
3402
|
-
action: "send",
|
|
3403
|
-
target: to,
|
|
3404
|
-
text: message,
|
|
3405
|
-
attachments,
|
|
3406
|
-
replyTo,
|
|
3407
|
-
expectsReply: false
|
|
3408
|
-
}, retryToken);
|
|
3409
|
-
const sendTo = await resolveTarget(connectedClient, to) ?? to;
|
|
3410
|
-
if (_signal?.aborted) {
|
|
3411
|
-
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3412
|
-
retryIdentity = undefined;
|
|
3413
|
-
return {
|
|
3414
|
-
content: [{ type: "text", text: `Cancelled${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}` }],
|
|
3415
|
-
isError: true,
|
|
3416
|
-
details: retryErrorDetails(retained.retryToken)
|
|
3417
|
-
};
|
|
3418
|
-
}
|
|
3419
|
-
if (sendTo === connectedClient.sessionId) {
|
|
3420
|
-
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3421
|
-
retryIdentity = undefined;
|
|
3422
|
-
return {
|
|
3423
|
-
content: [{
|
|
3424
|
-
type: "text",
|
|
3425
|
-
text: `Cannot message the current session${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
|
|
3426
|
-
}],
|
|
3427
|
-
isError: true,
|
|
3428
|
-
details: retryErrorDetails(retained.retryToken)
|
|
3429
|
-
};
|
|
3430
|
-
}
|
|
3431
|
-
const result = await connectedClient.send(sendTo, {
|
|
3432
|
-
messageId: retryIdentity.messageId,
|
|
3433
|
-
logicalTarget: to,
|
|
3434
|
-
text: message,
|
|
3435
|
-
attachments,
|
|
3436
|
-
replyTo
|
|
3437
|
-
});
|
|
3438
|
-
if (result.queued === true) {
|
|
3439
3607
|
retryIdentities.release(retryIdentity);
|
|
3440
3608
|
retryIdentity = undefined;
|
|
3441
3609
|
pi.appendEntry("intercom_sent", {
|
|
@@ -3444,376 +3612,379 @@ ${message}${attachmentText}`);
|
|
|
3444
3612
|
messageId: result.id,
|
|
3445
3613
|
timestamp: Date.now()
|
|
3446
3614
|
});
|
|
3447
|
-
|
|
3615
|
+
if (replyTo)
|
|
3616
|
+
activeReplyTracker().markReplied(replyTo);
|
|
3448
3617
|
return {
|
|
3449
|
-
content: [{
|
|
3450
|
-
type: "text",
|
|
3451
|
-
text: notInKnownSet ? `Message queued for ${to} (not in the workflow's known stage set; it will be delivered to every matching stage that starts before the run terminates)` : `Message queued for ${to}`
|
|
3452
|
-
}],
|
|
3618
|
+
content: [{ type: "text", text: `Message sent to ${to}` }],
|
|
3453
3619
|
isError: false,
|
|
3454
|
-
details: {
|
|
3455
|
-
messageId: result.id,
|
|
3456
|
-
delivered: false,
|
|
3457
|
-
queued: true,
|
|
3458
|
-
target: result.target,
|
|
3459
|
-
position: result.position,
|
|
3460
|
-
...notInKnownSet ? { notInKnownSet: true } : {}
|
|
3461
|
-
}
|
|
3620
|
+
details: { messageId: result.id, delivered: true }
|
|
3462
3621
|
};
|
|
3463
|
-
}
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
retryIdentity
|
|
3467
|
-
|
|
3622
|
+
} catch (error) {
|
|
3623
|
+
let failure = error;
|
|
3624
|
+
let retained;
|
|
3625
|
+
if (retryIdentity !== undefined) {
|
|
3626
|
+
if (isRecoverableIntercomDisconnect(error)) {
|
|
3627
|
+
try {
|
|
3628
|
+
retained = retainRecoverableRetry(retryIdentities, retryIdentity);
|
|
3629
|
+
} catch (retentionError) {
|
|
3630
|
+
failure = retentionError;
|
|
3631
|
+
}
|
|
3632
|
+
} else {
|
|
3633
|
+
retryIdentities.release(retryIdentity);
|
|
3634
|
+
}
|
|
3635
|
+
}
|
|
3468
3636
|
return {
|
|
3469
3637
|
content: [{
|
|
3470
3638
|
type: "text",
|
|
3471
|
-
text: `
|
|
3639
|
+
text: `Failed to send: ${getErrorMessage(failure)}`
|
|
3472
3640
|
}],
|
|
3473
3641
|
isError: true,
|
|
3474
|
-
details:
|
|
3475
|
-
delivered: false,
|
|
3476
|
-
reason: result.reason,
|
|
3477
|
-
...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
|
|
3478
|
-
}
|
|
3642
|
+
details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error) }
|
|
3479
3643
|
};
|
|
3480
3644
|
}
|
|
3481
|
-
retryIdentities.release(retryIdentity);
|
|
3482
|
-
retryIdentity = undefined;
|
|
3483
|
-
pi.appendEntry("intercom_sent", {
|
|
3484
|
-
to,
|
|
3485
|
-
message: { text: message, attachments, replyTo },
|
|
3486
|
-
messageId: result.id,
|
|
3487
|
-
timestamp: Date.now()
|
|
3488
|
-
});
|
|
3489
|
-
if (replyTo)
|
|
3490
|
-
activeReplyTracker().markReplied(replyTo);
|
|
3491
|
-
return {
|
|
3492
|
-
content: [{ type: "text", text: `Message sent to ${to}` }],
|
|
3493
|
-
isError: false,
|
|
3494
|
-
details: { messageId: result.id, delivered: true }
|
|
3495
|
-
};
|
|
3496
|
-
} catch (error) {
|
|
3497
|
-
let failure = error;
|
|
3498
|
-
let retained;
|
|
3499
|
-
if (retryIdentity !== undefined) {
|
|
3500
|
-
if (isRecoverableIntercomDisconnect(error)) {
|
|
3501
|
-
try {
|
|
3502
|
-
retained = retainRecoverableRetry(retryIdentities, retryIdentity);
|
|
3503
|
-
} catch (retentionError) {
|
|
3504
|
-
failure = retentionError;
|
|
3505
|
-
}
|
|
3506
|
-
} else {
|
|
3507
|
-
retryIdentities.release(retryIdentity);
|
|
3508
|
-
}
|
|
3509
|
-
}
|
|
3510
|
-
return {
|
|
3511
|
-
content: [{
|
|
3512
|
-
type: "text",
|
|
3513
|
-
text: `Failed to send: ${getErrorMessage(failure)}${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
|
|
3514
|
-
}],
|
|
3515
|
-
isError: true,
|
|
3516
|
-
details: retryErrorDetails(retained?.retryToken)
|
|
3517
|
-
};
|
|
3518
|
-
}
|
|
3519
|
-
}
|
|
3520
|
-
case "ask": {
|
|
3521
|
-
if (!to) {
|
|
3522
|
-
const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
|
|
3523
|
-
return {
|
|
3524
|
-
content: [{ type: "text", text: errorText }],
|
|
3525
|
-
isError: true,
|
|
3526
|
-
details: { error: true }
|
|
3527
|
-
};
|
|
3528
3645
|
}
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
type: "text",
|
|
3533
|
-
text: `Cancelled${retryTokenGuidance(retryToken, retryPreflightRemaining ?? 0)}`
|
|
3534
|
-
}],
|
|
3535
|
-
isError: true,
|
|
3536
|
-
details: retryErrorDetails(retryToken)
|
|
3537
|
-
};
|
|
3538
|
-
}
|
|
3539
|
-
let wait = null;
|
|
3540
|
-
let retryIdentity;
|
|
3541
|
-
try {
|
|
3542
|
-
if (retryToken !== undefined && !message)
|
|
3543
|
-
throw new RetryTokenError("mismatch");
|
|
3544
|
-
retryIdentity = retryIdentities.begin({
|
|
3545
|
-
sessionId: toolSessionId,
|
|
3546
|
-
action: "ask",
|
|
3547
|
-
target: to,
|
|
3548
|
-
text: message ?? "",
|
|
3549
|
-
attachments,
|
|
3550
|
-
replyTo,
|
|
3551
|
-
expectsReply: true
|
|
3552
|
-
}, retryToken);
|
|
3553
|
-
const metadata = getMetadata();
|
|
3554
|
-
const currentSupervisorId = connectedClient.supervisorSessionId ?? undefined;
|
|
3555
|
-
const metadataSupervisorId = metadata?.supervisor?.supervisorSessionId;
|
|
3556
|
-
const directParentTarget = Boolean(metadata && (to === metadata.orchestratorTarget || to === currentSupervisorId || to === metadataSupervisorId));
|
|
3557
|
-
const claimParentAsk = (resolvedTargetId) => Boolean(metadata && requestParentAskHandoff(pi.events, metadata, {
|
|
3558
|
-
kind: "intercom",
|
|
3559
|
-
question: typeof message === "string" ? message : "",
|
|
3560
|
-
attachments,
|
|
3561
|
-
resolvedTargetId
|
|
3562
|
-
}));
|
|
3563
|
-
if (retryToken === undefined && directParentTarget && claimParentAsk(currentSupervisorId ?? metadataSupervisorId ?? to)) {
|
|
3564
|
-
retryIdentities.release(retryIdentity);
|
|
3565
|
-
retryIdentity = undefined;
|
|
3566
|
-
return {
|
|
3567
|
-
content: [{ type: "text", text: "Parent ask claimed; this child is ending for a fresh subagent start." }],
|
|
3568
|
-
isError: false,
|
|
3569
|
-
details: { yielded: true }
|
|
3570
|
-
};
|
|
3571
|
-
}
|
|
3572
|
-
const sendTo = await resolveTarget(connectedClient, to) ?? to;
|
|
3573
|
-
if (_signal?.aborted) {
|
|
3574
|
-
const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3575
|
-
retryIdentity = undefined;
|
|
3646
|
+
case "ask": {
|
|
3647
|
+
if (!to) {
|
|
3648
|
+
const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
|
|
3576
3649
|
return {
|
|
3577
|
-
content: [{
|
|
3578
|
-
type: "text",
|
|
3579
|
-
text: `Cancelled${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
|
|
3580
|
-
}],
|
|
3650
|
+
content: [{ type: "text", text: errorText }],
|
|
3581
3651
|
isError: true,
|
|
3582
|
-
details:
|
|
3652
|
+
details: { error: true }
|
|
3583
3653
|
};
|
|
3584
3654
|
}
|
|
3585
|
-
if (
|
|
3586
|
-
const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3587
|
-
retryIdentity = undefined;
|
|
3655
|
+
if (_signal?.aborted) {
|
|
3588
3656
|
return {
|
|
3589
3657
|
content: [{
|
|
3590
3658
|
type: "text",
|
|
3591
|
-
text:
|
|
3659
|
+
text: "Cancelled"
|
|
3592
3660
|
}],
|
|
3593
3661
|
isError: true,
|
|
3594
|
-
details: retryErrorDetails(
|
|
3662
|
+
details: retryErrorDetails(retryToken)
|
|
3595
3663
|
};
|
|
3596
3664
|
}
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3665
|
+
let wait = null;
|
|
3666
|
+
let retryIdentity;
|
|
3667
|
+
let askDelivered = false;
|
|
3668
|
+
try {
|
|
3669
|
+
retryIdentity = retryIdentities.begin({
|
|
3670
|
+
sessionId: toolSessionId,
|
|
3671
|
+
action: "ask",
|
|
3672
|
+
target: to,
|
|
3673
|
+
text: message ?? "",
|
|
3674
|
+
attachments,
|
|
3675
|
+
replyTo,
|
|
3676
|
+
expectsReply: true
|
|
3677
|
+
}, retryToken);
|
|
3678
|
+
const metadata = getMetadata();
|
|
3679
|
+
const currentSupervisorId = connectedClient.supervisorSessionId ?? undefined;
|
|
3680
|
+
const metadataSupervisorId = metadata?.supervisor?.supervisorSessionId;
|
|
3681
|
+
const directParentTarget = Boolean(metadata && (to === metadata.orchestratorTarget || to === currentSupervisorId || to === metadataSupervisorId));
|
|
3682
|
+
let parentTarget = directParentTarget;
|
|
3683
|
+
const claimParentAsk = (resolvedTargetId) => Boolean(metadata && requestParentAskHandoff(pi.events, metadata, {
|
|
3684
|
+
kind: "intercom",
|
|
3685
|
+
question: typeof message === "string" ? message : "",
|
|
3686
|
+
attachments: params.attachments,
|
|
3687
|
+
resolvedTargetId
|
|
3688
|
+
}));
|
|
3689
|
+
if (retryToken === undefined && directParentTarget && claimParentAsk(currentSupervisorId ?? metadataSupervisorId ?? to)) {
|
|
3690
|
+
retryIdentities.release(retryIdentity);
|
|
3691
|
+
retryIdentity = undefined;
|
|
3692
|
+
return {
|
|
3693
|
+
content: [{ type: "text", text: "Parent ask claimed; this child is ending for a fresh subagent start." }],
|
|
3694
|
+
isError: false,
|
|
3695
|
+
details: { yielded: true }
|
|
3696
|
+
};
|
|
3697
|
+
}
|
|
3698
|
+
const sendTo = await resolveTarget(connectedClient, to) ?? to;
|
|
3699
|
+
if (_signal?.aborted) {
|
|
3700
|
+
const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3701
|
+
retryIdentity = undefined;
|
|
3702
|
+
return {
|
|
3703
|
+
content: [{
|
|
3704
|
+
type: "text",
|
|
3705
|
+
text: "Cancelled"
|
|
3706
|
+
}],
|
|
3707
|
+
isError: true,
|
|
3708
|
+
details: retryErrorDetails(retained?.retryToken)
|
|
3709
|
+
};
|
|
3710
|
+
}
|
|
3711
|
+
if (sendTo === connectedClient.sessionId) {
|
|
3712
|
+
const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3713
|
+
retryIdentity = undefined;
|
|
3714
|
+
return {
|
|
3715
|
+
content: [{
|
|
3716
|
+
type: "text",
|
|
3717
|
+
text: "Cannot message the current session"
|
|
3718
|
+
}],
|
|
3719
|
+
isError: true,
|
|
3720
|
+
details: retryErrorDetails(retained?.retryToken)
|
|
3721
|
+
};
|
|
3722
|
+
}
|
|
3723
|
+
if (metadata && !directParentTarget) {
|
|
3724
|
+
const authoritativeParent = [currentSupervisorId, metadataSupervisorId].find((candidate) => candidate === sendTo);
|
|
3725
|
+
const resolvedParent = authoritativeParent ?? await resolveTarget(connectedClient, metadata.orchestratorTarget);
|
|
3726
|
+
parentTarget = resolvedParent !== null && resolvedParent === sendTo;
|
|
3727
|
+
if (retryToken === undefined && parentTarget && claimParentAsk(sendTo)) {
|
|
3728
|
+
retryIdentities.release(retryIdentity);
|
|
3729
|
+
retryIdentity = undefined;
|
|
3730
|
+
return {
|
|
3731
|
+
content: [{ type: "text", text: "Parent ask claimed; this child is ending for a fresh subagent start." }],
|
|
3732
|
+
isError: false,
|
|
3733
|
+
details: { yielded: true }
|
|
3734
|
+
};
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3737
|
+
if (!message && !parentTarget) {
|
|
3738
|
+
retryIdentities.release(retryIdentity);
|
|
3739
|
+
retryIdentity = undefined;
|
|
3740
|
+
return {
|
|
3741
|
+
content: [{ type: "text", text: "Missing 'to' or 'message' parameter" }],
|
|
3742
|
+
isError: true,
|
|
3743
|
+
details: { error: true }
|
|
3744
|
+
};
|
|
3745
|
+
}
|
|
3746
|
+
const replySender = await resolveReplySender(connectedClient, to, sendTo);
|
|
3747
|
+
if (replySender.kind === "ambiguous") {
|
|
3748
|
+
const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3749
|
+
retryIdentity = undefined;
|
|
3750
|
+
return {
|
|
3751
|
+
content: [{
|
|
3752
|
+
type: "text",
|
|
3753
|
+
text: `Message to "${to}" is ambiguous: ${replySender.reason}. Use the exact target shown by intercom list.`
|
|
3754
|
+
}],
|
|
3755
|
+
isError: true,
|
|
3756
|
+
details: retryErrorDetails(retained?.retryToken)
|
|
3757
|
+
};
|
|
3758
|
+
}
|
|
3759
|
+
const questionId = retryIdentity.messageId;
|
|
3760
|
+
const replyFrom = replySender.kind === "resolved" ? replySender.sessionId : sendTo;
|
|
3761
|
+
const admission = beginReplyWait(replyFrom, questionId, _signal);
|
|
3762
|
+
if (!admission.ok) {
|
|
3763
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3764
|
+
retryIdentity = undefined;
|
|
3765
|
+
const text = admission.reason === "busy" ? `Too many pending asks (${admission.limit}); reply-wait slots are full` : "Cancelled";
|
|
3766
|
+
return {
|
|
3767
|
+
content: [{
|
|
3768
|
+
type: "text",
|
|
3769
|
+
text
|
|
3770
|
+
}],
|
|
3771
|
+
isError: true,
|
|
3772
|
+
details: retryErrorDetails(retained.retryToken)
|
|
3773
|
+
};
|
|
3774
|
+
}
|
|
3775
|
+
wait = admission.wait;
|
|
3776
|
+
const sendResult = await connectedClient.send(sendTo, {
|
|
3777
|
+
messageId: questionId,
|
|
3778
|
+
logicalTarget: to,
|
|
3779
|
+
text: message ?? "",
|
|
3780
|
+
attachments,
|
|
3781
|
+
replyTo,
|
|
3782
|
+
expectsReply: true,
|
|
3783
|
+
...parseWorkflowStageTarget(to)?.kind === "path" ? { onReplyTarget: wait.bindSender } : {}
|
|
3784
|
+
});
|
|
3785
|
+
if (sendResult.queued === true) {
|
|
3601
3786
|
retryIdentities.release(retryIdentity);
|
|
3602
3787
|
retryIdentity = undefined;
|
|
3788
|
+
wait.cancel(new Error(`Message queued for ${to}`));
|
|
3789
|
+
pi.appendEntry("intercom_sent", {
|
|
3790
|
+
to,
|
|
3791
|
+
message: { text: message, attachments, replyTo },
|
|
3792
|
+
messageId: sendResult.id,
|
|
3793
|
+
timestamp: Date.now()
|
|
3794
|
+
});
|
|
3603
3795
|
return {
|
|
3604
|
-
content: [{ type: "text", text:
|
|
3796
|
+
content: [{ type: "text", text: `Message queued for ${to}` }],
|
|
3605
3797
|
isError: false,
|
|
3606
|
-
details: {
|
|
3798
|
+
details: {
|
|
3799
|
+
messageId: sendResult.id,
|
|
3800
|
+
delivered: false,
|
|
3801
|
+
queued: true,
|
|
3802
|
+
target: sendResult.target,
|
|
3803
|
+
position: sendResult.position
|
|
3804
|
+
}
|
|
3607
3805
|
};
|
|
3608
3806
|
}
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
}
|
|
3631
|
-
|
|
3632
|
-
const questionId = retryIdentity.messageId;
|
|
3633
|
-
const replyFrom = replySender.kind === "resolved" ? replySender.sessionId : sendTo;
|
|
3634
|
-
const admission = beginReplyWait(replyFrom, questionId, _signal);
|
|
3635
|
-
if (!admission.ok) {
|
|
3636
|
-
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3637
|
-
retryIdentity = undefined;
|
|
3638
|
-
const text = admission.reason === "busy" ? `Too many pending asks (${admission.limit}); reply-wait slots are full` : "Cancelled";
|
|
3639
|
-
return {
|
|
3640
|
-
content: [{
|
|
3641
|
-
type: "text",
|
|
3642
|
-
text: `${text}${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
|
|
3643
|
-
}],
|
|
3644
|
-
isError: true,
|
|
3645
|
-
details: retryErrorDetails(retained.retryToken)
|
|
3646
|
-
};
|
|
3647
|
-
}
|
|
3648
|
-
wait = admission.wait;
|
|
3649
|
-
const sendResult = await connectedClient.send(sendTo, {
|
|
3650
|
-
messageId: questionId,
|
|
3651
|
-
logicalTarget: to,
|
|
3652
|
-
text: message,
|
|
3653
|
-
attachments,
|
|
3654
|
-
replyTo,
|
|
3655
|
-
expectsReply: true
|
|
3656
|
-
});
|
|
3657
|
-
if (sendResult.queued === true) {
|
|
3658
|
-
retryIdentities.release(retryIdentity);
|
|
3659
|
-
retryIdentity = undefined;
|
|
3660
|
-
wait.cancel(new Error(`Message queued for ${to}`));
|
|
3807
|
+
if (!sendResult.delivered) {
|
|
3808
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3809
|
+
retryIdentity = undefined;
|
|
3810
|
+
const errorText = sendResult.reason ?? "Session may not exist or has disconnected.";
|
|
3811
|
+
wait.cancel(new Error(`Message to "${to}" was not delivered: ${errorText}`));
|
|
3812
|
+
const pendingStageAskRefusal = errorText.startsWith("Cannot ask a workflow stage whose session has not initialized.");
|
|
3813
|
+
return {
|
|
3814
|
+
content: [{
|
|
3815
|
+
type: "text",
|
|
3816
|
+
text: `Message to "${to}" was not delivered: ${errorText}`
|
|
3817
|
+
}],
|
|
3818
|
+
isError: true,
|
|
3819
|
+
details: {
|
|
3820
|
+
...pendingStageAskRefusal ? {
|
|
3821
|
+
refusal: "pending_stage_ask_unsupported",
|
|
3822
|
+
recommendedAction: "send",
|
|
3823
|
+
reason: errorText
|
|
3824
|
+
} : {},
|
|
3825
|
+
...retryErrorDetails(retained.retryToken)
|
|
3826
|
+
}
|
|
3827
|
+
};
|
|
3828
|
+
}
|
|
3829
|
+
askDelivered = true;
|
|
3661
3830
|
pi.appendEntry("intercom_sent", {
|
|
3662
3831
|
to,
|
|
3663
3832
|
message: { text: message, attachments, replyTo },
|
|
3664
3833
|
messageId: sendResult.id,
|
|
3665
3834
|
timestamp: Date.now()
|
|
3666
3835
|
});
|
|
3836
|
+
const replyMessage = await wait.promise;
|
|
3837
|
+
retryIdentities.release(retryIdentity);
|
|
3838
|
+
retryIdentity = undefined;
|
|
3839
|
+
const replyText = replyMessage.content.text;
|
|
3840
|
+
const replyAttachments = replyMessage.content.attachments?.length ? formatAttachments(replyMessage.content.attachments) : "";
|
|
3841
|
+
pi.appendEntry("intercom_received", {
|
|
3842
|
+
from: to,
|
|
3843
|
+
message: { text: replyText, attachments: replyMessage.content.attachments },
|
|
3844
|
+
messageId: replyMessage.id,
|
|
3845
|
+
timestamp: replyMessage.timestamp
|
|
3846
|
+
});
|
|
3847
|
+
if (replyMessage.replyError !== undefined) {
|
|
3848
|
+
return {
|
|
3849
|
+
content: [{ type: "text", text: `Failed: ${replyMessage.replyError}` }],
|
|
3850
|
+
isError: true,
|
|
3851
|
+
details: { error: true, replyTo: replyMessage.replyTo }
|
|
3852
|
+
};
|
|
3853
|
+
}
|
|
3667
3854
|
return {
|
|
3668
|
-
content: [{ type: "text", text:
|
|
3855
|
+
content: [{ type: "text", text: `**Reply from ${to}:**
|
|
3856
|
+
${replyText}${replyAttachments}` }],
|
|
3669
3857
|
isError: false,
|
|
3670
|
-
details: {
|
|
3671
|
-
messageId: sendResult.id,
|
|
3672
|
-
delivered: false,
|
|
3673
|
-
queued: true,
|
|
3674
|
-
target: sendResult.target,
|
|
3675
|
-
position: sendResult.position
|
|
3676
|
-
}
|
|
3858
|
+
details: {}
|
|
3677
3859
|
};
|
|
3678
|
-
}
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3860
|
+
} catch (error) {
|
|
3861
|
+
wait?.cancel(toError3(error));
|
|
3862
|
+
let failure = error;
|
|
3863
|
+
let retained;
|
|
3864
|
+
if (retryIdentity !== undefined) {
|
|
3865
|
+
if (isRecoverableIntercomDisconnect(error)) {
|
|
3866
|
+
try {
|
|
3867
|
+
retained = retainRecoverableRetry(retryIdentities, retryIdentity);
|
|
3868
|
+
} catch (retentionError) {
|
|
3869
|
+
failure = retentionError;
|
|
3870
|
+
}
|
|
3871
|
+
} else {
|
|
3872
|
+
retryIdentities.release(retryIdentity);
|
|
3873
|
+
}
|
|
3874
|
+
}
|
|
3685
3875
|
return {
|
|
3686
3876
|
content: [{
|
|
3687
3877
|
type: "text",
|
|
3688
|
-
text: `
|
|
3878
|
+
text: `Failed: ${getErrorMessage(failure)}`
|
|
3689
3879
|
}],
|
|
3690
3880
|
isError: true,
|
|
3691
|
-
details: {
|
|
3692
|
-
...pendingStageAskRefusal ? {
|
|
3693
|
-
refusal: "pending_stage_ask_unsupported",
|
|
3694
|
-
recommendedAction: "send",
|
|
3695
|
-
reason: errorText
|
|
3696
|
-
} : {},
|
|
3697
|
-
...retryErrorDetails(retained.retryToken)
|
|
3698
|
-
}
|
|
3699
|
-
};
|
|
3700
|
-
}
|
|
3701
|
-
pi.appendEntry("intercom_sent", {
|
|
3702
|
-
to,
|
|
3703
|
-
message: { text: message, attachments, replyTo },
|
|
3704
|
-
messageId: sendResult.id,
|
|
3705
|
-
timestamp: Date.now()
|
|
3706
|
-
});
|
|
3707
|
-
const replyMessage = await wait.promise;
|
|
3708
|
-
retryIdentities.release(retryIdentity);
|
|
3709
|
-
retryIdentity = undefined;
|
|
3710
|
-
const replyText = replyMessage.content.text;
|
|
3711
|
-
const replyAttachments = replyMessage.content.attachments?.length ? formatAttachments(replyMessage.content.attachments) : "";
|
|
3712
|
-
pi.appendEntry("intercom_received", {
|
|
3713
|
-
from: to,
|
|
3714
|
-
message: { text: replyText, attachments: replyMessage.content.attachments },
|
|
3715
|
-
messageId: replyMessage.id,
|
|
3716
|
-
timestamp: replyMessage.timestamp
|
|
3717
|
-
});
|
|
3718
|
-
if (replyMessage.replyError !== undefined) {
|
|
3719
|
-
return {
|
|
3720
|
-
content: [{ type: "text", text: `Failed: ${replyMessage.replyError}` }],
|
|
3721
|
-
isError: true,
|
|
3722
|
-
details: { error: true, replyTo: replyMessage.replyTo }
|
|
3881
|
+
details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error), deliveryUncertain: askDelivered }
|
|
3723
3882
|
};
|
|
3724
3883
|
}
|
|
3725
|
-
return {
|
|
3726
|
-
content: [{ type: "text", text: `**Reply from ${to}:**
|
|
3727
|
-
${replyText}${replyAttachments}` }],
|
|
3728
|
-
isError: false,
|
|
3729
|
-
details: {}
|
|
3730
|
-
};
|
|
3731
|
-
} catch (error) {
|
|
3732
|
-
wait?.cancel(toError3(error));
|
|
3733
|
-
let failure = error;
|
|
3734
|
-
let retained;
|
|
3735
|
-
if (retryIdentity !== undefined) {
|
|
3736
|
-
if (isRecoverableIntercomDisconnect(error)) {
|
|
3737
|
-
try {
|
|
3738
|
-
retained = retainRecoverableRetry(retryIdentities, retryIdentity);
|
|
3739
|
-
} catch (retentionError) {
|
|
3740
|
-
failure = retentionError;
|
|
3741
|
-
}
|
|
3742
|
-
} else {
|
|
3743
|
-
retryIdentities.release(retryIdentity);
|
|
3744
|
-
}
|
|
3745
|
-
}
|
|
3746
|
-
return {
|
|
3747
|
-
content: [{
|
|
3748
|
-
type: "text",
|
|
3749
|
-
text: `Failed: ${getErrorMessage(failure)}${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
|
|
3750
|
-
}],
|
|
3751
|
-
isError: true,
|
|
3752
|
-
details: retryErrorDetails(retained?.retryToken)
|
|
3753
|
-
};
|
|
3754
|
-
}
|
|
3755
|
-
}
|
|
3756
|
-
case "reply": {
|
|
3757
|
-
if (!message) {
|
|
3758
|
-
const errorText = retryToken === undefined ? "Missing 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
|
|
3759
|
-
return {
|
|
3760
|
-
content: [{ type: "text", text: errorText }],
|
|
3761
|
-
isError: true,
|
|
3762
|
-
details: { error: true }
|
|
3763
|
-
};
|
|
3764
3884
|
}
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
sessionId: toolSessionId,
|
|
3769
|
-
action: "reply",
|
|
3770
|
-
target: to,
|
|
3771
|
-
text: message,
|
|
3772
|
-
attachments,
|
|
3773
|
-
replyTo,
|
|
3774
|
-
expectsReply: false
|
|
3775
|
-
}, retryToken);
|
|
3776
|
-
if (retryToken === undefined) {
|
|
3777
|
-
const target = activeReplyTracker().resolveReplyTarget({ to, replyTo });
|
|
3778
|
-
retryIdentities.bindReplyRoute(retryIdentity, {
|
|
3779
|
-
senderId: target.from.id,
|
|
3780
|
-
...target.from.name === undefined ? {} : { senderName: target.from.name },
|
|
3781
|
-
messageId: target.message.id,
|
|
3782
|
-
expectsReply: target.message.expectsReply === true
|
|
3783
|
-
});
|
|
3784
|
-
}
|
|
3785
|
-
const route = retryIdentities.replyRoute(retryIdentity);
|
|
3786
|
-
if (route === undefined)
|
|
3787
|
-
throw new RetryTokenError("invalid");
|
|
3788
|
-
const replySendTo = to ?? route.senderId;
|
|
3789
|
-
const replyLogicalTarget = to ?? route.senderId;
|
|
3790
|
-
const displayTarget = route.senderName || route.senderId;
|
|
3791
|
-
if (route.senderId === connectedClient.sessionId) {
|
|
3792
|
-
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3793
|
-
retryIdentity = undefined;
|
|
3885
|
+
case "reply": {
|
|
3886
|
+
if (!message) {
|
|
3887
|
+
const errorText = retryToken === undefined ? "Missing 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
|
|
3794
3888
|
return {
|
|
3795
|
-
content: [{
|
|
3796
|
-
type: "text",
|
|
3797
|
-
text: `Cannot message the current session${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
|
|
3798
|
-
}],
|
|
3889
|
+
content: [{ type: "text", text: errorText }],
|
|
3799
3890
|
isError: true,
|
|
3800
|
-
details:
|
|
3891
|
+
details: { error: true }
|
|
3801
3892
|
};
|
|
3802
3893
|
}
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
messageId: replyMessageId,
|
|
3806
|
-
logicalTarget: replyLogicalTarget,
|
|
3807
|
-
...route.expectsReply ? { requirePendingReply: true } : {},
|
|
3808
|
-
text: message,
|
|
3809
|
-
attachments,
|
|
3810
|
-
replyTo: route.messageId
|
|
3811
|
-
});
|
|
3812
|
-
let result = await sendReply(replySendTo);
|
|
3813
|
-
if (to === undefined && result.delivered === false && result.reasonCode === "session_not_found" && route.senderName !== undefined) {
|
|
3814
|
-
result = await sendReply(route.senderName);
|
|
3894
|
+
if (_signal?.aborted) {
|
|
3895
|
+
return { content: [{ type: "text", text: "Cancelled" }], isError: true, details: retryErrorDetails(retryToken) };
|
|
3815
3896
|
}
|
|
3816
|
-
|
|
3897
|
+
let retryIdentity;
|
|
3898
|
+
try {
|
|
3899
|
+
retryIdentity = retryIdentities.begin({
|
|
3900
|
+
sessionId: toolSessionId,
|
|
3901
|
+
action: "reply",
|
|
3902
|
+
target: to,
|
|
3903
|
+
text: message,
|
|
3904
|
+
attachments,
|
|
3905
|
+
replyTo,
|
|
3906
|
+
expectsReply: false
|
|
3907
|
+
}, retryToken);
|
|
3908
|
+
if (retryToken === undefined) {
|
|
3909
|
+
const target = activeReplyTracker().resolveReplyTarget({ to, replyTo });
|
|
3910
|
+
retryIdentities.bindReplyRoute(retryIdentity, {
|
|
3911
|
+
senderId: target.from.id,
|
|
3912
|
+
...target.from.name === undefined ? {} : { senderName: target.from.name },
|
|
3913
|
+
messageId: target.message.id,
|
|
3914
|
+
expectsReply: target.message.expectsReply === true
|
|
3915
|
+
});
|
|
3916
|
+
}
|
|
3917
|
+
const route = retryIdentities.replyRoute(retryIdentity);
|
|
3918
|
+
if (route === undefined)
|
|
3919
|
+
throw new RetryTokenError("invalid");
|
|
3920
|
+
const replySendTo = to ?? route.senderId;
|
|
3921
|
+
const replyLogicalTarget = to ?? route.senderId;
|
|
3922
|
+
const displayTarget = route.senderName || route.senderId;
|
|
3923
|
+
if (route.senderId === connectedClient.sessionId) {
|
|
3924
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3925
|
+
retryIdentity = undefined;
|
|
3926
|
+
return {
|
|
3927
|
+
content: [{
|
|
3928
|
+
type: "text",
|
|
3929
|
+
text: "Cannot message the current session"
|
|
3930
|
+
}],
|
|
3931
|
+
isError: true,
|
|
3932
|
+
details: retryErrorDetails(retained.retryToken)
|
|
3933
|
+
};
|
|
3934
|
+
}
|
|
3935
|
+
const replyMessageId = retryIdentity.messageId;
|
|
3936
|
+
const sendReply = (targetId) => connectedClient.send(targetId, {
|
|
3937
|
+
messageId: replyMessageId,
|
|
3938
|
+
logicalTarget: replyLogicalTarget,
|
|
3939
|
+
...route.expectsReply ? { requirePendingReply: true } : {},
|
|
3940
|
+
text: message,
|
|
3941
|
+
attachments,
|
|
3942
|
+
replyTo: route.messageId
|
|
3943
|
+
});
|
|
3944
|
+
let result = await sendReply(replySendTo);
|
|
3945
|
+
if (to === undefined && result.delivered === false && result.reasonCode === "session_not_found" && route.senderName !== undefined) {
|
|
3946
|
+
result = await sendReply(route.senderName);
|
|
3947
|
+
}
|
|
3948
|
+
if (result.queued === true) {
|
|
3949
|
+
retryIdentities.release(retryIdentity);
|
|
3950
|
+
retryIdentity = undefined;
|
|
3951
|
+
activeReplyTracker().markReplied(route.messageId);
|
|
3952
|
+
pi.appendEntry("intercom_sent", {
|
|
3953
|
+
to: displayTarget,
|
|
3954
|
+
message: { text: message, attachments, replyTo: route.messageId },
|
|
3955
|
+
messageId: result.id,
|
|
3956
|
+
timestamp: Date.now()
|
|
3957
|
+
});
|
|
3958
|
+
return {
|
|
3959
|
+
content: [{ type: "text", text: `Reply queued for ${displayTarget}` }],
|
|
3960
|
+
isError: false,
|
|
3961
|
+
details: {
|
|
3962
|
+
messageId: result.id,
|
|
3963
|
+
delivered: false,
|
|
3964
|
+
queued: true,
|
|
3965
|
+
replyTo: route.messageId,
|
|
3966
|
+
target: result.target,
|
|
3967
|
+
position: result.position
|
|
3968
|
+
}
|
|
3969
|
+
};
|
|
3970
|
+
}
|
|
3971
|
+
if (!result.delivered) {
|
|
3972
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3973
|
+
retryIdentity = undefined;
|
|
3974
|
+
const errorText = result.reason ?? "Session may not exist or has disconnected.";
|
|
3975
|
+
return {
|
|
3976
|
+
content: [{
|
|
3977
|
+
type: "text",
|
|
3978
|
+
text: `Reply to "${displayTarget}" was not delivered: ${errorText}`
|
|
3979
|
+
}],
|
|
3980
|
+
isError: true,
|
|
3981
|
+
details: retryToken === undefined ? { messageId: result.id, delivered: false, reason: result.reason } : {
|
|
3982
|
+
delivered: false,
|
|
3983
|
+
reason: result.reason,
|
|
3984
|
+
...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
|
|
3985
|
+
}
|
|
3986
|
+
};
|
|
3987
|
+
}
|
|
3817
3988
|
retryIdentities.release(retryIdentity);
|
|
3818
3989
|
retryIdentity = undefined;
|
|
3819
3990
|
activeReplyTracker().markReplied(route.messageId);
|
|
@@ -3824,136 +3995,101 @@ ${replyText}${replyAttachments}` }],
|
|
|
3824
3995
|
timestamp: Date.now()
|
|
3825
3996
|
});
|
|
3826
3997
|
return {
|
|
3827
|
-
content: [{ type: "text", text: `Reply
|
|
3998
|
+
content: [{ type: "text", text: `Reply sent to ${displayTarget}` }],
|
|
3828
3999
|
isError: false,
|
|
3829
|
-
details: {
|
|
3830
|
-
messageId: result.id,
|
|
3831
|
-
delivered: false,
|
|
3832
|
-
queued: true,
|
|
3833
|
-
replyTo: route.messageId,
|
|
3834
|
-
target: result.target,
|
|
3835
|
-
position: result.position
|
|
3836
|
-
}
|
|
4000
|
+
details: { messageId: result.id, delivered: true, replyTo: route.messageId }
|
|
3837
4001
|
};
|
|
3838
|
-
}
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
retryIdentity
|
|
3842
|
-
|
|
4002
|
+
} catch (error) {
|
|
4003
|
+
let failure = error;
|
|
4004
|
+
let retained;
|
|
4005
|
+
if (retryIdentity !== undefined) {
|
|
4006
|
+
if (isRecoverableIntercomDisconnect(error)) {
|
|
4007
|
+
try {
|
|
4008
|
+
retained = retainRecoverableRetry(retryIdentities, retryIdentity);
|
|
4009
|
+
} catch (retentionError) {
|
|
4010
|
+
failure = retentionError;
|
|
4011
|
+
}
|
|
4012
|
+
} else {
|
|
4013
|
+
retryIdentities.release(retryIdentity);
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
3843
4016
|
return {
|
|
3844
4017
|
content: [{
|
|
3845
4018
|
type: "text",
|
|
3846
|
-
text: `
|
|
4019
|
+
text: `Failed to reply: ${getErrorMessage(failure)}`
|
|
3847
4020
|
}],
|
|
3848
4021
|
isError: true,
|
|
3849
|
-
details:
|
|
3850
|
-
delivered: false,
|
|
3851
|
-
reason: result.reason,
|
|
3852
|
-
...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
|
|
3853
|
-
}
|
|
4022
|
+
details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error) }
|
|
3854
4023
|
};
|
|
3855
4024
|
}
|
|
3856
|
-
retryIdentities.release(retryIdentity);
|
|
3857
|
-
retryIdentity = undefined;
|
|
3858
|
-
activeReplyTracker().markReplied(route.messageId);
|
|
3859
|
-
pi.appendEntry("intercom_sent", {
|
|
3860
|
-
to: displayTarget,
|
|
3861
|
-
message: { text: message, attachments, replyTo: route.messageId },
|
|
3862
|
-
messageId: result.id,
|
|
3863
|
-
timestamp: Date.now()
|
|
3864
|
-
});
|
|
3865
|
-
return {
|
|
3866
|
-
content: [{ type: "text", text: `Reply sent to ${displayTarget}` }],
|
|
3867
|
-
isError: false,
|
|
3868
|
-
details: { messageId: result.id, delivered: true, replyTo: route.messageId }
|
|
3869
|
-
};
|
|
3870
|
-
} catch (error) {
|
|
3871
|
-
let failure = error;
|
|
3872
|
-
let retained;
|
|
3873
|
-
if (retryIdentity !== undefined) {
|
|
3874
|
-
if (isRecoverableIntercomDisconnect(error)) {
|
|
3875
|
-
try {
|
|
3876
|
-
retained = retainRecoverableRetry(retryIdentities, retryIdentity);
|
|
3877
|
-
} catch (retentionError) {
|
|
3878
|
-
failure = retentionError;
|
|
3879
|
-
}
|
|
3880
|
-
} else {
|
|
3881
|
-
retryIdentities.release(retryIdentity);
|
|
3882
|
-
}
|
|
3883
|
-
}
|
|
3884
|
-
return {
|
|
3885
|
-
content: [{
|
|
3886
|
-
type: "text",
|
|
3887
|
-
text: `Failed to reply: ${getErrorMessage(failure)}${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
|
|
3888
|
-
}],
|
|
3889
|
-
isError: true,
|
|
3890
|
-
details: retryErrorDetails(retained?.retryToken)
|
|
3891
|
-
};
|
|
3892
4025
|
}
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
4026
|
+
case "pending": {
|
|
4027
|
+
const pendingAsks = activeReplyTracker().listPending();
|
|
4028
|
+
if (pendingAsks.length === 0) {
|
|
4029
|
+
return {
|
|
4030
|
+
content: [{ type: "text", text: "No unresolved inbound asks." }],
|
|
4031
|
+
isError: false,
|
|
4032
|
+
details: {}
|
|
4033
|
+
};
|
|
4034
|
+
}
|
|
4035
|
+
const now = Date.now();
|
|
4036
|
+
const lines = pendingAsks.map(({ from, message, receivedAt }) => {
|
|
4037
|
+
const preview = message.content.text.replace(/\s+/g, " ").slice(0, 80);
|
|
4038
|
+
const elapsedSeconds = Math.max(0, Math.floor((now - receivedAt) / 1000));
|
|
4039
|
+
return `- ${from.name || from.id} · ${message.id} · ${elapsedSeconds}s ago · ${preview}`;
|
|
4040
|
+
});
|
|
3897
4041
|
return {
|
|
3898
|
-
content: [{ type: "text", text:
|
|
4042
|
+
content: [{ type: "text", text: `**Pending asks:**
|
|
4043
|
+
${lines.join(`
|
|
4044
|
+
`)}` }],
|
|
3899
4045
|
isError: false,
|
|
3900
4046
|
details: {}
|
|
3901
4047
|
};
|
|
3902
4048
|
}
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
${lines.join(`
|
|
3912
|
-
`)}` }],
|
|
3913
|
-
isError: false,
|
|
3914
|
-
details: {}
|
|
3915
|
-
};
|
|
3916
|
-
}
|
|
3917
|
-
case "status": {
|
|
3918
|
-
try {
|
|
3919
|
-
const mySessionId = connectedClient.sessionId;
|
|
3920
|
-
const sessions = await connectedClient.listSessions();
|
|
3921
|
-
const ownGroups = resolveOwnGroups(sessions);
|
|
3922
|
-
const selectedGroup = isOnlyOwnGroup(requestedGroup, ownGroups) ? undefined : requestedGroup;
|
|
3923
|
-
const selectedGroupSessions = selectedGroup === undefined ? undefined : await connectedClient.listSessions(selectedGroup);
|
|
3924
|
-
const selectedSection = selectedGroupSessions === undefined ? "" : `
|
|
4049
|
+
case "status": {
|
|
4050
|
+
try {
|
|
4051
|
+
const mySessionId = connectedClient.sessionId;
|
|
4052
|
+
const sessions = await connectedClient.listSessions();
|
|
4053
|
+
const ownGroups = resolveOwnGroups(sessions);
|
|
4054
|
+
const selectedGroup = isOnlyOwnGroup(requestedGroup, ownGroups) ? undefined : requestedGroup;
|
|
4055
|
+
const selectedGroupSessions = selectedGroup === undefined ? undefined : await connectedClient.listSessions(selectedGroup);
|
|
4056
|
+
const selectedSection = selectedGroupSessions === undefined ? "" : `
|
|
3925
4057
|
Selected group [${selectedGroup}]: ${selectedGroupSessions.length} session(s)`;
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
4058
|
+
return {
|
|
4059
|
+
content: [{
|
|
4060
|
+
type: "text",
|
|
4061
|
+
text: `**Intercom Status:**
|
|
3930
4062
|
Connected: Yes
|
|
3931
4063
|
Session ID: ${mySessionId}
|
|
3932
4064
|
Groups: ${ownGroups.join(", ")}
|
|
3933
4065
|
Active visible sessions: ${sessions.length}${selectedSection}`
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
4066
|
+
}],
|
|
4067
|
+
isError: false,
|
|
4068
|
+
details: {
|
|
4069
|
+
group: ownGroups.at(-1),
|
|
4070
|
+
groups: ownGroups,
|
|
4071
|
+
...selectedGroup === undefined ? {} : { selectedGroup, selectedGroupSessionCount: selectedGroupSessions?.length ?? 0 }
|
|
4072
|
+
}
|
|
4073
|
+
};
|
|
4074
|
+
} catch (error) {
|
|
4075
|
+
return {
|
|
4076
|
+
content: [{ type: "text", text: `Failed to get status: ${getErrorMessage(error)}` }],
|
|
4077
|
+
isError: true,
|
|
4078
|
+
details: { error: true }
|
|
4079
|
+
};
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
default:
|
|
3943
4083
|
return {
|
|
3944
|
-
content: [{ type: "text", text: `
|
|
4084
|
+
content: [{ type: "text", text: `Unknown action: ${action}` }],
|
|
3945
4085
|
isError: true,
|
|
3946
4086
|
details: { error: true }
|
|
3947
4087
|
};
|
|
3948
|
-
}
|
|
3949
4088
|
}
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
details: { error: true }
|
|
3955
|
-
};
|
|
3956
|
-
}
|
|
4089
|
+
};
|
|
4090
|
+
if (action !== "send" && action !== "ask" && action !== "reply")
|
|
4091
|
+
return executeAttempt(undefined, signal);
|
|
4092
|
+
return runIntercomOperation(executeAttempt, (token) => retryIdentities.discard(token), signal);
|
|
3957
4093
|
},
|
|
3958
4094
|
renderCall(args, theme) {
|
|
3959
4095
|
const action = typeof args.action === "string" ? args.action : "intercom";
|
|
@@ -3985,6 +4121,7 @@ var init_intercom_tool = __esm(() => {
|
|
|
3985
4121
|
init_workflow_stage_target();
|
|
3986
4122
|
init_recoverable_disconnect();
|
|
3987
4123
|
init_retry_identity();
|
|
4124
|
+
init_tool_retry();
|
|
3988
4125
|
});
|
|
3989
4126
|
|
|
3990
4127
|
// dist/builtin/intercom/ui/compose.ts
|
|
@@ -4375,7 +4512,10 @@ var init_overlay = __esm(() => {
|
|
|
4375
4512
|
function registerIntercomLifecycle(pi, deps) {
|
|
4376
4513
|
const activeReplyTracker = () => typeof deps.replyTracker === "function" ? deps.replyTracker() : deps.replyTracker;
|
|
4377
4514
|
let hasActiveSession = false;
|
|
4515
|
+
let unbindStageClose;
|
|
4378
4516
|
async function cleanupRuntime(reason) {
|
|
4517
|
+
unbindStageClose?.();
|
|
4518
|
+
unbindStageClose = undefined;
|
|
4379
4519
|
deps.setRuntimeStarted(false);
|
|
4380
4520
|
deps.setShuttingDown(true);
|
|
4381
4521
|
deps.setDisposed(true);
|
|
@@ -4426,6 +4566,12 @@ function registerIntercomLifecycle(pi, deps) {
|
|
|
4426
4566
|
deps.setSessionStartedAt(Date.now());
|
|
4427
4567
|
deps.setAgentRunning(false);
|
|
4428
4568
|
deps.activeTools.clear();
|
|
4569
|
+
const stage = ctx.orchestrationContext;
|
|
4570
|
+
const closeSignal = stage?.kind === "workflow-stage" ? stage.messageAdmission?.boundary?.closeSignal : undefined;
|
|
4571
|
+
closeSignal?.addEventListener("abort", deps.syncPresenceStatus, { once: true });
|
|
4572
|
+
unbindStageClose = () => closeSignal?.removeEventListener("abort", deps.syncPresenceStatus);
|
|
4573
|
+
if (closeSignal?.aborted)
|
|
4574
|
+
deps.syncPresenceStatus();
|
|
4429
4575
|
});
|
|
4430
4576
|
pi.on("session_shutdown", async () => {
|
|
4431
4577
|
if (!hasActiveSession)
|
|
@@ -4564,12 +4710,12 @@ function prepareDurableAuthority(storagePath) {
|
|
|
4564
4710
|
if (databaseExists !== keyExists)
|
|
4565
4711
|
return;
|
|
4566
4712
|
if (!databaseExists) {
|
|
4567
|
-
const
|
|
4568
|
-
writeFileSync2(keyPath,
|
|
4713
|
+
const key = randomBytes(AUTHORITY_KEY_BYTES);
|
|
4714
|
+
writeFileSync2(keyPath, key, { flag: "wx", mode: 384 });
|
|
4569
4715
|
const databaseDescriptor = openSync2(storagePath, "wx", 384);
|
|
4570
4716
|
closeSync2(databaseDescriptor);
|
|
4571
4717
|
restrictExistingAuthorityArtifacts(storagePath, keyPath);
|
|
4572
|
-
return
|
|
4718
|
+
return key;
|
|
4573
4719
|
}
|
|
4574
4720
|
const key = readFileSync3(keyPath);
|
|
4575
4721
|
if (key.length !== AUTHORITY_KEY_BYTES)
|
|
@@ -4878,7 +5024,7 @@ function parseBarrier(value) {
|
|
|
4878
5024
|
return null;
|
|
4879
5025
|
if (typeof record.terminalAt !== "number" || !Number.isFinite(record.terminalAt))
|
|
4880
5026
|
return null;
|
|
4881
|
-
if (record.source !== "detached-notify" && record.source !== "result-relay")
|
|
5027
|
+
if (record.source !== "detached-notify" && record.source !== "result-relay" && record.source !== "owner-task")
|
|
4882
5028
|
return null;
|
|
4883
5029
|
if (!Array.isArray(record.sourceSessionTargets))
|
|
4884
5030
|
return null;
|
|
@@ -4954,11 +5100,17 @@ function registerTerminalOrderingBarrier(pi, options) {
|
|
|
4954
5100
|
envelope.completion = currentOwner;
|
|
4955
5101
|
return;
|
|
4956
5102
|
}
|
|
4957
|
-
const drainedTargets = drainedTargetsByTerminal.get(terminalKey) ?? new Set;
|
|
5103
|
+
const drainedTargets = barrier.source === "owner-task" ? new Set : drainedTargetsByTerminal.get(terminalKey) ?? new Set;
|
|
4958
5104
|
const pendingTargets = barrier.sourceSessionTargets.filter((target) => !drainedTargets.has(target));
|
|
4959
5105
|
if (pendingTargets.length === 0)
|
|
4960
5106
|
return;
|
|
4961
5107
|
const claim = options.queue.claimOrdinarySourceTargets(barrier.runId, pendingTargets, barrier.terminalAt);
|
|
5108
|
+
const deliverPrelude = (entry) => {
|
|
5109
|
+
if (!claim.isCurrent() || options.isCurrent?.() === false) {
|
|
5110
|
+
throw new Error("Intercom terminal delivery owner retired");
|
|
5111
|
+
}
|
|
5112
|
+
return options.deliver(entry, "prelude");
|
|
5113
|
+
};
|
|
4962
5114
|
const ownership = Promise.withResolvers();
|
|
4963
5115
|
ownership.promise.catch(() => {});
|
|
4964
5116
|
inFlightByTerminal.set(terminalKey, ownership.promise);
|
|
@@ -4968,7 +5120,7 @@ function registerTerminalOrderingBarrier(pi, options) {
|
|
|
4968
5120
|
ownership.reject(error);
|
|
4969
5121
|
};
|
|
4970
5122
|
const finish = () => {
|
|
4971
|
-
if (barrier.dispatch && options.toMessage || claim.entries.length > 0) {
|
|
5123
|
+
if (barrier.source !== "owner-task" && (barrier.dispatch && options.toMessage || claim.entries.length > 0)) {
|
|
4972
5124
|
for (const target of pendingTargets)
|
|
4973
5125
|
drainedTargets.add(target);
|
|
4974
5126
|
drainedTargetsByTerminal.set(terminalKey, drainedTargets);
|
|
@@ -5019,7 +5171,7 @@ function registerTerminalOrderingBarrier(pi, options) {
|
|
|
5019
5171
|
let delivered;
|
|
5020
5172
|
let deliveredAsync;
|
|
5021
5173
|
try {
|
|
5022
|
-
delivered =
|
|
5174
|
+
delivered = deliverPrelude(claim.entries[index]);
|
|
5023
5175
|
deliveredAsync = isPromiseLike(delivered);
|
|
5024
5176
|
} catch (error) {
|
|
5025
5177
|
if (barrier.owner)
|
|
@@ -5035,7 +5187,7 @@ function registerTerminalOrderingBarrier(pi, options) {
|
|
|
5035
5187
|
try {
|
|
5036
5188
|
await delivered;
|
|
5037
5189
|
for (current = index + 1;current < claim.entries.length; current++) {
|
|
5038
|
-
await
|
|
5190
|
+
await deliverPrelude(claim.entries[current]);
|
|
5039
5191
|
}
|
|
5040
5192
|
finish();
|
|
5041
5193
|
} catch (error) {
|
|
@@ -5111,7 +5263,7 @@ async function dispatchRelayFallback(pi, prefix, terminalMessage, stageAdmission
|
|
|
5111
5263
|
}
|
|
5112
5264
|
}
|
|
5113
5265
|
function registerSubagentRelay(pi, deps) {
|
|
5114
|
-
const { getLiveContext, currentSessionTargetMatches, sendIncomingMessage, ensureConnected, resolveSessionTarget
|
|
5266
|
+
const { getLiveContext, currentSessionTargetMatches, sendIncomingMessage, ensureConnected, resolveSessionTarget } = deps;
|
|
5115
5267
|
const localDeliveries = deps.localDeliveryAuthority ?? new DeliveredMessageCache;
|
|
5116
5268
|
function deliverLocalSubagentRelayMessage(sender, status, messageText, terminalBarrier, requestId) {
|
|
5117
5269
|
const now = Date.now();
|
|
@@ -5268,7 +5420,7 @@ ${messageText}`,
|
|
|
5268
5420
|
let target;
|
|
5269
5421
|
try {
|
|
5270
5422
|
activeClient = await ensureConnected("background");
|
|
5271
|
-
target = await
|
|
5423
|
+
target = await resolveSessionTarget(activeClient, parsed.to) ?? parsed.to;
|
|
5272
5424
|
} catch (error) {
|
|
5273
5425
|
if (!relayStillLive()) {
|
|
5274
5426
|
acknowledgeResult(options, parsed.requestId, false, error);
|
|
@@ -5545,6 +5697,20 @@ function framePreStartPendingStageMessage(entry) {
|
|
|
5545
5697
|
|
|
5546
5698
|
Sent: ${framePendingStageTimestamp(entry.message.timestamp)}
|
|
5547
5699
|
|
|
5700
|
+
${entry.bodyText}`
|
|
5701
|
+
};
|
|
5702
|
+
}
|
|
5703
|
+
function isDeliveryFeedback(message) {
|
|
5704
|
+
return Boolean(message.replyTo) && message.replyError !== undefined;
|
|
5705
|
+
}
|
|
5706
|
+
function frameDeliveryFeedback(entry) {
|
|
5707
|
+
return {
|
|
5708
|
+
...entry,
|
|
5709
|
+
replyCommand: undefined,
|
|
5710
|
+
bodyText: `**Intercom delivery failed**
|
|
5711
|
+
|
|
5712
|
+
Sent: ${framePendingStageTimestamp(entry.message.timestamp)}
|
|
5713
|
+
|
|
5548
5714
|
${entry.bodyText}`
|
|
5549
5715
|
};
|
|
5550
5716
|
}
|
|
@@ -5566,6 +5732,7 @@ ${entry.bodyText}`,
|
|
|
5566
5732
|
// dist/builtin/intercom/inbound-idle-queue.ts
|
|
5567
5733
|
class InboundIdleQueue {
|
|
5568
5734
|
entries = [];
|
|
5735
|
+
generation = 0;
|
|
5569
5736
|
get size() {
|
|
5570
5737
|
return this.entries.length;
|
|
5571
5738
|
}
|
|
@@ -5589,6 +5756,7 @@ class InboundIdleQueue {
|
|
|
5589
5756
|
}
|
|
5590
5757
|
claimOrdinarySourceTargets(runId, sourceSessionTargets, terminalAt = Number.POSITIVE_INFINITY) {
|
|
5591
5758
|
const targets = new Set(sourceSessionTargets);
|
|
5759
|
+
const generation = this.generation;
|
|
5592
5760
|
const original = this.entries;
|
|
5593
5761
|
const legacyIdsByName = new Map;
|
|
5594
5762
|
for (const entry of original) {
|
|
@@ -5618,8 +5786,9 @@ class InboundIdleQueue {
|
|
|
5618
5786
|
let settled = false;
|
|
5619
5787
|
return {
|
|
5620
5788
|
entries: selected,
|
|
5789
|
+
isCurrent: () => generation === this.generation,
|
|
5621
5790
|
rollbackFrom: (index) => {
|
|
5622
|
-
if (settled)
|
|
5791
|
+
if (settled || generation !== this.generation)
|
|
5623
5792
|
return;
|
|
5624
5793
|
settled = true;
|
|
5625
5794
|
const undelivered = new Set(selected.slice(index));
|
|
@@ -5629,6 +5798,7 @@ class InboundIdleQueue {
|
|
|
5629
5798
|
};
|
|
5630
5799
|
}
|
|
5631
5800
|
clear() {
|
|
5801
|
+
this.generation++;
|
|
5632
5802
|
this.entries = [];
|
|
5633
5803
|
}
|
|
5634
5804
|
}
|
|
@@ -5954,7 +6124,7 @@ function routeClosedWorkflowStageMessage(entry, admission, tracker, waiter, deli
|
|
|
5954
6124
|
const sourceRunId = entry.message.source?.subagentRunId;
|
|
5955
6125
|
if (sourceRunId !== undefined && ownsSubagentRun(sourceRunId))
|
|
5956
6126
|
return;
|
|
5957
|
-
if (entry.message.expectsReply !== true) {
|
|
6127
|
+
if (entry.message.expectsReply !== true && !isDeliveryFeedback(entry.message)) {
|
|
5958
6128
|
retryStableDelivery({ deliver, isCurrent }).catch(() => {});
|
|
5959
6129
|
return;
|
|
5960
6130
|
}
|
|
@@ -5965,6 +6135,14 @@ function routeClosedWorkflowStageMessage(entry, admission, tracker, waiter, deli
|
|
|
5965
6135
|
admission.commit(admitted.reservation);
|
|
5966
6136
|
return;
|
|
5967
6137
|
}
|
|
6138
|
+
if (isDeliveryFeedback(entry.message)) {
|
|
6139
|
+
retryStableDelivery({ deliver, isCurrent }).then(() => {
|
|
6140
|
+
admission.commit(admitted.reservation);
|
|
6141
|
+
}, (error) => {
|
|
6142
|
+
admission.release(admitted.reservation, error instanceof Error ? error : new Error(String(error)));
|
|
6143
|
+
});
|
|
6144
|
+
return;
|
|
6145
|
+
}
|
|
5968
6146
|
const replyContext = tracker.recordIncomingMessage(entry.from, entry.message);
|
|
5969
6147
|
tracker.queueTurnContext(replyContext);
|
|
5970
6148
|
const delivery = invoke(deliver);
|
|
@@ -6050,6 +6228,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6050
6228
|
};
|
|
6051
6229
|
let client = null;
|
|
6052
6230
|
let clientRegistrationGroup = null;
|
|
6231
|
+
const replyCapability = registerSubagentReplyCapability(pi, () => client);
|
|
6053
6232
|
const config = loadConfig();
|
|
6054
6233
|
const legacyChildOrchestratorMetadata = readChildOrchestratorMetadata();
|
|
6055
6234
|
let runtimeContext = null;
|
|
@@ -6118,7 +6297,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6118
6297
|
}
|
|
6119
6298
|
function currentStatus() {
|
|
6120
6299
|
const activeToolName = activeTools.values().next().value;
|
|
6121
|
-
const
|
|
6300
|
+
const stage = getLiveContext()?.orchestrationContext;
|
|
6301
|
+
const lifecycleStatus = stage?.kind === "workflow-stage" && stage.messageAdmission?.isOpen() === false ? `closed · reply: ${stage.lateMessageRouter === undefined ? "unavailable" : "post-mortem only"}` : activeToolName ? `tool:${activeToolName}` : agentRunning ? "thinking" : "idle";
|
|
6122
6302
|
return config.status ? `${lifecycleStatus} · ${config.status}` : lifecycleStatus;
|
|
6123
6303
|
}
|
|
6124
6304
|
function resolveSessionHomeGroup() {
|
|
@@ -6156,6 +6336,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6156
6336
|
startedAt: sessionStartedAt,
|
|
6157
6337
|
lastActivity: Date.now(),
|
|
6158
6338
|
status: currentStatus(),
|
|
6339
|
+
replyCapability: replyCapability(),
|
|
6159
6340
|
groups: [...currentIntercomGroups()],
|
|
6160
6341
|
group: currentIntercomGroup()
|
|
6161
6342
|
};
|
|
@@ -6257,14 +6438,20 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6257
6438
|
const bodyText = `${message.content.text}${attachmentText}`;
|
|
6258
6439
|
const replyCommand = config.replyHint && message.expectsReply ? `intercom({ action: "reply", message: "..." })` : undefined;
|
|
6259
6440
|
const rawEntry = { from, message, replyCommand, bodyText, ...channel ? { channel } : {} };
|
|
6260
|
-
const
|
|
6441
|
+
const framedEntry = isDeliveryFeedback(message) ? frameDeliveryFeedback(rawEntry) : rawEntry;
|
|
6442
|
+
const entry = receivedBeforeStageStart ? framePreStartPendingStageMessage(framedEntry) : framedEntry;
|
|
6261
6443
|
if (receivedBeforeStageStart) {
|
|
6262
6444
|
return sendIncomingMessage(entry, "prelude", messageGeneration, false);
|
|
6263
6445
|
}
|
|
6264
6446
|
const stageAdmission = liveContext.orchestrationContext?.kind === "workflow-stage" ? liveContext.orchestrationContext.messageAdmission : undefined;
|
|
6265
6447
|
const stageClosed = stageAdmission?.isOpen() === false;
|
|
6266
6448
|
if (stageClosed) {
|
|
6267
|
-
routeClosedWorkflowStageMessage(entry, inboundDeliveries, replyTracker, replyWaiters.pending(), () =>
|
|
6449
|
+
routeClosedWorkflowStageMessage(entry, inboundDeliveries, replyTracker, replyWaiters.pending(), () => {
|
|
6450
|
+
if (message.expectsReply === true && liveContext.orchestrationContext?.lateMessageRouter === undefined) {
|
|
6451
|
+
throw new Error("Workflow stage is closed and cannot reply because post-mortem routing is unavailable. Contact a live stage or start new work with explicit context.");
|
|
6452
|
+
}
|
|
6453
|
+
return sendIncomingMessage(entry, isDeliveryFeedback(message) ? "prelude" : "trigger", messageGeneration, false);
|
|
6454
|
+
}, () => client, () => Boolean(getLiveContext(liveContext, messageGeneration)), (runId) => stageAdmission.boundary.ownsSubagentRun(runId));
|
|
6268
6455
|
return;
|
|
6269
6456
|
}
|
|
6270
6457
|
const admission = inboundDeliveries.admit(from, message);
|
|
@@ -6275,6 +6462,12 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6275
6462
|
inboundDeliveries.commit(reservation);
|
|
6276
6463
|
return;
|
|
6277
6464
|
}
|
|
6465
|
+
if (isDeliveryFeedback(message)) {
|
|
6466
|
+
return retryStableDelivery({
|
|
6467
|
+
deliver: () => sendIncomingMessage(entry, "prelude", messageGeneration, false),
|
|
6468
|
+
isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration))
|
|
6469
|
+
}).then(() => inboundDeliveries.commit(reservation), (error) => inboundDeliveries.release(reservation, toError3(error)));
|
|
6470
|
+
}
|
|
6278
6471
|
const replyContext = replyTracker.recordIncomingMessage(from, message);
|
|
6279
6472
|
const commit = () => {
|
|
6280
6473
|
inboundDeliveries.commit(reservation);
|
|
@@ -6311,9 +6504,11 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6311
6504
|
const activeClient = client;
|
|
6312
6505
|
if (!message.replyTo && activeClient?.isConnected()) {
|
|
6313
6506
|
try {
|
|
6507
|
+
const refusal = "Message not accepted: recipient was busy in non-interactive mode. Its task was not interrupted.";
|
|
6314
6508
|
const result = await activeClient.send(from.id, {
|
|
6315
|
-
text:
|
|
6316
|
-
replyTo: message.id
|
|
6509
|
+
text: refusal,
|
|
6510
|
+
replyTo: message.id,
|
|
6511
|
+
replyError: refusal
|
|
6317
6512
|
});
|
|
6318
6513
|
if (result.delivered && getLiveContext(liveContext, messageGeneration)) {
|
|
6319
6514
|
replyTracker.markReplied(message.id);
|
|
@@ -6581,7 +6776,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6581
6776
|
pendingStageRouteClients.set(runId, state);
|
|
6582
6777
|
if (state.client?.isConnected()) {
|
|
6583
6778
|
state.route = route;
|
|
6584
|
-
state.client.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages);
|
|
6779
|
+
state.client.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent);
|
|
6780
|
+
await state.client.listSessions();
|
|
6585
6781
|
return;
|
|
6586
6782
|
}
|
|
6587
6783
|
if (state.promise) {
|
|
@@ -6593,12 +6789,12 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6593
6789
|
const nextClient = new IntercomClient(`${currentSessionId}:pending-stage-route:${runId}`);
|
|
6594
6790
|
state.client = nextClient;
|
|
6595
6791
|
attachPendingStageRouteClientHandlers(runId, state, nextClient);
|
|
6596
|
-
await nextClient.connect({ ...buildRegistration(), name: undefined, groups: [normalizeGroup(route.group)], group: normalizeGroup(route.group) }, undefined, undefined, readSubagentMessageSource(runtimeContext?.subagentPolicy));
|
|
6792
|
+
await nextClient.connect({ ...buildRegistration(), recipientPurpose: "control", name: undefined, groups: [normalizeGroup(route.group)], group: normalizeGroup(route.group) }, undefined, undefined, readSubagentMessageSource(runtimeContext?.subagentPolicy));
|
|
6597
6793
|
if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
|
|
6598
6794
|
await nextClient.disconnect();
|
|
6599
6795
|
throw new Error("Intercom runtime no longer active");
|
|
6600
6796
|
}
|
|
6601
|
-
nextClient.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages);
|
|
6797
|
+
nextClient.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent);
|
|
6602
6798
|
await nextClient.listSessions();
|
|
6603
6799
|
if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
|
|
6604
6800
|
await nextClient.disconnect();
|
|
@@ -6646,7 +6842,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6646
6842
|
async function registerPendingStageRoute(activeClient, runId, route) {
|
|
6647
6843
|
const routeGroup = normalizeGroup(route.group);
|
|
6648
6844
|
if (clientRegistrationGroup === routeGroup) {
|
|
6649
|
-
activeClient.registerPendingStageRoute(runId, routeGroup, route.capability, route.stages, route.possibleStages);
|
|
6845
|
+
activeClient.registerPendingStageRoute(runId, routeGroup, route.capability, route.stages, route.possibleStages, route.parent);
|
|
6846
|
+
await activeClient.listSessions();
|
|
6650
6847
|
return;
|
|
6651
6848
|
}
|
|
6652
6849
|
await ensurePendingStageRouteClient(runId, { ...route, group: routeGroup });
|
|
@@ -6672,15 +6869,16 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6672
6869
|
let connectFailed = false;
|
|
6673
6870
|
await ownershipRecorded.promise;
|
|
6674
6871
|
const nextClient = new IntercomClient(currentSessionId);
|
|
6675
|
-
const registration = buildRegistration();
|
|
6676
6872
|
client = nextClient;
|
|
6677
6873
|
attachClientHandlers(nextClient);
|
|
6678
6874
|
try {
|
|
6679
6875
|
await testOverrides.beforeConnectAttempt?.(reason);
|
|
6680
6876
|
await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
|
|
6681
6877
|
const childMetadata = currentChildOrchestratorMetadata();
|
|
6682
|
-
await nextClient.connect(
|
|
6878
|
+
await nextClient.connect(buildRegistration(), childMetadata?.supervisor, supervisorAuthorizations.ownerToken, readSubagentMessageSource(runtimeContext?.subagentPolicy), resolveSessionHomeGroup());
|
|
6683
6879
|
clientRegistrationGroup = resolveSessionHomeGroup();
|
|
6880
|
+
if (replyCapability() === "terminal")
|
|
6881
|
+
nextClient.updatePresence({ replyCapability: "terminal" });
|
|
6684
6882
|
await supervisorAuthorizations.restore(nextClient);
|
|
6685
6883
|
for (const [runId, route] of pendingStageRoutes) {
|
|
6686
6884
|
await registerPendingStageRoute(nextClient, runId, route);
|
|
@@ -6734,7 +6932,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6734
6932
|
group: payload.group,
|
|
6735
6933
|
capability: payload.capability,
|
|
6736
6934
|
...payload.stages === undefined ? {} : { stages: payload.stages },
|
|
6737
|
-
...payload.possibleStages === undefined ? {} : { possibleStages: payload.possibleStages }
|
|
6935
|
+
...payload.possibleStages === undefined ? {} : { possibleStages: payload.possibleStages },
|
|
6936
|
+
...payload.parent === undefined ? {} : { parent: payload.parent }
|
|
6738
6937
|
});
|
|
6739
6938
|
const completion = ensureConnected("background").then((activeClient) => registerPendingStageRoute(activeClient, payload.runId, payload));
|
|
6740
6939
|
payload.completion = completion;
|
|
@@ -6942,8 +7141,34 @@ import { Text as Text4 } from "@earendil-works/pi-tui";
|
|
|
6942
7141
|
import { Type as Type3 } from "typebox";
|
|
6943
7142
|
|
|
6944
7143
|
// dist/builtin/intercom/lazy-tool-execution.ts
|
|
7144
|
+
init_recoverable_disconnect();
|
|
7145
|
+
init_retry_policy();
|
|
7146
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
6945
7147
|
async function executeHeavyTool(loadHeavy, name, args) {
|
|
6946
|
-
const
|
|
7148
|
+
const params = args[1];
|
|
7149
|
+
const recoverInitialization = name === "intercom" && ["send", "ask", "reply"].includes(params.action ?? "");
|
|
7150
|
+
let handle;
|
|
7151
|
+
let retries = 0;
|
|
7152
|
+
for (;; ) {
|
|
7153
|
+
if (recoverInitialization && args[2]?.aborted)
|
|
7154
|
+
return initializationFailure("Cancelled", retries);
|
|
7155
|
+
try {
|
|
7156
|
+
handle = await loadHeavy(args[4]);
|
|
7157
|
+
break;
|
|
7158
|
+
} catch (error) {
|
|
7159
|
+
if (!recoverInitialization || !isRecoverableIntercomDisconnect(error))
|
|
7160
|
+
throw error;
|
|
7161
|
+
const delayMs = RECONNECT_DELAYS_MS[retries];
|
|
7162
|
+
if (delayMs === undefined)
|
|
7163
|
+
return initializationFailure("Client disconnected", retries);
|
|
7164
|
+
try {
|
|
7165
|
+
await delay(delayMs, undefined, { signal: args[2] });
|
|
7166
|
+
} catch {
|
|
7167
|
+
return initializationFailure("Cancelled", retries);
|
|
7168
|
+
}
|
|
7169
|
+
retries += 1;
|
|
7170
|
+
}
|
|
7171
|
+
}
|
|
6947
7172
|
handle.assertCurrent();
|
|
6948
7173
|
const tool = handle.heavy.tools.get(name);
|
|
6949
7174
|
if (!tool?.execute)
|
|
@@ -6952,6 +7177,13 @@ async function executeHeavyTool(loadHeavy, name, args) {
|
|
|
6952
7177
|
handle.assertCurrent();
|
|
6953
7178
|
return result;
|
|
6954
7179
|
}
|
|
7180
|
+
function initializationFailure(reason, retries) {
|
|
7181
|
+
return {
|
|
7182
|
+
content: [{ type: "text", text: `${reason}. Intercom initialization stopped after ${retries} automatic retries. This operation was not sent.` }],
|
|
7183
|
+
isError: true,
|
|
7184
|
+
details: { error: true, terminal: true, automaticRetries: retries, outcome: "not_sent" }
|
|
7185
|
+
};
|
|
7186
|
+
}
|
|
6955
7187
|
async function runHeavyCommand(loadHeavy, args, ctx) {
|
|
6956
7188
|
const handle = await loadHeavy(ctx);
|
|
6957
7189
|
handle.assertCurrent();
|
|
@@ -7634,7 +7866,7 @@ function intercom(pi, options = {}) {
|
|
|
7634
7866
|
Use this to communicate findings, request help, or coordinate work with other sessions.
|
|
7635
7867
|
Sessions belong to an intercom group and can ONLY message sessions in the same group; cross-group sends are rejected by the broker. Ungrouped sessions share the "default" group.
|
|
7636
7868
|
For send, live session names and exact full session IDs remain supported. Workflow-stage targets use \`workflow:<rootRunId>/<segment>[/<segment>...]\`; \`*\` matches one segment and \`**\` any depth. Use \`intercom list\` inside the invocation group to see live, pending, and possible future targets with queued counts. \`workflow:<rootRunId>/**\` reaches live stages now and remains sticky for every future stage until root termination; valid targets outside the known set queue with a \`notInKnownSet\` warning and settle undeliverable at terminal only if never delivered. Use \`ask\` only on live targets.
|
|
7637
|
-
|
|
7869
|
+
For send/ask/reply, Intercom retries recoverable disconnects internally up to three times with the same operation identity. Each new tool call is a new operation. If recovery ends with an unknown delivery outcome, do not repeat it automatically.
|
|
7638
7870
|
Usage:
|
|
7639
7871
|
intercom({ action: "list" }) → List sessions in your group
|
|
7640
7872
|
intercom({ action: "list", group: "name" }) → Read-only peek at another group's sessions
|
|
@@ -7643,12 +7875,11 @@ Usage:
|
|
|
7643
7875
|
intercom({ action: "send", to: "session-name", message: "..." }) → Send message (own group only)
|
|
7644
7876
|
intercom({ action: "ask", to: "session-name", message: "..." }) → Ask and wait for reply
|
|
7645
7877
|
intercom({ action: "reply", message: "..." }) → Reply to the active or exact pending ask
|
|
7646
|
-
intercom({ action: "send", to: "session-name", message: "...", retryToken: "..." }) → Claim the exact retry returned by a retryable failure
|
|
7647
7878
|
intercom({ action: "pending" }) → List unresolved inbound asks
|
|
7648
7879
|
intercom({ action: "status" }) → Show connection status and your group
|
|
7649
7880
|
|
|
7650
7881
|
"default" is the shared group; "true" and "auto" are reserved for subagent auto-groups. Joining does not grant cross-group access; contact_supervisor remains the only cross-group path.`,
|
|
7651
|
-
promptSnippet: "Use to coordinate with other local agent sessions in your intercom group.
|
|
7882
|
+
promptSnippet: "Use to coordinate with other local agent sessions in your intercom group. Send/ask/reply retry reconnects internally; do not automatically repeat an unknown delivery outcome.",
|
|
7652
7883
|
parameters: Type3.Object({
|
|
7653
7884
|
action: Type3.String({ description: "Action: 'list', 'join', 'leave', 'send', 'ask', 'reply', 'pending', or 'status'" }),
|
|
7654
7885
|
to: Type3.Optional(Type3.String({ description: "Live session name, exact full session ID, or `workflow:<rootRunId>/<segment>[/<segment>...]` path; `*` matches one segment and `**` any depth. Send queues sticky pending/future delivery and `workflow:<rootRunId>/**` broadcasts to live and future stages; use `ask` only on live targets (for 'send', 'ask', or targeted 'reply')" })),
|
|
@@ -7660,10 +7891,15 @@ Usage:
|
|
|
7660
7891
|
language: Type3.Optional(Type3.String())
|
|
7661
7892
|
}))),
|
|
7662
7893
|
replyTo: Type3.Optional(Type3.String({ description: "Exact pending-ask message ID; disambiguates concurrent asks, including asks from one sender" })),
|
|
7663
|
-
retryToken: Type3.Optional(Type3.String({ minLength: 1, maxLength: 128, description: "Opaque token returned after a retryable send/ask/reply failure. Repeat the exact same action and arguments with it; omit it for fresh operations." })),
|
|
7664
7894
|
group: Type3.Optional(Type3.String({ description: "Group name for 'join'; read-only group filter for 'list'/'status'. 'send'/'ask' are locked to your own group." }))
|
|
7665
7895
|
}),
|
|
7666
|
-
execute: (...args) =>
|
|
7896
|
+
execute: (...args) => {
|
|
7897
|
+
const invocationLease = activeLease;
|
|
7898
|
+
return executeHeavyTool((ctx) => {
|
|
7899
|
+
assertLease(invocationLease);
|
|
7900
|
+
return loadHeavy(ctx);
|
|
7901
|
+
}, "intercom", args);
|
|
7902
|
+
},
|
|
7667
7903
|
renderResult: (...args) => renderHeavyToolResult(loadedHeavy?.heavy ?? null, "intercom", args),
|
|
7668
7904
|
renderCall(args, theme) {
|
|
7669
7905
|
const input = args;
|