+
    #jg{                       R t ^ RIH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 ]P                  P!                  ^ ]! ]	! ]4      P'                  4       P(                  4      4       ^ RIHtHtHtHtHtHtHtHtHtHtH t H!t!H"t"H#t#H$t$H%t%H&t&  ! R R]'4      t( ! R	 R
4      t)R R lt*R R lt+RR/R R llt,RRRR/R R llt-R R lt.RR R llt/]0R8X  d   ]Pb                  ! ]/! 4       4       R# R# )um  
run_workflow.py — Inject parameters into a ComfyUI workflow, submit it, monitor
execution, and download outputs.

Improvements over v1:
  - Cloud-aware URL routing (handles /api prefix and /history_v2 / /experiment/models renames)
  - API key from CLI flag OR $COMFY_CLOUD_API_KEY env var
  - WebSocket progress monitoring (--ws), with HTTP polling fallback
  - Streaming download (no whole-file buffering — handles GB-size video outputs)
  - Path-traversal-safe output writes
  - Subfolder-aware download paths (no silent overwrites)
  - Retry with exponential backoff on transient errors
  - Status-error correctly classified before "completed: true"
  - Image upload helper (--input-image NAME=PATH)
  - Auto-randomize seed when value is -1 or omitted on a randomize-seed flag
  - Auto-extends timeout heuristically for video workflows
  - Editor-format detection with helpful error
  - Doesn't pollute extra_data.api_key_comfy_org with the cloud auth key
    unless --partner-key is provided (correct semantic per cloud docs)

Usage:
    # Local server
    python3 run_workflow.py --workflow workflow_api.json         --args '{"prompt": "a cat", "seed": 42}'         --output-dir ./outputs

    # Cloud server (API key from env var)
    export COMFY_CLOUD_API_KEY="comfyui-xxxxxxx"
    python3 run_workflow.py --workflow workflow_api.json         --args '{"prompt": "a cat"}'         --host https://cloud.comfy.org         --output-dir ./outputs

    # With image input (auto-uploads, then references)
    python3 run_workflow.py --workflow img2img.json         --input-image image=./photo.png         --args '{"prompt": "make it cyberpunk"}'

    # WebSocket real-time progress
    python3 run_workflow.py --workflow flux_dev.json         --args '{"prompt": "..."}'         --ws

Stdlib-only by default (Python 3.10+). Will use `requests`/`websocket-client`
if installed for nicer behavior.
)annotationsN)Path)Any)	urlencodeurlparse)DEFAULT_LOCAL_HOSTENV_API_KEYcoerce_seed	emit_jsonhttp_get	http_posthttp_requestis_cloud_hostis_linkloglooks_like_video_workflowmedia_type_from_filenamenew_client_idresolve_api_keyresolve_urlsafe_path_joinunwrap_workflowc                  >   a  ] tR t^KtRtR V 3R lltR R ltRtV ;t# )WorkflowRunErrorzBRaised when a workflow run fails (validation, execution, timeout).c               $    V ^8  d   QhRRRRRR/# )   statusstrmessagedetailsr    )formats   "f/opt/hermes-venv/lib/python3.14/site-packages/../../../skills/creative/comfyui/scripts/run_workflow.py__annotate__WorkflowRunError.__annotate__N   s!      s S S     c                	J   < \         SV `  V4       Wn        W n        W0n        R # N)super__init__r   r   r   )selfr   r   r   	__class__s   &&&,r"   r)   WorkflowRunError.__init__N   s    !r%   c                   V ^8  d   QhRR/# )r   returndictr    )r!   s   "r"   r#   r$   T   s       r%   c                	p    R V P                   RV P                  /pVP                  V P                  4       V# )r   error)r   r   updater   )r*   ds   & r"   to_dictWorkflowRunError.to_dictT   s-    t{{GT\\:	r%   )r   r   r   )	__name__
__module____qualname____firstlineno____doc__r)   r4   __static_attributes____classcell__)r+   s   @r"   r   r   K   s    L  r%   r   c                      ] tR t^Zt]RRR3R R llt]R R l4       tR R ltR R	 lt	R
RRRRRRR/R R llt
R R ltR R ltRRRRRR/R R lltRRRR/R  R! lltR" R# ltR$RRR%/R& R' lltR+R( R) lltR*tR# ),ComfyRunnerNc               (    V ^8  d   QhRRRRRRRR/# )r   hostr   api_key
str | None	client_idpartner_keyr    )r!   s   "r"   r#   ComfyRunner.__annotate__[   s2     6 66 6 	6
  6r%   c                	    VP                  R 4      V n        W n        W@n        \	        V P                  4      V n        T;'       g    \        4       V n        R# )/N)rstripr@   rA   rD   r   is_cloudr   rC   )r*   r@   rA   rC   rD   s   &&&&&r"   r)   ComfyRunner.__init__[   s@     KK$	&%dii0"55mor%   c                   V ^8  d   QhRR/# )r   r.   zdict[str, str]r    )r!   s   "r"   r#   rE   i   s       r%   c                	L    / pV P                   '       d   V P                   VR &   V# )z	X-API-Key)rA   )r*   hs   & r"   headersComfyRunner.headersh   s"    <<<!\\AkNr%   c                    V ^8  d   QhRRRR/# )r   pathr   r.   r    )r!   s   "r"   r#   rE   o   s     D D D Dr%   c                	D    \        V P                  WP                  R 7      # ))rI   )r   r@   rI   )r*   rQ   s   &&r"   _urlComfyRunner._urlo   s    499d]]CCr%   c                   V ^8  d   QhRR/# )r   r.   ztuple[bool, dict | None]r    )r!   s   "r"   r#   rE   s   s     
