Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/api/providers/anthropic-vertex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
}
}

// Apply model family defaults for consistent behavior across providers
info = this.applyModelDefaults(id, info)

const params = getModelParams({ format: "anthropic", modelId: id, model: info, settings: this.options })

// Build betas array for request headers
Expand Down
3 changes: 3 additions & 0 deletions src/api/providers/anthropic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,9 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
}
}

// Apply model family defaults for consistent behavior across providers
info = this.applyModelDefaults(id, info)

const params = getModelParams({
format: "anthropic",
modelId: id,
Expand Down
4 changes: 3 additions & 1 deletion src/api/providers/base-openai-compatible-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ export abstract class BaseOpenAiCompatibleProvider<ModelName extends string>
? (this.options.apiModelId as ModelName)
: this.defaultProviderModelId

return { id, info: this.providerModels[id] }
// Apply model family defaults for consistent behavior across providers
const info = this.applyModelDefaults(id, this.providerModels[id])
return { id, info }
}
}
20 changes: 20 additions & 0 deletions src/api/providers/base-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { ModelInfo } from "@roo-code/types"
import type { ApiHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { ApiStream } from "../transform/stream"
import { countTokens } from "../../utils/countTokens"
import { applyModelFamilyDefaults } from "./utils/model-family-defaults"

/**
* Base class for API providers that implements common functionality.
Expand Down Expand Up @@ -103,4 +104,23 @@ export abstract class BaseProvider implements ApiHandler {

return countTokens(content, { useWorker: true })
}

/**
* Apply model family defaults to a ModelInfo object.
*
* This helper method allows providers to apply consistent defaults
* for recognized model families (OpenAI, Gemini, etc.) regardless of
* which provider is serving the model.
*
* Defaults are only applied when the corresponding property is not
* already explicitly set on the model info, ensuring that provider-specific
* or model-specific settings take precedence.
*
* @param modelId - The model identifier
* @param info - The original ModelInfo object
* @returns A new ModelInfo object with family defaults applied
*/
protected applyModelDefaults(modelId: string, info: ModelInfo): ModelInfo {
return applyModelFamilyDefaults(modelId, info)
}
}
9 changes: 7 additions & 2 deletions src/api/providers/bedrock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1072,15 +1072,17 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
reasoningBudget?: number
} {
if (this.costModelConfig?.id?.trim().length > 0) {
// Apply model family defaults for consistent behavior across providers
const info = this.applyModelDefaults(this.costModelConfig.id, this.costModelConfig.info)
// Get model params for cost model config
const params = getModelParams({
format: "anthropic",
modelId: this.costModelConfig.id,
model: this.costModelConfig.info,
model: info,
settings: this.options,
defaultTemperature: BEDROCK_DEFAULT_TEMPERATURE,
})
return { ...this.costModelConfig, ...params }
return { ...this.costModelConfig, info, ...params }
}

let modelConfig = undefined
Expand Down Expand Up @@ -1158,6 +1160,9 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
}
}

// Apply model family defaults for consistent behavior across providers
modelConfig.info = this.applyModelDefaults(modelConfig.id, modelConfig.info)

// Don't override maxTokens/contextWindow here; handled in getModelById (and includes user overrides)
return { ...modelConfig, ...params } as {
id: BedrockModelId | string
Expand Down
11 changes: 8 additions & 3 deletions src/api/providers/cerebras.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Anthropic } from "@anthropic-ai/sdk"

import { type CerebrasModelId, cerebrasDefaultModelId, cerebrasModels } from "@roo-code/types"
import { type CerebrasModelId, type ModelInfo, cerebrasDefaultModelId, cerebrasModels } from "@roo-code/types"

import type { ApiHandlerOptions } from "../../shared/api"
import { calculateApiCostOpenAI } from "../../shared/cost"
Expand Down Expand Up @@ -38,13 +38,18 @@ export class CerebrasHandler extends BaseProvider implements SingleCompletionHan
}
}

