feat: evict the oldest attachments at the chat file cap - #29063
Conversation
Docs previewCheck off each page once it's been reviewed. If a page changes in a later push, its checkbox clears automatically so it gets a fresh look. Pages not yet wired into the docs navigation aren't listed here. |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Documentation CheckUpdates Needed
Automated review via Coder Agents |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bcbe2deda3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2a3369b469
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review re: Lock link writes before deduplicating We don't support rolling upgrades, so this isn't a case we need to handle. No other migration in the repo guards against writes from an old replica mid-migration, and the upgrade docs recommend scaling to zero before upgrading. Between the DELETE and the ALTER TABLE there's nothing running that could insert a link. |
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
b25671b to
cf8a752
Compare
cf8a752 to
ba55c4e
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8ef11f7729
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db26ee0489
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review re: Replace the architecture rewrite with TODO markers That is the architecture.md change I've made and written, we don't want to commit todo markers to main. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db26ee0489
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (part.type === "file" && part.file_id) { | ||
| referencedFileIds.push(part.file_id); |
There was a problem hiding this comment.
Handle evicted recordings in the attachment fallback
When newer attachments evict a computer-use recording, this scan cannot detect it because recording_file_id and thumbnail_file_id are nested in a wait_agent tool result rather than represented as type: "file" parts. storeRecordingArtifact links those files to the parent chat, so they participate in the new eviction policy, but RecordingPreview will continue rendering an active play button and at most report the thumbnail as unavailable after the video has been deleted. Include recording IDs in the availability model and have the recording renderer show the expired state.
AGENTS.md reference: site/AGENTS.md:L11-L11
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 69d5aa0ef0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review re: Include queued attachments in eviction ordering The scan only loses its anchor when queued messages alone evict every historical file, which needs 50 or more files across queued messages while the chat is busy. A smaller queued batch on a full chat still flags the evicted files, because the newest surviving historical reference anchors the scan. Once the queued message is promoted its references enter the scan and the state corrects itself, and text attachments still fall back on click via the 404 path. Not worth the extra plumbing for that window. re: Exclude links belonging only to deleted messages This is pre-existing. On main those links count towards the cap and cause the attach to be rejected outright. Here they cause one earlier eviction and then age out as newer files arrive, so this branch is strictly better than main for that case. Unlinking on soft delete and queued delete is a reasonable follow-up but out of scope here. re: Base eviction order on attachment time Correct, the order is upload time rather than link time. The two differ only when a file is uploaded and linked later, which in the UI means a file sitting in the composer while the agent attaches 49 or more files before the user sends. The worst case is one user file evicted early and re-attached. The window is the 50 most recently uploaded files linked to the chat, and I'm happy with that trade-off rather than adding a timestamp to the link table. re: Replace the architecture rewrite with TODO markers That is the architecture.md change I've made and written, we don't want to commit todo markers to main. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 69d5aa0ef0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| }; | ||
|
|
||
| const displayMessages = buildDisplayMessages(parsedMessages); | ||
| const evictedFileIds = deriveEvictedFileIds(parsedMessages, chatFiles); |
There was a problem hiding this comment.
Refresh chat files after tool-created attachments
When attach_file, propose_plan, or recording storage evicts a file near the end of a run, this derives expiry from stale chatFiles: those tools do not invalidate the chat entity, watch payloads explicitly omit Files, and AgentsPageLayout cancels entity refetches before merging the terminal waiting status, which disables the only 5-second poll. The old attachment therefore remains rendered as available until a focus or manual refetch. Fresh evidence in this revision is that the new derivation now depends entirely on that metadata while the terminal watch path still cannot update it; invalidate the chat entity when an attachment-producing tool completes or when the run settles.
Useful? React with 👍 / 👎.
|
@codex review re: Include queued attachments in eviction ordering The scan only loses its anchor when queued messages alone evict every historical file, which needs 50 or more files across queued messages while the chat is busy. A smaller queued batch on a full chat still flags the evicted files, because the newest surviving historical reference anchors the scan. Once the queued message is promoted its references enter the scan and the state corrects itself, and text attachments still fall back on click via the 404 path. Not worth the extra plumbing for that window. re: Exclude links belonging only to deleted messages This is pre-existing. On main those links count towards the cap and cause the attach to be rejected outright. Here they cause one earlier eviction and then age out as newer files arrive, so this branch is strictly better than main for that case. Unlinking on soft delete and queued delete is a reasonable follow-up but out of scope here. re: Base eviction order on attachment time Correct, the order is upload time rather than link time. The two differ only when a file is uploaded and linked later, which in the UI means a file sitting in the composer while the agent attaches 49 or more files before the user sends. The worst case is one user file evicted early and re-attached. The window is the 50 most recently uploaded files linked to the chat, and I'm happy with that trade-off rather than adding a timestamp to the link table. re: Replace the architecture rewrite with TODO markers That is the architecture.md change I've made and written, we don't want to commit todo markers to main. re: Refresh chat files after tool-created attachments The mechanics are right, but the impact is one tile: a chat at the cap, an attachment landing in the last few seconds of a run, and the oldest attachment in the timeline shows as available instead of expired until the next send, next run, or reload. Clicking it hits the same 404 fallbacks the UI already had. A stale file list can never flag a live file as expired, so there is no false positive side. Not worth an extra fetch per run end for that, so leaving it. |
|
Codex Review: Didn't find any major issues. What shall we delve into next? Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Long-running agent sessions hit the 50 attachment cap and then rejected every further upload, screenshot, and attach_file call. A chat now keeps its 50 most recent attachments. LinkChatFilesAfterLock deletes the oldest chat_files rows on the chat in the same statement, and the ON DELETE CASCADE on chat_file_links removes the links. Files in the incoming batch, or still linked to another chat, are never evicted, so the only remaining rejection is a single message that references more than 50 files. Evicted attachments render as "Attachment expired" in the UI, and dispatch already replaces missing files with text placeholders. Closes CODAGT-933
A single tool attachment can no longer be rejected at the cap: a one-file batch always fits and eviction makes room. The mocked store returned a rejection the real query cannot produce for this caller.
Text and download tiles now probe attachment availability on mount, so evicted files render the expired placeholder without a click. The expired tooltip names the attachment cap alongside the retention window.
The mount-time probe fetched every attachment blob to learn whether it still existed, and nothing revalidated it after eviction. The chat record already lists the files it holds and eviction is oldest-first, so the timeline now marks a referenced file as evicted only when it is absent from chat.files and referenced before the newest file that is still listed. References after that point are newer than the record and are presumed present until the next refetch.
69d5aa0 to
5715f8f
Compare
|
@codex review re: Include queued attachments in eviction ordering The scan only loses its anchor when queued messages alone evict every historical file, which needs 50 or more files across queued messages while the chat is busy. A smaller queued batch on a full chat still flags the evicted files, because the newest surviving historical reference anchors the scan. Once the queued message is promoted its references enter the scan and the state corrects itself, and text attachments still fall back on click via the 404 path. Not worth the extra plumbing for that window. re: Exclude links belonging only to deleted messages This is pre-existing. On main those links count towards the cap and cause the attach to be rejected outright. Here they cause one earlier eviction and then age out as newer files arrive, so this branch is strictly better than main for that case. Unlinking on soft delete and queued delete is a reasonable follow-up but out of scope here. re: Base eviction order on attachment time Correct, the order is upload time rather than link time. The two differ only when a file is uploaded and linked later, which in the UI means a file sitting in the composer while the agent attaches 49 or more files before the user sends. The worst case is one user file evicted early and re-attached. The window is the 50 most recently uploaded files linked to the chat, and I'm happy with that trade-off rather than adding a timestamp to the link table. re: Replace the architecture rewrite with TODO markers That is the architecture.md change I've made and written, we don't want to commit todo markers to main. re: Refresh chat files after tool-created attachments The mechanics are right, but the impact is one tile: a chat at the cap, an attachment landing in the last few seconds of a run, and the oldest attachment in the timeline shows as available instead of expired until the next send, next run, or reload. Clicking it hits the same 404 fallbacks the UI already had. A stale file list can never flag a live file as expired, so there is no false positive side. Not worth an extra fetch per run end for that, so leaving it. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5715f8f642
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… stories Pixel screenshots the expired recording and download tiles. The fetch-count assertions on text and download tiles asserted nothing, since neither tile fetches on mount in any state.
|
@codex review re: Include queued attachments in eviction ordering The scan only loses its anchor when queued messages alone evict every historical file, which needs 50 or more files across queued messages while the chat is busy. A smaller queued batch on a full chat still flags the evicted files, because the newest surviving historical reference anchors the scan. Once the queued message is promoted its references enter the scan and the state corrects itself, and text attachments still fall back on click via the 404 path. Not worth the extra plumbing for that window. re: Exclude links belonging only to deleted messages This is pre-existing. On main those links count towards the cap and cause the attach to be rejected outright. Here they cause one earlier eviction and then age out as newer files arrive, so this branch is strictly better than main for that case. Unlinking on soft delete and queued delete is a reasonable follow-up but out of scope here. re: Base eviction order on attachment time Correct, the order is upload time rather than link time. The two differ only when a file is uploaded and linked later, which in the UI means a file sitting in the composer while the agent attaches 49 or more files before the user sends. The worst case is one user file evicted early and re-attached. The window is the 50 most recently uploaded files linked to the chat, and I'm happy with that trade-off rather than adding a timestamp to the link table. re: Replace the architecture rewrite with TODO markers That is the architecture.md change I've made and written, we don't want to commit todo markers to main. re: Refresh chat files after tool-created attachments The mechanics are right, but the impact is one tile: a chat at the cap, an attachment landing in the last few seconds of a run, and the oldest attachment in the timeline shows as available instead of expired until the next send, next run, or reload. Clicking it hits the same 404 fallbacks the UI already had. A stale file list can never flag a live file as expired, so there is no false positive side. Not worth an extra fetch per run end for that, so leaving it. re: Move expired-recording checks out of Storybook play and Move downloadable-expiry checks into Vitest Dropped both play functions since they only asserted the rendered state, which Pixel now captures. I have not moved the fetch-count check into Vitest: download tiles are plain links and text tiles fetch on click, so neither fetches on mount in any state and the assertion could never fail. The derivation that picks the expired tile is covered in messageHelpers.test.ts. |
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Closes CODAGT-933
Long agent sessions were hitting the 50 attachment cap, after which every upload, screenshot and
attach_filecall was rejected, so people were abandoning otherwise healthy chats.Rather than raise the cap (which just moves the cliff and multiplies the worst-case per-chat
byteastorage), a chat now keeps its 50 most recent attachments.LinkChatFilesAfterLockdeletes the oldestchat_filesrows in the same statement and the cascade drops their links. Files in the incoming batch are never evicted, so the only remaining rejection is a single message with more than 50 files.Nothing in the product ever linked one file to two chats, so rather than guard the eviction against it, this adds
UNIQUE (file_id)onchat_file_links, with the migration dropping any existing duplicates in favour of the oldest chat.Evicted attachments render as the existing "Attachment expired" tile. A
pinnedflag is the obvious follow-up if someone needs to keep a specific file around.