diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 294e9f22e31..6463a974991 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -242,7 +242,6 @@ const vertexSchema = apiModelIdProviderModelSchema.extend({ const openAiSchema = baseProviderSettingsSchema.extend({ openAiBaseUrl: z.string().optional(), openAiApiKey: z.string().optional(), - openAiLegacyFormat: z.boolean().optional(), openAiR1FormatEnabled: z.boolean().optional(), openAiModelId: z.string().optional(), openAiCustomModelInfo: modelInfoSchema.nullish(), diff --git a/src/api/providers/openai.ts b/src/api/providers/openai.ts index 860fb76a6f0..43a4fe7ae39 100644 --- a/src/api/providers/openai.ts +++ b/src/api/providers/openai.ts @@ -17,7 +17,6 @@ import { XmlMatcher } from "../../utils/xml-matcher" import { convertToOpenAiMessages } from "../transform/openai-format" import { convertToR1Format } from "../transform/r1-format" -import { convertToSimpleMessages } from "../transform/simple-format" import { ApiStream, ApiStreamUsageChunk } from "../transform/stream" import { getModelParams } from "../transform/model-params" @@ -90,10 +89,8 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl const modelUrl = this.options.openAiBaseUrl ?? "" const modelId = this.options.openAiModelId ?? "" const enabledR1Format = this.options.openAiR1FormatEnabled ?? false - const enabledLegacyFormat = this.options.openAiLegacyFormat ?? false const isAzureAiInference = this._isAzureAiInference(modelUrl) const deepseekReasoner = modelId.includes("deepseek-reasoner") || enabledR1Format - const ark = modelUrl.includes(".volces.com") if (modelId.includes("o1") || modelId.includes("o3") || modelId.includes("o4")) { yield* this.handleO3FamilyMessage(modelId, systemPrompt, messages, metadata) @@ -110,8 +107,6 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl if (deepseekReasoner) { convertedMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages]) - } else if (ark || enabledLegacyFormat) { - convertedMessages = [systemMessage, ...convertToSimpleMessages(messages)] } else { if (modelInfo.supportsPromptCache) { systemMessage = { @@ -233,9 +228,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl model: modelId, messages: deepseekReasoner ? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages]) - : enabledLegacyFormat - ? [systemMessage, ...convertToSimpleMessages(messages)] - : [systemMessage, ...convertToOpenAiMessages(messages)], + : [systemMessage, ...convertToOpenAiMessages(messages)], ...(metadata?.tools && { tools: this.convertToolsForOpenAI(metadata.tools) }), ...(metadata?.tool_choice && { tool_choice: metadata.tool_choice }), ...(metadata?.toolProtocol === "native" && { diff --git a/src/api/transform/__tests__/simple-format.spec.ts b/src/api/transform/__tests__/simple-format.spec.ts deleted file mode 100644 index 2775ca0d4ac..00000000000 --- a/src/api/transform/__tests__/simple-format.spec.ts +++ /dev/null @@ -1,140 +0,0 @@ -// npx vitest run src/api/transform/__tests__/simple-format.spec.ts - -import { Anthropic } from "@anthropic-ai/sdk" -import { convertToSimpleContent, convertToSimpleMessages } from "../simple-format" - -describe("simple-format", () => { - describe("convertToSimpleContent", () => { - it("returns string content as-is", () => { - const content = "Hello world" - expect(convertToSimpleContent(content)).toBe("Hello world") - }) - - it("extracts text from text blocks", () => { - const content = [ - { type: "text", text: "Hello" }, - { type: "text", text: "world" }, - ] as Anthropic.Messages.TextBlockParam[] - expect(convertToSimpleContent(content)).toBe("Hello\nworld") - }) - - it("converts image blocks to descriptive text", () => { - const content = [ - { type: "text", text: "Here's an image:" }, - { - type: "image", - source: { - type: "base64", - media_type: "image/png", - data: "base64data", - }, - }, - ] as Array - expect(convertToSimpleContent(content)).toBe("Here's an image:\n[Image: image/png]") - }) - - it("converts tool use blocks to descriptive text", () => { - const content = [ - { type: "text", text: "Using a tool:" }, - { - type: "tool_use", - id: "tool-1", - name: "read_file", - input: { path: "test.txt" }, - }, - ] as Array - expect(convertToSimpleContent(content)).toBe("Using a tool:\n[Tool Use: read_file]") - }) - - it("handles string tool result content", () => { - const content = [ - { type: "text", text: "Tool result:" }, - { - type: "tool_result", - tool_use_id: "tool-1", - content: "Result text", - }, - ] as Array - expect(convertToSimpleContent(content)).toBe("Tool result:\nResult text") - }) - - it("handles array tool result content with text and images", () => { - const content = [ - { - type: "tool_result", - tool_use_id: "tool-1", - content: [ - { type: "text", text: "Result 1" }, - { - type: "image", - source: { - type: "base64", - media_type: "image/jpeg", - data: "base64data", - }, - }, - { type: "text", text: "Result 2" }, - ], - }, - ] as Anthropic.Messages.ToolResultBlockParam[] - expect(convertToSimpleContent(content)).toBe("Result 1\n[Image: image/jpeg]\nResult 2") - }) - - it("filters out empty strings", () => { - const content = [ - { type: "text", text: "Hello" }, - { type: "text", text: "" }, - { type: "text", text: "world" }, - ] as Anthropic.Messages.TextBlockParam[] - expect(convertToSimpleContent(content)).toBe("Hello\nworld") - }) - }) - - describe("convertToSimpleMessages", () => { - it("converts messages with string content", () => { - const messages = [ - { role: "user", content: "Hello" }, - { role: "assistant", content: "Hi there" }, - ] as Anthropic.Messages.MessageParam[] - expect(convertToSimpleMessages(messages)).toEqual([ - { role: "user", content: "Hello" }, - { role: "assistant", content: "Hi there" }, - ]) - }) - - it("converts messages with complex content", () => { - const messages = [ - { - role: "user", - content: [ - { type: "text", text: "Look at this:" }, - { - type: "image", - source: { - type: "base64", - media_type: "image/png", - data: "base64data", - }, - }, - ], - }, - { - role: "assistant", - content: [ - { type: "text", text: "I see the image" }, - { - type: "tool_use", - id: "tool-1", - name: "analyze_image", - input: { data: "base64data" }, - }, - ], - }, - ] as Anthropic.Messages.MessageParam[] - expect(convertToSimpleMessages(messages)).toEqual([ - { role: "user", content: "Look at this:\n[Image: image/png]" }, - { role: "assistant", content: "I see the image\n[Tool Use: analyze_image]" }, - ]) - }) - }) -}) diff --git a/src/api/transform/simple-format.ts b/src/api/transform/simple-format.ts deleted file mode 100644 index 39049f76c27..00000000000 --- a/src/api/transform/simple-format.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Anthropic } from "@anthropic-ai/sdk" - -/** - * Convert complex content blocks to simple string content - */ -export function convertToSimpleContent(content: Anthropic.Messages.MessageParam["content"]): string { - if (typeof content === "string") { - return content - } - - // Extract text from content blocks - return content - .map((block) => { - if (block.type === "text") { - return block.text - } - if (block.type === "image") { - return `[Image: ${block.source.media_type}]` - } - if (block.type === "tool_use") { - return `[Tool Use: ${block.name}]` - } - if (block.type === "tool_result") { - if (typeof block.content === "string") { - return block.content - } - if (Array.isArray(block.content)) { - return block.content - .map((part) => { - if (part.type === "text") { - return part.text - } - if (part.type === "image") { - return `[Image: ${part.source.media_type}]` - } - return "" - }) - .join("\n") - } - return "" - } - return "" - }) - .filter(Boolean) - .join("\n") -} - -/** - * Convert Anthropic messages to simple format with string content - */ -export function convertToSimpleMessages( - messages: Anthropic.Messages.MessageParam[], -): Array<{ role: "user" | "assistant"; content: string }> { - return messages.map((message) => ({ - role: message.role, - content: convertToSimpleContent(message.content), - })) -} diff --git a/webview-ui/src/components/settings/providers/OpenAICompatible.tsx b/webview-ui/src/components/settings/providers/OpenAICompatible.tsx index 2cf77b8366e..17a6bc69c32 100644 --- a/webview-ui/src/components/settings/providers/OpenAICompatible.tsx +++ b/webview-ui/src/components/settings/providers/OpenAICompatible.tsx @@ -41,7 +41,6 @@ export const OpenAICompatible = ({ const { t } = useAppTranslation() const [azureApiVersionSelected, setAzureApiVersionSelected] = useState(!!apiConfiguration?.azureApiVersion) - const [openAiLegacyFormatSelected, setOpenAiLegacyFormatSelected] = useState(!!apiConfiguration?.openAiLegacyFormat) const [openAiModels, setOpenAiModels] = useState | null>(null) @@ -155,16 +154,6 @@ export const OpenAICompatible = ({ onChange={handleInputChange("openAiR1FormatEnabled", noTransform)} openAiR1FormatEnabled={apiConfiguration?.openAiR1FormatEnabled ?? false} /> -
- { - setOpenAiLegacyFormatSelected(checked) - setApiConfigurationField("openAiLegacyFormat", checked) - }}> - {t("settings:providers.useLegacyFormat")} - -
diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 32f6cedf2a3..a78775eee13 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "Utilitzar URL base personalitzada", "useReasoning": "Activar raonament", "useHostHeader": "Utilitzar capçalera Host personalitzada", - "useLegacyFormat": "Utilitzar el format d'API OpenAI antic", "customHeaders": "Capçaleres personalitzades", "headerName": "Nom de la capçalera", "headerValue": "Valor de la capçalera", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index f3d7466b8a3..276fda10c29 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -280,7 +280,6 @@ "useCustomBaseUrl": "Benutzerdefinierte Basis-URL verwenden", "useReasoning": "Reasoning aktivieren", "useHostHeader": "Benutzerdefinierten Host-Header verwenden", - "useLegacyFormat": "Altes OpenAI API-Format verwenden", "customHeaders": "Benutzerdefinierte Headers", "headerName": "Header-Name", "headerValue": "Header-Wert", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index b836ecbfc87..e13a97af479 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -287,7 +287,6 @@ "useCustomBaseUrl": "Use custom base URL", "useReasoning": "Enable reasoning", "useHostHeader": "Use custom Host header", - "useLegacyFormat": "Use legacy OpenAI API format", "customHeaders": "Custom Headers", "headerName": "Header name", "headerValue": "Header value", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 011d39df35c..9102adf812f 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "Usar URL base personalizada", "useReasoning": "Habilitar razonamiento", "useHostHeader": "Usar encabezado Host personalizado", - "useLegacyFormat": "Usar formato API de OpenAI heredado", "customHeaders": "Encabezados personalizados", "headerName": "Nombre del encabezado", "headerValue": "Valor del encabezado", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 57046c1f9dc..0a7746a5791 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "Utiliser une URL de base personnalisée", "useReasoning": "Activer le raisonnement", "useHostHeader": "Utiliser un en-tête Host personnalisé", - "useLegacyFormat": "Utiliser le format API OpenAI hérité", "customHeaders": "En-têtes personnalisés", "headerName": "Nom de l'en-tête", "headerValue": "Valeur de l'en-tête", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 589db4eb044..1003c5ad482 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "कस्टम बेस URL का उपयोग करें", "useReasoning": "तर्क सक्षम करें", "useHostHeader": "कस्टम होस्ट हेडर का उपयोग करें", - "useLegacyFormat": "पुराने OpenAI API प्रारूप का उपयोग करें", "customHeaders": "कस्टम हेडर्स", "headerName": "हेडर नाम", "headerValue": "हेडर मूल्य", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 7722518ec13..2790c922229 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -282,7 +282,6 @@ "useCustomBaseUrl": "Gunakan base URL kustom", "useReasoning": "Aktifkan reasoning", "useHostHeader": "Gunakan Host header kustom", - "useLegacyFormat": "Gunakan format API OpenAI legacy", "customHeaders": "Header Kustom", "headerName": "Nama header", "headerValue": "Nilai header", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 86269cfc770..315ad3f664c 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "Usa URL base personalizzato", "useReasoning": "Abilita ragionamento", "useHostHeader": "Usa intestazione Host personalizzata", - "useLegacyFormat": "Usa formato API OpenAI legacy", "customHeaders": "Intestazioni personalizzate", "headerName": "Nome intestazione", "headerValue": "Valore intestazione", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 6c347f9444b..a72baa5674a 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "カスタムベースURLを使用", "useReasoning": "推論を有効化", "useHostHeader": "カスタムHostヘッダーを使用", - "useLegacyFormat": "レガシーOpenAI API形式を使用", "customHeaders": "カスタムヘッダー", "headerName": "ヘッダー名", "headerValue": "ヘッダー値", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 9f64ae8f676..47278eec7f7 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "사용자 정의 기본 URL 사용", "useReasoning": "추론 활성화", "useHostHeader": "사용자 정의 Host 헤더 사용", - "useLegacyFormat": "레거시 OpenAI API 형식 사용", "customHeaders": "사용자 정의 헤더", "headerName": "헤더 이름", "headerValue": "헤더 값", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index e23872b1dc3..569099cddb2 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "Aangepaste basis-URL gebruiken", "useReasoning": "Redenering inschakelen", "useHostHeader": "Aangepaste Host-header gebruiken", - "useLegacyFormat": "Verouderd OpenAI API-formaat gebruiken", "customHeaders": "Aangepaste headers", "headerName": "Headernaam", "headerValue": "Headerwaarde", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 0aae9a09301..3907ac765da 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "Użyj niestandardowego URL bazowego", "useReasoning": "Włącz rozumowanie", "useHostHeader": "Użyj niestandardowego nagłówka Host", - "useLegacyFormat": "Użyj starszego formatu API OpenAI", "customHeaders": "Niestandardowe nagłówki", "headerName": "Nazwa nagłówka", "headerValue": "Wartość nagłówka", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index b0d6073f142..1b5cc8fcf3d 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "Usar URL base personalizado", "useReasoning": "Habilitar raciocínio", "useHostHeader": "Usar cabeçalho Host personalizado", - "useLegacyFormat": "Usar formato de API OpenAI legado", "customHeaders": "Cabeçalhos personalizados", "headerName": "Nome do cabeçalho", "headerValue": "Valor do cabeçalho", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 5655c3408e0..a30fed3395f 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "Использовать пользовательский базовый URL", "useReasoning": "Включить рассуждения", "useHostHeader": "Использовать пользовательский Host-заголовок", - "useLegacyFormat": "Использовать устаревший формат OpenAI API", "customHeaders": "Пользовательские заголовки", "headerName": "Имя заголовка", "headerValue": "Значение заголовка", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 1e3d128ec51..951bc29183c 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "Özel temel URL kullan", "useReasoning": "Akıl yürütmeyi etkinleştir", "useHostHeader": "Özel Host başlığı kullan", - "useLegacyFormat": "Eski OpenAI API formatını kullan", "customHeaders": "Özel Başlıklar", "headerName": "Başlık adı", "headerValue": "Başlık değeri", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index d7b3a6f63bc..4468b307f49 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "Sử dụng URL cơ sở tùy chỉnh", "useReasoning": "Bật lý luận", "useHostHeader": "Sử dụng tiêu đề Host tùy chỉnh", - "useLegacyFormat": "Sử dụng định dạng API OpenAI cũ", "customHeaders": "Tiêu đề tùy chỉnh", "headerName": "Tên tiêu đề", "headerValue": "Giá trị tiêu đề", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 69edd6ca813..b2952120b4f 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "使用自定义基础 URL", "useReasoning": "启用推理", "useHostHeader": "使用自定义 Host 标头", - "useLegacyFormat": "使用传统 OpenAI API 格式", "customHeaders": "自定义标头", "headerName": "标头名称", "headerValue": "标头值", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index c9e6bff2cdb..01ca8e8d5e7 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -278,7 +278,6 @@ "useCustomBaseUrl": "使用自訂基礎 URL", "useReasoning": "啟用推理", "useHostHeader": "使用自訂 Host 標頭", - "useLegacyFormat": "使用舊版 OpenAI API 格式", "customHeaders": "自訂標頭", "headerName": "標頭名稱", "headerValue": "標頭值",