---
name: comfyui_run_foreign_workflow_oneshot
kind: pipeline
lang: py
domain: pipelines
version: "1.0.0"
purity: impure
signature: "def comfyui_run_foreign_workflow_oneshot(source, *, server: str = \"127.0.0.1:8188\", dest: str | None = None, output_kind: str = \"auto\", install_nodes: bool = False, node_repos: dict | None = None, wait_timeout: float = 600.0, civitai_token: str | None = None, hf_token: str | None = None) -> dict"
description: "Ejecuta un workflow ComfyUI AJENO end-to-end en una sola llamada: importa desde cualquier fuente (URL Drive/GitHub/Civitai/HuggingFace, PNG/JSON local, o dict en API format) -> resuelve dependencias (nodos/modelos faltantes) -> valida -> encola -> espera -> descarga los outputs (imagen/video/malla). SEGURIDAD: nunca instala modelos a ciegas (los reporta en 'missing') y solo instala nodos custom si install_nodes=True y el caller pasa su URL de repo confiable en node_repos. Si faltan deps, NO encola. Compone comfyui_download_workflow + resolve_workflow_deps + install_custom_node + validate_workflow + submit_workflow + wait_result + fetch_output_image/video/mesh. Pipeline impuro: HTTP + disco."
tags: [comfyui, pipeline, workflow, foreign, oneshot, ml, video, image, mesh]
uses_functions:
  - comfyui_download_workflow_py_ml
  - comfyui_resolve_workflow_deps_py_ml
  - comfyui_install_custom_node_py_ml
  - comfyui_validate_workflow_py_ml
  - comfyui_submit_workflow_py_ml
  - comfyui_wait_result_py_ml
  - comfyui_fetch_output_image_py_ml
  - comfyui_fetch_output_video_py_ml
  - comfyui_fetch_output_mesh_py_ml
uses_types: []
returns: []
returns_optional: false
error_type: error_go_core
imports: []
params:
  - name: source
    desc: "Workflow de entrada: URL (Google Drive, GitHub, Civitai, HuggingFace o directa a .json/.png/.webp), ruta local (.json/.png), o dict ya en API format ({node_id: {class_type, inputs}})."
  - name: server
    desc: "host:port del servidor ComfyUI sin esquema. keyword-only."
  - name: dest
    desc: "Directorio destino de los outputs descargados. None = cwd. Se crea si no existe. keyword-only."
  - name: output_kind
    desc: "Que outputs descargar: 'auto' (todos: imagenes + primer video + primera malla), 'image', 'video' o 'mesh'. keyword-only."
  - name: install_nodes
    desc: "Si True, instala los nodos custom faltantes cuyo class_type este mapeado a una URL de repo confiable en node_repos. Tras instalar hay que reiniciar ComfyUI para cargarlos, asi que el pipeline NO completa el submit en esa llamada. Por defecto False. keyword-only."
  - name: node_repos
    desc: "Mapa {class_type: repo_url} con las URLs de repo confiables de los nodos custom que se permite instalar. Solo se usa si install_nodes=True. Los modelos faltantes NUNCA se instalan. keyword-only."
  - name: wait_timeout
    desc: "Segundos maximos esperando a que el server termine. keyword-only."
  - name: civitai_token
    desc: "Token de Civitai (Bearer) para fuentes gated. keyword-only."
  - name: hf_token
    desc: "Token de HuggingFace (Bearer) para datasets privados. keyword-only."
output: "dict {ok, prompt_id, outputs, missing, source_type, error}. outputs = lista de rutas locales descargadas. missing = lista de dependencias faltantes (cada una {kind: 'node'|'model', name, action, hint, ...}); no vacia cuando el workflow pide algo que no tenemos, y entonces ok=False y NO se encola. source_type = de donde vino ('github', 'drive', 'local', 'dict', ...). Si falla, ok=False y error explica."
tested: true
tests:
  - "test_classify_outputs_reparte_por_extension"
  - "test_resolve_workflow_dict_api_format"
  - "test_resolve_workflow_dict_mal_formado"
  - "test_resolve_workflow_tipo_invalido"
  - "test_pipeline_output_kind_invalido_no_toca_server"
  - "test_pipeline_dict_mal_formado_no_toca_server"
