feat: support conversation state events in JavaScript sessions
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
# Findings
|
||||
|
||||
- Git `main` 起点干净并与 `origin/main` 同步。
|
||||
- codebase-memory 项目 `home-cc-web` 索引状态为 `ready`。
|
||||
- 会话运行状态的统一判定入口是 `server.js` 中的 `isSessionRunning`。
|
||||
- 标准包源码由 `lib/javascript-session-runtime.js` 的 `packageIndexSource` 动态注入。
|
||||
- 内部脚本能力通过 `handleSessionCall` 映射到 `server.js` 注入的 `sessionApi`。
|
||||
- 会话列表刷新入口是 `broadcastSessionList`,但 idle 边沿不能仅依赖 UI 广播,需要服务端可等待的状态协议或包内封装。
|
||||
- `isSessionRunning` 由多个活动 Map/goal 状态综合推导;查询 API 必须直接复用它,不能另造状态字段。
|
||||
- 当前注入包的 HTTP `call()` 是短请求模型;最小可靠实现是新增服务端状态查询,监听和边沿判定由 `@ccweb/session` 内部封装,调用脚本不需要自行轮询。
|
||||
- `onConversationEvent` 适合设计为异步注册:`const unsubscribe = await onConversationEvent(...)`,注册阶段先验证会话并取得基线状态;注销函数同步停止计时器。
|
||||
- `scriptsDirFor(..., create=true)` 目前只在包入口不存在时写入;若不调整,已有 `.ccweb/scripts` 无法获得新增导出,因此生成包入口应在内容变化时原子刷新。
|
||||
- 现有运行时单测包含真实注入包 + 本地 HTTP MCP 的端到端骨架,可扩展为状态序列与注销验证。
|
||||
- “等待子对话回复”已有统一来源:`crossConversationWaitState(sessionId).waitingOnChildren`,其范围包括 `waiting`、`ready`、`delivering`、`failed` 的未处理跨对话回复。
|
||||
- 状态优先级采用 `running` > `waiting_for_children` > `idle`,避免会话自身仍在执行时被较弱等待态覆盖。
|
||||
- 持久子对话关系保存在 session meta 的 `createdFromKind='mcp'` 与 `createdFromSourceSessionId`;`listConversationSummaries(scope='children')` 已验证该筛选语义。
|
||||
- 新增 `getChildConversationIds` 只返回直接子对话,按现有会话列表排序后提取 ID;不递归包含孙对话。
|
||||
- 协议定型:公开 `onConversationEvent` 使用异步注册并返回同步注销函数;包内每 100ms 串行查询状态,不产生重叠请求,调用脚本无需自行轮询。
|
||||
- idle 事件 payload 为 `{ conversationId, event, previousStatus, status, occurredAt }`;只允许事件名 `idle`。
|
||||
- 注册时先取得基线:初始为 idle 不触发;后续任一活动态(running / waiting_for_children)转 idle 才触发。
|
||||
- 注销会清理定时器;已在途的状态请求返回后也会先检查 active 标记,因此不会产生注销后的新回调。
|
||||
- 监听器同步抛错或返回 rejected Promise 时不静默吞掉,按脚本未捕获异常处理;状态查询故障也停止监听并使脚本异常退出。
|
||||
- 动态包版本提升到 1.1.0,并在创建/写入/运行脚本时原子刷新生成的包入口,确保已有脚本目录获得新导出。
|
||||
- 用户明确要求抑制等待态登记延迟产生的临时 idle:服务端 idle 查询先等待 500ms 后复核,包内事件再要求 idle 连续稳定 250ms;任一时刻观察到 `waiting_for_children` 都取消 idle 候选。
|
||||
- 子对话元数据可直接使用 `compareSessionsForList` 排序,返回顺序与会话列表一致(置顶优先,其次最近更新)。
|
||||
@@ -0,0 +1,20 @@
|
||||
# Progress
|
||||
|
||||
- 2026-08-27:开始新增 `getConversationStatus` 与 `onConversationEvent`。
|
||||
- 已确定公开状态值沿用 ccweb 现有 `running` / `idle`。
|
||||
- 已确认 codebase-memory 索引可用,并定位状态判定、标准包注入和内部调用映射入口。
|
||||
- 计划审查通过;已补齐注销、边沿、manifest、重启前检查与“未完成自动继续”验收点。
|
||||
- 用户追加等待子对话状态与直接子对话 ID 查询;公开函数总数调整为 8。
|
||||
- 已定型公开 API、三态优先级、idle 边沿 payload、注销语义和已有注入包升级策略。
|
||||
- 已补充失败测试:8 函数 manifest、三态值、状态序列 idle→running→idle、注销后停止查询、直接子对话 ID、未知事件错误码。
|
||||
- 红灯结果符合预期:旧实现 manifest 仍为 5 个函数。
|
||||
- 已把 `running → 临时 idle → waiting_for_children → 稳定 idle` 固化为监听回归序列,只有最终稳定 idle 可回调。
|
||||
- 已实现服务端三态查询(idle 500ms 复核)与直接子对话 ID 查询,并接入隐藏脚本 MCP 授权链路。
|
||||
- 已实现 `@ccweb/session` 1.1.0 的 `getConversationStatus`、`getChildConversationIds`、`onConversationEvent`,包内 idle 稳定 250ms 并支持注销。
|
||||
- 已让生成的 `node_modules/@ccweb/session` 在已有脚本目录中按内容原子刷新。
|
||||
- 首轮语法检查与运行时单测通过。
|
||||
- 完整验证通过:`server.js`、运行时、MCP server、单测脚本语法检查,`javascript-session-runtime-unit` 与 `scripts/regression.js` 均成功。
|
||||
- `git diff --check` 通过;manifest 实测为 1.1.0、8 个函数、三态枚举完整。
|
||||
- 已按重启前规则确认仅当前对话运行后完成服务重启;重启后 manifest 与真实脚本均验证通过。
|
||||
- 真实闭环通过:新建子对话 → 监听 idle → 首次“未完成” → 回调内 `sendMessage` → 第二次“任务完成” → 注销;直接子对话 ID 查询和运行中状态查询同时通过。
|
||||
- 确认 `waiting_for_children` 期间及登记延迟造成的临时 idle 均不会触发监听;仅稳定活动态→idle 触发。
|
||||
@@ -0,0 +1,47 @@
|
||||
# JavaScript 会话状态与 idle 事件
|
||||
|
||||
## 目标
|
||||
|
||||
为 `@ccweb/session` 增加会话状态查询、直接子对话 ID 查询,以及指定会话从活动状态转为 `idle` 时的事件监听与注销能力;脚本不需要自行编写轮询。
|
||||
|
||||
## 已确认语义
|
||||
|
||||
- `getConversationStatus(conversationId)` 返回 `Promise<'running' | 'waiting_for_children' | 'idle'>`,优先级为 `running` > `waiting_for_children` > `idle`。
|
||||
- `getChildConversationIds(conversationId)` 返回该对话通过 MCP 创建的直接持久子对话 ID,不递归返回孙对话。
|
||||
- `onConversationEvent(conversationId, 'idle', listener)` 监听 `running/waiting_for_children → idle` 边沿,不因注册时已是 `idle` 而立即触发。
|
||||
- `onConversationEvent` 返回注销函数;注销后不再产生新回调。
|
||||
- 第一版只公开 `idle` 事件,但协议应便于后续扩展。
|
||||
- 回调错误不应破坏底层监听;由脚本自己的未捕获异常规则处理。
|
||||
|
||||
## 阶段
|
||||
|
||||
1. [complete] 梳理现有会话状态与脚本包调用链
|
||||
2. [complete] 确定状态查询、idle 等待、取消注销和 manifest 的协议语义
|
||||
3. [complete] 补充失败测试覆盖状态查询和 idle 监听
|
||||
4. [complete] 实现服务端状态查询与事件等待能力
|
||||
5. [complete] 实现 @ccweb/session 监听、注销和状态 API
|
||||
6. [complete] 更新 manifest 并运行单元与回归测试
|
||||
7. [complete] 检查运行对话后重启并验证 idle 后未完成则继续发送的闭环
|
||||
8. [complete] 清理临时计划并交付使用示例
|
||||
|
||||
## 风险
|
||||
|
||||
- 长时间监听必须能让脚本进程保持运行,又不能在注销后遗留服务端等待器。
|
||||
- idle 必须是活动状态到 idle 的边沿事件,不能把“注册时已经 idle”误判为新完成。
|
||||
- 当前来源对话允许 steer;事件监听必须与现有状态判定保持一致。
|
||||
- 重启前必须确认除当前对话外不存在其他 `running` 会话;否则不重启并记录阻塞。
|
||||
|
||||
## 协议验收清单
|
||||
|
||||
- 状态查询:按 conversationId 返回 `running`、`waiting_for_children` 或 `idle`。
|
||||
- 子对话查询:按 conversationId 返回直接子对话 ID 数组,不递归。
|
||||
- 事件等待:只支持 `idle`,且只响应 `running/waiting_for_children → idle`。
|
||||
- 注销取消:注销后停止包内监听,不再回调,也不遗留活动资源。
|
||||
- manifest:三个新函数的参数、返回值、状态值、触发/注销语义和错误码与实现一致,总计 8 个函数。
|
||||
- 场景闭环:idle 回调中判断任务未完成后调用 `sendMessage` 继续,随后再次进入 idle。
|
||||
|
||||
## 错误记录
|
||||
|
||||
| 错误 | 尝试 | 处理 |
|
||||
|---|---:|---|
|
||||
| 运行时单测 `5 !== 8` | 1 | 预期的红灯,证明新增 manifest/API 测试在旧实现上失败;进入实现阶段。 |
|
||||
Reference in New Issue
Block a user