Skip to content

feat(extension): collapse long assistant code blocks - #4750

Merged
iscekic merged 3 commits into
mainfrom
feat/ext-collapsible-code
Jul 24, 2026
Merged

feat(extension): collapse long assistant code blocks#4750
iscekic merged 3 commits into
mainfrom
feat/ext-collapsible-code

Conversation

@iscekic

@iscekic iscekic commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Long code blocks (>15 lines) in assistant chat messages in the Kilo browser extension side panel now render collapsed once the message finishes streaming: an 8-line preview with a fade-out and a Show more (N lines) toggle. Tool panels, thinking blocks, and user messages are unchanged.

Product decisions

  • Scope: assistant-message markdown pre blocks only (fenced and indented uniformly; inline code untouched)
  • Threshold: >15 lines (trailing-newline tolerant); default collapsed; per-block toggle; not persisted
  • Streaming: while a message's own stream is active, its blocks render fully with no collapse chrome; collapse applies the moment that message's stream ends — even while later tool rounds of the same run continue — and previously finalized messages never flash open on a new run
  • Appearance: 8-line preview + fade + Show more (N lines) / Show less with aria-expanded

Implementation

  • New pure module + CollapsibleCodeBlock component (entrypoints/sidepanel/collapsible-code-block.ts(x)); unconditional hooks so the streaming→collapsed handoff keeps hook order
  • MessageEvent overrides ReactMarkdown's pre renderer for the assistant branch only, with a defensive fallback to the default renderer on unexpected child shapes
  • Precise streaming signal: streamingMessageIdAtomFamily + core onAssistantStreaming start/end callback (start at the first content delta; end guaranteed by try/finally on success, abort, and error), wired through both turn runners; three clear points (core end signal, run finally, abortConversationRun) so stop/close/delete mid-stream never leaks a stale id
  • clearPerConversationAtoms evicts the new family (covers a conversation whose only entry is a mid-first-run streaming id)

Test plan

  • Vitest: line counting (trailing newlines, CRLF, empty), 15/16 boundary, preview slicing, chrome decision matrix, atom eviction (incl. streaming-only conversation), core start/end/reject/non-streamed streaming-callback contract — 243 pass
  • Chrome E2E (tests/e2e/collapsible-code-blocks.test.ts): scripted-SSE assistant message with 20-line + 18-line + 3-line fenced blocks; asserts collapsed previews, exact toggle labels, per-block independent expand/collapse with aria-expanded, short block plain, no horizontal overflow
  • Firefox E2E: same flow mirrored in firefox-selenium-e2e.ts (scroll assertions omitted — no helper idiom in that suite)
  • Mid-stream chrome state is unit-covered only: the scripted-SSE harness fulfills the whole body in one shot, so intermediate streaming paints are not stably observable. Named-mock justification: the mock is the extension's established tests/e2e/kilo-api-fixture.ts mockKiloApi harness — a real model call cannot deterministically produce an exact >15-line fenced block with a stable assertable line count and timing; every existing extension rendering E2E uses this harness per apps/extension/AGENTS.md.

Gate

verify (typecheck + lint + format:check + 243 unit tests), build, build:firefox, e2e:chrome (53 passed), e2e:firefox (26/26), pnpm format — all green.

@iscekic iscekic self-assigned this Jul 24, 2026
@kilo-code-bot

kilo-code-bot Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Reviewed the assistant-message code-block collapse feature (pure helpers, CollapsibleCodeBlock, streaming-id atom wiring through agent-chat-panel.tsx/agent-llm-turn-runner-core.ts, and virtualized list prop threading) with high confidence and found no security, correctness, or breaking-change issues in the changed lines.

Files Reviewed (14 files)
  • apps/extension/entrypoints/sidepanel/agent-chat-atoms.ts
  • apps/extension/entrypoints/sidepanel/agent-chat-panel.tsx
  • apps/extension/entrypoints/sidepanel/agent-conversation-events.tsx
  • apps/extension/entrypoints/sidepanel/agent-llm-turn-runner.ts
  • apps/extension/entrypoints/sidepanel/agent-safe-llm-turn-runner.ts
  • apps/extension/entrypoints/sidepanel/collapsible-code-block.test.ts
  • apps/extension/entrypoints/sidepanel/collapsible-code-block.ts
  • apps/extension/entrypoints/sidepanel/collapsible-code-block.tsx
  • apps/extension/entrypoints/sidepanel/conversation-list.tsx
  • apps/extension/src/shared/agent-chat-atoms.test.ts
  • apps/extension/src/shared/agent-llm-turn-runner-core.test.ts
  • apps/extension/src/shared/agent-llm-turn-runner-core.ts
  • apps/extension/tests/e2e/collapsible-code-blocks.test.ts
  • apps/extension/tests/e2e/firefox-selenium-e2e.ts

Reviewed by claude-sonnet-5 · Input: 32 · Output: 11.7K · Cached: 1.1M

Review guidance: REVIEW.md from base branch main

@iscekic
iscekic requested a review from pandemicsyn July 24, 2026 15:29
@iscekic
iscekic enabled auto-merge (squash) July 24, 2026 15:59

@pandemicsyn pandemicsyn 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.

lgtm - couple nits inline it looks like - feel free to ignore.

{expanded ? null : (
<div
aria-hidden="true"
className="pointer-events-none absolute inset-x-0 bottom-0 h-10 rounded-b bg-gradient-to-t from-[rgb(9_9_11)] to-transparent"

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.

Neon review finding (nit): The fade-out gradient uses an opaque rgb(9 9 11) end color, but the actual <pre> background (from .agent-message-markdown :where(pre)) is rgb(9 9 11 / 70%) layered over the assistant bubble's bg-zinc-900. The two colors are close but not identical, so the fade can show a faint seam against the real background instead of blending perfectly.

Suggested fix: Use the same semi-transparent background value (or a CSS variable shared with the pre rule) for the gradient's terminal color so the fade blends exactly with the block's actual background.

Generated by Neon. Edit or delete before submitting the review.

/>
)}
</div>
<button

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.

Neon review finding (nit): The toggle button has aria-expanded but no aria-controls/id association with the code region it discloses, which is a minor accessibility gap for a disclosure widget (screen readers can't programmatically link the control to the controlled content).

Suggested fix: Give the <pre>/wrapper an id and add aria-controls on the button pointing to it, consistent with standard disclosure-widget patterns.

Generated by Neon. Edit or delete before submitting the review.

@iscekic
iscekic merged commit 0a6187b into main Jul 24, 2026
18 checks passed
@iscekic
iscekic deleted the feat/ext-collapsible-code branch July 24, 2026 16:42
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.

2 participants