mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-27 11:22:03 +00:00
fix(desktop): route gateway restart / status / update to the active profile
restartGateway, getActionStatus, getStatus, updateHermes and
checkHermesUpdate all hit window.hermesDesktop.api WITHOUT spreading
profileScoped() — unlike their siblings (getModelInfo, setModelAssignment,
grantComputerUsePermissions). _apiProfile tracks the active gateway
profile, and the Electron proxy uses request.profile to pick which pooled
/ remote backend serves the call.
So for a multi-profile or global-remote user, the System-panel "Restart
gateway" (and its status poll, plus Update / status reads) targeted the
primary/default backend instead of the one they're on: the restart hit
the wrong gateway and the poll never saw the action → it looked like
restart silently failed. Single-profile users are unaffected
(profileScoped() returns {} when no profile is active).
Add ...profileScoped() to the five backend-action helpers so they follow
the active profile like the rest of the API surface.
This commit is contained in:
parent
d335164833
commit
65b13e9dbc
2 changed files with 54 additions and 0 deletions
49
apps/desktop/src/hermes-profile-scope.test.ts
Normal file
49
apps/desktop/src/hermes-profile-scope.test.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import {
|
||||
checkHermesUpdate,
|
||||
getActionStatus,
|
||||
getStatus,
|
||||
restartGateway,
|
||||
setApiRequestProfile,
|
||||
updateHermes
|
||||
} from './hermes'
|
||||
|
||||
// Contract: every backend-targeted action helper must carry the active gateway
|
||||
// profile, so a multi-profile / global-remote user's restart, status poll, and
|
||||
// update hit the backend they're actually on — not the primary/default. The
|
||||
// System-panel "restart does nothing" bug was these helpers dropping it.
|
||||
describe('backend action helpers are profile-scoped', () => {
|
||||
const api = vi.fn(async (_req: { path: string; profile?: string }) => ({}) as never)
|
||||
|
||||
beforeEach(() => {
|
||||
;(window as { hermesDesktop?: unknown }).hermesDesktop = { api }
|
||||
api.mockClear()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
setApiRequestProfile(null)
|
||||
delete (window as { hermesDesktop?: unknown }).hermesDesktop
|
||||
})
|
||||
|
||||
const lastProfile = () => api.mock.calls.at(-1)?.[0].profile
|
||||
|
||||
it('omits profile when none is active (single-profile users unaffected)', () => {
|
||||
void getStatus()
|
||||
expect(lastProfile()).toBeUndefined()
|
||||
})
|
||||
|
||||
it('forwards the active profile to every backend action', () => {
|
||||
setApiRequestProfile('coder')
|
||||
|
||||
void getStatus()
|
||||
void restartGateway()
|
||||
void updateHermes()
|
||||
void checkHermesUpdate()
|
||||
void getActionStatus('gateway-restart')
|
||||
|
||||
for (const call of api.mock.calls) {
|
||||
expect(call[0].profile).toBe('coder')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
@ -274,6 +274,7 @@ export function getGlobalModelInfo(): Promise<ModelInfoResponse> {
|
|||
|
||||
export function getStatus(): Promise<StatusResponse> {
|
||||
return window.hermesDesktop.api<StatusResponse>({
|
||||
...profileScoped(),
|
||||
path: '/api/status'
|
||||
})
|
||||
}
|
||||
|
|
@ -756,6 +757,7 @@ export function setModelAssignment(body: ModelAssignmentRequest): Promise<ModelA
|
|||
|
||||
export function restartGateway(): Promise<ActionResponse> {
|
||||
return window.hermesDesktop.api<ActionResponse>({
|
||||
...profileScoped(),
|
||||
path: '/api/gateway/restart',
|
||||
method: 'POST'
|
||||
})
|
||||
|
|
@ -763,6 +765,7 @@ export function restartGateway(): Promise<ActionResponse> {
|
|||
|
||||
export function updateHermes(): Promise<ActionResponse> {
|
||||
return window.hermesDesktop.api<ActionResponse>({
|
||||
...profileScoped(),
|
||||
path: '/api/hermes/update',
|
||||
method: 'POST'
|
||||
})
|
||||
|
|
@ -773,12 +776,14 @@ export function updateHermes(): Promise<ActionResponse> {
|
|||
* distinct from the Electron client clone's git state. */
|
||||
export function checkHermesUpdate(force = false): Promise<BackendUpdateCheckResponse> {
|
||||
return window.hermesDesktop.api<BackendUpdateCheckResponse>({
|
||||
...profileScoped(),
|
||||
path: `/api/hermes/update/check${force ? '?force=true' : ''}`
|
||||
})
|
||||
}
|
||||
|
||||
export function getActionStatus(name: string, lines = 200): Promise<ActionStatusResponse> {
|
||||
return window.hermesDesktop.api<ActionStatusResponse>({
|
||||
...profileScoped(),
|
||||
path: `/api/actions/${encodeURIComponent(name)}/status?lines=${Math.max(1, lines)}`
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue