-
Notifications
You must be signed in to change notification settings - Fork 2.6k
ui: turn on extensions at startup #1861
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,7 @@ | |
| import { ToastContainer } from 'react-toastify'; | ||
| import { extractExtensionName } from './components/settings/extensions/utils'; | ||
| import { GoosehintsModal } from './components/GoosehintsModal'; | ||
| import { SessionDetails, fetchSessionDetails } from './sessions'; | ||
|
|
||
| import WelcomeView from './components/WelcomeView'; | ||
| import ChatView from './components/ChatView'; | ||
|
|
@@ -24,12 +24,14 @@ | |
| import { useChat } from './hooks/useChat'; | ||
|
|
||
| import 'react-toastify/dist/ReactToastify.css'; | ||
| import { useConfig } from './components/ConfigContext'; | ||
| import { FixedExtensionEntry, useConfig } from './components/ConfigContext'; | ||
| import { | ||
| initializeBuiltInExtensions, | ||
| syncBuiltInExtensions, | ||
| addExtensionFromDeepLink as addExtensionFromDeepLinkV2, | ||
| addToAgentOnStartup, | ||
| } from './components/settings_v2/extensions'; | ||
| import { extractExtensionConfig } from './components/settings_v2/extensions/utils'; | ||
|
|
||
| // Views and their options | ||
| export type View = | ||
|
|
@@ -50,7 +52,7 @@ | |
| | { | ||
| resumedSession?: SessionDetails; | ||
| } | ||
| | Record<string, any>; | ||
| }; | ||
|
|
||
| export default function App() { | ||
|
|
@@ -74,6 +76,8 @@ | |
| } | ||
|
|
||
| // this is all settings v2 stuff | ||
| // Modified version of the alpha initialization flow for App.tsx | ||
|
|
||
| useEffect(() => { | ||
| // Skip if feature flag is not enabled | ||
| if (!process.env.ALPHA) { | ||
|
|
@@ -82,24 +86,68 @@ | |
|
|
||
| console.log('Alpha flow initializing...'); | ||
|
|
||
| const setupExtensions = async () => { | ||
| // First quickly check if we have model and provider to set chat view | ||
| const checkRequiredConfig = async () => { | ||
| try { | ||
| console.log('Setting up extensions...'); | ||
| console.log('Reading GOOSE_PROVIDER and GOOSE_MODEL from config...'); | ||
| const provider = (await read('GOOSE_PROVIDER', false)) as string; | ||
| const model = (await read('GOOSE_MODEL', false)) as string; | ||
|
|
||
| if (provider && model) { | ||
| // We have all needed configuration, set chat view immediately | ||
| console.log(`Found provider: ${provider}, model: ${model}, setting chat view`); | ||
| setView('chat'); | ||
|
|
||
| // Initialize the system in background | ||
| initializeSystem(provider, model) | ||
| .then(() => console.log('System initialization successful')) | ||
| .catch((error) => { | ||
| console.error('Error initializing system:', error); | ||
| setFatalError(`System initialization error: ${error.message || 'Unknown error'}`); | ||
| setView('welcome'); | ||
| }); | ||
| } else { | ||
| // Missing configuration, show onboarding | ||
| console.log('Missing configuration, showing onboarding'); | ||
| if (!provider) console.log('Missing provider'); | ||
| if (!model) console.log('Missing model'); | ||
| setView('welcome'); | ||
| } | ||
| } catch (error) { | ||
| console.error('Error checking configuration:', error); | ||
| setFatalError(`Configuration check error: ${error.message || 'Unknown error'}`); | ||
| setView('welcome'); | ||
| } | ||
| }; | ||
|
|
||
| // Set the ref immediately to prevent duplicate runs | ||
| initAttemptedRef.current = true; | ||
| console.log('Set initAttemptedRef to prevent duplicate runs'); | ||
| // Setup extensions in parallel | ||
| const setupExtensions = async () => { | ||
| // Set the ref immediately to prevent duplicate runs | ||
| initAttemptedRef.current = true; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does anything read from this? It doesn't appear so. We can probably remove it. |
||
|
|
||
| let refreshedExtensions: FixedExtensionEntry[] = []; | ||
| try { | ||
| // Force refresh extensions from the backend to ensure we have the latest | ||
| console.log('Getting extensions from backend...'); | ||
| const refreshedExtensions = await getExtensions(true); | ||
| refreshedExtensions = await getExtensions(true); | ||
| console.log(`Retrieved ${refreshedExtensions.length} extensions`); | ||
| } catch (error) { | ||
| console.log('Error getting extensions list'); | ||
| return; // Exit early if we can't get the extensions list | ||
| } | ||
|
|
||
| // built-in extensions block -- just adds them to config if missing | ||
| try { | ||
| console.log('Setting up built-in extensions...'); | ||
|
|
||
| if (refreshedExtensions.length === 0) { | ||
| // If we still have no extensions, this is truly a first-time setup | ||
| console.log('First-time setup: Adding all built-in extensions...'); | ||
| await initializeBuiltInExtensions(addExtension); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Conceptual question. If (No need to address this in this PR if it distracts - just trying to find opportunities to reduce complexity) |
||
| console.log('Built-in extensions initialization complete'); | ||
|
|
||
| // Refresh the extensions list after initialization | ||
| refreshedExtensions = await getExtensions(true); | ||
| } else { | ||
| // Extensions exist, check for any missing built-ins | ||
| console.log('Checking for missing built-in extensions...'); | ||
|
|
@@ -109,70 +157,38 @@ | |
| } | ||
| } catch (error) { | ||
| console.error('Error setting up extensions:', error); | ||
| console.error('Extension setup error details:', { | ||
| message: error.message, | ||
| stack: error.stack, | ||
| name: error.name, | ||
| }); | ||
| // We don't set fatal error here since the app might still work without extensions | ||
| } | ||
| }; | ||
|
|
||
| const initializeApp = async () => { | ||
| try { | ||
| console.log('Initializing alpha app...'); | ||
|
|
||
| // Check if we have the required configuration | ||
| console.log('Reading GOOSE_PROVIDER from config...'); | ||
| const provider = (await read('GOOSE_PROVIDER', false)) as string; | ||
| console.log('Provider from config:', provider); | ||
|
|
||
| console.log('Reading GOOSE_MODEL from config...'); | ||
| const model = (await read('GOOSE_MODEL', false)) as string; | ||
| console.log('Model from config:', model); | ||
|
|
||
| if (provider && model) { | ||
| // We have all needed configuration, initialize the system | ||
| console.log(`Initializing system with provider: ${provider}, model: ${model}`); | ||
| await initializeSystem(provider, model); | ||
| console.log('System initialization successful'); | ||
| setView('chat'); | ||
| // now try to add to agent | ||
| console.log('Adding enabled extensions to agent...'); | ||
| for (const extensionEntry of refreshedExtensions) { | ||
| if (extensionEntry.enabled) { | ||
| console.log(`Adding extension to agent: ${extensionEntry.name}`); | ||
| // need to convert to config because that's what the endpoint expects | ||
| const extensionConfig = extractExtensionConfig(extensionEntry); | ||
| // will handle toasts and also set failures to enabled = false | ||
| await addToAgentOnStartup({ addToConfig: addExtension, extensionConfig }); | ||
| } else { | ||
| // Missing configuration, show onboarding | ||
| console.log('Missing configuration, showing onboarding'); | ||
| if (!provider) console.log('Missing provider'); | ||
| if (!model) console.log('Missing model'); | ||
| setView('welcome'); | ||
| console.log(`Skipping disabled extension: ${extensionEntry.name}`); | ||
| } | ||
| } catch (error) { | ||
| console.error('Error initializing app:', error); | ||
| console.error('App initialization error details:', { | ||
| message: error.message, | ||
| stack: error.stack, | ||
| name: error.name, | ||
| }); | ||
| setFatalError(`Alpha initialization error: ${error.message || 'Unknown error'}`); | ||
| setView('welcome'); | ||
| } | ||
|
|
||
| console.log('Extensions setup complete'); | ||
| }; | ||
|
|
||
| // Execute with better promise handling | ||
| initializeApp() | ||
| .then(() => console.log('Alpha app initialization complete')) | ||
| .catch((error) => { | ||
| console.error('Unhandled error in initializeApp:', error); | ||
| setFatalError(`Unhandled alpha app error: ${error.message || 'Unknown error'}`); | ||
| }); | ||
|
|
||
| setupExtensions() | ||
| .then(() => console.log('Extensions setup complete')) | ||
| .catch((error) => { | ||
| console.error('Unhandled error in setupExtensions:', error); | ||
| // Not setting fatal error here since extensions are optional | ||
| }); | ||
| }, []); // Empty dependency array since we're using initAttemptedRef | ||
| // Execute the two flows in parallel for speed | ||
| checkRequiredConfig().catch((error) => { | ||
| console.error('Unhandled error in checkRequiredConfig:', error); | ||
| setFatalError(`Config check error: ${error.message || 'Unknown error'}`); | ||
| }); | ||
|
|
||
| setupExtensions().catch((error) => { | ||
| console.error('Unhandled error in setupExtensions:', error); | ||
| // Not setting fatal error here since extensions are optional | ||
| }); | ||
| }, []); // Empty dependency array since we're using initAttemptedRef | ||
| const setView = (view: View, viewOptions: Record<any, any> = {}) => { | ||
|
Check warning on line 191 in ui/desktop/src/App.tsx
|
||
| console.log(`Setting view to: ${view}`, viewOptions); | ||
| setInternalView({ view, viewOptions }); | ||
| }; | ||
|
|
@@ -215,7 +231,7 @@ | |
|
|
||
| useEffect(() => { | ||
| console.log('Setting up fatal error handler'); | ||
| const handleFatalError = (_: any, errorMessage: string) => { | ||
| console.error('Encountered a fatal error: ', errorMessage); | ||
| // Log additional context that might help diagnose the issue | ||
| console.error('Current view:', view); | ||
|
|
@@ -252,7 +268,7 @@ | |
| // TODO: modify | ||
| useEffect(() => { | ||
| console.log('Setting up extension handler'); | ||
| const handleAddExtension = (_: any, link: string) => { | ||
| try { | ||
| console.log(`Received add-extension event with link: ${link}`); | ||
| const command = extractCommand(link); | ||
|
|
@@ -376,7 +392,7 @@ | |
| console.error('ASYNC SETUP ERROR:', err); | ||
| setFatalError(`Async setup error: ${err.message || 'Unknown error'}`); | ||
| }); | ||
| }, []); | ||
|
|
||
| // keep | ||
| if (fatalError) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rearranged code into this otherwise we were stuck on onboarding page until extensions finished loading