feat: summarize codex app server turns

This commit is contained in:
AI Bot
2026-06-03 10:17:07 +08:00
parent 74b333ba2f
commit 1ae81fa3af
11 changed files with 200 additions and 5 deletions

View File

@@ -85,6 +85,7 @@
- 当前 App Server heartbeat discovery 已扩展到 `experimentalFeature/list / collaborationMode/list / permissionProfile/list / mcpServerStatus/list`,设备详情页会展示“治理:实验特性 / 协作模式 / MCP / 权限”摘要MCP 只保留服务名、工具数量、资源数量和认证状态permission profile 只保留 id/description不保存本地路径、resource URI、文件规则、token 或工具参数。 - 当前 App Server heartbeat discovery 已扩展到 `experimentalFeature/list / collaborationMode/list / permissionProfile/list / mcpServerStatus/list`,设备详情页会展示“治理:实验特性 / 协作模式 / MCP / 权限”摘要MCP 只保留服务名、工具数量、资源数量和认证状态permission profile 只保留 id/description不保存本地路径、resource URI、文件规则、token 或工具参数。
- 当前 App Server heartbeat discovery 已继续扩展到 `account/read / account/rateLimits/read / config/read / configRequirements/read / externalAgentConfig/detect`设备详情页会展示账号、套餐、额度、App 配置、托管要求和外部 Agent 迁移候选摘要该链路只保存计数、开关和状态不保存邮箱、API key、完整 config、本地路径、迁移描述或外部 Agent 原始内容。 - 当前 App Server heartbeat discovery 已继续扩展到 `account/read / account/rateLimits/read / config/read / configRequirements/read / externalAgentConfig/detect`设备详情页会展示账号、套餐、额度、App 配置、托管要求和外部 Agent 迁移候选摘要该链路只保存计数、开关和状态不保存邮箱、API key、完整 config、本地路径、迁移描述或外部 Agent 原始内容。
- 当前 App Server heartbeat discovery 已新增 `thread/list / thread/loaded/list` 线程可见性摘要设备详情页会展示线程总数、已加载线程、活跃线程和最新更新时间metadata 只保留非归档线程的 `id / name / sourceKind / status / updatedAt / loaded` 轻量目录,不保存 cwd、本地路径、turn 内容、用户正文或内部 prompt。 - 当前 App Server heartbeat discovery 已新增 `thread/list / thread/loaded/list` 线程可见性摘要设备详情页会展示线程总数、已加载线程、活跃线程和最新更新时间metadata 只保留非归档线程的 `id / name / sourceKind / status / updatedAt / loaded` 轻量目录,不保存 cwd、本地路径、turn 内容、用户正文或内部 prompt。
- 当前 App Server heartbeat discovery 已新增 `thread/turns/list` turn 运行态摘要,设备详情页会展示总轮次、运行中轮次、完成轮次和最新 turn 更新时间;请求固定使用 `itemsView=notLoaded`metadata 只保留每个线程的 turn 计数、最近状态和更新时间,不保存 turn id、items、用户输入、模型输出或内部 prompt。
- `GET http://127.0.0.1:4317/api/v1/skills` 正常,已返回本机扫描到的 Codex Skill - `GET http://127.0.0.1:4317/api/v1/skills` 正常,已返回本机扫描到的 Codex Skill
- `POST http://127.0.0.1:4317/api/v1/heartbeat` 正常,且会顺带触发 `thread-context` 上报 - `POST http://127.0.0.1:4317/api/v1/heartbeat` 正常,且会顺带触发 `thread-context` 上报
- `local-agent` 当前每 5 秒轮询一次本机 Skill lifecycle 请求;默认打开 `skillLifecycleEnabled=true`。远程 `install` 或带 `sourceUrl` 的更新必须命中 `skillLifecycleAllowedSources``skillLifecycleTrustedSources`,为空时只允许既有本地 Skill 的 `update / rollback / uninstall / version_lock`;请求携带 `checksum / expectedChecksum` 时会校验 `manifest.json``SKILL.md` 的 sha256失败会清理半安装目录或尽量恢复备份。卸载 / 更新 / 回滚前会在 `skillsDir/.boss-skill-backups` 保留备份,卸载仍限制在 `skillsDir` 目录内,版本锁写入 `.boss-skill-locks.json` - `local-agent` 当前每 5 秒轮询一次本机 Skill lifecycle 请求;默认打开 `skillLifecycleEnabled=true`。远程 `install` 或带 `sourceUrl` 的更新必须命中 `skillLifecycleAllowedSources``skillLifecycleTrustedSources`,为空时只允许既有本地 Skill 的 `update / rollback / uninstall / version_lock`;请求携带 `checksum / expectedChecksum` 时会校验 `manifest.json``SKILL.md` 的 sha256失败会清理半安装目录或尽量恢复备份。卸载 / 更新 / 回滚前会在 `skillsDir/.boss-skill-backups` 保留备份,卸载仍限制在 `skillsDir` 目录内,版本锁写入 `.boss-skill-locks.json`

View File

@@ -153,7 +153,7 @@
- Web 和原生 Android 当前都已经接上“新设备导入草稿 -> 勾选 -> 决议预览 -> 应用导入”的前台页面;已绑定生产设备继续保留 heartbeat 自动导入链路 - Web 和原生 Android 当前都已经接上“新设备导入草稿 -> 勾选 -> 决议预览 -> 应用导入”的前台页面;已绑定生产设备继续保留 heartbeat 自动导入链路
- 原生首页的刷新失败策略当前已改成按当前 tab 独立判错,不会再因为 `设备 / 设置 / OTA` 的旁路请求失败把会话页刷新一并判成失败 - 原生首页的刷新失败策略当前已改成按当前 tab 独立判错,不会再因为 `设备 / 设置 / OTA` 的旁路请求失败把会话页刷新一并判成失败
- 当前量产方向已经明确为“Boss 企业控制面 + 可插拔执行协议”:多租户、权限、审批、审计、备份、回退和 Skill 治理由 Boss 承担Codex App Server / Codex MCP / Codex CLI / Computer Use / 业务系统 API 都作为 provider 接入;详见 `docs/architecture/enterprise_ai_ops_architecture_cn.md` - 当前量产方向已经明确为“Boss 企业控制面 + 可插拔执行协议”:多租户、权限、审批、审计、备份、回退和 Skill 治理由 Boss 承担Codex App Server / Codex MCP / Codex CLI / Computer Use / 业务系统 API 都作为 provider 接入;详见 `docs/architecture/enterprise_ai_ops_architecture_cn.md`
- 当前 Codex App Server 已完成十批接入boss-agent 默认开启 `local-agent/codex-app-server-runner.mjs` 作为 Codex 绑定入口,优先走 `codex app-server` stdio也可灰度连接 `ws://127.0.0.1:<port>``unix://PATH` 同机长驻 App Server长驻连接支持 `Authorization: Bearer <token>`,配置上优先使用 `codexAppServerAuthTokenFile`。turn 启动前失败才回退 CLIturn 启动后不重复执行;桌面远程控制默认先走 `codex-computer-use`,失败后回退 `cua-driver-computer-use`。2026-05-31 已按本机 `codex-cli 0.135.0-alpha.1` 生成协议快照 `docs/protocol-snapshots/codex-app-server/0.135.0-alpha.1/`,并把 `turn/plan/updated``turn/diff/updated``item/started|completed``thread/started``item/*/requestApproval``item/autoApprovalReview/*``guardianWarning``serverRequest/resolved``item/fileChange/patchUpdated``thread/status/changed``thread/realtime/*``model/rerouted``thread/tokenUsage/updated``mcpServer/startupStatus/updated``remoteControl/status/changed``windowsSandbox/setupCompleted``thread/goal/*``thread/settings/updated``thread/compacted``account/updated``account/rateLimits/updated``model/verification``warning``configWarning``deprecationNotice``ThreadItem.collabToolCall``ThreadItem.contextCompaction``mcpToolCall``dynamicToolCall``webSearch``imageView``imageGeneration``hook/started|completed``enteredReviewMode``exitedReviewMode``commandExecution``ThreadItem.plan``ThreadItem.reasoning.summary` 归一到 Boss `execution_progress` 卡片realtime 只保留状态、文本摘要和计数运行状态只保留模型切换、上下文用量、MCP 状态、远控连接摘要和 Windows 沙箱准备状态,线程配置只保留目标、模型、审批、沙箱、协作模式和压缩状态,线程协作只保留工具名、状态、目标类型和智能体状态,工具活动只保留类型、名称、状态和安全摘要,图像生成只保留状态与安全文件名,钩子生命周期只保留事件名、处理器类型、状态、来源、执行模式和耗时,思考摘要只保留官方 summary 文本和状态,账号状态只保留认证方式、套餐、额度窗口、积分余额和模型校验摘要,不保存 SDP、音频原始数据、raw item、remote installationId、cwd、turnId、配置文件路径、collab 源/目标线程 ID、collab prompt、tool arguments/result/contentItems、web URL token、命令正文/输出、raw reasoning content、reasoning item id、imageGeneration revisedPrompt/result、hook sourcePath/statusMessage/entries、Windows sandbox sourcePath/samplePaths/本地绝对路径或未清洗密钥。heartbeat 已能缓存 `model/list / skills/list / plugin/list / app/list / modelProvider/capabilities/read / experimentalFeature/list / collaborationMode/list / permissionProfile/list / mcpServerStatus/list / account/read / account/rateLimits/read / config/read / configRequirements/read / externalAgentConfig/detect / thread/list / thread/loaded/list` 的能力摘要;同批已补 `turn/steer` 活跃 turn 干预和 `POST /api/v1/projects/[projectId]/thread-collaboration` 服务端线程协作排队入口。MCP、权限、账号、配置、外部 Agent 和线程 discovery 只保留安全摘要,不保存 resource URI、权限文件规则、工具参数、邮箱、完整 config、本地路径、迁移描述、turn 内容、用户正文或 token。 - 当前 Codex App Server 已完成十批接入boss-agent 默认开启 `local-agent/codex-app-server-runner.mjs` 作为 Codex 绑定入口,优先走 `codex app-server` stdio也可灰度连接 `ws://127.0.0.1:<port>``unix://PATH` 同机长驻 App Server长驻连接支持 `Authorization: Bearer <token>`,配置上优先使用 `codexAppServerAuthTokenFile`。turn 启动前失败才回退 CLIturn 启动后不重复执行;桌面远程控制默认先走 `codex-computer-use`,失败后回退 `cua-driver-computer-use`。2026-05-31 已按本机 `codex-cli 0.135.0-alpha.1` 生成协议快照 `docs/protocol-snapshots/codex-app-server/0.135.0-alpha.1/`,并把 `turn/plan/updated``turn/diff/updated``item/started|completed``thread/started``item/*/requestApproval``item/autoApprovalReview/*``guardianWarning``serverRequest/resolved``item/fileChange/patchUpdated``thread/status/changed``thread/realtime/*``model/rerouted``thread/tokenUsage/updated``mcpServer/startupStatus/updated``remoteControl/status/changed``windowsSandbox/setupCompleted``thread/goal/*``thread/settings/updated``thread/compacted``account/updated``account/rateLimits/updated``model/verification``warning``configWarning``deprecationNotice``ThreadItem.collabToolCall``ThreadItem.contextCompaction``mcpToolCall``dynamicToolCall``webSearch``imageView``imageGeneration``hook/started|completed``enteredReviewMode``exitedReviewMode``commandExecution``ThreadItem.plan``ThreadItem.reasoning.summary` 归一到 Boss `execution_progress` 卡片realtime 只保留状态、文本摘要和计数运行状态只保留模型切换、上下文用量、MCP 状态、远控连接摘要和 Windows 沙箱准备状态,线程配置只保留目标、模型、审批、沙箱、协作模式和压缩状态,线程协作只保留工具名、状态、目标类型和智能体状态,工具活动只保留类型、名称、状态和安全摘要,图像生成只保留状态与安全文件名,钩子生命周期只保留事件名、处理器类型、状态、来源、执行模式和耗时,思考摘要只保留官方 summary 文本和状态,账号状态只保留认证方式、套餐、额度窗口、积分余额和模型校验摘要,不保存 SDP、音频原始数据、raw item、remote installationId、cwd、turnId、配置文件路径、collab 源/目标线程 ID、collab prompt、tool arguments/result/contentItems、web URL token、命令正文/输出、raw reasoning content、reasoning item id、imageGeneration revisedPrompt/result、hook sourcePath/statusMessage/entries、Windows sandbox sourcePath/samplePaths/本地绝对路径或未清洗密钥。heartbeat 已能缓存 `model/list / skills/list / plugin/list / app/list / modelProvider/capabilities/read / experimentalFeature/list / collaborationMode/list / permissionProfile/list / mcpServerStatus/list / account/read / account/rateLimits/read / config/read / configRequirements/read / externalAgentConfig/detect / thread/list / thread/loaded/list / thread/turns/list` 的能力摘要;同批已补 `turn/steer` 活跃 turn 干预和 `POST /api/v1/projects/[projectId]/thread-collaboration` 服务端线程协作排队入口。MCP、权限、账号、配置、外部 Agent、线程和 turn discovery 只保留安全摘要,不保存 resource URI、权限文件规则、工具参数、邮箱、完整 config、本地路径、迁移描述、turn id、turn items、用户正文、模型输出或 token。
- 当前 boss-agent 已支持 Mac OTA`local-agent/boss-agent-ota-runner.mjs` 默认开启,每 5 分钟检查服务端最新包;状态页可手动检查或下载并安装,安装时保留原绑定配置,只更新版本号和本机 runtime 路径。最新验证版本为 `20260516221619`,已在 MacBook Air `macbook-air` 上确认 OTA 下载校验、暂存、覆盖安装后不会误切到默认 `config.cloud.json`。正式分发脚本已预留 Developer ID 公证路径:`BOSS_AGENT_NOTARIZE=1` 配合 notary profile 或 Apple ID 凭据。 - 当前 boss-agent 已支持 Mac OTA`local-agent/boss-agent-ota-runner.mjs` 默认开启,每 5 分钟检查服务端最新包;状态页可手动检查或下载并安装,安装时保留原绑定配置,只更新版本号和本机 runtime 路径。最新验证版本为 `20260516221619`,已在 MacBook Air `macbook-air` 上确认 OTA 下载校验、暂存、覆盖安装后不会误切到默认 `config.cloud.json`。正式分发脚本已预留 Developer ID 公证路径:`BOSS_AGENT_NOTARIZE=1` 配合 notary profile 或 Apple ID 凭据。
- 当前量产治理已补设备撤权和任务可靠性底座:`revoke_device` 会清空设备 token、标记离线并阻断 heartbeat / 任务认领 / Skill 同步 / 日志上报 / boss-agent OTA`MasterAgentTask` claim 会记录 attempt 和 lease运行中任务可按租约重试超过上限转 `timed_out`,用户或管理员可通过 cancel 接口转 `canceled` 且迟到 complete 不覆盖终态。 - 当前量产治理已补设备撤权和任务可靠性底座:`revoke_device` 会清空设备 token、标记离线并阻断 heartbeat / 任务认领 / Skill 同步 / 日志上报 / boss-agent OTA`MasterAgentTask` claim 会记录 attempt 和 lease运行中任务可按租约重试超过上限转 `timed_out`,用户或管理员可通过 cancel 接口转 `canceled` 且迟到 complete 不覆盖终态。
- 当前群聊 `dispatch_execution` 完成回写已补幂等,重复完成不会再向群聊重复追加结果 - 当前群聊 `dispatch_execution` 完成回写已补幂等,重复完成不会再向群聊重复追加结果

