
    `gj                    h   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 d dlm	Z	m
Z
mZ d dlZd dlmZmZ d dlmZmZmZ d dlmZ e	rd d	lmZ  ej.                  e      Zd.d
Z ed       G d d             Z ed       G d d             Zd/dZd0dZd1dZddd2dZ d3dZ!d4dZ"d5dZ#dddd6dZ$d5dZ% ed       G d d             Z&dddd7d Z'd8d!Z(d9d"Z)	 	 	 	 	 	 d:d#Z*	 	 d;	 	 	 	 	 d<d$Z+ ed       G d% d&             Z,d'Z-dddd(	 	 	 	 	 	 	 d=d)Z.d5d*Z/d<d+Z0ddd,	 	 	 	 	 	 	 d>d-Z1y)?    )annotationsN)	dataclass)datetimetimezone)TYPE_CHECKINGAnyOptional)_is_oauth_tokenresolve_anthropic_token)	AuthError_read_codex_tokens!resolve_codex_runtime_credentials)resolve_runtime_provider)	TypeGuardc                 H    t        j                  t        j                        S N)r   nowr   utc     F/root/.hermes/venv/lib/python3.12/site-packages/agent/account_usage.py_utc_nowr      s    <<%%r   T)frozenc                  B    e Zd ZU ded<   dZded<   dZded<   dZded	<   y)
AccountUsageWindowstrlabelNzOptional[float]used_percentOptional[datetime]reset_atOptional[str]detail)__name__
__module____qualname____annotations__r   r    r"   r   r   r   r   r      s&    J$(L/(#'H ' FM r   r   c                      e Zd ZU ded<   ded<   ded<   dZded<   dZd	ed
<   dZded<   dZded<   dZd	ed<   e	dd       Z
y)AccountUsageSnapshotr   providersourcer   
fetched_atzAccount limitstitleNr!   planr   ztuple[AccountUsageWindow, ...]windowstuple[str, ...]detailsunavailable_reasonc                f    t        | j                  xs | j                        xr | j                   S r   )boolr.   r0   r1   selfs    r   	availablezAccountUsageSnapshot.available,   s(    DLL0DLL1Q$:Q:Q6QQr   returnr3   )r#   r$   r%   r&   r,   r-   r.   r0   r1   propertyr6   r   r   r   r(   r(   !   sZ    MK!E3!D-.0G+0!G_!(,,R Rr   r(   c                    t        | xs d      j                         }|sy |j                  dd      j                  dd      j                         S )N _ -)r   stripreplacer,   )valuecleaneds     r   _title_case_slugrC   1   sF    %+2$$&G??3$,,S#6<<>>r   c                   | dv ry t        | t        t        f      r.t        j                  t        |       t
        j                        S t        | t              rp| j                         }|sy |j                  d      r|d d dz   }	 t        j                  |      }|j                  r|S |j                  t
        j                        S y # t        $ r Y y w xY w)N>   Nr;   )tzZz+00:00)tzinfo)
isinstanceintfloatr   fromtimestampr   r   r   r?   endswithfromisoformatrH   r@   
ValueError)rA   textdts      r   	_parse_dtrR   8   s    
%#u&%%eElx||DD%{{}==9x'D	''-B2G

(,,
(GG   		s   "C *C 	CCc                d   | sy| j                         }| t               z
  }t        |j                               }|dk  rd|j	                  d       dS t        |d      \  }}|dz  }|dk\  rt        |d      \  }}d	| d
| d}n|dkD  r
d	| d| d}nd	| d}| d|j	                  d       dS )Nunknownr   znow (z%Y-%m-%d %H:%M %Z)i  <      zin zd hzh m ()
astimezoner   rJ   total_secondsstrftimedivmod)	rQ   local_dtdeltar\   hoursremminutesdaysrels	            r   _format_resetrf   K   s    }}HOE++-.Mx(()<=>a@@t,JE3RiG{UB'eD6E7!$	E7"WIQ'G9AU"X&&':;<A>>r   Fmarkdownc          
     h   | sg S d|rdnd | j                    |rdnd }|g}| j                  r-|j                  d| j                   d| j                   d       n|j                  d| j                          | j                  D ]  }|j
                  |j                   d}nht        dt        d	t        |j
                        z
              }t        dt        t        |j
                                    }|j                   d
| d| d}|j                  r|dt        |j                         z  }n|j                  r|d|j                   z  }|j                  |        | j                  D ]  }|j                  |        | j                  r|j                  d| j                          |S )Nu   📈 z**r;   z
Provider: rZ   rU   z: unavailabler   d   z: z% remaining (z% used)u    • resets     • zUnavailable: )r,   r-   appendr)   r.   r   r   maxroundrK   r    rf   r"   r0   r1   )	snapshotrh   headerlineswindowbase	remainingusedr"   s	            r   render_account_usage_linesrv   _   s   	XT2.x~~.>xtUW>XYFHE}}z("3"3!4Bx}}oQGHz("3"3!456"" &ll^=1DAuS51D1D+E%EFGIq%f&9&9 :;<Dll^2i[dV7KD??l=#A"BCCD]]eFMM?++DT "" V""}X%@%@$ABCLr   c                    d| dS )N$z,.2fr   )ds    r   _fmt_usdrz   {   s    qh<r   c                    t        | t        t        f      xr( t        | t               xr t	        j
                  |       S )u"  True iff v is a real numeric value (int or float, not bool, not NaN/Inf).

    Typed as a ``TypeGuard[float]`` so the type checker narrows ``v`` to a real
    number in the positive branch — callers can then do arithmetic / pass it to
    ``_fmt_usd`` without a None-operand warning.
    )rI   rJ   rK   r3   mathisfinite)vs    r   _is_finite_numr      s3     a#u&Wz!T/B+BWt}}UVGWWr   c                   	 ddl m} | t        | dd      syt        | dd      }t        | dd      }g }g }|t        |dd      }t        |d	d      }t        |      rk|dkD  rft        |      r[||k  rV||z
  }t	        d
t        d||z  dz              }	|j                  t        d|	t        |       dt        |       d             |t        |dd      }
t        |
      r|j                  dt        |
              t        |dd      }t        |      r|j                  dt        |              t        |dd      }t        |      r|j                  dt        |              |]t        |dd      }t        |      r"|dkD  r|j                  dt        |              t        |dd      }|r|j                  d|        t        | dd      }|du r|j                  d       |s|sy|j                  d ||               |j                  d       |t        |dd      nd}t        dd t               d!|t        |      t        |      "      S # t        t        f$ r Y yw xY w)#a  Map a NousPortalAccountInfo into an AccountUsageSnapshot for /usage.

    Shows dollar magnitudes (subscription / top-up / total) + renewal date + a
    portal CTA. When the portal supplies a subscription denominator
    (``monthly_credits``), also emits a subscription-usage window so the renderer
    shows a real ``% used`` gauge; when it's absent (older portals) the view
    gracefully degrades to magnitudes-only. Returns None when there's no usable
    account info to show (fail-open: caller just shows nothing).
    r   )nous_portal_topup_urlN	logged_inFpaid_service_access_infosubscriptionmonthly_creditscredits_remaining              Y@Subscriptionz of  leftr   r   r"   subscription_credits_remainingzSubscription credits: purchased_credits_remainingzTop-up credits: total_usable_creditszTotal usable: rollover_creditsz
Rollover: current_period_endzRenews: paid_service_access-   Status: access depleted — top up to restorezTop up: z(or run /topup)r-   nouszportal-accountNous credits)r)   r*   r+   r,   r-   r.   r0   )hermes_cli.nous_accountr   getattrr   rm   minrl   r   rz   r(   r   tupleAttributeError	TypeError)account_infor   accesssubr.   r0   r   sub_remainingru   used_pctsub_credits	purchasedtotal_usablerollover
period_endpaidr-   s                    r   build_nous_credits_snapshotr      s   SAw|[%'P'A4HlND9,. ?%c+<dCO#C)<dCM/#a'"=1!_4&6sCto/E/M$NO&,%-"*="9!:$x?X>YY^_ !&*JDQKk*!78M7NOP(EtLIi(!1(92E1FGH"6+A4HLl+0F/GHI?s$6=Hh'HqLHX,>+?@A &:DAJ*67|%:DA5=NNJKw"7"E!FGH()-0_wsFD)$##z 'N'N
 	
 I& s   I GI /A'I I)(I)      $@)rh   timeoutc                ^   	 ddl m}  |       }|t        |      }t	        ||       S 	 ddlm}  |d      xs i j                  d      }t        |t              r|j                         sg S 	 	 ddl}ddlm} |j                  j                  d	
      5 }	|	j!                  |d      j#                  |      }
ddd       t%        
      }t	        ||       S # t        $ r d}Y w xY w# t        $ r g cY S w xY w# 1 sw Y   CxY w# t        $ r t&        j)                  dd       g cY S w xY w)a  Return rendered Nous-credits /usage lines, or [] when there's nothing to show.

    Account-independent of any live agent: gated on "a Nous account is logged in"
    (a cheap local auth-state check), then a wall-clock-bounded portal fetch. Shared
    by the CLI ``_show_usage`` and the TUI ``session.usage`` RPC so both surfaces show
    the same block regardless of session API-call count or resume state. Fail-open:
    any auth/portal hiccup or timeout returns [] (the caller shows nothing).

    Dev override: when HERMES_DEV_CREDITS_FIXTURE selects a fixture state, /usage
    renders from that fixture instead of the real portal (so the block + gauge are
    testable without a live account). Throwaway scaffolding.
    r   )dev_fixture_credits_stateNrg   get_provider_auth_stater   access_token)get_nous_portal_account_info   max_workersTforce_freshr   u9   credits ▸ /usage portal fetch/render failed (fail-open)exc_info)agent.credits_trackerr   	Exception_snapshot_from_credits_staterv   hermes_cli.authr   getrI   r   r?   concurrent.futuresr   r   futuresThreadPoolExecutorsubmitresultr   loggerdebug)rh   r   r   fixturero   r   tok
concurrentr   poolaccounts              r   nous_credits_linesr      s<   C+- /8)(XFF;&v.4"99.I3$I *5!H22q2A 	&Tkk,$ " fWf% 	& /w7)(XFF1    		& 	&   	P[_`		sM   C AC* /&D $C;9D C'&C'*C87C8;D D "D,+D,c                   	 | yg }g }t        | dd      }t        |t        t        f      rrt	        j
                  |      r]t        | dd      }t        | dd      }d}|r|r	d| d| d}|j                  t        dt        d	t        d
