+
    #j΃                    b  a  0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t
^ RIHt ^ RIHt ^ RIHtHt ^ RIHt  ^ RItRtR	tR
tRt^<t^tRtRt 0 Rmt!Rt"0 Rmt#0 Rmt$R]%R&   RRR.RRR.RRR.RRR.RRR./t&R]%R&   R R lt'/ RR.bRR.bRR.bRR.bRR.bRR.bR R.bR!R.bR"R.bR#R.bR$R.bR%R.bR&R.bR'RR.bR(. RObR)R.bR*R.bR+R.R,R.R-R.R.R.R/R.R0R.R1R.R2R.R3R.R4R.R5R.R6R.R7. /Ct(R8]%R9&   . RNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNER NERNERNERNERNERNERNERNERNER	NER
NERNERNt)R:]%R;&   0 ERmt*]PV                  ! R<]PX                  4      t-ERt.R=0t/R> R? lt0R@R/RA RB llt1RC RD lt2RER/RF RG llt3RH RI lt4] ! RJ RK4      4       t5]] 3RL RM llt6RNRRORRPRRQRRRRRS]RTRRU]RVRRWR/
RX RY llt7ERt8]'       d    ! RZ R[]Pr                  4      t:R\ R] lt;R^ R_ lt<R` Ra lt=Rb Rc lt>Rd Re lt?Rf Rg lt@Rh Ri ltARj Rk ltBRl Rm ltCRn Ro ltDRp Rq ltERr Rs ltFERtG^ tHRt Ru ltIRv Rw ltJRx Ry ltKRz R{ ltLR|^/R} R~ lltMR R ltNR#   ] d    Rt^ RIt^ RIt ELi ; i(  u  
_common.py — Shared logic for ComfyUI skill scripts.

Single source of truth for:
- HTTP transport (with retry/backoff, streaming, timeout handling)
- Cloud detection and endpoint mapping (local ComfyUI vs Comfy Cloud)
- Workflow node-type catalogs (param patterns, model loaders, output nodes)
- API-format validation
- Path-traversal-safe file writes
- API-key loading from env / CLI

Stdlib-only by design (with optional `requests` upgrade if installed). Python 3.10+.
)annotationsN)	dataclass)Path)AnyIterator)urlparseTFzhttp://127.0.0.1:8188zhttps://cloud.comfy.orgCOMFY_CLOUD_API_KEYg      ?g      >@set[str]OUTPUT_NODESunetdiffusion_modelscliptext_encoders
controlnetcontrol_netzdict[str, list[str]]FOLDER_ALIASESc                    V ^8  d   QhRRRR/# )   folderstrreturnz	list[str] )formats   "a/opt/hermes-venv/lib/python3.14/site-packages/../../../skills/creative/comfyui/scripts/_common.py__annotate__r   f   s     0 0s 0y 0    c                .    \         P                  W .4      # )z8Return the search order of folder names (primary first).)r   get)r   s   &r   folder_aliases_forr   f   s    fh//r   CheckpointLoaderSimpleCheckpointLoaderzCheckpointLoader (Simple)ImageOnlyCheckpointLoaderunCLIPCheckpointLoader
LoraLoaderLoraLoaderModelOnlyLoraLoaderTagsQuery	VAELoaderControlNetLoaderDiffControlNetLoaderControlNetLoaderAdvanced
CLIPLoaderDualCLIPLoaderTripleCLIPLoaderCLIPVisionLoader
UNETLoaderDiffusionModelLoaderUNETLoaderGGUFUpscaleModelLoaderStyleModelLoaderGLIGENLoaderHypernetworkLoaderIPAdapterModelLoaderInstantIDModelLoaderADE_LoadAnimateDiffModel ADE_AnimateDiffLoaderWithContextADE_AnimateDiffLoaderGen1PhotoMakerLoaderModelSamplingFluxz dict[str, list[tuple[str, str]]]MODEL_LOADERSzlist[tuple[str, str, str]]PARAM_PATTERNSzc(?:^|[\s,(\[])embedding\s*:\s*([A-Za-z0-9_\-\./\\]+?)(?:\.(?:pt|safetensors|bin))?(?=[\s:,)\(\]]|$)zcloud.comfy.orgc                    V ^8  d   QhRRRR/# )r   hostr   r   boolr   )r   s   "r   r   r   O  s     D D D Dr   c                  a \        RV 9   d   T MRV  24      pVP                  ;'       g    RP                  4       oS\        9   d   R# \        ;QJ d#    V3R l\
         4       F  '       g   K   R# 	  R# ! V3R l\
         4       4      # )zFTrue if the host points at Comfy Cloud (or staging/preview subdomain).z://zhttp:// Tc              3  F   <"   T F  pSP                  V4      x  K  	  R # 5iN)endswith).0shostnames   & r   	<genexpr> is_cloud_host.<locals>.<genexpr>U  s!     C-Bx  ##-Bs   !F)r   rH   lowerCLOUD_DOMAIN_EXACTanyCLOUD_DOMAIN_SUFFIXES)r?   parsedrH   s   & @r   is_cloud_hostrP   O  sm    etmd74&1ABF%%2,,.H%%3C-BC33C3C3C-BCCCr   force_cloudc               (    V ^8  d   QhRRRRRRRR/# )r   baser   pathrQ   bool | Noner   r   )r   s   "r   r   r   X  s)       3  WZ r   c                   V P                  R4      p Vf   \        V 4      MTpVP                  R4      '       g
   RV,           pV'       d!   VP                  R4      '       g
   RV,           pW,           # )a  Build a URL that adds /api prefix when targeting Comfy Cloud.

Local ComfyUI accepts both `/foo` and `/api/foo` for many endpoints.
Cloud requires `/api/foo`.

`path` should be a path component (e.g. "/prompt") or full path with query
(e.g. "/view?filename=x").
/z/api/z/api)rstriprP   
startswith)rS   rT   rQ   clouds   &&$ r   build_cloud_aware_urlr[   X  s]     ;;sD#.#6M$KE??3TzT__W--};r   c                    V ^8  d   QhRRRR/# )r   rT   r   r   r   )r   s   "r   r   r   j  s        r   c                    V P                  R4      '       d-   V P                  R4      '       g   RV \        R4      R ,           # V P                  R4      '       d   RV \        R4      R ,           # V R8X  d   R# V # )zMap a cloud endpoint path to its current canonical form.

Handles known renames documented in the Comfy Cloud API:
  /history       -> /history_v2
  /models/<f>    -> /experiment/models/<f>
  /models        -> /experiment/models
z/historyz/history_v2Nz/models/z/experiment/models/z/modelsz/experiment/models)rY   len)rT   s   &r   cloud_endpointr_   j  sn     z""4??=+I+ItC
O$4555z""$tC
O,<'===y#Kr   is_cloudc               (    V ^8  d   QhRRRRRRRR/# )r   rS   r   rT   r`   rU   r   r   )r   s   "r   r   r   {  s.     @ @c @ @; @# @r   c               d    Vf   \        V 4      MTpV'       d   \        V4      p\        WVR7      # )zETop-level URL resolver. Applies cloud rename + /api prefix as needed.)rQ   )rP   r_   r[   )rS   rT   r`   rZ   s   &&$ r   resolve_urlrc   {  s-    #+#3M$Ed# ??r   c                    V ^8  d   QhRRRR/# )r   explicitz
str | Noner   r   )r   s   "r   r   r     s      j Z r   c                    V '       d   T M"\         P                  P                  \        4      pVf   R# VP	                  4       P	                  R4      pT;'       g    R# )uH   Look up API key from CLI flag → env var. Strips whitespace and quotes.Nz'")osenvironr   ENV_API_KEYstrip)re   vals   & r   resolve_api_keyrl     sB    (BJJNN;$?C
{
))+

E
"C;;$r   c                  \    ] tR tRt$ R]R&   R]R&   R]R&   R]R	&   RR
 R lltR R ltRtR# )HTTPResponsei  intstatusdict[str, str]headersbytesbodyr   urlc                    V ^8  d   QhRRRR/# )r   encodingr   r   r   )r   s   "r   r   HTTPResponse.__annotate__  s     < <S <s <r   c                	<    V P                   P                  VR R7      # )replaceerrors)rt   decode)selfrw   s   &&r   textHTTPResponse.text  s    yy;;r   c                   V ^8  d   QhRR/# )r   r   r   r   )r   s   "r   r   rx     s     G Gc Gr   c                	d    \         P                  ! V P                  P                  R RR7      4      # )utf-8rz   r{   )jsonloadsrt   r}   )r~   s   &r   r   HTTPResponse.json  s%    zz$))**79*EFFr   r   N)r   )__name__
