agno 2.0.1__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 (314) hide show
  1. agno/agent/agent.py +6015 -2823
  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 +594 -186
  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 +2 -8
  105. agno/knowledge/types.py +9 -0
  106. agno/knowledge/utils.py +20 -0
  107. agno/media.py +72 -0
  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 +999 -519
  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 +103 -31
  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 +139 -0
  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 +59 -5
  142. agno/models/openai/chat.py +69 -29
  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 +77 -1
  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 -178
  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 +248 -94
  205. agno/run/base.py +44 -5
  206. agno/run/team.py +238 -97
  207. agno/run/workflow.py +144 -33
  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 -1610
  213. agno/tools/dalle.py +2 -4
  214. agno/tools/decorator.py +4 -2
  215. agno/tools/duckduckgo.py +15 -11
  216. agno/tools/e2b.py +14 -7
  217. agno/tools/eleven_labs.py +23 -25
  218. agno/tools/exa.py +21 -16
  219. agno/tools/file.py +153 -23
  220. agno/tools/file_generation.py +350 -0
  221. agno/tools/firecrawl.py +4 -4
  222. agno/tools/function.py +250 -30
  223. agno/tools/gmail.py +238 -14
  224. agno/tools/google_drive.py +270 -0
  225. agno/tools/googlecalendar.py +36 -8
  226. agno/tools/googlesheets.py +20 -5
  227. agno/tools/jira.py +20 -0
  228. agno/tools/knowledge.py +3 -3
  229. agno/tools/mcp/__init__.py +10 -0
  230. agno/tools/mcp/mcp.py +331 -0
  231. agno/tools/mcp/multi_mcp.py +347 -0
  232. agno/tools/mcp/params.py +24 -0
  233. agno/tools/mcp_toolbox.py +284 -0
  234. agno/tools/mem0.py +11 -17
  235. agno/tools/memori.py +1 -53
  236. agno/tools/memory.py +419 -0
  237. agno/tools/models/nebius.py +5 -5
  238. agno/tools/models_labs.py +20 -10
  239. agno/tools/notion.py +204 -0
  240. agno/tools/parallel.py +314 -0
  241. agno/tools/scrapegraph.py +58 -31
  242. agno/tools/searxng.py +2 -2
  243. agno/tools/serper.py +2 -2
  244. agno/tools/slack.py +18 -3
  245. agno/tools/spider.py +2 -2
  246. agno/tools/tavily.py +146 -0
  247. agno/tools/whatsapp.py +1 -1
  248. agno/tools/workflow.py +278 -0
  249. agno/tools/yfinance.py +12 -11
  250. agno/utils/agent.py +820 -0
  251. agno/utils/audio.py +27 -0
  252. agno/utils/common.py +90 -1
  253. agno/utils/events.py +217 -2
  254. agno/utils/gemini.py +180 -22
  255. agno/utils/hooks.py +57 -0
  256. agno/utils/http.py +111 -0
  257. agno/utils/knowledge.py +12 -5
  258. agno/utils/log.py +1 -0
  259. agno/utils/mcp.py +92 -2
  260. agno/utils/media.py +188 -10
  261. agno/utils/merge_dict.py +22 -1
  262. agno/utils/message.py +60 -0
  263. agno/utils/models/claude.py +40 -11
  264. agno/utils/print_response/agent.py +105 -21
  265. agno/utils/print_response/team.py +103 -38
  266. agno/utils/print_response/workflow.py +251 -34
  267. agno/utils/reasoning.py +22 -1
  268. agno/utils/serialize.py +32 -0
  269. agno/utils/streamlit.py +16 -10
  270. agno/utils/string.py +41 -0
  271. agno/utils/team.py +98 -9
  272. agno/utils/tools.py +1 -1
  273. agno/vectordb/base.py +23 -4
  274. agno/vectordb/cassandra/cassandra.py +65 -9
  275. agno/vectordb/chroma/chromadb.py +182 -38
  276. agno/vectordb/clickhouse/clickhousedb.py +64 -11
  277. agno/vectordb/couchbase/couchbase.py +105 -10
  278. agno/vectordb/lancedb/lance_db.py +124 -133
  279. agno/vectordb/langchaindb/langchaindb.py +25 -7
  280. agno/vectordb/lightrag/lightrag.py +17 -3
  281. agno/vectordb/llamaindex/__init__.py +3 -0
  282. agno/vectordb/llamaindex/llamaindexdb.py +46 -7
  283. agno/vectordb/milvus/milvus.py +126 -9
  284. agno/vectordb/mongodb/__init__.py +7 -1
  285. agno/vectordb/mongodb/mongodb.py +112 -7
  286. agno/vectordb/pgvector/pgvector.py +142 -21
  287. agno/vectordb/pineconedb/pineconedb.py +80 -8
  288. agno/vectordb/qdrant/qdrant.py +125 -39
  289. agno/vectordb/redis/__init__.py +9 -0
  290. agno/vectordb/redis/redisdb.py +694 -0
  291. agno/vectordb/singlestore/singlestore.py +111 -25
  292. agno/vectordb/surrealdb/surrealdb.py +31 -5
  293. agno/vectordb/upstashdb/upstashdb.py +76 -8
  294. agno/vectordb/weaviate/weaviate.py +86 -15
  295. agno/workflow/__init__.py +2 -0
  296. agno/workflow/agent.py +299 -0
  297. agno/workflow/condition.py +112 -18
  298. agno/workflow/loop.py +69 -10
  299. agno/workflow/parallel.py +266 -118
  300. agno/workflow/router.py +110 -17
  301. agno/workflow/step.py +638 -129
  302. agno/workflow/steps.py +65 -6
  303. agno/workflow/types.py +61 -23
  304. agno/workflow/workflow.py +2085 -272
  305. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/METADATA +182 -58
  306. agno-2.3.0.dist-info/RECORD +577 -0
  307. agno/knowledge/reader/url_reader.py +0 -128
  308. agno/tools/googlesearch.py +0 -98
  309. agno/tools/mcp.py +0 -610
  310. agno/utils/models/aws_claude.py +0 -170
  311. agno-2.0.1.dist-info/RECORD +0 -515
  312. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
  313. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/licenses/LICENSE +0 -0
  314. {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
agno/tools/mem0.py CHANGED
@@ -2,7 +2,6 @@ import json
2
2
  from os import getenv
3
3
  from typing import Any, Dict, List, Optional, Union
4
4
 
5
- from agno.agent import Agent
6
5
  from agno.tools import Toolkit
7
6
  from agno.utils.log import log_debug, log_error, log_warning
8
7
 
@@ -69,15 +68,13 @@ class Mem0Tools(Toolkit):
69
68
  def _get_user_id(
70
69
  self,
71
70
  method_name: str,
72
- agent: Optional[Agent] = None,
71
+ session_state: Dict[str, Any],
73
72
  ) -> str:
74
73
  """Resolve the user ID"""
75
74
  resolved_user_id = self.user_id
76
- if not resolved_user_id and agent is not None:
75
+ if not resolved_user_id:
77
76
  try:
78
- session_state = getattr(agent, "session_state", None)
79
- if isinstance(session_state, dict):
80
- resolved_user_id = session_state.get("current_user_id")
77
+ resolved_user_id = session_state.get("current_user_id")
81
78
  except Exception:
82
79
  pass
83
80
  if not resolved_user_id:
@@ -88,7 +85,7 @@ class Mem0Tools(Toolkit):
88
85
 
89
86
  def add_memory(
90
87
  self,
91
- agent: Agent,
88
+ session_state,
92
89
  content: Union[str, Dict[str, str]],
93
90
  ) -> str:
94
91
  """Add facts to the user's memory.
@@ -101,7 +98,7 @@ class Mem0Tools(Toolkit):
101
98
  str: JSON-encoded Mem0 response or an error message.
102
99
  """
103
100
 
104
- resolved_user_id = self._get_user_id("add_memory", agent=agent)
101
+ resolved_user_id = self._get_user_id("add_memory", session_state=session_state)
105
102
  if isinstance(resolved_user_id, str) and resolved_user_id.startswith("Error in add_memory:"):
106
103
  return resolved_user_id
107
104
  try:
@@ -116,7 +113,6 @@ class Mem0Tools(Toolkit):
116
113
  messages_list,
117
114
  user_id=resolved_user_id,
118
115
  infer=self.infer,
119
- output_format="v1.1",
120
116
  )
