Skip to content

[Partner Nodes] feat(Tripo3d): add new "Import 3D" node#14466

Merged
bigcat88 merged 1 commit into
masterfrom
feat/api-nodes/tripo-import-model
Jun 14, 2026
Merged

[Partner Nodes] feat(Tripo3d): add new "Import 3D" node#14466
bigcat88 merged 1 commit into
masterfrom
feat/api-nodes/tripo-import-model

Conversation

@bigcat88

@bigcat88 bigcat88 commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

PR adds new node for these endpoints: https://platform.tripo3d.ai/docs/upload-sts and https://platform.tripo3d.ai/docs/import-model
New node is free, and allows to process existing 3D models with Tripo API (rig, re-target rigged, ..)

API Node PR Checklist

Scope

  • Is API Node Change

Pricing & Billing

  • Need pricing update
  • No pricing update

If Need pricing update:

  • Metronome rate cards updated
  • Auto‑billing tests updated and passing

QA

  • QA done
  • QA not required

Comms

  • Informed Kosinkadink

Signed-off-by: bigcat88 <bigcat88@icloud.com>
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

comfy_api_nodes/nodes_tripo.py receives two additions. TripoTextureNode gains an optional texture_prompt string input in its schema and execute signature; the stripped prompt is included in TripoTextureModelRequest only when non-empty. A new TripoImportModelNode class is introduced that accepts a 3D model file, rejects GLTF format explicitly, enforces a 150 MB size limit, uploads the file via upload_3d_model_to_comfyapi, posts to Tripo's import endpoint using TripoImportModelRequest, polls the resulting task until it reaches a terminal state, and returns a MODEL_TASK_ID. The node is registered in TripoExtension.get_node_list().

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 title accurately describes the main change: adding a new 'Import 3D' node for Tripo3D integration, which aligns with the raw summary showing a new TripoImportModelNode.
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 PR description clearly relates to the changeset, detailing the addition of a new TripoImportModelNode for processing 3D models with Tripo API endpoints.

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


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
comfy_api_nodes/nodes_tripo.py (1)

598-598: 💤 Low value

Avoid calling .strip() twice.

The stripped value is computed twice. Consider caching it for efficiency.

