Compress tool output to reduce token usage#5106
Open
meganrogge wants to merge 3 commits intomainfrom
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces an opt-in post-processing layer that compresses tool results (initially focused on run_in_terminal) before they are forwarded to the language model, aiming to reduce token usage while preserving tool semantics where possible.
Changes:
- Added a new
IToolResultCompressorservice with a filter registry and telemetry reporting of compression savings. - Implemented initial terminal output compressors for
git diff/show,ls -l/-la, andnpm/yarn/pnpm install, plus unit tests for the terminal filters. - Wired compression into
ToolsService.invokeTooland exposed an (off-by-default) setting to enable it.
Show a summary per file
| File | Description |
|---|---|
| src/platform/configuration/common/configurationService.ts | Adds a new config key for enabling tool result compression. |
| src/extension/tools/vscode-node/toolsService.ts | Integrates compression into tool invocation and registers terminal compressors. |
| src/extension/tools/common/toolResultCompressor.ts | Introduces the compressor service, filter interfaces, and compression + telemetry logic. |
| src/extension/tools/node/compressors/terminalOutputCompressor.ts | Adds initial compression filters for common terminal commands. |
| src/extension/tools/node/test/terminalOutputCompressor.spec.ts | Adds unit tests covering terminal filter matching and transformations. |
| src/extension/extension/vscode-node/services.ts | Registers the new compressor service in the node DI container. |
| package.nls.json | Adds localized setting description text. |
| package.json | Contributes the new setting to VS Code configuration. |
Copilot's findings
- Files reviewed: 8/8 changed files
- Comments generated: 5
- gitDiffFilter: actually accumulate context-line runs and collapse them - toolResultCompressor: disable failing filters for the rest of a pass; warn once - toolResultCompressor: preserve LanguageModelTextPart2 audience when rewriting - toolResultCompressor: rename byte/bytes -> char/chars in telemetry + docs - Add unit tests for ToolResultCompressorService.maybeCompress
roblourens
previously approved these changes
May 5, 2026
git --no-pager diff was being parsed as sub=--no-pager and missing the gitDiffFilter. Now long flags after the head are skipped.
dmitrivMS
approved these changes
May 5, 2026
|
Nice work! Maybe @roblourens or @meganrogge can look at my PR? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a post-processing compression layer for tool results, inspired by ztk. When the model invokes a tool, we now have a chance to filter the result text before it reaches the model — same information, fewer tokens.
What
IToolResultCompressorservice insrc/extension/tools/common/toolResultCompressor.tswith a per-tool filter registry. Filters are pure functions over text parts. The service preserves stderr and exit codes, skips outputs under 80 bytes, and drops any filter that throws (ztk's "never make it worse" rule).run_in_terminalinsrc/extension/tools/node/compressors/terminalOutputCompressor.ts:git diff/git show— collapses unchanged context, dropsindex/similarity indexheaders, omits lockfile and snapshot diff bodies, preserves+/-/@@lines verbatim.ls -l/ls -la— keeps just file names (with/for dirs), drops perm/owner/size columns andtotal N.npm install/yarn/pnpm install— drops progress bars,npm warn deprecated, funding/audit nag lines.ToolsService.invokeToolas a single post-process step right aftervscode.lm.invokeToolresolves. Works for any tool — including the corerun_in_terminal— without core changes.github.copilot.chat.tools.compressOutput.enabled, off by default.toolResultCompressedreporting{ toolName, filters, beforeBytes, afterBytes }so we can quantify savings.Why
The terminal tool routinely dumps tens of thousands of raw tokens (a single
git diff HEAD~5can be 90KB+). Most of that is metadata, unchanged context, lockfile churn, or progress noise. Compressing this client-side before it hits the model is a cheap, predictable token win that doesn't change tool semantics.Tests
12 unit tests in
src/extension/tools/node/test/terminalOutputCompressor.spec.tscovering command parsing, each filter's match logic, and the actual compression behavior. All passing.Scope notes
IToolResultFilterand register it. Future filters: test-runner output,read_fileskeleton mode,grep_searchper-file match cap, session-level dedup cache.