Skip to content

fix(tui): resolve in-memory session UUID in session.resume for crash recovery #39013 - #39167

Closed
kyssta-exe wants to merge 1 commit into
NousResearch:mainfrom
kyssta-exe:auto-fix/issue-39013
Closed

fix(tui): resolve in-memory session UUID in session.resume for crash recovery #39013#39167
kyssta-exe wants to merge 1 commit into
NousResearch:mainfrom
kyssta-exe:auto-fix/issue-39013

Conversation

@kyssta-exe

Copy link
Copy Markdown
Contributor

Summary

After a TUI gateway child crashes and respawns, the recovery path calls session.resume with the in-memory session UUID (the TUI's sid). However, the DB stores sessions under a different primary key (stored_session_id), so the lookup fails with "session not found".

Root Cause

session.create returns two IDs:

  • session_id: an in-memory UUID used as the key in the Python _sessions dict
  • stored_session_id: the DB primary key stored in SQLite's sessions.id column

The TUI stores session_id as sid in its UI state. When the gateway child exits (e.g., due to rapid successive messages causing stdin EOF), the crash recovery path stores this sid in recoverSidRef and sends it to session.resume on the respawned gateway. Since the DB row is keyed by stored_session_id (not the in-memory UUID), db.get_session(target) returns None, and the user sees "session not found".

Fix

Three changes across 3 files (+85 lines):

  1. hermes_state.py: Added in_memory_id TEXT column to the sessions table schema (auto-migrated via declarative reconciliation). Added get_session_by_in_memory_id() and set_session_in_memory_id() methods to SessionDB.

  2. tui_gateway/server.py: Modified _ensure_session_db_row() to store the in-memory UUID in the in_memory_id column when first persisting the session. Modified session.resume to fall back to get_session_by_in_memory_id() when the primary ID and title lookups fail.

  3. tests/test_hermes_state.py: Added 4 tests for the new in_memory_id lookup functionality.

Testing

  • All 458 tests pass (255 hermes_state + 199 tui_gateway_server + 4 new in_memory_id tests)
  • Pre-existing flaky test test_goal_command.py::test_goal_bare_shows_status_when_none_set excluded (fails without changes too)

Issue

Fixes #39013

…y crash recovery

After a TUI gateway child crashes and respawns, the recovery path calls
session.resume with the in-memory session UUID (the TUI's sid). However,
the DB stores sessions under a different primary key (stored_session_id),
so the lookup fails with 'session not found'.

Add an in_memory_id column to the sessions table that stores the TUI's
in-memory UUID. session.resume now falls back to this column when the
primary and title lookups fail, allowing crash recovery to find and
resume the session correctly.

Fixes NousResearch#39013
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/tui Terminal UI (ui-tui/ + tui_gateway/) labels Jun 4, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tracing the runtime-versus-durable session identity mismatch. The stale-ID premise is still present on current main: ui-tui/src/app/useSessionLifecycle.ts:223-227 stores the runtime session_id, ui-tui/src/app/useMainApp.ts:801 carries it into recovery, and tui_gateway/server.py:5582-5601 cannot resolve it from the DB.

Problems

  • tui_gateway/server.py:5290-5291 already returns the durable stored_session_id, but SessionCreateResponse exposes only session_id (ui-tui/src/gatewayTypes.ts:225-228). Persisting another DB alias for the runtime ID is unnecessary extra schema surface when recovery can retain and submit the existing durable ID.
  • The added tests cover only the new SessionDB helpers. They do not exercise the create → first-prompt persistence → fresh gateway → recovery-resume path. Existing recovery coverage mocks resumeById at ui-tui/src/__tests__/createGatewayEventHandler.test.ts:758-766.

Suggested changes

  • Preserve both identities in the TUI and use stored_session_id exclusively for crash recovery; retain sid for live RPC dispatch.
  • Add a protocol/UI regression test covering the complete recovery boundary.

Automated hermes-sweeper review.

Comment thread tui_gateway/server.py
@@ -3959,7 +3977,7 @@ def _(rid, params: dict) -> dict:
_start_inflight_turn(session, text)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid persisting the runtime sid as a second DB identity here. session.create already returns the durable stored_session_id; expose and retain that value in the TUI recovery state, then pass it to session.resume. This keeps runtime and durable identities explicit without a schema migration.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 14, 2026
@kyssta-exe

Copy link
Copy Markdown
Contributor Author

Stale — oldest open PR, no merge activity for weeks.

@kyssta-exe kyssta-exe closed this Jul 14, 2026
@teknium1 teknium1 added area/sessions Session lifecycle, resume, persistence, history area/memory Memory subsystem: store, providers, sync, background reviews labels Jul 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/memory Memory subsystem: store, providers, sync, background reviews area/sessions Session lifecycle, resume, persistence, history comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TUI: "gateway exited" + "session not found" after rapid successive messages in same turn

3 participants