分页切片开头的前导条目并进后面那个回合

- buildDirectChatTurns 先攒住第一个用户条目之前的过程条目,交给后面那个回合
- 不再渲染没有用户气泡的孤儿回合;整份历史都没有用户条目时仍保留一个回合
- directTurnPresentation 单测补一条分页切片从半截回合开头的情形
This commit is contained in:
2026-09-17 00:02:11 +08:00
parent e17af3008e
commit 098693636a
2 changed files with 36 additions and 2 deletions
@@ -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) => {
@@ -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'),