From 31152ae108e84325db1d75a2c7f0f49037c866ee Mon Sep 17 00:00:00 2001
From: teknium1 <127238744+teknium1@users.noreply.github.com>
Date: Sat, 11 Jul 2026 04:00:15 -0700
Subject: [PATCH] fix(providers): align Fireworks integration with project
policy
---
.env.example | 5 +--
apps/desktop/public/fireworks-white.svg | 5 ---
apps/desktop/public/fireworks.svg | 5 ---
.../src/components/onboarding/index.test.tsx | 22 ++---------
.../src/components/onboarding/index.tsx | 23 +++++------
.../src/components/onboarding/providers.tsx | 28 -------------
apps/desktop/src/i18n/en.ts | 5 +--
apps/desktop/src/i18n/ja.ts | 5 +--
apps/desktop/src/i18n/types.ts | 1 -
apps/desktop/src/i18n/zh-hant.ts | 3 +-
apps/desktop/src/i18n/zh.ts | 3 +-
hermes_cli/config.py | 8 ----
hermes_cli/models.py | 4 +-
hermes_cli/providers.py | 1 -
plugins/model-providers/fireworks/__init__.py | 38 ++----------------
plugins/model-providers/fireworks/plugin.yaml | 2 +-
scripts/release.py | 1 +
tests/hermes_cli/test_fireworks_provider.py | 39 +++++--------------
.../model_providers/test_fireworks_profile.py | 18 ++++-----
tests/run_agent/test_fireworks_live.py | 4 +-
website/docs/getting-started/quickstart.md | 1 +
website/docs/integrations/providers.md | 7 ++++
.../docs/reference/environment-variables.md | 1 +
website/docs/user-guide/configuration.md | 4 +-
24 files changed, 55 insertions(+), 178 deletions(-)
delete mode 100644 apps/desktop/public/fireworks-white.svg
delete mode 100644 apps/desktop/public/fireworks.svg
diff --git a/.env.example b/.env.example
index 0e78d2023f9..828878c68c0 100644
--- a/.env.example
+++ b/.env.example
@@ -2,15 +2,12 @@
# Copy this file to .env and fill in your API keys
# =============================================================================
-# LLM PROVIDER (Fireworks AI) — preferred BYOK provider
+# LLM PROVIDER (Fireworks AI)
# =============================================================================
-# Fireworks AI — fastest inference for production AI, 300+ models, one API key.
# Get your key at: https://app.fireworks.ai/settings/users/api-keys
# Address models directly by catalog ID, e.g.
# accounts/fireworks/models/kimi-k2p6, accounts/fireworks/models/glm-5p2
# FIREWORKS_API_KEY=
-# FIREWORKS_BASE_URL=https://api.fireworks.ai/inference/v1 # Override default base URL
-
# =============================================================================
# LLM PROVIDER (OpenRouter)
# =============================================================================
diff --git a/apps/desktop/public/fireworks-white.svg b/apps/desktop/public/fireworks-white.svg
deleted file mode 100644
index cfab71d67ff..00000000000
--- a/apps/desktop/public/fireworks-white.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/apps/desktop/public/fireworks.svg b/apps/desktop/public/fireworks.svg
deleted file mode 100644
index f392879f60c..00000000000
--- a/apps/desktop/public/fireworks.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/apps/desktop/src/components/onboarding/index.test.tsx b/apps/desktop/src/components/onboarding/index.test.tsx
index dd9028943fd..35cac9c4d17 100644
--- a/apps/desktop/src/components/onboarding/index.test.tsx
+++ b/apps/desktop/src/components/onboarding/index.test.tsx
@@ -56,15 +56,12 @@ afterEach(() => {
})
describe('onboarding Picker', () => {
- it('features Nous Portal and Fireworks, and hides other providers behind a disclosure', () => {
+ it('features Nous Portal and hides other providers behind a disclosure', () => {
setProviders([provider('anthropic', 'Anthropic Claude'), provider('nous', 'Nous Portal')])
render()
expect(screen.getByText('Nous Portal')).toBeTruthy()
- // Fireworks is the preferred BYOK provider — a second hero card after Nous.
- expect(screen.getByText('Fireworks AI')).toBeTruthy()
- // Both hero cards carry a Recommended badge; the plain rows below do not.
- expect(screen.getAllByText('Recommended')).toHaveLength(2)
+ expect(screen.getByText('Recommended')).toBeTruthy()
expect(screen.queryByText('Anthropic API Key')).toBeNull()
fireEvent.click(screen.getByRole('button', { name: 'Other providers' }))
@@ -73,25 +70,14 @@ describe('onboarding Picker', () => {
expect(screen.getByRole('button', { name: 'Collapse' })).toBeTruthy()
})
- it('still features Fireworks when Nous Portal is absent', () => {
+ it('shows every provider directly when Nous Portal is absent', () => {
setProviders([provider('anthropic', 'Anthropic Claude'), provider('openai-codex', 'OpenAI Codex / ChatGPT')])
render()
expect(screen.getByText('Anthropic API Key')).toBeTruthy()
expect(screen.getByText('OpenAI OAuth (ChatGPT)')).toBeTruthy()
expect(screen.queryByText('Other sign-in options')).toBeNull()
- // Fireworks stays featured even without Nous — exactly one Recommended badge.
- expect(screen.getByText('Fireworks AI')).toBeTruthy()
- expect(screen.getAllByText('Recommended')).toHaveLength(1)
- })
-
- it('routes the Fireworks hero card into the API-key form', () => {
- setProviders([provider('nous', 'Nous Portal')])
- render()
-
- fireEvent.click(screen.getByText('Fireworks AI'))
-
- expect($desktopOnboarding.get().mode).toBe('apikey')
+ expect(screen.queryByText('Recommended')).toBeNull()
})
it('offers "choose later" on first run and persists the skip', () => {
diff --git a/apps/desktop/src/components/onboarding/index.tsx b/apps/desktop/src/components/onboarding/index.tsx
index 8c889ed20f6..df547b91a65 100644
--- a/apps/desktop/src/components/onboarding/index.tsx
+++ b/apps/desktop/src/components/onboarding/index.tsx
@@ -28,10 +28,9 @@ import {
import type { ModelOptionProvider, OAuthProvider } from '@/types/hermes'
import { DocsLink, FlowPanel, Status } from './flow'
-import { FeaturedFireworksRow, FeaturedProviderRow, KeyProviderRow, ProviderRow, sortProviders } from './providers'
+import { FeaturedProviderRow, KeyProviderRow, ProviderRow, sortProviders } from './providers'
export {
- FeaturedFireworksRow,
FeaturedProviderRow,
KeyProviderRow,
ProviderRow,
@@ -56,18 +55,18 @@ export interface ApiKeyOption {
}
const API_KEY_OPTIONS: ApiKeyOption[] = [
- {
- id: 'fireworks',
- name: 'Fireworks AI',
- envKey: 'FIREWORKS_API_KEY',
- docsUrl: 'https://app.fireworks.ai/settings/users/api-keys'
- },
{
id: 'openrouter',
name: 'OpenRouter',
envKey: 'OPENROUTER_API_KEY',
docsUrl: 'https://openrouter.ai/keys'
},
+ {
+ id: 'fireworks',
+ name: 'Fireworks AI',
+ envKey: 'FIREWORKS_API_KEY',
+ docsUrl: 'https://app.fireworks.ai/settings/users/api-keys'
+ },
{
id: 'openai',
name: 'OpenAI',
@@ -408,9 +407,8 @@ export function Picker({ ctx }: { ctx: OnboardingContext }) {
const { t } = useI18n()
const { localEndpoint, manual, mode, providers } = useStore($desktopOnboarding)
const [showAll, setShowAll] = useState(readShowAll)
- // Which key-form option to preselect when we flip to 'apikey' mode. Set by the
- // Fireworks hero card (its BYOK key) and the OpenRouter row; the generic
- // "I have an API key" link leaves it undefined and lands on the first option.
+ // Which key-form option to preselect when we flip to 'apikey' mode. The
+ // OpenRouter row selects its key; the generic link lands on the first option.
const [apiKeyInitialEnv, setApiKeyInitialEnv] = useState(undefined)
const openKeyForm = (envKey?: string) => {
setApiKeyInitialEnv(envKey)
@@ -459,9 +457,6 @@ export function Picker({ ctx }: { ctx: OnboardingContext }) {
{featured ? : null}
- {/* Fireworks — preferred BYOK provider, second hero card after Nous.
- Routes into the API-key form preselecting the Fireworks key. */}
- openKeyForm('FIREWORKS_API_KEY')} />
{showRest ? (
<>
{rest.map(p => (
diff --git a/apps/desktop/src/components/onboarding/providers.tsx b/apps/desktop/src/components/onboarding/providers.tsx
index 3bac195cfbb..f7dafdae95d 100644
--- a/apps/desktop/src/components/onboarding/providers.tsx
+++ b/apps/desktop/src/components/onboarding/providers.tsx
@@ -62,34 +62,6 @@ export function FeaturedProviderRow({
)
}
-// Fireworks is the preferred BYOK provider — a second hero card directly below
-// Nous Portal. It isn't an OAuth provider (no sign-in flow), so it takes a bare
-// onSelect that routes into the API-key form rather than an OAuthProvider.
-export function FeaturedFireworksRow({ onSelect }: { onSelect: () => void }) {
- const { t } = useI18n()
-
- return (
-
- )
-}
-
function ConnectedTag() {
const { t } = useI18n()
diff --git a/apps/desktop/src/i18n/en.ts b/apps/desktop/src/i18n/en.ts
index 246beec9bcf..b056bbca5f5 100644
--- a/apps/desktop/src/i18n/en.ts
+++ b/apps/desktop/src/i18n/en.ts
@@ -1928,12 +1928,11 @@ export const en: Translations = {
recommended: 'Recommended',
connected: 'Connected',
featuredPitch: 'One subscription, 300+ frontier models — the recommended way to run Hermes',
- fireworksPitch: 'Fastest inference for production AI — 300+ models, one API, deploy in a click',
openRouterPitch: 'One key, hundreds of models — a solid default',
apiKeyOptions: {
fireworks: {
- short: 'fastest inference',
- description: 'Direct access to 300+ open & proprietary models on Fireworks AI — one API key, production speed.'
+ short: 'direct model API',
+ description: 'Direct access to models hosted by Fireworks AI.'
},
openrouter: {
short: 'one key, many models',
diff --git a/apps/desktop/src/i18n/ja.ts b/apps/desktop/src/i18n/ja.ts
index 0efe672db9e..20ff811423b 100644
--- a/apps/desktop/src/i18n/ja.ts
+++ b/apps/desktop/src/i18n/ja.ts
@@ -1873,12 +1873,11 @@ export const ja = defineLocale({
recommended: '推奨',
connected: '接続済み',
featuredPitch: '1 つのサブスクリプションで 300 以上の最先端モデル — Hermes を実行するための推奨方法',
- fireworksPitch: 'プロダクション AI 向けの最速推論 — 300 以上のモデル、1 つの API、ワンクリックでデプロイ',
openRouterPitch: '1 つのキーで数百のモデル — 堅実なデフォルト',
apiKeyOptions: {
fireworks: {
- short: '最速の推論',
- description: 'Fireworks AI で 300 以上のオープン/プロプライエタリモデルに直接アクセス — 1 つの API キー、プロダクション速度。'
+ short: 'モデル API に直接接続',
+ description: 'Fireworks AI がホストするモデルに直接アクセスします。'
},
openrouter: {
short: '1 つのキーで多くのモデル',
diff --git a/apps/desktop/src/i18n/types.ts b/apps/desktop/src/i18n/types.ts
index ff19f13191b..031f5c78f6d 100644
--- a/apps/desktop/src/i18n/types.ts
+++ b/apps/desktop/src/i18n/types.ts
@@ -1582,7 +1582,6 @@ export interface Translations {
recommended: string
connected: string
featuredPitch: string
- fireworksPitch: string
openRouterPitch: string
apiKeyOptions: Record
backToSignIn: string
diff --git a/apps/desktop/src/i18n/zh-hant.ts b/apps/desktop/src/i18n/zh-hant.ts
index 008bf7def57..f58fe80edd5 100644
--- a/apps/desktop/src/i18n/zh-hant.ts
+++ b/apps/desktop/src/i18n/zh-hant.ts
@@ -1817,10 +1817,9 @@ export const zhHant = defineLocale({
recommended: '建議',
connected: '已連線',
featuredPitch: '一個訂閱,300+ 前沿模型 — 執行 Hermes 的建議方式',
- fireworksPitch: '面向生產 AI 的最快推理 — 300+ 模型,一個 API,一鍵部署',
openRouterPitch: '一個金鑰,數百個模型 — 穩定的預設選擇',
apiKeyOptions: {
- fireworks: { short: '最快推理', description: '透過 Fireworks AI 直接存取 300+ 開源與專有模型 — 一個 API 金鑰,生產級速度。' },
+ fireworks: { short: '直接模型 API', description: '直接存取 Fireworks AI 託管的模型。' },
openrouter: { short: '一個金鑰,多個模型', description: '用一個金鑰存取數百個模型。適合新安裝的預設選擇。' },
openai: { short: 'GPT 等級模型', description: '直接存取 OpenAI 模型。' },
gemini: { short: 'Gemini 模型', description: '直接存取 Google Gemini 模型。' },
diff --git a/apps/desktop/src/i18n/zh.ts b/apps/desktop/src/i18n/zh.ts
index 4a6a9ca9241..babc9b778d2 100644
--- a/apps/desktop/src/i18n/zh.ts
+++ b/apps/desktop/src/i18n/zh.ts
@@ -2100,10 +2100,9 @@ export const zh: Translations = {
recommended: '推荐',
connected: '已连接',
featuredPitch: '一个订阅,300+ 前沿模型 — 运行 Hermes 的推荐方式',
- fireworksPitch: '面向生产 AI 的最快推理 — 300+ 模型,一个 API,一键部署',
openRouterPitch: '一个密钥,数百个模型 — 稳妥的默认选择',
apiKeyOptions: {
- fireworks: { short: '最快推理', description: '通过 Fireworks AI 直接访问 300+ 开源与专有模型 — 一个 API 密钥,生产级速度。' },
+ fireworks: { short: '直接模型 API', description: '直接访问 Fireworks AI 托管的模型。' },
openrouter: { short: '一个密钥,多个模型', description: '用一个密钥访问数百个模型。适合新安装的默认选择。' },
openai: { short: 'GPT 级模型', description: '直接访问 OpenAI 模型。' },
gemini: { short: 'Gemini 模型', description: '直接访问 Google Gemini 模型。' },
diff --git a/hermes_cli/config.py b/hermes_cli/config.py
index 31fd9dbc764..9b9359888fa 100644
--- a/hermes_cli/config.py
+++ b/hermes_cli/config.py
@@ -3543,14 +3543,6 @@ OPTIONAL_ENV_VARS = {
"category": "provider",
"advanced": True,
},
- "FIREWORKS_BASE_URL": {
- "description": "Fireworks AI base URL override",
- "prompt": "Fireworks AI base URL (leave empty for default)",
- "url": None,
- "password": False,
- "category": "provider",
- "advanced": True,
- },
"MINIMAX_API_KEY": {
"description": "MiniMax API key (international)",
"prompt": "MiniMax API key",
diff --git a/hermes_cli/models.py b/hermes_cli/models.py
index 54df537b8ed..944e52d1d0a 100644
--- a/hermes_cli/models.py
+++ b/hermes_cli/models.py
@@ -1051,9 +1051,6 @@ class ProviderEntry(NamedTuple):
CANONICAL_PROVIDERS: list[ProviderEntry] = [
ProviderEntry("nous", "Nous Portal", "Nous Portal (Everything your agent needs, 300+ models with bundled tool use)"),
- # Fireworks AI — preferred BYOK inference partner. Sits directly below Nous
- # Portal (Nous's own provider stays first); everything else follows.
- ProviderEntry("fireworks", "Fireworks AI", "Fireworks AI (Fastest inference for production AI, 300+ models, one API key)"),
ProviderEntry("openrouter", "OpenRouter", "OpenRouter (Pay-per-use API aggregator)"),
ProviderEntry("moa", "Mixture of Agents", "Mixture of Agents (named presets; aggregator acts after reference models)"),
ProviderEntry("novita", "NovitaAI", "NovitaAI (Cloud: Model API, Agent Sandbox, GPU Cloud)"),
@@ -1083,6 +1080,7 @@ CANONICAL_PROVIDERS: list[ProviderEntry] = [
ProviderEntry("ollama-cloud", "Ollama Cloud", "Ollama Cloud (Cloud-hosted open models, ollama.com)"),
ProviderEntry("arcee", "Arcee AI", "Arcee AI (Trinity models, direct API)"),
ProviderEntry("gmi", "GMI Cloud", "GMI Cloud (Multi-model direct API)"),
+ ProviderEntry("fireworks", "Fireworks AI", "Fireworks AI (OpenAI-compatible direct model API)"),
ProviderEntry("kilocode", "Kilo Code", "Kilo Code (Kilo Gateway API)"),
ProviderEntry("opencode-zen", "OpenCode Zen", "OpenCode Zen (Curated models, pay-as-you-go)"),
ProviderEntry("opencode-go", "OpenCode Go", "OpenCode Go (Open models subscription)"),
diff --git a/hermes_cli/providers.py b/hermes_cli/providers.py
index 6d73683717a..53d0e23e06b 100644
--- a/hermes_cli/providers.py
+++ b/hermes_cli/providers.py
@@ -200,7 +200,6 @@ HERMES_OVERLAYS: Dict[str, HermesOverlay] = {
transport="openai_chat",
extra_env_vars=("FIREWORKS_API_KEY",),
base_url_override="https://api.fireworks.ai/inference/v1",
- base_url_env_var="FIREWORKS_BASE_URL",
),
"ollama-cloud": HermesOverlay(
transport="openai_chat",
diff --git a/plugins/model-providers/fireworks/__init__.py b/plugins/model-providers/fireworks/__init__.py
index 55b9f37da19..54f9758df9b 100644
--- a/plugins/model-providers/fireworks/__init__.py
+++ b/plugins/model-providers/fireworks/__init__.py
@@ -1,8 +1,7 @@
"""Fireworks AI provider profile.
Fireworks AI serves fast, production-grade inference for open and proprietary
-models through an OpenAI-compatible chat-completions endpoint. It is a bundled,
-preferred BYOK provider — users paste a Fireworks API key and go.
+models through an OpenAI-compatible chat-completions endpoint.
Address models directly by their catalog ID, e.g.
``accounts/fireworks/models/kimi-k2p6`` or ``accounts/fireworks/models/glm-5p2``.
@@ -18,19 +17,11 @@ fireworks = ProviderProfile(
name="fireworks",
aliases=("fireworks-ai", "fw"),
display_name="Fireworks AI",
- description="Fireworks AI — fastest inference for production AI, 300+ models, one API key",
+ description="Fireworks AI — OpenAI-compatible direct model API",
signup_url="https://app.fireworks.ai/settings/users/api-keys",
- env_vars=("FIREWORKS_API_KEY", "FIREWORKS_BASE_URL"),
+ env_vars=("FIREWORKS_API_KEY",),
base_url="https://api.fireworks.ai/inference/v1",
auth_type="api_key",
- # Attribution: lets Fireworks identify traffic originating from Hermes Agent
- # (partner/revenue attribution). Matches the canonical Hermes attribution
- # values in agent/auxiliary_client.py. Applied at client construction via the
- # generic profile.default_headers path in run_agent.py.
- default_headers={
- "HTTP-Referer": "https://hermes-agent.nousresearch.com",
- "X-Title": "Hermes Agent",
- },
# Auxiliary model for cheap tasks (compaction, title generation, vision).
# A standard pay-as-you-go catalog ``/models/`` ID.
default_aux_model="accounts/fireworks/models/glm-5p2",
@@ -43,26 +34,3 @@ fireworks = ProviderProfile(
)
register_provider(fireworks)
-
-
-# ---------------------------------------------------------------------------
-# Future work (intentionally disabled for now — do not ship as customer-facing).
-#
-# A second Fireworks key tier authenticates against the same endpoint but can
-# only address managed router IDs (accounts/fireworks/routers/...), not raw
-# /models/ IDs, and cannot list the account catalog. Enabling it means detecting
-# the key prefix and swapping the picker catalog + aux model to routers. Kept
-# here (commented out) so the wiring is ready when we turn it on. Router IDs and
-# behavior track fw-ai/fireconnect setup-cli.
-#
-# _MANAGED_KEY_PREFIX = "fpk_"
-# _MANAGED_ROUTERS = (
-# "accounts/fireworks/routers/glm-latest", # default
-# "accounts/fireworks/routers/glm-fast-latest",
-# "accounts/fireworks/routers/kimi-latest",
-# "accounts/fireworks/routers/kimi-k2p6-turbo", # turbo tier — not a default
-# )
-#
-# def _is_managed_key(api_key: str) -> bool:
-# return bool(api_key) and api_key.startswith(_MANAGED_KEY_PREFIX)
-# ---------------------------------------------------------------------------
diff --git a/plugins/model-providers/fireworks/plugin.yaml b/plugins/model-providers/fireworks/plugin.yaml
index 1523792ce80..dc9b25602ac 100644
--- a/plugins/model-providers/fireworks/plugin.yaml
+++ b/plugins/model-providers/fireworks/plugin.yaml
@@ -2,4 +2,4 @@ name: fireworks-provider
kind: model-provider
version: 1.0.0
description: Fireworks AI — fast inference for open and proprietary models
-author: Nous Research
+author: Alex Jestin Taylor (@alex-fireworks) + Hermes Agent
diff --git a/scripts/release.py b/scripts/release.py
index bacca2ef2b6..beaa0380269 100755
--- a/scripts/release.py
+++ b/scripts/release.py
@@ -77,6 +77,7 @@ AUTHOR_MAP = {
"lord-dubious@users.noreply.github.com": "lord-dubious", # PR #58453 salvage (preserve static custom provider models declared as dict rows)
"williamumu@users.noreply.github.com": "williamumu", # PR #31041 salvage (pairing: merge split legacy/new pairing store dirs at PairingStore init so approved users aren't re-prompted to pair)
"jonathan@mintrx.com": "JAlmanzarMint", # PR #52688 salvage (vision: rasterize SVG / re-encode unsupported raster formats to PNG before embedding), folded into #57890
+ "alex@fireworks.ai": "alex-fireworks", # PR #61182 salvage (Fireworks AI model-provider integration)
"al3060388206@gmail.com": "ooiuuii", # PR #58466/#58377 salvage (redact: fireworks fw-/fpk_ prefixes; telegram: redact bot tokens out of transport error strings). Also PR #58433 salvage (codex: accept recorded final_text when app-server omits turn/completed) and PR #58472 salvage (gateway: cap proxy SSE line buffer at 16MiB).
"Jigoooo@users.noreply.github.com": "Jigoooo", # PR #58474 salvage (auxiliary: fall back to token resolver when anthropic pool has no usable entry)
"root@vmi3351581.contaboserver.net": "ostravajih", # PR #58374 salvage (poolside: coerce integer finish_reason and tool_call id to strings)
diff --git a/tests/hermes_cli/test_fireworks_provider.py b/tests/hermes_cli/test_fireworks_provider.py
index 7ea528dd6c7..6ebb589ee9c 100644
--- a/tests/hermes_cli/test_fireworks_provider.py
+++ b/tests/hermes_cli/test_fireworks_provider.py
@@ -1,9 +1,8 @@
"""Focused tests for Fireworks AI first-class provider wiring.
-Fireworks is the bundled, preferred BYOK provider (sits right after Nous
-Portal). These tests pin the wiring that makes it a real provider — alias
-resolution through BOTH CLI resolvers, ordering, config/doctor/overlay
-registration, attribution headers, and credential/base-URL resolution — without
+These tests pin the wiring that makes Fireworks a real provider — alias
+resolution through both CLI resolvers, config/doctor/overlay registration,
+and credential/base-URL resolution — without
any live network calls.
"""
@@ -48,21 +47,12 @@ class TestFireworksAliases:
class TestFireworksOrdering:
- """Product contract: Fireworks is the preferred provider and sits directly
- below Nous Portal (Nous's own provider stays first)."""
+ """Fireworks participates in the canonical provider catalog."""
def test_present_in_canonical_providers(self):
slugs = [p.slug for p in CANONICAL_PROVIDERS]
assert "fireworks" in slugs
- def test_sits_immediately_after_nous(self):
- slugs = [p.slug for p in CANONICAL_PROVIDERS]
- assert slugs.index("fireworks") == slugs.index("nous") + 1, slugs[:4]
-
- def test_ranks_ahead_of_the_other_byok_providers(self):
- slugs = [p.slug for p in CANONICAL_PROVIDERS]
- # Ahead of the generic aggregators / other direct providers.
- assert slugs.index("fireworks") < slugs.index("openrouter")
def test_has_a_label(self):
assert _PROVIDER_LABELS.get("fireworks") == "Fireworks AI"
@@ -76,8 +66,7 @@ class TestFireworksConfigRegistry:
assert OPTIONAL_ENV_VARS["FIREWORKS_API_KEY"]["category"] == "provider"
assert OPTIONAL_ENV_VARS["FIREWORKS_API_KEY"]["password"] is True
- assert "FIREWORKS_BASE_URL" in OPTIONAL_ENV_VARS
- assert OPTIONAL_ENV_VARS["FIREWORKS_BASE_URL"]["password"] is False
+ assert "FIREWORKS_BASE_URL" not in OPTIONAL_ENV_VARS
class TestFireworksOverlay:
@@ -88,7 +77,7 @@ class TestFireworksOverlay:
overlay = HERMES_OVERLAYS["fireworks"]
assert overlay.transport == "openai_chat"
assert overlay.base_url_override == "https://api.fireworks.ai/inference/v1"
- assert overlay.base_url_env_var == "FIREWORKS_BASE_URL"
+ assert not overlay.base_url_env_var
assert not overlay.is_aggregator
@@ -153,16 +142,8 @@ class TestFireworksCredentials:
assert creds["api_key"] == "fw_test_key"
assert creds["base_url"] == "https://api.fireworks.ai/inference/v1"
- def test_base_url_override_is_honored(self, monkeypatch):
- monkeypatch.setenv("FIREWORKS_API_KEY", "fw_test_key")
- monkeypatch.setenv("FIREWORKS_BASE_URL", "https://gateway.example.com/v1")
- creds = resolve_api_key_provider_credentials("fireworks")
- assert creds["base_url"] == "https://gateway.example.com/v1"
-
-
class TestFireworksAuxiliary:
- """resolve_provider_client wires the BYOK key, PAYG-safe aux model, and the
- partner-attribution headers through to the OpenAI client."""
+ """resolve_provider_client wires the BYOK key and PAYG-safe aux model."""
def _resolve(self, name):
from unittest.mock import patch
@@ -174,13 +155,13 @@ class TestFireworksAuxiliary:
client, model = resolve_provider_client(name)
return client, model, mock_openai.call_args.kwargs
- def test_client_carries_attribution_headers(self, monkeypatch):
+ def test_client_has_no_partner_attribution_headers(self, monkeypatch):
monkeypatch.setenv("FIREWORKS_API_KEY", "fw_test_key")
client, model, kwargs = self._resolve("fireworks")
assert client is not None
headers = kwargs.get("default_headers", {})
- assert headers.get("HTTP-Referer") == "https://hermes-agent.nousresearch.com"
- assert headers.get("X-Title") == "Hermes Agent"
+ assert "HTTP-Referer" not in headers
+ assert "X-Title" not in headers
assert kwargs["base_url"] == "https://api.fireworks.ai/inference/v1"
def test_aux_model_is_payg_safe(self, monkeypatch):
diff --git a/tests/plugins/model_providers/test_fireworks_profile.py b/tests/plugins/model_providers/test_fireworks_profile.py
index c44ecbb79b1..0a04c7d97f9 100644
--- a/tests/plugins/model_providers/test_fireworks_profile.py
+++ b/tests/plugins/model_providers/test_fireworks_profile.py
@@ -1,8 +1,7 @@
"""Unit tests for the Fireworks AI provider profile.
-Pins the profile's contract without going live: identity, attribution headers
-(so Fireworks can attribute Hermes traffic for the partnership), alias
-registration, and the pay-as-you-go model defaults (direct catalog ``/models/``
+Pins the profile's contract without going live: identity, alias registration,
+and the pay-as-you-go model defaults (direct catalog ``/models/``
IDs, not the router-only tier).
"""
@@ -30,7 +29,7 @@ class TestFireworksIdentity:
assert p.auth_type == "api_key"
assert p.base_url == "https://api.fireworks.ai/inference/v1"
assert "FIREWORKS_API_KEY" in p.env_vars
- assert "FIREWORKS_BASE_URL" in p.env_vars
+ assert "FIREWORKS_BASE_URL" not in p.env_vars
def test_display_metadata_present(self, fireworks_profile):
# Prominence copy is surfaced in the picker; keep it non-empty rather
@@ -40,13 +39,10 @@ class TestFireworksIdentity:
assert fireworks_profile.signup_url.startswith("https://")
-class TestFireworksAttributionHeaders:
- """The profile carries the partner-attribution headers Fireworks captures."""
-
- def test_referer_and_title_headers(self, fireworks_profile):
- headers = fireworks_profile.default_headers
- assert headers.get("HTTP-Referer") == "https://hermes-agent.nousresearch.com"
- assert headers.get("X-Title") == "Hermes Agent"
+class TestFireworksHeaders:
+ def test_no_partner_attribution_headers(self, fireworks_profile):
+ assert "HTTP-Referer" not in fireworks_profile.default_headers
+ assert "X-Title" not in fireworks_profile.default_headers
class TestFireworksAliases:
diff --git a/tests/run_agent/test_fireworks_live.py b/tests/run_agent/test_fireworks_live.py
index 7f2abfd1de9..9e2944ef98c 100644
--- a/tests/run_agent/test_fireworks_live.py
+++ b/tests/run_agent/test_fireworks_live.py
@@ -6,7 +6,7 @@ Opt-in only:
Unlike a bare OpenAI() client pointed at the endpoint, this drives Hermes'
own provider resolution — ``resolve_provider_client('fireworks')`` — so it
-verifies the auth/config/base-URL/attribution-header/aux-model wiring that the
+verifies the auth/config/base-URL/aux-model wiring that the
bundled provider actually ships, then makes a real call through that client.
"""
@@ -51,8 +51,6 @@ def test_fireworks_basic_chat_through_runtime():
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": "Say exactly the word 'pong' and nothing else."}],
- max_tokens=32,
- temperature=0.0,
timeout=60,
)
diff --git a/website/docs/getting-started/quickstart.md b/website/docs/getting-started/quickstart.md
index 907af9c2402..2b390b3edef 100644
--- a/website/docs/getting-started/quickstart.md
+++ b/website/docs/getting-started/quickstart.md
@@ -113,6 +113,7 @@ Good defaults:
| **OpenAI Codex** | ChatGPT OAuth, uses Codex models | Device code auth via `hermes model` |
| **Anthropic** | Claude models directly — Max plan + extra usage credits (OAuth), or API key for pay-per-token | `hermes model` → OAuth login (requires Max + extra credits), or an Anthropic API key |
| **OpenRouter** | Multi-provider routing across many models | Enter your API key |
+| **Fireworks AI** | Direct OpenAI-compatible model API | Set `FIREWORKS_API_KEY` |
| **Z.AI** | GLM / Zhipu-hosted models | Set `GLM_API_KEY` / `ZAI_API_KEY` (also accepts `Z_AI_API_KEY`) |
| **Kimi / Moonshot** | Moonshot-hosted coding and chat models | Set `KIMI_API_KEY` (or the Kimi-Coding-specific `KIMI_CODING_API_KEY`) |
| **Kimi / Moonshot China** | China-region Moonshot endpoint | Set `KIMI_CN_API_KEY` |
diff --git a/website/docs/integrations/providers.md b/website/docs/integrations/providers.md
index a49b15d04de..d07d27e22b3 100644
--- a/website/docs/integrations/providers.md
+++ b/website/docs/integrations/providers.md
@@ -20,6 +20,7 @@ You need at least one way to connect to an LLM. Use `hermes model` to switch pro
| **GitHub Copilot ACP** | `hermes model` (spawns local `copilot --acp --stdio`) |
| **Anthropic** | `hermes model` (Claude Max + extra usage credits via OAuth; also supports Anthropic API key or manual setup-token — see note below) |
| **OpenRouter** | `OPENROUTER_API_KEY` in `~/.hermes/.env` |
+| **Fireworks AI** | `FIREWORKS_API_KEY` in `~/.hermes/.env` (provider: `fireworks`; aliases: `fireworks-ai`, `fw`) |
| **NovitaAI** | `NOVITA_API_KEY` in `~/.hermes/.env` (provider: `novita`, 200+ models, Model API, Agent Sandbox, GPU Cloud) |
| **z.ai / GLM** | `GLM_API_KEY` in `~/.hermes/.env` (provider: `zai`) |
| **Kimi / Moonshot** | `KIMI_API_KEY` in `~/.hermes/.env` (provider: `kimi-coding`) |
@@ -214,6 +215,10 @@ model:
These providers have built-in support with dedicated provider IDs. Set the API key and use `--provider` to select:
```bash
+# Fireworks AI
+hermes chat --provider fireworks --model accounts/fireworks/models/kimi-k2p6
+# Requires: FIREWORKS_API_KEY in ~/.hermes/.env
+
# NovitaAI Model API
hermes chat --provider novita --model moonshotai/kimi-k2.5
# Requires: NOVITA_API_KEY in ~/.hermes/.env
@@ -260,6 +265,8 @@ hermes chat --provider gmi --model zai-org/GLM-5.1-FP8
# Requires: GMI_API_KEY in ~/.hermes/.env
```
+Fireworks uses its native slash-form catalog IDs, such as `accounts/fireworks/models/kimi-k2p6`. Run `hermes model`, choose **Fireworks AI**, and select from the live catalog or enter another Fireworks model ID. The default endpoint is `https://api.fireworks.ai/inference/v1`; configure a different endpoint through `model.base_url` in `config.yaml`, not `.env`.
+
Or set the provider permanently in `config.yaml`:
```yaml
model:
diff --git a/website/docs/reference/environment-variables.md b/website/docs/reference/environment-variables.md
index b7df6823837..53f7a18a0be 100644
--- a/website/docs/reference/environment-variables.md
+++ b/website/docs/reference/environment-variables.md
@@ -14,6 +14,7 @@ Hermes reads environment variables from the process environment and, for user-ma
|----------|-------------|
| `OPENROUTER_API_KEY` | OpenRouter API key (recommended for flexibility) |
| `OPENROUTER_BASE_URL` | Override the OpenRouter-compatible base URL |
+| `FIREWORKS_API_KEY` | Fireworks AI API key ([app.fireworks.ai](https://app.fireworks.ai/settings/users/api-keys)). Configure endpoint overrides with `model.base_url` in `config.yaml`. |
| `HERMES_OPENROUTER_CACHE` | Enable OpenRouter response caching (`1`/`true`/`yes`/`on`). Overrides `openrouter.response_cache` in config.yaml. See [Response Caching](https://openrouter.ai/docs/guides/features/response-caching). |
| `HERMES_OPENROUTER_CACHE_TTL` | Cache TTL in seconds (1-86400). Overrides `openrouter.response_cache_ttl` in config.yaml. |
| `NOUS_BASE_URL` | Override Nous Portal base URL (rarely needed; development/testing only) |
diff --git a/website/docs/user-guide/configuration.md b/website/docs/user-guide/configuration.md
index 46afc11bcfd..269b7cff44c 100644
--- a/website/docs/user-guide/configuration.md
+++ b/website/docs/user-guide/configuration.md
@@ -1170,7 +1170,7 @@ These options apply to **auxiliary task configs** (`auxiliary:`, `compression:`)
| `"xai-oauth"` | Force xAI Grok OAuth (browser login for SuperGrok or X Premium+ subscribers, no API key). Same OAuth token covers chat, TTS, image, video, and transcription. | `hermes model` → xAI Grok OAuth (SuperGrok / Premium+) |
| `"main"` | Use your active custom/main endpoint. This can come from `OPENAI_BASE_URL` + `OPENAI_API_KEY` or from a custom endpoint saved via `hermes model` / `config.yaml`. Works with OpenAI, local models, or any OpenAI-compatible API. **Auxiliary tasks only — not valid for `model.provider`.** | Custom endpoint credentials + base URL |
-Direct API-key providers from the main provider catalog also work here when you want side tasks to bypass your default router. `gmi` is valid once `GMI_API_KEY` is configured:
+Direct API-key providers from the main provider catalog also work here when you want side tasks to bypass your default router. For example, `gmi` is valid once `GMI_API_KEY` is configured, and `fireworks` is valid once `FIREWORKS_API_KEY` is configured:
```yaml
auxiliary:
@@ -1179,7 +1179,7 @@ auxiliary:
model: "anthropic/claude-opus-4.6"
```
-For GMI auxiliary routing, use the exact model ID returned by GMI's `/v1/models` endpoint.
+For GMI auxiliary routing, use the exact model ID returned by GMI's `/v1/models` endpoint. Fireworks model IDs use the provider's native slash form, for example `accounts/fireworks/models/glm-5p2`.
### Common Setups