@@ -122,6 +122,10 @@ class AgentConfig(_common.BaseModel):
122122 This ID is used to refer to this agent, e.g., in AgentEvent.author, or in
123123 the `sub_agents` field. It must be unique within the `agents` map.""" ,
124124 )
125+ agent_resource_name : Optional [str ] = Field (
126+ default = None ,
127+ description = """The Agent Engine resource name, formatted as `projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine_id}`.""" ,
128+ )
125129 agent_type : Optional [str ] = Field (
126130 default = None ,
127131 description = """The type or class of the agent (e.g., "LlmAgent", "RouterAgent",
@@ -160,6 +164,51 @@ class AgentConfig(_common.BaseModel):
160164 description = """A field containing instructions from the developer for the agent.""" ,
161165 )
162166
167+ @staticmethod
168+ def _get_tool_declarations_from_agent (agent : Any ) -> genai_types .ToolListUnion :
169+ """Gets tool declarations from an agent.
170+
171+ Args:
172+ agent: The agent to get the tool declarations from. Data type is google.adk.agents.LLMAgent type, use Any to avoid dependency on ADK.
173+
174+ Returns:
175+ The tool declarations of the agent.
176+ """
177+ tool_declarations : genai_types .ToolListUnion = []
178+ for tool in agent .tools :
179+ tool_declarations .append (
180+ {
181+ "function_declarations" : [
182+ genai_types .FunctionDeclaration .from_callable_with_api_option (
183+ callable = tool
184+ )
185+ ]
186+ }
187+ )
188+ return tool_declarations
189+
190+ @classmethod
191+ def from_agent (
192+ cls , agent : Any , agent_resource_name : Optional [str ] = None
193+ ) -> "AgentConfig" :
194+ """Creates an AgentConfig from an ADK agent object.
195+
196+ Args:
197+ agent: The agent to get the agent info from, data type is google.adk.agents.LLMAgent type, use Any to avoid dependency on ADK.
198+ agent_resource_name: Optional. The agent engine resource name.
199+
200+ Returns:
201+ An AgentConfig object populated with the agent's metadata.
202+ """
203+ return cls ( # pytype: disable=missing-parameter
204+ agent_id = getattr (agent , "name" , "default_agent" ) or "default_agent" ,
205+ agent_resource_name = agent_resource_name ,
206+ agent_type = agent .__class__ .__name__ ,
207+ description = getattr (agent , "description" , None ),
208+ instruction = getattr (agent , "instruction" , None ),
209+ tools = AgentConfig ._get_tool_declarations_from_agent (agent ),
210+ )
211+
163212
164213class AgentConfigDict (TypedDict , total = False ):
165214 """Represents configuration for an Agent."""
@@ -169,6 +218,9 @@ class AgentConfigDict(TypedDict, total=False):
169218 This ID is used to refer to this agent, e.g., in AgentEvent.author, or in
170219 the `sub_agents` field. It must be unique within the `agents` map."""
171220
221+ agent_resource_name : Optional [str ]
222+ """The Agent Engine resource name, formatted as `projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine_id}`."""
223+
172224 agent_type : Optional [str ]
173225 """The type or class of the agent (e.g., "LlmAgent", "RouterAgent",
174226 "ToolUseAgent"). Useful for the autorater to understand the expected
@@ -334,6 +386,98 @@ class AgentData(_common.BaseModel):
334386 )
335387 events : Optional [Events ] = Field (default = None , description = """A list of events.""" )
336388
389+ @classmethod
390+ def from_session (cls , agent : Any , session_history : list [Any ]) -> "AgentData" :
391+ """Creates an AgentData object from a session history.
392+
393+ Segments the flat list of session events into ConversationTurns. A new turn
394+ is initiated by a User message.
395+
396+ Args:
397+ agent: The agent instance used in the session.
398+ session_history: A list of raw events/messages from the session.
399+
400+ Returns:
401+ An AgentData object containing the segmented history and agent config.
402+ """
403+ agent_config = AgentConfig .from_agent (agent )
404+ agent_id = agent_config .agent_id or "default_agent"
405+ agents_map = {agent_id : agent_config }
406+
407+ turns = []
408+ current_turn_events = []
409+
410+ for event in session_history :
411+ is_user = False
412+ if isinstance (event , dict ):
413+ if event .get ("role" ) == "user" :
414+ is_user = True
415+ elif (
416+ isinstance (event .get ("content" ), dict )
417+ and event ["content" ].get ("role" ) == "user"
418+ ):
419+ is_user = True
420+ elif hasattr (event , "role" ) and event .role == "user" :
421+ is_user = True
422+
423+ if is_user and current_turn_events :
424+ turns .append (
425+ ConversationTurn ( # pytype: disable=missing-parameter
426+ turn_index = len (turns ),
427+ turn_id = f"turn_{ len (turns )} " ,
428+ events = current_turn_events ,
429+ )
430+ )
431+ current_turn_events = []
432+
433+ author = "user" if is_user else agent_id
434+
435+ content = None
436+ if isinstance (event , dict ):
437+ if "content" in event :
438+ raw_content = event ["content" ]
439+ if isinstance (raw_content , genai_types .Content ):
440+ content = raw_content
441+ elif isinstance (raw_content , dict ):
442+ try :
443+ content = genai_types .Content .model_validate (raw_content )
444+ except Exception as e :
445+ raise ValueError (
446+ f"Failed to validate Content from dictionary in session history: { raw_content } "
447+ ) from e
448+ elif isinstance (raw_content , str ):
449+ content = genai_types .Content (
450+ parts = [genai_types .Part (text = raw_content )]
451+ )
452+ elif "parts" in event :
453+ try :
454+ content = genai_types .Content .model_validate (event )
455+ except Exception as e :
456+ raise ValueError (
457+ f"Failed to validate Content from event with 'parts': { event } "
458+ ) from e
459+ elif hasattr (event , "content" ) and isinstance (
460+ event .content , genai_types .Content
461+ ):
462+ content = event .content
463+
464+ agent_event = AgentEvent ( # pytype: disable=missing-parameter
465+ author = author ,
466+ content = content ,
467+ )
468+ current_turn_events .append (agent_event )
469+
470+ if current_turn_events :
471+ turns .append (
472+ ConversationTurn ( # pytype: disable=missing-parameter
473+ turn_index = len (turns ),
474+ turn_id = f"turn_{ len (turns )} " ,
475+ events = current_turn_events ,
476+ )
477+ )
478+
479+ return cls (agents = agents_map , turns = turns ) # pytype: disable=missing-parameter
480+
337481
338482class AgentDataDict (TypedDict , total = False ):
339483 """Represents data specific to multi-turn agent evaluations."""
0 commit comments