__module____qualname____firstlineno____annotations__r   r   __static_attributes__r   r   r   rn   rn     s(    K
K	H<G Gr   rn   c               (    V ^8  d   QhRRRRRRRR/# )r   attemptro   rS   floatcapr   Noner   )r   s   "r   r   r     s)      C u e bf r   c                    \        W!^V ,          ,          4      p\        P                  ! ^ V4      p\        P                  ! V4       R# )z+Sleep with full-jitter exponential backoff.N)minrandomuniformtimesleep)r   rS   r   delays   &&& r   _sleep_backoffr     s1    Q'\*+ENN1e$EJJur   rr   	json_bodydatafilesformtimeoutfollow_redirectsretriesstreamsinkc               L    V ^8  d   QhRRRRRRRRRR	R
RRRRRRRRRRRRRRR/# )r   methodr   ru   rr   zdict[str, str] | Noner   r   r   bytes | Noner   dict | Noner   r   r   r   r@   r   ro   r   r   Path | Noner   rn   r   )r   s   "r   r   r     s     @K @K@K	@K #	@K
 @K @K @K @K @K @K @K @K @K @Kr   c       
           Vf   / p\        V4      pVP                  RR4       V'       g   Ve   \        '       g   \        R4      hRp\	        V	4       FG  p \        WVW4WVWxWR7      pVP                  \        9   d   V^,           V	8  d   \        V4       KE  Vu # 	  V'       d   Vh\        R4      h  \        \        \        3 d(   pTpT^,           T	8  d   \        T4        Rp?K  h Rp?ii ; i)a  Single entry point for all HTTP traffic.

Behavior:
  - Retries on connection errors and on HTTP statuses in RETRY_STATUS_CODES,
    with exponential backoff + jitter.
  - For cross-host redirects, drops Authorization-style headers (so signed
    URLs don't leak the API key to S3/CloudFront).
  - When `stream=True` and `sink` is a Path, streams the response body to
    disk in 64 KiB chunks instead of buffering.

Either `json_body`, `data`, or `files`+`form` may be supplied (mutually exclusive).
Nz
User-Agentzhermes-comfyui-skill/5.0zTMultipart upload requires the `requests` package. Install with: pip install requests)r   ru   rr   r   r   r   r   r   r   r   r   z0http_request: retries exhausted with no response)dict
setdefaultHAS_REQUESTSRuntimeErrorrange
_http_oncerp   RETRY_STATUS_CODESr   TimeoutErrorConnectionErrorOSError)r   ru   rr   r   r   r   r   r   r   r   r   r   last_excr   respes   &&$$$$$$$$$$    r   http_requestr     s    6 7mG|%?@  |5 
 "&H>	#e	D {{00Wq[75Jw'K "( 
I
JJ ow7 	H{W$w'	s$   ?B4B44C1
C,+C,,C1c                  ,   a  ] tR tRtRtV 3R ltRtV ;t# ) _StripSensitiveOnRedirectSessioni  u  Session that drops sensitive headers on cross-host redirects.

`requests` already strips `Authorization` cross-host (rebuild_auth),
but it does NOT strip custom headers like `X-API-Key`. We override
`rebuild_auth` to additionally strip every header in
`_SENSITIVE_HEADERS` when the destination is a different host —
critical when ComfyUI Cloud's `/api/view` redirects to a signed S3 URL.
c                	  < \         S	V `  W4        VP                  P                  pVP                  p\	        V4      P
                  ;'       g    R P                  4       p\	        V4      P
                  ;'       g    R P                  4       pV'       d^   V'       dT   WV8w  dL   VP                  p\        VP                  4       4       F   pVP                  4       \        9   g   K  Wx K"  	  R# R# R# R#   \         d     R# i ; i)rB   N)superrebuild_authrequestru   r   rH   rK   rr   listkeys_SENSITIVE_HEADERS	Exception)
r~   prepared_requestresponseold_urlnew_urlold_hostnew_hostrr   key	__class__s
   &&&      r   r   -_StripSensitiveOnRedirectSession.rebuild_auth  s    G !1<"**..*..$W-66<<"CCE$W-66<<"CCEX-A.66G#GLLN399;*<< '  4 .B8
  s0   =C5 ,C5 =C5 C5 AC5 'C5 5DDr   )r   r   r   r   __doc__r   r   __classcell__r   s   @r   r   r     s    		 	r   r   c               H    V ^8  d   QhRRRRRRRRRR	R
RRRRRRRRRRRRR/# )r   r   r   ru   rr   rq   r   r   r   r   r   r   r   r   r   r   r@   r   r   r   r   rn   r   )r   s   "r   r   r     s     ie ieieie'5ieie&ie/:ieBMie ie '+ie 	ie $	ie
 ier   c                   \         '       EdN   RV RVRVRVRV/pVe   W;R&   MVe   WKR&   MVf   Ve	   W[R	&   WkR&   V	'       d   R
VR&   \        4       ;_uu_ 4       p VP                  ! R/ VB pV	'       d~   V
ez   V
P                  P	                  R
R
R7       V
P                  R4      ;_uu_ 4       pVP                  \        4       F  pV'       g   K  VP                  V4       K   	  RRR4       RpMVP                  p\        VP                  VP                  P                  4        UUu/ uF	  w  ppVVbK  	  uppVVP                  R7      uuRRR4       # Ve9   \.        P0                  ! V4      P3                  R4      pVP5                  RR4       MTp\6        P                  P9                  VVW R7      p ! R R\6        P                  P:                  4      p\=        V4      P>                  ;'       g    RPA                  4       p\6        P                  PC                  V! VV4      4      p VP                  VVR7      pTPQ                  4       pTPR                  p\K        TP                  4      pT	'       d   T
e   T
P                  P	                  R
R
R7       T
P                  R4      ;_uu_ 4       p TPM                  \        4      pT'       g   MTP                  T4       K2  RRR4       \        TTRTR7      # \        TTTPM                  4       TR7      #   + '       g   i     EL?; iu uppi   \        P                   P"                   dZ   p\%        T\        P                   P&                  4      '       d   \)        \+        T4      4      Th\-        \+        T4      4      ThRp?ii ; i  + '       g   i     ELj; i  \6        PD                  PF                   dn   p\        TPH                  TP                  '       d   \K        TP                  4      M/ TPM                  4       ;'       g    R\O        TRT4      R7      u Rp?# Rp?ii ; i  + '       g   i     ELu; i)zOne HTTP attempt. No retry.r   ru   rr   r   allow_redirectsNr   r   r   Tr   )parentsexist_okwbr   )rp   rr   rt   ru   r   zContent-Typezapplication/json)r   rr   r   c                  4   a  ] tR tRtR R ltV 3R ltRtV ;t# )$_http_once.<locals>._RedirectHandleriF  c                    V ^8  d   QhRRRR/# )r   original_hostr   followr@   r   )r   s   "r   r   1_http_once.<locals>._RedirectHandler.__annotate__G  s     	! 	!# 	!t 	!r   c                	    Wn         W n        R # rD   )r   r   )r~   r   r   s   &&&r   __init__-_http_once.<locals>._RedirectHandler.__init__G  s    !. Kr   c                	  < V P                   '       g   R # \        V4      P                  ;'       g    RP                  4       pWpP                  8w  d^   VP                  4        UU	u/ uF  w  rVP                  4       R9  g   K  WbK   	  p
pp	\        P                  P                  WjRR7      pV# \        SV `)  WW4WV4      # u up	pi )NrB   GET)rr   r   >   cookieauthorization	x-api-key)r   r   rH   rK   r   header_itemsurllibr   Requestr   redirect_request)r~   req2fpcodemsghdrsnewurlr   kvclean_headersnew_reqr   s   &&&&&&&     r   r   5_http_once.<locals>._RedirectHandler.redirect_requestK  s    ;;; (1177R>>@H--- &*%6%6%8!%8TQwwy(PP AD%8  ! !..00W\0]7+DdNN!s   &CC)r   r   )r   r   r   r   r   r   r   r   r   s   @r   _RedirectHandlerr   F  s    	!	O 	Or   r   rB   )r   r   )*r   r   r   parentmkdiropeniter_contentDOWNLOAD_CHUNK_SIZEwritecontentrn   status_coderr   itemsru   requests
exceptionsRequestException
isinstanceTimeoutr   r   r   r   dumpsencoder   r   r   HTTPRedirectHandlerr   rH   rK   build_openererror	HTTPErrorr   r   readgetattrgeturlrp   )r   ru   rr   r   r   r   r   r   r   r   r   kwargsrG   rfchunkrt   r   r   r   
body_bytesreqr   r   openerr   	final_urlfinal_statusfinal_headerss   $$$$$$$$$$$                  r   r   r     s    |feS)Ww 13C"
  &6N!6N$"2#7O!6N#F8 .//15II''d.KK%%dT%B4A%&^^4G%HE$u ! &I ) D99D#==./iioo.?@.?daQT.?@	 0/4 ZZ	*11':
>+=>

..
 
 :w
 
VC
O6>>== O& c]++11r88:M^^(()9-IY)Z[F
{{3{0 I;;L&M$"$6YYt__		"56  <SV_``|]Zcdd[ ) A &&77 5 a!4!4!<!<==&s1v.A5%c!f-145% 0//x <<!! 
66'(yyyDObS5#&	
 	

 __s   N4AL91L	L	)AL9-L3<L92O 8QQL0*L99N1AN,,N11N44O	Q'AQ6Q	QQQ(	c               $    V ^8  d   QhRRRRRR/# r   ru   r   r  r   r   rn   r   )r   s   "r   r   r   w  s!     . .# . . .r   c                    \        R V 3/ VB # )r   r   ru   r  s   &,r   http_getr  w  s    s-f--r   c               $    V ^8  d   QhRRRRRR/# r  r   )r   s   "r   r   r   {  s!     / /3 /# /, /r   c                    \        R V 3/ VB # )POSTr  r  s   &,r   	http_postr  {  s    .v..r   c                    V ^8  d   QhRRRR/# )r   workflowr   r   r@   r   )r   s   "r   r   r     s     	 	C 	D 	r   c                    \        V \        4      '       g   R# RV 9   d
   RV 9   d   R# V P                  4        F%  p\        V\        4      '       g   K  RV9   g   K$   R# 	  R# )z>API format = top-level dict where each value has `class_type`.Fnodeslinks
class_typeT)r   r   values)r  r   s   & r   is_api_formatr#    sQ    h%%(w(2__a<1#4  r   c                    V ^8  d   QhRRRR/# )r   payloadr   r   r   r   )r   s   "r   r   r     s      S T r   c                D   \        V \        4      '       d   \        V 4      '       d   V # \        V \        4      '       d)   RV 9   d"   \        V R,          4      '       d
   V R,          # \        V \        4      '       d   RV 9   d   RV 9   d   \        R4      h\        R4      h)zQUnwrap common wrapper variants. Returns API-format workflow or raises ValueError.promptr  r   u   Workflow is in editor format (has top-level 'nodes' and 'links' arrays). Re-export from ComfyUI using 'Workflow → Export (API)' (newer UI) or 'Save (API Format)' (older UI).zSWorkflow is not in API format. Each top-level entry must have a 'class_type' field.)r   r   r#  
ValueError)r%  s   &r   unwrap_workflowr)    s    '4  ]7%;%;'4  X%8]7S[K\=]=]x  '4  W%7Gw<N1
 	

 ] r   c                    V ^8  d   QhRRRR/# )r   valuer   r   r@   r   )r   s   "r   r   r     s      3 4 r   c                    \        V \        4      ;'       dM    \        V 4      ^8H  ;'       d7    \        V ^ ,          \        4      ;'       d    \        V ^,          \        4      # )zHTrue if `value` is a [node_id, output_index] connection (length-2 list).)r   r   r^   r   ro   r+  s   &r   is_linkr.    sZ     	5$ 	& 	&J!O	& 	&uQx%	& 	& uQx%	r   c                    V ^8  d   QhRRRR/# )r   r  r   r   zIterator[tuple[str, dict]]r   )r   s   "r   r   r     s          "<  r   c              #     "   V P                  4        F+  w  r\        V\        4      '       g   K  RV9   g   K&  W3x  K-  	  R# 5i)z5Yield (node_id, node) for each valid API-format node.r!  N)r   r   r   )r  node_idnodes   &  r   
iter_nodesr3    s4     !)dD!!ld&:- *s   )AAAc                    V ^8  d   QhRRRR/# )r   r  r   r   zIterator[dict]r   )r   s   "r   r   r     s      d ~ r   c              #  n  "   \        V 4       F  w  rVR,          pV\        9  d   K  VP                  R/ 4      ;'       g    / p\        V,           FY  w  rVVP                  V4      pV'       g   K   \        V\        4      '       g   K8  \        V4      '       d   KK  RVRVRVRVRV/x  K[  	  K  	  R# 5i)zLYield {node_id, class_type, field, value, folder} for each model dependency.r!  inputsr1  fieldr+  r   N)r3  r<   r   r   r   r.  )r  r1  r2  clsr6  
field_namer   rk   s   &       r   iter_model_depsr:    s     #H-< m#(B'--2"/"4"4J**Z(Csz#s++GCLLw #ZSf  #5 .s   ?B5+B52B5
B5B5c                    V ^8  d   QhRRRR/# )r   r  r   r   zIterator[tuple[str, str]]r   )r   s   "r   r   r     s     
* 
*$ 
*+D 
*r   c              #  J  "   \        V 4       F  w  rVP                  R/ 4      ;'       g    / pVP                  4        FZ  w  rEV\        9  d   K  \	        V\
        4      '       g   K*  \        P                  V4       F  pWP                  ^4      3x  K  	  K\  	  K  	  R# 5i)zGYield (node_id, embedding_name) for every embedding mention in prompts.r6  N)	r3  r   r   PROMPT_FIELDSr   r   EMBEDDING_REGEXfinditergroup)r  r1  r2  r6  r9  rk   ms   &      r   iter_embedding_refsrB    s     #H-(B'--2%||~OJ.c3''$--c2wwqz)) 3  . .s   )B#A7B#c               $    V ^8  d   QhRRRRRR/# )r   rS   r   partsr   r   r   )r   s   "r   r   r     s!       s t r   c                    V P                  4       pV P                  ! V!  P                  4       p VP                  V4       V#   \         d   p\        RT RT 24      ThRp?ii ; i)zJoin paths, raising if the result escapes `base`.

