Skip to content

fix(chat): render agent turns as chronological segments with scroll-follow#159

Merged
ABB65 merged 1 commit into
mainfrom
fix/chat-segment-flow
Jul 17, 2026
Merged

fix(chat): render agent turns as chronological segments with scroll-follow#159
ABB65 merged 1 commit into
mainfrom
fix/chat-segment-flow

Conversation

@ABB65

@ABB65 ABB65 commented Jul 17, 2026

Copy link
Copy Markdown
Member

Problem

During a long agent turn the user sees only the Thinking spinner; when the turn ends, every intermediate narration ("Şimdi 8 makaleyi oluşturuyorum…") lands as one glued, present-tense wall of text. Verified on staging (conversation `8ad2bba3…`):

  • The client appended all text deltas of a multi-iteration turn into one bubble (no separators) and dumped every tool card below it — chronology (text → tools → text → tools) was destroyed.
  • Auto-scroll fired only on new messages, never during streaming, so live narration accumulated off-screen.
  • On reload, tool cards vanished entirely: history hydration read the legacy `tool_calls` column (always null since the trace migration) instead of `content_blocks`.

Changes

  • useChat: `ChatMessage` now carries ordered `segments` (`text` | `tool`) built live from the SSE stream. New `messageText`/`hasVisibleContent` helpers; `streamTick` counter drives scroll-follow.
  • ChatPanel: assistant messages render segment-by-segment in real order; pin-to-bottom scroll-follow (releases when the user scrolls up, re-pins near the bottom).
  • ChatMarkdown atom: extracted throttled markdown pipeline from ChatBubble — finished segments freeze; only the trailing streaming segment pays the reparse cost.
  • Engine (additive): new `tool_input` SSE event at `tool_use_end` (card shows its input during the whole pending window) and `input` on `tool_result` as the guaranteed carrier. The ee conversation-api response is unchanged — it projects `{id, name, result}` explicitly.
  • History hydration prefers `content_blocks` over legacy `tool_calls`; the literal `[tool calls]` placeholder can no longer render.

Known/accepted: markdown split across a tool call renders as two independent documents (models don't straddle fences across tool calls in practice).

Follow-up PR (2/2) will make intermediate iterations visible in persisted history and harden the graceful-close summary.

Test

  • `pnpm test` — 130 files / 1075 tests green
  • `pnpm vitest run --project e2e tests/e2e/chat-stream.e2e.test.ts` — DOM-order + input assertions
  • `pnpm lint` + `pnpm typecheck` clean

🤖 Generated with Claude Code

…ollow

The chat panel rendered every assistant turn as one text bubble (all
iteration narrations glued together without separators) with every tool
card dumped below it, and auto-scroll only fired on new messages — so a
multi-minute agent turn showed nothing but the Thinking spinner and then
a present-tense wall of text at the end.

- useChat: ChatMessage now carries ordered segments (text | tool) built
  live from the SSE stream, so narration and tool cards keep their real
  chronology; streamTick drives scroll-follow
- ChatPanel: assistant messages render segment-by-segment; pin-to-bottom
  scroll-follow that releases when the user scrolls up
- ChatMarkdown atom: extracted throttled markdown pipeline — finished
  segments freeze, only the trailing streaming segment reparses
- engine: additive tool_input event (input visible while a tool is still
  pending) and input on tool_result; conversation-api response shape is
  unchanged (it projects fields explicitly)
- history hydration prefers content_blocks over the legacy tool_calls
  column, so reloaded conversations regain their tool cards and never
  show the literal '[tool calls]' placeholder
@ABB65
ABB65 merged commit 41a234b into main Jul 17, 2026
2 checks passed
@ABB65
ABB65 deleted the fix/chat-segment-flow branch July 17, 2026 16:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant