"""Node definition data models.
Defines structures for ComfyUI node schemas and metadata.
Supports node introspection for intelligent workflow construction.
"""
from dataclasses import dataclass, field
from typing import Any
@dataclass
class NodeInputSpec:
"""Specification for a single node input parameter.
Attributes:
name: Input parameter name (e.g., "prompt", "seed", "ckpt_name")
type: Python type hint or ComfyUI type string
required: Whether this input is required
default: Default value if optional
options: List of valid values (for enums/selects)
description: Human-readable description
"""
name: str
type: str | type
required: bool = True
default: Any = None
options: list[Any] | None = None
description: str = ""
@dataclass
class NodeOutputSpec:
"""Specification for a single node output.
Attributes:
index: Output index (0-based)
type: Output type (e.g., "IMAGE", "LATENT", "MODEL")
name: Optional output name
"""
index: int
type: str
name: str = ""
@dataclass
class NodeDefinition:
"""Complete definition of a ComfyUI node.
Represents the schema and metadata for a single node type,
parsed from ComfyUI's /object_info endpoint response.
Attributes:
class_type: Node class identifier (e.g., "KSampler", "CLIPTextEncode")
display_name: Human-readable node name
category: Node category for organization (e.g., "sampling", "conditioning")
description: Node description/documentation
input_types: Dictionary of input specifications (required and optional)
output_types: List of output specifications
return_types: List of output type strings (legacy ComfyUI format)
return_names: List of output names (legacy ComfyUI format)
python_module: Python module path if available
deprecated: Whether this node is deprecated
experimental: Whether this node is experimental
"""
class_type: str
display_name: str = ""
category: str = ""
description: str = ""
input_types: dict[str, list[NodeInputSpec]] = field(default_factory=dict)
output_types: list[NodeOutputSpec] = field(default_factory=list)
return_types: list[str] = field(default_factory=list)
return_names: list[str] = field(default_factory=list)
python_module: str = ""
deprecated: bool = False
experimental: bool = False
def get_required_inputs(self) -> list[NodeInputSpec]:
"""Get all required input parameters."""
return self.input_types.get("required", [])
def get_optional_inputs(self) -> list[NodeInputSpec]:
"""Get all optional input parameters."""
return self.input_types.get("optional", [])
def get_all_inputs(self) -> list[NodeInputSpec]:
"""Get all input parameters (required + optional)."""
return self.get_required_inputs() + self.get_optional_inputs()
def to_dict(self) -> dict[str, Any]:
"""Convert to dictionary for serialization."""
return {
"class_type": self.class_type,
"display_name": self.display_name,
"category": self.category,
"description": self.description,
"input_types": {
key: [
{
"name": inp.name,
"type": inp.type if isinstance(inp.type, str) else inp.type.__name__,
"required": inp.required,
"default": inp.default,
"options": inp.options,
"description": inp.description,
}
for inp in specs
]
for key, specs in self.input_types.items()
},
"output_types": [
{"index": out.index, "type": out.type, "name": out.name}
for out in self.output_types
],
"return_types": self.return_types,
"return_names": self.return_names,
"python_module": self.python_module,
"deprecated": self.deprecated,
"experimental": self.experimental,
}