fix: error scenario when checking provider (#8394)
This commit is contained in:
@@ -33,7 +33,7 @@ interface ConfigContextType {
|
||||
extensionsList: FixedExtensionEntry[];
|
||||
extensionWarnings: string[];
|
||||
upsert: (key: string, value: unknown, is_secret: boolean) => Promise<void>;
|
||||
read: (key: string, is_secret: boolean) => Promise<unknown>;
|
||||
read: (key: string, is_secret: boolean, options?: { throwOnError?: boolean }) => Promise<unknown>;
|
||||
remove: (key: string, is_secret: boolean) => Promise<void>;
|
||||
addExtension: (name: string, config: ExtensionConfig, enabled: boolean) => Promise<void>;
|
||||
toggleExtension: (name: string) => Promise<void>;
|
||||
@@ -88,11 +88,14 @@ export const ConfigProvider: React.FC<ConfigProviderProps> = ({ children }) => {
|
||||
[reloadConfig]
|
||||
);
|
||||
|
||||
const read = useCallback(async (key: string, is_secret: boolean = false) => {
|
||||
const read = useCallback(async (key: string, is_secret: boolean = false, options?: { throwOnError?: boolean }) => {
|
||||
const query: ConfigKeyQuery = { key: key, is_secret: is_secret };
|
||||
const response = await readConfig({
|
||||
body: query,
|
||||
});
|
||||
if (options?.throwOnError && response.error) {
|
||||
throw response.error;
|
||||
}
|
||||
return response.data;
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom';
|
||||
import { useConfig } from '../ConfigContext';
|
||||
import { useModelAndProvider } from '../ModelAndProviderContext';
|
||||
import { Goose } from '../icons';
|
||||
import { Button } from '../ui/button';
|
||||
import ProviderSelector from './ProviderSelector';
|
||||
import OnboardingSuccess from './OnboardingSuccess';
|
||||
import {
|
||||
@@ -23,6 +24,18 @@ const i18n = defineMessages({
|
||||
id: 'onboardingGuard.welcomeDescription',
|
||||
defaultMessage: 'Your local AI agent. Connect an AI model provider to get started.',
|
||||
},
|
||||
checkProviderErrorTitle: {
|
||||
id: 'onboardingGuard.checkProviderErrorTitle',
|
||||
defaultMessage: 'Unable to connect to Goose server',
|
||||
},
|
||||
checkProviderErrorDescription: {
|
||||
id: 'onboardingGuard.checkProviderErrorDescription',
|
||||
defaultMessage: 'The server may be starting up or temporarily unavailable.',
|
||||
},
|
||||
retry: {
|
||||
id: 'onboardingGuard.retry',
|
||||
defaultMessage: 'Retry',
|
||||
},
|
||||
});
|
||||
|
||||
const TELEMETRY_CONFIG_KEY = 'GOOSE_TELEMETRY_ENABLED';
|
||||
@@ -39,6 +52,7 @@ export default function OnboardingGuard({ children }: OnboardingGuardProps) {
|
||||
|
||||
const [isCheckingProvider, setIsCheckingProvider] = useState(true);
|
||||
const [hasProvider, setHasProvider] = useState(false);
|
||||
const [checkProviderError, setCheckProviderError] = useState(false);
|
||||
const [hasSelection, setHasSelection] = useState(false);
|
||||
const [configuredProvider, setConfiguredProvider] = useState<string | null>(null);
|
||||
const [configuredProviderDisplayName, setConfiguredProviderDisplayName] = useState<string | null>(
|
||||
@@ -47,27 +61,37 @@ export default function OnboardingGuard({ children }: OnboardingGuardProps) {
|
||||
const [configuredModel, setConfiguredModel] = useState<string | null>(null);
|
||||
const hasTrackedOnboardingStart = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
const checkProvider = async () => {
|
||||
const checkProvider = async (retries = 3, delay = 1000) => {
|
||||
setIsCheckingProvider(true);
|
||||
setCheckProviderError(false);
|
||||
for (let attempt = 0; attempt <= retries; attempt++) {
|
||||
try {
|
||||
const provider = ((await read('GOOSE_PROVIDER', false)) as string) || '';
|
||||
setHasProvider(provider.trim() !== '');
|
||||
} catch (error) {
|
||||
console.error('Error checking provider:', error);
|
||||
setHasProvider(false);
|
||||
} finally {
|
||||
const provider = (await read('GOOSE_PROVIDER', false, { throwOnError: true })) as string | null;
|
||||
setHasProvider(!!provider?.trim());
|
||||
setIsCheckingProvider(false);
|
||||
return;
|
||||
} catch (error) {
|
||||
console.error(`Error checking provider (attempt ${attempt + 1}/${retries + 1}):`, error);
|
||||
if (attempt < retries) {
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
}
|
||||
}
|
||||
};
|
||||
checkProvider();
|
||||
}, [read]);
|
||||
}
|
||||
setCheckProviderError(true);
|
||||
setIsCheckingProvider(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isCheckingProvider && !hasProvider && !hasTrackedOnboardingStart.current) {
|
||||
checkProvider();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isCheckingProvider && !hasProvider && !checkProviderError && !hasTrackedOnboardingStart.current) {
|
||||
trackOnboardingStarted();
|
||||
hasTrackedOnboardingStart.current = true;
|
||||
}
|
||||
}, [isCheckingProvider, hasProvider]);
|
||||
}, [isCheckingProvider, hasProvider, checkProviderError]);
|
||||
|
||||
const handleConfigured = async (providerName: string, modelId?: string) => {
|
||||
trackOnboardingProviderSelected({ provider: providerName });
|
||||
@@ -107,6 +131,23 @@ export default function OnboardingGuard({ children }: OnboardingGuardProps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (checkProviderError) {
|
||||
return (
|
||||
<div className="h-screen w-full bg-background-default flex flex-col items-center justify-center">
|
||||
<div className="text-center max-w-md">
|
||||
<div className="mb-4">
|
||||
<Goose className="size-8 mx-auto" />
|
||||
</div>
|
||||
<h1 className="text-xl font-light mb-3">{intl.formatMessage(i18n.checkProviderErrorTitle)}</h1>
|
||||
<p className="text-text-muted mb-6">{intl.formatMessage(i18n.checkProviderErrorDescription)}</p>
|
||||
<Button onClick={() => checkProvider()}>
|
||||
{intl.formatMessage(i18n.retry)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (hasProvider) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
@@ -2387,6 +2387,15 @@
|
||||
"navigationStyleSelector.tileLabel": {
|
||||
"defaultMessage": "Tile"
|
||||
},
|
||||
"onboardingGuard.checkProviderErrorDescription": {
|
||||
"defaultMessage": "The server may be starting up or temporarily unavailable."
|
||||
},
|
||||
"onboardingGuard.checkProviderErrorTitle": {
|
||||
"defaultMessage": "Unable to connect to Goose server"
|
||||
},
|
||||
"onboardingGuard.retry": {
|
||||
"defaultMessage": "Retry"
|
||||
},
|
||||
"onboardingGuard.welcomeDescription": {
|
||||
"defaultMessage": "Your local AI agent. Connect an AI model provider to get started."
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user