fix(cli): fix third-party service misidentified as local when editing in CLI Web

- Add apiKeySet field to GET /_web/ai/llm/configs response
- Allow saving in edit mode without re-entering API key when key already set
- Skip API key validation on save when editing with existing key unchanged
- Show edit-mode placeholder hint on API Key input
- Add missing customModels/disableThinking/isReasoningModel to CLI route types

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
diguaandCursor authored and digua committed 2026-05-27 23:47:27 +08:00
1 parent 1aee8133a3
commit 63e101feb4
4 files changed
+20 -5

No files matched your search

+1
View File
@@ -27,6 +27,7 @@ export interface AIServiceConfig {
apiFormat?: string
disableThinking?: boolean
isReasoningModel?: boolean
customModels?: Array<{ id: string; name: string }>
authProfile?: string
}
+7 -1
View File
@@ -179,7 +179,7 @@ export function registerAiRoutes(
const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
const configs = (data.configs || []).map((c: Record<string, unknown>) => {
const { apiKey: _k, ...rest } = c
return { ...rest, apiKey: '' }
return { ...rest, apiKey: '', apiKeySet: !!c.authProfile }
})
return {
configs,
@@ -268,6 +268,9 @@ export function registerAiRoutes(
baseUrl?: string
maxTokens?: number
apiFormat?: string
disableThinking?: boolean
isReasoningModel?: boolean
customModels?: Array<{ id: string; name: string }>
}
}>('/_web/ai/llm/configs', async (request) => {
const aiDataDir = getAiDir(dbManager)
@@ -284,6 +287,9 @@ export function registerAiRoutes(
baseUrl?: string
maxTokens?: number
apiFormat?: string
disableThinking?: boolean
isReasoningModel?: boolean
customModels?: Array<{ id: string; name: string }>
}
}>('/_web/ai/llm/configs/:id', async (request) => {
const aiDataDir = getAiDir(dbManager)
@@ -172,7 +172,7 @@ function closeModal() {
<!-- API Key -->
<ApiKeyInput
v-model="formData.apiKey"
:placeholder="t('settings.aiConfig.modal.apiKeyPlaceholder')"
:placeholder="mode === 'edit' && config?.apiKeySet ? t('settings.aiConfig.modal.apiKeyPlaceholderEdit') : t('settings.aiConfig.modal.apiKeyPlaceholder')"
:validate-loading="isValidating"
:validate-disabled="!formData.apiKey"
:validate-text="t('settings.aiConfig.modal.validate')"
@@ -402,7 +402,7 @@ function closeModal() {
<!-- API Key -->
<ApiKeyInput
v-model="formData.apiKey"
:placeholder="t('settings.aiConfig.modal.apiKeyPlaceholder')"
:placeholder="mode === 'edit' && config?.apiKeySet ? t('settings.aiConfig.modal.apiKeyPlaceholderEdit') : t('settings.aiConfig.modal.apiKeyPlaceholder')"
:validate-loading="isValidating"
:validate-disabled="!formData.apiKey || !formData.baseUrl"
:validate-text="t('settings.aiConfig.modal.validate')"
@@ -164,17 +164,19 @@ export function useAIConfigForm(props: {
const canSave = computed(() => {
const { provider, apiKey, baseUrl, model } = formData.value
const isEdit = props.mode.value === 'edit'
const existingKeySet = isEdit && props.config.value?.apiKeySet
if (isLocalMode.value) {
return baseUrl.trim() && model.trim()
}
if (isOpenAICompat.value) {
return baseUrl.trim() && apiKey.trim() && model.trim()
return baseUrl.trim() && (apiKey.trim() || existingKeySet) && model.trim()
}
if (!provider) return false
return apiKey.trim()
return apiKey.trim() || existingKeySet
})
const apiFormatItems = computed(() =>
@@ -690,6 +692,12 @@ export function useAIConfigForm(props: {
return doSave()
}
const hasNewApiKey = !!formData.value.apiKey.trim()
const isEditWithExistingKey = props.mode.value === 'edit' && props.config.value?.apiKeySet && !hasNewApiKey
if (isEditWithExistingKey) {
return doSave()
}
isValidating.value = true
try {
const testApiKey = formData.value.apiKey.trim() || 'sk-no-key-required'