Mobile chat UI overhaul: staged send, question cards, artifact cards#785
Conversation
- Staged (steer) strip: compact rows with one-line truncated text and
icon-only actions (fixes mid-word button-label wrapping); host now
converts chat.send during an active turn into the steer path so
offline-replayed sends are queued instead of dropped; iOS reconciles
lingering optimistic steers on turn end via a forced canonical refresh.
- Pending question card: capped to the transcript viewport (62%, min
240pt) with an internal self-sizing scroll for long option lists;
multi-question pager replaced with a chip tab strip + answered count.
- Answered questions collapse to a single compact row ("Answered · {choice}",
typed answers echoed in quotes, secrets never echoed) matching desktop.
- Artifact in-thread card: icon tile + 2-line title + "Kind · time"
metadata line; raw backend errors replaced with a muted preview-unavailable
fallback.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Drop dead accent property and stale doc comment on WorkResolvedQuestionCard; only echo freeform resolutions when the question model is present and known non-secret. - steerActionButton takes one required async closure; measuredBodyHeight sentinel replaced with an Optional. - routeActiveToSteer skips empty sends so they keep prepareSendMessage's no-op semantics instead of reporting a queued:false steer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 34 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (11)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@copilot review but do not make fixes |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1b7ee72ee3
ℹ️ 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".
| text: args.text, | ||
| attachments: args.attachments, | ||
| contextAttachments: args.contextAttachments, | ||
| metadata: args.metadata, |
There was a problem hiding this comment.
Preserve chat.send options when steering active sends
When a remote client calls chat.send during an active turn with fields such as displayText, reasoningEffort, executionMode, or interactionMode, this new branch bypasses prepareSendMessage(args) and calls steer with only text/attachments/context/metadata. Those fields are accepted by the remote chat.send parser, so the active-turn-only path now loses per-send mode settings and can render the raw expanded prompt instead of the intended displayText. Please carry the original send options through the steer path or prepare the message from the original args before enqueueing.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in bf32980: AgentChatSteerArgs and the pending-steer entries now carry displayText / reasoningEffort / executionMode / interactionMode; the chat.send routing passes them through, and deliverNextQueuedSteer applies executionMode/interactionMode (same session mutations + directives as prepareSendMessage) and uses displayText for the visible message. reasoningEffort is persisted on the entry but not yet applied at delivery — there is no turn-option channel for it (the send path applies it out-of-band via session mutation + query reset); flagged as a follow-up rather than replicating that block here.
displayText, executionMode, and interactionMode set on a chat.send that gets routed to the steer queue now survive to delivery: entries persist the fields, deliverNextQueuedSteer applies the same session mutations and prompt directives prepareSendMessage would, and the visible text stays the displayText. reasoningEffort is stored on the entry; applying it at delivery needs the send path's query-reset replication and is left as a follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex review |
|
Deployment failed with the following error: Learn More: https://vercel.com/arul28s-projects?upgradeToPro=build-rate-limit |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Summary
Fixes four mobile chat defects visible in Claude Agent SDK chats but applying to all runtimes:
chat.sendnow converts a send arriving during an active turn into the existing steer path (routeActiveToSteer, additive{steerId, queued}ack), so offline-replayed sends queue instead of being dropped; iOS additionally reconciles lingering optimistic steers on the active→idle transition via a forced canonical refresh.TabView(.page)pager is replaced with a chip tab strip + "n of m answered". Answered questions collapse to a single compact row ("Answered · {choice}", typed answers quoted, secrets never echoed) matching desktop/Claude Code.Validation
xcodebuildgreen (twice, including post-review fixes).agentChatService534/534, including two new regression tests (send-during-active-turn queues + delivers at turn end; empty send stays a no-op).chat.messageSession; ack fields are additive for old clients).🤖 Generated with Claude Code
Greptile Summary
This PR updates mobile chat behavior and presentation for staged sends, question cards, and artifact cards. The main changes are:
chat.sendcalls during active turns into the queued steer path.Confidence Score: 5/5
Safe to merge with low risk.
No correctness or security issues were identified in the reviewed changed paths. The active-send routing behavior is covered by new tests, and the iOS changes are localized UI and reconciliation updates.
No files require special attention.
What T-Rex did
Important Files Changed
chat.sendcalls through steer when a turn is active and returns additive queue acknowledgement fields.Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant iOS as iOS chat UI participant Sync as Sync remote command participant Chat as AgentChatService participant Runtime as Active runtime iOS->>Sync: chat.send(text, attachments) Sync->>Chat: sendMessage(..., routeActiveToSteer: true) Chat->>Chat: canRouteActiveSendToSteer() alt turn active and message routable Chat->>Chat: steer(...displayText/modes) Chat->>iOS: user_message(deliveryState: queued, steerId) Chat-->>Sync: "{ steerId, queued: true }" Sync-->>iOS: "{ ok: true, steerId, queued: true }" Runtime-->>Chat: active turn completes Chat->>Runtime: deliver queued steer with saved directives Chat->>iOS: delivered transcript update else idle or empty no-op Chat->>Runtime: normal send or no-op Sync-->>iOS: "{ ok: true }" end%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant iOS as iOS chat UI participant Sync as Sync remote command participant Chat as AgentChatService participant Runtime as Active runtime iOS->>Sync: chat.send(text, attachments) Sync->>Chat: sendMessage(..., routeActiveToSteer: true) Chat->>Chat: canRouteActiveSendToSteer() alt turn active and message routable Chat->>Chat: steer(...displayText/modes) Chat->>iOS: user_message(deliveryState: queued, steerId) Chat-->>Sync: "{ steerId, queued: true }" Sync-->>iOS: "{ ok: true, steerId, queued: true }" Runtime-->>Chat: active turn completes Chat->>Runtime: deliver queued steer with saved directives Chat->>iOS: delivered transcript update else idle or empty no-op Chat->>Runtime: normal send or no-op Sync-->>iOS: "{ ok: true }" endReviews (3): Last reviewed commit: "Carry per-send options through the queue..." | Re-trigger Greptile