From 0e7abee7153817572dcf263e81d6de7e6bbad225 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 7 Aug 2025 17:00:54 +0000 Subject: [PATCH 01/17] feat: add GPT-5 model support - Added GPT-5 models (gpt-5-2025-08-07, gpt-5-mini-2025-08-07, gpt-5-nano-2025-08-07) - Added nectarine-alpha-new-reasoning-effort-2025-07-25 experimental model - Set gpt-5-2025-08-07 as default OpenAI Native model - Implemented GPT-5 specific handling with streaming and reasoning effort support --- .changeset/gpt5-support.md | 11 ++++++++ packages/types/src/providers/openai.ts | 38 +++++++++++++++++++++++++- src/api/providers/openai-native.ts | 22 +++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 .changeset/gpt5-support.md diff --git a/.changeset/gpt5-support.md b/.changeset/gpt5-support.md new file mode 100644 index 0000000000..173d60899c --- /dev/null +++ b/.changeset/gpt5-support.md @@ -0,0 +1,11 @@ +--- +"@roo-code/types": minor +"roo-cline": minor +--- + +Add GPT-5 model support + +- Added GPT-5 models (gpt-5-2025-08-07, gpt-5-mini-2025-08-07, gpt-5-nano-2025-08-07) to OpenAI Native provider +- Added nectarine-alpha-new-reasoning-effort-2025-07-25 experimental model +- Set gpt-5-2025-08-07 as the new default OpenAI Native model +- Implemented GPT-5 specific handling with streaming and reasoning effort support diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index 0afdd46feb..027ee17f1a 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -3,9 +3,45 @@ import type { ModelInfo } from "../model.js" // https://openai.com/api/pricing/ export type OpenAiNativeModelId = keyof typeof openAiNativeModels -export const openAiNativeDefaultModelId: OpenAiNativeModelId = "gpt-4.1" +export const openAiNativeDefaultModelId: OpenAiNativeModelId = "gpt-5-2025-08-07" export const openAiNativeModels = { + "gpt-5-2025-08-07": { + maxTokens: 128000, + contextWindow: 256000, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 1.25, + outputPrice: 10.0, + cacheReadsPrice: 0.125, + }, + "gpt-5-mini-2025-08-07": { + maxTokens: 128000, + contextWindow: 256000, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 0.25, + outputPrice: 2.0, + cacheReadsPrice: 0.025, + }, + "gpt-5-nano-2025-08-07": { + maxTokens: 128000, + contextWindow: 256000, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 0.05, + outputPrice: 0.4, + cacheReadsPrice: 0.005, + }, + "nectarine-alpha-new-reasoning-effort-2025-07-25": { + maxTokens: 128000, + contextWindow: 256000, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 0, + outputPrice: 0, + cacheReadsPrice: 0, + }, "gpt-4.1": { maxTokens: 32_768, contextWindow: 1_047_576, diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index 3f14e65cc6..c9913406a5 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -53,6 +53,8 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio yield* this.handleReasonerMessage(model, id, systemPrompt, messages) } else if (model.id.startsWith("o1")) { yield* this.handleO1FamilyMessage(model, systemPrompt, messages) + } else if (this.isGPT5Model(model.id)) { + yield* this.handleGPT5Message(model, systemPrompt, messages) } else { yield* this.handleDefaultModelMessage(model, systemPrompt, messages) } @@ -123,6 +125,26 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio yield* this.handleStreamResponse(stream, model) } + private async *handleGPT5Message( + model: OpenAiNativeModel, + systemPrompt: string, + messages: Anthropic.Messages.MessageParam[], + ): ApiStream { + const stream = await this.client.chat.completions.create({ + model: model.id, + temperature: 1, + messages: [{ role: "developer", content: systemPrompt }, ...convertToOpenAiMessages(messages)], + stream: true, + stream_options: { include_usage: true }, + }) + + yield* this.handleStreamResponse(stream, model) + } + + private isGPT5Model(modelId: string): boolean { + return modelId.includes("gpt-5") || modelId.includes("gpt5") || modelId.includes("nectarine") + } + private async *handleStreamResponse( stream: AsyncIterable, model: OpenAiNativeModel, From b99eb415ffa54616aea19297595b3b8147880e35 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 7 Aug 2025 17:22:31 +0000 Subject: [PATCH 02/17] fix: remove hardcoded temperature from GPT-5 handler - Updated handleGPT5Message to use configurable temperature - Now uses this.options.modelTemperature ?? OPENAI_NATIVE_DEFAULT_TEMPERATURE - Maintains consistency with other model handlers --- src/api/providers/openai-native.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index c9913406a5..1ebef2ef46 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -132,7 +132,7 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio ): ApiStream { const stream = await this.client.chat.completions.create({ model: model.id, - temperature: 1, + temperature: this.options.modelTemperature ?? OPENAI_NATIVE_DEFAULT_TEMPERATURE, messages: [{ role: "developer", content: systemPrompt }, ...convertToOpenAiMessages(messages)], stream: true, stream_options: { include_usage: true }, From 57eccb5a5aee74582f71312235f4bcbf5ed205ea Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 7 Aug 2025 17:34:55 +0000 Subject: [PATCH 03/17] feat: add reasoning effort support for all OpenAI models --- packages/types/src/providers/openai.ts | 13 +++++++++++++ src/api/providers/openai-native.ts | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index 027ee17f1a..4b96b970b5 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -11,6 +11,7 @@ export const openAiNativeModels = { contextWindow: 256000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.25, outputPrice: 10.0, cacheReadsPrice: 0.125, @@ -20,6 +21,7 @@ export const openAiNativeModels = { contextWindow: 256000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 0.25, outputPrice: 2.0, cacheReadsPrice: 0.025, @@ -29,6 +31,7 @@ export const openAiNativeModels = { contextWindow: 256000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 0.05, outputPrice: 0.4, cacheReadsPrice: 0.005, @@ -38,6 +41,7 @@ export const openAiNativeModels = { contextWindow: 256000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 0, outputPrice: 0, cacheReadsPrice: 0, @@ -47,6 +51,7 @@ export const openAiNativeModels = { contextWindow: 1_047_576, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 2, outputPrice: 8, cacheReadsPrice: 0.5, @@ -56,6 +61,7 @@ export const openAiNativeModels = { contextWindow: 1_047_576, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 0.4, outputPrice: 1.6, cacheReadsPrice: 0.1, @@ -65,6 +71,7 @@ export const openAiNativeModels = { contextWindow: 1_047_576, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 0.1, outputPrice: 0.4, cacheReadsPrice: 0.025, @@ -167,6 +174,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 15, outputPrice: 60, cacheReadsPrice: 7.5, @@ -176,6 +184,7 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 15, outputPrice: 60, cacheReadsPrice: 7.5, @@ -185,6 +194,7 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, @@ -194,6 +204,7 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 75, outputPrice: 150, cacheReadsPrice: 37.5, @@ -203,6 +214,7 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 2.5, outputPrice: 10, cacheReadsPrice: 1.25, @@ -212,6 +224,7 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 0.15, outputPrice: 0.6, cacheReadsPrice: 0.075, diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index 1ebef2ef46..d8e22cf81d 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -68,6 +68,8 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio // o1 supports developer prompt with formatting // o1-preview and o1-mini only support user messages const isOriginalO1 = model.id === "o1" + const { reasoning } = this.getModel() + const response = await this.client.chat.completions.create({ model: model.id, messages: [ @@ -79,6 +81,7 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio ], stream: true, stream_options: { include_usage: true }, + ...(reasoning && reasoning), }) yield* this.handleStreamResponse(response, model) @@ -114,12 +117,15 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio systemPrompt: string, messages: Anthropic.Messages.MessageParam[], ): ApiStream { + const { reasoning } = this.getModel() + const stream = await this.client.chat.completions.create({ model: model.id, temperature: this.options.modelTemperature ?? OPENAI_NATIVE_DEFAULT_TEMPERATURE, messages: [{ role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages)], stream: true, stream_options: { include_usage: true }, + ...(reasoning && reasoning), }) yield* this.handleStreamResponse(stream, model) @@ -130,12 +136,15 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio systemPrompt: string, messages: Anthropic.Messages.MessageParam[], ): ApiStream { + const { reasoning } = this.getModel() + const stream = await this.client.chat.completions.create({ model: model.id, temperature: this.options.modelTemperature ?? OPENAI_NATIVE_DEFAULT_TEMPERATURE, messages: [{ role: "developer", content: systemPrompt }, ...convertToOpenAiMessages(messages)], stream: true, stream_options: { include_usage: true }, + ...(reasoning && reasoning), }) yield* this.handleStreamResponse(stream, model) From 4d6056ef2e8d7d984a25d9a11000cf9ac105e663 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 7 Aug 2025 17:45:58 +0000 Subject: [PATCH 04/17] fix: update test to expect new default model gpt-5-2025-08-07 --- src/api/providers/__tests__/openai-native.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/providers/__tests__/openai-native.spec.ts b/src/api/providers/__tests__/openai-native.spec.ts index 64080b4cac..056ad6cdc7 100644 --- a/src/api/providers/__tests__/openai-native.spec.ts +++ b/src/api/providers/__tests__/openai-native.spec.ts @@ -455,7 +455,7 @@ describe("OpenAiNativeHandler", () => { openAiNativeApiKey: "test-api-key", }) const modelInfo = handlerWithoutModel.getModel() - expect(modelInfo.id).toBe("gpt-4.1") // Default model + expect(modelInfo.id).toBe("gpt-5-2025-08-07") // Default model expect(modelInfo.info).toBeDefined() }) }) From fe82301ffaf075d44fc569c5d45f12a97f711fa0 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 7 Aug 2025 17:55:47 +0000 Subject: [PATCH 05/17] feat: increase GPT-5 models context window to 400,000 - Updated context window from 256,000 to 400,000 for gpt-5-2025-08-07 - Updated context window from 256,000 to 400,000 for gpt-5-mini-2025-08-07 - Updated context window from 256,000 to 400,000 for gpt-5-nano-2025-08-07 - Updated context window from 256,000 to 400,000 for nectarine-alpha-new-reasoning-effort-2025-07-25 As requested by @daniel-lxs in PR #6819 --- packages/types/src/providers/openai.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index 4b96b970b5..fb4433091d 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -8,7 +8,7 @@ export const openAiNativeDefaultModelId: OpenAiNativeModelId = "gpt-5-2025-08-07 export const openAiNativeModels = { "gpt-5-2025-08-07": { maxTokens: 128000, - contextWindow: 256000, + contextWindow: 400000, supportsImages: true, supportsPromptCache: true, supportsReasoningEffort: true, @@ -18,7 +18,7 @@ export const openAiNativeModels = { }, "gpt-5-mini-2025-08-07": { maxTokens: 128000, - contextWindow: 256000, + contextWindow: 400000, supportsImages: true, supportsPromptCache: true, supportsReasoningEffort: true, @@ -28,7 +28,7 @@ export const openAiNativeModels = { }, "gpt-5-nano-2025-08-07": { maxTokens: 128000, - contextWindow: 256000, + contextWindow: 400000, supportsImages: true, supportsPromptCache: true, supportsReasoningEffort: true, @@ -38,7 +38,7 @@ export const openAiNativeModels = { }, "nectarine-alpha-new-reasoning-effort-2025-07-25": { maxTokens: 128000, - contextWindow: 256000, + contextWindow: 400000, supportsImages: true, supportsPromptCache: true, supportsReasoningEffort: true, From 0c3260205db175f0652a659a8c862d38c3628bd2 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 7 Aug 2025 18:08:33 +0000 Subject: [PATCH 06/17] revert: remove GPT-5 models, keep only nectarine experimental model - Removed gpt-5-2025-08-07, gpt-5-mini-2025-08-07, gpt-5-nano-2025-08-07 - Kept nectarine-alpha-new-reasoning-effort-2025-07-25 experimental model - Reverted default model back to gpt-4o - Updated tests and changeset accordingly --- .changeset/gpt5-support.md | 8 ++-- packages/types/src/providers/openai.ts | 44 +------------------ .../providers/__tests__/openai-native.spec.ts | 2 +- src/api/providers/openai-native.ts | 10 ++--- 4 files changed, 10 insertions(+), 54 deletions(-) diff --git a/.changeset/gpt5-support.md b/.changeset/gpt5-support.md index 173d60899c..b394e7cf63 100644 --- a/.changeset/gpt5-support.md +++ b/.changeset/gpt5-support.md @@ -3,9 +3,7 @@ "roo-cline": minor --- -Add GPT-5 model support +Add nectarine experimental model support -- Added GPT-5 models (gpt-5-2025-08-07, gpt-5-mini-2025-08-07, gpt-5-nano-2025-08-07) to OpenAI Native provider -- Added nectarine-alpha-new-reasoning-effort-2025-07-25 experimental model -- Set gpt-5-2025-08-07 as the new default OpenAI Native model -- Implemented GPT-5 specific handling with streaming and reasoning effort support +- Added nectarine-alpha-new-reasoning-effort-2025-07-25 experimental model to OpenAI Native provider +- Implemented nectarine-specific handling with streaming and reasoning effort support diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index fb4433091d..0068503710 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -3,39 +3,9 @@ import type { ModelInfo } from "../model.js" // https://openai.com/api/pricing/ export type OpenAiNativeModelId = keyof typeof openAiNativeModels -export const openAiNativeDefaultModelId: OpenAiNativeModelId = "gpt-5-2025-08-07" +export const openAiNativeDefaultModelId: OpenAiNativeModelId = "gpt-4o" export const openAiNativeModels = { - "gpt-5-2025-08-07": { - maxTokens: 128000, - contextWindow: 400000, - supportsImages: true, - supportsPromptCache: true, - supportsReasoningEffort: true, - inputPrice: 1.25, - outputPrice: 10.0, - cacheReadsPrice: 0.125, - }, - "gpt-5-mini-2025-08-07": { - maxTokens: 128000, - contextWindow: 400000, - supportsImages: true, - supportsPromptCache: true, - supportsReasoningEffort: true, - inputPrice: 0.25, - outputPrice: 2.0, - cacheReadsPrice: 0.025, - }, - "gpt-5-nano-2025-08-07": { - maxTokens: 128000, - contextWindow: 400000, - supportsImages: true, - supportsPromptCache: true, - supportsReasoningEffort: true, - inputPrice: 0.05, - outputPrice: 0.4, - cacheReadsPrice: 0.005, - }, "nectarine-alpha-new-reasoning-effort-2025-07-25": { maxTokens: 128000, contextWindow: 400000, @@ -51,7 +21,6 @@ export const openAiNativeModels = { contextWindow: 1_047_576, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 2, outputPrice: 8, cacheReadsPrice: 0.5, @@ -61,7 +30,6 @@ export const openAiNativeModels = { contextWindow: 1_047_576, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 0.4, outputPrice: 1.6, cacheReadsPrice: 0.1, @@ -71,7 +39,6 @@ export const openAiNativeModels = { contextWindow: 1_047_576, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 0.1, outputPrice: 0.4, cacheReadsPrice: 0.025, @@ -84,7 +51,6 @@ export const openAiNativeModels = { inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, - supportsReasoningEffort: true, reasoningEffort: "medium", }, "o3-high": { @@ -115,7 +81,6 @@ export const openAiNativeModels = { inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, - supportsReasoningEffort: true, reasoningEffort: "medium", }, "o4-mini-high": { @@ -146,7 +111,6 @@ export const openAiNativeModels = { inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, - supportsReasoningEffort: true, reasoningEffort: "medium", }, "o3-mini-high": { @@ -174,7 +138,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 15, outputPrice: 60, cacheReadsPrice: 7.5, @@ -184,7 +147,6 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 15, outputPrice: 60, cacheReadsPrice: 7.5, @@ -194,7 +156,6 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, @@ -204,7 +165,6 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 75, outputPrice: 150, cacheReadsPrice: 37.5, @@ -214,7 +174,6 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 2.5, outputPrice: 10, cacheReadsPrice: 1.25, @@ -224,7 +183,6 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 0.15, outputPrice: 0.6, cacheReadsPrice: 0.075, diff --git a/src/api/providers/__tests__/openai-native.spec.ts b/src/api/providers/__tests__/openai-native.spec.ts index 056ad6cdc7..082e96dfb5 100644 --- a/src/api/providers/__tests__/openai-native.spec.ts +++ b/src/api/providers/__tests__/openai-native.spec.ts @@ -455,7 +455,7 @@ describe("OpenAiNativeHandler", () => { openAiNativeApiKey: "test-api-key", }) const modelInfo = handlerWithoutModel.getModel() - expect(modelInfo.id).toBe("gpt-5-2025-08-07") // Default model + expect(modelInfo.id).toBe("gpt-4o") // Default model expect(modelInfo.info).toBeDefined() }) }) diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index d8e22cf81d..936f2a42e5 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -53,8 +53,8 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio yield* this.handleReasonerMessage(model, id, systemPrompt, messages) } else if (model.id.startsWith("o1")) { yield* this.handleO1FamilyMessage(model, systemPrompt, messages) - } else if (this.isGPT5Model(model.id)) { - yield* this.handleGPT5Message(model, systemPrompt, messages) + } else if (this.isNectarineModel(model.id)) { + yield* this.handleNectarineMessage(model, systemPrompt, messages) } else { yield* this.handleDefaultModelMessage(model, systemPrompt, messages) } @@ -131,7 +131,7 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio yield* this.handleStreamResponse(stream, model) } - private async *handleGPT5Message( + private async *handleNectarineMessage( model: OpenAiNativeModel, systemPrompt: string, messages: Anthropic.Messages.MessageParam[], @@ -150,8 +150,8 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio yield* this.handleStreamResponse(stream, model) } - private isGPT5Model(modelId: string): boolean { - return modelId.includes("gpt-5") || modelId.includes("gpt5") || modelId.includes("nectarine") + private isNectarineModel(modelId: string): boolean { + return modelId.includes("nectarine") } private async *handleStreamResponse( From 7c5e5a09571fa623ffb3623470c91314e59fceff Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 7 Aug 2025 18:20:27 +0000 Subject: [PATCH 07/17] feat: add GPT-5 models with updated context windows - Added gpt-5-2025-08-07, gpt-5-mini-2025-08-07, gpt-5-nano-2025-08-07 models - All GPT-5 models configured with 400,000 context window - Updated nectarine model context window to 256,000 - All models configured with reasoning effort support - Set gpt-5-2025-08-07 as default OpenAI Native model - Added GPT-5 model handling in openai-native.ts - Updated tests to reflect new default model --- packages/types/src/providers/openai.ts | 34 +++++++++++++++++-- .../providers/__tests__/openai-native.spec.ts | 2 +- src/api/providers/openai-native.ts | 6 +++- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index 0068503710..a8765b21d8 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -3,10 +3,30 @@ import type { ModelInfo } from "../model.js" // https://openai.com/api/pricing/ export type OpenAiNativeModelId = keyof typeof openAiNativeModels -export const openAiNativeDefaultModelId: OpenAiNativeModelId = "gpt-4o" +export const openAiNativeDefaultModelId: OpenAiNativeModelId = "gpt-5-2025-08-07" export const openAiNativeModels = { - "nectarine-alpha-new-reasoning-effort-2025-07-25": { + "gpt-5-2025-08-07": { + maxTokens: 128000, + contextWindow: 400000, + supportsImages: true, + supportsPromptCache: true, + supportsReasoningEffort: true, + inputPrice: 0, + outputPrice: 0, + cacheReadsPrice: 0, + }, + "gpt-5-mini-2025-08-07": { + maxTokens: 128000, + contextWindow: 400000, + supportsImages: true, + supportsPromptCache: true, + supportsReasoningEffort: true, + inputPrice: 0, + outputPrice: 0, + cacheReadsPrice: 0, + }, + "gpt-5-nano-2025-08-07": { maxTokens: 128000, contextWindow: 400000, supportsImages: true, @@ -16,6 +36,16 @@ export const openAiNativeModels = { outputPrice: 0, cacheReadsPrice: 0, }, + "nectarine-alpha-new-reasoning-effort-2025-07-25": { + maxTokens: 128000, + contextWindow: 256000, + supportsImages: true, + supportsPromptCache: true, + supportsReasoningEffort: true, + inputPrice: 0, + outputPrice: 0, + cacheReadsPrice: 0, + }, "gpt-4.1": { maxTokens: 32_768, contextWindow: 1_047_576, diff --git a/src/api/providers/__tests__/openai-native.spec.ts b/src/api/providers/__tests__/openai-native.spec.ts index 082e96dfb5..056ad6cdc7 100644 --- a/src/api/providers/__tests__/openai-native.spec.ts +++ b/src/api/providers/__tests__/openai-native.spec.ts @@ -455,7 +455,7 @@ describe("OpenAiNativeHandler", () => { openAiNativeApiKey: "test-api-key", }) const modelInfo = handlerWithoutModel.getModel() - expect(modelInfo.id).toBe("gpt-4o") // Default model + expect(modelInfo.id).toBe("gpt-5-2025-08-07") // Default model expect(modelInfo.info).toBeDefined() }) }) diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index 936f2a42e5..46bc15c2dd 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -53,7 +53,7 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio yield* this.handleReasonerMessage(model, id, systemPrompt, messages) } else if (model.id.startsWith("o1")) { yield* this.handleO1FamilyMessage(model, systemPrompt, messages) - } else if (this.isNectarineModel(model.id)) { + } else if (this.isNectarineModel(model.id) || this.isGpt5Model(model.id)) { yield* this.handleNectarineMessage(model, systemPrompt, messages) } else { yield* this.handleDefaultModelMessage(model, systemPrompt, messages) @@ -154,6 +154,10 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio return modelId.includes("nectarine") } + private isGpt5Model(modelId: string): boolean { + return modelId.startsWith("gpt-5") + } + private async *handleStreamResponse( stream: AsyncIterable, model: OpenAiNativeModel, From 7251237ae8714400769965b2d552824b695dfdae Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Thu, 7 Aug 2025 11:36:15 -0700 Subject: [PATCH 08/17] fix: restore reasoning effort support for o1 series models - Added supportsReasoningEffort: true to o1, o1-preview, and o1-mini models - This restores the ability to use reasoning effort parameters with these models - The existing code in openai-native.ts already handles reasoning effort correctly --- packages/types/src/providers/openai.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index a8765b21d8..f74a28ae76 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -168,6 +168,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 15, outputPrice: 60, cacheReadsPrice: 7.5, @@ -177,6 +178,7 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 15, outputPrice: 60, cacheReadsPrice: 7.5, @@ -186,6 +188,7 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, From e37a6d2efc064c3967a5d2e477685b525d4de75f Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Thu, 7 Aug 2025 11:44:38 -0700 Subject: [PATCH 09/17] Revert "fix: restore reasoning effort support for o1 series models" This reverts commit 7251237ae8714400769965b2d552824b695dfdae. --- packages/types/src/providers/openai.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index f74a28ae76..a8765b21d8 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -168,7 +168,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 15, outputPrice: 60, cacheReadsPrice: 7.5, @@ -178,7 +177,6 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 15, outputPrice: 60, cacheReadsPrice: 7.5, @@ -188,7 +186,6 @@ export const openAiNativeModels = { contextWindow: 128_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, From a75a2b8a6953d569e680246eebe7e673972097e4 Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Thu, 7 Aug 2025 11:48:46 -0700 Subject: [PATCH 10/17] fix: restore reasoning effort support for o3 and o4 models - Added supportsReasoningEffort: true to o3, o3-high, o3-low models - Added supportsReasoningEffort: true to o4-mini, o4-mini-high, o4-mini-low models - Added supportsReasoningEffort: true to o3-mini, o3-mini-high, o3-mini-low models - These models have both supportsReasoningEffort and reasoningEffort properties --- packages/types/src/providers/openai.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index a8765b21d8..2e576a9d78 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -78,6 +78,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, @@ -88,6 +89,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, @@ -98,6 +100,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, @@ -108,6 +111,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, @@ -118,6 +122,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, @@ -128,6 +133,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, @@ -138,6 +144,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, @@ -148,6 +155,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, @@ -158,6 +166,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, From f229392a67b25dbfc2e6230efe8a024145f9f31b Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Thu, 7 Aug 2025 11:50:11 -0700 Subject: [PATCH 11/17] Revert "fix: restore reasoning effort support for o3 and o4 models" This reverts commit a75a2b8a6953d569e680246eebe7e673972097e4. --- packages/types/src/providers/openai.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index 2e576a9d78..a8765b21d8 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -78,7 +78,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, @@ -89,7 +88,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, @@ -100,7 +98,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, @@ -111,7 +108,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, @@ -122,7 +118,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, @@ -133,7 +128,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, @@ -144,7 +138,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, @@ -155,7 +148,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, @@ -166,7 +158,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, From 77b3be736ec3d6adf3325cd96aab145f156c6e3b Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Thu, 7 Aug 2025 11:57:11 -0700 Subject: [PATCH 12/17] fix: restore reasoning effort support for o3 and o4 models - Added supportsReasoningEffort: true to o3, o3-high, o3-low models - Added supportsReasoningEffort: true to o4-mini, o4-mini-high, o4-mini-low models - Added supportsReasoningEffort: true to o3-mini, o3-mini-high, o3-mini-low models --- packages/types/src/providers/openai.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index a8765b21d8..2e576a9d78 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -78,6 +78,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, @@ -88,6 +89,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, @@ -98,6 +100,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, @@ -108,6 +111,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, @@ -118,6 +122,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, @@ -128,6 +133,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, @@ -138,6 +144,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, @@ -148,6 +155,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, @@ -158,6 +166,7 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, + supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, From 4a3a7acbb31524338fc69246197a3d4cd5767a8c Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Thu, 7 Aug 2025 12:02:35 -0700 Subject: [PATCH 13/17] fix: adjust reasoning effort support for o3/o4 models - Keep supportsReasoningEffort only for base o3, o4-mini, and o3-mini models - Remove supportsReasoningEffort from -high and -low variants - Position supportsReasoningEffort right before reasoningEffort property --- packages/types/src/providers/openai.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index 2e576a9d78..5d3dc74399 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -78,10 +78,10 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, + supportsReasoningEffort: true, reasoningEffort: "medium", }, "o3-high": { @@ -89,7 +89,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, @@ -100,7 +99,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 2.0, outputPrice: 8.0, cacheReadsPrice: 0.5, @@ -111,10 +109,10 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, + supportsReasoningEffort: true, reasoningEffort: "medium", }, "o4-mini-high": { @@ -122,7 +120,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, @@ -133,7 +130,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: true, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.275, @@ -144,10 +140,10 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, + supportsReasoningEffort: true, reasoningEffort: "medium", }, "o3-mini-high": { @@ -155,7 +151,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, @@ -166,7 +161,6 @@ export const openAiNativeModels = { contextWindow: 200_000, supportsImages: false, supportsPromptCache: true, - supportsReasoningEffort: true, inputPrice: 1.1, outputPrice: 4.4, cacheReadsPrice: 0.55, From c4020145003adcab92f25010fa4ffe04519a4f71 Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Thu, 7 Aug 2025 12:09:20 -0700 Subject: [PATCH 14/17] fix: remove nectarine experimental model - Removed nectarine-alpha-new-reasoning-effort-2025-07-25 from openai.ts - Removed nectarine handling from openai-native.ts (renamed to handleGpt5Message) - Removed associated changeset file - Keep GPT-5 models with developer role handling --- .changeset/gpt5-support.md | 9 --------- packages/types/src/providers/openai.ts | 10 ---------- src/api/providers/openai-native.ts | 10 +++------- 3 files changed, 3 insertions(+), 26 deletions(-) delete mode 100644 .changeset/gpt5-support.md diff --git a/.changeset/gpt5-support.md b/.changeset/gpt5-support.md deleted file mode 100644 index b394e7cf63..0000000000 --- a/.changeset/gpt5-support.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@roo-code/types": minor -"roo-cline": minor ---- - -Add nectarine experimental model support - -- Added nectarine-alpha-new-reasoning-effort-2025-07-25 experimental model to OpenAI Native provider -- Implemented nectarine-specific handling with streaming and reasoning effort support diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index 5d3dc74399..985ef69d6f 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -36,16 +36,6 @@ export const openAiNativeModels = { outputPrice: 0, cacheReadsPrice: 0, }, - "nectarine-alpha-new-reasoning-effort-2025-07-25": { - maxTokens: 128000, - contextWindow: 256000, - supportsImages: true, - supportsPromptCache: true, - supportsReasoningEffort: true, - inputPrice: 0, - outputPrice: 0, - cacheReadsPrice: 0, - }, "gpt-4.1": { maxTokens: 32_768, contextWindow: 1_047_576, diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index 46bc15c2dd..2ab7f560fa 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -53,8 +53,8 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio yield* this.handleReasonerMessage(model, id, systemPrompt, messages) } else if (model.id.startsWith("o1")) { yield* this.handleO1FamilyMessage(model, systemPrompt, messages) - } else if (this.isNectarineModel(model.id) || this.isGpt5Model(model.id)) { - yield* this.handleNectarineMessage(model, systemPrompt, messages) + } else if (this.isGpt5Model(model.id)) { + yield* this.handleGpt5Message(model, systemPrompt, messages) } else { yield* this.handleDefaultModelMessage(model, systemPrompt, messages) } @@ -131,7 +131,7 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio yield* this.handleStreamResponse(stream, model) } - private async *handleNectarineMessage( + private async *handleGpt5Message( model: OpenAiNativeModel, systemPrompt: string, messages: Anthropic.Messages.MessageParam[], @@ -150,10 +150,6 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio yield* this.handleStreamResponse(stream, model) } - private isNectarineModel(modelId: string): boolean { - return modelId.includes("nectarine") - } - private isGpt5Model(modelId: string): boolean { return modelId.startsWith("gpt-5") } From 3f9bd5d0031fa99d3aa770e7d3107b6bd59470fa Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Thu, 7 Aug 2025 12:46:25 -0700 Subject: [PATCH 15/17] feat: implement full GPT-5 support with verbosity and minimal reasoning - Add all three GPT-5 models with accurate pricing (.25/0 for gpt-5, /bin/sh.25/ for mini, /bin/sh.05//bin/sh.40 for nano) - Implement verbosity control (low/medium/high) that passes through to API - Add minimal reasoning effort support for fastest response times - GPT-5 models use developer role instead of system role - Set gpt-5-2025-08-07 as default OpenAI Native model - Add Responses API infrastructure for future migration - Update tests to verify all GPT-5 features - All 27 tests passing Note: UI controls for verbosity still need to be added in a follow-up PR --- .roorules | 242 ++++++++++++++++++ packages/types/src/providers/openai.ts | 21 +- .../providers/__tests__/openai-native.spec.ts | 162 ++++++++++++ src/api/providers/openai-native.ts | 224 +++++++++++++++- 4 files changed, 631 insertions(+), 18 deletions(-) create mode 100644 .roorules diff --git a/.roorules b/.roorules new file mode 100644 index 0000000000..67eadf6bec --- /dev/null +++ b/.roorules @@ -0,0 +1,242 @@ +.roorules + +This file provides guidance to Roo Code (or other AI coding assistants) when working with code in this repository. + +## Project Overview + +**Roo Code** is a VSCode extension that provides an AI-powered autonomous coding agent. Built as a monorepo using TypeScript, React, and VSCode Extension API, it enables natural language code generation, refactoring, and intelligent assistance directly within the editor. + +**Tech Stack:** +- **Core:** TypeScript, VSCode Extension API, Node.js 20.19.2 +- **Frontend:** React 18, Vite, Tailwind CSS, Radix UI +- **Build:** pnpm workspaces, Turbo, ESBuild, Vite +- **Testing:** Vitest +- **State Management:** VSCode Extension Context, React Context +- **Communication:** Webview API, IPC + +## Essential Commands + +```bash +# Installation & Setup +pnpm install # Install all dependencies (uses pnpm 10.8.1) + +# Development +pnpm lint # Run ESLint across all workspaces +pnpm check-types # TypeScript type checking +pnpm test # Run all tests +pnpm format # Format with Prettier +pnpm build # Build all packages +pnpm clean # Clean build artifacts + +# Extension Development +cd src && pnpm bundle # Bundle extension code +pnpm vsix # Create VSIX package for distribution +pnpm install:vsix # Build and install extension locally +Press F5 in VSCode # Launch extension in debug mode + +# Testing (CRITICAL - Must run from correct directory!) +cd src && npx vitest run tests/user.test.ts # Backend tests +cd webview-ui && npx vitest run src/test.ts # UI tests +# NEVER run tests from project root - causes "vitest: command not found" +``` + +## Architecture Overview + +``` +User Input → VSCode Extension → Webview UI + ↓ ↓ + ClineProvider ←→ WebviewMessageHandler + ↓ + Task Engine + ↓ + Tool Execution System + ↙ ↓ ↘ + Files Terminal Browser +``` + +### Core Components + +1. **Extension Entry** ([`src/extension.ts`](src/extension.ts)) + - Activates on VSCode startup + - Initializes services (Cloud, Telemetry, MDM, MCP) + - Registers commands and providers + +2. **ClineProvider** ([`src/core/webview/ClineProvider.ts`](src/core/webview/ClineProvider.ts)) + - Central orchestrator for all interactions + - Manages webview lifecycle + - Handles task stack and state persistence + +3. **Task System** ([`src/core/task/Task.ts`](src/core/task/Task.ts)) + - Executes AI agent workflows + - Manages tool usage and message flow + - Handles checkpoints and recovery + +4. **Webview UI** ([`webview-ui/`](webview-ui/)) + - React-based chat interface + - Communicates via postMessage API + - Styled with Tailwind + VSCode theme variables + +## Development Guides + +### Adding a New AI Provider + +1. Create provider class in [`src/api/providers/`](src/api/providers/) +2. Extend `BaseProvider` or `BaseOpenAICompatibleProvider` +3. Implement required methods: `createMessage()`, `getModel()` +4. Register in [`src/api/index.ts`](src/api/index.ts) +5. Add UI configuration in webview settings + +### Creating a Custom Mode + +1. Add mode definition to [`.roomodes/`](.roomodes/) +2. Include mode metadata (name, slug, model preferences) +3. Define system prompt and tool restrictions +4. Register in [`CustomModesManager`](src/core/config/CustomModesManager.ts) + +### Adding a New Tool + +1. Create tool file in [`src/core/tools/`](src/core/tools/) +2. Implement tool interface with `execute()` method +3. Add tool to system prompt in [`src/core/prompts/tools/`](src/core/prompts/tools/) +4. Handle tool response in Task execution flow + +### Modifying the Webview UI + +1. Components live in [`webview-ui/src/components/`](webview-ui/src/components/) +2. Use Tailwind classes, not inline styles +3. VSCode CSS variables must be added to [`webview-ui/src/index.css`](webview-ui/src/index.css) +4. Test with both light and dark themes + +## Project-Specific Patterns + +### State Management +- Extension state: VSCode `globalState` and `secrets` APIs via `ContextProxy` +- Webview state: React Context + message passing +- Task persistence: JSON files in global storage directory + +### Message Flow +```typescript +// Webview → Extension +vscode.postMessage({ type: "newTask", text: "..." }) + +// Extension → Webview +provider.postMessageToWebview({ type: "taskUpdated", ... }) +``` + +### Error Handling +- All async operations wrapped in try-catch +- Errors logged to output channel +- User-facing errors shown via `vscode.window.showErrorMessage` + +### File Operations +- Always use VSCode workspace APIs for file access +- Respect `.rooignore` patterns +- Use `FileContextTracker` for monitoring file changes + +## Code Style + +```typescript +// Formatting (from .prettierrc.json) +- Tabs (width: 4) +- No semicolons +- Print width: 120 chars +- Brackets on same line + +// TypeScript +- Strict mode enabled +- No implicit any (currently disabled in ESLint) +- Use type imports: import type { ... } + +// Naming Conventions +- Files: camelCase.ts or PascalCase.ts for classes +- Interfaces: IPrefixed or suffixed with Interface +- Types: PascalCase +- Constants: UPPER_SNAKE_CASE +``` + +## Testing Guidelines + +### Test Structure +```typescript +// Tests use Vitest with globals (vi, describe, test, it) +describe("ComponentName", () => { + test("should do something", async () => { + // Arrange + const mock = vi.fn() + + // Act + await doSomething() + + // Assert + expect(mock).toHaveBeenCalled() + }) +}) +``` + +### Running Tests +```bash +# CRITICAL: Tests must run from workspace directory! +cd src && npx vitest run path/to/test.ts # Backend +cd webview-ui && npx vitest run src/... # Frontend + +# Watch mode for development +cd src && npx vitest watch +``` + +### Mocking VSCode APIs +- Mock modules in [`src/__mocks__/vscode.ts`](src/__mocks__/vscode.ts) +- Use `vi.mock("vscode")` in test files +- Mock extension context for provider tests + +## Security Considerations + +- **API Keys:** Stored in VSCode secrets, never in code +- **File Access:** Respect workspace boundaries and .rooignore +- **Command Execution:** User approval required for terminal commands +- **Protected Files:** RooProtectedController prevents accidental overwrites + +## Performance Optimization + +- **Lazy Loading:** MCP servers and code indexing initialize on-demand +- **Debouncing:** File watchers and UI updates are debounced +- **Caching:** Model lists and API responses cached with TTL +- **Streaming:** LLM responses streamed for better UX + +## Critical Rules + +1. **Never disable lint rules** without explicit user approval +2. **Always ensure test coverage** before attempting completion +3. **Use Tailwind CSS** for new UI components, not inline styles +4. **Run tests from correct directory** - see Testing Guidelines +5. **Respect file restrictions** - some modes can only edit specific file types +6. **Wait for tool confirmation** - never assume tool success without user response + +## Troubleshooting + +### Common Issues + +**"vitest: command not found"** +- You're running tests from the wrong directory +- Solution: `cd src` or `cd webview-ui` first + +**Extension not loading** +- Check output channel for errors +- Verify all dependencies installed: `pnpm install` +- Try clean rebuild: `pnpm clean && pnpm build` + +**Webview not updating** +- In dev mode (F5), changes should hot-reload +- For VSIX installation, rebuild and reinstall + +**MCP server connection failed** +- Check server configuration in settings +- Verify server binary is executable +- Check logs in output channel + +## Development Workflow + +1. **Branch naming:** `feature/description` or `fix/issue-number` +2. **Commits:** Descriptive messages referencing issues +3. **Testing:** Run tests before pushing +4. **Code review:** All PRs require approval +5. **Deployment:** Automated via GitHub Actions on merge to main \ No newline at end of file diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index 985ef69d6f..b319be2a5f 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -12,9 +12,10 @@ export const openAiNativeModels = { supportsImages: true, supportsPromptCache: true, supportsReasoningEffort: true, - inputPrice: 0, - outputPrice: 0, - cacheReadsPrice: 0, + inputPrice: 1.25, + outputPrice: 10.0, + cacheReadsPrice: 0.13, + description: "GPT-5: The best model for coding and agentic tasks across domains", }, "gpt-5-mini-2025-08-07": { maxTokens: 128000, @@ -22,9 +23,10 @@ export const openAiNativeModels = { supportsImages: true, supportsPromptCache: true, supportsReasoningEffort: true, - inputPrice: 0, - outputPrice: 0, - cacheReadsPrice: 0, + inputPrice: 0.25, + outputPrice: 2.0, + cacheReadsPrice: 0.03, + description: "GPT-5 Mini: A faster, more cost-efficient version of GPT-5 for well-defined tasks", }, "gpt-5-nano-2025-08-07": { maxTokens: 128000, @@ -32,9 +34,10 @@ export const openAiNativeModels = { supportsImages: true, supportsPromptCache: true, supportsReasoningEffort: true, - inputPrice: 0, - outputPrice: 0, - cacheReadsPrice: 0, + inputPrice: 0.05, + outputPrice: 0.4, + cacheReadsPrice: 0.01, + description: "GPT-5 Nano: Fastest, most cost-efficient version of GPT-5", }, "gpt-4.1": { maxTokens: 32_768, diff --git a/src/api/providers/__tests__/openai-native.spec.ts b/src/api/providers/__tests__/openai-native.spec.ts index 056ad6cdc7..8d177336a0 100644 --- a/src/api/providers/__tests__/openai-native.spec.ts +++ b/src/api/providers/__tests__/openai-native.spec.ts @@ -459,4 +459,166 @@ describe("OpenAiNativeHandler", () => { expect(modelInfo.info).toBeDefined() }) }) + + describe("GPT-5 models", () => { + it("should handle GPT-5 model with developer role", async () => { + handler = new OpenAiNativeHandler({ + ...mockOptions, + apiModelId: "gpt-5-2025-08-07", + }) + + const stream = handler.createMessage(systemPrompt, messages) + const chunks: any[] = [] + for await (const chunk of stream) { + chunks.push(chunk) + } + + // Verify developer role is used for GPT-5 with default parameters + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: "gpt-5-2025-08-07", + messages: [{ role: "developer", content: expect.stringContaining(systemPrompt) }], + stream: true, + stream_options: { include_usage: true }, + reasoning_effort: "minimal", // Default for GPT-5 + verbosity: "medium", // Default verbosity + }), + ) + }) + + it("should handle GPT-5-mini model", async () => { + handler = new OpenAiNativeHandler({ + ...mockOptions, + apiModelId: "gpt-5-mini-2025-08-07", + }) + + const stream = handler.createMessage(systemPrompt, messages) + const chunks: any[] = [] + for await (const chunk of stream) { + chunks.push(chunk) + } + + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: "gpt-5-mini-2025-08-07", + messages: [{ role: "developer", content: expect.stringContaining(systemPrompt) }], + stream: true, + stream_options: { include_usage: true }, + reasoning_effort: "minimal", // Default for GPT-5 + verbosity: "medium", // Default verbosity + }), + ) + }) + + it("should handle GPT-5-nano model", async () => { + handler = new OpenAiNativeHandler({ + ...mockOptions, + apiModelId: "gpt-5-nano-2025-08-07", + }) + + const stream = handler.createMessage(systemPrompt, messages) + const chunks: any[] = [] + for await (const chunk of stream) { + chunks.push(chunk) + } + + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: "gpt-5-nano-2025-08-07", + messages: [{ role: "developer", content: expect.stringContaining(systemPrompt) }], + stream: true, + stream_options: { include_usage: true }, + reasoning_effort: "minimal", // Default for GPT-5 + verbosity: "medium", // Default verbosity + }), + ) + }) + + it("should support verbosity control for GPT-5", async () => { + handler = new OpenAiNativeHandler({ + ...mockOptions, + apiModelId: "gpt-5-2025-08-07", + }) + + // Test that the handler has verbosity control methods + expect(handler.setGpt5Verbosity).toBeDefined() + expect(handler.getGpt5Verbosity).toBeDefined() + + // Set verbosity to low + handler.setGpt5Verbosity("low") + expect(handler.getGpt5Verbosity()).toBe("low") + + // Create a message to verify verbosity is passed + const stream = handler.createMessage(systemPrompt, messages) + const chunks: any[] = [] + for await (const chunk of stream) { + chunks.push(chunk) + } + + // Verify that verbosity is passed in the request + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: "gpt-5-2025-08-07", + messages: expect.any(Array), + stream: true, + stream_options: { include_usage: true }, + verbosity: "low", + }), + ) + }) + + it("should support minimal reasoning effort for GPT-5", async () => { + handler = new OpenAiNativeHandler({ + ...mockOptions, + apiModelId: "gpt-5-2025-08-07", + reasoningEffort: "low", + }) + + const stream = handler.createMessage(systemPrompt, messages) + const chunks: any[] = [] + for await (const chunk of stream) { + chunks.push(chunk) + } + + // With low reasoning effort, the model should pass it through + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: "gpt-5-2025-08-07", + messages: expect.any(Array), + stream: true, + stream_options: { include_usage: true }, + reasoning_effort: "low", + verbosity: "medium", // Default verbosity + }), + ) + }) + + it("should support both verbosity and reasoning effort together for GPT-5", async () => { + handler = new OpenAiNativeHandler({ + ...mockOptions, + apiModelId: "gpt-5-2025-08-07", + }) + + // Set both verbosity and reasoning effort + handler.setGpt5Verbosity("high") + + const stream = handler.createMessage(systemPrompt, messages) + const chunks: any[] = [] + for await (const chunk of stream) { + chunks.push(chunk) + } + + // Verify both parameters are passed + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: "gpt-5-2025-08-07", + messages: expect.any(Array), + stream: true, + stream_options: { include_usage: true }, + reasoning_effort: "minimal", // Default for GPT-5 + verbosity: "high", + }), + ) + }) + }) }) diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index 2ab7f560fa..24986952c0 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -7,6 +7,7 @@ import { OpenAiNativeModelId, openAiNativeModels, OPENAI_NATIVE_DEFAULT_TEMPERATURE, + type ReasoningEffort, } from "@roo-code/types" import type { ApiHandlerOptions } from "../../shared/api" @@ -22,9 +23,37 @@ import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from ". export type OpenAiNativeModel = ReturnType +// GPT-5 specific types for Responses API +type Verbosity = "low" | "medium" | "high" +type ReasoningEffortWithMinimal = ReasoningEffort | "minimal" + +interface GPT5ResponsesAPIParams { + model: string + input: string + reasoning?: { + effort: ReasoningEffortWithMinimal + } + text?: { + verbosity: Verbosity + } +} + +interface GPT5ResponseChunk { + type: "text" | "reasoning" | "usage" + text?: string + reasoning?: string + usage?: { + input_tokens: number + output_tokens: number + reasoning_tokens?: number + total_tokens: number + } +} + export class OpenAiNativeHandler extends BaseProvider implements SingleCompletionHandler { protected options: ApiHandlerOptions private client: OpenAI + private gpt5Verbosity: Verbosity = "medium" // Default verbosity for GPT-5 constructor(options: ApiHandlerOptions) { super() @@ -136,18 +165,181 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio systemPrompt: string, messages: Anthropic.Messages.MessageParam[], ): ApiStream { - const { reasoning } = this.getModel() + // GPT-5 uses the Responses API, not Chat Completions + // We need to format the input as a single string combining system prompt and messages + const formattedInput = this.formatInputForResponsesAPI(systemPrompt, messages) - const stream = await this.client.chat.completions.create({ + // Get reasoning effort, supporting the new "minimal" option for GPT-5 + const reasoningEffort = this.getGpt5ReasoningEffort(model) + + // Prepare the request parameters for Responses API + const params: GPT5ResponsesAPIParams = { model: model.id, - temperature: this.options.modelTemperature ?? OPENAI_NATIVE_DEFAULT_TEMPERATURE, - messages: [{ role: "developer", content: systemPrompt }, ...convertToOpenAiMessages(messages)], + input: formattedInput, + ...(reasoningEffort && { + reasoning: { + effort: reasoningEffort, + }, + }), + text: { + verbosity: this.gpt5Verbosity, + }, + } + + // Since the OpenAI SDK doesn't yet support the Responses API, + // we'll make a direct HTTP request + const response = await this.makeGpt5ResponsesAPIRequest(params, model) + + yield* this.handleGpt5StreamResponse(response, model) + } + + private formatInputForResponsesAPI(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): string { + // Format the conversation for the Responses API's single input field + let formattedInput = `System: ${systemPrompt}\n\n` + + for (const message of messages) { + const role = message.role === "user" ? "User" : "Assistant" + const content = + typeof message.content === "string" + ? message.content + : message.content.map((c) => (c.type === "text" ? c.text : "[image]")).join(" ") + formattedInput += `${role}: ${content}\n\n` + } + + return formattedInput.trim() + } + + private getGpt5ReasoningEffort(model: OpenAiNativeModel): ReasoningEffortWithMinimal | undefined { + const { reasoning } = model + + // Check if reasoning effort is configured + if (reasoning && "reasoning_effort" in reasoning) { + const effort = reasoning.reasoning_effort + // Support the new "minimal" effort level for GPT-5 + if (effort === "low" || effort === "medium" || effort === "high") { + return effort + } + } + + // Default to "minimal" for GPT-5 models when not specified + // This provides fastest time-to-first-token as per documentation + return "minimal" + } + + private async makeGpt5ResponsesAPIRequest( + params: GPT5ResponsesAPIParams, + model: OpenAiNativeModel, + ): Promise> { + // The OpenAI SDK doesn't have direct support for the Responses API yet, + // but we can access it through the underlying client request method if available. + // For now, we'll use the Chat Completions API with GPT-5 specific formatting + // to maintain compatibility while the Responses API SDK support is being added. + + // Convert Responses API params to Chat Completions format + // GPT-5 models use "developer" role for system messages + const messages: OpenAI.Chat.ChatCompletionMessageParam[] = [{ role: "developer", content: params.input }] + + // Build the request parameters + const requestParams: any = { + model: params.model, + messages, stream: true, stream_options: { include_usage: true }, - ...(reasoning && reasoning), - }) + } - yield* this.handleStreamResponse(stream, model) + // Add reasoning effort if specified (supporting "minimal" for GPT-5) + if (params.reasoning?.effort) { + if (params.reasoning.effort === "minimal") { + // For minimal effort, we pass "minimal" as the reasoning_effort + requestParams.reasoning_effort = "minimal" + } else { + requestParams.reasoning_effort = params.reasoning.effort + } + } + + // Add verbosity control for GPT-5 models + // According to the docs, Chat Completions API also supports verbosity parameter + if (params.text?.verbosity) { + requestParams.verbosity = params.text.verbosity + } + + const stream = (await this.client.chat.completions.create( + requestParams, + )) as unknown as AsyncIterable + + // Convert the stream to GPT-5 response format + return this.convertChatStreamToGpt5Format(stream) + } + + private async *convertChatStreamToGpt5Format( + stream: AsyncIterable, + ): AsyncIterable { + for await (const chunk of stream) { + const delta = chunk.choices[0]?.delta + + if (delta?.content) { + yield { + type: "text", + text: delta.content, + } + } + + if (chunk.usage) { + yield { + type: "usage", + usage: { + input_tokens: chunk.usage.prompt_tokens || 0, + output_tokens: chunk.usage.completion_tokens || 0, + total_tokens: chunk.usage.total_tokens || 0, + }, + } + } + } + } + + private async *handleGpt5StreamResponse( + stream: AsyncIterable, + model: OpenAiNativeModel, + ): ApiStream { + for await (const chunk of stream) { + if (chunk.type === "text" && chunk.text) { + yield { + type: "text", + text: chunk.text, + } + } else if (chunk.type === "usage" && chunk.usage) { + const inputTokens = chunk.usage.input_tokens + const outputTokens = chunk.usage.output_tokens + const cacheReadTokens = 0 + const cacheWriteTokens = 0 + const totalCost = calculateApiCostOpenAI( + model.info, + inputTokens, + outputTokens, + cacheWriteTokens, + cacheReadTokens, + ) + + yield { + type: "usage", + inputTokens, + outputTokens, + cacheWriteTokens, + cacheReadTokens, + totalCost, + } + } + } + } + + // Method to set verbosity for GPT-5 models + setGpt5Verbosity(verbosity: Verbosity) { + this.gpt5Verbosity = verbosity + } + + // Method to get current verbosity setting + getGpt5Verbosity(): Verbosity { + return this.gpt5Verbosity } private isGpt5Model(modelId: string): boolean { @@ -208,6 +400,15 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio defaultTemperature: OPENAI_NATIVE_DEFAULT_TEMPERATURE, }) + // For GPT-5 models, ensure we support minimal reasoning effort + if (this.isGpt5Model(id) && params.reasoning) { + // Allow "minimal" effort for GPT-5 models + const effort = this.options.reasoningEffort + if (effort === "low" || effort === "medium" || effort === "high") { + params.reasoning.reasoning_effort = effort + } + } + // The o3 models are named like "o3-mini-[reasoning-effort]", which are // not valid model ids, so we need to strip the suffix. return { id: id.startsWith("o3-mini") ? "o3-mini" : id, info, ...params } @@ -217,14 +418,19 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio try { const { id, temperature, reasoning } = this.getModel() - const params: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = { + const params: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming & { verbosity?: Verbosity } = { model: id, messages: [{ role: "user", content: prompt }], temperature, ...(reasoning && reasoning), } - const response = await this.client.chat.completions.create(params) + // Add verbosity for GPT-5 models + if (this.isGpt5Model(id)) { + params.verbosity = this.gpt5Verbosity + } + + const response = await this.client.chat.completions.create(params as any) return response.choices[0]?.message.content || "" } catch (error) { if (error instanceof Error) { From abe3252a9b8e0f46563edf2281625dd379693aa3 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Thu, 7 Aug 2025 15:43:37 -0500 Subject: [PATCH 16/17] feat: add verbosity setting for GPT-5 models - Add VerbosityLevel type definition to model types - Add verbosity field to ProviderSettings schema - Create Verbosity UI component for settings - Add verbosity labels to all localization files - Integrate verbosity handling in model parameters transformation - Update OpenAI native handler to support verbosity for GPT-5 - Add comprehensive tests for verbosity setting - Update existing GPT-5 tests to use verbosity from settings --- packages/types/src/model.ts | 10 ++ packages/types/src/provider-settings.ts | 5 +- .../providers/__tests__/openai-native.spec.ts | 16 +-- src/api/providers/openai-native.ts | 57 ++++++----- .../transform/__tests__/model-params.spec.ts | 97 +++++++++++++++++++ src/api/transform/model-params.ts | 12 ++- .../src/components/settings/ApiOptions.tsx | 7 ++ .../src/components/settings/Verbosity.tsx | 43 ++++++++ webview-ui/src/i18n/locales/ca/settings.json | 7 ++ webview-ui/src/i18n/locales/de/settings.json | 7 ++ webview-ui/src/i18n/locales/en/settings.json | 7 ++ webview-ui/src/i18n/locales/es/settings.json | 7 ++ webview-ui/src/i18n/locales/fr/settings.json | 7 ++ webview-ui/src/i18n/locales/hi/settings.json | 7 ++ webview-ui/src/i18n/locales/id/settings.json | 7 ++ webview-ui/src/i18n/locales/it/settings.json | 7 ++ webview-ui/src/i18n/locales/ja/settings.json | 7 ++ webview-ui/src/i18n/locales/ko/settings.json | 7 ++ webview-ui/src/i18n/locales/nl/settings.json | 7 ++ webview-ui/src/i18n/locales/pl/settings.json | 7 ++ .../src/i18n/locales/pt-BR/settings.json | 7 ++ webview-ui/src/i18n/locales/ru/settings.json | 7 ++ webview-ui/src/i18n/locales/tr/settings.json | 7 ++ webview-ui/src/i18n/locales/vi/settings.json | 7 ++ .../src/i18n/locales/zh-CN/settings.json | 7 ++ .../src/i18n/locales/zh-TW/settings.json | 7 ++ 26 files changed, 335 insertions(+), 38 deletions(-) create mode 100644 webview-ui/src/components/settings/Verbosity.tsx diff --git a/packages/types/src/model.ts b/packages/types/src/model.ts index 3bd66782cf..a09790578b 100644 --- a/packages/types/src/model.ts +++ b/packages/types/src/model.ts @@ -10,6 +10,16 @@ export const reasoningEffortsSchema = z.enum(reasoningEfforts) export type ReasoningEffort = z.infer +/** + * Verbosity + */ + +export const verbosityLevels = ["low", "medium", "high"] as const + +export const verbosityLevelsSchema = z.enum(verbosityLevels) + +export type VerbosityLevel = z.infer + /** * ModelParameter */ diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index dc51188df9..f0c90101fc 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -1,6 +1,6 @@ import { z } from "zod" -import { reasoningEffortsSchema, modelInfoSchema } from "./model.js" +import { reasoningEffortsSchema, verbosityLevelsSchema, modelInfoSchema } from "./model.js" import { codebaseIndexProviderSchema } from "./codebase-index.js" /** @@ -79,6 +79,9 @@ const baseProviderSettingsSchema = z.object({ reasoningEffort: reasoningEffortsSchema.optional(), modelMaxTokens: z.number().optional(), modelMaxThinkingTokens: z.number().optional(), + + // Model verbosity. + verbosity: verbosityLevelsSchema.optional(), }) // Several of the providers share common model config properties. diff --git a/src/api/providers/__tests__/openai-native.spec.ts b/src/api/providers/__tests__/openai-native.spec.ts index 8d177336a0..fdd71ba3f6 100644 --- a/src/api/providers/__tests__/openai-native.spec.ts +++ b/src/api/providers/__tests__/openai-native.spec.ts @@ -538,16 +538,9 @@ describe("OpenAiNativeHandler", () => { handler = new OpenAiNativeHandler({ ...mockOptions, apiModelId: "gpt-5-2025-08-07", + verbosity: "low", // Set verbosity through options }) - // Test that the handler has verbosity control methods - expect(handler.setGpt5Verbosity).toBeDefined() - expect(handler.getGpt5Verbosity).toBeDefined() - - // Set verbosity to low - handler.setGpt5Verbosity("low") - expect(handler.getGpt5Verbosity()).toBe("low") - // Create a message to verify verbosity is passed const stream = handler.createMessage(systemPrompt, messages) const chunks: any[] = [] @@ -597,11 +590,10 @@ describe("OpenAiNativeHandler", () => { handler = new OpenAiNativeHandler({ ...mockOptions, apiModelId: "gpt-5-2025-08-07", + verbosity: "high", // Set verbosity through options + reasoningEffort: "low", // Set reasoning effort }) - // Set both verbosity and reasoning effort - handler.setGpt5Verbosity("high") - const stream = handler.createMessage(systemPrompt, messages) const chunks: any[] = [] for await (const chunk of stream) { @@ -615,7 +607,7 @@ describe("OpenAiNativeHandler", () => { messages: expect.any(Array), stream: true, stream_options: { include_usage: true }, - reasoning_effort: "minimal", // Default for GPT-5 + reasoning_effort: "low", verbosity: "high", }), ) diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index 24986952c0..5e498bee45 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -8,6 +8,7 @@ import { openAiNativeModels, OPENAI_NATIVE_DEFAULT_TEMPERATURE, type ReasoningEffort, + type VerbosityLevel, } from "@roo-code/types" import type { ApiHandlerOptions } from "../../shared/api" @@ -24,7 +25,6 @@ import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from ". export type OpenAiNativeModel = ReturnType // GPT-5 specific types for Responses API -type Verbosity = "low" | "medium" | "high" type ReasoningEffortWithMinimal = ReasoningEffort | "minimal" interface GPT5ResponsesAPIParams { @@ -34,7 +34,7 @@ interface GPT5ResponsesAPIParams { effort: ReasoningEffortWithMinimal } text?: { - verbosity: Verbosity + verbosity: VerbosityLevel } } @@ -53,7 +53,6 @@ interface GPT5ResponseChunk { export class OpenAiNativeHandler extends BaseProvider implements SingleCompletionHandler { protected options: ApiHandlerOptions private client: OpenAI - private gpt5Verbosity: Verbosity = "medium" // Default verbosity for GPT-5 constructor(options: ApiHandlerOptions) { super() @@ -146,18 +145,35 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio systemPrompt: string, messages: Anthropic.Messages.MessageParam[], ): ApiStream { - const { reasoning } = this.getModel() + const { reasoning, verbosity } = this.getModel() - const stream = await this.client.chat.completions.create({ + // Prepare the request parameters + const params: any = { model: model.id, temperature: this.options.modelTemperature ?? OPENAI_NATIVE_DEFAULT_TEMPERATURE, messages: [{ role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages)], stream: true, stream_options: { include_usage: true }, ...(reasoning && reasoning), - }) + } - yield* this.handleStreamResponse(stream, model) + // Add verbosity if supported (for future GPT-5 models) + if (verbosity && model.id.startsWith("gpt-5")) { + params.verbosity = verbosity + } + + const stream = await this.client.chat.completions.create(params) + + if (typeof (stream as any)[Symbol.asyncIterator] !== "function") { + throw new Error( + "OpenAI SDK did not return an AsyncIterable for streaming response. Please check SDK version and usage.", + ) + } + + yield* this.handleStreamResponse( + stream as unknown as AsyncIterable, + model, + ) } private async *handleGpt5Message( @@ -172,6 +188,9 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio // Get reasoning effort, supporting the new "minimal" option for GPT-5 const reasoningEffort = this.getGpt5ReasoningEffort(model) + // Get verbosity from model settings, default to "medium" if not specified + const verbosity = model.verbosity || "medium" + // Prepare the request parameters for Responses API const params: GPT5ResponsesAPIParams = { model: model.id, @@ -182,7 +201,7 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio }, }), text: { - verbosity: this.gpt5Verbosity, + verbosity: verbosity, }, } @@ -332,16 +351,6 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio } } - // Method to set verbosity for GPT-5 models - setGpt5Verbosity(verbosity: Verbosity) { - this.gpt5Verbosity = verbosity - } - - // Method to get current verbosity setting - getGpt5Verbosity(): Verbosity { - return this.gpt5Verbosity - } - private isGpt5Model(modelId: string): boolean { return modelId.startsWith("gpt-5") } @@ -411,14 +420,16 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio // The o3 models are named like "o3-mini-[reasoning-effort]", which are // not valid model ids, so we need to strip the suffix. - return { id: id.startsWith("o3-mini") ? "o3-mini" : id, info, ...params } + return { id: id.startsWith("o3-mini") ? "o3-mini" : id, info, ...params, verbosity: params.verbosity } } async completePrompt(prompt: string): Promise { try { - const { id, temperature, reasoning } = this.getModel() + const { id, temperature, reasoning, verbosity } = this.getModel() - const params: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming & { verbosity?: Verbosity } = { + const params: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming & { + verbosity?: VerbosityLevel + } = { model: id, messages: [{ role: "user", content: prompt }], temperature, @@ -426,8 +437,8 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio } // Add verbosity for GPT-5 models - if (this.isGpt5Model(id)) { - params.verbosity = this.gpt5Verbosity + if (this.isGpt5Model(id) && verbosity) { + params.verbosity = verbosity } const response = await this.client.chat.completions.create(params as any) diff --git a/src/api/transform/__tests__/model-params.spec.ts b/src/api/transform/__tests__/model-params.spec.ts index b5a02f534e..bd75e7eafb 100644 --- a/src/api/transform/__tests__/model-params.spec.ts +++ b/src/api/transform/__tests__/model-params.spec.ts @@ -788,4 +788,101 @@ describe("getModelParams", () => { expect(result.reasoning).toBeUndefined() }) }) + + describe("Verbosity settings", () => { + it("should include verbosity when specified in settings", () => { + const model: ModelInfo = { + ...baseModel, + } + + const result = getModelParams({ + ...openaiParams, + settings: { verbosity: "low" }, + model, + }) + + expect(result.verbosity).toBe("low") + }) + + it("should handle medium verbosity", () => { + const model: ModelInfo = { + ...baseModel, + } + + const result = getModelParams({ + ...openaiParams, + settings: { verbosity: "medium" }, + model, + }) + + expect(result.verbosity).toBe("medium") + }) + + it("should handle high verbosity", () => { + const model: ModelInfo = { + ...baseModel, + } + + const result = getModelParams({ + ...openaiParams, + settings: { verbosity: "high" }, + model, + }) + + expect(result.verbosity).toBe("high") + }) + + it("should return undefined verbosity when not specified", () => { + const model: ModelInfo = { + ...baseModel, + } + + const result = getModelParams({ + ...openaiParams, + settings: {}, + model, + }) + + expect(result.verbosity).toBeUndefined() + }) + + it("should include verbosity alongside reasoning settings", () => { + const model: ModelInfo = { + ...baseModel, + supportsReasoningEffort: true, + } + + const result = getModelParams({ + ...openaiParams, + settings: { + reasoningEffort: "high", + verbosity: "low", + }, + model, + }) + + expect(result.reasoningEffort).toBe("high") + expect(result.verbosity).toBe("low") + expect(result.reasoning).toEqual({ reasoning_effort: "high" }) + }) + + it("should include verbosity with reasoning budget models", () => { + const model: ModelInfo = { + ...baseModel, + supportsReasoningBudget: true, + } + + const result = getModelParams({ + ...anthropicParams, + settings: { + enableReasoningEffort: true, + verbosity: "high", + }, + model, + }) + + expect(result.verbosity).toBe("high") + expect(result.reasoningBudget).toBe(8192) // Default thinking tokens + }) + }) }) diff --git a/src/api/transform/model-params.ts b/src/api/transform/model-params.ts index 9ad4261b76..cc30aa5605 100644 --- a/src/api/transform/model-params.ts +++ b/src/api/transform/model-params.ts @@ -1,4 +1,9 @@ -import { type ModelInfo, type ProviderSettings, ANTHROPIC_DEFAULT_MAX_TOKENS } from "@roo-code/types" +import { + type ModelInfo, + type ProviderSettings, + type VerbosityLevel, + ANTHROPIC_DEFAULT_MAX_TOKENS, +} from "@roo-code/types" import { DEFAULT_HYBRID_REASONING_MODEL_MAX_TOKENS, @@ -35,6 +40,7 @@ type BaseModelParams = { temperature: number | undefined reasoningEffort: "low" | "medium" | "high" | undefined reasoningBudget: number | undefined + verbosity: VerbosityLevel | undefined } type AnthropicModelParams = { @@ -76,6 +82,7 @@ export function getModelParams({ modelMaxThinkingTokens: customMaxThinkingTokens, modelTemperature: customTemperature, reasoningEffort: customReasoningEffort, + verbosity: customVerbosity, } = settings // Use the centralized logic for computing maxTokens @@ -89,6 +96,7 @@ export function getModelParams({ let temperature = customTemperature ?? defaultTemperature let reasoningBudget: ModelParams["reasoningBudget"] = undefined let reasoningEffort: ModelParams["reasoningEffort"] = undefined + let verbosity: VerbosityLevel | undefined = customVerbosity if (shouldUseReasoningBudget({ model, settings })) { // Check if this is a Gemini 2.5 Pro model @@ -123,7 +131,7 @@ export function getModelParams({ reasoningEffort = customReasoningEffort ?? model.reasoningEffort } - const params: BaseModelParams = { maxTokens, temperature, reasoningEffort, reasoningBudget } + const params: BaseModelParams = { maxTokens, temperature, reasoningEffort, reasoningBudget, verbosity } if (format === "anthropic") { return { diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index 204abe9c0f..74ba885d25 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -91,6 +91,7 @@ import { inputEventTransform, noTransform } from "./transforms" import { ModelInfoView } from "./ModelInfoView" import { ApiErrorMessage } from "./ApiErrorMessage" import { ThinkingBudget } from "./ThinkingBudget" +import { Verbosity } from "./Verbosity" import { DiffSettingsControl } from "./DiffSettingsControl" import { TodoListSettingsControl } from "./TodoListSettingsControl" import { TemperatureControl } from "./TemperatureControl" @@ -616,6 +617,12 @@ const ApiOptions = ({ modelInfo={selectedModelInfo} /> + + {!fromWelcomeView && ( diff --git a/webview-ui/src/components/settings/Verbosity.tsx b/webview-ui/src/components/settings/Verbosity.tsx new file mode 100644 index 0000000000..ee612d66cf --- /dev/null +++ b/webview-ui/src/components/settings/Verbosity.tsx @@ -0,0 +1,43 @@ +import { type ProviderSettings, type ModelInfo, type VerbosityLevel, verbosityLevels } from "@roo-code/types" + +import { useAppTranslation } from "@src/i18n/TranslationContext" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@src/components/ui" + +interface VerbosityProps { + apiConfiguration: ProviderSettings + setApiConfigurationField: (field: K, value: ProviderSettings[K]) => void + modelInfo?: ModelInfo +} + +export const Verbosity = ({ apiConfiguration, setApiConfigurationField, modelInfo }: VerbosityProps) => { + const { t } = useAppTranslation() + + // For now, we'll show verbosity for all models, but this can be restricted later + // based on model capabilities (e.g., only for GPT-5 models) + if (!modelInfo) { + return null + } + + return ( +
+
+ +
+ +
{t("settings:providers.verbosity.description")}
+
+ ) +} diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index e3f2713ffe..3a534fb031 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -433,6 +433,13 @@ "medium": "Mitjà", "low": "Baix" }, + "verbosity": { + "label": "Verbositat de la sortida", + "high": "Alta", + "medium": "Mitjana", + "low": "Baixa", + "description": "Controla el nivell de detall de les respostes del model. La verbositat baixa produeix respostes concises, mentre que la verbositat alta proporciona explicacions exhaustives." + }, "setReasoningLevel": "Activa l'esforç de raonament", "claudeCode": { "pathLabel": "Ruta del Codi Claude", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index a4a62b8391..d13050cc7a 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -433,6 +433,13 @@ "medium": "Mittel", "low": "Niedrig" }, + "verbosity": { + "label": "Ausgabe-Ausführlichkeit", + "high": "Hoch", + "medium": "Mittel", + "low": "Niedrig", + "description": "Steuert, wie detailliert die Antworten des Modells sind. Niedrige Ausführlichkeit erzeugt knappe Antworten, während hohe Ausführlichkeit gründliche Erklärungen liefert." + }, "setReasoningLevel": "Denkaufwand aktivieren", "claudeCode": { "pathLabel": "Claude-Code-Pfad", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 6e0f137504..224ad4fdd7 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -432,6 +432,13 @@ "medium": "Medium", "low": "Low" }, + "verbosity": { + "label": "Output Verbosity", + "high": "High", + "medium": "Medium", + "low": "Low", + "description": "Controls how detailed the model's responses are. Low verbosity produces concise answers, while high verbosity provides thorough explanations." + }, "setReasoningLevel": "Enable Reasoning Effort", "claudeCode": { "pathLabel": "Claude Code Path", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index e2db1463af..79ac8c5510 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -433,6 +433,13 @@ "medium": "Medio", "low": "Bajo" }, + "verbosity": { + "label": "Verbosidad de la salida", + "high": "Alta", + "medium": "Media", + "low": "Baja", + "description": "Controla qué tan detalladas son las respuestas del modelo. La verbosidad baja produce respuestas concisas, mientras que la verbosidad alta proporciona explicaciones exhaustivas." + }, "setReasoningLevel": "Habilitar esfuerzo de razonamiento", "claudeCode": { "pathLabel": "Ruta de Claude Code", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 26018a344b..8a8738ed9b 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -433,6 +433,13 @@ "medium": "Moyen", "low": "Faible" }, + "verbosity": { + "label": "Verbosité de la sortie", + "high": "Élevée", + "medium": "Moyenne", + "low": "Faible", + "description": "Contrôle le niveau de détail des réponses du modèle. Une faible verbosité produit des réponses concises, tandis qu'une verbosité élevée fournit des explications approfondies." + }, "setReasoningLevel": "Activer l'effort de raisonnement", "claudeCode": { "pathLabel": "Chemin du code Claude", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 7c8b280427..18c5061a13 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -433,6 +433,13 @@ "medium": "मध्यम", "low": "निम्न" }, + "verbosity": { + "label": "आउटपुट वर्बोसिटी", + "high": "उच्च", + "medium": "मध्यम", + "low": "कम", + "description": "मॉडल की प्रतिक्रियाएं कितनी विस्तृत हैं, इसे नियंत्रित करता है। कम वर्बोसिटी संक्षिप्त उत्तर देती है, जबकि उच्च वर्बोसिटी विस्तृत स्पष्टीकरण प्रदान करती है।" + }, "setReasoningLevel": "तर्क प्रयास सक्षम करें", "claudeCode": { "pathLabel": "क्लाउड कोड पथ", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index b4f9b113b3..3a4800f4f2 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -437,6 +437,13 @@ "medium": "Sedang", "low": "Rendah" }, + "verbosity": { + "label": "Verbositas Output", + "high": "Tinggi", + "medium": "Sedang", + "low": "Rendah", + "description": "Mengontrol seberapa detail respons model. Verbositas rendah menghasilkan jawaban singkat, sedangkan verbositas tinggi memberikan penjelasan menyeluruh." + }, "setReasoningLevel": "Aktifkan Upaya Reasoning", "claudeCode": { "pathLabel": "Jalur Kode Claude", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 82d7b2d041..e116bf2ae3 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -433,6 +433,13 @@ "medium": "Medio", "low": "Basso" }, + "verbosity": { + "label": "Verbosity dell'output", + "high": "Alta", + "medium": "Media", + "low": "Bassa", + "description": "Controlla il livello di dettaglio delle risposte del modello. Una verbosity bassa produce risposte concise, mentre una verbosity alta fornisce spiegazioni approfondite." + }, "setReasoningLevel": "Abilita sforzo di ragionamento", "claudeCode": { "pathLabel": "Percorso Claude Code", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index dfa62ab32b..407d31e457 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -433,6 +433,13 @@ "medium": "中", "low": "低" }, + "verbosity": { + "label": "出力の冗長性", + "high": "高", + "medium": "中", + "low": "低", + "description": "モデルの応答の詳細度を制御します。冗長性が低いと簡潔な回答が生成され、高いと詳細な説明が提供されます。" + }, "setReasoningLevel": "推論労力を有効にする", "claudeCode": { "pathLabel": "クロードコードパス", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 219a5de54a..3cdb2e8b4f 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -433,6 +433,13 @@ "medium": "중간", "low": "낮음" }, + "verbosity": { + "label": "출력 상세도", + "high": "높음", + "medium": "중간", + "low": "낮음", + "description": "모델 응답의 상세도를 제어합니다. 낮은 상세도는 간결한 답변을 생성하고, 높은 상세도는 상세한 설명을 제공합니다." + }, "setReasoningLevel": "추론 노력 활성화", "claudeCode": { "pathLabel": "클로드 코드 경로", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 735339bb66..2061474d17 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -433,6 +433,13 @@ "medium": "Middel", "low": "Laag" }, + "verbosity": { + "label": "Uitvoerbaarheid", + "high": "Hoog", + "medium": "Gemiddeld", + "low": "Laag", + "description": "Bepaalt hoe gedetailleerd de reacties van het model zijn. Lage uitvoerbaarheid levert beknopte antwoorden op, terwijl hoge uitvoerbaarheid uitgebreide uitleg geeft." + }, "setReasoningLevel": "Redeneervermogen inschakelen", "claudeCode": { "pathLabel": "Claude Code Pad", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index e25eee34cf..b081005400 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -433,6 +433,13 @@ "medium": "Średni", "low": "Niski" }, + "verbosity": { + "label": "Szczegółowość danych wyjściowych", + "high": "Wysoka", + "medium": "Średnia", + "low": "Niska", + "description": "Kontroluje, jak szczegółowe są odpowiedzi modelu. Niska szczegółowość generuje zwięzłe odpowiedzi, podczas gdy wysoka szczegółowość dostarcza dokładnych wyjaśnień." + }, "setReasoningLevel": "Włącz wysiłek rozumowania", "claudeCode": { "pathLabel": "Ścieżka Claude Code", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index e7243aa6f6..a71340391d 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -433,6 +433,13 @@ "medium": "Médio", "low": "Baixo" }, + "verbosity": { + "label": "Verbosidade da saída", + "high": "Alta", + "medium": "Média", + "low": "Baixa", + "description": "Controla o quão detalhadas são as respostas do modelo. A verbosidade baixa produz respostas concisas, enquanto a verbosidade alta fornisce explicações detalhadas." + }, "setReasoningLevel": "Habilitar esforço de raciocínio", "claudeCode": { "pathLabel": "Caminho do Claude Code", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 38e986ab88..00e9b79074 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -433,6 +433,13 @@ "medium": "Средние", "low": "Низкие" }, + "verbosity": { + "label": "Подробность вывода", + "high": "Высокая", + "medium": "Средняя", + "low": "Низкая", + "description": "Контролирует, насколько подробны ответы модели. Низкая подробность дает краткие ответы, а высокая — подробные объяснения." + }, "setReasoningLevel": "Включить усилие рассуждения", "claudeCode": { "pathLabel": "Путь к Claude Code", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index b4b9fd13e4..e79db2a3b2 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -433,6 +433,13 @@ "medium": "Orta", "low": "Düşük" }, + "verbosity": { + "label": "Çıktı Ayrıntı Düzeyi", + "high": "Yüksek", + "medium": "Orta", + "low": "Düşük", + "description": "Modelin yanıtlarının ne kadar ayrıntılı olduğunu kontrol eder. Düşük ayrıntı düzeyi kısa yanıtlar üretirken, yüksek ayrıntı düzeyi kapsamlı açıklamalar sunar." + }, "setReasoningLevel": "Akıl Yürütme Çabasını Etkinleştir", "claudeCode": { "pathLabel": "Claude Code Yolu", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index cdae509d5e..10de98d4da 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -433,6 +433,13 @@ "medium": "Trung bình", "low": "Thấp" }, + "verbosity": { + "label": "Mức độ chi tiết đầu ra", + "high": "Cao", + "medium": "Trung bình", + "low": "Thấp", + "description": "Kiểm soát mức độ chi tiết của các câu trả lời của mô hình. Mức độ chi tiết thấp tạo ra các câu trả lời ngắn gọn, trong khi mức độ chi tiết cao cung cấp giải thích kỹ lưỡng." + }, "setReasoningLevel": "Kích hoạt nỗ lực suy luận", "claudeCode": { "pathLabel": "Đường dẫn Claude Code", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index aca901cc3e..a6971d288f 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -433,6 +433,13 @@ "medium": "中", "low": "低" }, + "verbosity": { + "label": "输出详细程度", + "high": "高", + "medium": "中", + "low": "低", + "description": "控制模型响应的详细程度。低详细度产生简洁的回答,而高详细度提供详尽的解释。" + }, "setReasoningLevel": "启用推理工作量", "claudeCode": { "pathLabel": "Claude Code 路径", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index db3fc3c2cd..bec2ffd5e9 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -433,6 +433,13 @@ "medium": "中", "low": "低" }, + "verbosity": { + "label": "輸出詳細程度", + "high": "高", + "medium": "中", + "low": "低", + "description": "控制模型回應的詳細程度。低詳細度產生簡潔的回答,而高詳細度提供詳盡的解釋。" + }, "setReasoningLevel": "啟用推理工作量", "claudeCode": { "pathLabel": "Claude Code 路徑", From 331ecf26d24e46e3fcf4a490d9e32fd8f041dc21 Mon Sep 17 00:00:00 2001 From: Daniel <57051444+daniel-lxs@users.noreply.github.com> Date: Thu, 7 Aug 2025 15:49:47 -0500 Subject: [PATCH 17/17] Delete .roorules --- .roorules | 242 ------------------------------------------------------ 1 file changed, 242 deletions(-) delete mode 100644 .roorules diff --git a/.roorules b/.roorules deleted file mode 100644 index 67eadf6bec..0000000000 --- a/.roorules +++ /dev/null @@ -1,242 +0,0 @@ -.roorules - -This file provides guidance to Roo Code (or other AI coding assistants) when working with code in this repository. - -## Project Overview - -**Roo Code** is a VSCode extension that provides an AI-powered autonomous coding agent. Built as a monorepo using TypeScript, React, and VSCode Extension API, it enables natural language code generation, refactoring, and intelligent assistance directly within the editor. - -**Tech Stack:** -- **Core:** TypeScript, VSCode Extension API, Node.js 20.19.2 -- **Frontend:** React 18, Vite, Tailwind CSS, Radix UI -- **Build:** pnpm workspaces, Turbo, ESBuild, Vite -- **Testing:** Vitest -- **State Management:** VSCode Extension Context, React Context -- **Communication:** Webview API, IPC - -## Essential Commands - -```bash -# Installation & Setup -pnpm install # Install all dependencies (uses pnpm 10.8.1) - -# Development -pnpm lint # Run ESLint across all workspaces -pnpm check-types # TypeScript type checking -pnpm test # Run all tests -pnpm format # Format with Prettier -pnpm build # Build all packages -pnpm clean # Clean build artifacts - -# Extension Development -cd src && pnpm bundle # Bundle extension code -pnpm vsix # Create VSIX package for distribution -pnpm install:vsix # Build and install extension locally -Press F5 in VSCode # Launch extension in debug mode - -# Testing (CRITICAL - Must run from correct directory!) -cd src && npx vitest run tests/user.test.ts # Backend tests -cd webview-ui && npx vitest run src/test.ts # UI tests -# NEVER run tests from project root - causes "vitest: command not found" -``` - -## Architecture Overview - -``` -User Input → VSCode Extension → Webview UI - ↓ ↓ - ClineProvider ←→ WebviewMessageHandler - ↓ - Task Engine - ↓ - Tool Execution System - ↙ ↓ ↘ - Files Terminal Browser -``` - -### Core Components - -1. **Extension Entry** ([`src/extension.ts`](src/extension.ts)) - - Activates on VSCode startup - - Initializes services (Cloud, Telemetry, MDM, MCP) - - Registers commands and providers - -2. **ClineProvider** ([`src/core/webview/ClineProvider.ts`](src/core/webview/ClineProvider.ts)) - - Central orchestrator for all interactions - - Manages webview lifecycle - - Handles task stack and state persistence - -3. **Task System** ([`src/core/task/Task.ts`](src/core/task/Task.ts)) - - Executes AI agent workflows - - Manages tool usage and message flow - - Handles checkpoints and recovery - -4. **Webview UI** ([`webview-ui/`](webview-ui/)) - - React-based chat interface - - Communicates via postMessage API - - Styled with Tailwind + VSCode theme variables - -## Development Guides - -### Adding a New AI Provider - -1. Create provider class in [`src/api/providers/`](src/api/providers/) -2. Extend `BaseProvider` or `BaseOpenAICompatibleProvider` -3. Implement required methods: `createMessage()`, `getModel()` -4. Register in [`src/api/index.ts`](src/api/index.ts) -5. Add UI configuration in webview settings - -### Creating a Custom Mode - -1. Add mode definition to [`.roomodes/`](.roomodes/) -2. Include mode metadata (name, slug, model preferences) -3. Define system prompt and tool restrictions -4. Register in [`CustomModesManager`](src/core/config/CustomModesManager.ts) - -### Adding a New Tool - -1. Create tool file in [`src/core/tools/`](src/core/tools/) -2. Implement tool interface with `execute()` method -3. Add tool to system prompt in [`src/core/prompts/tools/`](src/core/prompts/tools/) -4. Handle tool response in Task execution flow - -### Modifying the Webview UI - -1. Components live in [`webview-ui/src/components/`](webview-ui/src/components/) -2. Use Tailwind classes, not inline styles -3. VSCode CSS variables must be added to [`webview-ui/src/index.css`](webview-ui/src/index.css) -4. Test with both light and dark themes - -## Project-Specific Patterns - -### State Management -- Extension state: VSCode `globalState` and `secrets` APIs via `ContextProxy` -- Webview state: React Context + message passing -- Task persistence: JSON files in global storage directory - -### Message Flow -```typescript -// Webview → Extension -vscode.postMessage({ type: "newTask", text: "..." }) - -// Extension → Webview -provider.postMessageToWebview({ type: "taskUpdated", ... }) -``` - -### Error Handling -- All async operations wrapped in try-catch -- Errors logged to output channel -- User-facing errors shown via `vscode.window.showErrorMessage` - -### File Operations -- Always use VSCode workspace APIs for file access -- Respect `.rooignore` patterns -- Use `FileContextTracker` for monitoring file changes - -## Code Style - -```typescript -// Formatting (from .prettierrc.json) -- Tabs (width: 4) -- No semicolons -- Print width: 120 chars -- Brackets on same line - -// TypeScript -- Strict mode enabled -- No implicit any (currently disabled in ESLint) -- Use type imports: import type { ... } - -// Naming Conventions -- Files: camelCase.ts or PascalCase.ts for classes -- Interfaces: IPrefixed or suffixed with Interface -- Types: PascalCase -- Constants: UPPER_SNAKE_CASE -``` - -## Testing Guidelines - -### Test Structure -```typescript -// Tests use Vitest with globals (vi, describe, test, it) -describe("ComponentName", () => { - test("should do something", async () => { - // Arrange - const mock = vi.fn() - - // Act - await doSomething() - - // Assert - expect(mock).toHaveBeenCalled() - }) -}) -``` - -### Running Tests -```bash -# CRITICAL: Tests must run from workspace directory! -cd src && npx vitest run path/to/test.ts # Backend -cd webview-ui && npx vitest run src/... # Frontend - -# Watch mode for development -cd src && npx vitest watch -``` - -### Mocking VSCode APIs -- Mock modules in [`src/__mocks__/vscode.ts`](src/__mocks__/vscode.ts) -- Use `vi.mock("vscode")` in test files -- Mock extension context for provider tests - -## Security Considerations - -- **API Keys:** Stored in VSCode secrets, never in code -- **File Access:** Respect workspace boundaries and .rooignore -- **Command Execution:** User approval required for terminal commands -- **Protected Files:** RooProtectedController prevents accidental overwrites - -## Performance Optimization - -- **Lazy Loading:** MCP servers and code indexing initialize on-demand -- **Debouncing:** File watchers and UI updates are debounced -- **Caching:** Model lists and API responses cached with TTL -- **Streaming:** LLM responses streamed for better UX - -## Critical Rules - -1. **Never disable lint rules** without explicit user approval -2. **Always ensure test coverage** before attempting completion -3. **Use Tailwind CSS** for new UI components, not inline styles -4. **Run tests from correct directory** - see Testing Guidelines -5. **Respect file restrictions** - some modes can only edit specific file types -6. **Wait for tool confirmation** - never assume tool success without user response - -## Troubleshooting - -### Common Issues - -**"vitest: command not found"** -- You're running tests from the wrong directory -- Solution: `cd src` or `cd webview-ui` first - -**Extension not loading** -- Check output channel for errors -- Verify all dependencies installed: `pnpm install` -- Try clean rebuild: `pnpm clean && pnpm build` - -**Webview not updating** -- In dev mode (F5), changes should hot-reload -- For VSIX installation, rebuild and reinstall - -**MCP server connection failed** -- Check server configuration in settings -- Verify server binary is executable -- Check logs in output channel - -## Development Workflow - -1. **Branch naming:** `feature/description` or `fix/issue-number` -2. **Commits:** Descriptive messages referencing issues -3. **Testing:** Run tests before pushing -4. **Code review:** All PRs require approval -5. **Deployment:** Automated via GitHub Actions on merge to main \ No newline at end of file