@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
package/dist/agents/workspace.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import { isSubagentSessionKey } from "../routing/session-key.js";
|
|
4
|
+
import { resolveRequiredHomeDir } from "../infra/home-dir.js";
|
|
6
5
|
import { runCommandWithTimeout } from "../process/exec.js";
|
|
6
|
+
import { isCronSessionKey, isSubagentSessionKey } from "../routing/session-key.js";
|
|
7
7
|
import { resolveUserPath } from "../utils.js";
|
|
8
|
+
import { resolveWorkspaceTemplateDir } from "./workspace-templates.js";
|
|
8
9
|
export function resolveDefaultAgentWorkspaceDir(env = process.env, homedir = os.homedir) {
|
|
10
|
+
const home = resolveRequiredHomeDir(env, homedir);
|
|
9
11
|
const profile = env.POOLBOT_PROFILE?.trim() || env.CLAWDBOT_PROFILE?.trim();
|
|
10
12
|
if (profile && profile.toLowerCase() !== "default") {
|
|
11
|
-
return path.join(
|
|
13
|
+
return path.join(home, `clawd-${profile}`);
|
|
12
14
|
}
|
|
13
|
-
return path.join(
|
|
15
|
+
return path.join(home, "clawd");
|
|
14
16
|
}
|
|
15
17
|
export const DEFAULT_AGENT_WORKSPACE_DIR = resolveDefaultAgentWorkspaceDir();
|
|
16
18
|
export const DEFAULT_AGENTS_FILENAME = "AGENTS.md";
|
|
@@ -22,66 +24,203 @@ export const DEFAULT_HEARTBEAT_FILENAME = "HEARTBEAT.md";
|
|
|
22
24
|
export const DEFAULT_BOOTSTRAP_FILENAME = "BOOTSTRAP.md";
|
|
23
25
|
export const DEFAULT_MEMORY_FILENAME = "MEMORY.md";
|
|
24
26
|
export const DEFAULT_MEMORY_ALT_FILENAME = "memory.md";
|
|
25
|
-
const
|
|
27
|
+
const WORKSPACE_STATE_DIRNAME = ".poolbot";
|
|
28
|
+
const WORKSPACE_STATE_FILENAME = "workspace-state.json";
|
|
29
|
+
const WORKSPACE_STATE_VERSION = 1;
|
|
30
|
+
const workspaceTemplateCache = new Map();
|
|
31
|
+
let gitAvailabilityPromise = null;
|
|
32
|
+
// File content cache with mtime invalidation to avoid redundant reads
|
|
33
|
+
const workspaceFileCache = new Map();
|
|
34
|
+
/**
|
|
35
|
+
* Read file with caching based on mtime. Returns cached content if file
|
|
36
|
+
* hasn't changed, otherwise reads from disk and updates cache.
|
|
37
|
+
*/
|
|
38
|
+
async function readFileWithCache(filePath) {
|
|
39
|
+
try {
|
|
40
|
+
const stats = await fs.stat(filePath);
|
|
41
|
+
const mtimeMs = stats.mtimeMs;
|
|
42
|
+
const cached = workspaceFileCache.get(filePath);
|
|
43
|
+
// Return cached content if mtime matches
|
|
44
|
+
if (cached && cached.mtimeMs === mtimeMs) {
|
|
45
|
+
return cached.content;
|
|
46
|
+
}
|
|
47
|
+
// Read from disk and update cache
|
|
48
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
49
|
+
workspaceFileCache.set(filePath, { content, mtimeMs });
|
|
50
|
+
return content;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
// Remove from cache if file doesn't exist or is unreadable
|
|
54
|
+
workspaceFileCache.delete(filePath);
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
26
58
|
function stripFrontMatter(content) {
|
|
27
|
-
if (!content.startsWith("---"))
|
|
59
|
+
if (!content.startsWith("---")) {
|
|
28
60
|
return content;
|
|
61
|
+
}
|
|
29
62
|
const endIndex = content.indexOf("\n---", 3);
|
|
30
|
-
if (endIndex === -1)
|
|
63
|
+
if (endIndex === -1) {
|
|
31
64
|
return content;
|
|
65
|
+
}
|
|
32
66
|
const start = endIndex + "\n---".length;
|
|
33
67
|
let trimmed = content.slice(start);
|
|
34
68
|
trimmed = trimmed.replace(/^\s+/, "");
|
|
35
69
|
return trimmed;
|
|
36
70
|
}
|
|
37
71
|
async function loadTemplate(name) {
|
|
38
|
-
const
|
|
72
|
+
const cached = workspaceTemplateCache.get(name);
|
|
73
|
+
if (cached) {
|
|
74
|
+
return cached;
|
|
75
|
+
}
|
|
76
|
+
const pending = (async () => {
|
|
77
|
+
const templateDir = await resolveWorkspaceTemplateDir();
|
|
78
|
+
const templatePath = path.join(templateDir, name);
|
|
79
|
+
try {
|
|
80
|
+
const content = await fs.readFile(templatePath, "utf-8");
|
|
81
|
+
return stripFrontMatter(content);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
throw new Error(`Missing workspace template: ${name} (${templatePath}). Ensure docs/reference/templates are packaged.`);
|
|
85
|
+
}
|
|
86
|
+
})();
|
|
87
|
+
workspaceTemplateCache.set(name, pending);
|
|
39
88
|
try {
|
|
40
|
-
|
|
41
|
-
return stripFrontMatter(content);
|
|
89
|
+
return await pending;
|
|
42
90
|
}
|
|
43
|
-
catch {
|
|
44
|
-
|
|
91
|
+
catch (error) {
|
|
92
|
+
workspaceTemplateCache.delete(name);
|
|
93
|
+
throw error;
|
|
45
94
|
}
|
|
46
95
|
}
|
|
96
|
+
/** Set of recognized bootstrap filenames for runtime validation */
|
|
97
|
+
const VALID_BOOTSTRAP_NAMES = new Set([
|
|
98
|
+
DEFAULT_AGENTS_FILENAME,
|
|
99
|
+
DEFAULT_SOUL_FILENAME,
|
|
100
|
+
DEFAULT_TOOLS_FILENAME,
|
|
101
|
+
DEFAULT_IDENTITY_FILENAME,
|
|
102
|
+
DEFAULT_USER_FILENAME,
|
|
103
|
+
DEFAULT_HEARTBEAT_FILENAME,
|
|
104
|
+
DEFAULT_BOOTSTRAP_FILENAME,
|
|
105
|
+
DEFAULT_MEMORY_FILENAME,
|
|
106
|
+
DEFAULT_MEMORY_ALT_FILENAME,
|
|
107
|
+
]);
|
|
47
108
|
async function writeFileIfMissing(filePath, content) {
|
|
48
109
|
try {
|
|
49
110
|
await fs.writeFile(filePath, content, {
|
|
50
111
|
encoding: "utf-8",
|
|
51
112
|
flag: "wx",
|
|
52
113
|
});
|
|
114
|
+
return true;
|
|
53
115
|
}
|
|
54
116
|
catch (err) {
|
|
55
117
|
const anyErr = err;
|
|
56
|
-
if (anyErr.code !== "EEXIST")
|
|
118
|
+
if (anyErr.code !== "EEXIST") {
|
|
57
119
|
throw err;
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
58
122
|
}
|
|
59
123
|
}
|
|
60
|
-
async function
|
|
124
|
+
async function fileExists(filePath) {
|
|
61
125
|
try {
|
|
62
|
-
await fs.
|
|
126
|
+
await fs.access(filePath);
|
|
63
127
|
return true;
|
|
64
128
|
}
|
|
65
129
|
catch {
|
|
66
130
|
return false;
|
|
67
131
|
}
|
|
68
132
|
}
|
|
69
|
-
|
|
133
|
+
function resolveWorkspaceStatePath(dir) {
|
|
134
|
+
return path.join(dir, WORKSPACE_STATE_DIRNAME, WORKSPACE_STATE_FILENAME);
|
|
135
|
+
}
|
|
136
|
+
function parseWorkspaceOnboardingState(raw) {
|
|
137
|
+
try {
|
|
138
|
+
const parsed = JSON.parse(raw);
|
|
139
|
+
if (!parsed || typeof parsed !== "object") {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
version: WORKSPACE_STATE_VERSION,
|
|
144
|
+
bootstrapSeededAt: typeof parsed.bootstrapSeededAt === "string" ? parsed.bootstrapSeededAt : undefined,
|
|
145
|
+
onboardingCompletedAt: typeof parsed.onboardingCompletedAt === "string" ? parsed.onboardingCompletedAt : undefined,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function readWorkspaceOnboardingState(statePath) {
|
|
153
|
+
try {
|
|
154
|
+
const raw = await fs.readFile(statePath, "utf-8");
|
|
155
|
+
return (parseWorkspaceOnboardingState(raw) ?? {
|
|
156
|
+
version: WORKSPACE_STATE_VERSION,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
const anyErr = err;
|
|
161
|
+
if (anyErr.code !== "ENOENT") {
|
|
162
|
+
throw err;
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
version: WORKSPACE_STATE_VERSION,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async function readWorkspaceOnboardingStateForDir(dir) {
|
|
170
|
+
const statePath = resolveWorkspaceStatePath(resolveUserPath(dir));
|
|
171
|
+
return await readWorkspaceOnboardingState(statePath);
|
|
172
|
+
}
|
|
173
|
+
export async function isWorkspaceOnboardingCompleted(dir) {
|
|
174
|
+
const state = await readWorkspaceOnboardingStateForDir(dir);
|
|
175
|
+
return (typeof state.onboardingCompletedAt === "string" && state.onboardingCompletedAt.trim().length > 0);
|
|
176
|
+
}
|
|
177
|
+
async function writeWorkspaceOnboardingState(statePath, state) {
|
|
178
|
+
await fs.mkdir(path.dirname(statePath), { recursive: true });
|
|
179
|
+
const payload = `${JSON.stringify(state, null, 2)}\n`;
|
|
180
|
+
const tmpPath = `${statePath}.tmp-${process.pid}-${Date.now().toString(36)}`;
|
|
70
181
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
182
|
+
await fs.writeFile(tmpPath, payload, { encoding: "utf-8" });
|
|
183
|
+
await fs.rename(tmpPath, statePath);
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
await fs.unlink(tmpPath).catch(() => { });
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async function hasGitRepo(dir) {
|
|
191
|
+
try {
|
|
192
|
+
await fs.stat(path.join(dir, ".git"));
|
|
193
|
+
return true;
|
|
73
194
|
}
|
|
74
195
|
catch {
|
|
75
196
|
return false;
|
|
76
197
|
}
|
|
77
198
|
}
|
|
199
|
+
async function isGitAvailable() {
|
|
200
|
+
if (gitAvailabilityPromise) {
|
|
201
|
+
return gitAvailabilityPromise;
|
|
202
|
+
}
|
|
203
|
+
gitAvailabilityPromise = (async () => {
|
|
204
|
+
try {
|
|
205
|
+
const result = await runCommandWithTimeout(["git", "--version"], { timeoutMs: 2_000 });
|
|
206
|
+
return result.code === 0;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
})();
|
|
212
|
+
return gitAvailabilityPromise;
|
|
213
|
+
}
|
|
78
214
|
async function ensureGitRepo(dir, isBrandNewWorkspace) {
|
|
79
|
-
if (!isBrandNewWorkspace)
|
|
215
|
+
if (!isBrandNewWorkspace) {
|
|
80
216
|
return;
|
|
81
|
-
|
|
217
|
+
}
|
|
218
|
+
if (await hasGitRepo(dir)) {
|
|
82
219
|
return;
|
|
83
|
-
|
|
220
|
+
}
|
|
221
|
+
if (!(await isGitAvailable())) {
|
|
84
222
|
return;
|
|
223
|
+
}
|
|
85
224
|
try {
|
|
86
225
|
await runCommandWithTimeout(["git", "init"], { cwd: dir, timeoutMs: 10_000 });
|
|
87
226
|
}
|
|
@@ -93,8 +232,9 @@ export async function ensureAgentWorkspace(params) {
|
|
|
93
232
|
const rawDir = params?.dir?.trim() ? params.dir.trim() : DEFAULT_AGENT_WORKSPACE_DIR;
|
|
94
233
|
const dir = resolveUserPath(rawDir);
|
|
95
234
|
await fs.mkdir(dir, { recursive: true });
|
|
96
|
-
if (!params?.ensureBootstrapFiles)
|
|
235
|
+
if (!params?.ensureBootstrapFiles) {
|
|
97
236
|
return { dir };
|
|
237
|
+
}
|
|
98
238
|
const agentsPath = path.join(dir, DEFAULT_AGENTS_FILENAME);
|
|
99
239
|
const soulPath = path.join(dir, DEFAULT_SOUL_FILENAME);
|
|
100
240
|
const toolsPath = path.join(dir, DEFAULT_TOOLS_FILENAME);
|
|
@@ -102,6 +242,7 @@ export async function ensureAgentWorkspace(params) {
|
|
|
102
242
|
const userPath = path.join(dir, DEFAULT_USER_FILENAME);
|
|
103
243
|
const heartbeatPath = path.join(dir, DEFAULT_HEARTBEAT_FILENAME);
|
|
104
244
|
const bootstrapPath = path.join(dir, DEFAULT_BOOTSTRAP_FILENAME);
|
|
245
|
+
const statePath = resolveWorkspaceStatePath(dir);
|
|
105
246
|
const isBrandNewWorkspace = await (async () => {
|
|
106
247
|
const paths = [agentsPath, soulPath, toolsPath, identityPath, userPath, heartbeatPath];
|
|
107
248
|
const existing = await Promise.all(paths.map(async (p) => {
|
|
@@ -121,15 +262,53 @@ export async function ensureAgentWorkspace(params) {
|
|
|
121
262
|
const identityTemplate = await loadTemplate(DEFAULT_IDENTITY_FILENAME);
|
|
122
263
|
const userTemplate = await loadTemplate(DEFAULT_USER_FILENAME);
|
|
123
264
|
const heartbeatTemplate = await loadTemplate(DEFAULT_HEARTBEAT_FILENAME);
|
|
124
|
-
const bootstrapTemplate = await loadTemplate(DEFAULT_BOOTSTRAP_FILENAME);
|
|
125
265
|
await writeFileIfMissing(agentsPath, agentsTemplate);
|
|
126
266
|
await writeFileIfMissing(soulPath, soulTemplate);
|
|
127
267
|
await writeFileIfMissing(toolsPath, toolsTemplate);
|
|
128
268
|
await writeFileIfMissing(identityPath, identityTemplate);
|
|
129
269
|
await writeFileIfMissing(userPath, userTemplate);
|
|
130
270
|
await writeFileIfMissing(heartbeatPath, heartbeatTemplate);
|
|
131
|
-
|
|
132
|
-
|
|
271
|
+
let state = await readWorkspaceOnboardingState(statePath);
|
|
272
|
+
let stateDirty = false;
|
|
273
|
+
const markState = (next) => {
|
|
274
|
+
state = { ...state, ...next };
|
|
275
|
+
stateDirty = true;
|
|
276
|
+
};
|
|
277
|
+
const nowIso = () => new Date().toISOString();
|
|
278
|
+
let bootstrapExists = await fileExists(bootstrapPath);
|
|
279
|
+
if (!state.bootstrapSeededAt && bootstrapExists) {
|
|
280
|
+
markState({ bootstrapSeededAt: nowIso() });
|
|
281
|
+
}
|
|
282
|
+
if (!state.onboardingCompletedAt && state.bootstrapSeededAt && !bootstrapExists) {
|
|
283
|
+
markState({ onboardingCompletedAt: nowIso() });
|
|
284
|
+
}
|
|
285
|
+
if (!state.bootstrapSeededAt && !state.onboardingCompletedAt && !bootstrapExists) {
|
|
286
|
+
// Legacy migration path: if USER/IDENTITY diverged from templates, treat onboarding as complete
|
|
287
|
+
// and avoid recreating BOOTSTRAP for already-onboarded workspaces.
|
|
288
|
+
const [identityContent, userContent] = await Promise.all([
|
|
289
|
+
fs.readFile(identityPath, "utf-8"),
|
|
290
|
+
fs.readFile(userPath, "utf-8"),
|
|
291
|
+
]);
|
|
292
|
+
const legacyOnboardingCompleted = identityContent !== identityTemplate || userContent !== userTemplate;
|
|
293
|
+
if (legacyOnboardingCompleted) {
|
|
294
|
+
markState({ onboardingCompletedAt: nowIso() });
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
const bootstrapTemplate = await loadTemplate(DEFAULT_BOOTSTRAP_FILENAME);
|
|
298
|
+
const wroteBootstrap = await writeFileIfMissing(bootstrapPath, bootstrapTemplate);
|
|
299
|
+
if (!wroteBootstrap) {
|
|
300
|
+
bootstrapExists = await fileExists(bootstrapPath);
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
bootstrapExists = true;
|
|
304
|
+
}
|
|
305
|
+
if (bootstrapExists && !state.bootstrapSeededAt) {
|
|
306
|
+
markState({ bootstrapSeededAt: nowIso() });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
if (stateDirty) {
|
|
311
|
+
await writeWorkspaceOnboardingState(statePath, state);
|
|
133
312
|
}
|
|
134
313
|
await ensureGitRepo(dir, isBrandNewWorkspace);
|
|
135
314
|
return {
|
|
@@ -159,8 +338,9 @@ async function resolveMemoryBootstrapEntries(resolvedDir) {
|
|
|
159
338
|
// optional
|
|
160
339
|
}
|
|
161
340
|
}
|
|
162
|
-
if (entries.length <= 1)
|
|
341
|
+
if (entries.length <= 1) {
|
|
163
342
|
return entries;
|
|
343
|
+
}
|
|
164
344
|
const seen = new Set();
|
|
165
345
|
const deduped = [];
|
|
166
346
|
for (const entry of entries) {
|
|
@@ -169,8 +349,9 @@ async function resolveMemoryBootstrapEntries(resolvedDir) {
|
|
|
169
349
|
key = await fs.realpath(entry.filePath);
|
|
170
350
|
}
|
|
171
351
|
catch { }
|
|
172
|
-
if (seen.has(key))
|
|
352
|
+
if (seen.has(key)) {
|
|
173
353
|
continue;
|
|
354
|
+
}
|
|
174
355
|
seen.add(key);
|
|
175
356
|
deduped.push(entry);
|
|
176
357
|
}
|
|
@@ -212,7 +393,7 @@ export async function loadWorkspaceBootstrapFiles(dir) {
|
|
|
212
393
|
const result = [];
|
|
213
394
|
for (const entry of entries) {
|
|
214
395
|
try {
|
|
215
|
-
const content = await
|
|
396
|
+
const content = await readFileWithCache(entry.filePath);
|
|
216
397
|
result.push({
|
|
217
398
|
name: entry.name,
|
|
218
399
|
path: entry.filePath,
|
|
@@ -226,18 +407,13 @@ export async function loadWorkspaceBootstrapFiles(dir) {
|
|
|
226
407
|
}
|
|
227
408
|
return result;
|
|
228
409
|
}
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
DEFAULT_HEARTBEAT_FILENAME,
|
|
237
|
-
DEFAULT_BOOTSTRAP_FILENAME,
|
|
238
|
-
DEFAULT_MEMORY_FILENAME,
|
|
239
|
-
DEFAULT_MEMORY_ALT_FILENAME,
|
|
240
|
-
]);
|
|
410
|
+
const MINIMAL_BOOTSTRAP_ALLOWLIST = new Set([DEFAULT_AGENTS_FILENAME, DEFAULT_TOOLS_FILENAME]);
|
|
411
|
+
export function filterBootstrapFilesForSession(files, sessionKey) {
|
|
412
|
+
if (!sessionKey || (!isSubagentSessionKey(sessionKey) && !isCronSessionKey(sessionKey))) {
|
|
413
|
+
return files;
|
|
414
|
+
}
|
|
415
|
+
return files.filter((file) => MINIMAL_BOOTSTRAP_ALLOWLIST.has(file.name));
|
|
416
|
+
}
|
|
241
417
|
export async function loadExtraBootstrapFiles(dir, extraPatterns) {
|
|
242
418
|
if (!extraPatterns.length) {
|
|
243
419
|
return [];
|
|
@@ -250,6 +426,7 @@ export async function loadExtraBootstrapFiles(dir, extraPatterns) {
|
|
|
250
426
|
catch {
|
|
251
427
|
// Keep lexical root if realpath fails.
|
|
252
428
|
}
|
|
429
|
+
// Resolve glob patterns into concrete file paths
|
|
253
430
|
const resolvedPaths = new Set();
|
|
254
431
|
for (const pattern of extraPatterns) {
|
|
255
432
|
if (pattern.includes("*") || pattern.includes("?") || pattern.includes("{")) {
|
|
@@ -260,6 +437,7 @@ export async function loadExtraBootstrapFiles(dir, extraPatterns) {
|
|
|
260
437
|
}
|
|
261
438
|
}
|
|
262
439
|
catch {
|
|
440
|
+
// glob not available or pattern error — fall back to literal
|
|
263
441
|
resolvedPaths.add(pattern);
|
|
264
442
|
}
|
|
265
443
|
}
|
|
@@ -270,20 +448,23 @@ export async function loadExtraBootstrapFiles(dir, extraPatterns) {
|
|
|
270
448
|
const result = [];
|
|
271
449
|
for (const relPath of resolvedPaths) {
|
|
272
450
|
const filePath = path.resolve(resolvedDir, relPath);
|
|
451
|
+
// Guard against path traversal — resolved path must stay within workspace
|
|
273
452
|
if (!filePath.startsWith(resolvedDir + path.sep) && filePath !== resolvedDir) {
|
|
274
453
|
continue;
|
|
275
454
|
}
|
|
276
455
|
try {
|
|
456
|
+
// Resolve symlinks and verify the real path is still within workspace
|
|
277
457
|
const realFilePath = await fs.realpath(filePath);
|
|
278
458
|
if (!realFilePath.startsWith(realResolvedDir + path.sep) &&
|
|
279
459
|
realFilePath !== realResolvedDir) {
|
|
280
460
|
continue;
|
|
281
461
|
}
|
|
462
|
+
// Only load files whose basename is a recognized bootstrap filename
|
|
282
463
|
const baseName = path.basename(relPath);
|
|
283
464
|
if (!VALID_BOOTSTRAP_NAMES.has(baseName)) {
|
|
284
465
|
continue;
|
|
285
466
|
}
|
|
286
|
-
const content = await
|
|
467
|
+
const content = await readFileWithCache(realFilePath);
|
|
287
468
|
result.push({
|
|
288
469
|
name: baseName,
|
|
289
470
|
path: filePath,
|
|
@@ -297,8 +478,3 @@ export async function loadExtraBootstrapFiles(dir, extraPatterns) {
|
|
|
297
478
|
}
|
|
298
479
|
return result;
|
|
299
480
|
}
|
|
300
|
-
export function filterBootstrapFilesForSession(files, sessionKey) {
|
|
301
|
-
if (!sessionKey || !isSubagentSessionKey(sessionKey))
|
|
302
|
-
return files;
|
|
303
|
-
return files.filter((file) => SUBAGENT_BOOTSTRAP_ALLOWLIST.has(file.name));
|
|
304
|
-
}
|
|
@@ -231,6 +231,28 @@ function buildChatCommands() {
|
|
|
231
231
|
textAlias: "/whoami",
|
|
232
232
|
category: "status",
|
|
233
233
|
}),
|
|
234
|
+
defineChatCommand({
|
|
235
|
+
key: "session",
|
|
236
|
+
nativeName: "session",
|
|
237
|
+
description: "Manage session-level settings (for example /session ttl).",
|
|
238
|
+
textAlias: "/session",
|
|
239
|
+
category: "session",
|
|
240
|
+
args: [
|
|
241
|
+
{
|
|
242
|
+
name: "action",
|
|
243
|
+
description: "ttl",
|
|
244
|
+
type: "string",
|
|
245
|
+
choices: ["ttl"],
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: "value",
|
|
249
|
+
description: "Duration (24h, 90m) or off",
|
|
250
|
+
type: "string",
|
|
251
|
+
captureRemaining: true,
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
argsMenu: "auto",
|
|
255
|
+
}),
|
|
234
256
|
defineChatCommand({
|
|
235
257
|
key: "subagents",
|
|
236
258
|
nativeName: "subagents",
|
|
@@ -258,6 +280,35 @@ function buildChatCommands() {
|
|
|
258
280
|
],
|
|
259
281
|
argsMenu: "auto",
|
|
260
282
|
}),
|
|
283
|
+
defineChatCommand({
|
|
284
|
+
key: "focus",
|
|
285
|
+
nativeName: "focus",
|
|
286
|
+
description: "Bind this Discord thread (or a new one) to a session target.",
|
|
287
|
+
textAlias: "/focus",
|
|
288
|
+
category: "management",
|
|
289
|
+
args: [
|
|
290
|
+
{
|
|
291
|
+
name: "target",
|
|
292
|
+
description: "Subagent label/index or session key/id/label",
|
|
293
|
+
type: "string",
|
|
294
|
+
captureRemaining: true,
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
}),
|
|
298
|
+
defineChatCommand({
|
|
299
|
+
key: "unfocus",
|
|
300
|
+
nativeName: "unfocus",
|
|
301
|
+
description: "Remove the current Discord thread binding.",
|
|
302
|
+
textAlias: "/unfocus",
|
|
303
|
+
category: "management",
|
|
304
|
+
}),
|
|
305
|
+
defineChatCommand({
|
|
306
|
+
key: "agents",
|
|
307
|
+
nativeName: "agents",
|
|
308
|
+
description: "List thread-bound agents for this session.",
|
|
309
|
+
textAlias: "/agents",
|
|
310
|
+
category: "management",
|
|
311
|
+
}),
|
|
261
312
|
defineChatCommand({
|
|
262
313
|
key: "kill",
|
|
263
314
|
nativeName: "kill",
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { getChatCommands, getNativeCommandSurfaces } from "./commands-registry.data.js";
|
|
2
1
|
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
|
|
3
2
|
import { resolveConfiguredModelRef } from "../agents/model-selection.js";
|
|
3
|
+
import { isCommandFlagEnabled } from "../config/commands.js";
|
|
4
|
+
import { escapeRegExp } from "../utils.js";
|
|
5
|
+
import { getChatCommands, getNativeCommandSurfaces } from "./commands-registry.data.js";
|
|
4
6
|
let cachedTextAliasMap = null;
|
|
5
7
|
let cachedTextAliasCommands = null;
|
|
6
8
|
let cachedDetection;
|
|
@@ -29,9 +31,6 @@ function getTextAliasMap() {
|
|
|
29
31
|
cachedTextAliasCommands = commands;
|
|
30
32
|
return map;
|
|
31
33
|
}
|
|
32
|
-
function escapeRegExp(value) {
|
|
33
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
34
|
-
}
|
|
35
34
|
function buildSkillCommandDefinitions(skillCommands) {
|
|
36
35
|
if (!skillCommands || skillCommands.length === 0)
|
|
37
36
|
return [];
|
|
@@ -53,11 +52,11 @@ export function listChatCommands(params) {
|
|
|
53
52
|
}
|
|
54
53
|
export function isCommandEnabled(cfg, commandKey) {
|
|
55
54
|
if (commandKey === "config")
|
|
56
|
-
return cfg
|
|
55
|
+
return isCommandFlagEnabled(cfg, "config");
|
|
57
56
|
if (commandKey === "debug")
|
|
58
|
-
return cfg
|
|
57
|
+
return isCommandFlagEnabled(cfg, "debug");
|
|
59
58
|
if (commandKey === "bash")
|
|
60
|
-
return cfg
|
|
59
|
+
return isCommandFlagEnabled(cfg, "bash");
|
|
61
60
|
return true;
|
|
62
61
|
}
|
|
63
62
|
export function listChatCommandsForConfig(cfg, params) {
|
|
@@ -81,25 +80,24 @@ function resolveNativeName(command, provider) {
|
|
|
81
80
|
}
|
|
82
81
|
return command.nativeName;
|
|
83
82
|
}
|
|
84
|
-
|
|
85
|
-
return
|
|
86
|
-
|
|
87
|
-
.map((command) => ({
|
|
88
|
-
name: resolveNativeName(command, params?.provider) ?? command.key,
|
|
83
|
+
function toNativeCommandSpec(command, provider) {
|
|
84
|
+
return {
|
|
85
|
+
name: resolveNativeName(command, provider) ?? command.key,
|
|
89
86
|
description: command.description,
|
|
90
87
|
acceptsArgs: Boolean(command.acceptsArgs),
|
|
91
88
|
args: command.args,
|
|
92
|
-
}
|
|
89
|
+
};
|
|
93
90
|
}
|
|
94
|
-
|
|
95
|
-
return
|
|
91
|
+
function listNativeSpecsFromCommands(commands, provider) {
|
|
92
|
+
return commands
|
|
96
93
|
.filter((command) => command.scope !== "text" && command.nativeName)
|
|
97
|
-
.map((command) => (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
94
|
+
.map((command) => toNativeCommandSpec(command, provider));
|
|
95
|
+
}
|
|
96
|
+
export function listNativeCommandSpecs(params) {
|
|
97
|
+
return listNativeSpecsFromCommands(listChatCommands({ skillCommands: params?.skillCommands }), params?.provider);
|
|
98
|
+
}
|
|
99
|
+
export function listNativeCommandSpecsForConfig(cfg, params) {
|
|
100
|
+
return listNativeSpecsFromCommands(listChatCommandsForConfig(cfg, params), params?.provider);
|
|
103
101
|
}
|
|
104
102
|
export function findCommandByNativeName(name, provider) {
|
|
105
103
|
const normalized = name.trim().toLowerCase();
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { formatProviderModelRef } from "./model-runtime.js";
|
|
2
|
+
const FALLBACK_REASON_PART_MAX = 80;
|
|
3
|
+
export function normalizeFallbackModelRef(value) {
|
|
4
|
+
const trimmed = String(value ?? "").trim();
|
|
5
|
+
return trimmed || undefined;
|
|
6
|
+
}
|
|
7
|
+
function truncateFallbackReasonPart(value, max = FALLBACK_REASON_PART_MAX) {
|
|
8
|
+
const text = String(value ?? "")
|
|
9
|
+
.replace(/\s+/g, " ")
|
|
10
|
+
.trim();
|
|
11
|
+
if (text.length <= max) {
|
|
12
|
+
return text;
|
|
13
|
+
}
|
|
14
|
+
return `${text.slice(0, Math.max(0, max - 1)).trimEnd()}…`;
|
|
15
|
+
}
|
|
16
|
+
export function formatFallbackAttemptReason(attempt) {
|
|
17
|
+
const reason = attempt.reason?.trim();
|
|
18
|
+
if (reason) {
|
|
19
|
+
return reason.replace(/_/g, " ");
|
|
20
|
+
}
|
|
21
|
+
const code = attempt.code?.trim();
|
|
22
|
+
if (code) {
|
|
23
|
+
return code;
|
|
24
|
+
}
|
|
25
|
+
if (typeof attempt.status === "number") {
|
|
26
|
+
return `HTTP ${attempt.status}`;
|
|
27
|
+
}
|
|
28
|
+
return truncateFallbackReasonPart(attempt.error || "error");
|
|
29
|
+
}
|
|
30
|
+
function formatFallbackAttemptSummary(attempt) {
|
|
31
|
+
return `${formatProviderModelRef(attempt.provider, attempt.model)} ${formatFallbackAttemptReason(attempt)}`;
|
|
32
|
+
}
|
|
33
|
+
export function buildFallbackReasonSummary(attempts) {
|
|
34
|
+
const firstAttempt = attempts[0];
|
|
35
|
+
const firstReason = firstAttempt
|
|
36
|
+
? formatFallbackAttemptReason(firstAttempt)
|
|
37
|
+
: "selected model unavailable";
|
|
38
|
+
const moreAttempts = attempts.length > 1 ? ` (+${attempts.length - 1} more attempts)` : "";
|
|
39
|
+
return `${truncateFallbackReasonPart(firstReason)}${moreAttempts}`;
|
|
40
|
+
}
|
|
41
|
+
export function buildFallbackAttemptSummaries(attempts) {
|
|
42
|
+
return attempts.map((attempt) => truncateFallbackReasonPart(formatFallbackAttemptSummary(attempt)));
|
|
43
|
+
}
|
|
44
|
+
export function buildFallbackNotice(params) {
|
|
45
|
+
const selected = formatProviderModelRef(params.selectedProvider, params.selectedModel);
|
|
46
|
+
const active = formatProviderModelRef(params.activeProvider, params.activeModel);
|
|
47
|
+
if (selected === active) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const reasonSummary = buildFallbackReasonSummary(params.attempts);
|
|
51
|
+
return `↪️ Model Fallback: ${active} (selected ${selected}; ${reasonSummary})`;
|
|
52
|
+
}
|
|
53
|
+
export function buildFallbackClearedNotice(params) {
|
|
54
|
+
const selected = formatProviderModelRef(params.selectedProvider, params.selectedModel);
|
|
55
|
+
const previous = normalizeFallbackModelRef(params.previousActiveModel);
|
|
56
|
+
if (previous && previous !== selected) {
|
|
57
|
+
return `↪️ Model Fallback cleared: ${selected} (was ${previous})`;
|
|
58
|
+
}
|
|
59
|
+
return `↪️ Model Fallback cleared: ${selected}`;
|
|
60
|
+
}
|
|
61
|
+
export function resolveActiveFallbackState(params) {
|
|
62
|
+
const selected = normalizeFallbackModelRef(params.state?.fallbackNoticeSelectedModel);
|
|
63
|
+
const active = normalizeFallbackModelRef(params.state?.fallbackNoticeActiveModel);
|
|
64
|
+
const reason = normalizeFallbackModelRef(params.state?.fallbackNoticeReason);
|
|
65
|
+
const fallbackActive = params.selectedModelRef !== params.activeModelRef &&
|
|
66
|
+
selected === params.selectedModelRef &&
|
|
67
|
+
active === params.activeModelRef;
|
|
68
|
+
return {
|
|
69
|
+
active: fallbackActive,
|
|
70
|
+
reason: fallbackActive ? reason : undefined,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export function resolveFallbackTransition(params) {
|
|
74
|
+
const selectedModelRef = formatProviderModelRef(params.selectedProvider, params.selectedModel);
|
|
75
|
+
const activeModelRef = formatProviderModelRef(params.activeProvider, params.activeModel);
|
|
76
|
+
const previousState = {
|
|
77
|
+
selectedModel: normalizeFallbackModelRef(params.state?.fallbackNoticeSelectedModel),
|
|
78
|
+
activeModel: normalizeFallbackModelRef(params.state?.fallbackNoticeActiveModel),
|
|
79
|
+
reason: normalizeFallbackModelRef(params.state?.fallbackNoticeReason),
|
|
80
|
+
};
|
|
81
|
+
const fallbackActive = selectedModelRef !== activeModelRef;
|
|
82
|
+
const fallbackTransitioned = fallbackActive &&
|
|
83
|
+
(previousState.selectedModel !== selectedModelRef ||
|
|
84
|
+
previousState.activeModel !== activeModelRef);
|
|
85
|
+
const fallbackCleared = !fallbackActive && Boolean(previousState.selectedModel || previousState.activeModel);
|
|
86
|
+
const reasonSummary = buildFallbackReasonSummary(params.attempts);
|
|
87
|
+
const attemptSummaries = buildFallbackAttemptSummaries(params.attempts);
|
|
88
|
+
const nextState = fallbackActive
|
|
89
|
+
? {
|
|
90
|
+
selectedModel: selectedModelRef,
|
|
91
|
+
activeModel: activeModelRef,
|
|
92
|
+
reason: reasonSummary,
|
|
93
|
+
}
|
|
94
|
+
: {
|
|
95
|
+
selectedModel: undefined,
|
|
96
|
+
activeModel: undefined,
|
|
97
|
+
reason: undefined,
|
|
98
|
+
};
|
|
99
|
+
const stateChanged = previousState.selectedModel !== nextState.selectedModel ||
|
|
100
|
+
previousState.activeModel !== nextState.activeModel ||
|
|
101
|
+
previousState.reason !== nextState.reason;
|
|
102
|
+
return {
|
|
103
|
+
selectedModelRef,
|
|
104
|
+
activeModelRef,
|
|
105
|
+
fallbackActive,
|
|
106
|
+
fallbackTransitioned,
|
|
107
|
+
fallbackCleared,
|
|
108
|
+
reasonSummary,
|
|
109
|
+
attemptSummaries,
|
|
110
|
+
previousState,
|
|
111
|
+
nextState,
|
|
112
|
+
stateChanged,
|
|
113
|
+
};
|
|
114
|
+
}
|