mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-16 09:31:37 +00:00
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:
parent
e31b74073b
commit
7d652fc466
3 changed files with 67 additions and 7 deletions
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -4657,6 +4657,34 @@ def _(rid, params: dict) -> dict:
|
|||
return _err(rid, 5016, str(e))
|
||||
|
||||
|
||||
@method("setup.runtime_check")
|
||||
def _(rid, params: dict) -> dict:
|
||||
"""Strict provider check: does the configured/default model actually resolve to a usable runtime?
|
||||
|
||||
Unlike setup.status (which returns True if ANY provider auth state is
|
||||
discoverable, including indirect fallbacks like ``gh auth token`` for
|
||||
Copilot), this runs the same resolve_runtime_provider() call the agent
|
||||
uses on session creation. It returns ok=False with the auth error message
|
||||
when the user's configured model cannot actually be served, so UIs can
|
||||
surface onboarding before the user submits a doomed prompt.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.runtime_provider import resolve_runtime_provider
|
||||
|
||||
runtime = resolve_runtime_provider(requested=None)
|
||||
return _ok(
|
||||
rid,
|
||||
{
|
||||
"ok": True,
|
||||
"provider": runtime.get("provider"),
|
||||
"model": runtime.get("model"),
|
||||
"source": runtime.get("source"),
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
return _ok(rid, {"ok": False, "error": str(e)})
|
||||
|
||||
|
||||
# ── Methods: tools & system ──────────────────────────────────────────
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue