agno 2.0.11__py3-none-any.whl → 2.1.1__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 +607 -176
- agno/db/in_memory/in_memory_db.py +42 -29
- agno/db/mongo/mongo.py +65 -66
- agno/db/postgres/postgres.py +6 -4
- agno/db/utils.py +50 -22
- agno/exceptions.py +62 -1
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +51 -0
- agno/knowledge/embedder/aws_bedrock.py +9 -4
- agno/knowledge/embedder/azure_openai.py +54 -0
- agno/knowledge/embedder/base.py +2 -0
- agno/knowledge/embedder/cohere.py +184 -5
- agno/knowledge/embedder/google.py +79 -1
- agno/knowledge/embedder/huggingface.py +9 -4
- agno/knowledge/embedder/jina.py +63 -0
- agno/knowledge/embedder/mistral.py +78 -11
- agno/knowledge/embedder/ollama.py +5 -0
- agno/knowledge/embedder/openai.py +18 -54
- agno/knowledge/embedder/voyageai.py +69 -16
- agno/knowledge/knowledge.py +11 -4
- agno/knowledge/reader/pdf_reader.py +4 -3
- agno/knowledge/reader/website_reader.py +3 -2
- agno/models/base.py +125 -32
- agno/models/cerebras/cerebras.py +1 -0
- agno/models/cerebras/cerebras_openai.py +1 -0
- agno/models/dashscope/dashscope.py +1 -0
- agno/models/google/gemini.py +27 -5
- agno/models/openai/chat.py +13 -4
- agno/models/openai/responses.py +1 -1
- agno/models/perplexity/perplexity.py +2 -3
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +49 -0
- agno/models/vllm/vllm.py +1 -0
- agno/models/xai/xai.py +1 -0
- agno/os/app.py +98 -126
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/agui/agui.py +21 -5
- agno/os/interfaces/base.py +4 -2
- agno/os/interfaces/slack/slack.py +13 -8
- agno/os/interfaces/whatsapp/router.py +2 -0
- agno/os/interfaces/whatsapp/whatsapp.py +12 -5
- agno/os/mcp.py +2 -2
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +182 -46
- agno/os/routers/home.py +2 -2
- agno/os/routers/memory/memory.py +23 -1
- agno/os/routers/memory/schemas.py +1 -1
- agno/os/routers/session/session.py +20 -3
- agno/os/utils.py +74 -8
- agno/run/agent.py +120 -77
- agno/run/base.py +2 -13
- agno/run/team.py +115 -72
- agno/run/workflow.py +5 -15
- agno/session/summary.py +9 -10
- agno/session/team.py +2 -1
- agno/team/team.py +721 -169
- agno/tools/firecrawl.py +4 -4
- agno/tools/function.py +42 -2
- agno/tools/knowledge.py +3 -3
- agno/tools/searxng.py +2 -2
- agno/tools/serper.py +2 -2
- agno/tools/spider.py +2 -2
- agno/tools/workflow.py +4 -5
- agno/utils/events.py +66 -1
- agno/utils/hooks.py +57 -0
- agno/utils/media.py +11 -9
- agno/utils/print_response/agent.py +43 -5
- agno/utils/print_response/team.py +48 -12
- agno/utils/serialize.py +32 -0
- agno/vectordb/cassandra/cassandra.py +44 -4
- agno/vectordb/chroma/chromadb.py +79 -8
- agno/vectordb/clickhouse/clickhousedb.py +43 -6
- agno/vectordb/couchbase/couchbase.py +76 -5
- agno/vectordb/lancedb/lance_db.py +38 -3
- agno/vectordb/milvus/milvus.py +76 -4
- agno/vectordb/mongodb/mongodb.py +76 -4
- agno/vectordb/pgvector/pgvector.py +50 -6
- agno/vectordb/pineconedb/pineconedb.py +39 -2
- agno/vectordb/qdrant/qdrant.py +76 -26
- agno/vectordb/singlestore/singlestore.py +77 -4
- agno/vectordb/upstashdb/upstashdb.py +42 -2
- agno/vectordb/weaviate/weaviate.py +39 -3
- agno/workflow/types.py +5 -6
- agno/workflow/workflow.py +58 -2
- {agno-2.0.11.dist-info → agno-2.1.1.dist-info}/METADATA +4 -3
- {agno-2.0.11.dist-info → agno-2.1.1.dist-info}/RECORD +93 -82
- {agno-2.0.11.dist-info → agno-2.1.1.dist-info}/WHEEL +0 -0
- {agno-2.0.11.dist-info → agno-2.1.1.dist-info}/licenses/LICENSE +0 -0
- {agno-2.0.11.dist-info → agno-2.1.1.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import time
|
|
2
|
+
from copy import deepcopy
|
|
2
3
|
from datetime import date, datetime, timedelta, timezone
|
|
3
4
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
4
5
|
from uuid import uuid4
|
|
@@ -107,15 +108,17 @@ class InMemoryDb(BaseDb):
|
|
|
107
108
|
if session_data.get("session_type") != session_type_value:
|
|
108
109
|
continue
|
|
109
110
|
|
|
111
|
+
session_data_copy = deepcopy(session_data)
|
|
112
|
+
|
|
110
113
|
if not deserialize:
|
|
111
|
-
return
|
|
114
|
+
return session_data_copy
|
|
112
115
|
|
|
113
116
|
if session_type == SessionType.AGENT:
|
|
114
|
-
return AgentSession.from_dict(
|
|
117
|
+
return AgentSession.from_dict(session_data_copy)
|
|
115
118
|
elif session_type == SessionType.TEAM:
|
|
116
|
-
return TeamSession.from_dict(
|
|
119
|
+
return TeamSession.from_dict(session_data_copy)
|
|
117
120
|
else:
|
|
118
|
-
return WorkflowSession.from_dict(
|
|
121
|
+
return WorkflowSession.from_dict(session_data_copy)
|
|
119
122
|
|
|
120
123
|
return None
|
|
121
124
|
|
|
@@ -188,7 +191,7 @@ class InMemoryDb(BaseDb):
|
|
|
188
191
|
if session_data.get("session_type") != session_type_value:
|
|
189
192
|
continue
|
|
190
193
|
|
|
191
|
-
filtered_sessions.append(session_data)
|
|
194
|
+
filtered_sessions.append(deepcopy(session_data))
|
|
192
195
|
|
|
193
196
|
total_count = len(filtered_sessions)
|
|
194
197
|
|
|
@@ -233,15 +236,16 @@ class InMemoryDb(BaseDb):
|
|
|
233
236
|
|
|
234
237
|
log_debug(f"Renamed session with id '{session_id}' to '{session_name}'")
|
|
235
238
|
|
|
239
|
+
session_copy = deepcopy(session)
|
|
236
240
|
if not deserialize:
|
|
237
|
-
return
|
|
241
|
+
return session_copy
|
|
238
242
|
|
|
239
243
|
if session_type == SessionType.AGENT:
|
|
240
|
-
return AgentSession.from_dict(
|
|
244
|
+
return AgentSession.from_dict(session_copy)
|
|
241
245
|
elif session_type == SessionType.TEAM:
|
|
242
|
-
return TeamSession.from_dict(
|
|
246
|
+
return TeamSession.from_dict(session_copy)
|
|
243
247
|
else:
|
|
244
|
-
return WorkflowSession.from_dict(
|
|
248
|
+
return WorkflowSession.from_dict(session_copy)
|
|
245
249
|
|
|
246
250
|
return None
|
|
247
251
|
|
|
@@ -269,22 +273,26 @@ class InMemoryDb(BaseDb):
|
|
|
269
273
|
if existing_session.get("session_id") == session_dict.get("session_id") and self._matches_session_key(
|
|
270
274
|
existing_session, session
|
|
271
275
|
):
|
|
272
|
-
# Update existing session
|
|
273
276
|
session_dict["updated_at"] = int(time.time())
|
|
274
|
-
self._sessions[i] = session_dict
|
|
277
|
+
self._sessions[i] = deepcopy(session_dict)
|
|
275
278
|
session_updated = True
|
|
276
279
|
break
|
|
277
280
|
|
|
278
281
|
if not session_updated:
|
|
279
|
-
# Add new session
|
|
280
282
|
session_dict["created_at"] = session_dict.get("created_at", int(time.time()))
|
|
281
283
|
session_dict["updated_at"] = session_dict.get("created_at")
|
|
282
|
-
self._sessions.append(session_dict)
|
|
284
|
+
self._sessions.append(deepcopy(session_dict))
|
|
283
285
|
|
|
286
|
+
session_dict_copy = deepcopy(session_dict)
|
|
284
287
|
if not deserialize:
|
|
285
|
-
return
|
|
288
|
+
return session_dict_copy
|
|
286
289
|
|
|
287
|
-
|
|
290
|
+
if session_dict_copy["session_type"] == SessionType.AGENT:
|
|
291
|
+
return AgentSession.from_dict(session_dict_copy)
|
|
292
|
+
elif session_dict_copy["session_type"] == SessionType.TEAM:
|
|
293
|
+
return TeamSession.from_dict(session_dict_copy)
|
|
294
|
+
else:
|
|
295
|
+
return WorkflowSession.from_dict(session_dict_copy)
|
|
288
296
|
|
|
289
297
|
except Exception as e:
|
|
290
298
|
log_error(f"Exception upserting session: {e}")
|
|
@@ -378,9 +386,10 @@ class InMemoryDb(BaseDb):
|
|
|
378
386
|
try:
|
|
379
387
|
for memory_data in self._memories:
|
|
380
388
|
if memory_data.get("memory_id") == memory_id:
|
|
389
|
+
memory_data_copy = deepcopy(memory_data)
|
|
381
390
|
if not deserialize:
|
|
382
|
-
return
|
|
383
|
-
return UserMemory.from_dict(
|
|
391
|
+
return memory_data_copy
|
|
392
|
+
return UserMemory.from_dict(memory_data_copy)
|
|
384
393
|
|
|
385
394
|
return None
|
|
386
395
|
|
|
@@ -420,7 +429,7 @@ class InMemoryDb(BaseDb):
|
|
|
420
429
|
if search_content.lower() not in memory_content.lower():
|
|
421
430
|
continue
|
|
422
431
|
|
|
423
|
-
filtered_memories.append(memory_data)
|
|
432
|
+
filtered_memories.append(deepcopy(memory_data))
|
|
424
433
|
|
|
425
434
|
total_count = len(filtered_memories)
|
|
426
435
|
|
|
@@ -499,9 +508,11 @@ class InMemoryDb(BaseDb):
|
|
|
499
508
|
if not memory_updated:
|
|
500
509
|
self._memories.append(memory_dict)
|
|
501
510
|
|
|
511
|
+
memory_dict_copy = deepcopy(memory_dict)
|
|
502
512
|
if not deserialize:
|
|
503
|
-
return
|
|
504
|
-
|
|
513
|
+
return memory_dict_copy
|
|
514
|
+
|
|
515
|
+
return UserMemory.from_dict(memory_dict_copy)
|
|
505
516
|
|
|
506
517
|
except Exception as e:
|
|
507
518
|
log_warning(f"Exception upserting user memory: {e}")
|
|
@@ -657,8 +668,8 @@ class InMemoryDb(BaseDb):
|
|
|
657
668
|
# Only include necessary fields for metrics
|
|
658
669
|
filtered_session = {
|
|
659
670
|
"user_id": session.get("user_id"),
|
|
660
|
-
"session_data": session.get("session_data"),
|
|
661
|
-
"runs": session.get("runs"),
|
|
671
|
+
"session_data": deepcopy(session.get("session_data")),
|
|
672
|
+
"runs": deepcopy(session.get("runs")),
|
|
662
673
|
"created_at": session.get("created_at"),
|
|
663
674
|
"session_type": session.get("session_type"),
|
|
664
675
|
}
|
|
@@ -688,7 +699,7 @@ class InMemoryDb(BaseDb):
|
|
|
688
699
|
if ending_date and metric_date > ending_date:
|
|
689
700
|
continue
|
|
690
701
|
|
|
691
|
-
filtered_metrics.append(metric)
|
|
702
|
+
filtered_metrics.append(deepcopy(metric))
|
|
692
703
|
|
|
693
704
|
updated_at = metric.get("updated_at")
|
|
694
705
|
if updated_at and (latest_updated_at is None or updated_at > latest_updated_at):
|
|
@@ -763,7 +774,7 @@ class InMemoryDb(BaseDb):
|
|
|
763
774
|
Exception: If an error occurs during retrieval.
|
|
764
775
|
"""
|
|
765
776
|
try:
|
|
766
|
-
knowledge_items = self._knowledge
|
|
777
|
+
knowledge_items = [deepcopy(item) for item in self._knowledge]
|
|
767
778
|
|
|
768
779
|
total_count = len(knowledge_items)
|
|
769
780
|
|
|
@@ -858,9 +869,10 @@ class InMemoryDb(BaseDb):
|
|
|
858
869
|
try:
|
|
859
870
|
for run_data in self._eval_runs:
|
|
860
871
|
if run_data.get("run_id") == eval_run_id:
|
|
872
|
+
run_data_copy = deepcopy(run_data)
|
|
861
873
|
if not deserialize:
|
|
862
|
-
return
|
|
863
|
-
return EvalRunRecord.model_validate(
|
|
874
|
+
return run_data_copy
|
|
875
|
+
return EvalRunRecord.model_validate(run_data_copy)
|
|
864
876
|
|
|
865
877
|
return None
|
|
866
878
|
|
|
@@ -906,7 +918,7 @@ class InMemoryDb(BaseDb):
|
|
|
906
918
|
elif filter_type == EvalFilterType.WORKFLOW and run_data.get("workflow_id") is None:
|
|
907
919
|
continue
|
|
908
920
|
|
|
909
|
-
filtered_runs.append(run_data)
|
|
921
|
+
filtered_runs.append(deepcopy(run_data))
|
|
910
922
|
|
|
911
923
|
total_count = len(filtered_runs)
|
|
912
924
|
|
|
@@ -945,10 +957,11 @@ class InMemoryDb(BaseDb):
|
|
|
945
957
|
|
|
946
958
|
log_debug(f"Renamed eval run with id '{eval_run_id}' to '{name}'")
|
|
947
959
|
|
|
960
|
+
run_data_copy = deepcopy(run_data)
|
|
948
961
|
if not deserialize:
|
|
949
|
-
return
|
|
962
|
+
return run_data_copy
|
|
950
963
|
|
|
951
|
-
return EvalRunRecord.model_validate(
|
|
964
|
+
return EvalRunRecord.model_validate(run_data_copy)
|
|
952
965
|
|
|
953
966
|
return None
|
|
954
967
|
|
agno/db/mongo/mongo.py
CHANGED
|
@@ -16,7 +16,7 @@ from agno.db.mongo.utils import (
|
|
|
16
16
|
from agno.db.schemas.evals import EvalFilterType, EvalRunRecord, EvalType
|
|
17
17
|
from agno.db.schemas.knowledge import KnowledgeRow
|
|
18
18
|
from agno.db.schemas.memory import UserMemory
|
|
19
|
-
from agno.db.utils import deserialize_session_json_fields
|
|
19
|
+
from agno.db.utils import deserialize_session_json_fields
|
|
20
20
|
from agno.session import AgentSession, Session, TeamSession, WorkflowSession
|
|
21
21
|
from agno.utils.log import log_debug, log_error, log_info
|
|
22
22
|
from agno.utils.string import generate_id
|
|
@@ -282,7 +282,6 @@ class MongoDb(BaseDb):
|
|
|
282
282
|
return None
|
|
283
283
|
|
|
284
284
|
session = deserialize_session_json_fields(result)
|
|
285
|
-
|
|
286
285
|
if not deserialize:
|
|
287
286
|
return session
|
|
288
287
|
|
|
@@ -385,7 +384,6 @@ class MongoDb(BaseDb):
|
|
|
385
384
|
records = list(cursor)
|
|
386
385
|
if records is None:
|
|
387
386
|
return [] if deserialize else ([], 0)
|
|
388
|
-
|
|
389
387
|
sessions_raw = [deserialize_session_json_fields(record) for record in records]
|
|
390
388
|
|
|
391
389
|
if not deserialize:
|
|
@@ -489,25 +487,25 @@ class MongoDb(BaseDb):
|
|
|
489
487
|
if collection is None:
|
|
490
488
|
return None
|
|
491
489
|
|
|
492
|
-
|
|
490
|
+
session_dict = session.to_dict()
|
|
493
491
|
|
|
494
492
|
if isinstance(session, AgentSession):
|
|
495
493
|
record = {
|
|
496
|
-
"session_id":
|
|
494
|
+
"session_id": session_dict.get("session_id"),
|
|
497
495
|
"session_type": SessionType.AGENT.value,
|
|
498
|
-
"agent_id":
|
|
499
|
-
"user_id":
|
|
500
|
-
"runs":
|
|
501
|
-
"agent_data":
|
|
502
|
-
"session_data":
|
|
503
|
-
"summary":
|
|
504
|
-
"metadata":
|
|
505
|
-
"created_at":
|
|
496
|
+
"agent_id": session_dict.get("agent_id"),
|
|
497
|
+
"user_id": session_dict.get("user_id"),
|
|
498
|
+
"runs": session_dict.get("runs"),
|
|
499
|
+
"agent_data": session_dict.get("agent_data"),
|
|
500
|
+
"session_data": session_dict.get("session_data"),
|
|
501
|
+
"summary": session_dict.get("summary"),
|
|
502
|
+
"metadata": session_dict.get("metadata"),
|
|
503
|
+
"created_at": session_dict.get("created_at"),
|
|
506
504
|
"updated_at": int(time.time()),
|
|
507
505
|
}
|
|
508
506
|
|
|
509
507
|
result = collection.find_one_and_replace(
|
|
510
|
-
filter={"session_id":
|
|
508
|
+
filter={"session_id": session_dict.get("session_id")},
|
|
511
509
|
replacement=record,
|
|
512
510
|
upsert=True,
|
|
513
511
|
return_document=ReturnDocument.AFTER,
|
|
@@ -515,7 +513,7 @@ class MongoDb(BaseDb):
|
|
|
515
513
|
if not result:
|
|
516
514
|
return None
|
|
517
515
|
|
|
518
|
-
session =
|
|
516
|
+
session = result # type: ignore
|
|
519
517
|
|
|
520
518
|
if not deserialize:
|
|
521
519
|
return session
|
|
@@ -524,21 +522,21 @@ class MongoDb(BaseDb):
|
|
|
524
522
|
|
|
525
523
|
elif isinstance(session, TeamSession):
|
|
526
524
|
record = {
|
|
527
|
-
"session_id":
|
|
525
|
+
"session_id": session_dict.get("session_id"),
|
|
528
526
|
"session_type": SessionType.TEAM.value,
|
|
529
|
-
"team_id":
|
|
530
|
-
"user_id":
|
|
531
|
-
"runs":
|
|
532
|
-
"team_data":
|
|
533
|
-
"session_data":
|
|
534
|
-
"summary":
|
|
535
|
-
"metadata":
|
|
536
|
-
"created_at":
|
|
527
|
+
"team_id": session_dict.get("team_id"),
|
|
528
|
+
"user_id": session_dict.get("user_id"),
|
|
529
|
+
"runs": session_dict.get("runs"),
|
|
530
|
+
"team_data": session_dict.get("team_data"),
|
|
531
|
+
"session_data": session_dict.get("session_data"),
|
|
532
|
+
"summary": session_dict.get("summary"),
|
|
533
|
+
"metadata": session_dict.get("metadata"),
|
|
534
|
+
"created_at": session_dict.get("created_at"),
|
|
537
535
|
"updated_at": int(time.time()),
|
|
538
536
|
}
|
|
539
537
|
|
|
540
538
|
result = collection.find_one_and_replace(
|
|
541
|
-
filter={"session_id":
|
|
539
|
+
filter={"session_id": session_dict.get("session_id")},
|
|
542
540
|
replacement=record,
|
|
543
541
|
upsert=True,
|
|
544
542
|
return_document=ReturnDocument.AFTER,
|
|
@@ -546,7 +544,8 @@ class MongoDb(BaseDb):
|
|
|
546
544
|
if not result:
|
|
547
545
|
return None
|
|
548
546
|
|
|
549
|
-
|
|
547
|
+
# MongoDB stores native objects, no deserialization needed for document fields
|
|
548
|
+
session = result # type: ignore
|
|
550
549
|
|
|
551
550
|
if not deserialize:
|
|
552
551
|
return session
|
|
@@ -555,21 +554,21 @@ class MongoDb(BaseDb):
|
|
|
555
554
|
|
|
556
555
|
else:
|
|
557
556
|
record = {
|
|
558
|
-
"session_id":
|
|
557
|
+
"session_id": session_dict.get("session_id"),
|
|
559
558
|
"session_type": SessionType.WORKFLOW.value,
|
|
560
|
-
"workflow_id":
|
|
561
|
-
"user_id":
|
|
562
|
-
"runs":
|
|
563
|
-
"workflow_data":
|
|
564
|
-
"session_data":
|
|
565
|
-
"summary":
|
|
566
|
-
"metadata":
|
|
567
|
-
"created_at":
|
|
559
|
+
"workflow_id": session_dict.get("workflow_id"),
|
|
560
|
+
"user_id": session_dict.get("user_id"),
|
|
561
|
+
"runs": session_dict.get("runs"),
|
|
562
|
+
"workflow_data": session_dict.get("workflow_data"),
|
|
563
|
+
"session_data": session_dict.get("session_data"),
|
|
564
|
+
"summary": session_dict.get("summary"),
|
|
565
|
+
"metadata": session_dict.get("metadata"),
|
|
566
|
+
"created_at": session_dict.get("created_at"),
|
|
568
567
|
"updated_at": int(time.time()),
|
|
569
568
|
}
|
|
570
569
|
|
|
571
570
|
result = collection.find_one_and_replace(
|
|
572
|
-
filter={"session_id":
|
|
571
|
+
filter={"session_id": session_dict.get("session_id")},
|
|
573
572
|
replacement=record,
|
|
574
573
|
upsert=True,
|
|
575
574
|
return_document=ReturnDocument.AFTER,
|
|
@@ -577,7 +576,7 @@ class MongoDb(BaseDb):
|
|
|
577
576
|
if not result:
|
|
578
577
|
return None
|
|
579
578
|
|
|
580
|
-
session =
|
|
579
|
+
session = result # type: ignore
|
|
581
580
|
|
|
582
581
|
if not deserialize:
|
|
583
582
|
return session
|
|
@@ -628,48 +627,48 @@ class MongoDb(BaseDb):
|
|
|
628
627
|
if session is None:
|
|
629
628
|
continue
|
|
630
629
|
|
|
631
|
-
|
|
630
|
+
session_dict = session.to_dict()
|
|
632
631
|
|
|
633
632
|
if isinstance(session, AgentSession):
|
|
634
633
|
record = {
|
|
635
|
-
"session_id":
|
|
634
|
+
"session_id": session_dict.get("session_id"),
|
|
636
635
|
"session_type": SessionType.AGENT.value,
|
|
637
|
-
"agent_id":
|
|
638
|
-
"user_id":
|
|
639
|
-
"runs":
|
|
640
|
-
"agent_data":
|
|
641
|
-
"session_data":
|
|
642
|
-
"summary":
|
|
643
|
-
"metadata":
|
|
644
|
-
"created_at":
|
|
636
|
+
"agent_id": session_dict.get("agent_id"),
|
|
637
|
+
"user_id": session_dict.get("user_id"),
|
|
638
|
+
"runs": session_dict.get("runs"),
|
|
639
|
+
"agent_data": session_dict.get("agent_data"),
|
|
640
|
+
"session_data": session_dict.get("session_data"),
|
|
641
|
+
"summary": session_dict.get("summary"),
|
|
642
|
+
"metadata": session_dict.get("metadata"),
|
|
643
|
+
"created_at": session_dict.get("created_at"),
|
|
645
644
|
"updated_at": int(time.time()),
|
|
646
645
|
}
|
|
647
646
|
elif isinstance(session, TeamSession):
|
|
648
647
|
record = {
|
|
649
|
-
"session_id":
|
|
648
|
+
"session_id": session_dict.get("session_id"),
|
|
650
649
|
"session_type": SessionType.TEAM.value,
|
|
651
|
-
"team_id":
|
|
652
|
-
"user_id":
|
|
653
|
-
"runs":
|
|
654
|
-
"team_data":
|
|
655
|
-
"session_data":
|
|
656
|
-
"summary":
|
|
657
|
-
"metadata":
|
|
658
|
-
"created_at":
|
|
650
|
+
"team_id": session_dict.get("team_id"),
|
|
651
|
+
"user_id": session_dict.get("user_id"),
|
|
652
|
+
"runs": session_dict.get("runs"),
|
|
653
|
+
"team_data": session_dict.get("team_data"),
|
|
654
|
+
"session_data": session_dict.get("session_data"),
|
|
655
|
+
"summary": session_dict.get("summary"),
|
|
656
|
+
"metadata": session_dict.get("metadata"),
|
|
657
|
+
"created_at": session_dict.get("created_at"),
|
|
659
658
|
"updated_at": int(time.time()),
|
|
660
659
|
}
|
|
661
660
|
elif isinstance(session, WorkflowSession):
|
|
662
661
|
record = {
|
|
663
|
-
"session_id":
|
|
662
|
+
"session_id": session_dict.get("session_id"),
|
|
664
663
|
"session_type": SessionType.WORKFLOW.value,
|
|
665
|
-
"workflow_id":
|
|
666
|
-
"user_id":
|
|
667
|
-
"runs":
|
|
668
|
-
"workflow_data":
|
|
669
|
-
"session_data":
|
|
670
|
-
"summary":
|
|
671
|
-
"metadata":
|
|
672
|
-
"created_at":
|
|
664
|
+
"workflow_id": session_dict.get("workflow_id"),
|
|
665
|
+
"user_id": session_dict.get("user_id"),
|
|
666
|
+
"runs": session_dict.get("runs"),
|
|
667
|
+
"workflow_data": session_dict.get("workflow_data"),
|
|
668
|
+
"session_data": session_dict.get("session_data"),
|
|
669
|
+
"summary": session_dict.get("summary"),
|
|
670
|
+
"metadata": session_dict.get("metadata"),
|
|
671
|
+
"created_at": session_dict.get("created_at"),
|
|
673
672
|
"updated_at": int(time.time()),
|
|
674
673
|
}
|
|
675
674
|
else:
|
|
@@ -688,7 +687,7 @@ class MongoDb(BaseDb):
|
|
|
688
687
|
cursor = collection.find({"session_id": {"$in": session_ids}})
|
|
689
688
|
|
|
690
689
|
for doc in cursor:
|
|
691
|
-
session_dict =
|
|
690
|
+
session_dict = doc
|
|
692
691
|
|
|
693
692
|
if deserialize:
|
|
694
693
|
session_type = doc.get("session_type")
|
agno/db/postgres/postgres.py
CHANGED
|
@@ -756,7 +756,7 @@ class PostgresDb(BaseDb):
|
|
|
756
756
|
)
|
|
757
757
|
|
|
758
758
|
with self.Session() as sess, sess.begin():
|
|
759
|
-
stmt = postgresql.insert(table)
|
|
759
|
+
stmt: Any = postgresql.insert(table)
|
|
760
760
|
update_columns = {
|
|
761
761
|
col.name: stmt.excluded[col.name]
|
|
762
762
|
for col in table.columns
|
|
@@ -1263,13 +1263,15 @@ class PostgresDb(BaseDb):
|
|
|
1263
1263
|
results: List[Union[UserMemory, Dict[str, Any]]] = []
|
|
1264
1264
|
|
|
1265
1265
|
with self.Session() as sess, sess.begin():
|
|
1266
|
-
|
|
1266
|
+
insert_stmt = postgresql.insert(table)
|
|
1267
1267
|
update_columns = {
|
|
1268
|
-
col.name:
|
|
1268
|
+
col.name: insert_stmt.excluded[col.name]
|
|
1269
1269
|
for col in table.columns
|
|
1270
1270
|
if col.name not in ["memory_id"] # Don't update primary key
|
|
1271
1271
|
}
|
|
1272
|
-
stmt =
|
|
1272
|
+
stmt = insert_stmt.on_conflict_do_update(index_elements=["memory_id"], set_=update_columns).returning(
|
|
1273
|
+
table
|
|
1274
|
+
)
|
|
1273
1275
|
|
|
1274
1276
|
result = sess.execute(stmt, memory_records)
|
|
1275
1277
|
for row in result.fetchall():
|
agno/db/utils.py
CHANGED
|
@@ -4,7 +4,6 @@ import json
|
|
|
4
4
|
from datetime import date, datetime
|
|
5
5
|
from uuid import UUID
|
|
6
6
|
|
|
7
|
-
from agno.db.base import SessionType
|
|
8
7
|
from agno.models.message import Message
|
|
9
8
|
from agno.models.metrics import Metrics
|
|
10
9
|
|
|
@@ -55,34 +54,63 @@ def serialize_session_json_fields(session: dict) -> dict:
|
|
|
55
54
|
|
|
56
55
|
|
|
57
56
|
def deserialize_session_json_fields(session: dict) -> dict:
|
|
58
|
-
"""Deserialize
|
|
57
|
+
"""Deserialize JSON fields in the given Session dictionary.
|
|
59
58
|
|
|
60
59
|
Args:
|
|
61
60
|
session (dict): The dictionary to deserialize.
|
|
62
61
|
|
|
63
62
|
Returns:
|
|
64
|
-
dict: The dictionary with JSON fields deserialized.
|
|
63
|
+
dict: The dictionary with JSON string fields deserialized to objects.
|
|
65
64
|
"""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if session.get("
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if session.get("
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
from agno.utils.log import log_warning
|
|
66
|
+
|
|
67
|
+
if session.get("agent_data") is not None and isinstance(session["agent_data"], str):
|
|
68
|
+
try:
|
|
69
|
+
session["agent_data"] = json.loads(session["agent_data"])
|
|
70
|
+
except (json.JSONDecodeError, TypeError) as e:
|
|
71
|
+
log_warning(f"Warning: Could not parse agent_data as JSON, keeping as string: {e}")
|
|
72
|
+
|
|
73
|
+
if session.get("team_data") is not None and isinstance(session["team_data"], str):
|
|
74
|
+
try:
|
|
75
|
+
session["team_data"] = json.loads(session["team_data"])
|
|
76
|
+
except (json.JSONDecodeError, TypeError) as e:
|
|
77
|
+
log_warning(f"Warning: Could not parse team_data as JSON, keeping as string: {e}")
|
|
78
|
+
|
|
79
|
+
if session.get("workflow_data") is not None and isinstance(session["workflow_data"], str):
|
|
80
|
+
try:
|
|
81
|
+
session["workflow_data"] = json.loads(session["workflow_data"])
|
|
82
|
+
except (json.JSONDecodeError, TypeError) as e:
|
|
83
|
+
log_warning(f"Warning: Could not parse workflow_data as JSON, keeping as string: {e}")
|
|
84
|
+
|
|
85
|
+
if session.get("metadata") is not None and isinstance(session["metadata"], str):
|
|
86
|
+
try:
|
|
87
|
+
session["metadata"] = json.loads(session["metadata"])
|
|
88
|
+
except (json.JSONDecodeError, TypeError) as e:
|
|
89
|
+
log_warning(f"Warning: Could not parse metadata as JSON, keeping as string: {e}")
|
|
90
|
+
|
|
91
|
+
if session.get("chat_history") is not None and isinstance(session["chat_history"], str):
|
|
92
|
+
try:
|
|
93
|
+
session["chat_history"] = json.loads(session["chat_history"])
|
|
94
|
+
except (json.JSONDecodeError, TypeError) as e:
|
|
95
|
+
log_warning(f"Warning: Could not parse chat_history as JSON, keeping as string: {e}")
|
|
96
|
+
|
|
97
|
+
if session.get("summary") is not None and isinstance(session["summary"], str):
|
|
98
|
+
try:
|
|
99
|
+
session["summary"] = json.loads(session["summary"])
|
|
100
|
+
except (json.JSONDecodeError, TypeError) as e:
|
|
101
|
+
log_warning(f"Warning: Could not parse summary as JSON, keeping as string: {e}")
|
|
102
|
+
|
|
78
103
|
if session.get("session_data") is not None and isinstance(session["session_data"], str):
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
104
|
+
try:
|
|
105
|
+
session["session_data"] = json.loads(session["session_data"])
|
|
106
|
+
except (json.JSONDecodeError, TypeError) as e:
|
|
107
|
+
log_warning(f"Warning: Could not parse session_data as JSON, keeping as string: {e}")
|
|
108
|
+
|
|
109
|
+
# Handle runs field with session type checking
|
|
110
|
+
if session.get("runs") is not None and isinstance(session["runs"], str):
|
|
111
|
+
try:
|
|
86
112
|
session["runs"] = json.loads(session["runs"])
|
|
113
|
+
except (json.JSONDecodeError, TypeError) as e:
|
|
114
|
+
log_warning(f"Warning: Could not parse runs as JSON, keeping as string: {e}")
|
|
87
115
|
|
|
88
116
|
return session
|