
    i             	          d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlmZ ddlmZ ddlmZ ddlmZmZmZmZ ddZ e             ej                            d e ee          j        j                             dd	lmZ dd
lmZm Z   e            Z!ddl"m#Z# ddl$m%Z% e!dz  Z& e%e! ee          '                                j(        d         dz             e!dz  Z)e)*                                r	 ddl+Z, e-e)d          5 Z. e,j/        e.          pi Z0ddd           n# 1 swxY w Y   ddl1m2Z2  e2e0          Z0e03                                D ]1\  Z4Z5 e6e5ee7e8e9f          re4ej:        vr ee5          ej:        e4<   2e0;                    di           Z<e<r e6e<e=          ri dddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:Z>e>3                                D ]]\  Z?Z@e?e<v rTe<e?         Z5e?dk    r ee5          d;v r% e6e5eA          r ejB        e5          ej:        e@<   J ee5          ej:        e@<   ^e0;                    d<i           ZCeCrs e6eCe=          rfd=d>d?d@dAdBdCdDdEdAdFdGdHdIdAdJZDeD3                                D ];\  ZEZFeC;                    eEi           ZG e6eGe=          s) eeG;                    dKdL                    H                                ZI eeG;                    dMdL                    H                                ZJ eeG;                    dNdL                    H                                ZK eeG;                    dOdL                    H                                ZLeIreIdPk    reIej:        eFdK         <   eJreJej:        eFdM         <   eKreKej:        eFdN         <   eLreLej:        eFdO         <   =e0;                    dQi           ZMeMr e6eMe=          rdReMv r eeMdR                   ej:        dS<   dTeMv r"dUej:        vr eeMdT                   ej:        dU<   dVeMv r"dWej:        vr eeMdV                   ej:        dW<   dXeMv r"dYej:        vr eeMdX                   ej:        dY<   dZeMv r"d[ej:        vr eeMdZ                   ej:        d[<   e0;                    d\i           ZNeNr2 e6eNe=          r&d]eNv r"d^ej:        vr eeNd]                   ej:        d^<   e0;                    d_dL          ZOeOr1 e6eOe          r%d`ej:        vreOH                                ej:        d`<   e0;                    dai           ZP e6ePe=          r<eP;                    db          ZQeQ% eeQ          R                                ej:        dc<   n# eS$ r Y nw xY w	 dddlmTZT de eU            v re0ni ;                    dfi           ZV e6eVe=          r!eV;                    dg          r eTdhi           n# eS$ r Y nw xY w	 ddjl1mWZW  eW             n# eS$ r Y nw xY w	 ddkl1mXZX  eX             n# eS$ r Y nw xY wdlej:        dm<   dlej:        dn<   ej:        ;                    ddL          ZYeYreYd;v r2 ejZ        do          p e ej[                              Z\e\ej:        d<   ddpl]m^Z^m_Z_m`Z` ddqlambZbmcZcmdZdmeZemfZfmgZg ddrlhmiZi ddsljmkZkmlZlmmZmmnZn ddtlompZpmqZqmrZr duedefdvZsdwedetfdxZu ejv        ew          Zx ey            Zzde=fdyZ{defdzZ|d{edeldz  fd|Z}d}ededz  fd~Z~dddefdZde=fdZdde=dz  defdZdeeAe                  fdZd{eddfdZde=ddfdZ G d d          Zdde
j        de7fdZddee_         de9dee7         de9fdZd Zewdk    r e             dS dS )a<  
Gateway runner - entry point for messaging platform integrations.

This module provides:
- start_gateway(): Start all configured platform adapters
- GatewayRunner: Main class managing the gateway lifecycle

Usage:
    # Start the gateway
    python -m gateway.run
    
    # Or from CLI
    python cli.py --gateway
    N)copy_contextPathdatetime)DictOptionalAnyListreturnc                     dt           j        v rdS ddl} |                                 }|j        |j        fD ]5}|r1t           j                            |          r|t           j        d<    dS 6	 ddl}|	                                t           j        d<   dS # t          $ r Y nw xY wdD ]3}t           j                            |          r|t           j        d<    dS 4dS )zBSet SSL_CERT_FILE if the system doesn't expose CA certs to Python.SSL_CERT_FILENr   )z"/etc/ssl/certs/ca-certificates.crtz /etc/pki/tls/certs/ca-bundle.crtz1/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pemz/etc/ssl/ca-bundle.pemz/etc/ssl/cert.pemz/etc/pki/tls/cert.pemz#/usr/local/etc/openssl@1.1/cert.pemz&/opt/homebrew/etc/openssl@1.1/cert.pem)osenvironsslget_default_verify_pathscafileopenssl_cafilepathexistscertifiwhereImportError)r   paths	candidater   s       3/home/agentuser/.hermes/hermes-agent/gateway/run.py_ensure_ssl_certsr   $   s   "*$$JJJ ((**ElE$89  	 		22 	*3BJ'FF&-mmoo
?#   	  	 7>>)$$ 	*3BJ'FF	 s   .%B 
B"!B")get_hermes_home)atomic_yaml_writeis_truthy_value)load_dotenv)load_hermes_dotenvz.env   )hermes_homeproject_envconfig.yamlutf-8encoding)_expand_env_varsterminalbackendTERMINAL_ENVcwdTERMINAL_CWDtimeoutTERMINAL_TIMEOUTlifetime_secondsTERMINAL_LIFETIME_SECONDSdocker_imageTERMINAL_DOCKER_IMAGEdocker_forward_envTERMINAL_DOCKER_FORWARD_ENVsingularity_imageTERMINAL_SINGULARITY_IMAGEmodal_imageTERMINAL_MODAL_IMAGEdaytona_imageTERMINAL_DAYTONA_IMAGEssh_hostTERMINAL_SSH_HOSTssh_userTERMINAL_SSH_USERssh_portTERMINAL_SSH_PORTssh_keyTERMINAL_SSH_KEYcontainer_cpuTERMINAL_CONTAINER_CPUcontainer_memoryTERMINAL_CONTAINER_MEMORYcontainer_diskTERMINAL_CONTAINER_DISKcontainer_persistentTERMINAL_CONTAINER_PERSISTENTTERMINAL_DOCKER_VOLUMESTERMINAL_SANDBOX_DIRTERMINAL_PERSISTENT_SHELL)docker_volumessandbox_dirpersistent_shell).autor.   	auxiliaryAUXILIARY_VISION_PROVIDERAUXILIARY_VISION_MODELAUXILIARY_VISION_BASE_URLAUXILIARY_VISION_API_KEY)providermodelbase_urlapi_keyAUXILIARY_WEB_EXTRACT_PROVIDERAUXILIARY_WEB_EXTRACT_MODELAUXILIARY_WEB_EXTRACT_BASE_URLAUXILIARY_WEB_EXTRACT_API_KEYAUXILIARY_APPROVAL_PROVIDERAUXILIARY_APPROVAL_MODELAUXILIARY_APPROVAL_BASE_URLAUXILIARY_APPROVAL_API_KEY)visionweb_extractapprovalr[    r\   r]   r^   rU   agent	max_turnsHERMES_MAX_ITERATIONSgateway_timeoutHERMES_AGENT_TIMEOUTgateway_timeout_warningHERMES_AGENT_TIMEOUT_WARNINGgateway_notify_intervalHERMES_AGENT_NOTIFY_INTERVALrestart_drain_timeoutHERMES_RESTART_DRAIN_TIMEOUTdisplaybusy_input_modeHERMES_GATEWAY_BUSY_INPUT_MODEtimezoneHERMES_TIMEZONEsecurityredact_secretsHERMES_REDACT_SECRETS)apply_ipv4_preference_cfgnetwork
force_ipv4Tforce)print_config_warnings)warn_deprecated_cwd_env_vars1HERMES_QUIETHERMES_EXEC_ASKMESSAGING_CWD)PlatformGatewayConfigload_gateway_config)SessionStoreSessionSourceSessionContextbuild_session_contextbuild_session_context_promptbuild_session_key)DeliveryRouter)BasePlatformAdapterMessageEventMessageTypemerge_pending_message_event)%DEFAULT_GATEWAY_RESTART_DRAIN_TIMEOUT!GATEWAY_SERVICE_RESTART_EXIT_CODEparse_restart_drain_timeoutvaluec                     t          | pd                                                              ddd                              dd          d                             dd          d         S )zDStrip WhatsApp JID/LID syntax down to its stable numeric identifier.rj   +r#   :r   @)strstripreplacesplitr   s    r   _normalize_whatsapp_identifierr     s\     	EKR		b!			sAq	 
sAq		    
identifierc                    t          |           }|st                      S t          dz  dz  }t                      }|g}|r|                    d          }|r||v r|                    |           dD ]}|d| | dz  }|                                s"	 t          t          j        |                    d                              }n# t          $ r Y ew xY w|r||vr|
                    |           ||S )	zFResolve WhatsApp phone/LID aliases using bridge session mapping files.whatsappsessionr   )rj   _reversezlid-mapping-.jsonr'   r(   )r   set_hermes_homepopaddr   jsonloads	read_text	Exceptionappend)	r   
normalizedsession_dirresolvedqueuecurrentsuffixmapping_pathmappeds	            r   _expand_whatsapp_auth_aliasesr   '  sJ   /
;;J uu+i7KuuHLE
 %))A,, 	'X--W& 	% 	%F&)N)N)N)N)NNL&&(( 7J|55w5GGHH      %&00V$$$#  %& Os   5C
CCc            
         ddl m} m} 	  | t          j        d                    }n+# t
          $ r}t           ||                    |d}~ww xY w|                    d          |                    d          |                    d          |                    d	          |                    d
          t          |                    d          pg           |                    d          dS )zCResolve provider credentials for gateway-created AIAgent instances.r   )resolve_runtime_providerformat_runtime_provider_errorHERMES_INFERENCE_PROVIDER)	requestedNr^   r]   r[   api_modecommandargscredential_pool)r^   r]   r[   r   r   r   r   )	hermes_cli.runtime_providerr   r   r   getenvr   RuntimeErrorgetlist)r   r   runtimeexcs       r   _resolve_runtime_agent_kwargsr   O  s           
H**i ;<<
 
 
  H H H88==>>CGH ;;y))KK
++KK
++KK
++;;y))W[[((.B//";;'899  s   ) 
AAAc                    g }t          | dd          pg }t          | dd          pg }t          |          D ]\  }}|t          |          k     r||         nd}|                    d          st          | dd          t          j        k    r|                    d| d           p|                    d	          r|                    d
| d           |                    d| d           d                    |          S )ag  Build a text placeholder for media-only events so they aren't dropped.

    When a photo/document is queued during active processing and later
    dequeued, only .text is extracted.  If the event has no caption,
    the media would be silently lost.  This builds a placeholder that
    the vision enrichment pipeline will replace with a real description.
    
media_urlsNmedia_typesrj   image/message_typez[User sent an image: ]audio/z[User sent audio: z[User sent a file: 
)getattr	enumeratelen
startswithr   PHOTOr   join)eventpartsr   r   iurlmtypes          r   _build_media_placeholderr   h  s*    Ed339rJ%55;KJ'' 7 73"#c+&6&6"6"6ABH%% 	7)M)MQ\Qb)b)bLL77778888h'' 	7LL4c4445555LL5s555666699Ur   session_keyc                 ,    |                      |          S )zConsume and return the full pending event for a session.

    Queued follow-ups must preserve their media metadata so they can re-enter
    the normal image/STT/document preprocessing path instead of being reduced
    to a placeholder string.
    )get_pending_message)adapterr   s     r   _dequeue_pending_eventr   ~  s     &&{333r   command_namec                    |                                                      dd          }	 ddlm} ddlm}  |            } |            D ]}|                                s|                    d          D ]g}t          d |j	        D                       r!|j
        j                                                             dd          }||k    r||v r
d|  d	c c S hdd
lm} t          t                                                    j
        j
        }	 ||	dz            }
|
                                r|
                    d          D ]}|j
        j                                                             dd          }||k    rQ|j
                            |
          }t%          |j	                  }dd                    |           }d|  d| dc S n# t(          $ r Y nw xY wdS )zCheck if a command matches a known-but-inactive skill.

    Returns a helpful message if the skill exists but is disabled or only
    available as an optional install. Returns None if no match found.
    _-r   )_get_disabled_skill_names)get_all_skills_dirszSKILL.mdc              3      K   | ]}|d v V  	dS )).gitz.githubz.hubN .0parts     r   	<genexpr>z+_check_unavailable_skill.<locals>.<genexpr>  s(      VVtt::VVVVVVr   The **zJ** skill is installed but disabled.
Enable it with: `hermes skills config`)get_optional_skills_dirzoptional-skillsz	official//zQ** skill is available but not installed.
Install it with: `hermes skills install `N)lowerr   tools.skills_toolr   agent.skill_utilsr   r   rglobanyr   parentnamehermes_constantsr   r   __file__resolverelative_tor   r   r   )r   r   r   r   disabled
skills_dirskill_mdr   r   	repo_rootoptional_dirrelr   install_paths                 r   _check_unavailable_skillr    s    ##%%--c377J$??????999999,,.. .-// 	 	J$$&& &,,Z88  VVx~VVVVV +1133;;CEE:%%$(*:*:B B B B     	=<<<<<NN**,,3:	..y;L/LMM   	(..z:: 
 
+1133;;CEE:%%"/55lCCC OOE#@sxx#@#@LS S SCOS S S   &    4s   B2G C9G G 
G&%G&platformr   c                 4    | t           j        k    rdn| j        S )uN   Map a Platform enum to its config.yaml key (LOCAL→"cli", rest→enum value).cli)r   LOCALr   r  s    r   _platform_config_keyr    s    ..55HNBr   c                  6   	 t           dz  } |                                 rEddl}t          | dd          5 }|                    |          pi cddd           S # 1 swxY w Y   n3# t
          $ r& t                              dt           dz             Y nw xY wi S )z@Load and parse ~/.hermes/config.yaml, returning {} on any error.r&   r   Nrr'   r(   z%Could not load gateway config from %s)r   r   yamlopen	safe_loadr   loggerdebug)config_pathr  fs      r   _load_gateway_configr    s    \"]2 	/KKKk3999 /Q~~a((.B/ / / / / / / / / / / / / / / / \ \ \<l]>Z[[[[[\Is4   4A& AA& AA& !A"A& &-BBconfigc                    | | nt                      }|                    di           }t          |t                    r|S t          |t                    r,|                    d          p|                    d          pdS dS )u   Read model from config.yaml — single source of truth.

    Without this, temporary AIAgent instances (memory flush, /compress) fall
    back to the hardcoded default which fails when the active provider is
    openai-codex.
    Nr\   defaultrj   )r  r   
isinstancer   dict)r  cfg	model_cfgs      r   _resolve_gateway_modelr$    s     &&&,@,B,BC$$I)S!! H	It	$	$ H}}Y''G9==+A+AGRG2r   c                      ddl } |                     d          }|r|gS 	 ddl}|j                            d          t
          j        ddgS n# t          $ r Y nw xY wdS )us  Resolve the Hermes update command as argv parts.

    Tries in order:
    1. ``shutil.which("hermes")`` — standard PATH lookup
    2. ``sys.executable -m hermes_cli.main`` — fallback when Hermes is running
       from a venv/module invocation and the ``hermes`` shim is not on PATH

    Returns argv parts ready for quoting/joining, or ``None`` if neither works.
    r   Nhermes
hermes_cliz-mzhermes_cli.main)shutilwhichimportlib.utilutil	find_specsys
executabler   )r(  
hermes_bin	importlibs      r   _resolve_hermes_binr1    s     MMMh''J |>##L11=ND*;<< >    4s   ,A 
AAzdict | Nonec                 
   |                      d          }t          |          dk    rZ|d         dk    rN|d         dk    rB|d         |d         |d	         d
}t          |          dk    r|d         dv r|d         |d<   |S dS )a@  Parse a session key into its component parts.

    Session keys follow the format
    ``agent:main:{platform}:{chat_type}:{chat_id}[:{extra}...]``.
    Returns a dict with ``platform``, ``chat_type``, ``chat_id``, and
    optionally ``thread_id`` keys, or None if the key doesn't match.

    The 6th element is only returned as ``thread_id`` for chat types where
    it is unambiguous (``dm`` and ``thread``).  For group/channel sessions
    the suffix may be a user_id (per-user isolation) rather than a
    thread_id, so we leave ``thread_id`` out to avoid mis-routing.
    r      r   rk   r#   main         )r  	chat_typechat_id)dmthread	thread_idN)r   r   )r   r   results      r   _parse_session_keyr>    s     c""E
5zzQ58w..58v3E3EaqQx
 

 u::>>eAh*:::"'(F;4r   evtz
str | Nonec                    |                      dd          }|                      dd          }|                      dd          }|dk    rd|                      dd	           d
S |dk    rb|                      dd          }|                      dd	          }|                      dd          }d| d| d| d| }|r	|d| dz  }|d
z  }|S dS )zLFormat a watch pattern event from completion_queue into a [SYSTEM:] message.type
completion
session_idunknownr   watch_disabledz	[SYSTEM: messagerj   r   watch_matchpattern?output
suppressedr   [SYSTEM: Background process z matched watch pattern "z".
Command: z
Matched output:
z
(z/ earlier matches were suppressed by rate limit)Nr   )r?  evt_type_sid_cmd_pat_out_suptexts           r   $_format_gateway_process_notificationrU    s   wwv|,,H77<++D779i((D###43779b114444=  wwy#&&wwx$$ww|Q'''4 ' '#' '' ' !%' ' 	  	PO$OOOOD4r   c                   2   e Zd ZU dZi Zeeef         ed<   dZ	eed<   e
Zeed<   dZee         ed<   dZeed	<   dZeed
<   dZeed<   dZeed<   dZeed<   dZeej                 ed<   i Zeeeeef         f         ed<   ddee         fdZdefdZedz  Zdeeef         fdZddZdededdfdZ ddZ!	 ddedee         fdZ"	 ddedee         fdZ#e$defd            Z%e$defd             Z&e$dee         fd!            Z'e$dee         fd"            Z(d#e)defd$Z*dddd%d#ee)         dee         d&ee+         de,ee+f         fd'Z-d(ed)ed*e+de+fd+Z.d,e/ddfd-Z0d.eddfd/Z1defd0Z2defd1Z3defd2Z4defd3Z5dd4ee         d5ee         ddfd6Z6dddd7d8ed9ee         d:ee         d;ee         ddf
d<Z7e8de9eee:f                  fd=            Z;e8defd>            Z<e8de+dz  fd?            Z=e8dedz  fd@            Z>e8defdA            Z?e8defdB            Z@e8defdC            ZAe8defdD            ZBe8de+fdE            ZCe8deDe+z  dz  fdF            ZEe8de+fdG            ZFdeee:f         fdHZGdedIeHddfdJZIdIeHdedefdKZJdLede,eee:f         ef         fdMZKd.eddfdNZLddOZMdPeee:f         ddfdQZNdRe:ddfdSZOdTZPdUZQdVeRddfdWZSdefdXZTdeddfdYZUddZZVddd[d\ed]edefd^ZWdefd_ZXddaefdbZYddcZZddddddeedfedgeddfdhZ[ddiZ\d8e]de:dee/         fdjZ^d#e)defdkZ_d8ee]         defdlZ`dIeHdee         fdmZadIeHd#e)dne9eee:f                  dee         fdoZbdpefdqZcdefdrZddIeHdefdsZedIeHdefdtZfdIeHdefduZgdIeHdefdvZhdIeHdefdwZidIeHdefdxZjdIeHdefdyZkdIeHdee         fdzZldIeHdefd{ZmdIeHdefd|ZndIeHdefd}ZodIeHdefd~ZpdIeHdefdZqe8dIeHdee         fd            ZrdIeHdefdZsdIeHdefdZtdIeHdefdZudeddfdZvdededefdZw	 ddIeHdedeDdedef
dZxdIeHdeddfdZydedIeHddfdZzdIeHdefdZ{dIeHdefdZ|ded#ddeddfdZ}dIeHdefdZ~dedededdfdZdIeHdefdZdIeHdefdZdIeHdefdZdIeHdefdZdIeHdefdZdIeHdefdZdIeHdefdZdIeHdefdZdIeHdefdZdIeHdefdZdIeHdefdZd`ZdIeHdee         fdZdIeHdefdZ ee]j        e]j        e]j        e]j        e]j        e]j        e]j        e]j        e]j        e]j        e]j        e]j        e]j        e]j        e]j        e]j        e]j        e]j        h          ZdIeHdefdZdIeHdefdZddZ	 	 	 ddededLeddfdZdefdZddZdedeDfdZdeDddfdZd Zdede9e         defdZdede9e         defdZde+fdZdede+ddfdZde+ddfdZdTZe8d)ede+deDdedef
dĄ            Zded)ed*e+de,fdńZdededefdǄZdeddfdȄZdee         fdɄZ	 	 ddededne9eee:f                  d#ddededee         deee:f         fd΄Z	 	 	 	 ddededne9eee:f                  d#e)dedededee         dee         deee:f         fd҄ZdS )GatewayRunnerz
    Main gateway controller.

    Manages the lifecycle of all platform adapters and routes
    messages to/from the agent.
    _running_agents_ts	interrupt_busy_input_mode_restart_drain_timeoutN
_exit_codeF	_draining_restart_requested_restart_task_started_restart_detached_restart_via_service
_stop_task_session_model_overridesr  c                    |pt                      | _        i | _        |                                 | _        |                                 | _        |                                 | _        | 	                                | _
        |                                 | _        |                                 | _        |                                 | _        |                                 | _        |                                 | _        |                                 | _        ddlm t3          | j        j        | j        fd          | _        t9          | j                  | _        d| _        t?          j                     | _!        d| _"        d| _#        d | _$        d | _%        d| _&        d| _'        d| _(        d| _)        d| _*        d | _+        i | _,        i | _-        i | _.        i | _/        dd l0}i | _1        |2                                | _3        i | _4        i | _5        i | _6        i | _7        	 ddl8m9}  |d           n# tt          $ r Y nw xY wd | _;        	 ddl<m=}  |            | _;        n2# tt          $ r%}t|          ?                    d	|           Y d }~nd }~ww xY wdd
l@mA}  |            | _B        ddlCmD}  |            | _E        | F                                | _G        t                      | _I        d S )Nr   process_registryc                 .                         |           S N)has_active_for_session)keyrf  s    r   <lambda>z(GatewayRunner.__init__.<locals>.<lambda>U  s    0@0W0WX[0\0\ r   )has_active_processes_fnF)ensure_installed)log_failures	SessionDBz&SQLite session store not available: %s)PairingStore)HookRegistry)Jr   r  adapters_load_prefill_messages_prefill_messages_load_ephemeral_system_prompt_ephemeral_system_prompt_load_reasoning_config_reasoning_config_load_service_tier_service_tier_load_show_reasoning_show_reasoning_load_busy_input_moderZ  _load_restart_drain_timeoutr[  _load_provider_routing_provider_routing_load_fallback_model_fallback_model_load_smart_model_routing_smart_model_routingtools.process_registryrf  r   sessions_dirsession_storer   delivery_router_runningasyncioEvent_shutdown_event_exit_cleanly_exit_with_failure_exit_reasonr\  r]  r^  r_  r`  ra  rb  _running_agentsrX  _pending_messages_busy_ack_ts	threading_agent_cacheLock_agent_cache_lockrc  _pending_approvals_failed_platforms_update_prompt_pendingtools.tirith_securityrm  r   _session_dbhermes_staterp  r  r  gateway.pairingrq  pairing_storegateway.hooksrr  hooks_load_voice_modes_voice_moder   _background_tasks)	selfr  
_threadingrm  rp  erq  rr  rf  s	           @r   __init__zGatewayRunner.__init__@  sL   5 3 5 5=? "&!<!<!>!>(,(J(J(L(L%!%!<!<!>!>!4466#88:: $ : : < <&*&F&F&H&H#!%!<!<!>!>#88::$($B$B$D$D! 	<;;;;;)K$dk$\$\$\$\
 
 
  .dk::&}""'+/)-"'%*"!&$)!26 024613.0 	'&&&.0!+!2!2 DF% >@ BD 8:#	>>>>>>%00000 	 	 	D	  	F......(y{{D 	F 	F 	FLLA1EEEEEEEE	F 	100000)\^^ 	/.....!\^^
 ,0+A+A+C+C '*ees*   "H5 5
III# #
J-JJr   c                 L    	 ddl m}  |d          duS # t          $ r Y dS w xY w)z3Check if the hermes-agent-setup skill is installed.r   )_find_skillzhermes-agent-setupNF)tools.skill_manager_toolr  r   )r  r  s     r   _has_setup_skillzGatewayRunner._has_setup_skill  sQ    	<<<<<<;344D@@ 	 	 	55	s    
##zgateway_voice_mode.jsonc                    	 t          j        | j                                                  }n$# t          t           j        t          f$ r i cY S w xY wt          |t                    si S h dfd|	                                D             S )N>   alloff
voice_onlyc                 >    i | ]\  }}|v 	t          |          |S r   )r   )r   r9  modevalid_modess      r   
<dictcomp>z3GatewayRunner._load_voice_modes.<locals>.<dictcomp>  s:     
 
 
{"" LL$"""r   )
r   r   _VOICE_MODE_PATHr   FileNotFoundErrorJSONDecodeErrorOSErrorr   r!  items)r  datar  s     @r   r  zGatewayRunner._load_voice_modes  s    	:d3==??@@DD!4#7A 	 	 	III	 $%% 	I222
 
 
 
!%
 
 
 	
s   +/ AAc                    	 | j         j                            dd           | j                             t	          j        | j        d                     d S # t          $ r&}t          	                    d|           Y d }~d S d }~ww xY w)NT)parentsexist_okr5  )indentzFailed to save voice modes: %s)
r  r   mkdir
write_textr   dumpsr  r  r  warning)r  r  s     r   _save_voice_modeszGatewayRunner._save_voice_modes  s    	@!(..td.KKK!,,
4+A666      	@ 	@ 	@NN;Q?????????	@s   AA 
B"BBr9  r  c                     t          |dd          }t          |t                    sdS |r|                    |           dS |                    |           dS )zBUpdate an adapter's in-memory auto-TTS suppression set if present._auto_tts_disabled_chatsN)r   r   r   r   discard)r  r   r9  r  disabled_chatss        r   _set_adapter_auto_tts_disabledz,GatewayRunner._set_adapter_auto_tts_disabled  sg     *DdKK.#.. 	F 	,w'''''""7+++++r   c                     t          |dd          }t          |t                    sdS |                                 |                    d | j                                        D                        dS )z@Restore persisted /voice off state into a live platform adapter.r  Nc              3   ,   K   | ]\  }}|d k    |V  dS )r  Nr   )r   r9  r  s      r   r   zBGatewayRunner._sync_voice_mode_state_to_adapter.<locals>.<genexpr>  s3       
 
%TU]]G]]]]
 
r   )r   r   r   clearupdater  r  )r  r   r  s      r   !_sync_voice_mode_state_to_adapterz/GatewayRunner._sync_voice_mode_state_to_adapter  s     *DdKK.#.. 	F 
 
)-)9)?)?)A)A
 
 
 	
 	
 	
 	
 	
r   old_session_idr   c                    |r2|                     d          rt                              d|           dS 	 | j                            |          }|rt          |          dk     rdS ddlm} |                     |          \  }}|	                    d          sdS  |di ||d	d
d
ddg|d}	 d |_
        d |D             }d}		 ddlm}
  |
            }dD ]S\  }}||z  }|                                r5|                    d                                          }|r|	d| d| z  }	Tn# t           $ r Y nw xY wd}|	r	|d|	 dz  }|dz  }|                    ||           |                     |           n# |                     |           w xY wt                              d|           dS # t           $ r'}t                              d||           Y d}~dS d}~ww xY w)u   Prompt the agent to save memories/skills before context is lost.

        Synchronous worker — meant to be called via run_in_executor from
        an async context so it doesn't block the event loop.
        cron_z*Skipping memory flush for cron session: %sNr7  r   AIAgent)r   r^      Tmemoryskillsr\   max_iterations
quiet_modeskip_memoryenabled_toolsetsrC  c                      d S rh  r   akws     r   rk  z;GatewayRunner._flush_memories_for_session.<locals>.<lambda>      t r   c                     g | ]Y}|                     d           dv |                     d          .|                     d           |                     d          dZS roleuser	assistantcontentr  r  rM  r   ms     r   
<listcomp>z=GatewayRunner._flush_memories_for_session.<locals>.<listcomp>  sg       uuV}}(===!%%	BRBR= UU6]]quuY7G7GHH===r   rj   )get_memory_dir))z	MEMORY.mdzMEMORY (your personal notes))zUSER.mdzUSER PROFILE (who the user is)r'   r(   z

## Current z:
u  [System: This session is about to be automatically reset due to inactivity or a scheduled daily reset. The conversation context will be cleared after this turn.

Review the conversation above and:
1. Save any important facts, preferences, or decisions to memory (user profile or your notes) that would be useful in future sessions.
2. If you discovered a reusable workflow or solved a non-trivial problem, consider saving it as a skill.
3. If nothing is worth saving, that's fine — just skip.

uA  IMPORTANT — here is the current live state of memory. Other sessions, cron jobs, or the user may have updated it since this conversation ended. Do NOT overwrite or remove entries unless the conversation above reveals something that genuinely supersedes them. Only add new information that is not already captured below.

z]Do NOT respond to the user. Just use the memory and skill_manage tools if needed, then stop.])user_messageconversation_historyz/Pre-reset memory flush completed for session %sz0Pre-reset memory flush failed for session %s: %sr   )r   r  r  r  load_transcriptr   	run_agentr  _resolve_session_agent_runtimer   	_print_fntools.memory_toolr  r   r   r   r   run_conversation_cleanup_agent_resourcesinfo)r  r  r   historyr  r\   runtime_kwargs	tmp_agentmsgs_current_memoryr  _mem_dirfnamelabelfpathr  flush_promptr  s                     r   _flush_memories_for_sessionz)GatewayRunner._flush_memories_for_session  s     	n77@@ 	LLE~VVVFY	`(88HHG c'llQ..))))))$($G$G' %H % %!E> "%%i00      "*H!5)   IA9 '<&;	# $   #%@@@@@@-~//H) Y Yu !)5 0 <<>> Y&+oowo&G&G&M&M&O&OG& Y /3XU3X3Xw3X3X XY !   D
T  # 	 1 +1 1 1L 3
 **!-)- +   
 --i8888--i8888KKI>ZZZZZ 	` 	` 	`LLK^]^_________	`s`   /F5 '4F5 F5 1E> A&D/ .E> /
D<9E> ;D<<,E> (F5 >FF5 5
G&?G!!G&c                 v   K   t          j                    }|                    d| j        ||           d{V  dS )zLRun the sync memory flush in a thread pool so it won't block the event loop.N)r  get_running_looprun_in_executorr  )r  r  r   loops       r   _async_flush_memoriesz#GatewayRunner._async_flush_memoriesR  se       '))"",	
 
 	
 	
 	
 	
 	
 	
 	
 	
 	
r   c                     | j         S rh  )r  r  s    r   should_exit_cleanlyz!GatewayRunner.should_exit_cleanly`  s    !!r   c                     | j         S rh  )r  r  s    r   should_exit_with_failurez&GatewayRunner.should_exit_with_failured  s    &&r   c                     | j         S rh  )r  r  s    r   exit_reasonzGatewayRunner.exit_reasonh  s      r   c                     | j         S rh  )r\  r  s    r   	exit_codezGatewayRunner.exit_codel  s
    r   sourcec           	      <   t          | d          rL| j        E	 | j                            |          }t          |t                    r|r|S n# t
          $ r Y nw xY wt          | dd          }t          |t          |dd          t          |dd                    S )	zUResolve the current session key for a source, honoring gateway config when available.r  Nr  group_sessions_per_userTthread_sessions_per_userF)r  r  )hasattrr  _generate_session_keyr   r   r   r   r   )r  r  r   r  s       r   _session_key_for_sourcez%GatewayRunner._session_key_for_sourcep  s    4)) 	d.@.L"0FFvNNk3// 'K '&&   x.. $+F4Mt$T$T%,V5OQV%W%W
 
 
 	
s   2A 
AAr  r   user_configr  c          	      h   |}|s+|)	 |                      |          }n# t          $ r d}Y nw xY wt          |          }|r| j                            |          nd}|r|                    d|          }|                    d          |                    d          |                    d          |                    d          d}|                    d          r?t
                              d|pd	dd
         |||                    d                     ||fS t
                              d|pd	dd
         ||           n\t
                              d|pd	dd
         || j        r.t          | j                                                  dd         nd           t                      }	|r|r| 
                    |||	          \  }}	|sb|	                    d          rM	 ddlm}
  |
|	d                   }|r"t
                              d||	d                    n# t          $ r Y nw xY w||	fS )a$  Resolve model/runtime for a session, honoring session-scoped /model overrides.

        If the session override already contains a complete provider bundle
        (provider/api_key/base_url/api_mode), prefer it directly instead of
        resolving fresh global runtime state first.
        Nr\   r[   r^   r]   r   r[   r^   r]   r   zZSession model override (fast): session=%s config_model=%s -> override_model=%s provider=%srj      z[Session model override (no api_key, fallback): session=%s config_model=%s override_model=%szFNo session model override: session=%s config_model=%s override_keys=%sr3  z[]r   )get_default_model_for_provideru8   No model configured — defaulting to %s for provider %s)r  r   r$  rc  r   r  r  r   keysr   _apply_session_model_overridehermes_cli.modelsr  r  )r  r  r   r  resolved_session_keyr\   overrideoverride_modeloverride_runtimer  r  s              r   r  z,GatewayRunner._resolve_session_agent_runtime  s     +# 	,(:,'+'C'CF'K'K$$ , , ,'+$$$, '{33Nbl40445IJJJhl 	%\\'599N$LL44#<<	22$LL44$LL44	     ##I.. 8p)/R"5un$((44  
 &'777 LLm%+SbS15.   
 LLX%+SbS15BFB_iT27799::2A2>>ei   788 	, 	$($F$F$e^% %!E>  
	++J77 
		LLLLLL66~j7QRR KKR~j9       n$$s    --$;H   
H-,H-r  r\   r  c                 6   ddl m} ddlm} ||                    d          |                    d          |                    d          |                    d          |                    d          t          |                    d	          pg           |                    d
          d} ||t          | di           |          }t          | dd           }|sd |d<   |S 	  ||                    d                    }	n# t          $ r d }	Y nw xY w|	|d<   |S )Nr   )resolve_turn_route)resolve_fast_mode_overridesr^   r]   r[   r   r   r   r   )r\   r^   r]   r[   r   r   r   r   r  r{  request_overridesr\   )agent.smart_model_routingr%  r  r&  r   r   r   r   )
r  r  r\   r  r%  r&  primaryrouteservice_tier	overridess
             r   _resolve_turn_agent_configz(GatewayRunner._resolve_turn_agent_config  sa   @@@@@@AAAAAA %)))44&**:66&**:66&**:66%)))44++F339r::-112CDD	
 	
 #"<?UWY1Z1Z\cddt_d;; 	)-E%&L	33EIIg4F4FGGII 	 	 	III	%.!"s   #D DDr   c                 R  K   t                               d|j        j        |j        pd|j        pd           |                     |j        j        |j        rdnd|j        |j                   | j        	                    |j                  }||u r	 |
                                 d{V  | j                            |j        d           | j        | j        _        n6# | j                            |j        d           | j        | j        _        w xY w|j        r| j        j        	                    |j                  }|rZ|j        | j        vrL|dt!          j                    d	z   d
| j        |j        <   t                               d|j        j                   | j        st| j        sm|j        pd| _        |j        r"d| _        t                               d           nt                               d           |                                  d{V  dS | j        s| j        r|j        rK|j        pd| _        d| _        t                               d           |                                  d{V  dS t                               dt/          | j                             dS dS dS )zReact to an adapter failure after startup.

        If the error is retryable (e.g. network blip, DNS failure), queue the
        platform for background reconnection instead of giving up permanently.
        zFatal %s adapter error (%s): %srD  unknown errorretryingfatalplatform_state
error_codeerror_messageNr   r  r  attempts
next_retryz%%s queued for background reconnectionz#All messaging adapters disconnectedTzSNo connected messaging platforms remain. Shutting down gateway for service restart.zGNo connected messaging platforms remain. Shutting down gateway cleanly.z4All messaging platforms failed with retryable errorszuAll messaging platforms failed with retryable errors. Shutting down gateway for service restart (systemd will retry).zSNo connected messaging platforms remain, but %d platform(s) queued for reconnection)r  errorr  r   fatal_error_codefatal_error_message_update_platform_runtime_statusfatal_error_retryablers  r   
disconnectr   r  r  	platformsr  time	monotonicr  r  r  stopr  r   )r  r   existingplatform_configs       r   _handle_adapter_fatal_errorz)GatewayRunner._handle_adapter_fatal_error  s      	-"$1	':?		
 	
 	
 	,,")0)FS::G/!5	 	- 	
 	
 	
 =$$W%566w>((*********!!'"2D99904$-- !!'"2D99904$-==== ( 	"k3778HIIO 	7#34;Q#Q#Q- !"&."2"2R"7< <&w'78
 ;$*  
 } 	T%; 	 ' ; d?dD, h*.'rssssfggg))++ 	4#9 	 , $+$?$yCy!*.'V   iikk!!!!!!!!!i.//    	 	 	 	s   C 3Dreasonc                 T    d| _         || _        | j                                         d S )NT)r  r  r  r   )r  rF  s     r   _request_clean_exitz!GatewayRunner._request_clean_exit)  s-    !"  """""r   c                 *    t          | j                  S rh  )r   r  r  s    r   _running_agent_countz"GatewayRunner._running_agent_count.  s    4'(((r   c                     | j         rdndS )Nrestartshutdownr^  r  s    r   _status_action_labelz"GatewayRunner._status_action_label1  s     3CyyCr   c                     | j         rdndS )N
restartingshutting downrN  r  s    r   _status_action_gerundz#GatewayRunner._status_action_gerund4  s    #6K||OKr   c                 &    | j         o
| j        dk    S )Nr   )r^  rZ  r  s    r   _queue_during_drain_enabledz)GatewayRunner._queue_during_drain_enabled7  s    &K4+@G+KKr   gateway_stater  c                     	 ddl m}  |||| j        |                                            d S # t          $ r Y d S w xY w)Nr   write_runtime_status)rV  r  restart_requestedactive_agents)gateway.statusrY  r^  rJ  r   )r  rV  r  rY  s       r   _update_runtime_statusz$GatewayRunner._update_runtime_status:  s|    		;;;;;;  +'"&"9"7799	       	 	 	DD	s   ,0 
>>r2  r  r3  r4  r5  c                T    	 ddl m}  |||||           d S # t          $ r Y d S w xY w)Nr   rX  )r  r3  r4  r5  )r\  rY  r   )r  r  r3  r4  r5  rY  s         r   r<  z-GatewayRunner._update_platform_runtime_statusF  sm    		;;;;;;  !-%+	       	 	 	DD	s    
''c                     ddl } t          j        dd          }|s	 ddl}t          dz  }|                                rVt          |d          5 }|                    |          pi }ddd           n# 1 swxY w Y   |                    dd          }n# t          $ r Y nw xY w|sg S t          |                                          }|                                s
t          |z  }|                                st                              d	|           g S 	 t          |d
d          5 }|                     |          }ddd           n# 1 swxY w Y   t!          |t"                    st                              d|           g S |S # t          $ r(}	t                              d||	           g cY d}	~	S d}	~	ww xY w)a  Load ephemeral prefill messages from config or env var.
        
        Checks HERMES_PREFILL_MESSAGES_FILE env var first, then falls back to
        the prefill_messages_file key in ~/.hermes/config.yaml.
        Relative paths are resolved from ~/.hermes/.
        r   NHERMES_PREFILL_MESSAGES_FILErj   r&   r'   r(   prefill_messages_filez#Prefill messages file not found: %sr  z3Prefill messages file must contain a JSON array: %sz+Failed to load prefill messages from %s: %s)r   r   r   r  r   r   r  r  r   r   r   
expanduseris_absoluter  r  loadr   r   )
_json	file_path_ycfg_path_fr"  r   r  r  r  s
             r   rt  z$GatewayRunner._load_prefill_messagesY  sg    	I<bAA	 		!!!!'-7??$$ Eh999 5R ll2..4"5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 #(? D DI    	II))++!! 	'$&D{{}} 	NN@$GGGI		dC'222 %azz!}}% % % % % % % % % % % % % % %dD)) TVZ[[[	K 	 	 	NNH$PQRRRIIIIII	s}   3B A4(B 4A88B ;A8<B 
B#"B#F -EF EF E4F F 
G F;5G ;G c                     t          j        dd          } | r| S 	 ddl}t          dz  }|                                r~t          |d          5 }|                    |          pi }ddd           n# 1 swxY w Y   |                    di                               d	d          pd                                S n# t          $ r Y nw xY wdS )
zLoad ephemeral system prompt from config or env var.
        
        Checks HERMES_EPHEMERAL_SYSTEM_PROMPT env var first, then falls back to
        agent.system_prompt in ~/.hermes/config.yaml.
        HERMES_EPHEMERAL_SYSTEM_PROMPTrj   r   Nr&   r'   r(   rk   system_prompt)
r   r   r  r   r   r  r  r   r   r   )promptrg  rh  ri  r"  s        r   rv  z+GatewayRunner._load_ephemeral_system_prompt  s.    ;R@@ 	M	#m3H   U(W555 1,,r**0bC1 1 1 1 1 1 1 1 1 1 1 1 1 1 1,,00"EEKRRTTTU  	 	 	D	rs6   3B< A2&B< 2A66B< 9A6:A B< <
C	C	c                     ddl m}  d}	 ddl}t          dz  }|                                rt          |d          5 }|                    |          pi }ddd           n# 1 swxY w Y   t          |                    di                               d	d          pd          	                                }n# t          $ r Y nw xY w | |          }|r1|	                                r|t                              d
|           |S )zLoad reasoning effort from config.yaml.

        Reads agent.reasoning_effort from config.yaml. Valid: "none",
        "minimal", "low", "medium", "high", "xhigh". Returns None to use
        default (medium).
        r   )parse_reasoning_effortrj   Nr&   r'   r(   rk   reasoning_effortz5Unknown reasoning_effort '%s', using default (medium))r  ro  r  r   r   r  r  r   r   r   r   r  r  )ro  effortrg  rh  ri  r"  r=  s          r   rx  z$GatewayRunner._load_reasoning_config  sk    	<;;;;;	#m3H   ](W555 1,,r**0bC1 1 1 1 1 1 1 1 1 1 1 1 1 1 1SWWWb11556H"MMSQSTTZZ\\ 	 	 	D	''// 	\fllnn 	\NNRTZ[[[s5   3B8 A!B8 !A%%B8 (A%)AB8 8
CCc                     d} 	 ddl }t          dz  }|                                rt          |d          5 }|                    |          pi }ddd           n# 1 swxY w Y   t          |                    di                               dd          pd                                          } n# t          $ r Y nw xY w| 	                                }|r|d	v rdS |d
v rdS t                              d|            dS )a  Load Priority Processing setting from config.yaml.

        Reads agent.service_tier from config.yaml. Accepted values mirror the CLI:
        "fast"/"priority"/"on" => "priority", while "normal"/"off" disables it.
        Returns None when unset or unsupported.
        rj   r   Nr&   r'   r(   rk   r+  >   r  nonenormalr  standard>   onfastpriorityrx  z#Unknown service_tier '%s', ignoring)r  r   r   r  r  r   r   r   r   r   r  r  rawrg  rh  ri  r"  r   s         r   rz  z GatewayRunner._load_service_tier  sa    	#m3H   V(W555 1,,r**0bC1 1 1 1 1 1 1 1 1 1 1 1 1 1 1#'''2..22>2FFL"MMSSUU 	 	 	D	 		 	!QQQ4...:<cBBBts5   3B2 AB2 AB2 "A#AB2 2
B?>B?c                  \   	 ddl } t          dz  }|                                rwt          |d          5 }|                     |          pi }ddd           n# 1 swxY w Y   t          |                    di                               dd                    S n# t          $ r Y nw xY wdS )	z<Load show_reasoning toggle from config.yaml display section.r   Nr&   r'   r(   rv   show_reasoningF)r  r   r   r  r  boolr   r   rg  rh  ri  r"  s       r   r|  z"GatewayRunner._load_show_reasoning  s   	#m3H   Q(W555 1,,r**0bC1 1 1 1 1 1 1 1 1 1 1 1 1 1 1CGGIr22667GOOPPPQ  	 	 	D	us4   3B AB AB  A!9B 
B)(B)c                  .   t          j        dd                                                                          } | s	 ddl}t
          dz  }|                                rt          |d          5 }|                    |          pi }ddd           n# 1 swxY w Y   t          |
                    di           
                    d	d          pd                                                                          } n# t          $ r Y nw xY w| d
k    rd
ndS )z<Load gateway drain-time busy-input behavior from config/env.rx   rj   r   Nr&   r'   r(   rv   rw   r   rY  )r   r   r   r   r  r   r   r  r  r   r   r   )r  rg  rh  ri  r"  s        r   r~  z#GatewayRunner._load_busy_input_mode  s\    y92>>DDFFLLNN 		!!!!'-7??$$ hh999 5R ll2..4"5 5 5 5 5 5 5 5 5 5 5 5 5 5 5swwy"5599:KRPPVTVWW]]__eeggD   '//ww{:s6   3C= 0BC= BC= BA C= =
D
	D
c                     t          j        dd                                          } | s	 ddl}t          dz  }|                                rt          |d          5 }|                    |          pi }ddd           n# 1 swxY w Y   t          |	                    di           	                    d	d          pd                                          } n# t          $ r Y nw xY wt          |           }| rT|t          k    rI	 t          |            n8# t          t          f$ r$ t                               d
| t                     Y nw xY w|S )z<Load graceful gateway restart/stop drain timeout in seconds.ru   rj   r   Nr&   r'   r(   rk   rt   z7Invalid restart_drain_timeout '%s', using default %.0fs)r   r   r   r  r   r   r  r  r   r   r   r   r   float	TypeError
ValueErrorr  r  ry  s         r   r  z)GatewayRunner._load_restart_drain_timeout  s    i6;;AACC 		!!!!'-7??$$ ch999 5R ll2..4"5 5 5 5 5 5 5 5 5 5 5 5 5 5 5cgggr22667NPRSSYWYZZ``bbC   +C00 	5AAAc



z*   M9     sH   3C B6C BC 	B
AC 
C&%C&D 2E
Ec                  <   t          j        dd          } | s	 ddl}t          dz  }|                                rt          |d          5 }|                    |          pi }ddd           n# 1 swxY w Y   |                    di                               d	          }|d
u rd} n|dvrt          |          } n# t          $ r Y nw xY w| pd
                                                                } h d}| |vrt                              d|            dS | S )u  Load background process notification mode from config or env var.

        Modes:
          - ``all``    — push running-output updates *and* the final message (default)
          - ``result`` — only the final completion message (regardless of exit code)
          - ``error``  — only the final message when exit code is non-zero
          - ``off``    — no watcher messages at all
        HERMES_BACKGROUND_NOTIFICATIONSrj   r   Nr&   r'   r(   rv    background_process_notificationsFr  )Nrj   r  >   r  r  r9  r=  zBUnknown background_process_notifications '%s', defaulting to 'all')r   r   r  r   r   r  r  r   r   r   r   r   r  r  )r  rg  rh  ri  r"  rz  valids          r   #_load_background_notifications_modez1GatewayRunner._load_background_notifications_mode   s    y:B?? 	!!!!'-7??$$ (h999 5R ll2..4"5 5 5 5 5 5 5 5 5 5 5 5 5 5 5'')R00445WXXCe||$J.."3xx   $$&&,,..111uNNT   5s6   3B? A0$B? 0A44B? 7A48AB? ?
CCc                     	 ddl } t          dz  }|                                rXt          |d          5 }|                     |          pi }ddd           n# 1 swxY w Y   |                    di           pi S n# t          $ r Y nw xY wi S )z>Load OpenRouter provider routing preferences from config.yaml.r   Nr&   r'   r(   provider_routingr  r   r   r  r  r   r   r~  s       r   r  z$GatewayRunner._load_provider_routing#  s    	#m3H   =(W555 1,,r**0bC1 1 1 1 1 1 1 1 1 1 1 1 1 1 1ww1266<"<=  	 	 	D		4   3A= AA= AA=  A!A= =
B
	B
c                  N   	 ddl } t          dz  }|                                rpt          |d          5 }|                     |          pi }ddd           n# 1 swxY w Y   |                    d          p|                    d          pd}|r|S n# t          $ r Y nw xY wdS )a  Load fallback provider chain from config.yaml.

        Returns a list of provider dicts (``fallback_providers``), a single
        dict (legacy ``fallback_model``), or None if not configured.
        AIAgent.__init__ normalizes both formats into a chain.
        r   Nr&   r'   r(   fallback_providersfallback_modelr  )rg  rh  ri  r"  fbs        r   r  z"GatewayRunner._load_fallback_model1  s   
	#m3H   (W555 1,,r**0bC1 1 1 1 1 1 1 1 1 1 1 1 1 1 1WW122Wcgg>N6O6OWSW I 	 	 	D	ts4   3B AB AB  A!2B 
B"!B"c                     	 ddl } t          dz  }|                                rXt          |d          5 }|                     |          pi }ddd           n# 1 swxY w Y   |                    di           pi S n# t          $ r Y nw xY wi S )z9Load optional smart cheap-vs-strong model routing config.r   Nr&   r'   r(   smart_model_routingr  r~  s       r   r  z'GatewayRunner._load_smart_model_routingF  s    	#m3H   @(W555 1,,r**0bC1 1 1 1 1 1 1 1 1 1 1 1 1 1 1ww4b99?R?@  	 	 	D		r  c                 H    d | j                                         D             S )Nc                 ,    i | ]\  }}|t           u||S r   )_AGENT_PENDING_SENTINEL)r   r   rk   s      r   r  z:GatewayRunner._snapshot_running_agents.<locals>.<dictcomp>U  s4     
 
 
"U333 333r   )r  r  r  s    r   _snapshot_running_agentsz&GatewayRunner._snapshot_running_agentsT  s2    
 
&*&:&@&@&B&B
 
 
 	
r   r   c                     | j                             |j        j                  }|sd S t	          |j        ||           d S rh  )rs  r   r  r  r   r  )r  r   r   r   s       r   _queue_or_replace_pending_eventz-GatewayRunner._queue_or_replace_pending_event[  sD    -##EL$9:: 	F#G$={ERRRRRr   c                   K   | j         r| j                            |j        j                  }|sdS |j        j        rd|j        j        ind }|                                 r/|                     ||           d|                                  d}nd|                                  d}|	                    |j        j
        ||j        |           d {V  dS | j                            |j        j                  }|sdS d	d
lm}  ||j        ||           | j                            |          }|r5|t           ur,	 |                    |j                   n# t&          $ r Y nw xY wd}t)          j                    }	| j                            |d	          }
|	|
z
  |k     rdS |	| j        |<   g }|r|t           ur	 |                                }|                    dd	          }|                    dd	          }|                    d          }| j                            |d	          }|r3t1          |	|z
  dz            }|d	k    r|                    | d           |r|                    d| d|            |r|                    d|            n# t&          $ r Y nw xY w|rdd                    |           dnd}d| d}|j        j        rd|j        j        ind }	 |	                    |j        j
        ||j        |           d {V  n2# t&          $ r%}t6                              d|           Y d }~nd }~ww xY wdS )NTr<     ⏳ Gateway 2    — queued for the next turn after it comes back.   ⏳ Gateway is - and is not accepting another turn right now.)r9  r  reply_tometadataFr   )r   r  api_call_countr  current_tool<    min elapsed
iteration r   	running:  (, )rj   u   ⚡ Interrupting current taskz'. I'll respond to your message shortly.zFailed to send busy-ack: %s)r]  rs  r   r  r  r<  rU  r  rS  _send_with_retryr9  
message_idgateway.platforms.baser   r  r  r  rY  rT  r   r@  r  get_activity_summaryrX  intr   r   r  r  )r  r   r   r   thread_metarF  r   running_agent_BUSY_ACK_COOLDOWNnowlast_ackstatus_partssummary	iterationmax_iterr  start_tselapsed_minstatus_detailr  s                       r   #_handle_active_session_busy_messagez1GatewayRunner._handle_active_session_busy_messagea  se     > 	m''(=>>G tCH<CYc;(>??_cK//11 x44[%HHHy)C)C)E)EyyywD,F,F,H,Hwww**,)$	 +          4 -##EL$9:: 	5 	GFFFFF##G$={ERRR ,00== 	]2III''
3333   
  ikk$((a88>...4),+&  	]2III'<<>>#KK(8!<<	";;'7;;&{{>::266{AFF J"%sX~&;"<"<K"Q$++{,H,H,HIII M ''(KY(K(K(K(KLLL D ''(BL(B(BCCC    <HO7TYY|447777R5M 5 5 5 	
 @E|?U_{EL$:;;[_	;**,)$	 +            	; 	; 	;LL6::::::::	; ts=   ?E 
E'&E'=CJ 
J'&J'*.L 
M#MMr0   c                 ~   K                                     }                                 dd
dt          dd f fd} j        s |d           |dfS  |d           |dk    r|dfS t	          j                                                    |z   } j        r}t	          j                                                    |k     rT |             t	          j        d	           d {V   j        r)t	          j                                                    |k     Tt           j                  } |d           ||fS )N        Fr   r   c                     t          j                                                    }                                }| s|k    s	|z
  dk    r                    d           ||d S d S )Ng      ?draining)r  r  r@  rJ  r]  )r   r  active_countlast_active_countlast_status_atr  s      r   _maybe_update_statusz@GatewayRunner._drain_active_agents.<locals>._maybe_update_status  s}    *,,1133C4466L %(999cN>RWZ=Z=Z++J777$0!!$ >[=Zr   Tr   r   皙?F)r  rJ  r}  r  r  r  r@  sleep)r  r0   snapshotr  deadline	timed_outr  r  s   `     @@r   _drain_active_agentsz"GatewayRunner._drain_active_agents  s     0022 5577	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% # 	#  t,,,,U?"4((((a<<T>!+--2244w>" 	%w'?'A'A'F'F'H'H8'S'S  """-$$$$$$$$$ " 	%w'?'A'A'F'F'H'H8'S'S -..	4((((""r   c                 H   t          | j                                                  D ]z\  }}|t          u r	 |                    |           t
                              d|d d                    I# t          $ r%}t
                              d|           Y d }~sd }~ww xY wd S )Nz8Interrupted running agent for session %s during shutdown   z-Failed interrupting agent during shutdown: %s)r   r  r  r  rY  r  r  r   )r  rF  r   rk   r  s        r   _interrupt_running_agentsz'GatewayRunner._interrupt_running_agents  s    "&t';'A'A'C'C"D"D 	Q 	QK///Q'''WYdehfhehYijjjj Q Q QLaPPPPPPPPQ	Q 	Qs   8A00
B:BBc                   K   |                                  }|sdS | j        rdnd}| j        rdnd}d| d| }t                      }|D ]}t          |          }|s|d         }|d	         }	||	f}
|
|v r-	 t	          |          }| j                            |          }|sZ|                    d
          }|rd
|ind}|                    |	||           d{V  |                    |
           t          
                    d||	           # t          $ r'}t                              d||	|           Y d}~d}~ww xY wdS )u&  Send a notification to every chat with an active agent.

        Called at the very start of stop() — adapters are still connected so
        messages can be delivered.  Best-effort: individual send failures are
        logged and swallowed so they never block the shutdown sequence.
        NrQ  rR  zbYour current task will be interrupted. Send any message after restart to resume where it left off.z&Your current task will be interrupted.u   ⚠️ Gateway     — r  r9  r<  r  z#Sent shutdown notification to %s:%sz1Failed to send shutdown notification to %s:%s: %s)r  r^  r   r>  r   rs  r   sendr   r  r  r   r  )r  activeactionhintmsgnotifiedr   _parsedplatform_strr9  	dedup_keyr  r   r<  r  r  s                   r   #_notify_active_sessions_of_shutdownz1GatewayRunner._notify_active_sessions_of_shutdown  s      ..00 	F!%!8Mo &: J J :	 	 433T33! #	 #	K(55G ":.Li(G &w/IH$$#L11-++H55  $KK44	7@JK33dll7C(lCCCCCCCCCY'''9 '       G '1       ?#	 #	s   7+D#A,D
ED<<Er[  c           	          |                                 D ]L}	 ddlm}  |dt          |dd           d           n# t          $ r Y nw xY w|                     |           Md S )Nr   invoke_hookon_session_finalizerC  gatewayrC  r  )valueshermes_cli.pluginsr  r   r   r  )r  r[  rk   _invoke_hooks       r   _finalize_shutdown_agentsz'GatewayRunner._finalize_shutdown_agents$  s    "))++ 
	1 
	1EJJJJJJ)&ulDAA&    
    ))%0000
	1 
	1s   #<
A	A	rk   c                     |dS 	 t          |d          r|                                 n# t          $ r Y nw xY w	 t          |d          r|                                 dS dS # t          $ r Y dS w xY w)z<Best-effort cleanup for temporary or cached agent instances.Nshutdown_memory_providerclose)r  r  r   r  )r  rk   s     r   r  z&GatewayRunner._cleanup_agent_resources1  s    =F	u899 1..000 	 	 	D	
	ug&&   	 	 	DD	s   $+ 
88$A$ $
A21A2r6  z.restart_failure_countsactive_session_keysc                 t   ddl }t          | j        z  }	 |                                r" |j        |                                          ni }n# t          $ r i }Y nw xY wi }|D ]}|                    |d          dz   ||<   	 |                     |j	        |                     dS # t          $ r Y dS w xY w)a  Increment restart-failure counters for sessions active at shutdown.

        Persists to a JSON file so counters survive across restarts.
        Sessions NOT in active_session_keys are removed (they completed
        successfully, so the loop is broken).
        r   Nr#   )
r   r   _STUCK_LOOP_FILEr   r   r   r   r   r  r  )r  r  r   r   counts
new_countsrj  s          r   !_increment_restart_failure_countsz/GatewayRunner._increment_restart_failure_countsF  s     	d33	59[[]]JZTZ 0 0111FF 	 	 	FFF	 
& 	5 	5C$jja0014JsOO	OOJDJz2233333 	 	 	DD	s#   8A AA#B) )
B76B7c                     ddl }t           j        z  }|                                sdS 	  |j        |                                          }n# t          $ r Y dS w xY wd} fd|                                D             }|D ]q}	  j        j	        
                    |          }|r=|j        s6d|_        |dz  }t                              d|dd         ||                    b# t          $ r Y nw xY w|r+	  j                                         n# t          $ r Y nw xY w	 |                    d           n# t          $ r Y nw xY w|S )	u,  Suspend sessions that have been active across too many restarts.

        Returns the number of sessions suspended.  Called on gateway startup
        AFTER suspend_recently_active() to catch the stuck-loop pattern:
        session loads → agent gets stuck → gateway restarts → repeat.
        r   Nc                 0    g | ]\  }}|j         k    |S r   )_STUCK_LOOP_THRESHOLD)r   kvr  s      r   r  z>GatewayRunner._suspend_stuck_loop_sessions.<locals>.<listcomp>t  s*    VVVDAqa4;U6U6Ua6U6U6Ur   Tr#   u_   Auto-suspended stuck session %s (active across %d consecutive restarts — likely a stuck loop)r  
missing_ok)r   r   r  r   r   r   r   r  r  _entriesr   	suspendedr  r  _saveunlink)r  r   r   r  r  
stuck_keysr   entrys   `       r   _suspend_stuck_loop_sessionsz*GatewayRunner._suspend_stuck_loop_sessionsa  s    	d33{{}} 	1	TZ 0 011FF 	 	 	11	 	VVVVFLLNNVVV
% 	 	K*377DD  &*EONINNH#CRC(&*=  
      	"((****   	KK4K(((( 	 	 	D	 sH   "A 
AAAC&&
C32C39D 
D D $D; ;
EEc                 L   ddl }t          | j        z  }|                                sdS 	  |j        |                                          }||v rB||= |r%|                     |j        |                     dS |                    d           dS dS # t          $ r Y dS w xY w)zClear the restart-failure counter for a session that completed OK.

        Called after a successful agent turn to signal the loop is broken.
        r   NTr  )
r   r   r  r   r   r   r  r  r  r   )r  r   r   r   r  s        r   _clear_restart_failure_countz*GatewayRunner._clear_restart_failure_count  s    
 	d33{{}} 	F		TZ 0 011Ff$$;' 1OOJDJv$6$677777KK4K00000 %$  	 	 	DD	s   AB ;B 
B#"B#c                   K   dd l }dd l}t                      }|st                              d           d S t          j                    }d                    d |D                       }d| d| d}|                    d          }|r)|	                    |d	d
|g|j
        |j
        d           d S |	                    d	d
|g|j
        |j
        d           d S )Nr   z4Could not locate hermes binary for detached /restart c              3   >   K   | ]}t          j        |          V  d S rh  shlexquoter   s     r   r   zAGatewayRunner._launch_detached_restart_command.<locals>.<genexpr>  s,      @@Tu{4((@@@@@@r   zwhile kill -0 z" 2>/dev/null; do sleep 0.2; done; z gateway restartsetsidbashz-lcTstdoutstderrstart_new_session)r(  
subprocessr1  r  r9  r   getpidr   r)  PopenDEVNULL)r  r(  r	  
hermes_cmdcurrent_pidcmd	shell_cmd
setsid_bins           r    _launch_detached_restart_commandz.GatewayRunner._launch_detached_restart_command  s8     (**
 	LLOPPPFikkhh@@Z@@@@@%[ % %% % % 	 \\(++
 	VUI6!)!)"&	       	*!)!)"&	      r   detachedvia_servicer  r  c                     j         rdS d _         _         _        d _         d fd}t	          j         |                      } j                            |           |                     j        j	                   dS )NFTr   c                  |   K   t          j        d           d {V                      d            d {V  d S )N皙?TrL  detached_restartservice_restart)r  r  rB  )r  r  r  s   r   _run_restartz3GatewayRunner.request_restart.<locals>._run_restart  sZ      -%%%%%%%%%))D8U`)aaaaaaaaaaar   r   N)
r_  r^  r`  ra  r  create_taskr  r   add_done_callbackr  )r  r  r  r  tasks   ```  r   request_restartzGatewayRunner.request_restart  s    % 	5"&!)$/!%)"	b 	b 	b 	b 	b 	b 	b 	b "<<>>22""4(((t5=>>>tr   c           
        K   t                               d           t                               d| j        j                   	 ddlm}  |            }|r!|dk    rt                               d|           n# t          $ r Y nw xY w	 ddlm}  |dd	
           n# t          $ r Y nw xY wt          d dD                       }t          j        dd                                          dv pt          d dD                       }|s|st                               d           | j                                         	 ddlm} |                                }|rt                               d|           n2# t          $ r%}t                               d|           Y d	}~nd	}~ww xY wt&          dz  }	|	                                r@t                               d           	 |	                                 nz# t          $ r Y nnw xY w	 | j                                        }
|
rt                               d|
           n2# t          $ r%}t                               d|           Y d	}~nd	}~ww xY w	 |                                 }|rt                               d|           n2# t          $ r%}t                               d|           Y d	}~nd	}~ww xY wd}d}g }g }| j        j                                        D ]&\  }}|j        s|dz  }|                     ||          }|s!t                               d|j                   L|                    | j                    |!                    | j"                   |#                    | j                   |$                    | j%                   t                               d|j                   | &                    |j        dd	d	            	 |'                                 d	{V }|rd|| j(        |<   | )                    |           |dz  }| &                    |j        d!d	d	            t                               d"|j                   nt                               d#|j                   |j*        r| &                    |j        |j+        rd$nd%|j,        |j-                    |j+        r|n|}|.                    |j         d&|j-                    |j+        r"|dt_          j0                    d'z   d(| j1        |<   n]| &                    |j        d$d	d)            |.                    |j         d*           |dt_          j0                    d'z   d(| j1        |<   # t          $ r}t           2                    d+|j        |           | &                    |j        d$d	tg          |                      |.                    |j         d&|            |dt_          j0                    d'z   d(| j1        |<   Y d	}~ d	}~ww xY w|dk    r|rld,4                    |          }t           2                    d-|           	 ddlm}  |d.|
           n# t          $ r Y nw xY w| 5                    |           d/S |dk    rYd,4                    |          pd0}t           2                    d1|           	 ddlm}  |d.|
           n# t          $ r Y nw xY wd2S t                               d3           t                               d4           | j(        | j6        _(        d/| _7        | 8                    d5           ts          | j        j:                  }|rt                               d6|           | j        ;                    d7d8d9 | j(        <                                D             i           d	{V  |dk    rt                               d:|           	 dd;l=m>}  || j(                  }t          d< |@                    d8i           A                                D                       }t                               d=|           n2# t          $ r%}t                               d>|           Y d	}~nd	}~ww xY w| B                                 d	{V }|s?t          d? t&          d@z  t&          dAz  fD                       r| C                                 | D                                 d	{V  	 ddlm} |jE        rv|jE        F                    d          }t          jH        | I                    |                     t                               dB|@                    dC                     |jE        vn2# t          $ r%}t           2                    dD|           Y d	}~nd	}~ww xY wt          jH        | J                                           | j1        rPt                               dEts          | j1                  dF4                    dG | j1        D                                  t          jH        | K                                           t                               dH           d/S )Iz
        Start the gateway and all configured platform adapters.
        
        Returns True if at least one adapter connected successfully.
        zStarting Hermes Gateway...zSession storage: %sr   get_active_profile_namer  zActive profile: %srX  startingN)rV  r  c              3   >   K   | ]}t          j        |          V  d S rh  )r   r   r   r  s     r   r   z&GatewayRunner.start.<locals>.<genexpr>  s>       
 
 IaLL
 
 
 
 
 
r   )TELEGRAM_ALLOWED_USERSDISCORD_ALLOWED_USERSWHATSAPP_ALLOWED_USERSSLACK_ALLOWED_USERSSIGNAL_ALLOWED_USERSSIGNAL_GROUP_ALLOWED_USERSEMAIL_ALLOWED_USERSSMS_ALLOWED_USERSMATTERMOST_ALLOWED_USERSMATRIX_ALLOWED_USERSDINGTALK_ALLOWED_USERSFEISHU_ALLOWED_USERSWECOM_ALLOWED_USERSWECOM_CALLBACK_ALLOWED_USERSWEIXIN_ALLOWED_USERSBLUEBUBBLES_ALLOWED_USERSQQ_ALLOWED_USERSGATEWAY_ALLOWED_USERSGATEWAY_ALLOW_ALL_USERSrj   truer   yesc              3   h   K   | ]-}t          j        |d                                           dv V  .dS )rj   r;  N)r   r   r   r'  s     r   r   z&GatewayRunner.start.<locals>.<genexpr>  s\       e
 e
 Ia""$$(<<e
 e
 e
 e
 e
 e
r   )TELEGRAM_ALLOW_ALL_USERSDISCORD_ALLOW_ALL_USERSWHATSAPP_ALLOW_ALL_USERSSLACK_ALLOW_ALL_USERSSIGNAL_ALLOW_ALL_USERSEMAIL_ALLOW_ALL_USERSSMS_ALLOW_ALL_USERSMATTERMOST_ALLOW_ALL_USERSMATRIX_ALLOW_ALL_USERSDINGTALK_ALLOW_ALL_USERSFEISHU_ALLOW_ALL_USERSWECOM_ALLOW_ALL_USERSWECOM_CALLBACK_ALLOW_ALL_USERSWEIXIN_ALLOW_ALL_USERSBLUEBUBBLES_ALLOW_ALL_USERSQQ_ALLOW_ALL_USERSzNo user allowlists configured. All unauthorized users will be denied. Set GATEWAY_ALLOW_ALL_USERS=true in ~/.hermes/.env to allow open access, or configure platform allowlists (e.g., TELEGRAM_ALLOWED_USERS=your_id).re  z5Recovered %s background process(es) from previous runzProcess checkpoint recovery: %s.clean_shutdownu?   Previous gateway exited cleanly — skipping session suspensionz3Suspended %d in-flight session(s) from previous runz(Session suspension on startup failed: %sz'Auto-suspended %d stuck-loop session(s)zStuck-loop detection failed: %sr#   zNo adapter available for %szConnecting to %s...
connectingr2  	connectedu   ✓ %s connectedu   ✗ %s failed to connectr0  r1  : r  r6  zfailed to connectz: failed to connectu   ✗ %s error: %sz; z0Gateway hit a non-retryable startup conflict: %sstartup_failedTz4all configured messaging platforms failed to connectz?Gateway failed to connect any configured messaging platform: %sFzNo messaging platforms enabled.z5Gateway will continue running for cron job execution.runningz%s hook(s) loadedzgateway:startupr?  c                     g | ]	}|j         
S r   r   r   ps     r   r  z'GatewayRunner.start.<locals>.<listcomp>  s    @@@a!'@@@r   z#Gateway running with %s platform(s)build_channel_directoryc              3   4   K   | ]}t          |          V  d S rh  r   )r   chss     r   r   z&GatewayRunner.start.<locals>.<genexpr>  s(      WW3s88WWWWWWr   z%Channel directory built: %d target(s)z"Channel directory build failed: %sc              3   >   K   | ]}|                                 V  d S rh  )r   )r   r   s     r   r   z&GatewayRunner.start.<locals>.<genexpr>  s>        
  
 KKMM 
  
  
  
  
  
r   .update_pending.json.update_pending.claimed.jsonz(Resumed watcher for recovered process %srC  z!Recovered watcher setup error: %sz;Starting reconnection watcher for %d failed platform(s): %sr  c              3   $   K   | ]}|j         V  d S rh  r   rV  s     r   r   z&GatewayRunner.start.<locals>.<genexpr>  s$      BBa!'BBBBBBr   zPress Ctrl+C to stop)Lr  r  r  r  hermes_cli.profilesr$  r   r\  rY  r   r   r   r   r  r  discover_and_loadr  rf  recover_from_checkpointr   r   r  r  suspend_recently_activer  r  r?  r  enabled_create_adapterr   set_message_handler_handle_messageset_fatal_error_handlerrE  set_session_storeset_busy_session_handlerr  r<  connectrs  r  has_fatal_errorr=  r:  r;  r   r@  rA  r  r9  r   r   rH  r  r  r]  r   loaded_hooksemitr  gateway.channel_directoryrY  sumr   r  _send_update_notification#_schedule_update_notification_watch_send_restart_notificationpending_watchersr   r  r  _run_process_watcher_session_expiry_watcher_platform_reconnect_watcher)r  r$  _profilerY  _any_allowlist
_allow_allrf  	recoveredr  _clean_markerr  stuckconnected_countenabled_platform_countstartup_nonretryable_errorsstartup_retryable_errorsr  rD  r   successtargetrF  
hook_countrY  	directorych_countr  watchers                               r   startzGatewayRunner.start  s      	0111)4;+CDDD	CCCCCC..00H <H	110(;;; 	 	 	D		;;;;;;  ztLLLLL 	 	 	D	  
 
0
 
 
 
 
  Y8"==CCEEI]] 
ad e
 e

-e
 e
 e
 b
 b

  	j 	NN[   	
$$&&&	A??????(@@BBI `SU^___ 	A 	A 	ANN<a@@@@@@@@	A %'88!! 	NKKYZZZ$$&&&&   N .FFHH	 bKK UW`aaa N N NI1MMMMMMMMN	?5577E QH%PPP 	? 	? 	?LL:A>>>>>>>>	? !"13#.0  *.)>)D)D)F)F [	 [	%Ho"* "a'"**8_EEG <hnMMM ''(<===++D,LMMM%%d&8999,,T-UVVV KK-x~>>>00+"	 1   C ' 1 1111111 2.5DM(+::7CCC#q(O88 '2#'&*	 9    KK 2HNCCCCNN#=x~NNN. %<<$N9@9V+c::\c'.'?*1*E	 =     '<=44!< 
 '~NN1LNN   #8 *9,-.2n.>.>.C@ @D28< <<$N+5'+*=	 =    177'~BBB  
 '6()*..*:*:R*?< <.x8
    /CCC44N#-#"%a&&	 5    )//8>0H0HQ0H0HIII . !"&."2"2R"74 4&x000000  a* 	#>??OQWXXXCCCCCC((7GU[\\\\\    D((000t%))#;<<v@v^`fgggCCCCCC((7GU[\\\\\    DuNN<===KKOPPP )-%##I... 011
 	9KK+Z888joo/@@4=+=+=+?+?@@@2
   	 	 	 	 	 	 	 QKK=OOO	DIIIIII//>>IWWy}}["/M/M/T/T/V/VWWWWWHKK?JJJJ 	D 	D 	DNN?CCCCCCCC	D
 7799999999 	7C  
  
 55== 
  
  
 
 
 	7 44666 --/////////	A??????"3 c*;??BB#D$=$=g$F$FGGGFT`HaHabbb #3 c  	A 	A 	ALL<a@@@@@@@@	A 	D88::;;; ! 	KKMD*++		BB4+ABBBBB  
 	D<<>>???*+++ts   3A7 7
BBB 
B)(B)?7E7 7
F&F!!F&"G7 7
HH6H? ?
I.	I))I.21J$ $
K.KK/FU??
X!	BXX!Y2 2
Y?>Y?[& &
[32[35A0a& &
b0bbBf 
gf<<g,  intervalc           	      	  K   t          j        d           d{V  i }d}| j        r_	 | j                                         g }t          | j        j                                                  D ]?\  }}|j        r| j        	                    |          s(|
                    ||f           @|ri }|D ]S\  }}	|                    d          }
t          |
          dk    r|
d         nd}|                    |d          dz   ||<   Td	                    d
 t          |                                          D                       }t                               dt          |          |           |D ]:\  }}	 |                     |j        |           d{V  d}t)          | dd          }|W|5  | j                            |          }t-          |t.                    r|d         n|r|nd}ddd           n# 1 swxY w Y   || j                            |          }|r|t2          ur|                     |           | j        j        5  d|_        | j                                         ddd           n# 1 swxY w Y   t                               d|j                   |                    |j        d           Q# t>          $ r}|                    |j        d          dz   }|||j        <   ||k    rt                                d||j        |           | j        j        5  d|_        | j                                         ddd           n# 1 swxY w Y   |                    |j        d           n#t                               d|||j        |           Y d}~4d}~ww xY w|retC          d |D                       }t          |          |z
  }|rt                               d||           nt                               d|           n2# t>          $ r%}t                               d|           Y d}~nd}~ww xY wtE          |          D ]%}| j        s nt          j        d           d{V  &| j        ]dS dS )a  Background task that proactively flushes memories for expired sessions.
        
        Runs every `interval` seconds (default 5 min).  For each session that
        has expired according to its reset policy, flushes memories in a thread
        pool and marks the session so it won't be flushed again.

        This means memories are already saved by the time the user sends their
        next message, so there's no blocking delay.
        r  Nr6  r   r5  rD  r   r#   r  c              3   *   K   | ]\  }}| d | V  dS )r   Nr   )r   rW  cs      r   r   z8GatewayRunner._session_expiry_watcher.<locals>.<genexpr>  sA       . .'+q!1

q

. . . . . .r   z)Session expiry: %d sessions to flush (%s)r  Tz%Memory flush completed for session %szeMemory flush gave up after %d attempts for %s: %s. Marking as flushed to prevent infinite retry loop.z&Memory flush failed (%d/%d) for %s: %sc              3   .   K   | ]\  }}|j         d V  dS )r#   N)memory_flushed)r   r   r  s      r   r   z8GatewayRunner._session_expiry_watcher.<locals>.<genexpr>W  sB       # #"a!:J## # # # # #r   z1Session expiry done: %d flushed, %d pending retryzSession expiry done: %d flushedz Session expiry watcher error: %s)#r  r  r  r  _ensure_loadedr   r  r  r  _is_session_expiredr   r   r   r   r   sortedr  r  r  rC  r   r  r   tupler  r  r  _lockr  r  r   r   r  rq  range)r  r  _flush_failures_MAX_FLUSH_RETRIES_expired_entriesrj  r  
_platforms_k_e_parts_plat_plat_summary_cached_agent_cache_lock_cachedr  failures_flushed_failedr   s                        r   rw  z%GatewayRunner._session_expiry_watcher  sU      mB*,m _	'YD"11333#% "&t'9'B'H'H'J'J"K"K : :JC+ ! -AA%HH ! $++S%L9999#  24J"2 I IB!##-0[[1__q		),6NN5!,D,Dq,H
5))$(II . ./5j6F6F6H6H/I/I. . . % %M KKC,--}  
 #3 - -JC,"889I3OOOOOOOOO )-&-d4G&N&N&2!, { {*.*;*?*?*D*D>HRW>X>X0z

ip^z^e^evz{ { { { { { { { { { { { { { {
 )0,0,@,D,DS,I,IM( I]BY-Y-Y 99-HHH "/5 7 737E0 .446667 7 7 7 7 7 7 7 7 7 7 7 7 7 7 C!,   (++E,<dCCCC$   #2#6#6u7G#K#Ka#O<D(89#'999"NN!U (%*:A  
 "&!3!9 ; ;7; 4 $ 2 8 8 : : :; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ,//0@$GGGG"LL H (*<e>NPQ  & $ " # #&6# # #    H ""233h>G O$g   
 =x    D D D?CCCCCCCCD 8__ ' '} EmA&&&&&&&&&& m _	' _	' _	' _	' _	's   EP :8K2>G<0K<H 	 KH 	AK!I<0K<J 	 KJ 	>KP 
N,AN'*!MN'MN'MAN'!P 'N,,A*P 
Q!QQc           
        K   d}d}t          j        d           d{V  | j        r8| j        s7t	          d          D ]&}| j        s dS t          j        d           d{V  'Ft          j                    }t          | j                                                  D ]}| j        s dS | j        |         }||d         k     r'|d         |k    r0t          
                    d	|j        |d                    | j        |= c|d
         }|d         dz   }t                              d|j        ||           	 |                     ||          }	|	s)t          
                    d|j                   | j        |= |	                    | j                   |	                    | j                   |	                    | j                   |	                    | j                   |	                                 d{V }
|
r|	| j        |<   |                     |	           | j        | j        _        | j        |= |                     |j        ddd           t                              d|j                   	 ddlm}  || j                   n# t:          $ r Y nw xY w|	j        r^|	j        sW|                     |j        d|	j         |	j!                   t          
                    d|j        |	j!                   | j        |= n|                     |j        d|	j         |	j!        pd           tE          dd|dz
  z  z  |          }||d<   t          j                    |z   |d<   t                              d|j        |           # t:          $ r}|                     |j        ddtG          |                     tE          dd|dz
  z  z  |          }||d<   t          j                    |z   |d<   t          
                    d|j        ||           Y d}~yd}~ww xY wt	          d          D ]&}| j        s dS t          j        d           d{V  '| j        6dS dS )u  Background task that periodically retries connecting failed platforms.

        Uses exponential backoff: 30s → 60s → 120s → 240s → 300s (cap).
        Stops retrying a platform after 20 failed attempts or if the error
        is non-retryable (e.g. bad auth token).
        r  r  
   Nr  r#   r8  r7  z+Giving up reconnecting %s after %d attemptsr  z"Reconnecting %s (attempt %d/%d)...zGReconnect %s: adapter creation returned None, removing from retry queuerQ  r2  u   ✓ %s reconnected successfullyr   rX  r1  zAReconnect %s: non-retryable error (%s), removing from retry queuer0  zfailed to reconnectr5  z&Reconnect %s failed, next retry in %dsz)Reconnect %s error: %s, next retry in %ds)$r  r  r  r  r  r@  rA  r   r  r  r  r   r  rf  rg  rh  ri  rE  rj  r  rk  r  rl  rs  r  r  r<  rp  rY  r   rm  r=  r:  r;  minr   )r  _MAX_ATTEMPTS_BACKOFF_CAPr   r  r  r  rD  attemptr   r  rY  backoffr  s                 r   rx  z)GatewayRunner._platform_reconnect_watcherl  ss      mBm r	') r + +A= !-**********.""C !7!<!<!>!>?? b b} FF-h7l+++
#}44NNE Z(8   .x8"&x.z*Q.8NG]  
L"228_MMG" !e$N   !28< //0DEEE33D4TUUU--d.@AAA44T5]^^^$+OO$5$5555555G .29h/>>wGGG8<,5 28<<<$N+6'+*.	 =    $Ex~VVV!YYYYYY33DMBBBB( ! ! ! D! #2 7;X  @@ (/6+2+C.5.I	 A    #NN c (0K   !% 6x @ @ @@ (/9+2+C.5.I.bMb	 A    '*"gk0B*C\&R&RG/6D,151A1AG1KD."KK H (   !   88 '1#'&)!ff	 9    ""gk(:";\JJG'.D$)-)9)9G)CD&NNC 7         2YY ' '} FFmA&&&&&&&&&&e m r	' r	' r	' r	' r	'sF   9A N:C:N5JN
JNJC*N
PBPPr  rL  r  r  c                    K   |rd _         | _        | _         j         j         d{V  dS d fd}t	          j         |                       _         j         d{V  dS )z-Stop the gateway and disconnect all adapters.TNr   c                  r
  K   t                               dj        rdnd           d_        d_                                         d {V  j        }                     |            d {V \  }}|rt                               d| 	                                           
                    j        rdnd           t          j                                                    d	z   }j        rt          j                                                    |k     r_                    d
           t          j        d           d {V  j        r)t          j                                                    |k     _j        rUj        rN	                                  d {V  n2# t&          $ r%}t                               d|           Y d }~nd }~ww xY w                    |           t-          j                                                  D ]\  }}	 |                                 d {V  n8# t&          $ r+}t                               d|j        |           Y d }~nd }~ww xY w	 |                                 d {V  t                               d|j                   # t&          $ r+}t                               d|j        |           Y d }~d }~ww xY wt-          j                  D ] }|j        u r|                                 !j                                          j                                          j                                          j!                                          j"                                          tG          d          rj$                                          j%        &                                 	 ddl'm(} |)                                 n# t&          $ r Y nw xY w	 ddl*m+}	  |	             n# t&          $ r Y nw xY w	 ddl,m-}
  |
             n# t&          $ r Y nw xY wddl.m/}  |             |s.	 t`          dz  1                                 n*# t&          $ r Y nw xY wt                               d           |r42                    tM          |3                                                     j        r!j4        rtj          _6        j7        pd_7        d_                            dj7                   t                               d           d S )NzStopping gateway%s...z for restartrj   FTzYGateway drain timed out after %.1fs with %d active agent(s); interrupting remaining work.zGateway restartingzGateway shutting down      @r  r  z-Failed to launch detached gateway restart: %su'   ✗ %s background-task cancel error: %su   ✓ %s disconnectedu   ✗ %s disconnect error: %sr  r   re  )cleanup_all_environments)cleanup_all_browsers)remove_pid_filerO  u   Skipping .clean_shutdown marker — drain timed out with interrupted agents; next startup will suspend recently active sessions.zGateway restart requestedstoppedzGateway stopped)8r  r  r^  r  r]  r  r[  r  r  rJ  r  r  r  r@  r  r]  r  r`  r  r   r9  r  r   rs  r  cancel_background_tasksr  r   r>  r  rb  cancelr  r  r  r  r  r  r   r  rf  kill_alltools.terminal_toolr  tools.browser_toolr  r\  r  r   touchr  r  ra  r   r\  r  )r0   r[  r  interrupt_deadliner  r  r   _taskrf  r  r  r  r  s               r   
_stop_implz&GatewayRunner.stop.<locals>._stop_impl  s`     KK'"&"9Ar   "DM!DN ::<<<<<<<<<1G-1-F-Fw-O-O'O'O'O'O'O'O$M9 -o--//  
 ..,0,C`((I`   &-%=%?%?%D%D%F%F%L"* -w/G/I/I/N/N/P/PSe/e/e//
;;;!-,,,,,,,,, * -w/G/I/I/N/N/P/PSe/e/e & U4+A UU??AAAAAAAAAA  U U ULL!PRSTTTTTTTTU **=999%)$-*=*=*?*?%@%@ 	S 	S!'_!99;;;;;;;;;;  _ _ _LL!JHN\]^^^^^^^^_S!,,.........KK 5x~FFFF  S S SLL!>PQRRRRRRRRS d455  DO++"((***M!!! &&((("((***#))+++t^,, *!''))) $$&&&CCCCCC ))++++   HHHHHH((****   CCCCCC$$&&&&    766666O  
!$55<<>>>>    D '    R66s=;M;M;O;O7P7PQQQ& U4+D U"C$($5$T9T!"DN''	43DEEEKK)*****s   
F% %
G/GGH33
I(=!I##I(,:J''
K1!KKO/ /
O<;O< P 
PP"P3 3
Q ?Q Q3 3
R ?R r  )r^  r`  ra  rb  r  r  )r  rL  r  r  r  s   `    r   rB  zGatewayRunner.stop  s        	8&*D#%5D"(7D%?&/!!!!!!!Ft	+ t	+ t	+ t	+ t	+ t	+l "-jjll;;or   c                 H   K   | j                                          d{V  dS )zWait for shutdown signal.N)r  waitr  s    r   wait_for_shutdownzGatewayRunner.wait_for_shutdownt	  s3      "'')))))))))))r   c                    t          |d          rnt          |j        t                    rT|j                            d| j        j                   |j                            dt          | j        dd                     |t          j	        k    r9ddl
m}m}  |            st                              d           dS  ||          S |t          j        k    r9dd	lm}m}  |            st                              d
           dS  ||          S |t          j        k    r9ddlm}m}  |            st                              d           dS  ||          S |t          j        k    r9ddlm}	m}
  |
            st                              d           dS  |	|          S |t          j        k    r9ddlm}m}  |            st                              d           dS  ||          S |t          j        k    r9ddl m!}m"}  |            st                              d           dS  ||          S |t          j#        k    r9ddl$m%}m&}  |            st                              d           dS  ||          S |t          j'        k    r9ddl(m)}m*}  |            st                              d           dS  ||          S |t          j+        k    r9ddl,m-}m.}  |            st                              d           dS  ||          S |t          j/        k    r9ddl0m1}m2}  |            st                              d           dS  ||          S |t          j3        k    r9ddl4m5}m6}  |            st                              d           dS  ||          S |t          j7        k    r9ddl8m9}m:}  |            st                              d           dS  ||          S |t          j;        k    r9ddl<m=}m>}  |            st                              d            dS  ||          S |t          j?        k    r9dd!l@mA}mB}  |            st                              d"           dS  ||          S |t          jC        k    r9dd#lDmE}mF}   |             st                              d$           dS  ||          S |t          jG        k    r9dd%lHmI}!mJ}"  |"            st                              d&           dS  |!|          S |t          jK        k    rBdd'lLmM}#mN}$  |$            st                              d(           dS  |#|          }%| |%_O        |%S |t          jP        k    r9dd)lQmR}&mS}'  |'            st                              d*           dS  |&|          S |t          jT        k    r9dd+lUmV}(mW})  |)            st                              d,           dS  |(|          S dS )-z.Create the appropriate adapter for a platform.extrar  r  Fr   )TelegramAdaptercheck_telegram_requirementsz+Telegram: python-telegram-bot not installedN)DiscordAdaptercheck_discord_requirementsz!Discord: discord.py not installed)WhatsAppAdaptercheck_whatsapp_requirementsz8WhatsApp: Node.js not installed or bridge not configured)SlackAdaptercheck_slack_requirementszGSlack: slack-bolt not installed. Run: pip install 'hermes-agent[slack]')SignalAdaptercheck_signal_requirementsz8Signal: SIGNAL_HTTP_URL or SIGNAL_ACCOUNT not configured)HomeAssistantAdaptercheck_ha_requirementsz:HomeAssistant: aiohttp not installed or HASS_TOKEN not set)EmailAdaptercheck_email_requirementszQEmail: EMAIL_ADDRESS, EMAIL_PASSWORD, EMAIL_IMAP_HOST, or EMAIL_SMTP_HOST not set)
SmsAdaptercheck_sms_requirementszJSMS: aiohttp not installed or TWILIO_ACCOUNT_SID/TWILIO_AUTH_TOKEN not set)DingTalkAdaptercheck_dingtalk_requirementszLDingTalk: dingtalk-stream not installed or DINGTALK_CLIENT_ID/SECRET not set)FeishuAdaptercheck_feishu_requirementsz?Feishu: lark-oapi not installed or FEISHU_APP_ID/SECRET not set)WecomCallbackAdapter!check_wecom_callback_requirementsz*WeComCallback: aiohttp/httpx not installed)WeComAdaptercheck_wecom_requirementsz;WeCom: aiohttp not installed or WECOM_BOT_ID/SECRET not set)WeixinAdaptercheck_weixin_requirementsz*Weixin: aiohttp/cryptography not installed)MattermostAdaptercheck_mattermost_requirementszJMattermost: MATTERMOST_TOKEN or MATTERMOST_URL not set, or aiohttp missing)MatrixAdaptercheck_matrix_requirementsz\Matrix: mautrix not installed or credentials not set. Run: pip install 'mautrix[encryption]')APIServerAdaptercheck_api_server_requirementsz!API Server: aiohttp not installed)WebhookAdaptercheck_webhook_requirementszWebhook: aiohttp not installed)BlueBubblesAdaptercheck_bluebubbles_requirementsz`BlueBubbles: aiohttp/httpx missing or BLUEBUBBLES_SERVER_URL/BLUEBUBBLES_PASSWORD not configured)	QQAdaptercheck_qq_requirementszIQQBot: aiohttp/httpx missing or QQ_APP_ID/QQ_CLIENT_SECRET not configured)Xr  r   r  r!  
setdefaultr  r  r   r   TELEGRAMgateway.platforms.telegramr  r  r  r  DISCORDgateway.platforms.discordr  r  WHATSAPPgateway.platforms.whatsappr  r  SLACKgateway.platforms.slackr  r  SIGNALgateway.platforms.signalr  r  HOMEASSISTANTgateway.platforms.homeassistantr  r  EMAILgateway.platforms.emailr  r  SMSgateway.platforms.smsr  r  DINGTALKgateway.platforms.dingtalkr  r  FEISHUgateway.platforms.feishur  r  WECOM_CALLBACK gateway.platforms.wecom_callbackr  r  WECOMgateway.platforms.wecomr  r  WEIXINgateway.platforms.weixinr  r  
MATTERMOSTgateway.platforms.mattermostr  r  MATRIXgateway.platforms.matrixr  r  
API_SERVERgateway.platforms.api_serverr  r  WEBHOOKgateway.platforms.webhookr  r  gateway_runnerBLUEBUBBLESgateway.platforms.bluebubblesr  r  QQBOTgateway.platforms.qqbotr  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  r  r  r  r  r  r  r  r  r  r  r  r   r  r  r  r  s*                                             r   rf  zGatewayRunner._create_adapterx	  s    67## 	
6<(F(F 	L##)3   L##*%?GG  
 x(((________..00 LMMMt"?6***)))\\\\\\\\--// BCCCt!>&)))***________..00 YZZZt"?6***''VVVVVVVV++-- hiiit<'''((YYYYYYYY,,.. YZZZt =(((///cccccccc((** [\\\t''///''VVVVVVVV++-- rssst<'''%%PPPPPPPP))++ klllt:f%%%***________..00 mnnnt"?6***((YYYYYYYY,,.. `aaat =(((000        5466 KLLLt''///''VVVVVVVV++-- \]]]t<'''((YYYYYYYY,,.. KLLLt =(((,,,eeeeeeee0022 klllt$$V,,,((YYYYYYYY,,.. }~~~t =(((,,,dddddddd0022 BCCCt##F+++)))\\\\\\\\--// ?@@@t$nV,,G%)G"N---hhhhhhhh1133    B  C  C  Ct%%f---''PPPPPPPP((** jkkkt9V$$$tr   c                 p   |j         t          j        t          j        fv rdS |j        }|sdS i t          j        dt          j        dt          j        dt          j        dt          j	        dt          j
        dt          j        d	t          j        d
t          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        d}i t          j        dt          j        dt          j        dt          j        dt          j	        dt          j
        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        dt          j        d t          j        d!t          j        d"}|                    |j         d#          }|r+t-          j        |d#                                          d$v rdS |j         r|j         j        nd#}| j                            ||          rdS t-          j        |                    |j         d#          d#                                          }t-          j        d%d#                                          }|s+|s)t-          j        d&d#                                          d$v S t;                      }	|r2|	                    d' |                    d(          D                        |r2|	                    d) |                    d(          D                        d*|	v rdS |h}
d+|v r.|
                     |                    d+          d,                    |j         t          j        k    rt;                      }|	D ]$}|                    tC          |                     %|r|}	|
                    tC          |                     tE          |          }|r|
                     |           tG          |
|	z            S )-ao  
        Check if a user is authorized to use the bot.
        
        Checks in order:
        1. Per-platform allow-all flag (e.g., DISCORD_ALLOW_ALL_USERS=true)
        2. Environment variable allowlists (TELEGRAM_ALLOWED_USERS, etc.)
        3. DM pairing approved list
        4. Global allow-all (GATEWAY_ALLOW_ALL_USERS=true)
        5. Default: deny
        TFr(  r)  r*  r+  r,  r.  r/  r0  r1  r2  r3  r4  r5  r6  r7  r8  r?  r@  rA  rB  rC  rD  rE  rF  rG  rH  rI  rJ  rK  rL  rM  rN  rj   r;  r9  r:  c              3   f   K   | ],}|                                 |                                 V  -d S rh  r   r   uids     r   r   z4GatewayRunner._is_user_authorized.<locals>.<genexpr>e
  s<      ccsWZW`W`WbWbcsyy{{ccccccr   ,c              3   f   K   | ],}|                                 |                                 V  -d S rh  r  r  s     r   r   z4GatewayRunner._is_user_authorized.<locals>.<genexpr>g
  s<      aasUXU^U^U`U`asyy{{aaaaaar   *r   r   )$r  r   r  r	  user_idr  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r   r   r   r   r  is_approvedr   r   r  r   r   r   r   r}  )r  r  r  platform_env_mapplatform_allow_all_mapplatform_allow_all_varplatform_nameplatform_allowlistglobal_allowlistallowed_ids	check_idsnormalized_allowed_ids
allowed_idnormalized_user_ids                 r   _is_user_authorizedz!GatewayRunner._is_user_authorized
  s     ?x5x7GHHH4. 	5
7
5
 7
 N1	

 O3
 N1
 L-
 !;
 O3
 7
 O3
 N1
 #%C
 O3
  "=
  N.!
$"
9"
7"
 9"
 N3	"

 O5"
 N3"
 L/"
 !="
 O5"
 9"
 O5"
 N3"
 #%E"
 O5"
  "?"
  N0!"
( "8!;!;FOR!P!P! 	bi0F&K&K&Q&Q&S&SWk&k&k4 28H--b))-AA 	4  Y'7';';FOR'P'PRTUU[[]]9%<bAAGGII! 	\*: 	\96;;AACCG[[[ ee 	dcc6H6N6Ns6S6Scccccc 	baa6F6L6LS6Q6Qaaaaaa +4I	'>>MM'--,,Q/000 ?h///%(UU") Y Y
&--.KJ.W.WXXXX% 54:7CCDDD!?!H!H! 20111I+,,,r   c                 v    t          | dd          }|r%t          |d          r|                    |          S dS )z=Return how unauthorized DMs should be handled for a platform.r  Nget_unauthorized_dm_behaviorpair)r   r  r'  )r  r  r  s      r   _get_unauthorized_dm_behaviorz+GatewayRunner._get_unauthorized_dm_behavior
  sH    x.. 	Agf&DEE 	A66x@@@vr   c                 +  K   |j         }t          |dd          rn|j        't                              d|j        j                   dS |                     |          snt                              d|j        |j	        |j        j                   |j
        dk    r/|                     |j                  dk    r|j        r|j        j        nd}| j                            ||j                  rdS | j                            ||j        |j	        pd	          }|rM| j                            |j                  }|r+|                    |j        d
| d| d| d           d{V  nb| j                            |j                  }|r!|                    |j        d           d{V  | j                            ||j                   dS |                     |          }t          | di           }|                    |          r|j        pd	                                }|                                }	|	dv rd}
n	|	dv rd}
n|}
|
rt0          dz  }	 |                    d          }|                    |
           |                    |           n7# t8          $ r*}t                              d|           d| cY d}~S d}~ww xY w|                    |d           t=          |
          dk    r|
n|
dd         dz   }d| dS t?          tA          j!        dd                    }| j"                            |d          }|| j#        v r|rtI          j$                    |z
  }| j#                            |          }t?          d          }d	}|rtK          |d           r	 |&                                }|                    d!t?          d                    }d"|                    d#d           d$|d%d&|                    d'd           d(|                    d)d           }n# tN          $ r Y nw xY w|dk    rtQ          |d*z  d+          nt?          d          }|tR          uo|dk    r||k    p||k    }|ret                              d,|dd-         ||||           | j#        |= | j"                            |d           | j*                            |d           || j#        v rU|                                d.k    r| +                    |           d{V S dd/l,m-} |                                }|r ||          nd}|r&|j.        d0k    r| /                    |           d{V S |r|j.        d1k    r| j#                            |          }|r|tR          ur|0                    d2           | j                            |j                  }|r%tK          |d3          r|1                    |           | j2                            |d           || j#        v r| j#        |= t          3                    d4|dd                    d5S |r|j.        d6k    r| j#                            |          }|r|tR          ur|0                    d7           | j                            |j                  }|r%tK          |d3          r|1                    |           | j2                            |d           || j#        v r| j#        |= | 4                    |           d{V S |                                d8v r|5                                                                }|sd9S | j                            |j                  }|r6dd:l6m7}m8}  |||j9        |j         |j:        |j;        ;          }||j2        |<   d<S |r|j.        d=k    rd>S |rJ|j.        d?v rA|j.        d@k    r| <                    |           d{V S | =                    |           d{V S |r&|j.        dAk    r| >                    |           d{V S |j?        tp          j@        k    r\t                              dB|dd                    | j                            |j                  }|rt          |j2        ||           dS t?          tA          j!        dCdD                    } | j"                            |d          }!|j        t          jC        k    r|j?        tp          j9        k    r| dk    r|!rtI          j$                    |!z
  | k    rst                              dEtI          j$                    |!z
  |dd                    | j                            |j                  }|rt          |j2        ||dFG           dS | j#                            |          }|tR          u r|                                d1k    r6|| j#        v r| j#        |= t          3                    dH|dd                    dIS | j                            |j                  }|rt          |j2        ||dFG           dS | jD        rn| E                                r| F                    ||           | E                                rdJ| G                                 dKndL| G                                 dMS t                              dN|dd                    |0                    |j                   || j2        v r| j2        |xx         dO|j        z   z  cc<   n|j        | j2        |<   dS |                                }"ddPl,mH}#m-}$ |"ri|"|#v re| jI        J                    dQ|" |j        r|j        j        nd	|j        |"|5                                                                dR           d{V  |"r |$|"          nd}%|%r|%j.        n|"}&|&d6k    r| 4                    |           d{V S |&dSk    r| K                    |           d{V S |&dTk    r| L                    |           d{V S |&dUk    r| M                    |           d{V S |&d.k    r| +                    |           d{V S |&d0k    r| /                    |           d{V S |&d1k    r| N                    |           d{V S |&dVk    r| O                    |           d{V S |&dWk    r| P                    |           d{V S |&dXk    r| Q                    |           d{V S |&dYk    r| R                    |           d{V S |&d=k    r| S                    |           d{V S |&dZk    r| T                    |           d{V S |&d[k    r| U                    |           d{V S |&d\k    r	 dd]lVmW}'mX}( |5                                                                }) |'|)          }* |(d^|)|d_|* `          |_        |j        sdaS d}&n6# tN          $ r)}t          Y                    db           dc| cY d}~S d}~ww xY w|&ddk    r| Z                    |           d{V S |&dek    r| [                    |           d{V S |&dfk    r| \                    |           d{V S |&dgk    r| ]                    |           d{V S |&dhk    r| ^                    |           d{V S |&dik    r| _                    |           d{V S |&djk    r| `                    |           d{V S |&d@k    r| <                    |           d{V S |&dkk    r| =                    |           d{V S |&dlk    r| a                    |           d{V S |&dmk    r| b                    |           d{V S |&dnk    r| c                    |           d{V S |&dok    r| d                    |           d{V S |&dpk    r| e                    |           d{V S |&dqk    r| f                    |           d{V S |&dAk    r| >                    |           d{V S |&drk    r| g                    |           d{V S |&dsk    r| h                    |           d{V S | jD        rdL| G                                 dtS |"r:t          | jj        t                    r| jj                            dui           pi }+nt          | jj        dui           pi }+t          |+t                    si }+|"|+v r|+|"         },|,                    dv          dwk    r|,                    dxd	          }-|-r	 t          jm        |-t          jn        jo        t          jn        jo        y           d{V }.t          jp        |.q                                d-z           d{V \  }/}0|/p|0r                                                                }1|1r|1nd{S # t          js        $ r Y d|S tN          $ r}d}| cY d}~S d}~ww xY wd~|" dS |,                    dv          dk    r|,                    dd	                                          }2|2rx|2t                    d(          r|2nd(|2 }2|2u                    d(          }3|5                                                                }4|2 d|4                                 |_        |3}"nd~|" dS d~|" dS |"r	 ddlvmw}5  |5|"                    dd                    }6|6re|5                                                                }4ddll}7 |6|4          }8|7x                    |8          r|8 d{V }8|8rt          |8          ndS n2# tN          $ r%}t                              d|           Y d}~nd}~ww xY w|"rE	 ddlVmz}9mX}(m{}:  |9            }; |:|"          }<|<|;|<                             dd	          }=|j        r|j        j        nd}>|>r|=rddl|m}}? |= |?|>          v r	d|= d|> dS |5                                                                }) |(|<|)|          }@|@r|@|_        n`t          |"          }A|Ar|AS |"                    dd          |#vr5t                              d|"|j        r|j        j        nd           d|" dS n2# tN          $ r%}t                              d|           Y d}~nd}~ww xY wtR          | j#        |<   tI          j$                    | j"        |<   	 |                     |||           d{V 	 | j#                            |          tR          u r| j#        |= | j"                            |d           S # | j#                            |          tR          u r| j#        |= | j"                            |d           w xY w)a  
        Handle an incoming message from any platform.
        
        This is the core message processing pipeline:
        1. Check user authorization
        2. Check for commands (/new, /reset, etc.)
        3. Check for running agent and interrupt if needed
        4. Get or create session
        5. Build context for agent
        6. Run agent conversation
        7. Return response
        internalFNz(Ignoring message with no user_id from %sz Unauthorized user: %s (%s) on %sr:  r(  rD  rj   z;Hi~ I don't recognize you yet!

Here's your pairing code: `z5`

Ask the bot owner to run:
`hermes pairing approve r  r   z<Too many pairing requests right now~ Please try again later!r  )approver=  y)denynon.update_response.tmpz#Failed to write update response: %su/   ✗ Failed to send response to update process: r     …u
   ✓ Sent `z` to the update process.ro     r   infr  seconds_since_activityz | last_activity=last_activity_descr  .0fzs ago) | iteration=r  r   r  r  i   zWEvicting stale _running_agents entry for %s (age: %.0fs, idle: %.0fs, timeout: %.0fs)%sr  statusresolve_commandrL  rB  Stop requestedr   u@   STOP for session %s — agent interrupted, session lock released+   ⚡ Stopped. You can continue this session.newzSession reset requested)r   qzUsage: /queue <prompt>r   r   )rT  r   r  r  channel_promptzQueued for the next turn.r\   u=   Agent is running — wait or /stop first, then switch models.)r,  r.  r,  
backgrounduF   PRIORITY photo follow-up for session %s — queueing without interrupt&HERMES_TELEGRAM_FOLLOWUP_GRACE_SECONDSz3.0uV   Telegram follow-up arrived %.2fs after run start for %s — queueing without interruptT)
merge_textu7   HARD STOP (pending) for session %s — sentinel cleareduE   ⚡ Force-stopped. The agent was still starting — session unlocked.r  r  r  r  z!PRIORITY interrupt for session %sr   )GATEWAY_KNOWN_COMMANDSr;  zcommand:)r  r  r   r   helpcommandsprofile	reasoningrw  verboseyolor[   personalityplan)build_plan_pathbuild_skill_invocation_messagez/planzlSave the markdown plan with write_file to this exact relative path inside the active workspace/backend cwd: )task_idruntime_notez'Failed to load the bundled /plan skill.zFailed to prepare /plan commandzFailed to enter plan mode: retryundosethomecompressusageinsightsz
reload-mcpr.  r  r  titleresumebranchrollbackbtwvoicez) and is not accepting new work right now.quick_commandsrA  execr   )r  r  r0   zCommand returned no output.zQuick command timed out (30s).zQuick command error: zQuick command '/z' has no command defined.aliasr  z' has no target defined.z4' has unsupported type (supported: 'exec', 'alias').)get_plugin_command_handlerr   r   z.Plugin command dispatch failed (non-fatal): %s)get_skill_commandsrO  resolve_skill_command_keyr   )get_disabled_skill_namesr  r   z** skill is disabled for z(.
Enable it with: `hermes skills config`rP  uO   Unrecognized slash command /%s from %s — replying with unknown-command noticerI  zUnknown command `/zl`. Type /commands to see what's available, or resend without the leading slash to send as a regular message.z*Skill command check failed (non-fatal): %s)r  r   r  r  r  r  r   r%  r  	user_namer8  r)  r  _is_rate_limitedgenerate_coders  r   r  r9  _record_rate_limitr  rT  r   get_commandr   with_suffixr  r   r  r   r   r  r   r   rX  r  r@  r  r  r   maxr  r  _handle_status_commandhermes_cli.commandsr;  r   _handle_restart_commandrY  r   r  r  _handle_reset_commandget_command_argsr  r   r   TEXTr  rA  _handle_approve_command_handle_deny_command_handle_background_commandr   r   r   r   r  r]  rU  r  rS  rE  r  ro  _handle_help_command_handle_commands_command_handle_profile_command_handle_stop_command_handle_reasoning_command_handle_fast_command_handle_verbose_command_handle_yolo_command_handle_model_command_handle_provider_command_handle_personality_commandagent.skill_commandsrN  rO  	exception_handle_retry_command_handle_undo_command_handle_set_home_command_handle_compress_command_handle_usage_command_handle_insights_command_handle_reload_mcp_command_handle_update_command_handle_debug_command_handle_title_command_handle_resume_command_handle_branch_command_handle_rollback_command_handle_btw_command_handle_voice_commandr   r  r!  r  create_subprocess_shellr	  PIPEwait_forcommunicatedecodeTimeoutErrorr   lstripr  rb  iscoroutiner   rc  rd  r   re  r  _handle_message_with_agent)Br  r   r  r  coder   
_quick_key_update_promptsrz  r  response_textresponse_pathtmpr  r  _raw_stale_timeout	_stale_ts
_stale_age_stale_agent_stale_idle_stale_detail_sa	_wall_ttl_should_evict_resolve_cmd_inner_evt_cmd_cmd_def_innerr  queued_text_ME_MTqueued_event_telegram_followup_grace_started_atr   rE  _resolve_cmd_cmd_def	canonicalrN  rO  user_instruction	plan_pathr^  qcmdexec_cmdprocr  r  rJ  r  target_command	user_argsrb  plugin_handler_aior=  rc  rd  
skill_cmdscmd_key_skill_namer  _get_plat_disabledr  _unavail_msgsB                                                                     r   rh  zGatewayRunner._handle_message
  s       5*e,, *	^#
 LLCV_EZ[[[4))&11 !	NN=v~vO_agapavwww4''D,N,Nv,_,_ci,i,i9? W 5 5i %66}fnUU  4)77!6>63C3Ir   Y"m//@@G %ll"NO:>O O 8EO O HLO O O         #m//@@G %ll"N6         &99-XXX4 11&99
!$(@"EEz** 	D:#**,,C##%%C((( #&& # # D ,/A AQ'33F;;CNN=111KK.... Q Q QNN#H!LLLPQPPPPPPPPQ  ##J555),]););r)A)A}UXVXUXGY\aGaCECCCC #29-CT#J#JKK+//
A>>	---)-y0J/33J??L  ,,KM 
6L M M 
	&;;==C"%''*BE%LL"Q"QKeCGG4H),T,T e e'4e e'*ww/?'C'Ce eFIggN^`aFbFbe e "M
 !   D
 ?QST>T>T.3T:::Z_`eZfZfI$;; '!+Q?Q0Q .!I-	   	8BssOZ&	   (4'++J===!%%j$777---  ""h..!88????????? RQQQQQ((**H=EO//9994N A."5"B"B!99%@@@@@@@@@  E."5"?"? $ 4 8 8 D D  >]:Q%Q%Q!++,<===-++FO<< <ww0EFF <//
;;;&**:t<<<!555,Z8^`jknlnkn`opppDD  ?."5">"> $ 4 8 8 D D  G]:Q%Q%Q!++,EFFF-++FO<< <ww0EFF <//
;;;&**:t<<< !555,Z8!77>>>>>>>>>   ""n44#4466<<>>" 433-++FO<< 	I^^^^^^^^#&3(%(X$|#(#3',';$ $ $L =IG-j922  W."5"@"@VV  >."59L"L"L!&)33!%!=!=e!D!DDDDDDDD!66u=========  D."5"E"E!<<UCCCCCCCCC![%666egqrusurugvwww-++FO<< ^/0I:W\]]]t',	BEJJ( ($ 155j!DDK8#444&+*:::,q00 1Y[[;.3KKKlIKK+-ssO  
 -++FO<< /1"#'	    t 044Z@@M 777$$&&&00!T%999 0<KK Y[efigifi[jkkkbb -++FO<< /1"#'	    t~ 3355 L88UKKK 7799ws4#=#=#?#?ssssv4+E+E+G+Gvvv
 LL<j"oNNN##EJ///T333&z222dUZ6GG22225:Z&z24 ##%%
 	`_______ 	w"888*//"6W"6"65;_LFO11"!>"..006688	9 9          -4=<<(((%-:HMM7	33E:::::::::225999999999
""66u=========	!!55e<<<<<<<<<  44U;;;;;;;;;	!!55e<<<<<<<<<225999999999##77>>>>>>>>>225999999999	!!55e<<<<<<<<<22599999999933E:::::::::
""66u=========%%99%@@@@@@@@@9````````#(#9#9#;#;#A#A#C#C +O,<==	;;$&PDMP P  
 z EDD 		 9 9 9  !BCCC8Q888888889 33E:::::::::225999999999	!!66u=========
""66u=========33E:::::::::
""66u=========$$88?????????	!!55e<<<<<<<<<225999999999  44U;;;;;;;;;33E:::::::::33E:::::::::  44U;;;;;;;;;  44U;;;;;;;;;
""66u=========$$88?????????11%88888888833E:::::::::> 	mlT%?%?%A%Allll  '	l$+t,, R!%1A2!F!F!L"!(6F!K!K!Qrnd33 $!#.((%g.88F##v--#xx	266H U?)0)H ('.'9'>'.'9'>* * * $ $ $ $ $ $D
 4;3CDDTDTDVDV`b3c3c3c-c-c-c-c-c-cNFF&,&6%>%>%@%@%F%F%H%HF-3#V669VV&3 D D D#C#C#C( ? ? ?#>1#>#>>>>>>>?  U'TTTTXXf%%00!XXh3399;;F T+1+<+<S+A+A!S|6||)/s););$)$:$:$<$<$B$B$D$D	(.%<%<%<%<%B%B%D%D
"0  T'SSSSkgkkkk  	RRIIIIII "<!;GOOCQT<U<U!V!V! ; % 6 6 8 8 > > @ @I****+^I66F''// .'-*0:3v;;;d:;  R R RMqQQQQQQQQR  :	N9N         
 0/11
33G<<&
 #-W"5"9"9&""E"EK5;_NFO11$E  dddddd&*<*<e*L*L*LLL!J !J !Ju !J !J !J (-'='='?'?'E'E'G'G$88!1:  C  )%(

 $<G#D#DL# ,++ sC008NNNC#5;_MFO11#	  5 5 5 5  N N NI1MMMMMMMMN ,CZ(.2ikk
+		:88
SSSSSSSSS #''
337NNN(4#''
D9999 #''
337NNN(4#''
D9999s   ?J 
K!K KK*BP- -
P:9P:<Ax x 
y"y yyE(BAH HAH,H	AH,HAH'H!AH,H'AH,K?BAN N
AN;NAN6N6AN;OA2AS P5AAS RAAS S
ATSAS>S>ATT1AV VAAWr  c                	  "#K   |pg }|j         pd"|j        dk    o|j        ot          | j        dd           }|r|j        rd|j         d" "|j        rg }g }t          |j                  D ]\  }}|t          |j	                  k     r|j	        |         nd}	|	
                    d          s|j        t          j        k    r|                    |           |	
                    d          s|j        t          j        t          j        fv r|                    |           |r|                     "|           d	{V "|r|                     "|           d	{V "d
}
t'          "fd|
D                       r| j                            |j                  }|j        r	d|j        ind	}|rP	 d}|                                 r|dz  }|                    |j        ||           d	{V  n# t4          $ r Y nw xY w|j        ro|j        t          j        k    rYdd	l}h d}t          |j                  D ];\  }}|t          |j	                  k     r|j	        |         nd}	|	dv rYdd	l}|j                            |          d                                          }||v rd}	n|!                    |          \  }}|r|}	|	
                    d          sdd	l}dd	l"}|j        #                    |          }|$                    dd          }t          |          dk    r|d         n|}|%                    dd|          }|	
                    d          r
d| d| d}n	d| d| d }| d!" "=t          |d"d	          r;|j&        r4|j'        d	d#         #t'          #fd$|D                       }|sd%# d&" "d'"v r	 dd(l(m)} dd)l*m+} t:          j,                            d*t:          j        -                    d+                    } || j.        | j/        pd,          } |"|||-           d	{V }|j0        r^| j                            |j                  } | r;|                     |j        d.1                    |j2                  pd/           d	{V  d	S |j3        r|j4        "n2# t4          $ r%}!tj          6                    d0|!           Y d	}!~!nd	}!~!ww xY w"S )1a  Prepare inbound event text for the agent.

        Keep the normal inbound path and the queued follow-up path on the same
        preprocessing pipeline so sender attribution, image enrichment, STT,
        document notes, reply context, and @ references all behave the same.
        rj   r:  r  F[] r   r   N)No STT providerzSTT is disabledzcan't listenVOICE_TOOLS_OPENAI_KEYc              3       K   | ]}|v V  	d S rh  r   )r   markermessage_texts     r   r   z>GatewayRunner._prepare_inbound_message_text.<locals>.<genexpr>  s(      NN&v-NNNNNNr   r<  u
  🎤 I received your voice message but can't transcribe it — no speech-to-text provider is configured.

To enable voice: install faster-whisper (`pip install faster-whisper` in the Hermes venv) and set `stt.enabled: true` in config.yaml, then /restart the gateway.z@

For full setup instructions, type: `/skill hermes-agent-setup`r  r   >   .md.cfg.csv.ini.log.txt.xml.yml.toml.yamlr   )rj   zapplication/octet-streamr#   z
text/plain)zapplication/text/r   r5  r6  z	[^\w.\- ]r  z![The user sent a text document: 'zC'. Its content has been included below. The file is also saved at: r   z[The user sent a document: 'z'. The file is saved at: z3. Ask the user what they'd like you to do with it.]r  reply_to_text  c              3      K   | ]<}|                     d           dv dd         |                     d          pdv V  =dS )r  )r  r  toolN   r  rj   rM  )r   r  reply_snippets     r   r   z>GatewayRunner._prepare_inbound_message_text.<locals>.<genexpr>P  sd       # #776??&CCC dsd#	(:(:(@bACCCC# #r   z[Replying to: "z"]

r   )#preprocess_context_references_asyncget_model_context_lengthr/   ~)r]   )r.   context_lengthallowed_rootr   zContext injection refused.z(@ context reference expansion failed: %s)7rT  r8  r<  r   r  rg  r   r   r   r   r   r   r   r   r   VOICEAUDIO_enrich_message_with_vision"_enrich_message_with_transcriptionr   rs  r   r  r  r  r9  r   DOCUMENT	mimetypesr   r   splitextr   
guess_typerebasenamer   subreply_to_message_idr  agent.context_referencesr  agent.model_metadatar  r   rb  _model	_base_urlblockedr   warningsexpandedrF  r  r  )$r  r   r  r  _is_shared_threadimage_pathsaudio_pathsr   r   r   _stt_fail_markers_stt_adapter	_stt_meta_stt_msg
_mimetypes_TEXT_EXTENSIONS_os2_extguessedr   _os_rer  r   display_namecontext_notefound_in_historyr  r  _msg_cwd_msg_ctx_len_ctx_result_adapterr   r  r  s$                                     @@r   _prepare_inbound_message_textz+GatewayRunner._prepare_inbound_message_text  s      -Rz'R $ L LDK)CUKKK 	
  	B!1 	BAv/AA<AAL 0	!KK$U%566 - -401C8I4J4J0J0J)!,,PR##H-- -1C{GX1X1X&&t,,,##H-- -1CHY[f[lGm1m1m&&t,,, %)%E%E & &            
   !%)%L%L & &            %! NNNN<MNNNNN !#'=#4#4V_#E#ELCICS ]f.> ? ?Y]I# !!!= %  $4466 q (,p p"."3"3 & ()2 #4 # #        
  ) ! ! ! D!  '	C 2k6J J J****yyy$U%566 #C #C401C8I4J4J0J0J)!,,PR<<<%%%%9--d33A6<<>>D/// ,%/%:%:4%@%@
" ,$+E''(ABB         8,,T22 sA..+.u::??uQxx"ww|S,GG##G,, >L > >6:> > > !LM| M M15M M M !
 #/BBLBB5/400 	UU5N 	U!/5M" # # # #"# # #    
 $ UTTTlTT,NXXXXXXIIIIII:>>."':L:LS:Q:QRR77K!^1r      %H$G  #/!)	% % %       &  #}00AAH &mm"N IIk&:;;[?[          4' 7#.#6L N N NGMMMMMMMMN s1   3>G2 2
G?>G?CR6 'R6 6
S% S  S%r  c                 /  K   t          j                     }t          |j        d          r|j        j        nt	          |j                  }|j        pddd                             dd          }t                              d||j	        p|j
        pd|j        pd|           | j                            |          }|j        }|j        |j        k    pt#          |d	d
          }	|	rC| j                            d|j        r|j        j        nd|j
        |j        |d           d{V  t+          || j        |          }
|                     |
          }d
}	 ddl}t3          t4          d          5 }|                    |          pi }ddd           n# 1 swxY w Y   t9          |                    d          pi                     dd
                    }n# t<          $ r Y nw xY wt?          |
|          }t#          |d	d
          rt#          |dd          pd}|dk    rd}n|dk    rd}nd}|dz   |z   }	 | j        j                             |j        t#          |dd                    }|j        r|j        j        nd}t#          |dd
          }|dk    p|j!        o
|o||j"        v}|r| j#                            |j                  }|r|dk    rd}nA|dk    rd |j$         d!}n/|j%        d"z  }|j%        d"z  }|s| d#n|r| d$| d%n| d%}d&| }d'| d(}	 | &                                }|r| d| }n# t<          $ r Y nw xY w|'                    |j        |t#          |d)d          *           d{V  n2# t<          $ r%}t          (                    d+|           Y d}~nd}~ww xY wd
|_)        d|_*        t#          |d,d          }|	r2|r/tW          |t                    r|gntY          |          } 	 dd-l-m.}!m/}" g }#g }$| D ]r}% |!|%|.          }&|&rF|&\  }'}(})d/|) d0}* |"|'|(|*          }+|+r*|#0                    |+           |$0                    |%           Wt          1                    d1|%           s|#rP|#0                    |j                   d2                    |#          |_        t                              d2|$|           n3# t<          $ r&}t          1                    d3| |           Y d}~nd}~ww xY w| j        3                    |j                  },|,r[ti          |,          d4k    rGdd5l5m6}-m7}. d6}/d7}0d8}1d}2d}3d}4d}5i }6	 tp          d9z  }7|79                                rddl}8t3          |7d          5 }9|8                    |9          pi }6ddd           n# 1 swxY w Y   |6                    d:i           }:tW          |:t                    r|:}/ntW          |:tt                    r|:                    d;          p|:                    d:          p|/}/|:                    d<          };|;(	 tw          |;          }2n# tx          tz          f$ r Y nw xY w|:                    d=          pd}3|:                    d>          pd}4|6                    d?i           }<tW          |<tt                    r7t	          |<                    d@d8                    >                                dAv }1	 | ?                    ||tW          |6tt                    r|6ndB          \  }/}=|=                    d=          p|3}3|=                    d>          p|4}4|=                    dC          p|5}5n# t<          $ r Y nw xY w|2I|4rF	 	 ddDl@mA}>  |>|6          }?n<# t<          $ r/ |6                    dE          }?tW          |?tX                    sg }?Y nw xY w|?D ]}@tW          |@tt                    s|@                    d>          pdB                    dF          }A|Ar|A|4B                    dF          k    r~|@                    dGi           }BtW          |Btt                    rQ|B                    |/i           }CtW          |Ctt                    r&|C                    d<          }D|Dtw          |D          }2 nn# tx          tz          f$ r Y nw xY wn# t<          $ r Y nw xY w|1r |.|/|4pd|5pd|2|3pdH          }Etw          |E|0z            }Ftw          |EdIz            }Gti          |,          }H|jC        }I|Idk    r|IdJ}Jn |-|,          dK}JdL}K|Fk    p|H|Kk    }L|Lr+t                              dM|HdN|Jtw          |0dOz            |EdN|FdN           |jD        r	dP|jD        ind}M	 ddQlEmF}N | ?                    ||tW          |6tt                    r|6ndB          \  }/}=|=                    dC          radR |,D             ti                    d4k    rA |Ndi |=|/d4d8d8dSg|j        dT	 dU _G        t          jI                    }O|OJ                    dfdV           d{V \  }P}Qj        }R|R|j        k    r |R|_        | j        K                                 | j        L                    |j        |P           d|_C        |P},ti          |P          }S |-|P          }Tt                              dW|H|SdN|TdN           |T|Gk    rt          1                    dX|TdN           | M                               n# | M                               w xY wn2# t<          $ r%}t          1                    dY|           Y d}~nd}~ww xY w|,s| j        N                                s|dZz  }|,s|j        r|j        t          jP        k    r|j        t          jQ        k    r|j        j        }|R                                 d[}Ut          jT        |U          sX| j#                            |j                  }|r7|'                    |j        d\|U                                 d]           d{V  |j        t          jV        k    rl| j#                            t          jV                  }| W                    |          }V|Vr1|r/t          |d^          r|X                    |V          }W|Wr|d|W z  }| Y                    |||,_           d{V }X|XdS 	 |j        r|j        j        nd|j
        |j        |Xdd`         da}Y| j                            db|Y           d{V  | Z                    |X||,||j        ||j[        |j\        c           d{V }Z	 | j#                            |j                  }[|[r0t          |[dd          r |[]                    |j                   d{V  n# t<          $ r Y nw xY w|Z                    de          pd}\|\dfk    rdg}\|Z                    dhg           }]t          j                     |z
  }^|Z                    did          }_ti          |\          }`t                              dj||j        pd|^|_|`           |r| ^                    |           |\s|Z                    dk          r|Z                    dldm          }at	          |a          >                                t          fdndoD                       pdpv oti          |,          dqk    }b|brdr}\ndst	          |a          ddt          du}\|Z                    dv          r|Zdv         |j        k    r|Zdv         |_        	 ddwl`ma}c  |ct                      t          |j                  dxt#          | dyd
                    }dn!# t<          $ r t#          | dyd
          }dY nw xY w|dr|\r|Z                    dz          }e|er|ed                                e                                }fti          |f          d{k    r7d2                    |fdd{                   }g|gd|ti          |f          d{z
   d}z  }gn|ed                                }gd~|g d|\ }\| j                            di |Yd|\pddd`         i           d{V  	 ddlfmg}h |hjh        rH|hjh        i                    d          }it          jj        | k                    |i                     |hjh        Hn2# t<          $ r%}t          l                    d|           Y d}~nd}~ww xY w	 ddlfmg}j g }k|jjm        n                                sa|jjm        o                                }l|l                    dd          }m|mdv r|k0                    |l           |jjm        n                                a|kD ]c}lt          |l          }n|nrP	 | q                    |n|l           d{V  1# t<          $ r%}ot          l                    d|o           Y d}o~o[d}o~oww xY wdn2# t<          $ r%}t          (                    d|           Y d}~nd}~ww xY wt9          |Z                    dk                    }p|pr t                              d|j                   |Z                    d          ru|rs|rqt                              d|j                   | j        r                    |           | s                    |           | jt        i                    |d           |\pddz   }\t          jv                    w                                }q|prn_|,s]|Z                    dg           }r| j        x                    |j        d|rpg t                      |j        r|j        j        nd|qd           |ps|Z                    dti          |,                    }sti          |]          |sk    r
|]|sd         ng }t|tsK| j        x                    |j        d|X|qd           |\r$| j        x                    |j        d|\|qd           nR| jz        du}u|tD ]F}v|v                    d          dk    ri |vd|qi}w| j        x                    |j        |w|u           G| j        {                    |j        |Z                    dd                     t9          |Z                    d                    }x| |                    ||\|]|x          r| }                    ||\           d{V  |Z                    d          rm|Z                    dk          sX|\r>| j#                            |j                  }y|yr| ~                    |\||y           d{V  	 |                     |           dS |\|                     |           S # t<          $ r}	 | j#                            |j                  }z|zr0t          |zdd          r |z]                    |j                   d{V  n# t<          $ r Y nw xY wt                              d|           t          |          j        }{t	          |          rt	          |          ddt         nd}ad}|t#          |dd          }}dt                      v rti          |,          nd}~|}dk    rd}|n|}dk    rd}|n|}dk    rt#          |dd          }i }	 |(|                                                    dli           }n# t<          $ r Y nw xY w|                    d          dk    rC|                    d          }|r)|dk    r#ddl}|                    |dz            }d| d}|n=d}|n:d}|n7|}dk    rd}|n.|}dv r*|~dqk    r	 Y d}~|                     |           drS |}dLk    rd}|d|{ d|a d|| dcY d}~|                     |           S d}~ww xY w# |                     |           w xY w)zAInner handler that runs under the _running_agents sentinel guard.r   rj   NP   r   r  z3inbound message: platform=%s user=%s chat=%s msg=%rrD  was_auto_resetFzsession:start)r  r  rC  r   r   r'   r(   privacy
redact_pii)r  auto_reset_reasonidler  zy[System note: The user's previous session was stopped and suspended. This is a fresh conversation with no prior context.]dailyz[System note: The user's session was automatically reset by the daily schedule. This is a fresh conversation with no prior context.]zy[System note: The user's previous session expired due to inactivity. This is a fresh conversation with no prior context.]r  r8  r:  )r  session_typereset_had_activityz+previous session was stopped or interruptedzdaily schedule at z:00r  hzh r  zinactive for u!   ◐ Session automatically reset (z). Conversation history cleared.
Use /resume to browse and restore a previous session.
Adjust reset timing in config.yaml under session_reset.r  r  z.Auto-reset notification failed (non-fatal): %s
auto_skill)_load_skill_payload_build_skill_messagerf  z[SYSTEM: The "zB" skill is auto-loaded. Follow its instructions for this session.]z#[Gateway] Auto-skill '%s' not foundz0[Gateway] Auto-loaded skill(s) %s for session %sz-[Gateway] Failed to auto-load skill(s) %s: %sr7  )estimate_messages_tokens_roughr  zanthropic/claude-sonnet-4.6g333333?Tr&   r\   r  r  r[   r]   compressionre  r;  r  r^   get_compatible_custom_providerscustom_providersr   modelsr]   r^   config_context_lengthr[   gffffff?actual	estimated  uf   Session hygiene: %s messages, ~%s tokens (%s) — auto-compressing (threshold: %s%% of %s = %s tokens)r  d   r<  r  c                     g | ]Y}|                     d           dv |                     d          .|                     d           |                     d          dZS r  rM  r  s     r   r  z<GatewayRunner._handle_message_with_agent.<locals>.<listcomp>  sk     ) ) )$%#$55==4I#I#I$%EE)$4$4 $J *+v155CSCS T T#I#I#Ir   r  r  c                      d S rh  r   r  s     r   rk  z:GatewayRunner._handle_message_with_agent.<locals>.<lambda>  s    D r   c                  4                         d           S )Nrj   )approx_tokens_compress_context)_approx_tokens
_hyg_agent	_hyg_msgss   r   rk  z:GatewayRunner._handle_message_with_agent.<locals>.<lambda>  s%    
0L0L,5r:H 1M 1* 1* r   u>   Session hygiene: compressed %s → %s msgs, ~%s → ~%s tokensz3Session hygiene: still ~%s tokens after compressionz(Session hygiene auto-compress failed: %sz

[System note: This is the user's very first message ever. Briefly introduce yourself and mention that /help shows available commands. Keep the introduction concise -- one or two sentences max.]_HOME_CHANNELu    📬 No home channel is set for z. A home channel is where Hermes delivers cron job results and cross-platform messages.

Type /sethome to make this chat your home channel, or ignore to skip.get_voice_channel_contextr   r  r  r  )r  r  rC  rF  zagent:start)rF  context_promptr  r  rC  r   event_message_idrA  stop_typingfinal_response(empty)u   ⚠️ The model returned no response after processing tool results. This can happen with some models — try again or rephrase your question.messages	api_callszMresponse ready: platform=%s chat=%s time=%.1fs api_calls=%d response=%d charsfailedr9  r/  c              3       K   | ]}|v V  	d S rh  r   )r   rW  	error_strs     r   r   z;GatewayRunner._handle_message_with_agent.<locals>.<genexpr>  s7       # #a1	> # # # # # #r   )contexttokenz	too largeztoo longexceedpayload4002   u}   ⚠️ Session too large for the model's context window.
Use /compact to compress the conversation, or /reset to start fresh.zThe request failed: r  z2
Try again or use /reset to start a fresh session.rC  resolve_display_settingr|  r}  last_reasoning   z
_... (z more lines)_u   💭 **Reasoning:**
```
z
```

z	agent:endresponsere  zProcess watcher setup error: %srA  rB  )rG  rE  &Watch notification injection error: %szWatch queue drain error: %sz`Skipping transcript persistence for failed request in session %s to prevent session growth loop.compression_exhaustedz7Auto-resetting session %s after compression exhaustion.u   

🔄 Session auto-reset — the conversation exceeded the maximum context size and could not be compressed further. Your next message will start a fresh session.toolssession_meta)r  rJ  r\   r  	timestamphistory_offsetr  )r  r  rL  r  r  systemrL  )skip_dblast_prompt_tokensrP  already_sent)rR  zAgent error in session %szno details availablestatus_coder  i  zH Check your API key or run `claude /login` to refresh OAuth credentials.i  zG Your API balance or quota is exhausted. Check your provider dashboard.i  usage_limit_reachedresets_in_secondsi  z9 Your plan's usage limit has been reached. It resets in ~zh.zG Your plan's usage limit has been reached. Please wait until it resets.z@ You are being rate-limited. Please wait a moment and try again.i  z= The API is temporarily overloaded. Please try again shortly.)r%  r  z% The request was rejected by the API.zSorry, I encountered an error (z).
z1Try again or use /reset to start a fresh session.r   )r@  r  r  r   r   rT  r   r  r  rg  r  r9  r  get_or_create_sessionr   
created_at
updated_atr   r  ro  rC  r   r  _set_session_envr  r  _config_pathr  r}  r   r   r   get_reset_policynotifynotify_exclude_platformsrs  at_houridle_minutes_format_session_infor  r  r  r  r   r   r  r  r  r   r  r   r  r   r  r  r  r   r   r!  r  r  r  r   r  hermes_cli.configr  rstriprP  r<  r  r  r  r  r  r  r  rewrite_transcriptr  has_any_sessionsr   r  r	  upperr   r   rX  r  _get_guild_idr1  r  
_run_agentr  rA  r5  r  r   gateway.display_configrD  r  r  r   
splitlinesr  rf  ru  r   r  rv  r9  completion_queueempty
get_nowaitrU  _inject_watch_notificationreset_session_evict_cached_agentrc  r   r  	isoformatappend_to_transcriptr$  r  update_session_should_send_voice_reply_send_voice_reply_deliver_media_from_response_clear_session_envr  rA  __name__localsr   mathceil)r  r   r  r  _msg_start_time_platform_name_msg_previewsession_entryr   _is_new_sessionr=  _session_env_tokens_redact_pii	_pii_yaml_pf_pcfgr3  reset_reasonr  policyr  had_activityshould_notifyr   reason_texthoursminsdurationnoticesession_infor  _auto_skill_namesr  r  _combined_parts_loaded_names_sname_loaded_loaded_skill
_skill_dir_display_name_note_partr  r  r  
_hyg_model_hyg_threshold_pct_hyg_compression_enabled_hyg_config_context_length_hyg_provider_hyg_base_url_hyg_api_key	_hyg_data_hyg_cfg_path	_hyg_yaml_hyg_f
_model_cfg_raw_ctx	_comp_cfg_hyg_runtime_gw_gcp_hyg_custom_providers_cp_cp_url
_cp_models_cp_model_cfg_cp_ctx_hyg_context_length_compress_token_threshold_warn_token_threshold
_msg_count_stored_tokens_token_source_HARD_MSG_LIMIT_needs_compress	_hyg_metar  r  _compressedr   _hyg_new_sid
_new_count_new_tokensenv_keyguild_id
vc_contextr  hook_ctxagent_result_typing_adapterrG  agent_messages_response_time
_api_calls	_resp_lenerror_detail_is_ctx_fail_rds_show_reasoning_effectiverE  linesdisplay_reasoningrf  r  _pr_watch_eventsr?  rN  
synth_texte2agent_failed_earlyts	tool_defshistory_lennew_messagesagent_persistedr  r  _already_sent_media_adapter_err_adapter
error_typestatus_hintrS  	_hist_len	_err_body	_err_json
_resets_inry  _hoursr-  r.  r/  r<  s                                                                                                                                       @@@@r   r  z(GatewayRunner._handle_message_with_agentw  s      )++29&/72S2Sm..Y\]c]lYmYm
(b#2#.66tSAAAF,KK)N'i	
 	
 	
 *@@HH#/ $(@@ ?}&6>> 	  	*///5;_LFO11"!>+6*	4 4          (]KK #33G<< 	$$$$lW555 7!++C006B7 7 7 7 7 7 7 7 7 7 7 7 7 7 7		) 4 4 :??eTTUUKK 	 	 	D	 6g+VVV ="2E:: <	3"=2EtLLVPVL{**  [((  f  [)F2^CN+R+2CC#_!(d!C!C D   :@ P 5 5b&}6JERR !- ; !M M$M%V-LL 
 ! "m//@@G ';66*WKK)W44*Rv~*R*R*RKK$*$72$=E#)#6#;D:>'p%{{{{[`DpuDWDWPTDWDWDWDWimfpfpfpH*D(*D*DKW W W W !+/+D+D+F+FL+ G,2)F)F)F)F( ! ! ! D!%ll"NF%,UJ%E%E +           R R RMqQQQQQQQQR ,1M(.2M+ |T22 	au 	a&0&<&<ME77$u++LaZZZZZZZZ-/+-* V VF11&*MMMG VCJ@z=J] J J J  !5 4]JPU V V  9+225999)00888'LfUUUU" #**5:666!'_!=!=EJKKJ%{    a a aNP\^_````````a $44]5MNN"  h	s7||q((        7J!%'+$)-& M MLIJ ,} < '')) :,,,,mg>>> F&$-$7$7$?$?$E2	F F F F F F F F F F F F F F F "+w!;!;J!*c22 K%/

#J55 K%/^^I%>%>%g*..QXBYBY%g]g
 $.>>2B#C#C#/%=@]] : :$-z#: % % % $% )3z(B(B(Jd(2z(B(B(Jd
 !*mR @ @I!)T22 :36%MM)T::4 4%''%94:0
/3/R/R%$/1;It1L1L$VIIRV 0S 0 0,J
 %1$4$4Z$@$@$QMM$0$4$4Z$@$@$QMM#/#3#3I#>#>#N,LL    D .5-5;dddddd4;GI4F4F11( ; ; ;4=MMBT4U4U1#-.CT#J#J ;8: 5; $9 & &C#-c4#8#8 ) ('*wwz':':'@b&H&H&M&MG& &7m6J6J36O6O+O+O-0WWXr-B-B
#-j$#?#? !V4>NN:r4R4RM'1-'F'F %V2?2C2CDT2U2U+2+>ILW,F %%z2       ( F&>&>*0b(.B*D*0b' ' '# -0'*<<- -) ),,?$,F(G(G% \\
 "/!A!A%%%3N$,MM%C%CG%L%LN$/M  #&"&?? 5!_4  
 # YKK>"~$9$9=.455.22488   DJCS ]f.> ? ?Y]IM555555373V3V#)(35?	45P5P(Z		VZ 4W 4 40
L
 (++I66 @N) ))0) ) )I  #9~~22-4W ." ."&2."*434/3046>Z/</G." ." ." ."
.!N;P;PJ$8+2+C+E+ED;?;O;O(,)* )* )* )* )* )*<& <& 6& 6& 6& 6& 6& 6&NK 4>3HL'3}7O'O'OCO(@(,(:(@(@(B(B(B$($6$I$I(5(@+%& %& %& HIM$D.9G14[1A1AJ2P2P(33& 3&K %+KK)=(2J+9(=(=+?Q?Q	%& %& %& (36K'K'K(.-:/:,>,>)* )* )* %)$A$A*$M$M$M$MD$A$A*$M$M$M$M$   F         	t1BBDD 	NN  	6? 	v(./P/PU[UdhphxUxUx"O1M&,,..===G9W%% 
-++FO<< !,,.=;N;N;P;P . . .         ?h...m''(899G))%00H :G :9T(U(U :$>>xHH
 :"&9Z&9&99N "?? @ 
 
 
 
 
 
 
 

 FY	9 6<_LFO11"!>+6'-	 H *//-::::::::: "&$-(3'!&!1$3 "1 	" 	" 	 	 	 	 	 	L"&-"3"3FO"D"D" Fw'N'N F)55fnEEEEEEEEE    $''(899?RH 9$$. 
 *--j"==N!Y[[?:N%))+q99JHIKK_ ;)
I    ?11+>>>   0 0 : : +//II--3355	
  # # # # # < # # #       Y& *Gr)    
1 HLs</@/@#/F L L L  -- F,|2LP]Ph2h2h+7+E(	TRRRRRR,0D(**(99$D"3U;;	- -))  T T T,3D:KU,S,S)))T( 
cX 
c!-!1!12B!C!C! c*0022==??E5zzB,0IIeCRCj,A,A))-VE

R-V-V-VV)),:,@,@,B,B)b<MbbX`bbH *//+ 00X^TcT20 0         CCCCCCC&7 L.?CCAFFG'(A(A'(J(JKKK '7 L  C C C>BBBBBBBBC?JJJJJJ ".4466 2.99;;C"wwv|<<H#DDD%,,S111	 .4466 2 ) W WC!Ec!J!JJ! WW"&"A"A*c"R"RRRRRRRRR( W W W"LL)QSUVVVVVVVVWWW  ? ? ?:A>>>>>>>>?& "&l&6&6x&@&@!A!A! A!,    788 ] { M!,   "00===((555-11+tDDD$ND ))++B
 "  (,,Wb99	"77!, .!*b!7!9!9=C_$TFO$9$9RT%' 	 	 	 & *../?WNN?B>?R?RU`?`?`~kll;;fh $ &;;%0!'LrRR     *??)4%0XTVWW   '+&6d&BO+ 	 	776??h66$ 83 8R 8 8*??)4e$3 @     --)#/#3#34H!#L#L .    !!1!1.!A!ABBM,,UHn[h,ii >,,UH========= // 8H8H8R8R  %)]%6%6v%G%GN% "??$e^         ~ ##$788888{ z ##$78888w  8	 8	 8	#}00AA CGL-$H$H C&226>BBBBBBBBB   8+FFFa)J+.q66M3q66$3$<<7MLK!!]D99K(1VXX(=(=G1Ic!!h##g###Az488		 ,$-NN$4$4$8$8"$E$E	    D==((,AAA!*/B!C!CJ! pj1nn#!%:+<!=!=&lbh&l&l&l&o"dKK##]
** r>>1    ##$788888 !C''"IKD* D DD DD D D     ##$78888w8	v ##$78888s2  G 6FG FG !F";G 
G+*G+C&N	 (M N	 
MN	 M5N	 	
N8N33N8CS 
T&TT4c V6*c 6V::c =V:>B	c Y c Y,)c +Y,,Bc  A7]8 7c 8
^c ^	c ^" !b= "6_b= _C!b= <c =cc cc 
c"!c"*Bm 0C9l? )m ?mm 
n	$nn	A?AV2 Aw$ #AV2 $
w1.AV2 0w11FAV2 5A~7 6AV2 7AV2 CAV2 B1AAD DAV2 D
AD6DAD1D,AV2 D1AD6D6AV2 D:BAH# GAG/G.AH# G/
AHG9AHHAH# HAHHAH# H"AV2 H#
AIH-AIIAV2 IAIIL1AV2 VAV2 V2A_V>AAXXA_X
AXXA_XAXXB;A_[*A\\A_\
A\\A_\A\\A6A_^A_ ^"A_^5A_^6A_ _A__A_ _A_/c                 d   ddl m}m} t                      }d}d}d}d}	 t          dz  }|                                rddl}	t          |d          5 }
|	                    |
          pi }ddd           n# 1 swxY w Y   |	                    di           }t          |t                    rm|	                    d          }|(	 t          |          }n# t          t          f$ r Y nw xY w|	                    d	          pd}|	                    d
          pd}n# t          $ r Y nw xY w	 t!                      }|p|	                    d	          }|p|	                    d
          }|	                    d          }n# t          $ r Y nw xY w |||pd|pd||pd          }|d}n||k    rd}nd}|dk    r
|dz  dd}n|dk    r	|dz   d}nt#          |          }d| dd|pd d| d| dg}|r$d|v sd|v sd|v r|                    d |            d!                    |          S )"a  Resolve current model config and return a formatted info block.

        Surfaces model, provider, context length, and endpoint so gateway
        users can immediately see if context detection went wrong (e.g.
        local models falling to the 128K default).
        r   )r  DEFAULT_FALLBACK_CONTEXTNr&   r'   r(   r\   r  r[   r]   r^   rj   r!  r  u:   default — set model.context_length in config to overridedetectedi@B z.1fMi  Ku   ◆ Model: `r   u   ◆ Provider: 
openrouteru   ◆ Context: z	 tokens (r  	localhostz	127.0.0.1z0.0.0.0u   ◆ Endpoint: 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[   r]   r^   rh  
_info_yamlr  r  r#  raw_ctxr   r  
ctx_sourcectx_displayr  s                      r   r`  z"GatewayRunner._format_session_info  s[    	\[[[[[[[&(( $	#m3H   A))))(W555 9%//228bD9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 HHWb11	i.. A'mm,<==G*!47LL11 ):6 ! ! ! D!(}}Z88@DH(}}Z88@DH 	 	 	D		355G:7;;z#:#:H:7;;z#:#:Hkk),,GG 	 	 	D	 21^Mr"7^
 
 
 !,!JJ777UJJ#J Y&&+i7>>>>KKu$$+u4777KKn--K $5###7X577?K??*???
  	600K84K4Ky\dOdOdLL4(44555yysm   3D A7+D 7A;;D >A;?AD C D C)&D (C))1D 
D('D(,AE> >
F
Fc                   K   |j         }|                     |          }	 | j        j                            |          }|rft          j        |                     |j        |                    }| j	        
                    |           |                    | j	        j                   n2# t          $ r%}t                              d|           Y d}~nd}~ww xY wt!          | dd          }|n|5  | j                            |          }t%          |t&                    r|d         n|r|nd}	ddd           n# 1 swxY w Y   |	|                     |	           |                     |           	 ddlm}
  |
             n# t          $ r Y nw xY w	 ddlm}  |             n# t          $ r Y nw xY w| j                            |          }| j                            |d           	 ddlm} |r|j        nd} |d||j        r|j        j         nd	
           n# t          $ r Y nw xY w| j!        "                    d|j        r|j        j         nd	|j#        |d           d{V  | j!        "                    d|j        r|j        j         nd	|j#        |d           d{V  	 | $                                }n# t          $ r d	}Y nw xY w|rd}n| j        %                    |d          }d}	 ddlm} |r|j        nd} |d||j        r|j        j         nd	
           n# t          $ r Y nw xY w	 ddl&m'} d |             }n# t          $ r d	}Y nw xY w|r	| d| | S | | S )zHandle /new or /reset command.z(Gateway memory flush on reset failed: %sNr  r   )clear_env_passthrough)clear_credential_filesr  r  rj   r  zsession:end)r  r  r   zsession:resetu"   ✨ Session reset! Starting fresh.T)	force_newu   ✨ New session started!on_session_reset)get_random_tipu
   
✦ Tip: r  )(r  r  r  r  r   r  r  r  rC  r  r   r  r  r   r  r  r   r  r   r  r  ro  tools.env_passthroughr  tools.credential_filesr  rn  rc  r   r  r  r  r   r  ro  r  r`  rV  hermes_cli.tipsr  )r  r   r  r   	old_entry_flush_taskr  r  r  
_old_agentr  r  	new_entryr  _old_sidr  header_new_sidr  	_tip_lines                       r   rq  z#GatewayRunner._handle_reset_command  sg      226::		H*377DDI N%1..y/C[QQ  &**;777--d.D.LMMM 	H 	H 	HLLCQGGGGGGGG	H
 d$7>>" h h+//<<+5gu+E+EgWQZZV]Kg77cg
h h h h h h h h h h h h h h h %--j999  ---	CCCCCC!!#### 	 	 	D		EEEEEE""$$$$ 	 	 	D	 &44[AA	 	%))+t<<<	FFFFFF/8By++dHL.8;A?"R&/"7"7PRT T T T T 	 	 	D	 joom17H--b~&.
 .
   	 	 	 	 	 	 	 jooo17H--b~&0
 0
   	 	 	 	 	 	 		4466LL 	 	 	LLL	  	09FF *@@SW@XXI/F	FFFFFF/8By++dHL+;A?"R&/"7"7PRT T T T T 	 	 	D		6666668nn&6&688II 	 	 	III	  	<;;,;	;;;%)%%%s   BB( (
C2CC/>D99D= D=1F 
FFF$ $
F10F1*2H 
H*)H*(J= =KK32L& &
L32L37M MMc                    K   ddl m} ddlm}  |            } |            }d| dd| dg}d                    |          S )u@   Handle /profile — show active profile name and home directory.r   display_hermes_homer#  u   👤 **Profile:** `r   u   📂 **Home:** `r   )r  r  ra  r$  r   )r  r   r  r$  rv   profile_namer  s          r   ry  z%GatewayRunner._handle_profile_commandT  s      888888??????%%''..00 2,111)w)))

 yyr   c                   K   |j         }| j                            |          }d | j                                        D             }|j        }|| j        v }d}| j        r3	 | j                            |j	                  }n# t          $ r d}Y nw xY wddd|j	         dg}|r|                    d|            |                    d|j                            d	           d
|j                            d	           d|j        dd|rdnd ddd                    |           g           d                    |          S )zHandle /status command.c                     g | ]	}|j         
S r   r   rV  s     r   r  z8GatewayRunner._handle_status_command.<locals>.<listcomp>h  s    EEE1qwEEEr   Nu   📊 **Hermes Gateway Status**rj   z**Session ID:** `r   z**Title:** z**Created:** z%Y-%m-%d %H:%Mz**Last Activity:** z**Tokens:** r  z**Agent Running:** u   Yes ⚡Noz**Connected Platforms:** r  r   )r  r  rV  rs  r  r   r  r  get_session_titlerC  r   r   extendrW  strftimerX  total_tokensr   )	r  r   r  r~  connected_platformsr   
is_runningrX  r  s	            r   rn  z$GatewayRunner._handle_status_commandc  s     *@@HHEE0B0B0D0DEEE $/ D$88
 	(::=;STT    -; 8;;;

  	0LL.u..///QM4==>NOOQQW-":"C"CDT"U"UWW9=5999Ez"C))tEEH		2E(F(FHH
 	 	 	 yys   !B BBc                 `  K   |j         }| j                            |          }|j        }| j                            |          }|t          u r6|| j        v r| j        |= t                              d|dd                    dS |r(|	                    d           || j        v r| j        |= dS dS )a  Handle /stop command - interrupt a running agent.

        When an agent is truly hung (blocked thread that never checks
        _interrupt_requested), the early intercept in _handle_message()
        handles /stop before this method is reached.  This handler fires
        only through normal command dispatch (no running agent) or as a
        fallback.  Force-clean the session lock in all cases for safety.

        The session is preserved so the user can continue the conversation.
        u2   STOP (pending) for session %s — sentinel clearedNr  uL   ⚡ Stopped. The agent hadn't started yet — you can continue this session.r<  r=  zNo active task to stop.)
r  r  rV  r   r  r   r  r  r  rY  )r  r   r  r~  r   rk   s         r   rz  z"GatewayRunner._handle_stop_command  s       *@@HH#/$((55+++d222(5KKLkZ][]Z]N^___aa 	-OO,--- d222(5@@,,r   c                   K   | j         s| j        r|                                 }|rd| dS dS 	 ddl}|j        j        r|j        j        j        nd|j        j        d}|j        j        r|j        j        |d<   t          dz  
                    |                    |                     n2# t          $ r%}t                              d	|           Y d}~nd}~ww xY w|                                 }t          t           j                            d
                    }|r|                     dd           n|                     dd           |rd| dS dS )zFHandle /restart command - drain active work, then restart the gateway.u   ⏳ Draining z" active agent(s) before restart...u*   ⏳ Gateway restart already in progress...r   N)r  r9  r<  .restart_notify.jsonz'Failed to write restart notify file: %sINVOCATION_IDFTr  uy   ♻ Restarting gateway. If you aren't notified within 60 seconds, restart from the console with `hermes gateway restart`.)r^  r]  rJ  r   r  r  r   r9  r<  r   r  r  r   r  r  r}  r   r   r   r!  )r  r   countre  notify_datar  r[  _under_services           r   rp  z%GatewayRunner._handle_restart_command  s     " 	@dn 	@--//E QPuPPPP??	G    ;@<;PZEL177VZ </ K |% B+0<+AK(22>>K((     	G 	G 	GLLBAFFFFFFFF	G 1133 bjnn_==>> 	C  %T BBBB  $E BBB 	UT=TTTT K  Ks   A;B, ,
C6CCc                   K   ddl m} dg |            }	 ddlm}  |            }|r|                    dt          |           d           t          |          }|dd         D ])}|                    d	| d
||         d                     *t          |          dk    r)|                    dt          |          dz
   d           n# t          $ r Y nw xY wd                    |          S )z/Handle /help command - list available commands.r   gateway_help_linesu   📖 **Hermes Commands**
rc  u   
⚡ **Skill Commands** (z	 active):Nr  r      ` — descriptionz	
... and z3 more. Use `/commands` for the full paginated list.r   )	ro  r  r  rc  r   r   r  r   r   )r  r   r  r  rc  r  sorted_cmdsr  s           r   rw  z"GatewayRunner._handle_help_command  sL     ::::::(
!!
	??????++--J zT#j//TTTUUU$Z00&ss+ R RCLL!PS!P!P
30N!P!PQQQQ{##b((LL!xc+.>.>.C!x!x!xyyy 	 	 	D	yys   B7C 
CCc                   K   ddl m} |                                                                }|r"	 t	          |          }n# t
          $ r Y dS w xY wd}t           |                      }	 ddlm}  |            }|r|	                    d           |	                    d           t          |          D ]M}||                             dd                                          pd	}	|	                    d
| d|	            Nn# t          $ r Y nw xY w|sdS ddlm}
 |j        j        |
j        k    rdnd}t%          dt'          |          |z   dz
  |z            }t%          dt)          ||                    }|dz
  |z  }||||z            }dt'          |           d| d| ddg|}|dk    rpg }|dk    r|	                    d|dz
   d           ||k     r|	                    d|dz    d
           |                    dd                    |          g           ||k    r|	                    d| d| d           d                    |          S )zDHandle /commands [page] - paginated list of all commands and skills.r   r  zUsage: `/commands [page]`r#   r  rj   u   ⚡ **Skill Commands**:r  zSkill commandr   r  zNo commands available.r   rF  r  u   📚 **Commands** (z total, page r   r  z`/commands u
   ` ← prevu   next → `/commands z | z_(Requested page z  was out of range, showing page z.)_r   )ro  r  rr  r   r  r  r   r  rc  r   r  r   r   gateway.configr   r  r  r  rm  r   r  r  r   )r  r   r  raw_argsrequested_pageentriesrc  r  r  descr   	page_sizetotal_pagespager  page_entriesr  	nav_partss                     r   rx  z&GatewayRunner._handle_commands_command  s     ::::::))++1133 	3!$X 3 3 32223 N ))++,,
	??????++--J :r"""8999!*-- : :C%c?..}bAAGGII\_DNN#8s#8#8$#8#89999 	 	 	D	  	,++++++++,/83DDDBB"	!c'llY6:yHII1c.+6677Y&uUY%667 S#g,,RRTRRKRRR
 

 ??Iaxx  !Ctax!C!C!CDDDk!!  !Cq!C!C!CDDDLL"ejj334555>!!LLf^ff]afffgggyys$   A 
AA-BD 
DDc                   ,-./01234K   ddl }ddlm2m}m} ddlm} |                                                                } ||          \  }}}	d}
d}d}d}d4d3t          dz  }	 |
                                rt          |d	          5 }|                    |          pi }ddd           n# 1 swxY w Y   |                    d
i           }t          |t                    rB|                    dd          }
|                    d|          }|                    dd          }|                    d          4	 ddlm}  ||          3n%# t$          $ r |                    d          3Y nw xY wn# t$          $ r Y nw xY w|j        }|                     |          }| j                            |i           }|rX|                    d
|
          }
|                    d|          }|                    d|          }|                    d|          }|s|s| j                            |j                  }|duot1          t3          |          dd          du}|r	  ||43d          }n# t$          $ r g }Y nw xY w|rx| 0|1|
.|/|-|,dt4          dt4          dt4          dt4          f,-./01234f	d}|j        r	d|j        ind}|                    |j        ||
||||           d{V }|j        rdS  ||          }d|
pd d| dg}	  ||43d          }|D ]}|d          rd!nd}|                    d"|d#          d$|d%          d&| d'           |d(         rd)                     d* |d(         D                       } |d+         tC          |d(                   k    r"d,|d+         tC          |d(                   z
   d-nd}!|                    d.|  |!            n4|                    d/          r|                    d0|d/          d&           |                    d           n# t$          $ r Y nw xY w|                    d1           |                    d2           |                    d3           d4                     |          S  2|||
|||	|435	  	        }|j        s
d6|j"         S d}"t1          | d7d          }#t1          | d8d          }$|#r1|$/|#5  |$                    |          }"ddd           n# 1 swxY w Y   |"ru|"d         m	 |"d                             |j#        |j$        |j%        |j&        |j'        9           n2# t$          $ r%}%tP          )                    d:|%           Y d}%~%nd}%~%ww xY wtU          | d;          si | _+        d<|
 d=|j#         d>|j,        p|j$         d?| j+        |<   |j#        |j$        |j%        |j&        |j'        d@| j        |<   | -                    |           |	r	 |
                                rAt          |d	          5 }|                    |          pi }ddd           n# 1 swxY w Y   ni }|.                    d
i           }|j#        |d<   |j$        |d<   |j&        r
|j&        |d<   ddAlm/}&  |&|           n2# t$          $ r%}'tP          )                    dB|'           Y d}'~'nd}'~'ww xY w|j,        p|j$        }dC|j#         d&g}|                    dD|            |j0        }(|(r|(j1        r|                    dE|(j1        dFdG           |(j2        r|                    dH|(j2        dFdG           |(3                                r*|                    dI|(4                                            |                    dJ|(5                                            nY	 ddKl6m7})  |)|j#        |j&        p||j%        p||j$        L          }*|                    dE|*dFdG           n# t$          $ r Y nw xY wd|j&        pd8                                v rdM|j#        8                                v p
|j'        dNk    }+|+r|                    dO           |j9        r|                    dP|j9                    |	r|                    dQ           n|                    dR           d4                     |          S )Su  Handle /model command — switch model for this session.

        Supports:
          /model                              — interactive picker (Telegram/Discord) or text list
          /model <name>                       — switch for this session only
          /model <name> --global              — switch and persist to config.yaml
          /model <name> --provider <provider> — switch provider + model
          /model --provider <provider>        — switch to provider, auto-detect model
        r   N)switch_modelparse_model_flagslist_authenticated_providers)	get_labelrj   r  r&   r'   r(   r\   r  r[   r]   	providersr  r  r^   send_model_pickerrB  )current_provideruser_providersr  
max_models_chat_idmodel_idprovider_slugr   c                   	K    |d|	  	        }|j         s
d|j         S d}t          dd          }t          dd          }|r1|/|5  |                              }ddd           n# 1 swxY w Y   |ru|d         m	 |d                             |j        |j        |j        |j        |j	                   n2# t          $ r%}t                              d	|           Y d}~nd}~ww xY wt          d
          si _        d d|j         d|j        p|j         dj        <   |j        |j        |j        |j        |j	        dj        <                                  |j        p|j        }d|j         dg}	|	                    d|            |j        }
|
r|
j        r|	                    d|
j        dd           |
j        r|	                    d|
j        dd           |
                                r*|	                    d|
                                            |	                    d|
                                            |	                    d           d                    |	          S )z6Perform the model switch and return confirmation text.F		raw_inputr+  current_modelcurrent_base_urlcurrent_api_key	is_globalexplicit_providerr,  r  Error: Nr  r  r   	new_modelnew_providerr^   r]   r   z/Picker model switch failed for cached agent: %s_pending_model_notes$[Note: model was just switched from  to  via /. Adjust your self-identification accordingly.]r\   r[   r^   r]   r   Model switched to `r   
Provider: 	Context: r   tokensMax output: Cost: Capabilities: u<   _(session only — use `/model <name> --global` to persist)_r   )r  r5  r   r   r%  r;  target_providerr^   r]   r   r   r  r  r  r=  provider_labelrc  ro  r   
model_infocontext_window
max_outputhas_cost_dataformat_costformat_capabilitiesr   )r.  r/  r0  r=  cached_entryr  _cacher   plabelr  mi_cur_api_key_cur_base_url
_cur_model_cur_provider_self_session_key_switch_modelcustom_provs
user_provss              r   _on_model_selectedz?GatewayRunner._handle_model_command.<locals>._on_model_selectedq  s      "/&.-:*4-:,8&+.;+5-9
" 
" 
"  &~ D#CV-A#C#CC (,&-e5H$&O&O!(!E!E& H6+=!, H H/5zz,/G/GH H H H H H H H H H H H H H H' 
gLO,G	g ,Q < <.4.>171G,2N-3_-3_ != !" !" !" !" $- g g g &/`be f f f f f f f fg  'u.DEE <9;E6M: M MSYSc M M#)#8#RF<RM M M 2<@ &,%5(.(>'-~(.(.H H6|D 11,??? "(!6!P&:P!Jv7G!J!J!J K%:&%:%:;;;#. V!0 W %-U9J-U-U-U-U V V V!} V %-TBM-T-T-T-T U U U!//11 J %-Hbnn6F6F-H-H I I I!LL)T":P:P:R:R)T)TUUU%cddd#yy///s*   A55A9<A99C 
C4C//C4r<  )r9  r)  r4  r+  r   on_model_selectedr  z
Current: `rD  z` on r3  
is_currentz
 (current)**r   z** `--provider slugr   r   r   r  c              3   "   K   | ]
}d | d V  dS r   Nr   r  s     r   r   z6GatewayRunner._handle_model_command.<locals>.<genexpr>  s*      .M.MAx1xxx.M.M.M.M.M.Mr   total_modelsz (+z more)z  api_urlz  `u    `/model <name>` — switch modelu5   `/model <name> --provider <slug>` — switch provideru$   `/model <name> --global` — persistr   r2  r9  r  r  r:  z1In-place model switch failed for cached agent: %sr=  r>  r?  r@  rA  rB  )save_configz"Failed to persist model switch: %srC  rD  rE  r  rF  rG  rH  rI  r  )r]   r^   r[   claudeanthropic_messageszPrompt caching: enabledz	Warning: z!Saved to config.yaml (`--global`)z-_(session only -- add `--global` to persist)_):r  hermes_cli.model_switchr%  r&  r'  hermes_cli.providersr(  rr  r   r   r   r  r  r   r   r!  ra  r  r   r  r  rc  rs  r  r   rA  r   r<  r*  r9  r  r   r   r   r5  r;  rJ  r^   r]   r   r  r  r  r=  rK  ro  r  rh  rL  rM  rN  rO  rP  rQ  r  r  r   warning_message)5r  r   r  r&  r'  r(  r  model_inputr8  persist_globalr4  r+  r5  r6  r  r  r"  r#  r  r  r   r!  r   
has_pickerr)  r_  r  r=  rK  r  rW  tag
model_strsr  rR  r  rS  r   rh  r  rU  r  ctxcache_enabledrV  rW  rX  rY  rZ  r[  r\  r]  r^  s5                                               @@@@@@@@@r   r  z#GatewayRunner._handle_model_command  s      		
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	322222))++1133 :K9J89T9T6& '
"]2	!!## ?+888 2A..++1rC2 2 2 2 2 2 2 2 2 2 2 2 2 2 2GGGR00	i.. E$-MM)R$@$@M'0}}ZAQ'R'R$'0}}Z'D'D$ WW[11
?QQQQQQ#B#B3#G#GLL  ? ? ?#&77+=#>#>LLL? 	 	 	D	 226::044["EE 	G$LL-@@M'||J8HII'||J8HII&ll9oFFO  O	$#4 O	$m''88Gt# RDMM+>EETQ 
  j$# < <)9'1)5#%	! ! !II ! # # # "III#  _$ !E#.L!.J$4M$4M#2LH0"%H014H0EHH0H0 H0 H0 H0 H0 H0 H0 H0 H0 H0 H0 H0 H0 H0T CIBR\V-=>>X\H#*#<#< &"+&3)9$/*<!) $= $ $      F ~ $#t 'Y'788NS-"<9SS>SSUWXE88%5#-%1 	  	 # 	% 	%A*+L/A,,rCLL!Rai!R!R&	!R!RC!R!R!RSSS{ <%)YY.M.M8.M.M.M%M%M
VWXfVgjmnopxnyjzjzVzVz Ra&7#ak:J:J&J R R R R  AC%=*%=e%=%=>>>>y)) <%:1Y<%:%:%:;;;LL$$$$	%     LL;<<<LLPQQQLL?@@@99U### !-'-+$/%)

 

 

 ~ 	43V1333 d$7>>~t44 	76- 7 7%zz+667 7 7 7 7 7 7 7 7 7 7 7 7 7 7  
	YLO7	YQ,,$.!'!7"N#_#_ -      Y Y YRTWXXXXXXXXY
 t344 	+(*D%== = =fFV = =(BF,B= = = 	!+. %.~6
 6
%k2 	  ---  	HH%%'' kG<<< 6"nnQ//526 6 6 6 6 6 6 6 6 6 6 6 6 6 6 CNN7B77	'-'7	)$(.(>	*%? <,2OIj)999999C     H H HCQGGGGGGGGH  .H&2H:v'7:::;2.22333  	  GE):EEEEFFF} FDBMDDDDEEE!! :8bnn&6&688999LLD"*@*@*B*BDDEEEE
IIIIII..$#_@0@"N=o#3	   777778888   
 fo3::<<<eVM]McMcMeMeAe 7"66 	  	4LL2333! 	?LL=V%;==>>> 	JLL<====LLHIIIyys   ,%E; B5)E; 5B99E; <B9=BE; E E; E74E; 6E77E; ;
FF(I8 8JJD!P> >
Q
Q1TTT)9U# #
V-VV%Z6 7YZ6 YZ6 "Y#AZ6 6
[% [  [%A`! !
`.-`.c           
      \  K   ddl }ddlm}m}m} d}i }t
          dz  }	 |                                rt          |d          5 }	|                    |	          pi }
ddd           n# 1 swxY w Y   |
	                    di           }t          |t                    r|	                    d	|          }n# t          $ r Y nw xY w ||          }|d
k    r%	 ddlm}  ||          }n# t          $ r d}Y nw xY w|dk    r5t          |t                    r|	                    dd          nd}|rd|vrd}|	                    ||          }d| d| dddg} |            }|D ]t}|d         |k    rdnd}|d         rdnd}|d         rdd                    |d                    dnd}|                    | d|d          d|d          | |            u|                    d           |                    d            |                    d!           d"                    |          S )#z4Handle /provider command - show available providers.r   N)list_available_providersnormalize_provider_PROVIDER_LABELSr  r&   r'   r(   r\   r[   rU   )resolve_providerr]   rj   zopenrouter.aicustomu   🔌 **Current provider:** z (`z`)z**Available providers:**idu    ← activeauthenticatedu   ✅u   ❌aliasesz
  _(also: r  )_z `r  r  z$Switch: `/model provider:model-name`zSetup: `hermes setup`r   )r  r  rv  rw  rx  r   r   r  r  r   r   r!  r   hermes_cli.authry  r   r   )r  r   r  rv  rw  rx  r+  r#  r  r  r"  _resolve_provider	_cfg_basecurrent_labelr  r)  rW  r  authr}  s                       r   r  z&GatewayRunner._handle_provider_command`  sI     	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 (	"]2	!!## S+888 2A..++1rC2 2 2 2 2 2 2 2 2 2 2 2 2 2 2GGGR00	i.. S'0}}ZAQ'R'R$ 	 	 	D	 .-.>??v%%0QQQQQQ#4#45E#F#F   0 0 0#/   0 |++9CIt9T9T\	j"555Z\I ,_I==#+ (,,-=?OPP Q-PP<LPPP&
 -,..	 	R 	RA&'g1A&A&A]]rFo.955EDBCI,V>499Qy\#:#:>>>>TVGLLDPPAdGPP1W:PwPPPQQQQR;<<<,---yysH   %B6 A)B6 )A--B6 0A-1AB6 6
CCC* *C98C9c                   K   ddl }ddlm} |                                                                                                }t          dz  }	 |                                rlt          |dd          5 }|	                    |          pi }ddd           n# 1 swxY w Y   |
                    di           
                    d	i           }ni }i }n# t          $ r i }i }Y nw xY w|sd
 |             dS |sdg}	|	                    d           |                                D ]\  }
}t          |t                    r4|
                    d          p|
                    dd          dd         }n"t!          |          dk    r|dd         dz   n|}|	                    d|
 d|            |	                    d           d                    |	          S d }|dv rs	 d|vs(t          |
                    d          t                    si |d<   d|d         d<   t%          ||           n# t          $ r}d| cY d}~S d}~ww xY wd| _        dS ||v r |||                   }	 d|vs(t          |
                    d          t                    si |d<   ||d         d<   t%          ||           n# t          $ r}d| cY d}~S d}~ww xY w|| _        d| dS dd                    d |D                       z   }d | d!| S )"z8Handle /personality command - list or set a personality.r   Nr  r&   r  r'   r(   rk   personalitiesz No personalities configured in `z/config.yaml`u!   🎭 **Available Personalities**
u'   • `none` — (no personality overlay)r  rl  rj   rB  ...u   • `r  z
Usage: `/personality <name>`r   c                    t          | t                    r|                     dd          g}|                     d          r|                    d| d                     |                     d          r|                    d| d                     d                    d |D                       S t          |           S )	Nrl  rj   tonezTone: stylezStyle: r   c              3      K   | ]}||V  	d S rh  r   rV  s     r   r   zUGatewayRunner._handle_personality_command.<locals>._resolve_prompt.<locals>.<genexpr>  s'       7 7qQ 7 7 7 7 7 7 7r   )r   r!  r   r   r   r   )r   r   s     r   _resolve_promptzBGatewayRunner._handle_personality_command.<locals>._resolve_prompt  s    %&& 8?B77899V$$ ;LL!9%-!9!9:::99W%% =LL!;5>!;!;<<<yy 7 7E 7 7 7777u::r   )rs  r  neutralu*   ⚠️ Failed to save personality change: uX   🎭 Personality cleared — using base agent behavior.
_(takes effect on next message)_u   🎭 Personality set to **z#**
_(takes effect on next message)_z`none`, r  c              3   "   K   | ]
}d | d V  dS re  r   )r   r0  s     r   r   z<GatewayRunner._handle_personality_command.<locals>.<genexpr>  s*      *K*K8q888*K*K*K*K*K*Kr   zUnknown personality: `z`

Available: )r  r  r  rr  r   r   r   r   r  r  r   r   r   r  r   r!  r   r   r   rw  )r  r   r  r  r   r  r  r  r  r  r   rm  previewr  r  
new_prompt	availables                    r   r  z)GatewayRunner._handle_personality_command  s1     888888%%''--//5577"]2
	!!## #+sW=== 5!^^A..4"F5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 &

7B 7 7 ; ;OR P P " 	 	 	FMMM	  	[Z6I6I6K6KZZZZ 
	$9:ELLBCCC - 3 3 5 5 < <ffd++ R$jj77_6::oWY;Z;Z[^\^[^;_GG58[[25E5EfSbSkE116G:T::::;;;;LL9:::99U###	 	 	 111H&((
6::g;N;NPT0U0U(&(F7O35w0!+v6666 H H HGAGGGGGGGGH,.D)nn]""(t)<==JH&((
6::g;N;NPT0U0U(&(F7O3=w0!+v6666 H H HGAGGGGGGGGH -7D)ZZZZZ*K*K]*K*K*K!K!KK	IIIiIIIst   &C 6BC BC !B"2C C&%C&%AH2 2
I<I II-AJ: :
KKKKc                 D  K   |j         }| j                            |          }| j                            |j                  }d}d}t          t          |          dz
  dd          D ]A}||                             d          dk    r ||                             dd          }|} nB|sdS |d|         }| j                            |j        |           d	|_	        t          |t          j        ||j        |j        
          }	|                     |	           d{V S )z6Handle /retry command - re-send the last user message.Nr#   r  r  r  rj   zNo previous message to retry.r   )rT  r   r  raw_messagerA  )r  r  rV  r  rC  r  r   r   rc  rP  r   r   rs  r  rA  rh  )
r  r   r  r~  r  last_user_msglast_user_idxr   	truncatedretry_events
             r   r  z#GatewayRunner._handle_retry_command  sI     *@@HH$44]5MNN s7||a'R00 	 	Aqz~~f%%// '
y" = = ! 0
  	322 N]N+	--m.F	RRR+,( #$)) /
 
 
 ))+666666666r   c                 0  K   |j         }| j                            |          }| j                            |j                  }d}t          t          |          dz
  dd          D ]%}||                             d          dk    r|} n&|dS ||                             dd          }t          |          |z
  }| j                            |j        |d|                    d	|_	        t          |          d
k    r|dd
         dz   n|}	d| d|	 dS )z?Handle /undo command - remove the last user/assistant exchange.Nr#   r  r  r  zNothing to undo.r  rj   r   (   r  u   ↩️ Undid z message(s).
Removed: "")
r  r  rV  r  rC  r  r   r   rc  rP  )
r  r   r  r~  r  r  r   removed_msgremoved_countr  s
             r   r  z"GatewayRunner._handle_undo_command  s>     *@@HH$44]5MNN s7||a'R00 	 	Aqz~~f%%// ! 0  %%m,00B??G}4--m.FP^Q^P^H_```+,(.1+.>.>.C.C+crc"U**R}RRwRRRRr   c                   K   |j         }|j        r|j        j        nd}|j        }|j        p|}|                                 d}	 ddl}t          dz  }i }	|                                r@t          |d          5 }
|
                    |
          pi }	ddd           n# 1 swxY w Y   ||	|<   t          ||	           t          |          t          j        |<   n# t          $ r}d| cY d}~S d}~ww xY wd	| d
| dS )zOHandle /sethome command -- set the current chat as the platform's home channel.rD  r0  r   Nr&   r'   r(   zFailed to save home channel: u   ✅ Home channel set to **z** (ID: z@).
Cron jobs and cross-platform messages will be delivered here.)r  r  r   r9  	chat_namere  r  r   r   r  r  r   r   r   r   r   )r  r   r  r  r9  r  r  r  r  r  r  r  s               r   r  z&GatewayRunner._handle_set_home_command!  s     17O--i.$/	"((**999	7KKK&6KK!!## :+888 :A"&.."3"3"9rK: : : : : : : : : : : : : : :#*K k;777"%g,,BJw 	7 	7 	76166666666	7M M MG M M M	
sB   5C <B C  B$$C 'B$(4C 
C6'C1+C61C6c                     t          | dd          }|dS t          |d          r|j        rt          |j                  S t          |d          r|j        r|j        j        S dS )z5Extract Discord guild_id from the raw message object.r  Nr  guild)r   r  r  r  r  r{  )r   rz  s     r   rf  zGatewayRunner._get_guild_id>  st     e]D11;43
## 	% 	%s|$$$3   	 SY 	 9<tr   c                 P  K   |                                                                                                 }|j        j        }| j                            |j        j                  }|dv r;d| j        |<   | 	                                 |r| 
                    ||d           	 dS |dv r:d| j        |<   | 	                                 |r| 
                    ||d           d	S |d
k    r;d| j        |<   | 	                                 |r| 
                    ||d           	 dS |dv r|                     |           d{V S |dk    r|                     |           d{V S |dk    r#| j                            |d          }dddd}| j                            |j        j                  }|                     |          }|rt          |d          r|                    |          }|rd|                    ||           d|d          d|d          g}	|d         D ];}
|
                    d          rdnd}|	                    d|
d           |            <d!                    |	          S d|                    ||           S | j                            |d          }|dk    r:d| j        |<   | 	                                 |r| 
                    ||d           d"S d| j        |<   | 	                                 |r| 
                    ||d           d#S )$z8Handle /voice [on|off|tts|channel|leave|status] command.)rv  enabler  Fr  z}Voice mode enabled.
I'll reply with voice when you send voice messages.
Use /voice tts to get voice replies for all messages.)r  disabler  Tz'Voice mode disabled. Text-only replies.ttsr  z;Auto-TTS enabled.
All replies will include a voice message.)channelr   Nleaver9  zOff (text only)z"On (voice reply to voice messages)z!TTS (voice reply to all messages))r  r  r  get_voice_channel_infozVoice mode: zVoice channel: #channel_namezParticipants: member_countmembersis_speakingz (speaking)rj   z  - r  r   zVoice mode enabled.zVoice mode disabled.)rr  r   r   r  r9  rs  r   r  r  r  r  _handle_voice_channel_join_handle_voice_channel_leaverf  r  r  r   r   )r  r   r   r9  r   r  labelsr  r  r  r  r9  r   s                r   r  z#GatewayRunner._handle_voice_commandL  s     %%''--//5577,&-##EL$9::###(4DW%""$$$ V33GWu3UUUH 
 '''(-DW%""$$$ U33GWt3TTT<<U]](-DW%""$$$ V33GWu3UUU<  (((88?????????W__99%@@@@@@@@@X#''77D(B: F m''(=>>G))%00H ,GG-EFF ,55h?? 	,?vzz$'='=??A4+?AA?n)=??E
 ")_ I I23%%2F2F!NB%GAn,=%Gv%G%GHHHH99U+++:&**T4"8"8::: &**7E::G%,8 )&&((( Z77SX7YYY,,,1 )&&((( Y77SW7XXX--r   c                   K   | j                             |j        j                  }t	          |d          sdS |                     |          }|sdS |                    ||j        j                   d{V }|sdS t	          |d          r| j        |_	        t	          |d          r| j
        |_        	 |                    |           d{V }nr# t          $ re}t                              d|           d|_	        t!          |                                          }d	|v sd
|v sd|v r	 Y d}~dS d| cY d}~S d}~ww xY w|rt%          |j        j                  |j        |<   t	          |d          r!|j                                        |j        |<   d| j        |j        j        <   |                                  |                     ||j        j        d           d|j         dS d|_	        dS )z.Join the user's current Discord voice channel.join_voice_channelz2Voice channels are not supported on this platform.z,This command only works in a Discord server.Nz(You need to be in a voice channel first._voice_input_callback_on_voice_disconnectz Failed to join voice channel: %spynaclnacldaveyzVoice dependencies are missing (PyNaCl / davey). Install or reinstall Hermes with the messaging extra, e.g. `pip install hermes-agent[messaging]`.zFailed to join voice channel: _voice_sourcesr  Fr  zJoined voice channel **zL**.
I'll speak my replies and listen to you. Use /voice leave to disconnect.zFFailed to join voice channel. Check bot permissions (Connect + Speak).)rs  r   r  r  r  rf  get_user_voice_channelr  _handle_voice_channel_inputr  _handle_voice_timeout_cleanupr  r  r   r  r  r   r   r  r9  _voice_text_channelsto_dictr  r  r  r  r   )r  r   r   r  voice_channelr  r  	err_lowers           r   r  z(GatewayRunner._handle_voice_channel_join  s     -##EL$9::w 455 	HGG%%e,, 	BAA%<<el*
 
 
 
 
 
 
 
  	>== 7344 	M,0,LG)7233 	N+/+MG(	8#66}EEEEEEEEGG 
	8 
	8 
	8NN=qAAA,0G)AI9$$)(;(;w)?S?S=     
 8A77777777
	8  
	589M5N5NG(2w 011 J38<3G3G3I3I&x05:DU\12""$$$//9MX]/^^^\-*< \ \ \
 )-%WWs%   5C 
E AD;1D;5E ;E c                 R  K   | j                             |j        j                  }|                     |          }|rt          |d          sdS t          |d          r|                    |          sdS 	 |                    |           d{V  n2# t          $ r%}t          
                    d|           Y d}~nd}~ww xY wd| j        |j        j        <   |                                  |                     ||j        j        d           t          |d	          rd|_        d
S )z Leave the Discord voice channel.leave_voice_channelzNot in a voice channel.is_in_voice_channelNzError leaving voice channel: %sr  Tr  r  zLeft voice channel.)rs  r   r  r  rf  r  r  r  r   r  r  r  r9  r  r  r  )r  r   r   r  r  s        r   r  z)GatewayRunner._handle_voice_channel_leave  s`     -##EL$9::%%e,, 	-ww0EFF 	-,,w 566 	-g>Y>YZb>c>c 	-,,	A--h7777777777 	A 	A 	ANN<a@@@@@@@@	A 27-.   ++GU\5ITX+YYY7344 	1,0G)$$s   8B 
CB>>Cc                     d| j         |<   |                                  | j                            t          j                  }|                     ||d           dS )zCalled by the adapter when a voice channel times out.

        Cleans up runner-side voice_mode state that the adapter cannot reach.
        r  Tr  N)r  r  rs  r   r   r  r  )r  r9  r   s      r   r  z+GatewayRunner._handle_voice_timeout_cleanup  s\    
 %*!   -##H$455++GWt+LLLLLr   r  r  
transcriptc           	        K   | j                             t          j                  }|sdS |j                            |          }|sdS t          |di                               |          }|r=t          j        |          }t          |          |_	        t          |          |_
        nEt          t          j        t          |          t          |          t          |          d          }|                     |          st                              d|           dS 	 |j                            |          }|rS|dd                             dd                              d	d
          }	|                    d| d|	            d{V  n# t$          $ r Y nw xY wddlm}
 t+          ||t,          j         |
|d                    }|                    |           d{V  dS )zHandle transcribed voice from a user in a voice channel.

        Creates a synthetic MessageEvent and processes it through the
        adapter's full message pipeline (session, typing, agent, TTS reply).
        Nr  r  )r  r9  r  rg  r8  z/Unauthorized voice input from user %d, ignoringi  z	@everyoneu   @​everyonez@hereu   @​herez**[Voice]** <@z>: r   )SimpleNamespace)r  r  )r  rT  r   r  )rs  r   r   r  r  r   r   	from_dictr   r  rg  r%  r  r  _clientget_channelr   r  r   typesr  r   r   r  handle_message)r  r  r  r  r   
text_ch_idsource_datar  r  	safe_textr  r   s               r   r  z)GatewayRunner._handle_voice_channel_input  s0      -##H$455 	F155h??
 	F g'7<<@@JJ 	",[99F \\FN"7||F"!)JGg,,#  F ''// 	LLJGTTTF	o11*==G M&uu-55kCTUU]]^egtuu	ll#KG#K#K	#K#KLLLLLLLLL 	 	 	D	 	*)))))$*'FFF	
 
 
 $$U+++++++++++s   $A/F 
F! F!rG  r  rR  c                    |r|                     d          rdS |j        j        }| j                            |d          }|j        t          j        k    }|dk    p|dk    o|}|sdS t          d |D                       }	|	rdS |r|sdS dS )a  Decide whether the runner should send a TTS voice reply.

        Returns False when:
        - voice_mode is off for this chat
        - response is empty or an error
        - agent already called text_to_speech tool (dedup)
        - voice input and base adapter auto-TTS already handled it (skip_double)
          UNLESS streaming already consumed the response (already_sent=True),
          in which case the base adapter won't have text for auto-TTS so the
          runner must handle it.
        zError:Fr  r  r  c              3      K   | ]K}|                     d           dk    o-t          d |                     d          pg D                       V  LdS )r  r  c              3   p   K   | ]1}|                     d i                                d          dk    V  2dS )functionr   text_to_speechNrM  )r   tcs     r   r   zCGatewayRunner._should_send_voice_reply.<locals>.<genexpr>.<genexpr>J  sX         z2&&**6226FF     r   
tool_callsN)r   r   )r   r  s     r   r   z9GatewayRunner._should_send_voice_reply.<locals>.<genexpr>H  s       
 
  GGFOO{*   77<006B    
 
 
 
 
 
r   T)	r   r  r9  r  r   r   r   r  r   )
r  r   rG  r  rR  r9  
voice_modeis_voice_inputshouldhas_agent_ttss
             r   rs  z&GatewayRunner._should_send_voice_reply'  s    $  	8..x88 	5,&%))'599
,0AA 5  ?l*=~ 	  	5  
 
 &
 
 
 
 
  	5  	, 	5tr   rT  c                   K   ddl }d}d}	 ddlm}m}  ||dd                   }|s3	 ||hdhz
  D ]'}		 t	          j        |	           # t          $ r Y $w xY wdS t          j                            t          j
                    dd|                                j        dd          d          }t	          j        t          j                            |          d	
           t          j        |||           d{V }
t#          j        |
          }|                    d|          }|                    d          rt          j                            |          sat*                              d|                    d                     	 ||hdhz
  D ]'}		 t	          j        |	           # t          $ r Y $w xY wdS | j                            |j        j                  }|                     |          }|rRt7          |d          rBt7          |d          r2|                    |          r|                    ||           d{V  nW|rUt7          |d          rE|j        j        ||j        d}|j        j         rd|j        j         i|d<    |j!        di | d{V  n4# tD          $ r'}t*                              d|d	           Y d}~nd}~ww xY w||hdhz
  D ]'}		 t	          j        |	           # t          $ r Y $w xY wdS # ||hdhz
  D ]'}		 t	          j        |	           # t          $ r Y $w xY ww xY w)zEGenerate TTS audio and send as a voice message before the text reply.r   N)text_to_speech_tool_strip_markdown_for_ttsi  hermes_voice
tts_reply_   .mp3T)r  )rT  output_pathrf  r  zAuto voice reply TTS failed: %sr9  play_in_voice_channelr  
send_voice)r9  
audio_pathr  r<  r  zAuto voice reply failed: %sexc_infor   )#uuidtools.tts_toolr  r  r   r  r  r   r   tempfile
gettempdiruuid4hexmakedirsdirnamer  	to_threadr   r   r   isfiler  r  rs  r  r  rf  r  r  r  r9  r  r<  r  r   )r  r   rT  _uuidr  actual_pathr  r  tts_textrW  result_jsonr=  r   r  send_kwargsr  s                   r   rt  zGatewayRunner._send_voice_reply]  sV     
3	SSSSSSSS..tETE{;;H T !+.$7  IaLLLL   D M #%%~9U[[]].ss3999 J K
33dCCCC ' 1#(
! ! !      K Z,,F !**[*==K::i(( {0K0K @&**WBUBUVVV. !+.$7  IaLLLL   D + m''(=>>G ))%00H 8)@AA8)>??8  33H==8 33HkJJJJJJJJJJ 8WWl;; 8$|3"- % 0/ /
 <) T/:EL<R.SK
+(g(77;777777777 	L 	L 	LNN8!dNKKKKKKKK	L !+.$7  IaLLLL   D j+.$7  IaLLLL   Ds   J% A


AAD1J% F..
F;:F; C$J% $L %
K/KL KL $K99
LLL=L,+L=,
L9	6L=8L9	9L=c                   K   ddl m} 	 |                    |          \  }}|                    |          \  }}|                    |          \  }}|j        j        rd|j        j        ind}	h d}
h d}h d}|D ]\  }}	  ||          j                                        }||
v r)|	                    |j        j
        ||	           d{V  n||v r)|                    |j        j
        ||		           d{V  nU||v r)|                    |j        j
        ||	
           d{V  n(|                    |j        j
        ||	           d{V  # t          $ r,}t                              d|j        |           Y d}~
d}~ww xY w|D ]}	  ||          j                                        }||v r)|                    |j        j
        ||	
           d{V  n(|                    |j        j
        ||	           d{V  {# t          $ r+}t                              d|j        |           Y d}~d}~ww xY wdS # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)u=  Extract MEDIA: tags and local file paths from a response and deliver them.

        Called after streaming has already sent the text to the user, so the
        text itself is already delivered — this only handles file attachments
        that the normal _process_message_background path would have caught.
        r   r   r<  N>   .m4a.ogg.wav.opusr  >   .3gp.avi.mkv.mov.mp4.webm>   .gif.jpg.png.jpeg.webp)r9  r  r  )r9  
video_pathr  )r9  
image_pathr  )r9  rf  r  z*[%s] Post-stream media delivery failed: %sz)[%s] Post-stream file delivery failed: %sz'Post-stream media extraction failed: %s)pathlibr   extract_mediaextract_imagesextract_local_filesr  r<  r   r   r  r9  
send_videosend_image_filesend_documentr   r  r  r   )r  rG  r   r   r   media_filesr   cleanedlocal_files_thread_meta_AUDIO_EXTS_VIDEO_EXTS_IMAGE_EXTS
media_pathis_voiceextr  rf  s                     r   ru  z*GatewayRunner._deliver_media_from_response  s      	!     <	I$228<<NK //99JAw$88AANKDILDZdK)?@@`dLCCCKKKKKDDDK(3 b b$
Hb$z**17799Ck))%00$)L$8'1%1 1          
 ++%00$)L$8'1%1 1          
 ++%55$)L$8'1%1 6           &33$)L$8&0%1 4         
 ! b b bNN#OQXQ]_`aaaaaaaab ) a a	a$y//06688Ck))%55$)L$8'0%1 6           &33$)L$8&/%1 4         
 ! a a aNN#NPWP\^_````````aa a$  	I 	I 	INNDaHHHHHHHHH	Isn   A8I CEI 
F!F I FI A7H
I 
I !H;6I ;I  I 
I5I00I5c                 N  K   ddl m}m} i }	 ddl}t          dz  }|                                rot          |d          5 }|                    |          pi }ddd           n# 1 swxY w Y   |                    di           }t          |t                    rd|i}n# t          $ r Y nw xY w|                    dd	          s	 d
S  |d|                    dd                    }	t          j        dt          t          j                                        }
|                                                                }|s!|	                    |
          } |||
          S |	                    |
          }|sd|
 S d}	 t)          |          dz
  }d|cxk    rt+          |          k     rn n||         d         }ndt+          |           dS n# t,          $ r |}Y nw xY w|	                    |
|          }|d         rd|d          d|d          dS d|d          S )uD   Handle /rollback command — list or restore filesystem checkpoints.r   )CheckpointManagerformat_checkpoint_listNr&   r'   r(   checkpointsre  FzXCheckpoints are not enabled.
Enable in config.yaml:
```
checkpoints:
  enabled: true
```Tmax_snapshotsrB  )re  r  r/   zNo checkpoints found for r#   hashz!Invalid checkpoint number. Use 1-rT   r  u   ✅ Restored to checkpoint restored_torR  rF  z1
A pre-rollback snapshot was saved automatically.u   ❌ r9  )tools.checkpoint_managerr  r  r  r   r   r  r  r   r   r}  r   r   r   r   r   homerr  r   list_checkpointsr  r   r  restore)r  r   r  r  cp_cfgrg  	_cfg_pathri  _datamgrr.   argr  target_hashidxr=  s                   r   r  z&GatewayRunner._handle_rollback_command  s     VVVVVVVV 
	$}4I!! 1)g666 3"LL,,2E3 3 3 3 3 3 3 3 3 3 3 3 3 3 3="55fd++ 1'0F 	 	 	D	 zz)U++ 	R 
   **_b99
 
 

 iDIKK(8(899$$&&,,.. 	<..s33K))+s;;; **3// 	54s444	c((Q,CC****#k*******)#.v6N3{;K;KNNNN   	 	 	KKK	 S+..) 	Df].C D DvhGW D D D (fWo'''sH   3B  A%B  %A))B  ,A)-2B   
B-,B-AG G&%G&c                 $  K   |                                                                 }|s	 dS |j        }dt          j                                        d           dt          j        d                                           }t          j
        |                     |||                    }| j                            |           |                    | j        j                   |dd         t!          |          dk    rdnd	z   }d
| d| dS )u)  Handle /background <prompt> — run a prompt in a separate background session.

        Spawns a new AIAgent in a background thread with its own session.
        When it completes, sends the result back to the same chat without
        modifying the active session's conversation history.
        u   Usage: /background <prompt>
Example: /background Summarize the top HN stories today

Runs the prompt in a separate session. You can keep chatting — the result will appear here when done.bg_%H%M%Sr   r6  Nr  r  rj   u   🔄 Background task started: "z"
Task ID: u9   
You can keep chatting — results will appear when done.)rr  r   r  r   r  r  r   urandomr  r  r  _run_background_taskr  r   r  r  r   )r  r   rm  r  rP  r  r  s          r   rv  z(GatewayRunner._handle_background_command  s3      ''))//11 	S  Q//99QQBJqMM<M<M<O<OQQ #%%ffg>>
 
 	""5))) 6 >???"+#f++*:*:C J  J  Jg  J  J  J  	Jr   rm  r   rP  c                    K   ddl m  j                            j                  }|s#t
                              dj                   dS j        r	dj        ind}	 t                      } 	                    |          \  }}|                    d          s)|
                    j        d d	|
           d{V  dS t          j                  ddlm}	 t           |	|                     j        t#          t%          j        dd                                                      _                                          _                             ||           fd}
                     |
           d{V }|r|                    dd          nd}|s"|r |                    d          rd|d          }|r%|                    |          \  }}|                    |          \  }}dd         t9                    dk    rdndz   }d| d}|r'|
                    j        ||z   |           d{V  n*|s(|s&|
                    j        |dz   |           d{V  |pg D ]9\  }}	 |                    j        ||           d{V  *# t<          $ r Y 6w xY w|pg D ]5}	 |                    j        |           d{V  &# t<          $ r Y 2w xY wdS dd         t9                    dk    rdndz   }|
                    j        d| d|           d{V  dS # t<          $ rg}t
                               d           	 |
                    j        d d| |           d{V  n# t<          $ r Y n
w xY wY d}~dS Y d}~dS d}~ww xY w)zCExecute a background agent task and deliver the result to the chat.r   r  z0No adapter for platform %s in background task %sNr<  )r  r  r^   u   ❌ Background task z, failed: no provider credentials configured.r  _get_platform_toolsrm   90c            
      b    ddd         id         i ddddddd	d
j         d                    d          d                    d          d                    d          d                    d          d                    d          d                    dd          d                    d          d
dd	j        dj        dj        } 	 |                     
                              |            S #                     |            w xY w)Nr\   r   r  r  Tverbose_loggingFr  reasoning_configr+  r'  providers_allowedonlyproviders_ignoredignoreproviders_orderorderprovider_sortsortprovider_require_parametersrequire_parametersprovider_data_collectiondata_collectionrC  r  r  
session_dbr  )r  rP  r   )r{  r   r  r  r  r  r  )rk   r  r  r  platform_keyprrm  r5  r  r  rP  
turn_routes    r   run_syncz4GatewayRunner._run_background_task.<locals>.run_syncb  s     $W- +   $2>  $t	
 %*E &6%5 &6%5 "&!3!3 '1nn5H&I&I&I ')ffVnnn ')ffX&6&6&6 %'FF7OOO #%&&... 137KU0S0S0S .0VV4E-F-F-F   'w!" *\#$ #NN%&  $//'( $(#7#7) ,9 11%+ ' 2  
 11%8888D11%8888s   +D D.r6  rj   r9  r9  r  r  u&   ✅ Background task complete
Prompt: ""

r9  r  r  (No response generated)r9  	image_urlcaptionr9  rf  z"

(No response generated)zBackground task %s failedz	 failed: )!r  r  rs  r   r  r  r  r<  r  r  r  r9  r  hermes_cli.tools_configr1  r  r  r  r   r   rx  ry  rz  r{  r-  _run_in_executor_with_contextr  r	  r   
send_imager   r  r  )r  rm  r  rP  r   _thread_metadatar  r\   r  r1  rF  r=  rG  r  imagestext_contentr  r  rK  alt_textr  r  r  r  r  rC  rD  r5  rE  s   ````                  @@@@@@@r   r.  z"GatewayRunner._run_background_task;  s-      	&%%%%%-##FO44 	NNMv`ghhhF>D>NXK)9::TXy	.00K$($G$G' %H % %!E> "%%i00 llN`7```- #         
 /@@LCCCCCC%&9&9+|&T&TUU'B +BD!I!IJJN#::<<%5D"!%!8!8!:!:D88WWJ9 9 9 9 9 9 9 9 9 9 9 9 9 9 9>  ==hGGGGGGGGF;AIvzz"2B777rH 7 76::g+>+> 76VG_66  .(/(=(=h(G(G%X'.'='=h'G'G$ "+#f++2B2BKQ7QQQ !,, & & 5!1 '          
    !,, & &)B B!1 '          -3Lb  'Ix%00$*N&/$, 1          
 %    $/#4"  J%33$*N&0 4           %     !"+#f++2B2BKll"Nkgkkk- #             		 		 		8'BBBll"NH7HHQHH- #          
          		s   +A$M GM #J<;M <
K	M K			M "K65M 6
L M LM A	M 
ON?9)N#"N?#
N0-N?/N00N??Oc                    
K   |                                                                 }|s	 dS |j        }                     |          
t	           di                               
          }|r|                                sdS t           d          si  _        ddl	}dt          j                                        d           d|                                j        dd	          }t          j                             ||
|                    } j                            |           | j        
<    
fd
}|                    |           |dd         t+          |          dk    rdndz   }	d|	 dS )uD   Handle /btw <question> — ephemeral side question in the same chat.zUsage: /btw <question>
Example: /btw what module owns session title sanitization?

Answers using session context. No tools, not persisted._active_btw_tasksz?A /btw is already running for this chat. Wait for it to finish.r   Nbtw_r,  r      c                     j                             |            j                                      | u rj                            d            d S d S rh  )r  r  rV  r   r   )r   r  r   s    r   _cleanupz3GatewayRunner._handle_btw_command.<locals>._cleanup  s]    "**4000%))+66$>>&**;===== ?>r   r  r  rj      💬 /btw: "z!"
Reply will appear here shortly.)rr  r   r  r  r   r   doner  rV  r  r   r  r  r  r  r  r  _run_btw_taskr  r   r  r   )r  r   questionr  rC  r  rP  r  rZ  r  r   s   `         @r   r  z!GatewayRunner._handle_btw_command  s     ))++1133 	J  226:: 4!4b99==kJJ 	UHMMOO 	UTTt011 	.+-D"T00::TTU[[]]=NrPQr=RTT#D$6$6xV]$^$^__""5))).3{+	> 	> 	> 	> 	> 	>
 	)))3B3-CMMB,>,>55BGIgIIIIr   r^  c           	      `   K   ddl m  j                            |j                  }|s#t
                              d|j                   dS |j        r	d|j        ind}	 t                      } 	                    |||          \  }}	|	                    d          s%|
                    |j        d|	           d{V  dS t          |j                                                                                     _                             |||	           j         j                            |          }
|
r*|
t&          ur!t)          t+          |
d
g           pg           n9 j                            |          } j                            |j                  d|z    f	d}                     |           d{V }|r|                    d          pdnd}|s"|r |                    d          rd|d          }|sd}|                    |          \  }}|                    |          \  }}|dd         t;          |          dk    rdndz   }d| d}|r'|
                    |j        ||z   |           d{V  n*|s(|s&|
                    |j        |dz   |           d{V  |pg D ]9\  }}	 |                    |j        ||           d{V  *# t>          $ r Y 6w xY w|pg D ]5}	 |                     |j        |           d{V  &# t>          $ r Y 2w xY wdS # t>          $ rd}t
          !                    d           	 |
                    |j        d| |           d{V  n# t>          $ r Y n
w xY wY d}~dS Y d}~dS d}~ww xY w)z?Execute an ephemeral /btw side question and deliver the answer.r   r  z*No adapter for platform %s in /btw task %sNr<  r  r^   u4   ❌ /btw failed: no provider credentials configured.r  _session_messageszs[Ephemeral /btw side question. Answer using the conversation context. No tools available. Be direct and concise.]

c            
      \  	  d!d	d         i	d         i ddddddd	g d
dj         d	                    d          d                    d          d                    d          d                    d          d                    d          d                    dd          d                    d          dddd dj        dddddd} 	 |                                                    |            S #                     |            w xY w)"Nr\   r   r  r  r  Tr4  Fr  r5  r+  r'  r6  r7  r8  r9  r:  r;  r<  r=  r>  r?  r@  rA  rC  r  rB  r  r  skip_context_filespersist_session)r  r  rP  r   )r{  r   r  r  r  )
rk   r  
btw_prompthistory_snapshotrC  rD  r5  r  rP  rE  s
    r   rF  z-GatewayRunner._run_btw_task.<locals>.run_sync  s     $W- +   $%1  $t	
 %*E &(R &6%5 "&!3!3 '1nn5H&I&I&I ')ffVnnn ')ffX&6&6&6 %'FF7OOO #%&&... 137KU0S0S0S .0VV4E-F-F-F   'w!" *\#$  $t%& $(#7#7'( !%)* (,t+, %*E- 09 11%/-= ' 2   11%8888D11%8888s   'D D+r6  rj   r9  r9  rI  r  r  r[  rG  rH  rJ  rM  z/btw task %s failedu   ❌ /btw failed: )"r  r  rs  r   r  r  r  r<  r  r  r  r9  r  rx  rz  r{  r-  r  r  r  r   r   r  rV  r  rC  rO  r  r	  r   rP  r   	send_filer  )r  r^  r  r   rP  r   r  r  r\   r  r  r~  rF  r=  rG  r  rR  rS  r  r  rK  rT  r  r  r  rd  re  rC  rD  r5  rE  s   `   `                   @@@@@@@r   r]  zGatewayRunner._run_btw_task  s      	&%%%%%-##FO44 	NNGZabbbF:@:JTV%566PTt	.00K$($G$G'' %H % %!E>
 "%%i00 llNJ) #         
 /@@L#::<<!%!8!8!:!:D885.YYJ'B !044[AAM `6M!M!M#'?RTV(W(W(][]#^#^   $ 2 H H P P#'#5#E#EmF^#_#_ K  9  9  9  9  9  9  9  9  9  9  9  9  9D  ==hGGGGGGGGF?EM

#344:2H 7 76::g+>+> 76VG_66 54$+$9$9($C$C!K#*#9#9(#C#C FLssmH0B0BuuKG2G222F ll"N"\1) #          
  K ll"N"%>>) #          )/"  #	8!,,V^ybj,kkkkkkkkkk    D  +0b  
!++FNj+YYYYYYYYYY    D   		 		 		2G<<<ll"N333) #          
          		s   )A!L? HL? #K32L? 3
L =L? ?L  	L? 
"L-,L? -
L:7L? 9L::L? ?
N-	N(%&NN(
NN(NN((N-c                   
K   ddl |                                                                                                }t          dz  
|                                 | _        |                                 | _        dt          f
fd}|sP| j        }|d}n0|
                    d          du rd	}n|
                    d
d          }| j        rdnd}d| d| dS t          |j        j                  }|dv rd| _         |d| dd           d| dS |dv rd| _         |d| dd           d| dS |                                }|dk    rddi}	n|dv rd|d}	nd| dS |	| _         |d|          rd | d!S d | d"S )#u  Handle /reasoning command — manage reasoning effort and display toggle.

        Usage:
            /reasoning              Show current effort level and display state
            /reasoning <level>      Set reasoning effort (none, minimal, low, medium, high, xhigh)
            /reasoning show|on      Show model reasoning in responses
            /reasoning hide|off     Hide model reasoning from responses
        r   Nr&   key_pathc                    	 i }                                 r@t          d          5 }	                    |          pi }ddd           n# 1 swxY w Y   |                     d          }|}|dd         D ].}||vst	          ||         t
                    si ||<   ||         }/|||d         <   t          |           dS # t          $ r'}t          	                    d| |           Y d}~dS d}~ww xY w	z(Save a dot-separated key to config.yaml.r'   r(   NrT   r  Tz Failed to save config key %s: %sF
r   r  r  r   r   r!  r   r   r  r9  
rh  r   r  r  r  r   r  r  r  r  s
           r   _save_config_keyzAGatewayRunner._handle_reasoning_command.<locals>._save_config_key{  a    %%'' >kG<<< >&*nnQ&7&7&=2> > > > > > > > > > > > > > >~~c**%crc ) )A''z'!*d/K/K'%'
%ajGG$)R!!+{;;;t   ?1MMMuuuuu;   'C AC AC AA.C 
C7C22C7zmedium (default)re  Fznone (disabled)rq  mediumu   on ✓r  u*   🧠 **Reasoning Settings**

**Effort:** `z`
**Display:** zF

_Usage:_ `/reasoning <none|minimal|low|medium|high|xhigh|show|hide>`)showrv  Tzdisplay.platforms.z.show_reasoninguZ   🧠 ✓ Reasoning display: **ON**
Model thinking will be shown before each response on ****.)hider  u*   🧠 ✓ Reasoning display: **OFF** for **rb  rs  )minimallowrp  highxhigh)re  rq     ⚠️ Unknown argument: `zT`

**Valid levels:** none, minimal, low, medium, high, xhigh
**Display:** show, hidezagent.reasoning_effortu"   🧠 ✓ Reasoning effort set to `z4` (saved to config)
_(takes effect on next message)_z` (this session only))r  rr  r   r   r   rx  ry  r|  r}  r   r   r  r  r  )r  r   r   rm  rcleveldisplay_staterC  rq  parsedr  r  s             @@r   r{  z'GatewayRunner._handle_reasoning_commandk  ss      	%%''--//5577"]2!%!<!<!>!>#88::	s 	 	 	 	 	 	 	(  	'Bz*	""e++)x22(,(<GHH%MW %W W -W W W ,EL,ABB>!!#'D O,OOOQUVVV\JV\ \ \
 ?""#(D O,OOOQVWWWPPPPP V'FFDDD!%88FF*V * * * "(4f== 	VuuuuuUUUUUr   c                   
K   ddl ddlm} |                                                                                                }t          dz  
|                                 | _        t                      }t          |          } ||          sdS dt          f
fd}|r|dk    r| j        d	k    rd
nd}d| dS |dv rd	| _        d
}d}	n|dv rd| _        d}d}	nd| dS  |d|          rd|	 dS d|	 dS )uL   Handle /fast — mirror the CLI Priority Processing toggle in gateway chats.r   N)model_supports_fast_moder&   uO   ⚡ /fast is only available for OpenAI models that support Priority Processing.rh  c                    	 i }                                 r@t          d          5 }	                    |          pi }ddd           n# 1 swxY w Y   |                     d          }|}|dd         D ].}||vst	          ||         t
                    si ||<   ||         }/|||d         <   t          |           dS # t          $ r'}t          	                    d| |           Y d}~dS d}~ww xY wrj  rk  rl  s
           r   rm  z<GatewayRunner._handle_fast_command.<locals>._save_config_key  rn  ro  r9  rx  rw  rt  u(   ⚡ Priority Processing

Current mode: `z(`

_Usage:_ `/fast <normal|fast|status>`>   rv  rw  FAST>   r  rt  NORMALrx  z*`

**Valid options:** normal, fast, statuszagent.service_tieru   ⚡ ✓ Priority Processing: **z5** (saved to config)
_(takes effect on next message)_z** (this session only))r  r  r~  rr  r   r   r   rz  r{  r  r$  r   )r  r   r~  r   r  r\   rm  r9  saved_valuer  r  r  s             @@r   r|  z"GatewayRunner._handle_fast_command  s     >>>>>>%%''--//5577"]2!4466*,,&{33''.. 	edd	s 	 	 	 	 	 	 	(  	tx''#1Z??VVXF8"(8 8 8 >!!!+D KEE&&&!%D"KEE:T : : :
 0+>> 	srUrrrrNNNNNr   c                    K   ddl m}m}m} |                     |j                  } ||          }|r ||           dS  ||           dS )uP   Handle /yolo — toggle dangerous command approval bypass for this session only.r   )disable_session_yoloenable_session_yolois_session_yolo_enableduW   ⚠️ YOLO mode **OFF** for this session — dangerous commands will require approval.uW   ⚡ YOLO mode **ON** for this session — all commands auto-approved. Use with caution.)tools.approvalr  r  r  r  r  )r  r   r  r  r  r   r   s          r   r~  z"GatewayRunner._handle_yolo_command  s      	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 225<@@))+66 	m  ---ll,,,llr   c                 j  K   ddl }t          dz  }t          |j        j                  }	 i }|                                r@t          |d          5 }|                    |          pi }ddd           n# 1 swxY w Y   |                    di                               dd          }n# t          $ r d}Y nw xY w|s	 d	S g d
}ddddd
}	ddl
m}
  |
||dd          }||vrd}|                    |          dz   t          |          z  }||         }	 d|vs(t          |                    d          t                    si |d<   |d         }d|vs(t          |                    d          t                    si |d<   ||d         vs.t          |d                             |          t                    si |d         |<   ||d         |         d<   t!          ||           |	|          d| dS # t          $ r3}t"                              d|           |	|          d| dcY d}~S d}~ww xY w)u  Handle /verbose command — cycle tool progress display mode.

        Gated by ``display.tool_progress_command`` in config.yaml (default off).
        When enabled, cycles the tool progress mode through off → new → all →
        verbose → off for the *current platform*.  The setting is saved to
        ``display.platforms.<platform>.tool_progress`` so each channel can
        have its own verbosity level independently.
        r   Nr&   r'   r(   rv   tool_progress_commandFzThe `/verbose` command is not enabled for messaging platforms.

Enable it in `config.yaml`:
```yaml
display:
  tool_progress_command: true
```)r  r>  r  rJ  u9   ⚙️ Tool progress: **OFF** — no tool activity shown.uv   ⚙️ Tool progress: **NEW** — shown when tool changes (preview length: `display.tool_preview_length`, default 40).ut   ⚙️ Tool progress: **ALL** — every tool call shown (preview length: `display.tool_preview_length`, default 40).uJ   ⚙️ Tool progress: **VERBOSE** — every tool call with full arguments.rC  tool_progressr  r#   r?  z
_(saved for **u%   ** — takes effect on next message)_z%Failed to save tool_progress mode: %sz
_(could not save to config: r~  )r  r   r  r  r  r   r  r  r   r   rh  rD  indexr   r   r!  r   r  r  )r  r   r  r  rC  r  r  gate_enabledcycledescriptionsrD  r   r)  new_moderv   r  s                   r   r}  z%GatewayRunner._handle_verbose_command  s(      	"]2+EL,ABB	!K!!## :+888 :A"&.."3"3"9rK: : : : : : : : : : : : : : :&??9b99==>UW\]]LL 	! 	! 	! LLL	!  	?  100N L Jc	
 
 	CBBBBB))+|_V[\\%G{{7##a'3u::5:	R++:kooi>X>XZ^3_3_+)+I&!),G'))GKK<T<TVZ1[1[)')$7;#777z'R]J^JbJbcoJpJprv?w?w757$\2BJGK .?k;777) U U!-U U U  	R 	R 	RNNBAFFF"8,QQAQQQQQQQQQ	RsT   'B, A6*B, 6A::B, =A:>-B, ,B;:B;CG5 5
H2?(H-'H2-H2c                 >  K   |j         }| j                            |          }| j                            |j                  }|rt          |          dk     rdS |                                pd                                pd	 ddlm	} ddl
m} ddlm} |                     |          }|                     ||	          \  }	}
|
                    d
          sdS d |D             t                    } |           |di |
|	ddddg|j        d	 d _        j        }|j        }|                    |          }|                    |          }||k    r	 |                                dS t/          j                    }|                    dfd           d{V \  }}j        }||j        k    r ||_        | j                                         | j                            ||           | j                            |j        d            ||          } |||          }|                                n# |                                w xY wd|d          g}r|                    d d           |                    |d                    |d         r|                    |d                    d                    |          S # t@          $ r*}tB          "                    d|           d| cY d}~S d}~ww xY w)a  Handle /compress command -- manually compress conversation context.

        Accepts an optional focus topic: ``/compress <focus>`` guides the
        summariser to preserve information related to *focus* while being
        more aggressive about discarding everything else.
        r7  z?Not enough conversation to compress (need at least 4 messages).rj   Nr   r  )summarize_manual_compressionr  )r  r   r^   z*No provider configured -- cannot compress.c                     g | ]Y}|                     d           dv |                     d          .|                     d           |                     d          dZS r  rM  r  s     r   r  z:GatewayRunner._handle_compress_command.<locals>.<listcomp>p  sg       55==$999aeeI>N>N9 v1553C3CDD999r   Tr  r  c                      d S rh  r   r  s     r   rk  z8GatewayRunner._handle_compress_command.<locals>.<lambda>  r  r   zHNothing to compress yet (the transcript is still all protected context).c                  6                         d           S )Nrj   )r*  focus_topicr+  )r*  r  r  r  s   r   rk  z8GatewayRunner._handle_compress_command.<locals>.<lambda>  s     I77bP]kv7ww r   rQ  u   🗜️ headlinezFocus: "r  
token_linenoter   zManual compress failed: %szCompression failed: r   )#r  r  rV  r  rC  r   rr  r   r  r  !agent.manual_compression_feedbackr  r  r  r  r  r   r  context_compressorprotect_first_n_align_boundary_forward_find_tail_cut_by_tokensr  r  r  r  r  rc  rr  r   r   r   r   r  r  )r  r   r  r~  r  r  r  r  r   r\   r  original_count
compressorcompress_startcompress_endr  
compressedr   new_session_id
new_tokensr  r  r  r*  r  r  r  s                          @@@@r   r  z&GatewayRunner._handle_compress_commandR  s       *@@HH$44]5MNN 	U#g,,**TT --//52<<>>F$N	.))))))VVVVVVKKKKKK66v>>K$($G$G' %H % %!E> "%%i00 DCC    D
 !YYN::4@@M     "*(3   I&9&;&;	#&9
!+!;!+!C!CD.!Y!Y)BB4XX!\11e< --i888889 /11&*&:&:wwwwwww' ' ! ! ! ! ! !
A "+!5!]%===/=M,&,,..."55njQQQ"11!-! 2    <;JGG
66!	  --i8888--i88885
 3556E :8888999LL.///v .WV_---99U### 	. 	. 	.NN7;;;-!--------	.sL   	AK( !=K( AI (K( ?B?I >K( I++A<K( (
L2LLLc                   K   |j         }| j                            |          }|j        }| j        sdS | j                            |          }|G	 | j                            ||j        r|j        j        nd|j	                   n# t          $ r Y nw xY w|                                                                }|r|	 | j                            |          }n# t          $ r}d| cY d}~S d}~ww xY w|sdS 	 | j                            ||          rd| dS d	S # t          $ r}d| cY d}~S d}~ww xY w| j                            |          }	|	r	d
| d|	 dS d
| dS )uB   Handle /title command — set or show the current session's title.Session database not available.NrD  )rC  r  r     ⚠️ uE   ⚠️ Title is empty after cleanup. Please use printable characters.u   ✏️ Session title set: **rb  zSession not found in database.u   📌 Session: `z`
Title: **z/`
No title set. Usage: `/title My Session Name`)r  r  rV  rC  r  r  create_sessionr  r   r  r   rr  r   sanitize_titler  set_session_title)
r  r   r  r~  rC  existing_title	title_arg	sanitizedr  rX  s
             r   r  z#GatewayRunner._handle_title_command  s     *@@HH"-
 	544 );;JGG! //)4:OR6?00"N 0    
     **,,2244	 	f% ,;;IFF		 % % %$}}$$$$$$% _^^%#55j)LL <G)GGGG;; % % %$}}$$$$$$% $66zBBE fJJJJJJJeeeeesN   5B 
BB C 
C4%C/)C4/C4< D 
D8)D3-D83D8c                   K   | j         sdS |j        }|                     |          }|                                                                }|s	 |j        r|j        j        nd}| j                             |d          }d |D             }|s	 dS dg}|dd         D ]M}	|	d         }
|	                    d	d
          dd         }|rd| dnd
}|	                    d|
 d|            N|	                    d           d
                    |          S # t          $ r*}t                              d|           d| cY d}~S d}~ww xY w| j                             |          }|sd| dS | j                            |          }|j        |k    rd| dS 	 t%          j        |                     |j        |                    }| j                            |           |                    | j        j                   n2# t          $ r%}t                              d|           Y d}~nd}~ww xY w|| j        v r| j        |= | j                            ||          }|sdS | j                             |          p|}
| j                            |          }|rt;          d |D                       nd}|rd| d|dk    rdnd
 d nd
}d!|
 d| d"S )#u@   Handle /resume command — switch to a previously-named session.r  Nr  )r  limitc                 <    g | ]}|                     d           |S )rX  rM  )r   ss     r   r  z8GatewayRunner._handle_resume_command.<locals>.<listcomp>  s'    @@@w@!@@@r   zNo named sessions found.
Use `/title My Session` to name your current session, then `/resume My Session` to return to it later.u   📋 **Named Sessions**
rX  r  rj   r  u    — _r   u   • **rb  z 
Usage: `/resume <session name>`r   z"Failed to list titled sessions: %szCould not list sessions: zNo session found matching '**z?**'.
Use `/resume` with no arguments to see available sessions.u   📌 Already on session **rr  z!Memory flush on resume failed: %szFailed to switch session.c                 D    g | ]}|                     d           dk    |S r  r  rM  r  s     r   r  z8GatewayRunner._handle_resume_command.<locals>.<listcomp>+  ,    GGGqquuV}}/F/F/F/F/Fr   r   r   messager#   r  r  u   ↻ Resumed session **z. Conversation restored.)r  r  r  rr  r   r  r   list_sessions_richr   r   r   r   r  r  resolve_session_by_titler  rV  rC  r  r  r  r  r   r  r  r  switch_sessionr  r  r   )r  r   r  r   r   user_sourcesessionstitledr  r  rX  r  preview_partr  	target_idcurrent_entryr  r  r  	msg_countmsg_parts                        r   r  z$GatewayRunner._handle_resume_command  s      	544226::%%''--// 	777=Pfo33D+>>&b ?   A@X@@@ K 
 55 C CAgJEeeIr223B37G:A#I#6G#6#6#6#6rLLL!A%!A!A<!A!ABBBB@AAAyy''' 7 7 7A1EEE61666666667
 $==dCC	 	M M M M *@@HH#y0099999	A!-**=+C[QQ K "&&{333))$*@*HIIII 	A 	A 	ALL<a@@@@@@@@	A $...$[1 &55k9MM	 	/..  229==E $44Y??LSZCGGGGGGHHHYZ	OX`K	KK)q..33bKKKK^`SSSSSSSs?   A D BD 
E"EEEA&H 
H3H..H3c                 l  K   ddl }| j        sdS |j        }|                     |          }| j                            |          }| j                            |j                  }|sdS |                                	                                }ddl
m
} |                                }	|	                    d          }
|                                j        dd         }|
 d| }|r|}n=| j                            |j                  }|pd	}| j                            |          }|j        }	 | j                            ||j        r|j        j        nd
t)          | j        t,                    r0| j                            di           pi                     d          nd|           n7# t0          $ r*}t2                              d|           d| cY d}~S d}~ww xY w|D ]}	 | j                            ||                    dd          |                    d          |                    d          p|                    d          |                    d          |                    d          |                    d                     # t0          $ r Y w xY w	 | j                            ||           n# t0          $ r Y nw xY w| j                            ||          }|sdS |                     |           t?          d |D                       }d| d| d|dk    rdnd  d!| d"| d#S )$u  Handle /branch [name] — fork the current session into a new independent copy.

        Copies conversation history to a new session so the user can explore
        a different approach without losing the original.
        Inspired by Claude Code's /branch command.
        r   Nr  u3   No conversation to branch — send a message first.r   z%Y%m%d_%H%M%SrX  r   rZ  r  r\   r  )rC  r  r\   parent_session_idz#Failed to create branch session: %szFailed to create branch: r  r  r  	tool_namer   r  tool_call_idrI  )rC  r  r  r  r  r  rI  z*Branch created but failed to switch to it.c                 D    g | ]}|                     d           dk    |S r  rM  r  s     r   r  z8GatewayRunner._handle_branch_command.<locals>.<listcomp>  r  r   u   ⑂ Branched to **z** (r  r#   r  rj   z copied)
Original: `z`
Branch: `z/`
Use `/resume` to switch back to the original.) r  r  r  r  r  rV  r  rC  rr  r   r   r  r  r  r  r  get_next_title_in_lineager  r  r   r   r  r!  r   r   r  r9  append_messager  r  ro  r   )r  r   r  r  r   r  r  branch_name_dtr  timestamp_str
short_uuidr  branch_titlecurrent_titlebaser  r  r  r  r  s                        r   r  z$GatewayRunner._handle_branch_command0  s      	 	544226:: *@@HH$44]5MNN 	IHH,,..4466 	-,,,,,ggii_55[[]]&rr*
)88J88  	L&LL ,>>}?WXXM ,HD+EEdKKL)4		3++)06Nv,,YMWX\XceiMjMjtt{w339r>>yIIIpt"3	 ,      	3 	3 	3LL>BBB2q22222222	3
  	 	C //-00GGI..!ggk22Ecggfoo"ww|44!$!8!8!ggk22 0        	..~|LLLL 	 	 	D	 &55k>RR	 	@?? 	  ---GGGGGGHH	= = == =+4>>CCr= =+= = '= = =	
sD   0A;F, ,
G 6GG G (B)J
JJ#J? ?
KKc           
        K   |j         }|                     |          }| j                            |          }|r	|t          u r_t          | dd          }t          | dd          }|r;|9|5  |                    |          }|r|d         }ddd           n# 1 swxY w Y   |rt          |d          r|j        dk    rg }|                                }	|	rC|	j	        r<ddl
m}
 |                    d |
|	                      |                    d           t          |d	d          pd}t          |d
d          pd}t          |dd          pd}t          |dd          pd}|                    d           |                    d|j         d           |                    d|d           |r|                    d|d           |r|                    d|d           |                    d|d           |                    d|j        d           |                    d|j                    	 ddlm}m}  ||j         |||||          t          |dd          t          |dd                    }|j        >|j        dk    rdnd}|                    d| dt)          |j                  d            n |j        d!k    r|                    d"           n# t*          $ r Y nw xY w|j        }|j        rU|j        r t3          d#|j        |j        z  d#z            nd}|                    d$|j        dd%|j        dd&|d'd(           |j        r|                    d)|j                    d*                    |          S | j                            |          }| j                            |j                  }|r4dd+l m!} d, |D             } ||          }d-tE          |           d.|dd/S d0S )1a:  Handle /usage command -- show token usage for the current session.

        Checks both _running_agents (mid-turn) and _agent_cache (between turns)
        so that rate limits, cost estimates, and detailed token breakdowns are
        available whenever the user asks, not only while the agent is running.
        r  Nr  r   session_total_tokens)format_rate_limit_compactu   ⏱️ **Rate Limits:** rj   session_input_tokenssession_output_tokenssession_cache_read_tokenssession_cache_write_tokensu   📊 **Session Token Usage**zModel: `r   zInput tokens: r  zCache read tokens: zCache write tokens: zOutput tokens: zTotal: zAPI calls: )CanonicalUsageestimate_usage_cost)input_tokensoutput_tokenscache_read_tokenscache_write_tokensr[   r]   )r[   r]   r$  r  rH  $z.4fincludedzCost: includedr&  rE  z / r  r8  z%)zCompressions: r   r  c                 j    g | ]0}|                     d           dv |                     d          .|1S )r  r  r  rM  r  s     r   r  z7GatewayRunner._handle_usage_command.<locals>.<listcomp>  sB    fff!!%%--;P*P*PUVUZUZ[dUeUe*PA*P*P*Pr   u    📊 **Session Info**
Messages: z
Estimated context: ~zC tokens
_(Detailed usage available after the first agent response)_z)No usage data available for this session.)#r  r  r  r   r  r   r  session_api_callsget_rate_limit_statehas_dataagent.rate_limit_trackerr  r   r\   r  agent.usage_pricingr  r  
amount_usdr9  r  r   r  rP  r  r  compression_countr   r  rV  r  rC  r  r  r   )r  r   r  r   rk   r  rS  cachedr  rl_stater  r  r  
cache_readcache_writer  r  cost_resultprefixrs  pctr~  r  r  r  approxs                             r   r  z#GatewayRunner._handle_usage_command  so      226:: $((55 	*!888!$(;TBBKT>488F *v1  * *#ZZ44F * &q	* * * * * * * * * * * * * * *
  9	$WU$:;; 9	$@WZ[@[@[E 1133H !H- !NNNNNN]8Q8QRZ8[8[]]^^^R    #5*@!DDIL#E+BAFFK!M (CQGGL1J!%)EqIINQKLL7888LL2EK222333LL:,:::;;; CA:AAABBB ECKCCCDDDLL<=<<<===LLA5#=AAABBBLL@u'>@@AAASSSSSSSS11K"N%1&3*4+6	   %UJ==$UJ==
 
 
 )5$/$6+$E$ESS2FLL!V&!V!V59O3P3P!V!V!VWWWW ':55LL!1222    *C% kUXUgnc#s58JJSPQQQmni)?iiicFXiii^aiiiijjj$ GEc.CEEFFF99U### *@@HH$44]5MNN 		KKKKKKffwfffD33D99FO YYO O'-:O O O ;:s%   , BBBB,K. .
K;:K;c                   
K   ddl }|                                                                }ddl}|                    dd|          }dd|r	|                                }d}|t          |          k     r||         dk    rT|dz   t          |          k     r>	 t          ||dz                      n# t          $ r d||dz             cY S w xY w|d	z  }nm||         d
k    r'|dz   t          |          k     r||dz            |d	z  }n:||         	                                rt          ||                   |dz  }n|dz  }|t          |          k     	 ddl
m ddlm
 |                                }
fd}|                    d|           d{V S # t           $ r,}	t"                              d|	d           d|	 cY d}	~	S d}	~	ww xY w)z>Handle /insights command -- show usage insights and analytics.r   Nz'[\u2012\u2013\u2014\u2015](days|source)z--\1r  z--daysr#   zInvalid --days value: r5  z--sourcero  )InsightsEnginec                                   }  |           }|                               }|                    |          }|                                  |S )N)daysr  )generateformat_gatewayr  )dbenginereportr=  r  rp  r  r  s       r   _run_insightsz=GatewayRunner._handle_insights_command.<locals>._run_insights  sW    Y[['++d6BB..v66


r   zInsights command error: %sTr  zError generating insights: )r  rr  r   r  r  r   r   r  r  isdigitr  rp  agent.insightsr  r  r  r   r  r9  )r  r   _asyncior   r  r   r   r  r  r  r  rp  r  r  s             @@@@r   r  z&GatewayRunner._handle_insights_command  sz     """"%%''--// 	wwA7DQQ  	JJLLEAc%jj..8x''AECJJ,>,>G"5Q<00% G G GFa!eFFFFFGFAA1X++AE

0B0B"1q5\FFAA1X%%'' uQx==DFAAFA c%jj.. 	5......555555,,..D        --dMBBBBBBBBB 	5 	5 	5LL5q4LHHH444444444	5s1   B8 8CCAF! !
G+!GGGc                   K   t          j                    }	 ddlm}m}m}m} |5  t          |                                          }ddd           n# 1 swxY w Y   |	                    d|           d{V  |	                    d|           d{V }|5  t          |                                          }	ddd           n# 1 swxY w Y   |	|z
  }
||	z
  }|	|z  }dg}|r8|
                    dd                    t          |                                |
r8|
                    dd                    t          |
                                |r8|
                    dd                    t          |                                |	s|
                    d	           n6|
                    d
t          |           dt          |	           d           g }|
r8|
                    dd                    t          |
                                |r8|
                    dd                    t          |                                |r8|
                    dd                    t          |                                |rt          |           dnd}|rd                    |          dz   nd}dd| | dd}	 | j                            |j                  }| j                            |j        |           n# t&          $ r Y nw xY wd                    |          S # t&          $ r*}t(                              d|           d| cY d}~S d}~ww xY w)zGHandle /reload-mcp command -- disconnect and reconnect all MCP servers.r   )shutdown_mcp_serversdiscover_mcp_tools_serversr  Nu   🔄 **MCP Servers Reloaded**
u   ♻️ Reconnected: r  u   ➕ Added: u   ➖ Removed: zNo MCP servers connected.u   
🔧 z tool(s) available from z
 server(s)zAdded servers: zRemoved servers: zReconnected servers: z MCP tool(s) now availablezNo MCP tools availablez. rj   r  z)[SYSTEM: MCP servers have been reloaded. zD. The tool list for this conversation has been updated accordingly.]r  r   zMCP reload failed: %su   ❌ MCP reload failed: )r  r  tools.mcp_toolr  r  r  r  r   r  r  r   r   r  r   r  rV  r  rq  rC  r   r  r  )r  r   r  r  r  r  r  old_servers	new_toolsconnected_serversaddedremovedreconnectedr  change_partstool_summarychange_detail
reload_msgr~  r  s                       r   r  z(GatewayRunner._handle_reload_mcp_command  s     '))>	1````````````  3 3!(--//223 3 3 3 3 3 3 3 3 3 3 3 3 3 3
 &&t-ABBBBBBBBB #2249KLLLLLLLLI  9 9$'$8$8!9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 &3E!$55G+k9K67E VTDIIf[>Q>Q4R4RTTUUU GE499VE]]+C+CEEFFF KITYYvg-G-GIIJJJ$ s89999qs9~~qqsSdOeOeqqqrrr
 L R##$Pdiiu6N6N$P$PQQQ V##$T		&//8R8R$T$TUUU ^##$\DIIf[FYFY<Z<Z$\$\]]]LUsc)nnHHHH[sL>JRDIIl33d::PRM i}  iVb  i  i  i J $ 2 H H V V"77!,j        99U### 	1 	1 	1NN2A6660Q00000000	1s   L2 "AL2 AL2 A=L2 "C:L2 C

L2 C
G>L2 ?L L2 
LL2 LL2 2
M&<M!M&!M&c                   K   |j         }|                     |          }ddlm}m}  ||          s'|| j        v r| j                            |           dS dS |                                                                	                                
                                }d|v }d |D             }t          d |D                       rd}	d	}
n"t          d
 |D                       rd}	d}
nd}	d}
 |||	|          }|sdS | j                            |j                  }|r|                    |j                   |dk    rd| dnd}t"                              d||
           d|dk    rdnd d|
 | dS )u  Handle /approve command — unblock waiting agent thread(s).

        The agent thread(s) are blocked inside tools/approval.py waiting for
        the user to respond.  This handler signals the event so the agent
        resumes and the terminal_tool executes the command inline — the same
        flow as the CLI's synchronous input() approval.

        Supports multiple concurrent approvals (parallel subagents,
        execute_code).  ``/approve`` resolves the oldest pending command;
        ``/approve all`` resolves every pending command at once.

        Usage:
            /approve              — approve oldest pending command once
            /approve all          — approve ALL pending commands at once
            /approve session      — approve oldest + remember for session
            /approve all session  — approve all + remember for session
            /approve always       — approve oldest + remember permanently
            /approve all always   — approve all + remember permanently
        r   resolve_gateway_approvalhas_blocking_approvaluQ   ⚠️ Approval expired (agent is no longer waiting). Ask the agent to try again.zNo pending command to approve.r  c                     g | ]
}|d k    |S )r  r   r   r  s     r   r  z9GatewayRunner._handle_approve_command.<locals>.<listcomp>  s    3331U

Q


r   c              3      K   | ]}|d v V  	dS ))always	permanentpermanentlyNr   r  s     r   r   z8GatewayRunner._handle_approve_command.<locals>.<genexpr>  s(      NNqq::NNNNNNr   r  z (pattern approved permanently)c              3      K   | ]}|d v V  	dS ))r   sesNr   r  s     r   r   z8GatewayRunner._handle_approve_command.<locals>.<genexpr>  s(      <<Q((<<<<<<r   r   z$ (pattern approved for this session)oncerj   resolve_allr#   r  
 commands)z4User approved %d dangerous command(s) via /approve%su   ✅ Commandr  z	 approvedz. The agent is resuming...)r  r  r  r  r  r  r   rr  r   r   r   r   rs  r   r  resume_typing_for_chatr9  r  r  )r  r   r  r   r  r  r   r  	remainingchoice	scope_msgr  r  	count_msgs                 r   rt  z%GatewayRunner._handle_approve_commandf  s     ( 226::	
 	
 	
 	
 	
 	
 	
 	
 %$[11 	4d555'++K888jj33 %%''--//5577==??tm33333	NNINNNNN 	F9II<<)<<<<< 	F>IIFI((f+VVV 	433 =$$V_55 	<++FN;;;.3aii*****R	JES\]]]pEAIISS2pp	p9ppppr   c                 8  K   |j         }|                     |          }ddlm}m}  ||          s'|| j        v r| j                            |           dS dS |                                                                	                                }d|v } ||d|          }|sdS | j
                            |j                  }	|	r|	                    |j                   |dk    rd	| d
nd}
t                              d|           d|dk    rdnd d|
 dS )u  Handle /deny command — reject pending dangerous command(s).

        Signals blocked agent thread(s) with a 'deny' result so they receive
        a definitive BLOCKED message, same as the CLI deny flow.

        ``/deny`` denies the oldest; ``/deny all`` denies everything.
        r   r  u(   ❌ Command denied (approval was stale).zNo pending command to deny.r  r.  r  r#   r  r  rj   z-User denied %d dangerous command(s) via /denyu   ❌ Commandr  z deniedrT   )r  r  r  r  r  r  r   rr  r   r   rs  r   r  r  r9  r  r  )r  r   r  r   r  r  r   r  r  r  r  s              r   ru  z"GatewayRunner._handle_deny_command  sv      226::	
 	
 	
 	
 	
 	
 	
 	
 %$[11 	1d555'++K888AA00%%''--//5577tm((f+VVV 	100 =$$V_55 	<++FN;;;.3aii*****R	CUKKKJEAIISS2JJiJJJJr   c                    	K   ddl }ddlmmm	mm  |j                    }	fd}|                    d|           d{V S )u6  Handle /debug — upload debug report (summary only) and return paste URLs.

        Gateway uploads ONLY the summary report (system info + log tails),
        NOT full log files, to protect conversation privacy.  Users who need
        full log uploads should use ``hermes debug share`` from the CLI.
        r   N)_capture_dumpcollect_debug_reportupload_to_pastebin_schedule_auto_delete_GATEWAY_PRIVACY_NOTICEc                  d    	            }  d|           }i }	  |          |d<   n# t           $ r}d| cY d }~S d }~ww xY w 
t          |                                                     dddg}t          d |D                       }|                                D ]$\  }}|                    d|d	| d
|            %|                    d           |                    d           |                    d           |                    d           d                    |          S )Nr  )	log_lines	dump_textReportu#   ✗ Failed to upload debug report: rj   z**Debug report uploaded:**c              3   4   K   | ]}t          |          V  d S rh  r[  )r   r  s     r   r   zSGatewayRunner._handle_debug_command.<locals>._collect_and_upload.<locals>.<genexpr>  s(      33c!ff333333r   r   <z`  u'   ⏱ Pastes will auto-delete in 6 hours.z<For full log uploads, use `hermes debug share` from the CLI.z3Share these links with the Hermes team for support.r   )r   r   r  rm  r  r   r   )r)  r  urlsr   r  label_widthr  r   r&  r"  r%  r#  r$  s           r   _collect_and_uploadz@GatewayRunner._handle_debug_command.<locals>._collect_and_upload  s~   %I))C9MMMFDC!3!3F!;!;X C C CBSBBBBBBBBC "!$t{{}}"5"5666,b2NPRSE33d33333K"jjll A A
s??????#??@@@@LLLLBCCCLLWXXXLLNOOO99U###s   + 
A?AA)	r  hermes_cli.debugr"  r#  r$  r%  r&  r  r  )
r  r   r  r  r/  r&  r"  r%  r#  r$  s
        @@@@@r   r  z#GatewayRunner._handle_debug_command  s       		
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 (w'))	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$0 ))$0CDDDDDDDDDr   c           
      x  K   ddl }ddl}ddl}ddlm} ddlm}m} |j        j        }|| j	        vrdS  |            rd |d           S t          t                    j        j                                        }	|	dz  }
|
                                sd	S t                      }|s	 d
S t           dz  }t           dz  }t           dz  }|                     |j                  }|j        j        j        |j        j        |j        j        | |j                                                    d}|                    d          }|                     |j        |                     |                    |           |                    d           d                    d |D                       }d| dt;          j        t?          |                     dt;          j        t?          |                     }	 |                     d          }|r(|!                    |dd|g|j"        |j"        d           n&|!                    dd|g|j"        |j"        d           nH# tF          $ r;}|                    d           |                    d           d| cY d}~S d}~ww xY w| $                                 dS )us  Handle /update command — update Hermes Agent to the latest version.

        Spawns ``hermes update`` in a detached session (via ``setsid``) so it
        survives the gateway restart that ``hermes update`` may trigger. Marker
        files are written so either the current gateway process or the next one
        can notify the user when the update finishes.
        r   Nr   )
is_managedformat_managed_messageu^   ✗ /update is only available from messaging platforms. Run `hermes update` from the terminal.u   ✗ zupdate Hermes Agentr   u+   ✗ Not a git repository — cannot update.u   ✗ Could not locate the `hermes` command. Hermes is running, but the update command could not find the executable on PATH or via the current Python interpreter. Try running `hermes update` manually in your terminal.r^  .update_output.txt.update_exit_code)r  r9  r  r   rL  r2  Tr  r  c              3   >   K   | ]}t          j        |          V  d S rh  r   r   s     r   r   z7GatewayRunner._handle_update_command.<locals>.<genexpr>9  s,      !K!K%+d"3"3!K!K!K!K!K!Kr   zPYTHONUNBUFFERED=1 z update --gateway > z* 2>&1; status=$?; printf '%s' "$status" > r  r  -cr  u   ✗ Failed to start update: u8   ⚕ Starting Hermes update… I'll stream progress here.)%r   r(  r	  r   ra  r2  r3  r  r  _UPDATE_ALLOWED_PLATFORMSr   r  r   r  r   r1  r   r  r   r9  r  r  rp  rl  r  r  r   r  r   r  r  r   r)  r  r  r   rs  )r  r   r   r(  r	  r   r2  r3  r  project_rootgit_dirr  pending_pathr  exit_code_pathr   pending_tmp_pendinghermes_cmd_str
update_cmdr  r  s                         r   r  z$GatewayRunner._handle_update_command  sm      	%%%%%%HHHHHHHH <(4999ss:<< 	JI001FGGIIIH~~,3;;=='~~ 	A@@(**
 	I  $&<<"%99%(;;225<@@-3|+|+&%1133
 
 $//77

7 3 3444\***... !K!K
!K!K!KKKW. W W+c+..//W W49KN@S@S4T4TW W 	
	6h//J   z:%-%-&*	 !       T:.%-%-&*	 !     	6 	6 	64000!!T!2225!55555555	6
 	00222IIs   8A%I 
J#(0JJ#J#c                    t          | dd          }|r|                                sdS 	 t          j        |                                           | _        dS # t          $ r t                              d           Y dS w xY w)z;Ensure a background task is watching for update completion._update_notification_taskNz;Skipping update notification watcher: no running event loop)	r   r\  r  r  _watch_update_progressrB  r   r  r  )r  existing_tasks     r   rs  z1GatewayRunner._schedule_update_notification_watchY  s    &A4HH 	!3!3!5!5 	F	X-4-@++--. .D***  	X 	X 	XLLVWWWWWW	Xs   +A $B ?B        @      @      @poll_intervalstream_intervalc                     !"#K   ddl }ddlt          dz  }t          dz  }t          dz  }t          dz  }t          dz  }	t          j                    ##                                |z   }
dd!d}||fD ]}|                                r	  |j        |                                          }|	                    d          }|	                    d	          !|	                    d
          }|r4!r2t          |          }| j        	                    |          |s| d! } n# t          $ r Y w xY wr!sQt                              d           |                                s|                                r#                                |
k     r|                                r|                                  d{V  dS t          j        |           d{V  |                                s|                                r#                                |
k     |                                s|                                rC|                                s/|                    d           |                                  d{V  dS dt$          dt$          ffdd}#                                "d d* !"#fd}#                                |
k     rR|                                r|                                rU	 |                                }t'          |          |k    r ||d         z   t'          |          }n# t(          $ r Y nw xY w |             d{V  	 |                                                                pd}t-          |          }|dk    r                    !d           d{V  n/                    !d                    |                     d{V  t                              d||           n2# t          $ r%}t                              d|           Y d}~nd}~ww xY w|||||	fD ]}|                    d           t          dz                      d           | j                            |d           dS |                                rU	 |                                }t'          |          |k    r ||d         z   t'          |          }n# t(          $ r Y nw xY w                                 r+#                                "z
  |k    r |             d{V  |	                                r|r| j        	                    |          s	  |j        |	                                          }|	                    dd          }|	                    dd          }|r |             d{V  d}t;          t=                    dd          U	                     !|||           d{V  d}n2# t          $ r%}t                               d |           Y d}~nd}~ww xY w|s,|rd!| d"nd}                    !d#| | d$           d{V  d| j        |<   |	                    d           t                              d%||dd&                    n9# |j!        t(          f$ r%}t                               d'|           Y d}~nd}~ww xY wt          j        |           d{V  #                                |
k     R|                                st                              d(|           |                    d            |             d{V  	                     !d)           d{V  n# t          $ r Y nw xY w|||||	fD ]}|                    d           t          dz                      d           | j                            |d           dS dS )+a  Watch ``hermes update --gateway``, streaming output + forwarding prompts.

        Polls ``.update_output.txt`` for new content and sends chunks to the
        user periodically.  Detects ``.update_prompt.json`` (written by the
        update process when it needs user input) and forwards the prompt to
        the messenger.  The user's next message is intercepted by
        ``_handle_message`` and written to ``.update_response``.
        r   Nr^  r_  r4  r5  z.update_prompt.jsonr  r9  r   r   zOUpdate watcher: cannot resolve adapter/chat_id, falling back to completion-only124rT  r   c                 2                         dd|           S )Nz\x1b\[[0-9;]*[A-Za-z]rj   )r  )rT  r  s    r   _strip_ansiz9GatewayRunner._watch_update_progress.<locals>._strip_ansi  s    773R>>>r   rj   c                    K                                    sddS                                             d
                                	sdS dfdt          dt                              D             } | D ]U}	                     d| d           d{V  $# t
          $ r%}t                              d|           Y d}~Nd}~ww xY wdS )	z!Send buffered output to the user.rj   N  c                 *    g | ]}||z            S r   r   )r   r   clean	max_chunks     r   r  zOGatewayRunner._watch_update_progress.<locals>._flush_buffer.<locals>.<listcomp>  s&    VVVeAa)mO,VVVr   r   z```

```zUpdate stream send failed: %s)r   r@  r  r   r  r   r  r  )chunkschunkr  rQ  rR  rM  r   bufferr9  last_stream_timer  s      @@r   _flush_bufferz;GatewayRunner._watch_update_progress.<locals>._flush_buffer  s2      <<>> K''--//EF#yy{{ IVVVVVeAs5zz96U6UVVVF E EE!,,w0D0D0D0DEEEEEEEEEE  E E ELL!@!DDDDDDDDEE Es    B((
C2CCr   u   ✅ Hermes update finished.u(   ❌ Hermes update failed (exit code {}).z&Update finished (exit=%s), notified %sz$Update final notification failed: %sTr  r1  rm  r  Fsend_update_prompt)r9  rm  r  r   z%Button-based update prompt failed: %sz (default: r  u"   ⚕ **Update needs your input:**

zG

Reply `/approve` (yes) or `/deny` (no), or type your answer directly.z!Forwarded update prompt to %s: %sr  z Failed to read update prompt: %sz$Update watcher timed out after %.0fsu-   ❌ Hermes update timed out after 30 minutes.r  )"r   r  r   r  r  r@  r   r   r   r   r   rs  r   r  r  rr  r  r  r   r   r  r   r  r  formatr  r  r  r   r   rA  rY  r  r  )$r  rH  rI  r0   r   r;  claimed_pathr  r<  prompt_pathr  r   r   r=  r  r  
bytes_sentrX  r  exit_code_rawr  r  rW  prompt_dataprompt_textr  sent_buttonsbtn_errdefault_hintr  rM  r   rV  r9  rW  r  s$                                @@@@@@@r   rC  z$GatewayRunner._watch_update_progressf  sR
      	#&<<#&DD"%99%(;;"%::'))99;;( !<0 	 	D{{}} (dj)9)9::G#*;;z#:#:L%kk)44G")++m"<"<K# F F#+L#9#9"&-"3"3H"="=* F-9*E*EG*E*EKE    D   	g 	NNlmmm&&(( 3L,?,?,A,A 3tyy{{U]G]G]!((** 88:::::::::FmM222222222	  &&(( 3L,?,?,A,A 3tyy{{U]G]G]
 ##%% 7)<)<)>)> 7H]H]H_H_ 7))%00044666666666F	?c 	?c 	? 	? 	? 	? 	? 	? 
99;;	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E* iikkH$$$$&& %%'' "-"7"7"9"9w<<*44"gjkk&::F),WJ"   #moo%%%%%%%	N$2$<$<$>$>$D$D$F$F$M#M #M 2 2I A~~%ll74QRRRRRRRRRR%ll74^4e4efo4p4pqqqqqqqqqKK H)U`aaaa  N N NNN#I1MMMMMMMMN 'k(+7 . .AHHH---- 22::d:KKK+//TBBB !!## )3355G7||j00'*++"66%(\\
   D ||~~ &499;;1A#Ao"U"U#moo%%%%%%% ""$$ (H (H 7;;KHH(H&H",$*[-B-B-D-D"E"EK"-//(B"?"?K)ooi<<G"  h ,moo-------',"4==2FMMY	_&-&@&@,3+6,30;	 'A '" '" !" !" !" !" !" !" !" 04#, _ _ _ &-TV] ^ ^ ^ ^ ^ ^ ^ ^_+ GN+V+C+C+C+C+CTVL"),, '!A#.!A0<!A !A !A# #        DH3K@
 $**d*;;;$GVabecebeVfggg,g6 H H HLL!CQGGGGGGGGH -.........} iikkH$$B $$&& 	?NNA7KKK%%e,,,-//!!!!!!!ll7,[\\\\\\\\\\   "L+$k3 * *D))))..66$6GGG'++K>>>>>	? 	?s   BD((
D54D5	AM 
MM.B%P 
QP>>Q6AS: :
TT=B [ >!X  [  
Y*Y
[ 
YA5[ [;[66[;^# #
^0/^0c                 ,	  K   ddl }ddl}t          dz  }t          dz  }t          dz  }t          dz  }|                                s|                                sdS d}|}	 |                                r	 |                    |           n# t
          $ rv |                                s_Y |rZ|                    d	           |                    d	           |                    d	           |                    d	           dS dS Y nww xY w|                                s_	 |rZ|                    d	           |                    d	           |                    d	           |                    d	           dS dS  |j        |                                          }	|		                    d
          }
|		                    d          }|                                st                              d           d}|}|                    |           	 |rZ|                    d	           |                    d	           |                    d	           |                    d	           dS dS |                                                                pd}t          |          }d}|                                r|                                }t          |
          }| j        	                    |          }|r|r|                    dd|                                          }|r4t#          |          dk    rd|dd         z   }|dk    rd| d}nd| d}n|dk    rd}nd}|                    ||           d{V  t                              d|
||           n2# t&          $ r%}t                              d|           Y d}~nd}~ww xY w|rX|                    d	           |                    d	           |                    d	           |                    d	           n`# |rY|                    d	           |                    d	           |                    d	           |                    d	           w w xY wdS )a  If an update finished, notify the user.

        Returns False when the update is still running so a caller can retry
        later. Returns True after a definitive send/skip decision.

        This is the legacy notification path used when the streaming watcher
        cannot resolve the adapter (e.g. after a gateway restart where the
        platform hasn't reconnected yet).
        r   Nr^  r_  r4  r5  FTr  r  r9  z2Update notification deferred: update still runningr   rj   z\x1b\[[0-9;]*mrO  r3  iTu!   ✅ Hermes update finished.

```
rS  u   ❌ Hermes update failed.

```
u(   ✅ Hermes update finished successfully.u]   ❌ Hermes update failed. Check the gateway logs or run `hermes update` manually for details.z0Sent post-update notification to %s:%s (exit=%s)z#Post-update notification failed: %s)r   r  r   r   r   r  r  r   r   r   r  r  r   r  r   rs  r  r   r  r   r  )r  r   r  r;  r[  r  r<  cleanupactive_pending_pathr=  r  r9  r^  r  rJ  r  r   r  r  s                      r   rr  z'GatewayRunner._send_update_notification-  s      	#&<<#&DD"%99%(;;""$$ 	\-@-@-B-B 	5*>	7""$$ $ ((6666( $ $ $'..00 $#h  7#**d*;;;##t#444""d"333%%%66666	7 7k$ $$ "((** d  7#**d*;;;##t#444""d"333%%%66666	7 7a !dj!7!7!9!9::G";;z22Lkk),,G!((** PQQQ&2#$$\222N  7#**d*;;;##t#444""d"333%%%66666	7 7K +4466<<>>E#MM**I F!!## 1$..00  --Hm''11G 7 !2B??EEGG ~6{{T))!&!7 A~~RVRRRP6PPP A~~H}ll7C000000000F 	    	E 	E 	ENN@!DDDDDDDD	E  7#**d*;;;##t#444""d"333%%%666	  7#**d*;;;##t#444""d"333%%%6666	7 tsi   "N' 7B N' D+N' 
N' DN' BN' 5D1N' &P4 '
O1OP4 OP4 4ARc                 d  K   ddl }t          dz  }|                                sdS 	 |                    |                                          }|                    d          }|                    d          }|                    d          }|r|s	 |                    d           dS t          |          }| j                            |          }|s4t          
                    d	|           	 |                    d           dS |rd|ind}	|                    |d
|	           d{V  t                              d||           n2# t          $ r%}
t                              d|
           Y d}
~
nd}
~
ww xY w|                    d           dS # |                    d           w xY w)zANotify the chat that initiated /restart that the gateway is back.r   Nr  r  r9  r<  Tr  z6Restart notification skipped: %s adapter not connectedu;   ♻ Gateway restarted successfully. Your session continues.r  z"Sent restart notification to %s:%szRestart notification failed: %s)r   r   r   r   r   r   r  r   rs  r  r  r  r  r   r  )r  re  notify_pathr  r  r9  r<  r  r   r  r  s              r   rt  z(GatewayRunner._send_restart_notification  s+     "%;;!!## 	F 	0;;{446677D88J//Lhhy))G--I w 2 $//////  --Hm''11G L      $///// 4=FY//$H,,M!          
 KK4   
  	A 	A 	ANN<a@@@@@@@@	A $/////K$////s>   A*E +AE 
AE F 
E<E72F 7E<<F F/r=  c           
      d   ddl m}  ||j        j        j        |j        j        |j        j        pd|j        j        rt          |j        j                  nd|j        j	        rt          |j        j	                  nd|j        j
        rt          |j        j
                  nd|j                  S )a@  Set session context variables for the current async task.

        Uses ``contextvars`` instead of ``os.environ`` so that concurrent
        gateway messages cannot overwrite each other's session state.

        Returns a list of reset tokens; pass them to ``_clear_session_env``
        in a ``finally`` block.
        r   )set_session_varsrj   )r  r9  r  r<  r  rg  r   )gateway.session_contextrj  r  r  r   r9  r  r<  r   r  rg  r   )r  r=  rj  s      r   rY  zGatewayRunner._set_session_env  s     	=<<<<<^,2N*n.4"7>~7OWc'.2333UW3:>3IQC.///r7>~7OWc'.2333UW+
 
 
 	
r   tokensc                 (    ddl m}  ||           dS )z>Restore session context variables to their pre-handler values.r   )clear_session_varsN)rk  rn  )r  rl  rn  s      r   rv  z GatewayRunner._clear_session_env  s+    >>>>>>6"""""r   c                 ~   K   t          j                    }t                      } |j        d|j        |g|R   d{V S )zJRun blocking work in the thread pool while preserving session contextvars.N)r  r  r   r  run)r  funcr   r  rs  s        r   rO  z+GatewayRunner._run_in_executor_with_context  sP      '))nn)T)$EEEEEEEEEEEr   	user_textr  c                 T  K   ddl m} ddl}d}g }|D ]}	 t                              d|            |||           d{V }|                    |          }	|	                    d          r3|	                    dd	          }
|                    d
|
 d| d           n|                    d| d           # t          $ r>}t          	                    d|           |                    d| d           Y d}~d}~ww xY w|r d
                    |          }|r| d| S |S |S )a  
        Auto-analyze user-attached images with the vision tool and prepend
        the descriptions to the message text.

        Each image is analyzed with a general-purpose prompt.  The resulting
        description *and* the local cache path are injected so the model can:
          1. Immediately understand what the user sent (no extra tool call).
          2. Re-examine the image with vision_analyze if it needs more detail.

        Args:
            user_text:   The user's original caption / message text.
            image_paths: List of local file paths to cached images.

        Returns:
            The enriched message string with vision descriptions prepended.
        r   )vision_analyze_toolNzDescribe everything visible in this image in thorough detail. Include any text, code, data, objects, people, layout, colors, and any other notable visual information.zAuto-analyzing user image: %s)rK  user_promptr  analysisrj   z0[The user sent an image~ Here's what I can see:
zA]
[If you need a closer look, use vision_analyze with image_url: z ~]z[The user sent an image but I couldn't quite see it this time (>_<) You can try looking at it yourself with vision_analyze using image_url: r   zVision auto-analysis error: %sz[The user sent an image but something went wrong when I tried to look at it~ You can try examining it yourself with vision_analyze using image_url: r  )tools.vision_toolsrt  r   r  r  r   r   r   r   r9  r   )r  rr  r  rt  re  analysis_promptenriched_partsr   r  r=  r  r  r  s                r   r  z)GatewayRunner._enrich_message_with_vision  s     * 	;:::::8 	  	 	D<dCCC$7$7" /% % %       [11::i(( "(**Z"<"<K"))0K 0 0&*0 0 0    #))H@DH H H  
    =qAAA%%D<@D D D         	[[00F 2 11i111Ms   B$B;;
D4C>>Dr  c                 v  K   t          | j        dd          s+d}|                                 r|dz  }|dz  }|r| d| S |S ddlm} dd	l}g }|D ]%}	 t                              d
|            |j        ||           d	{V }|d         r"|d         }	|	                    d|	 d           n~|
                    dd          }
d|
v s|
                    d          r6d}|                                 r|dz  }|dz  }|	                    |           n|	                    d|
 d           # t          $ r;}t                              d|           |	                    d           Y d	}~d	}~ww xY w|r>d                    |          }d}|r|                                |k    r|S |r| d| S |S |S )a  
        Auto-transcribe user voice/audio messages using the configured STT provider
        and prepend the transcript to the message text.

        Args:
            user_text:   The user's original caption / message text.
            audio_paths: List of local file paths to cached audio files.

        Returns:
            The enriched message string with transcriptions prepended.
        stt_enabledTzI[The user sent voice message(s), but transcription is disabled in config.z{ You have a skill called hermes-agent-setup that can help users configure Hermes features including voice, tools, and more.r   r  r   )transcribe_audioNzTranscribing user voice: %sr  r  z8[The user sent a voice message~ Here's what they said: "z"]r9  r/  r  z8Neither VOICE_TOOLS_OPENAI_KEY nor OPENAI_API_KEY is setu   [The user sent a voice message but I can't listen to it right now — no STT provider is configured. A direct message has already been sent to the user with setup instructions.zC[The user sent a voice message but I had trouble transcribing it~ (z)]zTranscription error: %sze[The user sent a voice message but something went wrong when I tried to listen to it~ Let them know!]z.(The user sent a message with no text content))r   r  r  tools.transcription_toolsr|  r  r  r  r  r   r   r   r   r9  r   r   )r  rr  r  disabled_noter|  r  ry  r   r=  r  r9  _no_stt_noter  r  _placeholders                  r   r  z0GatewayRunner._enrich_message_with_transcription  s       t{M488 
	!gM$$&& X S M 9'88Y888  >>>>>> (	 (	D':DAAA0w01A4HHHHHHHH)$ !'!5J"))C4>C C C   
 #JJw@@E)U22 ++,fgg 37 %  0022 (!DL
 %+&--l;;;;&--;16; ; ;      6:::%%D         		[[00F LL Y__..,>> 2 11i111Ms   CD11
E6;0E11E6r?  c                 r   ddl m} t          |                    d          pd                                          }d}d}d}|r	 | j                                         | j        j                            |          }|rt          |dd          r|j	        S n3# t          $ r&}t                              d||           Y d}~nd}~ww xY wt          |          }	|	r|	d         }|	d	         }|	d
         }t          |                    d          p|pd                                                                          }
t          |                    d	          p|pd                                                                          }t          |                    d
          p|pd                                          }|
r|r|sdS 	 t          |
          }n,# t          $ r t                              d|
           Y dS w xY w ||||t          |                    d          pd                                          pdt          |                    d          pd                                          pdt          |                    d          pd                                          pd          S )a  Resolve the canonical source for a synthetic background-process event.

        Prefer the persisted session-store origin for the event's session key.
        Falling back to the currently active foreground event is what causes
        cross-topic bleed, so don't do that.
        r   )r   r   rj   originNz>Synthetic process-event session-store lookup failed for %s: %sr  r8  r9  z9Synthetic process event has invalid platform metadata: %rr<  r  rg  )r  r9  r8  r<  r  rg  )gateway.sessionr   r   r   r   r  r  r  r   r  r   r  r  r>  r   r   r  )r  r?  r   r   derived_platformderived_chat_typederived_chat_idr  r   r  r  r8  r9  r  s                 r   _build_process_event_sourcez)GatewayRunner._build_process_event_sourcei  s    	211111#''-006B77==?? 	5
"11333*377DD (WUHd;; ( <'   T        )55G 5#*:#6 $+K$8!"))"4CGGJ//I3CIrJJPPRRXXZZ,,G0AGRHHNNPPVVXX	cggi((AOArBBHHJJ 	I 	W 	4	..HH 	 	 	NNK   44	 }#''+..4"55;;==E	**0b117799AT#''+..4"55;;==E
 
 
 	
s+   AB 
C	#CC	
G %HHr  c                   K   |                      |          }|s1t                              d|                    dd                     dS t	          |j        d          r|j        j        nt          |j                  }d}| j        	                                D ]\  }}|j        |k    r|} n|sdS 	 ddl
m}m}	  |||	j        |d	          }
t                              d
||j        |j                   |                    |
           d{V  dS # t$          $ r&}t                              d|           Y d}~dS d}~ww xY w)zInject a watch-pattern notification as a synthetic message event.

        Routing must come from the queued watch event itself, not from whatever
        foreground message happened to be active when the queue was drained.
        zCDropping watch notification with no routing metadata for process %srC  rD  Nr   r   r@  TrT  r   r  r+  uA   Watch pattern notification — injecting for %s chat=%s thread=%srH  )r  r  r  r   r  r  r   r   rs  r  r  r   r   rs  r  r9  r<  r  r   r9  )r  r  r?  r  r  r   rW  r  r   r   synth_eventr  s               r   rm  z(GatewayRunner._inject_watch_notification  s      11#66 	NNUi00   F18'1R1Rl--X[\b\kXlXlM'')) 	 	DAqw-'' (  	F	FHHHHHHHH&,(-	  K KKS 	   ((55555555555 	F 	F 	FLLA1EEEEEEEEE	Fs   5AD 
EE  Er  c           
      Z	  K   ddl m} |d         }|d         }|                    dd          }|                    dd          }|                    dd          }|                    d	d          }|                    d
d          }	|                    dd          }
|                    dd          }|                                 }t                              d||||           |dk    rZ|sX	 t          j        |           d{V  |                    |          }||j        rn:t                              d|           dS d}	 t          j        |           d{V  |                    |          }|nt          |j
                  }||k    }|}|j        r6ddl m} |r`|                    |          sJddlm} |j
        r ||j
        dd                   nd}d| d|j         d|j         d| d	}|                     ||||||	|
d          }|st                              d|           nVd}| j                                        D ]\  }}||j        k    r|} n|r|j        r	 ddlm}m}  |||j        |d          }t                              d|||j        |j                   |                    |           d{V  n2# t:          $ r%}t                              d|           Y d}~nd}~ww xY wn|d v p|d!k    o|j        d"v}|r|j
        r|j
        d#d         nd}d$| d%|j         d&| d}d}| j                                        D ]\  }}|j        |k    r|} n|r\|rZ	 |rd	|ind} |                     ||| '           d{V  n2# t:          $ r%}t                              d(|           Y d}~nd}~ww xY wn|r|d)k    r|s|j
        r|j
        d*d         nd}d$| d+| d}d}| j                                        D ]\  }}|j        |k    r|} n|r\|rZ	 |rd	|ind} |                     ||| '           d{V  n2# t:          $ r%}t                              d(|           Y d}~nd}~ww xY wHt                              d,|           dS )-u  
        Periodically check a background process and push updates to the user.

        Runs as an asyncio task. Stays silent when nothing changed.
        Auto-removes when the process exits or is killed.

        Notification mode (from ``display.background_process_notifications``):
          - ``all``    — running-output updates + final message
          - ``result`` — final completion message only
          - ``error``  — final message only when exit code != 0
          - ``off``    — no messages at all
        r   re  rC  check_intervalr   rj   r  r9  r<  r  rg  notify_on_completeFzCProcess watcher started: %s (every %ss, notify=%s, agent_notify=%s)r  TNz"Process watcher ended (silent): %s)
strip_ansii0rL  z completed (exit code z).
Command: z	
Output:
r   )rC  r   r  r9  r<  r  rg  zHDropping completion notification with no routing metadata for process %sr@  r  uU   Process %s finished — injecting agent notification for session %s chat=%s thread=%sz Agent notify injection error: %s)r  r=  r9  )r   Niz[Background process z finished with exit code z~ Here's the final output:
r  zWatcher delivery error: %sr  iz is still running~ New output:
zProcess watcher ended: %s)!r  rf  r   r  r  r  r  r  exitedr   output_bufferis_completion_consumedtools.ansi_stripr  r  r   r  r  rs  r  r  r9  r  r   r   rs  r  r<  r  r   r9  r   r  )!r  r  rf  rC  r  r   r  r9  r<  r  rg  agent_notifynotify_moder   last_output_lencurrent_output_lenhas_new_output	_pr_checkr  rR  r  r  r   rW  r  r   r   r  r  r  
new_outputr  	send_metas!                                    r   rv  z"GatewayRunner._run_process_watcher  s      	<;;;;;\*
+,kk-44J33++i,,KKR00	++i,,KKR00	{{#7??>>@@Z (K	G 	G 	G %mH---------*..z::?gn?	
 LL=zJJJFm	F-)))))))))&**:66G!$W%:!;!;//AN0O~ bF QPPPPP 1	(H(H(T(T 1;;;;;;HOH]e::g&;EFF&CDDDceD,z , ,&-&7, ,$+O, , %), , ,  "==&0'2$1#*%.#*%.? ?  F " f&   "G $ 3 3 5 5 " "1//&'G!E 0  P6> PPXXXXXXXX*6,%/-8-='-)-	+ + +K #KK w * + & & 0   #*"8"8"E"EEEEEEEEE( P P P"LL)KQOOOOOOOOP
  #44 W#w.U73DI3U  ! JBIBW!_!6uvv!>!>]_JCz C CT[Te C C5?C C C ! #G $ 3 3 5 5 " "17m33&'G!E 4  J7 JJDM(Wi(@(@SWI"),,wy,"Y"YYYYYYYYY( J J J"LL)EqIIIIIIIIJ FK5$8$8$8 >E=RZW245599XZ
2: 2 2$.2 2 2   M//11  DAqw-//"# 0  Fw FF@I$S[)$<$<t	%ll7L9lUUUUUUUUUU$ F F F%A1EEEEEEEEFYm	F^ 	0*=====sI   4AK 
LK>>L;&N" "
O,OO5&Q 
R&RRr   r  ephemeral_promptc           
      >   ddl }ddl}t          |                    dd          pd          }|r9|                    |                                                                          nd}|                    | ||                    dd          |                    dd          |                    dd          |rt          |          ng |pdgdt          	          }|                    |                                                                          dd
         S )u>  Compute a stable string key from agent config values.

        When this signature changes between messages, the cached AIAgent is
        discarded and rebuilt.  When it stays the same, the cached agent is
        reused — preserving the frozen system prompt and tool schemas for
        prompt cache hits.
        r   Nr^   rj   r]   r[   r   T)	sort_keysr     )	hashlibr   r   r   sha256encode	hexdigestr  r  )	r\   r   r  r  r  _j_api_key_api_key_fingerprintblobs	            r   _agent_config_signaturez%GatewayRunner._agent_config_signaturee  s     	#""""""" w{{9b117R88PX`w~~hoo.?.?@@JJLLL^`xx$J++J++J++,<D'(((" !&B
   
 
 ~~dkkmm,,6688"==r   c                     | j                             |          }|s||fS |                    d|          }dD ]}|                    |          }||||<   ||fS )a  Apply /model session overrides if present, returning (model, runtime_kwargs).

        The gateway /model command stores per-session overrides in
        ``_session_model_overrides``.  These must take precedence over
        config.yaml defaults so the switched model is actually used for
        subsequent messages.  Fields with ``None`` values are skipped so
        partial overrides don't clobber valid config defaults.
        r\   r  rc  r   )r  r   r\   r  r!  rj  vals          r   r  z+GatewayRunner._apply_session_model_override  s{     044[AA 	).((We,,B 	* 	*C,,s##C&)s#n$$r   agent_modelc                 p    | j                             |          }|duo|                    d          |k    S )zGReturn True if *agent_model* matches an active /model session override.Nr\   r  )r  r   r  r!  s       r   _is_intentional_model_switchz*GatewayRunner._is_intentional_model_switch  s9    044[AAt#LW(=(=(LLr   c                     t          | dd          }|r8|5  | j                            |d           ddd           dS # 1 swxY w Y   dS dS )zBRemove a cached agent for a session (called on /new, /model, etc).r  N)r   r  r   )r  r   r  s      r   ro  z!GatewayRunner._evict_cached_agent  s    1488 	9 9 9!%%k48889 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9	9 	9s   ?AAc                 F   t          j        dd                                          }|r|                    d          S t	                      }|                    d          pi                     dd                                          }|r|                    d          S dS )zReturn the proxy URL if proxy mode is configured, else None.

        Checks GATEWAY_PROXY_URL env var first (convenient for Docker),
        then ``gateway.proxy_url`` in config.yaml.
        GATEWAY_PROXY_URLrj   r   r  	proxy_urlN)r   r   r   rb  r  r   )r  r   r"  s      r   _get_proxy_urlzGatewayRunner._get_proxy_url  s     i+R006688 	#::c??""$$wwy!!'R,,["==CCEE 	#::c??"tr   rF  r3  rC  r4  c           
        K   	 ddl m}m}	 n# t          $ r
 dg dg dcY S w xY w|                                 }
|
sdg dg dS t          j        dd                                          }g }|r|                    d|d	           |D ]J}|	                    d
          }|	                    d          }|dv r|r|                    ||d	           K|                    d|d	           ddi}|rd| |d<   |r||d<   d|dd}d}t          t          | dd          dd          }|ddlm}  |            }t          |j                  }t                      }ddlm}  |||d          }||j        o
|j        dk    nt)          |          }|j        r
d|j        i}nd}|r	 ddlm}m} ddlm} | j        	                    |j                  }|r_t          |dd          }|r|j        nd} d }!|j        |j        k    rd} d}! ||j        |j        | |!!          }" |||j        |"|"          }n2# t@          $ r%}#tB          "                    d#|#           Y d}#~#nd}#~#ww xY wd}$|r&tG          j$        |%                                          }$| j        	                    |j                  }|r4	 |&                    |j        |$           d{V  n# t@          $ r Y nw xY wd}%tO          j'                    }&	  |	dd%&          }' ||''          4 d{V }(|((                    |
 d(||)          4 d{V 	 })|)j)        d*k    r|)*                                 d{V }*tB          +                    d+|)j)        |
|*dd,                    d-|)j)         d.|*dd/          g dg dcddd          d{V  cddd          d{V  |r|,                                 |$rS	 tG          j-        |$d0'           d{V  S # tF          j.        tF          j/        f$ r |$0                                 Y S w xY wS d}+|)j1        2                                2 3 d{V },|,3                    d1d23          }-|+|-z  }+d4|+v r|+4                    d4d5          \  }.}+|.                                }.|.s4|.5                    d6          r|.d7d         }/|/                                d8k    rn	 tm          j7        |/          }0|0	                    d9g           }1|1rP|1d         	                    d:i           }2|2	                    dd          }|r|%|z  }%|r|8                    |           n# tl          j9        $ r Y nw xY wd4|+v (6 	 ddd          d{V  n# 1 d{V swxY w Y   ddd          d{V  n# 1 d{V swxY w Y   n# tF          j/        $ r  t@          $ r}3tB          :                    d;|
|3           |%szd<|3 g dg dcY d}3~3|r|,                                 |$rS	 tG          j-        |$d0'           d{V  S # tF          j.        tF          j/        f$ r |$0                                 Y S w xY wS Y d}3~3nd}3~3ww xY w|r|,                                 |$rS	 tG          j-        |$d0'           d{V  n# tF          j.        tF          j/        f$ r |$0                                 Y nuw xY wnp# |r|,                                 |$rS	 tG          j-        |$d0'           d{V  w # tF          j.        tF          j/        f$ r |$0                                 Y w w xY ww xY wtO          j'                    |&z
  }4tB          ;                    d=|
|pddd>         |4ty          |%                     |%pd?d|d	d@|%d	gd5g ty          |          ||duot)          |%          dAS )BaT  Forward the message to a remote Hermes API server instead of
        running a local AIAgent.

        When ``GATEWAY_PROXY_URL`` (or ``gateway.proxy_url`` in config.yaml)
        is set, the gateway becomes a thin relay: it handles platform I/O
        (encryption, threading, media) and delegates all agent work to the
        remote server via ``POST /v1/chat/completions`` with SSE streaming.

        This lets a Docker container handle Matrix E2EE while the actual
        agent runs on the host with full access to local files, memory,
        skills, and a unified session store.
        r   )ClientSessionClientTimeoutuE   ⚠️ Proxy mode requires aiohttp. Install with: pip install aiohttpr6  r8  r9  rJ  uH   ⚠️ Proxy URL not configured (GATEWAY_PROXY_URL or gateway.proxy_url)GATEWAY_PROXY_KEYrj   rN  r  r  r  r  r  zContent-Typezapplication/jsonzBearer AuthorizationzX-Hermes-Session-Idzhermes-agentT)r\   r8  streamNr  	streamingStreamingConfigrC  r  r<  GatewayStreamConsumerStreamConsumerConfigr  SUPPORTS_MESSAGE_EDITINGFedit_intervalbuffer_thresholdcursorbuffer_onlyr   r9  r  r  z+Proxy: could not set up stream consumer: %sr  r4  )total	sock_readr`  z/v1/chat/completions)r   headersr  zProxy error (%d) from %s: %sr  u   ⚠️ Proxy error (z): r  r  r'   r   )errorsr   r#   zdata: rX  z[DONE]choicesdeltaz Proxy connection error to %s: %su   ⚠️ Proxy connection error: z>proxy response: url=%s session=%s time=%.1fs response=%d charsr  z(No response from remote agent)r  )r6  r8  r9  rJ  rM  rC  response_previewed)=aiohttpr  r  r   r  r   r   r   r   r   r   r  r  r  r  r  rh  rD  re  	transportr}  r<  gateway.stream_consumerr  r  r   rs  r  r  r  r  r9  r   r  r  r  r  rp  send_typingr@  postr9  rT  r  finishr  r  CancelledErrorr  r  iter_anyr  r   r   r   r   on_deltar  r9  r  r   )5r  rF  r3  r  r  rC  r   r4  _AioClientSessionr  r  	proxy_keyapi_messagesr  r  r  r  body_stream_consumer_scfgr  rC  r  rD  _plat_streaming_streaming_enabledrQ  r  r  r   r  _adapter_supports_edit_effective_cursor_buffer_only_consumer_cfg_sc_errstream_taskfull_response_start_timeoutr   resp
error_textrV  rU  rT  liner  objr  r  r  _elapseds5                                                        r   _run_agent_via_proxyz"GatewayRunner._run_agent_via_proxy  s     ,	QQQQQQQQQ 	 	 	"i	    	 ''))	 	"l	   I1266<<>>	 .0 	On M MNNN 	H 	HC776??Dggi((G,,,,##Tg$F$FGGGV@@AAA $23E"F 	='<'<'<GO$ 	8-7G)* $$
 
  h55{DII=666666#O%%E+FO<<*,,BBBBBB11{
 

 & M6eo6o&& 	  	$:EvGW9X# 	UU________333333=,,V_== -4X?Y[_-`-`*8N(VTV%#(L(/99,.)'+$8$8&+&9).)?0$0	% % %M (='< ( &,!1	( ( ($  U U UJGTTTTTTTTU  	F!-.>.B.B.D.DEEK =$$V_55 	**6>DT*UUUUUUUUUU    F	)$}1===H((::: .) .) .) .) .) .) .)g"<< 666# (   -) -) -) -) -) -) -) -) {c))+/99;;%6%6%6%6%6%6
: KJtt4D  
 /hT[.g.gU_`dad`dUe.g.g(*)*%'	   -) -) -) -) -) -) -) -) -) -) -) -) -).) .) .) .) .) .) .) .) .) .) .) .) .)|   * ''))) ))!*;DDDDDDDDDDD,g.DE ) ) )&&((((())Y  F'+|'<'<'>'> ) ) ) ) ) ) )e$||GI|FF$ #fnn+1<<a+@+@LD&#'::<<D#' ) (#x88 )'+ABBx#'::<<8#;#;$)!)*.*T*:*:C.1ggi.D.DG'. %S07
w0K0K27))Ir2J2J+2 )S,9W,DM/? -S0@0I0I'0R0R0R'+'; !) !) !)$(D!)' #fnn (?'>)-) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -) -).) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .) .)` % 	 	 	 	 	 	LL;YJJJ  &K&K&K "!"	         * ''))) ))!*;DDDDDDDDDDD,g.DE ) ) )&&((((())    	   * ''))) ))!*;DDDDDDDDDDD,g.DE ) ) )&&((((())   * ''))) ))!*;DDDDDDDDDDD,g.DE ) ) )&&((((()) 9;;'L
(b#2#.#m:L:L	
 	
 	
 ,P/PG44$?? !'ll$"2$">"V4CVCV
 
 	
sZ   !!&BH5 5
I$?II$3"K 
K#"K#<W "V1>A)V'V19W $P/P32P37VU:B	V"A<UVU1	.V0U1	1
V<V1
V	V1V	V1W 1
V;;W >V;?W [- Y>'Y9Y>[- !X>>/Y0/Y04[- 9Y>>[- Z7 7/[)([)-]\$#]$/]]]]r   _interrupt_depthrA  c
                 -   	WXYZ[\]^_`abcdefghijklmnopqrstK                                     r"                     |           d{V S ddlmW ddlmt                      tt          j                  }
ddlm	} t           |t|
                    ft                    di           }t          |t                    si }ddlmo 	 ddlm}  ot|
d	d          } ||rt%          |          nd           n# t&          $ r Y nw xY w ot|
d
          }|pt)          j        d          pdkddlmX kdk    oj        Xj        k    rj        Xj        k    o#t3          |                    d          d          grrm                                ndldgidghdgndvdt6          dt6          dt6          dt          fhiklnfdjj        Xj        k    r
j        p|_nj        __rd_ind^^lm fd}dgedgpdgsdgqt=          j                    \ j         Zdt$          dtB          ddfZ\fdd j"                            j                  `j#        b_rd_indcdt6          dt6          ddf\`bcfdaWXZ\_`abcde	fgjop qrstfd}d}rrt=          j$         |                      }d}qfd }t=          j$         |                      }e fd!}t=          j$         |                      }t=          j%                    [[e fd"}t=          j$         |                      }tM          t)          j        d#d$                    }|dk    r|ndYtO          j'                    ]Y]ce fd%}t=          j$         |                      }	 tM          t)          j        d&d'                    }|dk    r|nd}tM          t)          j        d(d)                    }|dk    r|nd}d*} t=          j(         )                    |                    }!d*}"d+}#|,d}$	 t=          j*        |!h|#,           d{V \  }%}&|%r|!+                                }$n[,                                sډr؉ j"                            j                  }'ed         }(|'r|(rt[          |'d-          r|'.                              r|'j/                                      })|)r|)j0        nd}*tb          2                    d.dd/         |3                                rd0nd1           |(4                    |*           [5                                 'nBd}$	 t=          j*        |!h|#,           d{V \  }%}&|%r|!+                                }$ned         }+d2},|+rLt[          |+d3          r<	 |+6                                }-|-                    d4d2          },n# t&          $ r Y nw xY w| s||,|k    rd}  j"                            j                  }.|.rt%          |d5z            pd6}/t%          ||z
  d5z            pd6}0	 |.7                    j#        d7|/ d8|0 d9c:           d{V  n2# t&          $ r%}1tb          8                    d;|1           Y d}1~1nd}1~1ww xY w|,|k    rd}"n[,                                sډr؉ j"                            j                  }'ed         }(|'r|(rt[          |'d-          r|'.                              r|'j/                                      })|)r|)j0        nd}*tb          2                    d.dd/         |3                                rd0nd1           |(4                    |*           [5                                 ?|"red         }2i }3|2r6t[          |2d3          r&	 |26                                }3n# t&          $ r Y nw xY w|3                    d<d=          }4|3                    d4d          }5|3                    d>          }6|3                    d?d          }7|3                    d@d          }8tb          9                    dA|5||4|7|8|6pdB           |2r%t[          |2dC          r|24                    dD           t%          |d5z            pd6}9dE|9 dFg}:|6r$|::                    dG|6 dH|5dIdJ|7 dK|8 dL	           n#|::                    dM|4 dN|5dIdO|7 dK|8 dP	           |::                    dQ           dR;                    |:          pd         rpd                             dSg           ng |7sd         pg dddT}$ed         };pd         }<|<r|<                    dU          nd*}=|;[t[          |;dV          rK|=sIty                      }>|;j=        |>k    r0 >                    |;j=                  s ?                               pd         }? j"                            j                  }@d}Ad}B|?r|@rrt          |@          }A|?                    dW          r-|As+|?                    dX          r|?                    dX          }Bn;|Ar9|Aj0        pt          |A          }Btb          8                    dY|BddZ                    |Br|BB                                C                    dK          r|BB                                D                    dd6          }C|Cr"|Cd         d6d         E                                nd[}D|DrB	 dd\lFmG}E  |E|D          rtb          2                    d]|D           d}Ad}Bn# t&          $ r Y nw xY w jH        rB|As|Br>tb          2                    d^r
dd/         nd_ I                                           d}Ad}B|As|Brtb          8                    d`|BddZ                    |@r:t[          |@da          r*r(|@jJ        v r|@jJ                 K                                 | jL        k    rtb          M                    db|            j"                            j                  }@|@r|Art          |@j/        |A           n(|@r&t[          |@dc          r|@O                    |B           pd         p|$dd	 |r|P                                 |P                                 |P                                 |rr	 t=          jQ        |d+,           d{V  nT# t<          jR        t<          jS        f$ r6 |P                                 	 | d{V  n# t<          jS        $ r Y nw xY wY nw xY w|P                                 r jT        v r jT        = r jU        V                    d            jH        r W                    de           ||||fD ]#}F|Fr	 |F d{V  # t<          jS        $ r Y w xY w$S |?                    dW          }G|Gsqd         }H|Hr|r	 t=          jQ        |d+,           d{V  n# t<          jR        t<          jS        f$ r6 |P                                 	 | d{V  n# t<          jS        $ r Y nw xY wY n1t&          $ r%}Itb          8                    df|I           Y d}I~Ind}I~Iww xY wt          |?                    dg                    }Jt          |Hrt          |Hdhd*          p|J          }K|?                    did[          }L|Lr|Ks~	 tb          2                    djr
dd/         nd_           |@7                    j#        |Lc:           d{V  n[# t&          $ r%}Itb          M                    dk|I           Y d}I~In1d}I~Iww xY w|Lr'tb          2                    dlr
dd/         nd_           |@rVt[          |@dm          rF|@jZ        V                    d          }Mt          |M          r	  |M             n# t&          $ r Y nw xY w|?                    dS          }N}O|B}Pd}Qd}R|At          |Adnd          p}O \                    |A|O|No           d{V }P|P>|?|r|P                                 |P                                 |P                                 |rr	 t=          jQ        |d+,           d{V  nT# t<          jR        t<          jS        f$ r6 |P                                 	 | d{V  n# t<          jS        $ r Y nw xY wY nw xY w|P                                 r jT        v r jT        = r jU        V                    d            jH        r W                    de           ||||fD ]#}F|Fr	 |F d{V  # t<          jS        $ r Y w xY w$S t          |Adpd          }Qt          |Adqd          }R j"                            j                  }S|Sr4	 |S]                    j#        c:           d{V  n# t&          $ r Y nw xY w ^                    |P|N|O|d6z   |Q|Rr	  	         d{V 	 |r|P                                 |P                                 |P                                 |rr	 t=          jQ        |d+,           d{V  nT# t<          jR        t<          jS        f$ r6 |P                                 	 | d{V  n# t<          jS        $ r Y nw xY wY nw xY w|P                                 r jT        v r jT        = r jU        V                    d            jH        r W                    de           ||||fD ]#}F|Fr	 |F d{V  # t<          jS        $ r Y w xY w$S 	 |r|P                                 |P                                 |P                                 |rr	 t=          jQ        |d+,           d{V  nT# t<          jR        t<          jS        f$ r6 |P                                 	 | d{V  n# t<          jS        $ r Y nw xY wY nw xY w|P                                 r jT        v r jT        = r jU        V                    d            jH        r W                    de           ||||fD ]#}F|Fr	 |F d{V  # t<          jS        $ r Y w xY w$nA# |r|P                                 |P                                 |P                                 |rr	 t=          jQ        |d+,           d{V  nT# t<          jR        t<          jS        f$ r6 |P                                 	 | d{V  n# t<          jS        $ r Y nw xY wY nw xY w|P                                 r jT        v r jT        = r jU        V                    d            jH        r W                    de           ||||fD ]#}F|Fr	 |F d{V  # t<          jS        $ r Y w xY w$w xY wqd         }Ht          |$t                    r|$                    dU          s|$                    di          pd[}T|T p|Tdsk    }Ut          |Hot          |Hdhd*                    }Vt          |$                    dg                    }J|Us2|Vs|Jr.tb          2                    dtr
dd/         nd_|V|J           d|$du<   |$S )wa  
        Run the agent with the given message and context.
        
        Returns the full result dict from run_conversation, including:
          - "final_response": str (the text to send back)
          - "messages": list (full conversation including tool calls)
          - "api_calls": int
          - "completed": bool
        
        This is run in a thread pool to not block the event loop.
        Supports interruption via new messages.
        )rF  r3  r  r  rC  r   r4  Nr   r  r0  rv   rC  )set_tool_preview_max_lentool_preview_lengthr  HERMES_TOOL_PROGRESS_MODEr  r  r  interim_assistant_messagesTr  
event_typer  r  r   c                 H   sdS | dvrdS dk    r|d         k    rdS |d<   ddl m}  ||d          }dk    r|rdd	l m}  |            }ddl}	|	                    |d
t
                    }
|dk    r#t          |
          |k    r|
d|dz
           dz   }
| d| dt          |                                           d|
 }n|r| d| d| d}n| d| d}	                    |           dS |rIdd	l m}  |            }|dk    r|nd}t          |          |k    r|d|dz
           dz   }| d| d| d}n| d| d}|d         k    r0dxx         dz  cc<   	                    d|d         f           dS |d<   dd<   	                    |           dS )z3Callback invoked by agent on tool lifecycle events.N)ztool.startedr>  r   )get_tool_emojiu   ⚙️r  rJ  )get_tool_preview_max_lenF)ensure_asciir  r6  r  r  (z)
z: "r  r  r#   	__dedup__)
agent.displayr  r  r   r  r   r   r   r  put)r  r  r  r   kwargsr  emojir  _plre  args_strr  _caplast_progress_msg	last_toolprogress_modeprogress_queuerepeat_counts                r   progress_callbackz3GatewayRunner._run_agent.<locals>.progress_callback   s   !  !222 %%)y|*C*C$IaL 544444"N9h???E 	)) 4FFFFFF2244C((((${{4eS{QQH Qww3x==3#6#6#+HS1WH#5#="QQYQQdiikk1B1BQQxQQCC 4"??Y??G???CC"33Y333C""3'''
  0BBBBBB..00!Aggss2w<<$&&%itaxi058G;;;;;;;/////
 '***Q1$ ""Kl1o#FGGG#&a LOs#####r   r<  c                    K   sd S j                             j                  } | sd S ddlm} t          |           j        |j        u rP                                s:	                                  n# t          $ r Y nw xY w                                :d S g }d }d}d}d}	 	                                 }t          |t                    rBt          |          dk    r/|d         dk    r#|\  }}	}
|r|	 d|
d	z    d
|d<   |r|d         n|	}n|}|                    |           t          j                    }|||z
  z
  }|dk    rt!          j        |           d {V  |r|d                    |          }|                     j        ||           d {V }|j        srt+          |dd          pd                                }d|v sd|v r t.                              d| j                   d}|                     j        |           d {V  ns|r9d                    |          }|                     j        |           d {V }n#|                     j        |           d {V }|j        r|j        r|j        }t          j                    }t!          j        d           d {V  |                     j                   d {V  n# j        $ r t!          j        d           d {V  Y n[t           j        $ r                                 s	                                 }t          |t                    r6t          |          dk    r#|d         dk    r|\  }}	}
|r|	 d|
d	z    d
|d<   n|                    |           n# t          $ r Y nw xY w                                |rN|rL|rJd                    |          }	 |                     j        ||           d {V  n# t          $ r Y nw xY wY d S t          $ r?}t.                              d|           t!          j        d	           d {V  Y d }~nd }~ww xY w)Nr   )r   Tr  g      ?r6  r  u    (×r#   r  r  r   )r9  r  r  r9  rj   floodzretry afterz1[%s] Progress edits disabled due to flood controlFrH  g333333?r  zProgress message error: %s) rs  r   r  r  r   rA  edit_messagerk  rl  r   r   r  r   r   r@  rA  r  r  r   r9  r  r   r   r  r  r   r  r  r  Emptyr  r9  )r   _BaseAdapterprogress_linesprogress_msg_idcan_edit_last_edit_ts_PROGRESS_EDIT_INTERVALrz  r   base_msgr  r  _now
_remaining	full_textr=  _errr  _progress_metadatar	  r   r  r  s                     r   send_progress_messagesz8GatewayRunner._run_agent.<locals>.send_progress_messages[   s     ! m''88G 
 SRRRRRG}})\-FFF(..00 &113333$    )..00 
 N"OHM&)#]+\+(3355C "#u-- 3#c((a--CFkDYDY-0*8U) O4<1N1N%!)1N1N1NN2.4BPnR00!&--c222  >++D!8D=<P!QJ!A~~ &mJ777777777  @O$?$(IIn$=$=	'.';';$*N'6$- (< ( ( " " " " " "
  &~ q$+FGR$@$@$FB#M#M#O#OD&$-42G2G !'$W$+L!" !" !" (-H"),,v~s]o,"p"pppppppp# z(,		.(A(AI+2<<Xal~<++%%%%%%FF ,3<<X[fx<+y+y%y%y%y%y%y%yF!> @f.? @.4.?O$(N$4$4M "-,,,,,,,,,!--fnGY-ZZZZZZZZZZ{ - - -!-,,,,,,,,,,,-   ,2244 
"	""0";";"="=C)#u55 ;#c((a--CPQFVaLaLa58 28U#1 !W<D9V9V%RS)9V9V9VN2$6 . 5 5c : : :( " " "!E" -2244 
"   	!N 	! 	!$(IIn$=$=	!")"6"6(.+:(1 #7 # #        
  ) ! ! ! D!FF  + + +LL!=qAAA!-**************+w]+s   !A6 6
BB(B=K  &E8K   $Q#Q+A4N Q 
N-*Q,N--2Q #PQ
PQPQ	Q 5QQr  
prev_toolsr   c                    	 g }|pg D ]d}t          |t                    r+|                    |                    d          pd           B|                    t	          |                     et          j                            dj        rj        j	        ndj
        | ||d                     d S # t          $ r&}t                              d|           Y d }~d S d }~ww xY w)Nr   rj   z
agent:step)r  r  rC  r  
tool_namesrJ  zagent:step hook error: %s)r   r!  r   r   r   r  run_coroutine_threadsafero  r  r   r  r   r  r  )	r  r	  _names_tr  
_hooks_ref_loop_for_steprC  r  s	        r   _step_callback_syncz5GatewayRunner._run_agent.<locals>._step_callback_sync   s#   > %'%+ / /B!"d++ /bffVnn&:;;;;c"gg....0OOL=C_$TFO$9$9RT#)>&0%.&,!+3 3   #
 
 
 
 
  > > >8"=========>s   B3B8 8
C(C##C(rF  c                     sd S 	 t          j                            |                     d S # t          $ r'}t                              d| |           Y d }~d S d }~ww xY w)Nr  zstatus_callback error (%s): %sr  r	  r  r   r  r  )r  rF  r  r!	  _status_adapter_status_chat_id_status_thread_metadatas      r   _status_callback_syncz7GatewayRunner._run_agent.<locals>._status_callback_sync   s    " 
O0#(('!8 )  
 #      O O O=z2NNNNNNNNNOs   +4 
A%A  A%c                    PQRSTU lpdt           j        d<   t          t          j        dd                    } mj        Wj        k    rdnmj        j        }bpd}apd                                }|r|dz   |z                                   }jj        r|dz   jj        z                                   }	 t          t          dd	           n2# t          $ r t          t          dd
	           Y nt          $ r Y nw xY w	 j                    mlq          \  }}t                              d||                    d          lpdd d                    n!# t          $ r}d| g dg dcY d }~S d }~ww xY wjj        }j                                }|j_        j                                j_        d Ud }	t-          t-          jdd           dd           }
|
ddlm}  |            }
 hq|d          }||
j        o
|
j        dk    nt7          |          }|}e}|}|s|r	 ddlm}m} jj                            mj                  }|rt-          |dd          }|stA          d          |
j!        }d}mj        Wj"        k    rd}d} ||
j#        |
j$        ||          } ||mj%        |ZrdZind           U|rUj&        }	Und<   n2# t          $ r%}t                              d|           Y d }~nd }~ww xY wdddtN          d t6          d!d fY[]^Ufd"}j(                    f||          }j)                    |d#         |d$         c|          }d }t-          jd%d           }t-          jd&d           }|r||5  |                    l          }|rU|d'         |k    rI|d         }tU          j*                    |_+        d(|_,        d|_-        t                              d)l           d d d            n# 1 swxY w Y   |; Vdzd#|d#         i|d$         i d*| d+dd,dd-cd.|pd d/jj.        pd d0|d1jj        d2|                    d2          d3|                    d4          d5|                    d6          d7|                    d8          d9|                    d:          d;|                    d<d          d=|                    d>          d?kd@|dAmj/        dBldCjj0        dDjj1        }|r#|!|5  ||f|l<   d d d            n# 1 swxY w Y   t                              dEl|           orgnd |_2        Xj3        r_nd |_4        |	|_5        |r|nd |_6        \|_7        ||_8        jj        |_9        |                    d2          |_:        tw          j<                    Sg Qtw          j=                    RdFtN          d!d fY[]^fdGTd{QRSTfdH} dFtN          d!d fQRST[fdI}!|!|_>        [rlrt-          [dJd           }"|"| |"l<   |`d<   t          |dK          r|j@        nd pd<   g }#dD ]}$|$                    dL          }%|%s|%dMv r|%dNk    r&dO|$v }&dP|$v }'|%dQk    }(|&s|'s|(r4dR |$A                                D             })|#B                    |)           n|$                    dS          }*|*rt|$                    dT          r|$                    dUdV          }+dW|+ dX|* }*|%|*dY},|%dZk    r!d[D ]}-|$                    |-          }.|.r|.|,|-<   |#B                    |,           t                      }/|#D ]}0|0                    dL          d\v r|0                    dSd          }1d]|1v rit          jE        d^|1          D ]S}2|2F                    d'                                          G                    d_          }3|3r|/H                    |3           Tdd`lImJ}4mK}5mL}6mM}7 dat          d!d fPY[]^fdb}8t-          jdci           }9lr|9O                    ld           nd }:|:r|:dz   fz   f|#r$|#dd                             dL          dQk    rdefz   flpdP |6P          }; |4P|8           	 |P                    f|#kf          }< |7P            |5|;           n#  |7P            |5|;           w xY w|<id<   UUQ                                 |<                    dg          }=d}>d}?d}@`d         }A|ArHt          |Adh          r8t-          |AjR        did          }>t-          |Adjd          }?t-          |Adkd          }@|Art-          |Ad#d           nd }B|=s|<                    dl          rdm|<dl          nd}C|C|<                    dng           |<                    dod          |<                    dpd          |<                    dqd          pd         pg t          |#          |>|?|@|BdrS d]|=vr<g }Dd}E|<                    dng           D ]}$|$                    dL          d\v r|$                    dSd          }*d]|*v rvt          jE        d^|*          D ]Z}F|FF                    d'                                          G                    d_          }G|Gr|G|/vr|DB                    d]|G            [ds|*v rd}E|Drvt                      }Hg }I|DD ]0}J|J|Hvr*|HH                    |J           |IB                    |J           1|Er|IT                    dds           |=dtz   dtU                    |I          z   }=`d         }d}K|rlrt          |d?          rt|jV        kk    rid}Kt          W                    duk|jV                   jjX        jY                            l          },|,r%|jV        |,_V        jjX        Z                                 |rt-          |d?k          nk}L|Krdnt          |#          }M|=rYjj0        rR	 ddvl[m\}N id         rid                             dng           ng }O |Njj0        |Lf|=|O           n# t          $ r Y nw xY w|=|<                    dw          id         rid                             dng           ng id         rid                             dod          ndpd         pg |M|>|?|@|B|L|<                    dxd          dyS )|Nrj   HERMES_SESSION_KEYrm   r2  r  r  Tr'   )r!  r)   zlatin-1r  z3run_agent resolved: model=%s provider=%s session=%sr[   r  u'   ⚠️ Provider authentication failed: r   r  r  r  r  r  r  r  z(skip streaming for non-editable platformFr  r<  r  z$Could not set up stream consumer: %s)already_streamedrT  r+	  r   c                x   .|r                                  n                    |            d S |s%r#t          | pd                                          sd S 	 t	          j                            |                      d S # t          $ r&}t          	                    d|           Y d }~d S d }~ww xY w)Nrj   r  z$interim_assistant_callback error: %s)
on_segment_breakon_commentaryr   r   r  r	  r  r   r  r  )rT  r+	  r  r!	  r%	  r&	  r'	  r  s      r   _interim_assistant_cbzIGatewayRunner._run_agent.<locals>.run_sync.<locals>._interim_assistant_cb!  s   #/' =(99;;;;(66t<<<F# ? #djb//BWBWBYBY F
M4',,+ %< -  
 '     ! M M MLL!GLLLLLLLLLMs   +B	 	
B9B44B9r\   r   r  r  r#   zstarting new turn (cached)z#Reusing cached agent for session %sr  r  r4  r  ephemeral_system_promptprefill_messagesr5  r+  r'  r6  r7  r8  r9  r:  r;  r<  r=  r>  r?  r@  rA  rC  r  r  gateway_session_keyrB  r  z)Created new agent for session %s (sig=%s)rF  c                     sd S 	 t          j                            |                      d S # t          $ r&}t                              d|           Y d }~d S d }~ww xY w)Nr  z$background_review_callback error: %sr$	  )rF  r  r!	  r%	  r&	  r'	  s     r   _deliver_bg_review_messagezNGatewayRunner._run_agent.<locals>.run_sync.<locals>._deliver_bg_review_message!  s    & F
M4',,+#%< -  
 '     ! M M MLL!GLLLLLLLLLMs   +4 
A$AA$c                                                        5  t                    }                                  d d d            n# 1 swxY w Y   | D ]} |           d S rh  )r   r   r  )r=  queued_bg_review_pending_bg_review_pending_lock_bg_review_releaser4	  s     r   _release_bg_review_messageszOGatewayRunner._run_agent.<locals>.run_sync.<locals>._release_bg_review_messages!  s    "&&(((, / /"#566G&,,.../ / / / / / / / / / / / / / / & 7 7F..v66667 7s   $AAAc                     sd S                                  sR5                                   s#                    |            	 d d d            d S 	 d d d            n# 1 swxY w Y    |            d S rh  )is_setr   )rF  r7	  r8	  r9	  r4	  r%	  s    r   _bg_review_sendzCGatewayRunner._run_agent.<locals>.run_sync.<locals>._bg_review_send!  s    & F)0022 #0 # #188:: #.55g>>>"# # # # # # # ### # # # # # # # # # # # # # # +*733333s   +A!!A%(A%_post_delivery_callbacksrJ  r  )rK  rN  r  r  r  c                 &    i | ]\  }}|d k    ||S )rL  r   )r   r  r  s      r   r  z>GatewayRunner._run_agent.<locals>.run_sync.<locals>.<dictcomp>1"  s(     R R R$!QkAQAQAAQAQAQr   r  mirrormirror_sourcezanother sessionz[Delivered from r  r  r  )rI  reasoning_detailscodex_reasoning_items)r  r  zMEDIA:zMEDIA:(\S+)z",})register_gateway_notifyreset_current_session_keyset_current_session_keyunregister_gateway_notifyapproval_datac           	      >   	                     
           |                     dd          }|                     dd          }t          t          	          dd          	 t	          j        	                    
||                                        d	          }|j        rdS t          
                    d
|j                   n2# t          $ r%}t          
                    d|           Y d}~nd}~ww xY wt          |          dk    r|dd         dz   n|}d| d| d}	 t	          j        	                    
|                                        d	           dS # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)aY  Send the approval request to the user from the agent thread.

                If the adapter supports interactive button-based approvals
                (e.g. Discord's ``send_exec_approval``), use that for a richer
                UX.  Otherwise fall back to a plain text message with
                ``/approve`` instructions.
                r   rj   r  zdangerous commandsend_exec_approvalN)r9  r   r   r  r  rF  r`  zLButton-based approval failed (send returned error), falling back to text: %sz6Button-based approval failed, falling back to text: %sr  r  u4   ⚠️ **Dangerous command requires approval:**
```
z
```
Reason: z

Reply `/approve` to execute, `/approve session` to approve this pattern for the session, `/approve always` to approve permanently, or `/deny` to cancel.r  z#Failed to send approval request: %s)pause_typing_for_chatr   r   rA  r  r	  rJ	  r=  r  r  r  r9  r   r   r  )rH	  r  r  _approval_resultr  cmd_previewr  _approval_session_keyr!	  r%	  r&	  r'	  s          r   _approval_notify_synczIGatewayRunner._run_agent.<locals>.run_sync.<locals>._approval_notify_sync`"  s:     55oFFF#''	266$((8KLL
 4002FMMY+2+K+>>(7(+,A,0)@ ?   +	, 	, !&&,, ) ,3 #"Fj,2    %   TVX        47s88c>>c$3$i%//sh'h h#h h h 
L4',,+%< -  
 '  fRf(((((  L L LLL!FKKKKKKKKKLs7   "AC , C 
C<C77C<+?E, ,
F6FFr=  r  a)  [System note: Your previous turn was interrupted before you could process the last tool result(s). The conversation history contains tool outputs you haven't responded to yet. Please finish processing those results and summarize what was accomplished, then address the user's new message below.]

)r  rP  r6  r  rP  session_prompt_tokenssession_completion_tokensr9  r  r8  r9  r:  rI  )r6  r8  r9  r:  rI  rJ  rM  rP  r  r  r\   z[[audio_as_voice]]r   u/   Session split detected: %s → %s (compression))maybe_auto_titlerE  r  )r6  rE  r8  r9  rJ  rM  rP  r  r  r\   rC  r  r   r  )]r   r   r  r   r  r  r   r   rw  r!   	_env_pathUnicodeDecodeErrorr   r  r  r  r   r  rx  ry  rz  r{  r   r  r  re  r  r}  r  r  r  rs  r   r  r  r  r  r9  r  r   r-  r  r@  _last_activity_ts_last_activity_desc_api_call_countru  r  r  r  tool_progress_callbackrn  step_callbackstream_delta_callbackinterim_assistant_callbackstatus_callbackr5  r+  r'  r  r  r  background_review_callbackr  rJ  r  r   r   r  finditergrouprb  r   r  rD	  rE	  rF	  rG	  r!  r   r  r  r  r   insertr   rC  r  r  r  r  agent.title_generatorrR	  )rr  rC  combined_ephemeralevent_channel_promptr\   r  r   rD  r5  _stream_delta_cbr  r  r  r  _want_stream_deltas_want_interim_messages_want_interim_consumerr  r  r  r  r  r  r  r  r/	  rE  _sigrk   r  rS  r  r:	  r=	  _pdcagent_historyr  r  has_tool_callshas_tool_call_idis_tool_message	clean_msgr  
mirror_srcr  _rkey_rval_history_media_paths_hm_hc_match_prD	  rE	  rF	  rG	  rO	  _pending_notes_msn_approval_session_tokenr=  r6  _last_prompt_toks_input_toks_output_toks_agent_resolved_model	error_msg
media_tagshas_voice_directivematchr   seenunique_tagsrq  _session_was_spliteffective_session_id_effective_history_offsetrR	  all_msgsrN	  r7	  r8	  r9	  r4	  r  r  r   r 	  r!	  _progress_thread_idr%	  r(	  r&	  r'	  r"	  agent_holderrA  r3  r  r  "interim_assistant_messages_enabledrF  r	  rD  result_holderr  rC  r   r  stream_consumer_holdertool_progress_enabledtools_holderr  sr                                                                                   @@@@@@r   rF  z*GatewayRunner._run_agent.<locals>.run_sync!  s    0;/@bBJ+, !+BD!I!IJJN %+Ox~$E$E556?K`L "0!52$2$8b#?#?#A#A # b&86&ADX&X%_%_%a%a", k&86&ADDa&a%h%h%j%j"IwGGGGG% J J JIyIIIIII   (,(K(K! + + )L ) )%~
 I>--j99K<M2sPRs;S       &UPS&U&U "!"	        'B#::<<%5D"!%!8!8!:!:D##GD(D99;MME}::::::'))
 65\; O #* :%/U":/** 
 #5%G"%;"" %R&< %R$Rcccccccc#}00AAH E 29C]_c1d1d.5 ["./Y"Z"ZZ,1L) (-!?ho==02-+/L(<(<*/*=-2-C#4(4	) ) ) ,A+@$,$*N#0K^%hk3F%G%Gdh	, , ,( / I/?/H,4D.q1  R R RLL!GQQQQQQQQR NS M M MC Md MW[ M M M M M M M M M M* 88%XXJ
 //7#9% "	 D E!$(;TBBKT>488F Yv1  
Y 
Y#ZZ44F Y&)t"3"3 &q	 37)++/4P101-%JKXXX
Y 
Y 
Y 
Y 
Y 
Y 
Y 
Y 
Y 
Y 
Y 
Y 
Y 
Y 
Y }  $W- +   $2>  $t	
 %*E &6%5 -?,F$ &*%;%Ct &6%5 "&!3!3 '1nn5H&I&I&I ')ffVnnn ')ffX&6&6&6 %'FF7OOO #%&&...  137KU0S0S0S!" .0VV4E-F-F-F#$  *z%& *\'( #NN)* )4+,  $//-. $(#7#7/ 2  <6#5$ < </4dm{+< < < < < < < < < < < < < < <H+W[\\\ AV+_+<+<[_E(9C9P"Z"5"5VZE*:E'H^/h/D/DdhE,$9E!%5E"!%!3E&0nn5H&I&IE#!*!2!2,.&/n&6&6#MC MD M M M M M M M M M7 7 7 7 7 7 7 7 74 4 4 4 4 4 4 4 4 4 4 4 0?E,  D; D0JDQQ#(CD% $LO-4UG-D-DNekk$LO M *4 *4wwv  ,,, 8## ".!4#1S#8 "&&.! 4%5 4 4 R R#))++ R R RI!((3333 "ggi00G 4778,, Q),BS)T)TJ&P&P&Pw&P&PG)-' B B
  ;..*C 9 9(+#( !938E%L%,,U333
 ), $ = =776??&:::'')R00C3&(k.#&F&F = =F!'a!6!6!8!8!?!?!F!FB! = 4 8 8 < < <           ALT ALd AL AL AL AL AL AL AL AL AL ALH %T+A2FFN<GQ>%%k4888TD 2-'1  r!2!6!6v!>!>&!H!H5
   %0$52!&=&=>S&T&T###$9;PQQQC//meo/pp))*?@@@))*ABBBB *)*?@@@))*ABBBB%M!  + ''))) $ZZ(899N !"KL!!_F O'&*>?? O$+F,EG[]^$_$_!%f.EqII&v/JANN@FPgfgt<<<DO! ;A::g;N;NV7fWo777TV	&/ &

:r : :!'K!;!;$jj599-3ZZ8OQV-W-W)!_2&)-&8&8*;$/%1,  0 ~--
&+#!::j"55 	; 	;Cwwv*>>>"%'')R"8"8#w..)+^W)M)M G G',{{1~~';';'='='D'DU'K'K#' !GD8L,L,L$.$5$5otoo$F$F$F3w>>6: 3 	T55D"$K) 4 4d?? HHSMMM'..s333* D#**1.BCCC%3d%:TYY{=S=S%SN !OE!& 	/ 	/)E)E 	/%JZ^hJhJh%)"E 0   *377DD /','7E$&,,...OT#d75,
#K#K#KZd  .@(WSEWEW%  $"2 FFFFFFGTUVGW_}Q/33JCCC]_H$$(,&     !   D #1"(**-=">">DQRSDT\M!,00R@@@Z\ERSTEU\]1-11+qAAA[\%a.B";&7 +!-(2&,jj1Eu&M&M  s   6C !C=1	C=<C=AE 
E5!	E0*E50E5$B)K 
K=K88K=A-O;;O?O?	TT!$T! b/ /cA q 
qqc                     K   t          d          D ]G} d         #d                                          d{V   dS t          j        d           d{V  HdS )z8Wait for the stream consumer to be created, then run it.r  r   Nr  )r  rp  r  r  )r   r	  s    r   _start_stream_consumerz8GatewayRunner._run_agent.<locals>._start_stream_consumerH#  s      3ZZ * *)!,80377999999999FFmD))))))))))	* *r   c                     K    d         "t          j        d           d {V   d         "r. d         j        <   j        r                    d           d S d S d S )Nr   r  r  )r  r  r  r]  r]  )r	  r  r   s   r   track_agentz-GatewayRunner._run_agent.<locals>.track_agentT#  s      q/)mD))))))))) q/) <4@O$[1> <//
;;;;;< << <r   c                  F  K   sd S 	 t          j        d           d {V  	 j                            	j                  } | s>t          | d          r|                               rtd         }|rj| j                                      }|r|j        nd }t          
                    d           |                    |                                            d S nA# t           j        $ r  t          $ r%}t          
                    d|           Y d }~nd }~ww xY w)NTg?has_pending_interruptr   z3Interrupt detected from adapter, signaling agent...z,monitor_for_interrupt error (will retry): %s)r  r  rs  r   r  r  r	  r  rT  r  r  rY  r   r  r   )
r  rk   _peek_eventpending_text_mon_err_interrupt_detectedr	  r  r   r  s
        r   monitor_for_interruptz7GatewayRunner._run_agent.<locals>.monitor_for_interruptg#  sp       [mC((((((((([  $}00AAH# ! 
 x)@AA "hFdFdepFqFq " ,Q  " +3*D*H*H*U*UK?J+T;+;+;PTL"LL)^___!OOL999/33555!E-     [ [ [LL!OQYZZZZZZZZ[? [s   !C  BC   D9DDrs   iX  c                  0  K   d S j                             j                  } | sd S 	 t          j                   d {V  t          t          j                    z
  dz            }
d         }d}|rt          |d          r	 |                                }d|d          d|d	          g}|                    d
          r|	                    d|d
                     n)|	                    |                    dd                     dd
                    |          z   }n# t          $ r Y nw xY w	 |                     j        d| d| d	           d {V  n2# t          $ r%}t                              d|           Y d }~nd }~ww xY wl)NTr  r   rj   r  r  r  r   r  r  r  r7  r  r  u   ⏳ Still working... (r  r  r  z#Long-running notification error: %s)rs  r   r  r  r  r  r@  r  r  r   r   r   r  r9  r  r  )_notify_adapter_elapsed_mins
_agent_ref_status_detail_ar  _ne_NOTIFY_INTERVAL_notify_startr'	  r	  r  r  s          r   _notify_long_runningz6GatewayRunner._run_agent.<locals>._notify_long_running#  s"     '"m//@@O" Mm$4555555555 #TY[[=%@R$G H H)!_
!# 
'*6L"M"M 
	'<<>>"\r2B/C"\"\bIYFZ"\"\!]66.11 L"MM*Jb6H*J*JKKKK"MM"&&1Er*J*JKKK)0499V3D3D)D$   M)..]]]N]]]!8 /          
 ! M M MLL!FLLLLLLLLM/Ms+   	BD( (
D54D59*E$ $
F.FFro   r4  rq   i  Fr  r`  r	  zABackup interrupt detected for session %s (monitor task state: %s)r  r\  rT  r  r  r6  r  r#   u   ⚠️ No activity for zB min. If the agent does not respond soon, it will be timed out in z- min. You can continue waiting or use /reset.r  z!Inactivity warning send error: %sr7  rD  r  r  r  zaAgent idle for %.0fs (timeout %.0fs) in session %s | last_activity=%s | iteration=%s/%s | tool=%srs  rY  z Execution timed out (inactivity)u   ⏱️ Agent inactive for u(    min — no tool calls or API responses.z!The agent appears stuck on tool `z` (r8  z!s since last activity, iteration r   z).zLast activity: r  zs ago, iteration z6). The agent may have been waiting on an API response.zTo increase the limit, set agent.gateway_timeout in config.yaml (value in seconds, 0 = no limit) and restart the gateway.
Try again, or use /reset to start fresh.r   r8  )r6  r8  r9  rJ  rM  r:  r:  r\   interruptedinterrupt_messagez9Processing queued message after agent completion: '%s...'r  rj   r:  uZ   Discarding command '/%s' from pending queue — commands must not be passed as agent inputz=Discarding pending follow-up for session %s during gateway %srI  z#Processing pending message: '%s...'_active_sessionsu^   Interrupt recursion depth %d reached for session %s — queueing message instead of recursing.queue_message)r6  r8  r  z5Stream consumer wait before queued message failed: %sr  final_response_sentr6  zoQueued follow-up for session %s: final stream delivery not confirmed; sending first response before continuing.z7Failed to send first response before queued message: %sz_Queued follow-up for session %s: skipping resend because final streamed delivery was confirmed.r>	  r  r2  r  rA  )	rF  r3  r  r  rC  r   r  r4  rA  r7  zjSuppressing normal final send for session %s: final delivery already confirmed (streamed=%s previewed=%s).rR  )NNN)_r  r  r  r  r   r  r  r  rN  r1  r  r   r   r!  rh  rD  r  r  r  r   r   r   r  r   r	  r    Queuer   r  r<  r  r  r  r   rs  r9  r  r  r  r@  ensure_futurerO  r  r=  r<	  r  r	  r  rT  r  r  r\  rY  r   r  r  r  r9  r   r   r$  r\   r  ro  r   r   r   r   r   r   ro  r;  r]  rO  r	  r  _MAX_INTERRUPT_DEPTHr  r   r	  r  r  r  r  r  rX  r   r]  r}  r   r>	  callabler  r  rg  )ur  rF  r3  r  r  rC  r   r  r4  rA  rC  r1  display_configr  _tpl_resolved_tpr	  rF  progress_taskr  r	  r	  tracking_taskr	  interrupt_monitor_NOTIFY_INTERVAL_RAWr	  _notify_task_agent_timeout_raw_agent_timeout_agent_warning_raw_agent_warning_warning_fired_executor_task_inactivity_timeout_POLL_INTERVALrG  r\  r   _backup_adapter_backup_agent	_bp_event_bp_textr	  
_idle_secs_act_warn_adapter_elapsed_warn_remaining_mins	_warn_err_timed_out_agent	_activity
_last_desc	_secs_ago	_cur_tool_iter_n	_iter_max_timeout_mins_diag_linesr}	  _result_for_fb_run_failed
_cfg_modelr=  r   pending_eventr=  _pending_parts_pending_cmd_word_rc_pendingr   was_interrupted_scr  
_previewed_already_streamedfirst_response_bg_cbupdated_historynext_sourcenext_messagenext_message_idnext_channel_prompt_followup_adapter_final_is_empty_sentinel	_streamedr  r   r	  r 	  r	  r!	  r	  r	  r	  r%	  r(	  r&	  r'	  r"	  r	  r  r	  r	  r	  r	  r	  r	  r   r	  rD  r	  r	  r	  r	  r  su   ```````  `                                                                             @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@r   rg  zGatewayRunner._run_agent  su!     2    		22-%'!1 3          	&%%%%%*,,+FO<<??????!"5"5k<"P"PQQ$B77.$// 	 N
 	CBBBBB	>>>>>>**;F[]^__D$$$%=SYYYA>>>> 	 	 	D	 /.{L/ZZ y455 	 	,+++++ - 6 ^6?hN^;^
 Ox// ""#?@@   	+ +@ITF	!Fs?	$ ?	$# ?	$# ?	$s ?	$ae ?	$ ?	$ ?	$ ?	$ ?	$ ?	$ ?	$ ?	$ ?	$ ?	$R ?hn,,"("2"F6F"("2CV`k+>??\`w	+ w	+ w	+ w	+ w	+ w	+ w	+ w	+ w	+t vv"& !133Z
	>3 	>D 	>T 	> 	> 	> 	> 	> 	> 	> 	> 	>4 -++FO<< .H["e;0C"D"Dae	Oc 	OC 	OD 	O 	O 	O 	O 	O 	O 	O 	O 	O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	 r	 r	 r	 r	 r	j   	J#/0F0F0H0HIIM 	* 	* 	* 	* 	* )*@*@*B*BCC	< 	< 	< 	< 	< 	< 	<  +KKMM:: &moo$	[ $	[ $	[ $	[ $	[ $	[ $	[ $	[ $	[L $/0E0E0G0GHH  %RY/Ms%S%STT3G!3K3K//QU		M 	M 	M 	M 	M 	M 	M 	M 	M 	M@ *+?+?+A+ABBJ	 "'ry1G'N'N!O!O3E3I3I//tN!&ry1OQT'U'U!V!V3E3I3I//tN"N$2228<< N #( N%  6$+L'(.% % %      GD!  #1#8#8#:#: /5577 6K 6*.-*;*;FO*L*L(4Q+ 6 6$+O=T$U$U6$3$I$I+$V$V6 )8(I(M(Mk(Z(ZI9B'Ly~~H"KK!; +CRC 0*;*@*@*B*B Q		   *33H===/3355516 .  66$+L'(.% % %      GD!  #1#8#8#:#:!-aJ!$J! !gj:P&Q&Q !!#-#B#B#D#DD)-2JC)P)PJJ( ! ! ! D! + ]~/I *n < <)-(,(9(9&/(J(J( ],/"0D,E,E,JM.1>N3RWY2Y.Z.Z._^_O
]&3&8&8$*N%Om %O %O7F%O %O %O .E '9 '" '" !" !" !" !" !" !" !" !" $- ] ] ] &-PR[ \ \ \ \ \ \ \ \]!^33.2+.5577 6K 6*.-*;*;FO*L*L(4Q+ 6 6$+O=T$U$U6$3$I$I+$V$V6 )8(I(M(Mk(Z(ZI9B'Ly~~H"KK!; +CRC 0*;*@*@*B*B Q		   *33H===/33555m66p # =#/? 	# 0@BX(Y(Y $4$I$I$K$K		$    ']]+?KK
%MM*BAFF	%MM.99	#--(8!<<%MM*:A>>	E~{'   $ S0@+(N(N S$../QRRR #Nb$8 9 9 >Q) ) ) )  &&=I = =%B= =%,= =/8= = =     &&N* N N	N N N%,N N/8N N N  
 ""?   '+ii&<&<HUVWHX `a 0 4 4Z D D D^`!()!_2&'" " "!_F*1-N:HS.,,X666eK!gfg&>&>!{!355
<:--d6W6WXcekeq6r6r- ,,[999 #1%Fm''88G !MG l' lk l 6w L L::m,, l] lvzzReGfGf l$jj)<==GG" l+0[4L]4[4[GLL!\^efigifi^jkkk  7==??55c:: !(!6!6tQ!?!?ES$[N1$5abb$9$?$?$A$A$AY[!$ VVVVVV&;'899 +"KK!M 1  
 -1M&*G$    ~ = G S(3<K$$--//  
 !% x xBGCRCLQQQ
  Bww0BCC B BXcgngXX,[9??AAA $t'@@@NNA(+  
 #m//@@G D= D3G4M{\ijjjj  DWWo%F%F D--k7CCC(+`(X_/`/``J  '$$&&&$$&&&!!!  !*;DDDDDDDDDDD,g.DE   &&((()))))))))"1   	   """ 6{d.BBB(5 ?'++K>>>~ 8++J777 '(9=,W   "







"1   { #)**]";";& 2% 13C 
e{ 
e	e")"2;"L"L"LLLLLLLLL ' 4g6LM % % %'..000%&1 1 1 1 1 1 1 1 1#*#9 % % % $%( e e e"LL)`bcdddddddde!%fjj1E&F&F!G!GJ(,K.CU!K!K &%) )% &,ZZ0@"%E%EN% .? i"KK !R4? HCRC 0 0S   #*,, & .)@ #/ # #        
  ) i i i"NN+dfghhhhhhhhi' }0;DK,,    %774N#O#O %!(!A!E!EkSW!X!X#F++ %% &#, % % % $% #)**Z"A"A$&"&&*# ,")-4"H"H"RFK)-)K)K+* / *L * * $ $ $ $ $ $L
 $+%<  '$$&&&$$&&&!!!  !*;DDDDDDDDDDD,g.DE   &&((()))))))))"1   	   """ 6{d.BBB(5 ?'++K>>>~ 8++J777 '(9=,W   "







"1   o '.m\4&P&PO*1-AQSW*X*X'
 %)M$5$5fo$F$F!$ /;;"N%< <           %    "__(#1+&) +%5%9%4#6 - 
 
 
 
 
 
 
 
 
  '$$&&&$$&&&!!!  !*;DDDDDDDDDDD,g.DE   &&((()))))))))"1   	   """ 6{d.BBB(5 ?'++K>>>~ 8++J777 '(9=,W   "







"1   kxv  '$$&&&$$&&&!!!  !*;DDDDDDDDDDD,g.DE   &&((()))))))))"1   	   """ 6{d.BBB(5 ?'++K>>>~ 8++J777 '(9=,W   "







"1   5  '$$&&&$$&&&!!!  !*;DDDDDDDDDDD,g.DE   &&((()))))))))"1   	   """ 6{d.BBB(5 ?'++K>>>~ 8++J777 '(9=,W   "







"1   ( %Q'h%% 	0hll8.D.D 	0\\"2339rF%+!Bv/BB%:EBB I
 hll+?@@AAJ% 09 0
 0 A(3<K$$	   ,0(s  0D 
DD8HAR8 *W/ .AR8 /
W<9AR8 ;W<<AAR8 *Z AR8 
Z2Z-(AR8 -Z22DAR8 _# "AR8 #
_0-AR8 /_00L8AR8 )0m AR8 
m'$AR8 &m''EAR8 /t/u<uuuuuuuww&%w&+$AR8 x- ,AR8 -/z+y&%z+&y85z+7y88z+;AR8 =	z+z&!AR8 &z++A!AR8 A
} AR8 
~"~=AR8 ~A(AR8 0
; :AR8 ;
A@@AR8 @A@@AAR8 B"AB?B?/ADC/AC8C7ADC8AD
DADD	AD
D
ADDADE>AFFAFFAFFAAR8 G""AH HAR8 H
AHHAR8 HAHH)AR8 I=AJJ/AK+K
AKKAK+KAK%K"AK+K$AK%K%AK+K*AK+MAM"M"AM4M3AM4N;AO O/AP)PAPPAP)PAP#P AP)P"AP#P#AP)P(AP)RAR R AR2R1AR2R8AAW6S:ATTAW6T/AU(UAUUAU(UAU"	UAU(U!AU"	U"AU(U%AW6U'AU(U(A-AW6WAWWAW6WAW1	W.AW6W0AW1	W1AW6rh  r  )NN)r  r  )rE  rF  rG  )Nr   NN)rw  
__module____qualname____doc__rX  r   r   r  __annotations__rZ  r   r[  r\  r	   r  r]  r}  r^  r_  r`  ra  rb  r  Taskrc  r   r  r  r   r  r  r  r  r  r  r  propertyr	  r  r  r  r   r  r!  r  r  r-  r   rE  rH  rJ  rO  rS  rU  r]  r<  staticmethodr   r
   rt  rv  rx  rz  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  rw  rx  rB  r  r   rf  r%  r)  rh  r  r  r`  rq  ry  rn  rz  rp  rw  rx  r  r  r  r  r  r  rf  r  r  r  r  r  rs  rt  ru  r  rv  r.  r  r]  r{  r|  r~  r}  r  r  r  r  r  r  r  _APPROVAL_TIMEOUT_SECONDSrt  ru  	frozensetr  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r8  r  r  rs  rC  rr  rt  r   rY  rv  rO  r  r  r  rm  rv  r	  r  r  r  ro  r  r  rg  r   r   r   rW  rW  *  s          ,.S%Z(---'c'''$IEIII $J$$$It$$$$"'4'''#t###!&$&&&)-J&---:<d3S#X#67<<<e, e,x6 e, e, e, e,X$     $&??
4S> 
 
 
 
 @ @ @ @,s ,d ,W[ , , , ,
 
 
 
 &*i` i`i` c]i` i` i` i`\ &*
 

 c]
 
 
 
 "T " " " X" '$ ' ' ' X' !Xc] ! ! ! X! 8C=    X
m 
 
 
 
 
& +/%)&*H% H% H% 'H% c]	H%
 d^H% 
sDy	H% H% H% H%Ts 3 X\ ae    8A9L AQU A A A AF## #$ # # # #
)c ) ) ) )Dc D D D DLs L L L LLT L L L L
 
HSM 
W_`cWd 
pt 
 
 
 
  )-$('+   !	
 SM  } 
   & $Dc3h$8 $ $ $ \$L 3    \( D4K    \. d
    \4 $    \ ;3 ; ; ; \;     \2         \ D D    \ $+"4    \( t    \
$sCx. 
 
 
 
S3 S| SX\ S S S S_| _Z] _bf _ _ _ _B#% #E$sCx.RVBV<W # # # #<Q Q Q Q Q Q8 8 8 8t1tCH~ 1$ 1 1 1 1c d    $ 0S T    6/c / / / /b     *   > 38U   4 d W[    "eT e e e eN	l' l'c l' l' l' l'\}' }' }' }'D !& %G G G G 	G
 G 
G G G GR* * * *ZZ Z 
%	&	Z Z Z Zxk-- k-D k- k- k- k-Zhx6H S    Q	:< Q	:HSM Q	: Q	: Q	: Q	:fZ Z 	Z
 d38n%Z 
#Z Z Z Zxb9# b9 b9 b9 b9HM c M  M  M  M ^h& h&# h& h& h& h&T <  C        " , " 3 "  "  "  " H- - - - - -@%K< %KC %K %K %K %KN           ,3 L 3 S 3  3  3  3 jE  E (3- E  E  E  E N
7 L 7 S 7  7  7  7 rIJ| IJ IJ IJ IJ IJV"7 "7# "7 "7 "7 "7HS S S S S S2
L 
S 
 
 
 
: \ hsm    \I. I.# I. I. I. I.V2Xl 2Xs 2X 2X 2X 2Xh%| % % % % %.MS MT M M M M9,9,&)9,7:9, 9, 9, 9,@ #4 44 4 	4
 4 
4 4 4 4l8\ 8 8 8 8 8 8tJIJI JI
 
JI JI JI JIX9(L 9(S 9( 9( 9( 9(vJl Js J J J J:FF#2F=@F	F F F FP#J| #J #J #J #J #JJAA25A@CA	A A A AFUV\ UVc UV UV UV UVn:O :O :O :O :O :Oxm m m m m m"AR< ARC AR AR AR ARF_.L _.S _. _. _. _.B.f .f# .f .f .f .f`KT, KT3 KT KT KT KTZX
, X
3 X
 X
 X
 X
t]; ];# ]; ]; ]; ];~25L 25S 25 25 25 25hA1l A1s A1 A1 A1 A1N !$;q< ;qHSM ;q ;q ;q ;qz#K #K #K #K #K #KN !*	8+X^X=N,hoh>O)@(/S[Sgiqiw  zB  zH	+ ! !)E )E# )E )E )E )EV[J, [J3 [J [J [J [JzX X X X  #!$	E? E?E? E? 	E?
 
E? E? E? E?NW W W W Wr(0 (0 (0 (0T
 
4 
 
 
 
(# #$ # # # #
F F FBB #YB 
	B B B BHTT #YT 
	T T T Tl7
t 7
 7
 7
 7
r%F3 %FT %Fd %F %F %F %FNX>$ X>4 X> X> X> X>t %>%>%> %> 	%>
 
%> %> %> \%>N%%'*%<@%	% % % %*M M# MRV M M M M
9s 9t 9 9 9 9    ,  *.m
 m
m
 m
 d38n%	m

  m
 m
 m
 #3-m
 
c3hm
 m
 m
 m
p   !*.(,t tt t d38n%	t
 t t t t #3-t !t 
c3ht t t t t tr   rW  r  
stop_eventr  c                    ddl m} ddlm}m} d}d}t
                              d|           d}	|                                 s	  |d||           n2# t          $ r%}
t
          	                    d	|
           Y d
}
~
nd
}
~
ww xY w|	dz  }	|	|z  dk    rG|rE	 ddl
m}  ||           n2# t          $ r%}
t
          	                    d|
           Y d
}
~
nd
}
~
ww xY w|	|z  dk    r	  |d          }|rt
                              d|           n2# t          $ r%}
t
          	                    d|
           Y d
}
~
nd
}
~
ww xY w	  |d          }|rt
                              d|           n2# t          $ r%}
t
          	                    d|
           Y d
}
~
nd
}
~
ww xY w|                     |           |                                 t
                              d           d
S )a  
    Background thread that ticks the cron scheduler at a regular interval.
    
    Runs inside the gateway process so cronjobs fire automatically without
    needing a separate `hermes cron daemon` or system cron entry.

    When ``adapters`` and ``loop`` are provided, passes them through to the
    cron delivery path so live adapters can be used for E2EE rooms.

    Also refreshes the channel directory every 5 minutes and prunes the
    image/audio/document cache once per hour.
    r   )tick)cleanup_image_cachecleanup_document_cacher  r3  z"Cron ticker started (interval=%ds)F)rJ  rs  r  zCron tick error: %sNr#   rX  z#Channel directory refresh error: %s   )max_age_hoursz-Image cache cleanup: removed %d stale file(s)zImage cache cleanup error: %sz0Document cache cleanup: removed %d stale file(s)z Document cache cleanup error: %sr`  zCron ticker stopped)cron.schedulerr	  r  r	  r	  r  r  r<	  r   r  rp  rY  r  )r	  rs  r  r  	cron_tickr	  r	  IMAGE_CACHE_EVERYCHANNEL_DIR_EVERY
tick_countr  rY  r  s                r   _start_cron_tickerr	  i%  s    100000RRRRRRRR
KK4h???J!! *	3IehTBBBBB 	3 	3 	3LL.22222222	3 	a
))Q..8.GMMMMMM''1111 G G GBAFFFFFFFFG ))Q..A--B??? ZKK OQXYYY A A A<a@@@@@@@@AD00rBBB ]KK RT[\\\ D D D?CCCCCCCCD 	))); !! *< KK%&&&&&s`   A 
BA??BB* *
C4CC&)D 
D?D::D?)E- -
F7FFFr   	verbosityc                 v  K   ddl }ddlm}m}m}  |            }||t          j                    k    r|rbt                              d|           	  ||d           n># t          $ r Y n2t          t          f$ r t                              d|           Y dS w xY wt          d          D ]E}	 t          j        |d           |                    d	           .# t          t          f$ r Y  n`w xY wt                              d
|           	  ||d           |                    d	           n# t          t          t          f$ r Y nw xY w |             	 ddlm}	  |	            }
|
rt                              d|
           n\# t$          $ r Y nPw xY wt'          t)                                }t                              d||           t+          d| d           dS 	 ddlm}  |d           n# t$          $ r Y nw xY wddlm}  |t4          d           |ddlm} t:          j        t:          j        d                     |t:          j!                  }t;          j"                    }|#                    |           |$                     |d                     t;          j%                    &                    |           |t;          j%                    j'        k     r&t;          j%                    #                    |           tQ          |           dfd}fd}tS          j*                    }tW          j,                    tW          j-                    u rt\          j/        t\          j0        fD ])}	 |1                    ||           # td          $ r Y &w xY wtg          t\          d          r2	 |1                    t\          j4        |           n+# td          $ r Y nw xY wnt                              d           5                                 d{V }|sdS j6        r)j7        r t                              dj7                   dS ddl8}ddlm9}m}  |             |:                    |           tW          j;                    }tW          j<        tz          |fj>        tS          j*                    ddd !          }|5                                 ?                                 d{V  j@        r)j7        r t                              d"j7                   dS |A                                 |B                    d#$           	 dd%lCmD}  |             n# t$          $ r Y nw xY wjE        t          jE                  r#jG        st                              d&           dS dS )'a7  
    Start the gateway and run until interrupted.
    
    This is the main entry point for running the gateway.
    Returns True if the gateway ran successfully, False if it failed to start.
    A False return causes a non-zero exit code so systemd can auto-restart.
    
    Args:
        config: Optional gateway configuration override.
        replace: If True, kill any existing gateway instance before starting.
                 Useful for systemd services to avoid restart-loop deadlocks
                 when the previous process hasn't fully exited yet.
    r   N)get_running_pidr  terminate_pidz<Replacing existing gateway instance (PID %d) with --replace.Fr   z1Permission denied killing PID %d. Cannot replace.r  g      ?zAOld gateway (PID %d) did not exit after SIGTERM, sending SIGKILL.T)release_all_scoped_locksz2Released %d stale scoped lock(s) from old gateway.zAnother gateway instance is already running (PID %d, HERMES_HOME=%s). Use 'hermes gateway restart' to replace it, or 'hermes gateway stop' first.u"   
❌ Gateway already running (PID z).
   Use 'hermes gateway restart' to replace it,
   or 'hermes gateway stop' to kill it first.
   Or use 'hermes gateway run --replace' to auto-replace.
)sync_skills)quiet)setup_loggingr  )r$   r  )RedactingFormatter)r   r#   z#%(levelname)s %(name)s: %(message)sc                     dt                               d           	 dd l} |                     ddgddd          }d |j                                        D             }|r/t                               d	d
                    |                     nt                               d           n# t          $ r Y nw xY wt          j
                                                   d S )NTu/   Received SIGTERM/SIGINT — initiating shutdownr   psauxr6  )capture_outputrT  r0   c                     g | ]l}d |                                 v sd|                                 v r>t          t          j                              |                                dd         vj|mS )r&  r  r#   r5  )r   r   r   r
  r   )r   r  s     r   r  zBstart_gateway.<locals>.shutdown_signal_handler.<locals>.<listcomp>&&  sq       

,,	TZZ\\0I0I	$$DJJLL1,=== ===r   u<   Shutdown diagnostic — other hermes processes running:
  %sz
  u7   Shutdown diagnostic — no other hermes processes found)r  r  r	  rp  r  ri  r  r   r   r  r  rB  )_sp_ps_hermes_procs_signal_initiated_shutdownrunners      r   shutdown_signal_handlerz.start_gateway.<locals>.shutdown_signal_handler&  s   %)"EFFF	$$$$''u#$   C !$!6!6!8!8  M
  WSKK..   
 UVVV 	 	 	D	FKKMM*****s   BB- -
B:9B:c                  6                          dd           d S )NFTr  )r!  )r
  s   r   restart_signal_handlerz-start_gateway.<locals>.restart_signal_handler6&  s"    4@@@@@r   SIGUSR1z6Skipping signal handlers (not running in main thread).zGateway exiting cleanly: %s)write_pid_filer  )rs  r  zcron-ticker)r  r   r  daemonr   z Gateway exiting with failure: %sr3  r`  )r  z}Exiting with code 1 (signal-initiated shutdown without restart request) so systemd Restart=on-failure can revive the gateway.)Hr@  r\  r	  r  r 
  r   r
  r  r  ProcessLookupErrorPermissionErrorr  r9  r  killr  r  r
  r   r   r   printtools.skills_syncr
  hermes_loggingr
  r   agent.redactr
  loggingWARNINGINFOr   DEBUGStreamHandlersetLevelsetFormatter	getLogger
addHandlerrz  rW  r  r  r  current_threadmain_threadsignalSIGINTSIGTERMadd_signal_handlerNotImplementedErrorr  r
  r  r	  r  atexitr
  registerr  Threadr	  rs  r  r  r   r   r   r  r  
SystemExitr^  )r  r   r	  _timer	  r  r 
  existing_pidr   r
  	_releasedr$   r
  r
  r
  _stderr_level_stderr_handlerr
  r
  r  sigr  r-
  r
  	cron_stopcron_threadr  r
  r
  s                              @@r   start_gatewayr9
  %  s]     & NNNNNNNNNN"?$$LLBIKK$?$? 9	KKN  	l%88888%   #W-   G    uu 2YY  GL!,,,KK$$$$*O<   EE W   !M,d;;;;KK$$$$*OWE   DOCCCCCC4466	 aKK TV_```    o//00KLL^k  
 Ol O O O   5111111$    -,,,,,Ml;;;; 333333#O==AA)W][[!/11  ///$$%7%78]%^%^___&&7777,..444((7776""F "'+ + + + + +:A A A A A #%%D!!Y%:%<%<<<M6>2 	 	C''-DEEEE&   69%% 	''8NOOOO&   	 	LMMM LLNN""""""G u!  	LLL68JKKKt MMM>>>>>>>>N
OOO$$$ !!I"!\"OW5M5O5OPP  K  
"
"
$
$$$$$$$$&  	QLL;V=OPPPu MMOOOQ777777    #)*** " &*C M	
 	
 	
 u4s   A% %
B 1+B B 5*C  C54C5"D7 7EE-F 
FF*G= =
H
	H
N
N&%N&? O   
O-,O-U) )
U65U6c                     ddl } |                     d          }|                    ddd           |                    d	d
dd           |                                }d}|j        r[ddl}t          |j        d          5 }|                    |          }t          j	        |          }ddd           n# 1 swxY w Y   t          j        t          |                    }|st          j        d           dS dS )z CLI entry point for the gateway.r   Nz)Hermes Gateway - Multi-platform messaging)r  z--configr7  zPath to gateway config file)rF  z	--verbosez-v
store_truezVerbose output)r  rF  r'   r(   r#   )argparseArgumentParseradd_argument
parse_argsr  r  r  r  r   r  r  rp  r9
  r-  exit)r<
  parserr   r  r  r  r  r  s           r   r4  r4  &  sI   OOO$$1\$]]F

D/LMMM
T,EUVVVDF{ 3$+000 	3A>>!$$D",T22F	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 k-//00G  s   *B99B= B=__main__r  rh  )NNr  )NFr   )r	  r  r   r
  r   r  r  r-  r(
  r  r  r@  contextvarsr   r  r   r   typingr   r	   r
   r   r   r   r`	  r   r  r   r  r   utilsr   r    r   dotenvr!   hermes_cli.env_loaderr"   rS	  r  r  rZ  r   r  _yamlr  ri  r  r   ra  r*   r  _key_valr   r  r  r}  r   r   _terminal_cfgr!  _terminal_env_map_cfg_key_env_varr   r  _auxiliary_cfg_aux_task_env	_task_key_env_map	_task_cfgr   _provr  r  r  
_agent_cfg_display_cfg_tz_cfg_security_cfg_redactr   r   r~   dir_network_cfgr   r   _configured_cwdr   r   	_fallbackr  r   r   r   r  r   r   r   r   r   r   gateway.deliveryr   r  r   r   r   r   gateway.restartr   r   r   r   r   r   r$
  rw  r  objectr  r   r   r   r  r  r  r$  r1  r>  rU  rW  r  r	  r9
  r4  r   r   r   <module>ra
     se       				 				  



        $ $ $ $ $ $             , , , , , , , , , , , ,# # # #J      33ttH~~,344 5 5 5 - , , , , , 4 4 4 4 4 4 4 4         4 4 4 4 4 46!	  |h9O9O9Q9Q9YZ[9\_e9e f f f f m+ {zT,111 	-R"5?2&&,"D	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	766666%%**,, 	- 	-JD$z$c5$ 788 -T=S=S#&3t99
4  R00 #	9ZZt<< #	9!>!~! -! #$?	!
  7! %&C! $%A! 5!  !9! /! /! /! -!  !9! #$?!  !";!!" '(G#!$ #<5$?)! ! !, '8&=&=&?&? 9 9"(},,(2D
  5((SSYY:N-N-N !z$-- 9/9tz$/?/?
8,,/2s4yy
8,
 +r22 $	?jj>> $	? !<5 ;9	  !A: @>	    !>7 =;	  M( (5':':'<'< ? ?#	8*..y"==	!z)T22 IMM*b99::@@BBY]]7B7788>>@@C	j" = =>>DDFF	3y}}Y;;<<BBDD =Uf__7<BJx
34 ;4:BJx01 A7@BJx
34 ?6>BJx	23XXgr**
 	f**Z66 	fj((69c*[:Q6R6R
23 !J..3IQSQ[3[3[58SDU9V5W5W
12(J66;Yacak;k;k=@SLeAf=g=g
9:(J66;Yacak;k;k=@SLeAf=g=g
9:&*449W_a_i9i9i=@SLcAd=e=e
9:xx	2.. 	dJJ|T:: 	d L005U]_]g5g5g?Bs<PaCb?c?c
;< ((:r** 	<zz'3// 	<4ERZ4W4W,3MMOOBJ()R00:mT** 	K#''(899G"69c'll6H6H6J6J
23   	666666"cceeOODD88BGGLz,%% *,*:*:<*H*H *D)))) 	 	 	D		777777 	 	 	D		>>>>>>  """" 	 	 	D	 !
>  !$
  *..44 +/-AAA	/**>cc)$)++.>.>I!*BJ~         
                , + + + + +                    # #    c c    > 
	8	$	$ !&(( t    2s    ,4 49L 4 4 4 4-3 -3: - - - -`C: C# C C C C

d 
 
 
 
 4$; #     Xd3i0    6C M    4d |    6|L |L |L |L |L |L |L |L~Y3' 3'9? 3'X[ 3' 3' 3' 3'li i 7 i ibjknbo ix| i i i iX  0 zDFFFFF sn   W D<0W <E  W E RW WWAX* *X21X26Y YYY$ $Y,+Y,