Compare commits

..

3 Commits

Author SHA1 Message Date
egutierrez f8793f96ac fix(comfyui): firmas sin keyword-only para que fn run las despache
El generador de runner de fn run (cmd/fn/pyrunner.go::generatePyRunner)
parsea la signature de la funcion desde el frontmatter del .md y emite
`<param> = _args[i]` por cada parametro posicional. Cuando la firma es
keyword-only (`def f(*, ...)`), el `*` se trata como un nombre de parametro
y genera la linea invalida `* = _args[0]`, que rompe el runner con
`SyntaxError: invalid syntax` antes de ejecutar la funcion.

Se quita el separador keyword-only (`*,`) de la firma — tanto en la `def`
del .py como en el campo `signature:` del .md (la fuente que lee el
indexer y el runner) — convirtiendo los parametros keyword-only en
parametros normales con su mismo default. No cambia nombres, defaults ni
comportamiento: las llamadas con keyword siguen siendo validas.

Afecta a 5 funciones detectadas en el report 0208 §3.3, todas con
SyntaxError reproducido via `fn run <id>`:
- comfyui_fetch_civitai_image_meta
- comfyui_load_skill
- comfyui_save_skill
- comfyui_import_workflow_png
- comfyui_list_skills

Se completa ademas el fix de comfyui_interrupt_queue: el commit 643ebfb8
quito el `*,` del .py pero dejo el `*,` en el campo `signature:` del .md,
que es justo lo que lee el runner — por eso `fn run comfyui_interrupt_queue`
seguia fallando. Aqui se corrige el .md.

Verificado: tras el cambio las 6 despachan sin SyntaxError (las 4 con
primer arg requerido devuelven el `missing required arg` esperado del
runner; list_skills e interrupt_queue ejecutan `ok:true`). Tests
existentes verdes (comfyui_fetch_civitai_image_meta_test.py +
tests/test_comfyui_interrupt_queue.py: 8 passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:23:59 +02:00
egutierrez 643ebfb849 fix(comfyui): comfyui_interrupt_queue firma sin keyword-only para que fn run la despache 2026-06-28 04:55:39 +02:00
egutierrez 537516e32e merge(comfyui): comfyui_interrupt_queue — control de cola (interrupt + clear_pending) 2026-06-28 04:54:46 +02:00
12 changed files with 18 additions and 20 deletions
@@ -5,7 +5,7 @@ lang: py
domain: ml
version: "1.0.0"
purity: impure
signature: "def comfyui_fetch_civitai_image_meta(image_ref, *, token: str | None = None, timeout: float = 15.0) -> dict"
signature: "def comfyui_fetch_civitai_image_meta(image_ref, token: str | None = None, timeout: float = 15.0) -> dict"
description: "Recupera los detalles de generacion de una imagen de Civitai por su id o URL (civitai.com/images/<id>): prompt, prompt negativo, modelo, sampler, steps, cfg, seed, dimensiones, recursos (checkpoint + LoRAs) y nivel NSFW. Es el paso 'entrar al link y observar como lo hicieron'. Usa los endpoints tRPC image.getGenerationData + image.get que consume la propia web de civitai.com, porque la API v1 publica (GET /api/v1/images) hoy devuelve meta=null y un JPEG recomprimido sin workflow embebido. Si la meta trae un workflow ComfyUI embebido (campo comfy) lo devuelve en API format. NO descarga la imagen ni reconstruye workflow: solo lee. Impura: HTTP a civitai.com + subprocess (pass para el token)."
tags: [comfyui, civitai, replicate, ml, metadata, http, stable-diffusion]
uses_functions: []
@@ -128,15 +128,15 @@ def _extract_comfy_workflow(meta):
return {}
def comfyui_fetch_civitai_image_meta(image_ref, *, token=None, timeout=15.0):
def comfyui_fetch_civitai_image_meta(image_ref, token=None, timeout=15.0):
"""Recupera los detalles de generación de una imagen de Civitai por id/URL.
Args:
image_ref: id numérico de la imagen (int o str), o su URL
`https://civitai.com/images/<id>` (con o sin query string).
token: API token de Civitai (header Authorization Bearer). Si None se
resuelve de `pass civitai/api-token`. No hardcodear. keyword-only.
timeout: timeout HTTP en segundos por petición. keyword-only.
resuelve de `pass civitai/api-token`. No hardcodear.
timeout: timeout HTTP en segundos por petición.
Returns:
dict {ok, image_id, meta, resources, process, comfy_workflow, width,
@@ -5,7 +5,7 @@ lang: py
domain: ml
version: "1.0.0"
purity: impure
signature: "def comfyui_import_workflow_png(png_path_or_url: str, *, timeout: float = 15.0) -> dict"
signature: "def comfyui_import_workflow_png(png_path_or_url: str, timeout: float = 15.0) -> dict"
description: "Extrae el workflow embebido en los chunks de texto de un PNG de ComfyUI. Lee el chunk 'prompt' (API format) y/o 'workflow' (UI graph) de los chunks tEXt/zTXt/iTXt con stdlib (struct, zlib). Acepta path local o URL. Impura: red opcional + lectura de disco."
tags: [comfyui, ml, import, png, workflow, stable-diffusion]
uses_functions: []
@@ -14,12 +14,12 @@ import urllib.request
import zlib
def comfyui_import_workflow_png(png_path_or_url: str, *, timeout: float = 15.0) -> dict:
def comfyui_import_workflow_png(png_path_or_url: str, timeout: float = 15.0) -> dict:
"""Devuelve el/los workflow(s) embebido(s) en un PNG de ComfyUI.
Args:
png_path_or_url: ruta local de un PNG, o URL http(s) de un PNG.
timeout: timeout HTTP en segundos (solo si es URL). keyword-only.
timeout: timeout HTTP en segundos (solo si es URL).
Returns:
dict {ok, prompt, workflow, format_detected, error}:
@@ -5,7 +5,7 @@ lang: py
domain: ml
version: "1.1.0"
purity: impure
signature: "def comfyui_interrupt_queue(*, clear_pending: bool = False, server: str = \"127.0.0.1:8188\", timeout: float = 10.0) -> dict"
signature: "def comfyui_interrupt_queue(clear_pending: bool = False, server: str = \"127.0.0.1:8188\", timeout: float = 10.0) -> dict"
description: "Corta la generacion en curso de ComfyUI (POST /interrupt) y, si clear_pending=True, vacia ademas la cola de pendientes (POST /queue {\"clear\":true}). Consulta GET /queue al final para reportar queue_remaining. Devuelve {ok, interrupted, cleared, queue_remaining, error}. NO lanza excepcion en fallo de red: degrada a {ok: False, error}. /interrupt corta solo el prompt en ejecucion, no vacia los pendientes salvo clear_pending. Impura: HTTP POST + GET, solo stdlib (urllib, json)."
tags: [comfyui, ml, queue, interrupt, control, http]
uses_functions: []
@@ -17,7 +17,6 @@ import urllib.request
def comfyui_interrupt_queue(
*,
clear_pending: bool = False,
server: str = "127.0.0.1:8188",
timeout: float = 10.0,
+1 -1
View File
@@ -5,7 +5,7 @@ lang: py
domain: ml
version: "1.0.0"
purity: impure
signature: "def comfyui_list_skills(*, library_dir: str = None, include_nsfw: bool = False) -> dict"
signature: "def comfyui_list_skills(library_dir: str = None, include_nsfw: bool = False) -> dict"
description: "Lista las skills ComfyUI guardadas en la libreria de disco con su metadata de resumen: slug, title, base_workflow, version, score_mean/score_n y nsfw (de provenance.nsfw), mas n_versions. Respeta include_nsfw=False (oculta las NSFW por defecto). Libreria inexistente o vacia -> lista vacia sin error. library_dir default ~/ComfyUI/skills_library."
error_type: error_go_core
tags: [comfyui, comfyui-skill, ml, skill, library]
+2 -3
View File
@@ -28,13 +28,12 @@ def _n_versions(skill_dir):
if f.startswith("v") and f.endswith(".json")])
def comfyui_list_skills(*, library_dir: str = None, include_nsfw: bool = False) -> dict:
def comfyui_list_skills(library_dir: str = None, include_nsfw: bool = False) -> dict:
"""Lista las skills de la libreria con su metadata de resumen.
Args:
library_dir: raiz de la libreria. Default `~/ComfyUI/skills_library`. keyword-only.
library_dir: raiz de la libreria. Default `~/ComfyUI/skills_library`.
include_nsfw: si False (default), oculta las skills con `provenance.nsfw == True`.
keyword-only.
Returns:
dict ``{ok, skills, count, error}`` donde `skills` es una lista de dicts
+1 -1
View File
@@ -5,7 +5,7 @@ lang: py
domain: ml
version: "1.0.0"
purity: impure
signature: "def comfyui_load_skill(slug: str, *, version=None, library_dir: str = None) -> dict"
signature: "def comfyui_load_skill(slug: str, version=None, library_dir: str = None) -> dict"
description: "Lee una receta de skill ComfyUI de la libreria de disco: recipe.json (version actual) o un snapshot versions/vN.json. Hermana inversa de comfyui_save_skill; el round-trip save(recipe)->load(slug) devuelve un dict identico. library_dir default ~/ComfyUI/skills_library. Slug, version o archivo inexistente -> {ok:False} sin lanzar."
error_type: error_go_core
tags: [comfyui, comfyui-skill, ml, skill, library]
+3 -3
View File
@@ -36,14 +36,14 @@ def _version_filename(version):
return None
def comfyui_load_skill(slug: str, *, version=None, library_dir: str = None) -> dict:
def comfyui_load_skill(slug: str, version=None, library_dir: str = None) -> dict:
"""Lee la receta de una skill (version actual o un snapshot concreto).
Args:
slug: slug de la skill (nombre de su carpeta en la libreria).
version: si None, lee `recipe.json` (version actual). Si se pasa (int, "1" o
"v1"), lee el snapshot `versions/vN.json`. keyword-only.
library_dir: raiz de la libreria. Default `~/ComfyUI/skills_library`. keyword-only.
"v1"), lee el snapshot `versions/vN.json`.
library_dir: raiz de la libreria. Default `~/ComfyUI/skills_library`.
Returns:
dict ``{ok, recipe, slug, path, version, error}``. En exito ``ok=True`` y `recipe`
+1 -1
View File
@@ -5,7 +5,7 @@ lang: py
domain: ml
version: "1.0.0"
purity: impure
signature: "def comfyui_save_skill(recipe: dict, *, library_dir: str = None) -> dict"
signature: "def comfyui_save_skill(recipe: dict, library_dir: str = None) -> dict"
description: "Persiste una receta de skill ComfyUI (schema comfyui-skill) en la libreria de disco: valida el schema minimo y escribe <library_dir>/<slug>/recipe.json + un snapshot inmutable versions/vN.json (N incremental) + bitacora growth_log.jsonl + regenera INDEX.md. No muta la receta (round-trip identico con comfyui_load_skill). library_dir default ~/ComfyUI/skills_library. Devuelve dict {ok, slug, path, version_file, n_versions, error}; nunca lanza."
error_type: error_go_core
tags: [comfyui, comfyui-skill, ml, skill, library, persistence]
+2 -2
View File
@@ -91,13 +91,13 @@ def _rewrite_index(lib):
fh.write("\n".join(lines))
def comfyui_save_skill(recipe: dict, *, library_dir: str = None) -> dict:
def comfyui_save_skill(recipe: dict, library_dir: str = None) -> dict:
"""Valida y persiste una receta de skill en la libreria de disco.
Args:
recipe: dict de la receta (schema `comfyui-skill`). Requiere al menos `slug`,
`base_workflow` y `version` (strings no vacios). No se muta.
library_dir: raiz de la libreria. Default `~/ComfyUI/skills_library`. keyword-only.
library_dir: raiz de la libreria. Default `~/ComfyUI/skills_library`.
Returns:
dict ``{ok, slug, path, recipe_path, version_file, n_versions, error}``. En error de