feat: summarize codex stream progress events

This commit is contained in:
AI Bot
2026-06-03 12:53:43 +08:00
parent bc9a586e81
commit 142fb2a4b3
11 changed files with 419 additions and 3 deletions

View File

@@ -1679,6 +1679,49 @@ public final class BossUi {
}
}
JSONObject streamEvents = progress == null ? null : progress.optJSONObject("streamEvents");
if (streamEvents != null) {
int agentDeltaCount = streamEvents.optInt("agentDeltaCount", 0);
int planDeltaCount = streamEvents.optInt("planDeltaCount", 0);
int reasoningDeltaCount = streamEvents.optInt("reasoningDeltaCount", 0);
int toolProgressCount = streamEvents.optInt("toolProgressCount", 0);
int commandOutputChunkCount = streamEvents.optInt("commandOutputChunkCount", 0);
int terminalInteractionCount = streamEvents.optInt("terminalInteractionCount", 0);
int fileOutputChunkCount = streamEvents.optInt("fileOutputChunkCount", 0);
boolean hasStreamEvents = agentDeltaCount > 0 || planDeltaCount > 0 || reasoningDeltaCount > 0 ||
toolProgressCount > 0 || commandOutputChunkCount > 0 || terminalInteractionCount > 0 ||
fileOutputChunkCount > 0;
if (hasStreamEvents) {
card.addView(divider(context));
card.addView(sectionTitle(context, "流式增量"));
String status = streamEvents.optString("status", "").trim();
if (!TextUtils.isEmpty(status)) {
card.addView(detailRow(context, "", "状态 " + status, "", false));
}
if (agentDeltaCount > 0) {
card.addView(detailRow(context, "", "回复片段 " + agentDeltaCount, "", false, true));
}
if (planDeltaCount > 0) {
card.addView(detailRow(context, "", "计划片段 " + planDeltaCount, "", false, true));
}
if (reasoningDeltaCount > 0) {
card.addView(detailRow(context, "", "思考片段 " + reasoningDeltaCount, "", false, true));
}
if (toolProgressCount > 0) {
card.addView(detailRow(context, "", "工具进度 " + toolProgressCount, "", false, true));
}
if (commandOutputChunkCount > 0) {
card.addView(detailRow(context, "", "命令输出片段 " + commandOutputChunkCount, "", false, true));
}
if (terminalInteractionCount > 0) {
card.addView(detailRow(context, "", "终端交互 " + terminalInteractionCount, "", false, true));
}
if (fileOutputChunkCount > 0) {
card.addView(detailRow(context, "", "文件输出片段 " + fileOutputChunkCount, "", false, true));
}
}
}
JSONArray warnings = progress == null ? null : progress.optJSONArray("warnings");
if (warnings != null && warnings.length() > 0) {
card.addView(divider(context));

View File

@@ -1234,6 +1234,58 @@ public class ProjectDetailActivityUiTest {
assertFalse(viewTreeContainsText(messageView, "sk-secret-should-not-render"));
}
@Test
public void executionProgressMessageRendersCodexStreamEventsSection() throws Exception {
Intent intent = new Intent()
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_ID, "stream-events")
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_NAME, "Boss开发主线程");
TestProjectDetailActivity activity = Robolectric
.buildActivity(TestProjectDetailActivity.class, intent)
.setup()
.get();
JSONObject message = new JSONObject()
.put("id", "progress-stream-events-1")
.put("sender", "master")
.put("senderLabel", "主 Agent")
.put("body", "执行进度")
.put("kind", "execution_progress")
.put("sentAt", "2026-06-03T11:20:00+08:00")
.put("executionProgress", new JSONObject()
.put("status", "running")
.put("steps", new JSONArray()
.put(new JSONObject().put("text", "接收 Codex 流式事件").put("status", "running")))
.put("streamEvents", new JSONObject()
.put("status", "streaming")
.put("agentDeltaCount", 2)
.put("planDeltaCount", 1)
.put("reasoningDeltaCount", 3)
.put("toolProgressCount", 1)
.put("commandOutputChunkCount", 4)
.put("terminalInteractionCount", 1)
.put("fileOutputChunkCount", 1)
.put("delta", "secret delta should-not-render")
.put("output", "secret output should-not-render")
.put("content", "secret content should-not-render")));
View messageView = ReflectionHelpers.callInstanceMethod(
activity,
"buildMessageView",
ReflectionHelpers.ClassParameter.from(JSONObject.class, message)
);
assertTrue(viewTreeContainsText(messageView, "流式增量"));
assertTrue(viewTreeContainsText(messageView, "状态 streaming"));
assertTrue(viewTreeContainsText(messageView, "回复片段 2"));
assertTrue(viewTreeContainsText(messageView, "计划片段 1"));
assertTrue(viewTreeContainsText(messageView, "思考片段 3"));
assertTrue(viewTreeContainsText(messageView, "工具进度 1"));
assertTrue(viewTreeContainsText(messageView, "命令输出片段 4"));
assertTrue(viewTreeContainsText(messageView, "终端交互 1"));
assertTrue(viewTreeContainsText(messageView, "文件输出片段 1"));
assertFalse(viewTreeContainsText(messageView, "should-not-render"));
}
@Test
public void executionProgressMessageRendersCodexToolActivitySection() throws Exception {
Intent intent = new Intent()