@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,18 +1,19 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
-
import { listChannelMessageActions, supportsChannelMessageButtons, supportsChannelMessageCards, } from "../../channels/plugins/message-actions.js";
|
|
3
|
-
import { CHANNEL_MESSAGE_ACTION_NAMES, } from "../../channels/plugins/types.js";
|
|
4
2
|
import { BLUEBUBBLES_GROUP_ACTIONS } from "../../channels/plugins/bluebubbles-actions.js";
|
|
3
|
+
import { listChannelMessageActions, supportsChannelMessageButtons, supportsChannelMessageButtonsForChannel, supportsChannelMessageCards, supportsChannelMessageCardsForChannel, } from "../../channels/plugins/message-actions.js";
|
|
4
|
+
import { CHANNEL_MESSAGE_ACTION_NAMES, } from "../../channels/plugins/types.js";
|
|
5
5
|
import { loadConfig } from "../../config/config.js";
|
|
6
6
|
import { GATEWAY_CLIENT_IDS, GATEWAY_CLIENT_MODES } from "../../gateway/protocol/client-info.js";
|
|
7
|
-
import { normalizeTargetForProvider } from "../../infra/outbound/target-normalization.js";
|
|
8
7
|
import { getToolResult, runMessageAction } from "../../infra/outbound/message-action-runner.js";
|
|
9
|
-
import {
|
|
8
|
+
import { normalizeTargetForProvider } from "../../infra/outbound/target-normalization.js";
|
|
10
9
|
import { normalizeAccountId } from "../../routing/session-key.js";
|
|
11
|
-
import { channelTargetSchema, channelTargetsSchema, stringEnum } from "../schema/typebox.js";
|
|
12
|
-
import { listChannelSupportedActions } from "../channel-tools.js";
|
|
13
|
-
import { normalizeMessageChannel } from "../../utils/message-channel.js";
|
|
14
10
|
import { stripReasoningTagsFromText } from "../../shared/text/reasoning-tags.js";
|
|
11
|
+
import { normalizeMessageChannel } from "../../utils/message-channel.js";
|
|
12
|
+
import { resolveSessionAgentId } from "../agent-scope.js";
|
|
13
|
+
import { listChannelSupportedActions } from "../channel-tools.js";
|
|
14
|
+
import { channelTargetSchema, channelTargetsSchema, stringEnum } from "../schema/typebox.js";
|
|
15
15
|
import { jsonResult, readNumberParam, readStringParam } from "./common.js";
|
|
16
|
+
import { resolveGatewayOptions } from "./gateway.js";
|
|
16
17
|
const AllMessageActions = CHANNEL_MESSAGE_ACTION_NAMES;
|
|
17
18
|
const EXPLICIT_TARGET_ACTIONS = new Set([
|
|
18
19
|
"send",
|
|
@@ -34,6 +35,90 @@ function buildRoutingSchema() {
|
|
|
34
35
|
dryRun: Type.Optional(Type.Boolean()),
|
|
35
36
|
};
|
|
36
37
|
}
|
|
38
|
+
const discordComponentEmojiSchema = Type.Object({
|
|
39
|
+
name: Type.String(),
|
|
40
|
+
id: Type.Optional(Type.String()),
|
|
41
|
+
animated: Type.Optional(Type.Boolean()),
|
|
42
|
+
});
|
|
43
|
+
const discordComponentOptionSchema = Type.Object({
|
|
44
|
+
label: Type.String(),
|
|
45
|
+
value: Type.String(),
|
|
46
|
+
description: Type.Optional(Type.String()),
|
|
47
|
+
emoji: Type.Optional(discordComponentEmojiSchema),
|
|
48
|
+
default: Type.Optional(Type.Boolean()),
|
|
49
|
+
});
|
|
50
|
+
const discordComponentButtonSchema = Type.Object({
|
|
51
|
+
label: Type.String(),
|
|
52
|
+
style: Type.Optional(stringEnum(["primary", "secondary", "success", "danger", "link"])),
|
|
53
|
+
url: Type.Optional(Type.String()),
|
|
54
|
+
emoji: Type.Optional(discordComponentEmojiSchema),
|
|
55
|
+
disabled: Type.Optional(Type.Boolean()),
|
|
56
|
+
allowedUsers: Type.Optional(Type.Array(Type.String({
|
|
57
|
+
description: "Discord user ids or names allowed to interact with this button.",
|
|
58
|
+
}))),
|
|
59
|
+
});
|
|
60
|
+
const discordComponentSelectSchema = Type.Object({
|
|
61
|
+
type: Type.Optional(stringEnum(["string", "user", "role", "mentionable", "channel"])),
|
|
62
|
+
placeholder: Type.Optional(Type.String()),
|
|
63
|
+
minValues: Type.Optional(Type.Number()),
|
|
64
|
+
maxValues: Type.Optional(Type.Number()),
|
|
65
|
+
options: Type.Optional(Type.Array(discordComponentOptionSchema)),
|
|
66
|
+
});
|
|
67
|
+
const discordComponentBlockSchema = Type.Object({
|
|
68
|
+
type: Type.String(),
|
|
69
|
+
text: Type.Optional(Type.String()),
|
|
70
|
+
texts: Type.Optional(Type.Array(Type.String())),
|
|
71
|
+
accessory: Type.Optional(Type.Object({
|
|
72
|
+
type: Type.String(),
|
|
73
|
+
url: Type.Optional(Type.String()),
|
|
74
|
+
button: Type.Optional(discordComponentButtonSchema),
|
|
75
|
+
})),
|
|
76
|
+
spacing: Type.Optional(stringEnum(["small", "large"])),
|
|
77
|
+
divider: Type.Optional(Type.Boolean()),
|
|
78
|
+
buttons: Type.Optional(Type.Array(discordComponentButtonSchema)),
|
|
79
|
+
select: Type.Optional(discordComponentSelectSchema),
|
|
80
|
+
items: Type.Optional(Type.Array(Type.Object({
|
|
81
|
+
url: Type.String(),
|
|
82
|
+
description: Type.Optional(Type.String()),
|
|
83
|
+
spoiler: Type.Optional(Type.Boolean()),
|
|
84
|
+
}))),
|
|
85
|
+
file: Type.Optional(Type.String()),
|
|
86
|
+
spoiler: Type.Optional(Type.Boolean()),
|
|
87
|
+
});
|
|
88
|
+
const discordComponentModalFieldSchema = Type.Object({
|
|
89
|
+
type: Type.String(),
|
|
90
|
+
name: Type.Optional(Type.String()),
|
|
91
|
+
label: Type.String(),
|
|
92
|
+
description: Type.Optional(Type.String()),
|
|
93
|
+
placeholder: Type.Optional(Type.String()),
|
|
94
|
+
required: Type.Optional(Type.Boolean()),
|
|
95
|
+
options: Type.Optional(Type.Array(discordComponentOptionSchema)),
|
|
96
|
+
minValues: Type.Optional(Type.Number()),
|
|
97
|
+
maxValues: Type.Optional(Type.Number()),
|
|
98
|
+
minLength: Type.Optional(Type.Number()),
|
|
99
|
+
maxLength: Type.Optional(Type.Number()),
|
|
100
|
+
style: Type.Optional(stringEnum(["short", "paragraph"])),
|
|
101
|
+
});
|
|
102
|
+
const discordComponentModalSchema = Type.Object({
|
|
103
|
+
title: Type.String(),
|
|
104
|
+
triggerLabel: Type.Optional(Type.String()),
|
|
105
|
+
triggerStyle: Type.Optional(stringEnum(["primary", "secondary", "success", "danger", "link"])),
|
|
106
|
+
fields: Type.Array(discordComponentModalFieldSchema),
|
|
107
|
+
});
|
|
108
|
+
const discordComponentMessageSchema = Type.Object({
|
|
109
|
+
text: Type.Optional(Type.String()),
|
|
110
|
+
reusable: Type.Optional(Type.Boolean({
|
|
111
|
+
description: "Allow components to be used multiple times until they expire.",
|
|
112
|
+
})),
|
|
113
|
+
container: Type.Optional(Type.Object({
|
|
114
|
+
accentColor: Type.Optional(Type.String()),
|
|
115
|
+
spoiler: Type.Optional(Type.Boolean()),
|
|
116
|
+
})),
|
|
117
|
+
blocks: Type.Optional(Type.Array(discordComponentBlockSchema)),
|
|
118
|
+
modal: Type.Optional(discordComponentModalSchema),
|
|
119
|
+
}, {
|
|
120
|
+
description: "Discord components v2 payload. Set reusable=true to keep buttons, selects, and forms active until expiry.",
|
|
121
|
+
});
|
|
37
122
|
function buildSendSchema(options) {
|
|
38
123
|
const props = {
|
|
39
124
|
message: Type.Optional(Type.String()),
|
|
@@ -57,12 +142,13 @@ function buildSendSchema(options) {
|
|
|
57
142
|
threadId: Type.Optional(Type.String()),
|
|
58
143
|
asVoice: Type.Optional(Type.Boolean()),
|
|
59
144
|
silent: Type.Optional(Type.Boolean()),
|
|
145
|
+
quoteText: Type.Optional(Type.String({ description: "Quote text for Telegram reply_parameters" })),
|
|
60
146
|
bestEffort: Type.Optional(Type.Boolean()),
|
|
61
147
|
gifPlayback: Type.Optional(Type.Boolean()),
|
|
62
|
-
quoteText: Type.Optional(Type.String({ description: "Quote text for Telegram reply_parameters" })),
|
|
63
148
|
buttons: Type.Optional(Type.Array(Type.Array(Type.Object({
|
|
64
149
|
text: Type.String(),
|
|
65
150
|
callback_data: Type.String(),
|
|
151
|
+
style: Type.Optional(stringEnum(["danger", "success", "primary"])),
|
|
66
152
|
})), {
|
|
67
153
|
description: "Telegram inline keyboard buttons (array of button rows)",
|
|
68
154
|
})),
|
|
@@ -70,11 +156,17 @@ function buildSendSchema(options) {
|
|
|
70
156
|
additionalProperties: true,
|
|
71
157
|
description: "Adaptive Card JSON object (when supported by the channel)",
|
|
72
158
|
})),
|
|
159
|
+
components: Type.Optional(discordComponentMessageSchema),
|
|
73
160
|
};
|
|
74
|
-
if (!options.includeButtons)
|
|
161
|
+
if (!options.includeButtons) {
|
|
75
162
|
delete props.buttons;
|
|
76
|
-
|
|
163
|
+
}
|
|
164
|
+
if (!options.includeCards) {
|
|
77
165
|
delete props.card;
|
|
166
|
+
}
|
|
167
|
+
if (!options.includeComponents) {
|
|
168
|
+
delete props.components;
|
|
169
|
+
}
|
|
78
170
|
return props;
|
|
79
171
|
}
|
|
80
172
|
function buildReactionSchema() {
|
|
@@ -159,21 +251,6 @@ function buildGatewaySchema() {
|
|
|
159
251
|
timeoutMs: Type.Optional(Type.Number()),
|
|
160
252
|
};
|
|
161
253
|
}
|
|
162
|
-
function buildChannelManagementSchema() {
|
|
163
|
-
return {
|
|
164
|
-
name: Type.Optional(Type.String()),
|
|
165
|
-
type: Type.Optional(Type.Number()),
|
|
166
|
-
parentId: Type.Optional(Type.String()),
|
|
167
|
-
topic: Type.Optional(Type.String()),
|
|
168
|
-
position: Type.Optional(Type.Number()),
|
|
169
|
-
nsfw: Type.Optional(Type.Boolean()),
|
|
170
|
-
rateLimitPerUser: Type.Optional(Type.Number()),
|
|
171
|
-
categoryId: Type.Optional(Type.String()),
|
|
172
|
-
clearParent: Type.Optional(Type.Boolean({
|
|
173
|
-
description: "Clear the parent/category when supported by the provider.",
|
|
174
|
-
})),
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
254
|
function buildPresenceSchema() {
|
|
178
255
|
return {
|
|
179
256
|
activityType: Type.Optional(Type.String({
|
|
@@ -191,6 +268,21 @@ function buildPresenceSchema() {
|
|
|
191
268
|
status: Type.Optional(Type.String({ description: "Bot status: online, dnd, idle, invisible." })),
|
|
192
269
|
};
|
|
193
270
|
}
|
|
271
|
+
function buildChannelManagementSchema() {
|
|
272
|
+
return {
|
|
273
|
+
name: Type.Optional(Type.String()),
|
|
274
|
+
type: Type.Optional(Type.Number()),
|
|
275
|
+
parentId: Type.Optional(Type.String()),
|
|
276
|
+
topic: Type.Optional(Type.String()),
|
|
277
|
+
position: Type.Optional(Type.Number()),
|
|
278
|
+
nsfw: Type.Optional(Type.Boolean()),
|
|
279
|
+
rateLimitPerUser: Type.Optional(Type.Number()),
|
|
280
|
+
categoryId: Type.Optional(Type.String()),
|
|
281
|
+
clearParent: Type.Optional(Type.Boolean({
|
|
282
|
+
description: "Clear the parent/category when supported by the provider.",
|
|
283
|
+
})),
|
|
284
|
+
};
|
|
285
|
+
}
|
|
194
286
|
function buildMessageToolSchemaProps(options) {
|
|
195
287
|
return {
|
|
196
288
|
...buildRoutingSchema(),
|
|
@@ -218,37 +310,74 @@ function buildMessageToolSchemaFromActions(actions, options) {
|
|
|
218
310
|
const MessageToolSchema = buildMessageToolSchemaFromActions(AllMessageActions, {
|
|
219
311
|
includeButtons: true,
|
|
220
312
|
includeCards: true,
|
|
313
|
+
includeComponents: true,
|
|
221
314
|
});
|
|
222
|
-
function
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
315
|
+
function resolveMessageToolSchemaActions(params) {
|
|
316
|
+
const currentChannel = normalizeMessageChannel(params.currentChannelProvider);
|
|
317
|
+
if (currentChannel) {
|
|
318
|
+
const scopedActions = filterActionsForContext({
|
|
319
|
+
actions: listChannelSupportedActions({
|
|
320
|
+
cfg: params.cfg,
|
|
321
|
+
channel: currentChannel,
|
|
322
|
+
}),
|
|
323
|
+
channel: currentChannel,
|
|
324
|
+
currentChannelId: params.currentChannelId,
|
|
325
|
+
});
|
|
326
|
+
const withSend = new Set(["send", ...scopedActions]);
|
|
327
|
+
return Array.from(withSend);
|
|
328
|
+
}
|
|
329
|
+
const actions = listChannelMessageActions(params.cfg);
|
|
330
|
+
return actions.length > 0 ? actions : ["send"];
|
|
331
|
+
}
|
|
332
|
+
function resolveIncludeComponents(params) {
|
|
333
|
+
const currentChannel = normalizeMessageChannel(params.currentChannelProvider);
|
|
334
|
+
if (currentChannel) {
|
|
335
|
+
return currentChannel === "discord";
|
|
336
|
+
}
|
|
337
|
+
// Components are currently Discord-specific.
|
|
338
|
+
return listChannelSupportedActions({ cfg: params.cfg, channel: "discord" }).length > 0;
|
|
339
|
+
}
|
|
340
|
+
function buildMessageToolSchema(params) {
|
|
341
|
+
const currentChannel = normalizeMessageChannel(params.currentChannelProvider);
|
|
342
|
+
const actions = resolveMessageToolSchemaActions(params);
|
|
343
|
+
const includeButtons = currentChannel
|
|
344
|
+
? supportsChannelMessageButtonsForChannel({ cfg: params.cfg, channel: currentChannel })
|
|
345
|
+
: supportsChannelMessageButtons(params.cfg);
|
|
346
|
+
const includeCards = currentChannel
|
|
347
|
+
? supportsChannelMessageCardsForChannel({ cfg: params.cfg, channel: currentChannel })
|
|
348
|
+
: supportsChannelMessageCards(params.cfg);
|
|
349
|
+
const includeComponents = resolveIncludeComponents(params);
|
|
226
350
|
return buildMessageToolSchemaFromActions(actions.length > 0 ? actions : ["send"], {
|
|
227
351
|
includeButtons,
|
|
228
352
|
includeCards,
|
|
353
|
+
includeComponents,
|
|
229
354
|
});
|
|
230
355
|
}
|
|
231
356
|
function resolveAgentAccountId(value) {
|
|
232
357
|
const trimmed = value?.trim();
|
|
233
|
-
if (!trimmed)
|
|
358
|
+
if (!trimmed) {
|
|
234
359
|
return undefined;
|
|
360
|
+
}
|
|
235
361
|
return normalizeAccountId(trimmed);
|
|
236
362
|
}
|
|
237
363
|
function filterActionsForContext(params) {
|
|
238
364
|
const channel = normalizeMessageChannel(params.channel);
|
|
239
|
-
if (!channel || channel !== "bluebubbles")
|
|
365
|
+
if (!channel || channel !== "bluebubbles") {
|
|
240
366
|
return params.actions;
|
|
367
|
+
}
|
|
241
368
|
const currentChannelId = params.currentChannelId?.trim();
|
|
242
|
-
if (!currentChannelId)
|
|
369
|
+
if (!currentChannelId) {
|
|
243
370
|
return params.actions;
|
|
371
|
+
}
|
|
244
372
|
const normalizedTarget = normalizeTargetForProvider(channel, currentChannelId) ?? currentChannelId;
|
|
245
373
|
const lowered = normalizedTarget.trim().toLowerCase();
|
|
246
374
|
const isGroupTarget = lowered.startsWith("chat_guid:") ||
|
|
247
375
|
lowered.startsWith("chat_id:") ||
|
|
248
376
|
lowered.startsWith("chat_identifier:") ||
|
|
249
377
|
lowered.startsWith("group:");
|
|
250
|
-
if (isGroupTarget)
|
|
378
|
+
if (isGroupTarget) {
|
|
251
379
|
return params.actions;
|
|
380
|
+
}
|
|
252
381
|
return params.actions.filter((action) => !BLUEBUBBLES_GROUP_ACTIONS.has(action));
|
|
253
382
|
}
|
|
254
383
|
function buildMessageToolDescription(options) {
|
|
@@ -266,7 +395,7 @@ function buildMessageToolDescription(options) {
|
|
|
266
395
|
if (channelActions.length > 0) {
|
|
267
396
|
// Always include "send" as a base action
|
|
268
397
|
const allActions = new Set(["send", ...channelActions]);
|
|
269
|
-
const actionList = Array.from(allActions).
|
|
398
|
+
const actionList = Array.from(allActions).toSorted().join(", ");
|
|
270
399
|
return `${baseDescription} Current channel (${options.currentChannel}) supports: ${actionList}.`;
|
|
271
400
|
}
|
|
272
401
|
}
|
|
@@ -281,7 +410,13 @@ function buildMessageToolDescription(options) {
|
|
|
281
410
|
}
|
|
282
411
|
export function createMessageTool(options) {
|
|
283
412
|
const agentAccountId = resolveAgentAccountId(options?.agentAccountId);
|
|
284
|
-
const schema = options?.config
|
|
413
|
+
const schema = options?.config
|
|
414
|
+
? buildMessageToolSchema({
|
|
415
|
+
cfg: options.config,
|
|
416
|
+
currentChannelProvider: options.currentChannelProvider,
|
|
417
|
+
currentChannelId: options.currentChannelId,
|
|
418
|
+
})
|
|
419
|
+
: MessageToolSchema;
|
|
285
420
|
const description = buildMessageToolDescription({
|
|
286
421
|
config: options?.config,
|
|
287
422
|
currentChannel: options?.currentChannelProvider,
|
|
@@ -312,7 +447,6 @@ export function createMessageTool(options) {
|
|
|
312
447
|
const action = readStringParam(params, "action", {
|
|
313
448
|
required: true,
|
|
314
449
|
});
|
|
315
|
-
// Enforce explicit target when required (e.g. cron/hook-initiated runs).
|
|
316
450
|
const requireExplicitTarget = options?.requireExplicitTarget === true;
|
|
317
451
|
if (requireExplicitTarget && actionNeedsExplicitTarget(action)) {
|
|
318
452
|
const explicitTarget = (typeof params.target === "string" && params.target.trim().length > 0) ||
|
|
@@ -328,10 +462,15 @@ export function createMessageTool(options) {
|
|
|
328
462
|
if (accountId) {
|
|
329
463
|
params.accountId = accountId;
|
|
330
464
|
}
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
465
|
+
const gatewayResolved = resolveGatewayOptions({
|
|
466
|
+
gatewayUrl: readStringParam(params, "gatewayUrl", { trim: false }),
|
|
467
|
+
gatewayToken: readStringParam(params, "gatewayToken", { trim: false }),
|
|
334
468
|
timeoutMs: readNumberParam(params, "timeoutMs"),
|
|
469
|
+
});
|
|
470
|
+
const gateway = {
|
|
471
|
+
url: gatewayResolved.url,
|
|
472
|
+
token: gatewayResolved.token,
|
|
473
|
+
timeoutMs: gatewayResolved.timeoutMs,
|
|
335
474
|
clientName: GATEWAY_CLIENT_IDS.GATEWAY_CLIENT,
|
|
336
475
|
clientDisplayName: "agent",
|
|
337
476
|
mode: GATEWAY_CLIENT_MODES.BACKEND,
|
|
@@ -359,6 +498,7 @@ export function createMessageTool(options) {
|
|
|
359
498
|
defaultAccountId: accountId ?? undefined,
|
|
360
499
|
gateway,
|
|
361
500
|
toolContext,
|
|
501
|
+
sessionKey: options?.agentSessionKey,
|
|
362
502
|
agentId: options?.agentSessionKey
|
|
363
503
|
? resolveSessionAgentId({ sessionKey: options.agentSessionKey, config: cfg })
|
|
364
504
|
: undefined,
|
|
@@ -366,8 +506,9 @@ export function createMessageTool(options) {
|
|
|
366
506
|
abortSignal: signal,
|
|
367
507
|
});
|
|
368
508
|
const toolResult = getToolResult(result);
|
|
369
|
-
if (toolResult)
|
|
509
|
+
if (toolResult) {
|
|
370
510
|
return toolResult;
|
|
511
|
+
}
|
|
371
512
|
return jsonResult(result.payload);
|
|
372
513
|
},
|
|
373
514
|
};
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
|
-
import { cameraTempPath, parseCameraClipPayload, parseCameraSnapPayload, writeBase64ToFile, } from "../../cli/nodes-camera.js";
|
|
3
|
+
import { cameraTempPath, parseCameraClipPayload, parseCameraSnapPayload, writeBase64ToFile, writeUrlToFile, } from "../../cli/nodes-camera.js";
|
|
4
4
|
import { parseEnvPairs, parseTimeoutMs } from "../../cli/nodes-run.js";
|
|
5
5
|
import { parseScreenRecordPayload, screenRecordTempPath, writeScreenRecordToFile, } from "../../cli/nodes-screen.js";
|
|
6
6
|
import { parseDurationMs } from "../../cli/parse-duration.js";
|
|
7
7
|
import { imageMimeFromFormat } from "../../media/mime.js";
|
|
8
8
|
import { resolveSessionAgentId } from "../agent-scope.js";
|
|
9
|
+
import { resolveImageSanitizationLimits } from "../image-sanitization.js";
|
|
9
10
|
import { optionalStringEnum, stringEnum } from "../schema/typebox.js";
|
|
10
11
|
import { sanitizeToolResultImages } from "../tool-images.js";
|
|
11
12
|
import { jsonResult, readStringParam } from "./common.js";
|
|
12
|
-
import { callGatewayTool } from "./gateway.js";
|
|
13
|
+
import { callGatewayTool, readGatewayCallOptions } from "./gateway.js";
|
|
13
14
|
import { listNodes, resolveNodeIdFromList, resolveNodeId } from "./nodes-utils.js";
|
|
14
15
|
const NODES_TOOL_ACTIONS = [
|
|
15
16
|
"status",
|
|
@@ -24,6 +25,7 @@ const NODES_TOOL_ACTIONS = [
|
|
|
24
25
|
"screen_record",
|
|
25
26
|
"location_get",
|
|
26
27
|
"run",
|
|
28
|
+
"invoke",
|
|
27
29
|
];
|
|
28
30
|
const NOTIFY_PRIORITIES = ["passive", "active", "timeSensitive"];
|
|
29
31
|
const NOTIFY_DELIVERIES = ["system", "overlay", "auto"];
|
|
@@ -69,6 +71,9 @@ const NodesToolSchema = Type.Object({
|
|
|
69
71
|
commandTimeoutMs: Type.Optional(Type.Number()),
|
|
70
72
|
invokeTimeoutMs: Type.Optional(Type.Number()),
|
|
71
73
|
needsScreenRecording: Type.Optional(Type.Boolean()),
|
|
74
|
+
// invoke
|
|
75
|
+
invokeCommand: Type.Optional(Type.String()),
|
|
76
|
+
invokeParamsJson: Type.Optional(Type.String()),
|
|
72
77
|
});
|
|
73
78
|
export function createNodesTool(options) {
|
|
74
79
|
const sessionKey = options?.agentSessionKey?.trim() || undefined;
|
|
@@ -76,19 +81,16 @@ export function createNodesTool(options) {
|
|
|
76
81
|
sessionKey: options?.agentSessionKey,
|
|
77
82
|
config: options?.config,
|
|
78
83
|
});
|
|
84
|
+
const imageSanitization = resolveImageSanitizationLimits(options?.config);
|
|
79
85
|
return {
|
|
80
86
|
label: "Nodes",
|
|
81
87
|
name: "nodes",
|
|
82
|
-
description: "Discover and control paired nodes (status/describe/pairing/notify/camera/screen/location/run).",
|
|
88
|
+
description: "Discover and control paired nodes (status/describe/pairing/notify/camera/screen/location/run/invoke).",
|
|
83
89
|
parameters: NodesToolSchema,
|
|
84
90
|
execute: async (_toolCallId, args) => {
|
|
85
91
|
const params = args;
|
|
86
92
|
const action = readStringParam(params, "action", { required: true });
|
|
87
|
-
const gatewayOpts =
|
|
88
|
-
gatewayUrl: readStringParam(params, "gatewayUrl", { trim: false }),
|
|
89
|
-
gatewayToken: readStringParam(params, "gatewayToken", { trim: false }),
|
|
90
|
-
timeoutMs: typeof params.timeoutMs === "number" ? params.timeoutMs : undefined,
|
|
91
|
-
};
|
|
93
|
+
const gatewayOpts = readGatewayCallOptions(params);
|
|
92
94
|
try {
|
|
93
95
|
switch (action) {
|
|
94
96
|
case "status":
|
|
@@ -164,7 +166,7 @@ export function createNodesTool(options) {
|
|
|
164
166
|
const content = [];
|
|
165
167
|
const details = [];
|
|
166
168
|
for (const facing of facings) {
|
|
167
|
-
const raw =
|
|
169
|
+
const raw = await callGatewayTool("node.invoke", gatewayOpts, {
|
|
168
170
|
nodeId,
|
|
169
171
|
command: "camera.snap",
|
|
170
172
|
params: {
|
|
@@ -176,7 +178,7 @@ export function createNodesTool(options) {
|
|
|
176
178
|
deviceId,
|
|
177
179
|
},
|
|
178
180
|
idempotencyKey: crypto.randomUUID(),
|
|
179
|
-
})
|
|
181
|
+
});
|
|
180
182
|
const payload = parseCameraSnapPayload(raw?.payload);
|
|
181
183
|
const normalizedFormat = payload.format.toLowerCase();
|
|
182
184
|
if (normalizedFormat !== "jpg" &&
|
|
@@ -190,13 +192,20 @@ export function createNodesTool(options) {
|
|
|
190
192
|
facing,
|
|
191
193
|
ext: isJpeg ? "jpg" : "png",
|
|
192
194
|
});
|
|
193
|
-
|
|
195
|
+
if (payload.url) {
|
|
196
|
+
await writeUrlToFile(filePath, payload.url);
|
|
197
|
+
}
|
|
198
|
+
else if (payload.base64) {
|
|
199
|
+
await writeBase64ToFile(filePath, payload.base64);
|
|
200
|
+
}
|
|
194
201
|
content.push({ type: "text", text: `MEDIA:${filePath}` });
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
202
|
+
if (payload.base64) {
|
|
203
|
+
content.push({
|
|
204
|
+
type: "image",
|
|
205
|
+
data: payload.base64,
|
|
206
|
+
mimeType: imageMimeFromFormat(payload.format) ?? (isJpeg ? "image/jpeg" : "image/png"),
|
|
207
|
+
});
|
|
208
|
+
}
|
|
200
209
|
details.push({
|
|
201
210
|
facing,
|
|
202
211
|
path: filePath,
|
|
@@ -205,17 +214,17 @@ export function createNodesTool(options) {
|
|
|
205
214
|
});
|
|
206
215
|
}
|
|
207
216
|
const result = { content, details };
|
|
208
|
-
return await sanitizeToolResultImages(result, "nodes:camera_snap");
|
|
217
|
+
return await sanitizeToolResultImages(result, "nodes:camera_snap", imageSanitization);
|
|
209
218
|
}
|
|
210
219
|
case "camera_list": {
|
|
211
220
|
const node = readStringParam(params, "node", { required: true });
|
|
212
221
|
const nodeId = await resolveNodeId(gatewayOpts, node);
|
|
213
|
-
const raw =
|
|
222
|
+
const raw = await callGatewayTool("node.invoke", gatewayOpts, {
|
|
214
223
|
nodeId,
|
|
215
224
|
command: "camera.list",
|
|
216
225
|
params: {},
|
|
217
226
|
idempotencyKey: crypto.randomUUID(),
|
|
218
|
-
})
|
|
227
|
+
});
|
|
219
228
|
const payload = raw && typeof raw.payload === "object" && raw.payload !== null ? raw.payload : {};
|
|
220
229
|
return jsonResult(payload);
|
|
221
230
|
}
|
|
@@ -235,7 +244,7 @@ export function createNodesTool(options) {
|
|
|
235
244
|
const deviceId = typeof params.deviceId === "string" && params.deviceId.trim()
|
|
236
245
|
? params.deviceId.trim()
|
|
237
246
|
: undefined;
|
|
238
|
-
const raw =
|
|
247
|
+
const raw = await callGatewayTool("node.invoke", gatewayOpts, {
|
|
239
248
|
nodeId,
|
|
240
249
|
command: "camera.clip",
|
|
241
250
|
params: {
|
|
@@ -246,14 +255,19 @@ export function createNodesTool(options) {
|
|
|
246
255
|
deviceId,
|
|
247
256
|
},
|
|
248
257
|
idempotencyKey: crypto.randomUUID(),
|
|
249
|
-
})
|
|
258
|
+
});
|
|
250
259
|
const payload = parseCameraClipPayload(raw?.payload);
|
|
251
260
|
const filePath = cameraTempPath({
|
|
252
261
|
kind: "clip",
|
|
253
262
|
facing,
|
|
254
263
|
ext: payload.format,
|
|
255
264
|
});
|
|
256
|
-
|
|
265
|
+
if (payload.url) {
|
|
266
|
+
await writeUrlToFile(filePath, payload.url);
|
|
267
|
+
}
|
|
268
|
+
else if (payload.base64) {
|
|
269
|
+
await writeBase64ToFile(filePath, payload.base64);
|
|
270
|
+
}
|
|
257
271
|
return {
|
|
258
272
|
content: [{ type: "text", text: `FILE:${filePath}` }],
|
|
259
273
|
details: {
|
|
@@ -277,7 +291,7 @@ export function createNodesTool(options) {
|
|
|
277
291
|
? params.screenIndex
|
|
278
292
|
: 0;
|
|
279
293
|
const includeAudio = typeof params.includeAudio === "boolean" ? params.includeAudio : true;
|
|
280
|
-
const raw =
|
|
294
|
+
const raw = await callGatewayTool("node.invoke", gatewayOpts, {
|
|
281
295
|
nodeId,
|
|
282
296
|
command: "screen.record",
|
|
283
297
|
params: {
|
|
@@ -288,7 +302,7 @@ export function createNodesTool(options) {
|
|
|
288
302
|
includeAudio,
|
|
289
303
|
},
|
|
290
304
|
idempotencyKey: crypto.randomUUID(),
|
|
291
|
-
})
|
|
305
|
+
});
|
|
292
306
|
const payload = parseScreenRecordPayload(raw?.payload);
|
|
293
307
|
const filePath = typeof params.outPath === "string" && params.outPath.trim()
|
|
294
308
|
? params.outPath.trim()
|
|
@@ -320,7 +334,7 @@ export function createNodesTool(options) {
|
|
|
320
334
|
Number.isFinite(params.locationTimeoutMs)
|
|
321
335
|
? params.locationTimeoutMs
|
|
322
336
|
: undefined;
|
|
323
|
-
const raw =
|
|
337
|
+
const raw = await callGatewayTool("node.invoke", gatewayOpts, {
|
|
324
338
|
nodeId,
|
|
325
339
|
command: "location.get",
|
|
326
340
|
params: {
|
|
@@ -329,7 +343,7 @@ export function createNodesTool(options) {
|
|
|
329
343
|
timeoutMs: locationTimeoutMs,
|
|
330
344
|
},
|
|
331
345
|
idempotencyKey: crypto.randomUUID(),
|
|
332
|
-
})
|
|
346
|
+
});
|
|
333
347
|
return jsonResult(raw?.payload ?? {});
|
|
334
348
|
}
|
|
335
349
|
case "run": {
|
|
@@ -364,23 +378,101 @@ export function createNodesTool(options) {
|
|
|
364
378
|
const needsScreenRecording = typeof params.needsScreenRecording === "boolean"
|
|
365
379
|
? params.needsScreenRecording
|
|
366
380
|
: undefined;
|
|
367
|
-
const
|
|
381
|
+
const runParams = {
|
|
382
|
+
command,
|
|
383
|
+
cwd,
|
|
384
|
+
env,
|
|
385
|
+
timeoutMs: commandTimeoutMs,
|
|
386
|
+
needsScreenRecording,
|
|
387
|
+
agentId,
|
|
388
|
+
sessionKey,
|
|
389
|
+
};
|
|
390
|
+
// First attempt without approval flags.
|
|
391
|
+
try {
|
|
392
|
+
const raw = await callGatewayTool("node.invoke", gatewayOpts, {
|
|
393
|
+
nodeId,
|
|
394
|
+
command: "system.run",
|
|
395
|
+
params: runParams,
|
|
396
|
+
timeoutMs: invokeTimeoutMs,
|
|
397
|
+
idempotencyKey: crypto.randomUUID(),
|
|
398
|
+
});
|
|
399
|
+
return jsonResult(raw?.payload ?? {});
|
|
400
|
+
}
|
|
401
|
+
catch (firstErr) {
|
|
402
|
+
const msg = firstErr instanceof Error ? firstErr.message : String(firstErr);
|
|
403
|
+
if (!msg.includes("SYSTEM_RUN_DENIED: approval required")) {
|
|
404
|
+
throw firstErr;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// Node requires approval – create a pending approval request on
|
|
408
|
+
// the gateway and wait for the user to approve/deny via the UI.
|
|
409
|
+
const APPROVAL_TIMEOUT_MS = 120_000;
|
|
410
|
+
const cmdText = command.join(" ");
|
|
411
|
+
const approvalId = crypto.randomUUID();
|
|
412
|
+
const approvalResult = await callGatewayTool("exec.approval.request", { ...gatewayOpts, timeoutMs: APPROVAL_TIMEOUT_MS + 5_000 }, {
|
|
413
|
+
id: approvalId,
|
|
414
|
+
command: cmdText,
|
|
415
|
+
cwd,
|
|
416
|
+
host: "node",
|
|
417
|
+
agentId,
|
|
418
|
+
sessionKey,
|
|
419
|
+
timeoutMs: APPROVAL_TIMEOUT_MS,
|
|
420
|
+
});
|
|
421
|
+
const decisionRaw = approvalResult && typeof approvalResult === "object"
|
|
422
|
+
? approvalResult.decision
|
|
423
|
+
: undefined;
|
|
424
|
+
const approvalDecision = decisionRaw === "allow-once" || decisionRaw === "allow-always" ? decisionRaw : null;
|
|
425
|
+
if (!approvalDecision) {
|
|
426
|
+
if (decisionRaw === "deny") {
|
|
427
|
+
throw new Error("exec denied: user denied");
|
|
428
|
+
}
|
|
429
|
+
if (decisionRaw === undefined || decisionRaw === null) {
|
|
430
|
+
throw new Error("exec denied: approval timed out");
|
|
431
|
+
}
|
|
432
|
+
throw new Error("exec denied: invalid approval decision");
|
|
433
|
+
}
|
|
434
|
+
// Retry with the approval decision.
|
|
435
|
+
const raw = await callGatewayTool("node.invoke", gatewayOpts, {
|
|
368
436
|
nodeId,
|
|
369
437
|
command: "system.run",
|
|
370
438
|
params: {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
needsScreenRecording,
|
|
376
|
-
agentId,
|
|
377
|
-
sessionKey,
|
|
439
|
+
...runParams,
|
|
440
|
+
runId: approvalId,
|
|
441
|
+
approved: true,
|
|
442
|
+
approvalDecision,
|
|
378
443
|
},
|
|
379
444
|
timeoutMs: invokeTimeoutMs,
|
|
380
445
|
idempotencyKey: crypto.randomUUID(),
|
|
381
|
-
})
|
|
446
|
+
});
|
|
382
447
|
return jsonResult(raw?.payload ?? {});
|
|
383
448
|
}
|
|
449
|
+
case "invoke": {
|
|
450
|
+
const node = readStringParam(params, "node", { required: true });
|
|
451
|
+
const nodeId = await resolveNodeId(gatewayOpts, node);
|
|
452
|
+
const invokeCommand = readStringParam(params, "invokeCommand", { required: true });
|
|
453
|
+
const invokeParamsJson = typeof params.invokeParamsJson === "string" ? params.invokeParamsJson.trim() : "";
|
|
454
|
+
let invokeParams = {};
|
|
455
|
+
if (invokeParamsJson) {
|
|
456
|
+
try {
|
|
457
|
+
invokeParams = JSON.parse(invokeParamsJson);
|
|
458
|
+
}
|
|
459
|
+
catch (err) {
|
|
460
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
461
|
+
throw new Error(`invokeParamsJson must be valid JSON: ${message}`, {
|
|
462
|
+
cause: err,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
const invokeTimeoutMs = parseTimeoutMs(params.invokeTimeoutMs);
|
|
467
|
+
const raw = await callGatewayTool("node.invoke", gatewayOpts, {
|
|
468
|
+
nodeId,
|
|
469
|
+
command: invokeCommand,
|
|
470
|
+
params: invokeParams,
|
|
471
|
+
timeoutMs: invokeTimeoutMs,
|
|
472
|
+
idempotencyKey: crypto.randomUUID(),
|
|
473
|
+
});
|
|
474
|
+
return jsonResult(raw ?? {});
|
|
475
|
+
}
|
|
384
476
|
default:
|
|
385
477
|
throw new Error(`Unknown action: ${action}`);
|
|
386
478
|
}
|
|
@@ -392,7 +484,7 @@ export function createNodesTool(options) {
|
|
|
392
484
|
: "default";
|
|
393
485
|
const agentLabel = agentId ?? "unknown";
|
|
394
486
|
const message = err instanceof Error ? err.message : String(err);
|
|
395
|
-
throw new Error(`agent=${agentLabel} node=${nodeLabel} gateway=${gatewayLabel} action=${action}: ${message}
|
|
487
|
+
throw new Error(`agent=${agentLabel} node=${nodeLabel} gateway=${gatewayLabel} action=${action}: ${message}`, { cause: err });
|
|
396
488
|
}
|
|
397
489
|
},
|
|
398
490
|
};
|