google-adk 0.5.0__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. google/adk/agents/base_agent.py +76 -30
  2. google/adk/agents/base_agent.py.orig +330 -0
  3. google/adk/agents/callback_context.py +0 -5
  4. google/adk/agents/llm_agent.py +122 -30
  5. google/adk/agents/loop_agent.py +1 -1
  6. google/adk/agents/parallel_agent.py +7 -0
  7. google/adk/agents/readonly_context.py +7 -1
  8. google/adk/agents/run_config.py +1 -1
  9. google/adk/agents/sequential_agent.py +31 -0
  10. google/adk/agents/transcription_entry.py +4 -2
  11. google/adk/artifacts/gcs_artifact_service.py +1 -1
  12. google/adk/artifacts/in_memory_artifact_service.py +1 -1
  13. google/adk/auth/auth_credential.py +6 -1
  14. google/adk/auth/auth_preprocessor.py +7 -1
  15. google/adk/auth/auth_tool.py +3 -4
  16. google/adk/cli/agent_graph.py +5 -5
  17. google/adk/cli/browser/index.html +2 -2
  18. google/adk/cli/browser/{main-ULN5R5I5.js → main-QOEMUXM4.js} +44 -45
  19. google/adk/cli/cli.py +7 -7
  20. google/adk/cli/cli_deploy.py +7 -2
  21. google/adk/cli/cli_eval.py +172 -99
  22. google/adk/cli/cli_tools_click.py +147 -64
  23. google/adk/cli/fast_api.py +330 -148
  24. google/adk/cli/fast_api.py.orig +174 -80
  25. google/adk/cli/utils/common.py +23 -0
  26. google/adk/cli/utils/evals.py +83 -1
  27. google/adk/cli/utils/logs.py +13 -5
  28. google/adk/code_executors/__init__.py +3 -1
  29. google/adk/code_executors/built_in_code_executor.py +52 -0
  30. google/adk/evaluation/__init__.py +1 -1
  31. google/adk/evaluation/agent_evaluator.py +168 -128
  32. google/adk/evaluation/eval_case.py +102 -0
  33. google/adk/evaluation/eval_set.py +37 -0
  34. google/adk/evaluation/eval_sets_manager.py +42 -0
  35. google/adk/evaluation/evaluation_generator.py +88 -113
  36. google/adk/evaluation/evaluator.py +56 -0
  37. google/adk/evaluation/local_eval_sets_manager.py +264 -0
  38. google/adk/evaluation/response_evaluator.py +106 -2
  39. google/adk/evaluation/trajectory_evaluator.py +83 -2
  40. google/adk/events/event.py +6 -1
  41. google/adk/events/event_actions.py +6 -1
  42. google/adk/examples/example_util.py +3 -2
  43. google/adk/flows/llm_flows/_code_execution.py +9 -1
  44. google/adk/flows/llm_flows/audio_transcriber.py +4 -3
  45. google/adk/flows/llm_flows/base_llm_flow.py +54 -15
  46. google/adk/flows/llm_flows/functions.py +9 -8
  47. google/adk/flows/llm_flows/instructions.py +13 -5
  48. google/adk/flows/llm_flows/single_flow.py +1 -1
  49. google/adk/memory/__init__.py +1 -1
  50. google/adk/memory/_utils.py +23 -0
  51. google/adk/memory/base_memory_service.py +23 -21
  52. google/adk/memory/base_memory_service.py.orig +76 -0
  53. google/adk/memory/in_memory_memory_service.py +57 -25
  54. google/adk/memory/memory_entry.py +37 -0
  55. google/adk/memory/vertex_ai_rag_memory_service.py +38 -15
  56. google/adk/models/anthropic_llm.py +16 -9
  57. google/adk/models/gemini_llm_connection.py +11 -11
  58. google/adk/models/google_llm.py +9 -2
  59. google/adk/models/google_llm.py.orig +305 -0
  60. google/adk/models/lite_llm.py +77 -21
  61. google/adk/models/llm_response.py +14 -2
  62. google/adk/models/registry.py +1 -1
  63. google/adk/runners.py +65 -41
  64. google/adk/sessions/__init__.py +1 -1
  65. google/adk/sessions/base_session_service.py +6 -33
  66. google/adk/sessions/database_session_service.py +58 -65
  67. google/adk/sessions/in_memory_session_service.py +106 -24
  68. google/adk/sessions/session.py +3 -0
  69. google/adk/sessions/vertex_ai_session_service.py +23 -45
  70. google/adk/telemetry.py +3 -0
  71. google/adk/tools/__init__.py +4 -7
  72. google/adk/tools/{built_in_code_execution_tool.py → _built_in_code_execution_tool.py} +11 -0
  73. google/adk/tools/_memory_entry_utils.py +30 -0
  74. google/adk/tools/agent_tool.py +9 -9
  75. google/adk/tools/apihub_tool/apihub_toolset.py +55 -74
  76. google/adk/tools/application_integration_tool/application_integration_toolset.py +107 -85
  77. google/adk/tools/application_integration_tool/clients/connections_client.py +20 -0
  78. google/adk/tools/application_integration_tool/clients/integration_client.py +6 -6
  79. google/adk/tools/application_integration_tool/integration_connector_tool.py +69 -26
  80. google/adk/tools/base_toolset.py +58 -0
  81. google/adk/tools/enterprise_search_tool.py +65 -0
  82. google/adk/tools/function_parameter_parse_util.py +2 -2
  83. google/adk/tools/google_api_tool/__init__.py +18 -70
  84. google/adk/tools/google_api_tool/google_api_tool.py +11 -5
  85. google/adk/tools/google_api_tool/google_api_toolset.py +126 -0
  86. google/adk/tools/google_api_tool/google_api_toolsets.py +102 -0
  87. google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +40 -42
  88. google/adk/tools/langchain_tool.py +96 -49
  89. google/adk/tools/load_memory_tool.py +14 -5
  90. google/adk/tools/mcp_tool/__init__.py +3 -2
  91. google/adk/tools/mcp_tool/mcp_session_manager.py +153 -16
  92. google/adk/tools/mcp_tool/mcp_session_manager.py.orig +322 -0
  93. google/adk/tools/mcp_tool/mcp_tool.py +12 -12
  94. google/adk/tools/mcp_tool/mcp_toolset.py +155 -195
  95. google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +32 -7
  96. google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +31 -31
  97. google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +1 -1
  98. google/adk/tools/preload_memory_tool.py +27 -18
  99. google/adk/tools/retrieval/__init__.py +1 -1
  100. google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +1 -1
  101. google/adk/tools/toolbox_toolset.py +79 -0
  102. google/adk/tools/transfer_to_agent_tool.py +0 -1
  103. google/adk/version.py +1 -1
  104. {google_adk-0.5.0.dist-info → google_adk-1.0.0.dist-info}/METADATA +7 -5
  105. google_adk-1.0.0.dist-info/RECORD +195 -0
  106. google/adk/agents/remote_agent.py +0 -50
  107. google/adk/tools/google_api_tool/google_api_tool_set.py +0 -110
  108. google/adk/tools/google_api_tool/google_api_tool_sets.py +0 -112
  109. google/adk/tools/toolbox_tool.py +0 -46
  110. google_adk-0.5.0.dist-info/RECORD +0 -180
  111. {google_adk-0.5.0.dist-info → google_adk-1.0.0.dist-info}/WHEEL +0 -0
  112. {google_adk-0.5.0.dist-info → google_adk-1.0.0.dist-info}/entry_points.txt +0 -0
  113. {google_adk-0.5.0.dist-info → google_adk-1.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -15,12 +15,14 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import inspect
18
- from typing import Any, Awaitable, Union
18
+ from typing import Any
19
19
  from typing import AsyncGenerator
20
+ from typing import Awaitable
20
21
  from typing import Callable
21
22
  from typing import final
22
23
  from typing import Optional
23
24
  from typing import TYPE_CHECKING
25
+ from typing import Union
24
26
 
25
27
  from google.genai import types
26
28
  from opentelemetry import trace
@@ -29,6 +31,7 @@ from pydantic import ConfigDict
29
31
  from pydantic import Field
30
32
  from pydantic import field_validator
31
33
  from typing_extensions import override
34
+ from typing_extensions import TypeAlias
32
35
 
33
36
  from ..events.event import Event
34
37
  from .callback_context import CallbackContext
@@ -38,14 +41,19 @@ if TYPE_CHECKING:
38
41
 
39
42
  tracer = trace.get_tracer('gcp.vertex.agent')
40
43
 
41
- BeforeAgentCallback = Callable[
44
+ _SingleAgentCallback: TypeAlias = Callable[
42
45
  [CallbackContext],
43
46
  Union[Awaitable[Optional[types.Content]], Optional[types.Content]],
44
47
  ]
45
48
 
46
- AfterAgentCallback = Callable[
47
- [CallbackContext],
48
- Union[Awaitable[Optional[types.Content]], Optional[types.Content]],
49
+ BeforeAgentCallback: TypeAlias = Union[
50
+ _SingleAgentCallback,
51
+ list[_SingleAgentCallback],
52
+ ]
53
+
54
+ AfterAgentCallback: TypeAlias = Union[
55
+ _SingleAgentCallback,
56
+ list[_SingleAgentCallback],
49
57
  ]
50
58
 
51
59
 
@@ -85,7 +93,10 @@ class BaseAgent(BaseModel):
85
93
  """The sub-agents of this agent."""
86
94
 
87
95
  before_agent_callback: Optional[BeforeAgentCallback] = None
88
- """Callback signature that is invoked before the agent run.
96
+ """Callback or list of callbacks to be invoked before the agent run.
97
+
98
+ When a list of callbacks is provided, the callbacks will be called in the
99
+ order they are listed until a callback does not return None.
89
100
 
90
101
  Args:
91
102
  callback_context: MUST be named 'callback_context' (enforced).
@@ -96,7 +107,10 @@ class BaseAgent(BaseModel):
96
107
  provided content will be returned to user.
97
108
  """
98
109
  after_agent_callback: Optional[AfterAgentCallback] = None
99
- """Callback signature that is invoked after the agent run.
110
+ """Callback or list of callbacks to be invoked after the agent run.
111
+
112
+ When a list of callbacks is provided, the callbacks will be called in the
113
+ order they are listed until a callback does not return None.
100
114
 
101
115
  Args:
102
116
  callback_context: MUST be named 'callback_context' (enforced).
@@ -236,6 +250,30 @@ class BaseAgent(BaseModel):
236
250
  invocation_context.branch = f'{parent_context.branch}.{self.name}'
237
251
  return invocation_context
238
252
 
253
+ @property
254
+ def canonical_before_agent_callbacks(self) -> list[_SingleAgentCallback]:
255
+ """The resolved self.before_agent_callback field as a list of _SingleAgentCallback.
256
+
257
+ This method is only for use by Agent Development Kit.
258
+ """
259
+ if not self.before_agent_callback:
260
+ return []
261
+ if isinstance(self.before_agent_callback, list):
262
+ return self.before_agent_callback
263
+ return [self.before_agent_callback]
264
+
265
+ @property
266
+ def canonical_after_agent_callbacks(self) -> list[_SingleAgentCallback]:
267
+ """The resolved self.after_agent_callback field as a list of _SingleAgentCallback.
268
+
269
+ This method is only for use by Agent Development Kit.
270
+ """
271
+ if not self.after_agent_callback:
272
+ return []
273
+ if isinstance(self.after_agent_callback, list):
274
+ return self.after_agent_callback
275
+ return [self.after_agent_callback]
276
+
239
277
  async def __handle_before_agent_callback(
240
278
  self, ctx: InvocationContext
241
279
  ) -> Optional[Event]:
@@ -246,27 +284,27 @@ class BaseAgent(BaseModel):
246
284
  """
247
285
  ret_event = None
248
286
 
249
- if not isinstance(self.before_agent_callback, Callable):
287
+ if not self.canonical_before_agent_callbacks:
250
288
  return ret_event
251
289
 
252
290
  callback_context = CallbackContext(ctx)
253
- before_agent_callback_content = self.before_agent_callback(
254
- callback_context=callback_context
255
- )
256
291
 
257
- if inspect.isawaitable(before_agent_callback_content):
258
- before_agent_callback_content = await before_agent_callback_content
259
-
260
- if before_agent_callback_content:
261
- ret_event = Event(
262
- invocation_id=ctx.invocation_id,
263
- author=self.name,
264
- branch=ctx.branch,
265
- content=before_agent_callback_content,
266
- actions=callback_context._event_actions,
292
+ for callback in self.canonical_before_agent_callbacks:
293
+ before_agent_callback_content = callback(
294
+ callback_context=callback_context
267
295
  )
268
- ctx.end_invocation = True
269
- return ret_event
296
+ if inspect.isawaitable(before_agent_callback_content):
297
+ before_agent_callback_content = await before_agent_callback_content
298
+ if before_agent_callback_content:
299
+ ret_event = Event(
300
+ invocation_id=ctx.invocation_id,
301
+ author=self.name,
302
+ branch=ctx.branch,
303
+ content=before_agent_callback_content,
304
+ actions=callback_context._event_actions,
305
+ )
306
+ ctx.end_invocation = True
307
+ return ret_event
270
308
 
271
309
  if callback_context.state.has_delta():
272
310
  ret_event = Event(
@@ -288,18 +326,26 @@ class BaseAgent(BaseModel):
288
326
  """
289
327
  ret_event = None
290
328
 
291
- if not isinstance(self.after_agent_callback, Callable):
329
+ if not self.canonical_after_agent_callbacks:
292
330
  return ret_event
293
331
 
294
332
  callback_context = CallbackContext(invocation_context)
295
- after_agent_callback_content = self.after_agent_callback(
296
- callback_context=callback_context
297
- )
298
333
 
299
- if inspect.isawaitable(after_agent_callback_content):
300
- after_agent_callback_content = await after_agent_callback_content
334
+ for callback in self.canonical_after_agent_callbacks:
335
+ after_agent_callback_content = callback(callback_context=callback_context)
336
+ if inspect.isawaitable(after_agent_callback_content):
337
+ after_agent_callback_content = await after_agent_callback_content
338
+ if after_agent_callback_content:
339
+ ret_event = Event(
340
+ invocation_id=invocation_context.invocation_id,
341
+ author=self.name,
342
+ branch=invocation_context.branch,
343
+ content=after_agent_callback_content,
344
+ actions=callback_context._event_actions,
345
+ )
346
+ return ret_event
301
347
 
302
- if after_agent_callback_content or callback_context.state.has_delta():
348
+ if callback_context.state.has_delta():
303
349
  ret_event = Event(
304
350
  invocation_id=invocation_context.invocation_id,
305
351
  author=self.name,
@@ -0,0 +1,330 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ from typing import Any
18
+ from typing import AsyncGenerator
19
+ from typing import Callable
20
+ from typing import final
21
+ from typing import Optional
22
+ from typing import TYPE_CHECKING
23
+
24
+ from google.genai import types
25
+ from opentelemetry import trace
26
+ from pydantic import BaseModel
27
+ from pydantic import ConfigDict
28
+ from pydantic import Field
29
+ from pydantic import field_validator
30
+ from typing_extensions import override
31
+
32
+ from ..events.event import Event
33
+ from .callback_context import CallbackContext
34
+
35
+ if TYPE_CHECKING:
36
+ from .invocation_context import InvocationContext
37
+
38
+ tracer = trace.get_tracer('gcp.vertex.agent')
39
+
40
+ BeforeAgentCallback = Callable[[CallbackContext], Optional[types.Content]]
41
+
42
+
43
+ AfterAgentCallback = Callable[[CallbackContext], Optional[types.Content]]
44
+
45
+
46
+ class BaseAgent(BaseModel):
47
+ """Base class for all agents in Agent Development Kit."""
48
+
49
+ model_config = ConfigDict(
50
+ arbitrary_types_allowed=True,
51
+ extra='forbid',
52
+ )
53
+
54
+ name: str
55
+ """The agent's name.
56
+
57
+ Agent name must be a Python identifier and unique within the agent tree.
58
+ Agent name cannot be "user", since it's reserved for end-user's input.
59
+ """
60
+
61
+ description: str = ''
62
+ """Description about the agent's capability.
63
+
64
+ The model uses this to determine whether to delegate control to the agent.
65
+ One-line description is enough and preferred.
66
+ """
67
+
68
+ parent_agent: Optional[BaseAgent] = Field(default=None, init=False)
69
+ """The parent agent of this agent.
70
+
71
+ Note that an agent can ONLY be added as sub-agent once.
72
+
73
+ If you want to add one agent twice as sub-agent, consider to create two agent
74
+ instances with identical config, but with different name and add them to the
75
+ agent tree.
76
+ """
77
+ sub_agents: list[BaseAgent] = Field(default_factory=list)
78
+ """The sub-agents of this agent."""
79
+
80
+ before_agent_callback: Optional[BeforeAgentCallback] = None
81
+ """Callback signature that is invoked before the agent run.
82
+
83
+ Args:
84
+ callback_context: MUST be named 'callback_context' (enforced).
85
+
86
+ Returns:
87
+ Optional[types.Content]: The content to return to the user.
88
+ When the content is present, the agent run will be skipped and the
89
+ provided content will be returned to user.
90
+ """
91
+ after_agent_callback: Optional[AfterAgentCallback] = None
92
+ """Callback signature that is invoked after the agent run.
93
+
94
+ Args:
95
+ callback_context: MUST be named 'callback_context' (enforced).
96
+
97
+ Returns:
98
+ Optional[types.Content]: The content to return to the user.
99
+ When the content is present, the provided content will be used as agent
100
+ response and appended to event history as agent response.
101
+ """
102
+
103
+ @final
104
+ async def run_async(
105
+ self,
106
+ parent_context: InvocationContext,
107
+ ) -> AsyncGenerator[Event, None]:
108
+ """Entry method to run an agent via text-based conversation.
109
+
110
+ Args:
111
+ parent_context: InvocationContext, the invocation context of the parent
112
+ agent.
113
+
114
+ Yields:
115
+ Event: the events generated by the agent.
116
+ """
117
+
118
+ with tracer.start_as_current_span(f'agent_run [{self.name}]'):
119
+ ctx = self._create_invocation_context(parent_context)
120
+
121
+ if event := self.__handle_before_agent_callback(ctx):
122
+ yield event
123
+ if ctx.end_invocation:
124
+ return
125
+
126
+ async for event in self._run_async_impl(ctx):
127
+ yield event
128
+
129
+ if ctx.end_invocation:
130
+ return
131
+
132
+ if event := self.__handle_after_agent_callback(ctx):
133
+ yield event
134
+
135
+ @final
136
+ async def run_live(
137
+ self,
138
+ parent_context: InvocationContext,
139
+ ) -> AsyncGenerator[Event, None]:
140
+ """Entry method to run an agent via video/audio-based conversation.
141
+
142
+ Args:
143
+ parent_context: InvocationContext, the invocation context of the parent
144
+ agent.
145
+
146
+ Yields:
147
+ Event: the events generated by the agent.
148
+ """
149
+ with tracer.start_as_current_span(f'agent_run [{self.name}]'):
150
+ ctx = self._create_invocation_context(parent_context)
151
+ # TODO(hangfei): support before/after_agent_callback
152
+
153
+ async for event in self._run_live_impl(ctx):
154
+ yield event
155
+
156
+ async def _run_async_impl(
157
+ self, ctx: InvocationContext
158
+ ) -> AsyncGenerator[Event, None]:
159
+ """Core logic to run this agent via text-based conversation.
160
+
161
+ Args:
162
+ ctx: InvocationContext, the invocation context for this agent.
163
+
164
+ Yields:
165
+ Event: the events generated by the agent.
166
+ """
167
+ raise NotImplementedError(
168
+ f'_run_async_impl for {type(self)} is not implemented.'
169
+ )
170
+ yield # AsyncGenerator requires having at least one yield statement
171
+
172
+ async def _run_live_impl(
173
+ self, ctx: InvocationContext
174
+ ) -> AsyncGenerator[Event, None]:
175
+ """Core logic to run this agent via video/audio-based conversation.
176
+
177
+ Args:
178
+ ctx: InvocationContext, the invocation context for this agent.
179
+
180
+ Yields:
181
+ Event: the events generated by the agent.
182
+ """
183
+ raise NotImplementedError(
184
+ f'_run_live_impl for {type(self)} is not implemented.'
185
+ )
186
+ yield # AsyncGenerator requires having at least one yield statement
187
+
188
+ @property
189
+ def root_agent(self) -> BaseAgent:
190
+ """Gets the root agent of this agent."""
191
+ root_agent = self
192
+ while root_agent.parent_agent is not None:
193
+ root_agent = root_agent.parent_agent
194
+ return root_agent
195
+
196
+ def find_agent(self, name: str) -> Optional[BaseAgent]:
197
+ """Finds the agent with the given name in this agent and its descendants.
198
+
199
+ Args:
200
+ name: The name of the agent to find.
201
+
202
+ Returns:
203
+ The agent with the matching name, or None if no such agent is found.
204
+ """
205
+ if self.name == name:
206
+ return self
207
+ return self.find_sub_agent(name)
208
+
209
+ def find_sub_agent(self, name: str) -> Optional[BaseAgent]:
210
+ """Finds the agent with the given name in this agent's descendants.
211
+
212
+ Args:
213
+ name: The name of the agent to find.
214
+
215
+ Returns:
216
+ The agent with the matching name, or None if no such agent is found.
217
+ """
218
+ for sub_agent in self.sub_agents:
219
+ if result := sub_agent.find_agent(name):
220
+ return result
221
+ return None
222
+
223
+ def _create_invocation_context(
224
+ self, parent_context: InvocationContext
225
+ ) -> InvocationContext:
226
+ """Creates a new invocation context for this agent."""
227
+ invocation_context = parent_context.model_copy(update={'agent': self})
228
+ if parent_context.branch:
229
+ invocation_context.branch = f'{parent_context.branch}.{self.name}'
230
+ return invocation_context
231
+
232
+ def __handle_before_agent_callback(
233
+ self, ctx: InvocationContext
234
+ ) -> Optional[Event]:
235
+ """Runs the before_agent_callback if it exists.
236
+
237
+ Returns:
238
+ Optional[Event]: an event if callback provides content or changed state.
239
+ """
240
+ ret_event = None
241
+
242
+ if not isinstance(self.before_agent_callback, Callable):
243
+ return ret_event
244
+
245
+ callback_context = CallbackContext(ctx)
246
+ before_agent_callback_content = self.before_agent_callback(
247
+ callback_context=callback_context
248
+ )
249
+
250
+ if before_agent_callback_content:
251
+ ret_event = Event(
252
+ invocation_id=ctx.invocation_id,
253
+ author=self.name,
254
+ branch=ctx.branch,
255
+ content=before_agent_callback_content,
256
+ actions=callback_context._event_actions,
257
+ )
258
+ ctx.end_invocation = True
259
+ return ret_event
260
+
261
+ if callback_context.state.has_delta():
262
+ ret_event = Event(
263
+ invocation_id=ctx.invocation_id,
264
+ author=self.name,
265
+ branch=ctx.branch,
266
+ actions=callback_context._event_actions,
267
+ )
268
+
269
+ return ret_event
270
+
271
+ def __handle_after_agent_callback(
272
+ self, invocation_context: InvocationContext
273
+ ) -> Optional[Event]:
274
+ """Runs the after_agent_callback if it exists.
275
+
276
+ Returns:
277
+ Optional[Event]: an event if callback provides content or changed state.
278
+ """
279
+ ret_event = None
280
+
281
+ if not isinstance(self.after_agent_callback, Callable):
282
+ return ret_event
283
+
284
+ callback_context = CallbackContext(invocation_context)
285
+ after_agent_callback_content = self.after_agent_callback(
286
+ callback_context=callback_context
287
+ )
288
+
289
+ if after_agent_callback_content or callback_context.state.has_delta():
290
+ ret_event = Event(
291
+ invocation_id=invocation_context.invocation_id,
292
+ author=self.name,
293
+ branch=invocation_context.branch,
294
+ content=after_agent_callback_content,
295
+ actions=callback_context._event_actions,
296
+ )
297
+
298
+ return ret_event
299
+
300
+ @override
301
+ def model_post_init(self, __context: Any) -> None:
302
+ self.__set_parent_agent_for_sub_agents()
303
+
304
+ @field_validator('name', mode='after')
305
+ @classmethod
306
+ def __validate_name(cls, value: str):
307
+ if not value.isidentifier():
308
+ raise ValueError(
309
+ f'Found invalid agent name: `{value}`.'
310
+ ' Agent name must be a valid identifier. It should start with a'
311
+ ' letter (a-z, A-Z) or an underscore (_), and can only contain'
312
+ ' letters, digits (0-9), and underscores.'
313
+ )
314
+ if value == 'user':
315
+ raise ValueError(
316
+ "Agent name cannot be `user`. `user` is reserved for end-user's"
317
+ ' input.'
318
+ )
319
+ return value
320
+
321
+ def __set_parent_agent_for_sub_agents(self) -> BaseAgent:
322
+ for sub_agent in self.sub_agents:
323
+ if sub_agent.parent_agent is not None:
324
+ raise ValueError(
325
+ f'Agent `{sub_agent.name}` already has a parent agent, current'
326
+ f' parent: `{sub_agent.parent_agent.name}`, trying to add:'
327
+ f' `{self.name}`'
328
+ )
329
+ sub_agent.parent_agent = self
330
+ return self
@@ -60,11 +60,6 @@ class CallbackContext(ReadonlyContext):
60
60
  """
61
61
  return self._state
62
62
 
63
- @property
64
- def user_content(self) -> Optional[types.Content]:
65
- """The user content that started this invocation. READONLY field."""
66
- return self._invocation_context.user_content
67
-
68
63
  async def load_artifact(
69
64
  self, filename: str, version: Optional[int] = None
70
65
  ) -> Optional[types.Part]: