Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 77 additions & 61 deletions ui/desktop/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ import ProviderSettings from './components/settings_v2/providers/ProviderSetting
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 =
Expand Down Expand Up @@ -74,6 +76,8 @@ export default function App() {
}

// 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) {
Expand All @@ -82,24 +86,68 @@ export default function App() {

console.log('Alpha flow initializing...');

const setupExtensions = async () => {
// First quickly check if we have model and provider to set chat view
const checkRequiredConfig = async () => {

Copy link
Copy Markdown
Contributor Author

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

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;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The 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);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conceptual question.

If refreshedExtensions comes back the first time you ever boot the app as empty, is it any different/required to have a separate initializeBuiltInExtensions function? Could we just use a single syncBuiltInExtensions that behaves the same was as initialize if there were no extensions to begin with?

(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...');
Expand All @@ -109,69 +157,37 @@ export default function App() {
}
} 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> = {}) => {
console.log(`Setting view to: ${view}`, viewOptions);
setInternalView({ view, viewOptions });
Expand Down
4 changes: 0 additions & 4 deletions ui/desktop/src/components/settings_v2/SettingsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ export default function SettingsView({
setView: (view: View) => void;
viewOptions: SettingsViewOptions;
}) {
const { config } = useConfig();

console.log(config);

return (
<div className="h-screen w-full">
<div className="relative flex items-center h-[36px] w-full bg-bgSubtle"></div>
Expand Down
Loading