Skip to content

Commit 309d80b

Browse files
author
beautistart
committed
feat(ide-bridge): ide_write_file 新增 edit 模式 + WorkspaceEdit 原生编辑 API + apply_edits 处理器
- ide_write_file 新增 mode='edit',传 edits 操作列表(insert/delete/replace/append),编辑器内实时更新且支持撤销 - VscodeExecutionBridge 新增 apply_edits 处理器,走 VS Code WorkspaceEdit 原生 API - fc_nodes.py 修复 Windows 路径正则以排除 URL 协议(如 http://) - config: threshold_budget_ratio 调整为 0.50
1 parent 7ccd41b commit 309d80b

7 files changed

Lines changed: 624 additions & 45 deletions

File tree

config/zulong_config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ attention_selection:
66
max_switch_history: 50
77
min_confidence_threshold: 0.3
88
oscillation_detection_window: 10
9-
threshold_budget_ratio: '0.15'
9+
threshold_budget_ratio: '0.50'
1010
pressure_threshold_high: '1.0'
1111
pressure_threshold_medium: '0.9'
1212
audio:
@@ -131,7 +131,7 @@ l2_inference:
131131
backup_model: deepseek-v4-pro
132132
circuit_breaker:
133133
bfs_min_interval: 3
134-
threshold_budget_ratio: '0.15'
134+
threshold_budget_ratio: '0.50'
135135
context_red_ratio: '1.0'
136136
context_window_size: 131072
137137
context_yellow_ratio: '0.9'

docs/ide_edits_mode_design.md

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
# 祖龙 IDE 写文件工具新增 edits 模式设计方案
2+
3+
> 状态:设计文档,暂不改业务代码。
4+
> 对齐 TSD 1.7 §23(IDE 工具体系)。
5+
6+
---
7+
8+
## 1. 背景
9+
10+
### 1.1 问题
11+
12+
当前 `ide_write_file` 只有 `overwrite``append` 两种模式,LLM 写长文件时面临:
13+
14+
1. **JSON 截断**:文件内容在 tool_call JSON 中,受 `max_tokens` 限制,长内容 JSON 会被截断导致解析失败
15+
2. **内容冗余**:LLM 做小修改(修 bug、加函数)也必须输出完整文件内容,浪费 token 和网络带宽
16+
3. **用户体验差**:用户看不到增量的代码变更,只能看到"文件被覆写/追加"
17+
18+
### 1.2 Cline 现有能力(已审计)
19+
20+
Cline 插件(`VscodeExecutionBridge.ts`)已有完整的编辑器操作能力:
21+
22+
| 操作 | 方法 | 实现方式 |
23+
|---|---|---|
24+
| `write_to_file` | `writeFile()` (L222-246) | `fs.writeFile` 完整写入,走 `confirmFileChange` 审批 |
25+
| `replace_in_file` | `replaceInFile()` (L267-287) | SEARCH/REPLACE 格式 diff,`applySearchReplaceDiff` |
26+
| `create_directory` | `createDirectory()` (L248-261) | `fs.mkdir` |
27+
| `delete_file` | `deleteFile()` (L314+) | `fs.unlink` |
28+
29+
`replace_in_file` 已经提供了 diff 编辑能力。**但 Python 工具层没有暴露这个功能。**
30+
31+
### 1.3 当前 Python→Cline 通信路径
32+
33+
```
34+
ide_write_file.execute() (Python)
35+
→ _run_async_request("ide:execute_tool", payload) (ide_bridge_tools.py:822)
36+
→ ide_server.request_ide_action("ide_execute_tool", payload) (ide_server.py:843)
37+
→ WebSocket → Cline executeTool(toolName, args)
38+
→ switch(toolName) { case "write_to_file": ... } (VscodeExecutionBridge.ts:143-148)
39+
```
40+
41+
---
42+
43+
## 2. 方案决策
44+
45+
### 2.1 是否直接改造 ide_write_file?
46+
**否,使用"扩展 mode 参数"方式,而非替换。**
47+
48+
`ide_write_file``overwrite``append` 模式仍然需要,不可删除:
49+
50+
| 场景 | 必需模式 | 原因 |
51+
|---|---|---|
52+
| 创建新文件 | overwrite | 从头建文件,无法 diff |
53+
| 追加内容 | append | 增量追加,适合日志/报告 |
54+
| 创建目录 | create_directory | 非文件操作 |
55+
| 修改现有文件 | edit(新增) | 精准编辑,不传输完整内容 |
56+
57+
### 2.2 edits vs diff 模式对比
58+
59+
| 维度 | SEARCH/REPLACE diff | Position-based edits |
60+
|---|---|---|
61+
| 格式 | `<<<<<<< SEARCH\n原文\n=======\n替换\n>>>>>>> REPLACE` | `[{op, line/range, text}]` |
62+
| LLM 生成难度 | 中等(需精确匹配原文字符) | 简单(只需行号+内容) |
63+
| 可靠性 | 差(空白/编码不一致→匹配失败) | 好(行号定位,容错性好) |
64+
| Cline 现成实现 |`replaceInFile` | ❌ 需新增 |
65+
| 实时编辑器更新 | ❌ 全文写入后 reload | ✅ WorkspaceEdit API |
66+
| 多块编辑 | 支持(可串多块 SEARCH/REPLACE) | 支持(操作列表) |
67+
68+
**推荐**:先复用 Cline 现有的 `replace_in_file`(最小投入),同时设计 `edit` 模式协议(中长期优化)。
69+
70+
### 2.3 方案
71+
72+
**Phase 1(立即可做)**:在 Python 工具层新增 `ide_replace_file` 工具,透传 Cline 的 `replace_in_file` 能力。**零 Cline 端改动。**
73+
74+
**Phase 2(后续优化)**:新增 `ide_write_file(mode="edit")`,支持基于位置的操作列表,需要在 Cline 端新增 handler。
75+
76+
---
77+
78+
## 3. Phase 1 设计:ide_replace_file(复用 Cline replace_in_file)
79+
80+
### 3.1 新增工具
81+
82+
```python
83+
# zulong/tools/ide_bridge_tools.py 新增
84+
85+
class IdeReplaceFileTool(BaseTool):
86+
"""通过 SEARCH/REPLACE diff 替换文件内容(复用 Cline replace_in_file)。"""
87+
88+
def __init__(self):
89+
super().__init__(name="ide_replace_file", category=ToolCategory.CODE)
90+
self.description = (
91+
"使用 SEARCH/REPLACE 格式差异替换文件中的指定内容。"
92+
"适合对已有文件做精准修改(修 bug、加函数、改配置),无需传输完整文件内容。"
93+
"diff 格式:第一块以 <<<<<<< SEARCH 开头,然后是原标题,"
94+
"======= 分隔,然后是替换内容,>>>>>>> REPLACE 结尾。"
95+
"可串联多块 diff。"
96+
"如果修改内容较多建议直接用 ide_write_file(mode='overwrite') 重写整个文件。"
97+
)
98+
```
99+
100+
### 3.2 WebSocket 协议(无改动)
101+
102+
复用现有 `ide:execute_tool` 协议,Cline 已有 handler:
103+
104+
```json
105+
// Python→Cline WebSocket 消息(现有协议,无需改动)
106+
{
107+
"type": "ide_execute_tool",
108+
"tool_name": "replace_in_file",
109+
"arguments": {
110+
"path": "/workspace/src/main.py",
111+
"diff": "<<<<<<< SEARCH\ndef old_func():\n pass\n=======\ndef old_func():\n return 42\n>>>>>>> REPLACE"
112+
}
113+
}
114+
```
115+
116+
### 3.3 与 ide_write_file 的联动
117+
118+
`ide_replace_file` 适合 LLM 自主选择使用。当 LLM 调用 `ide_write_file` 且文件已存在时,可在 prompt 中引导优先使用 `ide_replace_file` 做轻量修改。
119+
120+
---
121+
122+
## 4. Phase 2 设计:ide_write_file edits 模式
123+
124+
### 4.1 新增 mode 值
125+
126+
`ide_write_file` 新增 `mode="edit"`,接受 `edits` 参数:
127+
128+
```python
129+
# ide_write_file 参数扩展
130+
{
131+
"mode": "edit", # 新增值
132+
"file_path": "/workspace/src/main.py",
133+
"edits": [ # 新增参数
134+
{"op": "insert", "line": 5, "text": "import os\n"},
135+
{"op": "delete", "line": 3, "count": 2},
136+
{"op": "replace", "start_line": 10, "end_line": 12, "text": "def new_func():\n pass\n"},
137+
{"op": "append", "text": "\n# New section\n"}
138+
]
139+
}
140+
```
141+
142+
### 4.2 编辑操作类型
143+
144+
| op | 必需参数 | 语义 |
145+
|---|---|---|
146+
| `insert` | `line`, `text` | 在第 `line` 行前插入文本 |
147+
| `delete` | `line`, `count` | 从第 `line` 行开始删除 `count`|
148+
| `replace` | `start_line`, `end_line`, `text` | 替换第 `start_line``end_line`(含)的行为 `text` |
149+
| `append` | `text` | 追加到文件末尾 |
150+
151+
### 4.3 WebSocket 协议
152+
153+
```json
154+
// Python→Cline 新消息类型
155+
{
156+
"type": "ide_execute_tool",
157+
"tool_name": "apply_edits",
158+
"arguments": {
159+
"path": "/workspace/src/main.py",
160+
"edits": [
161+
{"op": "insert", "line": 5, "text": "import os\n"},
162+
{"op": "delete", "line": 3, "count": 2}
163+
]
164+
}
165+
}
166+
```
167+
168+
### 4.4 Cline 端实现(伪代码)
169+
170+
```typescript
171+
// VscodeExecutionBridge.ts 新增
172+
case "apply_edits":
173+
return this.applyEdits(args)
174+
175+
private async applyEdits(args: Record<string, any>): Promise<string> {
176+
const filePath = this.resolvePath(args.path)
177+
this.ensureInsideWorkspace(filePath)
178+
const original = await fs.readFile(filePath, "utf-8")
179+
const lines = original.split("\n")
180+
const edits: EditOp[] = args.edits || []
181+
182+
for (const edit of edits) {
183+
switch (edit.op) {
184+
case "insert": lines.splice(edit.line - 1, 0, ...edit.text.split("\n")); break
185+
case "delete": lines.splice(edit.line - 1, edit.count); break
186+
case "replace": lines.splice(edit.start_line - 1, edit.end_line - edit.start_line + 1, ...edit.text.split("\n")); break
187+
case "append": lines.push(...edit.text.split("\n")); break
188+
}
189+
}
190+
const next = lines.join("\n")
191+
192+
const approved = await this.confirmFileChange({
193+
filePath, original, next,
194+
operation: "modify",
195+
summary: `应用 ${edits.length} 个编辑操作`,
196+
})
197+
if (!approved) return `用户未应用编辑: ${filePath}`
198+
199+
await fs.writeFile(filePath, next, "utf-8")
200+
this.sendFileChanged(filePath, "edited")
201+
return `已应用 ${edits.length} 个编辑操作: ${filePath}`
202+
}
203+
```
204+
205+
### 4.5 为什么 edits 优于 diff
206+
207+
| 场景 | diff(SEARCH/REPLACE) | edits(行操作) |
208+
|---|---|---|
209+
| 换空白字符 | ❌ 匹配失败 | ✅ 不受影响 |
210+
| 文件已被人修改 | ❌ search 文本不匹配 | ✅ 行号可能偏移但容错 |
211+
| LLM 生成难度 | 高(需输出原文字符) | 低(只需行号 + 新内容) |
212+
| 多块编辑 | 支持 | 支持 |
213+
| 传输量 | 含原文字符,较大 | 只含新内容,小 |
214+
215+
---
216+
217+
## 5. Phase 2 备选方案:直接用 VS Code WorkspaceEdit API
218+
219+
Cline 插件可以直接调 `vscode.WorkspaceEdit`,在编辑器里实时应用修改,不需要 `fs.readFile`+`fs.writeFile`(当前 `writeFile``replaceInFile` 的实现方式)。
220+
221+
```typescript
222+
// 更优实现:直接用 WorkspaceEdit(免 fs 读写)
223+
const uri = vscode.Uri.file(filePath)
224+
const edit = new vscode.WorkspaceEdit()
225+
for (const op of edits) {
226+
const pos = new vscode.Position(op.line - 1, 0)
227+
switch (op.op) {
228+
case "insert": edit.insert(uri, pos, op.text); break
229+
case "delete": edit.delete(uri, new vscode.Range(pos, pos.translate(op.count, 0))); break
230+
case "replace": edit.replace(uri, new vscode.Range(
231+
new vscode.Position(op.start_line - 1, 0),
232+
new vscode.Position(op.end_line - 1, Number.MAX_SAFE_INTEGER)
233+
), op.text); break
234+
}
235+
}
236+
await vscode.workspace.applyEdit(edit)
237+
// → 编辑器实时更新,合并到 undo 栈,用户看得见光标变化
238+
```
239+
240+
**优势**
241+
- 编辑器内实时更新,光标跟随
242+
- 修改进 VS Code 的 undo stack(Ctrl+Z 可撤)
243+
- 不触发文件系统 IO,更快
244+
245+
**当前不推荐推进**:因为 Cline 的 `confirmFileChange` 审批流程依赖"原内容 vs 新内容"的 diff 对比,`WorkspaceEdit` 直接操作编辑器缓冲区不走这个审批流程,需要重构审批机制。**后续可做,当前先走 `fs.readFile`+`fs.writeFile` 方式。**
246+
247+
---
248+
249+
## 6. 实施路径
250+
251+
| 阶段 | 内容 | 改动文件 | 工作量 |
252+
|---|---|---|---|
253+
| **Phase 1** | 新增 `ide_replace_file` 工具(复用 Cline `replace_in_file`| `ide_bridge_tools.py`(新增 1 个类) | ~50 行 Python |
254+
| **Phase 1** | 工具注册 + LLM prompt 提示 | `tool_registry.py`(注册新工具) | ~5 行 |
255+
| **Phase 2** | `ide_write_file` 新增 `mode="edit"` + `edits` 参数 | `ide_bridge_tools.py`(扩展 IdeWriteFileTool.execute) | ~80 行 Python |
256+
| **Phase 2** | Cline 新增 `apply_edits` handler | `VscodeExecutionBridge.ts`(新增 case) | ~60 行 TS |
257+
| Phase 2(可选) | 切到 `WorkspaceEdit` API | `VscodeExecutionBridge.ts` | 需重构审批流 |
258+
259+
---
260+
261+
## 7. LLM Prompt 引导
262+
263+
在 system prompt 中新增:
264+
265+
```
266+
## 文件编辑策略
267+
268+
- 创建新文件:使用 ide_write_file(mode="overwrite", content="完整内容")
269+
- 追加内容:使用 ide_write_file(mode="append", content="追加内容")
270+
- 修改已有文件(轻量):优先使用 ide_replace_file(diff="SEARCH/REPLACE")
271+
- 修改已有文件(多处修改):使用 ide_write_file(mode="edit", edits=[...])
272+
- 完全重写文件:使用 ide_write_file(mode="overwrite")
273+
```
274+
275+
---
276+
277+
## 8. 与现有 ide_write_file 的兼容性
278+
279+
- `overwrite``append` 模式行为不变,向后兼容
280+
- `mode="edit"` 是新增值,老代码不受影响
281+
- `ide_replace_file` 是完全独立的新工具
282+
- 所有现有审批流程(`confirmFileChange``require_folder_access_authorization`、路径白名单)保持不变
283+
284+
---
285+
286+
## 9. 后续工作
287+
288+
- Phase 1 实施后,`_try_repair_truncated_json`(之前加的截断修复)可以降级为兜底——因为 LLM 用 `ide_replace_file` 时不再输出长 content,JSON 截断概率大幅降低
289+
- 长期考虑在 Cline 端用 `vscode.WorkspaceEdit` 实现编辑,给用户实时编辑体验
290+
- edits 模式稳定后,考虑自动降级:当 LLM 的 `ide_write_file` 内容超 2000 字符时,工具端自动拒绝并建议切换 edits 模式

0 commit comments

Comments
 (0)