From ac2cd0d0d43aa697f7aec292def8f96ca4152db6 Mon Sep 17 00:00:00 2001 From: Br1an67 <932039080@qq.com> Date: Mon, 2 Mar 2026 01:46:21 +0800 Subject: [PATCH 1/3] feat: add download_name parameter for custom download filenames Add download_name optional field to Element base class so developers can specify a human-readable filename for downloads instead of the UUID-based name. The file serving endpoint now sets Content-Disposition with the download_name (falling back to name) while keeping inline display for PDFs and other embedded elements. --- backend/chainlit/element.py | 3 +++ backend/chainlit/server.py | 8 +++++++- backend/chainlit/session.py | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/backend/chainlit/element.py b/backend/chainlit/element.py index 23a8b41a4a..b91b2b5c62 100644 --- a/backend/chainlit/element.py +++ b/backend/chainlit/element.py @@ -96,6 +96,8 @@ class Element: language: Optional[str] = None # Mime type, inferred based on content if not provided mime: Optional[str] = None + # Custom download filename. If set, this name is used when the file is downloaded. + download_name: Optional[str] = None def __post_init__(self) -> None: self.persisted = False @@ -218,6 +220,7 @@ async def _create(self, persist=True) -> bool: path=self.path, content=self.content, mime=self.mime or "", + download_name=self.download_name, ) self.chainlit_key = file_dict["id"] diff --git a/backend/chainlit/server.py b/backend/chainlit/server.py index f9393e5e3b..35e5f9203d 100644 --- a/backend/chainlit/server.py +++ b/backend/chainlit/server.py @@ -1657,7 +1657,13 @@ async def get_file( if file_id in session.files: file = session.files[file_id] - return FileResponse(file["path"], media_type=file["type"]) + filename = file.get("download_name") or file.get("name") + return FileResponse( + file["path"], + media_type=file["type"], + filename=filename, + content_disposition_type="inline", + ) else: raise HTTPException(status_code=404, detail="File not found") diff --git a/backend/chainlit/session.py b/backend/chainlit/session.py index d6bd3f6214..e30c0c6fe3 100644 --- a/backend/chainlit/session.py +++ b/backend/chainlit/session.py @@ -100,6 +100,7 @@ async def persist_file( mime: str, path: Optional[str] = None, content: Optional[Union[bytes, str]] = None, + download_name: Optional[str] = None, ) -> FileReference: if not path and not content: raise ValueError( @@ -140,6 +141,7 @@ async def persist_file( "name": name, "type": mime, "size": file_size, + "download_name": download_name, } return {"id": file_id} From 9522b812a3ff18cfc875c34c4fc4513974ae2421 Mon Sep 17 00:00:00 2001 From: Br1an67 <932039080@qq.com> Date: Mon, 2 Mar 2026 15:55:53 +0800 Subject: [PATCH 2/3] fix: include download_name in element serialization - Add downloadName to ElementDict TypedDict - Include download_name in to_dict() output - Restore download_name in from_dict() via common_params --- backend/chainlit/element.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/chainlit/element.py b/backend/chainlit/element.py index b91b2b5c62..785d609b5f 100644 --- a/backend/chainlit/element.py +++ b/backend/chainlit/element.py @@ -64,6 +64,7 @@ class ElementDict(TypedDict, total=False): playerConfig: Optional[dict] forId: Optional[str] mime: Optional[str] + downloadName: Optional[str] @dataclass @@ -125,6 +126,7 @@ def to_dict(self) -> ElementDict: "language": getattr(self, "language", None), "forId": getattr(self, "for_id", None), "mime": getattr(self, "mime", None), + "downloadName": getattr(self, "download_name", None), } ) return _dict @@ -151,6 +153,7 @@ def from_dict(cls, e_dict: ElementDict): chainlit_key = e_dict.get("chainlitKey") display = e_dict.get("display", "inline") mime_type = e_dict.get("mime", "") + download_name = e_dict.get("downloadName") # Common parameters for all element types common_params = { @@ -164,6 +167,7 @@ def from_dict(cls, e_dict: ElementDict): "chainlit_key": chainlit_key, "display": display, "mime": mime_type, + "download_name": download_name, } if type == "image": From c15c2757d39130d7044ee384bb92a770a0f19ce9 Mon Sep 17 00:00:00 2001 From: Br1an67 <932039080@qq.com> Date: Fri, 6 Mar 2026 04:02:01 +0000 Subject: [PATCH 3/3] fix: add download_name to FileDict TypedDict Add the missing download_name field to FileDict to fix mypy error in session.py where download_name was used but not defined in the TypedDict. Co-Authored-By: Claude --- backend/chainlit/types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/chainlit/types.py b/backend/chainlit/types.py index 2adcc8ad4e..82a39a84d8 100644 --- a/backend/chainlit/types.py +++ b/backend/chainlit/types.py @@ -167,6 +167,7 @@ class FileDict(TypedDict): path: Path size: int type: str + download_name: Optional[str] class MessagePayload(TypedDict):