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
@@ -13,6 +13,7 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
import copy
|
16
|
+
import logging
|
16
17
|
import time
|
17
18
|
from typing import Any
|
18
19
|
from typing import Optional
|
@@ -23,17 +24,19 @@ from typing_extensions import override
|
|
23
24
|
from ..events.event import Event
|
24
25
|
from .base_session_service import BaseSessionService
|
25
26
|
from .base_session_service import GetSessionConfig
|
26
|
-
from .base_session_service import ListEventsResponse
|
27
27
|
from .base_session_service import ListSessionsResponse
|
28
28
|
from .session import Session
|
29
29
|
from .state import State
|
30
30
|
|
31
|
+
logger = logging.getLogger('google_adk.' + __name__)
|
32
|
+
|
31
33
|
|
32
34
|
class InMemorySessionService(BaseSessionService):
|
33
35
|
"""An in-memory implementation of the session service."""
|
34
36
|
|
35
37
|
def __init__(self):
|
36
|
-
# A map from app name to a map from user ID to a map from session ID to
|
38
|
+
# A map from app name to a map from user ID to a map from session ID to
|
39
|
+
# session.
|
37
40
|
self.sessions: dict[str, dict[str, dict[str, Session]]] = {}
|
38
41
|
# A map from app name to a map from user ID to a map from key to the value.
|
39
42
|
self.user_state: dict[str, dict[str, dict[str, Any]]] = {}
|
@@ -41,7 +44,38 @@ class InMemorySessionService(BaseSessionService):
|
|
41
44
|
self.app_state: dict[str, dict[str, Any]] = {}
|
42
45
|
|
43
46
|
@override
|
44
|
-
def create_session(
|
47
|
+
async def create_session(
|
48
|
+
self,
|
49
|
+
*,
|
50
|
+
app_name: str,
|
51
|
+
user_id: str,
|
52
|
+
state: Optional[dict[str, Any]] = None,
|
53
|
+
session_id: Optional[str] = None,
|
54
|
+
) -> Session:
|
55
|
+
return self._create_session_impl(
|
56
|
+
app_name=app_name,
|
57
|
+
user_id=user_id,
|
58
|
+
state=state,
|
59
|
+
session_id=session_id,
|
60
|
+
)
|
61
|
+
|
62
|
+
def create_session_sync(
|
63
|
+
self,
|
64
|
+
*,
|
65
|
+
app_name: str,
|
66
|
+
user_id: str,
|
67
|
+
state: Optional[dict[str, Any]] = None,
|
68
|
+
session_id: Optional[str] = None,
|
69
|
+
) -> Session:
|
70
|
+
logger.warning('Deprecated. Please migrate to the async method.')
|
71
|
+
return self._create_session_impl(
|
72
|
+
app_name=app_name,
|
73
|
+
user_id=user_id,
|
74
|
+
state=state,
|
75
|
+
session_id=session_id,
|
76
|
+
)
|
77
|
+
|
78
|
+
def _create_session_impl(
|
45
79
|
self,
|
46
80
|
*,
|
47
81
|
app_name: str,
|
@@ -72,14 +106,45 @@ class InMemorySessionService(BaseSessionService):
|
|
72
106
|
return self._merge_state(app_name, user_id, copied_session)
|
73
107
|
|
74
108
|
@override
|
75
|
-
def get_session(
|
109
|
+
async def get_session(
|
76
110
|
self,
|
77
111
|
*,
|
78
112
|
app_name: str,
|
79
113
|
user_id: str,
|
80
114
|
session_id: str,
|
81
115
|
config: Optional[GetSessionConfig] = None,
|
82
|
-
) -> Session:
|
116
|
+
) -> Optional[Session]:
|
117
|
+
return self._get_session_impl(
|
118
|
+
app_name=app_name,
|
119
|
+
user_id=user_id,
|
120
|
+
session_id=session_id,
|
121
|
+
config=config,
|
122
|
+
)
|
123
|
+
|
124
|
+
def get_session_sync(
|
125
|
+
self,
|
126
|
+
*,
|
127
|
+
app_name: str,
|
128
|
+
user_id: str,
|
129
|
+
session_id: str,
|
130
|
+
config: Optional[GetSessionConfig] = None,
|
131
|
+
) -> Optional[Session]:
|
132
|
+
logger.warning('Deprecated. Please migrate to the async method.')
|
133
|
+
return self._get_session_impl(
|
134
|
+
app_name=app_name,
|
135
|
+
user_id=user_id,
|
136
|
+
session_id=session_id,
|
137
|
+
config=config,
|
138
|
+
)
|
139
|
+
|
140
|
+
def _get_session_impl(
|
141
|
+
self,
|
142
|
+
*,
|
143
|
+
app_name: str,
|
144
|
+
user_id: str,
|
145
|
+
session_id: str,
|
146
|
+
config: Optional[GetSessionConfig] = None,
|
147
|
+
) -> Optional[Session]:
|
83
148
|
if app_name not in self.sessions:
|
84
149
|
return None
|
85
150
|
if user_id not in self.sessions[app_name]:
|
@@ -102,11 +167,13 @@ class InMemorySessionService(BaseSessionService):
|
|
102
167
|
break
|
103
168
|
i -= 1
|
104
169
|
if i >= 0:
|
105
|
-
copied_session.events = copied_session.events[i + 1:]
|
170
|
+
copied_session.events = copied_session.events[i + 1 :]
|
106
171
|
|
107
172
|
return self._merge_state(app_name, user_id, copied_session)
|
108
173
|
|
109
|
-
def _merge_state(
|
174
|
+
def _merge_state(
|
175
|
+
self, app_name: str, user_id: str, copied_session: Session
|
176
|
+
) -> Session:
|
110
177
|
# Merge app state
|
111
178
|
if app_name in self.app_state:
|
112
179
|
for key in self.app_state[app_name].keys():
|
@@ -128,7 +195,18 @@ class InMemorySessionService(BaseSessionService):
|
|
128
195
|
return copied_session
|
129
196
|
|
130
197
|
@override
|
131
|
-
def list_sessions(
|
198
|
+
async def list_sessions(
|
199
|
+
self, *, app_name: str, user_id: str
|
200
|
+
) -> ListSessionsResponse:
|
201
|
+
return self._list_sessions_impl(app_name=app_name, user_id=user_id)
|
202
|
+
|
203
|
+
def list_sessions_sync(
|
204
|
+
self, *, app_name: str, user_id: str
|
205
|
+
) -> ListSessionsResponse:
|
206
|
+
logger.warning('Deprecated. Please migrate to the async method.')
|
207
|
+
return self._list_sessions_impl(app_name=app_name, user_id=user_id)
|
208
|
+
|
209
|
+
def _list_sessions_impl(
|
132
210
|
self, *, app_name: str, user_id: str
|
133
211
|
) -> ListSessionsResponse:
|
134
212
|
empty_response = ListSessionsResponse()
|
@@ -145,12 +223,26 @@ class InMemorySessionService(BaseSessionService):
|
|
145
223
|
sessions_without_events.append(copied_session)
|
146
224
|
return ListSessionsResponse(sessions=sessions_without_events)
|
147
225
|
|
148
|
-
|
149
|
-
|
226
|
+
async def delete_session(
|
227
|
+
self, *, app_name: str, user_id: str, session_id: str
|
228
|
+
) -> None:
|
229
|
+
self._delete_session_impl(
|
230
|
+
app_name=app_name, user_id=user_id, session_id=session_id
|
231
|
+
)
|
232
|
+
|
233
|
+
def delete_session_sync(
|
234
|
+
self, *, app_name: str, user_id: str, session_id: str
|
235
|
+
) -> None:
|
236
|
+
logger.warning('Deprecated. Please migrate to the async method.')
|
237
|
+
self._delete_session_impl(
|
238
|
+
app_name=app_name, user_id=user_id, session_id=session_id
|
239
|
+
)
|
240
|
+
|
241
|
+
def _delete_session_impl(
|
150
242
|
self, *, app_name: str, user_id: str, session_id: str
|
151
243
|
) -> None:
|
152
244
|
if (
|
153
|
-
self.
|
245
|
+
self._get_session_impl(
|
154
246
|
app_name=app_name, user_id=user_id, session_id=session_id
|
155
247
|
)
|
156
248
|
is None
|
@@ -160,9 +252,9 @@ class InMemorySessionService(BaseSessionService):
|
|
160
252
|
self.sessions[app_name][user_id].pop(session_id)
|
161
253
|
|
162
254
|
@override
|
163
|
-
def append_event(self, session: Session, event: Event) -> Event:
|
255
|
+
async def append_event(self, session: Session, event: Event) -> Event:
|
164
256
|
# Update the in-memory session.
|
165
|
-
super().append_event(session=session, event=event)
|
257
|
+
await super().append_event(session=session, event=event)
|
166
258
|
session.last_update_time = event.timestamp
|
167
259
|
|
168
260
|
# Update the storage session
|
@@ -189,18 +281,8 @@ class InMemorySessionService(BaseSessionService):
|
|
189
281
|
] = event.actions.state_delta[key]
|
190
282
|
|
191
283
|
storage_session = self.sessions[app_name][user_id].get(session_id)
|
192
|
-
super().append_event(session=storage_session, event=event)
|
284
|
+
await super().append_event(session=storage_session, event=event)
|
193
285
|
|
194
286
|
storage_session.last_update_time = event.timestamp
|
195
287
|
|
196
288
|
return event
|
197
|
-
|
198
|
-
@override
|
199
|
-
def list_events(
|
200
|
-
self,
|
201
|
-
*,
|
202
|
-
app_name: str,
|
203
|
-
user_id: str,
|
204
|
-
session_id: str,
|
205
|
-
) -> ListEventsResponse:
|
206
|
-
raise NotImplementedError()
|
google/adk/sessions/session.py
CHANGED
@@ -14,6 +14,7 @@
|
|
14
14
|
|
15
15
|
from typing import Any
|
16
16
|
|
17
|
+
from pydantic import alias_generators
|
17
18
|
from pydantic import BaseModel
|
18
19
|
from pydantic import ConfigDict
|
19
20
|
from pydantic import Field
|
@@ -37,6 +38,8 @@ class Session(BaseModel):
|
|
37
38
|
model_config = ConfigDict(
|
38
39
|
extra='forbid',
|
39
40
|
arbitrary_types_allowed=True,
|
41
|
+
alias_generator=alias_generators.to_camel,
|
42
|
+
populate_by_name=True,
|
40
43
|
)
|
41
44
|
"""The pydantic model config."""
|
42
45
|
|
@@ -11,27 +11,27 @@
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
|
+
import asyncio
|
14
15
|
import logging
|
15
16
|
import re
|
16
|
-
import
|
17
|
-
from typing import
|
17
|
+
from typing import Any
|
18
|
+
from typing import Optional
|
18
19
|
|
19
20
|
from dateutil import parser
|
20
|
-
from google import genai
|
21
21
|
from typing_extensions import override
|
22
22
|
|
23
|
+
from google import genai
|
24
|
+
|
25
|
+
from . import _session_util
|
23
26
|
from ..events.event import Event
|
24
27
|
from ..events.event_actions import EventActions
|
25
|
-
from . import _session_util
|
26
28
|
from .base_session_service import BaseSessionService
|
27
29
|
from .base_session_service import GetSessionConfig
|
28
|
-
from .base_session_service import ListEventsResponse
|
29
30
|
from .base_session_service import ListSessionsResponse
|
30
31
|
from .session import Session
|
31
32
|
|
32
|
-
|
33
33
|
isoparse = parser.isoparse
|
34
|
-
logger = logging.getLogger(__name__)
|
34
|
+
logger = logging.getLogger('google_adk.' + __name__)
|
35
35
|
|
36
36
|
|
37
37
|
class VertexAiSessionService(BaseSessionService):
|
@@ -49,7 +49,7 @@ class VertexAiSessionService(BaseSessionService):
|
|
49
49
|
self.api_client = client._api_client
|
50
50
|
|
51
51
|
@override
|
52
|
-
def create_session(
|
52
|
+
async def create_session(
|
53
53
|
self,
|
54
54
|
*,
|
55
55
|
app_name: str,
|
@@ -57,13 +57,20 @@ class VertexAiSessionService(BaseSessionService):
|
|
57
57
|
state: Optional[dict[str, Any]] = None,
|
58
58
|
session_id: Optional[str] = None,
|
59
59
|
) -> Session:
|
60
|
+
if session_id:
|
61
|
+
raise ValueError(
|
62
|
+
'User-provided Session id is not supported for'
|
63
|
+
' VertexAISessionService.'
|
64
|
+
)
|
65
|
+
|
60
66
|
reasoning_engine_id = _parse_reasoning_engine_id(app_name)
|
61
67
|
|
62
68
|
session_json_dict = {'user_id': user_id}
|
63
69
|
if state:
|
64
70
|
session_json_dict['session_state'] = state
|
65
71
|
|
66
|
-
|
72
|
+
api_client = _get_api_client(self.project, self.location)
|
73
|
+
api_response = await api_client.async_request(
|
67
74
|
http_method='POST',
|
68
75
|
path=f'reasoningEngines/{reasoning_engine_id}/sessions',
|
69
76
|
request_dict=session_json_dict,
|
@@ -75,7 +82,7 @@ class VertexAiSessionService(BaseSessionService):
|
|
75
82
|
|
76
83
|
max_retry_attempt = 5
|
77
84
|
while max_retry_attempt >= 0:
|
78
|
-
lro_response =
|
85
|
+
lro_response = await api_client.async_request(
|
79
86
|
http_method='GET',
|
80
87
|
path=f'operations/{operation_id}',
|
81
88
|
request_dict={},
|
@@ -84,11 +91,11 @@ class VertexAiSessionService(BaseSessionService):
|
|
84
91
|
if lro_response.get('done', None):
|
85
92
|
break
|
86
93
|
|
87
|
-
|
94
|
+
await asyncio.sleep(1)
|
88
95
|
max_retry_attempt -= 1
|
89
96
|
|
90
97
|
# Get session resource
|
91
|
-
get_session_api_response =
|
98
|
+
get_session_api_response = await api_client.async_request(
|
92
99
|
http_method='GET',
|
93
100
|
path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session_id}',
|
94
101
|
request_dict={},
|
@@ -107,18 +114,19 @@ class VertexAiSessionService(BaseSessionService):
|
|
107
114
|
return session
|
108
115
|
|
109
116
|
@override
|
110
|
-
def get_session(
|
117
|
+
async def get_session(
|
111
118
|
self,
|
112
119
|
*,
|
113
120
|
app_name: str,
|
114
121
|
user_id: str,
|
115
122
|
session_id: str,
|
116
123
|
config: Optional[GetSessionConfig] = None,
|
117
|
-
) -> Session:
|
124
|
+
) -> Optional[Session]:
|
118
125
|
reasoning_engine_id = _parse_reasoning_engine_id(app_name)
|
119
126
|
|
120
127
|
# Get session resource
|
121
|
-
|
128
|
+
api_client = _get_api_client(self.project, self.location)
|
129
|
+
get_session_api_response = await api_client.async_request(
|
122
130
|
http_method='GET',
|
123
131
|
path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session_id}',
|
124
132
|
request_dict={},
|
@@ -136,7 +144,7 @@ class VertexAiSessionService(BaseSessionService):
|
|
136
144
|
last_update_time=update_timestamp,
|
137
145
|
)
|
138
146
|
|
139
|
-
list_events_api_response =
|
147
|
+
list_events_api_response = await api_client.async_request(
|
140
148
|
http_method='GET',
|
141
149
|
path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session_id}/events',
|
142
150
|
request_dict={},
|
@@ -170,12 +178,13 @@ class VertexAiSessionService(BaseSessionService):
|
|
170
178
|
return session
|
171
179
|
|
172
180
|
@override
|
173
|
-
def list_sessions(
|
181
|
+
async def list_sessions(
|
174
182
|
self, *, app_name: str, user_id: str
|
175
183
|
) -> ListSessionsResponse:
|
176
184
|
reasoning_engine_id = _parse_reasoning_engine_id(app_name)
|
177
185
|
|
178
|
-
|
186
|
+
api_client = _get_api_client(self.project, self.location)
|
187
|
+
api_response = await api_client.async_request(
|
179
188
|
http_method='GET',
|
180
189
|
path=f'reasoningEngines/{reasoning_engine_id}/sessions?filter=user_id={user_id}',
|
181
190
|
request_dict={},
|
@@ -197,58 +206,42 @@ class VertexAiSessionService(BaseSessionService):
|
|
197
206
|
sessions.append(session)
|
198
207
|
return ListSessionsResponse(sessions=sessions)
|
199
208
|
|
200
|
-
def delete_session(
|
209
|
+
async def delete_session(
|
201
210
|
self, *, app_name: str, user_id: str, session_id: str
|
202
211
|
) -> None:
|
203
212
|
reasoning_engine_id = _parse_reasoning_engine_id(app_name)
|
204
|
-
self.
|
213
|
+
api_client = _get_api_client(self.project, self.location)
|
214
|
+
await api_client.async_request(
|
205
215
|
http_method='DELETE',
|
206
216
|
path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session_id}',
|
207
217
|
request_dict={},
|
208
218
|
)
|
209
219
|
|
210
220
|
@override
|
211
|
-
def
|
212
|
-
self,
|
213
|
-
*,
|
214
|
-
app_name: str,
|
215
|
-
user_id: str,
|
216
|
-
session_id: str,
|
217
|
-
) -> ListEventsResponse:
|
218
|
-
reasoning_engine_id = _parse_reasoning_engine_id(app_name)
|
219
|
-
api_response = self.api_client.request(
|
220
|
-
http_method='GET',
|
221
|
-
path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session_id}/events',
|
222
|
-
request_dict={},
|
223
|
-
)
|
224
|
-
|
225
|
-
logger.info(f'List events response {api_response}')
|
226
|
-
|
227
|
-
# Handles empty response case
|
228
|
-
if api_response.get('httpHeaders', None):
|
229
|
-
return ListEventsResponse()
|
230
|
-
|
231
|
-
session_events = api_response['sessionEvents']
|
232
|
-
|
233
|
-
return ListEventsResponse(
|
234
|
-
events=[_from_api_event(event) for event in session_events]
|
235
|
-
)
|
236
|
-
|
237
|
-
@override
|
238
|
-
def append_event(self, session: Session, event: Event) -> Event:
|
221
|
+
async def append_event(self, session: Session, event: Event) -> Event:
|
239
222
|
# Update the in-memory session.
|
240
|
-
super().append_event(session=session, event=event)
|
223
|
+
await super().append_event(session=session, event=event)
|
241
224
|
|
242
225
|
reasoning_engine_id = _parse_reasoning_engine_id(session.app_name)
|
243
|
-
self.
|
226
|
+
api_client = _get_api_client(self.project, self.location)
|
227
|
+
await api_client.async_request(
|
244
228
|
http_method='POST',
|
245
229
|
path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session.id}:appendEvent',
|
246
230
|
request_dict=_convert_event_to_json(event),
|
247
231
|
)
|
248
|
-
|
249
232
|
return event
|
250
233
|
|
251
234
|
|
235
|
+
def _get_api_client(project: str, location: str):
|
236
|
+
"""Instantiates an API client for the given project and location.
|
237
|
+
|
238
|
+
It needs to be instantiated inside each request so that the event loop
|
239
|
+
management.
|
240
|
+
"""
|
241
|
+
client = genai.Client(vertexai=True, project=project, location=location)
|
242
|
+
return client._api_client
|
243
|
+
|
244
|
+
|
252
245
|
def _convert_event_to_json(event: Event):
|
253
246
|
metadata_json = {
|
254
247
|
'partial': event.partial,
|
google/adk/telemetry.py
CHANGED
@@ -32,7 +32,6 @@ from .events.event import Event
|
|
32
32
|
from .models.llm_request import LlmRequest
|
33
33
|
from .models.llm_response import LlmResponse
|
34
34
|
|
35
|
-
|
36
35
|
tracer = trace.get_tracer('gcp.vertex.agent')
|
37
36
|
|
38
37
|
|
@@ -111,11 +110,17 @@ def trace_call_llm(
|
|
111
110
|
span.set_attribute(
|
112
111
|
'gcp.vertex.agent.invocation_id', invocation_context.invocation_id
|
113
112
|
)
|
113
|
+
span.set_attribute(
|
114
|
+
'gcp.vertex.agent.session_id', invocation_context.session.id
|
115
|
+
)
|
114
116
|
span.set_attribute('gcp.vertex.agent.event_id', event_id)
|
115
117
|
# Consider removing once GenAI SDK provides a way to record this info.
|
116
118
|
span.set_attribute(
|
117
119
|
'gcp.vertex.agent.llm_request',
|
118
|
-
json.dumps(
|
120
|
+
json.dumps(
|
121
|
+
_build_llm_request_for_trace(llm_request),
|
122
|
+
default=lambda o: '<not serializable>',
|
123
|
+
),
|
119
124
|
)
|
120
125
|
# Consider removing once GenAI SDK provides a way to record this info.
|
121
126
|
span.set_attribute(
|
google/adk/tools/__init__.py
CHANGED
@@ -11,31 +11,28 @@
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
|
-
|
15
|
-
from .base_tool import BaseTool
|
14
|
+
|
16
15
|
|
17
16
|
from ..auth.auth_tool import AuthToolArguments
|
18
17
|
from .apihub_tool.apihub_toolset import APIHubToolset
|
19
|
-
from .
|
20
|
-
from .google_search_tool import google_search
|
21
|
-
from .vertex_ai_search_tool import VertexAiSearchTool
|
18
|
+
from .base_tool import BaseTool
|
22
19
|
from .example_tool import ExampleTool
|
23
20
|
from .exit_loop_tool import exit_loop
|
24
21
|
from .function_tool import FunctionTool
|
25
22
|
from .get_user_choice_tool import get_user_choice_tool as get_user_choice
|
23
|
+
from .google_search_tool import google_search
|
26
24
|
from .load_artifacts_tool import load_artifacts_tool as load_artifacts
|
27
25
|
from .load_memory_tool import load_memory_tool as load_memory
|
28
26
|
from .long_running_tool import LongRunningFunctionTool
|
29
27
|
from .preload_memory_tool import preload_memory_tool as preload_memory
|
30
28
|
from .tool_context import ToolContext
|
31
29
|
from .transfer_to_agent_tool import transfer_to_agent
|
32
|
-
|
30
|
+
from .vertex_ai_search_tool import VertexAiSearchTool
|
33
31
|
|
34
32
|
__all__ = [
|
35
33
|
'APIHubToolset',
|
36
34
|
'AuthToolArguments',
|
37
35
|
'BaseTool',
|
38
|
-
'built_in_code_execution',
|
39
36
|
'google_search',
|
40
37
|
'VertexAiSearchTool',
|
41
38
|
'ExampleTool',
|
@@ -0,0 +1,30 @@
|
|
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
|
+
|
16
|
+
from __future__ import annotations
|
17
|
+
|
18
|
+
from typing import TYPE_CHECKING
|
19
|
+
|
20
|
+
if TYPE_CHECKING:
|
21
|
+
from ..memory.memory_entry import MemoryEntry
|
22
|
+
|
23
|
+
|
24
|
+
def extract_text(memory: MemoryEntry, splitter: str = ' ') -> str:
|
25
|
+
"""Extracts the text from the memory entry."""
|
26
|
+
if not memory.content.parts:
|
27
|
+
return ''
|
28
|
+
return splitter.join(
|
29
|
+
[part.text for part in memory.content.parts if part.text]
|
30
|
+
)
|
google/adk/tools/agent_tool.py
CHANGED
@@ -21,10 +21,10 @@ from google.genai import types
|
|
21
21
|
from pydantic import model_validator
|
22
22
|
from typing_extensions import override
|
23
23
|
|
24
|
+
from . import _automatic_function_calling_util
|
24
25
|
from ..memory.in_memory_memory_service import InMemoryMemoryService
|
25
26
|
from ..runners import Runner
|
26
27
|
from ..sessions.in_memory_session_service import InMemorySessionService
|
27
|
-
from . import _automatic_function_calling_util
|
28
28
|
from .base_tool import BaseTool
|
29
29
|
from .tool_context import ToolContext
|
30
30
|
|
@@ -129,7 +129,7 @@ class AgentTool(BaseTool):
|
|
129
129
|
session_service=InMemorySessionService(),
|
130
130
|
memory_service=InMemoryMemoryService(),
|
131
131
|
)
|
132
|
-
session = runner.session_service.create_session(
|
132
|
+
session = await runner.session_service.create_session(
|
133
133
|
app_name=self.agent.name,
|
134
134
|
user_id='tmp_user',
|
135
135
|
state=tool_context.state.to_dict(),
|
@@ -162,17 +162,17 @@ class AgentTool(BaseTool):
|
|
162
162
|
filename=artifact_name, artifact=artifact
|
163
163
|
)
|
164
164
|
|
165
|
-
if
|
166
|
-
not last_event
|
167
|
-
or not last_event.content
|
168
|
-
or not last_event.content.parts
|
169
|
-
or not last_event.content.parts[0].text
|
170
|
-
):
|
165
|
+
if not last_event or not last_event.content or not last_event.content.parts:
|
171
166
|
return ''
|
172
167
|
if isinstance(self.agent, LlmAgent) and self.agent.output_schema:
|
168
|
+
merged_text = '\n'.join(
|
169
|
+
[p.text for p in last_event.content.parts if p.text]
|
170
|
+
)
|
173
171
|
tool_result = self.agent.output_schema.model_validate_json(
|
174
|
-
|
172
|
+
merged_text
|
175
173
|
).model_dump(exclude_none=True)
|
176
174
|
else:
|
177
|
-
tool_result =
|
175
|
+
tool_result = '\n'.join(
|
176
|
+
[p.text for p in last_event.content.parts if p.text]
|
177
|
+
)
|
178
178
|
return tool_result
|