
    PL
j'                        d Z ddlmZ ddlZddlmZ ddlmZ  ej        e	          Z
dZe G d d                      ZddZddZddZddZddddZdS )a  Shared logic for the /codex-runtime slash command.

Toggles `model.openai_runtime` between "auto" (= chat_completions, Hermes'
default) and "codex_app_server" (= hand turns to a codex subprocess).

Both CLI (cli.py) and gateway (gateway/run.py) call into this module so the
behavior stays identical across surfaces.

The actual runtime resolution happens in hermes_cli.runtime_provider's
_maybe_apply_codex_app_server_runtime() helper, which reads the persisted
config value. This module just persists the value and reports the change.
    )annotationsN)	dataclass)Optional)autocodex_app_serverc                  r    e Zd ZU dZded<   dZded<   dZded<   dZd	ed
<   dZded<   dZ	ded<   dZ
ded<   dS )CodexRuntimeStatuszResult of a /codex-runtime invocation. Callers render this however
    suits their surface (CLI uses Rich panels, gateway sends a text message).boolsuccessNOptional[str]	new_value	old_value strmessageFrequires_new_sessionTcodex_binary_okcodex_version)__name__
__module____qualname____doc____annotations__r   r   r   r   r   r        C/home/kuhnn/.hermes/hermes-agent/hermes_cli/codex_runtime_switch.pyr	   r	      s         Q Q MMM#I#####I####G!&&&&& O    #'M''''''r   r	   
arg_stringr   returntuple[Optional[str], list[str]]c                    | pd                                                                 }|sdg fS |dv rdg fS |dv rdg fS |t          v r|g fS dd|dgfS )	u   Parse the slash-command argument string. Returns (value, errors).

    No args         → return current state (value=None)
    'auto' / 'codex_app_server' / 'on' / 'off' → return that value
    anything else   → error
    r   N>   oncodexenabler   >   offhermesdefaultdisabler   zUnknown runtime z-. Use one of: auto, codex_app_server, on, off)striplowerVALID_RUNTIMES)r   raws     r   