|d
z              |             t        | dd      }|r|j                  d|        t        | dd      }|r|j                  d|        t        | dd      }|r|j                  d|        t        | dd      du r|j                  d       |s|sy|j                  d       t        ddt               dt        |      t        |            S # t        t        f$ r Y yw xY w)u  Map a header-shaped CreditsState (e.g. a dev fixture) to the /usage snapshot.

    Renders the same magnitudes + monthly-grant % window the portal path produces,
    so HERMES_DEV_CREDITS_FIXTURE can exercise /usage without a live account. The
    *_usd strings are mock display values here (not server balance to compute on);
    the % comes from CreditsState.used_fraction (micros math). Fail-open → None.
    Nused_fractionsubscription_limit_usdsubscription_usdrx    of $r   r   r   r   r   zSubscription credits: $purchased_usdzTop-up credits: $remaining_usdzTotal usable: $paid_accessTFr   u,   (dev fixture — HERMES_DEV_CREDITS_FIXTURE)r   zdev-fixturer   )r)   r*   r+   r,   r.   r0   )r   rI   rJ   rK   r|   r}   rl   r   rm   r   r(   r   r   r   r   )	stater.   r0   ufcap_usdsub_usdr"   r   r   s	            r   r   r     s   /=,.UOT2b3,'DMM",=e%=tDGe%7>GF7WIU7)59NN"(!$S#eR%Z*@!A! %!3T:NN4WI>?=NN.}o>?=NN_]O<=5-.%7NNJKwEF# z 'N'N
 	
 I& s   E( D&E( ,;E( (E:9E:c                  T    e Zd ZU dZded<   dZded<   dZded	<   dZded
<   dZded<   y)CreditsViewuO  Surface-agnostic data for the ``/topup`` balance view.

    One portal fetch, one parse — consumed identically by the CLI panel, the
    gateway button, and any other money surface. Fail-open: when not logged in
    or the portal is unreachable, ``logged_in`` is False / ``topup_url`` is None
    and callers degrade gracefully.
    r3   r   r   r/   balance_linesNr!   identity_line	topup_urlFdepleted)	r#   r$   r%   __doc__r&   r   r   r   r   r   r   r   r   r   U  s6     O%'M?'#'M='#I}#Hdr   r   c                   t        d      }	 ddlm}  |d      xs i j                  d      }t	        |t
              r|j                         s|S 	 	 ddl}ddl	m
}m} |j                  j                  d	
      5 }|j                  |d      j                  |      }	ddd       	t%        |	dd      s|S t'        |	      }
