ComfyUI/app
Simon Pinfold 34744cd29e
Add tags_all / tags_any / tags_none tag filters to the assets list API (#15332)
* Implement tags_all/tags_any/tags_none on the assets list API (BE-6600)

Adds the three canonically-named tag filter params to GET /api/assets and
GET /api/assets/tags/refine:

- tags_all: asset carries every tag (replaces include_tags)
- tags_any: asset carries at least one tag (new)
- tags_none: asset carries no tag (replaces exclude_tags)

Clauses intersect; tags_none always wins. include_tags/exclude_tags remain
as permanent deprecated aliases and behave exactly as before when used on
their own.

Invalid combinations return 400 INVALID_TAG_FILTER, but only when the
request uses at least one new-name parameter (non-empty after
normalisation):

- mixed spellings of one slot (include_tags with tags_all, exclude_tags
  with tags_none)
- the same tag in the effective all-list and none-list (query can never
  match)

Old-names-only requests gain no new error paths: include_tags=a&exclude_tags=a
still returns an empty 200. tags_any/tags_none overlap stays valid (dead
term, not a dead query).

* Address review findings: positional-compat, deprecation metadata, test matrix

- Move any_tags to the end of the four touched signatures: inserting it
  mid-signature silently misbound pre-existing positional callers (e.g.
  a caller passing name_contains positionally would have it consumed as
  any_tags).
- Mark include_tags/exclude_tags Field(deprecated=True) on both list
  schemas so generated schema metadata matches the contract, not just a
  comment (schemas_out.py already uses this form for Asset.name).
- Add tests: legal cross-slot old/new combinations, repeated query-key
  concatenation (pins Core behavior; outside the cross-platform
  contract), tags_any two-page cursor consistency (total/has_more/
  no-overlap), refine-route mixed-spelling rejection + legacy-conflict
  preservation, and schema deprecation metadata.

* Pin tag-value opacity: case-sensitive matching, byte-exact conflict check

The prod tag survey (~/comfy/prod-model-tag-shape.md) found live
case-distinct tag pairs (SEEDVR2/seedvr2) that resolve differently, so
the contract now states tag values are opaque byte-strings. Pin that:
case-distinct tags filter separately, and a case-distinct all/none pair
is not an INVALID_TAG_FILTER conflict.

* Document tags_all/tags_any/tags_none in openapi.yaml, deprecate aliases

Add the three tag-filter parameters to both listAssets and
getAssetTagHistogram parameter blocks and mark include_tags/exclude_tags
deprecated: true, keeping the spec in step with the runtime schemas so
generated clients can discover the new filters while the aliases stay
present for existing consumers.

* Move schemas_in import to module scope in test_list_filter

Review feedback: no import cycle requires the local import.

* Silence per-request DeprecationWarning in the tag-filter remap shim

Reading the deprecated include_tags/exclude_tags fields by attribute
fires pydantic's DeprecationWarning on every list/refine request even
for callers using only the new names. The warning is aimed at API
clients, not the server's own remap; read via model_dump instead.

* Cap tag-filter lists at 100 entries, all spellings

Review finding: unbounded tag lists fan out into one correlated EXISTS
per tag on both page and count statements. Cap each list at 100
normalized entries with 400 INVALID_TAG_FILTER naming the parameter.

Applies to the legacy spellings as well — a deliberate, decided
exception to the old-names-behave-identically rule, since a cap only on
new names would leave the same fan-out reachable through the aliases.

* Strip process narration from comments

Comments carried decision dates, contract cross-references, and review
context. Keep only the constraints the code cannot show, one line each.
2026-08-10 14:05:21 -07:00
..
assets Add tags_all / tags_any / tags_none tag filters to the assets list API (#15332) 2026-08-10 14:05:21 -07:00
database feat(assets): align local API with cloud spec (#12863) 2026-03-16 12:34:04 -07:00
__init__.py Add `FrontendManager` to manage non-default front-end impl (#3897) 2024-07-16 11:26:11 -04:00
app_settings.py Update frontend to v1.25.10 and revert navigation mode override (#9522) 2025-08-23 17:54:01 -04:00
custom_node_manager.py Remove useless annotations imports. (#14105) 2026-05-25 19:23:29 -07:00
frontend_management.py Remove useless annotations imports. (#14105) 2026-05-25 19:23:29 -07:00
logger.py rename comfy/logging.py to comfy/internal_logging.py (#15231) 2026-08-02 16:20:27 -04:00
model_manager.py feat(api): expose registered extension filters on /experiment/models (#14797) 2026-07-09 12:59:30 -07:00
node_replace_manager.py fix: make NodeReplaceManager.register() idempotent (#13596) 2026-05-07 19:21:12 -07:00
subgraph_manager.py fix: specify UTF-8 encoding when reading subgraph files (#12563) 2026-02-21 15:05:00 -08:00
user_manager.py Fix user.css loading broken by #14734 (#15000) 2026-07-29 23:00:16 -07:00