parse_argsr,   (   s     
"
"
$
$
*
*
,
,C Rx
'''!2%%
555rz
nBwO3OOO  r   configdictc                6   t          | t                    sdS |                     d          pi }t          |t                    sdS t          |                    d          pd                                                                          }|t          v r|S dS )z}Read the current `model.openai_runtime` value from a config dict.
    Returns 'auto' for unset / empty / unrecognized values.r   modelopenai_runtimer   )
isinstancer.   getr   r(   r)   r*   )r-   	model_cfgvalues      r   get_current_runtimer6   >   s     fd## v

7##)rIi&& v	.//5266<<>>DDFFE6r   r   c                    |t           vrt          d|dt                      t          |           }t          |                     d          t
                    si | d<   || d         d<   |S )zMutate the config dict in place to persist the new runtime value.
    Returns the previous value for callers that want to report a delta.zinvalid runtime z; must be one of r0   r1   )r*   
ValueErrorr6   r2   r3   r.   )r-   r   olds      r   set_runtimer:   L   s~     &&MyMM^MM
 
 	
 f
%
%Cfjj))400 w(1F7O$%Jr   tuple[bool, Optional[str]]c                 `    	 ddl m}   |             S # t          $ r}dd| fcY d}~S d}~ww xY w)zqBest-effort verification that codex CLI is installed at acceptable
    version. Returns (ok, version_or_message).r   )check_codex_binaryFzcodex check failed: N)!agent.transports.codex_app_serverr=   	Exception)r=   excs     r   check_codex_binary_okrA   Z   sj    3HHHHHH!!### 3 3 32S2222222223s    
-(--)persist_callbackr   c                  t          |           }dd.fd}|: |            \  }}d| d|rd|z   nd|pd	z    }t          d
|||||r|nd          S ||k    rt          d
||d|           S |dk    r* |            \  }}|st          dd|d|pd ddd          S t          | |           |T	  ||            nG# t          $ r:}	t                              d           t          d||d|	           cY d}	~	S d}	~	ww xY wd| d| g}
|dk    r |            \  }}|r|
                    d|            	 ddlm}  ||           }d |j	        D             }|r;|
                    dt          |           dd                    |                      |j        rF|
                    dt          |j                   dd                    |j                              n$|j        r|
                    d|j                    |j        r|
                    d|j         d            d!|j	        v r*|
                    d"           |
                    d#           |
                    d$|j         d%           |j        D ]}|
                    d&|            n/# t          $ r"}	|
                    d'|	            Y d}	~	nd}	~	ww xY w|
                    d(           |
                    d)           n*|
                    d*           |
                    d+           t          d
||d,                    |
          d
-          S )/a  Top-level entry point used by both CLI and gateway handlers.

    Args:
        config: in-memory config dict (will be mutated when new_value is set)
        new_value: desired runtime; None means "show current state only"
        persist_callback: optional callable taking the mutated config dict
            and persisting it to disk. Skipped when None (used by tests).

    Returns: CodexRuntimeStatus describing the outcome.
    Nr   r;   c                 (     t                        S )N)rA   )_binary_checks   r   _check_binary_cachedz#apply.<locals>._check_binary_cached}   s     133Mr   zopenai_runtime: z
codex CLI: zOK u   not available — z%install with `npm i -g @openai/codex`T)r   r   r   r   r   r   zopenai_runtime already set to )r   r   r   r   r   Fz(Cannot enable codex_app_server runtime: zcodex CLI not availablez%
Install with: npm i -g @openai/codexz'failed to persist openai_runtime changez-updated config in memory but persist failed: u    → zcodex CLI: r   )migratec                    g | ]
}|d k    |S )hermes-toolsr   ).0ss     r   
<listcomp>zapply.<locals>.<listcomp>   s)       !~2E2E2E2E2Er   z	Migrated z MCP server(s): z, z native Codex plugin(s): z Codex plugin discovery skipped: zDefault sandbox: z$ (no approval prompt on every write)rI   zHermes tool callback registered: codex can now use web_search, web_extract, browser_*, vision_analyze, image_generate, skill_view, skills_list, text_to_speech, kanban_* (worker + orchestrator) via MCP.u|     (delegate_task, memory, session_search, todo run only on the default Hermes runtime — they need the agent loop context.)z  (config: )u   ⚠ MCP migration: u   ⚠ MCP migration skipped: zOpenAI/Codex turns now run through `codex app-server` (terminal/file ops/patching inside Codex; Hermes tools available via MCP callback).ud   Effective on next session — current cached agent keeps the prior runtime to preserve prompt cache.z7OpenAI/Codex turns will use the default Hermes runtime.zEffective on next session.
)r   r   r   r   r   r   r;   )r6   r	   r:   r?   logger	exceptionappend)hermes_cli.codex_runtime_plugin_migrationrG   migratedlenjoinmigrated_pluginsplugin_query_errorwrote_permissions_defaulttarget_patherrors)r-   r   rB   currentrF   okvermsg
ver_or_msgr@   	msg_linesrG   
mig_reportuser_serverserrrE   s                  @r   applyre   e   s     "&))G ;?M      &&((C{w { {)+x%#++1EIwPw1x{ { 	 "!#-##
 
 
 	
 G!>W>>	
 
 
 	
 &&&--//J 	%!;!>%>; ; ; !&"    	"""#		V$$$$ 	 	 	FGGG%#!MMM	        	 	574444I &&&&&((C 	20300111/	BIIIIII J %.  L    1L 1 1 1 1yy..1 1  
 * 	  QJ$? @ @ Q Q(,		*2M(N(NQ Q    .   7!47 7   3   ;
(L ; ; ;   !444  @     +  
 D:+ADDDEEE!( > >  !<s!<!<====> 	B 	B 	B@3@@AAAAAAAA	B8	
 	
 	

 	:	
 	
 	
 	

 	RSSS5666		)$$!   s7   4C   
D
/C?9D?D?E(J( (
K2KK)r   r   r   r   )r-   r.   r   r   )r-   r.   r   r   r   r   rO   )r-   r.   r   r   r   r	   )r   
__future__r   loggingdataclassesr   typingr   	getLoggerr   rP   r*   r	   r,   r6   r:   rA   re   r   r   r   <module>rk      s"    # " " " " "  ! ! ! ! ! !      		8	$	$ . 
( 
( 
( 
( 
( 
( 
( 
(   ,      3 3 3 3 	e e e e e e e er   