Merge pull request #36 from Askhz/fix/model-chat

fix: restrict ANTHROPIC_MODEL to anthropic-compatible providers in model picker
This commit is contained in:
yhf 2026-04-22 11:39:13 +08:00 committed by GitHub
commit 3e8a82d01c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 36 additions and 34 deletions

View File

@ -37,6 +37,7 @@ import { generateMachineId, saveCoStrictCredentials } from '../../costrict/provi
import { extractExpiryFromJWT } from '../../costrict/provider/token.js'; import { extractExpiryFromJWT } from '../../costrict/provider/token.js';
import { updateSettingsForSource } from '../../utils/settings/settings.js'; import { updateSettingsForSource } from '../../utils/settings/settings.js';
import { useSetAppState as useSetGlobalAppState } from '../../state/AppState.js'; import { useSetAppState as useSetGlobalAppState } from '../../state/AppState.js';
import { isNotLoggedIn } from '../../utils/logoV2Utils.js';
function ModelPickerWrapper({ function ModelPickerWrapper({
onDone, onDone,
@ -339,6 +340,15 @@ export const call: LocalJSXCommandCall = async (onDone, _context, args) => {
return <SetModelAndClose args={args} onDone={onDone} />; return <SetModelAndClose args={args} onDone={onDone} />;
} }
// Check if user is logged in before showing model picker
if (isNotLoggedIn()) {
// User is not logged in, redirect to login
onDone('You need to login first. Use /login to authenticate.', {
display: 'system',
});
return;
}
return <ModelPickerWrapper onDone={onDone} />; return <ModelPickerWrapper onDone={onDone} />;
}; };

View File

@ -288,6 +288,8 @@ export function ConsoleOAuthFlow({
updateSettingsForSource('userSettings', { model: getDefaultSonnetModel() } as any) updateSettingsForSource('userSettings', { model: getDefaultSonnetModel() } as any)
// Clear costrict env var to prevent conflicts // Clear costrict env var to prevent conflicts
delete process.env.CLAUDE_CODE_USE_COSTRICT delete process.env.CLAUDE_CODE_USE_COSTRICT
// Reset AppState model so logo reflects the new provider default
setAppState(prev => ({ ...prev, mainLoopModel: null, mainLoopModelForSession: null }))
setOAuthStatus({ state: 'success' }) setOAuthStatus({ state: 'success' })
void sendNotification( void sendNotification(
@ -734,6 +736,8 @@ function OAuthStatusMessage({
delete process.env.CLAUDE_CODE_USE_COSTRICT delete process.env.CLAUDE_CODE_USE_COSTRICT
// Set default model to sonnet for this provider // Set default model to sonnet for this provider
updateSettingsForSource('userSettings', { model: getDefaultSonnetModel() } as any) updateSettingsForSource('userSettings', { model: getDefaultSonnetModel() } as any)
// Reset AppState model so logo reflects the new provider default
setAppState(prev => ({ ...prev, mainLoopModel: null, mainLoopModelForSession: null }))
setOAuthStatus({ state: 'success' }) setOAuthStatus({ state: 'success' })
void onDone() void onDone()
} }
@ -958,6 +962,8 @@ function OAuthStatusMessage({
delete process.env.CLAUDE_CODE_USE_COSTRICT delete process.env.CLAUDE_CODE_USE_COSTRICT
// Set default model to sonnet for this provider // Set default model to sonnet for this provider
updateSettingsForSource('userSettings', { model: getDefaultSonnetModel() } as any) updateSettingsForSource('userSettings', { model: getDefaultSonnetModel() } as any)
// Reset AppState model so logo reflects the new provider default
setAppState(prev => ({ ...prev, mainLoopModel: null, mainLoopModelForSession: null }))
setOAuthStatus({ state: 'success' }) setOAuthStatus({ state: 'success' })
void onDone() void onDone()
} }
@ -1195,6 +1201,8 @@ function OAuthStatusMessage({
delete process.env.CLAUDE_CODE_USE_COSTRICT delete process.env.CLAUDE_CODE_USE_COSTRICT
// Set default model to sonnet for this provider // Set default model to sonnet for this provider
updateSettingsForSource('userSettings', { model: getDefaultSonnetModel() } as any) updateSettingsForSource('userSettings', { model: getDefaultSonnetModel() } as any)
// Reset AppState model so logo reflects the new provider default
setAppState(prev => ({ ...prev, mainLoopModel: null, mainLoopModelForSession: null }))
setOAuthStatus({ state: 'success' }) setOAuthStatus({ state: 'success' })
void onDone() void onDone()
} }

View File

@ -1,5 +1,4 @@
// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered // biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
import { getInitialMainLoopModel } from '../../bootstrap/state.js'
import { import {
isClaudeAISubscriber, isClaudeAISubscriber,
isMaxSubscriber, isMaxSubscriber,
@ -25,7 +24,6 @@ import {
getDefaultHaikuModel, getDefaultHaikuModel,
getDefaultMainLoopModelSetting, getDefaultMainLoopModelSetting,
getMarketingNameForModel, getMarketingNameForModel,
getUserSpecifiedModelSetting,
isOpus1mMergeEnabled, isOpus1mMergeEnabled,
getOpus46PricingSuffix, getOpus46PricingSuffix,
renderDefaultModelSetting, renderDefaultModelSetting,
@ -542,45 +540,31 @@ export function getModelOptions(fastMode = false): ModelOption[] {
} }
} }
// Add custom model from either the current model value or the initial one // Add ANTHROPIC_MODEL env var model as a custom option, but only for
// if it is not already in the options. // anthropic-compatible providers. settings.model is NOT added here.
let customModel: ModelSetting = null const provider = getAPIProvider()
const currentMainLoopModel = getUserSpecifiedModelSetting() const envModel =
const initialMainLoopModel = getInitialMainLoopModel() provider === 'firstParty' ||
if (currentMainLoopModel !== undefined && currentMainLoopModel !== null) { provider === 'bedrock' ||
customModel = currentMainLoopModel provider === 'vertex' ||
} else if (initialMainLoopModel !== null) { provider === 'foundry'
customModel = initialMainLoopModel ? process.env.ANTHROPIC_MODEL
} : undefined
if (customModel === null || options.some(opt => opt.value === customModel)) {
return filterModelOptionsByAllowlist(options) if (envModel && !options.some(opt => opt.value === envModel)) {
} else if (customModel === 'opusplan') { const knownOption = getKnownModelOption(envModel)
return filterModelOptionsByAllowlist([...options, getOpusPlanOption()])
} else if (customModel === 'opus' && getAPIProvider() === 'firstParty') {
return filterModelOptionsByAllowlist([
...options,
getMaxOpusOption(fastMode),
])
} else if (customModel === 'opus[1m]' && getAPIProvider() === 'firstParty') {
return filterModelOptionsByAllowlist([
...options,
getMergedOpus1MOption(fastMode),
])
} else {
// Try to show a human-readable label for known Anthropic models, with an
// upgrade hint if the alias now resolves to a newer version.
const knownOption = getKnownModelOption(customModel)
if (knownOption) { if (knownOption) {
options.push(knownOption) options.push(knownOption)
} else { } else {
options.push({ options.push({
value: customModel, value: envModel,
label: customModel, label: envModel,
description: 'Custom model', description: 'Custom model (ANTHROPIC_MODEL)',
}) })
} }
return filterModelOptionsByAllowlist(options)
} }
return filterModelOptionsByAllowlist(options)
} }
/** /**