Skip to content

Commit

Permalink
feat(vscode): support store chat session state.
Browse files Browse the repository at this point in the history
  • Loading branch information
icycodes committed Jan 16, 2025
1 parent 8fc3a79 commit 82a1873
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 18 deletions.
4 changes: 1 addition & 3 deletions clients/vscode/src/chat/chatPanel.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { window, ExtensionContext, ViewColumn } from "vscode";
import { v4 as uuid } from "uuid";
import { ChatWebview } from "./webview";
import type { Client } from "../lsp/Client";
import type { GitProvider } from "../git/GitProvider";

export async function createChatPanel(context: ExtensionContext, client: Client, gitProvider: GitProvider) {
const id = uuid();
const panel = window.createWebviewPanel(`tabby.chat.panel-${id}`, "Tabby", ViewColumn.One, {
const panel = window.createWebviewPanel(`tabby.chat.panel`, "Tabby", ViewColumn.One, {
retainContextWhenHidden: true,
});

Expand Down
2 changes: 2 additions & 0 deletions clients/vscode/src/chat/createClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export function createClient(webview: Webview, api: ClientApiMethods): ServerApi
openExternal: api.openExternal,
readWorkspaceGitRepositories: api.readWorkspaceGitRepositories,
getActiveEditorSelection: api.getActiveEditorSelection,
fetchSessionState: api.fetchSessionState,
storeSessionState: api.storeSessionState,
},
});
}
13 changes: 5 additions & 8 deletions clients/vscode/src/chat/html/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,18 @@ <h4 class="title">Welcome to Tabby Chat!</h4>
chatIframe.style.display = "block";
};

const checkFocused = () => {
vscode.postMessage({
action: "checkFocusedResult",
focused: document.hasFocus(),
});
};

window.addEventListener("message", (event) => {
if (event.data) {
if (event.data.action === "dispatchKeyboardEvent") {
window.dispatchEvent(new KeyboardEvent(event.data.type, event.data.event));
} else if (event.data.action === "showChatPanel") {
showChatIframe();
} else if (event.data.action === "checkFocused") {
checkFocused();
vscode.postMessage({
id: event.data.id,
action: "jsCallback",
args: [document.hasFocus()],
});
} else if (event.data.action === "postMessageToChatPanel") {
chatIframe.contentWindow.postMessage(event.data.message, "*");
} else {
Expand Down
42 changes: 35 additions & 7 deletions clients/vscode/src/chat/webview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type {
EditorFileContext,
} from "tabby-chat-panel";
import * as semver from "semver";
import { v4 as uuid } from "uuid";
import type { StatusInfo, Config } from "tabby-agent";
import type { GitProvider } from "../git/GitProvider";
import type { Client as LspClient } from "../lsp/Client";
Expand Down Expand Up @@ -70,8 +71,11 @@ export class ChatWebview {
// A number to ensure the html is reloaded when assigned a new value
private reloadCount = 0;

// A callback list for `isFocused` method
private pendingFocusCheckCallbacks: ((focused: boolean) => void)[] = [];
// A callback list for invoke javascript function by postMessage
private pendingCallbacks = new Map<string, (...arg: unknown[]) => void>();

// Store the chat state to be reload when webview is reloaded
private sessionState: Record<string, unknown> = {};

constructor(
private readonly context: ExtensionContext,
Expand Down Expand Up @@ -135,9 +139,9 @@ export class ChatWebview {
this.client?.updateTheme(event.style, this.getColorThemeString());
return;
}
case "checkFocusedResult": {
this.pendingFocusCheckCallbacks.forEach((cb) => cb(event.focused));
this.pendingFocusCheckCallbacks = [];
case "jsCallback": {
this.pendingCallbacks.get(event.id)?.(...event.args);
this.pendingCallbacks.delete(event.id);
return;
}
}
Expand All @@ -164,8 +168,11 @@ export class ChatWebview {
return false;
}
return new Promise((resolve) => {
webview.postMessage({ action: "checkFocused" });
this.pendingFocusCheckCallbacks.push(resolve);
const id = uuid();
this.pendingCallbacks.set(id, (...args) => {
resolve(args[0] as boolean);
});
webview.postMessage({ id, action: "checkFocused" });
});
}

Expand Down Expand Up @@ -464,6 +471,27 @@ export class ChatWebview {
const fileContext = await getFileContextFromSelection(editor, this.gitProvider);
return fileContext;
},

fetchSessionState: async (keys?: string[] | undefined): Promise<Record<string, unknown> | null> => {
if (!keys) {
return { ...this.sessionState };
}

const filtered: Record<string, unknown> = {};
for (const key of keys) {
if (key in this.sessionState) {
filtered[key] = this.sessionState[key];
}
}
return filtered;
},

storeSessionState: async (state: Record<string, unknown>) => {
this.sessionState = {
...this.sessionState,
...state,
};
},
});
}

Expand Down

0 comments on commit 82a1873

Please sign in to comment.