121
117
  return json.dumps(result)
122
118
  except Exception as e:
@@ -125,19 +121,18 @@ class Mem0Tools(Toolkit):
125
121
 
126
122
  def search_memory(
127
123
  self,
128
- agent: Agent,
124
+ session_state: Dict[str, Any],
129
125
  query: str,
130
126
  ) -> str:
131
127
  """Semantic search for *query* across the user's stored memories."""
132
128
 
133
- resolved_user_id = self._get_user_id("search_memory", agent=agent)
129
+ resolved_user_id = self._get_user_id("search_memory", session_state=session_state)
134
130
  if isinstance(resolved_user_id, str) and resolved_user_id.startswith("Error in search_memory:"):
135
131
  return resolved_user_id
136
132
  try:
137
133
  results = self.client.search(
138
134
  query=query,
139
135
  user_id=resolved_user_id,
140
- output_format="v1.1",
141
136
  )
142
137
 
143
138
  if isinstance(results, dict) and "results" in results:
@@ -156,16 +151,15 @@ class Mem0Tools(Toolkit):
156
151
  log_error(f"Error searching memory: {e}")
157
152
  return f"Error searching memory: {e}"
158
153
 
159
- def get_all_memories(self, agent: Agent) -> str:
154
+ def get_all_memories(self, session_state: Dict[str, Any]) -> str:
160
155
  """Return **all** memories for the current user as a JSON string."""
