fix(tui): first-run setup preflight + actionable no-provider panel

- tui_gateway: new `setup.status` RPC that reuses CLI's
  `_has_any_provider_configured()`, so the TUI can ask the same question
  the CLI bootstrap asks before launching a session
- useSessionLifecycle: preflight `setup.status` before both `newSession`
  and `resumeById`, and render a clear "Setup Required" panel when no
  provider is configured instead of booting a session that immediately
  fails with `agent init failed`
- createGatewayEventHandler: drop duplicate startup resume logic in
  favor of the preflighted `resumeById`, and special-case the
  no-provider agent-init error as a last-mile fallback to the same
  setup panel
- add regression tests for both paths
This commit is contained in:
Brooklyn Nicholson 2026-04-17 10:58:01 -05:00
parent 5b386ced71
commit 0dd5055d59
9 changed files with 145 additions and 62 deletions

View file

@ -26,6 +26,7 @@ const buildCtx = (appended: Msg[]) =>
colsRef: ref(80),
newSession: vi.fn(),
resetSession: vi.fn(),
resumeById: vi.fn(),
setCatalog: vi.fn()
},
system: {
@ -34,6 +35,8 @@ const buildCtx = (appended: Msg[]) =>
},
transcript: {
appendMessage: (msg: Msg) => appended.push(msg),
panel: (title: string, sections: any[]) =>
appended.push({ kind: 'panel', panelData: { sections, title }, role: 'system', text: '' }),
setHistoryItems: vi.fn()
}
}) as any
@ -138,4 +141,24 @@ describe('createGatewayEventHandler', () => {
expect(appended[0]?.thinking).toBe(fromServer)
expect(appended[0]?.thinkingTokens).toBe(estimateTokensRough(fromServer))
})
it('shows setup panel for missing provider startup error', () => {
const appended: Msg[] = []
const onEvent = createGatewayEventHandler(buildCtx(appended))
onEvent({
payload: {
message:
'agent init failed: No LLM provider configured. Run `hermes model` to select a provider, or run `hermes setup` for first-time configuration.'
},
type: 'error'
} as any)
expect(appended).toHaveLength(1)
expect(appended[0]).toMatchObject({
kind: 'panel',
panelData: { title: 'Setup Required' },
role: 'system'
})
})
})