diff --git a/packages/gen/gen_ai_hub/orchestration_v2/models/__init__.py b/packages/gen/gen_ai_hub/orchestration_v2/models/__init__.py index 790b0b75..efb0d5f5 100644 --- a/packages/gen/gen_ai_hub/orchestration_v2/models/__init__.py +++ b/packages/gen/gen_ai_hub/orchestration_v2/models/__init__.py @@ -18,7 +18,7 @@ from .llama_guard_3_filter import LlamaGuard38bFilter from .llm_model_details import LLMModelDetails from .message import (SystemMessage, UserMessage, AssistantMessage, ToolChatMessage, DeveloperChatMessage, ChatMessage, - ResponseChatMessage, FunctionCall, MessageToolCall) + ResponseChatMessage, FunctionCall, MessageToolCall, ReasoningBlock) from .multimodal_items import ImageDetailLevel, TextPart, ImageUrl, ImagePart, ContentPart, ImageItem from .response import (PromptTokensDetails, CompletionTokensDetails, TokenUsage, GenericModuleResult, TopLogprob, ChatCompletionTokenLogprob, ChoiceLogprobs, LLMChoice, StreamFunctionObject, StreamToolCall, @@ -73,7 +73,7 @@ # message "SystemMessage", "UserMessage", "AssistantMessage", "ToolChatMessage", "DeveloperChatMessage", - "ChatMessage", "ResponseChatMessage", "FunctionCall", "MessageToolCall", + "ChatMessage", "ResponseChatMessage", "FunctionCall", "MessageToolCall", "ReasoningBlock", # multimodal_items "ImageDetailLevel", "TextPart", "ImageUrl", "ImagePart", "ContentPart", "ImageItem", diff --git a/packages/gen/gen_ai_hub/orchestration_v2/models/message.py b/packages/gen/gen_ai_hub/orchestration_v2/models/message.py index f098c775..7a7fbe35 100644 --- a/packages/gen/gen_ai_hub/orchestration_v2/models/message.py +++ b/packages/gen/gen_ai_hub/orchestration_v2/models/message.py @@ -59,6 +59,17 @@ class MessageToolCall(BaseModel): type: typing.Literal["function"] = "function" function: FunctionCall +class ReasoningBlock(BaseModel): + """ + The reasoning content returned by the model. + + Attributes: + content: The reasoning content. + signature: Signature string for hidden reasoning content. + """ + content: str + signature: str + class Role(str, Enum): """ @@ -182,14 +193,17 @@ class ResponseChatMessage(BaseModel): refusal: A string indicating refusal reason. tool_calls: A list of tool call objects. + + reasoning_content: A list of reasoning content blocks. """ role: Role = Role.ASSISTANT content: str refusal: Optional[str] = None tool_calls: Optional[List[MessageToolCall]] = None + reasoning_content: Optional[List[ReasoningBlock]] = None ChatMessage = Union[SystemMessage, UserMessage, AssistantMessage, ToolChatMessage, DeveloperChatMessage, ResponseChatMessage] __all__ = ["Role", "SystemMessage", "UserMessage", "AssistantMessage", "ToolChatMessage", "DeveloperChatMessage", - "ChatMessage", "ResponseChatMessage", "FunctionCall", "MessageToolCall"] + "ChatMessage", "ResponseChatMessage", "FunctionCall", "MessageToolCall", "ReasoningBlock"] diff --git a/packages/gen/tests/orchestration_v2/test_message_v2.py b/packages/gen/tests/orchestration_v2/test_message_v2.py new file mode 100644 index 00000000..f4744e70 --- /dev/null +++ b/packages/gen/tests/orchestration_v2/test_message_v2.py @@ -0,0 +1,22 @@ +import unittest + +from gen_ai_hub.orchestration_v2.models.message import ( + ReasoningBlock, + ResponseChatMessage, +) + + +class TestResponseChatMessageValidation(unittest.TestCase): + + def test_reasoning_content_deserialized_from_dict(self): + msg = ResponseChatMessage.model_validate({ + "role": "assistant", + "content": "Hello", + "reasoning_content": [{"content": "I think...", "signature": "sig123"}], + }) + assert msg.reasoning_content is not None + self.assertIsInstance(msg.reasoning_content[0], ReasoningBlock) + + def test_reasoning_content_optional(self): + msg = ResponseChatMessage.model_validate({"role": "assistant", "content": "Hello"}) + self.assertIsNone(msg.reasoning_content)