diff --git a/client-next/messages/en.json b/client-next/messages/en.json
index 4becca2..e18872b 100644
--- a/client-next/messages/en.json
+++ b/client-next/messages/en.json
@@ -271,6 +271,7 @@
"cacheReadCost": "Cache Read Cost",
"cacheWriteCost": "Cache Write Cost",
"attachment": "Attachments",
+ "imageInput": "Vision (image input)",
"reasoning": "Reasoning",
"temperature": "Temperature",
"toolCall": "Tool Calls",
diff --git a/client-next/messages/ko.json b/client-next/messages/ko.json
index 00e3f22..fb88881 100644
--- a/client-next/messages/ko.json
+++ b/client-next/messages/ko.json
@@ -271,6 +271,7 @@
"cacheReadCost": "캐시 읽기 비용",
"cacheWriteCost": "캐시 쓰기 비용",
"attachment": "첨부 파일",
+ "imageInput": "비전(이미지 입력)",
"reasoning": "추론",
"temperature": "온도(Temperature)",
"toolCall": "도구 호출",
diff --git a/client-next/messages/zh-CN.json b/client-next/messages/zh-CN.json
index d6f110c..5380ba9 100644
--- a/client-next/messages/zh-CN.json
+++ b/client-next/messages/zh-CN.json
@@ -271,6 +271,7 @@
"cacheReadCost": "\u7f13\u5b58\u8bfb\u53d6\u6210\u672c",
"cacheWriteCost": "\u7f13\u5b58\u5199\u5165\u6210\u672c",
"attachment": "\u9644\u4ef6",
+ "imageInput": "\u89c6\u89c9\uff08\u56fe\u50cf\u8f93\u5165\uff09",
"reasoning": "\u63a8\u7406",
"temperature": "\u6e29\u5ea6",
"toolCall": "\u5de5\u5177\u8c03\u7528",
diff --git a/client-next/src/components/custom-provider-model-editor.tsx b/client-next/src/components/custom-provider-model-editor.tsx
index 5c46706..3e6a0fd 100644
--- a/client-next/src/components/custom-provider-model-editor.tsx
+++ b/client-next/src/components/custom-provider-model-editor.tsx
@@ -23,6 +23,7 @@ interface ModelDraft {
cacheReadCost: string;
cacheWriteCost: string;
attachment: boolean;
+ imageInput: boolean;
reasoning: boolean;
temperature: boolean;
toolCall: boolean;
@@ -65,6 +66,7 @@ function emptyModel(key = "model-id"): ModelDraft {
cacheReadCost: "",
cacheWriteCost: "",
attachment: false,
+ imageInput: false,
reasoning: false,
temperature: false,
toolCall: true,
@@ -112,7 +114,8 @@ function modelDraftsFromProvider(provider: ProviderConfig): ModelDraft[] {
outputCost: toNumberText(model.cost?.output),
cacheReadCost: toNumberText(model.cost?.cache_read),
cacheWriteCost: toNumberText(model.cost?.cache_write),
- attachment: model.attachment === true,
+ attachment: model.attachment === true || model.modalities?.input?.includes("image") === true,
+ imageInput: model.modalities?.input?.includes("image") === true,
reasoning: model.reasoning === true,
temperature: model.temperature === true,
toolCall: model.tool_call !== false,
@@ -203,8 +206,25 @@ function buildModelConfig(model: ModelDraft) {
delete next.cost;
}
- if (model.attachment) next.attachment = true;
+ if (model.attachment || model.imageInput) next.attachment = true;
else delete next.attachment;
+
+ if (model.source?.modalities || model.imageInput) {
+ const inputModalities = new Set(model.source?.modalities?.input || []);
+ const outputModalities = new Set(model.source?.modalities?.output || []);
+ if (model.imageInput) {
+ inputModalities.add("text");
+ inputModalities.add("image");
+ } else {
+ inputModalities.delete("image");
+ }
+ next.modalities = {
+ input: Array.from(inputModalities),
+ output: model.imageInput ? ["text"] : Array.from(outputModalities),
+ };
+ } else {
+ delete next.modalities;
+ }
if (model.reasoning) next.reasoning = true;
else delete next.reasoning;
if (model.temperature) next.temperature = true;
@@ -717,10 +737,27 @@ export function CustomProviderModelEditor({ config, onSave }: CustomProviderMode
+