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

@@ -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.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.codexTurns, "轮次3 个 · 运行中 1 个 · 完成 2 个 · 最新 2026-06-03 16:21");
});
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",
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,
"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;
}
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") {
send({
id: message.id,

View File

@@ -78,6 +78,19 @@ test("codex app-server discovery includes governance and MCP summaries without l
loaded: true,
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);
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("secret user text should not leak"), 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) {