mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-15 14:22:43 +00:00
refactor(desktop): DRY the cloud helpers
Tighten the salvaged Hermes Cloud code with no behavior change: - main: one `trimCloudOrg` projection reused by the success-echo and the 409 org list (drop the duplicated map), and a `cloudLoginError()` factory for the three needsCloudLogin throw sites. - renderer: a `cloudLoginLapsed()` predicate for the duplicated needsCloudLogin→signed-out check.
This commit is contained in:
parent
2d315d30f8
commit
0ff097439e
2 changed files with 29 additions and 24 deletions
|
|
@ -5552,6 +5552,20 @@ function openPortalLoginWindow() {
|
|||
})
|
||||
}
|
||||
|
||||
// A "portal session is gone, re-login" error the renderer flips to signed-out
|
||||
// on (via the `needsCloudLogin` tag). `cause` chains the underlying 401 when
|
||||
// the session lapsed mid-flight.
|
||||
function cloudLoginError(message, cause?) {
|
||||
const err = new Error(message) as any
|
||||
err.needsCloudLogin = true
|
||||
|
||||
if (cause) {
|
||||
err.cause = cause
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Discover the hosted (Hermes Cloud) agents the signed-in user can see. Calls
|
||||
// the NAS trimmed-summary endpoint over the partition-bound net, so the portal
|
||||
// session cookie is attached automatically (no bearer needed — NAS accepts the
|
||||
|
|
@ -5564,11 +5578,9 @@ async function discoverCloudAgents(org?: string) {
|
|||
const portalBaseUrl = resolvePortalBaseUrl()
|
||||
|
||||
if (!(await hasLivePortalSession())) {
|
||||
const err = new Error(
|
||||
throw cloudLoginError(
|
||||
'You are not signed in to Hermes Cloud. Open Settings → Gateway, choose Hermes Cloud, and sign in.'
|
||||
) as any
|
||||
err.needsCloudLogin = true
|
||||
throw err
|
||||
)
|
||||
}
|
||||
|
||||
const orgQuery = org ? `?org=${encodeURIComponent(org)}` : ''
|
||||
|
|
@ -5583,10 +5595,7 @@ async function discoverCloudAgents(org?: string) {
|
|||
// A 401 means the portal session lapsed between the liveness check and the
|
||||
// call — surface it as a re-login, not a generic failure.
|
||||
if (error && error.statusCode === 401) {
|
||||
const err = new Error('Your Hermes Cloud session has expired. Open Settings → Gateway and sign in again.') as any
|
||||
err.needsCloudLogin = true
|
||||
err.cause = error
|
||||
throw err
|
||||
throw cloudLoginError('Your Hermes Cloud session has expired. Open Settings → Gateway and sign in again.', error)
|
||||
}
|
||||
|
||||
// A 409 means we're a multi-org user who hasn't picked an org. The body
|
||||
|
|
@ -5607,8 +5616,10 @@ async function discoverCloudAgents(org?: string) {
|
|||
return { agents: trimCloudAgents(body), org: trimCloudOrg(body?.org) }
|
||||
}
|
||||
|
||||
// Project a NAS response org ({ id, slug, name, isPersonal }) to the trimmed
|
||||
// shape the renderer persists, or null when absent/malformed.
|
||||
// Project a NAS org row ({ id, slug, name, isPersonal, role }) to the trimmed
|
||||
// shape the renderer consumes/persists, or null when absent/malformed. Shared
|
||||
// by the success-body echo (trimCloudOrg) and the 409 org list, so the two can
|
||||
// never drift.
|
||||
function trimCloudOrg(org) {
|
||||
if (!org || typeof org !== 'object' || typeof org.id !== 'string') {
|
||||
return null
|
||||
|
|
@ -5646,15 +5657,7 @@ function parseOrgSelectionError(error) {
|
|||
return null
|
||||
}
|
||||
|
||||
return parsed.orgs
|
||||
.filter(o => o && typeof o === 'object' && typeof o.id === 'string')
|
||||
.map(o => ({
|
||||
id: o.id,
|
||||
slug: typeof o.slug === 'string' ? o.slug : null,
|
||||
name: typeof o.name === 'string' ? o.name : o.id,
|
||||
isPersonal: Boolean(o.isPersonal),
|
||||
role: typeof o.role === 'string' ? o.role : 'MEMBER'
|
||||
}))
|
||||
return parsed.orgs.map(trimCloudOrg).filter(Boolean)
|
||||
}
|
||||
|
||||
// Project NAS's agent rows to the trimmed DTO the renderer consumes.
|
||||
|
|
@ -5688,9 +5691,7 @@ async function cloudAgentSilentSignIn(dashboardUrl) {
|
|||
// interactive prompt rather than a silent cascade. Discovery already gates on
|
||||
// this, but a selection can arrive after the session lapsed.
|
||||
if (!(await hasLivePortalSession())) {
|
||||
const err = new Error('Your Hermes Cloud session has expired. Sign in to Hermes Cloud again.') as any
|
||||
err.needsCloudLogin = true
|
||||
throw err
|
||||
throw cloudLoginError('Your Hermes Cloud session has expired. Sign in to Hermes Cloud again.')
|
||||
}
|
||||
|
||||
await openOauthLoginWindow(baseUrl, { silent: true })
|
||||
|
|
|
|||
|
|
@ -428,6 +428,10 @@ export function GatewaySettings() {
|
|||
|
||||
// --- Hermes Cloud handlers ---
|
||||
|
||||
// A rejected cloud IPC call tagged `needsCloudLogin` means the portal session
|
||||
// lapsed — treat it as signed-out so the panel falls back to the sign-in view.
|
||||
const cloudLoginLapsed = (err: unknown) => Boolean(err && typeof err === 'object' && 'needsCloudLogin' in err)
|
||||
|
||||
// Pull the discovered agent list over the shared portal session. Tolerant of
|
||||
// a lapsed session: a needsCloudLogin error flips us back to signed-out.
|
||||
// `org` scopes discovery for multi-org users; when discovery comes back with
|
||||
|
|
@ -475,7 +479,7 @@ export function GatewaySettings() {
|
|||
setCloudDiscover('error')
|
||||
|
||||
// A lapsed/absent portal session means we're effectively signed out.
|
||||
if (err && typeof err === 'object' && 'needsCloudLogin' in err) {
|
||||
if (cloudLoginLapsed(err)) {
|
||||
setCloudSignedIn(false)
|
||||
}
|
||||
|
||||
|
|
@ -644,7 +648,7 @@ export function GatewaySettings() {
|
|||
setState(next)
|
||||
notify({ kind: 'success', title: g.cloudConnectedTitle, message: g.cloudConnectedTo(agent.name) })
|
||||
} catch (err) {
|
||||
if (err && typeof err === 'object' && 'needsCloudLogin' in err) {
|
||||
if (cloudLoginLapsed(err)) {
|
||||
setCloudSignedIn(false)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue