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.
- google/adk/agents/active_streaming_tool.py +1 -0
- google/adk/agents/base_agent.py +91 -47
- google/adk/agents/base_agent.py.orig +330 -0
- google/adk/agents/callback_context.py +4 -9
- google/adk/agents/invocation_context.py +1 -0
- google/adk/agents/langgraph_agent.py +1 -0
- google/adk/agents/live_request_queue.py +1 -0
- google/adk/agents/llm_agent.py +172 -35
- google/adk/agents/loop_agent.py +1 -1
- google/adk/agents/parallel_agent.py +7 -0
- google/adk/agents/readonly_context.py +7 -1
- google/adk/agents/run_config.py +5 -1
- google/adk/agents/sequential_agent.py +31 -0
- google/adk/agents/transcription_entry.py +5 -2
- google/adk/artifacts/base_artifact_service.py +5 -10
- google/adk/artifacts/gcs_artifact_service.py +9 -9
- google/adk/artifacts/in_memory_artifact_service.py +6 -6
- google/adk/auth/auth_credential.py +9 -5
- google/adk/auth/auth_preprocessor.py +7 -1
- google/adk/auth/auth_tool.py +3 -4
- google/adk/cli/agent_graph.py +5 -5
- google/adk/cli/browser/index.html +2 -2
- google/adk/cli/browser/{main-HWIBUY2R.js → main-QOEMUXM4.js} +58 -58
- google/adk/cli/cli.py +7 -7
- google/adk/cli/cli_deploy.py +7 -2
- google/adk/cli/cli_eval.py +181 -106
- google/adk/cli/cli_tools_click.py +147 -62
- google/adk/cli/fast_api.py +340 -158
- google/adk/cli/fast_api.py.orig +822 -0
- google/adk/cli/utils/common.py +23 -0
- google/adk/cli/utils/evals.py +83 -1
- google/adk/cli/utils/logs.py +13 -5
- google/adk/code_executors/__init__.py +3 -1
- google/adk/code_executors/built_in_code_executor.py +52 -0
- google/adk/evaluation/__init__.py +1 -1
- google/adk/evaluation/agent_evaluator.py +168 -128
- google/adk/evaluation/eval_case.py +102 -0
- google/adk/evaluation/eval_set.py +37 -0
- google/adk/evaluation/eval_sets_manager.py +42 -0
- google/adk/evaluation/evaluation_constants.py +1 -0
- google/adk/evaluation/evaluation_generator.py +89 -114
- google/adk/evaluation/evaluator.py +56 -0
- google/adk/evaluation/local_eval_sets_manager.py +264 -0
- google/adk/evaluation/response_evaluator.py +107 -3
- google/adk/evaluation/trajectory_evaluator.py +83 -2
- google/adk/events/event.py +7 -1
- google/adk/events/event_actions.py +7 -1
- google/adk/examples/example.py +1 -0
- google/adk/examples/example_util.py +3 -2
- google/adk/flows/__init__.py +0 -1
- google/adk/flows/llm_flows/_code_execution.py +19 -11
- google/adk/flows/llm_flows/audio_transcriber.py +4 -3
- google/adk/flows/llm_flows/base_llm_flow.py +86 -22
- google/adk/flows/llm_flows/basic.py +3 -0
- google/adk/flows/llm_flows/functions.py +10 -9
- google/adk/flows/llm_flows/instructions.py +28 -9
- google/adk/flows/llm_flows/single_flow.py +1 -1
- google/adk/memory/__init__.py +1 -1
- google/adk/memory/_utils.py +23 -0
- google/adk/memory/base_memory_service.py +25 -21
- google/adk/memory/base_memory_service.py.orig +76 -0
- google/adk/memory/in_memory_memory_service.py +59 -27
- google/adk/memory/memory_entry.py +37 -0
- google/adk/memory/vertex_ai_rag_memory_service.py +40 -17
- google/adk/models/anthropic_llm.py +36 -11
- google/adk/models/base_llm.py +45 -4
- google/adk/models/gemini_llm_connection.py +15 -2
- google/adk/models/google_llm.py +9 -44
- google/adk/models/google_llm.py.orig +305 -0
- google/adk/models/lite_llm.py +94 -38
- google/adk/models/llm_request.py +1 -1
- google/adk/models/llm_response.py +15 -3
- google/adk/models/registry.py +1 -1
- google/adk/runners.py +68 -44
- google/adk/sessions/__init__.py +1 -1
- google/adk/sessions/_session_util.py +14 -0
- google/adk/sessions/base_session_service.py +8 -32
- google/adk/sessions/database_session_service.py +58 -61
- google/adk/sessions/in_memory_session_service.py +108 -26
- google/adk/sessions/session.py +4 -0
- google/adk/sessions/vertex_ai_session_service.py +23 -45
- google/adk/telemetry.py +3 -0
- google/adk/tools/__init__.py +4 -7
- google/adk/tools/{built_in_code_execution_tool.py → _built_in_code_execution_tool.py} +11 -0
- google/adk/tools/_memory_entry_utils.py +30 -0
- google/adk/tools/agent_tool.py +16 -13
- google/adk/tools/apihub_tool/apihub_toolset.py +55 -74
- google/adk/tools/application_integration_tool/application_integration_toolset.py +107 -85
- google/adk/tools/application_integration_tool/clients/connections_client.py +29 -25
- google/adk/tools/application_integration_tool/clients/integration_client.py +6 -6
- google/adk/tools/application_integration_tool/integration_connector_tool.py +69 -26
- google/adk/tools/base_toolset.py +58 -0
- google/adk/tools/enterprise_search_tool.py +65 -0
- google/adk/tools/function_parameter_parse_util.py +2 -2
- google/adk/tools/google_api_tool/__init__.py +18 -70
- google/adk/tools/google_api_tool/google_api_tool.py +11 -5
- google/adk/tools/google_api_tool/google_api_toolset.py +126 -0
- google/adk/tools/google_api_tool/google_api_toolsets.py +102 -0
- google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +40 -42
- google/adk/tools/langchain_tool.py +96 -49
- google/adk/tools/load_artifacts_tool.py +4 -4
- google/adk/tools/load_memory_tool.py +16 -5
- google/adk/tools/mcp_tool/__init__.py +3 -2
- google/adk/tools/mcp_tool/conversion_utils.py +1 -1
- google/adk/tools/mcp_tool/mcp_session_manager.py +167 -16
- google/adk/tools/mcp_tool/mcp_session_manager.py.orig +322 -0
- google/adk/tools/mcp_tool/mcp_tool.py +12 -12
- google/adk/tools/mcp_tool/mcp_toolset.py +155 -195
- google/adk/tools/openapi_tool/common/common.py +2 -5
- google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +32 -7
- google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +43 -33
- google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +1 -1
- google/adk/tools/preload_memory_tool.py +27 -18
- google/adk/tools/retrieval/__init__.py +1 -1
- google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +1 -1
- google/adk/tools/tool_context.py +4 -4
- google/adk/tools/toolbox_toolset.py +79 -0
- google/adk/tools/transfer_to_agent_tool.py +0 -1
- google/adk/version.py +1 -1
- {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/METADATA +7 -5
- google_adk-1.0.0.dist-info/RECORD +195 -0
- google/adk/agents/remote_agent.py +0 -50
- google/adk/tools/google_api_tool/google_api_tool_set.py +0 -110
- google/adk/tools/google_api_tool/google_api_tool_sets.py +0 -112
- google/adk/tools/toolbox_tool.py +0 -46
- google_adk-0.4.0.dist-info/RECORD +0 -179
- {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/WHEEL +0 -0
- {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/entry_points.txt +0 -0
- {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/licenses/LICENSE +0 -0
google/adk/agents/llm_agent.py
CHANGED
@@ -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
|
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 =
|
52
|
-
|
63
|
+
BeforeModelCallback: TypeAlias = Union[
|
64
|
+
_SingleBeforeModelCallback,
|
65
|
+
list[_SingleBeforeModelCallback],
|
53
66
|
]
|
54
|
-
|
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
|
-
|
77
|
+
|
78
|
+
_SingleBeforeToolCallback: TypeAlias = Callable[
|
59
79
|
[BaseTool, dict[str, Any], ToolContext],
|
60
80
|
Union[Awaitable[Optional[dict]], Optional[dict]],
|
61
81
|
]
|
62
|
-
|
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
|
-
|
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
|
74
|
-
tool_union: ToolUnion,
|
75
|
-
) -> BaseTool:
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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,
|
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
|
-
"""
|
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
|
-
"""
|
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
|
-
"""
|
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
|
-
"""
|
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(
|
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
|
-
|
268
|
-
|
269
|
-
|
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
|
-
|
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
|
281
|
-
|
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
|
-
|
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:
|
google/adk/agents/loop_agent.py
CHANGED
@@ -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('
|
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."""
|
google/adk/agents/run_config.py
CHANGED
@@ -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 =
|
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):
|