@poolzin/pool-bot 2026.2.21 → 2026.2.22
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/api-key-rotation.js +47 -0
- package/dist/agents/apply-patch-update.js +19 -9
- package/dist/agents/apply-patch.js +72 -47
- package/dist/agents/bash-tools.exec.js +141 -559
- package/dist/agents/cli-backends.js +49 -6
- package/dist/agents/cli-runner/helpers.js +69 -152
- package/dist/agents/cli-runner.js +70 -19
- package/dist/agents/identity.js +20 -1
- package/dist/agents/image-sanitization.js +9 -0
- package/dist/agents/live-auth-keys.js +123 -26
- package/dist/agents/live-model-filter.js +13 -4
- package/dist/agents/model-catalog.js +40 -9
- package/dist/agents/model-forward-compat.js +60 -23
- package/dist/agents/model-selection.js +134 -41
- package/dist/agents/pi-auth-json.js +2 -2
- package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
- package/dist/agents/pi-embedded-helpers/errors.js +140 -15
- package/dist/agents/pi-embedded-helpers/images.js +22 -12
- package/dist/agents/pi-embedded-helpers.js +2 -2
- package/dist/agents/pi-embedded-runner/abort.js +10 -3
- package/dist/agents/pi-embedded-runner/compact.js +230 -32
- package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
- package/dist/agents/pi-embedded-runner/google.js +109 -19
- package/dist/agents/pi-embedded-runner/history.js +35 -17
- package/dist/agents/pi-embedded-runner/run/attempt.js +386 -95
- package/dist/agents/pi-embedded-runner/run/images.js +81 -55
- package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
- package/dist/agents/pi-embedded-runner/run.js +193 -25
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
- package/dist/agents/pi-embedded-runner/runs.js +17 -8
- package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
- package/dist/agents/pi-embedded-runner.js +1 -1
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
- package/dist/agents/pi-embedded-subscribe.js +37 -0
- package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
- package/dist/agents/pi-model-discovery.js +9 -2
- package/dist/agents/pi-tool-definition-adapter.js +60 -8
- package/dist/agents/pi-tools.before-tool-call.js +1 -1
- package/dist/agents/pi-tools.js +113 -94
- package/dist/agents/pi-tools.read.js +337 -38
- package/dist/agents/poolbot-tools.js +14 -5
- package/dist/agents/sandbox/docker.js +10 -5
- package/dist/agents/sandbox/registry.js +96 -46
- package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
- package/dist/agents/sandbox-paths.js +43 -10
- package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
- package/dist/agents/session-tool-result-guard.js +39 -39
- package/dist/agents/session-transcript-repair.js +36 -33
- package/dist/agents/session-write-lock.js +62 -44
- package/dist/agents/skills/frontmatter.js +49 -88
- package/dist/agents/skills/workspace.js +335 -28
- package/dist/agents/subagent-announce.js +508 -174
- package/dist/agents/subagent-registry.js +45 -4
- package/dist/agents/subagent-spawn.js +16 -33
- package/dist/agents/system-prompt-report.js +27 -10
- package/dist/agents/system-prompt.js +26 -32
- package/dist/agents/tool-call-id.js +69 -17
- package/dist/agents/tool-display-common.js +1 -1
- package/dist/agents/tool-images.js +64 -31
- package/dist/agents/tools/canvas-tool.js +17 -11
- package/dist/agents/tools/common.js +37 -19
- package/dist/agents/tools/cron-tool.js +40 -38
- package/dist/agents/tools/gateway.js +70 -2
- package/dist/agents/tools/message-tool.js +181 -40
- package/dist/agents/tools/nodes-tool.js +128 -36
- package/dist/agents/tools/nodes-utils.js +12 -38
- package/dist/agents/tools/session-status-tool.js +24 -71
- package/dist/agents/tools/sessions-helpers.js +38 -210
- package/dist/agents/tools/sessions-spawn-tool.js +28 -198
- package/dist/agents/tools/telegram-actions.js +58 -7
- package/dist/agents/tools/web-fetch-utils.js +112 -7
- package/dist/agents/tools/web-fetch.js +279 -175
- package/dist/agents/tools/web-shared.js +71 -8
- package/dist/agents/usage.js +25 -16
- package/dist/auto-reply/commands-registry.data.js +85 -11
- package/dist/auto-reply/dispatch.js +40 -21
- package/dist/auto-reply/reply/abort.js +102 -33
- package/dist/auto-reply/reply/commands-core.js +82 -33
- package/dist/auto-reply/reply/commands-export-session.js +1 -1
- package/dist/auto-reply/reply/commands-info.js +41 -12
- package/dist/auto-reply/reply/commands-subagents.js +352 -100
- package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
- package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
- package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
- package/dist/auto-reply/reply/inbound-meta.js +12 -1
- package/dist/auto-reply/reply/mentions.js +18 -11
- package/dist/auto-reply/reply/normalize-reply.js +17 -8
- package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
- package/dist/auto-reply/reply/session.js +102 -21
- package/dist/auto-reply/reply/streaming-directives.js +16 -5
- package/dist/auto-reply/status.js +73 -50
- package/dist/browser/extension-relay.js +3 -3
- package/dist/browser/http-auth.js +1 -1
- package/dist/browser/paths.js +2 -2
- package/dist/build-info.json +3 -3
- package/dist/channels/allowlist-match.js +20 -0
- package/dist/channels/allowlists/resolve-utils.js +65 -2
- package/dist/channels/chat-type.js +8 -4
- package/dist/channels/dock.js +127 -35
- package/dist/channels/draft-stream-loop.js +6 -2
- package/dist/channels/plugins/actions/telegram.js +42 -18
- package/dist/channels/plugins/allowlist-match.js +1 -1
- package/dist/channels/plugins/group-mentions.js +51 -41
- package/dist/channels/plugins/message-action-names.js +2 -0
- package/dist/channels/plugins/message-actions.js +24 -5
- package/dist/channels/plugins/normalize/discord.js +26 -4
- package/dist/channels/plugins/normalize/signal.js +35 -22
- package/dist/channels/plugins/onboarding/helpers.js +8 -26
- package/dist/channels/plugins/outbound/imessage.js +15 -14
- package/dist/channels/registry.js +20 -7
- package/dist/cli/acp-cli.js +7 -5
- package/dist/cli/browser-cli-extension.js +25 -12
- package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
- package/dist/cli/browser-cli-state.js +101 -145
- package/dist/cli/command-options.js +28 -0
- package/dist/cli/completion-cli.js +6 -6
- package/dist/cli/cron-cli/register.cron-add.js +25 -1
- package/dist/cli/cron-cli/register.cron-edit.js +44 -0
- package/dist/cli/cron-cli/shared.js +7 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
- package/dist/cli/daemon-cli/lifecycle.js +23 -247
- package/dist/cli/daemon-cli/register-service-commands.js +25 -4
- package/dist/cli/daemon-cli.js +1 -0
- package/dist/cli/devices-cli.js +33 -20
- package/dist/cli/gateway-cli/register.js +37 -105
- package/dist/cli/gateway-cli/run.js +49 -11
- package/dist/cli/nodes-camera.js +59 -4
- package/dist/cli/nodes-cli/register.camera.js +27 -24
- package/dist/cli/nodes-cli/rpc.js +21 -38
- package/dist/cli/qr-cli.js +2 -2
- package/dist/cli/skills-cli.format.js +2 -2
- package/dist/cli/update-cli/progress.js +2 -2
- package/dist/cli/update-cli/restart-helper.js +28 -7
- package/dist/cli/update-cli/shared.js +7 -7
- package/dist/cli/update-cli/status.js +1 -1
- package/dist/cli/update-cli/update-command.js +14 -8
- package/dist/cli/update-cli/wizard.js +2 -2
- package/dist/cli/update-cli.js +21 -1027
- package/dist/commands/auth-choice.apply.anthropic.js +10 -2
- package/dist/commands/channels/add-mutators.js +3 -35
- package/dist/commands/channels/add.js +39 -51
- package/dist/commands/config-validation.js +1 -1
- package/dist/commands/configure.gateway-auth.js +52 -15
- package/dist/commands/configure.gateway.js +84 -40
- package/dist/commands/doctor-completion.js +3 -3
- package/dist/commands/doctor-config-flow.js +536 -16
- package/dist/commands/doctor-gateway-services.js +103 -79
- package/dist/commands/doctor-memory-search.js +9 -9
- package/dist/commands/doctor-platform-notes.js +57 -30
- package/dist/commands/doctor-prompter.js +26 -15
- package/dist/commands/doctor-session-locks.js +1 -1
- package/dist/commands/doctor.js +21 -9
- package/dist/commands/model-picker.js +120 -95
- package/dist/commands/models/set.js +2 -21
- package/dist/commands/models/shared.js +65 -37
- package/dist/commands/onboard-helpers.js +81 -39
- package/dist/commands/openai-codex-oauth.js +1 -1
- package/dist/commands/sessions.js +52 -53
- package/dist/commands/status.summary.js +52 -34
- package/dist/commands/test-wizard-helpers.js +2 -2
- package/dist/config/defaults.js +79 -42
- package/dist/config/group-policy.js +50 -18
- package/dist/config/includes.js +37 -10
- package/dist/config/schema.help.js +5 -4
- package/dist/config/schema.hints.js +2 -2
- package/dist/config/schema.labels.js +1 -0
- package/dist/config/sessions/group.js +12 -11
- package/dist/config/sessions/paths.js +137 -11
- package/dist/config/sessions/store.js +185 -65
- package/dist/config/sessions/types.js +15 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/telegram-custom-commands.js +3 -2
- package/dist/config/types.js +2 -0
- package/dist/config/zod-schema.agent-defaults.js +6 -27
- package/dist/config/zod-schema.agent-runtime.js +171 -79
- package/dist/config/zod-schema.providers-core.js +138 -65
- package/dist/config/zod-schema.session.js +49 -22
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
- package/dist/cron/isolated-agent/run.js +224 -57
- package/dist/cron/normalize.js +48 -45
- package/dist/cron/run-log.js +14 -0
- package/dist/cron/service/jobs.js +190 -28
- package/dist/cron/service/normalize.js +29 -11
- package/dist/cron/service/store.js +30 -44
- package/dist/cron/service/timer.js +182 -96
- package/dist/cron/service.js +3 -0
- package/dist/cron/stagger.js +37 -0
- package/dist/daemon/inspect.js +132 -92
- package/dist/daemon/runtime-paths.js +25 -4
- package/dist/daemon/service-audit.js +47 -16
- package/dist/discord/accounts.js +23 -20
- package/dist/discord/monitor/agent-components.js +1115 -219
- package/dist/discord/monitor/allow-list.js +114 -34
- package/dist/discord/monitor/listeners.js +204 -97
- package/dist/discord/monitor/message-handler.js +21 -10
- package/dist/discord/monitor/message-handler.preflight.js +195 -101
- package/dist/discord/monitor/message-handler.process.js +384 -123
- package/dist/discord/monitor/message-utils.js +86 -23
- package/dist/discord/monitor/native-command.js +77 -57
- package/dist/discord/monitor/provider.js +122 -117
- package/dist/discord/monitor/reply-context.js +20 -16
- package/dist/discord/monitor/reply-delivery.js +40 -8
- package/dist/discord/monitor/rest-fetch.js +22 -0
- package/dist/discord/monitor/threading.js +117 -24
- package/dist/discord/send.js +2 -1
- package/dist/discord/send.outbound.js +124 -11
- package/dist/discord/send.shared.js +112 -72
- package/dist/discord/voice-message.js +3 -3
- package/dist/gateway/auth.js +119 -44
- package/dist/gateway/call.js +76 -34
- package/dist/gateway/channel-health-monitor.js +57 -50
- package/dist/gateway/client.js +63 -29
- package/dist/gateway/control-ui-contract.js +1 -1
- package/dist/gateway/gateway-config-prompts.shared.js +2 -2
- package/dist/gateway/net.js +109 -1
- package/dist/gateway/protocol/index.js +5 -8
- package/dist/gateway/protocol/schema/agent.js +19 -1
- package/dist/gateway/protocol/schema/channels.js +21 -0
- package/dist/gateway/protocol/schema/cron.js +43 -30
- package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
- package/dist/gateway/protocol/schema/sessions.js +5 -1
- package/dist/gateway/protocol/schema.js +0 -1
- package/dist/gateway/server/presence-events.js +12 -0
- package/dist/gateway/server/ws-connection/message-handler.js +203 -212
- package/dist/gateway/server/ws-connection.js +58 -21
- package/dist/gateway/server-broadcast.js +18 -13
- package/dist/gateway/server-cron.js +177 -10
- package/dist/gateway/server-methods/agent-job.js +131 -38
- package/dist/gateway/server-methods/send.js +60 -14
- package/dist/gateway/server-methods/sessions.js +160 -96
- package/dist/gateway/server-methods/system.js +5 -7
- package/dist/gateway/server-methods-list.js +8 -0
- package/dist/gateway/server-methods.js +24 -8
- package/dist/gateway/server-node-events.js +278 -68
- package/dist/gateway/session-utils.fs.js +316 -75
- package/dist/gateway/session-utils.js +224 -70
- package/dist/gateway/sessions-patch.js +63 -20
- package/dist/gateway/test-temp-config.js +1 -1
- package/dist/gateway/tools-invoke-http.js +118 -70
- package/dist/gateway/ws-log.js +135 -107
- package/dist/hooks/frontmatter.js +36 -82
- package/dist/hooks/install.js +149 -139
- package/dist/hooks/internal-hooks.js +29 -4
- package/dist/hooks/plugin-hooks.js +2 -1
- package/dist/imessage/monitor/deliver.js +10 -4
- package/dist/imessage/monitor/monitor-provider.js +138 -375
- package/dist/imessage/monitor/runtime.js +4 -8
- package/dist/imessage/send.js +65 -19
- package/dist/infra/exec-approvals-allowlist.js +7 -0
- package/dist/infra/exec-approvals.js +35 -920
- package/dist/infra/exec-safe-bin-trust.js +64 -0
- package/dist/infra/heartbeat-runner.js +207 -134
- package/dist/infra/heartbeat-wake.js +183 -22
- package/dist/infra/install-source-utils.js +47 -0
- package/dist/infra/net/ssrf.js +170 -36
- package/dist/infra/outbound/deliver.js +224 -58
- package/dist/infra/outbound/message-action-spec.js +12 -5
- package/dist/infra/outbound/outbound-session.js +27 -25
- package/dist/infra/poolbot-root.js +32 -22
- package/dist/infra/ports.js +14 -11
- package/dist/infra/skills-remote.js +48 -37
- package/dist/infra/system-events.js +25 -11
- package/dist/infra/system-presence.js +26 -33
- package/dist/infra/tmp-poolbot-dir.js +81 -2
- package/dist/infra/wsl.js +37 -1
- package/dist/line/bot-message-context.js +163 -191
- package/dist/logging/subsystem.js +59 -22
- package/dist/markdown/ir.js +124 -50
- package/dist/media/store.js +1 -1
- package/dist/media-understanding/runner.entries.js +42 -25
- package/dist/media-understanding/runner.js +53 -488
- package/dist/memory/embeddings-gemini.js +53 -38
- package/dist/memory/manager-embedding-ops.js +48 -69
- package/dist/pairing/pairing-store.js +178 -119
- package/dist/plugin-sdk/index.js +34 -6
- package/dist/plugins/hooks.js +135 -14
- package/dist/plugins/install.js +190 -152
- package/dist/polls.js +11 -0
- package/dist/routing/resolve-route.js +190 -56
- package/dist/routing/session-key.js +38 -22
- package/dist/runtime.js +35 -9
- package/dist/security/audit-channel.js +1 -1
- package/dist/sessions/session-key-utils.js +29 -11
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-types.js +1 -0
- package/dist/shared/string-normalization.js +15 -0
- package/dist/signal/monitor/event-handler.js +68 -36
- package/dist/signal/send.js +29 -37
- package/dist/slack/monitor/allow-list.js +10 -11
- package/dist/slack/monitor/commands.js +14 -3
- package/dist/slack/monitor/events/interactions.js +4 -4
- package/dist/slack/monitor/media.js +224 -16
- package/dist/slack/monitor/message-handler/dispatch.js +247 -13
- package/dist/slack/monitor/message-handler/prepare.js +128 -45
- package/dist/slack/monitor/slash.js +357 -144
- package/dist/slack/streaming.js +77 -0
- package/dist/telegram/accounts.js +40 -13
- package/dist/telegram/allowed-updates.js +3 -0
- package/dist/telegram/bot/delivery.js +129 -66
- package/dist/telegram/bot/helpers.js +136 -122
- package/dist/telegram/bot-handlers.js +600 -339
- package/dist/telegram/bot-message-context.js +115 -73
- package/dist/telegram/bot-message-dispatch.js +235 -104
- package/dist/telegram/bot-native-command-menu.js +3 -1
- package/dist/telegram/bot-native-commands.js +213 -193
- package/dist/telegram/bot.js +24 -132
- package/dist/telegram/draft-stream.js +84 -75
- package/dist/telegram/format.js +150 -6
- package/dist/telegram/send.js +415 -255
- package/dist/telegram/targets.js +21 -2
- package/dist/telegram/update-offset-store.js +19 -3
- package/dist/terminal/restore.js +5 -2
- package/dist/test-utils/fetch-mock.js +5 -0
- package/dist/version.js +18 -5
- package/dist/web/auto-reply/monitor/broadcast.js +7 -3
- package/dist/web/auto-reply/monitor/on-message.js +6 -3
- package/dist/web/inbound/media.js +34 -8
- package/dist/web/inbound/monitor.js +34 -17
- package/dist/web/inbound/send-api.js +18 -17
- package/dist/web/outbound.js +12 -5
- package/dist/wizard/clack-prompter.js +40 -7
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +5 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +5 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +5 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/openai-codex-auth/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +5 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +5 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +5 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +5 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
- package/skills/apple-reminders/SKILL.md +100 -49
- package/skills/coding-agent/SKILL.md +34 -28
- package/skills/github/SKILL.md +131 -16
- package/skills/imsg/SKILL.md +112 -15
- package/skills/openhue/SKILL.md +101 -19
- package/skills/tmux/SKILL.md +111 -79
- package/skills/weather/SKILL.md +88 -25
|
@@ -1,39 +1,256 @@
|
|
|
1
1
|
import { ChannelType } from "@buape/carbon";
|
|
2
2
|
import { resolveAckReaction, resolveHumanDelayConfig } from "../../agents/identity.js";
|
|
3
|
-
import {
|
|
4
|
-
import { logTypingFailure, logAckFailure } from "../../channels/logging.js";
|
|
5
|
-
import { createReplyPrefixContext } from "../../channels/reply-prefix.js";
|
|
6
|
-
import { createTypingCallbacks } from "../../channels/typing.js";
|
|
7
|
-
import { formatInboundEnvelope, formatThreadStarterEnvelope, resolveEnvelopeFormatOptions, } from "../../auto-reply/envelope.js";
|
|
3
|
+
import { resolveChunkMode } from "../../auto-reply/chunk.js";
|
|
8
4
|
import { dispatchInboundMessage } from "../../auto-reply/dispatch.js";
|
|
5
|
+
import { formatInboundEnvelope, resolveEnvelopeFormatOptions } from "../../auto-reply/envelope.js";
|
|
9
6
|
import { buildPendingHistoryContextFromMap, clearHistoryEntriesIfEnabled, } from "../../auto-reply/reply/history.js";
|
|
10
7
|
import { finalizeInboundContext } from "../../auto-reply/reply/inbound-context.js";
|
|
11
8
|
import { createReplyDispatcherWithTyping } from "../../auto-reply/reply/reply-dispatcher.js";
|
|
9
|
+
import { shouldAckReaction as shouldAckReactionGate } from "../../channels/ack-reactions.js";
|
|
10
|
+
import { logTypingFailure, logAckFailure } from "../../channels/logging.js";
|
|
11
|
+
import { createReplyPrefixOptions } from "../../channels/reply-prefix.js";
|
|
12
12
|
import { recordInboundSession } from "../../channels/session.js";
|
|
13
|
-
import {
|
|
14
|
-
import { resolveChunkMode } from "../../auto-reply/chunk.js";
|
|
13
|
+
import { createTypingCallbacks } from "../../channels/typing.js";
|
|
15
14
|
import { resolveMarkdownTableMode } from "../../config/markdown-tables.js";
|
|
15
|
+
import { readSessionUpdatedAt, resolveStorePath } from "../../config/sessions.js";
|
|
16
16
|
import { danger, logVerbose, shouldLogVerbose } from "../../globals.js";
|
|
17
17
|
import { buildAgentSessionKey } from "../../routing/resolve-route.js";
|
|
18
18
|
import { resolveThreadSessionKeys } from "../../routing/session-key.js";
|
|
19
|
+
import { buildUntrustedChannelMetadata } from "../../security/channel-metadata.js";
|
|
19
20
|
import { truncateUtf16Safe } from "../../utils.js";
|
|
20
21
|
import { reactMessageDiscord, removeReactionDiscord } from "../send.js";
|
|
21
|
-
import { normalizeDiscordSlug } from "./allow-list.js";
|
|
22
|
-
import {
|
|
23
|
-
import { buildDiscordMediaPayload, resolveDiscordMessageText, resolveMediaList, } from "./message-utils.js";
|
|
22
|
+
import { normalizeDiscordSlug, resolveDiscordOwnerAllowFrom } from "./allow-list.js";
|
|
23
|
+
import { resolveTimestampMs } from "./format.js";
|
|
24
|
+
import { buildDiscordMediaPayload, resolveDiscordMessageText, resolveForwardedMediaList, resolveMediaList, } from "./message-utils.js";
|
|
24
25
|
import { buildDirectLabel, buildGuildLabel, resolveReplyContext } from "./reply-context.js";
|
|
25
26
|
import { deliverDiscordReply } from "./reply-delivery.js";
|
|
26
27
|
import { resolveDiscordAutoThreadReplyPlan, resolveDiscordThreadStarter } from "./threading.js";
|
|
27
28
|
import { sendTyping } from "./typing.js";
|
|
29
|
+
const DISCORD_STATUS_THINKING_EMOJI = "🧠";
|
|
30
|
+
const DISCORD_STATUS_TOOL_EMOJI = "🛠️";
|
|
31
|
+
const DISCORD_STATUS_CODING_EMOJI = "💻";
|
|
32
|
+
const DISCORD_STATUS_WEB_EMOJI = "🌐";
|
|
33
|
+
const DISCORD_STATUS_DONE_EMOJI = "✅";
|
|
34
|
+
const DISCORD_STATUS_ERROR_EMOJI = "❌";
|
|
35
|
+
const DISCORD_STATUS_STALL_SOFT_EMOJI = "⏳";
|
|
36
|
+
const DISCORD_STATUS_STALL_HARD_EMOJI = "⚠️";
|
|
37
|
+
const DISCORD_STATUS_DONE_HOLD_MS = 1500;
|
|
38
|
+
const DISCORD_STATUS_ERROR_HOLD_MS = 2500;
|
|
39
|
+
const DISCORD_STATUS_DEBOUNCE_MS = 700;
|
|
40
|
+
const DISCORD_STATUS_STALL_SOFT_MS = 10_000;
|
|
41
|
+
const DISCORD_STATUS_STALL_HARD_MS = 30_000;
|
|
42
|
+
const CODING_STATUS_TOOL_TOKENS = [
|
|
43
|
+
"exec",
|
|
44
|
+
"process",
|
|
45
|
+
"read",
|
|
46
|
+
"write",
|
|
47
|
+
"edit",
|
|
48
|
+
"session_status",
|
|
49
|
+
"bash",
|
|
50
|
+
];
|
|
51
|
+
const WEB_STATUS_TOOL_TOKENS = ["web_search", "web-search", "web_fetch", "web-fetch", "browser"];
|
|
52
|
+
function resolveToolStatusEmoji(toolName) {
|
|
53
|
+
const normalized = toolName?.trim().toLowerCase() ?? "";
|
|
54
|
+
if (!normalized) {
|
|
55
|
+
return DISCORD_STATUS_TOOL_EMOJI;
|
|
56
|
+
}
|
|
57
|
+
if (WEB_STATUS_TOOL_TOKENS.some((token) => normalized.includes(token))) {
|
|
58
|
+
return DISCORD_STATUS_WEB_EMOJI;
|
|
59
|
+
}
|
|
60
|
+
if (CODING_STATUS_TOOL_TOKENS.some((token) => normalized.includes(token))) {
|
|
61
|
+
return DISCORD_STATUS_CODING_EMOJI;
|
|
62
|
+
}
|
|
63
|
+
return DISCORD_STATUS_TOOL_EMOJI;
|
|
64
|
+
}
|
|
65
|
+
function sleep(ms) {
|
|
66
|
+
return new Promise((resolve) => {
|
|
67
|
+
setTimeout(resolve, ms);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function createDiscordStatusReactionController(params) {
|
|
71
|
+
let activeEmoji = null;
|
|
72
|
+
let chain = Promise.resolve();
|
|
73
|
+
let pendingEmoji = null;
|
|
74
|
+
let pendingTimer = null;
|
|
75
|
+
let finished = false;
|
|
76
|
+
let softStallTimer = null;
|
|
77
|
+
let hardStallTimer = null;
|
|
78
|
+
const enqueue = (work) => {
|
|
79
|
+
chain = chain.then(work).catch((err) => {
|
|
80
|
+
logAckFailure({
|
|
81
|
+
log: logVerbose,
|
|
82
|
+
channel: "discord",
|
|
83
|
+
target: `${params.channelId}/${params.messageId}`,
|
|
84
|
+
error: err,
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
return chain;
|
|
88
|
+
};
|
|
89
|
+
const clearStallTimers = () => {
|
|
90
|
+
if (softStallTimer) {
|
|
91
|
+
clearTimeout(softStallTimer);
|
|
92
|
+
softStallTimer = null;
|
|
93
|
+
}
|
|
94
|
+
if (hardStallTimer) {
|
|
95
|
+
clearTimeout(hardStallTimer);
|
|
96
|
+
hardStallTimer = null;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const clearPendingDebounce = () => {
|
|
100
|
+
if (pendingTimer) {
|
|
101
|
+
clearTimeout(pendingTimer);
|
|
102
|
+
pendingTimer = null;
|
|
103
|
+
}
|
|
104
|
+
pendingEmoji = null;
|
|
105
|
+
};
|
|
106
|
+
const applyEmoji = (emoji) => enqueue(async () => {
|
|
107
|
+
if (!params.enabled || !emoji || activeEmoji === emoji) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const previousEmoji = activeEmoji;
|
|
111
|
+
await reactMessageDiscord(params.channelId, params.messageId, emoji, {
|
|
112
|
+
rest: params.rest,
|
|
113
|
+
});
|
|
114
|
+
activeEmoji = emoji;
|
|
115
|
+
if (previousEmoji && previousEmoji !== emoji) {
|
|
116
|
+
await removeReactionDiscord(params.channelId, params.messageId, previousEmoji, {
|
|
117
|
+
rest: params.rest,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
const requestEmoji = (emoji, options) => {
|
|
122
|
+
if (!params.enabled || !emoji) {
|
|
123
|
+
return Promise.resolve();
|
|
124
|
+
}
|
|
125
|
+
if (options?.immediate) {
|
|
126
|
+
clearPendingDebounce();
|
|
127
|
+
return applyEmoji(emoji);
|
|
128
|
+
}
|
|
129
|
+
pendingEmoji = emoji;
|
|
130
|
+
if (pendingTimer) {
|
|
131
|
+
clearTimeout(pendingTimer);
|
|
132
|
+
}
|
|
133
|
+
pendingTimer = setTimeout(() => {
|
|
134
|
+
pendingTimer = null;
|
|
135
|
+
const emojiToApply = pendingEmoji;
|
|
136
|
+
pendingEmoji = null;
|
|
137
|
+
if (!emojiToApply || emojiToApply === activeEmoji) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
void applyEmoji(emojiToApply);
|
|
141
|
+
}, DISCORD_STATUS_DEBOUNCE_MS);
|
|
142
|
+
return Promise.resolve();
|
|
143
|
+
};
|
|
144
|
+
const scheduleStallTimers = () => {
|
|
145
|
+
if (!params.enabled || finished) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
clearStallTimers();
|
|
149
|
+
softStallTimer = setTimeout(() => {
|
|
150
|
+
if (finished) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
void requestEmoji(DISCORD_STATUS_STALL_SOFT_EMOJI, { immediate: true });
|
|
154
|
+
}, DISCORD_STATUS_STALL_SOFT_MS);
|
|
155
|
+
hardStallTimer = setTimeout(() => {
|
|
156
|
+
if (finished) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
void requestEmoji(DISCORD_STATUS_STALL_HARD_EMOJI, { immediate: true });
|
|
160
|
+
}, DISCORD_STATUS_STALL_HARD_MS);
|
|
161
|
+
};
|
|
162
|
+
const setPhase = (emoji) => {
|
|
163
|
+
if (!params.enabled || finished) {
|
|
164
|
+
return Promise.resolve();
|
|
165
|
+
}
|
|
166
|
+
scheduleStallTimers();
|
|
167
|
+
return requestEmoji(emoji);
|
|
168
|
+
};
|
|
169
|
+
const setTerminal = async (emoji) => {
|
|
170
|
+
if (!params.enabled) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
finished = true;
|
|
174
|
+
clearStallTimers();
|
|
175
|
+
await requestEmoji(emoji, { immediate: true });
|
|
176
|
+
};
|
|
177
|
+
const clear = async () => {
|
|
178
|
+
if (!params.enabled) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
finished = true;
|
|
182
|
+
clearStallTimers();
|
|
183
|
+
clearPendingDebounce();
|
|
184
|
+
await enqueue(async () => {
|
|
185
|
+
const cleanupCandidates = new Set([
|
|
186
|
+
params.initialEmoji,
|
|
187
|
+
activeEmoji ?? "",
|
|
188
|
+
DISCORD_STATUS_THINKING_EMOJI,
|
|
189
|
+
DISCORD_STATUS_TOOL_EMOJI,
|
|
190
|
+
DISCORD_STATUS_CODING_EMOJI,
|
|
191
|
+
DISCORD_STATUS_WEB_EMOJI,
|
|
192
|
+
DISCORD_STATUS_DONE_EMOJI,
|
|
193
|
+
DISCORD_STATUS_ERROR_EMOJI,
|
|
194
|
+
DISCORD_STATUS_STALL_SOFT_EMOJI,
|
|
195
|
+
DISCORD_STATUS_STALL_HARD_EMOJI,
|
|
196
|
+
]);
|
|
197
|
+
activeEmoji = null;
|
|
198
|
+
for (const emoji of cleanupCandidates) {
|
|
199
|
+
if (!emoji) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
await removeReactionDiscord(params.channelId, params.messageId, emoji, {
|
|
204
|
+
rest: params.rest,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
logAckFailure({
|
|
209
|
+
log: logVerbose,
|
|
210
|
+
channel: "discord",
|
|
211
|
+
target: `${params.channelId}/${params.messageId}`,
|
|
212
|
+
error: err,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
const restoreInitial = async () => {
|
|
219
|
+
if (!params.enabled) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
finished = true;
|
|
223
|
+
clearStallTimers();
|
|
224
|
+
clearPendingDebounce();
|
|
225
|
+
await requestEmoji(params.initialEmoji, { immediate: true });
|
|
226
|
+
};
|
|
227
|
+
return {
|
|
228
|
+
setQueued: () => {
|
|
229
|
+
scheduleStallTimers();
|
|
230
|
+
return requestEmoji(params.initialEmoji, { immediate: true });
|
|
231
|
+
},
|
|
232
|
+
setThinking: () => setPhase(DISCORD_STATUS_THINKING_EMOJI),
|
|
233
|
+
setTool: (toolName) => setPhase(resolveToolStatusEmoji(toolName)),
|
|
234
|
+
setDone: () => setTerminal(DISCORD_STATUS_DONE_EMOJI),
|
|
235
|
+
setError: () => setTerminal(DISCORD_STATUS_ERROR_EMOJI),
|
|
236
|
+
clear,
|
|
237
|
+
restoreInitial,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
28
240
|
export async function processDiscordMessage(ctx) {
|
|
29
|
-
const { cfg, discordConfig, accountId, token, runtime, guildHistories, historyLimit, mediaMaxBytes, textLimit, replyToMode, ackReactionScope, message, author, data, client, channelInfo, channelName, isGuildMessage, isDirectMessage, isGroupDm, baseText, messageText, shouldRequireMention, canDetectMention, effectiveWasMentioned, shouldBypassMention, threadChannel, threadParentId, threadParentName, threadParentType, threadName, displayChannelSlug, guildInfo, guildSlug, channelConfig, baseSessionKey, route, commandAuthorized, } = ctx;
|
|
241
|
+
const { cfg, discordConfig, accountId, token, runtime, guildHistories, historyLimit, mediaMaxBytes, textLimit, replyToMode, ackReactionScope, message, author, sender, data, client, channelInfo, channelName, messageChannelId, isGuildMessage, isDirectMessage, isGroupDm, baseText, messageText, shouldRequireMention, canDetectMention, effectiveWasMentioned, shouldBypassMention, threadChannel, threadParentId, threadParentName, threadParentType, threadName, displayChannelSlug, guildInfo, guildSlug, channelConfig, baseSessionKey, route, commandAuthorized, } = ctx;
|
|
30
242
|
const mediaList = await resolveMediaList(message, mediaMaxBytes);
|
|
243
|
+
const forwardedMediaList = await resolveForwardedMediaList(message, mediaMaxBytes);
|
|
244
|
+
mediaList.push(...forwardedMediaList);
|
|
31
245
|
const text = messageText;
|
|
32
246
|
if (!text) {
|
|
33
247
|
logVerbose(`discord: drop message ${message.id} (empty content)`);
|
|
34
248
|
return;
|
|
35
249
|
}
|
|
36
|
-
const ackReaction = resolveAckReaction(cfg, route.agentId
|
|
250
|
+
const ackReaction = resolveAckReaction(cfg, route.agentId, {
|
|
251
|
+
channel: "discord",
|
|
252
|
+
accountId,
|
|
253
|
+
});
|
|
37
254
|
const removeAckAfterReply = cfg.messages?.removeAckAfterReply ?? false;
|
|
38
255
|
const shouldAckReaction = () => Boolean(ackReaction &&
|
|
39
256
|
shouldAckReactionGate({
|
|
@@ -46,26 +263,25 @@ export async function processDiscordMessage(ctx) {
|
|
|
46
263
|
effectiveWasMentioned,
|
|
47
264
|
shouldBypassMention,
|
|
48
265
|
}));
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
266
|
+
const statusReactionsEnabled = shouldAckReaction();
|
|
267
|
+
const statusReactions = createDiscordStatusReactionController({
|
|
268
|
+
enabled: statusReactionsEnabled,
|
|
269
|
+
channelId: messageChannelId,
|
|
270
|
+
messageId: message.id,
|
|
271
|
+
initialEmoji: ackReaction,
|
|
272
|
+
rest: client.rest,
|
|
273
|
+
});
|
|
274
|
+
if (statusReactionsEnabled) {
|
|
275
|
+
void statusReactions.setQueued();
|
|
276
|
+
}
|
|
57
277
|
const fromLabel = isDirectMessage
|
|
58
278
|
? buildDirectLabel(author)
|
|
59
279
|
: buildGuildLabel({
|
|
60
280
|
guild: data.guild ?? undefined,
|
|
61
|
-
channelName: channelName ??
|
|
62
|
-
channelId:
|
|
281
|
+
channelName: channelName ?? messageChannelId,
|
|
282
|
+
channelId: messageChannelId,
|
|
63
283
|
});
|
|
64
|
-
const
|
|
65
|
-
const senderDisplay = data.member?.nickname ?? author.globalName ?? author.username;
|
|
66
|
-
const senderLabel = senderDisplay && senderTag && senderDisplay !== senderTag
|
|
67
|
-
? `${senderDisplay} (${senderTag})`
|
|
68
|
-
: (senderDisplay ?? senderTag ?? author.id);
|
|
284
|
+
const senderLabel = sender.label;
|
|
69
285
|
const isForumParent = threadParentType === ChannelType.GuildForum || threadParentType === ChannelType.GuildMedia;
|
|
70
286
|
const forumParentSlug = isForumParent && threadParentName ? normalizeDiscordSlug(threadParentName) : "";
|
|
71
287
|
const threadChannelId = threadChannel?.id;
|
|
@@ -73,12 +289,27 @@ export async function processDiscordMessage(ctx) {
|
|
|
73
289
|
const forumContextLine = isForumStarter ? `[Forum parent: #${forumParentSlug}]` : null;
|
|
74
290
|
const groupChannel = isGuildMessage && displayChannelSlug ? `#${displayChannelSlug}` : undefined;
|
|
75
291
|
const groupSubject = isDirectMessage ? undefined : groupChannel;
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
292
|
+
const untrustedChannelMetadata = isGuildMessage
|
|
293
|
+
? buildUntrustedChannelMetadata({
|
|
294
|
+
source: "discord",
|
|
295
|
+
label: "Discord channel topic",
|
|
296
|
+
entries: [channelInfo?.topic],
|
|
297
|
+
})
|
|
298
|
+
: undefined;
|
|
299
|
+
const senderName = sender.isPluralKit
|
|
300
|
+
? (sender.name ?? author.username)
|
|
301
|
+
: (data.member?.nickname ?? author.globalName ?? author.username);
|
|
302
|
+
const senderUsername = sender.isPluralKit
|
|
303
|
+
? (sender.tag ?? sender.name ?? author.username)
|
|
304
|
+
: author.username;
|
|
305
|
+
const senderTag = sender.tag;
|
|
306
|
+
const systemPromptParts = [channelConfig?.systemPrompt?.trim() || null].filter((entry) => Boolean(entry));
|
|
81
307
|
const groupSystemPrompt = systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : undefined;
|
|
308
|
+
const ownerAllowFrom = resolveDiscordOwnerAllowFrom({
|
|
309
|
+
channelConfig,
|
|
310
|
+
guildInfo,
|
|
311
|
+
sender: { id: sender.id, name: sender.name, tag: sender.tag },
|
|
312
|
+
});
|
|
82
313
|
const storePath = resolveStorePath(cfg.session?.store, {
|
|
83
314
|
agentId: route.agentId,
|
|
84
315
|
});
|
|
@@ -101,26 +332,21 @@ export async function processDiscordMessage(ctx) {
|
|
|
101
332
|
if (shouldIncludeChannelHistory) {
|
|
102
333
|
combinedBody = buildPendingHistoryContextFromMap({
|
|
103
334
|
historyMap: guildHistories,
|
|
104
|
-
historyKey:
|
|
335
|
+
historyKey: messageChannelId,
|
|
105
336
|
limit: historyLimit,
|
|
106
337
|
currentMessage: combinedBody,
|
|
107
338
|
formatEntry: (entry) => formatInboundEnvelope({
|
|
108
339
|
channel: "Discord",
|
|
109
340
|
from: fromLabel,
|
|
110
341
|
timestamp: entry.timestamp,
|
|
111
|
-
body: `${entry.body} [id:${entry.messageId ?? "unknown"} channel:${
|
|
342
|
+
body: `${entry.body} [id:${entry.messageId ?? "unknown"} channel:${messageChannelId}]`,
|
|
112
343
|
chatType: "channel",
|
|
113
344
|
senderLabel: entry.sender,
|
|
114
345
|
envelope: envelopeOptions,
|
|
115
346
|
}),
|
|
116
347
|
});
|
|
117
348
|
}
|
|
118
|
-
const replyContext = resolveReplyContext(message, resolveDiscordMessageText
|
|
119
|
-
envelope: envelopeOptions,
|
|
120
|
-
});
|
|
121
|
-
if (replyContext) {
|
|
122
|
-
combinedBody = `[Replied message - for context]\n${replyContext}\n\n${combinedBody}`;
|
|
123
|
-
}
|
|
349
|
+
const replyContext = resolveReplyContext(message, resolveDiscordMessageText);
|
|
124
350
|
if (forumContextLine) {
|
|
125
351
|
combinedBody = `${combinedBody}\n${forumContextLine}`;
|
|
126
352
|
}
|
|
@@ -128,22 +354,19 @@ export async function processDiscordMessage(ctx) {
|
|
|
128
354
|
let threadLabel;
|
|
129
355
|
let parentSessionKey;
|
|
130
356
|
if (threadChannel) {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const starterEnvelope = formatThreadStarterEnvelope({
|
|
140
|
-
channel: "Discord",
|
|
141
|
-
author: starter.author,
|
|
142
|
-
timestamp: starter.timestamp,
|
|
143
|
-
body: starter.text,
|
|
144
|
-
envelope: envelopeOptions,
|
|
357
|
+
const includeThreadStarter = channelConfig?.includeThreadStarter !== false;
|
|
358
|
+
if (includeThreadStarter) {
|
|
359
|
+
const starter = await resolveDiscordThreadStarter({
|
|
360
|
+
channel: threadChannel,
|
|
361
|
+
client,
|
|
362
|
+
parentId: threadParentId,
|
|
363
|
+
parentType: threadParentType,
|
|
364
|
+
resolveTimestampMs,
|
|
145
365
|
});
|
|
146
|
-
|
|
366
|
+
if (starter?.text) {
|
|
367
|
+
// Keep thread starter as raw text; metadata is provided out-of-band in the system prompt.
|
|
368
|
+
threadStarterBody = starter.text;
|
|
369
|
+
}
|
|
147
370
|
}
|
|
148
371
|
const parentName = threadParentName ?? "parent";
|
|
149
372
|
threadLabel = threadName
|
|
@@ -160,16 +383,18 @@ export async function processDiscordMessage(ctx) {
|
|
|
160
383
|
const mediaPayload = buildDiscordMediaPayload(mediaList);
|
|
161
384
|
const threadKeys = resolveThreadSessionKeys({
|
|
162
385
|
baseSessionKey,
|
|
163
|
-
threadId: threadChannel ?
|
|
386
|
+
threadId: threadChannel ? messageChannelId : undefined,
|
|
164
387
|
parentSessionKey,
|
|
165
388
|
useSuffix: false,
|
|
166
389
|
});
|
|
167
390
|
const replyPlan = await resolveDiscordAutoThreadReplyPlan({
|
|
168
391
|
client,
|
|
169
392
|
message,
|
|
393
|
+
messageChannelId,
|
|
170
394
|
isGuildMessage,
|
|
171
395
|
channelConfig,
|
|
172
396
|
threadChannel,
|
|
397
|
+
channelType: channelInfo?.type,
|
|
173
398
|
baseText: baseText ?? "",
|
|
174
399
|
combinedBody,
|
|
175
400
|
replyToMode,
|
|
@@ -182,14 +407,25 @@ export async function processDiscordMessage(ctx) {
|
|
|
182
407
|
const autoThreadContext = replyPlan.autoThreadContext;
|
|
183
408
|
const effectiveFrom = isDirectMessage
|
|
184
409
|
? `discord:${author.id}`
|
|
185
|
-
: (autoThreadContext?.From ?? `discord:channel:${
|
|
410
|
+
: (autoThreadContext?.From ?? `discord:channel:${messageChannelId}`);
|
|
186
411
|
const effectiveTo = autoThreadContext?.To ?? replyTarget;
|
|
187
412
|
if (!effectiveTo) {
|
|
188
413
|
runtime.error?.(danger("discord: missing reply target"));
|
|
189
414
|
return;
|
|
190
415
|
}
|
|
416
|
+
// Keep DM routes user-addressed so follow-up sends resolve direct session keys.
|
|
417
|
+
const lastRouteTo = isDirectMessage ? `user:${author.id}` : effectiveTo;
|
|
418
|
+
const inboundHistory = shouldIncludeChannelHistory && historyLimit > 0
|
|
419
|
+
? (guildHistories.get(messageChannelId) ?? []).map((entry) => ({
|
|
420
|
+
sender: entry.sender,
|
|
421
|
+
body: entry.body,
|
|
422
|
+
timestamp: entry.timestamp,
|
|
423
|
+
}))
|
|
424
|
+
: undefined;
|
|
191
425
|
const ctxPayload = finalizeInboundContext({
|
|
192
426
|
Body: combinedBody,
|
|
427
|
+
BodyForAgent: baseText ?? text,
|
|
428
|
+
InboundHistory: inboundHistory,
|
|
193
429
|
RawBody: baseText,
|
|
194
430
|
CommandBody: baseText,
|
|
195
431
|
From: effectiveFrom,
|
|
@@ -198,18 +434,23 @@ export async function processDiscordMessage(ctx) {
|
|
|
198
434
|
AccountId: route.accountId,
|
|
199
435
|
ChatType: isDirectMessage ? "direct" : "channel",
|
|
200
436
|
ConversationLabel: fromLabel,
|
|
201
|
-
SenderName:
|
|
202
|
-
SenderId:
|
|
203
|
-
SenderUsername:
|
|
204
|
-
SenderTag:
|
|
437
|
+
SenderName: senderName,
|
|
438
|
+
SenderId: sender.id,
|
|
439
|
+
SenderUsername: senderUsername,
|
|
440
|
+
SenderTag: senderTag,
|
|
205
441
|
GroupSubject: groupSubject,
|
|
206
442
|
GroupChannel: groupChannel,
|
|
443
|
+
UntrustedContext: untrustedChannelMetadata ? [untrustedChannelMetadata] : undefined,
|
|
207
444
|
GroupSystemPrompt: isGuildMessage ? groupSystemPrompt : undefined,
|
|
208
445
|
GroupSpace: isGuildMessage ? (guildInfo?.id ?? guildSlug) || undefined : undefined,
|
|
446
|
+
OwnerAllowFrom: ownerAllowFrom,
|
|
209
447
|
Provider: "discord",
|
|
210
448
|
Surface: "discord",
|
|
211
449
|
WasMentioned: effectiveWasMentioned,
|
|
212
450
|
MessageSid: message.id,
|
|
451
|
+
ReplyToId: replyContext?.id,
|
|
452
|
+
ReplyToBody: replyContext?.body,
|
|
453
|
+
ReplyToSender: replyContext?.sender,
|
|
213
454
|
ParentSessionKey: autoThreadContext?.ParentSessionKey ?? threadKeys.parentSessionKey,
|
|
214
455
|
ThreadStarterBody: threadStarterBody,
|
|
215
456
|
ThreadLabel: threadLabel,
|
|
@@ -221,38 +462,52 @@ export async function processDiscordMessage(ctx) {
|
|
|
221
462
|
OriginatingChannel: "discord",
|
|
222
463
|
OriginatingTo: autoThreadContext?.OriginatingTo ?? replyTarget,
|
|
223
464
|
});
|
|
465
|
+
const persistedSessionKey = ctxPayload.SessionKey ?? route.sessionKey;
|
|
224
466
|
await recordInboundSession({
|
|
225
467
|
storePath,
|
|
226
|
-
sessionKey:
|
|
468
|
+
sessionKey: persistedSessionKey,
|
|
227
469
|
ctx: ctxPayload,
|
|
228
|
-
updateLastRoute:
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
: undefined,
|
|
470
|
+
updateLastRoute: {
|
|
471
|
+
sessionKey: persistedSessionKey,
|
|
472
|
+
channel: "discord",
|
|
473
|
+
to: lastRouteTo,
|
|
474
|
+
accountId: route.accountId,
|
|
475
|
+
},
|
|
236
476
|
onRecordError: (err) => {
|
|
237
477
|
logVerbose(`discord: failed updating session meta: ${String(err)}`);
|
|
238
478
|
},
|
|
239
479
|
});
|
|
240
480
|
if (shouldLogVerbose()) {
|
|
241
481
|
const preview = truncateUtf16Safe(combinedBody, 200).replace(/\n/g, "\\n");
|
|
242
|
-
logVerbose(`discord inbound: channel=${
|
|
482
|
+
logVerbose(`discord inbound: channel=${messageChannelId} deliver=${deliverTarget} from=${ctxPayload.From} preview="${preview}"`);
|
|
243
483
|
}
|
|
244
484
|
const typingChannelId = deliverTarget.startsWith("channel:")
|
|
245
485
|
? deliverTarget.slice("channel:".length)
|
|
246
|
-
:
|
|
247
|
-
const
|
|
486
|
+
: messageChannelId;
|
|
487
|
+
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
|
488
|
+
cfg,
|
|
489
|
+
agentId: route.agentId,
|
|
490
|
+
channel: "discord",
|
|
491
|
+
accountId: route.accountId,
|
|
492
|
+
});
|
|
248
493
|
const tableMode = resolveMarkdownTableMode({
|
|
249
494
|
cfg,
|
|
250
495
|
channel: "discord",
|
|
251
496
|
accountId,
|
|
252
497
|
});
|
|
498
|
+
const typingCallbacks = createTypingCallbacks({
|
|
499
|
+
start: () => sendTyping({ client, channelId: typingChannelId }),
|
|
500
|
+
onStartError: (err) => {
|
|
501
|
+
logTypingFailure({
|
|
502
|
+
log: logVerbose,
|
|
503
|
+
channel: "discord",
|
|
504
|
+
target: typingChannelId,
|
|
505
|
+
error: err,
|
|
506
|
+
});
|
|
507
|
+
},
|
|
508
|
+
});
|
|
253
509
|
const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcherWithTyping({
|
|
254
|
-
|
|
255
|
-
responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
|
|
510
|
+
...prefixOptions,
|
|
256
511
|
humanDelay: resolveHumanDelayConfig(cfg, route.agentId),
|
|
257
512
|
deliver: async (payload) => {
|
|
258
513
|
const replyToId = replyReference.use();
|
|
@@ -274,70 +529,76 @@ export async function processDiscordMessage(ctx) {
|
|
|
274
529
|
onError: (err, info) => {
|
|
275
530
|
runtime.error?.(danger(`discord ${info.kind} reply failed: ${String(err)}`));
|
|
276
531
|
},
|
|
277
|
-
onReplyStart:
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
logTypingFailure({
|
|
281
|
-
log: logVerbose,
|
|
282
|
-
channel: "discord",
|
|
283
|
-
target: typingChannelId,
|
|
284
|
-
error: err,
|
|
285
|
-
});
|
|
286
|
-
},
|
|
287
|
-
}).onReplyStart,
|
|
288
|
-
});
|
|
289
|
-
const { queuedFinal, counts } = await dispatchInboundMessage({
|
|
290
|
-
ctx: ctxPayload,
|
|
291
|
-
cfg,
|
|
292
|
-
dispatcher,
|
|
293
|
-
replyOptions: {
|
|
294
|
-
...replyOptions,
|
|
295
|
-
skillFilter: channelConfig?.skills,
|
|
296
|
-
disableBlockStreaming: typeof discordConfig?.blockStreaming === "boolean"
|
|
297
|
-
? !discordConfig.blockStreaming
|
|
298
|
-
: undefined,
|
|
299
|
-
onModelSelected: (ctx) => {
|
|
300
|
-
prefixContext.onModelSelected(ctx);
|
|
301
|
-
},
|
|
532
|
+
onReplyStart: async () => {
|
|
533
|
+
await typingCallbacks.onReplyStart();
|
|
534
|
+
await statusReactions.setThinking();
|
|
302
535
|
},
|
|
303
536
|
});
|
|
304
|
-
|
|
305
|
-
|
|
537
|
+
let dispatchResult = null;
|
|
538
|
+
let dispatchError = false;
|
|
539
|
+
try {
|
|
540
|
+
dispatchResult = await dispatchInboundMessage({
|
|
541
|
+
ctx: ctxPayload,
|
|
542
|
+
cfg,
|
|
543
|
+
dispatcher,
|
|
544
|
+
replyOptions: {
|
|
545
|
+
...replyOptions,
|
|
546
|
+
skillFilter: channelConfig?.skills,
|
|
547
|
+
disableBlockStreaming: typeof discordConfig?.blockStreaming === "boolean"
|
|
548
|
+
? !discordConfig.blockStreaming
|
|
549
|
+
: undefined,
|
|
550
|
+
onModelSelected,
|
|
551
|
+
onReasoningStream: async () => {
|
|
552
|
+
await statusReactions.setThinking();
|
|
553
|
+
},
|
|
554
|
+
onToolStart: async (payload) => {
|
|
555
|
+
await statusReactions.setTool(payload.name);
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
catch (err) {
|
|
561
|
+
dispatchError = true;
|
|
562
|
+
throw err;
|
|
563
|
+
}
|
|
564
|
+
finally {
|
|
565
|
+
markDispatchIdle();
|
|
566
|
+
if (statusReactionsEnabled) {
|
|
567
|
+
if (dispatchError) {
|
|
568
|
+
await statusReactions.setError();
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
await statusReactions.setDone();
|
|
572
|
+
}
|
|
573
|
+
if (removeAckAfterReply) {
|
|
574
|
+
void (async () => {
|
|
575
|
+
await sleep(dispatchError ? DISCORD_STATUS_ERROR_HOLD_MS : DISCORD_STATUS_DONE_HOLD_MS);
|
|
576
|
+
await statusReactions.clear();
|
|
577
|
+
})();
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
void statusReactions.restoreInitial();
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
if (!dispatchResult?.queuedFinal) {
|
|
306
585
|
if (isGuildMessage) {
|
|
307
586
|
clearHistoryEntriesIfEnabled({
|
|
308
587
|
historyMap: guildHistories,
|
|
309
|
-
historyKey:
|
|
588
|
+
historyKey: messageChannelId,
|
|
310
589
|
limit: historyLimit,
|
|
311
590
|
});
|
|
312
591
|
}
|
|
313
592
|
return;
|
|
314
593
|
}
|
|
315
594
|
if (shouldLogVerbose()) {
|
|
316
|
-
const finalCount = counts.final;
|
|
595
|
+
const finalCount = dispatchResult.counts.final;
|
|
317
596
|
logVerbose(`discord: delivered ${finalCount} reply${finalCount === 1 ? "" : "ies"} to ${replyTarget}`);
|
|
318
597
|
}
|
|
319
|
-
removeAckReactionAfterReply({
|
|
320
|
-
removeAfterReply: removeAckAfterReply,
|
|
321
|
-
ackReactionPromise,
|
|
322
|
-
ackReactionValue: ackReaction,
|
|
323
|
-
remove: async () => {
|
|
324
|
-
await removeReactionDiscord(message.channelId, message.id, ackReaction, {
|
|
325
|
-
rest: client.rest,
|
|
326
|
-
});
|
|
327
|
-
},
|
|
328
|
-
onError: (err) => {
|
|
329
|
-
logAckFailure({
|
|
330
|
-
log: logVerbose,
|
|
331
|
-
channel: "discord",
|
|
332
|
-
target: `${message.channelId}/${message.id}`,
|
|
333
|
-
error: err,
|
|
334
|
-
});
|
|
335
|
-
},
|
|
336
|
-
});
|
|
337
598
|
if (isGuildMessage) {
|
|
338
599
|
clearHistoryEntriesIfEnabled({
|
|
339
600
|
historyMap: guildHistories,
|
|
340
|
-
historyKey:
|
|
601
|
+
historyKey: messageChannelId,
|
|
341
602
|
limit: historyLimit,
|
|
342
603
|
});
|
|
343
604
|
}
|