Skip to content

feat(assets) Add asset file_path and display_name response fields#14005

Open
synap5e wants to merge 1 commit into
synap5e/assets-namespaced-tagsfrom
synap5e/feat/assets_add_file_path-BE-932
Open

feat(assets) Add asset file_path and display_name response fields#14005
synap5e wants to merge 1 commit into
synap5e/assets-namespaced-tagsfrom
synap5e/feat/assets_add_file_path-BE-932

Conversation

@synap5e

@synap5e synap5e commented May 20, 2026

Copy link
Copy Markdown

Add optional file_path and display_name to asset responses. Fields are constructed using known asset roots (input, output, temp, registered models folders).

Note External extra_model_paths.yaml are a known gap - models discovered here do not get these fields. Followup is planned.

What this does

Adds two optional fields to the asset API's Asset and AssetCreated response schemas:

  • file_path: A runtime-computed storage namespace locator for filesystem-backed asset references. It is not an absolute filesystem path, not a unique identity, and not a model-loader path.
  • display_name: A human-facing label derived from file_path, usually the path below the top-level storage namespace.

These fields are computed late from the stored absolute AssetReference.file_path when building API responses. They are not persisted separately and are not derived from tags.

This PR is now stacked on / aligned with #14511's namespaced asset tag semantics. Tags answer “what can this asset load as or be filtered by?”; file_path answers “where does this asset reference live in Comfy's storage namespace?”. Recommend reviewing this stack as a pair.

Motivation

In asset mode, the asset response's name field is overloaded. Depending on the asset's origin, clients may treat the same field as:

  • a display label,
  • a path-ish locator,
  • a filename,
  • or a fallback identity when no better field exists.

The frontend currently has to infer intent from value shape, tags, or backend-specific heuristics. This PR separates those roles:

  • id: API identity.
  • name: existing reference label, deprecated for path/display semantics.
  • file_path: storage locator for file-backed references.
  • display_name: UI label derived from the storage locator.
  • tags: classification/filter labels, including backend-generated model/loadability facts such as models and model_type:<folder_name>.

Semantics

file_path is a storage namespace locator, not a model-loader namespace.

Built-in storage roots:

  • files under input: input/<relative_path>
  • files under output: output/<relative_path>
  • files under temp: temp/<relative_path>
  • files under the configured Comfy models directory: models/<relative_path_under_models_dir>

Model loadability/classification remains represented by tags from #14511:

  • models
  • model_type:<folder_name>

This avoids conflating physical storage layout with model type. For example, a file under the legacy physical folder models/unet remains models/unet/... in file_path, while tags can say it is loadable as model_type:diffusion_models.

The response fields are omitted for hash-only/from-hash references or paths outside known storage roots.

Examples

Input file

Physical path:

<input>/uploads/cat.png

Response:

file_path:    input/uploads/cat.png
display_name: uploads/cat.png

Output image

Physical path:

<output>/ComfyUI_00001_.png

Response:

file_path:    output/ComfyUI_00001_.png
display_name: ComfyUI_00001_.png

Stock checkpoint file

Physical path:

<models_dir>/checkpoints/flux/model.safetensors

Response:

file_path:    models/checkpoints/flux/model.safetensors
display_name: checkpoints/flux/model.safetensors

Relevant tags:

models
model_type:checkpoints

Legacy physical diffusion-model folder

Physical path:

<models_dir>/unet/wan.safetensors

Response:

file_path:    models/unet/wan.safetensors
display_name: unet/wan.safetensors

Relevant tags:

models
model_type:diffusion_models

Output-backed registered model folder

If <output>/checkpoints is registered as a checkpoints model folder, a file at:

<output>/checkpoints/saved.safetensors

still has a storage locator under output:

file_path:    output/checkpoints/saved.safetensors
display_name: checkpoints/saved.safetensors

Relevant tags expose both facts:

output
models
model_type:checkpoints

Ordinary output checkpoint-like file

If <output>/checkpoints is not registered as a model folder:

file_path:    output/checkpoints/saved.safetensors
display_name: checkpoints/saved.safetensors

Relevant tags:

output

Hash-only/from-hash reference

A reference created from an existing hash can have user labels that look like system tags:

{
  "tags": ["models", "model_type:checkpoints"]
}

but because it has no trusted AssetReference.file_path, the response omits file_path and display_name.

Extra model paths

This PR deliberately does not rewrite arbitrary external registered model folders to models/<registered_model_folder>/....

Comfy currently flattens extra_model_paths.yaml entries into folder_paths.folder_names_and_paths, losing the YAML source key / provenance needed to build an unambiguous public storage locator. Until that provenance is preserved, external registered roots still receive model classification tags but omit file_path / display_name.

A future follow-up can add an extra_models/<source_alias>/<relative_path> namespace once extra-model-path provenance is recorded.

Changes

  • Add file_path and display_name to Asset, inherited by AssetCreated.
  • Populate both fields in the shared asset response builder used by list, detail, upload/create, create-from-hash, and update responses.
  • Add storage-locator helpers:
    • compute_asset_response_paths
    • compute_file_path
    • compute_display_name
  • Keep response fields independent from mutable tags.
  • Keep unknown or non-file-backed references omitted via existing exclude_none=True response behavior.
  • Preserve feat(assets): add namespaced model_type tags and align tag semantics #14511 upload/tag semantics:
    • model uploads use models + model_type:<folder_name>
    • nested placement uses explicit subfolder
    • extra tags are labels, not path components
  • Leave openapi.yaml hand edits out; core's API spec is downstream of the cloud spec sync.
  • Add focused tests for path computation, storage-vs-classification behavior, upload/list/detail response fields, hash-only/from-hash behavior, duplicate-byte reference-only behavior, and root overlap/path normalization cases.

Verification

uv run --with pytest pytest tests-unit/assets_test/services/test_path_utils.py -q
# 39 passed
uv run --with pytest --with pytest-asyncio pytest tests-unit/assets_test/test_uploads.py -q
# 34 passed
uv run --with-requirements requirements.txt --with-requirements tests-unit/requirements.txt pytest -q tests-unit/assets_test
# 442 passed, 10 skipped
git diff --check

@synap5e synap5e changed the title feat(assets) Add asset file path response fields feat(assets) Add asset file_path and display_name response fields May 20, 2026
@synap5e synap5e marked this pull request as ready for review May 21, 2026 04:12
@synap5e synap5e assigned synap5e, guill and Kosinkadink and unassigned synap5e May 21, 2026
@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds AssetRoot typing and new path utilities (compute_asset_response_paths, compute_file_path, compute_display_name, get_asset_root_folder_name_and_filepath). Routes now import and use compute_asset_response_paths to populate Asset responses' file_path and display_name (or set them to None). Upload validation for "models" tags now uses is_comfy_model_folder_name. Asset schema and OpenAPI mark name deprecated and add nullable file_path and display_name. Unit and upload tests were added/updated to cover the new behavior.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely describes the main addition of file_path and display_name response fields to the asset API.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description comprehensively explains the changes, including objectives, semantics, examples, and known limitations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@mattmillerai

Copy link
Copy Markdown
Contributor

Heads up on the x-runtime: [cloud, local] tags here — the established convention in this file is that absence of x-runtime means both runtimes populate the field (i.e. it's the default). All 177 existing x-runtime usages in this file are [cloud] only — they mark cloud-only divergence from the default-both behavior. [cloud, local] is redundant with no tag and introduces a second pattern.

Two cleaner options:

  1. Drop the x-runtime: [cloud, local] tags entirely — absence carries the same meaning, and the existing 177 [cloud] usages stay self-consistent. This is what the convention currently calls for.
  2. Keep them and file a separate convention-change discussion if there's a reason explicit-over-implicit is preferable here — but that's a wider change that should be applied uniformly, not selectively.

(1) is the smaller change and avoids introducing dual conventions in the same file.

mattmiller@comfy.org

Comment thread app/assets/services/path_utils.py Outdated
Comment on lines +122 to +123
`bucket` is only set for model assets. The returned relative path always
uses `/` separators and is empty when the path is exactly the matched root.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this function relies on a flawed assumption that all models will be in the models directory. As an example, the built-in SaveCheckpoint, SaveLora, etc. models actually save to the outputs directory but are still loadable as models.
If possible, I would really like to avoid special-casing models as that's usually going to fail for edge cases. Could you explain a bit more about why we actually need the bucket as a first-class concept?

@synap5e synap5e Jun 20, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New direction for this PR resolves this IMO.
file_path now represents the {asset's membership to} and {file location relative to} the asset's "storage root" i.e. input output temp models.

The prior special casing was a reaction to the edge cases, primarily

  1. overlapping model_folders via custom nodes e.g. a custom node registers a unet_gguf overlapping with checkpoints
  2. extra_model_paths.yml

I have intentionally deferred extra_model_paths.yml models from this PR, but I think this is also solvable.
#14511 solves the categorisation and (non-extra-models) overlap issues rather than sneaking that into file_path

Comment thread app/assets/services/path_utils.py Outdated
def get_asset_category_and_relative_path(
file_path: str,
) -> tuple[Literal["input", "output", "temp", "models"], str]:
) -> tuple[RootCategory, str]:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this isn't actually new to this PR, but I'm a little concerned about the assumption that models will be exactly one of these. We should make sure this works for cases like the built-in SaveCheckpoint or SaveLora nodes where the model is located under the outputs directory, but should also be treated as a model.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under new PR direction, SaveCheckpoint to output/checkpoints should now remain output/checkpoints/foo.safetensors - if that folder is a registered model root then it should gain the appropriate tags ouput models model_type:... per #14511

Making SaveCheckpoint ouputs automatically register as models regardless of location could be a followup PR, but is currently blocked by internal model loading behaviour. Once asset system node API lands, this should unblock.

@synap5e synap5e assigned synap5e and unassigned guill and Kosinkadink May 27, 2026
@synap5e synap5e force-pushed the synap5e/feat/assets_add_file_path-BE-932 branch 4 times, most recently from 73ba8c6 to c533a88 Compare June 5, 2026 09:29
@mattmillerai mattmillerai added the Core Core team dependency label Jun 9, 2026
@mattmillerai

mattmillerai commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

@guill @synap5e — picked this up to get it unblocked. Where it stands:

On the model-path concern (@guill) — let me be precise here, since my first pass overstated it:

The redesign does remove the "models live in the models/ directory" assumption. get_asset_root_folder_name_and_filepath resolves against ComfyUI's registered model-folder bases (folder_names_and_paths), checked before input/output/temp — so a model in any registered base (an external drive, an extra_model_paths.yaml entry, or a registered output path) maps to models/<folder>/… regardless of where it physically sits. models is a logical namespace derived from the registry, not a physical directory.

What it does not do is auto-reclassify an unregistered output/ file as a model. A built-in SaveCheckpoint / SaveLoRA writes to output/checkpoints/…, which isn't a registered checkpoints base by default, so it classifies as output/checkpoints/…. That's consistent with ComfyUI's own loader — get_filename_list("checkpoints") won't surface that file as a checkpoint either until its location is registered. So if we want output-saved checkpoints treated as models, that's a deliberate decision to register the output path as a model base, not a path-utils change.

Tests: test_output_model_folder_uses_model_namespace_file_path covers the registered-base-under-output case, and test_external_model_folder_uses_registered_folder_name_namespace covers an external registered base. Happy to keep iterating on the naming (the old "bucket" term is now root).

Conflicts + fixes (@synap5e):

  • Merged latest master (branch was ~149 behind); resolved conflicts in routes.py, schemas_out.py, and test_uploads.py as unions with master's hash work — both sets of fields/tests kept.
  • Fixed a Windows-only path-separator bug in path_utils: get_asset_category_and_relative_path returned os.path.relpath output directly (LLM\model.safetensors on Windows), now normalized to / like its sibling helper. That was the only failing check.
  • Dropped the openapi.yaml edits entirely. Core's spec is downstream of the cloud spec via the sync, and file_path will arrive through that (it isn't in cloud main yet), so hand-editing core's spec here was premature — display_name already came in that way. The Pydantic response models still emit both fields, so no behavior change.

