Commit 051a974
feat: s3 storage and richer file support (cgoinglove#301)
## Summary
- Stand up a production-ready S3 storage driver: presigned PUT upload
flow, head/tail download helpers, CLI smoke check, new env surface area,
and doc updates for
teams migrating off Vercel Blob.
- Rebuild the upload UX into a thread-scoped, multi-file pipeline with
drag-and-drop overlay, retry-aware queueing, per-file progress, and
consistent metadata fan-
out for chat state, clipboard, and API payloads.
- Normalize attachment rendering so user vs. assistant bubbles style
correctly, filenames truncate, filetype badges surface, and download
affordances remain obvious
—even when multiple cards stack together.
- Tighten the file-handling contract: only image/PDF MIME types flow
through as file parts; everything else gracefully downgrades to a
source-url card so models
never receive unsupported media. CSV is special-cased with a hidden
markdown preview that the model consumes while the UI stays clean.
- Advertise per-model MIME capabilities through customModelProvider,
letting the composer warn early and making unsupported models fall back
without breaking tool
calls.
- Auto-ingest CSV attachments by streaming server-side previews,
plugging into chat history so agents can immediately cite tabular
context. Added coverage for
preview formatting and ingestion gating.
- Document the new storage story (docs/storage/s3-setup.md) and codex
agent metadata (AGENTS.md), plus extend unit tests across storage utils,
ingestion, and MIME
support.
### File Handling Model
- Provider MIME gates: The client now trusts explicit allowlists
attached to each model. If a provider (e.g., OpenAI) cannot ingest a
media type, we flip the part
to source-url so the LLM sees a link instead of throwing “functionality
not supported.” This keeps uploads future-proof and highlights the
narrow set of formats
we genuinely support today (images + PDF).
- CSV ingestion preview: CSV files render an ingestionPreview text part
that the UI suppresses but the model consumes, giving instant structured
context without
polluting the chat transcript.
- Threaded uploader: Each thread maintains its own queue, enabling
parallel uploads, progress tracking, and safe retry semantics.
Drag-and-drop, button uploads, and
clipboard pastes all flow through a single hook so we don’t
double-handle state.
- UI parity: File bubbles respect author context, maintain readability
with truncation and badges, and keep download buttons consistent even
when stacking multiple
attachments.
## Screenshots / Recordings
### Drag and Drop
https://github.com/user-attachments/assets/1346b0e7-fa86-4a8f-abee-bd69542c93b9
### Multi File Drag and Drop
https://github.com/user-attachments/assets/d3e3bd27-6cee-4ac4-86f6-b08bc1ce5973
### CSV Preview
https://github.com/user-attachments/assets/9382005f-ea50-4377-9e15-34d3bb88c7fc
## Configuration Notes
- .env.example now documents FILE_STORAGE_TYPE (vercel-blob or s3),
FILE_STORAGE_S3_BUCKET, region, optional CDN origin, and other S3 knobs.
- S3 driver uses AWS credentials from env or the default provider chain;
fallback instructions live in docs/storage/s3-setup.md.
- CSV ingestion continues to leverage /api/storage/ingest; ensure your
storage backend serves direct downloads for the preview step.
## Verification Guide
1. pnpm dev
2. Upload a mix of image + CSV + PDF via the picker and via
drag-and-drop. Confirm badges, truncation, download button, and
per-thread queues.
3. Switch to a model that doesn’t support file parts; ensure attachments
render as “source-url” cards instead of failing tool calls.
4. Send a CSV attachment and validate the assistant references the
preview immediately with no visible summary text in the chat.
5. (Optional) Point to S3 credentials, generate a presigned PUT (CLI
script provided), upload through the UI, and confirm the file is present
via S3 console or aws
s3 head object.
## Tests
- pnpm format
- pnpm lint
- pnpm check-types
- pnpm test
## Documentation & Follow-up
- New S3 setup guide at docs/storage/s3-setup.md.
- Added AGENTS.md for Codex agent metadata.
- Future: add XLSX ingestion once a server-side parser/vectorization
pipeline lands; capture upload telemetry once S3 analytics hooks are in
place.
---------
Co-authored-by: Copilot <[email protected]>1 parent 4513ac0 commit 051a974
File tree
38 files changed
+1855
-205
lines changed- docs/storage
- messages
- src
- app/api
- chat
- storage
- ingest
- upload-url
- components
- hooks
- queries
- lib
- ai
- image
- ingest
- tools/code
- file-ingest
- file-storage
- types
38 files changed
+1855
-205
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
105 | | - | |
| 105 | + | |
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
109 | 109 | | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
194 | 194 | | |
195 | 195 | | |
196 | 196 | | |
197 | | - | |
| 197 | + | |
198 | 198 | | |
199 | 199 | | |
200 | 200 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
77 | | - | |
| 77 | + | |
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
77 | | - | |
| 77 | + | |
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
77 | | - | |
| 77 | + | |
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| 52 | + | |
| 53 | + | |
52 | 54 | | |
53 | 55 | | |
54 | 56 | | |
| |||
72 | 74 | | |
73 | 75 | | |
74 | 76 | | |
| 77 | + | |
75 | 78 | | |
76 | 79 | | |
77 | 80 | | |
| |||
104 | 107 | | |
105 | 108 | | |
106 | 109 | | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
107 | 174 | | |
108 | 175 | | |
109 | 176 | | |
| |||
0 commit comments