Ë
    áß²jë  ã                  ó*  — U d Z ddlmZ ddlZddlZddlmZ ddlmZm	Z	m
Z
mZ  ej                  e«      ZdZd\  ZZdZ ed	d¬
«      Zded<   i Zded<   dai Zded<   d„ Zdd„Zdd„Zdd„Zdd„Zdd„Zej<                  d d„«       Zd!d„Z d"d„Z!d#d„Z"y)$a<  Per-image token cost learned from the provider's own usage, never from a vendor formula.

A flat per-image constant is wrong in both directions: a 1920x1080 screenshot costs ~1,100 tokens
on one provider and 4,000+ on a local mmproj model. The provider prices every image exactly on the
request that carries it, so the cost is observable: with a fresh usage anchor (real prompt count of
the previous response), the residual between the next real ``prompt_tokens`` and
``anchor + text-only delta`` is the price of the N images that delta introduced (#70328).

The learned value is kept per ``model@host`` in ``~/.hermes/cache/image_token_costs.json`` so a new
session starts calibrated, and bound per turn through a ContextVar so every estimator
(preflight trigger, tail-budget walk, gateway hygiene) prices images the same way.
é    )ÚannotationsN)Ú
ContextVar)ÚAnyÚDictÚListÚOptionaliÜ  )é@   i €  g      à?Úhermes_image_token_cost)ÚdefaultzContextVar[Optional[int]]Ú_image_cost_varúDict[str, int]Ú_LEARNEDFzDict[str, Dict[str, int]]Ú_LEARNED_BY_HOMEc                 ó   — ddl m}   | d«      S )Nr   ©Ú_cache_filezimage_token_costs.json)Úagent.model_metadatar   r   s    ú;/home/ubuntu/.hermes/hermes-agent/agent/image_token_cost.pyÚ_cache_pathr   $   s   € Ý0áÐ/Ó0Ð0ó    c                ó@   — ddl m} | xs d› d ||xs d«      xs d› �S )Nr   )Úbase_url_hostnameÚ ú@)Úutilsr   )ÚmodelÚbase_urlr   s      r   Ú_keyr   *   s*   € Ý'àŠk�rˆ]˜!Ñ-¨hªn¸"Ó=ÒCÀÐDÐEÐEr   c                 óÊ   — ddl m}   | t        «       «      j                  «       D ��ci c].  \  }}t	        |t
        «      rt        |cxk  r	t        k  rn n||“Œ0 c}}S c c}}w )Nr   )Ú_load_json_dict)r   r    r   ÚitemsÚ
isinstanceÚintÚ_MIN_PLAUSIBLEÚ_MAX_PLAUSIBLE)r    ÚkÚvs      r   Ú_read_cacher(   0   sV   € Ý4á,¬[«]Ó;×AÑAÓC÷ M‘T�Q˜Ü˜!œSÔ!¤n¸Ô&K¼^Õ&Kð ˆq‰Dó Mð Mùó Ms   ¨3Ac                 óÜ   — ddl m} m}  | «       €+t        sdat        j                  t        «       «       t        S  |«       }t        j                  |«      }|€t        «       x}t        |<   |S )zFThe active profile's learned table, loaded lazily from its cache file.r   )Úget_hermes_home_overrideÚhermes_home_keyT)	Úhermes_constantsr*   r+   Ú_LOADEDr   Úupdater(   r   Úget)r*   r+   Úhome_keyÚtables       r   Ú_tabler2   7   s`   € ÷ KáÓ!Ð)ÝØˆGÜ�O‰OœK›MÔ*ÜˆÙÓ €HÜ× Ñ  Ó*€EØ€}Ü-8«]Ð:ˆÔ  Ñ*Ø€Lr   c                óR   — t        «       j                  t        | |«      t        «      S )zALearned per-image cost for ``model@host``, else the flat default.)r2   r/   r   ÚDEFAULT_IMAGE_TOKEN_COST)r   r   s     r   Úlearned_image_token_costr5   H   s   € ä‹8�<‰<œ˜U HÓ-Ô/GÓHÐHr   c                 ó>   — t         j                  «       } | �| S t        S )z]Per-image cost bound for the running turn (see :func:`image_cost_context`), else the default.)r   r/   r4   )Úbounds    r   Úcurrent_image_token_costr8   M   s!   € ä×ÑÓ!€EØÐ%ˆ5ÐCÔ+CÐCr   c              #  óž   K  — t         j                  | «      }	 d –— t         j                  |«       y # t         j                  |«       w xY w­w)N)r   ÚsetÚreset)ÚcostÚtokens     r   Úimage_cost_contextr>   S   s:   è ø€ ä×Ñ Ó%€Eð%Ûä×Ñ˜eÕ$øŒ×Ñ˜eÕ$üs   ‚A™3 �A³A
Á
Ac           
     ón   — t         j                  t        t        | dd«      t        | dd«      «      «       y)zXBind the agent's learned per-image cost to the current context for the rest of the turn.r   Nr   )r   r:   r5   Úgetattr)Úagents    r   Úbind_image_token_costrB   \   s.   € ä×ÑÔ0´¸ÀÈÓ1NÔPWÐX]Ð_iÐkoÓPpÓqÕrr   c                ó8   ‡— ddl mŠ t        ˆfd„| D «       «      S )Nr   )Ú_count_image_tokensc              3  óR   •K  — | ]  }t        |t        «      sŒ ‰|d «      –— Œ  y­w)é   N)r"   Údict)Ú.0ÚmrD   s     €r   ú	<genexpr>zcount_images.<locals>.<genexpr>d   s"   øè ø€ ÒR¨Q¼jÈÌDÕ>QÑ" 1 a×(ÑRùs   ƒ'™')r   rD   Úsum)ÚmessagesrD   s    @r   Úcount_imagesrM   a   s   ø€ Ý8äÓR°(ÔRÓRÐRr   c                óÔ  — ddl m} t        | dd«      }	 t        |xs d«      }|dk  s t        |t        «      rt        |t        «      syt        |j                  d«      xs d«      }||d }|r/t        |d   t        «      r|d   j                  d«      dk(  r|dd }t        |«      }|dk  ryt        d«      5   |||«      }	ddd«       	€y||	z
  |z  }
