mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
fix thread history persistence
This commit is contained in:
parent
8c9eeaa133
commit
fb69afd5c4
5 changed files with 28 additions and 23 deletions
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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') ?? {}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
|
||||||
Loading…
Reference in a new issue