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

5.3 KiB
Raw Permalink Blame History

轮询模式改造完成

改造内容

已成功将前端从 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 时停止

事件流格式

{
  "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 减少请求次数

构建

cd static
npm run build

构建成功!输出文件:

  • static/dist/assets/task.js (3.68 kB)
  • static/dist/assets/main.js (687.51 kB)