From dc54555158597c59cef4b4f85b6519effabf77b1 Mon Sep 17 00:00:00 2001 From: Jon Saad-Falcon <41205309+jonsaadfalcon@users.noreply.github.com> Date: Sat, 14 Mar 2026 12:54:59 -0700 Subject: [PATCH] feat: emit log entries from chat streaming and model operations --- frontend/src/components/Chat/InputArea.tsx | 22 ++++++++++++++++++++++ frontend/src/components/CommandPalette.tsx | 12 ++++++++++++ 2 files changed, 34 insertions(+) diff --git a/frontend/src/components/Chat/InputArea.tsx b/frontend/src/components/Chat/InputArea.tsx index 1f77b171..fbab01e8 100644 --- a/frontend/src/components/Chat/InputArea.tsx +++ b/frontend/src/components/Chat/InputArea.tsx @@ -137,6 +137,12 @@ export function InputArea() { activeToolCalls: [], content: '', }); + useAppStore.getState().addLogEntry({ + timestamp: Date.now(), + level: 'info', + category: 'chat', + message: `Request: "${content.slice(0, 80)}${content.length > 80 ? '...' : ''}" → ${selectedModel}`, + }); try { for await (const sseEvent of streamChat( @@ -149,6 +155,10 @@ export function InputArea() { setStreamState({ phase: 'Agent thinking...' }); } else if (eventName === 'inference_start') { setStreamState({ phase: 'Generating...' }); + useAppStore.getState().addLogEntry({ + timestamp: Date.now(), level: 'info', category: 'chat', + message: `Generating with ${selectedModel}...`, + }); } else if (eventName === 'tool_call_start') { try { const data = JSON.parse(sseEvent.data); @@ -164,6 +174,10 @@ export function InputArea() { activeToolCalls: [...toolCalls], }); updateLastAssistant(convId, accumulatedContent, [...toolCalls]); + useAppStore.getState().addLogEntry({ + timestamp: Date.now(), level: 'info', category: 'tool', + message: `Calling ${data.tool}(${data.arguments || ''})`, + }); } catch {} } else if (eventName === 'tool_call_end') { try { @@ -213,6 +227,10 @@ export function InputArea() { const errMsg = err?.message || String(err); accumulatedContent = accumulatedContent || `Error: ${errMsg}`; + useAppStore.getState().addLogEntry({ + timestamp: Date.now(), level: 'error', category: 'chat', + message: `Stream error: ${errMsg}`, + }); } } finally { if (!accumulatedContent) { @@ -229,6 +247,10 @@ export function InputArea() { timerRef.current = null; } resetStream(); + useAppStore.getState().addLogEntry({ + timestamp: Date.now(), level: 'info', category: 'chat', + message: `Response: ${accumulatedContent.length} chars`, + }); abortRef.current = null; fetchSavings() diff --git a/frontend/src/components/CommandPalette.tsx b/frontend/src/components/CommandPalette.tsx index 2a7a32cf..d85d67fa 100644 --- a/frontend/src/components/CommandPalette.tsx +++ b/frontend/src/components/CommandPalette.tsx @@ -99,11 +99,19 @@ export function CommandPalette() { try { await pullModel(modelId); setPullSuccess(modelId); + useAppStore.getState().addLogEntry({ + timestamp: Date.now(), level: 'info', category: 'model', + message: `Downloaded ${modelId}`, + }); await refreshModels(); // Auto-select the newly pulled model setSelectedModel(modelId); } catch (e: any) { setPullError(e.message || 'Download failed'); + useAppStore.getState().addLogEntry({ + timestamp: Date.now(), level: 'error', category: 'model', + message: `Download failed for ${modelId}: ${e.message}`, + }); } finally { setPulling(null); } @@ -114,6 +122,10 @@ export function CommandPalette() { setDeleting(modelId); try { await deleteModel(modelId); + useAppStore.getState().addLogEntry({ + timestamp: Date.now(), level: 'info', category: 'model', + message: `Deleted ${modelId}`, + }); await refreshModels(); if (selectedModel === modelId) { const remaining = models.filter((m) => m.id !== modelId);