import * as vscode from 'vscode'; import * as path from 'path'; import { SidebarChatProvider } from '../sidebarProvider'; import { getActiveBrainProfile, logInfo } from '../utils'; import { pickConfigTarget } from '../lib/paths'; /** * Handles chat-domain messages: prompts, model selection, sessions, streaming control, * generic webview transport (export, settings, addMessage), action approvals, and the * cross-cutting `ready` bootstrap. * * Returns true when the message was handled by this domain, false otherwise — the * caller chains domain handlers until one accepts the message. */ export async function handleChatMessage(provider: SidebarChatProvider, data: any): Promise { switch (data.type) { case 'prompt': case 'promptWithFile': provider._lmStudio?.activity.bump(); await provider._context.globalState.update(SidebarChatProvider.blankChatStateKey, false); await provider._handlePrompt(data); await provider._autoWriteChronicleAfterPrompt(); await provider._saveCurrentSession(); return true; case 'activity': provider._lmStudio?.activity.bump(); return true; case 'ready': await provider._sendBrainStatus(); await provider._sendBrainProfiles(); await provider._sendSessionList(); await provider._sendModels(); await provider._sendChronicleProjects(); await provider._restoreActiveSessionIntoView(); await provider._sendReadyStatus(); return true; case 'getReadyStatus': await provider._sendReadyStatus(); return true; case 'createLessonFromConversation': await vscode.commands.executeCommand('g1nation.lesson.fromConversation'); return true; case 'manageLessons': await vscode.commands.executeCommand('g1nation.lesson.manage'); return true; case 'getModels': await provider._sendModels(); return true; case 'getSessions': await provider._sendSessionList(); return true; case 'newChat': provider._currentSessionId = null; provider._currentSessionBrainId = getActiveBrainProfile().id; provider._agent.resetConversation(); await provider._context.globalState.update(SidebarChatProvider.activeSessionStateKey, null); await provider._context.globalState.update(SidebarChatProvider.lastVisibleChatStateKey, null); await provider._context.globalState.update(SidebarChatProvider.blankChatStateKey, true); provider.clearChat(); await provider._sendBrainStatus(); return true; case 'stopGeneration': provider._agent.stop(); return true; case 'loadSession': await provider._loadSession(data.id); return true; case 'deleteSession': await provider._deleteSession(data.id); return true; case 'openSettings': // Route the sidebar gear button to Astra's own settings webview. // Falls back to VS Code Settings if the view hasn't registered yet // (e.g. during the very first activation pass) and surfaces any // unexpected error so the user isn't stuck with a silent button. try { await vscode.commands.executeCommand('g1nation.settings.focus'); } catch (e: any) { logInfo('openSettings: settings.focus failed, falling back to VS Code Settings.', { error: e?.message ?? String(e) }); try { await vscode.commands.executeCommand('workbench.action.openSettings', 'g1nation'); } catch (e2: any) { vscode.window.showErrorMessage(`Astra Settings 열기 실패: ${e2?.message ?? e2}`); } } return true; case 'addMessage': provider._view?.webview.postMessage({ type: 'addMessage', role: data.role, value: data.value, rationale: data.rationale }); return true; case 'refreshModels': await provider._sendModels(true); return true; case 'model': { // Write to whichever scope already holds the value so a stale // Workspace override doesn't shadow our Global update — that was // the "sidebar shows e2b but Settings shows e4b" desync. const { target } = pickConfigTarget('g1nation', 'defaultModel'); await vscode.workspace.getConfiguration('g1nation').update('defaultModel', data.value, target); logInfo(`Default model updated to: ${data.value}`, { target }); provider._lmStudio?.lifecycle.onModelSelected(data.value); return true; } case 'proactiveTrigger': await provider._handleProactiveSuggestion(data.context); return true; case 'exportResponse': { const workspacePath = vscode.workspace.workspaceFolders?.[0].uri.fsPath || ''; const defaultPath = path.join(workspacePath, 'g1_response.md'); const uri = await vscode.window.showSaveDialog({ defaultUri: vscode.Uri.file(defaultPath), filters: { 'Markdown': ['md'] } }); if (uri) { await vscode.workspace.fs.writeFile(uri, Buffer.from(data.text, 'utf8')); vscode.window.showInformationMessage(`✅ Exported to ${path.basename(uri.fsPath)}`); } return true; } case 'approveAction': await provider._agent.approveTransaction(); return true; case 'rejectAction': await provider._agent.rejectTransaction(); return true; default: return false; } }