fix thread history persistence

This commit is contained in:
Andrew 2024-10-14 18:07:16 -07:00
parent 8c9eeaa133
commit fb69afd5c4
5 changed files with 28 additions and 23 deletions

View file

@ -20,6 +20,7 @@ export class SidebarWebviewProvider implements vscode.WebviewViewProvider {
private readonly _extensionUri: vscode.Uri private readonly _extensionUri: vscode.Uri
private _webviewView?: vscode.WebviewView; // only used inside onDidChangeConfiguration private _webviewView?: vscode.WebviewView; // only used inside onDidChangeConfiguration
private _webviewDeps: string[] = [];
constructor(context: vscode.ExtensionContext) { constructor(context: vscode.ExtensionContext) {
// const extensionPath = context.extensionPath // the directory where the extension is installed, might be useful later... was included in webviewProvider code // const extensionPath = context.extensionPath // the directory where the extension is installed, might be useful later... was included in webviewProvider code
@ -30,8 +31,10 @@ export class SidebarWebviewProvider implements vscode.WebviewViewProvider {
if (!temp_res) throw new Error("sidebar provider: resolver was undefined") if (!temp_res) throw new Error("sidebar provider: resolver was undefined")
this._res = temp_res this._res = temp_res
// if it affects one of the config items webview depends on, update the webview
// TODO should be able to move this entirely to React - make updateWebviewHTML mount once, and then send updates via postMessage from then on
vscode.workspace.onDidChangeConfiguration(event => { vscode.workspace.onDidChangeConfiguration(event => {
if (event.affectsConfiguration('void.ollama.endpoint')) { if (this._webviewDeps.map(dep => event.affectsConfiguration(dep)).some(v => !!v)) {
if (this._webviewView) { if (this._webviewView) {
this.updateWebviewHTML(this._webviewView.webview); this.updateWebviewHTML(this._webviewView.webview);
} }
@ -39,12 +42,18 @@ export class SidebarWebviewProvider implements vscode.WebviewViewProvider {
}); });
} }
// this is updated
private updateWebviewHTML(webview: vscode.Webview) { private updateWebviewHTML(webview: vscode.Webview) {
const allowed_urls = ['https://api.anthropic.com', 'https://api.openai.com', 'https://api.greptile.com']; const allowed_urls = ['https://api.anthropic.com', 'https://api.openai.com', 'https://api.greptile.com'];
this._webviewDeps = []
const ollamaEndpoint: string | undefined = vscode.workspace.getConfiguration('void.ollama').get('endpoint'); const ollamaEndpoint: string | undefined = vscode.workspace.getConfiguration('void.ollama').get('endpoint');
this._webviewDeps.push('void.ollama.endpoint');
if (ollamaEndpoint) if (ollamaEndpoint)
allowed_urls.push(ollamaEndpoint); allowed_urls.push(ollamaEndpoint);
const openAICompatibleEndpoint: string | undefined = vscode.workspace.getConfiguration('void.openAICompatible').get('endpoint'); const openAICompatibleEndpoint: string | undefined = vscode.workspace.getConfiguration('void.openAICompatible').get('endpoint');
this._webviewDeps.push('void.openAICompatible.endpoint');
if (openAICompatibleEndpoint) if (openAICompatibleEndpoint)
allowed_urls.push(openAICompatibleEndpoint); allowed_urls.push(openAICompatibleEndpoint);

View file

@ -143,13 +143,8 @@ export function activate(context: vscode.ExtensionContext) {
await approvalCodeLensProvider.addNewApprovals(editor, suggestedEdits) await approvalCodeLensProvider.addNewApprovals(editor, suggestedEdits)
} }
else if (m.type === 'getApiConfig') { else if (m.type === 'getApiConfig') {
context.workspaceState.update('allThreads', {})
const apiConfig = getApiConfig() const apiConfig = getApiConfig()
console.log('Api config:', apiConfig)
webview.postMessage({ type: 'apiConfig', apiConfig } satisfies WebviewMessage) webview.postMessage({ type: 'apiConfig', apiConfig } satisfies WebviewMessage)
} }
else if (m.type === 'getAllThreads') { else if (m.type === 'getAllThreads') {
const threads: ChatThreads = context.workspaceState.get('allThreads') ?? {} const threads: ChatThreads = context.workspaceState.get('allThreads') ?? {}

View file

@ -9,7 +9,7 @@ import BlockCode from "./markdown/BlockCode";
import * as vscode from 'vscode' import * as vscode from 'vscode'
import { SelectedFiles } from "./components/SelectedFiles"; import { SelectedFiles } from "./components/SelectedFiles";
import { useChat } from "./chatContext"; import { useThreads } from "./threadsContext";
const filesStr = (fullFiles: File[]) => { const filesStr = (fullFiles: File[]) => {
@ -69,7 +69,7 @@ const ChatBubble = ({ chatMessage }: { chatMessage: ChatMessage }) => {
} }
const ThreadSelector = ({ onClose }: { onClose: () => void }) => { const ThreadSelector = ({ onClose }: { onClose: () => void }) => {
const { allThreads, currentThread, switchToThread } = useChat() const { allThreads, currentThread, switchToThread } = useThreads()
return ( return (
<div className="flex flex-col space-y-1"> <div className="flex flex-col space-y-1">
<div className="text-right"> <div className="text-right">
@ -109,7 +109,7 @@ const ThreadSelector = ({ onClose }: { onClose: () => void }) => {
const Sidebar = () => { const Sidebar = () => {
const { allThreads, currentThread, addMessageToHistory, startNewThread, } = useChat() const { allThreads, currentThread, addMessageToHistory, startNewThread, } = useThreads()
// state of current message // state of current message
const [selection, setSelection] = useState<Selection | null>(null) // the code the user is selecting const [selection, setSelection] = useState<Selection | null>(null) // the code the user is selecting

View file

@ -1,7 +1,7 @@
import * as React from "react" import * as React from "react"
import * as ReactDOM from "react-dom/client" import * as ReactDOM from "react-dom/client"
import Sidebar from "./Sidebar" import Sidebar from "./Sidebar"
import { ChatProvider } from "./chatContext" import { ThreadsProvider } from "./threadsContext"
// mount the sidebar on the id="root" element // mount the sidebar on the id="root" element
if (typeof document === "undefined") { if (typeof document === "undefined") {
@ -9,12 +9,12 @@ if (typeof document === "undefined") {
} }
const rootElement = document.getElementById("root")! const rootElement = document.getElementById("root")!
console.log("root Element", rootElement) console.log("Void root Element:", rootElement)
const extension = ( const extension = (
<ChatProvider> <ThreadsProvider>
<Sidebar /> <Sidebar />
</ChatProvider> </ThreadsProvider>
) )
const root = ReactDOM.createRoot(rootElement) const root = ReactDOM.createRoot(rootElement)
root.render(extension) root.render(extension)

View file

@ -3,7 +3,7 @@ import { ChatMessage, ChatThreads } from "../shared_types"
import { awaitVSCodeResponse, getVSCodeAPI } from "./getVscodeApi" import { awaitVSCodeResponse, getVSCodeAPI } from "./getVscodeApi"
type ChatContextValue = { type ThreadsContextValue = {
readonly allThreads: ChatThreads | null, readonly allThreads: ChatThreads | null,
readonly currentThread: ChatThreads[string] | null; readonly currentThread: ChatThreads[string] | null;
addMessageToHistory: (message: ChatMessage) => void; addMessageToHistory: (message: ChatMessage) => void;
@ -11,7 +11,7 @@ type ChatContextValue = {
startNewThread: () => void; startNewThread: () => void;
} }
const ChatContext = createContext<ChatContextValue>({} as ChatContextValue) const ThreadsContext = createContext<ThreadsContextValue>(undefined as unknown as ThreadsContextValue)
const createNewThread = () => ({ const createNewThread = () => ({
id: new Date().getTime().toString(), id: new Date().getTime().toString(),
@ -33,7 +33,7 @@ const useInstantState = <T,>(initVal: T) => {
} }
function ChatProvider({ children }: { children: ReactNode }) { export function ThreadsProvider({ children }: { children: ReactNode }) {
const [allThreads, setAllThreads] = useInstantState<ChatThreads>({}) const [allThreads, setAllThreads] = useInstantState<ChatThreads>({})
const [currentThreadId, setCurrentThreadId] = useInstantState<string | null>(null) const [currentThreadId, setCurrentThreadId] = useInstantState<string | null>(null)
@ -41,12 +41,14 @@ function ChatProvider({ children }: { children: ReactNode }) {
useEffect(() => { useEffect(() => {
getVSCodeAPI().postMessage({ type: "getAllThreads" }) getVSCodeAPI().postMessage({ type: "getAllThreads" })
awaitVSCodeResponse('allThreads') awaitVSCodeResponse('allThreads')
.then(response => { setAllThreads(response.threads) }) .then(response => {
setAllThreads(response.threads)
})
}, [setAllThreads]) }, [setAllThreads])
return ( return (
<ChatContext.Provider <ThreadsContext.Provider
value={{ value={{
allThreads: allThreads.current, allThreads: allThreads.current,
currentThread: currentThreadId.current === null || allThreads.current === null ? null : allThreads.current[currentThreadId.current], currentThread: currentThreadId.current === null || allThreads.current === null ? null : allThreads.current[currentThreadId.current],
@ -84,16 +86,15 @@ function ChatProvider({ children }: { children: ReactNode }) {
}} }}
> >
{children} {children}
</ChatContext.Provider> </ThreadsContext.Provider>
) )
} }
function useChat(): ChatContextValue { export function useThreads(): ThreadsContextValue {
const context = useContext<ChatContextValue>(ChatContext) const context = useContext<ThreadsContextValue>(ThreadsContext)
if (context === undefined) { if (context === undefined) {
throw new Error("useChat must be used within a ChatProvider") throw new Error("useThreads must be used within a ThreadsProvider")
} }
return context return context
} }
export { ChatProvider, useChat }