Files the user hands the assistant — images, documents, video — and the limits that apply to them.
The paperclip does not exist until the widget has somewhere to put a file. That is deliberate: an attach button on a surface with no upload endpoint is a control that fails after the user has already chosen a file, which is the worst moment to say no.
createAiChatWidget({
endpoint: "/accounts/acc_1/ai/chat",
uploadEndpoint: "/accounts/acc_1/assets/media", // POST multipart
});
There is also getUploadEndpoint(), read at
call time, for a host whose account can change without remounting the
widget — the same shape as getToken.
A multipart/form-data POST per file, with the bearer token
from getToken if you supplied one:
| field | value |
|---|---|
file | the file itself |
session | 1 — always |
threadId | the current thread, when there is one |
Your endpoint must answer with exactly this, and the nesting matters:
{ "media": { "id": "med_1", "filename": "notes.pdf", "contentType": "application/pdf" } }
The chat turn then carries ids, not bytes.
A response without media is dropped
in silence — no chip, no error, nothing in the console. If you
attach a file and nothing happens, check this shape first; it is the
likeliest cause and it looks exactly like a broken button.
session=1 is the whole difference between a
chat attachment and an upload to the asset library. A file dropped into
a conversation is part of that conversation: reachable from its history
by id, and never filed into the library where it would sit alongside
deliberate uploads nobody meant to make.
| limit | value | why |
|---|---|---|
| files per turn | 6 | Extra files past the sixth are dropped, not refused — the turn still sends. |
| image / document | 25 MB | Read by the model inline, so this bounds a prompt. |
| video / audio | 100 MB | Referenced by id and never sent inline. A 30-second 1080p phone video is already past the document cap, so sharing the cap would refuse the everyday case for being ordinary. |
An oversize file gets its own error chip naming the file and the cap, and the others in the same selection still upload. One bad file does not lose the batch.
The widget in the corner has an upload endpoint, so it shows the paperclip. This page is static, so the "server" below is a stub that hands back a fake media id — attach anything and watch the chip appear, or pick something over 25 MB to see the refusal.