Server-supplied filenames may contain `../` etc. This guards against
path-traversal attacks when downloading outputs.
zRefusing path traversal: z is outside N)resolvejoinpathrelative_tor(  )rS   rD  base_resolved	candidater   s   &*   r   safe_path_joinrK    ss     LLNMu%--/Im,
 	  '	{,}oN
	s   A A%A  A%c                    V ^8  d   QhRRRR/# )r   filenamer   r   r   )r   s   "r   r   r     s     
 
s 
s 
r   c                    \        V 4      P                  P                  4       pVR9   d   R# VR9   d   R# VR9   d   R# VR	9   d   R# R# )
.mp4videoaudio3dr   image>   .avi.gif.mkv.movrO  .webm.webp>   .m4a.mp3.ogg.wav.flac>   .glb.obj.ply.gltf>   .md.txt.json)r   suffixrK   )rM  exts   & r   media_type_from_filenamerh    sM    
x.


%
%
'C
HH
77
//
&&r   c                    V ^8  d   QhRRRR/# )r   r  r   r   r@   r   )r   s   "r   r   r     s        r   c                    \        V 4       FI  w  rVR,          \        9   d    R# VR,          P                  4       P                  R4      '       g   KH   R# 	  R# )z1Used to bump default timeout for video workflows.r!  TF)animatediffade_wanvideohunyuanvideoltxvideocogvideo)r3  SLOW_OUTPUT_NODESrK   rY   )r  _r2  s   &  r   looks_like_video_workflowrs    sL    h'!22##%001|}}	 (
 r   c                    V ^8  d   QhRRRR/# )r   r+  r   r   ro   r   )r   s   "r   r   r     s      s s r   c                >   V f    \         P                  ! \        \        4      # \	        V \
        4      '       d5   V P                  4       R8X  d    \         P                  ! \        \        4      # V R8X  d    \         P                  ! \        \        4      # \        V 4      # )zConvert -1 or None to a fresh random seed; otherwise return int(value).

Accepts numeric -1 OR string "-1" (both treated as "randomize"). Other
parse failures raise TypeError/ValueError for the caller to surface.
z-1)r   randintSEED_MINSEED_MAXr   r   rj   ro   r-  s   &r   coerce_seedrz    sg     }~~h11%%++-4"7~~h11{~~h11u:r   c                    V ^8  d   QhRRRR/# )r   r%  r   r   r	   r   )r   s   "r   r   r     s      c h r   c                   \        V \        4      '       g   \        4       # \        4       pV  F  p\        V\        4      '       d   VP	                  V4       K,  \        V\
        4      '       g   KD  VP                  R4      ;'       g+    VP                  R4      ;'       g    VP                  R4      p\        V\        4      '       g   K  VP	                  V4       K  	  V# )zNormalize model-list responses from local ComfyUI vs Comfy Cloud.

