@@ -626,7 +626,7 @@ function claimInitialSupervisorMessageForPage(projectPath: string, scope = '') {
|
||||
* 初始需求是**乐观插入**到 messages 的(latch 命中后先插一条 user 消息,再发起回合),
|
||||
* 而历史回读在 replace 分支里是无条件整体替换 —— 只要回读晚于乐观插入,那条用户消息
|
||||
* 就会被冲掉(界面上看不到初始需求,但回合其实已经跑起来了)。
|
||||
* 这里只把当前 messages 里"非历史来源、运行时拥有、且回读结果里没有"的消息保留在末尾。
|
||||
* 这里把当前 messages 里"运行时拥有、且回读结果里没有"的消息保留在末尾(它们是最新的)。
|
||||
*/
|
||||
function mergeLoadedConversationWithPendingRuntimeMessages(
|
||||
loaded: ChatMessage[],
|
||||
@@ -644,7 +644,7 @@ function mergeLoadedConversationWithPendingRuntimeMessages(
|
||||
loaded.map((message) => `${message.role}\u0000${message.text}`),
|
||||
);
|
||||
const pending = current.filter((message) => {
|
||||
if (!message.runtimeOwned || message.fromHistory) {
|
||||
if (!message.runtimeOwned) {
|
||||
return false;
|
||||
}
|
||||
if (message.messageId) {
|
||||
@@ -4202,7 +4202,7 @@ export function App({
|
||||
const conversationMessages = mergeProjectSupervisorConversation(
|
||||
resolvedProjectConversation.messages,
|
||||
supervisorConversation?.messages ?? [],
|
||||
).map((message) => ({ ...message, fromHistory: true }));
|
||||
);
|
||||
if (
|
||||
conversationContainsProjectSupervisorResponseStream(
|
||||
supervisorConversation?.messages ?? [],
|
||||
@@ -12528,7 +12528,6 @@ export function App({
|
||||
: ('assistant' as const),
|
||||
text: message.content,
|
||||
runtimeOwned: true,
|
||||
fromHistory: true,
|
||||
messageId: message.messageId,
|
||||
updatedAt: message.updatedAt,
|
||||
}));
|
||||
|
||||
@@ -999,8 +999,6 @@ export interface ChatMessage {
|
||||
agentId?: string | null;
|
||||
updatedAt?: number;
|
||||
runtimeOwned?: boolean;
|
||||
/** 来自历史回读,不作为尚未落盘的实时消息追加到新历史页末尾。 */
|
||||
fromHistory?: boolean;
|
||||
}
|
||||
|
||||
export type DesignAgentInput =
|
||||
|
||||
@@ -97,43 +97,6 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe('Direct 聊天历史分页集成', () => {
|
||||
it('加载旧页后重读历史回到最新页,再翻页仍按原顺序且不重复', async () => {
|
||||
const invoke = install((args) =>
|
||||
args.beforeItemId
|
||||
? page(messages.slice(0, 6), false)
|
||||
: page(messages.slice(6), true),
|
||||
);
|
||||
mount();
|
||||
await screen.findByText('历史正文 25');
|
||||
fireEvent.click(earlier());
|
||||
await screen.findByText('历史正文 0');
|
||||
await setComposerText(screen.getByLabelText('陶泥儿对话内容'), '/history');
|
||||
fireEvent.click(screen.getByRole('button', { name: '发送' }));
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
});
|
||||
expect(screen.queryByText('历史正文 0')).toBeNull();
|
||||
expect(screen.getByText('历史正文 25')).not.toBeNull();
|
||||
fireEvent.click(earlier());
|
||||
await screen.findByText('历史正文 0');
|
||||
for (let index = 0; index < messages.length; index += 1) {
|
||||
expect(screen.getAllByText(`历史正文 ${index}`)).toHaveLength(1);
|
||||
if (index > 0) {
|
||||
expect(
|
||||
screen
|
||||
.getByText(`历史正文 ${index - 1}`)
|
||||
.compareDocumentPosition(screen.getByText(`历史正文 ${index}`)) &
|
||||
Node.DOCUMENT_POSITION_FOLLOWING,
|
||||
).not.toBe(0);
|
||||
}
|
||||
}
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_direct_project_history_slice',
|
||||
),
|
||||
).toHaveLength(4);
|
||||
});
|
||||
|
||||
it('首屏按消息加载20条,更早消息使用原生游标,原始工具记录不占页', async () => {
|
||||
const invoke = install((args) =>
|
||||
args.beforeItemId
|
||||
|
||||
Reference in New Issue
Block a user