g }|
Zt)        |
|       }|D cg c]B  }|j+                         j-                  d      s!|j+                         j-                  d      s|D }}t%        |	dd      }t%        |	dd      }g }|r|j/                  t        |             |r|j/                  d|        |rddj1                  |      z   nd}t        dt3        |      | ||	      t%        |	dd      du       S # t        $ r |cY S w xY w# 1 sw Y   'xY w# t        $ r t         j#                  dd       |cY S w xY wc c}w )u  Build the /topup balance view: balance block + identity line + top-up URL.

    Reuses the same account fetch + snapshot + URL builder as the /usage credits
    block, so the numbers always match. The balance block is the rendered
    snapshot MINUS its trailing top-up/command-hint lines (the /topup surface
    supplies its own affordance). Fail-open → ``CreditsView(logged_in=False)``.
    F)r   r   r   r   r   N)r   r   r   r   Tr   r   u2   credits ▸ /topup portal fetch failed (fail-open)r   r   rg   zTop up:z(or runemailorg_namezorg zTopping up as  / r   )r   r   r   r   r   )r   r   r   r   rI   r   r?   r   r   r   r   r   r   r   r   r   r   r   r   r   rv   lstrip
startswithrl   joinr   )rh   r   not_logged_inr   r   r   r   r   r   r   ro   r   renderedliner   r   whor   s                     r   build_credits_viewr   f  s     %0M;&v.4"99.I3$   *5
!	

 22q2A 	Tkk">DkQXX Y G	 gg{EB*73H  "M-hJ !
