| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- import { type ModelInfo, type ProviderSettings, ANTHROPIC_DEFAULT_MAX_TOKENS } from "@roo-code/types"
- import { shouldUseReasoningBudget, shouldUseReasoningEffort } from "../../shared/api"
- import {
- type AnthropicReasoningParams,
- type OpenAiReasoningParams,
- type GeminiReasoningParams,
- type OpenRouterReasoningParams,
- getAnthropicReasoning,
- getOpenAiReasoning,
- getGeminiReasoning,
- getOpenRouterReasoning,
- } from "./reasoning"
- type Format = "anthropic" | "openai" | "gemini" | "openrouter"
- type GetModelParamsOptions<T extends Format> = {
- format: T
- modelId: string
- model: ModelInfo
- settings: ProviderSettings
- defaultTemperature?: number
- }
- type BaseModelParams = {
- maxTokens: number | undefined
- temperature: number | undefined
- reasoningEffort: "low" | "medium" | "high" | undefined
- reasoningBudget: number | undefined
- }
- type AnthropicModelParams = {
- format: "anthropic"
- reasoning: AnthropicReasoningParams | undefined
- } & BaseModelParams
- type OpenAiModelParams = {
- format: "openai"
- reasoning: OpenAiReasoningParams | undefined
- } & BaseModelParams
- type GeminiModelParams = {
- format: "gemini"
- reasoning: GeminiReasoningParams | undefined
- } & BaseModelParams
- type OpenRouterModelParams = {
- format: "openrouter"
- reasoning: OpenRouterReasoningParams | undefined
- } & BaseModelParams
- export type ModelParams = AnthropicModelParams | OpenAiModelParams | GeminiModelParams | OpenRouterModelParams
- // Function overloads for specific return types
- export function getModelParams(options: GetModelParamsOptions<"anthropic">): AnthropicModelParams
- export function getModelParams(options: GetModelParamsOptions<"openai">): OpenAiModelParams
- export function getModelParams(options: GetModelParamsOptions<"gemini">): GeminiModelParams
- export function getModelParams(options: GetModelParamsOptions<"openrouter">): OpenRouterModelParams
- export function getModelParams({
- format,
- modelId,
- model,
- settings,
- defaultTemperature = 0,
- }: GetModelParamsOptions<Format>): ModelParams {
- const {
- modelMaxTokens: customMaxTokens,
- modelMaxThinkingTokens: customMaxThinkingTokens,
- modelTemperature: customTemperature,
- reasoningEffort: customReasoningEffort,
- } = settings
- let maxTokens = model.maxTokens ?? undefined
- let temperature = customTemperature ?? defaultTemperature
- let reasoningBudget: ModelParams["reasoningBudget"] = undefined
- let reasoningEffort: ModelParams["reasoningEffort"] = undefined
- if (shouldUseReasoningBudget({ model, settings })) {
- // "Hybrid" reasoning models use the `reasoningBudget` parameter.
- maxTokens = customMaxTokens ?? maxTokens
- // Clamp the thinking budget to be at most 80% of max tokens and at
- // least 1024 tokens.
- const maxBudgetTokens = Math.floor((maxTokens || ANTHROPIC_DEFAULT_MAX_TOKENS) * 0.8)
- reasoningBudget = Math.max(Math.min(customMaxThinkingTokens ?? maxBudgetTokens, maxBudgetTokens), 1024)
- // Let's assume that "Hybrid" reasoning models require a temperature of
- // 1.0 since Anthropic does.
- temperature = 1.0
- } else if (shouldUseReasoningEffort({ model, settings })) {
- // "Traditional" reasoning models use the `reasoningEffort` parameter.
- reasoningEffort = customReasoningEffort ?? model.reasoningEffort
- }
- // TODO: We should consolidate this logic to compute `maxTokens` with
- // `getModelMaxOutputTokens` in order to maintain a single source of truth.
- const isAnthropic = format === "anthropic" || (format === "openrouter" && modelId.startsWith("anthropic/"))
- // For "Hybrid" reasoning models, we should discard the model's actual
- // `maxTokens` value if we're not using reasoning. We do this for Anthropic
- // models only for now. Should we do this for Gemini too?
- if (model.supportsReasoningBudget && !reasoningBudget && isAnthropic) {
- maxTokens = ANTHROPIC_DEFAULT_MAX_TOKENS
- }
- // For Anthropic models we should always make sure a `maxTokens` value is
- // set.
- if (!maxTokens && isAnthropic) {
- maxTokens = ANTHROPIC_DEFAULT_MAX_TOKENS
- }
- const params: BaseModelParams = { maxTokens, temperature, reasoningEffort, reasoningBudget }
- if (format === "anthropic") {
- return {
- format,
- ...params,
- reasoning: getAnthropicReasoning({ model, reasoningBudget, reasoningEffort, settings }),
- }
- } else if (format === "openai") {
- // Special case for o1 and o3-mini, which don't support temperature.
- // TODO: Add a `supportsTemperature` field to the model info.
- if (modelId.startsWith("o1") || modelId.startsWith("o3-mini")) {
- params.temperature = undefined
- }
- return {
- format,
- ...params,
- reasoning: getOpenAiReasoning({ model, reasoningBudget, reasoningEffort, settings }),
- }
- } else if (format === "gemini") {
- return {
- format,
- ...params,
- reasoning: getGeminiReasoning({ model, reasoningBudget, reasoningEffort, settings }),
- }
- } else {
- // Special case for o1-pro, which doesn't support temperature.
- // Note that OpenRouter's `supported_parameters` field includes
- // `temperature`, which is probably a bug.
- // TODO: Add a `supportsTemperature` field to the model info and populate
- // it appropriately in the OpenRouter fetcher.
- if (modelId === "openai/o1-pro") {
- params.temperature = undefined
- }
- return {
- format,
- ...params,
- reasoning: getOpenRouterReasoning({ model, reasoningBudget, reasoningEffort, settings }),
- }
- }
- }
|