Add image attachment support - #55
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds cross-platform image picking, client upload APIs, server-side validated attachment storage, relay-aware proxied image URLs, chat UI attach/preview/send flow, and tests exercising uploads and agent input with attachments. ChangesImage Attachments for Agent Chat
Sequence Diagram(s)sequenceDiagram
participant Client as AgentChatScreen
participant ImagePicker
participant API as app/lib/api
participant Relay as RelayProxy
participant Server as MetadataServer
participant Store as AttachmentStore
Client->>ImagePicker: pickImageAttachment()
ImagePicker-->>Client: PickedImageAttachment (base64, preview)
Client->>API: uploadImageAttachment(base64...)
API->>Server: POST /attachments (direct project HTTP or via relay)
Server->>Store: createUploadedAttachment(data)
Store-->>Server: AttachmentRecord (id, path, meta)
Server-->>API: 201 AttachmentRecord
Client->>API: sendAgentInput(text?, attachmentIds)
API->>Server: POST /agents/input (may go via Relay)
Server->>Server: formatAgentInputWithAttachments(...)
Server->>Lifecycle: lifecycle.sendAgentInput(formattedText)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
app/components/screens/AgentChatScreen.tsxESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
app/lib/image-picker.native.ts (1)
33-37: ⚡ Quick win
MediaTypeOptionsis deprecated; use theMediaTypestring array.
ImagePicker.MediaTypeOptionshas been deprecated in expo-image-picker in favor of a singleMediaTypeor an array (e.g.['images']). It still works on SDK 54 (~17.0.x) but logs a deprecation warning and will eventually be removed.♻️ Proposed change
const result = await ImagePicker.launchImageLibraryAsync({ - mediaTypes: ImagePicker.MediaTypeOptions.Images, + mediaTypes: ["images"], base64: true, quality: 1, });The deprecation is confirmed in the expo-image-picker changelog: ImagePicker.MediaTypeOptions have been deprecated. Use a single MediaType or an array of MediaTypes instead. Please confirm the array form against the version pinned in this repo before merging.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/lib/image-picker.native.ts` around lines 33 - 37, The call to ImagePicker.launchImageLibraryAsync uses the deprecated ImagePicker.MediaTypeOptions.Images; update the options to use the new MediaType array form instead—modify the mediaTypes field passed to ImagePicker.launchImageLibraryAsync (the same call that assigns to result) to use a string or string-array like ['images'] (or the equivalent MediaType value supported by the pinned expo-image-picker version) so the deprecated MediaTypeOptions accessor is removed.src/metadata-server.ts (1)
2681-2683: ⚡ Quick winConsider improving the error message for clarity.
The error message "text is required" is shown when both text and attachments are empty. While technically correct (since text is required when there are no attachments), a clearer message would be "text or attachments are required" to better reflect the actual validation logic.
💬 Suggested improvement
if (!text.trim() && attachmentIds.length === 0) { - send(res, 400, { ok: false, error: "text is required" }); + send(res, 400, { ok: false, error: "text or attachments are required" }); return; }Note: This change would require updating the test expectation at line 1402 in
src/metadata-server.test.ts.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/metadata-server.ts` around lines 2681 - 2683, Update the validation error message emitted when both text and attachmentIds are empty: replace the current send(res, 400, { ok: false, error: "text is required" }) with a clearer message such as "text or attachments are required" so the response matches the condition if (!text.trim() && attachmentIds.length === 0); also update the corresponding test expectation in src/metadata-server.test.ts (the assertion around line 1402) to expect the new message.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/components/screens/AgentChatScreen.tsx`:
- Around line 246-280: The handleSendMessage function re-uploads attachments on
retry because the catch restores the original attachments array; change the flow
to track successfully uploaded attachment IDs (the uploaded array populated by
uploadImageAttachment) and on error restore only the remaining un-uploaded
attachments via setPendingAttachments (or persist uploaded IDs and restore those
IDs so retries call sendAgentInput with attachmentIds instead of re-uploading).
Specifically, update the upload loop and error handling around
uploadImageAttachment and sendAgentInput so that uploaded holds attachment
IDs/results to reuse, setDraft(text) only for unsent text, and
setPendingAttachments receives only attachments that were not yet uploaded;
alternatively split upload and send into separate functions that retry
sendAgentInput with existing attachment IDs when available.
In `@app/lib/image-picker.web.ts`:
- Around line 22-26: The promise awaiting the file picker can hang if the native
dialog is dismissed because input.onchange never fires; update the picker logic
to also detect dialog cancel by using a window focus handler: when initiating
the picker (before input.click()), add a one-time
window.addEventListener('focus', onFocus) that checks input.files and, if none
selected, resolves the promise with null; ensure you clean up the focus listener
and the input.onchange handler in both success and cancel paths so the Promise
always resolves and no listeners leak (refer to the existing input.onchange,
input.click and the local file promise).
---
Nitpick comments:
In `@app/lib/image-picker.native.ts`:
- Around line 33-37: The call to ImagePicker.launchImageLibraryAsync uses the
deprecated ImagePicker.MediaTypeOptions.Images; update the options to use the
new MediaType array form instead—modify the mediaTypes field passed to
ImagePicker.launchImageLibraryAsync (the same call that assigns to result) to
use a string or string-array like ['images'] (or the equivalent MediaType value
supported by the pinned expo-image-picker version) so the deprecated
MediaTypeOptions accessor is removed.
In `@src/metadata-server.ts`:
- Around line 2681-2683: Update the validation error message emitted when both
text and attachmentIds are empty: replace the current send(res, 400, { ok:
false, error: "text is required" }) with a clearer message such as "text or
attachments are required" so the response matches the condition if (!text.trim()
&& attachmentIds.length === 0); also update the corresponding test expectation
in src/metadata-server.test.ts (the assertion around line 1402) to expect the
new message.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 72ef28fe-6ec6-444f-846a-c881bed66470
⛔ Files ignored due to path filters (1)
app/yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (13)
app/components/MessageBlock.test.tsapp/components/MessageBlock.tsxapp/components/screens/AgentChatScreen.tsxapp/lib/api.test.tsapp/lib/api.tsapp/lib/daemon-url.tsapp/lib/image-picker.native.tsapp/lib/image-picker.tsapp/lib/image-picker.web.tsapp/package.jsonsrc/attachment-store.tssrc/metadata-server.test.tssrc/metadata-server.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/components/screens/AgentChatScreen.tsx`:
- Around line 250-253: Add a sendBusy guard to prevent duplicate sends: at the
start of handleSendMessage() check if (sendBusy) return, then immediately
setSendBusy(true) before any async work and clear it in a finally block
(setSendBusy(false)); also update the keyboard handler that calls
handleSendMessage to check sendBusy before invoking it. Reference:
handleSendMessage, sendBusy, setSendBusy, keyboard handler (the Enter key
handler) and mirror the same pattern used in handleAttachImage.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 89a59404-fa6e-42d7-af3e-9ae2e6ed785a
📒 Files selected for processing (2)
app/components/screens/AgentChatScreen.tsxapp/lib/image-picker.web.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- app/lib/image-picker.web.ts
Summary
Verification
Summary by CodeRabbit
New Features
Bug Fixes / Improvements
Tests
Chores