ESC
开源 2 分钟阅读

fast-jev-compaction:用 Jev 决策取代压缩摘要的 Claude Code 插件

开源项目 fast-jev-compaction 是 Claude Code 插件兼 npm 库,用 Jev 决策取代传统的上下文压缩摘要:通过快速请求为每个工具调用及结果打分,过期内容被删除或截断,保留部分逐字原样,避免摘要丢失文件路径、报错等关键信息。可作为 Claude Code function-hook 插件安装,也可作为 npm 库编程使用。

来源:GitHub

fast-jev-compaction

Claude Code 插件,用 Jev 决策取代压缩摘要:每个工具调用及其结果都在一次快速请求中被打分,过期的被删除或截断,所有保留的内容逐字原样。也可以作为 npm 库使用。

是什么与为什么

大多数上下文压缩会让 LLM 总结旧的对话轮次。摘要是无损的——不对,是有损的:文件路径、确切的报错、约束条件或命令可能在之后仍然重要时消失。这个库从不改写任何内容,只删除 Jev 认为不再需要的工具调用和工具结果,并且在向 Jev 提问时向其展示完整对话。用户和助手的文本保持逐字原样、顺序不变。

该仓库既是 npm 包(src/),也是 Claude Code 插件(hooks/、.claude-plugin/),插件利用这个包,把 Claude Code 内置的压缩摘要替换为原始消息。

工作原理

  1. 每个 tool_use 通过 tool_use_id 与其 tool_result 配对。第一条消息中或最新的 preserveRecentMessages 条消息中的调用被固定,绝不改动。
  2. 发送给 Jev 的状态是到目前为止的完整对话,从旧到新排列,每个工具结果都被替换为一条简短说明(ok, 4213 chars (omitted))。工具输入被包含在内,文本被包含在内,不做任何总结。
  3. 状态被分阶段适配到 maxStateTokens(默认 25k)以内,每个阶段仅在前一阶段不够时才应用:工具输入截断到 1000、然后 200、再 60 字符;长文本摘录为头部+尾部,最旧的未固定消息优先;旧的未固定消息折叠为一条 [… N chars omitted …] 说明;旧的工具调用各缩减为一行(t12 Read file_path=src/a.ts → ok 480ch);旧的没有调用的消息被略去;连续的旧"仅调用"消息折叠为一条。如果仍然放不下,压缩会抛出异常。Token 估算不使用分词器(每六个字母算一个词、每个数字半个 token、其他符号各约一个),并校准到略高于 Jev 报告的计数。
  4. 对于每个未固定的调用,Jev 会收到两个 noul 问题:调用本身是否应保留(知道它被发起过、连同其输入,是否仍然重要),以及结果是否应逐字保留(其内容仍然需要,且重新运行工具无法替代)。
  5. 问题被拆分为多个请求,以确保状态加问题保持在 maxRequestTokens(默认 30k,低于 Jev 的 32k 请求上限)以内。每次请求都重新发送同样的完整状态;请求并发运行,答案随后合并。
  6. 针对每个调用的决策,依据 keepThreshold:
    • keepResult ≥ threshold → 保留调用和结果;
    • 否则 keepCall ≥ threshold → 保留调用,结果截断为前 truncateHeadChars 个字符加一行说明;
    • 否则 → 连同结果一起删除该调用。
  7. 重建消息列表:失去全部内容的消息被移除,未改动的消息以原对象返回,任何结果都不会失去其对应的调用。

Jev 失败、答案格式错误、缺少密钥,或无法适配的历史都会抛出异常;由调用方(或 Claude Code hook)决定回退方案。

安装与使用

npm install fast-jev-compaction
export TYPESAFE_API_KEY=...
import { compactMessages, reductionRatio, type Message } from 'fast-jev-compaction';

const transcript: Message[] = [
  { role: 'user', text: 'Fix the failing test. Never edit src/generated.', toolUses: [] },
  {
    role: 'assistant',
    text: '',
    toolUses: [{ tool_use_id: 'toolu_1', tool: 'Read', input: { file_path: 'src/a.ts' } }],
  },
  { role: 'user', text: '', toolUses: [], toolResults: [{ tool_use_id: 'toolu_1', text: '…file…' }] },
  // …
];

const result = await compactMessages(transcript, { preserveRecentMessages: 4 });
console.log(result.messages, result.decisions, result.stats);
if (reductionRatio(result) < 0.25) {
  // not worth it: keep the original transcript, or summarize instead
}

