@poolzin/pool-bot 2026.2.24 → 2026.2.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/acp/client.js +207 -18
- package/dist/acp/event-mapper.js +87 -22
- package/dist/acp/meta.js +12 -6
- package/dist/acp/secret-file.js +22 -0
- package/dist/agents/agent-paths.js +8 -9
- package/dist/agents/agent-scope.js +17 -5
- package/dist/agents/auth-profiles/oauth.js +148 -64
- package/dist/agents/auth-profiles/session-override.js +13 -7
- 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 +240 -0
- package/dist/agents/bash-tools.exec-host-node.js +235 -0
- package/dist/agents/bash-tools.exec-runtime.js +2 -25
- package/dist/agents/bash-tools.exec-types.js +1 -0
- package/dist/agents/bash-tools.process.js +224 -218
- package/dist/agents/bedrock-discovery.js +3 -1
- package/dist/agents/byteplus-models.js +97 -0
- package/dist/agents/chutes-oauth.js +1 -0
- package/dist/agents/cli-runner/helpers.js +4 -0
- package/dist/agents/compaction.js +41 -14
- package/dist/agents/content-blocks.js +16 -0
- package/dist/agents/doubao-models.js +121 -0
- package/dist/agents/failover-error.js +2 -0
- package/dist/agents/huggingface-models.js +5 -3
- package/dist/agents/live-model-filter.js +5 -0
- package/dist/agents/minimax-vlm.js +10 -8
- package/dist/agents/model-auth.js +6 -0
- package/dist/agents/model-catalog.js +3 -1
- package/dist/agents/model-fallback.js +96 -101
- package/dist/agents/model-selection.js +7 -1
- package/dist/agents/models-config.providers.js +364 -165
- package/dist/agents/ollama-stream.js +117 -4
- package/dist/agents/opencode-zen-models.js +22 -11
- package/dist/agents/pi-embedded-helpers/errors.js +55 -33
- package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
- package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-payloads.js +1 -0
- package/dist/agents/pi-embedded-runner/compact.js +29 -7
- package/dist/agents/pi-embedded-runner/extensions.js +28 -26
- package/dist/agents/pi-embedded-runner/google.js +20 -8
- package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
- package/dist/agents/pi-embedded-runner/run.js +71 -12
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +34 -0
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
- package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
- package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
- package/dist/agents/pi-embedded-runner/thinking.js +42 -0
- package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
- package/dist/agents/pi-embedded-runner/utils.js +7 -10
- package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
- package/dist/agents/pi-embedded-subscribe.js +9 -4
- package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
- package/dist/agents/pi-embedded-utils.js +3 -0
- package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
- package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
- package/dist/agents/pi-settings.js +40 -0
- package/dist/agents/pi-tools.policy.js +2 -1
- package/dist/agents/provider/config-loader.js +1 -1
- package/dist/agents/sandbox/browser.js +170 -33
- package/dist/agents/sandbox/config-hash.js +14 -27
- package/dist/agents/sandbox/config.js +21 -2
- package/dist/agents/sandbox/constants.js +2 -0
- package/dist/agents/sandbox/docker.js +16 -2
- package/dist/agents/sandbox/novnc-auth.js +62 -0
- package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
- package/dist/agents/sandbox/shared.js +10 -6
- package/dist/agents/sandbox-paths.js +24 -11
- package/dist/agents/schema/clean-for-gemini.js +132 -85
- package/dist/agents/session-slug.js +10 -5
- package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
- package/dist/agents/session-tool-result-guard.js +3 -1
- package/dist/agents/session-transcript-repair.js +40 -6
- package/dist/agents/skills/bundled-dir.js +19 -5
- package/dist/agents/skills/env-overrides.js +124 -43
- package/dist/agents/skills/frontmatter.js +6 -6
- package/dist/agents/skills/plugin-skills.js +14 -7
- package/dist/agents/skills/workspace.js +1 -0
- package/dist/agents/skills.test-helpers.js +13 -0
- package/dist/agents/stable-stringify.js +12 -0
- package/dist/agents/subagent-announce.js +251 -49
- package/dist/agents/subagent-lifecycle-events.js +19 -0
- package/dist/agents/subagent-registry-cleanup.js +31 -0
- package/dist/agents/subagent-registry-completion.js +68 -0
- package/dist/agents/subagent-registry-queries.js +117 -0
- package/dist/agents/subagent-registry-state.js +46 -0
- package/dist/agents/subagent-registry.js +252 -221
- package/dist/agents/subagent-registry.mocks.shared.js +12 -0
- package/dist/agents/subagent-registry.store.js +1 -0
- package/dist/agents/subagent-registry.types.js +1 -0
- package/dist/agents/subagent-spawn.js +195 -7
- package/dist/agents/system-prompt.js +22 -6
- package/dist/agents/test-helpers/assistant-message-fixtures.js +29 -0
- package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
- package/dist/agents/test-helpers/fast-core-tools.js +1 -17
- package/dist/agents/test-helpers/pi-tools-sandbox-context.js +27 -0
- package/dist/agents/timeout.js +18 -6
- package/dist/agents/tool-call-id.js +1 -1
- package/dist/agents/tool-display-common.js +162 -29
- package/dist/agents/tool-images.js +82 -9
- package/dist/agents/tool-policy-shared.js +108 -0
- package/dist/agents/tool-policy.js +51 -26
- package/dist/agents/tools/browser-tool.js +160 -54
- package/dist/agents/tools/canvas-tool.js +27 -1
- package/dist/agents/tools/common.js +45 -0
- package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
- package/dist/agents/tools/discord-actions-guild.js +4 -1
- package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
- package/dist/agents/tools/gateway-tool.js +3 -1
- package/dist/agents/tools/image-tool.js +214 -99
- package/dist/agents/tools/nodes-utils.js +1 -10
- package/dist/agents/tools/sessions-history-tool.js +140 -108
- package/dist/agents/tools/sessions-send-helpers.js +12 -6
- package/dist/agents/tools/sessions-spawn-tool.js +8 -2
- package/dist/agents/tools/subagents-tool.js +2 -1
- package/dist/agents/tools/whatsapp-actions.js +10 -2
- package/dist/agents/tools/whatsapp-target-auth.js +18 -0
- package/dist/agents/transcript-policy.js +22 -8
- package/dist/agents/venice-models.js +11 -3
- package/dist/agents/workspace.js +222 -46
- package/dist/auto-reply/commands-registry.data.js +51 -0
- package/dist/auto-reply/commands-registry.js +19 -21
- package/dist/auto-reply/fallback-state.js +114 -0
- package/dist/auto-reply/group-activation.js +10 -5
- package/dist/auto-reply/inbound-debounce.js +10 -5
- package/dist/auto-reply/model-runtime.js +68 -0
- package/dist/auto-reply/reply/abort.js +1 -1
- package/dist/auto-reply/reply/agent-runner-execution.js +40 -5
- package/dist/auto-reply/reply/agent-runner.js +165 -39
- package/dist/auto-reply/reply/bash-command.js +41 -39
- package/dist/auto-reply/reply/command-gates.js +25 -0
- package/dist/auto-reply/reply/commands-allowlist.js +111 -72
- package/dist/auto-reply/reply/commands-bash.js +6 -5
- package/dist/auto-reply/reply/commands-config.js +30 -28
- package/dist/auto-reply/reply/commands-core.js +2 -1
- package/dist/auto-reply/reply/commands-info.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +65 -14
- package/dist/auto-reply/reply/commands-session.js +237 -82
- package/dist/auto-reply/reply/commands-setunset-standard.js +13 -0
- package/dist/auto-reply/reply/commands-setunset.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
- package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
- package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
- package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
- package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
- package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
- package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
- package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
- package/dist/auto-reply/reply/commands-subagents.js +51 -587
- package/dist/auto-reply/reply/commands-tts.js +10 -5
- package/dist/auto-reply/reply/config-value.js +10 -5
- package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
- package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
- package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
- package/dist/auto-reply/reply/followup-runner.js +1 -0
- package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
- package/dist/auto-reply/reply/get-reply-directives.js +17 -28
- package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
- package/dist/auto-reply/reply/get-reply.js +71 -12
- package/dist/auto-reply/reply/model-selection.js +80 -39
- package/dist/auto-reply/reply/queue/enqueue.js +10 -5
- package/dist/auto-reply/reply/queue/state.js +13 -12
- package/dist/auto-reply/reply/reply-payloads.js +67 -36
- package/dist/auto-reply/reply/reply-reference.js +9 -8
- package/dist/auto-reply/reply/route-reply.js +15 -8
- package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
- package/dist/auto-reply/reply/session.js +22 -6
- package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
- package/dist/auto-reply/reply/subagents-utils.js +56 -30
- package/dist/auto-reply/reply/typing.js +46 -21
- package/dist/auto-reply/send-policy.js +14 -7
- package/dist/auto-reply/status.js +140 -16
- package/dist/auto-reply/templating.js +10 -5
- package/dist/auto-reply/thinking.js +7 -16
- package/dist/auto-reply/tokens.js +21 -5
- package/dist/browser/bridge-server.js +36 -20
- package/dist/browser/cdp.helpers.js +7 -14
- package/dist/browser/cdp.js +35 -15
- package/dist/browser/chrome.profile-decoration.js +7 -4
- package/dist/browser/config.js +30 -0
- package/dist/browser/extension-relay-auth.js +55 -0
- package/dist/browser/extension-relay.js +74 -29
- package/dist/browser/navigation-guard.js +39 -0
- package/dist/browser/paths.js +77 -0
- package/dist/browser/profiles.js +13 -8
- package/dist/browser/pw-ai-module.js +10 -5
- package/dist/browser/pw-session.js +76 -39
- package/dist/browser/pw-tools-core.interactions.js +14 -7
- package/dist/browser/pw-tools-core.state.js +12 -6
- package/dist/browser/routes/agent.act.js +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-context.js +7 -0
- package/dist/browser/server-lifecycle.js +37 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/allow-from.js +26 -0
- package/dist/channels/allowlists/resolve-utils.js +43 -19
- package/dist/channels/channel-config.js +14 -7
- package/dist/channels/draft-stream-loop.js +7 -0
- package/dist/channels/model-overrides.js +82 -0
- package/dist/channels/plugins/account-action-gate.js +13 -0
- package/dist/channels/plugins/message-actions.js +10 -0
- package/dist/channels/plugins/normalize/imessage.js +14 -7
- package/dist/channels/plugins/normalize/slack.js +10 -5
- package/dist/channels/plugins/normalize/telegram.js +14 -7
- package/dist/channels/plugins/outbound/discord.js +80 -8
- package/dist/channels/plugins/outbound/signal.js +11 -11
- package/dist/channels/plugins/setup-helpers.js +10 -5
- package/dist/channels/sender-label.js +14 -7
- package/dist/channels/session.js +4 -2
- package/dist/channels/status-reactions.js +297 -0
- package/dist/channels/telegram/api.js +18 -0
- package/dist/cli/argv.js +84 -21
- package/dist/cli/banner.js +3 -2
- package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
- package/dist/cli/cli-name.js +11 -11
- package/dist/cli/cli-utils.js +13 -3
- package/dist/cli/command-format.js +1 -1
- package/dist/cli/config-cli.js +1 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
- package/dist/cli/daemon-cli/lifecycle.js +64 -2
- package/dist/cli/daemon-cli/restart-health.js +126 -0
- package/dist/cli/daemon-cli/status.gather.js +9 -13
- package/dist/cli/daemon-cli/status.print.js +2 -10
- package/dist/cli/deps.js +27 -22
- package/dist/cli/exec-approvals-cli.js +92 -124
- package/dist/cli/gateway-cli/run-loop.js +23 -5
- package/dist/cli/memory-cli.js +158 -61
- package/dist/cli/node-cli/register.js +14 -5
- package/dist/cli/nodes-cli/register.push.js +63 -0
- package/dist/cli/nodes-media-utils.js +26 -0
- package/dist/cli/outbound-send-deps.js +2 -9
- package/dist/cli/outbound-send-mapping.js +11 -0
- package/dist/cli/pairing-cli.js +40 -14
- package/dist/cli/plugins-cli.js +250 -73
- package/dist/cli/ports.js +11 -10
- package/dist/cli/program/build-program.js +3 -1
- package/dist/cli/program/command-registry.js +214 -136
- package/dist/cli/program/command-tree.js +16 -0
- package/dist/cli/program/help.js +43 -12
- package/dist/cli/program/preaction.js +13 -9
- package/dist/cli/program/register.configure.js +3 -18
- package/dist/cli/program/register.maintenance.js +2 -2
- package/dist/cli/program/register.onboard.js +2 -0
- package/dist/cli/program/register.status-health-sessions.js +16 -17
- package/dist/cli/program/register.subclis.js +93 -52
- package/dist/cli/route.js +12 -8
- package/dist/cli/system-cli.js +36 -46
- package/dist/cli/test-runtime-capture.js +24 -0
- package/dist/cli/update-cli/shared.js +22 -9
- package/dist/cli/update-cli/update-command.js +89 -14
- package/dist/cli/update-cli/wizard.js +6 -12
- package/dist/commands/agent/run-context.js +18 -5
- package/dist/commands/agent/session-store.js +17 -4
- package/dist/commands/agent.js +185 -89
- package/dist/commands/agents.bindings.js +14 -7
- package/dist/commands/agents.commands.add.js +13 -9
- package/dist/commands/agents.commands.identity.js +12 -6
- package/dist/commands/agents.commands.list.js +11 -6
- package/dist/commands/agents.config.js +8 -10
- package/dist/commands/agents.providers.js +12 -6
- package/dist/commands/auth-choice-options.js +103 -75
- package/dist/commands/auth-choice.apply.byteplus.js +55 -0
- package/dist/commands/auth-choice.apply.js +4 -0
- package/dist/commands/auth-choice.apply.minimax.js +61 -13
- package/dist/commands/auth-choice.apply.openai.js +3 -1
- package/dist/commands/auth-choice.apply.volcengine.js +55 -0
- package/dist/commands/auth-choice.preferred-provider.js +2 -0
- package/dist/commands/channels/remove.js +13 -6
- package/dist/commands/channels/shared.js +4 -14
- package/dist/commands/channels.mock-harness.js +23 -0
- package/dist/commands/configure.commands.js +14 -0
- package/dist/commands/configure.gateway.js +2 -4
- package/dist/commands/configure.js +1 -1
- package/dist/commands/configure.shared.js +11 -0
- package/dist/commands/daemon-install-helpers.js +2 -2
- package/dist/commands/daemon-install-runtime-warning.js +11 -0
- package/dist/commands/dashboard.js +12 -10
- package/dist/commands/docs.js +14 -8
- package/dist/commands/doctor-config-flow.js +11 -9
- package/dist/commands/doctor-legacy-config.js +281 -0
- package/dist/commands/doctor-state-integrity.js +99 -23
- package/dist/commands/doctor-update.js +12 -9
- package/dist/commands/models/list.list-command.js +7 -5
- package/dist/commands/models/set-image.js +2 -21
- package/dist/commands/node-daemon-install-helpers.js +10 -8
- package/dist/commands/onboard-auth.config-minimax.js +54 -80
- package/dist/commands/onboard-auth.config-opencode.js +2 -18
- package/dist/commands/onboard-auth.credentials.js +90 -13
- package/dist/commands/onboard-auth.js +1 -1
- package/dist/commands/onboard-auth.models.js +6 -5
- package/dist/commands/onboard-hooks.js +1 -1
- package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
- package/dist/commands/onboard-provider-auth-flags.js +14 -0
- package/dist/commands/onboard-remote.js +14 -7
- package/dist/commands/onboard.js +11 -13
- package/dist/commands/sandbox-display.js +6 -5
- package/dist/commands/sessions.test-helpers.js +61 -0
- package/dist/commands/status-all/diagnosis.js +14 -10
- package/dist/commands/status-all/format.js +1 -0
- package/dist/commands/status.gateway-probe.js +1 -16
- package/dist/commands/systemd-linger.js +12 -6
- package/dist/config/agent-limits.js +2 -0
- package/dist/config/commands.js +32 -15
- package/dist/config/config-paths.js +9 -11
- package/dist/config/config.js +1 -1
- package/dist/config/defaults.js +22 -2
- package/dist/config/discord-preview-streaming.js +104 -0
- package/dist/config/env-substitution.js +62 -34
- package/dist/config/env-vars.js +45 -7
- package/dist/config/includes.js +4 -0
- package/dist/config/io.js +656 -171
- package/dist/config/legacy.migrations.part-1.js +189 -78
- package/dist/config/legacy.shared.js +3 -1
- package/dist/config/merge-patch.js +54 -4
- package/dist/config/prototype-keys.js +4 -0
- package/dist/config/redact-snapshot.js +404 -76
- package/dist/config/schema.help.js +44 -7
- package/dist/config/schema.js +58 -570
- package/dist/config/schema.labels.js +38 -6
- package/dist/config/sessions/delivery-info.js +10 -3
- package/dist/config/sessions/main-session.js +10 -5
- package/dist/config/sessions/session-file.js +33 -0
- package/dist/config/sessions/session-key.js +10 -5
- package/dist/config/sessions/store.js +1 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/validation.js +140 -85
- package/dist/config/zod-schema.agent-runtime.js +11 -0
- package/dist/config/zod-schema.hooks.js +40 -11
- package/dist/config/zod-schema.installs.js +20 -0
- package/dist/config/zod-schema.js +156 -20
- package/dist/config/zod-schema.providers-core.js +78 -4
- package/dist/config/zod-schema.providers.js +6 -1
- package/dist/config/zod-schema.session.js +41 -2
- package/dist/cron/run-log.js +3 -0
- package/dist/cron/schedule.js +21 -10
- package/dist/cron/service/ops.js +35 -21
- package/dist/cron/service/timer.js +116 -16
- package/dist/cron/stagger.js +3 -1
- package/dist/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/api.js +12 -6
- package/dist/discord/draft-chunking.js +22 -0
- package/dist/discord/draft-stream.js +124 -0
- package/dist/discord/monitor/agent-components.js +1 -1
- package/dist/discord/monitor/commands.js +5 -0
- package/dist/discord/monitor/exec-approvals.js +357 -162
- package/dist/discord/monitor/gateway-plugin.js +2 -1
- package/dist/discord/monitor/listeners.js +37 -27
- package/dist/discord/monitor/message-handler.js +4 -1
- package/dist/discord/monitor/message-handler.preflight.js +65 -8
- package/dist/discord/monitor/message-handler.process.js +246 -217
- package/dist/discord/monitor/message-utils.js +143 -6
- package/dist/discord/monitor/model-picker-preferences.js +143 -0
- package/dist/discord/monitor/model-picker.js +651 -0
- package/dist/discord/monitor/native-command.js +573 -16
- package/dist/discord/monitor/provider.allowlist.js +223 -0
- package/dist/discord/monitor/provider.js +275 -347
- package/dist/discord/monitor/provider.lifecycle.js +100 -0
- package/dist/discord/monitor/reply-delivery.js +123 -16
- package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
- package/dist/discord/monitor/thread-bindings.js +4 -0
- package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
- package/dist/discord/monitor/thread-bindings.manager.js +423 -0
- package/dist/discord/monitor/thread-bindings.messages.js +55 -0
- package/dist/discord/monitor/thread-bindings.state.js +358 -0
- package/dist/discord/monitor/thread-bindings.types.js +6 -0
- package/dist/discord/resolve-users.js +33 -21
- package/dist/discord/send.channels.js +15 -0
- package/dist/discord/send.js +3 -2
- package/dist/discord/send.outbound.js +82 -26
- package/dist/discord/send.permissions.js +83 -30
- package/dist/discord/send.reactions.js +8 -4
- package/dist/discord/token.js +10 -5
- package/dist/discord/voice/command.js +263 -0
- package/dist/discord/voice/manager.js +531 -0
- package/dist/gateway/auth.js +72 -13
- package/dist/gateway/call.js +152 -83
- package/dist/gateway/canvas-capability.js +75 -0
- package/dist/gateway/client.js +28 -4
- package/dist/gateway/config-reload.js +3 -4
- package/dist/gateway/control-plane-audit.js +28 -0
- package/dist/gateway/control-plane-rate-limit.js +53 -0
- package/dist/gateway/control-ui.js +219 -96
- package/dist/gateway/events.js +1 -0
- package/dist/gateway/hooks-mapping.js +88 -38
- package/dist/gateway/hooks.js +109 -54
- package/dist/gateway/http-auth-helpers.js +3 -2
- package/dist/gateway/http-common.js +22 -0
- package/dist/gateway/http-endpoint-helpers.js +1 -0
- package/dist/gateway/method-scopes.js +169 -0
- package/dist/gateway/net.js +74 -9
- package/dist/gateway/node-invoke-system-run-approval.js +14 -35
- package/dist/gateway/node-registry.js +10 -5
- package/dist/gateway/openai-http.js +1 -0
- package/dist/gateway/openresponses-http.js +121 -110
- package/dist/gateway/origin-check.js +1 -18
- package/dist/gateway/probe-auth.js +2 -0
- package/dist/gateway/protocol/index.js +4 -2
- package/dist/gateway/protocol/schema/cron.js +1 -0
- package/dist/gateway/protocol/schema/devices.js +1 -0
- package/dist/gateway/protocol/schema/protocol-schemas.js +4 -1
- package/dist/gateway/protocol/schema/push.js +18 -0
- package/dist/gateway/protocol/schema/sessions.js +6 -0
- package/dist/gateway/protocol/schema.js +1 -0
- package/dist/gateway/role-policy.js +17 -0
- package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
- package/dist/gateway/server/ws-connection/message-handler.js +175 -148
- package/dist/gateway/server-chat.js +83 -25
- package/dist/gateway/server-constants.js +10 -9
- package/dist/gateway/server-cron.js +1 -0
- package/dist/gateway/server-http.js +247 -54
- package/dist/gateway/server-maintenance.js +20 -5
- package/dist/gateway/server-methods/agent.js +162 -24
- package/dist/gateway/server-methods/chat.js +465 -130
- package/dist/gateway/server-methods/config.js +193 -152
- package/dist/gateway/server-methods/devices.js +17 -3
- package/dist/gateway/server-methods/models.js +11 -1
- 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-methods/sessions.js +64 -8
- package/dist/gateway/server-methods/usage.js +162 -75
- package/dist/gateway/server-node-events.js +29 -0
- package/dist/gateway/server-reload-handlers.js +2 -3
- package/dist/gateway/server-runtime-config.js +39 -13
- package/dist/gateway/server-runtime-state.js +2 -0
- package/dist/gateway/server-startup-memory.js +17 -11
- 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/session-utils.fs.js +32 -34
- package/dist/gateway/sessions-resolve.js +17 -5
- 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.openai-mock.js +14 -7
- package/dist/gateway/test-helpers.server.js +161 -77
- package/dist/gateway/tools-invoke-http.js +21 -10
- package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
- package/dist/hooks/bundled/command-logger/handler.js +7 -2
- package/dist/hooks/bundled/session-memory/handler.js +170 -38
- package/dist/hooks/frontmatter.js +6 -6
- package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
- package/dist/hooks/gmail-watcher.js +11 -6
- package/dist/hooks/internal-hooks.js +11 -1
- package/dist/hooks/llm-slug-generator.js +4 -1
- package/dist/hooks/workspace.js +47 -17
- package/dist/imessage/accounts.js +9 -20
- package/dist/imessage/monitor/inbound-processing.js +2 -1
- package/dist/infra/archive-path.js +49 -0
- package/dist/infra/archive.js +174 -73
- package/dist/infra/control-ui-assets.js +14 -6
- package/dist/infra/device-pairing.js +204 -144
- package/dist/infra/env.js +10 -5
- package/dist/infra/exec-approvals-allowlist.js +141 -70
- package/dist/infra/exec-approvals-analysis.js +78 -20
- package/dist/infra/exec-approvals.js +5 -17
- package/dist/infra/exec-safe-bin-policy.js +277 -0
- package/dist/infra/fixed-window-rate-limit.js +33 -0
- package/dist/infra/fs-safe.js +71 -39
- package/dist/infra/gateway-lock.js +6 -2
- 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/heartbeat-wake.js +6 -12
- package/dist/infra/host-env-security-policy.json +19 -0
- package/dist/infra/host-env-security.js +66 -0
- package/dist/infra/install-source-utils.js +91 -7
- package/dist/infra/net/ssrf.js +131 -38
- 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/bound-delivery-router.js +88 -0
- package/dist/infra/outbound/channel-adapters.js +20 -7
- package/dist/infra/outbound/channel-selection.js +12 -6
- package/dist/infra/outbound/envelope.js +1 -1
- package/dist/infra/outbound/format.js +12 -6
- package/dist/infra/outbound/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/outbound/payloads.js +14 -7
- package/dist/infra/outbound/session-binding-service.js +123 -0
- package/dist/infra/pairing-files.js +10 -0
- package/dist/infra/path-guards.js +25 -0
- package/dist/infra/plain-object.js +9 -0
- package/dist/infra/provider-usage.fetch.codex.js +7 -15
- package/dist/infra/provider-usage.fetch.gemini.js +14 -11
- package/dist/infra/provider-usage.fetch.shared.js +30 -1
- package/dist/infra/provider-usage.fetch.zai.js +10 -9
- package/dist/infra/push-apns.js +365 -0
- package/dist/infra/restart-sentinel.js +16 -1
- package/dist/infra/restart.js +229 -26
- package/dist/infra/retry-policy.js +4 -2
- package/dist/infra/retry.js +9 -5
- package/dist/infra/scp-host.js +54 -0
- package/dist/infra/session-cost-usage.js +107 -59
- package/dist/infra/session-maintenance-warning.js +3 -1
- package/dist/infra/shell-env.js +98 -34
- package/dist/infra/ssh-config.js +12 -6
- package/dist/infra/system-run-command.js +49 -4
- package/dist/infra/update-channels.js +10 -5
- package/dist/infra/update-startup.js +86 -9
- package/dist/line/accounts.js +5 -7
- package/dist/line/bot-access.js +8 -20
- package/dist/line/bot-handlers.js +3 -1
- package/dist/link-understanding/detect.js +15 -7
- package/dist/media/constants.js +15 -6
- package/dist/media/image-ops.js +7 -0
- package/dist/media/inbound-path-policy.js +114 -0
- package/dist/media/input-files.js +16 -0
- package/dist/media/local-roots.js +3 -2
- package/dist/media-understanding/apply.js +4 -1
- package/dist/media-understanding/concurrency.js +8 -20
- package/dist/memory/backend-config.js +45 -6
- package/dist/memory/embeddings.js +10 -4
- package/dist/memory/fs-utils.js +23 -0
- package/dist/memory/manager-search.js +12 -6
- package/dist/memory/manager-sync-ops.js +12 -2
- package/dist/memory/qmd-manager.js +466 -53
- package/dist/memory/query-expansion.js +167 -3
- package/dist/memory/status-format.js +10 -5
- package/dist/memory/sync-memory-files.js +1 -1
- package/dist/memory/test-manager.js +8 -0
- package/dist/node-host/invoke-system-run.js +281 -0
- package/dist/node-host/invoke.js +55 -337
- package/dist/pairing/pairing-store.js +22 -0
- package/dist/plugin-sdk/allow-from.js +1 -1
- package/dist/plugin-sdk/command-auth.js +3 -1
- package/dist/plugin-sdk/index.js +6 -3
- package/dist/plugin-sdk/temp-path.js +47 -0
- package/dist/plugin-sdk/webhook-targets.js +32 -0
- package/dist/plugins/bundled-dir.js +9 -6
- package/dist/plugins/discovery.js +217 -23
- package/dist/plugins/hook-runner-global.js +16 -0
- package/dist/plugins/hooks.js +50 -0
- package/dist/plugins/install.js +28 -16
- 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/plugins/runtime.js +3 -17
- package/dist/plugins/update.js +78 -12
- package/dist/process/spawn-utils.js +14 -7
- package/dist/providers/github-copilot-models.js +4 -1
- package/dist/providers/github-copilot-token.js +11 -6
- package/dist/providers/qwen-portal-oauth.js +14 -6
- package/dist/routing/account-id.js +30 -0
- package/dist/routing/resolve-route.js +3 -7
- package/dist/routing/session-key.js +2 -16
- package/dist/security/audit-channel.js +100 -20
- package/dist/security/audit-extra.async.js +505 -179
- package/dist/security/audit-extra.js +12 -2
- package/dist/security/audit-extra.sync.js +421 -35
- package/dist/security/audit-fs.js +31 -13
- package/dist/security/audit.js +180 -370
- package/dist/security/dm-policy-shared.js +68 -0
- package/dist/security/external-content.js +46 -14
- 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/entry-status.js +6 -0
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-parse.js +13 -0
- package/dist/shared/node-match.js +11 -4
- package/dist/shared/operator-scope-compat.js +42 -0
- package/dist/shared/text-chunking.js +29 -0
- package/dist/signal/accounts.js +7 -20
- package/dist/signal/monitor/event-handler.js +3 -1
- package/dist/slack/accounts.js +6 -19
- package/dist/slack/actions.js +11 -3
- package/dist/slack/blocks.test-helpers.js +31 -0
- package/dist/slack/monitor/auth.js +1 -1
- package/dist/slack/monitor/message-handler/dispatch.js +50 -29
- package/dist/slack/monitor/mrkdwn.js +8 -0
- package/dist/slack/monitor/replies.js +15 -7
- package/dist/slack/monitor/slash.js +22 -13
- package/dist/slack/resolve-channels.js +10 -5
- package/dist/slack/send.js +102 -12
- package/dist/slack/stream-mode.js +10 -0
- package/dist/slack/streaming.js +4 -2
- package/dist/telegram/accounts.js +19 -14
- package/dist/telegram/bot/helpers.js +3 -5
- package/dist/telegram/bot-access.js +35 -36
- package/dist/telegram/bot-handlers.js +120 -148
- package/dist/telegram/bot-message-context.js +68 -9
- package/dist/telegram/bot-message-dispatch.js +477 -210
- package/dist/telegram/bot-native-commands.js +16 -0
- package/dist/telegram/draft-stream.js +44 -8
- package/dist/telegram/inline-buttons.js +5 -15
- package/dist/telegram/monitor.js +11 -7
- package/dist/telegram/network-config.js +19 -7
- package/dist/telegram/reasoning-lane-coordinator.js +128 -0
- package/dist/telegram/send.js +3 -2
- package/dist/telegram/sent-message-cache.js +5 -6
- package/dist/telegram/status-reaction-variants.js +208 -0
- package/dist/telegram/sticker-cache.js +11 -9
- package/dist/terminal/prompt-select-styled.js +9 -0
- package/dist/terminal/theme.js +12 -12
- 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/tts/tts.js +80 -567
- package/dist/tui/components/chat-log.js +50 -8
- package/dist/tui/theme/theme.js +10 -12
- package/dist/tui/tui-command-handlers.js +36 -27
- package/dist/tui/tui-event-handlers.js +122 -32
- package/dist/tui/tui-local-shell.js +16 -6
- package/dist/tui/tui.js +236 -48
- package/dist/utils/account-id.js +2 -4
- package/dist/utils/boolean.js +10 -5
- package/dist/utils/directive-tags.js +11 -0
- package/dist/utils/mask-api-key.js +10 -0
- package/dist/utils/queue-helpers.js +67 -12
- package/dist/utils/run-with-concurrency.js +39 -0
- package/dist/web/auto-reply/deliver-reply.js +8 -4
- package/dist/web/auto-reply/mentions.js +10 -5
- package/dist/web/auto-reply/monitor/group-members.js +14 -7
- package/dist/web/auto-reply/monitor/process-message.js +45 -24
- package/dist/web/inbound/access-control.js +5 -2
- package/dist/web/login-qr.js +12 -6
- package/dist/web/media.js +126 -15
- package/docs/tools/slash-commands.md +5 -1
- package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
- package/extensions/bluebubbles/src/monitor.ts +208 -1950
- package/extensions/feishu/src/external-keys.ts +19 -0
- package/extensions/lobster/src/windows-spawn.ts +193 -0
- package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
- package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
- package/package.json +1 -1
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
// Keep tool-policy browser-safe: do not import tools/common at runtime.
|
|
2
|
+
function wrapOwnerOnlyToolExecution(tool, senderIsOwner) {
|
|
3
|
+
if (tool.ownerOnly !== true || senderIsOwner || !tool.execute) {
|
|
4
|
+
return tool;
|
|
5
|
+
}
|
|
6
|
+
return {
|
|
7
|
+
...tool,
|
|
8
|
+
execute: async () => {
|
|
9
|
+
throw new Error("Tool restricted to owner senders.");
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
}
|
|
1
13
|
const TOOL_NAME_ALIASES = {
|
|
2
14
|
bash: "exec",
|
|
3
15
|
"apply-patch": "apply_patch",
|
|
@@ -16,6 +28,7 @@ export const TOOL_GROUPS = {
|
|
|
16
28
|
"sessions_history",
|
|
17
29
|
"sessions_send",
|
|
18
30
|
"sessions_spawn",
|
|
31
|
+
"subagents",
|
|
19
32
|
"session_status",
|
|
20
33
|
],
|
|
21
34
|
// UI helpers
|
|
@@ -26,7 +39,7 @@ export const TOOL_GROUPS = {
|
|
|
26
39
|
"group:messaging": ["message"],
|
|
27
40
|
// Nodes + device tools
|
|
28
41
|
"group:nodes": ["nodes"],
|
|
29
|
-
// All
|
|
42
|
+
// All Pool Bot native tools (excludes provider plugins).
|
|
30
43
|
"group:poolbot": [
|
|
31
44
|
"browser",
|
|
32
45
|
"canvas",
|
|
@@ -39,6 +52,7 @@ export const TOOL_GROUPS = {
|
|
|
39
52
|
"sessions_history",
|
|
40
53
|
"sessions_send",
|
|
41
54
|
"sessions_spawn",
|
|
55
|
+
"subagents",
|
|
42
56
|
"session_status",
|
|
43
57
|
"memory_search",
|
|
44
58
|
"memory_get",
|
|
@@ -47,7 +61,7 @@ export const TOOL_GROUPS = {
|
|
|
47
61
|
"image",
|
|
48
62
|
],
|
|
49
63
|
};
|
|
50
|
-
const
|
|
64
|
+
const OWNER_ONLY_TOOL_NAME_FALLBACKS = new Set(["whatsapp_login", "cron", "gateway"]);
|
|
51
65
|
const TOOL_PROFILES = {
|
|
52
66
|
minimal: {
|
|
53
67
|
allow: ["session_status"],
|
|
@@ -71,31 +85,27 @@ export function normalizeToolName(name) {
|
|
|
71
85
|
return TOOL_NAME_ALIASES[normalized] ?? normalized;
|
|
72
86
|
}
|
|
73
87
|
export function isOwnerOnlyToolName(name) {
|
|
74
|
-
return
|
|
88
|
+
return OWNER_ONLY_TOOL_NAME_FALLBACKS.has(normalizeToolName(name));
|
|
89
|
+
}
|
|
90
|
+
function isOwnerOnlyTool(tool) {
|
|
91
|
+
return tool.ownerOnly === true || isOwnerOnlyToolName(tool.name);
|
|
75
92
|
}
|
|
76
93
|
export function applyOwnerOnlyToolPolicy(tools, senderIsOwner) {
|
|
77
94
|
const withGuard = tools.map((tool) => {
|
|
78
|
-
if (!
|
|
95
|
+
if (!isOwnerOnlyTool(tool)) {
|
|
79
96
|
return tool;
|
|
80
97
|
}
|
|
81
|
-
|
|
82
|
-
return tool;
|
|
83
|
-
}
|
|
84
|
-
return {
|
|
85
|
-
...tool,
|
|
86
|
-
execute: async () => {
|
|
87
|
-
throw new Error("Tool restricted to owner senders.");
|
|
88
|
-
},
|
|
89
|
-
};
|
|
98
|
+
return wrapOwnerOnlyToolExecution(tool, senderIsOwner);
|
|
90
99
|
});
|
|
91
100
|
if (senderIsOwner) {
|
|
92
101
|
return withGuard;
|
|
93
102
|
}
|
|
94
|
-
return withGuard.filter((tool) => !
|
|
103
|
+
return withGuard.filter((tool) => !isOwnerOnlyTool(tool));
|
|
95
104
|
}
|
|
96
105
|
export function normalizeToolList(list) {
|
|
97
|
-
if (!list)
|
|
106
|
+
if (!list) {
|
|
98
107
|
return [];
|
|
108
|
+
}
|
|
99
109
|
return list.map(normalizeToolName).filter(Boolean);
|
|
100
110
|
}
|
|
101
111
|
export function expandToolGroups(list) {
|
|
@@ -114,14 +124,17 @@ export function expandToolGroups(list) {
|
|
|
114
124
|
export function collectExplicitAllowlist(policies) {
|
|
115
125
|
const entries = [];
|
|
116
126
|
for (const policy of policies) {
|
|
117
|
-
if (!policy?.allow)
|
|
127
|
+
if (!policy?.allow) {
|
|
118
128
|
continue;
|
|
129
|
+
}
|
|
119
130
|
for (const value of policy.allow) {
|
|
120
|
-
if (typeof value !== "string")
|
|
131
|
+
if (typeof value !== "string") {
|
|
121
132
|
continue;
|
|
133
|
+
}
|
|
122
134
|
const trimmed = value.trim();
|
|
123
|
-
if (trimmed)
|
|
135
|
+
if (trimmed) {
|
|
124
136
|
entries.push(trimmed);
|
|
137
|
+
}
|
|
125
138
|
}
|
|
126
139
|
}
|
|
127
140
|
return entries;
|
|
@@ -131,8 +144,9 @@ export function buildPluginToolGroups(params) {
|
|
|
131
144
|
const byPlugin = new Map();
|
|
132
145
|
for (const tool of params.tools) {
|
|
133
146
|
const meta = params.toolMeta(tool);
|
|
134
|
-
if (!meta)
|
|
147
|
+
if (!meta) {
|
|
135
148
|
continue;
|
|
149
|
+
}
|
|
136
150
|
const name = normalizeToolName(tool.name);
|
|
137
151
|
all.push(name);
|
|
138
152
|
const pluginId = meta.pluginId.toLowerCase();
|
|
@@ -143,8 +157,9 @@ export function buildPluginToolGroups(params) {
|
|
|
143
157
|
return { all, byPlugin };
|
|
144
158
|
}
|
|
145
159
|
export function expandPluginGroups(list, groups) {
|
|
146
|
-
if (!list || list.length === 0)
|
|
160
|
+
if (!list || list.length === 0) {
|
|
147
161
|
return list;
|
|
162
|
+
}
|
|
148
163
|
const expanded = [];
|
|
149
164
|
for (const entry of list) {
|
|
150
165
|
const normalized = normalizeToolName(entry);
|
|
@@ -167,8 +182,9 @@ export function expandPluginGroups(list, groups) {
|
|
|
167
182
|
return Array.from(new Set(expanded));
|
|
168
183
|
}
|
|
169
184
|
export function expandPolicyWithPluginGroups(policy, groups) {
|
|
170
|
-
if (!policy)
|
|
185
|
+
if (!policy) {
|
|
171
186
|
return undefined;
|
|
187
|
+
}
|
|
172
188
|
return {
|
|
173
189
|
allow: expandPluginGroups(policy.allow, groups),
|
|
174
190
|
deny: expandPluginGroups(policy.deny, groups),
|
|
@@ -187,13 +203,19 @@ export function stripPluginOnlyAllowlist(policy, groups, coreTools) {
|
|
|
187
203
|
const unknownAllowlist = [];
|
|
188
204
|
let hasCoreEntry = false;
|
|
189
205
|
for (const entry of normalized) {
|
|
206
|
+
if (entry === "*") {
|
|
207
|
+
hasCoreEntry = true;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
190
210
|
const isPluginEntry = entry === "group:plugins" || pluginIds.has(entry) || pluginTools.has(entry);
|
|
191
211
|
const expanded = expandToolGroups([entry]);
|
|
192
212
|
const isCoreEntry = expanded.some((tool) => coreTools.has(tool));
|
|
193
|
-
if (isCoreEntry)
|
|
213
|
+
if (isCoreEntry) {
|
|
194
214
|
hasCoreEntry = true;
|
|
195
|
-
|
|
215
|
+
}
|
|
216
|
+
if (!isCoreEntry && !isPluginEntry) {
|
|
196
217
|
unknownAllowlist.push(entry);
|
|
218
|
+
}
|
|
197
219
|
}
|
|
198
220
|
const strippedAllowlist = !hasCoreEntry;
|
|
199
221
|
// When an allowlist contains only plugin tools, we strip it to avoid accidentally
|
|
@@ -209,13 +231,16 @@ export function stripPluginOnlyAllowlist(policy, groups, coreTools) {
|
|
|
209
231
|
};
|
|
210
232
|
}
|
|
211
233
|
export function resolveToolProfilePolicy(profile) {
|
|
212
|
-
if (!profile)
|
|
234
|
+
if (!profile) {
|
|
213
235
|
return undefined;
|
|
236
|
+
}
|
|
214
237
|
const resolved = TOOL_PROFILES[profile];
|
|
215
|
-
if (!resolved)
|
|
238
|
+
if (!resolved) {
|
|
216
239
|
return undefined;
|
|
217
|
-
|
|
240
|
+
}
|
|
241
|
+
if (!resolved.allow && !resolved.deny) {
|
|
218
242
|
return undefined;
|
|
243
|
+
}
|
|
219
244
|
return {
|
|
220
245
|
allow: resolved.allow ? [...resolved.allow] : undefined,
|
|
221
246
|
deny: resolved.deny ? [...resolved.deny] : undefined,
|
|
@@ -1,14 +1,35 @@
|
|
|
1
|
-
import { browserCloseTab, browserFocusTab, browserOpenTab, browserProfiles, browserSnapshot, browserStart, browserStatus, browserStop, browserTabs, } from "../../browser/client.js";
|
|
2
|
-
import { browserAct, browserArmDialog, browserArmFileChooser, browserConsoleMessages, browserNavigate, browserPdfSave, browserScreenshotAction, } from "../../browser/client-actions.js";
|
|
3
1
|
import crypto from "node:crypto";
|
|
2
|
+
import { browserAct, browserArmDialog, browserArmFileChooser, browserConsoleMessages, browserNavigate, browserPdfSave, browserScreenshotAction, } from "../../browser/client-actions.js";
|
|
3
|
+
import { browserCloseTab, browserFocusTab, browserOpenTab, browserProfiles, browserSnapshot, browserStart, browserStatus, browserStop, browserTabs, } from "../../browser/client.js";
|
|
4
4
|
import { resolveBrowserConfig } from "../../browser/config.js";
|
|
5
5
|
import { DEFAULT_AI_SNAPSHOT_MAX_CHARS } from "../../browser/constants.js";
|
|
6
|
+
import { DEFAULT_UPLOAD_DIR, resolveExistingPathsWithinRoot } from "../../browser/paths.js";
|
|
7
|
+
import { applyBrowserProxyPaths, persistBrowserProxyFiles } from "../../browser/proxy-files.js";
|
|
6
8
|
import { loadConfig } from "../../config/config.js";
|
|
7
|
-
import {
|
|
8
|
-
import { listNodes, resolveNodeIdFromList } from "./nodes-utils.js";
|
|
9
|
+
import { wrapExternalContent } from "../../security/external-content.js";
|
|
9
10
|
import { BrowserToolSchema } from "./browser-tool.schema.js";
|
|
10
11
|
import { imageResultFromFile, jsonResult, readStringParam } from "./common.js";
|
|
11
12
|
import { callGatewayTool } from "./gateway.js";
|
|
13
|
+
import { listNodes, resolveNodeIdFromList } from "./nodes-utils.js";
|
|
14
|
+
function wrapBrowserExternalJson(params) {
|
|
15
|
+
const extractedText = JSON.stringify(params.payload, null, 2);
|
|
16
|
+
const wrappedText = wrapExternalContent(extractedText, {
|
|
17
|
+
source: "browser",
|
|
18
|
+
includeWarning: params.includeWarning ?? true,
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
wrappedText,
|
|
22
|
+
safeDetails: {
|
|
23
|
+
ok: true,
|
|
24
|
+
externalContent: {
|
|
25
|
+
untrusted: true,
|
|
26
|
+
source: "browser",
|
|
27
|
+
kind: params.kind,
|
|
28
|
+
wrapped: true,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
12
33
|
const DEFAULT_BROWSER_PROXY_TIMEOUT_MS = 20_000;
|
|
13
34
|
function isBrowserNode(node) {
|
|
14
35
|
const caps = Array.isArray(node.caps) ? node.caps : [];
|
|
@@ -28,8 +49,9 @@ async function resolveBrowserNodeTarget(params) {
|
|
|
28
49
|
if (params.sandboxBridgeUrl?.trim() && params.target !== "node" && !params.requestedNode) {
|
|
29
50
|
return null;
|
|
30
51
|
}
|
|
31
|
-
if (params.target && params.target !== "node")
|
|
52
|
+
if (params.target && params.target !== "node") {
|
|
32
53
|
return null;
|
|
54
|
+
}
|
|
33
55
|
if (mode === "manual" && params.target !== "node" && !params.requestedNode) {
|
|
34
56
|
return null;
|
|
35
57
|
}
|
|
@@ -54,8 +76,9 @@ async function resolveBrowserNodeTarget(params) {
|
|
|
54
76
|
}
|
|
55
77
|
throw new Error(`Multiple browser-capable nodes connected (${browserNodes.length}). Set gateway.nodes.browser.node or pass node=<id>.`);
|
|
56
78
|
}
|
|
57
|
-
if (mode === "manual")
|
|
79
|
+
if (mode === "manual") {
|
|
58
80
|
return null;
|
|
81
|
+
}
|
|
59
82
|
if (browserNodes.length === 1) {
|
|
60
83
|
const node = browserNodes[0];
|
|
61
84
|
return { nodeId: node.nodeId, label: node.displayName ?? node.remoteIp ?? node.nodeId };
|
|
@@ -66,7 +89,7 @@ async function callBrowserProxy(params) {
|
|
|
66
89
|
const gatewayTimeoutMs = typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs)
|
|
67
90
|
? Math.max(1, Math.floor(params.timeoutMs))
|
|
68
91
|
: DEFAULT_BROWSER_PROXY_TIMEOUT_MS;
|
|
69
|
-
const payload =
|
|
92
|
+
const payload = await callGatewayTool("node.invoke", { timeoutMs: gatewayTimeoutMs }, {
|
|
70
93
|
nodeId: params.nodeId,
|
|
71
94
|
command: "browser.proxy",
|
|
72
95
|
params: {
|
|
@@ -78,44 +101,21 @@ async function callBrowserProxy(params) {
|
|
|
78
101
|
profile: params.profile,
|
|
79
102
|
},
|
|
80
103
|
idempotencyKey: crypto.randomUUID(),
|
|
81
|
-
})
|
|
104
|
+
});
|
|
82
105
|
const parsed = payload?.payload ??
|
|
83
106
|
(typeof payload?.payloadJSON === "string" && payload.payloadJSON
|
|
84
107
|
? JSON.parse(payload.payloadJSON)
|
|
85
108
|
: null);
|
|
86
|
-
if (!parsed || typeof parsed !== "object") {
|
|
109
|
+
if (!parsed || typeof parsed !== "object" || !("result" in parsed)) {
|
|
87
110
|
throw new Error("browser proxy failed");
|
|
88
111
|
}
|
|
89
112
|
return parsed;
|
|
90
113
|
}
|
|
91
114
|
async function persistProxyFiles(files) {
|
|
92
|
-
|
|
93
|
-
return new Map();
|
|
94
|
-
const mapping = new Map();
|
|
95
|
-
for (const file of files) {
|
|
96
|
-
const buffer = Buffer.from(file.base64, "base64");
|
|
97
|
-
const saved = await saveMediaBuffer(buffer, file.mimeType, "browser", buffer.byteLength);
|
|
98
|
-
mapping.set(file.path, saved.path);
|
|
99
|
-
}
|
|
100
|
-
return mapping;
|
|
115
|
+
return await persistBrowserProxyFiles(files);
|
|
101
116
|
}
|
|
102
117
|
function applyProxyPaths(result, mapping) {
|
|
103
|
-
|
|
104
|
-
return;
|
|
105
|
-
const obj = result;
|
|
106
|
-
if (typeof obj.path === "string" && mapping.has(obj.path)) {
|
|
107
|
-
obj.path = mapping.get(obj.path);
|
|
108
|
-
}
|
|
109
|
-
if (typeof obj.imagePath === "string" && mapping.has(obj.imagePath)) {
|
|
110
|
-
obj.imagePath = mapping.get(obj.imagePath);
|
|
111
|
-
}
|
|
112
|
-
const download = obj.download;
|
|
113
|
-
if (download && typeof download === "object") {
|
|
114
|
-
const d = download;
|
|
115
|
-
if (typeof d.path === "string" && mapping.has(d.path)) {
|
|
116
|
-
d.path = mapping.get(d.path);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
118
|
+
applyBrowserProxyPaths(result, mapping);
|
|
119
119
|
}
|
|
120
120
|
function resolveBrowserBaseUrl(params) {
|
|
121
121
|
const cfg = loadConfig();
|
|
@@ -143,11 +143,11 @@ export function createBrowserTool(opts) {
|
|
|
143
143
|
label: "Browser",
|
|
144
144
|
name: "browser",
|
|
145
145
|
description: [
|
|
146
|
-
"Control the browser via
|
|
146
|
+
"Control the browser via Pool Bot's browser control server (status/start/stop/profiles/tabs/open/snapshot/screenshot/actions).",
|
|
147
147
|
'Profiles: use profile="chrome" for Chrome extension relay takeover (your existing Chrome tabs). Use profile="clawd" for the isolated clawd-managed browser.',
|
|
148
|
-
'If the user mentions the Chrome extension / Browser Relay / toolbar button /
|
|
148
|
+
'If the user mentions the Chrome extension / Browser Relay / toolbar button / "attach tab", ALWAYS use profile="chrome" (do not ask which profile).',
|
|
149
149
|
'When a node-hosted browser proxy is available, the tool may auto-route to it. Pin a node with node=<id|name> or target="node".',
|
|
150
|
-
"Chrome extension relay needs an attached tab: user must click the
|
|
150
|
+
"Chrome extension relay needs an attached tab: user must click the Pool Bot Browser Relay toolbar icon on the tab (badge ON). If no tab is connected, ask them to attach it.",
|
|
151
151
|
"When using refs from snapshot (e.g. e12), keep the same tab: prefer passing targetId from the snapshot response into subsequent actions (act/click/type/etc).",
|
|
152
152
|
'For stable, self-resolving refs across calls, use snapshot with refs="aria" (Playwright aria-ref ids). Default refs="role" are role+name-based.',
|
|
153
153
|
"Use snapshot+act for UI automation. Avoid act:wait by default; use only in exceptional cases when no reliable UI state exists.",
|
|
@@ -254,9 +254,28 @@ export function createBrowserTool(opts) {
|
|
|
254
254
|
profile,
|
|
255
255
|
});
|
|
256
256
|
const tabs = result.tabs ?? [];
|
|
257
|
-
|
|
257
|
+
const wrapped = wrapBrowserExternalJson({
|
|
258
|
+
kind: "tabs",
|
|
259
|
+
payload: { tabs },
|
|
260
|
+
includeWarning: false,
|
|
261
|
+
});
|
|
262
|
+
return {
|
|
263
|
+
content: [{ type: "text", text: wrapped.wrappedText }],
|
|
264
|
+
details: { ...wrapped.safeDetails, tabCount: tabs.length },
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
{
|
|
268
|
+
const tabs = await browserTabs(baseUrl, { profile });
|
|
269
|
+
const wrapped = wrapBrowserExternalJson({
|
|
270
|
+
kind: "tabs",
|
|
271
|
+
payload: { tabs },
|
|
272
|
+
includeWarning: false,
|
|
273
|
+
});
|
|
274
|
+
return {
|
|
275
|
+
content: [{ type: "text", text: wrapped.wrappedText }],
|
|
276
|
+
details: { ...wrapped.safeDetails, tabCount: tabs.length },
|
|
277
|
+
};
|
|
258
278
|
}
|
|
259
|
-
return jsonResult({ tabs: await browserTabs(baseUrl, { profile }) });
|
|
260
279
|
case "open": {
|
|
261
280
|
const targetUrl = readStringParam(params, "targetUrl", {
|
|
262
281
|
required: true,
|
|
@@ -305,10 +324,12 @@ export function createBrowserTool(opts) {
|
|
|
305
324
|
});
|
|
306
325
|
return jsonResult(result);
|
|
307
326
|
}
|
|
308
|
-
if (targetId)
|
|
327
|
+
if (targetId) {
|
|
309
328
|
await browserCloseTab(baseUrl, targetId, { profile });
|
|
310
|
-
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
311
331
|
await browserAct(baseUrl, { kind: "close" }, { profile });
|
|
332
|
+
}
|
|
312
333
|
return jsonResult({ ok: true });
|
|
313
334
|
}
|
|
314
335
|
case "snapshot": {
|
|
@@ -383,20 +404,68 @@ export function createBrowserTool(opts) {
|
|
|
383
404
|
profile,
|
|
384
405
|
});
|
|
385
406
|
if (snapshot.format === "ai") {
|
|
407
|
+
const extractedText = snapshot.snapshot ?? "";
|
|
408
|
+
const wrappedSnapshot = wrapExternalContent(extractedText, {
|
|
409
|
+
source: "browser",
|
|
410
|
+
includeWarning: true,
|
|
411
|
+
});
|
|
412
|
+
const safeDetails = {
|
|
413
|
+
ok: true,
|
|
414
|
+
format: snapshot.format,
|
|
415
|
+
targetId: snapshot.targetId,
|
|
416
|
+
url: snapshot.url,
|
|
417
|
+
truncated: snapshot.truncated,
|
|
418
|
+
stats: snapshot.stats,
|
|
419
|
+
refs: snapshot.refs ? Object.keys(snapshot.refs).length : undefined,
|
|
420
|
+
labels: snapshot.labels,
|
|
421
|
+
labelsCount: snapshot.labelsCount,
|
|
422
|
+
labelsSkipped: snapshot.labelsSkipped,
|
|
423
|
+
imagePath: snapshot.imagePath,
|
|
424
|
+
imageType: snapshot.imageType,
|
|
425
|
+
externalContent: {
|
|
426
|
+
untrusted: true,
|
|
427
|
+
source: "browser",
|
|
428
|
+
kind: "snapshot",
|
|
429
|
+
format: "ai",
|
|
430
|
+
wrapped: true,
|
|
431
|
+
},
|
|
432
|
+
};
|
|
386
433
|
if (labels && snapshot.imagePath) {
|
|
387
434
|
return await imageResultFromFile({
|
|
388
435
|
label: "browser:snapshot",
|
|
389
436
|
path: snapshot.imagePath,
|
|
390
|
-
extraText:
|
|
391
|
-
details:
|
|
437
|
+
extraText: wrappedSnapshot,
|
|
438
|
+
details: safeDetails,
|
|
392
439
|
});
|
|
393
440
|
}
|
|
394
441
|
return {
|
|
395
|
-
content: [{ type: "text", text:
|
|
396
|
-
details:
|
|
442
|
+
content: [{ type: "text", text: wrappedSnapshot }],
|
|
443
|
+
details: safeDetails,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
{
|
|
447
|
+
const wrapped = wrapBrowserExternalJson({
|
|
448
|
+
kind: "snapshot",
|
|
449
|
+
payload: snapshot,
|
|
450
|
+
});
|
|
451
|
+
return {
|
|
452
|
+
content: [{ type: "text", text: wrapped.wrappedText }],
|
|
453
|
+
details: {
|
|
454
|
+
...wrapped.safeDetails,
|
|
455
|
+
format: "aria",
|
|
456
|
+
targetId: snapshot.targetId,
|
|
457
|
+
url: snapshot.url,
|
|
458
|
+
nodeCount: snapshot.nodes.length,
|
|
459
|
+
externalContent: {
|
|
460
|
+
untrusted: true,
|
|
461
|
+
source: "browser",
|
|
462
|
+
kind: "snapshot",
|
|
463
|
+
format: "aria",
|
|
464
|
+
wrapped: true,
|
|
465
|
+
},
|
|
466
|
+
},
|
|
397
467
|
};
|
|
398
468
|
}
|
|
399
|
-
return jsonResult(snapshot);
|
|
400
469
|
}
|
|
401
470
|
case "screenshot": {
|
|
402
471
|
const targetId = readStringParam(params, "targetId");
|
|
@@ -458,7 +527,7 @@ export function createBrowserTool(opts) {
|
|
|
458
527
|
const level = typeof params.level === "string" ? params.level.trim() : undefined;
|
|
459
528
|
const targetId = typeof params.targetId === "string" ? params.targetId.trim() : undefined;
|
|
460
529
|
if (proxyRequest) {
|
|
461
|
-
const result = await proxyRequest({
|
|
530
|
+
const result = (await proxyRequest({
|
|
462
531
|
method: "GET",
|
|
463
532
|
path: "/console",
|
|
464
533
|
profile,
|
|
@@ -466,10 +535,37 @@ export function createBrowserTool(opts) {
|
|
|
466
535
|
level,
|
|
467
536
|
targetId,
|
|
468
537
|
},
|
|
538
|
+
}));
|
|
539
|
+
const wrapped = wrapBrowserExternalJson({
|
|
540
|
+
kind: "console",
|
|
541
|
+
payload: result,
|
|
542
|
+
includeWarning: false,
|
|
543
|
+
});
|
|
544
|
+
return {
|
|
545
|
+
content: [{ type: "text", text: wrapped.wrappedText }],
|
|
546
|
+
details: {
|
|
547
|
+
...wrapped.safeDetails,
|
|
548
|
+
targetId: typeof result.targetId === "string" ? result.targetId : undefined,
|
|
549
|
+
messageCount: Array.isArray(result.messages) ? result.messages.length : undefined,
|
|
550
|
+
},
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
{
|
|
554
|
+
const result = await browserConsoleMessages(baseUrl, { level, targetId, profile });
|
|
555
|
+
const wrapped = wrapBrowserExternalJson({
|
|
556
|
+
kind: "console",
|
|
557
|
+
payload: result,
|
|
558
|
+
includeWarning: false,
|
|
469
559
|
});
|
|
470
|
-
return
|
|
560
|
+
return {
|
|
561
|
+
content: [{ type: "text", text: wrapped.wrappedText }],
|
|
562
|
+
details: {
|
|
563
|
+
...wrapped.safeDetails,
|
|
564
|
+
targetId: result.targetId,
|
|
565
|
+
messageCount: result.messages.length,
|
|
566
|
+
},
|
|
567
|
+
};
|
|
471
568
|
}
|
|
472
|
-
return jsonResult(await browserConsoleMessages(baseUrl, { level, targetId, profile }));
|
|
473
569
|
}
|
|
474
570
|
case "pdf": {
|
|
475
571
|
const targetId = typeof params.targetId === "string" ? params.targetId.trim() : undefined;
|
|
@@ -488,8 +584,18 @@ export function createBrowserTool(opts) {
|
|
|
488
584
|
}
|
|
489
585
|
case "upload": {
|
|
490
586
|
const paths = Array.isArray(params.paths) ? params.paths.map((p) => String(p)) : [];
|
|
491
|
-
if (paths.length === 0)
|
|
587
|
+
if (paths.length === 0) {
|
|
492
588
|
throw new Error("paths required");
|
|
589
|
+
}
|
|
590
|
+
const uploadPathsResult = await resolveExistingPathsWithinRoot({
|
|
591
|
+
rootDir: DEFAULT_UPLOAD_DIR,
|
|
592
|
+
requestedPaths: paths,
|
|
593
|
+
scopeLabel: `uploads directory (${DEFAULT_UPLOAD_DIR})`,
|
|
594
|
+
});
|
|
595
|
+
if (!uploadPathsResult.ok) {
|
|
596
|
+
throw new Error(uploadPathsResult.error);
|
|
597
|
+
}
|
|
598
|
+
const normalizedPaths = uploadPathsResult.paths;
|
|
493
599
|
const ref = readStringParam(params, "ref");
|
|
494
600
|
const inputRef = readStringParam(params, "inputRef");
|
|
495
601
|
const element = readStringParam(params, "element");
|
|
@@ -503,7 +609,7 @@ export function createBrowserTool(opts) {
|
|
|
503
609
|
path: "/hooks/file-chooser",
|
|
504
610
|
profile,
|
|
505
611
|
body: {
|
|
506
|
-
paths,
|
|
612
|
+
paths: normalizedPaths,
|
|
507
613
|
ref,
|
|
508
614
|
inputRef,
|
|
509
615
|
element,
|
|
@@ -514,7 +620,7 @@ export function createBrowserTool(opts) {
|
|
|
514
620
|
return jsonResult(result);
|
|
515
621
|
}
|
|
516
622
|
return jsonResult(await browserArmFileChooser(baseUrl, {
|
|
517
|
-
paths,
|
|
623
|
+
paths: normalizedPaths,
|
|
518
624
|
ref,
|
|
519
625
|
inputRef,
|
|
520
626
|
element,
|
|
@@ -581,9 +687,9 @@ export function createBrowserTool(opts) {
|
|
|
581
687
|
})).tabs ?? [])
|
|
582
688
|
: await browserTabs(baseUrl, { profile }).catch(() => []);
|
|
583
689
|
if (!tabs.length) {
|
|
584
|
-
throw new Error("No Chrome tabs are attached via the
|
|
690
|
+
throw new Error("No Chrome tabs are attached via the Pool Bot Browser Relay extension. Click the toolbar icon on the tab you want to control (badge ON), then retry.", { cause: err });
|
|
585
691
|
}
|
|
586
|
-
throw new Error(`Chrome tab not found (stale targetId?). Run action=tabs profile="chrome" and use one of the returned targetIds
|
|
692
|
+
throw new Error(`Chrome tab not found (stale targetId?). Run action=tabs profile="chrome" and use one of the returned targetIds.`, { cause: err });
|
|
587
693
|
}
|
|
588
694
|
throw err;
|
|
589
695
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
3
4
|
import { Type } from "@sinclair/typebox";
|
|
4
5
|
import { writeBase64ToFile } from "../../cli/nodes-camera.js";
|
|
5
6
|
import { canvasSnapshotTempPath, parseCanvasSnapshotPayload } from "../../cli/nodes-canvas.js";
|
|
7
|
+
import { logVerbose, shouldLogVerbose } from "../../globals.js";
|
|
8
|
+
import { isInboundPathAllowed } from "../../media/inbound-path-policy.js";
|
|
9
|
+
import { getDefaultMediaLocalRoots } from "../../media/local-roots.js";
|
|
6
10
|
import { imageMimeFromFormat } from "../../media/mime.js";
|
|
7
11
|
import { resolveImageSanitizationLimits } from "../image-sanitization.js";
|
|
8
12
|
import { optionalStringEnum, stringEnum } from "../schema/typebox.js";
|
|
@@ -19,6 +23,28 @@ const CANVAS_ACTIONS = [
|
|
|
19
23
|
"a2ui_reset",
|
|
20
24
|
];
|
|
21
25
|
const CANVAS_SNAPSHOT_FORMATS = ["png", "jpg", "jpeg"];
|
|
26
|
+
async function readJsonlFromPath(jsonlPath) {
|
|
27
|
+
const trimmed = jsonlPath.trim();
|
|
28
|
+
if (!trimmed) {
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
const resolved = path.resolve(trimmed);
|
|
32
|
+
const roots = getDefaultMediaLocalRoots();
|
|
33
|
+
if (!isInboundPathAllowed({ filePath: resolved, roots })) {
|
|
34
|
+
if (shouldLogVerbose()) {
|
|
35
|
+
logVerbose(`Blocked canvas jsonlPath outside allowed roots: ${resolved}`);
|
|
36
|
+
}
|
|
37
|
+
throw new Error("jsonlPath outside allowed roots");
|
|
38
|
+
}
|
|
39
|
+
const canonical = await fs.realpath(resolved).catch(() => resolved);
|
|
40
|
+
if (!isInboundPathAllowed({ filePath: canonical, roots })) {
|
|
41
|
+
if (shouldLogVerbose()) {
|
|
42
|
+
logVerbose(`Blocked canvas jsonlPath outside allowed roots: ${canonical}`);
|
|
43
|
+
}
|
|
44
|
+
throw new Error("jsonlPath outside allowed roots");
|
|
45
|
+
}
|
|
46
|
+
return await fs.readFile(canonical, "utf8");
|
|
47
|
+
}
|
|
22
48
|
// Flattened schema: runtime validates per-action requirements.
|
|
23
49
|
const CanvasToolSchema = Type.Object({
|
|
24
50
|
action: stringEnum(CANVAS_ACTIONS),
|
|
@@ -145,7 +171,7 @@ export function createCanvasTool(options) {
|
|
|
145
171
|
const jsonl = typeof params.jsonl === "string" && params.jsonl.trim()
|
|
146
172
|
? params.jsonl
|
|
147
173
|
: typeof params.jsonlPath === "string" && params.jsonlPath.trim()
|
|
148
|
-
? await
|
|
174
|
+
? await readJsonlFromPath(params.jsonlPath)
|
|
149
175
|
: "";
|
|
150
176
|
if (!jsonl.trim()) {
|
|
151
177
|
throw new Error("jsonl or jsonlPath required");
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import { detectMime } from "../../media/mime.js";
|
|
3
3
|
import { sanitizeToolResultImages } from "../tool-images.js";
|
|
4
|
+
export const OWNER_ONLY_TOOL_ERROR = "Tool restricted to owner senders.";
|
|
4
5
|
export class ToolInputError extends Error {
|
|
5
6
|
status = 400;
|
|
6
7
|
constructor(message) {
|
|
@@ -8,6 +9,13 @@ export class ToolInputError extends Error {
|
|
|
8
9
|
this.name = "ToolInputError";
|
|
9
10
|
}
|
|
10
11
|
}
|
|
12
|
+
export class ToolAuthorizationError extends ToolInputError {
|
|
13
|
+
status = 403;
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "ToolAuthorizationError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
11
19
|
export function createActionGate(actions) {
|
|
12
20
|
return (key, defaultValue = true) => {
|
|
13
21
|
const value = actions?.[key];
|
|
@@ -131,6 +139,17 @@ export function jsonResult(payload) {
|
|
|
131
139
|
details: payload,
|
|
132
140
|
};
|
|
133
141
|
}
|
|
142
|
+
export function wrapOwnerOnlyToolExecution(tool, senderIsOwner) {
|
|
143
|
+
if (tool.ownerOnly !== true || senderIsOwner || !tool.execute) {
|
|
144
|
+
return tool;
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
...tool,
|
|
148
|
+
execute: async () => {
|
|
149
|
+
throw new Error(OWNER_ONLY_TOOL_ERROR);
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
134
153
|
export async function imageResult(params) {
|
|
135
154
|
const content = [
|
|
136
155
|
{
|
|
@@ -162,3 +181,29 @@ export async function imageResultFromFile(params) {
|
|
|
162
181
|
imageSanitization: params.imageSanitization,
|
|
163
182
|
});
|
|
164
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* Validate and parse an `availableTags` parameter from untrusted input.
|
|
186
|
+
* Returns `undefined` when the value is missing or not an array.
|
|
187
|
+
* Entries that lack a string `name` are silently dropped.
|
|
188
|
+
*/
|
|
189
|
+
export function parseAvailableTags(raw) {
|
|
190
|
+
if (raw === undefined || raw === null) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
if (!Array.isArray(raw)) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
const result = raw
|
|
197
|
+
.filter((t) => typeof t === "object" && t !== null && typeof t.name === "string")
|
|
198
|
+
.map((t) => ({
|
|
199
|
+
...(t.id !== undefined && typeof t.id === "string" ? { id: t.id } : {}),
|
|
200
|
+
name: t.name,
|
|
201
|
+
...(typeof t.moderated === "boolean" ? { moderated: t.moderated } : {}),
|
|
202
|
+
...(t.emoji_id === null || typeof t.emoji_id === "string" ? { emoji_id: t.emoji_id } : {}),
|
|
203
|
+
...(t.emoji_name === null || typeof t.emoji_name === "string"
|
|
204
|
+
? { emoji_name: t.emoji_name }
|
|
205
|
+
: {}),
|
|
206
|
+
}));
|
|
207
|
+
// Return undefined instead of empty array to avoid accidentally clearing all tags
|
|
208
|
+
return result.length ? result : undefined;
|
|
209
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { vi } from "vitest";
|
|
2
|
+
export const callGatewayMock = vi.fn();
|
|
3
|
+
vi.mock("../../gateway/call.js", () => ({
|
|
4
|
+
callGateway: (opts) => callGatewayMock(opts),
|
|
5
|
+
}));
|
|
6
|
+
vi.mock("../agent-scope.js", () => ({
|
|
7
|
+
resolveSessionAgentId: () => "agent-123",
|
|
8
|
+
}));
|
|
9
|
+
export function resetCronToolGatewayMock() {
|
|
10
|
+
callGatewayMock.mockReset();
|
|
11
|
+
callGatewayMock.mockResolvedValue({ ok: true });
|
|
12
|
+
}
|