t        |
cxk  r	t        k  sy yt        t        | d	d«      t        | d
d«      «      }t        «       }|j                  |«      }|€|
nt        |t         |
|z
  z  z   «      }|||<   t"        j%                  |«       	 ddlm}  |t+        «       t        |«      dd¬«       t.        j3                  d||
d›|d›|«       |S # t        t
        f$ r Y yw xY w# 1 sw Y   ŒõxY w# t,        $ r t.        j1                  dd¬«       Y Œbw xY w)a¢  Learn the per-image cost from the response that just priced ``messages``.

    Requires the PREVIOUS anchor (real count of the prior request) to still match: the residual
    ``prompt_tokens - (anchor + text-only delta)`` is then the provider's price for the images the
    delta introduced. Returns the new learned cost, or None when this response teaches nothing
    (no anchor, no new images, implausible residual).r   )Úanchored_context_tokensÚ_usage_anchorNÚ
base_countÚroleÚ	assistantrF   r   r   )Úatomic_json_write)ú,ú:)ÚindentÚ
separatorszimage token cost persist failedT)Úexc_infozdImage token cost calibrated from provider usage: %s images priced %s tokens each (learned %s for %s)rU   )Úagent.usage_anchorrO   r@   r#   Ú	TypeErrorÚ
ValueErrorr"   rG   Úlistr/   rM   r>   r$   r%   r   r2   Ú
_EMA_ALPHAr   r:   r   rT   r   Ú	ExceptionÚloggerÚdebugÚinfo)rA   rL   Úprompt_tokensrO   ÚanchorÚrealrQ   ÚdeltaÚn_imagesÚ	text_onlyÚ	per_imageÚkeyr1   ÚpriorÚlearnedrT   s                   r   Úcalibrate_from_usagerm   g   só  € õ ;ä�U˜O¨TÓ2€FðÜ�=Ò% AÓ&ˆð ˆq‚yœ
 6¬4Ô0¼
À8ÌTÔ8RØÜ�V—Z‘Z Ó-Ò2°Ó3€JØ�Z�[Ð!€EÙ”˜E !™H¤dÔ+°°a±·±¸VÓ0DÈÒ0SØ�a�b�	ˆÜ˜EÓ"€HØ�1‚}ØÜ	˜AÓ	ñ >Ù+¨H°fÓ=ˆ	÷>àÐØØ˜	Ñ! hÑ.€IÜ˜YÔ8¬.Ò8Øð 9ØÜ
Œw�u˜g tÓ,¬g°e¸ZÈÓ.NÓ
O€CÜ‹H€EØ�I‰I�c‹N€EØ ˜=‰i¬c°%¼*È	ÐTYÑHYÑ:ZÑ2ZÓ.[€GØ€Eˆ#�JÜ×Ñ˜Ô ðGÝ+áœ+›-¬¨e«¸QÈ:ÕVô ‡K�KØnØ�Y˜q�M w¨q k°Côð €NøôE ”zÐ"ò Ùðú÷>ð >ûô" ò GÜ�‰Ð6ÀˆÖFðGús/   •F# Â:
F8Å!#G Æ#F5Æ4F5Æ8GÇ G'Ç&G')r   r   r   r   ÚreturnÚstr)rn   r   )r   r   r   r   rn   r#   )rn   r#   )r<   úOptional[int])rA   r   rn   ÚNone)rL   úList[Dict[str, Any]]rn   r#   )rA   r   rL   rr   rc   r   rn   rp   )#Ú__doc__Ú
__future__r   Ú
contextlibÚloggingÚcontextvarsr   Útypingr   r   r   r   Ú	getLoggerÚ__name__r`   r4   r$   r%   r^   r   Ú__annotations__r   r-   r   r   r   r(   r2   r5   r8   Úcontextmanagerr>   rB   rM   rm   © r   r   ú<module>r~      sÃ   ðòõ #ã Û Ý "ß ,Ó ,à	ˆ×	Ñ	˜8Ó	$€àÐ à!+Ñ €�Ø€
á-7Ð8QÐ[_Ô-`€Ð*Ó `Ø€ˆ.Ó Ø
€ð /1Ð Ð+Ó 0ò1óFóMóó"Ió
Dð ×Ñò%ó ð%ósó
Sô.r   