View File

@@ -121,6 +121,7 @@
- App Server heartbeat discovery 现在还会按 TTL 拉取 `experimentalFeature/list / collaborationMode/list / permissionProfile/list / mcpServerStatus/list`,写入 `capabilities.codexAppServer.metadata.experimentalFeatures / collaborationModes / permissionProfiles / mcpServers`。这些字段用于 APP/后台治理页展示 Codex 当前可用的实验特性、多 Agent/协作模式、权限 profile 和 MCP 服务健康MCP 请求固定使用 `detail=toolsAndAuthOnly`,服务端状态里不保存 resource URI、工具参数、permission profile 文件规则、本地路径或密钥。 - App Server heartbeat discovery 现在还会按 TTL 拉取 `experimentalFeature/list / collaborationMode/list / permissionProfile/list / mcpServerStatus/list`,写入 `capabilities.codexAppServer.metadata.experimentalFeatures / collaborationModes / permissionProfiles / mcpServers`。这些字段用于 APP/后台治理页展示 Codex 当前可用的实验特性、多 Agent/协作模式、权限 profile 和 MCP 服务健康MCP 请求固定使用 `detail=toolsAndAuthOnly`,服务端状态里不保存 resource URI、工具参数、permission profile 文件规则、本地路径或密钥。
- App Server heartbeat discovery 现在还会按 TTL 拉取 `account/read / account/rateLimits/read / config/read / configRequirements/read / externalAgentConfig/detect`,写入 `capabilities.codexAppServer.metadata.accountSummary / rateLimitSummary / appConfigSummary / configRequirements / externalAgentMigration`。这些字段用于 APP/后台展示账号、额度、App 配置、企业托管要求和外部 Agent 迁移候选摘要;当前只做观测,不通过 Boss 远程写 `config.toml` 或执行外部 Agent 导入,且不保存邮箱、完整 config、API key、本地路径或迁移描述。 - App Server heartbeat discovery 现在还会按 TTL 拉取 `account/read / account/rateLimits/read / config/read / configRequirements/read / externalAgentConfig/detect`,写入 `capabilities.codexAppServer.metadata.accountSummary / rateLimitSummary / appConfigSummary / configRequirements / externalAgentMigration`。这些字段用于 APP/后台展示账号、额度、App 配置、企业托管要求和外部 Agent 迁移候选摘要;当前只做观测,不通过 Boss 远程写 `config.toml` 或执行外部 Agent 导入,且不保存邮箱、完整 config、API key、本地路径或迁移描述。
- App Server heartbeat discovery 现在还会按 TTL 拉取 `thread/list / thread/loaded/list`,写入 `capabilities.codexAppServer.metadata.threadSummary`。该字段用于 APP/后台展示 Codex 当前可见线程数量、加载态、活跃态和非归档线程轻量目录;目录只保留 `id / name / sourceKind / status / updatedAt / loaded`,不保存 cwd、本地路径、turn 内容、用户正文或内部 prompt。 - App Server heartbeat discovery 现在还会按 TTL 拉取 `thread/list / thread/loaded/list`,写入 `capabilities.codexAppServer.metadata.threadSummary`。该字段用于 APP/后台展示 Codex 当前可见线程数量、加载态、活跃态和非归档线程轻量目录;目录只保留 `id / name / sourceKind / status / updatedAt / loaded`,不保存 cwd、本地路径、turn 内容、用户正文或内部 prompt。
- App Server heartbeat discovery 现在还会按 TTL 对非归档可见线程拉取 `thread/turns/list`,写入 `capabilities.codexAppServer.metadata.threadTurnSummary`。该字段用于 APP/后台展示 Codex 当前线程 turn 运行态;请求固定 `itemsView=notLoaded`,只保留 turn 计数、运行中 / 完成计数、最近状态和更新时间,不保存 turn id、items、用户正文、模型输出或内部 prompt。
- 当前 Codex App Server runner 已新增第一版 Boss Inter-Thread Broker任务携带 `intentCategory=thread_collaboration``sourceCodexThreadRef``targetCodexThreadRef` 时,会先 `thread/read` 源线程,再通过 `thread/inject_items` 向目标线程注入受控摘要,最后 `turn/start` 目标线程;服务端入口是 `POST /api/v1/projects/[projectId]/thread-collaboration`,负责权限、源/目标线程校验和任务排队。这不是假设官方线程 P2P而是 Boss 自己做线程协作编排。 - 当前 Codex App Server runner 已新增第一版 Boss Inter-Thread Broker任务携带 `intentCategory=thread_collaboration``sourceCodexThreadRef``targetCodexThreadRef` 时,会先 `thread/read` 源线程,再通过 `thread/inject_items` 向目标线程注入受控摘要,最后 `turn/start` 目标线程;服务端入口是 `POST /api/v1/projects/[projectId]/thread-collaboration`,负责权限、源/目标线程校验和任务排队。这不是假设官方线程 P2P而是 Boss 自己做线程协作编排。
- 当前 boss-agent Mac OTA 已接入:`local-agent/boss-agent-ota-runner.mjs` 会用设备 token 调 Boss 服务端 `/api/v1/boss-agent/ota` 检查最新 Mac 运行包,`/api/v1/boss-agent/ota/apply` 会下载 `boss-agent-mac-latest.zip`、校验 sha256、暂存安装 wrapper并拉起本机安装器安装脚本会保留绑定配置并只更新版本号与本机 runtime 路径。安装器会优先沿用当前 LaunchAgent active config并保留所有 `config*.json`,避免多电脑场景中误绑定到默认设备配置。当前最新验证包为 `20260516221619`;构建脚本支持 `BOSS_AGENT_NOTARIZE=1` 的 Developer ID 公证路径。 - 当前 boss-agent Mac OTA 已接入:`local-agent/boss-agent-ota-runner.mjs` 会用设备 token 调 Boss 服务端 `/api/v1/boss-agent/ota` 检查最新 Mac 运行包,`/api/v1/boss-agent/ota/apply` 会下载 `boss-agent-mac-latest.zip`、校验 sha256、暂存安装 wrapper并拉起本机安装器安装脚本会保留绑定配置并只更新版本号与本机 runtime 路径。安装器会优先沿用当前 LaunchAgent active config并保留所有 `config*.json`,避免多电脑场景中误绑定到默认设备配置。当前最新验证包为 `20260516221619`;构建脚本支持 `BOSS_AGENT_NOTARIZE=1` 的 Developer ID 公证路径。
- 当前 `local-agent` 还新增了两条统一电脑控制 runtime - 当前 `local-agent` 还新增了两条统一电脑控制 runtime

View File

@@ -20,9 +20,9 @@ Boss 不能直接把 App Server 原始 Thread / Turn / Item 字段写进业务
2026-05-31 已继续把 `turn/plan/updated``turn/diff/updated``item/started|completed``thread/started` 这类协议事件归一化为 Boss `execution_progress` 的步骤、分支变更、产物和后台智能体。同日第二批补齐 `item/*/requestApproval``item/autoApprovalReview/*``guardianWarning``serverRequest/resolved``item/fileChange/patchUpdated` 的安全摘要映射APP 只展示审批状态、风险提醒和文件路径不展示完整命令、diff、系统提示词或密钥。第三批已把 `thread/status/changed``thread/realtime/*` 归一成 `executionProgress.threadStatus / realtime`APP 只展示活跃/等待审批/等待用户输入、realtime 文本摘要、音频片段计数和关闭/错误原因;第四批已把 `model/rerouted``thread/tokenUsage/updated``mcpServer/startupStatus/updated``remoteControl/status/changed` 归一成 `executionProgress.modelRoute / tokenUsage / mcpServers / remoteControl`,用于 APP “运行状态”区块。 2026-05-31 已继续把 `turn/plan/updated``turn/diff/updated``item/started|completed``thread/started` 这类协议事件归一化为 Boss `execution_progress` 的步骤、分支变更、产物和后台智能体。同日第二批补齐 `item/*/requestApproval``item/autoApprovalReview/*``guardianWarning``serverRequest/resolved``item/fileChange/patchUpdated` 的安全摘要映射APP 只展示审批状态、风险提醒和文件路径不展示完整命令、diff、系统提示词或密钥。第三批已把 `thread/status/changed``thread/realtime/*` 归一成 `executionProgress.threadStatus / realtime`APP 只展示活跃/等待审批/等待用户输入、realtime 文本摘要、音频片段计数和关闭/错误原因;第四批已把 `model/rerouted``thread/tokenUsage/updated``mcpServer/startupStatus/updated``remoteControl/status/changed` 归一成 `executionProgress.modelRoute / tokenUsage / mcpServers / remoteControl`,用于 APP “运行状态”区块。
2026-06-01 第五批已把 `thread/goal/updated|cleared``thread/settings/updated``thread/compacted` 归一成 `executionProgress.threadGoal / threadSettings / compaction`,用于 APP “线程配置”区块;第六批已把 `account/updated``account/rateLimits/updated``model/verification``warning``configWarning``deprecationNotice` 归一成 `executionProgress.accountStatus / modelVerification / warnings`;第七批已把官方 `ThreadItem.collabToolCall` 归一成 `executionProgress.threadCollaboration`,并按官方建议把新版 `ThreadItem.contextCompaction` 映射回 `executionProgress.compaction`;第八批已把 `mcpToolCall``dynamicToolCall``webSearch``imageView``enteredReviewMode``exitedReviewMode``commandExecution` 归一成 `executionProgress.toolActivities`;第九批已把官方 `ThreadItem.plan` 的最终 `item/completed` 文本映射为 `executionProgress.steps`,并把 `ThreadItem.reasoning.summary` 映射为 `executionProgress.reasoningSummary`;第十批已把 `ThreadItem.imageGeneration` 安全映射为 `executionProgress.toolActivities` 的图像生成活动和 `executionProgress.artifacts` 的图片产物;第十一批已把 `hook/started|completed` 安全映射为 `executionProgress.toolActivities` 的钩子活动,供 APP 以“钩子”轻卡展示企业治理和插件生命周期状态;第十二批已把 `windowsSandbox/setupCompleted` 安全映射为 `executionProgress.windowsSandbox`,供 APP 在“运行状态”里展示 Windows 沙箱准备状态、setup mode 和脱敏错误摘要;第十三批已把 heartbeat discovery 扩展到 `experimentalFeature/list``collaborationMode/list``permissionProfile/list``mcpServerStatus/list`供设备详情、APP 和 PC 后台看到实验特性、协作模式、权限 Profile 与 MCP 服务摘要;第十四批已把 `account/read``account/rateLimits/read``config/read``configRequirements/read``externalAgentConfig/detect` 纳入 heartbeat discovery用于展示账号、套餐、额度、App 配置、托管要求和外部 Agent 迁移候选摘要;第十五批已把 `thread/list``thread/loaded/list` 纳入 heartbeat discovery用于展示线程总数、已加载线程、活跃线程、归档线程和非归档可见线程轻量目录。 2026-06-01 第五批已把 `thread/goal/updated|cleared``thread/settings/updated``thread/compacted` 归一成 `executionProgress.threadGoal / threadSettings / compaction`,用于 APP “线程配置”区块;第六批已把 `account/updated``account/rateLimits/updated``model/verification``warning``configWarning``deprecationNotice` 归一成 `executionProgress.accountStatus / modelVerification / warnings`;第七批已把官方 `ThreadItem.collabToolCall` 归一成 `executionProgress.threadCollaboration`,并按官方建议把新版 `ThreadItem.contextCompaction` 映射回 `executionProgress.compaction`;第八批已把 `mcpToolCall``dynamicToolCall``webSearch``imageView``enteredReviewMode``exitedReviewMode``commandExecution` 归一成 `executionProgress.toolActivities`;第九批已把官方 `ThreadItem.plan` 的最终 `item/completed` 文本映射为 `executionProgress.steps`,并把 `ThreadItem.reasoning.summary` 映射为 `executionProgress.reasoningSummary`;第十批已把 `ThreadItem.imageGeneration` 安全映射为 `executionProgress.toolActivities` 的图像生成活动和 `executionProgress.artifacts` 的图片产物;第十一批已把 `hook/started|completed` 安全映射为 `executionProgress.toolActivities` 的钩子活动,供 APP 以“钩子”轻卡展示企业治理和插件生命周期状态;第十二批已把 `windowsSandbox/setupCompleted` 安全映射为 `executionProgress.windowsSandbox`,供 APP 在“运行状态”里展示 Windows 沙箱准备状态、setup mode 和脱敏错误摘要;第十三批已把 heartbeat discovery 扩展到 `experimentalFeature/list``collaborationMode/list``permissionProfile/list``mcpServerStatus/list`供设备详情、APP 和 PC 后台看到实验特性、协作模式、权限 Profile 与 MCP 服务摘要;第十四批已把 `account/read``account/rateLimits/read``config/read``configRequirements/read``externalAgentConfig/detect` 纳入 heartbeat discovery用于展示账号、套餐、额度、App 配置、托管要求和外部 Agent 迁移候选摘要;第十五批已把 `thread/list``thread/loaded/list` 纳入 heartbeat discovery用于展示线程总数、已加载线程、活跃线程、归档线程和非归档可见线程轻量目录;第十六批已把 `thread/turns/list` 纳入 heartbeat discovery用于展示总轮次、运行中轮次、完成轮次和每个非归档线程的最近 turn 状态摘要
`thread/realtime/sdp`、音频 base64、原始 realtime item、remote installationId、thread settings 的 `cwd`、compaction `turnId`、collaboration settings 内部 prompt、collabToolCall 源/目标线程 ID、tool arguments/result/contentItems、web URL token、命令正文/输出、raw reasoning `content`、reasoning item id、imageGeneration 原始 result/revisedPrompt、hook id/sourcePath/statusMessage/entries、Windows sandbox sourcePath/samplePaths、本地绝对路径、permission profile 文件规则、MCP resource URI、账号邮箱、API key、完整 config、外部 Agent 迁移描述、turn 内容、用户正文和未清洗的 MCP 错误不入账。 `thread/realtime/sdp`、音频 base64、原始 realtime item、remote installationId、thread settings 的 `cwd`、compaction `turnId`、collaboration settings 内部 prompt、collabToolCall 源/目标线程 ID、tool arguments/result/contentItems、web URL token、命令正文/输出、raw reasoning `content`、reasoning item id、imageGeneration 原始 result/revisedPrompt、hook id/sourcePath/statusMessage/entries、Windows sandbox sourcePath/samplePaths、本地绝对路径、permission profile 文件规则、MCP resource URI、账号邮箱、API key、完整 config、外部 Agent 迁移描述、turn id、turn items、turn 内容、用户正文、模型输出和未清洗的 MCP 错误不入账。
官方文档入口:`https://developers.openai.com/codex/app-server` 官方文档入口:`https://developers.openai.com/codex/app-server`
@@ -44,7 +44,7 @@ Boss 不能直接把 App Server 原始 Thread / Turn / Item 字段写进业务
- 本机协议快照已生成到 `docs/protocol-snapshots/codex-app-server/0.135.0-alpha.1/`,共识别 137 个协议方法;确认支持 `thread/inject_items``thread/rollback``thread/goal/*``turn/steer``command/exec``thread/realtime/*``account/*``model/verification``configWarning``deprecationNotice``model/list` - 本机协议快照已生成到 `docs/protocol-snapshots/codex-app-server/0.135.0-alpha.1/`,共识别 137 个协议方法;确认支持 `thread/inject_items``thread/rollback``thread/goal/*``turn/steer``command/exec``thread/realtime/*``account/*``model/verification``configWarning``deprecationNotice``model/list`
- Boss 当前默认仍以 `stdio` 作为本机 agent 接入方式;`ws://127.0.0.1:<port>``unix://PATH` 本地长驻 transport 已可灰度接入WebSocket/Unix WebSocket handshake 支持 `Authorization: Bearer <token>`;非 loopback signed bearer/JWT、自动重连和健康探测仍保留为后续增强不直接替换当前稳定链路 - Boss 当前默认仍以 `stdio` 作为本机 agent 接入方式;`ws://127.0.0.1:<port>``unix://PATH` 本地长驻 transport 已可灰度接入WebSocket/Unix WebSocket handshake 支持 `Authorization: Bearer <token>`;非 loopback signed bearer/JWT、自动重连和健康探测仍保留为后续增强不直接替换当前稳定链路
- 官方文档提示 WebSocket ingress 满载时会返回 JSON-RPC `-32001 / Server overloaded; retry later.`Boss runner 已对该错误做最多 3 次指数退避重试,避免长驻连接瞬时拥塞直接把用户任务打失败 - 官方文档提示 WebSocket ingress 满载时会返回 JSON-RPC `-32001 / Server overloaded; retry later.`Boss runner 已对该错误做最多 3 次指数退避重试,避免长驻连接瞬时拥塞直接把用户任务打失败
- Boss heartbeat 已新增 App Server 能力发现缓存:按 `codexAppServerDiscoveryTtlMs` 拉取 `model/list``modelProvider/capabilities/read``skills/list``plugin/list``app/list``experimentalFeature/list``collaborationMode/list``permissionProfile/list``mcpServerStatus/list``account/read``account/rateLimits/read``config/read``configRequirements/read``externalAgentConfig/detect``thread/list``thread/loaded/list`,归一成设备 `capabilities.codexAppServer.metadata`;发现失败只记录 warn不阻塞心跳。MCP discovery 使用 `detail=toolsAndAuthOnly`,账号、配置和线程 discovery 只保留安全摘要不保存邮箱、resource URI、工具参数、完整 config、本地路径、迁移描述、turn 内容或用户正文 - Boss heartbeat 已新增 App Server 能力发现缓存:按 `codexAppServerDiscoveryTtlMs` 拉取 `model/list``modelProvider/capabilities/read``skills/list``plugin/list``app/list``experimentalFeature/list``collaborationMode/list``permissionProfile/list``mcpServerStatus/list``account/read``account/rateLimits/read``config/read``configRequirements/read``externalAgentConfig/detect``thread/list``thread/loaded/list``thread/turns/list`,归一成设备 `capabilities.codexAppServer.metadata`;发现失败只记录 warn不阻塞心跳。MCP discovery 使用 `detail=toolsAndAuthOnly`turn discovery 固定 `itemsView=notLoaded`账号、配置和线程 discovery 只保留安全摘要不保存邮箱、resource URI、工具参数、完整 config、本地路径、迁移描述、turn id、turn items、用户正文或模型输出
- Boss 第一批只用 App Server 做任务级 provider不直接复用 ChatGPT Mobile 到 Codex App 的官方 relay官方移动控制链路仍属于 ChatGPT App 与 Codex App 同账号/工作区之间的产品能力,不是第三方 Boss 可以稳定依赖的私有通道 - Boss 第一批只用 App Server 做任务级 provider不直接复用 ChatGPT Mobile 到 Codex App 的官方 relay官方移动控制链路仍属于 ChatGPT App 与 Codex App 同账号/工作区之间的产品能力,不是第三方 Boss 可以稳定依赖的私有通道
下一轮再核对版本时,不要只看 npm 包版本号;必须同时读取 App Server schema / TypeScript 定义,并把 protocol snapshot 保存到 `docs/protocol-snapshots/codex-app-server/<version>/` 下一轮再核对版本时,不要只看 npm 包版本号;必须同时读取 App Server schema / TypeScript 定义,并把 protocol snapshot 保存到 `docs/protocol-snapshots/codex-app-server/<version>/`

