google-adk 0.5.0__py3-none-any.whl → 1.1.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 (139) hide show
  1. google/adk/agents/base_agent.py +76 -30
  2. google/adk/agents/callback_context.py +2 -6
  3. google/adk/agents/llm_agent.py +122 -30
  4. google/adk/agents/loop_agent.py +1 -1
  5. google/adk/agents/parallel_agent.py +7 -0
  6. google/adk/agents/readonly_context.py +8 -0
  7. google/adk/agents/run_config.py +1 -1
  8. google/adk/agents/sequential_agent.py +31 -0
  9. google/adk/agents/transcription_entry.py +4 -2
  10. google/adk/artifacts/gcs_artifact_service.py +1 -1
  11. google/adk/artifacts/in_memory_artifact_service.py +1 -1
  12. google/adk/auth/auth_credential.py +10 -2
  13. google/adk/auth/auth_preprocessor.py +7 -1
  14. google/adk/auth/auth_tool.py +3 -4
  15. google/adk/cli/agent_graph.py +5 -5
  16. google/adk/cli/browser/index.html +4 -4
  17. google/adk/cli/browser/{main-ULN5R5I5.js → main-PKDNKWJE.js} +59 -60
  18. google/adk/cli/browser/polyfills-B6TNHZQ6.js +17 -0
  19. google/adk/cli/cli.py +10 -9
  20. google/adk/cli/cli_deploy.py +7 -2
  21. google/adk/cli/cli_eval.py +109 -115
  22. google/adk/cli/cli_tools_click.py +179 -67
  23. google/adk/cli/fast_api.py +248 -197
  24. google/adk/cli/utils/agent_loader.py +137 -0
  25. google/adk/cli/utils/cleanup.py +40 -0
  26. google/adk/cli/utils/common.py +23 -0
  27. google/adk/cli/utils/evals.py +83 -0
  28. google/adk/cli/utils/logs.py +8 -5
  29. google/adk/code_executors/__init__.py +3 -1
  30. google/adk/code_executors/built_in_code_executor.py +52 -0
  31. google/adk/code_executors/code_execution_utils.py +2 -1
  32. google/adk/code_executors/container_code_executor.py +0 -1
  33. google/adk/code_executors/vertex_ai_code_executor.py +6 -8
  34. google/adk/evaluation/__init__.py +1 -1
  35. google/adk/evaluation/agent_evaluator.py +168 -128
  36. google/adk/evaluation/eval_case.py +104 -0
  37. google/adk/evaluation/eval_metrics.py +74 -0
  38. google/adk/evaluation/eval_result.py +86 -0
  39. google/adk/evaluation/eval_set.py +39 -0
  40. google/adk/evaluation/eval_set_results_manager.py +47 -0
  41. google/adk/evaluation/eval_sets_manager.py +43 -0
  42. google/adk/evaluation/evaluation_generator.py +88 -113
  43. google/adk/evaluation/evaluator.py +58 -0
  44. google/adk/evaluation/local_eval_set_results_manager.py +113 -0
  45. google/adk/evaluation/local_eval_sets_manager.py +264 -0
  46. google/adk/evaluation/response_evaluator.py +106 -1
  47. google/adk/evaluation/trajectory_evaluator.py +84 -2
  48. google/adk/events/event.py +6 -1
  49. google/adk/events/event_actions.py +6 -1
  50. google/adk/examples/base_example_provider.py +1 -0
  51. google/adk/examples/example_util.py +3 -2
  52. google/adk/flows/llm_flows/_code_execution.py +9 -1
  53. google/adk/flows/llm_flows/audio_transcriber.py +4 -3
  54. google/adk/flows/llm_flows/base_llm_flow.py +58 -21
  55. google/adk/flows/llm_flows/contents.py +3 -1
  56. google/adk/flows/llm_flows/functions.py +9 -8
  57. google/adk/flows/llm_flows/instructions.py +18 -80
  58. google/adk/flows/llm_flows/single_flow.py +2 -2
  59. google/adk/memory/__init__.py +1 -1
  60. google/adk/memory/_utils.py +23 -0
  61. google/adk/memory/base_memory_service.py +23 -21
  62. google/adk/memory/in_memory_memory_service.py +57 -25
  63. google/adk/memory/memory_entry.py +37 -0
  64. google/adk/memory/vertex_ai_rag_memory_service.py +38 -15
  65. google/adk/models/anthropic_llm.py +16 -9
  66. google/adk/models/base_llm.py +2 -1
  67. google/adk/models/base_llm_connection.py +2 -0
  68. google/adk/models/gemini_llm_connection.py +11 -11
  69. google/adk/models/google_llm.py +12 -2
  70. google/adk/models/lite_llm.py +80 -23
  71. google/adk/models/llm_response.py +16 -3
  72. google/adk/models/registry.py +1 -1
  73. google/adk/runners.py +98 -42
  74. google/adk/sessions/__init__.py +1 -1
  75. google/adk/sessions/_session_util.py +2 -1
  76. google/adk/sessions/base_session_service.py +6 -33
  77. google/adk/sessions/database_session_service.py +57 -67
  78. google/adk/sessions/in_memory_session_service.py +106 -24
  79. google/adk/sessions/session.py +3 -0
  80. google/adk/sessions/vertex_ai_session_service.py +44 -51
  81. google/adk/telemetry.py +7 -2
  82. google/adk/tools/__init__.py +4 -7
  83. google/adk/tools/_memory_entry_utils.py +30 -0
  84. google/adk/tools/agent_tool.py +10 -10
  85. google/adk/tools/apihub_tool/apihub_toolset.py +55 -74
  86. google/adk/tools/apihub_tool/clients/apihub_client.py +10 -3
  87. google/adk/tools/apihub_tool/clients/secret_client.py +1 -0
  88. google/adk/tools/application_integration_tool/application_integration_toolset.py +111 -85
  89. google/adk/tools/application_integration_tool/clients/connections_client.py +28 -1
  90. google/adk/tools/application_integration_tool/clients/integration_client.py +7 -5
  91. google/adk/tools/application_integration_tool/integration_connector_tool.py +69 -26
  92. google/adk/tools/base_toolset.py +96 -0
  93. google/adk/tools/bigquery/__init__.py +28 -0
  94. google/adk/tools/bigquery/bigquery_credentials.py +216 -0
  95. google/adk/tools/bigquery/bigquery_tool.py +116 -0
  96. google/adk/tools/{built_in_code_execution_tool.py → enterprise_search_tool.py} +17 -11
  97. google/adk/tools/function_parameter_parse_util.py +9 -2
  98. google/adk/tools/function_tool.py +33 -3
  99. google/adk/tools/get_user_choice_tool.py +1 -0
  100. google/adk/tools/google_api_tool/__init__.py +24 -70
  101. google/adk/tools/google_api_tool/google_api_tool.py +12 -6
  102. google/adk/tools/google_api_tool/{google_api_tool_set.py → google_api_toolset.py} +57 -55
  103. google/adk/tools/google_api_tool/google_api_toolsets.py +108 -0
  104. google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +40 -42
  105. google/adk/tools/google_search_tool.py +2 -2
  106. google/adk/tools/langchain_tool.py +96 -49
  107. google/adk/tools/load_memory_tool.py +14 -5
  108. google/adk/tools/mcp_tool/__init__.py +3 -2
  109. google/adk/tools/mcp_tool/conversion_utils.py +6 -2
  110. google/adk/tools/mcp_tool/mcp_session_manager.py +80 -69
  111. google/adk/tools/mcp_tool/mcp_tool.py +35 -32
  112. google/adk/tools/mcp_tool/mcp_toolset.py +99 -194
  113. google/adk/tools/openapi_tool/auth/credential_exchangers/base_credential_exchanger.py +1 -3
  114. google/adk/tools/openapi_tool/auth/credential_exchangers/service_account_exchanger.py +6 -7
  115. google/adk/tools/openapi_tool/common/common.py +5 -1
  116. google/adk/tools/openapi_tool/openapi_spec_parser/__init__.py +7 -2
  117. google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +27 -7
  118. google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +36 -32
  119. google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py +11 -1
  120. google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +1 -1
  121. google/adk/tools/preload_memory_tool.py +27 -18
  122. google/adk/tools/retrieval/__init__.py +1 -1
  123. google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +1 -1
  124. google/adk/tools/toolbox_toolset.py +107 -0
  125. google/adk/tools/transfer_to_agent_tool.py +0 -1
  126. google/adk/utils/__init__.py +13 -0
  127. google/adk/utils/instructions_utils.py +131 -0
  128. google/adk/version.py +1 -1
  129. {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/METADATA +18 -19
  130. google_adk-1.1.0.dist-info/RECORD +200 -0
  131. google/adk/agents/remote_agent.py +0 -50
  132. google/adk/cli/browser/polyfills-FFHMD2TL.js +0 -18
  133. google/adk/cli/fast_api.py.orig +0 -728
  134. google/adk/tools/google_api_tool/google_api_tool_sets.py +0 -112
  135. google/adk/tools/toolbox_tool.py +0 -46
  136. google_adk-0.5.0.dist-info/RECORD +0 -180
  137. {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/WHEEL +0 -0
  138. {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/entry_points.txt +0 -0
  139. {google_adk-0.5.0.dist-info → google_adk-1.1.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,
@@ -14,7 +14,8 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- from typing import Optional, TYPE_CHECKING
17
+ from typing import Optional
18
+ from typing import TYPE_CHECKING
18
19
 
19
20
  from typing_extensions import override
20
21
 
@@ -60,11 +61,6 @@ class CallbackContext(ReadonlyContext):
60
61
  """
61
62
  return self._state
62
63
 
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
64
  async def load_artifact(
69
65
  self, filename: str, version: Optional[int] = None
70
66
  ) -> Optional[types.Part]:
@@ -14,8 +14,15 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ import inspect
17
18
  import logging
18
- from typing import Any, AsyncGenerator, Awaitable, Callable, Literal, Optional, Union
19
+ from typing import Any
20
+ from typing import AsyncGenerator
21
+ from typing import Awaitable
22
+ from typing import Callable
23
+ from typing import Literal
24
+ from typing import Optional
25
+ from typing import Union
19
26
 
20
27
  from google.genai import types
21
28
  from pydantic import BaseModel
@@ -38,6 +45,7 @@ from ..models.llm_response import LlmResponse
38
45
  from ..models.registry import LLMRegistry
39
46
  from ..planners.base_planner import BasePlanner
40
47
  from ..tools.base_tool import BaseTool
48
+ from ..tools.base_toolset import BaseToolset
41
49
  from ..tools.function_tool import FunctionTool
42
50
  from ..tools.tool_context import ToolContext
43
51
  from .base_agent import BaseAgent
@@ -45,7 +53,7 @@ from .callback_context import CallbackContext
45
53
  from .invocation_context import InvocationContext
46
54
  from .readonly_context import ReadonlyContext
47
55
 
48
- logger = logging.getLogger(__name__)
56
+ logger = logging.getLogger('google_adk.' + __name__)
49
57
 
50
58
  _SingleBeforeModelCallback: TypeAlias = Callable[
51
59
  [CallbackContext, LlmRequest],
@@ -67,29 +75,43 @@ AfterModelCallback: TypeAlias = Union[
67
75
  list[_SingleAfterModelCallback],
68
76
  ]
69
77
 
70
- BeforeToolCallback: TypeAlias = Callable[
78
+ _SingleBeforeToolCallback: TypeAlias = Callable[
71
79
  [BaseTool, dict[str, Any], ToolContext],
72
80
  Union[Awaitable[Optional[dict]], Optional[dict]],
73
81
  ]
74
- AfterToolCallback: TypeAlias = Callable[
82
+
83
+ BeforeToolCallback: TypeAlias = Union[
84
+ _SingleBeforeToolCallback,
85
+ list[_SingleBeforeToolCallback],
86
+ ]
87
+
88
+ _SingleAfterToolCallback: TypeAlias = Callable[
75
89
  [BaseTool, dict[str, Any], ToolContext, dict],
76
90
  Union[Awaitable[Optional[dict]], Optional[dict]],
77
91
  ]
78
92
 
79
- InstructionProvider: TypeAlias = Callable[[ReadonlyContext], str]
93
+ AfterToolCallback: TypeAlias = Union[
94
+ _SingleAfterToolCallback,
95
+ list[_SingleAfterToolCallback],
96
+ ]
80
97
 
81
- ToolUnion: TypeAlias = Union[Callable, BaseTool]
98
+ InstructionProvider: TypeAlias = Callable[
99
+ [ReadonlyContext], Union[str, Awaitable[str]]
100
+ ]
101
+
102
+ ToolUnion: TypeAlias = Union[Callable, BaseTool, BaseToolset]
82
103
  ExamplesUnion = Union[list[Example], BaseExampleProvider]
83
104
 
84
105
 
85
- def _convert_tool_union_to_tool(
86
- tool_union: ToolUnion,
87
- ) -> BaseTool:
88
- return (
89
- tool_union
90
- if isinstance(tool_union, BaseTool)
91
- else FunctionTool(tool_union)
92
- )
106
+ async def _convert_tool_union_to_tools(
107
+ tool_union: ToolUnion, ctx: ReadonlyContext
108
+ ) -> list[BaseTool]:
109
+ if isinstance(tool_union, BaseTool):
110
+ return [tool_union]
111
+ if isinstance(tool_union, Callable):
112
+ return [FunctionTool(func=tool_union)]
113
+
114
+ return await tool_union.get_tools(ctx)
93
115
 
94
116
 
95
117
  class LlmAgent(BaseAgent):
@@ -128,7 +150,12 @@ class LlmAgent(BaseAgent):
128
150
 
129
151
  # LLM-based agent transfer configs - Start
130
152
  disallow_transfer_to_parent: bool = False
131
- """Disallows LLM-controlled transferring to the parent agent."""
153
+ """Disallows LLM-controlled transferring to the parent agent.
154
+
155
+ NOTE: Setting this as True also prevents this agent to continue reply to the
156
+ end-user. This behavior prevents one-way transfer, in which end-user may be
157
+ stuck with one agent that cannot transfer to other agents in the agent tree.
158
+ """
132
159
  disallow_transfer_to_peers: bool = False
133
160
  """Disallows LLM-controlled transferring to the peer agents."""
134
161
  # LLM-based agent transfer configs - End
@@ -173,8 +200,7 @@ class LlmAgent(BaseAgent):
173
200
 
174
201
  Check out available code executions in `google.adk.code_executor` package.
175
202
 
176
- NOTE: to use model's built-in code executor, don't set this field, add
177
- `google.adk.tools.built_in_code_execution` to tools instead.
203
+ NOTE: to use model's built-in code executor, use the `BuiltInCodeExecutor`.
178
204
  """
179
205
  # Advance features - End
180
206
 
@@ -214,7 +240,10 @@ class LlmAgent(BaseAgent):
214
240
  will be ignored and the provided content will be returned to user.
215
241
  """
216
242
  before_tool_callback: Optional[BeforeToolCallback] = None
217
- """Called before the tool is called.
243
+ """Callback or list of callbacks to be called before calling the tool.
244
+
245
+ When a list of callbacks is provided, the callbacks will be called in the
246
+ order they are listed until a callback does not return None.
218
247
 
219
248
  Args:
220
249
  tool: The tool to be called.
@@ -226,7 +255,10 @@ class LlmAgent(BaseAgent):
226
255
  the framework will skip calling the actual tool.
227
256
  """
228
257
  after_tool_callback: Optional[AfterToolCallback] = None
229
- """Called after the tool is called.
258
+ """Callback or list of callbacks to be called after calling the tool.
259
+
260
+ When a list of callbacks is provided, the callbacks will be called in the
261
+ order they are listed until a callback does not return None.
230
262
 
231
263
  Args:
232
264
  tool: The tool to be called.
@@ -275,33 +307,65 @@ class LlmAgent(BaseAgent):
275
307
  ancestor_agent = ancestor_agent.parent_agent
276
308
  raise ValueError(f'No model found for {self.name}.')
277
309
 
278
- def canonical_instruction(self, ctx: ReadonlyContext) -> str:
310
+ async def canonical_instruction(
311
+ self, ctx: ReadonlyContext
312
+ ) -> tuple[str, bool]:
279
313
  """The resolved self.instruction field to construct instruction for this agent.
280
314
 
281
315
  This method is only for use by Agent Development Kit.
316
+
317
+ Args:
318
+ ctx: The context to retrieve the session state.
319
+
320
+ Returns:
321
+ A tuple of (instruction, bypass_state_injection).
322
+ instruction: The resolved self.instruction field.
323
+ bypass_state_injection: Whether the instruction is based on
324
+ InstructionProvider.
282
325
  """
283
326
  if isinstance(self.instruction, str):
284
- return self.instruction
327
+ return self.instruction, False
285
328
  else:
286
- return self.instruction(ctx)
287
-
288
- def canonical_global_instruction(self, ctx: ReadonlyContext) -> str:
329
+ instruction = self.instruction(ctx)
330
+ if inspect.isawaitable(instruction):
331
+ instruction = await instruction
332
+ return instruction, True
333
+
334
+ async def canonical_global_instruction(
335
+ self, ctx: ReadonlyContext
336
+ ) -> tuple[str, bool]:
289
337
  """The resolved self.instruction field to construct global instruction.
290
338
 
291
339
  This method is only for use by Agent Development Kit.
340
+
341
+ Args:
342
+ ctx: The context to retrieve the session state.
343
+
344
+ Returns:
345
+ A tuple of (instruction, bypass_state_injection).
346
+ instruction: The resolved self.global_instruction field.
347
+ bypass_state_injection: Whether the instruction is based on
348
+ InstructionProvider.
292
349
  """
293
350
  if isinstance(self.global_instruction, str):
294
- return self.global_instruction
351
+ return self.global_instruction, False
295
352
  else:
296
- return self.global_instruction(ctx)
353
+ global_instruction = self.global_instruction(ctx)
354
+ if inspect.isawaitable(global_instruction):
355
+ global_instruction = await global_instruction
356
+ return global_instruction, True
297
357
 
298
- @property
299
- def canonical_tools(self) -> list[BaseTool]:
300
- """The resolved self.tools field as a list of BaseTool.
358
+ async def canonical_tools(
359
+ self, ctx: ReadonlyContext = None
360
+ ) -> list[BaseTool]:
361
+ """The resolved self.tools field as a list of BaseTool based on the context.
301
362
 
302
363
  This method is only for use by Agent Development Kit.
303
364
  """
304
- return [_convert_tool_union_to_tool(tool) for tool in self.tools]
365
+ resolved_tools = []
366
+ for tool_union in self.tools:
367
+ resolved_tools.extend(await _convert_tool_union_to_tools(tool_union, ctx))
368
+ return resolved_tools
305
369
 
306
370
  @property
307
371
  def canonical_before_model_callbacks(
@@ -329,6 +393,34 @@ class LlmAgent(BaseAgent):
329
393
  return self.after_model_callback
330
394
  return [self.after_model_callback]
331
395
 
396
+ @property
397
+ def canonical_before_tool_callbacks(
398
+ self,
399
+ ) -> list[BeforeToolCallback]:
400
+ """The resolved self.before_tool_callback field as a list of BeforeToolCallback.
401
+
402
+ This method is only for use by Agent Development Kit.
403
+ """
404
+ if not self.before_tool_callback:
405
+ return []
406
+ if isinstance(self.before_tool_callback, list):
407
+ return self.before_tool_callback
408
+ return [self.before_tool_callback]
409
+
410
+ @property
411
+ def canonical_after_tool_callbacks(
412
+ self,
413
+ ) -> list[AfterToolCallback]:
414
+ """The resolved self.after_tool_callback field as a list of AfterToolCallback.
415
+
416
+ This method is only for use by Agent Development Kit.
417
+ """
418
+ if not self.after_tool_callback:
419
+ return []
420
+ if isinstance(self.after_tool_callback, list):
421
+ return self.after_tool_callback
422
+ return [self.after_tool_callback]
423
+
332
424
  @property
333
425
  def _llm_flow(self) -> BaseLlmFlow:
334
426
  if (
@@ -58,5 +58,5 @@ class LoopAgent(BaseAgent):
58
58
  async def _run_live_impl(
59
59
  self, ctx: InvocationContext
60
60
  ) -> AsyncGenerator[Event, None]:
61
- raise NotImplementedError('The behavior for run_live is not defined yet.')
61
+ raise NotImplementedError('This is not supported yet for LoopAgent.')
62
62
  yield # AsyncGenerator requires having at least one yield statement
@@ -94,3 +94,10 @@ class ParallelAgent(BaseAgent):
94
94
  agent_runs = [agent.run_async(ctx) for agent in self.sub_agents]
95
95
  async for event in _merge_agent_run(agent_runs):
96
96
  yield event
97
+
98
+ @override
99
+ async def _run_live_impl(
100
+ self, ctx: InvocationContext
101
+ ) -> AsyncGenerator[Event, None]:
102
+ raise NotImplementedError("This is not supported yet for ParallelAgent.")
103
+ yield # AsyncGenerator requires having at least one yield statement
@@ -16,9 +16,12 @@ from __future__ import annotations
16
16
 
17
17
  from types import MappingProxyType
18
18
  from typing import Any
19
+ from typing import Optional
19
20
  from typing import TYPE_CHECKING
20
21
 
21
22
  if TYPE_CHECKING:
23
+ from google.genai import types
24
+
22
25
  from .invocation_context import InvocationContext
23
26
 
24
27
 
@@ -30,6 +33,11 @@ class ReadonlyContext:
30
33
  ) -> None:
31
34
  self._invocation_context = invocation_context
32
35
 
36
+ @property
37
+ def user_content(self) -> Optional[types.Content]:
38
+ """The user content that started this invocation. READONLY field."""
39
+ return self._invocation_context.user_content
40
+
33
41
  @property
34
42
  def invocation_id(self) -> str:
35
43
  """The current invocation id."""
@@ -22,7 +22,7 @@ from pydantic import BaseModel
22
22
  from pydantic import ConfigDict
23
23
  from pydantic import field_validator
24
24
 
25
- logger = logging.getLogger(__name__)
25
+ logger = logging.getLogger('google_adk.' + __name__)
26
26
 
27
27
 
28
28
  class StreamingMode(Enum):
@@ -23,6 +23,7 @@ from typing_extensions import override
23
23
  from ..agents.invocation_context import InvocationContext
24
24
  from ..events.event import Event
25
25
  from .base_agent import BaseAgent
26
+ from .llm_agent import LlmAgent
26
27
 
27
28
 
28
29
  class SequentialAgent(BaseAgent):
@@ -40,6 +41,36 @@ class SequentialAgent(BaseAgent):
40
41
  async def _run_live_impl(
41
42
  self, ctx: InvocationContext
42
43
  ) -> AsyncGenerator[Event, None]:
44
+ """Implementation for live SequentialAgent.
45
+
46
+ Compared to non-live case, live agents process a continous streams of audio
47
+ or video, so it doesn't have a way to tell if it's finished and should pass
48
+ to next agent or not. So we introduce a task_compelted() function so the
49
+ model can call this function to signal that it's finished the task and we
50
+ can move on to next agent.
51
+
52
+ Args:
53
+ ctx: The invocation context of the agent.
54
+ """
55
+ # There is no way to know if it's using live during init phase so we have to init it here
56
+ for sub_agent in self.sub_agents:
57
+ # add tool
58
+ def task_completed():
59
+ """
60
+ Signals that the model has successfully completed the user's question
61
+ or task.
62
+ """
63
+ return "Task completion signaled."
64
+
65
+ if isinstance(sub_agent, LlmAgent):
66
+ # Use function name to dedupe.
67
+ if task_completed.__name__ not in sub_agent.tools:
68
+ sub_agent.tools.append(task_completed)
69
+ sub_agent.instruction += f"""If you finished the user' request
70
+ according to its description, call {task_completed.__name__} function
71
+ to exit so the next agents can take over. When calling this function,
72
+ do not generate any text other than the function call.'"""
73
+
43
74
  for sub_agent in self.sub_agents:
44
75
  async for event in sub_agent.run_live(ctx):
45
76
  yield event
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from typing import Optional
15
16
  from typing import Union
16
17
 
17
18
  from google.genai import types
@@ -28,8 +29,9 @@ class TranscriptionEntry(BaseModel):
28
29
  )
29
30
  """The pydantic model config."""
30
31
 
31
- role: str
32
- """The role that created this data, typically "user" or "model"""
32
+ role: Optional[str] = None
33
+ """The role that created this data, typically "user" or "model". For function
34
+ call, this is None."""
33
35
 
34
36
  data: Union[types.Blob, types.Content]
35
37
  """The data that can be used for transcription"""
@@ -23,7 +23,7 @@ from typing_extensions import override
23
23
 
24
24
  from .base_artifact_service import BaseArtifactService
25
25
 
26
- logger = logging.getLogger(__name__)
26
+ logger = logging.getLogger("google_adk." + __name__)
27
27
 
28
28
 
29
29
  class GcsArtifactService(BaseArtifactService):
@@ -24,7 +24,7 @@ from typing_extensions import override
24
24
 
25
25
  from .base_artifact_service import BaseArtifactService
26
26
 
27
- logger = logging.getLogger(__name__)
27
+ logger = logging.getLogger("google_adk." + __name__)
28
28
 
29
29
 
30
30
  class InMemoryArtifactService(BaseArtifactService, BaseModel):
@@ -13,15 +13,23 @@
13
13
  # limitations under the License.
14
14
 
15
15
  from enum import Enum
16
- from typing import Any, Dict, List, Optional
16
+ from typing import Any
17
+ from typing import Dict
18
+ from typing import List
19
+ from typing import Optional
17
20
 
21
+ from pydantic import alias_generators
18
22
  from pydantic import BaseModel
19
23
  from pydantic import ConfigDict
20
24
  from pydantic import Field
21
25
 
22
26
 
23
27
  class BaseModelWithConfig(BaseModel):
24
- model_config = ConfigDict(extra="allow")
28
+ model_config = ConfigDict(
29
+ extra="allow",
30
+ alias_generator=alias_generators.to_camel,
31
+ populate_by_name=True,
32
+ )
25
33
  """The pydantic model config."""
26
34
 
27
35
 
@@ -20,6 +20,7 @@ from typing import TYPE_CHECKING
20
20
  from typing_extensions import override
21
21
 
22
22
  from ..agents.invocation_context import InvocationContext
23
+ from ..agents.readonly_context import ReadonlyContext
23
24
  from ..events.event import Event
24
25
  from ..flows.llm_flows import functions
25
26
  from ..flows.llm_flows._base_llm_processor import BaseLlmRequestProcessor
@@ -105,7 +106,12 @@ class _AuthLlmRequestProcessor(BaseLlmRequestProcessor):
105
106
  function_response_event = await functions.handle_function_calls_async(
106
107
  invocation_context,
107
108
  event,
108
- {tool.name: tool for tool in agent.canonical_tools},
109
+ {
110
+ tool.name: tool
111
+ for tool in await agent.canonical_tools(
112
+ ReadonlyContext(invocation_context)
113
+ )
114
+ },
109
115
  # there could be parallel function calls that require auth
110
116
  # auth response would be a dict keyed by function call id
111
117
  tools_to_resume,
@@ -12,13 +12,12 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from pydantic import BaseModel
16
-
17
15
  from .auth_credential import AuthCredential
16
+ from .auth_credential import BaseModelWithConfig
18
17
  from .auth_schemes import AuthScheme
19
18
 
20
19
 
21
- class AuthConfig(BaseModel):
20
+ class AuthConfig(BaseModelWithConfig):
22
21
  """The auth config sent by tool asking client to collect auth credentials and
23
22
 
24
23
  adk and client will help to fill in the response
@@ -45,7 +44,7 @@ class AuthConfig(BaseModel):
45
44
  this field"""
46
45
 
47
46
 
48
- class AuthToolArguments(BaseModel):
47
+ class AuthToolArguments(BaseModelWithConfig):
49
48
  """the arguments for the special long running function tool that is used to
50
49
 
51
50
  request end user credentials.