Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@
# Optional base URL override (default: Google's OpenAI-compatible endpoint)
# GEMINI_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai

# =============================================================================
# LLM PROVIDER (Fireworks AI)
# =============================================================================
# Fast serverless inference. OpenAI-compatible endpoint.
# Get your key at: https://fireworks.ai/account/api-keys
# FIREWORKS_API_KEY=your_fireworks_key_here
# Optional base URL override (default: https://api.fireworks.ai/inference/v1)
# FIREWORKS_BASE_URL=https://api.fireworks.ai/inference/v1

# =============================================================================
# LLM PROVIDER (z.ai / GLM)
# =============================================================================
Expand Down
1 change: 1 addition & 0 deletions agent/auxiliary_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def _normalize_aux_provider(provider: Optional[str], *, for_vision: bool = False
"opencode-zen": "gemini-3-flash",
"opencode-go": "glm-5",
"kilocode": "google/gemini-3-flash-preview",
"fireworks": "accounts/fireworks/models/llama3.1-8b",
}

# OpenRouter app attribution headers
Expand Down
3 changes: 2 additions & 1 deletion agent/model_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@
# are preserved so the full model name reaches cache lookups and server queries.
_PROVIDER_PREFIXES: frozenset[str] = frozenset({
"openrouter", "nous", "openai-codex", "copilot", "copilot-acp",
"gemini", "zai", "kimi-coding", "minimax", "minimax-cn", "anthropic", "deepseek",
"gemini", "fireworks", "zai", "kimi-coding", "minimax", "minimax-cn", "anthropic", "deepseek",
"opencode-zen", "opencode-go", "ai-gateway", "kilocode", "alibaba",
"custom", "local",
# Common aliases
"google", "google-gemini", "google-ai-studio",
"glm", "z-ai", "z.ai", "zhipu", "github", "github-copilot",
"github-models", "kimi", "moonshot", "claude", "deep-seek",
"fw", "fireworks-ai",
"opencode", "zen", "go", "vercel", "kilo", "dashscope", "aliyun", "qwen",
})

Expand Down
2 changes: 2 additions & 0 deletions cli-config.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ model:
# "minimax" - MiniMax global (requires: MINIMAX_API_KEY)
# "minimax-cn" - MiniMax China (requires: MINIMAX_CN_API_KEY)
# "huggingface" - Hugging Face Inference (requires: HF_TOKEN)
# "fireworks" - Fireworks AI (requires: FIREWORKS_API_KEY — https://fireworks.ai/account/api-keys)
# "kilocode" - KiloCode gateway (requires: KILOCODE_API_KEY)
# "ai-gateway" - Vercel AI Gateway (requires: AI_GATEWAY_API_KEY)
#
Expand Down Expand Up @@ -317,6 +318,7 @@ compression:
# "openrouter" - Force OpenRouter (requires OPENROUTER_API_KEY)
# "nous" - Force Nous Portal (requires: hermes login)
# "gemini" - Force Google AI Studio direct (requires: GOOGLE_API_KEY or GEMINI_API_KEY)
# "fireworks" - Fireworks AI (requires: FIREWORKS_API_KEY)
# "codex" - Force Codex OAuth (requires: hermes model → Codex).
# Uses gpt-5.3-codex which supports vision.
# "main" - Use your custom endpoint (OPENAI_BASE_URL + OPENAI_API_KEY).
Expand Down
10 changes: 10 additions & 0 deletions hermes_cli/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
DEFAULT_GITHUB_MODELS_BASE_URL = "https://api.githubcopilot.com"
DEFAULT_COPILOT_ACP_BASE_URL = "acp://copilot"
DEFAULT_GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai"
DEFAULT_FIREWORKS_BASE_URL = "https://api.fireworks.ai/inference/v1"
CODEX_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann"
CODEX_OAUTH_TOKEN_URL = "https://auth.openai.com/oauth/token"
CODEX_ACCESS_TOKEN_REFRESH_SKEW_SECONDS = 120
Expand Down Expand Up @@ -233,6 +234,14 @@ class ProviderConfig:
api_key_env_vars=("HF_TOKEN",),
base_url_env_var="HF_BASE_URL",
),
"fireworks": ProviderConfig(
id="fireworks",
name="Fireworks AI",
auth_type="api_key",
inference_base_url=DEFAULT_FIREWORKS_BASE_URL,
api_key_env_vars=("FIREWORKS_API_KEY",),
base_url_env_var="FIREWORKS_BASE_URL",
),
}


Expand Down Expand Up @@ -820,6 +829,7 @@ def resolve_provider(
"hf": "huggingface", "hugging-face": "huggingface", "huggingface-hub": "huggingface",
"go": "opencode-go", "opencode-go-sub": "opencode-go",
"kilo": "kilocode", "kilo-code": "kilocode", "kilo-gateway": "kilocode",
"fireworks-ai": "fireworks", "fw": "fireworks",
# Local server aliases — route through the generic custom provider
"lmstudio": "custom", "lm-studio": "custom", "lm_studio": "custom",
"ollama": "custom", "vllm": "custom", "llamacpp": "custom",
Expand Down
16 changes: 16 additions & 0 deletions hermes_cli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,22 @@ def ensure_hermes_home():
"category": "provider",
"advanced": True,
},
"FIREWORKS_API_KEY": {
"description": "Fireworks AI API key (fast serverless inference)",
"prompt": "Fireworks AI API key",
"url": "https://fireworks.ai/account/api-keys",
"password": True,
"category": "provider",
"advanced": True,
},
"FIREWORKS_BASE_URL": {
"description": "Fireworks AI base URL override (default: https://api.fireworks.ai/inference/v1)",
"prompt": "Fireworks base URL (leave empty for default)",
"url": None,
"password": False,
"category": "provider",
"advanced": True,
},

