diff --git a/src/commands/login/login.tsx b/src/commands/login/login.tsx
index a7419473..7435fdbd 100644
--- a/src/commands/login/login.tsx
+++ b/src/commands/login/login.tsx
@@ -11,6 +11,7 @@ import { ConfigurableShortcutHint } from '../../components/ConfigurableShortcutH
import { ConsoleOAuthFlow } from '../../components/ConsoleOAuthFlow.js'
import { Select } from '../../components/CustomSelect/select.js'
import { Dialog } from '../../components/design-system/Dialog.js'
+import { FirepassLoginFlow } from '../../components/FirepassLoginFlow.js'
import { OpenAILoginFlow } from '../../components/OpenAILoginFlow.js'
import { OpenRouterLoginFlow } from '../../components/OpenRouterLoginFlow.js'
import { useMainLoopModel } from '../../hooks/useMainLoopModel.js'
@@ -29,7 +30,7 @@ import {
} from '../../utils/permissions/bypassPermissionsKillswitch.js'
import { resetUserCache } from '../../utils/user.js'
-type AuthProviderChoice = 'anthropic' | 'openai' | 'openrouter'
+type AuthProviderChoice = 'anthropic' | 'openai' | 'openrouter' | 'firepass'
export async function call(
onDone: LocalJSXCommandOnDone,
@@ -124,6 +125,18 @@ export function Login(props: {
),
value: 'openrouter',
},
+ {
+ label: (
+
+ FirePass{' '}
+
+ Fireworks API key with Kimi K2.5 Turbo subscription
+
+ {'\n'}
+
+ ),
+ value: 'firepass',
+ },
],
[],
)
@@ -162,6 +175,11 @@ export function Login(props: {
onDone={onFlowDone}
startingMessage="Better-Clawd can use OpenRouter with your OpenRouter API key."
/>
+ ) : selectedProvider === 'firepass' ? (
+
) : (
void
+ startingMessage?: string
+}
+
+export function FirepassLoginFlow({
+ onDone,
+ startingMessage,
+}: FirepassLoginFlowProps): React.ReactNode {
+ const [isBusy, setIsBusy] = useState(false)
+ const [status, setStatus] = useState(null)
+ const [inputValue, setInputValue] = useState('')
+ const [cursorOffset, setCursorOffset] = useState(0)
+
+ async function handleSubmit(value: string): Promise {
+ const trimmed = value.trim()
+ if (!trimmed) {
+ return
+ }
+
+ setIsBusy(true)
+ setStatus(null)
+ try {
+ await saveFirepassApiKey(trimmed)
+ onDone()
+ } catch (error) {
+ setStatus(error instanceof Error ? error.message : String(error))
+ } finally {
+ setIsBusy(false)
+ }
+ }
+
+ if (isBusy) {
+ return (
+
+
+
+ Configuring FirePass login for Better-Clawd...
+
+
+ FirePass uses your Fireworks API key with the Anthropic-compatible
+ endpoint at `https://api.fireworks.ai/inference`.
+
+
+ )
+ }
+
+ return (
+
+
+ {startingMessage ??
+ 'Better-Clawd can use FirePass with your Fireworks API key.'}
+
+
+ FirePass provides subscription-based access to Kimi K2.5 Turbo with no
+ per-token charges. Get FirePass at{' '}
+ https://app.fireworks.ai/fire-pass
+
+
+ Paste your Fireworks API key:
+ {
+ setInputValue('')
+ setCursorOffset(0)
+ }}
+ cursorOffset={cursorOffset}
+ onChangeCursorOffset={setCursorOffset}
+ columns={72}
+ mask="*"
+ />
+
+ {status ? {status} : null}
+
+ Press Enter to save, or Esc{' '}
+ to cancel.
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/services/api/client.ts b/src/services/api/client.ts
index 386f8d79..490344eb 100644
--- a/src/services/api/client.ts
+++ b/src/services/api/client.ts
@@ -6,6 +6,7 @@ import {
getAnthropicApiKey,
getApiKeyFromApiKeyHelper,
getClaudeAIOAuthTokens,
+ getFirepassApiKey,
getOpenAIApiKey,
getOpenRouterApiKey,
isClaudeAISubscriber,
@@ -17,6 +18,7 @@ import { getUserAgent } from 'src/utils/http.js'
import { getSmallFastModel } from 'src/utils/model/model.js'
import {
getAPIProvider,
+ getFirepassBaseUrl,
getOpenAIBaseUrl,
getOpenRouterBaseUrl,
isFirstPartyAnthropicBaseUrl,
@@ -316,6 +318,26 @@ export async function getAnthropicClient({
return new Anthropic(clientConfig)
}
+ if (provider === 'firepass') {
+ // FirePass uses Fireworks AI's Anthropic-compatible endpoint
+ // Requires an active FirePass subscription for the kimi-k2p5-turbo router
+ const firepassKey = apiKey || getFirepassApiKey()
+ if (!firepassKey) {
+ throw new Error(
+ 'FirePass provider selected but no FirePass/Fireworks API key is configured. Set FIREPASS_API_KEY or FIREWORKS_API_KEY.',
+ )
+ }
+
+ const clientConfig: ConstructorParameters[0] = {
+ apiKey: firepassKey,
+ baseURL: getFirepassBaseUrl(),
+ ...ARGS,
+ ...(isDebugToStdErr() && { logger: createStderrLogger() }),
+ }
+
+ return new Anthropic(clientConfig)
+ }
+
if (provider === 'openai') {
await refreshOpenAIAuthTokenIfNeeded()
const openAIKey = apiKey || getOpenAIApiKey()
diff --git a/src/utils/auth.ts b/src/utils/auth.ts
index 5a3d984b..69de610b 100644
--- a/src/utils/auth.ts
+++ b/src/utils/auth.ts
@@ -239,6 +239,12 @@ export type OpenRouterApiKeySource =
| '/login managed OpenRouter key'
| 'none'
+export type FirepassApiKeySource =
+ | 'FIREPASS_API_KEY'
+ | 'FIREWORKS_API_KEY'
+ | '/login managed FirePass key'
+ | 'none'
+
export function getAnthropicApiKey(): null | string {
const { key } = getAnthropicApiKeyWithSource()
return key
@@ -307,10 +313,33 @@ export function getOpenRouterApiKeyWithSource(): {
: { key: null, source: 'none' }
}
+export function getFirepassApiKey(): null | string {
+ return getFirepassApiKeyWithSource().key
+}
+
+export function getFirepassApiKeyWithSource(): {
+ key: null | string
+ source: FirepassApiKeySource
+} {
+ // Check FIREPASS_API_KEY first, then fall back to FIREWORKS_API_KEY
+ if (process.env.FIREPASS_API_KEY) {
+ return { key: process.env.FIREPASS_API_KEY, source: 'FIREPASS_API_KEY' }
+ }
+ if (process.env.FIREWORKS_API_KEY) {
+ return { key: process.env.FIREWORKS_API_KEY, source: 'FIREWORKS_API_KEY' }
+ }
+
+ const key = getGlobalConfig().firepassApiKey
+ return key
+ ? { key, source: '/login managed FirePass key' }
+ : { key: null, source: 'none' }
+}
+
export function getConfiguredAuthProvider():
| 'anthropic'
| 'openrouter'
- | 'openai' {
+ | 'openai'
+ | 'firepass' {
const storedProvider = getGlobalConfig().authProvider
if (storedProvider) {
return storedProvider
@@ -322,6 +351,8 @@ export function getConfiguredAuthProvider():
return 'openrouter'
case 'openai':
return 'openai'
+ case 'firepass':
+ return 'firepass'
default:
return 'anthropic'
}
@@ -1406,6 +1437,19 @@ export async function saveOpenRouterApiKey(apiKey: string): Promise {
}))
}
+export async function saveFirepassApiKey(apiKey: string): Promise {
+ if (!isValidApiKey(apiKey)) {
+ throw new Error(
+ 'Invalid API key format. API key must contain only alphanumeric characters, dashes, and underscores.',
+ )
+ }
+ saveGlobalConfig(current => ({
+ ...current,
+ authProvider: 'firepass',
+ firepassApiKey: apiKey,
+ }))
+}
+
export function isCustomApiKeyApproved(apiKey: string): boolean {
const config = getGlobalConfig()
const normalizedKey = normalizeApiKeyForConfig(apiKey)
diff --git a/src/utils/config.ts b/src/utils/config.ts
index 6fa44486..2057f0ca 100644
--- a/src/utils/config.ts
+++ b/src/utils/config.ts
@@ -221,7 +221,7 @@ export type GlobalConfig = {
approved?: string[]
rejected?: string[]
}
- authProvider?: 'anthropic' | 'openrouter' | 'openai'
+ authProvider?: 'anthropic' | 'openrouter' | 'openai' | 'firepass'
primaryApiKey?: string // Primary API key for the user when no environment variable is set, set via oauth (TODO: rename)
openAiApiKey?: string
openAiAccessToken?: string
@@ -229,6 +229,7 @@ export type GlobalConfig = {
openAiTokenExpiresAt?: number
openAiWorkspaceId?: string
openRouterApiKey?: string
+ firepassApiKey?: string
hasAcknowledgedCostThreshold?: boolean
hasSeenUndercoverAutoNotice?: boolean // ant-only: whether the one-time auto-undercover explainer has been shown
hasSeenUltraplanTerms?: boolean // ant-only: whether the one-time CCR terms notice has been shown in the ultraplan launch dialog
diff --git a/src/utils/http.ts b/src/utils/http.ts
index f875bdd5..bc9e7da8 100644
--- a/src/utils/http.ts
+++ b/src/utils/http.ts
@@ -11,6 +11,7 @@ import { OAUTH_BETA_HEADER } from '../constants/oauth.js'
import {
getAnthropicApiKey,
getClaudeAIOAuthTokens,
+ getFirepassApiKey,
getOpenAIApiKey,
getOpenRouterApiKey,
handleOAuth401Error,
@@ -100,6 +101,22 @@ export function getAuthHeaders(): AuthHeaders {
}
}
+ if (provider === 'firepass') {
+ const apiKey = getFirepassApiKey()
+ if (!apiKey) {
+ return {
+ headers: {},
+ error: 'No FirePass API key available',
+ }
+ }
+ // FirePass uses x-api-key header like Anthropic
+ return {
+ headers: {
+ 'x-api-key': apiKey,
+ },
+ }
+ }
+
if (isClaudeAISubscriber()) {
const oauthTokens = getClaudeAIOAuthTokens()
if (!oauthTokens?.accessToken) {
diff --git a/src/utils/model/model.ts b/src/utils/model/model.ts
index a9f8eb1a..b2337f4a 100644
--- a/src/utils/model/model.ts
+++ b/src/utils/model/model.ts
@@ -109,6 +109,10 @@ export function getDefaultOpusModel(): ModelName {
if (process.env.ANTHROPIC_DEFAULT_OPUS_MODEL) {
return process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
}
+ // FirePass uses Kimi K2.5 Turbo for all model tiers
+ if (getAPIProvider() === 'firepass') {
+ return getModelStrings().opus46
+ }
// 3P providers (Bedrock, Vertex, Foundry) — kept as a separate branch
// even when values match, since 3P availability lags firstParty and
// these will diverge again at the next model launch.
@@ -123,6 +127,10 @@ export function getDefaultSonnetModel(): ModelName {
if (process.env.ANTHROPIC_DEFAULT_SONNET_MODEL) {
return process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
}
+ // FirePass uses Kimi K2.5 Turbo for all model tiers
+ if (getAPIProvider() === 'firepass') {
+ return getModelStrings().sonnet46
+ }
// Default to Sonnet 4.5 for 3P since they may not have 4.6 yet
if (getAPIProvider() !== 'firstParty') {
return getModelStrings().sonnet45
@@ -135,7 +143,10 @@ export function getDefaultHaikuModel(): ModelName {
if (process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL) {
return process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
}
-
+ // FirePass uses Kimi K2.5 Turbo for all model tiers
+ if (getAPIProvider() === 'firepass') {
+ return getModelStrings().haiku45
+ }
// Haiku 4.5 is available on all platforms (first-party, Foundry, Bedrock, Vertex)
return getModelStrings().haiku45
}
@@ -187,6 +198,11 @@ export function getDefaultMainLoopModelSetting(): ModelName | ModelAlias {
)
}
+ // FirePass uses Kimi K2.5 Turbo for all users
+ if (getAPIProvider() === 'firepass') {
+ return getModelStrings().sonnet46 // Returns Kimi K2.5 Turbo
+ }
+
// Max users get Opus as default
if (isMaxSubscriber()) {
return getDefaultOpusModel() + (isOpus1mMergeEnabled() ? '[1m]' : '')
@@ -350,6 +366,10 @@ export function renderModelSetting(setting: ModelName | ModelAlias): string {
* if the model is not recognized as a public model.
*/
export function getPublicModelDisplayName(model: ModelName): string | null {
+ // FirePass Kimi K2.5 Turbo
+ if (model.includes('kimi-k2p5-turbo') || model.includes('kimi-k2.5-turbo')) {
+ return 'Kimi K2.5 Turbo'
+ }
switch (model) {
case getModelStrings().opus46:
return 'Opus 4.6'
@@ -576,6 +596,11 @@ export function getMarketingNameForModel(modelId: string): string | undefined {
return undefined
}
+ // FirePass Kimi K2.5 Turbo
+ if (modelId.includes('kimi-k2p5-turbo') || modelId.includes('kimi-k2.5-turbo')) {
+ return 'Kimi K2.5 Turbo'
+ }
+
const has1m = modelId.toLowerCase().includes('[1m]')
const canonical = getCanonicalName(modelId)
diff --git a/src/utils/model/modelOptions.ts b/src/utils/model/modelOptions.ts
index fa3fd026..fcb16b7c 100644
--- a/src/utils/model/modelOptions.ts
+++ b/src/utils/model/modelOptions.ts
@@ -45,6 +45,7 @@ export type ModelOption = {
export function getDefaultOptionForUser(fastMode = false): ModelOption {
const provider = getAPIProvider()
const isOpenAI = provider === 'openai'
+ const isFirepass = provider === 'firepass'
if (process.env.USER_TYPE === 'ant') {
const currentModel = renderDefaultModelSetting(
getDefaultMainLoopModelSetting(),
@@ -68,6 +69,14 @@ export function getDefaultOptionForUser(fastMode = false): ModelOption {
// PAYG
const is3P = provider !== 'firstParty'
+ if (isFirepass) {
+ return {
+ value: null,
+ label: 'Default (recommended)',
+ description: 'Use Kimi K2.5 Turbo (FirePass subscription)',
+ descriptionForModel: 'Kimi K2.5 Turbo - FirePass subscription with 256K context',
+ }
+ }
return {
value: null,
label: 'Default (recommended)',
@@ -109,6 +118,16 @@ function getSonnet46Option(): ModelOption {
'GPT-5.4 - recommended for most coding and agentic tasks on OpenAI',
}
}
+ if (provider === 'firepass') {
+ const firepassModel = getModelStrings().sonnet46
+ return {
+ value: firepassModel,
+ label: 'Kimi K2.5 Turbo',
+ description: 'Kimi K2.5 Turbo · FirePass subscription model',
+ descriptionForModel:
+ 'Kimi K2.5 Turbo - FirePass subscription with 256K context, no per-token charges',
+ }
+ }
return {
value: is3P ? getModelStrings().sonnet46 : 'sonnet',
label: 'Sonnet',
@@ -156,6 +175,16 @@ function getOpus46Option(fastMode = false): ModelOption {
'GPT-5.4 - most capable OpenAI model for complex coding work',
}
}
+ if (provider === 'firepass') {
+ const firepassModel = getModelStrings().opus46
+ return {
+ value: firepassModel,
+ label: 'Kimi K2.5 Turbo',
+ description: 'Kimi K2.5 Turbo · FirePass subscription model',
+ descriptionForModel:
+ 'Kimi K2.5 Turbo - FirePass subscription with 256K context, no per-token charges',
+ }
+ }
return {
value: is3P ? getModelStrings().opus46 : 'opus',
label: 'Opus',
@@ -176,6 +205,17 @@ export function getSonnet46_1MOption(): ModelOption {
'GPT-5.4 for long-running OpenAI sessions and large codebases',
}
}
+ if (provider === 'firepass') {
+ // FirePass Kimi has 256K context, no need for separate 1M option
+ const firepassModel = getModelStrings().sonnet46
+ return {
+ value: firepassModel,
+ label: 'Kimi K2.5 Turbo',
+ description: 'Kimi K2.5 Turbo · 256K context included',
+ descriptionForModel:
+ 'Kimi K2.5 Turbo - 256K context window for long sessions',
+ }
+ }
return {
value: is3P ? getModelStrings().sonnet46 + '[1m]' : 'sonnet[1m]',
label: 'Sonnet (1M context)',
@@ -197,6 +237,17 @@ export function getOpus46_1MOption(fastMode = false): ModelOption {
'GPT-5.4 for long-running OpenAI sessions and large codebases',
}
}
+ if (provider === 'firepass') {
+ // FirePass Kimi has 256K context, no need for separate 1M option
+ const firepassModel = getModelStrings().opus46
+ return {
+ value: firepassModel,
+ label: 'Kimi K2.5 Turbo',
+ description: 'Kimi K2.5 Turbo · 256K context included',
+ descriptionForModel:
+ 'Kimi K2.5 Turbo - 256K context window for long sessions',
+ }
+ }
return {
value: is3P ? getModelStrings().opus46 + '[1m]' : 'opus[1m]',
label: 'Opus (1M context)',
@@ -234,6 +285,16 @@ function getHaiku45Option(): ModelOption {
'GPT-5.4 Mini - fastest OpenAI option for quick answers and lightweight tasks',
}
}
+ if (provider === 'firepass') {
+ const firepassModel = getModelStrings().haiku45
+ return {
+ value: firepassModel,
+ label: 'Kimi K2.5 Turbo',
+ description: 'Kimi K2.5 Turbo · FirePass subscription model',
+ descriptionForModel:
+ 'Kimi K2.5 Turbo - FirePass subscription with 256K context, no per-token charges',
+ }
+ }
return {
value: 'haiku',
label: 'Haiku',
@@ -255,6 +316,16 @@ function getHaiku35Option(): ModelOption {
'GPT-5.4 Mini - lower latency OpenAI model for simple tasks',
}
}
+ if (provider === 'firepass') {
+ const firepassModel = getModelStrings().haiku35
+ return {
+ value: firepassModel,
+ label: 'Kimi K2.5 Turbo',
+ description: 'Kimi K2.5 Turbo · FirePass subscription model',
+ descriptionForModel:
+ 'Kimi K2.5 Turbo - FirePass subscription with 256K context, no per-token charges',
+ }
+ }
return {
value: 'haiku',
label: 'Haiku',
@@ -405,6 +476,19 @@ function getModelOptionsBase(fastMode = false): ModelOption[] {
return payg1POptions
}
+ // FirePass: Simple list with just Kimi K2.5 Turbo
+ if (getAPIProvider() === 'firepass') {
+ const firepassModel = getModelStrings().sonnet46
+ return [
+ getDefaultOptionForUser(fastMode),
+ {
+ value: firepassModel,
+ label: 'Kimi K2.5 Turbo',
+ description: 'Kimi K2.5 Turbo · 256K context, subscription billing',
+ },
+ ]
+ }
+
// PAYG 3P: Default (Sonnet 4.5) + Sonnet (3P custom) or Sonnet 4.6/1M + Opus (3P custom) or Opus 4.1/Opus 4.6/Opus1M + Haiku + Opus 4.1
const payg3pOptions = [getDefaultOptionForUser(fastMode)]
diff --git a/src/utils/model/modelStrings.ts b/src/utils/model/modelStrings.ts
index 1db7e348..1e2d7fc7 100644
--- a/src/utils/model/modelStrings.ts
+++ b/src/utils/model/modelStrings.ts
@@ -35,10 +35,23 @@ function getBuiltinModelStrings(provider: APIProvider): ModelStrings {
const out = getBuiltinModelStrings('firstParty') as Record
out.sonnet46 =
process.env.OPENROUTER_SONNET_MODEL || 'anthropic/claude-sonnet-4.6'
+ out.opus46 =
process.env.OPENROUTER_OPUS_MODEL || 'anthropic/claude-opus-4.6'
return out as ModelStrings
}
+ if (provider === 'firepass') {
+ // FirePass uses Fireworks AI's Kimi K2.5 Turbo by default
+ // Users can override with FIREPASS_MODEL env var
+ const out = getBuiltinModelStrings('firstParty') as Record
+ const firepassModel =
+ process.env.FIREPASS_MODEL || 'accounts/fireworks/routers/kimi-k2p5-turbo'
+ out.haiku45 = firepassModel
+ out.sonnet46 = firepassModel
+ out.opus46 = firepassModel
+ return out as ModelStrings
+ }
+
const out = {} as ModelStrings
for (const key of MODEL_KEYS) {
out[key] = ALL_MODEL_CONFIGS[key][provider]
diff --git a/src/utils/model/providers.ts b/src/utils/model/providers.ts
index c48dc6f7..615861b6 100644
--- a/src/utils/model/providers.ts
+++ b/src/utils/model/providers.ts
@@ -5,6 +5,7 @@ export type APIProvider =
| 'firstParty'
| 'openrouter'
| 'openai'
+ | 'firepass'
| 'bedrock'
| 'vertex'
| 'foundry'
@@ -20,10 +21,11 @@ function getStoredProviderPreference(): APIProvider | null {
require('../env.js') as typeof import('../env.js')
const raw = readFileSync(getGlobalClaudeFile(), 'utf8')
const config = JSON.parse(raw) as {
- authProvider?: 'anthropic' | 'openrouter' | 'openai'
+ authProvider?: 'anthropic' | 'openrouter' | 'openai' | 'firepass'
openRouterApiKey?: string
openAiApiKey?: string
openAiAccessToken?: string
+ firepassApiKey?: string
}
switch (config.authProvider) {
@@ -33,6 +35,8 @@ function getStoredProviderPreference(): APIProvider | null {
return config.openAiApiKey || config.openAiAccessToken
? 'openai'
: null
+ case 'firepass':
+ return config.firepassApiKey ? 'firepass' : null
case 'anthropic':
return 'firstParty'
default:
@@ -57,6 +61,10 @@ function getExplicitProviderOverride(): APIProvider | null {
return 'openrouter'
case 'openai':
return 'openai'
+ case 'firepass':
+ case 'fire-pass':
+ case 'fire_pass':
+ return 'firepass'
case 'bedrock':
return 'bedrock'
case 'vertex':
@@ -98,6 +106,28 @@ export function isOpenAIConfigured(): boolean {
)
}
+export function isFirepassBaseUrl(baseUrl?: string | null): boolean {
+ if (!baseUrl) {
+ return false
+ }
+ try {
+ const host = new URL(baseUrl).host
+ return host === 'api.fireworks.ai'
+ } catch {
+ return false
+ }
+}
+
+export function isFirepassConfigured(): boolean {
+ return (
+ getExplicitProviderOverride() === 'firepass' ||
+ Boolean(process.env.FIREPASS_API_KEY) ||
+ Boolean(process.env.FIREWORKS_API_KEY) ||
+ isFirepassBaseUrl(process.env.FIREPASS_BASE_URL) ||
+ isFirepassBaseUrl(process.env.ANTHROPIC_BASE_URL)
+ )
+}
+
export function getOpenRouterBaseUrl(): string {
const configuredBaseUrl = process.env.OPENROUTER_BASE_URL
const fallbackBaseUrl = 'https://openrouter.ai/api'
@@ -129,6 +159,35 @@ export function getOpenAIBaseUrl(): string {
return process.env.OPENAI_BASE_URL ?? 'https://api.openai.com/v1'
}
+/**
+ * Get the FirePass base URL for Anthropic-compatible API.
+ * FirePass uses Fireworks AI's inference endpoint with Anthropic compatibility.
+ * Default: https://api.fireworks.ai/inference (Anthropic SDK appends /v1/messages)
+ */
+export function getFirepassBaseUrl(): string {
+ const configuredBaseUrl = process.env.FIREPASS_BASE_URL
+ if (!configuredBaseUrl) {
+ return 'https://api.fireworks.ai/inference'
+ }
+
+ try {
+ const url = new URL(configuredBaseUrl)
+
+ // Normalize path for Anthropic SDK compatibility
+ // SDK appends /v1/messages, so base should be /inference not /inference/v1
+ if (url.host === 'api.fireworks.ai') {
+ const normalizedPath = url.pathname.replace(/\/+$/, '')
+ if (normalizedPath === '/inference/v1' || normalizedPath === '/v1') {
+ url.pathname = '/inference'
+ }
+ }
+
+ return url.toString().replace(/\/$/, '')
+ } catch {
+ return configuredBaseUrl
+ }
+}
+
export function getAPIProvider(): APIProvider {
const explicitProvider = getExplicitProviderOverride()
if (explicitProvider) {
@@ -143,9 +202,11 @@ export function getAPIProvider(): APIProvider {
? 'foundry'
: isOpenAIConfigured()
? 'openai'
- : isOpenRouterConfigured()
- ? 'openrouter'
- : getStoredProviderPreference() ?? 'firstParty'
+ : isFirepassConfigured()
+ ? 'firepass'
+ : isOpenRouterConfigured()
+ ? 'openrouter'
+ : getStoredProviderPreference() ?? 'firstParty'
}
export function getAPIProviderForStatsig(): AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS {
diff --git a/src/utils/status.tsx b/src/utils/status.tsx
index ef4b946e..bc239cd1 100644
--- a/src/utils/status.tsx
+++ b/src/utils/status.tsx
@@ -13,6 +13,7 @@ import { getIdeClientName, type IDEExtensionInstallationStatus, isJetBrainsIde,
import { getClaudeAiUserDefaultModelDescription, modelDisplayString } from './model/model.js';
import {
getAPIProvider,
+ getFirepassBaseUrl,
getOpenAIBaseUrl,
getOpenRouterBaseUrl,
} from './model/providers.js';
@@ -248,6 +249,7 @@ export function buildAPIProviderProperties(): Property[] {
const providerLabel = {
openrouter: 'OpenRouter',
openai: 'OpenAI',
+ firepass: 'FirePass',
bedrock: 'AWS Bedrock',
vertex: 'Google Vertex AI',
foundry: 'Microsoft Foundry'
@@ -275,6 +277,11 @@ export function buildAPIProviderProperties(): Property[] {
label: 'OpenAI base URL',
value: getOpenAIBaseUrl()
});
+ } else if (apiProvider === 'firepass') {
+ properties.push({
+ label: 'FirePass base URL',
+ value: getFirepassBaseUrl()
+ });
} else if (apiProvider === 'bedrock') {
const bedrockBaseUrl = process.env.BEDROCK_BASE_URL;
if (bedrockBaseUrl) {