Message 是 Claude Code SessionMessage 的一个子集,因此会话记录可以直接传入。

要自带传输层,实现 JevAsker(一个 ask(state, questions) 方法)并调用 compact(messages, asker, options);buildJevRequest 和 parseJevResponse 为你提供 HTTP 请求体构造和响应校验。构建块(collectToolCalls、fitState、batchCalls、decideCall、applyDecisions)也都已导出。

apiKey 默认为 process.env.TYPESAFE_API_KEY。切勿提交密钥或将其放入源文件。

选项

选项默认值说明
apiKeyTYPESAFE_API_KEYTypeSafe API 密钥(compactMessages/JevClient)
modeljev-latestJev 模型名
baseUrlhttps://api.typesafe.ai/v1/systemoneSystem One 端点
fetch原生 fetch可注入的 fetch 实现,用于测试
goal最近 3 条用户提示包含在状态中的当前任务描述
keepThreshold0.5调用或结果得以保留的最低保留概率
preserveRecentMessages6永不改动的最新消息数(第一条总是保留)
maxStateTokens25000状态的估算 token 上限
maxRequestTokens30000状态加一批问题的估算上限
truncateHeadChars300被删结果在其说明之前保留的字符数

result.stats 报告压缩前后的消息数和字符数、按原因分类的决策计数、以估算 token 计的状态大小、所需的适配阶段以及请求数。

局限性

  • 只有工具调用和结果是候选对象;文本消息在输出中绝不会被删除或缩短(它们只在 Jev 所见的状态中被摘录)。
  • Token 大小基于字符数估算,而非分词器。
  • 校准在请求层面进行;一个概率并不能证明删除某个结果是安全的。助手随时可以重新运行工具。
  • 每次请求都重复完整状态,因此接近状态上限的历史记录,每几个问题就要花费一次请求。

Claude Code 插件

仓库根目录就是一个 Claude Code function-hook 插件:hooks/fast-jev.ts 是一个轻量适配器,将 session.compact 的记录送入 src/ 处理,在出错或压缩量不足时回退到 Claude Code 内置摘要。配置方法和 Claude Code 2.1.274 类型参考见 hooks/README.md。

在 Claude Code 中安装

Function hooks 是 Claude Code 的早期访问功能(2.1.274+),因此必须在 Claude Code 运行之处设置 opt-in 标志,例如在 ~/.claude/settings.json 中:

{ "env": { "CLAUDE_CODE_ENABLE_FUNCTION_HOOKS": "1", "TYPESAFE_API_KEY": "<your key>" } }

然后将本仓库添加为插件市场并安装插件,可以在 shell 中操作,也可以在会话内用斜杠命令:

claude plugin marketplace add tamaratran/fast-jev-compaction
claude plugin install fast-jev-compaction@fast-jev-compaction

安装时会提示输入插件选项(API 密钥、阈值、truncateHeadChars 等);保持默认即可使用环境中的 TYPESAFE_API_KEY。重启 Claude Code 或运行 /reload-plugins。从此 /compact(以及自动压缩)都会经过 Jev:当剪枝后的历史替换内置摘要时,提示显示 fast-jev-compaction: kept N/M messages, no summary (…);当 Jev 无法删除足够内容时(短会话或失败时),显示 fallback to built-in summary (…)。

要在 checkout 中直接运行而无需安装:从仓库根目录执行 CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude --plugin-dir .。无需发布步骤;市场就是仓库的 .claude-plugin/marketplace.json。

开发

npm install
npm run typecheck        # library + hook
npm test
npm run build
npm run validate:plugin  # claude plugin validate
TYPESAFE_API_KEY="$(cat ~/.typesafe_key)" npm run demo

单元测试使用假 Jev,绝不连接 TypeSafe。demo 是真实的网络检查。

动画演示

demo/JevDemo 是一个原生 SwiftUI 小应用,在 Claude Code 风格的终端里播放脚本化、戏剧化的压缩流程:预设记录中的工具调用被打分,Jev 放弃的结果和调用变红并折叠消失,其余保持逐字原样。它从不调用 API;它的存在就是为了被屏幕录制。

demo/JevDemo/build.sh   # builds demo/JevDemo/build/JevDemo.app and launches it

在应用中按空格键即可从头重播。