Skip to content

Commit 9a0a215

Browse files
committed
diag: add on-screen debug log panel to call UI
Adds a small "show log" toggle button in the top-right corner of the call screen (both active-call and start-call states). Tapping it reveals a scrollable panel showing every ElevenLabs event in real time: ✅ CONNECTED 🔄 MODE → speaking 💬 AI: "Thank you for calling..." ❌ DISCONNECTED reason=agent uptimeMs=3241 closeCode=... closeReason="..." 🔴 ERROR: "..." ctx=... This makes it possible to see exactly what the agent says and why it disconnects without opening browser devtools. https://claude.ai/code/session_01SGdxNUC1TVMDtW73TZbxjW
1 parent 7dbab1f commit 9a0a215

File tree

1 file changed

+74
-27
lines changed

1 file changed

+74
-27
lines changed

src/components/DemoCall/UserPhoneInterface.tsx

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ export default function UserPhoneInterface({
3838
const [isEnding, setIsEnding] = useState(false);
3939
const [connectionError, setConnectionError] = useState<string | null>(null);
4040

41+
// ─── ON-SCREEN DEBUG LOG ───────────────────────────────────────────────────
42+
const [debugLogs, setDebugLogs] = useState<string[]>([]);
43+
const [showDebug, setShowDebug] = useState(false);
44+
const addLog = useCallback((msg: string) => {
45+
const ts = new Date().toTimeString().slice(0, 8);
46+
const line = `[${ts}] ${msg}`;
47+
console.log('📞 [DIAG]', line);
48+
setDebugLogs(prev => [...prev.slice(-49), line]); // keep last 50
49+
}, []);
50+
// ──────────────────────────────────────────────────────────────────────────
51+
4152
const timerRef = useRef<NodeJS.Timeout | null>(null);
4253

4354
// Tracks when the WebSocket connected so we can log the live-to-dead delta.
@@ -54,26 +65,23 @@ export default function UserPhoneInterface({
5465
// re-initialising on every render, which can reset the active WebSocket.
5566
const onConnect = useCallback(() => {
5667
connectTimeRef.current = Date.now();
57-
console.log('📞 [DIAG] ElevenLabs connected at', new Date().toISOString());
68+
addLog('✅ CONNECTED');
5869
setConnectionError(null);
5970
setAgentStatus('listening');
60-
}, []);
71+
}, [addLog]);
6172

6273
const onDisconnect = useCallback((details?: DisconnectionDetails) => {
6374
const uptime = connectTimeRef.current !== null
6475
? Date.now() - connectTimeRef.current
6576
: null;
6677
connectTimeRef.current = null;
6778

68-
// ─── DIAGNOSTIC: log every field so we can identify the root cause ───
69-
console.log('📞 [DIAG] ElevenLabs disconnected', {
70-
reason: details?.reason ?? '(none)',
71-
message: (details as { message?: string })?.message,
72-
closeCode: (details as { closeCode?: number })?.closeCode,
73-
closeReason: (details as { closeReason?: string })?.closeReason,
74-
uptimeMs: uptime,
75-
timestamp: new Date().toISOString(),
76-
});
79+
const reason = details?.reason ?? '(none)';
80+
const closeCode = (details as { closeCode?: number })?.closeCode ?? '';
81+
const closeReason = (details as { closeReason?: string })?.closeReason ?? '';
82+
const errMsg = (details as { message?: string })?.message ?? '';
83+
84+
addLog(`❌ DISCONNECTED reason=${reason} uptimeMs=${uptime ?? '?'} closeCode=${closeCode} closeReason="${closeReason}" errMsg="${errMsg}"`);
7785

7886
setAgentStatus('idle');
7987

@@ -82,10 +90,10 @@ export default function UserPhoneInterface({
8290
if (details?.reason !== 'user') {
8391
endCall();
8492
}
85-
}, [endCall]);
93+
}, [endCall, addLog]);
8694

8795
const onMessage = useCallback((message: { source: string; message: string }) => {
88-
console.log(`📞 [${message.source}]: ${message.message}`);
96+
addLog(`💬 ${message.source.toUpperCase()}: "${message.message}"`);
8997
if (message.source === 'user') {
9098
setCurrentTranscript(message.message);
9199
addMessage('user', message.message);
@@ -96,28 +104,24 @@ export default function UserPhoneInterface({
96104
addMessage('agent', message.message);
97105
onTranscript?.(message.message, 'agent');
98106
}
99-
}, [addMessage, onTranscript]);
107+
}, [addMessage, onTranscript, addLog]);
100108

101109
const onError = useCallback((message: string, context?: unknown) => {
102-
// ─── DIAGNOSTIC: log message AND the context object (closeCode, etc.) ───
103-
console.error('📞 [DIAG] ElevenLabs error:', message, context);
104-
try {
105-
console.error('📞 [DIAG] ElevenLabs error context (JSON):', JSON.stringify(context, null, 2));
106-
} catch {
107-
// context may not be serialisable (e.g. native Event)
108-
}
110+
let ctxStr = '';
111+
try { ctxStr = JSON.stringify(context); } catch { ctxStr = String(context); }
112+
addLog(`🔴 ERROR: "${message}" ctx=${ctxStr}`);
109113
setConnectionError(message ?? 'Connection error');
110-
}, []);
114+
}, [addLog]);
111115

