@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,22 +1,187 @@
|
|
|
1
1
|
import { createEditTool, createReadTool, createWriteTool } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
import { detectMime } from "../media/mime.js";
|
|
3
|
+
import { sniffMimeFromBase64 } from "../media/sniff-mime-from-base64.js";
|
|
3
4
|
import { assertSandboxPath } from "./sandbox-paths.js";
|
|
4
5
|
import { sanitizeToolResultImages } from "./tool-images.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const DEFAULT_READ_PAGE_MAX_BYTES = 50 * 1024;
|
|
7
|
+
const MAX_ADAPTIVE_READ_MAX_BYTES = 512 * 1024;
|
|
8
|
+
const ADAPTIVE_READ_CONTEXT_SHARE = 0.2;
|
|
9
|
+
const CHARS_PER_TOKEN_ESTIMATE = 4;
|
|
10
|
+
const MAX_ADAPTIVE_READ_PAGES = 8;
|
|
11
|
+
const READ_CONTINUATION_NOTICE_RE = /\n\n\[(?:Showing lines [^\]]*?Use offset=\d+ to continue\.|\d+ more lines in file\. Use offset=\d+ to continue\.)\]\s*$/;
|
|
12
|
+
function clamp(value, min, max) {
|
|
13
|
+
return Math.max(min, Math.min(max, value));
|
|
14
|
+
}
|
|
15
|
+
function resolveAdaptiveReadMaxBytes(options) {
|
|
16
|
+
const contextWindowTokens = options?.modelContextWindowTokens;
|
|
17
|
+
if (typeof contextWindowTokens !== "number" ||
|
|
18
|
+
!Number.isFinite(contextWindowTokens) ||
|
|
19
|
+
contextWindowTokens <= 0) {
|
|
20
|
+
return DEFAULT_READ_PAGE_MAX_BYTES;
|
|
21
|
+
}
|
|
22
|
+
const fromContext = Math.floor(contextWindowTokens * CHARS_PER_TOKEN_ESTIMATE * ADAPTIVE_READ_CONTEXT_SHARE);
|
|
23
|
+
return clamp(fromContext, DEFAULT_READ_PAGE_MAX_BYTES, MAX_ADAPTIVE_READ_MAX_BYTES);
|
|
24
|
+
}
|
|
25
|
+
function formatBytes(bytes) {
|
|
26
|
+
if (bytes >= 1024 * 1024) {
|
|
27
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
28
|
+
}
|
|
29
|
+
if (bytes >= 1024) {
|
|
30
|
+
return `${Math.round(bytes / 1024)}KB`;
|
|
31
|
+
}
|
|
32
|
+
return `${bytes}B`;
|
|
33
|
+
}
|
|
34
|
+
function getToolResultText(result) {
|
|
35
|
+
const content = Array.isArray(result.content) ? result.content : [];
|
|
36
|
+
const textBlocks = content
|
|
37
|
+
.map((block) => {
|
|
38
|
+
if (block &&
|
|
39
|
+
typeof block === "object" &&
|
|
40
|
+
block.type === "text" &&
|
|
41
|
+
typeof block.text === "string") {
|
|
42
|
+
return block.text;
|
|
43
|
+
}
|
|
8
44
|
return undefined;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (
|
|
45
|
+
})
|
|
46
|
+
.filter((value) => typeof value === "string");
|
|
47
|
+
if (textBlocks.length === 0) {
|
|
12
48
|
return undefined;
|
|
13
|
-
try {
|
|
14
|
-
const head = Buffer.from(trimmed.slice(0, sliceLen), "base64");
|
|
15
|
-
return await detectMime({ buffer: head });
|
|
16
49
|
}
|
|
17
|
-
|
|
18
|
-
|
|
50
|
+
return textBlocks.join("\n");
|
|
51
|
+
}
|
|
52
|
+
function withToolResultText(result, text) {
|
|
53
|
+
const content = Array.isArray(result.content) ? result.content : [];
|
|
54
|
+
let replaced = false;
|
|
55
|
+
const nextContent = content.map((block) => {
|
|
56
|
+
if (!replaced &&
|
|
57
|
+
block &&
|
|
58
|
+
typeof block === "object" &&
|
|
59
|
+
block.type === "text") {
|
|
60
|
+
replaced = true;
|
|
61
|
+
return {
|
|
62
|
+
...block,
|
|
63
|
+
text,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return block;
|
|
67
|
+
});
|
|
68
|
+
if (replaced) {
|
|
69
|
+
return {
|
|
70
|
+
...result,
|
|
71
|
+
content: nextContent,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const textBlock = { type: "text", text };
|
|
75
|
+
return {
|
|
76
|
+
...result,
|
|
77
|
+
content: [textBlock],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function extractReadTruncationDetails(result) {
|
|
81
|
+
const details = result.details;
|
|
82
|
+
if (!details || typeof details !== "object") {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const truncation = details.truncation;
|
|
86
|
+
if (!truncation || typeof truncation !== "object") {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const record = truncation;
|
|
90
|
+
if (record.truncated !== true) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const outputLinesRaw = record.outputLines;
|
|
94
|
+
const outputLines = typeof outputLinesRaw === "number" && Number.isFinite(outputLinesRaw)
|
|
95
|
+
? Math.max(0, Math.floor(outputLinesRaw))
|
|
96
|
+
: 0;
|
|
97
|
+
return {
|
|
98
|
+
truncated: true,
|
|
99
|
+
outputLines,
|
|
100
|
+
firstLineExceedsLimit: record.firstLineExceedsLimit === true,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function stripReadContinuationNotice(text) {
|
|
104
|
+
return text.replace(READ_CONTINUATION_NOTICE_RE, "");
|
|
105
|
+
}
|
|
106
|
+
function stripReadTruncationContentDetails(result) {
|
|
107
|
+
const details = result.details;
|
|
108
|
+
if (!details || typeof details !== "object") {
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
const detailsRecord = details;
|
|
112
|
+
const truncationRaw = detailsRecord.truncation;
|
|
113
|
+
if (!truncationRaw || typeof truncationRaw !== "object") {
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
const truncation = truncationRaw;
|
|
117
|
+
if (!Object.prototype.hasOwnProperty.call(truncation, "content")) {
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
const { content: _content, ...restTruncation } = truncation;
|
|
121
|
+
return {
|
|
122
|
+
...result,
|
|
123
|
+
details: {
|
|
124
|
+
...detailsRecord,
|
|
125
|
+
truncation: restTruncation,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
async function executeReadWithAdaptivePaging(params) {
|
|
130
|
+
const userLimit = params.args.limit;
|
|
131
|
+
const hasExplicitLimit = typeof userLimit === "number" && Number.isFinite(userLimit) && userLimit > 0;
|
|
132
|
+
if (hasExplicitLimit) {
|
|
133
|
+
return await params.base.execute(params.toolCallId, params.args, params.signal);
|
|
134
|
+
}
|
|
135
|
+
const offsetRaw = params.args.offset;
|
|
136
|
+
let nextOffset = typeof offsetRaw === "number" && Number.isFinite(offsetRaw) && offsetRaw > 0
|
|
137
|
+
? Math.floor(offsetRaw)
|
|
138
|
+
: 1;
|
|
139
|
+
let firstResult = null;
|
|
140
|
+
let aggregatedText = "";
|
|
141
|
+
let aggregatedBytes = 0;
|
|
142
|
+
let capped = false;
|
|
143
|
+
let continuationOffset;
|
|
144
|
+
for (let page = 0; page < MAX_ADAPTIVE_READ_PAGES; page += 1) {
|
|
145
|
+
const pageArgs = { ...params.args, offset: nextOffset };
|
|
146
|
+
const pageResult = await params.base.execute(params.toolCallId, pageArgs, params.signal);
|
|
147
|
+
firstResult ??= pageResult;
|
|
148
|
+
const rawText = getToolResultText(pageResult);
|
|
149
|
+
if (typeof rawText !== "string") {
|
|
150
|
+
return pageResult;
|
|
151
|
+
}
|
|
152
|
+
const truncation = extractReadTruncationDetails(pageResult);
|
|
153
|
+
const canContinue = Boolean(truncation?.truncated) &&
|
|
154
|
+
!truncation?.firstLineExceedsLimit &&
|
|
155
|
+
(truncation?.outputLines ?? 0) > 0 &&
|
|
156
|
+
page < MAX_ADAPTIVE_READ_PAGES - 1;
|
|
157
|
+
const pageText = canContinue ? stripReadContinuationNotice(rawText) : rawText;
|
|
158
|
+
const delimiter = aggregatedText ? "\n\n" : "";
|
|
159
|
+
const nextBytes = Buffer.byteLength(`${delimiter}${pageText}`, "utf-8");
|
|
160
|
+
if (aggregatedText && aggregatedBytes + nextBytes > params.maxBytes) {
|
|
161
|
+
capped = true;
|
|
162
|
+
continuationOffset = nextOffset;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
aggregatedText += `${delimiter}${pageText}`;
|
|
166
|
+
aggregatedBytes += nextBytes;
|
|
167
|
+
if (!canContinue || !truncation) {
|
|
168
|
+
return withToolResultText(pageResult, aggregatedText);
|
|
169
|
+
}
|
|
170
|
+
nextOffset += truncation.outputLines;
|
|
171
|
+
continuationOffset = nextOffset;
|
|
172
|
+
if (aggregatedBytes >= params.maxBytes) {
|
|
173
|
+
capped = true;
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (!firstResult) {
|
|
178
|
+
return await params.base.execute(params.toolCallId, params.args, params.signal);
|
|
179
|
+
}
|
|
180
|
+
let finalText = aggregatedText;
|
|
181
|
+
if (capped && continuationOffset) {
|
|
182
|
+
finalText += `\n\n[Read output capped at ${formatBytes(params.maxBytes)} for this call. Use offset=${continuationOffset} to continue.]`;
|
|
19
183
|
}
|
|
184
|
+
return withToolResultText(firstResult, finalText);
|
|
20
185
|
}
|
|
21
186
|
function rewriteReadImageHeader(text, mimeType) {
|
|
22
187
|
// pi-coding-agent uses: "Read image file [image/png]"
|
|
@@ -32,19 +197,22 @@ async function normalizeReadImageResult(result, filePath) {
|
|
|
32
197
|
b.type === "image" &&
|
|
33
198
|
typeof b.data === "string" &&
|
|
34
199
|
typeof b.mimeType === "string");
|
|
35
|
-
if (!image)
|
|
200
|
+
if (!image) {
|
|
36
201
|
return result;
|
|
202
|
+
}
|
|
37
203
|
if (!image.data.trim()) {
|
|
38
204
|
throw new Error(`read: image payload is empty (${filePath})`);
|
|
39
205
|
}
|
|
40
206
|
const sniffed = await sniffMimeFromBase64(image.data);
|
|
41
|
-
if (!sniffed)
|
|
207
|
+
if (!sniffed) {
|
|
42
208
|
return result;
|
|
209
|
+
}
|
|
43
210
|
if (!sniffed.startsWith("image/")) {
|
|
44
211
|
throw new Error(`read: file looks like ${sniffed} but was treated as ${image.mimeType} (${filePath})`);
|
|
45
212
|
}
|
|
46
|
-
if (sniffed === image.mimeType)
|
|
213
|
+
if (sniffed === image.mimeType) {
|
|
47
214
|
return result;
|
|
215
|
+
}
|
|
48
216
|
const nextContent = content.map((block) => {
|
|
49
217
|
if (block && typeof block === "object" && block.type === "image") {
|
|
50
218
|
const b = block;
|
|
@@ -64,9 +232,16 @@ async function normalizeReadImageResult(result, filePath) {
|
|
|
64
232
|
});
|
|
65
233
|
return { ...result, content: nextContent };
|
|
66
234
|
}
|
|
235
|
+
const RETRY_GUIDANCE_SUFFIX = " Supply correct parameters before retrying.";
|
|
236
|
+
function parameterValidationError(message) {
|
|
237
|
+
return new Error(`${message}.${RETRY_GUIDANCE_SUFFIX}`);
|
|
238
|
+
}
|
|
67
239
|
export const CLAUDE_PARAM_GROUPS = {
|
|
68
240
|
read: [{ keys: ["path", "file_path"], label: "path (path or file_path)" }],
|
|
69
|
-
write: [
|
|
241
|
+
write: [
|
|
242
|
+
{ keys: ["path", "file_path"], label: "path (path or file_path)" },
|
|
243
|
+
{ keys: ["content"], label: "content" },
|
|
244
|
+
],
|
|
70
245
|
edit: [
|
|
71
246
|
{ keys: ["path", "file_path"], label: "path (path or file_path)" },
|
|
72
247
|
{
|
|
@@ -79,12 +254,61 @@ export const CLAUDE_PARAM_GROUPS = {
|
|
|
79
254
|
},
|
|
80
255
|
],
|
|
81
256
|
};
|
|
257
|
+
function extractStructuredText(value, depth = 0) {
|
|
258
|
+
if (depth > 6) {
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
if (typeof value === "string") {
|
|
262
|
+
return value;
|
|
263
|
+
}
|
|
264
|
+
if (Array.isArray(value)) {
|
|
265
|
+
const parts = value
|
|
266
|
+
.map((entry) => extractStructuredText(entry, depth + 1))
|
|
267
|
+
.filter((entry) => typeof entry === "string");
|
|
268
|
+
return parts.length > 0 ? parts.join("") : undefined;
|
|
269
|
+
}
|
|
270
|
+
if (!value || typeof value !== "object") {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
const record = value;
|
|
274
|
+
if (typeof record.text === "string") {
|
|
275
|
+
return record.text;
|
|
276
|
+
}
|
|
277
|
+
if (typeof record.content === "string") {
|
|
278
|
+
return record.content;
|
|
279
|
+
}
|
|
280
|
+
if (Array.isArray(record.content)) {
|
|
281
|
+
return extractStructuredText(record.content, depth + 1);
|
|
282
|
+
}
|
|
283
|
+
if (Array.isArray(record.parts)) {
|
|
284
|
+
return extractStructuredText(record.parts, depth + 1);
|
|
285
|
+
}
|
|
286
|
+
if (typeof record.value === "string" && record.value.length > 0) {
|
|
287
|
+
const type = typeof record.type === "string" ? record.type.toLowerCase() : "";
|
|
288
|
+
const kind = typeof record.kind === "string" ? record.kind.toLowerCase() : "";
|
|
289
|
+
if (type.includes("text") || kind === "text") {
|
|
290
|
+
return record.value;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
function normalizeTextLikeParam(record, key) {
|
|
296
|
+
const value = record[key];
|
|
297
|
+
if (typeof value === "string") {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
const extracted = extractStructuredText(value);
|
|
301
|
+
if (typeof extracted === "string") {
|
|
302
|
+
record[key] = extracted;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
82
305
|
// Normalize tool parameters from Claude Code conventions to pi-coding-agent conventions.
|
|
83
306
|
// Claude Code uses file_path/old_string/new_string while pi-coding-agent uses path/oldText/newText.
|
|
84
307
|
// This prevents models trained on Claude Code from getting stuck in tool-call loops.
|
|
85
308
|
export function normalizeToolParams(params) {
|
|
86
|
-
if (!params || typeof params !== "object")
|
|
309
|
+
if (!params || typeof params !== "object") {
|
|
87
310
|
return undefined;
|
|
311
|
+
}
|
|
88
312
|
const record = params;
|
|
89
313
|
const normalized = { ...record };
|
|
90
314
|
// file_path → path (read, write, edit)
|
|
@@ -102,6 +326,11 @@ export function normalizeToolParams(params) {
|
|
|
102
326
|
normalized.newText = normalized.new_string;
|
|
103
327
|
delete normalized.new_string;
|
|
104
328
|
}
|
|
329
|
+
// Some providers/models emit text payloads as structured blocks instead of raw strings.
|
|
330
|
+
// Normalize these for write/edit so content matching and writes stay deterministic.
|
|
331
|
+
normalizeTextLikeParam(normalized, "content");
|
|
332
|
+
normalizeTextLikeParam(normalized, "oldText");
|
|
333
|
+
normalizeTextLikeParam(normalized, "newText");
|
|
105
334
|
return normalized;
|
|
106
335
|
}
|
|
107
336
|
export function patchToolSchemaForClaudeCompatibility(tool) {
|
|
@@ -122,8 +351,9 @@ export function patchToolSchemaForClaudeCompatibility(tool) {
|
|
|
122
351
|
{ original: "newText", alias: "new_string" },
|
|
123
352
|
];
|
|
124
353
|
for (const { original, alias } of aliasPairs) {
|
|
125
|
-
if (!(original in properties))
|
|
354
|
+
if (!(original in properties)) {
|
|
126
355
|
continue;
|
|
356
|
+
}
|
|
127
357
|
if (!(alias in properties)) {
|
|
128
358
|
properties[alias] = properties[original];
|
|
129
359
|
changed = true;
|
|
@@ -134,37 +364,47 @@ export function patchToolSchemaForClaudeCompatibility(tool) {
|
|
|
134
364
|
changed = true;
|
|
135
365
|
}
|
|
136
366
|
}
|
|
137
|
-
if (!changed)
|
|
367
|
+
if (!changed) {
|
|
138
368
|
return tool;
|
|
369
|
+
}
|
|
139
370
|
return {
|
|
140
371
|
...tool,
|
|
141
372
|
parameters: {
|
|
142
373
|
...schema,
|
|
143
374
|
properties,
|
|
144
|
-
|
|
375
|
+
required,
|
|
145
376
|
},
|
|
146
377
|
};
|
|
147
378
|
}
|
|
148
379
|
export function assertRequiredParams(record, groups, toolName) {
|
|
149
380
|
if (!record || typeof record !== "object") {
|
|
150
|
-
throw
|
|
381
|
+
throw parameterValidationError(`Missing parameters for ${toolName}`);
|
|
151
382
|
}
|
|
383
|
+
const missingLabels = [];
|
|
152
384
|
for (const group of groups) {
|
|
153
385
|
const satisfied = group.keys.some((key) => {
|
|
154
|
-
if (!(key in record))
|
|
386
|
+
if (!(key in record)) {
|
|
155
387
|
return false;
|
|
388
|
+
}
|
|
156
389
|
const value = record[key];
|
|
157
|
-
if (typeof value !== "string")
|
|
390
|
+
if (typeof value !== "string") {
|
|
158
391
|
return false;
|
|
159
|
-
|
|
392
|
+
}
|
|
393
|
+
if (group.allowEmpty) {
|
|
160
394
|
return true;
|
|
395
|
+
}
|
|
161
396
|
return value.trim().length > 0;
|
|
162
397
|
});
|
|
163
398
|
if (!satisfied) {
|
|
164
399
|
const label = group.label ?? group.keys.join(" or ");
|
|
165
|
-
|
|
400
|
+
missingLabels.push(label);
|
|
166
401
|
}
|
|
167
402
|
}
|
|
403
|
+
if (missingLabels.length > 0) {
|
|
404
|
+
const joined = missingLabels.join(", ");
|
|
405
|
+
const noun = missingLabels.length === 1 ? "parameter" : "parameters";
|
|
406
|
+
throw parameterValidationError(`Missing required ${noun}: ${joined}`);
|
|
407
|
+
}
|
|
168
408
|
}
|
|
169
409
|
// Generic wrapper to normalize parameters for any tool
|
|
170
410
|
export function wrapToolParamNormalization(tool, requiredParamGroups) {
|
|
@@ -182,7 +422,7 @@ export function wrapToolParamNormalization(tool, requiredParamGroups) {
|
|
|
182
422
|
},
|
|
183
423
|
};
|
|
184
424
|
}
|
|
185
|
-
function
|
|
425
|
+
export function wrapToolWorkspaceRootGuard(tool, root) {
|
|
186
426
|
return {
|
|
187
427
|
...tool,
|
|
188
428
|
execute: async (toolCallId, args, signal, onUpdate) => {
|
|
@@ -197,19 +437,28 @@ function wrapSandboxPathGuard(tool, root) {
|
|
|
197
437
|
},
|
|
198
438
|
};
|
|
199
439
|
}
|
|
200
|
-
export function createSandboxedReadTool(
|
|
201
|
-
const base = createReadTool(root
|
|
202
|
-
|
|
440
|
+
export function createSandboxedReadTool(params) {
|
|
441
|
+
const base = createReadTool(params.root, {
|
|
442
|
+
operations: createSandboxReadOperations(params),
|
|
443
|
+
});
|
|
444
|
+
return createPoolbotReadTool(base, {
|
|
445
|
+
modelContextWindowTokens: params.modelContextWindowTokens,
|
|
446
|
+
imageSanitization: params.imageSanitization,
|
|
447
|
+
});
|
|
203
448
|
}
|
|
204
|
-
export function createSandboxedWriteTool(
|
|
205
|
-
const base = createWriteTool(root
|
|
206
|
-
|
|
449
|
+
export function createSandboxedWriteTool(params) {
|
|
450
|
+
const base = createWriteTool(params.root, {
|
|
451
|
+
operations: createSandboxWriteOperations(params),
|
|
452
|
+
});
|
|
453
|
+
return wrapToolParamNormalization(base, CLAUDE_PARAM_GROUPS.write);
|
|
207
454
|
}
|
|
208
|
-
export function createSandboxedEditTool(
|
|
209
|
-
const base = createEditTool(root
|
|
210
|
-
|
|
455
|
+
export function createSandboxedEditTool(params) {
|
|
456
|
+
const base = createEditTool(params.root, {
|
|
457
|
+
operations: createSandboxEditOperations(params),
|
|
458
|
+
});
|
|
459
|
+
return wrapToolParamNormalization(base, CLAUDE_PARAM_GROUPS.edit);
|
|
211
460
|
}
|
|
212
|
-
export function createPoolbotReadTool(base) {
|
|
461
|
+
export function createPoolbotReadTool(base, options) {
|
|
213
462
|
const patched = patchToolSchemaForClaudeCompatibility(base);
|
|
214
463
|
return {
|
|
215
464
|
...patched,
|
|
@@ -218,10 +467,60 @@ export function createPoolbotReadTool(base) {
|
|
|
218
467
|
const record = normalized ??
|
|
219
468
|
(params && typeof params === "object" ? params : undefined);
|
|
220
469
|
assertRequiredParams(record, CLAUDE_PARAM_GROUPS.read, base.name);
|
|
221
|
-
const result =
|
|
470
|
+
const result = await executeReadWithAdaptivePaging({
|
|
471
|
+
base,
|
|
472
|
+
toolCallId,
|
|
473
|
+
args: (normalized ?? params ?? {}),
|
|
474
|
+
signal,
|
|
475
|
+
maxBytes: resolveAdaptiveReadMaxBytes(options),
|
|
476
|
+
});
|
|
222
477
|
const filePath = typeof record?.path === "string" ? String(record.path) : "<unknown>";
|
|
223
|
-
const
|
|
224
|
-
|
|
478
|
+
const strippedDetailsResult = stripReadTruncationContentDetails(result);
|
|
479
|
+
const normalizedResult = await normalizeReadImageResult(strippedDetailsResult, filePath);
|
|
480
|
+
return sanitizeToolResultImages(normalizedResult, `read:${filePath}`, options?.imageSanitization);
|
|
225
481
|
},
|
|
226
482
|
};
|
|
227
483
|
}
|
|
484
|
+
function createSandboxReadOperations(params) {
|
|
485
|
+
return {
|
|
486
|
+
readFile: (absolutePath) => params.bridge.readFile({ filePath: absolutePath, cwd: params.root }),
|
|
487
|
+
access: async (absolutePath) => {
|
|
488
|
+
const stat = await params.bridge.stat({ filePath: absolutePath, cwd: params.root });
|
|
489
|
+
if (!stat) {
|
|
490
|
+
throw createFsAccessError("ENOENT", absolutePath);
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
detectImageMimeType: async (absolutePath) => {
|
|
494
|
+
const buffer = await params.bridge.readFile({ filePath: absolutePath, cwd: params.root });
|
|
495
|
+
const mime = await detectMime({ buffer, filePath: absolutePath });
|
|
496
|
+
return mime && mime.startsWith("image/") ? mime : undefined;
|
|
497
|
+
},
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
function createSandboxWriteOperations(params) {
|
|
501
|
+
return {
|
|
502
|
+
mkdir: async (dir) => {
|
|
503
|
+
await params.bridge.mkdirp({ filePath: dir, cwd: params.root });
|
|
504
|
+
},
|
|
505
|
+
writeFile: async (absolutePath, content) => {
|
|
506
|
+
await params.bridge.writeFile({ filePath: absolutePath, cwd: params.root, data: content });
|
|
507
|
+
},
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
function createSandboxEditOperations(params) {
|
|
511
|
+
return {
|
|
512
|
+
readFile: (absolutePath) => params.bridge.readFile({ filePath: absolutePath, cwd: params.root }),
|
|
513
|
+
writeFile: (absolutePath, content) => params.bridge.writeFile({ filePath: absolutePath, cwd: params.root, data: content }),
|
|
514
|
+
access: async (absolutePath) => {
|
|
515
|
+
const stat = await params.bridge.stat({ filePath: absolutePath, cwd: params.root });
|
|
516
|
+
if (!stat) {
|
|
517
|
+
throw createFsAccessError("ENOENT", absolutePath);
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
function createFsAccessError(code, filePath) {
|
|
523
|
+
const error = new Error(`Sandbox FS error (${code}): ${filePath}`);
|
|
524
|
+
error.code = code;
|
|
525
|
+
return error;
|
|
526
|
+
}
|
|
@@ -4,8 +4,8 @@ import { createAgentsListTool } from "./tools/agents-list-tool.js";
|
|
|
4
4
|
import { createBrowserTool } from "./tools/browser-tool.js";
|
|
5
5
|
import { createCanvasTool } from "./tools/canvas-tool.js";
|
|
6
6
|
import { createCronTool } from "./tools/cron-tool.js";
|
|
7
|
-
import { createGatewayTool } from "./tools/gateway-tool.js";
|
|
8
7
|
import { createDeepResearchTool } from "./tools/deep-research-tool.js";
|
|
8
|
+
import { createGatewayTool } from "./tools/gateway-tool.js";
|
|
9
9
|
import { createImageGenerateTool } from "./tools/image-generate-tool.js";
|
|
10
10
|
import { createImageTool } from "./tools/image-tool.js";
|
|
11
11
|
import { createMessageTool } from "./tools/message-tool.js";
|
|
@@ -15,14 +15,20 @@ import { createSessionsHistoryTool } from "./tools/sessions-history-tool.js";
|
|
|
15
15
|
import { createSessionsListTool } from "./tools/sessions-list-tool.js";
|
|
16
16
|
import { createSessionsSendTool } from "./tools/sessions-send-tool.js";
|
|
17
17
|
import { createSessionsSpawnTool } from "./tools/sessions-spawn-tool.js";
|
|
18
|
-
import {
|
|
18
|
+
import { createSubagentsTool } from "./tools/subagents-tool.js";
|
|
19
19
|
import { createTtsTool } from "./tools/tts-tool.js";
|
|
20
|
+
import { createWebFetchTool, createWebSearchTool } from "./tools/web-tools.js";
|
|
21
|
+
import { resolveWorkspaceRoot } from "./workspace-dir.js";
|
|
20
22
|
export function createPoolBotTools(options) {
|
|
23
|
+
const workspaceDir = resolveWorkspaceRoot(options?.workspaceDir);
|
|
21
24
|
const imageTool = options?.agentDir?.trim()
|
|
22
25
|
? createImageTool({
|
|
23
26
|
config: options?.config,
|
|
24
27
|
agentDir: options.agentDir,
|
|
25
|
-
|
|
28
|
+
workspaceDir,
|
|
29
|
+
sandbox: options?.sandboxRoot && options?.sandboxFsBridge
|
|
30
|
+
? { root: options.sandboxRoot, bridge: options.sandboxFsBridge }
|
|
31
|
+
: undefined,
|
|
26
32
|
modelHasVision: options?.modelHasVision,
|
|
27
33
|
})
|
|
28
34
|
: null;
|
|
@@ -58,7 +64,7 @@ export function createPoolBotTools(options) {
|
|
|
58
64
|
sandboxBridgeUrl: options?.sandboxBrowserBridgeUrl,
|
|
59
65
|
allowHostControl: options?.allowHostBrowserControl,
|
|
60
66
|
}),
|
|
61
|
-
createCanvasTool(),
|
|
67
|
+
createCanvasTool({ config: options?.config }),
|
|
62
68
|
createNodesTool({
|
|
63
69
|
agentSessionKey: options?.agentSessionKey,
|
|
64
70
|
config: options?.config,
|
|
@@ -104,6 +110,9 @@ export function createPoolBotTools(options) {
|
|
|
104
110
|
sandboxed: options?.sandboxed,
|
|
105
111
|
requesterAgentIdOverride: options?.requesterAgentIdOverride,
|
|
106
112
|
}),
|
|
113
|
+
createSubagentsTool({
|
|
114
|
+
agentSessionKey: options?.agentSessionKey,
|
|
115
|
+
}),
|
|
107
116
|
createSessionStatusTool({
|
|
108
117
|
agentSessionKey: options?.agentSessionKey,
|
|
109
118
|
config: options?.config,
|
|
@@ -124,7 +133,7 @@ export function createPoolBotTools(options) {
|
|
|
124
133
|
const pluginTools = resolvePluginTools({
|
|
125
134
|
context: {
|
|
126
135
|
config: options?.config,
|
|
127
|
-
workspaceDir
|
|
136
|
+
workspaceDir,
|
|
128
137
|
agentDir: options?.agentDir,
|
|
129
138
|
agentId: resolveSessionAgentId({
|
|
130
139
|
sessionKey: options?.agentSessionKey,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { sanitizeEnvVars } from "./sanitize-env-vars.js";
|
|
2
3
|
function createAbortError() {
|
|
3
4
|
const err = new Error("Aborted");
|
|
4
5
|
err.name = "AbortError";
|
|
@@ -209,11 +210,15 @@ export function buildSandboxCreateArgs(params) {
|
|
|
209
210
|
if (params.cfg.user) {
|
|
210
211
|
args.push("--user", params.cfg.user);
|
|
211
212
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
213
|
+
const envSanitization = sanitizeEnvVars(params.cfg.env ?? {});
|
|
214
|
+
if (envSanitization.blocked.length > 0) {
|
|
215
|
+
console.warn("[Security] Blocked sensitive environment variables:", envSanitization.blocked.join(", "));
|
|
216
|
+
}
|
|
217
|
+
if (envSanitization.warnings.length > 0) {
|
|
218
|
+
console.warn("[Security] Suspicious environment variables:", envSanitization.warnings);
|
|
219
|
+
}
|
|
220
|
+
for (const [key, value] of Object.entries(envSanitization.allowed)) {
|
|
221
|
+
args.push("--env", `${key}=${value}`);
|
|
217
222
|
}
|
|
218
223
|
for (const cap of params.cfg.capDrop) {
|
|
219
224
|
args.push("--cap-drop", cap);
|