161
156
 
162
- resolved_user_id = self._get_user_id("get_all_memories", agent=agent)
157
+ resolved_user_id = self._get_user_id("get_all_memories", session_state=session_state)
163
158
  if isinstance(resolved_user_id, str) and resolved_user_id.startswith("Error in get_all_memories:"):
164
159
  return resolved_user_id
165
160
  try:
166
161
  results = self.client.get_all(
167
162
  user_id=resolved_user_id,
168
- output_format="v1.1",
169
163
  )
170
164
 
171
165
  if isinstance(results, dict) and "results" in results:
@@ -183,10 +177,10 @@ class Mem0Tools(Toolkit):
183
177
  log_error(f"Error getting all memories: {e}")
184
178
  return f"Error getting all memories: {e}"
185
179
 
186
- def delete_all_memories(self, agent: Agent) -> str:
180
+ def delete_all_memories(self, session_state: Dict[str, Any]) -> str:
187
181
  """Delete *all* memories associated with the current user"""
188
182
 
189
- resolved_user_id = self._get_user_id("delete_all_memories", agent=agent)
183
+ resolved_user_id = self._get_user_id("delete_all_memories", session_state=session_state)
190
184
  if isinstance(resolved_user_id, str) and resolved_user_id.startswith("Error in delete_all_memories:"):
191
185
  error_msg = resolved_user_id
192
186
  log_error(error_msg)
agno/tools/memori.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import json
2
2
  from typing import Any, Dict, List, Optional
3
3
 
4
- from agno.agent import Agent
5
4
  from agno.tools.toolkit import Toolkit
6
5
  from agno.utils.log import log_debug, log_error, log_info, log_warning
7
6
 
@@ -122,7 +121,6 @@ class MemoriTools(Toolkit):
122
121
 
123
122
  def search_memory(
124
123
  self,
125
- agent: Agent,
126
124
  query: str,
127
125
  limit: Optional[int] = None,
128
126
  ) -> str:
@@ -180,7 +178,7 @@ class MemoriTools(Toolkit):
180
178
  log_error(f"Error searching memory: {e}")
181
179
  return json.dumps({"success": False, "error": f"Memory search error: {str(e)}"})
182
180
 
183
- def record_conversation(self, agent: Agent, content: str) -> str:
181
+ def record_conversation(self, content: str) -> str:
184
182
  """
185
183
  Add important information or facts to memory.
186
184
 
@@ -222,7 +220,6 @@ class MemoriTools(Toolkit):
222
220
 
223
221
  def get_memory_stats(
224
222
  self,
225
- agent: Agent,
226
223
  ) -> str:
227
224
  """
228
225
  Get statistics about the memory system.
@@ -340,52 +337,3 @@ class MemoriTools(Toolkit):
340
337
  except Exception as e:
341
338
  log_error(f"Failed to disable memory system: {e}")
342
339
  return False
