fix: stop re-attaching already-delivered conversation files#1742
Draft
cmorman89 wants to merge 1 commit into
Draft
fix: stop re-attaching already-delivered conversation files#1742cmorman89 wants to merge 1 commit into
cmorman89 wants to merge 1 commit into
Conversation
An uploaded conversation file was treated as a pending attachment forever: the server-side file state never records that a file was delivered with a user message, and the composer's only suppression of already-sent files is ephemeral client state that resets on every mount. Files staged before a conversation starts (or resurfacing after a page reload) were silently re-attached to subsequent messages, decorating them with an "Uploaded artifacts:" footer and re-feeding the same file to the agent on every turn. - common: add ConversationFile.consumed_at (epoch millis, set once when the file is delivered with a user message) and the isDeliverableFile() predicate (READY and not yet consumed) so all consumers share one rule. - ui: useFileProcessing accepts a set of already-delivered artifact references and excludes matching files from the pending-attachment map; ModernAgentConversation derives that set from sent-message history via the new collectDeliveredArtifactRefs() helper (colocated with parseUserMessageAttachments). Unlike the session-only removedFileIds, this survives reloads because it is rebuilt from the message record. The workflow-side counterpart (marking files consumed after delivery) ships with the conversation workflow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nt86hvkDV3ZxTZweG9cd7C
cmorman89
marked this pull request as draft
July 23, 2026 19:21
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
An uploaded conversation file was treated as a pending attachment forever. Two gaps compounded:
removedFileIds) that resets on every mount. The server'sfile_processingsnapshot replays from history on reload and resurrects the file as a pending composer chip.Reliable trigger: stage a file before starting the conversation (the start path uploads it out-of-band and never registers it in the client's suppression state), or reload the page after sending one. The re-inserted file then decorates subsequent messages — including tool-approval option clicks — with an
Uploaded artifacts:footer, and the same file is re-fed to the agent on every turn.Changes
ConversationFile.consumed_at(set once when the file is delivered with a user message) and the sharedisDeliverableFile()predicate (READY and not consumed) so every consumer applies one rule.useFileProcessingaccepts a set of already-delivered artifact references and excludes matching files from the pending-attachment map.ModernAgentConversationderives the set from sent-message history via the newcollectDeliveredArtifactRefs()(colocated withparseUserMessageAttachments). Rebuilt from the message record on every mount, so it survives reloads — and works even against workers that don't yet stampconsumed_at.The workflow-side counterpart (stamping
consumed_atafter delivery and skipping consumed files when building agent context) ships with the conversation workflow.Verification
vitest:useFileProcessing.test.tsx— 6 tests incl. new delivered-refs exclusion (matches bothartifact:reference and bare path)turbo buildfor@vertesia/common+@vertesia/ui,typecheck:test, Biome — all clean🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com