112116
const onModeChange = useCallback((modeEvent: { mode: string }) => {
113-
console.log('📞 [DIAG] Mode change →', modeEvent.mode, 'at', new Date().toISOString());
117+
addLog(`🔄 MODE → ${modeEvent.mode}`);
114118
if (modeEvent.mode === 'speaking') {
115119
setAgentStatus('speaking');
116120
setCurrentTranscript('');
117121
} else if (modeEvent.mode === 'listening') {
118122
setAgentStatus('listening');
119123
}
120-
}, []);
124+
}, [addLog]);
121125

122126
// ElevenLabs Conversational AI — handles STT + LLM + TTS in one WebSocket
123127
const conversation = useConversation({
@@ -189,16 +193,19 @@ export default function UserPhoneInterface({
189193
}
190194

191195
startCall('voice');
196+
addLog('🟡 Fetching signed URL…');
192197

193198
try {
194199
const signedUrl = await getSignedUrl();
200+
addLog(`🟡 Got signed URL, starting session…`);
195201
await conversation.startSession({ signedUrl });
196202
} catch (error) {
197-
console.error('📞 Failed to start ElevenLabs session:', error);
198-
setConnectionError(error instanceof Error ? error.message : 'Failed to connect');
203+
const msg = error instanceof Error ? error.message : String(error);
204+
addLog(`🔴 startSession failed: ${msg}`);
205+
setConnectionError(msg || 'Failed to connect');
199206
setAgentStatus('idle');
200207
}
201-
}, [startCall, getSignedUrl, conversation]);
208+
}, [startCall, getSignedUrl, conversation, addLog]);
202209

203210
const handleEndCall = useCallback(async () => {
204211
console.log('🔴 End call button pressed');
@@ -395,6 +402,26 @@ export default function UserPhoneInterface({
395402
</div>
396403
</div>
397404

405+
{/* ── On-screen debug log ── */}
406+
<div className="absolute top-4 right-4 z-30 text-left">
407+
<button
408+
onClick={() => setShowDebug(v => !v)}
409+
className="text-[10px] font-mono px-2 py-1 rounded bg-white/10 text-white/50 hover:bg-white/20"
410+
>
411+
{showDebug ? 'hide log' : 'show log'}
412+
</button>
413+
{showDebug && (
414+
<div className="mt-1 w-80 max-h-52 overflow-y-auto rounded-xl bg-black/80 border border-white/10 p-2">
415+
{debugLogs.length === 0
416+
? <p className="text-white/30 text-[10px] font-mono">No events yet.</p>
417+
: debugLogs.map((l, i) => (
418+
<p key={i} className="text-[10px] font-mono text-white/70 leading-relaxed break-all">{l}</p>
419+
))
420+
}
421+
</div>
422+
)}
423+
</div>
424+
398425
{/* Bottom Controls */}
399426
<div className="p-8 pb-[max(2rem,env(safe-area-inset-bottom))] w-full z-20 bg-gradient-to-t from-black via-black/80 to-transparent">
400427
<div className="flex items-center justify-center gap-6 max-w-lg mx-auto">
@@ -455,6 +482,26 @@ export default function UserPhoneInterface({
455482
</div>
456483
)}
457484

485+
{/* ── On-screen debug log ── */}
486+
<div className="absolute top-4 right-4 z-30 text-left">
487+
<button
488+
onClick={() => setShowDebug(v => !v)}
489+
className="text-[10px] font-mono px-2 py-1 rounded bg-white/10 text-white/50 hover:bg-white/20"
490+
>
491+
{showDebug ? 'hide log' : 'show log'}
492+
</button>
493+
{showDebug && (
494+
<div className="mt-1 w-80 max-h-52 overflow-y-auto rounded-xl bg-black/80 border border-white/10 p-2">
495+
{debugLogs.length === 0
496+
? <p className="text-white/30 text-[10px] font-mono">No events yet.</p>
497+
: debugLogs.map((l, i) => (
498+
<p key={i} className="text-[10px] font-mono text-white/70 leading-relaxed break-all">{l}</p>
499+
))
500+
}
501+
</div>
502+
)}
503+
</div>
504+
458505
{/* Main Content Area */}
459506
<div className="flex-1 flex flex-col items-center justify-center relative px-6 z-10 w-full max-w-[92vw] sm:max-w-lg mx-auto">
460507
{/* Avatar */}

0 commit comments

Comments
 (0)