跳转到主要内容
Zeus 的消息队列包含两个层面:用户侧消息队列(允许用户在 Agent 处理时排队发送消息)和后端事件持久化系统(确保消息可靠投递)。

用户消息队列

当 Agent 正在处理回复时,用户可以继续输入并排队发送消息,无需等待。

行为规则

场景行为
Agent 处理中 + 用户发送消息加入队列(不立即发送)
Agent 正常完成100 ms 后自动发送队列中的下一条
Agent 被中断(Stop)队列不自动消费,由用户决定发送哪条
用户点击队列中的立即发送(↑)停止当前生成(如有),然后发送该消息

队列 UI

当有排队消息时,队列面板显示在聊天输入框上方:
  • 编辑(铅笔图标)— 行内编辑排队消息内容
  • 立即发送(↑ 箭头图标)— 停止当前生成并立即发送此消息
  • 移除(垃圾桶图标)— 从队列中删除

截断上下文

当回复被中途停止时,AI 的部分内容会保留在对话历史中,作为后续消息的上下文。同时持久化到数据库,刷新页面后不丢失。

对话与文件回退

用户可以回退到任意一轮对话,类似 Cursor 的分支模型。

对话回退

  1. 鼠标悬停在用户消息上 → 点击回退按钮(↺)
  2. 回退点之后的消息变灰(40% 透明度),不会删除
  3. 出现分叉分隔线,带有取消回退选项
  4. 新消息添加在分隔线下方
  5. 发送给后端的聊天历史只包含回退点之前的消息

文件回退

当用户回退时,回退点之后被修改的沙盒文件会恢复到之前的状态:
handleRollback(forkMessageId)
  → 保存当前文件为 preRollbackFiles
  → 收集 forkMessageId 之后的 FileSnapshot
  → POST /api/sandbox/restore-files(写回旧版本)
  → 更新 trajectoryStore.sandboxFiles
取消回退会逆向操作,从 preRollbackFiles 恢复最新文件版本。

刷新后文件恢复

沙盒文件从数据库事件中恢复,而非仅依赖 E2B 沙盒存活状态,因此即使沙盒过期文件也不会丢失。 文件内容按需加载:当用户点击内容为空的文件标签时,前端调用 GET /api/sandbox/read-file 从沙盒获取内容。

Event Persistence

RealtimeEventSaver

RealtimeEventSaver 负责将实时 SSE 事件批量持久化到数据库:

配置

配置项说明
批量大小3 个事件缓冲区达到此数量时触发写入
批量间隔100ms即使未满也定时刷新
重试次数3 次最大重试次数
重试策略指数退避1s → 2s → 4s
降级方案LocalStorage所有重试失败后的备份存储

Message Batching

前端消息合并

前端合并快速连续的文本更新,避免过度渲染:
策略说明
UI 批量刷新约 60fps 频率批量更新,合并快速连续的 token
虚拟滚动只渲染可视区域的消息卡片
选择性持久化只持久化 sessionIdmessageIds,消息内容按需加载

Chat History 构建

前端从 Zustand Store 加载当前会话的消息历史,排除当前正在发送的消息,传递给后端。后端将其转换为 LangChain 消息类型,限制最多 30 条

Concurrency & Isolation

隔离维度机制说明
Sessionthread_id每个 Session 拥有独立的 Checkpointer 状态
Contextsession_idContext Cache 按 session_id 隔离,resume 只恢复对应会话
工具执行LangGraph同一 Session 内工具串行执行,不会并发
工作空间user_id用户文件系统按 user_id 完全隔离

Session Recovery

系统支持会话中断后的恢复:

保存时机

  • 工具调用完成后
  • 消息发送后
  • HITL 中断时(通过 Checkpointer)

恢复流程


Messages

完整的消息流程、请求参数和状态管理

Retry Policy

错误处理、重试策略和降级方案