mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
Merge df3b55e4f0 into fd10463069
This commit is contained in:
commit
e9fd9f6109
5 changed files with 100 additions and 0 deletions
|
|
@ -182,6 +182,14 @@ PROVIDER_REGISTRY: Dict[str, ProviderConfig] = {
|
|||
api_key_env_vars=("GOOGLE_API_KEY", "GEMINI_API_KEY"),
|
||||
base_url_env_var="GEMINI_BASE_URL",
|
||||
),
|
||||
"ppq": ProviderConfig(
|
||||
id="ppq",
|
||||
name="PPQ (PayPerQ)",
|
||||
auth_type="api_key",
|
||||
inference_base_url="https://api.ppq.ai",
|
||||
api_key_env_vars=("PPQ_API_KEY",),
|
||||
base_url_env_var="PPQ_BASE_URL",
|
||||
),
|
||||
"zai": ProviderConfig(
|
||||
id="zai",
|
||||
name="Z.AI / GLM",
|
||||
|
|
@ -1090,6 +1098,7 @@ def resolve_provider(
|
|||
# Normalize provider aliases
|
||||
_PROVIDER_ALIASES = {
|
||||
"glm": "zai", "z-ai": "zai", "z.ai": "zai", "zhipu": "zai",
|
||||
"payperq": "ppq", "ppq.ai": "ppq",
|
||||
"google": "gemini", "google-gemini": "gemini", "google-ai-studio": "gemini",
|
||||
"x-ai": "xai", "x.ai": "xai", "grok": "xai",
|
||||
"kimi": "kimi-coding", "kimi-for-coding": "kimi-coding", "moonshot": "kimi-coding",
|
||||
|
|
|
|||
|
|
@ -177,6 +177,40 @@ _PROVIDER_MODELS: dict[str, list[str]] = {
|
|||
"gemini-2.5-pro",
|
||||
"grok-code-fast-1",
|
||||
],
|
||||
"ppq": [
|
||||
# Curated PPQ list — mirrors the OpenRouter selection using PPQ's native IDs.
|
||||
# PPQ uses shorter IDs for some providers (e.g. claude-opus-4.7 vs anthropic/claude-opus-4.7).
|
||||
# Verified against live /v1/models catalog (329 models as of 2026-04-18).
|
||||
"claude-opus-4.7",
|
||||
"anthropic/claude-opus-4.6",
|
||||
"claude-sonnet-4.6",
|
||||
"qwen/qwen3.6-plus",
|
||||
"anthropic/claude-sonnet-4.5",
|
||||
"claude-haiku-4.5",
|
||||
"gpt-5.4",
|
||||
"gpt-5.4-mini",
|
||||
"gpt-5.4-pro",
|
||||
"gpt-5.4-nano",
|
||||
"gpt-5.3-codex",
|
||||
"google/gemini-3-pro-image-preview",
|
||||
"gemini-3-flash-preview",
|
||||
"google/gemini-3.1-pro-preview",
|
||||
"google/gemini-3.1-flash-lite-preview",
|
||||
"xiaomi/mimo-v2-pro",
|
||||
"z-ai/glm-5.1",
|
||||
"z-ai/glm-5-turbo",
|
||||
"z-ai/glm-5v-turbo",
|
||||
"moonshotai/kimi-k2.5",
|
||||
"minimax/minimax-m2.7",
|
||||
"minimax/minimax-m2.5",
|
||||
"qwen/qwen3.5-plus-02-15",
|
||||
"qwen/qwen3.5-35b-a3b",
|
||||
"stepfun/step-3.5-flash",
|
||||
"x-ai/grok-4.20",
|
||||
"nvidia/nemotron-3-super-120b-a12b",
|
||||
"arcee-ai/trinity-large-thinking",
|
||||
"arcee-ai/trinity-large-preview",
|
||||
],
|
||||
"gemini": [
|
||||
"gemini-3.1-pro-preview",
|
||||
"gemini-3-pro-preview",
|
||||
|
|
@ -725,6 +759,7 @@ CANONICAL_PROVIDERS: list[ProviderEntry] = [
|
|||
ProviderEntry("huggingface", "Hugging Face", "Hugging Face Inference Providers (20+ open models)"),
|
||||
ProviderEntry("gemini", "Google AI Studio", "Google AI Studio (Gemini models — native Gemini API)"),
|
||||
ProviderEntry("google-gemini-cli", "Google Gemini (OAuth)", "Google Gemini via OAuth + Code Assist (free tier supported; no API key needed)"),
|
||||
ProviderEntry("ppq", "PPQ (PayPerQ)", "PPQ (PayPerQ multi-provider gateway)"),
|
||||
ProviderEntry("deepseek", "DeepSeek", "DeepSeek (DeepSeek-V3, R1, coder — direct API)"),
|
||||
ProviderEntry("xai", "xAI", "xAI (Grok models — direct API)"),
|
||||
ProviderEntry("zai", "Z.AI / GLM", "Z.AI / GLM (Zhipu AI direct API)"),
|
||||
|
|
@ -752,6 +787,8 @@ _PROVIDER_ALIASES = {
|
|||
"z-ai": "zai",
|
||||
"z.ai": "zai",
|
||||
"zhipu": "zai",
|
||||
"payperq": "ppq",
|
||||
"ppq.ai": "ppq",
|
||||
"github": "copilot",
|
||||
"github-copilot": "copilot",
|
||||
"github-models": "copilot",
|
||||
|
|
@ -1748,6 +1785,20 @@ def provider_model_ids(provider: Optional[str], *, force_refresh: bool = False)
|
|||
return live
|
||||
except Exception:
|
||||
pass
|
||||
if normalized == "ppq":
|
||||
# Try live PPQ /v1/models endpoint
|
||||
try:
|
||||
from hermes_cli.auth import resolve_api_key_provider_credentials
|
||||
|
||||
creds = resolve_api_key_provider_credentials("ppq")
|
||||
api_key = str(creds.get("api_key") or "").strip()
|
||||
base_url = str(creds.get("base_url") or "").strip()
|
||||
if api_key and base_url:
|
||||
live = fetch_api_models(api_key, base_url)
|
||||
if live:
|
||||
return live
|
||||
except Exception:
|
||||
pass
|
||||
if normalized == "anthropic":
|
||||
live = _fetch_anthropic_models()
|
||||
if live:
|
||||
|
|
|
|||
|
|
@ -90,6 +90,13 @@ HERMES_OVERLAYS: Dict[str, HermesOverlay] = {
|
|||
extra_env_vars=("GLM_API_KEY", "ZAI_API_KEY", "Z_AI_API_KEY"),
|
||||
base_url_env_var="GLM_BASE_URL",
|
||||
),
|
||||
"ppq": HermesOverlay(
|
||||
transport="openai_chat",
|
||||
is_aggregator=True,
|
||||
extra_env_vars=("PPQ_API_KEY",),
|
||||
base_url_override="https://api.ppq.ai",
|
||||
base_url_env_var="PPQ_BASE_URL",
|
||||
),
|
||||
"kimi-for-coding": HermesOverlay(
|
||||
transport="openai_chat",
|
||||
base_url_env_var="KIMI_BASE_URL",
|
||||
|
|
@ -203,6 +210,10 @@ ALIASES: Dict[str, str] = {
|
|||
"z.ai": "zai",
|
||||
"zhipu": "zai",
|
||||
|
||||
# ppq
|
||||
"payperq": "ppq",
|
||||
"ppq.ai": "ppq",
|
||||
|
||||
# xai
|
||||
"x-ai": "xai",
|
||||
"x.ai": "xai",
|
||||
|
|
@ -313,6 +324,7 @@ _LABEL_OVERRIDES: Dict[str, str] = {
|
|||
"copilot-acp": "GitHub Copilot ACP",
|
||||
"stepfun": "StepFun Step Plan",
|
||||
"xiaomi": "Xiaomi MiMo",
|
||||
"ppq": "PPQ (PayPerQ)",
|
||||
"local": "Local endpoint",
|
||||
"bedrock": "AWS Bedrock",
|
||||
"ollama-cloud": "Ollama Cloud",
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ class TestProviderRegistry:
|
|||
("copilot-acp", "GitHub Copilot ACP", "external_process"),
|
||||
("copilot", "GitHub Copilot", "api_key"),
|
||||
("huggingface", "Hugging Face", "api_key"),
|
||||
("ppq", "PPQ (PayPerQ)", "api_key"),
|
||||
("zai", "Z.AI / GLM", "api_key"),
|
||||
("xai", "xAI", "api_key"),
|
||||
("nvidia", "NVIDIA NIM", "api_key"),
|
||||
|
|
@ -67,6 +68,12 @@ class TestProviderRegistry:
|
|||
assert pconfig.base_url_env_var == "NVIDIA_BASE_URL"
|
||||
assert pconfig.inference_base_url == "https://integrate.api.nvidia.com/v1"
|
||||
|
||||
def test_ppq_env_vars(self):
|
||||
pconfig = PROVIDER_REGISTRY["ppq"]
|
||||
assert pconfig.api_key_env_vars == ("PPQ_API_KEY",)
|
||||
assert pconfig.base_url_env_var == "PPQ_BASE_URL"
|
||||
assert pconfig.inference_base_url == "https://api.ppq.ai"
|
||||
|
||||
def test_copilot_env_vars(self):
|
||||
pconfig = PROVIDER_REGISTRY["copilot"]
|
||||
assert pconfig.api_key_env_vars == ("COPILOT_GITHUB_TOKEN", "GH_TOKEN", "GITHUB_TOKEN")
|
||||
|
|
@ -138,6 +145,7 @@ class TestProviderRegistry:
|
|||
PROVIDER_ENV_VARS = (
|
||||
"OPENROUTER_API_KEY", "OPENAI_API_KEY", "ANTHROPIC_API_KEY", "ANTHROPIC_TOKEN",
|
||||
"CLAUDE_CODE_OAUTH_TOKEN",
|
||||
"PPQ_API_KEY",
|
||||
"GLM_API_KEY", "ZAI_API_KEY", "Z_AI_API_KEY",
|
||||
"KIMI_API_KEY", "KIMI_BASE_URL", "STEPFUN_API_KEY", "STEPFUN_BASE_URL",
|
||||
"MINIMAX_API_KEY", "MINIMAX_CN_API_KEY",
|
||||
|
|
|
|||
|
|
@ -157,6 +157,8 @@ class TestNormalizeProvider:
|
|||
|
||||
def test_known_aliases(self):
|
||||
assert normalize_provider("glm") == "zai"
|
||||
assert normalize_provider("payperq") == "ppq"
|
||||
assert normalize_provider("ppq.ai") == "ppq"
|
||||
assert normalize_provider("kimi") == "kimi-coding"
|
||||
assert normalize_provider("moonshot") == "kimi-coding"
|
||||
assert normalize_provider("step") == "stepfun"
|
||||
|
|
@ -173,6 +175,7 @@ class TestProviderLabel:
|
|||
assert provider_label("stepfun") == "StepFun Step Plan"
|
||||
assert provider_label("copilot") == "GitHub Copilot"
|
||||
assert provider_label("copilot-acp") == "GitHub Copilot ACP"
|
||||
assert provider_label("ppq") == "PPQ (PayPerQ)"
|
||||
assert provider_label("auto") == "Auto"
|
||||
|
||||
def test_unknown_provider_preserves_original_name(self):
|
||||
|
|
@ -210,6 +213,23 @@ class TestProviderModelIds:
|
|||
):
|
||||
assert provider_model_ids("stepfun") == ["step-3.5-flash", "step-3-agent-lite"]
|
||||
|
||||
def test_ppq_prefers_live_catalog(self):
|
||||
with patch("hermes_cli.auth.resolve_api_key_provider_credentials", return_value={
|
||||
"api_key": "***", "base_url": "https://api.ppq.ai",
|
||||
}), patch("hermes_cli.models.fetch_api_models", return_value=[
|
||||
"claude-sonnet-4.6", "openai/gpt-5.4",
|
||||
]):
|
||||
assert provider_model_ids("ppq") == ["claude-sonnet-4.6", "openai/gpt-5.4"]
|
||||
|
||||
def test_ppq_falls_back_to_curated(self):
|
||||
"""When live fetch fails, PPQ falls back to the curated _PROVIDER_MODELS list."""
|
||||
with patch("hermes_cli.auth.resolve_api_key_provider_credentials", return_value={
|
||||
"api_key": "", "base_url": "https://api.ppq.ai",
|
||||
}):
|
||||
ids = provider_model_ids("ppq")
|
||||
assert len(ids) > 0
|
||||
assert "claude-opus-4.7" in ids
|
||||
|
||||
def test_copilot_prefers_live_catalog(self):
|
||||
with patch("hermes_cli.auth.resolve_api_key_provider_credentials", return_value={"api_key": "gh-token"}), \
|
||||
patch("hermes_cli.models._fetch_github_models", return_value=["gpt-5.4", "claude-sonnet-4.6"]):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue