Skip to content

Warn on staged text attachment the model may read truncated - #625

Merged
davidmckayv merged 2 commits into
CopilotKit:mainfrom
ApexYash11:fix/attachment-truncation-warning
Sep 20, 2026
Merged

davidmckayv merged 2 commits into
CopilotKit:mainfrom
ApexYash11:fix/attachment-truncation-warning

Conversation

@ApexYash11

Copy link
Copy Markdown
Contributor

Fixes #624.

Summary

Closes the trust gap recorded in shared/attachments.ts: the server accepts text uploads up to MAX_FILE_BYTES (1MB) but the model reads only the first MAX_EXTRACTED_CHARACTERS (120k). Until now the truncation caption went to the model only (attachment-parts.ts) with nothing on screen for the person, so a 1MB CSV showed as a 1.0MB tile and was answered as roughly its first eighth with no warning.

Changes

  • shared/attachments.ts: new mayBeTruncatedForModel(sizeBytes) predicate (size over MAX_EXTRACTED_CHARACTERS). Exact in the safe direction: UTF-8 N bytes decode to at most N chars, so a file at or under the ceiling cannot be cut; over it may be (multi-byte scripts lose less, hence may). Warning only, never refusal.
  • app/src/lib/channels/attachments.ts: re-export through the @/ path.
  • app/src/components/channels/composer/composer.tsx: files memo sets mayTruncate for non-uploading, non-image staged files over the ceiling. Images excluded (base64 path, not extraction); unnamed picks get no warning until the server sniffs them and the strip re-renders off the url source.
  • app/src/components/channels/composer/attachment-strip.tsx: StagedFile gains optional mayTruncate; tile shows May be read truncated with a title naming the 120,000-character limit.
  • shared/attachments.test.ts: existing inline predicate replaced with the real export (boundary at/under/over, max-upload case).
  • app/tests/composer-attachment-strip.test.tsx: tile warns when flagged, silent when not.

Verification

  • Standalone bun script exercising the real predicate plus source assertions: 11/11 PASS (boundary, zero-byte, wiring, render conditions).
  • Full bun test / typecheck / lint not runnable in reporter env: node_modules absent (no network install), repo bun 1.3.5 vs pinned 1.3.14, eventsource preload blocks the suite. Upstream CI will run format:check, lint, typecheck, test (floor 400), build.
  • Scope: display-only; no DB/migration/auth/policy/computer changes; screenPickedFiles refusal paths untouched.

@davidmckayv

Copy link
Copy Markdown
Contributor

This one is a real gap and the repository asks for it by name: shared/attachments.ts says the fix is a composer change and records it rather than fixing it there, and shared/attachments.test.ts already carries a placeholder calling it "the truncation warning the composer owes the sender". So the direction is right, and a 1 MB CSV reaching the model as roughly a tenth of itself is an answer-correctness problem, not a cosmetic one.

Closing this revision because of two defects rather than the idea.

The third line of text squashes the icon. The tile is a fixed h-20 with two flex children, so the text block growing to three lines takes the difference out of the icon, which renders about 20x14 instead of 20x20. The h-20 is load-bearing (it is what makes a file tile and a thumbnail read as one row), so the fix is shrink-0 on the icon, or folding the warning into the size line, something like "1.0MB · may be read truncated". jsdom cannot see this, which is why the tests pass.

The predicate is also the wrong one. attachment.type !== "image" reads the browser's claimed type, while the surrounding filter already excludes images using stagedModality, which deliberately prefers the server-sniffed mime. So a file the browser mislabelled as an image but the server sniffed as text lands in the file strip and gets no warning, which is exactly the file that will be truncated.

If you want to take another pass: those two, plus a test over the composer's derivation of the flag rather than only the tile rendering it. Happy to merge that.

@davidmckayv davidmckayv reopened this Sep 20, 2026
The warning arrived as a third line of text in a tile whose height is fixed, so
it did not fit: at this repository's 15px root the two in-flow children need
63.75px inside a 58px box, and the icon is the only one that can give. Measured
in Chromium, it rendered 18.75x13 on exactly the tiles carrying the warning.
Pinning the icon alone only moves the overflow onto the border, so the warning
folds onto the size line instead and the tile keeps two lines. `truncate` is
what guarantees that: `formatBytes` is unbounded, and a large enough file would
otherwise wrap the line and put the third one back.

Also drops the `attachment.type` test from the composer's derivation. The filter
above it already excludes images using `stagedModality`, which prefers the mime
the server sniffed; `attachment.type` is the browser's claim, fixed at pick time
and never revised. Testing both could only subtract, and the file it subtracted
is the one that matters: a file the browser called a PNG and the server read as
text goes down the extraction path and is exactly what gets cut. Covered by a
composer-level test, which the warning did not have.
@davidmckayv
davidmckayv merged commit 81c63a1 into CopilotKit:main Sep 20, 2026
16 checks passed
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.

Text attachments truncated for the model without telling the person

2 participants