diff --git a/src/app/chat/page.tsx b/src/app/chat/page.tsx
index 872559b..7569ea5 100644
--- a/src/app/chat/page.tsx
+++ b/src/app/chat/page.tsx
@@ -6045,30 +6045,10 @@ export default function ChatPage() {
setIsDragOver(false);
if (event.dataTransfer.files.length) addFiles(event.dataTransfer.files);
}}
- agentPanel={voiceMode === "agent" && !activeThread ? (
+ agentPanel={voiceMode === "agent" && !activeThread && agentOverlayMode !== "immersive" ? (
- {agentOverlayMode === "immersive" && (
-
- )}
sendMessage(text, { forceVoiceResponse: true })}
onRealtimeTranscript={(event) => persistRealtimeTranscript(event, {
@@ -6081,8 +6061,7 @@ export default function ChatPage() {
isLoading={isLoading}
accentColor={resolvedVisualAccentColor}
autoActivate
- compact={agentOverlayMode !== "immersive"}
- immersive={agentOverlayMode === "immersive"}
+ compact
isMicMuted={agentMicMuted}
isAgentMuted={agentAudioMuted}
onMicMutedChange={setAgentMicMuted}
@@ -6097,36 +6076,25 @@ export default function ChatPage() {
voiceSettings={resolvedVoiceSettings}
visualSettings={resolvedVisualSettings}
/>
-
+
@@ -6135,6 +6103,75 @@ export default function ChatPage() {
/>
+ {voiceMode === "agent" && !activeThread && agentOverlayMode === "immersive" ? (
+
+
+
sendMessage(text, { forceVoiceResponse: true })}
+ onRealtimeTranscript={(event) => persistRealtimeTranscript(event, {
+ sessionKey: activeVoiceSessionKey,
+ storeKey: activeVoiceStoreKey,
+ setVisibleMessages: setMessages,
+ })}
+ isPlayingAudio={isPlayingAudio}
+ onInterrupt={interruptAudio}
+ isLoading={isLoading}
+ accentColor={resolvedVisualAccentColor}
+ autoActivate
+ immersive
+ isMicMuted={agentMicMuted}
+ isAgentMuted={agentAudioMuted}
+ onMicMutedChange={setAgentMicMuted}
+ onAgentMutedChange={handleAgentAudioMutedChange}
+ agent={selectedAgent?.callsign}
+ gatewayAgent={delegatedViaAgent?.callsign ?? selectedAgent?.callsign}
+ companyId={company?.id}
+ sessionKey={selectedSessionBelongsToAgent(selectedSessionKey, selectedAgent?.callsign)
+ ? selectedSessionKey ?? gatewaySessionKeyForAgent(selectedAgent)
+ : gatewaySessionKeyForAgent(selectedAgent)}
+ realtimeRuntimeId={selectedAgent?.runtimeId ?? undefined}
+ voiceSettings={resolvedVoiceSettings}
+ visualSettings={resolvedVisualSettings}
+ />
+
+
+
+
+
+ ) : null}
diff --git a/src/app/globals.css b/src/app/globals.css
index 1116e63..376268a 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -342,6 +342,7 @@ body { margin: 0; min-height: 100vh; background: radial-gradient(circle at top l
.voice-agent-visual-layer {
position: absolute;
inset: 0;
+ z-index: 1;
border-radius: 999px;
overflow: hidden;
}
@@ -354,7 +355,7 @@ body { margin: 0; min-height: 100vh; background: radial-gradient(circle at top l
.voice-visual-hologram,
.voice-visual-command {
position: absolute;
- inset: 4%;
+ inset: 2%;
border-radius: 999px;
pointer-events: none;
}
@@ -364,9 +365,9 @@ body { margin: 0; min-height: 100vh; background: radial-gradient(circle at top l
inset: 8%;
border-radius: 999px;
background:
- radial-gradient(circle, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.08 + var(--voice-volume, 0) * 0.12)) 0%, transparent 58%),
+ radial-gradient(circle, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.14 + var(--voice-volume, 0) * 0.18)) 0%, transparent 58%),
repeating-radial-gradient(circle, var(--voice-shell-grid-soft) 0 1px, transparent 1px 28px);
- opacity: calc(0.28 + var(--voice-motion, 0) * 0.3);
+ opacity: calc(0.48 + var(--voice-motion, 0) * 0.34);
filter: blur(0.2px);
animation: voice-agent-breathe calc(5.8s / var(--voice-intensity, 1)) ease-in-out infinite;
}
@@ -380,7 +381,7 @@ body { margin: 0; min-height: 100vh; background: radial-gradient(circle at top l
linear-gradient(24deg, transparent 18%, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.08 + var(--voice-motion, 0) * 0.18)) 18.5%, transparent 20% 46%, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.1 + var(--voice-volume, 0) * 0.16)) 47%, transparent 48.5%),
linear-gradient(144deg, transparent 24%, var(--voice-shell-grid) 25%, transparent 26% 62%, rgba(var(--voice-accent-rgb, 99, 183, 170), 0.18) 63%, transparent 64%),
linear-gradient(82deg, transparent 32%, var(--voice-shell-grid-soft) 33%, transparent 34% 72%, rgba(var(--voice-accent-rgb, 99, 183, 170), 0.12) 73%, transparent 74%);
- opacity: calc(0.38 + var(--voice-motion, 0) * 0.34);
+ opacity: calc(0.58 + var(--voice-motion, 0) * 0.36);
animation: voice-agent-drift calc(13s / var(--voice-intensity, 1)) ease-in-out infinite;
}
@@ -400,7 +401,7 @@ body { margin: 0; min-height: 100vh; background: radial-gradient(circle at top l
margin-left: calc(var(--node-size) / -2);
margin-top: calc(var(--node-size) / -2);
border-radius: 999px;
- background: rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.62 + var(--voice-motion, 0) * 0.32));
+ background: rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.78 + var(--voice-motion, 0) * 0.2));
box-shadow:
0 0 calc(8px + var(--voice-volume, 0) * 18px * var(--voice-intensity, 1)) rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.34 + var(--voice-motion, 0) * 0.34)),
0 0 1px var(--voice-shell-highlight);
@@ -408,7 +409,7 @@ body { margin: 0; min-height: 100vh; background: radial-gradient(circle at top l
rotate(var(--node-angle))
translateY(calc(-1 * var(--node-radius)))
scale(calc(0.84 + var(--voice-volume, 0) * 0.32 + var(--voice-motion, 0) * 0.38));
- opacity: calc(0.38 + var(--voice-volume, 0) * 0.22 + var(--voice-motion, 0) * 0.28);
+ opacity: calc(0.68 + var(--voice-volume, 0) * 0.16 + var(--voice-motion, 0) * 0.16);
animation: voice-neural-node calc(7s / var(--voice-intensity, 1)) ease-in-out infinite;
animation-delay: var(--node-delay);
}
@@ -416,7 +417,7 @@ body { margin: 0; min-height: 100vh; background: radial-gradient(circle at top l
.voice-visual-hologram {
inset: 14%;
overflow: hidden;
- border: 1px solid color-mix(in srgb, rgba(var(--voice-accent-rgb, 99, 183, 170), 0.24) 80%, transparent);
+ border: 1px solid rgba(var(--voice-accent-rgb, 99, 183, 170), 0.42);
background:
radial-gradient(ellipse at center, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.08 + var(--voice-volume, 0) * 0.1)), transparent 68%),
linear-gradient(180deg, transparent, color-mix(in srgb, var(--voice-shell-highlight) 16%, transparent), transparent);
@@ -435,7 +436,7 @@ body { margin: 0; min-height: 100vh; background: radial-gradient(circle at top l
radial-gradient(ellipse at 25% 50%, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.18 + var(--voice-volume, 0) * 0.22)), transparent 44%),
linear-gradient(90deg, transparent, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.12 + var(--voice-volume, 0) * 0.2)), transparent);
filter: blur(calc(var(--ribbon-index) * 0.35px));
- opacity: calc(0.24 + var(--voice-motion, 0) * 0.38);
+ opacity: calc(0.54 + var(--voice-motion, 0) * 0.38);
transform: translateY(-50%) skewX(-8deg) scaleX(calc(0.78 + var(--voice-motion, 0) * 0.18 + var(--ribbon-index) * 0.035));
animation: voice-hologram-ribbon calc(2.8s / var(--voice-intensity, 1)) ease-in-out infinite;
animation-delay: var(--ribbon-delay);
@@ -464,8 +465,8 @@ body { margin: 0; min-height: 100vh; background: radial-gradient(circle at top l
inset: 6%;
overflow: hidden;
background:
- radial-gradient(circle, transparent 0 41%, rgba(var(--voice-accent-rgb, 99, 183, 170), 0.08) 42% 43%, transparent 44%),
- conic-gradient(from 0deg, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.08 + var(--voice-motion, 0) * 0.16)), transparent 18%, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.1 + var(--voice-volume, 0) * 0.16)), transparent 52%, rgba(var(--voice-accent-rgb, 99, 183, 170), 0.08));
+ radial-gradient(circle, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.06 + var(--voice-volume, 0) * 0.1)) 0 40%, rgba(var(--voice-accent-rgb, 99, 183, 170), 0.18) 42% 43%, transparent 44%),
+ conic-gradient(from 0deg, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.18 + var(--voice-motion, 0) * 0.22)), transparent 18%, rgba(var(--voice-accent-rgb, 99, 183, 170), calc(0.2 + var(--voice-volume, 0) * 0.22)), transparent 52%, rgba(var(--voice-accent-rgb, 99, 183, 170), 0.18));
}
.voice-visual-command-grid {
@@ -477,7 +478,7 @@ body { margin: 0; min-height: 100vh; background: radial-gradient(circle at top l
linear-gradient(90deg, var(--voice-shell-grid-soft) 1px, transparent 1px);
background-size: 18px 18px;
mask-image: radial-gradient(circle, black 50%, transparent 74%);
- opacity: calc(0.18 + var(--voice-motion, 0) * 0.24);
+ opacity: calc(0.3 + var(--voice-motion, 0) * 0.34);
}
.voice-visual-command-ring {
diff --git a/src/components/chat/voice-agent.tsx b/src/components/chat/voice-agent.tsx
index adcf200..dbaa9df 100644
--- a/src/components/chat/voice-agent.tsx
+++ b/src/components/chat/voice-agent.tsx
@@ -1190,16 +1190,6 @@ export function VoiceAgent({
const listeningRgb = "var(--voice-listening-rgb)";
const speakingRgb = "var(--voice-speaking-rgb)";
const processingRgb = "var(--voice-processing-rgb)";
- const activeRgb =
- isMicMuted && !isPlayingAudio && !isLoading
- ? "var(--text-muted-rgb, 128, 128, 128)"
- : state === "listening"
- ? listeningRgb
- : state === "speaking"
- ? speakingRgb
- : state === "processing"
- ? processingRgb
- : accentRgb;
const stateColor =
isMicMuted && !isPlayingAudio && !isLoading
? "var(--text-tertiary)"
@@ -1212,7 +1202,14 @@ export function VoiceAgent({
: "var(--text-tertiary)";
const glowStrength = state === "idle" ? 0.16 : 0.28 + volumeLevel * 0.32;
const realtimeRelayActive = Boolean(realtimeRelayRef.current);
- const visualVolume = Math.min(1, volumeLevel * (nativeSessionActive || realtimeRelayActive ? 1.25 : 0.8));
+ const baseReactiveLevel = state === "speaking"
+ ? 0.36
+ : state === "listening"
+ ? 0.22
+ : state === "processing"
+ ? 0.28
+ : 0;
+ const visualVolume = Math.min(1, Math.max(baseReactiveLevel, volumeLevel * (nativeSessionActive || realtimeRelayActive ? 1.25 : 0.8)));
const motionLevel =
state === "speaking"
? Math.min(0.82, 0.24 + visualVolume * 0.78)
@@ -1257,7 +1254,7 @@ export function VoiceAgent({
haloSize={haloSize}
orbScale={orbScale}
glowStrength={glowStrength}
- activeRgb={activeRgb}
+ activeRgb={accentRgb}
listeningRgb={listeningRgb}
speakingRgb={speakingRgb}
processingRgb={processingRgb}