feat(chat): chat experience overhaul — badges, status dots, Ayu code, phase pills, apply-diff card, agent question card#94
Merged
Conversation
…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>
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>
…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>
…ter responsiveness
…ging known sessions
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
ProviderUserInputRequestevent end-to-end so Codex'sitem/tool/requestUserInputand Claude CLI'sAskUserQuestiontool_useboth feed the same question card instead of being misrouted into the permission-card path.Closes #
Changes
ToolPhasePillchip color-encoded bytoolPhaseClassifier(think / tool / I/O); persistent tool cards stay in the bubble after completion.SessionStatusDot(streaming / awaiting / errored / idle) prefixed to each conversation tile; derived state viasessionStatusFor+ a lightweightchatSessionStreamingprovider that replaces a per-tilechatMessagesProviderwatch.ayu_highlight_themes.dart), newDiffBody+DiffCardfor fenced diff blocks, neutral#0E0E0Ecode-block bg, diff-add / diff-del moved toAppColorstokens; always-visible per-message copy / retry / delete toolbar onMessageBubble.ProviderUserInputRequestruntime-event variant; Codex_handleServerRequestbranchesrequestUserInputto it; Claude CLI parser interceptsAskUserQuestiontool_use; newrespondToUserInputRequestAPI surfaced through datasource → repository → service; newAgentUserInputRequestNotifierdrivesAskUserQuestionCardin info-blue single-step mode (stepper hidden whentotalSteps == 1).ApplyDiffCard(ready / applied / failed) replaces theapply_code_dialog.dartsnackbar stub;_loadOldContentguarded by a generation counter to avoid races.brandColorFor(Anthropic / OpenAI / Gemini / Ollama with vendor-pair grouping forclaude-cli/anthropicandcodex/openai); model chip neutral.ToolRegistry→ToolRegistryService(file + provider + tests) to close the loneService-suffix deviation called out in CLAUDE.md.FileReadResultmodel,ClaudeSessionPreferences, localhost URL linkification, AUQ peek-then-remove fix, codex unknown-session drop logging, regenerated*.g.dart/*.freezed.dartcommitted alongside sources.Type of change
Checklist
flutter analyzepasses with no issuesdart format lib/ test/appliedflutter testpassesbuild_runnerwas re-run and generated files (*.g.dart,*.freezed.dart) are committed alongside their source files