mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-01 15:32:11 +08:00
fix: remove provider metadata duplication
This commit is contained in:
+22
-18
@@ -18,6 +18,8 @@ import ai.kilocode.rpc.dto.MessageDto
|
||||
import ai.kilocode.rpc.dto.MessageErrorDto
|
||||
import ai.kilocode.rpc.dto.MessageTimeDto
|
||||
import ai.kilocode.rpc.dto.MessageWithPartsDto
|
||||
import ai.kilocode.rpc.dto.ModelDto
|
||||
import ai.kilocode.rpc.dto.ModelLimitDto
|
||||
import ai.kilocode.rpc.dto.ModelSelectionDto
|
||||
import ai.kilocode.rpc.dto.ModelStateDto
|
||||
import ai.kilocode.rpc.dto.PartDto
|
||||
@@ -437,22 +439,7 @@ object KiloCliDataParser {
|
||||
source = item.str("source"),
|
||||
key = item.str("key"),
|
||||
metadata = parseProviderMetadata(item["metadata"].obj()),
|
||||
models = item["models"]?.jsonObject?.mapValues { (id, v) ->
|
||||
val model = parseModel(id, v.jsonObject)
|
||||
ai.kilocode.rpc.dto.ModelDto(
|
||||
id = model.id,
|
||||
name = model.name,
|
||||
attachment = model.attachment,
|
||||
reasoning = model.reasoning,
|
||||
temperature = model.temperature,
|
||||
toolCall = model.toolCall,
|
||||
free = model.free,
|
||||
status = model.status,
|
||||
recommendedIndex = model.recommendedIndex,
|
||||
variants = model.variants,
|
||||
limit = model.limit?.let { ai.kilocode.rpc.dto.ModelLimitDto(it.context, it.input, it.output) },
|
||||
)
|
||||
} ?: emptyMap(),
|
||||
models = item["models"]?.jsonObject?.mapValues { (id, v) -> parseModelDto(id, v.jsonObject) } ?: emptyMap(),
|
||||
)
|
||||
} ?: emptyList()
|
||||
val connected = obj["connected"]?.jsonArray?.mapNotNull { it.jsonPrimitive.contentOrNull } ?: emptyList()
|
||||
@@ -984,13 +971,30 @@ object KiloCliDataParser {
|
||||
if (obj == null) return null
|
||||
val dto = ProviderMetadataDto(
|
||||
noteKey = obj.str("noteKey"),
|
||||
note = obj.str("note"),
|
||||
icon = obj.str("icon"),
|
||||
priority = obj.num("priority")?.toInt(),
|
||||
)
|
||||
if (dto.noteKey == null && dto.note == null && dto.icon == null) return null
|
||||
if (dto.noteKey == null && dto.icon == null && dto.priority == null) return null
|
||||
return dto
|
||||
}
|
||||
|
||||
private fun parseModelDto(id: String, obj: JsonObject): ModelDto {
|
||||
val model = parseModel(id, obj)
|
||||
return ModelDto(
|
||||
id = model.id,
|
||||
name = model.name,
|
||||
attachment = model.attachment,
|
||||
reasoning = model.reasoning,
|
||||
temperature = model.temperature,
|
||||
toolCall = model.toolCall,
|
||||
free = model.free,
|
||||
status = model.status,
|
||||
recommendedIndex = model.recommendedIndex,
|
||||
variants = model.variants,
|
||||
limit = model.limit?.let { ModelLimitDto(it.context, it.input, it.output) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun parseModel(id: String, obj: JsonObject): ModelInfo {
|
||||
val cap = obj["capabilities"]?.jsonObject
|
||||
val limit = obj["limit"]?.jsonObject
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ internal class KiloBackendProviderSettingsManager(
|
||||
result.providers.forEach { provider ->
|
||||
val configured = provider.id in result.connected || provider.key != null || provider.source == "config" || provider.id in result.config
|
||||
LOG.debug {
|
||||
"provider settings provider: id=${provider.id} source=${provider.source} connected=${provider.id in result.connected} configured=$configured disabled=${provider.id in result.disabled} enabled=${provider.id in result.enabled} hasKey=${provider.key != null} auth=${result.auth[provider.id].orEmpty().map { it.type }.distinct().joinToString(",")} config=${provider.id in result.config} models=${provider.models.size} description=${provider.description?.isNotBlank() == true} note=${provider.metadata?.note?.isNotBlank() == true} noteKey=${provider.metadata?.noteKey} icon=${provider.metadata?.icon}"
|
||||
"provider settings provider: id=${provider.id} source=${provider.source} connected=${provider.id in result.connected} configured=$configured disabled=${provider.id in result.disabled} enabled=${provider.id in result.enabled} hasKey=${provider.key != null} auth=${result.auth[provider.id].orEmpty().map { it.type }.distinct().joinToString(",")} config=${provider.id in result.config} models=${provider.models.size} description=${provider.description?.isNotBlank() == true} noteKey=${provider.metadata?.noteKey} icon=${provider.metadata?.icon} priority=${provider.metadata?.priority}"
|
||||
}
|
||||
}
|
||||
LOG.debug { "provider settings state: completed dir=$directory providers=${result.providers.size} connected=${result.connected.size} auth=${result.auth.size} errors=${result.errors.size} durationMs=${System.currentTimeMillis() - start}" }
|
||||
|
||||
+2
-2
@@ -1317,8 +1317,8 @@ class KiloCliDataParserTest {
|
||||
"source": "api",
|
||||
"metadata": {
|
||||
"noteKey": "settings.providers.note.openai",
|
||||
"note": "GPT and Codex models with API key or ChatGPT login",
|
||||
"icon": "openai",
|
||||
"priority": 3,
|
||||
"extra": true
|
||||
},
|
||||
"unknown": "ok",
|
||||
@@ -1333,8 +1333,8 @@ class KiloCliDataParserTest {
|
||||
|
||||
assertEquals("settings.providers.note.openai", provider.metadata?.noteKey)
|
||||
assertEquals("Build with OpenAI models", provider.description)
|
||||
assertEquals("GPT and Codex models with API key or ChatGPT login", provider.metadata?.note)
|
||||
assertEquals("openai", provider.metadata?.icon)
|
||||
assertEquals(3, provider.metadata?.priority)
|
||||
assertEquals(listOf("openai"), result.second)
|
||||
assertEquals(mapOf("code" to "openai/gpt-5"), result.third)
|
||||
}
|
||||
|
||||
+2
-8
@@ -18,19 +18,13 @@ import kotlin.math.roundToInt
|
||||
internal const val KILO_PROVIDER_ID = "kilo"
|
||||
internal const val CUSTOM_PROVIDER_PACKAGE = "@ai-sdk/openai-compatible"
|
||||
|
||||
internal val POPULAR_PROVIDER_IDS = listOf(KILO_PROVIDER_ID, "anthropic", "deepseek", "openai", "google", "openrouter", "vercel")
|
||||
internal fun isPopularProvider(provider: ProviderSettingsProviderDto) = provider.metadata?.priority != null
|
||||
|
||||
internal fun isPopularProvider(id: String) = id in POPULAR_PROVIDER_IDS
|
||||
|
||||
internal fun popularProviderIndex(id: String): Int {
|
||||
val index = POPULAR_PROVIDER_IDS.indexOf(id)
|
||||
return if (index >= 0) index else Int.MAX_VALUE
|
||||
}
|
||||
internal fun popularProviderIndex(provider: ProviderSettingsProviderDto): Int = provider.metadata?.priority ?: Int.MAX_VALUE
|
||||
|
||||
internal fun providerDescription(provider: ProviderSettingsProviderDto): String {
|
||||
provider.description?.takeIf { it.isNotBlank() }?.let { return it }
|
||||
provider.metadata?.noteKey?.let { key -> KiloBundle.optional(key)?.let { return it } }
|
||||
provider.metadata?.note?.let { return it }
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -31,14 +31,14 @@ internal fun providerListRows(state: ProviderSettingsDto, query: String, disable
|
||||
val filtered = state.providers.filter { ModelSearch.matches(q, it.name) }
|
||||
val connected = filtered
|
||||
.filter { configured(it, state, ids) }
|
||||
.sortedWith(compareBy<ProviderSettingsProviderDto> { popularProviderIndex(it.id) }.thenBy { it.name.lowercase() }.thenBy { it.id })
|
||||
.sortedWith(compareBy<ProviderSettingsProviderDto> { popularProviderIndex(it) }.thenBy { it.name.lowercase() }.thenBy { it.id })
|
||||
val connectedIds = connected.mapTo(mutableSetOf()) { it.id }
|
||||
val popular = filtered
|
||||
.filter { it.id !in connectedIds }
|
||||
.filter { it.id !in disabled }
|
||||
.filter { !hiddenProvider(it) }
|
||||
.filter { isPopularProvider(it.id) }
|
||||
.sortedWith(compareBy<ProviderSettingsProviderDto> { popularProviderIndex(it.id) }.thenBy { it.name.lowercase() }.thenBy { it.id })
|
||||
.filter { isPopularProvider(it) }
|
||||
.sortedWith(compareBy<ProviderSettingsProviderDto> { popularProviderIndex(it) }.thenBy { it.name.lowercase() }.thenBy { it.id })
|
||||
val popularIds = popular.mapTo(mutableSetOf()) { it.id }
|
||||
val all = filtered
|
||||
.filter { it.id !in connectedIds }
|
||||
|
||||
+16
-16
@@ -147,13 +147,13 @@ class ProvidersSettingsUiTest : BasePlatformTestCase() {
|
||||
val rows = providerListRows(
|
||||
ProviderSettingsDto(
|
||||
providers = listOf(
|
||||
provider("openrouter", "OpenRouter"),
|
||||
provider("kilo", "Kilo"),
|
||||
provider("google", "Google"),
|
||||
provider("anthropic", "Anthropic"),
|
||||
provider("vercel", "Vercel"),
|
||||
provider("openai", "OpenAI"),
|
||||
provider("deepseek", "DeepSeek"),
|
||||
provider("openrouter", "OpenRouter", priority = 5),
|
||||
provider("kilo", "Kilo", priority = 0),
|
||||
provider("google", "Google", priority = 4),
|
||||
provider("anthropic", "Anthropic", priority = 1),
|
||||
provider("vercel", "Vercel", priority = 6),
|
||||
provider("openai", "OpenAI", priority = 3),
|
||||
provider("deepseek", "DeepSeek", priority = 2),
|
||||
),
|
||||
),
|
||||
"",
|
||||
@@ -166,7 +166,7 @@ class ProvidersSettingsUiTest : BasePlatformTestCase() {
|
||||
fun `test connected providers appear first and are not duplicated in popular section`() {
|
||||
val rows = providerListRows(
|
||||
ProviderSettingsDto(
|
||||
providers = listOf(provider("anthropic", "Anthropic"), provider("openai", "OpenAI")),
|
||||
providers = listOf(provider("anthropic", "Anthropic", priority = 1), provider("openai", "OpenAI", priority = 3)),
|
||||
connected = listOf("anthropic"),
|
||||
),
|
||||
"",
|
||||
@@ -183,7 +183,7 @@ class ProvidersSettingsUiTest : BasePlatformTestCase() {
|
||||
val rows = providerListRows(
|
||||
ProviderSettingsDto(
|
||||
providers = listOf(
|
||||
provider("anthropic", "Anthropic", source = "custom"),
|
||||
provider("anthropic", "Anthropic", source = "custom", priority = 1),
|
||||
provider("available-custom", "Available Custom", source = "custom"),
|
||||
provider("local-openai", "Local OpenAI", source = "custom"),
|
||||
),
|
||||
@@ -227,7 +227,7 @@ class ProvidersSettingsUiTest : BasePlatformTestCase() {
|
||||
fun `test disabled popular provider appears in all providers with enable`() {
|
||||
val rows = providerListRows(
|
||||
ProviderSettingsDto(
|
||||
providers = listOf(provider("anthropic", "Anthropic"), provider("openai", "OpenAI")),
|
||||
providers = listOf(provider("anthropic", "Anthropic", priority = 1), provider("openai", "OpenAI", priority = 3)),
|
||||
disabled = listOf("anthropic"),
|
||||
),
|
||||
"",
|
||||
@@ -244,7 +244,7 @@ class ProvidersSettingsUiTest : BasePlatformTestCase() {
|
||||
providers = listOf(
|
||||
provider("zeta", "Zeta"),
|
||||
provider("alpha", "Alpha"),
|
||||
provider("openai", "OpenAI"),
|
||||
provider("openai", "OpenAI", priority = 3),
|
||||
),
|
||||
),
|
||||
"",
|
||||
@@ -260,8 +260,8 @@ class ProvidersSettingsUiTest : BasePlatformTestCase() {
|
||||
content.update(
|
||||
ProviderSettingsDto(
|
||||
providers = listOf(
|
||||
provider("openai", "OpenAI"),
|
||||
provider("anthropic", "Anthropic"),
|
||||
provider("openai", "OpenAI", priority = 3),
|
||||
provider("anthropic", "Anthropic", priority = 1),
|
||||
provider("alpha", "Alpha Labs"),
|
||||
),
|
||||
),
|
||||
@@ -402,7 +402,6 @@ class ProvidersSettingsUiTest : BasePlatformTestCase() {
|
||||
"OpenAI",
|
||||
metadata = ProviderMetadataDto(
|
||||
noteKey = "settings.providers.note.openai",
|
||||
note = "GPT and Codex models with API key or ChatGPT login",
|
||||
icon = "openai",
|
||||
),
|
||||
),
|
||||
@@ -428,7 +427,7 @@ class ProvidersSettingsUiTest : BasePlatformTestCase() {
|
||||
"openai",
|
||||
"OpenAI",
|
||||
description = "Build with OpenAI models",
|
||||
metadata = ProviderMetadataDto(note = "Fallback metadata note"),
|
||||
metadata = ProviderMetadataDto(noteKey = "settings.providers.note.openai"),
|
||||
),
|
||||
"Popular providers",
|
||||
listOf(ProviderListAction.CONNECT),
|
||||
@@ -781,12 +780,13 @@ class ProvidersSettingsUiTest : BasePlatformTestCase() {
|
||||
description: String? = null,
|
||||
source: String? = null,
|
||||
metadata: ProviderMetadataDto? = null,
|
||||
priority: Int? = null,
|
||||
) = ProviderSettingsProviderDto(
|
||||
id = id,
|
||||
name = name,
|
||||
description = description,
|
||||
source = source,
|
||||
metadata = metadata,
|
||||
metadata = metadata ?: priority?.let { ProviderMetadataDto(priority = it) },
|
||||
models = mapOf("model" to ModelDto("model", "Model")),
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -30,8 +30,8 @@ data class ProviderSettingsProviderDto(
|
||||
@Serializable
|
||||
data class ProviderMetadataDto(
|
||||
val noteKey: String? = null,
|
||||
val note: String? = null,
|
||||
val icon: String? = null,
|
||||
val priority: Int? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
|
||||
@@ -5,6 +5,7 @@ export type CustomProviderPackage = (typeof CUSTOM_PROVIDER_PACKAGES)[number]
|
||||
export const CUSTOM_PROVIDER_PACKAGE: CustomProviderPackage = "@ai-sdk/openai-compatible"
|
||||
export const PROVIDER_ID_PATTERN = /^[a-z0-9][a-z0-9-_]*$/
|
||||
|
||||
// Legacy/static fallback for provider objects created before backend metadata is available.
|
||||
export const PROVIDER_PRIORITY = [
|
||||
KILO_PROVIDER_ID,
|
||||
"anthropic",
|
||||
@@ -37,6 +38,11 @@ export function createKiloFallbackProvider() {
|
||||
name: "Kilo Gateway",
|
||||
source: "custom" as const,
|
||||
env: ["KILO_API_KEY"],
|
||||
metadata: {
|
||||
noteKey: "settings.providers.note.kilo",
|
||||
icon: KILO_PROVIDER_ID,
|
||||
priority: 0,
|
||||
},
|
||||
models: {},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ const ProviderSelectDialog = () => {
|
||||
items={items()}
|
||||
filterKeys={["id", "name"]}
|
||||
groupBy={(item) =>
|
||||
item.id !== CUSTOM_PROVIDER_ID && isPopularProvider(item.id)
|
||||
item.id !== CUSTOM_PROVIDER_ID && isPopularProvider(item.provider ?? item.id)
|
||||
? language.t("settings.providers.group.recommended")
|
||||
: language.t("dialog.provider.group.other")
|
||||
}
|
||||
@@ -89,7 +89,7 @@ const ProviderSelectDialog = () => {
|
||||
if (a.id === CUSTOM_PROVIDER_ID) return -1
|
||||
if (b.id === CUSTOM_PROVIDER_ID) return 1
|
||||
|
||||
const rank = popularProviderIndex(a.id) - popularProviderIndex(b.id)
|
||||
const rank = popularProviderIndex(a.provider ?? a.id) - popularProviderIndex(b.provider ?? b.id)
|
||||
if (rank !== 0) return rank
|
||||
return a.name.localeCompare(b.name)
|
||||
}}
|
||||
@@ -106,7 +106,12 @@ const ProviderSelectDialog = () => {
|
||||
>
|
||||
{(item) => (
|
||||
<div style={{ display: "flex", gap: "10px", "align-items": "center", width: "100%", "min-width": 0 }}>
|
||||
<ProviderIcon id={providerIcon(item.provider ?? item.id)} width={18} height={18} data-slot="list-item-extra-icon" />
|
||||
<ProviderIcon
|
||||
id={providerIcon(item.provider ?? item.id)}
|
||||
width={18}
|
||||
height={18}
|
||||
data-slot="list-item-extra-icon"
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
|
||||
@@ -15,7 +15,7 @@ import type { Provider } from "../../types/messages"
|
||||
import CustomProviderDialog from "./CustomProviderDialog"
|
||||
import ProviderConnectDialog from "./ProviderConnectDialog"
|
||||
import ProviderSelectDialog from "./ProviderSelectDialog"
|
||||
import { CUSTOM_PROVIDER_ID, isPopularProvider, providerIcon, providerNote, providerNoteKey, sortProviders } from "./provider-catalog"
|
||||
import { CUSTOM_PROVIDER_ID, isPopularProvider, providerIcon, providerNoteKey, sortProviders } from "./provider-catalog"
|
||||
import { disabledProviderOptions, providersWithKiloFallback, visibleConnectedIds } from "./provider-visibility"
|
||||
import { isCustomProviderPackage, KILO_PROVIDER_ID } from "../../../../src/shared/provider-model"
|
||||
import { createProviderAction } from "../../utils/provider-action"
|
||||
@@ -53,10 +53,7 @@ const ProvidersTab: Component = () => {
|
||||
return sortProviders(
|
||||
all.filter(
|
||||
(item) =>
|
||||
item.id !== KILO_PROVIDER_ID &&
|
||||
isPopularProvider(item.id) &&
|
||||
!connected.has(item.id) &&
|
||||
!disabled.has(item.id),
|
||||
item.id !== KILO_PROVIDER_ID && isPopularProvider(item) && !connected.has(item.id) && !disabled.has(item.id),
|
||||
),
|
||||
)
|
||||
})
|
||||
@@ -289,7 +286,6 @@ const ProvidersTab: Component = () => {
|
||||
<For each={popularProviders()}>
|
||||
{(item) => {
|
||||
const noteKey = providerNoteKey(item)
|
||||
const note = providerNote(item)
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@@ -329,19 +325,6 @@ const ProvidersTab: Component = () => {
|
||||
</span>
|
||||
)}
|
||||
</Show>
|
||||
<Show when={!noteKey && note}>
|
||||
{(text) => (
|
||||
<span
|
||||
style={{
|
||||
"font-size": "var(--kilo-font-size-12)",
|
||||
color: "var(--text-weak-base, var(--vscode-descriptionForeground))",
|
||||
"margin-top": "2px",
|
||||
}}
|
||||
>
|
||||
{text()}
|
||||
</span>
|
||||
)}
|
||||
</Show>
|
||||
</div>
|
||||
<Button size="large" variant="secondary" icon="plus-small" onClick={() => connectProvider(item)}>
|
||||
{language.t("common.connect")}
|
||||
|
||||
@@ -2,22 +2,23 @@ import { iconNames, type IconName } from "@opencode-ai/ui/icons/provider"
|
||||
import type { Provider } from "../../types/messages"
|
||||
import {
|
||||
KILO_PROVIDER_ID,
|
||||
PROVIDER_PRIORITY as POPULAR_PROVIDER_IDS,
|
||||
PROVIDER_PRIORITY as FALLBACK_PROVIDER_IDS,
|
||||
createKiloFallbackProvider,
|
||||
providerOrderIndex,
|
||||
} from "../../../../src/shared/provider-model"
|
||||
|
||||
export const CUSTOM_PROVIDER_ID = "_custom"
|
||||
export { POPULAR_PROVIDER_IDS }
|
||||
|
||||
const POPULAR_PROVIDER_SET = new Set<string>(POPULAR_PROVIDER_IDS)
|
||||
const fallback = new Set<string>(FALLBACK_PROVIDER_IDS)
|
||||
|
||||
export function isPopularProvider(providerID: string) {
|
||||
return POPULAR_PROVIDER_SET.has(providerID)
|
||||
export function isPopularProvider(provider: Provider | string) {
|
||||
if (typeof provider !== "string") return provider.metadata?.priority !== undefined
|
||||
return fallback.has(provider)
|
||||
}
|
||||
|
||||
export function popularProviderIndex(providerID: string) {
|
||||
return providerOrderIndex(providerID, POPULAR_PROVIDER_IDS)
|
||||
export function popularProviderIndex(provider: Provider | string) {
|
||||
if (typeof provider !== "string") return provider.metadata?.priority ?? Number.MAX_SAFE_INTEGER
|
||||
return providerOrderIndex(provider, FALLBACK_PROVIDER_IDS)
|
||||
}
|
||||
|
||||
function validIcon(id: string | undefined): IconName | undefined {
|
||||
@@ -42,26 +43,13 @@ export function kiloFallbackProvider(): Provider {
|
||||
|
||||
export function providerNoteKey(provider: Provider | string) {
|
||||
if (typeof provider !== "string" && provider.metadata?.noteKey) return provider.metadata.noteKey
|
||||
const providerID = typeof provider === "string" ? provider : provider.id
|
||||
if (providerID === "kilo") return "settings.providers.note.kilo"
|
||||
if (providerID === "opencode") return "settings.providers.note.opencode"
|
||||
if (providerID === "anthropic") return "settings.providers.note.anthropic"
|
||||
if (providerID === "deepseek") return "settings.providers.note.deepseek"
|
||||
if (providerID.startsWith("github-copilot")) return "settings.providers.note.copilot"
|
||||
if (providerID === "openai") return "settings.providers.note.openai"
|
||||
if (providerID === "google") return "settings.providers.note.google"
|
||||
if (providerID === "openrouter") return "settings.providers.note.openrouter"
|
||||
if (providerID === "vercel") return "settings.providers.note.vercel"
|
||||
if (provider === KILO_PROVIDER_ID) return "settings.providers.note.kilo"
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function providerNote(provider: Provider) {
|
||||
return provider.metadata?.note
|
||||
}
|
||||
|
||||
export function sortProviders(items: Provider[]) {
|
||||
return items.slice().sort((a, b) => {
|
||||
const rank = popularProviderIndex(a.id) - popularProviderIndex(b.id)
|
||||
const rank = popularProviderIndex(a) - popularProviderIndex(b)
|
||||
if (rank !== 0) return rank
|
||||
return a.name.localeCompare(b.name)
|
||||
})
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "البحث عن موفرين",
|
||||
"dialog.provider.empty": "لم يتم العثور على موفرين",
|
||||
"dialog.provider.group.popular": "شائع",
|
||||
"dialog.provider.group.other": "آخر",
|
||||
"dialog.provider.tag.recommended": "موصى به",
|
||||
"dialog.provider.opencode.note": "نماذج مختارة تشمل Claude وGPT وGemini والمزيد",
|
||||
"dialog.provider.anthropic.note": "اتصل باستخدام Claude Pro/Max أو مفتاح API",
|
||||
"dialog.provider.deepseek.note": "نماذج DeepSeek لمهام الاستدلال والبرمجة",
|
||||
"dialog.provider.openai.note": "اتصل باستخدام ChatGPT Pro/Plus أو مفتاح API",
|
||||
"dialog.provider.google.note": "نماذج Gemini للاستجابات السريعة والمنظمة",
|
||||
"dialog.provider.openrouter.note": "الوصول إلى جميع النماذج المدعومة من موفر واحد",
|
||||
"dialog.provider.vercel.note": "وصول موحد إلى نماذج الذكاء الاصطناعي مع توجيه ذكي",
|
||||
"dialog.provider.copilot.note": "اتصل باستخدام Copilot أو مفتاح API",
|
||||
|
||||
"dialog.model.select.title": "تحديد نموذج",
|
||||
"dialog.model.search.placeholder": "البحث عن نماذج",
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Buscar provedores",
|
||||
"dialog.provider.empty": "Nenhum provedor encontrado",
|
||||
"dialog.provider.group.popular": "Popular",
|
||||
"dialog.provider.group.other": "Outro",
|
||||
"dialog.provider.tag.recommended": "Recomendado",
|
||||
"dialog.provider.opencode.note": "Modelos selecionados incluindo Claude, GPT, Gemini e mais",
|
||||
"dialog.provider.anthropic.note": "Conectar com Claude Pro/Max ou chave de API",
|
||||
"dialog.provider.deepseek.note": "Modelos DeepSeek para tarefas de raciocínio e programação",
|
||||
"dialog.provider.openai.note": "Conectar com ChatGPT Pro/Plus ou chave de API",
|
||||
"dialog.provider.google.note": "Modelos Gemini para respostas rápidas e estruturadas",
|
||||
"dialog.provider.openrouter.note": "Acesse todos os modelos suportados a partir de um único provedor",
|
||||
"dialog.provider.vercel.note": "Acesso unificado a modelos de IA com roteamento inteligente",
|
||||
"dialog.provider.copilot.note": "Conectar com Copilot ou chave de API",
|
||||
|
||||
"dialog.model.select.title": "Selecionar modelo",
|
||||
"dialog.model.search.placeholder": "Buscar modelos",
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Pretraži provajdere",
|
||||
"dialog.provider.empty": "Nema pronađenih provajdera",
|
||||
"dialog.provider.group.popular": "Popularno",
|
||||
"dialog.provider.group.other": "Ostalo",
|
||||
"dialog.provider.tag.recommended": "Preporučeno",
|
||||
"dialog.provider.opencode.note": "Kurirani modeli uključujući Claude, GPT, Gemini i druge",
|
||||
"dialog.provider.anthropic.note": "Direktan pristup Claude modelima, uključujući Pro i Max",
|
||||
"dialog.provider.deepseek.note": "DeepSeek modeli za zadatke zaključivanja i kodiranja",
|
||||
"dialog.provider.copilot.note": "Claude modeli za pomoć pri kodiranju",
|
||||
"dialog.provider.openai.note": "GPT modeli za brze, sposobne opšte AI zadatke",
|
||||
"dialog.provider.google.note": "Gemini modeli za brze, strukturirane odgovore",
|
||||
"dialog.provider.openrouter.note": "Pristup svim podržanim modelima preko jednog provajdera",
|
||||
"dialog.provider.vercel.note": "Jedinstven pristup AI modelima uz pametno rutiranje",
|
||||
|
||||
"dialog.model.select.title": "Odaberi model",
|
||||
"dialog.model.search.placeholder": "Pretraži modele",
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Søg udbydere",
|
||||
"dialog.provider.empty": "Ingen udbydere fundet",
|
||||
"dialog.provider.group.popular": "Populære",
|
||||
"dialog.provider.group.other": "Andre",
|
||||
"dialog.provider.tag.recommended": "Anbefalet",
|
||||
"dialog.provider.opencode.note": "Udvalgte modeller inkl. Claude, GPT, Gemini og flere",
|
||||
"dialog.provider.anthropic.note": "Forbind med Claude Pro/Max eller API-nøgle",
|
||||
"dialog.provider.deepseek.note": "DeepSeek-modeller til ræsonnering og kodningsopgaver",
|
||||
"dialog.provider.openai.note": "Forbind med ChatGPT Pro/Plus eller API-nøgle",
|
||||
"dialog.provider.google.note": "Gemini-modeller til hurtige, strukturerede svar",
|
||||
"dialog.provider.openrouter.note": "Adgang til alle understøttede modeller fra én udbyder",
|
||||
"dialog.provider.vercel.note": "Samlet adgang til AI-modeller med smart routing",
|
||||
"dialog.provider.copilot.note": "Forbind med Copilot eller API-nøgle",
|
||||
|
||||
"dialog.model.select.title": "Vælg model",
|
||||
"dialog.model.search.placeholder": "Søg modeller",
|
||||
|
||||
-9
@@ -105,17 +105,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Anbieter durchsuchen",
|
||||
"dialog.provider.empty": "Keine Anbieter gefunden",
|
||||
"dialog.provider.group.popular": "Beliebt",
|
||||
"dialog.provider.group.other": "Andere",
|
||||
"dialog.provider.tag.recommended": "Empfohlen",
|
||||
"dialog.provider.opencode.note": "Kuratierte Modelle wie Claude, GPT, Gemini und mehr",
|
||||
"dialog.provider.anthropic.note": "Mit Claude Pro/Max oder API-Schlüssel verbinden",
|
||||
"dialog.provider.deepseek.note": "DeepSeek-Modelle für Reasoning- und Programmieraufgaben",
|
||||
"dialog.provider.openai.note": "Mit ChatGPT Pro/Plus oder API-Schlüssel verbinden",
|
||||
"dialog.provider.google.note": "Gemini-Modelle für schnelle, strukturierte Antworten",
|
||||
"dialog.provider.openrouter.note": "Zugriff auf alle unterstützten Modelle über einen Anbieter",
|
||||
"dialog.provider.vercel.note": "Einheitlicher Zugriff auf KI-Modelle mit intelligentem Routing",
|
||||
"dialog.provider.copilot.note": "Mit Copilot oder API-Schlüssel verbinden",
|
||||
|
||||
"dialog.model.select.title": "Modell auswählen",
|
||||
"dialog.model.search.placeholder": "Modelle durchsuchen",
|
||||
|
||||
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Search providers",
|
||||
"dialog.provider.empty": "No providers found",
|
||||
"dialog.provider.group.popular": "Popular",
|
||||
"dialog.provider.group.other": "Other",
|
||||
"dialog.provider.tag.recommended": "Recommended",
|
||||
"dialog.provider.opencode.note": "Curated models including Claude, GPT, Gemini and more",
|
||||
"dialog.provider.anthropic.note": "Direct access to Claude models, including Pro and Max",
|
||||
"dialog.provider.deepseek.note": "DeepSeek models for reasoning and coding tasks",
|
||||
"dialog.provider.copilot.note": "Claude models for coding assistance",
|
||||
"dialog.provider.openai.note": "GPT and Codex models with API key or ChatGPT login",
|
||||
"dialog.provider.google.note": "Gemini models for fast, structured responses",
|
||||
"dialog.provider.openrouter.note": "Access all supported models from one provider",
|
||||
"dialog.provider.vercel.note": "Unified access to AI models with smart routing",
|
||||
|
||||
"dialog.model.select.title": "Select model",
|
||||
"dialog.model.search.placeholder": "Search models",
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Buscar proveedores",
|
||||
"dialog.provider.empty": "No se encontraron proveedores",
|
||||
"dialog.provider.group.popular": "Popular",
|
||||
"dialog.provider.group.other": "Otro",
|
||||
"dialog.provider.tag.recommended": "Recomendado",
|
||||
"dialog.provider.opencode.note": "Modelos curados incluyendo Claude, GPT, Gemini y más",
|
||||
"dialog.provider.anthropic.note": "Conectar con Claude Pro/Max o clave API",
|
||||
"dialog.provider.deepseek.note": "Modelos DeepSeek para tareas de razonamiento y programación",
|
||||
"dialog.provider.openai.note": "Conectar con ChatGPT Pro/Plus o clave API",
|
||||
"dialog.provider.google.note": "Modelos Gemini para respuestas rápidas y estructuradas",
|
||||
"dialog.provider.openrouter.note": "Accede a todos los modelos soportados desde un solo proveedor",
|
||||
"dialog.provider.vercel.note": "Acceso unificado a modelos de IA con enrutamiento inteligente",
|
||||
"dialog.provider.copilot.note": "Conectar con Copilot o clave API",
|
||||
|
||||
"dialog.model.select.title": "Seleccionar modelo",
|
||||
"dialog.model.search.placeholder": "Buscar modelos",
|
||||
|
||||
-9
@@ -102,17 +102,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Rechercher des fournisseurs",
|
||||
"dialog.provider.empty": "Aucun fournisseur trouvé",
|
||||
"dialog.provider.group.popular": "Populaire",
|
||||
"dialog.provider.group.other": "Autre",
|
||||
"dialog.provider.tag.recommended": "Recommandé",
|
||||
"dialog.provider.opencode.note": "Modèles sélectionnés incluant Claude, GPT, Gemini et plus",
|
||||
"dialog.provider.anthropic.note": "Connectez-vous avec Claude Pro/Max ou une clé API",
|
||||
"dialog.provider.deepseek.note": "Modèles DeepSeek pour les tâches de raisonnement et de codage",
|
||||
"dialog.provider.openai.note": "Connectez-vous avec ChatGPT Pro/Plus ou une clé API",
|
||||
"dialog.provider.google.note": "Modèles Gemini pour des réponses rapides et structurées",
|
||||
"dialog.provider.openrouter.note": "Accédez à tous les modèles supportés depuis un seul fournisseur",
|
||||
"dialog.provider.vercel.note": "Accès unifié aux modèles IA avec routage intelligent",
|
||||
"dialog.provider.copilot.note": "Connectez-vous avec Copilot ou une clé API",
|
||||
|
||||
"dialog.model.select.title": "Sélectionner un modèle",
|
||||
"dialog.model.search.placeholder": "Rechercher des modèles",
|
||||
|
||||
-9
@@ -92,17 +92,8 @@ export const dict = {
|
||||
"palette.group.files": "File",
|
||||
"dialog.provider.search.placeholder": "Cerca provider",
|
||||
"dialog.provider.empty": "Nessun provider trovato",
|
||||
"dialog.provider.group.popular": "Popolari",
|
||||
"dialog.provider.group.other": "Altro",
|
||||
"dialog.provider.tag.recommended": "Consigliato",
|
||||
"dialog.provider.opencode.note": "Modelli curati, inclusi Claude, GPT, Gemini e altri",
|
||||
"dialog.provider.anthropic.note": "Accesso diretto ai modelli Claude, inclusi Pro e Max",
|
||||
"dialog.provider.copilot.note": "Modelli AI per assistenza al coding tramite GitHub Copilot",
|
||||
"dialog.provider.openai.note": "Modelli GPT per attività AI generali rapide e capaci",
|
||||
"dialog.provider.google.note": "Modelli Gemini per risposte rapide e strutturate",
|
||||
"dialog.provider.deepseek.note": "Modelli DeepSeek per ragionamento e attività di coding",
|
||||
"dialog.provider.openrouter.note": "Accesso a tutti i modelli supportati da un solo provider",
|
||||
"dialog.provider.vercel.note": "Accesso unificato ai modelli AI con routing intelligente",
|
||||
"dialog.model.select.title": "Seleziona modello",
|
||||
"dialog.model.search.placeholder": "Cerca modelli",
|
||||
"dialog.model.empty": "Nessun risultato modello",
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "プロバイダーを検索",
|
||||
"dialog.provider.empty": "プロバイダーが見つかりません",
|
||||
"dialog.provider.group.popular": "人気",
|
||||
"dialog.provider.group.other": "その他",
|
||||
"dialog.provider.tag.recommended": "推奨",
|
||||
"dialog.provider.opencode.note": "Claude、GPT、Geminiなどの厳選されたモデル",
|
||||
"dialog.provider.anthropic.note": "Claude Pro/MaxまたはAPIキーで接続",
|
||||
"dialog.provider.deepseek.note": "推論とコーディングタスク向けのDeepSeekモデル",
|
||||
"dialog.provider.openai.note": "ChatGPT Pro/PlusまたはAPIキーで接続",
|
||||
"dialog.provider.google.note": "高速で構造化された応答のためのGeminiモデル",
|
||||
"dialog.provider.openrouter.note": "1つのプロバイダーからすべてのモデルにアクセス",
|
||||
"dialog.provider.vercel.note": "スマートルーティングによるAIモデルへの統合アクセス",
|
||||
"dialog.provider.copilot.note": "CopilotまたはAPIキーで接続",
|
||||
|
||||
"dialog.model.select.title": "モデルを選択",
|
||||
"dialog.model.search.placeholder": "モデルを検索",
|
||||
|
||||
-9
@@ -105,17 +105,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "공급자 검색",
|
||||
"dialog.provider.empty": "공급자 없음",
|
||||
"dialog.provider.group.popular": "인기",
|
||||
"dialog.provider.group.other": "기타",
|
||||
"dialog.provider.tag.recommended": "추천",
|
||||
"dialog.provider.opencode.note": "Claude, GPT, Gemini 등 엄선된 모델",
|
||||
"dialog.provider.anthropic.note": "Claude Pro/Max 또는 API 키로 연결",
|
||||
"dialog.provider.deepseek.note": "추론 및 코딩 작업을 위한 DeepSeek 모델",
|
||||
"dialog.provider.openai.note": "ChatGPT Pro/Plus 또는 API 키로 연결",
|
||||
"dialog.provider.google.note": "빠르고 구조화된 응답을 위한 Gemini 모델",
|
||||
"dialog.provider.openrouter.note": "하나의 공급자에서 모든 지원 모델에 액세스",
|
||||
"dialog.provider.vercel.note": "스마트 라우팅으로 AI 모델에 통합 액세스",
|
||||
"dialog.provider.copilot.note": "Copilot 또는 API 키로 연결",
|
||||
|
||||
"dialog.model.select.title": "모델 선택",
|
||||
"dialog.model.search.placeholder": "모델 검색",
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Providers zoeken",
|
||||
"dialog.provider.empty": "Geen providers gevonden",
|
||||
"dialog.provider.group.popular": "Populair",
|
||||
"dialog.provider.group.other": "Overige",
|
||||
"dialog.provider.tag.recommended": "Aanbevolen",
|
||||
"dialog.provider.opencode.note": "Geselecteerde modellen waaronder Claude, GPT, Gemini en meer",
|
||||
"dialog.provider.anthropic.note": "Directe toegang tot Claude-modellen, inclusief Pro en Max",
|
||||
"dialog.provider.deepseek.note": "DeepSeek-modellen voor redeneer- en programmeertaken",
|
||||
"dialog.provider.copilot.note": "Claude-modellen voor programmeerhulp",
|
||||
"dialog.provider.openai.note": "GPT-modellen voor snelle, capabele algemene AI-taken",
|
||||
"dialog.provider.google.note": "Gemini-modellen voor snelle, gestructureerde antwoorden",
|
||||
"dialog.provider.openrouter.note": "Toegang tot alle ondersteunde modellen via één provider",
|
||||
"dialog.provider.vercel.note": "Gecentraliseerde toegang tot AI-modellen met slimme routering",
|
||||
|
||||
"dialog.model.select.title": "Model selecteren",
|
||||
"dialog.model.search.placeholder": "Modellen zoeken",
|
||||
|
||||
-9
@@ -104,17 +104,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Søk etter leverandører",
|
||||
"dialog.provider.empty": "Ingen leverandører funnet",
|
||||
"dialog.provider.group.popular": "Populære",
|
||||
"dialog.provider.group.other": "Andre",
|
||||
"dialog.provider.tag.recommended": "Anbefalt",
|
||||
"dialog.provider.opencode.note": "Utvalgte modeller inkludert Claude, GPT, Gemini og flere",
|
||||
"dialog.provider.anthropic.note": "Koble til med Claude Pro/Max eller API-nøkkel",
|
||||
"dialog.provider.deepseek.note": "DeepSeek-modeller for resonnering og kodeoppgaver",
|
||||
"dialog.provider.openai.note": "Koble til med ChatGPT Pro/Plus eller API-nøkkel",
|
||||
"dialog.provider.google.note": "Gemini-modeller for raske, strukturerte svar",
|
||||
"dialog.provider.openrouter.note": "Tilgang til alle støttede modeller fra én leverandør",
|
||||
"dialog.provider.vercel.note": "Samlet tilgang til AI-modeller med smart ruting",
|
||||
"dialog.provider.copilot.note": "Koble til med Copilot eller API-nøkkel",
|
||||
|
||||
"dialog.model.select.title": "Velg modell",
|
||||
"dialog.model.search.placeholder": "Søk etter modeller",
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Szukaj dostawców",
|
||||
"dialog.provider.empty": "Nie znaleziono dostawców",
|
||||
"dialog.provider.group.popular": "Popularne",
|
||||
"dialog.provider.group.other": "Inne",
|
||||
"dialog.provider.tag.recommended": "Zalecane",
|
||||
"dialog.provider.opencode.note": "Wybrane modele, w tym Claude, GPT, Gemini i więcej",
|
||||
"dialog.provider.anthropic.note": "Połącz z Claude Pro/Max lub kluczem API",
|
||||
"dialog.provider.deepseek.note": "Modele DeepSeek do zadań wymagających rozumowania i kodowania",
|
||||
"dialog.provider.openai.note": "Połącz z ChatGPT Pro/Plus lub kluczem API",
|
||||
"dialog.provider.google.note": "Modele Gemini do szybkich, strukturalnych odpowiedzi",
|
||||
"dialog.provider.openrouter.note": "Dostęp do wszystkich obsługiwanych modeli od jednego dostawcy",
|
||||
"dialog.provider.vercel.note": "Ujednolicony dostęp do modeli AI z inteligentnym routingiem",
|
||||
"dialog.provider.copilot.note": "Połącz z Copilot lub kluczem API",
|
||||
|
||||
"dialog.model.select.title": "Wybierz model",
|
||||
"dialog.model.search.placeholder": "Szukaj modeli",
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Поиск провайдеров",
|
||||
"dialog.provider.empty": "Провайдеры не найдены",
|
||||
"dialog.provider.group.popular": "Популярные",
|
||||
"dialog.provider.group.other": "Другие",
|
||||
"dialog.provider.tag.recommended": "Рекомендуемые",
|
||||
"dialog.provider.opencode.note": "Отобранные модели, включая Claude, GPT, Gemini и другие",
|
||||
"dialog.provider.anthropic.note": "Подключитесь с помощью Claude Pro/Max или API ключа",
|
||||
"dialog.provider.deepseek.note": "Модели DeepSeek для задач рассуждения и программирования",
|
||||
"dialog.provider.openai.note": "Подключитесь с помощью ChatGPT Pro/Plus или API ключа",
|
||||
"dialog.provider.google.note": "Модели Gemini для быстрых структурированных ответов",
|
||||
"dialog.provider.openrouter.note": "Доступ ко всем поддерживаемым моделям через одного провайдера",
|
||||
"dialog.provider.vercel.note": "Единый доступ к AI-моделям с интеллектуальной маршрутизацией",
|
||||
"dialog.provider.copilot.note": "Подключитесь с помощью Copilot или API ключа",
|
||||
|
||||
"dialog.model.select.title": "Выбрать модель",
|
||||
"dialog.model.search.placeholder": "Поиск моделей",
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "ค้นหาผู้ให้บริการ",
|
||||
"dialog.provider.empty": "ไม่พบผู้ให้บริการ",
|
||||
"dialog.provider.group.popular": "ยอดนิยม",
|
||||
"dialog.provider.group.other": "อื่น ๆ",
|
||||
"dialog.provider.tag.recommended": "แนะนำ",
|
||||
"dialog.provider.opencode.note": "โมเดลที่คัดสรร รวมถึง Claude, GPT, Gemini และอื่น ๆ",
|
||||
"dialog.provider.anthropic.note": "เข้าถึงโมเดล Claude โดยตรง รวมถึง Pro และ Max",
|
||||
"dialog.provider.deepseek.note": "โมเดล DeepSeek สำหรับงานการให้เหตุผลและการเขียนโค้ด",
|
||||
"dialog.provider.copilot.note": "โมเดล Claude สำหรับการช่วยเหลือในการเขียนโค้ด",
|
||||
"dialog.provider.openai.note": "โมเดล GPT สำหรับงาน AI ทั่วไปที่รวดเร็วและมีความสามารถ",
|
||||
"dialog.provider.google.note": "โมเดล Gemini สำหรับการตอบสนองที่รวดเร็วและมีโครงสร้าง",
|
||||
"dialog.provider.openrouter.note": "เข้าถึงโมเดลที่รองรับทั้งหมดจากผู้ให้บริการเดียว",
|
||||
"dialog.provider.vercel.note": "การเข้าถึงโมเดล AI แบบรวมด้วยการกำหนดเส้นทางอัจฉริยะ",
|
||||
|
||||
"dialog.model.select.title": "เลือกโมเดล",
|
||||
"dialog.model.search.placeholder": "ค้นหาโมเดล",
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Sağlayıcı ara",
|
||||
"dialog.provider.empty": "Sağlayıcı bulunamadı",
|
||||
"dialog.provider.group.popular": "Popüler",
|
||||
"dialog.provider.group.other": "Diğer",
|
||||
"dialog.provider.tag.recommended": "Önerilen",
|
||||
"dialog.provider.opencode.note": "Claude, GPT, Gemini ve daha fazlasını içeren seçilmiş modeller",
|
||||
"dialog.provider.anthropic.note": "Pro ve Max dahil Claude modellerine doğrudan erişim",
|
||||
"dialog.provider.deepseek.note": "Muhakeme ve kodlama görevleri için DeepSeek modelleri",
|
||||
"dialog.provider.copilot.note": "Kodlama yardımı için Claude modelleri",
|
||||
"dialog.provider.openai.note": "Hızlı ve yetenekli genel yapay zeka görevleri için GPT modelleri",
|
||||
"dialog.provider.google.note": "Hızlı ve yapılandırılmış yanıtlar için Gemini modelleri",
|
||||
"dialog.provider.openrouter.note": "Tek bir sağlayıcıdan tüm desteklenen modellere eriş",
|
||||
"dialog.provider.vercel.note": "Akıllı yönlendirme ile yapay zeka modellerine birleşik erişim",
|
||||
|
||||
"dialog.model.select.title": "Model seç",
|
||||
"dialog.model.search.placeholder": "Model ara",
|
||||
|
||||
-9
@@ -101,17 +101,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "Пошук провайдера",
|
||||
"dialog.provider.empty": "Провайдерів не знайдено",
|
||||
"dialog.provider.group.popular": "Популярні",
|
||||
"dialog.provider.group.other": "Інші",
|
||||
"dialog.provider.tag.recommended": "Рекомендовано",
|
||||
"dialog.provider.opencode.note": "Добірка моделей включаючи Claude, GPT, Gemini та інші",
|
||||
"dialog.provider.anthropic.note": "Прямий доступ до моделей Claude включаючи Pro та Max",
|
||||
"dialog.provider.deepseek.note": "Моделі DeepSeek для завдань міркування та програмування",
|
||||
"dialog.provider.copilot.note": "Моделі Claude для допомоги з кодуванням",
|
||||
"dialog.provider.openai.note": "Моделі GPT для швидких і потужних загальних завдань ШІ",
|
||||
"dialog.provider.google.note": "Моделі Gemini для швидких і структурованих відповідей",
|
||||
"dialog.provider.openrouter.note": "Доступ до всіх підтримуваних моделей від одного провайдера",
|
||||
"dialog.provider.vercel.note": "Уніфікований доступ до моделей ШІ з інтелектуальною маршрутизацією",
|
||||
|
||||
"dialog.model.select.title": "Вибір моделі",
|
||||
"dialog.model.search.placeholder": "Пошук моделі",
|
||||
|
||||
-9
@@ -105,17 +105,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "搜索提供商",
|
||||
"dialog.provider.empty": "未找到提供商",
|
||||
"dialog.provider.group.popular": "热门",
|
||||
"dialog.provider.group.other": "其他",
|
||||
"dialog.provider.tag.recommended": "推荐",
|
||||
"dialog.provider.anthropic.note": "使用 Claude Pro/Max 或 API 密钥连接",
|
||||
"dialog.provider.deepseek.note": "用于推理和编程任务的 DeepSeek 模型",
|
||||
"dialog.provider.openai.note": "使用 ChatGPT Pro/Plus 或 API 密钥连接",
|
||||
"dialog.provider.copilot.note": "使用 Copilot 或 API 密钥连接",
|
||||
"dialog.provider.opencode.note": "使用 OpenCode Zen 或 API 密钥连接",
|
||||
"dialog.provider.google.note": "使用 Google 账号或 API 密钥连接",
|
||||
"dialog.provider.openrouter.note": "使用 OpenRouter 账号或 API 密钥连接",
|
||||
"dialog.provider.vercel.note": "使用 Vercel 账号或 API 密钥连接",
|
||||
|
||||
"dialog.model.select.title": "选择模型",
|
||||
"dialog.model.search.placeholder": "搜索模型",
|
||||
|
||||
-9
@@ -105,17 +105,8 @@ export const dict = {
|
||||
|
||||
"dialog.provider.search.placeholder": "搜尋供應商",
|
||||
"dialog.provider.empty": "找不到供應商",
|
||||
"dialog.provider.group.popular": "熱門",
|
||||
"dialog.provider.group.other": "其他",
|
||||
"dialog.provider.tag.recommended": "推薦",
|
||||
"dialog.provider.opencode.note": "精選模型,包含 Claude、GPT、Gemini 等",
|
||||
"dialog.provider.anthropic.note": "使用 Claude Pro/Max 或 API 金鑰連線",
|
||||
"dialog.provider.deepseek.note": "用於推理和程式設計任務的 DeepSeek 模型",
|
||||
"dialog.provider.openai.note": "使用 ChatGPT Pro/Plus 或 API 金鑰連線",
|
||||
"dialog.provider.copilot.note": "使用 Copilot 或 API 金鑰連線",
|
||||
"dialog.provider.google.note": "Gemini 模型,提供快速且結構化的回應",
|
||||
"dialog.provider.openrouter.note": "透過單一供應商存取所有支援模型",
|
||||
"dialog.provider.vercel.note": "透過智慧路由統一存取 AI 模型",
|
||||
|
||||
"dialog.model.select.title": "選擇模型",
|
||||
"dialog.model.search.placeholder": "搜尋模型",
|
||||
|
||||
@@ -41,8 +41,8 @@ export interface Provider {
|
||||
env?: string[]
|
||||
metadata?: {
|
||||
noteKey?: string
|
||||
note?: string
|
||||
icon?: string
|
||||
priority?: number
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,34 +2,26 @@ import { iconNames, type IconName } from "@opencode-ai/ui/icons/provider"
|
||||
|
||||
export type ProviderMetadata = {
|
||||
noteKey?: string
|
||||
note?: string
|
||||
icon?: string
|
||||
priority?: number
|
||||
}
|
||||
|
||||
const notes: Record<string, { key: string; note: string }> = {
|
||||
kilo: { key: "settings.providers.note.kilo", note: "Access 500+ AI models" },
|
||||
opencode: {
|
||||
key: "settings.providers.note.opencode",
|
||||
note: "Curated models including Claude, GPT, Gemini and more",
|
||||
},
|
||||
anthropic: {
|
||||
key: "settings.providers.note.anthropic",
|
||||
note: "Direct access to Claude models, including Pro and Max",
|
||||
},
|
||||
deepseek: {
|
||||
key: "settings.providers.note.deepseek",
|
||||
note: "DeepSeek models for reasoning and coding tasks",
|
||||
},
|
||||
"github-copilot": { key: "settings.providers.note.copilot", note: "Claude models for coding assistance" },
|
||||
openai: {
|
||||
key: "settings.providers.note.openai",
|
||||
note: "GPT and Codex models with API key or ChatGPT login",
|
||||
},
|
||||
google: { key: "settings.providers.note.google", note: "Gemini models for fast, structured responses" },
|
||||
openrouter: { key: "settings.providers.note.openrouter", note: "Access all supported models from one provider" },
|
||||
vercel: { key: "settings.providers.note.vercel", note: "Unified access to AI models with smart routing" },
|
||||
const notes: Record<string, string> = {
|
||||
kilo: "settings.providers.note.kilo",
|
||||
opencode: "settings.providers.note.opencode",
|
||||
anthropic: "settings.providers.note.anthropic",
|
||||
deepseek: "settings.providers.note.deepseek",
|
||||
"github-copilot": "settings.providers.note.copilot",
|
||||
openai: "settings.providers.note.openai",
|
||||
google: "settings.providers.note.google",
|
||||
openrouter: "settings.providers.note.openrouter",
|
||||
vercel: "settings.providers.note.vercel",
|
||||
}
|
||||
|
||||
const order = ["kilo", "anthropic", "deepseek", "openai", "google", "openrouter", "vercel"] as const
|
||||
|
||||
const priority = new Map<string, number>(order.map((id, index) => [id, index]))
|
||||
|
||||
const icons = new Set<string>(iconNames)
|
||||
|
||||
function key(id: string) {
|
||||
@@ -41,8 +33,8 @@ export function providerMetadata(id: string): ProviderMetadata {
|
||||
const name = key(id)
|
||||
const note = notes[name]
|
||||
return {
|
||||
noteKey: note?.key,
|
||||
note: note?.note,
|
||||
noteKey: note,
|
||||
icon: icons.has(name as IconName) ? name : "synthetic",
|
||||
priority: priority.get(name),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,8 +938,8 @@ const ProviderLimit = Schema.Struct({
|
||||
// kilocode_change start
|
||||
const ProviderMetadata = Schema.Struct({
|
||||
noteKey: optionalOmitUndefined(Schema.String),
|
||||
note: optionalOmitUndefined(Schema.String),
|
||||
icon: optionalOmitUndefined(Schema.String),
|
||||
priority: optionalOmitUndefined(Schema.Int),
|
||||
})
|
||||
// kilocode_change end
|
||||
|
||||
|
||||
@@ -2,18 +2,17 @@ import { describe, expect, test } from "bun:test"
|
||||
import { providerMetadata } from "../../src/kilocode/provider/metadata"
|
||||
|
||||
describe("providerMetadata", () => {
|
||||
test("returns shared provider note and icon metadata", () => {
|
||||
test("returns shared provider key, icon, and priority metadata", () => {
|
||||
expect(providerMetadata("openai")).toEqual({
|
||||
noteKey: "settings.providers.note.openai",
|
||||
note: "GPT and Codex models with API key or ChatGPT login",
|
||||
icon: "openai",
|
||||
priority: 3,
|
||||
})
|
||||
})
|
||||
|
||||
test("maps github copilot aliases to stable metadata", () => {
|
||||
expect(providerMetadata("github-copilot-custom")).toEqual({
|
||||
noteKey: "settings.providers.note.copilot",
|
||||
note: "Claude models for coding assistance",
|
||||
icon: "github-copilot",
|
||||
})
|
||||
})
|
||||
@@ -21,8 +20,8 @@ describe("providerMetadata", () => {
|
||||
test("uses the Kilo icon for Kilo Gateway", () => {
|
||||
expect(providerMetadata("kilo")).toEqual({
|
||||
noteKey: "settings.providers.note.kilo",
|
||||
note: "Access 500+ AI models",
|
||||
icon: "kilo",
|
||||
priority: 0,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1615,8 +1615,8 @@ export type Provider = {
|
||||
key?: string
|
||||
metadata?: {
|
||||
noteKey?: string
|
||||
note?: string
|
||||
icon?: string
|
||||
priority?: number
|
||||
}
|
||||
options: {
|
||||
[key: string]: unknown
|
||||
|
||||
@@ -16779,9 +16779,6 @@
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -19242,6 +19239,9 @@
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": ["env", "config", "custom", "api"]
|
||||
@@ -19261,11 +19261,11 @@
|
||||
"noteKey": {
|
||||
"type": "string"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string"
|
||||
},
|
||||
"priority": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
||||
Reference in New Issue
Block a user