@cjhyy/code-shell-core 0.5.0-rc.1 → 0.6.0-rc.1
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/README.md +13 -10
- package/dist/agent/agent-definition-registry.d.ts +21 -3
- package/dist/agent/agent-definition-registry.js +49 -18
- package/dist/agent/agent-definition.d.ts +32 -0
- package/dist/agent/agent-definition.js +49 -4
- package/dist/arena/arena.js +11 -12
- package/dist/arena/context/context-tools.js +47 -6
- package/dist/arena/context/within-root.d.ts +7 -0
- package/dist/arena/context/within-root.js +15 -0
- package/dist/arena/iterate/phases/argue.js +8 -2
- package/dist/arena/iterate/phases/revise.js +1 -1
- package/dist/arena/iterate/phases/tournament.js +3 -3
- package/dist/arena/ledger.js +9 -1
- package/dist/arena/phases/adjudication.js +1 -4
- package/dist/arena/phases/build-consensus.js +1 -4
- package/dist/arena/phases/cross-review.js +2 -8
- package/dist/arena/phases/debate-rounds.js +1 -4
- package/dist/arena/phases/participant-research.js +1 -4
- package/dist/arena/phases/planning-detail-expansion.js +8 -10
- package/dist/arena/planner.js +0 -1
- package/dist/arena/providers/docs.d.ts +1 -0
- package/dist/arena/providers/docs.js +5 -2
- package/dist/arena/providers/repo.d.ts +1 -0
- package/dist/arena/providers/repo.js +5 -2
- package/dist/arena/strategies/utils.d.ts +1 -4
- package/dist/arena/strategies/utils.js +7 -51
- package/dist/arena/transitions.d.ts +7 -2
- package/dist/arena/transitions.js +9 -4
- package/dist/arena/types.d.ts +8 -2
- package/dist/automation/cron-expr.d.ts +41 -0
- package/dist/automation/cron-expr.js +169 -0
- package/dist/automation/index.d.ts +41 -0
- package/dist/automation/index.js +39 -0
- package/dist/automation/runner.d.ts +84 -0
- package/dist/automation/runner.js +92 -0
- package/dist/automation/scheduler.d.ts +194 -0
- package/dist/automation/scheduler.js +623 -0
- package/dist/automation/store.d.ts +39 -0
- package/dist/automation/store.js +122 -0
- package/dist/automation/write-policy.d.ts +34 -0
- package/dist/automation/write-policy.js +113 -0
- package/dist/automation/write-run.d.ts +51 -0
- package/dist/automation/write-run.js +38 -0
- package/dist/capability-control/disabled-lists.d.ts +25 -0
- package/dist/capability-control/disabled-lists.js +57 -0
- package/dist/capability-control/index.d.ts +5 -0
- package/dist/capability-control/index.js +3 -0
- package/dist/capability-control/overlay.d.ts +64 -0
- package/dist/capability-control/overlay.js +116 -0
- package/dist/capability-control/project.d.ts +65 -0
- package/dist/capability-control/project.js +147 -0
- package/dist/capability-control/service.d.ts +70 -0
- package/dist/capability-control/service.js +147 -0
- package/dist/capability-control/types.d.ts +62 -0
- package/dist/capability-control/types.js +17 -0
- package/dist/cc-orchestrator/agent-adapter.d.ts +50 -0
- package/dist/cc-orchestrator/agent-adapter.js +133 -0
- package/dist/cc-orchestrator/cc-capability.d.ts +19 -0
- package/dist/cc-orchestrator/cc-capability.js +53 -0
- package/dist/cc-orchestrator/codex-session-discovery.d.ts +24 -0
- package/dist/cc-orchestrator/codex-session-discovery.js +191 -0
- package/dist/cc-orchestrator/codex-session-history.d.ts +25 -0
- package/dist/cc-orchestrator/codex-session-history.js +187 -0
- package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
- package/dist/cc-orchestrator/external-agent-changes.js +214 -0
- package/dist/cc-orchestrator/external-agent-driver.d.ts +18 -0
- package/dist/cc-orchestrator/external-agent-driver.js +69 -0
- package/dist/cc-orchestrator/index.d.ts +8 -0
- package/dist/cc-orchestrator/index.js +8 -0
- package/dist/cc-orchestrator/relevance-judge.d.ts +15 -0
- package/dist/cc-orchestrator/relevance-judge.js +29 -0
- package/dist/cc-orchestrator/session-discovery.d.ts +46 -0
- package/dist/cc-orchestrator/session-discovery.js +125 -0
- package/dist/cc-orchestrator/session-history.d.ts +19 -0
- package/dist/cc-orchestrator/session-history.js +67 -0
- package/dist/cli/agent-server-stdio.d.ts +26 -1
- package/dist/cli/agent-server-stdio.js +221 -28
- package/dist/cli/agent-server-tcp.d.ts +20 -0
- package/dist/cli/agent-server-tcp.js +134 -0
- package/dist/cli/graceful-shutdown.d.ts +27 -0
- package/dist/cli/graceful-shutdown.js +30 -0
- package/dist/context/compaction.d.ts +56 -0
- package/dist/context/compaction.js +209 -15
- package/dist/context/manager.d.ts +0 -20
- package/dist/context/manager.js +25 -41
- package/dist/cost-tracker.js +5 -61
- package/dist/credentials/cipher.d.ts +49 -0
- package/dist/credentials/cipher.js +45 -0
- package/dist/credentials/cookie-jar.d.ts +24 -0
- package/dist/credentials/cookie-jar.js +40 -0
- package/dist/credentials/index.d.ts +7 -0
- package/dist/credentials/index.js +5 -0
- package/dist/credentials/inject-credential-tool.d.ts +20 -0
- package/dist/credentials/inject-credential-tool.js +130 -0
- package/dist/credentials/store.d.ts +72 -0
- package/dist/credentials/store.js +184 -0
- package/dist/credentials/types.d.ts +56 -0
- package/dist/credentials/use-credential-tool.d.ts +29 -0
- package/dist/credentials/use-credential-tool.js +205 -0
- package/dist/credentials/use-gate.d.ts +56 -0
- package/dist/credentials/use-gate.js +52 -0
- package/dist/cron/cron-runtime.d.ts +2 -0
- package/dist/cron/cron-runtime.js +2 -0
- package/dist/cron/cron-store.d.ts +2 -0
- package/dist/cron/cron-store.js +2 -0
- package/dist/cron/scheduler.d.ts +5 -32
- package/dist/cron/scheduler.js +5 -113
- package/dist/data/model-metadata.d.ts +77 -0
- package/dist/data/model-metadata.js +56 -0
- package/dist/data/model-metadata.json +216 -0
- package/dist/data/openrouter-models.d.ts +18 -7
- package/dist/data/openrouter-models.js +35 -8
- package/dist/data/openrouter-sync.js +1 -1
- package/dist/engine/aux-key.d.ts +10 -0
- package/dist/engine/aux-key.js +11 -0
- package/dist/engine/dynamic-tool-defs.d.ts +19 -0
- package/dist/engine/dynamic-tool-defs.js +36 -0
- package/dist/engine/engine.d.ts +431 -108
- package/dist/engine/engine.js +1630 -279
- package/dist/engine/friendly-error.d.ts +18 -0
- package/dist/engine/friendly-error.js +63 -0
- package/dist/engine/goal.d.ts +187 -0
- package/dist/engine/goal.js +196 -0
- package/dist/engine/image-compression.d.ts +81 -0
- package/dist/engine/image-compression.js +186 -0
- package/dist/engine/image-policy.d.ts +165 -0
- package/dist/engine/image-policy.js +189 -0
- package/dist/engine/model-connections-pool.d.ts +17 -0
- package/dist/engine/model-connections-pool.js +66 -0
- package/dist/engine/model-facade.d.ts +10 -0
- package/dist/engine/model-facade.js +25 -0
- package/dist/engine/patch-orphaned-tools.js +3 -0
- package/dist/engine/reactive-threshold.d.ts +13 -0
- package/dist/engine/reactive-threshold.js +17 -0
- package/dist/engine/resolve-llm-config.d.ts +16 -0
- package/dist/engine/resolve-llm-config.js +44 -0
- package/dist/engine/runtime.js +9 -1
- package/dist/engine/sandbox-cache-key.d.ts +10 -0
- package/dist/engine/sandbox-cache-key.js +9 -0
- package/dist/engine/sandbox-config.d.ts +31 -0
- package/dist/engine/sandbox-config.js +38 -0
- package/dist/engine/session-title.d.ts +13 -0
- package/dist/engine/session-title.js +34 -0
- package/dist/engine/session-usage.d.ts +19 -0
- package/dist/engine/session-usage.js +25 -0
- package/dist/engine/steer-queue.d.ts +32 -0
- package/dist/engine/steer-queue.js +26 -0
- package/dist/engine/streaming-tool-queue.d.ts +12 -0
- package/dist/engine/streaming-tool-queue.js +50 -10
- package/dist/engine/turn-loop.d.ts +94 -9
- package/dist/engine/turn-loop.js +775 -342
- package/dist/engine/types.d.ts +175 -0
- package/dist/engine/types.js +13 -0
- package/dist/external-agents/config.d.ts +2 -0
- package/dist/external-agents/config.js +15 -0
- package/dist/external-agents/types.d.ts +31 -0
- package/dist/external-agents/types.js +1 -0
- package/dist/git/parse-log.d.ts +13 -0
- package/dist/git/parse-log.js +21 -0
- package/dist/git/utils.d.ts +8 -6
- package/dist/git/utils.js +62 -26
- package/dist/git/worktree.d.ts +48 -0
- package/dist/git/worktree.js +111 -20
- package/dist/hooks/events.d.ts +23 -1
- package/dist/hooks/goal-stop-hook.d.ts +58 -0
- package/dist/hooks/goal-stop-hook.js +279 -0
- package/dist/hooks/hook-output.d.ts +33 -0
- package/dist/hooks/hook-output.js +79 -0
- package/dist/hooks/registry.d.ts +15 -0
- package/dist/hooks/registry.js +57 -1
- package/dist/hooks/shell-runner.d.ts +2 -0
- package/dist/hooks/shell-runner.js +48 -18
- package/dist/index.d.ts +79 -11
- package/dist/index.js +89 -6
- package/dist/llm/capabilities/param-specs.d.ts +14 -0
- package/dist/llm/capabilities/param-specs.js +62 -0
- package/dist/llm/capabilities/reasoning-control.d.ts +24 -0
- package/dist/llm/capabilities/reasoning-control.js +38 -0
- package/dist/llm/capabilities/rules.js +37 -3
- package/dist/llm/capabilities/types.d.ts +32 -2
- package/dist/llm/clamp-max-tokens.d.ts +11 -0
- package/dist/llm/clamp-max-tokens.js +17 -0
- package/dist/llm/client-base.d.ts +69 -5
- package/dist/llm/client-base.js +185 -25
- package/dist/llm/client-factory.d.ts +3 -3
- package/dist/llm/client-factory.js +2 -2
- package/dist/llm/model-cache.js +4 -2
- package/dist/llm/model-pool.d.ts +29 -11
- package/dist/llm/model-pool.js +36 -20
- package/dist/llm/provider-auth.d.ts +41 -0
- package/dist/llm/provider-auth.js +76 -0
- package/dist/llm/provider-catalog.d.ts +6 -2
- package/dist/llm/providers/anthropic.d.ts +32 -2
- package/dist/llm/providers/anthropic.js +207 -18
- package/dist/llm/providers/openai.d.ts +47 -2
- package/dist/llm/providers/openai.js +478 -71
- package/dist/llm/reasoning-setting.d.ts +51 -0
- package/dist/llm/reasoning-setting.js +40 -0
- package/dist/llm/stop-reason.d.ts +13 -0
- package/dist/llm/stop-reason.js +21 -0
- package/dist/llm/stream-watchdog.js +5 -1
- package/dist/llm/strip-vision.d.ts +32 -0
- package/dist/llm/strip-vision.js +94 -0
- package/dist/llm/token-counter.js +9 -2
- package/dist/llm/types.d.ts +9 -6
- package/dist/logging/logger.js +18 -4
- package/dist/logging/sanitize-messages.d.ts +10 -0
- package/dist/logging/sanitize-messages.js +112 -0
- package/dist/lsp/client.js +28 -8
- package/dist/lsp/manager.d.ts +1 -1
- package/dist/lsp/manager.js +42 -11
- package/dist/lsp/root-path.d.ts +9 -0
- package/dist/lsp/root-path.js +12 -0
- package/dist/model-catalog/builtin.d.ts +12 -0
- package/dist/model-catalog/builtin.js +407 -0
- package/dist/model-catalog/gen-connections.d.ts +20 -0
- package/dist/model-catalog/gen-connections.js +28 -0
- package/dist/model-catalog/index.d.ts +41 -0
- package/dist/model-catalog/index.js +90 -0
- package/dist/model-catalog/params.d.ts +20 -0
- package/dist/model-catalog/params.js +45 -0
- package/dist/model-catalog/resolve.d.ts +48 -0
- package/dist/model-catalog/resolve.js +33 -0
- package/dist/model-catalog/save-entry.d.ts +32 -0
- package/dist/model-catalog/save-entry.js +104 -0
- package/dist/model-catalog/types.d.ts +561 -0
- package/dist/model-catalog/types.js +93 -0
- package/dist/model-catalog/upsert.d.ts +9 -0
- package/dist/model-catalog/upsert.js +8 -0
- package/dist/onboarding.d.ts +12 -82
- package/dist/onboarding.js +75 -333
- package/dist/plugins/gitOps.d.ts +53 -0
- package/dist/plugins/gitOps.js +130 -5
- package/dist/plugins/installer/checkUpdate.d.ts +16 -0
- package/dist/plugins/installer/checkUpdate.js +32 -0
- package/dist/plugins/installer/codex/convertAgents.d.ts +7 -0
- package/dist/plugins/installer/codex/convertAgents.js +55 -0
- package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
- package/dist/plugins/installer/codex/convertCommands.js +46 -0
- package/dist/plugins/installer/codex/convertMcp.d.ts +11 -0
- package/dist/plugins/installer/codex/convertMcp.js +85 -0
- package/dist/plugins/installer/codex/convertSkills.d.ts +12 -0
- package/dist/plugins/installer/codex/convertSkills.js +33 -0
- package/dist/plugins/installer/detectFormat.d.ts +2 -0
- package/dist/plugins/installer/detectFormat.js +6 -0
- package/dist/plugins/installer/install.d.ts +7 -0
- package/dist/plugins/installer/install.js +123 -0
- package/dist/plugins/installer/installFromArchive.d.ts +43 -0
- package/dist/plugins/installer/installFromArchive.js +134 -0
- package/dist/plugins/installer/installFromSource.d.ts +13 -0
- package/dist/plugins/installer/installFromSource.js +51 -0
- package/dist/plugins/installer/list.d.ts +9 -0
- package/dist/plugins/installer/list.js +30 -0
- package/dist/plugins/installer/loadPluginAgents.d.ts +3 -0
- package/dist/plugins/installer/loadPluginAgents.js +27 -0
- package/dist/plugins/installer/loadPluginMcp.d.ts +14 -0
- package/dist/plugins/installer/loadPluginMcp.js +107 -0
- package/dist/plugins/installer/parseSource.d.ts +20 -0
- package/dist/plugins/installer/parseSource.js +74 -0
- package/dist/plugins/installer/paths.d.ts +5 -0
- package/dist/plugins/installer/paths.js +25 -0
- package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
- package/dist/plugins/installer/pruneDisabled.js +73 -0
- package/dist/plugins/installer/types.d.ts +52 -0
- package/dist/plugins/installer/types.js +28 -0
- package/dist/plugins/installer/uninstall.d.ts +2 -0
- package/dist/plugins/installer/uninstall.js +18 -0
- package/dist/plugins/installer/unzip.d.ts +14 -0
- package/dist/plugins/installer/unzip.js +82 -0
- package/dist/plugins/installer/update.d.ts +28 -0
- package/dist/plugins/installer/update.js +97 -0
- package/dist/plugins/loadPluginHooks.d.ts +54 -1
- package/dist/plugins/loadPluginHooks.js +83 -1
- package/dist/plugins/marketplaceManager.d.ts +15 -1
- package/dist/plugins/marketplaceManager.js +58 -4
- package/dist/plugins/pluginCommandHook.js +34 -14
- package/dist/plugins/pluginContent.d.ts +30 -0
- package/dist/plugins/pluginContent.js +83 -0
- package/dist/plugins/pluginInstaller.d.ts +34 -0
- package/dist/plugins/pluginInstaller.js +168 -35
- package/dist/plugins/schemas.js +41 -6
- package/dist/plugins/types.d.ts +10 -0
- package/dist/preset/index.d.ts +7 -1
- package/dist/preset/index.js +112 -6
- package/dist/product/types.d.ts +1 -1
- package/dist/prompt/composer.d.ts +31 -0
- package/dist/prompt/composer.js +95 -25
- package/dist/prompt/instruction-scanner.js +5 -3
- package/dist/prompt/section-loader.js +1 -0
- package/dist/prompt/sections/base.md +1 -0
- package/dist/prompt/sections/browser.md +10 -0
- package/dist/prompt/sections/coding.md +4 -0
- package/dist/prompt/sections/orchestration.md +8 -0
- package/dist/protocol/chat-session-manager.d.ts +15 -2
- package/dist/protocol/chat-session-manager.js +46 -0
- package/dist/protocol/chat-session.d.ts +82 -0
- package/dist/protocol/chat-session.js +121 -1
- package/dist/protocol/client.d.ts +27 -0
- package/dist/protocol/client.js +38 -0
- package/dist/protocol/redact.d.ts +50 -0
- package/dist/protocol/redact.js +71 -0
- package/dist/protocol/server.d.ts +153 -2
- package/dist/protocol/server.js +807 -39
- package/dist/protocol/tcp-transport.d.ts +45 -0
- package/dist/protocol/tcp-transport.js +74 -0
- package/dist/protocol/transport.js +3 -2
- package/dist/protocol/types.d.ts +69 -0
- package/dist/protocol/types.js +22 -0
- package/dist/quota/credentials.d.ts +3 -0
- package/dist/quota/credentials.js +80 -0
- package/dist/quota/index.d.ts +36 -0
- package/dist/quota/index.js +155 -0
- package/dist/quota/types.d.ts +48 -0
- package/dist/quota/types.js +13 -0
- package/dist/remote/bridge.d.ts +11 -2
- package/dist/remote/bridge.js +61 -33
- package/dist/review/review-prompt.d.ts +28 -0
- package/dist/review/review-prompt.js +81 -0
- package/dist/run/ArtifactTracker.js +5 -4
- package/dist/run/EngineRunner.d.ts +27 -1
- package/dist/run/EngineRunner.js +46 -8
- package/dist/run/FileRunStore.js +40 -11
- package/dist/run/RunApprovalBackend.js +25 -5
- package/dist/run/RunLock.d.ts +28 -2
- package/dist/run/RunLock.js +49 -7
- package/dist/run/RunManager.d.ts +12 -0
- package/dist/run/RunManager.js +86 -3
- package/dist/run/RunQueue.d.ts +1 -0
- package/dist/run/RunQueue.js +8 -2
- package/dist/run/factory.d.ts +8 -1
- package/dist/run/factory.js +1 -0
- package/dist/run/index.d.ts +2 -2
- package/dist/run/index.js +1 -1
- package/dist/run/redirect-target.d.ts +7 -0
- package/dist/run/redirect-target.js +13 -0
- package/dist/run/types.js +1 -1
- package/dist/runtime/background-shell.d.ts +139 -0
- package/dist/runtime/background-shell.js +495 -0
- package/dist/runtime/output-clean.d.ts +24 -0
- package/dist/runtime/output-clean.js +41 -0
- package/dist/runtime/ring-file.d.ts +64 -0
- package/dist/runtime/ring-file.js +174 -0
- package/dist/runtime/safe-spawn.js +15 -34
- package/dist/runtime/spawn-common.d.ts +148 -0
- package/dist/runtime/spawn-common.js +303 -0
- package/dist/runtime/truncate-output.d.ts +22 -0
- package/dist/runtime/truncate-output.js +49 -0
- package/dist/runtime/utf8-cut.d.ts +11 -0
- package/dist/runtime/utf8-cut.js +23 -0
- package/dist/services/auto-dream.d.ts +4 -0
- package/dist/services/auto-dream.js +26 -26
- package/dist/services/browser-open.d.ts +13 -0
- package/dist/services/browser-open.js +16 -0
- package/dist/services/diagnostics.d.ts +1 -2
- package/dist/services/diagnostics.js +12 -7
- package/dist/services/dream-consolidation.d.ts +57 -0
- package/dist/services/dream-consolidation.js +151 -0
- package/dist/services/extract-memories.d.ts +14 -1
- package/dist/services/extract-memories.js +45 -6
- package/dist/services/memory-orchestrator.d.ts +21 -0
- package/dist/services/memory-orchestrator.js +125 -32
- package/dist/services/notifier.d.ts +8 -0
- package/dist/services/notifier.js +39 -25
- package/dist/services/oauth.js +5 -7
- package/dist/services/session-memory-sort.d.ts +8 -0
- package/dist/services/session-memory-sort.js +9 -0
- package/dist/services/session-memory.js +30 -19
- package/dist/session/file-history.d.ts +124 -1
- package/dist/session/file-history.js +232 -9
- package/dist/session/memory.d.ts +116 -2
- package/dist/session/memory.js +250 -28
- package/dist/session/session-manager.d.ts +63 -1
- package/dist/session/session-manager.js +186 -5
- package/dist/session/simple-diff.d.ts +23 -0
- package/dist/session/simple-diff.js +84 -0
- package/dist/session/transcript.d.ts +25 -1
- package/dist/session/transcript.js +35 -2
- package/dist/session/undo-target.d.ts +67 -0
- package/dist/session/undo-target.js +144 -0
- package/dist/settings/disk-defaults.d.ts +42 -0
- package/dist/settings/disk-defaults.js +33 -0
- package/dist/settings/feature-flags.d.ts +64 -0
- package/dist/settings/feature-flags.js +61 -0
- package/dist/settings/manager.d.ts +101 -1
- package/dist/settings/manager.js +345 -15
- package/dist/settings/migrate-config.d.ts +45 -0
- package/dist/settings/migrate-config.js +125 -0
- package/dist/settings/personalization.d.ts +19 -0
- package/dist/settings/personalization.js +7 -0
- package/dist/settings/schema-export.d.ts +25 -0
- package/dist/settings/schema-export.js +38 -0
- package/dist/settings/schema.d.ts +1827 -396
- package/dist/settings/schema.js +361 -81
- package/dist/skills/scanner.d.ts +9 -0
- package/dist/skills/scanner.js +30 -2
- package/dist/stt/resolve-transcribe.d.ts +31 -0
- package/dist/stt/resolve-transcribe.js +108 -0
- package/dist/stt/transcribe.d.ts +51 -0
- package/dist/stt/transcribe.js +65 -0
- package/dist/tool-system/browser-bridge.d.ts +226 -0
- package/dist/tool-system/browser-bridge.js +163 -0
- package/dist/tool-system/builtin/add-marketplace.d.ts +12 -0
- package/dist/tool-system/builtin/add-marketplace.js +76 -0
- package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
- package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
- package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
- package/dist/tool-system/builtin/agent-notifications.js +9 -3
- package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
- package/dist/tool-system/builtin/agent-output-file.js +72 -0
- package/dist/tool-system/builtin/agent-registry.d.ts +23 -0
- package/dist/tool-system/builtin/agent-registry.js +16 -4
- package/dist/tool-system/builtin/agent.d.ts +50 -11
- package/dist/tool-system/builtin/agent.js +576 -73
- package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
- package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
- package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
- package/dist/tool-system/builtin/apply-patch/index.js +7 -3
- package/dist/tool-system/builtin/arena.js +6 -7
- package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
- package/dist/tool-system/builtin/background-jobs.js +124 -0
- package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
- package/dist/tool-system/builtin/background-shell-tools.js +108 -0
- package/dist/tool-system/builtin/background-work.d.ts +67 -0
- package/dist/tool-system/builtin/background-work.js +86 -0
- package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
- package/dist/tool-system/builtin/bash-output-style.js +40 -0
- package/dist/tool-system/builtin/bash.d.ts +5 -2
- package/dist/tool-system/builtin/bash.js +98 -62
- package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
- package/dist/tool-system/builtin/browser-tools.js +312 -0
- package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
- package/dist/tool-system/builtin/cancel-goal.js +64 -0
- package/dist/tool-system/builtin/check-quota.d.ts +15 -0
- package/dist/tool-system/builtin/check-quota.js +34 -0
- package/dist/tool-system/builtin/complete-goal.d.ts +25 -0
- package/dist/tool-system/builtin/complete-goal.js +45 -0
- package/dist/tool-system/builtin/config.js +7 -0
- package/dist/tool-system/builtin/cron.d.ts +7 -0
- package/dist/tool-system/builtin/cron.js +105 -9
- package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
- package/dist/tool-system/builtin/drive-claude-code.js +157 -0
- package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
- package/dist/tool-system/builtin/edit-model-catalog.js +94 -0
- package/dist/tool-system/builtin/edit.d.ts +2 -1
- package/dist/tool-system/builtin/edit.js +21 -12
- package/dist/tool-system/builtin/eol.d.ts +29 -0
- package/dist/tool-system/builtin/eol.js +37 -0
- package/dist/tool-system/builtin/file-cache.d.ts +6 -0
- package/dist/tool-system/builtin/file-cache.js +8 -0
- package/dist/tool-system/builtin/generate-image.d.ts +60 -0
- package/dist/tool-system/builtin/generate-image.js +374 -0
- package/dist/tool-system/builtin/generate-video.d.ts +55 -0
- package/dist/tool-system/builtin/generate-video.js +361 -0
- package/dist/tool-system/builtin/grep.js +6 -2
- package/dist/tool-system/builtin/image-providers.d.ts +86 -0
- package/dist/tool-system/builtin/image-providers.js +190 -0
- package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
- package/dist/tool-system/builtin/image-uploader.js +74 -0
- package/dist/tool-system/builtin/index.d.ts +24 -1
- package/dist/tool-system/builtin/index.js +310 -25
- package/dist/tool-system/builtin/mcp-tools.js +23 -3
- package/dist/tool-system/builtin/memory.js +45 -7
- package/dist/tool-system/builtin/notebook-edit.d.ts +2 -1
- package/dist/tool-system/builtin/notebook-edit.js +1 -1
- package/dist/tool-system/builtin/powershell.js +4 -1
- package/dist/tool-system/builtin/read.d.ts +2 -1
- package/dist/tool-system/builtin/read.js +11 -3
- package/dist/tool-system/builtin/repl.js +4 -1
- package/dist/tool-system/builtin/skill.js +9 -0
- package/dist/tool-system/builtin/sleep.js +12 -5
- package/dist/tool-system/builtin/task.js +4 -1
- package/dist/tool-system/builtin/tool-search.js +25 -7
- package/dist/tool-system/builtin/update-automation-memory.d.ts +24 -0
- package/dist/tool-system/builtin/update-automation-memory.js +60 -0
- package/dist/tool-system/builtin/video-providers.d.ts +154 -0
- package/dist/tool-system/builtin/video-providers.js +235 -0
- package/dist/tool-system/builtin/view-image.d.ts +18 -0
- package/dist/tool-system/builtin/view-image.js +96 -0
- package/dist/tool-system/builtin/web-fetch.js +12 -2
- package/dist/tool-system/builtin/web-search.d.ts +4 -1
- package/dist/tool-system/builtin/web-search.js +57 -10
- package/dist/tool-system/builtin/worktree.d.ts +2 -1
- package/dist/tool-system/builtin/worktree.js +31 -4
- package/dist/tool-system/builtin/write.d.ts +2 -1
- package/dist/tool-system/builtin/write.js +1 -1
- package/dist/tool-system/context.d.ts +166 -6
- package/dist/tool-system/executor.d.ts +3 -2
- package/dist/tool-system/executor.js +197 -119
- package/dist/tool-system/investigation-guard.d.ts +4 -1
- package/dist/tool-system/investigation-guard.js +20 -4
- package/dist/tool-system/mcp-manager.d.ts +78 -16
- package/dist/tool-system/mcp-manager.js +357 -28
- package/dist/tool-system/path-policy.d.ts +99 -0
- package/dist/tool-system/path-policy.js +578 -0
- package/dist/tool-system/permission.d.ts +36 -1
- package/dist/tool-system/permission.js +322 -117
- package/dist/tool-system/plan-mode-allowlist.d.ts +32 -0
- package/dist/tool-system/plan-mode-allowlist.js +65 -0
- package/dist/tool-system/registry.d.ts +1 -0
- package/dist/tool-system/registry.js +26 -1
- package/dist/tool-system/sandbox/index.d.ts +8 -0
- package/dist/tool-system/sandbox/index.js +7 -2
- package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
- package/dist/tool-system/validate-tool-metadata.js +63 -0
- package/dist/tool-system/validation.d.ts +10 -0
- package/dist/tool-system/validation.js +16 -3
- package/dist/types.d.ts +301 -15
- package/dist/updater.js +20 -9
- package/dist/utils/envUtils.d.ts +0 -9
- package/dist/utils/envUtils.js +3 -28
- package/dist/utils/exec.d.ts +40 -0
- package/dist/utils/exec.js +144 -0
- package/dist/utils/format.js +4 -2
- package/dist/utils/json.d.ts +12 -0
- package/dist/utils/json.js +92 -0
- package/dist/utils/lockfile.js +9 -2
- package/dist/utils/theme.d.ts +7 -1
- package/dist/utils/theme.js +5 -3
- package/dist/utils/toolDisplay.js +0 -1
- package/package.json +14 -7
- package/dist/agent/coordinator.d.ts +0 -49
- package/dist/agent/coordinator.js +0 -77
- package/dist/settings/manager.test.js +0 -73
- package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
- package/dist/tool-system/builtin/remote-trigger.js +0 -54
- package/dist/tool-system/builtin/send-message.d.ts +0 -6
- package/dist/tool-system/builtin/send-message.js +0 -47
- /package/dist/{settings/manager.test.d.ts → credentials/types.js} +0 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-side image compression — the fallback for hosts that didn't
|
|
3
|
+
* pre-compress.
|
|
4
|
+
*
|
|
5
|
+
* The desktop renderer already compresses via <canvas> + Blob before
|
|
6
|
+
* sending; the TUI and MCP image-returning tools historically didn't.
|
|
7
|
+
* When the {@link enforceImagePolicy} gate would otherwise refuse a
|
|
8
|
+
* turn for "image too large", we try to bring the offender(s) under
|
|
9
|
+
* the limit first by:
|
|
10
|
+
*
|
|
11
|
+
* 1. Decoding the base64 payload.
|
|
12
|
+
* 2. Resizing the longest edge down to {@link IMAGE_TARGETS.targetMaxDimension}.
|
|
13
|
+
* 3. Re-encoding as JPEG at {@link IMAGE_TARGETS.jpegQuality}.
|
|
14
|
+
*
|
|
15
|
+
* jimp is the obvious pick — pure-JS, no native binaries, runs in
|
|
16
|
+
* both Node and Bun, supports PNG / JPEG / WebP input. But shipping
|
|
17
|
+
* it as a hard `core` dep would balloon the published bundle for
|
|
18
|
+
* every consumer. So we resolve it dynamically: hosts that want
|
|
19
|
+
* automatic compression just `npm install jimp`; everyone else gets
|
|
20
|
+
* the existing "image too large" refusal.
|
|
21
|
+
*
|
|
22
|
+
* Hosts can also inject a custom {@link ImageCompressor} via
|
|
23
|
+
* {@link setEngineImageCompressor} — useful for tests, future
|
|
24
|
+
* sharp-based compressors, or arena agents with different size
|
|
25
|
+
* targets.
|
|
26
|
+
*
|
|
27
|
+
* The defaults must stay pure-JS so this module is safe to bundle for
|
|
28
|
+
* Electron preload / browser worker contexts. Anything that needs
|
|
29
|
+
* native code (e.g. sharp) should be injected explicitly.
|
|
30
|
+
*/
|
|
31
|
+
import { IMAGE_LIMITS, IMAGE_TARGETS, byteLengthFromBase64 } from "./image-policy.js";
|
|
32
|
+
/**
|
|
33
|
+
* No-op compressor: returns the input unchanged. Used when the host
|
|
34
|
+
* didn't install jimp and didn't inject anything else, so behavior
|
|
35
|
+
* stays the same as before this module existed.
|
|
36
|
+
*/
|
|
37
|
+
const NOOP_COMPRESSOR = {
|
|
38
|
+
async compress(image, _maxBytes) {
|
|
39
|
+
const bytes = byteLengthFromBase64(image.base64);
|
|
40
|
+
return {
|
|
41
|
+
image,
|
|
42
|
+
compressed: false,
|
|
43
|
+
originalBytes: bytes,
|
|
44
|
+
finalBytes: bytes,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
let activeCompressor = null;
|
|
49
|
+
/**
|
|
50
|
+
* Override the engine's active compressor. Pass `null` to clear the
|
|
51
|
+
* override and fall back to lazy jimp resolution. Hosts that want
|
|
52
|
+
* deterministic behavior in tests typically call this with a stub.
|
|
53
|
+
*/
|
|
54
|
+
export function setEngineImageCompressor(c) {
|
|
55
|
+
activeCompressor = c;
|
|
56
|
+
}
|
|
57
|
+
/** Reset state — for tests. */
|
|
58
|
+
export function resetEngineImageCompressor() {
|
|
59
|
+
activeCompressor = null;
|
|
60
|
+
cachedJimpCompressor = null;
|
|
61
|
+
}
|
|
62
|
+
let cachedJimpCompressor = null;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a jimp-backed compressor on first call. If jimp isn't
|
|
65
|
+
* installed, cache the no-op and stop retrying.
|
|
66
|
+
*
|
|
67
|
+
* jimp's API: `await Jimp.read(buffer)` → resize / quality / getBuffer.
|
|
68
|
+
* v0.x used CamelCase constants (e.g. `Jimp.MIME_JPEG`); v1 moved to
|
|
69
|
+
* an explicit string mime arg. We accept both by feature-testing.
|
|
70
|
+
*/
|
|
71
|
+
async function resolveJimpCompressor() {
|
|
72
|
+
if (cachedJimpCompressor)
|
|
73
|
+
return cachedJimpCompressor;
|
|
74
|
+
try {
|
|
75
|
+
// Dynamic import so consumers without jimp installed don't pay
|
|
76
|
+
// the bundle cost. The default export shape differs across v0/v1,
|
|
77
|
+
// hence the `any` cast. The literal module specifier is a string
|
|
78
|
+
// we resolve at runtime — TS sees no type info for it and would
|
|
79
|
+
// otherwise error TS2307 when jimp isn't on the host's path.
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
81
|
+
const dynImport = (s) =>
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
83
|
+
Function("s", "return import(s)")(s);
|
|
84
|
+
const mod = (await dynImport("jimp"));
|
|
85
|
+
const Jimp = (mod.default ?? mod.Jimp ?? mod);
|
|
86
|
+
cachedJimpCompressor = {
|
|
87
|
+
async compress(image, maxBytes) {
|
|
88
|
+
const original = Buffer.from(image.base64, "base64");
|
|
89
|
+
const originalBytes = original.byteLength;
|
|
90
|
+
if (originalBytes <= maxBytes) {
|
|
91
|
+
return { image, compressed: false, originalBytes, finalBytes: originalBytes };
|
|
92
|
+
}
|
|
93
|
+
let pic;
|
|
94
|
+
try {
|
|
95
|
+
pic = await Jimp.read(original);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Unknown / corrupt format. Leave it alone; the policy gate
|
|
99
|
+
// will refuse and surface a meaningful message to the user.
|
|
100
|
+
return { image, compressed: false, originalBytes, finalBytes: originalBytes };
|
|
101
|
+
}
|
|
102
|
+
// Scale longest edge down to the target. We may still be over
|
|
103
|
+
// after one pass for very large source images, so loop with
|
|
104
|
+
// decreasing quality / dimension until under cap or we hit the
|
|
105
|
+
// floor.
|
|
106
|
+
const targets = [
|
|
107
|
+
{ dim: IMAGE_TARGETS.targetMaxDimension, q: Math.round(IMAGE_TARGETS.jpegQuality * 100) },
|
|
108
|
+
{ dim: 1280, q: 75 },
|
|
109
|
+
{ dim: 1024, q: 65 },
|
|
110
|
+
{ dim: 800, q: 55 },
|
|
111
|
+
];
|
|
112
|
+
const mime = Jimp.MIME_JPEG ?? "image/jpeg";
|
|
113
|
+
let bestBuf = null;
|
|
114
|
+
for (const t of targets) {
|
|
115
|
+
const w = pic.bitmap?.width ?? t.dim;
|
|
116
|
+
const h = pic.bitmap?.height ?? t.dim;
|
|
117
|
+
const longest = Math.max(w, h);
|
|
118
|
+
// Only scale down — never up an already-small image.
|
|
119
|
+
if (longest > t.dim) {
|
|
120
|
+
if (w >= h) {
|
|
121
|
+
pic.resize(t.dim, Math.round((h / w) * t.dim));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
pic.resize(Math.round((w / h) * t.dim), t.dim);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
pic.quality(t.q);
|
|
128
|
+
const buf = await pic.getBufferAsync(mime);
|
|
129
|
+
if (buf.byteLength <= maxBytes) {
|
|
130
|
+
bestBuf = buf;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
bestBuf = buf;
|
|
134
|
+
}
|
|
135
|
+
if (!bestBuf) {
|
|
136
|
+
return { image, compressed: false, originalBytes, finalBytes: originalBytes };
|
|
137
|
+
}
|
|
138
|
+
const finalBytes = bestBuf.byteLength;
|
|
139
|
+
const out = {
|
|
140
|
+
...image,
|
|
141
|
+
base64: bestBuf.toString("base64"),
|
|
142
|
+
mime: "image/jpeg",
|
|
143
|
+
};
|
|
144
|
+
return {
|
|
145
|
+
image: out,
|
|
146
|
+
compressed: true,
|
|
147
|
+
originalBytes,
|
|
148
|
+
finalBytes,
|
|
149
|
+
};
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
cachedJimpCompressor = NOOP_COMPRESSOR;
|
|
155
|
+
}
|
|
156
|
+
return cachedJimpCompressor;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Try compressing every image in the batch so it fits under the
|
|
160
|
+
* single-image cap. Returns the (possibly transformed) batch plus a
|
|
161
|
+
* summary of what changed. Callers should hand the returned images
|
|
162
|
+
* back into {@link enforceImagePolicy} to confirm; this function
|
|
163
|
+
* doesn't itself decide whether the result is acceptable.
|
|
164
|
+
*/
|
|
165
|
+
export async function tryCompressImages(images) {
|
|
166
|
+
if (images.length === 0)
|
|
167
|
+
return { images: [], anyCompressed: false };
|
|
168
|
+
const compressor = activeCompressor ?? (await resolveJimpCompressor());
|
|
169
|
+
if (compressor === NOOP_COMPRESSOR) {
|
|
170
|
+
return { images: images.slice(), anyCompressed: false };
|
|
171
|
+
}
|
|
172
|
+
const out = [];
|
|
173
|
+
let anyCompressed = false;
|
|
174
|
+
for (const img of images) {
|
|
175
|
+
const bytes = byteLengthFromBase64(img.base64);
|
|
176
|
+
if (bytes <= IMAGE_LIMITS.maxBytesPerImage) {
|
|
177
|
+
out.push(img);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const result = await compressor.compress(img, IMAGE_LIMITS.maxBytesPerImage);
|
|
181
|
+
out.push(result.image);
|
|
182
|
+
if (result.compressed)
|
|
183
|
+
anyCompressed = true;
|
|
184
|
+
}
|
|
185
|
+
return { images: out, anyCompressed };
|
|
186
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-side image policy: a single source of truth for what counts as
|
|
3
|
+
* an "OK to ship to the model" attachment.
|
|
4
|
+
*
|
|
5
|
+
* Why this exists
|
|
6
|
+
* ---------------
|
|
7
|
+
* The desktop renderer happily takes a 4 MB screenshot, base64-encodes it,
|
|
8
|
+
* and ships it to the LLM. OpenAI-compatible providers stream the request
|
|
9
|
+
* body; a payload that fat plus a flaky link manifests as
|
|
10
|
+
* `OpenAI API error: Connection error.` with no useful classification,
|
|
11
|
+
* three retries deep. That bug is in our session log
|
|
12
|
+
* `s-mppk3ot5-02d35ca4`: textLen=4,364,933, promptTokens=1,091,232.
|
|
13
|
+
*
|
|
14
|
+
* The right fix is to keep the bytes small *before* they leave the host.
|
|
15
|
+
* But not every entry point has the same compressor available:
|
|
16
|
+
* - desktop renderer has <canvas> + Blob, no native deps
|
|
17
|
+
* - TUI runs in plain Node and has neither
|
|
18
|
+
* - MCP tools / future arena agents will need it too
|
|
19
|
+
*
|
|
20
|
+
* So this module owns:
|
|
21
|
+
* 1. The shared *thresholds* every host honors before sending to the LLM
|
|
22
|
+
* (`IMAGE_LIMITS`).
|
|
23
|
+
* 2. A `byteLengthFromBase64()` helper everyone uses to measure decoded
|
|
24
|
+
* payload size without actually decoding it.
|
|
25
|
+
* 3. An `enforceImagePolicy()` engine gate that runs *after* parse-task
|
|
26
|
+
* and *before* the message hits the provider. When a single image
|
|
27
|
+
* blows the limit, the gate refuses the turn with a friendly error
|
|
28
|
+
* and a hint telling the user what to do. The engine is the last
|
|
29
|
+
* place we can refuse cheaply — the next step is a $0.10 vision call
|
|
30
|
+
* over a flaky socket.
|
|
31
|
+
*
|
|
32
|
+
* Hosts (desktop, TUI) are encouraged to compress upstream so this gate
|
|
33
|
+
* never fires in practice. When it does fire, the user gets a clear
|
|
34
|
+
* message instead of "Connection error. Connection error. Connection
|
|
35
|
+
* error.".
|
|
36
|
+
*
|
|
37
|
+
* Pure + no I/O — safe to use from any caller.
|
|
38
|
+
*/
|
|
39
|
+
import type { ParsedImage } from "./parse-task.js";
|
|
40
|
+
/**
|
|
41
|
+
* Hard limits the engine enforces. Soft hints (target sizes) live in
|
|
42
|
+
* `IMAGE_TARGETS` so hosts know what to aim for when they pre-compress.
|
|
43
|
+
*
|
|
44
|
+
* Rationale for each number:
|
|
45
|
+
* - `maxBytesPerImage`: 2 MB decoded. OpenAI's `gpt-4o` accepts up to
|
|
46
|
+
* 20 MB but charges by tile count; 2 MB ≈ a 2048×2048 PNG which is
|
|
47
|
+
* plenty for every UI screenshot. Above this we've measured the
|
|
48
|
+
* "Connection error" failure mode in practice.
|
|
49
|
+
* - `maxBytesPerTurn`: 6 MB total, regardless of count. The four-image
|
|
50
|
+
* attach is the typical worst case from the desktop UI, and 4× the
|
|
51
|
+
* per-image cap would blow past most providers' rate-limited request
|
|
52
|
+
* body sizes.
|
|
53
|
+
* - `maxImagesPerTurn`: 6 (matches the desktop renderer's UI limit, so
|
|
54
|
+
* a wider engine gate is just dead defense).
|
|
55
|
+
*/
|
|
56
|
+
export declare const IMAGE_LIMITS: {
|
|
57
|
+
readonly maxBytesPerImage: number;
|
|
58
|
+
readonly maxBytesPerTurn: number;
|
|
59
|
+
readonly maxImagesPerTurn: 6;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Soft targets hosts use when pre-compressing. `targetMaxDimension` is
|
|
63
|
+
* the longest-edge pixel cap that *almost always* keeps a JPEG under
|
|
64
|
+
* `maxBytesPerImage`. Hosts re-encode at `jpegQuality` and only escalate
|
|
65
|
+
* the compression if the result is still over.
|
|
66
|
+
*/
|
|
67
|
+
export declare const IMAGE_TARGETS: {
|
|
68
|
+
readonly targetMaxDimension: 2048;
|
|
69
|
+
readonly jpegQuality: 0.82;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Decode-free size estimate of a base64 string.
|
|
73
|
+
*
|
|
74
|
+
* Returns the count of bytes the base64 string would produce *after*
|
|
75
|
+
* decoding. Used everywhere we need to "weigh" an image without paying
|
|
76
|
+
* the cost of `Buffer.from(s, "base64")` allocation.
|
|
77
|
+
*
|
|
78
|
+
* - 4 base64 chars → 3 decoded bytes.
|
|
79
|
+
* - Trailing `=` padding subtracts from the byte count.
|
|
80
|
+
* - Tolerates whitespace and missing padding by working off `length`
|
|
81
|
+
* modulo 4 — the wire format strips whitespace via parse-task, so
|
|
82
|
+
* this only matters when an exotic caller hands us raw textarea text.
|
|
83
|
+
*/
|
|
84
|
+
export declare function byteLengthFromBase64(b64: string): number;
|
|
85
|
+
/**
|
|
86
|
+
* Verdict returned by {@link enforceImagePolicy}. `ok: true` means the
|
|
87
|
+
* caller can proceed with the original images unchanged. `ok: false`
|
|
88
|
+
* carries a user-facing message + machine-readable reason so callers can
|
|
89
|
+
* decide whether to render an error card or refuse the turn outright.
|
|
90
|
+
*/
|
|
91
|
+
export type ImagePolicyVerdict = {
|
|
92
|
+
ok: true;
|
|
93
|
+
} | {
|
|
94
|
+
ok: false;
|
|
95
|
+
/**
|
|
96
|
+
* Stable string the engine surfaces as the run's terminal reason.
|
|
97
|
+
* Distinct values so a future UI could pick different icons.
|
|
98
|
+
*/
|
|
99
|
+
code: "image_too_large" | "images_total_too_large" | "too_many_images";
|
|
100
|
+
/** User-facing message — Chinese-friendly because both UIs are zh. */
|
|
101
|
+
message: string;
|
|
102
|
+
/** Optional fields the UI may use for finer-grained reporting. */
|
|
103
|
+
offender?: {
|
|
104
|
+
name: string;
|
|
105
|
+
mime: string;
|
|
106
|
+
bytes: number;
|
|
107
|
+
};
|
|
108
|
+
totals: {
|
|
109
|
+
imageCount: number;
|
|
110
|
+
totalBytes: number;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Run the per-turn image policy.
|
|
115
|
+
*
|
|
116
|
+
* Three failure modes, all surfaced with a Chinese-language hint that
|
|
117
|
+
* tells the user *what to do next*:
|
|
118
|
+
*
|
|
119
|
+
* 1. Per-image cap exceeded → name the file + the cap, suggest
|
|
120
|
+
* re-saving / cropping. (`code: "image_too_large"`)
|
|
121
|
+
* 2. Per-turn cumulative cap exceeded → total bytes + cap. The user
|
|
122
|
+
* likely attached too many screenshots; suggest removing some.
|
|
123
|
+
* (`code: "images_total_too_large"`)
|
|
124
|
+
* 3. Count cap exceeded → the desktop UI already caps at 6, so this
|
|
125
|
+
* mostly catches future-MCP / TUI batch paths. (`code: "too_many_images"`)
|
|
126
|
+
*
|
|
127
|
+
* The gate is **strict** — no silent truncation. The "Connection error"
|
|
128
|
+
* failure mode this exists to prevent was effectively a silent truncate
|
|
129
|
+
* (bytes lost mid-stream); a friendly refusal is strictly better.
|
|
130
|
+
*/
|
|
131
|
+
/**
|
|
132
|
+
* Drop the images that exceed {@link IMAGE_LIMITS.maxBytesPerImage}
|
|
133
|
+
* and return a textual placeholder describing what was removed. The
|
|
134
|
+
* engine uses this to keep a poisoned image out of conversation
|
|
135
|
+
* history while still letting the rest of the turn proceed — Claude
|
|
136
|
+
* Code's "5MB brick session" failure mode is exactly the bug where
|
|
137
|
+
* a too-large image enters history and every subsequent request
|
|
138
|
+
* re-sends it (see docs/research-cc-vs-codex-image-handling.md §A).
|
|
139
|
+
*
|
|
140
|
+
* Returns the filtered image list and, when anything was dropped, a
|
|
141
|
+
* Chinese-language note suitable for prepending to the user text.
|
|
142
|
+
*/
|
|
143
|
+
export interface DropOversizedResult {
|
|
144
|
+
/** Images that fit under the per-image cap (in original order). */
|
|
145
|
+
kept: ParsedImage[];
|
|
146
|
+
/** A human-readable note about what was removed, or "" if nothing was. */
|
|
147
|
+
placeholder: string;
|
|
148
|
+
/** Number of images removed. */
|
|
149
|
+
droppedCount: number;
|
|
150
|
+
}
|
|
151
|
+
export declare function dropOversizedImages(images: readonly ParsedImage[]): DropOversizedResult;
|
|
152
|
+
export declare function enforceImagePolicy(images: readonly ParsedImage[]): ImagePolicyVerdict;
|
|
153
|
+
/**
|
|
154
|
+
* Collect the workspace file paths of any attached images that came from a
|
|
155
|
+
* real file (the desktop composer's path-attach flow sets ParsedImage.name to
|
|
156
|
+
* the absolute path). Pasted screenshots whose name is a bare filename, or any
|
|
157
|
+
* name that doesn't resolve to an existing file, are excluded.
|
|
158
|
+
*
|
|
159
|
+
* Pure given an `exists` predicate + `resolve` joiner, so it's unit-testable
|
|
160
|
+
* without touching the real fs. The engine passes `existsSync` and a
|
|
161
|
+
* cwd-aware joiner; downstream this surfaces the paths to the model so tools
|
|
162
|
+
* like GenerateImage(referenceImages) can use them (the path the composer
|
|
163
|
+
* already knew was otherwise dropped on the way to the LLM).
|
|
164
|
+
*/
|
|
165
|
+
export declare function collectAttachedImagePaths(images: ReadonlyArray<ParsedImage>, resolve: (name: string) => string, exists: (absPath: string) => boolean): string[];
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-side image policy: a single source of truth for what counts as
|
|
3
|
+
* an "OK to ship to the model" attachment.
|
|
4
|
+
*
|
|
5
|
+
* Why this exists
|
|
6
|
+
* ---------------
|
|
7
|
+
* The desktop renderer happily takes a 4 MB screenshot, base64-encodes it,
|
|
8
|
+
* and ships it to the LLM. OpenAI-compatible providers stream the request
|
|
9
|
+
* body; a payload that fat plus a flaky link manifests as
|
|
10
|
+
* `OpenAI API error: Connection error.` with no useful classification,
|
|
11
|
+
* three retries deep. That bug is in our session log
|
|
12
|
+
* `s-mppk3ot5-02d35ca4`: textLen=4,364,933, promptTokens=1,091,232.
|
|
13
|
+
*
|
|
14
|
+
* The right fix is to keep the bytes small *before* they leave the host.
|
|
15
|
+
* But not every entry point has the same compressor available:
|
|
16
|
+
* - desktop renderer has <canvas> + Blob, no native deps
|
|
17
|
+
* - TUI runs in plain Node and has neither
|
|
18
|
+
* - MCP tools / future arena agents will need it too
|
|
19
|
+
*
|
|
20
|
+
* So this module owns:
|
|
21
|
+
* 1. The shared *thresholds* every host honors before sending to the LLM
|
|
22
|
+
* (`IMAGE_LIMITS`).
|
|
23
|
+
* 2. A `byteLengthFromBase64()` helper everyone uses to measure decoded
|
|
24
|
+
* payload size without actually decoding it.
|
|
25
|
+
* 3. An `enforceImagePolicy()` engine gate that runs *after* parse-task
|
|
26
|
+
* and *before* the message hits the provider. When a single image
|
|
27
|
+
* blows the limit, the gate refuses the turn with a friendly error
|
|
28
|
+
* and a hint telling the user what to do. The engine is the last
|
|
29
|
+
* place we can refuse cheaply — the next step is a $0.10 vision call
|
|
30
|
+
* over a flaky socket.
|
|
31
|
+
*
|
|
32
|
+
* Hosts (desktop, TUI) are encouraged to compress upstream so this gate
|
|
33
|
+
* never fires in practice. When it does fire, the user gets a clear
|
|
34
|
+
* message instead of "Connection error. Connection error. Connection
|
|
35
|
+
* error.".
|
|
36
|
+
*
|
|
37
|
+
* Pure + no I/O — safe to use from any caller.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Hard limits the engine enforces. Soft hints (target sizes) live in
|
|
41
|
+
* `IMAGE_TARGETS` so hosts know what to aim for when they pre-compress.
|
|
42
|
+
*
|
|
43
|
+
* Rationale for each number:
|
|
44
|
+
* - `maxBytesPerImage`: 2 MB decoded. OpenAI's `gpt-4o` accepts up to
|
|
45
|
+
* 20 MB but charges by tile count; 2 MB ≈ a 2048×2048 PNG which is
|
|
46
|
+
* plenty for every UI screenshot. Above this we've measured the
|
|
47
|
+
* "Connection error" failure mode in practice.
|
|
48
|
+
* - `maxBytesPerTurn`: 6 MB total, regardless of count. The four-image
|
|
49
|
+
* attach is the typical worst case from the desktop UI, and 4× the
|
|
50
|
+
* per-image cap would blow past most providers' rate-limited request
|
|
51
|
+
* body sizes.
|
|
52
|
+
* - `maxImagesPerTurn`: 6 (matches the desktop renderer's UI limit, so
|
|
53
|
+
* a wider engine gate is just dead defense).
|
|
54
|
+
*/
|
|
55
|
+
export const IMAGE_LIMITS = {
|
|
56
|
+
maxBytesPerImage: 2 * 1024 * 1024,
|
|
57
|
+
maxBytesPerTurn: 6 * 1024 * 1024,
|
|
58
|
+
maxImagesPerTurn: 6,
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Soft targets hosts use when pre-compressing. `targetMaxDimension` is
|
|
62
|
+
* the longest-edge pixel cap that *almost always* keeps a JPEG under
|
|
63
|
+
* `maxBytesPerImage`. Hosts re-encode at `jpegQuality` and only escalate
|
|
64
|
+
* the compression if the result is still over.
|
|
65
|
+
*/
|
|
66
|
+
export const IMAGE_TARGETS = {
|
|
67
|
+
targetMaxDimension: 2048,
|
|
68
|
+
jpegQuality: 0.82,
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Decode-free size estimate of a base64 string.
|
|
72
|
+
*
|
|
73
|
+
* Returns the count of bytes the base64 string would produce *after*
|
|
74
|
+
* decoding. Used everywhere we need to "weigh" an image without paying
|
|
75
|
+
* the cost of `Buffer.from(s, "base64")` allocation.
|
|
76
|
+
*
|
|
77
|
+
* - 4 base64 chars → 3 decoded bytes.
|
|
78
|
+
* - Trailing `=` padding subtracts from the byte count.
|
|
79
|
+
* - Tolerates whitespace and missing padding by working off `length`
|
|
80
|
+
* modulo 4 — the wire format strips whitespace via parse-task, so
|
|
81
|
+
* this only matters when an exotic caller hands us raw textarea text.
|
|
82
|
+
*/
|
|
83
|
+
export function byteLengthFromBase64(b64) {
|
|
84
|
+
if (!b64)
|
|
85
|
+
return 0;
|
|
86
|
+
// Strip whitespace defensively; the parser already does this, but other
|
|
87
|
+
// callers (logging stubs, MCP image blocks) might not.
|
|
88
|
+
const clean = b64.replace(/\s+/g, "");
|
|
89
|
+
const padding = clean.endsWith("==") ? 2 : clean.endsWith("=") ? 1 : 0;
|
|
90
|
+
return Math.floor((clean.length * 3) / 4) - padding;
|
|
91
|
+
}
|
|
92
|
+
function fmtMB(bytes) {
|
|
93
|
+
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
94
|
+
}
|
|
95
|
+
export function dropOversizedImages(images) {
|
|
96
|
+
const kept = [];
|
|
97
|
+
const dropped = [];
|
|
98
|
+
for (const img of images) {
|
|
99
|
+
const bytes = byteLengthFromBase64(img.base64);
|
|
100
|
+
if (bytes > IMAGE_LIMITS.maxBytesPerImage) {
|
|
101
|
+
dropped.push({ name: img.name || "(未命名)", bytes });
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
kept.push(img);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (dropped.length === 0) {
|
|
108
|
+
return { kept, placeholder: "", droppedCount: 0 };
|
|
109
|
+
}
|
|
110
|
+
const list = dropped
|
|
111
|
+
.map((d) => `「${d.name}」(~${fmtMB(d.bytes)})`)
|
|
112
|
+
.join("、");
|
|
113
|
+
const placeholder = `[已自动跳过 ${dropped.length} 张超大图片:${list};` +
|
|
114
|
+
`单图上限 ${fmtMB(IMAGE_LIMITS.maxBytesPerImage)}。` +
|
|
115
|
+
`图片未进入对话历史,本轮其余内容继续。]`;
|
|
116
|
+
return { kept, placeholder, droppedCount: dropped.length };
|
|
117
|
+
}
|
|
118
|
+
export function enforceImagePolicy(images) {
|
|
119
|
+
if (images.length === 0)
|
|
120
|
+
return { ok: true };
|
|
121
|
+
if (images.length > IMAGE_LIMITS.maxImagesPerTurn) {
|
|
122
|
+
return {
|
|
123
|
+
ok: false,
|
|
124
|
+
code: "too_many_images",
|
|
125
|
+
message: `一次最多附 ${IMAGE_LIMITS.maxImagesPerTurn} 张图片,` +
|
|
126
|
+
`本次有 ${images.length} 张。请删掉一些再发。`,
|
|
127
|
+
totals: {
|
|
128
|
+
imageCount: images.length,
|
|
129
|
+
totalBytes: images.reduce((s, i) => s + byteLengthFromBase64(i.base64), 0),
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
let totalBytes = 0;
|
|
134
|
+
for (const img of images) {
|
|
135
|
+
const bytes = byteLengthFromBase64(img.base64);
|
|
136
|
+
if (bytes > IMAGE_LIMITS.maxBytesPerImage) {
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
code: "image_too_large",
|
|
140
|
+
message: `图片「${img.name || "(未命名)"}」解码后约 ${fmtMB(bytes)},` +
|
|
141
|
+
`超过单图上限 ${fmtMB(IMAGE_LIMITS.maxBytesPerImage)}。` +
|
|
142
|
+
`请先截图压缩或保存为 JPEG(最长边 ≤ ${IMAGE_TARGETS.targetMaxDimension}px)再发。`,
|
|
143
|
+
offender: { name: img.name, mime: img.mime, bytes },
|
|
144
|
+
totals: {
|
|
145
|
+
imageCount: images.length,
|
|
146
|
+
totalBytes: totalBytes + bytes,
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
totalBytes += bytes;
|
|
151
|
+
}
|
|
152
|
+
if (totalBytes > IMAGE_LIMITS.maxBytesPerTurn) {
|
|
153
|
+
return {
|
|
154
|
+
ok: false,
|
|
155
|
+
code: "images_total_too_large",
|
|
156
|
+
message: `本次附图合计约 ${fmtMB(totalBytes)},超过每轮上限 ${fmtMB(IMAGE_LIMITS.maxBytesPerTurn)}。` +
|
|
157
|
+
`请删掉一些图片,或先把图片压缩后再发。`,
|
|
158
|
+
totals: {
|
|
159
|
+
imageCount: images.length,
|
|
160
|
+
totalBytes,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return { ok: true };
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Collect the workspace file paths of any attached images that came from a
|
|
168
|
+
* real file (the desktop composer's path-attach flow sets ParsedImage.name to
|
|
169
|
+
* the absolute path). Pasted screenshots whose name is a bare filename, or any
|
|
170
|
+
* name that doesn't resolve to an existing file, are excluded.
|
|
171
|
+
*
|
|
172
|
+
* Pure given an `exists` predicate + `resolve` joiner, so it's unit-testable
|
|
173
|
+
* without touching the real fs. The engine passes `existsSync` and a
|
|
174
|
+
* cwd-aware joiner; downstream this surfaces the paths to the model so tools
|
|
175
|
+
* like GenerateImage(referenceImages) can use them (the path the composer
|
|
176
|
+
* already knew was otherwise dropped on the way to the LLM).
|
|
177
|
+
*/
|
|
178
|
+
export function collectAttachedImagePaths(images, resolve, exists) {
|
|
179
|
+
const out = [];
|
|
180
|
+
for (const img of images) {
|
|
181
|
+
const name = img.name?.trim();
|
|
182
|
+
if (!name)
|
|
183
|
+
continue;
|
|
184
|
+
const abs = resolve(name);
|
|
185
|
+
if (exists(abs))
|
|
186
|
+
out.push(abs);
|
|
187
|
+
}
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge settings.modelConnections[] (the unified instance store) into
|
|
3
|
+
* ModelPool entries, so the engine sends requests using the new catalog-driven
|
|
4
|
+
* model selection. Pure: instances + catalog → ModelEntry[]. apiKeyRef is
|
|
5
|
+
* dereferenced via resolveInstance; protocol/baseUrl/token limits come from the
|
|
6
|
+
* resolved catalog entry + preset.
|
|
7
|
+
* See docs/superpowers/specs/2026-06-15-unified-model-catalog-design.md §6.
|
|
8
|
+
*/
|
|
9
|
+
import { type ModelInstance, type Credential } from "../model-catalog/resolve.js";
|
|
10
|
+
import type { CatalogEntry } from "../model-catalog/index.js";
|
|
11
|
+
import type { ModelEntry } from "../llm/model-pool.js";
|
|
12
|
+
export type { ModelInstance, Credential } from "../model-catalog/resolve.js";
|
|
13
|
+
/**
|
|
14
|
+
* Convert text model connections into ModelPool register entries. Non-text
|
|
15
|
+
* instances and ones whose catalogId doesn't resolve are skipped.
|
|
16
|
+
*/
|
|
17
|
+
export declare function modelEntriesFromConnections(connections: ModelInstance[], credentials: Credential[], catalog: CatalogEntry[]): ModelEntry[];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge settings.modelConnections[] (the unified instance store) into
|
|
3
|
+
* ModelPool entries, so the engine sends requests using the new catalog-driven
|
|
4
|
+
* model selection. Pure: instances + catalog → ModelEntry[]. apiKeyRef is
|
|
5
|
+
* dereferenced via resolveInstance; protocol/baseUrl/token limits come from the
|
|
6
|
+
* resolved catalog entry + preset.
|
|
7
|
+
* See docs/superpowers/specs/2026-06-15-unified-model-catalog-design.md §6.
|
|
8
|
+
*/
|
|
9
|
+
import { resolveInstance } from "../model-catalog/resolve.js";
|
|
10
|
+
import { applyParams } from "../model-catalog/params.js";
|
|
11
|
+
/** Map a catalog entry's protocol to the ModelPool `provider` (LLM client). */
|
|
12
|
+
function clientProvider(entry) {
|
|
13
|
+
return entry.protocol === "anthropic-style" ? "anthropic" : "openai";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Map a connection's `paramValues.reasoning` to the engine's ReasoningSetting,
|
|
17
|
+
* so the new param store flows through the existing reasoning request pipeline
|
|
18
|
+
* (no new request-layer plumbing). enum→effort, number→budget, boolean→on/off.
|
|
19
|
+
*/
|
|
20
|
+
function reasoningFromParamValues(paramValues) {
|
|
21
|
+
const v = paramValues?.reasoning;
|
|
22
|
+
if (typeof v === "string") {
|
|
23
|
+
return { mode: "effort", effort: v };
|
|
24
|
+
}
|
|
25
|
+
if (typeof v === "number")
|
|
26
|
+
return { mode: "budget", budgetTokens: v };
|
|
27
|
+
if (typeof v === "boolean")
|
|
28
|
+
return v ? { mode: "on" } : { mode: "off" };
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Convert text model connections into ModelPool register entries. Non-text
|
|
33
|
+
* instances and ones whose catalogId doesn't resolve are skipped.
|
|
34
|
+
*/
|
|
35
|
+
export function modelEntriesFromConnections(connections, credentials, catalog) {
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const inst of connections) {
|
|
38
|
+
if (inst.tag !== "text")
|
|
39
|
+
continue;
|
|
40
|
+
const resolved = resolveInstance(inst, credentials, catalog);
|
|
41
|
+
if (!resolved)
|
|
42
|
+
continue;
|
|
43
|
+
const { entry, preset } = resolved;
|
|
44
|
+
const reasoning = reasoningFromParamValues(inst.paramValues);
|
|
45
|
+
// Generic param passthrough: map the connection's paramValues to request-body
|
|
46
|
+
// fields via each ParamSpec's wire.field. Exclude `reasoning` — it rides the
|
|
47
|
+
// dedicated entry.reasoning path (per-model dynamic translation in the client);
|
|
48
|
+
// emitting it here too would double-send it.
|
|
49
|
+
const passthroughParams = (preset?.params ?? []).filter((p) => p.name !== "reasoning");
|
|
50
|
+
const extraBody = applyParams(inst.paramValues ?? {}, passthroughParams);
|
|
51
|
+
const e = {
|
|
52
|
+
key: inst.id,
|
|
53
|
+
provider: clientProvider(entry),
|
|
54
|
+
model: resolved.model,
|
|
55
|
+
baseUrl: resolved.baseUrl,
|
|
56
|
+
needsKey: resolved.needsKey,
|
|
57
|
+
...(resolved.apiKey !== undefined ? { apiKey: resolved.apiKey } : {}),
|
|
58
|
+
...(preset?.maxContextTokens !== undefined ? { maxContextTokens: preset.maxContextTokens } : {}),
|
|
59
|
+
...(preset?.maxOutputTokens !== undefined ? { maxOutputTokens: preset.maxOutputTokens } : {}),
|
|
60
|
+
...(reasoning !== undefined ? { reasoning } : {}),
|
|
61
|
+
...(Object.keys(extraBody).length > 0 ? { extraBody } : {}),
|
|
62
|
+
};
|
|
63
|
+
out.push(e);
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
import type { LLMClientBase } from "../llm/client-base.js";
|
|
5
5
|
import type { Message, ToolDefinition, LLMResponse, StreamCallback } from "../types.js";
|
|
6
6
|
import { Transcript } from "../session/transcript.js";
|
|
7
|
+
/**
|
|
8
|
+
* Prompt-cache hit rate for one request, as CC computes it:
|
|
9
|
+
* cacheRead / (cacheRead + cacheCreation + uncachedInput)
|
|
10
|
+
* where uncachedInput = promptTokens − cacheRead − cacheCreation (promptTokens
|
|
11
|
+
* already includes the cached portion). Returns undefined when the provider
|
|
12
|
+
* reported no cache info at all, so `llm.request` only carries the field when
|
|
13
|
+
* it's meaningful. Makes hit-rate observable in logs — the prerequisite for
|
|
14
|
+
* any caching tuning (docs/todo/prompt-cache-optimization.md §四 step 1).
|
|
15
|
+
*/
|
|
16
|
+
export declare function cacheHitRate(usage: LLMResponse["usage"]): number | undefined;
|
|
7
17
|
export declare class ModelFacade {
|
|
8
18
|
private readonly client;
|
|
9
19
|
private readonly transcript;
|