hermes-agent/tui_gateway
teknium1 60c8fc6290 fix(gateway): deliver the first message when the deferred agent build outlives 30s (#63078)
Leg 2 of #63078: prompt.submit returns {"status":"streaming"} immediately and
runs _start_agent_build + _wait_agent(timeout=30s) behind it. The deferred
build (MCP discovery with per-server retry backoff, synchronous model-metadata
HTTP, skills scanning) routinely outlives 30s on cold starts; on timeout
run_after_agent_ready emitted an error EVENT and returned without ever calling
_run_prompt_submit — the user's first message was permanently discarded while
the build finished successfully in the background. The desktop's optimistic
row eventually cleared with no visible error: the blank first session.

New _wait_agent_for_prompt replaces the flat cliff for the deferred prompt
path only (_sess()'s RPC-blocking _wait_agent keeps its 30s contract):

- The pending prompt stays attached to the (already off-RPC) run thread and
  is delivered the moment the still-running build completes — a slow build is
  no longer message loss.
- The wait runs in 5s slices so a cancel (session.interrupt / churn) is
  honored promptly; the cancelled path returns None and defers to the
  caller's cancel branch (the #65567 emit) for user-visible messaging.
- Past 30s the client gets ONE keyed notification.show ('Still starting the
  agent…', key=agent-build-slow, desktop toast / TUI status bar), cleared on
  delivery — patient, never silent.
- Permanent failure only when the build itself fails: agent_error set at
  ready, the build thread died without signalling ready (fail fast via the
  new _agent_build_thread handle instead of sitting out the cap on a corpse),
  or the bounded cap expired on a genuinely hung build. The cap defaults to
  600s and is tunable via agent.build_wait_timeout in config.yaml (no new
  env vars); the error message states the message was not sent.

Tests: slow-build delivery with zero error events; the keyed progress notice
shown once and cleared; build-failure surfacing exactly one error event with
the real reason; dead-thread fail-fast; cancel honored mid-wait; config
override + fallback semantics; cap expiry message. The compute-host fallback
test stubs the new waiter alongside _wait_agent.
2026-07-24 21:40:08 -07:00
..
__init__.py feat: new tui based on ink 2026-04-02 19:07:53 -05:00
_stdin_recovery.py fix: Windows guard, dedup recovery, profile-safe paths, clear SO_RCVTIMEO 2026-07-20 12:48:50 +05:30
compute_host.py fix(windows): widen utf-8 subprocess decode guard to sibling desktop-backend sites 2026-07-24 09:48:28 -07:00
entry.py feat(themes): agent-authored skins switch live via a gateway skin watcher 2026-07-21 21:00:43 -05:00
event_publisher.py chore: address copilot comments 2026-04-24 12:51:04 -04:00
git_probe.py fix(windows): share one bounded, tree-killing git probe across both call sites (#68997) 2026-07-21 20:18:43 -05:00
host_supervisor.py fix(windows): widen utf-8 subprocess decode guard to sibling desktop-backend sites 2026-07-24 09:48:28 -07:00
loop_noise.py fix(tui_gateway): suppress WS peer-hangup teardown error flood (#50005) (#54126) 2026-06-28 02:35:01 -07:00
project_tree.py fix(desktop): mirror Windows path identity in live overlay + WSL spelling 2026-07-12 04:33:05 -04:00
render.py tui: inherit Python-side rendering via gateway bridge 2026-04-05 18:50:41 -05:00
server.py fix(gateway): deliver the first message when the deferred agent build outlives 30s (#63078) 2026-07-24 21:40:08 -07:00
slash_worker.py fix: Windows guard, dedup recovery, profile-safe paths, clear SO_RCVTIMEO 2026-07-20 12:48:50 +05:30
synthetic_turn.py feat(dashboard): isolate turns in compute host (#65895) 2026-07-16 15:24:03 -04:00
transport.py fix(tui-gateway): harden stdio transport against half-closed pipes + SIGTERM races (#17118) 2026-04-28 17:54:06 -05:00
ws.py fix(tui_gateway): preserve websocket batch order (#69684) 2026-07-23 05:02:45 +00:00