Skip to content

fix(chat,examples-chat): interrupt panel visual pass — one source of truth, clean reason text, theme-aware#293

Merged
blove merged 1 commit into
mainfrom
claude/interrupt-visual-pass
May 13, 2026
Merged

fix(chat,examples-chat): interrupt panel visual pass — one source of truth, clean reason text, theme-aware#293
blove merged 1 commit into
mainfrom
claude/interrupt-visual-pass

Conversation

@blove
Copy link
Copy Markdown
Contributor

@blove blove commented May 13, 2026

Summary

Visual + UX pass on the agent-interrupt surface, plus a hydration bug fix surfaced during the smoke walk.

Fixes

  1. Single source of truth. Removed the inline <chat-interrupt> primitive from inside <chat>. The docked <chat-interrupt-panel> (rendered by the demo-shell) is now the only place the interrupt UI shows. The chat-interrupt primitive remains a public-api export for consumers who want to render it themselves.
  2. Clean reason text. The panel no longer dumps the raw JSON envelope (e.g. {"type":"approval_request","reason":"..."}). It pulls out value.reason when it's a string, accepts plain string values, and only falls back to a pretty JSON dump as a last resort. Title also normalized to "Agent paused" (matching the primitive's vocabulary).
  3. Theme-aware styling. Replaced dark-only hardcoded colors with chat tokens: --ngaf-chat-surface, --ngaf-chat-text, --ngaf-chat-text-muted, --ngaf-chat-separator, --ngaf-chat-warning-text. Light/dark themes both render correctly.
  4. Layout. Demo-shell now positions the panel via bottom: calc(80px + var(--demo-shell-interrupt-offset, 0px)), with z-index: 999 (below the search palette at 1000), and drops the hardcoded dark bg — the panel itself owns its surface color via tokens.
  5. Button hierarchy. Accept is primary (filled, brand bg), Edit/Respond are secondary (bordered transparent), Ignore is tertiary (muted text only). New --primary / --secondary / --tertiary BEM modifiers.
  6. Bonus: reload bug. refreshHistory in the langgraph stream-manager bridge didn't project tasks[i].interrupts from the latest checkpoint onto interrupt$ / interrupts$. So reloading a paused thread silently lost the pending-interrupt signal, and the next user message hit a BadRequestError. New hydrateInterruptsFromHistory helper fixes that.

Smoke checklist

Updated examples/chat/smoke/CHECKLIST.md Interrupts section to cover all six items above.

Test plan

  • npx vitest run --root libs/chat — 640 tests pass across 85 files
  • npx vitest run --root libs/langgraph — 144 tests pass across 10 files
  • npx nx build chat — clean
  • npx nx lint chat — clean
  • npx nx build examples-chat-angular — clean
  • npm run generate-api-docs — clean
  • Manual: trigger an interrupt, verify panel renders once, reason is human-readable, theme-aware, button hierarchy correct
  • Manual: reload page while paused at interrupt — panel re-appears with same reason text

…truth, clean reason text, theme-aware

- Remove inline <chat-interrupt> primitive from the chat composition. The
  docked <chat-interrupt-panel> in the demo shell is the canonical action
  surface; the primitive is still exported via public-api for downstream
  consumers who want to render it themselves.
- Replace raw JSON envelope dump with a human-readable reason. The panel
  now reads `value.reason` when it's a string, plain string values, or
  falls back to a pretty-printed JSON dump only as a last resort.
- Use the existing chat tokens throughout the panel (--ngaf-chat-surface,
  --ngaf-chat-text, --ngaf-chat-text-muted, --ngaf-chat-separator,
  --ngaf-chat-warning-text) so the panel respects light/dark themes
  instead of being dark-only.
- Refresh button hierarchy: Accept primary (filled), Edit/Respond
  secondary (bordered), Ignore tertiary (muted text). New
  --primary/--secondary/--tertiary BEM modifiers.
- Demo-shell layout: clear the input + subagents strip via
  bottom: calc(80px + var(--demo-shell-interrupt-offset, 0px)); bump
  z-index to 999 (under search palette); drop the dark hardcoded bg.
- Fix: hydrate pending interrupts from history on thread reload. The
  stream-manager bridge now projects tasks[i].interrupts from the latest
  checkpoint onto interrupt$ / interrupts$ when refreshHistory runs, so
  reloading a paused thread re-renders the interrupt panel instead of
  silently letting the user send a message into a BadRequestError.
- Update smoke checklist with the new acceptance criteria.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cacheplane Ready Ready Preview, Comment May 13, 2026 4:47am

Request Review

@blove blove merged commit 916c807 into main May 13, 2026
14 checks passed
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