-
Notifications
You must be signed in to change notification settings - Fork 28
🤖 feat: add stateful pending reviews #970
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
ae38229 to
3f281ea
Compare
- Add PendingReview types (pending/checked status, timestamps) - Add usePendingReviews hook for localStorage persistence per workspace - Add PendingReviewsBanner component above chat input - Thin collapsible stripe showing pending count - Expand to see review list with check/send/remove actions - Toggle between pending and checked views - Clear all checked reviews option - Uses shadcn Button component with semantic Tailwind classes - Review notes from diff viewer now queue to pending instead of direct chat - Enable review notes on inline file_edit diffs in chat messages - DRY: reuses existing onReviewNote prop through message rendering chain - AIView -> MessageRenderer -> ToolMessage -> FileEditToolCall - Reviews persist across sessions via localStorage - Add Storybook stories for pending reviews feature
- Add ReviewNoteData interface for structured review data - Add formatReviewNoteForChat() to format data when sending to chat - Update PendingReview.data to hold ReviewNoteData instead of content string - Update all onReviewNote callbacks throughout the callback chain - Simplify getReviewSummary() to use review.data.userNote directly - Remove string parsing regex from banner component
- Add BannerErrorBoundary class component to catch rendering errors - Show 'Reviews data corrupted' message with clear button on error - Add clearAll() method to usePendingReviews hook - Wire up onClearAll prop through AIView Handles old localStorage format gracefully by catching render errors rather than requiring migration logic.
Major improvements to PendingReviewsBanner: - Self-contained ConnectedPendingReviewsBanner - only needs workspaceId + chatInputAPI - Full review display with expandable diff viewer and editable comments - Pending reviews first, then completed reviews with 'show more' load - Relative timestamps (ages) for each review - updateReviewNote() method in usePendingReviews hook Styled review rendering in chat: - New shared ReviewBlock component in shared/ReviewBlock.tsx - Reviews render as styled cards in UserMessage (not raw text) - Live preview of reviews in ChatInput before sending - Custom 'review' element handler in MarkdownComponents Also removes ~10 props from AIView → PendingReviewsBanner wiring
- Track attached reviews separately from text input in ChatInput - Add attachReview/detachReview/getAttachedReviews to ChatInputAPI - Show attached reviews as styled blocks with X to remove above input - Auto-mark reviews as completed when sent to chat - Use text-primary for review comments (more readable) - Pass filePath to DiffRenderer for syntax highlighting - Rename ConnectedPendingReviewsBanner to PendingReviewsBanner _Generated with mux_
cbe03f7 to
25327da
Compare
- Use draft construct for error recovery (no duplication) - Hide attached reviews from banner to prevent double-send - Move 'Send to chat' action left, away from delete - Make 'Clear' button smaller (just text link) - Grey chat icon when no pending reviews - Reduce padding/margins in ReviewBlock for compact display - Notify parent when attached reviews change _Generated with mux_
25327da to
b25ea62
Compare
…nly sends, auto-attach - Move X remove button inside ReviewBlock header (within yellow borders) - Add onRemove prop to ReviewBlock component for flexible usage - Allow submitting messages with only attached reviews (no text required) - Auto-attach reviews to chat input when created in Review panel - Remove unused X import from ChatInput
- Simplify extractTextContent in MarkdownComponents (cleaner recursive impl) - Add className prop to DiffRenderer for container styling override - Remove rounding from code block in ReviewBlock (flush with borders) - Increase max height of code preview from max-h-28 to max-h-64 - Show 10 lines at start and 10 at end (was 1 each) before eliding
- Add space-y-2 wrapper in ContentWithReviews for better spacing in sent messages - Trim text segments to remove excess whitespace - Increase ChatInput review preview max-height from max-h-36 to max-h-[50vh] - Increase gap between reviews from space-y-1 to space-y-2 - Add inline editing to ReviewBlock with onEditComment prop - Wire up onUpdateReviewNote callback from ChatInput to AIView - Add pencil edit button that appears on hover over comment
- Add ReviewNoteDataForDisplay type to MuxFrontendMetadata for 'normal' messages - Store structured review data when sending messages (avoids re-parsing from text) - Add reviews field to DisplayedMessage user type - Extract reviews from muxMetadata in StreamingMessageAggregator - Add ReviewBlockFromData component that takes structured data directly - Update UserMessage to prefer metadata-based display over text parsing - Keep fallback parsing for legacy messages before metadata support - Fix file path text readability (change from text-secondary to text-primary) This eliminates the need for janky regex parsing when displaying user messages that contain reviews. The text format is still sent to Claude for context, but the UI now reads from structured metadata.
- Extract ReviewBlockCore as shared internal component - ReviewBlock (parsing) and ReviewBlockFromData (structured) both use core - Add SAVE_EDIT keybind to keybinds.ts (Ctrl/Cmd+Enter) - Use matchesKeybind() for save/cancel in ReviewBlock and PendingReviewsBanner - Pass maxHeight='none' to DiffRenderer in ReviewBlockCore to fix code preview (outer container's max-h-64 handles height constraints) This eliminates ~130 lines of duplicated code between ReviewBlock variants and ensures consistent keybind behavior across the app.
…orage - Add 'attached' to PendingReviewStatus type (pending | attached | checked) - New reviews start as 'attached' (auto-shows in chat input) - Remove attachedReviewIds storage key (state lives on review itself) - Simplify ChatInput: receives attachedReviews prop from parent - Simplify PendingReviewsBanner: only needs workspaceId - Remove legacy review parsing from UserMessage (metadata only) - Remove ContentWithReviews/hasReviewBlocks/splitContentWithReviews - Fix horizontal scroll: add min-w-0 to ReviewBlock, min-w-fit to DiffRenderer - ChatInputAPI no longer has attachReview/detachReview/getAttachedReviews
- Move reviews to MuxFrontendMetadataBase (available on all types) - Remove legacy parsing code from ReviewBlock.tsx (keep only ReviewBlockFromData) - Remove review component from MarkdownComponents.tsx - Fix review order: oldest first (newest at end of list) - Simplify StreamingMessageAggregator reviews extraction
- Rename getPendingReviewsKey -> getReviewsKey (contains all review states) - Rename PendingReviewsState -> ReviewsState - Use updatePersistedState in storyHelpers instead of direct localStorage
Display first line of comment with ellipsis truncation in the collapsed view of pending reviews banner.
- PendingReview -> Review - PendingReviewStatus -> ReviewStatus - usePendingReviews -> useReviews (file and hook) - PendingReviewsBanner -> ReviewsBanner (file and component) - UsePendingReviewsReturn -> UseReviewsReturn - setPendingReviews -> setReviews, createPendingReview -> createReview - Update all story names to remove 'Pending' prefix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
mux/src/browser/components/ChatInput/index.tsx
Lines 979 to 982 in 1c8593d
| continueMessage: { | |
| text: messageText, | |
| imageParts, | |
| model: sendMessageOptions.model, |
When auto-compaction triggers, the queued continueMessage only includes the trimmed text and image parts from the current draft and omits any attached review notes, so the follow-up message sent after compaction drops the user’s selected code/comments. Users hitting the compaction threshold with pending reviews will have their review content silently omitted from the actual message sent to the model. Include the attached reviews in the continueMessage payload so they survive the compaction flow.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- Add UserMessageContent type shared between normal send and continue-after-compaction - Add prepareUserMessageForSend() utility to format reviews into message text + metadata - Update ContinueMessage to extend UserMessageContent (includes reviews field) - Backend now processes reviews in continueMessage using shared utility - ChatInput auto-compaction path now includes attached reviews in continueMessage - Remove duplicate formatReviewNoteForChat from review.ts This ensures reviews work correctly regardless of whether auto-compaction triggers.
- Remove duplicate ReviewNoteDataForDisplay interface (identical to ReviewNoteData) - Export ReviewNoteDataForDisplay as type alias to ReviewNoteData for backwards compat - Move formatReviewForModel to review.ts (single source of truth) - Import and use shared function in message.ts
Apply max-w-4xl mx-auto to banner content so it aligns with the chat area on wide screens, matching ChatInput's layout pattern.
Summary
Adds a reviews system that allows users to create review notes from diff viewers, manage them via a collapsible banner, and send them to Claude with messages. Reviews are orthogonal to message type (works with both normal messages and auto-compaction).
Architecture
Data Flow:
ReviewNoteDatacreatedstatus: "attached"(auto-shows in ChatInput)muxMetadatafor rich UI displayKey Types (
src/common/types/):ReviewNoteData: Structured data withfilePath,lineRange,selectedCode,userNoteReview: Containsid,data,status("pending" | "attached" | "checked"), timestampsUserMessageContent: Shared type for normal send and continue-after-compaction (ensures reviews work with auto-compaction)prepareUserMessageForSend(): Shared utility to format reviews → message text + metadataComponents:
useReviewshook: localStorage persistence per workspace with cross-component syncReviewsBanner: Collapsible banner above chat input showing pending/checked reviewsReviewBlockFromData: Renders review with diff preview and editable commentsChatInput: Shows attached reviews, handles send with reviewsReview State Machine
Key Implementation Details
continueMessageso they survive compaction flowmax-w-4xl mx-autoto align with chatStories
App/Reviews/ReviewsBanner- Multiple reviews in different statesApp/Reviews/AllReviewsChecked- All completed stateApp/Reviews/ManyReviews- Scroll behavior with many itemsGenerated with
mux