♻️ Proposed refactor
+        stripped_prompt = texture_prompt.strip()
         response = await sync_op(
             cls,
             endpoint=ApiEndpoint(path="/proxy/tripo/v2/openapi/task", method="POST"),
             response_model=TripoTaskResponse,
             data=TripoTextureModelRequest(
                 original_model_task_id=model_task_id,
                 texture=texture,
                 pbr=pbr,
                 texture_seed=texture_seed,
                 texture_quality=texture_quality,
                 texture_alignment=texture_alignment,
-                texture_prompt=TripoTexturePrompt(text=texture_prompt.strip()) if texture_prompt.strip() else None,
+                texture_prompt=TripoTexturePrompt(text=stripped_prompt) if stripped_prompt else None,
             ),
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@comfy_api_nodes/nodes_tripo.py` at line 598, The texture_prompt.strip()
method is being called twice on the same line - once in the conditional check
and once when creating the TripoTexturePrompt object. Cache the stripped value
in a temporary variable (such as stripped_texture_prompt) before the conditional
statement, then use that cached variable both in the condition and as the
argument to TripoTexturePrompt to avoid redundant string operations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@comfy_api_nodes/nodes_tripo.py`:
- Around line 995-1009: The poll_op call at line 995 is missing the
completed_statuses parameter, which causes polling to continue until
max_poll_attempts exhausts when tasks enter terminal failure states like
UNKNOWN, BANNED, or EXPIRED instead of failing immediately. Add the
completed_statuses=[TripoTaskStatus.SUCCESS] parameter to the poll_op function
call to explicitly define terminal success states and match the polling pattern
used elsewhere, ensuring deterministic behavior for all terminal states.

---

Nitpick comments:
In `@comfy_api_nodes/nodes_tripo.py`:
- Line 598: The texture_prompt.strip() method is being called twice on the same
line - once in the conditional check and once when creating the
TripoTexturePrompt object. Cache the stripped value in a temporary variable
(such as stripped_texture_prompt) before the conditional statement, then use
that cached variable both in the condition and as the argument to
TripoTexturePrompt to avoid redundant string operations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3609300c-8507-48e6-bc12-565f463b36e9

📥 Commits

Reviewing files that changed from the base of the PR and between a1d95f3 and b5e7f6a.

⛔ Files ignored due to path filters (1)
  • comfy_api_nodes/apis/tripo.py is excluded by !comfy_api_nodes/apis/**
📒 Files selected for processing (1)
  • comfy_api_nodes/nodes_tripo.py

Comment thread comfy_api_nodes/nodes_tripo.py
@bigcat88 bigcat88 merged commit 5897d0c into master Jun 14, 2026
17 checks passed
@bigcat88 bigcat88 deleted the feat/api-nodes/tripo-import-model branch June 15, 2026 08:01
POWERFULMOVES added a commit to POWERFULMOVES/PMOVES-Creator that referenced this pull request Jun 17, 2026
* feat(assets): add job_ids filter to GET /api/assets (Comfy-Org#13998)

* feat(assets): add job_ids filter to GET /api/assets

Mirrors the existing cloud `job_ids` query param on the local Python server:
clients can pass a comma-separated list (or repeated query params) of UUIDs
to filter assets by their associated job.

The `AssetReference.job_id` column already exists, so no migration is
needed — this just plumbs the filter through schema → service → query.

Marks the parameter as available in both runtimes by dropping the
`[cloud-only]` description prefix and the `x-runtime: [cloud]` tag from
the OpenAPI spec, per the OSS field-drift convention (absent runtime tag
= populated by both local and cloud).

* fix(assets): tighten job_ids — array schema, max_length, narrow except

From cursor-reviews on the parent commit:

- OpenAPI: declare job_ids as `type: array, items: string format: uuid`
  with `style: form, explode: true` so it matches the documented
  contract (and matches sibling include_tags/exclude_tags shape).
  Description now states both accepted shapes explicitly.
- Schema: cap `job_ids` at 500 entries (max_length on the Pydantic
  field) so a client can't splice an unbounded list into the IN clauses.
- Schema: drop `AttributeError` from the except — `raw` only contains
  `str` items by construction, so `uuid.UUID(<str>)` raises `ValueError`
  exclusively; the second clause was dead code.

* fix(assets): tighten job_ids validator + add schema-level tests

Aligns with the parallel hardening from draft PR Comfy-Org#13848 (now closed as
a duplicate). The validator now:

- Raises ValueError on non-string list items (was: silently dropped).
- Raises ValueError on non-string / non-list top-level values like dict
  or int (was: silently passed through to Pydantic's downstream coercion).

Adds tests-unit/assets_test/queries/test_list_assets_query.py covering
the validator end-to-end: CSV canonicalization, dedup order, default
empty, invalid UUID, non-string list item, non-string non-list value,
and the max_length=500 boundary.

* feat(prompt): enforce canonical UUID prompt_id at job creation

POST /prompt previously accepted any client-supplied prompt_id verbatim,
str()-coercing even non-strings, and minting the literal job id "None"
for an explicit JSON null. The new GET /api/assets job_ids filter matches
stored job ids as canonical UUIDs exactly, so a non-UUID id minted a job
whose assets could never be filtered.

- validate_job_id (comfy_execution/jobs.py): requires a string in the
  canonical lowercase hyphenated UUID form; raises ValueError otherwise,
  including parseable-but-non-canonical spellings (uppercase, braced, URN,
  bare hex), which would otherwise be silently rewritten and then miss
  every exact-match lookup downstream (history keys, websocket
  correlation, /interrupt, the assets job_ids filter).
- POST /prompt: absent or null prompt_id means the server mints uuid4;
  invalid means 400 invalid_prompt_id on the standard error envelope.
- openapi.yaml: document the request-side prompt_id (format uuid,
  nullable) on PromptRequest.
- tests: unit matrix for validate_job_id; integration tests against the
  booted server covering rejection, acceptance, and null handling.

---------

Co-authored-by: guill <jacob.e.segal@gmail.com>

* feat(assets): include asset id in executed WebSocket message (Comfy-Org#13862)

* feat(assets): enrich executed WS message with asset metadata

When --enable-assets is set, each file-type output entry in the
`executed` WebSocket message now includes id, name, asset_hash, size,
and mime_type — matching the shape already returned by /upload/image.

The enrichment lives in comfy_execution/asset_enrichment.py (no torch
dependency) and is called from both send sites in execution.py: freshly
executed nodes register the file inline via register_file_in_place;
cached node re-sends look up the existing AssetReference by file path
to avoid re-hashing. Errors are caught per-entry so a failure never
blocks the WS message from sending.

* fix(assets): inject only id in executed WS message per Asset Identity RFC

Per the Asset Identity RFC, the executed WebSocket payload should carry
id alone — hash is already encoded in the filename, and name/preview_url/
size belong behind GET /api/assets/{id} rather than being pushed eagerly.

Simplifies the DB lookup path: we only need ref.id, so the asset.hash
null-check is no longer required as a fallback trigger.

* fix(assets): reject path traversal when resolving output abs_path

Subfolder/filename were joined and absolutized without containment check,
so '..' segments or an absolute filename could escape the type's base
directory and register an unrelated on-disk file as an asset.

Add commonpath-based containment check; skip enrichment (warn, leave
entry unchanged) when the resolved path escapes base. Catches ValueError
from cross-drive paths on Windows.

* docs(assets): drop Asset Identity RFC reference from docstring

* docs(assets): trim docstring to what enrichment does, not what it doesn't

* test(assets): use real platform paths so containment check works on Windows

The previous test setup patched os.path.abspath to identity and used a
POSIX-style '/output' base, which collided with Windows path separators
in os.path.commonpath. Drop the abspath/join patches and use a real
tempdir-rooted base so the containment check runs against actual
platform paths.

* refactor(assets): enrich at output-processing time, not in the WS send path

Per review: enrichment lived inside the client_id-guarded send sites, so a
headless run (no websocket client) never registered assets at all, and
ui_outputs/history stored the un-enriched entries.

Now output_ui is enriched once, right after the node produces it and before
it is stored in ui_outputs — so registration happens regardless of connected
clients, and the asset id flows into history and the execution cache for
free. _send_cached_ui re-sends the stored (already-enriched) dict verbatim,
which lets the DB-lookup-by-path fallback be deleted: every enrichment is
now a fresh output, and register_file_in_place re-hashes on upsert so an
overwritten path can never carry a stale id.

* revert(assets): drop job_ids filter from GET /api/assets (Comfy-Org#14408)

The job_ids query filter added in Comfy-Org#13998 has no live consumer: the
frontend Generated tab kept sourcing from GET /jobs, and the cloud side
removed its equivalent filter from the shared asset spec. Carrying it on
the local server only re-introduces Core<->Cloud drift on the shared
contract, so remove it to match.

Removed: the job_ids field + validator on ListAssetsQuery, the IN(...)
clauses in list_references_page, the service/route passthrough, and the
filter-only tests.

Kept: the canonical-UUID prompt_id enforcement at job creation (also
landed in Comfy-Org#13998). It stands on its own -- job ids are matched verbatim
by history keys, websocket correlation, and /interrupt -- and cloud
inherits it by running core for execution, so no divergence is created.

* chore(openapi): sync shared API contract from cloud@e3c52ad (Comfy-Org#14406)

* I don't think this actually works anymore. (Comfy-Org#14403)

* ops: tolerate already force casted dynamic weight (Comfy-Org#14410)

Some custom nodes .to weights completely out of load context which
can wreak havoc if its for a model that is not active. Detect this
condition and just let it fall-through to the non-dynamic loader
straight up.

* Improve context window resizing for SCAIL2 (CORE-286) (Comfy-Org#14394)

* Fix SCAIL-2 reference mask background convention (Comfy-Org#14415)

* [Partner Nodes] fix(GPT Image): handle mismatched image sizes returned when size="auto" (Comfy-Org#14414)

Signed-off-by: bigcat88 <bigcat88@icloud.com>

* [Partner Nodes] fix(KlingTextToVideoNode): validation error for "kling-v2-master" model (Comfy-Org#14418)

Signed-off-by: bigcat88 <bigcat88@icloud.com>

* Make --enable-manager-legacy-ui imply --enable-manager (Comfy-Org#14421)

* Don't crash when using flux kv cache with split batches. (Comfy-Org#14422)

* Add Comfy-Usage-Source pass-through for API node requests (Comfy-Org#14404)

* [Partner Nodes] feat: enable Bria Replace Background node (Comfy-Org#14397)

* Fix potential dtype issue with ideogram 4. (Comfy-Org#14436)

* add --high-ram option (Comfy-Org#14437)

Add this option for users who know they have so much ram they want
to pin everything or have a pagefile that outruns their disk speed.

The removes the RAM pressure caps completely and pins behind the
primary model load forcing all models to be permanently comitted
to RAM.

* [Partner Nodes] feat: add Runway Aleph2 node (Comfy-Org#14306)

Signed-off-by: bigcat88 <bigcat88@icloud.com>

* Use comfy kitchen apply rope in omnigen2 model. (Comfy-Org#14442)

* Add 10-bit video support (Comfy-Org#14452)

Create Video gets a bit_depth option (8-bit/10-bit); the selected depth is carried by the video and applied when it gets encoded. Save Video and Video Slice now keep the source bit depth instead of always quantizing to 8-bit, so 10-bit videos stay 10-bit. 10-bit uses h264 with the yuv420p10le pixel format,so there's no new codec or container.

Signed-off-by: bigcat88 <bigcat88@icloud.com>

* Expose deploy_environment in /system_stats (Comfy-Org#14402)

* Remove the comfy python path append.

* Revert last commit. Last time I use this stupid GitHub app.

* Fix nondeterministic video decode at unaligned widths (CORE-299) (Comfy-Org#14438)

* [Partner Nodes] feat(Tripo3d): add new "Import 3D" node (Comfy-Org#14466)

Signed-off-by: bigcat88 <bigcat88@icloud.com>

* bump manager version to 4.2.2 (Comfy-Org#14471)

* This is already auto enabled by default. (Comfy-Org#14476)

* chore: update embedded docs to v0.5.4 (Comfy-Org#14478)

* fix(ruff): exclude vendored ComfyUI tree from lint (scope to PMOVES code)

* fix(ruff): resolve PMOVES-owned lint in pmoves_health

Scoped ruff (after excluding vendored ComfyUI) surfaced PMOVES-owned violations:
remove unused imports (F401), fix undefined FastAPI annotation (F821) by importing
it at module scope, and # noqa intentional demo/CLI prints (T201).

* fix(ruff): resolve PMOVES-owned lint in pmoves_announcer

Scoped ruff (after excluding vendored ComfyUI) surfaced PMOVES-owned violations:
remove unused imports (F401), fix undefined FastAPI annotation (F821) by importing
it at module scope, and # noqa intentional demo/CLI prints (T201).

* fix(ruff): resolve PMOVES-owned lint in pmoves_registry

Scoped ruff (after excluding vendored ComfyUI) surfaced PMOVES-owned violations:
remove unused imports (F401), fix undefined FastAPI annotation (F821) by importing
it at module scope, and # noqa intentional demo/CLI prints (T201).

---------

Signed-off-by: bigcat88 <bigcat88@icloud.com>
Co-authored-by: Matt Miller <mattmiller@comfy.org>
Co-authored-by: guill <jacob.e.segal@gmail.com>
Co-authored-by: Comfy Org PR Bot <snomiao+comfy-pr@gmail.com>
Co-authored-by: comfyanonymous <121283862+comfyanonymous@users.noreply.github.com>
Co-authored-by: rattus <46076784+rattus128@users.noreply.github.com>
Co-authored-by: Barish Ozbay <17261091+drozbay@users.noreply.github.com>
Co-authored-by: Jukka Seppänen <40791699+kijai@users.noreply.github.com>
Co-authored-by: Alexander Piskun <13381981+bigcat88@users.noreply.github.com>
Co-authored-by: Jedrzej Kosinski <kosinkadink1@gmail.com>
Co-authored-by: Robin Huang <robin.j.huang@gmail.com>
Co-authored-by: John Pollock <pollockjj@users.noreply.github.com>
Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
Co-authored-by: Daxiong (Lin) <contact@comfyui-wiki.com>
Co-authored-by: pmoves-fork-sync[bot] <pmoves-fork-sync[bot]@users.noreply.github.com>
Co-authored-by: POWERFULMOVES <142271328+POWERFULMOVES@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants