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.
- google/adk/agents/base_agent.py +76 -30
- google/adk/agents/callback_context.py +2 -6
- google/adk/agents/llm_agent.py +122 -30
- google/adk/agents/loop_agent.py +1 -1
- google/adk/agents/parallel_agent.py +7 -0
- google/adk/agents/readonly_context.py +8 -0
- google/adk/agents/run_config.py +1 -1
- google/adk/agents/sequential_agent.py +31 -0
- google/adk/agents/transcription_entry.py +4 -2
- google/adk/artifacts/gcs_artifact_service.py +1 -1
- google/adk/artifacts/in_memory_artifact_service.py +1 -1
- google/adk/auth/auth_credential.py +10 -2
- 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 +4 -4
- google/adk/cli/browser/{main-ULN5R5I5.js → main-PKDNKWJE.js} +59 -60
- google/adk/cli/browser/polyfills-B6TNHZQ6.js +17 -0
- google/adk/cli/cli.py +10 -9
- google/adk/cli/cli_deploy.py +7 -2
- google/adk/cli/cli_eval.py +109 -115
- google/adk/cli/cli_tools_click.py +179 -67
- google/adk/cli/fast_api.py +248 -197
- google/adk/cli/utils/agent_loader.py +137 -0
- google/adk/cli/utils/cleanup.py +40 -0
- google/adk/cli/utils/common.py +23 -0
- google/adk/cli/utils/evals.py +83 -0
- google/adk/cli/utils/logs.py +8 -5
- google/adk/code_executors/__init__.py +3 -1
- google/adk/code_executors/built_in_code_executor.py +52 -0
- google/adk/code_executors/code_execution_utils.py +2 -1
- google/adk/code_executors/container_code_executor.py +0 -1
- google/adk/code_executors/vertex_ai_code_executor.py +6 -8
- google/adk/evaluation/__init__.py +1 -1
- google/adk/evaluation/agent_evaluator.py +168 -128
- google/adk/evaluation/eval_case.py +104 -0
- google/adk/evaluation/eval_metrics.py +74 -0
- google/adk/evaluation/eval_result.py +86 -0
- google/adk/evaluation/eval_set.py +39 -0
- google/adk/evaluation/eval_set_results_manager.py +47 -0
- google/adk/evaluation/eval_sets_manager.py +43 -0
- google/adk/evaluation/evaluation_generator.py +88 -113
- google/adk/evaluation/evaluator.py +58 -0
- google/adk/evaluation/local_eval_set_results_manager.py +113 -0
- google/adk/evaluation/local_eval_sets_manager.py +264 -0
- google/adk/evaluation/response_evaluator.py +106 -1
- google/adk/evaluation/trajectory_evaluator.py +84 -2
- google/adk/events/event.py +6 -1
- google/adk/events/event_actions.py +6 -1
- google/adk/examples/base_example_provider.py +1 -0
- google/adk/examples/example_util.py +3 -2
- google/adk/flows/llm_flows/_code_execution.py +9 -1
- google/adk/flows/llm_flows/audio_transcriber.py +4 -3
- google/adk/flows/llm_flows/base_llm_flow.py +58 -21
- google/adk/flows/llm_flows/contents.py +3 -1
- google/adk/flows/llm_flows/functions.py +9 -8
- google/adk/flows/llm_flows/instructions.py +18 -80
- google/adk/flows/llm_flows/single_flow.py +2 -2
- google/adk/memory/__init__.py +1 -1
- google/adk/memory/_utils.py +23 -0
- google/adk/memory/base_memory_service.py +23 -21
- google/adk/memory/in_memory_memory_service.py +57 -25
- google/adk/memory/memory_entry.py +37 -0
- google/adk/memory/vertex_ai_rag_memory_service.py +38 -15
- google/adk/models/anthropic_llm.py +16 -9
- google/adk/models/base_llm.py +2 -1
- google/adk/models/base_llm_connection.py +2 -0
- google/adk/models/gemini_llm_connection.py +11 -11
- google/adk/models/google_llm.py +12 -2
- google/adk/models/lite_llm.py +80 -23
- google/adk/models/llm_response.py +16 -3
- google/adk/models/registry.py +1 -1
- google/adk/runners.py +98 -42
- google/adk/sessions/__init__.py +1 -1
- google/adk/sessions/_session_util.py +2 -1
- google/adk/sessions/base_session_service.py +6 -33
- google/adk/sessions/database_session_service.py +57 -67
- google/adk/sessions/in_memory_session_service.py +106 -24
- google/adk/sessions/session.py +3 -0
- google/adk/sessions/vertex_ai_session_service.py +44 -51
- google/adk/telemetry.py +7 -2
- google/adk/tools/__init__.py +4 -7
- google/adk/tools/_memory_entry_utils.py +30 -0
- google/adk/tools/agent_tool.py +10 -10
- google/adk/tools/apihub_tool/apihub_toolset.py +55 -74
- google/adk/tools/apihub_tool/clients/apihub_client.py +10 -3
- google/adk/tools/apihub_tool/clients/secret_client.py +1 -0
- google/adk/tools/application_integration_tool/application_integration_toolset.py +111 -85
- google/adk/tools/application_integration_tool/clients/connections_client.py +28 -1
- google/adk/tools/application_integration_tool/clients/integration_client.py +7 -5
- google/adk/tools/application_integration_tool/integration_connector_tool.py +69 -26
- google/adk/tools/base_toolset.py +96 -0
- google/adk/tools/bigquery/__init__.py +28 -0
- google/adk/tools/bigquery/bigquery_credentials.py +216 -0
- google/adk/tools/bigquery/bigquery_tool.py +116 -0
- google/adk/tools/{built_in_code_execution_tool.py → enterprise_search_tool.py} +17 -11
- google/adk/tools/function_parameter_parse_util.py +9 -2
- google/adk/tools/function_tool.py +33 -3
- google/adk/tools/get_user_choice_tool.py +1 -0
- google/adk/tools/google_api_tool/__init__.py +24 -70
- google/adk/tools/google_api_tool/google_api_tool.py +12 -6
- google/adk/tools/google_api_tool/{google_api_tool_set.py → google_api_toolset.py} +57 -55
- google/adk/tools/google_api_tool/google_api_toolsets.py +108 -0
- google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +40 -42
- google/adk/tools/google_search_tool.py +2 -2
- google/adk/tools/langchain_tool.py +96 -49
- google/adk/tools/load_memory_tool.py +14 -5
- google/adk/tools/mcp_tool/__init__.py +3 -2
- google/adk/tools/mcp_tool/conversion_utils.py +6 -2
- google/adk/tools/mcp_tool/mcp_session_manager.py +80 -69
- google/adk/tools/mcp_tool/mcp_tool.py +35 -32
- google/adk/tools/mcp_tool/mcp_toolset.py +99 -194
- google/adk/tools/openapi_tool/auth/credential_exchangers/base_credential_exchanger.py +1 -3
- google/adk/tools/openapi_tool/auth/credential_exchangers/service_account_exchanger.py +6 -7
- google/adk/tools/openapi_tool/common/common.py +5 -1
- google/adk/tools/openapi_tool/openapi_spec_parser/__init__.py +7 -2
- google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +27 -7
- google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +36 -32
- google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py +11 -1
- 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/toolbox_toolset.py +107 -0
- google/adk/tools/transfer_to_agent_tool.py +0 -1
- google/adk/utils/__init__.py +13 -0
- google/adk/utils/instructions_utils.py +131 -0
- google/adk/version.py +1 -1
- {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/METADATA +18 -19
- google_adk-1.1.0.dist-info/RECORD +200 -0
- google/adk/agents/remote_agent.py +0 -50
- google/adk/cli/browser/polyfills-FFHMD2TL.js +0 -18
- google/adk/cli/fast_api.py.orig +0 -728
- google/adk/tools/google_api_tool/google_api_tool_sets.py +0 -112
- google/adk/tools/toolbox_tool.py +0 -46
- google_adk-0.5.0.dist-info/RECORD +0 -180
- {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/WHEEL +0 -0
- {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/entry_points.txt +0 -0
- {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/licenses/LICENSE +0 -0
google/adk/agents/base_agent.py
CHANGED
@@ -15,12 +15,14 @@
|
|
15
15
|
from __future__ import annotations
|
16
16
|
|
17
17
|
import inspect
|
18
|
-
from typing import Any
|
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
|
-
|
44
|
+
_SingleAgentCallback: TypeAlias = Callable[
|
42
45
|
[CallbackContext],
|
43
46
|
Union[Awaitable[Optional[types.Content]], Optional[types.Content]],
|
44
47
|
]
|
45
48
|
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
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
|
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
|
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
|
-
|
258
|
-
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
|
-
|
269
|
-
|
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
|
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
|
-
|
300
|
-
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
|
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
|
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]:
|
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,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
|
-
|
78
|
+
_SingleBeforeToolCallback: TypeAlias = Callable[
|
71
79
|
[BaseTool, dict[str, Any], ToolContext],
|
72
80
|
Union[Awaitable[Optional[dict]], Optional[dict]],
|
73
81
|
]
|
74
|
-
|
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
|
-
|
93
|
+
AfterToolCallback: TypeAlias = Union[
|
94
|
+
_SingleAfterToolCallback,
|
95
|
+
list[_SingleAfterToolCallback],
|
96
|
+
]
|
80
97
|
|
81
|
-
|
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
|
86
|
-
tool_union: ToolUnion,
|
87
|
-
) -> BaseTool:
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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,
|
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
|
-
"""
|
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
|
-
"""
|
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(
|
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
|
-
|
287
|
-
|
288
|
-
|
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
|
-
|
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
|
-
|
299
|
-
|
300
|
-
|
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
|
-
|
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 (
|
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
|
@@ -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."""
|
google/adk/agents/run_config.py
CHANGED
@@ -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"""
|
@@ -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
|
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(
|
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
|
-
{
|
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,
|
google/adk/auth/auth_tool.py
CHANGED
@@ -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(
|
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(
|
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.
|