agno 2.0.7__py3-none-any.whl → 2.0.9__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 (64) hide show
  1. agno/agent/agent.py +83 -51
  2. agno/db/base.py +14 -0
  3. agno/db/dynamo/dynamo.py +107 -27
  4. agno/db/firestore/firestore.py +109 -33
  5. agno/db/gcs_json/gcs_json_db.py +100 -20
  6. agno/db/in_memory/in_memory_db.py +95 -20
  7. agno/db/json/json_db.py +101 -21
  8. agno/db/migrations/v1_to_v2.py +322 -47
  9. agno/db/mongo/mongo.py +251 -26
  10. agno/db/mysql/mysql.py +307 -6
  11. agno/db/postgres/postgres.py +279 -33
  12. agno/db/redis/redis.py +99 -22
  13. agno/db/singlestore/singlestore.py +319 -38
  14. agno/db/sqlite/sqlite.py +339 -23
  15. agno/knowledge/embedder/sentence_transformer.py +3 -3
  16. agno/knowledge/knowledge.py +152 -31
  17. agno/knowledge/types.py +8 -0
  18. agno/models/anthropic/claude.py +0 -20
  19. agno/models/cometapi/__init__.py +5 -0
  20. agno/models/cometapi/cometapi.py +57 -0
  21. agno/models/google/gemini.py +4 -8
  22. agno/models/huggingface/huggingface.py +2 -1
  23. agno/models/ollama/chat.py +52 -3
  24. agno/models/openai/chat.py +9 -7
  25. agno/models/openai/responses.py +21 -17
  26. agno/os/interfaces/agui/agui.py +2 -2
  27. agno/os/interfaces/agui/utils.py +81 -18
  28. agno/os/interfaces/base.py +2 -0
  29. agno/os/interfaces/slack/router.py +50 -10
  30. agno/os/interfaces/slack/slack.py +6 -4
  31. agno/os/interfaces/whatsapp/router.py +7 -4
  32. agno/os/interfaces/whatsapp/whatsapp.py +2 -2
  33. agno/os/router.py +18 -0
  34. agno/os/utils.py +10 -2
  35. agno/reasoning/azure_ai_foundry.py +2 -2
  36. agno/reasoning/deepseek.py +2 -2
  37. agno/reasoning/default.py +3 -1
  38. agno/reasoning/groq.py +2 -2
  39. agno/reasoning/ollama.py +2 -2
  40. agno/reasoning/openai.py +2 -2
  41. agno/run/base.py +15 -2
  42. agno/session/agent.py +8 -5
  43. agno/session/team.py +14 -10
  44. agno/team/team.py +218 -111
  45. agno/tools/function.py +43 -4
  46. agno/tools/mcp.py +60 -37
  47. agno/tools/mcp_toolbox.py +284 -0
  48. agno/tools/scrapegraph.py +58 -31
  49. agno/tools/whatsapp.py +1 -1
  50. agno/utils/gemini.py +147 -19
  51. agno/utils/models/claude.py +9 -0
  52. agno/utils/print_response/agent.py +18 -2
  53. agno/utils/print_response/team.py +22 -6
  54. agno/utils/reasoning.py +22 -1
  55. agno/utils/string.py +9 -0
  56. agno/vectordb/base.py +2 -2
  57. agno/vectordb/langchaindb/langchaindb.py +5 -7
  58. agno/vectordb/llamaindex/llamaindexdb.py +25 -6
  59. agno/workflow/workflow.py +30 -15
  60. {agno-2.0.7.dist-info → agno-2.0.9.dist-info}/METADATA +4 -1
  61. {agno-2.0.7.dist-info → agno-2.0.9.dist-info}/RECORD +64 -61
  62. {agno-2.0.7.dist-info → agno-2.0.9.dist-info}/WHEEL +0 -0
  63. {agno-2.0.7.dist-info → agno-2.0.9.dist-info}/licenses/LICENSE +0 -0
  64. {agno-2.0.7.dist-info → agno-2.0.9.dist-info}/top_level.txt +0 -0
