@kenkaiiii/ggcoder 5.49.4 → 5.49.6
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/app-sidecar.js +3 -1
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/lsp/edit-telemetry.d.ts +27 -0
- package/dist/core/lsp/edit-telemetry.d.ts.map +1 -0
- package/dist/core/lsp/edit-telemetry.js +50 -0
- package/dist/core/lsp/edit-telemetry.js.map +1 -0
- package/dist/core/lsp/manager.d.ts +24 -1
- package/dist/core/lsp/manager.d.ts.map +1 -1
- package/dist/core/lsp/manager.js +53 -2
- package/dist/core/lsp/manager.js.map +1 -1
- package/dist/core/mcp/content.d.ts +5 -0
- package/dist/core/mcp/content.d.ts.map +1 -1
- package/dist/core/mcp/content.js +20 -2
- package/dist/core/mcp/content.js.map +1 -1
- package/dist/core/sandbox.d.ts +17 -1
- package/dist/core/sandbox.d.ts.map +1 -1
- package/dist/core/sandbox.js +74 -8
- package/dist/core/sandbox.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +10 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/tools/edit.d.ts +2 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +21 -5
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +28 -4
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/tools/write.d.ts +1 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +1 -1
- package/dist/tools/write.js.map +1 -1
- package/dist/ui/utils/text-utils.d.ts +0 -6
- package/dist/ui/utils/text-utils.d.ts.map +1 -1
- package/dist/ui/utils/text-utils.js +8 -3
- package/dist/ui/utils/text-utils.js.map +1 -1
- package/dist/utils/text.d.ts +41 -0
- package/dist/utils/text.d.ts.map +1 -1
- package/dist/utils/text.js +46 -0
- package/dist/utils/text.js.map +1 -1
- package/package.json +6 -10
- package/dist/app-sidecar-auth-broadcast.test.d.ts +0 -2
- package/dist/app-sidecar-auth-broadcast.test.d.ts.map +0 -1
- package/dist/app-sidecar-auth-broadcast.test.js +0 -383
- package/dist/app-sidecar-auth-broadcast.test.js.map +0 -1
- package/dist/app-sidecar-sessions.test.d.ts +0 -2
- package/dist/app-sidecar-sessions.test.d.ts.map +0 -1
- package/dist/app-sidecar-sessions.test.js +0 -178
- package/dist/app-sidecar-sessions.test.js.map +0 -1
- package/dist/chat-agents/general.test.d.ts +0 -2
- package/dist/chat-agents/general.test.d.ts.map +0 -1
- package/dist/chat-agents/general.test.js +0 -53
- package/dist/chat-agents/general.test.js.map +0 -1
- package/dist/chat-agents/jiwa.test.d.ts +0 -2
- package/dist/chat-agents/jiwa.test.d.ts.map +0 -1
- package/dist/chat-agents/jiwa.test.js +0 -66
- package/dist/chat-agents/jiwa.test.js.map +0 -1
- package/dist/chat-agents/memory.test.d.ts +0 -2
- package/dist/chat-agents/memory.test.d.ts.map +0 -1
- package/dist/chat-agents/memory.test.js +0 -165
- package/dist/chat-agents/memory.test.js.map +0 -1
- package/dist/chat-agents/specialists.test.d.ts +0 -2
- package/dist/chat-agents/specialists.test.d.ts.map +0 -1
- package/dist/chat-agents/specialists.test.js +0 -98
- package/dist/chat-agents/specialists.test.js.map +0 -1
- package/dist/cli/command-routing.test.d.ts +0 -2
- package/dist/cli/command-routing.test.d.ts.map +0 -1
- package/dist/cli/command-routing.test.js +0 -60
- package/dist/cli/command-routing.test.js.map +0 -1
- package/dist/config.test.d.ts +0 -2
- package/dist/config.test.d.ts.map +0 -1
- package/dist/config.test.js +0 -148
- package/dist/config.test.js.map +0 -1
- package/dist/core/agent-mcp-passthrough.test.d.ts +0 -2
- package/dist/core/agent-mcp-passthrough.test.d.ts.map +0 -1
- package/dist/core/agent-mcp-passthrough.test.js +0 -61
- package/dist/core/agent-mcp-passthrough.test.js.map +0 -1
- package/dist/core/agent-notifications.test.d.ts +0 -2
- package/dist/core/agent-notifications.test.d.ts.map +0 -1
- package/dist/core/agent-notifications.test.js +0 -97
- package/dist/core/agent-notifications.test.js.map +0 -1
- package/dist/core/agent-session-add-dir.test.d.ts +0 -2
- package/dist/core/agent-session-add-dir.test.d.ts.map +0 -1
- package/dist/core/agent-session-add-dir.test.js +0 -110
- package/dist/core/agent-session-add-dir.test.js.map +0 -1
- package/dist/core/agent-session-checkpoint-flush.test.d.ts +0 -2
- package/dist/core/agent-session-checkpoint-flush.test.d.ts.map +0 -1
- package/dist/core/agent-session-checkpoint-flush.test.js +0 -201
- package/dist/core/agent-session-checkpoint-flush.test.js.map +0 -1
- package/dist/core/agent-session-compaction.test.d.ts +0 -2
- package/dist/core/agent-session-compaction.test.d.ts.map +0 -1
- package/dist/core/agent-session-compaction.test.js +0 -1157
- package/dist/core/agent-session-compaction.test.js.map +0 -1
- package/dist/core/agent-session-crash-durability.test.d.ts +0 -2
- package/dist/core/agent-session-crash-durability.test.d.ts.map +0 -1
- package/dist/core/agent-session-crash-durability.test.js +0 -102
- package/dist/core/agent-session-crash-durability.test.js.map +0 -1
- package/dist/core/agent-session-marker-anchors.test.d.ts +0 -2
- package/dist/core/agent-session-marker-anchors.test.d.ts.map +0 -1
- package/dist/core/agent-session-marker-anchors.test.js +0 -326
- package/dist/core/agent-session-marker-anchors.test.js.map +0 -1
- package/dist/core/agent-session-memory-tail.test.d.ts +0 -2
- package/dist/core/agent-session-memory-tail.test.d.ts.map +0 -1
- package/dist/core/agent-session-memory-tail.test.js +0 -119
- package/dist/core/agent-session-memory-tail.test.js.map +0 -1
- package/dist/core/agent-session-model-switch.test.d.ts +0 -2
- package/dist/core/agent-session-model-switch.test.d.ts.map +0 -1
- package/dist/core/agent-session-model-switch.test.js +0 -161
- package/dist/core/agent-session-model-switch.test.js.map +0 -1
- package/dist/core/agent-session-notifications.test.d.ts +0 -2
- package/dist/core/agent-session-notifications.test.d.ts.map +0 -1
- package/dist/core/agent-session-notifications.test.js +0 -114
- package/dist/core/agent-session-notifications.test.js.map +0 -1
- package/dist/core/agent-session-pre-init-arming.test.d.ts +0 -2
- package/dist/core/agent-session-pre-init-arming.test.d.ts.map +0 -1
- package/dist/core/agent-session-pre-init-arming.test.js +0 -60
- package/dist/core/agent-session-pre-init-arming.test.js.map +0 -1
- package/dist/core/agent-session-process-gate.test.d.ts +0 -2
- package/dist/core/agent-session-process-gate.test.d.ts.map +0 -1
- package/dist/core/agent-session-process-gate.test.js +0 -98
- package/dist/core/agent-session-process-gate.test.js.map +0 -1
- package/dist/core/agent-session-queue.test.d.ts +0 -2
- package/dist/core/agent-session-queue.test.d.ts.map +0 -1
- package/dist/core/agent-session-queue.test.js +0 -184
- package/dist/core/agent-session-queue.test.js.map +0 -1
- package/dist/core/agent-session-review-coverage.test.d.ts +0 -2
- package/dist/core/agent-session-review-coverage.test.d.ts.map +0 -1
- package/dist/core/agent-session-review-coverage.test.js +0 -191
- package/dist/core/agent-session-review-coverage.test.js.map +0 -1
- package/dist/core/agent-session-slash-restore.test.d.ts +0 -2
- package/dist/core/agent-session-slash-restore.test.d.ts.map +0 -1
- package/dist/core/agent-session-slash-restore.test.js +0 -121
- package/dist/core/agent-session-slash-restore.test.js.map +0 -1
- package/dist/core/agent-session-subagent-policy.test.d.ts +0 -2
- package/dist/core/agent-session-subagent-policy.test.d.ts.map +0 -1
- package/dist/core/agent-session-subagent-policy.test.js +0 -40
- package/dist/core/agent-session-subagent-policy.test.js.map +0 -1
- package/dist/core/agent-session-tool-result-policy.test.d.ts +0 -2
- package/dist/core/agent-session-tool-result-policy.test.d.ts.map +0 -1
- package/dist/core/agent-session-tool-result-policy.test.js +0 -25
- package/dist/core/agent-session-tool-result-policy.test.js.map +0 -1
- package/dist/core/agent-session-tool-tiers.test.d.ts +0 -2
- package/dist/core/agent-session-tool-tiers.test.d.ts.map +0 -1
- package/dist/core/agent-session-tool-tiers.test.js +0 -138
- package/dist/core/agent-session-tool-tiers.test.js.map +0 -1
- package/dist/core/agent-session-verification-flow.test.d.ts +0 -2
- package/dist/core/agent-session-verification-flow.test.d.ts.map +0 -1
- package/dist/core/agent-session-verification-flow.test.js +0 -125
- package/dist/core/agent-session-verification-flow.test.js.map +0 -1
- package/dist/core/agent-session-verification-gate.test.d.ts +0 -2
- package/dist/core/agent-session-verification-gate.test.d.ts.map +0 -1
- package/dist/core/agent-session-verification-gate.test.js +0 -137
- package/dist/core/agent-session-verification-gate.test.js.map +0 -1
- package/dist/core/agent-tools-allowlist.test.d.ts +0 -2
- package/dist/core/agent-tools-allowlist.test.d.ts.map +0 -1
- package/dist/core/agent-tools-allowlist.test.js +0 -74
- package/dist/core/agent-tools-allowlist.test.js.map +0 -1
- package/dist/core/agents.test.d.ts +0 -2
- package/dist/core/agents.test.d.ts.map +0 -1
- package/dist/core/agents.test.js +0 -147
- package/dist/core/agents.test.js.map +0 -1
- package/dist/core/auto-update.test.d.ts +0 -2
- package/dist/core/auto-update.test.d.ts.map +0 -1
- package/dist/core/auto-update.test.js +0 -204
- package/dist/core/auto-update.test.js.map +0 -1
- package/dist/core/autopilot-cycle.test.d.ts +0 -2
- package/dist/core/autopilot-cycle.test.d.ts.map +0 -1
- package/dist/core/autopilot-cycle.test.js +0 -375
- package/dist/core/autopilot-cycle.test.js.map +0 -1
- package/dist/core/autopilot-gate.test.d.ts +0 -2
- package/dist/core/autopilot-gate.test.d.ts.map +0 -1
- package/dist/core/autopilot-gate.test.js +0 -298
- package/dist/core/autopilot-gate.test.js.map +0 -1
- package/dist/core/autopilot-verdict.test.d.ts +0 -2
- package/dist/core/autopilot-verdict.test.d.ts.map +0 -1
- package/dist/core/autopilot-verdict.test.js +0 -153
- package/dist/core/autopilot-verdict.test.js.map +0 -1
- package/dist/core/checkpoint-store.test.d.ts +0 -2
- package/dist/core/checkpoint-store.test.d.ts.map +0 -1
- package/dist/core/checkpoint-store.test.js +0 -111
- package/dist/core/checkpoint-store.test.js.map +0 -1
- package/dist/core/code-retrieval-chunkers.test.d.ts +0 -2
- package/dist/core/code-retrieval-chunkers.test.d.ts.map +0 -1
- package/dist/core/code-retrieval-chunkers.test.js +0 -203
- package/dist/core/code-retrieval-chunkers.test.js.map +0 -1
- package/dist/core/compaction/active-context.test.d.ts +0 -2
- package/dist/core/compaction/active-context.test.d.ts.map +0 -1
- package/dist/core/compaction/active-context.test.js +0 -57
- package/dist/core/compaction/active-context.test.js.map +0 -1
- package/dist/core/compaction/compactor.test.d.ts +0 -2
- package/dist/core/compaction/compactor.test.d.ts.map +0 -1
- package/dist/core/compaction/compactor.test.js +0 -1072
- package/dist/core/compaction/compactor.test.js.map +0 -1
- package/dist/core/compaction/policy.test.d.ts +0 -2
- package/dist/core/compaction/policy.test.d.ts.map +0 -1
- package/dist/core/compaction/policy.test.js +0 -35
- package/dist/core/compaction/policy.test.js.map +0 -1
- package/dist/core/compaction/query-aware-selector.test.d.ts +0 -2
- package/dist/core/compaction/query-aware-selector.test.d.ts.map +0 -1
- package/dist/core/compaction/query-aware-selector.test.js +0 -96
- package/dist/core/compaction/query-aware-selector.test.js.map +0 -1
- package/dist/core/compaction/token-estimator.test.d.ts +0 -2
- package/dist/core/compaction/token-estimator.test.d.ts.map +0 -1
- package/dist/core/compaction/token-estimator.test.js +0 -283
- package/dist/core/compaction/token-estimator.test.js.map +0 -1
- package/dist/core/compaction/tool-result-pruner.test.d.ts +0 -2
- package/dist/core/compaction/tool-result-pruner.test.d.ts.map +0 -1
- package/dist/core/compaction/tool-result-pruner.test.js +0 -320
- package/dist/core/compaction/tool-result-pruner.test.js.map +0 -1
- package/dist/core/context-limits.test.d.ts +0 -2
- package/dist/core/context-limits.test.d.ts.map +0 -1
- package/dist/core/context-limits.test.js +0 -55
- package/dist/core/context-limits.test.js.map +0 -1
- package/dist/core/continue-replay-inventory.test.d.ts +0 -2
- package/dist/core/continue-replay-inventory.test.d.ts.map +0 -1
- package/dist/core/continue-replay-inventory.test.js +0 -42
- package/dist/core/continue-replay-inventory.test.js.map +0 -1
- package/dist/core/encode-cwd.test.d.ts +0 -2
- package/dist/core/encode-cwd.test.d.ts.map +0 -1
- package/dist/core/encode-cwd.test.js +0 -80
- package/dist/core/encode-cwd.test.js.map +0 -1
- package/dist/core/event-bus.test.d.ts +0 -2
- package/dist/core/event-bus.test.d.ts.map +0 -1
- package/dist/core/event-bus.test.js +0 -33
- package/dist/core/event-bus.test.js.map +0 -1
- package/dist/core/extensions/plugin-bundles.test.d.ts +0 -2
- package/dist/core/extensions/plugin-bundles.test.d.ts.map +0 -1
- package/dist/core/extensions/plugin-bundles.test.js +0 -110
- package/dist/core/extensions/plugin-bundles.test.js.map +0 -1
- package/dist/core/foreign-session-import.test.d.ts +0 -2
- package/dist/core/foreign-session-import.test.d.ts.map +0 -1
- package/dist/core/foreign-session-import.test.js +0 -220
- package/dist/core/foreign-session-import.test.js.map +0 -1
- package/dist/core/hashline-edit-benchmark.test.d.ts +0 -2
- package/dist/core/hashline-edit-benchmark.test.d.ts.map +0 -1
- package/dist/core/hashline-edit-benchmark.test.js +0 -190
- package/dist/core/hashline-edit-benchmark.test.js.map +0 -1
- package/dist/core/ideal-review.test.d.ts +0 -2
- package/dist/core/ideal-review.test.d.ts.map +0 -1
- package/dist/core/ideal-review.test.js +0 -242
- package/dist/core/ideal-review.test.js.map +0 -1
- package/dist/core/input-normalization.test.d.ts +0 -2
- package/dist/core/input-normalization.test.d.ts.map +0 -1
- package/dist/core/input-normalization.test.js +0 -75
- package/dist/core/input-normalization.test.js.map +0 -1
- package/dist/core/json-mode-flag-parity.test.d.ts +0 -2
- package/dist/core/json-mode-flag-parity.test.d.ts.map +0 -1
- package/dist/core/json-mode-flag-parity.test.js +0 -66
- package/dist/core/json-mode-flag-parity.test.js.map +0 -1
- package/dist/core/ken-context.test.d.ts +0 -2
- package/dist/core/ken-context.test.d.ts.map +0 -1
- package/dist/core/ken-context.test.js +0 -342
- package/dist/core/ken-context.test.js.map +0 -1
- package/dist/core/ken-model.test.d.ts +0 -2
- package/dist/core/ken-model.test.d.ts.map +0 -1
- package/dist/core/ken-model.test.js +0 -51
- package/dist/core/ken-model.test.js.map +0 -1
- package/dist/core/ken-prompt.test.d.ts +0 -2
- package/dist/core/ken-prompt.test.d.ts.map +0 -1
- package/dist/core/ken-prompt.test.js +0 -191
- package/dist/core/ken-prompt.test.js.map +0 -1
- package/dist/core/language-detector.test.d.ts +0 -2
- package/dist/core/language-detector.test.d.ts.map +0 -1
- package/dist/core/language-detector.test.js +0 -109
- package/dist/core/language-detector.test.js.map +0 -1
- package/dist/core/local-endpoint-store.test.d.ts +0 -2
- package/dist/core/local-endpoint-store.test.d.ts.map +0 -1
- package/dist/core/local-endpoint-store.test.js +0 -123
- package/dist/core/local-endpoint-store.test.js.map +0 -1
- package/dist/core/loop-breaker.test.d.ts +0 -2
- package/dist/core/loop-breaker.test.d.ts.map +0 -1
- package/dist/core/loop-breaker.test.js +0 -238
- package/dist/core/loop-breaker.test.js.map +0 -1
- package/dist/core/lsp/client-navigation.test.d.ts +0 -2
- package/dist/core/lsp/client-navigation.test.d.ts.map +0 -1
- package/dist/core/lsp/client-navigation.test.js +0 -135
- package/dist/core/lsp/client-navigation.test.js.map +0 -1
- package/dist/core/lsp/format.test.d.ts +0 -2
- package/dist/core/lsp/format.test.d.ts.map +0 -1
- package/dist/core/lsp/format.test.js +0 -56
- package/dist/core/lsp/format.test.js.map +0 -1
- package/dist/core/lsp/integration.test.d.ts +0 -2
- package/dist/core/lsp/integration.test.d.ts.map +0 -1
- package/dist/core/lsp/integration.test.js +0 -60
- package/dist/core/lsp/integration.test.js.map +0 -1
- package/dist/core/lsp/jsonrpc.test.d.ts +0 -2
- package/dist/core/lsp/jsonrpc.test.d.ts.map +0 -1
- package/dist/core/lsp/jsonrpc.test.js +0 -127
- package/dist/core/lsp/jsonrpc.test.js.map +0 -1
- package/dist/core/lsp/manager-navigation.test.d.ts +0 -2
- package/dist/core/lsp/manager-navigation.test.d.ts.map +0 -1
- package/dist/core/lsp/manager-navigation.test.js +0 -121
- package/dist/core/lsp/manager-navigation.test.js.map +0 -1
- package/dist/core/lsp/manager.test.d.ts +0 -2
- package/dist/core/lsp/manager.test.d.ts.map +0 -1
- package/dist/core/lsp/manager.test.js +0 -220
- package/dist/core/lsp/manager.test.js.map +0 -1
- package/dist/core/lsp/pool.test.d.ts +0 -2
- package/dist/core/lsp/pool.test.d.ts.map +0 -1
- package/dist/core/lsp/pool.test.js +0 -286
- package/dist/core/lsp/pool.test.js.map +0 -1
- package/dist/core/lsp/servers.test.d.ts +0 -2
- package/dist/core/lsp/servers.test.d.ts.map +0 -1
- package/dist/core/lsp/servers.test.js +0 -67
- package/dist/core/lsp/servers.test.js.map +0 -1
- package/dist/core/lsp/uri.test.d.ts +0 -2
- package/dist/core/lsp/uri.test.d.ts.map +0 -1
- package/dist/core/lsp/uri.test.js +0 -56
- package/dist/core/lsp/uri.test.js.map +0 -1
- package/dist/core/lsp/windows.test.d.ts +0 -2
- package/dist/core/lsp/windows.test.d.ts.map +0 -1
- package/dist/core/lsp/windows.test.js +0 -239
- package/dist/core/lsp/windows.test.js.map +0 -1
- package/dist/core/mcp/catalog-cache.test.d.ts +0 -2
- package/dist/core/mcp/catalog-cache.test.d.ts.map +0 -1
- package/dist/core/mcp/catalog-cache.test.js +0 -99
- package/dist/core/mcp/catalog-cache.test.js.map +0 -1
- package/dist/core/mcp/client-session-recovery.test.d.ts +0 -2
- package/dist/core/mcp/client-session-recovery.test.d.ts.map +0 -1
- package/dist/core/mcp/client-session-recovery.test.js +0 -231
- package/dist/core/mcp/client-session-recovery.test.js.map +0 -1
- package/dist/core/mcp/content.test.d.ts +0 -2
- package/dist/core/mcp/content.test.d.ts.map +0 -1
- package/dist/core/mcp/content.test.js +0 -135
- package/dist/core/mcp/content.test.js.map +0 -1
- package/dist/core/mcp/defaults.test.d.ts +0 -2
- package/dist/core/mcp/defaults.test.d.ts.map +0 -1
- package/dist/core/mcp/defaults.test.js +0 -60
- package/dist/core/mcp/defaults.test.js.map +0 -1
- package/dist/core/mcp/elicitation.test.d.ts +0 -2
- package/dist/core/mcp/elicitation.test.d.ts.map +0 -1
- package/dist/core/mcp/elicitation.test.js +0 -158
- package/dist/core/mcp/elicitation.test.js.map +0 -1
- package/dist/core/mcp/legacy-negotiation.test.d.ts +0 -2
- package/dist/core/mcp/legacy-negotiation.test.d.ts.map +0 -1
- package/dist/core/mcp/legacy-negotiation.test.js +0 -80
- package/dist/core/mcp/legacy-negotiation.test.js.map +0 -1
- package/dist/core/mcp/loopback.test.d.ts +0 -2
- package/dist/core/mcp/loopback.test.d.ts.map +0 -1
- package/dist/core/mcp/loopback.test.js +0 -87
- package/dist/core/mcp/loopback.test.js.map +0 -1
- package/dist/core/mcp/oauth-store.test.d.ts +0 -2
- package/dist/core/mcp/oauth-store.test.d.ts.map +0 -1
- package/dist/core/mcp/oauth-store.test.js +0 -94
- package/dist/core/mcp/oauth-store.test.js.map +0 -1
- package/dist/core/mcp/parse-add-command.test.d.ts +0 -2
- package/dist/core/mcp/parse-add-command.test.d.ts.map +0 -1
- package/dist/core/mcp/parse-add-command.test.js +0 -81
- package/dist/core/mcp/parse-add-command.test.js.map +0 -1
- package/dist/core/mcp/resolve-stdio.test.d.ts +0 -2
- package/dist/core/mcp/resolve-stdio.test.d.ts.map +0 -1
- package/dist/core/mcp/resolve-stdio.test.js +0 -239
- package/dist/core/mcp/resolve-stdio.test.js.map +0 -1
- package/dist/core/mcp/session-elicitation-wiring.test.d.ts +0 -2
- package/dist/core/mcp/session-elicitation-wiring.test.d.ts.map +0 -1
- package/dist/core/mcp/session-elicitation-wiring.test.js +0 -138
- package/dist/core/mcp/session-elicitation-wiring.test.js.map +0 -1
- package/dist/core/mcp/shared-pool.test.d.ts +0 -2
- package/dist/core/mcp/shared-pool.test.d.ts.map +0 -1
- package/dist/core/mcp/shared-pool.test.js +0 -425
- package/dist/core/mcp/shared-pool.test.js.map +0 -1
- package/dist/core/mcp/store.test.d.ts +0 -2
- package/dist/core/mcp/store.test.d.ts.map +0 -1
- package/dist/core/mcp/store.test.js +0 -110
- package/dist/core/mcp/store.test.js.map +0 -1
- package/dist/core/mcp/when-connected.test.d.ts +0 -2
- package/dist/core/mcp/when-connected.test.d.ts.map +0 -1
- package/dist/core/mcp/when-connected.test.js +0 -46
- package/dist/core/mcp/when-connected.test.js.map +0 -1
- package/dist/core/message-images.test.d.ts +0 -2
- package/dist/core/message-images.test.d.ts.map +0 -1
- package/dist/core/message-images.test.js +0 -62
- package/dist/core/message-images.test.js.map +0 -1
- package/dist/core/network-guard.test.d.ts +0 -2
- package/dist/core/network-guard.test.d.ts.map +0 -1
- package/dist/core/network-guard.test.js +0 -72
- package/dist/core/network-guard.test.js.map +0 -1
- package/dist/core/persistent-shell.test.d.ts +0 -2
- package/dist/core/persistent-shell.test.d.ts.map +0 -1
- package/dist/core/persistent-shell.test.js +0 -84
- package/dist/core/persistent-shell.test.js.map +0 -1
- package/dist/core/process-gate.test.d.ts +0 -2
- package/dist/core/process-gate.test.d.ts.map +0 -1
- package/dist/core/process-gate.test.js +0 -87
- package/dist/core/process-gate.test.js.map +0 -1
- package/dist/core/process-manager-dev-server-repro.test.d.ts +0 -2
- package/dist/core/process-manager-dev-server-repro.test.d.ts.map +0 -1
- package/dist/core/process-manager-dev-server-repro.test.js +0 -225
- package/dist/core/process-manager-dev-server-repro.test.js.map +0 -1
- package/dist/core/process-manager-notifications.test.d.ts +0 -2
- package/dist/core/process-manager-notifications.test.d.ts.map +0 -1
- package/dist/core/process-manager-notifications.test.js +0 -245
- package/dist/core/process-manager-notifications.test.js.map +0 -1
- package/dist/core/process-manager-wake.test.d.ts +0 -2
- package/dist/core/process-manager-wake.test.d.ts.map +0 -1
- package/dist/core/process-manager-wake.test.js +0 -100
- package/dist/core/process-manager-wake.test.js.map +0 -1
- package/dist/core/progress/engine.test.d.ts +0 -2
- package/dist/core/progress/engine.test.d.ts.map +0 -1
- package/dist/core/progress/engine.test.js +0 -136
- package/dist/core/progress/engine.test.js.map +0 -1
- package/dist/core/progress/git-xp.test.d.ts +0 -2
- package/dist/core/progress/git-xp.test.d.ts.map +0 -1
- package/dist/core/progress/git-xp.test.js +0 -88
- package/dist/core/progress/git-xp.test.js.map +0 -1
- package/dist/core/progress/ranks.test.d.ts +0 -2
- package/dist/core/progress/ranks.test.d.ts.map +0 -1
- package/dist/core/progress/ranks.test.js +0 -100
- package/dist/core/progress/ranks.test.js.map +0 -1
- package/dist/core/progress/rebuild.test.d.ts +0 -2
- package/dist/core/progress/rebuild.test.d.ts.map +0 -1
- package/dist/core/progress/rebuild.test.js +0 -103
- package/dist/core/progress/rebuild.test.js.map +0 -1
- package/dist/core/progress/store.test.d.ts +0 -2
- package/dist/core/progress/store.test.d.ts.map +0 -1
- package/dist/core/progress/store.test.js +0 -108
- package/dist/core/progress/store.test.js.map +0 -1
- package/dist/core/project-discovery.test.d.ts +0 -2
- package/dist/core/project-discovery.test.d.ts.map +0 -1
- package/dist/core/project-discovery.test.js +0 -519
- package/dist/core/project-discovery.test.js.map +0 -1
- package/dist/core/prompt-commands.test.d.ts +0 -2
- package/dist/core/prompt-commands.test.d.ts.map +0 -1
- package/dist/core/prompt-commands.test.js +0 -180
- package/dist/core/prompt-commands.test.js.map +0 -1
- package/dist/core/provider-cache.e2e.test.d.ts +0 -2
- package/dist/core/provider-cache.e2e.test.d.ts.map +0 -1
- package/dist/core/provider-cache.e2e.test.js +0 -125
- package/dist/core/provider-cache.e2e.test.js.map +0 -1
- package/dist/core/radio.test.d.ts +0 -2
- package/dist/core/radio.test.d.ts.map +0 -1
- package/dist/core/radio.test.js +0 -117
- package/dist/core/radio.test.js.map +0 -1
- package/dist/core/regrounding.test.d.ts +0 -2
- package/dist/core/regrounding.test.d.ts.map +0 -1
- package/dist/core/regrounding.test.js +0 -38
- package/dist/core/regrounding.test.js.map +0 -1
- package/dist/core/resolve-start.test.d.ts +0 -2
- package/dist/core/resolve-start.test.d.ts.map +0 -1
- package/dist/core/resolve-start.test.js +0 -68
- package/dist/core/resolve-start.test.js.map +0 -1
- package/dist/core/run-claim.test.d.ts +0 -2
- package/dist/core/run-claim.test.d.ts.map +0 -1
- package/dist/core/run-claim.test.js +0 -107
- package/dist/core/run-claim.test.js.map +0 -1
- package/dist/core/run-journal.test.d.ts +0 -2
- package/dist/core/run-journal.test.d.ts.map +0 -1
- package/dist/core/run-journal.test.js +0 -195
- package/dist/core/run-journal.test.js.map +0 -1
- package/dist/core/run-lifecycle.test.d.ts +0 -2
- package/dist/core/run-lifecycle.test.d.ts.map +0 -1
- package/dist/core/run-lifecycle.test.js +0 -64
- package/dist/core/run-lifecycle.test.js.map +0 -1
- package/dist/core/sandbox-feedback.test.d.ts +0 -2
- package/dist/core/sandbox-feedback.test.d.ts.map +0 -1
- package/dist/core/sandbox-feedback.test.js +0 -32
- package/dist/core/sandbox-feedback.test.js.map +0 -1
- package/dist/core/sandbox.test.d.ts +0 -2
- package/dist/core/sandbox.test.d.ts.map +0 -1
- package/dist/core/sandbox.test.js +0 -221
- package/dist/core/sandbox.test.js.map +0 -1
- package/dist/core/semantic-search-benchmark.test.d.ts +0 -2
- package/dist/core/semantic-search-benchmark.test.d.ts.map +0 -1
- package/dist/core/semantic-search-benchmark.test.js +0 -89
- package/dist/core/semantic-search-benchmark.test.js.map +0 -1
- package/dist/core/session-compaction.test.d.ts +0 -2
- package/dist/core/session-compaction.test.d.ts.map +0 -1
- package/dist/core/session-compaction.test.js +0 -92
- package/dist/core/session-compaction.test.js.map +0 -1
- package/dist/core/session-export.test.d.ts +0 -2
- package/dist/core/session-export.test.d.ts.map +0 -1
- package/dist/core/session-export.test.js +0 -353
- package/dist/core/session-export.test.js.map +0 -1
- package/dist/core/session-history.test.d.ts +0 -2
- package/dist/core/session-history.test.d.ts.map +0 -1
- package/dist/core/session-history.test.js +0 -272
- package/dist/core/session-history.test.js.map +0 -1
- package/dist/core/session-injections.test.d.ts +0 -2
- package/dist/core/session-injections.test.d.ts.map +0 -1
- package/dist/core/session-injections.test.js +0 -117
- package/dist/core/session-injections.test.js.map +0 -1
- package/dist/core/session-manager.test.d.ts +0 -2
- package/dist/core/session-manager.test.d.ts.map +0 -1
- package/dist/core/session-manager.test.js +0 -571
- package/dist/core/session-manager.test.js.map +0 -1
- package/dist/core/session-notification-visibility.test.d.ts +0 -2
- package/dist/core/session-notification-visibility.test.d.ts.map +0 -1
- package/dist/core/session-notification-visibility.test.js +0 -113
- package/dist/core/session-notification-visibility.test.js.map +0 -1
- package/dist/core/session-reconstructability.test.d.ts +0 -2
- package/dist/core/session-reconstructability.test.d.ts.map +0 -1
- package/dist/core/session-reconstructability.test.js +0 -105
- package/dist/core/session-reconstructability.test.js.map +0 -1
- package/dist/core/session-restore-display.test.d.ts +0 -2
- package/dist/core/session-restore-display.test.d.ts.map +0 -1
- package/dist/core/session-restore-display.test.js +0 -103
- package/dist/core/session-restore-display.test.js.map +0 -1
- package/dist/core/session-storage-fd-leak.test.d.ts +0 -2
- package/dist/core/session-storage-fd-leak.test.d.ts.map +0 -1
- package/dist/core/session-storage-fd-leak.test.js +0 -116
- package/dist/core/session-storage-fd-leak.test.js.map +0 -1
- package/dist/core/session-storage.test.d.ts +0 -2
- package/dist/core/session-storage.test.d.ts.map +0 -1
- package/dist/core/session-storage.test.js +0 -277
- package/dist/core/session-storage.test.js.map +0 -1
- package/dist/core/setup-history.test.d.ts +0 -2
- package/dist/core/setup-history.test.d.ts.map +0 -1
- package/dist/core/setup-history.test.js +0 -59
- package/dist/core/setup-history.test.js.map +0 -1
- package/dist/core/shell.test.d.ts +0 -2
- package/dist/core/shell.test.d.ts.map +0 -1
- package/dist/core/shell.test.js +0 -87
- package/dist/core/shell.test.js.map +0 -1
- package/dist/core/shutdown.test.d.ts +0 -2
- package/dist/core/shutdown.test.d.ts.map +0 -1
- package/dist/core/shutdown.test.js +0 -160
- package/dist/core/shutdown.test.js.map +0 -1
- package/dist/core/sidecar-error-reporter.test.d.ts +0 -2
- package/dist/core/sidecar-error-reporter.test.d.ts.map +0 -1
- package/dist/core/sidecar-error-reporter.test.js +0 -61
- package/dist/core/sidecar-error-reporter.test.js.map +0 -1
- package/dist/core/skills-routing.test.d.ts +0 -2
- package/dist/core/skills-routing.test.d.ts.map +0 -1
- package/dist/core/skills-routing.test.js +0 -310
- package/dist/core/skills-routing.test.js.map +0 -1
- package/dist/core/slash-commands.test.d.ts +0 -2
- package/dist/core/slash-commands.test.d.ts.map +0 -1
- package/dist/core/slash-commands.test.js +0 -59
- package/dist/core/slash-commands.test.js.map +0 -1
- package/dist/core/source-maps.test.d.ts +0 -2
- package/dist/core/source-maps.test.d.ts.map +0 -1
- package/dist/core/source-maps.test.js +0 -175
- package/dist/core/source-maps.test.js.map +0 -1
- package/dist/core/speed-benchmark.test.d.ts +0 -2
- package/dist/core/speed-benchmark.test.d.ts.map +0 -1
- package/dist/core/speed-benchmark.test.js +0 -102
- package/dist/core/speed-benchmark.test.js.map +0 -1
- package/dist/core/subagent-manager.test.d.ts +0 -2
- package/dist/core/subagent-manager.test.d.ts.map +0 -1
- package/dist/core/subagent-manager.test.js +0 -536
- package/dist/core/subagent-manager.test.js.map +0 -1
- package/dist/core/subagent-store.test.d.ts +0 -2
- package/dist/core/subagent-store.test.d.ts.map +0 -1
- package/dist/core/subagent-store.test.js +0 -106
- package/dist/core/subagent-store.test.js.map +0 -1
- package/dist/core/subagent-turn-record.test.d.ts +0 -2
- package/dist/core/subagent-turn-record.test.d.ts.map +0 -1
- package/dist/core/subagent-turn-record.test.js +0 -70
- package/dist/core/subagent-turn-record.test.js.map +0 -1
- package/dist/core/verification-evidence.test.d.ts +0 -2
- package/dist/core/verification-evidence.test.d.ts.map +0 -1
- package/dist/core/verification-evidence.test.js +0 -103
- package/dist/core/verification-evidence.test.js.map +0 -1
- package/dist/core/verification-gate.test.d.ts +0 -2
- package/dist/core/verification-gate.test.d.ts.map +0 -1
- package/dist/core/verification-gate.test.js +0 -138
- package/dist/core/verification-gate.test.js.map +0 -1
- package/dist/core/verify-commands.test.d.ts +0 -2
- package/dist/core/verify-commands.test.d.ts.map +0 -1
- package/dist/core/verify-commands.test.js +0 -81
- package/dist/core/verify-commands.test.js.map +0 -1
- package/dist/core/workspace-guard.test.d.ts +0 -2
- package/dist/core/workspace-guard.test.d.ts.map +0 -1
- package/dist/core/workspace-guard.test.js +0 -107
- package/dist/core/workspace-guard.test.js.map +0 -1
- package/dist/hf-pull.test.d.ts +0 -2
- package/dist/hf-pull.test.d.ts.map +0 -1
- package/dist/hf-pull.test.js +0 -112
- package/dist/hf-pull.test.js.map +0 -1
- package/dist/modes/acp-mode.test.d.ts +0 -2
- package/dist/modes/acp-mode.test.d.ts.map +0 -1
- package/dist/modes/acp-mode.test.js +0 -1067
- package/dist/modes/acp-mode.test.js.map +0 -1
- package/dist/modes/json-mode.test.d.ts +0 -2
- package/dist/modes/json-mode.test.d.ts.map +0 -1
- package/dist/modes/json-mode.test.js +0 -84
- package/dist/modes/json-mode.test.js.map +0 -1
- package/dist/modes/subagent-worker-mode.test.d.ts +0 -2
- package/dist/modes/subagent-worker-mode.test.d.ts.map +0 -1
- package/dist/modes/subagent-worker-mode.test.js +0 -52
- package/dist/modes/subagent-worker-mode.test.js.map +0 -1
- package/dist/session.test.d.ts +0 -2
- package/dist/session.test.d.ts.map +0 -1
- package/dist/session.test.js +0 -35
- package/dist/session.test.js.map +0 -1
- package/dist/system-prompt.test.d.ts +0 -2
- package/dist/system-prompt.test.d.ts.map +0 -1
- package/dist/system-prompt.test.js +0 -684
- package/dist/system-prompt.test.js.map +0 -1
- package/dist/system-prompt.tiering.test.d.ts +0 -2
- package/dist/system-prompt.tiering.test.d.ts.map +0 -1
- package/dist/system-prompt.tiering.test.js +0 -112
- package/dist/system-prompt.tiering.test.js.map +0 -1
- package/dist/tools/bash.test.d.ts +0 -2
- package/dist/tools/bash.test.d.ts.map +0 -1
- package/dist/tools/bash.test.js +0 -248
- package/dist/tools/bash.test.js.map +0 -1
- package/dist/tools/checkpoint-hook.test.d.ts +0 -2
- package/dist/tools/checkpoint-hook.test.d.ts.map +0 -1
- package/dist/tools/checkpoint-hook.test.js +0 -65
- package/dist/tools/checkpoint-hook.test.js.map +0 -1
- package/dist/tools/code-nav.test.d.ts +0 -2
- package/dist/tools/code-nav.test.d.ts.map +0 -1
- package/dist/tools/code-nav.test.js +0 -136
- package/dist/tools/code-nav.test.js.map +0 -1
- package/dist/tools/code-skeleton.test.d.ts +0 -2
- package/dist/tools/code-skeleton.test.d.ts.map +0 -1
- package/dist/tools/code-skeleton.test.js +0 -115
- package/dist/tools/code-skeleton.test.js.map +0 -1
- package/dist/tools/compress-integration.test.d.ts +0 -2
- package/dist/tools/compress-integration.test.d.ts.map +0 -1
- package/dist/tools/compress-integration.test.js +0 -59
- package/dist/tools/compress-integration.test.js.map +0 -1
- package/dist/tools/compress.test.d.ts +0 -2
- package/dist/tools/compress.test.d.ts.map +0 -1
- package/dist/tools/compress.test.js +0 -60
- package/dist/tools/compress.test.js.map +0 -1
- package/dist/tools/edit-diff.test.d.ts +0 -2
- package/dist/tools/edit-diff.test.d.ts.map +0 -1
- package/dist/tools/edit-diff.test.js +0 -329
- package/dist/tools/edit-diff.test.js.map +0 -1
- package/dist/tools/edit-robustness.test.d.ts +0 -2
- package/dist/tools/edit-robustness.test.d.ts.map +0 -1
- package/dist/tools/edit-robustness.test.js +0 -417
- package/dist/tools/edit-robustness.test.js.map +0 -1
- package/dist/tools/edit.test.d.ts +0 -2
- package/dist/tools/edit.test.d.ts.map +0 -1
- package/dist/tools/edit.test.js +0 -984
- package/dist/tools/edit.test.js.map +0 -1
- package/dist/tools/exit-plan.test.d.ts +0 -2
- package/dist/tools/exit-plan.test.d.ts.map +0 -1
- package/dist/tools/exit-plan.test.js +0 -72
- package/dist/tools/exit-plan.test.js.map +0 -1
- package/dist/tools/generate-image.test.d.ts +0 -2
- package/dist/tools/generate-image.test.d.ts.map +0 -1
- package/dist/tools/generate-image.test.js +0 -240
- package/dist/tools/generate-image.test.js.map +0 -1
- package/dist/tools/grep-parity.test.d.ts +0 -2
- package/dist/tools/grep-parity.test.d.ts.map +0 -1
- package/dist/tools/grep-parity.test.js +0 -92
- package/dist/tools/grep-parity.test.js.map +0 -1
- package/dist/tools/grep-recall.test.d.ts +0 -2
- package/dist/tools/grep-recall.test.d.ts.map +0 -1
- package/dist/tools/grep-recall.test.js +0 -114
- package/dist/tools/grep-recall.test.js.map +0 -1
- package/dist/tools/grep-spawn.test.d.ts +0 -2
- package/dist/tools/grep-spawn.test.d.ts.map +0 -1
- package/dist/tools/grep-spawn.test.js +0 -66
- package/dist/tools/grep-spawn.test.js.map +0 -1
- package/dist/tools/grep.test.d.ts +0 -2
- package/dist/tools/grep.test.d.ts.map +0 -1
- package/dist/tools/grep.test.js +0 -82
- package/dist/tools/grep.test.js.map +0 -1
- package/dist/tools/html-extract.test.d.ts +0 -2
- package/dist/tools/html-extract.test.d.ts.map +0 -1
- package/dist/tools/html-extract.test.js +0 -60
- package/dist/tools/html-extract.test.js.map +0 -1
- package/dist/tools/index.test.d.ts +0 -2
- package/dist/tools/index.test.d.ts.map +0 -1
- package/dist/tools/index.test.js +0 -55
- package/dist/tools/index.test.js.map +0 -1
- package/dist/tools/overflow.test.d.ts +0 -2
- package/dist/tools/overflow.test.d.ts.map +0 -1
- package/dist/tools/overflow.test.js +0 -59
- package/dist/tools/overflow.test.js.map +0 -1
- package/dist/tools/path-utils.test.d.ts +0 -2
- package/dist/tools/path-utils.test.d.ts.map +0 -1
- package/dist/tools/path-utils.test.js +0 -110
- package/dist/tools/path-utils.test.js.map +0 -1
- package/dist/tools/pdf-extract.test.d.ts +0 -2
- package/dist/tools/pdf-extract.test.d.ts.map +0 -1
- package/dist/tools/pdf-extract.test.js +0 -15
- package/dist/tools/pdf-extract.test.js.map +0 -1
- package/dist/tools/plan-mode.test.d.ts +0 -2
- package/dist/tools/plan-mode.test.d.ts.map +0 -1
- package/dist/tools/plan-mode.test.js +0 -91
- package/dist/tools/plan-mode.test.js.map +0 -1
- package/dist/tools/read-only-bash.test.d.ts +0 -2
- package/dist/tools/read-only-bash.test.d.ts.map +0 -1
- package/dist/tools/read-only-bash.test.js +0 -96
- package/dist/tools/read-only-bash.test.js.map +0 -1
- package/dist/tools/read.test.d.ts +0 -2
- package/dist/tools/read.test.d.ts.map +0 -1
- package/dist/tools/read.test.js +0 -146
- package/dist/tools/read.test.js.map +0 -1
- package/dist/tools/screenshot.test.d.ts +0 -2
- package/dist/tools/screenshot.test.d.ts.map +0 -1
- package/dist/tools/screenshot.test.js +0 -145
- package/dist/tools/screenshot.test.js.map +0 -1
- package/dist/tools/search-code.test.d.ts +0 -2
- package/dist/tools/search-code.test.d.ts.map +0 -1
- package/dist/tools/search-code.test.js +0 -83
- package/dist/tools/search-code.test.js.map +0 -1
- package/dist/tools/source-path.test.d.ts +0 -2
- package/dist/tools/source-path.test.d.ts.map +0 -1
- package/dist/tools/source-path.test.js +0 -80
- package/dist/tools/source-path.test.js.map +0 -1
- package/dist/tools/subagent-control.test.d.ts +0 -2
- package/dist/tools/subagent-control.test.d.ts.map +0 -1
- package/dist/tools/subagent-control.test.js +0 -73
- package/dist/tools/subagent-control.test.js.map +0 -1
- package/dist/tools/subagent-shared.test.d.ts +0 -2
- package/dist/tools/subagent-shared.test.d.ts.map +0 -1
- package/dist/tools/subagent-shared.test.js +0 -83
- package/dist/tools/subagent-shared.test.js.map +0 -1
- package/dist/tools/subagent.test.d.ts +0 -2
- package/dist/tools/subagent.test.d.ts.map +0 -1
- package/dist/tools/subagent.test.js +0 -180
- package/dist/tools/subagent.test.js.map +0 -1
- package/dist/tools/task-send.test.d.ts +0 -2
- package/dist/tools/task-send.test.d.ts.map +0 -1
- package/dist/tools/task-send.test.js +0 -104
- package/dist/tools/task-send.test.js.map +0 -1
- package/dist/tools/tool-catalog.test.d.ts +0 -2
- package/dist/tools/tool-catalog.test.d.ts.map +0 -1
- package/dist/tools/tool-catalog.test.js +0 -124
- package/dist/tools/tool-catalog.test.js.map +0 -1
- package/dist/tools/tool-search.test.d.ts +0 -2
- package/dist/tools/tool-search.test.d.ts.map +0 -1
- package/dist/tools/tool-search.test.js +0 -127
- package/dist/tools/tool-search.test.js.map +0 -1
- package/dist/tools/tool-tiers.test.d.ts +0 -2
- package/dist/tools/tool-tiers.test.d.ts.map +0 -1
- package/dist/tools/tool-tiers.test.js +0 -48
- package/dist/tools/tool-tiers.test.js.map +0 -1
- package/dist/tools/truncate-utils.test.d.ts +0 -2
- package/dist/tools/truncate-utils.test.d.ts.map +0 -1
- package/dist/tools/truncate-utils.test.js +0 -93
- package/dist/tools/truncate-utils.test.js.map +0 -1
- package/dist/tools/truncate.test.d.ts +0 -2
- package/dist/tools/truncate.test.d.ts.map +0 -1
- package/dist/tools/truncate.test.js +0 -100
- package/dist/tools/truncate.test.js.map +0 -1
- package/dist/tools/web-fetch.test.d.ts +0 -2
- package/dist/tools/web-fetch.test.d.ts.map +0 -1
- package/dist/tools/web-fetch.test.js +0 -676
- package/dist/tools/web-fetch.test.js.map +0 -1
- package/dist/tools/web-search.test.d.ts +0 -2
- package/dist/tools/web-search.test.d.ts.map +0 -1
- package/dist/tools/web-search.test.js +0 -333
- package/dist/tools/web-search.test.js.map +0 -1
- package/dist/tools/write.test.d.ts +0 -2
- package/dist/tools/write.test.d.ts.map +0 -1
- package/dist/tools/write.test.js +0 -176
- package/dist/tools/write.test.js.map +0 -1
- package/dist/ui/anchor-pad-reclaim.test.d.ts +0 -2
- package/dist/ui/anchor-pad-reclaim.test.d.ts.map +0 -1
- package/dist/ui/anchor-pad-reclaim.test.js +0 -146
- package/dist/ui/anchor-pad-reclaim.test.js.map +0 -1
- package/dist/ui/app-items.test.d.ts +0 -2
- package/dist/ui/app-items.test.d.ts.map +0 -1
- package/dist/ui/app-items.test.js +0 -54
- package/dist/ui/app-items.test.js.map +0 -1
- package/dist/ui/app-state-persistence.test.d.ts +0 -2
- package/dist/ui/app-state-persistence.test.d.ts.map +0 -1
- package/dist/ui/app-state-persistence.test.js +0 -71
- package/dist/ui/app-state-persistence.test.js.map +0 -1
- package/dist/ui/assistant-stream-flush-parity.test.d.ts +0 -2
- package/dist/ui/assistant-stream-flush-parity.test.d.ts.map +0 -1
- package/dist/ui/assistant-stream-flush-parity.test.js +0 -85
- package/dist/ui/assistant-stream-flush-parity.test.js.map +0 -1
- package/dist/ui/atomic-flush-regression.test.d.ts +0 -2
- package/dist/ui/atomic-flush-regression.test.d.ts.map +0 -1
- package/dist/ui/atomic-flush-regression.test.js +0 -218
- package/dist/ui/atomic-flush-regression.test.js.map +0 -1
- package/dist/ui/chat-layout-pinning.test.d.ts +0 -2
- package/dist/ui/chat-layout-pinning.test.d.ts.map +0 -1
- package/dist/ui/chat-layout-pinning.test.js +0 -525
- package/dist/ui/chat-layout-pinning.test.js.map +0 -1
- package/dist/ui/components/ActivityIndicator.test.d.ts +0 -2
- package/dist/ui/components/ActivityIndicator.test.d.ts.map +0 -1
- package/dist/ui/components/ActivityIndicator.test.js +0 -40
- package/dist/ui/components/ActivityIndicator.test.js.map +0 -1
- package/dist/ui/components/AssistantMessage.test.d.ts +0 -2
- package/dist/ui/components/AssistantMessage.test.d.ts.map +0 -1
- package/dist/ui/components/AssistantMessage.test.js +0 -418
- package/dist/ui/components/AssistantMessage.test.js.map +0 -1
- package/dist/ui/components/Footer.test.d.ts +0 -2
- package/dist/ui/components/Footer.test.d.ts.map +0 -1
- package/dist/ui/components/Footer.test.js +0 -16
- package/dist/ui/components/Footer.test.js.map +0 -1
- package/dist/ui/components/InputArea.test.d.ts +0 -2
- package/dist/ui/components/InputArea.test.d.ts.map +0 -1
- package/dist/ui/components/InputArea.test.js +0 -95
- package/dist/ui/components/InputArea.test.js.map +0 -1
- package/dist/ui/components/PlanOverlay.test.d.ts +0 -2
- package/dist/ui/components/PlanOverlay.test.d.ts.map +0 -1
- package/dist/ui/components/PlanOverlay.test.js +0 -24
- package/dist/ui/components/PlanOverlay.test.js.map +0 -1
- package/dist/ui/components/StreamingArea.test.d.ts +0 -2
- package/dist/ui/components/StreamingArea.test.d.ts.map +0 -1
- package/dist/ui/components/StreamingArea.test.js +0 -18
- package/dist/ui/components/StreamingArea.test.js.map +0 -1
- package/dist/ui/components/UserMessage.test.d.ts +0 -2
- package/dist/ui/components/UserMessage.test.d.ts.map +0 -1
- package/dist/ui/components/UserMessage.test.js +0 -39
- package/dist/ui/components/UserMessage.test.js.map +0 -1
- package/dist/ui/components/themed-output.test.d.ts +0 -2
- package/dist/ui/components/themed-output.test.d.ts.map +0 -1
- package/dist/ui/components/themed-output.test.js +0 -111
- package/dist/ui/components/themed-output.test.js.map +0 -1
- package/dist/ui/footer-jump-regression.test.d.ts +0 -2
- package/dist/ui/footer-jump-regression.test.d.ts.map +0 -1
- package/dist/ui/footer-jump-regression.test.js +0 -224
- package/dist/ui/footer-jump-regression.test.js.map +0 -1
- package/dist/ui/footer-status-layout.test.d.ts +0 -2
- package/dist/ui/footer-status-layout.test.d.ts.map +0 -1
- package/dist/ui/footer-status-layout.test.js +0 -71
- package/dist/ui/footer-status-layout.test.js.map +0 -1
- package/dist/ui/frame-clip-regression.test.d.ts +0 -2
- package/dist/ui/frame-clip-regression.test.d.ts.map +0 -1
- package/dist/ui/frame-clip-regression.test.js +0 -215
- package/dist/ui/frame-clip-regression.test.js.map +0 -1
- package/dist/ui/hooks/stall-retry-duplicate.test.d.ts +0 -2
- package/dist/ui/hooks/stall-retry-duplicate.test.d.ts.map +0 -1
- package/dist/ui/hooks/stall-retry-duplicate.test.js +0 -94
- package/dist/ui/hooks/stall-retry-duplicate.test.js.map +0 -1
- package/dist/ui/hooks/useAgentLoop.test.d.ts +0 -2
- package/dist/ui/hooks/useAgentLoop.test.d.ts.map +0 -1
- package/dist/ui/hooks/useAgentLoop.test.js +0 -66
- package/dist/ui/hooks/useAgentLoop.test.js.map +0 -1
- package/dist/ui/hooks/useContextCompaction.test.d.ts +0 -2
- package/dist/ui/hooks/useContextCompaction.test.d.ts.map +0 -1
- package/dist/ui/hooks/useContextCompaction.test.js +0 -135
- package/dist/ui/hooks/useContextCompaction.test.js.map +0 -1
- package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.d.ts +0 -2
- package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.d.ts.map +0 -1
- package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.js +0 -81
- package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.js.map +0 -1
- package/dist/ui/hooks/useTranscriptHistory.test.d.ts +0 -2
- package/dist/ui/hooks/useTranscriptHistory.test.d.ts.map +0 -1
- package/dist/ui/hooks/useTranscriptHistory.test.js +0 -61
- package/dist/ui/hooks/useTranscriptHistory.test.js.map +0 -1
- package/dist/ui/hooks/useTranscriptScroll.test.d.ts +0 -2
- package/dist/ui/hooks/useTranscriptScroll.test.d.ts.map +0 -1
- package/dist/ui/hooks/useTranscriptScroll.test.js +0 -119
- package/dist/ui/hooks/useTranscriptScroll.test.js.map +0 -1
- package/dist/ui/live-area-clamp.test.d.ts +0 -2
- package/dist/ui/live-area-clamp.test.d.ts.map +0 -1
- package/dist/ui/live-area-clamp.test.js +0 -125
- package/dist/ui/live-area-clamp.test.js.map +0 -1
- package/dist/ui/live-area-height.test.d.ts +0 -2
- package/dist/ui/live-area-height.test.d.ts.map +0 -1
- package/dist/ui/live-area-height.test.js +0 -76
- package/dist/ui/live-area-height.test.js.map +0 -1
- package/dist/ui/live-frame-height.test.d.ts +0 -2
- package/dist/ui/live-frame-height.test.d.ts.map +0 -1
- package/dist/ui/live-frame-height.test.js +0 -116
- package/dist/ui/live-frame-height.test.js.map +0 -1
- package/dist/ui/live-item-flush.test.d.ts +0 -2
- package/dist/ui/live-item-flush.test.d.ts.map +0 -1
- package/dist/ui/live-item-flush.test.js +0 -437
- package/dist/ui/live-item-flush.test.js.map +0 -1
- package/dist/ui/long-prompt-regression-harness.test.d.ts +0 -2
- package/dist/ui/long-prompt-regression-harness.test.d.ts.map +0 -1
- package/dist/ui/long-prompt-regression-harness.test.js +0 -195
- package/dist/ui/long-prompt-regression-harness.test.js.map +0 -1
- package/dist/ui/plan-overlay.test.d.ts +0 -2
- package/dist/ui/plan-overlay.test.d.ts.map +0 -1
- package/dist/ui/plan-overlay.test.js +0 -305
- package/dist/ui/plan-overlay.test.js.map +0 -1
- package/dist/ui/queued-message.test.d.ts +0 -2
- package/dist/ui/queued-message.test.d.ts.map +0 -1
- package/dist/ui/queued-message.test.js +0 -172
- package/dist/ui/queued-message.test.js.map +0 -1
- package/dist/ui/render.test.d.ts +0 -2
- package/dist/ui/render.test.d.ts.map +0 -1
- package/dist/ui/render.test.js +0 -42
- package/dist/ui/render.test.js.map +0 -1
- package/dist/ui/scroll-stabilization.test.d.ts +0 -2
- package/dist/ui/scroll-stabilization.test.d.ts.map +0 -1
- package/dist/ui/scroll-stabilization.test.js +0 -64
- package/dist/ui/scroll-stabilization.test.js.map +0 -1
- package/dist/ui/slash-command-images.test.d.ts +0 -2
- package/dist/ui/slash-command-images.test.d.ts.map +0 -1
- package/dist/ui/slash-command-images.test.js +0 -110
- package/dist/ui/slash-command-images.test.js.map +0 -1
- package/dist/ui/startup-banner-order.test.d.ts +0 -2
- package/dist/ui/startup-banner-order.test.d.ts.map +0 -1
- package/dist/ui/startup-banner-order.test.js +0 -105
- package/dist/ui/startup-banner-order.test.js.map +0 -1
- package/dist/ui/stores/transcript-scroll-store.test.d.ts +0 -2
- package/dist/ui/stores/transcript-scroll-store.test.d.ts.map +0 -1
- package/dist/ui/stores/transcript-scroll-store.test.js +0 -73
- package/dist/ui/stores/transcript-scroll-store.test.js.map +0 -1
- package/dist/ui/streaming-flush-bounce.test.d.ts +0 -2
- package/dist/ui/streaming-flush-bounce.test.d.ts.map +0 -1
- package/dist/ui/streaming-flush-bounce.test.js +0 -177
- package/dist/ui/streaming-flush-bounce.test.js.map +0 -1
- package/dist/ui/submit-boundary-gap.test.d.ts +0 -2
- package/dist/ui/submit-boundary-gap.test.d.ts.map +0 -1
- package/dist/ui/submit-boundary-gap.test.js +0 -180
- package/dist/ui/submit-boundary-gap.test.js.map +0 -1
- package/dist/ui/terminal-history-repaint.test.d.ts +0 -2
- package/dist/ui/terminal-history-repaint.test.d.ts.map +0 -1
- package/dist/ui/terminal-history-repaint.test.js +0 -73
- package/dist/ui/terminal-history-repaint.test.js.map +0 -1
- package/dist/ui/terminal-history-retry-dedup.test.d.ts +0 -2
- package/dist/ui/terminal-history-retry-dedup.test.d.ts.map +0 -1
- package/dist/ui/terminal-history-retry-dedup.test.js +0 -61
- package/dist/ui/terminal-history-retry-dedup.test.js.map +0 -1
- package/dist/ui/terminal-history.test.d.ts +0 -2
- package/dist/ui/terminal-history.test.d.ts.map +0 -1
- package/dist/ui/terminal-history.test.js +0 -557
- package/dist/ui/terminal-history.test.js.map +0 -1
- package/dist/ui/thinking-level-cycle.test.d.ts +0 -2
- package/dist/ui/thinking-level-cycle.test.d.ts.map +0 -1
- package/dist/ui/thinking-level-cycle.test.js +0 -45
- package/dist/ui/thinking-level-cycle.test.js.map +0 -1
- package/dist/ui/tool-group-summary.test.d.ts +0 -2
- package/dist/ui/tool-group-summary.test.d.ts.map +0 -1
- package/dist/ui/tool-group-summary.test.js +0 -79
- package/dist/ui/tool-group-summary.test.js.map +0 -1
- package/dist/ui/transcript/spacing.test.d.ts +0 -2
- package/dist/ui/transcript/spacing.test.d.ts.map +0 -1
- package/dist/ui/transcript/spacing.test.js +0 -187
- package/dist/ui/transcript/spacing.test.js.map +0 -1
- package/dist/ui/transcript/transcript-lines.test.d.ts +0 -2
- package/dist/ui/transcript/transcript-lines.test.d.ts.map +0 -1
- package/dist/ui/transcript/transcript-lines.test.js +0 -76
- package/dist/ui/transcript/transcript-lines.test.js.map +0 -1
- package/dist/ui/transcript-viewport-pinning.test.d.ts +0 -2
- package/dist/ui/transcript-viewport-pinning.test.d.ts.map +0 -1
- package/dist/ui/transcript-viewport-pinning.test.js +0 -148
- package/dist/ui/transcript-viewport-pinning.test.js.map +0 -1
- package/dist/ui/tui-history-parity.test.d.ts +0 -2
- package/dist/ui/tui-history-parity.test.d.ts.map +0 -1
- package/dist/ui/tui-history-parity.test.js +0 -369
- package/dist/ui/tui-history-parity.test.js.map +0 -1
- package/dist/ui/tui-simulation.test.d.ts +0 -2
- package/dist/ui/tui-simulation.test.d.ts.map +0 -1
- package/dist/ui/tui-simulation.test.js +0 -145
- package/dist/ui/tui-simulation.test.js.map +0 -1
- package/dist/ui/tui-terminal-recorder.test.d.ts +0 -2
- package/dist/ui/tui-terminal-recorder.test.d.ts.map +0 -1
- package/dist/ui/tui-terminal-recorder.test.js +0 -134
- package/dist/ui/tui-terminal-recorder.test.js.map +0 -1
- package/dist/ui/utils/assistant-stream-split.test.d.ts +0 -2
- package/dist/ui/utils/assistant-stream-split.test.d.ts.map +0 -1
- package/dist/ui/utils/assistant-stream-split.test.js +0 -74
- package/dist/ui/utils/assistant-stream-split.test.js.map +0 -1
- package/dist/ui/utils/markdown-renderer.test.d.ts +0 -2
- package/dist/ui/utils/markdown-renderer.test.d.ts.map +0 -1
- package/dist/ui/utils/markdown-renderer.test.js +0 -63
- package/dist/ui/utils/markdown-renderer.test.js.map +0 -1
- package/dist/ui/utils/table-text.test.d.ts +0 -2
- package/dist/ui/utils/table-text.test.d.ts.map +0 -1
- package/dist/ui/utils/table-text.test.js +0 -202
- package/dist/ui/utils/table-text.test.js.map +0 -1
- package/dist/ui/utils/terminal-graphics.test.d.ts +0 -2
- package/dist/ui/utils/terminal-graphics.test.d.ts.map +0 -1
- package/dist/ui/utils/terminal-graphics.test.js +0 -100
- package/dist/ui/utils/terminal-graphics.test.js.map +0 -1
- package/dist/ui/utils/terminal-input.test.d.ts +0 -2
- package/dist/ui/utils/terminal-input.test.d.ts.map +0 -1
- package/dist/ui/utils/terminal-input.test.js +0 -15
- package/dist/ui/utils/terminal-input.test.js.map +0 -1
- package/dist/utils/git.test.d.ts +0 -2
- package/dist/utils/git.test.d.ts.map +0 -1
- package/dist/utils/git.test.js +0 -36
- package/dist/utils/git.test.js.map +0 -1
- package/dist/utils/github.test.d.ts +0 -2
- package/dist/utils/github.test.d.ts.map +0 -1
- package/dist/utils/github.test.js +0 -23
- package/dist/utils/github.test.js.map +0 -1
- package/dist/utils/http-body.test.d.ts +0 -2
- package/dist/utils/http-body.test.d.ts.map +0 -1
- package/dist/utils/http-body.test.js +0 -68
- package/dist/utils/http-body.test.js.map +0 -1
- package/dist/utils/image.test.d.ts +0 -2
- package/dist/utils/image.test.d.ts.map +0 -1
- package/dist/utils/image.test.js +0 -139
- package/dist/utils/image.test.js.map +0 -1
- package/dist/utils/plan-steps.test.d.ts +0 -2
- package/dist/utils/plan-steps.test.d.ts.map +0 -1
- package/dist/utils/plan-steps.test.js +0 -159
- package/dist/utils/plan-steps.test.js.map +0 -1
- package/dist/utils/process.test.d.ts +0 -2
- package/dist/utils/process.test.d.ts.map +0 -1
- package/dist/utils/process.test.js +0 -42
- package/dist/utils/process.test.js.map +0 -1
|
@@ -1,1072 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { shouldCompact, getCompactionReserveTokens, findRecentCutPoint, prepareMessagesForSummary, selectMessagesInBudget, classifyMessagesForSummary, findLatestPreviousSummary, buildFallbackSummary, extractSummaryText, compact, compactHistoricalToolCallArgs, extractFileOperations, splitTrackedModifiedFiles, buildModifiedFilesSection, resolveSummaryOutputTokens, HISTORICAL_TOOL_ARG_MAX_CHARS, MAX_TRACKED_MODIFIED_FILES, MIN_SUMMARY_OUTPUT_TOKENS, MAX_SUMMARY_OUTPUT_TOKENS, SUMMARY_ATTEMPT_TIMEOUT_MS, } from "./compactor.js";
|
|
3
|
-
import { remapAnchorForCompaction } from "../session-history.js";
|
|
4
|
-
import { estimateConversationTokens } from "./token-estimator.js";
|
|
5
|
-
import { MODELS, getContextWindow } from "@kenkaiiii/gg-core";
|
|
6
|
-
function makeMessage(role, content) {
|
|
7
|
-
return { role, content };
|
|
8
|
-
}
|
|
9
|
-
function makeToolCallMessage(name = "read", args = { file_path: "foo.ts" }, id = "t1") {
|
|
10
|
-
return {
|
|
11
|
-
role: "assistant",
|
|
12
|
-
content: [{ type: "tool_call", id, name, args }],
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
function makeToolResultMessage(toolCallId = "t1", content = "file contents") {
|
|
16
|
-
return {
|
|
17
|
-
role: "tool",
|
|
18
|
-
content: [{ type: "tool_result", toolCallId, content }],
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
function makeAssistantWithThinking(text, thinking) {
|
|
22
|
-
return {
|
|
23
|
-
role: "assistant",
|
|
24
|
-
content: [
|
|
25
|
-
{ type: "thinking", text: thinking, signature: "sig123" },
|
|
26
|
-
{ type: "text", text },
|
|
27
|
-
],
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
// ── shouldCompact ──────────────────────────────────────────
|
|
31
|
-
describe("shouldCompact", () => {
|
|
32
|
-
it("returns false when under threshold", () => {
|
|
33
|
-
const messages = [makeMessage("system", "sys"), makeMessage("user", "hello")];
|
|
34
|
-
expect(shouldCompact(messages, 200_000, 0.8)).toBe(false);
|
|
35
|
-
});
|
|
36
|
-
it("returns true when over threshold", () => {
|
|
37
|
-
const bigContent = "x".repeat(1000);
|
|
38
|
-
const messages = [
|
|
39
|
-
makeMessage("system", bigContent),
|
|
40
|
-
makeMessage("user", bigContent),
|
|
41
|
-
makeMessage("assistant", bigContent),
|
|
42
|
-
makeMessage("user", bigContent),
|
|
43
|
-
];
|
|
44
|
-
expect(shouldCompact(messages, 500, 0.8)).toBe(true);
|
|
45
|
-
});
|
|
46
|
-
it("uses default threshold of 0.85", () => {
|
|
47
|
-
const content = "x".repeat(400);
|
|
48
|
-
const messages = [
|
|
49
|
-
makeMessage("system", content),
|
|
50
|
-
makeMessage("user", content),
|
|
51
|
-
makeMessage("assistant", content),
|
|
52
|
-
makeMessage("user", content),
|
|
53
|
-
];
|
|
54
|
-
const estimated = estimateConversationTokens(messages);
|
|
55
|
-
// estimated ≈ 0.7 × window → under the 0.85 default boundary
|
|
56
|
-
expect(shouldCompact(messages, Math.ceil(estimated / 0.7))).toBe(false);
|
|
57
|
-
// estimated ≈ 0.9 × window → over the 0.85 default boundary
|
|
58
|
-
expect(shouldCompact(messages, Math.ceil(estimated / 0.9))).toBe(true);
|
|
59
|
-
});
|
|
60
|
-
it("handles custom threshold", () => {
|
|
61
|
-
const content = "x".repeat(200);
|
|
62
|
-
const messages = [
|
|
63
|
-
makeMessage("system", content),
|
|
64
|
-
makeMessage("user", content),
|
|
65
|
-
makeMessage("assistant", content),
|
|
66
|
-
makeMessage("user", content),
|
|
67
|
-
];
|
|
68
|
-
const estimated = estimateConversationTokens(messages);
|
|
69
|
-
expect(shouldCompact(messages, estimated * 3, 0.5)).toBe(false);
|
|
70
|
-
expect(shouldCompact(messages, estimated, 0.5)).toBe(true);
|
|
71
|
-
});
|
|
72
|
-
it("respects per-model context window for compaction threshold", () => {
|
|
73
|
-
// Each message: ~10000 chars / 3.5 ≈ 2857 tokens + 4 overhead ≈ 2861 tokens
|
|
74
|
-
// 160 pairs ≈ 160 × 2 × 2861 ≈ 916k tokens
|
|
75
|
-
const messages = [makeMessage("system", "sys")];
|
|
76
|
-
for (let i = 0; i < 160; i++) {
|
|
77
|
-
messages.push(makeMessage("user", `msg ${i} ${"x".repeat(10_000)}`));
|
|
78
|
-
messages.push(makeMessage("assistant", `response ${i}`));
|
|
79
|
-
}
|
|
80
|
-
const estimated = estimateConversationTokens(messages);
|
|
81
|
-
const opusContext = getContextWindow("claude-opus-5");
|
|
82
|
-
const kimiContext = getContextWindow("kimi-k2.7-code");
|
|
83
|
-
// Sanity: Opus has 1M, Kimi has 256k
|
|
84
|
-
expect(opusContext).toBe(1_000_000);
|
|
85
|
-
expect(kimiContext).toBe(262_144);
|
|
86
|
-
// Under Opus (1M): conversation is under 80% threshold (800k) — no compaction
|
|
87
|
-
expect(shouldCompact(messages, opusContext, 0.8)).toBe(false);
|
|
88
|
-
expect(estimated).toBeLessThan(opusContext * 0.8);
|
|
89
|
-
// Under Kimi (256k): same conversation exceeds 80% threshold (~210k) — must compact
|
|
90
|
-
expect(shouldCompact(messages, kimiContext, 0.8)).toBe(true);
|
|
91
|
-
expect(estimated).toBeGreaterThan(kimiContext * 0.8);
|
|
92
|
-
});
|
|
93
|
-
it("prefers actual API tokens over char-based estimate", () => {
|
|
94
|
-
const messages = [makeMessage("system", "sys"), makeMessage("user", "hello")];
|
|
95
|
-
// Char-based estimate is tiny, but actualTokens says we're over
|
|
96
|
-
expect(shouldCompact(messages, 200_000, 0.8, 170_000)).toBe(true);
|
|
97
|
-
// actualTokens under threshold — no compact despite same messages
|
|
98
|
-
expect(shouldCompact(messages, 200_000, 0.8, 100_000)).toBe(false);
|
|
99
|
-
});
|
|
100
|
-
it("falls back to char-based estimate when actualTokens is undefined", () => {
|
|
101
|
-
const content = "x".repeat(1000);
|
|
102
|
-
// Need >= COMPACTION_MIN_MESSAGES (4) to pass the message count guard
|
|
103
|
-
const messages = [
|
|
104
|
-
makeMessage("system", "sys"),
|
|
105
|
-
makeMessage("user", content),
|
|
106
|
-
makeMessage("assistant", content),
|
|
107
|
-
makeMessage("user", content),
|
|
108
|
-
];
|
|
109
|
-
const estimated = estimateConversationTokens(messages);
|
|
110
|
-
// Set contextWindow so estimated is just over 80%
|
|
111
|
-
const contextWindow = Math.floor(estimated / 0.85);
|
|
112
|
-
expect(shouldCompact(messages, contextWindow, 0.8)).toBe(true);
|
|
113
|
-
expect(shouldCompact(messages, contextWindow, 0.8, undefined)).toBe(true);
|
|
114
|
-
});
|
|
115
|
-
it("skips compaction with too few messages when using char-based estimate", () => {
|
|
116
|
-
const content = "x".repeat(10000);
|
|
117
|
-
const messages = [makeMessage("user", content)];
|
|
118
|
-
// Even if estimated tokens exceed threshold, too few messages → skip
|
|
119
|
-
const contextWindow = 100;
|
|
120
|
-
expect(shouldCompact(messages, contextWindow, 0.8)).toBe(false);
|
|
121
|
-
// But with explicit actualTokens, the guard is bypassed
|
|
122
|
-
expect(shouldCompact(messages, contextWindow, 0.8, 200)).toBe(true);
|
|
123
|
-
});
|
|
124
|
-
it("keeps the deprecated reserve helper source-compatible", () => {
|
|
125
|
-
expect(getCompactionReserveTokens(4_096)).toBe(16_384);
|
|
126
|
-
expect(getCompactionReserveTokens(16_384)).toBe(21_384);
|
|
127
|
-
});
|
|
128
|
-
it("does not let an output-token reserve move the percentage boundary", () => {
|
|
129
|
-
const messages = [makeMessage("user", "x")];
|
|
130
|
-
const contextWindow = 272_000;
|
|
131
|
-
const boundary = Math.ceil(contextWindow * 0.8);
|
|
132
|
-
expect(shouldCompact(messages, contextWindow, 0.8, boundary - 1, 128_000)).toBe(false);
|
|
133
|
-
expect(shouldCompact(messages, contextWindow, 0.8, boundary, 128_000)).toBe(true);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
// ── Cross-model compaction thresholds ─────────────────────
|
|
137
|
-
describe("compaction thresholds across all models", () => {
|
|
138
|
-
const messages = [makeMessage("user", "x")];
|
|
139
|
-
it.each(MODELS)("$id crosses the default boundary at exactly 85%", (model) => {
|
|
140
|
-
const contextWindow = getContextWindow(model.id, { provider: model.provider });
|
|
141
|
-
const boundary = Math.ceil(contextWindow * 0.85);
|
|
142
|
-
expect(contextWindow).toBe(model.contextWindow);
|
|
143
|
-
expect(shouldCompact(messages, contextWindow, undefined, boundary - 1)).toBe(false);
|
|
144
|
-
expect(shouldCompact(messages, contextWindow, undefined, boundary)).toBe(true);
|
|
145
|
-
});
|
|
146
|
-
it.each(MODELS)("$id honors a custom threshold", (model) => {
|
|
147
|
-
const contextWindow = getContextWindow(model.id, { provider: model.provider });
|
|
148
|
-
const customBoundary = Math.ceil(contextWindow * 0.65);
|
|
149
|
-
expect(shouldCompact(messages, contextWindow, 0.65, customBoundary - 1)).toBe(false);
|
|
150
|
-
expect(shouldCompact(messages, contextWindow, 0.65, customBoundary)).toBe(true);
|
|
151
|
-
});
|
|
152
|
-
it.each(MODELS)("$id ignores theoretical output size at the boundary", (model) => {
|
|
153
|
-
const contextWindow = getContextWindow(model.id, { provider: model.provider });
|
|
154
|
-
const boundary = Math.ceil(contextWindow * 0.8);
|
|
155
|
-
expect(shouldCompact(messages, contextWindow, 0.8, boundary - 1, model.maxOutputTokens)).toBe(false);
|
|
156
|
-
expect(shouldCompact(messages, contextWindow, 0.8, boundary, model.maxOutputTokens)).toBe(true);
|
|
157
|
-
});
|
|
158
|
-
it("unknown models fall back to a 200k context window", () => {
|
|
159
|
-
expect(getContextWindow("some-unknown-model")).toBe(200_000);
|
|
160
|
-
});
|
|
161
|
-
const openAITransportCases = [
|
|
162
|
-
{ id: "gpt-5.6-sol", publicWindow: 1_050_000, codexWindow: 272_000 },
|
|
163
|
-
{ id: "gpt-5.6-terra", publicWindow: 1_050_000, codexWindow: 272_000 },
|
|
164
|
-
{ id: "gpt-5.6-luna", publicWindow: 1_050_000, codexWindow: 272_000 },
|
|
165
|
-
{ id: "gpt-5.5", publicWindow: 1_050_000, codexWindow: 272_000 },
|
|
166
|
-
];
|
|
167
|
-
it.each(openAITransportCases)("$id uses its public API window without accountId", (testCase) => {
|
|
168
|
-
const contextWindow = getContextWindow(testCase.id, { provider: "openai" });
|
|
169
|
-
const boundary = Math.ceil(testCase.publicWindow * 0.8);
|
|
170
|
-
expect(contextWindow).toBe(testCase.publicWindow);
|
|
171
|
-
expect(shouldCompact(messages, contextWindow, 0.8, boundary - 1)).toBe(false);
|
|
172
|
-
expect(shouldCompact(messages, contextWindow, 0.8, boundary)).toBe(true);
|
|
173
|
-
});
|
|
174
|
-
it.each(openAITransportCases)("$id uses its Codex OAuth window with accountId", (testCase) => {
|
|
175
|
-
const contextWindow = getContextWindow(testCase.id, {
|
|
176
|
-
provider: "openai",
|
|
177
|
-
accountId: "chatgpt-account",
|
|
178
|
-
});
|
|
179
|
-
const boundary = Math.ceil(testCase.codexWindow * 0.8);
|
|
180
|
-
expect(contextWindow).toBe(testCase.codexWindow);
|
|
181
|
-
expect(shouldCompact(messages, contextWindow, 0.8, boundary - 1)).toBe(false);
|
|
182
|
-
expect(shouldCompact(messages, contextWindow, 0.8, boundary)).toBe(true);
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
// ── findRecentCutPoint ─────────────────────────────────────
|
|
186
|
-
describe("findRecentCutPoint", () => {
|
|
187
|
-
it("keeps all messages when total tokens are under budget", () => {
|
|
188
|
-
const messages = [
|
|
189
|
-
makeMessage("system", "sys"),
|
|
190
|
-
makeMessage("user", "hello"),
|
|
191
|
-
makeMessage("assistant", "hi"),
|
|
192
|
-
];
|
|
193
|
-
const cut = findRecentCutPoint(messages, 100_000);
|
|
194
|
-
expect(cut).toBe(1);
|
|
195
|
-
});
|
|
196
|
-
it("keeps only recent messages when total exceeds budget", () => {
|
|
197
|
-
const big = "x".repeat(400);
|
|
198
|
-
const messages = [
|
|
199
|
-
makeMessage("system", "sys"),
|
|
200
|
-
makeMessage("user", big),
|
|
201
|
-
makeMessage("assistant", big),
|
|
202
|
-
makeMessage("user", big),
|
|
203
|
-
makeMessage("assistant", big),
|
|
204
|
-
makeMessage("user", "last"),
|
|
205
|
-
];
|
|
206
|
-
const cut = findRecentCutPoint(messages, 120);
|
|
207
|
-
expect(cut).toBeGreaterThan(1);
|
|
208
|
-
expect(cut).toBeLessThan(messages.length);
|
|
209
|
-
});
|
|
210
|
-
it("never cuts at index 0 (system message)", () => {
|
|
211
|
-
const messages = [makeMessage("system", "sys"), makeMessage("user", "hi")];
|
|
212
|
-
const cut = findRecentCutPoint(messages, 100_000);
|
|
213
|
-
expect(cut).toBeGreaterThanOrEqual(1);
|
|
214
|
-
});
|
|
215
|
-
it("does not split tool_call and tool_result pairs", () => {
|
|
216
|
-
const big = "x".repeat(400);
|
|
217
|
-
const messages = [
|
|
218
|
-
makeMessage("system", "sys"),
|
|
219
|
-
makeMessage("user", big),
|
|
220
|
-
makeToolCallMessage(),
|
|
221
|
-
makeToolResultMessage(),
|
|
222
|
-
makeMessage("user", "thanks"),
|
|
223
|
-
];
|
|
224
|
-
const cut = findRecentCutPoint(messages, 50);
|
|
225
|
-
if (cut < messages.length) {
|
|
226
|
-
expect(messages[cut].role).not.toBe("tool");
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
it("handles conversation with only system message", () => {
|
|
230
|
-
const messages = [makeMessage("system", "sys")];
|
|
231
|
-
const cut = findRecentCutPoint(messages, 100);
|
|
232
|
-
expect(cut).toBe(1);
|
|
233
|
-
});
|
|
234
|
-
it("keeps at least last user→assistant exchange when budget is 0", () => {
|
|
235
|
-
const messages = [
|
|
236
|
-
makeMessage("system", "sys"),
|
|
237
|
-
makeMessage("user", "hello"),
|
|
238
|
-
makeMessage("assistant", "hi"),
|
|
239
|
-
];
|
|
240
|
-
const cut = findRecentCutPoint(messages, 0);
|
|
241
|
-
// Budget 0 means nothing fits, but the guard ensures we always keep
|
|
242
|
-
// the last user→assistant pair so compaction never produces empty recent messages.
|
|
243
|
-
expect(cut).toBe(1);
|
|
244
|
-
});
|
|
245
|
-
it("keeps only the latest atomic tool group when its result exceeds the budget", () => {
|
|
246
|
-
const messages = [
|
|
247
|
-
makeMessage("system", "sys"),
|
|
248
|
-
makeMessage("user", "one long task"),
|
|
249
|
-
makeToolCallMessage("read", { file_path: "old.ts" }, "old"),
|
|
250
|
-
makeToolResultMessage("old", "old result"),
|
|
251
|
-
makeToolCallMessage("bash", { command: "generate" }, "latest"),
|
|
252
|
-
makeToolResultMessage("latest", "x".repeat(100_000)),
|
|
253
|
-
];
|
|
254
|
-
const cut = findRecentCutPoint(messages, 8_000);
|
|
255
|
-
expect(cut).toBe(4);
|
|
256
|
-
expect(messages.slice(cut).map((message) => message.role)).toEqual(["assistant", "tool"]);
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
// ── prepareMessagesForSummary ──────────────────────────────
|
|
260
|
-
describe("prepareMessagesForSummary", () => {
|
|
261
|
-
it("strips thinking blocks from assistant messages", () => {
|
|
262
|
-
const msgs = [makeAssistantWithThinking("Hello there", "Let me think about this...")];
|
|
263
|
-
const prepared = prepareMessagesForSummary(msgs);
|
|
264
|
-
const content = prepared[0].content;
|
|
265
|
-
expect(content).toHaveLength(1);
|
|
266
|
-
expect(content[0].type).toBe("text");
|
|
267
|
-
});
|
|
268
|
-
it("converts tool results to truncated user text", () => {
|
|
269
|
-
const longContent = "x".repeat(5000);
|
|
270
|
-
const msgs = [makeToolResultMessage("t1", longContent)];
|
|
271
|
-
const prepared = prepareMessagesForSummary(msgs);
|
|
272
|
-
// Tool messages are converted to user text messages for the summarizer
|
|
273
|
-
expect(prepared[0].role).toBe("user");
|
|
274
|
-
const text = prepared[0].content;
|
|
275
|
-
expect(text.length).toBeLessThan(longContent.length);
|
|
276
|
-
expect(text).toContain("truncated");
|
|
277
|
-
});
|
|
278
|
-
it("truncates very long user messages but preserves moderately long ones", () => {
|
|
279
|
-
// Moderately long user messages (under the 8k user cap) are kept verbatim —
|
|
280
|
-
// user turns are the highest-signal content for resuming work.
|
|
281
|
-
const moderate = "x".repeat(5000);
|
|
282
|
-
const keptUnchanged = prepareMessagesForSummary([makeMessage("user", moderate)]);
|
|
283
|
-
expect(keptUnchanged[0].content).toBe(moderate);
|
|
284
|
-
// Pathologically long user messages are still capped.
|
|
285
|
-
const huge = "x".repeat(20000);
|
|
286
|
-
const truncated = prepareMessagesForSummary([makeMessage("user", huge)]);
|
|
287
|
-
expect(truncated[0].content.length).toBeLessThan(huge.length);
|
|
288
|
-
expect(truncated[0].content).toContain("truncated");
|
|
289
|
-
});
|
|
290
|
-
it("truncates long assistant text parts", () => {
|
|
291
|
-
const longText = "x".repeat(5000);
|
|
292
|
-
const msgs = [
|
|
293
|
-
{ role: "assistant", content: [{ type: "text", text: longText }] },
|
|
294
|
-
];
|
|
295
|
-
const prepared = prepareMessagesForSummary(msgs);
|
|
296
|
-
const content = prepared[0].content;
|
|
297
|
-
const textPart = content[0];
|
|
298
|
-
expect(textPart.text.length).toBeLessThan(longText.length);
|
|
299
|
-
expect(textPart.text).toContain("truncated");
|
|
300
|
-
});
|
|
301
|
-
it("does not mutate original messages", () => {
|
|
302
|
-
const longContent = "x".repeat(5000);
|
|
303
|
-
const original = makeToolResultMessage("t1", longContent);
|
|
304
|
-
const originalContent = original.content[0].content;
|
|
305
|
-
prepareMessagesForSummary([original]);
|
|
306
|
-
// Original should be unchanged
|
|
307
|
-
expect(original.content[0].content).toBe(originalContent);
|
|
308
|
-
expect(original.content[0].content.length).toBe(5000);
|
|
309
|
-
});
|
|
310
|
-
it("passes through short messages unchanged", () => {
|
|
311
|
-
const msgs = [makeMessage("user", "hello")];
|
|
312
|
-
const prepared = prepareMessagesForSummary(msgs);
|
|
313
|
-
expect(prepared[0].content).toBe("hello");
|
|
314
|
-
});
|
|
315
|
-
it("returns empty string content when all parts are thinking blocks", () => {
|
|
316
|
-
const msgs = [
|
|
317
|
-
{
|
|
318
|
-
role: "assistant",
|
|
319
|
-
content: [{ type: "thinking", text: "deep thoughts", signature: "sig" }],
|
|
320
|
-
},
|
|
321
|
-
];
|
|
322
|
-
const prepared = prepareMessagesForSummary(msgs);
|
|
323
|
-
expect(prepared[0].content).toBe("");
|
|
324
|
-
});
|
|
325
|
-
});
|
|
326
|
-
// ── selectMessagesInBudget ─────────────────────────────────
|
|
327
|
-
describe("selectMessagesInBudget", () => {
|
|
328
|
-
it("selects all messages when budget is large", () => {
|
|
329
|
-
const msgs = [makeMessage("user", "hello"), makeMessage("assistant", "hi")];
|
|
330
|
-
const selected = selectMessagesInBudget(msgs, 100_000);
|
|
331
|
-
expect(selected).toHaveLength(2);
|
|
332
|
-
});
|
|
333
|
-
it("selects no messages when budget is 0", () => {
|
|
334
|
-
const msgs = [makeMessage("user", "hello")];
|
|
335
|
-
const selected = selectMessagesInBudget(msgs, 0);
|
|
336
|
-
expect(selected).toHaveLength(0);
|
|
337
|
-
});
|
|
338
|
-
it("stops when budget is exceeded", () => {
|
|
339
|
-
const big = "x".repeat(2000); // ~500 tokens each + overhead
|
|
340
|
-
const msgs = [
|
|
341
|
-
makeMessage("user", big),
|
|
342
|
-
makeMessage("assistant", big),
|
|
343
|
-
makeMessage("user", big),
|
|
344
|
-
makeMessage("assistant", big),
|
|
345
|
-
];
|
|
346
|
-
const selected = selectMessagesInBudget(msgs, 600);
|
|
347
|
-
expect(selected.length).toBeGreaterThan(0);
|
|
348
|
-
expect(selected.length).toBeLessThan(msgs.length);
|
|
349
|
-
});
|
|
350
|
-
it("pins the earliest request and fills the remaining budget from newest messages", () => {
|
|
351
|
-
const msgs = [
|
|
352
|
-
makeMessage("user", `first ${"a".repeat(2_000)}`),
|
|
353
|
-
makeMessage("assistant", `old ${"b".repeat(2_000)}`),
|
|
354
|
-
makeMessage("user", `latest ${"c".repeat(2_000)}`),
|
|
355
|
-
];
|
|
356
|
-
const budget = estimateConversationTokens([msgs[0], msgs[2]]);
|
|
357
|
-
const selected = selectMessagesInBudget(msgs, budget);
|
|
358
|
-
expect(selected).toEqual([msgs[0], msgs[2]]);
|
|
359
|
-
});
|
|
360
|
-
});
|
|
361
|
-
describe("summary provenance classification", () => {
|
|
362
|
-
it("anchors the latest previous summary and excludes low-value runtime controls", () => {
|
|
363
|
-
const previous = {
|
|
364
|
-
role: "user",
|
|
365
|
-
content: "[Previous conversation summary]\n\nold memory",
|
|
366
|
-
provenance: {
|
|
367
|
-
source: "runtime",
|
|
368
|
-
kind: "compaction_summary",
|
|
369
|
-
visibility: "summary",
|
|
370
|
-
},
|
|
371
|
-
};
|
|
372
|
-
const messages = [
|
|
373
|
-
previous,
|
|
374
|
-
{
|
|
375
|
-
role: "user",
|
|
376
|
-
content: "keep this correction",
|
|
377
|
-
provenance: { source: "human", kind: "steering", visibility: "transcript" },
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
role: "user",
|
|
381
|
-
content: "continue",
|
|
382
|
-
provenance: { source: "runtime", kind: "continuation", visibility: "hidden" },
|
|
383
|
-
},
|
|
384
|
-
{
|
|
385
|
-
role: "user",
|
|
386
|
-
content: "model changed",
|
|
387
|
-
provenance: { source: "runtime", kind: "model_switch", visibility: "hidden" },
|
|
388
|
-
},
|
|
389
|
-
];
|
|
390
|
-
expect(findLatestPreviousSummary(messages)).toEqual({ index: 0, text: "old memory" });
|
|
391
|
-
const classified = classifyMessagesForSummary(messages);
|
|
392
|
-
expect(classified.map((message) => message.content)).toEqual([
|
|
393
|
-
"[Human steering]\nkeep this correction",
|
|
394
|
-
"[Runtime fact: model_switch]\nmodel changed",
|
|
395
|
-
]);
|
|
396
|
-
});
|
|
397
|
-
});
|
|
398
|
-
// ── buildFallbackSummary ───────────────────────────────────
|
|
399
|
-
describe("buildFallbackSummary", () => {
|
|
400
|
-
it("includes goal from first user message", () => {
|
|
401
|
-
const msgs = [
|
|
402
|
-
makeMessage("user", "Fix the login bug"),
|
|
403
|
-
makeMessage("assistant", "I'll look into it"),
|
|
404
|
-
];
|
|
405
|
-
const summary = buildFallbackSummary(msgs, { read: new Set(), modified: new Set() });
|
|
406
|
-
expect(summary).toContain("Fix the login bug");
|
|
407
|
-
expect(summary).toContain("## Goal");
|
|
408
|
-
});
|
|
409
|
-
it("includes message and tool call counts", () => {
|
|
410
|
-
const msgs = [
|
|
411
|
-
makeMessage("user", "Fix it"),
|
|
412
|
-
makeToolCallMessage(),
|
|
413
|
-
makeToolResultMessage(),
|
|
414
|
-
makeMessage("assistant", "Done"),
|
|
415
|
-
];
|
|
416
|
-
const summary = buildFallbackSummary(msgs, { read: new Set(), modified: new Set() });
|
|
417
|
-
expect(summary).toContain("## Progress");
|
|
418
|
-
expect(summary).toContain("4 messages exchanged");
|
|
419
|
-
expect(summary).toContain("1 tool calls executed");
|
|
420
|
-
});
|
|
421
|
-
it("includes read files", () => {
|
|
422
|
-
const fileOps = {
|
|
423
|
-
read: new Set(["src/foo.ts", "src/bar.ts"]),
|
|
424
|
-
modified: new Set(),
|
|
425
|
-
};
|
|
426
|
-
const summary = buildFallbackSummary([makeMessage("user", "Check files")], fileOps);
|
|
427
|
-
expect(summary).toContain("## Files Read");
|
|
428
|
-
expect(summary).toContain("src/foo.ts");
|
|
429
|
-
expect(summary).toContain("src/bar.ts");
|
|
430
|
-
});
|
|
431
|
-
it("includes modified files", () => {
|
|
432
|
-
const fileOps = {
|
|
433
|
-
read: new Set(),
|
|
434
|
-
modified: new Set(["src/main.ts"]),
|
|
435
|
-
};
|
|
436
|
-
const summary = buildFallbackSummary([makeMessage("user", "Edit main")], fileOps);
|
|
437
|
-
expect(summary).toContain("## Files Modified");
|
|
438
|
-
expect(summary).toContain("src/main.ts");
|
|
439
|
-
});
|
|
440
|
-
it("handles no user messages gracefully", () => {
|
|
441
|
-
const summary = buildFallbackSummary([makeMessage("assistant", "Something")], {
|
|
442
|
-
read: new Set(),
|
|
443
|
-
modified: new Set(),
|
|
444
|
-
});
|
|
445
|
-
expect(summary).toContain("could not determine");
|
|
446
|
-
});
|
|
447
|
-
it("truncates very long first user message", () => {
|
|
448
|
-
const longMsg = "x".repeat(1000);
|
|
449
|
-
const summary = buildFallbackSummary([makeMessage("user", longMsg)], {
|
|
450
|
-
read: new Set(),
|
|
451
|
-
modified: new Set(),
|
|
452
|
-
});
|
|
453
|
-
expect(summary.length).toBeLessThan(longMsg.length);
|
|
454
|
-
});
|
|
455
|
-
});
|
|
456
|
-
// ── extractSummaryText ─────────────────────────────────────
|
|
457
|
-
describe("extractSummaryText", () => {
|
|
458
|
-
it("returns string content directly", () => {
|
|
459
|
-
expect(extractSummaryText("Hello summary")).toBe("Hello summary");
|
|
460
|
-
});
|
|
461
|
-
it("extracts text from ContentPart array", () => {
|
|
462
|
-
const parts = [
|
|
463
|
-
{ type: "text", text: "Part one. " },
|
|
464
|
-
{ type: "text", text: "Part two." },
|
|
465
|
-
];
|
|
466
|
-
expect(extractSummaryText(parts)).toBe("Part one. Part two.");
|
|
467
|
-
});
|
|
468
|
-
it("filters out non-text parts", () => {
|
|
469
|
-
const parts = [
|
|
470
|
-
{ type: "thinking", text: "hmm", signature: "sig" },
|
|
471
|
-
{ type: "text", text: "The summary." },
|
|
472
|
-
];
|
|
473
|
-
expect(extractSummaryText(parts)).toBe("The summary.");
|
|
474
|
-
});
|
|
475
|
-
it("returns empty string for empty array", () => {
|
|
476
|
-
expect(extractSummaryText([])).toBe("");
|
|
477
|
-
});
|
|
478
|
-
it("returns empty string for array with only thinking parts", () => {
|
|
479
|
-
const parts = [{ type: "thinking", text: "hmm", signature: "sig" }];
|
|
480
|
-
expect(extractSummaryText(parts)).toBe("");
|
|
481
|
-
});
|
|
482
|
-
});
|
|
483
|
-
// ── historical tool-call compaction ───────────────────────
|
|
484
|
-
describe("compactHistoricalToolCallArgs", () => {
|
|
485
|
-
it("caps large string arguments without mutating the session history", () => {
|
|
486
|
-
const largeContent = "x".repeat(HISTORICAL_TOOL_ARG_MAX_CHARS * 4);
|
|
487
|
-
const original = makeToolCallMessage("write", { file_path: "large.ts", content: largeContent });
|
|
488
|
-
const [compacted] = compactHistoricalToolCallArgs([original]);
|
|
489
|
-
const compactedCall = compacted.content[0];
|
|
490
|
-
const originalCall = original.content[0];
|
|
491
|
-
expect(compactedCall.args.file_path).toBe("large.ts");
|
|
492
|
-
expect(compactedCall.args.content.length).toBeLessThan(largeContent.length);
|
|
493
|
-
expect(compactedCall.args.content).toContain("more characters truncated");
|
|
494
|
-
expect(originalCall.args.content).toBe(largeContent);
|
|
495
|
-
});
|
|
496
|
-
it("caps large strings nested inside edit arrays", () => {
|
|
497
|
-
const largeEdit = "x".repeat(HISTORICAL_TOOL_ARG_MAX_CHARS * 4);
|
|
498
|
-
const original = makeToolCallMessage("edit", {
|
|
499
|
-
file_path: "large.ts",
|
|
500
|
-
edits: [{ old_text: "before", new_text: largeEdit }],
|
|
501
|
-
});
|
|
502
|
-
const [compacted] = compactHistoricalToolCallArgs([original]);
|
|
503
|
-
const compactedCall = compacted.content[0];
|
|
504
|
-
expect(compactedCall.args.edits[0].old_text).toBe("before");
|
|
505
|
-
expect(compactedCall.args.edits[0].new_text.length).toBeLessThan(largeEdit.length);
|
|
506
|
-
expect(compactedCall.args.edits[0].new_text).toContain("more characters truncated");
|
|
507
|
-
});
|
|
508
|
-
});
|
|
509
|
-
// ── compact (integration) ──────────────────────────────────
|
|
510
|
-
vi.mock("@kenkaiiii/gg-ai", async (importOriginal) => {
|
|
511
|
-
const actual = await importOriginal();
|
|
512
|
-
return {
|
|
513
|
-
...actual,
|
|
514
|
-
stream: vi.fn(),
|
|
515
|
-
};
|
|
516
|
-
});
|
|
517
|
-
// Must import stream AFTER mock setup
|
|
518
|
-
import { stream } from "@kenkaiiii/gg-ai";
|
|
519
|
-
describe("compact", () => {
|
|
520
|
-
const baseOptions = {
|
|
521
|
-
provider: "anthropic",
|
|
522
|
-
model: "claude-sonnet-5",
|
|
523
|
-
apiKey: "test-key",
|
|
524
|
-
contextWindow: 200_000,
|
|
525
|
-
};
|
|
526
|
-
// Each user message: ~20 + 10000 chars ≈ 2504 tokens + 4 overhead ≈ 2508 tokens
|
|
527
|
-
// Each assistant: ~12 chars ≈ 7 tokens
|
|
528
|
-
// 30 pairs ≈ 30 × 2515 ≈ 75K tokens total (well over the 8K recent budget)
|
|
529
|
-
function buildConversation(middleCount) {
|
|
530
|
-
const msgs = [makeMessage("system", "You are a helpful assistant.")];
|
|
531
|
-
for (let i = 0; i < middleCount; i++) {
|
|
532
|
-
const big = `Message content ${i} ${"x".repeat(10_000)}`;
|
|
533
|
-
msgs.push(makeMessage("user", big));
|
|
534
|
-
msgs.push(makeMessage("assistant", `Response ${i}`));
|
|
535
|
-
}
|
|
536
|
-
// Add a recent small message
|
|
537
|
-
msgs.push(makeMessage("user", "latest question"));
|
|
538
|
-
return msgs;
|
|
539
|
-
}
|
|
540
|
-
/** Build a mock StreamResult-like object that resolves to the given response. */
|
|
541
|
-
function mockStreamResult(response) {
|
|
542
|
-
// Suppress unhandled rejection for error mocks
|
|
543
|
-
response.catch(() => { });
|
|
544
|
-
return {
|
|
545
|
-
response,
|
|
546
|
-
events: {
|
|
547
|
-
[Symbol.asyncIterator]: () => ({
|
|
548
|
-
next: () => Promise.resolve({ done: true, value: undefined }),
|
|
549
|
-
}),
|
|
550
|
-
},
|
|
551
|
-
[Symbol.asyncIterator]() {
|
|
552
|
-
return {
|
|
553
|
-
next: () => Promise.resolve({ done: true, value: undefined }),
|
|
554
|
-
};
|
|
555
|
-
},
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
it("skips compaction when too few middle messages", async () => {
|
|
559
|
-
const messages = [
|
|
560
|
-
makeMessage("system", "sys"),
|
|
561
|
-
makeMessage("user", "hi"),
|
|
562
|
-
makeMessage("assistant", "hello"),
|
|
563
|
-
];
|
|
564
|
-
const result = await compact(messages, baseOptions);
|
|
565
|
-
expect(result.result.compacted).toBe(false);
|
|
566
|
-
expect(result.result.reason).toBe("too_few_messages");
|
|
567
|
-
expect(result.result.originalCount).toBe(3);
|
|
568
|
-
expect(result.result.newCount).toBe(3);
|
|
569
|
-
expect(result.messages).toHaveLength(3);
|
|
570
|
-
});
|
|
571
|
-
it("produces summary message with LLM response", async () => {
|
|
572
|
-
const mockStream = vi.mocked(stream);
|
|
573
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.resolve({
|
|
574
|
-
message: { role: "assistant", content: "This is a great summary of the conversation." },
|
|
575
|
-
stopReason: "end_turn",
|
|
576
|
-
usage: { inputTokens: 1000, outputTokens: 200 },
|
|
577
|
-
})));
|
|
578
|
-
const messages = buildConversation(30);
|
|
579
|
-
const result = await compact(messages, baseOptions);
|
|
580
|
-
// Should have: system + summary + assistant ack + recent messages
|
|
581
|
-
expect(result.result.compacted).toBe(true);
|
|
582
|
-
expect(result.messages.length).toBeLessThan(messages.length);
|
|
583
|
-
expect(result.result.originalCount).toBe(messages.length);
|
|
584
|
-
// The summary message should contain the LLM's summary
|
|
585
|
-
const summaryMsg = result.messages[1];
|
|
586
|
-
expect(summaryMsg.role).toBe("user");
|
|
587
|
-
expect(summaryMsg.content).toContain("[Previous conversation summary]");
|
|
588
|
-
expect(summaryMsg.content).toContain("great summary");
|
|
589
|
-
expect(result.result.reductionStatus).toBe("material");
|
|
590
|
-
expect(result.result.summarizedCount).toBeGreaterThan(0);
|
|
591
|
-
expect(result.result.retainedCount).toBeGreaterThanOrEqual(0);
|
|
592
|
-
expect(result.result.tokensAfterEstimate).toBeLessThan(result.result.targetTokens);
|
|
593
|
-
});
|
|
594
|
-
it("feeds query-relevant older evidence to the summarizer when its prompt budget is constrained", async () => {
|
|
595
|
-
const mockStream = vi.mocked(stream);
|
|
596
|
-
mockStream.mockImplementation((request) => {
|
|
597
|
-
const requestText = request.messages
|
|
598
|
-
.map((message) => typeof message.content === "string" ? message.content : JSON.stringify(message.content))
|
|
599
|
-
.join("\n");
|
|
600
|
-
expect(requestText).toContain("OLD_EVIDENCE_MARKER");
|
|
601
|
-
return mockStreamResult(Promise.resolve({
|
|
602
|
-
message: { role: "assistant", content: "Relevant summary." },
|
|
603
|
-
stopReason: "end_turn",
|
|
604
|
-
usage: { inputTokens: 1000, outputTokens: 50 },
|
|
605
|
-
}));
|
|
606
|
-
});
|
|
607
|
-
const messages = [makeMessage("system", "sys")];
|
|
608
|
-
messages.push(makeMessage("user", `Original account task ${"a".repeat(10_000)}`));
|
|
609
|
-
for (let index = 0; index < 100; index++) {
|
|
610
|
-
const detail = index === 5
|
|
611
|
-
? "OAuth verifier mismatch root cause OLD_EVIDENCE_MARKER"
|
|
612
|
-
: `Unrelated dashboard detail ${index}`;
|
|
613
|
-
messages.push(makeMessage("user", `${detail} ${"x".repeat(10_000)}`));
|
|
614
|
-
messages.push(makeMessage("assistant", `Handled detail ${index}`));
|
|
615
|
-
}
|
|
616
|
-
messages.push(makeMessage("user", "Fix the OAuth verifier mismatch."));
|
|
617
|
-
const result = await compact(messages, baseOptions);
|
|
618
|
-
expect(mockStream).toHaveBeenCalled();
|
|
619
|
-
expect(result.result.contextSelection).toMatchObject({
|
|
620
|
-
strategy: "query_aware",
|
|
621
|
-
queryTerms: expect.any(Number),
|
|
622
|
-
selectedTokens: expect.any(Number),
|
|
623
|
-
droppedMessages: expect.any(Number),
|
|
624
|
-
});
|
|
625
|
-
});
|
|
626
|
-
it("updates an anchored prior summary and preserves the approved plan reference", async () => {
|
|
627
|
-
const mockStream = vi.mocked(stream);
|
|
628
|
-
mockStream.mockImplementation((request) => {
|
|
629
|
-
const requestMessages = request.messages;
|
|
630
|
-
expect(requestMessages[0].content).toContain("/tmp/approved-plan.md");
|
|
631
|
-
expect(requestMessages[0].content).toContain("Update the anchored <previous-summary>");
|
|
632
|
-
expect(requestMessages[1].content).toContain("<previous-summary>\nold durable memory");
|
|
633
|
-
expect(requestMessages[1].content).toContain("</previous-summary>");
|
|
634
|
-
expect(requestMessages.filter((message) => typeof message.content === "string" && message.content.includes("old durable memory"))).toHaveLength(1);
|
|
635
|
-
return mockStreamResult(Promise.resolve({
|
|
636
|
-
message: { role: "assistant", content: "Updated summary." },
|
|
637
|
-
stopReason: "end_turn",
|
|
638
|
-
usage: { inputTokens: 1000, outputTokens: 50 },
|
|
639
|
-
}));
|
|
640
|
-
});
|
|
641
|
-
const messages = buildConversation(30);
|
|
642
|
-
messages.splice(1, 0, {
|
|
643
|
-
role: "user",
|
|
644
|
-
content: "[Previous conversation summary]\n\nold durable memory",
|
|
645
|
-
provenance: { source: "runtime", kind: "compaction_summary", visibility: "summary" },
|
|
646
|
-
});
|
|
647
|
-
const result = await compact(messages, {
|
|
648
|
-
...baseOptions,
|
|
649
|
-
approvedPlanPath: "/tmp/approved-plan.md",
|
|
650
|
-
});
|
|
651
|
-
expect(result.result.compacted).toBe(true);
|
|
652
|
-
});
|
|
653
|
-
it("rejects a rewrite that cannot land below the configured target", async () => {
|
|
654
|
-
const mockStream = vi.mocked(stream);
|
|
655
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.resolve({
|
|
656
|
-
message: { role: "assistant", content: "Summary." },
|
|
657
|
-
stopReason: "end_turn",
|
|
658
|
-
usage: { inputTokens: 1000, outputTokens: 50 },
|
|
659
|
-
})));
|
|
660
|
-
const messages = buildConversation(30);
|
|
661
|
-
const result = await compact(messages, { ...baseOptions, targetTokens: 1 });
|
|
662
|
-
expect(result.result.compacted).toBe(false);
|
|
663
|
-
expect(result.result.reason).toBe("above_target");
|
|
664
|
-
expect(result.result.reductionStatus).toBe("above_target");
|
|
665
|
-
expect(result.messages).toEqual(messages);
|
|
666
|
-
});
|
|
667
|
-
it("caps the preserved recent tail at ~8K tokens", async () => {
|
|
668
|
-
const mockStream = vi.mocked(stream);
|
|
669
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.resolve({
|
|
670
|
-
message: { role: "assistant", content: "Summary." },
|
|
671
|
-
stopReason: "end_turn",
|
|
672
|
-
usage: { inputTokens: 1000, outputTokens: 50 },
|
|
673
|
-
})));
|
|
674
|
-
const messages = buildConversation(30);
|
|
675
|
-
const result = await compact(messages, baseOptions);
|
|
676
|
-
expect(result.result.compacted).toBe(true);
|
|
677
|
-
// Recent tail = everything after system + summary + assistant ack.
|
|
678
|
-
const tail = result.messages.slice(3);
|
|
679
|
-
const tailTokens = estimateConversationTokens(tail);
|
|
680
|
-
// Budget is 8K; one ≈2.5K-token conversation pair of slack covers the
|
|
681
|
-
// never-split-a-pair / always-keep-last-user-exchange guards.
|
|
682
|
-
expect(tailTokens).toBeLessThanOrEqual(8_000 + 3_000);
|
|
683
|
-
});
|
|
684
|
-
it("uses fallback summary when LLM returns empty", async () => {
|
|
685
|
-
const mockStream = vi.mocked(stream);
|
|
686
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.resolve({
|
|
687
|
-
message: { role: "assistant", content: "" },
|
|
688
|
-
stopReason: "end_turn",
|
|
689
|
-
usage: { inputTokens: 1000, outputTokens: 0 },
|
|
690
|
-
})));
|
|
691
|
-
const messages = buildConversation(30);
|
|
692
|
-
const result = await compact(messages, baseOptions);
|
|
693
|
-
const summaryMsg = result.messages[1];
|
|
694
|
-
expect(summaryMsg.role).toBe("user");
|
|
695
|
-
expect(summaryMsg.content).toContain("[Previous conversation summary]");
|
|
696
|
-
expect(summaryMsg.content).toContain("## Goal");
|
|
697
|
-
expect(summaryMsg.content).toContain("## Progress");
|
|
698
|
-
});
|
|
699
|
-
it("preserves previous compacted memory in the fallback summary", async () => {
|
|
700
|
-
const mockStream = vi.mocked(stream);
|
|
701
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.resolve({
|
|
702
|
-
message: { role: "assistant", content: "" },
|
|
703
|
-
stopReason: "end_turn",
|
|
704
|
-
usage: { inputTokens: 1000, outputTokens: 0 },
|
|
705
|
-
})));
|
|
706
|
-
const messages = buildConversation(30);
|
|
707
|
-
messages[1] = {
|
|
708
|
-
role: "user",
|
|
709
|
-
content: "[Previous conversation summary]\n\nCritical earlier decision: retain durable lineage.",
|
|
710
|
-
provenance: { source: "runtime", kind: "compaction_summary", visibility: "summary" },
|
|
711
|
-
};
|
|
712
|
-
const result = await compact(messages, baseOptions);
|
|
713
|
-
expect(result.messages[1]?.content).toContain("Critical earlier decision: retain durable lineage.");
|
|
714
|
-
expect(result.messages[1]?.content).toContain("## Update since the previous summary");
|
|
715
|
-
});
|
|
716
|
-
it("uses fallback summary when LLM throws error", async () => {
|
|
717
|
-
const mockStream = vi.mocked(stream);
|
|
718
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.reject(new Error("API error"))));
|
|
719
|
-
const messages = buildConversation(30);
|
|
720
|
-
const result = await compact(messages, baseOptions);
|
|
721
|
-
const summaryMsg = result.messages[1];
|
|
722
|
-
expect(summaryMsg.content).toContain("## Goal");
|
|
723
|
-
});
|
|
724
|
-
it("preserves system message", async () => {
|
|
725
|
-
const mockStream = vi.mocked(stream);
|
|
726
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.resolve({
|
|
727
|
-
message: { role: "assistant", content: "Summary text here." },
|
|
728
|
-
stopReason: "end_turn",
|
|
729
|
-
usage: { inputTokens: 500, outputTokens: 100 },
|
|
730
|
-
})));
|
|
731
|
-
const messages = buildConversation(30);
|
|
732
|
-
const result = await compact(messages, baseOptions);
|
|
733
|
-
expect(result.messages[0].role).toBe("system");
|
|
734
|
-
expect(result.messages[0].content).toBe("You are a helpful assistant.");
|
|
735
|
-
});
|
|
736
|
-
it("does not end with an assistant message", async () => {
|
|
737
|
-
const mockStream = vi.mocked(stream);
|
|
738
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.resolve({
|
|
739
|
-
message: { role: "assistant", content: "Summary." },
|
|
740
|
-
stopReason: "end_turn",
|
|
741
|
-
usage: { inputTokens: 500, outputTokens: 50 },
|
|
742
|
-
})));
|
|
743
|
-
const messages = buildConversation(30);
|
|
744
|
-
const result = await compact(messages, baseOptions);
|
|
745
|
-
const lastMsg = result.messages[result.messages.length - 1];
|
|
746
|
-
expect(lastMsg.role).not.toBe("assistant");
|
|
747
|
-
});
|
|
748
|
-
it("uses fallback summary when summary response wait times out", async () => {
|
|
749
|
-
vi.useFakeTimers();
|
|
750
|
-
try {
|
|
751
|
-
const mockStream = vi.mocked(stream);
|
|
752
|
-
mockStream.mockClear();
|
|
753
|
-
mockStream.mockReturnValue(mockStreamResult(new Promise(() => { })));
|
|
754
|
-
const messages = buildConversation(30);
|
|
755
|
-
const promise = compact(messages, baseOptions);
|
|
756
|
-
await vi.advanceTimersByTimeAsync(SUMMARY_ATTEMPT_TIMEOUT_MS + 1);
|
|
757
|
-
const result = await promise;
|
|
758
|
-
expect(mockStream).toHaveBeenCalledTimes(1);
|
|
759
|
-
const summaryMsg = result.messages[1];
|
|
760
|
-
expect(summaryMsg.role).toBe("user");
|
|
761
|
-
expect(summaryMsg.content).toContain("## Goal");
|
|
762
|
-
}
|
|
763
|
-
finally {
|
|
764
|
-
vi.useRealTimers();
|
|
765
|
-
}
|
|
766
|
-
});
|
|
767
|
-
it("keeps waiting past the deadline while the stream is actively emitting events", async () => {
|
|
768
|
-
// Regression: the 30s deadline used to be a HARD total cap, killing every
|
|
769
|
-
// large summary mid-generation (they stream for well over 30s) and forcing
|
|
770
|
-
// the extractive fallback. It is now an INACTIVITY deadline — each stream
|
|
771
|
-
// event re-arms it — so a response that takes 2.5× the timeout but never
|
|
772
|
-
// goes silent longer than the window must produce the REAL summary.
|
|
773
|
-
vi.useFakeTimers();
|
|
774
|
-
try {
|
|
775
|
-
const mockStream = vi.mocked(stream);
|
|
776
|
-
mockStream.mockClear();
|
|
777
|
-
const eventGap = SUMMARY_ATTEMPT_TIMEOUT_MS * 0.66; // each gap < timeout
|
|
778
|
-
const totalDuration = SUMMARY_ATTEMPT_TIMEOUT_MS * 2.5; // total ≫ timeout
|
|
779
|
-
const response = new Promise((resolve) => {
|
|
780
|
-
setTimeout(() => resolve({
|
|
781
|
-
message: { role: "assistant", content: "Real streamed summary." },
|
|
782
|
-
stopReason: "end_turn",
|
|
783
|
-
usage: { inputTokens: 1000, outputTokens: 200 },
|
|
784
|
-
}), totalDuration);
|
|
785
|
-
});
|
|
786
|
-
let emitted = 0;
|
|
787
|
-
const iterator = () => ({
|
|
788
|
-
next: () => new Promise((resolve) => {
|
|
789
|
-
if (emitted >= 3) {
|
|
790
|
-
resolve({ done: true, value: undefined });
|
|
791
|
-
return;
|
|
792
|
-
}
|
|
793
|
-
emitted++;
|
|
794
|
-
setTimeout(() => resolve({ done: false, value: { type: "text_delta" } }), eventGap);
|
|
795
|
-
}),
|
|
796
|
-
});
|
|
797
|
-
mockStream.mockReturnValue({
|
|
798
|
-
response,
|
|
799
|
-
events: { [Symbol.asyncIterator]: iterator },
|
|
800
|
-
[Symbol.asyncIterator]: iterator,
|
|
801
|
-
});
|
|
802
|
-
const messages = buildConversation(30);
|
|
803
|
-
const promise = compact(messages, baseOptions);
|
|
804
|
-
await vi.advanceTimersByTimeAsync(totalDuration + 1);
|
|
805
|
-
const result = await promise;
|
|
806
|
-
const summaryMsg = result.messages[1];
|
|
807
|
-
expect(summaryMsg.role).toBe("user");
|
|
808
|
-
expect(summaryMsg.content).toContain("Real streamed summary.");
|
|
809
|
-
expect(summaryMsg.content).not.toContain("## Goal");
|
|
810
|
-
}
|
|
811
|
-
finally {
|
|
812
|
-
vi.useRealTimers();
|
|
813
|
-
}
|
|
814
|
-
});
|
|
815
|
-
it("passes AbortSignal to summary stream and rejects without compacting on abort", async () => {
|
|
816
|
-
const mockStream = vi.mocked(stream);
|
|
817
|
-
const ac = new AbortController();
|
|
818
|
-
mockStream.mockImplementation(({ signal }) => {
|
|
819
|
-
expect(signal).toBeInstanceOf(AbortSignal);
|
|
820
|
-
expect(signal).not.toBe(ac.signal);
|
|
821
|
-
return mockStreamResult(new Promise((_, reject) => {
|
|
822
|
-
signal?.addEventListener("abort", () => reject(new DOMException("Aborted", "AbortError")), { once: true });
|
|
823
|
-
}));
|
|
824
|
-
});
|
|
825
|
-
const messages = buildConversation(30);
|
|
826
|
-
const promise = compact(messages, { ...baseOptions, signal: ac.signal });
|
|
827
|
-
ac.abort();
|
|
828
|
-
await expect(promise).rejects.toMatchObject({ name: "AbortError" });
|
|
829
|
-
expect(messages[0]).toEqual(makeMessage("system", "You are a helpful assistant."));
|
|
830
|
-
expect(messages).toHaveLength(62);
|
|
831
|
-
});
|
|
832
|
-
it("retries on empty response before falling back", async () => {
|
|
833
|
-
const mockStream = vi.mocked(stream);
|
|
834
|
-
let callCount = 0;
|
|
835
|
-
mockStream.mockImplementation(() => {
|
|
836
|
-
callCount++;
|
|
837
|
-
const content = callCount <= 2 ? "" : "Summary on third try.";
|
|
838
|
-
return mockStreamResult(Promise.resolve({
|
|
839
|
-
message: { role: "assistant", content },
|
|
840
|
-
stopReason: "end_turn",
|
|
841
|
-
usage: { inputTokens: 500, outputTokens: callCount <= 2 ? 0 : 100 },
|
|
842
|
-
}));
|
|
843
|
-
});
|
|
844
|
-
const messages = buildConversation(30);
|
|
845
|
-
const result = await compact(messages, baseOptions);
|
|
846
|
-
// Should have retried and gotten the summary on the 3rd attempt
|
|
847
|
-
expect(callCount).toBe(3);
|
|
848
|
-
const summaryMsg = result.messages[1];
|
|
849
|
-
expect(summaryMsg.content).toContain("Summary on third try");
|
|
850
|
-
});
|
|
851
|
-
// anchorRemap is what lets callers move transcript markers (Ken turns,
|
|
852
|
-
// autopilot verdicts, error rows) onto the rewritten message list. If it
|
|
853
|
-
// disagrees with the actual collapse, restored markers land in the wrong
|
|
854
|
-
// place — the "everything bunched at the bottom" bug.
|
|
855
|
-
it("reports an anchorRemap that matches the real collapse (ack skipped)", async () => {
|
|
856
|
-
const mockStream = vi.mocked(stream);
|
|
857
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.resolve({
|
|
858
|
-
message: { role: "assistant", content: "Summary." },
|
|
859
|
-
stopReason: "end_turn",
|
|
860
|
-
usage: { inputTokens: 1000, outputTokens: 50 },
|
|
861
|
-
})));
|
|
862
|
-
const messages = buildConversation(30);
|
|
863
|
-
const result = await compact(messages, baseOptions);
|
|
864
|
-
const remap = result.result.anchorRemap;
|
|
865
|
-
expect(remap).toBeDefined();
|
|
866
|
-
// This fixture's retained tail starts with an assistant message, so the
|
|
867
|
-
// ack is skipped and the summary block is a single message.
|
|
868
|
-
expect(remap.prefixCount).toBe(1);
|
|
869
|
-
const newNonSystem = result.messages.filter((m) => m.role !== "system").length;
|
|
870
|
-
const oldNonSystem = messages.filter((m) => m.role !== "system").length;
|
|
871
|
-
// The reported new length must be the real one — everything downstream
|
|
872
|
-
// clamps against it.
|
|
873
|
-
expect(remap.newNonSystemCount).toBe(newNonSystem);
|
|
874
|
-
// The summary block replaces the summarized head; the untouched tail is
|
|
875
|
-
// exactly what remains after it.
|
|
876
|
-
const keptTail = oldNonSystem - remap.summarizedCount;
|
|
877
|
-
expect(remap.prefixCount + keptTail).toBe(newNonSystem);
|
|
878
|
-
// That tail really is the ORIGINAL trailing messages, so an anchor in that
|
|
879
|
-
// region only shifts — it never needs re-interpreting.
|
|
880
|
-
expect(result.messages.slice(-keptTail)).toEqual(messages.slice(-keptTail));
|
|
881
|
-
// Remapping the last pre-compaction anchor must land exactly at the end of
|
|
882
|
-
// the new transcript — never past it (past-the-end is what gets dropped or
|
|
883
|
-
// clamped to the bottom on resume).
|
|
884
|
-
expect(remapAnchorForCompaction(oldNonSystem, remap)).toBe(newNonSystem);
|
|
885
|
-
for (let anchor = 0; anchor <= oldNonSystem; anchor++) {
|
|
886
|
-
const moved = remapAnchorForCompaction(anchor, remap);
|
|
887
|
-
expect(moved).toBeGreaterThanOrEqual(0);
|
|
888
|
-
expect(moved).toBeLessThanOrEqual(newNonSystem);
|
|
889
|
-
}
|
|
890
|
-
});
|
|
891
|
-
it("keeps anchorRemap correct when the ack IS emitted", async () => {
|
|
892
|
-
const mockStream = vi.mocked(stream);
|
|
893
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.resolve({
|
|
894
|
-
message: { role: "assistant", content: "Summary." },
|
|
895
|
-
stopReason: "end_turn",
|
|
896
|
-
usage: { inputTokens: 1000, outputTokens: 50 },
|
|
897
|
-
})));
|
|
898
|
-
// A huge trailing assistant message pushes the cut point past it, so the
|
|
899
|
-
// retained tail starts with a user message and the ack is emitted — the
|
|
900
|
-
// summary block is 2 messages, and the remap must account for both.
|
|
901
|
-
const messages = buildConversation(30);
|
|
902
|
-
messages.push(makeMessage("assistant", `tail ${"y".repeat(40_000)}`));
|
|
903
|
-
messages.push(makeMessage("user", "and finally this"));
|
|
904
|
-
const result = await compact(messages, baseOptions);
|
|
905
|
-
const remap = result.result.anchorRemap;
|
|
906
|
-
expect(remap).toBeDefined();
|
|
907
|
-
expect(remap.prefixCount).toBe(2);
|
|
908
|
-
const newNonSystem = result.messages.filter((m) => m.role !== "system").length;
|
|
909
|
-
const oldNonSystem = messages.filter((m) => m.role !== "system").length;
|
|
910
|
-
expect(remap.newNonSystemCount).toBe(newNonSystem);
|
|
911
|
-
expect(remap.prefixCount + (oldNonSystem - remap.summarizedCount)).toBe(newNonSystem);
|
|
912
|
-
expect(remapAnchorForCompaction(oldNonSystem, remap)).toBe(newNonSystem);
|
|
913
|
-
});
|
|
914
|
-
// repairToolPairing and the trailing-assistant pop can shorten the retained
|
|
915
|
-
// tail AFTER the collapse is decided. Deriving the new length from
|
|
916
|
-
// summarizedCount alone then overshoots, pushing tail anchors past the end —
|
|
917
|
-
// where markers get dropped and Ken turns clamp to the bottom, which is the
|
|
918
|
-
// exact symptom this remap exists to prevent.
|
|
919
|
-
it("never maps an anchor past the end when the trailing assistant is popped", async () => {
|
|
920
|
-
const mockStream = vi.mocked(stream);
|
|
921
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.resolve({
|
|
922
|
-
message: { role: "assistant", content: "Summary." },
|
|
923
|
-
stopReason: "end_turn",
|
|
924
|
-
usage: { inputTokens: 1000, outputTokens: 50 },
|
|
925
|
-
})));
|
|
926
|
-
// Ends with an assistant message, so the pop loop fires and trims the tail.
|
|
927
|
-
const messages = buildConversation(30);
|
|
928
|
-
messages.push(makeMessage("assistant", "trailing assistant reply"));
|
|
929
|
-
expect(messages[messages.length - 1].role).toBe("assistant");
|
|
930
|
-
const result = await compact(messages, baseOptions);
|
|
931
|
-
const remap = result.result.anchorRemap;
|
|
932
|
-
expect(remap).toBeDefined();
|
|
933
|
-
const newNonSystem = result.messages.filter((m) => m.role !== "system").length;
|
|
934
|
-
const oldNonSystem = messages.filter((m) => m.role !== "system").length;
|
|
935
|
-
expect(remap.newNonSystemCount).toBe(newNonSystem);
|
|
936
|
-
// Every anchor — especially the last one — stays inside the new transcript.
|
|
937
|
-
for (let anchor = 0; anchor <= oldNonSystem; anchor++) {
|
|
938
|
-
expect(remapAnchorForCompaction(anchor, remap)).toBeLessThanOrEqual(newNonSystem);
|
|
939
|
-
}
|
|
940
|
-
});
|
|
941
|
-
it("appends one merged modified-files block and never lists read files", async () => {
|
|
942
|
-
const mockStream = vi.mocked(stream);
|
|
943
|
-
mockStream.mockReturnValue(mockStreamResult(Promise.resolve({
|
|
944
|
-
message: { role: "assistant", content: "Fresh summary." },
|
|
945
|
-
stopReason: "end_turn",
|
|
946
|
-
usage: { inputTokens: 1000, outputTokens: 50 },
|
|
947
|
-
})));
|
|
948
|
-
const messages = buildConversation(30);
|
|
949
|
-
// Prior compacted memory already carrying tracked edits from a collapsed segment.
|
|
950
|
-
messages.splice(1, 0, {
|
|
951
|
-
role: "user",
|
|
952
|
-
content: "[Previous conversation summary]\n\nOlder work.\n\n" +
|
|
953
|
-
"<read-files>\nsrc/legacy-read.ts\n</read-files>\n" +
|
|
954
|
-
"<modified-files>\nsrc/carried.ts\n</modified-files>",
|
|
955
|
-
provenance: { source: "runtime", kind: "compaction_summary", visibility: "summary" },
|
|
956
|
-
});
|
|
957
|
-
messages.splice(2, 0, makeToolCallMessage("edit", { file_path: "src/fresh.ts" }, "e1"));
|
|
958
|
-
messages.splice(3, 0, makeToolCallMessage("grep", { path: "src/" }, "g1"));
|
|
959
|
-
const result = await compact(messages, baseOptions);
|
|
960
|
-
const summary = result.messages[1].content;
|
|
961
|
-
expect(summary).not.toContain("<read-files>");
|
|
962
|
-
expect(summary).not.toContain("src/legacy-read.ts");
|
|
963
|
-
// Exactly one block, carrying both the pre-collapse and the fresh edit.
|
|
964
|
-
expect(summary.match(/<modified-files>/gu)).toHaveLength(1);
|
|
965
|
-
expect(summary).toContain("src/carried.ts");
|
|
966
|
-
expect(summary).toContain("src/fresh.ts");
|
|
967
|
-
// grep's path argument is a directory, not a file the agent opened.
|
|
968
|
-
expect(summary).not.toContain("src/\n");
|
|
969
|
-
// The prior block is stripped from the prose handed back to the summarizer,
|
|
970
|
-
// so it cannot be transcribed into the new summary a second time.
|
|
971
|
-
// Mocks are not reset between tests in this file — inspect this test's call.
|
|
972
|
-
const lastCall = vi.mocked(stream).mock.calls.at(-1);
|
|
973
|
-
const sentText = lastCall[0].messages
|
|
974
|
-
.map((m) => (typeof m.content === "string" ? m.content : JSON.stringify(m.content)))
|
|
975
|
-
.join("\n");
|
|
976
|
-
expect(sentText).toContain("<previous-summary>");
|
|
977
|
-
expect(sentText).not.toContain("<modified-files>");
|
|
978
|
-
expect(sentText).toContain("SUPERSEDES");
|
|
979
|
-
});
|
|
980
|
-
});
|
|
981
|
-
// ── extractFileOperations ──────────────────────────────────
|
|
982
|
-
describe("extractFileOperations", () => {
|
|
983
|
-
it("counts only the read tool as a read, not grep/find directory scans", () => {
|
|
984
|
-
const ops = extractFileOperations([
|
|
985
|
-
makeToolCallMessage("read", { file_path: "src/opened.ts" }, "r1"),
|
|
986
|
-
makeToolCallMessage("grep", { path: "src/components" }, "g1"),
|
|
987
|
-
makeToolCallMessage("find", { path: "packages" }, "f1"),
|
|
988
|
-
makeToolCallMessage("edit", { file_path: "src/changed.ts" }, "e1"),
|
|
989
|
-
]);
|
|
990
|
-
expect([...ops.read]).toEqual(["src/opened.ts"]);
|
|
991
|
-
expect([...ops.modified]).toEqual(["src/changed.ts"]);
|
|
992
|
-
});
|
|
993
|
-
});
|
|
994
|
-
// ── modified-file tracking ─────────────────────────────────
|
|
995
|
-
describe("splitTrackedModifiedFiles", () => {
|
|
996
|
-
it("extracts tracked paths and strips both tracking blocks from the prose", () => {
|
|
997
|
-
const { text, files } = splitTrackedModifiedFiles("Prose body.\n\n<read-files>\nsrc/a.ts\n</read-files>\n" +
|
|
998
|
-
"<modified-files>\nsrc/b.ts\nsrc/c.ts\n</modified-files>");
|
|
999
|
-
expect(text).toBe("Prose body.");
|
|
1000
|
-
expect(files).toEqual(["src/b.ts", "src/c.ts"]);
|
|
1001
|
-
});
|
|
1002
|
-
it("leaves prose without tracking blocks untouched", () => {
|
|
1003
|
-
const { text, files, omitted } = splitTrackedModifiedFiles("Just a summary.");
|
|
1004
|
-
expect(text).toBe("Just a summary.");
|
|
1005
|
-
expect(files).toEqual([]);
|
|
1006
|
-
expect(omitted).toBe(0);
|
|
1007
|
-
});
|
|
1008
|
-
it("reads the overflow note as a count, never as a file path", () => {
|
|
1009
|
-
const { files, omitted } = splitTrackedModifiedFiles("Prose.\n\n<modified-files>\nsrc/a.ts\n[... 7 earlier modified files omitted]\n</modified-files>");
|
|
1010
|
-
expect(files).toEqual(["src/a.ts"]);
|
|
1011
|
-
expect(omitted).toBe(7);
|
|
1012
|
-
});
|
|
1013
|
-
});
|
|
1014
|
-
describe("buildModifiedFilesSection", () => {
|
|
1015
|
-
it("returns empty string when nothing was modified", () => {
|
|
1016
|
-
expect(buildModifiedFilesSection([])).toBe("");
|
|
1017
|
-
expect(buildModifiedFilesSection([" ", ""])).toBe("");
|
|
1018
|
-
});
|
|
1019
|
-
it("dedupes carried and fresh paths into a single block", () => {
|
|
1020
|
-
const section = buildModifiedFilesSection(["src/a.ts", "src/b.ts", "src/a.ts"]);
|
|
1021
|
-
expect(section.match(/src\/a\.ts/gu)).toHaveLength(1);
|
|
1022
|
-
expect(section).toContain("src/b.ts");
|
|
1023
|
-
});
|
|
1024
|
-
it("keeps the most recent paths when the list overflows", () => {
|
|
1025
|
-
const paths = Array.from({ length: MAX_TRACKED_MODIFIED_FILES + 5 }, (_v, i) => `src/f${i}.ts`);
|
|
1026
|
-
const section = buildModifiedFilesSection(paths);
|
|
1027
|
-
expect(section).toContain(`src/f${paths.length - 1}.ts`);
|
|
1028
|
-
expect(section).not.toContain("src/f0.ts\n");
|
|
1029
|
-
expect(section).toContain("[... 5 earlier modified files omitted]");
|
|
1030
|
-
});
|
|
1031
|
-
it("accumulates the omitted count across generations instead of resetting", () => {
|
|
1032
|
-
const section = buildModifiedFilesSection(["src/a.ts"], 7);
|
|
1033
|
-
expect(section).toContain("[... 7 earlier modified files omitted]");
|
|
1034
|
-
const overflowing = Array.from({ length: MAX_TRACKED_MODIFIED_FILES + 5 }, (_v, i) => `src/f${i}.ts`);
|
|
1035
|
-
expect(buildModifiedFilesSection(overflowing, 7)).toContain("[... 12 earlier modified files omitted]");
|
|
1036
|
-
});
|
|
1037
|
-
it("still reports prior omissions when nothing survives the merge", () => {
|
|
1038
|
-
expect(buildModifiedFilesSection([], 4)).toContain("[... 4 earlier modified files omitted]");
|
|
1039
|
-
});
|
|
1040
|
-
it("survives repeated build/split generations without stacking notes", () => {
|
|
1041
|
-
// Generation 1: overflow by 5.
|
|
1042
|
-
let section = buildModifiedFilesSection(Array.from({ length: MAX_TRACKED_MODIFIED_FILES + 5 }, (_v, i) => `src/f${i}.ts`));
|
|
1043
|
-
// Three further generations, each adding two fresh edits.
|
|
1044
|
-
let carried = splitTrackedModifiedFiles(`Prose.${section}`);
|
|
1045
|
-
for (let gen = 0; gen < 3; gen++) {
|
|
1046
|
-
expect(carried.files).toHaveLength(MAX_TRACKED_MODIFIED_FILES);
|
|
1047
|
-
// The note must never be mistaken for a path.
|
|
1048
|
-
expect(carried.files.some((f) => f.startsWith("[..."))).toBe(false);
|
|
1049
|
-
section = buildModifiedFilesSection([...carried.files, `src/new-${gen}-a.ts`, `src/new-${gen}-b.ts`], carried.omitted);
|
|
1050
|
-
carried = splitTrackedModifiedFiles(`Prose.${section}`);
|
|
1051
|
-
}
|
|
1052
|
-
// Exactly one note line, with the running total (5 + 2 + 2 + 2).
|
|
1053
|
-
expect(section.match(/earlier modified files omitted/gu)).toHaveLength(1);
|
|
1054
|
-
expect(section).toContain("[... 11 earlier modified files omitted]");
|
|
1055
|
-
expect(carried.omitted).toBe(11);
|
|
1056
|
-
expect(carried.files).toHaveLength(MAX_TRACKED_MODIFIED_FILES);
|
|
1057
|
-
expect(section).toContain("src/new-2-b.ts");
|
|
1058
|
-
});
|
|
1059
|
-
});
|
|
1060
|
-
// ── resolveSummaryOutputTokens ─────────────────────────────
|
|
1061
|
-
describe("resolveSummaryOutputTokens", () => {
|
|
1062
|
-
it("floors at the minimum for small or unknown windows", () => {
|
|
1063
|
-
expect(resolveSummaryOutputTokens(32_000)).toBe(MIN_SUMMARY_OUTPUT_TOKENS);
|
|
1064
|
-
expect(resolveSummaryOutputTokens(0)).toBe(MIN_SUMMARY_OUTPUT_TOKENS);
|
|
1065
|
-
expect(resolveSummaryOutputTokens(Number.NaN)).toBe(MIN_SUMMARY_OUTPUT_TOKENS);
|
|
1066
|
-
});
|
|
1067
|
-
it("scales with the window and caps at the maximum", () => {
|
|
1068
|
-
expect(resolveSummaryOutputTokens(200_000)).toBe(6000);
|
|
1069
|
-
expect(resolveSummaryOutputTokens(1_000_000)).toBe(MAX_SUMMARY_OUTPUT_TOKENS);
|
|
1070
|
-
});
|
|
1071
|
-
});
|
|
1072
|
-
//# sourceMappingURL=compactor.test.js.map
|