@poolzin/pool-bot 2026.2.17 → 2026.2.18
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 +17 -0
- package/dist/agents/agent-scope.js +4 -0
- package/dist/agents/announce-idempotency.js +14 -0
- package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +23 -0
- package/dist/agents/bash-tools.exec-runtime.js +438 -0
- package/dist/agents/bash-tools.shared.js +6 -0
- package/dist/agents/cli-runner/reliability.js +61 -0
- package/dist/agents/cli-watchdog-defaults.js +11 -0
- package/dist/agents/command-poll-backoff.js +63 -0
- package/dist/agents/current-time.js +16 -0
- package/dist/agents/model-alias-lines.js +18 -0
- package/dist/agents/model-auth-label.js +61 -0
- package/dist/agents/models-config.e2e-harness.js +115 -0
- package/dist/agents/ollama-stream.js +11 -3
- package/dist/agents/openclaw-tools.js +135 -0
- package/dist/agents/pi-auth-json.js +118 -0
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +147 -0
- package/dist/agents/pi-embedded-subscribe.e2e-harness.js +90 -0
- package/dist/agents/pi-embedded-subscribe.handlers.compaction.js +63 -0
- package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +30 -0
- package/dist/agents/pi-extensions/session-manager-runtime-registry.js +23 -0
- package/dist/agents/pi-tools.js +2 -0
- package/dist/agents/queued-file-writer.js +22 -0
- package/dist/agents/sandbox/docker.js +133 -40
- package/dist/agents/sandbox/fs-bridge.js +146 -0
- package/dist/agents/sandbox/fs-paths.js +205 -0
- package/dist/agents/sandbox/hash.js +4 -0
- package/dist/agents/sandbox-paths.js +3 -0
- package/dist/agents/session-dirs.js +20 -0
- package/dist/agents/skills/filter.js +24 -0
- package/dist/agents/skills/tools-dir.js +9 -0
- package/dist/agents/skills-install-download.js +290 -0
- package/dist/agents/skills-install-output.js +30 -0
- package/dist/agents/skills-install.download-test-utils.js +36 -0
- package/dist/agents/skills.e2e-test-helpers.js +13 -0
- package/dist/agents/subagent-announce-queue.js +59 -15
- package/dist/agents/subagent-depth.js +137 -0
- package/dist/agents/subagent-registry.js +448 -96
- package/dist/agents/subagent-spawn.js +262 -0
- package/dist/agents/test-helpers/fast-tool-stubs.js +18 -0
- package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +74 -0
- package/dist/agents/tool-display-common.js +782 -0
- package/dist/agents/tools/image-tool.js +1 -1
- package/dist/agents/tools/sessions-access.js +178 -0
- package/dist/agents/tools/sessions-resolution.js +206 -0
- package/dist/agents/tools/subagents-tool.js +616 -0
- package/dist/agents/workspace-dir.js +18 -0
- package/dist/agents/workspace-dirs.js +14 -0
- package/dist/agents/workspace.js +70 -0
- package/dist/auto-reply/heartbeat-reply-payload.js +18 -0
- package/dist/auto-reply/reply/commands-export-session.js +163 -0
- package/dist/auto-reply/reply/commands-mesh.js +245 -0
- package/dist/auto-reply/reply/commands-setunset.js +28 -0
- package/dist/auto-reply/reply/commands-slash-parse.js +31 -0
- package/dist/auto-reply/reply/commands-system-prompt.js +117 -0
- package/dist/auto-reply/reply/directive-handling.levels.js +17 -0
- package/dist/auto-reply/reply/directive-handling.params.js +1 -0
- package/dist/auto-reply/reply/directive-parsing.js +36 -0
- package/dist/auto-reply/reply/dispatcher-registry.js +43 -0
- package/dist/auto-reply/reply/elevated-unavailable.js +20 -0
- package/dist/auto-reply/reply/reply-delivery.js +92 -0
- package/dist/auto-reply/reply/session-reset-prompt.js +1 -0
- package/dist/auto-reply/reply/session-run-accounting.js +33 -0
- package/dist/auto-reply/reply.directive.directive-behavior.e2e-harness.js +115 -0
- package/dist/auto-reply/reply.directive.directive-behavior.e2e-mocks.js +12 -0
- package/dist/browser/bridge-auth-registry.js +26 -0
- package/dist/browser/client-actions-url.js +10 -0
- package/dist/browser/control-auth.js +73 -0
- package/dist/browser/csrf.js +64 -0
- package/dist/browser/http-auth.js +52 -0
- package/dist/browser/paths.js +37 -0
- package/dist/browser/proxy-files.js +32 -0
- package/dist/browser/pw-ai-state.js +7 -0
- package/dist/browser/resolved-config-refresh.js +42 -0
- package/dist/browser/routes/path-output.js +1 -0
- package/dist/browser/server-context.chrome-test-harness.js +20 -0
- package/dist/browser/server-middleware.js +31 -0
- package/dist/browser/test-port.js +16 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/file-resolver.js +43 -0
- package/dist/channels/account-summary.js +19 -0
- package/dist/channels/draft-stream-loop.js +77 -0
- package/dist/channels/plugins/account-helpers.js +26 -0
- package/dist/channels/telegram/allow-from.js +10 -0
- package/dist/cli/browser-cli-resize.js +22 -0
- package/dist/cli/browser-cli-shared.js +8 -0
- package/dist/cli/clawbot-cli.js +5 -0
- package/dist/cli/completion-cli.js +566 -0
- package/dist/cli/config-cli.js +63 -5
- package/dist/cli/daemon-cli/lifecycle-core.js +256 -0
- package/dist/cli/daemon-cli/register-service-commands.js +60 -0
- package/dist/cli/daemon-cli-compat.js +80 -0
- package/dist/cli/nodes-cli/pairing-render.js +26 -0
- package/dist/cli/program/action-reparse.js +17 -0
- package/dist/cli/program/command-registry.js +17 -0
- package/dist/cli/program/program-context.js +8 -0
- package/dist/cli/program/register.subclis.js +7 -0
- package/dist/cli/program/routes.js +233 -0
- package/dist/cli/qr-cli.js +132 -0
- package/dist/cli/requirements-test-fixtures.js +17 -0
- package/dist/cli/respawn-policy.js +4 -0
- package/dist/cli/shared/parse-port.js +18 -0
- package/dist/cli/skills-cli.format.js +241 -0
- package/dist/cli/update-cli/progress.js +121 -0
- package/dist/cli/update-cli/restart-helper.js +108 -0
- package/dist/cli/update-cli/shared.js +196 -0
- package/dist/cli/update-cli/status.js +97 -0
- package/dist/cli/update-cli/suppress-deprecations.js +17 -0
- package/dist/cli/update-cli/update-command.js +506 -0
- package/dist/cli/update-cli/wizard.js +130 -0
- package/dist/cli/update-cli.js +3 -9
- package/dist/cli/windows-argv.js +69 -0
- package/dist/commands/auth-choice-legacy.js +20 -0
- package/dist/commands/auth-choice.apply-helpers.js +8 -0
- package/dist/commands/channel-test-helpers.js +19 -0
- package/dist/commands/cleanup-plan.js +10 -0
- package/dist/commands/cleanup-utils.js +7 -0
- package/dist/commands/config-validation.js +15 -0
- package/dist/commands/doctor-completion.js +112 -0
- package/dist/commands/doctor-memory-search.js +119 -0
- package/dist/commands/doctor-session-locks.js +73 -0
- package/dist/commands/doctor.e2e-harness.js +364 -0
- package/dist/commands/gateway-presence.js +19 -0
- package/dist/commands/model-default.js +35 -0
- package/dist/commands/models/fallbacks-shared.js +102 -0
- package/dist/commands/models/shared.js +24 -0
- package/dist/commands/onboard-auth.config-gateways.js +64 -0
- package/dist/commands/onboard-auth.config-litellm.js +45 -0
- package/dist/commands/onboard-auth.config-shared.js +116 -0
- package/dist/commands/onboard-config.js +16 -0
- package/dist/commands/onboard-non-interactive.test-helpers.js +31 -0
- package/dist/commands/onboard-provider-auth-flags.js +136 -0
- package/dist/commands/openai-codex-oauth.js +40 -0
- package/dist/commands/test-runtime-config-helpers.js +21 -0
- package/dist/commands/test-wizard-helpers.js +68 -0
- package/dist/commands/vllm-setup.js +66 -0
- package/dist/compat/legacy-names.js +2 -0
- package/dist/config/backup-rotation.js +19 -0
- package/dist/config/env-preserve.js +122 -0
- package/dist/config/includes-scan.js +78 -0
- package/dist/config/plugins-allowlist.js +13 -0
- package/dist/config/schema.help.js +256 -0
- package/dist/config/schema.hints.js +189 -0
- package/dist/config/schema.irc.js +20 -0
- package/dist/config/schema.labels.js +317 -0
- package/dist/config/sessions/delivery-info.js +40 -0
- package/dist/config/types.irc.js +1 -0
- package/dist/config/zod-schema.agent-model.js +10 -0
- package/dist/config/zod-schema.allowdeny.js +35 -0
- package/dist/config/zod-schema.sensitive.js +4 -0
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
- package/dist/cron/isolated-agent/skills-snapshot.js +26 -0
- package/dist/cron/isolated-agent/subagent-followup.js +127 -0
- package/dist/cron/isolated-agent.mocks.js +12 -0
- package/dist/cron/isolated-agent.test-setup.js +22 -0
- package/dist/cron/legacy-delivery.js +43 -0
- package/dist/cron/webhook-url.js +22 -0
- package/dist/daemon/arg-split.js +40 -0
- package/dist/daemon/exec-file.js +23 -0
- package/dist/daemon/output.js +6 -0
- package/dist/daemon/runtime-format.js +31 -0
- package/dist/daemon/schtasks-exec.js +4 -0
- package/dist/daemon/service-audit.js +22 -0
- package/dist/discord/client.js +41 -0
- package/dist/discord/components-registry.js +57 -0
- package/dist/discord/components.js +816 -0
- package/dist/discord/guilds.js +12 -0
- package/dist/discord/monitor/gateway-plugin.js +48 -0
- package/dist/discord/monitor/presence.js +30 -0
- package/dist/discord/send.components.js +115 -0
- package/dist/discord/send.shared.js +4 -0
- package/dist/discord/ui.js +26 -0
- package/dist/discord/voice-message.js +254 -0
- package/dist/gateway/agent-event-assistant-text.js +5 -0
- package/dist/gateway/agent-prompt.js +33 -0
- package/dist/gateway/auth-rate-limit.js +136 -0
- package/dist/gateway/channel-health-monitor.js +114 -0
- package/dist/gateway/control-ui-contract.js +1 -0
- package/dist/gateway/control-ui-csp.js +15 -0
- package/dist/gateway/gateway-config-prompts.shared.js +25 -0
- package/dist/gateway/http-auth-helpers.js +18 -0
- package/dist/gateway/http-common.js +18 -0
- package/dist/gateway/http-endpoint-helpers.js +27 -0
- package/dist/gateway/node-invoke-sanitize.js +11 -0
- package/dist/gateway/node-invoke-system-run-approval.js +205 -0
- package/dist/gateway/probe-auth.js +21 -0
- package/dist/gateway/protocol/index.js +7 -2
- package/dist/gateway/protocol/schema/mesh.js +54 -0
- package/dist/gateway/protocol/schema/protocol-schemas.js +7 -0
- package/dist/gateway/protocol/schema.js +1 -0
- package/dist/gateway/server/ws-connection/auth-messages.js +54 -0
- package/dist/gateway/server-channels.js +11 -0
- package/dist/gateway/server-methods/attachment-normalize.js +16 -0
- package/dist/gateway/server-methods/base-hash.js +8 -0
- package/dist/gateway/server-methods/mesh.js +700 -0
- package/dist/gateway/server-methods/nodes.handlers.invoke-result.js +55 -0
- package/dist/gateway/server-methods/restart-request.js +13 -0
- package/dist/gateway/server-methods/validation.js +8 -0
- package/dist/gateway/server.agent.gateway-server-agent.mocks.js +35 -0
- package/dist/gateway/server.e2e-registry-helpers.js +1 -0
- package/dist/gateway/server.e2e-ws-harness.js +20 -0
- package/dist/gateway/test-helpers.js +2 -0
- package/dist/gateway/test-helpers.server.js +3 -1
- package/dist/gateway/test-http-response.js +12 -0
- package/dist/gateway/test-openai-responses-model.js +20 -0
- package/dist/gateway/test-temp-config.js +30 -0
- package/dist/gateway/test-with-server.js +32 -0
- package/dist/hooks/bundled/bootstrap-extra-files/handler.js +46 -0
- package/dist/imessage/monitor/abort-handler.js +23 -0
- package/dist/imessage/monitor/inbound-processing.js +346 -0
- package/dist/imessage/monitor/parse-notification.js +64 -0
- package/dist/imessage/target-parsing-helpers.js +92 -0
- package/dist/infra/archive.js +244 -20
- package/dist/infra/detect-package-manager.js +26 -0
- package/dist/infra/exec-approvals-allowlist.js +257 -0
- package/dist/infra/exec-approvals-analysis.js +770 -0
- package/dist/infra/exec-approvals.js +13 -0
- package/dist/infra/file-lock.js +1 -0
- package/dist/infra/gemini-auth.js +39 -0
- package/dist/infra/heartbeat-active-hours.js +85 -0
- package/dist/infra/heartbeat-events-filter.js +50 -0
- package/dist/infra/heartbeat-runner.test-utils.js +39 -0
- package/dist/infra/http-body.js +265 -0
- package/dist/infra/install-package-dir.js +50 -0
- package/dist/infra/install-safe-path.js +49 -0
- package/dist/infra/json-files.js +49 -0
- package/dist/infra/jsonl-socket.js +52 -0
- package/dist/infra/map-size.js +14 -0
- package/dist/infra/net/hostname.js +7 -0
- package/dist/infra/npm-registry-spec.js +39 -0
- package/dist/infra/openclaw-root.js +109 -0
- package/dist/infra/outbound/delivery-queue.js +214 -0
- package/dist/infra/outbound/identity.js +23 -0
- package/dist/infra/outbound/message-action-params.js +307 -0
- package/dist/infra/outbound/tool-payload.js +21 -0
- package/dist/infra/package-json.js +23 -0
- package/dist/infra/pairing-files.js +19 -0
- package/dist/infra/pairing-token.js +9 -0
- package/dist/infra/path-prepend.js +51 -0
- package/dist/infra/process-respawn.js +49 -0
- package/dist/infra/runtime-status.js +16 -0
- package/dist/infra/session-cost-usage.types.js +1 -0
- package/dist/infra/session-maintenance-warning.js +89 -0
- package/dist/infra/system-run-command.js +78 -0
- package/dist/infra/tmp-openclaw-dir.js +81 -0
- package/dist/infra/tmp-poolbot-dir.js +2 -0
- package/dist/infra/update-channels.js +19 -0
- package/dist/line/actions.js +45 -0
- package/dist/line/channel-access-token.js +9 -0
- package/dist/line/flex-templates/basic-cards.js +332 -0
- package/dist/line/flex-templates/common.js +18 -0
- package/dist/line/flex-templates/media-control-cards.js +453 -0
- package/dist/line/flex-templates/message.js +10 -0
- package/dist/line/flex-templates/schedule-cards.js +399 -0
- package/dist/line/flex-templates/types.js +1 -0
- package/dist/line/webhook-node.js +100 -0
- package/dist/line/webhook-utils.js +11 -0
- package/dist/logging/timestamps.js +14 -0
- package/dist/markdown/whatsapp.js +62 -0
- package/dist/media/base64.js +34 -0
- package/dist/media/local-roots.js +32 -0
- package/dist/media/outbound-attachment.js +10 -0
- package/dist/media/read-response-with-limit.js +41 -0
- package/dist/media/sniff-mime-from-base64.js +19 -0
- package/dist/media-understanding/audio-preflight.js +67 -0
- package/dist/media-understanding/fs.js +13 -0
- package/dist/media-understanding/output-extract.js +26 -0
- package/dist/media-understanding/providers/audio.test-helpers.js +34 -0
- package/dist/media-understanding/providers/google/inline-data.js +64 -0
- package/dist/media-understanding/providers/shared.js +7 -0
- package/dist/media-understanding/runner.entries.js +459 -0
- package/dist/memory/batch-error-utils.js +11 -0
- package/dist/memory/batch-http.js +27 -0
- package/dist/memory/batch-output.js +29 -0
- package/dist/memory/batch-runner.js +22 -0
- package/dist/memory/batch-upload.js +23 -0
- package/dist/memory/batch-utils.js +26 -0
- package/dist/memory/embeddings-debug.js +11 -0
- package/dist/memory/embeddings-remote-client.js +22 -0
- package/dist/memory/embeddings-remote-fetch.js +14 -0
- package/dist/memory/manager-embedding-ops.js +616 -0
- package/dist/memory/manager-sync-ops.js +953 -0
- package/dist/memory/qmd-manager.js +1061 -0
- package/dist/memory/qmd-query-parser.js +107 -0
- package/dist/memory/qmd-scope.js +93 -0
- package/dist/memory/search-manager.js +0 -1
- package/dist/memory/sync-index.js +21 -0
- package/dist/memory/sync-progress.js +22 -0
- package/dist/memory/sync-stale.js +30 -0
- package/dist/memory/test-embeddings-mock.js +16 -0
- package/dist/memory/test-manager-helpers.js +14 -0
- package/dist/memory/test-runtime-mocks.js +11 -0
- package/dist/node-host/invoke-browser.js +177 -0
- package/dist/node-host/invoke.js +685 -0
- package/dist/pairing/setup-code.js +285 -0
- package/dist/plugin-sdk/account-id.js +1 -0
- package/dist/plugin-sdk/agent-media-payload.js +13 -0
- package/dist/plugin-sdk/allow-from.js +47 -0
- package/dist/plugin-sdk/command-auth.js +23 -0
- package/dist/plugin-sdk/config-paths.js +9 -0
- package/dist/plugin-sdk/file-lock.js +116 -0
- package/dist/plugin-sdk/json-store.js +31 -0
- package/dist/plugin-sdk/onboarding.js +28 -0
- package/dist/plugin-sdk/provider-auth-result.js +29 -0
- package/dist/plugin-sdk/slack-message-actions.js +133 -0
- package/dist/plugin-sdk/status-helpers.js +35 -0
- package/dist/plugin-sdk/text-chunking.js +31 -0
- package/dist/plugin-sdk/tool-send.js +12 -0
- package/dist/plugin-sdk/webhook-path.js +27 -0
- package/dist/plugin-sdk/webhook-targets.js +34 -0
- package/dist/plugins/hooks.test-helpers.js +21 -0
- package/dist/plugins/uninstall.js +171 -0
- package/dist/process/supervisor/adapters/child.js +143 -0
- package/dist/process/supervisor/adapters/env.js +13 -0
- package/dist/process/supervisor/adapters/pty.js +148 -0
- package/dist/process/supervisor/index.js +10 -0
- package/dist/process/supervisor/registry.js +117 -0
- package/dist/process/supervisor/supervisor.js +244 -0
- package/dist/process/supervisor/types.js +1 -0
- package/dist/providers/google-shared.test-helpers.js +75 -0
- package/dist/security/audit-channel.js +419 -0
- package/dist/security/audit-tool-policy.js +1 -0
- package/dist/security/scan-paths.js +12 -0
- package/dist/sessions/input-provenance.js +55 -0
- package/dist/sessions/session-key-utils.js +7 -0
- package/dist/shared/chat-content.js +31 -0
- package/dist/shared/chat-envelope.js +45 -0
- package/dist/shared/config-eval.js +117 -0
- package/dist/shared/device-auth.js +16 -0
- package/dist/shared/entry-metadata.js +9 -0
- package/dist/shared/entry-status.js +25 -0
- package/dist/shared/frontmatter.js +98 -0
- package/dist/shared/model-param-b.js +19 -0
- package/dist/shared/net/ipv4.js +17 -0
- package/dist/shared/node-match.js +53 -0
- package/dist/shared/requirements.js +128 -0
- package/dist/shared/subagents-format.js +84 -0
- package/dist/shared/usage-aggregates.js +28 -0
- package/dist/signal/monitor/mentions.js +45 -0
- package/dist/signal/rpc-context.js +19 -0
- package/dist/slack/blocks-fallback.js +76 -0
- package/dist/slack/blocks-input.js +40 -0
- package/dist/slack/draft-stream.js +106 -0
- package/dist/slack/message-actions.js +51 -0
- package/dist/slack/modal-metadata.js +32 -0
- package/dist/slack/monitor/events/interactions.js +462 -0
- package/dist/slack/monitor/room-context.js +17 -0
- package/dist/slack/stream-mode.js +41 -0
- package/dist/telegram/bot-native-command-menu.js +64 -0
- package/dist/telegram/bot.media.e2e-harness.js +81 -0
- package/dist/telegram/button-types.js +1 -0
- package/dist/telegram/group-access.js +65 -0
- package/dist/telegram/outbound-params.js +21 -0
- package/dist/telegram/poll-vote-cache.js +21 -0
- package/dist/terminal/health-style.js +36 -0
- package/dist/test-utils/chunk-test-helpers.js +21 -0
- package/dist/test-utils/env.js +72 -0
- package/dist/test-utils/exec-assertions.js +12 -0
- package/dist/test-utils/imessage-test-plugin.js +54 -0
- package/dist/test-utils/mock-http-response.js +17 -0
- package/dist/test-utils/vitest-mock-fn.js +1 -0
- package/dist/tts/tts-core.js +550 -0
- package/dist/utils/chunk-items.js +10 -0
- package/dist/utils/reaction-level.js +52 -0
- package/dist/utils/safe-json.js +22 -0
- package/dist/utils/with-timeout.js +14 -0
- package/dist/web/media.js +17 -5
- package/dist/whatsapp/resolve-outbound-target.js +42 -0
- package/dist/wizard/onboarding.completion.js +74 -0
- package/extensions/bluebubbles/src/account-resolve.ts +29 -0
- package/extensions/bluebubbles/src/monitor-normalize.ts +796 -0
- package/extensions/bluebubbles/src/monitor-processing.ts +1007 -0
- package/extensions/bluebubbles/src/monitor-reply-cache.ts +185 -0
- package/extensions/bluebubbles/src/monitor-shared.ts +51 -0
- package/extensions/bluebubbles/src/multipart.ts +32 -0
- package/extensions/bluebubbles/src/send-helpers.ts +53 -0
- package/extensions/bluebubbles/src/test-harness.ts +50 -0
- package/extensions/bluebubbles/src/test-mocks.ts +11 -0
- package/extensions/device-pair/index.ts +554 -0
- package/extensions/discord/src/channel.js +366 -0
- package/extensions/discord/src/runtime.js +10 -0
- package/extensions/feishu/index.ts +63 -0
- package/extensions/feishu/src/accounts.ts +114 -0
- package/extensions/feishu/src/bitable.ts +739 -0
- package/extensions/feishu/src/bot.ts +965 -0
- package/extensions/feishu/src/channel.ts +351 -0
- package/extensions/feishu/src/client.ts +118 -0
- package/extensions/feishu/src/config-schema.ts +206 -0
- package/extensions/feishu/src/dedup.ts +33 -0
- package/extensions/feishu/src/directory.ts +177 -0
- package/extensions/feishu/src/doc-schema.ts +47 -0
- package/extensions/feishu/src/docx.ts +536 -0
- package/extensions/feishu/src/drive-schema.ts +46 -0
- package/extensions/feishu/src/drive.ts +227 -0
- package/extensions/feishu/src/dynamic-agent.ts +131 -0
- package/extensions/feishu/src/media.ts +449 -0
- package/extensions/feishu/src/mention.ts +126 -0
- package/extensions/feishu/src/monitor.ts +330 -0
- package/extensions/feishu/src/onboarding.ts +359 -0
- package/extensions/feishu/src/outbound.ts +55 -0
- package/extensions/feishu/src/perm-schema.ts +52 -0
- package/extensions/feishu/src/perm.ts +173 -0
- package/extensions/feishu/src/policy.ts +84 -0
- package/extensions/feishu/src/probe.ts +44 -0
- package/extensions/feishu/src/reactions.ts +160 -0
- package/extensions/feishu/src/reply-dispatcher.ts +239 -0
- package/extensions/feishu/src/runtime.ts +14 -0
- package/extensions/feishu/src/send-result.ts +29 -0
- package/extensions/feishu/src/send.ts +335 -0
- package/extensions/feishu/src/streaming-card.ts +223 -0
- package/extensions/feishu/src/targets.ts +78 -0
- package/extensions/feishu/src/tools-config.ts +21 -0
- package/extensions/feishu/src/types.ts +81 -0
- package/extensions/feishu/src/typing.ts +80 -0
- package/extensions/feishu/src/wiki-schema.ts +55 -0
- package/extensions/feishu/src/wiki.ts +232 -0
- package/extensions/imessage/src/channel.js +253 -0
- package/extensions/imessage/src/runtime.js +10 -0
- package/extensions/irc/index.ts +17 -0
- package/extensions/irc/src/accounts.ts +268 -0
- package/extensions/irc/src/channel.ts +367 -0
- package/extensions/irc/src/client.ts +439 -0
- package/extensions/irc/src/config-schema.ts +97 -0
- package/extensions/irc/src/connect-options.ts +30 -0
- package/extensions/irc/src/control-chars.ts +22 -0
- package/extensions/irc/src/inbound.ts +334 -0
- package/extensions/irc/src/monitor.ts +147 -0
- package/extensions/irc/src/normalize.ts +117 -0
- package/extensions/irc/src/onboarding.ts +479 -0
- package/extensions/irc/src/policy.ts +157 -0
- package/extensions/irc/src/probe.ts +53 -0
- package/extensions/irc/src/protocol.ts +169 -0
- package/extensions/irc/src/runtime.ts +14 -0
- package/extensions/irc/src/send.ts +88 -0
- package/extensions/irc/src/types.ts +93 -0
- package/extensions/matrix/src/matrix/client-bootstrap.ts +39 -0
- package/extensions/mattermost/src/mattermost/monitor-onchar.ts +25 -0
- package/extensions/mattermost/src/mattermost/monitor-websocket.ts +221 -0
- package/extensions/mattermost/src/mattermost/reactions.ts +130 -0
- package/extensions/mattermost/src/mattermost/reconnect.ts +103 -0
- package/extensions/minimax-portal-auth/index.ts +161 -0
- package/extensions/minimax-portal-auth/oauth.ts +247 -0
- package/extensions/msteams/src/file-lock.ts +1 -0
- package/extensions/msteams/src/graph.ts +92 -0
- package/extensions/msteams/src/mentions.ts +114 -0
- package/extensions/msteams/src/test-runtime.ts +16 -0
- package/extensions/openai-codex-auth/index.ts +177 -0
- package/extensions/phone-control/index.ts +421 -0
- package/extensions/shared/resolve-target-test-helpers.ts +66 -0
- package/extensions/signal/src/channel.js +273 -0
- package/extensions/signal/src/runtime.js +10 -0
- package/extensions/slack/src/channel.js +489 -0
- package/extensions/slack/src/runtime.js +10 -0
- package/extensions/talk-voice/index.ts +150 -0
- package/extensions/telegram/src/channel.js +424 -0
- package/extensions/telegram/src/runtime.js +10 -0
- package/extensions/thread-ownership/index.ts +133 -0
- package/extensions/tlon/src/account-fields.ts +25 -0
- package/extensions/tlon/src/urbit/base-url.ts +57 -0
- package/extensions/tlon/src/urbit/channel-client.ts +157 -0
- package/extensions/tlon/src/urbit/channel-ops.ts +164 -0
- package/extensions/tlon/src/urbit/context.ts +47 -0
- package/extensions/tlon/src/urbit/errors.ts +51 -0
- package/extensions/tlon/src/urbit/fetch.ts +39 -0
- package/extensions/twitch/src/test-fixtures.ts +30 -0
- package/extensions/voice-call/src/allowlist.ts +19 -0
- package/extensions/whatsapp/src/channel.js +429 -0
- package/extensions/whatsapp/src/runtime.js +10 -0
- package/package.json +1 -1
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { clearSessionQueues } from "../../auto-reply/reply/queue.js";
|
|
4
|
+
import { loadConfig } from "../../config/config.js";
|
|
5
|
+
import { loadSessionStore, resolveStorePath, updateSessionStore } from "../../config/sessions.js";
|
|
6
|
+
import { callGateway } from "../../gateway/call.js";
|
|
7
|
+
import { logVerbose } from "../../globals.js";
|
|
8
|
+
import { isSubagentSessionKey, parseAgentSessionKey, } from "../../routing/session-key.js";
|
|
9
|
+
import { formatDurationCompact, formatTokenUsageDisplay, resolveTotalTokens, truncateLine, } from "../../shared/subagents-format.js";
|
|
10
|
+
import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/message-channel.js";
|
|
11
|
+
import { AGENT_LANE_SUBAGENT } from "../lanes.js";
|
|
12
|
+
import { abortEmbeddedPiRun } from "../pi-embedded.js";
|
|
13
|
+
import { optionalStringEnum } from "../schema/typebox.js";
|
|
14
|
+
import { getSubagentDepthFromSessionStore } from "../subagent-depth.js";
|
|
15
|
+
import { clearSubagentRunSteerRestart, listSubagentRunsForRequester, markSubagentRunTerminated, markSubagentRunForSteerRestart, replaceSubagentRunAfterSteer, } from "../subagent-registry.js";
|
|
16
|
+
import { jsonResult, readNumberParam, readStringParam } from "./common.js";
|
|
17
|
+
import { resolveInternalSessionKey, resolveMainSessionAlias } from "./sessions-helpers.js";
|
|
18
|
+
const SUBAGENT_ACTIONS = ["list", "kill", "steer"];
|
|
19
|
+
const DEFAULT_RECENT_MINUTES = 30;
|
|
20
|
+
const MAX_RECENT_MINUTES = 24 * 60;
|
|
21
|
+
const MAX_STEER_MESSAGE_CHARS = 4_000;
|
|
22
|
+
const STEER_RATE_LIMIT_MS = 2_000;
|
|
23
|
+
const STEER_ABORT_SETTLE_TIMEOUT_MS = 5_000;
|
|
24
|
+
const steerRateLimit = new Map();
|
|
25
|
+
const SubagentsToolSchema = Type.Object({
|
|
26
|
+
action: optionalStringEnum(SUBAGENT_ACTIONS),
|
|
27
|
+
target: Type.Optional(Type.String()),
|
|
28
|
+
message: Type.Optional(Type.String()),
|
|
29
|
+
recentMinutes: Type.Optional(Type.Number({ minimum: 1 })),
|
|
30
|
+
});
|
|
31
|
+
function resolveRunLabel(entry, fallback = "subagent") {
|
|
32
|
+
const raw = entry.label?.trim() || entry.task?.trim() || "";
|
|
33
|
+
return raw || fallback;
|
|
34
|
+
}
|
|
35
|
+
function resolveRunStatus(entry) {
|
|
36
|
+
if (!entry.endedAt) {
|
|
37
|
+
return "running";
|
|
38
|
+
}
|
|
39
|
+
const status = entry.outcome?.status ?? "done";
|
|
40
|
+
if (status === "ok") {
|
|
41
|
+
return "done";
|
|
42
|
+
}
|
|
43
|
+
if (status === "error") {
|
|
44
|
+
return "failed";
|
|
45
|
+
}
|
|
46
|
+
return status;
|
|
47
|
+
}
|
|
48
|
+
function sortRuns(runs) {
|
|
49
|
+
return [...runs].toSorted((a, b) => {
|
|
50
|
+
const aTime = a.startedAt ?? a.createdAt ?? 0;
|
|
51
|
+
const bTime = b.startedAt ?? b.createdAt ?? 0;
|
|
52
|
+
return bTime - aTime;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function resolveModelRef(entry) {
|
|
56
|
+
const model = typeof entry?.model === "string" ? entry.model.trim() : "";
|
|
57
|
+
const provider = typeof entry?.modelProvider === "string" ? entry.modelProvider.trim() : "";
|
|
58
|
+
if (model.includes("/")) {
|
|
59
|
+
return model;
|
|
60
|
+
}
|
|
61
|
+
if (model && provider) {
|
|
62
|
+
return `${provider}/${model}`;
|
|
63
|
+
}
|
|
64
|
+
if (model) {
|
|
65
|
+
return model;
|
|
66
|
+
}
|
|
67
|
+
if (provider) {
|
|
68
|
+
return provider;
|
|
69
|
+
}
|
|
70
|
+
// Fall back to override fields which are populated at spawn time,
|
|
71
|
+
// before the first run completes and writes model/modelProvider.
|
|
72
|
+
const overrideModel = typeof entry?.modelOverride === "string" ? entry.modelOverride.trim() : "";
|
|
73
|
+
const overrideProvider = typeof entry?.providerOverride === "string" ? entry.providerOverride.trim() : "";
|
|
74
|
+
if (overrideModel.includes("/")) {
|
|
75
|
+
return overrideModel;
|
|
76
|
+
}
|
|
77
|
+
if (overrideModel && overrideProvider) {
|
|
78
|
+
return `${overrideProvider}/${overrideModel}`;
|
|
79
|
+
}
|
|
80
|
+
if (overrideModel) {
|
|
81
|
+
return overrideModel;
|
|
82
|
+
}
|
|
83
|
+
return overrideProvider || undefined;
|
|
84
|
+
}
|
|
85
|
+
function resolveModelDisplay(entry, fallbackModel) {
|
|
86
|
+
const modelRef = resolveModelRef(entry) || fallbackModel || undefined;
|
|
87
|
+
if (!modelRef) {
|
|
88
|
+
return "model n/a";
|
|
89
|
+
}
|
|
90
|
+
const slash = modelRef.lastIndexOf("/");
|
|
91
|
+
if (slash >= 0 && slash < modelRef.length - 1) {
|
|
92
|
+
return modelRef.slice(slash + 1);
|
|
93
|
+
}
|
|
94
|
+
return modelRef;
|
|
95
|
+
}
|
|
96
|
+
function resolveSubagentTarget(runs, token, options) {
|
|
97
|
+
const trimmed = token?.trim();
|
|
98
|
+
if (!trimmed) {
|
|
99
|
+
return { error: "Missing subagent target." };
|
|
100
|
+
}
|
|
101
|
+
const sorted = sortRuns(runs);
|
|
102
|
+
const recentMinutes = options?.recentMinutes ?? DEFAULT_RECENT_MINUTES;
|
|
103
|
+
const recentCutoff = Date.now() - recentMinutes * 60_000;
|
|
104
|
+
const numericOrder = [
|
|
105
|
+
...sorted.filter((entry) => !entry.endedAt),
|
|
106
|
+
...sorted.filter((entry) => !!entry.endedAt && (entry.endedAt ?? 0) >= recentCutoff),
|
|
107
|
+
];
|
|
108
|
+
if (trimmed === "last") {
|
|
109
|
+
return { entry: sorted[0] };
|
|
110
|
+
}
|
|
111
|
+
if (/^\d+$/.test(trimmed)) {
|
|
112
|
+
const idx = Number.parseInt(trimmed, 10);
|
|
113
|
+
if (!Number.isFinite(idx) || idx <= 0 || idx > numericOrder.length) {
|
|
114
|
+
return { error: `Invalid subagent index: ${trimmed}` };
|
|
115
|
+
}
|
|
116
|
+
return { entry: numericOrder[idx - 1] };
|
|
117
|
+
}
|
|
118
|
+
if (trimmed.includes(":")) {
|
|
119
|
+
const bySessionKey = sorted.find((entry) => entry.childSessionKey === trimmed);
|
|
120
|
+
return bySessionKey
|
|
121
|
+
? { entry: bySessionKey }
|
|
122
|
+
: { error: `Unknown subagent session: ${trimmed}` };
|
|
123
|
+
}
|
|
124
|
+
const lowered = trimmed.toLowerCase();
|
|
125
|
+
const byExactLabel = sorted.filter((entry) => resolveRunLabel(entry).toLowerCase() === lowered);
|
|
126
|
+
if (byExactLabel.length === 1) {
|
|
127
|
+
return { entry: byExactLabel[0] };
|
|
128
|
+
}
|
|
129
|
+
if (byExactLabel.length > 1) {
|
|
130
|
+
return { error: `Ambiguous subagent label: ${trimmed}` };
|
|
131
|
+
}
|
|
132
|
+
const byLabelPrefix = sorted.filter((entry) => resolveRunLabel(entry).toLowerCase().startsWith(lowered));
|
|
133
|
+
if (byLabelPrefix.length === 1) {
|
|
134
|
+
return { entry: byLabelPrefix[0] };
|
|
135
|
+
}
|
|
136
|
+
if (byLabelPrefix.length > 1) {
|
|
137
|
+
return { error: `Ambiguous subagent label prefix: ${trimmed}` };
|
|
138
|
+
}
|
|
139
|
+
const byRunIdPrefix = sorted.filter((entry) => entry.runId.startsWith(trimmed));
|
|
140
|
+
if (byRunIdPrefix.length === 1) {
|
|
141
|
+
return { entry: byRunIdPrefix[0] };
|
|
142
|
+
}
|
|
143
|
+
if (byRunIdPrefix.length > 1) {
|
|
144
|
+
return { error: `Ambiguous subagent run id prefix: ${trimmed}` };
|
|
145
|
+
}
|
|
146
|
+
return { error: `Unknown subagent target: ${trimmed}` };
|
|
147
|
+
}
|
|
148
|
+
function resolveStorePathForKey(cfg, key, parsed) {
|
|
149
|
+
return resolveStorePath(cfg.session?.store, {
|
|
150
|
+
agentId: parsed?.agentId,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function resolveSessionEntryForKey(params) {
|
|
154
|
+
const parsed = parseAgentSessionKey(params.key);
|
|
155
|
+
const storePath = resolveStorePathForKey(params.cfg, params.key, parsed);
|
|
156
|
+
let store = params.cache.get(storePath);
|
|
157
|
+
if (!store) {
|
|
158
|
+
store = loadSessionStore(storePath);
|
|
159
|
+
params.cache.set(storePath, store);
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
storePath,
|
|
163
|
+
entry: store[params.key],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function resolveRequesterKey(params) {
|
|
167
|
+
const { mainKey, alias } = resolveMainSessionAlias(params.cfg);
|
|
168
|
+
const callerRaw = params.agentSessionKey?.trim() || alias;
|
|
169
|
+
const callerSessionKey = resolveInternalSessionKey({
|
|
170
|
+
key: callerRaw,
|
|
171
|
+
alias,
|
|
172
|
+
mainKey,
|
|
173
|
+
});
|
|
174
|
+
if (!isSubagentSessionKey(callerSessionKey)) {
|
|
175
|
+
return {
|
|
176
|
+
requesterSessionKey: callerSessionKey,
|
|
177
|
+
callerSessionKey,
|
|
178
|
+
callerIsSubagent: false,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
// Check if this sub-agent can spawn children (orchestrator).
|
|
182
|
+
// If so, it should see its own children, not its parent's children.
|
|
183
|
+
const callerDepth = getSubagentDepthFromSessionStore(callerSessionKey, { cfg: params.cfg });
|
|
184
|
+
const maxSpawnDepth = params.cfg.agents?.defaults?.subagents?.maxSpawnDepth ?? 1;
|
|
185
|
+
if (callerDepth < maxSpawnDepth) {
|
|
186
|
+
// Orchestrator sub-agent: use its own session key as requester
|
|
187
|
+
// so it sees children it spawned.
|
|
188
|
+
return {
|
|
189
|
+
requesterSessionKey: callerSessionKey,
|
|
190
|
+
callerSessionKey,
|
|
191
|
+
callerIsSubagent: true,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
// Leaf sub-agent: walk up to its parent so it can see sibling runs.
|
|
195
|
+
const cache = new Map();
|
|
196
|
+
const callerEntry = resolveSessionEntryForKey({
|
|
197
|
+
cfg: params.cfg,
|
|
198
|
+
key: callerSessionKey,
|
|
199
|
+
cache,
|
|
200
|
+
}).entry;
|
|
201
|
+
const spawnedBy = typeof callerEntry?.spawnedBy === "string" ? callerEntry.spawnedBy.trim() : "";
|
|
202
|
+
return {
|
|
203
|
+
requesterSessionKey: spawnedBy || callerSessionKey,
|
|
204
|
+
callerSessionKey,
|
|
205
|
+
callerIsSubagent: true,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
async function killSubagentRun(params) {
|
|
209
|
+
if (params.entry.endedAt) {
|
|
210
|
+
return { killed: false };
|
|
211
|
+
}
|
|
212
|
+
const childSessionKey = params.entry.childSessionKey;
|
|
213
|
+
const resolved = resolveSessionEntryForKey({
|
|
214
|
+
cfg: params.cfg,
|
|
215
|
+
key: childSessionKey,
|
|
216
|
+
cache: params.cache,
|
|
217
|
+
});
|
|
218
|
+
const sessionId = resolved.entry?.sessionId;
|
|
219
|
+
const aborted = sessionId ? abortEmbeddedPiRun(sessionId) : false;
|
|
220
|
+
const cleared = clearSessionQueues([childSessionKey, sessionId]);
|
|
221
|
+
if (cleared.followupCleared > 0 || cleared.laneCleared > 0) {
|
|
222
|
+
logVerbose(`subagents tool kill: cleared followups=${cleared.followupCleared} lane=${cleared.laneCleared} keys=${cleared.keys.join(",")}`);
|
|
223
|
+
}
|
|
224
|
+
if (resolved.entry) {
|
|
225
|
+
await updateSessionStore(resolved.storePath, (store) => {
|
|
226
|
+
const current = store[childSessionKey];
|
|
227
|
+
if (!current) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
current.abortedLastRun = true;
|
|
231
|
+
current.updatedAt = Date.now();
|
|
232
|
+
store[childSessionKey] = current;
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
const marked = markSubagentRunTerminated({
|
|
236
|
+
runId: params.entry.runId,
|
|
237
|
+
childSessionKey,
|
|
238
|
+
reason: "killed",
|
|
239
|
+
});
|
|
240
|
+
const killed = marked > 0 || aborted || cleared.followupCleared > 0 || cleared.laneCleared > 0;
|
|
241
|
+
return { killed, sessionId };
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Recursively kill all descendant subagent runs spawned by a given parent session key.
|
|
245
|
+
* This ensures that when a subagent is killed, all of its children (and their children) are also killed.
|
|
246
|
+
*/
|
|
247
|
+
async function cascadeKillChildren(params) {
|
|
248
|
+
const childRuns = listSubagentRunsForRequester(params.parentChildSessionKey);
|
|
249
|
+
const seenChildSessionKeys = params.seenChildSessionKeys ?? new Set();
|
|
250
|
+
let killed = 0;
|
|
251
|
+
const labels = [];
|
|
252
|
+
for (const run of childRuns) {
|
|
253
|
+
const childKey = run.childSessionKey?.trim();
|
|
254
|
+
if (!childKey || seenChildSessionKeys.has(childKey)) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
seenChildSessionKeys.add(childKey);
|
|
258
|
+
if (!run.endedAt) {
|
|
259
|
+
const stopResult = await killSubagentRun({
|
|
260
|
+
cfg: params.cfg,
|
|
261
|
+
entry: run,
|
|
262
|
+
cache: params.cache,
|
|
263
|
+
});
|
|
264
|
+
if (stopResult.killed) {
|
|
265
|
+
killed += 1;
|
|
266
|
+
labels.push(resolveRunLabel(run));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// Recurse for grandchildren even if this parent already ended.
|
|
270
|
+
const cascade = await cascadeKillChildren({
|
|
271
|
+
cfg: params.cfg,
|
|
272
|
+
parentChildSessionKey: childKey,
|
|
273
|
+
cache: params.cache,
|
|
274
|
+
seenChildSessionKeys,
|
|
275
|
+
});
|
|
276
|
+
killed += cascade.killed;
|
|
277
|
+
labels.push(...cascade.labels);
|
|
278
|
+
}
|
|
279
|
+
return { killed, labels };
|
|
280
|
+
}
|
|
281
|
+
function buildListText(params) {
|
|
282
|
+
const lines = [];
|
|
283
|
+
lines.push("active subagents:");
|
|
284
|
+
if (params.active.length === 0) {
|
|
285
|
+
lines.push("(none)");
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
lines.push(...params.active.map((entry) => entry.line));
|
|
289
|
+
}
|
|
290
|
+
lines.push("");
|
|
291
|
+
lines.push(`recent (last ${params.recentMinutes}m):`);
|
|
292
|
+
if (params.recent.length === 0) {
|
|
293
|
+
lines.push("(none)");
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
lines.push(...params.recent.map((entry) => entry.line));
|
|
297
|
+
}
|
|
298
|
+
return lines.join("\n");
|
|
299
|
+
}
|
|
300
|
+
export function createSubagentsTool(opts) {
|
|
301
|
+
return {
|
|
302
|
+
label: "Subagents",
|
|
303
|
+
name: "subagents",
|
|
304
|
+
description: "List, kill, or steer spawned sub-agents for this requester session. Use this for sub-agent orchestration.",
|
|
305
|
+
parameters: SubagentsToolSchema,
|
|
306
|
+
execute: async (_toolCallId, args) => {
|
|
307
|
+
const params = args;
|
|
308
|
+
const action = (readStringParam(params, "action") ?? "list");
|
|
309
|
+
const cfg = loadConfig();
|
|
310
|
+
const requester = resolveRequesterKey({
|
|
311
|
+
cfg,
|
|
312
|
+
agentSessionKey: opts?.agentSessionKey,
|
|
313
|
+
});
|
|
314
|
+
const runs = sortRuns(listSubagentRunsForRequester(requester.requesterSessionKey));
|
|
315
|
+
const recentMinutesRaw = readNumberParam(params, "recentMinutes");
|
|
316
|
+
const recentMinutes = recentMinutesRaw
|
|
317
|
+
? Math.max(1, Math.min(MAX_RECENT_MINUTES, Math.floor(recentMinutesRaw)))
|
|
318
|
+
: DEFAULT_RECENT_MINUTES;
|
|
319
|
+
if (action === "list") {
|
|
320
|
+
const now = Date.now();
|
|
321
|
+
const recentCutoff = now - recentMinutes * 60_000;
|
|
322
|
+
const cache = new Map();
|
|
323
|
+
let index = 1;
|
|
324
|
+
const buildListEntry = (entry, runtimeMs) => {
|
|
325
|
+
const sessionEntry = resolveSessionEntryForKey({
|
|
326
|
+
cfg,
|
|
327
|
+
key: entry.childSessionKey,
|
|
328
|
+
cache,
|
|
329
|
+
}).entry;
|
|
330
|
+
const totalTokens = resolveTotalTokens(sessionEntry);
|
|
331
|
+
const usageText = formatTokenUsageDisplay(sessionEntry);
|
|
332
|
+
const status = resolveRunStatus(entry);
|
|
333
|
+
const runtime = formatDurationCompact(runtimeMs);
|
|
334
|
+
const label = truncateLine(resolveRunLabel(entry), 48);
|
|
335
|
+
const task = truncateLine(entry.task.trim(), 72);
|
|
336
|
+
const line = `${index}. ${label} (${resolveModelDisplay(sessionEntry, entry.model)}, ${runtime}${usageText ? `, ${usageText}` : ""}) ${status}${task.toLowerCase() !== label.toLowerCase() ? ` - ${task}` : ""}`;
|
|
337
|
+
const baseView = {
|
|
338
|
+
index,
|
|
339
|
+
runId: entry.runId,
|
|
340
|
+
sessionKey: entry.childSessionKey,
|
|
341
|
+
label,
|
|
342
|
+
task,
|
|
343
|
+
status,
|
|
344
|
+
runtime,
|
|
345
|
+
runtimeMs,
|
|
346
|
+
model: resolveModelRef(sessionEntry) || entry.model,
|
|
347
|
+
totalTokens,
|
|
348
|
+
startedAt: entry.startedAt,
|
|
349
|
+
};
|
|
350
|
+
index += 1;
|
|
351
|
+
return { line, view: entry.endedAt ? { ...baseView, endedAt: entry.endedAt } : baseView };
|
|
352
|
+
};
|
|
353
|
+
const active = runs
|
|
354
|
+
.filter((entry) => !entry.endedAt)
|
|
355
|
+
.map((entry) => buildListEntry(entry, now - (entry.startedAt ?? entry.createdAt)));
|
|
356
|
+
const recent = runs
|
|
357
|
+
.filter((entry) => !!entry.endedAt && (entry.endedAt ?? 0) >= recentCutoff)
|
|
358
|
+
.map((entry) => buildListEntry(entry, (entry.endedAt ?? now) - (entry.startedAt ?? entry.createdAt)));
|
|
359
|
+
const text = buildListText({ active, recent, recentMinutes });
|
|
360
|
+
return jsonResult({
|
|
361
|
+
status: "ok",
|
|
362
|
+
action: "list",
|
|
363
|
+
requesterSessionKey: requester.requesterSessionKey,
|
|
364
|
+
callerSessionKey: requester.callerSessionKey,
|
|
365
|
+
callerIsSubagent: requester.callerIsSubagent,
|
|
366
|
+
total: runs.length,
|
|
367
|
+
active: active.map((entry) => entry.view),
|
|
368
|
+
recent: recent.map((entry) => entry.view),
|
|
369
|
+
text,
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
if (action === "kill") {
|
|
373
|
+
const target = readStringParam(params, "target", { required: true });
|
|
374
|
+
if (target === "all" || target === "*") {
|
|
375
|
+
const cache = new Map();
|
|
376
|
+
const seenChildSessionKeys = new Set();
|
|
377
|
+
const killedLabels = [];
|
|
378
|
+
let killed = 0;
|
|
379
|
+
for (const entry of runs) {
|
|
380
|
+
const childKey = entry.childSessionKey?.trim();
|
|
381
|
+
if (!childKey || seenChildSessionKeys.has(childKey)) {
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
seenChildSessionKeys.add(childKey);
|
|
385
|
+
if (!entry.endedAt) {
|
|
386
|
+
const stopResult = await killSubagentRun({ cfg, entry, cache });
|
|
387
|
+
if (stopResult.killed) {
|
|
388
|
+
killed += 1;
|
|
389
|
+
killedLabels.push(resolveRunLabel(entry));
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// Traverse descendants even when the direct run is already finished.
|
|
393
|
+
const cascade = await cascadeKillChildren({
|
|
394
|
+
cfg,
|
|
395
|
+
parentChildSessionKey: childKey,
|
|
396
|
+
cache,
|
|
397
|
+
seenChildSessionKeys,
|
|
398
|
+
});
|
|
399
|
+
killed += cascade.killed;
|
|
400
|
+
killedLabels.push(...cascade.labels);
|
|
401
|
+
}
|
|
402
|
+
return jsonResult({
|
|
403
|
+
status: "ok",
|
|
404
|
+
action: "kill",
|
|
405
|
+
target: "all",
|
|
406
|
+
killed,
|
|
407
|
+
labels: killedLabels,
|
|
408
|
+
text: killed > 0
|
|
409
|
+
? `killed ${killed} subagent${killed === 1 ? "" : "s"}.`
|
|
410
|
+
: "no running subagents to kill.",
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
const resolved = resolveSubagentTarget(runs, target, { recentMinutes });
|
|
414
|
+
if (!resolved.entry) {
|
|
415
|
+
return jsonResult({
|
|
416
|
+
status: "error",
|
|
417
|
+
action: "kill",
|
|
418
|
+
target,
|
|
419
|
+
error: resolved.error ?? "Unknown subagent target.",
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
const killCache = new Map();
|
|
423
|
+
const stopResult = await killSubagentRun({
|
|
424
|
+
cfg,
|
|
425
|
+
entry: resolved.entry,
|
|
426
|
+
cache: killCache,
|
|
427
|
+
});
|
|
428
|
+
const seenChildSessionKeys = new Set();
|
|
429
|
+
const targetChildKey = resolved.entry.childSessionKey?.trim();
|
|
430
|
+
if (targetChildKey) {
|
|
431
|
+
seenChildSessionKeys.add(targetChildKey);
|
|
432
|
+
}
|
|
433
|
+
// Traverse descendants even when the selected run is already finished.
|
|
434
|
+
const cascade = await cascadeKillChildren({
|
|
435
|
+
cfg,
|
|
436
|
+
parentChildSessionKey: resolved.entry.childSessionKey,
|
|
437
|
+
cache: killCache,
|
|
438
|
+
seenChildSessionKeys,
|
|
439
|
+
});
|
|
440
|
+
if (!stopResult.killed && cascade.killed === 0) {
|
|
441
|
+
return jsonResult({
|
|
442
|
+
status: "done",
|
|
443
|
+
action: "kill",
|
|
444
|
+
target,
|
|
445
|
+
runId: resolved.entry.runId,
|
|
446
|
+
sessionKey: resolved.entry.childSessionKey,
|
|
447
|
+
text: `${resolveRunLabel(resolved.entry)} is already finished.`,
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
const cascadeText = cascade.killed > 0
|
|
451
|
+
? ` (+ ${cascade.killed} descendant${cascade.killed === 1 ? "" : "s"})`
|
|
452
|
+
: "";
|
|
453
|
+
return jsonResult({
|
|
454
|
+
status: "ok",
|
|
455
|
+
action: "kill",
|
|
456
|
+
target,
|
|
457
|
+
runId: resolved.entry.runId,
|
|
458
|
+
sessionKey: resolved.entry.childSessionKey,
|
|
459
|
+
label: resolveRunLabel(resolved.entry),
|
|
460
|
+
cascadeKilled: cascade.killed,
|
|
461
|
+
cascadeLabels: cascade.killed > 0 ? cascade.labels : undefined,
|
|
462
|
+
text: stopResult.killed
|
|
463
|
+
? `killed ${resolveRunLabel(resolved.entry)}${cascadeText}.`
|
|
464
|
+
: `killed ${cascade.killed} descendant${cascade.killed === 1 ? "" : "s"} of ${resolveRunLabel(resolved.entry)}.`,
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
if (action === "steer") {
|
|
468
|
+
const target = readStringParam(params, "target", { required: true });
|
|
469
|
+
const message = readStringParam(params, "message", { required: true });
|
|
470
|
+
if (message.length > MAX_STEER_MESSAGE_CHARS) {
|
|
471
|
+
return jsonResult({
|
|
472
|
+
status: "error",
|
|
473
|
+
action: "steer",
|
|
474
|
+
target,
|
|
475
|
+
error: `Message too long (${message.length} chars, max ${MAX_STEER_MESSAGE_CHARS}).`,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
const resolved = resolveSubagentTarget(runs, target, { recentMinutes });
|
|
479
|
+
if (!resolved.entry) {
|
|
480
|
+
return jsonResult({
|
|
481
|
+
status: "error",
|
|
482
|
+
action: "steer",
|
|
483
|
+
target,
|
|
484
|
+
error: resolved.error ?? "Unknown subagent target.",
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
if (resolved.entry.endedAt) {
|
|
488
|
+
return jsonResult({
|
|
489
|
+
status: "done",
|
|
490
|
+
action: "steer",
|
|
491
|
+
target,
|
|
492
|
+
runId: resolved.entry.runId,
|
|
493
|
+
sessionKey: resolved.entry.childSessionKey,
|
|
494
|
+
text: `${resolveRunLabel(resolved.entry)} is already finished.`,
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
if (requester.callerIsSubagent &&
|
|
498
|
+
requester.callerSessionKey === resolved.entry.childSessionKey) {
|
|
499
|
+
return jsonResult({
|
|
500
|
+
status: "forbidden",
|
|
501
|
+
action: "steer",
|
|
502
|
+
target,
|
|
503
|
+
runId: resolved.entry.runId,
|
|
504
|
+
sessionKey: resolved.entry.childSessionKey,
|
|
505
|
+
error: "Subagents cannot steer themselves.",
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
const rateKey = `${requester.callerSessionKey}:${resolved.entry.childSessionKey}`;
|
|
509
|
+
const now = Date.now();
|
|
510
|
+
const lastSentAt = steerRateLimit.get(rateKey) ?? 0;
|
|
511
|
+
if (now - lastSentAt < STEER_RATE_LIMIT_MS) {
|
|
512
|
+
return jsonResult({
|
|
513
|
+
status: "rate_limited",
|
|
514
|
+
action: "steer",
|
|
515
|
+
target,
|
|
516
|
+
runId: resolved.entry.runId,
|
|
517
|
+
sessionKey: resolved.entry.childSessionKey,
|
|
518
|
+
error: "Steer rate limit exceeded. Wait a moment before sending another steer.",
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
steerRateLimit.set(rateKey, now);
|
|
522
|
+
// Suppress announce for the interrupted run before aborting so we don't
|
|
523
|
+
// emit stale pre-steer findings if the run exits immediately.
|
|
524
|
+
markSubagentRunForSteerRestart(resolved.entry.runId);
|
|
525
|
+
const targetSession = resolveSessionEntryForKey({
|
|
526
|
+
cfg,
|
|
527
|
+
key: resolved.entry.childSessionKey,
|
|
528
|
+
cache: new Map(),
|
|
529
|
+
});
|
|
530
|
+
const sessionId = typeof targetSession.entry?.sessionId === "string" && targetSession.entry.sessionId.trim()
|
|
531
|
+
? targetSession.entry.sessionId.trim()
|
|
532
|
+
: undefined;
|
|
533
|
+
// Interrupt current work first so steer takes precedence immediately.
|
|
534
|
+
if (sessionId) {
|
|
535
|
+
abortEmbeddedPiRun(sessionId);
|
|
536
|
+
}
|
|
537
|
+
const cleared = clearSessionQueues([resolved.entry.childSessionKey, sessionId]);
|
|
538
|
+
if (cleared.followupCleared > 0 || cleared.laneCleared > 0) {
|
|
539
|
+
logVerbose(`subagents tool steer: cleared followups=${cleared.followupCleared} lane=${cleared.laneCleared} keys=${cleared.keys.join(",")}`);
|
|
540
|
+
}
|
|
541
|
+
// Best effort: wait for the interrupted run to settle so the steer
|
|
542
|
+
// message appends onto the existing conversation context.
|
|
543
|
+
try {
|
|
544
|
+
await callGateway({
|
|
545
|
+
method: "agent.wait",
|
|
546
|
+
params: {
|
|
547
|
+
runId: resolved.entry.runId,
|
|
548
|
+
timeoutMs: STEER_ABORT_SETTLE_TIMEOUT_MS,
|
|
549
|
+
},
|
|
550
|
+
timeoutMs: STEER_ABORT_SETTLE_TIMEOUT_MS + 2_000,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
catch {
|
|
554
|
+
// Continue even if wait fails; steer should still be attempted.
|
|
555
|
+
}
|
|
556
|
+
const idempotencyKey = crypto.randomUUID();
|
|
557
|
+
let runId = idempotencyKey;
|
|
558
|
+
try {
|
|
559
|
+
const response = await callGateway({
|
|
560
|
+
method: "agent",
|
|
561
|
+
params: {
|
|
562
|
+
message,
|
|
563
|
+
sessionKey: resolved.entry.childSessionKey,
|
|
564
|
+
sessionId,
|
|
565
|
+
idempotencyKey,
|
|
566
|
+
deliver: false,
|
|
567
|
+
channel: INTERNAL_MESSAGE_CHANNEL,
|
|
568
|
+
lane: AGENT_LANE_SUBAGENT,
|
|
569
|
+
timeout: 0,
|
|
570
|
+
},
|
|
571
|
+
timeoutMs: 10_000,
|
|
572
|
+
});
|
|
573
|
+
if (typeof response?.runId === "string" && response.runId) {
|
|
574
|
+
runId = response.runId;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
catch (err) {
|
|
578
|
+
// Replacement launch failed; restore normal announce behavior for the
|
|
579
|
+
// original run so completion is not silently suppressed.
|
|
580
|
+
clearSubagentRunSteerRestart(resolved.entry.runId);
|
|
581
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
582
|
+
return jsonResult({
|
|
583
|
+
status: "error",
|
|
584
|
+
action: "steer",
|
|
585
|
+
target,
|
|
586
|
+
runId,
|
|
587
|
+
sessionKey: resolved.entry.childSessionKey,
|
|
588
|
+
sessionId,
|
|
589
|
+
error,
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
replaceSubagentRunAfterSteer({
|
|
593
|
+
previousRunId: resolved.entry.runId,
|
|
594
|
+
nextRunId: runId,
|
|
595
|
+
fallback: resolved.entry,
|
|
596
|
+
runTimeoutSeconds: resolved.entry.runTimeoutSeconds ?? 0,
|
|
597
|
+
});
|
|
598
|
+
return jsonResult({
|
|
599
|
+
status: "accepted",
|
|
600
|
+
action: "steer",
|
|
601
|
+
target,
|
|
602
|
+
runId,
|
|
603
|
+
sessionKey: resolved.entry.childSessionKey,
|
|
604
|
+
sessionId,
|
|
605
|
+
mode: "restart",
|
|
606
|
+
label: resolveRunLabel(resolved.entry),
|
|
607
|
+
text: `steered ${resolveRunLabel(resolved.entry)}.`,
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
return jsonResult({
|
|
611
|
+
status: "error",
|
|
612
|
+
error: "Unsupported action.",
|
|
613
|
+
});
|
|
614
|
+
},
|
|
615
|
+
};
|
|
616
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { resolveUserPath } from "../utils.js";
|
|
3
|
+
export function normalizeWorkspaceDir(workspaceDir) {
|
|
4
|
+
const trimmed = workspaceDir?.trim();
|
|
5
|
+
if (!trimmed) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
const expanded = trimmed.startsWith("~") ? resolveUserPath(trimmed) : trimmed;
|
|
9
|
+
const resolved = path.resolve(expanded);
|
|
10
|
+
// Refuse filesystem roots as "workspace" (too broad; almost always a bug).
|
|
11
|
+
if (resolved === path.parse(resolved).root) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return resolved;
|
|
15
|
+
}
|
|
16
|
+
export function resolveWorkspaceRoot(workspaceDir) {
|
|
17
|
+
return normalizeWorkspaceDir(workspaceDir) ?? process.cwd();
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "./agent-scope.js";
|
|
2
|
+
export function listAgentWorkspaceDirs(cfg) {
|
|
3
|
+
const dirs = new Set();
|
|
4
|
+
const list = cfg.agents?.list;
|
|
5
|
+
if (Array.isArray(list)) {
|
|
6
|
+
for (const entry of list) {
|
|
7
|
+
if (entry && typeof entry === "object" && typeof entry.id === "string") {
|
|
8
|
+
dirs.add(resolveAgentWorkspaceDir(cfg, entry.id));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
dirs.add(resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg)));
|
|
13
|
+
return [...dirs];
|
|
14
|
+
}
|