npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opencode-context-trimmer

v0.1.0

Published

An opencode plugin that trims upstream conversation context on long sessions to cut token cost, with a cache-aware gate and on-disk config.

Readme

context-trimmer

一个 opencode 插件:在长会话中裁剪发送给上游模型的对话上下文, 降低 token 成本与延迟,同时把完整历史保留在本地、可按需检索。

opencode 对模型是无状态的:每次请求都会把整段对话历史重新发给模型。在长会话里, 这意味着每一轮都要发送几万甚至几十万 token。本插件在消息真正发出前重写待发送的消息列表, 只保留真正需要的轮次。

工作原理

插件挂载 experimental.chat.messages.transform 钩子(重写待发送消息的时机), 应用一个可插拔的策略(strategy)。内置且默认的唯一策略是 turn-window

  • 轮(turn) = 一条或多条连续的用户消息,加上回应它们的助手消息。 连续的用户消息会被合并成一轮(以吸收轮次中途"排队"发出的消息)。
  • 当活跃轮数超过 threshold 时触发裁剪:
    • 最近 recentFullTurns完整保留(用户输入 + 工具循环 + 最终回答);
    • 再往前的 priorTrimmedTurns 轮只保留用户输入 + 助手最终文本(丢弃工具循环);
    • 更早的全部丢弃
  • 裁剪边界是粘性的:固定在 c - (recentFullTurns + priorTrimmedTurns), 随对话增长保持不动,使序列化后的前缀保持逐字节稳定,从而不破坏上游的 prompt 缓存。 只有当活跃轮数再次超过 threshold 时,边界才会向前跳。

裁剪后会在第一条保留的用户消息里合并一段提示,告诉模型较早的上下文已被裁剪, 以及如何取回(见下方工具)。

缓存感知门控

(重新)触发裁剪会重塑前缀、使上游 prompt 缓存失效(缓存通常有约 5 分钟的 TTL)。 cacheAwareMinutes 会推迟触发,直到会话空闲至少这么多分钟——那时缓存本就已过期, 因此不会付出额外的缓存未命中代价。活跃对话期间裁剪会被推迟;设为 0 则命中阈值即裁。

安装

方式一:npm 包(推荐)

在 opencode 配置文件(~/.config/opencode/opencode.json 或项目级 opencode.json) 的 plugin 数组里加入包名,opencode 启动时会自动用 Bun 安装:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["opencode-context-trimmer"]
}

方式二:本地文件

opencode 也会自动发现 ~/.config/opencode/plugin/(或 plugins/)下的插件。 把插件入口文件及其目录一起复制过去:

mkdir -p ~/.config/opencode/plugin
cp -R context-trimmer.ts context-trimmer ~/.config/opencode/plugin/

确认已加载

重启 opencode,然后查看日志:

grep "\[context-trimmer\]" ~/.local/share/opencode/log/opencode.log

你应能看到一行 plugin loaded;每当裁剪一次请求时,还会看到一行 trimmed before=… after=…

@opencode-ai/plugin@opencode-ai/sdk 由 opencode 运行时提供——无需手动安装。

配置

可选。没有配置文件时使用内置默认值。要自定义,创建:

$XDG_CONFIG_HOME/opencode/context-trimmer.json
# 默认:~/.config/opencode/context-trimmer.json
{
  "enabled": true,
  "threshold": 10,
  "recentFullTurns": 3,
  "priorTrimmedTurns": 2,
  "cacheAwareMinutes": 5
}

| 字段 | 默认值 | 含义 | |------|--------|------| | enabled | true | 总开关。false 时不改动任何请求。 | | threshold | 10 | 活跃轮数超过此值时(重新)触发裁剪。 | | recentFullTurns | 3 | 最近完整保留的轮数。 | | priorTrimmedTurns | 2 | 再往前只保留"用户输入 + 最终输出"的轮数。 | | cacheAwareMinutes | 5 | 会话空闲达到这么多分钟(缓存已过期)后才(重新)触发。0 关闭该门控。 |

改动在下一次请求即生效——无需重启(文件通过 mtime 缓存重新读取)。 文件缺失或格式错误时回落到默认值;单个非法字段只回落该字段的默认值,不影响其余字段。

示例:更宽松的裁剪

更晚触发、保留更多——适合更看重上下文完整性、不那么在意 token 成本的场景:

{
  "enabled": true,
  "threshold": 20,
  "recentFullTurns": 5,
  "priorTrimmedTurns": 5,
  "cacheAwareMinutes": 5
}

取回被裁剪的历史

裁剪只重塑上游请求——opencode 仍在本地保留完整历史。插件注册了一个 context_recall 工具,让模型可以按需取回被裁掉的内容:

  • query —— 关键词;以空格分隔的多个词按"与"匹配(大小写不敏感)。
  • scope —— current(默认,仅当前会话)或 all(所有会话,涵盖 subagent 子会话)。

扩展

context-trimmer/strategies/ 下新增一个策略文件,实现 Strategy 接口 (enabled(ctx) + apply(messages, ctx)),并在 context-trimmer/strategies/index.ts 中注册。策略按顺序执行,每个都能看到前一个的输出;抛异常的策略会被跳过(fail-open), 因此一个有缺陷的策略永远不会破坏请求。

项目结构

context-trimmer.ts              插件入口(钩子 + 工具注册)
context-trimmer/
  config.ts                     全局配置加载器(mtime 缓存、fail-safe)
  context.ts                    从 chat.params 桥接的每会话模型/provider 信息
  logger.ts                     基于 client.app.log 的 fail-safe 日志器
  pipeline.ts                   按顺序运行已启用策略(fail-open)
  globals.d.ts                  最小 ambient 声明(不引入 @types/node)
  strategies/
    types.ts                    策略契约
    index.ts                    策略注册表
    turn-window.ts              粘性 turn-window 策略
  tools/
    recall.ts                   context_recall 工具

测试与被测文件放在一起,命名为 *.test.ts,用 bun run <file>.test.ts 运行。