Files
hermes-agent/apps/desktop/electron/api-expected-404.test.ts
hernanda-git 65db662577 fix(desktop): stop logging a handler stack for expected session-probe 404s
resolveStoredSession() is a probe ladder — cache, then a by-id GET on the
active backend, then the same GET scoped to each other profile until one
hits. A miss on rungs 2 and 3 is expected and already handled: the backend
answers 404 {"detail":"Session not found"} and the renderer falls to the
next rung.

But ipcMain.handle logs "Error occurred in handler for 'hermes:api'" with a
full stack for every rejected invoke, with no per-handler opt-out — so each
designed fall-through printed a multi-line stack on startup and on every
session switch, burying real hermes:api failures.

Extract the handler body, and for that one expected case resolve with a
sentinel instead of rejecting; preload — our own code on the other side of
the same seam — rethrows it as an Error with the identical '404: <body>'
message. The renderer contract is byte-identical (the ladder and its tests
are untouched); only Electron's logging is bypassed. Every other failure
still rejects and still logs in full.

The sentinel check is deliberately narrow (a plain object whose only key is
the sentinel, with a string value) so no backend payload can be mistaken
for one.

Fixes #79265
2026-10-01 04:50:03 -05:00

61 lines
2.0 KiB
TypeScript

import assert from 'node:assert/strict'
import { test } from 'vitest'
import { HERMES_API_EXPECTED_404, isExpectedNotFoundSentinel, unwrapExpectedNotFound } from './api-expected-404'
test('a handler-produced sentinel is recognized', () => {
assert.equal(isExpectedNotFoundSentinel({ [HERMES_API_EXPECTED_404]: '404: {"detail":"Session not found"}' }), true)
})
test('real backend payloads are never mistaken for a sentinel', () => {
const notSentinels: unknown[] = [
null,
undefined,
'string',
42,
[],
[{ [HERMES_API_EXPECTED_404]: 'x' }],
{},
{ session_id: 's1' },
// right key, wrong value type
{ [HERMES_API_EXPECTED_404]: 404 },
// right key, but carries real data alongside — not our shape
{ [HERMES_API_EXPECTED_404]: 'x', session_id: 's1' }
]
for (const value of notSentinels) {
assert.equal(isExpectedNotFoundSentinel(value), false, `treated ${JSON.stringify(value)} as a sentinel`)
}
})
test('unwrap rethrows the sentinel as the exact rejection the renderer expects', () => {
const message = '404: {"detail":"Session not found"}'
assert.throws(
() => unwrapExpectedNotFound({ [HERMES_API_EXPECTED_404]: message }),
(error: Error) => error instanceof Error && error.message === message
)
})
test('unwrap passes real responses through untouched, by reference', () => {
const payload = { session_id: 's1', messages: [] }
assert.equal(unwrapExpectedNotFound(payload), payload)
assert.equal(unwrapExpectedNotFound(null), null)
assert.equal(unwrapExpectedNotFound(''), '')
})
test('the rethrown message still matches the renderer 404 probe predicate', () => {
// `resolveStoredSession` and friends branch on a `404`-shaped message; the
// seam must not change what they see.
const message = '404: {"detail":"Session not found"}'
try {
unwrapExpectedNotFound({ [HERMES_API_EXPECTED_404]: message })
assert.fail('expected a rejection')
} catch (error) {
assert.match(String((error as Error).message), /(?:^|\s)404\b/)
}
})