# 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（接近流式效果）
- ✅ 刷新后不重复显示内容
- ✅ 任务完成后不重复加载历史
- ✅ 状态检查避免重复恢复

现在可以启动服务器测试了！
