diff --git a/src/components/settings/acp-agent-settings.tsx b/src/components/settings/acp-agent-settings.tsx index 4227739..a76198a 100644 --- a/src/components/settings/acp-agent-settings.tsx +++ b/src/components/settings/acp-agent-settings.tsx @@ -53,6 +53,16 @@ import { } from "@/components/ui/select" import { Switch } from "@/components/ui/switch" import { Textarea } from "@/components/ui/textarea" +import { + Combobox, + ComboboxContent, + ComboboxEmpty, + ComboboxGroup, + ComboboxInput, + ComboboxItem, + ComboboxLabel, + ComboboxList, +} from "@/components/ui/combobox" import { cn } from "@/lib/utils" import { acpClearBinaryCache, @@ -932,6 +942,90 @@ const OPENCODE_PROVIDER_NPM_OPTIONS = [ }, ] as const +interface OpenCodeModelOptionGroup { + providerId: string + label: string + models: { value: string; label: string }[] +} + +function buildOpenCodeModelOptions( + config: OpenCodeConfigView | null +): OpenCodeModelOptionGroup[] { + if (!config) return [] + const groups: OpenCodeModelOptionGroup[] = [] + for (const providerId of config.providerIds) { + const provider = config.providers[providerId] + if (!provider || provider.modelIds.length === 0) continue + groups.push({ + providerId, + label: provider.name || providerId, + models: provider.modelIds.map((modelId) => ({ + value: `${providerId}/${modelId}`, + label: modelId, + })), + }) + } + return groups +} + +function OpenCodeModelCombobox({ + value, + onValueChange, + groups, + placeholder, +}: { + value: string + onValueChange: (value: string) => void + groups: OpenCodeModelOptionGroup[] + placeholder: string +}) { + const inputRef = useRef(null) + + const handleSelect = useCallback( + (next: string | null) => { + if (typeof next === "string" && next !== value) { + onValueChange(next) + } + }, + [onValueChange, value] + ) + + const handleBlur = useCallback(() => { + const trimmed = (inputRef.current?.value ?? "").trim() + if (trimmed !== value) { + onValueChange(trimmed) + } + }, [onValueChange, value]) + + return ( + + + + + {groups.map((group) => ( + + {group.label} + {group.models.map((model) => ( + + {model.value} + + ))} + + ))} + + {acpText("openCode.noMatchingModels", "No matching models")} + + + + + ) +} + function buildOpenCodeNpmOptions(currentValue: string): string[] { const next = new Set( OPENCODE_PROVIDER_NPM_OPTIONS.map((v) => v.value) @@ -3207,6 +3301,10 @@ export function AcpAgentSettings() { selectedConfigText, selectedOpenCodeAuthJsonText, ]) + const openCodeModelOptions = useMemo( + () => buildOpenCodeModelOptions(selectedOpenCodeConfig), + [selectedOpenCodeConfig] + ) const selectedChecks = useMemo(() => { if (!selectedAgent || !locale) return [] return getAgentChecks(selectedAgent, selectedCurrent) @@ -5533,32 +5631,28 @@ supports_websockets = true`}
- { - handleOpenCodeFieldChange( - "model", - event.target.value - ) - }} - placeholder="google/gemini-3-pro-preview" + onValueChange={(v) => + handleOpenCodeFieldChange("model", v) + } + groups={openCodeModelOptions} + placeholder="provider/model-id" />
- { - handleOpenCodeFieldChange( - "small_model", - event.target.value - ) - }} - placeholder="google/gemini-3-flash-preview" + onValueChange={(v) => + handleOpenCodeFieldChange("small_model", v) + } + groups={openCodeModelOptions} + placeholder="provider/model-id" />
diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 5228225..e6ab1a3 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -555,7 +555,10 @@ "modelId": "معرّف النموذج", "modelName": "اسم النموذج", "deleteModel": "حذف النموذج {modelId}", - "nativeJsonConfig": "إعداد JSON الأصلي لـ OpenCode" + "nativeJsonConfig": "إعداد JSON الأصلي لـ OpenCode", + "mainModel": "النموذج الرئيسي", + "smallModel": "النموذج الصغير", + "noMatchingModels": "لا توجد نماذج مطابقة" }, "openClaw": { "gatewayConfig": "إعداد Gateway", diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 6484130..bf1db0a 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -555,7 +555,10 @@ "modelId": "Modell-ID", "modelName": "Modellname", "deleteModel": "Modell {modelId} löschen", - "nativeJsonConfig": "OpenCode Native JSON-Konfiguration" + "nativeJsonConfig": "OpenCode Native JSON-Konfiguration", + "mainModel": "Hauptmodell", + "smallModel": "Kleines Modell", + "noMatchingModels": "Keine passenden Modelle" }, "openClaw": { "gatewayConfig": "Gateway-Konfiguration", diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 59ff902..e2b8987 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -555,7 +555,10 @@ "modelId": "Model ID", "modelName": "Model Name", "deleteModel": "Delete model {modelId}", - "nativeJsonConfig": "OpenCode Native JSON Config" + "nativeJsonConfig": "OpenCode Native JSON Config", + "mainModel": "Main Model", + "smallModel": "Small Model", + "noMatchingModels": "No matching models" }, "openClaw": { "gatewayConfig": "Gateway Config", diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json index e397094..4ee1100 100644 --- a/src/i18n/messages/es.json +++ b/src/i18n/messages/es.json @@ -555,7 +555,10 @@ "modelId": "ID de modelo", "modelName": "Nombre del modelo", "deleteModel": "Eliminar modelo {modelId}", - "nativeJsonConfig": "Configuración JSON nativa de OpenCode" + "nativeJsonConfig": "Configuración JSON nativa de OpenCode", + "mainModel": "Modelo principal", + "smallModel": "Modelo pequeño", + "noMatchingModels": "No hay modelos coincidentes" }, "openClaw": { "gatewayConfig": "Configuración de Gateway", diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index e63f7e3..ea7e75b 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -555,7 +555,10 @@ "modelId": "ID du modèle", "modelName": "Nom du modèle", "deleteModel": "Supprimer le modèle {modelId}", - "nativeJsonConfig": "Configuration JSON native OpenCode" + "nativeJsonConfig": "Configuration JSON native OpenCode", + "mainModel": "Modèle principal", + "smallModel": "Petit modèle", + "noMatchingModels": "Aucun modèle correspondant" }, "openClaw": { "gatewayConfig": "Configuration Gateway", diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json index 64ac549..33ad37b 100644 --- a/src/i18n/messages/ja.json +++ b/src/i18n/messages/ja.json @@ -555,7 +555,10 @@ "modelId": "モデル ID", "modelName": "モデル名", "deleteModel": "モデル {modelId} を削除", - "nativeJsonConfig": "OpenCode ネイティブ JSON 設定" + "nativeJsonConfig": "OpenCode ネイティブ JSON 設定", + "mainModel": "メインモデル", + "smallModel": "スモールモデル", + "noMatchingModels": "一致するモデルがありません" }, "openClaw": { "gatewayConfig": "Gateway 設定", diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json index c27145b..8bf13eb 100644 --- a/src/i18n/messages/ko.json +++ b/src/i18n/messages/ko.json @@ -555,7 +555,10 @@ "modelId": "모델 ID", "modelName": "모델 이름", "deleteModel": "모델 {modelId} 삭제", - "nativeJsonConfig": "OpenCode 네이티브 JSON 구성" + "nativeJsonConfig": "OpenCode 네이티브 JSON 구성", + "mainModel": "메인 모델", + "smallModel": "스몰 모델", + "noMatchingModels": "일치하는 모델 없음" }, "openClaw": { "gatewayConfig": "Gateway 구성", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index c94d6b6..523ae3f 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -555,7 +555,10 @@ "modelId": "ID do modelo", "modelName": "Nome do modelo", "deleteModel": "Excluir modelo {modelId}", - "nativeJsonConfig": "Configuração JSON nativa do OpenCode" + "nativeJsonConfig": "Configuração JSON nativa do OpenCode", + "mainModel": "Modelo principal", + "smallModel": "Modelo pequeno", + "noMatchingModels": "Nenhum modelo correspondente" }, "openClaw": { "gatewayConfig": "Configuração de Gateway", diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index 475a7fb..1959fc9 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -555,7 +555,10 @@ "modelId": "模型 ID", "modelName": "模型名称", "deleteModel": "删除模型 {modelId}", - "nativeJsonConfig": "OpenCode 原生 JSON 配置" + "nativeJsonConfig": "OpenCode 原生 JSON 配置", + "mainModel": "主模型", + "smallModel": "小模型", + "noMatchingModels": "没有匹配的模型" }, "openClaw": { "gatewayConfig": "Gateway 配置", diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json index f058dba..784f180 100644 --- a/src/i18n/messages/zh-TW.json +++ b/src/i18n/messages/zh-TW.json @@ -555,7 +555,10 @@ "modelId": "模型 ID", "modelName": "模型名稱", "deleteModel": "刪除模型 {modelId}", - "nativeJsonConfig": "OpenCode 原生 JSON 配置" + "nativeJsonConfig": "OpenCode 原生 JSON 配置", + "mainModel": "主模型", + "smallModel": "小模型", + "noMatchingModels": "沒有匹配的模型" }, "openClaw": { "gatewayConfig": "Gateway 配置",