订阅模式
入口页只负责入口摘要;--agent 的完整运行心智、协议链路和排障继续看这里。
重点是讲清它为什么不是 chat / fast / plan 的附属状态,而是一条独立的订阅执行面。
先判断是不是这页的范围
- 你要理解
--agent做了什么,以及它和chat / fast / plan的边界:看这里 - 你要排查
/agents/open、/agents/ws、resume、断线重连和消息去重:看这里 - 你只是想在本地交互输入目标,切换
CHAT / FAST / PLAN:先看交互模式 - 你只想理解项目整体分层,不需要进入协议细节:先看
背景与架构
怎么读这页
- 先看“模式定位”和“启动流程”,建立
agent的基本心智 - 再看“协议时序”和“任务下发”,理解服务端如何把任务推到本地
- 最后看“恢复与排障”,确认 409、断线和重放时应该怎么看
模式定位
--agent 是一条独立的订阅模式,不是 REPL 内部状态之一。
chat / fast / plan:本地主动发起一次请求,再等待本轮执行结束agent:本地先向服务端注册会话,再通过长链路持续接收服务端下发的任务
入口关系:
- CLI 参数层面,--agent 与 --chat / --fast / --plan 是同级互斥入口
- 运行时层面,Mind.agent_loop() 直接进入订阅循环,不经过 REPL 三态切换
一句话理解:
chat / fast / plan是本地主动请求agent是本地订阅,等待服务端推任务
启动流程
当执行:
mind --agent
本地会按下面的顺序进入订阅模式:
- 构造
AgentConfig - 生成稳定
device_id - 调用
/agents/open - 从响应中提取
session_id / ws_token / resume_token / ws_url - 建立
/agents/ws长链路 - 发送
hello - 进入持续监听状态
启动时本地会带上这些身份信息:
- agent_id
- device_id
- client_version
- platform
- arch
- hostname
其中:
- device_id 是根据主机名、网卡地址、系统和架构做稳定摘要,不是随机临时值
- 服务端如果认为当前 agent + device 已有未释放会话,open 可能返回 409
协议时序
高层时序可以理解成:
mind --agent
↓
POST /agents/open
↓
session_id / ws_token / resume_token
↓
connect /agents/ws
↓
hello
↓
ready
↓
ping / pong
↓
mind.forward
↓
mind.received
↓
本地执行 chat / fast / plan 或 code 任务
几个关键消息:
hello:本地首次握手,声明当前客户端版本和设备身份ready:服务端确认长链路已进入可用状态,并返回心跳与恢复相关参数ping / pong:链路保活mind.forward:服务端正式下发任务mind.received:本地确认“我已经收到这条任务”,不是“任务已执行成功”resume:断线后告诉服务端,本地已经确认到哪个seqreplay.batch:服务端补发断线期间的历史消息
任务下发
agent 模式本身不直接定义新执行器;它做的是把服务端任务映射回本地已有运行面。
下发任务里的执行模式目前只允许:
- chat
- fast
- plan
如果任务走“输入入口列表”模式:
- 类型是 list[str]
- 常见项包括本地文件路径、inline:...、https://... 或 -
- 服务端只做链接合法性校验和透传,不做意图抽取
映射关系:
- 文本输入非空:mind.calling(message=..., mode=...)
- 文本输入为空且输入入口列表非空:mind.mind_pack(profile, mode, ...)
关键约束:
- mode 不是任意字符串,只能落回本地现有三种执行面
- 同时存在文本输入和输入入口列表时,本地按文本输入优先执行
- 文本输入与意图摘要在输入入口列表模式下都可能为空
- 本地会先发 mind.received,再把实际执行放到后台任务里,避免阻塞 WS 心跳
恢复与重连
agent 模式默认把“不断线”当成不现实前提,所以恢复链路是核心能力,不是补丁逻辑。
正常恢复
当 WS 因网络、超时或服务端抖动断开后,本地会:
- 保留
session_id / resume_token / last_acked_seq - 调用
/agents/resume - 如果服务端返回
resumable=true,复用原会话 - 重连 WS 后发送
resume - 接收可能的
replay.batch
恢复失败后的回退
如果服务端认为会话已不可恢复:
- 本地把状态标记为
Resume Expired - 再次调用
/agents/open - 打开一个全新的订阅会话
这就是文档里常说的 resume or reopen。
去重与确认
agent 模式同时维护两类确认信息:
- 已确认的服务端消息序号:用于断线恢复
- 已执行过的任务消息标识:避免重放时重复执行
因此要注意:
- mind.received 解决的是“服务端知道你收到了”
- 本地去重缓存解决的是“本地不要把同一条任务执行两次”
- 它们不是一回事,不能混为“任务成功回执”
常见排障
/agents/open 返回 409
通常表示服务端仍认为同一个 agent 持有旧会话。
排查建议: - 先确认是否已有另一台同标识实例在线 - 看服务端是否还保留旧会话 - 本地实现会等待 5 秒后继续重试,不会立刻退出
一直在重连
优先看这几类问题:
- 服务端地址或 ws_url 是否正确
- X-Agent-Token 对应的 client secret 是否匹配
- 网络是否允许 HTTP 成功但 WS 被拦截
- 服务端是否在 ready 前主动断链
可以连上但不执行任务
优先确认:
- 是否收到了 mind.forward
- 执行模式是否是 chat / fast / plan
- 文本输入是否非空;如果为空,再看输入入口列表是否是非空列表
- 消息是否因为缺少必要的任务标识或会话标识被本地丢弃
怀疑任务被重复执行
优先检查:
- 服务端是否重复投递了相同任务消息标识
- 本地日志里是否出现 mind.forward replay skipped
- 断线恢复后是否发生了 replay.batch
和其他文档的关系
交互模式讲的是 REPL 三态,不覆盖agent背景与架构讲系统骨架,不展开agent协议时序- 如果后续
agent引入新的下发消息类型、执行结果回传协议或服务端治理约束,应继续补这页,而不是把细节塞回入口文档