77
88from io import StringIO
99
10- from pydantic import BaseModel
10+ from typing import Any , Self
11+
12+ from pydantic import (
13+ BaseModel ,
14+ ConfigDict ,
15+ field_serializer ,
16+ PrivateAttr ,
17+ )
18+ from pydantic .functional_validators import model_validator
1119
1220from f5_ai_gateway_sdk .multipart_fields import INPUT_NAME
1321from f5_ai_gateway_sdk .multipart_response import MultipartResponseField
@@ -40,9 +48,43 @@ class Message(BaseModel):
4048 """
4149
4250 __autoclass_content__ = "class"
51+ model_config = ConfigDict (extra = "allow" )
4352
4453 content : str
4554 role : str = MessageRole .USER
55+ _content_parsed_as_null : bool = PrivateAttr (default = False )
56+
57+ # messages may have null content when
58+ # containing tool_calls
59+ # this tracks that case in order to allow
60+ # returning in the same format without the
61+ # SDK user needing to handle None on content
62+ @model_validator (mode = "before" )
63+ @classmethod
64+ def track_null_content (cls , data : Any ) -> Any :
65+ if isinstance (data , dict ) and data .get ("content" ) is None :
66+ # Store this info in the data itself so it survives validation
67+ data ["__content_parsed_as_null__" ] = True
68+ data ["content" ] = ""
69+ return data
70+
71+ @model_validator (mode = "after" )
72+ def set_null_flag (self ) -> Self :
73+ # Check if the original data indicated null content
74+ if hasattr (self , "__content_parsed_as_null__" ) or getattr (
75+ self , "__content_parsed_as_null__" , False
76+ ):
77+ self ._content_parsed_as_null = True
78+ # Remove the temporary tracking field now that we've set the private attribute
79+ if hasattr (self , "__content_parsed_as_null__" ):
80+ delattr (self , "__content_parsed_as_null__" )
81+ return self
82+
83+ @field_serializer ("content" )
84+ def serialize_content (self , content : str ):
85+ if self ._content_parsed_as_null and len (content ) == 0 :
86+ return None
87+ return content
4688
4789
4890class RequestInput (BaseModel ):
@@ -68,6 +110,8 @@ class RequestInput(BaseModel):
68110 """
69111
70112 __autoclass_content__ = "class"
113+ model_config = ConfigDict (extra = "allow" )
114+
71115 messages : list [Message ]
72116
73117 def to_multipart_field (self ) -> MultipartResponseField :
0 commit comments