diff --git a/.changeset/ready-hands-share.md b/.changeset/ready-hands-share.md new file mode 100644 index 000000000000..8571d55394cb --- /dev/null +++ b/.changeset/ready-hands-share.md @@ -0,0 +1,6 @@ +--- +"@roo-code/types": minor +"roo-cline": minor +--- + +Add Anthropic Batch API support with 50% cost savings toggle. Users can now enable async batch processing for Anthropic API requests, reducing costs by 50% with a simple settings toggle. diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index a66aae08a243..3399b9c7f370 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -193,6 +193,7 @@ const anthropicSchema = apiModelIdProviderModelSchema.extend({ anthropicBaseUrl: z.string().optional(), anthropicUseAuthToken: z.boolean().optional(), anthropicBeta1MContext: z.boolean().optional(), // Enable 'context-1m-2025-08-07' beta for 1M context window. + anthropicUseBatchApi: z.boolean().optional(), // Enable batch API for 50% cost savings (async processing) }) const claudeCodeSchema = apiModelIdProviderModelSchema.extend({ diff --git a/src/api/providers/anthropic.ts b/src/api/providers/anthropic.ts index b2e158eca53e..5ab5018d9f67 100644 --- a/src/api/providers/anthropic.ts +++ b/src/api/providers/anthropic.ts @@ -17,7 +17,11 @@ import { getModelParams } from "../transform/model-params" import { BaseProvider } from "./base-provider" import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index" -import { calculateApiCostAnthropic } from "../../shared/cost" +import { calculateApiCostAnthropic, applyBatchApiDiscount } from "../../shared/cost" + +// Batch API polling configuration +const BATCH_POLL_INTERVAL_MS = 5000 // Poll every 5 seconds +const BATCH_MAX_POLL_TIME_MS = 600000 // Max 10 minutes polling export class AnthropicHandler extends BaseProvider implements SingleCompletionHandler { private options: ApiHandlerOptions @@ -36,12 +40,67 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa }) } + /** + * Models that support prompt caching + */ + private supportsPromptCaching(modelId: string): boolean { + return [ + "claude-sonnet-4-5", + "claude-sonnet-4-20250514", + "claude-opus-4-1-20250805", + "claude-opus-4-20250514", + "claude-3-7-sonnet-20250219", + "claude-3-5-sonnet-20241022", + "claude-3-5-haiku-20241022", + "claude-3-opus-20240229", + "claude-3-haiku-20240307", + ].includes(modelId) + } + + /** + * Applies cache control to messages for prompt caching + */ + private applyCacheBreakpoints( + messages: Anthropic.Messages.MessageParam[], + cacheControl: CacheControlEphemeral, + ): Anthropic.Messages.MessageParam[] { + const userMsgIndices = messages.reduce( + (acc, msg, index) => (msg.role === "user" ? [...acc, index] : acc), + [] as number[], + ) + + const lastUserMsgIndex = userMsgIndices[userMsgIndices.length - 1] ?? -1 + const secondLastMsgUserIndex = userMsgIndices[userMsgIndices.length - 2] ?? -1 + + return messages.map((message, index) => { + if (index === lastUserMsgIndex || index === secondLastMsgUserIndex) { + return { + ...message, + content: + typeof message.content === "string" + ? [{ type: "text" as const, text: message.content, cache_control: cacheControl }] + : message.content.map((content, contentIndex) => + contentIndex === message.content.length - 1 + ? { ...content, cache_control: cacheControl } + : content, + ), + } + } + return message + }) + } + async *createMessage( systemPrompt: string, messages: Anthropic.Messages.MessageParam[], metadata?: ApiHandlerCreateMessageMetadata, ): ApiStream { - let stream: AnthropicStream + // Use batch API if enabled (50% cost savings, async processing) + if (this.options.anthropicUseBatchApi) { + yield* this.createBatchMessage(systemPrompt, messages, metadata) + return + } + const cacheControl: CacheControlEphemeral = { type: "ephemeral" } let { id: modelId, betas = [], maxTokens, temperature, reasoning: thinking } = this.getModel() @@ -53,98 +112,42 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa betas.push("context-1m-2025-08-07") } - switch (modelId) { - case "claude-sonnet-4-5": - case "claude-sonnet-4-20250514": - case "claude-opus-4-1-20250805": - case "claude-opus-4-20250514": - case "claude-3-7-sonnet-20250219": - case "claude-3-5-sonnet-20241022": - case "claude-3-5-haiku-20241022": - case "claude-3-opus-20240229": - case "claude-haiku-4-5-20251001": - case "claude-3-haiku-20240307": { - /** - * The latest message will be the new user message, one before - * will be the assistant message from a previous request, and - * the user message before that will be a previously cached user - * message. So we need to mark the latest user message as - * ephemeral to cache it for the next request, and mark the - * second to last user message as ephemeral to let the server - * know the last message to retrieve from the cache for the - * current request. - */ - const userMsgIndices = messages.reduce( - (acc, msg, index) => (msg.role === "user" ? [...acc, index] : acc), - [] as number[], - ) - - const lastUserMsgIndex = userMsgIndices[userMsgIndices.length - 1] ?? -1 - const secondLastMsgUserIndex = userMsgIndices[userMsgIndices.length - 2] ?? -1 - - stream = await this.client.messages.create( - { - model: modelId, - max_tokens: maxTokens ?? ANTHROPIC_DEFAULT_MAX_TOKENS, - temperature, - thinking, - // Setting cache breakpoint for system prompt so new tasks can reuse it. - system: [{ text: systemPrompt, type: "text", cache_control: cacheControl }], - messages: messages.map((message, index) => { - if (index === lastUserMsgIndex || index === secondLastMsgUserIndex) { - return { - ...message, - content: - typeof message.content === "string" - ? [{ type: "text", text: message.content, cache_control: cacheControl }] - : message.content.map((content, contentIndex) => - contentIndex === message.content.length - 1 - ? { ...content, cache_control: cacheControl } - : content, - ), - } - } - return message - }), - stream: true, - }, - (() => { - // prompt caching: https://x.com/alexalbert__/status/1823751995901272068 - // https://github.com/anthropics/anthropic-sdk-typescript?tab=readme-ov-file#default-headers - // https://github.com/anthropics/anthropic-sdk-typescript/commit/c920b77fc67bd839bfeb6716ceab9d7c9bbe7393 - - // Then check for models that support prompt caching - switch (modelId) { - case "claude-sonnet-4-5": - case "claude-sonnet-4-20250514": - case "claude-opus-4-1-20250805": - case "claude-opus-4-20250514": - case "claude-3-7-sonnet-20250219": - case "claude-3-5-sonnet-20241022": - case "claude-3-5-haiku-20241022": - case "claude-3-opus-20240229": - case "claude-haiku-4-5-20251001": - case "claude-3-haiku-20240307": - betas.push("prompt-caching-2024-07-31") - return { headers: { "anthropic-beta": betas.join(",") } } - default: - return undefined - } - })(), - ) - break - } - default: { - stream = (await this.client.messages.create({ + let stream: AnthropicStream + + if (this.supportsPromptCaching(modelId)) { + /** + * The latest message will be the new user message, one before + * will be the assistant message from a previous request, and + * the user message before that will be a previously cached user + * message. So we need to mark the latest user message as + * ephemeral to cache it for the next request, and mark the + * second to last user message as ephemeral to let the server + * know the last message to retrieve from the cache for the + * current request. + */ + betas.push("prompt-caching-2024-07-31") + + stream = await this.client.messages.create( + { model: modelId, max_tokens: maxTokens ?? ANTHROPIC_DEFAULT_MAX_TOKENS, temperature, - system: [{ text: systemPrompt, type: "text" }], - messages, + thinking, + system: [{ text: systemPrompt, type: "text", cache_control: cacheControl }], + messages: this.applyCacheBreakpoints(messages, cacheControl), stream: true, - })) as any - break - } + }, + { headers: { "anthropic-beta": betas.join(",") } }, + ) + } else { + stream = (await this.client.messages.create({ + model: modelId, + max_tokens: maxTokens ?? ANTHROPIC_DEFAULT_MAX_TOKENS, + temperature, + system: [{ text: systemPrompt, type: "text" }], + messages, + stream: true, + })) as any } let inputTokens = 0 @@ -266,6 +269,11 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa } } + // Apply 50% discount for Batch API (applies after 1M context pricing if both enabled) + if (this.options.anthropicUseBatchApi) { + info = applyBatchApiDiscount(info) + } + const params = getModelParams({ format: "anthropic", modelId: id, @@ -301,6 +309,145 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa return content?.type === "text" ? content.text : "" } + /** + * Creates a message using the Batch API for 50% cost savings. + * This method handles the async batch job lifecycle: create, poll, and retrieve results. + */ + private async *createBatchMessage( + systemPrompt: string, + messages: Anthropic.Messages.MessageParam[], + metadata?: ApiHandlerCreateMessageMetadata, + ): ApiStream { + const cacheControl: CacheControlEphemeral = { type: "ephemeral" } + let { id: modelId, betas = [], maxTokens, temperature, reasoning: thinking } = this.getModel() + + // Add 1M context beta flag if enabled for Claude Sonnet 4 and 4.5 + if ( + (modelId === "claude-sonnet-4-20250514" || modelId === "claude-sonnet-4-5") && + this.options.anthropicBeta1MContext + ) { + betas.push("context-1m-2025-08-07") + } + + // Add prompt caching beta if model supports it + if (this.supportsPromptCaching(modelId)) { + betas.push("prompt-caching-2024-07-31") + } + + // Notify user about batch processing + yield { + type: "text", + text: "⏳ **Using Batch API (50% cost savings)** - Processing request asynchronously, this may take a moment...\n\n", + } + + // Prepare request with cache breakpoints if supported + const processedMessages = this.supportsPromptCaching(modelId) + ? this.applyCacheBreakpoints(messages, cacheControl) + : messages + + const batchRequest: Anthropic.Messages.MessageCreateParamsNonStreaming = { + model: modelId, + max_tokens: maxTokens ?? ANTHROPIC_DEFAULT_MAX_TOKENS, + temperature, + thinking, + system: this.supportsPromptCaching(modelId) + ? [{ text: systemPrompt, type: "text", cache_control: cacheControl }] + : [{ text: systemPrompt, type: "text" }], + messages: processedMessages, + } + + // Create batch job with beta headers if needed + const batchOptions = betas.length > 0 ? { headers: { "anthropic-beta": betas.join(",") } } : undefined + const batch = await this.client.messages.batches.create( + { + requests: [ + { + // Using Date.now() is sufficient since we only send one request per batch + // If we support multiple requests per batch in the future, consider using crypto.randomUUID() + custom_id: `req_${Date.now()}`, + params: batchRequest, + }, + ], + }, + batchOptions, + ) + + // Poll for batch completion (silently) + const startTime = Date.now() + let completedBatch: Anthropic.Beta.Messages.Batches.BetaMessageBatch | null = null + + while (Date.now() - startTime < BATCH_MAX_POLL_TIME_MS) { + const status = await this.client.messages.batches.retrieve(batch.id) + + if (status.processing_status === "ended") { + completedBatch = status + break + } + + // Only fail on truly failed states; continue polling for all valid transitional states + // Note: SDK types may not include all possible states, so we check the actual string value + const statusStr = status.processing_status as string + if (statusStr === "errored" || statusStr === "expired" || statusStr === "canceled") { + throw new Error(`Batch processing failed with status: ${status.processing_status}`) + } + + // Wait before next poll + await new Promise((resolve) => setTimeout(resolve, BATCH_POLL_INTERVAL_MS)) + } + + if (!completedBatch) { + throw new Error("Batch processing timeout exceeded") + } + + // Retrieve results + const results = await this.client.messages.batches.results(batch.id) + + // Process results + for await (const result of results) { + if (result.result.type === "succeeded") { + const message = result.result.message + + // Yield content blocks + for (const content of message.content) { + if (content.type === "text") { + yield { type: "text", text: content.text } + } else if (content.type === "thinking") { + yield { type: "reasoning", text: content.thinking } + } + } + + // Yield usage information + const usage = message.usage + yield { + type: "usage", + inputTokens: usage.input_tokens || 0, + outputTokens: usage.output_tokens || 0, + cacheWriteTokens: usage.cache_creation_input_tokens || undefined, + cacheReadTokens: usage.cache_read_input_tokens || undefined, + } + + // Calculate and yield cost + yield { + type: "usage", + inputTokens: 0, + outputTokens: 0, + totalCost: calculateApiCostAnthropic( + this.getModel().info, + usage.input_tokens || 0, + usage.output_tokens || 0, + usage.cache_creation_input_tokens || 0, + usage.cache_read_input_tokens || 0, + ), + } + } else if (result.result.type === "errored") { + const error = result.result.error + // ErrorResponse only has 'type' field in SDK types, but may have 'message' at runtime + const errorDetails = JSON.stringify(error) + throw new Error(`Batch request failed: ${error.type} - ${errorDetails}`) + } + } + } + /** * Counts tokens for the given content using Anthropic's API * diff --git a/src/shared/cost.ts b/src/shared/cost.ts index a628756b0dbd..3593bbf49820 100644 --- a/src/shared/cost.ts +++ b/src/shared/cost.ts @@ -54,4 +54,17 @@ export function calculateApiCostOpenAI( ) } +/** + * Applies 50% discount to all pricing fields for Anthropic Batch API usage + */ +export function applyBatchApiDiscount(info: ModelInfo): ModelInfo { + return { + ...info, + inputPrice: typeof info.inputPrice === "number" ? info.inputPrice * 0.5 : undefined, + outputPrice: typeof info.outputPrice === "number" ? info.outputPrice * 0.5 : undefined, + cacheWritesPrice: typeof info.cacheWritesPrice === "number" ? info.cacheWritesPrice * 0.5 : undefined, + cacheReadsPrice: typeof info.cacheReadsPrice === "number" ? info.cacheReadsPrice * 0.5 : undefined, + } +} + export const parseApiPrice = (price: any) => (price ? parseFloat(price) * 1_000_000 : undefined) diff --git a/webview-ui/src/components/settings/providers/Anthropic.tsx b/webview-ui/src/components/settings/providers/Anthropic.tsx index feef788d49ea..df4a6a8f098d 100644 --- a/webview-ui/src/components/settings/providers/Anthropic.tsx +++ b/webview-ui/src/components/settings/providers/Anthropic.tsx @@ -99,6 +99,18 @@ export const Anthropic = ({ apiConfiguration, setApiConfigurationField }: Anthro )} +
+ { + setApiConfigurationField("anthropicUseBatchApi", checked) + }}> + {t("settings:providers.anthropicBatchApiLabel")} + +
+ {t("settings:providers.anthropicBatchApiDescription")} +
+
) } diff --git a/webview-ui/src/components/ui/hooks/useSelectedModel.ts b/webview-ui/src/components/ui/hooks/useSelectedModel.ts index 0d0514b4d667..ce5f71747986 100644 --- a/webview-ui/src/components/ui/hooks/useSelectedModel.ts +++ b/webview-ui/src/components/ui/hooks/useSelectedModel.ts @@ -60,6 +60,7 @@ import { } from "@roo-code/types" import type { ModelRecord, RouterModels } from "@roo/api" +import { applyBatchApiDiscount } from "@roo/cost" import { useRouterModels } from "./useRouterModels" import { useOpenRouterModelProviders } from "./useOpenRouterModelProviders" @@ -362,7 +363,7 @@ function getSelectedModel({ default: { provider satisfies "anthropic" | "gemini-cli" | "qwen-code" | "human-relay" | "fake-ai" const id = apiConfiguration.apiModelId ?? anthropicDefaultModelId - const baseInfo = anthropicModels[id as keyof typeof anthropicModels] + let baseInfo: ModelInfo | undefined = anthropicModels[id as keyof typeof anthropicModels] // Apply 1M context beta tier pricing for Claude Sonnet 4 if ( @@ -384,7 +385,7 @@ function getSelectedModel({ const tier = modelWithTiers.tiers?.[0] if (tier) { // Create a new ModelInfo object with updated values - const info: ModelInfo = { + baseInfo = { ...baseInfo, contextWindow: tier.contextWindow, inputPrice: tier.inputPrice ?? baseInfo.inputPrice, @@ -392,10 +393,14 @@ function getSelectedModel({ cacheWritesPrice: tier.cacheWritesPrice ?? baseInfo.cacheWritesPrice, cacheReadsPrice: tier.cacheReadsPrice ?? baseInfo.cacheReadsPrice, } - return { id, info } } } + // Apply 50% discount for Batch API (applies after 1M context pricing if both enabled) + if (provider === "anthropic" && apiConfiguration.anthropicUseBatchApi && baseInfo) { + baseInfo = applyBatchApiDiscount(baseInfo) + } + return { id, info: baseInfo } } } diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 611159069b29..70a08c1a9e66 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -273,7 +273,9 @@ "anthropicUseAuthToken": "Passar la clau API d'Anthropic com a capçalera d'autorització en lloc de X-Api-Key", "anthropic1MContextBetaLabel": "Activa la finestra de context d'1M (Beta)", "anthropic1MContextBetaDescription": "Amplia la finestra de context a 1 milió de tokens per a Claude Sonnet 4", - "awsBedrock1MContextBetaLabel": "Activa la finestra de context d'1M (Beta)", + "anthropicBatchApiLabel": "Utilitza l'API per lots (50% d'estalvi)", + "anthropicBatchApiDescription": "Processa les sol·licituds de forma asíncrona per reduir els costos en un 50%. Les sol·licituds poden trigar diversos segons o minuts a completar-se.", + "awsBedrock1MContextBetaLabel": "Habilita la finestra de context d'1M (Beta)", "awsBedrock1MContextBetaDescription": "Amplia la finestra de context a 1 milió de tokens per a Claude Sonnet 4", "cerebrasApiKey": "Clau API de Cerebras", "getCerebrasApiKey": "Obtenir clau API de Cerebras", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 00827751b0fd..a0492dc41ed4 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -275,6 +275,8 @@ "anthropicUseAuthToken": "Anthropic API-Schlüssel als Authorization-Header anstelle von X-Api-Key übergeben", "anthropic1MContextBetaLabel": "1M Kontextfenster aktivieren (Beta)", "anthropic1MContextBetaDescription": "Erweitert das Kontextfenster für Claude Sonnet 4 auf 1 Million Token", + "anthropicBatchApiLabel": "Batch-API verwenden (50% Kostenersparnis)", + "anthropicBatchApiDescription": "Anfragen asynchron verarbeiten für 50% niedrigere Kosten. Anfragen können mehrere Sekunden bis Minuten dauern.", "awsBedrock1MContextBetaLabel": "1M Kontextfenster aktivieren (Beta)", "awsBedrock1MContextBetaDescription": "Erweitert das Kontextfenster für Claude Sonnet 4 auf 1 Million Token", "cerebrasApiKey": "Cerebras API-Schlüssel", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index dfccc49cc4ce..8068ba4b7bb4 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -278,6 +278,8 @@ "anthropicUseAuthToken": "Pass Anthropic API Key as Authorization header instead of X-Api-Key", "anthropic1MContextBetaLabel": "Enable 1M context window (Beta)", "anthropic1MContextBetaDescription": "Extends context window to 1 million tokens for Claude Sonnet 4", + "anthropicBatchApiLabel": "Use Batch API (50% cost savings)", + "anthropicBatchApiDescription": "Process requests asynchronously for 50% lower costs. Requests may take several seconds to minutes to complete.", "awsBedrock1MContextBetaLabel": "Enable 1M context window (Beta)", "awsBedrock1MContextBetaDescription": "Extends context window to 1 million tokens for Claude Sonnet 4", "cerebrasApiKey": "Cerebras API Key", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index c1271df82740..5082f735ccca 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -273,6 +273,8 @@ "anthropicUseAuthToken": "Pasar la clave API de Anthropic como encabezado de autorización en lugar de X-Api-Key", "anthropic1MContextBetaLabel": "Habilitar ventana de contexto de 1M (Beta)", "anthropic1MContextBetaDescription": "Amplía la ventana de contexto a 1 millón de tokens para Claude Sonnet 4", + "anthropicBatchApiLabel": "Usar API por lotes (50% de ahorro)", + "anthropicBatchApiDescription": "Procesar solicitudes de forma asíncrona para reducir costos en un 50%. Las solicitudes pueden tardar varios segundos o minutos en completarse.", "awsBedrock1MContextBetaLabel": "Habilitar ventana de contexto de 1M (Beta)", "awsBedrock1MContextBetaDescription": "Amplía la ventana de contexto a 1 millón de tokens para Claude Sonnet 4", "cerebrasApiKey": "Clave API de Cerebras", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index abcf401d6402..3ce0c8064aac 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -273,6 +273,8 @@ "anthropicUseAuthToken": "Passer la clé API Anthropic comme en-tête d'autorisation au lieu de X-Api-Key", "anthropic1MContextBetaLabel": "Activer la fenêtre de contexte de 1M (Bêta)", "anthropic1MContextBetaDescription": "Étend la fenêtre de contexte à 1 million de tokens pour Claude Sonnet 4", + "anthropicBatchApiLabel": "Utiliser l'API Batch (économies de 50%)", + "anthropicBatchApiDescription": "Traiter les requêtes de manière asynchrone pour des coûts réduits de 50%. Les requêtes peuvent prendre de plusieurs secondes à plusieurs minutes.", "awsBedrock1MContextBetaLabel": "Activer la fenêtre de contexte de 1M (Bêta)", "awsBedrock1MContextBetaDescription": "Étend la fenêtre de contexte à 1 million de tokens pour Claude Sonnet 4", "cerebrasApiKey": "Clé API Cerebras", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 975e35411eea..d5d093091890 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -273,6 +273,8 @@ "anthropicUseAuthToken": "X-Api-Key के बजाय Anthropic API कुंजी को Authorization हेडर के रूप में पास करें", "anthropic1MContextBetaLabel": "1M संदर्भ विंडो सक्षम करें (बीटा)", "anthropic1MContextBetaDescription": "Claude Sonnet 4 के लिए संदर्भ विंडो को 1 मिलियन टोकन तक बढ़ाता है", + "anthropicBatchApiLabel": "बैच API का उपयोग करें (50% लागत बचत)", + "anthropicBatchApiDescription": "50% कम लागत के लिए अनुरोधों को एसिंक्रोनस रूप से प्रोसेस करें। अनुरोधों को पूरा होने में कई सेकंड से लेकर मिनटों तक का समय लग सकता है।", "awsBedrock1MContextBetaLabel": "1M संदर्भ विंडो सक्षम करें (बीटा)", "awsBedrock1MContextBetaDescription": "Claude Sonnet 4 के लिए संदर्भ विंडो को 1 मिलियन टोकन तक बढ़ाता है", "cerebrasApiKey": "Cerebras API कुंजी", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index aa2c1172119a..8e4d2c7801c4 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -277,6 +277,8 @@ "anthropicUseAuthToken": "Kirim Anthropic API Key sebagai Authorization header alih-alih X-Api-Key", "anthropic1MContextBetaLabel": "Aktifkan jendela konteks 1M (Beta)", "anthropic1MContextBetaDescription": "Memperluas jendela konteks menjadi 1 juta token untuk Claude Sonnet 4", + "anthropicBatchApiLabel": "Gunakan API Batch (hemat biaya 50%)", + "anthropicBatchApiDescription": "Proses permintaan secara asinkron untuk biaya 50% lebih rendah. Permintaan mungkin memerlukan waktu beberapa detik hingga menit untuk selesai.", "awsBedrock1MContextBetaLabel": "Aktifkan jendela konteks 1M (Beta)", "awsBedrock1MContextBetaDescription": "Memperluas jendela konteks menjadi 1 juta token untuk Claude Sonnet 4", "cerebrasApiKey": "Cerebras API Key", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 6f2e06bb8fd6..62afcbb0ba3b 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -273,7 +273,9 @@ "anthropicUseAuthToken": "Passa la chiave API Anthropic come header di autorizzazione invece di X-Api-Key", "anthropic1MContextBetaLabel": "Abilita finestra di contesto da 1M (Beta)", "anthropic1MContextBetaDescription": "Estende la finestra di contesto a 1 milione di token per Claude Sonnet 4", - "awsBedrock1MContextBetaLabel": "Abilita finestra di contesto da 1M (Beta)", + "anthropicBatchApiLabel": "Usa API Batch (50% di risparmio)", + "anthropicBatchApiDescription": "Elabora le richieste in modo asincrono per ridurre i costi del 50%. Le richieste possono richiedere da pochi secondi a diversi minuti per completarsi.", + "awsBedrock1MContextBetaLabel": "Abilita finestra di contesto 1M (Beta)", "awsBedrock1MContextBetaDescription": "Estende la finestra di contesto a 1 milione di token per Claude Sonnet 4", "cerebrasApiKey": "Chiave API Cerebras", "getCerebrasApiKey": "Ottieni chiave API Cerebras", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index cc1ea09317eb..818bcc77a84e 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -273,6 +273,8 @@ "anthropicUseAuthToken": "Anthropic APIキーをX-Api-Keyの代わりにAuthorizationヘッダーとして渡す", "anthropic1MContextBetaLabel": "1Mコンテキストウィンドウを有効にする(ベータ版)", "anthropic1MContextBetaDescription": "Claude Sonnet 4のコンテキストウィンドウを100万トークンに拡張します", + "anthropicBatchApiLabel": "バッチAPIを使用(50%コスト削減)", + "anthropicBatchApiDescription": "リクエストを非同期で処理し、コストを50%削減します。リクエストの完了には数秒から数分かかる場合があります。", "awsBedrock1MContextBetaLabel": "1Mコンテキストウィンドウを有効にする(ベータ版)", "awsBedrock1MContextBetaDescription": "Claude Sonnet 4のコンテキストウィンドウを100万トークンに拡張します", "cerebrasApiKey": "Cerebras APIキー", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 61539cfc4d9f..f978c704ef2a 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -272,9 +272,11 @@ "getAnthropicApiKey": "Anthropic API 키 받기", "anthropicUseAuthToken": "X-Api-Key 대신 Authorization 헤더로 Anthropic API 키 전달", "anthropic1MContextBetaLabel": "1M 컨텍스트 창 활성화 (베타)", - "anthropic1MContextBetaDescription": "Claude Sonnet 4의 컨텍스트 창을 100만 토큰으로 확장", + "anthropic1MContextBetaDescription": "Claude Sonnet 4의 컨텍스트 창을 100만 토큰으로 확장합니다", + "anthropicBatchApiLabel": "배치 API 사용 (50% 비용 절감)", + "anthropicBatchApiDescription": "비동기로 요청을 처리하여 50% 더 낮은 비용으로 사용할 수 있습니다. 요청은 완료되는 데 몇 초에서 몇 분이 걸릴 수 있습니다.", "awsBedrock1MContextBetaLabel": "1M 컨텍스트 창 활성화 (베타)", - "awsBedrock1MContextBetaDescription": "Claude Sonnet 4의 컨텍스트 창을 100만 토큰으로 확장", + "awsBedrock1MContextBetaDescription": "Claude Sonnet 4의 컨텍스트 창을 100만 토큰으로 확장합니다", "cerebrasApiKey": "Cerebras API 키", "getCerebrasApiKey": "Cerebras API 키 가져오기", "chutesApiKey": "Chutes API 키", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 41ee3e5910bb..c1361cb6a854 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -272,9 +272,11 @@ "getAnthropicApiKey": "Anthropic API-sleutel ophalen", "anthropicUseAuthToken": "Anthropic API-sleutel als Authorization-header doorgeven in plaats van X-Api-Key", "anthropic1MContextBetaLabel": "1M contextvenster inschakelen (bèta)", - "anthropic1MContextBetaDescription": "Breidt het contextvenster uit tot 1 miljoen tokens voor Claude Sonnet 4", - "awsBedrock1MContextBetaLabel": "1M contextvenster inschakelen (bèta)", - "awsBedrock1MContextBetaDescription": "Breidt het contextvenster uit tot 1 miljoen tokens voor Claude Sonnet 4", + "anthropic1MContextBetaDescription": "Breidt het contextvenster uit naar 1 miljoen tokens voor Claude Sonnet 4", + "anthropicBatchApiLabel": "Batch-API gebruiken (50% kostenbesparing)", + "anthropicBatchApiDescription": "Verwerk verzoeken asynchroon voor 50% lagere kosten. Verzoeken kunnen enkele seconden tot minuten duren om te voltooien.", + "awsBedrock1MContextBetaLabel": "1M contextvenster inschakelen (Beta)", + "awsBedrock1MContextBetaDescription": "Breidt het contextvenster uit naar 1 miljoen tokens voor Claude Sonnet 4", "cerebrasApiKey": "Cerebras API-sleutel", "getCerebrasApiKey": "Cerebras API-sleutel verkrijgen", "chutesApiKey": "Chutes API-sleutel", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 6862d6f7edda..15597b71846b 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -272,9 +272,11 @@ "getAnthropicApiKey": "Uzyskaj klucz API Anthropic", "anthropicUseAuthToken": "Przekaż klucz API Anthropic jako nagłówek Authorization zamiast X-Api-Key", "anthropic1MContextBetaLabel": "Włącz okno kontekstowe 1M (Beta)", - "anthropic1MContextBetaDescription": "Rozszerza okno kontekstowe do 1 miliona tokenów dla Claude Sonnet 4", - "awsBedrock1MContextBetaLabel": "Włącz okno kontekstowe 1M (Beta)", - "awsBedrock1MContextBetaDescription": "Rozszerza okno kontekstowe do 1 miliona tokenów dla Claude Sonnet 4", + "anthropic1MContextBetaDescription": "Rozszerza okno kontekstu do 1 miliona tokenów dla Claude Sonnet 4", + "anthropicBatchApiLabel": "Użyj API wsadowego (50% oszczędności)", + "anthropicBatchApiDescription": "Przetwarzaj żądania asynchronicznie, aby obniżyć koszty o 50%. Żądania mogą potrwać od kilku sekund do kilku minut.", + "awsBedrock1MContextBetaLabel": "Włącz okno kontekstu 1M (Beta)", + "awsBedrock1MContextBetaDescription": "Rozszerza okno kontekstu do 1 miliona tokenów dla Claude Sonnet 4", "cerebrasApiKey": "Klucz API Cerebras", "getCerebrasApiKey": "Pobierz klucz API Cerebras", "chutesApiKey": "Klucz API Chutes", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index b8184777acf0..911d9a5e39ec 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -272,9 +272,11 @@ "getAnthropicApiKey": "Obter chave de API Anthropic", "anthropicUseAuthToken": "Passar a chave de API Anthropic como cabeçalho Authorization em vez de X-Api-Key", "anthropic1MContextBetaLabel": "Ativar janela de contexto de 1M (Beta)", - "anthropic1MContextBetaDescription": "Estende a janela de contexto para 1 milhão de tokens para o Claude Sonnet 4", + "anthropic1MContextBetaDescription": "Estende a janela de contexto para 1 milhão de tokens para Claude Sonnet 4", + "anthropicBatchApiLabel": "Usar API em Lote (50% de economia)", + "anthropicBatchApiDescription": "Processa requisições de forma assíncrona para reduzir custos em 50%. As requisições podem levar de alguns segundos a vários minutos para serem concluídas.", "awsBedrock1MContextBetaLabel": "Ativar janela de contexto de 1M (Beta)", - "awsBedrock1MContextBetaDescription": "Estende a janela de contexto para 1 milhão de tokens para o Claude Sonnet 4", + "awsBedrock1MContextBetaDescription": "Estende a janela de contexto para 1 milhão de tokens para Claude Sonnet 4", "cerebrasApiKey": "Chave de API Cerebras", "getCerebrasApiKey": "Obter chave de API Cerebras", "chutesApiKey": "Chave de API Chutes", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index bcbd72089a45..3fefa4173b09 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -273,6 +273,8 @@ "anthropicUseAuthToken": "Передавать Anthropic API-ключ как Authorization-заголовок вместо X-Api-Key", "anthropic1MContextBetaLabel": "Включить контекстное окно 1M (бета)", "anthropic1MContextBetaDescription": "Расширяет контекстное окно до 1 миллиона токенов для Claude Sonnet 4", + "anthropicBatchApiLabel": "Использовать пакетный API (экономия 50%)", + "anthropicBatchApiDescription": "Обрабатывайте запросы асинхронно для снижения затрат на 50%. Выполнение запросов может занять от нескольких секунд до нескольких минут.", "awsBedrock1MContextBetaLabel": "Включить контекстное окно 1M (бета)", "awsBedrock1MContextBetaDescription": "Расширяет контекстное окно до 1 миллиона токенов для Claude Sonnet 4", "cerebrasApiKey": "Cerebras API-ключ", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 4ac28f47d2f2..6f42adf17a23 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -272,9 +272,11 @@ "getAnthropicApiKey": "Anthropic API Anahtarı Al", "anthropicUseAuthToken": "Anthropic API Anahtarını X-Api-Key yerine Authorization başlığı olarak geçir", "anthropic1MContextBetaLabel": "1M bağlam penceresini etkinleştir (Beta)", - "anthropic1MContextBetaDescription": "Claude Sonnet 4 için bağlam penceresini 1 milyon token'a genişletir", + "anthropic1MContextBetaDescription": "Claude Sonnet 4 için bağlam penceresini 1 milyon belirteçe genişletir", + "anthropicBatchApiLabel": "Toplu API kullan (%50 maliyet tasarrufu)", + "anthropicBatchApiDescription": "İstekleri eşzamansız olarak işleyerek %50 daha düşük maliyetlerle çalıştırın. İsteklerin tamamlanması birkaç saniye ila birkaç dakika sürebilir.", "awsBedrock1MContextBetaLabel": "1M bağlam penceresini etkinleştir (Beta)", - "awsBedrock1MContextBetaDescription": "Claude Sonnet 4 için bağlam penceresini 1 milyon token'a genişletir", + "awsBedrock1MContextBetaDescription": "Claude Sonnet 4 için bağlam penceresini 1 milyon belirteçe genişletir", "cerebrasApiKey": "Cerebras API Anahtarı", "getCerebrasApiKey": "Cerebras API Anahtarını Al", "chutesApiKey": "Chutes API Anahtarı", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 4303325d068e..f632f69d179a 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -273,6 +273,8 @@ "anthropicUseAuthToken": "Truyền khóa API Anthropic dưới dạng tiêu đề Authorization thay vì X-Api-Key", "anthropic1MContextBetaLabel": "Bật cửa sổ ngữ cảnh 1M (Beta)", "anthropic1MContextBetaDescription": "Mở rộng cửa sổ ngữ cảnh lên 1 triệu token cho Claude Sonnet 4", + "anthropicBatchApiLabel": "Sử dụng API hàng loạt (tiết kiệm 50% chi phí)", + "anthropicBatchApiDescription": "Xử lý các yêu cầu không đồng bộ để giảm 50% chi phí. Các yêu cầu có thể mất từ vài giây đến vài phút để hoàn thành.", "awsBedrock1MContextBetaLabel": "Bật cửa sổ ngữ cảnh 1M (Beta)", "awsBedrock1MContextBetaDescription": "Mở rộng cửa sổ ngữ cảnh lên 1 triệu token cho Claude Sonnet 4", "cerebrasApiKey": "Khóa API Cerebras", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index f574106f4568..6199eadb0f92 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -273,6 +273,8 @@ "anthropicUseAuthToken": "将 Anthropic API 密钥作为 Authorization 标头传递,而不是 X-Api-Key", "anthropic1MContextBetaLabel": "启用 1M 上下文窗口 (Beta)", "anthropic1MContextBetaDescription": "为 Claude Sonnet 4 将上下文窗口扩展至 100 万个 token", + "anthropicBatchApiLabel": "使用批处理 API(节省 50% 成本)", + "anthropicBatchApiDescription": "异步处理请求,降低 50% 成本。请求可能需要几秒到几分钟才能完成。", "awsBedrock1MContextBetaLabel": "启用 1M 上下文窗口 (Beta)", "awsBedrock1MContextBetaDescription": "为 Claude Sonnet 4 将上下文窗口扩展至 100 万个 token", "cerebrasApiKey": "Cerebras API 密钥", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 67e8c43b60a9..22402dba754c 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -273,6 +273,8 @@ "anthropicUseAuthToken": "將 Anthropic API 金鑰作為 Authorization 標頭傳遞,而非使用 X-Api-Key", "anthropic1MContextBetaLabel": "啟用 1M 上下文視窗 (Beta)", "anthropic1MContextBetaDescription": "為 Claude Sonnet 4 將上下文視窗擴展至 100 萬個 token", + "anthropicBatchApiLabel": "使用批次 API(節省 50% 成本)", + "anthropicBatchApiDescription": "以非同步方式處理請求,降低 50% 成本。請求可能需要幾秒到幾分鐘才能完成。", "awsBedrock1MContextBetaLabel": "啟用 1M 上下文視窗 (Beta)", "awsBedrock1MContextBetaDescription": "為 Claude Sonnet 4 將上下文視窗擴展至 100 萬個 token", "cerebrasApiKey": "Cerebras API 金鑰",