343
-
344
-
345
- def create_memori_search_tool(memori_toolkit: MemoriTools):
346
- """
347
- Create a standalone memory search function for use with Agno agents.
348
-
349
- This is a convenience function that creates a memory search tool similar
350
- to the pattern shown in the Memori example code.
351
-
352
- Args:
353
- memori_toolkit: An initialized MemoriTools instance
354
-
355
- Returns:
356
- Callable: A memory search function that can be used as an agent tool
357
-
358
- Example:
359
- ```python
360
- memori_tools = MemoriTools(database_connect="sqlite:///memory.db")
361
- search_tool = create_memori_search_tool(memori_tools)
362
-
363
- agent = Agent(
364
- model=OpenAIChat(),
365
- tools=[search_tool],
366
- description="Agent with memory search capability"
367
- )
368
- ```
369
- """
370
-
371
- def search_memory(query: str) -> str:
372
- """
373
- Search the agent's memory for past conversations and information.
374
-
375
- Args:
376
- query: What to search for in memory
377
-
378
- Returns:
379
- str: Search results or error message
380
- """
381
- try:
382
- if not query.strip():
383
- return "Please provide a search query"
384
-
385
- result = memori_toolkit._memory_tool.execute(query=query.strip())
386
- return str(result) if result else "No relevant memories found"
387
-
388
- except Exception as e:
389
- return f"Memory search error: {str(e)}"
390
-
391
- return search_memory
agno/tools/memory.py ADDED
@@ -0,0 +1,419 @@
1
+ import json
2
+ from textwrap import dedent
3
+ from typing import Any, Dict, List, Optional
4
+ from uuid import uuid4
5
+
6
+ from agno.db.base import BaseDb
7
+ from agno.db.schemas import UserMemory
8
+ from agno.tools import Toolkit
9
+ from agno.utils.log import log_debug, log_error
10
+
11
+
12
+ class MemoryTools(Toolkit):
13
+ def __init__(
14
+ self,
15
+ db: BaseDb,
16
+ enable_get_memories: bool = True,
17
+ enable_add_memory: bool = True,
18
+ enable_update_memory: bool = True,
19
+ enable_delete_memory: bool = True,
20
+ enable_analyze: bool = True,
21
+ enable_think: bool = True,
22
+ instructions: Optional[str] = None,
23
+ add_instructions: bool = True,
24
+ add_few_shot: bool = True,
25
+ few_shot_examples: Optional[str] = None,
26
+ all: bool = False,
27
+ **kwargs,
28
+ ):
29
+ # Add instructions for using this toolkit
30
+ if instructions is None:
31
+ self.instructions = self.DEFAULT_INSTRUCTIONS
32
+ if add_few_shot:
33
+ if few_shot_examples is not None:
34
+ self.instructions += "\n" + few_shot_examples
35
+ else:
36
+ self.instructions += "\n" + self.FEW_SHOT_EXAMPLES
37
+ else:
38
+ self.instructions = instructions
39
+
40
+ # The database to use for memory operations
41
+ self.db: BaseDb = db
42
+
43
+ tools: List[Any] = []
44
+ if enable_think or all:
45
+ tools.append(self.think)
46
+ if enable_get_memories or all:
47
+ tools.append(self.get_memories)
48
+ if enable_add_memory or all:
49
+ tools.append(self.add_memory)
50
+ if enable_update_memory or all:
51
+ tools.append(self.update_memory)
52
+ if enable_delete_memory or all:
53
+ tools.append(self.delete_memory)
54
+ if enable_analyze or all:
55
+ tools.append(self.analyze)
56
+
57
+ super().__init__(
58
+ name="memory_tools",
59
+ instructions=self.instructions,
60
+ add_instructions=add_instructions,
61
+ tools=tools,
62
+ **kwargs,
63
+ )
64
+
65
+ def think(self, session_state: Dict[str, Any], thought: str) -> str:
66
+ """Use this tool as a scratchpad to reason about memory operations, refine your approach, brainstorm memory content, or revise your plan.
67
+
68
+ Call `Think` whenever you need to figure out what to do next, analyze the user's requirements, plan memory operations, or decide on execution strategy.
69
+ You should use this tool as frequently as needed.
70
+
71
+ Args:
72
+ thought: Your thought process and reasoning about memory operations.
73
+ """
74
+ try:
75
+ log_debug(f"Memory Thought: {thought}")
76
+
77
+ # Add the thought to the session state
78
+ if session_state is None:
79
+ session_state = {}
80
+ if "memory_thoughts" not in session_state:
81
+ session_state["memory_thoughts"] = []
82
+ session_state["memory_thoughts"].append(thought)
83
+
84
+ # Return the full log of thoughts and the new thought
85
+ thoughts = "\n".join([f"- {t}" for t in session_state["memory_thoughts"]])
86
+ formatted_thoughts = dedent(
87
+ f"""Memory Thoughts:
88
+ {thoughts}
89
+ """
90
+ ).strip()
91
+ return formatted_thoughts
92
+ except Exception as e:
93
+ log_error(f"Error recording memory thought: {e}")
94
+ return f"Error recording memory thought: {e}"
95
+
96
+ def get_memories(self, session_state: Dict[str, Any]) -> str:
97
+ """
98
+ Use this tool to get a list of memories for the current user from the database.
99
+ """
100
+ try:
101
+ # Get user info from session state
102
+ user_id = session_state.get("current_user_id") if session_state else None
103
+
104
+ memories = self.db.get_user_memories(user_id=user_id)
105
+
106
+ # Store the result in session state for analysis
107
+ if session_state is None:
108
+ session_state = {}
109
+ if "memory_operations" not in session_state:
110
+ session_state["memory_operations"] = []
111
+
112
+ operation_result = {
113
+ "operation": "get_memories",
114
+ "success": True,
115
+ "memories": [memory.to_dict() for memory in memories], # type: ignore
116
+ "error": None,
117
+ }
118
+ session_state["memory_operations"].append(operation_result)
119
+
120
+ return json.dumps([memory.to_dict() for memory in memories], indent=2) # type: ignore
121
+ except Exception as e:
122
+ log_error(f"Error getting memories: {e}")
123
+ return json.dumps({"error": str(e)}, indent=2)
124
+
125
+ def add_memory(
126
+ self,
127
+ session_state: Dict[str, Any],
128
+ memory: str,
129
+ topics: Optional[List[str]] = None,
130
+ ) -> str:
131
+ """Use this tool to add a new memory to the database.
132
+
133
+ Args:
134
+ memory: The memory content to store
135
+ topics: Optional list of topics associated with this memory
136
+
137
+ Returns:
138
+ str: JSON string containing the created memory information
139
+ """
140
+ try:
141
+ log_debug(f"Adding memory: {memory}")
142
+
143
+ # Get user and agent info from session state
144
+ user_id = session_state.get("current_user_id") if session_state else None
145
+
146
+ # Create UserMemory object
147
+ user_memory = UserMemory(
148
+ memory_id=str(uuid4()),
149
+ memory=memory,
150
+ topics=topics,
151
+ user_id=user_id,
152
+ )
153
+
154
+ # Add to database
155
+ created_memory = self.db.upsert_user_memory(user_memory)
156
+
157
+ # Store the result in session state for analysis
158
+ if session_state is None:
159
+ session_state = {}
160
+ if "memory_operations" not in session_state:
161
+ session_state["memory_operations"] = []
162
+
163
+ memory_dict = created_memory.to_dict() if created_memory else None # type: ignore
164
+
165
+ operation_result = {
166
+ "operation": "add_memory",
167
+ "success": created_memory is not None,
168
+ "memory": memory_dict,
169
+ "error": None,
170
+ }
171
+ session_state["memory_operations"].append(operation_result)
172
+
173
+ if created_memory:
174
+ return json.dumps({"success": True, "operation": "add_memory", "memory": memory_dict}, indent=2)
175
+ else:
176
+ return json.dumps(
177
+ {"success": False, "operation": "add_memory", "error": "Failed to create memory"}, indent=2
178
+ )
179
+
180
+ except Exception as e:
181
+ log_error(f"Error adding memory: {e}")
182
+ return json.dumps({"success": False, "operation": "add_memory", "error": str(e)}, indent=2)
183
+
184
+ def update_memory(
185
+ self,
186
+ session_state: Dict[str, Any],
187
+ memory_id: str,
188
+ memory: Optional[str] = None,
189
+ topics: Optional[List[str]] = None,
190
+ ) -> str:
191
+ """Use this tool to update an existing memory in the database.
192
+
193
+ Args:
194
+ memory_id: The ID of the memory to update
195
+ memory: Updated memory content (if provided)
196
+ topics: Updated list of topics (if provided)
197
+
198
+ Returns:
199
+ str: JSON string containing the updated memory information
200
+ """
201
+ try:
202
+ log_debug(f"Updating memory: {memory_id}")
203
+
204
+ # First get the existing memory
205
+ existing_memory = self.db.get_user_memory(memory_id)
206
+ if not existing_memory:
207
+ return json.dumps(
208
+ {"success": False, "operation": "update_memory", "error": f"Memory with ID {memory_id} not found"},
209
+ indent=2,
210
+ )
211
+
212
+ # Update fields if provided
213
+ updated_memory = UserMemory(
214
+ memory=memory if memory is not None else existing_memory.memory, # type: ignore
215
+ memory_id=memory_id,
216
+ topics=topics if topics is not None else existing_memory.topics, # type: ignore
217
+ user_id=existing_memory.user_id, # type: ignore
218
+ )
219
+
220
+ # Update in database
221
+ updated_result = self.db.upsert_user_memory(updated_memory)
222
+
223
+ # Store the result in session state for analysis
224
+ if session_state is None:
225
+ session_state = {}
226
+ if "memory_operations" not in session_state:
227
+ session_state["memory_operations"] = []
228
+
229
+ memory_dict = updated_result.to_dict() if updated_result else None # type: ignore
230
+
231
+ operation_result = {
232
+ "operation": "update_memory",
233
+ "success": updated_result is not None,
234
+ "memory": memory_dict,
235
+ "error": None,
236
+ }
237
+ session_state["memory_operations"].append(operation_result)
238
+
239
+ if updated_result:
240
+ return json.dumps({"success": True, "operation": "update_memory", "memory": memory_dict}, indent=2)
241
+ else:
242
+ return json.dumps(
243
+ {"success": False, "operation": "update_memory", "error": "Failed to update memory"}, indent=2
244
+ )
245
+
246
+ except Exception as e:
247
+ log_error(f"Error updating memory: {e}")
248
+ return json.dumps({"success": False, "operation": "update_memory", "error": str(e)}, indent=2)
249
+
250
+ def delete_memory(
251
+ self,
252
+ session_state: Dict[str, Any],
253
+ memory_id: str,
254
+ ) -> str:
255
+ """Use this tool to delete a memory from the database.
256
+
257
+ Args:
258
+ memory_id: The ID of the memory to delete
259
+
260
+ Returns:
261
+ str: JSON string containing the deletion result
262
+ """
263
+ try:
264
+ log_debug(f"Deleting memory: {memory_id}")
265
+
266
+ # Check if memory exists before deletion
267
+ existing_memory = self.db.get_user_memory(memory_id)
268
+ if not existing_memory:
269
+ return json.dumps(
270
+ {"success": False, "operation": "delete_memory", "error": f"Memory with ID {memory_id} not found"},
271
+ indent=2,
272
+ )
273
+
274
+ # Delete from database
275
+ self.db.delete_user_memory(memory_id)
276
+
277
+ # Store the result in session state for analysis
278
+ if session_state is None:
279
+ session_state = {}
280
+ if "memory_operations" not in session_state:
281
+ session_state["memory_operations"] = []
282
+
283
+ memory_dict = existing_memory.to_dict() if existing_memory else None # type: ignore
284
+
285
+ operation_result = {
286
+ "operation": "delete_memory",
287
+ "success": True,
288
+ "memory_id": memory_id,
289
+ "deleted_memory": memory_dict,
290
+ "error": None,
291
+ }
292
+ session_state["memory_operations"].append(operation_result)
293
+
294
+ return json.dumps(
295
+ {
296
+ "success": True,
297
+ "operation": "delete_memory",
298
+ "memory_id": memory_id,
299
+ "deleted_memory": memory_dict,
300
+ },
301
+ indent=2,
302
+ )
303
+
304
+ except Exception as e:
305
+ log_error(f"Error deleting memory: {e}")
306
+ return json.dumps({"success": False, "operation": "delete_memory", "error": str(e)}, indent=2)
307
+
308
+ def analyze(self, session_state: Dict[str, Any], analysis: str) -> str:
309
+ """Use this tool to evaluate whether the memory operations results are correct and sufficient.
310
+ If not, go back to "Think" or use memory operations with refined parameters.
311
+
312
+ Args:
313
+ analysis: Your analysis of the memory operations results.
314
+ """
315
+ try:
316
+ log_debug(f"Memory Analysis: {analysis}")
317
+
318
+ # Add the analysis to the session state
319
+ if session_state is None:
320
+ session_state = {}
321
+ if "memory_analysis" not in session_state:
322
+ session_state["memory_analysis"] = []
323
+ session_state["memory_analysis"].append(analysis)
324
+
325
+ # Return the full log of analysis and the new analysis
326
+ analysis_log = "\n".join([f"- {a}" for a in session_state["memory_analysis"]])
327
+ formatted_analysis = dedent(
328
+ f"""Memory Analysis:
329
+ {analysis_log}
330
+ """
331
+ ).strip()
332
+ return formatted_analysis
333
+ except Exception as e:
334
+ log_error(f"Error recording memory analysis: {e}")
335
+ return f"Error recording memory analysis: {e}"
336
+
337
+ DEFAULT_INSTRUCTIONS = dedent("""\
338
+ You have access to the Think, Add Memory, Update Memory, Delete Memory, and Analyze tools that will help you manage user memories and analyze their operations. Use these tools as frequently as needed to successfully complete memory management tasks.
339
+
340
+ ## How to use the Think, Memory Operations, and Analyze tools:
341
+
342
+ 1. **Think**
343
+ - Purpose: A scratchpad for planning memory operations, brainstorming memory content, and refining your approach. You never reveal your "Think" content to the user.
344
+ - Usage: Call `think` whenever you need to figure out what memory operations to perform, analyze requirements, or decide on strategy.
345
+
346
+ 2. **Get Memories**
347
+ - Purpose: Retrieves a list of memories from the database for the current user.
348
+ - Usage: Call `get_memories` when you need to retrieve memories for the current user.
349
+
350
+ 3. **Add Memory**
351
+ - Purpose: Creates new memories in the database with specified content and metadata.
352
+ - Usage: Call `add_memory` with memory content and optional topics when you need to store new information.
353
+
354
+ 4. **Update Memory**
355
+ - Purpose: Modifies existing memories in the database by memory ID.
356
+ - Usage: Call `update_memory` with a memory ID and the fields you want to change. Only specify the fields that need updating.
357
+
358
+ 5. **Delete Memory**
359
+ - Purpose: Removes memories from the database by memory ID.
360
+ - Usage: Call `delete_memory` with a memory ID when a memory is no longer needed or requested to be removed.
361
+
362
+ 6. **Analyze**
363
+ - Purpose: Evaluate whether the memory operations results are correct and sufficient. If not, go back to "Think" or use memory operations with refined parameters.
364
+ - Usage: Call `analyze` after performing memory operations to verify:
365
+ - Success: Did the operation complete successfully?
366
+ - Accuracy: Is the memory content correct and well-formed?
367
+ - Completeness: Are all required fields populated appropriately?
368
+ - Errors: Were there any failures or unexpected behaviors?
369
+
370
+ **Important Guidelines**:
371
+ - Do not include your internal chain-of-thought in direct user responses.
372
+ - Use "Think" to reason internally. These notes are never exposed to the user.
373
+ - When you provide a final answer to the user, be clear, concise, and based on the memory operation results.
374
+ - If memory operations fail or produce unexpected results, acknowledge limitations and explain what went wrong.
375
+ - Always verify memory IDs exist before attempting updates or deletions.
376
+ - Use descriptive topics and clear memory content to make memories easily searchable and understandable.\
377
+ """)
378
+
379
+ FEW_SHOT_EXAMPLES = dedent("""\
380
+ You can refer to the examples below as guidance for how to use each tool.
381
+
382
+ ### Examples
383
+
384
+ #### Example 1: Adding User Preferences
385
+
386
+ User: I prefer vegetarian recipes and I'm allergic to nuts.
387
+ Think: I should store the user's dietary preferences. I should create a memory with this information and use relevant topics for easy retrieval.
388
+ Add Memory: memory="User prefers vegetarian recipes and is allergic to nuts", topics=["dietary_preferences", "allergies", "food"]
389
+ Analyze: Successfully created memory with dietary preferences. The topics are well-chosen for future retrieval. This should help with future food-related requests.
390
+
391
+ Final Answer: Noted. I've stored your dietary preferences. I'll remember that you prefer vegetarian recipes and have a nut allergy for future reference.
392
+
393
+ #### Example 2: Updating Existing Information
394
+
395
+ User: Actually, update my dietary info - I'm now eating fish too, so I'm pescatarian.
396
+ Think: The user wants to update their previous dietary preference from vegetarian to pescatarian. I need to find their existing dietary memory and update it.
397
+ Update Memory: memory_id="previous_memory_id", memory="User follows pescatarian diet (vegetarian + fish) and is allergic to nuts", topics=["dietary_preferences", "allergies", "food", "pescatarian"]
398
+ Analyze: Successfully updated the dietary preference memory. The content now accurately reflects pescatarian diet and maintains the nut allergy information.
399
+
400
+ Final Answer: I've updated your dietary preferences to reflect that you follow a pescatarian diet (vegetarian plus fish) while maintaining your nut allergy information.
401
+
402
+ #### Example 3: Removing Outdated Information
403
+
404
+ User: Please forget about my old work schedule - it's completely changed.
405
+ Think: The user wants me to delete their old work schedule memory since it's no longer relevant. I should find and remove that memory.
406
+ Delete Memory: memory_id="work_schedule_memory_id"
407
+ Analyze: Successfully deleted the outdated work schedule memory. The old information won't interfere with future scheduling requests.
408
+
409
+ Final Answer: I've removed your old work schedule information. Feel free to share your new schedule when you're ready, and I'll store the updated information.
410
+
411
+ #### Example 4: Retrieving Memories
412
+
413
+ User: What have you remembered about me?
414
+ Think: The user wants to retrieve memories about themselves. I should use the get_memories tool to retrieve the memories.
415
+ Get Memories:
416
+ Analyze: Successfully retrieved the memories about the user. The memories are relevant to the user's preferences and activities.
417
+
418
+ Final Answer: I've retrieved the memories about you. You like to hike in the mountains on weekends and travel to new places and experience different cultures. You are planning to travel to Africa in December.\
419
+ """)
@@ -12,12 +12,12 @@ from agno.utils.log import log_error, log_warning
12
12
 
13
13
 
14
14
  class NebiusTools(Toolkit):
15
- """Tools for interacting with Nebius AI Studio's text-to-image API"""
15
+ """Tools for interacting with Nebius Token Factory's text-to-image API"""
16
16
 
17
17
  def __init__(
18
18
  self,
19
19
  api_key: Optional[str] = None,
20
- base_url: str = "https://api.studio.nebius.com/v1",
20
+ base_url: str = "https://api.tokenfactory.nebius.com/v1",
21
21
  image_model: str = "black-forest-labs/flux-schnell",
22
22
  image_quality: Optional[str] = "standard",
23
23
  image_size: Optional[str] = "1024x1024",
@@ -26,11 +26,11 @@ class NebiusTools(Toolkit):
26
26
  all: bool = False,
27
27
  **kwargs,
28
28
  ):
29
- """Initialize Nebius AI Studio text-to-image tools.
29
+ """Initialize Nebius Token Factory text-to-image tools.
30
30
 
31
31
  Args:
32
32
  api_key: Nebius API key. If not provided, will look for NEBIUS_API_KEY environment variable.
33
- base_url: The base URL for the Nebius AI Studio API. This should be configured according to Nebius's documentation.
33
+ base_url: The base URL for the Nebius Token Factory API. This should be configured according to Nebius's documentation.
34
34
  image_model: The model to use for generation. Options include:
35
35
  - "black-forest-labs/flux-schnell" (fastest)
36
36
  - "black-forest-labs/flux-dev" (balanced)
@@ -69,7 +69,7 @@ class NebiusTools(Toolkit):
69
69
  agent: Agent,
70
70
  prompt: str,
71
71
  ) -> ToolResult:
72
- """Generate images based on a text prompt using Nebius AI Studio.
72
+ """Generate images based on a text prompt using Nebius Token Factory.
73
73
 
74
74
  Args:
75
75
  agent: The agent instance for adding images