feat(opencode): compress and recover tool outputs - #2819
Open
javargasm wants to merge 6 commits into
Open
Conversation
The OpenCode plugin was a thin delegator that only rewrote bash/shell commands via `rtk rewrite`. But OpenCode's built-in tools (read, grep, glob, task, webfetch) and MCP tools (codegraph, context7, engram, graphify, chrome-devtools, notebooks) never pass through `rtk rewrite` — their output reaches the LLM untouched. Add a `tool.execute.after` hook that compresses those outputs client-side: - Per-tool strategy registry (HEAVY_TOOLS); unlisted tools fall back to truncate-middle so every heavy output is covered. - Strategies: truncate-middle, truncate-tail, json-compact, and rtk-minimal (strips comments, preserves OpenCode's `N:` line prefixes, mirroring `rtk read --level minimal`). - Conservative guards mirroring the Rust core's never_worse: only compress above RTK_TOKEN_THRESHOLD, only apply when it saves >10%. - MCP sink handling: mutate output.content[] (rebuilt into output.output after the hook since OpenCode 458ec7b37); skip mixed/binary content so image and resource attachments are never dropped. - RTK_DEBUG=1 opt-in logging to /tmp/rtk-plugin.log; no I/O by default. Configurable via RTK_TOKEN_THRESHOLD, RTK_MAX_OUTPUT_CHARS, RTK_DEBUG. Document both responsibilities in hooks/opencode/README.md.
No behavior change — output is byte-identical to the previous version (verified with a differential harness over 52 cases: text/JSON/source inputs across every strategy and boundary condition). - Extract magic numbers into named tunables (CHARS_PER_TOKEN, HEAD_RATIO, MIN_SAVINGS_PCT, JSON_* limits) instead of literals scattered inline. - Replace the per-key comment wall in HEAVY_TOOLS with a compact table and a single strategy legend. - Build the comment-style lookup from an extension→style map instead of a long switch; C_STYLE/HASH_STYLE are now shared constants. - Factor the tool-result plumbing into extractText()/writeSink() so the two hooks read top-to-bottom without inline sink juggling. - Share truncationMarker() and tokensFromChars() between strategies. - Fold debug logging into logDebug() (timestamp added there) and gate the hot path on sink presence. Net -37 lines (433 → 396), same embedded-plugin install test coverage.
The registry hard-coded strategies for MCP servers and plugins (codegraph, context7, graphify, chrome-devtools, notebooks, engram) that most users don't run. The plugin ships to everyone via `rtk init`, so baking in those tool ids added noise for the common case. Keep explicit strategies only for OpenCode's built-in tools (read, grep, glob, task, webfetch), which are present in every install. All other tools — MCP servers, third-party plugins, anything unknown — now flow through DEFAULT_STRATEGY (truncate-middle), which already handles arbitrary output safely. No tool loses compression; the non-built-ins just use the generic path instead of a hard-coded one. Update hooks/opencode/README.md to match.
Keep compression active without the RTK binary, preserve MCP content ordering, and expose bounded recovery through rtk_retrieve. Add atomic cache handling, final-payload budgets, structured metrics, focused Bun coverage, CI validation, and updated documentation.
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.
Summary
tool.execute.after.outputPathor the new boundedrtk_retrievetool.tool.execute.before, including permission-gated rewrites returned with exit code 3.Changes
Output compression
read,grep,glob,task, andwebfetch.truncate-middlefallback.metadata.rtkmetrics.rtk-minimalonly strips unambiguous full-line comments and now handles extensionless files such asDockerfile.Reversible recovery
metadata.outputPathvalues remain visible and unchanged.0600files.rtk_retrievesupports boundedoffset/limitreads and case-insensitive substring search.OpenCode runtime alignment
tool.execute.afterpath by OpenCode design.Tests and documentation
hooks/opencode/rtk.test.tswith 21 Bun tests covering budgets, recovery, cache security, MCP ordering/resources, Unicode, ANSI output, comment stripping, rewrite exit codes, and Never Block behavior.hooks/opencode/README.mdwith the runtime flow, recovery model, configuration, and test command.Configuration
RTK_TRIGGER_TOKENS3000RTK_TARGET_TOKENS2500RTK_MAX_OUTPUT_CHARS32000RTK_TOKEN_THRESHOLD3000RTK_CACHE_DIRRTK_DEBUGTest plan
bun test hooks/opencode/rtk.test.ts- 21 passedcargo fmt --all -- --checkcargo clippy --all-targets- no warningscargo test --all- 2410 passed, 8 ignoredtest_opencode_plugin_install_and_update- passed@opencode-ai/pluginand OpenCode 1.17.18readcompressed approximately 7509 to 2500 tokens andrtk_retrieverecovered omitted contentRuntime verification
git status --shortrewrote tortk git status --short.text,image,textordering and an intact recovery ID.0600, and search retrieval recovered the original unique content.Review scope
This PR now changes 4 files with 1,260 additions and 23 deletions. The update intentionally remains in the existing PR because the embedded plugin, its behavioral/security tests, documentation, and CI gate form one deployable unit; splitting them would leave an untested or lossy intermediate state.
Suggested review order:
hooks/opencode/rtk.test.ts- behavioral contracthooks/opencode/rtk.ts- implementationhooks/opencode/README.md- user-facing contract.github/workflows/ci.yml- focused test gateCommits
feat(opencode): compress heavy tool outputs in the pluginrefactor(opencode): clean up plugin structure and readabilityrefactor(opencode): scope HEAVY_TOOLS to OpenCode built-ins onlyfeat(opencode): make output compression recoverableNotes for reviewers
include_str!insrc/hooks/init.rs.