Skip to content

feat(web): text file attachments for Ask#1374

Open
whoisthey wants to merge 28 commits into
mainfrom
whoisthey/text-file-attachments
Open

feat(web): text file attachments for Ask#1374
whoisthey wants to merge 28 commits into
mainfrom
whoisthey/text-file-attachments

Conversation

@whoisthey

@whoisthey whoisthey commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Adds text file attachments to Ask. Users can attach text/code/config files to a
chat message and the contents are folded into that turn's prompt.

Ways to attach

  • Paperclip button → native file picker (allowlisted text types)
  • Drag-and-drop anywhere on the chat pane (landing page + thread) with a drop overlay
  • Paste files directly into the chat box

Large-paste auto-conversion

  • A big plain-text paste (≥1,500 chars or ≥15 lines) is automatically turned into a
    pasted.txt attachment instead of being inserted inline, with a toast hinting that
    ⌘⇧V / Ctrl+Shift+V pastes inline.
  • The raw-paste chord (⌘⇧V / Ctrl+Shift+V) bypasses conversion for a single paste.
  • Falls back to inline insertion (and an error toast) if the size/count cap is hit.

Attachment UX

  • Staged tray of chips below the input (view contents / remove) before sending.
  • Sent attachments render above the user message and open a read-only viewer dialog.

Plumbing & limits

  • Attachments ride on the user message as data-attachment parts and are re-emitted
    per turn into the content as an <attachments> block, keeping them bound to the turn.
  • Server-side defensive truncation + filename sanitization/escaping.
  • Caps: 256KB per file, 5 attachments per message, allowlisted text MIME types/extensions.
  • Adds react-dropzone.

Potential Followup

  • Treat file attachments as first-class evidence that can be handled just like code/docs in the assistant's answer that can be rendered with per-line refs
Screen.Recording.2026-06-27.at.2.29.59.PM.mov
Screen.Recording.2026-06-27.at.2.32.59.PM.mov

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Attach text files to chat via drag-and-drop, the attachment picker, or paste (with auto-conversion for large pastes).
    • New chats and replies now include attachments alongside your message.
    • Attachment chips are shown in the thread, with an in-chat viewer dialog for inspecting attachment contents.
  • Bug Fixes

    • Improved reliability for capturing pasted/dropped attachments and ensuring they’re included in submitted messages and displayed in thread history.

whoisthey and others added 14 commits June 25, 2026 20:58
Add an optional `inputModalities` declaration to language model config and
expose a resolved capability set to the client.

- Schema: add optional `inputModalities` (`text` | `image` | `pdf`) to every
  provider definition in `schemas/v3/languageModel.json` and regenerate the
  schema types/snippets.
- Add a fail-closed `resolveModelInputModalities` resolver that defaults to
  text-only when a model does not declare its input modalities.
- Expose the resolved `inputModalities` on the client-safe `LanguageModelInfo`
  (populated via `getConfiguredLanguageModelsInfo` and the MCP ask path).

This is groundwork for chat file attachments. It adds no attachment UI and no
live provider capability probing yet.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
inputModalities now only enumerates true perceptual channels
(text | image | audio | video). Document/container formats like PDF
move to a separate fail-closed `supportedDocumentTypes` field, since
PDF is not a model modality but a format providers decompose into
text/image internally.

Co-authored-by: Cursor <cursoragent@cursor.com>
Tighten the inputModalities / supportedDocumentTypes descriptions to
remove the implication that omitting supportedDocumentTypes blocks all
non-text attachments. Clarify the taxonomy: single-medium files
(images, audio, video) and plain-text files (.txt, .md) are governed by
inputModalities; supportedDocumentTypes only gates rich compound
container formats like PDF.

Co-authored-by: Cursor <cursoragent@cursor.com>
LanguageModelInfo now has required inputModalities/supportedDocumentTypes,
so a raw LanguageModel config (where those are optional) is no longer
assignable to it. getLanguageModelKey only reads provider/model/displayName,
so type its parameter as that Pick subset, letting both LanguageModel and
LanguageModelInfo be keyed. Fixes the docker build type check.

Co-authored-by: Cursor <cursoragent@cursor.com>
Two dev-experience fixes for the stale-build-output footgun:

