mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
/config (cli.py show_config) and the agent's key banner (_print_key_banner) printed "Microsoft Entra ID" for every callable api_key, so a custom provider's key_cmd bearer or MiniMax OAuth read as Azure. /config also picked Vertex out with a __module__ string compare, and the banner had no Vertex case at all. Each builder now tags the callable it returns with a source (agent/credential_source.py): build_token_provider -> entra-id, vertex_access_token -> vertex-oauth, CommandTokenSource -> key-cmd, build_minimax_oauth_token_provider -> minimax-oauth. Both surfaces resolve the label through one source-to-label table. An untagged callable gets the neutral "Token provider" label. The tag is read with getattr, so no display path calls the callable (no token minted just to mask it). New catalog keys key_cmd_token, minimax_oauth and token_provider in every locale (English text, matching the brand-name convention of the existing microsoft_entra_id / google_vertex_oauth keys). Tests: tests/agent/test_credential_source_labels.py, one red/green case per label on each surface (7 red before: key_cmd/minimax/unknown on /config, vertex/key_cmd/minimax/unknown on the banner). Each case's callable raises if invoked. The old "any other callable is Entra" pin now uses a real Entra-tagged provider. Review finding by @unsupportedpastels on #140469 Review finding by @alt-glitch on #140469 Refs #134889 (T6) Refs #140337
58 lines
2.1 KiB
Python
58 lines
2.1 KiB
Python
"""Name a callable API key's credential source without calling it.
|
|
|
|
A callable ``api_key`` mints a bearer on first use (Entra ID, Vertex OAuth, a custom provider's
|
|
``key_cmd``, MiniMax OAuth). Display paths (``/config``, the agent's key banner) must say which
|
|
kind it is, but calling it would mint a token just to mask it. Each builder tags the callable it
|
|
returns with a source; display reads the tag through one source-to-label table. An untagged
|
|
callable gets a neutral label, never another vendor's name.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Callable, Optional, TypeVar
|
|
|
|
ENTRA_ID = "entra-id"
|
|
VERTEX_OAUTH = "vertex-oauth"
|
|
KEY_CMD = "key-cmd"
|
|
MINIMAX_OAUTH = "minimax-oauth"
|
|
|
|
# Attribute read with getattr only: reading it never invokes the callable.
|
|
SOURCE_ATTR = "hermes_credential_source"
|
|
|
|
# Credential source -> i18n key. Both display surfaces resolve labels here.
|
|
SOURCE_LABEL_KEYS = {
|
|
ENTRA_ID: "cli.config.microsoft_entra_id",
|
|
VERTEX_OAUTH: "cli.config.google_vertex_oauth",
|
|
KEY_CMD: "cli.config.key_cmd_token",
|
|
MINIMAX_OAUTH: "cli.config.minimax_oauth",
|
|
}
|
|
UNKNOWN_LABEL_KEY = "cli.config.token_provider"
|
|
|
|
_F = TypeVar("_F", bound=Callable[..., Any])
|
|
|
|
|
|
def tag_credential_source(provider: _F, source: str) -> _F:
|
|
"""Record *source* on *provider* and return it (a no-op for objects that refuse attributes)."""
|
|
try:
|
|
setattr(provider, SOURCE_ATTR, source)
|
|
except (AttributeError, TypeError):
|
|
pass
|
|
return provider
|
|
|
|
|
|
def credential_source(key: Any) -> Optional[str]:
|
|
"""The source tag of a callable key, or None (string keys and untagged callables)."""
|
|
if isinstance(key, str) or not callable(key):
|
|
return None
|
|
source = getattr(key, SOURCE_ATTR, None)
|
|
return source if isinstance(source, str) else None
|
|
|
|
|
|
def credential_label(key: Any) -> Optional[str]:
|
|
"""Translated label for a callable key's source (neutral when untagged); None for a non-callable."""
|
|
if isinstance(key, str) or not callable(key):
|
|
return None
|
|
from agent.i18n import t
|
|
|
|
return t(SOURCE_LABEL_KEYS.get(credential_source(key) or "", UNKNOWN_LABEL_KEY))
|