Ë
    âß²j§.  ã                  ó  — U d Z ddlmZ ddlZddlmZmZmZ  ej                  e	«      Z
 eh d£«      ZdZ e«       Zded<   dd	„Zdd
„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zd d„Zd!d„Zd"d„Zd#d„Zd$d„Zd%d„Zd&d„Zd'd„Z y)(uÅ  Model-provider plugins as first-class citizens of ``hermes auth`` and the credential pool.

A ``plugins/model-providers/<name>/`` profile (``providers.base.ProviderProfile``) is mirrored into
``hermes_cli.auth.PROVIDER_REGISTRY`` with the ``auth_type`` it declares, so ``resolve_provider()``
accepts it whatever its auth shape. Non-api-key plugins own their login through two optional profile
callables that core consults BEFORE any built-in, name-keyed path:

- ``auth_handler(action, args) -> bool`` for ``hermes auth add|status|logout|refresh <name>``
  (``args`` is the parsed CLI namespace; truthy = the plugin owned the action, falsy = built-in path).
- ``refresh_credential(entry) -> Mapping | None`` for the credential pool: given the pooled
  ``PooledCredential`` it returns the rotated fields (``access_token``, ``refresh_token``,
  ``expires_at_ms`` â€¦) or raises. A separate hook rather than ``auth_handler("refresh", â€¦)`` because
  the pool has a credential row, not an argparse namespace, and needs tokens back, not a bool.

Every function here late-imports ``hermes_cli.auth`` names: this module is imported by the auth facade
right after ``PROVIDER_REGISTRY`` exists, and by ``agent.credential_pool``.
é    )ÚannotationsN)ÚAnyÚCallableÚOptional>   úkimi-codingúkimi-coding-cnÚzaiÚcustomÚcopilotÚ
openrouter)ÚaddÚstatusÚlogoutÚrefreshzset[str]ÚPLUGIN_MIRRORED_PROVIDERSc                ó¨   ‡— d„ Št        ˆfd„| j                  D «       «      xs | j                  t        ˆfd„| j                  D «       d«      xs dfS )zXSplit a profile's ``env_vars`` into (api-key vars, base-URL var); the URL var may be "".c                óJ   — | j                  d«      xs | j                  d«      S )NÚ	_BASE_URLÚ_URL)Úendswith)Úvs    úE/home/ubuntu/.hermes/hermes-agent/hermes_cli/auth_plugin_providers.pyú<lambda>z%_api_key_env_fields.<locals>.<lambda>(   s   € �q—z‘z +Ó.ÒD°!·*±*¸VÓ2D€ ó    c              3  ó4   •K  — | ]  } ‰|«      rŒ|–— Œ y ­w©N© ©Ú.0r   Úis_urls     €r   ú	<genexpr>z&_api_key_env_fields.<locals>.<genexpr>)   s   øè ø€ Ò:˜±°qµ	”!Ñ:ùó   ƒ‘c              3  ó4   •K  — | ]  } ‰|«      sŒ|–— Œ y ­wr   r   r   s     €r   r!   z&_api_key_env_fields.<locals>.<genexpr>*   s   øè ø€ Ò6˜©F°1­I”!Ñ6ùr"   NÚ )ÚtupleÚenv_varsÚnext)Úppr    s    @r   Ú_api_key_env_fieldsr)   &   sH   ø€ áD€FÜÓ:˜RŸ[™[Ô:Ó:ÒI¸b¿k¹kÜÓ6˜RŸ[™[Ô6¸Ó=ÒCÀðEð Er   c                óð  — ddl m}m}m} | j                  t
        v ry| j                  dk(  rN| j                  sy || j                  | j                  xs | j                  | j                  gt        | «      ¢­Ž }nB || j                  | j                  xs | j                  | j                  | j                  ¬«      }||| j                  <   t        j                  | j                  «       t        || «       y)a  Mirror one profile into ``PROVIDER_REGISTRY`` under the ``auth_type`` it declares.

    Registering is what lets an out-of-tree provider pass ``resolve_provider()``'s known-provider
    gate ("Unknown provider"); OAuth-shaped plugins carry their own login via ``auth_handler``.
    r   )ÚPROVIDER_REGISTRYÚProviderConfigÚ_api_key_providerNÚapi_key)Úinference_base_url)Úhermes_cli.authr+   r,   r-   ÚnameÚ_REGISTRY_PLUGIN_SKIPÚ	auth_typer&   Údisplay_nameÚbase_urlr)   r   r   Úmirror_aliases)r(   r+   r,   r-   Úpconfigs        r   Úregister_plugin_providerr8   -   s·   € ÷ UÑTà	‡w�wÔ'Ñ'ØØ	‡|�|�yÒ Ø�{Š{ØÙ# B§G¡G¨R¯_©_Ò-GÀÇÁÈÏÉÐoÔWjÐkmÓWnÒo‰á  §¡¨"¯/©/Ò*D¸R¿W¹WÀbÇlÁlÐgi×grÑgrÔsˆØ!(Ð�b—g‘gÑÜ×!Ñ! "§'¡'Ô*Ü�7˜BÕr   c                ó®   — 	 ddl m}m}  ||«      }|duxr0 |j                  | j                  k(  xr  || j                  «      dk(  S # t        $ r Y yw xY w)zZTrue when *alias* resolves to the ``$HERMES_HOME`` plugin *pp* in the ``providers`` layer.r   )Úget_provider_profileÚprovider_sourceFNÚuser)Ú	providersr:   r;   Ú	Exceptionr1   )r(   Úaliasr:   r;   Úowners        r   Ú_user_owns_aliasrA   B   s[   € ðßCñ ! Ó'€EØ˜ÐÒ] §¡¨r¯w©wÑ!6Ò]¹?È2Ï7É7Ó;SÐW]Ñ;]Ð]øô ò Ùðús   ‚A Á	AÁAc                ó^   — ddl m} |j                  D ]  }||vst        ||«      sŒ| ||<   Œ y)uÅ  Point ``pp.aliases`` at *pconfig* so ``resolve_provider()`` resolves them too.

    A bundled plugin never steals an alias another row already holds; a ``$HERMES_HOME`` plugin
    whose alias the ``providers`` layer already resolves to it does â€” the same ownership rule as
    :func:`override_registry_row`, otherwise the alias kept resolving to the built-in row while
    ``providers.get_provider_profile`` followed the user's profile (#116668).
    r   ©r+   N)r0   r+   ÚaliasesrA   )r7   r(   r+   r?   s       r   r6   r6   L   s8   € õ 2à—‘ò /ˆØÐ)Ñ)Ô-=¸bÀ%Õ-HØ'.Ð˜eÒ$ñ/r   c                ó  — |j                   r|j                   | _        |j                  r|j                  | _        |j                  dcxk(  r| j                  k(  r.n y|j
                  rt        |«      \  | _        }|r|| _        yyyy)u�  A ``$HERMES_HOME`` plugin re-registering a name that already has a row wins for the fields
    it declares â€” ``display_name``, ``base_url`` and, on api-key rows, ``env_vars`` (#48450, #116668). ``register_provider()``
    is last-writer-wins for the profile; without this the runtime kept reading the built-in
    endpoint. In place, so alias rows sharing the object follow; idempotent, so re-sync is free.
    r.   N)	r4   r1   r5   r/   r3   r&   r)   Úapi_key_env_varsÚbase_url_env_var)r7   r(   Úurl_vars      r   Úoverride_registry_rowrI   [   sq   € ð 
‡‚Ø—‘ˆŒØ	‡{‚{Ø%'§[¡[ˆÔ"Ø	‡|�|�yÔ5 G×$5Ñ$5Õ5¸"¿+º+Ü,?ÀÓ,CÑ)ˆÔ  'ÙØ'.ˆGÕ$ð ð ;FÐ5r   c                 ó¶  — ddl m} m} 	 ddlm}m}  |«       }d}|D ]ª  }|j                  |v r~|j                  | v xs |j                  t        v }|rY|j                  t        vrG ||j                  «      dk(  r2t        ||j                     |«       t        ||j                     |«       Œ�t        |«       ||j                  |v z  }Œ¬ |S # t        $ r Y yw xY w)uÕ  Mirror provider-plugin profiles into ``PROVIDER_REGISTRY``; return how many were added.

    Idempotent (existing entries are never replaced â€” a user plugin re-registering a bundled name
    only rewrites the fields it declares, see :func:`override_registry_row`), so it is safe from
    resolution paths. It runs at
    auth import and again whenever a name is missing (:func:`registry_lookup`) or when ``providers``
    finishes discovery, because the import-time pass can observe a *partial* profile list: a plugin
    whose own imports pull ``hermes_cli.auth`` in mid-``_discover_providers()`` sees only what was
    registered so far, and every later plugin would otherwise fail with "Unknown provider" (#102123).
    r   )ÚBUILTIN_PROVIDER_IDSr+   )Úlist_providersr;   r<   )r0   rK   r+   r=   rL   r;   r>   r1   r   r2   rI   r6   r8   )rK   r+   rL   r;   ÚprofilesÚaddedr(   Úcore_rows           r   Úsync_plugin_provider_registryrP   k   sà   € ÷ Hðß=Ù!Ó#ˆð €EØò 
.ˆØ�7‰7Ð'Ñ'ð —w‘wÐ"6Ð6Ò^¸"¿'¹'ÔE^Ð:^ˆHÙ˜BŸG™GÔ+@Ñ@Á_ÐUW×U\ÑU\ÓE]ÐagÒEgÜ%Ð&7¸¿¹Ñ&@À"ÔEÜÐ0°·±Ñ9¸2Ô>ØÜ  Ô$Ø�—‘Ð-Ð-Ñ-‰ð
.ð €Løô ò Ùðús   ŠC Ã	CÃCc                ón   — ddl m} |j                  | «      }|€t        «       r|j                  | «      }|S )zB``PROVIDER_REGISTRY.get`` that re-syncs plugin profiles on a miss.r   rC   )r0   r+   ÚgetrP   )Úprovider_idr+   r7   s      r   Úregistry_lookuprT   Œ   s5   € å1à×#Ñ# KÓ0€GØ€Ô8Ô:Ø#×'Ñ'¨Ó4ˆØ€Nr   c                ó>   — 	 ddl m}  || «      S # t        $ r Y yw xY w)z`The registered ``ProviderProfile`` for *provider*, or None (also when the layer is unavailable).r   )r:   N)r=   r:   r>   )Úproviderr:   s     r   Úplugin_profilerW   –   s+   € ðÝ2ñ   Ó)Ð)øô ò Ùðús   ‚ �	›c                óL   — t        t        | «      |d «      }t        |«      r|S d S r   )ÚgetattrrW   Úcallable)rV   r1   Úhooks      r   Ú_profile_hookr\   Ÿ   s&   € Ü”> (Ó+¨T°4Ó8€DÜ˜D”>ˆ4Ð+ tÐ+r   c                ó   — t        | d«      S )NÚauth_handler©r\   ©rV   s    r   Úplugin_auth_handlerra   ¤   s   € Ü˜ >Ó2Ð2r   c                ó   — t        | d«      S )z^The profile's ``refresh_credential`` hook, i.e. whether its pooled OAuth rows are refreshable.Úrefresh_credentialr_   r`   s    r   Úplugin_refresh_hookrd   ¨   s   € ä˜Ð#7Ó8Ð8r   c                ó4   — ddl m} | |v xs t        | «      duS )zMBuilt-in refreshable set OR a plugin profile shipping ``refresh_credential``.r   )ÚREFRESHABLE_OAUTH_PROVIDERSN)Úagent.credential_poolrf   rd   )rV   rf   s     r   Úis_refreshable_oauth_providerrh   ­   s"   € åAàÐ2Ð2Ò_Ô6IÈ(Ó6SÐ[_Ð6_Ð_r   c           
     óÌ   — t        |«      }|€y	 t         || |«      «      S # t        $ r ‚ t        $ r/}t        |› d| › dt	        |«      j
                  › d|› �«      |‚d}~ww xY w)a  Offer ``hermes auth <action> <provider>`` to the provider's ``auth_handler``.

    True = the plugin owned the action (core prints nothing more). False = run the built-in path. A
    handler exception becomes a readable ``SystemExit`` naming provider and action.
    NFz auth handler failed for `z`: z: )ra   ÚboolÚ
