From e517cc02163ec42fe265f95dbe32cb6976429e90 Mon Sep 17 00:00:00 2001 From: Ivan Pegashev Date: Fri, 10 May 2024 07:14:59 +0300 Subject: [PATCH 1/4] feat(chat): make chat general available --- package.json | 3 +- src/common/panel/chat.ts | 22 ++++++++++ webviews/src/hooks/useSettings.ts | 0 webviews/src/index.tsx | 15 ++++--- webviews/src/routes/chatsHistory/index.tsx | 5 ++- webviews/src/routes/init/index.tsx | 3 ++ webviews/src/routes/requireInit/index.tsx | 16 ++++++++ webviews/src/routes/root/index.tsx | 47 ++++++++++++++++++++++ webviews/src/routes/root/root.tsx | 24 ----------- webviews/src/utilities/vscode.ts | 18 +++++++++ 10 files changed, 120 insertions(+), 33 deletions(-) create mode 100644 webviews/src/hooks/useSettings.ts create mode 100644 webviews/src/routes/init/index.tsx create mode 100644 webviews/src/routes/requireInit/index.tsx create mode 100644 webviews/src/routes/root/index.tsx delete mode 100644 webviews/src/routes/root/root.tsx diff --git a/package.json b/package.json index c2989ea..6ae7200 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,7 @@ "type": "webview", "id": "firecoder.chat-gui", "name": "", - "visibility": "visible", - "when": "config.firecoder.experimental.chat || config.firecoder.cloud.use" + "visibility": "visible" } ] }, diff --git a/src/common/panel/chat.ts b/src/common/panel/chat.ts index 68b9464..d2706bf 100644 --- a/src/common/panel/chat.ts +++ b/src/common/panel/chat.ts @@ -5,6 +5,7 @@ import { getNonce } from "../utils/getNonce"; import { chat } from "../chat"; import { Chat, ChatMessage } from "../prompt/promptChat"; import { state } from "../utils/state"; +import { configuration } from "../utils/configuration"; export type MessageType = | { @@ -29,6 +30,9 @@ type MessageToExtention = type: "abort-generate"; id: string; } + | { + type: "get-settings"; + } | { type: "get-chat"; chatId: string; @@ -173,6 +177,11 @@ export class ChatPanel implements vscode.WebviewViewProvider { id: message.id, }); break; + case "get-settings": + await this.handleGetSettings({ + id: message.id, + }); + break; default: break; } @@ -213,6 +222,19 @@ export class ChatPanel implements vscode.WebviewViewProvider { sendResponse("", true); } + private async handleGetSettings({ id }: { id: string }) { + const enable = configuration.get("experimental.chat"); + + await this.postMessage({ + type: "e2w-response", + id: id, + data: { + chatEnable: enable, + }, + done: true, + }); + } + private async handleGetChat({ chatId, id }: { chatId: string; id: string }) { const sendResponse = (messageToResponse: Chat | null, done: boolean) => { this.postMessage({ diff --git a/webviews/src/hooks/useSettings.ts b/webviews/src/hooks/useSettings.ts new file mode 100644 index 0000000..e69de29 diff --git a/webviews/src/index.tsx b/webviews/src/index.tsx index f637539..4ef5f4c 100644 --- a/webviews/src/index.tsx +++ b/webviews/src/index.tsx @@ -2,29 +2,34 @@ import React from "react"; import ReactDOM from "react-dom"; import { createMemoryRouter, RouterProvider } from "react-router-dom"; import "./index.css"; -import Root from "./routes/root/root"; +import Root, { loader as RootLoader } from "./routes/root"; import { ChatInstance } from "./routes/chat"; import ChatsHistory, { loader as ChatsHistoryLoader, } from "./routes/chatsHistory"; +import Init from "./routes/init"; const router = createMemoryRouter( [ { - path: "/", element: , + loader: RootLoader, children: [ { - path: "chats", + path: "/init", + element: , + }, + { + path: "/chats", element: , loader: ChatsHistoryLoader, }, { - path: "chats/new-chat", + path: "/chats/new-chat", element: , }, { - path: "chats/:chatId", + path: "/chats/:chatId", element: , }, ], diff --git a/webviews/src/routes/chatsHistory/index.tsx b/webviews/src/routes/chatsHistory/index.tsx index 103e97e..63e0536 100644 --- a/webviews/src/routes/chatsHistory/index.tsx +++ b/webviews/src/routes/chatsHistory/index.tsx @@ -1,5 +1,4 @@ import { useLoaderData, useNavigate } from "react-router-dom"; -import { Chat } from "../../hooks/useChat"; import { vscode } from "../../utilities/vscode"; import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import styles from "./style.module.css"; @@ -9,8 +8,10 @@ export async function loader() { return chats; } +type LoaderReturn = Awaited>; + const ChatsHistory = () => { - const chats = useLoaderData() as Chat[]; + const chats = useLoaderData() as LoaderReturn; const navigate = useNavigate(); diff --git a/webviews/src/routes/init/index.tsx b/webviews/src/routes/init/index.tsx new file mode 100644 index 0000000..eba6dd6 --- /dev/null +++ b/webviews/src/routes/init/index.tsx @@ -0,0 +1,3 @@ +export default function Init() { + return
Init Screen
; +} diff --git a/webviews/src/routes/requireInit/index.tsx b/webviews/src/routes/requireInit/index.tsx new file mode 100644 index 0000000..18ce429 --- /dev/null +++ b/webviews/src/routes/requireInit/index.tsx @@ -0,0 +1,16 @@ +import { Navigate, useLocation } from "react-router-dom"; + +export function RequireInit({ children }: { children: JSX.Element }) { + let auth = useAuth(); + let location = useLocation(); + + if (!auth.user) { + // Redirect them to the /login page, but save the current location they were + // trying to go to when they were redirected. This allows us to send them + // along to that page after they login, which is a nicer user experience + // than dropping them off on the home page. + return ; + } + + return children; +} diff --git a/webviews/src/routes/root/index.tsx b/webviews/src/routes/root/index.tsx new file mode 100644 index 0000000..5a4c4fe --- /dev/null +++ b/webviews/src/routes/root/index.tsx @@ -0,0 +1,47 @@ +import { useEffect } from "react"; +import { + Outlet, + useLoaderData, + useLocation, + useNavigate, +} from "react-router-dom"; +import { useMessageListener } from "../../hooks/messageListener"; +import { vscode } from "../../utilities/vscode"; + +export async function loader() { + const settings = await vscode.getSettings(); + return settings; +} + +type LoaderReturn = Awaited>; + +export default function Root() { + const settings = useLoaderData() as LoaderReturn; + + let location = useLocation(); + + useEffect(() => { + console.log(location); + }, [location]); + + const navigate = useNavigate(); + + useMessageListener("start-new-chat", () => { + console.log("callback start-new-chat"); + navigate("/chats/new-chat"); + }); + + useEffect(() => { + if (!settings.chatEnable) { + navigate("/init"); + } + }, [settings, navigate]); + + console.log(settings); + + return ( + <> + + + ); +} diff --git a/webviews/src/routes/root/root.tsx b/webviews/src/routes/root/root.tsx deleted file mode 100644 index 2fe169c..0000000 --- a/webviews/src/routes/root/root.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { useEffect } from "react"; -import { Outlet, useLocation, useNavigate } from "react-router-dom"; -import { useMessageListener } from "../../hooks/messageListener"; - -export default function Root() { - let location = useLocation(); - - useEffect(() => { - console.log(location); - }, [location]); - - const navigate = useNavigate(); - - useMessageListener("start-new-chat", () => { - console.log("callback start-new-chat"); - navigate("/chats/new-chat"); - }); - - return ( - <> - - - ); -} diff --git a/webviews/src/utilities/vscode.ts b/webviews/src/utilities/vscode.ts index 7b63b47..be13ce3 100644 --- a/webviews/src/utilities/vscode.ts +++ b/webviews/src/utilities/vscode.ts @@ -26,6 +26,9 @@ type MessageToExtention = type: "abort-generate"; id: string; } + | { + type: "get-settings"; + } | { type: "get-chat"; chatId: string; @@ -154,6 +157,21 @@ class VSCodeAPIWrapper { }); } + public getSettings() { + return new Promise<{ + chatEnable: boolean; + }>((resolve) => { + this.postMessageCallback( + { + type: "get-settings", + }, + (message) => { + resolve(message.data); + } + ); + }); + } + public saveChatHistory(chatId: string, history: Chat) { return new Promise((resolve) => { this.postMessageCallback( From 1a1eee55d7a2844777bbae3c8b379d6c91836795 Mon Sep 17 00:00:00 2001 From: gespispace Date: Sat, 11 May 2024 11:55:14 +0300 Subject: [PATCH 2/4] update --- webviews/src/hooks/useSettings.ts | 0 webviews/src/hooks/useSettings.tsx | 42 +++++++++++++++++++++++ webviews/src/index.tsx | 34 +++++++++++------- webviews/src/routes/requireInit/index.tsx | 18 ++++------ webviews/src/routes/root/index.tsx | 25 +------------- 5 files changed, 71 insertions(+), 48 deletions(-) delete mode 100644 webviews/src/hooks/useSettings.ts create mode 100644 webviews/src/hooks/useSettings.tsx diff --git a/webviews/src/hooks/useSettings.ts b/webviews/src/hooks/useSettings.ts deleted file mode 100644 index e69de29..0000000 diff --git a/webviews/src/hooks/useSettings.tsx b/webviews/src/hooks/useSettings.tsx new file mode 100644 index 0000000..1f2145e --- /dev/null +++ b/webviews/src/hooks/useSettings.tsx @@ -0,0 +1,42 @@ +import { createContext, useContext, useEffect, useMemo, useState } from "react"; +import { vscode } from "../utilities/vscode"; + +type ConfigurationType = { + chatEnabled: boolean; +}; + +interface SettingsContextType { + configuration: ConfigurationType; +} + +const SettingsContext = createContext(null!); + +export const SettingsProvider = ({ + children, +}: { + children: React.ReactNode; +}) => { + const [configuration, setConfiguration] = useState(null!); + + useEffect(() => { + const getSettings = async () => { + const settings = await vscode.getSettings(); + setConfiguration({ + chatEnabled: settings.chatEnable, + }); + }; + getSettings(); + }, []); + + const value = useMemo(() => ({ configuration }), [configuration]); + + return ( + + {children} + + ); +}; + +export const useSettings = () => { + return useContext(SettingsContext); +}; diff --git a/webviews/src/index.tsx b/webviews/src/index.tsx index 4ef5f4c..ae560c6 100644 --- a/webviews/src/index.tsx +++ b/webviews/src/index.tsx @@ -2,18 +2,19 @@ import React from "react"; import ReactDOM from "react-dom"; import { createMemoryRouter, RouterProvider } from "react-router-dom"; import "./index.css"; -import Root, { loader as RootLoader } from "./routes/root"; +import Root from "./routes/root"; import { ChatInstance } from "./routes/chat"; import ChatsHistory, { loader as ChatsHistoryLoader, } from "./routes/chatsHistory"; import Init from "./routes/init"; +import { SettingsProvider } from "./hooks/useSettings"; +import { RequireInit } from "./routes/requireInit"; const router = createMemoryRouter( [ { element: , - loader: RootLoader, children: [ { path: "/init", @@ -21,16 +22,21 @@ const router = createMemoryRouter( }, { path: "/chats", - element: , - loader: ChatsHistoryLoader, - }, - { - path: "/chats/new-chat", - element: , - }, - { - path: "/chats/:chatId", - element: , + element: , + children: [ + { + element: , + loader: ChatsHistoryLoader, + }, + { + path: "/chats/new-chat", + element: , + }, + { + path: "/chats/:chatId", + element: , + }, + ], }, ], }, @@ -42,7 +48,9 @@ const router = createMemoryRouter( ReactDOM.render( - + + + , document.getElementById("root") ); diff --git a/webviews/src/routes/requireInit/index.tsx b/webviews/src/routes/requireInit/index.tsx index 18ce429..4f34b77 100644 --- a/webviews/src/routes/requireInit/index.tsx +++ b/webviews/src/routes/requireInit/index.tsx @@ -1,16 +1,12 @@ -import { Navigate, useLocation } from "react-router-dom"; +import { Navigate, Outlet } from "react-router-dom"; +import { useSettings } from "../../hooks/useSettings"; -export function RequireInit({ children }: { children: JSX.Element }) { - let auth = useAuth(); - let location = useLocation(); +export function RequireInit() { + let settings = useSettings(); - if (!auth.user) { - // Redirect them to the /login page, but save the current location they were - // trying to go to when they were redirected. This allows us to send them - // along to that page after they login, which is a nicer user experience - // than dropping them off on the home page. - return ; + if (!settings.configuration.chatEnabled) { + return ; } - return children; + return ; } diff --git a/webviews/src/routes/root/index.tsx b/webviews/src/routes/root/index.tsx index 5a4c4fe..2fe169c 100644 --- a/webviews/src/routes/root/index.tsx +++ b/webviews/src/routes/root/index.tsx @@ -1,23 +1,8 @@ import { useEffect } from "react"; -import { - Outlet, - useLoaderData, - useLocation, - useNavigate, -} from "react-router-dom"; +import { Outlet, useLocation, useNavigate } from "react-router-dom"; import { useMessageListener } from "../../hooks/messageListener"; -import { vscode } from "../../utilities/vscode"; - -export async function loader() { - const settings = await vscode.getSettings(); - return settings; -} - -type LoaderReturn = Awaited>; export default function Root() { - const settings = useLoaderData() as LoaderReturn; - let location = useLocation(); useEffect(() => { @@ -31,14 +16,6 @@ export default function Root() { navigate("/chats/new-chat"); }); - useEffect(() => { - if (!settings.chatEnable) { - navigate("/init"); - } - }, [settings, navigate]); - - console.log(settings); - return ( <> From af165bd23fa8268448f14f7264e2910c61b95e4e Mon Sep 17 00:00:00 2001 From: Ivan Pegashev Date: Sun, 12 May 2024 16:20:24 +0300 Subject: [PATCH 3/4] update --- src/common/auth/supabaseClient.ts | 2 +- src/common/panel/chat.ts | 51 +++++++- src/common/server/index.ts | 6 +- src/common/utils/configuration.ts | 13 +- src/extension.ts | 150 ++++++++++++---------- webviews/src/hooks/messageListener.ts | 2 +- webviews/src/hooks/useSettings.tsx | 26 +++- webviews/src/index.tsx | 1 + webviews/src/routes/chat/index.tsx | 5 +- webviews/src/routes/init/index.tsx | 50 +++++++- webviews/src/routes/init/style.module.css | 7 + webviews/src/utilities/vscode.ts | 19 ++- 12 files changed, 240 insertions(+), 92 deletions(-) create mode 100644 webviews/src/routes/init/style.module.css diff --git a/src/common/auth/supabaseClient.ts b/src/common/auth/supabaseClient.ts index c0c26c0..506ec2a 100644 --- a/src/common/auth/supabaseClient.ts +++ b/src/common/auth/supabaseClient.ts @@ -16,7 +16,7 @@ export const getSuppabaseClient = () => { autoRefreshToken: true, persistSession: true, detectSessionInUrl: false, - debug: true, + // debug: true, storage: secretsStorage, }, }); diff --git a/src/common/panel/chat.ts b/src/common/panel/chat.ts index d2706bf..b1a15ce 100644 --- a/src/common/panel/chat.ts +++ b/src/common/panel/chat.ts @@ -6,6 +6,8 @@ import { chat } from "../chat"; import { Chat, ChatMessage } from "../prompt/promptChat"; import { state } from "../utils/state"; import { configuration } from "../utils/configuration"; +import { TypeModelsChat, modelsChat, servers } from "../server"; +import { getSuppabaseClient } from "../auth/supabaseClient"; export type MessageType = | { @@ -33,6 +35,9 @@ type MessageToExtention = | { type: "get-settings"; } + | { + type: "enable-chat"; + } | { type: "get-chat"; chatId: string; @@ -182,6 +187,11 @@ export class ChatPanel implements vscode.WebviewViewProvider { id: message.id, }); break; + case "enable-chat": + await this.handleEnableChat({ + id: message.id, + }); + break; default: break; } @@ -223,18 +233,39 @@ export class ChatPanel implements vscode.WebviewViewProvider { } private async handleGetSettings({ id }: { id: string }) { - const enable = configuration.get("experimental.chat"); + const settigns = await this.getSettings(); await this.postMessage({ type: "e2w-response", id: id, - data: { - chatEnable: enable, - }, + data: settigns, done: true, }); } + private async getSettings() { + const cloudUsing = configuration.get("cloud.use"); + const cloudChatUsing = configuration.get("cloud.chat.use"); + const chatServerIsWorking = Object.keys(modelsChat) + .map( + (chatModel) => servers[chatModel as TypeModelsChat].status === "started" + ) + .some((serverIsWorking) => serverIsWorking); + + const localChatUsing = configuration.get("experimental.chat"); + const supabase = getSuppabaseClient(); + const sesssion = await supabase.auth.getSession(); + const userLoggined = sesssion.data.session ? true : false; + + const chatEnabled = + (localChatUsing && chatServerIsWorking) || (cloudUsing && cloudChatUsing); + + return { + chatEnabled: chatEnabled, + userLoggined: userLoggined, + }; + } + private async handleGetChat({ chatId, id }: { chatId: string; id: string }) { const sendResponse = (messageToResponse: Chat | null, done: boolean) => { this.postMessage({ @@ -292,7 +323,17 @@ export class ChatPanel implements vscode.WebviewViewProvider { await this.postMessage({ type: "e2w-response", id: id, - data: "", + data: true, + done: true, + }); + } + + private async handleEnableChat({ id }: { id: string }) { + await configuration.set("experimental.chat", true); + await this.postMessage({ + type: "e2w-response", + id: id, + data: true, done: true, }); } diff --git a/src/common/server/index.ts b/src/common/server/index.ts index 2f42331..41ac32f 100644 --- a/src/common/server/index.ts +++ b/src/common/server/index.ts @@ -17,7 +17,7 @@ const modelsBase = { }; export type TypeModelsBase = keyof typeof modelsBase; -const modelsChat = { +export const modelsChat = { "chat-small": { port: 39725, }, @@ -197,7 +197,7 @@ class Server { }); const isServerStarted = await this.checkServerStatusIntervalWithTimeout( - 1000000 + 20000 ); if (!isServerStarted) { @@ -217,7 +217,7 @@ class Server { return true; } - public async stopServer() { + public stopServer() { if (this.serverProcess) { const result = this.serverProcess.kill(9); if (result === false) { diff --git a/src/common/utils/configuration.ts b/src/common/utils/configuration.ts index c70d2a6..d590116 100644 --- a/src/common/utils/configuration.ts +++ b/src/common/utils/configuration.ts @@ -87,11 +87,6 @@ interface ConfigurationPropertiesType } class Configuration { - // private configuration: vscode.WorkspaceConfiguration; - // constructor() { - // this.configuration = vscode.workspace.getConfiguration("firecoder"); - // } - public get( property: T ): ConfigurationPropertiesType[T]["possibleValues"] { @@ -100,6 +95,14 @@ class Configuration { return value ?? ConfigurationProperties[property]["default"]; } + + public async set( + property: T, + value: ConfigurationPropertiesType[T]["possibleValues"] + ) { + const configuration = vscode.workspace.getConfiguration("firecoder"); + await configuration.update(property, value, true); + } } export const configuration = new Configuration(); diff --git a/src/extension.ts b/src/extension.ts index c405e94..17aa3d0 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -70,18 +70,13 @@ export async function activate(context: vscode.ExtensionContext) { vscode.workspace.onDidChangeConfiguration(async (event) => { if (event.affectsConfiguration("firecoder.cloud.use")) { const cloudUse = configuration.get("cloud.use"); + const supabase = getSuppabaseClient(); if (cloudUse === true) { - const supabase = getSuppabaseClient(); - const data = await supabase.auth.getUser(); if (data.error) { await login(); return; } - } else { - const supabase = getSuppabaseClient(); - - await supabase.auth.signOut(); } } }); @@ -94,87 +89,67 @@ export async function activate(context: vscode.ExtensionContext) { }) ); - vscode.workspace.onDidChangeConfiguration(async (event) => { - if ( - event.affectsConfiguration("firecoder.cloud.use") || - event.affectsConfiguration("firecoder.experimental.chat") || - event.affectsConfiguration("firecoder.completion.manuallyMode") || - event.affectsConfiguration("firecoder.completion.autoMode") || - event.affectsConfiguration( - "firecoder.experimental.useGpu.linux.nvidia" - ) || - event.affectsConfiguration("firecoder.experimental.useGpu.osx.metal") || - event.affectsConfiguration( - "firecoder.experimental.useGpu.windows.nvidia" - ) || - event.affectsConfiguration("firecoder.server.usePreRelease") || - event.affectsConfiguration("firecoder.cloud.use.chat") || - event.affectsConfiguration("firecoder.cloud.use.autocomplete") - ) { - Object.values(servers).forEach((server) => server.stopServer()); - - const completionServers = - configuration.get("cloud.use") && - configuration.get("cloud.autocomplete.use") - ? [] - : new Set([ - configuration.get("completion.autoMode"), - configuration.get("completion.manuallyMode"), - ]); - const serversToStart = [ - ...completionServers, - ...(configuration.get("experimental.chat") && - configuration.get("cloud.use") && - configuration.get("cloud.chat.use") - ? [] - : ["chat-medium" as const]), - ]; - await Promise.all( - serversToStart.map((serverType) => servers[serverType].startServer()) - ); + const startChat = async () => { + if (configuration.get("cloud.use") && configuration.get("cloud.chat.use")) { + Logger.info("Use cloud for chat.", { + component: "main", + sendTelemetry: true, + }); + } else if (configuration.get("experimental.chat")) { + Logger.info("Use local for chat.", { + component: "main", + sendTelemetry: true, + }); + try { + await servers["chat-medium"].startServer(); + } catch (error) { + vscode.window.showErrorMessage((error as Error).message); + Logger.error(error, { + component: "server", + sendTelemetry: true, + }); + } + Logger.info("Chat is ready to start.", { + component: "main", + sendTelemetry: true, + }); + } else { + Logger.info("Chat is not enable", { + component: "main", + sendTelemetry: true, + }); } - }); + }; - (async () => { - if (configuration.get("cloud.use")) { - Logger.info("Use cloud for chat and completions", { + const startCompletion = async (registerCompletionProvider: boolean) => { + if ( + configuration.get("cloud.use") && + configuration.get("cloud.autocomplete.use") + ) { + Logger.info("Use cloud for auto completions.", { component: "main", sendTelemetry: true, }); - - const InlineCompletionProvider = getInlineCompletionProvider(context); - vscode.languages.registerInlineCompletionItemProvider( - { pattern: "**" }, - InlineCompletionProvider - ); } else { + Logger.info("Use local for auto completions.", { + component: "main", + sendTelemetry: true, + }); try { - const completionServers = configuration.get("cloud.use") - ? [] - : new Set([ - configuration.get("completion.autoMode"), - configuration.get("completion.manuallyMode"), - ]); const serversStarted = await Promise.all( [ - ...completionServers, - ...(configuration.get("experimental.chat") && - !configuration.get("cloud.use") - ? ["chat-medium" as const] - : []), + ...new Set([ + configuration.get("completion.autoMode"), + configuration.get("completion.manuallyMode"), + ]), ].map((serverType) => servers[serverType].startServer()) ); if (serversStarted.some((serverStarted) => serverStarted)) { - Logger.info("Server inited", { + Logger.info("Servers inited", { component: "main", sendTelemetry: true, }); - const InlineCompletionProvider = getInlineCompletionProvider(context); - vscode.languages.registerInlineCompletionItemProvider( - { pattern: "**" }, - InlineCompletionProvider - ); } } catch (error) { vscode.window.showErrorMessage((error as Error).message); @@ -184,12 +159,45 @@ export async function activate(context: vscode.ExtensionContext) { }); } } + if (registerCompletionProvider) { + const InlineCompletionProvider = getInlineCompletionProvider(context); + vscode.languages.registerInlineCompletionItemProvider( + { pattern: "**" }, + InlineCompletionProvider + ); + } + }; + + (async () => { + await Promise.all([startChat(), startCompletion(true)]); Logger.info("FireCoder is ready.", { component: "main", sendTelemetry: true, }); })(); + + vscode.workspace.onDidChangeConfiguration(async (event) => { + if ( + event.affectsConfiguration("firecoder.cloud.use") || + event.affectsConfiguration("firecoder.cloud.chat.use") || + event.affectsConfiguration("firecoder.cloud.autocomplete.use") || + event.affectsConfiguration("firecoder.experimental.chat") || + event.affectsConfiguration("firecoder.completion.manuallyMode") || + event.affectsConfiguration("firecoder.completion.autoMode") || + event.affectsConfiguration( + "firecoder.experimental.useGpu.linux.nvidia" + ) || + event.affectsConfiguration("firecoder.experimental.useGpu.osx.metal") || + event.affectsConfiguration( + "firecoder.experimental.useGpu.windows.nvidia" + ) || + event.affectsConfiguration("firecoder.server.usePreRelease") + ) { + Object.values(servers).forEach((server) => server.stopServer()); + await Promise.all([startChat(), startCompletion(false)]); + } + }); } export function deactivate() { diff --git a/webviews/src/hooks/messageListener.ts b/webviews/src/hooks/messageListener.ts index 96545fb..7ce32dd 100644 --- a/webviews/src/hooks/messageListener.ts +++ b/webviews/src/hooks/messageListener.ts @@ -2,7 +2,7 @@ import { useEffect } from "react"; import { vscode } from "../utilities/vscode"; export const useMessageListener = ( - command: "start-new-chat", + command: "start-new-chat" | "settings-updated", callback: (message: any) => void ) => { useEffect(() => { diff --git a/webviews/src/hooks/useSettings.tsx b/webviews/src/hooks/useSettings.tsx index 1f2145e..fd1879c 100644 --- a/webviews/src/hooks/useSettings.tsx +++ b/webviews/src/hooks/useSettings.tsx @@ -3,6 +3,7 @@ import { vscode } from "../utilities/vscode"; type ConfigurationType = { chatEnabled: boolean; + userLoggined: boolean; }; interface SettingsContextType { @@ -19,17 +20,36 @@ export const SettingsProvider = ({ const [configuration, setConfiguration] = useState(null!); useEffect(() => { + let lastSettings: any = null; + const getSettings = async () => { const settings = await vscode.getSettings(); - setConfiguration({ - chatEnabled: settings.chatEnable, - }); + if ( + settings.chatEnabled !== lastSettings?.chatEnabled || + settings.userLoggined !== lastSettings?.userLoggined + ) { + lastSettings = settings; + + setConfiguration({ + chatEnabled: settings.chatEnabled, + userLoggined: settings.userLoggined, + }); + } }; getSettings(); + + const interval = setInterval(getSettings, 5000); + return () => { + clearInterval(interval); + }; }, []); const value = useMemo(() => ({ configuration }), [configuration]); + if (configuration === null) { + return null; + } + return ( {children} diff --git a/webviews/src/index.tsx b/webviews/src/index.tsx index ae560c6..b8f3664 100644 --- a/webviews/src/index.tsx +++ b/webviews/src/index.tsx @@ -25,6 +25,7 @@ const router = createMemoryRouter( element: , children: [ { + path: "/chats/history", element: , loader: ChatsHistoryLoader, }, diff --git a/webviews/src/routes/chat/index.tsx b/webviews/src/routes/chat/index.tsx index f1c2a81..2730a1d 100644 --- a/webviews/src/routes/chat/index.tsx +++ b/webviews/src/routes/chat/index.tsx @@ -30,7 +30,10 @@ export const ChatInstance = () => { return (
- navigate("/chats")}> + navigate("/chats/history")} + >
diff --git a/webviews/src/routes/init/index.tsx b/webviews/src/routes/init/index.tsx index eba6dd6..fd812a0 100644 --- a/webviews/src/routes/init/index.tsx +++ b/webviews/src/routes/init/index.tsx @@ -1,3 +1,51 @@ +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; +import styles from "./style.module.css"; +import { vscode } from "../../utilities/vscode"; +import { useState } from "react"; +import { useSettings } from "../../hooks/useSettings"; +import { Navigate } from "react-router-dom"; + export default function Init() { - return
Init Screen
; + const [isChatEnabled, setIsChatEnabled] = useState(false); + const settings = useSettings(); + + if (settings.configuration.chatEnabled) { + return ; + } + + return ( +
+

+ FireCoder Chat is currently disabled. Please enable it to start + chatting. +

+

+ FireCoder needs to download the chat model and save it to your device's + local storage. +
+ This model is quite large, around 6GB, so the download may take a few + minutes. +

+ { + setIsChatEnabled(true); + vscode.enableChat(); + }} + > + Enable + {isChatEnabled ? ( + + ) : ( + + )} + +
+ ); } diff --git a/webviews/src/routes/init/style.module.css b/webviews/src/routes/init/style.module.css new file mode 100644 index 0000000..d165127 --- /dev/null +++ b/webviews/src/routes/init/style.module.css @@ -0,0 +1,7 @@ +.init { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 16px; +} diff --git a/webviews/src/utilities/vscode.ts b/webviews/src/utilities/vscode.ts index be13ce3..d702fcc 100644 --- a/webviews/src/utilities/vscode.ts +++ b/webviews/src/utilities/vscode.ts @@ -29,6 +29,9 @@ type MessageToExtention = | { type: "get-settings"; } + | { + type: "enable-chat"; + } | { type: "get-chat"; chatId: string; @@ -159,7 +162,8 @@ class VSCodeAPIWrapper { public getSettings() { return new Promise<{ - chatEnable: boolean; + chatEnabled: boolean; + userLoggined: boolean; }>((resolve) => { this.postMessageCallback( { @@ -172,6 +176,19 @@ class VSCodeAPIWrapper { }); } + public enableChat() { + return new Promise((resolve) => { + this.postMessageCallback( + { + type: "enable-chat", + }, + (message) => { + resolve(message.data); + } + ); + }); + } + public saveChatHistory(chatId: string, history: Chat) { return new Promise((resolve) => { this.postMessageCallback( From 91fbd3a7d02cb8e924e4aa7153eaf82b8e933804 Mon Sep 17 00:00:00 2001 From: Ivan Pegashev Date: Sun, 12 May 2024 16:22:35 +0300 Subject: [PATCH 4/4] update --- src/common/auth/supabaseClient.ts | 1 - webviews/src/hooks/messageListener.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/common/auth/supabaseClient.ts b/src/common/auth/supabaseClient.ts index 506ec2a..285e915 100644 --- a/src/common/auth/supabaseClient.ts +++ b/src/common/auth/supabaseClient.ts @@ -16,7 +16,6 @@ export const getSuppabaseClient = () => { autoRefreshToken: true, persistSession: true, detectSessionInUrl: false, - // debug: true, storage: secretsStorage, }, }); diff --git a/webviews/src/hooks/messageListener.ts b/webviews/src/hooks/messageListener.ts index 7ce32dd..96545fb 100644 --- a/webviews/src/hooks/messageListener.ts +++ b/webviews/src/hooks/messageListener.ts @@ -2,7 +2,7 @@ import { useEffect } from "react"; import { vscode } from "../utilities/vscode"; export const useMessageListener = ( - command: "start-new-chat" | "settings-updated", + command: "start-new-chat", callback: (message: any) => void ) => { useEffect(() => {