@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,9 +1,22 @@
|
|
|
1
1
|
import { resolveAgentConfig } from "../agent-scope.js";
|
|
2
|
-
import { DEFAULT_SANDBOX_BROWSER_AUTOSTART_TIMEOUT_MS, DEFAULT_SANDBOX_BROWSER_CDP_PORT, DEFAULT_SANDBOX_BROWSER_IMAGE, DEFAULT_SANDBOX_BROWSER_NOVNC_PORT, DEFAULT_SANDBOX_BROWSER_PREFIX, DEFAULT_SANDBOX_BROWSER_VNC_PORT, DEFAULT_SANDBOX_CONTAINER_PREFIX, DEFAULT_SANDBOX_IDLE_HOURS, DEFAULT_SANDBOX_IMAGE, DEFAULT_SANDBOX_MAX_AGE_DAYS, DEFAULT_SANDBOX_WORKDIR, DEFAULT_SANDBOX_WORKSPACE_ROOT, } from "./constants.js";
|
|
2
|
+
import { DEFAULT_SANDBOX_BROWSER_AUTOSTART_TIMEOUT_MS, DEFAULT_SANDBOX_BROWSER_CDP_PORT, DEFAULT_SANDBOX_BROWSER_IMAGE, DEFAULT_SANDBOX_BROWSER_NETWORK, DEFAULT_SANDBOX_BROWSER_NOVNC_PORT, DEFAULT_SANDBOX_BROWSER_PREFIX, DEFAULT_SANDBOX_BROWSER_VNC_PORT, DEFAULT_SANDBOX_CONTAINER_PREFIX, DEFAULT_SANDBOX_IDLE_HOURS, DEFAULT_SANDBOX_IMAGE, DEFAULT_SANDBOX_MAX_AGE_DAYS, DEFAULT_SANDBOX_WORKDIR, DEFAULT_SANDBOX_WORKSPACE_ROOT, } from "./constants.js";
|
|
3
3
|
import { resolveSandboxToolPolicyForAgent } from "./tool-policy.js";
|
|
4
|
+
export function resolveSandboxBrowserDockerCreateConfig(params) {
|
|
5
|
+
const browserNetwork = params.browser.network.trim();
|
|
6
|
+
const base = {
|
|
7
|
+
...params.docker,
|
|
8
|
+
// Browser container needs network access for Chrome, downloads, etc.
|
|
9
|
+
network: browserNetwork || DEFAULT_SANDBOX_BROWSER_NETWORK,
|
|
10
|
+
// For hashing and consistency, treat browser image as the docker image even though we
|
|
11
|
+
// pass it separately as the final `docker create` argument.
|
|
12
|
+
image: params.browser.image,
|
|
13
|
+
};
|
|
14
|
+
return params.browser.binds !== undefined ? { ...base, binds: params.browser.binds } : base;
|
|
15
|
+
}
|
|
4
16
|
export function resolveSandboxScope(params) {
|
|
5
|
-
if (params.scope)
|
|
17
|
+
if (params.scope) {
|
|
6
18
|
return params.scope;
|
|
19
|
+
}
|
|
7
20
|
if (typeof params.perSession === "boolean") {
|
|
8
21
|
return params.perSession ? "session" : "shared";
|
|
9
22
|
}
|
|
@@ -47,13 +60,18 @@ export function resolveSandboxDockerConfig(params) {
|
|
|
47
60
|
export function resolveSandboxBrowserConfig(params) {
|
|
48
61
|
const agentBrowser = params.scope === "shared" ? undefined : params.agentBrowser;
|
|
49
62
|
const globalBrowser = params.globalBrowser;
|
|
63
|
+
const binds = [...(globalBrowser?.binds ?? []), ...(agentBrowser?.binds ?? [])];
|
|
64
|
+
// Treat `binds: []` as an explicit override, so it can disable `docker.binds` for the browser container.
|
|
65
|
+
const bindsConfigured = globalBrowser?.binds !== undefined || agentBrowser?.binds !== undefined;
|
|
50
66
|
return {
|
|
51
67
|
enabled: agentBrowser?.enabled ?? globalBrowser?.enabled ?? false,
|
|
52
68
|
image: agentBrowser?.image ?? globalBrowser?.image ?? DEFAULT_SANDBOX_BROWSER_IMAGE,
|
|
53
69
|
containerPrefix: agentBrowser?.containerPrefix ??
|
|
54
70
|
globalBrowser?.containerPrefix ??
|
|
55
71
|
DEFAULT_SANDBOX_BROWSER_PREFIX,
|
|
72
|
+
network: agentBrowser?.network ?? globalBrowser?.network ?? DEFAULT_SANDBOX_BROWSER_NETWORK,
|
|
56
73
|
cdpPort: agentBrowser?.cdpPort ?? globalBrowser?.cdpPort ?? DEFAULT_SANDBOX_BROWSER_CDP_PORT,
|
|
74
|
+
cdpSourceRange: agentBrowser?.cdpSourceRange ?? globalBrowser?.cdpSourceRange,
|
|
57
75
|
vncPort: agentBrowser?.vncPort ?? globalBrowser?.vncPort ?? DEFAULT_SANDBOX_BROWSER_VNC_PORT,
|
|
58
76
|
noVncPort: agentBrowser?.noVncPort ?? globalBrowser?.noVncPort ?? DEFAULT_SANDBOX_BROWSER_NOVNC_PORT,
|
|
59
77
|
headless: agentBrowser?.headless ?? globalBrowser?.headless ?? false,
|
|
@@ -63,6 +81,7 @@ export function resolveSandboxBrowserConfig(params) {
|
|
|
63
81
|
autoStartTimeoutMs: agentBrowser?.autoStartTimeoutMs ??
|
|
64
82
|
globalBrowser?.autoStartTimeoutMs ??
|
|
65
83
|
DEFAULT_SANDBOX_BROWSER_AUTOSTART_TIMEOUT_MS,
|
|
84
|
+
binds: bindsConfigured ? binds : undefined,
|
|
66
85
|
};
|
|
67
86
|
}
|
|
68
87
|
export function resolveSandboxPruneConfig(params) {
|
|
@@ -43,3 +43,5 @@ const resolvedSandboxStateDir = STATE_DIR ?? path.join(os.homedir(), ".poolbot")
|
|
|
43
43
|
export const SANDBOX_STATE_DIR = path.join(resolvedSandboxStateDir, "sandbox");
|
|
44
44
|
export const SANDBOX_REGISTRY_PATH = path.join(SANDBOX_STATE_DIR, "containers.json");
|
|
45
45
|
export const SANDBOX_BROWSER_REGISTRY_PATH = path.join(SANDBOX_STATE_DIR, "browsers.json");
|
|
46
|
+
export const SANDBOX_BROWSER_SECURITY_HASH_EPOCH = "2026-02-21-novnc-auth-default";
|
|
47
|
+
export const DEFAULT_SANDBOX_BROWSER_NETWORK = "poolbot-sandbox-browser";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
|
2
3
|
import { sanitizeEnvVars } from "./sanitize-env-vars.js";
|
|
3
4
|
function createAbortError() {
|
|
4
5
|
const err = new Error("Aborted");
|
|
@@ -82,6 +83,7 @@ import { DEFAULT_SANDBOX_IMAGE, SANDBOX_AGENT_WORKSPACE_MOUNT } from "./constant
|
|
|
82
83
|
import { readRegistry, updateRegistry } from "./registry.js";
|
|
83
84
|
import { resolveSandboxAgentId, resolveSandboxScopeKey, slugifySessionKey } from "./shared.js";
|
|
84
85
|
import { validateSandboxSecurity } from "./validate-sandbox-security.js";
|
|
86
|
+
const log = createSubsystemLogger("docker");
|
|
85
87
|
const HOT_CONTAINER_WINDOW_MS = 5 * 60 * 1000;
|
|
86
88
|
export async function execDocker(args, opts) {
|
|
87
89
|
const result = await execDockerRaw(args, opts);
|
|
@@ -102,6 +104,18 @@ export async function readDockerContainerLabel(containerName, label) {
|
|
|
102
104
|
}
|
|
103
105
|
return raw;
|
|
104
106
|
}
|
|
107
|
+
export async function readDockerContainerEnvVar(containerName, envVar) {
|
|
108
|
+
const result = await execDocker(["inspect", "-f", "{{range .Config.Env}}{{println .}}{{end}}", containerName], { allowFailure: true });
|
|
109
|
+
if (result.code !== 0) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
for (const line of result.stdout.split(/\r?\n/)) {
|
|
113
|
+
if (line.startsWith(`${envVar}=`)) {
|
|
114
|
+
return line.slice(envVar.length + 1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
105
119
|
export async function readDockerPort(containerName, port) {
|
|
106
120
|
const result = await execDocker(["port", containerName, `${port}/tcp`], {
|
|
107
121
|
allowFailure: true,
|
|
@@ -212,10 +226,10 @@ export function buildSandboxCreateArgs(params) {
|
|
|
212
226
|
}
|
|
213
227
|
const envSanitization = sanitizeEnvVars(params.cfg.env ?? {});
|
|
214
228
|
if (envSanitization.blocked.length > 0) {
|
|
215
|
-
|
|
229
|
+
log.warn(`Blocked sensitive environment variables: ${envSanitization.blocked.join(", ")}`);
|
|
216
230
|
}
|
|
217
231
|
if (envSanitization.warnings.length > 0) {
|
|
218
|
-
|
|
232
|
+
log.warn(`Suspicious environment variables: ${envSanitization.warnings.join(", ")}`);
|
|
219
233
|
}
|
|
220
234
|
for (const [key, value] of Object.entries(envSanitization.allowed)) {
|
|
221
235
|
args.push("--env", `${key}=${value}`);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
export const NOVNC_PASSWORD_ENV_KEY = "POOLBOT_BROWSER_NOVNC_PASSWORD";
|
|
3
|
+
const NOVNC_TOKEN_TTL_MS = 5 * 60 * 1000;
|
|
4
|
+
const NO_VNC_OBSERVER_TOKENS = new Map();
|
|
5
|
+
function pruneExpiredNoVncObserverTokens(now) {
|
|
6
|
+
for (const [token, entry] of NO_VNC_OBSERVER_TOKENS) {
|
|
7
|
+
if (entry.expiresAt <= now) {
|
|
8
|
+
NO_VNC_OBSERVER_TOKENS.delete(token);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function isNoVncEnabled(params) {
|
|
13
|
+
return params.enableNoVnc && !params.headless;
|
|
14
|
+
}
|
|
15
|
+
export function generateNoVncPassword() {
|
|
16
|
+
// VNC auth uses an 8-char password max.
|
|
17
|
+
return crypto.randomBytes(4).toString("hex");
|
|
18
|
+
}
|
|
19
|
+
export function buildNoVncDirectUrl(port, password) {
|
|
20
|
+
const query = new URLSearchParams({
|
|
21
|
+
autoconnect: "1",
|
|
22
|
+
resize: "remote",
|
|
23
|
+
});
|
|
24
|
+
if (password?.trim()) {
|
|
25
|
+
query.set("password", password);
|
|
26
|
+
}
|
|
27
|
+
return `http://127.0.0.1:${port}/vnc.html?${query.toString()}`;
|
|
28
|
+
}
|
|
29
|
+
export function issueNoVncObserverToken(params) {
|
|
30
|
+
const now = params.nowMs ?? Date.now();
|
|
31
|
+
pruneExpiredNoVncObserverTokens(now);
|
|
32
|
+
const token = crypto.randomBytes(24).toString("hex");
|
|
33
|
+
NO_VNC_OBSERVER_TOKENS.set(token, {
|
|
34
|
+
url: params.url,
|
|
35
|
+
expiresAt: now + Math.max(1, params.ttlMs ?? NOVNC_TOKEN_TTL_MS),
|
|
36
|
+
});
|
|
37
|
+
return token;
|
|
38
|
+
}
|
|
39
|
+
export function consumeNoVncObserverToken(token, nowMs) {
|
|
40
|
+
const now = nowMs ?? Date.now();
|
|
41
|
+
pruneExpiredNoVncObserverTokens(now);
|
|
42
|
+
const normalized = token.trim();
|
|
43
|
+
if (!normalized) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const entry = NO_VNC_OBSERVER_TOKENS.get(normalized);
|
|
47
|
+
if (!entry) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
NO_VNC_OBSERVER_TOKENS.delete(normalized);
|
|
51
|
+
if (entry.expiresAt <= now) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
return entry.url;
|
|
55
|
+
}
|
|
56
|
+
export function buildNoVncObserverTokenUrl(baseUrl, token) {
|
|
57
|
+
const query = new URLSearchParams({ token });
|
|
58
|
+
return `${baseUrl}/sandbox/novnc?${query.toString()}`;
|
|
59
|
+
}
|
|
60
|
+
export function resetNoVncObserverTokensForTests() {
|
|
61
|
+
NO_VNC_OBSERVER_TOKENS.clear();
|
|
62
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import crypto from "node:crypto";
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { normalizeAgentId } from "../../routing/session-key.js";
|
|
4
3
|
import { resolveUserPath } from "../../utils.js";
|
|
5
4
|
import { resolveAgentIdFromSessionKey } from "../agent-scope.js";
|
|
5
|
+
import { hashTextSha256 } from "./hash.js";
|
|
6
6
|
export function slugifySessionKey(value) {
|
|
7
7
|
const trimmed = value.trim() || "session";
|
|
8
|
-
const hash =
|
|
8
|
+
const hash = hashTextSha256(trimmed).slice(0, 8);
|
|
9
9
|
const safe = trimmed
|
|
10
10
|
.toLowerCase()
|
|
11
11
|
.replace(/[^a-z0-9._-]+/g, "-")
|
|
@@ -20,19 +20,23 @@ export function resolveSandboxWorkspaceDir(root, sessionKey) {
|
|
|
20
20
|
}
|
|
21
21
|
export function resolveSandboxScopeKey(scope, sessionKey) {
|
|
22
22
|
const trimmed = sessionKey.trim() || "main";
|
|
23
|
-
if (scope === "shared")
|
|
23
|
+
if (scope === "shared") {
|
|
24
24
|
return "shared";
|
|
25
|
-
|
|
25
|
+
}
|
|
26
|
+
if (scope === "session") {
|
|
26
27
|
return trimmed;
|
|
28
|
+
}
|
|
27
29
|
const agentId = resolveAgentIdFromSessionKey(trimmed);
|
|
28
30
|
return `agent:${agentId}`;
|
|
29
31
|
}
|
|
30
32
|
export function resolveSandboxAgentId(scopeKey) {
|
|
31
33
|
const trimmed = scopeKey.trim();
|
|
32
|
-
if (!trimmed || trimmed === "shared")
|
|
34
|
+
if (!trimmed || trimmed === "shared") {
|
|
33
35
|
return undefined;
|
|
36
|
+
}
|
|
34
37
|
const parts = trimmed.split(":").filter(Boolean);
|
|
35
|
-
if (parts[0] === "agent" && parts[1])
|
|
38
|
+
if (parts[0] === "agent" && parts[1]) {
|
|
36
39
|
return normalizeAgentId(parts[1]);
|
|
40
|
+
}
|
|
37
41
|
return resolveAgentIdFromSessionKey(trimmed);
|
|
38
42
|
}
|
|
@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { isNotFoundPathError, isPathInside } from "../infra/path-guards.js";
|
|
5
6
|
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
6
7
|
const HTTP_URL_RE = /^https?:\/\//i;
|
|
7
8
|
const DATA_URL_RE = /^data:/i;
|
|
@@ -70,12 +71,32 @@ export async function resolveSandboxedMediaSource(params) {
|
|
|
70
71
|
throw new Error(`Invalid file:// URL for sandboxed media: ${raw}`);
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
|
-
const
|
|
74
|
+
const tmpMediaPath = await resolveAllowedTmpMediaPath({
|
|
75
|
+
candidate,
|
|
76
|
+
sandboxRoot: params.sandboxRoot,
|
|
77
|
+
});
|
|
78
|
+
if (tmpMediaPath) {
|
|
79
|
+
return tmpMediaPath;
|
|
80
|
+
}
|
|
81
|
+
const sandboxResult = await assertSandboxPath({
|
|
74
82
|
filePath: candidate,
|
|
75
83
|
cwd: params.sandboxRoot,
|
|
76
84
|
root: params.sandboxRoot,
|
|
77
85
|
});
|
|
78
|
-
return
|
|
86
|
+
return sandboxResult.resolved;
|
|
87
|
+
}
|
|
88
|
+
async function resolveAllowedTmpMediaPath(params) {
|
|
89
|
+
const candidateIsAbsolute = path.isAbsolute(expandPath(params.candidate));
|
|
90
|
+
if (!candidateIsAbsolute) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
const resolved = path.resolve(resolveSandboxInputPath(params.candidate, params.sandboxRoot));
|
|
94
|
+
const tmpDir = path.resolve(os.tmpdir());
|
|
95
|
+
if (!isPathInside(tmpDir, resolved)) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
await assertNoSymlinkEscape(path.relative(tmpDir, resolved), tmpDir);
|
|
99
|
+
return resolved;
|
|
79
100
|
}
|
|
80
101
|
async function assertNoSymlinkEscape(relative, root, options) {
|
|
81
102
|
if (!relative) {
|
|
@@ -104,8 +125,7 @@ async function assertNoSymlinkEscape(relative, root, options) {
|
|
|
104
125
|
}
|
|
105
126
|
}
|
|
106
127
|
catch (err) {
|
|
107
|
-
|
|
108
|
-
if (anyErr.code === "ENOENT") {
|
|
128
|
+
if (isNotFoundPathError(err)) {
|
|
109
129
|
return;
|
|
110
130
|
}
|
|
111
131
|
throw err;
|
|
@@ -120,13 +140,6 @@ async function tryRealpath(value) {
|
|
|
120
140
|
return path.resolve(value);
|
|
121
141
|
}
|
|
122
142
|
}
|
|
123
|
-
function isPathInside(root, target) {
|
|
124
|
-
const relative = path.relative(root, target);
|
|
125
|
-
if (!relative || relative === "") {
|
|
126
|
-
return true;
|
|
127
|
-
}
|
|
128
|
-
return !(relative.startsWith("..") || path.isAbsolute(relative));
|
|
129
|
-
}
|
|
130
143
|
function shortPath(value) {
|
|
131
144
|
if (value.startsWith(os.homedir())) {
|
|
132
145
|
return `~${value.slice(os.homedir().length)}`;
|
|
@@ -26,18 +26,28 @@ export const GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS = new Set([
|
|
|
26
26
|
"minProperties",
|
|
27
27
|
"maxProperties",
|
|
28
28
|
]);
|
|
29
|
+
const SCHEMA_META_KEYS = ["description", "title", "default"];
|
|
30
|
+
function copySchemaMeta(from, to) {
|
|
31
|
+
for (const key of SCHEMA_META_KEYS) {
|
|
32
|
+
if (key in from && from[key] !== undefined) {
|
|
33
|
+
to[key] = from[key];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
29
37
|
// Check if an anyOf/oneOf array contains only literal values that can be flattened.
|
|
30
38
|
// TypeBox Type.Literal generates { const: "value", type: "string" }.
|
|
31
39
|
// Some schemas may use { enum: ["value"], type: "string" }.
|
|
32
40
|
// Both patterns are flattened to { type: "string", enum: ["a", "b", ...] }.
|
|
33
41
|
function tryFlattenLiteralAnyOf(variants) {
|
|
34
|
-
if (variants.length === 0)
|
|
42
|
+
if (variants.length === 0) {
|
|
35
43
|
return null;
|
|
44
|
+
}
|
|
36
45
|
const allValues = [];
|
|
37
46
|
let commonType = null;
|
|
38
47
|
for (const variant of variants) {
|
|
39
|
-
if (!variant || typeof variant !== "object")
|
|
48
|
+
if (!variant || typeof variant !== "object") {
|
|
40
49
|
return null;
|
|
50
|
+
}
|
|
41
51
|
const v = variant;
|
|
42
52
|
let literalValue;
|
|
43
53
|
if ("const" in v) {
|
|
@@ -50,16 +60,20 @@ function tryFlattenLiteralAnyOf(variants) {
|
|
|
50
60
|
return null;
|
|
51
61
|
}
|
|
52
62
|
const variantType = typeof v.type === "string" ? v.type : null;
|
|
53
|
-
if (!variantType)
|
|
63
|
+
if (!variantType) {
|
|
54
64
|
return null;
|
|
55
|
-
|
|
65
|
+
}
|
|
66
|
+
if (commonType === null) {
|
|
56
67
|
commonType = variantType;
|
|
57
|
-
|
|
68
|
+
}
|
|
69
|
+
else if (commonType !== variantType) {
|
|
58
70
|
return null;
|
|
71
|
+
}
|
|
59
72
|
allValues.push(literalValue);
|
|
60
73
|
}
|
|
61
|
-
if (commonType && allValues.length > 0)
|
|
74
|
+
if (commonType && allValues.length > 0) {
|
|
62
75
|
return { type: commonType, enum: allValues };
|
|
76
|
+
}
|
|
63
77
|
return null;
|
|
64
78
|
}
|
|
65
79
|
function isNullSchema(variant) {
|
|
@@ -67,22 +81,25 @@ function isNullSchema(variant) {
|
|
|
67
81
|
return false;
|
|
68
82
|
}
|
|
69
83
|
const record = variant;
|
|
70
|
-
if ("const" in record && record.const === null)
|
|
84
|
+
if ("const" in record && record.const === null) {
|
|
71
85
|
return true;
|
|
86
|
+
}
|
|
72
87
|
if (Array.isArray(record.enum) && record.enum.length === 1) {
|
|
73
88
|
return record.enum[0] === null;
|
|
74
89
|
}
|
|
75
90
|
const typeValue = record.type;
|
|
76
|
-
if (typeValue === "null")
|
|
91
|
+
if (typeValue === "null") {
|
|
77
92
|
return true;
|
|
93
|
+
}
|
|
78
94
|
if (Array.isArray(typeValue) && typeValue.length === 1 && typeValue[0] === "null") {
|
|
79
95
|
return true;
|
|
80
96
|
}
|
|
81
97
|
return false;
|
|
82
98
|
}
|
|
83
99
|
function stripNullVariants(variants) {
|
|
84
|
-
if (variants.length === 0)
|
|
100
|
+
if (variants.length === 0) {
|
|
85
101
|
return { variants, stripped: false };
|
|
102
|
+
}
|
|
86
103
|
const nonNull = variants.filter((variant) => !isNullSchema(variant));
|
|
87
104
|
return {
|
|
88
105
|
variants: nonNull,
|
|
@@ -98,16 +115,19 @@ function extendSchemaDefs(defs, schema) {
|
|
|
98
115
|
!Array.isArray(schema.definitions)
|
|
99
116
|
? schema.definitions
|
|
100
117
|
: undefined;
|
|
101
|
-
if (!defsEntry && !legacyDefsEntry)
|
|
118
|
+
if (!defsEntry && !legacyDefsEntry) {
|
|
102
119
|
return defs;
|
|
120
|
+
}
|
|
103
121
|
const next = defs ? new Map(defs) : new Map();
|
|
104
122
|
if (defsEntry) {
|
|
105
|
-
for (const [key, value] of Object.entries(defsEntry))
|
|
123
|
+
for (const [key, value] of Object.entries(defsEntry)) {
|
|
106
124
|
next.set(key, value);
|
|
125
|
+
}
|
|
107
126
|
}
|
|
108
127
|
if (legacyDefsEntry) {
|
|
109
|
-
for (const [key, value] of Object.entries(legacyDefsEntry))
|
|
128
|
+
for (const [key, value] of Object.entries(legacyDefsEntry)) {
|
|
110
129
|
next.set(key, value);
|
|
130
|
+
}
|
|
111
131
|
}
|
|
112
132
|
return next;
|
|
113
133
|
}
|
|
@@ -115,19 +135,48 @@ function decodeJsonPointerSegment(segment) {
|
|
|
115
135
|
return segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
116
136
|
}
|
|
117
137
|
function tryResolveLocalRef(ref, defs) {
|
|
118
|
-
if (!defs)
|
|
138
|
+
if (!defs) {
|
|
119
139
|
return undefined;
|
|
140
|
+
}
|
|
120
141
|
const match = ref.match(/^#\/(?:\$defs|definitions)\/(.+)$/);
|
|
121
|
-
if (!match)
|
|
142
|
+
if (!match) {
|
|
122
143
|
return undefined;
|
|
144
|
+
}
|
|
123
145
|
const name = decodeJsonPointerSegment(match[1] ?? "");
|
|
124
|
-
if (!name)
|
|
146
|
+
if (!name) {
|
|
125
147
|
return undefined;
|
|
148
|
+
}
|
|
126
149
|
return defs.get(name);
|
|
127
150
|
}
|
|
151
|
+
function simplifyUnionVariants(params) {
|
|
152
|
+
const { obj, variants } = params;
|
|
153
|
+
const { variants: nonNullVariants, stripped } = stripNullVariants(variants);
|
|
154
|
+
const flattened = tryFlattenLiteralAnyOf(nonNullVariants);
|
|
155
|
+
if (flattened) {
|
|
156
|
+
const result = {
|
|
157
|
+
type: flattened.type,
|
|
158
|
+
enum: flattened.enum,
|
|
159
|
+
};
|
|
160
|
+
copySchemaMeta(obj, result);
|
|
161
|
+
return { variants: nonNullVariants, simplified: result };
|
|
162
|
+
}
|
|
163
|
+
if (stripped && nonNullVariants.length === 1) {
|
|
164
|
+
const lone = nonNullVariants[0];
|
|
165
|
+
if (lone && typeof lone === "object" && !Array.isArray(lone)) {
|
|
166
|
+
const result = {
|
|
167
|
+
...lone,
|
|
168
|
+
};
|
|
169
|
+
copySchemaMeta(obj, result);
|
|
170
|
+
return { variants: nonNullVariants, simplified: result };
|
|
171
|
+
}
|
|
172
|
+
return { variants: nonNullVariants, simplified: lone };
|
|
173
|
+
}
|
|
174
|
+
return { variants: stripped ? nonNullVariants : variants };
|
|
175
|
+
}
|
|
128
176
|
function cleanSchemaForGeminiWithDefs(schema, defs, refStack) {
|
|
129
|
-
if (!schema || typeof schema !== "object")
|
|
177
|
+
if (!schema || typeof schema !== "object") {
|
|
130
178
|
return schema;
|
|
179
|
+
}
|
|
131
180
|
if (Array.isArray(schema)) {
|
|
132
181
|
return schema.map((item) => cleanSchemaForGeminiWithDefs(item, defs, refStack));
|
|
133
182
|
}
|
|
@@ -135,8 +184,9 @@ function cleanSchemaForGeminiWithDefs(schema, defs, refStack) {
|
|
|
135
184
|
const nextDefs = extendSchemaDefs(defs, obj);
|
|
136
185
|
const refValue = typeof obj.$ref === "string" ? obj.$ref : undefined;
|
|
137
186
|
if (refValue) {
|
|
138
|
-
if (refStack?.has(refValue))
|
|
187
|
+
if (refStack?.has(refValue)) {
|
|
139
188
|
return {};
|
|
189
|
+
}
|
|
140
190
|
const resolved = tryResolveLocalRef(refValue, nextDefs);
|
|
141
191
|
if (resolved) {
|
|
142
192
|
const nextRefStack = refStack ? new Set(refStack) : new Set();
|
|
@@ -148,17 +198,11 @@ function cleanSchemaForGeminiWithDefs(schema, defs, refStack) {
|
|
|
148
198
|
const result = {
|
|
149
199
|
...cleaned,
|
|
150
200
|
};
|
|
151
|
-
|
|
152
|
-
if (key in obj && obj[key] !== undefined)
|
|
153
|
-
result[key] = obj[key];
|
|
154
|
-
}
|
|
201
|
+
copySchemaMeta(obj, result);
|
|
155
202
|
return result;
|
|
156
203
|
}
|
|
157
204
|
const result = {};
|
|
158
|
-
|
|
159
|
-
if (key in obj && obj[key] !== undefined)
|
|
160
|
-
result[key] = obj[key];
|
|
161
|
-
}
|
|
205
|
+
copySchemaMeta(obj, result);
|
|
162
206
|
return result;
|
|
163
207
|
}
|
|
164
208
|
const hasAnyOf = "anyOf" in obj && Array.isArray(obj.anyOf);
|
|
@@ -170,77 +214,31 @@ function cleanSchemaForGeminiWithDefs(schema, defs, refStack) {
|
|
|
170
214
|
? obj.oneOf.map((variant) => cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack))
|
|
171
215
|
: undefined;
|
|
172
216
|
if (hasAnyOf) {
|
|
173
|
-
const { variants:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (flattened) {
|
|
178
|
-
const result = {
|
|
179
|
-
type: flattened.type,
|
|
180
|
-
enum: flattened.enum,
|
|
181
|
-
};
|
|
182
|
-
for (const key of ["description", "title", "default"]) {
|
|
183
|
-
if (key in obj && obj[key] !== undefined)
|
|
184
|
-
result[key] = obj[key];
|
|
185
|
-
}
|
|
186
|
-
return result;
|
|
187
|
-
}
|
|
188
|
-
if (stripped && nonNullVariants.length === 1) {
|
|
189
|
-
const lone = nonNullVariants[0];
|
|
190
|
-
if (lone && typeof lone === "object" && !Array.isArray(lone)) {
|
|
191
|
-
const result = {
|
|
192
|
-
...lone,
|
|
193
|
-
};
|
|
194
|
-
for (const key of ["description", "title", "default"]) {
|
|
195
|
-
if (key in obj && obj[key] !== undefined)
|
|
196
|
-
result[key] = obj[key];
|
|
197
|
-
}
|
|
198
|
-
return result;
|
|
199
|
-
}
|
|
200
|
-
return lone;
|
|
217
|
+
const simplified = simplifyUnionVariants({ obj, variants: cleanedAnyOf ?? [] });
|
|
218
|
+
cleanedAnyOf = simplified.variants;
|
|
219
|
+
if ("simplified" in simplified) {
|
|
220
|
+
return simplified.simplified;
|
|
201
221
|
}
|
|
202
222
|
}
|
|
203
223
|
if (hasOneOf) {
|
|
204
|
-
const { variants:
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (flattened) {
|
|
209
|
-
const result = {
|
|
210
|
-
type: flattened.type,
|
|
211
|
-
enum: flattened.enum,
|
|
212
|
-
};
|
|
213
|
-
for (const key of ["description", "title", "default"]) {
|
|
214
|
-
if (key in obj && obj[key] !== undefined)
|
|
215
|
-
result[key] = obj[key];
|
|
216
|
-
}
|
|
217
|
-
return result;
|
|
218
|
-
}
|
|
219
|
-
if (stripped && nonNullVariants.length === 1) {
|
|
220
|
-
const lone = nonNullVariants[0];
|
|
221
|
-
if (lone && typeof lone === "object" && !Array.isArray(lone)) {
|
|
222
|
-
const result = {
|
|
223
|
-
...lone,
|
|
224
|
-
};
|
|
225
|
-
for (const key of ["description", "title", "default"]) {
|
|
226
|
-
if (key in obj && obj[key] !== undefined)
|
|
227
|
-
result[key] = obj[key];
|
|
228
|
-
}
|
|
229
|
-
return result;
|
|
230
|
-
}
|
|
231
|
-
return lone;
|
|
224
|
+
const simplified = simplifyUnionVariants({ obj, variants: cleanedOneOf ?? [] });
|
|
225
|
+
cleanedOneOf = simplified.variants;
|
|
226
|
+
if ("simplified" in simplified) {
|
|
227
|
+
return simplified.simplified;
|
|
232
228
|
}
|
|
233
229
|
}
|
|
234
230
|
const cleaned = {};
|
|
235
231
|
for (const [key, value] of Object.entries(obj)) {
|
|
236
|
-
if (GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS.has(key))
|
|
232
|
+
if (GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS.has(key)) {
|
|
237
233
|
continue;
|
|
234
|
+
}
|
|
238
235
|
if (key === "const") {
|
|
239
236
|
cleaned.enum = [value];
|
|
240
237
|
continue;
|
|
241
238
|
}
|
|
242
|
-
if (key === "type" && (hasAnyOf || hasOneOf))
|
|
239
|
+
if (key === "type" && (hasAnyOf || hasOneOf)) {
|
|
243
240
|
continue;
|
|
241
|
+
}
|
|
244
242
|
if (key === "type" &&
|
|
245
243
|
Array.isArray(value) &&
|
|
246
244
|
value.every((entry) => typeof entry === "string")) {
|
|
@@ -283,13 +281,62 @@ function cleanSchemaForGeminiWithDefs(schema, defs, refStack) {
|
|
|
283
281
|
cleaned[key] = value;
|
|
284
282
|
}
|
|
285
283
|
}
|
|
284
|
+
// Cloud Code Assist API rejects anyOf/oneOf in nested schemas even after
|
|
285
|
+
// simplifyUnionVariants runs above. Flatten remaining unions as a fallback:
|
|
286
|
+
// pick the common type or use the first variant's type so the tool
|
|
287
|
+
// declaration is accepted by Google's validation layer.
|
|
288
|
+
if (cleaned.anyOf && Array.isArray(cleaned.anyOf)) {
|
|
289
|
+
const flattened = flattenUnionFallback(cleaned, cleaned.anyOf);
|
|
290
|
+
if (flattened) {
|
|
291
|
+
return flattened;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (cleaned.oneOf && Array.isArray(cleaned.oneOf)) {
|
|
295
|
+
const flattened = flattenUnionFallback(cleaned, cleaned.oneOf);
|
|
296
|
+
if (flattened) {
|
|
297
|
+
return flattened;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
286
300
|
return cleaned;
|
|
287
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* Last-resort flattening for anyOf/oneOf arrays that could not be simplified
|
|
304
|
+
* by `simplifyUnionVariants`. Picks a representative type so the schema is
|
|
305
|
+
* accepted by Google's restricted JSON Schema validation.
|
|
306
|
+
*/
|
|
307
|
+
function flattenUnionFallback(obj, variants) {
|
|
308
|
+
const objects = variants.filter((v) => !!v && typeof v === "object");
|
|
309
|
+
if (objects.length === 0) {
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
const types = new Set(objects.map((v) => v.type).filter(Boolean));
|
|
313
|
+
if (objects.length === 1) {
|
|
314
|
+
const merged = { ...objects[0] };
|
|
315
|
+
copySchemaMeta(obj, merged);
|
|
316
|
+
return merged;
|
|
317
|
+
}
|
|
318
|
+
if (types.size === 1) {
|
|
319
|
+
const merged = { type: Array.from(types)[0] };
|
|
320
|
+
copySchemaMeta(obj, merged);
|
|
321
|
+
return merged;
|
|
322
|
+
}
|
|
323
|
+
const first = objects[0];
|
|
324
|
+
if (first?.type) {
|
|
325
|
+
const merged = { type: first.type };
|
|
326
|
+
copySchemaMeta(obj, merged);
|
|
327
|
+
return merged;
|
|
328
|
+
}
|
|
329
|
+
const merged = {};
|
|
330
|
+
copySchemaMeta(obj, merged);
|
|
331
|
+
return merged;
|
|
332
|
+
}
|
|
288
333
|
export function cleanSchemaForGemini(schema) {
|
|
289
|
-
if (!schema || typeof schema !== "object")
|
|
334
|
+
if (!schema || typeof schema !== "object") {
|
|
290
335
|
return schema;
|
|
291
|
-
|
|
336
|
+
}
|
|
337
|
+
if (Array.isArray(schema)) {
|
|
292
338
|
return schema.map(cleanSchemaForGemini);
|
|
339
|
+
}
|
|
293
340
|
const defs = extendSchemaDefs(undefined, schema);
|
|
294
341
|
return cleanSchemaForGeminiWithDefs(schema, defs, undefined);
|
|
295
342
|
}
|
|
@@ -103,30 +103,35 @@ function randomChoice(values, fallback) {
|
|
|
103
103
|
}
|
|
104
104
|
function createSlugBase(words = 2) {
|
|
105
105
|
const parts = [randomChoice(SLUG_ADJECTIVES, "steady"), randomChoice(SLUG_NOUNS, "harbor")];
|
|
106
|
-
if (words > 2)
|
|
106
|
+
if (words > 2) {
|
|
107
107
|
parts.push(randomChoice(SLUG_NOUNS, "reef"));
|
|
108
|
+
}
|
|
108
109
|
return parts.join("-");
|
|
109
110
|
}
|
|
110
111
|
export function createSessionSlug(isTaken) {
|
|
111
112
|
const isIdTaken = isTaken ?? (() => false);
|
|
112
113
|
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
113
114
|
const base = createSlugBase(2);
|
|
114
|
-
if (!isIdTaken(base))
|
|
115
|
+
if (!isIdTaken(base)) {
|
|
115
116
|
return base;
|
|
117
|
+
}
|
|
116
118
|
for (let i = 2; i <= 12; i += 1) {
|
|
117
119
|
const candidate = `${base}-${i}`;
|
|
118
|
-
if (!isIdTaken(candidate))
|
|
120
|
+
if (!isIdTaken(candidate)) {
|
|
119
121
|
return candidate;
|
|
122
|
+
}
|
|
120
123
|
}
|
|
121
124
|
}
|
|
122
125
|
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
123
126
|
const base = createSlugBase(3);
|
|
124
|
-
if (!isIdTaken(base))
|
|
127
|
+
if (!isIdTaken(base)) {
|
|
125
128
|
return base;
|
|
129
|
+
}
|
|
126
130
|
for (let i = 2; i <= 12; i += 1) {
|
|
127
131
|
const candidate = `${base}-${i}`;
|
|
128
|
-
if (!isIdTaken(candidate))
|
|
132
|
+
if (!isIdTaken(candidate)) {
|
|
129
133
|
return candidate;
|
|
134
|
+
}
|
|
130
135
|
}
|
|
131
136
|
}
|
|
132
137
|
const fallback = `${createSlugBase(3)}-${Math.random().toString(36).slice(2, 5)}`;
|