mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-23 16:55:51 +00:00
gemini模型环境变量分离 provider指令支持切换gemini
This commit is contained in:
31
CLAUDE.md
31
CLAUDE.md
@@ -182,6 +182,37 @@ Feature flag `VOICE_MODE`,dev/build 默认启用。Push-to-Talk 语音输入
|
|||||||
|
|
||||||
关键环境变量:`CLAUDE_CODE_USE_OPENAI`、`OPENAI_API_KEY`、`OPENAI_BASE_URL`、`OPENAI_MODEL`、`OPENAI_DEFAULT_OPUS_MODEL`、`OPENAI_DEFAULT_SONNET_MODEL`、`OPENAI_DEFAULT_HAIKU_MODEL`。详见 `docs/plans/openai-compatibility.md`。
|
关键环境变量:`CLAUDE_CODE_USE_OPENAI`、`OPENAI_API_KEY`、`OPENAI_BASE_URL`、`OPENAI_MODEL`、`OPENAI_DEFAULT_OPUS_MODEL`、`OPENAI_DEFAULT_SONNET_MODEL`、`OPENAI_DEFAULT_HAIKU_MODEL`。详见 `docs/plans/openai-compatibility.md`。
|
||||||
|
|
||||||
|
### Gemini 兼容层
|
||||||
|
|
||||||
|
通过 `CLAUDE_CODE_USE_GEMINI=1` 环境变量或 `modelType: "gemini"` 设置启用,支持 Google Gemini API。独立的环境变量体系,不与 OpenAI 或 Anthropic 配置混杂。
|
||||||
|
|
||||||
|
- **`src/services/api/gemini/`** — client、模型映射、类型定义
|
||||||
|
- **`src/utils/model/providers.ts`** — 添加 `'gemini'` provider 类型
|
||||||
|
- **`src/utils/managedEnvConstants.ts`** — Gemini 专用的 managed env vars
|
||||||
|
|
||||||
|
关键环境变量:
|
||||||
|
- `CLAUDE_CODE_USE_GEMINI` - 启用 Gemini provider
|
||||||
|
- `GEMINI_API_KEY` - API 密钥(必填)
|
||||||
|
- `GEMINI_BASE_URL` - API 端点(可选,默认 `https://generativelanguage.googleapis.com/v1beta`)
|
||||||
|
- `GEMINI_MODEL` - 直接指定模型(最高优先级)
|
||||||
|
- `GEMINI_DEFAULT_HAIKU_MODEL` / `GEMINI_DEFAULT_SONNET_MODEL` / `GEMINI_DEFAULT_OPUS_MODEL` - 按能力级别映射
|
||||||
|
- `GEMINI_DEFAULT_HAIKU_MODEL_NAME` / `DESCRIPTION` / `SUPPORTED_CAPABILITIES` - 显示名称和描述
|
||||||
|
- `GEMINI_SMALL_FAST_MODEL` - 快速任务使用的模型(可选)
|
||||||
|
|
||||||
|
模型映射优先级(`src/services/api/gemini/modelMapping.ts`):
|
||||||
|
1. `GEMINI_MODEL` - 直接覆盖
|
||||||
|
2. `GEMINI_DEFAULT_*_MODEL` - 独立配置(推荐)
|
||||||
|
3. `ANTHROPIC_DEFAULT_*_MODEL` - 向后兼容 fallback(已废弃)
|
||||||
|
4. 原样返回 Anthropic 模型名
|
||||||
|
|
||||||
|
使用示例:
|
||||||
|
```bash
|
||||||
|
export CLAUDE_CODE_USE_GEMINI=1
|
||||||
|
export GEMINI_API_KEY="your-api-key"
|
||||||
|
export GEMINI_DEFAULT_SONNET_MODEL="gemini-2.5-flash"
|
||||||
|
export GEMINI_DEFAULT_OPUS_MODEL="gemini-2.5-pro"
|
||||||
|
```
|
||||||
|
|
||||||
### Key Type Files
|
### Key Type Files
|
||||||
|
|
||||||
- **`src/types/global.d.ts`** — Declares `MACRO`, `BUILD_TARGET`, `BUILD_ENV` and internal Anthropic-only identifiers.
|
- **`src/types/global.d.ts`** — Declares `MACRO`, `BUILD_TARGET`, `BUILD_ENV` and internal Anthropic-only identifiers.
|
||||||
|
|||||||
102
src/commands/__tests__/provider.test.ts
Normal file
102
src/commands/__tests__/provider.test.ts
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import { describe, expect, test, beforeEach, afterEach, mock } from "bun:test";
|
||||||
|
import { readFileSync, writeFileSync } from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
import { homedir } from "os";
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
function getSettingsPath(): string {
|
||||||
|
return path.join(homedir(), ".claude", "settings.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock settings module
|
||||||
|
mock.module("../utils/settings/settings.js", () => ({
|
||||||
|
getInitialSettings: () => ({}),
|
||||||
|
getSettings_DEPRECATED: () => ({}),
|
||||||
|
getSettingsForSource: () => ({}),
|
||||||
|
updateSettingsForSource: () => {},
|
||||||
|
}));
|
||||||
|
mock.module("../utils/managedEnv.js", () => ({
|
||||||
|
applyConfigEnvironmentVariables: () => {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const { default: providerCommand } = await import("../provider.ts");
|
||||||
|
|
||||||
|
describe("provider command", () => {
|
||||||
|
const envKeys = [
|
||||||
|
"CLAUDE_CODE_USE_GEMINI",
|
||||||
|
"CLAUDE_CODE_USE_BEDROCK",
|
||||||
|
"CLAUDE_CODE_USE_VERTEX",
|
||||||
|
"CLAUDE_CODE_USE_FOUNDRY",
|
||||||
|
"CLAUDE_CODE_USE_OPENAI",
|
||||||
|
"GEMINI_API_KEY",
|
||||||
|
"OPENAI_API_KEY",
|
||||||
|
"OPENAI_BASE_URL",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const savedEnv: Record<string, string | undefined> = {};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// Save and clear environment variables
|
||||||
|
for (const key of envKeys) {
|
||||||
|
savedEnv[key] = process.env[key];
|
||||||
|
delete process.env[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
// Restore environment variables
|
||||||
|
for (const key of envKeys) {
|
||||||
|
if (savedEnv[key] !== undefined) {
|
||||||
|
process.env[key] = savedEnv[key];
|
||||||
|
} else {
|
||||||
|
delete process.env[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("validates gemini as a valid provider", async () => {
|
||||||
|
const result = await providerCommand.load().then(cmd => cmd.call("gemini", {} as any));
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
// Should not return an error about invalid provider
|
||||||
|
if (result && typeof result === 'object' && 'value' in result) {
|
||||||
|
expect(result.value as string).toContain("gemini");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("switches to gemini without API key warning", async () => {
|
||||||
|
const result = await providerCommand.load().then(cmd => cmd.call("gemini", {} as any));
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
if (result && typeof result === 'object' && 'value' in result) {
|
||||||
|
const value = result.value as string;
|
||||||
|
// Should either succeed or show warning about missing API key
|
||||||
|
expect(value).toMatch(/API provider set to gemini|Switched to Gemini provider/);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("switches to gemini with API key set", async () => {
|
||||||
|
process.env.GEMINI_API_KEY = "test-key";
|
||||||
|
const result = await providerCommand.load().then(cmd => cmd.call("gemini", {} as any));
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
if (result && typeof result === 'object' && 'value' in result) {
|
||||||
|
const value = result.value as string;
|
||||||
|
expect(value).toContain("API provider set to gemini");
|
||||||
|
expect(value).not.toContain("Warning");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("provider list includes gemini", async () => {
|
||||||
|
// Test that help or description shows gemini is supported
|
||||||
|
expect(providerCommand.description).toContain("gemini");
|
||||||
|
expect(providerCommand.argumentHint).toContain("gemini");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("unset clears gemini env var", async () => {
|
||||||
|
process.env.CLAUDE_CODE_USE_GEMINI = "1";
|
||||||
|
const result = await providerCommand.load().then(cmd => cmd.call("unset", {} as any));
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(process.env.CLAUDE_CODE_USE_GEMINI).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -13,6 +13,8 @@ function getEnvVarForProvider(provider: string): string {
|
|||||||
return 'CLAUDE_CODE_USE_VERTEX'
|
return 'CLAUDE_CODE_USE_VERTEX'
|
||||||
case 'foundry':
|
case 'foundry':
|
||||||
return 'CLAUDE_CODE_USE_FOUNDRY'
|
return 'CLAUDE_CODE_USE_FOUNDRY'
|
||||||
|
case 'gemini':
|
||||||
|
return 'CLAUDE_CODE_USE_GEMINI'
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unknown provider: ${provider}`)
|
throw new Error(`Unknown provider: ${provider}`)
|
||||||
}
|
}
|
||||||
@@ -45,13 +47,27 @@ const call: LocalCommandCall = async (args, context) => {
|
|||||||
delete process.env.CLAUDE_CODE_USE_VERTEX
|
delete process.env.CLAUDE_CODE_USE_VERTEX
|
||||||
delete process.env.CLAUDE_CODE_USE_FOUNDRY
|
delete process.env.CLAUDE_CODE_USE_FOUNDRY
|
||||||
delete process.env.CLAUDE_CODE_USE_OPENAI
|
delete process.env.CLAUDE_CODE_USE_OPENAI
|
||||||
return { type: 'text', value: 'API provider cleared (will use environment variables).' }
|
delete process.env.CLAUDE_CODE_USE_GEMINI
|
||||||
|
return {
|
||||||
|
type: 'text',
|
||||||
|
value: 'API provider cleared (will use environment variables).',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate provider
|
// Validate provider
|
||||||
const validProviders = ['anthropic', 'openai', 'bedrock', 'vertex', 'foundry']
|
const validProviders = [
|
||||||
|
'anthropic',
|
||||||
|
'openai',
|
||||||
|
'gemini',
|
||||||
|
'bedrock',
|
||||||
|
'vertex',
|
||||||
|
'foundry',
|
||||||
|
]
|
||||||
if (!validProviders.includes(arg)) {
|
if (!validProviders.includes(arg)) {
|
||||||
return { type: 'text', value: `Invalid provider: ${arg}\nValid: ${validProviders.join(', ')}` }
|
return {
|
||||||
|
type: 'text',
|
||||||
|
value: `Invalid provider: ${arg}\nValid: ${validProviders.join(', ')}`,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check env vars when switching to openai (including settings.env)
|
// Check env vars when switching to openai (including settings.env)
|
||||||
@@ -71,37 +87,58 @@ const call: LocalCommandCall = async (args, context) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check env vars when switching to gemini (including settings.env)
|
||||||
|
if (arg === 'gemini') {
|
||||||
|
const mergedEnv = getMergedEnv()
|
||||||
|
const hasKey = !!mergedEnv.GEMINI_API_KEY
|
||||||
|
// GEMINI_BASE_URL is optional (has default)
|
||||||
|
if (!hasKey) {
|
||||||
|
updateSettingsForSource('userSettings', { modelType: 'gemini' })
|
||||||
|
return {
|
||||||
|
type: 'text',
|
||||||
|
value: `Switched to Gemini provider.\nWarning: Missing env var: GEMINI_API_KEY\nConfigure it via /login or set manually.`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle different provider types
|
// Handle different provider types
|
||||||
// - 'anthropic' and 'openai' are stored in settings.json (persistent)
|
// - 'anthropic', 'openai', 'gemini' are stored in settings.json (persistent)
|
||||||
// - 'bedrock', 'vertex', 'foundry' are env-only (do NOT touch settings.json)
|
// - 'bedrock', 'vertex', 'foundry' are env-only (do NOT touch settings.json)
|
||||||
if (arg === 'anthropic' || arg === 'openai') {
|
if (arg === 'anthropic' || arg === 'openai' || arg === 'gemini') {
|
||||||
// Clear any cloud provider env vars to avoid conflicts
|
// Clear any cloud provider env vars to avoid conflicts
|
||||||
delete process.env.CLAUDE_CODE_USE_BEDROCK
|
delete process.env.CLAUDE_CODE_USE_BEDROCK
|
||||||
delete process.env.CLAUDE_CODE_USE_VERTEX
|
delete process.env.CLAUDE_CODE_USE_VERTEX
|
||||||
delete process.env.CLAUDE_CODE_USE_FOUNDRY
|
delete process.env.CLAUDE_CODE_USE_FOUNDRY
|
||||||
|
delete process.env.CLAUDE_CODE_USE_OPENAI
|
||||||
|
delete process.env.CLAUDE_CODE_USE_GEMINI
|
||||||
// Update settings.json
|
// Update settings.json
|
||||||
updateSettingsForSource('userSettings', { modelType: arg })
|
updateSettingsForSource('userSettings', { modelType: arg })
|
||||||
// Ensure settings.env gets applied to process.env
|
// Ensure settings.env gets applied to process.env
|
||||||
applyConfigEnvironmentVariables()
|
applyConfigEnvironmentVariables()
|
||||||
return { type: 'text', value: `API provider set to ${arg}.` }
|
return { type: 'text', value: `API provider set to ${arg}.` }
|
||||||
} else {
|
} else {
|
||||||
// Cloud providers: set env vars only, do NOT touch settings.modelType
|
// Cloud providers: set env vars only, do NOT touch settings.json
|
||||||
delete process.env.CLAUDE_CODE_USE_OPENAI
|
delete process.env.CLAUDE_CODE_USE_OPENAI
|
||||||
delete process.env.OPENAI_API_KEY
|
delete process.env.OPENAI_API_KEY
|
||||||
delete process.env.OPENAI_BASE_URL
|
delete process.env.OPENAI_BASE_URL
|
||||||
|
delete process.env.CLAUDE_CODE_USE_GEMINI
|
||||||
process.env[getEnvVarForProvider(arg)] = '1'
|
process.env[getEnvVarForProvider(arg)] = '1'
|
||||||
// Do not modify settings.json - cloud providers controlled solely by env vars
|
// Do not modify settings.json - cloud providers controlled solely by env vars
|
||||||
applyConfigEnvironmentVariables()
|
applyConfigEnvironmentVariables()
|
||||||
return { type: 'text', value: `API provider set to ${arg} (via environment variable).` }
|
return {
|
||||||
|
type: 'text',
|
||||||
|
value: `API provider set to ${arg} (via environment variable).`,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const provider = {
|
const provider = {
|
||||||
type: 'local',
|
type: 'local',
|
||||||
name: 'provider',
|
name: 'provider',
|
||||||
description: 'Switch API provider (anthropic/openai/bedrock/vertex/foundry)',
|
description:
|
||||||
|
'Switch API provider (anthropic/openai/gemini/bedrock/vertex/foundry)',
|
||||||
aliases: ['api'],
|
aliases: ['api'],
|
||||||
argumentHint: '[anthropic|openai|bedrock|vertex|foundry|unset]',
|
argumentHint: '[anthropic|openai|gemini|bedrock|vertex|foundry|unset]',
|
||||||
supportsNonInteractive: true,
|
supportsNonInteractive: true,
|
||||||
load: () => Promise.resolve({ call }),
|
load: () => Promise.resolve({ call }),
|
||||||
} satisfies Command
|
} satisfies Command
|
||||||
|
|||||||
@@ -561,9 +561,9 @@ function OAuthStatusMessage({
|
|||||||
state: 'gemini_api',
|
state: 'gemini_api',
|
||||||
baseUrl: process.env.GEMINI_BASE_URL ?? '',
|
baseUrl: process.env.GEMINI_BASE_URL ?? '',
|
||||||
apiKey: process.env.GEMINI_API_KEY ?? '',
|
apiKey: process.env.GEMINI_API_KEY ?? '',
|
||||||
haikuModel: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL ?? '',
|
haikuModel: process.env.GEMINI_DEFAULT_HAIKU_MODEL ?? '',
|
||||||
sonnetModel: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL ?? '',
|
sonnetModel: process.env.GEMINI_DEFAULT_SONNET_MODEL ?? '',
|
||||||
opusModel: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL ?? '',
|
opusModel: process.env.GEMINI_DEFAULT_OPUS_MODEL ?? '',
|
||||||
activeField: 'base_url',
|
activeField: 'base_url',
|
||||||
})
|
})
|
||||||
} else if (value === 'platform') {
|
} else if (value === 'platform') {
|
||||||
@@ -1127,9 +1127,9 @@ function OAuthStatusMessage({
|
|||||||
const env: Record<string, string> = {}
|
const env: Record<string, string> = {}
|
||||||
if (finalVals.base_url) env.GEMINI_BASE_URL = finalVals.base_url
|
if (finalVals.base_url) env.GEMINI_BASE_URL = finalVals.base_url
|
||||||
if (finalVals.api_key) env.GEMINI_API_KEY = finalVals.api_key
|
if (finalVals.api_key) env.GEMINI_API_KEY = finalVals.api_key
|
||||||
if (finalVals.haiku_model) env.ANTHROPIC_DEFAULT_HAIKU_MODEL = finalVals.haiku_model
|
if (finalVals.haiku_model) env.GEMINI_DEFAULT_HAIKU_MODEL = finalVals.haiku_model
|
||||||
if (finalVals.sonnet_model) env.ANTHROPIC_DEFAULT_SONNET_MODEL = finalVals.sonnet_model
|
if (finalVals.sonnet_model) env.GEMINI_DEFAULT_SONNET_MODEL = finalVals.sonnet_model
|
||||||
if (finalVals.opus_model) env.ANTHROPIC_DEFAULT_OPUS_MODEL = finalVals.opus_model
|
if (finalVals.opus_model) env.GEMINI_DEFAULT_OPUS_MODEL = finalVals.opus_model
|
||||||
const { error } = updateSettingsForSource('userSettings', {
|
const { error } = updateSettingsForSource('userSettings', {
|
||||||
modelType: 'gemini' as any,
|
modelType: 'gemini' as any,
|
||||||
env,
|
env,
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import { resolveGeminiModel } from '../modelMapping.js'
|
|||||||
describe('resolveGeminiModel', () => {
|
describe('resolveGeminiModel', () => {
|
||||||
const originalEnv = {
|
const originalEnv = {
|
||||||
GEMINI_MODEL: process.env.GEMINI_MODEL,
|
GEMINI_MODEL: process.env.GEMINI_MODEL,
|
||||||
|
GEMINI_DEFAULT_HAIKU_MODEL: process.env.GEMINI_DEFAULT_HAIKU_MODEL,
|
||||||
|
GEMINI_DEFAULT_SONNET_MODEL: process.env.GEMINI_DEFAULT_SONNET_MODEL,
|
||||||
|
GEMINI_DEFAULT_OPUS_MODEL: process.env.GEMINI_DEFAULT_OPUS_MODEL,
|
||||||
ANTHROPIC_DEFAULT_HAIKU_MODEL: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL,
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL,
|
||||||
ANTHROPIC_DEFAULT_SONNET_MODEL: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL,
|
ANTHROPIC_DEFAULT_SONNET_MODEL: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL,
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL,
|
ANTHROPIC_DEFAULT_OPUS_MODEL: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL,
|
||||||
@@ -11,6 +14,9 @@ describe('resolveGeminiModel', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
delete process.env.GEMINI_MODEL
|
delete process.env.GEMINI_MODEL
|
||||||
|
delete process.env.GEMINI_DEFAULT_HAIKU_MODEL
|
||||||
|
delete process.env.GEMINI_DEFAULT_SONNET_MODEL
|
||||||
|
delete process.env.GEMINI_DEFAULT_OPUS_MODEL
|
||||||
delete process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
delete process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
||||||
delete process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
delete process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
||||||
delete process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
delete process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
||||||
@@ -27,35 +33,57 @@ describe('resolveGeminiModel', () => {
|
|||||||
expect(resolveGeminiModel('claude-sonnet-4-6')).toBe('gemini-2.5-pro')
|
expect(resolveGeminiModel('claude-sonnet-4-6')).toBe('gemini-2.5-pro')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('resolves sonnet model from shared family override', () => {
|
test('GEMINI_DEFAULT_*_MODEL takes precedence over ANTHROPIC_DEFAULT_*', () => {
|
||||||
|
process.env.GEMINI_DEFAULT_SONNET_MODEL = 'gemini-2.5-flash-priority'
|
||||||
|
process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'gemini-2.5-flash-fallback'
|
||||||
|
|
||||||
|
expect(resolveGeminiModel('claude-sonnet-4-6')).toBe(
|
||||||
|
'gemini-2.5-flash-priority',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('resolves sonnet model from GEMINI_DEFAULT_SONNET_MODEL', () => {
|
||||||
|
process.env.GEMINI_DEFAULT_SONNET_MODEL = 'gemini-2.5-flash'
|
||||||
|
expect(resolveGeminiModel('claude-sonnet-4-6')).toBe('gemini-2.5-flash')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('resolves haiku model from GEMINI_DEFAULT_HAIKU_MODEL', () => {
|
||||||
|
process.env.GEMINI_DEFAULT_HAIKU_MODEL = 'gemini-2.5-flash-lite'
|
||||||
|
expect(resolveGeminiModel('claude-haiku-4-5-20251001')).toBe(
|
||||||
|
'gemini-2.5-flash-lite',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('resolves opus model from GEMINI_DEFAULT_OPUS_MODEL', () => {
|
||||||
|
process.env.GEMINI_DEFAULT_OPUS_MODEL = 'gemini-2.5-pro'
|
||||||
|
expect(resolveGeminiModel('claude-opus-4-6')).toBe('gemini-2.5-pro')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('falls back to ANTHROPIC_DEFAULT_* when GEMINI_DEFAULT_* not set', () => {
|
||||||
process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'gemini-2.5-flash'
|
process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'gemini-2.5-flash'
|
||||||
expect(resolveGeminiModel('claude-sonnet-4-6')).toBe('gemini-2.5-flash')
|
expect(resolveGeminiModel('claude-sonnet-4-6')).toBe('gemini-2.5-flash')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('resolves haiku model from shared family override', () => {
|
test('resolves haiku from ANTHROPIC_DEFAULT_HAIKU_MODEL as fallback', () => {
|
||||||
process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = 'gemini-2.5-flash-lite'
|
process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = 'gemini-2.5-flash-lite'
|
||||||
expect(resolveGeminiModel('claude-haiku-4-5-20251001')).toBe(
|
expect(resolveGeminiModel('claude-haiku-4-5-20251001')).toBe(
|
||||||
'gemini-2.5-flash-lite',
|
'gemini-2.5-flash-lite',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('resolves opus model from shared family override', () => {
|
test('resolves opus from ANTHROPIC_DEFAULT_OPUS_MODEL as fallback', () => {
|
||||||
process.env.ANTHROPIC_DEFAULT_OPUS_MODEL = 'gemini-2.5-pro'
|
process.env.ANTHROPIC_DEFAULT_OPUS_MODEL = 'gemini-2.5-pro'
|
||||||
expect(resolveGeminiModel('claude-opus-4-6')).toBe('gemini-2.5-pro')
|
expect(resolveGeminiModel('claude-opus-4-6')).toBe('gemini-2.5-pro')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('uses shared family override', () => {
|
test('uses backward compatible family override', () => {
|
||||||
process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'legacy-gemini-sonnet'
|
process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'legacy-gemini-sonnet'
|
||||||
expect(resolveGeminiModel('claude-sonnet-4-6')).toBe(
|
expect(resolveGeminiModel('claude-sonnet-4-6')).toBe('legacy-gemini-sonnet')
|
||||||
'legacy-gemini-sonnet',
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('strips [1m] suffix before resolving', () => {
|
test('strips [1m] suffix before resolving', () => {
|
||||||
process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'gemini-2.5-flash'
|
process.env.GEMINI_DEFAULT_SONNET_MODEL = 'gemini-2.5-flash'
|
||||||
expect(resolveGeminiModel('claude-sonnet-4-6[1m]')).toBe(
|
expect(resolveGeminiModel('claude-sonnet-4-6[1m]')).toBe('gemini-2.5-flash')
|
||||||
'gemini-2.5-flash',
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('passes through explicit Gemini model names', () => {
|
test('passes through explicit Gemini model names', () => {
|
||||||
@@ -64,9 +92,9 @@ describe('resolveGeminiModel', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('throws when family mapping is missing', () => {
|
test('throws when no Gemini model configuration is available', () => {
|
||||||
expect(() => resolveGeminiModel('claude-sonnet-4-6')).toThrow(
|
expect(() => resolveGeminiModel('claude-sonnet-4-6')).toThrow(
|
||||||
'Gemini provider requires GEMINI_MODEL or ANTHROPIC_DEFAULT_SONNET_MODEL to be configured.',
|
'Gemini provider requires GEMINI_MODEL or GEMINI_DEFAULT_SONNET_MODEL (or ANTHROPIC_DEFAULT_SONNET_MODEL for backward compatibility) to be configured.',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -17,6 +17,14 @@ export function resolveGeminiModel(anthropicModel: string): string {
|
|||||||
return cleanModel
|
return cleanModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First, try Gemini-specific DEFAULT variables (separated from Anthropic)
|
||||||
|
const geminiEnvVar = `GEMINI_DEFAULT_${family.toUpperCase()}_MODEL`
|
||||||
|
const geminiModel = process.env[geminiEnvVar]
|
||||||
|
if (geminiModel) {
|
||||||
|
return geminiModel
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to Anthropic DEFAULT variables for backward compatibility
|
||||||
const sharedEnvVar = `ANTHROPIC_DEFAULT_${family.toUpperCase()}_MODEL`
|
const sharedEnvVar = `ANTHROPIC_DEFAULT_${family.toUpperCase()}_MODEL`
|
||||||
const resolvedModel = process.env[sharedEnvVar]
|
const resolvedModel = process.env[sharedEnvVar]
|
||||||
if (resolvedModel) {
|
if (resolvedModel) {
|
||||||
@@ -24,7 +32,6 @@ export function resolveGeminiModel(anthropicModel: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Gemini provider requires GEMINI_MODEL or ${sharedEnvVar} to be configured.`,
|
`Gemini provider requires GEMINI_MODEL or ${geminiEnvVar} (or ${sharedEnvVar} for backward compatibility) to be configured.`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,20 @@ const PROVIDER_MANAGED_ENV_VARS = new Set([
|
|||||||
'ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION',
|
'ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION',
|
||||||
'CLAUDE_CODE_SUBAGENT_MODEL',
|
'CLAUDE_CODE_SUBAGENT_MODEL',
|
||||||
'GEMINI_MODEL',
|
'GEMINI_MODEL',
|
||||||
|
'GEMINI_SMALL_FAST_MODEL',
|
||||||
|
// Gemini provider specific - separate from Anthropic/OpenAI
|
||||||
|
'GEMINI_DEFAULT_HAIKU_MODEL',
|
||||||
|
'GEMINI_DEFAULT_HAIKU_MODEL_DESCRIPTION',
|
||||||
|
'GEMINI_DEFAULT_HAIKU_MODEL_NAME',
|
||||||
|
'GEMINI_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES',
|
||||||
|
'GEMINI_DEFAULT_OPUS_MODEL',
|
||||||
|
'GEMINI_DEFAULT_OPUS_MODEL_DESCRIPTION',
|
||||||
|
'GEMINI_DEFAULT_OPUS_MODEL_NAME',
|
||||||
|
'GEMINI_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES',
|
||||||
|
'GEMINI_DEFAULT_SONNET_MODEL',
|
||||||
|
'GEMINI_DEFAULT_SONNET_MODEL_DESCRIPTION',
|
||||||
|
'GEMINI_DEFAULT_SONNET_MODEL_NAME',
|
||||||
|
'GEMINI_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES',
|
||||||
])
|
])
|
||||||
|
|
||||||
const PROVIDER_MANAGED_ENV_PREFIXES = [
|
const PROVIDER_MANAGED_ENV_PREFIXES = [
|
||||||
@@ -188,6 +202,19 @@ export const SAFE_ENV_VARS = new Set([
|
|||||||
'CLAUDE_CODE_USE_GEMINI',
|
'CLAUDE_CODE_USE_GEMINI',
|
||||||
'CLAUDE_CODE_USE_VERTEX',
|
'CLAUDE_CODE_USE_VERTEX',
|
||||||
'GEMINI_MODEL',
|
'GEMINI_MODEL',
|
||||||
|
'GEMINI_SMALL_FAST_MODEL',
|
||||||
|
'GEMINI_DEFAULT_HAIKU_MODEL',
|
||||||
|
'GEMINI_DEFAULT_HAIKU_MODEL_DESCRIPTION',
|
||||||
|
'GEMINI_DEFAULT_HAIKU_MODEL_NAME',
|
||||||
|
'GEMINI_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES',
|
||||||
|
'GEMINI_DEFAULT_OPUS_MODEL',
|
||||||
|
'GEMINI_DEFAULT_OPUS_MODEL_DESCRIPTION',
|
||||||
|
'GEMINI_DEFAULT_OPUS_MODEL_NAME',
|
||||||
|
'GEMINI_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES',
|
||||||
|
'GEMINI_DEFAULT_SONNET_MODEL',
|
||||||
|
'GEMINI_DEFAULT_SONNET_MODEL_DESCRIPTION',
|
||||||
|
'GEMINI_DEFAULT_SONNET_MODEL_NAME',
|
||||||
|
'GEMINI_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES',
|
||||||
'DISABLE_AUTOUPDATER',
|
'DISABLE_AUTOUPDATER',
|
||||||
'DISABLE_BUG_COMMAND',
|
'DISABLE_BUG_COMMAND',
|
||||||
'DISABLE_COST_WARNINGS',
|
'DISABLE_COST_WARNINGS',
|
||||||
|
|||||||
@@ -35,6 +35,15 @@ export type ModelName = string
|
|||||||
export type ModelSetting = ModelName | ModelAlias | null
|
export type ModelSetting = ModelName | ModelAlias | null
|
||||||
|
|
||||||
export function getSmallFastModel(): ModelName {
|
export function getSmallFastModel(): ModelName {
|
||||||
|
const provider = getAPIProvider()
|
||||||
|
// Provider-specific small fast model
|
||||||
|
if (provider === 'openai' && process.env.OPENAI_SMALL_FAST_MODEL) {
|
||||||
|
return process.env.OPENAI_SMALL_FAST_MODEL
|
||||||
|
}
|
||||||
|
if (provider === 'gemini' && process.env.GEMINI_SMALL_FAST_MODEL) {
|
||||||
|
return process.env.GEMINI_SMALL_FAST_MODEL
|
||||||
|
}
|
||||||
|
// Anthropic-specific or fallback
|
||||||
return process.env.ANTHROPIC_SMALL_FAST_MODEL || getDefaultHaikuModel()
|
return process.env.ANTHROPIC_SMALL_FAST_MODEL || getDefaultHaikuModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,10 +113,15 @@ export function getBestModel(): ModelName {
|
|||||||
|
|
||||||
// @[MODEL LAUNCH]: Update the default Opus model (3P providers may lag so keep defaults unchanged).
|
// @[MODEL LAUNCH]: Update the default Opus model (3P providers may lag so keep defaults unchanged).
|
||||||
export function getDefaultOpusModel(): ModelName {
|
export function getDefaultOpusModel(): ModelName {
|
||||||
|
const provider = getAPIProvider()
|
||||||
// For OpenAI provider, check OPENAI_DEFAULT_OPUS_MODEL first
|
// For OpenAI provider, check OPENAI_DEFAULT_OPUS_MODEL first
|
||||||
if (getAPIProvider() === 'openai' && process.env.OPENAI_DEFAULT_OPUS_MODEL) {
|
if (provider === 'openai' && process.env.OPENAI_DEFAULT_OPUS_MODEL) {
|
||||||
return process.env.OPENAI_DEFAULT_OPUS_MODEL
|
return process.env.OPENAI_DEFAULT_OPUS_MODEL
|
||||||
}
|
}
|
||||||
|
// For Gemini provider, check GEMINI_DEFAULT_OPUS_MODEL
|
||||||
|
if (provider === 'gemini' && process.env.GEMINI_DEFAULT_OPUS_MODEL) {
|
||||||
|
return process.env.GEMINI_DEFAULT_OPUS_MODEL
|
||||||
|
}
|
||||||
// Anthropic-specific override (for first-party and other 3P providers)
|
// Anthropic-specific override (for first-party and other 3P providers)
|
||||||
if (process.env.ANTHROPIC_DEFAULT_OPUS_MODEL) {
|
if (process.env.ANTHROPIC_DEFAULT_OPUS_MODEL) {
|
||||||
return process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
return process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
||||||
@@ -115,7 +129,7 @@ export function getDefaultOpusModel(): ModelName {
|
|||||||
// 3P providers (Bedrock, Vertex, Foundry) — kept as a separate branch
|
// 3P providers (Bedrock, Vertex, Foundry) — kept as a separate branch
|
||||||
// even when values match, since 3P availability lags firstParty and
|
// even when values match, since 3P availability lags firstParty and
|
||||||
// these will diverge again at the next model launch.
|
// these will diverge again at the next model launch.
|
||||||
if (getAPIProvider() !== 'firstParty') {
|
if (provider !== 'firstParty') {
|
||||||
return getModelStrings().opus46
|
return getModelStrings().opus46
|
||||||
}
|
}
|
||||||
return getModelStrings().opus46
|
return getModelStrings().opus46
|
||||||
@@ -123,19 +137,24 @@ export function getDefaultOpusModel(): ModelName {
|
|||||||
|
|
||||||
// @[MODEL LAUNCH]: Update the default Sonnet model (3P providers may lag so keep defaults unchanged).
|
// @[MODEL LAUNCH]: Update the default Sonnet model (3P providers may lag so keep defaults unchanged).
|
||||||
export function getDefaultSonnetModel(): ModelName {
|
export function getDefaultSonnetModel(): ModelName {
|
||||||
|
const provider = getAPIProvider()
|
||||||
// For OpenAI provider, check OPENAI_DEFAULT_SONNET_MODEL first
|
// For OpenAI provider, check OPENAI_DEFAULT_SONNET_MODEL first
|
||||||
if (
|
if (
|
||||||
getAPIProvider() === 'openai' &&
|
provider === 'openai' &&
|
||||||
process.env.OPENAI_DEFAULT_SONNET_MODEL
|
process.env.OPENAI_DEFAULT_SONNET_MODEL
|
||||||
) {
|
) {
|
||||||
return process.env.OPENAI_DEFAULT_SONNET_MODEL
|
return process.env.OPENAI_DEFAULT_SONNET_MODEL
|
||||||
}
|
}
|
||||||
|
// For Gemini provider, check GEMINI_DEFAULT_SONNET_MODEL
|
||||||
|
if (provider === 'gemini' && process.env.GEMINI_DEFAULT_SONNET_MODEL) {
|
||||||
|
return process.env.GEMINI_DEFAULT_SONNET_MODEL
|
||||||
|
}
|
||||||
// Anthropic-specific override (for first-party and other 3P providers)
|
// Anthropic-specific override (for first-party and other 3P providers)
|
||||||
if (process.env.ANTHROPIC_DEFAULT_SONNET_MODEL) {
|
if (process.env.ANTHROPIC_DEFAULT_SONNET_MODEL) {
|
||||||
return process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
return process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
||||||
}
|
}
|
||||||
// Default to Sonnet 4.5 for 3P since they may not have 4.6 yet
|
// Default to Sonnet 4.5 for 3P since they may not have 4.6 yet
|
||||||
if (getAPIProvider() !== 'firstParty') {
|
if (provider !== 'firstParty') {
|
||||||
return getModelStrings().sonnet45
|
return getModelStrings().sonnet45
|
||||||
}
|
}
|
||||||
return getModelStrings().sonnet46
|
return getModelStrings().sonnet46
|
||||||
@@ -143,10 +162,15 @@ export function getDefaultSonnetModel(): ModelName {
|
|||||||
|
|
||||||
// @[MODEL LAUNCH]: Update the default Haiku model (3P providers may lag so keep defaults unchanged).
|
// @[MODEL LAUNCH]: Update the default Haiku model (3P providers may lag so keep defaults unchanged).
|
||||||
export function getDefaultHaikuModel(): ModelName {
|
export function getDefaultHaikuModel(): ModelName {
|
||||||
|
const provider = getAPIProvider()
|
||||||
// For OpenAI provider, check OPENAI_DEFAULT_HAIKU_MODEL first
|
// For OpenAI provider, check OPENAI_DEFAULT_HAIKU_MODEL first
|
||||||
if (getAPIProvider() === 'openai' && process.env.OPENAI_DEFAULT_HAIKU_MODEL) {
|
if (provider === 'openai' && process.env.OPENAI_DEFAULT_HAIKU_MODEL) {
|
||||||
return process.env.OPENAI_DEFAULT_HAIKU_MODEL
|
return process.env.OPENAI_DEFAULT_HAIKU_MODEL
|
||||||
}
|
}
|
||||||
|
// For Gemini provider, check GEMINI_DEFAULT_HAIKU_MODEL
|
||||||
|
if (provider === 'gemini' && process.env.GEMINI_DEFAULT_HAIKU_MODEL) {
|
||||||
|
return process.env.GEMINI_DEFAULT_HAIKU_MODEL
|
||||||
|
}
|
||||||
// Anthropic-specific override (for first-party and other 3P providers)
|
// Anthropic-specific override (for first-party and other 3P providers)
|
||||||
if (process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL) {
|
if (process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL) {
|
||||||
return process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
return process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
||||||
|
|||||||
@@ -76,22 +76,29 @@ export function getDefaultOptionForUser(fastMode = false): ModelOption {
|
|||||||
|
|
||||||
function getCustomSonnetOption(): ModelOption | undefined {
|
function getCustomSonnetOption(): ModelOption | undefined {
|
||||||
const is3P = getAPIProvider() !== 'firstParty'
|
const is3P = getAPIProvider() !== 'firstParty'
|
||||||
// For OpenAI provider, use OPENAI_DEFAULT_SONNET_MODEL; for other 3P, use ANTHROPIC_DEFAULT_SONNET_MODEL
|
const provider = getAPIProvider()
|
||||||
|
// Use provider-specific DEFAULT_SONNET_MODEL
|
||||||
const customSonnetModel =
|
const customSonnetModel =
|
||||||
getAPIProvider() === 'openai'
|
provider === 'openai'
|
||||||
? process.env.OPENAI_DEFAULT_SONNET_MODEL
|
? process.env.OPENAI_DEFAULT_SONNET_MODEL
|
||||||
|
: provider === 'gemini'
|
||||||
|
? process.env.GEMINI_DEFAULT_SONNET_MODEL
|
||||||
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
||||||
// When a 3P user has a custom sonnet model string, show it directly
|
// When a 3P user has a custom sonnet model string, show it directly
|
||||||
if (is3P && customSonnetModel) {
|
if (is3P && customSonnetModel) {
|
||||||
const is1m = has1mContext(customSonnetModel)
|
const is1m = has1mContext(customSonnetModel)
|
||||||
// Use appropriate NAME/DESCRIPTION env vars based on provider
|
// Use appropriate NAME/DESCRIPTION env vars based on provider
|
||||||
const nameEnv =
|
const nameEnv =
|
||||||
getAPIProvider() === 'openai'
|
provider === 'openai'
|
||||||
? process.env.OPENAI_DEFAULT_SONNET_MODEL_NAME
|
? process.env.OPENAI_DEFAULT_SONNET_MODEL_NAME
|
||||||
|
: provider === 'gemini'
|
||||||
|
? process.env.GEMINI_DEFAULT_SONNET_MODEL_NAME
|
||||||
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_NAME
|
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_NAME
|
||||||
const descEnv =
|
const descEnv =
|
||||||
getAPIProvider() === 'openai'
|
provider === 'openai'
|
||||||
? process.env.OPENAI_DEFAULT_SONNET_MODEL_DESCRIPTION
|
? process.env.OPENAI_DEFAULT_SONNET_MODEL_DESCRIPTION
|
||||||
|
: provider === 'gemini'
|
||||||
|
? process.env.GEMINI_DEFAULT_SONNET_MODEL_DESCRIPTION
|
||||||
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION
|
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION
|
||||||
return {
|
return {
|
||||||
value: 'sonnet',
|
value: 'sonnet',
|
||||||
@@ -118,22 +125,29 @@ function getSonnet46Option(): ModelOption {
|
|||||||
|
|
||||||
function getCustomOpusOption(): ModelOption | undefined {
|
function getCustomOpusOption(): ModelOption | undefined {
|
||||||
const is3P = getAPIProvider() !== 'firstParty'
|
const is3P = getAPIProvider() !== 'firstParty'
|
||||||
// For OpenAI provider, use OPENAI_DEFAULT_OPUS_MODEL; for other 3P, use ANTHROPIC_DEFAULT_OPUS_MODEL
|
const provider = getAPIProvider()
|
||||||
|
// Use provider-specific DEFAULT_OPUS_MODEL
|
||||||
const customOpusModel =
|
const customOpusModel =
|
||||||
getAPIProvider() === 'openai'
|
provider === 'openai'
|
||||||
? process.env.OPENAI_DEFAULT_OPUS_MODEL
|
? process.env.OPENAI_DEFAULT_OPUS_MODEL
|
||||||
|
: provider === 'gemini'
|
||||||
|
? process.env.GEMINI_DEFAULT_OPUS_MODEL
|
||||||
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
||||||
// When a 3P user has a custom opus model string, show it directly
|
// When a 3P user has a custom opus model string, show it directly
|
||||||
if (is3P && customOpusModel) {
|
if (is3P && customOpusModel) {
|
||||||
const is1m = has1mContext(customOpusModel)
|
const is1m = has1mContext(customOpusModel)
|
||||||
// Use appropriate NAME/DESCRIPTION env vars based on provider
|
// Use appropriate NAME/DESCRIPTION env vars based on provider
|
||||||
const nameEnv =
|
const nameEnv =
|
||||||
getAPIProvider() === 'openai'
|
provider === 'openai'
|
||||||
? process.env.OPENAI_DEFAULT_OPUS_MODEL_NAME
|
? process.env.OPENAI_DEFAULT_OPUS_MODEL_NAME
|
||||||
|
: provider === 'gemini'
|
||||||
|
? process.env.GEMINI_DEFAULT_OPUS_MODEL_NAME
|
||||||
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL_NAME
|
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL_NAME
|
||||||
const descEnv =
|
const descEnv =
|
||||||
getAPIProvider() === 'openai'
|
provider === 'openai'
|
||||||
? process.env.OPENAI_DEFAULT_OPUS_MODEL_DESCRIPTION
|
? process.env.OPENAI_DEFAULT_OPUS_MODEL_DESCRIPTION
|
||||||
|
: provider === 'gemini'
|
||||||
|
? process.env.GEMINI_DEFAULT_OPUS_MODEL_DESCRIPTION
|
||||||
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION
|
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION
|
||||||
return {
|
return {
|
||||||
value: 'opus',
|
value: 'opus',
|
||||||
@@ -187,21 +201,28 @@ export function getOpus46_1MOption(fastMode = false): ModelOption {
|
|||||||
|
|
||||||
function getCustomHaikuOption(): ModelOption | undefined {
|
function getCustomHaikuOption(): ModelOption | undefined {
|
||||||
const is3P = getAPIProvider() !== 'firstParty'
|
const is3P = getAPIProvider() !== 'firstParty'
|
||||||
// For OpenAI provider, use OPENAI_DEFAULT_HAIKU_MODEL; for other 3P, use ANTHROPIC_DEFAULT_HAIKU_MODEL
|
const provider = getAPIProvider()
|
||||||
|
// Use provider-specific DEFAULT_HAIKU_MODEL
|
||||||
const customHaikuModel =
|
const customHaikuModel =
|
||||||
getAPIProvider() === 'openai'
|
provider === 'openai'
|
||||||
? process.env.OPENAI_DEFAULT_HAIKU_MODEL
|
? process.env.OPENAI_DEFAULT_HAIKU_MODEL
|
||||||
|
: provider === 'gemini'
|
||||||
|
? process.env.GEMINI_DEFAULT_HAIKU_MODEL
|
||||||
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
||||||
// When a 3P user has a custom haiku model string, show it directly
|
// When a 3P user has a custom haiku model string, show it directly
|
||||||
if (is3P && customHaikuModel) {
|
if (is3P && customHaikuModel) {
|
||||||
// Use appropriate NAME/DESCRIPTION env vars based on provider
|
// Use appropriate NAME/DESCRIPTION env vars based on provider
|
||||||
const nameEnv =
|
const nameEnv =
|
||||||
getAPIProvider() === 'openai'
|
provider === 'openai'
|
||||||
? process.env.OPENAI_DEFAULT_HAIKU_MODEL_NAME
|
? process.env.OPENAI_DEFAULT_HAIKU_MODEL_NAME
|
||||||
|
: provider === 'gemini'
|
||||||
|
? process.env.GEMINI_DEFAULT_HAIKU_MODEL_NAME
|
||||||
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME
|
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME
|
||||||
const descEnv =
|
const descEnv =
|
||||||
getAPIProvider() === 'openai'
|
provider === 'openai'
|
||||||
? process.env.OPENAI_DEFAULT_HAIKU_MODEL_DESCRIPTION
|
? process.env.OPENAI_DEFAULT_HAIKU_MODEL_DESCRIPTION
|
||||||
|
: provider === 'gemini'
|
||||||
|
? process.env.GEMINI_DEFAULT_HAIKU_MODEL_DESCRIPTION
|
||||||
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION
|
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION
|
||||||
return {
|
return {
|
||||||
value: 'haiku',
|
value: 'haiku',
|
||||||
|
|||||||
Reference in New Issue
Block a user