getModel(): { id: CerebrasModelId; info: (typeof cerebrasModels)[CerebrasModelId] } {
getModel(): { id: CerebrasModelId; info: ModelInfo } {
const modelId = this.options.apiModelId as CerebrasModelId
const validModelId = modelId && this.providerModels[modelId] ? modelId : this.defaultProviderModelId

let info: ModelInfo = { ...this.providerModels[validModelId] }

// Apply model family defaults for consistent behavior across providers
info = this.applyModelDefaults(validModelId, info)

return {
id: validModelId,
info: this.providerModels[validModelId],
info,
}
}

Expand Down
11 changes: 9 additions & 2 deletions src/api/providers/claude-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
type ModelInfo,
} from "@roo-code/types"
import { type ApiHandler, ApiHandlerCreateMessageMetadata, type SingleCompletionHandler } from ".."
import { applyModelFamilyDefaults } from "./utils/model-family-defaults"
import { ApiStreamUsageChunk, type ApiStream } from "../transform/stream"
import { claudeCodeOAuthManager, generateUserId } from "../../integrations/claude-code/oauth"
import {
Expand Down Expand Up @@ -275,12 +276,18 @@ export class ClaudeCodeHandler implements ApiHandler, SingleCompletionHandler {
const modelId = this.options.apiModelId
if (modelId && Object.hasOwn(claudeCodeModels, modelId)) {
const id = modelId as ClaudeCodeModelId
return { id, info: { ...claudeCodeModels[id] } }
// Apply model family defaults for consistent behavior across providers
const info = applyModelFamilyDefaults(id, { ...claudeCodeModels[id] })
return { id, info }
}

// Apply model family defaults for consistent behavior across providers
const info = applyModelFamilyDefaults(claudeCodeDefaultModelId, {
...claudeCodeModels[claudeCodeDefaultModelId],
})
return {
id: claudeCodeDefaultModelId,
info: { ...claudeCodeModels[claudeCodeDefaultModelId] },
info,
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/api/providers/deepinfra.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ export class DeepInfraHandler extends RouterProvider implements SingleCompletion

override getModel() {
const id = this.options.deepInfraModelId ?? deepInfraDefaultModelId
const info = this.models[id] ?? deepInfraDefaultModelInfo
let info = this.models[id] ?? deepInfraDefaultModelInfo

// Apply model family defaults for consistent behavior across providers
info = this.applyModelDefaults(id, info)

const params = getModelParams({
format: "openai",
Expand Down
9 changes: 8 additions & 1 deletion src/api/providers/deepseek.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"

import {
type ModelInfo,
deepSeekModels,
deepSeekDefaultModelId,
DEEP_SEEK_DEFAULT_TEMPERATURE,
Expand Down Expand Up @@ -36,7 +37,13 @@ export class DeepSeekHandler extends OpenAiHandler {

override getModel() {
const id = this.options.apiModelId ?? deepSeekDefaultModelId
const info = deepSeekModels[id as keyof typeof deepSeekModels] || deepSeekModels[deepSeekDefaultModelId]
let info: ModelInfo = {
...(deepSeekModels[id as keyof typeof deepSeekModels] || deepSeekModels[deepSeekDefaultModelId]),
}

// Apply model family defaults for consistent behavior across providers
info = this.applyModelDefaults(id, info)

const params = getModelParams({ format: "openai", modelId: id, model: info, settings: this.options })
return { id, info, ...params }
}
Expand Down
10 changes: 8 additions & 2 deletions src/api/providers/doubao.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { OpenAiHandler } from "./openai"
import type { ApiHandlerOptions } from "../../shared/api"
import { DOUBAO_API_BASE_URL, doubaoDefaultModelId, doubaoModels } from "@roo-code/types"
import { type ModelInfo, DOUBAO_API_BASE_URL, doubaoDefaultModelId, doubaoModels } from "@roo-code/types"
import { getModelParams } from "../transform/model-params"
import { ApiStreamUsageChunk } from "../transform/stream"

Expand Down Expand Up @@ -63,7 +63,13 @@ export class DoubaoHandler extends OpenAiHandler {

override getModel() {
const id = this.options.apiModelId ?? doubaoDefaultModelId
const info = doubaoModels[id as keyof typeof doubaoModels] || doubaoModels[doubaoDefaultModelId]
let info: ModelInfo = {
...(doubaoModels[id as keyof typeof doubaoModels] || doubaoModels[doubaoDefaultModelId]),
}

// Apply model family defaults for consistent behavior across providers
info = this.applyModelDefaults(id, info)

const params = getModelParams({ format: "openai", modelId: id, model: info, settings: this.options })
return { id, info, ...params }
}
Expand Down
3 changes: 3 additions & 0 deletions src/api/providers/gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,9 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
let id = modelId && modelId in geminiModels ? (modelId as GeminiModelId) : geminiDefaultModelId
let info: ModelInfo = geminiModels[id]

// Apply model family defaults for consistent behavior across providers
info = this.applyModelDefaults(id, info)

const params = getModelParams({
format: "gemini",
modelId: id,
Expand Down
23 changes: 16 additions & 7 deletions src/api/providers/huggingface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import OpenAI from "openai"
import { Anthropic } from "@anthropic-ai/sdk"

import type { ModelInfo } from "@roo-code/types"

import type { ApiHandlerOptions, ModelRecord } from "../../shared/api"
import { ApiStream } from "../transform/stream"
import { convertToOpenAiMessages } from "../transform/openai-format"
Expand Down Expand Up @@ -112,24 +114,31 @@ export class HuggingFaceHandler extends BaseProvider implements SingleCompletion
const modelId = this.options.huggingFaceModelId || "meta-llama/Llama-3.3-70B-Instruct"

// Try to get model info from cache
const modelInfo = this.modelCache?.[modelId]
let modelInfo = this.modelCache?.[modelId]

if (modelInfo) {
// Apply model family defaults for consistent behavior across providers
modelInfo = this.applyModelDefaults(modelId, modelInfo)
return {
id: modelId,
info: modelInfo,
}
}

// Fallback to default values if model not found in cache
let defaultInfo: ModelInfo = {
maxTokens: 8192,
contextWindow: 131072,
supportsImages: false,
supportsPromptCache: false,
}

// Apply model family defaults for consistent behavior across providers
defaultInfo = this.applyModelDefaults(modelId, defaultInfo)

return {
id: modelId,
info: {
maxTokens: 8192,
contextWindow: 131072,
supportsImages: false,
supportsPromptCache: false,
},
info: defaultInfo,
}
}
}
25 changes: 15 additions & 10 deletions src/api/providers/human-relay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getCommand } from "../../utils/commands"
import { ApiStream } from "../transform/stream"

import type { ApiHandler, SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { applyModelFamilyDefaults } from "./utils/model-family-defaults"

/**
* Human Relay API processor
Expand Down Expand Up @@ -62,18 +63,22 @@ export class HumanRelayHandler implements ApiHandler, SingleCompletionHandler {
* Get model information
*/
getModel(): { id: string; info: ModelInfo } {
const modelId = "human-relay"
// Human relay does not depend on a specific model, here is a default configuration
const baseInfo: ModelInfo = {
maxTokens: 16384,
contextWindow: 100000,
supportsImages: true,
supportsPromptCache: false,
inputPrice: 0,
outputPrice: 0,
description: "Calling web-side AI model through human relay",
}
// Apply model family defaults for consistent behavior across providers
const info = applyModelFamilyDefaults(modelId, baseInfo)
return {
id: "human-relay",
info: {
maxTokens: 16384,
contextWindow: 100000,
supportsImages: true,
supportsPromptCache: false,
inputPrice: 0,
outputPrice: 0,
description: "Calling web-side AI model through human relay",
},
id: modelId,
info,
}
}

Expand Down
28 changes: 20 additions & 8 deletions src/api/providers/io-intelligence.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { ioIntelligenceDefaultModelId, ioIntelligenceModels, type IOIntelligenceModelId } from "@roo-code/types"
import {
type ModelInfo,
ioIntelligenceDefaultModelId,
ioIntelligenceModels,
type IOIntelligenceModelId,
} from "@roo-code/types"

import type { ApiHandlerOptions } from "../../shared/api"
import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"
Expand Down Expand Up @@ -27,18 +32,25 @@ export class IOIntelligenceHandler extends BaseOpenAiCompatibleProvider<IOIntell
this.providerModels[modelId as IOIntelligenceModelId] ?? this.providerModels[ioIntelligenceDefaultModelId]

if (modelInfo) {
return { id: modelId as IOIntelligenceModelId, info: modelInfo }
// Apply model family defaults for consistent behavior across providers
const info = this.applyModelDefaults(modelId, modelInfo)
return { id: modelId as IOIntelligenceModelId, info }
}

// Return the requested model ID even if not found, with fallback info.
let defaultInfo: ModelInfo = {
maxTokens: 8192,
contextWindow: 128000,
supportsImages: false,
supportsPromptCache: false,
}

// Apply model family defaults for consistent behavior across providers
defaultInfo = this.applyModelDefaults(modelId, defaultInfo)

return {
id: modelId as IOIntelligenceModelId,
info: {
maxTokens: 8192,
contextWindow: 128000,
supportsImages: false,
supportsPromptCache: false,
},
info: defaultInfo,
}
}
}
15 changes: 10 additions & 5 deletions src/api/providers/lm-studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,21 @@ export class LmStudioHandler extends BaseProvider implements SingleCompletionHan
}

override getModel(): { id: string; info: ModelInfo } {
const modelId = this.options.lmStudioModelId || ""
const models = getModelsFromCache("lmstudio")
if (models && this.options.lmStudioModelId && models[this.options.lmStudioModelId]) {
if (models && modelId && models[modelId]) {
// Apply model family defaults for consistent behavior across providers
const info = this.applyModelDefaults(modelId, models[modelId])
return {
id: this.options.lmStudioModelId,
info: models[this.options.lmStudioModelId],
id: modelId,
info,
}
} else {
// Apply model family defaults for consistent behavior across providers
const info = this.applyModelDefaults(modelId, openAiModelInfoSaneDefaults)
return {
id: this.options.lmStudioModelId || "",
info: openAiModelInfoSaneDefaults,
id: modelId,
info,
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/api/providers/minimax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,9 @@ export class MiniMaxHandler extends BaseProvider implements SingleCompletionHand
getModel() {
const modelId = this.options.apiModelId
const id = modelId && modelId in minimaxModels ? (modelId as MinimaxModelId) : minimaxDefaultModelId
const info = minimaxModels[id]
const baseInfo = minimaxModels[id]
// Apply model family defaults for consistent behavior across providers
const info = this.applyModelDefaults(id, baseInfo)

const params = getModelParams({
format: "anthropic",
Expand Down
Loading
Loading