Local: `["a.safetensors", "b.safetensors"]`
Cloud: `[{"name": "a.safetensors", "pathIndex": 0}, ...]`
namerM  rT   )r   r   setr   addr   r   )r%  outitemr}  s   &   r   parse_model_listr    s     gt$$uECdC  GGDMd##88F#OOtxx
';OOtxx?OD$$$  Jr   c                   V ^8  d   QhRR/# )r   r   r   r   )r   s   "r   r   r   3  s      s r   c                 >    \        \        P                  ! 4       4      # rD   )r   uuiduuid4r   r   r   new_client_idr  3  s    tzz|r   c                    V ^8  d   QhRRRR/# )r   dr   r   r   r   )r   s   "r   r   r   7  s     8 8d 8s 8r   c                N    RP                  R V P                  4        4       4      # )zPretty key=value for log lines. c              3  6   "   T F  w  rV R V: 2x  K  	  R# 5i)=Nr   )rF   r   r   s   &  r   rI   fmt_kv.<locals>.<genexpr>9  s     7YTQqc1%LYs   )joinr   )r  s   &r   fmt_kvr  7  s    887QWWY777r   indentc               $    V ^8  d   QhRRRRRR/# )r   objr   r  ro   r   r   r   )r   s   "r   r   r   <  s!     7 73 73 7t 7r   c               P    \        \        P                  ! W\        R7      4       R# )zKPrint JSON to stdout. Centralised so behavior can be tweaked (e.g., --raw).)r  defaultN)printr   r   r   )r  r  s   &$r   	emit_jsonr  <  s    	$**S
56r   c                    V ^8  d   QhRRRR/# )r   r   r   r   r   r   )r   s   "r   r   r   A  s     5 5S 5T 5r   c                B    \        RV  2\        P                  R7       R# )z?stderr log with consistent prefix (so JSON stdout stays clean).z[comfyui-skill] )fileN)r  sysstderr)r   s   &r   logr  A  s    	SE
"4r   >   
                i   >   	SaveAudio	SaveVideoCogVideoSamplerLTXVideoSamplerSaveAnimatedPNGWanVideoSamplerSaveAnimatedWEBPVHS_VideoCombineHunyuanVideoSamplerSaveAnimateDiffVideoSVD_img2vid_Conditioning>   Save3DSaveGLB	ImageSaver  	SaveImager  
SaveLatentPreviewAudioPreviewImagePreviewVideor  r  r  
Image Saveeasy imageSaveShowText|pysssssPreviewImage|pysssssImage Save With Metadata)	ckpt_namecheckpoints)	lora_nameloras)vae_namevae)control_net_namer   )	clip_namer   
clip_name1r   
clip_name2r   )r  r  )
clip_name3r   )r  clip_vision)	unet_namer   )
model_namer   )r  upscale_models)style_model_namestyle_models)gligen_namegligen)hypernetwork_namehypernetworks)ipadapter_file	ipadapter)instantid_file	instantid)r  animatediff_models)photomaker_model_name
photomaker)CLIPTextEncoder   r'  )CLIPTextEncodeSDXLtext_gr'  )r  text_lprompt_l)CLIPTextEncodeSDXLRefinerr   refiner_prompt)CLIPTextEncodeFluxclip_lr  )r  t5xxlr'  )r  guidancer  )zsmZ CLIPTextEncoder   r'  )BNK_CLIPTextEncodeAdvancedr   r'  )KSamplerseedr  )r  stepsr  )r  cfgr  )r  sampler_namer  )r  	schedulerr  )r  denoiser  )KSamplerAdvanced
noise_seedr  )r  r  r  )r  r  r  )r  r  r  )r  r  r  )r  start_at_stepr  )r  end_at_stepr  )RandomNoiser  r  )BasicSchedulerr  r  )r  r  r  )r  r  r  )KSamplerSelectr  r  )	CFGGuiderr  r  )DualCFGGuider	cfg_condsr  )r  cfg_cond2_negativecfg_negative)r;   	max_shiftr  )r;   
base_shiftr  )r;   widthmodel_width)r;   heightmodel_height)ModelSamplingSD3shiftr  )ModelSamplingDiscretesamplingr  )SDTurboSchedulerr  r  )r  r  r  )SamplerCustomr  r  )r  r  r  )EmptyLatentImager  r  )r  r  r  )r  
batch_sizer  )EmptySD3LatentImager  r  )r	  r  r  )r	  r  r  )EmptyHunyuanLatentVideor  r  )r
  r  r  )r
  lengthr  )r
  r  r  )EmptyMochiLatentVideor  r  )r  r  r  )r  r  r  )EmptyLTXVLatentVideor  r  )r  r  r  )r  r  r  )LatentUpscaler  upscale_width)r  r  upscale_height)LatentUpscaleByscale_byr  )
