Name and Version
aidial-client 0.13.0
What steps will reproduce the bug?
-
Upload any file via the client:
Reproduction snippet
from aidial_client import AsyncDial
dial = AsyncDial(base_url=..., api_key=...)
metadata = await dial.files.upload("files/<bucket>/folder/file.png", file=...)
print(type(metadata)) # aidial_client.types.metadata.FileMetadata
print(metadata.next_token) # None — always
print(metadata.items) # None — always
-
Inspect the declared return type: FileMetadata in aidial_client/types/metadata.py declares next_token, items and etag alongside content_length/content_type.
What is the expected behavior?
upload() should return a type that models the actual upload response. Per the DIAL API documentation for uploadFile, the 200 response body is exactly the shape of the SDK's FileItem model, not FileMetadata:
Documented 200 response body
{
"name": "file.png",
"parentPath": "folder1/folder2",
"bucket": "3CcedGxCx23EwiVbVmscVktScRyf46KypuBQ65miviST",
"url": "files/.../folder1/folder2/file.png",
"nodeType": "ITEM",
"resourceType": "FILE",
"contentLength": 128630,
"contentType": "image/png"
}
DIAL Core confirms this: the upload endpoint (UploadFileController) responds with the server-side FileMetadata, which extends ResourceItemMetadata — an item shape (plus optional etag, createdAt, updatedAt, author). The nextToken/items fields exist only on the separate ResourceFolderMetadata returned by the metadata/listing endpoint. An upload response can never contain them.
What do you see instead?
The SDK reuses one FileMetadata model for two different server responses — the upload response (item-shaped) and the metadata/listing response (folder-shaped) — by unioning their fields and making everything optional:
Current SDK models (aidial_client/types/metadata.py)
class FileItem(BaseMetadata):
content_length: int | None = None
content_type: str | None = None
updated_at: int | None = None
class FileMetadata(BaseMetadata):
content_length: int | None = None
content_type: str | None = None
next_token: str | None = None # listing-only, never present on upload
items: list[FileItem] | None = None # listing-only, never present on upload
etag: str | None = None
Consequences for client code:
-
upload() advertises next_token/items, which are dead fields (always None) for an upload response.
-
The actual upload response is under-modeled: DIAL Core sends etag, createdAt, updatedAt and author, but FileMetadata types only etag; updated_at is declared on FileItem yet missing from FileMetadata, and createdAt/author survive only as untyped extras (extra="allow").
-
Code that works with files from both upload() and folder listings (metadata.get(...).items → list[FileItem]) has to juggle two types for the same domain object, or convert manually:
FileItem.model_validate(metadata.model_dump(by_alias=True, exclude_none=True))
Additional information
Suggested fix: type upload() (and the single-file branch of the metadata resource) as returning FileItem (ideally extended with the typed etag/created_at/updated_at/author fields the server actually sends), and keep FileMetadata as the folder-listing response only. Since every field involved is optional, this is unlikely to break deserialization of existing payloads, though it is a typing-level API change for callers who annotate the return value as FileMetadata.
Name and Version
aidial-client 0.13.0What steps will reproduce the bug?
Upload any file via the client:
Reproduction snippet
Inspect the declared return type:
FileMetadatainaidial_client/types/metadata.pydeclaresnext_token,itemsandetagalongsidecontent_length/content_type.What is the expected behavior?
upload()should return a type that models the actual upload response. Per the DIAL API documentation foruploadFile, the 200 response body is exactly the shape of the SDK'sFileItemmodel, notFileMetadata:Documented 200 response body
{ "name": "file.png", "parentPath": "folder1/folder2", "bucket": "3CcedGxCx23EwiVbVmscVktScRyf46KypuBQ65miviST", "url": "files/.../folder1/folder2/file.png", "nodeType": "ITEM", "resourceType": "FILE", "contentLength": 128630, "contentType": "image/png" }DIAL Core confirms this: the upload endpoint (
UploadFileController) responds with the server-sideFileMetadata, which extendsResourceItemMetadata— an item shape (plus optionaletag,createdAt,updatedAt,author). ThenextToken/itemsfields exist only on the separateResourceFolderMetadatareturned by the metadata/listing endpoint. An upload response can never contain them.What do you see instead?
The SDK reuses one
FileMetadatamodel for two different server responses — the upload response (item-shaped) and the metadata/listing response (folder-shaped) — by unioning their fields and making everything optional:Current SDK models (aidial_client/types/metadata.py)
Consequences for client code:
upload()advertisesnext_token/items, which are dead fields (alwaysNone) for an upload response.The actual upload response is under-modeled: DIAL Core sends
etag,createdAt,updatedAtandauthor, butFileMetadatatypes onlyetag;updated_atis declared onFileItemyet missing fromFileMetadata, andcreatedAt/authorsurvive only as untyped extras (extra="allow").Code that works with files from both
upload()and folder listings (metadata.get(...).items→list[FileItem]) has to juggle two types for the same domain object, or convert manually:Additional information
Suggested fix: type
upload()(and the single-file branch of the metadata resource) as returningFileItem(ideally extended with the typedetag/created_at/updated_at/authorfields the server actually sends), and keepFileMetadataas the folder-listing response only. Since every field involved is optional, this is unlikely to break deserialization of existing payloads, though it is a typing-level API change for callers who annotate the return value asFileMetadata.