model-params.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import { type ModelInfo, type ProviderSettings, ANTHROPIC_DEFAULT_MAX_TOKENS } from "@roo-code/types"
  2. import { shouldUseReasoningBudget, shouldUseReasoningEffort } from "../../shared/api"
  3. import {
  4. type AnthropicReasoningParams,
  5. type OpenAiReasoningParams,
  6. type GeminiReasoningParams,
  7. type OpenRouterReasoningParams,
  8. getAnthropicReasoning,
  9. getOpenAiReasoning,
  10. getGeminiReasoning,
  11. getOpenRouterReasoning,
  12. } from "./reasoning"
  13. type Format = "anthropic" | "openai" | "gemini" | "openrouter"
  14. type GetModelParamsOptions<T extends Format> = {
  15. format: T
  16. modelId: string
  17. model: ModelInfo
  18. settings: ProviderSettings
  19. defaultTemperature?: number
  20. }
  21. type BaseModelParams = {
  22. maxTokens: number | undefined
  23. temperature: number | undefined
  24. reasoningEffort: "low" | "medium" | "high" | undefined
  25. reasoningBudget: number | undefined
  26. }
  27. type AnthropicModelParams = {
  28. format: "anthropic"
  29. reasoning: AnthropicReasoningParams | undefined
  30. } & BaseModelParams
  31. type OpenAiModelParams = {
  32. format: "openai"
  33. reasoning: OpenAiReasoningParams | undefined
  34. } & BaseModelParams
  35. type GeminiModelParams = {
  36. format: "gemini"
  37. reasoning: GeminiReasoningParams | undefined
  38. } & BaseModelParams
  39. type OpenRouterModelParams = {
  40. format: "openrouter"
  41. reasoning: OpenRouterReasoningParams | undefined
  42. } & BaseModelParams
  43. export type ModelParams = AnthropicModelParams | OpenAiModelParams | GeminiModelParams | OpenRouterModelParams
  44. // Function overloads for specific return types
  45. export function getModelParams(options: GetModelParamsOptions<"anthropic">): AnthropicModelParams
  46. export function getModelParams(options: GetModelParamsOptions<"openai">): OpenAiModelParams
  47. export function getModelParams(options: GetModelParamsOptions<"gemini">): GeminiModelParams
  48. export function getModelParams(options: GetModelParamsOptions<"openrouter">): OpenRouterModelParams
  49. export function getModelParams({
  50. format,
  51. modelId,
  52. model,
  53. settings,
  54. defaultTemperature = 0,
  55. }: GetModelParamsOptions<Format>): ModelParams {
  56. const {
  57. modelMaxTokens: customMaxTokens,
  58. modelMaxThinkingTokens: customMaxThinkingTokens,
  59. modelTemperature: customTemperature,
  60. reasoningEffort: customReasoningEffort,
  61. } = settings
  62. let maxTokens = model.maxTokens ?? undefined
  63. let temperature = customTemperature ?? defaultTemperature
  64. let reasoningBudget: ModelParams["reasoningBudget"] = undefined
  65. let reasoningEffort: ModelParams["reasoningEffort"] = undefined
  66. if (shouldUseReasoningBudget({ model, settings })) {
  67. // "Hybrid" reasoning models use the `reasoningBudget` parameter.
  68. maxTokens = customMaxTokens ?? maxTokens
  69. // Clamp the thinking budget to be at most 80% of max tokens and at
  70. // least 1024 tokens.
  71. const maxBudgetTokens = Math.floor((maxTokens || ANTHROPIC_DEFAULT_MAX_TOKENS) * 0.8)
  72. reasoningBudget = Math.max(Math.min(customMaxThinkingTokens ?? maxBudgetTokens, maxBudgetTokens), 1024)
  73. // Let's assume that "Hybrid" reasoning models require a temperature of
  74. // 1.0 since Anthropic does.
  75. temperature = 1.0
  76. } else if (shouldUseReasoningEffort({ model, settings })) {
  77. // "Traditional" reasoning models use the `reasoningEffort` parameter.
  78. reasoningEffort = customReasoningEffort ?? model.reasoningEffort
  79. }
  80. // TODO: We should consolidate this logic to compute `maxTokens` with
  81. // `getModelMaxOutputTokens` in order to maintain a single source of truth.
  82. const isAnthropic = format === "anthropic" || (format === "openrouter" && modelId.startsWith("anthropic/"))
  83. // For "Hybrid" reasoning models, we should discard the model's actual
  84. // `maxTokens` value if we're not using reasoning. We do this for Anthropic
  85. // models only for now. Should we do this for Gemini too?
  86. if (model.supportsReasoningBudget && !reasoningBudget && isAnthropic) {
  87. maxTokens = ANTHROPIC_DEFAULT_MAX_TOKENS
  88. }
  89. // For Anthropic models we should always make sure a `maxTokens` value is
  90. // set.
  91. if (!maxTokens && isAnthropic) {
  92. maxTokens = ANTHROPIC_DEFAULT_MAX_TOKENS
  93. }
  94. const params: BaseModelParams = { maxTokens, temperature, reasoningEffort, reasoningBudget }
  95. if (format === "anthropic") {
  96. return {
  97. format,
  98. ...params,
  99. reasoning: getAnthropicReasoning({ model, reasoningBudget, reasoningEffort, settings }),
  100. }
  101. } else if (format === "openai") {
  102. // Special case for o1 and o3-mini, which don't support temperature.
  103. // TODO: Add a `supportsTemperature` field to the model info.
  104. if (modelId.startsWith("o1") || modelId.startsWith("o3-mini")) {
  105. params.temperature = undefined
  106. }
  107. return {
  108. format,
  109. ...params,
  110. reasoning: getOpenAiReasoning({ model, reasoningBudget, reasoningEffort, settings }),
  111. }
  112. } else if (format === "gemini") {
  113. return {
  114. format,
  115. ...params,
  116. reasoning: getGeminiReasoning({ model, reasoningBudget, reasoningEffort, settings }),
  117. }
  118. } else {
  119. // Special case for o1-pro, which doesn't support temperature.
  120. // Note that OpenRouter's `supported_parameters` field includes
  121. // `temperature`, which is probably a bug.
  122. // TODO: Add a `supportsTemperature` field to the model info and populate
  123. // it appropriately in the OpenRouter fetcher.
  124. if (modelId === "openai/o1-pro") {
  125. params.temperature = undefined
  126. }
  127. return {
  128. format,
  129. ...params,
  130. reasoning: getOpenRouterReasoning({ model, reasoningBudget, reasoningEffort, settings }),
  131. }
  132. }
  133. }