View File

@@ -39,6 +39,7 @@
- 当前 App Server 能力发现已新增治理摘要local-agent 会在 heartbeat discovery 中拉取 `experimentalFeature/list / collaborationMode/list / permissionProfile/list / mcpServerStatus/list`,并把实验特性、协作模式、权限 Profile 与 MCP 服务状态写入设备 `codexAppServer.metadata`;设备详情页会显示“治理”摘要。该链路只保留安全摘要,不保存 MCP resource URI、permission profile 文件规则、本地路径、token 或工具参数。 - 当前 App Server 能力发现已新增治理摘要local-agent 会在 heartbeat discovery 中拉取 `experimentalFeature/list / collaborationMode/list / permissionProfile/list / mcpServerStatus/list`,并把实验特性、协作模式、权限 Profile 与 MCP 服务状态写入设备 `codexAppServer.metadata`;设备详情页会显示“治理”摘要。该链路只保留安全摘要,不保存 MCP resource URI、permission profile 文件规则、本地路径、token 或工具参数。
- 当前 App Server 能力发现已新增账号与配置摘要local-agent 会在 heartbeat discovery 中拉取 `account/read / account/rateLimits/read / config/read / configRequirements/read / externalAgentConfig/detect`并把账号登录方式、套餐、额度使用率、App 配置计数、托管要求数量和外部 Agent 迁移候选数量写入设备 `codexAppServer.metadata`;设备详情页会显示“账号 / 配置”摘要。该链路只读不写,不保存账号邮箱、完整 config、API key、本地路径或迁移描述。 - 当前 App Server 能力发现已新增账号与配置摘要local-agent 会在 heartbeat discovery 中拉取 `account/read / account/rateLimits/read / config/read / configRequirements/read / externalAgentConfig/detect`并把账号登录方式、套餐、额度使用率、App 配置计数、托管要求数量和外部 Agent 迁移候选数量写入设备 `codexAppServer.metadata`;设备详情页会显示“账号 / 配置”摘要。该链路只读不写,不保存账号邮箱、完整 config、API key、本地路径或迁移描述。
- 当前 App Server 能力发现已新增线程可见性摘要local-agent 会在 heartbeat discovery 中拉取 `thread/list / thread/loaded/list`,并把线程总数、已加载线程数、活跃线程数、归档线程数、最新更新时间和非归档线程轻量目录写入设备 `codexAppServer.metadata.threadSummary`;设备详情页会显示“线程”摘要。该链路不保存 cwd、本地路径、turn 内容、用户正文或内部 prompt。 - 当前 App Server 能力发现已新增线程可见性摘要local-agent 会在 heartbeat discovery 中拉取 `thread/list / thread/loaded/list`,并把线程总数、已加载线程数、活跃线程数、归档线程数、最新更新时间和非归档线程轻量目录写入设备 `codexAppServer.metadata.threadSummary`;设备详情页会显示“线程”摘要。该链路不保存 cwd、本地路径、turn 内容、用户正文或内部 prompt。
- 当前 App Server 能力发现已新增 turn 运行态摘要local-agent 会在 heartbeat discovery 中对非归档可见线程拉取 `thread/turns/list`,请求固定 `itemsView=notLoaded`,并把总轮次、运行中轮次、完成轮次、最新 turn 更新时间和每个线程的最近 turn 状态写入设备 `codexAppServer.metadata.threadTurnSummary`;设备详情页会显示“轮次”摘要。该链路不保存 turn id、turn items、用户正文、模型输出或内部 prompt。
- 当前量产 B+ 架构开发文档已新增:`docs/architecture/enterprise_ai_ops_architecture_cn.md`。该文档把 PPT 中的主 Agent / 业务 Agent / 老板端 / 经理端 / 员工端 / 治理层 / 系统层 / 设备层 / 执行层 / 接入层整理成后续产品架构约束并明确数据库备份、业务回退、Codex 协议扩展和 Skill 治理方向;它是规划文档,不代表当前全部已落地 - 当前量产 B+ 架构开发文档已新增:`docs/architecture/enterprise_ai_ops_architecture_cn.md`。该文档把 PPT 中的主 Agent / 业务 Agent / 老板端 / 经理端 / 员工端 / 治理层 / 系统层 / 设备层 / 执行层 / 接入层整理成后续产品架构约束并明确数据库备份、业务回退、Codex 协议扩展和 Skill 治理方向;它是规划文档,不代表当前全部已落地
- 当前 `claw-code` 已以最小 `ClawBackendAdapter` 形式接入执行底座,但默认关闭;只有显式配置 `BOSS_CLAW_*` 且可用性探测通过时,`master-agent` 当前对话中才会出现并允许选择 `claw-runtime` - 当前 `claw-code` 已以最小 `ClawBackendAdapter` 形式接入执行底座,但默认关闭;只有显式配置 `BOSS_CLAW_*` 且可用性探测通过时,`master-agent` 当前对话中才会出现并允许选择 `claw-runtime`
- 当前已新增最小 `Telegram Gateway`Boss 当前可直接暴露 Telegram webhook把 Telegram 私聊或受控群聊文本桥接进 `master-agent` 或按群 / Topic 路由到指定 Boss 项目,并在主 Agent 异步任务完成后自动回推 Telegram配置入口已接到 Web `/me/telegram` 和原生 Android `我的 > Telegram 接入` - 当前已新增最小 `Telegram Gateway`Boss 当前可直接暴露 Telegram webhook把 Telegram 私聊或受控群聊文本桥接进 `master-agent` 或按群 / Topic 路由到指定 Boss 项目,并在主 Agent 异步任务完成后自动回推 Telegram配置入口已接到 Web `/me/telegram` 和原生 Android `我的 > Telegram 接入`

