@chances-ai/engine 24.0.0
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/dist/agents/discover.d.ts +30 -0
- package/dist/agents/discover.d.ts.map +1 -0
- package/dist/agents/discover.js +183 -0
- package/dist/agents/discover.js.map +1 -0
- package/dist/agents/index.d.ts +20 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +52 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/parse.d.ts +61 -0
- package/dist/agents/parse.d.ts.map +1 -0
- package/dist/agents/parse.js +527 -0
- package/dist/agents/parse.js.map +1 -0
- package/dist/agents/types.d.ts +52 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +8 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/ai/adapters/ai-sdk-stream.d.ts +19 -0
- package/dist/ai/adapters/ai-sdk-stream.d.ts.map +1 -0
- package/dist/ai/adapters/ai-sdk-stream.js +125 -0
- package/dist/ai/adapters/ai-sdk-stream.js.map +1 -0
- package/dist/ai/adapters/ai-sdk.d.ts +56 -0
- package/dist/ai/adapters/ai-sdk.d.ts.map +1 -0
- package/dist/ai/adapters/ai-sdk.js +112 -0
- package/dist/ai/adapters/ai-sdk.js.map +1 -0
- package/dist/ai/adapters/mock.d.ts +13 -0
- package/dist/ai/adapters/mock.d.ts.map +1 -0
- package/dist/ai/adapters/mock.js +54 -0
- package/dist/ai/adapters/mock.js.map +1 -0
- package/dist/ai/adapters/openai-compatible.d.ts +23 -0
- package/dist/ai/adapters/openai-compatible.d.ts.map +1 -0
- package/dist/ai/adapters/openai-compatible.js +45 -0
- package/dist/ai/adapters/openai-compatible.js.map +1 -0
- package/dist/ai/cost.d.ts +3 -0
- package/dist/ai/cost.d.ts.map +1 -0
- package/dist/ai/cost.js +5 -0
- package/dist/ai/cost.js.map +1 -0
- package/dist/ai/index.d.ts +12 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +11 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/known-models.d.ts +20 -0
- package/dist/ai/known-models.d.ts.map +1 -0
- package/dist/ai/known-models.js +129 -0
- package/dist/ai/known-models.js.map +1 -0
- package/dist/ai/registry.d.ts +12 -0
- package/dist/ai/registry.d.ts.map +1 -0
- package/dist/ai/registry.js +24 -0
- package/dist/ai/registry.js.map +1 -0
- package/dist/ai/retry.d.ts +11 -0
- package/dist/ai/retry.d.ts.map +1 -0
- package/dist/ai/retry.js +14 -0
- package/dist/ai/retry.js.map +1 -0
- package/dist/ai/router.d.ts +25 -0
- package/dist/ai/router.d.ts.map +1 -0
- package/dist/ai/router.js +36 -0
- package/dist/ai/router.js.map +1 -0
- package/dist/ai/setup.d.ts +23 -0
- package/dist/ai/setup.d.ts.map +1 -0
- package/dist/ai/setup.js +47 -0
- package/dist/ai/setup.js.map +1 -0
- package/dist/ai/summarizer.d.ts +24 -0
- package/dist/ai/summarizer.d.ts.map +1 -0
- package/dist/ai/summarizer.js +56 -0
- package/dist/ai/summarizer.js.map +1 -0
- package/dist/ai/types.d.ts +83 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +2 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/core/compaction/circuit-breaker.d.ts +32 -0
- package/dist/core/compaction/circuit-breaker.d.ts.map +1 -0
- package/dist/core/compaction/circuit-breaker.js +42 -0
- package/dist/core/compaction/circuit-breaker.js.map +1 -0
- package/dist/core/compaction/compactor.d.ts +75 -0
- package/dist/core/compaction/compactor.d.ts.map +1 -0
- package/dist/core/compaction/compactor.js +261 -0
- package/dist/core/compaction/compactor.js.map +1 -0
- package/dist/core/compaction/estimate.d.ts +39 -0
- package/dist/core/compaction/estimate.d.ts.map +1 -0
- package/dist/core/compaction/estimate.js +74 -0
- package/dist/core/compaction/estimate.js.map +1 -0
- package/dist/core/compaction/index.d.ts +5 -0
- package/dist/core/compaction/index.d.ts.map +1 -0
- package/dist/core/compaction/index.js +5 -0
- package/dist/core/compaction/index.js.map +1 -0
- package/dist/core/compaction/prune.d.ts +43 -0
- package/dist/core/compaction/prune.d.ts.map +1 -0
- package/dist/core/compaction/prune.js +51 -0
- package/dist/core/compaction/prune.js.map +1 -0
- package/dist/core/engine.d.ts +268 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +767 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/task-tool.d.ts +175 -0
- package/dist/core/task-tool.d.ts.map +1 -0
- package/dist/core/task-tool.js +901 -0
- package/dist/core/task-tool.js.map +1 -0
- package/dist/core/workspace-query.d.ts +83 -0
- package/dist/core/workspace-query.d.ts.map +1 -0
- package/dist/core/workspace-query.js +217 -0
- package/dist/core/workspace-query.js.map +1 -0
- package/dist/core/worktree/active-marker.d.ts +31 -0
- package/dist/core/worktree/active-marker.d.ts.map +1 -0
- package/dist/core/worktree/active-marker.js +109 -0
- package/dist/core/worktree/active-marker.js.map +1 -0
- package/dist/core/worktree/create.d.ts +40 -0
- package/dist/core/worktree/create.d.ts.map +1 -0
- package/dist/core/worktree/create.js +121 -0
- package/dist/core/worktree/create.js.map +1 -0
- package/dist/core/worktree/errors.d.ts +7 -0
- package/dist/core/worktree/errors.d.ts.map +1 -0
- package/dist/core/worktree/errors.js +11 -0
- package/dist/core/worktree/errors.js.map +1 -0
- package/dist/core/worktree/gc.d.ts +39 -0
- package/dist/core/worktree/gc.d.ts.map +1 -0
- package/dist/core/worktree/gc.js +146 -0
- package/dist/core/worktree/gc.js.map +1 -0
- package/dist/core/worktree/git.d.ts +53 -0
- package/dist/core/worktree/git.d.ts.map +1 -0
- package/dist/core/worktree/git.js +166 -0
- package/dist/core/worktree/git.js.map +1 -0
- package/dist/core/worktree/index.d.ts +8 -0
- package/dist/core/worktree/index.d.ts.map +1 -0
- package/dist/core/worktree/index.js +8 -0
- package/dist/core/worktree/index.js.map +1 -0
- package/dist/core/worktree/paths.d.ts +26 -0
- package/dist/core/worktree/paths.d.ts.map +1 -0
- package/dist/core/worktree/paths.js +57 -0
- package/dist/core/worktree/paths.js.map +1 -0
- package/dist/core/worktree/slug.d.ts +6 -0
- package/dist/core/worktree/slug.d.ts.map +1 -0
- package/dist/core/worktree/slug.js +21 -0
- package/dist/core/worktree/slug.js.map +1 -0
- package/dist/local-vault/file-store.d.ts +64 -0
- package/dist/local-vault/file-store.d.ts.map +1 -0
- package/dist/local-vault/file-store.js +225 -0
- package/dist/local-vault/file-store.js.map +1 -0
- package/dist/local-vault/index.d.ts +57 -0
- package/dist/local-vault/index.d.ts.map +1 -0
- package/dist/local-vault/index.js +68 -0
- package/dist/local-vault/index.js.map +1 -0
- package/dist/local-vault/keychain.d.ts +58 -0
- package/dist/local-vault/keychain.d.ts.map +1 -0
- package/dist/local-vault/keychain.js +200 -0
- package/dist/local-vault/keychain.js.map +1 -0
- package/dist/local-vault/mutex.d.ts +20 -0
- package/dist/local-vault/mutex.d.ts.map +1 -0
- package/dist/local-vault/mutex.js +44 -0
- package/dist/local-vault/mutex.js.map +1 -0
- package/dist/local-vault/passphrase.d.ts +30 -0
- package/dist/local-vault/passphrase.d.ts.map +1 -0
- package/dist/local-vault/passphrase.js +72 -0
- package/dist/local-vault/passphrase.js.map +1 -0
- package/dist/lsp/config.d.ts +34 -0
- package/dist/lsp/config.d.ts.map +1 -0
- package/dist/lsp/config.js +68 -0
- package/dist/lsp/config.js.map +1 -0
- package/dist/lsp/detect.d.ts +7 -0
- package/dist/lsp/detect.d.ts.map +1 -0
- package/dist/lsp/detect.js +78 -0
- package/dist/lsp/detect.js.map +1 -0
- package/dist/lsp/errors.d.ts +11 -0
- package/dist/lsp/errors.d.ts.map +1 -0
- package/dist/lsp/errors.js +11 -0
- package/dist/lsp/errors.js.map +1 -0
- package/dist/lsp/formatters.d.ts +147 -0
- package/dist/lsp/formatters.d.ts.map +1 -0
- package/dist/lsp/formatters.js +259 -0
- package/dist/lsp/formatters.js.map +1 -0
- package/dist/lsp/index.d.ts +31 -0
- package/dist/lsp/index.d.ts.map +1 -0
- package/dist/lsp/index.js +31 -0
- package/dist/lsp/index.js.map +1 -0
- package/dist/lsp/instance.d.ts +72 -0
- package/dist/lsp/instance.d.ts.map +1 -0
- package/dist/lsp/instance.js +489 -0
- package/dist/lsp/instance.js.map +1 -0
- package/dist/lsp/lazy-load.d.ts +27 -0
- package/dist/lsp/lazy-load.d.ts.map +1 -0
- package/dist/lsp/lazy-load.js +57 -0
- package/dist/lsp/lazy-load.js.map +1 -0
- package/dist/lsp/manager.d.ts +59 -0
- package/dist/lsp/manager.d.ts.map +1 -0
- package/dist/lsp/manager.js +242 -0
- package/dist/lsp/manager.js.map +1 -0
- package/dist/lsp/ops.d.ts +13 -0
- package/dist/lsp/ops.d.ts.map +1 -0
- package/dist/lsp/ops.js +225 -0
- package/dist/lsp/ops.js.map +1 -0
- package/dist/lsp/rpc.d.ts +47 -0
- package/dist/lsp/rpc.d.ts.map +1 -0
- package/dist/lsp/rpc.js +134 -0
- package/dist/lsp/rpc.js.map +1 -0
- package/dist/lsp/safe-uri.d.ts +18 -0
- package/dist/lsp/safe-uri.d.ts.map +1 -0
- package/dist/lsp/safe-uri.js +96 -0
- package/dist/lsp/safe-uri.js.map +1 -0
- package/dist/lsp/types.d.ts +70 -0
- package/dist/lsp/types.d.ts.map +1 -0
- package/dist/lsp/types.js +16 -0
- package/dist/lsp/types.js.map +1 -0
- package/dist/mcp/bridge.d.ts +57 -0
- package/dist/mcp/bridge.d.ts.map +1 -0
- package/dist/mcp/bridge.js +98 -0
- package/dist/mcp/bridge.js.map +1 -0
- package/dist/mcp/category.d.ts +22 -0
- package/dist/mcp/category.d.ts.map +1 -0
- package/dist/mcp/category.js +11 -0
- package/dist/mcp/category.js.map +1 -0
- package/dist/mcp/client.d.ts +228 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +352 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/content.d.ts +86 -0
- package/dist/mcp/content.d.ts.map +1 -0
- package/dist/mcp/content.js +147 -0
- package/dist/mcp/content.js.map +1 -0
- package/dist/mcp/env.d.ts +19 -0
- package/dist/mcp/env.d.ts.map +1 -0
- package/dist/mcp/env.js +50 -0
- package/dist/mcp/env.js.map +1 -0
- package/dist/mcp/host.d.ts +199 -0
- package/dist/mcp/host.d.ts.map +1 -0
- package/dist/mcp/host.js +530 -0
- package/dist/mcp/host.js.map +1 -0
- package/dist/mcp/index.d.ts +18 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +17 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/load-mcp-host.d.ts +32 -0
- package/dist/mcp/load-mcp-host.d.ts.map +1 -0
- package/dist/mcp/load-mcp-host.js +49 -0
- package/dist/mcp/load-mcp-host.js.map +1 -0
- package/dist/mcp/oauth/callback-server.d.ts +73 -0
- package/dist/mcp/oauth/callback-server.d.ts.map +1 -0
- package/dist/mcp/oauth/callback-server.js +280 -0
- package/dist/mcp/oauth/callback-server.js.map +1 -0
- package/dist/mcp/oauth/config-hash.d.ts +24 -0
- package/dist/mcp/oauth/config-hash.d.ts.map +1 -0
- package/dist/mcp/oauth/config-hash.js +55 -0
- package/dist/mcp/oauth/config-hash.js.map +1 -0
- package/dist/mcp/oauth/error-normalize.d.ts +39 -0
- package/dist/mcp/oauth/error-normalize.d.ts.map +1 -0
- package/dist/mcp/oauth/error-normalize.js +91 -0
- package/dist/mcp/oauth/error-normalize.js.map +1 -0
- package/dist/mcp/oauth/provider.d.ts +190 -0
- package/dist/mcp/oauth/provider.d.ts.map +1 -0
- package/dist/mcp/oauth/provider.js +305 -0
- package/dist/mcp/oauth/provider.js.map +1 -0
- package/dist/mcp/oauth/refresh-coalescer.d.ts +46 -0
- package/dist/mcp/oauth/refresh-coalescer.d.ts.map +1 -0
- package/dist/mcp/oauth/refresh-coalescer.js +77 -0
- package/dist/mcp/oauth/refresh-coalescer.js.map +1 -0
- package/dist/mcp/oauth/sdk-shapes.d.ts +77 -0
- package/dist/mcp/oauth/sdk-shapes.d.ts.map +1 -0
- package/dist/mcp/oauth/sdk-shapes.js +21 -0
- package/dist/mcp/oauth/sdk-shapes.js.map +1 -0
- package/dist/mcp/parse.d.ts +28 -0
- package/dist/mcp/parse.d.ts.map +1 -0
- package/dist/mcp/parse.js +209 -0
- package/dist/mcp/parse.js.map +1 -0
- package/dist/mcp/prompts.d.ts +31 -0
- package/dist/mcp/prompts.d.ts.map +1 -0
- package/dist/mcp/prompts.js +71 -0
- package/dist/mcp/prompts.js.map +1 -0
- package/dist/mcp/redact.d.ts +62 -0
- package/dist/mcp/redact.d.ts.map +1 -0
- package/dist/mcp/redact.js +87 -0
- package/dist/mcp/redact.js.map +1 -0
- package/dist/mcp/resources.d.ts +70 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +170 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/types.d.ts +123 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +2 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/memory/frontmatter.d.ts +18 -0
- package/dist/memory/frontmatter.d.ts.map +1 -0
- package/dist/memory/frontmatter.js +81 -0
- package/dist/memory/frontmatter.js.map +1 -0
- package/dist/memory/index.d.ts +5 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +5 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/store.d.ts +44 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +237 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/memory/tools.d.ts +11 -0
- package/dist/memory/tools.d.ts.map +1 -0
- package/dist/memory/tools.js +159 -0
- package/dist/memory/tools.js.map +1 -0
- package/dist/memory/types.d.ts +32 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +20 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/plugin-api/index.d.ts +167 -0
- package/dist/plugin-api/index.d.ts.map +1 -0
- package/dist/plugin-api/index.js +151 -0
- package/dist/plugin-api/index.js.map +1 -0
- package/dist/plugin-logger/index.d.ts +21 -0
- package/dist/plugin-logger/index.d.ts.map +1 -0
- package/dist/plugin-logger/index.js +59 -0
- package/dist/plugin-logger/index.js.map +1 -0
- package/dist/session/index.d.ts +125 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +202 -0
- package/dist/session/index.js.map +1 -0
- package/dist/tools/approval.d.ts +33 -0
- package/dist/tools/approval.d.ts.map +1 -0
- package/dist/tools/approval.js +53 -0
- package/dist/tools/approval.js.map +1 -0
- package/dist/tools/builtins/_shared.d.ts +94 -0
- package/dist/tools/builtins/_shared.d.ts.map +1 -0
- package/dist/tools/builtins/_shared.js +246 -0
- package/dist/tools/builtins/_shared.js.map +1 -0
- package/dist/tools/builtins/ask-user-question.d.ts +27 -0
- package/dist/tools/builtins/ask-user-question.d.ts.map +1 -0
- package/dist/tools/builtins/ask-user-question.js +191 -0
- package/dist/tools/builtins/ask-user-question.js.map +1 -0
- package/dist/tools/builtins/bash.d.ts +3 -0
- package/dist/tools/builtins/bash.d.ts.map +1 -0
- package/dist/tools/builtins/bash.js +158 -0
- package/dist/tools/builtins/bash.js.map +1 -0
- package/dist/tools/builtins/diff.d.ts +3 -0
- package/dist/tools/builtins/diff.d.ts.map +1 -0
- package/dist/tools/builtins/diff.js +83 -0
- package/dist/tools/builtins/diff.js.map +1 -0
- package/dist/tools/builtins/edit.d.ts +3 -0
- package/dist/tools/builtins/edit.d.ts.map +1 -0
- package/dist/tools/builtins/edit.js +40 -0
- package/dist/tools/builtins/edit.js.map +1 -0
- package/dist/tools/builtins/glob.d.ts +3 -0
- package/dist/tools/builtins/glob.d.ts.map +1 -0
- package/dist/tools/builtins/glob.js +37 -0
- package/dist/tools/builtins/glob.js.map +1 -0
- package/dist/tools/builtins/grep.d.ts +3 -0
- package/dist/tools/builtins/grep.d.ts.map +1 -0
- package/dist/tools/builtins/grep.js +81 -0
- package/dist/tools/builtins/grep.js.map +1 -0
- package/dist/tools/builtins/lsp.d.ts +3 -0
- package/dist/tools/builtins/lsp.d.ts.map +1 -0
- package/dist/tools/builtins/lsp.js +102 -0
- package/dist/tools/builtins/lsp.js.map +1 -0
- package/dist/tools/builtins/pty.d.ts +64 -0
- package/dist/tools/builtins/pty.d.ts.map +1 -0
- package/dist/tools/builtins/pty.js +536 -0
- package/dist/tools/builtins/pty.js.map +1 -0
- package/dist/tools/builtins/read.d.ts +3 -0
- package/dist/tools/builtins/read.d.ts.map +1 -0
- package/dist/tools/builtins/read.js +18 -0
- package/dist/tools/builtins/read.js.map +1 -0
- package/dist/tools/builtins/web-fetch.d.ts +4 -0
- package/dist/tools/builtins/web-fetch.d.ts.map +1 -0
- package/dist/tools/builtins/web-fetch.js +353 -0
- package/dist/tools/builtins/web-fetch.js.map +1 -0
- package/dist/tools/builtins/write.d.ts +3 -0
- package/dist/tools/builtins/write.d.ts.map +1 -0
- package/dist/tools/builtins/write.js +48 -0
- package/dist/tools/builtins/write.js.map +1 -0
- package/dist/tools/builtins.d.ts +9 -0
- package/dist/tools/builtins.d.ts.map +1 -0
- package/dist/tools/builtins.js +29 -0
- package/dist/tools/builtins.js.map +1 -0
- package/dist/tools/diff.d.ts +18 -0
- package/dist/tools/diff.d.ts.map +1 -0
- package/dist/tools/diff.js +57 -0
- package/dist/tools/diff.js.map +1 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/permission.d.ts +120 -0
- package/dist/tools/permission.d.ts.map +1 -0
- package/dist/tools/permission.js +208 -0
- package/dist/tools/permission.js.map +1 -0
- package/dist/tools/registry.d.ts +12 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +19 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/types.d.ts +244 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +15 -0
- package/dist/tools/types.js.map +1 -0
- package/package.json +109 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../../src/core/compaction/circuit-breaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,cAAc;IACjB,QAAQ,GAAG,CAAC,CAAC;IACJ,KAAK,CAAS;IAE/B,YAAY,KAAK,GAAG,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC;IACrC,CAAC;IAED;;oEAEgE;IAChE,IAAI;QACF,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;IACrB,CAAC;IAED,8DAA8D;IAC9D,KAAK;QACH,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;IACpB,CAAC;IAED,8CAA8C;IAC9C,YAAY;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type CompactionReason, type EventBus } from "@chances-ai/runtime";
|
|
2
|
+
import { type ModelDescriptor, type ProviderAdapter } from "../../ai/index.js";
|
|
3
|
+
import type { ModelRouter } from "../../ai/index.js";
|
|
4
|
+
import type { ModelSelection } from "@chances-ai/runtime";
|
|
5
|
+
import type { SessionManager } from "../../session/index.js";
|
|
6
|
+
import type { CompactionConfig } from "@chances-ai/runtime/config";
|
|
7
|
+
export interface ShouldCompactInput {
|
|
8
|
+
/** Last provider-stream-call's `usage.inputTokens`. NOT the
|
|
9
|
+
* turn-aggregate (codex Round-1 MUST-FIX #1). */
|
|
10
|
+
lastRequestInputTokens: number;
|
|
11
|
+
model: ModelDescriptor;
|
|
12
|
+
}
|
|
13
|
+
export interface CompactResult {
|
|
14
|
+
ok: boolean;
|
|
15
|
+
mode?: "prune" | "summary";
|
|
16
|
+
beforeTokens: number;
|
|
17
|
+
afterTokens?: number;
|
|
18
|
+
savedTokens?: number;
|
|
19
|
+
/** When `ok === false`, a one-line reason: `"circuit-open"`,
|
|
20
|
+
* `"disabled"`, `"in-progress"`, `"empty-summary"`,
|
|
21
|
+
* `"summary-failed"`, `"cancelled"`. */
|
|
22
|
+
reason?: string;
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface CompactorDeps {
|
|
26
|
+
session: SessionManager;
|
|
27
|
+
router: ModelRouter;
|
|
28
|
+
bus: EventBus;
|
|
29
|
+
selection: ModelSelection;
|
|
30
|
+
config?: CompactionConfig;
|
|
31
|
+
/** Override for tests. Defaults to `Date.now`. */
|
|
32
|
+
clock?: () => number;
|
|
33
|
+
/** Test seam: substitute the summarizer (e.g. to return canned
|
|
34
|
+
* text or simulate failure). Default uses the real adapter
|
|
35
|
+
* helper. */
|
|
36
|
+
summarize?: (adapter: ProviderAdapter, modelId: string, signal: AbortSignal) => Promise<string>;
|
|
37
|
+
}
|
|
38
|
+
export declare class Compactor {
|
|
39
|
+
private readonly deps;
|
|
40
|
+
private readonly breaker;
|
|
41
|
+
private readonly settings;
|
|
42
|
+
private readonly clock;
|
|
43
|
+
private inFlight;
|
|
44
|
+
/** Tracks whether the just-finished compaction is the most recent
|
|
45
|
+
* thing on the session. Reset by the engine after the next non-
|
|
46
|
+
* compaction turn lands. */
|
|
47
|
+
private compactedRecently;
|
|
48
|
+
constructor(deps: CompactorDeps);
|
|
49
|
+
/**
|
|
50
|
+
* Predicate: should the engine call `compact("threshold")` now?
|
|
51
|
+
* Pure decision — no side effects, no events emitted.
|
|
52
|
+
*/
|
|
53
|
+
shouldCompact(input: ShouldCompactInput): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Runs a compaction. Returns immediately if another compaction is
|
|
56
|
+
* in flight (callers serialize via this, not externally). Emits
|
|
57
|
+
* `compaction:start` / `compaction:end` on the bus. Never throws —
|
|
58
|
+
* all failures are folded into `CompactResult.ok=false`.
|
|
59
|
+
*/
|
|
60
|
+
compact(reason: CompactionReason, signal: AbortSignal): Promise<CompactResult>;
|
|
61
|
+
/** Engine calls this after a non-compaction turn appends — clears
|
|
62
|
+
* the "we just compacted" latch so the next threshold check can
|
|
63
|
+
* fire. */
|
|
64
|
+
noteNonCompactionTurn(): void;
|
|
65
|
+
/** Used by `chances doctor` / tests. */
|
|
66
|
+
diagnostics(): {
|
|
67
|
+
tripped: boolean;
|
|
68
|
+
failureCount: number;
|
|
69
|
+
inFlight: boolean;
|
|
70
|
+
compactedRecently: boolean;
|
|
71
|
+
};
|
|
72
|
+
private estimateSessionTokens;
|
|
73
|
+
private finishFailure;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=compactor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compactor.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/compactor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,gBAAgB,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAChG,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,eAAe,EAAyB,MAAM,mBAAmB,CAAC;AACtG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAwDnE,MAAM,WAAW,kBAAkB;IACjC;qDACiD;IACjD,sBAAsB,EAAE,MAAM,CAAC;IAC/B,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;4CAEwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,GAAG,EAAE,QAAQ,CAAC;IACd,SAAS,EAAE,cAAc,CAAC;IAC1B,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IACrB;;iBAEa;IACb,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACjG;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAC5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAS;IACzB;;gCAE4B;IAC5B,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,IAAI,EAAE,aAAa;IAM/B;;;OAGG;IACH,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO;IAcjD;;;;;OAKG;IACG,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;IAqIpF;;eAEW;IACX,qBAAqB,IAAI,IAAI;IAI7B,wCAAwC;IACxC,WAAW,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,iBAAiB,EAAE,OAAO,CAAA;KAAE;IASxG,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,aAAa;CAoBtB"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { AppError, ErrorCode } from "@chances-ai/runtime";
|
|
2
|
+
import { summarizeConversation } from "../../ai/index.js";
|
|
3
|
+
import { CircuitBreaker } from "./circuit-breaker.js";
|
|
4
|
+
import { estimateTokens } from "./estimate.js";
|
|
5
|
+
import { pruneToolOutputs } from "./prune.js";
|
|
6
|
+
/**
|
|
7
|
+
* (3.5) Auto-compaction orchestrator. Stateless w.r.t. session
|
|
8
|
+
* messages — the engine owns the session, the compactor owns the
|
|
9
|
+
* policy + circuit breaker + in-flight lock.
|
|
10
|
+
*
|
|
11
|
+
* See `docs/3.5-design.md` for the full design rationale, including
|
|
12
|
+
* the codex Round-1 findings folded into the impl. Three triggers:
|
|
13
|
+
* - `manual`: bypasses circuit breaker; resets it on success.
|
|
14
|
+
* - `threshold`: gated by `shouldCompact()`; honors breaker.
|
|
15
|
+
* - `overflow`: bypasses circuit breaker (a 413 from the provider
|
|
16
|
+
* is itself a hard signal we must try); engine-driven, Anthropic-only.
|
|
17
|
+
*/
|
|
18
|
+
const DEFAULT_KEEP_RECENT_TURNS = 5;
|
|
19
|
+
const DEFAULT_PRUNE_MIN_SAVINGS = 20_000;
|
|
20
|
+
const DEFAULT_RESERVE_FLOOR = 16_384;
|
|
21
|
+
const DEFAULT_COMPACTABLE_TOOLS = ["bash", "grep"];
|
|
22
|
+
const RESERVE_RATIO = 0.10;
|
|
23
|
+
function resolveSettings(cfg) {
|
|
24
|
+
return {
|
|
25
|
+
enabled: cfg?.enabled ?? true,
|
|
26
|
+
keepRecentTurns: cfg?.keepRecentTurns ?? DEFAULT_KEEP_RECENT_TURNS,
|
|
27
|
+
pruneMinSavings: cfg?.pruneMinSavings ?? DEFAULT_PRUNE_MIN_SAVINGS,
|
|
28
|
+
compactableTools: cfg?.compactableTools ?? DEFAULT_COMPACTABLE_TOOLS,
|
|
29
|
+
reserveOverride: cfg?.reserveTokens,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Effective reserve for a given context window. Returns the
|
|
34
|
+
* config override if set, else `max(16384, floor(window * 0.10))`.
|
|
35
|
+
* Single ratio + floor; intentionally simpler than claude-code's
|
|
36
|
+
* tiered table (`13K @ <400K`, `30K @ <800K`, `50K @ >=800K`)
|
|
37
|
+
* which we don't have telemetry to tune.
|
|
38
|
+
*/
|
|
39
|
+
function reserveTokensFor(window, override) {
|
|
40
|
+
if (override !== undefined)
|
|
41
|
+
return override;
|
|
42
|
+
return Math.max(DEFAULT_RESERVE_FLOOR, Math.floor(window * RESERVE_RATIO));
|
|
43
|
+
}
|
|
44
|
+
export class Compactor {
|
|
45
|
+
deps;
|
|
46
|
+
breaker = new CircuitBreaker();
|
|
47
|
+
settings;
|
|
48
|
+
clock;
|
|
49
|
+
inFlight = false;
|
|
50
|
+
/** Tracks whether the just-finished compaction is the most recent
|
|
51
|
+
* thing on the session. Reset by the engine after the next non-
|
|
52
|
+
* compaction turn lands. */
|
|
53
|
+
compactedRecently = false;
|
|
54
|
+
constructor(deps) {
|
|
55
|
+
this.deps = deps;
|
|
56
|
+
this.settings = resolveSettings(deps.config);
|
|
57
|
+
this.clock = deps.clock ?? Date.now;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Predicate: should the engine call `compact("threshold")` now?
|
|
61
|
+
* Pure decision — no side effects, no events emitted.
|
|
62
|
+
*/
|
|
63
|
+
shouldCompact(input) {
|
|
64
|
+
if (!this.settings.enabled)
|
|
65
|
+
return false;
|
|
66
|
+
if (this.breaker.tripped())
|
|
67
|
+
return false;
|
|
68
|
+
// (codex Round-1 SHOULD-FIX #3 / design "compactedRecently" latch)
|
|
69
|
+
// Engine clears this via `noteNonCompactionTurn()` after each turn
|
|
70
|
+
// that did NOT compact, so a single threshold-compact doesn't
|
|
71
|
+
// re-fire on the very next turn before the model has had a chance
|
|
72
|
+
// to actually use the new shorter context.
|
|
73
|
+
if (this.compactedRecently)
|
|
74
|
+
return false;
|
|
75
|
+
const reserve = reserveTokensFor(input.model.contextWindow, this.settings.reserveOverride);
|
|
76
|
+
const threshold = input.model.contextWindow - reserve;
|
|
77
|
+
return input.lastRequestInputTokens > threshold;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Runs a compaction. Returns immediately if another compaction is
|
|
81
|
+
* in flight (callers serialize via this, not externally). Emits
|
|
82
|
+
* `compaction:start` / `compaction:end` on the bus. Never throws —
|
|
83
|
+
* all failures are folded into `CompactResult.ok=false`.
|
|
84
|
+
*/
|
|
85
|
+
async compact(reason, signal) {
|
|
86
|
+
if (this.inFlight) {
|
|
87
|
+
return { ok: false, reason: "in-progress", beforeTokens: this.estimateSessionTokens() };
|
|
88
|
+
}
|
|
89
|
+
if (reason === "threshold" && this.breaker.tripped()) {
|
|
90
|
+
return { ok: false, reason: "circuit-open", beforeTokens: this.estimateSessionTokens() };
|
|
91
|
+
}
|
|
92
|
+
// (codex Round-2 MUST-FIX #1) `enabled:false` is the "disable
|
|
93
|
+
// AUTO compaction" knob — the user explicitly invoking `/compact`
|
|
94
|
+
// (`reason === "manual"`) should still work. Same logic for
|
|
95
|
+
// `overflow`: a 413 from the provider is a hard signal we must
|
|
96
|
+
// try regardless of the config switch (otherwise the disabled
|
|
97
|
+
// setting silently breaks recovery). Threshold compaction
|
|
98
|
+
// honors the switch.
|
|
99
|
+
if (!this.settings.enabled && reason === "threshold") {
|
|
100
|
+
return { ok: false, reason: "disabled", beforeTokens: this.estimateSessionTokens() };
|
|
101
|
+
}
|
|
102
|
+
this.inFlight = true;
|
|
103
|
+
const startedAt = this.clock();
|
|
104
|
+
const beforeTokens = this.estimateSessionTokens();
|
|
105
|
+
this.deps.bus.emit({ type: "compaction:start", reason, beforeTokens });
|
|
106
|
+
try {
|
|
107
|
+
// Stage 1: prune. Single-pass over flattened messages to
|
|
108
|
+
// estimate savings; if it clears the gate, commit per-turn
|
|
109
|
+
// via SessionManager so the persistence layer mirrors the
|
|
110
|
+
// pruned form on disk.
|
|
111
|
+
const flat = this.deps.session.messages();
|
|
112
|
+
const dryRun = pruneToolOutputs(flat, { compactableTools: this.settings.compactableTools });
|
|
113
|
+
if (dryRun.savedTokens >= this.settings.pruneMinSavings) {
|
|
114
|
+
this.deps.session.pruneTurns(this.settings.keepRecentTurns, (turnMsgs) => pruneToolOutputs(turnMsgs, { compactableTools: this.settings.compactableTools }).messages);
|
|
115
|
+
const afterTokens = this.estimateSessionTokens();
|
|
116
|
+
const savedTokens = Math.max(0, beforeTokens - afterTokens);
|
|
117
|
+
const durationMs = this.clock() - startedAt;
|
|
118
|
+
this.breaker.reset();
|
|
119
|
+
this.compactedRecently = true;
|
|
120
|
+
this.deps.bus.emit({
|
|
121
|
+
type: "compaction:end",
|
|
122
|
+
reason,
|
|
123
|
+
ok: true,
|
|
124
|
+
beforeTokens,
|
|
125
|
+
afterTokens,
|
|
126
|
+
savedTokens,
|
|
127
|
+
mode: "prune",
|
|
128
|
+
durationMs,
|
|
129
|
+
});
|
|
130
|
+
return { ok: true, mode: "prune", beforeTokens, afterTokens, savedTokens };
|
|
131
|
+
}
|
|
132
|
+
// Stage 2: LLM summary. Reuses the existing summarizer +
|
|
133
|
+
// session.compactTurns API.
|
|
134
|
+
const choice = this.deps.selection.get();
|
|
135
|
+
let route;
|
|
136
|
+
try {
|
|
137
|
+
route = this.deps.router.pick({
|
|
138
|
+
preferredModel: choice.model,
|
|
139
|
+
preferredProvider: choice.provider,
|
|
140
|
+
needsTools: false,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
return this.finishFailure(reason, beforeTokens, startedAt, e, "no-route");
|
|
145
|
+
}
|
|
146
|
+
const messages = this.deps.session.messages();
|
|
147
|
+
let summary;
|
|
148
|
+
try {
|
|
149
|
+
summary = await (this.deps.summarize
|
|
150
|
+
? this.deps.summarize(route.adapter, route.model.id, signal)
|
|
151
|
+
: summarizeConversation(route.adapter, route.model.id, messages, signal));
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
// (codex Round-2 MUST-FIX #2) Cancellation classification.
|
|
155
|
+
// The AI-SDK adapter converts ANY thrown stream error,
|
|
156
|
+
// including AbortError, into a provider `{type:"error"}`
|
|
157
|
+
// event (`packages/ai/src/adapters/ai-sdk-stream.ts:87`),
|
|
158
|
+
// which `summarizeConversation` then maps to
|
|
159
|
+
// `AppError(Provider)` — NOT `AppError(Cancelled)`. So the
|
|
160
|
+
// old `e.code === Cancelled` check silently absorbed user
|
|
161
|
+
// Ctrl-C as a compactor fault and incremented the breaker.
|
|
162
|
+
// Detect by also inspecting `signal.aborted` so a real abort
|
|
163
|
+
// is correctly classified regardless of how the underlying
|
|
164
|
+
// SDK chose to wrap it.
|
|
165
|
+
const isCancelled = signal.aborted ||
|
|
166
|
+
(e instanceof AppError && e.code === ErrorCode.Cancelled);
|
|
167
|
+
if (isCancelled) {
|
|
168
|
+
const durationMs = this.clock() - startedAt;
|
|
169
|
+
this.deps.bus.emit({
|
|
170
|
+
type: "compaction:end",
|
|
171
|
+
reason,
|
|
172
|
+
ok: false,
|
|
173
|
+
beforeTokens,
|
|
174
|
+
durationMs,
|
|
175
|
+
error: "Cancelled",
|
|
176
|
+
});
|
|
177
|
+
return { ok: false, reason: "cancelled", beforeTokens, error: "Cancelled" };
|
|
178
|
+
}
|
|
179
|
+
return this.finishFailure(reason, beforeTokens, startedAt, e, "summary-failed");
|
|
180
|
+
}
|
|
181
|
+
if (!summary || summary.trim().length === 0) {
|
|
182
|
+
return this.finishFailure(reason, beforeTokens, startedAt, new Error("empty summary"), "empty-summary");
|
|
183
|
+
}
|
|
184
|
+
this.deps.session.compactTurns(summary, this.settings.keepRecentTurns);
|
|
185
|
+
const afterTokens = this.estimateSessionTokens();
|
|
186
|
+
const savedTokens = Math.max(0, beforeTokens - afterTokens);
|
|
187
|
+
const durationMs = this.clock() - startedAt;
|
|
188
|
+
// Manual + overflow override AND threshold success both reset
|
|
189
|
+
// the breaker. Threshold success says "the summarizer is alive
|
|
190
|
+
// again"; manual says "user vouches for it."
|
|
191
|
+
this.breaker.reset();
|
|
192
|
+
this.compactedRecently = true;
|
|
193
|
+
this.deps.bus.emit({
|
|
194
|
+
type: "compaction:end",
|
|
195
|
+
reason,
|
|
196
|
+
ok: true,
|
|
197
|
+
beforeTokens,
|
|
198
|
+
afterTokens,
|
|
199
|
+
savedTokens,
|
|
200
|
+
mode: "summary",
|
|
201
|
+
durationMs,
|
|
202
|
+
});
|
|
203
|
+
return { ok: true, mode: "summary", beforeTokens, afterTokens, savedTokens };
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
this.inFlight = false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/** Engine calls this after a non-compaction turn appends — clears
|
|
210
|
+
* the "we just compacted" latch so the next threshold check can
|
|
211
|
+
* fire. */
|
|
212
|
+
noteNonCompactionTurn() {
|
|
213
|
+
this.compactedRecently = false;
|
|
214
|
+
}
|
|
215
|
+
/** Used by `chances doctor` / tests. */
|
|
216
|
+
diagnostics() {
|
|
217
|
+
return {
|
|
218
|
+
tripped: this.breaker.tripped(),
|
|
219
|
+
failureCount: this.breaker.failureCount(),
|
|
220
|
+
inFlight: this.inFlight,
|
|
221
|
+
compactedRecently: this.compactedRecently,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
estimateSessionTokens() {
|
|
225
|
+
// Sum every text + tool-result output across the session.
|
|
226
|
+
let total = 0;
|
|
227
|
+
for (const m of this.deps.session.messages()) {
|
|
228
|
+
for (const p of m.content) {
|
|
229
|
+
if (p.type === "text")
|
|
230
|
+
total += estimateTokens(p.text);
|
|
231
|
+
else if (p.type === "tool-result")
|
|
232
|
+
total += estimateTokens(p.output);
|
|
233
|
+
else if (p.type === "tool-call") {
|
|
234
|
+
// args is JSON; serialize for estimate.
|
|
235
|
+
try {
|
|
236
|
+
total += estimateTokens(JSON.stringify(p.args));
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
/* circular / unserializable — skip */
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return total;
|
|
245
|
+
}
|
|
246
|
+
finishFailure(reason, beforeTokens, startedAt, err, failureReason) {
|
|
247
|
+
this.breaker.note();
|
|
248
|
+
const durationMs = this.clock() - startedAt;
|
|
249
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
250
|
+
this.deps.bus.emit({
|
|
251
|
+
type: "compaction:end",
|
|
252
|
+
reason,
|
|
253
|
+
ok: false,
|
|
254
|
+
beforeTokens,
|
|
255
|
+
durationMs,
|
|
256
|
+
error: errMsg,
|
|
257
|
+
});
|
|
258
|
+
return { ok: false, reason: failureReason, beforeTokens, error: errMsg };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=compactor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compactor.js","sourceRoot":"","sources":["../../../src/core/compaction/compactor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* (3.5) Conservative token estimator. Used by the pruner's
|
|
3
|
+
* "minimum savings" gate and by the compactor's `beforeTokens` /
|
|
4
|
+
* `savedTokens` reporting on bus events.
|
|
5
|
+
*
|
|
6
|
+
* Codex Round-1 SHOULD-FIX #1: the GPT-3 era `char/4` estimate
|
|
7
|
+
* underestimates by ~2x for CJK-heavy content (one Han glyph is
|
|
8
|
+
* typically 1–2 tokens, not 0.25). Three of the 11 providers we
|
|
9
|
+
* ship are CJK-first with tight windows — Doubao 32K, Kimi 32K,
|
|
10
|
+
* DeepSeek 65K — where a 16K reserve is already half the window.
|
|
11
|
+
* We take `max(char/4, cjk/2)` so estimates are conservative in
|
|
12
|
+
* the direction that matters (false "over threshold" wastes a
|
|
13
|
+
* compaction; false "under threshold" silently overflows the
|
|
14
|
+
* next request).
|
|
15
|
+
*
|
|
16
|
+
* Estimates are NEVER used as proof of success. After a
|
|
17
|
+
* compaction returns, the proof is the NEXT turn's actual
|
|
18
|
+
* `lastRequestInputTokens` from the provider, surfaced on the
|
|
19
|
+
* `usage:turn` event.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Conservative token estimate. Returns the max of:
|
|
23
|
+
* - the BPE-accurate native count (tiktoken via `@chances-ai/native`), and
|
|
24
|
+
* - a heuristic floor `max(ceil(chars/4), ceil(cjk/2))` — the GPT-3 ASCII
|
|
25
|
+
* rule plus the CJK adjustment from SHOULD-FIX #1.
|
|
26
|
+
*
|
|
27
|
+
* (7.2 R1 #11) Taking the `max` means the accurate native count is used when
|
|
28
|
+
* available, but the estimate can NEVER drop below the conservative CJK floor —
|
|
29
|
+
* preserving the compaction/prune safety direction (over-estimating wastes a
|
|
30
|
+
* compaction; under-estimating silently overflows the next request). When the
|
|
31
|
+
* native addon is absent, `native.countTokens` itself returns a `chars/4`
|
|
32
|
+
* heuristic, so the result collapses to the CJK floor. Stays synchronous
|
|
33
|
+
* (tiktoken is CPU-only) so the pruner/compactor hot paths are unaffected.
|
|
34
|
+
*
|
|
35
|
+
* Iterates code points (NOT UTF-16 units) so a single emoji or extended-plane
|
|
36
|
+
* glyph counts once.
|
|
37
|
+
*/
|
|
38
|
+
export declare function estimateTokens(text: string): number;
|
|
39
|
+
//# sourceMappingURL=estimate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estimate.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/estimate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AA4BH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWnD"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* (3.5) Conservative token estimator. Used by the pruner's
|
|
3
|
+
* "minimum savings" gate and by the compactor's `beforeTokens` /
|
|
4
|
+
* `savedTokens` reporting on bus events.
|
|
5
|
+
*
|
|
6
|
+
* Codex Round-1 SHOULD-FIX #1: the GPT-3 era `char/4` estimate
|
|
7
|
+
* underestimates by ~2x for CJK-heavy content (one Han glyph is
|
|
8
|
+
* typically 1–2 tokens, not 0.25). Three of the 11 providers we
|
|
9
|
+
* ship are CJK-first with tight windows — Doubao 32K, Kimi 32K,
|
|
10
|
+
* DeepSeek 65K — where a 16K reserve is already half the window.
|
|
11
|
+
* We take `max(char/4, cjk/2)` so estimates are conservative in
|
|
12
|
+
* the direction that matters (false "over threshold" wastes a
|
|
13
|
+
* compaction; false "under threshold" silently overflows the
|
|
14
|
+
* next request).
|
|
15
|
+
*
|
|
16
|
+
* Estimates are NEVER used as proof of success. After a
|
|
17
|
+
* compaction returns, the proof is the NEXT turn's actual
|
|
18
|
+
* `lastRequestInputTokens` from the provider, surfaced on the
|
|
19
|
+
* `usage:turn` event.
|
|
20
|
+
*/
|
|
21
|
+
import { native } from "@chances-ai/native";
|
|
22
|
+
/**
|
|
23
|
+
* Code-point ranges we count as "CJK" for the purposes of the
|
|
24
|
+
* dual-estimate. Includes:
|
|
25
|
+
* - CJK Unified Ideographs (U+4E00–U+9FFF)
|
|
26
|
+
* - CJK Extension A (U+3400–U+4DBF)
|
|
27
|
+
* - Hiragana (U+3040–U+309F)
|
|
28
|
+
* - Katakana (U+30A0–U+30FF)
|
|
29
|
+
* - Hangul Syllables (U+AC00–U+D7AF)
|
|
30
|
+
* - CJK Symbols & Punctuation (U+3000–U+303F)
|
|
31
|
+
*
|
|
32
|
+
* Surrogate pairs (CJK Extensions B-F at U+20000+) decode as a
|
|
33
|
+
* single code point through `for…of`, so they count once each.
|
|
34
|
+
*/
|
|
35
|
+
function isCjkCodePoint(cp) {
|
|
36
|
+
return ((cp >= 0x4e00 && cp <= 0x9fff) ||
|
|
37
|
+
(cp >= 0x3400 && cp <= 0x4dbf) ||
|
|
38
|
+
(cp >= 0x3040 && cp <= 0x309f) ||
|
|
39
|
+
(cp >= 0x30a0 && cp <= 0x30ff) ||
|
|
40
|
+
(cp >= 0xac00 && cp <= 0xd7af) ||
|
|
41
|
+
(cp >= 0x3000 && cp <= 0x303f));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Conservative token estimate. Returns the max of:
|
|
45
|
+
* - the BPE-accurate native count (tiktoken via `@chances-ai/native`), and
|
|
46
|
+
* - a heuristic floor `max(ceil(chars/4), ceil(cjk/2))` — the GPT-3 ASCII
|
|
47
|
+
* rule plus the CJK adjustment from SHOULD-FIX #1.
|
|
48
|
+
*
|
|
49
|
+
* (7.2 R1 #11) Taking the `max` means the accurate native count is used when
|
|
50
|
+
* available, but the estimate can NEVER drop below the conservative CJK floor —
|
|
51
|
+
* preserving the compaction/prune safety direction (over-estimating wastes a
|
|
52
|
+
* compaction; under-estimating silently overflows the next request). When the
|
|
53
|
+
* native addon is absent, `native.countTokens` itself returns a `chars/4`
|
|
54
|
+
* heuristic, so the result collapses to the CJK floor. Stays synchronous
|
|
55
|
+
* (tiktoken is CPU-only) so the pruner/compactor hot paths are unaffected.
|
|
56
|
+
*
|
|
57
|
+
* Iterates code points (NOT UTF-16 units) so a single emoji or extended-plane
|
|
58
|
+
* glyph counts once.
|
|
59
|
+
*/
|
|
60
|
+
export function estimateTokens(text) {
|
|
61
|
+
if (text.length === 0)
|
|
62
|
+
return 0;
|
|
63
|
+
let total = 0;
|
|
64
|
+
let cjk = 0;
|
|
65
|
+
for (const ch of text) {
|
|
66
|
+
total += 1;
|
|
67
|
+
const cp = ch.codePointAt(0);
|
|
68
|
+
if (cp !== undefined && isCjkCodePoint(cp))
|
|
69
|
+
cjk += 1;
|
|
70
|
+
}
|
|
71
|
+
const heuristicFloor = Math.max(Math.ceil(total / 4), Math.ceil(cjk / 2));
|
|
72
|
+
return Math.max(native.countTokens(text), heuristicFloor);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=estimate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estimate.js","sourceRoot":"","sources":["../../../src/core/compaction/estimate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C;;;;;;;;;;;;GAYG;AACH,SAAS,cAAc,CAAC,EAAU;IAChC,OAAO,CACL,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC,CAC/B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAChC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,KAAK,IAAI,CAAC,CAAC;QACX,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,EAAE,KAAK,SAAS,IAAI,cAAc,CAAC,EAAE,CAAC;YAAE,GAAG,IAAI,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAC1E,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Compactor, type CompactResult, type CompactorDeps, type ShouldCompactInput } from "./compactor.js";
|
|
2
|
+
export { CircuitBreaker } from "./circuit-breaker.js";
|
|
3
|
+
export { estimateTokens } from "./estimate.js";
|
|
4
|
+
export { pruneToolOutputs, type PruneResult, type PruneSettings } from "./prune.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC5G,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/compaction/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAmE,MAAM,gBAAgB,CAAC;AAC5G,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAwC,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Message } from "../../ai/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* (3.5) Stage 1 compaction: cheap, deterministic, no LLM call.
|
|
4
|
+
*
|
|
5
|
+
* Pure transform over a SINGLE turn's messages. For every
|
|
6
|
+
* `tool-result` content part whose `name` is in `compactableTools`,
|
|
7
|
+
* replaces the part's `output` field with a one-line marker.
|
|
8
|
+
* `callId` / `name` / `ok` / `type` stay intact so the Anthropic
|
|
9
|
+
* `tool_use ↔ tool_result` pairing (and OpenAI / Google
|
|
10
|
+
* equivalents) survives — codex Round-1 MUST-FIX #2 spelled this
|
|
11
|
+
* out: replacing the whole part orphans the `tool_use` ID and the
|
|
12
|
+
* provider refuses the message list.
|
|
13
|
+
*
|
|
14
|
+
* The "recent window" gate lives in the caller
|
|
15
|
+
* (`SessionManager.pruneTurns(keepRecentTurns, ...)`), not here.
|
|
16
|
+
* This function unconditionally prunes every allowlisted
|
|
17
|
+
* tool-result it sees; the caller decides which turns to feed it.
|
|
18
|
+
*
|
|
19
|
+
* Allowlist not denylist (codex Round-1 SHOULD-FIX #2): the default
|
|
20
|
+
* `compactableTools = ["bash", "grep"]` covers the high-volume,
|
|
21
|
+
* low-information-density tools. Everything else — `read`,
|
|
22
|
+
* `glob`, `diff`, `web_fetch`, `task`, `memory_*`, every
|
|
23
|
+
* `mcp__*` — is shielded by virtue of not being in the allowlist.
|
|
24
|
+
*/
|
|
25
|
+
export interface PruneSettings {
|
|
26
|
+
/** Tool names whose `tool-result.output` is eligible for pruning. */
|
|
27
|
+
compactableTools: readonly string[];
|
|
28
|
+
}
|
|
29
|
+
export interface PruneResult {
|
|
30
|
+
/** Same array length; possibly-rewritten tool-result parts. */
|
|
31
|
+
messages: Message[];
|
|
32
|
+
/**
|
|
33
|
+
* Estimated tokens removed by the pruning pass. Computed as
|
|
34
|
+
* `sum(estimateTokens(original.output) - estimateTokens(marker))`
|
|
35
|
+
* with negative deltas clamped to zero (a tiny output whose marker
|
|
36
|
+
* would be longer is left untouched).
|
|
37
|
+
*/
|
|
38
|
+
savedTokens: number;
|
|
39
|
+
/** How many `tool-result` parts were rewritten. */
|
|
40
|
+
prunedCount: number;
|
|
41
|
+
}
|
|
42
|
+
export declare function pruneToolOutputs(messages: Message[], settings: PruneSettings): PruneResult;
|
|
43
|
+
//# sourceMappingURL=prune.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/prune.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAIjD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB;;;;;OAKG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,OAAO,EAAE,EACnB,QAAQ,EAAE,aAAa,GACtB,WAAW,CAqCb"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { stripControlChars } from "@chances-ai/runtime";
|
|
2
|
+
import { estimateTokens } from "./estimate.js";
|
|
3
|
+
export function pruneToolOutputs(messages, settings) {
|
|
4
|
+
if (messages.length === 0 || settings.compactableTools.length === 0) {
|
|
5
|
+
return { messages: messages.slice(), savedTokens: 0, prunedCount: 0 };
|
|
6
|
+
}
|
|
7
|
+
const allowSet = new Set(settings.compactableTools);
|
|
8
|
+
let savedTokens = 0;
|
|
9
|
+
let prunedCount = 0;
|
|
10
|
+
const out = messages.map((m) => {
|
|
11
|
+
let touched = false;
|
|
12
|
+
const newContent = m.content.map((part) => {
|
|
13
|
+
if (part.type !== "tool-result")
|
|
14
|
+
return part;
|
|
15
|
+
if (!allowSet.has(part.name))
|
|
16
|
+
return part;
|
|
17
|
+
const before = estimateTokens(part.output);
|
|
18
|
+
// Marker is short + bounded. Per-tool-name so a model that
|
|
19
|
+
// looks at the marker can still tell which tool produced it.
|
|
20
|
+
// (codex Round-2 SHOULD-FIX #3) Sanitize the display name —
|
|
21
|
+
// plugin-registered tool names aren't validated at
|
|
22
|
+
// `ToolRegistry.register` (`packages/tools/src/registry.ts:7`)
|
|
23
|
+
// and could carry newlines / control chars / extreme length
|
|
24
|
+
// that would corrupt the synthetic marker sent back to the
|
|
25
|
+
// model. The on-record `part.name` is preserved unchanged
|
|
26
|
+
// (Anthropic / OpenAI / Google all key tool_result on it).
|
|
27
|
+
const marker = `[tool output pruned for context — ${sanitizeDisplayName(part.name)}]`;
|
|
28
|
+
const after = estimateTokens(marker);
|
|
29
|
+
const delta = before - after;
|
|
30
|
+
if (delta <= 0)
|
|
31
|
+
return part; // marker would be longer; skip
|
|
32
|
+
savedTokens += delta;
|
|
33
|
+
prunedCount += 1;
|
|
34
|
+
touched = true;
|
|
35
|
+
return { ...part, output: marker };
|
|
36
|
+
});
|
|
37
|
+
return touched ? { ...m, content: newContent } : m;
|
|
38
|
+
});
|
|
39
|
+
return { messages: out, savedTokens, prunedCount };
|
|
40
|
+
}
|
|
41
|
+
/** Strip C0 + DEL controls, collapse whitespace, cap at 64 chars.
|
|
42
|
+
* Used only for the human-readable marker text; the canonical
|
|
43
|
+
* `part.name` survives unchanged so provider tool_result pairing
|
|
44
|
+
* is not affected. */
|
|
45
|
+
function sanitizeDisplayName(name) {
|
|
46
|
+
const stripped = stripControlChars(name).replace(/\s+/g, " ").trim();
|
|
47
|
+
if (stripped.length === 0)
|
|
48
|
+
return "(unnamed)";
|
|
49
|
+
return stripped.length <= 64 ? stripped : stripped.slice(0, 63) + "…";
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=prune.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune.js","sourceRoot":"","sources":["../../../src/core/compaction/prune.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AA6C/C,MAAM,UAAU,gBAAgB,CAC9B,QAAmB,EACnB,QAAuB;IAEvB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpE,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;IACxE,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACpD,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,MAAM,GAAG,GAAc,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACxC,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,UAAU,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACxC,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa;gBAAE,OAAO,IAAI,CAAC;YAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC1C,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC3C,2DAA2D;YAC3D,6DAA6D;YAC7D,4DAA4D;YAC5D,mDAAmD;YACnD,+DAA+D;YAC/D,4DAA4D;YAC5D,2DAA2D;YAC3D,0DAA0D;YAC1D,2DAA2D;YAC3D,MAAM,MAAM,GAAG,qCAAqC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;YACtF,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;YAC7B,IAAI,KAAK,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC,CAAC,+BAA+B;YAC5D,WAAW,IAAI,KAAK,CAAC;YACrB,WAAW,IAAI,CAAC,CAAC;YACjB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QACrC,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AACrD,CAAC;AAED;;;sBAGsB;AACtB,SAAS,mBAAmB,CAAC,IAAY;IACvC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACrE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IAC9C,OAAO,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC;AACxE,CAAC"}
|