diff --git a/.changeset/little-ravens-rest.md b/.changeset/little-ravens-rest.md new file mode 100644 index 00000000000..d56f2dded97 --- /dev/null +++ b/.changeset/little-ravens-rest.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Fix image generation handler not using Kilo Gateway properly diff --git a/.changeset/silly-lamps-create.md b/.changeset/silly-lamps-create.md new file mode 100644 index 00000000000..897d1154b5a --- /dev/null +++ b/.changeset/silly-lamps-create.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Fix duplicate tool processing in OpenAI-compatible provider diff --git a/cli/docs/PROVIDER_CONFIGURATION.md b/cli/docs/PROVIDER_CONFIGURATION.md index 6746d75b4d4..ff392b68163 100644 --- a/cli/docs/PROVIDER_CONFIGURATION.md +++ b/cli/docs/PROVIDER_CONFIGURATION.md @@ -6,6 +6,7 @@ This guide provides detailed information on how to configure each provider in Ki - [Introduction](#introduction) - [Configuration Methods](#configuration-methods) +- [Common Parameters](#common-parameters) - [Provider Details](#provider-details) - [Kilo Code](#kilocode) - [Anthropic](#anthropic) @@ -64,6 +65,17 @@ You can configure providers using: --- +## Common Parameters + +**Description**: Parameters that are shared by all providers. + +**Optional Fields**: + +- `enableReasoningEffort` (boolean): Enable or disable reasoning for supported models. Many models have no, dynamic or compulsive reasoning regardless of this setting. Must be set to `true` for `reasoningEffort` or `modelMaxThinkingTokens` to take effect. +- `reasoningEffort` (text): Specify reasoning effort for supported models. Can be `"low"`, `"medium"`, `"high"` or `"xhigh"`. Requires `enableReasoningEffort` to be `true`, mutually exclusive with `modelMaxThinkingTokens`. +- `modelMaxThinkingTokens` (number): Specify reasoning token limit for supported models (mainly Claude models). Requires `enableReasoningEffort` to be `true`, mutually exclusive with `reasoningEffort`. +- `verbosity` (text): Controls the verbosity and length of the model response for supported models (mainly GPT-5.x and Claude Opus 4.5). Also known as output effort. Supported values are `"low"`, `"medium"` and `"high"`. + ## Provider Details ### kilocode diff --git a/src/api/providers/base-openai-compatible-provider.ts b/src/api/providers/base-openai-compatible-provider.ts index ef549a42f0b..605a6583da1 100644 --- a/src/api/providers/base-openai-compatible-provider.ts +++ b/src/api/providers/base-openai-compatible-provider.ts @@ -1,7 +1,7 @@ import { Anthropic } from "@anthropic-ai/sdk" import OpenAI from "openai" -import { type ModelInfo } from "@roo-code/types" +import type { ModelInfo } from "@roo-code/types" import { type ApiHandlerOptions, getModelMaxOutputTokens } from "../../shared/api" import { XmlMatcher } from "../../utils/xml-matcher" @@ -15,7 +15,6 @@ import { verifyFinishReason } from "./kilocode/verifyFinishReason" import { handleOpenAIError } from "./utils/openai-error-handler" import { fetchWithTimeout } from "./kilocode/fetchWithTimeout" // kilocode_change import { getApiRequestTimeout } from "./utils/timeout-config" // kilocode_change -import { ToolCallAccumulator } from "./kilocode/nativeToolCallHelpers" // kilocode_change import { calculateApiCostOpenAI } from "../../shared/cost" type BaseOpenAiCompatibleProviderOptions = ApiHandlerOptions & { @@ -135,16 +134,11 @@ export abstract class BaseOpenAiCompatibleProvider }) as const, ) - const toolCallAccumulator = new ToolCallAccumulator() // kilocode_change let lastUsage: OpenAI.CompletionUsage | undefined for await (const chunk of stream) { verifyFinishReason(chunk.choices?.[0]) // kilocode_change - const delta = chunk.choices?.[0]?.delta - - yield* toolCallAccumulator.processChunk(chunk) // kilocode_change - // Check for provider-specific error responses (e.g., MiniMax base_resp) const chunkAny = chunk as any if (chunkAny.base_resp?.status_code && chunkAny.base_resp.status_code !== 0) { @@ -153,6 +147,8 @@ export abstract class BaseOpenAiCompatibleProvider ) } + const delta = chunk.choices?.[0]?.delta + if (delta?.content) { for (const processedChunk of matcher.update(delta.content)) { yield processedChunk diff --git a/src/api/providers/openai.ts b/src/api/providers/openai.ts index 207a9fa26f6..e1e6c66b24a 100644 --- a/src/api/providers/openai.ts +++ b/src/api/providers/openai.ts @@ -19,7 +19,7 @@ import { convertToR1Format } from "../transform/r1-format" import { convertToSimpleMessages } from "../transform/simple-format" import { ApiStream, ApiStreamUsageChunk } from "../transform/stream" import { getModelParams } from "../transform/model-params" -import { ToolCallAccumulator } from "./kilocode/nativeToolCallHelpers" + import { DEFAULT_HEADERS } from "./constants" import { BaseProvider } from "./base-provider" import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index" @@ -194,13 +194,10 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl ) let lastUsage - const toolCallAccumulator = new ToolCallAccumulator() // kilocode_change for await (const chunk of stream) { const delta = chunk.choices?.[0]?.delta ?? {} - yield* toolCallAccumulator.processChunk(chunk) // kilocode_change - if (delta.content) { for (const chunk of matcher.update(delta.content)) { yield chunk diff --git a/src/core/tools/GenerateImageTool.ts b/src/core/tools/GenerateImageTool.ts index 9aef22dc1ae..91ee15c3566 100644 --- a/src/core/tools/GenerateImageTool.ts +++ b/src/core/tools/GenerateImageTool.ts @@ -203,17 +203,12 @@ export class GenerateImageTool extends BaseTool<"generate_image"> { } let result - if (modelProvider === "kilocode") { - // kilocode_change: Updated from "roo" to "kilocode" provider - // Use Kilo Code Cloud provider (supports both chat completions and images API via OpenRouter) - const rooHandler = new RooHandler({} as any) - result = await rooHandler.generateImage(prompt, selectedModel, inputImageData, apiMethod) - } else { - // Use OpenRouter provider (only supports chat completions API) - // kilocode_change start - const openRouterHandler = openRouterApiKey - ? new OpenRouterHandler({}) - : new KilocodeOpenrouterHandler({ + // kilocode_change start: Updated from "roo" to "kilocode" provider + // Use Kilo Code Cloud provider (supports both chat completions and images API via OpenRouter) + // Use OpenRouter provider (only supports chat completions API) + const handler = + modelProvider === "kilocode" + ? new KilocodeOpenrouterHandler({ kilocodeToken: kiloCodeApiKey, kilocodeOrganizationId: task.apiConfiguration.apiProvider === "kilocode" && @@ -221,21 +216,21 @@ export class GenerateImageTool extends BaseTool<"generate_image"> { ? task.apiConfiguration.kilocodeOrganizationId : undefined, }) - // kilocode_change end - result = await openRouterHandler.generateImage( - prompt, - selectedModel, - // kilocode_change start - openRouterApiKey || - kiloCodeApiKey || - (() => { - throw new Error("Unreachable because of earlier check.") - })(), - // kilocode_change end - inputImageData, - task.taskId, // kilocode_change - ) - } + : new OpenRouterHandler({}) + result = await handler.generateImage( + prompt, + selectedModel, + openRouterApiKey || + kiloCodeApiKey || + (() => { + throw new Error("Unreachable because of earlier check.") + })(), + + inputImageData, + task.taskId, + ) + + // kilocode_change end if (!result.success) { await task.say("error", result.error || "Failed to generate image")