fix: dedupe assistant chat messages

This commit is contained in:
Haitao Pan 2026-05-07 19:34:19 +08:00
parent 679ce97d7b
commit 77c761bcc1
2 changed files with 83 additions and 1 deletions

View File

@ -489,7 +489,22 @@ extension AppControllerDesktopThreadSessions on AppController {
),
);
}
return items;
return dedupeGatewayChatMessagesByIdThreadSessionInternal(items);
}
List<GatewayChatMessage> dedupeGatewayChatMessagesByIdThreadSessionInternal(
List<GatewayChatMessage> messages,
) {
final seenIds = <String>{};
final deduped = <GatewayChatMessage>[];
for (final message in messages) {
final id = message.id.trim();
if (id.isNotEmpty && !seenIds.add(id)) {
continue;
}
deduped.add(message);
}
return deduped;
}
String normalizedAssistantSessionKeyInternal(String sessionKey) {

View File

@ -596,6 +596,73 @@ void main() {
);
},
);
test(
'chatMessages does not duplicate persisted local turn messages',
() async {
final controller = AppController(
environmentOverride: const <String, String>{},
);
addTearDown(controller.dispose);
await controller.sessionsController.switchSession('session-1');
final userMessage = GatewayChatMessage(
id: 'local-user-1',
role: 'user',
text: 'hi',
timestampMs: DateTime.now().millisecondsSinceEpoch.toDouble(),
toolCallId: null,
toolName: null,
stopReason: null,
pending: false,
error: false,
);
final assistantMessage = GatewayChatMessage(
id: 'local-assistant-1',
role: 'assistant',
text: 'Bridge response',
timestampMs: DateTime.now().millisecondsSinceEpoch.toDouble(),
toolCallId: null,
toolName: null,
stopReason: null,
pending: false,
error: false,
);
controller.appendLocalSessionMessageInternal(
'session-1',
userMessage,
persistInThreadContext: true,
);
controller.appendLocalSessionMessageInternal(
'session-1',
assistantMessage,
persistInThreadContext: true,
);
controller.assistantThreadMessagesInternal['session-1'] =
List<GatewayChatMessage>.from(
controller
.requireTaskThreadForSessionInternal('session-1')
.messages,
);
final visibleMessages = controller.chatMessages;
expect(
visibleMessages.where((message) => message.id == userMessage.id),
hasLength(1),
);
expect(
visibleMessages.where((message) => message.id == assistantMessage.id),
hasLength(1),
);
expect(
visibleMessages.map((message) => message.text),
containsAllInOrder(<String>[userMessage.text, assistantMessage.text]),
);
},
);
});
}