opencode-recall
v0.1.0
Published
OpenCode plugin for reversible context pruning: prune tool I/O into on-disk blobs and restore on demand
Maintainers
Readme
OpenCode Recall 🧠
Tool I/O 越聊越多占满上下文?剪掉它,留指针,随时恢复。
⚡️ 核心痛点
OpenCode 已经有"单次工具输出超限就截断,并把完整输出临时写到 tool-output/"的兜底机制(通常还会附带如何用 grep / read offset/limit / 子代理继续处理的提示)。
但更常见、也更影响体验的问题是:输出没超限,却在长会话里不断累积 —— 你每一轮都在为同一批历史工具 I/O 反复付 token。
你是否遇到过:
- ❌ 单次日志/文件读取不大,但 10+ 轮后上下文被几十次工具输出拖到很臃肿(慢、贵、容易跑偏)
- ❌ 同一个命令反复跑、同一个文件反复读:旧输出早就"过期"了,却仍然占着上下文
- ❌
write/edit的大输入(content/patch)在后续read到最新文件后已经冗余,但还在上下文里付 token - ❌ 触发 compaction/summary 后,想回到"当时的原始证据"核对细节,却拿不到
Recall 的解决方案:把热上下文变成冷存储(可逆、可探索)
| Before Recall | After Recall |
| :-------------------------------------------- | :-------------------------------------------------------------- |
| 🐢 上下文越聊越胖(重复/过期的工具 I/O 堆积) | ⚡ 用 [RCL:...] 指针替代;原文落盘到 .opencode/rcl/blobs/ |
| 🔍 想找关键信息只能翻历史/重跑工具 | 🔎 rcl_explore 子会话读取/搜索,只带回结论 |
| 💸 每一轮都为历史输出重复付 token | 💰 自动去重/剪枝(不额外调用 LLM),需要时再 rcl_restore/探索 |
┌─────────────────────────────────┬─────────────────────────────────────┐
│ Before Recall │ After Recall │
├─────────────────────────────────┼─────────────────────────────────────┤
│ [build log ~6KB] │ [RCL:o:.opencode/rcl/blobs/... ] │
│ [git diff ~3KB] │ (restore_chars≈6K) │
│ [read src/app.ts ~2KB] │ │
│ ... │ ↓ 需要时再恢复/探索 │
│ │ rcl_explore(path="[RCL:o:...]", │
│ │ question="找出关键报错") │
│ │ rcl_restore(path="[RCL:o:...], │
│ │ force=true) │
│ 上下文: 逐轮膨胀 💥 │ 上下文: 保持精简 ✅ │
└─────────────────────────────────┴─────────────────────────────────────┘📊 实测效果
以 Demo 场景 为例:运行构建命令两次(触发去重剪枝)→ 用 rcl_explore 从被剪枝的日志中提取报错 → 修复问题并验证 → 生成并保存项目说明(触发 supersedeWrites 剪枝)→ 用 rcl_restore 恢复原始日志核对细节。
启用 Recall 后,上下文占用 ≈ 8%

不启用 Recall,上下文占用 ≈ 21%

同样的 6 轮对话,上下文占用减少约 60%。 ┌─────────────────────────────────┬─────────────────────────────────────┐ │ Before Recall │ After Recall │ ├─────────────────────────────────┼─────────────────────────────────────┤ │ [build log ~6KB] │ [RCL:o:.opencode/rcl/blobs/... ] │ │ [git diff ~3KB] │ (restore_chars≈6K) │ │ [read src/app.ts ~2KB] │ │ │ ... │ ↓ 需要时再恢复/探索 │ │ │ rcl_explore(path="[RCL:o:...]", │ │ │ question="找出关键报错") │ │ │ rcl_restore(path="[RCL:o:...]", │ │ │ force=true) │ │ 上下文: 逐轮膨胀 💥 │ 上下文: 保持精简 ✅ │ └─────────────────────────────────┴─────────────────────────────────────┘
## 🚀 快速安装
无需复杂配置,即刻生效。
### 1. 安装插件
在项目根目录的 OpenCode 配置文件中添加:
```jsonc
// .opencode/opencode.jsonc
{
"plugin": ["opencode-recall@latest"],
}
```
### 2. 重启 OpenCode
插件会自动开始工作,拦截并优化冗余的工具输出。
## ✨ 核心特性
- **✂️ 智能去重 (Deduplication)**
自动识别重复的 `read` 或 `ls` 操作,只保留最新版本。旧的调用会自动折叠。
- **💾 落盘存档 (Offloading)**
当 Recall 识别到“重复/过期/可替代”的工具 I/O 时,会把原始内容写入 `.opencode/rcl/blobs/`(项目内),上下文中只留 `[RCL:o:...]` / `[RCL:i:...]` 指针。
- **🔍 子代理探索 (Sub-agent Exploration)**
不想把整个大文件恢复到主上下文?使用 `rcl_explore` 启动一个独立子会话,帮你读取大文件并提取关键信息,只把结论传回主会话。
- **🛡️ 可逆剪枝**
所有被剪掉的内容都是**安全**的。随时可以通过 `rcl_restore` 找回当时的完整快照。
## 📖 动手体验
我们准备了一个包含故障排查场景的 5 分钟演示脚本,带你体验“剪枝 -> 探索 -> 恢复”的全流程。
👉 **[点击查看演示指南](./demo/README.md)**
## 🛠️ 配置详解
Recall 开箱即用,但也支持深度定制。配置文件支持 `~/.config/opencode/rcl.jsonc` (全局) 或 `.opencode/rcl.jsonc` (项目级)。
```jsonc
{
"enabled": true,
"pruneNotification": "detailed", // "off" | "minimal" | "detailed"
// 保护最近 N 轮不被剪枝
"turnProtection": {
"enabled": false,
"turns": 4,
},
// 永远不剪枝这些文件
"protectedFilePatterns": ["**/*.env", "**/secrets/**"],
// 子代理配置
"explore": {
"enabled": true,
"agentVariant": "low", // 使用低成本模型探索
"maxResultChars": 4000,
},
}
```
更多配置项请参考 [rcl.schema.json](./rcl.schema.json)。
## ❓ 常见问题 (FAQ)
**Q: 剪枝把文件落盘了,后面要用还要读回来,这有什么意义?**
A: Recall 的核心价值是将“**热数据**(会被每一轮反复带入上下文的历史工具 I/O)”转变为“**冷数据**(落盘指针,可按需恢复/探索)”。
- **不剪枝**:哪怕每次只有几 KB,累积到 10+ 轮时仍会被反复计入上下文,持续消耗 Token。
- **剪枝后**:默认只在需要时才恢复;更推荐用 `rcl_explore` 读取/搜索并带回结论,避免把原文整块塞回主上下文。
**Q: 我怎么知道哪些内容被剪了?**
A: 插件会在 OpenCode 中通过 Toast 弹窗(通知栏)提示节省了多少 Token。上下文中也会留下 `[RCL:...]` 标记作为线索。
## 开发与贡献
```bash
# 构建
npm run build
# 本地调试 (链接到 OpenCode)
# .opencode/opencode.jsonc
{ "plugin": ["file:///abs/path/to/opencode-recall/dist/index.js"] }
```
## Attribution
本项目灵感来源于 `@tarquinen/opencode-dcp`,并在此基础上增加了“可逆恢复”与“子代理探索”等特性。