google-adk 0.4.0__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. google/adk/agents/active_streaming_tool.py +1 -0
  2. google/adk/agents/base_agent.py +91 -47
  3. google/adk/agents/base_agent.py.orig +330 -0
  4. google/adk/agents/callback_context.py +4 -9
  5. google/adk/agents/invocation_context.py +1 -0
  6. google/adk/agents/langgraph_agent.py +1 -0
  7. google/adk/agents/live_request_queue.py +1 -0
  8. google/adk/agents/llm_agent.py +172 -35
  9. google/adk/agents/loop_agent.py +1 -1
  10. google/adk/agents/parallel_agent.py +7 -0
  11. google/adk/agents/readonly_context.py +7 -1
  12. google/adk/agents/run_config.py +5 -1
  13. google/adk/agents/sequential_agent.py +31 -0
  14. google/adk/agents/transcription_entry.py +5 -2
  15. google/adk/artifacts/base_artifact_service.py +5 -10
  16. google/adk/artifacts/gcs_artifact_service.py +9 -9
  17. google/adk/artifacts/in_memory_artifact_service.py +6 -6
  18. google/adk/auth/auth_credential.py +9 -5
  19. google/adk/auth/auth_preprocessor.py +7 -1
  20. google/adk/auth/auth_tool.py +3 -4
  21. google/adk/cli/agent_graph.py +5 -5
  22. google/adk/cli/browser/index.html +2 -2
  23. google/adk/cli/browser/{main-HWIBUY2R.js → main-QOEMUXM4.js} +58 -58
  24. google/adk/cli/cli.py +7 -7
  25. google/adk/cli/cli_deploy.py +7 -2
  26. google/adk/cli/cli_eval.py +181 -106
  27. google/adk/cli/cli_tools_click.py +147 -62
  28. google/adk/cli/fast_api.py +340 -158
  29. google/adk/cli/fast_api.py.orig +822 -0
  30. google/adk/cli/utils/common.py +23 -0
  31. google/adk/cli/utils/evals.py +83 -1
  32. google/adk/cli/utils/logs.py +13 -5
  33. google/adk/code_executors/__init__.py +3 -1
  34. google/adk/code_executors/built_in_code_executor.py +52 -0
  35. google/adk/evaluation/__init__.py +1 -1
  36. google/adk/evaluation/agent_evaluator.py +168 -128
  37. google/adk/evaluation/eval_case.py +102 -0
  38. google/adk/evaluation/eval_set.py +37 -0
  39. google/adk/evaluation/eval_sets_manager.py +42 -0
  40. google/adk/evaluation/evaluation_constants.py +1 -0
  41. google/adk/evaluation/evaluation_generator.py +89 -114
  42. google/adk/evaluation/evaluator.py +56 -0
  43. google/adk/evaluation/local_eval_sets_manager.py +264 -0
  44. google/adk/evaluation/response_evaluator.py +107 -3
  45. google/adk/evaluation/trajectory_evaluator.py +83 -2
  46. google/adk/events/event.py +7 -1
  47. google/adk/events/event_actions.py +7 -1
  48. google/adk/examples/example.py +1 -0
  49. google/adk/examples/example_util.py +3 -2
  50. google/adk/flows/__init__.py +0 -1
  51. google/adk/flows/llm_flows/_code_execution.py +19 -11
  52. google/adk/flows/llm_flows/audio_transcriber.py +4 -3
  53. google/adk/flows/llm_flows/base_llm_flow.py +86 -22
  54. google/adk/flows/llm_flows/basic.py +3 -0
  55. google/adk/flows/llm_flows/functions.py +10 -9
  56. google/adk/flows/llm_flows/instructions.py +28 -9
  57. google/adk/flows/llm_flows/single_flow.py +1 -1
  58. google/adk/memory/__init__.py +1 -1
  59. google/adk/memory/_utils.py +23 -0
  60. google/adk/memory/base_memory_service.py +25 -21
  61. google/adk/memory/base_memory_service.py.orig +76 -0
  62. google/adk/memory/in_memory_memory_service.py +59 -27
  63. google/adk/memory/memory_entry.py +37 -0
  64. google/adk/memory/vertex_ai_rag_memory_service.py +40 -17
  65. google/adk/models/anthropic_llm.py +36 -11
  66. google/adk/models/base_llm.py +45 -4
  67. google/adk/models/gemini_llm_connection.py +15 -2
  68. google/adk/models/google_llm.py +9 -44
  69. google/adk/models/google_llm.py.orig +305 -0
  70. google/adk/models/lite_llm.py +94 -38
  71. google/adk/models/llm_request.py +1 -1
  72. google/adk/models/llm_response.py +15 -3
  73. google/adk/models/registry.py +1 -1
  74. google/adk/runners.py +68 -44
  75. google/adk/sessions/__init__.py +1 -1
  76. google/adk/sessions/_session_util.py +14 -0
  77. google/adk/sessions/base_session_service.py +8 -32
  78. google/adk/sessions/database_session_service.py +58 -61
  79. google/adk/sessions/in_memory_session_service.py +108 -26
  80. google/adk/sessions/session.py +4 -0
  81. google/adk/sessions/vertex_ai_session_service.py +23 -45
  82. google/adk/telemetry.py +3 -0
  83. google/adk/tools/__init__.py +4 -7
  84. google/adk/tools/{built_in_code_execution_tool.py → _built_in_code_execution_tool.py} +11 -0
  85. google/adk/tools/_memory_entry_utils.py +30 -0
  86. google/adk/tools/agent_tool.py +16 -13
  87. google/adk/tools/apihub_tool/apihub_toolset.py +55 -74
  88. google/adk/tools/application_integration_tool/application_integration_toolset.py +107 -85
  89. google/adk/tools/application_integration_tool/clients/connections_client.py +29 -25
  90. google/adk/tools/application_integration_tool/clients/integration_client.py +6 -6
  91. google/adk/tools/application_integration_tool/integration_connector_tool.py +69 -26
  92. google/adk/tools/base_toolset.py +58 -0
  93. google/adk/tools/enterprise_search_tool.py +65 -0
  94. google/adk/tools/function_parameter_parse_util.py +2 -2
  95. google/adk/tools/google_api_tool/__init__.py +18 -70
  96. google/adk/tools/google_api_tool/google_api_tool.py +11 -5
  97. google/adk/tools/google_api_tool/google_api_toolset.py +126 -0
  98. google/adk/tools/google_api_tool/google_api_toolsets.py +102 -0
  99. google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +40 -42
  100. google/adk/tools/langchain_tool.py +96 -49
  101. google/adk/tools/load_artifacts_tool.py +4 -4
  102. google/adk/tools/load_memory_tool.py +16 -5
  103. google/adk/tools/mcp_tool/__init__.py +3 -2
  104. google/adk/tools/mcp_tool/conversion_utils.py +1 -1
  105. google/adk/tools/mcp_tool/mcp_session_manager.py +167 -16
  106. google/adk/tools/mcp_tool/mcp_session_manager.py.orig +322 -0
  107. google/adk/tools/mcp_tool/mcp_tool.py +12 -12
  108. google/adk/tools/mcp_tool/mcp_toolset.py +155 -195
  109. google/adk/tools/openapi_tool/common/common.py +2 -5
  110. google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +32 -7
  111. google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +43 -33
  112. google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +1 -1
  113. google/adk/tools/preload_memory_tool.py +27 -18
  114. google/adk/tools/retrieval/__init__.py +1 -1
  115. google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +1 -1
  116. google/adk/tools/tool_context.py +4 -4
  117. google/adk/tools/toolbox_toolset.py +79 -0
  118. google/adk/tools/transfer_to_agent_tool.py +0 -1
  119. google/adk/version.py +1 -1
  120. {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/METADATA +7 -5
  121. google_adk-1.0.0.dist-info/RECORD +195 -0
  122. google/adk/agents/remote_agent.py +0 -50
  123. google/adk/tools/google_api_tool/google_api_tool_set.py +0 -110
  124. google/adk/tools/google_api_tool/google_api_tool_sets.py +0 -112
  125. google/adk/tools/toolbox_tool.py +0 -46
  126. google_adk-0.4.0.dist-info/RECORD +0 -179
  127. {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/WHEEL +0 -0
  128. {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/entry_points.txt +0 -0
  129. {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -312,9 +312,7 @@ class ConnectionsClient:
312
312
  "content": {
313
313
  "application/json": {
314
314
  "schema": {
315
- "$ref": (
316
- f"#/components/schemas/{action_display_name}_Request"
317
- )
315
+ "$ref": f"#/components/schemas/{action_display_name}_Request"
318
316
  }
319
317
  }
320
318
  }
@@ -325,9 +323,7 @@ class ConnectionsClient:
325
323
  "content": {
326
324
  "application/json": {
327
325
  "schema": {
328
- "$ref": (
329
- f"#/components/schemas/{action_display_name}_Response"
330
- ),
326
+ "$ref": f"#/components/schemas/{action_display_name}_Response",
331
327
  }
332
328
  }
333
329
  },
@@ -346,11 +342,9 @@ class ConnectionsClient:
346
342
  return {
347
343
  "post": {
348
344
  "summary": f"List {entity}",
349
- "description": (
350
- f"""Returns the list of {entity} data. If the page token was available in the response, let users know there are more records available. Ask if the user wants to fetch the next page of results. When passing filter use the
345
+ "description": f"""Returns the list of {entity} data. If the page token was available in the response, let users know there are more records available. Ask if the user wants to fetch the next page of results. When passing filter use the
351
346
  following format: `field_name1='value1' AND field_name2='value2'
352
- `. {tool_instructions}"""
353
- ),
347
+ `. {tool_instructions}""",
354
348
  "x-operation": "LIST_ENTITIES",
355
349
  "x-entity": f"{entity}",
356
350
  "operationId": f"{tool_name}_list_{entity}",
@@ -375,9 +369,7 @@ class ConnectionsClient:
375
369
  f"Returns a list of {entity} of json"
376
370
  f" schema: {schema_as_string}"
377
371
  ),
378
- "$ref": (
379
- "#/components/schemas/execute-connector_Response"
380
- ),
372
+ "$ref": "#/components/schemas/execute-connector_Response",
381
373
  }
382
374
  }
383
375
  },
@@ -421,9 +413,7 @@ class ConnectionsClient:
421
413
  f"Returns {entity} of json schema:"
422
414
  f" {schema_as_string}"
423
415
  ),
424
- "$ref": (
425
- "#/components/schemas/execute-connector_Response"
426
- ),
416
+ "$ref": "#/components/schemas/execute-connector_Response",
427
417
  }
428
418
  }
429
419
  },
@@ -460,9 +450,7 @@ class ConnectionsClient:
460
450
  "content": {
461
451
  "application/json": {
462
452
  "schema": {
463
- "$ref": (
464
- "#/components/schemas/execute-connector_Response"
465
- )
453
+ "$ref": "#/components/schemas/execute-connector_Response"
466
454
  }
467
455
  }
468
456
  },
@@ -499,9 +487,7 @@ class ConnectionsClient:
499
487
  "content": {
500
488
  "application/json": {
501
489
  "schema": {
502
- "$ref": (
503
- "#/components/schemas/execute-connector_Response"
504
- )
490
+ "$ref": "#/components/schemas/execute-connector_Response"
505
491
  }
506
492
  }
507
493
  },
@@ -538,9 +524,7 @@ class ConnectionsClient:
538
524
  "content": {
539
525
  "application/json": {
540
526
  "schema": {
541
- "$ref": (
542
- "#/components/schemas/execute-connector_Response"
543
- )
527
+ "$ref": "#/components/schemas/execute-connector_Response"
544
528
  }
545
529
  }
546
530
  },
@@ -570,6 +554,9 @@ class ConnectionsClient:
570
554
  "serviceName": {"$ref": "#/components/schemas/serviceName"},
571
555
  "host": {"$ref": "#/components/schemas/host"},
572
556
  "entity": {"$ref": "#/components/schemas/entity"},
557
+ "dynamicAuthConfig": {
558
+ "$ref": "#/components/schemas/dynamicAuthConfig"
559
+ },
573
560
  },
574
561
  }
575
562
 
@@ -596,6 +583,10 @@ class ConnectionsClient:
596
583
  "serviceName": {"$ref": "#/components/schemas/serviceName"},
597
584
  "host": {"$ref": "#/components/schemas/host"},
598
585
  "entity": {"$ref": "#/components/schemas/entity"},
586
+ "dynamicAuthConfig": {
587
+ "$ref": "#/components/schemas/dynamicAuthConfig"
588
+ },
589
+ "filterClause": {"$ref": "#/components/schemas/filterClause"},
599
590
  },
600
591
  }
601
592
 
@@ -618,6 +609,9 @@ class ConnectionsClient:
618
609
  "serviceName": {"$ref": "#/components/schemas/serviceName"},
619
610
  "host": {"$ref": "#/components/schemas/host"},
620
611
  "entity": {"$ref": "#/components/schemas/entity"},
612
+ "dynamicAuthConfig": {
613
+ "$ref": "#/components/schemas/dynamicAuthConfig"
614
+ },
621
615
  },
622
616
  }
623
617
 
@@ -640,6 +634,10 @@ class ConnectionsClient:
640
634
  "serviceName": {"$ref": "#/components/schemas/serviceName"},
641
635
  "host": {"$ref": "#/components/schemas/host"},
642
636
  "entity": {"$ref": "#/components/schemas/entity"},
637
+ "dynamicAuthConfig": {
638
+ "$ref": "#/components/schemas/dynamicAuthConfig"
639
+ },
640
+ "filterClause": {"$ref": "#/components/schemas/filterClause"},
643
641
  },
644
642
  }
645
643
 
@@ -663,6 +661,9 @@ class ConnectionsClient:
663
661
  "serviceName": {"$ref": "#/components/schemas/serviceName"},
664
662
  "host": {"$ref": "#/components/schemas/host"},
665
663
  "entity": {"$ref": "#/components/schemas/entity"},
664
+ "dynamicAuthConfig": {
665
+ "$ref": "#/components/schemas/dynamicAuthConfig"
666
+ },
666
667
  },
667
668
  }
668
669
 
@@ -687,6 +688,9 @@ class ConnectionsClient:
687
688
  "connectorInputPayload": {
688
689
  "$ref": f"#/components/schemas/connectorInputPayload_{action}"
689
690
  },
691
+ "dynamicAuthConfig": {
692
+ "$ref": "#/components/schemas/dynamicAuthConfig"
693
+ },
690
694
  },
691
695
  }
692
696
 
@@ -13,7 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import json
16
- from typing import Optional
16
+ from typing import List, Optional
17
17
  from google.adk.tools.application_integration_tool.clients.connections_client import ConnectionsClient
18
18
  import google.auth
19
19
  from google.auth import default as default_service_credential
@@ -35,7 +35,7 @@ class IntegrationClient:
35
35
  project: str,
36
36
  location: str,
37
37
  integration: Optional[str] = None,
38
- trigger: Optional[str] = None,
38
+ triggers: Optional[List[str]] = None,
39
39
  connection: Optional[str] = None,
40
40
  entity_operations: Optional[dict[str, list[str]]] = None,
41
41
  actions: Optional[list[str]] = None,
@@ -47,7 +47,7 @@ class IntegrationClient:
47
47
  project: The Google Cloud project ID.
48
48
  location: The Google Cloud location (e.g., us-central1).
49
49
  integration: The integration name.
50
- trigger: The trigger ID for the integration.
50
+ triggers: The list of trigger IDs for the integration.
51
51
  connection: The connection name.
52
52
  entity_operations: A dictionary mapping entity names to a list of
53
53
  operations (e.g., LIST, CREATE, UPDATE, DELETE, GET).
@@ -59,7 +59,7 @@ class IntegrationClient:
59
59
  self.project = project
60
60
  self.location = location
61
61
  self.integration = integration
62
- self.trigger = trigger
62
+ self.triggers = triggers
63
63
  self.connection = connection
64
64
  self.entity_operations = (
65
65
  entity_operations if entity_operations is not None else {}
@@ -88,7 +88,7 @@ class IntegrationClient:
88
88
  "apiTriggerResources": [
89
89
  {
90
90
  "integrationResource": self.integration,
91
- "triggerId": [self.trigger],
91
+ "triggerId": self.triggers,
92
92
  },
93
93
  ],
94
94
  "fileFormat": "JSON",
@@ -109,7 +109,7 @@ class IntegrationClient:
109
109
  raise ValueError(
110
110
  "Invalid request. Please check the provided values of"
111
111
  f" project({self.project}), location({self.location}),"
112
- f" integration({self.integration}) and trigger({self.trigger})."
112
+ f" integration({self.integration})."
113
113
  ) from e
114
114
  raise ValueError(f"Request error: {e}") from e
115
115
  except Exception as e:
@@ -12,21 +12,24 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
-
16
15
  import logging
17
16
  from typing import Any
18
17
  from typing import Dict
19
18
  from typing import Optional
19
+ from typing import Union
20
20
 
21
- from google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool import RestApiTool
22
- from google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool import to_gemini_schema
23
21
  from google.genai.types import FunctionDeclaration
24
22
  from typing_extensions import override
25
23
 
24
+ from ...auth.auth_credential import AuthCredential
25
+ from ...auth.auth_schemes import AuthScheme
26
26
  from .. import BaseTool
27
+ from ..openapi_tool.openapi_spec_parser.rest_api_tool import RestApiTool
28
+ from ..openapi_tool.openapi_spec_parser.rest_api_tool import to_gemini_schema
29
+ from ..openapi_tool.openapi_spec_parser.tool_auth_handler import ToolAuthHandler
27
30
  from ..tool_context import ToolContext
28
31
 
29
- logger = logging.getLogger(__name__)
32
+ logger = logging.getLogger('google_adk.' + __name__)
30
33
 
31
34
 
32
35
  class IntegrationConnectorTool(BaseTool):
@@ -56,6 +59,7 @@ class IntegrationConnectorTool(BaseTool):
56
59
  'entity',
57
60
  'operation',
58
61
  'action',
62
+ 'dynamic_auth_config',
59
63
  ]
60
64
 
61
65
  OPTIONAL_FIELDS = [
@@ -75,6 +79,8 @@ class IntegrationConnectorTool(BaseTool):
75
79
  operation: str,
76
80
  action: str,
77
81
  rest_api_tool: RestApiTool,
82
+ auth_scheme: Optional[Union[AuthScheme, str]] = None,
83
+ auth_credential: Optional[Union[AuthCredential, str]] = None,
78
84
  ):
79
85
  """Initializes the ApplicationIntegrationTool.
80
86
 
@@ -101,18 +107,20 @@ class IntegrationConnectorTool(BaseTool):
101
107
  name=name,
102
108
  description=description,
103
109
  )
104
- self.connection_name = connection_name
105
- self.connection_host = connection_host
106
- self.connection_service_name = connection_service_name
107
- self.entity = entity
108
- self.operation = operation
109
- self.action = action
110
- self.rest_api_tool = rest_api_tool
110
+ self._connection_name = connection_name
111
+ self._connection_host = connection_host
112
+ self._connection_service_name = connection_service_name
113
+ self._entity = entity
114
+ self._operation = operation
115
+ self._action = action
116
+ self._rest_api_tool = rest_api_tool
117
+ self._auth_scheme = auth_scheme
118
+ self._auth_credential = auth_credential
111
119
 
112
120
  @override
113
121
  def _get_declaration(self) -> FunctionDeclaration:
114
122
  """Returns the function declaration in the Gemini Schema format."""
115
- schema_dict = self.rest_api_tool._operation_parser.get_json_schema()
123
+ schema_dict = self._rest_api_tool._operation_parser.get_json_schema()
116
124
  for field in self.EXCLUDE_FIELDS:
117
125
  if field in schema_dict['properties']:
118
126
  del schema_dict['properties'][field]
@@ -126,34 +134,69 @@ class IntegrationConnectorTool(BaseTool):
126
134
  )
127
135
  return function_decl
128
136
 
137
+ def _prepare_dynamic_euc(self, auth_credential: AuthCredential) -> str:
138
+ if (
139
+ auth_credential
140
+ and auth_credential.http
141
+ and auth_credential.http.credentials
142
+ and auth_credential.http.credentials.token
143
+ ):
144
+ return auth_credential.http.credentials.token
145
+ return None
146
+
129
147
  @override
130
148
  async def run_async(
131
149
  self, *, args: dict[str, Any], tool_context: Optional[ToolContext]
132
150
  ) -> Dict[str, Any]:
133
- args['connection_name'] = self.connection_name
134
- args['service_name'] = self.connection_service_name
135
- args['host'] = self.connection_host
136
- args['entity'] = self.entity
137
- args['operation'] = self.operation
138
- args['action'] = self.action
151
+
152
+ tool_auth_handler = ToolAuthHandler.from_tool_context(
153
+ tool_context, self._auth_scheme, self._auth_credential
154
+ )
155
+ auth_result = tool_auth_handler.prepare_auth_credentials()
156
+
157
+ if auth_result.state == 'pending':
158
+ return {
159
+ 'pending': True,
160
+ 'message': 'Needs your authorization to access your data.',
161
+ }
162
+
163
+ # Attach parameters from auth into main parameters list
164
+ if auth_result.auth_credential:
165
+ # Attach parameters from auth into main parameters list
166
+ auth_credential_token = self._prepare_dynamic_euc(
167
+ auth_result.auth_credential
168
+ )
169
+ if auth_credential_token:
170
+ args['dynamic_auth_config'] = {
171
+ 'oauth2_auth_code_flow.access_token': auth_credential_token
172
+ }
173
+ else:
174
+ args['dynamic_auth_config'] = {'oauth2_auth_code_flow.access_token': {}}
175
+
176
+ args['connection_name'] = self._connection_name
177
+ args['service_name'] = self._connection_service_name
178
+ args['host'] = self._connection_host
179
+ args['entity'] = self._entity
180
+ args['operation'] = self._operation
181
+ args['action'] = self._action
139
182
  logger.info('Running tool: %s with args: %s', self.name, args)
140
- return self.rest_api_tool.call(args=args, tool_context=tool_context)
183
+ return self._rest_api_tool.call(args=args, tool_context=tool_context)
141
184
 
142
185
  def __str__(self):
143
186
  return (
144
187
  f'ApplicationIntegrationTool(name="{self.name}",'
145
188
  f' description="{self.description}",'
146
- f' connection_name="{self.connection_name}", entity="{self.entity}",'
147
- f' operation="{self.operation}", action="{self.action}")'
189
+ f' connection_name="{self._connection_name}", entity="{self._entity}",'
190
+ f' operation="{self._operation}", action="{self._action}")'
148
191
  )
149
192
 
150
193
  def __repr__(self):
151
194
  return (
152
195
  f'ApplicationIntegrationTool(name="{self.name}",'
153
196
  f' description="{self.description}",'
154
- f' connection_name="{self.connection_name}",'
155
- f' connection_host="{self.connection_host}",'
156
- f' connection_service_name="{self.connection_service_name}",'
157
- f' entity="{self.entity}", operation="{self.operation}",'
158
- f' action="{self.action}", rest_api_tool={repr(self.rest_api_tool)})'
197
+ f' connection_name="{self._connection_name}",'
198
+ f' connection_host="{self._connection_host}",'
199
+ f' connection_service_name="{self._connection_service_name}",'
200
+ f' entity="{self._entity}", operation="{self._operation}",'
201
+ f' action="{self._action}", rest_api_tool={repr(self._rest_api_tool)})'
159
202
  )
@@ -0,0 +1,58 @@
1
+ from abc import ABC
2
+ from abc import abstractmethod
3
+ from typing import Optional, runtime_checkable
4
+ from typing import Protocol
5
+
6
+ from ..agents.readonly_context import ReadonlyContext
7
+ from .base_tool import BaseTool
8
+
9
+
10
+ @runtime_checkable
11
+ class ToolPredicate(Protocol):
12
+ """Base class for a predicate that defines the interface to decide whether a
13
+
14
+ tool should be exposed to LLM. Toolset implementer could consider whether to
15
+ accept such instance in the toolset's constructor and apply the predicate in
16
+ get_tools method.
17
+ """
18
+
19
+ def __call__(
20
+ self, tool: BaseTool, readonly_context: Optional[ReadonlyContext] = None
21
+ ) -> bool:
22
+ """Decide whether the passed-in tool should be exposed to LLM based on the
23
+
24
+ current context. True if the tool is usable by the LLM.
25
+
26
+ It's used to filter tools in the toolset.
27
+ """
28
+
29
+
30
+ class BaseToolset(ABC):
31
+ """Base class for toolset.
32
+
33
+ A toolset is a collection of tools that can be used by an agent.
34
+ """
35
+
36
+ @abstractmethod
37
+ async def get_tools(
38
+ self, readonly_context: Optional[ReadonlyContext] = None
39
+ ) -> list[BaseTool]:
40
+ """Return all tools in the toolset based on the provided context.
41
+
42
+ Args:
43
+ readony_context (ReadonlyContext, optional): Context used to filter tools
44
+ available to the agent. If None, all tools in the toolset are returned.
45
+
46
+ Returns:
47
+ list[BaseTool]: A list of tools available under the specified context.
48
+ """
49
+
50
+ @abstractmethod
51
+ async def close(self) -> None:
52
+ """Performs cleanup and releases resources held by the toolset.
53
+
54
+ NOTE: This method is invoked, for example, at the end of an agent server's
55
+ lifecycle or when the toolset is no longer needed. Implementations
56
+ should ensure that any open connections, files, or other managed
57
+ resources are properly released to prevent leaks.
58
+ """
@@ -0,0 +1,65 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ from typing import TYPE_CHECKING
18
+
19
+ from google.genai import types
20
+ from typing_extensions import override
21
+
22
+ from .base_tool import BaseTool
23
+ from .tool_context import ToolContext
24
+
25
+ if TYPE_CHECKING:
26
+ from ..models import LlmRequest
27
+
28
+
29
+ class EnterpriseWebSearchTool(BaseTool):
30
+ """A Gemini 2+ built-in tool using web grounding for Enterprise compliance.
31
+
32
+ See the documentation for more details:
33
+ https://cloud.google.com/vertex-ai/generative-ai/docs/grounding/web-grounding-enterprise.
34
+ """
35
+
36
+ def __init__(self):
37
+ """Initializes the Vertex AI Search tool."""
38
+ # Name and description are not used because this is a model built-in tool.
39
+ super().__init__(
40
+ name='enterprise_web_search', description='enterprise_web_search'
41
+ )
42
+
43
+ @override
44
+ async def process_llm_request(
45
+ self,
46
+ *,
47
+ tool_context: ToolContext,
48
+ llm_request: LlmRequest,
49
+ ) -> None:
50
+ if llm_request.model and llm_request.model.startswith('gemini-'):
51
+ if llm_request.model.startswith('gemini-1') and llm_request.config.tools:
52
+ raise ValueError(
53
+ 'Enterprise web search tool can not be used with other tools in'
54
+ ' Gemini 1.x.'
55
+ )
56
+ llm_request.config = llm_request.config or types.GenerateContentConfig()
57
+ llm_request.config.tools = llm_request.config.tools or []
58
+ llm_request.config.tools.append(
59
+ types.Tool(enterprise_web_search=types.EnterpriseWebSearch())
60
+ )
61
+ else:
62
+ raise ValueError(
63
+ 'Enterprise web search tool is not supported for model'
64
+ f' {llm_request.model}'
65
+ )
@@ -35,7 +35,7 @@ _py_builtin_type_to_schema_type = {
35
35
  dict: types.Type.OBJECT,
36
36
  }
37
37
 
38
- logger = logging.getLogger(__name__)
38
+ logger = logging.getLogger('google_adk.' + __name__)
39
39
 
40
40
 
41
41
  def _is_builtin_primitive_or_compound(
@@ -292,7 +292,7 @@ def _parse_schema_from_parameter(
292
292
  raise ValueError(
293
293
  f'Failed to parse the parameter {param} of function {func_name} for'
294
294
  ' automatic function calling. Automatic function calling works best with'
295
- ' simpler function signature schema,consider manually parse your'
295
+ ' simpler function signature schema, consider manually parsing your'
296
296
  f' function declaration for function {func_name}.'
297
297
  )
298
298
 
@@ -12,76 +12,24 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  __all__ = [
15
- 'bigquery_tool_set',
16
- 'calendar_tool_set',
17
- 'gmail_tool_set',
18
- 'youtube_tool_set',
19
- 'slides_tool_set',
20
- 'sheets_tool_set',
21
- 'docs_tool_set',
15
+ 'BigQueryToolset',
16
+ 'CalendarToolset',
17
+ 'GmailToolset',
18
+ 'YoutubeToolset',
19
+ 'SlidesToolset',
20
+ 'SheetsToolset',
21
+ 'DocsToolset',
22
+ 'GoogleApiToolset',
23
+ 'GoogleApiTool',
22
24
  ]
23
25
 
24
- # Nothing is imported here automatically
25
- # Each tool set will only be imported when accessed
26
26
 
27
- _bigquery_tool_set = None
28
- _calendar_tool_set = None
29
- _gmail_tool_set = None
30
- _youtube_tool_set = None
31
- _slides_tool_set = None
32
- _sheets_tool_set = None
33
- _docs_tool_set = None
34
-
35
-
36
- def __getattr__(name):
37
- global _bigquery_tool_set, _calendar_tool_set, _gmail_tool_set, _youtube_tool_set, _slides_tool_set, _sheets_tool_set, _docs_tool_set
38
-
39
- match name:
40
- case 'bigquery_tool_set':
41
- if _bigquery_tool_set is None:
42
- from .google_api_tool_sets import bigquery_tool_set as bigquery
43
-
44
- _bigquery_tool_set = bigquery
45
- return _bigquery_tool_set
46
-
47
- case 'calendar_tool_set':
48
- if _calendar_tool_set is None:
49
- from .google_api_tool_sets import calendar_tool_set as calendar
50
-
51
- _calendar_tool_set = calendar
52
- return _calendar_tool_set
53
-
54
- case 'gmail_tool_set':
55
- if _gmail_tool_set is None:
56
- from .google_api_tool_sets import gmail_tool_set as gmail
57
-
58
- _gmail_tool_set = gmail
59
- return _gmail_tool_set
60
-
61
- case 'youtube_tool_set':
62
- if _youtube_tool_set is None:
63
- from .google_api_tool_sets import youtube_tool_set as youtube
64
-
65
- _youtube_tool_set = youtube
66
- return _youtube_tool_set
67
-
68
- case 'slides_tool_set':
69
- if _slides_tool_set is None:
70
- from .google_api_tool_sets import slides_tool_set as slides
71
-
72
- _slides_tool_set = slides
73
- return _slides_tool_set
74
-
75
- case 'sheets_tool_set':
76
- if _sheets_tool_set is None:
77
- from .google_api_tool_sets import sheets_tool_set as sheets
78
-
79
- _sheets_tool_set = sheets
80
- return _sheets_tool_set
81
-
82
- case 'docs_tool_set':
83
- if _docs_tool_set is None:
84
- from .google_api_tool_sets import docs_tool_set as docs
85
-
86
- _docs_tool_set = docs
87
- return _docs_tool_set
27
+ from .google_api_tool import GoogleApiTool
28
+ from .google_api_toolset import GoogleApiToolset
29
+ from .google_api_toolsets import BigQueryToolset
30
+ from .google_api_toolsets import CalendarToolset
31
+ from .google_api_toolsets import DocsToolset
32
+ from .google_api_toolsets import GmailToolset
33
+ from .google_api_toolsets import SheetsToolset
34
+ from .google_api_toolsets import SlidesToolset
35
+ from .google_api_toolsets import YoutubeToolset
@@ -29,28 +29,34 @@ from ..tool_context import ToolContext
29
29
 
30
30
  class GoogleApiTool(BaseTool):
31
31
 
32
- def __init__(self, rest_api_tool: RestApiTool):
32
+ def __init__(
33
+ self,
34
+ rest_api_tool: RestApiTool,
35
+ client_id: Optional[str] = None,
36
+ client_secret: Optional[str] = None,
37
+ ):
33
38
  super().__init__(
34
39
  name=rest_api_tool.name,
35
40
  description=rest_api_tool.description,
36
41
  is_long_running=rest_api_tool.is_long_running,
37
42
  )
38
- self.rest_api_tool = rest_api_tool
43
+ self._rest_api_tool = rest_api_tool
44
+ self.configure_auth(client_id, client_secret)
39
45
 
40
46
  @override
41
47
  def _get_declaration(self) -> FunctionDeclaration:
42
- return self.rest_api_tool._get_declaration()
48
+ return self._rest_api_tool._get_declaration()
43
49
 
44
50
  @override
45
51
  async def run_async(
46
52
  self, *, args: dict[str, Any], tool_context: Optional[ToolContext]
47
53
  ) -> Dict[str, Any]:
48
- return await self.rest_api_tool.run_async(
54
+ return await self._rest_api_tool.run_async(
49
55
  args=args, tool_context=tool_context
50
56
  )
51
57
 
52
58
  def configure_auth(self, client_id: str, client_secret: str):
53
- self.rest_api_tool.auth_credential = AuthCredential(
59
+ self._rest_api_tool.auth_credential = AuthCredential(
54
60
  auth_type=AuthCredentialTypes.OPEN_ID_CONNECT,
55
61
  oauth2=OAuth2Auth(
56
62
  client_id=client_id,