- schemas watch now runs `yarn build` (generate + tsc) instead of
  generate-only, so editing a schema JSON during `yarn dev` refreshes
  dist (both the .d.ts types and the runtime index.schema.js used by
  ajv), not just the generated source.
- web tsconfig maps @sourcebot/schemas/v3|v2/* to the package source,
  so type-checking and the IDE read committed source directly instead
  of stale built .d.ts. Web only imports .type files (erased at
  compile), so there is no bundling/runtime impact.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ards, wired into user message via xml-like tags similar to system context
….json

Re-source language model input-modality / document capabilities from the
models.dev catalog instead of hand-declared config.json fields, aligning
with the move to de-emphasize on-disk config in favor of automatic
resolution (the same catalog already backs context-window resolution).

- Revert the inputModalities/supportedDocumentTypes additions to
  schemas/v3/languageModel.json and all regenerated artifacts; capabilities
  are no longer declared in config.json.
- Extract the shared models.dev catalog plumbing (fetch/TTL/negative-cache/
  stale-while-revalidate/provider-id overrides) into modelsDevCatalog.server.ts,
  now consumed by both context-window and capability resolution.
- Add models.dev-backed resolveModelCapabilities (modelCapabilities.server.ts),
  partitioning the catalog's modalities.input list into Sourcebot's
  inputModalities (channels) and supportedDocumentTypes (containers); falls back
  to text-only for uncatalogued / self-hosted models.

The client-safe LanguageModelInfo contract is unchanged; only the resolution
backend moved.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1bafe865-db53-4931-b010-a02e250b5614

📥 Commits

Reviewing files that changed from the base of the PR and between 14a237d and cb8181d.

📒 Files selected for processing (1)
  • packages/web/src/features/chat/components/chatBox/chatBox.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/web/src/features/chat/components/chatBox/chatBox.tsx

Walkthrough

Adds text attachment support across chat input, message creation, rendering, and agent prompt handling. The PR introduces attachment schemas, constants, utilities, dropzone/file-picker UI, ChatBox attachment state and submission changes, and landing-page/chat-thread wiring for dropped or pasted files.

Changes

Chat File Attachment Feature

Layer / File(s) Summary
Attachment types and constants
packages/web/src/features/chat/types.ts, packages/web/src/features/chat/constants.ts, packages/web/package.json
Defines attachment schemas and message part typing, exports attachment limits and allowlists, and adds the required chat dependencies.
Attachment utility functions
packages/web/src/features/chat/attachmentUtils.ts
Adds filename sanitization, pending attachment helpers, file acceptance checks, pasted-text attachment creation, and asynchronous file reading helpers.
ChatBox attachment state and submission
packages/web/src/features/chat/components/chatBox/chatBox.tsx, packages/web/src/features/chat/components/chatBox/index.ts
Extends ChatBox with attachment-aware state, imperative file ingestion, paste handling, submit behavior, and the updated public handle and submit contract.
Attachment picker and viewer components
packages/web/src/features/chat/components/chatBox/attachmentButton.tsx, packages/web/src/features/chat/components/chatBox/attachmentTray.tsx, packages/web/src/features/chat/components/chatBox/attachmentViewerDialog.tsx, packages/web/src/ee/features/chat/components/chatThread/messageAttachments.tsx
Adds the file picker button, pending attachment tray, and attachment viewer dialog used to inspect uploaded text attachments, plus message-level attachment rendering.
ChatPaneDropzone drag-and-drop component
packages/web/src/features/chat/components/chatBox/chatPaneDropzone.tsx
Adds the drag-and-drop wrapper for chat panes, including accepted and rejected drag states, overlay rendering, file-drop forwarding, and rejection toasts.
Message attachment propagation
packages/web/src/features/chat/utils.ts, packages/web/src/features/chat/useCreateNewChatThread.ts
Extends chat message creation and user-message helpers to carry attachment parts and format attachment text for prompts.
Agent prompt includes attachment text
packages/web/src/ee/features/chat/agent.ts
Updates user-turn normalization in the agent to append formatted attachment content with a byte limit.
ChatThread dropzone and submission wiring
packages/web/src/ee/features/chat/components/chatThread/chatThread.tsx
Adds attachment drop handling and attachment-aware submission wiring to the chat thread input area.
Landing page dropzone wiring
packages/web/src/app/(app)/askgh/[owner]/[repo]/components/landingPage.tsx, packages/web/src/app/(app)/chat/chatLandingPage.tsx, packages/web/src/app/(app)/chat/components/chatLandingDropzone.tsx, packages/web/src/app/(app)/chat/components/landingPageChatBox.tsx, CHANGELOG.md
Wraps the chat landing experiences in dropzone containers, wires the chat box ref registration used to inject dropped files, and updates the changelog entry.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • brendan-kellam
  • msukkari
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: text file attachments for Ask in the web app.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch whoisthey/text-file-attachments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@whoisthey whoisthey changed the base branch from main to whoisthey/language-model-input-modalities June 27, 2026 18:47
@github-actions

github-actions Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

License Audit

⚠️ Status: PASS

Metric Count
Total packages 2224
Resolved (non-standard) 12
Unresolved 0
Strong copyleft 0
Weak copyleft 39

Weak Copyleft Packages (informational)

Package Version License
@img/sharp-libvips-darwin-arm64 1.0.4 LGPL-3.0-or-later
@img/sharp-libvips-darwin-arm64 1.2.4 LGPL-3.0-or-later
@img/sharp-libvips-darwin-x64 1.0.4 LGPL-3.0-or-later
@img/sharp-libvips-darwin-x64 1.2.4 LGPL-3.0-or-later
@img/sharp-libvips-linux-arm 1.0.5 LGPL-3.0-or-later
@img/sharp-libvips-linux-arm 1.2.4 LGPL-3.0-or-later
@img/sharp-libvips-linux-arm64 1.0.4 LGPL-3.0-or-later
@img/sharp-libvips-linux-arm64 1.2.4 LGPL-3.0-or-later
@img/sharp-libvips-linux-ppc64 1.2.4 LGPL-3.0-or-later
@img/sharp-libvips-linux-riscv64 1.2.4 LGPL-3.0-or-later
@img/sharp-libvips-linux-s390x 1.0.4 LGPL-3.0-or-later
@img/sharp-libvips-linux-s390x 1.2.4 LGPL-3.0-or-later
@img/sharp-libvips-linux-x64 1.0.4 LGPL-3.0-or-later
@img/sharp-libvips-linux-x64 1.2.4 LGPL-3.0-or-later
@img/sharp-libvips-linuxmusl-arm64 1.0.4 LGPL-3.0-or-later
@img/sharp-libvips-linuxmusl-arm64 1.2.4 LGPL-3.0-or-later
@img/sharp-libvips-linuxmusl-x64 1.0.4 LGPL-3.0-or-later
@img/sharp-libvips-linuxmusl-x64 1.2.4 LGPL-3.0-or-later
@img/sharp-wasm32 0.33.5 Apache-2.0 AND LGPL-3.0-or-later AND MIT
@img/sharp-wasm32 0.34.5 Apache-2.0 AND LGPL-3.0-or-later AND MIT
@img/sharp-win32-arm64 0.34.5 Apache-2.0 AND LGPL-3.0-or-later
@img/sharp-win32-ia32 0.33.5 Apache-2.0 AND LGPL-3.0-or-later
@img/sharp-win32-ia32 0.34.5 Apache-2.0 AND LGPL-3.0-or-later
@img/sharp-win32-x64 0.33.5 Apache-2.0 AND LGPL-3.0-or-later
@img/sharp-win32-x64 0.34.5 Apache-2.0 AND LGPL-3.0-or-later
axe-core 4.10.3 MPL-2.0
dompurify 3.4.11 (MPL-2.0 OR Apache-2.0)
lightningcss 1.32.0 MPL-2.0
lightningcss-android-arm64 1.32.0 MPL-2.0
lightningcss-darwin-arm64 1.32.0 MPL-2.0
lightningcss-darwin-x64 1.32.0 MPL-2.0
lightningcss-freebsd-x64 1.32.0 MPL-2.0
lightningcss-linux-arm-gnueabihf 1.32.0 MPL-2.0
lightningcss-linux-arm64-gnu 1.32.0 MPL-2.0
lightningcss-linux-arm64-musl 1.32.0 MPL-2.0
lightningcss-linux-x64-gnu 1.32.0 MPL-2.0
lightningcss-linux-x64-musl 1.32.0 MPL-2.0
lightningcss-win32-arm64-msvc 1.32.0 MPL-2.0
lightningcss-win32-x64-msvc 1.32.0 MPL-2.0
Resolved Packages (12)
Package Version Original Resolved Source
@react-grab/cli 0.1.23 UNKNOWN MIT GitHub repo (aidenybai/react-grab) + bundled LICENSE in npm tarball
@react-grab/cli 0.1.29 UNKNOWN MIT GitHub repo (aidenybai/react-grab) + bundled LICENSE in npm tarball
@react-grab/mcp 0.1.29 UNKNOWN MIT bundled LICENSE in npm tarball (@react-grab monorepo, MIT)
codemirror-lang-elixir 4.0.0 UNKNOWN Apache-2.0 GitHub repo LICENSE (livebook-dev/codemirror-lang-elixir)
element-source 0.0.3 UNKNOWN MIT bundled LICENSE in npm tarball
khroma 2.1.0 UNKNOWN MIT GitHub repo LICENSE (fabiospampinato/khroma)
lezer-elixir 1.1.2 UNKNOWN Apache-2.0 GitHub repo LICENSE (livebook-dev/lezer-elixir)
map-stream 0.1.0 UNKNOWN MIT GitHub repo LICENSE (dominictarr/map-stream)
memorystream 0.3.1 UNKNOWN MIT npm registry licenses field {type:MIT}
pause-stream 0.0.11 ["MIT","Apache2"] MIT extracted from object/array license ["MIT","Apache2"]
posthog-js 1.369.0 SEE LICENSE IN LICENSE Apache-2.0 GitHub repo LICENSE (PostHog/posthog-js)
valid-url 1.0.9 UNKNOWN MIT GitHub repo LICENSE (ogt/valid-url)

@whoisthey whoisthey changed the base branch from whoisthey/language-model-input-modalities to main June 27, 2026 21:08
@whoisthey whoisthey marked this pull request as ready for review June 27, 2026 21:09
@github-actions

This comment has been minimized.

@brendan-kellam

Copy link
Copy Markdown
Contributor

@whoisthey do you mind adding screenshots of the UX?

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/web/src/features/chat/components/chatBox/chatBox.tsx (1)

270-283: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Persist attachments through the login/upgrade redirect.

Lines 270-282 only save children, and Line 325 restores the submission with [], so attached files are silently lost on the auth/upsell path.

Suggested direction
- JSON.stringify({ pathname, children: editor.children }),
+ JSON.stringify({
+   pathname,
+   children: editor.children,
+   attachments: attachments.map(toAttachmentData),
+ }),
...
- const { pathname: storedPathname, children } = JSON.parse(stored) as { pathname: string; children: Descendant[] };
+ const {
+   pathname: storedPathname,
+   children,
+   attachments: storedAttachments = [],
+ } = JSON.parse(stored) as {
+   pathname: string;
+   children: Descendant[];
+   attachments?: AttachmentData[];
+ };
...
- _onSubmit(children, editor, []);
+ _onSubmit(children, editor, storedAttachments);

Also applies to: 324-325

🤖 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 `@packages/web/src/features/chat/components/chatBox/chatBox.tsx` around lines
270 - 283, Persist the full pending submission through the auth/upgrade flow in
chatBox.tsx, not just editor.children. Update the sessionStorage payload written
in the login/upgrade branches of the chat submission path to include attachments
(and any other required submission state) alongside pathname and children, then
update the restore logic that currently rebuilds the submission with an empty
attachments array so it rehydrates from the saved data instead. Use the existing
pending submission handling in the chatBox component and the sessionStorage key
to keep the login/upgrade redirect path lossless.
🤖 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 `@packages/web/src/app/`(app)/askgh/[owner]/[repo]/components/landingPage.tsx:
- Around line 72-81: Attachments are being dropped from the pending submission
flow on the AskGH landing page, so unauthenticated users lose staged files after
passing the login wall. Update the gated submit path in landingPage.tsx where
ChatBox/onSubmit calls createNewChatThread, and ensure the pending-submission
serializer/restorer includes attachments alongside pathname and children so
files survive auth resume. Use the existing ChatBox, createNewChatThread, and
pending-submission handling symbols to wire attachments through end-to-end.

In `@packages/web/src/features/chat/attachmentUtils.ts`:
- Around line 196-237: The attachment limit check in readFilesAsAttachments is
using only the stale existingCount snapshot, which allows overlapping add flows
to bypass ATTACHMENT_MAX_COUNT. Update the add flow in chatBox.tsx’s onAddFiles
and the helper in attachmentUtils.ts so the limit is enforced against the latest
attachment state at commit time, not just at read time; use the current
attachments length when appending and recheck before merging added files. Keep
the logic tied to readFilesAsAttachments, ATTACHMENT_MAX_COUNT, and
setAttachments so concurrent drops/selections cannot overshoot the cap.
- Around line 33-37: The filename truncation logic in attachmentUtils’s
extension-preserving helper can still exceed ATTACHMENT_MAX_FILENAME_LENGTH when
the extension is long. Update the truncation in this helper so the final result,
including the ellipsis and extension, is always capped at the limit by reducing
or omitting the extension as needed before returning the string. Use the
existing ATTACHMENT_MAX_FILENAME_LENGTH, cleaned, dotIndex, and stem logic to
locate the fix.

In `@packages/web/src/features/chat/components/chatBox/chatBox.tsx`:
- Around line 141-149: The attachment quota check in onAddFiles uses a stale
render-time attachments.length and can be bypassed by overlapping addFiles()
calls. Update chatBox.tsx so readFilesAsAttachments and the subsequent
setAttachments append are both clamped against the latest attachment count,
ideally by computing the remaining slots from the current state inside
setAttachments or by passing a fresh count derived from prev rather than the
closed-over attachments value.
- Around line 464-468: The AttachmentTray in chatBox should not expose remove
actions while rendering submittedAttachments during redirect, because
removeAttachment only updates the pending attachments state. Update the chatBox
conditional around AttachmentTray so the onRemove handler is omitted or disabled
when isRedirecting is true, using the isRedirecting, submittedAttachments, and
removeAttachment symbols to keep the tray controls consistent with the active
state.

In `@packages/web/src/features/chat/utils.ts`:
- Around line 430-441: Escape or encode the attachment body in the `blocks`
mapping inside `utils.ts` before interpolating `attachment.text` into the
`<attachment>` wrapper. The current `text` value can contain tag-closing
sequences like `</attachment>` and break the prompt structure, so update the
`attachment.text` handling in this block to use a safe structured encoding
rather than raw insertion, while keeping the existing filename sanitization in
place.
- Around line 431-433: The attachment truncation in the text handling logic is
using string slicing by UTF-16 code units instead of enforcing the byte cap, so
update the `maxBytesPerAttachment` branch in `utils.ts` to truncate by UTF-8
bytes. Use `TextEncoder` or equivalent byte counting in the attachment text path
so the `attachment.text` value stays within `ATTACHMENT_MAX_TEXT_BYTES` even for
non-ASCII content, and keep the change localized to the truncation logic around
`text`.

---

Outside diff comments:
In `@packages/web/src/features/chat/components/chatBox/chatBox.tsx`:
- Around line 270-283: Persist the full pending submission through the
auth/upgrade flow in chatBox.tsx, not just editor.children. Update the
sessionStorage payload written in the login/upgrade branches of the chat
submission path to include attachments (and any other required submission state)
alongside pathname and children, then update the restore logic that currently
rebuilds the submission with an empty attachments array so it rehydrates from
the saved data instead. Use the existing pending submission handling in the
chatBox component and the sessionStorage key to keep the login/upgrade redirect
path lossless.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b37bc956-4494-43c6-8cae-f7448b529a9b

📥 Commits

Reviewing files that changed from the base of the PR and between d546511 and 38472b7.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (21)
  • packages/web/package.json
  • packages/web/src/app/(app)/askgh/[owner]/[repo]/components/landingPage.tsx
  • packages/web/src/app/(app)/chat/chatLandingPage.tsx
  • packages/web/src/app/(app)/chat/components/chatLandingDropzone.tsx
  • packages/web/src/app/(app)/chat/components/landingPageChatBox.tsx
  • packages/web/src/ee/features/chat/agent.ts
  • packages/web/src/ee/features/chat/components/chatThread/chatThread.tsx
  • packages/web/src/ee/features/chat/components/chatThread/chatThreadListItem.tsx
  • packages/web/src/ee/features/chat/components/chatThread/detailsCard.tsx
  • packages/web/src/ee/features/chat/components/chatThread/messageAttachments.tsx
  • packages/web/src/features/chat/attachmentUtils.ts
  • packages/web/src/features/chat/components/chatBox/attachmentButton.tsx
  • packages/web/src/features/chat/components/chatBox/attachmentTray.tsx
  • packages/web/src/features/chat/components/chatBox/attachmentViewerDialog.tsx
  • packages/web/src/features/chat/components/chatBox/chatBox.tsx
  • packages/web/src/features/chat/components/chatBox/chatPaneDropzone.tsx
  • packages/web/src/features/chat/components/chatBox/index.ts
  • packages/web/src/features/chat/constants.ts
  • packages/web/src/features/chat/types.ts
  • packages/web/src/features/chat/useCreateNewChatThread.ts
  • packages/web/src/features/chat/utils.ts

Comment thread packages/web/src/features/chat/attachmentUtils.ts Outdated
Comment thread packages/web/src/features/chat/attachmentUtils.ts
Comment thread packages/web/src/features/chat/components/chatBox/chatBox.tsx
Comment thread packages/web/src/features/chat/components/chatBox/chatBox.tsx
Comment thread packages/web/src/features/chat/utils.ts
Comment thread packages/web/src/features/chat/utils.ts Outdated
Comment thread packages/web/src/ee/features/chat/agent.ts
Comment thread packages/web/src/features/chat/constants.ts Outdated
@whoisthey

Copy link
Copy Markdown
Contributor Author

@whoisthey do you mind adding screenshots of the UX?

Added two vids showing flows (drag and drop, paste file/text, paste inline, and click-to-attach)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/web/src/features/chat/attachmentUtils.ts (1)

183-190: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Budget attachments from decoded text, not raw file bytes.

Line 189 stores file.size, but packages/web/src/features/chat/components/chatBox/chatBox.tsx enforces the turn limit through getSubmittedTextBytes(), which is documented as UTF-8 prompt bytes. That makes file attachments use on-disk bytes while pasted attachments use text bytes, so UTF-16/BOM text files can be rejected or admitted incorrectly.

Suggested fix
         try {
             const text = await readAsText(file);
+            const sizeBytes = new TextEncoder().encode(text).length;
             attachments.push({
                 id: uuidv4(),
                 kind: 'text',
                 filename: sanitizeFilename(file.name),
                 mediaType: file.type || 'text/plain',
-                sizeBytes: file.size,
+                sizeBytes,
                 text,
             });
         } catch {
🤖 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 `@packages/web/src/features/chat/attachmentUtils.ts` around lines 183 - 190,
The attachment size accounting in attachmentUtils should use the decoded text
bytes instead of the raw file.size value so it matches the UTF-8 prompt
budgeting used by chatBox and getSubmittedTextBytes(). Update the text
attachment path in attachmentUtils to derive sizeBytes from the text content
(after readAsText/file decoding) and keep the existing filename/mediaType
handling unchanged, so text files are accepted or rejected consistently with
pasted text.
🤖 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.

Outside diff comments:
In `@packages/web/src/features/chat/attachmentUtils.ts`:
- Around line 183-190: The attachment size accounting in attachmentUtils should
use the decoded text bytes instead of the raw file.size value so it matches the
UTF-8 prompt budgeting used by chatBox and getSubmittedTextBytes(). Update the
text attachment path in attachmentUtils to derive sizeBytes from the text
content (after readAsText/file decoding) and keep the existing
filename/mediaType handling unchanged, so text files are accepted or rejected
consistently with pasted text.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 41b6f302-c9a3-46e5-a1d8-ff6f003848f1

📥 Commits

Reviewing files that changed from the base of the PR and between 2222dba and 14a237d.

📒 Files selected for processing (6)
  • packages/web/src/ee/features/chat/agent.ts
  • packages/web/src/features/chat/attachmentUtils.ts
  • packages/web/src/features/chat/components/chatBox/attachmentTray.tsx
  • packages/web/src/features/chat/components/chatBox/chatBox.tsx
  • packages/web/src/features/chat/constants.ts
  • packages/web/src/features/chat/utils.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/web/src/features/chat/components/chatBox/attachmentTray.tsx
  • packages/web/src/ee/features/chat/agent.ts
  • packages/web/src/features/chat/components/chatBox/chatBox.tsx

@whoisthey whoisthey requested a review from brendan-kellam June 27, 2026 22:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants