44
55import uuid
66from dataclasses import dataclass , field
7- from typing import Dict , List , Optional , Any
7+ from typing import Dict , List , Optional , Any , ClassVar
88
99from .base import BaseModel
1010from .message import Message , MessageRole
@@ -20,6 +20,9 @@ class Conversation(BaseModel):
2020 conversation_id : str = field (default_factory = lambda : str (uuid .uuid4 ()))
2121 messages : List [Message ] = field (default_factory = list )
2222 metadata : Optional [Dict [str , Any ]] = None
23+
24+ # Add a class variable to track protocol compatibility mode
25+ _GOOGLE_A2A_COMPATIBILITY : ClassVar [bool ] = False
2326
2427 def add_message (self , message : Message ) -> Message :
2528 """
@@ -135,9 +138,140 @@ def create_error_message(self, error_message: str,
135138 @classmethod
136139 def from_dict (cls , data : Dict [str , Any ]) -> 'Conversation' :
137140 """Create a Conversation from a dictionary"""
141+ # Check if this is Google A2A format with careful detection
142+ if ("messages" in data and isinstance (data .get ("messages" ), list ) and
143+ data ["messages" ] and "parts" in data ["messages" ][0 ] and
144+ isinstance (data ["messages" ][0 ].get ("parts" ), list ) and
145+ "role" in data ["messages" ][0 ] and not "content" in data ["messages" ][0 ]):
146+ return cls .from_google_a2a (data )
147+
148+ # Standard python_a2a format
138149 messages = [Message .from_dict (m ) for m in data .get ("messages" , [])]
139150 return cls (
140151 conversation_id = data .get ("conversation_id" , str (uuid .uuid4 ())),
141152 messages = messages ,
142153 metadata = data .get ("metadata" )
143- )
154+ )
155+
156+ def to_dict (self ) -> Dict [str , Any ]:
157+ """Convert Conversation to dictionary representation"""
158+ # Use google format if compatibility mode is enabled
159+ if self ._GOOGLE_A2A_COMPATIBILITY :
160+ return self .to_google_a2a ()
161+
162+ # Standard python_a2a format
163+ result = {
164+ "conversation_id" : self .conversation_id ,
165+ "messages" : [message .to_dict () for message in self .messages ]
166+ }
167+
168+ if self .metadata :
169+ result ["metadata" ] = self .metadata
170+
171+ return result
172+
173+ @classmethod
174+ def from_google_a2a (cls , data : Dict [str , Any ]) -> 'Conversation' :
175+ """Create a Conversation from a Google A2A format dictionary
176+
177+ Args:
178+ data: A dictionary in Google A2A format
179+
180+ Returns:
181+ A Conversation object
182+ """
183+ if not ("messages" in data and isinstance (data .get ("messages" ), list )):
184+ raise ValueError ("Not a valid Google A2A format conversation" )
185+
186+ conversation_id = data .get ("conversation_id" , str (uuid .uuid4 ()))
187+
188+ # Process messages
189+ messages = []
190+ for msg_data in data .get ("messages" , []):
191+ # Skip invalid messages
192+ if not isinstance (msg_data , dict ):
193+ continue
194+
195+ # Try to convert from Google A2A format
196+ if "parts" in msg_data and "role" in msg_data and not "content" in msg_data :
197+ try :
198+ # Convert message from Google A2A format
199+ message = Message .from_google_a2a (msg_data )
200+
201+ # Set conversation_id if not already set
202+ if not message .conversation_id :
203+ message .conversation_id = conversation_id
204+
205+ messages .append (message )
206+ except Exception :
207+ # If conversion fails, skip this message
208+ continue
209+ else :
210+ # Try standard format as fallback
211+ try :
212+ message = Message .from_dict (msg_data )
213+
214+ # Set conversation_id if not already set
215+ if not message .conversation_id :
216+ message .conversation_id = conversation_id
217+
218+ messages .append (message )
219+ except Exception :
220+ # If parsing fails, skip this message
221+ continue
222+
223+ return cls (
224+ conversation_id = conversation_id ,
225+ messages = messages ,
226+ metadata = data .get ("metadata" )
227+ )
228+
229+ def to_google_a2a (self ) -> Dict [str , Any ]:
230+ """Convert to Google A2A format dictionary
231+
232+ Returns:
233+ A dictionary in Google A2A format
234+ """
235+ # Convert messages to Google A2A format
236+ google_messages = []
237+ for message in self .messages :
238+ # Convert message to Google A2A format
239+ try :
240+ google_messages .append (message .to_google_a2a ())
241+ except Exception :
242+ # Skip any messages that can't be converted
243+ continue
244+
245+ # Create the Google A2A conversation dict
246+ result = {
247+ "conversation_id" : self .conversation_id ,
248+ "messages" : google_messages
249+ }
250+
251+ if self .metadata :
252+ result ["metadata" ] = self .metadata
253+
254+ return result
255+
256+ @classmethod
257+ def enable_google_a2a_compatibility (cls , enable : bool = True ) -> None :
258+ """Enable or disable Google A2A compatibility mode
259+
260+ When enabled, to_dict() will output Google A2A format
261+
262+ Args:
263+ enable: Whether to enable compatibility mode
264+ """
265+ cls ._GOOGLE_A2A_COMPATIBILITY = enable
266+ # Also update Message class compatibility
267+ from .message import Message
268+ Message .enable_google_a2a_compatibility (enable )
269+
270+ @classmethod
271+ def is_google_a2a_compatibility_enabled (cls ) -> bool :
272+ """Check if Google A2A compatibility mode is enabled
273+
274+ Returns:
275+ True if enabled, False otherwise
276+ """
277+ return cls ._GOOGLE_A2A_COMPATIBILITY
0 commit comments