mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-19 13:33:35 +08:00
Stop provider model selection from inheriting global Claude settings
The desktop provider flow was still mixing provider-managed state with `~/.claude/settings.json`, which let unrelated tools leak fields like `ANTHROPIC_REASONING_MODEL` and `model` back into the active provider path. This change moves the provider JSON editor onto `~/.claude/cc-haha/settings.json`, routes provider settings through dedicated `/api/providers/settings` endpoints, and makes model reads/writes under an active provider use the managed cc-haha settings instead of the global user settings file. Constraint: Active provider model selection must be isolated from legacy ~/.claude/settings.json Rejected: Keep merging provider JSON with settingsApi.getUser() | external tools can reintroduce unrelated model fields into the provider flow Confidence: high Scope-risk: narrow Reversibility: clean Directive: Any future provider-model UI or runtime change should read/write cc-haha managed settings first, not the global user settings file Tested: bun test src/server/__tests__/provider-presets.test.ts src/server/__tests__/settings.test.ts; cd desktop && bun run lint Not-tested: Manual desktop provider modal interaction after the cc-haha settings API switch
This commit is contained in:
parent
e0142b286b
commit
d8a44c0a54
@ -33,6 +33,14 @@ export const providersApi = {
|
|||||||
return api.get<AuthStatusResponse>('/api/providers/auth-status')
|
return api.get<AuthStatusResponse>('/api/providers/auth-status')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getSettings() {
|
||||||
|
return api.get<Record<string, unknown>>('/api/providers/settings')
|
||||||
|
},
|
||||||
|
|
||||||
|
updateSettings(settings: Record<string, unknown>) {
|
||||||
|
return api.put<{ ok: true }>('/api/providers/settings', settings)
|
||||||
|
},
|
||||||
|
|
||||||
create(input: CreateProviderInput) {
|
create(input: CreateProviderInput) {
|
||||||
return api.post<ProviderResponse>('/api/providers', input)
|
return api.post<ProviderResponse>('/api/providers', input)
|
||||||
},
|
},
|
||||||
|
|||||||
@ -102,7 +102,7 @@ export const en = {
|
|||||||
'settings.providers.sameAsMain': 'Same as main',
|
'settings.providers.sameAsMain': 'Same as main',
|
||||||
'settings.providers.testConnection': 'Test Connection',
|
'settings.providers.testConnection': 'Test Connection',
|
||||||
'settings.providers.settingsJson': 'Settings JSON',
|
'settings.providers.settingsJson': 'Settings JSON',
|
||||||
'settings.providers.settingsJsonDesc': '~/.claude/settings.json — edit directly, will be written on save.',
|
'settings.providers.settingsJsonDesc': '~/.claude/cc-haha/settings.json — edit directly, will be written on save.',
|
||||||
'settings.providers.jsonError': 'JSON syntax error: {error}',
|
'settings.providers.jsonError': 'JSON syntax error: {error}',
|
||||||
'settings.providers.apiFormat': 'API Format',
|
'settings.providers.apiFormat': 'API Format',
|
||||||
'settings.providers.apiFormatAnthropic': 'Anthropic Messages (native)',
|
'settings.providers.apiFormatAnthropic': 'Anthropic Messages (native)',
|
||||||
|
|||||||
@ -104,7 +104,7 @@ export const zh: Record<TranslationKey, string> = {
|
|||||||
'settings.providers.sameAsMain': '与主模型相同',
|
'settings.providers.sameAsMain': '与主模型相同',
|
||||||
'settings.providers.testConnection': '测试连接',
|
'settings.providers.testConnection': '测试连接',
|
||||||
'settings.providers.settingsJson': '设置 JSON',
|
'settings.providers.settingsJson': '设置 JSON',
|
||||||
'settings.providers.settingsJsonDesc': '~/.claude/settings.json — 直接编辑,保存时写入。',
|
'settings.providers.settingsJsonDesc': '~/.claude/cc-haha/settings.json — 直接编辑,保存时写入。',
|
||||||
'settings.providers.jsonError': 'JSON 语法错误: {error}',
|
'settings.providers.jsonError': 'JSON 语法错误: {error}',
|
||||||
'settings.providers.apiFormat': 'API 格式',
|
'settings.providers.apiFormat': 'API 格式',
|
||||||
'settings.providers.apiFormatAnthropic': 'Anthropic Messages (原生)',
|
'settings.providers.apiFormatAnthropic': 'Anthropic Messages (原生)',
|
||||||
|
|||||||
@ -350,8 +350,8 @@ function ProviderFormModal({ open, onClose, mode, provider, presets }: ProviderF
|
|||||||
jsonPastedRef.current = false
|
jsonPastedRef.current = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
import('../api/settings').then(({ settingsApi }) => {
|
import('../api/providers').then(({ providersApi }) => {
|
||||||
settingsApi.getUser().then((settings) => {
|
providersApi.getSettings().then((settings) => {
|
||||||
const needsProxy = apiFormat !== 'anthropic'
|
const needsProxy = apiFormat !== 'anthropic'
|
||||||
const merged = {
|
const merged = {
|
||||||
...settings,
|
...settings,
|
||||||
@ -390,12 +390,13 @@ function ProviderFormModal({ open, onClose, mode, provider, presets }: ProviderF
|
|||||||
if (!canSubmit) return
|
if (!canSubmit) return
|
||||||
setIsSubmitting(true)
|
setIsSubmitting(true)
|
||||||
try {
|
try {
|
||||||
// Write the edited settings.json first (for all presets including official)
|
// Write the edited cc-haha settings.json first so provider-specific model
|
||||||
|
// settings never conflict with the user's global ~/.claude/settings.json.
|
||||||
if (settingsJson.trim()) {
|
if (settingsJson.trim()) {
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(settingsJson)
|
const parsed = JSON.parse(settingsJson)
|
||||||
const { settingsApi } = await import('../api/settings')
|
const { providersApi } = await import('../api/providers')
|
||||||
await settingsApi.updateUser(parsed)
|
await providersApi.updateSettings(parsed)
|
||||||
} catch {
|
} catch {
|
||||||
// JSON validation already prevents this
|
// JSON validation already prevents this
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,41 @@
|
|||||||
import { describe, test, expect } from 'bun:test'
|
import { describe, test, expect, beforeEach, afterEach } from 'bun:test'
|
||||||
|
import * as fs from 'fs/promises'
|
||||||
|
import * as os from 'os'
|
||||||
|
import * as path from 'path'
|
||||||
|
|
||||||
import { handleProvidersApi } from '../api/providers.js'
|
import { handleProvidersApi } from '../api/providers.js'
|
||||||
import { PROVIDER_PRESETS } from '../config/providerPresets.js'
|
import { PROVIDER_PRESETS } from '../config/providerPresets.js'
|
||||||
|
|
||||||
function makeRequest(method: string, urlStr: string): { req: Request; url: URL; segments: string[] } {
|
let tmpDir: string
|
||||||
|
let originalConfigDir: string | undefined
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'provider-presets-test-'))
|
||||||
|
originalConfigDir = process.env.CLAUDE_CONFIG_DIR
|
||||||
|
process.env.CLAUDE_CONFIG_DIR = tmpDir
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
if (originalConfigDir !== undefined) {
|
||||||
|
process.env.CLAUDE_CONFIG_DIR = originalConfigDir
|
||||||
|
} else {
|
||||||
|
delete process.env.CLAUDE_CONFIG_DIR
|
||||||
|
}
|
||||||
|
await fs.rm(tmpDir, { recursive: true, force: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
function makeRequest(
|
||||||
|
method: string,
|
||||||
|
urlStr: string,
|
||||||
|
body?: Record<string, unknown>,
|
||||||
|
): { req: Request; url: URL; segments: string[] } {
|
||||||
const url = new URL(urlStr, 'http://localhost:3456')
|
const url = new URL(urlStr, 'http://localhost:3456')
|
||||||
const req = new Request(url.toString(), { method })
|
const init: RequestInit = { method }
|
||||||
|
if (body) {
|
||||||
|
init.headers = { 'Content-Type': 'application/json' }
|
||||||
|
init.body = JSON.stringify(body)
|
||||||
|
}
|
||||||
|
const req = new Request(url.toString(), init)
|
||||||
const segments = url.pathname.split('/').filter(Boolean)
|
const segments = url.pathname.split('/').filter(Boolean)
|
||||||
return { req, url, segments }
|
return { req, url, segments }
|
||||||
}
|
}
|
||||||
@ -39,4 +69,37 @@ describe('provider presets API', () => {
|
|||||||
expect(kimi?.defaultModels.main).toBe('kimi-k2.6')
|
expect(kimi?.defaultModels.main).toBe('kimi-k2.6')
|
||||||
expect(minimax?.defaultModels.main).toBe('MiniMax-M2.7')
|
expect(minimax?.defaultModels.main).toBe('MiniMax-M2.7')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('GET and PUT /api/providers/settings read and write cc-haha settings.json', async () => {
|
||||||
|
const initial = {
|
||||||
|
env: {
|
||||||
|
ANTHROPIC_MODEL: 'glm-5.1',
|
||||||
|
},
|
||||||
|
model: 'glm-5.1',
|
||||||
|
}
|
||||||
|
await fs.mkdir(path.join(tmpDir, 'cc-haha'), { recursive: true })
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(tmpDir, 'cc-haha', 'settings.json'),
|
||||||
|
JSON.stringify(initial, null, 2),
|
||||||
|
'utf-8',
|
||||||
|
)
|
||||||
|
|
||||||
|
const getReq = makeRequest('GET', '/api/providers/settings')
|
||||||
|
const getRes = await handleProvidersApi(getReq.req, getReq.url, getReq.segments)
|
||||||
|
expect(getRes.status).toBe(200)
|
||||||
|
expect(await getRes.json()).toEqual(initial)
|
||||||
|
|
||||||
|
const updateBody = {
|
||||||
|
model: 'kimi-k2.6',
|
||||||
|
env: {
|
||||||
|
ANTHROPIC_MODEL: 'kimi-k2.6',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const putReq = makeRequest('PUT', '/api/providers/settings', updateBody)
|
||||||
|
const putRes = await handleProvidersApi(putReq.req, putReq.url, putReq.segments)
|
||||||
|
expect(putRes.status).toBe(200)
|
||||||
|
|
||||||
|
const updatedRaw = await fs.readFile(path.join(tmpDir, 'cc-haha', 'settings.json'), 'utf-8')
|
||||||
|
expect(JSON.parse(updatedRaw)).toEqual(updateBody)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { SettingsService } from '../services/settingsService.js'
|
|||||||
import { handleSettingsApi } from '../api/settings.js'
|
import { handleSettingsApi } from '../api/settings.js'
|
||||||
import { handleModelsApi } from '../api/models.js'
|
import { handleModelsApi } from '../api/models.js'
|
||||||
import { handleStatusApi, resetUsage, addUsage } from '../api/status.js'
|
import { handleStatusApi, resetUsage, addUsage } from '../api/status.js'
|
||||||
|
import { ProviderService } from '../services/providerService.js'
|
||||||
|
|
||||||
// ─── Test helpers ─────────────────────────────────────────────────────────────
|
// ─── Test helpers ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@ -254,7 +255,7 @@ describe('Models API', () => {
|
|||||||
expect(res.status).toBe(200)
|
expect(res.status).toBe(200)
|
||||||
const body = await res.json()
|
const body = await res.json()
|
||||||
expect(body.models).toBeArray()
|
expect(body.models).toBeArray()
|
||||||
expect(body.models.length).toBe(4)
|
expect(body.models.length).toBe(3)
|
||||||
expect(body.models[0].id).toContain('claude')
|
expect(body.models[0].id).toContain('claude')
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -264,7 +265,7 @@ describe('Models API', () => {
|
|||||||
|
|
||||||
expect(res.status).toBe(200)
|
expect(res.status).toBe(200)
|
||||||
const body = await res.json()
|
const body = await res.json()
|
||||||
expect(body.model.id).toBe('claude-sonnet-4-6')
|
expect(body.model.id).toBe('claude-opus-4-7')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('PUT /api/models/current should switch model', async () => {
|
it('PUT /api/models/current should switch model', async () => {
|
||||||
@ -291,6 +292,66 @@ describe('Models API', () => {
|
|||||||
expect(res.status).toBe(400)
|
expect(res.status).toBe(400)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('GET /api/models/current should prefer cc-haha managed model over global user model when provider is active', async () => {
|
||||||
|
const settingsSvc = new SettingsService()
|
||||||
|
await settingsSvc.updateUserSettings({ model: 'kimi-k2.6' })
|
||||||
|
|
||||||
|
const providerSvc = new ProviderService()
|
||||||
|
const provider = await providerSvc.addProvider({
|
||||||
|
presetId: 'zhipuglm',
|
||||||
|
name: 'Zhipu GLM',
|
||||||
|
baseUrl: 'https://open.bigmodel.cn/api/anthropic',
|
||||||
|
apiKey: 'test-key',
|
||||||
|
apiFormat: 'anthropic',
|
||||||
|
models: {
|
||||||
|
main: 'glm-5.1',
|
||||||
|
haiku: 'glm-4.5-air',
|
||||||
|
sonnet: 'glm-5-turbo',
|
||||||
|
opus: 'glm-5.1',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await providerSvc.activateProvider(provider.id)
|
||||||
|
await providerSvc.updateManagedSettings({ model: 'glm-5-turbo' })
|
||||||
|
|
||||||
|
const { req, url, segments } = makeRequest('GET', '/api/models/current')
|
||||||
|
const res = await handleModelsApi(req, url, segments)
|
||||||
|
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
const body = await res.json()
|
||||||
|
expect(body.model.id).toBe('glm-5-turbo')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('PUT /api/models/current should persist to cc-haha managed settings when provider is active', async () => {
|
||||||
|
const settingsSvc = new SettingsService()
|
||||||
|
const providerSvc = new ProviderService()
|
||||||
|
const provider = await providerSvc.addProvider({
|
||||||
|
presetId: 'zhipuglm',
|
||||||
|
name: 'Zhipu GLM',
|
||||||
|
baseUrl: 'https://open.bigmodel.cn/api/anthropic',
|
||||||
|
apiKey: 'test-key',
|
||||||
|
apiFormat: 'anthropic',
|
||||||
|
models: {
|
||||||
|
main: 'glm-5.1',
|
||||||
|
haiku: 'glm-4.5-air',
|
||||||
|
sonnet: 'glm-5-turbo',
|
||||||
|
opus: 'glm-5.1',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await providerSvc.activateProvider(provider.id)
|
||||||
|
|
||||||
|
const putReq = makeRequest('PUT', '/api/models/current', {
|
||||||
|
modelId: 'glm-5-turbo',
|
||||||
|
})
|
||||||
|
const putRes = await handleModelsApi(putReq.req, putReq.url, putReq.segments)
|
||||||
|
expect(putRes.status).toBe(200)
|
||||||
|
|
||||||
|
const managedSettings = await providerSvc.getManagedSettings()
|
||||||
|
expect(managedSettings.model).toBe('glm-5-turbo')
|
||||||
|
|
||||||
|
const globalSettings = await settingsSvc.getUserSettings()
|
||||||
|
expect(globalSettings.model).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
it('GET /api/effort should return default effort level', async () => {
|
it('GET /api/effort should return default effort level', async () => {
|
||||||
const { req, url, segments } = makeRequest('GET', '/api/effort')
|
const { req, url, segments } = makeRequest('GET', '/api/effort')
|
||||||
const res = await handleModelsApi(req, url, segments)
|
const res = await handleModelsApi(req, url, segments)
|
||||||
|
|||||||
@ -100,28 +100,28 @@ async function handleModelsList(): Promise<Response> {
|
|||||||
|
|
||||||
async function handleCurrentModel(req: Request): Promise<Response> {
|
async function handleCurrentModel(req: Request): Promise<Response> {
|
||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
const settings = await settingsService.getUserSettings()
|
|
||||||
const explicitModel = (settings.model as string) || ''
|
|
||||||
const contextTier = (settings.modelContext as string) || undefined
|
|
||||||
const env = (settings.env as Record<string, string>) || {}
|
|
||||||
|
|
||||||
// Build the full model list: prefer active provider's models, fall back to defaults
|
// Build the full model list: prefer active provider's models, fall back to defaults
|
||||||
const { providers, activeId } = await providerService.listProviders()
|
const { providers, activeId } = await providerService.listProviders()
|
||||||
const activeProvider = activeId ? providers.find((p) => p.id === activeId) : null
|
const activeProvider = activeId ? providers.find((p) => p.id === activeId) : null
|
||||||
|
const settings = activeProvider
|
||||||
|
? await providerService.getManagedSettings()
|
||||||
|
: await settingsService.getUserSettings()
|
||||||
|
const explicitModel = (settings.model as string) || ''
|
||||||
|
const contextTier = (settings.modelContext as string) || undefined
|
||||||
|
const env = (settings.env as Record<string, string>) || {}
|
||||||
|
|
||||||
let currentModelId: string
|
let currentModelId: string
|
||||||
let currentModelName: string
|
let currentModelName: string
|
||||||
|
|
||||||
if (activeProvider) {
|
if (activeProvider) {
|
||||||
// Provider is active — use the model from env (set by syncToSettings when provider was activated)
|
// Provider is active — only use the provider-managed cc-haha settings.
|
||||||
// unless user explicitly set a different model ID in settings
|
// This avoids leaking global ~/.claude/settings.json model choices into
|
||||||
|
// the active provider flow.
|
||||||
const providerEnvModel = env.ANTHROPIC_MODEL
|
const providerEnvModel = env.ANTHROPIC_MODEL
|
||||||
if (providerEnvModel && (!explicitModel || explicitModel === DEFAULT_MODEL)) {
|
if (providerEnvModel && !explicitModel) {
|
||||||
// No explicit model override — use the provider's configured model
|
|
||||||
currentModelId = providerEnvModel
|
currentModelId = providerEnvModel
|
||||||
currentModelName = providerEnvModel
|
currentModelName = providerEnvModel
|
||||||
} else {
|
} else {
|
||||||
// User explicitly set a model (possibly from the provider's model list)
|
|
||||||
currentModelId = explicitModel || providerEnvModel || activeProvider.models.main
|
currentModelId = explicitModel || providerEnvModel || activeProvider.models.main
|
||||||
currentModelName = currentModelId
|
currentModelName = currentModelId
|
||||||
}
|
}
|
||||||
@ -175,7 +175,12 @@ async function handleCurrentModel(req: Request): Promise<Response> {
|
|||||||
// Clear context tier when switching to a non-composite model
|
// Clear context tier when switching to a non-composite model
|
||||||
updates.modelContext = undefined
|
updates.modelContext = undefined
|
||||||
}
|
}
|
||||||
await settingsService.updateUserSettings(updates)
|
const { activeId } = await providerService.listProviders()
|
||||||
|
if (activeId) {
|
||||||
|
await providerService.updateManagedSettings(updates)
|
||||||
|
} else {
|
||||||
|
await settingsService.updateUserSettings(updates)
|
||||||
|
}
|
||||||
return Response.json({ ok: true, model: modelId })
|
return Response.json({ ok: true, model: modelId })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,9 @@
|
|||||||
* GET /api/providers — list all saved providers + activeId
|
* GET /api/providers — list all saved providers + activeId
|
||||||
* GET /api/providers/presets — list available presets
|
* GET /api/providers/presets — list available presets
|
||||||
* GET /api/providers/auth-status — check whether any usable auth exists
|
* GET /api/providers/auth-status — check whether any usable auth exists
|
||||||
|
* GET /api/providers/settings — read cc-haha managed settings.json
|
||||||
* POST /api/providers — add a provider
|
* POST /api/providers — add a provider
|
||||||
|
* PUT /api/providers/settings — update cc-haha managed settings.json
|
||||||
* PUT /api/providers/:id — update a provider
|
* PUT /api/providers/:id — update a provider
|
||||||
* DELETE /api/providers/:id — delete a provider
|
* DELETE /api/providers/:id — delete a provider
|
||||||
* POST /api/providers/:id/activate — activate a saved provider
|
* POST /api/providers/:id/activate — activate a saved provider
|
||||||
@ -62,6 +64,19 @@ export async function handleProvidersApi(
|
|||||||
return Response.json(status)
|
return Response.json(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /api/providers/settings
|
||||||
|
if (id === 'settings') {
|
||||||
|
if (req.method === 'GET') {
|
||||||
|
return Response.json(await providerService.getManagedSettings())
|
||||||
|
}
|
||||||
|
if (req.method === 'PUT') {
|
||||||
|
const body = await parseJsonBody(req)
|
||||||
|
await providerService.updateManagedSettings(body)
|
||||||
|
return Response.json({ ok: true })
|
||||||
|
}
|
||||||
|
throw methodNotAllowed(req.method)
|
||||||
|
}
|
||||||
|
|
||||||
// POST /api/providers/official
|
// POST /api/providers/official
|
||||||
if (id === 'official' && req.method === 'POST') {
|
if (id === 'official' && req.method === 'POST') {
|
||||||
await providerService.activateOfficial()
|
await providerService.activateOfficial()
|
||||||
|
|||||||
@ -115,6 +115,15 @@ export class ProviderService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getManagedSettings(): Promise<Record<string, unknown>> {
|
||||||
|
return this.readSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateManagedSettings(settings: Record<string, unknown>): Promise<void> {
|
||||||
|
const current = await this.readSettings()
|
||||||
|
await this.writeSettings(Object.assign({}, current, settings))
|
||||||
|
}
|
||||||
|
|
||||||
// --- CRUD ---
|
// --- CRUD ---
|
||||||
|
|
||||||
async listProviders(): Promise<{ providers: SavedProvider[]; activeId: string | null }> {
|
async listProviders(): Promise<{ providers: SavedProvider[]; activeId: string | null }> {
|
||||||
@ -530,4 +539,3 @@ function validateResponseBody(
|
|||||||
}
|
}
|
||||||
return { ok: true, model: (body.model as string) || undefined }
|
return { ok: true, model: (body.model as string) || undefined }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -850,27 +850,31 @@ async function getRuntimeSettings(): Promise<{
|
|||||||
model?: string
|
model?: string
|
||||||
effort?: string
|
effort?: string
|
||||||
}> {
|
}> {
|
||||||
|
// Check if a custom provider is active
|
||||||
|
const { activeId } = await providerService.listProviders()
|
||||||
const userSettings = await settingsService.getUserSettings()
|
const userSettings = await settingsService.getUserSettings()
|
||||||
|
const providerSettings = activeId
|
||||||
|
? await providerService.getManagedSettings()
|
||||||
|
: undefined
|
||||||
|
const modelSettings = providerSettings ?? userSettings
|
||||||
const modelContext =
|
const modelContext =
|
||||||
typeof userSettings.modelContext === 'string' && userSettings.modelContext.trim()
|
typeof modelSettings.modelContext === 'string' && modelSettings.modelContext.trim()
|
||||||
? userSettings.modelContext
|
? modelSettings.modelContext
|
||||||
: undefined
|
: undefined
|
||||||
const effort =
|
const effort =
|
||||||
typeof userSettings.effort === 'string' && userSettings.effort.trim()
|
typeof userSettings.effort === 'string' && userSettings.effort.trim()
|
||||||
? userSettings.effort
|
? userSettings.effort
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
// Check if a custom provider is active
|
|
||||||
const { activeId } = await providerService.listProviders()
|
|
||||||
|
|
||||||
let model: string | undefined
|
let model: string | undefined
|
||||||
if (activeId) {
|
if (activeId) {
|
||||||
// Provider is active — only pass --model if user explicitly selected a non-default model.
|
// Provider is active — only consult provider-managed cc-haha settings.
|
||||||
// Otherwise the CLI should use ANTHROPIC_MODEL from env (set by syncToSettings).
|
// Global ~/.claude/settings.json model values must not bleed into provider mode.
|
||||||
// Default Anthropic model should be overridden by the provider's model.
|
const baseModel =
|
||||||
const baseModel = (userSettings.model as string) || ''
|
typeof modelSettings.model === 'string' && modelSettings.model.trim()
|
||||||
if (baseModel && baseModel !== 'claude-sonnet-4-6') {
|
? modelSettings.model
|
||||||
// User explicitly selected a different model — pass it through
|
: ''
|
||||||
|
if (baseModel) {
|
||||||
model = baseModel
|
model = baseModel
|
||||||
if (modelContext) model += `:${modelContext}`
|
if (modelContext) model += `:${modelContext}`
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user