agent-Specialization/POLLING_MODE_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

181 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.

# 轮询模式改造完成
## 改造内容
已成功将前端从 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)