diff --git a/frontend/src/views/accounts/components/AccountQuotaSummaryCell/index.vue b/frontend/src/views/accounts/components/AccountQuotaSummaryCell/index.vue index be144720f..5633c2ab9 100644 --- a/frontend/src/views/accounts/components/AccountQuotaSummaryCell/index.vue +++ b/frontend/src/views/accounts/components/AccountQuotaSummaryCell/index.vue @@ -50,7 +50,7 @@ const additionalEntryCount = computed(() => Math.max(summaryEntries.value.length class="flex shrink-0 items-baseline gap-1 text-[9px] font-emphasis text-cp-text-quaternary" title="最近使用额度的当前已用比例" > - 消耗比例 + 使用率 {{ currentUsageDisplay }} diff --git a/frontend/src/views/api-keys/components/ApiKeyUseModal.vue b/frontend/src/views/api-keys/components/ApiKeyUseModal.vue index e01dda302..04c83e7ca 100644 --- a/frontend/src/views/api-keys/components/ApiKeyUseModal.vue +++ b/frontend/src/views/api-keys/components/ApiKeyUseModal.vue @@ -8,6 +8,10 @@ import BaseModal from '@/components/base/BaseModal/index.vue' import BaseScrollbar from '@/components/base/BaseScrollbar.vue' import BaseSegmented from '@/components/base/BaseSegmented.vue' import BaseSwitch from '@/components/base/BaseSwitch.vue' +import { + buildCodexConfigFiles, + CODEX_WEBSOCKET_ENABLED_BY_DEFAULT, +} from '../utils/codexConfig' const props = defineProps<{ apiKey: { @@ -24,7 +28,7 @@ const emit = defineEmits<{ const open = defineModel({ default: false }) const activePlatform = shallowRef('unix') -const websocketEnabled = shallowRef(true) +const websocketEnabled = shallowRef(CODEX_WEBSOCKET_ENABLED_BY_DEFAULT) const platformOptions = [ { label: 'macOS / Linux', value: 'unix', icon: Apple }, @@ -40,31 +44,15 @@ const configPath = computed(() => const authPath = computed(() => activePlatform.value === 'windows' ? '%userprofile%\\.codex\\auth.json' : '~/.codex/auth.json', ) -const codexAuthJson = computed(() => JSON.stringify({ OPENAI_API_KEY: keyValue.value }, null, 2)) -const defaultModel = 'gpt-5.6-terra' - -const codexConfigToml = computed( - () => `model_provider = "OpenAI" -model = "${defaultModel}" -review_model = "${defaultModel}" -model_reasoning_effort = "max" -service_tier = "default" -disable_response_storage = true -network_access = "enabled" - -[model_providers.OpenAI] -name = "OpenAI" -base_url = "${props.apiBaseUrl}" -wire_api = "responses"${websocketEnabled.value ? '\nsupports_websockets = true' : ''} -requires_openai_auth = true - -[features]${websocketEnabled.value ? '\nresponses_websockets_v2 = true' : ''} -goals = true`, -) +const codexConfigFiles = computed(() => buildCodexConfigFiles({ + apiKey: keyValue.value, + baseUrl: props.apiBaseUrl, + websocketEnabled: websocketEnabled.value, +})) const visibleFiles = computed(() => [ - { path: configPath.value, content: codexConfigToml.value, scrollbarHeight: '360px' }, - { path: authPath.value, content: codexAuthJson.value, scrollbarHeight: undefined }, + { path: configPath.value, content: codexConfigFiles.value.configToml, scrollbarHeight: '360px' }, + { path: authPath.value, content: codexConfigFiles.value.authJson, scrollbarHeight: undefined }, ]) diff --git a/frontend/src/views/api-keys/utils/ccswitchImport.ts b/frontend/src/views/api-keys/utils/ccswitchImport.ts index faded9851..26df5b2fb 100644 --- a/frontend/src/views/api-keys/utils/ccswitchImport.ts +++ b/frontend/src/views/api-keys/utils/ccswitchImport.ts @@ -1,4 +1,8 @@ -const DEFAULT_CC_SWITCH_MODEL = 'gpt-5.5' +import { + buildCodexConfigFiles, + CODEX_DEFAULT_MODEL, + CODEX_WEBSOCKET_ENABLED_BY_DEFAULT, +} from './codexConfig' export interface CodexCcSwitchImportInput { apiKey: string @@ -7,18 +11,37 @@ export interface CodexCcSwitchImportInput { } export function buildCodexCcSwitchImportDeeplink(input: CodexCcSwitchImportInput): string { - const baseUrl = input.baseUrl.replace(/\/+$/, '') + const configFiles = buildCodexConfigFiles({ + apiKey: input.apiKey, + baseUrl: input.baseUrl, + websocketEnabled: CODEX_WEBSOCKET_ENABLED_BY_DEFAULT, + }) + // Carry the complete files shown in the UI; the explicit fields below keep + // compatibility with CCSwitch versions that only extract common settings. + const config = encodeBase64(JSON.stringify({ + auth: configFiles.auth, + config: configFiles.configToml, + })) const entries: [string, string][] = [ ['resource', 'provider'], ['app', 'codex'], - ['model', DEFAULT_CC_SWITCH_MODEL], + ['model', CODEX_DEFAULT_MODEL], ['name', input.providerName], - ['homepage', baseUrl], - ['endpoint', baseUrl], + ['homepage', configFiles.baseUrl], + ['endpoint', configFiles.baseUrl], ['apiKey', input.apiKey], ['configFormat', 'json'], + ['config', config], ['usageEnabled', 'false'], ] return `ccswitch://v1/import?${new URLSearchParams(entries).toString()}` } + +function encodeBase64(value: string) { + const bytes = new TextEncoder().encode(value) + let binary = '' + for (const byte of bytes) + binary += String.fromCharCode(byte) + return btoa(binary) +} diff --git a/frontend/src/views/api-keys/utils/codexConfig.ts b/frontend/src/views/api-keys/utils/codexConfig.ts new file mode 100644 index 000000000..1cb19229c --- /dev/null +++ b/frontend/src/views/api-keys/utils/codexConfig.ts @@ -0,0 +1,37 @@ +export const CODEX_DEFAULT_MODEL = 'gpt-5.6-terra' +export const CODEX_WEBSOCKET_ENABLED_BY_DEFAULT = true + +export interface CodexConfigInput { + apiKey: string + baseUrl: string + websocketEnabled?: boolean +} + +export function buildCodexConfigFiles(input: CodexConfigInput) { + const baseUrl = input.baseUrl.replace(/\/+$/, '') + const websocketEnabled = input.websocketEnabled ?? CODEX_WEBSOCKET_ENABLED_BY_DEFAULT + const auth = { OPENAI_API_KEY: input.apiKey } + const configToml = `model_provider = "OpenAI" +model = "${CODEX_DEFAULT_MODEL}" +review_model = "${CODEX_DEFAULT_MODEL}" +model_reasoning_effort = "max" +service_tier = "default" +disable_response_storage = true +network_access = "enabled" + +[model_providers.OpenAI] +name = "OpenAI" +base_url = "${baseUrl}" +wire_api = "responses"${websocketEnabled ? '\nsupports_websockets = true' : ''} +requires_openai_auth = true + +[features]${websocketEnabled ? '\nresponses_websockets_v2 = true' : ''} +goals = true` + + return { + auth, + authJson: JSON.stringify(auth, null, 2), + baseUrl, + configToml, + } +}