mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
fix: enable the local apikey models while using openai auth subscription
This commit is contained in:
parent
24d31e284f
commit
2835426cf3
@ -11,6 +11,12 @@ import { handleSettingsApi } from '../api/settings.js'
|
||||
import { handleModelsApi } from '../api/models.js'
|
||||
import { handleStatusApi, resetUsage, addUsage } from '../api/status.js'
|
||||
import { ProviderService } from '../services/providerService.js'
|
||||
import {
|
||||
clearOpenAIOAuthTokenCache,
|
||||
deleteOpenAIOAuthTokens,
|
||||
saveOpenAIOAuthTokens,
|
||||
} from '../../services/openaiAuth/storage.js'
|
||||
import { getModelOptions } from '../../utils/model/modelOptions.js'
|
||||
|
||||
// ─── Test helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
@ -21,6 +27,12 @@ let originalUserProfile: string | undefined
|
||||
let originalShell: string | undefined
|
||||
let originalPath: string | undefined
|
||||
let originalCliPath: string | undefined
|
||||
let originalAnthropicApiKey: string | undefined
|
||||
let originalAnthropicBaseUrl: string | undefined
|
||||
let originalAnthropicModel: string | undefined
|
||||
let originalAnthropicDefaultHaikuModel: string | undefined
|
||||
let originalAnthropicDefaultSonnetModel: string | undefined
|
||||
let originalAnthropicDefaultOpusModel: string | undefined
|
||||
|
||||
async function setup() {
|
||||
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'claude-test-'))
|
||||
@ -30,11 +42,24 @@ async function setup() {
|
||||
originalShell = process.env.SHELL
|
||||
originalPath = process.env.PATH
|
||||
originalCliPath = process.env.CLAUDE_CLI_PATH
|
||||
originalAnthropicApiKey = process.env.ANTHROPIC_API_KEY
|
||||
originalAnthropicBaseUrl = process.env.ANTHROPIC_BASE_URL
|
||||
originalAnthropicModel = process.env.ANTHROPIC_MODEL
|
||||
originalAnthropicDefaultHaikuModel = process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
||||
originalAnthropicDefaultSonnetModel = process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
||||
originalAnthropicDefaultOpusModel = process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
||||
process.env.CLAUDE_CONFIG_DIR = tmpDir
|
||||
process.env.HOME = tmpDir
|
||||
process.env.USERPROFILE = tmpDir
|
||||
process.env.SHELL = '/bin/zsh'
|
||||
process.env.PATH = ''
|
||||
delete process.env.ANTHROPIC_API_KEY
|
||||
delete process.env.ANTHROPIC_BASE_URL
|
||||
delete process.env.ANTHROPIC_MODEL
|
||||
delete process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
||||
delete process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
||||
delete process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
||||
clearOpenAIOAuthTokenCache()
|
||||
}
|
||||
|
||||
async function teardown() {
|
||||
@ -74,6 +99,45 @@ async function teardown() {
|
||||
delete process.env.CLAUDE_CLI_PATH
|
||||
}
|
||||
|
||||
if (originalAnthropicApiKey !== undefined) {
|
||||
process.env.ANTHROPIC_API_KEY = originalAnthropicApiKey
|
||||
} else {
|
||||
delete process.env.ANTHROPIC_API_KEY
|
||||
}
|
||||
|
||||
if (originalAnthropicBaseUrl !== undefined) {
|
||||
process.env.ANTHROPIC_BASE_URL = originalAnthropicBaseUrl
|
||||
} else {
|
||||
delete process.env.ANTHROPIC_BASE_URL
|
||||
}
|
||||
|
||||
if (originalAnthropicModel !== undefined) {
|
||||
process.env.ANTHROPIC_MODEL = originalAnthropicModel
|
||||
} else {
|
||||
delete process.env.ANTHROPIC_MODEL
|
||||
}
|
||||
|
||||
if (originalAnthropicDefaultHaikuModel !== undefined) {
|
||||
process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = originalAnthropicDefaultHaikuModel
|
||||
} else {
|
||||
delete process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
||||
}
|
||||
|
||||
if (originalAnthropicDefaultSonnetModel !== undefined) {
|
||||
process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = originalAnthropicDefaultSonnetModel
|
||||
} else {
|
||||
delete process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
||||
}
|
||||
|
||||
if (originalAnthropicDefaultOpusModel !== undefined) {
|
||||
process.env.ANTHROPIC_DEFAULT_OPUS_MODEL = originalAnthropicDefaultOpusModel
|
||||
} else {
|
||||
delete process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
||||
}
|
||||
|
||||
deleteOpenAIOAuthTokens()
|
||||
clearOpenAIOAuthTokenCache()
|
||||
|
||||
await fs.rm(tmpDir, { recursive: true, force: true })
|
||||
}
|
||||
|
||||
@ -324,6 +388,34 @@ describe('Models API', () => {
|
||||
expect(body.models[0].id).toContain('claude')
|
||||
})
|
||||
|
||||
it('GET /api/models should merge env-configured provider models with saved OpenAI OAuth models', async () => {
|
||||
process.env.ANTHROPIC_API_KEY = 'deepseek-key'
|
||||
process.env.ANTHROPIC_BASE_URL = 'https://api.deepseek.com/anthropic'
|
||||
process.env.ANTHROPIC_MODEL = 'deepseek-v4-pro'
|
||||
process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = 'deepseek-v4-flash'
|
||||
process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'deepseek-v4-pro'
|
||||
process.env.ANTHROPIC_DEFAULT_OPUS_MODEL = 'deepseek-v4-pro'
|
||||
saveOpenAIOAuthTokens({
|
||||
accessToken: 'access-token',
|
||||
refreshToken: 'refresh-token',
|
||||
expiresAt: Date.now() + 60_000,
|
||||
})
|
||||
|
||||
const { req, url, segments } = makeRequest('GET', '/api/models')
|
||||
const res = await handleModelsApi(req, url, segments)
|
||||
|
||||
expect(res.status).toBe(200)
|
||||
const body = await res.json()
|
||||
const ids = body.models.map((model: { id: string }) => model.id)
|
||||
|
||||
expect(ids).toContain('deepseek-v4-pro')
|
||||
expect(ids).toContain('deepseek-v4-flash')
|
||||
expect(ids).toContain('gpt-5.3-codex')
|
||||
expect(ids).toContain('gpt-5.4')
|
||||
expect(ids).toContain('gpt-5.4-mini')
|
||||
expect(ids.filter((id: string) => id === 'deepseek-v4-pro')).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('GET /api/models/current should return default model when not set', async () => {
|
||||
const { req, url, segments } = makeRequest('GET', '/api/models/current')
|
||||
const res = await handleModelsApi(req, url, segments)
|
||||
@ -333,6 +425,17 @@ describe('Models API', () => {
|
||||
expect(body.model.id).toBe('claude-opus-4-7')
|
||||
})
|
||||
|
||||
it('GET /api/models/current should respect env-configured default model when no provider is active', async () => {
|
||||
process.env.ANTHROPIC_MODEL = 'deepseek-v4-pro'
|
||||
|
||||
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('deepseek-v4-pro')
|
||||
})
|
||||
|
||||
it('PUT /api/models/current should switch model', async () => {
|
||||
const { req, url, segments } = makeRequest('PUT', '/api/models/current', {
|
||||
modelId: 'claude-opus-4-7',
|
||||
@ -450,6 +553,37 @@ describe('Models API', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('Model Options', () => {
|
||||
beforeEach(setup)
|
||||
afterEach(teardown)
|
||||
|
||||
it('should keep OpenAI OAuth models visible alongside env-configured provider models', () => {
|
||||
process.env.ANTHROPIC_API_KEY = 'deepseek-key'
|
||||
process.env.ANTHROPIC_BASE_URL = 'https://api.deepseek.com/anthropic'
|
||||
process.env.ANTHROPIC_MODEL = 'deepseek-v4-pro'
|
||||
process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = 'deepseek-v4-flash'
|
||||
process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'deepseek-v4-pro'
|
||||
process.env.ANTHROPIC_DEFAULT_OPUS_MODEL = 'deepseek-v4-pro'
|
||||
saveOpenAIOAuthTokens({
|
||||
accessToken: 'access-token',
|
||||
refreshToken: 'refresh-token',
|
||||
expiresAt: Date.now() + 60_000,
|
||||
})
|
||||
|
||||
const options = getModelOptions()
|
||||
const values = options
|
||||
.map(option => option.value)
|
||||
.filter((value): value is string => typeof value === 'string')
|
||||
const labels = options.map(option => option.label)
|
||||
|
||||
expect(values).toContain('gpt-5.3-codex')
|
||||
expect(values).toContain('gpt-5.4')
|
||||
expect(values).toContain('gpt-5.4-mini')
|
||||
expect(labels).toContain('deepseek-v4-pro')
|
||||
expect(labels).toContain('deepseek-v4-flash')
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// Status API
|
||||
// =============================================================================
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
import { SettingsService } from '../services/settingsService.js'
|
||||
import { ProviderService } from '../services/providerService.js'
|
||||
import { ApiError, errorResponse } from '../middleware/errorHandler.js'
|
||||
import { hasOpenAIAuthLogin } from '../../utils/auth.js'
|
||||
import { OPENAI_CODEX_MODEL_CATALOG } from '../../services/openaiAuth/models.js'
|
||||
|
||||
// ─── Fallback models (used when no provider is configured) ────────────────────
|
||||
|
||||
@ -43,6 +45,106 @@ const DEFAULT_EFFORT = 'medium'
|
||||
const settingsService = new SettingsService()
|
||||
const providerService = new ProviderService()
|
||||
|
||||
type ApiModelInfo = {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
context: string
|
||||
}
|
||||
|
||||
function addUniqueModel(
|
||||
models: ApiModelInfo[],
|
||||
model: ApiModelInfo | null,
|
||||
): void {
|
||||
if (!model || !model.id.trim()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (models.some(existing => existing.id === model.id)) {
|
||||
return
|
||||
}
|
||||
|
||||
models.push(model)
|
||||
}
|
||||
|
||||
function buildProviderModelList(models: {
|
||||
main: string
|
||||
haiku: string
|
||||
sonnet: string
|
||||
opus: string
|
||||
}): ApiModelInfo[] {
|
||||
const modelList: ApiModelInfo[] = []
|
||||
|
||||
addUniqueModel(modelList, {
|
||||
id: models.main,
|
||||
name: models.main,
|
||||
description: 'Main model',
|
||||
context: '',
|
||||
})
|
||||
addUniqueModel(modelList, models.haiku
|
||||
? {
|
||||
id: models.haiku,
|
||||
name: models.haiku,
|
||||
description: 'Haiku model',
|
||||
context: '',
|
||||
}
|
||||
: null)
|
||||
addUniqueModel(modelList, models.sonnet
|
||||
? {
|
||||
id: models.sonnet,
|
||||
name: models.sonnet,
|
||||
description: 'Sonnet model',
|
||||
context: '',
|
||||
}
|
||||
: null)
|
||||
addUniqueModel(modelList, models.opus
|
||||
? {
|
||||
id: models.opus,
|
||||
name: models.opus,
|
||||
description: 'Opus model',
|
||||
context: '',
|
||||
}
|
||||
: null)
|
||||
|
||||
return modelList
|
||||
}
|
||||
|
||||
function getEnvConfiguredAnthropicModels(): ApiModelInfo[] {
|
||||
return buildProviderModelList({
|
||||
main: process.env.ANTHROPIC_MODEL?.trim() || '',
|
||||
haiku: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL?.trim() || '',
|
||||
sonnet: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL?.trim() || '',
|
||||
opus: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL?.trim() || '',
|
||||
})
|
||||
}
|
||||
|
||||
function getOpenAIAuthModels(): ApiModelInfo[] {
|
||||
if (!hasOpenAIAuthLogin()) {
|
||||
return []
|
||||
}
|
||||
|
||||
return OPENAI_CODEX_MODEL_CATALOG.map(model => ({
|
||||
id: model.value,
|
||||
name: model.label,
|
||||
description: model.description,
|
||||
context: '',
|
||||
}))
|
||||
}
|
||||
|
||||
function getStandaloneModelList(): ApiModelInfo[] {
|
||||
const models = [...getEnvConfiguredAnthropicModels()]
|
||||
|
||||
if (models.length === 0) {
|
||||
models.push(...DEFAULT_MODELS)
|
||||
}
|
||||
|
||||
for (const model of getOpenAIAuthModels()) {
|
||||
addUniqueModel(models, model)
|
||||
}
|
||||
|
||||
return models
|
||||
}
|
||||
|
||||
// ─── Router ───────────────────────────────────────────────────────────────────
|
||||
|
||||
export async function handleModelsApi(
|
||||
@ -83,19 +185,13 @@ async function handleModelsList(): Promise<Response> {
|
||||
const { providers, activeId } = await providerService.listProviders()
|
||||
const activeProvider = activeId ? providers.find((p) => p.id === activeId) : null
|
||||
if (activeProvider) {
|
||||
// Convert ModelMapping to model list for API compatibility
|
||||
const modelList = [
|
||||
{ id: activeProvider.models.main, name: activeProvider.models.main, description: 'Main model', context: '' },
|
||||
...(activeProvider.models.haiku !== activeProvider.models.main ? [{ id: activeProvider.models.haiku, name: activeProvider.models.haiku, description: 'Haiku model', context: '' }] : []),
|
||||
...(activeProvider.models.sonnet !== activeProvider.models.main ? [{ id: activeProvider.models.sonnet, name: activeProvider.models.sonnet, description: 'Sonnet model', context: '' }] : []),
|
||||
...(activeProvider.models.opus !== activeProvider.models.main ? [{ id: activeProvider.models.opus, name: activeProvider.models.opus, description: 'Opus model', context: '' }] : []),
|
||||
]
|
||||
const modelList = buildProviderModelList(activeProvider.models)
|
||||
return Response.json({
|
||||
models: modelList,
|
||||
provider: { id: activeProvider.id, name: activeProvider.name },
|
||||
})
|
||||
}
|
||||
return Response.json({ models: DEFAULT_MODELS, provider: null })
|
||||
return Response.json({ models: getStandaloneModelList(), provider: null })
|
||||
}
|
||||
|
||||
async function handleCurrentModel(req: Request): Promise<Response> {
|
||||
@ -109,6 +205,7 @@ async function handleCurrentModel(req: Request): Promise<Response> {
|
||||
const explicitModel = (settings.model as string) || ''
|
||||
const contextTier = (settings.modelContext as string) || undefined
|
||||
const env = (settings.env as Record<string, string>) || {}
|
||||
const envModel = process.env.ANTHROPIC_MODEL?.trim() || ''
|
||||
|
||||
let currentModelId: string
|
||||
let currentModelName: string
|
||||
@ -127,7 +224,7 @@ async function handleCurrentModel(req: Request): Promise<Response> {
|
||||
}
|
||||
} else {
|
||||
// No provider — use settings model with context tier
|
||||
currentModelId = explicitModel || DEFAULT_MODEL
|
||||
currentModelId = explicitModel || envModel || DEFAULT_MODEL
|
||||
currentModelName = currentModelId
|
||||
}
|
||||
|
||||
@ -135,13 +232,8 @@ async function handleCurrentModel(req: Request): Promise<Response> {
|
||||
|
||||
// Build available models for name lookup
|
||||
const availableModels = activeProvider
|
||||
? [
|
||||
{ id: activeProvider.models.main, name: activeProvider.models.main, description: 'Main model', context: '' },
|
||||
...(activeProvider.models.haiku && activeProvider.models.haiku !== activeProvider.models.main ? [{ id: activeProvider.models.haiku, name: activeProvider.models.haiku, description: 'Haiku model', context: '' }] : []),
|
||||
...(activeProvider.models.sonnet && activeProvider.models.sonnet !== activeProvider.models.main ? [{ id: activeProvider.models.sonnet, name: activeProvider.models.sonnet, description: 'Sonnet model', context: '' }] : []),
|
||||
...(activeProvider.models.opus && activeProvider.models.opus !== activeProvider.models.main ? [{ id: activeProvider.models.opus, name: activeProvider.models.opus, description: 'Opus model', context: '' }] : []),
|
||||
]
|
||||
: DEFAULT_MODELS
|
||||
? buildProviderModelList(activeProvider.models)
|
||||
: getStandaloneModelList()
|
||||
|
||||
const modelEntry = availableModels.find((m) => m.id === lookupId)
|
||||
|| availableModels.find((m) => m.id === currentModelId)
|
||||
|
||||
@ -1911,6 +1911,11 @@ export function getOpenAIAuthOverrideWarning(): string | null {
|
||||
return null
|
||||
}
|
||||
|
||||
export function hasOpenAIAuthLogin(): boolean {
|
||||
const openaiTokens = getOpenAIOAuthTokens()
|
||||
return !!openaiTokens?.refreshToken && !isUsing3PServices()
|
||||
}
|
||||
|
||||
export function isOpenAIAuthActive(): boolean {
|
||||
return getOpenAIAccountInformationIfActive() !== undefined
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
|
||||
import { getInitialMainLoopModel } from '../../bootstrap/state.js'
|
||||
import {
|
||||
hasOpenAIAuthLogin,
|
||||
isClaudeAISubscriber,
|
||||
isMaxSubscriber,
|
||||
isOpenAIAuthActive,
|
||||
@ -15,7 +16,7 @@ import {
|
||||
} from '../modelCost.js'
|
||||
import { getSettings_DEPRECATED } from '../settings/settings.js'
|
||||
import { checkOpus1mAccess, checkSonnet1mAccess } from './check1mAccess.js'
|
||||
import { getAPIProvider } from './providers.js'
|
||||
import { getAPIProvider, isFirstPartyAnthropicBaseUrl } from './providers.js'
|
||||
import { isModelAllowed } from './modelAllowlist.js'
|
||||
import {
|
||||
getCanonicalName,
|
||||
@ -44,6 +45,25 @@ export type ModelOption = {
|
||||
descriptionForModel?: string
|
||||
}
|
||||
|
||||
function hasAnthropicCompatibleThirdPartyConfig(): boolean {
|
||||
return getAPIProvider() !== 'firstParty' || !isFirstPartyAnthropicBaseUrl()
|
||||
}
|
||||
|
||||
function pushUniqueOption(
|
||||
options: ModelOption[],
|
||||
option: ModelOption | undefined,
|
||||
): void {
|
||||
if (!option) {
|
||||
return
|
||||
}
|
||||
|
||||
if (options.some(existing => existing.value === option.value)) {
|
||||
return
|
||||
}
|
||||
|
||||
options.push(option)
|
||||
}
|
||||
|
||||
export function getDefaultOptionForUser(fastMode = false): ModelOption {
|
||||
if (process.env.USER_TYPE === 'ant') {
|
||||
const currentModel = renderDefaultModelSetting(
|
||||
@ -79,7 +99,7 @@ export function getDefaultOptionForUser(fastMode = false): ModelOption {
|
||||
}
|
||||
|
||||
// PAYG
|
||||
const is3P = getAPIProvider() !== 'firstParty'
|
||||
const is3P = hasAnthropicCompatibleThirdPartyConfig()
|
||||
return {
|
||||
value: null,
|
||||
label: 'Default (recommended)',
|
||||
@ -88,7 +108,7 @@ export function getDefaultOptionForUser(fastMode = false): ModelOption {
|
||||
}
|
||||
|
||||
function getCustomSonnetOption(): ModelOption | undefined {
|
||||
const is3P = getAPIProvider() !== 'firstParty'
|
||||
const is3P = hasAnthropicCompatibleThirdPartyConfig()
|
||||
const customSonnetModel = process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
||||
// When a 3P user has a custom sonnet model string, show it directly
|
||||
if (is3P && customSonnetModel) {
|
||||
@ -108,7 +128,7 @@ function getCustomSonnetOption(): ModelOption | undefined {
|
||||
// @[MODEL LAUNCH]: Update or add model option functions (getSonnetXXOption, getOpusXXOption, etc.)
|
||||
// with the new model's label and description. These appear in the /model picker.
|
||||
function getSonnet46Option(): ModelOption {
|
||||
const is3P = getAPIProvider() !== 'firstParty'
|
||||
const is3P = hasAnthropicCompatibleThirdPartyConfig()
|
||||
return {
|
||||
value: is3P ? getModelStrings().sonnet46 : 'sonnet',
|
||||
label: 'Sonnet',
|
||||
@ -119,7 +139,7 @@ function getSonnet46Option(): ModelOption {
|
||||
}
|
||||
|
||||
function getCustomOpusOption(): ModelOption | undefined {
|
||||
const is3P = getAPIProvider() !== 'firstParty'
|
||||
const is3P = hasAnthropicCompatibleThirdPartyConfig()
|
||||
const customOpusModel = process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
||||
// When a 3P user has a custom opus model string, show it directly
|
||||
if (is3P && customOpusModel) {
|
||||
@ -155,7 +175,7 @@ function getOpus46Option(fastMode = false): ModelOption {
|
||||
}
|
||||
|
||||
export function getSonnet46_1MOption(): ModelOption {
|
||||
const is3P = getAPIProvider() !== 'firstParty'
|
||||
const is3P = hasAnthropicCompatibleThirdPartyConfig()
|
||||
return {
|
||||
value: is3P ? getModelStrings().sonnet46 + '[1m]' : 'sonnet[1m]',
|
||||
label: 'Sonnet (1M context)',
|
||||
@ -166,7 +186,7 @@ export function getSonnet46_1MOption(): ModelOption {
|
||||
}
|
||||
|
||||
export function getOpus46_1MOption(fastMode = false): ModelOption {
|
||||
const is3P = getAPIProvider() !== 'firstParty'
|
||||
const is3P = hasAnthropicCompatibleThirdPartyConfig()
|
||||
return {
|
||||
value: is3P ? getModelStrings().opus46 + '[1m]' : 'opus[1m]',
|
||||
label: 'Opus (1M context)',
|
||||
@ -177,7 +197,7 @@ export function getOpus46_1MOption(fastMode = false): ModelOption {
|
||||
}
|
||||
|
||||
function getCustomHaikuOption(): ModelOption | undefined {
|
||||
const is3P = getAPIProvider() !== 'firstParty'
|
||||
const is3P = hasAnthropicCompatibleThirdPartyConfig()
|
||||
const customHaikuModel = process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
||||
// When a 3P user has a custom haiku model string, show it directly
|
||||
if (is3P && customHaikuModel) {
|
||||
@ -193,7 +213,7 @@ function getCustomHaikuOption(): ModelOption | undefined {
|
||||
}
|
||||
|
||||
function getHaiku45Option(): ModelOption {
|
||||
const is3P = getAPIProvider() !== 'firstParty'
|
||||
const is3P = hasAnthropicCompatibleThirdPartyConfig()
|
||||
return {
|
||||
value: 'haiku',
|
||||
label: 'Haiku',
|
||||
@ -231,7 +251,7 @@ function getMaxOpusOption(fastMode = false): ModelOption {
|
||||
}
|
||||
|
||||
export function getMaxSonnet46_1MOption(): ModelOption {
|
||||
const is3P = getAPIProvider() !== 'firstParty'
|
||||
const is3P = hasAnthropicCompatibleThirdPartyConfig()
|
||||
const billingInfo = isClaudeAISubscriber() ? ' · Billed as extra usage' : ''
|
||||
return {
|
||||
value: 'sonnet[1m]',
|
||||
@ -250,7 +270,7 @@ export function getMaxOpus46_1MOption(fastMode = false): ModelOption {
|
||||
}
|
||||
|
||||
function getMergedOpus1MOption(fastMode = false): ModelOption {
|
||||
const is3P = getAPIProvider() !== 'firstParty'
|
||||
const is3P = hasAnthropicCompatibleThirdPartyConfig()
|
||||
return {
|
||||
value: is3P ? getModelStrings().opus46 + '[1m]' : 'opus[1m]',
|
||||
label: 'Opus (1M context)',
|
||||
@ -319,8 +339,17 @@ function getOpenAIModelOptions(): ModelOption[] {
|
||||
descriptionForModel: model.descriptionForModel,
|
||||
})),
|
||||
]
|
||||
}
|
||||
|
||||
if (!hasAnthropicCompatibleThirdPartyConfig()) {
|
||||
return options
|
||||
}
|
||||
|
||||
pushUniqueOption(options, getCustomSonnetOption())
|
||||
pushUniqueOption(options, getCustomOpusOption())
|
||||
pushUniqueOption(options, getCustomHaikuOption())
|
||||
|
||||
return options
|
||||
}
|
||||
// @[MODEL LAUNCH]: Update the model picker lists below to include/reorder options for the new model.
|
||||
// Each user tier (ant, Max/Team Premium, Pro/Team Standard/Enterprise, PAYG 1P, PAYG 3P) has its own list.
|
||||
function getModelOptionsBase(fastMode = false): ModelOption[] {
|
||||
@ -346,8 +375,8 @@ function getModelOptionsBase(fastMode = false): ModelOption[] {
|
||||
]
|
||||
}
|
||||
|
||||
if (isOpenAIAuthActive()) {
|
||||
return getOpenAIModelOptions()
|
||||
if (hasOpenAIAuthLogin()) {
|
||||
return getOpenAIModelOptions(fastMode)
|
||||
}
|
||||
|
||||
if (isClaudeAISubscriber()) {
|
||||
@ -387,7 +416,7 @@ function getModelOptionsBase(fastMode = false): ModelOption[] {
|
||||
}
|
||||
|
||||
// PAYG 1P API: Default (Sonnet) + Sonnet 1M + Opus 4.7 + Opus 1M + Haiku
|
||||
if (getAPIProvider() === 'firstParty') {
|
||||
if (!hasAnthropicCompatibleThirdPartyConfig()) {
|
||||
const payg1POptions = [getDefaultOptionForUser(fastMode)]
|
||||
if (checkSonnet1mAccess()) {
|
||||
payg1POptions.push(getSonnet46_1MOption())
|
||||
@ -409,7 +438,7 @@ function getModelOptionsBase(fastMode = false): ModelOption[] {
|
||||
|
||||
const customSonnet = getCustomSonnetOption()
|
||||
if (customSonnet !== undefined) {
|
||||
payg3pOptions.push(customSonnet)
|
||||
pushUniqueOption(payg3pOptions, customSonnet)
|
||||
} else {
|
||||
// Add Sonnet 4.6 since Sonnet 4.5 is the default
|
||||
payg3pOptions.push(getSonnet46Option())
|
||||
@ -420,7 +449,7 @@ function getModelOptionsBase(fastMode = false): ModelOption[] {
|
||||
|
||||
const customOpus = getCustomOpusOption()
|
||||
if (customOpus !== undefined) {
|
||||
payg3pOptions.push(customOpus)
|
||||
pushUniqueOption(payg3pOptions, customOpus)
|
||||
} else {
|
||||
// Add Opus 4.1, Opus 4.7 and Opus 4.7 1M
|
||||
payg3pOptions.push(getOpus41Option()) // This is the default opus
|
||||
@ -431,7 +460,7 @@ function getModelOptionsBase(fastMode = false): ModelOption[] {
|
||||
}
|
||||
const customHaiku = getCustomHaikuOption()
|
||||
if (customHaiku !== undefined) {
|
||||
payg3pOptions.push(customHaiku)
|
||||
pushUniqueOption(payg3pOptions, customHaiku)
|
||||
} else {
|
||||
payg3pOptions.push(getHaikuOption())
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user