- 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>
181 lines
5.3 KiB
Markdown
181 lines
5.3 KiB
Markdown
# 轮询模式改造完成
|
||
|
||
## 改造内容
|
||
|
||
已成功将前端从 WebSocket 实时推送模式改造为 REST API + 轮询模式。
|
||
|
||
### 主要变更
|
||
|
||
#### 1. 后端改造
|
||
- **server/tasks.py**: 已有完整的任务管理系统
|
||
- `POST /api/tasks` - 创建任务
|
||
- `GET /api/tasks/<task_id>?from=<offset>` - 轮询任务事件
|
||
- `POST /api/tasks/<task_id>/cancel` - 取消任务
|
||
- 支持 videos 和 run_mode 参数
|
||
|
||
#### 2. 前端改造
|
||
- **stores/task.ts** (新建): 任务轮询状态管理
|
||
- `createTask()` - 创建任务并启动轮询
|
||
- `pollTaskEvents()` - 轮询任务事件
|
||
- `startPolling()` / `stopPolling()` - 控制轮询
|
||
- `loadRunningTask()` - 加载运行中的任务(用于页面刷新恢复)
|
||
|
||
- **app/methods/taskPolling.ts** (新建): 事件处理器
|
||
- `handleTaskEvent()` - 统一事件分发
|
||
- `handleAiMessageStart()` - AI 消息开始
|
||
- `handleThinkingStart/Chunk/End()` - 思考过程
|
||
- `handleTextStart/Chunk/End()` - 文本输出
|
||
- `handleToolPreparing/Start/UpdateAction()` - 工具执行
|
||
- `handleAppendPayload/ModifyPayload()` - 文件操作
|
||
- `handleTaskComplete()` - 任务完成
|
||
- `restoreTaskState()` - 恢复任务状态(页面刷新后)
|
||
|
||
- **app/methods/message.ts**: 修改消息发送逻辑
|
||
- 改为调用 REST API 创建任务
|
||
- 停止任务改为调用 REST API 取消任务
|
||
- 保留 WebSocket 兼容性(命令模式)
|
||
|
||
- **app/lifecycle.ts**: 修改生命周期
|
||
- `mounted()` 中注册全局事件处理器
|
||
- `mounted()` 中延迟调用 `restoreTaskState()` 恢复任务
|
||
- `beforeUnmount()` 中停止轮询
|
||
|
||
- **app.ts**: 集成任务轮询方法
|
||
|
||
## 功能特性
|
||
|
||
### ✅ 已实现
|
||
|
||
1. **后端独立运行**
|
||
- 任务创建后在后台线程运行
|
||
- 不依赖 WebSocket 连接
|
||
- 事件完整记录到内存队列(最多 1000 条)
|
||
|
||
2. **前端轮询更新**
|
||
- 1 秒间隔轮询任务事件
|
||
- 增量获取新事件(通过 `from` 参数)
|
||
- 任务完成后自动停止轮询
|
||
|
||
3. **页面刷新恢复**
|
||
- 页面加载时自动查找运行中的任务
|
||
- 从事件流重建前端状态
|
||
- 恢复思考块、文本块、工具块的展开状态
|
||
- 继续轮询更新新事件
|
||
|
||
4. **状态完整恢复**
|
||
- 正在输出的思考内容 → 展开的思考块 + 已输出内容
|
||
- 正在输出的文本内容 → 文本块 + 已输出内容
|
||
- 正在执行的工具 → 工具块 + 执行状态
|
||
- 文件操作 → append/modify payload 块
|
||
|
||
5. **任务取消**
|
||
- 支持通过 REST API 取消任务
|
||
- 前端立即清理状态
|
||
- 后端标记停止标志
|
||
|
||
## 使用方式
|
||
|
||
### 正常使用
|
||
1. 输入消息并发送
|
||
2. 后端自动创建任务并开始执行
|
||
3. 前端每秒轮询一次,实时更新界面
|
||
4. 任务完成后自动停止轮询
|
||
|
||
### 页面刷新
|
||
1. 刷新页面
|
||
2. 前端自动检测运行中的任务
|
||
3. 从事件流重建状态(思考块、文本块、工具块)
|
||
4. 继续轮询更新新事件
|
||
5. 显示提示:"检测到进行中的任务,已恢复连接"
|
||
|
||
### 停止任务
|
||
1. 点击停止按钮
|
||
2. 调用 REST API 取消任务
|
||
3. 前端立即清理状态
|
||
4. 后端收到停止信号后终止执行
|
||
|
||
## 技术细节
|
||
|
||
### 轮询机制
|
||
- 间隔:1 秒
|
||
- 增量获取:通过 `from` 参数指定起始事件索引
|
||
- 自动停止:任务状态为 `succeeded/failed/canceled` 时停止
|
||
|
||
### 事件流格式
|
||
```json
|
||
{
|
||
"idx": 0,
|
||
"type": "ai_message_start",
|
||
"data": {},
|
||
"ts": 1234567890.123
|
||
}
|
||
```
|
||
|
||
### 任务状态
|
||
- `pending` - 待执行
|
||
- `running` - 执行中
|
||
- `succeeded` - 成功完成
|
||
- `failed` - 执行失败
|
||
- `canceled` - 已取消
|
||
|
||
### 事件类型
|
||
- `ai_message_start` - AI 消息开始
|
||
- `thinking_start/chunk/end` - 思考过程
|
||
- `text_start/chunk/end` - 文本输出
|
||
- `tool_preparing/start/update_action` - 工具执行
|
||
- `append_payload/modify_payload` - 文件操作
|
||
- `task_complete` - 任务完成
|
||
- `error` - 错误
|
||
- `token_update` - Token 统计更新
|
||
- `conversation_resolved` - 对话已解析
|
||
|
||
## 兼容性
|
||
|
||
- ✅ 保留 WebSocket 连接(用于命令模式和实时推送)
|
||
- ✅ 命令模式(`/clear` 等)仍使用 WebSocket
|
||
- ✅ 在线用户仍可收到实时推送(通过 `socketio.emit` 到房间)
|
||
- ✅ 支持多标签页同时查看进度
|
||
|
||
## 测试建议
|
||
|
||
1. **基本功能测试**
|
||
- 发送消息,观察是否正常输出
|
||
- 刷新页面,观察是否恢复状态
|
||
- 停止任务,观察是否立即停止
|
||
|
||
2. **边界情况测试**
|
||
- 任务执行中刷新多次
|
||
- 任务完成后刷新
|
||
- 多个标签页同时打开
|
||
- 网络断开后重连
|
||
|
||
3. **性能测试**
|
||
- 长时间运行任务(观察轮询是否稳定)
|
||
- 大量事件(1000+ 条)
|
||
- 多用户并发
|
||
|
||
## 已知限制
|
||
|
||
1. **事件队列大小**: 最多保留 1000 条事件(deque maxlen=1000)
|
||
2. **任务持久化**: 当前仅内存存储,服务器重启后丢失
|
||
3. **并发限制**: 单用户单工作区同时只能有一个任务
|
||
|
||
## 后续优化建议
|
||
|
||
1. **持久化**: 将任务和事件存储到 Redis/数据库
|
||
2. **事件压缩**: 对历史事件进行压缩存储
|
||
3. **断点续传**: 支持从任意事件索引恢复
|
||
4. **WebSocket 降级**: 完全移除 WebSocket 依赖
|
||
5. **长轮询**: 使用 long-polling 减少请求次数
|
||
|
||
## 构建
|
||
|
||
```bash
|
||
cd static
|
||
npm run build
|
||
```
|
||
|
||
构建成功!输出文件:
|
||
- `static/dist/assets/task.js` (3.68 kB)
|
||
- `static/dist/assets/main.js` (687.51 kB)
|