Commit 3ba5928
committed
fix(copilot): disambiguate VFS upload paths to prevent stale-row reads
Same-name chat attachments (e.g. multiple "image.png" screenshots) collided
on the VFS path uploads/<originalName>. The agent's read("uploads/image.png")
returned whichever row Postgres ordered first — leading to the agent reading
stale uploads instead of the latest one (real prod incident: trace
71f719d884194b6820851e2267b98cda).
Adds a nullable display_name column on workspace_files plus a partial unique
index on (chat_id, display_name) WHERE context='mothership' that spans the
row's entire lifetime (NOT gated on deleted_at IS NULL). VFS paths handed to
the LLM during a session must remain stable — soft-deleting a sibling cannot
free a name slot the model has already been told about, since that would
make read("uploads/<name>") silently resolve to a different file.
Migration is a clean two-statement ADD COLUMN + CREATE UNIQUE INDEX with no
backfill. Legacy rows keep display_name = NULL; readers coalesce to
original_name. Pre-existing collisions in legacy data persist (the upload
already happened — no fix possible without rewriting history) but new
uploads get full disambiguation. NULLs are distinct in PG unique indexes,
so legacy rows don't block index creation or new inserts.
trackChatUpload allocates "image.png", then "image (2).png", "image (3).png",
... with retry on 23505 narrowed to the displayName index (other 23505s, e.g.
key-active collisions from concurrent same-s3Key inserts, rethrow). Returns
the assigned displayName so the read-hint string given to the model uses it.
Resolver matches displayName for new rows, falls back to original_name for
legacy NULL rows, and orders by uploaded_at DESC so legacy ambiguity resolves
to the newest upload (which fixes the original prod symptom even pre-fix).1 parent 288f023 commit 3ba5928
3 files changed
Lines changed: 10 additions & 22 deletions
File tree
- apps/sim/lib
- copilot/tools/handlers
- uploads/contexts/workspace
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
14 | | - | |
15 | | - | |
16 | | - | |
17 | | - | |
| 13 | + | |
18 | 14 | | |
19 | 15 | | |
20 | 16 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | | - | |
| 10 | + | |
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| |||
100 | 100 | | |
101 | 101 | | |
102 | 102 | | |
103 | | - | |
| 103 | + | |
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
| |||
Lines changed: 7 additions & 15 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
408 | 408 | | |
409 | 409 | | |
410 | 410 | | |
411 | | - | |
412 | | - | |
413 | | - | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
414 | 414 | | |
415 | 415 | | |
416 | | - | |
417 | | - | |
418 | | - | |
419 | | - | |
| 416 | + | |
420 | 417 | | |
421 | 418 | | |
422 | 419 | | |
423 | 420 | | |
424 | 421 | | |
425 | | - | |
| 422 | + | |
426 | 423 | | |
427 | 424 | | |
428 | 425 | | |
| |||
485 | 482 | | |
486 | 483 | | |
487 | 484 | | |
488 | | - | |
489 | | - | |
490 | | - | |
491 | | - | |
492 | | - | |
493 | | - | |
494 | | - | |
| 485 | + | |
| 486 | + | |
495 | 487 | | |
496 | 488 | | |
497 | 489 | | |
| |||
0 commit comments