SystemExitr>   ÚtypeÚ__name__)ÚactionÚargsrV   ÚhandlerÚexcs        r   Údispatch_plugin_authrr   ´   s€   € ô " (Ó+€GØ€ØðqÜ‘G˜F DÓ)Ó*Ð*øÜò ØÜò qÜ˜H˜:Ð%?À¸xÀsÌ4ÐPSË9×K]ÑK]ÐJ^Ð^`ÐadÐ`eÐfÓgÐmpÐpûðqús   �" ¢A#´*AÁA#c                ó¨   — | t         vryt        | «      }|�|j                  dk(  st        | «      �yt	        d| › d|j                  › d|› d| › d�	«      S )a  Fail loud for a registered non-api-key plugin that ships no ``auth_handler``.

    Its login is not something core can perform (there is no token endpoint to call), and silently
    running the api-key prompt or reporting "Unknown provider" both hide the plugin bug.
    Nr.   z
Provider 'z' declares auth_type 'z8' but its plugin ships no auth_handler, so `hermes auth ú zf` cannot be handled. Add `auth_handler=` to its ProviderProfile (see the model-provider plugin guide).)r   rW   r3   ra   rk   )rV   rn   Úprofiles      r   Ú!plugin_missing_auth_handler_errorrv   Å   s|   € ð Ô0Ñ0ØÜ˜XÓ&€GØ€˜'×+Ñ+¨yÒ8Ô<OÐPXÓ<YÐ<eØÜØ
�X�JÐ4°W×5FÑ5FÐ4Gð H)Ø)/¨°°(°ð <Xð	XóYð Yr   c                ó  — ddl }ddlm} | j                  �2t	        | j                  «      t	        |j                  «       dz  «      k  S | j
                  r+ || j
                  «      }|duxr ||j                  «       k  S y)z]A pooled OAuth row is expired when its ``expires_at_ms`` / ISO ``expires_at`` is in the past.r   N)Ú_parse_iso_timestampiè  F)Útimer0   rx   Úexpires_at_msÚintÚ