agno/db/dynamo/dynamo.py CHANGED
@@ -31,7 +31,7 @@ from agno.db.schemas.evals import EvalFilterType, EvalRunRecord, EvalType
31
31
  from agno.db.schemas.knowledge import KnowledgeRow
32
32
  from agno.db.schemas.memory import UserMemory
33
33
  from agno.session import AgentSession, Session, TeamSession, WorkflowSession
34
- from agno.utils.log import log_debug, log_error
34
+ from agno.utils.log import log_debug, log_error, log_info
35
35
  from agno.utils.string import generate_id
36
36
 
37
37
  try:
@@ -232,6 +232,7 @@ class DynamoDb(BaseDb):
232
232
 
233
233
  except Exception as e:
234
234
  log_error(f"Failed to delete sessions: {e}")
235
+ raise e
235
236
 
236
237
  def get_session(
237
238
  self,
@@ -290,7 +291,7 @@ class DynamoDb(BaseDb):
290
291
 
291
292
  except Exception as e:
292
293
  log_error(f"Failed to get session {session_id}: {e}")
293
- return None
294
+ raise e
294
295
 
295
296
  def get_sessions(
296
297
  self,
@@ -410,7 +411,7 @@ class DynamoDb(BaseDb):
410
411
 
411
412
  except Exception as e:
412
413
  log_error(f"Failed to get sessions: {e}")
413
- return []
414
+ raise e
414
415
 
415
416
  def rename_session(
416
417
  self,
@@ -478,7 +479,7 @@ class DynamoDb(BaseDb):
478
479
 
479
480
  except Exception as e:
480
481
  log_error(f"Failed to rename session {session_id}: {e}")
481
- return None
482
+ raise e
482
483
 
483
484
  def upsert_session(
484
485
  self, session: Session, deserialize: Optional[bool] = True
@@ -520,7 +521,44 @@ class DynamoDb(BaseDb):
520
521
 
521
522
  except Exception as e:
522
523
  log_error(f"Failed to upsert session {session.session_id}: {e}")
523
- return None
524
+ raise e
525
+
526
+ def upsert_sessions(
527
+ self, sessions: List[Session], deserialize: Optional[bool] = True
528
+ ) -> List[Union[Session, Dict[str, Any]]]:
529
+ """
530
+ Bulk upsert multiple sessions for improved performance on large datasets.
531
+
532
+ Args:
533
+ sessions (List[Session]): List of sessions to upsert.
534
+ deserialize (Optional[bool]): Whether to deserialize the sessions. Defaults to True.
535
+
536
+ Returns:
537
+ List[Union[Session, Dict[str, Any]]]: List of upserted sessions.
538
+
539
+ Raises:
540
+ Exception: If an error occurs during bulk upsert.
541
+ """
542
+ if not sessions:
543
+ return []
544
+
545
+ try:
546
+ log_info(
547
+ f"DynamoDb doesn't support efficient bulk operations, falling back to individual upserts for {len(sessions)} sessions"
548
+ )
549
+
550
+ # Fall back to individual upserts
551
+ results = []
552
+ for session in sessions:
553
+ if session is not None:
554
+ result = self.upsert_session(session, deserialize=deserialize)
555
+ if result is not None:
556
+ results.append(result)
557
+ return results
558
+
559
+ except Exception as e:
560
+ log_error(f"Exception during bulk session upsert: {e}")
561
+ return []
524
562
 
525
563
  # --- User Memory ---
526
564
 
@@ -543,6 +581,7 @@ class DynamoDb(BaseDb):
543
581
 
544
582
  except Exception as e:
545
583
  log_error(f"Failed to delete user memory {memory_id}: {e}")
584
+ raise e
546
585
 
547
586
  def delete_user_memories(self, memory_ids: List[str]) -> None:
548
587
  """
@@ -567,6 +606,7 @@ class DynamoDb(BaseDb):
567
606
 
568
607
  except Exception as e:
569
608
  log_error(f"Failed to delete user memories: {e}")
609
+ raise e
570
610
 
571
611
  def get_all_memory_topics(self) -> List[str]:
572
612
  """Get all memory topics from the database.
@@ -599,7 +639,7 @@ class DynamoDb(BaseDb):
599
639
 
600
640
  except Exception as e:
601
641
  log_error(f"Exception reading from memory table: {e}")
602
- return []
642
+ raise e
603
643
 
604
644
  def get_user_memory(
605
645
  self, memory_id: str, deserialize: Optional[bool] = True
@@ -632,7 +672,7 @@ class DynamoDb(BaseDb):
632
672
 
633
673
  except Exception as e:
634
674
  log_error(f"Failed to get user memory {memory_id}: {e}")
635
- return None
675
+ raise e
636
676
 
637
677
  def get_user_memories(
638
678
  self,
@@ -752,7 +792,7 @@ class DynamoDb(BaseDb):
752
792
 
753
793
  except Exception as e:
754
794
  log_error(f"Failed to get user memories: {e}")
755
- return [] if deserialize else ([], 0)
795
+ raise e
756
796
 
757
797
  def get_user_memory_stats(
758
798
  self,
@@ -838,7 +878,7 @@ class DynamoDb(BaseDb):
838
878
 
839
879
  except Exception as e:
840
880
  log_error(f"Failed to get user memory stats: {e}")
841
- return [], 0
881
+ raise e
842
882
 
843
883
  def upsert_user_memory(
844
884
  self, memory: UserMemory, deserialize: Optional[bool] = True
@@ -867,7 +907,44 @@ class DynamoDb(BaseDb):
867
907
 
868
908
  except Exception as e:
869
909
  log_error(f"Failed to upsert user memory: {e}")
870
- return None
910
+ raise e
911
+
912
+ def upsert_memories(
913
+ self, memories: List[UserMemory], deserialize: Optional[bool] = True
914
+ ) -> List[Union[UserMemory, Dict[str, Any]]]:
915
+ """
916
+ Bulk upsert multiple user memories for improved performance on large datasets.
917
+
918
+ Args:
919
+ memories (List[UserMemory]): List of memories to upsert.
920
+ deserialize (Optional[bool]): Whether to deserialize the memories. Defaults to True.
921
+
922
+ Returns:
923
+ List[Union[UserMemory, Dict[str, Any]]]: List of upserted memories.
924
+
925
+ Raises:
926
+ Exception: If an error occurs during bulk upsert.
927
+ """
928
+ if not memories:
929
+ return []
930
+
931
+ try:
932
+ log_info(
933
+ f"DynamoDb doesn't support efficient bulk operations, falling back to individual upserts for {len(memories)} memories"
934
+ )
935
+
936
+ # Fall back to individual upserts
937
+ results = []
938
+ for memory in memories:
939
+ if memory is not None:
940
+ result = self.upsert_user_memory(memory, deserialize=deserialize)
941
+ if result is not None:
942
+ results.append(result)
943
+ return results
944
+
945
+ except Exception as e:
946
+ log_error(f"Exception during bulk memory upsert: {e}")
947
+ return []
871
948
 
872
949
  def clear_memories(self) -> None:
873
950
  """Delete all memories from the database.
@@ -908,6 +985,7 @@ class DynamoDb(BaseDb):
908
985
  from agno.utils.log import log_warning
909
986
 
910
987
  log_warning(f"Exception deleting all memories: {e}")
988
+ raise e
911
989
 
912
990
  # --- Metrics ---
913
991
 
@@ -985,7 +1063,7 @@ class DynamoDb(BaseDb):
985
1063
 
986
1064
  except Exception as e:
987
1065
  log_error(f"Failed to calculate metrics: {e}")
988
- return None
1066
+ raise e
989
1067
 
990
1068
  def _get_metrics_calculation_starting_date(self) -> Optional[date]:
991
1069
  """Get the first date for which metrics calculation is needed:
@@ -1071,7 +1149,7 @@ class DynamoDb(BaseDb):
1071
1149
 
1072
1150
  except Exception as e:
1073
1151
  log_error(f"Failed to get metrics calculation starting date: {e}")
1074
- return None
1152
+ raise e
1075
1153
 
1076
1154
  def _get_all_sessions_for_metrics_calculation(
1077
1155
  self, start_timestamp: int, end_timestamp: int
@@ -1129,7 +1207,7 @@ class DynamoDb(BaseDb):
1129
1207
 
1130
1208
  except Exception as e:
1131
1209
  log_error(f"Failed to get sessions for metrics calculation: {e}")
1132
- return []
1210
+ raise e
1133
1211
 
1134
1212
  def _bulk_upsert_metrics(self, metrics_records: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
1135
1213
  """Bulk upsert metrics records into DynamoDB with proper deduplication.
@@ -1157,7 +1235,7 @@ class DynamoDb(BaseDb):
1157
1235
 
1158
1236
  except Exception as e:
1159
1237
  log_error(f"Failed to bulk upsert metrics: {e}")
1160
- return []
1238
+ raise e
1161
1239
 
1162
1240
  def _upsert_single_metrics_record(self, table_name: str, record: Dict[str, Any]) -> Optional[Dict[str, Any]]:
1163
1241
  """Upsert a single metrics record, checking for existing records with the same date.
@@ -1189,7 +1267,7 @@ class DynamoDb(BaseDb):
1189
1267
 
1190
1268
  except Exception as e:
1191
1269
  log_error(f"Failed to upsert single metrics record: {e}")
1192
- return None
1270
+ raise e
1193
1271
 
1194
1272
  def _get_existing_metrics_record(self, table_name: str, date_str: str) -> Optional[Dict[str, Any]]:
1195
1273
  """Get existing metrics record for a given date.
@@ -1222,7 +1300,7 @@ class DynamoDb(BaseDb):
1222
1300
 
1223
1301
  except Exception as e:
1224
1302
  log_error(f"Failed to get existing metrics record for date {date_str}: {e}")
1225
- return None
1303
+ raise e
1226
1304
 
1227
1305
  def _update_existing_metrics_record(
1228
1306
  self,
@@ -1256,7 +1334,7 @@ class DynamoDb(BaseDb):
1256
1334
 
1257
1335
  except Exception as e:
1258
1336
  log_error(f"Failed to update existing metrics record: {e}")
1259
- return None
1337
+ raise e
1260
1338
 
1261
1339
  def _create_new_metrics_record(self, table_name: str, record: Dict[str, Any]) -> Optional[Dict[str, Any]]:
1262
1340
  """Create a new metrics record.
@@ -1280,7 +1358,7 @@ class DynamoDb(BaseDb):
1280
1358
 
1281
1359
  except Exception as e:
1282
1360
  log_error(f"Failed to create new metrics record: {e}")
1283
- return None
1361
+ raise e
1284
1362
 
1285
1363
  def _prepare_metrics_record_for_dynamo(self, record: Dict[str, Any]) -> Dict[str, Any]:
1286
1364
  """Prepare a metrics record for DynamoDB serialization by converting all data types properly.
@@ -1403,7 +1481,7 @@ class DynamoDb(BaseDb):
1403
1481
 
1404
1482
  except Exception as e:
1405
1483
  log_error(f"Failed to get metrics: {e}")
1406
- return [], 0
1484
+ raise e
1407
1485
 
1408
1486
  # --- Knowledge methods ---
1409
1487
 
@@ -1425,6 +1503,7 @@ class DynamoDb(BaseDb):
1425
1503
 
1426
1504
  except Exception as e:
1427
1505
  log_error(f"Failed to delete knowledge content {id}: {e}")
1506
+ raise e
1428
1507
 
1429
1508
  def get_knowledge_content(self, id: str) -> Optional[KnowledgeRow]:
1430
1509
  """Get a knowledge row from the database.
@@ -1447,7 +1526,7 @@ class DynamoDb(BaseDb):
1447
1526
 
1448
1527
  except Exception as e:
1449
1528
  log_error(f"Failed to get knowledge content {id}: {e}")
1450
- return None
1529
+ raise e
1451
1530
 
1452
1531
  def get_knowledge_contents(
1453
1532
  self,
@@ -1519,7 +1598,7 @@ class DynamoDb(BaseDb):
1519
1598
 
1520
1599
  except Exception as e:
1521
1600
  log_error(f"Failed to get knowledge contents: {e}")
1522
- return [], 0
1601
+ raise e
1523
1602
 
1524
1603
  def upsert_knowledge_content(self, knowledge_row: KnowledgeRow):
1525
1604
  """Upsert knowledge content in the database.
@@ -1540,7 +1619,7 @@ class DynamoDb(BaseDb):
1540
1619
 
1541
1620
  except Exception as e:
1542
1621
  log_error(f"Failed to upsert knowledge content {knowledge_row.id}: {e}")
1543
- return None
1622
+ raise e
1544
1623
 
1545
1624
  # --- Eval ---
1546
1625
 
@@ -1570,7 +1649,7 @@ class DynamoDb(BaseDb):
1570
1649
 
1571
1650
  except Exception as e:
1572
1651
  log_error(f"Failed to create eval run: {e}")
1573
- return None
1652
+ raise e
1574
1653
 
1575
1654
  def delete_eval_runs(self, eval_run_ids: List[str]) -> None:
1576
1655
  if not eval_run_ids or not self.eval_table_name:
@@ -1588,6 +1667,7 @@ class DynamoDb(BaseDb):
1588
1667
 
1589
1668
  except Exception as e:
1590
1669
  log_error(f"Failed to delete eval runs: {e}")
1670
+ raise e
1591
1671
 
1592
1672
  def get_eval_run_raw(self, eval_run_id: str, table: Optional[Any] = None) -> Optional[Dict[str, Any]]:
1593
1673
  if not self.eval_table_name:
@@ -1603,7 +1683,7 @@ class DynamoDb(BaseDb):
1603
1683
 
1604
1684
  except Exception as e:
1605
1685
  log_error(f"Failed to get eval run {eval_run_id}: {e}")
1606
- return None
1686
+ raise e
1607
1687
 
1608
1688
  def get_eval_run(self, eval_run_id: str, table: Optional[Any] = None) -> Optional[EvalRunRecord]:
1609
1689
  if not self.eval_table_name:
@@ -1619,7 +1699,7 @@ class DynamoDb(BaseDb):
1619
1699
 
1620
1700
  except Exception as e:
1621
1701
  log_error(f"Failed to get eval run {eval_run_id}: {e}")
1622
- return None
1702
+ raise e
1623
1703
 
1624
1704
  def get_eval_runs(
1625
1705
  self,
@@ -1718,7 +1798,7 @@ class DynamoDb(BaseDb):
1718
1798
 
1719
1799
  except Exception as e:
1720
1800
  log_error(f"Failed to get eval runs: {e}")
1721
- return [] if deserialize else ([], 0)
1801
+ raise e
1722
1802
 
1723
1803
  def rename_eval_run(
1724
1804
  self, eval_run_id: str, name: str, deserialize: Optional[bool] = True
@@ -1750,4 +1830,4 @@ class DynamoDb(BaseDb):
1750
1830
 
1751
1831
  except Exception as e:
1752
1832
  log_error(f"Failed to rename eval run {eval_run_id}: {e}")
1753
- return None
1833
+ raise e
@@ -205,7 +205,7 @@ class FirestoreDb(BaseDb):
205
205
 
206
206
  except Exception as e:
207
207
  log_error(f"Error deleting session: {e}")
208
- return False
208
+ raise e
209
209
 
210
210
  def delete_sessions(self, session_ids: List[str]) -> None:
211
211
  """Delete multiple sessions from the database.
@@ -230,6 +230,7 @@ class FirestoreDb(BaseDb):
230
230
 
231
231
  except Exception as e:
232
232
  log_error(f"Error deleting sessions: {e}")
233
+ raise e
233
234
 
234
235
  def get_session(
235
236
  self,
@@ -288,7 +289,7 @@ class FirestoreDb(BaseDb):
288
289
 
289
290
  except Exception as e:
290
291
  log_error(f"Exception reading session: {e}")
291
- return None
292
+ raise e
292
293
 
293
294
  def get_sessions(
294
295
  self,
@@ -402,7 +403,7 @@ class FirestoreDb(BaseDb):
402
403
 
403
404
  except Exception as e:
404
405
  log_error(f"Exception reading sessions: {e}")
405
- return [] if deserialize else ([], 0)
406
+ raise e
406
407
 
407
408
  def rename_session(
408
409
  self, session_id: str, session_type: SessionType, session_name: str, deserialize: Optional[bool] = True
@@ -457,7 +458,7 @@ class FirestoreDb(BaseDb):
457
458
 
458
459
  except Exception as e:
459
460
  log_error(f"Exception renaming session: {e}")
460
- return None
461
+ raise e
461
462
 
462
463
  def upsert_session(
463
464
  self, session: Session, deserialize: Optional[bool] = True
@@ -554,7 +555,44 @@ class FirestoreDb(BaseDb):
554
555
 
555
556
  except Exception as e:
556
557
  log_error(f"Exception upserting session: {e}")
557
- return None
558
+ raise e
559
+
560
+ def upsert_sessions(
561
+ self, sessions: List[Session], deserialize: Optional[bool] = True
562
+ ) -> List[Union[Session, Dict[str, Any]]]:
563
+ """
564
+ Bulk upsert multiple sessions for improved performance on large datasets.
565
+
566
+ Args:
567
+ sessions (List[Session]): List of sessions to upsert.
568
+ deserialize (Optional[bool]): Whether to deserialize the sessions. Defaults to True.
569
+
570
+ Returns:
571
+ List[Union[Session, Dict[str, Any]]]: List of upserted sessions.
572
+
573
+ Raises:
574
+ Exception: If an error occurs during bulk upsert.
575
+ """
576
+ if not sessions:
577
+ return []
578
+
579
+ try:
580
+ log_info(
581
+ f"FirestoreDb doesn't support efficient bulk operations, falling back to individual upserts for {len(sessions)} sessions"
582
+ )
583
+
584
+ # Fall back to individual upserts
585
+ results = []
586
+ for session in sessions:
587
+ if session is not None:
588
+ result = self.upsert_session(session, deserialize=deserialize)
589
+ if result is not None:
590
+ results.append(result)
591
+ return results
592
+
593
+ except Exception as e:
594
+ log_error(f"Exception during bulk session upsert: {e}")
595
+ return []
558
596
 
559
597
  # -- Memory methods --
560
598
 
@@ -587,6 +625,7 @@ class FirestoreDb(BaseDb):
587
625
 
588
626
  except Exception as e:
589
627
  log_error(f"Error deleting user memory: {e}")
628
+ raise e
590
629
 
591
630
  def delete_user_memories(self, memory_ids: List[str]) -> None:
592
631
  """Delete user memories from the database.
@@ -617,6 +656,7 @@ class FirestoreDb(BaseDb):
617
656
 
618
657
  except Exception as e:
619
658
  log_error(f"Error deleting memories: {e}")
659
+ raise e
620
660
 
621
661
  def get_all_memory_topics(self, create_collection_if_not_found: Optional[bool] = True) -> List[str]:
622
662
  """Get all memory topics from the database.
@@ -644,8 +684,8 @@ class FirestoreDb(BaseDb):
644
684
  return [topic for topic in all_topics if topic]
645
685
 
646
686
  except Exception as e:
647
- log_error(f"Exception reading from collection: {e}")
648
- return []
687
+ log_error(f"Exception getting all memory topics: {e}")
688
+ raise e
649
689
 
650
690
  def get_user_memory(self, memory_id: str, deserialize: Optional[bool] = True) -> Optional[UserMemory]:
651
691
  """Get a memory from the database.
@@ -677,8 +717,8 @@ class FirestoreDb(BaseDb):
677
717
  return UserMemory.from_dict(result)
678
718
 
679
719
  except Exception as e:
680
- log_error(f"Exception reading from collection: {e}")
681
- return None
720
+ log_error(f"Exception getting user memory: {e}")
721
+ raise e
682
722
 
683
723
  def get_user_memories(
684
724
  self,
@@ -756,8 +796,8 @@ class FirestoreDb(BaseDb):
756
796
  return [UserMemory.from_dict(record) for record in records]
757
797
 
758
798
  except Exception as e:
759
- log_error(f"Exception reading from collection: {e}")
760
- return []
799
+ log_error(f"Exception getting user memories: {e}")
800
+ raise e
761
801
 
762
802
  def get_user_memory_stats(
763
803
  self,
@@ -813,7 +853,7 @@ class FirestoreDb(BaseDb):
813
853
 
814
854
  except Exception as e:
815
855
  log_error(f"Exception getting user memory stats: {e}")
816
- return [], 0
856
+ raise e
817
857
 
818
858
  def upsert_user_memory(
819
859
  self, memory: UserMemory, deserialize: Optional[bool] = True
@@ -859,7 +899,43 @@ class FirestoreDb(BaseDb):
859
899
 
860
900
  except Exception as e:
861
901
  log_error(f"Exception upserting user memory: {e}")
862
- return None
902
+ raise e
903
+
904
+ def upsert_memories(
905
+ self, memories: List[UserMemory], deserialize: Optional[bool] = True
906
+ ) -> List[Union[UserMemory, Dict[str, Any]]]:
907
+ """
908
+ Bulk upsert multiple user memories for improved performance on large datasets.
909
+
910
+ Args:
911
+ memories (List[UserMemory]): List of memories to upsert.
912
+ deserialize (Optional[bool]): Whether to deserialize the memories. Defaults to True.
913
+
914
+ Returns:
915
+ List[Union[UserMemory, Dict[str, Any]]]: List of upserted memories.
916
+
917
+ Raises:
918
+ Exception: If an error occurs during bulk upsert.
919
+ """
920
+ if not memories:
921
+ return []
922
+
923
+ try:
924
+ log_info(
925
+ f"FirestoreDb doesn't support efficient bulk operations, falling back to individual upserts for {len(memories)} memories"
926
+ )
927
+ # Fall back to individual upserts
928
+ results = []
929
+ for memory in memories:
930
+ if memory is not None:
931
+ result = self.upsert_user_memory(memory, deserialize=deserialize)
932
+ if result is not None:
933
+ results.append(result)
934
+ return results
935
+
936
+ except Exception as e:
937
+ log_error(f"Exception during bulk memory upsert: {e}")
938
+ return []
863
939
 
864
940
  def clear_memories(self) -> None:
865
941
  """Delete all memories from the database.
@@ -892,9 +968,8 @@ class FirestoreDb(BaseDb):
892
968
  batch.commit()
893
969
 
894
970
  except Exception as e:
895
- from agno.utils.log import log_warning
896
-
897
- log_warning(f"Exception deleting all memories: {e}")
971
+ log_error(f"Exception deleting all memories: {e}")
972
+ raise e
898
973
 
899
974
  # -- Metrics methods --
900
975
 
@@ -928,8 +1003,8 @@ class FirestoreDb(BaseDb):
928
1003
  return results
929
1004
 
930
1005
  except Exception as e:
931
- log_error(f"Exception reading from sessions collection: {e}")
932
- return []
1006
+ log_error(f"Exception getting all sessions for metrics calculation: {e}")
1007
+ raise e
933
1008
 
934
1009
  def _get_metrics_calculation_starting_date(self, collection_ref) -> Optional[date]:
935
1010
  """Get the first date for which metrics calculation is needed."""
@@ -961,7 +1036,7 @@ class FirestoreDb(BaseDb):
961
1036
 
962
1037
  except Exception as e:
963
1038
  log_error(f"Exception getting metrics calculation starting date: {e}")
964
- return None
1039
+ raise e
965
1040
 
966
1041
  def calculate_metrics(self) -> Optional[list[dict]]:
967
1042
  """Calculate metrics for all dates without complete metrics."""
@@ -1053,7 +1128,7 @@ class FirestoreDb(BaseDb):
1053
1128
 
1054
1129
  except Exception as e:
1055
1130
  log_error(f"Exception getting metrics: {e}")
1056
- return [], None
1131
+ raise e
1057
1132
 
1058
1133
  # -- Knowledge methods --
1059
1134
 
@@ -1074,7 +1149,8 @@ class FirestoreDb(BaseDb):
1074
1149
  doc.reference.delete()
1075
1150
 
1076
1151
  except Exception as e:
1077
- log_error(f"Error deleting knowledge source: {e}")
1152
+ log_error(f"Error deleting knowledge content: {e}")
1153
+ raise e
1078
1154
 
1079
1155
  def get_knowledge_content(self, id: str) -> Optional[KnowledgeRow]:
1080
1156
  """Get a knowledge row from the database.
@@ -1099,8 +1175,8 @@ class FirestoreDb(BaseDb):
1099
1175
  return None
1100
1176
 
1101
1177
  except Exception as e:
1102
- log_error(f"Error getting knowledge source: {e}")
1103
- return None
1178
+ log_error(f"Error getting knowledge content: {e}")
1179
+ raise e
1104
1180
 
1105
1181
  def get_knowledge_contents(
1106
1182
  self,
@@ -1148,8 +1224,8 @@ class FirestoreDb(BaseDb):
1148
1224
  return knowledge_rows, total_count
1149
1225
 
1150
1226
  except Exception as e:
1151
- log_error(f"Error getting knowledge sources: {e}")
1152
- return [], 0
1227
+ log_error(f"Error getting knowledge contents: {e}")
1228
+ raise e
1153
1229
 
1154
1230
  def upsert_knowledge_content(self, knowledge_row: KnowledgeRow):
1155
1231
  """Upsert knowledge content in the database.
@@ -1179,8 +1255,8 @@ class FirestoreDb(BaseDb):
1179
1255
  return knowledge_row
1180
1256
 
1181
1257
  except Exception as e:
1182
- log_error(f"Error upserting knowledge document: {e}")
1183
- return None
1258
+ log_error(f"Error upserting knowledge content: {e}")
1259
+ raise e
1184
1260
 
1185
1261
  # -- Eval methods --
1186
1262
 
@@ -1203,7 +1279,7 @@ class FirestoreDb(BaseDb):
1203
1279
 
1204
1280
  except Exception as e:
1205
1281
  log_error(f"Error creating eval run: {e}")
1206
- return None
1282
+ raise e
1207
1283
 
1208
1284
  def delete_eval_run(self, eval_run_id: str) -> None:
1209
1285
  """Delete an eval run from the database."""
@@ -1223,7 +1299,7 @@ class FirestoreDb(BaseDb):
1223
1299
 
1224
1300
  except Exception as e:
1225
1301
  log_error(f"Error deleting eval run {eval_run_id}: {e}")
1226
- raise
1302
+ raise e
1227
1303
 
1228
1304
  def delete_eval_runs(self, eval_run_ids: List[str]) -> None:
1229
1305
  """Delete multiple eval runs from the database.
@@ -1254,7 +1330,7 @@ class FirestoreDb(BaseDb):
1254
1330
 
1255
1331
  except Exception as e:
1256
1332
  log_error(f"Error deleting eval runs {eval_run_ids}: {e}")
1257
- raise
1333
+ raise e
1258
1334
 
1259
1335
  def get_eval_run(
1260
1336
  self, eval_run_id: str, deserialize: Optional[bool] = True
@@ -1292,7 +1368,7 @@ class FirestoreDb(BaseDb):
1292
1368
 
1293
1369
  except Exception as e:
1294
1370
  log_error(f"Exception getting eval run {eval_run_id}: {e}")
1295
- return None
1371
+ raise e
1296
1372
 
1297
1373
  def get_eval_runs(
1298
1374
  self,
@@ -1393,7 +1469,7 @@ class FirestoreDb(BaseDb):
1393
1469
 
1394
1470
  except Exception as e:
1395
1471
  log_error(f"Exception getting eval runs: {e}")
1396
- return [] if deserialize else ([], 0)
1472
+ raise e
1397
1473
 
1398
1474
  def rename_eval_run(
1399
1475
  self, eval_run_id: str, name: str, deserialize: Optional[bool] = True
@@ -1439,4 +1515,4 @@ class FirestoreDb(BaseDb):
1439
1515
 
1440
1516
  except Exception as e:
1441
1517
  log_error(f"Error updating eval run name {eval_run_id}: {e}")
1442
- raise
1518
+ raise e