agno 1.7.2__py3-none-any.whl → 1.7.4__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.
- agno/agent/agent.py +264 -155
- agno/api/schemas/agent.py +1 -0
- agno/api/schemas/team.py +1 -0
- agno/app/base.py +0 -22
- agno/app/discord/client.py +134 -56
- agno/app/fastapi/app.py +0 -11
- agno/app/playground/app.py +3 -24
- agno/app/playground/async_router.py +97 -28
- agno/app/playground/operator.py +25 -19
- agno/app/playground/schemas.py +1 -0
- agno/app/playground/sync_router.py +93 -26
- agno/document/reader/gcs/__init__.py +0 -0
- agno/document/reader/gcs/pdf_reader.py +44 -0
- agno/embedder/langdb.py +9 -5
- agno/knowledge/document.py +199 -8
- agno/knowledge/gcs/__init__.py +0 -0
- agno/knowledge/gcs/base.py +39 -0
- agno/knowledge/gcs/pdf.py +21 -0
- agno/models/langdb/langdb.py +8 -5
- agno/run/base.py +2 -0
- agno/run/response.py +4 -4
- agno/run/team.py +6 -6
- agno/run/v2/__init__.py +0 -0
- agno/run/v2/workflow.py +563 -0
- agno/storage/base.py +4 -4
- agno/storage/dynamodb.py +74 -10
- agno/storage/firestore.py +6 -1
- agno/storage/gcs_json.py +8 -2
- agno/storage/json.py +20 -5
- agno/storage/mongodb.py +14 -5
- agno/storage/mysql.py +56 -17
- agno/storage/postgres.py +55 -13
- agno/storage/redis.py +25 -5
- agno/storage/session/__init__.py +3 -1
- agno/storage/session/agent.py +3 -0
- agno/storage/session/team.py +3 -0
- agno/storage/session/v2/__init__.py +5 -0
- agno/storage/session/v2/workflow.py +89 -0
- agno/storage/singlestore.py +74 -12
- agno/storage/sqlite.py +64 -18
- agno/storage/yaml.py +26 -6
- agno/team/team.py +198 -243
- agno/tools/scrapegraph.py +8 -10
- agno/utils/log.py +12 -0
- agno/utils/message.py +5 -1
- agno/utils/openai.py +20 -5
- agno/utils/pprint.py +32 -8
- agno/workflow/v2/__init__.py +21 -0
- agno/workflow/v2/condition.py +554 -0
- agno/workflow/v2/loop.py +602 -0
- agno/workflow/v2/parallel.py +659 -0
- agno/workflow/v2/router.py +521 -0
- agno/workflow/v2/step.py +861 -0
- agno/workflow/v2/steps.py +465 -0
- agno/workflow/v2/types.py +347 -0
- agno/workflow/v2/workflow.py +3134 -0
- agno/workflow/workflow.py +15 -147
- {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/METADATA +1 -1
- {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/RECORD +63 -45
- {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/WHEEL +0 -0
- {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/entry_points.txt +0 -0
- {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/licenses/LICENSE +0 -0
- {agno-1.7.2.dist-info → agno-1.7.4.dist-info}/top_level.txt +0 -0
agno/storage/sqlite.py
CHANGED
|
@@ -6,6 +6,7 @@ from agno.storage.base import Storage
|
|
|
6
6
|
from agno.storage.session import Session
|
|
7
7
|
from agno.storage.session.agent import AgentSession
|
|
8
8
|
from agno.storage.session.team import TeamSession
|
|
9
|
+
from agno.storage.session.v2.workflow import WorkflowSession as WorkflowSessionV2
|
|
9
10
|
from agno.storage.session.workflow import WorkflowSession
|
|
10
11
|
from agno.utils.log import log_debug, log_info, log_warning, logger
|
|
11
12
|
|
|
@@ -32,7 +33,7 @@ class SqliteStorage(Storage):
|
|
|
32
33
|
db_engine: Optional[Engine] = None,
|
|
33
34
|
schema_version: int = 1,
|
|
34
35
|
auto_upgrade_schema: bool = False,
|
|
35
|
-
mode: Optional[Literal["agent", "team", "workflow"]] = "agent",
|
|
36
|
+
mode: Optional[Literal["agent", "team", "workflow", "workflow_v2"]] = "agent",
|
|
36
37
|
):
|
|
37
38
|
"""
|
|
38
39
|
This class provides agent storage using a sqlite database.
|
|
@@ -84,12 +85,12 @@ class SqliteStorage(Storage):
|
|
|
84
85
|
self.table: Table = self.get_table()
|
|
85
86
|
|
|
86
87
|
@property
|
|
87
|
-
def mode(self) -> Optional[Literal["agent", "team", "workflow"]]:
|
|
88
|
+
def mode(self) -> Optional[Literal["agent", "team", "workflow", "workflow_v2"]]:
|
|
88
89
|
"""Get the mode of the storage."""
|
|
89
90
|
return super().mode
|
|
90
91
|
|
|
91
92
|
@mode.setter
|
|
92
|
-
def mode(self, value: Optional[Literal["agent", "team", "workflow"]]) -> None:
|
|
93
|
+
def mode(self, value: Optional[Literal["agent", "team", "workflow", "workflow_v2"]]) -> None:
|
|
93
94
|
"""Set the mode and refresh the table if mode changes."""
|
|
94
95
|
super(SqliteStorage, type(self)).mode.fset(self, value) # type: ignore
|
|
95
96
|
if value is not None:
|
|
@@ -131,6 +132,14 @@ class SqliteStorage(Storage):
|
|
|
131
132
|
Column("workflow_id", String, index=True),
|
|
132
133
|
Column("workflow_data", sqlite.JSON),
|
|
133
134
|
]
|
|
135
|
+
elif self.mode == "workflow_v2":
|
|
136
|
+
specific_columns = [
|
|
137
|
+
Column("workflow_id", String, index=True),
|
|
138
|
+
Column("workflow_name", String, index=True),
|
|
139
|
+
Column("workflow_data", sqlite.JSON),
|
|
140
|
+
# Store WorkflowRunResponse objects
|
|
141
|
+
Column("runs", sqlite.JSON),
|
|
142
|
+
]
|
|
134
143
|
|
|
135
144
|
# Create table with all columns
|
|
136
145
|
table = Table(
|
|
@@ -241,6 +250,8 @@ class SqliteStorage(Storage):
|
|
|
241
250
|
return TeamSession.from_dict(result._mapping) if result is not None else None # type: ignore
|
|
242
251
|
elif self.mode == "workflow":
|
|
243
252
|
return WorkflowSession.from_dict(result._mapping) if result is not None else None # type: ignore
|
|
253
|
+
elif self.mode == "workflow_v2":
|
|
254
|
+
return WorkflowSessionV2.from_dict(result._mapping) if result is not None else None # type: ignore
|
|
244
255
|
except Exception as e:
|
|
245
256
|
if "no such table" in str(e):
|
|
246
257
|
log_debug(f"Table does not exist: {self.table.name}")
|
|
@@ -273,6 +284,8 @@ class SqliteStorage(Storage):
|
|
|
273
284
|
stmt = stmt.where(self.table.c.team_id == entity_id)
|
|
274
285
|
elif self.mode == "workflow":
|
|
275
286
|
stmt = stmt.where(self.table.c.workflow_id == entity_id)
|
|
287
|
+
elif self.mode == "workflow_v2":
|
|
288
|
+
stmt = stmt.where(self.table.c.workflow_id == entity_id)
|
|
276
289
|
# order by created_at desc
|
|
277
290
|
stmt = stmt.order_by(self.table.c.created_at.desc())
|
|
278
291
|
# execute query
|
|
@@ -308,11 +321,11 @@ class SqliteStorage(Storage):
|
|
|
308
321
|
stmt = stmt.where(self.table.c.agent_id == entity_id)
|
|
309
322
|
elif self.mode == "team":
|
|
310
323
|
stmt = stmt.where(self.table.c.team_id == entity_id)
|
|
311
|
-
elif self.mode
|
|
324
|
+
elif self.mode in ["workflow", "workflow_v2"]:
|
|
312
325
|
stmt = stmt.where(self.table.c.workflow_id == entity_id)
|
|
313
326
|
# order by created_at desc
|
|
314
327
|
stmt = stmt.order_by(self.table.c.created_at.desc())
|
|
315
|
-
|
|
328
|
+
|
|
316
329
|
rows = sess.execute(stmt).fetchall()
|
|
317
330
|
if rows is not None:
|
|
318
331
|
if self.mode == "agent":
|
|
@@ -321,6 +334,8 @@ class SqliteStorage(Storage):
|
|
|
321
334
|
return [TeamSession.from_dict(row._mapping) for row in rows] # type: ignore
|
|
322
335
|
elif self.mode == "workflow":
|
|
323
336
|
return [WorkflowSession.from_dict(row._mapping) for row in rows] # type: ignore
|
|
337
|
+
elif self.mode == "workflow_v2":
|
|
338
|
+
return [WorkflowSessionV2.from_dict(row._mapping) for row in rows] # type: ignore
|
|
324
339
|
else:
|
|
325
340
|
return []
|
|
326
341
|
except Exception as e:
|
|
@@ -341,7 +356,7 @@ class SqliteStorage(Storage):
|
|
|
341
356
|
Get the last N sessions, ordered by created_at descending.
|
|
342
357
|
|
|
343
358
|
Args:
|
|
344
|
-
|
|
359
|
+
limit: Number of most recent sessions to return
|
|
345
360
|
user_id: Filter by user ID
|
|
346
361
|
entity_id: Filter by entity ID (agent_id, team_id, or workflow_id)
|
|
347
362
|
|
|
@@ -359,7 +374,7 @@ class SqliteStorage(Storage):
|
|
|
359
374
|
stmt = stmt.where(self.table.c.agent_id == entity_id)
|
|
360
375
|
elif self.mode == "team":
|
|
361
376
|
stmt = stmt.where(self.table.c.team_id == entity_id)
|
|
362
|
-
elif self.mode
|
|
377
|
+
elif self.mode in ["workflow", "workflow_v2"]:
|
|
363
378
|
stmt = stmt.where(self.table.c.workflow_id == entity_id)
|
|
364
379
|
|
|
365
380
|
# Order by created_at desc and limit to num_history_sessions
|
|
@@ -370,12 +385,14 @@ class SqliteStorage(Storage):
|
|
|
370
385
|
# Execute query
|
|
371
386
|
rows = sess.execute(stmt).fetchall()
|
|
372
387
|
if rows is not None:
|
|
373
|
-
if self.mode == "agent":
|
|
388
|
+
if self.mode == "agent": # type: ignore
|
|
374
389
|
return [AgentSession.from_dict(row._mapping) for row in rows] # type: ignore
|
|
375
390
|
elif self.mode == "team":
|
|
376
391
|
return [TeamSession.from_dict(row._mapping) for row in rows] # type: ignore
|
|
377
392
|
elif self.mode == "workflow":
|
|
378
393
|
return [WorkflowSession.from_dict(row._mapping) for row in rows] # type: ignore
|
|
394
|
+
elif self.mode == "workflow_v2":
|
|
395
|
+
return [WorkflowSessionV2.from_dict(row._mapping) for row in rows] # type: ignore
|
|
379
396
|
return []
|
|
380
397
|
except Exception as e:
|
|
381
398
|
if "no such table" in str(e):
|
|
@@ -437,26 +454,25 @@ class SqliteStorage(Storage):
|
|
|
437
454
|
agent_id=session.agent_id, # type: ignore
|
|
438
455
|
team_session_id=session.team_session_id, # type: ignore
|
|
439
456
|
user_id=session.user_id,
|
|
440
|
-
memory=session
|
|
457
|
+
memory=getattr(session, "memory", None),
|
|
441
458
|
agent_data=session.agent_data, # type: ignore
|
|
442
459
|
session_data=session.session_data,
|
|
443
460
|
extra_data=session.extra_data,
|
|
444
461
|
)
|
|
445
462
|
|
|
446
463
|
# Define the upsert if the session_id already exists
|
|
447
|
-
# See: https://docs.sqlalchemy.org/en/20/dialects/sqlite.html#insert-on-conflict-upsert
|
|
448
464
|
stmt = stmt.on_conflict_do_update(
|
|
449
465
|
index_elements=["session_id"],
|
|
450
466
|
set_=dict(
|
|
451
467
|
agent_id=session.agent_id, # type: ignore
|
|
452
468
|
team_session_id=session.team_session_id, # type: ignore
|
|
453
469
|
user_id=session.user_id,
|
|
454
|
-
memory=session
|
|
470
|
+
memory=getattr(session, "memory", None),
|
|
455
471
|
agent_data=session.agent_data, # type: ignore
|
|
456
472
|
session_data=session.session_data,
|
|
457
473
|
extra_data=session.extra_data,
|
|
458
474
|
updated_at=int(time.time()),
|
|
459
|
-
),
|
|
475
|
+
),
|
|
460
476
|
)
|
|
461
477
|
elif self.mode == "team":
|
|
462
478
|
# Create an insert statement
|
|
@@ -465,7 +481,7 @@ class SqliteStorage(Storage):
|
|
|
465
481
|
team_id=session.team_id, # type: ignore
|
|
466
482
|
user_id=session.user_id,
|
|
467
483
|
team_session_id=session.team_session_id, # type: ignore
|
|
468
|
-
memory=session
|
|
484
|
+
memory=getattr(session, "memory", None),
|
|
469
485
|
team_data=session.team_data, # type: ignore
|
|
470
486
|
session_data=session.session_data,
|
|
471
487
|
extra_data=session.extra_data,
|
|
@@ -479,12 +495,12 @@ class SqliteStorage(Storage):
|
|
|
479
495
|
team_id=session.team_id, # type: ignore
|
|
480
496
|
user_id=session.user_id,
|
|
481
497
|
team_session_id=session.team_session_id, # type: ignore
|
|
482
|
-
memory=session
|
|
498
|
+
memory=getattr(session, "memory", None),
|
|
483
499
|
team_data=session.team_data, # type: ignore
|
|
484
500
|
session_data=session.session_data,
|
|
485
501
|
extra_data=session.extra_data,
|
|
486
502
|
updated_at=int(time.time()),
|
|
487
|
-
),
|
|
503
|
+
),
|
|
488
504
|
)
|
|
489
505
|
elif self.mode == "workflow":
|
|
490
506
|
# Create an insert statement
|
|
@@ -492,7 +508,7 @@ class SqliteStorage(Storage):
|
|
|
492
508
|
session_id=session.session_id,
|
|
493
509
|
workflow_id=session.workflow_id, # type: ignore
|
|
494
510
|
user_id=session.user_id,
|
|
495
|
-
memory=session
|
|
511
|
+
memory=getattr(session, "memory", None),
|
|
496
512
|
workflow_data=session.workflow_data, # type: ignore
|
|
497
513
|
session_data=session.session_data,
|
|
498
514
|
extra_data=session.extra_data,
|
|
@@ -505,12 +521,42 @@ class SqliteStorage(Storage):
|
|
|
505
521
|
set_=dict(
|
|
506
522
|
workflow_id=session.workflow_id, # type: ignore
|
|
507
523
|
user_id=session.user_id,
|
|
508
|
-
memory=session
|
|
524
|
+
memory=getattr(session, "memory", None),
|
|
525
|
+
workflow_data=session.workflow_data, # type: ignore
|
|
526
|
+
session_data=session.session_data,
|
|
527
|
+
extra_data=session.extra_data,
|
|
528
|
+
updated_at=int(time.time()),
|
|
529
|
+
),
|
|
530
|
+
)
|
|
531
|
+
elif self.mode == "workflow_v2":
|
|
532
|
+
# Convert session to dict to ensure proper serialization
|
|
533
|
+
session_dict = session.to_dict()
|
|
534
|
+
|
|
535
|
+
# Create an insert statement for WorkflowSessionV2
|
|
536
|
+
stmt = sqlite.insert(self.table).values(
|
|
537
|
+
session_id=session.session_id,
|
|
538
|
+
workflow_id=session.workflow_id, # type: ignore
|
|
539
|
+
workflow_name=session.workflow_name, # type: ignore
|
|
540
|
+
user_id=session.user_id,
|
|
541
|
+
runs=session_dict.get("runs"),
|
|
542
|
+
workflow_data=session.workflow_data, # type: ignore
|
|
543
|
+
session_data=session.session_data,
|
|
544
|
+
extra_data=session.extra_data,
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
# Define the upsert if the session_id already exists
|
|
548
|
+
stmt = stmt.on_conflict_do_update(
|
|
549
|
+
index_elements=["session_id"],
|
|
550
|
+
set_=dict(
|
|
551
|
+
workflow_id=session.workflow_id, # type: ignore
|
|
552
|
+
workflow_name=session.workflow_name, # type: ignore
|
|
553
|
+
user_id=session.user_id,
|
|
554
|
+
runs=session_dict.get("runs"),
|
|
509
555
|
workflow_data=session.workflow_data, # type: ignore
|
|
510
556
|
session_data=session.session_data,
|
|
511
557
|
extra_data=session.extra_data,
|
|
512
558
|
updated_at=int(time.time()),
|
|
513
|
-
),
|
|
559
|
+
),
|
|
514
560
|
)
|
|
515
561
|
|
|
516
562
|
sess.execute(stmt)
|
agno/storage/yaml.py
CHANGED
|
@@ -9,12 +9,15 @@ from agno.storage.base import Storage
|
|
|
9
9
|
from agno.storage.session import Session
|
|
10
10
|
from agno.storage.session.agent import AgentSession
|
|
11
11
|
from agno.storage.session.team import TeamSession
|
|
12
|
+
from agno.storage.session.v2.workflow import WorkflowSession as WorkflowSessionV2
|
|
12
13
|
from agno.storage.session.workflow import WorkflowSession
|
|
13
14
|
from agno.utils.log import logger
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class YamlStorage(Storage):
|
|
17
|
-
def __init__(
|
|
18
|
+
def __init__(
|
|
19
|
+
self, dir_path: Union[str, Path], mode: Optional[Literal["agent", "team", "workflow", "workflow_v2"]] = "agent"
|
|
20
|
+
):
|
|
18
21
|
super().__init__(mode)
|
|
19
22
|
self.dir_path = Path(dir_path)
|
|
20
23
|
self.dir_path.mkdir(parents=True, exist_ok=True)
|
|
@@ -43,6 +46,8 @@ class YamlStorage(Storage):
|
|
|
43
46
|
return TeamSession.from_dict(data)
|
|
44
47
|
elif self.mode == "workflow":
|
|
45
48
|
return WorkflowSession.from_dict(data)
|
|
49
|
+
elif self.mode == "workflow_v2":
|
|
50
|
+
return WorkflowSessionV2.from_dict(data)
|
|
46
51
|
except FileNotFoundError:
|
|
47
52
|
return None
|
|
48
53
|
|
|
@@ -62,6 +67,8 @@ class YamlStorage(Storage):
|
|
|
62
67
|
self.mode == "workflow" and data["workflow_id"] == entity_id and data["user_id"] == user_id
|
|
63
68
|
):
|
|
64
69
|
session_ids.append(data["session_id"])
|
|
70
|
+
elif self.mode == "workflow_v2" and data["workflow_id"] == entity_id:
|
|
71
|
+
session_ids.append(data["session_id"])
|
|
65
72
|
elif user_id and data["user_id"] == user_id:
|
|
66
73
|
session_ids.append(data["session_id"])
|
|
67
74
|
elif entity_id:
|
|
@@ -71,6 +78,8 @@ class YamlStorage(Storage):
|
|
|
71
78
|
session_ids.append(data["session_id"])
|
|
72
79
|
elif self.mode == "workflow" and data["workflow_id"] == entity_id:
|
|
73
80
|
session_ids.append(data["session_id"])
|
|
81
|
+
elif self.mode == "workflow_v2" and data["workflow_id"] == entity_id:
|
|
82
|
+
session_ids.append(data["session_id"])
|
|
74
83
|
else:
|
|
75
84
|
# No filters applied, add all session_ids
|
|
76
85
|
session_ids.append(data["session_id"])
|
|
@@ -93,6 +102,8 @@ class YamlStorage(Storage):
|
|
|
93
102
|
self.mode == "workflow" and data["workflow_id"] == entity_id and data["user_id"] == user_id
|
|
94
103
|
):
|
|
95
104
|
_session = WorkflowSession.from_dict(data)
|
|
105
|
+
elif self.mode == "workflow_v2" and data["workflow_id"] == entity_id:
|
|
106
|
+
_session = WorkflowSessionV2.from_dict(data)
|
|
96
107
|
elif user_id and data["user_id"] == user_id:
|
|
97
108
|
if self.mode == "agent":
|
|
98
109
|
_session = AgentSession.from_dict(data)
|
|
@@ -100,6 +111,8 @@ class YamlStorage(Storage):
|
|
|
100
111
|
_session = TeamSession.from_dict(data)
|
|
101
112
|
elif self.mode == "workflow":
|
|
102
113
|
_session = WorkflowSession.from_dict(data)
|
|
114
|
+
elif self.mode == "workflow_v2":
|
|
115
|
+
_session = WorkflowSessionV2.from_dict(data)
|
|
103
116
|
elif entity_id:
|
|
104
117
|
if self.mode == "agent" and data["agent_id"] == entity_id:
|
|
105
118
|
_session = AgentSession.from_dict(data)
|
|
@@ -107,7 +120,8 @@ class YamlStorage(Storage):
|
|
|
107
120
|
_session = TeamSession.from_dict(data)
|
|
108
121
|
elif self.mode == "workflow" and data["workflow_id"] == entity_id:
|
|
109
122
|
_session = WorkflowSession.from_dict(data)
|
|
110
|
-
|
|
123
|
+
elif self.mode == "workflow_v2" and data["workflow_id"] == entity_id:
|
|
124
|
+
_session = WorkflowSessionV2.from_dict(data)
|
|
111
125
|
if _session:
|
|
112
126
|
sessions.append(_session)
|
|
113
127
|
else:
|
|
@@ -118,6 +132,8 @@ class YamlStorage(Storage):
|
|
|
118
132
|
_session = TeamSession.from_dict(data)
|
|
119
133
|
elif self.mode == "workflow":
|
|
120
134
|
_session = WorkflowSession.from_dict(data)
|
|
135
|
+
elif self.mode == "workflow_v2":
|
|
136
|
+
_session = WorkflowSessionV2.from_dict(data)
|
|
121
137
|
if _session:
|
|
122
138
|
sessions.append(_session)
|
|
123
139
|
return sessions
|
|
@@ -158,7 +174,8 @@ class YamlStorage(Storage):
|
|
|
158
174
|
continue
|
|
159
175
|
elif self.mode == "workflow" and data["workflow_id"] != entity_id:
|
|
160
176
|
continue
|
|
161
|
-
|
|
177
|
+
elif self.mode == "workflow_v2" and data["workflow_id"] != entity_id:
|
|
178
|
+
continue
|
|
162
179
|
# Store with created_at for sorting
|
|
163
180
|
created_at = data.get("created_at", 0)
|
|
164
181
|
session_data.append((created_at, data))
|
|
@@ -181,7 +198,8 @@ class YamlStorage(Storage):
|
|
|
181
198
|
session = TeamSession.from_dict(data)
|
|
182
199
|
elif self.mode == "workflow":
|
|
183
200
|
session = WorkflowSession.from_dict(data)
|
|
184
|
-
|
|
201
|
+
elif self.mode == "workflow_v2":
|
|
202
|
+
session = WorkflowSessionV2.from_dict(data)
|
|
185
203
|
if session is not None:
|
|
186
204
|
sessions.append(session)
|
|
187
205
|
|
|
@@ -190,11 +208,13 @@ class YamlStorage(Storage):
|
|
|
190
208
|
def upsert(self, session: Session) -> Optional[Session]:
|
|
191
209
|
"""Insert or update an Session in storage."""
|
|
192
210
|
try:
|
|
193
|
-
|
|
211
|
+
if self.mode == "workflow_v2":
|
|
212
|
+
data = session.to_dict()
|
|
213
|
+
else:
|
|
214
|
+
data = asdict(session)
|
|
194
215
|
data["updated_at"] = int(time.time())
|
|
195
216
|
if "created_at" not in data:
|
|
196
217
|
data["created_at"] = data["updated_at"]
|
|
197
|
-
|
|
198
218
|
with open(self.dir_path / f"{session.session_id}.yaml", "w", encoding="utf-8") as f:
|
|
199
219
|
f.write(self.serialize(data))
|
|
200
220
|
return session
|