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
@@ -12,15 +12,21 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
|
15
16
|
from contextlib import AsyncExitStack
|
16
17
|
import functools
|
18
|
+
import logging
|
17
19
|
import sys
|
18
|
-
from typing import Any
|
20
|
+
from typing import Any
|
21
|
+
from typing import Optional
|
22
|
+
from typing import TextIO
|
23
|
+
|
19
24
|
import anyio
|
20
25
|
from pydantic import BaseModel
|
21
26
|
|
22
27
|
try:
|
23
|
-
from mcp import ClientSession
|
28
|
+
from mcp import ClientSession
|
29
|
+
from mcp import StdioServerParameters
|
24
30
|
from mcp.client.sse import sse_client
|
25
31
|
from mcp.client.stdio import stdio_client
|
26
32
|
except ImportError as e:
|
@@ -34,6 +40,8 @@ except ImportError as e:
|
|
34
40
|
else:
|
35
41
|
raise e
|
36
42
|
|
43
|
+
logger = logging.getLogger('google_adk.' + __name__)
|
44
|
+
|
37
45
|
|
38
46
|
class SseServerParams(BaseModel):
|
39
47
|
"""Parameters for the MCP SSE connection.
|
@@ -62,29 +70,27 @@ def retry_on_closed_resource(async_reinit_func_name: str):
|
|
62
70
|
|
63
71
|
Usage:
|
64
72
|
class MCPTool:
|
65
|
-
|
66
|
-
|
67
|
-
|
73
|
+
...
|
74
|
+
async def create_session(self):
|
75
|
+
self.session = ...
|
68
76
|
|
69
|
-
|
70
|
-
|
71
|
-
|
77
|
+
@retry_on_closed_resource('create_session')
|
78
|
+
async def use_session(self):
|
79
|
+
await self.session.call_tool()
|
72
80
|
|
73
81
|
Args:
|
74
|
-
|
82
|
+
async_reinit_func_name: The name of the async function to recreate session.
|
75
83
|
|
76
84
|
Returns:
|
77
|
-
|
85
|
+
The decorated function.
|
78
86
|
"""
|
79
87
|
|
80
88
|
def decorator(func):
|
81
|
-
@functools.wraps(
|
82
|
-
func
|
83
|
-
) # Preserves original function metadata (name, docstring)
|
89
|
+
@functools.wraps(func) # Preserves original function metadata
|
84
90
|
async def wrapper(self, *args, **kwargs):
|
85
91
|
try:
|
86
92
|
return await func(self, *args, **kwargs)
|
87
|
-
except anyio.ClosedResourceError:
|
93
|
+
except anyio.ClosedResourceError as close_err:
|
88
94
|
try:
|
89
95
|
if hasattr(self, async_reinit_func_name) and callable(
|
90
96
|
getattr(self, async_reinit_func_name)
|
@@ -96,7 +102,7 @@ def retry_on_closed_resource(async_reinit_func_name: str):
|
|
96
102
|
f'Function {async_reinit_func_name} does not exist in decorated'
|
97
103
|
' class. Please check the function name in'
|
98
104
|
' retry_on_closed_resource decorator.'
|
99
|
-
)
|
105
|
+
) from close_err
|
100
106
|
except Exception as reinit_err:
|
101
107
|
raise RuntimeError(
|
102
108
|
f'Error reinitializing: {reinit_err}'
|
@@ -118,73 +124,78 @@ class MCPSessionManager:
|
|
118
124
|
def __init__(
|
119
125
|
self,
|
120
126
|
connection_params: StdioServerParameters | SseServerParams,
|
121
|
-
exit_stack: AsyncExitStack,
|
122
127
|
errlog: TextIO = sys.stderr,
|
123
|
-
)
|
128
|
+
):
|
124
129
|
"""Initializes the MCP session manager.
|
125
130
|
|
126
|
-
Example usage:
|
127
|
-
```
|
128
|
-
mcp_session_manager = MCPSessionManager(
|
129
|
-
connection_params=connection_params,
|
130
|
-
exit_stack=exit_stack,
|
131
|
-
)
|
132
|
-
session = await mcp_session_manager.create_session()
|
133
|
-
```
|
134
|
-
|
135
131
|
Args:
|
136
132
|
connection_params: Parameters for the MCP connection (Stdio or SSE).
|
137
|
-
exit_stack: AsyncExitStack to manage the session lifecycle.
|
138
133
|
errlog: (Optional) TextIO stream for error logging. Use only for
|
139
134
|
initializing a local stdio MCP session.
|
140
135
|
"""
|
141
|
-
self.
|
142
|
-
self.
|
143
|
-
|
136
|
+
self._connection_params = connection_params
|
137
|
+
self._errlog = errlog
|
138
|
+
# Each session manager maintains its own exit stack for proper cleanup
|
139
|
+
self._exit_stack: Optional[AsyncExitStack] = None
|
140
|
+
self._session: Optional[ClientSession] = None
|
144
141
|
|
145
142
|
async def create_session(self) -> ClientSession:
|
146
|
-
|
147
|
-
connection_params=self.connection_params,
|
148
|
-
exit_stack=self.exit_stack,
|
149
|
-
errlog=self.errlog,
|
150
|
-
)
|
151
|
-
|
152
|
-
@classmethod
|
153
|
-
async def initialize_session(
|
154
|
-
cls,
|
155
|
-
*,
|
156
|
-
connection_params: StdioServerParameters | SseServerParams,
|
157
|
-
exit_stack: AsyncExitStack,
|
158
|
-
errlog: TextIO = sys.stderr,
|
159
|
-
) -> ClientSession:
|
160
|
-
"""Initializes an MCP client session.
|
161
|
-
|
162
|
-
Args:
|
163
|
-
connection_params: Parameters for the MCP connection (Stdio or SSE).
|
164
|
-
exit_stack: AsyncExitStack to manage the session lifecycle.
|
165
|
-
errlog: (Optional) TextIO stream for error logging. Use only for
|
166
|
-
initializing a local stdio MCP session.
|
143
|
+
"""Creates and initializes an MCP client session.
|
167
144
|
|
168
145
|
Returns:
|
169
146
|
ClientSession: The initialized MCP client session.
|
170
147
|
"""
|
171
|
-
if
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
148
|
+
if self._session is not None:
|
149
|
+
return self._session
|
150
|
+
|
151
|
+
# Create a new exit stack for this session
|
152
|
+
self._exit_stack = AsyncExitStack()
|
153
|
+
|
154
|
+
try:
|
155
|
+
if isinstance(self._connection_params, StdioServerParameters):
|
156
|
+
client = stdio_client(
|
157
|
+
server=self._connection_params, errlog=self._errlog
|
158
|
+
)
|
159
|
+
elif isinstance(self._connection_params, SseServerParams):
|
160
|
+
client = sse_client(
|
161
|
+
url=self._connection_params.url,
|
162
|
+
headers=self._connection_params.headers,
|
163
|
+
timeout=self._connection_params.timeout,
|
164
|
+
sse_read_timeout=self._connection_params.sse_read_timeout,
|
165
|
+
)
|
166
|
+
else:
|
167
|
+
raise ValueError(
|
168
|
+
'Unable to initialize connection. Connection should be'
|
169
|
+
' StdioServerParameters or SseServerParams, but got'
|
170
|
+
f' {self._connection_params}'
|
171
|
+
)
|
172
|
+
|
173
|
+
transports = await self._exit_stack.enter_async_context(client)
|
174
|
+
session = await self._exit_stack.enter_async_context(
|
175
|
+
ClientSession(*transports)
|
185
176
|
)
|
177
|
+
await session.initialize()
|
186
178
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
179
|
+
self._session = session
|
180
|
+
return session
|
181
|
+
|
182
|
+
except Exception:
|
183
|
+
# If session creation fails, clean up the exit stack
|
184
|
+
if self._exit_stack:
|
185
|
+
await self._exit_stack.aclose()
|
186
|
+
self._exit_stack = None
|
187
|
+
raise
|
188
|
+
|
189
|
+
async def close(self):
|
190
|
+
"""Closes the session and cleans up resources."""
|
191
|
+
if self._exit_stack:
|
192
|
+
try:
|
193
|
+
await self._exit_stack.aclose()
|
194
|
+
except Exception as e:
|
195
|
+
# Log the error but don't re-raise to avoid blocking shutdown
|
196
|
+
print(
|
197
|
+
f'Warning: Error during MCP session cleanup: {e}', file=self._errlog
|
198
|
+
)
|
199
|
+
finally:
|
200
|
+
self._exit_stack = None
|
201
|
+
self._session = None
|
@@ -12,17 +12,19 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
|
16
|
+
import logging
|
15
17
|
from typing import Optional
|
16
18
|
|
17
19
|
from google.genai.types import FunctionDeclaration
|
18
20
|
from typing_extensions import override
|
19
21
|
|
20
|
-
from .mcp_session_manager import MCPSessionManager
|
22
|
+
from .mcp_session_manager import MCPSessionManager
|
23
|
+
from .mcp_session_manager import retry_on_closed_resource
|
21
24
|
|
22
25
|
# Attempt to import MCP Tool from the MCP library, and hints user to upgrade
|
23
26
|
# their Python version to 3.10 if it fails.
|
24
27
|
try:
|
25
|
-
from mcp import ClientSession
|
26
28
|
from mcp.types import Tool as McpBaseTool
|
27
29
|
except ImportError as e:
|
28
30
|
import sys
|
@@ -36,12 +38,14 @@ except ImportError as e:
|
|
36
38
|
raise e
|
37
39
|
|
38
40
|
|
39
|
-
from ..base_tool import BaseTool
|
40
41
|
from ...auth.auth_credential import AuthCredential
|
41
42
|
from ...auth.auth_schemes import AuthScheme
|
43
|
+
from ..base_tool import BaseTool
|
42
44
|
from ..openapi_tool.openapi_spec_parser.rest_api_tool import to_gemini_schema
|
43
45
|
from ..tool_context import ToolContext
|
44
46
|
|
47
|
+
logger = logging.getLogger("google_adk." + __name__)
|
48
|
+
|
45
49
|
|
46
50
|
class MCPTool(BaseTool):
|
47
51
|
"""Turns a MCP Tool into a Vertex Agent Framework Tool.
|
@@ -52,44 +56,39 @@ class MCPTool(BaseTool):
|
|
52
56
|
|
53
57
|
def __init__(
|
54
58
|
self,
|
59
|
+
*,
|
55
60
|
mcp_tool: McpBaseTool,
|
56
|
-
mcp_session: ClientSession,
|
57
61
|
mcp_session_manager: MCPSessionManager,
|
58
62
|
auth_scheme: Optional[AuthScheme] = None,
|
59
|
-
auth_credential: Optional[AuthCredential]
|
63
|
+
auth_credential: Optional[AuthCredential] = None,
|
60
64
|
):
|
61
65
|
"""Initializes a MCPTool.
|
62
66
|
|
63
|
-
This tool wraps a MCP Tool interface and
|
64
|
-
|
65
|
-
|
66
|
-
Example:
|
67
|
-
tool = MCPTool(mcp_tool=mcp_tool, mcp_session=mcp_session)
|
67
|
+
This tool wraps a MCP Tool interface and uses a session manager to
|
68
|
+
communicate with the MCP server.
|
68
69
|
|
69
70
|
Args:
|
70
71
|
mcp_tool: The MCP tool to wrap.
|
71
|
-
|
72
|
+
mcp_session_manager: The MCP session manager to use for communication.
|
72
73
|
auth_scheme: The authentication scheme to use.
|
73
74
|
auth_credential: The authentication credential to use.
|
74
75
|
|
75
76
|
Raises:
|
76
|
-
ValueError: If mcp_tool or
|
77
|
+
ValueError: If mcp_tool or mcp_session_manager is None.
|
77
78
|
"""
|
78
79
|
if mcp_tool is None:
|
79
80
|
raise ValueError("mcp_tool cannot be None")
|
80
|
-
if
|
81
|
-
raise ValueError("
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
self.
|
81
|
+
if mcp_session_manager is None:
|
82
|
+
raise ValueError("mcp_session_manager cannot be None")
|
83
|
+
super().__init__(
|
84
|
+
name=mcp_tool.name,
|
85
|
+
description=mcp_tool.description if mcp_tool.description else "",
|
86
|
+
)
|
87
|
+
self._mcp_tool = mcp_tool
|
88
|
+
self._mcp_session_manager = mcp_session_manager
|
87
89
|
# TODO(cheliu): Support passing auth to MCP Server.
|
88
|
-
self.
|
89
|
-
self.
|
90
|
-
|
91
|
-
async def _reinitialize_session(self):
|
92
|
-
self.mcp_session = await self.mcp_session_manager.create_session()
|
90
|
+
self._auth_scheme = auth_scheme
|
91
|
+
self._auth_credential = auth_credential
|
93
92
|
|
94
93
|
@override
|
95
94
|
def _get_declaration(self) -> FunctionDeclaration:
|
@@ -98,14 +97,13 @@ class MCPTool(BaseTool):
|
|
98
97
|
Returns:
|
99
98
|
FunctionDeclaration: The Gemini function declaration for the tool.
|
100
99
|
"""
|
101
|
-
schema_dict = self.
|
100
|
+
schema_dict = self._mcp_tool.inputSchema
|
102
101
|
parameters = to_gemini_schema(schema_dict)
|
103
102
|
function_decl = FunctionDeclaration(
|
104
103
|
name=self.name, description=self.description, parameters=parameters
|
105
104
|
)
|
106
105
|
return function_decl
|
107
106
|
|
108
|
-
@override
|
109
107
|
@retry_on_closed_resource("_reinitialize_session")
|
110
108
|
async def run_async(self, *, args, tool_context: ToolContext):
|
111
109
|
"""Runs the tool asynchronously.
|
@@ -117,10 +115,15 @@ class MCPTool(BaseTool):
|
|
117
115
|
Returns:
|
118
116
|
Any: The response from the tool.
|
119
117
|
"""
|
118
|
+
# Get the session from the session manager
|
119
|
+
session = await self._mcp_session_manager.create_session()
|
120
|
+
|
120
121
|
# TODO(cheliu): Support passing tool context to MCP Server.
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
122
|
+
response = await session.call_tool(self.name, arguments=args)
|
123
|
+
return response
|
124
|
+
|
125
|
+
async def _reinitialize_session(self):
|
126
|
+
"""Reinitializes the session when connection is lost."""
|
127
|
+
# Close the old session and create a new one
|
128
|
+
await self._mcp_session_manager.close()
|
129
|
+
await self._mcp_session_manager.create_session()
|