feat: surface codex reasoning summaries

This commit is contained in:
AI Bot
2026-06-01 18:20:04 +08:00
parent 2ca2737520
commit 5d62560217
11 changed files with 338 additions and 7 deletions

View File

@@ -1639,6 +1639,20 @@ public final class BossUi {
}
}
JSONObject reasoningSummary = progress == null ? null : progress.optJSONObject("reasoningSummary");
if (reasoningSummary != null) {
String summary = reasoningSummary.optString("summary", "").trim();
if (!TextUtils.isEmpty(summary)) {
String status = reasoningSummary.optString("status", "").trim();
card.addView(divider(context));
card.addView(sectionTitle(context, "思考摘要"));
if (!TextUtils.isEmpty(status)) {
card.addView(detailRow(context, "", status, "", false));
}
card.addView(detailRow(context, "", summary, "", false, true));
}
}
JSONArray warnings = progress == null ? null : progress.optJSONArray("warnings");
if (warnings != null && warnings.length() > 0) {
card.addView(divider(context));

View File

@@ -1285,6 +1285,48 @@ public class ProjectDetailActivityUiTest {
assertFalse(viewTreeContainsText(messageView, "id_rsa"));
}
@Test
public void executionProgressMessageRendersCodexReasoningSummarySection() throws Exception {
Intent intent = new Intent()
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_ID, "reasoning-summary")
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_NAME, "Boss开发主线程");
TestProjectDetailActivity activity = Robolectric
.buildActivity(TestProjectDetailActivity.class, intent)
.setup()
.get();
JSONObject message = new JSONObject()
.put("id", "progress-reasoning-summary-1")
.put("sender", "master")
.put("senderLabel", "主 Agent")
.put("body", "执行进度")
.put("kind", "execution_progress")
.put("sentAt", "2026-06-01T12:10:00+08:00")
.put("executionProgress", new JSONObject()
.put("status", "running")
.put("steps", new JSONArray()
.put(new JSONObject().put("text", "同步 Codex 思考摘要").put("status", "running")))
.put("reasoningSummary", new JSONObject()
.put("status", "completed")
.put("summary", "确认只展示官方 summary不展示 raw content。")
.put("content", new JSONArray()
.put(new JSONObject().put("text", "raw hidden chain of thought token=sk-secret-should-not-render")))
.put("itemId", "reasoning-secret-should-not-render")));
View messageView = ReflectionHelpers.callInstanceMethod(
activity,
"buildMessageView",
ReflectionHelpers.ClassParameter.from(JSONObject.class, message)
);
assertTrue(viewTreeContainsText(messageView, "思考摘要"));
assertTrue(viewTreeContainsText(messageView, "completed"));
assertTrue(viewTreeContainsText(messageView, "确认只展示官方 summary不展示 raw content。"));
assertFalse(viewTreeContainsText(messageView, "raw hidden chain of thought"));
assertFalse(viewTreeContainsText(messageView, "sk-secret-should-not-render"));
assertFalse(viewTreeContainsText(messageView, "reasoning-secret-should-not-render"));
}
@Test
public void nativeRemoteExecutionProgressDoesNotRenderCodexSections() throws Exception {
Intent intent = new Intent()

View File

@@ -153,7 +153,7 @@
- Web 和原生 Android 当前都已经接上“新设备导入草稿 -> 勾选 -> 决议预览 -> 应用导入”的前台页面;已绑定生产设备继续保留 heartbeat 自动导入链路
- 原生首页的刷新失败策略当前已改成按当前 tab 独立判错,不会再因为 `设备 / 设置 / OTA` 的旁路请求失败把会话页刷新一并判成失败
- 当前量产方向已经明确为“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``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``enteredReviewMode``exitedReviewMode``commandExecution` 归一到 Boss `execution_progress` 卡片realtime 只保留状态、文本摘要和计数运行状态只保留模型切换、上下文用量、MCP 状态和远控连接摘要,线程配置只保留目标、模型、审批、沙箱、协作模式和压缩状态,线程协作只保留工具名、状态、目标类型和智能体状态,工具活动只保留类型、名称、状态和安全摘要,账号状态只保留认证方式、套餐、额度窗口、积分余额和模型校验摘要,不保存 SDP、音频原始数据、raw item、remote installationId、cwd、turnId、配置文件路径、collab 源/目标线程 ID、collab prompt、tool arguments/result/contentItems、web URL token、命令正文/输出或未清洗密钥。heartbeat 已能缓存 `model/list / skills/list / plugin/list / app/list / modelProvider/capabilities/read` 的能力摘要;同批已补 `turn/steer` 活跃 turn 干预和 `POST /api/v1/projects/[projectId]/thread-collaboration` 服务端线程协作排队入口。
- 当前 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``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``enteredReviewMode``exitedReviewMode``commandExecution``ThreadItem.plan``ThreadItem.reasoning.summary` 归一到 Boss `execution_progress` 卡片realtime 只保留状态、文本摘要和计数运行状态只保留模型切换、上下文用量、MCP 状态和远控连接摘要,线程配置只保留目标、模型、审批、沙箱、协作模式和压缩状态,线程协作只保留工具名、状态、目标类型和智能体状态,工具活动只保留类型、名称、状态和安全摘要,思考摘要只保留官方 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 或未清洗密钥。heartbeat 已能缓存 `model/list / skills/list / plugin/list / app/list / modelProvider/capabilities/read` 的能力摘要;同批已补 `turn/steer` 活跃 turn 干预和 `POST /api/v1/projects/[projectId]/thread-collaboration` 服务端线程协作排队入口。
- 当前 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 不覆盖终态。
- 当前群聊 `dispatch_execution` 完成回写已补幂等,重复完成不会再向群聊重复追加结果

View File

@@ -73,7 +73,7 @@
- 当前已支持聊天附件主链:输入框左侧 `+` 会打开底部抽屉,支持图片 / 视频 / 文件发送;图片 / 视频先确认,文件直接发送
- 当前附件消息支持下载、原生打开、手动分析和自动分析状态展示
- 当前线程聊天消息会按该线程绑定的 Codex 电脑显示来源头像:单线程会话使用项目绑定设备头像,多设备 / 群聊消息会优先根据发送人里的设备名匹配对应电脑头像;主 Agent 总入口自身仍保留主 Agent 对话样式
- 当前已支持 `execution_progress` 执行进度卡:普通线程对话、主 Agent 托管线程和群聊目标线程执行时,会在对应聊天窗口显示“进度 / 线程状态 / 实时状态 / 线程配置 / 线程协作 / 工具活动 / 账号状态 / 运行状态 / 安全提醒 / 审批状态 / 文件变更 / 分支详情 / 生成结果 / 后台智能体”结构化卡片;线程过程噪音仍走 `thread_process` 折叠
- 当前已支持 `execution_progress` 执行进度卡:普通线程对话、主 Agent 托管线程和群聊目标线程执行时,会在对应聊天窗口显示“进度 / 线程状态 / 实时状态 / 线程配置 / 线程协作 / 工具活动 / 思考摘要 / 账号状态 / 运行状态 / 安全提醒 / 审批状态 / 文件变更 / 分支详情 / 生成结果 / 后台智能体”结构化卡片;线程过程噪音仍走 `thread_process` 折叠
- `线程详情 / 运维调试` 仍保留对应原生活动页,但已退出主聊天面
- 当前已补上本地发送中气泡、发送按钮状态控制,以及“只有接近底部才自动滚到底”的消息流行为
- 当前根页导航:
@@ -117,7 +117,7 @@
- 当前 `RemoteRuntimeAdapter` 还负责拦截固定模式的线程内部环境提示;命中后会直接改写成失败,避免把只读/cwd 这类脏文本写进聊天记录
- 当前普通单线程 `conversation_reply` 在真正执行 `codex exec resume` 前,会先把 Boss 用户消息镜像进目标 Codex Desktop rollout定位优先走 `state_5.sqlite`,不可用时回退扫描 `~/.codex/sessions`,并按 `sourceMessageId` 去重
- 当前 Codex Desktop 同步新增常驻刷新桥:`scripts/codex-desktop-refresh-bridge-daemon.mjs` 通过 launchd 监听 `127.0.0.1:4318`,暴露 `POST /api/v1/codex-desktop/refresh``GET /api/v1/codex-desktop/events``GET /api/v1/codex-desktop/events/recent``GET /api/v1/codex-desktop/capabilities``local-agent` 会优先调用 refresh endpoint失败时回退到 `scripts/codex-desktop-refresh-hint.mjs` 命令式刷新。SSE 事件只包含线程引用、消息 ID、状态、deep link 等安全元数据,不包含用户正文或内部 prompt`scripts/codex-desktop-event-consumer.mjs` 可作为 Desktop 插件/IPC 接入前的订阅 smoke`scripts/codex-desktop-integration-probe.mjs` 负责只读探测 Codex.app 能力
- 当前新增 Codex App Server runner`local-agent/codex-app-server-runner.mjs`。boss-agent 默认配置 `codexAppServerEnabled=true`,会接管 `conversation_reply / dispatch_execution`;它默认通过 stdio 启动 `codex app-server`,也支持 `codexAppServerTransport=ws + codexAppServerUrl=ws://127.0.0.1:<port>``codexAppServerTransport=unix + codexAppServerUrl=unix:///absolute/path.sock` 连接同机长驻 App Serverbearer token 可通过 `codexAppServerAuthTokenFile` 读取并在握手时发送 `Authorization: Bearer <token>`。runner 执行 `initialize -> thread/resume|thread/start -> turn/start|turn/steer`,并把 `item/agentMessage/delta``item/completed` 归一成 Boss 任务回复;当 App Server 对单个 JSON-RPC 请求返回 `-32001 / retry later`runner 会做最多 3 次指数退避重试。turn 启动前失败可回退 CLIturn 启动后失败不回退避免重复执行。2026-05-31 起runner 会把 `turn/plan/updated``turn/diff/updated``item/started|completed``thread/started` 归一成 `executionProgress.steps / branch / artifacts / agents`,把 `item/*/requestApproval``item/autoApprovalReview/*``guardianWarning``serverRequest/resolved``item/fileChange/patchUpdated` 归一成 `executionProgress.approvals / warnings / fileChanges`,把 `thread/status/changed``thread/realtime/started|transcript|outputAudio|itemAdded|error|closed` 归一成 `executionProgress.threadStatus / realtime`,把 `model/rerouted``thread/tokenUsage/updated``mcpServer/startupStatus/updated``remoteControl/status/changed` 归一成 `executionProgress.modelRoute / tokenUsage / mcpServers / remoteControl`,并把 `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``enteredReviewMode``exitedReviewMode``commandExecution` 归一成线程配置、账号状态、模型校验、安全提醒、线程协作、上下文压缩工具活动摘要;服务端 complete 回写会与本地 Git/GitHub 进度合并,且不保存 SDP、音频 base64、raw realtime item、remote installationId、cwd、turnId、配置路径、collab 源/目标线程 ID、collab prompt、tool arguments/result/contentItems、web URL token、命令正文/输出或未清洗的 MCP 错误。heartbeat 同时支持按 TTL 拉取 `model/list / skills/list / plugin/list / app/list / modelProvider/capabilities/read`,并把摘要保存在 `capabilities.codexAppServer.metadata`
- 当前新增 Codex App Server runner`local-agent/codex-app-server-runner.mjs`。boss-agent 默认配置 `codexAppServerEnabled=true`,会接管 `conversation_reply / dispatch_execution`;它默认通过 stdio 启动 `codex app-server`,也支持 `codexAppServerTransport=ws + codexAppServerUrl=ws://127.0.0.1:<port>``codexAppServerTransport=unix + codexAppServerUrl=unix:///absolute/path.sock` 连接同机长驻 App Serverbearer token 可通过 `codexAppServerAuthTokenFile` 读取并在握手时发送 `Authorization: Bearer <token>`。runner 执行 `initialize -> thread/resume|thread/start -> turn/start|turn/steer`,并把 `item/agentMessage/delta``item/completed` 归一成 Boss 任务回复;当 App Server 对单个 JSON-RPC 请求返回 `-32001 / retry later`runner 会做最多 3 次指数退避重试。turn 启动前失败可回退 CLIturn 启动后失败不回退避免重复执行。2026-05-31 起runner 会把 `turn/plan/updated``turn/diff/updated``item/started|completed``thread/started` 归一成 `executionProgress.steps / branch / artifacts / agents`,把 `item/*/requestApproval``item/autoApprovalReview/*``guardianWarning``serverRequest/resolved``item/fileChange/patchUpdated` 归一成 `executionProgress.approvals / warnings / fileChanges`,把 `thread/status/changed``thread/realtime/started|transcript|outputAudio|itemAdded|error|closed` 归一成 `executionProgress.threadStatus / realtime`,把 `model/rerouted``thread/tokenUsage/updated``mcpServer/startupStatus/updated``remoteControl/status/changed` 归一成 `executionProgress.modelRoute / tokenUsage / mcpServers / remoteControl`,并把 `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``enteredReviewMode``exitedReviewMode``commandExecution``ThreadItem.plan``ThreadItem.reasoning.summary` 归一成线程配置、账号状态、模型校验、安全提醒、线程协作、上下文压缩工具活动、计划步骤和思考摘要;服务端 complete 回写会与本地 Git/GitHub 进度合并,且不保存 SDP、音频 base64、raw realtime item、remote installationId、cwd、turnId、配置路径、collab 源/目标线程 ID、collab prompt、tool arguments/result/contentItems、web URL token、命令正文/输出、raw reasoning content、reasoning item id 或未清洗的 MCP 错误。heartbeat 同时支持按 TTL 拉取 `model/list / skills/list / plugin/list / app/list / modelProvider/capabilities/read`,并把摘要保存在 `capabilities.codexAppServer.metadata`
- 当前 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 公证路径。
- 当前 `local-agent` 还新增了两条统一电脑控制 runtime

View File

@@ -16,7 +16,13 @@ Codex App Server 是更适合 Boss 长期接入的协议层,因为它面向富
- model/list、skills/list、plugin/list、app/list
- command execution、file change、tool input、MCP tool-call approvals
Boss 不能直接把 App Server 原始 Thread / Turn / Item 字段写进业务层。当前第一批已经新增 `local-agent/codex-app-server-runner.mjs`,把 App Server 的 `thread/resume | thread/start -> turn/start -> item/agentMessage/delta -> turn/completed` 映射成 Boss 的普通任务完成回写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``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、命令正文/输出和未清洗的 MCP 错误不入账
Boss 不能直接把 App Server 原始 Thread / Turn / Item 字段写进业务层。当前第一批已经新增 `local-agent/codex-app-server-runner.mjs`,把 App Server 的 `thread/resume | thread/start -> turn/start -> item/agentMessage/delta -> turn/completed` 映射成 Boss 的普通任务完成回写。
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`,供 APP 以“思考摘要”轻卡展示。
`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 和未清洗的 MCP 错误不入账。
官方文档入口:`https://developers.openai.com/codex/app-server`
@@ -78,6 +84,7 @@ APP 展示结构对齐截图:
- `线程配置`:展示 thread goal、模型 / provider、审批 / 沙箱、协作模式和上下文压缩状态
- `线程协作`:展示 `collabToolCall` 的工具名、执行状态、目标类型和智能体状态,不展示源/目标线程 ID 或 prompt
- `工具活动`:展示 MCP / dynamic tool / web search / image view / Review / command 的类型、名称、状态和安全摘要不展示参数、结果、URL token、命令正文或命令输出
- `思考摘要`:展示 Codex 官方 reasoning `summary` 和状态,不展示 raw reasoning `content`、item id 或密钥
- `运行状态`展示模型重路由、上下文用量、MCP 启动状态和远控连接状态
- `分支详情`变更行、Git 操作、GitHub CLI 可用状态
- `生成结果`从执行结果里提取文件、图片、APK、文档等产物名
@@ -86,7 +93,7 @@ APP 展示结构对齐截图:
UI 参考:
- image2 生成稿:`design/image2/boss-app-codex-app-server-progress-card-20260531.png`
- 当前生成稿保持微信效率型:顶部保留项目目标 / 版本记录固定入口,聊天区只展示最终用户消息和结构化进度卡,进度卡分为 `进度 / 线程状态 / 实时状态 / 线程配置 / 线程协作 / 工具活动 / 账号状态 / 运行状态 / 安全提醒 / 审批状态 / 文件变更 / 分支详情 / 生成结果 / 后台智能体`
- 当前生成稿保持微信效率型:顶部保留项目目标 / 版本记录固定入口,聊天区只展示最终用户消息和结构化进度卡,进度卡分为 `进度 / 线程状态 / 实时状态 / 线程配置 / 线程协作 / 工具活动 / 思考摘要 / 账号状态 / 运行状态 / 安全提醒 / 审批状态 / 文件变更 / 分支详情 / 生成结果 / 后台智能体`
- 后续 Android / Web 继续按该稿收口,不新增无关功能,不把协议字段、系统提示词或执行 envelope 暴露给用户
## 3. 安全边界
@@ -132,6 +139,7 @@ UI 参考:
- `local-agent/codex-app-server-runner.mjs` 已把 App Server `account/updated``account/rateLimits/updated``model/verification``warning``configWarning``deprecationNotice` 归一成 `executionProgress.accountStatus / modelVerification / warnings`;服务端进度路由和 Android 原生进度卡已支持展示测试覆盖配置路径、turnId 和密钥不外泄
- `local-agent/codex-app-server-runner.mjs` 已把 App Server `ThreadItem.collabToolCall``ThreadItem.contextCompaction` 归一成 `executionProgress.threadCollaboration / compaction`;服务端进度路由和 Android 原生进度卡已支持展示,测试覆盖源/目标线程 ID、内部 prompt、turnId 和密钥不外泄
- `local-agent/codex-app-server-runner.mjs` 已把 App Server `mcpToolCall``dynamicToolCall``webSearch``imageView``enteredReviewMode``exitedReviewMode``commandExecution` 归一成 `executionProgress.toolActivities`;服务端进度路由和 Android 原生进度卡已支持展示,测试覆盖 tool arguments/result、URL token、命令正文/输出、本地路径和密钥不外泄
- `local-agent/codex-app-server-runner.mjs` 已把 App Server `ThreadItem.plan``ThreadItem.reasoning.summary` 归一成 `executionProgress.steps / reasoningSummary`;服务端进度路由和 Android 原生进度卡已支持展示,测试覆盖 raw reasoning content、reasoning item id 和密钥不外泄
- 新增实时进度入口 `POST /api/v1/master-agent/tasks/[taskId]/progress`,设备端可在任务执行中持续刷新同一张 `execution_progress` 卡;`local-agent` 的 App Server runner 已在收到协议进度事件时调用该接口complete 仍携带最终进度作为兜底
- 新增服务端线程协作入口 `POST /api/v1/projects/[projectId]/thread-collaboration`,由 Boss 校验源/目标项目权限并创建 `intentCategory=thread_collaboration``conversation_reply` 任务;设备端继续通过 App Server runner 执行 `thread/read -> thread/inject_items -> turn/start`,避免把“线程互通”误做成无监管 P2P
- 新增活跃 turn 干预:任务携带 `targetCodexTurnId` / `targetTurnId`App Server runner 会调用 `turn/steer`,并把 `turnControl=steer``turnId` 写回执行结果;没有活跃 turn id 时仍使用 `turn/start`

View File

@@ -1,6 +1,6 @@
# Boss 当前运行与部署状态
更新时间:`2026-05-31`
更新时间:`2026-06-01`
## 1. 本地状态
@@ -249,7 +249,7 @@ cd /Users/kris/code/boss
- 当前 `local-agent` 已新增 `Codex App Server` providerboss-agent 默认配置 `codexAppServerEnabled=true``conversation_reply / dispatch_execution` 会先通过 `codex app-server` 的 stdio JSON-RPC 恢复或创建线程,也可配置 `codexAppServerTransport=ws + codexAppServerUrl=ws://127.0.0.1:<port>``codexAppServerTransport=unix + codexAppServerUrl=unix:///absolute/path.sock` 连接同机长驻 App Server长驻连接可通过 `codexAppServerAuthTokenFile``BOSS_CODEX_APP_SERVER_AUTH_TOKEN_FILE` 提供 bearer token。随后 runner 下发 `turn/start` 并收集流式 agent 回复;如果单个 JSON-RPC 请求返回 `-32001 / retry later`runner 会先做指数退避重试;如果任务携带 `targetCodexTurnId`,会改用 `turn/steer` 干预活跃 turn如果 App Server 在 turn 启动前失败,默认允许回退到 `codex exec resume`,如果 turn 已经启动则不再回退,避免同一轮用户消息被重复执行。桌面控制另有 `codexComputerUseEnabled=true`,默认先走 Codex Computer Use再回退 CUA Driver。
- 当前已新增 Boss 自有 Inter-Thread Broker 第一版:服务端入口 `POST /api/v1/projects/[projectId]/thread-collaboration` 会创建带源/目标 Codex 线程引用的协作任务App Server runner 执行 `thread/read(source) -> thread/inject_items(target) -> turn/start(target)`,用于让一个线程的结论受控进入另一个线程,不依赖官方任意线程 P2P 互聊能力
- 当前 `local-agent``dispatch_execution` 任务会按 `orchestrationBackendId` 分流:默认走 `codex exec resume`;当任务显式选择 `omx-team` 且本机 `omxEnabled + omxCommand/omxArgs` 可用时,会改走 `OMX Team Runtime` JSON 协议执行并回写 `rawThreadReply / replyBody`
- 当前 `local-agent` 会在 Codex 任务执行中和完成时回传 `executionProgress`:服务端把同一任务的进度卡从 queued / running 更新到 completed / failedAndroid 原生聊天页会显示“进度 / 线程状态 / 实时状态 / 线程配置 / 线程协作 / 工具活动 / 账号状态 / 运行状态 / 安全提醒 / 审批状态 / 文件变更 / 分支详情 / 生成结果 / 后台智能体”。2026-05-31 起Codex App Server 的 `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` 安全映射为运行状态摘要;第五批已把 `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``enteredReviewMode``exitedReviewMode``commandExecution` 映射为工具活动摘要。所有进度均通过 `POST /api/v1/master-agent/tasks/[taskId]/progress` 实时刷新;字段白名单会剥离 cwd、turnId、配置文件路径、内部 prompt、collab 源/目标线程 ID、tool arguments/result、web URL token、命令正文/输出和未清洗密钥complete 回写仍会携带最终进度兜底
- 当前 `local-agent` 会在 Codex 任务执行中和完成时回传 `executionProgress`:服务端把同一任务的进度卡从 queued / running 更新到 completed / failedAndroid 原生聊天页会显示“进度 / 线程状态 / 实时状态 / 线程配置 / 线程协作 / 工具活动 / 思考摘要 / 账号状态 / 运行状态 / 安全提醒 / 审批状态 / 文件变更 / 分支详情 / 生成结果 / 后台智能体”。2026-05-31 起Codex App Server 的 `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` 安全映射为运行状态摘要;第五批已把 `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``enteredReviewMode``exitedReviewMode``commandExecution` 映射为工具活动摘要;第九批已把 `ThreadItem.plan``ThreadItem.reasoning.summary` 映射为计划步骤与思考摘要。所有进度均通过 `POST /api/v1/master-agent/tasks/[taskId]/progress` 实时刷新;字段白名单会剥离 cwd、turnId、配置文件路径、内部 prompt、collab 源/目标线程 ID、tool arguments/result、web URL token、命令正文/输出、raw reasoning content、reasoning item id 和未清洗密钥complete 回写仍会携带最终进度兜底
- 当前 `local-agent` heartbeat 已新增 Codex App Server capability discovery按 TTL 拉取模型、provider 能力、Skill、Plugin、App 摘要,写入 `capabilities.codexAppServer.metadata`Web 设备详情会展示 App Server 连接状态、模型数量、默认/快速/深度模型和扩展数量
- 当前 `MasterAgentTask` 已具备服务端租约和取消基础状态机claim 会写入 `attemptCount / maxAttempts / leaseExpiresAt`,运行中任务租约过期后可被重新认领,超过重试上限会转 `timed_out``POST /api/v1/master-agent/tasks/[taskId]/cancel` 会把任务转 `canceled`,迟到的成功 complete 不会覆盖终态
- 当前 `local-agent``browser_control / desktop_control` 已从占位骨架升级成外部 runtime 桥:当本机配置了 `browserControlEnabled + browserControlCommand``computerUseEnabled + computerUseCommand` 时,会把标准化 JSON 请求透传给外部进程,并解析单行 JSON 结果;未启用时会 fail closed返回明确的 runtime disabled 错误,不再假装执行成功

View File

@@ -698,6 +698,65 @@ function extractToolActivitySnapshot(item, lifecycleStatus = "running") {
return null;
}
function cleanPlanStepText(text) {
return safeProgressText(text, 220)
.replace(/^\s*(?:[-*•]|\d+[.)]|[☐✓✔]|\[[ xX✓]\])\s*/u, "")
.trim();
}
function extractPlanStepsFromItem(item) {
if (!item || typeof item !== "object" || item.type !== "plan") {
return [];
}
const rawSteps = asArray(item.steps).length > 0
? asArray(item.steps).map((step) => extractProgressText(step))
: String(item.text ?? "")
.split(/\r?\n/)
.map((line) => line.trim());
return rawSteps
.map(cleanPlanStepText)
.filter(Boolean)
.slice(0, 10)
.map((text, index) => ({
id: `plan-item-${index + 1}`,
text,
status: "pending",
}));
}
function extractReasoningSummaryText(summary) {
const values = asArray(summary).length > 0 ? asArray(summary) : [summary];
return safeProgressText(
values
.map((item) => {
if (typeof item === "string") {
return item;
}
if (item && typeof item === "object") {
return item.text ?? item.summary ?? "";
}
return "";
})
.filter(Boolean)
.join(" / "),
280,
);
}
function extractReasoningSummarySnapshot(item, lifecycleStatus = "running") {
if (!item || typeof item !== "object" || item.type !== "reasoning") {
return null;
}
const summary = extractReasoningSummaryText(item.summary);
if (!summary) {
return null;
}
return {
status: safeProgressText(item.status, 40) || lifecycleStatus,
summary,
};
}
function extractSubAgentSource(value) {
if (!value || typeof value !== "object") {
return undefined;
@@ -1249,6 +1308,7 @@ function createProgressCollector() {
let compaction;
let threadCollaboration;
const toolActivities = [];
let reasoningSummary;
let accountStatus;
let modelVerification;
@@ -1390,6 +1450,10 @@ function createProgressCollector() {
for (const artifact of extractArtifactsFromItem(message.params?.item, artifacts.length)) {
upsertArtifact(artifact);
}
const itemPlanSteps = extractPlanStepsFromItem(item);
if (itemPlanSteps.length > 0) {
steps.splice(0, steps.length, ...itemPlanSteps);
}
const nextCollaboration = extractThreadCollaborationSnapshot(item);
if (nextCollaboration) {
threadCollaboration = nextCollaboration;
@@ -1397,6 +1461,13 @@ function createProgressCollector() {
upsertToolActivity(
extractToolActivitySnapshot(item, message.method === "item/completed" ? "completed" : "running"),
);
const nextReasoningSummary = extractReasoningSummarySnapshot(
item,
message.method === "item/completed" ? "completed" : "running",
);
if (nextReasoningSummary) {
reasoningSummary = nextReasoningSummary;
}
if (item?.type === "contextCompaction") {
compaction = {
status: "completed",
@@ -1703,6 +1774,9 @@ function createProgressCollector() {
if (toolActivities.length > 0) {
result.toolActivities = toolActivities.map((item) => ({ ...item }));
}
if (reasoningSummary) {
result.reasoningSummary = { ...reasoningSummary };
}
if (accountStatus) {
result.accountStatus = { ...accountStatus };
}

View File

@@ -246,6 +246,11 @@ export interface ExecutionProgressToolActivity {
detail?: string;
}
export interface ExecutionProgressReasoningSummary {
status: string;
summary: string;
}
export interface ExecutionProgressSnapshot {
taskId: string;
projectId: string;
@@ -277,6 +282,7 @@ export interface ExecutionProgressSnapshot {
compaction?: ExecutionProgressCompaction;
threadCollaboration?: ExecutionProgressThreadCollaboration;
toolActivities?: ExecutionProgressToolActivity[];
reasoningSummary?: ExecutionProgressReasoningSummary;
updatedAt: string;
}
@@ -316,6 +322,10 @@ export interface ExecutionProgressInput {
cwd?: unknown;
}
>;
reasoningSummary?: Partial<ExecutionProgressReasoningSummary> & {
content?: unknown;
itemId?: unknown;
};
}
export interface ForwardSource {
@@ -4004,6 +4014,9 @@ function normalizeExecutionProgressSnapshot(raw: Partial<ExecutionProgressSnapsh
? undefined
: normalizeExecutionProgressThreadCollaboration(raw.threadCollaboration),
toolActivities: nativeRemoteControl ? undefined : normalizeExecutionProgressToolActivities(raw.toolActivities),
reasoningSummary: nativeRemoteControl
? undefined
: normalizeExecutionProgressReasoningSummary(raw.reasoningSummary),
updatedAt: raw.updatedAt ?? nowIso(),
};
}
@@ -5803,6 +5816,22 @@ function normalizeExecutionProgressToolActivities(
return activities.length > 0 ? activities : undefined;
}
function normalizeExecutionProgressReasoningSummary(
input?: ExecutionProgressInput["reasoningSummary"],
): ExecutionProgressReasoningSummary | undefined {
if (!input) {
return undefined;
}
const summary = safeExecutionProgressText(input.summary);
if (!summary) {
return undefined;
}
return {
status: safeExecutionProgressText(input.status) || "running",
summary,
};
}
function defaultExecutionProgressStepTexts(task: Pick<MasterAgentTask, "taskType" | "relayViaMasterAgent">) {
if (task.taskType === "browser_control") {
return [
@@ -5955,6 +5984,9 @@ function buildExecutionProgressSnapshot(
? undefined
: normalizeExecutionProgressThreadCollaboration(input?.threadCollaboration),
toolActivities: nativeRemoteControl ? undefined : normalizeExecutionProgressToolActivities(input?.toolActivities),
reasoningSummary: nativeRemoteControl
? undefined
: normalizeExecutionProgressReasoningSummary(input?.reasoningSummary),
updatedAt: nowIso(),
};
}

View File

@@ -818,6 +818,58 @@ rl.on("line", (line) => {
},
});
}
if (process.env.BOSS_CODEX_APP_SERVER_FIXTURE_EMIT_REASONING_PLAN_EVENTS === "1") {
send({
method: "item/completed",
params: {
threadId: message.params?.threadId,
turnId: "turn-fixture",
item: {
type: "plan",
id: "plan-secret-should-not-leak",
text: "1. 回读官方 App Server item 协议\n2. 补充 reasoning summary 安全映射",
},
},
});
send({
method: "item/started",
params: {
threadId: message.params?.threadId,
turnId: "turn-fixture",
item: {
type: "reasoning",
id: "reasoning-secret-should-not-leak",
summary: [
{
text: "正在判断哪些思考摘要可以展示。",
},
],
content: [
{
text: "raw hidden reasoning token=sk-secret-should-not-leak",
},
],
},
},
});
send({
method: "item/completed",
params: {
threadId: message.params?.threadId,
turnId: "turn-fixture",
item: {
type: "reasoning",
id: "reasoning-secret-should-not-leak",
summary: ["确认只展示官方 summary不展示 raw content。"],
content: [
{
text: "raw hidden chain of thought token=sk-secret-should-not-leak",
},
],
},
},
});
}
send({
method: "item/agentMessage/delta",
params: {

View File

@@ -718,6 +718,58 @@ test("codex app-server runner maps tool, search, image, review, and command acti
}
});
test("codex app-server runner maps item plan and reasoning summary without leaking raw reasoning", async () => {
const previous = process.env.BOSS_CODEX_APP_SERVER_FIXTURE_EMIT_REASONING_PLAN_EVENTS;
process.env.BOSS_CODEX_APP_SERVER_FIXTURE_EMIT_REASONING_PLAN_EVENTS = "1";
try {
const runnerConfig = getCodexAppServerRunnerConfig(process.env, {
codexAppServerEnabled: true,
codexAppServerCommand: process.execPath,
codexAppServerArgs: ["tests/fixtures/codex-app-server-runtime.mjs"],
codexAppServerWorkdir: repoRoot,
codexAppServerTimeoutMs: 5000,
masterAgentModel: "gpt-5.4",
});
const result = await executeCodexAppServerTask(runnerConfig, {
taskId: "task-app-server-reasoning-plan-events",
taskType: "conversation_reply",
targetCodexThreadRef: "019d-app-server-thread",
targetCodexFolderRef: repoRoot,
executionPrompt: "检查 Codex plan 和 reasoning item",
});
assert.equal(result.status, "completed");
assert.deepEqual(result.executionProgress.steps, [
{
id: "plan-item-1",
text: "回读官方 App Server item 协议",
status: "pending",
},
{
id: "plan-item-2",
text: "补充 reasoning summary 安全映射",
status: "pending",
},
]);
assert.deepEqual(result.executionProgress.reasoningSummary, {
status: "completed",
summary: "确认只展示官方 summary不展示 raw content。",
});
const serialized = JSON.stringify(result.executionProgress);
assert.equal(serialized.includes("raw hidden reasoning"), false);
assert.equal(serialized.includes("raw hidden chain of thought"), false);
assert.equal(serialized.includes("sk-secret-should-not-leak"), false);
assert.equal(serialized.includes("reasoning-secret-should-not-leak"), false);
} finally {
if (previous === undefined) {
delete process.env.BOSS_CODEX_APP_SERVER_FIXTURE_EMIT_REASONING_PLAN_EVENTS;
} else {
process.env.BOSS_CODEX_APP_SERVER_FIXTURE_EMIT_REASONING_PLAN_EVENTS = previous;
}
}
});
test("codex app-server runner bridges source thread context into target thread through inject_items", async () => {
const previous = process.env.BOSS_CODEX_APP_SERVER_FIXTURE_INTER_THREAD;
process.env.BOSS_CODEX_APP_SERVER_FIXTURE_INTER_THREAD = "1";

View File

@@ -611,3 +611,60 @@ test("POST task progress preserves Codex tool activity summaries without leaking
assert.equal(serialized.includes("/Users/kris"), false);
assert.equal(serialized.includes("id_rsa"), false);
});
test("POST task progress preserves Codex reasoning summaries without leaking raw content", async () => {
const task = await data.queueMasterAgentTask({
taskId: "route-progress-reasoning-summary-task",
projectId: "group-progress-test",
taskType: "dispatch_execution",
requestMessageId: "msg-route-progress-reasoning-summary",
requestText: "检查 Codex 思考摘要",
executionPrompt: "检查 Codex 思考摘要",
requestedBy: "krisolo",
requestedByAccount: "krisolo",
deviceId: "mac-studio",
targetProjectId: "master-agent",
targetThreadId: "master-agent-thread",
});
await data.claimNextMasterAgentTask("mac-studio");
const response = await postProgress(
new NextRequest(`http://127.0.0.1:3000/api/v1/master-agent/tasks/${task.taskId}/progress`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-boss-device-token": "boss-mac-studio-token",
},
body: JSON.stringify({
deviceId: "mac-studio",
status: "running",
executionProgress: {
steps: [{ text: "同步 Codex 思考摘要", status: "running" }],
reasoningSummary: {
status: "completed",
summary: "确认只展示官方 summary不展示 raw content token=sk-secret-should-not-persist。",
content: [{ text: "raw hidden chain of thought token=sk-secret-should-not-persist" }],
itemId: "reasoning-secret-should-not-persist",
},
},
}),
}),
{ params: Promise.resolve({ taskId: task.taskId }) },
);
assert.equal(response.status, 200);
const state = await data.readState();
const progress = state.projects
.find((project) => project.id === "master-agent")
?.messages.find((message) => message.executionProgress?.taskId === task.taskId)
?.executionProgress;
assert.deepEqual(progress?.reasoningSummary, {
status: "completed",
summary: "确认只展示官方 summary不展示 raw content token=[redacted]",
});
const serialized = JSON.stringify(progress);
assert.equal(serialized.includes("raw hidden chain of thought"), false);
assert.equal(serialized.includes("sk-secret-should-not-persist"), false);
assert.equal(serialized.includes("reasoning-secret-should-not-persist"), false);
});