, 
,6 
,r%   c                	\    \        V P                  R 4      V P                  ^R7      pVP                  ^8X  d    RVP	                  4       3# RRVP                  RVP                  4       R,          /3#   \
         d    R	u # i ; i  \
         d   pRR\        T4      /3u Rp?# Rp?ii ; i)
z/system_statsrN   retriesTNFhttp_statusbodyNi  Nr1   )TN)r   rS   rN   r   json	Exceptiontextr   )r*   res   &  r"   check_serverComfyRunner.check_servers   s    		,?3T\\STUAxx3&>) =!((FAFFHTNKKK ! &%%&  	,7CF+++	,s@   8B A4 &B 4BB BB B+B& B+&B+
image_typeinput	overwriteTendpointz/upload/image
extra_formc               0    V ^8  d   QhRRRRRRRRRR	R
R/# )r   rQ   r   rc   r   re   boolrf   rg   zdict | Noner.   r/   r    )r!   s   "r"   r#   rE      s:     ' ' 'c 'PT '"'BM'Y]'r%   c                  VP                  4       '       g   \        RV 24      hVP                  R4      ;_uu_ 4       pRVP                  V3/pRV/pV'       d   RVR&   V'       d>   TP	                  VP                  4        U	U
u/ uF  w  rV	\        V
4      bK  	  up
p	4       \        RV P                  V4      V P                  WxR^R	7      pR
R
R
4       XP                  ^8w  d>   \        RRVP                   RVP                   2VP                  4       R,          R7      h VP                  4       # u up
p	i   + '       g   i     Lu; i  \         d    RTP                  /u # i ; i)zAUpload an image file via multipart. Returns server-side ref dict.zinput image not found: rbimagetypetruere   POST,  )rN   filesformtimeoutrX   Nupload_failedz
Upload of  failed: HTTP r[   )rZ   name)existsFileNotFoundErroropenrv   r2   itemsr   r   rS   rN   r   r   r^   r\   r]   )r*   rQ   rc   re   rf   rg   fhrq   rr   kvr_   s   &&$$$$      r"   upload_imageComfyRunner.upload_image   s7    {{}}#&=dV$DEEYYt__tyy"o.EJ'D$*[!:3C3C3EF3E41QAY3EFG		(+EQA  88s?"TYYK~ahhZ@VVXd^ 
	'668O G _(  	'DII&&	's5   )D<(D<D62D<&E 6D<<E	E+*E+c               $    V ^8  d   QhRRRRRR/# )r   rQ   r   original_refr/   r.   r    )r!   s   "r"   r#   rE      s!     
 
 
D 
T 
r%   c           
     Z    V P                  VRRRR\        P                  ! V4      /R7      # )zUpload an inpaint mask, linked to a previously uploaded source image.

`original_ref` should be the dict returned by `upload_image()` for the
source image (or `{"filename": ..., "subfolder": ..., "type": "input"}`).
z/upload/mask	subfolder	clipspacer   )rf   rg   )r~   r\   dumps)r*   rQ   r   s   &&&r"   upload_maskComfyRunner.upload_mask   s:       #[

< 8 ! 
 	
r%   c                    V ^8  d   QhRRRR/# r   workflowr/   r.   r    )r!   s   "r"   r#   rE      s      t  r%   c                	t   R VRV P                   /pV P                  '       d   RV P                  /VR&   \        V P                  R4      V P                  V^xR7      p VP                  4       pVP                  ^8w  d   RVP                  R	V/# V#   \         d    RTP                  4       R,          /p LIi ; i)
promptrC   api_key_comfy_org
extra_dataz/prompt)rN   	json_bodyrs   rawr[   _http_errorrZ   )	rC   rD   r   rS   rN   r\   r]   r^   r   )r*   r   payloadr_   rZ   s   &&   r"   submitComfyRunner.submit   s    #+X{DNN"S%8$:J:J$KGL!dii	*DLLG]`a	+668D 88s?!188VT::	  	+1668D>*D	+s   B $B76B7rs   g     r@initial_intervalg      ?max_intervalg       @c          
     ,    V ^8  d   QhRRRRRRRRRR/# )	r   	prompt_idr   rs   floatr   r   r.   r/   r    )r!   s   "r"   r#   rE      s9     7E 7ES 7Ee 7E&+7EAF7EQU7Er%   c               	z   \         P                   ! 4       pTp\         P                   ! 4       V,
          V8  Ed   V P                  '       d   \        V P                  R V R24      V P                  ^^R7      pVP
                  ^8X  dK    VP                  4       pVP                  R4      p	V	R8X  d   RRRV/# V	R9   d   RRRV/# V	R8X  d   RRRV/# MVP
                  R	8X  d   MM\        V P                  R
V 24      V P                  ^^R7      pVP
                  ^8X  d    VP                  4       ;'       g    / pVP                  V4      p
\        V
\        4      '       dh   V
P                  R4      ;'       g    / pVP                  R4      pVR8X  d   RRRV
/# VP                  RR4      '       d   RRRV
P                  R/ 4      /# \         P                  ! V4       \        WFR,          4      pEK  RRR\         P                   ! 4       V,
          /#   \         d    / p ELi ; i  \         d    / p Li ; i)z/job/z/status)rN   rX   rs   r   	completedsuccessdatar1   	cancelledi  	/history/
status_strFoutputsgffffff?rs   elapsed>   failed)timerI   r   rS   rN   r   r\   r]   get
isinstancer/   sleepmin)r*   r   rs   r   r   startintervalr_   r   sentrystr   s   &&$$$        r"   poll_statusComfyRunner.poll_status   s   		#iikE!G+}}}IIi[89 LL!R 88s?" vvx *AK' ()VTBBK' ('64@@K' (+vtDD ( XX_  II	)56 LL!R 88s?" vvx~~2 !HHY/E!%.."YYx066B%'VVL%9
%0$,gvu#EE66+u55$,iEIIiY[D\#]] JJx <C8H)Y		e0CDDS % "!"2 % "!"s*   
H #H* :H* H'&H'*H:9H:on_progressc               (    V ^8  d   QhRRRRRRRR/# )	r   r   r   rs   r   r   r   r.   r/   r    )r!   s   "r"   r#   rE      s0     `9 `9C `9U `9 #`9/3`9r%   c                   ^ RI p\	        T P
                  4      pTP                  R8X  d   RMRpTP                  pTP                  P                  R4      pT RT T R	T P                   2p	T P                  '       d)   T P                  '       d   T	R
T P                   2,          p	/ p
RpRpRpTP                  YR7      p TP                  T4       \        P                  ! 4       T,           p\        P                  ! 4       T8  Ed%   TP!                  4       p\#        T\$        4      '       d   KC   \&        P(                  ! T4      pTP-                  RR4      pTP-                  R/ 4      ;'       g    / pTP-                  R4      pTe
   TT8w  d   K  TR8X  dS   \/        T4      '       d@   T! RRRTP-                  R4      RTP-                  R4      RTP-                  R4      /4       K  K  TR8X  d4   \/        T4      '       d    T! RRRTP-                  R/ 4      /4       EK6  EK9  TR8X  dY   TP-                  R4      p\/        T4      '       d   T! RRRT/4       Tf$   T P                  '       g   T'       d   RpMEK  EK  EK  TR8X  dB   RpTP-                  R4      pTP-                  R4      ;'       g    / pT'       d	   TT
T&   EK  EK  TR8X  d4   \/        T4      '       d    T! RRRTP-                  RR4      /4       EK  EK  TR8X  d   RpMTR8X  d   TpMTR8X  g   EK8  RR/TCp  TP1                  4        Te   R R!RT/# T'       d   R R"R#T
/# R R$R%T/#   \         d!    \        R4       T P                  YR7      u # i ; i  \*         d     EK  i ; i  \*         d     Lli ; i   TP1                  4        i   \*         d     i i ; i; i)&zConnect to /ws and listen until execution_success / execution_error.

Falls back to HTTP polling if `websocket-client` is not installed.
Returns same shape as poll_status.
Nz<websocket-client not installed; falling back to HTTP pollingrs   httpswsswsrG   z://z/ws?clientId=z&token=Frm    r   r   progressvaluemaxnodeprogress_statenodes	executingTexecutedoutputnotificationr   execution_successexecution_errorexecution_interruptedinterruptedr   r1   r   r   rs   r   )	websocketImportErrorr   r   r   r@   schemenetlocrQ   rH   rC   rI   rA   create_connection
settimeoutr   recvr   bytesr\   loadsr]   r   callableclose)r*   r   rs   r   r   parsedr   r   	base_pathws_urlr   error_payloadr   seen_executedr   deadlinemsgr   mtypemdatapidr   nidouts   &&$$                    r"   
monitor_wsComfyRunner.monitor_ws   s   	@ $))$ --72KK&&s+	83vhykt~~>NO===T\\\~..F"$/3(((A=	MM'"yy{W,H))+(ggic5))"jjoG  FB/FB/552 ii,?si'7J&,,#"J#UYYw%7!599U#3"EIIf$5	%  - ..,,#V-=w		RY[]H^$_` -k) 99V,D,,#V[&$$GH|DMMMm"& ?LM| j($(M))F+C))H-33C'* n,,,#V^Y		RY[]H^$_` -11"G//$)M55%2D$BE$BM
 $gv}==iG<<)Y88o  	@NO##I#??	@< ! d  
 s   M A0N/ 3N 	*N/ 4C>N/ 3N/ ;=N/ 9
N/ AN/ 'N/ /N (NNNN/ NN/ N,+N,/O1OOOOOOc                    V ^8  d   QhRRRR/# )r   r   r   r.   r/   r    )r!   s   "r"   r#   rE   Y  s     . .S .T .r%   c                	$   V P                   '       Ed7   \        V P                  R V 24      V P                  ^R7      pVP                  ^8X  d6    VP                  4       ;'       g    / P                  R/ 4      ;'       g    / # \        V P                  RV 24      V P                  ^R7      pVP                  ^8X  d    VP                  4       ;'       g    / p\        V\        4      '       d)   W9   d#   W1,          P                  R/ 4      ;'       g    / # \        V\        4      '       d   RV9   d   VR,          ;'       g    / # / # \        V P                  RV 24      V P                  ^R7      pVP                  ^8w  d   / #  VP                  4       ;'       g    / pTP                  T4      ;'       g    / pTP                  R/ 4      ;'       g    / #   \         d     ELci ; i  \         d    / p EL!i ; i  \         d    / u # i ; i)z/jobs/rW   r   r   )
rI   r   rS   rN   r   r\   r   r]   r   r/   )r*   r   r_   rZ   r   s   &&   r"   get_outputsComfyRunner.get_outputsY  s   ===VI;#78$,,XYZAxx3FFHNN//	2>DD"D Yyk#:;T\\[\]Axx3668>>rD dD))i.??..y"=CCCdD))i4.?	?00b0ITYY9+67WXY88s?I	668>>rD #))ryyB'--2-/ !  ! D  	I	sN   G 'G G  G+ G+ G? G? G('G(+G<;G<?HHpreserve_subfolderFc               4    V ^8  d   QhRRRRRRRRRRR	RR
R/# )r   filenamer   r   	file_type
output_dirr   r   ri   re   r.   r    )r!   s   "r"   r#   rE   y  sF     1 11+.1;>11.21FJ1 
1r%   c               <   RVRVRV/pV P                  R4      R,           \        V4      ,           p. p	V'       d0   V'       d(   V	P                  R VP                  R4       4       4       V	P	                  V4       \        V.V	O5!  p
V
P                  4       '       d_   V'       gW   V
P                  V
P                  r^p V
P                  V R	V V 24      pVP                  4       '       g   Tp
MV^,          pK=  V
P                  P                  RRR
7       \        RWP                  R^RRV
R7      pVP                  ^8w  dF    V
P                  4       '       d   V
P                  4        \#        RRT RTP                   2TR7      hV
#   \          d     L-i ; i)z4Stream a single output to disk. Path-traversal-safe.r   r   rm   z/view?c              3  J   "   T F  q'       g   K  VR9  g   K  Vx  K  	  R# 5i).N>   r   ..r    ).0ps   & r"   	<genexpr>.ComfyRunner.download_output.<locals>.<genexpr>  s      ^+?a1R]I]+?s   	##
#rG   T_parentsexist_okGETiX  )rN   rs   rX   follow_redirectsstreamsinkdownload_failedzDownload of ru   )url)rS   r   extendsplitappendr   rw   stemsuffix	with_nameparentmkdirr   rN   r   unlinkr]   r   )r*   r   r   r   r   r   re   paramsr   target_partsout_pathr   r   i	candidater_   s   &$$$$$$         r"   download_outputComfyRunner.download_outputy  s   
 hY	Rii 3&6):: #%)^9??3+?^^H%!*<|<??Y#==(//&A$..$qF8/DE	 ''))(HQdT: 3Th

 88s???$$OO% #!xjqxxjA 
   s   F F FFc                    V ^8  d   QhRRRR/# )r   r   rB   r.   ri   r    )r!   s   "r"   r#   rE     s     	 	
 	d 	r%   c                	    V'       d;   \        V P                  R 4      V P                  RV./^R7      pVP                  ^8H  # \        V P                  R4      V P                  ^R7      pVP                  ^8H  # )z/queuedelete)rN   r   rX   z
/interruptrW   )r   rS   rN   r   )r*   r   r_   s   && r"   cancelComfyRunner.cancel  sf    		(#T\\#i[11A 88s?"dii-t||QOxx3r%   )rA   rC   r@   rI   rD   r'   )r6   r7   r8   r9   r   r)   propertyrN   rS   ra   r~   r   r   r   r   r   r	  r  r;   r    r%   r"   r>   r>   Z   s     '" $"&6  D
,'G 'W[ '%4'PT':
 7Ee 7E.17EIL7Et`9U `9&*`9F.@1591MR1h	 	r%   r>   c                    V ^8  d   QhRRRR/# r   r    )r!   s   "r"   r#   r#     s     $ $T $d $r%   c                    ^ RI H p V! V 4      # )z8Generate schema using the sibling extract_schema module.extract_schemar  )r   r  s   & r"   _inline_schemar    s    -(##r%   c               $    V ^8  d   QhRRRRRR/# )r   schema_pathrB   r   r/   r.   r    )r!   s   "r"   r#   r#     s!     $ $Z $4 $D $r%   c                    V '       d5   \        V 4      ;_uu_ 4       p\        P                  ! V4      uuR R R 4       # \        V4      #   + '       g   i     L; ir'   )ry   r\   loadr  )r  r   fs   && r"   load_schemar    s9    +!99Q< (## s   AA	randomize_seed_if_unsetFc          
     ,    V ^8  d   QhRRRRRRRRRR/# )	r   r   r/   schemaargsr  ri   r.   ztuple[dict, list[str]]r    )r!   s   "r"   r#   r#     s6     ) )) )(,) $) )r%   c          
     v   \         P                  ! V 4      pVP                  R/ 4      ;'       g    / p. pRV9   d   RV9   dK   VR,          R9   d=   \        V4      p\	        VR,          4      VR&   VP                  RVR,           24       MCV'       d<   RV9  d5   \        V4      p\	        R4      VR&   VP                  RVR,           24       VP                  4        F  w  rxWu9  d   VP                  RV R24       K"  WW,          p	V	R,          V	R	,          rVP                  V
4      p\        V\        4      '       d   R
V9  d   VP                  RV
 RV R24       K  VR
,          P                  V4      p\        V4      '       d   VP                  RV RV
 RV R24       K  WR
,          V&   K  	  WF3# )zEInject user args into the workflow. Returns (new_workflow, warnings).
parametersseedNzseed=-1 expanded to zseed auto-randomized to zunknown parameter 'z' (not in schema), skippingnode_idfieldinputsznode 'z' for parameter 'z' missing in workflowzparameter 'z
' targets r   zf which is currently a link; refusing to overwrite (set the schema to point at the source node instead)>   N-1)	copydeepcopyr   r/   r	   r   rz   r   r   )r   r  r  r  wfr  warningsrv   r   mr   r$  r   curs   &&&$          r"   inject_paramsr.    s   
 
x	 BZZb)//RFH T>d6l.>>:D&tF|4DLOO24<.AB$t);:D&t,DLOO6tF|nEFzz|OO1$7RSTLy\1W:Uvvc{$%%)=OOfSE):4&@UVW8n  '3<<OOdV:cU!E7 ;] ^  %Xu% $( <r%   r   Tre   c               0    V ^8  d   QhRRRRRRRRR	RR
R/# )r   runnerr>   r   r/   r   r   r   ri   re   r.   z
list[dict]r    )r!   s   "r"   r#   r#     s>     , ,,"&,48,,37, ,r%   c                  VP                  RRR7       . pRpT;'       g    / P                  4        EF  w  rx\        V\        4      '       g   K  V F  p	VP	                  V	4      p
V
'       g   K  \        V
\
        4      '       g   V
.p
V
 F  p\        V\        4      '       g   K  VP	                  R4      ;'       g    RpV'       g   K@  VP	                  R4      ;'       g    RpVP	                  R4      ;'       g    Rp V P                  WVW#VR7      pVP                  R	\        V4      R
VR\        V4      RVRVRV/4       K  	  K  	  EK  	  V#   \         d   p\        RT RT 24        Rp?K  Rp?ii ; i)z{Walk the outputs dict and download every file. Cloud uses `video` (singular);
local uses `videos` (plural). We accept both.Tr   r   r   r   rm   r   )r   r   r   r   r   re   filer#  source_typezWARN: failed to download : N)imagesgifsvideosvideoaudiorq   models3d)r  rz   r   r/   r   listr	  r   r   r   r]   r   )r0  r   r   r   re   
downloadedOUTPUT_KEYSr#  node_outputkeyentriesfir   r   r   r  r`   s   &&&$$            r"   download_outputsrC    sy    TD1JYK!(B 5 5 7+t,,C!ooc*Ggt,,")!"d++66*-33FF;/552	FF6N66h	E%55!))#-"+  6  H
 %%H!7 8 B"H#Y%y'    !8B  ! E3H:RsCDDEs   AEE<	 E7	7E<	c                    V ^8  d   QhRRRR/# )r   specr   r.   ztuple[str, Path]r    )r!   s   "r"   r#   r#   -  s     , , ,(8 ,r%   c                    RV 9   d>   V P                  R^4      w  rVP                  4       \        V4      P                  4       3# R\        V 4      P                  4       3# )z@Parse `name=path` (or `path` alone, defaulting to name='image').=rl   )r   stripr   
expanduser)rE  rv   rQ   s   &  r"   parse_input_image_argrJ  -  sQ    
d{ZZQ'
zz|T$Z22444DJ))+++r%   c                    V ^8  d   QhRRRR/# )r   argvzlist[str] | Noner.   intr    )r!   s   "r"   r#   r#   5  s     c c c3 cr%   c           
        \         P                  ! R \         P                  R7      pVP                  RRRR7       VP                  RRRR	7       VP                  R
RR7       VP                  R\        RR	7       VP                  RR\
         R2R7       VP                  RRR7       VP                  RRRR	7       VP                  R\        ^ RR7       VP                  RR. RR7       VP                  RRR R!7       VP                  R"RR#R!7       VP                  R$RR%R!7       VP                  R&RR'R!7       VP                  R(RR)R!7       VP                  R*RR+R!7       VP                  R,R-R7       VP                  R.RR/R!7       VP                  V 4      p\        VP                  4      P                  4       pVP                  4       '       g   \        R0R1VP                   2/4       ^#  VP                  4       ;_uu_ 4       p\        P                  ! V4      pR2R2R24       \!        X4      pTP(                  pTP+                  R44      '       d"    \        TR5,          4      P-                  4       p TP1                  4       '       d   \        P2                  ! T4      M/ p	\5        T	\6        4      '       g   \        R0R8/4       ^# \9        TP:                  4      p
TP<                  ;'       g    R2pTP>                  '       d   T
'       g   T'       d   Tp
\A        TPB                  YTPD                  R97      pTPG                  4       w  rT'       g)   \        R0R:TPB                   2R;TR<R=\
         R>2/4       ^# . pTPH                   FW  p \K        T4      w  pp TPO                  T4      pTPQ                  RC4      ;'       g    TPR                  pTT	9  g   KR  TT	T&   KY  	  \U        TPV                  T4      p\Y        TTYPZ                  RD7      w  ppTT,           pT F  p\]        RET 24       K  	  TP_                  T4      pRFT9   d*   \        R0RGRHTRF,          RITPQ                  RI4      /4       ^# \5        TPQ                  R04      \6        4      '       d*   \        R0RJR;TR0,          RKTPQ                  RK4      /4       ^# TPQ                  RL4      pT'       g   \        R0RMRNT/4       ^# TPQ                  RK4      ;'       g    / pT'       d   \        R0RJRKT/4       ^# TP`                  '       d   \        RORPRLTRQT/4       ^ # TPb                  pT^ 8:  d   \e        T4      '       d   RRMRSp\]        RTT RUT RV24       RW RX lp TPf                  '       d   TPi                  TTTRY7      pMTPk                  TTRZ7      p TRO,          Rb8X  d%   \        RORbRLTRcTPQ                  Rc4      R<Rd/4       ^# TRO,          R08X  d#   \        ROR0RLTR;TPQ                  Re4      /4       ^# TRO,          Rf8X  d   \        RORfRLT/4       ^# TPQ                  Rg4      pT'       g   TPq                  T4      pTPr                  '       d   \        RORhRLTRgTRQT/4       ^ # \u        TT\        TPv                  4      P                  4       TPx                  '       * TPz                  Ri7      p \        RORhRLTRgT RQT/4       ^ #   + '       g   i     EL; i  \"         d"   p\        R0\%        T4      /4        R2p?^# R2p?i\        P&                   d   p\        R0R3T 2/4        R2p?^# R2p?ii ; i  \.         d   p\        R0R6T 2/4        R2p?^# R2p?ii ; i  \        P&                   d   p\        R0R7T 2/4        R2p?^# R2p?ii ; i  \L         d    p\        R0R?T R@T 2/4        R2p? ^# R2p?ii ; i  \L         d    p\        R0RAT RBT 2/4        R2p? ^# R2p?ii ; i  \l         d_    \]        R[T R\24        TPo                  T4       M'  \L         d   p\]        R]T R^24        R2p?MR2p?ii ; i\        ROR_RLTR`Ra/4        ^# i ; i)jz0Run a ComfyUI workflow with parameter injection.)descriptionformatter_classz
--workflowTzPath to workflow API JSON file)requiredhelpz--argsz{}z4JSON parameters to inject (or `@/path/to/args.json`))defaultrR  z--schemaz/Path to schema JSON (auto-generated if omitted))rR  z--hostzComfyUI server URLz	--api-keyzAPI key for cloud (or set $z	 env var)z--partner-keyz~Partner-node API key (extra_data.api_key_comfy_org). Required for Flux Pro / Ideogram / etc. Defaults to --api-key if not set.z--output-dirz	./outputszDirectory to save outputsz	--timeoutz;Max seconds to wait (0=auto: 300 / 900 for video workflows))rm   rS  rR  z--input-imager   zUpload local image before running. Format: `name=path` or `path`. The `name` becomes the value injected into the matching schema parameter.)actionrS  rR  z--randomize-seed
store_truezHIf schema has a 'seed' parameter and --args didn't set one, randomize it)rT  rR  z--wszBUse WebSocket for real-time progress (requires `websocket-client`)z--no-downloadzSkip downloading outputsz--flat-outputzBDon't preserve server-side subfolder structure when saving outputsz--overwritez9Overwrite existing files instead of appending _1, _2, ...z--submit-onlyz+Submit and return prompt_id without waitingz--client-idz#Override generated client_id (UUID)z--use-partner-key-as-authzS(Compat) Use --partner-key value as cloud X-API-Key. Don't use unless you know why.r1   zWorkflow file not found: NzInvalid JSON in workflow file: @:   NNzCannot read args file: zInvalid --args JSON: z--args must be a JSON object)r@   rA   rD   rC   zCannot reach server at r   hintz@Check `comfy launch --background` is running for local, or set $z for cloud.zBad --input-image spec 'z': zUpload failed for r4  rv   )r  zWARN: r   zSubmission HTTP errorrY   rZ   zWorkflow validation failednode_errorsr   zNo prompt_id in submit responseresponser   	submittedr+  i  rp   zSubmitted: prompt_id=z, waiting (timeout=u   s)…c                    V ^8  d   QhRRRR/# )r   evtr/   r.   Noner    )r!   s   "r"   r#   main.<locals>.__annotate__  s     0 0$ 04 0r%   c           
         V P                  R 4      pVR8X  dD   \        RV P                  R4       RV P                  R4       RV P                  R4       24       R
# VR8X  d,   V P                  R4      pV'       d   \        R	V 24       R
# R
# R
# )rm   r   z  step r   rG   r   z	 on node r   r   z  executing node N)r   r   )r]  tr   s   &  r"   _on_progressmain.<locals>._on_progress  s    GGFO
?'#'''*+1SWWU^,<IcggfoEVWX+776?D'v./  r%   )rs   r   r   u   Interrupted — cancelling job u    on server…z  (cancel request failed: )r   notez-Ctrl+C received; sent cancellation to server.rs   r   zCRe-run with larger --timeout, or use --submit-only and check later.r   r   r   r   )r   re   )>argparseArgumentParserRawDescriptionHelpFormatteradd_argumentr   r   rM  
parse_argsr   r   rI  rw   r
   ry   r\   r  r   
ValueErrorr   JSONDecodeErrorr  
startswith	read_textOSErrorrH  r   r   r/   r   rA   rD   use_partner_key_as_authr>   r@   rC   ra   input_imagerJ  r]   r~   r   rv   r  r  r.  randomize_seedr   r   submit_onlyrs   r   r   r   r   KeyboardInterruptr  r   no_downloadrC  r   flat_outputre   )!rL  r   r  wf_pathr  workflow_rawr   r`   args_str	user_argsrA   rD   r0  okinfoupload_warningsrE  
param_namerQ   refuploaded_namer  inj_warningsr+  wsubmit_respr   rY  rs   rb  wait_resultr   r=  s!   &                                r"   mainr  5  s^   F <<	A NN<$5UNVNN8TN  PNN:$UNVNN8%7>RNSNN;5k])L  NNN?d  e NN>;=XNYNN;S!U  WNN?8Rd  e NN%lb  dNN6,\  ^NN?<>XNYNN?<\  ^NN=S  UNN?<E  GNN='LNMNN.|m  o <<D 4==!,,.G>>77GHI	\\^^q99Q<L "<0 yyH3	HRL)335H,4NN,<,<DJJx("	 i&&7:;< dll+G""**dK###G YY..F ""$HB.tyyk:t&-{4	
 	  "$O  	4T:J	%%d+C
 44499Y&$1Ij! !" h/F*&)=P=PHl -HfQCL  --)K#,;}5KOOF+
 	
 +//'*D111{7+;??=9
 	
 ,I7=z;WX//-066BK78-UV8[+y*hWX llG!|28<<##
	{*=gYeLM0777 ++IwT`+aK ,,Y,HK 8	)i{y1Y	
 	 8'8Wk9iY_I`ab8+8[+yAB ooi(G$$Y/iiw
H
 	 !doo.99;#///4>>J
 )Y:H	  o ^^  7CF#$ 7=aSABC  	w"9! =>?	
  73A3789J  	w":4&A3 GHI	
  	w"4TF"QC @AB	L  -i[FG	3MM)$ 	3,QCq122	3mC
 	
 s   0\
 [6\
  ]' 7^ ^ __0
&` 1` 6\		\
 
]$\11]$]$	]]$'^2^^_ %^;;_ _-_((_-0`;``b8a
	b
a.a)$b)a..bb__main__r'   )2r:   
__future__r   rf  r(  r\   sysr   pathlibr   typingr   urllib.parser   r   rQ   insertr   __file__resolver  _commonr   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r]   r   r>   r  r  r.  rC  rJ  r  r6   exitr    r%   r"   <module>r     s   -^ #    
    , 3tH~--/667 8    y \ \F$$)',)`,"&,:?,f,cL zHHTV r%   