# ── Tool API keys ──
"EXA_API_KEY": {
Expand Down
6 changes: 4 additions & 2 deletions hermes_cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,7 @@ def select_provider_and_model(args=None):
"kilocode": "Kilo Code",
"alibaba": "Alibaba Cloud (DashScope)",
"huggingface": "Hugging Face",
"fireworks": "Fireworks AI",
"custom": "Custom endpoint",
}
active_label = provider_labels.get(active, active) if active else "none"
Expand Down Expand Up @@ -963,6 +964,7 @@ def select_provider_and_model(args=None):
("opencode-go", "OpenCode Go (open models, $10/month subscription)"),
("ai-gateway", "AI Gateway (Vercel — 200+ models, pay-per-use)"),
("alibaba", "Alibaba Cloud / DashScope Coding (Qwen + multi-provider)"),
("fireworks", "Fireworks AI (fast serverless inference — OpenAI-compatible)"),
]

# Add user-defined custom providers from config.yaml
Expand Down Expand Up @@ -1057,7 +1059,7 @@ def select_provider_and_model(args=None):
_model_flow_anthropic(config, current_model)
elif selected_provider == "kimi-coding":
_model_flow_kimi(config, current_model)
elif selected_provider in ("gemini", "zai", "minimax", "minimax-cn", "kilocode", "opencode-zen", "opencode-go", "ai-gateway", "alibaba", "huggingface"):
elif selected_provider in ("gemini", "zai", "minimax", "minimax-cn", "kilocode", "opencode-zen", "opencode-go", "ai-gateway", "alibaba", "huggingface", "fireworks"):
_model_flow_api_key_provider(config, selected_provider, current_model)


Expand Down Expand Up @@ -4240,7 +4242,7 @@ def main():
)
chat_parser.add_argument(
"--provider",
choices=["auto", "openrouter", "nous", "openai-codex", "copilot-acp", "copilot", "anthropic", "gemini", "huggingface", "zai", "kimi-coding", "minimax", "minimax-cn", "kilocode"],
choices=["auto", "openrouter", "nous", "openai-codex", "copilot-acp", "copilot", "anthropic", "gemini", "fireworks", "huggingface", "zai", "kimi-coding", "minimax", "minimax-cn", "kilocode"],
default=None,
help="Inference provider (default: auto)"
)
Expand Down
1 change: 1 addition & 0 deletions hermes_cli/model_normalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
"minimax-cn",
"alibaba",
"huggingface",
"fireworks",
"openai-codex",
"custom",
})
Expand Down
5 changes: 4 additions & 1 deletion hermes_cli/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ def check_nous_free_tier() -> bool:
"kilocode": "Kilo Code",
"alibaba": "Alibaba Cloud (DashScope)",
"huggingface": "Hugging Face",
"fireworks": "Fireworks AI",
"custom": "Custom endpoint",
}

Expand Down Expand Up @@ -521,6 +522,8 @@ def check_nous_free_tier() -> bool:
"hf": "huggingface",
"hugging-face": "huggingface",
"huggingface-hub": "huggingface",
"fireworks-ai": "fireworks",
"fw": "fireworks",
}


Expand Down Expand Up @@ -761,7 +764,7 @@ def list_available_providers() -> list[dict[str, str]]:
# Canonical providers in display order
_PROVIDER_ORDER = [
"openrouter", "nous", "openai-codex", "copilot", "copilot-acp",
"gemini", "huggingface",
"gemini", "fireworks", "huggingface",
"zai", "kimi-coding", "minimax", "minimax-cn", "kilocode", "anthropic", "alibaba",
"opencode-zen", "opencode-go",
"ai-gateway", "deepseek", "custom",
Expand Down
10 changes: 10 additions & 0 deletions hermes_cli/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ class HermesOverlay:
is_aggregator=True,
base_url_env_var="HF_BASE_URL",
),
"fireworks": HermesOverlay(
transport="openai_chat",
base_url_env_var="FIREWORKS_BASE_URL",
),
}


Expand Down Expand Up @@ -200,6 +204,10 @@ def is_user_defined(self) -> bool:
# deepseek
"deep-seek": "deepseek",

# fireworks
"fireworks-ai": "fireworks",
"fw": "fireworks",

# alibaba
"dashscope": "alibaba",
"aliyun": "alibaba",
Expand Down Expand Up @@ -232,6 +240,7 @@ def is_user_defined(self) -> bool:
"openai-codex": "OpenAI Codex",
"copilot-acp": "GitHub Copilot ACP",
"local": "Local endpoint",
"fireworks": "Fireworks AI",
}


Expand Down Expand Up @@ -367,6 +376,7 @@ def get_label(provider_id: str) -> str:
"huggingface": "Hugging Face",
"local": "Local endpoint",
"custom": "Custom endpoint",
"fireworks": "Fireworks AI",
# Legacy Hermes IDs (point to same providers)
"ai-gateway": "Vercel AI Gateway",
"kilocode": "Kilo Gateway",
Expand Down
Loading
Loading