google-adk-extras 0.1.1__py3-none-any.whl → 0.2.3__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 (35) hide show
  1. google_adk_extras/__init__.py +31 -1
  2. google_adk_extras/adk_builder.py +1030 -0
  3. google_adk_extras/artifacts/__init__.py +25 -12
  4. google_adk_extras/artifacts/base_custom_artifact_service.py +148 -11
  5. google_adk_extras/artifacts/local_folder_artifact_service.py +133 -13
  6. google_adk_extras/artifacts/s3_artifact_service.py +135 -19
  7. google_adk_extras/artifacts/sql_artifact_service.py +109 -10
  8. google_adk_extras/credentials/__init__.py +34 -0
  9. google_adk_extras/credentials/base_custom_credential_service.py +113 -0
  10. google_adk_extras/credentials/github_oauth2_credential_service.py +213 -0
  11. google_adk_extras/credentials/google_oauth2_credential_service.py +216 -0
  12. google_adk_extras/credentials/http_basic_auth_credential_service.py +388 -0
  13. google_adk_extras/credentials/jwt_credential_service.py +345 -0
  14. google_adk_extras/credentials/microsoft_oauth2_credential_service.py +250 -0
  15. google_adk_extras/credentials/x_oauth2_credential_service.py +240 -0
  16. google_adk_extras/custom_agent_loader.py +156 -0
  17. google_adk_extras/enhanced_adk_web_server.py +137 -0
  18. google_adk_extras/enhanced_fastapi.py +470 -0
  19. google_adk_extras/enhanced_runner.py +38 -0
  20. google_adk_extras/memory/__init__.py +30 -13
  21. google_adk_extras/memory/base_custom_memory_service.py +37 -5
  22. google_adk_extras/memory/sql_memory_service.py +105 -19
  23. google_adk_extras/memory/yaml_file_memory_service.py +115 -22
  24. google_adk_extras/sessions/__init__.py +29 -13
  25. google_adk_extras/sessions/base_custom_session_service.py +133 -11
  26. google_adk_extras/sessions/sql_session_service.py +127 -16
  27. google_adk_extras/sessions/yaml_file_session_service.py +122 -14
  28. google_adk_extras-0.2.3.dist-info/METADATA +302 -0
  29. google_adk_extras-0.2.3.dist-info/RECORD +37 -0
  30. google_adk_extras/py.typed +0 -0
  31. google_adk_extras-0.1.1.dist-info/METADATA +0 -175
  32. google_adk_extras-0.1.1.dist-info/RECORD +0 -25
  33. {google_adk_extras-0.1.1.dist-info → google_adk_extras-0.2.3.dist-info}/WHEEL +0 -0
  34. {google_adk_extras-0.1.1.dist-info → google_adk_extras-0.2.3.dist-info}/licenses/LICENSE +0 -0
  35. {google_adk_extras-0.1.1.dist-info → google_adk_extras-0.2.3.dist-info}/top_level.txt +0 -0
@@ -43,7 +43,11 @@ class SQLSessionModel(Base):
43
43
 
44
44
 
45
45
  class SQLSessionService(BaseCustomSessionService):
46
- """SQL-based session service implementation."""
46
+ """SQL-based session service implementation.
47
+
48
+ This service stores sessions in a SQL database using SQLAlchemy.
49
+ It supports various SQL databases including SQLite, PostgreSQL, and MySQL.
50
+ """
47
51
 
48
52
  def __init__(self, database_url: str):
49
53
  """Initialize the SQL session service.
@@ -57,7 +61,11 @@ class SQLSessionService(BaseCustomSessionService):
57
61
  self.session_local: Optional[object] = None
58
62
 
59
63
  async def _initialize_impl(self) -> None:
60
- """Initialize the database connection and create tables."""
64
+ """Initialize the database connection and create tables.
65
+
66
+ Raises:
67
+ RuntimeError: If database initialization fails.
68
+ """
61
69
  try:
62
70
  self.engine = create_engine(self.database_url)
63
71
  Base.metadata.create_all(self.engine)
@@ -77,27 +85,64 @@ class SQLSessionService(BaseCustomSessionService):
77
85
  self.session_local = None
78
86
 
79
87
  def _get_db_session(self):
80
- """Get a database session."""
88
+ """Get a database session.
89
+
90
+ Returns:
91
+ A database session object.
92
+
93
+ Raises:
94
+ RuntimeError: If the service is not initialized.
95
+ """
81
96
  if not self.session_local:
82
97
  raise RuntimeError("Service not initialized")
83
98
  return self.session_local()
84
99
 
85
100
  def _serialize_state(self, state: dict[str, Any]) -> str:
86
- """Serialize session state to JSON string."""
101
+ """Serialize session state to JSON string.
102
+
103
+ Args:
104
+ state: The state dictionary to serialize.
105
+
106
+ Returns:
107
+ JSON string representation of the state.
108
+
109
+ Raises:
110
+ ValueError: If serialization fails.
111
+ """
87
112
  try:
88
113
  return json.dumps(state)
89
114
  except (TypeError, ValueError) as e:
90
115
  raise ValueError(f"Failed to serialize state: {e}")
91
116
 
92
117
  def _deserialize_state(self, state_str: str) -> dict[str, Any]:
93
- """Deserialize session state from JSON string."""
118
+ """Deserialize session state from JSON string.
119
+
120
+ Args:
121
+ state_str: JSON string representation of the state.
122
+
123
+ Returns:
124
+ The deserialized state dictionary.
125
+
126
+ Raises:
127
+ ValueError: If deserialization fails.
128
+ """
94
129
  try:
95
130
  return json.loads(state_str) if state_str else {}
96
131
  except (TypeError, ValueError) as e:
97
132
  raise ValueError(f"Failed to deserialize state: {e}")
98
133
 
99
134
  def _serialize_events(self, events: list[Event]) -> str:
100
- """Serialize events to JSON string."""
135
+ """Serialize events to JSON string.
136
+
137
+ Args:
138
+ events: List of events to serialize.
139
+
140
+ Returns:
141
+ JSON string representation of the events.
142
+
143
+ Raises:
144
+ ValueError: If serialization fails.
145
+ """
101
146
  try:
102
147
  # Convert events to dictionaries
103
148
  event_dicts = [event.model_dump() for event in events]
@@ -106,7 +151,17 @@ class SQLSessionService(BaseCustomSessionService):
106
151
  raise ValueError(f"Failed to serialize events: {e}")
107
152
 
108
153
  def _deserialize_events(self, events_str: str) -> list[Event]:
109
- """Deserialize events from JSON string."""
154
+ """Deserialize events from JSON string.
155
+
156
+ Args:
157
+ events_str: JSON string representation of the events.
158
+
159
+ Returns:
160
+ List of deserialized events.
161
+
162
+ Raises:
163
+ ValueError: If deserialization fails.
164
+ """
110
165
  try:
111
166
  event_dicts = json.loads(events_str) if events_str else []
112
167
  return [Event(**event_dict) for event_dict in event_dicts]
@@ -121,7 +176,20 @@ class SQLSessionService(BaseCustomSessionService):
121
176
  state: Optional[dict[str, Any]] = None,
122
177
  session_id: Optional[str] = None,
123
178
  ) -> "Session":
124
- """Implementation of session creation."""
179
+ """Implementation of session creation.
180
+
181
+ Args:
182
+ app_name: The name of the application.
183
+ user_id: The ID of the user.
184
+ state: Optional initial state for the session.
185
+ session_id: Optional specific ID for the session.
186
+
187
+ Returns:
188
+ The created Session object.
189
+
190
+ Raises:
191
+ RuntimeError: If session creation fails.
192
+ """
125
193
  # Import Session inside the function to avoid circular import
126
194
  from google.adk.sessions.session import Session
127
195
  import time
@@ -170,9 +238,20 @@ class SQLSessionService(BaseCustomSessionService):
170
238
  session_id: str,
171
239
  config: Optional["GetSessionConfig"] = None,
172
240
  ) -> Optional["Session"]:
173
- """Implementation of session retrieval."""
174
- from google.adk.sessions.base_session_service import GetSessionConfig
241
+ """Implementation of session retrieval.
175
242
 
