google-adk 0.4.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 (129) hide show
  1. google/adk/agents/active_streaming_tool.py +1 -0
  2. google/adk/agents/base_agent.py +91 -47
  3. google/adk/agents/base_agent.py.orig +330 -0
  4. google/adk/agents/callback_context.py +4 -9
  5. google/adk/agents/invocation_context.py +1 -0
  6. google/adk/agents/langgraph_agent.py +1 -0
  7. google/adk/agents/live_request_queue.py +1 -0
  8. google/adk/agents/llm_agent.py +172 -35
  9. google/adk/agents/loop_agent.py +1 -1
  10. google/adk/agents/parallel_agent.py +7 -0
  11. google/adk/agents/readonly_context.py +7 -1
  12. google/adk/agents/run_config.py +5 -1
  13. google/adk/agents/sequential_agent.py +31 -0
  14. google/adk/agents/transcription_entry.py +5 -2
  15. google/adk/artifacts/base_artifact_service.py +5 -10
  16. google/adk/artifacts/gcs_artifact_service.py +9 -9
  17. google/adk/artifacts/in_memory_artifact_service.py +6 -6
  18. google/adk/auth/auth_credential.py +9 -5
  19. google/adk/auth/auth_preprocessor.py +7 -1
  20. google/adk/auth/auth_tool.py +3 -4
  21. google/adk/cli/agent_graph.py +5 -5
  22. google/adk/cli/browser/index.html +2 -2
  23. google/adk/cli/browser/{main-HWIBUY2R.js → main-QOEMUXM4.js} +58 -58
  24. google/adk/cli/cli.py +7 -7
  25. google/adk/cli/cli_deploy.py +7 -2
  26. google/adk/cli/cli_eval.py +181 -106
  27. google/adk/cli/cli_tools_click.py +147 -62
  28. google/adk/cli/fast_api.py +340 -158
  29. google/adk/cli/fast_api.py.orig +822 -0
  30. google/adk/cli/utils/common.py +23 -0
  31. google/adk/cli/utils/evals.py +83 -1
  32. google/adk/cli/utils/logs.py +13 -5
  33. google/adk/code_executors/__init__.py +3 -1
  34. google/adk/code_executors/built_in_code_executor.py +52 -0
  35. google/adk/evaluation/__init__.py +1 -1
  36. google/adk/evaluation/agent_evaluator.py +168 -128
  37. google/adk/evaluation/eval_case.py +102 -0
  38. google/adk/evaluation/eval_set.py +37 -0
  39. google/adk/evaluation/eval_sets_manager.py +42 -0
  40. google/adk/evaluation/evaluation_constants.py +1 -0
  41. google/adk/evaluation/evaluation_generator.py +89 -114
  42. google/adk/evaluation/evaluator.py +56 -0
  43. google/adk/evaluation/local_eval_sets_manager.py +264 -0
  44. google/adk/evaluation/response_evaluator.py +107 -3
  45. google/adk/evaluation/trajectory_evaluator.py +83 -2
  46. google/adk/events/event.py +7 -1
  47. google/adk/events/event_actions.py +7 -1
  48. google/adk/examples/example.py +1 -0
  49. google/adk/examples/example_util.py +3 -2
  50. google/adk/flows/__init__.py +0 -1
  51. google/adk/flows/llm_flows/_code_execution.py +19 -11
  52. google/adk/flows/llm_flows/audio_transcriber.py +4 -3
  53. google/adk/flows/llm_flows/base_llm_flow.py +86 -22
  54. google/adk/flows/llm_flows/basic.py +3 -0
  55. google/adk/flows/llm_flows/functions.py +10 -9
  56. google/adk/flows/llm_flows/instructions.py +28 -9
  57. google/adk/flows/llm_flows/single_flow.py +1 -1
  58. google/adk/memory/__init__.py +1 -1
  59. google/adk/memory/_utils.py +23 -0
  60. google/adk/memory/base_memory_service.py +25 -21
  61. google/adk/memory/base_memory_service.py.orig +76 -0
  62. google/adk/memory/in_memory_memory_service.py +59 -27
  63. google/adk/memory/memory_entry.py +37 -0
  64. google/adk/memory/vertex_ai_rag_memory_service.py +40 -17
  65. google/adk/models/anthropic_llm.py +36 -11
  66. google/adk/models/base_llm.py +45 -4
  67. google/adk/models/gemini_llm_connection.py +15 -2
  68. google/adk/models/google_llm.py +9 -44
  69. google/adk/models/google_llm.py.orig +305 -0
  70. google/adk/models/lite_llm.py +94 -38
  71. google/adk/models/llm_request.py +1 -1
  72. google/adk/models/llm_response.py +15 -3
  73. google/adk/models/registry.py +1 -1
  74. google/adk/runners.py +68 -44
  75. google/adk/sessions/__init__.py +1 -1
  76. google/adk/sessions/_session_util.py +14 -0
  77. google/adk/sessions/base_session_service.py +8 -32
  78. google/adk/sessions/database_session_service.py +58 -61
  79. google/adk/sessions/in_memory_session_service.py +108 -26
  80. google/adk/sessions/session.py +4 -0
  81. google/adk/sessions/vertex_ai_session_service.py +23 -45
  82. google/adk/telemetry.py +3 -0
  83. google/adk/tools/__init__.py +4 -7
  84. google/adk/tools/{built_in_code_execution_tool.py → _built_in_code_execution_tool.py} +11 -0
  85. google/adk/tools/_memory_entry_utils.py +30 -0
  86. google/adk/tools/agent_tool.py +16 -13
  87. google/adk/tools/apihub_tool/apihub_toolset.py +55 -74
  88. google/adk/tools/application_integration_tool/application_integration_toolset.py +107 -85
  89. google/adk/tools/application_integration_tool/clients/connections_client.py +29 -25
  90. google/adk/tools/application_integration_tool/clients/integration_client.py +6 -6
  91. google/adk/tools/application_integration_tool/integration_connector_tool.py +69 -26
  92. google/adk/tools/base_toolset.py +58 -0
  93. google/adk/tools/enterprise_search_tool.py +65 -0
  94. google/adk/tools/function_parameter_parse_util.py +2 -2
  95. google/adk/tools/google_api_tool/__init__.py +18 -70
  96. google/adk/tools/google_api_tool/google_api_tool.py +11 -5
  97. google/adk/tools/google_api_tool/google_api_toolset.py +126 -0
  98. google/adk/tools/google_api_tool/google_api_toolsets.py +102 -0
  99. google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +40 -42
  100. google/adk/tools/langchain_tool.py +96 -49
  101. google/adk/tools/load_artifacts_tool.py +4 -4
  102. google/adk/tools/load_memory_tool.py +16 -5
  103. google/adk/tools/mcp_tool/__init__.py +3 -2
  104. google/adk/tools/mcp_tool/conversion_utils.py +1 -1
  105. google/adk/tools/mcp_tool/mcp_session_manager.py +167 -16
  106. google/adk/tools/mcp_tool/mcp_session_manager.py.orig +322 -0
  107. google/adk/tools/mcp_tool/mcp_tool.py +12 -12
  108. google/adk/tools/mcp_tool/mcp_toolset.py +155 -195
  109. google/adk/tools/openapi_tool/common/common.py +2 -5
  110. google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +32 -7
  111. google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +43 -33
  112. google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +1 -1
  113. google/adk/tools/preload_memory_tool.py +27 -18
  114. google/adk/tools/retrieval/__init__.py +1 -1
  115. google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +1 -1
  116. google/adk/tools/tool_context.py +4 -4
  117. google/adk/tools/toolbox_toolset.py +79 -0
  118. google/adk/tools/transfer_to_agent_tool.py +0 -1
  119. google/adk/version.py +1 -1
  120. {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/METADATA +7 -5
  121. google_adk-1.0.0.dist-info/RECORD +195 -0
  122. google/adk/agents/remote_agent.py +0 -50
  123. google/adk/tools/google_api_tool/google_api_tool_set.py +0 -110
  124. google/adk/tools/google_api_tool/google_api_tool_sets.py +0 -112
  125. google/adk/tools/toolbox_tool.py +0 -46
  126. google_adk-0.4.0.dist-info/RECORD +0 -179
  127. {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/WHEEL +0 -0
  128. {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/entry_points.txt +0 -0
  129. {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -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,39 +53,65 @@ 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
 
58
+ _SingleBeforeModelCallback: TypeAlias = Callable[
59
+ [CallbackContext, LlmRequest],
60
+ Union[Awaitable[Optional[LlmResponse]], Optional[LlmResponse]],
61
+ ]
50
62
 
51
- BeforeModelCallback: TypeAlias = Callable[
52
- [CallbackContext, LlmRequest], Optional[LlmResponse]
63
+ BeforeModelCallback: TypeAlias = Union[
64
+ _SingleBeforeModelCallback,
65
+ list[_SingleBeforeModelCallback],
53
66
  ]
54
- AfterModelCallback: TypeAlias = Callable[
67
+
68
+ _SingleAfterModelCallback: TypeAlias = Callable[
55
69
  [CallbackContext, LlmResponse],
56
- Optional[LlmResponse],
70
+ Union[Awaitable[Optional[LlmResponse]], Optional[LlmResponse]],
71
+ ]
72
+
73
+ AfterModelCallback: TypeAlias = Union[
74
+ _SingleAfterModelCallback,
75
+ list[_SingleAfterModelCallback],
57
76
  ]
58
- BeforeToolCallback: TypeAlias = Callable[
77
+
78
+ _SingleBeforeToolCallback: TypeAlias = Callable[
59
79
  [BaseTool, dict[str, Any], ToolContext],
60
80
  Union[Awaitable[Optional[dict]], Optional[dict]],
61
81
  ]
62
- AfterToolCallback: TypeAlias = Callable[
82
+
83
+ BeforeToolCallback: TypeAlias = Union[
84
+ _SingleBeforeToolCallback,
85
+ list[_SingleBeforeToolCallback],
86
+ ]
87
+
88
+ _SingleAfterToolCallback: TypeAlias = Callable[
63
89
  [BaseTool, dict[str, Any], ToolContext, dict],
64
90
  Union[Awaitable[Optional[dict]], Optional[dict]],
65
91
  ]
66
92
 
67
- InstructionProvider: TypeAlias = Callable[[ReadonlyContext], str]
93
+ AfterToolCallback: TypeAlias = Union[
94
+ _SingleAfterToolCallback,
95
+ list[_SingleAfterToolCallback],
96
+ ]
97
+
98
+ InstructionProvider: TypeAlias = Callable[
99
+ [ReadonlyContext], Union[str, Awaitable[str]]
100
+ ]
68
101
 
69
- ToolUnion: TypeAlias = Union[Callable, BaseTool]
102
+ ToolUnion: TypeAlias = Union[Callable, BaseTool, BaseToolset]
70
103
  ExamplesUnion = Union[list[Example], BaseExampleProvider]
71
104
 
72
105
 
73
- def _convert_tool_union_to_tool(
74
- tool_union: ToolUnion,
75
- ) -> BaseTool:
76
- return (
77
- tool_union
78
- if isinstance(tool_union, BaseTool)
79
- else FunctionTool(tool_union)
80
- )
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)
81
115
 
82
116
 
83
117
  class LlmAgent(BaseAgent):
@@ -116,7 +150,12 @@ class LlmAgent(BaseAgent):
116
150
 
117
151
  # LLM-based agent transfer configs - Start
118
152
  disallow_transfer_to_parent: bool = False
119
- """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
+ """
120
159
  disallow_transfer_to_peers: bool = False
121
160
  """Disallows LLM-controlled transferring to the peer agents."""
122
161
  # LLM-based agent transfer configs - End
@@ -161,8 +200,7 @@ class LlmAgent(BaseAgent):
161
200
 
162
201
  Check out available code executions in `google.adk.code_executor` package.
163
202
 
164
- NOTE: to use model's built-in code executor, don't set this field, add
165
- `google.adk.tools.built_in_code_execution` to tools instead.
203
+ NOTE: to use model's built-in code executor, use the `BuiltInCodeExecutor`.
166
204
  """
167
205
  # Advance features - End
168
206
 
@@ -173,7 +211,11 @@ class LlmAgent(BaseAgent):
173
211
 
174
212
  # Callbacks - Start
175
213
  before_model_callback: Optional[BeforeModelCallback] = None
176
- """Called before calling the LLM.
214
+ """Callback or list of callbacks to be called before calling the LLM.
215
+
216
+ When a list of callbacks is provided, the callbacks will be called in the
217
+ order they are listed until a callback does not return None.
218
+
177
219
  Args:
178
220
  callback_context: CallbackContext,
179
221
  llm_request: LlmRequest, The raw model request. Callback can mutate the
@@ -184,7 +226,10 @@ class LlmAgent(BaseAgent):
184
226
  skipped and the provided content will be returned to user.
185
227
  """
186
228
  after_model_callback: Optional[AfterModelCallback] = None
187
- """Called after calling LLM.
229
+ """Callback or list of callbacks to be called after calling the LLM.
230
+
231
+ When a list of callbacks is provided, the callbacks will be called in the
232
+ order they are listed until a callback does not return None.
188
233
 
189
234
  Args:
190
235
  callback_context: CallbackContext,
@@ -195,7 +240,10 @@ class LlmAgent(BaseAgent):
195
240
  will be ignored and the provided content will be returned to user.
196
241
  """
197
242
  before_tool_callback: Optional[BeforeToolCallback] = None
198
- """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.
199
247
 
200
248
  Args:
201
249
  tool: The tool to be called.
@@ -207,7 +255,10 @@ class LlmAgent(BaseAgent):
207
255
  the framework will skip calling the actual tool.
208
256
  """
209
257
  after_tool_callback: Optional[AfterToolCallback] = None
210
- """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.
211
262
 
212
263
  Args:
213
264
  tool: The tool to be called.
@@ -256,33 +307,119 @@ class LlmAgent(BaseAgent):
256
307
  ancestor_agent = ancestor_agent.parent_agent
257
308
  raise ValueError(f'No model found for {self.name}.')
258
309
 
259
- def canonical_instruction(self, ctx: ReadonlyContext) -> str:
310
+ async def canonical_instruction(
311
+ self, ctx: ReadonlyContext
312
+ ) -> tuple[str, bool]:
260
313
  """The resolved self.instruction field to construct instruction for this agent.
261
314
 
262
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.
263
325
  """
264
326
  if isinstance(self.instruction, str):
265
- return self.instruction
327
+ return self.instruction, False
266
328
  else:
267
- return self.instruction(ctx)
268
-
269
- 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]:
270
337
  """The resolved self.instruction field to construct global instruction.
271
338
 
272
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.
273
349
  """
274
350
  if isinstance(self.global_instruction, str):
275
- return self.global_instruction
351
+ return self.global_instruction, False
276
352
  else:
277
- 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
357
+
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.
362
+
363
+ This method is only for use by Agent Development Kit.
364
+ """
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
369
+
370
+ @property
371
+ def canonical_before_model_callbacks(
372
+ self,
373
+ ) -> list[_SingleBeforeModelCallback]:
374
+ """The resolved self.before_model_callback field as a list of _SingleBeforeModelCallback.
375
+
376
+ This method is only for use by Agent Development Kit.
377
+ """
378
+ if not self.before_model_callback:
379
+ return []
380
+ if isinstance(self.before_model_callback, list):
381
+ return self.before_model_callback
382
+ return [self.before_model_callback]
383
+
384
+ @property
385
+ def canonical_after_model_callbacks(self) -> list[_SingleAfterModelCallback]:
386
+ """The resolved self.after_model_callback field as a list of _SingleAfterModelCallback.
387
+
388
+ This method is only for use by Agent Development Kit.
389
+ """
390
+ if not self.after_model_callback:
391
+ return []
392
+ if isinstance(self.after_model_callback, list):
393
+ return self.after_model_callback
394
+ return [self.after_model_callback]
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]
278
409
 
279
410
  @property
280
- def canonical_tools(self) -> list[BaseTool]:
281
- """The resolved self.tools field as a list of BaseTool.
411
+ def canonical_after_tool_callbacks(
412
+ self,
413
+ ) -> list[AfterToolCallback]:
414
+ """The resolved self.after_tool_callback field as a list of AfterToolCallback.
282
415
 
283
416
  This method is only for use by Agent Development Kit.
284
417
  """
285
- return [_convert_tool_union_to_tool(tool) for tool in self.tools]
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]
286
423
 
287
424
  @property
288
425
  def _llm_flow(self) -> BaseLlmFlow:
@@ -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
@@ -15,10 +15,11 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  from types import MappingProxyType
18
- from typing import Any
18
+ from typing import Any, Optional
19
19
  from typing import TYPE_CHECKING
20
20
 
21
21
  if TYPE_CHECKING:
22
+ from google.genai import types
22
23
  from .invocation_context import InvocationContext
23
24
 
24
25
 
@@ -30,6 +31,11 @@ class ReadonlyContext:
30
31
  ) -> None:
31
32
  self._invocation_context = invocation_context
32
33
 
34
+ @property
35
+ def user_content(self) -> Optional[types.Content]:
36
+ """The user content that started this invocation. READONLY field."""
37
+ return self._invocation_context.user_content
38
+
33
39
  @property
34
40
  def invocation_id(self) -> str:
35
41
  """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):
@@ -37,6 +37,7 @@ class RunConfig(BaseModel):
37
37
  model_config = ConfigDict(
38
38
  extra='forbid',
39
39
  )
40
+ """The pydantic model config."""
40
41
 
41
42
  speech_config: Optional[types.SpeechConfig] = None
42
43
  """Speech configuration for the live agent."""
@@ -64,6 +65,9 @@ class RunConfig(BaseModel):
64
65
  output_audio_transcription: Optional[types.AudioTranscriptionConfig] = None
65
66
  """Output transcription for live agents with audio response."""
66
67
 
68
+ input_audio_transcription: Optional[types.AudioTranscriptionConfig] = None
69
+ """Input transcription for live agents with audio input from user."""
70
+
67
71
  max_llm_calls: int = 500
68
72
  """
69
73
  A limit on the total number of llm calls for a given run.
@@ -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
@@ -26,9 +27,11 @@ class TranscriptionEntry(BaseModel):
26
27
  arbitrary_types_allowed=True,
27
28
  extra='forbid',
28
29
  )
30
+ """The pydantic model config."""
29
31
 
30
- role: str
31
- """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."""
32
35
 
33
36
  data: Union[types.Blob, types.Content]
34
37
  """The data that can be used for transcription"""
@@ -12,7 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- """Abstract base class for artifact services."""
16
15
 
17
16
  from abc import ABC
18
17
  from abc import abstractmethod
@@ -25,7 +24,7 @@ class BaseArtifactService(ABC):
25
24
  """Abstract base class for artifact services."""
26
25
 
27
26
  @abstractmethod
28
- def save_artifact(
27
+ async def save_artifact(
29
28
  self,
30
29
  *,
31
30
  app_name: str,
@@ -53,7 +52,7 @@ class BaseArtifactService(ABC):
53
52
  """
54
53
 
55
54
  @abstractmethod
56
- def load_artifact(
55
+ async def load_artifact(
57
56
  self,
58
57
  *,
59
58
  app_name: str,
@@ -78,10 +77,9 @@ class BaseArtifactService(ABC):
78
77
  Returns:
79
78
  The artifact or None if not found.
80
79
  """
81
- pass
82
80
 
83
81
  @abstractmethod
84
- def list_artifact_keys(
82
+ async def list_artifact_keys(
85
83
  self, *, app_name: str, user_id: str, session_id: str
86
84
  ) -> list[str]:
87
85
  """Lists all the artifact filenames within a session.
@@ -94,10 +92,9 @@ class BaseArtifactService(ABC):
94
92
  Returns:
95
93
  A list of all artifact filenames within a session.
96
94
  """
97
- pass
98
95
 
99
96
  @abstractmethod
100
- def delete_artifact(
97
+ async def delete_artifact(
101
98
  self, *, app_name: str, user_id: str, session_id: str, filename: str
102
99
  ) -> None:
103
100
  """Deletes an artifact.
@@ -108,10 +105,9 @@ class BaseArtifactService(ABC):
108
105
  session_id: The ID of the session.
109
106
  filename: The name of the artifact file.
110
107
  """
111
- pass
112
108
 
113
109
  @abstractmethod
114
- def list_versions(
110
+ async def list_versions(
115
111
  self, *, app_name: str, user_id: str, session_id: str, filename: str
116
112
  ) -> list[int]:
117
113
  """Lists all versions of an artifact.
@@ -125,4 +121,3 @@ class BaseArtifactService(ABC):
125
121
  Returns:
126
122
  A list of all available versions of the artifact.
127
123
  """
128
- pass
@@ -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):
@@ -77,7 +77,7 @@ class GcsArtifactService(BaseArtifactService):
77
77
  return f"{app_name}/{user_id}/{session_id}/{filename}/{version}"
78
78
 
79
79
  @override
80
- def save_artifact(
80
+ async def save_artifact(
81
81
  self,
82
82
  *,
83
83
  app_name: str,
@@ -86,7 +86,7 @@ class GcsArtifactService(BaseArtifactService):
86
86
  filename: str,
87
87
  artifact: types.Part,
88
88
  ) -> int:
89
- versions = self.list_versions(
89
+ versions = await self.list_versions(
90
90
  app_name=app_name,
91
91
  user_id=user_id,
92
92
  session_id=session_id,
@@ -107,7 +107,7 @@ class GcsArtifactService(BaseArtifactService):
107
107
  return version
108
108
 
109
109
  @override
110
- def load_artifact(
110
+ async def load_artifact(
111
111
  self,
112
112
  *,
113
113
  app_name: str,
@@ -117,7 +117,7 @@ class GcsArtifactService(BaseArtifactService):
117
117
  version: Optional[int] = None,
118
118
  ) -> Optional[types.Part]:
119
119
  if version is None:
120
- versions = self.list_versions(
120
+ versions = await self.list_versions(
121
121
  app_name=app_name,
122
122
  user_id=user_id,
123
123
  session_id=session_id,
@@ -141,7 +141,7 @@ class GcsArtifactService(BaseArtifactService):
141
141
  return artifact
142
142
 
143
143
  @override
144
- def list_artifact_keys(
144
+ async def list_artifact_keys(
145
145
  self, *, app_name: str, user_id: str, session_id: str
146
146
  ) -> list[str]:
147
147
  filenames = set()
@@ -165,10 +165,10 @@ class GcsArtifactService(BaseArtifactService):
165
165
  return sorted(list(filenames))
166
166
 
167
167
  @override
168
- def delete_artifact(
168
+ async def delete_artifact(
169
169
  self, *, app_name: str, user_id: str, session_id: str, filename: str
170
170
  ) -> None:
171
- versions = self.list_versions(
171
+ versions = await self.list_versions(
172
172
  app_name=app_name,
173
173
  user_id=user_id,
174
174
  session_id=session_id,
@@ -183,7 +183,7 @@ class GcsArtifactService(BaseArtifactService):
183
183
  return
184
184
 
185
185
  @override
186
- def list_versions(
186
+ async def list_versions(
187
187
  self, *, app_name: str, user_id: str, session_id: str, filename: str
188
188
  ) -> list[int]:
189
189
  prefix = self._get_blob_name(app_name, user_id, session_id, filename, "")
@@ -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):
@@ -63,7 +63,7 @@ class InMemoryArtifactService(BaseArtifactService, BaseModel):
63
63
  return f"{app_name}/{user_id}/{session_id}/{filename}"
64
64
 
65
65
  @override
66
- def save_artifact(
66
+ async def save_artifact(
67
67
  self,
68
68
  *,
69
69
  app_name: str,
@@ -80,7 +80,7 @@ class InMemoryArtifactService(BaseArtifactService, BaseModel):
80
80
  return version
81
81
 
82
82
  @override
83
- def load_artifact(
83
+ async def load_artifact(
84
84
  self,
85
85
  *,
86
86
  app_name: str,
@@ -98,7 +98,7 @@ class InMemoryArtifactService(BaseArtifactService, BaseModel):
98
98
  return versions[version]
99
99
 
100
100
  @override
101
- def list_artifact_keys(
101
+ async def list_artifact_keys(
102
102
  self, *, app_name: str, user_id: str, session_id: str
103
103
  ) -> list[str]:
104
104
  session_prefix = f"{app_name}/{user_id}/{session_id}/"
@@ -114,7 +114,7 @@ class InMemoryArtifactService(BaseArtifactService, BaseModel):
114
114
  return sorted(filenames)
115
115
 
116
116
  @override
117
- def delete_artifact(
117
+ async def delete_artifact(
118
118
  self, *, app_name: str, user_id: str, session_id: str, filename: str
119
119
  ) -> None:
120
120
  path = self._artifact_path(app_name, user_id, session_id, filename)
@@ -123,7 +123,7 @@ class InMemoryArtifactService(BaseArtifactService, BaseModel):
123
123
  self.artifacts.pop(path, None)
124
124
 
125
125
  @override
126
- def list_versions(
126
+ async def list_versions(
127
127
  self, *, app_name: str, user_id: str, session_id: str, filename: str
128
128
  ) -> list[int]:
129
129
  path = self._artifact_path(app_name, user_id, session_id, filename)
@@ -13,17 +13,21 @@
13
13
  # limitations under the License.
14
14
 
15
15
  from enum import Enum
16
- from typing import Any
17
- from typing import Dict
18
- from typing import List
19
- from typing import Optional
16
+ from typing import Any, Dict, List, Optional
20
17
 
18
+ from pydantic import alias_generators
21
19
  from pydantic import BaseModel
20
+ from pydantic import ConfigDict
22
21
  from pydantic import Field
23
22
 
24
23
 
25
24
  class BaseModelWithConfig(BaseModel):
26
- model_config = {"extra": "allow"}
25
+ model_config = ConfigDict(
26
+ extra="allow",
27
+ alias_generator=alias_generators.to_camel,
28
+ populate_by_name=True,
29
+ )
30
+ """The pydantic model config."""
27
31
 
28
32
 
29
33
  class HttpCredentials(BaseModelWithConfig):