fix(desktop): suppress generic provider warning in onboarding

Hide the red setup notice when the message is the generic missing-provider guidance, since onboarding already presents provider auth actions. Centralize provider-setup matching across desktop hooks and add coverage for the matcher.
This commit is contained in:
Brooklyn Nicholson 2026-05-11 22:17:46 -04:00
parent 2252160dcf
commit 939ab58b8d
5 changed files with 44 additions and 8 deletions

View file

@ -15,6 +15,7 @@ import {
} from '@/lib/chat-messages'
import { coerceGatewayText, coerceThinkingText, normalizePersonalityValue } from '@/lib/chat-runtime'
import { triggerHaptic } from '@/lib/haptics'
import { isProviderSetupErrorMessage } from '@/lib/provider-setup-errors'
import { setClarifyRequest } from '@/store/clarify'
import { notify } from '@/store/notifications'
import { requestDesktopOnboarding } from '@/store/onboarding'
@ -35,9 +36,6 @@ import type { RpcEvent } from '@/types/hermes'
import type { ClientSessionState } from '../../types'
const PROVIDER_SETUP_ERROR_RE =
/No inference provider configured|no_provider_configured|OPENROUTER_API_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY|set an API key/i
interface MessageStreamOptions {
activeSessionIdRef: MutableRefObject<string | null>
hydrateFromStoredSession: (
@ -598,7 +596,7 @@ export function useMessageStream({
}
} else if (event.type === 'error') {
const errorMessage = payload?.message || 'Hermes reported an error'
const looksLikeProviderSetup = PROVIDER_SETUP_ERROR_RE.test(errorMessage)
const looksLikeProviderSetup = isProviderSetupErrorMessage(errorMessage)
if (looksLikeProviderSetup) {
requestDesktopOnboarding(errorMessage)

View file

@ -18,6 +18,7 @@ import {
isDesktopSlashCommand
} from '@/lib/desktop-slash-commands'
import { triggerHaptic } from '@/lib/haptics'
import { isProviderSetupErrorMessage } from '@/lib/provider-setup-errors'
import {
$composerAttachments,
addComposerAttachment,
@ -49,9 +50,7 @@ function blobToDataUrl(blob: Blob): Promise<string> {
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|set an API key/i.test(
message
)
return isProviderSetupErrorMessage(message)
}
interface PromptActionsOptions {

View file

@ -5,6 +5,7 @@ import { ModelPickerDialog } from '@/components/model-picker'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Check, ChevronLeft, ChevronRight, ExternalLink, KeyRound, Loader2, Sparkles } from '@/lib/icons'
import { isProviderSetupErrorMessage } from '@/lib/provider-setup-errors'
import { cn } from '@/lib/utils'
import { $desktopBoot, type DesktopBootState } from '@/store/boot'
import {
@ -137,7 +138,8 @@ export function DesktopOnboardingOverlay({ enabled, onCompleted, requestGateway
}
const { flow } = onboarding
const reason = onboarding.reason?.trim() || null
const rawReason = onboarding.reason?.trim() || null
const reason = rawReason && !isProviderSetupErrorMessage(rawReason) ? rawReason : null
const ready = enabled && onboarding.configured === false
const showPicker = flow.status === 'idle' || flow.status === 'success'

View file

@ -0,0 +1,25 @@
import { describe, expect, it } from 'vitest'
import { isProviderSetupErrorMessage } from './provider-setup-errors'
describe('isProviderSetupErrorMessage', () => {
it('matches generic missing-provider copy', () => {
expect(isProviderSetupErrorMessage('No inference provider configured. Run `hermes model` to choose one.')).toBe(true)
expect(isProviderSetupErrorMessage('No inference provider is configured.')).toBe(true)
expect(isProviderSetupErrorMessage('set an API key (OPENROUTER_API_KEY) in ~/.hermes/.env')).toBe(true)
})
it('does not match non-provider runtime failures', () => {
expect(
isProviderSetupErrorMessage(
'Selected runtime is not available. setup.status reports configured credentials.'
)
).toBe(false)
})
it('returns false for empty input', () => {
expect(isProviderSetupErrorMessage('')).toBe(false)
expect(isProviderSetupErrorMessage(null)).toBe(false)
expect(isProviderSetupErrorMessage(undefined)).toBe(false)
})
})

View file

@ -0,0 +1,12 @@
const PROVIDER_SETUP_ERROR_RE =
/No inference provider(?: is)? configured|no_provider_configured|OPENROUTER_API_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY|set an API key/i
export function isProviderSetupErrorMessage(message: null | string | undefined): boolean {
const text = message?.trim()
if (!text) {
return false
}
return PROVIDER_SETUP_ERROR_RE.test(text)
}