Matthias Nott
2026-03-23 e1c8bac29517bc4390e6e7ca22e37f74bbf7f20a
fix: atomic bundle with voiceMessageId for transcript, no double voice send
1 files modified
changed files
lib/screens/chat_screen.dart patch | view | blame | history
lib/screens/chat_screen.dart
....@@ -874,37 +874,32 @@
874874 textCaption = '';
875875 }
876876
877
- // Send everything as a single atomic bundle — the server will compose
878
- // all attachments + caption into one terminal input (like dropping files + text)
879877 final attachments = encodedImages.map((b64) =>
880878 <String, dynamic>{'data': b64, 'mimeType': 'image/jpeg'}
881879 ).toList();
882880
883
- _ws?.send({
884
- 'type': 'bundle',
885
- 'caption': textCaption,
886
- if (voiceB64 != null) 'audioBase64': voiceB64,
887
- 'attachments': attachments,
888
- 'sessionId': targetSessionId,
889
- });
890
-
891
- // If voice caption, also send separately for Whisper transcription
881
+ // Create voice bubble first to get messageId for transcript reflection
882
+ String? voiceMessageId;
892883 if (voiceB64 != null) {
893884 final voiceMsg = Message.voice(
894885 role: MessageRole.user,
895886 audioUri: caption.substring('__voice__:'.length),
896887 status: MessageStatus.sent,
897888 );
889
+ voiceMessageId = voiceMsg.id;
898890 ref.read(messagesProvider.notifier).addMessage(voiceMsg);
899
- _ws?.send({
900
- 'type': 'voice',
901
- 'audioBase64': voiceB64,
902
- 'content': '',
903
- 'messageId': voiceMsg.id,
904
- 'sessionId': targetSessionId,
905
- });
906891 }
907892
893
+ // Send everything as a single atomic bundle
894
+ _ws?.send({
895
+ 'type': 'bundle',
896
+ 'caption': textCaption,
897
+ if (voiceB64 != null) 'audioBase64': voiceB64,
898
+ if (voiceMessageId != null) 'voiceMessageId': voiceMessageId,
899
+ 'attachments': attachments,
900
+ 'sessionId': targetSessionId,
901
+ });
902
+
908903 // Show images in chat locally
909904 for (var i = 0; i < encodedImages.length; i++) {
910905 final message = Message.image(