Skip to content

fix(desktop): recover incomplete transcript turns - #88127

Open
szzhoujiarui wants to merge 1 commit into
NousResearch:mainfrom
szzhoujiarui:fix/88036-desktop-transcript-render
Open

szzhoujiarui wants to merge 1 commit into
NousResearch:mainfrom
szzhoujiarui:fix/88036-desktop-transcript-render

Conversation

@szzhoujiarui

Copy link
Copy Markdown
Contributor

What does this PR do?

Recovers Desktop assistant output when a turn finishes without a usable terminal message.

There are two related failure paths:

  • An empty message.complete can arrive while the live transcript still ends with the user message, even though the durable session already contains the assistant response. The completion handler now hydrates that durable response.
  • A confirmed live turn can transition to session.info running=false without receiving message.complete, including after interim assistant output. The session handler now settles the pending bubble, refreshes session metadata, and hydrates the active transcript from durable history.

Foreground isolation remains intact: background sessions update their cached busy state and sidebar metadata without replacing the visible transcript.

The older #62504 and #41922 changes preserve assistant text that was already streamed into the renderer. This change covers the complementary cases where no final assistant text is visible and durable-history catch-up is required, or where the terminal event is missing entirely.

Related Issue

Fixes #88036

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Security fix
  • Documentation update
  • Tests (adding or improving test coverage)
  • Refactor (no behavior change)
  • New skill (bundled or hub)

Changes Made

  • Updated apps/desktop/src/app/session/hooks/use-message-stream/index.ts to hydrate durable history when an empty completion leaves an unresolved user tail.
  • Updated apps/desktop/src/app/session/hooks/use-message-stream/gateway-event.ts to recover any confirmed live turn that ends without message.complete, including turns with interim assistant output.
  • Added regression coverage in interim-sealing.test.tsx and session-info-side-effects.test.tsx for both event sequences and active/background session isolation.

How to Test

  1. Run cd apps/desktop && npx vitest run src/app/session/hooks/use-message-stream.
  2. Run npm run typecheck, npm run lint, and npm run build from apps/desktop.
  3. Simulate an empty message.complete after message.start, and a message.interim followed by session.info running=false without message.complete; verify the active transcript hydrates from stored history and the composer is released.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass (N/A: Desktop TypeScript-only change)
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Linux

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) - N/A
  • I've updated cli-config.yaml.example if I added/changed config keys - N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows - N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide - event-state logic is platform-independent
  • I've updated tool descriptions/schemas if I changed tool behavior - N/A

Screenshots / Logs

use-message-stream: 22 test files passed, 119 tests passed
typecheck: passed
lint: 0 errors (111 existing warnings)
build: passed, dist assertion passed

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/desktop Electron desktop app (apps/desktop/*) area/sessions Session lifecycle, resume, persistence, history area/streaming Streaming responses: gateway delivery, provider wire sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Aug 17, 2026
@Enough1122

Copy link
Copy Markdown
Contributor

AI code review — automated review for reference; please use your judgment.

  1. gateway-event.ts — Positive: widening the recovery edge from "never saw an assistant payload" to turnLive (a confirmed live turn whose terminal message never arrived) closes the reconnect-gap case where interim text streamed but message.complete was lost — previously that left awaitingResponse latched exactly like [Bug]: TUI (Desktop App) shows "Running Code..." indicator indefinitely after session has completed #46517 but with partial content on screen, which is worse because it looks alive. The once-per-edge coalescing comment carries over correctly.

  2. index.ts hydration gate — Positive: (!unresolvedUserTail || !finalText) is the subtle half — a turn that produced some text but ended unresolved still needs the durable transcript pulled rather than trusting the stream; its regression test mounts a state whose transcript ends on the user message and asserts hydration fires with the right args on an empty completion. No change requested.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/sessions Session lifecycle, resume, persistence, history area/streaming Streaming responses: gateway delivery, provider wire comp/desktop Electron desktop app (apps/desktop/*) P2 Medium — degraded but workaround exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

3 participants