
    JjQ!                    :   U d Z ddlmZ ddlZddlmZmZ ddlm	Z	 ddl
mZ ddlZddlmZ dZd	Zd
ZdZg dg ddZded<   d>dZddd?dZddd@dZdAd#ZdBd%ZdddCd'ZdDd(Z e            Zded)<   dDd*Zdd+dEd,ZdFdGd0Zdddd1dHd7Z ddddddd8dId=Z!dS )Ja  Human-friendly generic gateway status phrases.

These helpers deliberately avoid relaying raw model scratch text.  They turn
Hermes' long-running gateway status surface into short status lines suitable
for chat surfaces.

Built-in defaults live in ``gateway/assets/status_phrases.yaml``. Users can add
portable, profile-relative phrase catalogs under ``HERMES_HOME`` either by using
conventional paths::

    ~/.hermes/status_phrases.yaml
    ~/.hermes/status_phrases/*.yaml

or by pointing config at a relative file/directory::

    display:
      status_phrases:
        path: status_phrases/whatsapp.yaml  # relative to HERMES_HOME
        mode: append                        # append (default) or replace

Absolute paths and ``..`` escapes are ignored on purpose so config stays
profile-portable and does not accidentally read arbitrary files.

Only configured phrase strings are used; raw tool args, commands, previews, and
reasoning text are never interpolated into the returned phrase.
    )annotationsN)MappingMutableSequence)Path)Any)get_hermes_home)statusgenericP      )status_phrases.yamlstatus_phrases)zstill on itzstill working through itzwaiting for the result)zon itzone seczchecking that nowdict[str, list[str]]_FALLBACK_PHRASESvaluer   return	list[str]c                P   t          | t                    sg S g }t                      }| d t                   D ]n}t	          |pd                                          }|rt          |          t          k    s||v rD|                    |           |	                    |           o|S )N )

isinstancelistset_MAX_CUSTOM_PHRASES_PER_SURFACEstrstriplen_MAX_PHRASE_CHARSappendadd)r   cleanedseenitemphrases        </home/rurouni/.hermes/hermes-agent/gateway/status_phrases.py_clean_phrase_listr%   5   s    eT"" 	GUUD6667  TZR&&(( 	V'888FdNNvN    inherited_modecatalogsectionMapping[str, Any]r(   
str | NoneNonec                  t          |                    d          p|pd                                                                          }|dk    }t	          |                    d          t
                    r|                    d          n|}t          D ]_}t          t	          |t
                    r|                    |          nd           }|s>|r|ng |                     |g           || |<   `d S )Nmoder   replacephrases)r   getr   lowerr   r   _STATUS_SURFACESr%   )r)   r*   r(   r/   r0   
phrase_mapsurfacer1   s           r$   _merge_phrase_mappingr7   C   s    w{{6""@n@AAGGIIOOQQDiG+5gkk)6L6Lg+V+VcY'''\cJ# Y Y$
:W^@_@_%iZ^^G%<%<%<eijj 	&-X773XW[["5M5M3XPW3X	Y Yr&   pathr   c                   	 t          j        |                    d                    }n# t          $ r Y d S w xY wt	          |t
                    rt          | ||           d S d S )Nzutf-8)encodingr'   )yaml	safe_load	read_text	Exceptionr   r   r7   )r)   r8   r(   loadeds       r$   _merge_phrase_filer@   N   s     @ @AA   &'"" NgvnMMMMMMN Ns   (+ 
99base_dirraw_pathPath | Nonec                z   t          |pd                                          }|sd S t          |                                          }|                                s	d|j        v rd S |                                 }||z                                  }	 |                    |           n# t          $ r Y d S w xY w|S )Nr   z..)	r   r   r   
expanduseris_absolutepartsresolverelative_to
ValueError)rA   rB   raw	candidatebaseresolveds         r$   _relative_path_underrO   W   s    
hn"


#
#
%
%C tS		$$&&I $)/"9"9tDy ))++HT""""   ttOs   B* *
B87B8
list[Path]c                    |                                  r| j                                        dv r| gS |                                 r+t	          d |                                 D                       S g S )N   .yml.yamlc              3  x   K   | ]5}|                                 r|j                                        d v 1|V  6dS )rR   N)is_filesuffixr3   ).0childs     r$   	<genexpr>z%_iter_phrase_files.<locals>.<genexpr>k   sX       
 
}}
#(<#5#5#7#7;L#L#L #L#L#L#L
 
r&   )rV   rW   r3   is_dirsortediterdir)r8   s    r$   _iter_phrase_filesr^   g   s    ||~~ $+++--1BBBv{{}} 
 
 
#||~~
 
 
 
 
 	
 Ir&   pathsc                   |d S t          |t                    r|n|g}|D ]9}t          ||          }|t          |          D ]}t	          | ||           :d S )Nr'   )r   r   rO   r^   r@   )r)   r_   rA   r(   	raw_pathsrB   rN   phrase_files           r$   _merge_phrase_pathsrc   r   s     }#E400=ugI T T'(;;-h77 	T 	TKwNSSSSS	T	T Tr&   c                     d t                                           D             } t          t                                                    j        dz  dz  }t          | |d           | S )Nc                4    i | ]\  }}|t          |          S  r   rX   r6   r1   s      r$   
<dictcomp>z)_load_builtin_catalog.<locals>.<dictcomp>   s%    XXX*:'7wWXXXr&   assetsr   r0   r'   )r   itemsr   __file__rH   parentr@   )r)   catalog_paths     r$   _load_builtin_catalogro      sa    XX>O>U>U>W>WXXXG>>))++2X=@UULwYGGGGNr&   _DEFAULT_PHRASESc                 H    d t                                           D             S )Nc                4    i | ]\  }}|t          |          S rf   rg   rh   s      r$   ri   z)_copy_default_catalog.<locals>.<dictcomp>   s%    TTT'7wGT']]TTTr&   )rp   rk   rf   r&   r$   _copy_default_catalogrs      s#    TT;K;Q;Q;S;STTTTr&   rA   c                  t          |t                    sdS t          |                    d          pd                                                                          }|Lt          | |                    d          ||           t          | |                    d          ||           t          | |           dS )z@Merge one display.status_phrases-style section into ``catalog``.Nr/   r   r8   )rA   r(   r_   )r   r   r   r2   r   r3   rc   r7   )r)   r*   rA   r/   s       r$   _merge_phrase_configrv      s    gw'' w{{6"".h//5577==??DGW[[%8%88\`aaaaGW[[%9%9H]abbbb'7+++++r&   user_configMapping[str, Any] | Noneplatform_keyc                   t                      }t                      }t          |t          t                    |           t          | t                    r| pi                     d          nd}t          |t                    s|S t          ||                    d          |           t          ||                    d          |           |                    d          }|rt          |t                    rt|                    |          }t          |t                    rJt          ||                    d          |           t          ||                    d          |           |S )a>  Resolve built-in + user-configured generic status phrases.

    Resolution order mirrors gateway display settings: built-ins, conventional
    profile-relative user files, global ``display.status_phrases`` (or legacy
    alias ``generic_status_phrases``), then
    ``display.platforms.<platform>.status_phrases``.
    rt   displayNgeneric_status_phrasesr   	platforms)	rs   r   rc   r   _CONVENTIONAL_RELATIVE_PATHSr   r   r2   rv   )rw   ry   r)   hermes_homer{   r}   platform_displays          r$   resolve_status_phrase_catalogr      sd    $%%G!##K&B!C!CkZZZZ4>{G4T4T^{ b%%i000Z^Ggw'' '++.F"G"GR]^^^^'++.>"?"?+VVVVK((I h
9g66 h$==66&00 	h *:*>*>?W*X*Xcnoooo *:*>*>?O*P*P[fggggNr&   	tool_namepreviewargskindr   r   r   r   c               |    t          | pd                                                                          }|dv rdS dS )zCClassify an internal gateway event into a Hermes UI-surface bucket.r   >   r	   waiting	heartbeatlong_runningr	   r
   )r   r   r3   )r   r   r   r   
normalizeds        r$   classify_status_contextr      sA     TZR&&((..00JGGGx9r&   )r   r   r   recentrngr)   r   MutableSequence[str] | Noner   Mapping[str, list[str]] | Nonec                  |pt           }t          | |||          }t          |                    |          p!|                    d          pt           d                   }	|r!t	          |          fd|	D             }
|
r|
}	|pt
          }|                    |	          }||                    |           |dd= |S )zPick a short generic status phrase, avoiding recent repeats.

    ``preview`` and ``args`` are accepted for callback compatibility, but their
    raw contents are never embedded in the returned phrase.
    r   r
   c                    g | ]}|v|	S rf   rf   )rX   r#   
recent_sets     r$   
<listcomp>z(choose_status_phrase.<locals>.<listcomp>   s#    MMMFF*4L4L4L4L4Lr&   Ni)rp   r   r   r2   r   _randomchoicer   )r   r   r   r   r   r   r)   phrase_catalogcategory
candidatesfreshpickerr#   r   s                @r$   choose_status_phraser      s     0 0N&ty'X\]]]Hn((22rn6H6H6S6SrWghqWrssJ [[
MMMMjMMM 	J^GF]]:&&Ff3B3KMr&   )r   r   r   r   )r)   r   r*   r+   r(   r,   r   r-   )r)   r   r8   r   r(   r,   r   r-   )rA   r   rB   r   r   rC   )r8   r   r   rP   )
r)   r   r_   r   rA   r   r(   r,   r   r-   )r   r   )r)   r   r*   r   rA   rC   r   r-   )N)rw   rx   ry   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   )"__doc__
__future__r   randomr   collections.abcr   r   pathlibr   typingr   r;   hermes_constantsr   r4   r   r   r~   r   __annotations__r%   r7   r@   rO   r^   rc   ro   rp   rs   rv   r   r   r   rf   r&   r$   <module>r      s    6 # " " " " "     4 4 4 4 4 4 4 4              , , , , , ,
 ) "$  H  TSS888+ +         vz Y Y Y Y Y Y cg N N N N N N         "&T T T T T T$    *?)>)@)@  @ @ @ @U U U U bf , , , , , ,    > !     " !*..2       r&   