Skip to content

fix: stop re-attaching already-delivered conversation files#1742

Draft
cmorman89 wants to merge 1 commit into
release/1.4from
fix-staged-uploads
Draft

fix: stop re-attaching already-delivered conversation files#1742
cmorman89 wants to merge 1 commit into
release/1.4from
fix-staged-uploads

Conversation

@cmorman89

Copy link
Copy Markdown
Contributor

Summary

An uploaded conversation file was treated as a pending attachment forever. Two gaps compounded:

  1. No delivered state. Nothing records that a file was already delivered to the agent with a user message, so the workflow's file map keeps offering it for re-attachment on every turn.
  2. Ephemeral suppression. The composer's only defense against re-attaching an already-sent file is in-session state (removedFileIds) that resets on every mount. The server's file_processing snapshot 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

  • common: ConversationFile.consumed_at (set once when the file is delivered with a user message) and the shared isDeliverableFile() predicate (READY and not consumed) so every consumer applies one rule.
  • ui: useFileProcessing accepts a set of already-delivered artifact references and excludes matching files from the pending-attachment map. ModernAgentConversation derives the set from sent-message history via the new collectDeliveredArtifactRefs() (colocated with parseUserMessageAttachments). Rebuilt from the message record on every mount, so it survives reloads — and works even against workers that don't yet stamp consumed_at.

The workflow-side counterpart (stamping consumed_at after 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 both artifact: reference and bare path)
  • turbo build for @vertesia/common + @vertesia/ui, typecheck:test, Biome — all clean

🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com

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
cmorman89 requested a review from a team as a code owner July 16, 2026 22:15
@cmorman89
cmorman89 marked this pull request as draft July 23, 2026 19:21
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.

1 participant