@poolzin/pool-bot 2026.2.25 → 2026.2.26
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/dist/acp/event-mapper.js +87 -22
- package/dist/acp/meta.js +12 -6
- package/dist/agents/agent-paths.js +8 -9
- package/dist/agents/agent-scope.js +7 -5
- package/dist/agents/auth-profiles/oauth.js +148 -64
- package/dist/agents/auth-profiles/session-override.js +13 -7
- package/dist/agents/bash-tools.exec-host-gateway.js +14 -4
- package/dist/agents/bash-tools.exec-runtime.js +2 -25
- package/dist/agents/bedrock-discovery.js +3 -1
- package/dist/agents/byteplus-models.js +97 -0
- package/dist/agents/chutes-oauth.js +1 -0
- package/dist/agents/cli-runner/helpers.js +4 -0
- package/dist/agents/compaction.js +41 -14
- package/dist/agents/doubao-models.js +121 -0
- package/dist/agents/failover-error.js +2 -0
- package/dist/agents/huggingface-models.js +5 -3
- package/dist/agents/live-model-filter.js +5 -0
- package/dist/agents/minimax-vlm.js +10 -8
- package/dist/agents/model-auth.js +6 -0
- package/dist/agents/model-catalog.js +3 -1
- package/dist/agents/model-selection.js +7 -1
- package/dist/agents/models-config.providers.js +93 -11
- package/dist/agents/ollama-stream.js +117 -4
- package/dist/agents/opencode-zen-models.js +22 -11
- package/dist/agents/pi-embedded-helpers/errors.js +55 -33
- package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
- package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +29 -7
- package/dist/agents/pi-embedded-runner/extensions.js +28 -26
- package/dist/agents/pi-embedded-runner/google.js +20 -8
- package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
- package/dist/agents/pi-embedded-runner/run.js +71 -12
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
- package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
- package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
- package/dist/agents/pi-embedded-runner/thinking.js +42 -0
- package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
- package/dist/agents/pi-embedded-runner/utils.js +7 -10
- package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
- package/dist/agents/pi-embedded-subscribe.js +9 -4
- package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
- package/dist/agents/pi-embedded-utils.js +3 -0
- package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
- package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
- package/dist/agents/pi-settings.js +40 -0
- package/dist/agents/pi-tools.policy.js +2 -1
- package/dist/agents/provider/config-loader.js +1 -1
- package/dist/agents/sandbox/browser.js +170 -33
- package/dist/agents/sandbox/config-hash.js +14 -27
- package/dist/agents/sandbox/config.js +21 -2
- package/dist/agents/sandbox/constants.js +2 -0
- package/dist/agents/sandbox/docker.js +16 -2
- package/dist/agents/sandbox/novnc-auth.js +62 -0
- package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
- package/dist/agents/sandbox/shared.js +10 -6
- package/dist/agents/sandbox-paths.js +24 -11
- package/dist/agents/schema/clean-for-gemini.js +132 -85
- package/dist/agents/session-slug.js +10 -5
- package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
- package/dist/agents/session-tool-result-guard.js +3 -1
- package/dist/agents/session-transcript-repair.js +40 -6
- package/dist/agents/skills/bundled-dir.js +19 -5
- package/dist/agents/skills/env-overrides.js +124 -43
- package/dist/agents/skills/frontmatter.js +6 -6
- package/dist/agents/skills/plugin-skills.js +14 -7
- package/dist/agents/skills/workspace.js +1 -0
- package/dist/agents/subagent-announce.js +251 -49
- package/dist/agents/subagent-lifecycle-events.js +19 -0
- package/dist/agents/subagent-registry-cleanup.js +31 -0
- package/dist/agents/subagent-registry-completion.js +68 -0
- package/dist/agents/subagent-registry-queries.js +117 -0
- package/dist/agents/subagent-registry-state.js +46 -0
- package/dist/agents/subagent-registry.js +252 -221
- package/dist/agents/subagent-registry.store.js +1 -0
- package/dist/agents/subagent-registry.types.js +1 -0
- package/dist/agents/subagent-spawn.js +195 -7
- package/dist/agents/system-prompt.js +22 -6
- package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
- package/dist/agents/test-helpers/fast-core-tools.js +1 -17
- package/dist/agents/timeout.js +18 -6
- package/dist/agents/tool-call-id.js +1 -1
- package/dist/agents/tool-display-common.js +162 -29
- package/dist/agents/tool-images.js +82 -9
- package/dist/agents/tool-policy.js +51 -26
- package/dist/agents/tools/browser-tool.js +2 -2
- package/dist/agents/tools/canvas-tool.js +27 -1
- package/dist/agents/tools/common.js +45 -0
- package/dist/agents/tools/discord-actions-guild.js +4 -1
- package/dist/agents/tools/gateway-tool.js +3 -1
- package/dist/agents/tools/nodes-utils.js +1 -10
- package/dist/agents/tools/sessions-send-helpers.js +12 -6
- package/dist/agents/tools/sessions-spawn-tool.js +8 -2
- package/dist/agents/tools/subagents-tool.js +2 -1
- package/dist/agents/tools/whatsapp-actions.js +10 -2
- package/dist/agents/tools/whatsapp-target-auth.js +18 -0
- package/dist/agents/transcript-policy.js +22 -8
- package/dist/agents/venice-models.js +11 -3
- package/dist/auto-reply/commands-registry.data.js +51 -0
- package/dist/auto-reply/commands-registry.js +4 -3
- package/dist/auto-reply/group-activation.js +10 -5
- package/dist/auto-reply/inbound-debounce.js +10 -5
- package/dist/auto-reply/reply/abort.js +1 -1
- package/dist/auto-reply/reply/agent-runner-execution.js +4 -1
- package/dist/auto-reply/reply/bash-command.js +41 -39
- package/dist/auto-reply/reply/command-gates.js +25 -0
- package/dist/auto-reply/reply/commands-allowlist.js +111 -72
- package/dist/auto-reply/reply/commands-bash.js +6 -5
- package/dist/auto-reply/reply/commands-config.js +30 -28
- package/dist/auto-reply/reply/commands-core.js +2 -1
- package/dist/auto-reply/reply/commands-info.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +65 -14
- package/dist/auto-reply/reply/commands-session.js +237 -82
- package/dist/auto-reply/reply/commands-setunset.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
- package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
- package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
- package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
- package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
- package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
- package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
- package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
- package/dist/auto-reply/reply/commands-subagents.js +51 -587
- package/dist/auto-reply/reply/commands-tts.js +10 -5
- package/dist/auto-reply/reply/config-value.js +10 -5
- package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
- package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
- package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
- package/dist/auto-reply/reply/followup-runner.js +1 -0
- package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
- package/dist/auto-reply/reply/get-reply-directives.js +17 -28
- package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
- package/dist/auto-reply/reply/get-reply.js +71 -12
- package/dist/auto-reply/reply/model-selection.js +80 -39
- package/dist/auto-reply/reply/queue/enqueue.js +10 -5
- package/dist/auto-reply/reply/queue/state.js +13 -12
- package/dist/auto-reply/reply/reply-payloads.js +67 -36
- package/dist/auto-reply/reply/reply-reference.js +9 -8
- package/dist/auto-reply/reply/route-reply.js +15 -8
- package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
- package/dist/auto-reply/reply/session.js +22 -6
- package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
- package/dist/auto-reply/reply/subagents-utils.js +56 -30
- package/dist/auto-reply/reply/typing.js +46 -21
- package/dist/auto-reply/send-policy.js +14 -7
- package/dist/auto-reply/status.js +140 -16
- package/dist/auto-reply/templating.js +10 -5
- package/dist/auto-reply/thinking.js +7 -16
- package/dist/auto-reply/tokens.js +21 -5
- package/dist/browser/bridge-server.js +36 -20
- package/dist/browser/cdp.helpers.js +7 -14
- package/dist/browser/cdp.js +35 -15
- package/dist/browser/chrome.profile-decoration.js +7 -4
- package/dist/browser/config.js +4 -0
- package/dist/browser/extension-relay-auth.js +55 -0
- package/dist/browser/extension-relay.js +74 -29
- package/dist/browser/navigation-guard.js +9 -1
- package/dist/browser/paths.js +77 -0
- package/dist/browser/profiles.js +13 -8
- package/dist/browser/pw-ai-module.js +10 -5
- package/dist/browser/pw-session.js +76 -39
- package/dist/browser/pw-tools-core.interactions.js +14 -7
- package/dist/browser/pw-tools-core.state.js +12 -6
- package/dist/browser/routes/agent.act.js +2 -2
- package/dist/browser/server-context.js +7 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/allow-from.js +2 -1
- package/dist/channels/allowlists/resolve-utils.js +43 -19
- package/dist/channels/channel-config.js +14 -7
- package/dist/channels/draft-stream-loop.js +7 -0
- package/dist/channels/model-overrides.js +82 -0
- package/dist/channels/plugins/normalize/imessage.js +14 -7
- package/dist/channels/plugins/normalize/slack.js +10 -5
- package/dist/channels/plugins/normalize/telegram.js +14 -7
- package/dist/channels/plugins/outbound/discord.js +80 -8
- package/dist/channels/plugins/outbound/signal.js +11 -11
- package/dist/channels/plugins/setup-helpers.js +10 -5
- package/dist/channels/sender-label.js +14 -7
- package/dist/channels/session.js +4 -2
- package/dist/channels/status-reactions.js +297 -0
- package/dist/cli/banner.js +1 -1
- package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
- package/dist/cli/cli-name.js +11 -11
- package/dist/cli/cli-utils.js +13 -3
- package/dist/cli/command-format.js +1 -1
- package/dist/cli/config-cli.js +1 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
- package/dist/cli/daemon-cli/lifecycle.js +64 -2
- package/dist/cli/daemon-cli/restart-health.js +126 -0
- package/dist/cli/daemon-cli/status.gather.js +9 -13
- package/dist/cli/daemon-cli/status.print.js +2 -10
- package/dist/cli/deps.js +27 -22
- package/dist/cli/gateway-cli/run-loop.js +23 -5
- package/dist/cli/node-cli/register.js +14 -5
- package/dist/cli/nodes-media-utils.js +7 -2
- package/dist/cli/outbound-send-deps.js +2 -9
- package/dist/cli/outbound-send-mapping.js +11 -0
- package/dist/cli/pairing-cli.js +40 -14
- package/dist/cli/plugins-cli.js +34 -41
- package/dist/cli/ports.js +11 -10
- package/dist/cli/program/command-registry.js +2 -11
- package/dist/cli/program/command-tree.js +16 -0
- package/dist/cli/program/preaction.js +13 -9
- package/dist/cli/program/register.configure.js +3 -18
- package/dist/cli/program/register.maintenance.js +2 -2
- package/dist/cli/program/register.onboard.js +2 -0
- package/dist/cli/program/register.status-health-sessions.js +16 -17
- package/dist/cli/program/register.subclis.js +93 -52
- package/dist/cli/route.js +11 -7
- package/dist/cli/system-cli.js +36 -46
- package/dist/cli/update-cli/shared.js +22 -9
- package/dist/cli/update-cli/update-command.js +89 -14
- package/dist/cli/update-cli/wizard.js +6 -12
- package/dist/commands/agent/run-context.js +18 -5
- package/dist/commands/agent/session-store.js +17 -4
- package/dist/commands/agent.js +22 -2
- package/dist/commands/agents.bindings.js +14 -7
- package/dist/commands/agents.commands.add.js +13 -9
- package/dist/commands/agents.commands.identity.js +12 -6
- package/dist/commands/agents.commands.list.js +11 -6
- package/dist/commands/agents.config.js +8 -10
- package/dist/commands/agents.providers.js +12 -6
- package/dist/commands/auth-choice-options.js +103 -75
- package/dist/commands/auth-choice.apply.byteplus.js +55 -0
- package/dist/commands/auth-choice.apply.js +4 -0
- package/dist/commands/auth-choice.apply.minimax.js +61 -13
- package/dist/commands/auth-choice.apply.openai.js +3 -1
- package/dist/commands/auth-choice.apply.volcengine.js +55 -0
- package/dist/commands/auth-choice.preferred-provider.js +2 -0
- package/dist/commands/channels/remove.js +13 -6
- package/dist/commands/channels/shared.js +4 -14
- package/dist/commands/configure.commands.js +14 -0
- package/dist/commands/configure.gateway.js +2 -4
- package/dist/commands/configure.js +1 -1
- package/dist/commands/configure.shared.js +11 -0
- package/dist/commands/daemon-install-helpers.js +2 -2
- package/dist/commands/dashboard.js +12 -10
- package/dist/commands/docs.js +14 -8
- package/dist/commands/doctor-config-flow.js +11 -9
- package/dist/commands/doctor-legacy-config.js +281 -0
- package/dist/commands/doctor-state-integrity.js +99 -23
- package/dist/commands/doctor-update.js +12 -9
- package/dist/commands/models/list.list-command.js +7 -5
- package/dist/commands/models/set-image.js +2 -21
- package/dist/commands/node-daemon-install-helpers.js +10 -8
- package/dist/commands/onboard-auth.config-minimax.js +54 -80
- package/dist/commands/onboard-auth.config-opencode.js +2 -18
- package/dist/commands/onboard-auth.credentials.js +90 -13
- package/dist/commands/onboard-auth.js +1 -1
- package/dist/commands/onboard-auth.models.js +6 -5
- package/dist/commands/onboard-hooks.js +1 -1
- package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
- package/dist/commands/onboard-provider-auth-flags.js +14 -0
- package/dist/commands/onboard-remote.js +14 -7
- package/dist/commands/onboard.js +11 -13
- package/dist/commands/sandbox-display.js +6 -5
- package/dist/commands/status-all/diagnosis.js +14 -10
- package/dist/commands/status-all/format.js +1 -0
- package/dist/commands/status.gateway-probe.js +1 -16
- package/dist/commands/systemd-linger.js +12 -6
- package/dist/config/agent-limits.js +2 -0
- package/dist/config/commands.js +30 -16
- package/dist/config/config-paths.js +9 -11
- package/dist/config/defaults.js +22 -2
- package/dist/config/discord-preview-streaming.js +104 -0
- package/dist/config/env-vars.js +37 -8
- package/dist/config/includes.js +4 -0
- package/dist/config/io.js +97 -12
- package/dist/config/legacy.migrations.part-1.js +189 -78
- package/dist/config/legacy.shared.js +3 -1
- package/dist/config/merge-patch.js +4 -0
- package/dist/config/prototype-keys.js +4 -0
- package/dist/config/schema.help.js +44 -7
- package/dist/config/schema.labels.js +38 -6
- package/dist/config/sessions/delivery-info.js +10 -3
- package/dist/config/sessions/main-session.js +10 -5
- package/dist/config/sessions/session-file.js +33 -0
- package/dist/config/sessions/session-key.js +10 -5
- package/dist/config/sessions/store.js +1 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/zod-schema.agent-runtime.js +11 -0
- package/dist/config/zod-schema.js +148 -13
- package/dist/config/zod-schema.providers-core.js +78 -4
- package/dist/config/zod-schema.providers.js +6 -1
- package/dist/config/zod-schema.session.js +41 -2
- package/dist/cron/run-log.js +3 -0
- package/dist/cron/schedule.js +21 -10
- package/dist/cron/service/ops.js +35 -21
- package/dist/cron/service/timer.js +116 -16
- package/dist/cron/stagger.js +3 -1
- package/dist/discord/api.js +12 -6
- package/dist/discord/draft-chunking.js +22 -0
- package/dist/discord/draft-stream.js +124 -0
- package/dist/discord/monitor/agent-components.js +1 -1
- package/dist/discord/monitor/commands.js +5 -0
- package/dist/discord/monitor/gateway-plugin.js +2 -1
- package/dist/discord/monitor/listeners.js +37 -27
- package/dist/discord/monitor/message-handler.js +4 -1
- package/dist/discord/monitor/message-handler.preflight.js +65 -8
- package/dist/discord/monitor/message-handler.process.js +246 -217
- package/dist/discord/monitor/message-utils.js +143 -6
- package/dist/discord/monitor/model-picker-preferences.js +143 -0
- package/dist/discord/monitor/model-picker.js +651 -0
- package/dist/discord/monitor/native-command.js +573 -16
- package/dist/discord/monitor/provider.allowlist.js +223 -0
- package/dist/discord/monitor/provider.js +275 -347
- package/dist/discord/monitor/provider.lifecycle.js +100 -0
- package/dist/discord/monitor/reply-delivery.js +123 -16
- package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
- package/dist/discord/monitor/thread-bindings.js +4 -0
- package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
- package/dist/discord/monitor/thread-bindings.manager.js +423 -0
- package/dist/discord/monitor/thread-bindings.messages.js +55 -0
- package/dist/discord/monitor/thread-bindings.state.js +358 -0
- package/dist/discord/monitor/thread-bindings.types.js +6 -0
- package/dist/discord/resolve-users.js +33 -21
- package/dist/discord/send.channels.js +15 -0
- package/dist/discord/send.js +3 -2
- package/dist/discord/send.outbound.js +82 -26
- package/dist/discord/send.permissions.js +83 -30
- package/dist/discord/send.reactions.js +8 -4
- package/dist/discord/token.js +10 -5
- package/dist/discord/voice/command.js +263 -0
- package/dist/discord/voice/manager.js +531 -0
- package/dist/gateway/auth.js +34 -10
- package/dist/gateway/call.js +4 -16
- package/dist/gateway/client.js +28 -4
- package/dist/gateway/config-reload.js +3 -4
- package/dist/gateway/control-ui.js +219 -96
- package/dist/gateway/hooks-mapping.js +88 -38
- package/dist/gateway/http-auth-helpers.js +3 -2
- package/dist/gateway/http-endpoint-helpers.js +1 -0
- package/dist/gateway/net.js +54 -12
- package/dist/gateway/node-invoke-system-run-approval.js +14 -35
- package/dist/gateway/node-registry.js +10 -5
- package/dist/gateway/openai-http.js +1 -0
- package/dist/gateway/openresponses-http.js +1 -0
- package/dist/gateway/origin-check.js +1 -18
- package/dist/gateway/protocol/index.js +4 -3
- package/dist/gateway/protocol/schema/cron.js +1 -0
- package/dist/gateway/protocol/schema/devices.js +1 -0
- package/dist/gateway/protocol/schema/protocol-schemas.js +2 -1
- package/dist/gateway/protocol/schema/sessions.js +6 -0
- package/dist/gateway/role-policy.js +17 -0
- package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
- package/dist/gateway/server/ws-connection/message-handler.js +175 -148
- package/dist/gateway/server-chat.js +83 -25
- package/dist/gateway/server-constants.js +10 -9
- package/dist/gateway/server-cron.js +1 -0
- package/dist/gateway/server-http.js +16 -7
- package/dist/gateway/server-maintenance.js +20 -5
- package/dist/gateway/server-methods/chat.js +10 -6
- package/dist/gateway/server-methods/config.js +12 -14
- package/dist/gateway/server-methods/devices.js +17 -3
- package/dist/gateway/server-methods/models.js +11 -1
- package/dist/gateway/server-methods/sessions.js +64 -8
- package/dist/gateway/server-methods/usage.js +162 -75
- package/dist/gateway/server-node-events.js +29 -0
- package/dist/gateway/server-runtime-config.js +34 -13
- package/dist/gateway/server-startup-memory.js +17 -11
- package/dist/gateway/session-utils.fs.js +32 -34
- package/dist/gateway/sessions-resolve.js +17 -5
- package/dist/gateway/test-helpers.openai-mock.js +14 -7
- package/dist/gateway/tools-invoke-http.js +21 -10
- package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
- package/dist/hooks/bundled/command-logger/handler.js +7 -2
- package/dist/hooks/bundled/session-memory/handler.js +6 -5
- package/dist/hooks/frontmatter.js +6 -6
- package/dist/hooks/gmail-watcher.js +11 -6
- package/dist/hooks/internal-hooks.js +11 -1
- package/dist/hooks/llm-slug-generator.js +4 -1
- package/dist/hooks/workspace.js +47 -17
- package/dist/imessage/accounts.js +9 -20
- package/dist/imessage/monitor/inbound-processing.js +2 -1
- package/dist/infra/archive.js +174 -73
- package/dist/infra/control-ui-assets.js +14 -6
- package/dist/infra/device-pairing.js +108 -29
- package/dist/infra/env.js +10 -5
- package/dist/infra/exec-approvals-allowlist.js +122 -0
- package/dist/infra/exec-approvals-analysis.js +34 -3
- package/dist/infra/exec-approvals.js +5 -17
- package/dist/infra/exec-safe-bin-policy.js +53 -45
- package/dist/infra/fs-safe.js +71 -39
- package/dist/infra/gateway-lock.js +6 -2
- package/dist/infra/heartbeat-wake.js +6 -12
- package/dist/infra/host-env-security-policy.json +19 -0
- package/dist/infra/host-env-security.js +66 -0
- package/dist/infra/net/ssrf.js +131 -38
- package/dist/infra/outbound/bound-delivery-router.js +88 -0
- package/dist/infra/outbound/channel-selection.js +12 -6
- package/dist/infra/outbound/envelope.js +1 -1
- package/dist/infra/outbound/format.js +12 -6
- package/dist/infra/outbound/payloads.js +14 -7
- package/dist/infra/outbound/session-binding-service.js +123 -0
- package/dist/infra/path-guards.js +25 -0
- package/dist/infra/provider-usage.fetch.codex.js +7 -15
- package/dist/infra/provider-usage.fetch.gemini.js +14 -11
- package/dist/infra/provider-usage.fetch.shared.js +30 -1
- package/dist/infra/provider-usage.fetch.zai.js +10 -9
- package/dist/infra/retry-policy.js +4 -2
- package/dist/infra/retry.js +9 -5
- package/dist/infra/session-cost-usage.js +107 -59
- package/dist/infra/session-maintenance-warning.js +3 -1
- package/dist/infra/shell-env.js +98 -34
- package/dist/infra/ssh-config.js +12 -6
- package/dist/infra/system-run-command.js +49 -4
- package/dist/infra/update-channels.js +10 -5
- package/dist/line/accounts.js +5 -7
- package/dist/line/bot-access.js +8 -20
- package/dist/line/bot-handlers.js +3 -1
- package/dist/link-understanding/detect.js +15 -7
- package/dist/media/constants.js +15 -6
- package/dist/media/image-ops.js +7 -0
- package/dist/media/local-roots.js +3 -2
- package/dist/media-understanding/apply.js +4 -1
- package/dist/media-understanding/concurrency.js +8 -20
- package/dist/memory/backend-config.js +45 -6
- package/dist/memory/embeddings.js +10 -4
- package/dist/memory/fs-utils.js +23 -0
- package/dist/memory/manager-search.js +12 -6
- package/dist/memory/manager-sync-ops.js +12 -2
- package/dist/memory/qmd-manager.js +466 -53
- package/dist/memory/query-expansion.js +167 -3
- package/dist/memory/status-format.js +10 -5
- package/dist/memory/sync-memory-files.js +1 -1
- package/dist/node-host/invoke-system-run.js +281 -0
- package/dist/node-host/invoke.js +55 -337
- package/dist/pairing/pairing-store.js +22 -0
- package/dist/plugin-sdk/allow-from.js +1 -1
- package/dist/plugin-sdk/command-auth.js +3 -1
- package/dist/plugin-sdk/index.js +6 -3
- package/dist/plugin-sdk/webhook-targets.js +32 -0
- package/dist/plugins/bundled-dir.js +9 -6
- package/dist/plugins/hooks.js +50 -0
- package/dist/plugins/install.js +28 -16
- package/dist/plugins/runtime.js +3 -17
- package/dist/plugins/update.js +78 -12
- package/dist/process/spawn-utils.js +14 -7
- package/dist/providers/github-copilot-token.js +11 -6
- package/dist/providers/qwen-portal-oauth.js +14 -6
- package/dist/routing/account-id.js +30 -0
- package/dist/routing/resolve-route.js +3 -7
- package/dist/routing/session-key.js +2 -16
- package/dist/security/audit-channel.js +93 -2
- package/dist/security/audit-extra.async.js +159 -5
- package/dist/security/audit-extra.js +1 -1
- package/dist/security/audit-extra.sync.js +85 -6
- package/dist/security/audit.js +40 -4
- package/dist/security/dm-policy-shared.js +44 -0
- package/dist/security/external-content.js +26 -6
- package/dist/shared/entry-status.js +6 -0
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-match.js +11 -4
- package/dist/shared/operator-scope-compat.js +8 -3
- package/dist/signal/accounts.js +7 -20
- package/dist/signal/monitor/event-handler.js +3 -1
- package/dist/slack/accounts.js +6 -19
- package/dist/slack/actions.js +11 -3
- package/dist/slack/monitor/auth.js +1 -1
- package/dist/slack/monitor/message-handler/dispatch.js +50 -29
- package/dist/slack/monitor/replies.js +15 -7
- package/dist/slack/monitor/slash.js +22 -13
- package/dist/slack/resolve-channels.js +10 -5
- package/dist/slack/send.js +102 -12
- package/dist/slack/stream-mode.js +10 -0
- package/dist/slack/streaming.js +4 -2
- package/dist/telegram/accounts.js +19 -14
- package/dist/telegram/bot/helpers.js +3 -5
- package/dist/telegram/bot-access.js +35 -36
- package/dist/telegram/bot-handlers.js +120 -148
- package/dist/telegram/bot-message-context.js +68 -9
- package/dist/telegram/bot-message-dispatch.js +155 -90
- package/dist/telegram/bot-native-commands.js +16 -0
- package/dist/telegram/draft-stream.js +14 -1
- package/dist/telegram/inline-buttons.js +5 -15
- package/dist/telegram/monitor.js +11 -7
- package/dist/telegram/network-config.js +19 -7
- package/dist/telegram/send.js +3 -2
- package/dist/telegram/sent-message-cache.js +5 -6
- package/dist/telegram/status-reaction-variants.js +208 -0
- package/dist/telegram/sticker-cache.js +11 -9
- package/dist/terminal/theme.js +12 -12
- package/dist/tts/tts.js +80 -567
- package/dist/tui/components/chat-log.js +41 -8
- package/dist/tui/theme/theme.js +10 -12
- package/dist/tui/tui-local-shell.js +16 -6
- package/dist/tui/tui.js +58 -6
- package/dist/utils/account-id.js +2 -4
- package/dist/utils/boolean.js +10 -5
- package/dist/utils/directive-tags.js +11 -0
- package/dist/utils/queue-helpers.js +67 -12
- package/dist/web/auto-reply/deliver-reply.js +8 -4
- package/dist/web/auto-reply/mentions.js +10 -5
- package/dist/web/auto-reply/monitor/group-members.js +14 -7
- package/dist/web/auto-reply/monitor/process-message.js +45 -24
- package/dist/web/inbound/access-control.js +5 -2
- package/dist/web/login-qr.js +12 -6
- package/dist/web/media.js +123 -16
- package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
- package/extensions/bluebubbles/src/monitor.ts +208 -1950
- package/package.json +1 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { danger } from "../../globals.js";
|
|
2
|
+
import { attachDiscordGatewayLogging } from "../gateway-logging.js";
|
|
3
|
+
import { getDiscordGatewayEmitter, waitForDiscordGatewayStop } from "../monitor.gateway.js";
|
|
4
|
+
import { registerGateway, unregisterGateway } from "./gateway-registry.js";
|
|
5
|
+
export async function runDiscordGatewayLifecycle(params) {
|
|
6
|
+
const gateway = params.client.getPlugin("gateway");
|
|
7
|
+
if (gateway) {
|
|
8
|
+
registerGateway(params.accountId, gateway);
|
|
9
|
+
}
|
|
10
|
+
const gatewayEmitter = getDiscordGatewayEmitter(gateway);
|
|
11
|
+
const stopGatewayLogging = attachDiscordGatewayLogging({
|
|
12
|
+
emitter: gatewayEmitter,
|
|
13
|
+
runtime: params.runtime,
|
|
14
|
+
});
|
|
15
|
+
const onAbort = () => {
|
|
16
|
+
if (!gateway) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
gatewayEmitter?.once("error", () => { });
|
|
20
|
+
gateway.options.reconnect = { maxAttempts: 0 };
|
|
21
|
+
gateway.disconnect();
|
|
22
|
+
};
|
|
23
|
+
if (params.abortSignal?.aborted) {
|
|
24
|
+
onAbort();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
params.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
28
|
+
}
|
|
29
|
+
const HELLO_TIMEOUT_MS = 30000;
|
|
30
|
+
let helloTimeoutId;
|
|
31
|
+
const onGatewayDebug = (msg) => {
|
|
32
|
+
const message = String(msg);
|
|
33
|
+
if (!message.includes("WebSocket connection opened")) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (helloTimeoutId) {
|
|
37
|
+
clearTimeout(helloTimeoutId);
|
|
38
|
+
}
|
|
39
|
+
helloTimeoutId = setTimeout(() => {
|
|
40
|
+
if (!gateway?.isConnected) {
|
|
41
|
+
params.runtime.log?.(danger(`connection stalled: no HELLO received within ${HELLO_TIMEOUT_MS}ms, forcing reconnect`));
|
|
42
|
+
gateway?.disconnect();
|
|
43
|
+
gateway?.connect(false);
|
|
44
|
+
}
|
|
45
|
+
helloTimeoutId = undefined;
|
|
46
|
+
}, HELLO_TIMEOUT_MS);
|
|
47
|
+
};
|
|
48
|
+
gatewayEmitter?.on("debug", onGatewayDebug);
|
|
49
|
+
let sawDisallowedIntents = false;
|
|
50
|
+
try {
|
|
51
|
+
if (params.execApprovalsHandler) {
|
|
52
|
+
await params.execApprovalsHandler.start();
|
|
53
|
+
}
|
|
54
|
+
await waitForDiscordGatewayStop({
|
|
55
|
+
gateway: gateway
|
|
56
|
+
? {
|
|
57
|
+
emitter: gatewayEmitter,
|
|
58
|
+
disconnect: () => gateway.disconnect(),
|
|
59
|
+
}
|
|
60
|
+
: undefined,
|
|
61
|
+
abortSignal: params.abortSignal,
|
|
62
|
+
onGatewayError: (err) => {
|
|
63
|
+
if (params.isDisallowedIntentsError(err)) {
|
|
64
|
+
sawDisallowedIntents = true;
|
|
65
|
+
params.runtime.error?.(danger("discord: gateway closed with code 4014 (missing privileged gateway intents). Enable the required intents in the Discord Developer Portal or disable them in config."));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
params.runtime.error?.(danger(`discord gateway error: ${String(err)}`));
|
|
69
|
+
},
|
|
70
|
+
shouldStopOnError: (err) => {
|
|
71
|
+
const message = String(err);
|
|
72
|
+
return (message.includes("Max reconnect attempts") ||
|
|
73
|
+
message.includes("Fatal Gateway error") ||
|
|
74
|
+
params.isDisallowedIntentsError(err));
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
if (!sawDisallowedIntents && !params.isDisallowedIntentsError(err)) {
|
|
80
|
+
throw err;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
unregisterGateway(params.accountId);
|
|
85
|
+
stopGatewayLogging();
|
|
86
|
+
if (helloTimeoutId) {
|
|
87
|
+
clearTimeout(helloTimeoutId);
|
|
88
|
+
}
|
|
89
|
+
gatewayEmitter?.removeListener("debug", onGatewayDebug);
|
|
90
|
+
params.abortSignal?.removeEventListener("abort", onAbort);
|
|
91
|
+
if (params.voiceManager) {
|
|
92
|
+
await params.voiceManager.destroy();
|
|
93
|
+
params.voiceManagerRef.current = null;
|
|
94
|
+
}
|
|
95
|
+
if (params.execApprovalsHandler) {
|
|
96
|
+
await params.execApprovalsHandler.stop();
|
|
97
|
+
}
|
|
98
|
+
params.threadBindings.stop();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -1,8 +1,104 @@
|
|
|
1
|
+
import { resolveAgentAvatar } from "../../agents/identity-avatar.js";
|
|
2
|
+
import { loadConfig } from "../../config/config.js";
|
|
1
3
|
import { convertMarkdownTables } from "../../markdown/tables.js";
|
|
2
4
|
import { chunkDiscordTextWithMode } from "../chunk.js";
|
|
3
|
-
import { sendMessageDiscord, sendVoiceMessageDiscord } from "../send.js";
|
|
5
|
+
import { sendMessageDiscord, sendVoiceMessageDiscord, sendWebhookMessageDiscord } from "../send.js";
|
|
6
|
+
function resolveTargetChannelId(target) {
|
|
7
|
+
if (!target.startsWith("channel:")) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
const channelId = target.slice("channel:".length).trim();
|
|
11
|
+
return channelId || undefined;
|
|
12
|
+
}
|
|
13
|
+
function resolveBoundThreadBinding(params) {
|
|
14
|
+
const sessionKey = params.sessionKey?.trim();
|
|
15
|
+
if (!params.threadBindings || !sessionKey) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const bindings = params.threadBindings.listBySessionKey(sessionKey);
|
|
19
|
+
if (bindings.length === 0) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const targetChannelId = resolveTargetChannelId(params.target);
|
|
23
|
+
if (!targetChannelId) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
return bindings.find((entry) => entry.threadId === targetChannelId);
|
|
27
|
+
}
|
|
28
|
+
function resolveBindingPersona(binding) {
|
|
29
|
+
if (!binding) {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
const baseLabel = binding.label?.trim() || binding.agentId;
|
|
33
|
+
const username = (`🤖 ${baseLabel}`.trim() || "🤖 agent").slice(0, 80);
|
|
34
|
+
let avatarUrl;
|
|
35
|
+
try {
|
|
36
|
+
const avatar = resolveAgentAvatar(loadConfig(), binding.agentId);
|
|
37
|
+
if (avatar.kind === "remote") {
|
|
38
|
+
avatarUrl = avatar.url;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
avatarUrl = undefined;
|
|
43
|
+
}
|
|
44
|
+
return { username, avatarUrl };
|
|
45
|
+
}
|
|
46
|
+
async function sendDiscordChunkWithFallback(params) {
|
|
47
|
+
const text = params.text.trim();
|
|
48
|
+
if (!text) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const binding = params.binding;
|
|
52
|
+
if (binding?.webhookId && binding?.webhookToken) {
|
|
53
|
+
try {
|
|
54
|
+
await sendWebhookMessageDiscord(text, {
|
|
55
|
+
webhookId: binding.webhookId,
|
|
56
|
+
webhookToken: binding.webhookToken,
|
|
57
|
+
accountId: binding.accountId,
|
|
58
|
+
threadId: binding.threadId,
|
|
59
|
+
replyTo: params.replyTo,
|
|
60
|
+
username: params.username,
|
|
61
|
+
avatarUrl: params.avatarUrl,
|
|
62
|
+
});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Fall through to the standard bot sender path.
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
await sendMessageDiscord(params.target, text, {
|
|
70
|
+
token: params.token,
|
|
71
|
+
rest: params.rest,
|
|
72
|
+
accountId: params.accountId,
|
|
73
|
+
replyTo: params.replyTo,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
4
76
|
export async function deliverDiscordReply(params) {
|
|
5
77
|
const chunkLimit = Math.min(params.textLimit, 2000);
|
|
78
|
+
const replyTo = params.replyToId?.trim() || undefined;
|
|
79
|
+
const replyToMode = params.replyToMode ?? "all";
|
|
80
|
+
// replyToMode=first should only apply to the first physical send.
|
|
81
|
+
const replyOnce = replyToMode === "first";
|
|
82
|
+
let replyUsed = false;
|
|
83
|
+
const resolveReplyTo = () => {
|
|
84
|
+
if (!replyTo) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
if (!replyOnce) {
|
|
88
|
+
return replyTo;
|
|
89
|
+
}
|
|
90
|
+
if (replyUsed) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
replyUsed = true;
|
|
94
|
+
return replyTo;
|
|
95
|
+
};
|
|
96
|
+
const binding = resolveBoundThreadBinding({
|
|
97
|
+
threadBindings: params.threadBindings,
|
|
98
|
+
sessionKey: params.sessionKey,
|
|
99
|
+
target: params.target,
|
|
100
|
+
});
|
|
101
|
+
const persona = resolveBindingPersona(binding);
|
|
6
102
|
for (const payload of params.replies) {
|
|
7
103
|
const mediaList = payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []);
|
|
8
104
|
const rawText = payload.text ?? "";
|
|
@@ -11,7 +107,6 @@ export async function deliverDiscordReply(params) {
|
|
|
11
107
|
if (!text && mediaList.length === 0) {
|
|
12
108
|
continue;
|
|
13
109
|
}
|
|
14
|
-
const replyTo = params.replyToId?.trim() || undefined;
|
|
15
110
|
if (mediaList.length === 0) {
|
|
16
111
|
const mode = params.chunkMode ?? "length";
|
|
17
112
|
const chunks = chunkDiscordTextWithMode(text, {
|
|
@@ -23,15 +118,20 @@ export async function deliverDiscordReply(params) {
|
|
|
23
118
|
chunks.push(text);
|
|
24
119
|
}
|
|
25
120
|
for (const chunk of chunks) {
|
|
26
|
-
|
|
27
|
-
if (!trimmed) {
|
|
121
|
+
if (!chunk.trim()) {
|
|
28
122
|
continue;
|
|
29
123
|
}
|
|
30
|
-
|
|
124
|
+
const replyTo = resolveReplyTo();
|
|
125
|
+
await sendDiscordChunkWithFallback({
|
|
126
|
+
target: params.target,
|
|
127
|
+
text: chunk,
|
|
31
128
|
token: params.token,
|
|
32
129
|
rest: params.rest,
|
|
33
130
|
accountId: params.accountId,
|
|
34
131
|
replyTo,
|
|
132
|
+
binding,
|
|
133
|
+
username: persona.username,
|
|
134
|
+
avatarUrl: persona.avatarUrl,
|
|
35
135
|
});
|
|
36
136
|
}
|
|
37
137
|
continue;
|
|
@@ -40,25 +140,30 @@ export async function deliverDiscordReply(params) {
|
|
|
40
140
|
if (!firstMedia) {
|
|
41
141
|
continue;
|
|
42
142
|
}
|
|
43
|
-
// Voice message path: audioAsVoice flag routes through sendVoiceMessageDiscord
|
|
143
|
+
// Voice message path: audioAsVoice flag routes through sendVoiceMessageDiscord.
|
|
44
144
|
if (payload.audioAsVoice) {
|
|
145
|
+
const replyTo = resolveReplyTo();
|
|
45
146
|
await sendVoiceMessageDiscord(params.target, firstMedia, {
|
|
46
147
|
token: params.token,
|
|
47
148
|
rest: params.rest,
|
|
48
149
|
accountId: params.accountId,
|
|
49
150
|
replyTo,
|
|
50
151
|
});
|
|
51
|
-
// Voice messages cannot include text; send remaining text separately if present
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
152
|
+
// Voice messages cannot include text; send remaining text separately if present.
|
|
153
|
+
await sendDiscordChunkWithFallback({
|
|
154
|
+
target: params.target,
|
|
155
|
+
text,
|
|
156
|
+
token: params.token,
|
|
157
|
+
rest: params.rest,
|
|
158
|
+
accountId: params.accountId,
|
|
159
|
+
replyTo: resolveReplyTo(),
|
|
160
|
+
binding,
|
|
161
|
+
username: persona.username,
|
|
162
|
+
avatarUrl: persona.avatarUrl,
|
|
163
|
+
});
|
|
164
|
+
// Additional media items are sent as regular attachments (voice is single-file only).
|
|
61
165
|
for (const extra of mediaList.slice(1)) {
|
|
166
|
+
const replyTo = resolveReplyTo();
|
|
62
167
|
await sendMessageDiscord(params.target, "", {
|
|
63
168
|
token: params.token,
|
|
64
169
|
rest: params.rest,
|
|
@@ -69,6 +174,7 @@ export async function deliverDiscordReply(params) {
|
|
|
69
174
|
}
|
|
70
175
|
continue;
|
|
71
176
|
}
|
|
177
|
+
const replyTo = resolveReplyTo();
|
|
72
178
|
await sendMessageDiscord(params.target, text, {
|
|
73
179
|
token: params.token,
|
|
74
180
|
rest: params.rest,
|
|
@@ -77,6 +183,7 @@ export async function deliverDiscordReply(params) {
|
|
|
77
183
|
replyTo,
|
|
78
184
|
});
|
|
79
185
|
for (const extra of mediaList.slice(1)) {
|
|
186
|
+
const replyTo = resolveReplyTo();
|
|
80
187
|
await sendMessageDiscord(params.target, "", {
|
|
81
188
|
token: params.token,
|
|
82
189
|
rest: params.rest,
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { ChannelType, Routes } from "discord-api-types/v10";
|
|
2
|
+
import { logVerbose } from "../../globals.js";
|
|
3
|
+
import { createDiscordRestClient } from "../client.js";
|
|
4
|
+
import { sendMessageDiscord, sendWebhookMessageDiscord } from "../send.js";
|
|
5
|
+
import { createThreadDiscord } from "../send.messages.js";
|
|
6
|
+
import { summarizeBindingPersona } from "./thread-bindings.messages.js";
|
|
7
|
+
import { BINDINGS_BY_THREAD_ID, REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL, rememberReusableWebhook, toReusableWebhookKey, } from "./thread-bindings.state.js";
|
|
8
|
+
import { DISCORD_UNKNOWN_CHANNEL_ERROR_CODE, } from "./thread-bindings.types.js";
|
|
9
|
+
function buildThreadTarget(threadId) {
|
|
10
|
+
return `channel:${threadId}`;
|
|
11
|
+
}
|
|
12
|
+
export function isThreadArchived(raw) {
|
|
13
|
+
if (!raw || typeof raw !== "object") {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const asRecord = raw;
|
|
17
|
+
if (asRecord.archived === true) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (asRecord.thread_metadata?.archived === true) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
if (asRecord.threadMetadata?.archived === true) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
function isThreadChannelType(type) {
|
|
29
|
+
return (type === ChannelType.PublicThread ||
|
|
30
|
+
type === ChannelType.PrivateThread ||
|
|
31
|
+
type === ChannelType.AnnouncementThread);
|
|
32
|
+
}
|
|
33
|
+
export function summarizeDiscordError(err) {
|
|
34
|
+
if (err instanceof Error) {
|
|
35
|
+
return err.message;
|
|
36
|
+
}
|
|
37
|
+
if (typeof err === "string") {
|
|
38
|
+
return err;
|
|
39
|
+
}
|
|
40
|
+
if (typeof err === "number" ||
|
|
41
|
+
typeof err === "boolean" ||
|
|
42
|
+
typeof err === "bigint" ||
|
|
43
|
+
typeof err === "symbol") {
|
|
44
|
+
return String(err);
|
|
45
|
+
}
|
|
46
|
+
return "error";
|
|
47
|
+
}
|
|
48
|
+
function extractNumericDiscordErrorValue(value) {
|
|
49
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
50
|
+
return Math.trunc(value);
|
|
51
|
+
}
|
|
52
|
+
if (typeof value === "string" && /^\d+$/.test(value.trim())) {
|
|
53
|
+
return Number(value);
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
function extractDiscordErrorStatus(err) {
|
|
58
|
+
if (!err || typeof err !== "object") {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const candidate = err;
|
|
62
|
+
return (extractNumericDiscordErrorValue(candidate.status) ??
|
|
63
|
+
extractNumericDiscordErrorValue(candidate.statusCode) ??
|
|
64
|
+
extractNumericDiscordErrorValue(candidate.response?.status));
|
|
65
|
+
}
|
|
66
|
+
function extractDiscordErrorCode(err) {
|
|
67
|
+
if (!err || typeof err !== "object") {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
const candidate = err;
|
|
71
|
+
return (extractNumericDiscordErrorValue(candidate.code) ??
|
|
72
|
+
extractNumericDiscordErrorValue(candidate.rawError?.code) ??
|
|
73
|
+
extractNumericDiscordErrorValue(candidate.body?.code) ??
|
|
74
|
+
extractNumericDiscordErrorValue(candidate.response?.body?.code) ??
|
|
75
|
+
extractNumericDiscordErrorValue(candidate.response?.data?.code));
|
|
76
|
+
}
|
|
77
|
+
export function isDiscordThreadGoneError(err) {
|
|
78
|
+
const code = extractDiscordErrorCode(err);
|
|
79
|
+
if (code === DISCORD_UNKNOWN_CHANNEL_ERROR_CODE) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
const status = extractDiscordErrorStatus(err);
|
|
83
|
+
// 404: deleted/unknown channel. 403: bot no longer has access.
|
|
84
|
+
return status === 404 || status === 403;
|
|
85
|
+
}
|
|
86
|
+
export async function maybeSendBindingMessage(params) {
|
|
87
|
+
const text = params.text.trim();
|
|
88
|
+
if (!text) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const record = params.record;
|
|
92
|
+
if (params.preferWebhook !== false && record.webhookId && record.webhookToken) {
|
|
93
|
+
try {
|
|
94
|
+
await sendWebhookMessageDiscord(text, {
|
|
95
|
+
webhookId: record.webhookId,
|
|
96
|
+
webhookToken: record.webhookToken,
|
|
97
|
+
accountId: record.accountId,
|
|
98
|
+
threadId: record.threadId,
|
|
99
|
+
username: summarizeBindingPersona(record),
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
logVerbose(`discord thread binding webhook send failed: ${summarizeDiscordError(err)}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
await sendMessageDiscord(buildThreadTarget(record.threadId), text, {
|
|
109
|
+
accountId: record.accountId,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
logVerbose(`discord thread binding fallback send failed: ${summarizeDiscordError(err)}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export async function createWebhookForChannel(params) {
|
|
117
|
+
try {
|
|
118
|
+
const rest = createDiscordRestClient({
|
|
119
|
+
accountId: params.accountId,
|
|
120
|
+
token: params.token,
|
|
121
|
+
}).rest;
|
|
122
|
+
const created = (await rest.post(Routes.channelWebhooks(params.channelId), {
|
|
123
|
+
body: {
|
|
124
|
+
name: "Pool Bot Agents",
|
|
125
|
+
},
|
|
126
|
+
}));
|
|
127
|
+
const webhookId = typeof created?.id === "string" ? created.id.trim() : "";
|
|
128
|
+
const webhookToken = typeof created?.token === "string" ? created.token.trim() : "";
|
|
129
|
+
if (!webhookId || !webhookToken) {
|
|
130
|
+
return {};
|
|
131
|
+
}
|
|
132
|
+
return { webhookId, webhookToken };
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
logVerbose(`discord thread binding webhook create failed for ${params.channelId}: ${summarizeDiscordError(err)}`);
|
|
136
|
+
return {};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export function findReusableWebhook(params) {
|
|
140
|
+
const reusableKey = toReusableWebhookKey({
|
|
141
|
+
accountId: params.accountId,
|
|
142
|
+
channelId: params.channelId,
|
|
143
|
+
});
|
|
144
|
+
const cached = REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.get(reusableKey);
|
|
145
|
+
if (cached) {
|
|
146
|
+
return {
|
|
147
|
+
webhookId: cached.webhookId,
|
|
148
|
+
webhookToken: cached.webhookToken,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
for (const record of BINDINGS_BY_THREAD_ID.values()) {
|
|
152
|
+
if (record.accountId !== params.accountId) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (record.channelId !== params.channelId) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (!record.webhookId || !record.webhookToken) {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
rememberReusableWebhook(record);
|
|
162
|
+
return {
|
|
163
|
+
webhookId: record.webhookId,
|
|
164
|
+
webhookToken: record.webhookToken,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return {};
|
|
168
|
+
}
|
|
169
|
+
export async function resolveChannelIdForBinding(params) {
|
|
170
|
+
const explicit = params.channelId?.trim();
|
|
171
|
+
if (explicit) {
|
|
172
|
+
return explicit;
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
const rest = createDiscordRestClient({
|
|
176
|
+
accountId: params.accountId,
|
|
177
|
+
token: params.token,
|
|
178
|
+
}).rest;
|
|
179
|
+
const channel = (await rest.get(Routes.channel(params.threadId)));
|
|
180
|
+
const channelId = typeof channel?.id === "string" ? channel.id.trim() : "";
|
|
181
|
+
const type = channel?.type;
|
|
182
|
+
const parentId = typeof channel?.parent_id === "string"
|
|
183
|
+
? channel.parent_id.trim()
|
|
184
|
+
: typeof channel?.parentId === "string"
|
|
185
|
+
? channel.parentId.trim()
|
|
186
|
+
: "";
|
|
187
|
+
// Only thread channels should resolve to their parent channel.
|
|
188
|
+
// Non-thread channels (text/forum/media) must keep their own ID.
|
|
189
|
+
if (parentId && isThreadChannelType(type)) {
|
|
190
|
+
return parentId;
|
|
191
|
+
}
|
|
192
|
+
return channelId || null;
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
logVerbose(`discord thread binding channel resolve failed for ${params.threadId}: ${summarizeDiscordError(err)}`);
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
export async function createThreadForBinding(params) {
|
|
200
|
+
try {
|
|
201
|
+
const created = (await createThreadDiscord(params.channelId, {
|
|
202
|
+
name: params.threadName,
|
|
203
|
+
autoArchiveMinutes: 60,
|
|
204
|
+
}, {
|
|
205
|
+
accountId: params.accountId,
|
|
206
|
+
token: params.token,
|
|
207
|
+
}));
|
|
208
|
+
const createdId = typeof created?.id === "string" ? created.id.trim() : "";
|
|
209
|
+
return createdId || null;
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
logVerbose(`discord thread binding auto-thread create failed for ${params.channelId}: ${summarizeDiscordError(err)}`);
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { formatThreadBindingTtlLabel, resolveThreadBindingIntroText, resolveThreadBindingThreadName, } from "./thread-bindings.messages.js";
|
|
2
|
+
export { isRecentlyUnboundThreadWebhookMessage } from "./thread-bindings.state.js";
|
|
3
|
+
export { autoBindSpawnedDiscordSubagent, listThreadBindingsBySessionKey, listThreadBindingsForAccount, setThreadBindingTtlBySessionKey, unbindThreadBindingsBySessionKey, } from "./thread-bindings.lifecycle.js";
|
|
4
|
+
export { __testing, createNoopThreadBindingManager, createThreadBindingManager, getThreadBindingManager, } from "./thread-bindings.manager.js";
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { normalizeAccountId } from "../../routing/session-key.js";
|
|
2
|
+
import { parseDiscordTarget } from "../targets.js";
|
|
3
|
+
import { resolveChannelIdForBinding } from "./thread-bindings.discord-api.js";
|
|
4
|
+
import { getThreadBindingManager } from "./thread-bindings.manager.js";
|
|
5
|
+
import { resolveThreadBindingIntroText, resolveThreadBindingThreadName, } from "./thread-bindings.messages.js";
|
|
6
|
+
import { BINDINGS_BY_THREAD_ID, MANAGERS_BY_ACCOUNT_ID, ensureBindingsLoaded, getThreadBindingToken, normalizeThreadBindingTtlMs, normalizeThreadId, rememberRecentUnboundWebhookEcho, removeBindingRecord, resolveBindingIdsForSession, saveBindingsToDisk, setBindingRecord, shouldPersistBindingMutations, } from "./thread-bindings.state.js";
|
|
7
|
+
export function listThreadBindingsForAccount(accountId) {
|
|
8
|
+
const manager = getThreadBindingManager(accountId);
|
|
9
|
+
if (!manager) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
return manager.listBindings();
|
|
13
|
+
}
|
|
14
|
+
export function listThreadBindingsBySessionKey(params) {
|
|
15
|
+
ensureBindingsLoaded();
|
|
16
|
+
const targetSessionKey = params.targetSessionKey.trim();
|
|
17
|
+
if (!targetSessionKey) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
const accountId = params.accountId ? normalizeAccountId(params.accountId) : undefined;
|
|
21
|
+
const ids = resolveBindingIdsForSession({
|
|
22
|
+
targetSessionKey,
|
|
23
|
+
accountId,
|
|
24
|
+
targetKind: params.targetKind,
|
|
25
|
+
});
|
|
26
|
+
return ids
|
|
27
|
+
.map((bindingKey) => BINDINGS_BY_THREAD_ID.get(bindingKey))
|
|
28
|
+
.filter((entry) => Boolean(entry));
|
|
29
|
+
}
|
|
30
|
+
export async function autoBindSpawnedDiscordSubagent(params) {
|
|
31
|
+
const channel = params.channel?.trim().toLowerCase();
|
|
32
|
+
if (channel !== "discord") {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const manager = getThreadBindingManager(params.accountId);
|
|
36
|
+
if (!manager) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const managerToken = getThreadBindingToken(manager.accountId);
|
|
40
|
+
const requesterThreadId = normalizeThreadId(params.threadId);
|
|
41
|
+
let channelId = "";
|
|
42
|
+
if (requesterThreadId) {
|
|
43
|
+
const existing = manager.getByThreadId(requesterThreadId);
|
|
44
|
+
if (existing?.channelId?.trim()) {
|
|
45
|
+
channelId = existing.channelId.trim();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
channelId =
|
|
49
|
+
(await resolveChannelIdForBinding({
|
|
50
|
+
accountId: manager.accountId,
|
|
51
|
+
token: managerToken,
|
|
52
|
+
threadId: requesterThreadId,
|
|
53
|
+
})) ?? "";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (!channelId) {
|
|
57
|
+
const to = params.to?.trim() || "";
|
|
58
|
+
if (!to) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const target = parseDiscordTarget(to, { defaultKind: "channel" });
|
|
63
|
+
if (!target || target.kind !== "channel") {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
channelId =
|
|
67
|
+
(await resolveChannelIdForBinding({
|
|
68
|
+
accountId: manager.accountId,
|
|
69
|
+
token: managerToken,
|
|
70
|
+
threadId: target.id,
|
|
71
|
+
})) ?? "";
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return await manager.bindTarget({
|
|
78
|
+
threadId: undefined,
|
|
79
|
+
channelId,
|
|
80
|
+
createThread: true,
|
|
81
|
+
threadName: resolveThreadBindingThreadName({
|
|
82
|
+
agentId: params.agentId,
|
|
83
|
+
label: params.label,
|
|
84
|
+
}),
|
|
85
|
+
targetKind: "subagent",
|
|
86
|
+
targetSessionKey: params.childSessionKey,
|
|
87
|
+
agentId: params.agentId,
|
|
88
|
+
label: params.label,
|
|
89
|
+
boundBy: params.boundBy ?? "system",
|
|
90
|
+
introText: resolveThreadBindingIntroText({
|
|
91
|
+
agentId: params.agentId,
|
|
92
|
+
label: params.label,
|
|
93
|
+
sessionTtlMs: manager.getSessionTtlMs(),
|
|
94
|
+
}),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
export function unbindThreadBindingsBySessionKey(params) {
|
|
98
|
+
ensureBindingsLoaded();
|
|
99
|
+
const targetSessionKey = params.targetSessionKey.trim();
|
|
100
|
+
if (!targetSessionKey) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
const accountId = params.accountId ? normalizeAccountId(params.accountId) : undefined;
|
|
104
|
+
const ids = resolveBindingIdsForSession({
|
|
105
|
+
targetSessionKey,
|
|
106
|
+
accountId,
|
|
107
|
+
targetKind: params.targetKind,
|
|
108
|
+
});
|
|
109
|
+
if (ids.length === 0) {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
const removed = [];
|
|
113
|
+
for (const bindingKey of ids) {
|
|
114
|
+
const record = BINDINGS_BY_THREAD_ID.get(bindingKey);
|
|
115
|
+
if (!record) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const manager = MANAGERS_BY_ACCOUNT_ID.get(record.accountId);
|
|
119
|
+
if (manager) {
|
|
120
|
+
const unbound = manager.unbindThread({
|
|
121
|
+
threadId: record.threadId,
|
|
122
|
+
reason: params.reason,
|
|
123
|
+
sendFarewell: params.sendFarewell,
|
|
124
|
+
farewellText: params.farewellText,
|
|
125
|
+
});
|
|
126
|
+
if (unbound) {
|
|
127
|
+
removed.push(unbound);
|
|
128
|
+
}
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const unbound = removeBindingRecord(bindingKey);
|
|
132
|
+
if (unbound) {
|
|
133
|
+
rememberRecentUnboundWebhookEcho(unbound);
|
|
134
|
+
removed.push(unbound);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (removed.length > 0 && shouldPersistBindingMutations()) {
|
|
138
|
+
saveBindingsToDisk({ force: true });
|
|
139
|
+
}
|
|
140
|
+
return removed;
|
|
141
|
+
}
|
|
142
|
+
export function setThreadBindingTtlBySessionKey(params) {
|
|
143
|
+
ensureBindingsLoaded();
|
|
144
|
+
const targetSessionKey = params.targetSessionKey.trim();
|
|
145
|
+
if (!targetSessionKey) {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
const accountId = params.accountId ? normalizeAccountId(params.accountId) : undefined;
|
|
149
|
+
const ids = resolveBindingIdsForSession({
|
|
150
|
+
targetSessionKey,
|
|
151
|
+
accountId,
|
|
152
|
+
});
|
|
153
|
+
if (ids.length === 0) {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
const ttlMs = normalizeThreadBindingTtlMs(params.ttlMs);
|
|
157
|
+
const now = Date.now();
|
|
158
|
+
const expiresAt = ttlMs > 0 ? now + ttlMs : 0;
|
|
159
|
+
const updated = [];
|
|
160
|
+
for (const bindingKey of ids) {
|
|
161
|
+
const existing = BINDINGS_BY_THREAD_ID.get(bindingKey);
|
|
162
|
+
if (!existing) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const nextRecord = {
|
|
166
|
+
...existing,
|
|
167
|
+
boundAt: now,
|
|
168
|
+
expiresAt,
|
|
169
|
+
};
|
|
170
|
+
setBindingRecord(nextRecord);
|
|
171
|
+
updated.push(nextRecord);
|
|
172
|
+
}
|
|
173
|
+
if (updated.length > 0 && shouldPersistBindingMutations()) {
|
|
174
|
+
saveBindingsToDisk({ force: true });
|
|
175
|
+
}
|
|
176
|
+
return updated;
|
|
177
|
+
}
|