@prestyj/cli 5.10.0 → 5.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -4
- package/assets/skills/compliance-guard/SKILL.md +251 -0
- package/assets/skills/compliance-guard/references/artifacts.md +186 -0
- package/assets/skills/compliance-guard/references/eu-uk.md +151 -0
- package/assets/skills/compliance-guard/references/exposure-triage.md +161 -0
- package/assets/skills/compliance-guard/references/lawsuit-vectors.md +141 -0
- package/assets/skills/compliance-guard/references/provenance.md +42 -0
- package/assets/skills/compliance-guard/references/sector-gates.md +173 -0
- package/assets/skills/compliance-guard/references/security-baseline.md +130 -0
- package/assets/skills/compliance-guard/references/trigger-map.md +163 -0
- package/assets/skills/compliance-guard/references/us.md +164 -0
- package/dist/app-sidecar-auth-broadcast.test.d.ts +2 -0
- package/dist/app-sidecar-auth-broadcast.test.d.ts.map +1 -0
- package/dist/app-sidecar-auth-broadcast.test.js +348 -0
- package/dist/app-sidecar-auth-broadcast.test.js.map +1 -0
- package/dist/app-sidecar-sessions.d.ts +5 -2
- package/dist/app-sidecar-sessions.d.ts.map +1 -1
- package/dist/app-sidecar-sessions.js +34 -8
- package/dist/app-sidecar-sessions.js.map +1 -1
- package/dist/app-sidecar-sessions.test.js +96 -1
- package/dist/app-sidecar-sessions.test.js.map +1 -1
- package/dist/app-sidecar.js +616 -173
- package/dist/app-sidecar.js.map +1 -1
- package/dist/chat-agents/jiwa.test.js +1 -1
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +33 -36
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/command-routing.d.ts +1 -1
- package/dist/cli/command-routing.d.ts.map +1 -1
- package/dist/cli/command-routing.js +1 -0
- package/dist/cli/command-routing.js.map +1 -1
- package/dist/cli/command-routing.test.js +1 -0
- package/dist/cli/command-routing.test.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +179 -48
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +18 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +45 -76
- package/dist/config.js.map +1 -1
- package/dist/config.test.js +30 -13
- package/dist/config.test.js.map +1 -1
- package/dist/core/agent-notifications.d.ts +62 -0
- package/dist/core/agent-notifications.d.ts.map +1 -0
- package/dist/core/agent-notifications.js +92 -0
- package/dist/core/agent-notifications.js.map +1 -0
- package/dist/core/agent-notifications.test.d.ts +2 -0
- package/dist/core/agent-notifications.test.d.ts.map +1 -0
- package/dist/core/agent-notifications.test.js +97 -0
- package/dist/core/agent-notifications.test.js.map +1 -0
- package/dist/core/agent-session-checkpoint-flush.test.d.ts +2 -0
- package/dist/core/agent-session-checkpoint-flush.test.d.ts.map +1 -0
- package/dist/core/agent-session-checkpoint-flush.test.js +201 -0
- package/dist/core/agent-session-checkpoint-flush.test.js.map +1 -0
- package/dist/core/agent-session-compaction.test.js +323 -6
- package/dist/core/agent-session-compaction.test.js.map +1 -1
- package/dist/core/agent-session-crash-durability.test.d.ts +2 -0
- package/dist/core/agent-session-crash-durability.test.d.ts.map +1 -0
- package/dist/core/agent-session-crash-durability.test.js +102 -0
- package/dist/core/agent-session-crash-durability.test.js.map +1 -0
- package/dist/core/agent-session-marker-anchors.test.js +181 -2
- package/dist/core/agent-session-marker-anchors.test.js.map +1 -1
- package/dist/core/agent-session-model-switch.test.d.ts +2 -0
- package/dist/core/agent-session-model-switch.test.d.ts.map +1 -0
- package/dist/core/agent-session-model-switch.test.js +161 -0
- package/dist/core/agent-session-model-switch.test.js.map +1 -0
- package/dist/core/agent-session-notifications.test.d.ts +2 -0
- package/dist/core/agent-session-notifications.test.d.ts.map +1 -0
- package/dist/core/agent-session-notifications.test.js +114 -0
- package/dist/core/agent-session-notifications.test.js.map +1 -0
- package/dist/core/agent-session-process-gate.test.d.ts +2 -0
- package/dist/core/agent-session-process-gate.test.d.ts.map +1 -0
- package/dist/core/agent-session-process-gate.test.js +98 -0
- package/dist/core/agent-session-process-gate.test.js.map +1 -0
- package/dist/core/agent-session-queue.test.js +65 -0
- package/dist/core/agent-session-queue.test.js.map +1 -1
- package/dist/core/agent-session-review-coverage.test.js +80 -23
- package/dist/core/agent-session-review-coverage.test.js.map +1 -1
- package/dist/core/agent-session-slash-restore.test.d.ts +2 -0
- package/dist/core/agent-session-slash-restore.test.d.ts.map +1 -0
- package/dist/core/agent-session-slash-restore.test.js +121 -0
- package/dist/core/agent-session-slash-restore.test.js.map +1 -0
- package/dist/core/agent-session-tool-tiers.test.d.ts +2 -0
- package/dist/core/agent-session-tool-tiers.test.d.ts.map +1 -0
- package/dist/core/agent-session-tool-tiers.test.js +138 -0
- package/dist/core/agent-session-tool-tiers.test.js.map +1 -0
- package/dist/core/agent-session.d.ts +257 -13
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1118 -241
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/agents.d.ts +29 -1
- package/dist/core/agents.d.ts.map +1 -1
- package/dist/core/agents.js +47 -97
- package/dist/core/agents.js.map +1 -1
- package/dist/core/agents.test.js +87 -7
- package/dist/core/agents.test.js.map +1 -1
- package/dist/core/api-benchmark.d.ts +3 -3
- package/dist/core/api-benchmark.js +7 -7
- package/dist/core/auth-providers.d.ts +37 -1
- package/dist/core/auth-providers.d.ts.map +1 -1
- package/dist/core/auth-providers.js +83 -3
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/auto-update.test.js +1 -1
- package/dist/core/autopilot-gate.d.ts +2 -2
- package/dist/core/autopilot-gate.js +1 -1
- package/dist/core/bash-spawn-benchmark.js +6 -6
- package/dist/core/bundled-agents.d.ts +3 -0
- package/dist/core/bundled-agents.d.ts.map +1 -0
- package/dist/core/bundled-agents.js +252 -0
- package/dist/core/bundled-agents.js.map +1 -0
- package/dist/core/cache-warm-benchmark.d.ts +2 -2
- package/dist/core/cache-warm-benchmark.js +5 -5
- package/dist/core/code-retrieval-chunkers.d.ts +27 -0
- package/dist/core/code-retrieval-chunkers.d.ts.map +1 -0
- package/dist/core/code-retrieval-chunkers.js +264 -0
- package/dist/core/code-retrieval-chunkers.js.map +1 -0
- package/dist/core/code-retrieval-chunkers.test.d.ts +2 -0
- package/dist/core/code-retrieval-chunkers.test.d.ts.map +1 -0
- package/dist/core/code-retrieval-chunkers.test.js +203 -0
- package/dist/core/code-retrieval-chunkers.test.js.map +1 -0
- package/dist/core/code-retrieval.d.ts +6 -0
- package/dist/core/code-retrieval.d.ts.map +1 -1
- package/dist/core/code-retrieval.js +38 -1
- package/dist/core/code-retrieval.js.map +1 -1
- package/dist/core/compaction/active-context.test.js +21 -0
- package/dist/core/compaction/active-context.test.js.map +1 -1
- package/dist/core/compaction/compactor.d.ts +108 -8
- package/dist/core/compaction/compactor.d.ts.map +1 -1
- package/dist/core/compaction/compactor.js +423 -119
- package/dist/core/compaction/compactor.js.map +1 -1
- package/dist/core/compaction/compactor.test.js +360 -8
- package/dist/core/compaction/compactor.test.js.map +1 -1
- package/dist/core/compaction/policy.d.ts +17 -0
- package/dist/core/compaction/policy.d.ts.map +1 -0
- package/dist/core/compaction/policy.js +22 -0
- package/dist/core/compaction/policy.js.map +1 -0
- package/dist/core/compaction/policy.test.d.ts +2 -0
- package/dist/core/compaction/policy.test.d.ts.map +1 -0
- package/dist/core/compaction/policy.test.js +35 -0
- package/dist/core/compaction/policy.test.js.map +1 -0
- package/dist/core/compaction/query-aware-selector.d.ts +33 -0
- package/dist/core/compaction/query-aware-selector.d.ts.map +1 -0
- package/dist/core/compaction/query-aware-selector.js +202 -0
- package/dist/core/compaction/query-aware-selector.js.map +1 -0
- package/dist/core/compaction/query-aware-selector.test.d.ts +2 -0
- package/dist/core/compaction/query-aware-selector.test.d.ts.map +1 -0
- package/dist/core/compaction/query-aware-selector.test.js +96 -0
- package/dist/core/compaction/query-aware-selector.test.js.map +1 -0
- package/dist/core/compaction/tool-result-pruner.d.ts +24 -11
- package/dist/core/compaction/tool-result-pruner.d.ts.map +1 -1
- package/dist/core/compaction/tool-result-pruner.js +98 -26
- package/dist/core/compaction/tool-result-pruner.js.map +1 -1
- package/dist/core/compaction/tool-result-pruner.test.js +178 -6
- package/dist/core/compaction/tool-result-pruner.test.js.map +1 -1
- package/dist/core/encode-cwd.test.js +1 -1
- package/dist/core/event-bus.d.ts +23 -0
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js +10 -0
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +28 -8
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/plugin-bundles.d.ts +23 -0
- package/dist/core/extensions/plugin-bundles.d.ts.map +1 -0
- package/dist/core/extensions/plugin-bundles.js +228 -0
- package/dist/core/extensions/plugin-bundles.js.map +1 -0
- package/dist/core/extensions/plugin-bundles.test.d.ts +2 -0
- package/dist/core/extensions/plugin-bundles.test.d.ts.map +1 -0
- package/dist/core/extensions/plugin-bundles.test.js +110 -0
- package/dist/core/extensions/plugin-bundles.test.js.map +1 -0
- package/dist/core/fast-apply-benchmark.d.ts +2 -2
- package/dist/core/fast-apply-benchmark.js +6 -6
- package/dist/core/foreign-session-import.d.ts +120 -0
- package/dist/core/foreign-session-import.d.ts.map +1 -0
- package/dist/core/foreign-session-import.js +598 -0
- package/dist/core/foreign-session-import.js.map +1 -0
- package/dist/core/foreign-session-import.test.d.ts +2 -0
- package/dist/core/foreign-session-import.test.d.ts.map +1 -0
- package/dist/core/foreign-session-import.test.js +220 -0
- package/dist/core/foreign-session-import.test.js.map +1 -0
- package/dist/core/foreign-transcript-blocks.d.ts +51 -0
- package/dist/core/foreign-transcript-blocks.d.ts.map +1 -0
- package/dist/core/foreign-transcript-blocks.js +151 -0
- package/dist/core/foreign-transcript-blocks.js.map +1 -0
- package/dist/core/goal-lifecycle-smoke.test.js +2 -2
- package/dist/core/goal-store.js +1 -1
- package/dist/core/goal-store.test.js +2 -2
- package/dist/core/goal-verifier.test.js +2 -2
- package/dist/core/goal-worker-dev-server-lifecycle.test.js +1 -1
- package/dist/core/goal-worker.test.js +2 -2
- package/dist/core/hashline-edit-benchmark.d.ts +2 -2
- package/dist/core/hashline-edit-benchmark.js +7 -7
- package/dist/core/ideal-review.d.ts +20 -1
- package/dist/core/ideal-review.d.ts.map +1 -1
- package/dist/core/ideal-review.js +37 -2
- package/dist/core/ideal-review.js.map +1 -1
- package/dist/core/ideal-review.test.js +99 -3
- package/dist/core/ideal-review.test.js.map +1 -1
- package/dist/core/local-endpoint-store.test.js +1 -1
- package/dist/core/logger.d.ts +1 -1
- package/dist/core/logger.js +2 -2
- package/dist/core/logger.js.map +1 -1
- package/dist/core/loop-breaker.d.ts.map +1 -1
- package/dist/core/loop-breaker.js +1 -0
- package/dist/core/loop-breaker.js.map +1 -1
- package/dist/core/lsp/client-navigation.test.d.ts +2 -0
- package/dist/core/lsp/client-navigation.test.d.ts.map +1 -0
- package/dist/core/lsp/client-navigation.test.js +135 -0
- package/dist/core/lsp/client-navigation.test.js.map +1 -0
- package/dist/core/lsp/client.d.ts +84 -0
- package/dist/core/lsp/client.d.ts.map +1 -1
- package/dist/core/lsp/client.js +190 -3
- package/dist/core/lsp/client.js.map +1 -1
- package/dist/core/lsp/integration.test.js +2 -2
- package/dist/core/lsp/manager-navigation.test.d.ts +2 -0
- package/dist/core/lsp/manager-navigation.test.d.ts.map +1 -0
- package/dist/core/lsp/manager-navigation.test.js +121 -0
- package/dist/core/lsp/manager-navigation.test.js.map +1 -0
- package/dist/core/lsp/manager.d.ts +81 -9
- package/dist/core/lsp/manager.d.ts.map +1 -1
- package/dist/core/lsp/manager.js +183 -64
- package/dist/core/lsp/manager.js.map +1 -1
- package/dist/core/lsp/manager.test.js +18 -0
- package/dist/core/lsp/manager.test.js.map +1 -1
- package/dist/core/lsp/pool.d.ts +113 -0
- package/dist/core/lsp/pool.d.ts.map +1 -0
- package/dist/core/lsp/pool.js +255 -0
- package/dist/core/lsp/pool.js.map +1 -0
- package/dist/core/lsp/pool.test.d.ts +2 -0
- package/dist/core/lsp/pool.test.d.ts.map +1 -0
- package/dist/core/lsp/pool.test.js +286 -0
- package/dist/core/lsp/pool.test.js.map +1 -0
- package/dist/core/lsp/servers.d.ts.map +1 -1
- package/dist/core/lsp/servers.js +43 -3
- package/dist/core/lsp/servers.js.map +1 -1
- package/dist/core/lsp/servers.test.d.ts +2 -0
- package/dist/core/lsp/servers.test.d.ts.map +1 -0
- package/dist/core/lsp/servers.test.js +67 -0
- package/dist/core/lsp/servers.test.js.map +1 -0
- package/dist/core/lsp/windows.test.js +6 -18
- package/dist/core/lsp/windows.test.js.map +1 -1
- package/dist/core/mcp/catalog-cache.d.ts +63 -0
- package/dist/core/mcp/catalog-cache.d.ts.map +1 -0
- package/dist/core/mcp/catalog-cache.js +163 -0
- package/dist/core/mcp/catalog-cache.js.map +1 -0
- package/dist/core/mcp/catalog-cache.test.d.ts +2 -0
- package/dist/core/mcp/catalog-cache.test.d.ts.map +1 -0
- package/dist/core/mcp/catalog-cache.test.js +99 -0
- package/dist/core/mcp/catalog-cache.test.js.map +1 -0
- package/dist/core/mcp/client-session-recovery.test.d.ts +2 -0
- package/dist/core/mcp/client-session-recovery.test.d.ts.map +1 -0
- package/dist/core/mcp/client-session-recovery.test.js +231 -0
- package/dist/core/mcp/client-session-recovery.test.js.map +1 -0
- package/dist/core/mcp/client.d.ts +158 -0
- package/dist/core/mcp/client.d.ts.map +1 -1
- package/dist/core/mcp/client.js +478 -45
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/content.d.ts +19 -0
- package/dist/core/mcp/content.d.ts.map +1 -0
- package/dist/core/mcp/content.js +172 -0
- package/dist/core/mcp/content.js.map +1 -0
- package/dist/core/mcp/content.test.d.ts +2 -0
- package/dist/core/mcp/content.test.d.ts.map +1 -0
- package/dist/core/mcp/content.test.js +135 -0
- package/dist/core/mcp/content.test.js.map +1 -0
- package/dist/core/mcp/deferred-catalog.d.ts +1 -1
- package/dist/core/mcp/deferred-catalog.js +1 -1
- package/dist/core/mcp/elicitation-bridge.d.ts +41 -0
- package/dist/core/mcp/elicitation-bridge.d.ts.map +1 -0
- package/dist/core/mcp/elicitation-bridge.js +52 -0
- package/dist/core/mcp/elicitation-bridge.js.map +1 -0
- package/dist/core/mcp/elicitation.test.d.ts +2 -0
- package/dist/core/mcp/elicitation.test.d.ts.map +1 -0
- package/dist/core/mcp/elicitation.test.js +158 -0
- package/dist/core/mcp/elicitation.test.js.map +1 -0
- package/dist/core/mcp/index.d.ts +5 -1
- package/dist/core/mcp/index.d.ts.map +1 -1
- package/dist/core/mcp/index.js +2 -0
- package/dist/core/mcp/index.js.map +1 -1
- package/dist/core/mcp/legacy-negotiation.test.d.ts +2 -0
- package/dist/core/mcp/legacy-negotiation.test.d.ts.map +1 -0
- package/dist/core/mcp/legacy-negotiation.test.js +80 -0
- package/dist/core/mcp/legacy-negotiation.test.js.map +1 -0
- package/dist/core/mcp/oauth-provider.d.ts +1 -2
- package/dist/core/mcp/oauth-provider.d.ts.map +1 -1
- package/dist/core/mcp/oauth-provider.js +6 -2
- package/dist/core/mcp/oauth-provider.js.map +1 -1
- package/dist/core/mcp/oauth-store.d.ts +1 -1
- package/dist/core/mcp/oauth-store.d.ts.map +1 -1
- package/dist/core/mcp/oauth-store.js.map +1 -1
- package/dist/core/mcp/oauth-store.test.js +2 -2
- package/dist/core/mcp/resolve-stdio.test.js +5 -5
- package/dist/core/mcp/session-elicitation-wiring.test.d.ts +2 -0
- package/dist/core/mcp/session-elicitation-wiring.test.d.ts.map +1 -0
- package/dist/core/mcp/session-elicitation-wiring.test.js +138 -0
- package/dist/core/mcp/session-elicitation-wiring.test.js.map +1 -0
- package/dist/core/mcp/shared-pool.d.ts +158 -0
- package/dist/core/mcp/shared-pool.d.ts.map +1 -0
- package/dist/core/mcp/shared-pool.js +235 -0
- package/dist/core/mcp/shared-pool.js.map +1 -0
- package/dist/core/mcp/shared-pool.test.d.ts +2 -0
- package/dist/core/mcp/shared-pool.test.d.ts.map +1 -0
- package/dist/core/mcp/shared-pool.test.js +425 -0
- package/dist/core/mcp/shared-pool.test.js.map +1 -0
- package/dist/core/mcp/store.test.js +5 -5
- package/dist/core/mcp/types.d.ts +12 -0
- package/dist/core/mcp/types.d.ts.map +1 -1
- package/dist/core/mcp/when-connected.test.d.ts +2 -0
- package/dist/core/mcp/when-connected.test.d.ts.map +1 -0
- package/dist/core/mcp/when-connected.test.js +46 -0
- package/dist/core/mcp/when-connected.test.js.map +1 -0
- package/dist/core/nolan-context.d.ts.map +1 -1
- package/dist/core/nolan-context.js +8 -0
- package/dist/core/nolan-context.js.map +1 -1
- package/dist/core/nolan-context.test.js +40 -0
- package/dist/core/nolan-context.test.js.map +1 -1
- package/dist/core/nolan-model.test.js +1 -1
- package/dist/core/nolan-prompt.js +8 -5
- package/dist/core/nolan-prompt.js.map +1 -1
- package/dist/core/nolan-prompt.test.js +5 -0
- package/dist/core/nolan-prompt.test.js.map +1 -1
- package/dist/core/oauth/xai.d.ts +2 -0
- package/dist/core/oauth/xai.d.ts.map +1 -0
- package/dist/core/oauth/xai.js +4 -0
- package/dist/core/oauth/xai.js.map +1 -0
- package/dist/core/persistent-shell.d.ts +3 -2
- package/dist/core/persistent-shell.d.ts.map +1 -1
- package/dist/core/persistent-shell.js +11 -4
- package/dist/core/persistent-shell.js.map +1 -1
- package/dist/core/persistent-shell.test.js +6 -6
- package/dist/core/process-gate.d.ts +45 -0
- package/dist/core/process-gate.d.ts.map +1 -0
- package/dist/core/process-gate.js +79 -0
- package/dist/core/process-gate.js.map +1 -0
- package/dist/core/process-gate.test.d.ts +2 -0
- package/dist/core/process-gate.test.d.ts.map +1 -0
- package/dist/core/process-gate.test.js +87 -0
- package/dist/core/process-gate.test.js.map +1 -0
- package/dist/core/process-manager-dev-server-repro.test.js +51 -12
- package/dist/core/process-manager-dev-server-repro.test.js.map +1 -1
- package/dist/core/process-manager-notifications.test.d.ts +2 -0
- package/dist/core/process-manager-notifications.test.d.ts.map +1 -0
- package/dist/core/process-manager-notifications.test.js +227 -0
- package/dist/core/process-manager-notifications.test.js.map +1 -0
- package/dist/core/process-manager.d.ts +72 -1
- package/dist/core/process-manager.d.ts.map +1 -1
- package/dist/core/process-manager.js +247 -4
- package/dist/core/process-manager.js.map +1 -1
- package/dist/core/progress/git-xp.test.js +2 -2
- package/dist/core/progress/ranks.d.ts +14 -3
- package/dist/core/progress/ranks.d.ts.map +1 -1
- package/dist/core/progress/ranks.js +181 -12
- package/dist/core/progress/ranks.js.map +1 -1
- package/dist/core/progress/ranks.test.js +48 -7
- package/dist/core/progress/ranks.test.js.map +1 -1
- package/dist/core/progress/rebuild.test.js +1 -1
- package/dist/core/progress/store.test.js +1 -1
- package/dist/core/progress/types.d.ts +2 -1
- package/dist/core/progress/types.d.ts.map +1 -1
- package/dist/core/project-discovery.d.ts +31 -6
- package/dist/core/project-discovery.d.ts.map +1 -1
- package/dist/core/project-discovery.js +349 -79
- package/dist/core/project-discovery.js.map +1 -1
- package/dist/core/project-discovery.test.js +128 -4
- package/dist/core/project-discovery.test.js.map +1 -1
- package/dist/core/prompt-commands.js +3 -3
- package/dist/core/radio.d.ts +1 -1
- package/dist/core/radio.d.ts.map +1 -1
- package/dist/core/radio.js +90 -6
- package/dist/core/radio.js.map +1 -1
- package/dist/core/radio.test.js +15 -2
- package/dist/core/radio.test.js.map +1 -1
- package/dist/core/regrounding.d.ts.map +1 -1
- package/dist/core/regrounding.js +1 -0
- package/dist/core/regrounding.js.map +1 -1
- package/dist/core/run-claim.d.ts +37 -0
- package/dist/core/run-claim.d.ts.map +1 -0
- package/dist/core/run-claim.js +46 -0
- package/dist/core/run-claim.js.map +1 -0
- package/dist/core/run-claim.test.d.ts +2 -0
- package/dist/core/run-claim.test.d.ts.map +1 -0
- package/dist/core/run-claim.test.js +107 -0
- package/dist/core/run-claim.test.js.map +1 -0
- package/dist/core/run-journal.test.d.ts +2 -0
- package/dist/core/run-journal.test.d.ts.map +1 -0
- package/dist/core/run-journal.test.js +195 -0
- package/dist/core/run-journal.test.js.map +1 -0
- package/dist/core/run-lifecycle.d.ts +22 -3
- package/dist/core/run-lifecycle.d.ts.map +1 -1
- package/dist/core/run-lifecycle.js +12 -3
- package/dist/core/run-lifecycle.js.map +1 -1
- package/dist/core/sandbox-domains.d.ts +14 -0
- package/dist/core/sandbox-domains.d.ts.map +1 -0
- package/dist/core/sandbox-domains.js +76 -0
- package/dist/core/sandbox-domains.js.map +1 -0
- package/dist/core/sandbox-feedback.d.ts +22 -0
- package/dist/core/sandbox-feedback.d.ts.map +1 -0
- package/dist/core/sandbox-feedback.js +69 -0
- package/dist/core/sandbox-feedback.js.map +1 -0
- package/dist/core/sandbox-feedback.test.d.ts +2 -0
- package/dist/core/sandbox-feedback.test.d.ts.map +1 -0
- package/dist/core/sandbox-feedback.test.js +32 -0
- package/dist/core/sandbox-feedback.test.js.map +1 -0
- package/dist/core/sandbox.d.ts +91 -0
- package/dist/core/sandbox.d.ts.map +1 -0
- package/dist/core/sandbox.js +254 -0
- package/dist/core/sandbox.js.map +1 -0
- package/dist/core/sandbox.test.d.ts +2 -0
- package/dist/core/sandbox.test.d.ts.map +1 -0
- package/dist/core/sandbox.test.js +157 -0
- package/dist/core/sandbox.test.js.map +1 -0
- package/dist/core/semantic-search-benchmark.d.ts +2 -2
- package/dist/core/semantic-search-benchmark.js +5 -5
- package/dist/core/session-compaction.d.ts +6 -0
- package/dist/core/session-compaction.d.ts.map +1 -1
- package/dist/core/session-compaction.js +11 -1
- package/dist/core/session-compaction.js.map +1 -1
- package/dist/core/session-compaction.test.js +19 -2
- package/dist/core/session-compaction.test.js.map +1 -1
- package/dist/core/session-export.d.ts.map +1 -1
- package/dist/core/session-export.js +12 -4
- package/dist/core/session-export.js.map +1 -1
- package/dist/core/session-history.d.ts +95 -6
- package/dist/core/session-history.d.ts.map +1 -1
- package/dist/core/session-history.js +261 -17
- package/dist/core/session-history.js.map +1 -1
- package/dist/core/session-history.test.js +173 -2
- package/dist/core/session-history.test.js.map +1 -1
- package/dist/core/session-manager.d.ts +223 -6
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +579 -74
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-manager.test.js +154 -10
- package/dist/core/session-manager.test.js.map +1 -1
- package/dist/core/session-notification-visibility.test.d.ts +2 -0
- package/dist/core/session-notification-visibility.test.d.ts.map +1 -0
- package/dist/core/session-notification-visibility.test.js +113 -0
- package/dist/core/session-notification-visibility.test.js.map +1 -0
- package/dist/core/session-preview.d.ts +5 -4
- package/dist/core/session-preview.d.ts.map +1 -1
- package/dist/core/session-preview.js +12 -5
- package/dist/core/session-preview.js.map +1 -1
- package/dist/core/session-restore-display.test.js +25 -0
- package/dist/core/session-restore-display.test.js.map +1 -1
- package/dist/core/session-storage-fd-leak.test.d.ts +2 -0
- package/dist/core/session-storage-fd-leak.test.d.ts.map +1 -0
- package/dist/core/session-storage-fd-leak.test.js +116 -0
- package/dist/core/session-storage-fd-leak.test.js.map +1 -0
- package/dist/core/session-storage.d.ts +22 -2
- package/dist/core/session-storage.d.ts.map +1 -1
- package/dist/core/session-storage.js +72 -9
- package/dist/core/session-storage.js.map +1 -1
- package/dist/core/session-storage.test.js +8 -3
- package/dist/core/session-storage.test.js.map +1 -1
- package/dist/core/settings-manager.d.ts +10 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +36 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/shell-path.js +1 -1
- package/dist/core/shell.d.ts +1 -1
- package/dist/core/shell.js +2 -2
- package/dist/core/shell.test.js +2 -2
- package/dist/core/shutdown.d.ts +71 -0
- package/dist/core/shutdown.d.ts.map +1 -0
- package/dist/core/shutdown.js +144 -0
- package/dist/core/shutdown.js.map +1 -0
- package/dist/core/shutdown.test.d.ts +2 -0
- package/dist/core/shutdown.test.d.ts.map +1 -0
- package/dist/core/shutdown.test.js +160 -0
- package/dist/core/shutdown.test.js.map +1 -0
- package/dist/core/sidecar-error-reporter.js +1 -1
- package/dist/core/sidecar-error-reporter.test.js +2 -2
- package/dist/core/skills-routing.test.js +96 -0
- package/dist/core/skills-routing.test.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +3 -0
- package/dist/core/skills.js.map +1 -1
- package/dist/core/steering.d.ts +12 -0
- package/dist/core/steering.d.ts.map +1 -1
- package/dist/core/steering.js +16 -0
- package/dist/core/steering.js.map +1 -1
- package/dist/core/subagent-manager.d.ts +22 -0
- package/dist/core/subagent-manager.d.ts.map +1 -1
- package/dist/core/subagent-manager.js +84 -13
- package/dist/core/subagent-manager.js.map +1 -1
- package/dist/core/subagent-manager.test.js +57 -15
- package/dist/core/subagent-manager.test.js.map +1 -1
- package/dist/core/subagent-store.test.js +3 -3
- package/dist/core/task-store.js +1 -1
- package/dist/core/verification-evidence.d.ts +17 -0
- package/dist/core/verification-evidence.d.ts.map +1 -0
- package/dist/core/verification-evidence.js +283 -0
- package/dist/core/verification-evidence.js.map +1 -0
- package/dist/core/verification-evidence.test.d.ts +2 -0
- package/dist/core/verification-evidence.test.d.ts.map +1 -0
- package/dist/core/verification-evidence.test.js +103 -0
- package/dist/core/verification-evidence.test.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interactive.d.ts.map +1 -1
- package/dist/interactive.js +17 -3
- package/dist/interactive.js.map +1 -1
- package/dist/modes/acp-mode.d.ts +122 -0
- package/dist/modes/acp-mode.d.ts.map +1 -0
- package/dist/modes/acp-mode.js +1366 -0
- package/dist/modes/acp-mode.js.map +1 -0
- package/dist/modes/acp-mode.test.d.ts +2 -0
- package/dist/modes/acp-mode.test.d.ts.map +1 -0
- package/dist/modes/acp-mode.test.js +1065 -0
- package/dist/modes/acp-mode.test.js.map +1 -0
- package/dist/modes/agent-home-mode.d.ts.map +1 -1
- package/dist/modes/agent-home-mode.js +15 -11
- package/dist/modes/agent-home-mode.js.map +1 -1
- package/dist/modes/index.d.ts +1 -0
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js +1 -0
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/json-mode.d.ts +36 -0
- package/dist/modes/json-mode.d.ts.map +1 -1
- package/dist/modes/json-mode.js +39 -0
- package/dist/modes/json-mode.js.map +1 -1
- package/dist/modes/json-mode.test.d.ts +2 -0
- package/dist/modes/json-mode.test.d.ts.map +1 -0
- package/dist/modes/json-mode.test.js +84 -0
- package/dist/modes/json-mode.test.js.map +1 -0
- package/dist/modes/serve-mode.d.ts +1 -1
- package/dist/modes/serve-mode.d.ts.map +1 -1
- package/dist/modes/serve-mode.js +14 -9
- package/dist/modes/serve-mode.js.map +1 -1
- package/dist/modes/subagent-worker-mode.d.ts +8 -0
- package/dist/modes/subagent-worker-mode.d.ts.map +1 -1
- package/dist/modes/subagent-worker-mode.js +91 -11
- package/dist/modes/subagent-worker-mode.js.map +1 -1
- package/dist/modes/subagent-worker-mode.test.d.ts +2 -0
- package/dist/modes/subagent-worker-mode.test.d.ts.map +1 -0
- package/dist/modes/subagent-worker-mode.test.js +52 -0
- package/dist/modes/subagent-worker-mode.test.js.map +1 -0
- package/dist/session.d.ts +29 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +41 -0
- package/dist/session.js.map +1 -1
- package/dist/session.test.js +1 -1
- package/dist/system-prompt.d.ts +37 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +123 -11
- package/dist/system-prompt.js.map +1 -1
- package/dist/system-prompt.test.js +90 -11
- package/dist/system-prompt.test.js.map +1 -1
- package/dist/system-prompt.tiering.test.d.ts +2 -0
- package/dist/system-prompt.tiering.test.d.ts.map +1 -0
- package/dist/system-prompt.tiering.test.js +105 -0
- package/dist/system-prompt.tiering.test.js.map +1 -0
- package/dist/tools/bash.d.ts +2 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +55 -16
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/code-nav.d.ts +30 -0
- package/dist/tools/code-nav.d.ts.map +1 -0
- package/dist/tools/code-nav.js +320 -0
- package/dist/tools/code-nav.js.map +1 -0
- package/dist/tools/code-nav.test.d.ts +2 -0
- package/dist/tools/code-nav.test.d.ts.map +1 -0
- package/dist/tools/code-nav.test.js +136 -0
- package/dist/tools/code-nav.test.js.map +1 -0
- package/dist/tools/edit.test.js +1 -1
- package/dist/tools/generate-image.d.ts +1 -1
- package/dist/tools/goals.d.ts +4 -4
- package/dist/tools/goals.test.js +2 -2
- package/dist/tools/grep-parity.test.d.ts +2 -0
- package/dist/tools/grep-parity.test.d.ts.map +1 -0
- package/dist/tools/grep-parity.test.js +92 -0
- package/dist/tools/grep-parity.test.js.map +1 -0
- package/dist/tools/grep-recall.test.d.ts +2 -0
- package/dist/tools/grep-recall.test.d.ts.map +1 -0
- package/dist/tools/grep-recall.test.js +114 -0
- package/dist/tools/grep-recall.test.js.map +1 -0
- package/dist/tools/grep-spawn.test.d.ts +2 -0
- package/dist/tools/grep-spawn.test.d.ts.map +1 -0
- package/dist/tools/grep-spawn.test.js +66 -0
- package/dist/tools/grep-spawn.test.js.map +1 -0
- package/dist/tools/grep.d.ts +13 -3
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +342 -41
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/grep.test.js +17 -14
- package/dist/tools/grep.test.js.map +1 -1
- package/dist/tools/index.d.ts +20 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +28 -18
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/index.test.d.ts +2 -0
- package/dist/tools/index.test.d.ts.map +1 -0
- package/dist/tools/index.test.js +55 -0
- package/dist/tools/index.test.js.map +1 -0
- package/dist/tools/plan-mode.test.js +1 -1
- package/dist/tools/prompt-hints.d.ts +9 -0
- package/dist/tools/prompt-hints.d.ts.map +1 -1
- package/dist/tools/prompt-hints.js +61 -8
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/read-only-bash.d.ts +3 -0
- package/dist/tools/read-only-bash.d.ts.map +1 -1
- package/dist/tools/read-only-bash.js +7 -9
- package/dist/tools/read-only-bash.js.map +1 -1
- package/dist/tools/safe-env.js +1 -1
- package/dist/tools/search-code.d.ts.map +1 -1
- package/dist/tools/search-code.js +7 -6
- package/dist/tools/search-code.js.map +1 -1
- package/dist/tools/search-code.test.js +8 -2
- package/dist/tools/search-code.test.js.map +1 -1
- package/dist/tools/skill.js +2 -1
- package/dist/tools/skill.js.map +1 -1
- package/dist/tools/subagent-control.d.ts.map +1 -1
- package/dist/tools/subagent-control.js +25 -6
- package/dist/tools/subagent-control.js.map +1 -1
- package/dist/tools/subagent-control.test.js +34 -1
- package/dist/tools/subagent-control.test.js.map +1 -1
- package/dist/tools/subagent-shared.d.ts +26 -1
- package/dist/tools/subagent-shared.d.ts.map +1 -1
- package/dist/tools/subagent-shared.js +40 -7
- package/dist/tools/subagent-shared.js.map +1 -1
- package/dist/tools/subagent-shared.test.js +43 -9
- package/dist/tools/subagent-shared.test.js.map +1 -1
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +54 -16
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/subagent.test.js +68 -3
- package/dist/tools/subagent.test.js.map +1 -1
- package/dist/tools/task-output.d.ts.map +1 -1
- package/dist/tools/task-output.js +3 -1
- package/dist/tools/task-output.js.map +1 -1
- package/dist/tools/task-send.test.js +19 -10
- package/dist/tools/task-send.test.js.map +1 -1
- package/dist/tools/tool-search.d.ts +12 -1
- package/dist/tools/tool-search.d.ts.map +1 -1
- package/dist/tools/tool-search.js +24 -4
- package/dist/tools/tool-search.js.map +1 -1
- package/dist/tools/tool-search.test.d.ts +2 -0
- package/dist/tools/tool-search.test.d.ts.map +1 -0
- package/dist/tools/tool-search.test.js +69 -0
- package/dist/tools/tool-search.test.js.map +1 -0
- package/dist/tools/tool-tiers.d.ts +42 -0
- package/dist/tools/tool-tiers.d.ts.map +1 -0
- package/dist/tools/tool-tiers.js +78 -0
- package/dist/tools/tool-tiers.js.map +1 -0
- package/dist/tools/tool-tiers.test.d.ts +2 -0
- package/dist/tools/tool-tiers.test.d.ts.map +1 -0
- package/dist/tools/tool-tiers.test.js +48 -0
- package/dist/tools/tool-tiers.test.js.map +1 -0
- package/dist/tools/web-fetch.d.ts +1 -1
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +5 -2
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/tools/write.test.js +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +27 -1
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/Banner.d.ts.map +1 -1
- package/dist/ui/components/Banner.js +24 -16
- package/dist/ui/components/Banner.js.map +1 -1
- package/dist/ui/components/ToolExecution.js +42 -34
- package/dist/ui/components/ToolExecution.js.map +1 -1
- package/dist/ui/components/force-color.d.ts +2 -0
- package/dist/ui/components/force-color.d.ts.map +1 -0
- package/dist/ui/components/force-color.js +11 -0
- package/dist/ui/components/force-color.js.map +1 -0
- package/dist/ui/components/themed-output.test.d.ts +2 -0
- package/dist/ui/components/themed-output.test.d.ts.map +1 -0
- package/dist/ui/components/themed-output.test.js +111 -0
- package/dist/ui/components/themed-output.test.js.map +1 -0
- package/dist/ui/error-item.d.ts +1 -1
- package/dist/ui/error-item.js +3 -3
- package/dist/ui/error-item.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts +3 -0
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +45 -6
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/ui/login.js +1 -1
- package/dist/ui/login.js.map +1 -1
- package/dist/ui/render.d.ts +1 -1
- package/dist/ui/render.js +6 -6
- package/dist/ui/theme/dark-ansi.json +6 -0
- package/dist/ui/theme/dark-daltonized.json +6 -0
- package/dist/ui/theme/dark.json +6 -0
- package/dist/ui/theme/light-ansi.json +6 -0
- package/dist/ui/theme/light-daltonized.json +6 -0
- package/dist/ui/theme/light.json +6 -0
- package/dist/ui/theme/theme.d.ts +6 -0
- package/dist/ui/theme/theme.d.ts.map +1 -1
- package/dist/ui/tui-terminal-recorder.test.js +1 -1
- package/dist/utils/git.test.js +3 -3
- package/dist/utils/github.test.js +3 -3
- package/dist/utils/github.test.js.map +1 -1
- package/dist/utils/image.d.ts +26 -3
- package/dist/utils/image.d.ts.map +1 -1
- package/dist/utils/image.js +83 -14
- package/dist/utils/image.js.map +1 -1
- package/dist/utils/image.test.d.ts +2 -0
- package/dist/utils/image.test.d.ts.map +1 -0
- package/dist/utils/image.test.js +139 -0
- package/dist/utils/image.test.js.map +1 -0
- package/package.json +7 -6
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { selectMessagesInBudget } from "./compactor.js";
|
|
3
|
+
import { estimateConversationTokens } from "./token-estimator.js";
|
|
4
|
+
import { findLatestHumanQuery, selectQueryAwareContext } from "./query-aware-selector.js";
|
|
5
|
+
function message(role, content) {
|
|
6
|
+
return { role, content };
|
|
7
|
+
}
|
|
8
|
+
describe("selectQueryAwareContext", () => {
|
|
9
|
+
it("keeps older evidence relevant to the latest request ahead of unrelated recent context", () => {
|
|
10
|
+
const messages = [
|
|
11
|
+
message("user", "Build the account settings flow."),
|
|
12
|
+
message("assistant", "AuthService validates the OAuth callback verifier in src/auth/callback.ts."),
|
|
13
|
+
message("assistant", "Adjusted unrelated dashboard colors and spacing."),
|
|
14
|
+
message("user", "Fix the OAuth callback verifier mismatch in AuthService."),
|
|
15
|
+
];
|
|
16
|
+
const budget = estimateConversationTokens([messages[0], messages[1], messages[3]]);
|
|
17
|
+
const result = selectQueryAwareContext(messages, "Fix the OAuth callback verifier mismatch in AuthService.", budget, { fallback: selectMessagesInBudget });
|
|
18
|
+
expect(result.strategy).toBe("query_aware");
|
|
19
|
+
expect(result.messages).toEqual([messages[0], messages[1], messages[3]]);
|
|
20
|
+
expect(result.messages).not.toContain(messages[2]);
|
|
21
|
+
});
|
|
22
|
+
it("never exceeds the hard token budget", () => {
|
|
23
|
+
const messages = [
|
|
24
|
+
message("user", `Original request ${"a".repeat(1_000)}`),
|
|
25
|
+
message("assistant", `OAuth callback evidence ${"b".repeat(1_000)}`),
|
|
26
|
+
message("assistant", `OAuth verifier definition ${"c".repeat(1_000)}`),
|
|
27
|
+
message("user", "Investigate the OAuth verifier."),
|
|
28
|
+
];
|
|
29
|
+
const budget = 320;
|
|
30
|
+
const result = selectQueryAwareContext(messages, "Investigate the OAuth verifier.", budget, {
|
|
31
|
+
fallback: selectMessagesInBudget,
|
|
32
|
+
});
|
|
33
|
+
expect(result.selectedTokens).toBeLessThanOrEqual(budget);
|
|
34
|
+
expect(estimateConversationTokens(result.messages)).toBeLessThanOrEqual(budget);
|
|
35
|
+
});
|
|
36
|
+
it("uses the existing selector deterministically when the query has no signal", () => {
|
|
37
|
+
const messages = [
|
|
38
|
+
message("user", "first"),
|
|
39
|
+
message("assistant", "middle"),
|
|
40
|
+
message("user", "latest"),
|
|
41
|
+
];
|
|
42
|
+
const fallback = vi.fn(selectMessagesInBudget);
|
|
43
|
+
const first = selectQueryAwareContext(messages, "please continue", 100, { fallback });
|
|
44
|
+
const second = selectQueryAwareContext(messages, "please continue", 100, { fallback });
|
|
45
|
+
expect(first).toEqual(second);
|
|
46
|
+
expect(first).toMatchObject({ strategy: "fallback", fallbackReason: "empty_query" });
|
|
47
|
+
expect(first.messages).toEqual(selectMessagesInBudget(messages, 100));
|
|
48
|
+
expect(fallback).toHaveBeenCalledTimes(2);
|
|
49
|
+
});
|
|
50
|
+
it("falls back without throwing when retrieval fails or returns invalid rankings", () => {
|
|
51
|
+
const messages = [
|
|
52
|
+
message("user", "Original OAuth request"),
|
|
53
|
+
message("assistant", "OAuth implementation evidence"),
|
|
54
|
+
message("user", "Fix OAuth verifier"),
|
|
55
|
+
];
|
|
56
|
+
const expected = selectMessagesInBudget(messages, 100);
|
|
57
|
+
const failed = selectQueryAwareContext(messages, "Fix OAuth verifier", 100, {
|
|
58
|
+
fallback: selectMessagesInBudget,
|
|
59
|
+
retrieve: () => {
|
|
60
|
+
throw new Error("retriever unavailable");
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
const invalid = selectQueryAwareContext(messages, "Fix OAuth verifier", 100, {
|
|
64
|
+
fallback: selectMessagesInBudget,
|
|
65
|
+
retrieve: () => [{ index: 99, score: 1 }],
|
|
66
|
+
});
|
|
67
|
+
expect(failed).toMatchObject({
|
|
68
|
+
strategy: "fallback",
|
|
69
|
+
fallbackReason: "retrieval_failed",
|
|
70
|
+
messages: expected,
|
|
71
|
+
});
|
|
72
|
+
expect(invalid).toMatchObject({
|
|
73
|
+
strategy: "fallback",
|
|
74
|
+
fallbackReason: "invalid_ranking",
|
|
75
|
+
messages: expected,
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe("findLatestHumanQuery", () => {
|
|
80
|
+
it("ignores runtime continuation messages", () => {
|
|
81
|
+
const messages = [
|
|
82
|
+
{
|
|
83
|
+
role: "user",
|
|
84
|
+
content: "Fix the OAuth verifier",
|
|
85
|
+
provenance: { source: "human", kind: "prompt", visibility: "transcript" },
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
role: "user",
|
|
89
|
+
content: "Continue after compaction",
|
|
90
|
+
provenance: { source: "runtime", kind: "continuation", visibility: "hidden" },
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
expect(findLatestHumanQuery(messages)).toBe("Fix the OAuth verifier");
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=query-aware-selector.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-aware-selector.test.js","sourceRoot":"","sources":["../../../src/core/compaction/query-aware-selector.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,34 +1,47 @@
|
|
|
1
1
|
import type { Message } from "@prestyj/ai";
|
|
2
2
|
/**
|
|
3
|
-
* Cheap context pruning for stale tool
|
|
3
|
+
* Cheap context pruning for stale tool payloads (opencode-style, no LLM call).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Three signals, one pass:
|
|
6
6
|
* 1. Superseded reads — an old `read` of a file that was re-read later carries
|
|
7
7
|
* zero information; the newest read wins.
|
|
8
8
|
* 2. Old tool-output overflow — walking backwards, the most recent
|
|
9
|
-
* `protectTokens` worth of tool output
|
|
10
|
-
*
|
|
9
|
+
* `protectTokens` worth of tool output plus the last `protectToolBatches`
|
|
10
|
+
* provider tool batches are kept verbatim; anything older is stubbed.
|
|
11
|
+
* 3. Large completed tool arguments — old write/edit payloads are capped once
|
|
12
|
+
* their result has returned; the files and tool result are the durable truth.
|
|
13
|
+
*
|
|
14
|
+
* `PROTECTED_TOOLS` output is never pruned: it is behavioural instruction rather
|
|
15
|
+
* than reproducible data, so a "re-run the tool" stub is not recoverable — the
|
|
16
|
+
* agent has no signal that it ever loaded the skill.
|
|
17
|
+
*
|
|
18
|
+
* Tool batches—not human turns—are the protection boundary. Autonomous research
|
|
19
|
+
* can execute dozens of provider/tool cycles for one user prompt; protecting the
|
|
20
|
+
* whole human turn lets reproducible reads refill the context immediately after
|
|
21
|
+
* compaction.
|
|
11
22
|
*
|
|
12
23
|
* Cache stability: pruning mutates history, which invalidates the provider's
|
|
13
|
-
* prompt-cache prefix
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* Stubs are idempotent (marked with a prefix) and never re-pruned.
|
|
24
|
+
* prompt-cache prefix. To limit churn, nothing is pruned unless at least
|
|
25
|
+
* `minimumTokens` would be freed in one batch. Stubs and compacted arguments are
|
|
26
|
+
* idempotent, so later passes leave the rewritten prefix stable.
|
|
17
27
|
*/
|
|
18
28
|
export declare const PRUNE_PROTECT_TOKENS = 40000;
|
|
19
29
|
export declare const PRUNE_MINIMUM_TOKENS = 20000;
|
|
20
|
-
export declare const
|
|
30
|
+
export declare const PRUNE_PROTECT_TOOL_BATCHES = 2;
|
|
31
|
+
/** Tools whose output is instruction, not reproducible data — never pruned. */
|
|
32
|
+
export declare const PRUNE_PROTECTED_TOOLS: Set<string>;
|
|
21
33
|
export interface PruneOptions {
|
|
22
34
|
/** Recent tool-output token budget kept verbatim. Default 40k. */
|
|
23
35
|
protectTokens?: number;
|
|
24
36
|
/** Minimum freed tokens required to apply a prune batch. Default 20k. */
|
|
25
37
|
minimumTokens?: number;
|
|
26
|
-
/** Number of most-recent
|
|
27
|
-
|
|
38
|
+
/** Number of most-recent provider tool batches never pruned. Default 2. */
|
|
39
|
+
protectToolBatches?: number;
|
|
28
40
|
}
|
|
29
41
|
export interface PruneResult {
|
|
30
42
|
pruned: boolean;
|
|
31
43
|
prunedResults: number;
|
|
44
|
+
compactedToolCalls: number;
|
|
32
45
|
freedTokens: number;
|
|
33
46
|
}
|
|
34
47
|
/** Mutates `messages` in place; message/array identity is preserved so usage
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-result-pruner.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/tool-result-pruner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"tool-result-pruner.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/tool-result-pruner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,OAAO,EAAc,MAAM,aAAa,CAAC;AAIpE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAC3C,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAC3C,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C,+EAA+E;AAC/E,eAAO,MAAM,qBAAqB,aAAqB,CAAC;AAWxD,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAeD;iEACiE;AACjE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,IAAI,GAAE,YAAiB,GAAG,WAAW,CA+I/F"}
|
|
@@ -1,30 +1,50 @@
|
|
|
1
|
+
import { compactHistoricalToolCallArgs } from "./compactor.js";
|
|
1
2
|
import { estimateTokens } from "./token-estimator.js";
|
|
2
3
|
/**
|
|
3
|
-
* Cheap context pruning for stale tool
|
|
4
|
+
* Cheap context pruning for stale tool payloads (opencode-style, no LLM call).
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
+
* Three signals, one pass:
|
|
6
7
|
* 1. Superseded reads — an old `read` of a file that was re-read later carries
|
|
7
8
|
* zero information; the newest read wins.
|
|
8
9
|
* 2. Old tool-output overflow — walking backwards, the most recent
|
|
9
|
-
* `protectTokens` worth of tool output
|
|
10
|
-
*
|
|
10
|
+
* `protectTokens` worth of tool output plus the last `protectToolBatches`
|
|
11
|
+
* provider tool batches are kept verbatim; anything older is stubbed.
|
|
12
|
+
* 3. Large completed tool arguments — old write/edit payloads are capped once
|
|
13
|
+
* their result has returned; the files and tool result are the durable truth.
|
|
14
|
+
*
|
|
15
|
+
* `PROTECTED_TOOLS` output is never pruned: it is behavioural instruction rather
|
|
16
|
+
* than reproducible data, so a "re-run the tool" stub is not recoverable — the
|
|
17
|
+
* agent has no signal that it ever loaded the skill.
|
|
18
|
+
*
|
|
19
|
+
* Tool batches—not human turns—are the protection boundary. Autonomous research
|
|
20
|
+
* can execute dozens of provider/tool cycles for one user prompt; protecting the
|
|
21
|
+
* whole human turn lets reproducible reads refill the context immediately after
|
|
22
|
+
* compaction.
|
|
11
23
|
*
|
|
12
24
|
* Cache stability: pruning mutates history, which invalidates the provider's
|
|
13
|
-
* prompt-cache prefix
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* Stubs are idempotent (marked with a prefix) and never re-pruned.
|
|
25
|
+
* prompt-cache prefix. To limit churn, nothing is pruned unless at least
|
|
26
|
+
* `minimumTokens` would be freed in one batch. Stubs and compacted arguments are
|
|
27
|
+
* idempotent, so later passes leave the rewritten prefix stable.
|
|
17
28
|
*/
|
|
18
29
|
export const PRUNE_PROTECT_TOKENS = 40_000;
|
|
19
30
|
export const PRUNE_MINIMUM_TOKENS = 20_000;
|
|
20
|
-
export const
|
|
31
|
+
export const PRUNE_PROTECT_TOOL_BATCHES = 2;
|
|
32
|
+
/** Tools whose output is instruction, not reproducible data — never pruned. */
|
|
33
|
+
export const PRUNE_PROTECTED_TOOLS = new Set(["skill"]);
|
|
21
34
|
const PRUNE_MARKER = "[Pruned:";
|
|
35
|
+
/**
|
|
36
|
+
* Prefix of the token-overflow stub specifically. Reaching one of these while
|
|
37
|
+
* walking backwards proves the whole older prefix was already considered, which
|
|
38
|
+
* a superseded-read stub does NOT prove — read dedup fires independently of the
|
|
39
|
+
* token budget, so an older verbatim result can sit behind one.
|
|
40
|
+
*/
|
|
41
|
+
const PRUNE_OVERFLOW_MARKER = `${PRUNE_MARKER} old tool output`;
|
|
22
42
|
/** Mutates `messages` in place; message/array identity is preserved so usage
|
|
23
43
|
* anchors and React refs stay valid. Returns what was freed. */
|
|
24
44
|
export function pruneStaleToolResults(messages, opts = {}) {
|
|
25
45
|
const protectTokens = opts.protectTokens ?? PRUNE_PROTECT_TOKENS;
|
|
26
46
|
const minimumTokens = opts.minimumTokens ?? PRUNE_MINIMUM_TOKENS;
|
|
27
|
-
const
|
|
47
|
+
const protectToolBatches = opts.protectToolBatches ?? PRUNE_PROTECT_TOOL_BATCHES;
|
|
28
48
|
// toolCallId → tool name + args (for read-dedup path identification).
|
|
29
49
|
const callInfo = new Map();
|
|
30
50
|
for (const msg of messages) {
|
|
@@ -37,22 +57,37 @@ export function pruneStaleToolResults(messages, opts = {}) {
|
|
|
37
57
|
}
|
|
38
58
|
}
|
|
39
59
|
const seenReadPaths = new Set();
|
|
40
|
-
const
|
|
41
|
-
|
|
60
|
+
const resultCandidates = [];
|
|
61
|
+
const toolBatchByCallId = new Map();
|
|
62
|
+
let recentToolBatches = 0;
|
|
42
63
|
let recentToolTokens = 0;
|
|
43
|
-
for (let msgIndex = messages.length - 1; msgIndex >= 0; msgIndex--) {
|
|
64
|
+
scan: for (let msgIndex = messages.length - 1; msgIndex >= 0; msgIndex--) {
|
|
44
65
|
const msg = messages[msgIndex];
|
|
45
|
-
if (msg.role === "user")
|
|
46
|
-
userTurns++;
|
|
47
66
|
if (msg.role !== "tool" || !Array.isArray(msg.content))
|
|
48
67
|
continue;
|
|
68
|
+
recentToolBatches++;
|
|
69
|
+
const protectedBatch = recentToolBatches <= protectToolBatches;
|
|
49
70
|
for (let partIndex = msg.content.length - 1; partIndex >= 0; partIndex--) {
|
|
50
71
|
const result = msg.content[partIndex];
|
|
51
|
-
if (result.type !== "tool_result"
|
|
72
|
+
if (result.type !== "tool_result")
|
|
73
|
+
continue;
|
|
74
|
+
toolBatchByCallId.set(result.toolCallId, recentToolBatches);
|
|
75
|
+
if (typeof result.content !== "string")
|
|
52
76
|
continue;
|
|
53
|
-
|
|
77
|
+
// An overflow stub outside the protect zone means an earlier pass blew
|
|
78
|
+
// the token budget here and pruned every prunable result older than it in
|
|
79
|
+
// that same batch. History only grows at the tail, so nothing older can
|
|
80
|
+
// have become prunable since: stop instead of re-scanning the whole
|
|
81
|
+
// transcript every turn. Other stub kinds prove nothing about what lies
|
|
82
|
+
// behind them, so they are merely skipped.
|
|
83
|
+
if (result.content.startsWith(PRUNE_MARKER)) {
|
|
84
|
+
if (!protectedBatch && result.content.startsWith(PRUNE_OVERFLOW_MARKER))
|
|
85
|
+
break scan;
|
|
54
86
|
continue;
|
|
87
|
+
}
|
|
55
88
|
const info = callInfo.get(result.toolCallId);
|
|
89
|
+
if (info && PRUNE_PROTECTED_TOOLS.has(info.name))
|
|
90
|
+
continue;
|
|
56
91
|
// Dedup key includes the range: a partial read (offset/limit) covers
|
|
57
92
|
// different content than a full read or another range, so only an
|
|
58
93
|
// identical path+range read supersedes an older one.
|
|
@@ -62,13 +97,12 @@ export function pruneStaleToolResults(messages, opts = {}) {
|
|
|
62
97
|
const readKey = readPath !== undefined
|
|
63
98
|
? `${readPath}#${String(info?.args.offset ?? "")}:${String(info?.args.limit ?? "")}`
|
|
64
99
|
: undefined;
|
|
65
|
-
const protectedTurn = userTurns < protectTurns;
|
|
66
100
|
// Newest read of each path+range wins — remember it even inside the
|
|
67
101
|
// protect zone so an older duplicate outside the zone still counts as
|
|
68
102
|
// superseded.
|
|
69
103
|
if (readKey !== undefined) {
|
|
70
|
-
if (seenReadPaths.has(readKey) && !
|
|
71
|
-
|
|
104
|
+
if (seenReadPaths.has(readKey) && !protectedBatch) {
|
|
105
|
+
resultCandidates.push({
|
|
72
106
|
result,
|
|
73
107
|
freedTokens: estimateTokens(result.content),
|
|
74
108
|
stub: `${PRUNE_MARKER} this read of ${readPath} was superseded by a newer read later in the conversation.]`,
|
|
@@ -77,13 +111,13 @@ export function pruneStaleToolResults(messages, opts = {}) {
|
|
|
77
111
|
}
|
|
78
112
|
seenReadPaths.add(readKey);
|
|
79
113
|
}
|
|
80
|
-
if (
|
|
114
|
+
if (protectedBatch)
|
|
81
115
|
continue;
|
|
82
116
|
const resultTokens = estimateTokens(result.content);
|
|
83
117
|
recentToolTokens += resultTokens;
|
|
84
118
|
if (recentToolTokens <= protectTokens)
|
|
85
119
|
continue;
|
|
86
|
-
|
|
120
|
+
resultCandidates.push({
|
|
87
121
|
result,
|
|
88
122
|
freedTokens: resultTokens,
|
|
89
123
|
stub: `${PRUNE_MARKER} old tool output (${result.content.length} chars) removed to save ` +
|
|
@@ -91,13 +125,51 @@ export function pruneStaleToolResults(messages, opts = {}) {
|
|
|
91
125
|
});
|
|
92
126
|
}
|
|
93
127
|
}
|
|
94
|
-
|
|
128
|
+
// Completed write/edit-style calls can carry entire files in their arguments.
|
|
129
|
+
// Once outside the protected batches, cap those payloads before they alone can
|
|
130
|
+
// trigger an LLM compaction. Unresolved calls are deliberately left untouched.
|
|
131
|
+
const toolArgCandidates = [];
|
|
132
|
+
for (const message of messages) {
|
|
133
|
+
if (message.role !== "assistant" || !Array.isArray(message.content))
|
|
134
|
+
continue;
|
|
135
|
+
const compactedMessage = compactHistoricalToolCallArgs([message], (toolCallId) => {
|
|
136
|
+
const batch = toolBatchByCallId.get(toolCallId);
|
|
137
|
+
return batch !== undefined && batch > protectToolBatches;
|
|
138
|
+
})[0];
|
|
139
|
+
if (compactedMessage === message)
|
|
140
|
+
continue;
|
|
141
|
+
const originalContent = message.content;
|
|
142
|
+
const compactedContent = compactedMessage.content;
|
|
143
|
+
const originalTokens = estimateTokens(JSON.stringify(originalContent));
|
|
144
|
+
const compactedTokens = estimateTokens(JSON.stringify(compactedContent));
|
|
145
|
+
const compactedToolCalls = compactedContent.filter((part, index) => part !== originalContent[index]).length;
|
|
146
|
+
toolArgCandidates.push({
|
|
147
|
+
message,
|
|
148
|
+
content: compactedMessage.content,
|
|
149
|
+
compactedToolCalls,
|
|
150
|
+
freedTokens: Math.max(0, originalTokens - compactedTokens),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
const freedTokens = [...resultCandidates, ...toolArgCandidates].reduce((sum, candidate) => sum + candidate.freedTokens, 0);
|
|
95
154
|
if (freedTokens < minimumTokens) {
|
|
96
|
-
return {
|
|
155
|
+
return {
|
|
156
|
+
pruned: false,
|
|
157
|
+
prunedResults: 0,
|
|
158
|
+
compactedToolCalls: 0,
|
|
159
|
+
freedTokens: 0,
|
|
160
|
+
};
|
|
97
161
|
}
|
|
98
|
-
for (const candidate of
|
|
162
|
+
for (const candidate of resultCandidates) {
|
|
99
163
|
candidate.result.content = candidate.stub;
|
|
100
164
|
}
|
|
101
|
-
|
|
165
|
+
for (const candidate of toolArgCandidates) {
|
|
166
|
+
candidate.message.content = candidate.content;
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
pruned: true,
|
|
170
|
+
prunedResults: resultCandidates.length,
|
|
171
|
+
compactedToolCalls: toolArgCandidates.reduce((sum, candidate) => sum + candidate.compactedToolCalls, 0),
|
|
172
|
+
freedTokens,
|
|
173
|
+
};
|
|
102
174
|
}
|
|
103
175
|
//# sourceMappingURL=tool-result-pruner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-result-pruner.js","sourceRoot":"","sources":["../../../src/core/compaction/tool-result-pruner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD
|
|
1
|
+
{"version":3,"file":"tool-result-pruner.js","sourceRoot":"","sources":["../../../src/core/compaction/tool-result-pruner.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,8 +17,19 @@ function resultOf(messages, toolCallId) {
|
|
|
17
17
|
}
|
|
18
18
|
throw new Error(`missing tool result ${toolCallId}`);
|
|
19
19
|
}
|
|
20
|
+
function callOf(messages, toolCallId) {
|
|
21
|
+
for (const msg of messages) {
|
|
22
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.content))
|
|
23
|
+
continue;
|
|
24
|
+
for (const part of msg.content) {
|
|
25
|
+
if (part.type === "tool_call" && part.id === toolCallId)
|
|
26
|
+
return part;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
throw new Error(`missing tool call ${toolCallId}`);
|
|
30
|
+
}
|
|
20
31
|
describe("pruneStaleToolResults", () => {
|
|
21
|
-
it("stubs superseded reads outside the
|
|
32
|
+
it("stubs superseded reads outside the protected tool batches", () => {
|
|
22
33
|
const messages = [
|
|
23
34
|
{ role: "user", content: "turn 1" },
|
|
24
35
|
...toolTurn("old-read", "read", { file_path: "src/a.ts" }, "x".repeat(40_000)),
|
|
@@ -27,7 +38,10 @@ describe("pruneStaleToolResults", () => {
|
|
|
27
38
|
...toolTurn("new-read", "read", { file_path: "src/a.ts" }, "fresh content"),
|
|
28
39
|
{ role: "user", content: "turn 3" },
|
|
29
40
|
];
|
|
30
|
-
const result = pruneStaleToolResults(messages, {
|
|
41
|
+
const result = pruneStaleToolResults(messages, {
|
|
42
|
+
minimumTokens: 1_000,
|
|
43
|
+
protectToolBatches: 1,
|
|
44
|
+
});
|
|
31
45
|
expect(result.pruned).toBe(true);
|
|
32
46
|
expect(result.prunedResults).toBe(1);
|
|
33
47
|
expect(resultOf(messages, "old-read").content).toContain("superseded by a newer read");
|
|
@@ -63,6 +77,7 @@ describe("pruneStaleToolResults", () => {
|
|
|
63
77
|
const result = pruneStaleToolResults(messages, {
|
|
64
78
|
protectTokens: 10_000,
|
|
65
79
|
minimumTokens: 1_000,
|
|
80
|
+
protectToolBatches: 1,
|
|
66
81
|
});
|
|
67
82
|
expect(result.pruned).toBe(true);
|
|
68
83
|
// "recent" fills the 10k protect budget; "oldest" overflows it.
|
|
@@ -70,7 +85,7 @@ describe("pruneStaleToolResults", () => {
|
|
|
70
85
|
expect(resultOf(messages, "oldest").content).toContain("old tool output");
|
|
71
86
|
expect(resultOf(messages, "oldest").content).toContain("Re-run the tool");
|
|
72
87
|
});
|
|
73
|
-
it("never touches tool output inside the protected recent
|
|
88
|
+
it("never touches tool output inside the protected recent batches", () => {
|
|
74
89
|
const messages = [
|
|
75
90
|
{ role: "user", content: "turn 1" },
|
|
76
91
|
...toolTurn("latest", "bash", { command: "ls" }, "z".repeat(200_000)),
|
|
@@ -82,6 +97,35 @@ describe("pruneStaleToolResults", () => {
|
|
|
82
97
|
expect(result.pruned).toBe(false);
|
|
83
98
|
expect(resultOf(messages, "latest").content).toBe("z".repeat(200_000));
|
|
84
99
|
});
|
|
100
|
+
it("caps large completed tool arguments outside the protected batches", () => {
|
|
101
|
+
const oldContent = "old".repeat(40_000);
|
|
102
|
+
const recentContent = "recent".repeat(20_000);
|
|
103
|
+
const messages = [
|
|
104
|
+
{ role: "user", content: "implement several files" },
|
|
105
|
+
...toolTurn("old-write", "write", { file_path: "old.ts", content: oldContent }, "ok"),
|
|
106
|
+
...toolTurn("recent-write", "write", { file_path: "recent.ts", content: recentContent }, "ok"),
|
|
107
|
+
...toolTurn("latest", "grep", { pattern: "done" }, "done"),
|
|
108
|
+
];
|
|
109
|
+
const first = pruneStaleToolResults(messages, {
|
|
110
|
+
protectTokens: 100_000,
|
|
111
|
+
minimumTokens: 1,
|
|
112
|
+
protectToolBatches: 2,
|
|
113
|
+
});
|
|
114
|
+
const compacted = callOf(messages, "old-write").args.content;
|
|
115
|
+
expect(first.pruned).toBe(true);
|
|
116
|
+
expect(first.prunedResults).toBe(0);
|
|
117
|
+
expect(first.compactedToolCalls).toBe(1);
|
|
118
|
+
expect(compacted.length).toBeLessThan(oldContent.length);
|
|
119
|
+
expect(compacted).toContain("more characters truncated");
|
|
120
|
+
expect(callOf(messages, "recent-write").args.content).toBe(recentContent);
|
|
121
|
+
const second = pruneStaleToolResults(messages, {
|
|
122
|
+
protectTokens: 100_000,
|
|
123
|
+
minimumTokens: 1,
|
|
124
|
+
protectToolBatches: 2,
|
|
125
|
+
});
|
|
126
|
+
expect(second.pruned).toBe(false);
|
|
127
|
+
expect(callOf(messages, "old-write").args.content).toBe(compacted);
|
|
128
|
+
});
|
|
85
129
|
it("holds the batch until the minimum freed-token threshold is met", () => {
|
|
86
130
|
const messages = [
|
|
87
131
|
{ role: "user", content: "turn 1" },
|
|
@@ -92,10 +136,57 @@ describe("pruneStaleToolResults", () => {
|
|
|
92
136
|
const result = pruneStaleToolResults(messages, {
|
|
93
137
|
protectTokens: 100,
|
|
94
138
|
minimumTokens: 20_000,
|
|
139
|
+
protectToolBatches: 0,
|
|
95
140
|
});
|
|
96
141
|
expect(result.pruned).toBe(false);
|
|
97
142
|
expect(resultOf(messages, "small").content).toBe("s".repeat(2_000));
|
|
98
143
|
});
|
|
144
|
+
it("bounds tool output during one long autonomous user turn", () => {
|
|
145
|
+
const messages = [{ role: "user", content: "research then implement" }];
|
|
146
|
+
for (let batch = 1; batch <= 12; batch++) {
|
|
147
|
+
messages.push(...toolTurn(`batch-${batch}`, "read", { file_path: `repo/${batch}.ts` }, "x".repeat(100_000)));
|
|
148
|
+
pruneStaleToolResults(messages, {
|
|
149
|
+
protectTokens: 40_000,
|
|
150
|
+
minimumTokens: 20_000,
|
|
151
|
+
protectToolBatches: 2,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const verbatimResults = Array.from({ length: 12 }, (_, index) => resultOf(messages, `batch-${index + 1}`)).filter((result) => !result.content.toString().startsWith("[Pruned:"));
|
|
155
|
+
// Two protected batches plus one older result fitting inside the 40k-token budget.
|
|
156
|
+
expect(verbatimResults).toHaveLength(3);
|
|
157
|
+
expect(resultOf(messages, "batch-10").content).toBe("x".repeat(100_000));
|
|
158
|
+
expect(resultOf(messages, "batch-11").content).toBe("x".repeat(100_000));
|
|
159
|
+
expect(resultOf(messages, "batch-12").content).toBe("x".repeat(100_000));
|
|
160
|
+
expect(resultOf(messages, "batch-1").content).toContain("old tool output");
|
|
161
|
+
});
|
|
162
|
+
it("treats parallel tool results as one provider batch", () => {
|
|
163
|
+
const messages = [
|
|
164
|
+
{ role: "user", content: "research in parallel" },
|
|
165
|
+
{
|
|
166
|
+
role: "assistant",
|
|
167
|
+
content: [
|
|
168
|
+
{ type: "tool_call", id: "parallel-a", name: "grep", args: { pattern: "a" } },
|
|
169
|
+
{ type: "tool_call", id: "parallel-b", name: "grep", args: { pattern: "b" } },
|
|
170
|
+
],
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
role: "tool",
|
|
174
|
+
content: [
|
|
175
|
+
{ type: "tool_result", toolCallId: "parallel-a", content: "a".repeat(100_000) },
|
|
176
|
+
{ type: "tool_result", toolCallId: "parallel-b", content: "b".repeat(100_000) },
|
|
177
|
+
],
|
|
178
|
+
},
|
|
179
|
+
...toolTurn("latest", "read", { file_path: "src/latest.ts" }, "latest"),
|
|
180
|
+
];
|
|
181
|
+
const result = pruneStaleToolResults(messages, {
|
|
182
|
+
protectTokens: 1,
|
|
183
|
+
minimumTokens: 1,
|
|
184
|
+
protectToolBatches: 2,
|
|
185
|
+
});
|
|
186
|
+
expect(result.pruned).toBe(false);
|
|
187
|
+
expect(resultOf(messages, "parallel-a").content).toBe("a".repeat(100_000));
|
|
188
|
+
expect(resultOf(messages, "parallel-b").content).toBe("b".repeat(100_000));
|
|
189
|
+
});
|
|
99
190
|
it("is idempotent: stubs are never re-pruned or re-counted", () => {
|
|
100
191
|
const messages = [
|
|
101
192
|
{ role: "user", content: "turn 1" },
|
|
@@ -103,13 +194,90 @@ describe("pruneStaleToolResults", () => {
|
|
|
103
194
|
{ role: "user", content: "turn 2" },
|
|
104
195
|
{ role: "user", content: "turn 3" },
|
|
105
196
|
];
|
|
106
|
-
const first = pruneStaleToolResults(messages, {
|
|
197
|
+
const first = pruneStaleToolResults(messages, {
|
|
198
|
+
protectTokens: 100,
|
|
199
|
+
minimumTokens: 1_000,
|
|
200
|
+
protectToolBatches: 0,
|
|
201
|
+
});
|
|
107
202
|
const stub = resultOf(messages, "old").content;
|
|
108
|
-
const second = pruneStaleToolResults(messages, {
|
|
203
|
+
const second = pruneStaleToolResults(messages, {
|
|
204
|
+
protectTokens: 100,
|
|
205
|
+
minimumTokens: 1,
|
|
206
|
+
protectToolBatches: 0,
|
|
207
|
+
});
|
|
109
208
|
expect(first.pruned).toBe(true);
|
|
110
209
|
expect(second.pruned).toBe(false);
|
|
111
210
|
expect(resultOf(messages, "old").content).toBe(stub);
|
|
112
211
|
});
|
|
212
|
+
it("never prunes skill output, which is instruction rather than reproducible data", () => {
|
|
213
|
+
const messages = [
|
|
214
|
+
{ role: "user", content: "turn 1" },
|
|
215
|
+
...toolTurn("skill-load", "skill", { skill: "evidence-led-ui" }, "s".repeat(120_000)),
|
|
216
|
+
{ role: "user", content: "turn 2" },
|
|
217
|
+
...toolTurn("old-bash", "bash", { command: "ls" }, "o".repeat(120_000)),
|
|
218
|
+
{ role: "user", content: "turn 3" },
|
|
219
|
+
{ role: "user", content: "turn 4" },
|
|
220
|
+
];
|
|
221
|
+
const result = pruneStaleToolResults(messages, {
|
|
222
|
+
protectTokens: 100,
|
|
223
|
+
minimumTokens: 1_000,
|
|
224
|
+
protectToolBatches: 0,
|
|
225
|
+
});
|
|
226
|
+
expect(result.pruned).toBe(true);
|
|
227
|
+
expect(result.prunedResults).toBe(1);
|
|
228
|
+
expect(resultOf(messages, "skill-load").content).toBe("s".repeat(120_000));
|
|
229
|
+
expect(resultOf(messages, "old-bash").content).toContain("old tool output");
|
|
230
|
+
});
|
|
231
|
+
it("stops scanning at the first stub outside the protected batches", () => {
|
|
232
|
+
const messages = [
|
|
233
|
+
{ role: "user", content: "turn 1" },
|
|
234
|
+
...toolTurn("oldest", "bash", { command: "ls" }, "o".repeat(120_000)),
|
|
235
|
+
{ role: "user", content: "turn 2" },
|
|
236
|
+
...toolTurn("middle", "bash", { command: "pwd" }, "m".repeat(120_000)),
|
|
237
|
+
{ role: "user", content: "turn 3" },
|
|
238
|
+
];
|
|
239
|
+
const opts = { protectTokens: 100, minimumTokens: 1_000, protectToolBatches: 0 };
|
|
240
|
+
expect(pruneStaleToolResults(messages, opts).prunedResults).toBe(2);
|
|
241
|
+
// Fresh output arrives; the older half is already stubbed, so the second
|
|
242
|
+
// pass must stop at "middle" rather than re-walking the whole transcript.
|
|
243
|
+
messages.push(...toolTurn("newest", "bash", { command: "env" }, "n".repeat(120_000)));
|
|
244
|
+
const second = pruneStaleToolResults(messages, opts);
|
|
245
|
+
expect(second.pruned).toBe(true);
|
|
246
|
+
expect(second.prunedResults).toBe(1);
|
|
247
|
+
expect(resultOf(messages, "newest").content).toContain("old tool output");
|
|
248
|
+
expect(resultOf(messages, "oldest").content).toContain("old tool output");
|
|
249
|
+
});
|
|
250
|
+
it("does not let a superseded-read stub strand older output behind it", () => {
|
|
251
|
+
// A read dedup stub is written regardless of the token budget, so it can
|
|
252
|
+
// sit in front of results that are still verbatim. Stopping the backwards
|
|
253
|
+
// walk at one would strand them permanently.
|
|
254
|
+
const messages = [
|
|
255
|
+
{ role: "user", content: "turn 1" },
|
|
256
|
+
...toolTurn("old-bash", "bash", { command: "ls" }, "o".repeat(400_000)),
|
|
257
|
+
{ role: "user", content: "turn 2" },
|
|
258
|
+
...toolTurn("read-1", "read", { file_path: "/a.ts" }, "a".repeat(1_000)),
|
|
259
|
+
{ role: "user", content: "turn 3" },
|
|
260
|
+
...toolTurn("read-2", "read", { file_path: "/a.ts" }, "a".repeat(1_000)),
|
|
261
|
+
{ role: "user", content: "turn 4" },
|
|
262
|
+
];
|
|
263
|
+
// A protect budget this large spares the bash output, so only the
|
|
264
|
+
// superseded read is stubbed on the first pass.
|
|
265
|
+
const first = pruneStaleToolResults(messages, {
|
|
266
|
+
protectTokens: 500_000,
|
|
267
|
+
minimumTokens: 100,
|
|
268
|
+
protectToolBatches: 0,
|
|
269
|
+
});
|
|
270
|
+
expect(first.prunedResults).toBe(1);
|
|
271
|
+
expect(resultOf(messages, "old-bash").content).toBe("o".repeat(400_000));
|
|
272
|
+
// Now the budget is tight: the older bash output must still be reachable.
|
|
273
|
+
const second = pruneStaleToolResults(messages, {
|
|
274
|
+
protectTokens: 100,
|
|
275
|
+
minimumTokens: 1_000,
|
|
276
|
+
protectToolBatches: 0,
|
|
277
|
+
});
|
|
278
|
+
expect(second.pruned).toBe(true);
|
|
279
|
+
expect(resultOf(messages, "old-bash").content).toContain("old tool output");
|
|
280
|
+
});
|
|
113
281
|
it("skips structured (non-string) tool results", () => {
|
|
114
282
|
const messages = [
|
|
115
283
|
{ role: "user", content: "turn 1" },
|
|
@@ -140,7 +308,11 @@ describe("pruneStaleToolResults", () => {
|
|
|
140
308
|
];
|
|
141
309
|
const anchor = messages[3];
|
|
142
310
|
const toolMsg = messages[2];
|
|
143
|
-
pruneStaleToolResults(messages, {
|
|
311
|
+
pruneStaleToolResults(messages, {
|
|
312
|
+
protectTokens: 100,
|
|
313
|
+
minimumTokens: 1_000,
|
|
314
|
+
protectToolBatches: 0,
|
|
315
|
+
});
|
|
144
316
|
expect(messages[3]).toBe(anchor);
|
|
145
317
|
expect(messages[2]).toBe(toolMsg);
|
|
146
318
|
});
|