243
+ Args:
244
+ app_name: The name of the application.
245
+ user_id: The ID of the user.
246
+ session_id: The ID of the session to retrieve.
247
+ config: Optional configuration for session retrieval.
248
+
249
+ Returns:
250
+ The Session object if found, None otherwise.
251
+
252
+ Raises:
253
+ RuntimeError: If session retrieval fails.
254
+ """
176
255
  db_session = self._get_db_session()
177
256
  try:
178
257
  db_session_model = db_session.query(SQLSessionModel).filter(
@@ -219,9 +298,18 @@ class SQLSessionService(BaseCustomSessionService):
219
298
  app_name: str,
220
299
  user_id: str
221
300
  ) -> "ListSessionsResponse":
222
- """Implementation of session listing."""
223
- from google.adk.sessions.base_session_service import ListSessionsResponse
301
+ """Implementation of session listing.
224
302
 
303
+ Args:
304
+ app_name: The name of the application.
305
+ user_id: The ID of the user.
306
+
307
+ Returns:
308
+ A ListSessionsResponse containing the sessions.
309
+
310
+ Raises:
311
+ RuntimeError: If session listing fails.
312
+ """
225
313
  db_session = self._get_db_session()
226
314
  try:
227
315
  # Retrieve all sessions for user (without events)
@@ -245,7 +333,12 @@ class SQLSessionService(BaseCustomSessionService):
245
333
  )
246
334
  sessions.append(session)
247
335
 
248
- return ListSessionsResponse(sessions=sessions)
336
+ try:
337
+ from google.adk.sessions.base_session_service import ListSessionsResponse
338
+ return ListSessionsResponse(sessions=sessions)
339
+ except Exception:
340
+ from types import SimpleNamespace
341
+ return SimpleNamespace(sessions=sessions)
249
342
  except SQLAlchemyError as e:
250
343
  raise RuntimeError(f"Failed to list sessions: {e}")
251
344
  finally:
@@ -258,7 +351,16 @@ class SQLSessionService(BaseCustomSessionService):
258
351
  user_id: str,
259
352
  session_id: str
260
353
  ) -> None:
261
- """Implementation of session deletion."""
354
+ """Implementation of session deletion.
355
+
356
+ Args:
357
+ app_name: The name of the application.
358
+ user_id: The ID of the user.
359
+ session_id: The ID of the session to delete.
360
+
361
+ Raises:
362
+ RuntimeError: If session deletion fails.
363
+ """
262
364
  db_session = self._get_db_session()
263
365
  try:
264
366
  # Delete from database
@@ -276,7 +378,16 @@ class SQLSessionService(BaseCustomSessionService):
276
378
  db_session.close()
277
379
 
278
380
  async def _append_event_impl(self, session: "Session", event: Event) -> None:
279
- """Implementation of event appending."""
381
+ """Implementation of event appending.
382
+
383
+ Args:
384
+ session: The session to append the event to.
385
+ event: The event to append.
386
+
387
+ Raises:
388
+ RuntimeError: If appending the event fails.
389
+ ValueError: If the session is not found.
390
+ """
280
391
  db_session = self._get_db_session()
281
392
  try:
282
393
  # Update session in database
@@ -305,4 +416,4 @@ class SQLSessionService(BaseCustomSessionService):
305
416
  db_session.rollback()
306
417
  raise RuntimeError(f"Failed to append event: {e}")
307
418
  finally:
308
- db_session.close()
419
+ db_session.close()
@@ -23,13 +23,17 @@ from .base_custom_session_service import BaseCustomSessionService
23
23
 
24
24
 
25
25
  class YamlFileSessionService(BaseCustomSessionService):
26
- """YAML file-based session service implementation."""
26
+ """YAML file-based session service implementation.
27
+
28
+ This service stores sessions in YAML files in a hierarchical directory structure.
29
+ Each session is stored in a separate YAML file organized by app name and user ID.
30
+ """
27
31
 
28
32
  def __init__(self, base_directory: str = "./sessions"):
29
33
  """Initialize the YAML file session service.
