Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97,844 changes: 54,018 additions & 43,826 deletions resources/model-db/providers.json

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions src/main/presenter/configPresenter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,34 @@ export class ConfigPresenter implements IConfigPresenter {
console.warn('Failed to migrate legacy default_system_prompt:', e)
}
}

// Before version 0.5.8, split OpenAI Responses and OpenAI Completions semantics
if (oldVersion && compare(oldVersion, '0.5.8', '<')) {
const providers = this.getProviders()
let hasChanges = false

const migratedProviders = providers.map((provider) => {
if (provider.apiType === 'openai-compatible') {
hasChanges = true
return { ...provider, apiType: 'openai-completions' }
}

if (
provider.id !== 'openai' &&
provider.id !== 'minimax' &&
provider.apiType === 'openai'
) {
hasChanges = true
return { ...provider, apiType: 'openai-completions' }
}

return provider
})

if (hasChanges) {
this.setProviders(migratedProviders)
}
}
}

private migrateMinimaxProvider(): void {
Expand Down
26 changes: 13 additions & 13 deletions src/main/presenter/configPresenter/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'qiniu',
name: 'Qiniu',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://api.qnaigc.com/v1',
enable: false,
Expand Down Expand Up @@ -80,7 +80,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'ppio',
name: 'PPIO',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://api.ppinfra.com/v3/openai',
enable: false,
Expand Down Expand Up @@ -128,7 +128,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'tokenflux',
name: 'TokenFlux',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://tokenflux.ai/v1',
enable: false,
Expand All @@ -144,7 +144,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'burncloud',
name: 'BurnCloud',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://ai.burncloud.com',
enable: false,
Expand Down Expand Up @@ -280,7 +280,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'openrouter',
name: 'OpenRouter',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://openrouter.ai/api/v1/',
enable: false,
Expand Down Expand Up @@ -310,7 +310,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: '302ai',
name: '302.AI',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://api.302.ai/v1',
enable: false,
Expand Down Expand Up @@ -370,7 +370,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'github',
name: 'GitHub Models',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://models.inference.ai.azure.com',
enable: false,
Expand Down Expand Up @@ -476,7 +476,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'moonshot',
name: 'Moonshot',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://api.moonshot.cn/v1',
enable: false,
Expand Down Expand Up @@ -628,7 +628,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'aihubmix',
name: 'AIHubMix',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://aihubmix.com/v1',
enable: false,
Expand Down Expand Up @@ -673,7 +673,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'hunyuan',
name: 'Hunyuan',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://api.hunyuan.cloud.tencent.com/v1',
enable: false,
Expand Down Expand Up @@ -703,7 +703,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'azure-openai',
name: 'Azure OpenAI',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: '',
enable: false,
Expand All @@ -720,7 +720,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'modelscope',
name: 'ModelScope',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://api-inference.modelscope.cn/v1/',
enable: false,
Expand Down Expand Up @@ -750,7 +750,7 @@ export const DEFAULT_PROVIDERS: LLM_PROVIDER_BASE[] = [
{
id: 'xiaomi',
name: 'Xiaomi',
apiType: 'openai',
apiType: 'openai-completions',
apiKey: '',
baseUrl: 'https://api.xiaomimimo.com/v1',
enable: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ProviderBatchUpdate, ProviderChange } from '@shared/provider-operations'
import { IConfigPresenter, LLM_PROVIDER } from '@shared/presenter'
import { BaseLLMProvider } from '../baseProvider'
import { OpenAIProvider } from '../providers/openAIProvider'
import { DeepseekProvider } from '../providers/deepseekProvider'
import { SiliconcloudProvider } from '../providers/siliconcloudProvider'
import { DashscopeProvider } from '../providers/dashscopeProvider'
Expand Down Expand Up @@ -85,7 +84,7 @@ export class ProviderInstanceManager {
['ollama', OllamaProvider],
['anthropic', AnthropicProvider],
['doubao', DoubaoProvider],
['openai', OpenAIProvider],
['openai', OpenAIResponsesProvider],
['voiceai', VoiceAIProvider],
['openai-responses', OpenAIResponsesProvider],
['cherryin', CherryInProvider],
Expand Down Expand Up @@ -118,7 +117,8 @@ export class ProviderInstanceManager {
['ollama', OllamaProvider],
['anthropic', AnthropicProvider],
['doubao', DoubaoProvider],
['openai', OpenAIProvider],
['openai', OpenAIResponsesProvider],
['openai-completions', OpenAICompatibleProvider],
['voiceai', VoiceAIProvider],
['openai-compatible', OpenAICompatibleProvider],
['openai-responses', OpenAIResponsesProvider],
Expand Down
19 changes: 15 additions & 4 deletions src/renderer/settings/components/AddCustomProviderDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</SelectTrigger>
<SelectContent>
<SelectItem value="openai">OpenAI</SelectItem>
<SelectItem value="openai-responses">OpenAI Responses</SelectItem>
<SelectItem value="openai-completions">OpenAI Completions</SelectItem>
<SelectItem value="gemini">Gemini</SelectItem>
<SelectItem value="anthropic">Anthropic</SelectItem>
<SelectItem value="ollama">Ollama</SelectItem>
Expand Down Expand Up @@ -69,8 +69,8 @@
:placeholder="t('settings.provider.dialog.addCustomProvider.baseUrlPlaceholder')"
required
/>
<div v-if="formData.apiType === 'openai'" class="text-xs text-muted-foreground mt-1">
{{ `${formData.baseUrl ?? ''}/chat/completions` }}
<div v-if="apiEndpointSuffix" class="text-xs text-muted-foreground mt-1">
{{ `${formData.baseUrl ?? ''}${apiEndpointSuffix}` }}
</div>
</span>
</div>
Expand Down Expand Up @@ -100,7 +100,7 @@
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { nanoid } from 'nanoid'
import {
Expand Down Expand Up @@ -139,6 +139,17 @@ const emit = defineEmits<{

const isOpen = ref(props.open)
const isSubmitting = ref(false)
const apiEndpointSuffix = computed(() => {
if (formData.value.apiType === 'openai') {
return '/responses'
}

if (formData.value.apiType === 'openai-completions') {
return '/chat/completions'
}

return ''
})

const formData = ref<LLM_PROVIDER>({
id: '',
Expand Down
12 changes: 12 additions & 0 deletions src/renderer/settings/components/ProviderApiConfig.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
<template>
<div class="flex flex-col gap-4">
<div
v-if="provider.id === 'openai'"
class="w-full rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-amber-900"
>
<div class="flex items-start gap-2">
<Icon icon="lucide:triangle-alert" class="h-4 w-4 mt-0.5 shrink-0" />
<p class="text-sm font-medium leading-5">
{{ t('settings.provider.openaiResponsesNotice') }}
</p>
</div>
</div>

<!-- API URL 配置 -->
<div class="flex flex-col items-start gap-2">
<div class="flex justify-between items-center w-full">
Expand Down
24 changes: 20 additions & 4 deletions src/renderer/src/components/settings/ModelConfigDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ import { ApiEndpointType, ModelType } from '@shared/model'
import type { ModelConfig } from '@shared/presenter'
import { useModelConfigStore } from '@/stores/modelConfigStore'
import { useModelStore } from '@/stores/modelStore'
import { useProviderStore } from '@/stores/providerStore'
import { usePresenter } from '@/composables/usePresenter'
import {
Dialog,
Expand Down Expand Up @@ -496,8 +497,13 @@ const emit = defineEmits<{
const { t } = useI18n()
const modelConfigStore = useModelConfigStore()
const modelStore = useModelStore()
const providerStore = useProviderStore()
const { customModels, allProviderModels } = storeToRefs(modelStore)
const configPresenter = usePresenter('configPresenter')
const providerIdLower = computed(() => props.providerId?.toLowerCase() || '')
const currentProvider = computed(() =>
providerStore.providers.find((provider) => provider.id === props.providerId)
)

const isOpenAICompatibleProvider = computed(() => {
const EXCLUDED_PROVIDERS = [
Expand All @@ -510,11 +516,21 @@ const isOpenAICompatibleProvider = computed(() => {
'acp',
'voiceai'
]
const providerId = props.providerId?.toLowerCase() || ''
return !EXCLUDED_PROVIDERS.some((excluded) => providerId.includes(excluded))
return !EXCLUDED_PROVIDERS.some((excluded) => providerIdLower.value.includes(excluded))
})

const isResponsesProvider = computed(() => {
if (providerIdLower.value === 'openai' || providerIdLower.value === 'openai-responses') {
return true
}

const apiType = currentProvider.value?.apiType?.toLowerCase()
return apiType === 'openai' || apiType === 'openai-responses'
})

const showApiEndpointSelector = computed(() => isOpenAICompatibleProvider.value)
const showApiEndpointSelector = computed(
() => !isResponsesProvider.value && isOpenAICompatibleProvider.value
)

const createDefaultConfig = (): ModelConfig => ({
maxTokens: 4096,
Expand Down Expand Up @@ -636,7 +652,7 @@ const loadConfig = async () => {
const modelConfig = await modelConfigStore.getModelConfig(props.modelId, props.providerId)
config.value = { ...modelConfig }

if (isOpenAICompatibleProvider.value && !config.value.apiEndpoint) {
if (showApiEndpointSelector.value && !config.value.apiEndpoint) {
config.value.apiEndpoint = ApiEndpointType.Chat
}
} catch (error) {
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/da-DK/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@
"getKeyTipEnd": "for at få API-nøglen",
"urlFormat": "API-eksempel: {defaultUrl}",
"urlFormatFill": "Udfyld API-URL",
"openaiResponsesNotice": "OpenAI bruger som standard Responses API. Hvis et tredjeparts-endpoint kun understøtter Chat Completions, skal du bruge OpenAI Completions-udbyderen.",
"modelList": "Modelliste",
"enableModels": "Aktivér modeller",
"disableAllModels": "Deaktiver alle modeller",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/en-US/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@
"getKeyTipEnd": "to get API Key",
"urlFormat": "API Example: {defaultUrl}",
"urlFormatFill": "Fill into API URL",
"openaiResponsesNotice": "OpenAI defaults to the Responses API. If a third-party endpoint only supports Chat Completions, use the OpenAI Completions provider.",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

New i18n key doesn’t follow lowercase dot-separated naming.

The key openaiResponsesNotice introduces camelCase. Consider nesting as provider.openai.responses.notice and update references + other locales accordingly.

♻️ Suggested key structure (en-US example)
-    "openaiResponsesNotice": "OpenAI defaults to the Responses API. If a third-party endpoint only supports Chat Completions, use the OpenAI Completions provider.",
+    "openai": {
+      "responses": {
+        "notice": "OpenAI defaults to the Responses API. If a third-party endpoint only supports Chat Completions, use the OpenAI Completions provider."
+      }
+    },

As per coding guidelines: Use dot-separated hierarchical structure for translation key naming with lowercase letters and descriptive names grouped by feature/context (e.g., common.button.submit, chat.send.placeholder).

🤖 Prompt for AI Agents
In `@src/renderer/src/i18n/en-US/settings.json` at line 317, The i18n key
openaiResponsesNotice uses camelCase instead of the required lowercase
dot-separated hierarchy; rename the key to provider.openai.responses.notice in
src/renderer/src/i18n/en-US/settings.json, update all code references that read
openaiResponsesNotice to use provider.openai.responses.notice (eg. any
getString/getTranslation or useI18n lookups), and mirror the same key change
across all locale files so translations remain in sync.

"modelList": "Model List",
"enableModels": "Enable Models",
"disableAllModels": "Disable All Models",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/fa-IR/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@
"getKeyTipEnd": "بروید تا کلید API را دریافت کنید",
"urlFormat": "نمونه API: {defaultUrl}",
"urlFormatFill": "قرار دادن در URL API",
"openaiResponsesNotice": "OpenAI به صورت پیش‌فرض از Responses API استفاده می‌کند. اگر endpoint شخص ثالث فقط از Chat Completions پشتیبانی می‌کند، از ارائه‌دهنده OpenAI Completions استفاده کنید.",
"modelList": "فهرست مدل‌ها",
"enableModels": "روشن کردن مدل‌ها",
"disableAllModels": "خاموش کردن همه مدل‌ها",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/fr-FR/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@
"getKeyTipEnd": "pour obtenir la clé API",
"urlFormat": "Exemple d'API : {defaultUrl}",
"urlFormatFill": "Renseigner l'URL de l'API",
"openaiResponsesNotice": "OpenAI utilise par défaut l'API Responses. Si un endpoint tiers ne prend en charge que Chat Completions, utilisez le fournisseur OpenAI Completions.",
"modelList": "Liste des modèles",
"enableModels": "Activer les modèles",
"disableAllModels": "Désactiver tous les modèles",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/he-IL/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@
"getKeyTipEnd": "כדי לקבל מפתח API",
"urlFormat": "דוגמת API: {defaultUrl}",
"urlFormatFill": "מילוי בכתובת ה-API",
"openaiResponsesNotice": "OpenAI משתמשת כברירת מחדל ב-Responses API. אם endpoint של צד שלישי תומך רק ב-Chat Completions, השתמש בספק OpenAI Completions.",
"modelList": "רשימת מודלים",
"enableModels": "הפעל מודלים",
"disableAllModels": "השבת את כל המודלים",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/ja-JP/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@
"getKeyTipEnd": "API Keyを取得する",
"urlFormat": "API例:{defaultUrl}",
"urlFormatFill": "API URL に入力",
"openaiResponsesNotice": "OpenAI 公式サービスはデフォルトで Responses API を使用します。サードパーティのエンドポイントが Chat Completions のみをサポートしている場合は、OpenAI Completions プロバイダーを使用してください。",
"modelList": "モデル一覧",
"enableModels": "モデルを有効にする",
"disableAllModels": "すべてのモデルを無効にする",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/ko-KR/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@
"localModels": "로컬 모델",
"urlFormat": "API 샘플 : {defaultUrl}",
"urlFormatFill": "API URL에 입력",
"openaiResponsesNotice": "OpenAI 공식 서비스는 기본적으로 Responses API를 사용합니다. 서드파티 엔드포인트가 Chat Completions만 지원하는 경우 OpenAI Completions 공급자를 사용하세요.",
"azureApiVersion": "API 버전",
"safety": {
"title": "보안 설정",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/pt-BR/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@
"getKeyTipEnd": "para obter a Chave da API",
"urlFormat": "Exemplo de API: {defaultUrl}",
"urlFormatFill": "Preencher na URL da API",
"openaiResponsesNotice": "A OpenAI usa a API Responses por padrão. Se um endpoint de terceiros oferecer suporte apenas a Chat Completions, use o provedor OpenAI Completions.",
"modelList": "Lista de Modelos",
"enableModels": "Habilitar Modelos",
"disableAllModels": "Desabilitar Todos os Modelos",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/ru-RU/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@
"localModels": "Локальные модели",
"urlFormat": "Образец API: {defaultUrl}",
"urlFormatFill": "Подставить в URL API",
"openaiResponsesNotice": "OpenAI по умолчанию использует Responses API. Если сторонний endpoint поддерживает только Chat Completions, используйте провайдера OpenAI Completions.",
"azureApiVersion": "Версия API",
"safety": {
"title": "Настройки безопасности",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/zh-CN/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@
"getKeyTipEnd": "获取API Key",
"urlFormat": "API样例:{defaultUrl}",
"urlFormatFill": "填充到 API URL",
"openaiResponsesNotice": "OpenAI 官方服务默认使用 Responses API;若第三方仅支持 Chat Completions,请使用 OpenAI Completions 服务商。",
"modelList": "模型列表",
"enableModels": "启用模型",
"disableAllModels": "禁用全部",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/zh-HK/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@
"getKeyTipEnd": "獲取API Key",
"urlFormat": "API範例:{defaultUrl}",
"urlFormatFill": "填入 API URL",
"openaiResponsesNotice": "OpenAI 官方服務預設使用 Responses API;若第三方僅支援 Chat Completions,請使用 OpenAI Completions 服務商。",
"modelList": "模型列表",
"enableModels": "模型已經啟用",
"verifyLink": "驗證鏈接",
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/i18n/zh-TW/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@
"getKeyTipEnd": "取得 API 金鑰",
"urlFormat": "API 範例:{defaultUrl}",
"urlFormatFill": "填入 API URL",
"openaiResponsesNotice": "OpenAI 官方服務預設使用 Responses API;若第三方僅支援 Chat Completions,請使用 OpenAI Completions 服務商。",
"modelList": "模型清單",
"enableModels": "啟用模型",
"disableAllModels": "全部停用",
Expand Down