@cjhyy/code-shell-core 0.5.0-rc.2 → 0.6.0-rc.10
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 +3 -0
- package/dist/agent/agent-definition-registry.js +3 -1
- package/dist/agent/agent-definition.d.ts +15 -0
- package/dist/agent/agent-definition.js +27 -3
- package/dist/arena/context/context-tools.js +47 -4
- package/dist/arena/ledger.js +9 -1
- package/dist/arena/strategies/utils.d.ts +1 -4
- package/dist/arena/strategies/utils.js +7 -84
- package/dist/automation/cron-expr.d.ts +10 -0
- package/dist/automation/cron-expr.js +23 -5
- package/dist/automation/runner.d.ts +21 -4
- package/dist/automation/runner.js +48 -12
- package/dist/automation/scheduler.d.ts +38 -0
- package/dist/automation/scheduler.js +89 -12
- package/dist/automation/store.js +5 -2
- package/dist/capability-control/disabled-lists.d.ts +25 -0
- package/dist/capability-control/disabled-lists.js +57 -0
- package/dist/capability-control/overlay.d.ts +15 -0
- package/dist/capability-control/overlay.js +27 -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 +15 -1
- package/dist/cli/agent-server-stdio.js +115 -17
- package/dist/cli/agent-server-tcp.js +40 -26
- package/dist/context/compaction.d.ts +86 -0
- package/dist/context/compaction.js +279 -0
- package/dist/context/manager.d.ts +18 -0
- package/dist/context/manager.js +181 -48
- package/dist/context/token-counter.js +13 -0
- 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/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/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 +280 -141
- package/dist/engine/engine.js +1193 -245
- package/dist/engine/friendly-error.d.ts +18 -0
- package/dist/engine/friendly-error.js +63 -0
- package/dist/engine/goal.d.ts +145 -0
- package/dist/engine/goal.js +144 -0
- package/dist/engine/image-policy.d.ts +13 -0
- package/dist/engine/image-policy.js +24 -0
- package/dist/engine/model-connections-pool.d.ts +17 -0
- package/dist/engine/model-connections-pool.js +67 -0
- package/dist/engine/model-facade.d.ts +10 -0
- package/dist/engine/model-facade.js +15 -0
- package/dist/engine/patch-orphaned-tools.js +3 -0
- package/dist/engine/query.js +2 -0
- package/dist/engine/resolve-llm-config.d.ts +16 -0
- package/dist/engine/resolve-llm-config.js +44 -0
- package/dist/engine/runtime.d.ts +2 -0
- package/dist/engine/runtime.js +27 -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-usage.d.ts +31 -0
- package/dist/engine/session-usage.js +81 -0
- package/dist/engine/steer-queue.d.ts +33 -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 -4
- package/dist/engine/turn-loop.js +432 -54
- 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/utils.d.ts +12 -0
- package/dist/git/utils.js +38 -6
- package/dist/git/worktree.d.ts +48 -0
- package/dist/git/worktree.js +86 -10
- package/dist/hooks/goal-stop-hook.d.ts +28 -0
- package/dist/hooks/goal-stop-hook.js +186 -9
- package/dist/hooks/registry.d.ts +8 -0
- package/dist/hooks/registry.js +19 -0
- package/dist/hooks/shell-runner.js +10 -21
- package/dist/index.d.ts +51 -7
- package/dist/index.js +62 -5
- package/dist/llm/capabilities/param-specs.d.ts +14 -0
- package/dist/llm/capabilities/param-specs.js +62 -0
- package/dist/llm/capabilities/rules.js +5 -1
- package/dist/llm/capabilities/types.d.ts +10 -0
- package/dist/llm/client-base.d.ts +28 -1
- package/dist/llm/client-base.js +119 -13
- package/dist/llm/model-cache.js +4 -2
- package/dist/llm/model-pool.d.ts +21 -0
- package/dist/llm/model-pool.js +21 -1
- package/dist/llm/provider-auth.d.ts +41 -0
- package/dist/llm/provider-auth.js +76 -0
- package/dist/llm/provider-catalog.d.ts +4 -0
- package/dist/llm/providers/anthropic.js +64 -14
- package/dist/llm/providers/openai.d.ts +36 -0
- package/dist/llm/providers/openai.js +257 -51
- package/dist/llm/reasoning-setting.d.ts +3 -3
- package/dist/llm/reasoning-setting.js +9 -1
- package/dist/llm/stream-watchdog.js +5 -1
- package/dist/llm/token-counter.js +9 -2
- package/dist/llm/types.d.ts +4 -0
- package/dist/logging/sanitize-messages.js +22 -0
- package/dist/lsp/manager.d.ts +1 -1
- package/dist/lsp/manager.js +40 -10
- package/dist/model-catalog/builtin.d.ts +12 -0
- package/dist/model-catalog/builtin.js +412 -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 +61 -326
- package/dist/plugins/gitOps.d.ts +19 -0
- package/dist/plugins/gitOps.js +73 -4
- package/dist/plugins/installer/checkUpdate.d.ts +16 -0
- package/dist/plugins/installer/checkUpdate.js +32 -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 +5 -2
- package/dist/plugins/installer/codex/convertMcp.js +45 -5
- package/dist/plugins/installer/install.js +25 -1
- package/dist/plugins/installer/installFromArchive.d.ts +43 -0
- package/dist/plugins/installer/installFromArchive.js +134 -0
- package/dist/plugins/installer/installFromSource.js +8 -2
- package/dist/plugins/installer/loadPluginAgents.js +6 -2
- package/dist/plugins/installer/loadPluginMcp.d.ts +9 -2
- package/dist/plugins/installer/loadPluginMcp.js +35 -2
- package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
- package/dist/plugins/installer/pruneDisabled.js +73 -0
- package/dist/plugins/installer/types.d.ts +5 -2
- package/dist/plugins/installer/types.js +1 -0
- package/dist/plugins/installer/uninstall.js +4 -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 +14 -0
- package/dist/plugins/installer/update.js +53 -21
- package/dist/plugins/loadPluginHooks.d.ts +47 -1
- package/dist/plugins/loadPluginHooks.js +73 -1
- package/dist/plugins/marketplaceManager.d.ts +7 -0
- package/dist/plugins/marketplaceManager.js +20 -0
- package/dist/plugins/pluginCommandHook.js +4 -18
- package/dist/plugins/pluginContent.d.ts +30 -0
- package/dist/plugins/pluginContent.js +83 -0
- package/dist/plugins/pluginInstaller.d.ts +13 -0
- package/dist/plugins/pluginInstaller.js +42 -8
- package/dist/plugins/schemas.js +1 -0
- package/dist/plugins/types.d.ts +6 -0
- package/dist/preset/index.d.ts +11 -1
- package/dist/preset/index.js +115 -6
- package/dist/product/types.d.ts +1 -1
- package/dist/prompt/composer.d.ts +32 -0
- package/dist/prompt/composer.js +75 -21
- package/dist/prompt/instruction-scanner.js +5 -3
- package/dist/prompt/section-loader.js +1 -0
- package/dist/prompt/sections/base.md +2 -0
- package/dist/prompt/sections/browser.md +10 -0
- package/dist/prompt/sections/coding.md +4 -0
- package/dist/protocol/chat-session-manager.d.ts +9 -2
- package/dist/protocol/chat-session-manager.js +38 -0
- package/dist/protocol/chat-session.d.ts +69 -1
- package/dist/protocol/chat-session.js +102 -4
- package/dist/protocol/client.d.ts +31 -0
- package/dist/protocol/client.js +44 -0
- package/dist/protocol/server.d.ts +120 -7
- package/dist/protocol/server.js +753 -51
- package/dist/protocol/transport.js +3 -2
- package/dist/protocol/types.d.ts +60 -0
- package/dist/protocol/types.js +16 -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/review/review-prompt.d.ts +28 -0
- package/dist/review/review-prompt.js +81 -0
- package/dist/run/FileRunStore.js +8 -3
- package/dist/run/RunApprovalBackend.js +25 -5
- package/dist/run/RunManager.d.ts +12 -0
- package/dist/run/RunManager.js +35 -0
- package/dist/run/factory.d.ts +1 -1
- package/dist/runtime/background-shell.d.ts +139 -0
- package/dist/runtime/background-shell.js +509 -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 +98 -39
- package/dist/runtime/spawn-common.d.ts +159 -0
- package/dist/runtime/spawn-common.js +404 -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/diagnostics.d.ts +1 -2
- package/dist/services/diagnostics.js +12 -7
- 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 -50
- package/dist/services/session-memory.js +24 -12
- package/dist/session/file-history.d.ts +124 -1
- package/dist/session/file-history.js +222 -6
- package/dist/session/memory.d.ts +116 -2
- package/dist/session/memory.js +250 -28
- package/dist/session/session-manager.d.ts +40 -0
- package/dist/session/session-manager.js +119 -3
- package/dist/session/simple-diff.d.ts +23 -0
- package/dist/session/simple-diff.js +84 -0
- package/dist/session/transcript.d.ts +29 -1
- package/dist/session/transcript.js +56 -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 +9 -2
- package/dist/settings/disk-defaults.js +11 -2
- package/dist/settings/feature-flags.d.ts +64 -0
- package/dist/settings/feature-flags.js +61 -0
- package/dist/settings/manager.d.ts +68 -1
- package/dist/settings/manager.js +266 -29
- package/dist/settings/migrate-config.d.ts +45 -0
- package/dist/settings/migrate-config.js +125 -0
- package/dist/settings/schema-export.d.ts +25 -0
- package/dist/settings/schema-export.js +38 -0
- package/dist/settings/schema.d.ts +1186 -771
- package/dist/settings/schema.js +268 -97
- 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/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 +12 -0
- package/dist/tool-system/builtin/agent-registry.js +8 -0
- package/dist/tool-system/builtin/agent.d.ts +21 -1
- package/dist/tool-system/builtin/agent.js +489 -42
- 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 +0 -15
- 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 +101 -64
- 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/config.js +7 -0
- package/dist/tool-system/builtin/cron.d.ts +7 -0
- package/dist/tool-system/builtin/cron.js +64 -4
- 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 +104 -0
- package/dist/tool-system/builtin/edit.js +20 -16
- 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 +35 -0
- package/dist/tool-system/builtin/generate-image.js +278 -50
- package/dist/tool-system/builtin/generate-video.d.ts +55 -0
- package/dist/tool-system/builtin/generate-video.js +364 -0
- package/dist/tool-system/builtin/glob.js +0 -7
- package/dist/tool-system/builtin/grep.d.ts +9 -0
- package/dist/tool-system/builtin/grep.js +106 -11
- 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 +10 -2
- package/dist/tool-system/builtin/index.js +251 -27
- 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.js +0 -7
- package/dist/tool-system/builtin/powershell.js +8 -2
- package/dist/tool-system/builtin/read.js +10 -10
- 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 +8 -2
- package/dist/tool-system/builtin/tool-search.js +25 -7
- 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/web-fetch.js +12 -2
- package/dist/tool-system/builtin/web-search.js +21 -7
- 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.js +0 -6
- package/dist/tool-system/context.d.ts +164 -6
- package/dist/tool-system/executor.d.ts +3 -1
- package/dist/tool-system/executor.js +197 -90
- package/dist/tool-system/investigation-guard.js +1 -1
- package/dist/tool-system/mcp-manager.d.ts +42 -4
- package/dist/tool-system/mcp-manager.js +203 -20
- package/dist/tool-system/mcp-stdio-diagnostics.d.ts +9 -0
- package/dist/tool-system/mcp-stdio-diagnostics.js +93 -0
- package/dist/tool-system/path-policy.d.ts +5 -0
- package/dist/tool-system/path-policy.js +307 -8
- package/dist/tool-system/permission.d.ts +39 -2
- package/dist/tool-system/permission.js +283 -70
- package/dist/tool-system/plan-mode-allowlist.d.ts +13 -2
- package/dist/tool-system/plan-mode-allowlist.js +24 -2
- package/dist/tool-system/registry.d.ts +1 -0
- package/dist/tool-system/registry.js +16 -2
- package/dist/tool-system/sandbox/index.d.ts +8 -0
- package/dist/tool-system/sandbox/index.js +7 -2
- package/dist/tool-system/sandbox/off.js +7 -1
- package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
- package/dist/tool-system/validate-tool-metadata.js +63 -0
- package/dist/types.d.ts +252 -7
- 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 +48 -0
- package/dist/utils/exec.js +154 -0
- package/dist/utils/json.d.ts +12 -0
- package/dist/utils/json.js +92 -0
- package/dist/utils/theme.d.ts +1 -1
- package/dist/utils/theme.js +1 -1
- package/dist/utils/toolDisplay.js +0 -1
- package/package.json +13 -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
package/dist/context/manager.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Tier 2: LLM summary (async) — generate summary of older messages via model call
|
|
6
6
|
* Tier 3: window compact (sync, emergency) — aggressive truncation fallback
|
|
7
7
|
*/
|
|
8
|
-
import { estimateTokens, microcompact, snipCompact, windowCompact, truncateToolResult, buildSummarizationPrompt, applySummaryCompaction, applyToolResultBudget, extractAnchoredSummary, } from "./compaction.js";
|
|
8
|
+
import { estimateTokens, microcompact, dedupeFileReads, maskOldObservations, snipCompact, windowCompact, truncateToolResult, buildSummarizationPrompt, applySummaryCompaction, applyToolResultBudget, extractAnchoredSummary, } from "./compaction.js";
|
|
9
9
|
import { applyToolResultPersistence, createContentReplacementState, reconstructContentReplacementState, resolveToolResultsDir, } from "./tool-result-storage.js";
|
|
10
10
|
import { logger } from "../logging/logger.js";
|
|
11
11
|
const DEFAULT_CONFIG = {
|
|
@@ -41,6 +41,8 @@ export class ContextManager {
|
|
|
41
41
|
config;
|
|
42
42
|
summarizeFn;
|
|
43
43
|
consecutiveSummaryFailures = 0;
|
|
44
|
+
/** Prevents repeated spin-band LLM calls after a summary generated no shrink. */
|
|
45
|
+
suppressNoOpMicroSummaryUntilCompact = false;
|
|
44
46
|
lastSummary;
|
|
45
47
|
/** Last known actual token count from API usage data. */
|
|
46
48
|
lastActualTokens;
|
|
@@ -91,6 +93,64 @@ export class ContextManager {
|
|
|
91
93
|
setSummarizeFn(fn) {
|
|
92
94
|
this.summarizeFn = fn;
|
|
93
95
|
}
|
|
96
|
+
async trySummaryCompact(messages, before, logEvent) {
|
|
97
|
+
if (!this.summarizeFn || this.consecutiveSummaryFailures >= 3) {
|
|
98
|
+
return { messages, tokens: before, compacted: false, noProgress: false };
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const keepRecentN = Math.max(8, Math.floor(messages.length * 0.3));
|
|
102
|
+
const messagesToSummarize = messages.slice(1, -keepRecentN); // skip first (userContext) and recent
|
|
103
|
+
if (messagesToSummarize.length <= 3) {
|
|
104
|
+
return { messages, tokens: before, compacted: false, noProgress: false };
|
|
105
|
+
}
|
|
106
|
+
// Rolling summary: if a prior summary is already anchored in the
|
|
107
|
+
// messages (from an earlier compaction in this session or in a resumed
|
|
108
|
+
// session), feed it back so the LLM merges-updates rather than
|
|
109
|
+
// re-summarizes from scratch.
|
|
110
|
+
const priorSummary = extractAnchoredSummary(messages) ?? this.lastSummary;
|
|
111
|
+
const prompt = buildSummarizationPrompt(messagesToSummarize, priorSummary);
|
|
112
|
+
const summary = await this.summarizeFn(prompt);
|
|
113
|
+
if (!summary || summary.length <= 50) {
|
|
114
|
+
this.consecutiveSummaryFailures++;
|
|
115
|
+
logger.warn("context.summary_failed", {
|
|
116
|
+
failures: this.consecutiveSummaryFailures,
|
|
117
|
+
error: "summary was empty or too short",
|
|
118
|
+
});
|
|
119
|
+
return { messages, tokens: before, compacted: false, noProgress: true };
|
|
120
|
+
}
|
|
121
|
+
const compacted = applySummaryCompaction(messages, summary, keepRecentN, this.transcriptPath);
|
|
122
|
+
const after = estimateTokens(compacted);
|
|
123
|
+
if (after >= before) {
|
|
124
|
+
this.consecutiveSummaryFailures++;
|
|
125
|
+
logger.warn("context.summary_no_progress", {
|
|
126
|
+
failures: this.consecutiveSummaryFailures,
|
|
127
|
+
before,
|
|
128
|
+
after,
|
|
129
|
+
summaryLen: summary.length,
|
|
130
|
+
rolling: priorSummary !== undefined,
|
|
131
|
+
});
|
|
132
|
+
return { messages, tokens: before, compacted: false, noProgress: true };
|
|
133
|
+
}
|
|
134
|
+
this.consecutiveSummaryFailures = 0;
|
|
135
|
+
this.lastSummary = summary;
|
|
136
|
+
logger.info(logEvent, {
|
|
137
|
+
before,
|
|
138
|
+
after,
|
|
139
|
+
summaryLen: summary.length,
|
|
140
|
+
rolling: priorSummary !== undefined,
|
|
141
|
+
});
|
|
142
|
+
this.onCompact?.({ strategy: "summary", before, after });
|
|
143
|
+
return { messages: compacted, tokens: after, compacted: true, noProgress: false };
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
this.consecutiveSummaryFailures++;
|
|
147
|
+
logger.warn("context.summary_failed", {
|
|
148
|
+
failures: this.consecutiveSummaryFailures,
|
|
149
|
+
error: err.message,
|
|
150
|
+
});
|
|
151
|
+
return { messages, tokens: before, compacted: false, noProgress: false };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
94
154
|
/**
|
|
95
155
|
* Set the transcript path so compaction can reference it. The
|
|
96
156
|
* tool-results directory lives alongside the transcript file:
|
|
@@ -127,6 +187,25 @@ export class ContextManager {
|
|
|
127
187
|
// Tier 0c: Aggregate tool result budget (per-message) — char-level
|
|
128
188
|
// backstop for messages still over the limit after persistence.
|
|
129
189
|
result = applyToolResultBudget(result);
|
|
190
|
+
// Tier 0d: dedup repeated Reads of the same file — keep only the latest
|
|
191
|
+
// copy (older ones are stale). Always-on + zero-cost: it's pure waste
|
|
192
|
+
// removal (the model never needs two snapshots of one file), unlike the
|
|
193
|
+
// pressure-/recency-gated tiers below. Runs before microcompact so an
|
|
194
|
+
// already-deduped result isn't double-counted toward the keep-recent window.
|
|
195
|
+
const dedup = dedupeFileReads(result);
|
|
196
|
+
if (dedup.clearedCount > 0) {
|
|
197
|
+
result = dedup.messages;
|
|
198
|
+
logger.info("context.dedupe_file_reads", { cleared: dedup.clearedCount });
|
|
199
|
+
}
|
|
200
|
+
// Tier 0d': browser observation masking — keep only the latest
|
|
201
|
+
// browser_snapshot, collapse older ones (stale element lists, often large).
|
|
202
|
+
// Same always-on waste-removal class as dedupeFileReads. The research's
|
|
203
|
+
// top browser-token lever (folding old observations beats LLM summarizing).
|
|
204
|
+
const masked = maskOldObservations(result);
|
|
205
|
+
if (masked.maskedCount > 0) {
|
|
206
|
+
result = masked.messages;
|
|
207
|
+
logger.info("context.mask_browser_snapshots", { masked: masked.maskedCount });
|
|
208
|
+
}
|
|
130
209
|
// Tier 1: microcompact — fingerprint old whitelisted tool_results.
|
|
131
210
|
// Only runs above the floor ratio: under-pressure context keeps full
|
|
132
211
|
// detail so the model isn't forced to re-Read files it just looked at.
|
|
@@ -221,7 +300,9 @@ export class ContextManager {
|
|
|
221
300
|
result = applyToolResultBudget(result);
|
|
222
301
|
// Tier 1: microcompact — see manage() for the rationale on the floor.
|
|
223
302
|
const preTier1Tokens = this.estimateTokensHybrid(result);
|
|
224
|
-
|
|
303
|
+
const microFloorGate = this.config.maxTokens * this.config.microcompactFloorRatio;
|
|
304
|
+
let microNoOpAtFloor = false;
|
|
305
|
+
if (preTier1Tokens > microFloorGate) {
|
|
225
306
|
const keepRecentN = this.config.microcompactKeepRecent ?? defaultKeepRecent(this.config.maxTokens);
|
|
226
307
|
// See manage(): onClear fires synchronously before microcompact returns,
|
|
227
308
|
// so defer the token re-estimate until result is reassigned.
|
|
@@ -232,63 +313,58 @@ export class ContextManager {
|
|
|
232
313
|
clearedInfo = info;
|
|
233
314
|
},
|
|
234
315
|
});
|
|
316
|
+
const postTier1Tokens = this.estimateTokensHybrid(result);
|
|
317
|
+
microNoOpAtFloor = postTier1Tokens === preTier1Tokens;
|
|
318
|
+
if (postTier1Tokens < preTier1Tokens) {
|
|
319
|
+
this.suppressNoOpMicroSummaryUntilCompact = false;
|
|
320
|
+
}
|
|
235
321
|
if (clearedInfo) {
|
|
236
|
-
const after = this.estimateTokensHybrid(result);
|
|
237
322
|
logger.info("context.microcompact", {
|
|
238
323
|
before: preTier1Tokens,
|
|
239
|
-
after,
|
|
324
|
+
after: postTier1Tokens,
|
|
240
325
|
keepRecentN,
|
|
241
326
|
clearedRounds: clearedInfo.clearedRounds,
|
|
242
327
|
toolNames: clearedInfo.toolNames,
|
|
243
328
|
});
|
|
244
|
-
this.onCompact?.({
|
|
329
|
+
this.onCompact?.({
|
|
330
|
+
strategy: "micro",
|
|
331
|
+
before: preTier1Tokens,
|
|
332
|
+
after: postTier1Tokens,
|
|
333
|
+
});
|
|
245
334
|
}
|
|
246
335
|
}
|
|
247
|
-
|
|
336
|
+
let tokens = this.estimateTokensHybrid(result);
|
|
248
337
|
const ratio = tokens / this.config.maxTokens;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (summary && summary.length > 50) {
|
|
266
|
-
result = applySummaryCompaction(result, summary, keepRecentN, this.transcriptPath);
|
|
267
|
-
this.consecutiveSummaryFailures = 0;
|
|
268
|
-
this.lastSummary = summary;
|
|
269
|
-
const after = estimateTokens(result);
|
|
270
|
-
logger.info("context.summary_compact", {
|
|
271
|
-
before: tokens,
|
|
272
|
-
after,
|
|
273
|
-
summaryLen: summary.length,
|
|
274
|
-
rolling: priorSummary !== undefined,
|
|
275
|
-
});
|
|
276
|
-
this.onCompact?.({ strategy: "summary", before: tokens, after });
|
|
277
|
-
return result;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
338
|
+
if (ratio < this.config.microcompactFloorRatio) {
|
|
339
|
+
this.suppressNoOpMicroSummaryUntilCompact = false;
|
|
340
|
+
}
|
|
341
|
+
const noOpMicroSpinBand = microNoOpAtFloor &&
|
|
342
|
+
ratio >= this.config.microcompactFloorRatio &&
|
|
343
|
+
ratio < this.config.compactAtRatio;
|
|
344
|
+
const shouldEscalateNoOpMicro = noOpMicroSpinBand && !this.suppressNoOpMicroSummaryUntilCompact;
|
|
345
|
+
// Tier 2: LLM summary if approaching limit, or if micro was the only tier
|
|
346
|
+
// available in the 0.70-0.85 band and it freed nothing.
|
|
347
|
+
if (ratio >= this.config.compactAtRatio || shouldEscalateNoOpMicro) {
|
|
348
|
+
const summarized = await this.trySummaryCompact(result, tokens, "context.summary_compact");
|
|
349
|
+
result = summarized.messages;
|
|
350
|
+
tokens = summarized.tokens;
|
|
351
|
+
if (summarized.compacted) {
|
|
352
|
+
this.suppressNoOpMicroSummaryUntilCompact = false;
|
|
353
|
+
return result;
|
|
280
354
|
}
|
|
281
|
-
|
|
282
|
-
this.
|
|
283
|
-
logger.
|
|
284
|
-
|
|
285
|
-
|
|
355
|
+
if (shouldEscalateNoOpMicro && summarized.noProgress) {
|
|
356
|
+
this.suppressNoOpMicroSummaryUntilCompact = true;
|
|
357
|
+
logger.info("context.micro_noop_summary_suppressed", {
|
|
358
|
+
tokens,
|
|
359
|
+
ratio,
|
|
360
|
+
compactAtRatio: this.config.compactAtRatio,
|
|
361
|
+
microcompactFloorRatio: this.config.microcompactFloorRatio,
|
|
286
362
|
});
|
|
287
363
|
}
|
|
288
364
|
}
|
|
289
|
-
// Reuse the `tokens` we already computed above. We only get here if
|
|
290
|
-
//
|
|
291
|
-
//
|
|
365
|
+
// Reuse the `tokens` we already computed above. We only get here if no
|
|
366
|
+
// summary compacted the prompt (no summarizeFn, too many failures, a
|
|
367
|
+
// thrown error, or a generated summary that did not shrink anything).
|
|
292
368
|
let live = tokens;
|
|
293
369
|
const snipGate = this.config.maxTokens * this.config.compactAtRatio;
|
|
294
370
|
const windowGate = this.config.maxTokens * (this.config.compactAtRatio + 0.05);
|
|
@@ -317,6 +393,61 @@ export class ContextManager {
|
|
|
317
393
|
}
|
|
318
394
|
return result;
|
|
319
395
|
}
|
|
396
|
+
/**
|
|
397
|
+
* Force maximum compaction, ignoring the ratio gates. This is what a manual
|
|
398
|
+
* `/compact` invokes: the user explicitly asked to shrink NOW, so we don't
|
|
399
|
+
* wait for the prompt to reach compactAtRatio.
|
|
400
|
+
*
|
|
401
|
+
* Order: tier-0 cleanups (persist/truncate/dedupe/mask) + microcompact, then
|
|
402
|
+
* an unconditional LLM summary of the older messages. If no summarizeFn is
|
|
403
|
+
* wired (or it fails / yields nothing), fall back to snip → window so the
|
|
404
|
+
* call still shrinks the conversation rather than no-opping.
|
|
405
|
+
*
|
|
406
|
+
* Unlike manage()/manageAsync(), there is NO `ratio >= compactAtRatio` gate:
|
|
407
|
+
* a long-but-under-threshold text-only conversation (the /compact bug) still
|
|
408
|
+
* gets summarized here.
|
|
409
|
+
*/
|
|
410
|
+
async forceSummarize(messages) {
|
|
411
|
+
let result = messages;
|
|
412
|
+
// Tier 0: same waste-removal + micro as the automatic path.
|
|
413
|
+
result = this.persistLargeToolResults(result);
|
|
414
|
+
result = this.truncateToolResults(result);
|
|
415
|
+
result = applyToolResultBudget(result);
|
|
416
|
+
const dedup = dedupeFileReads(result);
|
|
417
|
+
if (dedup.clearedCount > 0)
|
|
418
|
+
result = dedup.messages;
|
|
419
|
+
const masked = maskOldObservations(result);
|
|
420
|
+
if (masked.maskedCount > 0)
|
|
421
|
+
result = masked.messages;
|
|
422
|
+
const keepRecentN = this.config.microcompactKeepRecent ?? defaultKeepRecent(this.config.maxTokens);
|
|
423
|
+
result = microcompact(result, { keepRecentN });
|
|
424
|
+
let tokens = this.estimateTokensHybrid(result);
|
|
425
|
+
// Unconditional LLM summary (no ratio gate).
|
|
426
|
+
{
|
|
427
|
+
const summarized = await this.trySummaryCompact(result, tokens, "context.force_summary_compact");
|
|
428
|
+
result = summarized.messages;
|
|
429
|
+
tokens = summarized.tokens;
|
|
430
|
+
if (summarized.compacted)
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
// Fallback: no summary available — snip, then window, so /compact still
|
|
434
|
+
// shrinks the conversation instead of no-opping.
|
|
435
|
+
{
|
|
436
|
+
const before = tokens;
|
|
437
|
+
result = snipCompact(result, 3, 8);
|
|
438
|
+
tokens = this.estimateTokensHybrid(result);
|
|
439
|
+
if (tokens < before)
|
|
440
|
+
this.onCompact?.({ strategy: "snip", before, after: tokens });
|
|
441
|
+
}
|
|
442
|
+
if (this.estimateTokensHybrid(result) >= this.estimateTokensHybrid(messages)) {
|
|
443
|
+
const before = tokens;
|
|
444
|
+
const keepN = Math.max(10, Math.floor(result.length * 0.4));
|
|
445
|
+
result = windowCompact(result, keepN);
|
|
446
|
+
tokens = this.estimateTokensHybrid(result);
|
|
447
|
+
this.onCompact?.({ strategy: "window", before, after: tokens });
|
|
448
|
+
}
|
|
449
|
+
return result;
|
|
450
|
+
}
|
|
320
451
|
/**
|
|
321
452
|
* Persist large tool_result blocks to disk and replace them with a
|
|
322
453
|
* preview + filepath. No-op when transcript path hasn't been set
|
|
@@ -341,20 +472,22 @@ export class ContextManager {
|
|
|
341
472
|
*/
|
|
342
473
|
truncateToolResults(messages) {
|
|
343
474
|
const maxChars = this.config.maxToolResultChars;
|
|
344
|
-
let modified = false;
|
|
345
475
|
const result = messages.map((msg) => {
|
|
346
476
|
if (!Array.isArray(msg.content))
|
|
347
477
|
return msg;
|
|
478
|
+
// Per-message flag: a truncation in an earlier message must not force
|
|
479
|
+
// later, unchanged messages to be spread-copied.
|
|
480
|
+
let messageModified = false;
|
|
348
481
|
const newContent = msg.content.map((block) => {
|
|
349
482
|
if (block.type === "tool_result" && typeof block.content === "string") {
|
|
350
483
|
if (block.content.length > maxChars) {
|
|
351
|
-
|
|
484
|
+
messageModified = true;
|
|
352
485
|
return { ...block, content: truncateToolResult(block.content, maxChars) };
|
|
353
486
|
}
|
|
354
487
|
}
|
|
355
488
|
return block;
|
|
356
489
|
});
|
|
357
|
-
return
|
|
490
|
+
return messageModified ? { ...msg, content: newContent } : msg;
|
|
358
491
|
});
|
|
359
492
|
return result;
|
|
360
493
|
}
|
|
@@ -69,11 +69,24 @@ function estimateBlockTokens(block) {
|
|
|
69
69
|
if (block.content && typeof block.content === "string") {
|
|
70
70
|
tokens += estimateStringTokens(block.content);
|
|
71
71
|
}
|
|
72
|
+
else if (Array.isArray(block.content)) {
|
|
73
|
+
for (const nested of block.content) {
|
|
74
|
+
tokens += estimateBlockTokens(nested);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
72
77
|
if (block.input) {
|
|
73
78
|
tokens += estimateStringTokens(JSON.stringify(block.input));
|
|
74
79
|
}
|
|
75
80
|
if (block.name)
|
|
76
81
|
tokens += estimateStringTokens(block.name);
|
|
82
|
+
if (block.source?.data) {
|
|
83
|
+
tokens += estimateStringTokens(block.source.media_type);
|
|
84
|
+
tokens += estimateStringTokens(block.source.data);
|
|
85
|
+
}
|
|
86
|
+
const maybeOpenAI = block;
|
|
87
|
+
if (typeof maybeOpenAI.image_url?.url === "string") {
|
|
88
|
+
tokens += estimateStringTokens(maybeOpenAI.image_url.url);
|
|
89
|
+
}
|
|
77
90
|
return tokens;
|
|
78
91
|
}
|
|
79
92
|
export function calculateContextUsage(messages, systemPrompt, maxTokens) {
|
package/dist/cost-tracker.js
CHANGED
|
@@ -3,67 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { NOOP_COLORIZER } from "./colorizer.js";
|
|
5
5
|
import { findOpenRouterModel } from "./data/openrouter-models.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// Anthropic (per 1M tokens, USD)
|
|
12
|
-
"claude-opus-4.6": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
|
|
13
|
-
"claude-opus-4-6": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }, // alias
|
|
14
|
-
"claude-opus-4.5": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
|
|
15
|
-
"claude-opus-4.1": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
|
|
16
|
-
"claude-opus-4": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
|
|
17
|
-
"claude-sonnet-4.6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
18
|
-
"claude-sonnet-4-6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, // alias
|
|
19
|
-
"claude-sonnet-4.5": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
20
|
-
"claude-sonnet-4": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
21
|
-
"claude-3.7-sonnet": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
22
|
-
"claude-3-7-sonnet": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
23
|
-
"claude-3.5-haiku": { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 },
|
|
24
|
-
"claude-haiku-4.5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 },
|
|
25
|
-
"claude-haiku-4-5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, // alias
|
|
26
|
-
// OpenAI
|
|
27
|
-
"gpt-5.4": pricing(5, 20),
|
|
28
|
-
"gpt-5.4-mini": pricing(1.5, 6),
|
|
29
|
-
"gpt-5.4-pro": pricing(10, 40),
|
|
30
|
-
"gpt-5": pricing(5, 20),
|
|
31
|
-
"gpt-4o": pricing(2.5, 10),
|
|
32
|
-
"gpt-4o-mini": pricing(0.15, 0.6),
|
|
33
|
-
"gpt-4.1": pricing(2, 8),
|
|
34
|
-
"gpt-4.1-mini": pricing(0.4, 1.6),
|
|
35
|
-
"o4-mini": pricing(1.1, 4.4),
|
|
36
|
-
"o3": pricing(10, 40),
|
|
37
|
-
"o3-mini": pricing(1.1, 4.4),
|
|
38
|
-
// Google
|
|
39
|
-
"gemini-2.5-pro": pricing(1.25, 10),
|
|
40
|
-
"gemini-2.5-pro-preview": pricing(1.25, 10),
|
|
41
|
-
"gemini-2.5-flash": pricing(0.15, 0.6),
|
|
42
|
-
"gemini-3.1-pro-preview": pricing(2, 10),
|
|
43
|
-
"gemini-3-flash-preview": pricing(0.15, 0.6),
|
|
44
|
-
"gemini-2.0-flash": pricing(0.1, 0.4),
|
|
45
|
-
// DeepSeek
|
|
46
|
-
"deepseek-v4-flash": pricing(0.126, 0.252),
|
|
47
|
-
"deepseek-v4-pro": pricing(0.5, 2),
|
|
48
|
-
"deepseek-v3.2": pricing(0.14, 0.28),
|
|
49
|
-
"deepseek-chat": pricing(0.14, 0.28),
|
|
50
|
-
"deepseek-r1": pricing(0.55, 2.19),
|
|
51
|
-
"deepseek-reasoner": pricing(0.55, 2.19),
|
|
52
|
-
// Qwen
|
|
53
|
-
"qwen3-coder": pricing(0.3, 0.6),
|
|
54
|
-
"qwen3-235b-a22b": pricing(0.3, 1.2),
|
|
55
|
-
"qwen3-30b-a3b": pricing(0.1, 0.3),
|
|
56
|
-
"qwen3-max": pricing(0.5, 2),
|
|
57
|
-
// Meta
|
|
58
|
-
"llama-4-maverick": pricing(0.2, 0.8),
|
|
59
|
-
"llama-4-scout": pricing(0.15, 0.4),
|
|
60
|
-
// Mistral
|
|
61
|
-
"devstral-medium": pricing(0.5, 1.5),
|
|
62
|
-
"mistral-large": pricing(2, 6),
|
|
63
|
-
"devstral-small": pricing(0.1, 0.3),
|
|
64
|
-
};
|
|
65
|
-
// Default fallback pricing
|
|
66
|
-
const DEFAULT_PRICING = pricing(3, 15);
|
|
6
|
+
import { MODEL_PRICING, DEFAULT_PRICING, } from "./data/model-metadata.js";
|
|
7
|
+
// Pricing per 1M tokens (USD). The MODEL_PRICING table + DEFAULT_PRICING now
|
|
8
|
+
// live in data/model-metadata.json (loaded by data/model-metadata.ts) so a
|
|
9
|
+
// price change is a data edit, not a code change. cacheRead/cacheWrite are
|
|
10
|
+
// derived there: read = 10% of input, write = 125% of input.
|
|
67
11
|
/** Build a ModelPricing from an OpenRouter snapshot entry. */
|
|
68
12
|
function openRouterPricing(hit) {
|
|
69
13
|
const input = hit.inputPricePerMillion;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential encryption boundary.
|
|
3
|
+
*
|
|
4
|
+
* The core has no business owning a platform encryption key — on the desktop
|
|
5
|
+
* the only safe key lives behind Electron `safeStorage`, which is in the main
|
|
6
|
+
* process, not in this worker. So core defines an INTERFACE and the host feeds
|
|
7
|
+
* an implementation: desktop main injects a safeStorage-backed cipher; the
|
|
8
|
+
* headless CLI / SDK inject {@link PlaintextCipher}. This keeps `safeStorage`
|
|
9
|
+
* out of `packages/core` entirely (`grep -R safeStorage packages/core/src`
|
|
10
|
+
* must stay empty) and puts secret crypto where the key actually is.
|
|
11
|
+
*
|
|
12
|
+
* The stored field is a tagged string so a store written by one cipher can be
|
|
13
|
+
* read (or rejected) by another:
|
|
14
|
+
* - `plain:<secret>` — PlaintextCipher, or any pre-cipher legacy value
|
|
15
|
+
* that has no recognized prefix (treated as plain).
|
|
16
|
+
* - `enc:<scheme>:<base64>` — an encrypting cipher; `<scheme>` lets a cipher
|
|
17
|
+
* recognize its own ciphertext via canDecrypt().
|
|
18
|
+
*/
|
|
19
|
+
export interface EncryptionCipher {
|
|
20
|
+
/** Encrypt a plaintext secret into its stored (tagged) form. */
|
|
21
|
+
encrypt(plaintext: string): string;
|
|
22
|
+
/** Decrypt a stored value back to plaintext. Must accept this cipher's own
|
|
23
|
+
* output and legacy un-prefixed plaintext; may throw if a value is
|
|
24
|
+
* recognizably foreign and undecryptable. */
|
|
25
|
+
decrypt(stored: string): string;
|
|
26
|
+
/** True when this cipher can decrypt `stored`. Used by the store to decide
|
|
27
|
+
* whether to migrate (re-encrypt on next save) a value written by a
|
|
28
|
+
* different cipher / left as legacy plaintext. */
|
|
29
|
+
canDecrypt?(stored: string): boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The no-encryption strategy — chosen explicitly, not a no-op. Headless and
|
|
33
|
+
* SDK hosts have no safe key store, so they keep credentials as owner-only
|
|
34
|
+
* (0o600) plaintext, exactly as before this boundary existed. Named so the
|
|
35
|
+
* choice reads honestly in host wiring: `new CredentialStore(cwd, new
|
|
36
|
+
* PlaintextCipher())` says "plaintext on purpose", not "forgot to encrypt".
|
|
37
|
+
*/
|
|
38
|
+
export declare class PlaintextCipher implements EncryptionCipher {
|
|
39
|
+
encrypt(plaintext: string): string;
|
|
40
|
+
decrypt(stored: string): string;
|
|
41
|
+
canDecrypt(stored: string): boolean;
|
|
42
|
+
}
|
|
43
|
+
/** Reads a value that may be tagged (`plain:`) or legacy bare plaintext. */
|
|
44
|
+
export declare function readPlaintext(stored: string): string;
|
|
45
|
+
/** Host startup hook: install the process-wide credential cipher (desktop main
|
|
46
|
+
* passes a safeStorage-backed implementation). Idempotent; last call wins. */
|
|
47
|
+
export declare function setDefaultCredentialCipher(cipher: EncryptionCipher): void;
|
|
48
|
+
/** The current process-default cipher (PlaintextCipher unless a host set one). */
|
|
49
|
+
export declare function getDefaultCredentialCipher(): EncryptionCipher;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const PLAIN_PREFIX = "plain:";
|
|
2
|
+
/**
|
|
3
|
+
* The no-encryption strategy — chosen explicitly, not a no-op. Headless and
|
|
4
|
+
* SDK hosts have no safe key store, so they keep credentials as owner-only
|
|
5
|
+
* (0o600) plaintext, exactly as before this boundary existed. Named so the
|
|
6
|
+
* choice reads honestly in host wiring: `new CredentialStore(cwd, new
|
|
7
|
+
* PlaintextCipher())` says "plaintext on purpose", not "forgot to encrypt".
|
|
8
|
+
*/
|
|
9
|
+
export class PlaintextCipher {
|
|
10
|
+
encrypt(plaintext) {
|
|
11
|
+
return `${PLAIN_PREFIX}${plaintext}`;
|
|
12
|
+
}
|
|
13
|
+
decrypt(stored) {
|
|
14
|
+
// Accept our own tag, and treat any un-tagged legacy value as plaintext.
|
|
15
|
+
if (stored.startsWith(PLAIN_PREFIX))
|
|
16
|
+
return stored.slice(PLAIN_PREFIX.length);
|
|
17
|
+
if (stored.startsWith("enc:")) {
|
|
18
|
+
throw new Error("PlaintextCipher cannot decrypt an encrypted credential");
|
|
19
|
+
}
|
|
20
|
+
return stored;
|
|
21
|
+
}
|
|
22
|
+
canDecrypt(stored) {
|
|
23
|
+
return !stored.startsWith("enc:");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Reads a value that may be tagged (`plain:`) or legacy bare plaintext. */
|
|
27
|
+
export function readPlaintext(stored) {
|
|
28
|
+
return stored.startsWith(PLAIN_PREFIX) ? stored.slice(PLAIN_PREFIX.length) : stored;
|
|
29
|
+
}
|
|
30
|
+
// ─── Process-default cipher ──────────────────────────────────────
|
|
31
|
+
// CredentialStore is constructed at ~12 call sites (core + desktop) as
|
|
32
|
+
// `new CredentialStore(cwd)`. Rather than thread a cipher through every one,
|
|
33
|
+
// the host sets the process default ONCE at startup; stores pick it up unless
|
|
34
|
+
// a cipher is passed explicitly. Defaults to PlaintextCipher so any host that
|
|
35
|
+
// never calls the setter behaves exactly as before.
|
|
36
|
+
let defaultCipher = new PlaintextCipher();
|
|
37
|
+
/** Host startup hook: install the process-wide credential cipher (desktop main
|
|
38
|
+
* passes a safeStorage-backed implementation). Idempotent; last call wins. */
|
|
39
|
+
export function setDefaultCredentialCipher(cipher) {
|
|
40
|
+
defaultCipher = cipher;
|
|
41
|
+
}
|
|
42
|
+
/** The current process-default cipher (PlaintextCipher unless a host set one). */
|
|
43
|
+
export function getDefaultCredentialCipher() {
|
|
44
|
+
return defaultCipher;
|
|
45
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie jar 工具(凭证模块第二期):core 侧的纯函数,把存进 CredentialStore 的
|
|
3
|
+
* cookie 凭证(序列化的 jar)转成 yt-dlp/curl/wget/aria2 都吃的 Netscape cookies.txt。
|
|
4
|
+
*
|
|
5
|
+
* 形态与 desktop/src/main/credentials-service.ts 的 `formatNetscapeCookies` 一致
|
|
6
|
+
* (desktop 在拓取那一刻用,core 在取用那一刻用)。core 不能 import desktop,故各持一份
|
|
7
|
+
* 同语义的纯实现 —— 都无 Electron 依赖、可单测。
|
|
8
|
+
*/
|
|
9
|
+
/** 与 Electron Cookie 对齐的最小子集(jar 里存的就是这个)。 */
|
|
10
|
+
export interface CookieLike {
|
|
11
|
+
domain?: string;
|
|
12
|
+
hostOnly?: boolean;
|
|
13
|
+
path?: string;
|
|
14
|
+
secure?: boolean;
|
|
15
|
+
expirationDate?: number;
|
|
16
|
+
name: string;
|
|
17
|
+
value: string;
|
|
18
|
+
}
|
|
19
|
+
/** Cookie[] → Netscape cookies.txt 字符串。跳过含 TAB/换行的脏 cookie。 */
|
|
20
|
+
export declare function formatNetscapeCookies(cookies: CookieLike[]): string;
|
|
21
|
+
/**
|
|
22
|
+
* 解析 cookie 凭证的 `secret`(序列化 jar)。容错:非数组/坏 JSON → 空数组。
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseCookieJar(secret: string | undefined): CookieLike[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie jar 工具(凭证模块第二期):core 侧的纯函数,把存进 CredentialStore 的
|
|
3
|
+
* cookie 凭证(序列化的 jar)转成 yt-dlp/curl/wget/aria2 都吃的 Netscape cookies.txt。
|
|
4
|
+
*
|
|
5
|
+
* 形态与 desktop/src/main/credentials-service.ts 的 `formatNetscapeCookies` 一致
|
|
6
|
+
* (desktop 在拓取那一刻用,core 在取用那一刻用)。core 不能 import desktop,故各持一份
|
|
7
|
+
* 同语义的纯实现 —— 都无 Electron 依赖、可单测。
|
|
8
|
+
*/
|
|
9
|
+
function bad(s) {
|
|
10
|
+
return s.includes("\t") || s.includes("\n") || s.includes("\r");
|
|
11
|
+
}
|
|
12
|
+
/** Cookie[] → Netscape cookies.txt 字符串。跳过含 TAB/换行的脏 cookie。 */
|
|
13
|
+
export function formatNetscapeCookies(cookies) {
|
|
14
|
+
const lines = ["# Netscape HTTP Cookie File"];
|
|
15
|
+
for (const c of cookies) {
|
|
16
|
+
if (bad(c.name) || bad(c.value) || (c.domain && bad(c.domain)))
|
|
17
|
+
continue;
|
|
18
|
+
const domain = c.domain ?? "";
|
|
19
|
+
const includeSub = c.hostOnly === true ? "FALSE" : "TRUE";
|
|
20
|
+
const path = c.path ?? "/";
|
|
21
|
+
const secure = c.secure ? "TRUE" : "FALSE";
|
|
22
|
+
const expiry = typeof c.expirationDate === "number" ? String(Math.floor(c.expirationDate)) : "0";
|
|
23
|
+
lines.push([domain, includeSub, path, secure, expiry, c.name, c.value].join("\t"));
|
|
24
|
+
}
|
|
25
|
+
return lines.join("\n") + "\n";
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 解析 cookie 凭证的 `secret`(序列化 jar)。容错:非数组/坏 JSON → 空数组。
|
|
29
|
+
*/
|
|
30
|
+
export function parseCookieJar(secret) {
|
|
31
|
+
if (!secret)
|
|
32
|
+
return [];
|
|
33
|
+
try {
|
|
34
|
+
const parsed = JSON.parse(secret);
|
|
35
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { CredentialStore } from "./store.js";
|
|
2
|
+
export type { CredentialScope, MaskedCredential } from "./store.js";
|
|
3
|
+
export { type EncryptionCipher, PlaintextCipher, setDefaultCredentialCipher, getDefaultCredentialCipher, } from "./cipher.js";
|
|
4
|
+
export type { Credential, CredentialType, CredentialStoreFile } from "./types.js";
|
|
5
|
+
export { formatNetscapeCookies, parseCookieJar, type CookieLike } from "./cookie-jar.js";
|
|
6
|
+
export { useCredentialToolDef, useCredentialToolDefFor, useCredentialTool, sweepStaleCredentialCookies, } from "./use-credential-tool.js";
|
|
7
|
+
export { credentialUseGate } from "./use-gate.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { CredentialStore } from "./store.js";
|
|
2
|
+
export { PlaintextCipher, setDefaultCredentialCipher, getDefaultCredentialCipher, } from "./cipher.js";
|
|
3
|
+
export { formatNetscapeCookies, parseCookieJar } from "./cookie-jar.js";
|
|
4
|
+
export { useCredentialToolDef, useCredentialToolDefFor, useCredentialTool, sweepStaleCredentialCookies, } from "./use-credential-tool.js";
|
|
5
|
+
export { credentialUseGate } from "./use-gate.js";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InjectCredential 工具:把一条 cookie 凭证「注入内置浏览器」(恢复登录态),
|
|
3
|
+
* 让 AI 能以该账号身份在内置浏览器面板做 UI 操作(配 browser_* 工具)。
|
|
4
|
+
*
|
|
5
|
+
* 与 UseCredential 的区别:
|
|
6
|
+
* - UseCredential 取 cookie 文件路径走 HTTP 请求(curl/yt-dlp),只读、不改浏览器。
|
|
7
|
+
* - InjectCredential 改的是内置浏览器的登录态(先清再灌),副作用更大 →
|
|
8
|
+
* 独立的逐条门 `autoInjectByAI`(不复用 autoUseByAI)。
|
|
9
|
+
*
|
|
10
|
+
* 跨进程:实际的 restoreCookiesToBrowser 在 desktop main(core 够不到 Electron
|
|
11
|
+
* session),经 `ctx.injectCredentialToBrowser` 回调(宿主注入,镜像 askUser)触发。
|
|
12
|
+
*/
|
|
13
|
+
import type { ToolDefinition } from "../types.js";
|
|
14
|
+
import type { ToolContext } from "../tool-system/context.js";
|
|
15
|
+
export declare const injectCredentialToolDef: ToolDefinition;
|
|
16
|
+
/** 该工具仅在有 cookie 凭证 且 宿主接了注入回调时才可见(BUILTIN_TOOL_GUARDS)。 */
|
|
17
|
+
export declare function isInjectCredentialAvailable(cwd: string): boolean;
|
|
18
|
+
export declare function injectCredentialTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string>;
|
|
19
|
+
/** 测试钩子:清空会话 allow 集。 */
|
|
20
|
+
export declare function __resetInjectCredentialSessionAllowForTests(): void;
|