ComfyUI/app/assets/api/schemas_out.py
Matt Miller 58df1a3564 feat: implement remaining listAssets contract fields (display_name, hash filter, include_public)
Bring GET /api/assets into param-for-param parity with the projected
openapi.yaml listAssets contract for the three remaining fields:

- Add display_name to the Asset response schema (nullable, mirrors name)
  and populate it from ref.name in _build_asset_response, covering list,
  get, create, update, and upload responses uniformly.
- Add the hash query param to ListAssetsQuery (named hash per the spec,
  not asset_hash) with before-validation strip/lower normalization, and
  thread it through list_assets_page -> list_references_page, filtering
  both the page and count statements on Asset.hash for consistency.
- Accept include_public (bool, default true) for contract parity; it is
  inert in core (no public asset pool) and intentionally not passed to
  the service layer.

Cursor pagination and size optionality are untouched.

Add integration tests covering display_name mirroring, exact hash match,
unknown-hash empty page, and include_public acceptance.
2026-06-30 02:22:06 -07:00

77 lines
2.2 KiB
Python

from datetime import datetime
from typing import Any
from pydantic import BaseModel, ConfigDict, Field, field_serializer
class Asset(BaseModel):
"""API view of an asset. Maps to DB ``AssetReference`` joined with its ``Asset`` blob;
``id`` here is the AssetReference id, not the content-addressed Asset id."""
id: str
name: str
# Mirrors `name` for backwards compatibility.
display_name: str | None = None
hash: str | None = None
asset_hash: str | None = None
size: int | None = None
mime_type: str | None = None
tags: list[str] = Field(default_factory=list)
preview_url: str | None = None
preview_id: str | None = None # references an asset_reference id, not an asset id
user_metadata: dict[str, Any] = Field(default_factory=dict)
is_immutable: bool = False
metadata: dict[str, Any] | None = None
job_id: str | None = None
prompt_id: str | None = None # deprecated: use job_id
created_at: datetime
updated_at: datetime
last_access_time: datetime | None = None
model_config = ConfigDict(from_attributes=True)
@field_serializer("created_at", "updated_at", "last_access_time")
def _serialize_datetime(self, v: datetime | None, _info):
return v.isoformat() if v else None
class AssetCreated(Asset):
created_new: bool
class AssetsList(BaseModel):
assets: list[Asset]
total: int
has_more: bool
# Opaque cursor for the next page. Omitted when there are no more results.
next_cursor: str | None = None
class TagUsage(BaseModel):
name: str
count: int
class TagsList(BaseModel):
tags: list[TagUsage] = Field(default_factory=list)
total: int
has_more: bool
class TagsAdd(BaseModel):
model_config = ConfigDict(str_strip_whitespace=True)
added: list[str] = Field(default_factory=list)
already_present: list[str] = Field(default_factory=list)
total_tags: list[str] = Field(default_factory=list)
class TagsRemove(BaseModel):
model_config = ConfigDict(str_strip_whitespace=True)
removed: list[str] = Field(default_factory=list)
not_present: list[str] = Field(default_factory=list)
total_tags: list[str] = Field(default_factory=list)
class TagHistogram(BaseModel):
tag_counts: dict[str, int]