Skip to content

fix(desktop): preserve streamed reasoning on late fallback - #71930

Open
yuexiongHNU wants to merge 3 commits into
NousResearch:mainfrom
yuexiongHNU:fix/64995-preserve-streamed-reasoning
Open

yuexiongHNU wants to merge 3 commits into
NousResearch:mainfrom
yuexiongHNU:fix/64995-preserve-streamed-reasoning

Conversation

@yuexiongHNU

@yuexiongHNU yuexiongHNU commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Prevents a late reasoning.available fallback from replacing reasoning that already arrived through reasoning.delta. If no reasoning was streamed, the fallback is inserted before assistant text instead.

The backend now relays the complete fallback rather than truncating it to 500 characters. The fallback has its own update path, so MoA events keep their existing replacement semantics.

This rebuilds the closed #65432 work on current main. The two original commits and author metadata from @skyc1e and @rasitakyol are preserved; the follow-up commit fixes the MoA regression found during the current-main review.

Related Issue

Fixes #64995

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Tests (adding or improving test coverage)

Changes Made

  • agent/conversation_loop.py: relay the complete structured reasoning fallback while keeping delegated-subagent previews bounded.
  • apps/desktop/src/app/session/hooks/use-message-stream/index.ts: preserve an existing streamed reasoning part and place a missing fallback before assistant text.
  • apps/desktop/src/app/session/hooks/use-message-stream/gateway-event.ts: route reasoning.available through the fallback-specific path without changing MoA replacement behavior.
  • Add reducer, event-timeline, and backend regression tests.

How to Test

  1. Stream reasoning through reasoning.delta, then emit reasoning.available; the existing reasoning part must remain unchanged.

  2. Emit reasoning.available without prior reasoning; it must appear before assistant text and retain more than 500 characters.

  3. Run:

    cd apps/desktop
    npm exec vitest -- run --project ui src/app/session/hooks/use-message-stream.test.ts src/app/session/hooks/use-message-stream/reasoning-available-event.test.tsx src/app/session/hooks/use-message-stream/moa-progress-event.test.tsx
    npm run typecheck
  4. Run:

    scripts/run_tests.sh tests/agent/test_reasoning_available.py -q

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs and preserved the original authorship from closed fix(desktop): preserve streamed reasoning on late fallback #65432
  • My PR contains only changes related to this fix
  • I've run the complete Python suite; the focused backend regression passes
  • I've added tests for the changed behavior
  • I've tested on Windows 11

Documentation & Housekeeping

  • Documentation update: N/A
  • cli-config.yaml.example: N/A
  • CONTRIBUTING.md / AGENTS.md: N/A
  • Cross-platform impact considered; the renderer and callback semantics are platform-neutral
  • Tool descriptions/schemas: N/A

Screenshots / Logs

Targeted Desktop UI: 3 files passed, 8 tests passed
Desktop TypeScript: all three typecheck configurations passed
ESLint / Prettier: passed for touched Desktop files
Python regression: 1 file, 2 tests passed
Ruff: passed for touched Python files

A full Desktop UI run exposed the MoA replacement regression in the closed implementation; the fallback-specific path in the final commit fixes it, and the MoA regression file now passes 4/4. Re-running the other failed files with one worker left four unrelated current-main failures: three host-locale assertions tracked by #71659 / #71750 and the existing Dialog/Select dismiss repro.

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/desktop Electron desktop app (apps/desktop/*) area/streaming Streaming responses: gateway delivery, provider wire labels Jul 26, 2026
@yuexiongHNU
yuexiongHNU force-pushed the fix/64995-preserve-streamed-reasoning branch 2 times, most recently from e4ac976 to 79d503d Compare July 27, 2026 04:37
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks for preserving the original authorship while rebuilding this against the split streaming hooks. Current main reproduces both reported defects: agent/conversation_loop.py:5545 truncates the fallback to 500 characters, while gateway-event.ts:587-590 routes reasoning.available to the replacement path that removes existing reasoning in index.ts:340-355.

Commit 3af5d3bd3364 separates that availability fallback from the existing MoA replacement paths (gateway-event.ts:608-624, 650-663), which is the required boundary. No blocking issue found in this static read-only review.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 30, 2026
@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Summary

Two PRs address #64995 by preserving streamed reasoning when a late reasoning.available event arrives and by removing the backend's 500-character truncation. #71930 rebuilds the closed #65432 implementation on current main and adds a dedicated availability-fallback path so MoA replacement behavior remains intact.

Related pull requests

Duplicates

#65432 and #71930 substantially implement the same truncation and late-fallback fix; #71930 supersedes #65432 through its current-main rebuild and dedicated MoA-safe reasoning.available routing.

Suggested consolidation

Keep #71930 open with a salvage path, consistent with the automated keep_open review: retain its dedicated reasoning.available routing, full-content backend relay, and focused regression tests while resolving any remaining author-side update needed on current main. Keep #65432 closed as a duplicate superseded by #71930.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    I64995(["issue #64995 (open)"])
    subgraph Dup65432 ["PRs duplicating each other"]
        P65432["PR #65432 (closed)"]
        P71930["PR #71930 (open)"]
    end
    P71930 -->|best fix| I64995
    class I64995 open
    class P65432 closed
    class P71930 open
    class P71930 best
    class P71930 target
    click I64995 "https://github.com/NousResearch/hermes-agent/issues/64995"
    click P65432 "https://github.com/NousResearch/hermes-agent/pull/65432"
    click P71930 "https://github.com/NousResearch/hermes-agent/pull/71930"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).

Cross-PR triage: Reviewed 2 pull requests and 1 issue in this complex. Each diff was read against this issue; Assessment working set: 24 kB of PR diffs, 13 kB of issue/PR text, <1 kB of discussion (1 comments), 4 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

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/streaming Streaming responses: gateway delivery, provider wire comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform 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.

Desktop: reasoning.available replace truncates streamed reasoning to 500 chars, causing thinking disclosure to re-render from scratch

6 participants