From 45efef442a85d801ac0b8b22381f0a4594e416cb Mon Sep 17 00:00:00 2001 From: Variet Date: Sun, 8 Mar 2026 00:48:55 +0900 Subject: [PATCH] feat(realtime): live trajectory refresh on step_changed, auto-scroll to bottom, debounced 2s --- public/js/app.js | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/public/js/app.js b/public/js/app.js index 7be96ba..e4e3a1f 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -144,7 +144,10 @@ if (session) { chatPanel.showSession({ name: session.name, status: session.isRunning ? 'running' : 'connected' }); } - // trajectory에서 전체 대화 내용 가져오기 + await refreshTrajectory(sessionId); + } + + async function refreshTrajectory(sessionId, scrollToBottom = true) { try { const res = await fetch(`/api/bridge/trajectory/${sessionId}`); if (!res.ok) return; @@ -152,12 +155,26 @@ if (data.trajectory?.steps) { const messages = parseTrajectoryToMessages(data.trajectory.steps); chatPanel.updateChat(messages); + if (scrollToBottom) { + const el = document.getElementById('chatMessages'); + if (el) setTimeout(() => el.scrollTop = el.scrollHeight, 50); + } } } catch (e) { console.warn('[Bridge] trajectory 로드 실패:', e); } } + // 실시간 갱신 디바운스 + let refreshTimer = null; + function scheduleRefresh() { + if (refreshTimer) return; + refreshTimer = setTimeout(() => { + refreshTimer = null; + if (activeBridgeSession) refreshTrajectory(activeBridgeSession, false); + }, 2000); // 2초 디바운스 + } + /** * Trajectory 스텝을 Antigravity 스타일 대화 흐름으로 변환 * @@ -301,7 +318,15 @@ break; case 'bridge_event': - handleBridgeEvent(msg); + // Bridge WS 이벤트 처리 + if (msg.step_changed || msg.type === 'step_changed') { + scheduleRefresh(); + loadBridgeSessions(); // 세션 목록도 갱신 (stepCount 등) + } else if (msg.type === 'session_changed' || msg.type === 'new_conversation') { + loadBridgeSessions(); + } else if (msg.type === 'state_changed') { + scheduleRefresh(); + } break; case 'screenshot':