provider指令切换模型类型

This commit is contained in:
HitMargin
2026-04-04 23:14:26 +08:00
parent ad104449f9
commit b5d1dbc9d0
3 changed files with 116 additions and 0 deletions

View File

@@ -150,6 +150,7 @@ import sandboxToggle from './commands/sandbox-toggle/index.js'
import chrome from './commands/chrome/index.js'
import stickers from './commands/stickers/index.js'
import advisor from './commands/advisor.js'
import provider from './commands/provider.js'
import { logError } from './utils/log.js'
import { toError } from './utils/errors.js'
import { logForDebugging } from './utils/debug.js'
@@ -258,6 +259,7 @@ export const INTERNAL_ONLY_COMMANDS = [
const COMMANDS = memoize((): Command[] => [
addDir,
advisor,
provider,
agents,
branch,
btw,

111
src/commands/provider.ts Normal file
View File

@@ -0,0 +1,111 @@
import type { Command } from '../commands.js'
import type { LocalCommandCall } from '../types/command.js'
import { getAPIProvider } from '../utils/model/providers.js'
import { updateSettingsForSource } from '../utils/settings/settings.js'
import { getSettings_DEPRECATED } from '../utils/settings/settings.js'
import { applyConfigEnvironmentVariables } from '../utils/managedEnv.js'
function getEnvVarForProvider(provider: string): string {
switch (provider) {
case 'bedrock':
return 'CLAUDE_CODE_USE_BEDROCK'
case 'vertex':
return 'CLAUDE_CODE_USE_VERTEX'
case 'foundry':
return 'CLAUDE_CODE_USE_FOUNDRY'
default:
throw new Error(`Unknown provider: ${provider}`)
}
}
// Get merged env: process.env + settings.env (from userSettings)
function getMergedEnv(): Record<string, string> {
const settings = getSettings_DEPRECATED()
const merged = { ...process.env }
if (settings?.env) {
Object.assign(merged, settings.env)
}
return merged
}
const call: LocalCommandCall = async (args, context) => {
const arg = args.trim().toLowerCase()
// No argument: show current provider
if (!arg) {
const current = getAPIProvider()
return { type: 'text', value: `Current API provider: ${current}` }
}
// unset - clear settings, fallback to env vars
if (arg === 'unset') {
updateSettingsForSource('userSettings', { modelType: undefined })
// Also clear all provider-specific env vars to prevent conflicts
delete process.env.CLAUDE_CODE_USE_BEDROCK
delete process.env.CLAUDE_CODE_USE_VERTEX
delete process.env.CLAUDE_CODE_USE_FOUNDRY
delete process.env.CLAUDE_CODE_USE_OPENAI
return { type: 'text', value: 'API provider cleared (will use environment variables).' }
}
// Validate provider
const validProviders = ['anthropic', 'openai', 'bedrock', 'vertex', 'foundry']
if (!validProviders.includes(arg)) {
return { type: 'text', value: `Invalid provider: ${arg}\nValid: ${validProviders.join(', ')}` }
}
// Check env vars when switching to openai (including settings.env)
if (arg === 'openai') {
const mergedEnv = getMergedEnv()
const hasKey = !!mergedEnv.OPENAI_API_KEY
const hasUrl = !!mergedEnv.OPENAI_BASE_URL
if (!hasKey || !hasUrl) {
updateSettingsForSource('userSettings', { modelType: 'openai' })
const missing = []
if (!hasKey) missing.push('OPENAI_API_KEY')
if (!hasUrl) missing.push('OPENAI_BASE_URL')
return {
type: 'text',
value: `Switched to OpenAI provider.\nWarning: Missing env vars: ${missing.join(', ')}\nConfigure them via /login or set manually.`,
}
}
}
// Handle different provider types
// - 'anthropic' and 'openai' are stored in settings.json (persistent)
// - 'bedrock', 'vertex', 'foundry' are env-only (do NOT touch settings.json)
if (arg === 'anthropic' || arg === 'openai') {
// Clear any cloud provider env vars to avoid conflicts
delete process.env.CLAUDE_CODE_USE_BEDROCK
delete process.env.CLAUDE_CODE_USE_VERTEX
delete process.env.CLAUDE_CODE_USE_FOUNDRY
// Update settings.json
updateSettingsForSource('userSettings', { modelType: arg })
// Ensure settings.env gets applied to process.env
applyConfigEnvironmentVariables()
return { type: 'text', value: `API provider set to ${arg}.` }
} else {
// Cloud providers: set env vars only, clear settings.modelType
delete process.env.CLAUDE_CODE_USE_OPENAI
delete process.env.OPENAI_API_KEY
delete process.env.OPENAI_BASE_URL
process.env[getEnvVarForProvider(arg)] = '1'
// Clear settings.json to 'anthropic' to avoid validation errors
updateSettingsForSource('userSettings', { modelType: 'anthropic' })
// Ensure settings.env gets applied to process.env (in case it contains provider-specific creds)
applyConfigEnvironmentVariables()
return { type: 'text', value: `API provider set to ${arg} (via environment variable).` }
}
}
const provider = {
type: 'local',
name: 'provider',
description: 'Switch API provider (anthropic/openai/bedrock/vertex/foundry)',
aliases: ['api'],
argumentHint: '[anthropic|openai|bedrock|vertex|foundry|unset]',
supportsNonInteractive: true,
load: () => Promise.resolve({ call }),
} satisfies Command
export default provider

View File

@@ -8,6 +8,9 @@ export function getAPIProvider(): APIProvider {
// 1. Check settings.json modelType field (highest priority)
const modelType = getInitialSettings().modelType
if (modelType === 'openai') return 'openai'
if (modelType === 'bedrock') return 'bedrock'
if (modelType === 'vertex') return 'vertex'
if (modelType === 'foundry') return 'foundry'
// 2. Check environment variables (backward compatibility)
return isEnvTruthy(process.env.CLAUDE_CODE_USE_OPENAI)