mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-19 10:02:16 +00:00
feat(desktop): support connecting to a remote Hermes backend
Add HERMES_DESKTOP_REMOTE_URL and HERMES_DESKTOP_REMOTE_TOKEN env vars that, when set, short-circuit the local-child spawn in startHermes() and connect the Electron renderer to an already- running 'hermes dashboard' server reachable over the network. Motivating use case: WSL2 users who want to run the Hermes core (agent loop, tools, filesystem access) inside their WSL distribution while rendering the Electron GUI on native Windows. Before this change, the desktop app always spawned a local Python child on the same host as the renderer, which doesn't cross the WSL/Windows boundary. The remote path reuses waitForHermes() as a liveness probe (/api/status is in the backend's public endpoint allowlist), so the connection is only returned once the backend is actually ready. WebSocket URL derivation picks ws:// or wss:// based on the input scheme. URL validation rejects non-http(s) schemes and requires both env vars together to avoid a half-configured connection that would silently fall through to the spawn path. No behaviour change when the env vars are unset — the default local-spawn flow is untouched. Typical usage: # in WSL2 hermes dashboard --tui --no-open --host 0.0.0.0 --port 9119 --insecure # on Windows set HERMES_DESKTOP_REMOTE_URL=http://localhost:9119 set HERMES_DESKTOP_REMOTE_TOKEN=<session token> set HERMES_DESKTOP_IGNORE_EXISTING=1 (launch Hermes desktop)
This commit is contained in:
parent
2964f25534
commit
3aabae20eb
1 changed files with 47 additions and 0 deletions
|
|
@ -1068,9 +1068,56 @@ function installMediaPermissions() {
|
|||
})
|
||||
}
|
||||
|
||||
function resolveRemoteBackend() {
|
||||
const rawUrl = process.env.HERMES_DESKTOP_REMOTE_URL
|
||||
const rawToken = process.env.HERMES_DESKTOP_REMOTE_TOKEN
|
||||
if (!rawUrl) return null
|
||||
if (!rawToken) {
|
||||
throw new Error(
|
||||
'HERMES_DESKTOP_REMOTE_URL is set but HERMES_DESKTOP_REMOTE_TOKEN is not. ' +
|
||||
'Both must be provided to connect to a remote Hermes backend.'
|
||||
)
|
||||
}
|
||||
|
||||
let parsed
|
||||
try {
|
||||
parsed = new URL(rawUrl)
|
||||
} catch (error) {
|
||||
throw new Error(`HERMES_DESKTOP_REMOTE_URL is not a valid URL: ${error.message}`)
|
||||
}
|
||||
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
||||
throw new Error(`HERMES_DESKTOP_REMOTE_URL must be http:// or https://, got ${parsed.protocol}`)
|
||||
}
|
||||
|
||||
const baseUrl = `${parsed.protocol}//${parsed.host}`
|
||||
const wsScheme = parsed.protocol === 'https:' ? 'wss' : 'ws'
|
||||
const wsUrl = `${wsScheme}://${parsed.host}/api/ws?token=${encodeURIComponent(rawToken)}`
|
||||
|
||||
return { baseUrl, token: rawToken, wsUrl }
|
||||
}
|
||||
|
||||
async function startHermes() {
|
||||
if (connectionPromise) return connectionPromise
|
||||
|
||||
const remote = resolveRemoteBackend()
|
||||
if (remote) {
|
||||
connectionPromise = (async () => {
|
||||
rememberLog(`Using remote Hermes backend at ${remote.baseUrl}`)
|
||||
await waitForHermes(remote.baseUrl, remote.token)
|
||||
return {
|
||||
baseUrl: remote.baseUrl,
|
||||
token: remote.token,
|
||||
wsUrl: remote.wsUrl,
|
||||
logs: hermesLog.slice(-80),
|
||||
windowButtonPosition: getWindowButtonPosition()
|
||||
}
|
||||
})().catch(error => {
|
||||
connectionPromise = null
|
||||
throw error
|
||||
})
|
||||
return connectionPromise
|
||||
}
|
||||
|
||||
connectionPromise = (async () => {
|
||||
const port = await pickPort()
|
||||
const token = crypto.randomBytes(32).toString('base64url')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue