google-adk 0.5.0__py3-none-any.whl → 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. google/adk/agents/base_agent.py +76 -30
  2. google/adk/agents/callback_context.py +2 -6
  3. google/adk/agents/llm_agent.py +122 -30
  4. google/adk/agents/loop_agent.py +1 -1
  5. google/adk/agents/parallel_agent.py +7 -0
  6. google/adk/agents/readonly_context.py +8 -0
  7. google/adk/agents/run_config.py +1 -1
  8. google/adk/agents/sequential_agent.py +31 -0
  9. google/adk/agents/transcription_entry.py +4 -2
  10. google/adk/artifacts/gcs_artifact_service.py +1 -1
  11. google/adk/artifacts/in_memory_artifact_service.py +1 -1
  12. google/adk/auth/auth_credential.py +10 -2
  13. google/adk/auth/auth_preprocessor.py +7 -1
  14. google/adk/auth/auth_tool.py +3 -4
  15. google/adk/cli/agent_graph.py +5 -5
  16. google/adk/cli/browser/index.html +4 -4
  17. google/adk/cli/browser/{main-ULN5R5I5.js → main-PKDNKWJE.js} +59 -60
  18. google/adk/cli/browser/polyfills-B6TNHZQ6.js +17 -0
  19. google/adk/cli/cli.py +10 -9
  20. google/adk/cli/cli_deploy.py +7 -2
  21. google/adk/cli/cli_eval.py +109 -115
  22. google/adk/cli/cli_tools_click.py +179 -67
  23. google/adk/cli/fast_api.py +248 -197
  24. google/adk/cli/utils/agent_loader.py +137 -0
  25. google/adk/cli/utils/cleanup.py +40 -0
  26. google/adk/cli/utils/common.py +23 -0
  27. google/adk/cli/utils/evals.py +83 -0
  28. google/adk/cli/utils/logs.py +8 -5
  29. google/adk/code_executors/__init__.py +3 -1
  30. google/adk/code_executors/built_in_code_executor.py +52 -0
  31. google/adk/code_executors/code_execution_utils.py +2 -1
  32. google/adk/code_executors/container_code_executor.py +0 -1
  33. google/adk/code_executors/vertex_ai_code_executor.py +6 -8
  34. google/adk/evaluation/__init__.py +1 -1
  35. google/adk/evaluation/agent_evaluator.py +168 -128
  36. google/adk/evaluation/eval_case.py +104 -0
  37. google/adk/evaluation/eval_metrics.py +74 -0
  38. google/adk/evaluation/eval_result.py +86 -0
  39. google/adk/evaluation/eval_set.py +39 -0
  40. google/adk/evaluation/eval_set_results_manager.py +47 -0
  41. google/adk/evaluation/eval_sets_manager.py +43 -0
  42. google/adk/evaluation/evaluation_generator.py +88 -113
  43. google/adk/evaluation/evaluator.py +58 -0
  44. google/adk/evaluation/local_eval_set_results_manager.py +113 -0
  45. google/adk/evaluation/local_eval_sets_manager.py +264 -0
  46. google/adk/evaluation/response_evaluator.py +106 -1
  47. google/adk/evaluation/trajectory_evaluator.py +84 -2
  48. google/adk/events/event.py +6 -1
  49. google/adk/events/event_actions.py +6 -1
  50. google/adk/examples/base_example_provider.py +1 -0
  51. google/adk/examples/example_util.py +3 -2
  52. google/adk/flows/llm_flows/_code_execution.py +9 -1
  53. google/adk/flows/llm_flows/audio_transcriber.py +4 -3
  54. google/adk/flows/llm_flows/base_llm_flow.py +58 -21
  55. google/adk/flows/llm_flows/contents.py +3 -1
  56. google/adk/flows/llm_flows/functions.py +9 -8
  57. google/adk/flows/llm_flows/instructions.py +18 -80
  58. google/adk/flows/llm_flows/single_flow.py +2 -2
  59. google/adk/memory/__init__.py +1 -1
  60. google/adk/memory/_utils.py +23 -0
  61. google/adk/memory/base_memory_service.py +23 -21
  62. google/adk/memory/in_memory_memory_service.py +57 -25
  63. google/adk/memory/memory_entry.py +37 -0
  64. google/adk/memory/vertex_ai_rag_memory_service.py +38 -15
  65. google/adk/models/anthropic_llm.py +16 -9
  66. google/adk/models/base_llm.py +2 -1
  67. google/adk/models/base_llm_connection.py +2 -0
  68. google/adk/models/gemini_llm_connection.py +11 -11
  69. google/adk/models/google_llm.py +12 -2
  70. google/adk/models/lite_llm.py +80 -23
  71. google/adk/models/llm_response.py +16 -3
  72. google/adk/models/registry.py +1 -1
  73. google/adk/runners.py +98 -42
  74. google/adk/sessions/__init__.py +1 -1
  75. google/adk/sessions/_session_util.py +2 -1
  76. google/adk/sessions/base_session_service.py +6 -33
  77. google/adk/sessions/database_session_service.py +57 -67
  78. google/adk/sessions/in_memory_session_service.py +106 -24
  79. google/adk/sessions/session.py +3 -0
  80. google/adk/sessions/vertex_ai_session_service.py +44 -51
  81. google/adk/telemetry.py +7 -2
  82. google/adk/tools/__init__.py +4 -7
  83. google/adk/tools/_memory_entry_utils.py +30 -0
  84. google/adk/tools/agent_tool.py +10 -10
  85. google/adk/tools/apihub_tool/apihub_toolset.py +55 -74
  86. google/adk/tools/apihub_tool/clients/apihub_client.py +10 -3
  87. google/adk/tools/apihub_tool/clients/secret_client.py +1 -0
  88. google/adk/tools/application_integration_tool/application_integration_toolset.py +111 -85
  89. google/adk/tools/application_integration_tool/clients/connections_client.py +28 -1
  90. google/adk/tools/application_integration_tool/clients/integration_client.py +7 -5
  91. google/adk/tools/application_integration_tool/integration_connector_tool.py +69 -26
  92. google/adk/tools/base_toolset.py +96 -0
  93. google/adk/tools/bigquery/__init__.py +28 -0
  94. google/adk/tools/bigquery/bigquery_credentials.py +216 -0
  95. google/adk/tools/bigquery/bigquery_tool.py +116 -0
  96. google/adk/tools/{built_in_code_execution_tool.py → enterprise_search_tool.py} +17 -11
  97. google/adk/tools/function_parameter_parse_util.py +9 -2
  98. google/adk/tools/function_tool.py +33 -3
  99. google/adk/tools/get_user_choice_tool.py +1 -0
  100. google/adk/tools/google_api_tool/__init__.py +24 -70
  101. google/adk/tools/google_api_tool/google_api_tool.py +12 -6
  102. google/adk/tools/google_api_tool/{google_api_tool_set.py → google_api_toolset.py} +57 -55
  103. google/adk/tools/google_api_tool/google_api_toolsets.py +108 -0
  104. google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +40 -42
  105. google/adk/tools/google_search_tool.py +2 -2
  106. google/adk/tools/langchain_tool.py +96 -49
  107. google/adk/tools/load_memory_tool.py +14 -5
  108. google/adk/tools/mcp_tool/__init__.py +3 -2
  109. google/adk/tools/mcp_tool/conversion_utils.py +6 -2
  110. google/adk/tools/mcp_tool/mcp_session_manager.py +80 -69
  111. google/adk/tools/mcp_tool/mcp_tool.py +35 -32
  112. google/adk/tools/mcp_tool/mcp_toolset.py +99 -194
  113. google/adk/tools/openapi_tool/auth/credential_exchangers/base_credential_exchanger.py +1 -3
  114. google/adk/tools/openapi_tool/auth/credential_exchangers/service_account_exchanger.py +6 -7
  115. google/adk/tools/openapi_tool/common/common.py +5 -1
  116. google/adk/tools/openapi_tool/openapi_spec_parser/__init__.py +7 -2
  117. google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +27 -7
  118. google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +36 -32
  119. google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py +11 -1
  120. google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +1 -1
  121. google/adk/tools/preload_memory_tool.py +27 -18
  122. google/adk/tools/retrieval/__init__.py +1 -1
  123. google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +1 -1
  124. google/adk/tools/toolbox_toolset.py +107 -0
  125. google/adk/tools/transfer_to_agent_tool.py +0 -1
  126. google/adk/utils/__init__.py +13 -0
  127. google/adk/utils/instructions_utils.py +131 -0
  128. google/adk/version.py +1 -1
  129. {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/METADATA +18 -19
  130. google_adk-1.1.0.dist-info/RECORD +200 -0
  131. google/adk/agents/remote_agent.py +0 -50
  132. google/adk/cli/browser/polyfills-FFHMD2TL.js +0 -18
  133. google/adk/cli/fast_api.py.orig +0 -728
  134. google/adk/tools/google_api_tool/google_api_tool_sets.py +0 -112
  135. google/adk/tools/toolbox_tool.py +0 -46
  136. google_adk-0.5.0.dist-info/RECORD +0 -180
  137. {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/WHEEL +0 -0
  138. {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/entry_points.txt +0 -0
  139. {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/licenses/LICENSE +0 -0
@@ -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, TextIO
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, StdioServerParameters
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
- async def create_session(self):
67
- self.session = ...
73
+ ...
74
+ async def create_session(self):
75
+ self.session = ...
68
76
 
69
- @retry_on_closed_resource('create_session')
70
- async def use_session(self):
71
- await self.session.call_tool()
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
- async_reinit_func_name: The name of the async function to recreate session.
82
+ async_reinit_func_name: The name of the async function to recreate session.
75
83
 
76
84
  Returns:
77
- The decorated function.
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
- ) -> ClientSession:
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.connection_params = connection_params
142
- self.exit_stack = exit_stack
143
- self.errlog = errlog
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
- return await MCPSessionManager.initialize_session(
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 isinstance(connection_params, StdioServerParameters):
172
- client = stdio_client(server=connection_params, errlog=errlog)
173
- elif isinstance(connection_params, SseServerParams):
174
- client = sse_client(
175
- url=connection_params.url,
176
- headers=connection_params.headers,
177
- timeout=connection_params.timeout,
178
- sse_read_timeout=connection_params.sse_read_timeout,
179
- )
180
- else:
181
- raise ValueError(
182
- 'Unable to initialize connection. Connection should be'
183
- ' StdioServerParameters or SseServerParams, but got'
184
- f' {connection_params}'
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
- transports = await exit_stack.enter_async_context(client)
188
- session = await exit_stack.enter_async_context(ClientSession(*transports))
189
- await session.initialize()
190
- return session
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, retry_on_closed_resource
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] | None = None,
63
+ auth_credential: Optional[AuthCredential] = None,
60
64
  ):
61
65
  """Initializes a MCPTool.
62
66
 
63
- This tool wraps a MCP Tool interface and an active MCP Session. It invokes
64
- the MCP Tool through executing the tool from remote MCP Session.
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
- mcp_session: The MCP session to use to call the tool.
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 mcp_session is None.
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 mcp_session is None:
81
- raise ValueError("mcp_session cannot be None")
82
- self.name = mcp_tool.name
83
- self.description = mcp_tool.description if mcp_tool.description else ""
84
- self.mcp_tool = mcp_tool
85
- self.mcp_session = mcp_session
86
- self.mcp_session_manager = mcp_session_manager
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.auth_scheme = auth_scheme
89
- self.auth_credential = auth_credential
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.mcp_tool.inputSchema
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
- try:
122
- response = await self.mcp_session.call_tool(self.name, arguments=args)
123
- return response
124
- except Exception as e:
125
- print(e)
126
- raise e
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()