View File

@@ -1410,6 +1410,58 @@ function normalizeDiscoveryThreadSummary(threadListResult, loadedListResult, lim
}; };
} }
function extractDiscoveryTurnStatus(turn) {
const status = turn?.status && typeof turn.status === "object" ? turn.status : turn?.status;
return safeProgressText(
typeof status === "string"
? status
: status?.type ?? status?.state ?? turn?.state ?? "unknown",
40,
);
}
function normalizeDiscoveryThreadTurnSummary(threadTurnResults, limit) {
const threadSummaries = threadTurnResults
.map(({ threadId, result }) => {
const rawTurns = asArray(result?.data).length > 0 ? asArray(result?.data) : asArray(result?.turns);
const turns = rawTurns
.map((turn) => {
const status = extractDiscoveryTurnStatus(turn);
return {
status,
updatedAt: trimToDefined(turn?.updatedAt ?? turn?.lastUpdatedAt ?? turn?.createdAt) || "",
};
})
.filter((turn) => turn.status || turn.updatedAt);
const latestTurn = turns
.slice()
.sort((left, right) => String(right.updatedAt).localeCompare(String(left.updatedAt)))[0];
return {
threadId,
turnCount: turns.length,
runningTurnCount: turns.filter((turn) => /active|running|streaming|in[_-]?progress/i.test(turn.status)).length,
completedTurnCount: turns.filter((turn) => /completed|complete|success|succeeded/i.test(turn.status)).length,
latestTurnStatus: latestTurn?.status || "unknown",
latestTurnUpdatedAt: latestTurn?.updatedAt || "",
};
})
.sort((left, right) => String(right.latestTurnUpdatedAt).localeCompare(String(left.latestTurnUpdatedAt)))
.slice(0, limit);
const latestUpdatedAt = threadSummaries
.map((thread) => thread.latestTurnUpdatedAt)
.filter(Boolean)
.sort()
.at(-1) || "";
return {
threadCount: threadSummaries.length,
totalTurnCount: threadSummaries.reduce((sum, thread) => sum + thread.turnCount, 0),
runningTurnCount: threadSummaries.reduce((sum, thread) => sum + thread.runningTurnCount, 0),
completedTurnCount: threadSummaries.reduce((sum, thread) => sum + thread.completedTurnCount, 0),
latestUpdatedAt,
threads: threadSummaries,
};
}
async function withCodexAppServerRpcSession(runnerConfig, callback) { async function withCodexAppServerRpcSession(runnerConfig, callback) {
const cwd = runnerConfig.cwd || process.cwd(); const cwd = runnerConfig.cwd || process.cwd();
let closed = false; let closed = false;
@@ -1559,6 +1611,22 @@ export async function discoverCodexAppServerCapabilities(runnerConfig) {
const defaultModelId = models.find((model) => model.isDefault)?.id || models[0]?.id || ""; const defaultModelId = models.find((model) => model.isDefault)?.id || models[0]?.id || "";
const fastModelId = pickFastModelId(models); const fastModelId = pickFastModelId(models);
const deepModelId = models.find((model) => model.id !== fastModelId)?.id || defaultModelId; const deepModelId = models.find((model) => model.id !== fastModelId)?.id || defaultModelId;
const threadSummary = normalizeDiscoveryThreadSummary(threadListResult, loadedThreadsResult, limit);
const turnProbeLimit = Math.min(limit, 10);
const threadTurnResults = await Promise.all(
asArray(threadSummary.visibleThreads)
.slice(0, turnProbeLimit)
.map(async (thread) => ({
threadId: thread.id,
result: await safeRequest(request, "thread/turns/list", {
threadId: thread.id,
limit: turnProbeLimit,
sortDirection: "desc",
itemsView: "notLoaded",
}),
})),
);
return { return {
version: trimToDefined(runnerConfig.version), version: trimToDefined(runnerConfig.version),
discoveredAt: new Date().toISOString(), discoveredAt: new Date().toISOString(),
@@ -1583,7 +1651,8 @@ export async function discoverCodexAppServerCapabilities(runnerConfig) {
appConfigSummary: normalizeDiscoveryAppConfigSummary(configResult), appConfigSummary: normalizeDiscoveryAppConfigSummary(configResult),
configRequirements: normalizeDiscoveryConfigRequirements(configRequirementsResult), configRequirements: normalizeDiscoveryConfigRequirements(configRequirementsResult),
externalAgentMigration: normalizeDiscoveryExternalAgentMigration(externalAgentConfigResult), externalAgentMigration: normalizeDiscoveryExternalAgentMigration(externalAgentConfigResult),
threadSummary: normalizeDiscoveryThreadSummary(threadListResult, loadedThreadsResult, limit), threadSummary,
threadTurnSummary: normalizeDiscoveryThreadTurnSummary(threadTurnResults, limit),
errors: [ errors: [
modelResult?.__bossError ? `model/list:${safeRuntimeDiagnosticText(modelResult.__bossError)}` : undefined, modelResult?.__bossError ? `model/list:${safeRuntimeDiagnosticText(modelResult.__bossError)}` : undefined,
providerCapabilities?.__bossError providerCapabilities?.__bossError
@@ -1621,6 +1690,9 @@ export async function discoverCodexAppServerCapabilities(runnerConfig) {
loadedThreadsResult?.__bossError loadedThreadsResult?.__bossError
? `thread/loaded/list:${safeRuntimeDiagnosticText(loadedThreadsResult.__bossError)}` ? `thread/loaded/list:${safeRuntimeDiagnosticText(loadedThreadsResult.__bossError)}`
: undefined, : undefined,
...threadTurnResults
.filter((entry) => entry.result?.__bossError)
.map((entry) => `thread/turns/list:${entry.threadId}:${safeRuntimeDiagnosticText(entry.result.__bossError)}`),
].filter(Boolean), ].filter(Boolean),
}; };
}); });

View File

@@ -120,6 +120,7 @@ export function buildDeviceWorkspaceDetailCards(workspace: DeviceWorkspaceView)
const codexConfigRequirements = objectFromMetadata(codexAppServerMetadata.configRequirements); const codexConfigRequirements = objectFromMetadata(codexAppServerMetadata.configRequirements);
const codexExternalAgentMigration = objectFromMetadata(codexAppServerMetadata.externalAgentMigration); const codexExternalAgentMigration = objectFromMetadata(codexAppServerMetadata.externalAgentMigration);
const codexThreadSummary = objectFromMetadata(codexAppServerMetadata.threadSummary); const codexThreadSummary = objectFromMetadata(codexAppServerMetadata.threadSummary);
const codexThreadTurnSummary = objectFromMetadata(codexAppServerMetadata.threadTurnSummary);
return { return {
capabilities: { capabilities: {
@@ -159,6 +160,11 @@ export function buildDeviceWorkspaceDetailCards(workspace: DeviceWorkspaceView)
)} 个 · 活跃 ${numberFromMetadata(codexThreadSummary.activeThreadCount)} 个 · 最新 ${minuteTimestampFromMetadata( )} 个 · 活跃 ${numberFromMetadata(codexThreadSummary.activeThreadCount)} 个 · 最新 ${minuteTimestampFromMetadata(
codexThreadSummary.latestUpdatedAt, codexThreadSummary.latestUpdatedAt,
)}`, )}`,
codexTurns: `轮次:${numberFromMetadata(codexThreadTurnSummary.totalTurnCount)} 个 · 运行中 ${numberFromMetadata(
codexThreadTurnSummary.runningTurnCount,
)} 个 · 完成 ${numberFromMetadata(codexThreadTurnSummary.completedTurnCount)} 个 · 最新 ${minuteTimestampFromMetadata(
codexThreadTurnSummary.latestUpdatedAt,
)}`,
preferredExecutionMode: `默认执行模式:${ preferredExecutionMode: `默认执行模式:${
selectedDevice?.preferredExecutionMode === "gui" selectedDevice?.preferredExecutionMode === "gui"
? "GUI" ? "GUI"
@@ -802,6 +808,9 @@ export function DeviceEditorCard({
<div className="rounded-2xl bg-[#F7F8FA] px-3 py-2"> <div className="rounded-2xl bg-[#F7F8FA] px-3 py-2">
{detailCards.capabilities.items.codexThreads} {detailCards.capabilities.items.codexThreads}
</div> </div>
<div className="rounded-2xl bg-[#F7F8FA] px-3 py-2">
{detailCards.capabilities.items.codexTurns}
</div>
<div className="rounded-2xl bg-[#F7F8FA] px-3 py-2"> <div className="rounded-2xl bg-[#F7F8FA] px-3 py-2">
{detailCards.capabilities.items.preferredExecutionMode} {detailCards.capabilities.items.preferredExecutionMode}
</div> </div>

View File

@@ -118,6 +118,23 @@ test("device detail exposes Codex App Server discovered model and extension summ
}, },
], ],
}, },
threadTurnSummary: {
threadCount: 2,
totalTurnCount: 3,
runningTurnCount: 1,
completedTurnCount: 2,
latestUpdatedAt: "2026-06-03T08:21:00.000Z",
threads: [
{
threadId: "thr-active",
turnCount: 2,
runningTurnCount: 1,
completedTurnCount: 1,
latestTurnStatus: "running",
latestTurnUpdatedAt: "2026-06-03T08:21:00.000Z",
},
],
},
}, },
}, },
}; };
@@ -133,6 +150,7 @@ test("device detail exposes Codex App Server discovered model and extension summ
assert.equal(cards.capabilities.items.codexAccount, "账号chatgpt · 套餐 pro · 额度 42%"); assert.equal(cards.capabilities.items.codexAccount, "账号chatgpt · 套餐 pro · 额度 42%");
assert.equal(cards.capabilities.items.codexConfig, "配置App 2 个 · 已启用 1 个 · 托管要求 2 个 · 外部迁移 3 项"); assert.equal(cards.capabilities.items.codexConfig, "配置App 2 个 · 已启用 1 个 · 托管要求 2 个 · 外部迁移 3 项");
assert.equal(cards.capabilities.items.codexThreads, "线程3 个 · 已加载 2 个 · 活跃 1 个 · 最新 2026-06-03 16:20"); assert.equal(cards.capabilities.items.codexThreads, "线程3 个 · 已加载 2 个 · 活跃 1 个 · 最新 2026-06-03 16:20");
assert.equal(cards.capabilities.items.codexTurns, "轮次3 个 · 运行中 1 个 · 完成 2 个 · 最新 2026-06-03 16:21");
}); });
test("device detail exposes folder and project conflict skeleton from workspace policy", async () => { test("device detail exposes folder and project conflict skeleton from workspace policy", async () => {

View File

@@ -75,6 +75,13 @@ test("device heartbeat preserves Codex App Server capability metadata", async ()
latestUpdatedAt: "2026-06-03T08:20:00.000Z", latestUpdatedAt: "2026-06-03T08:20:00.000Z",
visibleThreads: [{ id: "thr-active", name: "Boss App Server rollout", loaded: true }], visibleThreads: [{ id: "thr-active", name: "Boss App Server rollout", loaded: true }],
}, },
threadTurnSummary: {
threadCount: 2,
totalTurnCount: 3,
runningTurnCount: 1,
latestUpdatedAt: "2026-06-03T08:21:00.000Z",
threads: [{ threadId: "thr-active", turnCount: 2, runningTurnCount: 1 }],
},
}, },
}, },
}, },
@@ -129,4 +136,20 @@ test("device heartbeat preserves Codex App Server capability metadata", async ()
)?.visibleThreads?.[0]?.id, )?.visibleThreads?.[0]?.id,
"thr-active", "thr-active",
); );
assert.equal(
(
updatedDevice?.capabilities?.codexAppServer.metadata?.threadTurnSummary as
| { totalTurnCount?: number; threads?: Array<{ threadId?: string }> }
| undefined
)?.totalTurnCount,
3,
);
assert.equal(
(
updatedDevice?.capabilities?.codexAppServer.metadata?.threadTurnSummary as
| { threads?: Array<{ threadId?: string }> }
| undefined
)?.threads?.[0]?.threadId,
"thr-active",
);
}); });

