opencode-recall 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +161 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +123 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +73 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +779 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/explore-tool.d.ts +11 -0
- package/dist/lib/explore-tool.d.ts.map +1 -0
- package/dist/lib/explore-tool.js +240 -0
- package/dist/lib/explore-tool.js.map +1 -0
- package/dist/lib/hooks.d.ts +10 -0
- package/dist/lib/hooks.d.ts.map +1 -0
- package/dist/lib/hooks.js +58 -0
- package/dist/lib/hooks.js.map +1 -0
- package/dist/lib/logger.d.ts +31 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +183 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/messages/index.d.ts +3 -0
- package/dist/lib/messages/index.d.ts.map +1 -0
- package/dist/lib/messages/index.js +3 -0
- package/dist/lib/messages/index.js.map +1 -0
- package/dist/lib/messages/inject.d.ts +5 -0
- package/dist/lib/messages/inject.d.ts.map +1 -0
- package/dist/lib/messages/inject.js +114 -0
- package/dist/lib/messages/inject.js.map +1 -0
- package/dist/lib/messages/prune.d.ts +5 -0
- package/dist/lib/messages/prune.d.ts.map +1 -0
- package/dist/lib/messages/prune.js +179 -0
- package/dist/lib/messages/prune.js.map +1 -0
- package/dist/lib/messages/utils.d.ts +10 -0
- package/dist/lib/messages/utils.d.ts.map +1 -0
- package/dist/lib/messages/utils.js +193 -0
- package/dist/lib/messages/utils.js.map +1 -0
- package/dist/lib/prompts/agent/rcl-explorer.d.ts +2 -0
- package/dist/lib/prompts/agent/rcl-explorer.d.ts.map +1 -0
- package/dist/lib/prompts/agent/rcl-explorer.js +39 -0
- package/dist/lib/prompts/agent/rcl-explorer.js.map +1 -0
- package/dist/lib/prompts/discard-tool-spec.d.ts +2 -0
- package/dist/lib/prompts/discard-tool-spec.d.ts.map +1 -0
- package/dist/lib/prompts/discard-tool-spec.js +41 -0
- package/dist/lib/prompts/discard-tool-spec.js.map +1 -0
- package/dist/lib/prompts/extract-tool-spec.d.ts +2 -0
- package/dist/lib/prompts/extract-tool-spec.d.ts.map +1 -0
- package/dist/lib/prompts/extract-tool-spec.js +48 -0
- package/dist/lib/prompts/extract-tool-spec.js.map +1 -0
- package/dist/lib/prompts/index.d.ts +2 -0
- package/dist/lib/prompts/index.d.ts.map +1 -0
- package/dist/lib/prompts/index.js +41 -0
- package/dist/lib/prompts/index.js.map +1 -0
- package/dist/lib/prompts/nudge/both.d.ts +2 -0
- package/dist/lib/prompts/nudge/both.d.ts.map +1 -0
- package/dist/lib/prompts/nudge/both.js +11 -0
- package/dist/lib/prompts/nudge/both.js.map +1 -0
- package/dist/lib/prompts/nudge/discard.d.ts +2 -0
- package/dist/lib/prompts/nudge/discard.d.ts.map +1 -0
- package/dist/lib/prompts/nudge/discard.js +10 -0
- package/dist/lib/prompts/nudge/discard.js.map +1 -0
- package/dist/lib/prompts/nudge/extract.d.ts +2 -0
- package/dist/lib/prompts/nudge/extract.d.ts.map +1 -0
- package/dist/lib/prompts/nudge/extract.js +10 -0
- package/dist/lib/prompts/nudge/extract.js.map +1 -0
- package/dist/lib/prompts/restore-tool-spec.d.ts +2 -0
- package/dist/lib/prompts/restore-tool-spec.d.ts.map +1 -0
- package/dist/lib/prompts/restore-tool-spec.js +21 -0
- package/dist/lib/prompts/restore-tool-spec.js.map +1 -0
- package/dist/lib/prompts/system/both.d.ts +2 -0
- package/dist/lib/prompts/system/both.d.ts.map +1 -0
- package/dist/lib/prompts/system/both.js +72 -0
- package/dist/lib/prompts/system/both.js.map +1 -0
- package/dist/lib/prompts/system/core.d.ts +2 -0
- package/dist/lib/prompts/system/core.d.ts.map +1 -0
- package/dist/lib/prompts/system/core.js +26 -0
- package/dist/lib/prompts/system/core.js.map +1 -0
- package/dist/lib/prompts/system/discard.d.ts +2 -0
- package/dist/lib/prompts/system/discard.d.ts.map +1 -0
- package/dist/lib/prompts/system/discard.js +63 -0
- package/dist/lib/prompts/system/discard.js.map +1 -0
- package/dist/lib/prompts/system/extract.d.ts +2 -0
- package/dist/lib/prompts/system/extract.d.ts.map +1 -0
- package/dist/lib/prompts/system/extract.js +63 -0
- package/dist/lib/prompts/system/extract.js.map +1 -0
- package/dist/lib/protected-file-patterns.d.ts +12 -0
- package/dist/lib/protected-file-patterns.d.ts.map +1 -0
- package/dist/lib/protected-file-patterns.js +69 -0
- package/dist/lib/protected-file-patterns.js.map +1 -0
- package/dist/lib/pruned-blobs.d.ts +19 -0
- package/dist/lib/pruned-blobs.d.ts.map +1 -0
- package/dist/lib/pruned-blobs.js +111 -0
- package/dist/lib/pruned-blobs.js.map +1 -0
- package/dist/lib/rcl-pointer.d.ts +3 -0
- package/dist/lib/rcl-pointer.d.ts.map +1 -0
- package/dist/lib/rcl-pointer.js +63 -0
- package/dist/lib/rcl-pointer.js.map +1 -0
- package/dist/lib/restore-tool.d.ts +15 -0
- package/dist/lib/restore-tool.d.ts.map +1 -0
- package/dist/lib/restore-tool.js +142 -0
- package/dist/lib/restore-tool.js.map +1 -0
- package/dist/lib/shared-utils.d.ts +4 -0
- package/dist/lib/shared-utils.d.ts.map +1 -0
- package/dist/lib/shared-utils.js +14 -0
- package/dist/lib/shared-utils.js.map +1 -0
- package/dist/lib/state/index.d.ts +4 -0
- package/dist/lib/state/index.d.ts.map +1 -0
- package/dist/lib/state/index.js +4 -0
- package/dist/lib/state/index.js.map +1 -0
- package/dist/lib/state/persistence.d.ts +16 -0
- package/dist/lib/state/persistence.d.ts.map +1 -0
- package/dist/lib/state/persistence.js +73 -0
- package/dist/lib/state/persistence.js.map +1 -0
- package/dist/lib/state/state.d.ts +8 -0
- package/dist/lib/state/state.d.ts.map +1 -0
- package/dist/lib/state/state.js +114 -0
- package/dist/lib/state/state.js.map +1 -0
- package/dist/lib/state/tool-cache.d.ts +13 -0
- package/dist/lib/state/tool-cache.d.ts.map +1 -0
- package/dist/lib/state/tool-cache.js +79 -0
- package/dist/lib/state/tool-cache.js.map +1 -0
- package/dist/lib/state/types.d.ts +33 -0
- package/dist/lib/state/types.d.ts.map +1 -0
- package/dist/lib/state/types.js +2 -0
- package/dist/lib/state/types.js.map +1 -0
- package/dist/lib/state/utils.d.ts +2 -0
- package/dist/lib/state/utils.d.ts.map +1 -0
- package/dist/lib/state/utils.js +10 -0
- package/dist/lib/state/utils.js.map +1 -0
- package/dist/lib/strategies/deduplication.d.ts +10 -0
- package/dist/lib/strategies/deduplication.d.ts.map +1 -0
- package/dist/lib/strategies/deduplication.js +94 -0
- package/dist/lib/strategies/deduplication.js.map +1 -0
- package/dist/lib/strategies/index.d.ts +5 -0
- package/dist/lib/strategies/index.d.ts.map +1 -0
- package/dist/lib/strategies/index.js +5 -0
- package/dist/lib/strategies/index.js.map +1 -0
- package/dist/lib/strategies/purge-errors.d.ts +13 -0
- package/dist/lib/strategies/purge-errors.d.ts.map +1 -0
- package/dist/lib/strategies/purge-errors.js +59 -0
- package/dist/lib/strategies/purge-errors.js.map +1 -0
- package/dist/lib/strategies/supersede-writes.d.ts +13 -0
- package/dist/lib/strategies/supersede-writes.d.ts.map +1 -0
- package/dist/lib/strategies/supersede-writes.js +84 -0
- package/dist/lib/strategies/supersede-writes.js.map +1 -0
- package/dist/lib/strategies/tools.d.ts +14 -0
- package/dist/lib/strategies/tools.d.ts.map +1 -0
- package/dist/lib/strategies/tools.js +135 -0
- package/dist/lib/strategies/tools.js.map +1 -0
- package/dist/lib/strategies/utils.d.ts +13 -0
- package/dist/lib/strategies/utils.d.ts.map +1 -0
- package/dist/lib/strategies/utils.js +93 -0
- package/dist/lib/strategies/utils.js.map +1 -0
- package/dist/lib/ui/notification.d.ts +8 -0
- package/dist/lib/ui/notification.d.ts.map +1 -0
- package/dist/lib/ui/notification.js +54 -0
- package/dist/lib/ui/notification.js.map +1 -0
- package/dist/lib/ui/utils.d.ts +15 -0
- package/dist/lib/ui/utils.d.ts.map +1 -0
- package/dist/lib/ui/utils.js +87 -0
- package/dist/lib/ui/utils.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 tarquinen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# OpenCode Recall 🧠
|
|
2
|
+
|
|
3
|
+
> **Tool I/O 越聊越多占满上下文?剪掉它,留指针,随时恢复。**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ⚡️ 核心痛点
|
|
8
|
+
|
|
9
|
+
OpenCode 已经有"单次工具输出超限就截断,并把完整输出临时写到 `tool-output/`"的兜底机制(通常还会附带如何用 `grep` / `read offset/limit` / 子代理继续处理的提示)。
|
|
10
|
+
但更常见、也更影响体验的问题是:**输出没超限,却在长会话里不断累积** —— 你每一轮都在为同一批历史工具 I/O 反复付 token。
|
|
11
|
+
|
|
12
|
+
你是否遇到过:
|
|
13
|
+
|
|
14
|
+
- ❌ 单次日志/文件读取不大,但 10+ 轮后上下文被几十次工具输出拖到很臃肿(慢、贵、容易跑偏)
|
|
15
|
+
- ❌ 同一个命令反复跑、同一个文件反复读:旧输出早就"过期"了,却仍然占着上下文
|
|
16
|
+
- ❌ `write`/`edit` 的大输入(content/patch)在后续 `read` 到最新文件后已经冗余,但还在上下文里付 token
|
|
17
|
+
- ❌ 触发 compaction/summary 后,想回到"当时的原始证据"核对细节,却拿不到
|
|
18
|
+
|
|
19
|
+
**Recall 的解决方案:把热上下文变成冷存储(可逆、可探索)**
|
|
20
|
+
|
|
21
|
+
| Before Recall | After Recall |
|
|
22
|
+
| :-------------------------------------------- | :-------------------------------------------------------------- |
|
|
23
|
+
| 🐢 上下文越聊越胖(重复/过期的工具 I/O 堆积) | ⚡ 用 `[RCL:...]` 指针替代;原文落盘到 `.opencode/rcl/blobs/` |
|
|
24
|
+
| 🔍 想找关键信息只能翻历史/重跑工具 | 🔎 `rcl_explore` 子会话读取/搜索,只带回结论 |
|
|
25
|
+
| 💸 每一轮都为历史输出重复付 token | 💰 自动去重/剪枝(不额外调用 LLM),需要时再 `rcl_restore`/探索 |
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
┌─────────────────────────────────┬─────────────────────────────────────┐
|
|
29
|
+
│ Before Recall │ After Recall │
|
|
30
|
+
├─────────────────────────────────┼─────────────────────────────────────┤
|
|
31
|
+
│ [build log ~6KB] │ [RCL:o:.opencode/rcl/blobs/... ] │
|
|
32
|
+
│ [git diff ~3KB] │ (restore_chars≈6K) │
|
|
33
|
+
│ [read src/app.ts ~2KB] │ │
|
|
34
|
+
│ ... │ ↓ 需要时再恢复/探索 │
|
|
35
|
+
│ │ rcl_explore(path="[RCL:o:...]", │
|
|
36
|
+
│ │ question="找出关键报错") │
|
|
37
|
+
│ │ rcl_restore(path="[RCL:o:...], │
|
|
38
|
+
│ │ force=true) │
|
|
39
|
+
│ 上下文: 逐轮膨胀 💥 │ 上下文: 保持精简 ✅ │
|
|
40
|
+
└─────────────────────────────────┴─────────────────────────────────────┘
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 📊 实测效果
|
|
44
|
+
|
|
45
|
+
以 [Demo 场景](./demo/README.md) 为例:运行构建命令两次(触发去重剪枝)→ 用 `rcl_explore` 从被剪枝的日志中提取报错 → 修复问题并验证 → 生成并保存项目说明(触发 supersedeWrites 剪枝)→ 用 `rcl_restore` 恢复原始日志核对细节。
|
|
46
|
+
|
|
47
|
+
**启用 Recall 后,上下文占用 ≈ 8%**
|
|
48
|
+
|
|
49
|
+

