@bastani/atomic 0.9.18 → 0.9.19-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +100 -0
- package/dist/builtin/intercom/CHANGELOG.md +16 -0
- package/dist/builtin/intercom/README.md +21 -11
- package/dist/builtin/intercom/broker/broker.ts +73 -9
- package/dist/builtin/intercom/broker/client.ts +4 -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 +34 -5
- package/dist/builtin/intercom/broker/terminal-questions.ts +29 -0
- package/dist/builtin/intercom/index.bundle.mjs +936 -740
- 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 +16 -2
- 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 +27 -0
- package/dist/builtin/subagents/README.md +33 -12
- 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 +1284 -609
- 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 +48 -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 +56236 -25199
- package/dist/builtin/workflows/src/index.js +1217 -547
- 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.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +14 -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 +9 -0
- package/dist/core/agent-session-tasks.d.ts.map +1 -0
- package/dist/core/agent-session-tasks.js +113 -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 +7 -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-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.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/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-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 +11 -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 +32 -0
- package/dist/core/tasks/agent-adapter.d.ts.map +1 -0
- package/dist/core/tasks/agent-adapter.js +71 -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/supervisor.d.ts +121 -0
- package/dist/core/tasks/supervisor.d.ts.map +1 -0
- package/dist/core/tasks/supervisor.js +916 -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 +11 -4
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +52 -8
- 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 +32 -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.map +1 -1
- package/dist/core/tools/resource-selectors.js +15 -7
- 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 +97 -1
- 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 +199 -0
- package/docs/compaction.md +2 -0
- package/docs/development.md +3 -1
- package/docs/docs.json +2 -0
- package/docs/environment-variables.md +1 -1
- package/docs/extensions.md +108 -6
- package/docs/herdr.md +106 -0
- package/docs/intercom.md +38 -35
- package/docs/keybindings.md +19 -2
- package/docs/models/evals.md +222 -147
- package/docs/models/model-selection.md +20 -14
- package/docs/models/pareto-efficiency.md +2 -2
- package/docs/providers.md +48 -46
- package/docs/quickstart.md +2 -2
- package/docs/sdk.md +244 -0
- package/docs/settings.md +15 -3
- package/docs/skills.md +23 -1
- package/docs/subagents.md +71 -9
- package/docs/themes.md +4 -0
- package/docs/tools.md +25 -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 +13 -4
- package/docs/workflows/operations.md +59 -5
- 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 +781 -661
- 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);
|
|
@@ -1096,14 +1147,15 @@ var init_client = __esm(() => {
|
|
|
1096
1147
|
}
|
|
1097
1148
|
});
|
|
1098
1149
|
}
|
|
1099
|
-
registerPendingStageRoute(runId, group, capability, stages, possibleStages) {
|
|
1150
|
+
registerPendingStageRoute(runId, group, capability, stages, possibleStages, parent) {
|
|
1100
1151
|
writeMessage(this.requireActiveSocket(), {
|
|
1101
1152
|
type: "register_pending_stage_route",
|
|
1102
1153
|
runId,
|
|
1103
1154
|
group,
|
|
1104
1155
|
capability,
|
|
1105
1156
|
stages,
|
|
1106
|
-
possibleStages
|
|
1157
|
+
possibleStages,
|
|
1158
|
+
...parent === undefined ? {} : { parent }
|
|
1107
1159
|
});
|
|
1108
1160
|
}
|
|
1109
1161
|
registerLiveWorkflowStageRoute(runId, stageKeys, capability) {
|
|
@@ -1676,15 +1728,6 @@ class InlineMessageComponent {
|
|
|
1676
1728
|
}
|
|
1677
1729
|
var init_inline_message = () => {};
|
|
1678
1730
|
|
|
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
1731
|
// dist/builtin/intercom/reply-waiter.ts
|
|
1689
1732
|
class ReplyWaiterRegistry {
|
|
1690
1733
|
timeoutMs;
|
|
@@ -2264,32 +2307,32 @@ function validateSupervisorInterviewReply(value, interview) {
|
|
|
2264
2307
|
if (!Object.hasOwn(raw, "value")) {
|
|
2265
2308
|
throw new Error(`responses[${index}].value is required`);
|
|
2266
2309
|
}
|
|
2267
|
-
const
|
|
2310
|
+
const value = raw.value;
|
|
2268
2311
|
if (question.type === "single") {
|
|
2269
|
-
if (typeof
|
|
2312
|
+
if (typeof value !== "string")
|
|
2270
2313
|
throw new Error(`responses[${index}].value must be a string for single questions`);
|
|
2271
2314
|
const optionLabels = new Set(question.options?.map(interviewOptionLabel));
|
|
2272
|
-
if (!optionLabels.has(
|
|
2315
|
+
if (!optionLabels.has(value.trim()))
|
|
2273
2316
|
throw new Error(`responses[${index}].value must match one of the question options`);
|
|
2274
|
-
responses.push({ id, value:
|
|
2317
|
+
responses.push({ id, value: value.trim() });
|
|
2275
2318
|
continue;
|
|
2276
2319
|
}
|
|
2277
2320
|
if (question.type === "multi") {
|
|
2278
|
-
if (!Array.isArray(
|
|
2321
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
2279
2322
|
throw new Error(`responses[${index}].value must be an array of strings for multi questions`);
|
|
2280
2323
|
}
|
|
2281
2324
|
const optionLabels = new Set(question.options?.map(interviewOptionLabel));
|
|
2282
|
-
const selected =
|
|
2325
|
+
const selected = value.map((item) => item.trim());
|
|
2283
2326
|
const invalid = selected.find((item) => !optionLabels.has(item));
|
|
2284
2327
|
if (invalid)
|
|
2285
2328
|
throw new Error(`responses[${index}].value contains an option that is not in the question options: ${invalid}`);
|
|
2286
2329
|
responses.push({ id, value: selected });
|
|
2287
2330
|
continue;
|
|
2288
2331
|
}
|
|
2289
|
-
if (typeof
|
|
2332
|
+
if (typeof value !== "string") {
|
|
2290
2333
|
throw new Error(`responses[${index}].value must be a string for ${question.type} questions`);
|
|
2291
2334
|
}
|
|
2292
|
-
responses.push({ id, value
|
|
2335
|
+
responses.push({ id, value });
|
|
2293
2336
|
}
|
|
2294
2337
|
return { responses };
|
|
2295
2338
|
}
|
|
@@ -2395,7 +2438,7 @@ import { randomUUID as randomUUID3 } from "crypto";
|
|
|
2395
2438
|
import { Type } from "typebox";
|
|
2396
2439
|
import { Text as Text2 } from "@earendil-works/pi-tui";
|
|
2397
2440
|
function registerContactSupervisorTool(pi, deps) {
|
|
2398
|
-
const { childOrchestratorMetadata, ensureConnected, syncPresenceIdentity, resolveSessionTarget
|
|
2441
|
+
const { childOrchestratorMetadata, ensureConnected, syncPresenceIdentity, resolveSessionTarget, beginReplyWait } = deps;
|
|
2399
2442
|
const getMetadata = typeof childOrchestratorMetadata === "function" ? childOrchestratorMetadata : () => childOrchestratorMetadata;
|
|
2400
2443
|
let supervisorWaitActive = false;
|
|
2401
2444
|
let supervisorHandoffClaimed = false;
|
|
@@ -2508,13 +2551,6 @@ function registerContactSupervisorTool(pi, deps) {
|
|
|
2508
2551
|
details: { yielded: true }
|
|
2509
2552
|
};
|
|
2510
2553
|
}
|
|
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
2554
|
let connectedClient;
|
|
2519
2555
|
try {
|
|
2520
2556
|
connectedClient = await ensureConnected("tool");
|
|
@@ -2538,7 +2574,7 @@ function registerContactSupervisorTool(pi, deps) {
|
|
|
2538
2574
|
sendTo = connectedClient.supervisorSessionId ?? metadata.supervisor.supervisorSessionId;
|
|
2539
2575
|
} else {
|
|
2540
2576
|
try {
|
|
2541
|
-
sendTo = await
|
|
2577
|
+
sendTo = await resolveSessionTarget(connectedClient, metadata.orchestratorTarget) ?? metadata.orchestratorTarget;
|
|
2542
2578
|
} catch (error) {
|
|
2543
2579
|
return {
|
|
2544
2580
|
content: [{ type: "text", text: `Failed to resolve supervisor target: ${getErrorMessage(error)}` }],
|
|
@@ -2607,7 +2643,7 @@ function registerContactSupervisorTool(pi, deps) {
|
|
|
2607
2643
|
};
|
|
2608
2644
|
}
|
|
2609
2645
|
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);
|
|
2646
|
+
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
2647
|
const sendResult = await connectedClient.sendToSupervisor(sendTo, {
|
|
2612
2648
|
messageId: questionId,
|
|
2613
2649
|
text: requestText,
|
|
@@ -2808,6 +2844,11 @@ class RetryIdentityReservations {
|
|
|
2808
2844
|
}
|
|
2809
2845
|
this.finishRetained(reservation, "settled");
|
|
2810
2846
|
}
|
|
2847
|
+
discard(retryToken) {
|
|
2848
|
+
const reservation = this.tokenReservations.get(retryToken);
|
|
2849
|
+
if (reservation !== undefined)
|
|
2850
|
+
this.expire(reservation);
|
|
2851
|
+
}
|
|
2811
2852
|
remainingRetries(attempt) {
|
|
2812
2853
|
const reservation = this.currentReservation(attempt);
|
|
2813
2854
|
return reservation === undefined ? 0 : Math.max(0, this.maxReuses - reservation.reuseCount);
|
|
@@ -2961,14 +3002,73 @@ var init_retry_identity = __esm(() => {
|
|
|
2961
3002
|
};
|
|
2962
3003
|
});
|
|
2963
3004
|
|
|
3005
|
+
// dist/builtin/intercom/tool-retry.ts
|
|
3006
|
+
import { setTimeout as delay2 } from "node:timers/promises";
|
|
3007
|
+
async function runIntercomOperation(attempt, release, signal) {
|
|
3008
|
+
const deadline = new AbortController;
|
|
3009
|
+
const timer = setTimeout(() => deadline.abort(), RETRY_IDENTITY_TTL_MS);
|
|
3010
|
+
const operationSignal = signal === undefined ? deadline.signal : AbortSignal.any([signal, deadline.signal]);
|
|
3011
|
+
let token;
|
|
3012
|
+
let recovering = false;
|
|
3013
|
+
let retries = 0;
|
|
3014
|
+
let last = {
|
|
3015
|
+
content: [{ type: "text", text: "Cancelled" }],
|
|
3016
|
+
isError: true,
|
|
3017
|
+
details: { error: true }
|
|
3018
|
+
};
|
|
3019
|
+
try {
|
|
3020
|
+
for (;; ) {
|
|
3021
|
+
if (operationSignal.aborted)
|
|
3022
|
+
break;
|
|
3023
|
+
last = await attempt(token, operationSignal);
|
|
3024
|
+
const { retryToken, retryable, deliveryUncertain, ...details } = last.details;
|
|
3025
|
+
last = { ...last, details };
|
|
3026
|
+
if (!last.isError)
|
|
3027
|
+
return last;
|
|
3028
|
+
recovering ||= deliveryUncertain === true || retryable === true;
|
|
3029
|
+
const nextToken = typeof retryToken === "string" ? retryToken : undefined;
|
|
3030
|
+
const canRetry = nextToken !== undefined || token === undefined && retryable === true;
|
|
3031
|
+
token = nextToken ?? token;
|
|
3032
|
+
if (!canRetry) {
|
|
3033
|
+
if (!recovering && retryable !== true)
|
|
3034
|
+
return last;
|
|
3035
|
+
break;
|
|
3036
|
+
}
|
|
3037
|
+
recovering = true;
|
|
3038
|
+
if (retries >= RETRY_IDENTITY_MAX_REUSES || operationSignal.aborted)
|
|
3039
|
+
break;
|
|
3040
|
+
try {
|
|
3041
|
+
await delay2(RECONNECT_DELAYS_MS[retries], undefined, { signal: operationSignal });
|
|
3042
|
+
} catch {
|
|
3043
|
+
break;
|
|
3044
|
+
}
|
|
3045
|
+
retries += 1;
|
|
3046
|
+
}
|
|
3047
|
+
const reason = operationSignal.aborted ? "Cancelled" : last.content.map(({ text }) => text).join(`
|
|
3048
|
+
`);
|
|
3049
|
+
return {
|
|
3050
|
+
content: [{
|
|
3051
|
+
type: "text",
|
|
3052
|
+
text: recovering ? `${reason}
|
|
3053
|
+
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
|
|
3054
|
+
}],
|
|
3055
|
+
isError: true,
|
|
3056
|
+
details: { error: true, terminal: true, automaticRetries: retries, ...recovering ? { outcome: "unknown" } : {} }
|
|
3057
|
+
};
|
|
3058
|
+
} finally {
|
|
3059
|
+
clearTimeout(timer);
|
|
3060
|
+
if (token !== undefined)
|
|
3061
|
+
release(token);
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
var init_tool_retry = __esm(() => {
|
|
3065
|
+
init_retry_identity();
|
|
3066
|
+
init_retry_policy();
|
|
3067
|
+
});
|
|
3068
|
+
|
|
2964
3069
|
// dist/builtin/intercom/intercom-tool.ts
|
|
2965
3070
|
import { Type as Type2 } from "typebox";
|
|
2966
3071
|
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
3072
|
function retryErrorDetails(retryToken) {
|
|
2973
3073
|
return retryToken === undefined ? { error: true } : { error: true, retryToken };
|
|
2974
3074
|
}
|
|
@@ -3086,7 +3186,7 @@ A valid target outside the known set queues speculatively with a \`notInKnownSet
|
|
|
3086
3186
|
undeliverable at terminal only if never delivered. Use \`ask\` only for a live, reply-capable target.
|
|
3087
3187
|
Stage paths win over same-named owned subgroups for send/ask; \`list\` with \`group\` continues to
|
|
3088
3188
|
select the group.
|
|
3089
|
-
|
|
3189
|
+
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
3190
|
|
|
3091
3191
|
Usage:
|
|
3092
3192
|
intercom({ action: "list" }) → List sessions visible through your groups
|
|
@@ -3098,14 +3198,13 @@ Usage:
|
|
|
3098
3198
|
intercom({ action: "send", to: "session-name", message: "..." }) → Send message (shared group only)
|
|
3099
3199
|
intercom({ action: "ask", to: "session-name", message: "..." }) → Ask and wait for reply
|
|
3100
3200
|
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
3201
|
intercom({ action: "pending" }) → List unresolved inbound asks
|
|
3103
3202
|
intercom({ action: "status" }) → Show connection status and all your groups
|
|
3104
3203
|
|
|
3105
3204
|
The "join" action is additive. "default" is the shared default group; "true" and
|
|
3106
3205
|
"auto" are reserved for subagent auto-groups. Ordinary delivery requires at least
|
|
3107
3206
|
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.
|
|
3207
|
+
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
3208
|
parameters: Type2.Object({
|
|
3110
3209
|
action: Type2.String({
|
|
3111
3210
|
description: "Action: 'list', 'groups', 'join', 'leave', 'send', 'ask', 'reply', 'pending', or 'status'"
|
|
@@ -3125,78 +3224,25 @@ one shared membership; contact_supervisor remains the only cross-group path.`,
|
|
|
3125
3224
|
replyTo: Type2.Optional(Type2.String({
|
|
3126
3225
|
description: "Exact pending-ask message ID; disambiguates concurrent asks, including asks from one sender"
|
|
3127
3226
|
})),
|
|
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
3227
|
group: Type2.Optional(Type2.String({
|
|
3134
3228
|
description: "Group name for 'join' or optional targeted 'leave'; read-only group filter for 'list'/'status'. 'send'/'ask' use shared memberships."
|
|
3135
3229
|
}))
|
|
3136
3230
|
}),
|
|
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;
|
|
3231
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
3232
|
+
if ("retryToken" in params) {
|
|
3165
3233
|
return {
|
|
3166
|
-
content: [{
|
|
3167
|
-
type: "text",
|
|
3168
|
-
text: `Intercom not connected: ${getErrorMessage(error)}${retryTokenGuidance(retainedToken, retryPreflightRemaining ?? 0)}`
|
|
3169
|
-
}],
|
|
3234
|
+
content: [{ type: "text", text: "Intercom manages retries internally. Caller-supplied retry tokens are not supported; this call was not sent." }],
|
|
3170
3235
|
isError: true,
|
|
3171
|
-
details:
|
|
3236
|
+
details: { error: true }
|
|
3172
3237
|
};
|
|
3173
3238
|
}
|
|
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) {
|
|
3239
|
+
const toolSessionId = ctx.sessionManager.getSessionId();
|
|
3240
|
+
const { action, to, message, replyTo, group } = params;
|
|
3241
|
+
const attachments = params.attachments?.map((attachment) => ({ ...attachment }));
|
|
3242
|
+
const executeAttempt = async (retryToken, _signal) => {
|
|
3243
|
+
if (retryToken !== undefined) {
|
|
3244
|
+
if (action !== "send" && action !== "ask" && action !== "reply") {
|
|
3245
|
+
const error = new RetryTokenError("mismatch");
|
|
3200
3246
|
return {
|
|
3201
3247
|
content: [{ type: "text", text: getErrorMessage(error) }],
|
|
3202
3248
|
isError: true,
|
|
@@ -3204,174 +3250,256 @@ one shared membership; contact_supervisor remains the only cross-group path.`,
|
|
|
3204
3250
|
};
|
|
3205
3251
|
}
|
|
3206
3252
|
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
|
-
};
|
|
3253
|
+
retryIdentities.validateRetryToken(retryToken, toolSessionId, action);
|
|
3214
3254
|
} catch (error) {
|
|
3215
3255
|
return {
|
|
3216
|
-
content: [{ type: "text", text:
|
|
3256
|
+
content: [{ type: "text", text: getErrorMessage(error) }],
|
|
3217
3257
|
isError: true,
|
|
3218
3258
|
details: { error: true }
|
|
3219
3259
|
};
|
|
3220
3260
|
}
|
|
3221
3261
|
}
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3262
|
+
let connectedClient;
|
|
3263
|
+
try {
|
|
3264
|
+
connectedClient = await ensureConnected("tool");
|
|
3265
|
+
} catch (error) {
|
|
3266
|
+
const retainedToken = retryToken !== undefined && isRecoverableIntercomDisconnect(error) ? retryToken : undefined;
|
|
3267
|
+
return {
|
|
3268
|
+
content: [{
|
|
3269
|
+
type: "text",
|
|
3270
|
+
text: `Intercom not connected: ${getErrorMessage(error)}`
|
|
3271
|
+
}],
|
|
3272
|
+
isError: true,
|
|
3273
|
+
details: { ...retryErrorDetails(retainedToken), retryable: isRecoverableIntercomDisconnect(error) }
|
|
3274
|
+
};
|
|
3275
|
+
}
|
|
3276
|
+
syncPresenceIdentity(toolSessionId);
|
|
3277
|
+
const resolveOwnGroups = (sessions) => {
|
|
3278
|
+
if (Array.isArray(connectedClient.groups)) {
|
|
3279
|
+
return connectedClient.groups.map((membership) => normalizeGroup(membership));
|
|
3280
|
+
}
|
|
3281
|
+
const self = sessions?.find((session) => session.id === connectedClient.sessionId);
|
|
3282
|
+
return [...normalizeGroups(self?.groups, self?.group)];
|
|
3283
|
+
};
|
|
3284
|
+
const isOnlyOwnGroup = (candidate, ownGroups) => candidate !== undefined && ownGroups.length === 1 && ownGroups[0] === candidate;
|
|
3285
|
+
const requestedGroup = typeof group === "string" && group.trim() ? normalizeGroup(group) : undefined;
|
|
3286
|
+
if ((action === "send" || action === "ask") && requestedGroup) {
|
|
3287
|
+
const ownGroups = resolveOwnGroups();
|
|
3288
|
+
if (!ownGroups.includes(requestedGroup)) {
|
|
3230
3289
|
return {
|
|
3231
|
-
content: [{ type: "text", text: `
|
|
3290
|
+
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
3291
|
isError: true,
|
|
3233
3292
|
details: { error: true }
|
|
3234
3293
|
};
|
|
3235
3294
|
}
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3295
|
+
}
|
|
3296
|
+
switch (action) {
|
|
3297
|
+
case "join": {
|
|
3298
|
+
let targetGroup;
|
|
3299
|
+
try {
|
|
3300
|
+
targetGroup = validateRuntimeGroup(group);
|
|
3301
|
+
} catch (error) {
|
|
3302
|
+
return {
|
|
3303
|
+
content: [{ type: "text", text: getErrorMessage(error) }],
|
|
3304
|
+
isError: true,
|
|
3305
|
+
details: { error: true }
|
|
3306
|
+
};
|
|
3307
|
+
}
|
|
3308
|
+
try {
|
|
3309
|
+
const groups = await connectedClient.joinGroup(targetGroup);
|
|
3246
3310
|
deps.setJoinedGroups(groups);
|
|
3311
|
+
return {
|
|
3312
|
+
content: [{ type: "text", text: `Joined intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.` }],
|
|
3313
|
+
isError: false,
|
|
3314
|
+
details: { group: targetGroup, groups }
|
|
3315
|
+
};
|
|
3316
|
+
} catch (error) {
|
|
3317
|
+
return {
|
|
3318
|
+
content: [{ type: "text", text: `Failed to join group: ${getErrorMessage(error)}` }],
|
|
3319
|
+
isError: true,
|
|
3320
|
+
details: { error: true }
|
|
3321
|
+
};
|
|
3247
3322
|
}
|
|
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
3323
|
}
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3324
|
+
case "leave": {
|
|
3325
|
+
let targetGroup;
|
|
3326
|
+
let homeGroup;
|
|
3327
|
+
try {
|
|
3328
|
+
targetGroup = typeof group === "string" && group.trim().length > 0 ? validateRuntimeGroup(group) : undefined;
|
|
3329
|
+
if (targetGroup === undefined)
|
|
3330
|
+
homeGroup = validateRuntimeGroup(deps.homeGroup());
|
|
3331
|
+
} catch (error) {
|
|
3332
|
+
return {
|
|
3333
|
+
content: [{ type: "text", text: `Cannot leave intercom group: ${getErrorMessage(error)}` }],
|
|
3334
|
+
isError: true,
|
|
3335
|
+
details: { error: true }
|
|
3336
|
+
};
|
|
3337
|
+
}
|
|
3338
|
+
try {
|
|
3339
|
+
let groups;
|
|
3340
|
+
if (targetGroup === undefined) {
|
|
3341
|
+
if (homeGroup === undefined)
|
|
3342
|
+
throw new Error("Intercom home group is unavailable");
|
|
3343
|
+
await connectedClient.updatePresenceAcked({ groups: [homeGroup] });
|
|
3344
|
+
groups = connectedClient.groups;
|
|
3345
|
+
deps.clearJoinedGroups();
|
|
3346
|
+
} else {
|
|
3347
|
+
groups = await connectedClient.leaveGroup(targetGroup);
|
|
3348
|
+
deps.setJoinedGroups(groups);
|
|
3349
|
+
}
|
|
3350
|
+
const text = targetGroup === undefined ? `Returned to home intercom membership. Memberships: ${groups.join(", ")}.` : `Left intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.`;
|
|
3351
|
+
return {
|
|
3352
|
+
content: [{ type: "text", text }],
|
|
3353
|
+
isError: false,
|
|
3354
|
+
details: targetGroup === undefined ? { group: homeGroup, groups } : { groups }
|
|
3355
|
+
};
|
|
3356
|
+
} catch (error) {
|
|
3357
|
+
return {
|
|
3358
|
+
content: [{ type: "text", text: `Failed to leave group: ${getErrorMessage(error)}` }],
|
|
3359
|
+
isError: true,
|
|
3360
|
+
details: { error: true }
|
|
3361
|
+
};
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
case "groups": {
|
|
3365
|
+
try {
|
|
3366
|
+
const groups = await connectedClient.listGroups();
|
|
3367
|
+
const lines = groups.map(({ group: groupName, sessionCount, member }) => `- ${groupName} — ${sessionCount} session${sessionCount === 1 ? "" : "s"}${member ? " [member]" : ""}`);
|
|
3368
|
+
return {
|
|
3369
|
+
content: [{ type: "text", text: `**Intercom groups:**
|
|
3268
3370
|
${lines.join(`
|
|
3269
3371
|
`)}` }],
|
|
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) {
|
|
3372
|
+
isError: false,
|
|
3373
|
+
details: { groups }
|
|
3374
|
+
};
|
|
3375
|
+
} catch (error) {
|
|
3288
3376
|
return {
|
|
3289
|
-
content: [{ type: "text", text:
|
|
3377
|
+
content: [{ type: "text", text: `Failed to list groups: ${getErrorMessage(error)}` }],
|
|
3290
3378
|
isError: true,
|
|
3291
3379
|
details: { error: true }
|
|
3292
3380
|
};
|
|
3293
3381
|
}
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
const
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3382
|
+
}
|
|
3383
|
+
case "list": {
|
|
3384
|
+
try {
|
|
3385
|
+
const mySessionId = connectedClient.sessionId;
|
|
3386
|
+
const ownDirectory = await listDirectory(connectedClient);
|
|
3387
|
+
const ownSessions = ownDirectory.sessions;
|
|
3388
|
+
const currentSession = ownSessions.find((session) => session.id === mySessionId);
|
|
3389
|
+
if (!currentSession) {
|
|
3390
|
+
return {
|
|
3391
|
+
content: [{ type: "text", text: "Current session is missing from intercom session list." }],
|
|
3392
|
+
isError: true,
|
|
3393
|
+
details: { error: true }
|
|
3394
|
+
};
|
|
3395
|
+
}
|
|
3396
|
+
const ownGroups = resolveOwnGroups(ownSessions);
|
|
3397
|
+
if (requestedGroup && !isOnlyOwnGroup(requestedGroup, ownGroups)) {
|
|
3398
|
+
const peeked = await listDirectory(connectedClient, requestedGroup);
|
|
3399
|
+
const rows = [
|
|
3400
|
+
...peeked.sessions.map((session) => formatSessionListRow(session, currentSession.cwd, session.id === mySessionId)),
|
|
3401
|
+
...peeked.workflowStages.map(formatWorkflowStageRow),
|
|
3402
|
+
...(peeked.workflowFutureStages ?? []).map(formatWorkflowFutureStageRow)
|
|
3403
|
+
];
|
|
3404
|
+
const section = rows.length === 0 ? `**Group [${requestedGroup}] (read-only peek):**
|
|
3303
3405
|
No sessions or workflow stages in this group.` : `**Group [${requestedGroup}] (read-only peek):**
|
|
3304
3406
|
${rows.join(`
|
|
3305
3407
|
`)}`;
|
|
3306
|
-
|
|
3307
|
-
|
|
3408
|
+
return {
|
|
3409
|
+
content: [{ type: "text", text: `Your groups: ${ownGroups.join(", ")}
|
|
3308
3410
|
|
|
3309
3411
|
${section}` }],
|
|
3412
|
+
isError: false,
|
|
3413
|
+
details: {
|
|
3414
|
+
group: ownGroups.at(-1),
|
|
3415
|
+
groups: ownGroups,
|
|
3416
|
+
peekGroup: requestedGroup,
|
|
3417
|
+
workflowStages: peeked.workflowStages,
|
|
3418
|
+
...(peeked.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: peeked.workflowFutureStages }
|
|
3419
|
+
}
|
|
3420
|
+
};
|
|
3421
|
+
}
|
|
3422
|
+
const otherSessions = ownSessions.filter((session) => session.id !== mySessionId);
|
|
3423
|
+
const currentSection = `**Current session** (groups: ${ownGroups.join(", ")}):
|
|
3424
|
+
${formatSessionListRow(currentSession, currentSession.cwd, true)}`;
|
|
3425
|
+
const visibleRows = [
|
|
3426
|
+
...otherSessions.map((session) => formatSessionListRow(session, currentSession.cwd, false)),
|
|
3427
|
+
...ownDirectory.workflowStages.map(formatWorkflowStageRow),
|
|
3428
|
+
...(ownDirectory.workflowFutureStages ?? []).map(formatWorkflowFutureStageRow)
|
|
3429
|
+
];
|
|
3430
|
+
const otherSection = visibleRows.length === 0 ? `**Other sessions and workflow stages:**
|
|
3431
|
+
No other sessions or workflow stages share any of your groups.` : `**Other visible sessions and workflow stages:**
|
|
3432
|
+
${visibleRows.join(`
|
|
3433
|
+
`)}`;
|
|
3434
|
+
return {
|
|
3435
|
+
content: [{ type: "text", text: `${currentSection}
|
|
3436
|
+
|
|
3437
|
+
${otherSection}` }],
|
|
3310
3438
|
isError: false,
|
|
3311
3439
|
details: {
|
|
3312
3440
|
group: ownGroups.at(-1),
|
|
3313
3441
|
groups: ownGroups,
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
...(peeked.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: peeked.workflowFutureStages }
|
|
3442
|
+
...ownDirectory.workflowStages.length === 0 ? {} : { workflowStages: ownDirectory.workflowStages },
|
|
3443
|
+
...(ownDirectory.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: ownDirectory.workflowFutureStages }
|
|
3317
3444
|
}
|
|
3318
3445
|
};
|
|
3446
|
+
} catch (error) {
|
|
3447
|
+
return {
|
|
3448
|
+
content: [{ type: "text", text: `Failed to list sessions: ${getErrorMessage(error)}` }],
|
|
3449
|
+
isError: true,
|
|
3450
|
+
details: { error: true }
|
|
3451
|
+
};
|
|
3319
3452
|
}
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3453
|
+
}
|
|
3454
|
+
case "send": {
|
|
3455
|
+
if (!to || !message) {
|
|
3456
|
+
const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
|
|
3457
|
+
return {
|
|
3458
|
+
content: [{ type: "text", text: errorText }],
|
|
3459
|
+
isError: true,
|
|
3460
|
+
details: { error: true }
|
|
3461
|
+
};
|
|
3462
|
+
}
|
|
3463
|
+
if (_signal?.aborted) {
|
|
3464
|
+
return {
|
|
3465
|
+
content: [{
|
|
3466
|
+
type: "text",
|
|
3467
|
+
text: "Cancelled"
|
|
3468
|
+
}],
|
|
3469
|
+
isError: true,
|
|
3470
|
+
details: retryErrorDetails(retryToken)
|
|
3471
|
+
};
|
|
3472
|
+
}
|
|
3473
|
+
let retryIdentity;
|
|
3474
|
+
try {
|
|
3475
|
+
if (retryToken === undefined) {
|
|
3476
|
+
retryIdentity = retryIdentities.begin({
|
|
3477
|
+
sessionId: toolSessionId,
|
|
3478
|
+
action: "send",
|
|
3479
|
+
target: to,
|
|
3480
|
+
text: message,
|
|
3481
|
+
attachments,
|
|
3482
|
+
replyTo,
|
|
3483
|
+
expectsReply: false
|
|
3484
|
+
});
|
|
3485
|
+
}
|
|
3486
|
+
if (retryToken === undefined && !replyTo && deps.confirmSend && ctx.hasUI) {
|
|
3487
|
+
const attachmentText = attachments?.length ? formatAttachments(attachments) : "";
|
|
3488
|
+
const confirmed = await ctx.ui.confirm("Send Message", `Send to "${to}":
|
|
3334
3489
|
|
|
3335
|
-
${
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3490
|
+
${message}${attachmentText}`);
|
|
3491
|
+
if (!confirmed) {
|
|
3492
|
+
if (retryIdentity !== undefined)
|
|
3493
|
+
retryIdentities.release(retryIdentity);
|
|
3494
|
+
retryIdentity = undefined;
|
|
3495
|
+
return {
|
|
3496
|
+
content: [{ type: "text", text: "Message cancelled by user" }],
|
|
3497
|
+
isError: false,
|
|
3498
|
+
details: {}
|
|
3499
|
+
};
|
|
3500
|
+
}
|
|
3342
3501
|
}
|
|
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({
|
|
3502
|
+
retryIdentity ??= retryIdentities.begin({
|
|
3375
3503
|
sessionId: toolSessionId,
|
|
3376
3504
|
action: "send",
|
|
3377
3505
|
target: to,
|
|
@@ -3379,63 +3507,79 @@ ${otherSection}` }],
|
|
|
3379
3507
|
attachments,
|
|
3380
3508
|
replyTo,
|
|
3381
3509
|
expectsReply: false
|
|
3510
|
+
}, retryToken);
|
|
3511
|
+
const sendTo = await resolveTarget(connectedClient, to) ?? to;
|
|
3512
|
+
if (_signal?.aborted) {
|
|
3513
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3514
|
+
retryIdentity = undefined;
|
|
3515
|
+
return {
|
|
3516
|
+
content: [{ type: "text", text: "Cancelled" }],
|
|
3517
|
+
isError: true,
|
|
3518
|
+
details: retryErrorDetails(retained.retryToken)
|
|
3519
|
+
};
|
|
3520
|
+
}
|
|
3521
|
+
if (sendTo === connectedClient.sessionId) {
|
|
3522
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3523
|
+
retryIdentity = undefined;
|
|
3524
|
+
return {
|
|
3525
|
+
content: [{
|
|
3526
|
+
type: "text",
|
|
3527
|
+
text: "Cannot message the current session"
|
|
3528
|
+
}],
|
|
3529
|
+
isError: true,
|
|
3530
|
+
details: retryErrorDetails(retained.retryToken)
|
|
3531
|
+
};
|
|
3532
|
+
}
|
|
3533
|
+
const result = await connectedClient.send(sendTo, {
|
|
3534
|
+
messageId: retryIdentity.messageId,
|
|
3535
|
+
logicalTarget: to,
|
|
3536
|
+
text: message,
|
|
3537
|
+
attachments,
|
|
3538
|
+
replyTo
|
|
3382
3539
|
});
|
|
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);
|
|
3540
|
+
if (result.queued === true) {
|
|
3541
|
+
retryIdentities.release(retryIdentity);
|
|
3392
3542
|
retryIdentity = undefined;
|
|
3543
|
+
pi.appendEntry("intercom_sent", {
|
|
3544
|
+
to,
|
|
3545
|
+
message: { text: message, attachments, replyTo },
|
|
3546
|
+
messageId: result.id,
|
|
3547
|
+
timestamp: Date.now()
|
|
3548
|
+
});
|
|
3549
|
+
const notInKnownSet = result.notInKnownSet === true;
|
|
3393
3550
|
return {
|
|
3394
|
-
content: [{
|
|
3551
|
+
content: [{
|
|
3552
|
+
type: "text",
|
|
3553
|
+
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}`
|
|
3554
|
+
}],
|
|
3395
3555
|
isError: false,
|
|
3396
|
-
details: {
|
|
3556
|
+
details: {
|
|
3557
|
+
messageId: result.id,
|
|
3558
|
+
delivered: false,
|
|
3559
|
+
queued: true,
|
|
3560
|
+
target: result.target,
|
|
3561
|
+
position: result.position,
|
|
3562
|
+
...notInKnownSet ? { notInKnownSet: true } : {}
|
|
3563
|
+
}
|
|
3564
|
+
};
|
|
3565
|
+
}
|
|
3566
|
+
if (!result.delivered) {
|
|
3567
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3568
|
+
retryIdentity = undefined;
|
|
3569
|
+
const errorText = result.reason ?? "Session may not exist or has disconnected.";
|
|
3570
|
+
return {
|
|
3571
|
+
content: [{
|
|
3572
|
+
type: "text",
|
|
3573
|
+
text: `Message to "${to}" was not delivered: ${errorText}`
|
|
3574
|
+
}],
|
|
3575
|
+
isError: true,
|
|
3576
|
+
details: retryToken === undefined ? { messageId: result.id, delivered: false, reason: result.reason } : {
|
|
3577
|
+
delivered: false,
|
|
3578
|
+
reason: result.reason,
|
|
3579
|
+
...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
|
|
3580
|
+
}
|
|
3397
3581
|
};
|
|
3398
3582
|
}
|
|
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
3583
|
retryIdentities.release(retryIdentity);
|
|
3440
3584
|
retryIdentity = undefined;
|
|
3441
3585
|
pi.appendEntry("intercom_sent", {
|
|
@@ -3444,376 +3588,378 @@ ${message}${attachmentText}`);
|
|
|
3444
3588
|
messageId: result.id,
|
|
3445
3589
|
timestamp: Date.now()
|
|
3446
3590
|
});
|
|
3447
|
-
|
|
3591
|
+
if (replyTo)
|
|
3592
|
+
activeReplyTracker().markReplied(replyTo);
|
|
3448
3593
|
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
|
-
}],
|
|
3594
|
+
content: [{ type: "text", text: `Message sent to ${to}` }],
|
|
3453
3595
|
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
|
-
}
|
|
3596
|
+
details: { messageId: result.id, delivered: true }
|
|
3462
3597
|
};
|
|
3463
|
-
}
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
retryIdentity
|
|
3467
|
-
|
|
3598
|
+
} catch (error) {
|
|
3599
|
+
let failure = error;
|
|
3600
|
+
let retained;
|
|
3601
|
+
if (retryIdentity !== undefined) {
|
|
3602
|
+
if (isRecoverableIntercomDisconnect(error)) {
|
|
3603
|
+
try {
|
|
3604
|
+
retained = retainRecoverableRetry(retryIdentities, retryIdentity);
|
|
3605
|
+
} catch (retentionError) {
|
|
3606
|
+
failure = retentionError;
|
|
3607
|
+
}
|
|
3608
|
+
} else {
|
|
3609
|
+
retryIdentities.release(retryIdentity);
|
|
3610
|
+
}
|
|
3611
|
+
}
|
|
3468
3612
|
return {
|
|
3469
3613
|
content: [{
|
|
3470
3614
|
type: "text",
|
|
3471
|
-
text: `
|
|
3615
|
+
text: `Failed to send: ${getErrorMessage(failure)}`
|
|
3472
3616
|
}],
|
|
3473
3617
|
isError: true,
|
|
3474
|
-
details:
|
|
3475
|
-
delivered: false,
|
|
3476
|
-
reason: result.reason,
|
|
3477
|
-
...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
|
|
3478
|
-
}
|
|
3618
|
+
details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error) }
|
|
3479
3619
|
};
|
|
3480
3620
|
}
|
|
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
3621
|
}
|
|
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;
|
|
3622
|
+
case "ask": {
|
|
3623
|
+
if (!to) {
|
|
3624
|
+
const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
|
|
3576
3625
|
return {
|
|
3577
|
-
content: [{
|
|
3578
|
-
type: "text",
|
|
3579
|
-
text: `Cancelled${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
|
|
3580
|
-
}],
|
|
3626
|
+
content: [{ type: "text", text: errorText }],
|
|
3581
3627
|
isError: true,
|
|
3582
|
-
details:
|
|
3628
|
+
details: { error: true }
|
|
3583
3629
|
};
|
|
3584
3630
|
}
|
|
3585
|
-
if (
|
|
3586
|
-
const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3587
|
-
retryIdentity = undefined;
|
|
3631
|
+
if (_signal?.aborted) {
|
|
3588
3632
|
return {
|
|
3589
3633
|
content: [{
|
|
3590
3634
|
type: "text",
|
|
3591
|
-
text:
|
|
3635
|
+
text: "Cancelled"
|
|
3592
3636
|
}],
|
|
3593
3637
|
isError: true,
|
|
3594
|
-
details: retryErrorDetails(
|
|
3638
|
+
details: retryErrorDetails(retryToken)
|
|
3595
3639
|
};
|
|
3596
3640
|
}
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3641
|
+
let wait = null;
|
|
3642
|
+
let retryIdentity;
|
|
3643
|
+
let askDelivered = false;
|
|
3644
|
+
try {
|
|
3645
|
+
retryIdentity = retryIdentities.begin({
|
|
3646
|
+
sessionId: toolSessionId,
|
|
3647
|
+
action: "ask",
|
|
3648
|
+
target: to,
|
|
3649
|
+
text: message ?? "",
|
|
3650
|
+
attachments,
|
|
3651
|
+
replyTo,
|
|
3652
|
+
expectsReply: true
|
|
3653
|
+
}, retryToken);
|
|
3654
|
+
const metadata = getMetadata();
|
|
3655
|
+
const currentSupervisorId = connectedClient.supervisorSessionId ?? undefined;
|
|
3656
|
+
const metadataSupervisorId = metadata?.supervisor?.supervisorSessionId;
|
|
3657
|
+
const directParentTarget = Boolean(metadata && (to === metadata.orchestratorTarget || to === currentSupervisorId || to === metadataSupervisorId));
|
|
3658
|
+
let parentTarget = directParentTarget;
|
|
3659
|
+
const claimParentAsk = (resolvedTargetId) => Boolean(metadata && requestParentAskHandoff(pi.events, metadata, {
|
|
3660
|
+
kind: "intercom",
|
|
3661
|
+
question: typeof message === "string" ? message : "",
|
|
3662
|
+
attachments: params.attachments,
|
|
3663
|
+
resolvedTargetId
|
|
3664
|
+
}));
|
|
3665
|
+
if (retryToken === undefined && directParentTarget && claimParentAsk(currentSupervisorId ?? metadataSupervisorId ?? to)) {
|
|
3666
|
+
retryIdentities.release(retryIdentity);
|
|
3667
|
+
retryIdentity = undefined;
|
|
3668
|
+
return {
|
|
3669
|
+
content: [{ type: "text", text: "Parent ask claimed; this child is ending for a fresh subagent start." }],
|
|
3670
|
+
isError: false,
|
|
3671
|
+
details: { yielded: true }
|
|
3672
|
+
};
|
|
3673
|
+
}
|
|
3674
|
+
const sendTo = await resolveTarget(connectedClient, to) ?? to;
|
|
3675
|
+
if (_signal?.aborted) {
|
|
3676
|
+
const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3677
|
+
retryIdentity = undefined;
|
|
3678
|
+
return {
|
|
3679
|
+
content: [{
|
|
3680
|
+
type: "text",
|
|
3681
|
+
text: "Cancelled"
|
|
3682
|
+
}],
|
|
3683
|
+
isError: true,
|
|
3684
|
+
details: retryErrorDetails(retained?.retryToken)
|
|
3685
|
+
};
|
|
3686
|
+
}
|
|
3687
|
+
if (sendTo === connectedClient.sessionId) {
|
|
3688
|
+
const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3689
|
+
retryIdentity = undefined;
|
|
3690
|
+
return {
|
|
3691
|
+
content: [{
|
|
3692
|
+
type: "text",
|
|
3693
|
+
text: "Cannot message the current session"
|
|
3694
|
+
}],
|
|
3695
|
+
isError: true,
|
|
3696
|
+
details: retryErrorDetails(retained?.retryToken)
|
|
3697
|
+
};
|
|
3698
|
+
}
|
|
3699
|
+
if (metadata && !directParentTarget) {
|
|
3700
|
+
const authoritativeParent = [currentSupervisorId, metadataSupervisorId].find((candidate) => candidate === sendTo);
|
|
3701
|
+
const resolvedParent = authoritativeParent ?? await resolveTarget(connectedClient, metadata.orchestratorTarget);
|
|
3702
|
+
parentTarget = resolvedParent !== null && resolvedParent === sendTo;
|
|
3703
|
+
if (retryToken === undefined && parentTarget && claimParentAsk(sendTo)) {
|
|
3704
|
+
retryIdentities.release(retryIdentity);
|
|
3705
|
+
retryIdentity = undefined;
|
|
3706
|
+
return {
|
|
3707
|
+
content: [{ type: "text", text: "Parent ask claimed; this child is ending for a fresh subagent start." }],
|
|
3708
|
+
isError: false,
|
|
3709
|
+
details: { yielded: true }
|
|
3710
|
+
};
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
if (!message && !parentTarget) {
|
|
3714
|
+
retryIdentities.release(retryIdentity);
|
|
3715
|
+
retryIdentity = undefined;
|
|
3716
|
+
return {
|
|
3717
|
+
content: [{ type: "text", text: "Missing 'to' or 'message' parameter" }],
|
|
3718
|
+
isError: true,
|
|
3719
|
+
details: { error: true }
|
|
3720
|
+
};
|
|
3721
|
+
}
|
|
3722
|
+
const replySender = await resolveReplySender(connectedClient, to, sendTo);
|
|
3723
|
+
if (replySender.kind === "ambiguous") {
|
|
3724
|
+
const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3725
|
+
retryIdentity = undefined;
|
|
3726
|
+
return {
|
|
3727
|
+
content: [{
|
|
3728
|
+
type: "text",
|
|
3729
|
+
text: `Message to "${to}" is ambiguous: ${replySender.reason}. Use the exact target shown by intercom list.`
|
|
3730
|
+
}],
|
|
3731
|
+
isError: true,
|
|
3732
|
+
details: retryErrorDetails(retained?.retryToken)
|
|
3733
|
+
};
|
|
3734
|
+
}
|
|
3735
|
+
const questionId = retryIdentity.messageId;
|
|
3736
|
+
const replyFrom = replySender.kind === "resolved" ? replySender.sessionId : sendTo;
|
|
3737
|
+
const admission = beginReplyWait(replyFrom, questionId, _signal);
|
|
3738
|
+
if (!admission.ok) {
|
|
3739
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3740
|
+
retryIdentity = undefined;
|
|
3741
|
+
const text = admission.reason === "busy" ? `Too many pending asks (${admission.limit}); reply-wait slots are full` : "Cancelled";
|
|
3742
|
+
return {
|
|
3743
|
+
content: [{
|
|
3744
|
+
type: "text",
|
|
3745
|
+
text
|
|
3746
|
+
}],
|
|
3747
|
+
isError: true,
|
|
3748
|
+
details: retryErrorDetails(retained.retryToken)
|
|
3749
|
+
};
|
|
3750
|
+
}
|
|
3751
|
+
wait = admission.wait;
|
|
3752
|
+
const sendResult = await connectedClient.send(sendTo, {
|
|
3753
|
+
messageId: questionId,
|
|
3754
|
+
logicalTarget: to,
|
|
3755
|
+
text: message ?? "",
|
|
3756
|
+
attachments,
|
|
3757
|
+
replyTo,
|
|
3758
|
+
expectsReply: true
|
|
3759
|
+
});
|
|
3760
|
+
if (sendResult.queued === true) {
|
|
3601
3761
|
retryIdentities.release(retryIdentity);
|
|
3602
3762
|
retryIdentity = undefined;
|
|
3763
|
+
wait.cancel(new Error(`Message queued for ${to}`));
|
|
3764
|
+
pi.appendEntry("intercom_sent", {
|
|
3765
|
+
to,
|
|
3766
|
+
message: { text: message, attachments, replyTo },
|
|
3767
|
+
messageId: sendResult.id,
|
|
3768
|
+
timestamp: Date.now()
|
|
3769
|
+
});
|
|
3603
3770
|
return {
|
|
3604
|
-
content: [{ type: "text", text:
|
|
3771
|
+
content: [{ type: "text", text: `Message queued for ${to}` }],
|
|
3605
3772
|
isError: false,
|
|
3606
|
-
details: {
|
|
3773
|
+
details: {
|
|
3774
|
+
messageId: sendResult.id,
|
|
3775
|
+
delivered: false,
|
|
3776
|
+
queued: true,
|
|
3777
|
+
target: sendResult.target,
|
|
3778
|
+
position: sendResult.position
|
|
3779
|
+
}
|
|
3607
3780
|
};
|
|
3608
3781
|
}
|
|
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}`));
|
|
3782
|
+
if (!sendResult.delivered) {
|
|
3783
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3784
|
+
retryIdentity = undefined;
|
|
3785
|
+
const errorText = sendResult.reason ?? "Session may not exist or has disconnected.";
|
|
3786
|
+
wait.cancel(new Error(`Message to "${to}" was not delivered: ${errorText}`));
|
|
3787
|
+
const pendingStageAskRefusal = errorText.startsWith("Cannot ask a workflow stage whose session has not initialized.");
|
|
3788
|
+
return {
|
|
3789
|
+
content: [{
|
|
3790
|
+
type: "text",
|
|
3791
|
+
text: `Message to "${to}" was not delivered: ${errorText}`
|
|
3792
|
+
}],
|
|
3793
|
+
isError: true,
|
|
3794
|
+
details: {
|
|
3795
|
+
...pendingStageAskRefusal ? {
|
|
3796
|
+
refusal: "pending_stage_ask_unsupported",
|
|
3797
|
+
recommendedAction: "send",
|
|
3798
|
+
reason: errorText
|
|
3799
|
+
} : {},
|
|
3800
|
+
...retryErrorDetails(retained.retryToken)
|
|
3801
|
+
}
|
|
3802
|
+
};
|
|
3803
|
+
}
|
|
3804
|
+
askDelivered = true;
|
|
3661
3805
|
pi.appendEntry("intercom_sent", {
|
|
3662
3806
|
to,
|
|
3663
3807
|
message: { text: message, attachments, replyTo },
|
|
3664
3808
|
messageId: sendResult.id,
|
|
3665
3809
|
timestamp: Date.now()
|
|
3666
3810
|
});
|
|
3811
|
+
const replyMessage = await wait.promise;
|
|
3812
|
+
retryIdentities.release(retryIdentity);
|
|
3813
|
+
retryIdentity = undefined;
|
|
3814
|
+
const replyText = replyMessage.content.text;
|
|
3815
|
+
const replyAttachments = replyMessage.content.attachments?.length ? formatAttachments(replyMessage.content.attachments) : "";
|
|
3816
|
+
pi.appendEntry("intercom_received", {
|
|
3817
|
+
from: to,
|
|
3818
|
+
message: { text: replyText, attachments: replyMessage.content.attachments },
|
|
3819
|
+
messageId: replyMessage.id,
|
|
3820
|
+
timestamp: replyMessage.timestamp
|
|
3821
|
+
});
|
|
3822
|
+
if (replyMessage.replyError !== undefined) {
|
|
3823
|
+
return {
|
|
3824
|
+
content: [{ type: "text", text: `Failed: ${replyMessage.replyError}` }],
|
|
3825
|
+
isError: true,
|
|
3826
|
+
details: { error: true, replyTo: replyMessage.replyTo }
|
|
3827
|
+
};
|
|
3828
|
+
}
|
|
3667
3829
|
return {
|
|
3668
|
-
content: [{ type: "text", text:
|
|
3830
|
+
content: [{ type: "text", text: `**Reply from ${to}:**
|
|
3831
|
+
${replyText}${replyAttachments}` }],
|
|
3669
3832
|
isError: false,
|
|
3670
|
-
details: {
|
|
3671
|
-
messageId: sendResult.id,
|
|
3672
|
-
delivered: false,
|
|
3673
|
-
queued: true,
|
|
3674
|
-
target: sendResult.target,
|
|
3675
|
-
position: sendResult.position
|
|
3676
|
-
}
|
|
3833
|
+
details: {}
|
|
3677
3834
|
};
|
|
3678
|
-
}
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3835
|
+
} catch (error) {
|
|
3836
|
+
wait?.cancel(toError3(error));
|
|
3837
|
+
let failure = error;
|
|
3838
|
+
let retained;
|
|
3839
|
+
if (retryIdentity !== undefined) {
|
|
3840
|
+
if (isRecoverableIntercomDisconnect(error)) {
|
|
3841
|
+
try {
|
|
3842
|
+
retained = retainRecoverableRetry(retryIdentities, retryIdentity);
|
|
3843
|
+
} catch (retentionError) {
|
|
3844
|
+
failure = retentionError;
|
|
3845
|
+
}
|
|
3846
|
+
} else {
|
|
3847
|
+
retryIdentities.release(retryIdentity);
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3685
3850
|
return {
|
|
3686
3851
|
content: [{
|
|
3687
3852
|
type: "text",
|
|
3688
|
-
text: `
|
|
3853
|
+
text: `Failed: ${getErrorMessage(failure)}`
|
|
3689
3854
|
}],
|
|
3690
3855
|
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 }
|
|
3856
|
+
details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error), deliveryUncertain: askDelivered }
|
|
3723
3857
|
};
|
|
3724
3858
|
}
|
|
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
3859
|
}
|
|
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;
|
|
3860
|
+
case "reply": {
|
|
3861
|
+
if (!message) {
|
|
3862
|
+
const errorText = retryToken === undefined ? "Missing 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
|
|
3794
3863
|
return {
|
|
3795
|
-
content: [{
|
|
3796
|
-
type: "text",
|
|
3797
|
-
text: `Cannot message the current session${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
|
|
3798
|
-
}],
|
|
3864
|
+
content: [{ type: "text", text: errorText }],
|
|
3799
3865
|
isError: true,
|
|
3800
|
-
details:
|
|
3866
|
+
details: { error: true }
|
|
3801
3867
|
};
|
|
3802
3868
|
}
|
|
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);
|
|
3869
|
+
if (_signal?.aborted) {
|
|
3870
|
+
return { content: [{ type: "text", text: "Cancelled" }], isError: true, details: retryErrorDetails(retryToken) };
|
|
3815
3871
|
}
|
|
3816
|
-
|
|
3872
|
+
let retryIdentity;
|
|
3873
|
+
try {
|
|
3874
|
+
retryIdentity = retryIdentities.begin({
|
|
3875
|
+
sessionId: toolSessionId,
|
|
3876
|
+
action: "reply",
|
|
3877
|
+
target: to,
|
|
3878
|
+
text: message,
|
|
3879
|
+
attachments,
|
|
3880
|
+
replyTo,
|
|
3881
|
+
expectsReply: false
|
|
3882
|
+
}, retryToken);
|
|
3883
|
+
if (retryToken === undefined) {
|
|
3884
|
+
const target = activeReplyTracker().resolveReplyTarget({ to, replyTo });
|
|
3885
|
+
retryIdentities.bindReplyRoute(retryIdentity, {
|
|
3886
|
+
senderId: target.from.id,
|
|
3887
|
+
...target.from.name === undefined ? {} : { senderName: target.from.name },
|
|
3888
|
+
messageId: target.message.id,
|
|
3889
|
+
expectsReply: target.message.expectsReply === true
|
|
3890
|
+
});
|
|
3891
|
+
}
|
|
3892
|
+
const route = retryIdentities.replyRoute(retryIdentity);
|
|
3893
|
+
if (route === undefined)
|
|
3894
|
+
throw new RetryTokenError("invalid");
|
|
3895
|
+
const replySendTo = to ?? route.senderId;
|
|
3896
|
+
const replyLogicalTarget = to ?? route.senderId;
|
|
3897
|
+
const displayTarget = route.senderName || route.senderId;
|
|
3898
|
+
if (route.senderId === connectedClient.sessionId) {
|
|
3899
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3900
|
+
retryIdentity = undefined;
|
|
3901
|
+
return {
|
|
3902
|
+
content: [{
|
|
3903
|
+
type: "text",
|
|
3904
|
+
text: "Cannot message the current session"
|
|
3905
|
+
}],
|
|
3906
|
+
isError: true,
|
|
3907
|
+
details: retryErrorDetails(retained.retryToken)
|
|
3908
|
+
};
|
|
3909
|
+
}
|
|
3910
|
+
const replyMessageId = retryIdentity.messageId;
|
|
3911
|
+
const sendReply = (targetId) => connectedClient.send(targetId, {
|
|
3912
|
+
messageId: replyMessageId,
|
|
3913
|
+
logicalTarget: replyLogicalTarget,
|
|
3914
|
+
...route.expectsReply ? { requirePendingReply: true } : {},
|
|
3915
|
+
text: message,
|
|
3916
|
+
attachments,
|
|
3917
|
+
replyTo: route.messageId
|
|
3918
|
+
});
|
|
3919
|
+
let result = await sendReply(replySendTo);
|
|
3920
|
+
if (to === undefined && result.delivered === false && result.reasonCode === "session_not_found" && route.senderName !== undefined) {
|
|
3921
|
+
result = await sendReply(route.senderName);
|
|
3922
|
+
}
|
|
3923
|
+
if (result.queued === true) {
|
|
3924
|
+
retryIdentities.release(retryIdentity);
|
|
3925
|
+
retryIdentity = undefined;
|
|
3926
|
+
activeReplyTracker().markReplied(route.messageId);
|
|
3927
|
+
pi.appendEntry("intercom_sent", {
|
|
3928
|
+
to: displayTarget,
|
|
3929
|
+
message: { text: message, attachments, replyTo: route.messageId },
|
|
3930
|
+
messageId: result.id,
|
|
3931
|
+
timestamp: Date.now()
|
|
3932
|
+
});
|
|
3933
|
+
return {
|
|
3934
|
+
content: [{ type: "text", text: `Reply queued for ${displayTarget}` }],
|
|
3935
|
+
isError: false,
|
|
3936
|
+
details: {
|
|
3937
|
+
messageId: result.id,
|
|
3938
|
+
delivered: false,
|
|
3939
|
+
queued: true,
|
|
3940
|
+
replyTo: route.messageId,
|
|
3941
|
+
target: result.target,
|
|
3942
|
+
position: result.position
|
|
3943
|
+
}
|
|
3944
|
+
};
|
|
3945
|
+
}
|
|
3946
|
+
if (!result.delivered) {
|
|
3947
|
+
const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
|
|
3948
|
+
retryIdentity = undefined;
|
|
3949
|
+
const errorText = result.reason ?? "Session may not exist or has disconnected.";
|
|
3950
|
+
return {
|
|
3951
|
+
content: [{
|
|
3952
|
+
type: "text",
|
|
3953
|
+
text: `Reply to "${displayTarget}" was not delivered: ${errorText}`
|
|
3954
|
+
}],
|
|
3955
|
+
isError: true,
|
|
3956
|
+
details: retryToken === undefined ? { messageId: result.id, delivered: false, reason: result.reason } : {
|
|
3957
|
+
delivered: false,
|
|
3958
|
+
reason: result.reason,
|
|
3959
|
+
...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
|
|
3960
|
+
}
|
|
3961
|
+
};
|
|
3962
|
+
}
|
|
3817
3963
|
retryIdentities.release(retryIdentity);
|
|
3818
3964
|
retryIdentity = undefined;
|
|
3819
3965
|
activeReplyTracker().markReplied(route.messageId);
|
|
@@ -3824,136 +3970,101 @@ ${replyText}${replyAttachments}` }],
|
|
|
3824
3970
|
timestamp: Date.now()
|
|
3825
3971
|
});
|
|
3826
3972
|
return {
|
|
3827
|
-
content: [{ type: "text", text: `Reply
|
|
3973
|
+
content: [{ type: "text", text: `Reply sent to ${displayTarget}` }],
|
|
3828
3974
|
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
|
-
}
|
|
3975
|
+
details: { messageId: result.id, delivered: true, replyTo: route.messageId }
|
|
3837
3976
|
};
|
|
3838
|
-
}
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
retryIdentity
|
|
3842
|
-
|
|
3977
|
+
} catch (error) {
|
|
3978
|
+
let failure = error;
|
|
3979
|
+
let retained;
|
|
3980
|
+
if (retryIdentity !== undefined) {
|
|
3981
|
+
if (isRecoverableIntercomDisconnect(error)) {
|
|
3982
|
+
try {
|
|
3983
|
+
retained = retainRecoverableRetry(retryIdentities, retryIdentity);
|
|
3984
|
+
} catch (retentionError) {
|
|
3985
|
+
failure = retentionError;
|
|
3986
|
+
}
|
|
3987
|
+
} else {
|
|
3988
|
+
retryIdentities.release(retryIdentity);
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3843
3991
|
return {
|
|
3844
3992
|
content: [{
|
|
3845
3993
|
type: "text",
|
|
3846
|
-
text: `
|
|
3994
|
+
text: `Failed to reply: ${getErrorMessage(failure)}`
|
|
3847
3995
|
}],
|
|
3848
3996
|
isError: true,
|
|
3849
|
-
details:
|
|
3850
|
-
delivered: false,
|
|
3851
|
-
reason: result.reason,
|
|
3852
|
-
...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
|
|
3853
|
-
}
|
|
3997
|
+
details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error) }
|
|
3854
3998
|
};
|
|
3855
3999
|
}
|
|
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
4000
|
}
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
4001
|
+
case "pending": {
|
|
4002
|
+
const pendingAsks = activeReplyTracker().listPending();
|
|
4003
|
+
if (pendingAsks.length === 0) {
|
|
4004
|
+
return {
|
|
4005
|
+
content: [{ type: "text", text: "No unresolved inbound asks." }],
|
|
4006
|
+
isError: false,
|
|
4007
|
+
details: {}
|
|
4008
|
+
};
|
|
4009
|
+
}
|
|
4010
|
+
const now = Date.now();
|
|
4011
|
+
const lines = pendingAsks.map(({ from, message, receivedAt }) => {
|
|
4012
|
+
const preview = message.content.text.replace(/\s+/g, " ").slice(0, 80);
|
|
4013
|
+
const elapsedSeconds = Math.max(0, Math.floor((now - receivedAt) / 1000));
|
|
4014
|
+
return `- ${from.name || from.id} · ${message.id} · ${elapsedSeconds}s ago · ${preview}`;
|
|
4015
|
+
});
|
|
3897
4016
|
return {
|
|
3898
|
-
content: [{ type: "text", text:
|
|
4017
|
+
content: [{ type: "text", text: `**Pending asks:**
|
|
4018
|
+
${lines.join(`
|
|
4019
|
+
`)}` }],
|
|
3899
4020
|
isError: false,
|
|
3900
4021
|
details: {}
|
|
3901
4022
|
};
|
|
3902
4023
|
}
|
|
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 ? "" : `
|
|
4024
|
+
case "status": {
|
|
4025
|
+
try {
|
|
4026
|
+
const mySessionId = connectedClient.sessionId;
|
|
4027
|
+
const sessions = await connectedClient.listSessions();
|
|
4028
|
+
const ownGroups = resolveOwnGroups(sessions);
|
|
4029
|
+
const selectedGroup = isOnlyOwnGroup(requestedGroup, ownGroups) ? undefined : requestedGroup;
|
|
4030
|
+
const selectedGroupSessions = selectedGroup === undefined ? undefined : await connectedClient.listSessions(selectedGroup);
|
|
4031
|
+
const selectedSection = selectedGroupSessions === undefined ? "" : `
|
|
3925
4032
|
Selected group [${selectedGroup}]: ${selectedGroupSessions.length} session(s)`;
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
4033
|
+
return {
|
|
4034
|
+
content: [{
|
|
4035
|
+
type: "text",
|
|
4036
|
+
text: `**Intercom Status:**
|
|
3930
4037
|
Connected: Yes
|
|
3931
4038
|
Session ID: ${mySessionId}
|
|
3932
4039
|
Groups: ${ownGroups.join(", ")}
|
|
3933
4040
|
Active visible sessions: ${sessions.length}${selectedSection}`
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
4041
|
+
}],
|
|
4042
|
+
isError: false,
|
|
4043
|
+
details: {
|
|
4044
|
+
group: ownGroups.at(-1),
|
|
4045
|
+
groups: ownGroups,
|
|
4046
|
+
...selectedGroup === undefined ? {} : { selectedGroup, selectedGroupSessionCount: selectedGroupSessions?.length ?? 0 }
|
|
4047
|
+
}
|
|
4048
|
+
};
|
|
4049
|
+
} catch (error) {
|
|
4050
|
+
return {
|
|
4051
|
+
content: [{ type: "text", text: `Failed to get status: ${getErrorMessage(error)}` }],
|
|
4052
|
+
isError: true,
|
|
4053
|
+
details: { error: true }
|
|
4054
|
+
};
|
|
4055
|
+
}
|
|
4056
|
+
}
|
|
4057
|
+
default:
|
|
3943
4058
|
return {
|
|
3944
|
-
content: [{ type: "text", text: `
|
|
4059
|
+
content: [{ type: "text", text: `Unknown action: ${action}` }],
|
|
3945
4060
|
isError: true,
|
|
3946
4061
|
details: { error: true }
|
|
3947
4062
|
};
|
|
3948
|
-
}
|
|
3949
4063
|
}
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
details: { error: true }
|
|
3955
|
-
};
|
|
3956
|
-
}
|
|
4064
|
+
};
|
|
4065
|
+
if (action !== "send" && action !== "ask" && action !== "reply")
|
|
4066
|
+
return executeAttempt(undefined, signal);
|
|
4067
|
+
return runIntercomOperation(executeAttempt, (token) => retryIdentities.discard(token), signal);
|
|
3957
4068
|
},
|
|
3958
4069
|
renderCall(args, theme) {
|
|
3959
4070
|
const action = typeof args.action === "string" ? args.action : "intercom";
|
|
@@ -3985,6 +4096,7 @@ var init_intercom_tool = __esm(() => {
|
|
|
3985
4096
|
init_workflow_stage_target();
|
|
3986
4097
|
init_recoverable_disconnect();
|
|
3987
4098
|
init_retry_identity();
|
|
4099
|
+
init_tool_retry();
|
|
3988
4100
|
});
|
|
3989
4101
|
|
|
3990
4102
|
// dist/builtin/intercom/ui/compose.ts
|
|
@@ -4564,12 +4676,12 @@ function prepareDurableAuthority(storagePath) {
|
|
|
4564
4676
|
if (databaseExists !== keyExists)
|
|
4565
4677
|
return;
|
|
4566
4678
|
if (!databaseExists) {
|
|
4567
|
-
const
|
|
4568
|
-
writeFileSync2(keyPath,
|
|
4679
|
+
const key = randomBytes(AUTHORITY_KEY_BYTES);
|
|
4680
|
+
writeFileSync2(keyPath, key, { flag: "wx", mode: 384 });
|
|
4569
4681
|
const databaseDescriptor = openSync2(storagePath, "wx", 384);
|
|
4570
4682
|
closeSync2(databaseDescriptor);
|
|
4571
4683
|
restrictExistingAuthorityArtifacts(storagePath, keyPath);
|
|
4572
|
-
return
|
|
4684
|
+
return key;
|
|
4573
4685
|
}
|
|
4574
4686
|
const key = readFileSync3(keyPath);
|
|
4575
4687
|
if (key.length !== AUTHORITY_KEY_BYTES)
|
|
@@ -4878,7 +4990,7 @@ function parseBarrier(value) {
|
|
|
4878
4990
|
return null;
|
|
4879
4991
|
if (typeof record.terminalAt !== "number" || !Number.isFinite(record.terminalAt))
|
|
4880
4992
|
return null;
|
|
4881
|
-
if (record.source !== "detached-notify" && record.source !== "result-relay")
|
|
4993
|
+
if (record.source !== "detached-notify" && record.source !== "result-relay" && record.source !== "owner-task")
|
|
4882
4994
|
return null;
|
|
4883
4995
|
if (!Array.isArray(record.sourceSessionTargets))
|
|
4884
4996
|
return null;
|
|
@@ -4954,11 +5066,17 @@ function registerTerminalOrderingBarrier(pi, options) {
|
|
|
4954
5066
|
envelope.completion = currentOwner;
|
|
4955
5067
|
return;
|
|
4956
5068
|
}
|
|
4957
|
-
const drainedTargets = drainedTargetsByTerminal.get(terminalKey) ?? new Set;
|
|
5069
|
+
const drainedTargets = barrier.source === "owner-task" ? new Set : drainedTargetsByTerminal.get(terminalKey) ?? new Set;
|
|
4958
5070
|
const pendingTargets = barrier.sourceSessionTargets.filter((target) => !drainedTargets.has(target));
|
|
4959
5071
|
if (pendingTargets.length === 0)
|
|
4960
5072
|
return;
|
|
4961
5073
|
const claim = options.queue.claimOrdinarySourceTargets(barrier.runId, pendingTargets, barrier.terminalAt);
|
|
5074
|
+
const deliverPrelude = (entry) => {
|
|
5075
|
+
if (!claim.isCurrent() || options.isCurrent?.() === false) {
|
|
5076
|
+
throw new Error("Intercom terminal delivery owner retired");
|
|
5077
|
+
}
|
|
5078
|
+
return options.deliver(entry, "prelude");
|
|
5079
|
+
};
|
|
4962
5080
|
const ownership = Promise.withResolvers();
|
|
4963
5081
|
ownership.promise.catch(() => {});
|
|
4964
5082
|
inFlightByTerminal.set(terminalKey, ownership.promise);
|
|
@@ -4968,7 +5086,7 @@ function registerTerminalOrderingBarrier(pi, options) {
|
|
|
4968
5086
|
ownership.reject(error);
|
|
4969
5087
|
};
|
|
4970
5088
|
const finish = () => {
|
|
4971
|
-
if (barrier.dispatch && options.toMessage || claim.entries.length > 0) {
|
|
5089
|
+
if (barrier.source !== "owner-task" && (barrier.dispatch && options.toMessage || claim.entries.length > 0)) {
|
|
4972
5090
|
for (const target of pendingTargets)
|
|
4973
5091
|
drainedTargets.add(target);
|
|
4974
5092
|
drainedTargetsByTerminal.set(terminalKey, drainedTargets);
|
|
@@ -5019,7 +5137,7 @@ function registerTerminalOrderingBarrier(pi, options) {
|
|
|
5019
5137
|
let delivered;
|
|
5020
5138
|
let deliveredAsync;
|
|
5021
5139
|
try {
|
|
5022
|
-
delivered =
|
|
5140
|
+
delivered = deliverPrelude(claim.entries[index]);
|
|
5023
5141
|
deliveredAsync = isPromiseLike(delivered);
|
|
5024
5142
|
} catch (error) {
|
|
5025
5143
|
if (barrier.owner)
|
|
@@ -5035,7 +5153,7 @@ function registerTerminalOrderingBarrier(pi, options) {
|
|
|
5035
5153
|
try {
|
|
5036
5154
|
await delivered;
|
|
5037
5155
|
for (current = index + 1;current < claim.entries.length; current++) {
|
|
5038
|
-
await
|
|
5156
|
+
await deliverPrelude(claim.entries[current]);
|
|
5039
5157
|
}
|
|
5040
5158
|
finish();
|
|
5041
5159
|
} catch (error) {
|
|
@@ -5111,7 +5229,7 @@ async function dispatchRelayFallback(pi, prefix, terminalMessage, stageAdmission
|
|
|
5111
5229
|
}
|
|
5112
5230
|
}
|
|
5113
5231
|
function registerSubagentRelay(pi, deps) {
|
|
5114
|
-
const { getLiveContext, currentSessionTargetMatches, sendIncomingMessage, ensureConnected, resolveSessionTarget
|
|
5232
|
+
const { getLiveContext, currentSessionTargetMatches, sendIncomingMessage, ensureConnected, resolveSessionTarget } = deps;
|
|
5115
5233
|
const localDeliveries = deps.localDeliveryAuthority ?? new DeliveredMessageCache;
|
|
5116
5234
|
function deliverLocalSubagentRelayMessage(sender, status, messageText, terminalBarrier, requestId) {
|
|
5117
5235
|
const now = Date.now();
|
|
@@ -5268,7 +5386,7 @@ ${messageText}`,
|
|
|
5268
5386
|
let target;
|
|
5269
5387
|
try {
|
|
5270
5388
|
activeClient = await ensureConnected("background");
|
|
5271
|
-
target = await
|
|
5389
|
+
target = await resolveSessionTarget(activeClient, parsed.to) ?? parsed.to;
|
|
5272
5390
|
} catch (error) {
|
|
5273
5391
|
if (!relayStillLive()) {
|
|
5274
5392
|
acknowledgeResult(options, parsed.requestId, false, error);
|
|
@@ -5545,6 +5663,20 @@ function framePreStartPendingStageMessage(entry) {
|
|
|
5545
5663
|
|
|
5546
5664
|
Sent: ${framePendingStageTimestamp(entry.message.timestamp)}
|
|
5547
5665
|
|
|
5666
|
+
${entry.bodyText}`
|
|
5667
|
+
};
|
|
5668
|
+
}
|
|
5669
|
+
function isDeliveryFeedback(message) {
|
|
5670
|
+
return Boolean(message.replyTo) && message.replyError !== undefined;
|
|
5671
|
+
}
|
|
5672
|
+
function frameDeliveryFeedback(entry) {
|
|
5673
|
+
return {
|
|
5674
|
+
...entry,
|
|
5675
|
+
replyCommand: undefined,
|
|
5676
|
+
bodyText: `**Intercom delivery failed**
|
|
5677
|
+
|
|
5678
|
+
Sent: ${framePendingStageTimestamp(entry.message.timestamp)}
|
|
5679
|
+
|
|
5548
5680
|
${entry.bodyText}`
|
|
5549
5681
|
};
|
|
5550
5682
|
}
|
|
@@ -5566,6 +5698,7 @@ ${entry.bodyText}`,
|
|
|
5566
5698
|
// dist/builtin/intercom/inbound-idle-queue.ts
|
|
5567
5699
|
class InboundIdleQueue {
|
|
5568
5700
|
entries = [];
|
|
5701
|
+
generation = 0;
|
|
5569
5702
|
get size() {
|
|
5570
5703
|
return this.entries.length;
|
|
5571
5704
|
}
|
|
@@ -5589,6 +5722,7 @@ class InboundIdleQueue {
|
|
|
5589
5722
|
}
|
|
5590
5723
|
claimOrdinarySourceTargets(runId, sourceSessionTargets, terminalAt = Number.POSITIVE_INFINITY) {
|
|
5591
5724
|
const targets = new Set(sourceSessionTargets);
|
|
5725
|
+
const generation = this.generation;
|
|
5592
5726
|
const original = this.entries;
|
|
5593
5727
|
const legacyIdsByName = new Map;
|
|
5594
5728
|
for (const entry of original) {
|
|
@@ -5618,8 +5752,9 @@ class InboundIdleQueue {
|
|
|
5618
5752
|
let settled = false;
|
|
5619
5753
|
return {
|
|
5620
5754
|
entries: selected,
|
|
5755
|
+
isCurrent: () => generation === this.generation,
|
|
5621
5756
|
rollbackFrom: (index) => {
|
|
5622
|
-
if (settled)
|
|
5757
|
+
if (settled || generation !== this.generation)
|
|
5623
5758
|
return;
|
|
5624
5759
|
settled = true;
|
|
5625
5760
|
const undelivered = new Set(selected.slice(index));
|
|
@@ -5629,6 +5764,7 @@ class InboundIdleQueue {
|
|
|
5629
5764
|
};
|
|
5630
5765
|
}
|
|
5631
5766
|
clear() {
|
|
5767
|
+
this.generation++;
|
|
5632
5768
|
this.entries = [];
|
|
5633
5769
|
}
|
|
5634
5770
|
}
|
|
@@ -5954,7 +6090,7 @@ function routeClosedWorkflowStageMessage(entry, admission, tracker, waiter, deli
|
|
|
5954
6090
|
const sourceRunId = entry.message.source?.subagentRunId;
|
|
5955
6091
|
if (sourceRunId !== undefined && ownsSubagentRun(sourceRunId))
|
|
5956
6092
|
return;
|
|
5957
|
-
if (entry.message.expectsReply !== true) {
|
|
6093
|
+
if (entry.message.expectsReply !== true && !isDeliveryFeedback(entry.message)) {
|
|
5958
6094
|
retryStableDelivery({ deliver, isCurrent }).catch(() => {});
|
|
5959
6095
|
return;
|
|
5960
6096
|
}
|
|
@@ -5965,6 +6101,14 @@ function routeClosedWorkflowStageMessage(entry, admission, tracker, waiter, deli
|
|
|
5965
6101
|
admission.commit(admitted.reservation);
|
|
5966
6102
|
return;
|
|
5967
6103
|
}
|
|
6104
|
+
if (isDeliveryFeedback(entry.message)) {
|
|
6105
|
+
retryStableDelivery({ deliver, isCurrent }).then(() => {
|
|
6106
|
+
admission.commit(admitted.reservation);
|
|
6107
|
+
}, (error) => {
|
|
6108
|
+
admission.release(admitted.reservation, error instanceof Error ? error : new Error(String(error)));
|
|
6109
|
+
});
|
|
6110
|
+
return;
|
|
6111
|
+
}
|
|
5968
6112
|
const replyContext = tracker.recordIncomingMessage(entry.from, entry.message);
|
|
5969
6113
|
tracker.queueTurnContext(replyContext);
|
|
5970
6114
|
const delivery = invoke(deliver);
|
|
@@ -6050,6 +6194,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6050
6194
|
};
|
|
6051
6195
|
let client = null;
|
|
6052
6196
|
let clientRegistrationGroup = null;
|
|
6197
|
+
const replyCapability = registerSubagentReplyCapability(pi, () => client);
|
|
6053
6198
|
const config = loadConfig();
|
|
6054
6199
|
const legacyChildOrchestratorMetadata = readChildOrchestratorMetadata();
|
|
6055
6200
|
let runtimeContext = null;
|
|
@@ -6156,6 +6301,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6156
6301
|
startedAt: sessionStartedAt,
|
|
6157
6302
|
lastActivity: Date.now(),
|
|
6158
6303
|
status: currentStatus(),
|
|
6304
|
+
replyCapability: replyCapability(),
|
|
6159
6305
|
groups: [...currentIntercomGroups()],
|
|
6160
6306
|
group: currentIntercomGroup()
|
|
6161
6307
|
};
|
|
@@ -6257,14 +6403,15 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6257
6403
|
const bodyText = `${message.content.text}${attachmentText}`;
|
|
6258
6404
|
const replyCommand = config.replyHint && message.expectsReply ? `intercom({ action: "reply", message: "..." })` : undefined;
|
|
6259
6405
|
const rawEntry = { from, message, replyCommand, bodyText, ...channel ? { channel } : {} };
|
|
6260
|
-
const
|
|
6406
|
+
const framedEntry = isDeliveryFeedback(message) ? frameDeliveryFeedback(rawEntry) : rawEntry;
|
|
6407
|
+
const entry = receivedBeforeStageStart ? framePreStartPendingStageMessage(framedEntry) : framedEntry;
|
|
6261
6408
|
if (receivedBeforeStageStart) {
|
|
6262
6409
|
return sendIncomingMessage(entry, "prelude", messageGeneration, false);
|
|
6263
6410
|
}
|
|
6264
6411
|
const stageAdmission = liveContext.orchestrationContext?.kind === "workflow-stage" ? liveContext.orchestrationContext.messageAdmission : undefined;
|
|
6265
6412
|
const stageClosed = stageAdmission?.isOpen() === false;
|
|
6266
6413
|
if (stageClosed) {
|
|
6267
|
-
routeClosedWorkflowStageMessage(entry, inboundDeliveries, replyTracker, replyWaiters.pending(), () => sendIncomingMessage(entry, "trigger", messageGeneration, false), () => client, () => Boolean(getLiveContext(liveContext, messageGeneration)), (runId) => stageAdmission.boundary.ownsSubagentRun(runId));
|
|
6414
|
+
routeClosedWorkflowStageMessage(entry, inboundDeliveries, replyTracker, replyWaiters.pending(), () => sendIncomingMessage(entry, isDeliveryFeedback(message) ? "prelude" : "trigger", messageGeneration, false), () => client, () => Boolean(getLiveContext(liveContext, messageGeneration)), (runId) => stageAdmission.boundary.ownsSubagentRun(runId));
|
|
6268
6415
|
return;
|
|
6269
6416
|
}
|
|
6270
6417
|
const admission = inboundDeliveries.admit(from, message);
|
|
@@ -6275,6 +6422,12 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6275
6422
|
inboundDeliveries.commit(reservation);
|
|
6276
6423
|
return;
|
|
6277
6424
|
}
|
|
6425
|
+
if (isDeliveryFeedback(message)) {
|
|
6426
|
+
return retryStableDelivery({
|
|
6427
|
+
deliver: () => sendIncomingMessage(entry, "prelude", messageGeneration, false),
|
|
6428
|
+
isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration))
|
|
6429
|
+
}).then(() => inboundDeliveries.commit(reservation), (error) => inboundDeliveries.release(reservation, toError3(error)));
|
|
6430
|
+
}
|
|
6278
6431
|
const replyContext = replyTracker.recordIncomingMessage(from, message);
|
|
6279
6432
|
const commit = () => {
|
|
6280
6433
|
inboundDeliveries.commit(reservation);
|
|
@@ -6311,9 +6464,11 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6311
6464
|
const activeClient = client;
|
|
6312
6465
|
if (!message.replyTo && activeClient?.isConnected()) {
|
|
6313
6466
|
try {
|
|
6467
|
+
const refusal = "Message not accepted: recipient was busy in non-interactive mode. Its task was not interrupted.";
|
|
6314
6468
|
const result = await activeClient.send(from.id, {
|
|
6315
|
-
text:
|
|
6316
|
-
replyTo: message.id
|
|
6469
|
+
text: refusal,
|
|
6470
|
+
replyTo: message.id,
|
|
6471
|
+
replyError: refusal
|
|
6317
6472
|
});
|
|
6318
6473
|
if (result.delivered && getLiveContext(liveContext, messageGeneration)) {
|
|
6319
6474
|
replyTracker.markReplied(message.id);
|
|
@@ -6581,7 +6736,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6581
6736
|
pendingStageRouteClients.set(runId, state);
|
|
6582
6737
|
if (state.client?.isConnected()) {
|
|
6583
6738
|
state.route = route;
|
|
6584
|
-
state.client.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages);
|
|
6739
|
+
state.client.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent);
|
|
6740
|
+
await state.client.listSessions();
|
|
6585
6741
|
return;
|
|
6586
6742
|
}
|
|
6587
6743
|
if (state.promise) {
|
|
@@ -6593,12 +6749,12 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6593
6749
|
const nextClient = new IntercomClient(`${currentSessionId}:pending-stage-route:${runId}`);
|
|
6594
6750
|
state.client = nextClient;
|
|
6595
6751
|
attachPendingStageRouteClientHandlers(runId, state, nextClient);
|
|
6596
|
-
await nextClient.connect({ ...buildRegistration(), name: undefined, groups: [normalizeGroup(route.group)], group: normalizeGroup(route.group) }, undefined, undefined, readSubagentMessageSource(runtimeContext?.subagentPolicy));
|
|
6752
|
+
await nextClient.connect({ ...buildRegistration(), recipientPurpose: "control", name: undefined, groups: [normalizeGroup(route.group)], group: normalizeGroup(route.group) }, undefined, undefined, readSubagentMessageSource(runtimeContext?.subagentPolicy));
|
|
6597
6753
|
if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
|
|
6598
6754
|
await nextClient.disconnect();
|
|
6599
6755
|
throw new Error("Intercom runtime no longer active");
|
|
6600
6756
|
}
|
|
6601
|
-
nextClient.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages);
|
|
6757
|
+
nextClient.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent);
|
|
6602
6758
|
await nextClient.listSessions();
|
|
6603
6759
|
if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
|
|
6604
6760
|
await nextClient.disconnect();
|
|
@@ -6646,7 +6802,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6646
6802
|
async function registerPendingStageRoute(activeClient, runId, route) {
|
|
6647
6803
|
const routeGroup = normalizeGroup(route.group);
|
|
6648
6804
|
if (clientRegistrationGroup === routeGroup) {
|
|
6649
|
-
activeClient.registerPendingStageRoute(runId, routeGroup, route.capability, route.stages, route.possibleStages);
|
|
6805
|
+
activeClient.registerPendingStageRoute(runId, routeGroup, route.capability, route.stages, route.possibleStages, route.parent);
|
|
6806
|
+
await activeClient.listSessions();
|
|
6650
6807
|
return;
|
|
6651
6808
|
}
|
|
6652
6809
|
await ensurePendingStageRouteClient(runId, { ...route, group: routeGroup });
|
|
@@ -6672,15 +6829,16 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6672
6829
|
let connectFailed = false;
|
|
6673
6830
|
await ownershipRecorded.promise;
|
|
6674
6831
|
const nextClient = new IntercomClient(currentSessionId);
|
|
6675
|
-
const registration = buildRegistration();
|
|
6676
6832
|
client = nextClient;
|
|
6677
6833
|
attachClientHandlers(nextClient);
|
|
6678
6834
|
try {
|
|
6679
6835
|
await testOverrides.beforeConnectAttempt?.(reason);
|
|
6680
6836
|
await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
|
|
6681
6837
|
const childMetadata = currentChildOrchestratorMetadata();
|
|
6682
|
-
await nextClient.connect(
|
|
6838
|
+
await nextClient.connect(buildRegistration(), childMetadata?.supervisor, supervisorAuthorizations.ownerToken, readSubagentMessageSource(runtimeContext?.subagentPolicy), resolveSessionHomeGroup());
|
|
6683
6839
|
clientRegistrationGroup = resolveSessionHomeGroup();
|
|
6840
|
+
if (replyCapability() === "terminal")
|
|
6841
|
+
nextClient.updatePresence({ replyCapability: "terminal" });
|
|
6684
6842
|
await supervisorAuthorizations.restore(nextClient);
|
|
6685
6843
|
for (const [runId, route] of pendingStageRoutes) {
|
|
6686
6844
|
await registerPendingStageRoute(nextClient, runId, route);
|
|
@@ -6734,7 +6892,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6734
6892
|
group: payload.group,
|
|
6735
6893
|
capability: payload.capability,
|
|
6736
6894
|
...payload.stages === undefined ? {} : { stages: payload.stages },
|
|
6737
|
-
...payload.possibleStages === undefined ? {} : { possibleStages: payload.possibleStages }
|
|
6895
|
+
...payload.possibleStages === undefined ? {} : { possibleStages: payload.possibleStages },
|
|
6896
|
+
...payload.parent === undefined ? {} : { parent: payload.parent }
|
|
6738
6897
|
});
|
|
6739
6898
|
const completion = ensureConnected("background").then((activeClient) => registerPendingStageRoute(activeClient, payload.runId, payload));
|
|
6740
6899
|
payload.completion = completion;
|
|
@@ -6942,8 +7101,34 @@ import { Text as Text4 } from "@earendil-works/pi-tui";
|
|
|
6942
7101
|
import { Type as Type3 } from "typebox";
|
|
6943
7102
|
|
|
6944
7103
|
// dist/builtin/intercom/lazy-tool-execution.ts
|
|
7104
|
+
init_recoverable_disconnect();
|
|
7105
|
+
init_retry_policy();
|
|
7106
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
6945
7107
|
async function executeHeavyTool(loadHeavy, name, args) {
|
|
6946
|
-
const
|
|
7108
|
+
const params = args[1];
|
|
7109
|
+
const recoverInitialization = name === "intercom" && ["send", "ask", "reply"].includes(params.action ?? "");
|
|
7110
|
+
let handle;
|
|
7111
|
+
let retries = 0;
|
|
7112
|
+
for (;; ) {
|
|
7113
|
+
if (recoverInitialization && args[2]?.aborted)
|
|
7114
|
+
return initializationFailure("Cancelled", retries);
|
|
7115
|
+
try {
|
|
7116
|
+
handle = await loadHeavy(args[4]);
|
|
7117
|
+
break;
|
|
7118
|
+
} catch (error) {
|
|
7119
|
+
if (!recoverInitialization || !isRecoverableIntercomDisconnect(error))
|
|
7120
|
+
throw error;
|
|
7121
|
+
const delayMs = RECONNECT_DELAYS_MS[retries];
|
|
7122
|
+
if (delayMs === undefined)
|
|
7123
|
+
return initializationFailure("Client disconnected", retries);
|
|
7124
|
+
try {
|
|
7125
|
+
await delay(delayMs, undefined, { signal: args[2] });
|
|
7126
|
+
} catch {
|
|
7127
|
+
return initializationFailure("Cancelled", retries);
|
|
7128
|
+
}
|
|
7129
|
+
retries += 1;
|
|
7130
|
+
}
|
|
7131
|
+
}
|
|
6947
7132
|
handle.assertCurrent();
|
|
6948
7133
|
const tool = handle.heavy.tools.get(name);
|
|
6949
7134
|
if (!tool?.execute)
|
|
@@ -6952,6 +7137,13 @@ async function executeHeavyTool(loadHeavy, name, args) {
|
|
|
6952
7137
|
handle.assertCurrent();
|
|
6953
7138
|
return result;
|
|
6954
7139
|
}
|
|
7140
|
+
function initializationFailure(reason, retries) {
|
|
7141
|
+
return {
|
|
7142
|
+
content: [{ type: "text", text: `${reason}. Intercom initialization stopped after ${retries} automatic retries. This operation was not sent.` }],
|
|
7143
|
+
isError: true,
|
|
7144
|
+
details: { error: true, terminal: true, automaticRetries: retries, outcome: "not_sent" }
|
|
7145
|
+
};
|
|
7146
|
+
}
|
|
6955
7147
|
async function runHeavyCommand(loadHeavy, args, ctx) {
|
|
6956
7148
|
const handle = await loadHeavy(ctx);
|
|
6957
7149
|
handle.assertCurrent();
|
|
@@ -7634,7 +7826,7 @@ function intercom(pi, options = {}) {
|
|
|
7634
7826
|
Use this to communicate findings, request help, or coordinate work with other sessions.
|
|
7635
7827
|
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
7828
|
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
|
-
|
|
7829
|
+
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
7830
|
Usage:
|
|
7639
7831
|
intercom({ action: "list" }) → List sessions in your group
|
|
7640
7832
|
intercom({ action: "list", group: "name" }) → Read-only peek at another group's sessions
|
|
@@ -7643,12 +7835,11 @@ Usage:
|
|
|
7643
7835
|
intercom({ action: "send", to: "session-name", message: "..." }) → Send message (own group only)
|
|
7644
7836
|
intercom({ action: "ask", to: "session-name", message: "..." }) → Ask and wait for reply
|
|
7645
7837
|
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
7838
|
intercom({ action: "pending" }) → List unresolved inbound asks
|
|
7648
7839
|
intercom({ action: "status" }) → Show connection status and your group
|
|
7649
7840
|
|
|
7650
7841
|
"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.
|
|
7842
|
+
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
7843
|
parameters: Type3.Object({
|
|
7653
7844
|
action: Type3.String({ description: "Action: 'list', 'join', 'leave', 'send', 'ask', 'reply', 'pending', or 'status'" }),
|
|
7654
7845
|
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 +7851,15 @@ Usage:
|
|
|
7660
7851
|
language: Type3.Optional(Type3.String())
|
|
7661
7852
|
}))),
|
|
7662
7853
|
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
7854
|
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
7855
|
}),
|
|
7666
|
-
execute: (...args) =>
|
|
7856
|
+
execute: (...args) => {
|
|
7857
|
+
const invocationLease = activeLease;
|
|
7858
|
+
return executeHeavyTool((ctx) => {
|
|
7859
|
+
assertLease(invocationLease);
|
|
7860
|
+
return loadHeavy(ctx);
|
|
7861
|
+
}, "intercom", args);
|
|
7862
|
+
},
|
|
7667
7863
|
renderResult: (...args) => renderHeavyToolResult(loadedHeavy?.heavy ?? null, "intercom", args),
|
|
7668
7864
|
renderCall(args, theme) {
|
|
7669
7865
|
const input = args;
|