test_file_path: "python/functions/pipelines/comfyui_run_foreign_workflow_oneshot_test.py"
file_path: "python/functions/pipelines/comfyui_run_foreign_workflow_oneshot.py"
---

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from pipelines.comfyui_run_foreign_workflow_oneshot import comfyui_run_foreign_workflow_oneshot

# Workflow ajeno desde GitHub raw -> se importa, valida y ejecuta en nuestro server.
res = comfyui_run_foreign_workflow_oneshot(
    "https://raw.githubusercontent.com/cubiq/ComfyUI_Workflows/main/ComfyUI_Simple/SDXL_simple.json",
    dest="/tmp/comfy_foreign",
)
# Si faltan deps NO encola:
# res == {"ok": False, "prompt_id": "", "outputs": [], "source_type": "github",
#         "missing": [{"kind": "model", "name": "sd_xl_base_1.0.safetensors", ...}],
#         "error": "dependencias faltantes; no se encola"}

# Con todo presente:
# res == {"ok": True, "prompt_id": "...", "outputs": ["/tmp/comfy_foreign/out_00001_.png"],
#         "missing": [], "source_type": "github", "error": ""}

# Tambien acepta un workflow ya validado de la libreria local o un dict en API format.
res2 = comfyui_run_foreign_workflow_oneshot(
    os.path.expanduser("~/ComfyUI/workflows_library/txt2img_flux_schnell.api.json"),
    dest="/tmp/comfy_foreign", output_kind="image",
)
```

Lánzalo con el python del venv (import de arriba o heredoc). `./fn run` directo no aplica porque la firma usa `*` (keyword-only).

## Cuando usarla

Cuando te pasan un workflow de ComfyUI de internet (un `.json`/`.png` de Drive,
GitHub, Civitai o HuggingFace, o un dict en API format) y quieres ejecutarlo en
nuestro servidor sin montar el flujo a mano. Hace en una llamada lo que antes eran
6-9 pasos: importar a API format, detectar qué nodos/modelos faltan, (opcionalmente)
instalar nodos custom confiables, validar, encolar, esperar y bajar los outputs.
Úsalo como puerta de entrada segura para workflows de terceros: te dice exactamente
qué falta antes de tocar la GPU. Para builders propios del registry (txt2img, img2vid,
img-to-3d) usa sus pipelines dedicados; este es para workflows que NO construimos nosotros.

## Gotchas

- Pipeline impuro: HTTP (import/validate/submit/poll/fetch) + escritura en disco
  (+ subprocess git/pip si instala nodos). Requiere el server ComfyUI vivo.
- **Seguridad — código de terceros**: un workflow ajeno se ejecuta como grafo en
  NUESTRO servidor. Por eso el pipeline SIEMPRE resuelve dependencias antes del
  submit y NUNCA instala nada a ciegas. Los **modelos** faltantes se REPORTAN en
  `missing`, jamás se descargan automáticamente. Los **nodos custom** solo se instalan
  si `install_nodes=True` y el caller pasa la URL del repo en `node_repos` (fuente
  confiable explícita).
- Tras instalar un nodo custom, ComfyUI debe reiniciarse para cargarlo (no en
  caliente: cortaría generaciones en curso). Por eso, si instala nodos, el pipeline
  devuelve `ok=False` con la instrucción de reiniciar y reintentar — no completa el
  submit en esa misma llamada.
- Si tras resolver quedan dependencias faltantes (modelos, o nodos sin cargar), NO
  encola: `ok=False` con `missing` poblado. Revisa `missing` para saber qué bajar/instalar.
- `output_kind="auto"` baja todas las imágenes + el primer vídeo + la primera malla.
  Un `.webp` se clasifica como vídeo/animación (no imagen estática).
- `wait_timeout` por defecto 600s cubre vídeo/3D; súbelo para workflows muy largos.
- `dest` se trata siempre como directorio y se crea si no existe.

## Capability growth log

- v1.0.0 (2026-06-24) — creación. Promueve la secuencia del roadmap 0064/0087
  (import → resolve deps → validate → submit → wait → fetch) a un pipeline one-shot
  para workflows ComfyUI ajenos, con gate de dependencias y sin instalación a ciegas.
