agno 1.8.1__py3-none-any.whl → 2.0.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 (590) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +3143 -4170
  4. agno/api/agent.py +11 -67
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +8 -19
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -41
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +5 -21
  11. agno/api/schemas/evals.py +7 -16
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +5 -21
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +11 -7
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +11 -66
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/db/__init__.py +24 -0
  25. agno/db/base.py +245 -0
  26. agno/db/dynamo/__init__.py +3 -0
  27. agno/db/dynamo/dynamo.py +1743 -0
  28. agno/db/dynamo/schemas.py +278 -0
  29. agno/db/dynamo/utils.py +684 -0
  30. agno/db/firestore/__init__.py +3 -0
  31. agno/db/firestore/firestore.py +1432 -0
  32. agno/db/firestore/schemas.py +130 -0
  33. agno/db/firestore/utils.py +278 -0
  34. agno/db/gcs_json/__init__.py +3 -0
  35. agno/db/gcs_json/gcs_json_db.py +1001 -0
  36. agno/db/gcs_json/utils.py +194 -0
  37. agno/db/in_memory/__init__.py +3 -0
  38. agno/db/in_memory/in_memory_db.py +882 -0
  39. agno/db/in_memory/utils.py +172 -0
  40. agno/db/json/__init__.py +3 -0
  41. agno/db/json/json_db.py +1045 -0
  42. agno/db/json/utils.py +196 -0
  43. agno/db/migrations/v1_to_v2.py +162 -0
  44. agno/db/mongo/__init__.py +3 -0
  45. agno/db/mongo/mongo.py +1416 -0
  46. agno/db/mongo/schemas.py +77 -0
  47. agno/db/mongo/utils.py +204 -0
  48. agno/db/mysql/__init__.py +3 -0
  49. agno/db/mysql/mysql.py +1719 -0
  50. agno/db/mysql/schemas.py +124 -0
  51. agno/db/mysql/utils.py +297 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1710 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +280 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1367 -0
  58. agno/db/redis/schemas.py +109 -0
  59. agno/db/redis/utils.py +288 -0
  60. agno/db/schemas/__init__.py +3 -0
  61. agno/db/schemas/evals.py +33 -0
  62. agno/db/schemas/knowledge.py +40 -0
  63. agno/db/schemas/memory.py +46 -0
  64. agno/db/singlestore/__init__.py +3 -0
  65. agno/db/singlestore/schemas.py +116 -0
  66. agno/db/singlestore/singlestore.py +1712 -0
  67. agno/db/singlestore/utils.py +326 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1676 -0
  71. agno/db/sqlite/utils.py +268 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +154 -48
  75. agno/eval/performance.py +88 -23
  76. agno/eval/reliability.py +73 -20
  77. agno/eval/utils.py +23 -13
  78. agno/integrations/discord/__init__.py +3 -0
  79. agno/{app → integrations}/discord/client.py +15 -11
  80. agno/knowledge/__init__.py +2 -2
  81. agno/{document → knowledge}/chunking/agentic.py +2 -2
  82. agno/{document → knowledge}/chunking/document.py +2 -2
  83. agno/{document → knowledge}/chunking/fixed.py +3 -3
  84. agno/{document → knowledge}/chunking/markdown.py +2 -2
  85. agno/{document → knowledge}/chunking/recursive.py +2 -2
  86. agno/{document → knowledge}/chunking/row.py +2 -2
  87. agno/knowledge/chunking/semantic.py +59 -0
  88. agno/knowledge/chunking/strategy.py +121 -0
  89. agno/knowledge/content.py +74 -0
  90. agno/knowledge/document/__init__.py +5 -0
  91. agno/{document → knowledge/document}/base.py +12 -2
  92. agno/knowledge/embedder/__init__.py +5 -0
  93. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  94. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  95. agno/{embedder → knowledge/embedder}/base.py +6 -0
  96. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  97. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  98. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  99. agno/{embedder → knowledge/embedder}/google.py +74 -1
  100. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  101. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  102. agno/knowledge/embedder/langdb.py +22 -0
  103. agno/knowledge/embedder/mistral.py +139 -0
  104. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  105. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  106. agno/knowledge/embedder/openai.py +223 -0
  107. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  108. agno/{embedder → knowledge/embedder}/together.py +1 -1
  109. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  110. agno/knowledge/knowledge.py +1551 -0
  111. agno/knowledge/reader/__init__.py +7 -0
  112. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  113. agno/knowledge/reader/base.py +88 -0
  114. agno/{document → knowledge}/reader/csv_reader.py +47 -65
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/{document → knowledge}/reader/json_reader.py +30 -9
  118. agno/{document → knowledge}/reader/markdown_reader.py +58 -9
  119. agno/{document → knowledge}/reader/pdf_reader.py +71 -126
  120. agno/knowledge/reader/reader_factory.py +268 -0
  121. agno/knowledge/reader/s3_reader.py +101 -0
  122. agno/{document → knowledge}/reader/text_reader.py +31 -10
  123. agno/knowledge/reader/url_reader.py +128 -0
  124. agno/knowledge/reader/web_search_reader.py +366 -0
  125. agno/{document → knowledge}/reader/website_reader.py +37 -10
  126. agno/knowledge/reader/wikipedia_reader.py +59 -0
  127. agno/knowledge/reader/youtube_reader.py +78 -0
  128. agno/knowledge/remote_content/remote_content.py +88 -0
  129. agno/{reranker → knowledge/reranker}/base.py +1 -1
  130. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  131. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  132. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  133. agno/knowledge/types.py +30 -0
  134. agno/knowledge/utils.py +169 -0
  135. agno/media.py +269 -268
  136. agno/memory/__init__.py +2 -10
  137. agno/memory/manager.py +1003 -148
  138. agno/models/aimlapi/__init__.py +2 -2
  139. agno/models/aimlapi/aimlapi.py +6 -6
  140. agno/models/anthropic/claude.py +131 -131
  141. agno/models/aws/bedrock.py +110 -182
  142. agno/models/aws/claude.py +64 -18
  143. agno/models/azure/ai_foundry.py +73 -23
  144. agno/models/base.py +346 -290
  145. agno/models/cerebras/cerebras.py +84 -27
  146. agno/models/cohere/chat.py +106 -98
  147. agno/models/google/gemini.py +105 -46
  148. agno/models/groq/groq.py +97 -35
  149. agno/models/huggingface/huggingface.py +92 -27
  150. agno/models/ibm/watsonx.py +72 -13
  151. agno/models/litellm/chat.py +85 -13
  152. agno/models/message.py +46 -151
  153. agno/models/meta/llama.py +85 -49
  154. agno/models/metrics.py +120 -0
  155. agno/models/mistral/mistral.py +90 -21
  156. agno/models/ollama/__init__.py +0 -2
  157. agno/models/ollama/chat.py +85 -47
  158. agno/models/openai/chat.py +154 -37
  159. agno/models/openai/responses.py +178 -105
  160. agno/models/perplexity/perplexity.py +26 -2
  161. agno/models/portkey/portkey.py +0 -7
  162. agno/models/response.py +15 -9
  163. agno/models/utils.py +20 -0
  164. agno/models/vercel/__init__.py +2 -2
  165. agno/models/vercel/v0.py +1 -1
  166. agno/models/vllm/__init__.py +2 -2
  167. agno/models/vllm/vllm.py +3 -3
  168. agno/models/xai/xai.py +10 -10
  169. agno/os/__init__.py +3 -0
  170. agno/os/app.py +497 -0
  171. agno/os/auth.py +47 -0
  172. agno/os/config.py +103 -0
  173. agno/os/interfaces/agui/__init__.py +3 -0
  174. agno/os/interfaces/agui/agui.py +31 -0
  175. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  176. agno/{app → os/interfaces}/agui/utils.py +77 -33
  177. agno/os/interfaces/base.py +21 -0
  178. agno/os/interfaces/slack/__init__.py +3 -0
  179. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  180. agno/os/interfaces/slack/slack.py +32 -0
  181. agno/os/interfaces/whatsapp/__init__.py +3 -0
  182. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  183. agno/os/interfaces/whatsapp/whatsapp.py +29 -0
  184. agno/os/mcp.py +235 -0
  185. agno/os/router.py +1400 -0
  186. agno/os/routers/__init__.py +3 -0
  187. agno/os/routers/evals/__init__.py +3 -0
  188. agno/os/routers/evals/evals.py +393 -0
  189. agno/os/routers/evals/schemas.py +142 -0
  190. agno/os/routers/evals/utils.py +161 -0
  191. agno/os/routers/knowledge/__init__.py +3 -0
  192. agno/os/routers/knowledge/knowledge.py +850 -0
  193. agno/os/routers/knowledge/schemas.py +118 -0
  194. agno/os/routers/memory/__init__.py +3 -0
  195. agno/os/routers/memory/memory.py +410 -0
  196. agno/os/routers/memory/schemas.py +58 -0
  197. agno/os/routers/metrics/__init__.py +3 -0
  198. agno/os/routers/metrics/metrics.py +178 -0
  199. agno/os/routers/metrics/schemas.py +47 -0
  200. agno/os/routers/session/__init__.py +3 -0
  201. agno/os/routers/session/session.py +536 -0
  202. agno/os/schema.py +945 -0
  203. agno/{app/playground → os}/settings.py +7 -15
  204. agno/os/utils.py +270 -0
  205. agno/reasoning/azure_ai_foundry.py +4 -4
  206. agno/reasoning/deepseek.py +4 -4
  207. agno/reasoning/default.py +6 -11
  208. agno/reasoning/groq.py +4 -4
  209. agno/reasoning/helpers.py +4 -6
  210. agno/reasoning/ollama.py +4 -4
  211. agno/reasoning/openai.py +4 -4
  212. agno/run/agent.py +633 -0
  213. agno/run/base.py +53 -77
  214. agno/run/cancel.py +81 -0
  215. agno/run/team.py +243 -96
  216. agno/run/workflow.py +550 -12
  217. agno/session/__init__.py +10 -0
  218. agno/session/agent.py +244 -0
  219. agno/session/summary.py +225 -0
  220. agno/session/team.py +262 -0
  221. agno/{storage/session/v2 → session}/workflow.py +47 -24
  222. agno/team/__init__.py +15 -16
  223. agno/team/team.py +3260 -4824
  224. agno/tools/agentql.py +14 -5
  225. agno/tools/airflow.py +9 -4
  226. agno/tools/api.py +7 -3
  227. agno/tools/apify.py +2 -46
  228. agno/tools/arxiv.py +8 -3
  229. agno/tools/aws_lambda.py +7 -5
  230. agno/tools/aws_ses.py +7 -1
  231. agno/tools/baidusearch.py +4 -1
  232. agno/tools/bitbucket.py +4 -4
  233. agno/tools/brandfetch.py +14 -11
  234. agno/tools/bravesearch.py +4 -1
  235. agno/tools/brightdata.py +43 -23
  236. agno/tools/browserbase.py +13 -4
  237. agno/tools/calcom.py +12 -10
  238. agno/tools/calculator.py +10 -27
  239. agno/tools/cartesia.py +20 -17
  240. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  241. agno/tools/confluence.py +8 -8
  242. agno/tools/crawl4ai.py +7 -1
  243. agno/tools/csv_toolkit.py +9 -8
  244. agno/tools/dalle.py +22 -12
  245. agno/tools/daytona.py +13 -16
  246. agno/tools/decorator.py +6 -3
  247. agno/tools/desi_vocal.py +17 -8
  248. agno/tools/discord.py +11 -8
  249. agno/tools/docker.py +30 -42
  250. agno/tools/duckdb.py +34 -53
  251. agno/tools/duckduckgo.py +8 -7
  252. agno/tools/e2b.py +62 -62
  253. agno/tools/eleven_labs.py +36 -29
  254. agno/tools/email.py +4 -1
  255. agno/tools/evm.py +7 -1
  256. agno/tools/exa.py +19 -14
  257. agno/tools/fal.py +30 -30
  258. agno/tools/file.py +9 -8
  259. agno/tools/financial_datasets.py +25 -44
  260. agno/tools/firecrawl.py +22 -22
  261. agno/tools/function.py +127 -18
  262. agno/tools/giphy.py +23 -11
  263. agno/tools/github.py +48 -126
  264. agno/tools/gmail.py +45 -61
  265. agno/tools/google_bigquery.py +7 -6
  266. agno/tools/google_maps.py +11 -26
  267. agno/tools/googlesearch.py +7 -2
  268. agno/tools/googlesheets.py +21 -17
  269. agno/tools/hackernews.py +9 -5
  270. agno/tools/jina.py +5 -4
  271. agno/tools/jira.py +18 -9
  272. agno/tools/knowledge.py +31 -32
  273. agno/tools/linear.py +19 -34
  274. agno/tools/linkup.py +5 -1
  275. agno/tools/local_file_system.py +8 -5
  276. agno/tools/lumalab.py +32 -20
  277. agno/tools/mcp.py +1 -2
  278. agno/tools/mem0.py +18 -12
  279. agno/tools/memori.py +14 -10
  280. agno/tools/mlx_transcribe.py +3 -2
  281. agno/tools/models/azure_openai.py +33 -15
  282. agno/tools/models/gemini.py +59 -32
  283. agno/tools/models/groq.py +30 -23
  284. agno/tools/models/nebius.py +28 -12
  285. agno/tools/models_labs.py +40 -16
  286. agno/tools/moviepy_video.py +7 -6
  287. agno/tools/neo4j.py +10 -8
  288. agno/tools/newspaper.py +7 -2
  289. agno/tools/newspaper4k.py +8 -3
  290. agno/tools/openai.py +58 -32
  291. agno/tools/openbb.py +12 -11
  292. agno/tools/opencv.py +63 -47
  293. agno/tools/openweather.py +14 -12
  294. agno/tools/pandas.py +11 -3
  295. agno/tools/postgres.py +4 -12
  296. agno/tools/pubmed.py +4 -1
  297. agno/tools/python.py +9 -22
  298. agno/tools/reasoning.py +35 -27
  299. agno/tools/reddit.py +11 -26
  300. agno/tools/replicate.py +55 -42
  301. agno/tools/resend.py +4 -1
  302. agno/tools/scrapegraph.py +15 -14
  303. agno/tools/searxng.py +10 -23
  304. agno/tools/serpapi.py +6 -3
  305. agno/tools/serper.py +13 -4
  306. agno/tools/shell.py +9 -2
  307. agno/tools/slack.py +12 -11
  308. agno/tools/sleep.py +3 -2
  309. agno/tools/spider.py +24 -4
  310. agno/tools/sql.py +7 -6
  311. agno/tools/tavily.py +6 -4
  312. agno/tools/telegram.py +12 -4
  313. agno/tools/todoist.py +11 -31
  314. agno/tools/toolkit.py +1 -1
  315. agno/tools/trafilatura.py +22 -6
  316. agno/tools/trello.py +9 -22
  317. agno/tools/twilio.py +10 -3
  318. agno/tools/user_control_flow.py +6 -1
  319. agno/tools/valyu.py +34 -5
  320. agno/tools/visualization.py +19 -28
  321. agno/tools/webbrowser.py +4 -3
  322. agno/tools/webex.py +11 -7
  323. agno/tools/website.py +15 -46
  324. agno/tools/webtools.py +12 -4
  325. agno/tools/whatsapp.py +5 -9
  326. agno/tools/wikipedia.py +20 -13
  327. agno/tools/x.py +14 -13
  328. agno/tools/yfinance.py +13 -40
  329. agno/tools/youtube.py +26 -20
  330. agno/tools/zendesk.py +7 -2
  331. agno/tools/zep.py +10 -7
  332. agno/tools/zoom.py +10 -9
  333. agno/utils/common.py +1 -19
  334. agno/utils/events.py +100 -123
  335. agno/utils/gemini.py +32 -2
  336. agno/utils/knowledge.py +29 -0
  337. agno/utils/log.py +54 -4
  338. agno/utils/mcp.py +68 -10
  339. agno/utils/media.py +39 -0
  340. agno/utils/message.py +12 -1
  341. agno/utils/models/aws_claude.py +1 -1
  342. agno/utils/models/claude.py +47 -4
  343. agno/utils/models/cohere.py +1 -1
  344. agno/utils/models/mistral.py +8 -7
  345. agno/utils/models/schema_utils.py +3 -3
  346. agno/utils/models/watsonx.py +1 -1
  347. agno/utils/openai.py +1 -1
  348. agno/utils/pprint.py +33 -32
  349. agno/utils/print_response/agent.py +779 -0
  350. agno/utils/print_response/team.py +1669 -0
  351. agno/utils/print_response/workflow.py +1451 -0
  352. agno/utils/prompts.py +14 -14
  353. agno/utils/reasoning.py +87 -0
  354. agno/utils/response.py +42 -42
  355. agno/utils/streamlit.py +481 -0
  356. agno/utils/string.py +8 -22
  357. agno/utils/team.py +50 -0
  358. agno/utils/timer.py +2 -2
  359. agno/vectordb/base.py +33 -21
  360. agno/vectordb/cassandra/cassandra.py +287 -23
  361. agno/vectordb/chroma/chromadb.py +482 -59
  362. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  363. agno/vectordb/couchbase/couchbase.py +309 -29
  364. agno/vectordb/lancedb/lance_db.py +360 -21
  365. agno/vectordb/langchaindb/__init__.py +5 -0
  366. agno/vectordb/langchaindb/langchaindb.py +145 -0
  367. agno/vectordb/lightrag/__init__.py +5 -0
  368. agno/vectordb/lightrag/lightrag.py +374 -0
  369. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  370. agno/vectordb/milvus/milvus.py +242 -32
  371. agno/vectordb/mongodb/mongodb.py +200 -24
  372. agno/vectordb/pgvector/pgvector.py +319 -37
  373. agno/vectordb/pineconedb/pineconedb.py +221 -27
  374. agno/vectordb/qdrant/qdrant.py +334 -14
  375. agno/vectordb/singlestore/singlestore.py +286 -29
  376. agno/vectordb/surrealdb/surrealdb.py +187 -7
  377. agno/vectordb/upstashdb/upstashdb.py +342 -26
  378. agno/vectordb/weaviate/weaviate.py +227 -165
  379. agno/workflow/__init__.py +17 -13
  380. agno/workflow/{v2/condition.py → condition.py} +135 -32
  381. agno/workflow/{v2/loop.py → loop.py} +115 -28
  382. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  383. agno/workflow/{v2/router.py → router.py} +133 -32
  384. agno/workflow/{v2/step.py → step.py} +207 -49
  385. agno/workflow/{v2/steps.py → steps.py} +147 -66
  386. agno/workflow/types.py +482 -0
  387. agno/workflow/workflow.py +2410 -696
  388. agno-2.0.0.dist-info/METADATA +494 -0
  389. agno-2.0.0.dist-info/RECORD +515 -0
  390. agno-2.0.0.dist-info/licenses/LICENSE +201 -0
  391. agno/agent/metrics.py +0 -107
  392. agno/api/app.py +0 -35
  393. agno/api/playground.py +0 -92
  394. agno/api/schemas/app.py +0 -12
  395. agno/api/schemas/playground.py +0 -22
  396. agno/api/schemas/user.py +0 -35
  397. agno/api/schemas/workspace.py +0 -46
  398. agno/api/user.py +0 -160
  399. agno/api/workflows.py +0 -33
  400. agno/api/workspace.py +0 -175
  401. agno/app/agui/__init__.py +0 -3
  402. agno/app/agui/app.py +0 -17
  403. agno/app/agui/sync_router.py +0 -120
  404. agno/app/base.py +0 -186
  405. agno/app/discord/__init__.py +0 -3
  406. agno/app/fastapi/__init__.py +0 -3
  407. agno/app/fastapi/app.py +0 -107
  408. agno/app/fastapi/async_router.py +0 -457
  409. agno/app/fastapi/sync_router.py +0 -448
  410. agno/app/playground/app.py +0 -228
  411. agno/app/playground/async_router.py +0 -1050
  412. agno/app/playground/deploy.py +0 -249
  413. agno/app/playground/operator.py +0 -183
  414. agno/app/playground/schemas.py +0 -220
  415. agno/app/playground/serve.py +0 -55
  416. agno/app/playground/sync_router.py +0 -1042
  417. agno/app/playground/utils.py +0 -46
  418. agno/app/settings.py +0 -15
  419. agno/app/slack/__init__.py +0 -3
  420. agno/app/slack/app.py +0 -19
  421. agno/app/slack/sync_router.py +0 -92
  422. agno/app/utils.py +0 -54
  423. agno/app/whatsapp/__init__.py +0 -3
  424. agno/app/whatsapp/app.py +0 -15
  425. agno/app/whatsapp/sync_router.py +0 -197
  426. agno/cli/auth_server.py +0 -249
  427. agno/cli/config.py +0 -274
  428. agno/cli/console.py +0 -88
  429. agno/cli/credentials.py +0 -23
  430. agno/cli/entrypoint.py +0 -571
  431. agno/cli/operator.py +0 -357
  432. agno/cli/settings.py +0 -96
  433. agno/cli/ws/ws_cli.py +0 -817
  434. agno/constants.py +0 -13
  435. agno/document/__init__.py +0 -5
  436. agno/document/chunking/semantic.py +0 -45
  437. agno/document/chunking/strategy.py +0 -31
  438. agno/document/reader/__init__.py +0 -5
  439. agno/document/reader/base.py +0 -47
  440. agno/document/reader/docx_reader.py +0 -60
  441. agno/document/reader/gcs/pdf_reader.py +0 -44
  442. agno/document/reader/s3/pdf_reader.py +0 -59
  443. agno/document/reader/s3/text_reader.py +0 -63
  444. agno/document/reader/url_reader.py +0 -59
  445. agno/document/reader/youtube_reader.py +0 -58
  446. agno/embedder/__init__.py +0 -5
  447. agno/embedder/langdb.py +0 -80
  448. agno/embedder/mistral.py +0 -82
  449. agno/embedder/openai.py +0 -78
  450. agno/file/__init__.py +0 -5
  451. agno/file/file.py +0 -16
  452. agno/file/local/csv.py +0 -32
  453. agno/file/local/txt.py +0 -19
  454. agno/infra/app.py +0 -240
  455. agno/infra/base.py +0 -144
  456. agno/infra/context.py +0 -20
  457. agno/infra/db_app.py +0 -52
  458. agno/infra/resource.py +0 -205
  459. agno/infra/resources.py +0 -55
  460. agno/knowledge/agent.py +0 -702
  461. agno/knowledge/arxiv.py +0 -33
  462. agno/knowledge/combined.py +0 -36
  463. agno/knowledge/csv.py +0 -144
  464. agno/knowledge/csv_url.py +0 -124
  465. agno/knowledge/document.py +0 -223
  466. agno/knowledge/docx.py +0 -137
  467. agno/knowledge/firecrawl.py +0 -34
  468. agno/knowledge/gcs/__init__.py +0 -0
  469. agno/knowledge/gcs/base.py +0 -39
  470. agno/knowledge/gcs/pdf.py +0 -125
  471. agno/knowledge/json.py +0 -137
  472. agno/knowledge/langchain.py +0 -71
  473. agno/knowledge/light_rag.py +0 -273
  474. agno/knowledge/llamaindex.py +0 -66
  475. agno/knowledge/markdown.py +0 -154
  476. agno/knowledge/pdf.py +0 -164
  477. agno/knowledge/pdf_bytes.py +0 -42
  478. agno/knowledge/pdf_url.py +0 -148
  479. agno/knowledge/s3/__init__.py +0 -0
  480. agno/knowledge/s3/base.py +0 -64
  481. agno/knowledge/s3/pdf.py +0 -33
  482. agno/knowledge/s3/text.py +0 -34
  483. agno/knowledge/text.py +0 -141
  484. agno/knowledge/url.py +0 -46
  485. agno/knowledge/website.py +0 -179
  486. agno/knowledge/wikipedia.py +0 -32
  487. agno/knowledge/youtube.py +0 -35
  488. agno/memory/agent.py +0 -423
  489. agno/memory/classifier.py +0 -104
  490. agno/memory/db/__init__.py +0 -5
  491. agno/memory/db/base.py +0 -42
  492. agno/memory/db/mongodb.py +0 -189
  493. agno/memory/db/postgres.py +0 -203
  494. agno/memory/db/sqlite.py +0 -193
  495. agno/memory/memory.py +0 -22
  496. agno/memory/row.py +0 -36
  497. agno/memory/summarizer.py +0 -201
  498. agno/memory/summary.py +0 -19
  499. agno/memory/team.py +0 -415
  500. agno/memory/v2/__init__.py +0 -2
  501. agno/memory/v2/db/__init__.py +0 -1
  502. agno/memory/v2/db/base.py +0 -42
  503. agno/memory/v2/db/firestore.py +0 -339
  504. agno/memory/v2/db/mongodb.py +0 -196
  505. agno/memory/v2/db/postgres.py +0 -214
  506. agno/memory/v2/db/redis.py +0 -187
  507. agno/memory/v2/db/schema.py +0 -54
  508. agno/memory/v2/db/sqlite.py +0 -209
  509. agno/memory/v2/manager.py +0 -437
  510. agno/memory/v2/memory.py +0 -1097
  511. agno/memory/v2/schema.py +0 -55
  512. agno/memory/v2/summarizer.py +0 -215
  513. agno/memory/workflow.py +0 -38
  514. agno/models/ollama/tools.py +0 -430
  515. agno/models/qwen/__init__.py +0 -5
  516. agno/playground/__init__.py +0 -10
  517. agno/playground/deploy.py +0 -3
  518. agno/playground/playground.py +0 -3
  519. agno/playground/serve.py +0 -3
  520. agno/playground/settings.py +0 -3
  521. agno/reranker/__init__.py +0 -0
  522. agno/run/response.py +0 -467
  523. agno/run/v2/__init__.py +0 -0
  524. agno/run/v2/workflow.py +0 -567
  525. agno/storage/__init__.py +0 -0
  526. agno/storage/agent/__init__.py +0 -0
  527. agno/storage/agent/dynamodb.py +0 -1
  528. agno/storage/agent/json.py +0 -1
  529. agno/storage/agent/mongodb.py +0 -1
  530. agno/storage/agent/postgres.py +0 -1
  531. agno/storage/agent/singlestore.py +0 -1
  532. agno/storage/agent/sqlite.py +0 -1
  533. agno/storage/agent/yaml.py +0 -1
  534. agno/storage/base.py +0 -60
  535. agno/storage/dynamodb.py +0 -673
  536. agno/storage/firestore.py +0 -297
  537. agno/storage/gcs_json.py +0 -261
  538. agno/storage/in_memory.py +0 -234
  539. agno/storage/json.py +0 -237
  540. agno/storage/mongodb.py +0 -328
  541. agno/storage/mysql.py +0 -685
  542. agno/storage/postgres.py +0 -682
  543. agno/storage/redis.py +0 -336
  544. agno/storage/session/__init__.py +0 -16
  545. agno/storage/session/agent.py +0 -64
  546. agno/storage/session/team.py +0 -63
  547. agno/storage/session/v2/__init__.py +0 -5
  548. agno/storage/session/workflow.py +0 -61
  549. agno/storage/singlestore.py +0 -606
  550. agno/storage/sqlite.py +0 -646
  551. agno/storage/workflow/__init__.py +0 -0
  552. agno/storage/workflow/mongodb.py +0 -1
  553. agno/storage/workflow/postgres.py +0 -1
  554. agno/storage/workflow/sqlite.py +0 -1
  555. agno/storage/yaml.py +0 -241
  556. agno/tools/thinking.py +0 -73
  557. agno/utils/defaults.py +0 -57
  558. agno/utils/filesystem.py +0 -39
  559. agno/utils/git.py +0 -52
  560. agno/utils/json_io.py +0 -30
  561. agno/utils/load_env.py +0 -19
  562. agno/utils/py_io.py +0 -19
  563. agno/utils/pyproject.py +0 -18
  564. agno/utils/resource_filter.py +0 -31
  565. agno/workflow/v2/__init__.py +0 -21
  566. agno/workflow/v2/types.py +0 -357
  567. agno/workflow/v2/workflow.py +0 -3312
  568. agno/workspace/__init__.py +0 -0
  569. agno/workspace/config.py +0 -325
  570. agno/workspace/enums.py +0 -6
  571. agno/workspace/helpers.py +0 -52
  572. agno/workspace/operator.py +0 -757
  573. agno/workspace/settings.py +0 -158
  574. agno-1.8.1.dist-info/METADATA +0 -982
  575. agno-1.8.1.dist-info/RECORD +0 -566
  576. agno-1.8.1.dist-info/entry_points.txt +0 -3
  577. agno-1.8.1.dist-info/licenses/LICENSE +0 -375
  578. /agno/{app → db/migrations}/__init__.py +0 -0
  579. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  580. /agno/{cli → integrations}/__init__.py +0 -0
  581. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  582. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  583. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  584. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  585. /agno/{app → os/interfaces}/slack/security.py +0 -0
  586. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  587. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  588. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  589. {agno-1.8.1.dist-info → agno-2.0.0.dist-info}/WHEEL +0 -0
  590. {agno-1.8.1.dist-info → agno-2.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,118 @@
1
+ from datetime import datetime, timezone
2
+ from enum import Enum
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class ContentStatus(str, Enum):
9
+ """Enumeration of possible content processing statuses."""
10
+
11
+ PROCESSING = "processing"
12
+ COMPLETED = "completed"
13
+ FAILED = "failed"
14
+
15
+
16
+ class ContentStatusResponse(BaseModel):
17
+ """Response model for content status endpoint."""
18
+
19
+ status: ContentStatus
20
+ status_message: str = ""
21
+
22
+
23
+ class ContentResponseSchema(BaseModel):
24
+ id: str
25
+ name: Optional[str] = None
26
+ description: Optional[str] = None
27
+ type: Optional[str] = None
28
+ size: Optional[str] = None
29
+ linked_to: Optional[str] = None
30
+ metadata: Optional[dict] = None
31
+ access_count: Optional[int] = None
32
+ status: Optional[ContentStatus] = None
33
+ status_message: Optional[str] = None
34
+ created_at: Optional[datetime] = None
35
+ updated_at: Optional[datetime] = None
36
+
37
+ @classmethod
38
+ def from_dict(cls, content: Dict[str, Any]) -> "ContentResponseSchema":
39
+ status = content.get("status")
40
+ if isinstance(status, str):
41
+ try:
42
+ status = ContentStatus(status.lower())
43
+ except ValueError:
44
+ # Handle legacy or unknown statuses gracefully
45
+ if "failed" in status.lower():
46
+ status = ContentStatus.FAILED
47
+ elif "completed" in status.lower():
48
+ status = ContentStatus.COMPLETED
49
+ else:
50
+ status = ContentStatus.PROCESSING
51
+ elif status is None:
52
+ status = ContentStatus.PROCESSING # Default for None values
53
+
54
+ # Helper function to safely parse timestamps
55
+ def parse_timestamp(timestamp_value):
56
+ if timestamp_value is None:
57
+ return None
58
+ try:
59
+ # If it's already a datetime object, return it
60
+ if isinstance(timestamp_value, datetime):
61
+ return timestamp_value
62
+ # If it's a string, try to parse it as ISO format first
63
+ if isinstance(timestamp_value, str):
64
+ try:
65
+ return datetime.fromisoformat(timestamp_value.replace("Z", "+00:00"))
66
+ except ValueError:
67
+ # Try to parse as float/int timestamp
68
+ timestamp_value = float(timestamp_value)
69
+ # If it's a number, use fromtimestamp
70
+ return datetime.fromtimestamp(timestamp_value, tz=timezone.utc)
71
+ except (ValueError, TypeError, OSError):
72
+ # If all parsing fails, return None
73
+ return None
74
+
75
+ return cls(
76
+ id=content.get("id"), # type: ignore
77
+ name=content.get("name"),
78
+ description=content.get("description"),
79
+ type=content.get("file_type"),
80
+ size=str(content.get("size")) if content.get("size") else "0",
81
+ metadata=content.get("metadata"),
82
+ status=status,
83
+ status_message=content.get("status_message"),
84
+ created_at=parse_timestamp(content.get("created_at")),
85
+ updated_at=parse_timestamp(content.get("updated_at")),
86
+ # TODO: These fields are not available in the Content class. Fix the inconsistency
87
+ access_count=None,
88
+ linked_to=None,
89
+ )
90
+
91
+
92
+ class ContentUpdateSchema(BaseModel):
93
+ """Schema for updating content."""
94
+
95
+ name: Optional[str] = Field(None, description="Content name", min_length=1, max_length=255)
96
+ description: Optional[str] = Field(None, description="Content description", max_length=1000)
97
+ metadata: Optional[Dict[str, Any]] = Field(None, description="Content metadata as key-value pairs")
98
+ reader_id: Optional[str] = Field(None, description="ID of the reader to use for processing", min_length=1)
99
+
100
+
101
+ class ReaderSchema(BaseModel):
102
+ id: str
103
+ name: Optional[str] = None
104
+ description: Optional[str] = None
105
+ chunkers: Optional[List[str]] = None
106
+
107
+
108
+ class ChunkerSchema(BaseModel):
109
+ key: str
110
+ name: Optional[str] = None
111
+ description: Optional[str] = None
112
+
113
+
114
+ class ConfigResponseSchema(BaseModel):
115
+ readers: Optional[Dict[str, ReaderSchema]] = None
116
+ readersForType: Optional[Dict[str, List[str]]] = None
117
+ chunkers: Optional[Dict[str, ChunkerSchema]] = None
118
+ filters: Optional[List[str]] = None
@@ -0,0 +1,3 @@
1
+ from agno.os.routers.memory.memory import get_memory_router
2
+
3
+ __all__ = ["get_memory_router"]
@@ -0,0 +1,410 @@
1
+ import logging
2
+ import math
3
+ from typing import List, Optional
4
+ from uuid import uuid4
5
+
6
+ from fastapi import Depends, HTTPException, Path, Query
7
+ from fastapi.routing import APIRouter
8
+
9
+ from agno.db.base import BaseDb
10
+ from agno.db.schemas import UserMemory
11
+ from agno.os.auth import get_authentication_dependency
12
+ from agno.os.routers.memory.schemas import (
13
+ DeleteMemoriesRequest,
14
+ UserMemoryCreateSchema,
15
+ UserMemorySchema,
16
+ UserStatsSchema,
17
+ )
18
+ from agno.os.schema import (
19
+ BadRequestResponse,
20
+ InternalServerErrorResponse,
21
+ NotFoundResponse,
22
+ PaginatedResponse,
23
+ PaginationInfo,
24
+ SortOrder,
25
+ UnauthenticatedResponse,
26
+ ValidationErrorResponse,
27
+ )
28
+ from agno.os.settings import AgnoAPISettings
29
+ from agno.os.utils import get_db
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+
34
+ def get_memory_router(dbs: dict[str, BaseDb], settings: AgnoAPISettings = AgnoAPISettings(), **kwargs) -> APIRouter:
35
+ """Create memory router with comprehensive OpenAPI documentation for user memory management endpoints."""
36
+ router = APIRouter(
37
+ dependencies=[Depends(get_authentication_dependency(settings))],
38
+ tags=["Memory"],
39
+ responses={
40
+ 400: {"description": "Bad Request", "model": BadRequestResponse},
41
+ 401: {"description": "Unauthorized", "model": UnauthenticatedResponse},
42
+ 404: {"description": "Not Found", "model": NotFoundResponse},
43
+ 422: {"description": "Validation Error", "model": ValidationErrorResponse},
44
+ 500: {"description": "Internal Server Error", "model": InternalServerErrorResponse},
45
+ },
46
+ )
47
+ return attach_routes(router=router, dbs=dbs)
48
+
49
+
50
+ def attach_routes(router: APIRouter, dbs: dict[str, BaseDb]) -> APIRouter:
51
+ @router.post(
52
+ "/memories",
53
+ response_model=UserMemorySchema,
54
+ status_code=200,
55
+ operation_id="create_memory",
56
+ summary="Create Memory",
57
+ description=(
58
+ "Create a new user memory with content and associated topics. "
59
+ "Memories are used to store contextual information for users across conversations."
60
+ ),
61
+ responses={
62
+ 200: {
63
+ "description": "Memory created successfully",
64
+ "content": {
65
+ "application/json": {
66
+ "example": {
67
+ "memory_id": "mem-123",
68
+ "memory": "User prefers technical explanations with code examples",
69
+ "topics": ["preferences", "communication_style", "technical"],
70
+ "user_id": "user-456",
71
+ "created_at": "2024-01-15T10:30:00Z",
72
+ "updated_at": "2024-01-15T10:30:00Z",
73
+ }
74
+ }
75
+ },
76
+ },
77
+ 400: {"description": "Invalid request data", "model": BadRequestResponse},
78
+ 422: {"description": "Validation error in payload", "model": ValidationErrorResponse},
79
+ 500: {"description": "Failed to create memory", "model": InternalServerErrorResponse},
80
+ },
81
+ )
82
+ async def create_memory(
83
+ payload: UserMemoryCreateSchema,
84
+ db_id: Optional[str] = Query(default=None, description="Database ID to use for memory storage"),
85
+ ) -> UserMemorySchema:
86
+ db = get_db(dbs, db_id)
87
+ user_memory = db.upsert_user_memory(
88
+ memory=UserMemory(
89
+ memory_id=str(uuid4()),
90
+ memory=payload.memory,
91
+ topics=payload.topics or [],
92
+ user_id=payload.user_id,
93
+ ),
94
+ deserialize=False,
95
+ )
96
+ if not user_memory:
97
+ raise HTTPException(status_code=500, detail="Failed to create memory")
98
+
99
+ return UserMemorySchema.from_dict(user_memory) # type: ignore
100
+
101
+ @router.delete(
102
+ "/memories/{memory_id}",
103
+ status_code=204,
104
+ operation_id="delete_memory",
105
+ summary="Delete Memory",
106
+ description="Permanently delete a specific user memory. This action cannot be undone.",
107
+ responses={
108
+ 204: {"description": "Memory deleted successfully"},
109
+ 404: {"description": "Memory not found", "model": NotFoundResponse},
110
+ 500: {"description": "Failed to delete memory", "model": InternalServerErrorResponse},
111
+ },
112
+ )
113
+ async def delete_memory(
114
+ memory_id: str = Path(description="Memory ID to delete"),
115
+ db_id: Optional[str] = Query(default=None, description="Database ID to use for deletion"),
116
+ ) -> None:
117
+ db = get_db(dbs, db_id)
118
+ db.delete_user_memory(memory_id=memory_id)
119
+
120
+ @router.delete(
121
+ "/memories",
122
+ status_code=204,
123
+ operation_id="delete_memories",
124
+ summary="Delete Multiple Memories",
125
+ description=(
126
+ "Delete multiple user memories by their IDs in a single operation. "
127
+ "This action cannot be undone and all specified memories will be permanently removed."
128
+ ),
129
+ responses={
130
+ 204: {"description": "Memories deleted successfully"},
131
+ 400: {"description": "Invalid request - empty memory_ids list", "model": BadRequestResponse},
132
+ 500: {"description": "Failed to delete memories", "model": InternalServerErrorResponse},
133
+ },
134
+ )
135
+ async def delete_memories(
136
+ request: DeleteMemoriesRequest,
137
+ db_id: Optional[str] = Query(default=None, description="Database ID to use for deletion"),
138
+ ) -> None:
139
+ db = get_db(dbs, db_id)
140
+ db.delete_user_memories(memory_ids=request.memory_ids)
141
+
142
+ @router.get(
143
+ "/memories",
144
+ response_model=PaginatedResponse[UserMemorySchema],
145
+ status_code=200,
146
+ operation_id="get_memories",
147
+ summary="List Memories",
148
+ description=(
149
+ "Retrieve paginated list of user memories with filtering and search capabilities. "
150
+ "Filter by user, agent, team, topics, or search within memory content."
151
+ ),
152
+ responses={
153
+ 200: {
154
+ "description": "Memories retrieved successfully",
155
+ "content": {
156
+ "application/json": {
157
+ "example": {
158
+ "data": [
159
+ {
160
+ "memory_id": "f9361a69-2997-40c7-ae4e-a5861d434047",
161
+ "memory": "User likes coffee.",
162
+ "topics": ["preferences"],
163
+ "agent_id": None,
164
+ "team_id": None,
165
+ "user_id": "123",
166
+ "updated_at": "2025-09-01T07:53:17Z",
167
+ }
168
+ ]
169
+ }
170
+ }
171
+ },
172
+ }
173
+ },
174
+ )
175
+ async def get_memories(
176
+ user_id: Optional[str] = Query(default=None, description="Filter memories by user ID"),
177
+ agent_id: Optional[str] = Query(default=None, description="Filter memories by agent ID"),
178
+ team_id: Optional[str] = Query(default=None, description="Filter memories by team ID"),
179
+ topics: Optional[List[str]] = Depends(parse_topics),
180
+ search_content: Optional[str] = Query(default=None, description="Fuzzy search within memory content"),
181
+ limit: Optional[int] = Query(default=20, description="Number of memories to return per page"),
182
+ page: Optional[int] = Query(default=1, description="Page number for pagination"),
183
+ sort_by: Optional[str] = Query(default="updated_at", description="Field to sort memories by"),
184
+ sort_order: Optional[SortOrder] = Query(default="desc", description="Sort order (asc or desc)"),
185
+ db_id: Optional[str] = Query(default=None, description="Database ID to query memories from"),
186
+ ) -> PaginatedResponse[UserMemorySchema]:
187
+ db = get_db(dbs, db_id)
188
+ user_memories, total_count = db.get_user_memories(
189
+ limit=limit,
190
+ page=page,
191
+ user_id=user_id,
192
+ agent_id=agent_id,
193
+ team_id=team_id,
194
+ topics=topics,
195
+ search_content=search_content,
196
+ sort_by=sort_by,
197
+ sort_order=sort_order,
198
+ deserialize=False,
199
+ )
200
+ return PaginatedResponse(
201
+ data=[UserMemorySchema.from_dict(user_memory) for user_memory in user_memories], # type: ignore
202
+ meta=PaginationInfo(
203
+ page=page,
204
+ limit=limit,
205
+ total_count=total_count, # type: ignore
206
+ total_pages=math.ceil(total_count / limit) if limit is not None and limit > 0 else 0, # type: ignore
207
+ ),
208
+ )
209
+
210
+ @router.get(
211
+ "/memories/{memory_id}",
212
+ response_model=UserMemorySchema,
213
+ status_code=200,
214
+ operation_id="get_memory",
215
+ summary="Get Memory by ID",
216
+ description="Retrieve detailed information about a specific user memory by its ID.",
217
+ responses={
218
+ 200: {
219
+ "description": "Memory retrieved successfully",
220
+ "content": {
221
+ "application/json": {
222
+ "example": {
223
+ "memory_id": "f9361a69-2997-40c7-ae4e-a5861d434047",
224
+ "memory": "User likes coffee.",
225
+ "topics": ["preferences"],
226
+ "agent_id": None,
227
+ "team_id": None,
228
+ "user_id": "123",
229
+ "updated_at": "2025-09-01T07:53:17Z",
230
+ }
231
+ }
232
+ },
233
+ },
234
+ 404: {"description": "Memory not found", "model": NotFoundResponse},
235
+ },
236
+ )
237
+ async def get_memory(
238
+ memory_id: str = Path(description="Memory ID to retrieve"),
239
+ db_id: Optional[str] = Query(default=None, description="Database ID to query memory from"),
240
+ ) -> UserMemorySchema:
241
+ db = get_db(dbs, db_id)
242
+ user_memory = db.get_user_memory(memory_id=memory_id, deserialize=False)
243
+ if not user_memory:
244
+ raise HTTPException(status_code=404, detail=f"Memory with ID {memory_id} not found")
245
+
246
+ return UserMemorySchema.from_dict(user_memory) # type: ignore
247
+
248
+ @router.get(
249
+ "/memory_topics",
250
+ response_model=List[str],
251
+ status_code=200,
252
+ operation_id="get_memory_topics",
253
+ summary="Get Memory Topics",
254
+ description=(
255
+ "Retrieve all unique topics associated with memories in the system. "
256
+ "Useful for filtering and categorizing memories by topic."
257
+ ),
258
+ responses={
259
+ 200: {
260
+ "description": "Memory topics retrieved successfully",
261
+ "content": {
262
+ "application/json": {
263
+ "example": [
264
+ "preferences",
265
+ "communication_style",
266
+ "technical",
267
+ "industry",
268
+ "compliance",
269
+ "code_examples",
270
+ "requirements",
271
+ "healthcare",
272
+ "finance",
273
+ ]
274
+ }
275
+ },
276
+ }
277
+ },
278
+ )
279
+ async def get_topics(
280
+ db_id: Optional[str] = Query(default=None, description="Database ID to query topics from"),
281
+ ) -> List[str]:
282
+ db = get_db(dbs, db_id)
283
+ return db.get_all_memory_topics()
284
+
285
+ @router.patch(
286
+ "/memories/{memory_id}",
287
+ response_model=UserMemorySchema,
288
+ status_code=200,
289
+ operation_id="update_memory",
290
+ summary="Update Memory",
291
+ description=(
292
+ "Update an existing user memory's content and topics. "
293
+ "Replaces the entire memory content and topic list with the provided values."
294
+ ),
295
+ responses={
296
+ 200: {
297
+ "description": "Memory updated successfully",
298
+ "content": {
299
+ "application/json": {
300
+ "example": {
301
+ "memory_id": "f9361a69-2997-40c7-ae4e-a5861d434047",
302
+ "memory": "User likes coffee.",
303
+ "topics": ["preferences"],
304
+ "agent_id": None,
305
+ "team_id": None,
306
+ "user_id": "123",
307
+ "updated_at": "2025-09-01T07:53:17Z",
308
+ }
309
+ }
310
+ },
311
+ },
312
+ 400: {"description": "Invalid request data", "model": BadRequestResponse},
313
+ 404: {"description": "Memory not found", "model": NotFoundResponse},
314
+ 422: {"description": "Validation error in payload", "model": ValidationErrorResponse},
315
+ 500: {"description": "Failed to update memory", "model": InternalServerErrorResponse},
316
+ },
317
+ )
318
+ async def update_memory(
319
+ payload: UserMemoryCreateSchema,
320
+ memory_id: str = Path(description="Memory ID to update"),
321
+ db_id: Optional[str] = Query(default=None, description="Database ID to use for update"),
322
+ ) -> UserMemorySchema:
323
+ db = get_db(dbs, db_id)
324
+ user_memory = db.upsert_user_memory(
325
+ memory=UserMemory(
326
+ memory_id=memory_id,
327
+ memory=payload.memory,
328
+ topics=payload.topics or [],
329
+ user_id=payload.user_id,
330
+ ),
331
+ deserialize=False,
332
+ )
333
+ if not user_memory:
334
+ raise HTTPException(status_code=500, detail="Failed to update memory")
335
+
336
+ return UserMemorySchema.from_dict(user_memory) # type: ignore
337
+
338
+ @router.get(
339
+ "/user_memory_stats",
340
+ response_model=PaginatedResponse[UserStatsSchema],
341
+ status_code=200,
342
+ operation_id="get_user_memory_stats",
343
+ summary="Get User Memory Statistics",
344
+ description=(
345
+ "Retrieve paginated statistics about memory usage by user. "
346
+ "Provides insights into user engagement and memory distribution across users."
347
+ ),
348
+ responses={
349
+ 200: {
350
+ "description": "User memory statistics retrieved successfully",
351
+ "content": {
352
+ "application/json": {
353
+ "example": {
354
+ "data": [
355
+ {
356
+ "user_id": "123",
357
+ "total_memories": 3,
358
+ "last_memory_updated_at": "2025-09-01T07:53:17Z",
359
+ }
360
+ ]
361
+ }
362
+ }
363
+ },
364
+ },
365
+ 500: {"description": "Failed to retrieve user statistics", "model": InternalServerErrorResponse},
366
+ },
367
+ )
368
+ async def get_user_memory_stats(
369
+ limit: Optional[int] = Query(default=20, description="Number of user statistics to return per page"),
370
+ page: Optional[int] = Query(default=1, description="Page number for pagination"),
371
+ db_id: Optional[str] = Query(default=None, description="Database ID to query statistics from"),
372
+ ) -> PaginatedResponse[UserStatsSchema]:
373
+ db = get_db(dbs, db_id)
374
+ try:
375
+ user_stats, total_count = db.get_user_memory_stats(
376
+ limit=limit,
377
+ page=page,
378
+ )
379
+ return PaginatedResponse(
380
+ data=[UserStatsSchema.from_dict(stats) for stats in user_stats],
381
+ meta=PaginationInfo(
382
+ page=page,
383
+ limit=limit,
384
+ total_count=total_count,
385
+ total_pages=(total_count + limit - 1) // limit if limit is not None and limit > 0 else 0,
386
+ ),
387
+ )
388
+
389
+ except Exception as e:
390
+ raise HTTPException(status_code=500, detail=f"Failed to get user statistics: {str(e)}")
391
+
392
+ return router
393
+
394
+
395
+ def parse_topics(
396
+ topics: Optional[List[str]] = Query(
397
+ default=None,
398
+ description="Comma-separated list of topics to filter by",
399
+ example=["preferences,technical,communication_style"],
400
+ ),
401
+ ) -> Optional[List[str]]:
402
+ """Parse comma-separated topics into a list for filtering memories by topic."""
403
+ if not topics:
404
+ return None
405
+
406
+ try:
407
+ return [topic.strip() for topic in topics[0].split(",") if topic.strip()]
408
+
409
+ except Exception as e:
410
+ raise HTTPException(status_code=422, detail=f"Invalid topics format: {e}")
@@ -0,0 +1,58 @@
1
+ from datetime import datetime, timezone
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class DeleteMemoriesRequest(BaseModel):
8
+ memory_ids: List[str]
9
+
10
+
11
+ class UserMemorySchema(BaseModel):
12
+ memory_id: str
13
+ memory: str
14
+ topics: Optional[List[str]]
15
+
16
+ agent_id: Optional[str]
17
+ team_id: Optional[str]
18
+ user_id: Optional[str]
19
+
20
+ updated_at: Optional[datetime]
21
+
22
+ @classmethod
23
+ def from_dict(cls, memory_dict: Dict[str, Any]) -> "UserMemorySchema":
24
+ return cls(
25
+ memory_id=memory_dict["memory_id"],
26
+ user_id=str(memory_dict["user_id"]),
27
+ agent_id=memory_dict.get("agent_id"),
28
+ team_id=memory_dict.get("team_id"),
29
+ memory=memory_dict["memory"],
30
+ topics=memory_dict.get("topics", []),
31
+ updated_at=memory_dict["updated_at"],
32
+ )
33
+
34
+
35
+ class UserMemoryCreateSchema(BaseModel):
36
+ """Define the payload expected for creating a new user memory"""
37
+
38
+ memory: str
39
+ user_id: str
40
+ topics: Optional[List[str]] = None
41
+
42
+
43
+ class UserStatsSchema(BaseModel):
44
+ """Schema for user memory statistics"""
45
+
46
+ user_id: str
47
+ total_memories: int
48
+ last_memory_updated_at: Optional[datetime] = None
49
+
50
+ @classmethod
51
+ def from_dict(cls, user_stats_dict: Dict[str, Any]) -> "UserStatsSchema":
52
+ updated_at = user_stats_dict.get("last_memory_updated_at")
53
+
54
+ return cls(
55
+ user_id=str(user_stats_dict["user_id"]),
56
+ total_memories=user_stats_dict["total_memories"],
57
+ last_memory_updated_at=datetime.fromtimestamp(updated_at, tz=timezone.utc) if updated_at else None,
58
+ )
@@ -0,0 +1,3 @@
1
+ from agno.os.routers.metrics.metrics import get_metrics_router
2
+
3
+ __all__ = ["get_metrics_router"]