From 22d32aca3ac00f05fdecf3e255f54395acfe069d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aneta=20Jastrz=C4=99bska?= <1544710+anetaj@users.noreply.github.com> Date: Sat, 21 Sep 2024 18:05:25 +0200 Subject: [PATCH 01/12] save chat threads to workspace history --- extensions/void/src/extension.ts | 16 ++++++++++- extensions/void/src/shared_types.ts | 31 +++++++++++++++++++++ extensions/void/src/sidebar/getVscodeApi.ts | 5 +++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/extensions/void/src/extension.ts b/extensions/void/src/extension.ts index 4cd8ac26..953e89e4 100644 --- a/extensions/void/src/extension.ts +++ b/extensions/void/src/extension.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { WebviewMessage } from './shared_types'; +import { ChatThread, WebviewMessage } from './shared_types'; import { CtrlKCodeLensProvider } from './CtrlKCodeLensProvider'; import { getDiffedLines } from './getDiffedLines'; import { ApprovalCodeLensProvider, SuggestedEdit } from './ApprovalCodeLensProvider'; @@ -124,6 +124,20 @@ export function activate(context: vscode.ExtensionContext) { webview.postMessage({ type: 'apiConfig', apiConfig } satisfies WebviewMessage) } + else if (m.type === 'getThreadHistory') { + + const threads: ChatThread[] = context.workspaceState.get('threadHistory') ?? [] + webview.postMessage({ type: 'threadHistory', threads } satisfies WebviewMessage) + } + else if (m.type === 'updateThread') { + + const threads: ChatThread[] = context.workspaceState.get('threadHistory') as [] ?? [] + const updatedThreads = threads.find((t: ChatThread) => t.id === m.thread.id) + ? threads.map((t: ChatThread) => t.id === m.thread.id ? m.thread : t) + : [...threads, m.thread] + context.workspaceState.update('threadHistory', updatedThreads) + webview.postMessage({ type: 'threadHistory', threads: updatedThreads } satisfies WebviewMessage) + } else { console.error('unrecognized command', m.type, m) diff --git a/extensions/void/src/shared_types.ts b/extensions/void/src/shared_types.ts index 4d7c0dc9..563f3ec8 100644 --- a/extensions/void/src/shared_types.ts +++ b/extensions/void/src/shared_types.ts @@ -27,13 +27,44 @@ type WebviewMessage = ( // editor -> sidebar | { type: 'apiConfig', apiConfig: ApiConfig } + // sidebar -> editor + | { type: 'getThreadHistory' } + + // editor -> sidebar + | { type: 'threadHistory', threads: ChatThread[] } + + // sidebar -> editor + | { type: 'updateThread', thread: ChatThread } + ) type Command = WebviewMessage['type'] +type ChatThread = { + id: string; + createdAt: string; + messages: ChatMessage[]; +} + +type ChatMessage = + | { + role: "user"; + content: string; // content sent to the llm + displayContent: string; // content displayed to user + selection: Selection | null; // the user's selection + files: vscode.Uri[]; // the files sent in the message + } + | { + role: "assistant"; + content: string; // content received from LLM + displayContent: string; // content displayed to user (this is the same as content for now) + } + export { Selection, File, WebviewMessage, Command, + ChatThread, + ChatMessage, } diff --git a/extensions/void/src/sidebar/getVscodeApi.ts b/extensions/void/src/sidebar/getVscodeApi.ts index 890b31f2..126207c7 100644 --- a/extensions/void/src/sidebar/getVscodeApi.ts +++ b/extensions/void/src/sidebar/getVscodeApi.ts @@ -9,7 +9,10 @@ const awaiting: { [c in Command]: ((res: any) => void)[] } = { "requestFiles": [], "files": [], "apiConfig": [], - "getApiConfig": [] + "getApiConfig": [], + "getThreadHistory": [], + "threadHistory": [], + "updateThread": [], } // use this function to await responses From 3a98d1edb11fbdab8d1562f4d8ce797c592f7699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aneta=20Jastrz=C4=99bska?= <1544710+anetaj@users.noreply.github.com> Date: Sat, 21 Sep 2024 18:06:26 +0200 Subject: [PATCH 02/12] add chat context --- extensions/void/src/sidebar/context.tsx | 77 +++++++++++++++++++++++++ extensions/void/src/sidebar/index.tsx | 26 +++++---- 2 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 extensions/void/src/sidebar/context.tsx diff --git a/extensions/void/src/sidebar/context.tsx b/extensions/void/src/sidebar/context.tsx new file mode 100644 index 00000000..dabb836b --- /dev/null +++ b/extensions/void/src/sidebar/context.tsx @@ -0,0 +1,77 @@ +import React, { + ReactNode, + createContext, + useContext, + useEffect, + useState, +} from "react" +import * as vscode from "vscode" +import { ChatMessage, ChatThread, Selection } from "../shared_types" +import { getVSCodeAPI } from "./getVscodeApi" + +interface IChatProviderProps { + chatMessageHistory: ChatMessage[] + addMessageToHistory: (message: ChatMessage) => void + setPreviousThreads: (threads: any) => void +} + +const defaults = { + chatMessageHistory: [], + addMessageToHistory: () => {}, + setPreviousThreads: () => {}, + thread: { + id: "", + createdAt: "", + messages: [], + }, +} + +const ChatContext = createContext(defaults) + +function ChatProvider({ children }: { children: ReactNode }) { + const [previousThreads, setPreviousThreads] = useState([]) + const [thread, setThread] = useState(defaults.thread) + + useEffect(() => { + getVSCodeAPI().postMessage({ type: "getThreadHistory" }) + }, []) + + useEffect(() => { + if (thread.messages.length) { + getVSCodeAPI().postMessage({ type: "updateThread", thread }) + } + }, [thread]) + + const addMessageToHistory = (message: ChatMessage) => { + setThread((prev) => ({ + ...prev, + ...(!thread.id && { + id: new Date().getTime().toString(), + createdAt: new Date().toISOString(), + }), + messages: [...prev.messages, message], + })) + } + + return ( + + {children} + + ) +} + +function useChat(): IChatProviderProps { + const context = useContext(ChatContext) + if (context === undefined) { + throw new Error("useChat must be used within a ChatProvider") + } + return context +} + +export { ChatProvider, useChat } diff --git a/extensions/void/src/sidebar/index.tsx b/extensions/void/src/sidebar/index.tsx index cdd0ce57..8c754705 100644 --- a/extensions/void/src/sidebar/index.tsx +++ b/extensions/void/src/sidebar/index.tsx @@ -1,16 +1,20 @@ -import * as React from 'react' -import * as ReactDOM from 'react-dom/client' -import Sidebar from './Sidebar' +import * as React from "react" +import * as ReactDOM from "react-dom/client" +import Sidebar from "./Sidebar" +import { ChatProvider } from "./context" // mount the sidebar on the id="root" element -if (typeof document === 'undefined') { - console.log('index.tsx error: document was undefined') +if (typeof document === "undefined") { + console.log("index.tsx error: document was undefined") } -const rootElement = document.getElementById('root')! -console.log('root Element', rootElement) +const rootElement = document.getElementById("root")! +console.log("root Element", rootElement) + +const extension = ( + + + +) const root = ReactDOM.createRoot(rootElement) -root.render() - - - +root.render(extension) From c6dcb8eb9ed78178774749c8dfb9516f3d73c31e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aneta=20Jastrz=C4=99bska?= <1544710+anetaj@users.noreply.github.com> Date: Sat, 21 Sep 2024 18:07:07 +0200 Subject: [PATCH 03/12] add message to history & sync saved thread --- extensions/void/src/sidebar/Sidebar.tsx | 32 ++++++++++--------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/extensions/void/src/sidebar/Sidebar.tsx b/extensions/void/src/sidebar/Sidebar.tsx index d2ae76ed..ddcf658b 100644 --- a/extensions/void/src/sidebar/Sidebar.tsx +++ b/extensions/void/src/sidebar/Sidebar.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, useRef, useCallback, FormEvent } from "react" import { ApiConfig, sendLLMMessage } from "../common/sendLLMMessage" -import { File, Selection, WebviewMessage } from "../shared_types" +import { ChatMessage, File, Selection, WebviewMessage } from "../shared_types" import { awaitVSCodeResponse, getVSCodeAPI, resolveAwaitingVSCodeResponse } from "./getVscodeApi" import { marked } from 'marked'; @@ -8,6 +8,7 @@ import { MarkdownRender, BlockCode } from "./MarkdownRender"; import * as vscode from 'vscode' import { FilesSelector, IncludedFiles } from "./components/Files"; +import { useChat } from "./context"; const filesStr = (fullFiles: File[]) => { @@ -66,18 +67,6 @@ const ChatBubble = ({ chatMessage }: { chatMessage: ChatMessage }) => { } -type ChatMessage = { - role: 'user' - content: string, // content sent to the llm - displayContent: string, // content displayed to user - selection: Selection | null, // the user's selection - files: vscode.Uri[], // the files sent in the message -} | { - role: 'assistant', - content: string, // content received from LLM - displayContent: string // content displayed to user (this is the same as content for now) -} - // const [stateRef, setState] = useInstantState(initVal) // setState instantly changes the value of stateRef instead of having to wait until the next render @@ -94,6 +83,7 @@ const useInstantState = (initVal: T) => { const Sidebar = () => { + const { chatMessageHistory, addMessageToHistory, setPreviousThreads } = useChat() // state of current message const [selection, setSelection] = useState(null) // the code the user is selecting @@ -101,7 +91,6 @@ const Sidebar = () => { const [instructions, setInstructions] = useState('') // the user's instructions // state of chat - const [chatMessageHistory, setChatHistory] = useState([]) const [messageStream, setMessageStream] = useState('') const [isLoading, setIsLoading] = useState(false) @@ -139,10 +128,15 @@ const Sidebar = () => { setApiConfig(m.apiConfig) } + // when get apiConfig, set + else if (m.type === 'threadHistory') { + setPreviousThreads(m.threads) + } + } window.addEventListener('message', listener); return () => { window.removeEventListener('message', listener) } - }, [files, selection]) + }, [files, selection, setPreviousThreads]) const formRef = useRef(null) @@ -165,7 +159,7 @@ const Sidebar = () => { const content = userInstructionsStr(instructions, relevantFiles.files, selection) // console.log('prompt:\n', content) const newHistoryElt: ChatMessage = { role: 'user', content, displayContent: instructions, selection, files } - setChatHistory(chatMessageHistory => [...chatMessageHistory, newHistoryElt]) + addMessageToHistory(newHistoryElt) // send message to claude let { abort } = sendLLMMessage({ @@ -175,7 +169,7 @@ const Sidebar = () => { // add assistant's message to chat history const newHistoryElt: ChatMessage = { role: 'assistant', content, displayContent: content, } - setChatHistory(chatMessageHistory => [...chatMessageHistory, newHistoryElt]) + addMessageToHistory(newHistoryElt) // clear selection setMessageStream('') @@ -194,12 +188,12 @@ const Sidebar = () => { // if messageStream was not empty, add it to the history const llmContent = messageStream || '(canceled)' const newHistoryElt: ChatMessage = { role: 'assistant', displayContent: messageStream, content: llmContent } - setChatHistory(chatMessageHistory => [...chatMessageHistory, newHistoryElt]) + addMessageToHistory(newHistoryElt) setMessageStream('') setIsLoading(false) - }, [messageStream]) + }, [addMessageToHistory, messageStream]) //Clear code selection const clearSelection = () => { From 31cd10b9e66ac17554dd443bdf4b0b396074797d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aneta=20Jastrz=C4=99bska?= <1544710+anetaj@users.noreply.github.com> Date: Sat, 21 Sep 2024 19:19:16 +0200 Subject: [PATCH 04/12] handle receive threads history --- extensions/void/src/sidebar/Sidebar.tsx | 6 ++-- extensions/void/src/sidebar/context.tsx | 48 ++++++++++++++++++------- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/extensions/void/src/sidebar/Sidebar.tsx b/extensions/void/src/sidebar/Sidebar.tsx index ddcf658b..41b3836c 100644 --- a/extensions/void/src/sidebar/Sidebar.tsx +++ b/extensions/void/src/sidebar/Sidebar.tsx @@ -9,6 +9,7 @@ import { MarkdownRender, BlockCode } from "./MarkdownRender"; import * as vscode from 'vscode' import { FilesSelector, IncludedFiles } from "./components/Files"; import { useChat } from "./context"; +import ThreadHistory from "./components/ThreadHistory"; const filesStr = (fullFiles: File[]) => { @@ -83,7 +84,7 @@ const useInstantState = (initVal: T) => { const Sidebar = () => { - const { chatMessageHistory, addMessageToHistory, setPreviousThreads } = useChat() + const { chatMessageHistory, addMessageToHistory, setPreviousThreads, previousThreads } = useChat() // state of current message const [selection, setSelection] = useState(null) // the code the user is selecting @@ -128,7 +129,7 @@ const Sidebar = () => { setApiConfig(m.apiConfig) } - // when get apiConfig, set + // incoming thread history else if (m.type === 'threadHistory') { setPreviousThreads(m.threads) } @@ -268,6 +269,7 @@ const Sidebar = () => { } + {!!previousThreads.length && } diff --git a/extensions/void/src/sidebar/context.tsx b/extensions/void/src/sidebar/context.tsx index dabb836b..39cd0586 100644 --- a/extensions/void/src/sidebar/context.tsx +++ b/extensions/void/src/sidebar/context.tsx @@ -5,31 +5,45 @@ import React, { useEffect, useState, } from "react" -import * as vscode from "vscode" -import { ChatMessage, ChatThread, Selection } from "../shared_types" +import { ChatMessage, ChatThread } from "../shared_types" import { getVSCodeAPI } from "./getVscodeApi" +const createEmptyThread = () => ({ + id: "", + createdAt: "", + messages: [], +}) + +const createNewThread = () => ({ + id: new Date().getTime().toString(), + createdAt: new Date().toISOString(), + messages: [], +}) + interface IChatProviderProps { chatMessageHistory: ChatMessage[] addMessageToHistory: (message: ChatMessage) => void setPreviousThreads: (threads: any) => void + previousThreads: ChatThread[] + selectThread: (thread: ChatThread) => void } const defaults = { chatMessageHistory: [], addMessageToHistory: () => {}, setPreviousThreads: () => {}, - thread: { - id: "", - createdAt: "", - messages: [], - }, + // placeholder for thread until first message is sent so that createdAt date is accurate + thread: createEmptyThread(), + previousThreads: [], + selectThread: () => {}, } const ChatContext = createContext(defaults) function ChatProvider({ children }: { children: ReactNode }) { - const [previousThreads, setPreviousThreads] = useState([]) + const [previousThreads, setPreviousThreads] = useState( + defaults.previousThreads + ) const [thread, setThread] = useState(defaults.thread) useEffect(() => { @@ -45,20 +59,28 @@ function ChatProvider({ children }: { children: ReactNode }) { const addMessageToHistory = (message: ChatMessage) => { setThread((prev) => ({ ...prev, - ...(!thread.id && { - id: new Date().getTime().toString(), - createdAt: new Date().toISOString(), - }), + // if there is no thread, create a new one with current timestamp + ...(!thread.id && createNewThread()), messages: [...prev.messages, message], })) } + const handleReceiveThreadHistory = (threads: ChatThread[]) => + setPreviousThreads( + threads.sort( + (a, b) => + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() + ) + ) + return ( {children} From e54f49ebfb4d12fd52adc7efe852645a553c1f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aneta=20Jastrz=C4=99bska?= <1544710+anetaj@users.noreply.github.com> Date: Sat, 21 Sep 2024 19:19:26 +0200 Subject: [PATCH 05/12] threads history list --- .../src/sidebar/components/ThreadHistory.tsx | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 extensions/void/src/sidebar/components/ThreadHistory.tsx diff --git a/extensions/void/src/sidebar/components/ThreadHistory.tsx b/extensions/void/src/sidebar/components/ThreadHistory.tsx new file mode 100644 index 00000000..609c1d5d --- /dev/null +++ b/extensions/void/src/sidebar/components/ThreadHistory.tsx @@ -0,0 +1,27 @@ +import React from "react" +import { ChatThread } from "../../shared_types" +import { useChat } from "../context" + +const ThreadHistory = ({ + threads, +}: { + threads: ChatThread[] +}) => { + const { selectThread } = useChat() + + return ( +
+ {threads.map((thread) => ( + + ))} +
+ ) +} + +export default ThreadHistory From 083bbf7d9f3262c4917292596af0cf8236868b62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aneta=20Jastrz=C4=99bska?= <1544710+anetaj@users.noreply.github.com> Date: Sat, 21 Sep 2024 21:11:52 +0200 Subject: [PATCH 06/12] start new chat; toggle thread history --- extensions/void/src/sidebar/Sidebar.tsx | 21 +++++++++++++++++-- .../src/sidebar/components/ThreadHistory.tsx | 6 +----- extensions/void/src/sidebar/context.tsx | 5 ++++- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/extensions/void/src/sidebar/Sidebar.tsx b/extensions/void/src/sidebar/Sidebar.tsx index 41b3836c..0f7de288 100644 --- a/extensions/void/src/sidebar/Sidebar.tsx +++ b/extensions/void/src/sidebar/Sidebar.tsx @@ -84,7 +84,13 @@ const useInstantState = (initVal: T) => { const Sidebar = () => { - const { chatMessageHistory, addMessageToHistory, setPreviousThreads, previousThreads } = useChat() + const { + chatMessageHistory, + addMessageToHistory, + setPreviousThreads, + previousThreads, + startNewChat, + } = useChat() // state of current message const [selection, setSelection] = useState(null) // the code the user is selecting @@ -94,6 +100,7 @@ const Sidebar = () => { // state of chat const [messageStream, setMessageStream] = useState('') const [isLoading, setIsLoading] = useState(false) + const [showChatHistory, setShowChatHistory] = useState(false) const abortFnRef = useRef<(() => void) | null>(null) @@ -203,6 +210,17 @@ const Sidebar = () => { return <>
+
+
+ + {!!previousThreads.length && ( + + )} +
+ {showChatHistory && } +
{/* previous messages */} {chatMessageHistory.map((message, i) => @@ -269,7 +287,6 @@ const Sidebar = () => { }
- {!!previousThreads.length && }
diff --git a/extensions/void/src/sidebar/components/ThreadHistory.tsx b/extensions/void/src/sidebar/components/ThreadHistory.tsx index 609c1d5d..4e0d0300 100644 --- a/extensions/void/src/sidebar/components/ThreadHistory.tsx +++ b/extensions/void/src/sidebar/components/ThreadHistory.tsx @@ -2,11 +2,7 @@ import React from "react" import { ChatThread } from "../../shared_types" import { useChat } from "../context" -const ThreadHistory = ({ - threads, -}: { - threads: ChatThread[] -}) => { +const ThreadHistory = ({ threads }: { threads: ChatThread[] }) => { const { selectThread } = useChat() return ( diff --git a/extensions/void/src/sidebar/context.tsx b/extensions/void/src/sidebar/context.tsx index 39cd0586..6c2ab653 100644 --- a/extensions/void/src/sidebar/context.tsx +++ b/extensions/void/src/sidebar/context.tsx @@ -26,6 +26,7 @@ interface IChatProviderProps { setPreviousThreads: (threads: any) => void previousThreads: ChatThread[] selectThread: (thread: ChatThread) => void + startNewChat: () => void } const defaults = { @@ -36,6 +37,7 @@ const defaults = { thread: createEmptyThread(), previousThreads: [], selectThread: () => {}, + startNewChat: () => {}, } const ChatContext = createContext(defaults) @@ -59,7 +61,7 @@ function ChatProvider({ children }: { children: ReactNode }) { const addMessageToHistory = (message: ChatMessage) => { setThread((prev) => ({ ...prev, - // if there is no thread, create a new one with current timestamp + // replace placeholder thread with new thread if it's the first message ...(!thread.id && createNewThread()), messages: [...prev.messages, message], })) @@ -81,6 +83,7 @@ function ChatProvider({ children }: { children: ReactNode }) { setPreviousThreads: handleReceiveThreadHistory, previousThreads, selectThread: setThread, + startNewChat: () => setThread(createNewThread()), }} > {children} From 7269c4e5825284393df627bbe205c73d979a9a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aneta=20Jastrz=C4=99bska?= <1544710+anetaj@users.noreply.github.com> Date: Sat, 21 Sep 2024 21:19:36 +0200 Subject: [PATCH 07/12] show new thread button --- extensions/void/src/sidebar/Sidebar.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/void/src/sidebar/Sidebar.tsx b/extensions/void/src/sidebar/Sidebar.tsx index 0f7de288..df543a0c 100644 --- a/extensions/void/src/sidebar/Sidebar.tsx +++ b/extensions/void/src/sidebar/Sidebar.tsx @@ -100,7 +100,7 @@ const Sidebar = () => { // state of chat const [messageStream, setMessageStream] = useState('') const [isLoading, setIsLoading] = useState(false) - const [showChatHistory, setShowChatHistory] = useState(false) + const [showThreadsHistory, setShowThreadsHistory] = useState(false) const abortFnRef = useRef<(() => void) | null>(null) @@ -212,14 +212,14 @@ const Sidebar = () => {
- + {!!chatMessageHistory.length && } {!!previousThreads.length && ( - )}
- {showChatHistory && } + {showThreadsHistory && }
{/* previous messages */} From 30b528402c129cf7931f0ae202b82ac25c3d8004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aneta=20Jastrz=C4=99bska?= <1544710+anetaj@users.noreply.github.com> Date: Sun, 22 Sep 2024 11:03:42 +0200 Subject: [PATCH 08/12] add new toolbar + commands --- extensions/void/package.json | 26 +++++++++++++++++++++++++- extensions/void/src/extension.ts | 8 ++++++++ extensions/void/src/shared_types.ts | 6 ++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/extensions/void/package.json b/extensions/void/package.json index 1147f7e0..719bc480 100644 --- a/extensions/void/package.json +++ b/extensions/void/package.json @@ -63,6 +63,16 @@ { "command": "void.discardDiff", "title": "Discard Diff" + }, + { + "command": "void.newChat", + "title": "New chat", + "icon": "$(add)" + }, + { + "command": "void.prevChats", + "title": "Previous chats", + "icon": "$(history)" } ], "viewsContainers": { @@ -94,7 +104,21 @@ "key": "ctrl+k", "mac": "cmd+k" } - ] + ], + "menus": { + "view/title": [ + { + "command": "void.newChat", + "when": "view == 'void.viewnumberone'", + "group": "navigation" + }, + { + "command": "void.prevChats", + "when": "view == 'void.viewnumberone'", + "group": "navigation" + } + ] + } }, "scripts": { "vscode:prepublish": "npm run compile", diff --git a/extensions/void/src/extension.ts b/extensions/void/src/extension.ts index 953e89e4..0580058f 100644 --- a/extensions/void/src/extension.ts +++ b/extensions/void/src/extension.ts @@ -83,6 +83,14 @@ export function activate(context: vscode.ExtensionContext) { webviewProvider.webview.then( webview => { + // top navigation bar commands + context.subscriptions.push(vscode.commands.registerCommand('void.newChat', async () => { + webview.postMessage({ type: 'startNewChat' } satisfies WebviewMessage) + })) + context.subscriptions.push(vscode.commands.registerCommand('void.prevChats', async () => { + webview.postMessage({ type: 'showPreviousChats' } satisfies WebviewMessage) + })) + // when config changes, send it to the sidebar vscode.workspace.onDidChangeConfiguration(e => { if (e.affectsConfiguration('void')) { diff --git a/extensions/void/src/shared_types.ts b/extensions/void/src/shared_types.ts index 563f3ec8..6ea0790e 100644 --- a/extensions/void/src/shared_types.ts +++ b/extensions/void/src/shared_types.ts @@ -36,6 +36,12 @@ type WebviewMessage = ( // sidebar -> editor | { type: 'updateThread', thread: ChatThread } + // editor -> sidebar + | { type: 'startNewChat' } + + // editor -> sidebar + | { type: 'showPreviousChats' } + ) type Command = WebviewMessage['type'] From ff0dcd5095462ac5a482d9370287b728ad1f9ee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aneta=20Jastrz=C4=99bska?= <1544710+anetaj@users.noreply.github.com> Date: Sun, 22 Sep 2024 11:04:28 +0200 Subject: [PATCH 09/12] handle show thread history --- extensions/void/src/sidebar/Sidebar.tsx | 34 +++++++++-------- .../src/sidebar/components/ThreadHistory.tsx | 38 ++++++++++++++----- extensions/void/src/sidebar/context.tsx | 13 +++---- extensions/void/src/sidebar/getVscodeApi.ts | 2 + 4 files changed, 56 insertions(+), 31 deletions(-) diff --git a/extensions/void/src/sidebar/Sidebar.tsx b/extensions/void/src/sidebar/Sidebar.tsx index df543a0c..c36d3e88 100644 --- a/extensions/void/src/sidebar/Sidebar.tsx +++ b/extensions/void/src/sidebar/Sidebar.tsx @@ -85,10 +85,9 @@ const useInstantState = (initVal: T) => { const Sidebar = () => { const { - chatMessageHistory, + thread, addMessageToHistory, setPreviousThreads, - previousThreads, startNewChat, } = useChat() @@ -141,10 +140,21 @@ const Sidebar = () => { setPreviousThreads(m.threads) } + // top navigation bar command - new chat + else if (m.type === 'startNewChat') { + setShowThreadsHistory(false) + startNewChat() + } + + // top navigation bar command - new chat + else if (m.type === 'showPreviousChats') { + setShowThreadsHistory(true) + } + } window.addEventListener('message', listener); return () => { window.removeEventListener('message', listener) } - }, [files, selection, setPreviousThreads]) + }, [files, selection, setPreviousThreads, startNewChat]) const formRef = useRef(null) @@ -171,7 +181,7 @@ const Sidebar = () => { // send message to claude let { abort } = sendLLMMessage({ - messages: [...chatMessageHistory.map(m => ({ role: m.role, content: m.content })), { role: 'user', content }], + messages: [...thread.messages.map(m => ({ role: m.role, content: m.content })), { role: 'user', content }], onText: (newText, fullText) => setMessageStream(fullText), onFinalMessage: (content) => { @@ -210,20 +220,14 @@ const Sidebar = () => { return <>
-
-
- {!!chatMessageHistory.length && } - {!!previousThreads.length && ( - - )} + {showThreadsHistory && ( +
+ setShowThreadsHistory(false)} />
- {showThreadsHistory && } -
+ )}
{/* previous messages */} - {chatMessageHistory.map((message, i) => + {thread.messages.map((message, i) => )} {/* message stream */} diff --git a/extensions/void/src/sidebar/components/ThreadHistory.tsx b/extensions/void/src/sidebar/components/ThreadHistory.tsx index 4e0d0300..0994ae22 100644 --- a/extensions/void/src/sidebar/components/ThreadHistory.tsx +++ b/extensions/void/src/sidebar/components/ThreadHistory.tsx @@ -1,19 +1,39 @@ import React from "react" -import { ChatThread } from "../../shared_types" import { useChat } from "../context" +import { classNames } from "../utils" -const ThreadHistory = ({ threads }: { threads: ChatThread[] }) => { - const { selectThread } = useChat() +const ThreadHistory = ({ onClose }: { onClose: () => void }) => { + const { selectThread, previousThreads, thread } = useChat() return ( -
- {threads.map((thread) => ( +
+
+ +
+ {previousThreads.map((prevThread) => ( ))}
diff --git a/extensions/void/src/sidebar/context.tsx b/extensions/void/src/sidebar/context.tsx index 6c2ab653..c294423d 100644 --- a/extensions/void/src/sidebar/context.tsx +++ b/extensions/void/src/sidebar/context.tsx @@ -9,9 +9,9 @@ import { ChatMessage, ChatThread } from "../shared_types" import { getVSCodeAPI } from "./getVscodeApi" const createEmptyThread = () => ({ - id: "", - createdAt: "", - messages: [], + id: "", + createdAt: "", + messages: [], }) const createNewThread = () => ({ @@ -21,7 +21,7 @@ const createNewThread = () => ({ }) interface IChatProviderProps { - chatMessageHistory: ChatMessage[] + thread: ChatThread addMessageToHistory: (message: ChatMessage) => void setPreviousThreads: (threads: any) => void previousThreads: ChatThread[] @@ -30,10 +30,9 @@ interface IChatProviderProps { } const defaults = { - chatMessageHistory: [], addMessageToHistory: () => {}, setPreviousThreads: () => {}, - // placeholder for thread until first message is sent so that createdAt date is accurate + // placeholder for thread until first message is sent so that createdAt date is accurate thread: createEmptyThread(), previousThreads: [], selectThread: () => {}, @@ -78,7 +77,7 @@ function ChatProvider({ children }: { children: ReactNode }) { return ( void)[] } = { "getThreadHistory": [], "threadHistory": [], "updateThread": [], + "startNewChat": [], + "showPreviousChats": [], } // use this function to await responses From 251b65d04ddda7e518368a8c39cb3c2561b2cb88 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 11 Oct 2024 16:35:33 -0700 Subject: [PATCH 10/12] finish merge --- extensions/void/README.md | 3 + extensions/void/package.json | 12 +- extensions/void/src/extension.ts | 29 +-- extensions/void/src/shared_types.ts | 38 ++-- .../src/sidebar/MarkdownRender/BlockCode.tsx | 7 +- extensions/void/src/sidebar/Sidebar.tsx | 206 ++++++++++-------- .../src/sidebar/components/ThreadHistory.tsx | 43 ---- extensions/void/src/sidebar/context.tsx | 102 ++++----- extensions/void/src/sidebar/getVscodeApi.ts | 10 +- .../void/src/sidebar/utils/classNames.ts | 3 - extensions/void/src/sidebar/utils/index.ts | 1 - 11 files changed, 200 insertions(+), 254 deletions(-) delete mode 100644 extensions/void/src/sidebar/components/ThreadHistory.tsx delete mode 100644 extensions/void/src/sidebar/utils/classNames.ts delete mode 100644 extensions/void/src/sidebar/utils/index.ts diff --git a/extensions/void/README.md b/extensions/void/README.md index fd4840c4..d455ba30 100644 --- a/extensions/void/README.md +++ b/extensions/void/README.md @@ -6,3 +6,6 @@ Here's an overview on how the extension works: - The extension mounts in `extension.ts`. - The Sidebar's HTML (everything in `sidebar/`) is built in React, and it's rendered by mounting a `