;;=++I6KKM,,Y7 
 
 GWd+Ew
D1HC

3u:

T($%<?%

37TMM*#'0"7>%G ]  	 	  ITXY
sC   AF3 (G ;$GG AG93G GG	G "G65G6c                    | xs dj                         j                  d      }|sd}|j                  d      r|dt        d        }|d|v rdndz   }|d	z   |d
z   |dz   fS )a  Resolve the Codex backend endpoints (usage, reset-credits list, consume).

    Mirrors the Codex CLI's PathStyle split (codex-rs backend-client): base URLs
    containing ``/backend-api`` use the ChatGPT ``/wham/...`` paths; everything
    else uses ``/api/codex/...``.
    r;   /z%https://chatgpt.com/backend-api/codexz/codexNz/backend-apiz/whamz
/api/codexz/usagez/rate-limit-reset-creditsz!/rate-limit-reset-credits/consume)r?   rstriprM   len)base_url
normalizedprefixs      r   _codex_backend_urlsr     s     .b'')005J<
8$ 03x=.1
n
&B7UF,,44 r   c                    t        |       d   S )Nr   )r   )r   s    r   _resolve_codex_usage_urlr     s    x(++r   c                   t        |xs d      j                         }|r |t        | xs d      j                         dfS 	 t        d      }d}	 t               }|j	                  d      xs i }t        |j	                  dd      xs d      j                         xs d}|d	   t        |j	                  d
d      xs d      j                         |fS # t
        $ r t        j                  dd       Y Uw xY w# t
        $ r t        j                  dd       Y nw xY wddlm	}  |d      }|j                         }	|	t        d      |	j                  t        |	j                  xs | xs d      j                         dfS )aL  Resolve Codex quota credentials from the native runtime path.

    Prefer explicit live-agent credentials, then the legacy singleton OAuth
    state, then the credential pool.  Hermes's native OAuth setup now stores
    device-code logins in the pool, so quota diagnostics must not depend only
    on the older singleton store.
    r;   NT)refresh_if_expiringtokens
account_idu5   codex ▸ /usage account_id read failed (best-effort)r   api_keyr   u@   codex ▸ /usage runtime resolver returned no creds; trying poolr   )	load_poolopenai-codexz7No available openai-codex credential in credential pool)r   r?   r   r   r   r   r   r   agent.credential_poolr   selectRuntimeErrorruntime_api_keyruntime_base_url)
r   r   explicit_keycredsr   
token_datar   r   r   entrys
             r    _resolve_codex_usage_credentialsr    ss    w}"%++-LSR0668$>>"h1dK$(
	a+-J^^H-3FVZZb9?R@FFHPDJ YUYYz2%>%D"!E!K!K!MzYY  	aLLP[_L`	a  hWbfgh 0^$DKKME}TUU  #e&<&<&N&NB"O"U"U"WY]]]s7   C9 AC  2C9  C63C9 5C66C9 9 DDc                   t        | |      \  }}}d| ddd}|r||d<   t        j                  d      5 }|j                  t	        |      |      }|j                          d d d        j                         xs i }|j                  d	      xs i }	g }
d
D ]l  \  }}|	j                  |      xs i }|j                  d      }|/|
j                  t        |t        |      t        |j                  d                         n g }|j                  d      xs i }|j                  d      }t        |t        t        f      r:t        |      dkD  r,t        |      }|dk7  rdnd}|j                  d| d| d       |j                  d      xs i }|j                  d      rh|j                  d      }t        |t        t        f      r|j                  dt        |      d       n"|j                  d      r|j                  d       t        ddt               t        |j                  d             t!        |
      t!        |      !      S # 1 sw Y   xY w)"NBearer application/json	codex-cliAuthorizationAccept
User-AgentChatGPT-Account-Id      .@r   headers
rate_limit))primary_windowSession)secondary_windowWeeklyr   r    r   r   r    rate_limit_reset_creditsavailable_countr   r   sr;   z	You have  resetz& banked - use /usage reset to activatecreditshas_creditsbalanceCredits balance: $.2f	unlimitedzCredits balance: unlimitedr   	usage_api	plan_type)r)   r*   r+   r-   r.   r0   )r  httpxClientr   r   raise_for_statusjsonrl   r   rK   rR   rI   rJ   r(   r   rC   r   )r   r   tokenresolved_base_urlr   r  clientresponsepayloadr  r.   keyr   rr   ru   r0   reset_creditsbankedcountpluralr  r  s                         r   _fetch_codex_account_usager/    sA    ,LHV]+^(Ej"5'*$!G
 (2$%	d	# $v::67HISZ:[!!#$ mmo#G\*0bJ(*GU 

U$*zz.)<"4["6::j#9:	

 GKK :;ArM01F&3,'CK!OF
wfVH,RS	
 kk)$*G{{=!++i(gU|,NN/gs/CDE[[%NN78:gkk+67gg E$ $s   -IIc                  T    e Zd ZU dZded<   ded<   dZded<   dZded<   edd	       Zy
)CodexResetRedeemResultz>Outcome of a `/usage reset` attempt against the Codex backend.r   statusmessager   rJ   r  windows_resetc                     | j                   dk(  S )Nreset)r2  r4   s    r   redeemedzCodexResetRedeemResult.redeemed@  s    {{g%%r   Nr7   )	r#   r$   r%   r   r&   r  r4  r9   r7  r   r   r   r1  r1  6  s5    HKLOSM3& &r   r1  r   )r   r   forcec                ,   ddl }	 t        | |      \  }}}t	        |      \  }}}	d| ddd	}
|r||
d
<   	 t        j                  d      5 }|j                  ||
      }|j                          |j                         xs i }|j                  d      xs i }|j                  d      }t        |t        t        f      rt        |      nd}|dk  rt        dd      cddd       S |j                  d      xs i }d}dD ]V  }|j                  |      xs i j                  d      }t        |t        t        f      s>t        |xs dt        |            }X |duxr	 |t        k\  }|s7|s5|d|ddnd}|dk7  rdnd}t        dd| d| d | d!|"      cddd       S |j                  |	i |