30
34
 
31
35
  Args:
32
- base_directory: Base directory for storing session files
36
+ base_directory: Base directory for storing session files. Defaults to "./sessions".
33
37
  """
34
38
  super().__init__()
35
39
  self.base_directory = Path(base_directory)
@@ -37,7 +41,10 @@ class YamlFileSessionService(BaseCustomSessionService):
37
41
  self.base_directory.mkdir(parents=True, exist_ok=True)
38
42
 
39
43
  async def _initialize_impl(self) -> None:
40
- """Initialize the file system session service."""
44
+ """Initialize the file system session service.
45
+
46
+ Ensures the base directory exists.
47
+ """
41
48
  # Ensure base directory exists
42
49
  self.base_directory.mkdir(parents=True, exist_ok=True)
43
50
 
@@ -46,7 +53,16 @@ class YamlFileSessionService(BaseCustomSessionService):
46
53
  pass
47
54
 
48
55
  def _get_session_file_path(self, app_name: str, user_id: str, session_id: str) -> Path:
49
- """Generate file path for a session."""
56
+ """Generate file path for a session.
57
+
58
+ Args:
59
+ app_name: The name of the application.
60
+ user_id: The ID of the user.
61
+ session_id: The ID of the session.
62
+
63
+ Returns:
64
+ Path to the session file.
65
+ """
50
66
  # Create app directory
51
67
  app_dir = self.base_directory / app_name
52
68
  app_dir.mkdir(exist_ok=True)
@@ -59,19 +75,48 @@ class YamlFileSessionService(BaseCustomSessionService):
59
75
  return user_dir / f"{session_id}.yaml"
60
76
 
61
77
  def _get_user_directory(self, app_name: str, user_id: str) -> Path:
62
- """Get the directory path for a user's sessions."""
78
+ """Get the directory path for a user's sessions.
79
+
80
+ Args:
81
+ app_name: The name of the application.
82
+ user_id: The ID of the user.
83
+
84
+ Returns:
85
+ Path to the user's session directory.
86
+ """
63
87
  return self.base_directory / app_name / user_id
64
88
 
65
89
  def _serialize_events(self, events: list[Event]) -> list[dict]:
66
- """Serialize events to dictionaries."""
90
+ """Serialize events to dictionaries.
91
+
92
+ Args:
93
+ events: List of Event objects to serialize.
94
+
95
+ Returns:
96
+ List of dictionaries representing the events.
97
+ """
67
98
  return [event.model_dump() for event in events]
68
99
 
69
100
  def _deserialize_events(self, event_dicts: list[dict]) -> list[Event]:
70
- """Deserialize events from dictionaries."""
101
+ """Deserialize events from dictionaries.
102
+
103
+ Args:
104
+ event_dicts: List of dictionaries representing events.
105
+
106
+ Returns:
107
+ List of Event objects.
108
+ """
71
109
  return [Event(**event_dict) for event_dict in event_dicts]
72
110
 
73
111
  def _session_to_dict(self, session: Session) -> dict:
74
- """Convert session to dictionary for YAML serialization."""
112
+ """Convert session to dictionary for YAML serialization.
113
+
114
+ Args:
115
+ session: The Session object to convert.
116
+
117
+ Returns:
118
+ Dictionary representation of the session.
119
+ """
75
120
  return {
76
121
  "id": session.id,
77
122
  "app_name": session.app_name,
@@ -82,7 +127,14 @@ class YamlFileSessionService(BaseCustomSessionService):
82
127
  }
83
128
 
84
129
  def _dict_to_session(self, data: dict) -> Session:
85
- """Convert dictionary to session object."""
130
+ """Convert dictionary to session object.
131
+
132
+ Args:
133
+ data: Dictionary representation of the session.
134
+
135
+ Returns:
136
+ Session object.
137
+ """
86
138
  return Session(
87
139
  id=data["id"],
88
140
  app_name=data["app_name"],
@@ -100,7 +152,21 @@ class YamlFileSessionService(BaseCustomSessionService):
100
152
  state: Optional[dict[str, Any]] = None,
101
153
  session_id: Optional[str] = None,
102
154
  ) -> Session:
103
- """Implementation of session creation."""
155
+ """Implementation of session creation.
156
+
157
+ Args:
158
+ app_name: The name of the application.
159
+ user_id: The ID of the user.
160
+ state: Optional initial state for the session.
161
+ session_id: Optional specific ID for the session. If not provided,
162
+ a UUID will be generated.
163
+
164
+ Returns:
165
+ The created Session object.
166
+
167
+ Raises:
168
+ RuntimeError: If session creation fails.
169
+ """
104
170
  # Generate session ID if not provided
105
171
  session_id = session_id or str(uuid.uuid4())
106
172
 
@@ -134,7 +200,20 @@ class YamlFileSessionService(BaseCustomSessionService):
134
200
  session_id: str,
135
201
  config: Optional[GetSessionConfig] = None,
136
202
  ) -> Optional[Session]:
137
- """Implementation of session retrieval."""
203
+ """Implementation of session retrieval.
204
+
205
+ Args:
206
+ app_name: The name of the application.
207
+ user_id: The ID of the user.
208
+ session_id: The ID of the session to retrieve.
209
+ config: Optional configuration for session retrieval.
210
+
211
+ Returns:
212
+ The Session object if found, None otherwise.
213
+
214
+ Raises:
215
+ RuntimeError: If session retrieval fails.
216
+ """
138
217
  file_path = self._get_session_file_path(app_name, user_id, session_id)
139
218
 
140
219
  # Check if file exists
@@ -170,7 +249,18 @@ class YamlFileSessionService(BaseCustomSessionService):
170
249
  app_name: str,
171
250
  user_id: str
172
251
  ) -> ListSessionsResponse:
173
- """Implementation of session listing."""
252
+ """Implementation of session listing.
253
+
254
+ Args:
255
+ app_name: The name of the application.
256
+ user_id: The ID of the user.
257
+
258
+ Returns:
259
+ A ListSessionsResponse containing the sessions.
260
+
261
+ Raises:
262
+ RuntimeError: If session listing fails.
263
+ """
174
264
  user_dir = self._get_user_directory(app_name, user_id)
175
265
 
176
266
  # Check if user directory exists
@@ -207,7 +297,16 @@ class YamlFileSessionService(BaseCustomSessionService):
207
297
  user_id: str,
208
298
  session_id: str
209
299
  ) -> None:
210
- """Implementation of session deletion."""
300
+ """Implementation of session deletion.
301
+
302
+ Args:
303
+ app_name: The name of the application.
304
+ user_id: The ID of the user.
305
+ session_id: The ID of the session to delete.
306
+
307
+ Raises:
308
+ RuntimeError: If session deletion fails.
309
+ """
211
310
  file_path = self._get_session_file_path(app_name, user_id, session_id)
212
311
 
213
312
  # Delete file if it exists
@@ -218,7 +317,16 @@ class YamlFileSessionService(BaseCustomSessionService):
218
317
  raise RuntimeError(f"Failed to delete session file: {e}")
219
318
 
220
319
  async def _append_event_impl(self, session: Session, event: Event) -> None:
221
- """Implementation of event appending."""
320
+ """Implementation of event appending.
321
+
322
+ Args:
323
+ session: The session to append the event to.
324
+ event: The event to append.
325
+
326
+ Raises:
327
+ RuntimeError: If appending the event fails.
328
+ ValueError: If the session file is not found.
329
+ """
222
330
  file_path = self._get_session_file_path(session.app_name, session.user_id, session.id)
223
331
 
224
332
  # Check if file exists