fix(desktop): use strict runtime check to drive onboarding
setup.status returned True whenever any provider auth state was discoverable, including indirect fallbacks like a gh-CLI Copilot token. That made desktop think the user was set up while the agent's actual resolve_runtime_provider call still raised AuthError, leaving the user with a useless toast and no onboarding. Add a setup.runtime_check gateway method that runs the same resolver the agent uses on session creation, and switch the desktop onboarding overlay and prompt precheck to use it.
This commit is contained in:
@@ -50,10 +50,15 @@ interface SetupStatus {
|
||||
provider_configured?: boolean
|
||||
}
|
||||
|
||||
interface RuntimeCheck {
|
||||
error?: string
|
||||
ok?: boolean
|
||||
}
|
||||
|
||||
function isProviderSetupError(error: unknown) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
|
||||
return /No inference provider configured|OPENROUTER_API_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY/i.test(message)
|
||||
return /No inference provider configured|OPENROUTER_API_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY|set an API key/i.test(message)
|
||||
}
|
||||
|
||||
interface PromptActionsOptions {
|
||||
@@ -227,11 +232,18 @@ export function usePromptActions({
|
||||
setAwaitingResponse(true)
|
||||
clearNotifications()
|
||||
|
||||
const setup = await requestGateway<SetupStatus>('setup.status').catch(() => null)
|
||||
const [setup, runtime] = await Promise.all([
|
||||
requestGateway<SetupStatus>('setup.status').catch(() => null),
|
||||
requestGateway<RuntimeCheck>('setup.runtime_check').catch(() => null)
|
||||
])
|
||||
|
||||
if (setup?.provider_configured === false) {
|
||||
const runtimeReady = runtime?.ok !== undefined ? Boolean(runtime?.ok) : setup?.provider_configured !== false
|
||||
|
||||
if (!runtimeReady) {
|
||||
releaseBusy()
|
||||
requestDesktopOnboarding('Add a provider credential before sending your first message.')
|
||||
requestDesktopOnboarding(
|
||||
runtime?.error || 'Add a provider credential before sending your first message.'
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -20,6 +20,13 @@ interface SetupStatus {
|
||||
provider_configured?: boolean
|
||||
}
|
||||
|
||||
interface RuntimeCheck {
|
||||
error?: string
|
||||
model?: string
|
||||
ok?: boolean
|
||||
provider?: string
|
||||
}
|
||||
|
||||
interface ProviderOption {
|
||||
key: string
|
||||
label: string
|
||||
@@ -90,17 +97,30 @@ export function DesktopOnboardingOverlay({
|
||||
setError(null)
|
||||
|
||||
try {
|
||||
const [status, vars] = await Promise.all([requestGateway<SetupStatus>('setup.status'), getEnvVars()])
|
||||
const [status, runtime, vars] = await Promise.all([
|
||||
requestGateway<SetupStatus>('setup.status').catch(() => ({}) as SetupStatus),
|
||||
requestGateway<RuntimeCheck>('setup.runtime_check').catch(() => ({ ok: false }) as RuntimeCheck),
|
||||
getEnvVars()
|
||||
])
|
||||
|
||||
if (cancelled) {
|
||||
return
|
||||
}
|
||||
|
||||
setProviderConfigured(Boolean(status.provider_configured))
|
||||
// The strict runtime check is the source of truth: it runs the same
|
||||
// resolver the agent uses, so it can't be fooled by fallbacks like
|
||||
// gh-CLI Copilot tokens when the user's configured model isn't a
|
||||
// Copilot model. setup.status is kept as a coarse sanity check
|
||||
// for backends that don't expose setup.runtime_check yet.
|
||||
const runtimeOk = runtime.ok !== undefined ? Boolean(runtime.ok) : Boolean(status.provider_configured)
|
||||
|
||||
setProviderConfigured(runtimeOk)
|
||||
setEnvVars(vars)
|
||||
|
||||
if (status.provider_configured) {
|
||||
if (runtimeOk) {
|
||||
completeDesktopOnboarding()
|
||||
} else if (runtime.error) {
|
||||
setError(runtime.error)
|
||||
}
|
||||
|
||||
const firstAvailable = PREFERRED_PROVIDER_KEYS.find(option => vars[option.key])
|
||||
|
||||
Reference in New Issue
Block a user