alexhancock/extension-init-cleanup (#1890)

This commit is contained in:
Alex Hancock
2025-03-27 16:47:38 -04:00
committed by GitHub
parent 9c290c569f
commit 6bd4f36331
2 changed files with 49 additions and 214 deletions
+43 -211
View File
@@ -72,116 +72,6 @@ export default function App() {
const { getExtensions, addExtension, read } = useConfig(); const { getExtensions, addExtension, read } = useConfig();
const initAttemptedRef = useRef(false); const initAttemptedRef = useRef(false);
useEffect(() => {
// Skip if feature flag is not enabled
if (!process.env.ALPHA) {
return;
}
console.log('Alpha flow initializing...');
// First quickly check if we have model and provider to set chat view
const checkRequiredConfig = async () => {
try {
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');
}
};
// Setup extensions in parallel
const setupExtensions = async () => {
// Set the ref immediately to prevent duplicate runs
initAttemptedRef.current = true;
let refreshedExtensions: FixedExtensionEntry[] = [];
try {
// Force refresh extensions from the backend to ensure we have the latest
console.log('Getting extensions from backend...');
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);
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...');
console.log('Current extensions:', refreshedExtensions);
await syncBuiltInExtensions(refreshedExtensions, addExtension);
console.log('Built-in extensions sync complete');
}
} catch (error) {
console.error('Error setting up extensions:', error);
// We don't set fatal error here since the app might still work without extensions
}
// 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 {
console.log(`Skipping disabled extension: ${extensionEntry.name}`);
}
}
console.log('Extensions setup complete');
};
// 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
// Utility function to extract the command from the link // Utility function to extract the command from the link
function extractCommand(link: string): string { function extractCommand(link: string): string {
const url = new URL(link); const url = new URL(link);
@@ -190,133 +80,75 @@ export default function App() {
return `${cmd} ${args.join(' ')}`.trim(); return `${cmd} ${args.join(' ')}`.trim();
} }
// this is all settings v2 stuff
// Modified version of the alpha initialization flow for App.tsx
useEffect(() => { useEffect(() => {
// Skip if feature flag is not enabled
if (!process.env.ALPHA) { if (!process.env.ALPHA) {
return; return;
} }
console.log('Alpha flow initializing...'); // Guard against multiple initialization attempts
if (initAttemptedRef.current) {
console.log('Initialization already attempted, skipping...');
return;
}
initAttemptedRef.current = true;
// First quickly check if we have model and provider to set chat view console.log(`Initializing app in alpha mode...`);
const checkRequiredConfig = async () => {
const initializeApp = async () => {
try { try {
console.log('Reading GOOSE_PROVIDER and GOOSE_MODEL from config...'); const config = window.electron.getConfig();
const provider = (await read('GOOSE_PROVIDER', false)) as string; const provider = config.GOOSE_PROVIDER ?? (await read('GOOSE_PROVIDER', false));
const model = (await read('GOOSE_MODEL', false)) as string; const model = config.GOOSE_MODEL ?? (await read('GOOSE_MODEL', false));
if (provider && model) { if (provider && model) {
// We have all needed configuration, set chat view immediately console.log(`Using provider: ${provider}, model: ${model}`);
console.log(`Found provider: ${provider}, model: ${model}, setting chat view`);
setView('chat'); setView('chat');
// Initialize the system and wait for it to complete before setting up extensions
try { try {
console.log('Initializing system before setting up extensions...');
await initializeSystem(provider, model); await initializeSystem(provider, model);
console.log('System initialization successful');
// Now that the agent is initialized, we can safely set up extensions // Initialize or sync built-in extensions into config.yaml
return true; let refreshedExtensions = await getExtensions(true);
if (refreshedExtensions.length === 0) {
await initializeBuiltInExtensions(addExtension);
refreshedExtensions = await getExtensions(true);
} else {
await syncBuiltInExtensions(refreshedExtensions, addExtension);
}
// Add enabled extensions to agent
for (const extensionEntry of refreshedExtensions) {
if (extensionEntry.enabled) {
const extensionConfig = extractExtensionConfig(extensionEntry);
await addToAgentOnStartup({ addToConfig: addExtension, extensionConfig });
}
}
} catch (error) { } catch (error) {
console.error('Error initializing system:', error); console.error('Error in alpha initialization:', error);
setFatalError(`System initialization error: ${error.message || 'Unknown error'}`); setFatalError(`System initialization error: ${error.message || 'Unknown error'}`);
setView('welcome'); setView('welcome');
return false;
} }
} else { } else {
// Missing configuration, show onboarding console.log('Missing required configuration, showing onboarding');
console.log('Missing configuration, showing onboarding');
if (!provider) console.log('Missing provider');
if (!model) console.log('Missing model');
setView('welcome'); setView('welcome');
return false;
} }
} catch (error) { } catch (error) {
console.error('Error checking configuration:', error); console.error('Error in alpha config check:', error);
setFatalError(`Configuration check error: ${error.message || 'Unknown error'}`); setFatalError(`Configuration error: ${error.message || 'Unknown error'}`);
setView('welcome'); setView('welcome');
return false;
}
};
// Setup extensions after agent is initialized
const setupExtensions = async () => {
// Set the ref immediately to prevent duplicate runs
initAttemptedRef.current = true;
let refreshedExtensions: FixedExtensionEntry[] = [];
try {
// Force refresh extensions from the backend to ensure we have the latest
console.log('Getting extensions from backend...');
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 // Reset toast service after initialization
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);
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...');
console.log('Current extensions:', refreshedExtensions);
await syncBuiltInExtensions(refreshedExtensions, addExtension);
console.log('Built-in extensions sync complete');
}
} catch (error) {
console.error('Error setting up extensions:', error);
// We don't set fatal error here since the app might still work without extensions
}
// 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 {
console.log(`Skipping disabled extension: ${extensionEntry.name}`);
}
}
console.log('Extensions setup complete');
// Reset the toast service silent flag to ensure toasts work after startup
toastService.configure({ silent: false }); toastService.configure({ silent: false });
}; };
// Execute the flows sequentially to ensure agent is initialized before adding extensions initializeApp().catch((error) => {
checkRequiredConfig() console.error('Unhandled error in initialization:', error);
.then((agentInitialized) => { setFatalError(`Initialization error: ${error.message || 'Unknown error'}`);
// Only proceed with extension setup if agent was successfully initialized });
if (agentInitialized) { }, []);
return setupExtensions();
}
console.log('Skipping extension setup because agent was not initialized');
return Promise.resolve();
})
.catch((error) => {
console.error('Unhandled error in startup sequence:', error);
setFatalError(`Startup error: ${error.message || 'Unknown error'}`);
});
}, []); // Empty dependency array since we're using initAttemptedRef
const setView = (view: View, viewOptions: Record<any, any> = {}) => { const setView = (view: View, viewOptions: Record<any, any> = {}) => {
console.log(`Setting view to: ${view}`, viewOptions); console.log(`Setting view to: ${view}`, viewOptions);
setInternalView({ view, viewOptions }); setInternalView({ view, viewOptions });
@@ -484,7 +316,7 @@ export default function App() {
return; return;
} }
console.log('Non-alpha flow initializing...'); console.log(`Initializing app in non-alpha mode...`);
// Attempt to detect config for a stored provider // Attempt to detect config for a stored provider
const detectStoredProvider = () => { const detectStoredProvider = () => {
+6 -3
View File
@@ -70,9 +70,12 @@ export const initializeSystem = async (provider: string, model: string) => {
console.log('initializing agent with provider', provider, 'model', model); console.log('initializing agent with provider', provider, 'model', model);
await initializeAgent({ provider, model }); await initializeAgent({ provider, model });
// Sync the model state with React // This will go away after the release of settings v2 as this is now handled in config.yaml
const syncedModel = syncModelWithAgent(provider, model); if (!process.env.ALPHA) {
console.log('Model synced with React state:', syncedModel); // Sync the model state with React
const syncedModel = syncModelWithAgent(provider, model);
console.log('Model synced with React state:', syncedModel);
}
// Get botConfig directly here // Get botConfig directly here
const botConfig = window.appConfig?.get?.('botConfig'); const botConfig = window.appConfig?.get?.('botConfig');