@@ -152,12 +152,31 @@ def _coerce_message_content_to_text(content: Any, _depth: int = 0) -> str:
152152 if content is None :
153153 return ""
154154
155+ # Handle basic string types first (most common case)
155156 if isinstance (content , str ):
156157 return content
157158
159+ # Handle bytes and bytearray types
158160 if isinstance (content , bytes | bytearray ):
159161 return content .decode ("utf-8" , errors = "ignore" )
160162
163+ # Handle objects with text attribute using explicit type checking
164+ # We need to be careful here to avoid type checker issues with subclasses
165+ has_text_attr = hasattr (content , "text" )
166+ if has_text_attr :
167+ # Use getattr with a default to avoid type checker issues
168+ try :
169+ text_attr = getattr (content , "text" , None )
170+ if text_attr is not None :
171+ if isinstance (text_attr , str ):
172+ return text_attr
173+ if isinstance (text_attr , bytes | bytearray ):
174+ return text_attr .decode ("utf-8" , errors = "ignore" )
175+ except Exception :
176+ # If we can't access the text attribute, continue with other processing
177+ pass
178+
179+ # Handle objects with model_dump method
161180 if hasattr (content , "model_dump" ):
162181 try :
163182 dumped = content .model_dump ()
@@ -168,6 +187,7 @@ def _coerce_message_content_to_text(content: Any, _depth: int = 0) -> str:
168187 dumped , _depth + 1
169188 )
170189
190+ # Handle dictionary objects
171191 if isinstance (content , dict ):
172192 text_value = content .get ("text" )
173193 if isinstance (text_value , str ):
@@ -192,6 +212,8 @@ def _coerce_message_content_to_text(content: Any, _depth: int = 0) -> str:
192212 return f"[Circular reference detected at depth { _depth } ]"
193213 return error_message or str (content )
194214
215+ # Handle sequences (lists and tuples)
216+ # Check if it's a sequence but not a string/bytes/bytearray to avoid conflicts
195217 if isinstance (content , list | tuple ) and not isinstance (
196218 content , str | bytes | bytearray
197219 ):
@@ -204,13 +226,7 @@ def _coerce_message_content_to_text(content: Any, _depth: int = 0) -> str:
204226 parts .append (text_part )
205227 return "\n \n " .join (parts )
206228
207- if hasattr (content , "text" ):
208- text_attr = content .text
209- if isinstance (text_attr , str ):
210- return text_attr
211- if isinstance (text_attr , bytes | bytearray ):
212- return text_attr .decode ("utf-8" , errors = "ignore" )
213-
229+ # Fallback to string representation
214230 return str (content )
215231
216232 async def handle_chat_completion (
0 commit comments