Skip to content

voice: announce LLM errors instead of silent 'thinking forever' (LLMErrorAnnouncer) #576

Description

@mabry1985

Problem

When the active LLM endpoint fails (auth 401, unreachable, timeout), the orb sits in "thinking" forever, silently. The StallWatchdog disarms on LLMFullResponseStartFrame (pushed before the HTTP call), and the resulting ErrorFrame flows upstream where nothing re-arms or reacts. The user gets no signal at all.

This is the worst first-run failure, and the free + OSS pivot makes it more acute: every user now wires their own LLM endpoint, so a misconfigured key / wrong URL (→ 401 / connection refused) is one of the most likely first-run states.

Secondary effect: a dead LLM + silence also trips wake auto-close, which masquerades as "the app keeps turning off."

Proposed fix — LLMErrorAnnouncer

A processor/observer that:

  1. Catches the upstream ErrorFrame from the active LLM service.
  2. Classifies it: auth (401/403) vs unreachable (connection/DNS/timeout) vs other.
  3. Speaks one throttled canned line via an out-of-band TTSSpeakFrame (append_to_context=False), e.g. "I can't reach my language model right now — check the endpoint in settings." Distinct copy per class.
  4. Re-arms the StallWatchdog (or otherwise clears the stuck "thinking" state) so the next turn is clean.

Notes / guardrails

  • Throttle hard (one line per N seconds) — a flapping endpoint must not spam.
  • Route the spoken line through TTS only (no LLM round-trip — the LLM is what's broken).
  • Pairs with the StallWatchdog; see STATUS.md 06-11 "Live incident during testing".

LOE: S–M. Priority: top of the audit/robustness list.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions