feat: enhanced sockets, tuned retries and polling fallback

This commit is contained in:
cogwheel0
2025-09-07 11:13:05 +05:30
parent 3decf9d46b
commit a16fb86e27
11 changed files with 519 additions and 138 deletions

View File

@@ -55,10 +55,27 @@ class ChatMessagesNotifier extends StateNotifier<List<ChatMessage>> {
// locally streamed assistant content with an outdated server copy.
if (previous?.updatedAt != next?.updatedAt) {
final serverMessages = next?.messages ?? const [];
// Only replace local messages if the server has strictly more messages
// (i.e., includes new content we don't have yet).
// Primary rule: adopt server messages when there are strictly more of them.
if (serverMessages.length > state.length) {
state = serverMessages;
return;
}
// Secondary rule: if counts are equal but the last assistant message grew,
// adopt the server copy to recover from missed socket events.
if (serverMessages.isNotEmpty && state.isNotEmpty) {
final serverLast = serverMessages.last;
final localLast = state.last;
final serverText = serverLast.content.trim();
final localText = localLast.content.trim();
final sameLastId = serverLast.id == localLast.id;
final isAssistant = serverLast.role == 'assistant';
final serverHasMore = serverText.isNotEmpty && serverText.length > localText.length;
final localEmptyButServerHas = localText.isEmpty && serverText.isNotEmpty;
if (sameLastId && isAssistant && (serverHasMore || localEmptyButServerHas)) {
state = serverMessages;
return;
}
}
}
return;

View File

@@ -1408,16 +1408,21 @@ class _ChatPageState extends ConsumerState<ChatPage> {
try {
final full = await api.getConversation(active.id);
ref
.read(activeConversationProvider.notifier)
.state =
full;
.read(activeConversationProvider.notifier)
.state = full;
} catch (e) {
debugPrint(
'DEBUG: Failed to refresh conversation: $e',
);
// Could show a snackbar here if needed
debugPrint('DEBUG: Failed to refresh conversation: $e');
}
}
// Also refresh the conversations list to reconcile missed events
// and keep timestamps/order in sync with the server.
try {
ref.invalidate(conversationsProvider);
// Best-effort await to stabilize UI; ignore errors.
await ref.read(conversationsProvider.future);
} catch (_) {}
// Add small delay for better UX feedback
await Future.delayed(const Duration(milliseconds: 300));
},