From 098693636aa3e48c8eb8855a4683efa7ddf24ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Thu, 17 Sep 2026 00:02:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E9=A1=B5=E5=88=87=E7=89=87=E5=BC=80?= =?UTF-8?q?=E5=A4=B4=E7=9A=84=E5=89=8D=E5=AF=BC=E6=9D=A1=E7=9B=AE=E5=B9=B6?= =?UTF-8?q?=E8=BF=9B=E5=90=8E=E9=9D=A2=E9=82=A3=E4=B8=AA=E5=9B=9E=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - buildDirectChatTurns 先攒住第一个用户条目之前的过程条目,交给后面那个回合 - 不再渲染没有用户气泡的孤儿回合;整份历史都没有用户条目时仍保留一个回合 - directTurnPresentation 单测补一条分页切片从半截回合开头的情形 --- .../directTurnPresentation.ts | 17 +++++++++++++-- .../tests/directTurnPresentation.test.ts | 21 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/directTurnPresentation.ts b/apps/ai-game-creator-shell/src/features/project-workspace/directTurnPresentation.ts index 20e17ca0e..a481c03ed 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/directTurnPresentation.ts +++ b/apps/ai-game-creator-shell/src/features/project-workspace/directTurnPresentation.ts @@ -149,17 +149,30 @@ export function buildDirectChatTurns({ }): DirectChatTurn[] { const turns: DirectChatTurnEntries[] = []; let current: DirectChatTurnEntries | null = null; + // 分页切片的开头可能落在半截回合里(那一条用户条目还在更早的一屏):这些前导条目先攒着, + // 交给后面第一个用户条目开的回合,避免渲染出一个没有用户气泡的孤儿回合。 + const leadingEntries: DirectChatEntry[] = []; for (const entry of entries) { if (entry.kind === 'message' && entry.role === 'user') { current = newTurn(entry.itemId); turns.push(current); + if (leadingEntries.length > 0) { + current.entries.push(...leadingEntries); + leadingEntries.length = 0; + } } if (!current) { - current = newTurn(`history:${turns.length}`); - turns.push(current); + leadingEntries.push(entry); + continue; } current.entries.push(entry); } + if (!current && leadingEntries.length > 0) { + // 整份历史都没有用户条目:仍然保留一个回合承载正文。 + current = newTurn(`history:${turns.length}`); + current.entries.push(...leadingEntries); + turns.push(current); + } const entryIds = new Set(entries.map((entry) => entry.itemId)); localMessages.forEach((message, index) => { diff --git a/apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts b/apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts index a887f02c2..809041ff9 100644 --- a/apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts +++ b/apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts @@ -202,6 +202,27 @@ describe('DirectProject 聊天分区', () => { expect(turns[0]?.finals[0]).toMatchObject({ text: '只有回复' }); }); + it('分页切片开头落在半截回合里时并进后面那个回合,不生成没有用户气泡的孤儿回合', () => { + // 更早的一屏把上一条用户条目切在外面:这三条前导条目属于上一轮,但不能自成回合。 + const turns = buildDirectChatTurns({ + entries: [ + reasoningEntry('r-prev'), + toolEntry('t-prev'), + assistantEntry('a-prev', '上一轮的答复', 1_800_000_000_900), + userEntry('u2', 1_800_000_010_000), + assistantEntry('a2', '这一轮的答复', 1_800_000_011_000), + ], + }); + expect(turns.map((turn) => turn.key)).toEqual(['u2']); + expect(turns[0]?.users.map((block) => block.key)).toEqual(['u2:u2']); + expect(turns[0]?.process.map((block) => block.key)).toEqual([ + 'u2:r-prev', + 'u2:t-prev', + 'u2:a-prev', + ]); + expect(turns[0]?.finals.map((block) => block.key)).toEqual(['u2:a2']); + }); + it('条目转消息只保留用户 / 助手正文,并按身份去重', () => { const messages = directChatEntriesToMessages([ userEntry('u1'),