Mirror user text into realtime (#17520)

- Let typed user messages submit while realtime is active and mirror
accepted text into the realtime text stream.
- Add integration coverage and snapshot for outbound realtime text.
This commit is contained in:
Ahmed Ibrahim
2026-04-12 15:03:14 -07:00
committed by GitHub
parent cb870a169a
commit d840b247d7
7 changed files with 200 additions and 102 deletions
-26
View File
@@ -29,7 +29,6 @@ pub(super) struct RealtimeConversationUiState {
pub(super) phase: RealtimeConversationPhase,
requested_close: bool,
session_id: Option<String>,
warned_audio_only_submission: bool,
transport: RealtimeConversationUiTransport,
#[cfg(not(target_os = "linux"))]
pub(super) meter_placeholder_id: Option<String>,
@@ -191,28 +190,6 @@ impl ChatWidget {
self.last_rendered_user_message_event.as_ref() != Some(&key)
}
pub(super) fn maybe_defer_user_message_for_realtime(
&mut self,
user_message: UserMessage,
) -> Option<UserMessage> {
if !self.realtime_conversation.is_live() {
return Some(user_message);
}
self.restore_user_message_to_composer(user_message);
if !self.realtime_conversation.warned_audio_only_submission {
self.realtime_conversation.warned_audio_only_submission = true;
self.add_info_message(
"Realtime voice mode is audio-only. Use /realtime to stop.".to_string(),
/*hint*/ None,
);
} else {
self.request_redraw();
}
None
}
fn realtime_footer_hint_items() -> Vec<(String, String)> {
vec![("/realtime".to_string(), "stop live voice".to_string())]
}
@@ -238,7 +215,6 @@ impl ChatWidget {
self.realtime_conversation.phase = RealtimeConversationPhase::Starting;
self.realtime_conversation.requested_close = false;
self.realtime_conversation.session_id = None;
self.realtime_conversation.warned_audio_only_submission = false;
self.set_footer_hint_override(Some(Self::realtime_footer_hint_items()));
match self.config.realtime.transport {
RealtimeTransport::Websocket => {
@@ -297,7 +273,6 @@ impl ChatWidget {
self.realtime_conversation.phase = RealtimeConversationPhase::Inactive;
self.realtime_conversation.requested_close = false;
self.realtime_conversation.session_id = None;
self.realtime_conversation.warned_audio_only_submission = false;
self.realtime_conversation.transport = RealtimeConversationUiTransport::Websocket;
}
@@ -320,7 +295,6 @@ impl ChatWidget {
return;
}
self.realtime_conversation.session_id = ev.session_id;
self.realtime_conversation.warned_audio_only_submission = false;
self.set_footer_hint_override(Some(Self::realtime_footer_hint_items()));
if self.realtime_conversation_uses_webrtc() {
self.realtime_conversation.phase = RealtimeConversationPhase::Starting;