1- from dataclasses import dataclass
1+ from dataclasses import asdict , dataclass
22from typing import Literal , cast
33
44from openai import AsyncOpenAI
55from openai .types .chat import ChatCompletion , ChatCompletionMessage , ChatCompletionMessageParam
66from openai .types .chat .chat_completion import Choice
7- from pydantic import BaseModel
7+ from pydantic import AliasChoices , BaseModel , Field , TypeAdapter
88from typing_extensions import TypedDict
99
1010from .. import _utils
@@ -253,21 +253,21 @@ class ReasoningSummary(BaseReasoningDetail):
253253 """Represents a high-level summary of the reasoning process."""
254254
255255 type : Literal ['reasoning.summary' ]
256- summary : str
256+ summary : str = Field ( validation_alias = AliasChoices ( 'summary' , 'content' ))
257257
258258
259259class ReasoningEncrypted (BaseReasoningDetail ):
260260 """Represents encrypted reasoning data."""
261261
262262 type : Literal ['reasoning.encrypted' ]
263- data : str
263+ data : str = Field ( validation_alias = AliasChoices ( 'data' , 'signature' ))
264264
265265
266266class ReasoningText (BaseReasoningDetail ):
267267 """Represents raw text reasoning."""
268268
269269 type : Literal ['reasoning.text' ]
270- text : str
270+ text : str = Field ( validation_alias = AliasChoices ( 'text' , 'content' ))
271271 signature : str | None = None
272272
273273
@@ -276,7 +276,7 @@ class ReasoningText(BaseReasoningDetail):
276276
277277@dataclass (repr = False )
278278class OpenRouterThinkingPart (ThinkingPart ):
279- """filler ."""
279+ """A special ThinkingPart that includes reasoning attributes specific to OpenRouter ."""
280280
281281 type : Literal ['reasoning.summary' , 'reasoning.encrypted' , 'reasoning.text' ]
282282 index : int
@@ -317,22 +317,7 @@ def from_reasoning_detail(cls, reasoning: OpenRouterReasoningDetail, provider_na
317317 )
318318
319319 def into_reasoning_detail (self ):
320- reasoning_detail = {
321- 'type' : self .type ,
322- 'id' : self .id ,
323- 'format' : self .format ,
324- 'index' : self .index ,
325- }
326-
327- if self .type == 'reasoning.summary' :
328- reasoning_detail ['summary' ] = self .content
329- elif self .type == 'reasoning.text' :
330- reasoning_detail ['text' ] = self .content
331- reasoning_detail ['signature' ] = self .signature
332- elif self .type == 'reasoning.encrypted' :
333- reasoning_detail ['data' ] = self .signature
334-
335- return reasoning_detail
320+ return TypeAdapter (OpenRouterReasoningDetail ).validate_python (asdict (self )).model_dump ()
336321
337322
338323class OpenRouterCompletionMessage (ChatCompletionMessage ):
@@ -475,12 +460,8 @@ async def _map_messages(self, messages: list[ModelMessage]) -> list[ChatCompleti
475460
476461 for message , openai_message in zip (messages , openai_messages ):
477462 if isinstance (message , ModelResponse ):
478- reasoning_details = []
479-
480- for part in message .parts :
481- if isinstance (part , OpenRouterThinkingPart ):
482- reasoning_details .append (part .into_reasoning_detail ())
483-
484- openai_message ['reasoning_details' ] = reasoning_details
463+ openai_message ['reasoning_details' ] = [
464+ part .into_reasoning_detail () for part in message .parts if isinstance (part , OpenRouterThinkingPart )
465+ ]
485466
486467 return openai_messages
0 commit comments