d#did$t!        |j#                               i%      }|j                          |j                         xs i }ddd       t!        j                  d,d      xs d      j+                         j-                         }|j                  d-      }t        |t        t        f      rt        |      nd}t        ddz
        }|dk7  rdnd}|d.k(  rt        d.d/| d0| d1||2      S |d3k(  rt        d3d4|"      S |d5k(  rt        d5d6      S |d7k(  rt        d7d8|"      S t        dd9|      S # t        $ r t        dd      cY S w xY w# 1 sw Y   xY w# t
        j$                  $ rK}|j&                  j(                  }|d&v rt        dd'| d(      cY d}~S t        dd)| d*      cY d}~S d}~wt        $ r}t        dd+|       cY d}~S d}~ww xY w):u  Redeem one banked Codex rate-limit reset credit (`/usage reset`).

    Flow (mirrors the Codex CLI's reset-credits picker, codex-rs
    ``backend-client``):

    1. ``GET .../usage`` — read the current windows + banked credit count.
    2. Guard: zero banked credits → refuse. No window fully used and not
       ``force`` → refuse with a warning (a banked reset restores the WHOLE
       5h + weekly allowance; burning it early wastes it). The backend has
       the same protection (``nothing_to_reset`` doesn't consume the
       credit), but failing fast client-side gives a clearer message.
    3. ``POST .../rate-limit-reset-credits/consume`` with a fresh UUID
       idempotency key (``redeem_request_id``). No ``credit_id`` — the
       backend picks the next available credit, exactly like the CLI's
       default "Full reset" option.

    Never raises: every failure mode returns a ``CodexResetRedeemResult``
    with a user-renderable message.
    r   NunavailablezWNo Codex credentials available. Run `hermes auth` to sign in with your ChatGPT account.)r2  r3  r  r  r  r  r  r  r   r  r  r  no_credits_bankedu>   No banked reset credits on this account — nothing to redeem.r  )r  r  r   r   zyour busiest window is only z.0fz% usedz6your current usage could not be confirmed as exhaustedr   r  r;   not_exhaustedu   ⚠️ Not redeeming: zl. A banked reset restores your FULL 5h + weekly limits, so spending it now would waste most of it. You have r  z5 banked. Use `/usage reset --force` to redeem anyway.)r2  r3  r  Content-Typeredeem_request_id)r  r$  )i  i  z)Codex backend rejected the request (HTTP ur   ). Reset credits require ChatGPT-account (OAuth) auth — run `hermes auth` and sign in with your ChatGPT account.zCodex backend error (HTTP u   ) — try again shortly.z#Could not reach the Codex backend: coder4  r6  u:   ✅ Reset redeemed — your usage limits have been reset. z banked resetz remaining.)r2  r3  r  r4  nothing_to_resetu\   Backend reports nothing to reset — your limits aren't exhausted. The credit was NOT spent.	no_creditz:Backend reports no available reset credit on this account.already_redeemeduI   This redemption was already processed — no additional credit was spent.z,Unexpected response from the Codex backend: )uuidr  r   r1  r   r!  r"  r   r#  r$  rI   rJ   rK   rm   _CODEX_WINDOW_EXHAUSTED_PERCENTpostr   uuid4HTTPStatusErrorr(  status_coder?   lower)r   r   r8  rC  r%  r&  r   	usage_url_credits_urlconsume_urlr  r'  
