Skip to content

TUI: session.info event does not update ctx.sid after compression fork #36777

@laoli-no1

Description

@laoli-no1

Summary

When /compress triggers a session fork (compression ends the current SessionDB session and creates a new continuation session), the TUI frontend does not update its local ctx.sid to match the new session ID. The gateway correctly syncs session_key via _sync_session_key_after_compress() and emits session.info with the updated session_id, but the TUI handler only patches info and usage without updating the active session ID.

Impact

After compression, the TUI display goes blank because:

  • Gateway session key → new session ID
  • TUI ctx.sid → stale (pointing to ended parent session)

Subsequent RPC calls (e.g., message submission, /image, /model) use the stale ctx.sid, targeting the closed parent session.

Reproduction

  1. Start a TUI session with enough messages to trigger auto-compression (or manually run /compress)
  2. Compression completes, session ID rotates in SessionDB
  3. TUI display shows blank / new session state instead of compressed history
  4. agent.log confirms compression succeeded correctly

Root Cause

File: ui-tui/src/app/createGatewayEventHandler.ts (L389-401)

The session.info handler updates info, status, usage, and intro messages — but does not update sid in the UI state. When info.session_id differs from the current state.sid, the TUI should sync to the new session.

Suggested Fix

In the session.info handler, check if info.session_id has changed and update the UI state accordingly:

case 'session.info': {
  const info = ev.payload

  patchUiState(state => {
    const sidChanged = info.session_id && info.session_id !== state.sid
    return {
      ...state,
      info,
      sid: sidChanged ? info.session_id : state.sid,
      status: state.status === 'starting agent…' ? 'ready' : state.status,
      usage: info.usage ? { ...state.usage, ...info.usage } : state.usage
    }
  })

  setHistoryItems(prev => prev.map(m => (m.kind === 'intro' ? { ...m, info } : m)))

  return
}

Workaround

Use /resume <new_session_id> or /new to re-sync the TUI to the correct session after compression.

Environment

  • Hermes Agent v0.15.1 (2026.5.29)
  • macOS (26.5)
  • Main model: Qwen/Qwen3.6-27B-FP8 @ custom (SGLang)
  • Compression: auxiliary.compression.provider: auto

Regression Source

Introduced in v2026.4.23 by commit a8e0a1148 (perf(tui): async session.create).

This commit made session.create async: instead of returning sid synchronously, it returns immediately and pushes the full session info via session.info event. The TS handler was written to only patch info, status, usage, and intro messages — not sid.

In the initial session creation flow this works fine (sid is set from session.create response). However, when /compress forks the session (added in v2026.4.30 via fc7f55f49), the session.info event carries the new session_id but the handler ignores it, leaving ctx.sid stale.

Timeline:

  • v2026.4.23: a8e0a1148 — async session.create (latent bug)
  • v2026.4.30: fc7f55f49/compress + _sync_session_key_after_compress (triggers the bug)
  • v2026.5.7: 3b750715a — fixes lazy session regressions (bug remains)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/tuiTerminal UI (ui-tui/ + tui_gateway/)type/bugSomething isn't working

    Type

    No type
    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