+
    jHàj1  ã                  óÀ   € R t ^ RIHt ^ RIt^ RIt^ RItRtRtR tR R lt	R t
R R	 ltR
 R ltRR R lltR R ltR R ltR R ltR R ltRR/R R lltR tR# )u(  Session-cumulative usage for a local viewer (wave A2 / CALLMAP W3).

Main's HermesCLI read its status bar (context, ``â—·`` latency, ``t/s``, the spinner's ``â†“ N tok``),
``/usage`` and the exit summary straight off the in-process agent's ``session_*`` counters,
``context_compressor`` and ``get_rate_limit_state()``. On the session authority the agent lives in
the gateway, so the same numbers are projected here: published as ``session.usage`` after every API
call and at turn end of a local-viewer turn, and returned by the ``session.stats`` verb.
)ÚannotationsNÚ_viewer_turn_output_basec                óh   € V e.   W 8X  d(   ^ T u;8  d   R8  d   M M\        \        V 4      ^4      # R # )Ng    €„.A)ÚroundÚfloat)Úvalues   &Ú:/home/ubuntu/.hermes/hermes-agent/gateway/session_usage.pyÚ_finiter	      s.   € Ø%*Ò%6¸5¼>ÈaÐRWÎoÐZ]ÏoŒ5”�u“˜qÓ!ÐgÐcgÐgó    c               ó   € V ^8„  d   QhRR/# ©é   ÚreturnÚdict© )Úformats   "r   Ú__annotate__r      s   € ÷ Sñ S 4ñ Sr
   c                ót  € Vf   R^ R^ RRRRRRR^ /# ^ RI Hp \        ^ \        VR^ 4      ;'       g    ^ 4      pTp\        P
                  ! \        4      ;_uu_ 4        ^ R	IHp \        V R
R4      pT! \        V\        4      '       d   TM. \        V RR4      RR7      pVe
   V^ 8”  d   TpRRR4       \        ^ \        VR^ 4      ;'       g    ^ 4      pRTRV'       d   \        WH4      MTRT;'       g    RR\        VRR4      RV! V4      R\        VR^ 4      ;'       g    ^ /#   + '       g   i     L‚; i)zWMain's status-bar context figures (``_get_status_bar_snapshot``), clamped the same way.NÚlast_prompt_tokensÚcontext_tokensÚcontext_lengthÚconfig_context_lengthÚcontext_sourceÚcompression_count)Úcontext_display_source)Úanchored_context_tokensÚ_session_messagesÚ_turn_base_usage_anchorF)Úcharge_stale_thinkingÚ_config_context_length)Úagent.context_breakdownr   ÚmaxÚgetattrÚ
contextlibÚsuppressÚ	ExceptionÚagent.usage_anchorr   Ú
isinstanceÚlistÚmin)	ÚagentÚ
compressorr   ÚlastÚtokensr   ÚmessagesÚanchoredÚlengths	   &&       r   Ú_contextr1      sJ  € àÒØ$ aÐ)9¸1Ð>NÐPTØ'¨Ð/?ÀÐGZÐ\]ð_ð 	_å>Üˆq”'˜*Ð&:¸AÓ>×CÐCÀ!ÓD€DØ€FÜ	×	Ò	œY×	'Õ	'Ý>Ü˜5Ð"5°tÓ<ˆÙ*´zÀ(ÌD×7QÒ7Q©8ÐWYÜ+2°5Ð:SÐUYÓ+ZØAFôHˆð Ò H¨q¤LØˆF÷ 
(ô �”G˜JÐ(8¸!Ó<×AÐAÀÓB€FØ  $Ð(8×QW¼#¸fÔ:MÐ]cØ˜fŸn˜n¨Ø#¤W¨ZÐ9QÐSWÓ%XØÑ4°ZÓ@Ø¤¨Ð5HÈ!Ó!L×!QÐ!QÐPQð	Sð S÷ 
(×	'ús   ÁAD'Ä'D7	c                óP  € \         P                  ! \        4      ;_uu_ 4        V P                  4       pVeS   \        P
                  ! V4      '       d7   \        V\        4      '       g!   \        P                  ! V4      uuR R R 4       # R R R 4       R #   + '       g   i     R # ; i©N)	r#   r$   r%   Úget_rate_limit_stateÚdataclassesÚis_dataclassr'   ÚtypeÚasdict)r*   Ústates   & r   Ú_rate_limitr:   5   sq   € Ü	×	Ò	œY×	'Õ	'Ø×*Ñ*Ó,ˆØÒ¤×!9Ò!9¸%×!@Ò!@ÌÐTYÔ[_×I`ÒI`Ü×%Ò% eÓ,÷ 
(×	'Ò	'ñ ÷	 
(Ö	'ñ ús   £0BÁ+BÂB%	c               ó   € V ^8„  d   QhRR/# )r   r   zdict | Noner   )r   s   "r   r   r   =   s   € ÷ ñ ˜ñ r
   c           
     óš  € \         P                  ! \        4      ;_uu_ 4        \        V RR4      p\        VRR4      RJ dî   VP                  p\        R VP                   4       R4      pVe   VP                  '       d   TMT;'       g    Tp\        VRR4      pVe�   \        V\        4      '       d5   ^ Tu;8  d+   \        \        P                  ! 4       R,          4      8:  gH   M R	VP                  R
VP                  R\        VP                  4      RVP                  /uuRRR4       # RRR4       R#   + '       g   i     R# ; i)uÆ   Window plans only: the allowance the status bar shows at a glance (today's, else the one that binds),
from the reply headers the agent already tracks â€” no extra round trip, None for everyone else.Ú_credits_stateNÚis_usage_windowFTc              3  óp   "  € T F,  qP                   R 8X  g   K  VP                  R8X  g   K(  Vx € K.  	  R# 5i)ÚdayÚallN)ÚidÚscope)Ú.0Úgs   & r   Ú	<genexpr>Úplan_gauge.<locals>.<genexpr>D   s(   é € ÐV¡<˜a·4±4¸5±=œÀQÇWÁWÐPUÑEUŸš£<ùs   ‚6™6¬
6Úresets_at_msiè  rB   ÚlabelÚused_bp)r#   r$   r%   r"   Úbinding_gaugeÚnextÚgaugesÚfullr'   ÚintÚtimerB   rI   rJ   rH   )r*   r9   Úbindingr@   ÚgaugeÚresets   &     r   Ú
plan_gaugerT   =   s  € ô 
×	Ò	œY×	'Õ	'Ü˜Ð/°Ó6ˆÜ�5Ð+¨UÓ3°tÓ;Ø×)Ñ)ˆGÜÑV 5§<¢<ÓVÐX\Ó]ˆCà&Ò2°w·|·|°|‘GÈ#Ï.È.ÐQXˆEÜ˜E >°4Ó8ˆEØÒ ¬*°U¼C×*@Ò*@ÀQÈÖEiÔRUÔVZ×V_ÒV_ÓVaÐdhÕVhÓRiÖEiØ˜eŸh™h¨°·±¸iÌÈUÏ]É]ÓI[Ø&¨×(:Ñ(:ð<÷ 
(×	'Ò	'ñ ÷ 
(Ö	'ñ ús   £AD9Â
D9ÂBD9Ä9E
	c               ó   € V ^8„  d   QhRR/# r   r   )r   s   "r   r   r   N   s   € ÷ ñ ˜$ñ r
   c                ó(  € \          UUu/ uF%  w  rT\        \        W^ 4      ;'       g    ^ 4      bK'  	  pppVP                  \	        V \        V RR4      4      4       R;rE\
        P                  ! \        4      ;_uu_ 4        \        \        V RR4      ;'       g    . 4      p\        \        V RR4      ;'       g    . 4      p\        \        V4      \        V4      4      ;p'       dG   \        Wh) R 4      p	\        W˜,          4      pV	^ 8”  d   \        \        Wx) R 4      V	,          4      MRpRRR4       ^ p
\
        P                  ! \        4      ;_uu_ 4        ^ RIHp V! 4       p
RRR4       \        V \        R4      pTP                  YE\!        V\        4      '       d   \#        ^ VR,          V,
          4      M^ V e   \%        V 4      MRT
\'        \        V RR4      ;'       g    R4      \'        \        V R	R4      ;'       g    R4      \        V R
R4      RJ d+   \'        \        V RR4      ;'       g    R4      ;'       g    RMRR7       \)        V 4      ;pe   WÓR&   V# u uppi   + '       g   i     ELE; i  + '       g   i     EL; i)zbThe frozen ``session.usage`` / ``session.stats`` dict; zeros before the first turn built an agent.Úcontext_compressorNÚ_api_latency_historyÚ_api_output_history)Úactive_countÚoutput_tokensÚmodelÚ ÚproviderÚ_fallback_activatedFT)Úavg_latency_sÚtokens_per_sÚlast_turn_tokensÚ
rate_limitÚactive_subagentsr\   r^   Úfallback_modelrT   )Ú	_COUNTERSrO   r"   Úupdater1   r#   r$   r%   r(   r)   ÚlenÚsumr	   Útools.async_delegationrZ   ÚTURN_BASE_ATTRr'   r!   r:   ÚstrrT   )r*   ÚkeyÚattrÚstatsÚavg_latencyÚtpsÚ	latenciesÚoutputsÚnÚtotalÚactiverZ   ÚbaserR   s   &             r   Úusage_statsrx   N   s)  € åKTÔUÉ9¹i¸c�3œœG E°Ó3×8Ð8°qÓ9Ò9É9€EÑUØ	‡L�L”˜%¤¨Ð0DÀdÓ!KÓLÔMØÐ€KÜ	×	Ò	œY×	'Õ	'Üœ Ð(>ÀÓE×KÐKÈÓLˆ	Ü”w˜uÐ&;¸TÓB×HÐHÀbÓIˆÜ”C˜	“N¤C¨£LÓ1Ð1ˆ1Ö1Ü˜	 " #˜Ó'ˆEÜ! %¥)Ó,ˆKØ8=À¼	”'œ#˜g b c˜lÓ+¨eÕ3Ô4ÀtˆC÷ 
(ð €FÜ	×	Ò	œY×	'Õ	'Ý7Ù“ˆ÷ 
(ô �5œ.¨$Ó/€DØ	‡L�L˜{ÜKUÐVZÔ\_×K`ÒK`¤# a¨¨Õ)?À$Õ)FÔ"GÐfgØ27Ò2CœK¨Ô.ÈÐ`fÜœ7 5¨'°2Ó6×<Ð<¸"Ó=ÌÌGÐTYÐ[eÐgiÓLj×LpÐLpÐnpÓHqä˜EÐ#8¸%Ó@ÀDÓHô "%¤W¨U°G¸RÓ%@×%FÐ%FÀBÓ!G×!OÐ!OÈ4øØNRð ô Tô ˜EÓ"Ð"ˆÒ/Ø#ˆlÑØ€Lùó/ V÷ 
(×	'Ð	'ú÷ 
(×	'Ð	'ús$   Š+I&Â9I,Â=A3I,ÅJ É,I=	Ê J	c               ó   € V ^8„  d   QhRR/# )r   r   rO   r   )r   s   "r   r   r   j   s   € ÷ _ñ _°3ñ _r
   c                óÌ   € \        \        VRR4      R^ 4      p\        V R^ 4      p\        \        V\        4      '       d   TM^ \        V\        4      '       d   V4      # ^ 4      # )a  Compactions of this conversation: main's agent counted them on its compressor for the
session's life. A canonical compress evicts the gateway's agent (a session boundary), so the
count rides the live session and seeds the successor (``seed_compression_count``).rW   Nr   )r"   r!   r'   rO   )Úliver*   ÚownÚcarrieds   &&  r   Úcarried_compression_countr~   j   s^   € ô ”'˜%Ð!5°tÓ<Ð>QÐSTÓ
U€CÜ�dÐ/°Ó3€GÜœ* W¬c×2Ò2‰w¸Ä*ÈSÔRU×BVÒBV¸3Ó^Ð^Ð\]Ó^Ð^r
   c               ó   € V ^8„  d   QhRR/# ©r   r   ÚNoner   )r   s   "r   r   r   s   s   € ÷ Hñ H¨dñ Hr
   c                óà   € Rp\         P                  ! \        \        4      ;_uu_ 4        V P	                  V4      pRRR4       \        W#4      ^,           Vn        R#   + '       g   i     L); i)z^A committed (never an exact-retried) compress: one more compaction than the evicted agent saw.N)r#   r$   ÚAttributeErrorÚKeyErrorr*   r~   r   )Ú	authorityÚrefr{   r*   s   &&& r   Únote_compressionr‡   s   sH   € à€EÜ	×	Ò	œ^¬X×	6Õ	6Ø—‘ Ó$ˆ÷ 
7ä6°tÓCÀaÕG€DÖ÷ 
7×	6ús   ªAÁA-	c               ó   € V ^8„  d   QhRR/# r€   r   )r   s   "r   r   r   {   s   € ÷ Rñ R¨4ñ Rr
   c                óÖ   € \        VR R4      pV eD   Ve>   \        P                  ! \        4      ;_uu_ 4        \	        W4      Vn        RRR4       R# R# R#   + '       g   i     R# ; i)rW   N)r"   r#   r$   r%   r~   r   )r{   r*   r+   s   && r   Úseed_compression_countrŠ   {   sT   € Ü˜Ð 4°dÓ;€JØÒ˜JÒ2Ü× Ò ¤×+Õ+Ü+DÀTÓ+QˆJÔ(÷ ,Ñ+ñ 3Ñß+×+Ð+ús   ¸AÁA(	c               ó    € V ^8„  d   QhRRRR/# ©r   ro   r   r   r   )r   s   "r   r   r   ‚   s   € ÷ ñ �Tð ˜dñ r
   c                ó*  € RV P                  R4      ;'       g    RRV P                  R4      ;'       g    V P                  R4      ;'       g    ^ RV P                  R4      ;'       g    V P                  R4      ;'       g    ^ R	V P                  R
4      ;'       g    ^ RV P                  R4      ;'       g    ^ RV P                  R4      ;'       g    ^ RV P                  R4      ;'       g    ^ RV P                  R4      ;'       g    ^ /pV P                  R4      ;'       g    ^ V P                  R4      ;'       g    ^ r2V'       dp   V'       dh   \        W#4      pV P                  R4      ;'       g    RpVP                  W#\        ^ \        ^d\	        W#,          ^d,          4      4      4      WDR8g  R7       V P                  R4      e   V P                  R4      ;'       g    ^ VR&   V P                  R4      ;'       g    ^ V P                  R4      ;'       g    ^ reV^ 8”  d7   V^ 8”  d0   \        ^ \        ^d\	        We,          ^d,          4      4      4      VR&   R FO  w  rx\        V P                  V4      \        \        34      '       g   K2  \	        \        W,          4      ^4      W&   KQ  	  \        V P                  R4      \        4      '       d   V R,          VR&   \        V P                  R4      \        4      '       d   V R,          VR&   V# )u   ``stats`` in main's TUI ``Usage`` shape (``tui_gateway/server.py::_get_usage``): the fields its
status bar (context used/max/bar, ``â—·`` latency, ``t/s``, ``cmp`` badge, cache hit) and ``/usage``
read off ``message.complete.usage``. Absent figures are omitted, never fabricated as zeros.r\   r]   ÚinputÚinput_tokensÚprompt_tokensÚoutputr[   Úcompletion_tokensÚ	reasoningÚreasoning_tokensÚpromptÚ
completionru   Útotal_tokensÚcallsÚ	api_callsr   r   r   Úprovider_usage)Úcontext_usedÚcontext_maxÚcontext_percentr   Úcontext_estimatedr   ÚcompressionsÚcache_read_tokensÚcache_hit_pctrd   rT   ))r`   r`   )Úavg_tpsra   )	Úgetr)   rg   r!   r   r'   rO   r   r   )	ro   ÚusageÚusedÚmaximumÚsourceÚprompt_totalÚ
cache_readrm   Ú
source_keys	   &        r   Ú	tui_usager«   ‚   s”  € ð �e—i‘i Ó(×.Ð.¨B°¸¿¹À>Ó9R×9uÐ9uÐV[×V_ÑV_Ð`oÓVp×9uÐ9uÐtuØ�u—y‘y Ó1×XÐX°U·Y±YÐ?RÓ5S×XÐXÐWXØ˜%Ÿ)™)Ð$6Ó7×<Ð<¸1¸hÈÏ	É	ÐRaÓHb×HgÐHgÐfgØ˜5Ÿ9™9Ð%8Ó9×>Ð>¸QÀÈÏÉÐSaÓIb×IgÐIgÐfgØ�e—i‘i Ó,×1Ð1°ð	3€Eð
 —I‘IÐ2Ó3×8Ð8°q¸%¿)¹)ÐDTÓ:U×:ZÐ:ZÐYZˆ'ß—ä�4Ó!ˆØ—‘Ð+Ó,×@Ð@Ð0@ˆØ�‰ $Ü%(¨¬C°´U¸4½>ÈCÕ;OÓ5PÓ,QÓ%RØ$*ÐHXÑ>Xð 	ô 	Zð ‡y�yÐ!Ó"Ò.Ø %§	¡	Ð*=Ó >× CÐ CÀ!ˆˆnÑØ$Ÿy™y¨Ó9×>Ð>¸QÀÇ	Á	ÐJ]Ó@^×@cÐ@cÐbc�*Ø�aÔ˜J¨œNÜ!$ Q¬¨C´°zÕ7PÐSVÕ7VÓ1WÓ(XÓ!YˆˆoÑÛ\‰ˆÜ�e—i‘i 
Ó+¬c´5¨\×:Ô:Üœu UÕ%6Ó7¸Ó;ˆE‹Jñ ]ô �%—)‘)Ð.Ó/´×5Ò5Ø$)Ð*<Õ$=ˆÐ Ñ!Ü�%—)‘)˜LÓ)¬4×0Ò0Ø# LÕ1ˆˆlÑØ€Lr
   c               ó    € V ^8„  d   QhRRRR/# rŒ   r   )r   s   "r   r   r   ¢   s   € ÷ 0ñ 0�tð 0 ñ 0r
   c                ó    € R\        V 4      /V C# )u¼  The ``session.usage`` event payload: BOTH views of the same counters, in one frame.

``SessionUsagePayload`` (``tui_gateway/contracts/events.py``) allows either view â€” the TUI
``usage`` object (``server._start_usage_ticker``) or the session-cumulative counters at the top
level â€” and the readers on the far end want different halves. The classic CLI
(``hermes_cli.gateway_connection.SessionState.apply_event``) keeps the top-level counters
whenever they are present and ignores the nested view; ACP (``acp_adapter.gateway_server``)
reads only the top level; a Desktop bundle older than ``usageFromTick`` reads only
``payload.usage``, so its context / cache-hit / tokens-per-second meters render their empty
placeholder for as long as the frame carries the counters alone. Publishing both serves every
viewer from one frame, and leaves the counters untouched for every existing consumer.

``usage`` is the standard status-bar projection of the embedded ticker's ``server._get_usage``
view, with two exceptions: ``dev_credits_spent_micros`` (``HERMES_DEV_CREDITS`` only) is not
carried, and ``avg_latency_s`` / ``avg_tps`` are rounded from the counters' two decimals rather
than the raw values, so they can differ by 0.1 at a rounding boundary. A Desktop bundle that
reads only ``payload.usage`` fills its meters here too. The
top-level counters on this event are deprecated: new viewers read ``usage`` (or call
``session.stats`` for the counters). Before they can be dropped, these readers must move off
them: the classic CLI's ``SessionState.apply_event`` â†’ ``GatewayAgent.apply_session_usage``,
ACP's ``_project_usage`` (``usage_update`` / ``turn_usage``), and the flat branch of
``usageFromTick`` (Desktop and Ink).
r¤   )r«   )ro   s   &r   Úusage_framer®   ¢   s   € ð0 ”Y˜uÓ%Ð/¨Ð/Ð/r
   ÚrecordFc               ó    € V ^8„  d   QhRRRR/# )r   r¯   Úboolr   r�   r   )r   s   "r   r   r   ½   s   € ÷ 2ñ 2¨$ð 2¸4ñ 2r
   c               ó(  € Vf   R# \         P                  ! \        4      ;_uu_ 4        \        V4      pV P	                  R\        V4      4       V'       d   ^ RIHp VP                  4       pVe   W5R&   RRR4       R#   + '       g   i     R# ; i)a  One ``session.usage`` frame on the viewer's stream; never breaks the turn. At turn end
(``record``) the same dict rides the captured execution result, so the turn's
``message.complete`` carries main's ``usage`` (``session_settlement_recovery.completion_payload``).Nzsession.usage)Úexecution_resultÚsession_usage)	r#   r$   r%   rx   Ú_publish_executionr®   Úgateway.session_resultsr³   r£   )Úturnr*   r¯   ro   r³   Úcaptureds   &&$   r   Úpublish_usager¹   ½   sm   € ð ‚}ÙÜ	×	Ò	œY×	'Õ	'Ü˜EÓ"ˆØ×Ñ ´¸UÓ1CÔDßÝ@Ø'×+Ñ+Ó-ˆHØÒ#Ø,1˜Ñ)÷ 
(×	'×	'Ò	'ús   ©AB Â B	c              ƒ  ó‚  "  € ^ RI Hp \        V4      RR0,
          '       d	   V! R4      hV P                  P	                  V P
                  V4      G Rj  x€L
  V P                  P                  V4      p\        V4      p\        V P                  P                  P                  VP                  4      V4      VR&   V#  Lh5i)zH``session.stats {session_id}``: the same dict ``session.usage`` carries.)ÚRuntimeStoreErrorÚ
session_idÚprofileÚinvalid_paramsNr   )Úhermes_state_runtimer»   Úsetr…   ÚresolveÚactorr*   rx   r~   Úsessionsr£   r¼   )Ú
connectionr†   Úparamsr»   r*   Úresults   &&&   r   ro   ro   Í   s¥   é € å6Ü
ˆ6ƒ{�l IÐ.×.Ô.ÙÐ 0Ó1Ð1Ø
×
Ñ
×
&Ñ
& z×'7Ñ'7¸Ó
=×=Ð=Ø× Ñ ×&Ñ& sÓ+€EÜ˜Ó€FÜ";¸J×<PÑ<P×<YÑ<Y×<]Ñ<]Ð^a×^lÑ^lÓ<mÐotÓ"u€FÐÑØ€Mñ	 >ùs   ‚AB?ÁB=ÁA)B?)	)r�   Úsession_input_tokens)r[   Úsession_output_tokens)r    Úsession_cache_read_tokens)Úcache_write_tokensÚsession_cache_write_tokens)r�   Úsession_prompt_tokens)r’   Úsession_completion_tokens)r—   Úsession_total_tokens)r”   Úsession_reasoning_tokens)r™   Úsession_api_callsr3   )Ú__doc__Ú
__future__r   r#   r5   rP   rf   rk   r	   r1   r:   rT   rx   r~   r‡   rŠ   r«   r®   r¹   ro   r   r
   r   Ú<module>rÓ      so   ðñõ #ã Û Û ð1€	ð ,€òhõSò0õõ"÷8_õHõRõõ@0ð62°÷ 2ô 	r
   