expires_at)Úentryry   rx   Úepochs       r   Ú_pool_entry_expiredr   Ö   sq   € ãÝ4à×ÑÐ&Ü�5×&Ñ&Ó'¬3¨t¯y©y«{¸TÑ/AÓ+BÑBÐBØ×ÒÙ$ U×%5Ñ%5Ó6ˆØ˜DÐ Ò9 U¨d¯i©i«kÑ%9Ð9Ør   c           
     ó   — | t         vrddiS ddlm}  || «      j                  «       D �cg c]1  }|j                  xs |j
                  xs dj                  «       sŒ0|‘Œ3 }}|D �cg c]  }t        |«      rŒ|‘Œ }}|s(t        | «      r|D �cg c]  }|j                  sŒ|‘Œ c}ng }d| t        |«      t        |«      t        |«      t        d„ ||z   D «       d«      xs d|rdd
œS d| › d	�d
œS c c}w c c}w c c}w )uí  Status for an OAuth-shaped PLUGIN provider, read from the credential pool its ``auth_handler`` fills.

    ``configured`` = the profile is registered; ``logged_in`` = a pool row carries a live token;
    ``needs_refresh`` = every token is expired but refresh material (and a ``refresh_credential`` hook)
    exists. Bundled OAuth providers keep their bespoke builders (``_BESPOKE_STATUS_FUNCTIONS``) â€” this
    one is gated on the plugin-mirrored set so their status bytes never change.
    Ú	logged_inFr   )Ú	load_poolr$   Tc              3  óN   K  — | ]  }|j                   sŒ|j                   –— Œ y ­wr   )r5   )r   Úes     r   r!   z/get_plugin_oauth_auth_status.<locals>.<genexpr>õ   s   è ø€ ÒO¨ÀAÇJÃJ˜!Ÿ*�*ÑOùs   ‚%”%zRun `hermes auth add z` to sign in.)Ú
configuredrV   r�   Úneeds_refreshÚaccountsr5   Úhint)r   rg   r‚   ÚentriesÚaccess_tokenÚ	agent_keyÚstripr   rd   Úrefresh_tokenrj   Úlenr'   )rS   r‚   r„   r‰   ÚliveÚrefreshables         r   Úget_plugin_oauth_auth_statusr‘   ã   s  € ð Ô3Ñ3Ø˜UÐ#Ð#Ý/á# KÓ0×8Ñ8Ó:Öl�Q¸q¿~¹~Ò?bÐQR×Q\ÑQ\Ò?bÐ`b×>iÑ>iÕ>kŠqÐl€GÐlØÖ=�!Ô&9¸!Õ&<ŠAÐ=€DÐ=ÙAEÔJ]Ð^iÔJj˜gÖ9˜¨¯«’1Ó9Ðpr€Kà¨Ä$ÀtÃ*Ü˜kÓ*¼¸G»ÜÑO¨d°[Ñ.@ÔOÐQSÓTÒZÐXZÙ�ñ	Tð Tð #8¸°}ÀMÐ Rñ	Tð Tùò mùÚ=ùÚ9s#   «1C1ÁC1Á'C6Á8C6ÂC;Â!C;)r(   r   Úreturnztuple[tuple, str])r(   r   r’   ÚNone)r(   r   r?   Ústrr’   rj   )r7   r   r(   r   r’   r“   )r’   r{   )rS   r”   r’   úOptional[Any])rV   r”   r’   r•   )rV   r”   r1   r”   r’   zOptional[Callable[..., Any]])rV   r”   r’   z#Optional[Callable[[str, Any], Any]])rV   r”   r’   zOptional[Callable[[Any], Any]])rV   r”   r’   rj   )rn   r”   ro   r   rV   r”   r’   rj   )rV   r”   rn   r”   r’   zOptional[SystemExit])r}   r   r’   rj   )rS   r”   r’   zdict[str, Any])!Ú__doc__Ú
__future__r   ÚloggingÚtypingr   r   r   Ú	getLoggerrm   ÚloggerÚ	frozensetr2   ÚPLUGIN_AUTH_ACTIONSÚsetr   Ú__annotations__r)   r8   rA   r6   rI   rP   rT   rW   r\   ra   rd   rh   rr   rv   r   r‘   r   r   r   ú<module>r       s¤   ðòõ" #ã ß *Ñ *à	ˆ×	Ñ	˜8Ó	$€ñ
 "Ò"mÓnÐ à<Ð ñ
 '*£eÐ ˜8Ó +óEó ó*^ó/ó/ó óBó*ó,ó
3ó9ó
`óqó"Yó"
ôTr   