|
|
50
|
+
|
|
51
|
+
**不启用 Recall,上下文占用 ≈ 21%**
|
|
52
|
+
|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
> 同样的 6 轮对话,上下文占用减少约 60%。
|
|
56
|
+
> ┌─────────────────────────────────┬─────────────────────────────────────┐
|
|
57
|
+
> │ Before Recall │ After Recall │
|
|
58
|
+
> ├─────────────────────────────────┼─────────────────────────────────────┤
|
|
59
|
+
> │ [build log ~6KB] │ [RCL:o:.opencode/rcl/blobs/... ] │
|
|
60
|
+
> │ [git diff ~3KB] │ (restore_chars≈6K) │
|
|
61
|
+
> │ [read src/app.ts ~2KB] │ │
|
|
62
|
+
> │ ... │ ↓ 需要时再恢复/探索 │
|
|
63
|
+
> │ │ rcl_explore(path="[RCL:o:...]", │
|
|
64
|
+
> │ │ question="找出关键报错") │
|
|
65
|
+
> │ │ rcl_restore(path="[RCL:o:...]", │
|
|
66
|
+
> │ │ force=true) │
|
|
67
|
+
> │ 上下文: 逐轮膨胀 💥 │ 上下文: 保持精简 ✅ │
|
|
68
|
+
> └─────────────────────────────────┴─────────────────────────────────────┘
|
|
69
|
+
|
|
70
|
+
````
|
|
71
|
+
|
|
72
|
+
## 🚀 快速安装
|
|
73
|
+
|
|
74
|
+
无需复杂配置,即刻生效。
|
|
75
|
+
|
|
76
|
+
### 1. 安装插件
|
|
77
|
+
|
|
78
|
+
在项目根目录的 OpenCode 配置文件中添加:
|
|
79
|
+
|
|
80
|
+
```jsonc
|
|
81
|
+
// .opencode/opencode.jsonc
|
|
82
|
+
{
|
|
83
|
+
"plugin": ["opencode-recall@latest"],
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2. 重启 OpenCode
|
|
88
|
+
|
|
89
|
+
插件会自动开始工作,拦截并优化冗余的工具输出。
|
|
90
|
+
|
|
91
|
+
## ✨ 核心特性
|
|
92
|
+
|
|
93
|
+
- **✂️ 智能去重 (Deduplication)**
|
|
94
|
+
自动识别重复的 `read` 或 `ls` 操作,只保留最新版本。旧的调用会自动折叠。
|
|
95
|
+
|
|
96
|
+
- **💾 落盘存档 (Offloading)**
|
|
97
|
+
当 Recall 识别到“重复/过期/可替代”的工具 I/O 时,会把原始内容写入 `.opencode/rcl/blobs/`(项目内),上下文中只留 `[RCL:o:...]` / `[RCL:i:...]` 指针。
|
|
98
|
+
|
|
99
|
+
- **🔍 子代理探索 (Sub-agent Exploration)**
|
|
100
|
+
不想把整个大文件恢复到主上下文?使用 `rcl_explore` 启动一个独立子会话,帮你读取大文件并提取关键信息,只把结论传回主会话。
|
|
101
|
+
|
|
102
|
+
- **🛡️ 可逆剪枝**
|
|
103
|
+
所有被剪掉的内容都是**安全**的。随时可以通过 `rcl_restore` 找回当时的完整快照。
|
|
104
|
+
|
|
105
|
+
## 📖 动手体验
|
|
106
|
+
|
|
107
|
+
我们准备了一个包含故障排查场景的 5 分钟演示脚本,带你体验“剪枝 -> 探索 -> 恢复”的全流程。
|
|
108
|
+
|
|
109
|
+
👉 **[点击查看演示指南](./demo/README.md)**
|
|
110
|
+
|
|
111
|
+
## 🛠️ 配置详解
|
|
112
|
+
|
|
113
|
+
Recall 开箱即用,但也支持深度定制。配置文件支持 `~/.config/opencode/rcl.jsonc` (全局) 或 `.opencode/rcl.jsonc` (项目级)。
|
|
114
|
+
|
|
115
|
+
```jsonc
|
|
116
|
+
{
|
|
117
|
+
"enabled": true,
|
|
118
|
+
"pruneNotification": "detailed", // "off" | "minimal" | "detailed"
|
|
119
|
+
// 保护最近 N 轮不被剪枝
|
|
120
|
+
"turnProtection": {
|
|
121
|
+
"enabled": false,
|
|
122
|
+
"turns": 4,
|
|
123
|
+
},
|
|
124
|
+
// 永远不剪枝这些文件
|
|
125
|
+
"protectedFilePatterns": ["**/*.env", "**/secrets/**"],
|
|
126
|
+
// 子代理配置
|
|
127
|
+
"explore": {
|
|
128
|
+
"enabled": true,
|
|
129
|
+
"agentVariant": "low", // 使用低成本模型探索
|
|
130
|
+
"maxResultChars": 4000,
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
更多配置项请参考 [rcl.schema.json](./rcl.schema.json)。
|
|
136
|
+
|
|
137
|
+
## ❓ 常见问题 (FAQ)
|
|
138
|
+
|
|
139
|
+
**Q: 剪枝把文件落盘了,后面要用还要读回来,这有什么意义?**
|
|
140
|
+
A: Recall 的核心价值是将“**热数据**(会被每一轮反复带入上下文的历史工具 I/O)”转变为“**冷数据**(落盘指针,可按需恢复/探索)”。
|
|
141
|
+
|
|
142
|
+
- **不剪枝**:哪怕每次只有几 KB,累积到 10+ 轮时仍会被反复计入上下文,持续消耗 Token。
|
|
143
|
+
- **剪枝后**:默认只在需要时才恢复;更推荐用 `rcl_explore` 读取/搜索并带回结论,避免把原文整块塞回主上下文。
|
|
144
|
+
|
|
145
|
+
**Q: 我怎么知道哪些内容被剪了?**
|
|
146
|
+
A: 插件会在 OpenCode 中通过 Toast 弹窗(通知栏)提示节省了多少 Token。上下文中也会留下 `[RCL:...]` 标记作为线索。
|
|
147
|
+
|
|
148
|
+
## 开发与贡献
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# 构建
|
|
152
|
+
npm run build
|
|
153
|
+
|
|
154
|
+
# 本地调试 (链接到 OpenCode)
|
|
155
|
+
# .opencode/opencode.jsonc
|
|
156
|
+
{ "plugin": ["file:///abs/path/to/opencode-recall/dist/index.js"] }
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Attribution
|
|
160
|
+
|
|
161
|
+
本项目灵感来源于 `@tarquinen/opencode-dcp`,并在此基础上增加了“可逆恢复”与“子代理探索”等特性。
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAUjD,QAAA,MAAM,MAAM,EAAE,MA0IK,CAAA;AAEnB,eAAe,MAAM,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { getConfig } from "./lib/config";
|
|
2
|
+
import { Logger } from "./lib/logger";
|
|
3
|
+
import { createSessionState } from "./lib/state";
|
|
4
|
+
import { createDiscardTool, createExtractTool } from "./lib/strategies";
|
|
5
|
+
import { createChatMessageTransformHandler, createSystemPromptHandler } from "./lib/hooks";
|
|
6
|
+
import { createRestoreTool } from "./lib/restore-tool";
|
|
7
|
+
import { createExploreTool } from "./lib/explore-tool";
|
|
8
|
+
import { loadPrompt } from "./lib/prompts";
|
|
9
|
+
const plugin = (async (ctx) => {
|
|
10
|
+
const config = getConfig(ctx);
|
|
11
|
+
if (!config.enabled) {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
const logger = new Logger(config.debug);
|
|
15
|
+
const state = createSessionState();
|
|
16
|
+
logger.info("RCL initialized", {
|
|
17
|
+
strategies: config.strategies,
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
"experimental.chat.system.transform": createSystemPromptHandler(state, logger, config),
|
|
21
|
+
"experimental.chat.messages.transform": createChatMessageTransformHandler(ctx.client, state, logger, config, ctx.directory),
|
|
22
|
+
"chat.message": async (input, _output) => {
|
|
23
|
+
// Cache variant from real user messages (not synthetic)
|
|
24
|
+
// This avoids scanning all messages to find variant
|
|
25
|
+
state.variant = input.variant;
|
|
26
|
+
logger.debug("Cached variant from chat.message hook", { variant: input.variant });
|
|
27
|
+
},
|
|
28
|
+
tool: {
|
|
29
|
+
// Always available: restores pruned content from `.opencode/rcl/blobs/...`.
|
|
30
|
+
rcl_restore: createRestoreTool({
|
|
31
|
+
logger,
|
|
32
|
+
workingDirectory: ctx.directory,
|
|
33
|
+
config,
|
|
34
|
+
}),
|
|
35
|
+
...(config.explore.enabled && {
|
|
36
|
+
// Runs a dedicated sub-agent to restore and explore blobs off-context.
|
|
37
|
+
rcl_explore: createExploreTool({
|
|
38
|
+
client: ctx.client,
|
|
39
|
+
logger,
|
|
40
|
+
config,
|
|
41
|
+
workingDirectory: ctx.directory,
|
|
42
|
+
}),
|
|
43
|
+
}),
|
|
44
|
+
...(config.tools.discard.enabled && {
|
|
45
|
+
discard: createDiscardTool({
|
|
46
|
+
client: ctx.client,
|
|
47
|
+
state,
|
|
48
|
+
logger,
|
|
49
|
+
config,
|
|
50
|
+
workingDirectory: ctx.directory,
|
|
51
|
+
}),
|
|
52
|
+
}),
|
|
53
|
+
...(config.tools.extract.enabled && {
|
|
54
|
+
extract: createExtractTool({
|
|
55
|
+
client: ctx.client,
|
|
56
|
+
state,
|
|
57
|
+
logger,
|
|
58
|
+
config,
|
|
59
|
+
workingDirectory: ctx.directory,
|
|
60
|
+
}),
|
|
61
|
+
}),
|
|
62
|
+
},
|
|
63
|
+
config: async (opencodeConfig) => {
|
|
64
|
+
// Add enabled tools to primary_tools by mutating the opencode config
|
|
65
|
+
// This works because config is cached and passed by reference
|
|
66
|
+
const toolsToAdd = [];
|
|
67
|
+
toolsToAdd.push("rcl_restore");
|
|
68
|
+
if (config.explore.enabled)
|
|
69
|
+
toolsToAdd.push("rcl_explore");
|
|
70
|
+
if (config.tools.discard.enabled)
|
|
71
|
+
toolsToAdd.push("discard");
|
|
72
|
+
if (config.tools.extract.enabled)
|
|
73
|
+
toolsToAdd.push("extract");
|
|
74
|
+
if (toolsToAdd.length > 0) {
|
|
75
|
+
const existingPrimaryTools = opencodeConfig.experimental?.primary_tools ?? [];
|
|
76
|
+
opencodeConfig.experimental = {
|
|
77
|
+
...opencodeConfig.experimental,
|
|
78
|
+
primary_tools: Array.from(new Set([...existingPrimaryTools, ...toolsToAdd])),
|
|
79
|
+
};
|
|
80
|
+
logger.info(`Added ${toolsToAdd.map((t) => `'${t}'`).join(" and ")} to experimental.primary_tools via config mutation`);
|
|
81
|
+
}
|
|
82
|
+
// Ensure the rcl_explorer agent exists for rcl_explore to use.
|
|
83
|
+
// We default its model to the OpenCode default agent's model (if present),
|
|
84
|
+
// so users don't need to hardcode a provider-specific model in rcl.jsonc.
|
|
85
|
+
const cfgAny = opencodeConfig;
|
|
86
|
+
const agents = cfgAny.agent ?? {};
|
|
87
|
+
const defaultAgentName = cfgAny.default_agent;
|
|
88
|
+
const inferModelFromAgents = () => {
|
|
89
|
+
if (config.explore.agentModel)
|
|
90
|
+
return config.explore.agentModel;
|
|
91
|
+
if (defaultAgentName && agents[defaultAgentName]?.model)
|
|
92
|
+
return agents[defaultAgentName].model;
|
|
93
|
+
if (agents.code?.model)
|
|
94
|
+
return agents.code.model;
|
|
95
|
+
for (const a of Object.values(agents)) {
|
|
96
|
+
if (a && typeof a.model === "string" && a.model.length > 0) {
|
|
97
|
+
return a.model;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
};
|
|
102
|
+
const model = inferModelFromAgents();
|
|
103
|
+
if (!model) {
|
|
104
|
+
logger.warn("Could not infer a model for rcl_explorer; set explore.agentModel in rcl.jsonc or define agent.rcl_explorer in your OpenCode config.");
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!cfgAny.agent) {
|
|
108
|
+
cfgAny.agent = agents;
|
|
109
|
+
}
|
|
110
|
+
if (!cfgAny.agent.rcl_explorer) {
|
|
111
|
+
cfgAny.agent.rcl_explorer = {
|
|
112
|
+
model,
|
|
113
|
+
temperature: 0.1,
|
|
114
|
+
prompt: loadPrompt("agent/rcl-explorer"),
|
|
115
|
+
description: "Recall sub-agent: restores and explores pruned RCL blobs, returning small distilled answers.",
|
|
116
|
+
};
|
|
117
|
+
logger.info("Injected rcl_explorer agent config via config mutation", { model });
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
export default plugin;
|
|
123
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAAE,iCAAiC,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAC1F,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE1C,MAAM,MAAM,GAAW,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAClC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;IAE7B,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,EAAE,CAAA;IACb,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACvC,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAA;IAElC,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;KAChC,CAAC,CAAA;IAEF,OAAO;QACH,oCAAoC,EAAE,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;QAEtF,sCAAsC,EAAE,iCAAiC,CACrE,GAAG,CAAC,MAAM,EACV,KAAK,EACL,MAAM,EACN,MAAM,EACN,GAAG,CAAC,SAAS,CAChB;QACD,cAAc,EAAE,KAAK,EACjB,KAMC,EACD,OAAY,EACd,EAAE;YACA,wDAAwD;YACxD,oDAAoD;YACpD,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAA;YAC7B,MAAM,CAAC,KAAK,CAAC,uCAAuC,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QACrF,CAAC;QACD,IAAI,EAAE;YACF,4EAA4E;YAC5E,WAAW,EAAE,iBAAiB,CAAC;gBAC3B,MAAM;gBACN,gBAAgB,EAAE,GAAG,CAAC,SAAS;gBAC/B,MAAM;aACT,CAAC;YACF,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI;gBAC1B,uEAAuE;gBACvE,WAAW,EAAE,iBAAiB,CAAC;oBAC3B,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,MAAM;oBACN,MAAM;oBACN,gBAAgB,EAAE,GAAG,CAAC,SAAS;iBAClC,CAAC;aACL,CAAC;YACF,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI;gBAChC,OAAO,EAAE,iBAAiB,CAAC;oBACvB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,KAAK;oBACL,MAAM;oBACN,MAAM;oBACN,gBAAgB,EAAE,GAAG,CAAC,SAAS;iBAClC,CAAC;aACL,CAAC;YACF,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI;gBAChC,OAAO,EAAE,iBAAiB,CAAC;oBACvB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,KAAK;oBACL,MAAM;oBACN,MAAM;oBACN,gBAAgB,EAAE,GAAG,CAAC,SAAS;iBAClC,CAAC;aACL,CAAC;SACL;QACD,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;YAC7B,qEAAqE;YACrE,8DAA8D;YAC9D,MAAM,UAAU,GAAa,EAAE,CAAA;YAC/B,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;YAC9B,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO;gBAAE,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;YAC1D,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO;gBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO;gBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAE5D,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,oBAAoB,GAAG,cAAc,CAAC,YAAY,EAAE,aAAa,IAAI,EAAE,CAAA;gBAC7E,cAAc,CAAC,YAAY,GAAG;oBAC1B,GAAG,cAAc,CAAC,YAAY;oBAC9B,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,oBAAoB,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC;iBAC/E,CAAA;gBACD,MAAM,CAAC,IAAI,CACP,SAAS,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,oDAAoD,CAC7G,CAAA;YACL,CAAC;YAED,+DAA+D;YAC/D,2EAA2E;YAC3E,0EAA0E;YAC1E,MAAM,MAAM,GAAG,cAAqB,CAAA;YACpC,MAAM,MAAM,GAAwB,MAAM,CAAC,KAAK,IAAI,EAAE,CAAA;YAEtD,MAAM,gBAAgB,GAAuB,MAAM,CAAC,aAAa,CAAA;YACjE,MAAM,oBAAoB,GAAG,GAAuB,EAAE;gBAClD,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU;oBAAE,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,CAAA;gBAC/D,IAAI,gBAAgB,IAAI,MAAM,CAAC,gBAAgB,CAAC,EAAE,KAAK;oBACnD,OAAO,MAAM,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAA;gBACzC,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK;oBAAE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAA;gBAChD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;oBACpC,IAAI,CAAC,IAAI,OAAQ,CAAS,CAAC,KAAK,KAAK,QAAQ,IAAK,CAAS,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC3E,OAAQ,CAAS,CAAC,KAAK,CAAA;oBAC3B,CAAC;gBACL,CAAC;gBACD,OAAO,SAAS,CAAA;YACpB,CAAC,CAAA;YAED,MAAM,KAAK,GAAG,oBAAoB,EAAE,CAAA;YACpC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACT,MAAM,CAAC,IAAI,CACP,qIAAqI,CACxI,CAAA;gBACD,OAAM;YACV,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBAChB,MAAM,CAAC,KAAK,GAAG,MAAM,CAAA;YACzB,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;gBAC7B,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG;oBACxB,KAAK;oBACL,WAAW,EAAE,GAAG;oBAChB,MAAM,EAAE,UAAU,CAAC,oBAAoB,CAAC;oBACxC,WAAW,EACP,8FAA8F;iBACrG,CAAA;gBACD,MAAM,CAAC,IAAI,CAAC,wDAAwD,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;YACpF,CAAC;QACL,CAAC;KACJ,CAAA;AACL,CAAC,CAAkB,CAAA;AAEnB,eAAe,MAAM,CAAA"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
+
export interface Deduplication {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
protectedTools: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface DiscardTool {
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface ExtractTool {
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
showDistillation: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface ToolSettings {
|
|
14
|
+
nudgeEnabled: boolean;
|
|
15
|
+
nudgeFrequency: number;
|
|
16
|
+
restoreProtectionTurns: number;
|
|
17
|
+
restoreMaxBytes: number;
|
|
18
|
+
protectedTools: string[];
|
|
19
|
+
}
|
|
20
|
+
export interface Tools {
|
|
21
|
+
settings: ToolSettings;
|
|
22
|
+
discard: DiscardTool;
|
|
23
|
+
extract: ExtractTool;
|
|
24
|
+
}
|
|
25
|
+
export interface SupersedeWrites {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface PurgeErrors {
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
turns: number;
|
|
31
|
+
protectedTools: string[];
|
|
32
|
+
}
|
|
33
|
+
export interface TurnProtection {
|
|
34
|
+
enabled: boolean;
|
|
35
|
+
turns: number;
|
|
36
|
+
}
|
|
37
|
+
export interface ExploreConfig {
|
|
38
|
+
enabled: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Optional model override for the rcl_explorer sub-agent.
|
|
41
|
+
*
|
|
42
|
+
* If omitted, Recall will try to infer a sensible default from your OpenCode agent config
|
|
43
|
+
* (typically the default agent's model).
|
|
44
|
+
*/
|
|
45
|
+
agentModel?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Optional variant override for the rcl_explorer sub-agent (e.g. "low" | "medium" | "high").
|
|
48
|
+
* If omitted, OpenCode's defaults apply.
|
|
49
|
+
*/
|
|
50
|
+
agentVariant?: string;
|
|
51
|
+
/** Maximum time to wait for the sub-agent session to complete. */
|
|
52
|
+
timeoutMs: number;
|
|
53
|
+
/** Hard cap for how many characters rcl_explore returns to the main session. */
|
|
54
|
+
maxResultChars: number;
|
|
55
|
+
}
|
|
56
|
+
export interface PluginConfig {
|
|
57
|
+
enabled: boolean;
|
|
58
|
+
debug: boolean;
|
|
59
|
+
pruneNotification: "off" | "minimal" | "detailed";
|
|
60
|
+
turnProtection: TurnProtection;
|
|
61
|
+
protectedFilePatterns: string[];
|
|
62
|
+
explore: ExploreConfig;
|
|
63
|
+
tools: Tools;
|
|
64
|
+
strategies: {
|
|
65
|
+
deduplication: Deduplication;
|
|
66
|
+
supersedeWrites: SupersedeWrites;
|
|
67
|
+
purgeErrors: PurgeErrors;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export declare const VALID_CONFIG_KEYS: Set<string>;
|
|
71
|
+
export declare function getInvalidConfigKeys(userConfig: Record<string, any>): string[];
|
|
72
|
+
export declare function getConfig(ctx: PluginInput): PluginConfig;
|
|
73
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../lib/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEtD,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,cAAc,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,gBAAgB,EAAE,OAAO,CAAA;CAC5B;AAED,MAAM,WAAW,YAAY;IACzB,YAAY,EAAE,OAAO,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,eAAe,EAAE,MAAM,CAAA;IACvB,cAAc,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,KAAK;IAClB,QAAQ,EAAE,YAAY,CAAA;IACtB,OAAO,EAAE,WAAW,CAAA;IACpB,OAAO,EAAE,WAAW,CAAA;CACvB;AAED,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,cAAc,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAA;IACjB,gFAAgF;IAChF,cAAc,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,YAAY;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,iBAAiB,EAAE,KAAK,GAAG,SAAS,GAAG,UAAU,CAAA;IACjD,cAAc,EAAE,cAAc,CAAA;IAC9B,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,OAAO,EAAE,aAAa,CAAA;IACtB,KAAK,EAAE,KAAK,CAAA;IACZ,UAAU,EAAE;QACR,aAAa,EAAE,aAAa,CAAA;QAC5B,eAAe,EAAE,eAAe,CAAA;QAChC,WAAW,EAAE,WAAW,CAAA;KAC3B,CAAA;CACJ;AAiBD,eAAO,MAAM,iBAAiB,aA0C5B,CAAA;AAgBF,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAG9E;AAmpBD,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,YAAY,CAgIxD"}
|