跳到正文
FunCoding

搜索

搜索文档、Skill 和 MCP

会话生命周期与客户端身份

区分 create、attach、load、resume、detach 和会话终止。

一个 daemon session 是绑定 ACP sessionId 的逻辑对话。client 是参与它的控制端;SSE subscriber 又只是某次事件订阅。三者生命周期不同,不能用“断开连接”统称所有关闭。

创建、附加与恢复

操作含义
POST /session,single scope已有 default session 时附加,否则创建
POST /session,thread scope创建独立对话,仍受 maxSessions 约束
POST /session/:id/load恢复并返回有界 replay snapshot
POST /session/:id/resume恢复但不请求同样的历史 replay
POST /session/:id/detach解除一个 client 的附着,返回 204;本身不是持久删除

恢复使用 pendingRestoreIds 避免同 ID 并发重复进行,并缓存 restoreState 供稍后附加者。session_resume 是稳定 daemon capability,ACP 内部方法仍可叫 unstable_resumeSession;客户端不应继续只检测旧别名。

Client ID 的选择

X-Qwen-Client-Id 由客户端自行选择,daemon 不代为生成。格式为 [A-Za-z0-9._:-]{1,128}。不同 controller 应使用各自稳定 ID;宿主与嵌入 Web Shell 只有确实作为同一逻辑控制端时才共用。

共用 ID 后,日志无法区分是谁发起请求。它也不是登录身份或 proof-of-possession;审批边界见多客户端审批。

关联事件可在 envelope 中带 originatorClientId。对自己的用户回显或 mid_turn_message_injected 去重前,必须比较实际 originator,不能因为自己也订阅该 session 就丢掉所有用户消息。

心跳与元数据

POST /session/:id/heartbeat 更新 sessionLastSeenAt;携带已登记 ID 时也更新对应 clientLastSeenAt。当前心跳提供可见性,不实施 v1 单客户端撤销/驱逐策略。

PATCH /session/:id/metadata 更新 displayName,长度最多 256,拒绝 U+0000–U+001F 和 U+007F 控制字符。成功后广播 session_metadata_updated。

终止信号

事件范围
session_closedsession 主动关闭或确认的 workspace runtime stop
session_diedchild 异常退出、其他 kill 路径或 daemon shutdown
client_evicted仅当前慢 subscriber 被关闭,session 可继续
stream_error当前订阅建立或传输失败

确认的 workspace stop 若仍有持久化不确定,会在 session_closed 带 persistenceUnconfirmed:true;客户端不能把所有 closed 都解释为历史已可靠落盘。

创建者断线不误杀附加者

创建请求因 TCP reset 无法交付时,route 可要求 requireZeroAttaches 清理新 session。如果其他客户端已经附加,则先保留 session,并记录 spawnOwnerWantedKill;后续 detach 使附着数归零时再完成延后清理。

同理,detach 与 subscriber 关闭的最终回收要结合剩余引用判断,不应把本客户端离开当作所有参与者都结束。持久归档和删除另见会话存储状态。