@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,11 +1,11 @@
|
|
|
1
|
+
import { resolveSessionAgentId } from "../../agents/agent-scope.js";
|
|
1
2
|
import { getChannelPlugin, normalizeChannelId } from "../../channels/plugins/index.js";
|
|
2
3
|
import { DEFAULT_CHAT_CHANNEL } from "../../channels/registry.js";
|
|
3
|
-
import { loadConfig } from "../../config/config.js";
|
|
4
4
|
import { createOutboundSendDeps } from "../../cli/deps.js";
|
|
5
|
+
import { loadConfig } from "../../config/config.js";
|
|
5
6
|
import { deliverOutboundPayloads } from "../../infra/outbound/deliver.js";
|
|
6
|
-
import { normalizeReplyPayloadsForDelivery } from "../../infra/outbound/payloads.js";
|
|
7
7
|
import { ensureOutboundSessionEntry, resolveOutboundSessionRoute, } from "../../infra/outbound/outbound-session.js";
|
|
8
|
-
import {
|
|
8
|
+
import { normalizeReplyPayloadsForDelivery } from "../../infra/outbound/payloads.js";
|
|
9
9
|
import { resolveOutboundTarget } from "../../infra/outbound/targets.js";
|
|
10
10
|
import { normalizePollInput } from "../../polls.js";
|
|
11
11
|
import { ErrorCodes, errorShape, formatValidationErrors, validatePollParams, validateSendParams, } from "../protocol/index.js";
|
|
@@ -45,11 +45,27 @@ export const sendHandlers = {
|
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
47
|
const to = request.to.trim();
|
|
48
|
-
const message = request.message.trim();
|
|
49
|
-
const
|
|
48
|
+
const message = typeof request.message === "string" ? request.message.trim() : "";
|
|
49
|
+
const mediaUrl = typeof request.mediaUrl === "string" && request.mediaUrl.trim().length > 0
|
|
50
|
+
? request.mediaUrl.trim()
|
|
51
|
+
: undefined;
|
|
52
|
+
const mediaUrls = Array.isArray(request.mediaUrls)
|
|
53
|
+
? request.mediaUrls
|
|
54
|
+
.map((entry) => (typeof entry === "string" ? entry.trim() : ""))
|
|
55
|
+
.filter((entry) => entry.length > 0)
|
|
56
|
+
: undefined;
|
|
57
|
+
if (!message && !mediaUrl && (mediaUrls?.length ?? 0) === 0) {
|
|
58
|
+
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "invalid send params: text or media is required"));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
50
61
|
const channelInput = typeof request.channel === "string" ? request.channel : undefined;
|
|
51
62
|
const normalizedChannel = channelInput ? normalizeChannelId(channelInput) : null;
|
|
52
63
|
if (channelInput && !normalizedChannel) {
|
|
64
|
+
const normalizedInput = channelInput.trim().toLowerCase();
|
|
65
|
+
if (normalizedInput === "webchat") {
|
|
66
|
+
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "unsupported channel: webchat (internal-only). Use `chat.send` for WebChat UI messages or choose a deliverable channel."));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
53
69
|
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `unsupported channel: ${channelInput}`));
|
|
54
70
|
return;
|
|
55
71
|
}
|
|
@@ -57,6 +73,9 @@ export const sendHandlers = {
|
|
|
57
73
|
const accountId = typeof request.accountId === "string" && request.accountId.trim().length
|
|
58
74
|
? request.accountId.trim()
|
|
59
75
|
: undefined;
|
|
76
|
+
const threadId = typeof request.threadId === "string" && request.threadId.trim().length
|
|
77
|
+
? request.threadId.trim()
|
|
78
|
+
: undefined;
|
|
60
79
|
const outboundChannel = channel;
|
|
61
80
|
const plugin = getChannelPlugin(channel);
|
|
62
81
|
if (!plugin) {
|
|
@@ -82,7 +101,7 @@ export const sendHandlers = {
|
|
|
82
101
|
}
|
|
83
102
|
const outboundDeps = context.deps ? createOutboundSendDeps(context.deps) : undefined;
|
|
84
103
|
const mirrorPayloads = normalizeReplyPayloadsForDelivery([
|
|
85
|
-
{ text: message, mediaUrl
|
|
104
|
+
{ text: message, mediaUrl, mediaUrls },
|
|
86
105
|
]);
|
|
87
106
|
const mirrorText = mirrorPayloads
|
|
88
107
|
.map((payload) => payload.text)
|
|
@@ -101,6 +120,7 @@ export const sendHandlers = {
|
|
|
101
120
|
agentId: derivedAgentId,
|
|
102
121
|
accountId,
|
|
103
122
|
target: resolved.to,
|
|
123
|
+
threadId,
|
|
104
124
|
})
|
|
105
125
|
: null;
|
|
106
126
|
if (derivedRoute) {
|
|
@@ -117,8 +137,12 @@ export const sendHandlers = {
|
|
|
117
137
|
channel: outboundChannel,
|
|
118
138
|
to: resolved.to,
|
|
119
139
|
accountId,
|
|
120
|
-
payloads: [{ text: message, mediaUrl
|
|
140
|
+
payloads: [{ text: message, mediaUrl, mediaUrls }],
|
|
141
|
+
agentId: providedSessionKey
|
|
142
|
+
? resolveSessionAgentId({ sessionKey: providedSessionKey, config: cfg })
|
|
143
|
+
: derivedAgentId,
|
|
121
144
|
gifPlayback: request.gifPlayback,
|
|
145
|
+
threadId: threadId ?? null,
|
|
122
146
|
deps: outboundDeps,
|
|
123
147
|
mirror: providedSessionKey
|
|
124
148
|
? {
|
|
@@ -145,12 +169,15 @@ export const sendHandlers = {
|
|
|
145
169
|
messageId: result.messageId,
|
|
146
170
|
channel,
|
|
147
171
|
};
|
|
148
|
-
if ("chatId" in result)
|
|
172
|
+
if ("chatId" in result) {
|
|
149
173
|
payload.chatId = result.chatId;
|
|
150
|
-
|
|
174
|
+
}
|
|
175
|
+
if ("channelId" in result) {
|
|
151
176
|
payload.channelId = result.channelId;
|
|
152
|
-
|
|
177
|
+
}
|
|
178
|
+
if ("toJid" in result) {
|
|
153
179
|
payload.toJid = result.toJid;
|
|
180
|
+
}
|
|
154
181
|
if ("conversationId" in result) {
|
|
155
182
|
payload.conversationId = result.conversationId;
|
|
156
183
|
}
|
|
@@ -207,12 +234,24 @@ export const sendHandlers = {
|
|
|
207
234
|
return;
|
|
208
235
|
}
|
|
209
236
|
const channel = normalizedChannel ?? DEFAULT_CHAT_CHANNEL;
|
|
237
|
+
if (typeof request.durationSeconds === "number" && channel !== "telegram") {
|
|
238
|
+
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "durationSeconds is only supported for Telegram polls"));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (typeof request.isAnonymous === "boolean" && channel !== "telegram") {
|
|
242
|
+
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "isAnonymous is only supported for Telegram polls"));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
210
245
|
const poll = {
|
|
211
246
|
question: request.question,
|
|
212
247
|
options: request.options,
|
|
213
248
|
maxSelections: request.maxSelections,
|
|
249
|
+
durationSeconds: request.durationSeconds,
|
|
214
250
|
durationHours: request.durationHours,
|
|
215
251
|
};
|
|
252
|
+
const threadId = typeof request.threadId === "string" && request.threadId.trim().length
|
|
253
|
+
? request.threadId.trim()
|
|
254
|
+
: undefined;
|
|
216
255
|
const accountId = typeof request.accountId === "string" && request.accountId.trim().length
|
|
217
256
|
? request.accountId.trim()
|
|
218
257
|
: undefined;
|
|
@@ -243,20 +282,27 @@ export const sendHandlers = {
|
|
|
243
282
|
to: resolved.to,
|
|
244
283
|
poll: normalized,
|
|
245
284
|
accountId,
|
|
285
|
+
threadId,
|
|
286
|
+
silent: request.silent,
|
|
287
|
+
isAnonymous: request.isAnonymous,
|
|
246
288
|
});
|
|
247
289
|
const payload = {
|
|
248
290
|
runId: idem,
|
|
249
291
|
messageId: result.messageId,
|
|
250
292
|
channel,
|
|
251
293
|
};
|
|
252
|
-
if (result.toJid)
|
|
294
|
+
if (result.toJid) {
|
|
253
295
|
payload.toJid = result.toJid;
|
|
254
|
-
|
|
296
|
+
}
|
|
297
|
+
if (result.channelId) {
|
|
255
298
|
payload.channelId = result.channelId;
|
|
256
|
-
|
|
299
|
+
}
|
|
300
|
+
if (result.conversationId) {
|
|
257
301
|
payload.conversationId = result.conversationId;
|
|
258
|
-
|
|
302
|
+
}
|
|
303
|
+
if (result.pollId) {
|
|
259
304
|
payload.pollId = result.pollId;
|
|
305
|
+
}
|
|
260
306
|
context.dedupe.set(`poll:${idem}`, {
|
|
261
307
|
ts: Date.now(),
|
|
262
308
|
ok: true,
|
|
@@ -1,18 +1,91 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
+
import { resolveDefaultAgentId } from "../../agents/agent-scope.js";
|
|
3
4
|
import { abortEmbeddedPiRun, waitForEmbeddedPiRunEnd } from "../../agents/pi-embedded.js";
|
|
4
5
|
import { stopSubagentsForRequester } from "../../auto-reply/reply/abort.js";
|
|
5
6
|
import { clearSessionQueues } from "../../auto-reply/reply/queue.js";
|
|
6
7
|
import { loadConfig } from "../../config/config.js";
|
|
7
8
|
import { loadSessionStore, snapshotSessionOrigin, resolveMainSessionKey, updateSessionStore, } from "../../config/sessions.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
9
|
+
import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js";
|
|
10
|
+
import { normalizeAgentId, parseAgentSessionKey } from "../../routing/session-key.js";
|
|
11
|
+
import { ErrorCodes, errorShape, validateSessionsCompactParams, validateSessionsDeleteParams, validateSessionsListParams, validateSessionsPatchParams, validateSessionsPreviewParams, validateSessionsResetParams, validateSessionsResolveParams, } from "../protocol/index.js";
|
|
12
|
+
import { archiveFileOnDisk, archiveSessionTranscripts, listSessionsFromStore, loadCombinedSessionStoreForGateway, loadSessionEntry, pruneLegacyStoreKeys, readSessionPreviewItemsFromTranscript, resolveGatewaySessionStoreTarget, resolveSessionModelRef, resolveSessionTranscriptCandidates, } from "../session-utils.js";
|
|
10
13
|
import { applySessionsPatchToStore } from "../sessions-patch.js";
|
|
11
14
|
import { resolveSessionKeyFromResolveParams } from "../sessions-resolve.js";
|
|
15
|
+
import { assertValidParams } from "./validation.js";
|
|
16
|
+
function requireSessionKey(key, respond) {
|
|
17
|
+
const raw = typeof key === "string"
|
|
18
|
+
? key
|
|
19
|
+
: typeof key === "number"
|
|
20
|
+
? String(key)
|
|
21
|
+
: typeof key === "bigint"
|
|
22
|
+
? String(key)
|
|
23
|
+
: "";
|
|
24
|
+
const normalized = raw.trim();
|
|
25
|
+
if (!normalized) {
|
|
26
|
+
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "key required"));
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return normalized;
|
|
30
|
+
}
|
|
31
|
+
function resolveGatewaySessionTargetFromKey(key) {
|
|
32
|
+
const cfg = loadConfig();
|
|
33
|
+
const target = resolveGatewaySessionStoreTarget({ cfg, key });
|
|
34
|
+
return { cfg, target, storePath: target.storePath };
|
|
35
|
+
}
|
|
36
|
+
function migrateAndPruneSessionStoreKey(params) {
|
|
37
|
+
const target = resolveGatewaySessionStoreTarget({
|
|
38
|
+
cfg: params.cfg,
|
|
39
|
+
key: params.key,
|
|
40
|
+
store: params.store,
|
|
41
|
+
});
|
|
42
|
+
const primaryKey = target.canonicalKey;
|
|
43
|
+
if (!params.store[primaryKey]) {
|
|
44
|
+
const existingKey = target.storeKeys.find((candidate) => Boolean(params.store[candidate]));
|
|
45
|
+
if (existingKey) {
|
|
46
|
+
params.store[primaryKey] = params.store[existingKey];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
pruneLegacyStoreKeys({
|
|
50
|
+
store: params.store,
|
|
51
|
+
canonicalKey: primaryKey,
|
|
52
|
+
candidates: target.storeKeys,
|
|
53
|
+
});
|
|
54
|
+
return { target, primaryKey, entry: params.store[primaryKey] };
|
|
55
|
+
}
|
|
56
|
+
function archiveSessionTranscriptsForSession(params) {
|
|
57
|
+
if (!params.sessionId) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
return archiveSessionTranscripts({
|
|
61
|
+
sessionId: params.sessionId,
|
|
62
|
+
storePath: params.storePath,
|
|
63
|
+
sessionFile: params.sessionFile,
|
|
64
|
+
agentId: params.agentId,
|
|
65
|
+
reason: params.reason,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async function ensureSessionRuntimeCleanup(params) {
|
|
69
|
+
const queueKeys = new Set(params.target.storeKeys);
|
|
70
|
+
queueKeys.add(params.target.canonicalKey);
|
|
71
|
+
if (params.sessionId) {
|
|
72
|
+
queueKeys.add(params.sessionId);
|
|
73
|
+
}
|
|
74
|
+
clearSessionQueues([...queueKeys]);
|
|
75
|
+
stopSubagentsForRequester({ cfg: params.cfg, requesterSessionKey: params.target.canonicalKey });
|
|
76
|
+
if (!params.sessionId) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
abortEmbeddedPiRun(params.sessionId);
|
|
80
|
+
const ended = await waitForEmbeddedPiRunEnd(params.sessionId, 15_000);
|
|
81
|
+
if (ended) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
return errorShape(ErrorCodes.UNAVAILABLE, `Session ${params.key} is still active; try again in a moment.`);
|
|
85
|
+
}
|
|
12
86
|
export const sessionsHandlers = {
|
|
13
87
|
"sessions.list": ({ params, respond }) => {
|
|
14
|
-
if (!
|
|
15
|
-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid sessions.list params: ${formatValidationErrors(validateSessionsListParams.errors)}`));
|
|
88
|
+
if (!assertValidParams(params, validateSessionsListParams, "sessions.list", respond)) {
|
|
16
89
|
return;
|
|
17
90
|
}
|
|
18
91
|
const p = params;
|
|
@@ -27,8 +100,7 @@ export const sessionsHandlers = {
|
|
|
27
100
|
respond(true, result, undefined);
|
|
28
101
|
},
|
|
29
102
|
"sessions.preview": ({ params, respond }) => {
|
|
30
|
-
if (!
|
|
31
|
-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid sessions.preview params: ${formatValidationErrors(validateSessionsPreviewParams.errors)}`));
|
|
103
|
+
if (!assertValidParams(params, validateSessionsPreviewParams, "sessions.preview", respond)) {
|
|
32
104
|
return;
|
|
33
105
|
}
|
|
34
106
|
const p = params;
|
|
@@ -50,11 +122,15 @@ export const sessionsHandlers = {
|
|
|
50
122
|
const previews = [];
|
|
51
123
|
for (const key of keys) {
|
|
52
124
|
try {
|
|
53
|
-
const
|
|
54
|
-
const store = storeCache.get(
|
|
55
|
-
storeCache.set(
|
|
56
|
-
const
|
|
57
|
-
|
|
125
|
+
const storeTarget = resolveGatewaySessionStoreTarget({ cfg, key, scanLegacyKeys: false });
|
|
126
|
+
const store = storeCache.get(storeTarget.storePath) ?? loadSessionStore(storeTarget.storePath);
|
|
127
|
+
storeCache.set(storeTarget.storePath, store);
|
|
128
|
+
const target = resolveGatewaySessionStoreTarget({
|
|
129
|
+
cfg,
|
|
130
|
+
key,
|
|
131
|
+
store,
|
|
132
|
+
});
|
|
133
|
+
const entry = target.storeKeys.map((candidate) => store[candidate]).find(Boolean);
|
|
58
134
|
if (!entry?.sessionId) {
|
|
59
135
|
previews.push({ key, status: "missing", items: [] });
|
|
60
136
|
continue;
|
|
@@ -72,14 +148,13 @@ export const sessionsHandlers = {
|
|
|
72
148
|
}
|
|
73
149
|
respond(true, { ts: Date.now(), previews }, undefined);
|
|
74
150
|
},
|
|
75
|
-
"sessions.resolve": ({ params, respond }) => {
|
|
76
|
-
if (!
|
|
77
|
-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid sessions.resolve params: ${formatValidationErrors(validateSessionsResolveParams.errors)}`));
|
|
151
|
+
"sessions.resolve": async ({ params, respond }) => {
|
|
152
|
+
if (!assertValidParams(params, validateSessionsResolveParams, "sessions.resolve", respond)) {
|
|
78
153
|
return;
|
|
79
154
|
}
|
|
80
155
|
const p = params;
|
|
81
156
|
const cfg = loadConfig();
|
|
82
|
-
const resolved = resolveSessionKeyFromResolveParams({ cfg, p });
|
|
157
|
+
const resolved = await resolveSessionKeyFromResolveParams({ cfg, p });
|
|
83
158
|
if (!resolved.ok) {
|
|
84
159
|
respond(false, undefined, resolved.error);
|
|
85
160
|
return;
|
|
@@ -87,26 +162,17 @@ export const sessionsHandlers = {
|
|
|
87
162
|
respond(true, { ok: true, key: resolved.key }, undefined);
|
|
88
163
|
},
|
|
89
164
|
"sessions.patch": async ({ params, respond, context }) => {
|
|
90
|
-
if (!
|
|
91
|
-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid sessions.patch params: ${formatValidationErrors(validateSessionsPatchParams.errors)}`));
|
|
165
|
+
if (!assertValidParams(params, validateSessionsPatchParams, "sessions.patch", respond)) {
|
|
92
166
|
return;
|
|
93
167
|
}
|
|
94
168
|
const p = params;
|
|
95
|
-
const key =
|
|
169
|
+
const key = requireSessionKey(p.key, respond);
|
|
96
170
|
if (!key) {
|
|
97
|
-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "key required"));
|
|
98
171
|
return;
|
|
99
172
|
}
|
|
100
|
-
const cfg =
|
|
101
|
-
const target = resolveGatewaySessionStoreTarget({ cfg, key });
|
|
102
|
-
const storePath = target.storePath;
|
|
173
|
+
const { cfg, target, storePath } = resolveGatewaySessionTargetFromKey(key);
|
|
103
174
|
const applied = await updateSessionStore(storePath, async (store) => {
|
|
104
|
-
const primaryKey =
|
|
105
|
-
const existingKey = target.storeKeys.find((candidate) => store[candidate]);
|
|
106
|
-
if (existingKey && existingKey !== primaryKey && !store[primaryKey]) {
|
|
107
|
-
store[primaryKey] = store[existingKey];
|
|
108
|
-
delete store[existingKey];
|
|
109
|
-
}
|
|
175
|
+
const { primaryKey } = migrateAndPruneSessionStoreKey({ cfg, key, store });
|
|
110
176
|
return await applySessionsPatchToStore({
|
|
111
177
|
cfg,
|
|
112
178
|
store,
|
|
@@ -119,36 +185,53 @@ export const sessionsHandlers = {
|
|
|
119
185
|
respond(false, undefined, applied.error);
|
|
120
186
|
return;
|
|
121
187
|
}
|
|
188
|
+
const parsed = parseAgentSessionKey(target.canonicalKey ?? key);
|
|
189
|
+
const agentId = normalizeAgentId(parsed?.agentId ?? resolveDefaultAgentId(cfg));
|
|
190
|
+
const resolved = resolveSessionModelRef(cfg, applied.entry, agentId);
|
|
122
191
|
const result = {
|
|
123
192
|
ok: true,
|
|
124
193
|
path: storePath,
|
|
125
194
|
key: target.canonicalKey,
|
|
126
195
|
entry: applied.entry,
|
|
196
|
+
resolved: {
|
|
197
|
+
modelProvider: resolved.provider,
|
|
198
|
+
model: resolved.model,
|
|
199
|
+
},
|
|
127
200
|
};
|
|
128
201
|
respond(true, result, undefined);
|
|
129
202
|
},
|
|
130
203
|
"sessions.reset": async ({ params, respond }) => {
|
|
131
|
-
if (!
|
|
132
|
-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid sessions.reset params: ${formatValidationErrors(validateSessionsResetParams.errors)}`));
|
|
204
|
+
if (!assertValidParams(params, validateSessionsResetParams, "sessions.reset", respond)) {
|
|
133
205
|
return;
|
|
134
206
|
}
|
|
135
207
|
const p = params;
|
|
136
|
-
const key =
|
|
208
|
+
const key = requireSessionKey(p.key, respond);
|
|
137
209
|
if (!key) {
|
|
138
|
-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "key required"));
|
|
139
210
|
return;
|
|
140
211
|
}
|
|
141
|
-
const cfg =
|
|
142
|
-
const
|
|
143
|
-
const
|
|
212
|
+
const { cfg, target, storePath } = resolveGatewaySessionTargetFromKey(key);
|
|
213
|
+
const { entry } = loadSessionEntry(key);
|
|
214
|
+
const commandReason = p.reason === "new" ? "new" : "reset";
|
|
215
|
+
const hookEvent = createInternalHookEvent("command", commandReason, target.canonicalKey ?? key, {
|
|
216
|
+
sessionEntry: entry,
|
|
217
|
+
previousSessionEntry: entry,
|
|
218
|
+
commandSource: "gateway:sessions.reset",
|
|
219
|
+
cfg,
|
|
220
|
+
});
|
|
221
|
+
await triggerInternalHook(hookEvent);
|
|
222
|
+
const sessionId = entry?.sessionId;
|
|
223
|
+
const cleanupError = await ensureSessionRuntimeCleanup({ cfg, key, target, sessionId });
|
|
224
|
+
if (cleanupError) {
|
|
225
|
+
respond(false, undefined, cleanupError);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
let oldSessionId;
|
|
229
|
+
let oldSessionFile;
|
|
144
230
|
const next = await updateSessionStore(storePath, (store) => {
|
|
145
|
-
const primaryKey =
|
|
146
|
-
const existingKey = target.storeKeys.find((candidate) => store[candidate]);
|
|
147
|
-
if (existingKey && existingKey !== primaryKey && !store[primaryKey]) {
|
|
148
|
-
store[primaryKey] = store[existingKey];
|
|
149
|
-
delete store[existingKey];
|
|
150
|
-
}
|
|
231
|
+
const { primaryKey } = migrateAndPruneSessionStoreKey({ cfg, key, store });
|
|
151
232
|
const entry = store[primaryKey];
|
|
233
|
+
oldSessionId = entry?.sessionId;
|
|
234
|
+
oldSessionFile = entry?.sessionFile;
|
|
152
235
|
const now = Date.now();
|
|
153
236
|
const nextEntry = {
|
|
154
237
|
sessionId: randomUUID(),
|
|
@@ -171,100 +254,79 @@ export const sessionsHandlers = {
|
|
|
171
254
|
inputTokens: 0,
|
|
172
255
|
outputTokens: 0,
|
|
173
256
|
totalTokens: 0,
|
|
257
|
+
totalTokensFresh: true,
|
|
174
258
|
};
|
|
175
259
|
store[primaryKey] = nextEntry;
|
|
176
260
|
return nextEntry;
|
|
177
261
|
});
|
|
262
|
+
// Archive old transcript so it doesn't accumulate on disk (#14869).
|
|
263
|
+
archiveSessionTranscriptsForSession({
|
|
264
|
+
sessionId: oldSessionId,
|
|
265
|
+
storePath,
|
|
266
|
+
sessionFile: oldSessionFile,
|
|
267
|
+
agentId: target.agentId,
|
|
268
|
+
reason: "reset",
|
|
269
|
+
});
|
|
178
270
|
respond(true, { ok: true, key: target.canonicalKey, entry: next }, undefined);
|
|
179
271
|
},
|
|
180
272
|
"sessions.delete": async ({ params, respond }) => {
|
|
181
|
-
if (!
|
|
182
|
-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid sessions.delete params: ${formatValidationErrors(validateSessionsDeleteParams.errors)}`));
|
|
273
|
+
if (!assertValidParams(params, validateSessionsDeleteParams, "sessions.delete", respond)) {
|
|
183
274
|
return;
|
|
184
275
|
}
|
|
185
276
|
const p = params;
|
|
186
|
-
const key =
|
|
277
|
+
const key = requireSessionKey(p.key, respond);
|
|
187
278
|
if (!key) {
|
|
188
|
-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "key required"));
|
|
189
279
|
return;
|
|
190
280
|
}
|
|
191
|
-
const cfg =
|
|
281
|
+
const { cfg, target, storePath } = resolveGatewaySessionTargetFromKey(key);
|
|
192
282
|
const mainKey = resolveMainSessionKey(cfg);
|
|
193
|
-
const target = resolveGatewaySessionStoreTarget({ cfg, key });
|
|
194
283
|
if (target.canonicalKey === mainKey) {
|
|
195
284
|
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `Cannot delete the main session (${mainKey}).`));
|
|
196
285
|
return;
|
|
197
286
|
}
|
|
198
287
|
const deleteTranscript = typeof p.deleteTranscript === "boolean" ? p.deleteTranscript : true;
|
|
199
|
-
const storePath = target.storePath;
|
|
200
288
|
const { entry } = loadSessionEntry(key);
|
|
201
289
|
const sessionId = entry?.sessionId;
|
|
202
290
|
const existed = Boolean(entry);
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
clearSessionQueues([...queueKeys]);
|
|
208
|
-
stopSubagentsForRequester({ cfg, requesterSessionKey: target.canonicalKey });
|
|
209
|
-
if (sessionId) {
|
|
210
|
-
abortEmbeddedPiRun(sessionId);
|
|
211
|
-
const ended = await waitForEmbeddedPiRunEnd(sessionId, 15_000);
|
|
212
|
-
if (!ended) {
|
|
213
|
-
respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, `Session ${key} is still active; try again in a moment.`));
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
291
|
+
const cleanupError = await ensureSessionRuntimeCleanup({ cfg, key, target, sessionId });
|
|
292
|
+
if (cleanupError) {
|
|
293
|
+
respond(false, undefined, cleanupError);
|
|
294
|
+
return;
|
|
216
295
|
}
|
|
217
296
|
await updateSessionStore(storePath, (store) => {
|
|
218
|
-
const primaryKey =
|
|
219
|
-
|
|
220
|
-
if (existingKey && existingKey !== primaryKey && !store[primaryKey]) {
|
|
221
|
-
store[primaryKey] = store[existingKey];
|
|
222
|
-
delete store[existingKey];
|
|
223
|
-
}
|
|
224
|
-
if (store[primaryKey])
|
|
297
|
+
const { primaryKey } = migrateAndPruneSessionStoreKey({ cfg, key, store });
|
|
298
|
+
if (store[primaryKey]) {
|
|
225
299
|
delete store[primaryKey];
|
|
226
|
-
});
|
|
227
|
-
const archived = [];
|
|
228
|
-
if (deleteTranscript && sessionId) {
|
|
229
|
-
for (const candidate of resolveSessionTranscriptCandidates(sessionId, storePath, entry?.sessionFile, target.agentId)) {
|
|
230
|
-
if (!fs.existsSync(candidate))
|
|
231
|
-
continue;
|
|
232
|
-
try {
|
|
233
|
-
archived.push(archiveFileOnDisk(candidate, "deleted"));
|
|
234
|
-
}
|
|
235
|
-
catch {
|
|
236
|
-
// Best-effort.
|
|
237
|
-
}
|
|
238
300
|
}
|
|
239
|
-
}
|
|
301
|
+
});
|
|
302
|
+
const archived = deleteTranscript
|
|
303
|
+
? archiveSessionTranscriptsForSession({
|
|
304
|
+
sessionId,
|
|
305
|
+
storePath,
|
|
306
|
+
sessionFile: entry?.sessionFile,
|
|
307
|
+
agentId: target.agentId,
|
|
308
|
+
reason: "deleted",
|
|
309
|
+
})
|
|
310
|
+
: [];
|
|
240
311
|
respond(true, { ok: true, key: target.canonicalKey, deleted: existed, archived }, undefined);
|
|
241
312
|
},
|
|
242
313
|
"sessions.compact": async ({ params, respond }) => {
|
|
243
|
-
if (!
|
|
244
|
-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid sessions.compact params: ${formatValidationErrors(validateSessionsCompactParams.errors)}`));
|
|
314
|
+
if (!assertValidParams(params, validateSessionsCompactParams, "sessions.compact", respond)) {
|
|
245
315
|
return;
|
|
246
316
|
}
|
|
247
317
|
const p = params;
|
|
248
|
-
const key =
|
|
318
|
+
const key = requireSessionKey(p.key, respond);
|
|
249
319
|
if (!key) {
|
|
250
|
-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "key required"));
|
|
251
320
|
return;
|
|
252
321
|
}
|
|
253
322
|
const maxLines = typeof p.maxLines === "number" && Number.isFinite(p.maxLines)
|
|
254
323
|
? Math.max(1, Math.floor(p.maxLines))
|
|
255
324
|
: 400;
|
|
256
|
-
const cfg =
|
|
257
|
-
const target = resolveGatewaySessionStoreTarget({ cfg, key });
|
|
258
|
-
const storePath = target.storePath;
|
|
325
|
+
const { cfg, target, storePath } = resolveGatewaySessionTargetFromKey(key);
|
|
259
326
|
// Lock + read in a short critical section; transcript work happens outside.
|
|
260
327
|
const compactTarget = await updateSessionStore(storePath, (store) => {
|
|
261
|
-
const primaryKey =
|
|
262
|
-
|
|
263
|
-
if (existingKey && existingKey !== primaryKey && !store[primaryKey]) {
|
|
264
|
-
store[primaryKey] = store[existingKey];
|
|
265
|
-
delete store[existingKey];
|
|
266
|
-
}
|
|
267
|
-
return { entry: store[primaryKey], primaryKey };
|
|
328
|
+
const { entry, primaryKey } = migrateAndPruneSessionStoreKey({ cfg, key, store });
|
|
329
|
+
return { entry, primaryKey };
|
|
268
330
|
});
|
|
269
331
|
const entry = compactTarget.entry;
|
|
270
332
|
const sessionId = entry?.sessionId;
|
|
@@ -304,11 +366,13 @@ export const sessionsHandlers = {
|
|
|
304
366
|
await updateSessionStore(storePath, (store) => {
|
|
305
367
|
const entryKey = compactTarget.primaryKey;
|
|
306
368
|
const entryToUpdate = store[entryKey];
|
|
307
|
-
if (!entryToUpdate)
|
|
369
|
+
if (!entryToUpdate) {
|
|
308
370
|
return;
|
|
371
|
+
}
|
|
309
372
|
delete entryToUpdate.inputTokens;
|
|
310
373
|
delete entryToUpdate.outputTokens;
|
|
311
374
|
delete entryToUpdate.totalTokens;
|
|
375
|
+
delete entryToUpdate.totalTokensFresh;
|
|
312
376
|
entryToUpdate.updatedAt = Date.now();
|
|
313
377
|
});
|
|
314
378
|
respond(true, {
|
|
@@ -4,6 +4,7 @@ import { setHeartbeatsEnabled } from "../../infra/heartbeat-runner.js";
|
|
|
4
4
|
import { enqueueSystemEvent, isSystemEventContextChanged } from "../../infra/system-events.js";
|
|
5
5
|
import { listSystemPresence, updateSystemPresence } from "../../infra/system-presence.js";
|
|
6
6
|
import { ErrorCodes, errorShape } from "../protocol/index.js";
|
|
7
|
+
import { broadcastPresenceSnapshot } from "../server/presence-events.js";
|
|
7
8
|
export const systemHandlers = {
|
|
8
9
|
"last-heartbeat": ({ respond }) => {
|
|
9
10
|
respond(true, getLastHeartbeatEvent(), undefined);
|
|
@@ -109,13 +110,10 @@ export const systemHandlers = {
|
|
|
109
110
|
else {
|
|
110
111
|
enqueueSystemEvent(text, { sessionKey });
|
|
111
112
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
presence: nextPresenceVersion,
|
|
117
|
-
health: context.getHealthVersion(),
|
|
118
|
-
},
|
|
113
|
+
broadcastPresenceSnapshot({
|
|
114
|
+
broadcast: context.broadcast,
|
|
115
|
+
incrementPresenceVersion: context.incrementPresenceVersion,
|
|
116
|
+
getHealthVersion: context.getHealthVersion,
|
|
119
117
|
});
|
|
120
118
|
respond(true, { ok: true }, undefined);
|
|
121
119
|
},
|
|
@@ -23,14 +23,22 @@ const BASE_METHODS = [
|
|
|
23
23
|
"exec.approvals.node.get",
|
|
24
24
|
"exec.approvals.node.set",
|
|
25
25
|
"exec.approval.request",
|
|
26
|
+
"exec.approval.waitDecision",
|
|
26
27
|
"exec.approval.resolve",
|
|
27
28
|
"wizard.start",
|
|
28
29
|
"wizard.next",
|
|
29
30
|
"wizard.cancel",
|
|
30
31
|
"wizard.status",
|
|
32
|
+
"talk.config",
|
|
31
33
|
"talk.mode",
|
|
32
34
|
"models.list",
|
|
33
35
|
"agents.list",
|
|
36
|
+
"agents.create",
|
|
37
|
+
"agents.update",
|
|
38
|
+
"agents.delete",
|
|
39
|
+
"agents.files.list",
|
|
40
|
+
"agents.files.get",
|
|
41
|
+
"agents.files.set",
|
|
34
42
|
"skills.status",
|
|
35
43
|
"skills.bins",
|
|
36
44
|
"skills.install",
|