fix: set inline disposition for renderable blob elements - #2950
fix: set inline disposition for renderable blob elements#2950axelray-dev wants to merge 3 commits into
Conversation
SQLAlchemyDataLayer.create_element never passed content_disposition to storage_provider.upload_file, so Azure Blob Storage defaulted to Content-Disposition: attachment. This caused PDF elements (and other browser-renderable types) to render blank on chat resume because the browser refused to display them in an iframe. Set content_disposition='inline' for browser-renderable MIME types (application/pdf, image/*, audio/*, video/*) while preserving the existing behavior (None) for non-renderable uploads like generic files. Fixes Chainlit#2946 Co-Authored-By: OpenAI Codex <noreply@openai.com>
|
@codex review |
dokterbob
left a comment
There was a problem hiding this comment.
Please see my comment.
| if element.mime: | ||
| if element.mime in _RENDERABLE_MIME_TYPES or element.mime.startswith( | ||
| _RENDERABLE_MIME_PREFIXES | ||
| ): |
There was a problem hiding this comment.
Is there a more structural/consistent way to define renderable mime types?
I don't think this definition belongs inside a storage engine. I also don't think it should be in a single storage engine (how are others doing it?).
Sanity would dictate that some piece of code somewhere decides whether some attachment is rendered inline. Probably closer to the frontend than the storage backend. If this code already determines it, we should get the info from where it's determined, and there should be a well-defined interface for all data backends to look this up in the same way.
Move renderable disposition policy out of SQLAlchemy into Element.get_content_disposition based on element.type, and use it in SQLAlchemy, DynamoDB, and ChainlitDataLayer so browser-rendered media gets inline disposition consistently.
|
Moved the renderable disposition policy out of SQLAlchemy into Element.get_content_disposition(). It is based on element.type (image/pdf/audio/video), not MIME, because that is what the frontend uses for rendering. Element.display is still only UI placement. SQLAlchemy, DynamoDB, and ChainlitDataLayer now all use the same helper. ChainlitDataLayer still keeps its previous attachment/GCS fallback for non-renderable files. Also fixed the backend typecheck issues in the SQLAlchemy tests. |
Fixes #2946
Summary
SQLAlchemyDataLayer.create_element never passed content_disposition to storage_provider.upload_file. Azure Blob Storage defaults to Content-Disposition: attachment in this case, which causes browser-renderable elements (PDF, images, audio, video) to render blank on chat resume because iframes and media tags refuse to display content served with an attachment disposition.
This fix sets content_disposition='inline' for browser-renderable MIME types while preserving the existing behavior for non-renderable uploads.
Scope
Only browser-renderable MIME types are affected:
All other element types (generic files, text/plain, application/octet-stream, etc.) keep content_disposition=None, preserving the existing download behavior.
Changes
Testing
Backend tests run locally:
Note: pre-commit hooks could not run locally (frontend build OOMs on VPS). CI will verify lint and format.
Backward Compatibility
This change is fully backward-compatible per AGENTS.md requirements:
Summary by cubic
Serve browser-renderable blobs with inline Content-Disposition so PDFs, images, audio, and video display in iframes/media on chat resume. The policy is now centralized on
Elementand applied across data layers; non-renderable files keep download behavior.Element.get_content_disposition()and used bySQLAlchemyDataLayer,ChainlitDataLayer, and DynamoDB.inlineforpdf,image,audio,video; keep default for others.ChainlitDataLayerpreservesattachment; filename=...for generic files (non-GCS). Tests added for inline/default cases and Element behavior.Written for commit 3d7346e. Summary will update on new commits.