fix(composer): recover after error and allow attachment-only send - #5319
Conversation
Resolve composer disabled state from real locks only: read-only, transport send, loading, blocking interaction, and missing model. The assistant error banner no longer locks the input, so the user can type and send again after a failed request.
Set contextMenuHidden and pointerEvents="none" on the composer TextInput when it is not editable, so a disabled field does not open writing tools or a selection menu on iOS.
Enable send when there is text or at least one uploaded attachment. handleSend no longer requires non-empty text, so an empty draft with a ready attachment sends prompt: '' plus the attachment payload.
Add send-only prompt clones and a rejectEmptyPromptWithoutAttachments refine so a follow-up send with an empty prompt and attachment files parses, while prepare still requires a prompt.
The prompt handler now accepts an empty prompt when attachments or parts are present, so materializePromptAttachments runs for attachment-only sends.
admitSubmittedMessage admits an empty prompt when attachment files are present and keeps No prompt provided for a prompt with no attachments.
Add a send-only payload schema so baseSendMessageNextSchema accepts an empty prompt with files while prepare initialPayload still requires a prompt.
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryIncremental review of the send-only schema Files Reviewed (2 files)
Previous Review Summary (commit d122fe2)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit d122fe2)Status: No Issues Found | Recommendation: Merge Executive SummaryReviewed all 18 changed files across the mobile composer, web tRPC schemas, and the cloud-agent-next worker (router, message queue, wrapper); the three-gate empty-prompt-with-attachments contract is implemented consistently and the composer unlock/iOS input hardening changes are sound. Coverage notes:
Files Reviewed (18 files)
Reviewed by grok-4.6 · Input: 126K · Output: 9K · Cached: 407.8K Review guidance: REVIEW.md from base branch |
Replace hand-copied send-only payload schemas with .extend derivations in cloud-agent-next and web. The .extend override drops .min(1) on prompt for the send-only types while the prepare types stay text-required.
Summary
Fixes three composer defects without a rewrite.
For the user: after
Assistant request failed, the composer unlocks so you can type and send again in the same session; the red banner stays until the next successful send. A disabled composer on iOS no longer opens writing tools or a selection menu. A ready attachment with no text now sends.For the product manager: the composer now recovers from an assistant error instead of dead-ending the session, and attachment-only sends work end to end. An empty prompt with no attachments stays rejected.
For the maintainer: the composer disabled state now derives from real locks only (
resolveSessionComposerDisabled— read-only, transportcanSend, loading, blocking interaction, missing model), dropping theBoolean(error)lock. The iOSTextInputsetscontextMenuHiddenandpointerEvents="none"when not editable. Attachment-only send is enabled byreadyAttachmentsCountincanSend, and the backend accepts an empty prompt plus attachments across three gates: the send schemas (send-only clones plusrejectEmptyPromptWithoutAttachments), the wrappercreatePromptHandler, andadmitSubmittedMessage. Prepare and new-session paths keep.min(1).Verification
pnpm --filter kilo-app test— 4525 passedpnpm --filter cloud-agent-next test— 2548 passed, 3 skippedpnpm --filter web test -- src/routers/cloud-agent-next-send-schema.test.ts— 8 passedpnpm --filter kilo-app typecheck,pnpm --filter cloud-agent-next typecheck,pnpm --filter web typecheck— passpnpm --filter kilo-app lint,pnpm --filter cloud-agent-next lint,pnpm --filter web lint— 0 warnings, 0 errorspnpm -w exec oxfmt --checkon changed files — passAutomated E2E (bot-e2e) covers the three runtime behaviors on iOS.
Visual Changes
N/A — behavior-only changes; no visual redesign. The red banner, composer layout, and send button appearance are unchanged.
Reviewer Notes
.min(1); only follow-up send is relaxed.ChatInputare unchanged.Human steps
No human step is needed. No migration, secret, flag, or deploy-order change.