View File

@@ -431,6 +431,60 @@ rl.on("line", (line) => {
return; return;
} }
if (message.method === "thread/turns/list") {
const threadId = message.params?.threadId;
if (threadId === "thr-active") {
send({
id: message.id,
result: {
data: [
{
id: "turn-active-2",
status: "running",
createdAt: "2026-06-03T08:18:00.000Z",
updatedAt: "2026-06-03T08:21:00.000Z",
userInput: "private active turn text should not leak",
items: [{ type: "message", content: "private item content should not leak" }],
},
{
id: "turn-active-1",
status: "completed",
createdAt: "2026-06-03T08:00:00.000Z",
updatedAt: "2026-06-03T08:10:00.000Z",
},
],
nextCursor: null,
backwardsCursor: null,
},
});
return;
}
if (threadId === "thr-idle") {
send({
id: message.id,
result: {
data: [
{
id: "turn-idle-1",
status: { type: "completed" },
createdAt: "2026-06-03T07:00:00.000Z",
updatedAt: "2026-06-03T07:30:00.000Z",
userInput: "private idle turn text should not leak",
},
],
nextCursor: null,
backwardsCursor: null,
},
});
return;
}
send({
id: message.id,
result: { data: [], nextCursor: null, backwardsCursor: null },
});
return;
}
if (message.method === "thread/resume") { if (message.method === "thread/resume") {
send({ send({
id: message.id, id: message.id,

View File

@@ -78,6 +78,19 @@ test("codex app-server discovery includes governance and MCP summaries without l
loaded: true, loaded: true,
updatedAt: "2026-06-03T08:20:00.000Z", updatedAt: "2026-06-03T08:20:00.000Z",
}); });
assert.equal(metadata.threadTurnSummary.threadCount, 2);
assert.equal(metadata.threadTurnSummary.totalTurnCount, 3);
assert.equal(metadata.threadTurnSummary.runningTurnCount, 1);
assert.equal(metadata.threadTurnSummary.completedTurnCount, 2);
assert.equal(metadata.threadTurnSummary.latestUpdatedAt, "2026-06-03T08:21:00.000Z");
assert.deepEqual(metadata.threadTurnSummary.threads[0], {
threadId: "thr-active",
turnCount: 2,
runningTurnCount: 1,
completedTurnCount: 1,
latestTurnStatus: "running",
latestTurnUpdatedAt: "2026-06-03T08:21:00.000Z",
});
const serialized = JSON.stringify(metadata); const serialized = JSON.stringify(metadata);
assert.equal(serialized.includes("sk-secret-should-not-leak"), false); assert.equal(serialized.includes("sk-secret-should-not-leak"), false);
@@ -90,6 +103,9 @@ test("codex app-server discovery includes governance and MCP summaries without l
assert.equal(serialized.includes("AGENTS.md"), false); assert.equal(serialized.includes("AGENTS.md"), false);
assert.equal(serialized.includes("secret user text should not leak"), false); assert.equal(serialized.includes("secret user text should not leak"), false);
assert.equal(serialized.includes("Old private thread"), false); assert.equal(serialized.includes("Old private thread"), false);
assert.equal(serialized.includes("private active turn text should not leak"), false);
assert.equal(serialized.includes("private item content should not leak"), false);
assert.equal(serialized.includes("private idle turn text should not leak"), false);
}); });
function encodeWsTextFrame(value) { function encodeWsTextFrame(value) {