usage_respr)  r+  	raw_countr6   r  
worst_usedr*  ru   	exhausted
usage_noter.  consume_respbodyexcr?  r4  rt   s                                 r   redeem_codex_reset_creditrU  K  sH   2 
/OPXZa/b, * ,??P+Q(I|["5'*$!G
 (2$%B
\\$' -	-6Iw?J'') oo'-2G#KK(BCIrM%))*;<I*4Ye*MISTIA~-.\-	- -	- !\28bJ*.J= E"s+1r66~FdS%L1!$Z%63d!DJE #$.`:A`3`IU "- 3:c2B&IQ 
 !*QB-*0 =$$-;fVH =GH
 %.	9-	- -	-N ";;G7GN4FG)3tzz|+<= ' L
 ))+$$&,"D[-	-F txx#)r*00288:DHH_-M*4]S%L*QC&WXMAy1}%INSFw%L+]6(+? &'
 	
 !!%%, &
 	
 {%P
 	
 !!%%_%
 	

 ">thG k  
% m
 	

-	- -	-\    
||'':)$?f OO  & 06NO
 	
  
% 9#?
 	

s   K+ L BL	L (AL?AL	L "AL9L +LLLL N'*M-NM-'N-N9NNNc                 (   t               xs dj                         } | sy t        |       st        ddt	               d      S d|  dddd	d
}t        j                  d      5 }|j                  d|      }|j                          d d d        j                         xs i }g }d}|D ]  \  }}|j                  |      xs i }	|	j                  d      }
|
/t        |
      dk  rt        |
      dz  n
t        |
      }|j                  t        ||t        |	j                  d                          g }|j                  d      xs i }|j                  d      r|j                  d      }|j                  d      }|j                  d      xs d}t        |t        t        f      r2t        |t        t        f      r|j                  d|dd|dd|        t        ddt	               t!        |      t!        |            S # 1 sw Y   xY w) Nr;   	anthropicoauth_usage_apizMAnthropic account limits are only available for OAuth-backed Claude accounts.)r)   r*   r+   r1   r  r  zoauth-2025-04-20zclaude-code/2.1.0)r  r	  r=  zanthropic-betar
  r  r   z)https://api.anthropic.com/api/oauth/usager  ))	five_hourzCurrent session)	seven_dayzCurrent week)seven_day_opusz	Opus week)seven_day_sonnetzSonnet weekutilizationr   rj   	resets_atr  extra_usage
is_enabledused_creditsmonthly_limitcurrencyUSDzExtra usage: r  r   r=   r)   r*   r+   r.   r0   )r   r?   r
   r(   r   r!  r"  r   r#  r$  rK   rl   r   rR   rI   rJ   r   )r%  r  r'  r(  r)  r.   mappingr*  r   rr   utilru   r0   extrara  rb  rc  s                    r   _fetch_anthropic_account_usageri    s   $&,"335E5!# $zn	
 	
 #5'*$*,)G 
d	# $v::ISZ:[!!#$ mmo#G(*GG  

US!'Rzz-(<$)$K1$4uT{S %+!"6::k#:;	

 GKK&,"Eyyyy0		/299Z(1ElS%L1jQTV[P\6]NNS1]34Gq
S   :gg E$ $s   #$HHc           	        t        d| |      }t        |j                  dd      xs d      j                         }|sy t        |j                  dd      xs d      j	                  d      }| d}| d}d	| d
d}t        j                  d      5 }|j                  ||      }	|	j                          |	j                         xs i j                  d      xs i }
	 |j                  ||      }|j                          |j                         xs i j                  d      xs i }d d d        t        
