diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx index ac459702d..73b987cf8 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx @@ -442,6 +442,9 @@ export function ProjectSupervisorView({ const toolCallsByAnchor = new Map(); const liveToolCalls: GameCreatorDirectToolCall[] = []; let liveToolCallTurnId = ''; + // 老项目里持久化的 assistant 消息 id 是 Codex 原始 id(不是 `direct-codex::assistant`), + // 因此锚不上;这些工具的回合不能丢,统一收集后渲染在列表末尾。 + const unanchoredToolCallsByTurn = new Map(); // 正在跑的回合:它的流条目直接渲染在消息列表末尾,直到用户消息落盘、由那条消息接管。 const liveStreamTurnId = streamTurnId && turnStreamByTurn.has(streamTurnId) ? streamTurnId @@ -472,9 +475,20 @@ export function ProjectSupervisorView({ liveToolCallTurnId = call.turnId; } liveToolCalls.push(call); + continue; } + const bucket = unanchoredToolCallsByTurn.get(call.turnId) ?? []; + bucket.push(call); + unanchoredToolCallsByTurn.set(call.turnId, bucket); } } + const unanchoredToolCalls = [...unanchoredToolCallsByTurn.entries()] + .sort((left, right) => { + const leftAt = Math.min(...left[1].map((call) => call.startedAt || 0)); + const rightAt = Math.min(...right[1].map((call) => call.startedAt || 0)); + return leftAt - rightAt; + }) + .map(([turnId, calls]) => ({ turnId, calls })); // 该回合用户消息的 `updatedAt`:拿得到就在块头显示「发送 → 结束」,拿不到只显示结束时间。 const userMessageUpdatedAtForTurn = (turnId: string) => { if (!turnId) { @@ -738,6 +752,14 @@ export function ProjectSupervisorView({ ); })} + {unanchoredToolCalls.map(({ turnId, calls }) => ( + + ))} {liveToolCalls.length > 0 ? (