agno 2.0.0rc2__py3-none-any.whl → 2.3.0__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 (331) hide show
  1. agno/agent/agent.py +6009 -2874
  2. agno/api/api.py +2 -0
  3. agno/api/os.py +1 -1
  4. agno/culture/__init__.py +3 -0
  5. agno/culture/manager.py +956 -0
  6. agno/db/async_postgres/__init__.py +3 -0
  7. agno/db/base.py +385 -6
  8. agno/db/dynamo/dynamo.py +388 -81
  9. agno/db/dynamo/schemas.py +47 -10
  10. agno/db/dynamo/utils.py +63 -4
  11. agno/db/firestore/firestore.py +435 -64
  12. agno/db/firestore/schemas.py +11 -0
  13. agno/db/firestore/utils.py +102 -4
  14. agno/db/gcs_json/gcs_json_db.py +384 -42
  15. agno/db/gcs_json/utils.py +60 -26
  16. agno/db/in_memory/in_memory_db.py +351 -66
  17. agno/db/in_memory/utils.py +60 -2
  18. agno/db/json/json_db.py +339 -48
  19. agno/db/json/utils.py +60 -26
  20. agno/db/migrations/manager.py +199 -0
  21. agno/db/migrations/v1_to_v2.py +510 -37
  22. agno/db/migrations/versions/__init__.py +0 -0
  23. agno/db/migrations/versions/v2_3_0.py +938 -0
  24. agno/db/mongo/__init__.py +15 -1
  25. agno/db/mongo/async_mongo.py +2036 -0
  26. agno/db/mongo/mongo.py +653 -76
  27. agno/db/mongo/schemas.py +13 -0
  28. agno/db/mongo/utils.py +80 -8
  29. agno/db/mysql/mysql.py +687 -25
  30. agno/db/mysql/schemas.py +61 -37
  31. agno/db/mysql/utils.py +60 -2
  32. agno/db/postgres/__init__.py +2 -1
  33. agno/db/postgres/async_postgres.py +2001 -0
  34. agno/db/postgres/postgres.py +676 -57
  35. agno/db/postgres/schemas.py +43 -18
  36. agno/db/postgres/utils.py +164 -2
  37. agno/db/redis/redis.py +344 -38
  38. agno/db/redis/schemas.py +18 -0
  39. agno/db/redis/utils.py +60 -2
  40. agno/db/schemas/__init__.py +2 -1
  41. agno/db/schemas/culture.py +120 -0
  42. agno/db/schemas/memory.py +13 -0
  43. agno/db/singlestore/schemas.py +26 -1
  44. agno/db/singlestore/singlestore.py +687 -53
  45. agno/db/singlestore/utils.py +60 -2
  46. agno/db/sqlite/__init__.py +2 -1
  47. agno/db/sqlite/async_sqlite.py +2371 -0
  48. agno/db/sqlite/schemas.py +24 -0
  49. agno/db/sqlite/sqlite.py +774 -85
  50. agno/db/sqlite/utils.py +168 -5
  51. agno/db/surrealdb/__init__.py +3 -0
  52. agno/db/surrealdb/metrics.py +292 -0
  53. agno/db/surrealdb/models.py +309 -0
  54. agno/db/surrealdb/queries.py +71 -0
  55. agno/db/surrealdb/surrealdb.py +1361 -0
  56. agno/db/surrealdb/utils.py +147 -0
  57. agno/db/utils.py +50 -22
  58. agno/eval/accuracy.py +50 -43
  59. agno/eval/performance.py +6 -3
  60. agno/eval/reliability.py +6 -3
  61. agno/eval/utils.py +33 -16
  62. agno/exceptions.py +68 -1
  63. agno/filters.py +354 -0
  64. agno/guardrails/__init__.py +6 -0
  65. agno/guardrails/base.py +19 -0
  66. agno/guardrails/openai.py +144 -0
  67. agno/guardrails/pii.py +94 -0
  68. agno/guardrails/prompt_injection.py +52 -0
  69. agno/integrations/discord/client.py +1 -0
  70. agno/knowledge/chunking/agentic.py +13 -10
  71. agno/knowledge/chunking/fixed.py +1 -1
  72. agno/knowledge/chunking/semantic.py +40 -8
  73. agno/knowledge/chunking/strategy.py +59 -15
  74. agno/knowledge/embedder/aws_bedrock.py +9 -4
  75. agno/knowledge/embedder/azure_openai.py +54 -0
  76. agno/knowledge/embedder/base.py +2 -0
  77. agno/knowledge/embedder/cohere.py +184 -5
  78. agno/knowledge/embedder/fastembed.py +1 -1
  79. agno/knowledge/embedder/google.py +79 -1
  80. agno/knowledge/embedder/huggingface.py +9 -4
  81. agno/knowledge/embedder/jina.py +63 -0
  82. agno/knowledge/embedder/mistral.py +78 -11
  83. agno/knowledge/embedder/nebius.py +1 -1
  84. agno/knowledge/embedder/ollama.py +13 -0
  85. agno/knowledge/embedder/openai.py +37 -65
  86. agno/knowledge/embedder/sentence_transformer.py +8 -4
  87. agno/knowledge/embedder/vllm.py +262 -0
  88. agno/knowledge/embedder/voyageai.py +69 -16
  89. agno/knowledge/knowledge.py +595 -187
  90. agno/knowledge/reader/base.py +9 -2
  91. agno/knowledge/reader/csv_reader.py +8 -10
  92. agno/knowledge/reader/docx_reader.py +5 -6
  93. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  94. agno/knowledge/reader/json_reader.py +6 -5
  95. agno/knowledge/reader/markdown_reader.py +13 -13
  96. agno/knowledge/reader/pdf_reader.py +43 -68
  97. agno/knowledge/reader/pptx_reader.py +101 -0
  98. agno/knowledge/reader/reader_factory.py +51 -6
  99. agno/knowledge/reader/s3_reader.py +3 -15
  100. agno/knowledge/reader/tavily_reader.py +194 -0
  101. agno/knowledge/reader/text_reader.py +13 -13
  102. agno/knowledge/reader/web_search_reader.py +2 -43
  103. agno/knowledge/reader/website_reader.py +43 -25
  104. agno/knowledge/reranker/__init__.py +3 -0
  105. agno/knowledge/types.py +9 -0
  106. agno/knowledge/utils.py +20 -0
  107. agno/media.py +339 -266
  108. agno/memory/manager.py +336 -82
  109. agno/models/aimlapi/aimlapi.py +2 -2
  110. agno/models/anthropic/claude.py +183 -37
  111. agno/models/aws/bedrock.py +52 -112
  112. agno/models/aws/claude.py +33 -1
  113. agno/models/azure/ai_foundry.py +33 -15
  114. agno/models/azure/openai_chat.py +25 -8
  115. agno/models/base.py +1011 -566
  116. agno/models/cerebras/cerebras.py +19 -13
  117. agno/models/cerebras/cerebras_openai.py +8 -5
  118. agno/models/cohere/chat.py +27 -1
  119. agno/models/cometapi/__init__.py +5 -0
  120. agno/models/cometapi/cometapi.py +57 -0
  121. agno/models/dashscope/dashscope.py +1 -0
  122. agno/models/deepinfra/deepinfra.py +2 -2
  123. agno/models/deepseek/deepseek.py +2 -2
  124. agno/models/fireworks/fireworks.py +2 -2
  125. agno/models/google/gemini.py +110 -37
  126. agno/models/groq/groq.py +28 -11
  127. agno/models/huggingface/huggingface.py +2 -1
  128. agno/models/internlm/internlm.py +2 -2
  129. agno/models/langdb/langdb.py +4 -4
  130. agno/models/litellm/chat.py +18 -1
  131. agno/models/litellm/litellm_openai.py +2 -2
  132. agno/models/llama_cpp/__init__.py +5 -0
  133. agno/models/llama_cpp/llama_cpp.py +22 -0
  134. agno/models/message.py +143 -4
  135. agno/models/meta/llama.py +27 -10
  136. agno/models/meta/llama_openai.py +5 -17
  137. agno/models/nebius/nebius.py +6 -6
  138. agno/models/nexus/__init__.py +3 -0
  139. agno/models/nexus/nexus.py +22 -0
  140. agno/models/nvidia/nvidia.py +2 -2
  141. agno/models/ollama/chat.py +60 -6
  142. agno/models/openai/chat.py +102 -43
  143. agno/models/openai/responses.py +103 -106
  144. agno/models/openrouter/openrouter.py +41 -3
  145. agno/models/perplexity/perplexity.py +4 -5
  146. agno/models/portkey/portkey.py +3 -3
  147. agno/models/requesty/__init__.py +5 -0
  148. agno/models/requesty/requesty.py +52 -0
  149. agno/models/response.py +81 -5
  150. agno/models/sambanova/sambanova.py +2 -2
  151. agno/models/siliconflow/__init__.py +5 -0
  152. agno/models/siliconflow/siliconflow.py +25 -0
  153. agno/models/together/together.py +2 -2
  154. agno/models/utils.py +254 -8
  155. agno/models/vercel/v0.py +2 -2
  156. agno/models/vertexai/__init__.py +0 -0
  157. agno/models/vertexai/claude.py +96 -0
  158. agno/models/vllm/vllm.py +1 -0
  159. agno/models/xai/xai.py +3 -2
  160. agno/os/app.py +543 -175
  161. agno/os/auth.py +24 -14
  162. agno/os/config.py +1 -0
  163. agno/os/interfaces/__init__.py +1 -0
  164. agno/os/interfaces/a2a/__init__.py +3 -0
  165. agno/os/interfaces/a2a/a2a.py +42 -0
  166. agno/os/interfaces/a2a/router.py +250 -0
  167. agno/os/interfaces/a2a/utils.py +924 -0
  168. agno/os/interfaces/agui/agui.py +23 -7
  169. agno/os/interfaces/agui/router.py +27 -3
  170. agno/os/interfaces/agui/utils.py +242 -142
  171. agno/os/interfaces/base.py +6 -2
  172. agno/os/interfaces/slack/router.py +81 -23
  173. agno/os/interfaces/slack/slack.py +29 -14
  174. agno/os/interfaces/whatsapp/router.py +11 -4
  175. agno/os/interfaces/whatsapp/whatsapp.py +14 -7
  176. agno/os/mcp.py +111 -54
  177. agno/os/middleware/__init__.py +7 -0
  178. agno/os/middleware/jwt.py +233 -0
  179. agno/os/router.py +556 -139
  180. agno/os/routers/evals/evals.py +71 -34
  181. agno/os/routers/evals/schemas.py +31 -31
  182. agno/os/routers/evals/utils.py +6 -5
  183. agno/os/routers/health.py +31 -0
  184. agno/os/routers/home.py +52 -0
  185. agno/os/routers/knowledge/knowledge.py +185 -38
  186. agno/os/routers/knowledge/schemas.py +82 -22
  187. agno/os/routers/memory/memory.py +158 -53
  188. agno/os/routers/memory/schemas.py +20 -16
  189. agno/os/routers/metrics/metrics.py +20 -8
  190. agno/os/routers/metrics/schemas.py +16 -16
  191. agno/os/routers/session/session.py +499 -38
  192. agno/os/schema.py +308 -198
  193. agno/os/utils.py +401 -41
  194. agno/reasoning/anthropic.py +80 -0
  195. agno/reasoning/azure_ai_foundry.py +2 -2
  196. agno/reasoning/deepseek.py +2 -2
  197. agno/reasoning/default.py +3 -1
  198. agno/reasoning/gemini.py +73 -0
  199. agno/reasoning/groq.py +2 -2
  200. agno/reasoning/ollama.py +2 -2
  201. agno/reasoning/openai.py +7 -2
  202. agno/reasoning/vertexai.py +76 -0
  203. agno/run/__init__.py +6 -0
  204. agno/run/agent.py +266 -112
  205. agno/run/base.py +53 -24
  206. agno/run/team.py +252 -111
  207. agno/run/workflow.py +156 -45
  208. agno/session/agent.py +105 -89
  209. agno/session/summary.py +65 -25
  210. agno/session/team.py +176 -96
  211. agno/session/workflow.py +406 -40
  212. agno/team/team.py +3854 -1692
  213. agno/tools/brightdata.py +3 -3
  214. agno/tools/cartesia.py +3 -5
  215. agno/tools/dalle.py +9 -8
  216. agno/tools/decorator.py +4 -2
  217. agno/tools/desi_vocal.py +2 -2
  218. agno/tools/duckduckgo.py +15 -11
  219. agno/tools/e2b.py +20 -13
  220. agno/tools/eleven_labs.py +26 -28
  221. agno/tools/exa.py +21 -16
  222. agno/tools/fal.py +4 -4
  223. agno/tools/file.py +153 -23
  224. agno/tools/file_generation.py +350 -0
  225. agno/tools/firecrawl.py +4 -4
  226. agno/tools/function.py +257 -37
  227. agno/tools/giphy.py +2 -2
  228. agno/tools/gmail.py +238 -14
  229. agno/tools/google_drive.py +270 -0
  230. agno/tools/googlecalendar.py +36 -8
  231. agno/tools/googlesheets.py +20 -5
  232. agno/tools/jira.py +20 -0
  233. agno/tools/knowledge.py +3 -3
  234. agno/tools/lumalab.py +3 -3
  235. agno/tools/mcp/__init__.py +10 -0
  236. agno/tools/mcp/mcp.py +331 -0
  237. agno/tools/mcp/multi_mcp.py +347 -0
  238. agno/tools/mcp/params.py +24 -0
  239. agno/tools/mcp_toolbox.py +284 -0
  240. agno/tools/mem0.py +11 -17
  241. agno/tools/memori.py +1 -53
  242. agno/tools/memory.py +419 -0
  243. agno/tools/models/azure_openai.py +2 -2
  244. agno/tools/models/gemini.py +3 -3
  245. agno/tools/models/groq.py +3 -5
  246. agno/tools/models/nebius.py +7 -7
  247. agno/tools/models_labs.py +25 -15
  248. agno/tools/notion.py +204 -0
  249. agno/tools/openai.py +4 -9
  250. agno/tools/opencv.py +3 -3
  251. agno/tools/parallel.py +314 -0
  252. agno/tools/replicate.py +7 -7
  253. agno/tools/scrapegraph.py +58 -31
  254. agno/tools/searxng.py +2 -2
  255. agno/tools/serper.py +2 -2
  256. agno/tools/slack.py +18 -3
  257. agno/tools/spider.py +2 -2
  258. agno/tools/tavily.py +146 -0
  259. agno/tools/whatsapp.py +1 -1
  260. agno/tools/workflow.py +278 -0
  261. agno/tools/yfinance.py +12 -11
  262. agno/utils/agent.py +820 -0
  263. agno/utils/audio.py +27 -0
  264. agno/utils/common.py +90 -1
  265. agno/utils/events.py +222 -7
  266. agno/utils/gemini.py +181 -23
  267. agno/utils/hooks.py +57 -0
  268. agno/utils/http.py +111 -0
  269. agno/utils/knowledge.py +12 -5
  270. agno/utils/log.py +1 -0
  271. agno/utils/mcp.py +95 -5
  272. agno/utils/media.py +188 -10
  273. agno/utils/merge_dict.py +22 -1
  274. agno/utils/message.py +60 -0
  275. agno/utils/models/claude.py +40 -11
  276. agno/utils/models/cohere.py +1 -1
  277. agno/utils/models/watsonx.py +1 -1
  278. agno/utils/openai.py +1 -1
  279. agno/utils/print_response/agent.py +105 -21
  280. agno/utils/print_response/team.py +103 -38
  281. agno/utils/print_response/workflow.py +251 -34
  282. agno/utils/reasoning.py +22 -1
  283. agno/utils/serialize.py +32 -0
  284. agno/utils/streamlit.py +16 -10
  285. agno/utils/string.py +41 -0
  286. agno/utils/team.py +98 -9
  287. agno/utils/tools.py +1 -1
  288. agno/vectordb/base.py +23 -4
  289. agno/vectordb/cassandra/cassandra.py +65 -9
  290. agno/vectordb/chroma/chromadb.py +182 -38
  291. agno/vectordb/clickhouse/clickhousedb.py +64 -11
  292. agno/vectordb/couchbase/couchbase.py +105 -10
  293. agno/vectordb/lancedb/lance_db.py +183 -135
  294. agno/vectordb/langchaindb/langchaindb.py +25 -7
  295. agno/vectordb/lightrag/lightrag.py +17 -3
  296. agno/vectordb/llamaindex/__init__.py +3 -0
  297. agno/vectordb/llamaindex/llamaindexdb.py +46 -7
  298. agno/vectordb/milvus/milvus.py +126 -9
  299. agno/vectordb/mongodb/__init__.py +7 -1
  300. agno/vectordb/mongodb/mongodb.py +112 -7
  301. agno/vectordb/pgvector/pgvector.py +142 -21
  302. agno/vectordb/pineconedb/pineconedb.py +80 -8
  303. agno/vectordb/qdrant/qdrant.py +125 -39
  304. agno/vectordb/redis/__init__.py +9 -0
  305. agno/vectordb/redis/redisdb.py +694 -0
  306. agno/vectordb/singlestore/singlestore.py +111 -25
  307. agno/vectordb/surrealdb/surrealdb.py +31 -5
  308. agno/vectordb/upstashdb/upstashdb.py +76 -8
  309. agno/vectordb/weaviate/weaviate.py +86 -15
  310. agno/workflow/__init__.py +2 -0
  311. agno/workflow/agent.py +299 -0
  312. agno/workflow/condition.py +112 -18
  313. agno/workflow/loop.py +69 -10
  314. agno/workflow/parallel.py +266 -118
  315. agno/workflow/router.py +110 -17
  316. agno/workflow/step.py +645 -136
  317. agno/workflow/steps.py +65 -6
  318. agno/workflow/types.py +71 -33
  319. agno/workflow/workflow.py +2113 -300
  320. agno-2.3.0.dist-info/METADATA +618 -0
  321. agno-2.3.0.dist-info/RECORD +577 -0
  322. agno-2.3.0.dist-info/licenses/LICENSE +201 -0
  323. agno/knowledge/reader/url_reader.py +0 -128
  324. agno/tools/googlesearch.py +0 -98
  325. agno/tools/mcp.py +0 -610
  326. agno/utils/models/aws_claude.py +0 -170
  327. agno-2.0.0rc2.dist-info/METADATA +0 -355
  328. agno-2.0.0rc2.dist-info/RECORD +0 -515
  329. agno-2.0.0rc2.dist-info/licenses/LICENSE +0 -375
  330. {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
  331. {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
agno/memory/manager.py CHANGED
@@ -7,12 +7,19 @@ from typing import Any, Callable, Dict, List, Literal, Optional, Type, Union
7
7
 
8
8
  from pydantic import BaseModel, Field
9
9
 
10
- from agno.db.base import BaseDb
10
+ from agno.db.base import AsyncBaseDb, BaseDb
11
11
  from agno.db.schemas import UserMemory
12
12
  from agno.models.base import Model
13
13
  from agno.models.message import Message
14
+ from agno.models.utils import get_model
14
15
  from agno.tools.function import Function
15
- from agno.utils.log import log_debug, log_error, log_warning, set_log_level_to_debug, set_log_level_to_info
16
+ from agno.utils.log import (
17
+ log_debug,
18
+ log_error,
19
+ log_warning,
20
+ set_log_level_to_debug,
21
+ set_log_level_to_info,
22
+ )
16
23
  from agno.utils.prompts import get_json_output_prompt
17
24
  from agno.utils.string import parse_response_model_str
18
25
 
@@ -21,7 +28,8 @@ class MemorySearchResponse(BaseModel):
21
28
  """Model for Memory Search Response."""
22
29
 
23
30
  memory_ids: List[str] = Field(
24
- ..., description="The IDs of the memories that are most semantically similar to the query."
31
+ ...,
32
+ description="The IDs of the memories that are most semantically similar to the query.",
25
33
  )
26
34
 
27
35
 
@@ -32,11 +40,11 @@ class MemoryManager:
32
40
  # Model used for memory management
33
41
  model: Optional[Model] = None
34
42
 
35
- # Provide the system message for the manager as a string. If not provided, a default prompt will be used.
43
+ # Provide the system message for the manager as a string. If not provided, the default system message will be used.
36
44
  system_message: Optional[str] = None
37
- # Provide the memory capture instructions for the manager as a string. If not provided, a default prompt will be used.
45
+ # Provide the memory capture instructions for the manager as a string. If not provided, the default memory capture instructions will be used.
38
46
  memory_capture_instructions: Optional[str] = None
39
- # Additional instructions for the manager
47
+ # Additional instructions for the manager. These instructions are appended to the default system message.
40
48
  additional_instructions: Optional[str] = None
41
49
 
42
50
  # Whether memories were created in the last run
@@ -53,26 +61,24 @@ class MemoryManager:
53
61
  add_memories: bool = True
54
62
 
55
63
  # The database to store memories
56
- db: Optional[BaseDb] = None
64
+ db: Optional[Union[BaseDb, AsyncBaseDb]] = None
57
65
 
58
66
  debug_mode: bool = False
59
67
 
60
68
  def __init__(
61
69
  self,
62
- model: Optional[Model] = None,
70
+ model: Optional[Union[Model, str]] = None,
63
71
  system_message: Optional[str] = None,
64
72
  memory_capture_instructions: Optional[str] = None,
65
73
  additional_instructions: Optional[str] = None,
66
- db: Optional[BaseDb] = None,
67
- delete_memories: bool = True,
74
+ db: Optional[Union[BaseDb, AsyncBaseDb]] = None,
75
+ delete_memories: bool = False,
68
76
  update_memories: bool = True,
69
77
  add_memories: bool = True,
70
- clear_memories: bool = True,
78
+ clear_memories: bool = False,
71
79
  debug_mode: bool = False,
72
80
  ):
73
- self.model = model
74
- if self.model is not None and isinstance(self.model, str):
75
- raise ValueError("Model must be a Model object, not a string")
81
+ self.model = model # type: ignore[assignment]
76
82
  self.system_message = system_message
77
83
  self.memory_capture_instructions = memory_capture_instructions
78
84
  self.additional_instructions = additional_instructions
@@ -82,8 +88,12 @@ class MemoryManager:
82
88
  self.add_memories = add_memories
83
89
  self.clear_memories = clear_memories
84
90
  self.debug_mode = debug_mode
85
- self._tools_for_model: Optional[List[Dict[str, Any]]] = None
86
- self._functions_for_model: Optional[Dict[str, Function]] = None
91
+
92
+ self._get_models()
93
+
94
+ def _get_models(self) -> None:
95
+ if self.model is not None:
96
+ self.model = get_model(self.model)
87
97
 
88
98
  def get_model(self) -> Model:
89
99
  if self.model is None:
@@ -114,6 +124,28 @@ class MemoryManager:
114
124
  return memories
115
125
  return None
116
126
 
127
+ async def aread_from_db(self, user_id: Optional[str] = None):
128
+ if self.db:
129
+ if isinstance(self.db, AsyncBaseDb):
130
+ # If no user_id is provided, read all memories
131
+ if user_id is None:
132
+ all_memories: List[UserMemory] = await self.db.get_user_memories() # type: ignore
133
+ else:
134
+ all_memories = await self.db.get_user_memories(user_id=user_id) # type: ignore
135
+ else:
136
+ if user_id is None:
137
+ all_memories = self.db.get_user_memories() # type: ignore
138
+ else:
139
+ all_memories = self.db.get_user_memories(user_id=user_id) # type: ignore
140
+
141
+ memories: Dict[str, List[UserMemory]] = {}
142
+ for memory in all_memories:
143
+ if memory.user_id is not None and memory.memory_id is not None:
144
+ memories.setdefault(memory.user_id, []).append(memory)
145
+
146
+ return memories
147
+ return None
148
+
117
149
  def set_log_level(self):
118
150
  if self.debug_mode or getenv("AGNO_DEBUG", "false").lower() == "true":
119
151
  self.debug_mode = True
@@ -139,6 +171,20 @@ class MemoryManager:
139
171
  log_warning("Memory Db not provided.")
140
172
  return []
141
173
 
174
+ async def aget_user_memories(self, user_id: Optional[str] = None) -> Optional[List[UserMemory]]:
175
+ """Get the user memories for a given user id"""
176
+ if self.db:
177
+ if user_id is None:
178
+ user_id = "default"
179
+ # Refresh from the Db
180
+ memories = await self.aread_from_db(user_id=user_id)
181
+ if memories is None:
182
+ return []
183
+ return memories.get(user_id, [])
184
+ else:
185
+ log_warning("Memory Db not provided.")
186
+ return []
187
+
142
188
  def get_user_memory(self, memory_id: str, user_id: Optional[str] = None) -> Optional[UserMemory]:
143
189
  """Get the user memory for a given user id"""
144
190
  if self.db:
@@ -236,8 +282,11 @@ class MemoryManager:
236
282
  memory_id (str): The id of the memory to delete
237
283
  user_id (Optional[str]): The user id to delete the memory from. If not provided, the memory is deleted from the "default" user.
238
284
  """
285
+ if user_id is None:
286
+ user_id = "default"
287
+
239
288
  if self.db:
240
- self._delete_db_memory(memory_id=memory_id)
289
+ self._delete_db_memory(memory_id=memory_id, user_id=user_id)
241
290
  else:
242
291
  log_warning("Memory DB not provided.")
243
292
  return None
@@ -258,6 +307,11 @@ class MemoryManager:
258
307
  log_warning("MemoryDb not provided.")
259
308
  return "Please provide a db to store memories"
260
309
 
310
+ if isinstance(self.db, AsyncBaseDb):
311
+ raise ValueError(
312
+ "create_user_memories() is not supported with an async DB. Please use acreate_user_memories() instead."
313
+ )
314
+
261
315
  if not messages and not message:
262
316
  raise ValueError("You must provide either a message or a list of messages")
263
317
 
@@ -318,7 +372,10 @@ class MemoryManager:
318
372
  if user_id is None:
319
373
  user_id = "default"
320
374
 
321
- memories = self.read_from_db(user_id=user_id)
375
+ if isinstance(self.db, AsyncBaseDb):
376
+ memories = await self.aread_from_db(user_id=user_id)
377
+ else:
378
+ memories = self.read_from_db(user_id=user_id)
322
379
  if memories is None:
323
380
  memories = {}
324
381
 
@@ -337,7 +394,10 @@ class MemoryManager:
337
394
  )
338
395
 
339
396
  # We refresh from the DB
340
- self.read_from_db(user_id=user_id)
397
+ if isinstance(self.db, AsyncBaseDb):
398
+ memories = await self.aread_from_db(user_id=user_id)
399
+ else:
400
+ memories = self.read_from_db(user_id=user_id)
341
401
 
342
402
  return response
343
403
 
@@ -348,6 +408,11 @@ class MemoryManager:
348
408
  log_warning("MemoryDb not provided.")
349
409
  return "Please provide a db to store memories"
350
410
 
411
+ if not isinstance(self.db, BaseDb):
412
+ raise ValueError(
413
+ "update_memory_task() is not supported with an async DB. Please use aupdate_memory_task() instead."
414
+ )
415
+
351
416
  if user_id is None:
352
417
  user_id = "default"
353
418
 
@@ -385,7 +450,11 @@ class MemoryManager:
385
450
  if user_id is None:
386
451
  user_id = "default"
387
452
 
388
- memories = self.read_from_db(user_id=user_id)
453
+ if isinstance(self.db, AsyncBaseDb):
454
+ memories = await self.aread_from_db(user_id=user_id)
455
+ else:
456
+ memories = self.read_from_db(user_id=user_id)
457
+
389
458
  if memories is None:
390
459
  memories = {}
391
460
 
@@ -404,7 +473,10 @@ class MemoryManager:
404
473
  )
405
474
 
406
475
  # We refresh from the DB
407
- self.read_from_db(user_id=user_id)
476
+ if isinstance(self.db, AsyncBaseDb):
477
+ await self.aread_from_db(user_id=user_id)
478
+ else:
479
+ self.read_from_db(user_id=user_id)
408
480
 
409
481
  return response
410
482
 
@@ -420,12 +492,16 @@ class MemoryManager:
420
492
  log_warning(f"Error storing memory in db: {e}")
421
493
  return f"Error adding memory: {e}"
422
494
 
423
- def _delete_db_memory(self, memory_id: str) -> str:
495
+ def _delete_db_memory(self, memory_id: str, user_id: Optional[str] = None) -> str:
424
496
  """Use this function to delete a memory from the database."""
425
497
  try:
426
498
  if not self.db:
427
499
  raise ValueError("Memory db not initialized")
428
- self.db.delete_user_memory(memory_id=memory_id)
500
+
501
+ if user_id is None:
502
+ user_id = "default"
503
+
504
+ self.db.delete_user_memory(memory_id=memory_id, user_id=user_id)
429
505
  return "Memory deleted successfully"
430
506
  except Exception as e:
431
507
  log_warning(f"Error deleting memory in db: {e}")
@@ -637,23 +713,26 @@ class MemoryManager:
637
713
  return sorted_memories_list
638
714
 
639
715
  # --Memory Manager Functions--
640
- def determine_tools_for_model(self, tools: List[Callable]) -> None:
716
+ def determine_tools_for_model(self, tools: List[Callable]) -> List[Union[Function, dict]]:
641
717
  # Have to reset each time, because of different user IDs
642
- self._tools_for_model = []
643
- self._functions_for_model = {}
718
+ _function_names = []
719
+ _functions: List[Union[Function, dict]] = []
644
720
 
645
721
  for tool in tools:
646
722
  try:
647
723
  function_name = tool.__name__
648
- if function_name not in self._functions_for_model:
649
- func = Function.from_callable(tool, strict=True) # type: ignore
650
- func.strict = True
651
- self._functions_for_model[func.name] = func
652
- self._tools_for_model.append({"type": "function", "function": func.to_dict()})
653
- log_debug(f"Added function {func.name}")
724
+ if function_name in _function_names:
725
+ continue
726
+ _function_names.append(function_name)
727
+ func = Function.from_callable(tool, strict=True) # type: ignore
728
+ func.strict = True
729
+ _functions.append(func)
730
+ log_debug(f"Added function {func.name}")
654
731
  except Exception as e:
655
732
  log_warning(f"Could not add function {tool}: {e}")
656
733
 
734
+ return _functions
735
+
657
736
  def get_system_message(
658
737
  self,
659
738
  existing_memories: Optional[List[Dict[str, Any]]] = None,
@@ -665,18 +744,20 @@ class MemoryManager:
665
744
  if self.system_message is not None:
666
745
  return Message(role="system", content=self.system_message)
667
746
 
668
- memory_capture_instructions = self.memory_capture_instructions or dedent("""\
669
- Memories should include details that could personalize ongoing interactions with the user, such as:
670
- - Personal facts: name, age, occupation, location, interests, preferences, etc.
671
- - Significant life events or experiences shared by the user
672
- - Important context about the user's current situation, challenges or goals
673
- - What the user likes or dislikes, their opinions, beliefs, values, etc.
674
- - Any other details that provide valuable insights into the user's personality, perspective or needs\
675
- """)
747
+ memory_capture_instructions = self.memory_capture_instructions or dedent(
748
+ """\
749
+ Memories should capture personal information about the user that is relevant to the current conversation, such as:
750
+ - Personal facts: name, age, occupation, location, interests, and preferences
751
+ - Opinions and preferences: what the user likes, dislikes, enjoys, or finds frustrating
752
+ - Significant life events or experiences shared by the user
753
+ - Important context about the user's current situation, challenges, or goals
754
+ - Any other details that offer meaningful insight into the user's personality, perspective, or needs
755
+ """
756
+ )
676
757
 
677
758
  # -*- Return a system message for the memory manager
678
759
  system_prompt_lines = [
679
- "You are a MemoryConnector that is responsible for manging key information about the user. "
760
+ "You are a Memory Manager that is responsible for managing information and preferences about the user. "
680
761
  "You will be provided with a criteria for memories to capture in the <memories_to_capture> section and a list of existing memories in the <existing_memories> section.",
681
762
  "",
682
763
  "## When to add or update memories",
@@ -705,16 +786,16 @@ class MemoryManager:
705
786
  "",
706
787
  "## Updating memories",
707
788
  "You will also be provided with a list of existing memories in the <existing_memories> section. You can:",
708
- " 1. Decide to make no changes.",
789
+ " - Decide to make no changes.",
709
790
  ]
710
791
  if enable_add_memory:
711
- system_prompt_lines.append(" 2. Decide to add a new memory, using the `add_memory` tool.")
792
+ system_prompt_lines.append(" - Decide to add a new memory, using the `add_memory` tool.")
712
793
  if enable_update_memory:
713
- system_prompt_lines.append(" 3. Decide to update an existing memory, using the `update_memory` tool.")
794
+ system_prompt_lines.append(" - Decide to update an existing memory, using the `update_memory` tool.")
714
795
  if enable_delete_memory:
715
- system_prompt_lines.append(" 4. Decide to delete an existing memory, using the `delete_memory` tool.")
796
+ system_prompt_lines.append(" - Decide to delete an existing memory, using the `delete_memory` tool.")
716
797
  if enable_clear_memory:
717
- system_prompt_lines.append(" 5. Decide to clear all memories, using the `clear_memory` tool.")
798
+ system_prompt_lines.append(" - Decide to clear all memories, using the `clear_memory` tool.")
718
799
 
719
800
  system_prompt_lines += [
720
801
  "You can call multiple tools in a single response if needed. ",
@@ -758,7 +839,7 @@ class MemoryManager:
758
839
 
759
840
  model_copy = deepcopy(self.model)
760
841
  # Update the Model (set defaults, add logit etc.)
761
- self.determine_tools_for_model(
842
+ _tools = self.determine_tools_for_model(
762
843
  self._get_db_tools(
763
844
  user_id,
764
845
  db,
@@ -767,7 +848,7 @@ class MemoryManager:
767
848
  team_id=team_id,
768
849
  enable_add_memory=add_memories,
769
850
  enable_update_memory=update_memories,
770
- enable_delete_memory=False,
851
+ enable_delete_memory=True,
771
852
  enable_clear_memory=False,
772
853
  ),
773
854
  )
@@ -778,7 +859,7 @@ class MemoryManager:
778
859
  existing_memories=existing_memories,
779
860
  enable_update_memory=update_memories,
780
861
  enable_add_memory=add_memories,
781
- enable_delete_memory=False,
862
+ enable_delete_memory=True,
782
863
  enable_clear_memory=False,
783
864
  ),
784
865
  *messages,
@@ -786,7 +867,8 @@ class MemoryManager:
786
867
 
787
868
  # Generate a response from the Model (includes running function calls)
788
869
  response = model_copy.response(
789
- messages=messages_for_model, tools=self._tools_for_model, functions=self._functions_for_model
870
+ messages=messages_for_model,
871
+ tools=_tools,
790
872
  )
791
873
 
792
874
  if response.tool_calls is not None and len(response.tool_calls) > 0:
@@ -800,7 +882,7 @@ class MemoryManager:
800
882
  messages: List[Message],
801
883
  existing_memories: List[Dict[str, Any]],
802
884
  user_id: str,
803
- db: BaseDb,
885
+ db: Union[BaseDb, AsyncBaseDb],
804
886
  agent_id: Optional[str] = None,
805
887
  team_id: Optional[str] = None,
806
888
  update_memories: bool = True,
@@ -819,19 +901,34 @@ class MemoryManager:
819
901
 
820
902
  model_copy = deepcopy(self.model)
821
903
  # Update the Model (set defaults, add logit etc.)
822
- self.determine_tools_for_model(
823
- self._get_db_tools(
824
- user_id,
825
- db,
826
- input_string,
827
- agent_id=agent_id,
828
- team_id=team_id,
829
- enable_add_memory=add_memories,
830
- enable_update_memory=update_memories,
831
- enable_delete_memory=False,
832
- enable_clear_memory=False,
833
- ),
834
- )
904
+ if isinstance(db, AsyncBaseDb):
905
+ _tools = self.determine_tools_for_model(
906
+ await self._aget_db_tools(
907
+ user_id,
908
+ db,
909
+ input_string,
910
+ agent_id=agent_id,
911
+ team_id=team_id,
912
+ enable_add_memory=add_memories,
913
+ enable_update_memory=update_memories,
914
+ enable_delete_memory=True,
915
+ enable_clear_memory=False,
916
+ ),
917
+ )
918
+ else:
919
+ _tools = self.determine_tools_for_model(
920
+ self._get_db_tools(
921
+ user_id,
922
+ db,
923
+ input_string,
924
+ agent_id=agent_id,
925
+ team_id=team_id,
926
+ enable_add_memory=add_memories,
927
+ enable_update_memory=update_memories,
928
+ enable_delete_memory=True,
929
+ enable_clear_memory=False,
930
+ ),
931
+ )
835
932
 
836
933
  # Prepare the List of messages to send to the Model
837
934
  messages_for_model: List[Message] = [
@@ -839,7 +936,7 @@ class MemoryManager:
839
936
  existing_memories=existing_memories,
840
937
  enable_update_memory=update_memories,
841
938
  enable_add_memory=add_memories,
842
- enable_delete_memory=False,
939
+ enable_delete_memory=True,
843
940
  enable_clear_memory=False,
844
941
  ),
845
942
  *messages,
@@ -847,7 +944,8 @@ class MemoryManager:
847
944
 
848
945
  # Generate a response from the Model (includes running function calls)
849
946
  response = await model_copy.aresponse(
850
- messages=messages_for_model, tools=self._tools_for_model, functions=self._functions_for_model
947
+ messages=messages_for_model,
948
+ tools=_tools,
851
949
  )
852
950
 
853
951
  if response.tool_calls is not None and len(response.tool_calls) > 0:
@@ -875,7 +973,7 @@ class MemoryManager:
875
973
 
876
974
  model_copy = deepcopy(self.model)
877
975
  # Update the Model (set defaults, add logit etc.)
878
- self.determine_tools_for_model(
976
+ _tools = self.determine_tools_for_model(
879
977
  self._get_db_tools(
880
978
  user_id,
881
979
  db,
@@ -902,7 +1000,8 @@ class MemoryManager:
902
1000
 
903
1001
  # Generate a response from the Model (includes running function calls)
904
1002
  response = model_copy.response(
905
- messages=messages_for_model, tools=self._tools_for_model, functions=self._functions_for_model
1003
+ messages=messages_for_model,
1004
+ tools=_tools,
906
1005
  )
907
1006
 
908
1007
  if response.tool_calls is not None and len(response.tool_calls) > 0:
@@ -916,7 +1015,7 @@ class MemoryManager:
916
1015
  task: str,
917
1016
  existing_memories: List[Dict[str, Any]],
918
1017
  user_id: str,
919
- db: BaseDb,
1018
+ db: Union[BaseDb, AsyncBaseDb],
920
1019
  delete_memories: bool = True,
921
1020
  clear_memories: bool = True,
922
1021
  update_memories: bool = True,
@@ -930,17 +1029,30 @@ class MemoryManager:
930
1029
 
931
1030
  model_copy = deepcopy(self.model)
932
1031
  # Update the Model (set defaults, add logit etc.)
933
- self.determine_tools_for_model(
934
- self._get_db_tools(
935
- user_id,
936
- db,
937
- task,
938
- enable_delete_memory=delete_memories,
939
- enable_clear_memory=clear_memories,
940
- enable_update_memory=update_memories,
941
- enable_add_memory=add_memories,
942
- ),
943
- )
1032
+ if isinstance(db, AsyncBaseDb):
1033
+ _tools = self.determine_tools_for_model(
1034
+ await self._aget_db_tools(
1035
+ user_id,
1036
+ db,
1037
+ task,
1038
+ enable_delete_memory=delete_memories,
1039
+ enable_clear_memory=clear_memories,
1040
+ enable_update_memory=update_memories,
1041
+ enable_add_memory=add_memories,
1042
+ ),
1043
+ )
1044
+ else:
1045
+ _tools = self.determine_tools_for_model(
1046
+ self._get_db_tools(
1047
+ user_id,
1048
+ db,
1049
+ task,
1050
+ enable_delete_memory=delete_memories,
1051
+ enable_clear_memory=clear_memories,
1052
+ enable_update_memory=update_memories,
1053
+ enable_add_memory=add_memories,
1054
+ ),
1055
+ )
944
1056
 
945
1057
  # Prepare the List of messages to send to the Model
946
1058
  messages_for_model: List[Message] = [
@@ -957,7 +1069,8 @@ class MemoryManager:
957
1069
 
958
1070
  # Generate a response from the Model (includes running function calls)
959
1071
  response = await model_copy.aresponse(
960
- messages=messages_for_model, tools=self._tools_for_model, functions=self._functions_for_model
1072
+ messages=messages_for_model,
1073
+ tools=_tools,
961
1074
  )
962
1075
 
963
1076
  if response.tool_calls is not None and len(response.tool_calls) > 0:
@@ -1021,12 +1134,16 @@ class MemoryManager:
1021
1134
  """
1022
1135
  from agno.db.base import UserMemory
1023
1136
 
1137
+ if memory == "":
1138
+ return "Can't update memory with empty string. Use the delete memory function if available."
1139
+
1024
1140
  try:
1025
1141
  db.upsert_user_memory(
1026
1142
  UserMemory(
1027
1143
  memory_id=memory_id,
1028
1144
  memory=memory,
1029
1145
  topics=topics,
1146
+ user_id=user_id,
1030
1147
  input=input_string,
1031
1148
  )
1032
1149
  )
@@ -1044,7 +1161,7 @@ class MemoryManager:
1044
1161
  str: A message indicating if the memory was deleted successfully or not.
1045
1162
  """
1046
1163
  try:
1047
- db.delete_user_memory(memory_id=memory_id)
1164
+ db.delete_user_memory(memory_id=memory_id, user_id=user_id)
1048
1165
  log_debug("Memory deleted")
1049
1166
  return "Memory deleted successfully"
1050
1167
  except Exception as e:
@@ -1071,3 +1188,140 @@ class MemoryManager:
1071
1188
  if enable_clear_memory:
1072
1189
  functions.append(clear_memory)
1073
1190
  return functions
1191
+
1192
+ async def _aget_db_tools(
1193
+ self,
1194
+ user_id: str,
1195
+ db: Union[BaseDb, AsyncBaseDb],
1196
+ input_string: str,
1197
+ enable_add_memory: bool = True,
1198
+ enable_update_memory: bool = True,
1199
+ enable_delete_memory: bool = True,
1200
+ enable_clear_memory: bool = True,
1201
+ agent_id: Optional[str] = None,
1202
+ team_id: Optional[str] = None,
1203
+ ) -> List[Callable]:
1204
+ async def add_memory(memory: str, topics: Optional[List[str]] = None) -> str:
1205
+ """Use this function to add a memory to the database.
1206
+ Args:
1207
+ memory (str): The memory to be added.
1208
+ topics (Optional[List[str]]): The topics of the memory (e.g. ["name", "hobbies", "location"]).
1209
+ Returns:
1210
+ str: A message indicating if the memory was added successfully or not.
1211
+ """
1212
+ from uuid import uuid4
1213
+
1214
+ from agno.db.base import UserMemory
1215
+
1216
+ try:
1217
+ memory_id = str(uuid4())
1218
+ if isinstance(db, AsyncBaseDb):
1219
+ await db.upsert_user_memory(
1220
+ UserMemory(
1221
+ memory_id=memory_id,
1222
+ user_id=user_id,
1223
+ agent_id=agent_id,
1224
+ team_id=team_id,
1225
+ memory=memory,
1226
+ topics=topics,
1227
+ input=input_string,
1228
+ )
1229
+ )
1230
+ else:
1231
+ db.upsert_user_memory(
1232
+ UserMemory(
1233
+ memory_id=memory_id,
1234
+ user_id=user_id,
1235
+ agent_id=agent_id,
1236
+ team_id=team_id,
1237
+ memory=memory,
1238
+ topics=topics,
1239
+ input=input_string,
1240
+ )
1241
+ )
1242
+ log_debug(f"Memory added: {memory_id}")
1243
+ return "Memory added successfully"
1244
+ except Exception as e:
1245
+ log_warning(f"Error storing memory in db: {e}")
1246
+ return f"Error adding memory: {e}"
1247
+
1248
+ async def update_memory(memory_id: str, memory: str, topics: Optional[List[str]] = None) -> str:
1249
+ """Use this function to update an existing memory in the database.
1250
+ Args:
1251
+ memory_id (str): The id of the memory to be updated.
1252
+ memory (str): The updated memory.
1253
+ topics (Optional[List[str]]): The topics of the memory (e.g. ["name", "hobbies", "location"]).
1254
+ Returns:
1255
+ str: A message indicating if the memory was updated successfully or not.
1256
+ """
1257
+ from agno.db.base import UserMemory
1258
+
1259
+ if memory == "":
1260
+ return "Can't update memory with empty string. Use the delete memory function if available."
1261
+
1262
+ try:
1263
+ if isinstance(db, AsyncBaseDb):
1264
+ await db.upsert_user_memory(
1265
+ UserMemory(
1266
+ memory_id=memory_id,
1267
+ memory=memory,
1268
+ topics=topics,
1269
+ input=input_string,
1270
+ )
1271
+ )
1272
+ else:
1273
+ db.upsert_user_memory(
1274
+ UserMemory(
1275
+ memory_id=memory_id,
1276
+ memory=memory,
1277
+ topics=topics,
1278
+ input=input_string,
1279
+ )
1280
+ )
1281
+ log_debug("Memory updated")
1282
+ return "Memory updated successfully"
1283
+ except Exception as e:
1284
+ log_warning(f"Error storing memory in db: {e}")
1285
+ return f"Error adding memory: {e}"
1286
+
1287
+ async def delete_memory(memory_id: str) -> str:
1288
+ """Use this function to delete a single memory from the database.
1289
+ Args:
1290
+ memory_id (str): The id of the memory to be deleted.
1291
+ Returns:
1292
+ str: A message indicating if the memory was deleted successfully or not.
1293
+ """
1294
+ try:
1295
+ if isinstance(db, AsyncBaseDb):
1296
+ await db.delete_user_memory(memory_id=memory_id)
1297
+ else:
1298
+ db.delete_user_memory(memory_id=memory_id)
1299
+ log_debug("Memory deleted")
1300
+ return "Memory deleted successfully"
1301
+ except Exception as e:
1302
+ log_warning(f"Error deleting memory in db: {e}")
1303
+ return f"Error deleting memory: {e}"
1304
+
1305
+ async def clear_memory() -> str:
1306
+ """Use this function to remove all (or clear all) memories from the database.
1307
+
1308
+ Returns:
1309
+ str: A message indicating if the memory was cleared successfully or not.
1310
+ """
1311
+ if isinstance(db, AsyncBaseDb):
1312
+ await db.clear_memories()
1313
+ else:
1314
+ db.clear_memories()
1315
+ log_debug("Memory cleared")
1316
+ return "Memory cleared successfully"
1317
+
1318
+ functions: List[Callable] = []
1319
+ if enable_add_memory:
1320
+ functions.append(add_memory)
1321
+ if enable_update_memory:
1322
+ functions.append(update_memory)
1323
+ if enable_delete_memory:
1324
+ functions.append(delete_memory)
1325
+ if enable_clear_memory:
1326
+ functions.append(clear_memory)
1327
+ return functions