diff --git a/ui/desktop/src/App.tsx b/ui/desktop/src/App.tsx index 31e584c0..78daea77 100644 --- a/ui/desktop/src/App.tsx +++ b/ui/desktop/src/App.tsx @@ -63,7 +63,7 @@ export default function App() { view: 'welcome', viewOptions: {}, }); - const { getExtensions, addExtension, read } = useConfig(); + const { getExtensions, addExtension, read, upsert } = useConfig(); const initAttemptedRef = useRef(false); // Utility function to extract the command from the link @@ -91,6 +91,7 @@ export default function App() { const initializeApp = async () => { try { const config = window.electron.getConfig(); + const provider = config.GOOSE_PROVIDER ?? (await read('GOOSE_PROVIDER', false)); const model = config.GOOSE_MODEL ?? (await read('GOOSE_MODEL', false)); diff --git a/ui/desktop/src/components/more_menu/MoreMenu.tsx b/ui/desktop/src/components/more_menu/MoreMenu.tsx index c5cc38e6..9abdc87d 100644 --- a/ui/desktop/src/components/more_menu/MoreMenu.tsx +++ b/ui/desktop/src/components/more_menu/MoreMenu.tsx @@ -9,6 +9,7 @@ import { ChatSmart, Idea, More, Refresh, Time, Send } from '../icons'; import { FolderOpen, Moon, Sliders, Sun } from 'lucide-react'; import { View } from '../../App'; import { useConfig } from '../ConfigContext'; +import { toastService } from '../../toasts'; interface VersionInfo { current_version: string; @@ -262,7 +263,7 @@ export default function MoreMenu({ await remove('GOOSE_PROVIDER', false); await remove('GOOSE_MODEL', false); setOpen(false); - window.electron.createChatWindow(); + setView('welcome'); }} danger subtitle="Clear selected model and restart (alpha)" diff --git a/ui/desktop/src/components/settings_v2/extensions/agent-api.ts b/ui/desktop/src/components/settings_v2/extensions/agent-api.ts index 799b0dbc..ec6fc5a7 100644 --- a/ui/desktop/src/components/settings_v2/extensions/agent-api.ts +++ b/ui/desktop/src/components/settings_v2/extensions/agent-api.ts @@ -76,7 +76,7 @@ export async function extensionApiCall( } catch (error) { // Final catch-all error handler toastService.dismiss(toastId); - const msg = error.length < 100 ? error : `Failed to ${action.presentTense} extension`; + const msg = error.length < 70 ? error : `Failed to ${action.presentTense} extension`; toastService.error({ title: extensionName, msg: msg, diff --git a/ui/desktop/src/components/settings_v2/extensions/built-in-extensions.json b/ui/desktop/src/components/settings_v2/extensions/bundled-extensions.json similarity index 100% rename from ui/desktop/src/components/settings_v2/extensions/built-in-extensions.json rename to ui/desktop/src/components/settings_v2/extensions/bundled-extensions.json diff --git a/ui/desktop/src/components/settings_v2/extensions/built-in.ts b/ui/desktop/src/components/settings_v2/extensions/bundled-extensions.ts similarity index 54% rename from ui/desktop/src/components/settings_v2/extensions/built-in.ts rename to ui/desktop/src/components/settings_v2/extensions/bundled-extensions.ts index 59431252..682be4e1 100644 --- a/ui/desktop/src/components/settings_v2/extensions/built-in.ts +++ b/ui/desktop/src/components/settings_v2/extensions/bundled-extensions.ts @@ -1,18 +1,22 @@ import type { ExtensionConfig } from '../../../api/types.gen'; import { FixedExtensionEntry } from '../../ConfigContext'; -import builtInExtensionsData from './built-in-extensions.json'; +import bundledExtensionsData from './bundled-extensions.json'; import { nameToKey } from './utils'; // Type definition for built-in extensions from JSON -type BuiltinExtension = { +type BundledExtension = { id: string; name: string; - display_name: string; - description: string; + display_name?: string; + description?: string; enabled: boolean; - type: 'builtin'; + type: 'builtin' | 'stdio' | 'sse'; + cmd?: string; + args?: string[]; + uri?: string; envs?: { [key: string]: string }; timeout?: number; + allow_configure?: boolean; }; /** @@ -24,43 +28,61 @@ type BuiltinExtension = { * @param addExtensionFn Function to add a new extension to the config * @returns Promise that resolves when sync is complete */ -export async function syncBuiltInExtensions( +export async function syncBundledExtensions( existingExtensions: FixedExtensionEntry[], addExtensionFn: (name: string, config: ExtensionConfig, enabled: boolean) => Promise ): Promise { try { - console.log('Setting up built-in extensions... in syncBuiltinExtensions'); - // Create a set of existing extension IDs for quick lookup const existingExtensionKeys = new Set(existingExtensions.map((ext) => nameToKey(ext.name))); - console.log('existing extension ids', existingExtensionKeys); // Cast the imported JSON data to the expected type - const builtinExtensions = builtInExtensionsData as BuiltinExtension[]; + const bundledExtensions = bundledExtensionsData as BundledExtension[]; // Track how many extensions were added let addedCount = 0; // Check each built-in extension - for (const builtinExt of builtinExtensions) { + for (const bundledExt of bundledExtensions) { // Only add if the extension doesn't already exist -- use the id - if (!existingExtensionKeys.has(builtinExt.id)) { - console.log(`Adding built-in extension: ${builtinExt.id}`); - - // Convert to the ExtensionConfig format - const extConfig: ExtensionConfig = { - name: builtinExt.name, - display_name: builtinExt.display_name, - type: 'builtin', - timeout: builtinExt.timeout ?? 300, - }; - + if (!existingExtensionKeys.has(bundledExt.id)) { + console.log(`Adding built-in extension: ${bundledExt.id}`); + let extConfig: ExtensionConfig; + switch (bundledExt.type) { + case 'builtin': + extConfig = { + name: bundledExt.name, + display_name: bundledExt.display_name, + type: bundledExt.type, + timeout: bundledExt.timeout ?? 300, + }; + break; + case 'stdio': + extConfig = { + name: bundledExt.name, + description: bundledExt.description, + type: bundledExt.type, + timeout: bundledExt.timeout, + cmd: bundledExt.cmd, + args: bundledExt.args, + envs: bundledExt.envs, + }; + break; + case 'sse': + extConfig = { + name: bundledExt.name, + description: bundledExt.description, + type: bundledExt.type, + timeout: bundledExt.timeout, + uri: bundledExt.uri, + }; + } // Add the extension with its default enabled state try { - await addExtensionFn(nameToKey(builtinExt.name), extConfig, builtinExt.enabled); + await addExtensionFn(bundledExt.name, extConfig, bundledExt.enabled); addedCount++; } catch (error) { - console.error(`Failed to add built-in extension ${builtinExt.name}:`, error); + console.error(`Failed to add built-in extension ${bundledExt.name}:`, error); // Continue with other extensions even if one fails } } @@ -81,9 +103,9 @@ export async function syncBuiltInExtensions( * Function to initialize all built-in extensions for a first-time user. * This can be called when the application is first installed. */ -export async function initializeBuiltInExtensions( +export async function initializeBundledExtensions( addExtensionFn: (name: string, config: ExtensionConfig, enabled: boolean) => Promise ): Promise { // Call with an empty list to ensure all built-ins are added - await syncBuiltInExtensions([], addExtensionFn); + await syncBundledExtensions([], addExtensionFn); } diff --git a/ui/desktop/src/components/settings_v2/extensions/index.ts b/ui/desktop/src/components/settings_v2/extensions/index.ts index baff99e4..5469fc52 100644 --- a/ui/desktop/src/components/settings_v2/extensions/index.ts +++ b/ui/desktop/src/components/settings_v2/extensions/index.ts @@ -11,7 +11,7 @@ export { } from './extension-manager'; // Export built-in extension functions -export { syncBuiltInExtensions, initializeBuiltInExtensions } from './built-in'; +export { syncBundledExtensions, initializeBundledExtensions } from './bundled-extensions'; // Export deeplink handling export { addExtensionFromDeepLink } from './deeplink'; diff --git a/ui/desktop/src/components/settings_v2/models/ModelsSection.tsx b/ui/desktop/src/components/settings_v2/models/ModelsSection.tsx index 005d7738..7aa9f1a0 100644 --- a/ui/desktop/src/components/settings_v2/models/ModelsSection.tsx +++ b/ui/desktop/src/components/settings_v2/models/ModelsSection.tsx @@ -4,13 +4,12 @@ import ModelSettingsButtons from './subcomponents/ModelSettingsButtons'; import { useConfig } from '../../ConfigContext'; import { toastError } from '../../../toasts'; +import { UNKNOWN_PROVIDER_MSG, UNKNOWN_PROVIDER_TITLE } from './index'; + interface ModelsSectionProps { setView: (view: View) => void; } -const UNKNOWN_PROVIDER_TITLE = 'Provider name error'; -const UNKNOWN_PROVIDER_MSG = 'Unknown provider in config -- please inspect your config.yaml'; - export default function ModelsSection({ setView }: ModelsSectionProps) { const [provider, setProvider] = useState(null); const [model, setModel] = useState(''); diff --git a/ui/desktop/src/components/settings_v2/models/index.ts b/ui/desktop/src/components/settings_v2/models/index.ts index 59ac26fa..879cf92d 100644 --- a/ui/desktop/src/components/settings_v2/models/index.ts +++ b/ui/desktop/src/components/settings_v2/models/index.ts @@ -8,13 +8,13 @@ import type { ExtensionConfig, FixedExtensionEntry } from '../../ConfigContext'; // titles const CHANGE_MODEL_TOAST_TITLE = 'Model selected'; const START_AGENT_TITLE = 'Initialize agent'; -const UNKNOWN_PROVIDER_TITLE = 'Provider name lookup'; +export const UNKNOWN_PROVIDER_TITLE = 'Provider name lookup'; // errors const SWITCH_MODEL_AGENT_ERROR_MSG = 'Failed to start agent with selected model'; const CONFIG_UPDATE_ERROR_MSG = 'Failed to update configuration settings'; const CONFIG_READ_MODEL_ERROR_MSG = 'Failed to read GOOSE_MODEL or GOOSE_PROVIDER from config'; -const UNKNOWN_PROVIDER_MSG = 'Unknown provider in config -- please inspect your config.yaml'; +export const UNKNOWN_PROVIDER_MSG = 'Unknown provider in config -- please inspect your config.yaml'; // success const SWITCH_MODEL_SUCCESS_MSG = 'Successfully switched models'; @@ -114,11 +114,6 @@ export async function getCurrentModelAndProviderForDisplay({ try { metadata = await getProviderMetadata(gooseProvider, getProviders); } catch (error) { - toastError({ - title: UNKNOWN_PROVIDER_TITLE, - msg: UNKNOWN_PROVIDER_MSG, - traceback: error, - }); return { model: gooseModel, provider: gooseProvider }; } const providerDisplayName = metadata.display_name; diff --git a/ui/desktop/src/components/settings_v2/providers/ProviderSettingsPage.tsx b/ui/desktop/src/components/settings_v2/providers/ProviderSettingsPage.tsx index d20c3872..05190f3f 100644 --- a/ui/desktop/src/components/settings_v2/providers/ProviderSettingsPage.tsx +++ b/ui/desktop/src/components/settings_v2/providers/ProviderSettingsPage.tsx @@ -6,6 +6,8 @@ import { useConfig } from '../../ConfigContext'; import { ProviderDetails } from '../../../api/types.gen'; import { initializeSystem } from '../../../utils/providerUtils'; import WelcomeGooseLogo from '../../WelcomeGooseLogo'; +import { toastService } from '../../../toasts'; +import { toast } from 'react-toastify'; interface ProviderSettingsProps { onClose: () => void; @@ -56,7 +58,6 @@ export default function ProviderSettings({ onClose, isOnboarding }: ProviderSett const provider_name = provider.name; const model = provider.metadata.default_model; - console.log(`Launching with provider: ${provider.name}`); try { // update the config // set GOOSE_PROVIDER in the config file @@ -76,6 +77,11 @@ export default function ProviderSettings({ onClose, isOnboarding }: ProviderSett } catch (error) { console.error(`Failed to initialize with provider ${provider_name}:`, error); } + toastService.configure({ silent: false }); + toastService.success({ + title: 'Success!', + msg: `Started goose with ${model} by ${provider.metadata.display_name}. You can change the model via the lower right corner.`, + }); onClose(); }, [onClose, upsert] diff --git a/ui/desktop/src/toasts.tsx b/ui/desktop/src/toasts.tsx index 73d3dd13..91dec865 100644 --- a/ui/desktop/src/toasts.tsx +++ b/ui/desktop/src/toasts.tsx @@ -1,5 +1,6 @@ import { toast, ToastOptions } from 'react-toastify'; import React from 'react'; +import { Button } from './components/ui/button'; export interface ToastServiceOptions { silent?: boolean; @@ -123,12 +124,12 @@ export function toastError({ title, msg, traceback, toastOptions }: ToastErrorPr
{traceback ? ( - + ) : null}
, diff --git a/ui/desktop/src/utils/providerUtils.ts b/ui/desktop/src/utils/providerUtils.ts index 6975d510..e4ba1b0e 100644 --- a/ui/desktop/src/utils/providerUtils.ts +++ b/ui/desktop/src/utils/providerUtils.ts @@ -5,8 +5,8 @@ import { Model } from '../components/settings/models/ModelContext'; import { gooseModels } from '../components/settings/models/GooseModels'; import { initializeAgent } from '../agent'; import { - initializeBuiltInExtensions, - syncBuiltInExtensions, + initializeBundledExtensions, + syncBundledExtensions, addToAgentOnStartup, } from '../components/settings_v2/extensions'; import { extractExtensionConfig } from '../components/settings_v2/extensions/utils'; @@ -128,10 +128,10 @@ export const initializeSystem = async ( let refreshedExtensions = await options.getExtensions(false); if (refreshedExtensions.length === 0) { - await initializeBuiltInExtensions(options.addExtension); + await initializeBundledExtensions(options.addExtension); refreshedExtensions = await options.getExtensions(false); } else { - await syncBuiltInExtensions(refreshedExtensions, options.addExtension); + await syncBundledExtensions(refreshedExtensions, options.addExtension); } // Add enabled extensions to agent