ImageScaler  r  )r  r  r  )	LoadImagerS  rS  )LoadImageMaskrS  
mask_image)LoadImageOutputrS  rS  )VHS_LoadVideorP  rP  )VHS_LoadAudiorQ  rQ  )r   r  r  )r    r  r  )r!   r  r  )r&   r  r  )r.   r  r  )r/   r  diffusion_model_name)r1   r  upscale_model_name)r*   r  r  )r+   r  r  )r+   r  r  )r'   r  controlnet_name)r#   r  r  )r#   strength_modellora_strength)r#   strength_cliplora_strength_clip)r$   r  r  )r$   r  r  )ControlNetApplystrengthcontrolnet_strength)ControlNetApplyAdvancedr"  r#  )r$  start_percentcontrolnet_start)r$  end_percentcontrolnet_end)IPAdapterAdvancedweightipadapter_weight)r)  start_atipadapter_start)r)  end_atipadapter_end)	IPAdapterr*  r+  )ImageUpscaleWithModelupscale_methodr2  )r8   motion_scaler3  )r9   r3  r3  )r  
frame_rater4  )r  r   video_format)r  filename_prefixr6  )r  r6  r6  )r  r  r  )r  r  r  )r  r  r  )r  r  r  )r  r  r  )r  r  r  )LTXVSchedulerr  r  )r7  r  r  )zSeed (rgthree)r  r  )zImage Comparer (rgthree)image_arS  )zPower Lora Loader (rgthree)PowerLoraLoaderHeaderWidget_lora_header)PrimitiveNoder+  primitive_value)z	easy seedr  r  )zeasy positivepositiver'  )zeasy negativenegativenegative_prompt)easy fullLoaderr  r  )r@  r  r  )r@  r  r  )r@  r=  r'  )r@  r>  r?  >   r   r  r  r  r  r>  r=  )z
.comfy.org)r   r   r   l    )O__conditional_annotations__r   
__future__r   r   rg   r   rer  r   r  dataclassesr   pathlibr   typingr   r   urllib.parser   r   r   ImportErrorurllib.errorr   urllib.requestDEFAULT_LOCAL_HOSTDEFAULT_CLOUD_HOSTri   DEFAULT_HTTP_TIMEOUTDEFAULT_RETRIESRETRY_BASE_DELAYRETRY_MAX_DELAYr   r   rq  r
   r   r   r   r<   r=   r=  compile
IGNORECASEr>  rN   rL   rP   r[   r_   rc   rl   rn   r   r   r   Sessionr   r   r  r  r#  r)  r.  r3  r:  rB  rK  rh  rs  ry  rx  rz  r  r  r  r  r  )rA  s   @r   <module>rT     s	   #  	  	 
   !    !L - . #   =    h 2 V'(+V4
V_%ov.</($ 0.3!= >.3 != >.3  ">!?	.3
  ">!?.3 != >.3 !7 8.3 !7 8.3 !7 8.3 !4 5.3 !C D.3 !C D.3  !C D!.3$ !6 7%.3& !79O P'.3(  h).3* != >+.3. !6 7/.30 !C D!6 7!A B!E F!: ;!G H
 !@ A!@ A!E F&)M(N"F!G!H I[.3/ .hU.(U. /U. 1	U.
 <U. 1U. .U. 3U. -U. 5U. !U. #U. U.  1!U." +#U.$ '%U.& /'U.( +)U.* '+U., 9-U.. 3/U.0 ;1U.2 73U.8 *9U.: );U.< 1=U.> -?U.@ 7AU.D  EU.F *GU.H <IU.J 4KU.L 6MU.N 2OU.P 4QU.R +SU.T 6UU.V +WU.X /YU.Z ,[U.\ $]U.d +eU.f -gU.h 5iU.j .kU.l 0mU.n 8oU.p 2qU.r 4sU.t 4uU.v <wU.x 0yU.z 2{U.| 2}U.~ /U.@ 1AU.B 1CU.D 0EU.F 2GU.H 0IU.J %KU.L 'MU.R $SU.T -UU.V *WU.X (YU.Z ([U.` 9aU.b 3cU.d <eU.f *gU.h -iU.j CkU.l ?mU.n -oU.p 3qU.r 3sU.t @uU.z -{U.| 6}U.~ :U.@ 6AU.B ?CU.H ;IU.J CKU.L EMU.N AOU.T 8UU.V 9WU.X 5YU.Z 0[U.` BaU.f IgU.h BiU.n 5oU.p 3qU.r ?sU.t 8uU.z ,{U.| .}U.~ *U.@ (AU.B *CU.D &EU.F 0GU.H 2IU.N 'OU.P 5QU.R SSU.X 2YU.Z "[U.\ ,]U.^ 5_U.` 2aU.b 0cU.d 2eU.f .gU.h 7iU.* Up X **jMM ( '( Dd $"@ @ 
G 
G 
G 0@o @K &*	@K
 @K @K @K @K *@K "@K #@K @K @KF >  8+;+; 6ieX./	& &
*""
 (.8
7 7
5A  Ls   L L.-L.