google-adk 1.6.1__py3-none-any.whl → 1.7.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/a2a/converters/event_converter.py +5 -85
- google/adk/a2a/executor/a2a_agent_executor.py +45 -16
- google/adk/agents/__init__.py +5 -0
- google/adk/agents/agent_config.py +46 -0
- google/adk/agents/base_agent.py +234 -41
- google/adk/agents/callback_context.py +41 -0
- google/adk/agents/common_configs.py +79 -0
- google/adk/agents/config_agent_utils.py +184 -0
- google/adk/agents/config_schemas/AgentConfig.json +544 -0
- google/adk/agents/invocation_context.py +5 -1
- google/adk/agents/llm_agent.py +190 -9
- google/adk/agents/loop_agent.py +29 -0
- google/adk/agents/parallel_agent.py +24 -3
- google/adk/agents/remote_a2a_agent.py +15 -3
- google/adk/agents/sequential_agent.py +22 -1
- google/adk/artifacts/gcs_artifact_service.py +24 -2
- google/adk/auth/auth_handler.py +3 -3
- google/adk/auth/credential_manager.py +23 -23
- google/adk/auth/credential_service/base_credential_service.py +6 -6
- google/adk/auth/credential_service/in_memory_credential_service.py +10 -8
- google/adk/auth/credential_service/session_state_credential_service.py +8 -8
- google/adk/auth/exchanger/oauth2_credential_exchanger.py +3 -3
- google/adk/auth/oauth2_credential_util.py +2 -2
- google/adk/auth/refresher/oauth2_credential_refresher.py +4 -4
- google/adk/cli/agent_graph.py +3 -1
- google/adk/cli/browser/index.html +1 -1
- google/adk/cli/browser/main-SRBSE46V.js +3914 -0
- google/adk/cli/browser/polyfills-B6TNHZQ6.js +17 -0
- google/adk/cli/fast_api.py +42 -2
- google/adk/cli/utils/agent_loader.py +35 -1
- google/adk/code_executors/base_code_executor.py +14 -19
- google/adk/code_executors/built_in_code_executor.py +4 -1
- google/adk/evaluation/base_eval_service.py +46 -2
- google/adk/evaluation/evaluation_generator.py +1 -1
- google/adk/evaluation/in_memory_eval_sets_manager.py +151 -0
- google/adk/evaluation/local_eval_service.py +389 -0
- google/adk/evaluation/local_eval_sets_manager.py +23 -8
- google/adk/flows/llm_flows/auto_flow.py +6 -11
- google/adk/flows/llm_flows/base_llm_flow.py +41 -23
- google/adk/flows/llm_flows/contents.py +16 -10
- google/adk/flows/llm_flows/functions.py +76 -33
- google/adk/memory/in_memory_memory_service.py +20 -14
- google/adk/models/anthropic_llm.py +44 -5
- google/adk/models/google_llm.py +11 -6
- google/adk/models/lite_llm.py +21 -4
- google/adk/plugins/__init__.py +17 -0
- google/adk/plugins/base_plugin.py +317 -0
- google/adk/plugins/plugin_manager.py +265 -0
- google/adk/runners.py +122 -18
- google/adk/sessions/database_session_service.py +26 -28
- google/adk/sessions/vertex_ai_session_service.py +14 -7
- google/adk/tools/agent_tool.py +1 -0
- google/adk/tools/apihub_tool/apihub_toolset.py +38 -39
- google/adk/tools/application_integration_tool/application_integration_toolset.py +35 -37
- google/adk/tools/application_integration_tool/integration_connector_tool.py +2 -3
- google/adk/tools/base_tool.py +9 -9
- google/adk/tools/base_toolset.py +7 -5
- google/adk/tools/bigquery/__init__.py +3 -3
- google/adk/tools/enterprise_search_tool.py +4 -2
- google/adk/tools/google_api_tool/google_api_tool.py +16 -1
- google/adk/tools/google_api_tool/google_api_toolset.py +9 -7
- google/adk/tools/google_api_tool/google_api_toolsets.py +41 -20
- google/adk/tools/google_search_tool.py +4 -2
- google/adk/tools/langchain_tool.py +2 -3
- google/adk/tools/long_running_tool.py +21 -0
- google/adk/tools/mcp_tool/mcp_toolset.py +27 -28
- google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +8 -8
- google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py +4 -6
- google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +3 -2
- google/adk/tools/tool_context.py +0 -10
- google/adk/tools/url_context_tool.py +4 -2
- google/adk/tools/vertex_ai_search_tool.py +4 -2
- google/adk/utils/model_name_utils.py +90 -0
- google/adk/version.py +1 -1
- {google_adk-1.6.1.dist-info → google_adk-1.7.0.dist-info}/METADATA +2 -2
- {google_adk-1.6.1.dist-info → google_adk-1.7.0.dist-info}/RECORD +79 -69
- google/adk/cli/browser/main-RXDVX3K6.js +0 -3914
- google/adk/cli/browser/polyfills-FFHMD2TL.js +0 -17
- {google_adk-1.6.1.dist-info → google_adk-1.7.0.dist-info}/WHEEL +0 -0
- {google_adk-1.6.1.dist-info → google_adk-1.7.0.dist-info}/entry_points.txt +0 -0
- {google_adk-1.6.1.dist-info → google_adk-1.7.0.dist-info}/licenses/LICENSE +0 -0
google/adk/runners.py
CHANGED
@@ -17,9 +17,14 @@ from __future__ import annotations
|
|
17
17
|
import asyncio
|
18
18
|
import logging
|
19
19
|
import queue
|
20
|
+
import time
|
21
|
+
from typing import Any
|
20
22
|
from typing import AsyncGenerator
|
23
|
+
from typing import Callable
|
21
24
|
from typing import Generator
|
25
|
+
from typing import List
|
22
26
|
from typing import Optional
|
27
|
+
import uuid
|
23
28
|
import warnings
|
24
29
|
|
25
30
|
from google.genai import types
|
@@ -36,10 +41,13 @@ from .artifacts.in_memory_artifact_service import InMemoryArtifactService
|
|
36
41
|
from .auth.credential_service.base_credential_service import BaseCredentialService
|
37
42
|
from .code_executors.built_in_code_executor import BuiltInCodeExecutor
|
38
43
|
from .events.event import Event
|
44
|
+
from .events.event import EventActions
|
39
45
|
from .flows.llm_flows.functions import find_matching_function_call
|
40
46
|
from .memory.base_memory_service import BaseMemoryService
|
41
47
|
from .memory.in_memory_memory_service import InMemoryMemoryService
|
42
48
|
from .platform.thread import create_thread
|
49
|
+
from .plugins.base_plugin import BasePlugin
|
50
|
+
from .plugins.plugin_manager import PluginManager
|
43
51
|
from .sessions.base_session_service import BaseSessionService
|
44
52
|
from .sessions.in_memory_session_service import InMemorySessionService
|
45
53
|
from .sessions.session import Session
|
@@ -60,6 +68,7 @@ class Runner:
|
|
60
68
|
app_name: The application name of the runner.
|
61
69
|
agent: The root agent to run.
|
62
70
|
artifact_service: The artifact service for the runner.
|
71
|
+
plugin_manager: The plugin manager for the runner.
|
63
72
|
session_service: The session service for the runner.
|
64
73
|
memory_service: The memory service for the runner.
|
65
74
|
"""
|
@@ -70,6 +79,8 @@ class Runner:
|
|
70
79
|
"""The root agent to run."""
|
71
80
|
artifact_service: Optional[BaseArtifactService] = None
|
72
81
|
"""The artifact service for the runner."""
|
82
|
+
plugin_manager: PluginManager
|
83
|
+
"""The plugin manager for the runner."""
|
73
84
|
session_service: BaseSessionService
|
74
85
|
"""The session service for the runner."""
|
75
86
|
memory_service: Optional[BaseMemoryService] = None
|
@@ -82,6 +93,7 @@ class Runner:
|
|
82
93
|
*,
|
83
94
|
app_name: str,
|
84
95
|
agent: BaseAgent,
|
96
|
+
plugins: Optional[List[BasePlugin]] = None,
|
85
97
|
artifact_service: Optional[BaseArtifactService] = None,
|
86
98
|
session_service: BaseSessionService,
|
87
99
|
memory_service: Optional[BaseMemoryService] = None,
|
@@ -102,6 +114,7 @@ class Runner:
|
|
102
114
|
self.session_service = session_service
|
103
115
|
self.memory_service = memory_service
|
104
116
|
self.credential_service = credential_service
|
117
|
+
self.plugin_manager = PluginManager(plugins=plugins)
|
105
118
|
|
106
119
|
def run(
|
107
120
|
self,
|
@@ -113,8 +126,9 @@ class Runner:
|
|
113
126
|
) -> Generator[Event, None, None]:
|
114
127
|
"""Runs the agent.
|
115
128
|
|
116
|
-
NOTE:
|
117
|
-
|
129
|
+
NOTE:
|
130
|
+
This sync interface is only for local testing and convenience purpose.
|
131
|
+
Consider using `run_async` for production usage.
|
118
132
|
|
119
133
|
Args:
|
120
134
|
user_id: The user ID of the session.
|
@@ -164,6 +178,7 @@ class Runner:
|
|
164
178
|
user_id: str,
|
165
179
|
session_id: str,
|
166
180
|
new_message: types.Content,
|
181
|
+
state_delta: Optional[dict[str, Any]] = None,
|
167
182
|
run_config: RunConfig = RunConfig(),
|
168
183
|
) -> AsyncGenerator[Event, None]:
|
169
184
|
"""Main entry method to run the agent in this runner.
|
@@ -191,19 +206,83 @@ class Runner:
|
|
191
206
|
)
|
192
207
|
root_agent = self.agent
|
193
208
|
|
209
|
+
# Modify user message before execution.
|
210
|
+
modified_user_message = (
|
211
|
+
await invocation_context.plugin_manager.run_on_user_message_callback(
|
212
|
+
invocation_context=invocation_context, user_message=new_message
|
213
|
+
)
|
214
|
+
)
|
215
|
+
if modified_user_message is not None:
|
216
|
+
new_message = modified_user_message
|
217
|
+
|
194
218
|
if new_message:
|
195
219
|
await self._append_new_message_to_session(
|
196
220
|
session,
|
197
221
|
new_message,
|
198
222
|
invocation_context,
|
199
223
|
run_config.save_input_blobs_as_artifacts,
|
224
|
+
state_delta,
|
200
225
|
)
|
201
226
|
|
202
227
|
invocation_context.agent = self._find_agent_to_run(session, root_agent)
|
203
|
-
|
228
|
+
|
229
|
+
async def execute(ctx: InvocationContext) -> AsyncGenerator[Event]:
|
230
|
+
async for event in ctx.agent.run_async(ctx):
|
231
|
+
yield event
|
232
|
+
|
233
|
+
async for event in self._exec_with_plugin(
|
234
|
+
invocation_context, session, execute
|
235
|
+
):
|
236
|
+
yield event
|
237
|
+
|
238
|
+
async def _exec_with_plugin(
|
239
|
+
self,
|
240
|
+
invocation_context: InvocationContext,
|
241
|
+
session: Session,
|
242
|
+
execute_fn: Callable[[InvocationContext], AsyncGenerator[Event, None]],
|
243
|
+
) -> AsyncGenerator[Event, None]:
|
244
|
+
"""Wraps execution with plugin callbacks.
|
245
|
+
|
246
|
+
Args:
|
247
|
+
invocation_context: The invocation context
|
248
|
+
session: The current session
|
249
|
+
execute_fn: A callable that returns an AsyncGenerator of Events
|
250
|
+
|
251
|
+
Yields:
|
252
|
+
Events from the execution, including any generated by plugins
|
253
|
+
"""
|
254
|
+
|
255
|
+
plugin_manager = invocation_context.plugin_manager
|
256
|
+
|
257
|
+
# Step 1: Run the before_run callbacks to see if we should early exit.
|
258
|
+
early_exit_result = await plugin_manager.run_before_run_callback(
|
259
|
+
invocation_context=invocation_context
|
260
|
+
)
|
261
|
+
if isinstance(early_exit_result, Event):
|
262
|
+
await self.session_service.append_event(
|
263
|
+
session=session,
|
264
|
+
event=Event(
|
265
|
+
invocation_id=invocation_context.invocation_id,
|
266
|
+
author='model',
|
267
|
+
content=early_exit_result,
|
268
|
+
),
|
269
|
+
)
|
270
|
+
yield early_exit_result
|
271
|
+
else:
|
272
|
+
# Step 2: Otherwise continue with normal execution
|
273
|
+
async for event in execute_fn(invocation_context):
|
204
274
|
if not event.partial:
|
205
275
|
await self.session_service.append_event(session=session, event=event)
|
206
|
-
|
276
|
+
# Step 3: Run the on_event callbacks to optionally modify the event.
|
277
|
+
modified_event = await plugin_manager.run_on_event_callback(
|
278
|
+
invocation_context=invocation_context, event=event
|
279
|
+
)
|
280
|
+
yield (modified_event if modified_event else event)
|
281
|
+
|
282
|
+
# Step 4: Run the after_run callbacks to optionally modify the context.
|
283
|
+
await plugin_manager.run_after_run_callback(
|
284
|
+
invocation_context=invocation_context
|
285
|
+
)
|
207
286
|
|
208
287
|
async def _append_new_message_to_session(
|
209
288
|
self,
|
@@ -211,6 +290,7 @@ class Runner:
|
|
211
290
|
new_message: types.Content,
|
212
291
|
invocation_context: InvocationContext,
|
213
292
|
save_input_blobs_as_artifacts: bool = False,
|
293
|
+
state_delta: Optional[dict[str, Any]] = None,
|
214
294
|
):
|
215
295
|
"""Appends a new message to the session.
|
216
296
|
|
@@ -242,11 +322,19 @@ class Runner:
|
|
242
322
|
text=f'Uploaded file: {file_name}. It is saved into artifacts'
|
243
323
|
)
|
244
324
|
# Appends only. We do not yield the event because it's not from the model.
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
325
|
+
if state_delta:
|
326
|
+
event = Event(
|
327
|
+
invocation_id=invocation_context.invocation_id,
|
328
|
+
author='user',
|
329
|
+
actions=EventActions(state_delta=state_delta),
|
330
|
+
content=new_message,
|
331
|
+
)
|
332
|
+
else:
|
333
|
+
event = Event(
|
334
|
+
invocation_id=invocation_context.invocation_id,
|
335
|
+
author='user',
|
336
|
+
content=new_message,
|
337
|
+
)
|
250
338
|
await self.session_service.append_event(session=session, event=event)
|
251
339
|
|
252
340
|
async def run_live(
|
@@ -278,7 +366,7 @@ class Runner:
|
|
278
366
|
This feature is **experimental** and its API or behavior may change
|
279
367
|
in future releases.
|
280
368
|
|
281
|
-
..
|
369
|
+
.. NOTE::
|
282
370
|
Either `session` or both `user_id` and `session_id` must be provided.
|
283
371
|
"""
|
284
372
|
if session is None and (user_id is None or session_id is None):
|
@@ -345,8 +433,14 @@ class Runner:
|
|
345
433
|
invocation_context.active_streaming_tools[tool.__name__] = (
|
346
434
|
active_streaming_tool
|
347
435
|
)
|
348
|
-
|
349
|
-
|
436
|
+
|
437
|
+
async def execute(ctx: InvocationContext) -> AsyncGenerator[Event]:
|
438
|
+
async for event in ctx.agent.run_live(ctx):
|
439
|
+
yield event
|
440
|
+
|
441
|
+
async for event in self._exec_with_plugin(
|
442
|
+
invocation_context, session, execute
|
443
|
+
):
|
350
444
|
yield event
|
351
445
|
|
352
446
|
def _find_agent_to_run(
|
@@ -355,9 +449,10 @@ class Runner:
|
|
355
449
|
"""Finds the agent to run to continue the session.
|
356
450
|
|
357
451
|
A qualified agent must be either of:
|
452
|
+
|
358
453
|
- The agent that returned a function call and the last user message is a
|
359
454
|
function response to this function call.
|
360
|
-
- The root agent
|
455
|
+
- The root agent.
|
361
456
|
- An LlmAgent who replied last and is capable to transfer to any other agent
|
362
457
|
in the agent hierarchy.
|
363
458
|
|
@@ -366,7 +461,8 @@ class Runner:
|
|
366
461
|
root_agent: The root agent of the runner.
|
367
462
|
|
368
463
|
Returns:
|
369
|
-
The agent
|
464
|
+
The agent to run. (the active agent that should reply to the latest user
|
465
|
+
message)
|
370
466
|
"""
|
371
467
|
# If the last event is a function response, should send this response to
|
372
468
|
# the agent that returned the corressponding function call regardless the
|
@@ -395,8 +491,8 @@ class Runner:
|
|
395
491
|
def _is_transferable_across_agent_tree(self, agent_to_run: BaseAgent) -> bool:
|
396
492
|
"""Whether the agent to run can transfer to any other agent in the agent tree.
|
397
493
|
|
398
|
-
This typically means all agent_to_run's
|
399
|
-
|
494
|
+
This typically means all agent_to_run's ancestor can transfer to their
|
495
|
+
parent_agent all the way to the root_agent.
|
400
496
|
|
401
497
|
Args:
|
402
498
|
agent_to_run: The agent to check for transferability.
|
@@ -407,7 +503,7 @@ class Runner:
|
|
407
503
|
agent = agent_to_run
|
408
504
|
while agent:
|
409
505
|
if not isinstance(agent, LlmAgent):
|
410
|
-
# Only LLM-based Agent can
|
506
|
+
# Only LLM-based Agent can provide agent transfer capability.
|
411
507
|
return False
|
412
508
|
if agent.disallow_transfer_to_parent:
|
413
509
|
return False
|
@@ -450,6 +546,7 @@ class Runner:
|
|
450
546
|
session_service=self.session_service,
|
451
547
|
memory_service=self.memory_service,
|
452
548
|
credential_service=self.credential_service,
|
549
|
+
plugin_manager=self.plugin_manager,
|
453
550
|
invocation_id=invocation_id,
|
454
551
|
agent=self.agent,
|
455
552
|
session=session,
|
@@ -538,7 +635,13 @@ class InMemoryRunner(Runner):
|
|
538
635
|
session service for the runner.
|
539
636
|
"""
|
540
637
|
|
541
|
-
def __init__(
|
638
|
+
def __init__(
|
639
|
+
self,
|
640
|
+
agent: BaseAgent,
|
641
|
+
*,
|
642
|
+
app_name: str = 'InMemoryRunner',
|
643
|
+
plugins: Optional[list[BasePlugin]] = None,
|
644
|
+
):
|
542
645
|
"""Initializes the InMemoryRunner.
|
543
646
|
|
544
647
|
Args:
|
@@ -551,6 +654,7 @@ class InMemoryRunner(Runner):
|
|
551
654
|
app_name=app_name,
|
552
655
|
agent=agent,
|
553
656
|
artifact_service=InMemoryArtifactService(),
|
657
|
+
plugins=plugins,
|
554
658
|
session_service=self._in_memory_session_service,
|
555
659
|
memory_service=InMemoryMemoryService(),
|
556
660
|
)
|
@@ -137,7 +137,7 @@ class StorageSession(Base):
|
|
137
137
|
DateTime(), default=func.now(), onupdate=func.now()
|
138
138
|
)
|
139
139
|
|
140
|
-
storage_events: Mapped[list[
|
140
|
+
storage_events: Mapped[list[StorageEvent]] = relationship(
|
141
141
|
"StorageEvent",
|
142
142
|
back_populates="storage_session",
|
143
143
|
)
|
@@ -373,11 +373,11 @@ class DatabaseSessionService(BaseSessionService):
|
|
373
373
|
# 4. Build the session object with generated id
|
374
374
|
# 5. Return the session
|
375
375
|
|
376
|
-
with self.database_session_factory() as
|
376
|
+
with self.database_session_factory() as sql_session:
|
377
377
|
|
378
378
|
# Fetch app and user states from storage
|
379
|
-
storage_app_state =
|
380
|
-
storage_user_state =
|
379
|
+
storage_app_state = sql_session.get(StorageAppState, (app_name))
|
380
|
+
storage_user_state = sql_session.get(
|
381
381
|
StorageUserState, (app_name, user_id)
|
382
382
|
)
|
383
383
|
|
@@ -387,12 +387,12 @@ class DatabaseSessionService(BaseSessionService):
|
|
387
387
|
# Create state tables if not exist
|
388
388
|
if not storage_app_state:
|
389
389
|
storage_app_state = StorageAppState(app_name=app_name, state={})
|
390
|
-
|
390
|
+
sql_session.add(storage_app_state)
|
391
391
|
if not storage_user_state:
|
392
392
|
storage_user_state = StorageUserState(
|
393
393
|
app_name=app_name, user_id=user_id, state={}
|
394
394
|
)
|
395
|
-
|
395
|
+
sql_session.add(storage_user_state)
|
396
396
|
|
397
397
|
# Extract state deltas
|
398
398
|
app_state_delta, user_state_delta, session_state = _extract_state_delta(
|
@@ -416,10 +416,10 @@ class DatabaseSessionService(BaseSessionService):
|
|
416
416
|
id=session_id,
|
417
417
|
state=session_state,
|
418
418
|
)
|
419
|
-
|
420
|
-
|
419
|
+
sql_session.add(storage_session)
|
420
|
+
sql_session.commit()
|
421
421
|
|
422
|
-
|
422
|
+
sql_session.refresh(storage_session)
|
423
423
|
|
424
424
|
# Merge states for response
|
425
425
|
merged_state = _merge_state(app_state, user_state, session_state)
|
@@ -444,8 +444,8 @@ class DatabaseSessionService(BaseSessionService):
|
|
444
444
|
# 1. Get the storage session entry from session table
|
445
445
|
# 2. Get all the events based on session id and filtering config
|
446
446
|
# 3. Convert and return the session
|
447
|
-
with self.database_session_factory() as
|
448
|
-
storage_session =
|
447
|
+
with self.database_session_factory() as sql_session:
|
448
|
+
storage_session = sql_session.get(
|
449
449
|
StorageSession, (app_name, user_id, session_id)
|
450
450
|
)
|
451
451
|
if storage_session is None:
|
@@ -458,7 +458,7 @@ class DatabaseSessionService(BaseSessionService):
|
|
458
458
|
timestamp_filter = True
|
459
459
|
|
460
460
|
storage_events = (
|
461
|
-
|
461
|
+
sql_session.query(StorageEvent)
|
462
462
|
.filter(StorageEvent.app_name == app_name)
|
463
463
|
.filter(StorageEvent.session_id == storage_session.id)
|
464
464
|
.filter(StorageEvent.user_id == user_id)
|
@@ -473,8 +473,8 @@ class DatabaseSessionService(BaseSessionService):
|
|
473
473
|
)
|
474
474
|
|
475
475
|
# Fetch states from storage
|
476
|
-
storage_app_state =
|
477
|
-
storage_user_state =
|
476
|
+
storage_app_state = sql_session.get(StorageAppState, (app_name))
|
477
|
+
storage_user_state = sql_session.get(
|
478
478
|
StorageUserState, (app_name, user_id)
|
479
479
|
)
|
480
480
|
|
@@ -500,9 +500,9 @@ class DatabaseSessionService(BaseSessionService):
|
|
500
500
|
async def list_sessions(
|
501
501
|
self, *, app_name: str, user_id: str
|
502
502
|
) -> ListSessionsResponse:
|
503
|
-
with self.database_session_factory() as
|
503
|
+
with self.database_session_factory() as sql_session:
|
504
504
|
results = (
|
505
|
-
|
505
|
+
sql_session.query(StorageSession)
|
506
506
|
.filter(StorageSession.app_name == app_name)
|
507
507
|
.filter(StorageSession.user_id == user_id)
|
508
508
|
.all()
|
@@ -523,14 +523,14 @@ class DatabaseSessionService(BaseSessionService):
|
|
523
523
|
async def delete_session(
|
524
524
|
self, app_name: str, user_id: str, session_id: str
|
525
525
|
) -> None:
|
526
|
-
with self.database_session_factory() as
|
526
|
+
with self.database_session_factory() as sql_session:
|
527
527
|
stmt = delete(StorageSession).where(
|
528
528
|
StorageSession.app_name == app_name,
|
529
529
|
StorageSession.user_id == user_id,
|
530
530
|
StorageSession.id == session_id,
|
531
531
|
)
|
532
|
-
|
533
|
-
|
532
|
+
sql_session.execute(stmt)
|
533
|
+
sql_session.commit()
|
534
534
|
|
535
535
|
@override
|
536
536
|
async def append_event(self, session: Session, event: Event) -> Event:
|
@@ -542,8 +542,8 @@ class DatabaseSessionService(BaseSessionService):
|
|
542
542
|
# 1. Check if timestamp is stale
|
543
543
|
# 2. Update session attributes based on event config
|
544
544
|
# 3. Store event to table
|
545
|
-
with self.database_session_factory() as
|
546
|
-
storage_session =
|
545
|
+
with self.database_session_factory() as sql_session:
|
546
|
+
storage_session = sql_session.get(
|
547
547
|
StorageSession, (session.app_name, session.user_id, session.id)
|
548
548
|
)
|
549
549
|
|
@@ -557,10 +557,8 @@ class DatabaseSessionService(BaseSessionService):
|
|
557
557
|
)
|
558
558
|
|
559
559
|
# Fetch states from storage
|
560
|
-
storage_app_state =
|
561
|
-
|
562
|
-
)
|
563
|
-
storage_user_state = session_factory.get(
|
560
|
+
storage_app_state = sql_session.get(StorageAppState, (session.app_name))
|
561
|
+
storage_user_state = sql_session.get(
|
564
562
|
StorageUserState, (session.app_name, session.user_id)
|
565
563
|
)
|
566
564
|
|
@@ -589,10 +587,10 @@ class DatabaseSessionService(BaseSessionService):
|
|
589
587
|
session_state.update(session_state_delta)
|
590
588
|
storage_session.state = session_state
|
591
589
|
|
592
|
-
|
590
|
+
sql_session.add(StorageEvent.from_event(session, event))
|
593
591
|
|
594
|
-
|
595
|
-
|
592
|
+
sql_session.commit()
|
593
|
+
sql_session.refresh(storage_session)
|
596
594
|
|
597
595
|
# Update timestamp with commit time
|
598
596
|
session.last_update_time = storage_session.update_timestamp_tz
|
@@ -216,29 +216,36 @@ class VertexAiSessionService(BaseSessionService):
|
|
216
216
|
path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session_id}/events',
|
217
217
|
request_dict={},
|
218
218
|
)
|
219
|
-
|
219
|
+
converted_api_response = _convert_api_response(list_events_api_response)
|
220
220
|
|
221
|
-
# Handles empty response case
|
222
|
-
if not
|
221
|
+
# Handles empty response case where there are no events to fetch
|
222
|
+
if not converted_api_response or converted_api_response.get(
|
223
223
|
'httpHeaders', None
|
224
224
|
):
|
225
225
|
return session
|
226
226
|
|
227
227
|
session.events += [
|
228
228
|
_from_api_event(event)
|
229
|
-
for event in
|
229
|
+
for event in converted_api_response['sessionEvents']
|
230
230
|
]
|
231
231
|
|
232
|
-
while
|
233
|
-
page_token =
|
232
|
+
while converted_api_response.get('nextPageToken', None):
|
233
|
+
page_token = converted_api_response.get('nextPageToken', None)
|
234
234
|
list_events_api_response = await api_client.async_request(
|
235
235
|
http_method='GET',
|
236
236
|
path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session_id}/events?pageToken={page_token}',
|
237
237
|
request_dict={},
|
238
238
|
)
|
239
|
+
converted_api_response = _convert_api_response(list_events_api_response)
|
240
|
+
|
241
|
+
# Handles empty response case where there are no more events to fetch
|
242
|
+
if not converted_api_response or converted_api_response.get(
|
243
|
+
'httpHeaders', None
|
244
|
+
):
|
245
|
+
break
|
239
246
|
session.events += [
|
240
247
|
_from_api_event(event)
|
241
|
-
for event in
|
248
|
+
for event in converted_api_response['sessionEvents']
|
242
249
|
]
|
243
250
|
|
244
251
|
session.events = [
|
google/adk/tools/agent_tool.py
CHANGED
@@ -116,6 +116,7 @@ class AgentTool(BaseTool):
|
|
116
116
|
artifact_service=ForwardingArtifactService(tool_context),
|
117
117
|
session_service=InMemorySessionService(),
|
118
118
|
memory_service=InMemoryMemoryService(),
|
119
|
+
credential_service=tool_context._invocation_context.credential_service,
|
119
120
|
)
|
120
121
|
session = await runner.session_service.create_session(
|
121
122
|
app_name=self.agent.name,
|
@@ -35,27 +35,25 @@ from .clients.apihub_client import APIHubClient
|
|
35
35
|
class APIHubToolset(BaseToolset):
|
36
36
|
"""APIHubTool generates tools from a given API Hub resource.
|
37
37
|
|
38
|
-
Examples
|
38
|
+
Examples::
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
)
|
47
|
-
|
48
|
-
# Get all available tools
|
49
|
-
agent = LlmAgent(tools=apihub_toolset)
|
40
|
+
apihub_toolset = APIHubToolset(
|
41
|
+
apihub_resource_name="projects/test-project/locations/us-central1/apis/test-api",
|
42
|
+
service_account_json="...",
|
43
|
+
tool_filter=lambda tool, ctx=None: tool.name in ('my_tool',
|
44
|
+
'my_other_tool')
|
45
|
+
)
|
50
46
|
|
51
|
-
|
47
|
+
# Get all available tools
|
48
|
+
agent = LlmAgent(tools=apihub_toolset)
|
52
49
|
|
53
50
|
**apihub_resource_name** is the resource name from API Hub. It must include
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
51
|
+
API name, and can optionally include API version and spec name.
|
52
|
+
|
53
|
+
- If apihub_resource_name includes a spec resource name, the content of that
|
54
|
+
spec will be used for generating the tools.
|
55
|
+
- If apihub_resource_name includes only an api or a version name, the
|
56
|
+
first spec of the first version of that API will be used.
|
59
57
|
"""
|
60
58
|
|
61
59
|
def __init__(
|
@@ -78,44 +76,45 @@ class APIHubToolset(BaseToolset):
|
|
78
76
|
):
|
79
77
|
"""Initializes the APIHubTool with the given parameters.
|
80
78
|
|
81
|
-
Examples
|
82
|
-
```
|
83
|
-
apihub_toolset = APIHubToolset(
|
84
|
-
apihub_resource_name="projects/test-project/locations/us-central1/apis/test-api",
|
85
|
-
service_account_json="...",
|
86
|
-
)
|
79
|
+
Examples::
|
87
80
|
|
88
|
-
|
89
|
-
|
81
|
+
apihub_toolset = APIHubToolset(
|
82
|
+
apihub_resource_name="projects/test-project/locations/us-central1/apis/test-api",
|
83
|
+
service_account_json="...",
|
84
|
+
)
|
90
85
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
86
|
+
# Get all available tools
|
87
|
+
agent = LlmAgent(tools=[apihub_toolset])
|
88
|
+
|
89
|
+
apihub_toolset = APIHubToolset(
|
90
|
+
apihub_resource_name="projects/test-project/locations/us-central1/apis/test-api",
|
91
|
+
service_account_json="...",
|
92
|
+
tool_filter = ['my_tool']
|
93
|
+
)
|
94
|
+
# Get a specific tool
|
95
|
+
agent = LlmAgent(tools=[
|
96
|
+
...,
|
97
|
+
apihub_toolset,
|
98
|
+
])
|
102
99
|
|
103
100
|
**apihub_resource_name** is the resource name from API Hub. It must include
|
104
101
|
API name, and can optionally include API version and spec name.
|
102
|
+
|
105
103
|
- If apihub_resource_name includes a spec resource name, the content of that
|
106
104
|
spec will be used for generating the tools.
|
107
105
|
- If apihub_resource_name includes only an api or a version name, the
|
108
106
|
first spec of the first version of that API will be used.
|
109
107
|
|
110
108
|
Example:
|
109
|
+
|
111
110
|
* projects/xxx/locations/us-central1/apis/apiname/...
|
112
111
|
* https://console.cloud.google.com/apigee/api-hub/apis/apiname?project=xxx
|
113
112
|
|
114
113
|
Args:
|
115
114
|
apihub_resource_name: The resource name of the API in API Hub.
|
116
|
-
Example:
|
117
|
-
access_token: Google Access token. Generate with gcloud cli
|
118
|
-
auth print-access-token
|
115
|
+
Example: ``projects/test-project/locations/us-central1/apis/test-api``.
|
116
|
+
access_token: Google Access token. Generate with gcloud cli
|
117
|
+
``gcloud auth auth print-access-token``. Used for fetching API Specs from API Hub.
|
119
118
|
service_account_json: The service account config as a json string.
|
120
119
|
Required if not using default service credential. It is used for
|
121
120
|
creating the API Hub client and fetching the API Specs from API Hub.
|