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
@@ -13,9 +13,11 @@
13
13
  # limitations under the License.
14
14
  import copy
15
15
  from datetime import datetime
16
+ from datetime import timezone
16
17
  import json
17
18
  import logging
18
- from typing import Any, Optional
19
+ from typing import Any
20
+ from typing import Optional
19
21
  import uuid
20
22
 
21
23
  from sqlalchemy import Boolean
@@ -49,23 +51,18 @@ from ..events.event import Event
49
51
  from . import _session_util
50
52
  from .base_session_service import BaseSessionService
51
53
  from .base_session_service import GetSessionConfig
52
- from .base_session_service import ListEventsResponse
53
54
  from .base_session_service import ListSessionsResponse
54
55
  from .session import Session
55
56
  from .state import State
56
57
 
57
-
58
- logger = logging.getLogger(__name__)
58
+ logger = logging.getLogger("google_adk." + __name__)
59
59
 
60
60
  DEFAULT_MAX_KEY_LENGTH = 128
61
61
  DEFAULT_MAX_VARCHAR_LENGTH = 256
62
62
 
63
63
 
64
64
  class DynamicJSON(TypeDecorator):
65
- """A JSON-like type that uses JSONB on PostgreSQL and TEXT with JSON
66
-
67
- serialization for other databases.
68
- """
65
+ """A JSON-like type that uses JSONB on PostgreSQL and TEXT with JSON serialization for other databases."""
69
66
 
70
67
  impl = Text # Default implementation is TEXT
71
68
 
@@ -219,6 +216,7 @@ class StorageAppState(Base):
219
216
  DateTime(), default=func.now(), onupdate=func.now()
220
217
  )
221
218
 
219
+
222
220
  class StorageUserState(Base):
223
221
  """Represents a user state stored in the database."""
224
222
 
@@ -242,10 +240,7 @@ class DatabaseSessionService(BaseSessionService):
242
240
  """A session service that uses a database for storage."""
243
241
 
244
242
  def __init__(self, db_url: str):
245
- """
246
- Args:
247
- db_url: The database URL to connect to.
248
- """
243
+ """Initializes the database session service with a database URL."""
249
244
  # 1. Create DB engine for db connection
250
245
  # 2. Create all tables based on schema
251
246
  # 3. Initialize all properties
@@ -274,7 +269,7 @@ class DatabaseSessionService(BaseSessionService):
274
269
  self.inspector = inspect(self.db_engine)
275
270
 
276
271
  # DB session factory method
277
- self.DatabaseSessionFactory: sessionmaker[DatabaseSessionFactory] = (
272
+ self.database_session_factory: sessionmaker[DatabaseSessionFactory] = (
278
273
  sessionmaker(bind=self.db_engine)
279
274
  )
280
275
 
@@ -283,7 +278,7 @@ class DatabaseSessionService(BaseSessionService):
283
278
  Base.metadata.create_all(self.db_engine)
284
279
 
285
280
  @override
286
- def create_session(
281
+ async def create_session(
287
282
  self,
288
283
  *,
289
284
  app_name: str,
@@ -297,11 +292,11 @@ class DatabaseSessionService(BaseSessionService):
297
292
  # 4. Build the session object with generated id
298
293
  # 5. Return the session
299
294
 
300
- with self.DatabaseSessionFactory() as sessionFactory:
295
+ with self.database_session_factory() as session_factory:
301
296
 
302
297
  # Fetch app and user states from storage
303
- storage_app_state = sessionFactory.get(StorageAppState, (app_name))
304
- storage_user_state = sessionFactory.get(
298
+ storage_app_state = session_factory.get(StorageAppState, (app_name))
299
+ storage_user_state = session_factory.get(
305
300
  StorageUserState, (app_name, user_id)
306
301
  )
307
302
 
@@ -311,12 +306,12 @@ class DatabaseSessionService(BaseSessionService):
311
306
  # Create state tables if not exist
312
307
  if not storage_app_state:
313
308
  storage_app_state = StorageAppState(app_name=app_name, state={})
314
- sessionFactory.add(storage_app_state)
309
+ session_factory.add(storage_app_state)
315
310
  if not storage_user_state:
316
311
  storage_user_state = StorageUserState(
317
312
  app_name=app_name, user_id=user_id, state={}
318
313
  )
319
- sessionFactory.add(storage_user_state)
314
+ session_factory.add(storage_user_state)
320
315
 
321
316
  # Extract state deltas
322
317
  app_state_delta, user_state_delta, session_state = _extract_state_delta(
@@ -340,10 +335,10 @@ class DatabaseSessionService(BaseSessionService):
340
335
  id=session_id,
341
336
  state=session_state,
342
337
  )
343
- sessionFactory.add(storage_session)
344
- sessionFactory.commit()
338
+ session_factory.add(storage_session)
339
+ session_factory.commit()
345
340
 
346
- sessionFactory.refresh(storage_session)
341
+ session_factory.refresh(storage_session)
347
342
 
348
343
  # Merge states for response
349
344
  merged_state = _merge_state(app_state, user_state, session_state)
@@ -357,7 +352,7 @@ class DatabaseSessionService(BaseSessionService):
357
352
  return session
358
353
 
359
354
  @override
360
- def get_session(
355
+ async def get_session(
361
356
  self,
362
357
  *,
363
358
  app_name: str,
@@ -368,29 +363,37 @@ class DatabaseSessionService(BaseSessionService):
368
363
  # 1. Get the storage session entry from session table
369
364
  # 2. Get all the events based on session id and filtering config
370
365
  # 3. Convert and return the session
371
- with self.DatabaseSessionFactory() as sessionFactory:
372
- storage_session = sessionFactory.get(
366
+ with self.database_session_factory() as session_factory:
367
+ storage_session = session_factory.get(
373
368
  StorageSession, (app_name, user_id, session_id)
374
369
  )
375
370
  if storage_session is None:
376
371
  return None
377
372
 
373
+ if config and config.after_timestamp:
374
+ after_dt = datetime.fromtimestamp(
375
+ config.after_timestamp, tz=timezone.utc
376
+ )
377
+ timestamp_filter = StorageEvent.timestamp > after_dt
378
+ else:
379
+ timestamp_filter = True
380
+
378
381
  storage_events = (
379
- sessionFactory.query(StorageEvent)
382
+ session_factory.query(StorageEvent)
380
383
  .filter(StorageEvent.session_id == storage_session.id)
381
- .filter(
382
- StorageEvent.timestamp < config.after_timestamp
383
- if config
384
- else True
385
- )
386
- .limit(config.num_recent_events if config else None)
384
+ .filter(timestamp_filter)
387
385
  .order_by(StorageEvent.timestamp.asc())
386
+ .limit(
387
+ config.num_recent_events
388
+ if config and config.num_recent_events
389
+ else None
390
+ )
388
391
  .all()
389
392
  )
390
393
 
391
394
  # Fetch states from storage
392
- storage_app_state = sessionFactory.get(StorageAppState, (app_name))
393
- storage_user_state = sessionFactory.get(
395
+ storage_app_state = session_factory.get(StorageAppState, (app_name))
396
+ storage_user_state = session_factory.get(
394
397
  StorageUserState, (app_name, user_id)
395
398
  )
396
399
 
@@ -431,12 +434,12 @@ class DatabaseSessionService(BaseSessionService):
431
434
  return session
432
435
 
433
436
  @override
434
- def list_sessions(
437
+ async def list_sessions(
435
438
  self, *, app_name: str, user_id: str
436
439
  ) -> ListSessionsResponse:
437
- with self.DatabaseSessionFactory() as sessionFactory:
440
+ with self.database_session_factory() as session_factory:
438
441
  results = (
439
- sessionFactory.query(StorageSession)
442
+ session_factory.query(StorageSession)
440
443
  .filter(StorageSession.app_name == app_name)
441
444
  .filter(StorageSession.user_id == user_id)
442
445
  .all()
@@ -454,20 +457,20 @@ class DatabaseSessionService(BaseSessionService):
454
457
  return ListSessionsResponse(sessions=sessions)
455
458
 
456
459
  @override
457
- def delete_session(
460
+ async def delete_session(
458
461
  self, app_name: str, user_id: str, session_id: str
459
462
  ) -> None:
460
- with self.DatabaseSessionFactory() as sessionFactory:
463
+ with self.database_session_factory() as session_factory:
461
464
  stmt = delete(StorageSession).where(
462
465
  StorageSession.app_name == app_name,
463
466
  StorageSession.user_id == user_id,
464
467
  StorageSession.id == session_id,
465
468
  )
466
- sessionFactory.execute(stmt)
467
- sessionFactory.commit()
469
+ session_factory.execute(stmt)
470
+ session_factory.commit()
468
471
 
469
472
  @override
470
- def append_event(self, session: Session, event: Event) -> Event:
473
+ async def append_event(self, session: Session, event: Event) -> Event:
471
474
  logger.info(f"Append event: {event} to session {session.id}")
472
475
 
473
476
  if event.partial:
@@ -476,22 +479,25 @@ class DatabaseSessionService(BaseSessionService):
476
479
  # 1. Check if timestamp is stale
477
480
  # 2. Update session attributes based on event config
478
481
  # 3. Store event to table
479
- with self.DatabaseSessionFactory() as sessionFactory:
480
- storage_session = sessionFactory.get(
482
+ with self.database_session_factory() as session_factory:
483
+ storage_session = session_factory.get(
481
484
  StorageSession, (session.app_name, session.user_id, session.id)
482
485
  )
483
486
 
484
487
  if storage_session.update_time.timestamp() > session.last_update_time:
485
488
  raise ValueError(
486
- f"Session last_update_time {session.last_update_time} is later than"
487
- f" the upate_time in storage {storage_session.update_time}"
489
+ "The last_update_time provided in the session object"
490
+ f" {datetime.fromtimestamp(session.last_update_time):'%Y-%m-%d %H:%M:%S'} is"
491
+ " earlier than the update_time in the storage_session"
492
+ f" {storage_session.update_time:'%Y-%m-%d %H:%M:%S'}. Please check"
493
+ " if it is a stale session."
488
494
  )
489
495
 
490
496
  # Fetch states from storage
491
- storage_app_state = sessionFactory.get(
497
+ storage_app_state = session_factory.get(
492
498
  StorageAppState, (session.app_name)
493
499
  )
494
- storage_user_state = sessionFactory.get(
500
+ storage_user_state = session_factory.get(
495
501
  StorageUserState, (session.app_name, session.user_id)
496
502
  )
497
503
 
@@ -540,27 +546,18 @@ class DatabaseSessionService(BaseSessionService):
540
546
  if event.content:
541
547
  storage_event.content = _session_util.encode_content(event.content)
542
548
 
543
- sessionFactory.add(storage_event)
549
+ session_factory.add(storage_event)
544
550
 
545
- sessionFactory.commit()
546
- sessionFactory.refresh(storage_session)
551
+ session_factory.commit()
552
+ session_factory.refresh(storage_session)
547
553
 
548
554
  # Update timestamp with commit time
549
555
  session.last_update_time = storage_session.update_time.timestamp()
550
556
 
551
557
  # Also update the in-memory session
552
- super().append_event(session=session, event=event)
558
+ await super().append_event(session=session, event=event)
553
559
  return event
554
560
 
555
- @override
556
- def list_events(
557
- self,
558
- *,
559
- app_name: str,
560
- user_id: str,
561
- session_id: str,
562
- ) -> ListEventsResponse:
563
- raise NotImplementedError()
564
561
 
565
562
  def convert_event(event: StorageEvent) -> Event:
566
563
  """Converts a storage event to an event."""
@@ -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 session.
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]:
@@ -95,18 +160,20 @@ class InMemorySessionService(BaseSessionService):
95
160
  copied_session.events = copied_session.events[
96
161
  -config.num_recent_events :
97
162
  ]
98
- elif config.after_timestamp:
99
- i = len(session.events) - 1
163
+ if config.after_timestamp:
164
+ i = len(copied_session.events) - 1
100
165
  while i >= 0:
101
166
  if copied_session.events[i].timestamp < config.after_timestamp:
102
167
  break
103
168
  i -= 1
104
169
  if i >= 0:
105
- copied_session.events = copied_session.events[i:]
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(self, app_name: str, user_id: str, copied_session: Session):
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
- @override
149
- def delete_session(
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.get_session(
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()
@@ -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,7 +38,10 @@ 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
  )
44
+ """The pydantic model config."""
41
45
 
42
46
  id: str
43
47
  """The unique identifier of the session."""
@@ -14,7 +14,8 @@
14
14
  import logging
15
15
  import re
16
16
  import time
17
- from typing import Any, Optional
17
+ from typing import Any
18
+ from typing import Optional
18
19
 
19
20
  from dateutil import parser
20
21
  from google import genai
@@ -25,13 +26,11 @@ from ..events.event_actions import EventActions
25
26
  from . import _session_util
26
27
  from .base_session_service import BaseSessionService
27
28
  from .base_session_service import GetSessionConfig
28
- from .base_session_service import ListEventsResponse
29
29
  from .base_session_service import ListSessionsResponse
30
30
  from .session import Session
31
31
 
32
-
33
32
  isoparse = parser.isoparse
34
- logger = logging.getLogger(__name__)
33
+ logger = logging.getLogger('google_adk.' + __name__)
35
34
 
36
35
 
37
36
  class VertexAiSessionService(BaseSessionService):
@@ -49,7 +48,7 @@ class VertexAiSessionService(BaseSessionService):
49
48
  self.api_client = client._api_client
50
49
 
51
50
  @override
52
- def create_session(
51
+ async def create_session(
53
52
  self,
54
53
  *,
55
54
  app_name: str,
@@ -57,13 +56,19 @@ class VertexAiSessionService(BaseSessionService):
57
56
  state: Optional[dict[str, Any]] = None,
58
57
  session_id: Optional[str] = None,
59
58
  ) -> Session:
59
+ if session_id:
60
+ raise ValueError(
61
+ 'User-provided Session id is not supported for'
62
+ ' VertexAISessionService.'
63
+ )
64
+
60
65
  reasoning_engine_id = _parse_reasoning_engine_id(app_name)
61
66
 
62
67
  session_json_dict = {'user_id': user_id}
63
68
  if state:
64
69
  session_json_dict['session_state'] = state
65
70
 
66
- api_response = self.api_client.request(
71
+ api_response = await self.api_client.async_request(
67
72
  http_method='POST',
68
73
  path=f'reasoningEngines/{reasoning_engine_id}/sessions',
69
74
  request_dict=session_json_dict,
@@ -75,7 +80,7 @@ class VertexAiSessionService(BaseSessionService):
75
80
 
76
81
  max_retry_attempt = 5
77
82
  while max_retry_attempt >= 0:
78
- lro_response = self.api_client.request(
83
+ lro_response = await self.api_client.async_request(
79
84
  http_method='GET',
80
85
  path=f'operations/{operation_id}',
81
86
  request_dict={},
@@ -88,7 +93,7 @@ class VertexAiSessionService(BaseSessionService):
88
93
  max_retry_attempt -= 1
89
94
 
90
95
  # Get session resource
91
- get_session_api_response = self.api_client.request(
96
+ get_session_api_response = await self.api_client.async_request(
92
97
  http_method='GET',
93
98
  path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session_id}',
94
99
  request_dict={},
@@ -107,18 +112,18 @@ class VertexAiSessionService(BaseSessionService):
107
112
  return session
108
113
 
109
114
  @override
110
- def get_session(
115
+ async def get_session(
111
116
  self,
112
117
  *,
113
118
  app_name: str,
114
119
  user_id: str,
115
120
  session_id: str,
116
121
  config: Optional[GetSessionConfig] = None,
117
- ) -> Session:
122
+ ) -> Optional[Session]:
118
123
  reasoning_engine_id = _parse_reasoning_engine_id(app_name)
119
124
 
120
125
  # Get session resource
121
- get_session_api_response = self.api_client.request(
126
+ get_session_api_response = await self.api_client.async_request(
122
127
  http_method='GET',
123
128
  path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session_id}',
124
129
  request_dict={},
@@ -136,7 +141,7 @@ class VertexAiSessionService(BaseSessionService):
136
141
  last_update_time=update_timestamp,
137
142
  )
138
143
 
139
- list_events_api_response = self.api_client.request(
144
+ list_events_api_response = await self.api_client.async_request(
140
145
  http_method='GET',
141
146
  path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session_id}/events',
142
147
  request_dict={},
@@ -170,7 +175,7 @@ class VertexAiSessionService(BaseSessionService):
170
175
  return session
171
176
 
172
177
  @override
173
- def list_sessions(
178
+ async def list_sessions(
174
179
  self, *, app_name: str, user_id: str
175
180
  ) -> ListSessionsResponse:
176
181
  reasoning_engine_id = _parse_reasoning_engine_id(app_name)
@@ -197,50 +202,23 @@ class VertexAiSessionService(BaseSessionService):
197
202
  sessions.append(session)
198
203
  return ListSessionsResponse(sessions=sessions)
199
204
 
200
- def delete_session(
205
+ async def delete_session(
201
206
  self, *, app_name: str, user_id: str, session_id: str
202
207
  ) -> None:
203
208
  reasoning_engine_id = _parse_reasoning_engine_id(app_name)
204
- self.api_client.request(
209
+ await self.api_client.async_request(
205
210
  http_method='DELETE',
206
211
  path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session_id}',
207
212
  request_dict={},
208
213
  )
209
214
 
210
215
  @override
211
- def list_events(
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:
216
+ async def append_event(self, session: Session, event: Event) -> Event:
239
217
  # Update the in-memory session.
240
- super().append_event(session=session, event=event)
218
+ await super().append_event(session=session, event=event)
241
219
 
242
220
  reasoning_engine_id = _parse_reasoning_engine_id(session.app_name)
243
- self.api_client.request(
221
+ await self.api_client.async_request(
244
222
  http_method='POST',
245
223
  path=f'reasoningEngines/{reasoning_engine_id}/sessions/{session.id}:appendEvent',
246
224
  request_dict=_convert_event_to_json(event),
google/adk/telemetry.py CHANGED
@@ -111,6 +111,9 @@ def trace_call_llm(
111
111
  span.set_attribute(
112
112
  'gcp.vertex.agent.invocation_id', invocation_context.invocation_id
113
113
  )
114
+ span.set_attribute(
115
+ 'gcp.vertex.agent.session_id', invocation_context.session.id
116
+ )
114
117
  span.set_attribute('gcp.vertex.agent.event_id', event_id)
115
118
  # Consider removing once GenAI SDK provides a way to record this info.
116
119
  span.set_attribute(