@poolzin/pool-bot 2026.2.23 → 2026.2.25
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 +29 -0
- package/dist/acp/client.js +207 -18
- package/dist/acp/secret-file.js +22 -0
- package/dist/agents/agent-scope.js +10 -0
- package/dist/agents/bash-process-registry.test-helpers.js +29 -0
- package/dist/agents/bash-tools.exec-approval-request.js +20 -0
- package/dist/agents/bash-tools.exec-host-gateway.js +230 -0
- package/dist/agents/bash-tools.exec-host-node.js +235 -0
- package/dist/agents/bash-tools.exec-types.js +1 -0
- package/dist/agents/bash-tools.process.js +224 -218
- package/dist/agents/content-blocks.js +16 -0
- package/dist/agents/model-fallback.js +96 -101
- package/dist/agents/models-config.providers.js +299 -182
- package/dist/agents/pi-embedded-payloads.js +1 -0
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +34 -0
- package/dist/agents/skills.test-helpers.js +13 -0
- package/dist/agents/stable-stringify.js +12 -0
- package/dist/agents/subagent-registry.mocks.shared.js +12 -0
- package/dist/agents/test-helpers/assistant-message-fixtures.js +29 -0
- package/dist/agents/test-helpers/pi-tools-sandbox-context.js +27 -0
- package/dist/agents/tool-policy-shared.js +108 -0
- package/dist/agents/tools/browser-tool.js +160 -54
- package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
- package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
- package/dist/agents/tools/image-tool.js +214 -99
- package/dist/agents/tools/sessions-history-tool.js +140 -108
- package/dist/agents/workspace.js +222 -46
- package/dist/auto-reply/commands-registry.js +15 -18
- package/dist/auto-reply/fallback-state.js +114 -0
- package/dist/auto-reply/model-runtime.js +68 -0
- package/dist/auto-reply/reply/agent-runner-execution.js +36 -4
- package/dist/auto-reply/reply/agent-runner.js +165 -39
- package/dist/auto-reply/reply/commands-setunset-standard.js +13 -0
- package/dist/browser/config.js +26 -0
- package/dist/browser/navigation-guard.js +31 -0
- package/dist/browser/routes/agent.act.js +431 -424
- package/dist/browser/routes/agent.shared.js +47 -3
- package/dist/browser/routes/agent.snapshot.js +122 -116
- package/dist/browser/routes/agent.storage.js +303 -297
- package/dist/browser/routes/tabs.js +154 -100
- package/dist/browser/server-lifecycle.js +37 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/allow-from.js +25 -0
- package/dist/channels/plugins/account-action-gate.js +13 -0
- package/dist/channels/plugins/message-actions.js +10 -0
- package/dist/channels/telegram/api.js +18 -0
- package/dist/cli/argv.js +84 -21
- package/dist/cli/banner.js +2 -1
- package/dist/cli/exec-approvals-cli.js +92 -124
- package/dist/cli/memory-cli.js +158 -61
- package/dist/cli/nodes-cli/register.push.js +63 -0
- package/dist/cli/nodes-media-utils.js +21 -0
- package/dist/cli/plugins-cli.js +245 -61
- package/dist/cli/program/build-program.js +3 -1
- package/dist/cli/program/command-registry.js +223 -136
- package/dist/cli/program/help.js +43 -12
- package/dist/cli/route.js +1 -1
- package/dist/cli/test-runtime-capture.js +24 -0
- package/dist/commands/agent.js +163 -87
- package/dist/commands/channels.mock-harness.js +23 -0
- package/dist/commands/daemon-install-runtime-warning.js +11 -0
- package/dist/commands/onboard-helpers.js +4 -4
- package/dist/commands/sessions.test-helpers.js +61 -0
- package/dist/compat/legacy-names.js +2 -2
- package/dist/config/commands.js +3 -0
- package/dist/config/config.js +1 -1
- package/dist/config/env-substitution.js +62 -34
- package/dist/config/env-vars.js +9 -0
- package/dist/config/io.js +571 -171
- package/dist/config/merge-patch.js +50 -4
- package/dist/config/redact-snapshot.js +404 -76
- package/dist/config/schema.js +58 -570
- package/dist/config/validation.js +140 -85
- package/dist/config/zod-schema.hooks.js +40 -11
- package/dist/config/zod-schema.installs.js +20 -0
- package/dist/config/zod-schema.js +8 -7
- package/dist/control-ui/assets/{index-HRr1grwl.js → index-Dvkl4Xlx.js} +2 -1
- package/dist/control-ui/assets/{index-HRr1grwl.js.map → index-Dvkl4Xlx.js.map} +1 -1
- package/dist/control-ui/index.html +1 -1
- package/dist/daemon/cmd-argv.js +21 -0
- package/dist/daemon/cmd-set.js +58 -0
- package/dist/daemon/service-types.js +1 -0
- package/dist/discord/monitor/exec-approvals.js +357 -162
- package/dist/gateway/auth.js +38 -3
- package/dist/gateway/call.js +149 -68
- package/dist/gateway/canvas-capability.js +75 -0
- package/dist/gateway/control-plane-audit.js +28 -0
- package/dist/gateway/control-plane-rate-limit.js +53 -0
- package/dist/gateway/events.js +1 -0
- package/dist/gateway/hooks.js +109 -54
- package/dist/gateway/http-common.js +22 -0
- package/dist/gateway/method-scopes.js +169 -0
- package/dist/gateway/net.js +23 -0
- package/dist/gateway/openresponses-http.js +120 -110
- package/dist/gateway/probe-auth.js +2 -0
- package/dist/gateway/protocol/index.js +3 -2
- package/dist/gateway/protocol/schema/protocol-schemas.js +2 -0
- package/dist/gateway/protocol/schema/push.js +18 -0
- package/dist/gateway/protocol/schema.js +1 -0
- package/dist/gateway/server-http.js +236 -52
- package/dist/gateway/server-methods/agent.js +162 -24
- package/dist/gateway/server-methods/chat.js +461 -130
- package/dist/gateway/server-methods/config.js +193 -150
- package/dist/gateway/server-methods/nodes.helpers.js +12 -0
- package/dist/gateway/server-methods/nodes.js +251 -69
- package/dist/gateway/server-methods/push.js +53 -0
- package/dist/gateway/server-reload-handlers.js +2 -3
- package/dist/gateway/server-runtime-config.js +5 -0
- package/dist/gateway/server-runtime-state.js +2 -0
- package/dist/gateway/server-ws-runtime.js +1 -0
- package/dist/gateway/server.impl.js +296 -139
- package/dist/gateway/session-preview.test-helpers.js +11 -0
- package/dist/gateway/startup-auth.js +126 -0
- package/dist/gateway/test-helpers.agent-results.js +15 -0
- package/dist/gateway/test-helpers.mocks.js +37 -14
- package/dist/gateway/test-helpers.server.js +161 -77
- package/dist/hooks/bundled/session-memory/handler.js +165 -34
- package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
- package/dist/infra/archive-path.js +49 -0
- package/dist/infra/device-pairing.js +148 -167
- package/dist/infra/exec-approvals-allowlist.js +19 -70
- package/dist/infra/exec-approvals-analysis.js +44 -17
- package/dist/infra/exec-safe-bin-policy.js +269 -0
- package/dist/infra/fixed-window-rate-limit.js +33 -0
- package/dist/infra/git-root.js +61 -0
- package/dist/infra/heartbeat-active-hours.js +2 -2
- package/dist/infra/heartbeat-reason.js +40 -0
- package/dist/infra/heartbeat-runner.js +72 -32
- package/dist/infra/install-source-utils.js +91 -7
- package/dist/infra/node-pairing.js +50 -105
- package/dist/infra/npm-integrity.js +45 -0
- package/dist/infra/npm-pack-install.js +40 -0
- package/dist/infra/outbound/channel-adapters.js +20 -7
- package/dist/infra/outbound/message-action-runner.js +107 -327
- package/dist/infra/outbound/message.js +59 -36
- package/dist/infra/outbound/outbound-policy.js +52 -25
- package/dist/infra/outbound/outbound-send-service.js +58 -71
- package/dist/infra/pairing-files.js +10 -0
- package/dist/infra/plain-object.js +9 -0
- package/dist/infra/push-apns.js +365 -0
- package/dist/infra/restart-sentinel.js +16 -1
- package/dist/infra/restart.js +229 -26
- package/dist/infra/scp-host.js +54 -0
- package/dist/infra/update-startup.js +86 -9
- package/dist/media/inbound-path-policy.js +114 -0
- package/dist/media/input-files.js +16 -0
- package/dist/memory/test-manager.js +8 -0
- package/dist/plugin-sdk/temp-path.js +47 -0
- package/dist/plugins/discovery.js +217 -23
- package/dist/plugins/hook-runner-global.js +16 -0
- package/dist/plugins/loader.js +192 -26
- package/dist/plugins/logger.js +8 -0
- package/dist/plugins/manifest-registry.js +3 -0
- package/dist/plugins/path-safety.js +34 -0
- package/dist/plugins/registry.js +5 -2
- package/dist/plugins/runtime/index.js +271 -206
- package/dist/providers/github-copilot-models.js +4 -1
- package/dist/security/audit-channel.js +8 -19
- package/dist/security/audit-extra.async.js +354 -182
- package/dist/security/audit-extra.js +11 -1
- package/dist/security/audit-extra.sync.js +340 -33
- package/dist/security/audit-fs.js +31 -13
- package/dist/security/audit.js +145 -371
- package/dist/security/dm-policy-shared.js +24 -0
- package/dist/security/external-content.js +20 -8
- package/dist/security/fix.js +49 -85
- package/dist/security/scan-paths.js +20 -0
- package/dist/security/secret-equal.js +3 -7
- package/dist/security/windows-acl.js +30 -15
- package/dist/shared/node-list-parse.js +13 -0
- package/dist/shared/operator-scope-compat.js +37 -0
- package/dist/shared/text-chunking.js +29 -0
- package/dist/slack/blocks.test-helpers.js +31 -0
- package/dist/slack/monitor/mrkdwn.js +8 -0
- package/dist/telegram/bot-message-dispatch.js +366 -164
- package/dist/telegram/draft-stream.js +30 -7
- package/dist/telegram/reasoning-lane-coordinator.js +128 -0
- package/dist/terminal/prompt-select-styled.js +9 -0
- package/dist/test-utils/command-runner.js +6 -0
- package/dist/test-utils/internal-hook-event-payload.js +10 -0
- package/dist/test-utils/model-auth-mock.js +12 -0
- package/dist/test-utils/provider-usage-fetch.js +14 -0
- package/dist/test-utils/temp-home.js +33 -0
- package/dist/tui/components/chat-log.js +9 -0
- package/dist/tui/tui-command-handlers.js +36 -27
- package/dist/tui/tui-event-handlers.js +122 -32
- package/dist/tui/tui.js +181 -45
- package/dist/utils/mask-api-key.js +10 -0
- package/dist/utils/run-with-concurrency.js +39 -0
- package/dist/web/media.js +4 -0
- package/docs/tools/slash-commands.md +5 -1
- 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/feishu/src/external-keys.ts +19 -0
- 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/lobster/src/windows-spawn.ts +193 -0
- package/extensions/matrix/CHANGELOG.md +5 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
- package/extensions/mattermost/package.json +1 -1
- package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
- 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
|
@@ -1,15 +1,37 @@
|
|
|
1
1
|
import { getChannelPlugin, normalizeChannelId } from "../../channels/plugins/index.js";
|
|
2
2
|
import { loadConfig } from "../../config/config.js";
|
|
3
|
-
import {
|
|
3
|
+
import { callGatewayLeastPrivilege, randomIdempotencyKey } from "../../gateway/call.js";
|
|
4
4
|
import { normalizePollInput } from "../../polls.js";
|
|
5
5
|
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES, } from "../../utils/message-channel.js";
|
|
6
6
|
import { resolveMessageChannelSelection } from "./channel-selection.js";
|
|
7
7
|
import { deliverOutboundPayloads, } from "./deliver.js";
|
|
8
8
|
import { normalizeReplyPayloadsForDelivery } from "./payloads.js";
|
|
9
9
|
import { resolveOutboundTarget } from "./targets.js";
|
|
10
|
+
async function resolveRequiredChannel(params) {
|
|
11
|
+
const channel = params.channel?.trim()
|
|
12
|
+
? normalizeChannelId(params.channel)
|
|
13
|
+
: (await resolveMessageChannelSelection({ cfg: params.cfg })).channel;
|
|
14
|
+
if (!channel) {
|
|
15
|
+
throw new Error(`Unknown channel: ${params.channel}`);
|
|
16
|
+
}
|
|
17
|
+
return channel;
|
|
18
|
+
}
|
|
19
|
+
function resolveRequiredPlugin(channel) {
|
|
20
|
+
const plugin = getChannelPlugin(channel);
|
|
21
|
+
if (!plugin) {
|
|
22
|
+
throw new Error(`Unknown channel: ${channel}`);
|
|
23
|
+
}
|
|
24
|
+
return plugin;
|
|
25
|
+
}
|
|
10
26
|
function resolveGatewayOptions(opts) {
|
|
27
|
+
// Security: backend callers (tools/agents) must not accept user-controlled gateway URLs.
|
|
28
|
+
// Use config-derived gateway target only.
|
|
29
|
+
const url = opts?.mode === GATEWAY_CLIENT_MODES.BACKEND ||
|
|
30
|
+
opts?.clientName === GATEWAY_CLIENT_NAMES.GATEWAY_CLIENT
|
|
31
|
+
? undefined
|
|
32
|
+
: opts?.url;
|
|
11
33
|
return {
|
|
12
|
-
url
|
|
34
|
+
url,
|
|
13
35
|
token: opts?.token,
|
|
14
36
|
timeoutMs: typeof opts?.timeoutMs === "number" && Number.isFinite(opts.timeoutMs)
|
|
15
37
|
? Math.max(1, Math.floor(opts.timeoutMs))
|
|
@@ -19,18 +41,23 @@ function resolveGatewayOptions(opts) {
|
|
|
19
41
|
mode: opts?.mode ?? GATEWAY_CLIENT_MODES.CLI,
|
|
20
42
|
};
|
|
21
43
|
}
|
|
44
|
+
async function callMessageGateway(params) {
|
|
45
|
+
const gateway = resolveGatewayOptions(params.gateway);
|
|
46
|
+
return await callGatewayLeastPrivilege({
|
|
47
|
+
url: gateway.url,
|
|
48
|
+
token: gateway.token,
|
|
49
|
+
method: params.method,
|
|
50
|
+
params: params.params,
|
|
51
|
+
timeoutMs: gateway.timeoutMs,
|
|
52
|
+
clientName: gateway.clientName,
|
|
53
|
+
clientDisplayName: gateway.clientDisplayName,
|
|
54
|
+
mode: gateway.mode,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
22
57
|
export async function sendMessage(params) {
|
|
23
58
|
const cfg = params.cfg ?? loadConfig();
|
|
24
|
-
const channel = params.channel
|
|
25
|
-
|
|
26
|
-
: (await resolveMessageChannelSelection({ cfg })).channel;
|
|
27
|
-
if (!channel) {
|
|
28
|
-
throw new Error(`Unknown channel: ${params.channel}`);
|
|
29
|
-
}
|
|
30
|
-
const plugin = getChannelPlugin(channel);
|
|
31
|
-
if (!plugin) {
|
|
32
|
-
throw new Error(`Unknown channel: ${channel}`);
|
|
33
|
-
}
|
|
59
|
+
const channel = await resolveRequiredChannel({ cfg, channel: params.channel });
|
|
60
|
+
const plugin = resolveRequiredPlugin(channel);
|
|
34
61
|
const deliveryMode = plugin.outbound?.deliveryMode ?? "direct";
|
|
35
62
|
const normalizedPayloads = normalizeReplyPayloadsForDelivery([
|
|
36
63
|
{
|
|
@@ -64,18 +91,23 @@ export async function sendMessage(params) {
|
|
|
64
91
|
accountId: params.accountId,
|
|
65
92
|
mode: "explicit",
|
|
66
93
|
});
|
|
67
|
-
if (!resolvedTarget.ok)
|
|
94
|
+
if (!resolvedTarget.ok) {
|
|
68
95
|
throw resolvedTarget.error;
|
|
96
|
+
}
|
|
69
97
|
const results = await deliverOutboundPayloads({
|
|
70
98
|
cfg,
|
|
71
99
|
channel: outboundChannel,
|
|
72
100
|
to: resolvedTarget.to,
|
|
101
|
+
agentId: params.agentId,
|
|
73
102
|
accountId: params.accountId,
|
|
74
103
|
payloads: normalizedPayloads,
|
|
104
|
+
replyToId: params.replyToId,
|
|
105
|
+
threadId: params.threadId,
|
|
75
106
|
gifPlayback: params.gifPlayback,
|
|
76
107
|
deps: params.deps,
|
|
77
108
|
bestEffort: params.bestEffort,
|
|
78
109
|
abortSignal: params.abortSignal,
|
|
110
|
+
silent: params.silent,
|
|
79
111
|
mirror: params.mirror
|
|
80
112
|
? {
|
|
81
113
|
...params.mirror,
|
|
@@ -93,10 +125,8 @@ export async function sendMessage(params) {
|
|
|
93
125
|
result: results.at(-1),
|
|
94
126
|
};
|
|
95
127
|
}
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
url: gateway.url,
|
|
99
|
-
token: gateway.token,
|
|
128
|
+
const result = await callMessageGateway({
|
|
129
|
+
gateway: params.gateway,
|
|
100
130
|
method: "send",
|
|
101
131
|
params: {
|
|
102
132
|
to: params.to,
|
|
@@ -109,10 +139,6 @@ export async function sendMessage(params) {
|
|
|
109
139
|
sessionKey: params.mirror?.sessionKey,
|
|
110
140
|
idempotencyKey: params.idempotencyKey ?? randomIdempotencyKey(),
|
|
111
141
|
},
|
|
112
|
-
timeoutMs: gateway.timeoutMs,
|
|
113
|
-
clientName: gateway.clientName,
|
|
114
|
-
clientDisplayName: gateway.clientDisplayName,
|
|
115
|
-
mode: gateway.mode,
|
|
116
142
|
});
|
|
117
143
|
return {
|
|
118
144
|
channel,
|
|
@@ -125,19 +151,15 @@ export async function sendMessage(params) {
|
|
|
125
151
|
}
|
|
126
152
|
export async function sendPoll(params) {
|
|
127
153
|
const cfg = params.cfg ?? loadConfig();
|
|
128
|
-
const channel = params.channel
|
|
129
|
-
? normalizeChannelId(params.channel)
|
|
130
|
-
: (await resolveMessageChannelSelection({ cfg })).channel;
|
|
131
|
-
if (!channel) {
|
|
132
|
-
throw new Error(`Unknown channel: ${params.channel}`);
|
|
133
|
-
}
|
|
154
|
+
const channel = await resolveRequiredChannel({ cfg, channel: params.channel });
|
|
134
155
|
const pollInput = {
|
|
135
156
|
question: params.question,
|
|
136
157
|
options: params.options,
|
|
137
158
|
maxSelections: params.maxSelections,
|
|
159
|
+
durationSeconds: params.durationSeconds,
|
|
138
160
|
durationHours: params.durationHours,
|
|
139
161
|
};
|
|
140
|
-
const plugin =
|
|
162
|
+
const plugin = resolveRequiredPlugin(channel);
|
|
141
163
|
const outbound = plugin?.outbound;
|
|
142
164
|
if (!outbound?.sendPoll) {
|
|
143
165
|
throw new Error(`Unsupported poll channel: ${channel}`);
|
|
@@ -152,29 +174,29 @@ export async function sendPoll(params) {
|
|
|
152
174
|
question: normalized.question,
|
|
153
175
|
options: normalized.options,
|
|
154
176
|
maxSelections: normalized.maxSelections,
|
|
177
|
+
durationSeconds: normalized.durationSeconds ?? null,
|
|
155
178
|
durationHours: normalized.durationHours ?? null,
|
|
156
179
|
via: "gateway",
|
|
157
180
|
dryRun: true,
|
|
158
181
|
};
|
|
159
182
|
}
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
url: gateway.url,
|
|
163
|
-
token: gateway.token,
|
|
183
|
+
const result = await callMessageGateway({
|
|
184
|
+
gateway: params.gateway,
|
|
164
185
|
method: "poll",
|
|
165
186
|
params: {
|
|
166
187
|
to: params.to,
|
|
167
188
|
question: normalized.question,
|
|
168
189
|
options: normalized.options,
|
|
169
190
|
maxSelections: normalized.maxSelections,
|
|
191
|
+
durationSeconds: normalized.durationSeconds,
|
|
170
192
|
durationHours: normalized.durationHours,
|
|
193
|
+
threadId: params.threadId,
|
|
194
|
+
silent: params.silent,
|
|
195
|
+
isAnonymous: params.isAnonymous,
|
|
171
196
|
channel,
|
|
197
|
+
accountId: params.accountId,
|
|
172
198
|
idempotencyKey: params.idempotencyKey ?? randomIdempotencyKey(),
|
|
173
199
|
},
|
|
174
|
-
timeoutMs: gateway.timeoutMs,
|
|
175
|
-
clientName: gateway.clientName,
|
|
176
|
-
clientDisplayName: gateway.clientDisplayName,
|
|
177
|
-
mode: gateway.mode,
|
|
178
200
|
});
|
|
179
201
|
return {
|
|
180
202
|
channel,
|
|
@@ -182,6 +204,7 @@ export async function sendPoll(params) {
|
|
|
182
204
|
question: normalized.question,
|
|
183
205
|
options: normalized.options,
|
|
184
206
|
maxSelections: normalized.maxSelections,
|
|
207
|
+
durationSeconds: normalized.durationSeconds ?? null,
|
|
185
208
|
durationHours: normalized.durationHours ?? null,
|
|
186
209
|
via: "gateway",
|
|
187
210
|
result,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { getChannelMessageAdapter, } from "./channel-adapters.js";
|
|
1
2
|
import { normalizeTargetForProvider } from "./target-normalization.js";
|
|
2
|
-
import { getChannelMessageAdapter } from "./channel-adapters.js";
|
|
3
3
|
import { formatTargetDisplay, lookupDirectoryDisplay } from "./target-resolver.js";
|
|
4
4
|
const CONTEXT_GUARDED_ACTIONS = new Set([
|
|
5
5
|
"send",
|
|
@@ -21,42 +21,52 @@ const CONTEXT_MARKER_ACTIONS = new Set([
|
|
|
21
21
|
"sticker",
|
|
22
22
|
]);
|
|
23
23
|
function resolveContextGuardTarget(action, params) {
|
|
24
|
-
if (!CONTEXT_GUARDED_ACTIONS.has(action))
|
|
24
|
+
if (!CONTEXT_GUARDED_ACTIONS.has(action)) {
|
|
25
25
|
return undefined;
|
|
26
|
+
}
|
|
26
27
|
if (action === "thread-reply" || action === "thread-create") {
|
|
27
|
-
if (typeof params.channelId === "string")
|
|
28
|
+
if (typeof params.channelId === "string") {
|
|
28
29
|
return params.channelId;
|
|
29
|
-
|
|
30
|
+
}
|
|
31
|
+
if (typeof params.to === "string") {
|
|
30
32
|
return params.to;
|
|
33
|
+
}
|
|
31
34
|
return undefined;
|
|
32
35
|
}
|
|
33
|
-
if (typeof params.to === "string")
|
|
36
|
+
if (typeof params.to === "string") {
|
|
34
37
|
return params.to;
|
|
35
|
-
|
|
38
|
+
}
|
|
39
|
+
if (typeof params.channelId === "string") {
|
|
36
40
|
return params.channelId;
|
|
41
|
+
}
|
|
37
42
|
return undefined;
|
|
38
43
|
}
|
|
39
44
|
function normalizeTarget(channel, raw) {
|
|
40
|
-
return normalizeTargetForProvider(channel, raw) ?? raw.trim()
|
|
45
|
+
return normalizeTargetForProvider(channel, raw) ?? raw.trim();
|
|
41
46
|
}
|
|
42
47
|
function isCrossContextTarget(params) {
|
|
43
48
|
const currentTarget = params.toolContext?.currentChannelId?.trim();
|
|
44
|
-
if (!currentTarget)
|
|
49
|
+
if (!currentTarget) {
|
|
45
50
|
return false;
|
|
51
|
+
}
|
|
46
52
|
const normalizedTarget = normalizeTarget(params.channel, params.target);
|
|
47
53
|
const normalizedCurrent = normalizeTarget(params.channel, currentTarget);
|
|
48
|
-
if (!normalizedTarget || !normalizedCurrent)
|
|
54
|
+
if (!normalizedTarget || !normalizedCurrent) {
|
|
49
55
|
return false;
|
|
56
|
+
}
|
|
50
57
|
return normalizedTarget !== normalizedCurrent;
|
|
51
58
|
}
|
|
52
59
|
export function enforceCrossContextPolicy(params) {
|
|
53
60
|
const currentTarget = params.toolContext?.currentChannelId?.trim();
|
|
54
|
-
if (!currentTarget)
|
|
61
|
+
if (!currentTarget) {
|
|
55
62
|
return;
|
|
56
|
-
|
|
63
|
+
}
|
|
64
|
+
if (!CONTEXT_GUARDED_ACTIONS.has(params.action)) {
|
|
57
65
|
return;
|
|
58
|
-
|
|
66
|
+
}
|
|
67
|
+
if (params.cfg.tools?.message?.allowCrossContextSend) {
|
|
59
68
|
return;
|
|
69
|
+
}
|
|
60
70
|
const currentProvider = params.toolContext?.currentChannelProvider;
|
|
61
71
|
const allowWithinProvider = params.cfg.tools?.message?.crossContext?.allowWithinProvider !== false;
|
|
62
72
|
const allowAcrossProviders = params.cfg.tools?.message?.crossContext?.allowAcrossProviders === true;
|
|
@@ -66,27 +76,33 @@ export function enforceCrossContextPolicy(params) {
|
|
|
66
76
|
}
|
|
67
77
|
return;
|
|
68
78
|
}
|
|
69
|
-
if (allowWithinProvider)
|
|
79
|
+
if (allowWithinProvider) {
|
|
70
80
|
return;
|
|
81
|
+
}
|
|
71
82
|
const target = resolveContextGuardTarget(params.action, params.args);
|
|
72
|
-
if (!target)
|
|
83
|
+
if (!target) {
|
|
73
84
|
return;
|
|
85
|
+
}
|
|
74
86
|
if (!isCrossContextTarget({ channel: params.channel, target, toolContext: params.toolContext })) {
|
|
75
87
|
return;
|
|
76
88
|
}
|
|
77
89
|
throw new Error(`Cross-context messaging denied: action=${params.action} target="${target}" while bound to "${currentTarget}" (channel=${params.channel}).`);
|
|
78
90
|
}
|
|
79
91
|
export async function buildCrossContextDecoration(params) {
|
|
80
|
-
if (!params.toolContext?.currentChannelId)
|
|
92
|
+
if (!params.toolContext?.currentChannelId) {
|
|
81
93
|
return null;
|
|
94
|
+
}
|
|
82
95
|
// Skip decoration for direct tool sends (agent composing, not forwarding)
|
|
83
|
-
if (params.toolContext.skipCrossContextDecoration)
|
|
96
|
+
if (params.toolContext.skipCrossContextDecoration) {
|
|
84
97
|
return null;
|
|
85
|
-
|
|
98
|
+
}
|
|
99
|
+
if (!isCrossContextTarget(params)) {
|
|
86
100
|
return null;
|
|
101
|
+
}
|
|
87
102
|
const markerConfig = params.cfg.tools?.message?.crossContext?.marker;
|
|
88
|
-
if (markerConfig?.enabled === false)
|
|
103
|
+
if (markerConfig?.enabled === false) {
|
|
89
104
|
return null;
|
|
105
|
+
}
|
|
90
106
|
const currentName = (await lookupDirectoryDisplay({
|
|
91
107
|
cfg: params.cfg,
|
|
92
108
|
channel: params.channel,
|
|
@@ -104,19 +120,30 @@ export async function buildCrossContextDecoration(params) {
|
|
|
104
120
|
const prefix = prefixTemplate.replaceAll("{channel}", originLabel);
|
|
105
121
|
const suffix = suffixTemplate.replaceAll("{channel}", originLabel);
|
|
106
122
|
const adapter = getChannelMessageAdapter(params.channel);
|
|
107
|
-
const
|
|
108
|
-
?
|
|
123
|
+
const componentsBuilder = adapter.supportsComponentsV2
|
|
124
|
+
? adapter.buildCrossContextComponents
|
|
125
|
+
? (message) => adapter.buildCrossContextComponents({
|
|
126
|
+
originLabel,
|
|
127
|
+
message,
|
|
128
|
+
cfg: params.cfg,
|
|
129
|
+
accountId: params.accountId ?? undefined,
|
|
130
|
+
})
|
|
131
|
+
: undefined
|
|
109
132
|
: undefined;
|
|
110
|
-
return { prefix, suffix,
|
|
133
|
+
return { prefix, suffix, componentsBuilder };
|
|
111
134
|
}
|
|
112
135
|
export function shouldApplyCrossContextMarker(action) {
|
|
113
136
|
return CONTEXT_MARKER_ACTIONS.has(action);
|
|
114
137
|
}
|
|
115
138
|
export function applyCrossContextDecoration(params) {
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
118
|
-
return {
|
|
139
|
+
const useComponents = params.preferComponents && params.decoration.componentsBuilder;
|
|
140
|
+
if (useComponents) {
|
|
141
|
+
return {
|
|
142
|
+
message: params.message,
|
|
143
|
+
componentsBuilder: params.decoration.componentsBuilder,
|
|
144
|
+
usedComponents: true,
|
|
145
|
+
};
|
|
119
146
|
}
|
|
120
147
|
const message = `${params.decoration.prefix}${params.message}${params.decoration.suffix}`;
|
|
121
|
-
return { message,
|
|
148
|
+
return { message, usedComponents: false };
|
|
122
149
|
}
|
|
@@ -1,75 +1,68 @@
|
|
|
1
1
|
import { dispatchChannelMessageAction } from "../../channels/plugins/message-actions.js";
|
|
2
2
|
import { appendAssistantMessageToSessionTranscript } from "../../config/sessions.js";
|
|
3
|
+
import { throwIfAborted } from "./abort.js";
|
|
3
4
|
import { sendMessage, sendPoll } from "./message.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
? result.content.find((block) => block &&
|
|
9
|
-
typeof block === "object" &&
|
|
10
|
-
block.type === "text" &&
|
|
11
|
-
typeof block.text === "string")
|
|
12
|
-
: undefined;
|
|
13
|
-
const text = textBlock?.text;
|
|
14
|
-
if (text) {
|
|
15
|
-
try {
|
|
16
|
-
return JSON.parse(text);
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
return text;
|
|
20
|
-
}
|
|
5
|
+
import { extractToolPayload } from "./tool-payload.js";
|
|
6
|
+
async function tryHandleWithPluginAction(params) {
|
|
7
|
+
if (params.ctx.dryRun) {
|
|
8
|
+
return null;
|
|
21
9
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
const handled = await dispatchChannelMessageAction({
|
|
11
|
+
channel: params.ctx.channel,
|
|
12
|
+
action: params.action,
|
|
13
|
+
cfg: params.ctx.cfg,
|
|
14
|
+
params: params.ctx.params,
|
|
15
|
+
accountId: params.ctx.accountId ?? undefined,
|
|
16
|
+
gateway: params.ctx.gateway,
|
|
17
|
+
toolContext: params.ctx.toolContext,
|
|
18
|
+
dryRun: params.ctx.dryRun,
|
|
19
|
+
});
|
|
20
|
+
if (!handled) {
|
|
21
|
+
return null;
|
|
29
22
|
}
|
|
23
|
+
await params.onHandled?.();
|
|
24
|
+
return {
|
|
25
|
+
handledBy: "plugin",
|
|
26
|
+
payload: extractToolPayload(handled),
|
|
27
|
+
toolResult: handled,
|
|
28
|
+
};
|
|
30
29
|
}
|
|
31
30
|
export async function executeSendAction(params) {
|
|
32
31
|
throwIfAborted(params.ctx.abortSignal);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
accountId: params.ctx.accountId ?? undefined,
|
|
40
|
-
gateway: params.ctx.gateway,
|
|
41
|
-
toolContext: params.ctx.toolContext,
|
|
42
|
-
dryRun: params.ctx.dryRun,
|
|
43
|
-
});
|
|
44
|
-
if (handled) {
|
|
45
|
-
if (params.ctx.mirror) {
|
|
46
|
-
const mirrorText = params.ctx.mirror.text ?? params.message;
|
|
47
|
-
const mirrorMediaUrls = params.ctx.mirror.mediaUrls ??
|
|
48
|
-
params.mediaUrls ??
|
|
49
|
-
(params.mediaUrl ? [params.mediaUrl] : undefined);
|
|
50
|
-
await appendAssistantMessageToSessionTranscript({
|
|
51
|
-
agentId: params.ctx.mirror.agentId,
|
|
52
|
-
sessionKey: params.ctx.mirror.sessionKey,
|
|
53
|
-
text: mirrorText,
|
|
54
|
-
mediaUrls: mirrorMediaUrls,
|
|
55
|
-
});
|
|
32
|
+
const pluginHandled = await tryHandleWithPluginAction({
|
|
33
|
+
ctx: params.ctx,
|
|
34
|
+
action: "send",
|
|
35
|
+
onHandled: async () => {
|
|
36
|
+
if (!params.ctx.mirror) {
|
|
37
|
+
return;
|
|
56
38
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
39
|
+
const mirrorText = params.ctx.mirror.text ?? params.message;
|
|
40
|
+
const mirrorMediaUrls = params.ctx.mirror.mediaUrls ??
|
|
41
|
+
params.mediaUrls ??
|
|
42
|
+
(params.mediaUrl ? [params.mediaUrl] : undefined);
|
|
43
|
+
await appendAssistantMessageToSessionTranscript({
|
|
44
|
+
agentId: params.ctx.mirror.agentId,
|
|
45
|
+
sessionKey: params.ctx.mirror.sessionKey,
|
|
46
|
+
text: mirrorText,
|
|
47
|
+
mediaUrls: mirrorMediaUrls,
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
if (pluginHandled) {
|
|
52
|
+
return pluginHandled;
|
|
63
53
|
}
|
|
64
54
|
throwIfAborted(params.ctx.abortSignal);
|
|
65
55
|
const result = await sendMessage({
|
|
66
56
|
cfg: params.ctx.cfg,
|
|
67
57
|
to: params.to,
|
|
68
58
|
content: params.message,
|
|
59
|
+
agentId: params.ctx.agentId,
|
|
69
60
|
mediaUrl: params.mediaUrl || undefined,
|
|
70
61
|
mediaUrls: params.mediaUrls,
|
|
71
62
|
channel: params.ctx.channel || undefined,
|
|
72
63
|
accountId: params.ctx.accountId ?? undefined,
|
|
64
|
+
replyToId: params.replyToId,
|
|
65
|
+
threadId: params.threadId,
|
|
73
66
|
gifPlayback: params.gifPlayback,
|
|
74
67
|
dryRun: params.ctx.dryRun,
|
|
75
68
|
bestEffort: params.bestEffort ?? undefined,
|
|
@@ -77,6 +70,7 @@ export async function executeSendAction(params) {
|
|
|
77
70
|
gateway: params.ctx.gateway,
|
|
78
71
|
mirror: params.ctx.mirror,
|
|
79
72
|
abortSignal: params.ctx.abortSignal,
|
|
73
|
+
silent: params.ctx.silent,
|
|
80
74
|
});
|
|
81
75
|
return {
|
|
82
76
|
handledBy: "core",
|
|
@@ -85,24 +79,12 @@ export async function executeSendAction(params) {
|
|
|
85
79
|
};
|
|
86
80
|
}
|
|
87
81
|
export async function executePollAction(params) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
accountId: params.ctx.accountId ?? undefined,
|
|
95
|
-
gateway: params.ctx.gateway,
|
|
96
|
-
toolContext: params.ctx.toolContext,
|
|
97
|
-
dryRun: params.ctx.dryRun,
|
|
98
|
-
});
|
|
99
|
-
if (handled) {
|
|
100
|
-
return {
|
|
101
|
-
handledBy: "plugin",
|
|
102
|
-
payload: extractToolPayload(handled),
|
|
103
|
-
toolResult: handled,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
82
|
+
const pluginHandled = await tryHandleWithPluginAction({
|
|
83
|
+
ctx: params.ctx,
|
|
84
|
+
action: "poll",
|
|
85
|
+
});
|
|
86
|
+
if (pluginHandled) {
|
|
87
|
+
return pluginHandled;
|
|
106
88
|
}
|
|
107
89
|
const result = await sendPoll({
|
|
108
90
|
cfg: params.ctx.cfg,
|
|
@@ -110,8 +92,13 @@ export async function executePollAction(params) {
|
|
|
110
92
|
question: params.question,
|
|
111
93
|
options: params.options,
|
|
112
94
|
maxSelections: params.maxSelections,
|
|
95
|
+
durationSeconds: params.durationSeconds ?? undefined,
|
|
113
96
|
durationHours: params.durationHours ?? undefined,
|
|
114
97
|
channel: params.ctx.channel,
|
|
98
|
+
accountId: params.ctx.accountId ?? undefined,
|
|
99
|
+
threadId: params.threadId ?? undefined,
|
|
100
|
+
silent: params.ctx.silent ?? undefined,
|
|
101
|
+
isAnonymous: params.isAnonymous ?? undefined,
|
|
115
102
|
dryRun: params.ctx.dryRun,
|
|
116
103
|
gateway: params.ctx.gateway,
|
|
117
104
|
});
|
|
@@ -17,3 +17,13 @@ export function pruneExpiredPending(pendingById, nowMs, ttlMs) {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
+
export async function upsertPendingPairingRequest(params) {
|
|
21
|
+
const existing = Object.values(params.pendingById).find(params.isExisting);
|
|
22
|
+
if (existing) {
|
|
23
|
+
return { status: "pending", request: existing, created: false };
|
|
24
|
+
}
|
|
25
|
+
const request = params.createRequest(params.isRepair);
|
|
26
|
+
params.pendingById[request.requestId] = request;
|
|
27
|
+
await params.persist();
|
|
28
|
+
return { status: "pending", request, created: true };
|
|
29
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strict plain-object guard (excludes arrays and host objects).
|
|
3
|
+
*/
|
|
4
|
+
export function isPlainObject(value) {
|
|
5
|
+
return (typeof value === "object" &&
|
|
6
|
+
value !== null &&
|
|
7
|
+
!Array.isArray(value) &&
|
|
8
|
+
Object.prototype.toString.call(value) === "[object Object]");
|
|
9
|
+
}
|