Skip to content

feat(chat): chat experience overhaul — badges, status dots, Ayu code, phase pills, apply-diff card, agent question card#94

Merged
mkappworks merged 55 commits into
mainfrom
feat/2026-05-08-chat-experience-overhaul
May 10, 2026
Merged

feat(chat): chat experience overhaul — badges, status dots, Ayu code, phase pills, apply-diff card, agent question card#94
mkappworks merged 55 commits into
mainfrom
feat/2026-05-08-chat-experience-overhaul

Conversation

@mkappworks
Copy link
Copy Markdown
Contributor

@mkappworks mkappworks commented May 9, 2026

Summary

Chat-experience overhaul bundling phases 5–9 of the UI queue: live phase pills, session-row status dots, Ayu code/diff styling, a cross-provider question-card path, and an inline apply-diff card. Also threads a ProviderUserInputRequest event end-to-end so Codex's item/tool/requestUserInput and Claude CLI's AskUserQuestion tool_use both feed the same question card instead of being misrouted into the permission-card path.

Closes #

Changes

  • Live progress signals — new ToolPhasePill chip color-encoded by toolPhaseClassifier (think / tool / I/O); persistent tool cards stay in the bubble after completion.
  • Session list status — new SessionStatusDot (streaming / awaiting / errored / idle) prefixed to each conversation tile; derived state via sessionStatusFor + a lightweight chatSessionStreaming provider that replaces a per-tile chatMessagesProvider watch.
  • Markdown & diff styling — Ayu Dark / Ayu Light code theme (ayu_highlight_themes.dart), new DiffBody + DiffCard for fenced diff blocks, neutral #0E0E0E code-block bg, diff-add / diff-del moved to AppColors tokens; always-visible per-message copy / retry / delete toolbar on MessageBubble.
  • Cross-provider question card — new ProviderUserInputRequest runtime-event variant; Codex _handleServerRequest branches requestUserInput to it; Claude CLI parser intercepts AskUserQuestion tool_use; new respondToUserInputRequest API surfaced through datasource → repository → service; new AgentUserInputRequestNotifier drives AskUserQuestionCard in info-blue single-step mode (stepper hidden when totalSteps == 1).
  • Inline apply-diff cardApplyDiffCard (ready / applied / failed) replaces the apply_code_dialog.dart snackbar stub; _loadOldContent guarded by a generation counter to avoid races.
  • Tool-call attribution — brand-colored provider chip + 6 px brand dot via brandColorFor (Anthropic / OpenAI / Gemini / Ollama with vendor-pair grouping for claude-cli/anthropic and codex/openai); model chip neutral.
  • Tool-registry renameToolRegistryToolRegistryService (file + provider + tests) to close the lone Service-suffix deviation called out in CLAUDE.md.
  • OtherFileReadResult model, ClaudeSessionPreferences, localhost URL linkification, AUQ peek-then-remove fix, codex unknown-session drop logging, regenerated *.g.dart / *.freezed.dart committed alongside sources.

Type of change

  • Bug fix
  • New feature
  • Refactor / internal improvement
  • Documentation

Checklist

  • flutter analyze passes with no issues
  • dart format lib/ test/ applied
  • flutter test passes
  • If Drift tables or Riverpod providers were changed, build_runner was re-run and generated files (*.g.dart, *.freezed.dart) are committed alongside their source files
  • PR is focused on a single concern

mkappworks and others added 30 commits May 8, 2026 16:59
…tions

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
… actions

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…hive

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…, repo layer

- Task 5.5: DiffBody (multi-line diff renderer with gutters/markers/tinting)
  + DiffCard (read-only card for markdown ```diff blocks)
- Task 10.5: Replace ApplyDiffCard._Body two-Text stub with DiffBody
- Task 12.5: Surface respondToUserInputRequest through the repository layer

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…der, applyChange call

- Task 4 + 8: (_, _) → (context, _) in AnimatedBuilder — Dart <3.7 rejects
  duplicate parameter names; wildcard form (context, _) is always safe
- Task 15: replace message.isStreaming guard with isLastInSession bool
  param on MessageBubble; stream pauses while awaiting answer so isStreaming
  flips false before user responds
- Task 10 Step 6: replace fictional apply(codeBlock:, messageId:) call with
  real applyChange(projectId:, filePath:, projectPath:, newContent:,
  sessionId:, messageId:) via _ApplyCardLoader widget that also handles
  async oldPreview loading and per-card state tracking

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds SessionStatusDot widget with pulsing animation for streaming state, and integrates it into ConversationTile replacing the static active indicator.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ream-based awaiting

Adds chatSessionAwaitingProvider that derives pending-permission/question
state from the in-memory ChatStreamRegistryService (watchMessages + liveMessagesFor)
instead of loading up to 50 SQLite rows via chatMessagesProvider for every
visible sidebar tile.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ayu is not available in re_highlight v0.0.3; Tokyo Night (dark/light)
is the closest available paired alternative. Updates codeBlockBg /
jsonEditorBg to match the new palette (dark: #0B0E14, light: #FAFAFA).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds DiffBody (line-level diff renderer) and DiffCard (header + body wrapper with filename/stat parsing), then wires DiffCard into CodeBlockBuilder so ```diff fences render as a styled diff view instead of a plain code block.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove hover-gating from _AssistantActionRow: drop _hovering field,
MouseRegion, hovering parameter, and AnimatedOpacity wrapper so the
copy button is always fully visible without requiring hover.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds retryAssistantMessage and deleteAssistantMessage to ChatMessagesActions,
wires Retry (refresh icon) and Delete (trash icon) IconButtons into
_AssistantActionRow, and extends ChatMessagesFailure with a retryFailed variant.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ering

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ering

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ayer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
mkappworks and others added 15 commits May 9, 2026 00:26
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ifier

Threads requestUserInput callback through SessionService._streamProvider so
ProviderUserInputRequest events from CLI providers unblock the agent loop
rather than being swallowed. The last assistant bubble renders an agent-mode
AskUserQuestionCard that submits via agentUserInputRequestProvider.notifier,
and cancelSend() now cancels any pending user-input request alongside
permissions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…serInputRequest, comment cleanup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Defines the AskUserQuestion tool name, description, and JSON-schema with
provider-shaped getters (anthropicShape, openAiShape, geminiShape,
ollamaShape) for future registration when API-direct datasources grow
tool-call support.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@mkappworks mkappworks self-assigned this May 9, 2026
mkappworks and others added 10 commits May 10, 2026 00:56
…oolRegistryService rename

- AUQ flow: keep stdin open until stream done; family provider keyed by
  sessionId prevents cross-session contamination; sealed AgentUserInputResult
  (answer/cancelled/preempted); route respondToUserInputRequest by providerId
  (returns bool); auto-decline with sLog when no requestPermission callback
- workingDirectory guard: isAcceptableWorkingDirectory() via package:path
  (cross-platform, replaces startsWith('/'))
- codex_session_pool: maxSessions cap (default 16) with force-evict oldest
- codex_session: SIGTERM escalation after 2 s grace on cancel; sLog on
  process-gone write failure; defensive rawPrompt coercion with sLog
- FileReadResult sealed type (content/notFound/error) replaces nullable String
  in ApplyService.readFileContent; widgets switch exhaustively
- compute_line_diff: manual linesToChars encoding over diff_match_patch so
  ApplyDiffCard shows real +N/-N counts and unified diff text
- ChatStreamRegistryService.reportFailure for external failure signalling
- ChatMessagesFailure: deleteUserFailed/deleteAssistantFailed split; unknown removed
- ToolRegistry → ToolRegistryService rename (class, file, provider, tests);
  CLAUDE.md named exception removed
- sLog wraps --version probe errors to avoid leaking secrets in structured logs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…snapshot

- message_bubble: pre-process localhost:PORT (bare or http(s)://) into
  [url](url) markdown links before rendering — GFM autolinks reject
  `localhost` (no dot in domain), so explicit link syntax is required;
  add onTapLink to open via url_launcher; export linkifyLocalhost for testing
- session_service: yield pendingPermissionRequest snapshot before awaiting
  user approval so PermissionRequestCard renders during the hold — same
  pattern as agent_service already uses for Codex
- claude_cli_datasource: revert --permission-prompt-tool (requires registered
  MCP tool; bare tool name causes CLI exit 1 at startup)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…kens

- Add hand-rolled ayuDarkTheme / ayuLightTheme maps (re_highlight + flutter_highlight compatible)
- Switch app_colors jsonHighlightTheme from Tokyo Night to Ayu
- Flip dark codeBlockBg from Ayu #0B0E14 to neutral #0E0E0E (kills the blue cast that competed with the surface hierarchy)
- Inline code tokens shift to Ayu warm accent (#FFB454 dark / #B8761D light on tinted fill)
- Add markdownH1/H2/H3FontSize tokens to ThemeConstants
- Add AppIcons.document for the upcoming markdown doc panel

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…treamingDot

- Extract shared markdown style + builders into chat_markdown_style.dart so message_bubble and the new doc panel render markdown identically (h1/h2 bottom border, near-white strong, h3+ secondary, Ayu warm inline code, blockquote bg tint)
- Add MarkdownDocPanel widget rendered when a code fence has language=markdown — renders the markdown live with a "Copy raw" button that returns the unparsed source. CodeBlockBuilder takes a routeMarkdownToDocPanel flag to prevent recursion when the panel itself processes inner fences
- Code block chrome: +N/−N diff-stat in header, _GutteredHighlight with line-number gutter for plain blocks, per-line MouseRegion hover overlay on diff rows (alpha-blends with diff bg so green/red signal survives)
- Sidebar conversation dot now watches agentUserInputRequestProvider for the session — turns amber when an agent question card is pending, not just permission requests
- Remove unused StreamingDot widget + its dead test references
- Fix linkifyLocalhost re-wrapping URLs already inside [...](...) markdown links — two-pass approach now passes existing link expressions through unchanged

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three-phase plan for interleaving tool calls with text in assistant message bubbles. Phase 1 adds a List<MessageBlock> data model additively. Phase 2 has the streaming pipeline write blocks in emission order. Phase 3 swaps the renderer behind an optional flag. Each phase is independently revertable.

Aligns with the brainstorm decision in final-summary.html ("Tool cards persistent · interleaved with text") and matches the convention shipped by Claude.ai and ChatGPT/OpenAI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mkappworks mkappworks merged commit 072664c into main May 10, 2026
3 checks passed
@mkappworks mkappworks deleted the feat/2026-05-08-chat-experience-overhaul branch May 10, 2026 23:12
@mkappworks mkappworks mentioned this pull request May 10, 2026
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