@@ -5867,86 +5867,6 @@ export default function ChatPage() {
58675867 ) }
58685868 </ div >
58695869
5870- { /* Voice surface: inline by default, immersive only when expanded. */ }
5871- { voiceMode === "agent" && ! activeThread && agentOverlayMode === "immersive" && (
5872- < div
5873- className = "fixed inset-0 z-[90] overflow-hidden"
5874- style = { {
5875- color : "var(--text-primary)" ,
5876- background : "linear-gradient(180deg, color-mix(in srgb, var(--bg-primary) 97%, transparent), color-mix(in srgb, var(--bg-primary) 93%, var(--bg-secondary) 7%))" ,
5877- } }
5878- >
5879- < div
5880- className = "absolute inset-0 opacity-60"
5881- style = { {
5882- backgroundImage : [
5883- "linear-gradient(var(--voice-overlay-grid) 1px, transparent 1px)" ,
5884- "linear-gradient(90deg, var(--voice-overlay-grid-soft) 1px, transparent 1px)" ,
5885- ] . join ( ", " ) ,
5886- backgroundSize : "44px 44px" ,
5887- } }
5888- />
5889- < div className = "relative flex h-full flex-col justify-center" >
5890- < div className = "absolute right-4 top-[max(var(--mobile-safe-top),1rem)] z-10 flex gap-2 sm:right-6" >
5891- < button
5892- onClick = { ( ) => setVoicePickerOpen ( true ) }
5893- title = "Choose voice"
5894- aria-label = "Choose voice"
5895- className = { `flex h-10 w-10 items-center justify-center rounded-full border shadow-[var(--theme-shadow)] transition ${ sessionVoiceOverride ? "border-[#00f0ff]/45 bg-[#00f0ff]/15 text-[#00f0ff]" : "border-[var(--border-medium)] bg-[var(--bg-surface)]/85 text-[var(--text-secondary)] hover:bg-[var(--bg-surface-hover)] hover:text-[var(--text-primary)]" } ` }
5896- >
5897- < VoicePersonIcon />
5898- </ button >
5899- < button
5900- onClick = { ( ) => setAgentOverlayMode ( "transcript" ) }
5901- title = "Return to chat"
5902- aria-label = "Return to chat"
5903- className = "flex h-10 w-10 items-center justify-center rounded-full border border-[var(--border-medium)] bg-[var(--bg-surface)]/85 text-[var(--text-secondary)] shadow-[var(--theme-shadow)] transition hover:bg-[var(--bg-surface-hover)] hover:text-[var(--text-primary)]"
5904- >
5905- < svg className = "h-4 w-4" fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" strokeWidth = { 1.75 } >
5906- < path strokeLinecap = "round" strokeLinejoin = "round" d = "M9 4.5H5.25A.75.75 0 0 0 4.5 5.25V9m10.5-4.5h3.75a.75.75 0 0 1 .75.75V9M9 19.5H5.25a.75.75 0 0 1-.75-.75V15m10.5 4.5h3.75a.75.75 0 0 0 .75-.75V15M8.25 8.25l-3.75-3.75m15 0-3.75 3.75m-7.5 7.5-3.75 3.75m15 0-3.75-3.75" />
5907- </ svg >
5908- </ button >
5909- </ div >
5910-
5911- < div
5912- className = "flex flex-1 items-center px-4 pb-3 sm:px-6"
5913- >
5914- < div className = "mx-auto w-full max-w-none px-0 py-0" >
5915- < div
5916- className = "flex flex-col items-center gap-2"
5917- >
5918- < VoiceAgent
5919- onTranscript = { ( text ) => sendMessage ( text , { forceVoiceResponse : true } ) }
5920- onRealtimeTranscript = { ( event ) => persistRealtimeTranscript ( event , {
5921- sessionKey : activeVoiceSessionKey ,
5922- storeKey : activeVoiceStoreKey ,
5923- setVisibleMessages : setMessages ,
5924- } ) }
5925- isPlayingAudio = { isPlayingAudio }
5926- onInterrupt = { interruptAudio }
5927- isLoading = { isLoading }
5928- accentColor = { agentColor }
5929- autoActivate
5930- immersive
5931- isMicMuted = { agentMicMuted }
5932- isAgentMuted = { agentAudioMuted }
5933- onMicMutedChange = { setAgentMicMuted }
5934- onAgentMutedChange = { handleAgentAudioMutedChange }
5935- agent = { selectedAgent ?. callsign }
5936- gatewayAgent = { delegatedViaAgent ?. callsign ?? selectedAgent ?. callsign }
5937- companyId = { company ?. id }
5938- sessionKey = { selectedSessionBelongsToAgent ( selectedSessionKey , selectedAgent ?. callsign )
5939- ? selectedSessionKey ?? gatewaySessionKeyForAgent ( selectedAgent )
5940- : gatewaySessionKeyForAgent ( selectedAgent ) }
5941- realtimeRuntimeId = { selectedAgent ?. runtimeId ?? undefined }
5942- />
5943- </ div >
5944- </ div >
5945- </ div >
5946- </ div >
5947- </ div >
5948- ) }
5949-
59505870 < VoiceSelectModal
59515871 open = { voicePickerOpen }
59525872 title = "Voice"
@@ -5993,8 +5913,30 @@ export default function ChatPage() {
59935913 setIsDragOver ( false ) ;
59945914 if ( event . dataTransfer . files . length ) addFiles ( event . dataTransfer . files ) ;
59955915 } }
5996- agentPanel = { voiceMode === "agent" && ! activeThread && agentOverlayMode === "transcript" ? (
5997- < div className = "relative max-h-[min(10.75rem,28dvh)] overflow-hidden rounded-[24px] border border-[var(--voice-shell-border)] bg-[var(--bg-surface)]/88 px-3 py-2 shadow-[var(--theme-shadow)] backdrop-blur-xl sm:max-h-none" >
5916+ agentPanel = { voiceMode === "agent" && ! activeThread ? (
5917+ < div
5918+ className = { agentOverlayMode === "immersive"
5919+ ? "fixed inset-0 z-[90] flex items-center justify-center overflow-hidden px-4 pb-3 sm:px-6"
5920+ : "relative max-h-[min(10.75rem,28dvh)] overflow-hidden rounded-[24px] border border-[var(--voice-shell-border)] bg-[var(--bg-surface)]/88 px-3 py-2 shadow-[var(--theme-shadow)] backdrop-blur-xl sm:max-h-none" }
5921+ style = { agentOverlayMode === "immersive"
5922+ ? {
5923+ color : "var(--text-primary)" ,
5924+ background : "linear-gradient(180deg, color-mix(in srgb, var(--bg-primary) 97%, transparent), color-mix(in srgb, var(--bg-primary) 93%, var(--bg-secondary) 7%))" ,
5925+ }
5926+ : undefined }
5927+ >
5928+ { agentOverlayMode === "immersive" && (
5929+ < div
5930+ className = "absolute inset-0 opacity-60"
5931+ style = { {
5932+ backgroundImage : [
5933+ "linear-gradient(var(--voice-overlay-grid) 1px, transparent 1px)" ,
5934+ "linear-gradient(90deg, var(--voice-overlay-grid-soft) 1px, transparent 1px)" ,
5935+ ] . join ( ", " ) ,
5936+ backgroundSize : "44px 44px" ,
5937+ } }
5938+ />
5939+ ) }
59985940 < VoiceAgent
59995941 onTranscript = { ( text ) => sendMessage ( text , { forceVoiceResponse : true } ) }
60005942 onRealtimeTranscript = { ( event ) => persistRealtimeTranscript ( event , {
@@ -6007,7 +5949,8 @@ export default function ChatPage() {
60075949 isLoading = { isLoading }
60085950 accentColor = { agentColor }
60095951 autoActivate
6010- compact
5952+ compact = { agentOverlayMode !== "immersive" }
5953+ immersive = { agentOverlayMode === "immersive" }
60115954 isMicMuted = { agentMicMuted }
60125955 isAgentMuted = { agentAudioMuted }
60135956 onMicMutedChange = { setAgentMicMuted }
@@ -6020,23 +5963,34 @@ export default function ChatPage() {
60205963 : gatewaySessionKeyForAgent ( selectedAgent ) }
60215964 realtimeRuntimeId = { selectedAgent ?. runtimeId ?? undefined }
60225965 />
6023- < div className = "absolute right-2 top-2 flex items-center gap-1" >
5966+ < div className = { agentOverlayMode === "immersive"
5967+ ? "absolute right-4 top-[max(var(--mobile-safe-top),1rem)] z-10 flex gap-2 sm:right-6"
5968+ : "absolute right-2 top-2 flex items-center gap-1" }
5969+ >
60245970 < button
60255971 onClick = { ( ) => setVoicePickerOpen ( true ) }
60265972 title = "Choose voice"
60275973 aria-label = "Choose voice"
6028- className = { `flex h-8 w-8 items-center justify-center rounded-full border transition ${ sessionVoiceOverride ? "border-[#00f0ff]/45 bg-[#00f0ff]/15 text-[#00f0ff]" : "border-[var(--border-medium)] bg-[var(--bg-primary)]/70 text-[var(--text-secondary)] hover:bg-[var(--bg-surface-hover)] hover:text-[var(--text-primary)]" } ` }
5974+ className = { agentOverlayMode === "immersive"
5975+ ? `flex h-10 w-10 items-center justify-center rounded-full border shadow-[var(--theme-shadow)] transition ${ sessionVoiceOverride ? "border-[#00f0ff]/45 bg-[#00f0ff]/15 text-[#00f0ff]" : "border-[var(--border-medium)] bg-[var(--bg-surface)]/85 text-[var(--text-secondary)] hover:bg-[var(--bg-surface-hover)] hover:text-[var(--text-primary)]" } `
5976+ : `flex h-8 w-8 items-center justify-center rounded-full border transition ${ sessionVoiceOverride ? "border-[#00f0ff]/45 bg-[#00f0ff]/15 text-[#00f0ff]" : "border-[var(--border-medium)] bg-[var(--bg-primary)]/70 text-[var(--text-secondary)] hover:bg-[var(--bg-surface-hover)] hover:text-[var(--text-primary)]" } ` }
60295977 >
6030- < VoicePersonIcon className = " h-3.5 w-3.5" />
5978+ < VoicePersonIcon className = { agentOverlayMode === "immersive" ? undefined : " h-3.5 w-3.5"} />
60315979 </ button >
60325980 < button
6033- onClick = { ( ) => setAgentOverlayMode ( "immersive" ) }
6034- title = "Enter fullscreen visual mode"
6035- aria-label = "Enter fullscreen visual mode"
6036- className = "flex h-8 w-8 items-center justify-center rounded-full border border-[var(--border-medium)] bg-[var(--bg-primary)]/70 text-[var(--text-secondary)] transition hover:bg-[var(--bg-surface-hover)] hover:text-[var(--text-primary)]"
5981+ onClick = { ( ) => setAgentOverlayMode ( agentOverlayMode === "immersive" ? "transcript" : "immersive" ) }
5982+ title = { agentOverlayMode === "immersive" ? "Return to chat" : "Enter fullscreen visual mode" }
5983+ aria-label = { agentOverlayMode === "immersive" ? "Return to chat" : "Enter fullscreen visual mode" }
5984+ className = { agentOverlayMode === "immersive"
5985+ ? "flex h-10 w-10 items-center justify-center rounded-full border border-[var(--border-medium)] bg-[var(--bg-surface)]/85 text-[var(--text-secondary)] shadow-[var(--theme-shadow)] transition hover:bg-[var(--bg-surface-hover)] hover:text-[var(--text-primary)]"
5986+ : "flex h-8 w-8 items-center justify-center rounded-full border border-[var(--border-medium)] bg-[var(--bg-primary)]/70 text-[var(--text-secondary)] transition hover:bg-[var(--bg-surface-hover)] hover:text-[var(--text-primary)]" }
60375987 >
6038- < svg className = "h-3.5 w-3.5" fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" strokeWidth = { 1.75 } >
6039- < path strokeLinecap = "round" strokeLinejoin = "round" d = "M3.75 9V5.25A1.5 1.5 0 0 1 5.25 3.75H9m6 0h3.75A1.5 1.5 0 0 1 20.25 5.25V9m0 6v3.75a1.5 1.5 0 0 1-1.5 1.5H15m-6 0H5.25a1.5 1.5 0 0 1-1.5-1.5V15" />
5988+ < svg className = { agentOverlayMode === "immersive" ? "h-4 w-4" : "h-3.5 w-3.5" } fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" strokeWidth = { 1.75 } >
5989+ { agentOverlayMode === "immersive" ? (
5990+ < path strokeLinecap = "round" strokeLinejoin = "round" d = "M9 4.5H5.25A.75.75 0 0 0 4.5 5.25V9m10.5-4.5h3.75a.75.75 0 0 1 .75.75V9M9 19.5H5.25a.75.75 0 0 1-.75-.75V15m10.5 4.5h3.75a.75.75 0 0 0 .75-.75V15M8.25 8.25l-3.75-3.75m15 0-3.75 3.75m-7.5 7.5-3.75 3.75m15 0-3.75-3.75" />
5991+ ) : (
5992+ < path strokeLinecap = "round" strokeLinejoin = "round" d = "M3.75 9V5.25A1.5 1.5 0 0 1 5.25 3.75H9m6 0h3.75A1.5 1.5 0 0 1 20.25 5.25V9m0 6v3.75a1.5 1.5 0 0 1-1.5 1.5H15m-6 0H5.25a1.5 1.5 0 0 1-1.5-1.5V15" />
5993+ ) }
60405994 </ svg >
60415995 </ button >
60425996 </ div >
0 commit comments