j                  d      xs d      }t        |
j                  d      xs d      }dt        d||z
        dg}g }j                  d      }|j                  d      }t        |j                  d      xs d      j                         }|j                  d      }t        |t        t        f      rt        |      dkD  rt        |t        t        f      rdt        |      cxk  rt        |      k  rrn not        |      }t        |      }||z
  |z  dz  }d|dd|ddg}|r|j                  d|        |j                  t        d|d j!                  |      !             t        |t        t        f      rd"t        |      dd#g}|j                  d$      d%f|j                  d&      d'f|j                  d(      d)ffD ]L  \  }}t        |t        t        f      st        |      dkD  s,|j                  dt        |      dd*|        N |j                  d j!                  |             t#        dd+t%               t'        |      t'        |      ,      S # t        $ r i }Y w xY w# 1 sw Y   xY w)-N
openrouter)	requestedexplicit_base_urlexplicit_api_keyr   r;   r   r   z/creditsz/keyr  r  )r  r	  r   r   r  datatotal_creditsr   total_usager  r  limitlimit_remaininglimit_resetusager   rj   rx   r   z
 remainingzresets zAPI key quotark   r   zAPI key usage: $z totalusage_dailytodayusage_weeklyz	this weekusage_monthlyz
this monthr=   credits_apire  )r   r   r   r?   r   r!  r"  r#  r$  r   rK   rm   rI   rJ   rl   r   r   r(   r   r   )r   r   runtimer%  r   credits_urlkey_urlr  r'  credits_respr  key_respkey_datarp  rq  r0   r.   rr  rs  rt  ru  limit_valueremaining_valuer   detail_partsusage_partsrA   r   s                               r   _fetch_openrouter_account_usager     s   &" G
 Ir*0b1779EW[[R06B7>>sCJL)KD!G"5'*$G 
d	# 	vzz+wz?%%'$$&,"11&9?R	zz'7z;H%%' -2226:@bH	 '++o6=#>MM29c:K#C][-H$I##NOPG(*GLL!Ell#45Ohll=17R8>>@KLL!E53,'%L1e5'75<7El0$6+ELOC0k#5FjQR'+ 78%)||L1	
 %#u&)%,s);6BC\\-('2\\.);7\\/*L9
 	CLE5
 %#u.5<!3C""QuU|C&8%#AB	C 	w||K01:gg O  	H		 	s,   AN7!A
N%%N40N73N44N77Or   r   c                   t        | xs d      j                         j                         }|dv ry 	 |dk(  rt        ||      S |dk(  r
t	               S |dk(  rt        ||      S 	 y # t        $ r Y y w xY w)Nr;   >   r;   autocustomr   r  rW  rk  )r   r?   rI  r/  ri  r  r   )r)   r   r   r   s       r   fetch_account_usager  h  s     X^$**,224J++'-xQQ$133%28WEE &   s   A& A& A& &	A21A2)r8   r   )rA   r!   r8   r!   )rA   r   r8   r   )rQ   r   r8   r   )ro   Optional[AccountUsageSnapshot]rh   r3   r8   	list[str])ry   rK   r8   r   )r~   r   r8   zTypeGuard[float])r8   r  )rh   r3   r   rK   r8   r  )rh   r3   r   rK   r8   r   )r   r   r8   ztuple[str, str, str])r   r   r8   r   )r   r!   r   r!   r8   ztuple[str, str, Optional[str]])NN)r   r!   r   r!   r8   r  )r   r!   r   r!   r8  r3   r8   r1  )r)   r!   r   r!   r   r!   r8   r  )2
__future__r   loggingr|   dataclassesr   r   r   typingr   r   r	   r!  agent.anthropic_adapterr
   r   r   r   r   r   hermes_cli.runtime_providerr   r   	getLoggerr#   r   r   r   r(   rC   rR   rf   rv   rz   r   r   r   r   r   r   r   r   r  r/  r1  rD  rU  ri  r  r  r   r   r   <module>r     s   "   ! ' / /  L \ \ @ 			8	$& $! ! ! $R R R?&?( ^c 8X]@ ,14 /d7t $    ,14 CL(,7^7^7^ $7^v #!555 $5p $& & &" #( 
 #!	UU U 	U
 Up:zEV #!	  	
 $r   