google-adk-extras 0.1.1__py3-none-any.whl → 0.2.5__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_extras/__init__.py +31 -1
- google_adk_extras/adk_builder.py +1030 -0
- google_adk_extras/artifacts/__init__.py +25 -12
- google_adk_extras/artifacts/base_custom_artifact_service.py +148 -11
- google_adk_extras/artifacts/local_folder_artifact_service.py +133 -13
- google_adk_extras/artifacts/s3_artifact_service.py +135 -19
- google_adk_extras/artifacts/sql_artifact_service.py +109 -10
- google_adk_extras/credentials/__init__.py +34 -0
- google_adk_extras/credentials/base_custom_credential_service.py +113 -0
- google_adk_extras/credentials/github_oauth2_credential_service.py +213 -0
- google_adk_extras/credentials/google_oauth2_credential_service.py +216 -0
- google_adk_extras/credentials/http_basic_auth_credential_service.py +388 -0
- google_adk_extras/credentials/jwt_credential_service.py +345 -0
- google_adk_extras/credentials/microsoft_oauth2_credential_service.py +250 -0
- google_adk_extras/credentials/x_oauth2_credential_service.py +240 -0
- google_adk_extras/custom_agent_loader.py +170 -0
- google_adk_extras/enhanced_adk_web_server.py +137 -0
- google_adk_extras/enhanced_fastapi.py +507 -0
- google_adk_extras/enhanced_runner.py +38 -0
- google_adk_extras/memory/__init__.py +30 -13
- google_adk_extras/memory/base_custom_memory_service.py +37 -5
- google_adk_extras/memory/sql_memory_service.py +105 -19
- google_adk_extras/memory/yaml_file_memory_service.py +115 -22
- google_adk_extras/sessions/__init__.py +29 -13
- google_adk_extras/sessions/base_custom_session_service.py +133 -11
- google_adk_extras/sessions/sql_session_service.py +127 -16
- google_adk_extras/sessions/yaml_file_session_service.py +122 -14
- google_adk_extras-0.2.5.dist-info/METADATA +302 -0
- google_adk_extras-0.2.5.dist-info/RECORD +37 -0
- google_adk_extras/py.typed +0 -0
- google_adk_extras-0.1.1.dist-info/METADATA +0 -175
- google_adk_extras-0.1.1.dist-info/RECORD +0 -25
- {google_adk_extras-0.1.1.dist-info → google_adk_extras-0.2.5.dist-info}/WHEEL +0 -0
- {google_adk_extras-0.1.1.dist-info → google_adk_extras-0.2.5.dist-info}/licenses/LICENSE +0 -0
- {google_adk_extras-0.1.1.dist-info → google_adk_extras-0.2.5.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
|
-
|
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
|