@@ -52,6 +52,8 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
5252 ...convertToOpenAiMessages ( messages ) ,
5353 ]
5454
55+ const { id : modelId , info : modelInfo } = this . getModel ( )
56+
5557 // prompt caching: https://openrouter.ai/docs/prompt-caching
5658 // this is specifically for claude models (some models may 'support prompt caching' automatically without this)
5759 switch ( true ) {
@@ -95,10 +97,7 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
9597 let topP : number | undefined = undefined
9698
9799 // Handle models based on deepseek-r1
98- if (
99- this . getModel ( ) . id . startsWith ( "deepseek/deepseek-r1" ) ||
100- this . getModel ( ) . id === "perplexity/sonar-reasoning"
101- ) {
100+ if ( modelId . startsWith ( "deepseek/deepseek-r1" ) || modelId === "perplexity/sonar-reasoning" ) {
102101 // Recommended temperature for DeepSeek reasoning models
103102 defaultTemperature = DEEP_SEEK_DEFAULT_TEMPERATURE
104103 // DeepSeek highly recommends using user instead of system role
@@ -107,24 +106,34 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
107106 topP = 0.95
108107 }
109108
109+ let temperature = this . options . modelTemperature ?? defaultTemperature
110+
111+ // Anthropic "Thinking" models require a temperature of 1.0.
112+ if ( modelInfo . thinking ) {
113+ temperature = 1.0
114+ }
115+
110116 // https://openrouter.ai/docs/transforms
111117 let fullResponseText = ""
112- const stream = await this . client . chat . completions . create ( {
113- model : this . getModel ( ) . id ,
114- max_tokens : this . getModel ( ) . info . maxTokens ,
115- temperature : this . options . modelTemperature ?? defaultTemperature ,
118+
119+ const completionParams : OpenRouterChatCompletionParams = {
120+ model : modelId ,
121+ max_tokens : modelInfo . maxTokens ,
122+ temperature,
116123 top_p : topP ,
117124 messages : openAiMessages ,
118125 stream : true ,
119126 include_reasoning : true ,
120127 // This way, the transforms field will only be included in the parameters when openRouterUseMiddleOutTransform is true.
121128 ...( this . options . openRouterUseMiddleOutTransform && { transforms : [ "middle-out" ] } ) ,
122- } as OpenRouterChatCompletionParams )
129+ }
130+
131+ const stream = await this . client . chat . completions . create ( completionParams )
123132
124133 let genId : string | undefined
125134
126135 for await ( const chunk of stream as unknown as AsyncIterable < OpenAI . Chat . Completions . ChatCompletionChunk > ) {
127- // openrouter returns an error object instead of the openai sdk throwing an error
136+ // OpenRouter returns an error object instead of the OpenAI SDK throwing an error.
128137 if ( "error" in chunk ) {
129138 const error = chunk . error as { message ?: string ; code ?: number }
130139 console . error ( `OpenRouter API Error: ${ error ?. code } - ${ error ?. message } ` )
@@ -136,19 +145,22 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
136145 }
137146
138147 const delta = chunk . choices [ 0 ] ?. delta
148+
139149 if ( "reasoning" in delta && delta . reasoning ) {
140150 yield {
141151 type : "reasoning" ,
142152 text : delta . reasoning ,
143153 } as ApiStreamChunk
144154 }
155+
145156 if ( delta ?. content ) {
146157 fullResponseText += delta . content
147158 yield {
148159 type : "text" ,
149160 text : delta . content ,
150161 } as ApiStreamChunk
151162 }
163+
152164 // if (chunk.usage) {
153165 // yield {
154166 // type: "usage",
@@ -158,10 +170,12 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
158170 // }
159171 }
160172
161- // retry fetching generation details
173+ // Retry fetching generation details.
162174 let attempt = 0
175+
163176 while ( attempt ++ < 10 ) {
164177 await delay ( 200 ) // FIXME: necessary delay to ensure generation endpoint is ready
178+
165179 try {
166180 const response = await axios . get ( `https://openrouter.ai/api/v1/generation?id=${ genId } ` , {
167181 headers : {
@@ -171,7 +185,7 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
171185 } )
172186
173187 const generation = response . data ?. data
174- console . log ( "OpenRouter generation details:" , response . data )
188+
175189 yield {
176190 type : "usage" ,
177191 // cacheWriteTokens: 0,
@@ -182,20 +196,21 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
182196 totalCost : generation ?. total_cost || 0 ,
183197 fullResponseText,
184198 } as OpenRouterApiStreamUsageChunk
199+
185200 return
186201 } catch ( error ) {
187202 // ignore if fails
188203 console . error ( "Error fetching OpenRouter generation details:" , error )
189204 }
190205 }
191206 }
192- getModel ( ) : { id : string ; info : ModelInfo } {
207+
208+ getModel ( ) {
193209 const modelId = this . options . openRouterModelId
194210 const modelInfo = this . options . openRouterModelInfo
195- if ( modelId && modelInfo ) {
196- return { id : modelId , info : modelInfo }
197- }
198- return { id : openRouterDefaultModelId , info : openRouterDefaultModelInfo }
211+ return modelId && modelInfo
212+ ? { id : modelId , info : modelInfo }
213+ : { id : openRouterDefaultModelId , info : openRouterDefaultModelInfo }
199214 }
200215
201216 async completePrompt ( prompt : string ) : Promise < string > {
@@ -218,6 +233,7 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
218233 if ( error instanceof Error ) {
219234 throw new Error ( `OpenRouter completion error: ${ error . message } ` )
220235 }
236+
221237 throw error
222238 }
223239 }
@@ -239,6 +255,7 @@ export async function getOpenRouterModels() {
239255 inputPrice : parseApiPrice ( rawModel . pricing ?. prompt ) ,
240256 outputPrice : parseApiPrice ( rawModel . pricing ?. completion ) ,
241257 description : rawModel . description ,
258+ thinking : rawModel . id === "anthropic/claude-3.7-sonnet:thinking" ,
242259 }
243260
244261 // NOTE: this needs to be synced with api.ts/openrouter default model info.
0 commit comments