agent-Specialization/BUG_FIX_V2_CHANGELOG.md
JOJO 07be7a1061 feat: gracefully stop tool execution on user request
- Remove direct task.cancel() calls, use stop flag instead
- Monitor stop flag every 100ms during tool execution
- Cancel tool task immediately when stop flag is detected
- Return "命令执行被用户取消" as tool result with role=tool
- Save cancellation result to conversation history
- Prevent abrupt task termination, allow graceful shutdown

Changes:
- server/socket_handlers.py: Comment out pending_task.cancel()
- server/tasks.py: Comment out entry['task'].cancel()
- server/chat_flow_tool_loop.py: Add stop flag monitoring loop

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-08 03:50:34 +08:00

192 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Bug 修复 v2 - 工具块和轮询优化
## 修复的问题
### 1. 工具块无法显示
**原因**: 工具事件处理逻辑不完整,缺少关键的工具创建和更新逻辑
**解决方案**:
- 完整实现 `handleToolPreparing()` - 创建工具准备块
- 完整实现 `handleToolStart()` - 工具开始执行
- 完整实现 `handleToolUpdateAction()` - 工具状态更新和完成
- 添加 `update_action` 事件处理(工具完成的关键事件)
- 在 WebSocket 中跳过 `update_action` 事件
### 2. 轮询频率太慢1秒
**原因**: 1秒的轮询间隔无法提供流式输出的体验
**解决方案**:
- 将轮询间隔从 1000ms 改为 **150ms**
- 接近流式输出的效果(每秒约 6-7 次更新)
-`stores/task.ts` 中修改 `startPolling()` 方法
### 3. 刷新后加载两遍内容
**原因**:
- `restoreTaskState()` 没有检查是否已在流式输出中
- `handleTaskComplete()` 会重新加载历史记录
**解决方案**:
-`restoreTaskState()` 中添加状态检查,避免重复恢复
- 检查最后一条消息是否是 assistant 消息
-`handleTaskComplete()` 中移除 `fetchAndDisplayHistory()`,只更新统计
## 修改的文件
### 1. static/src/app/methods/taskPolling.ts
**工具处理逻辑**:
```javascript
handleToolPreparing(data) {
// 创建工具准备块
const action = {
id: data.id,
type: 'tool',
tool: {
status: 'preparing',
name: data.name,
// ... 完整的工具属性
}
};
msg.actions.push(action);
this.preparingTools.set(data.id, action);
}
handleToolStart(data) {
// 从 preparing 转为 running
let action = this.preparingTools.get(data.preparing_id);
action.tool.status = 'running';
action.tool.arguments = data.arguments;
// ... 更新工具状态
}
handleToolUpdateAction(data) {
// 更新工具状态(包括完成)
let targetAction = this.toolFindAction(data.id, ...);
targetAction.tool.status = data.status;
targetAction.tool.result = data.result;
// ... 更新工具结果
}
```
**恢复逻辑优化**:
```javascript
async restoreTaskState() {
// 检查是否已在流式输出中
if (this.streamingMessage || this.taskInProgress) {
return;
}
// 检查是否已有 assistant 消息
const lastMessage = this.messages[this.messages.length - 1];
const hasAssistantMessage = lastMessage && lastMessage.role === 'assistant';
// 只标记状态,不清空消息
this.streamingMessage = true;
this.taskInProgress = true;
}
```
**任务完成优化**:
```javascript
handleTaskComplete(data) {
// 只更新统计,不重新加载历史
this.fetchConversationTokenStatistics();
this.updateCurrentContextTokens();
// 移除了 fetchAndDisplayHistory()
}
```
### 2. static/src/stores/task.ts
**轮询频率优化**:
```javascript
startPolling(eventHandler) {
// 150ms 间隔,接近流式输出效果
this.pollingInterval = window.setInterval(() => {
this.pollTaskEvents(handler);
}, 150);
}
```
### 3. static/src/composables/useLegacySocket.ts
**跳过 update_action 事件**:
```javascript
ctx.socket.on('update_action', (data) => {
if (ctx.usePollingMode) {
return; // 跳过 WebSocket 事件
}
// ... 原有逻辑
});
```
## 事件处理流程
### 工具执行流程
1. `tool_preparing` → 创建工具准备块
2. `tool_start` → 工具开始执行,更新状态为 running
3. `update_action` → 工具完成,更新状态为 completed显示结果
### 轮询流程
1. 每 150ms 轮询一次
2. 获取新事件(通过 `from` 参数)
3. 处理事件,更新界面
4. 任务完成后停止轮询
### 刷新恢复流程
1. 页面加载完成
2. 延迟 1 秒后调用 `restoreTaskState()`
3. 检查是否已在流式输出中(避免重复)
4. 检查是否已有 assistant 消息(历史已加载)
5. 只标记状态,启动轮询
6. 轮询只处理新事件,不重建历史
## 性能优化
- **轮询频率**: 150ms每秒约 6-7 次)
- **事件增量获取**: 通过 `from` 参数只获取新事件
- **避免重复加载**: 检查状态和消息,避免重复恢复
- **避免重复显示**: 任务完成后不重新加载历史
## 测试建议
1. **工具块显示**
- 发送需要调用工具的消息
- 观察工具块是否正常显示
- 观察工具状态变化preparing → running → completed
- 观察工具结果是否正确显示
2. **流式输出效果**
- 发送消息,观察输出是否流畅
- 观察思考块、文本块的更新频率
- 对比之前 1 秒轮询的卡顿感
3. **刷新恢复**
- 任务执行中刷新页面
- 观察是否只显示一遍内容
- 观察新内容是否正常追加
- 观察工具块是否保留
4. **任务完成**
- 等待任务完成
- 观察是否有重复内容
- 观察统计是否正确更新
## 构建
```bash
cd static
npm run build
```
构建成功!
- `static/dist/assets/main.js` (689.89 kB)
- `static/dist/assets/task.js` (3.68 kB)
## 已知改进
- ✅ 工具块正常显示
- ✅ 轮询频率提升到 150ms接近流式效果
- ✅ 刷新后不重复显示内容
- ✅ 任务完成后不重复加载历史
- ✅ 状态检查避免重复恢复
现在可以启动服务器测试了!