fix: chat history persistence and webview state restoration
This commit is contained in:
@@ -1,3 +1,12 @@
|
|||||||
|
# Patch Notes - v2.33.6 (2026-05-01)
|
||||||
|
|
||||||
|
## 🛠️ Critical Bug Fixes
|
||||||
|
- **Chat Persistence Overhaul:** Resolved an issue where chat history disappeared after switching sidebar tabs.
|
||||||
|
- **Webview State Management:** Implemented `vscode.setState` for instant UI restoration.
|
||||||
|
- **Internal Message Logic:** Refined message filtering to ensure intermediate agent steps are visible to the user.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Patch Notes - v2.33.5 (2026-05-01)
|
# Patch Notes - v2.33.5 (2026-05-01)
|
||||||
|
|
||||||
## 🎨 UI Refinement
|
## 🎨 UI Refinement
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
"name": "g1nation",
|
"name": "g1nation",
|
||||||
"displayName": "G1nation",
|
"displayName": "G1nation",
|
||||||
"description": "High-performance autonomous local AI coding agent for VS Code. Features vectorized inference, asynchronous task management, and 100% offline processing.",
|
"description": "High-performance autonomous local AI coding agent for VS Code. Features vectorized inference, asynchronous task management, and 100% offline processing.",
|
||||||
"version": "2.33.5",
|
"version": "2.33.6",
|
||||||
"publisher": "connectailab",
|
"publisher": "connectailab",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"icon": "assets/icon.png",
|
"icon": "assets/icon.png",
|
||||||
|
|||||||
+2
-3
@@ -119,7 +119,7 @@ export class AgentExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getHistory() {
|
public getHistory() {
|
||||||
return this.chatHistory.filter(message => !message.internal);
|
return this.chatHistory.filter(message => !message.internal || message.role === 'assistant');
|
||||||
}
|
}
|
||||||
|
|
||||||
public setHistory(history: ChatMessage[]) {
|
public setHistory(history: ChatMessage[]) {
|
||||||
@@ -394,7 +394,7 @@ export class AgentExecutor {
|
|||||||
|
|
||||||
// 5. Execute Actions
|
// 5. Execute Actions
|
||||||
const rationale = this.parseRationale(aiResponseText);
|
const rationale = this.parseRationale(aiResponseText);
|
||||||
const assistantMessage: ChatMessage = { role: 'assistant', content: aiResponseText, internal: true, rationale };
|
const assistantMessage: ChatMessage = { role: 'assistant', content: aiResponseText, internal: false, rationale };
|
||||||
this.chatHistory.push(assistantMessage);
|
this.chatHistory.push(assistantMessage);
|
||||||
|
|
||||||
this.statusBarManager.updateStatus(AgentStatus.Executing);
|
this.statusBarManager.updateStatus(AgentStatus.Executing);
|
||||||
@@ -443,7 +443,6 @@ export class AgentExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assistantMessage.internal = false;
|
|
||||||
this.emitHistoryChanged();
|
this.emitHistoryChanged();
|
||||||
this.statusBarManager.updateStatus(AgentStatus.Success);
|
this.statusBarManager.updateStatus(AgentStatus.Success);
|
||||||
this.webview.postMessage({ type: 'streamChunk', value: aiResponseText });
|
this.webview.postMessage({ type: 'streamChunk', value: aiResponseText });
|
||||||
|
|||||||
+45
-10
@@ -200,7 +200,9 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
|||||||
if (!this._view) return;
|
if (!this._view) return;
|
||||||
|
|
||||||
const blankChatActive = this._context.globalState.get<boolean>(SidebarChatProvider.blankChatStateKey, false);
|
const blankChatActive = this._context.globalState.get<boolean>(SidebarChatProvider.blankChatStateKey, false);
|
||||||
if (blankChatActive) {
|
const currentHistory = this._agent.getHistory();
|
||||||
|
|
||||||
|
if (blankChatActive && currentHistory.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +214,6 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
|||||||
await this._context.globalState.update(SidebarChatProvider.activeSessionStateKey, null);
|
await this._context.globalState.update(SidebarChatProvider.activeSessionStateKey, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentHistory = this._agent.getHistory();
|
|
||||||
if (currentHistory.length > 0) {
|
if (currentHistory.length > 0) {
|
||||||
this._view.webview.postMessage({ type: 'restoreHistory', value: currentHistory });
|
this._view.webview.postMessage({ type: 'restoreHistory', value: currentHistory });
|
||||||
await this._persistLastVisibleChat(currentHistory);
|
await this._persistLastVisibleChat(currentHistory);
|
||||||
@@ -1893,6 +1894,29 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
|||||||
const vscode = acquireVsCodeApi();
|
const vscode = acquireVsCodeApi();
|
||||||
const chat = document.getElementById('chat');
|
const chat = document.getElementById('chat');
|
||||||
const input = document.getElementById('input');
|
const input = document.getElementById('input');
|
||||||
|
|
||||||
|
// [State Persistence - Tier 0] 즉시 복원 (Instant Restore from WebView State)
|
||||||
|
const previousState = vscode.getState();
|
||||||
|
if (previousState && previousState.history && previousState.history.length > 0) {
|
||||||
|
console.log('[G1nation] Restoring from Webview State...');
|
||||||
|
renderHistory(previousState.history);
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveWebviewState(history) {
|
||||||
|
vscode.setState({ history });
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderHistory(history) {
|
||||||
|
if (!history || history.length === 0) return;
|
||||||
|
chat.innerHTML = '';
|
||||||
|
history.forEach(m => {
|
||||||
|
if (!m) return;
|
||||||
|
// Only skip truly internal system messages, keep assistant thoughts
|
||||||
|
if (m.role === 'system' && m.internal) return;
|
||||||
|
addMsg(m.content, m.role === 'assistant' ? 'assistant' : 'user', m.rationale);
|
||||||
|
});
|
||||||
|
chat.scrollTop = chat.scrollHeight;
|
||||||
|
}
|
||||||
const sendBtn = document.getElementById('sendBtn');
|
const sendBtn = document.getElementById('sendBtn');
|
||||||
const stopBtn = document.getElementById('stopBtn');
|
const stopBtn = document.getElementById('stopBtn');
|
||||||
const cancelBtn = document.getElementById('cancelBtn');
|
const cancelBtn = document.getElementById('cancelBtn');
|
||||||
@@ -2112,6 +2136,10 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
|||||||
switch(msg.type) {
|
switch(msg.type) {
|
||||||
case 'addMessage':
|
case 'addMessage':
|
||||||
addMsg(msg.value, msg.role, msg.rationale);
|
addMsg(msg.value, msg.role, msg.rationale);
|
||||||
|
// Update state for non-streamed messages
|
||||||
|
const s = vscode.getState() || { history: [] };
|
||||||
|
s.history.push({ role: msg.role === 'assistant' ? 'assistant' : 'user', content: msg.value, rationale: msg.rationale });
|
||||||
|
saveWebviewState(s.history);
|
||||||
break;
|
break;
|
||||||
case 'streamStart':
|
case 'streamStart':
|
||||||
thinkingBar.classList.remove('active');
|
thinkingBar.classList.remove('active');
|
||||||
@@ -2128,9 +2156,15 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'streamEnd':
|
case 'streamEnd':
|
||||||
if (streamBody) streamBody.classList.remove('stream-active');
|
if (streamBody) {
|
||||||
|
streamBody.classList.remove('stream-active');
|
||||||
|
// Update state after stream finishes
|
||||||
|
const state = vscode.getState() || { history: [] };
|
||||||
|
state.history.push({ role: 'assistant', content: streamBody._parent._raw });
|
||||||
|
saveWebviewState(state.history);
|
||||||
|
}
|
||||||
streamBody = null;
|
streamBody = null;
|
||||||
// \uc0dd\uc131 \uc644\ub8cc \uc2dc Stop \ubc84\ud2bc \uc228\uae30\uace0 Send \ubcf5\uad50
|
// 생성 완료 시 Stop 버튼 숨기고 Send 복구
|
||||||
setGenerating(false);
|
setGenerating(false);
|
||||||
resetStepper();
|
resetStepper();
|
||||||
Sound.success();
|
Sound.success();
|
||||||
@@ -2143,12 +2177,8 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
|||||||
: (Array.isArray(historyPayload?.history) ? historyPayload.history : []);
|
: (Array.isArray(historyPayload?.history) ? historyPayload.history : []);
|
||||||
|
|
||||||
if (history && history.length > 0) {
|
if (history && history.length > 0) {
|
||||||
chat.innerHTML = '';
|
renderHistory(history);
|
||||||
history.forEach(m => {
|
saveWebviewState(history);
|
||||||
if (!m || m.internal) return;
|
|
||||||
addMsg(m.content, m.role === 'assistant' ? 'assistant' : 'user', m.rationale);
|
|
||||||
});
|
|
||||||
chat.scrollTop = chat.scrollHeight;
|
|
||||||
}
|
}
|
||||||
if (historyPayload?.negativePrompt !== undefined) {
|
if (historyPayload?.negativePrompt !== undefined) {
|
||||||
negativePrompt.value = historyPayload.negativePrompt;
|
negativePrompt.value = historyPayload.negativePrompt;
|
||||||
@@ -2358,6 +2388,11 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
|||||||
setDraftActive(false);
|
setDraftActive(false);
|
||||||
setGenerating(true);
|
setGenerating(true);
|
||||||
thinkingBar.classList.add('active');
|
thinkingBar.classList.add('active');
|
||||||
|
|
||||||
|
// Save state after sending
|
||||||
|
const currentState = vscode.getState() || { history: [] };
|
||||||
|
currentState.history.push({ role: 'user', content: val });
|
||||||
|
saveWebviewState(currentState.history);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendBtn.onclick = send;
|
sendBtn.onclick = send;
|
||||||
|
|||||||
Reference in New Issue
Block a user