CI is green apart from the now-fixed Windows job. @synap5e — flag if you'd rather I revert any of the above; otherwise this just needs a maintainer approval.

@synap5e

synap5e commented Jun 19, 2026

Copy link
Copy Markdown
Author

Thanks Matt — I picked this back up and changed direction after lining it up with #14511.

The branch is now rebuilt on top of the namespaced tag/upload semantics from #14511. I also kept the important cleanup from your earlier pass: no hand-edited openapi.yaml, and public path-like response values are normalized to / separators.

The bigger semantic change is that file_path is no longer trying to represent the registered model-folder namespace. It is now a storage locator:

  • <models_dir>/unet/foo.safetensorsmodels/unet/foo.safetensors
  • <output>/checkpoints/foo.safetensorsoutput/checkpoints/foo.safetensors
  • model loadability/type is expressed separately through tags like models and model_type:checkpoints

That separation is what resolves Guill's concern about output-backed model folders. A file can be physically located under output/checkpoints/... while also being classified as a checkpoint via tags. We no longer have to force file_path to choose between “this is in output storage” and “this is loadable as a checkpoint.”

For arbitrary external registered model roots, this PR currently omits file_path / display_name instead of inventing a possibly-wrong namespace. We can add something like extra_models/<source_alias>/... later, but only once extra_model_paths.yaml provenance is preserved through discovery; today the YAML key that would make that public path meaningful is flattened away.

So the revised split is:

  • file_path: where this filesystem-backed reference lives in Comfy's storage namespace, when known
  • display_name: UI label derived from that locator
  • tags: filtering/loadability/classification, including models and model_type:<folder_name>
  • name: existing reference label, deprecated for path/display semantics

@synap5e synap5e force-pushed the synap5e/feat/assets_add_file_path-BE-932 branch from aa376ac to 61ae5ff Compare June 19, 2026 09:55
@synap5e synap5e changed the base branch from master to synap5e/assets-namespaced-tags June 19, 2026 09:58
@synap5e synap5e force-pushed the synap5e/feat/assets_add_file_path-BE-932 branch from ed2016a to 733b4eb Compare June 19, 2026 10:50
@synap5e synap5e force-pushed the synap5e/assets-namespaced-tags branch from 4a757fc to 4340337 Compare June 20, 2026 01:28
@synap5e synap5e force-pushed the synap5e/feat/assets_add_file_path-BE-932 branch from 733b4eb to 990242a Compare June 20, 2026 01:32
@synap5e synap5e assigned guill and mattmillerai and unassigned synap5e Jun 20, 2026
@synap5e synap5e requested a review from guill June 20, 2026 01:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-coded Core Core team dependency

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants