
    i64                        d Z ddlmZ ddlZddlmZmZmZmZ d%d	Z	d&dZ
d'dZd(dZd)dZd*dZd+dZd,dZd+dZd-dZd+dZd+dZd.d#Zd+d$ZdS )/ug  
hermes fallback — manage the fallback provider chain.

Fallback providers are tried in order when the primary model fails with
rate-limit, overload, or connection errors. See:
https://hermes-agent.nousresearch.com/docs/user-guide/features/fallback-providers

Subcommands:
  hermes fallback [list]   Show the current fallback chain (default when no subcommand)
  hermes fallback add      Pick provider + model via the same picker as `hermes model`,
                           then append the selection to the chain
  hermes fallback remove   Pick an entry to delete from the chain
  hermes fallback clear    Remove all fallback entries

Storage: ``fallback_providers`` in ``~/.hermes/config.yaml`` (top-level, list of
``{provider, model, base_url?, api_mode?}`` dicts).  The legacy single-dict
``fallback_model`` format is migrated to the new list format on first add.
    )annotationsN)AnyDictListOptionalconfigDict[str, Any]returnList[Dict[str, Any]]c                   |                      d          pg }t          |t                    rd |D             }|r|S |                      d          }t          |t                    r:|                     d          r%|                     d          rt          |          gS t          |t                    rd |D             S g S )u  Return the normalized fallback chain as a list of dicts.

    Accepts both the new list format (``fallback_providers``) and the legacy
    single-dict format (``fallback_model``).  The returned list is always a
    fresh copy — callers can mutate without touching the config dict.
    fallback_providersc                    g | ]P}t          |t                    |                    d           ,|                    d          At          |          QS providermodel
isinstancedictget.0es     </home/ubuntu/.hermes/hermes-agent/hermes_cli/fallback_cmd.py
<listcomp>z_read_chain.<locals>.<listcomp>&   sS    iiiaJq$,?,?iAEE*DUDUiZ[Z_Z_`gZhZhi$q''iii    fallback_modelr   r   c                    g | ]P}t          |t                    |                    d           ,|                    d          At          |          QS r   r   r   s     r   r   z_read_chain.<locals>.<listcomp>-   sS    hhhA:a+>+>h155CTCThYZY^Y^_fYgYghQhhhr   )r   r   listr   )r   chainresultlegacys       r   _read_chainr"      s     JJ+,,2E% ii5iii 	MZZ())F&$ FJJz$:$: vzz'?R?R V~&$ ihhhhhhIr   r   Nonec                H    || d<   d| v r|                      dd           dS dS )zAPersist the chain to ``fallback_providers`` and clear legacy key.r   r   N)pop)r   r   s     r   _write_chainr&   1   s;    #(F 6!!

#T***** "!r   entrystrc                    |                      dd          }|                      dd          }|                      d          }|rd| dnd}| d| d	| S )
z6One-line human-readable rendering of a fallback entry.r   ?r   base_urlz  []   (via ))r   )r'   r   r   basesuffixs        r   _format_entryr2   9   sk    yyS))HIIgs##E99Z  D"*]4]]]]F//H//v///r   	model_cfgr   Optional[Dict[str, Any]]c                   t          | t                    sdS |                     d          pd                                }|                     d          p|                     d          pd                                }|r|sdS ||d}|                     d          pd                                }|r||d<   |                     d          pd                                }|r||d<   |S )	z^Pull the ``{provider, model, base_url?, api_mode?}`` dict from a ``config["model"]`` snapshot.Nr   r-   defaultr   r   r+   api_mode)r   r   r   strip)r3   r   r   r'   r+   r7   s         r    _extract_fallback_from_model_cfgr9   B   s    i&& tj))/R6688H]]9%%Ew)?)?E2LLNNE 5 t)1EBBEj))/R6688H %$jj))/R6688H %$jLr   c                 p    	 ddl m}   |             }|                    d          S # t          $ r Y dS w xY w)zRReturn the current ``active_provider`` in auth.json, or a sentinel if unavailable.r   )_load_auth_storeactive_providerN)hermes_cli.authr;   r   	Exception)r;   stores     r   _snapshot_auth_active_providerr@   U   s\    444444  ""yy*+++   tts   $' 
55valuec                    	 ddl m}m}m}  |            5   |            }| |d<    ||           ddd           dS # 1 swxY w Y   dS # t          $ r Y dS w xY w)z>Write back a previously snapshotted ``active_provider`` value.r   )_auth_store_lockr;   _save_auth_storer<   N)r=   rC   r;   rD   r>   )rA   rC   r;   rD   r?   s        r   _restore_auth_active_providerrE   _   s    
XXXXXXXXXX 	$ 	$$$&&E',E#$U###	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$     		s1   A >A AA AA 
AAc           	        ddl m}  |            }t          |          }t                       |s<t          d           t                       t          d           t                       dS t	          |          }|r t          d|            t                       t          dt          |           dt          |          d	k    rd
nd d           t          |d	          D ]'\  }}t          d| dt          |                      (t                       t          d           t          d           t                       dS )z!Print the current fallback chain.r   )load_configz#  No fallback providers configured.z$  Add one with:  hermes fallback addNz  Primary:   z  Fallback chain (    r'   entries):    . zM  Tried in order when the primary fails (rate-limit, 5xx, connection errors).zY  Docs: https://hermes-agent.nousresearch.com/docs/user-guide/features/fallback-providers)hermes_cli.configrG   r"   print_describe_primarylen	enumerater2   )argsrG   r   r   primaryir'   s          r   cmd_fallback_listrV   r   s\   ------[]]FE	GGG 34444555''G 'g''(((	
Ys5zz
Y
Ys5zzQGGI
Y
Y
YZZZeQ'' 2 250Q00-..001111	GGG	
YZZZ	
efff	GGGGGr   Optional[str]c                   |                      d          }t          |t                    rs|                     d          pd                                pd}|                     d          p|                     d          pd                                pd}| d| dS t          |t                    r(|                                r|                                S dS )z?One-line description of the primary model for display purposes.r   r   r*   r6   r.   r/   N)r   r   r   r8   r(   )r   r3   r   r   s       r   rP   rP      s    

7##I)T"" ,MM*--4;;==Dy))JY]]7-C-CJsQQSSZWZ++++++)S!! !ioo&7&7 !   4r   c                \   ddl m}m} ddlm}m}  |d            |            }t          j        |                    d                    }t                      }t                       t          d           t          d           t                       	  ||            n-# t          $ r  t          |           t          |            w xY w |            }|                    d          }	t          |	          }
|
s=t          |           t          |           t                       t          d	           d
S t          |          }|r|d         |
d         k    ro|d         |
d         k    r]t          |           t          |           t                       t          dt          |
           d           t          d           d
S t          |           t          |            |            }t!          |          }|D ]q}|                    d          |
d         k    rP|                    d          |
d         k    r1t                       t          dt          |
           d            d
S r|                    |
           t%          ||            ||           t                       t          dt          |
                      t          dt'          |           dt'          |          dk    rdnd d           t                       t          d           d
S )zQLaunch the same picker as `hermes model`, then append the selection to the chain.r   )_require_ttyselect_provider_and_modelrG   save_configzfallback addr   zG  Adding a fallback provider.  The picker below is the same one used byuH     `hermes model` — select the provider + model you want as a fallback.)rS   z  No fallback added.Nr   z.  Selected model matches the current primary (z).u;     A provider cannot be a fallback for itself — no change.  u.    is already in the fallback chain — skipped.z  Added fallback:   Chain is now rH   rI   r'   rJ    long.zL  Run `hermes fallback list` to view, or `hermes fallback remove` to delete.)hermes_cli.mainrZ   r[   rN   rG   r]   copydeepcopyr   r@   rO   
SystemExit_restore_model_cfgrE   r9   r2   r"   appendr&   rQ   )rS   rZ   r[   rG   r]   
before_cfgmodel_beforeactive_provider_before	after_cfgmodel_after	new_entryprimary_entry	final_cfgr   existings                  r   cmd_fallback_addrp      sk   GGGGGGGG::::::::L    J=!8!899L;==	GGG	
STTT	
TUUU	GGG!!t,,,,,   <(((%&<===	 I--((K0==I <(((%&<===$%%% 5\BBM z2i
6KKKg&)G*<<<<(((%&<===[}Y?W?W[[[\\\KLLL |$$$!"8999I	""E   <<
##y'<<<LL))Yw-???GGG_}Y//___```FF	LLE"""K		GGG	
9}Y77
9
9:::	
ZCJJ
Z
ZCJJ!OO
Z
Z
Z[[[	GGG	
XYYYYYs   B# #*Crh   c                    ddl m}m}  |            }| |                    dd           nt	          j        |           |d<    ||           dS )z>Restore ``config["model"]`` to a previously-captured snapshot.r   r\   Nr   )rN   rG   r]   r%   rb   rc   )rh   rG   r]   cfgs       r   re   re      sk    ::::::::
+--C}\22GKr   c                0   ddl m}m}  |            }t          |          }|s-t	                       t	          d           t	                       dS d |D             }|                    d           	 ddlm}  |d|d          }n # t          $ r t          d|          }Y nw xY w||dk     s|t          |          k    rt	                       t	          d	           dS |                    |          }t          ||            ||           t	                       t	          d
t          |                      |r9t	          dt          |           dt          |          dk    rdnd d           nt	          d           t	                       dS )z+Pick an entry from the chain and remove it.r   r\   u9     No fallback providers configured — nothing to remove.Nc                ,    g | ]}t          |          S  )r2   r   s     r   r   z'cmd_fallback_remove.<locals>.<listcomp>  s     ///A}Q///r   Cancel)_curses_prompt_choicezSelect a fallback to remove:     Cancelled — no change.z  Removed fallback: r_   rH   rI   r'   rJ   r`   z  Fallback chain is now empty.)rN   rG   r]   r"   rO   rf   hermes_cli.setuprw   r>   _numbered_pickrQ   r%   r&   r2   )	rS   rG   r]   r   r   choicesrw   idxremoveds	            r   cmd_fallback_remover~      s   ::::::::[]]FE IJJJ/////GNN8F::::::##$BGQOO F F F;WEEF {cAggE

!2!2*+++iinnGK	GGG	
9w!7!7
9
9::: 0^E

^^E

aWWY^^^____.///	GGGGGs   3B B$#B$c           	     H   ddl m}m}  |            }t          |          }|s-t	                       t	          d           t	                       dS t	                       t	          dt          |           dt          |          dk    rdnd	 d
           t          |d          D ]'\  }}t	          d| dt          |                      (t	                       	 t          d          	                                
                                }n5# t          t          f$ r! t	                       t	          d           Y dS w xY w|dvrt	          d           dS t          |g             ||           t	                       t	          d           t	                       dS )z0Remove all fallback entries (with confirmation).r   r\   u8     No fallback providers configured — nothing to clear.Nz  Current fallback chain (rH   rI   r'   rJ   rK   rL   rM   z  Clear all entries? [y/N]: z  Cancelled.)yyesrx   z  Fallback chain cleared.)rN   rG   r]   r"   rO   rQ   rR   r2   inputr8   lowerKeyboardInterruptEOFErrorr&   )rS   rG   r]   r   r   rU   r'   resps           r   cmd_fallback_clearr     s   ::::::::[]]FE HIII	GGG	
as5zz
a
as5zzQGGT]
a
a
abbbeQ'' 2 250Q00-..001111	GGG344::<<BBDDx(   n <*+++K	GGG	
%&&&	GGGGGs   3D .EEquestionr{   	List[str]Optional[int]c                &   t          |            t          |d          D ]\  }}t          d| d|            t                       	 	 t          dt          |           d                                          }|sdS t          |          dz
  }d|cxk    rt          |          k     rn n|S t          d	t          |                      n@# t          $ r t          d
           Y n%t          t          f$ r t                       Y dS w xY w)z9Fallback numbered-list picker when curses is unavailable.rI   r^   rM   Tz
Choice [1-z]: Nr   zPlease enter 1-zPlease enter a number)	rO   rR   r   rQ   r8   int
ValueErrorr   r   )r   r{   rU   cvalr|   s         r   rz   rz   A  sJ   	(OOO'1%%  1m1mmmm	GGG	6S\\66677==??C tc((Q,CC&&&&#g,,&&&&&
2CLL223333 	+ 	+ 	+)*****!8, 	 	 	GGG44	s$   4C 0C 2C D-DDc                4   t          | dd          }|dv rt          |            dS |dk    rt          |            dS |dv rt          |            dS |dk    rt	          |            dS t          d|            t          d           t          d	          )
z:Top-level dispatcher for ``hermes fallback [subcommand]``.fallback_commandN)Nr-   r   lsadd)removermclearzUnknown fallback subcommand: z$Use one of: list, add, remove, clear   )getattrrV   rp   r~   r   rO   rd   )rS   subs     r   cmd_fallbackr   [  s    
$*D
1
1C
&&&$		 	 	 D!!!!!	4     3c334444555mmr   )r   r	   r
   r   )r   r	   r   r   r
   r#   )r'   r	   r
   r(   )r3   r   r
   r4   )r
   r   )rA   r   r
   r#   )r
   r#   )r   r	   r
   rW   )rh   r   r
   r#   )r   r(   r{   r   r
   r   )__doc__
__future__r   rb   typingr   r   r   r   r"   r&   r2   r9   r@   rE   rV   rP   rp   re   r~   r   rz   r   ru   r   r   <module>r      s}   $ # " " " " "  , , , , , , , , , , , ,   (+ + + +0 0 0 0   &      &   8	 	 	 	MZ MZ MZ MZ`	 	 	 	% % % %P       F   4     r   