agno 1.8.1__py3-none-any.whl → 2.0.0a1__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 (580) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +2778 -4123
  4. agno/api/agent.py +9 -65
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +6 -17
  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 +9 -64
  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 +1749 -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 +1438 -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 +888 -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 +1051 -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 +1417 -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 +298 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1720 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +281 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1371 -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 +1722 -0
  67. agno/db/singlestore/utils.py +327 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1680 -0
  71. agno/db/sqlite/utils.py +269 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +142 -43
  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 +10 -10
  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 +1515 -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 +68 -15
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/knowledge/reader/gcs_reader.py +67 -0
  118. agno/{document → knowledge}/reader/json_reader.py +30 -9
  119. agno/{document → knowledge}/reader/markdown_reader.py +36 -9
  120. agno/{document → knowledge}/reader/pdf_reader.py +79 -21
  121. agno/knowledge/reader/reader_factory.py +275 -0
  122. agno/knowledge/reader/s3_reader.py +171 -0
  123. agno/{document → knowledge}/reader/text_reader.py +31 -10
  124. agno/knowledge/reader/url_reader.py +84 -0
  125. agno/knowledge/reader/web_search_reader.py +389 -0
  126. agno/{document → knowledge}/reader/website_reader.py +37 -10
  127. agno/knowledge/reader/wikipedia_reader.py +59 -0
  128. agno/knowledge/reader/youtube_reader.py +78 -0
  129. agno/knowledge/remote_content/remote_content.py +88 -0
  130. agno/{reranker → knowledge/reranker}/base.py +1 -1
  131. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  132. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  133. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  134. agno/knowledge/types.py +30 -0
  135. agno/knowledge/utils.py +169 -0
  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 +129 -82
  141. agno/models/aws/bedrock.py +107 -175
  142. agno/models/aws/claude.py +64 -18
  143. agno/models/azure/ai_foundry.py +73 -23
  144. agno/models/base.py +347 -287
  145. agno/models/cerebras/cerebras.py +84 -27
  146. agno/models/cohere/chat.py +106 -98
  147. agno/models/google/gemini.py +100 -42
  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 +38 -144
  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 +84 -46
  158. agno/models/openai/chat.py +121 -23
  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 +14 -8
  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 +393 -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 +65 -28
  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 +33 -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 +30 -0
  184. agno/os/router.py +843 -0
  185. agno/os/routers/__init__.py +3 -0
  186. agno/os/routers/evals/__init__.py +3 -0
  187. agno/os/routers/evals/evals.py +204 -0
  188. agno/os/routers/evals/schemas.py +142 -0
  189. agno/os/routers/evals/utils.py +161 -0
  190. agno/os/routers/knowledge/__init__.py +3 -0
  191. agno/os/routers/knowledge/knowledge.py +413 -0
  192. agno/os/routers/knowledge/schemas.py +118 -0
  193. agno/os/routers/memory/__init__.py +3 -0
  194. agno/os/routers/memory/memory.py +179 -0
  195. agno/os/routers/memory/schemas.py +58 -0
  196. agno/os/routers/metrics/__init__.py +3 -0
  197. agno/os/routers/metrics/metrics.py +58 -0
  198. agno/os/routers/metrics/schemas.py +47 -0
  199. agno/os/routers/session/__init__.py +3 -0
  200. agno/os/routers/session/session.py +163 -0
  201. agno/os/schema.py +892 -0
  202. agno/{app/playground → os}/settings.py +8 -15
  203. agno/os/utils.py +270 -0
  204. agno/reasoning/azure_ai_foundry.py +4 -4
  205. agno/reasoning/deepseek.py +4 -4
  206. agno/reasoning/default.py +6 -11
  207. agno/reasoning/groq.py +4 -4
  208. agno/reasoning/helpers.py +4 -6
  209. agno/reasoning/ollama.py +4 -4
  210. agno/reasoning/openai.py +4 -4
  211. agno/run/{response.py → agent.py} +144 -72
  212. agno/run/base.py +44 -58
  213. agno/run/cancel.py +83 -0
  214. agno/run/team.py +133 -77
  215. agno/run/workflow.py +537 -12
  216. agno/session/__init__.py +10 -0
  217. agno/session/agent.py +244 -0
  218. agno/session/summary.py +225 -0
  219. agno/session/team.py +262 -0
  220. agno/{storage/session/v2 → session}/workflow.py +47 -24
  221. agno/team/__init__.py +15 -16
  222. agno/team/team.py +2961 -4253
  223. agno/tools/agentql.py +14 -5
  224. agno/tools/airflow.py +9 -4
  225. agno/tools/api.py +7 -3
  226. agno/tools/apify.py +2 -46
  227. agno/tools/arxiv.py +8 -3
  228. agno/tools/aws_lambda.py +7 -5
  229. agno/tools/aws_ses.py +7 -1
  230. agno/tools/baidusearch.py +4 -1
  231. agno/tools/bitbucket.py +4 -4
  232. agno/tools/brandfetch.py +14 -11
  233. agno/tools/bravesearch.py +4 -1
  234. agno/tools/brightdata.py +42 -22
  235. agno/tools/browserbase.py +13 -4
  236. agno/tools/calcom.py +12 -10
  237. agno/tools/calculator.py +10 -27
  238. agno/tools/cartesia.py +18 -13
  239. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  240. agno/tools/confluence.py +8 -8
  241. agno/tools/crawl4ai.py +7 -1
  242. agno/tools/csv_toolkit.py +9 -8
  243. agno/tools/dalle.py +18 -11
  244. agno/tools/daytona.py +13 -16
  245. agno/tools/decorator.py +6 -3
  246. agno/tools/desi_vocal.py +16 -7
  247. agno/tools/discord.py +11 -8
  248. agno/tools/docker.py +30 -42
  249. agno/tools/duckdb.py +34 -53
  250. agno/tools/duckduckgo.py +8 -7
  251. agno/tools/e2b.py +61 -61
  252. agno/tools/eleven_labs.py +35 -28
  253. agno/tools/email.py +4 -1
  254. agno/tools/evm.py +7 -1
  255. agno/tools/exa.py +19 -14
  256. agno/tools/fal.py +29 -29
  257. agno/tools/file.py +9 -8
  258. agno/tools/financial_datasets.py +25 -44
  259. agno/tools/firecrawl.py +22 -22
  260. agno/tools/function.py +68 -17
  261. agno/tools/giphy.py +22 -10
  262. agno/tools/github.py +48 -126
  263. agno/tools/gmail.py +45 -61
  264. agno/tools/google_bigquery.py +7 -6
  265. agno/tools/google_maps.py +11 -26
  266. agno/tools/googlesearch.py +7 -2
  267. agno/tools/googlesheets.py +21 -17
  268. agno/tools/hackernews.py +9 -5
  269. agno/tools/jina.py +5 -4
  270. agno/tools/jira.py +18 -9
  271. agno/tools/knowledge.py +31 -32
  272. agno/tools/linear.py +18 -33
  273. agno/tools/linkup.py +5 -1
  274. agno/tools/local_file_system.py +8 -5
  275. agno/tools/lumalab.py +31 -19
  276. agno/tools/mem0.py +18 -12
  277. agno/tools/memori.py +14 -10
  278. agno/tools/mlx_transcribe.py +3 -2
  279. agno/tools/models/azure_openai.py +32 -14
  280. agno/tools/models/gemini.py +58 -31
  281. agno/tools/models/groq.py +29 -20
  282. agno/tools/models/nebius.py +27 -11
  283. agno/tools/models_labs.py +39 -15
  284. agno/tools/moviepy_video.py +7 -6
  285. agno/tools/neo4j.py +10 -8
  286. agno/tools/newspaper.py +7 -2
  287. agno/tools/newspaper4k.py +8 -3
  288. agno/tools/openai.py +57 -26
  289. agno/tools/openbb.py +12 -11
  290. agno/tools/opencv.py +62 -46
  291. agno/tools/openweather.py +14 -12
  292. agno/tools/pandas.py +11 -3
  293. agno/tools/postgres.py +4 -12
  294. agno/tools/pubmed.py +4 -1
  295. agno/tools/python.py +9 -22
  296. agno/tools/reasoning.py +35 -27
  297. agno/tools/reddit.py +11 -26
  298. agno/tools/replicate.py +54 -41
  299. agno/tools/resend.py +4 -1
  300. agno/tools/scrapegraph.py +15 -14
  301. agno/tools/searxng.py +10 -23
  302. agno/tools/serpapi.py +6 -3
  303. agno/tools/serper.py +13 -4
  304. agno/tools/shell.py +9 -2
  305. agno/tools/slack.py +12 -11
  306. agno/tools/sleep.py +3 -2
  307. agno/tools/spider.py +24 -4
  308. agno/tools/sql.py +7 -6
  309. agno/tools/tavily.py +6 -4
  310. agno/tools/telegram.py +12 -4
  311. agno/tools/todoist.py +11 -31
  312. agno/tools/toolkit.py +1 -1
  313. agno/tools/trafilatura.py +22 -6
  314. agno/tools/trello.py +9 -22
  315. agno/tools/twilio.py +10 -3
  316. agno/tools/user_control_flow.py +6 -1
  317. agno/tools/valyu.py +34 -5
  318. agno/tools/visualization.py +19 -28
  319. agno/tools/webbrowser.py +4 -3
  320. agno/tools/webex.py +11 -7
  321. agno/tools/website.py +15 -46
  322. agno/tools/webtools.py +12 -4
  323. agno/tools/whatsapp.py +5 -9
  324. agno/tools/wikipedia.py +20 -13
  325. agno/tools/x.py +14 -13
  326. agno/tools/yfinance.py +13 -40
  327. agno/tools/youtube.py +26 -20
  328. agno/tools/zendesk.py +7 -2
  329. agno/tools/zep.py +10 -7
  330. agno/tools/zoom.py +10 -9
  331. agno/utils/common.py +1 -19
  332. agno/utils/events.py +95 -118
  333. agno/utils/knowledge.py +29 -0
  334. agno/utils/log.py +2 -2
  335. agno/utils/mcp.py +11 -5
  336. agno/utils/media.py +39 -0
  337. agno/utils/message.py +12 -1
  338. agno/utils/models/claude.py +6 -4
  339. agno/utils/models/mistral.py +8 -7
  340. agno/utils/models/schema_utils.py +3 -3
  341. agno/utils/pprint.py +33 -32
  342. agno/utils/print_response/agent.py +779 -0
  343. agno/utils/print_response/team.py +1565 -0
  344. agno/utils/print_response/workflow.py +1451 -0
  345. agno/utils/prompts.py +14 -14
  346. agno/utils/reasoning.py +87 -0
  347. agno/utils/response.py +42 -42
  348. agno/utils/string.py +8 -22
  349. agno/utils/team.py +50 -0
  350. agno/utils/timer.py +2 -2
  351. agno/vectordb/base.py +33 -21
  352. agno/vectordb/cassandra/cassandra.py +287 -23
  353. agno/vectordb/chroma/chromadb.py +482 -59
  354. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  355. agno/vectordb/couchbase/couchbase.py +309 -29
  356. agno/vectordb/lancedb/lance_db.py +360 -21
  357. agno/vectordb/langchaindb/__init__.py +5 -0
  358. agno/vectordb/langchaindb/langchaindb.py +145 -0
  359. agno/vectordb/lightrag/__init__.py +5 -0
  360. agno/vectordb/lightrag/lightrag.py +374 -0
  361. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  362. agno/vectordb/milvus/milvus.py +242 -32
  363. agno/vectordb/mongodb/mongodb.py +200 -24
  364. agno/vectordb/pgvector/pgvector.py +319 -37
  365. agno/vectordb/pineconedb/pineconedb.py +221 -27
  366. agno/vectordb/qdrant/qdrant.py +334 -14
  367. agno/vectordb/singlestore/singlestore.py +286 -29
  368. agno/vectordb/surrealdb/surrealdb.py +187 -7
  369. agno/vectordb/upstashdb/upstashdb.py +342 -26
  370. agno/vectordb/weaviate/weaviate.py +227 -165
  371. agno/workflow/__init__.py +17 -13
  372. agno/workflow/{v2/condition.py → condition.py} +135 -32
  373. agno/workflow/{v2/loop.py → loop.py} +115 -28
  374. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  375. agno/workflow/{v2/router.py → router.py} +133 -32
  376. agno/workflow/{v2/step.py → step.py} +200 -42
  377. agno/workflow/{v2/steps.py → steps.py} +147 -66
  378. agno/workflow/types.py +482 -0
  379. agno/workflow/workflow.py +2394 -696
  380. agno-2.0.0a1.dist-info/METADATA +355 -0
  381. agno-2.0.0a1.dist-info/RECORD +514 -0
  382. agno/agent/metrics.py +0 -107
  383. agno/api/app.py +0 -35
  384. agno/api/playground.py +0 -92
  385. agno/api/schemas/app.py +0 -12
  386. agno/api/schemas/playground.py +0 -22
  387. agno/api/schemas/user.py +0 -35
  388. agno/api/schemas/workspace.py +0 -46
  389. agno/api/user.py +0 -160
  390. agno/api/workflows.py +0 -33
  391. agno/api/workspace.py +0 -175
  392. agno/app/agui/__init__.py +0 -3
  393. agno/app/agui/app.py +0 -17
  394. agno/app/agui/sync_router.py +0 -120
  395. agno/app/base.py +0 -186
  396. agno/app/discord/__init__.py +0 -3
  397. agno/app/fastapi/__init__.py +0 -3
  398. agno/app/fastapi/app.py +0 -107
  399. agno/app/fastapi/async_router.py +0 -457
  400. agno/app/fastapi/sync_router.py +0 -448
  401. agno/app/playground/app.py +0 -228
  402. agno/app/playground/async_router.py +0 -1050
  403. agno/app/playground/deploy.py +0 -249
  404. agno/app/playground/operator.py +0 -183
  405. agno/app/playground/schemas.py +0 -220
  406. agno/app/playground/serve.py +0 -55
  407. agno/app/playground/sync_router.py +0 -1042
  408. agno/app/playground/utils.py +0 -46
  409. agno/app/settings.py +0 -15
  410. agno/app/slack/__init__.py +0 -3
  411. agno/app/slack/app.py +0 -19
  412. agno/app/slack/sync_router.py +0 -92
  413. agno/app/utils.py +0 -54
  414. agno/app/whatsapp/__init__.py +0 -3
  415. agno/app/whatsapp/app.py +0 -15
  416. agno/app/whatsapp/sync_router.py +0 -197
  417. agno/cli/auth_server.py +0 -249
  418. agno/cli/config.py +0 -274
  419. agno/cli/console.py +0 -88
  420. agno/cli/credentials.py +0 -23
  421. agno/cli/entrypoint.py +0 -571
  422. agno/cli/operator.py +0 -357
  423. agno/cli/settings.py +0 -96
  424. agno/cli/ws/ws_cli.py +0 -817
  425. agno/constants.py +0 -13
  426. agno/document/__init__.py +0 -5
  427. agno/document/chunking/semantic.py +0 -45
  428. agno/document/chunking/strategy.py +0 -31
  429. agno/document/reader/__init__.py +0 -5
  430. agno/document/reader/base.py +0 -47
  431. agno/document/reader/docx_reader.py +0 -60
  432. agno/document/reader/gcs/pdf_reader.py +0 -44
  433. agno/document/reader/s3/pdf_reader.py +0 -59
  434. agno/document/reader/s3/text_reader.py +0 -63
  435. agno/document/reader/url_reader.py +0 -59
  436. agno/document/reader/youtube_reader.py +0 -58
  437. agno/embedder/__init__.py +0 -5
  438. agno/embedder/langdb.py +0 -80
  439. agno/embedder/mistral.py +0 -82
  440. agno/embedder/openai.py +0 -78
  441. agno/file/__init__.py +0 -5
  442. agno/file/file.py +0 -16
  443. agno/file/local/csv.py +0 -32
  444. agno/file/local/txt.py +0 -19
  445. agno/infra/app.py +0 -240
  446. agno/infra/base.py +0 -144
  447. agno/infra/context.py +0 -20
  448. agno/infra/db_app.py +0 -52
  449. agno/infra/resource.py +0 -205
  450. agno/infra/resources.py +0 -55
  451. agno/knowledge/agent.py +0 -702
  452. agno/knowledge/arxiv.py +0 -33
  453. agno/knowledge/combined.py +0 -36
  454. agno/knowledge/csv.py +0 -144
  455. agno/knowledge/csv_url.py +0 -124
  456. agno/knowledge/document.py +0 -223
  457. agno/knowledge/docx.py +0 -137
  458. agno/knowledge/firecrawl.py +0 -34
  459. agno/knowledge/gcs/__init__.py +0 -0
  460. agno/knowledge/gcs/base.py +0 -39
  461. agno/knowledge/gcs/pdf.py +0 -125
  462. agno/knowledge/json.py +0 -137
  463. agno/knowledge/langchain.py +0 -71
  464. agno/knowledge/light_rag.py +0 -273
  465. agno/knowledge/llamaindex.py +0 -66
  466. agno/knowledge/markdown.py +0 -154
  467. agno/knowledge/pdf.py +0 -164
  468. agno/knowledge/pdf_bytes.py +0 -42
  469. agno/knowledge/pdf_url.py +0 -148
  470. agno/knowledge/s3/__init__.py +0 -0
  471. agno/knowledge/s3/base.py +0 -64
  472. agno/knowledge/s3/pdf.py +0 -33
  473. agno/knowledge/s3/text.py +0 -34
  474. agno/knowledge/text.py +0 -141
  475. agno/knowledge/url.py +0 -46
  476. agno/knowledge/website.py +0 -179
  477. agno/knowledge/wikipedia.py +0 -32
  478. agno/knowledge/youtube.py +0 -35
  479. agno/memory/agent.py +0 -423
  480. agno/memory/classifier.py +0 -104
  481. agno/memory/db/__init__.py +0 -5
  482. agno/memory/db/base.py +0 -42
  483. agno/memory/db/mongodb.py +0 -189
  484. agno/memory/db/postgres.py +0 -203
  485. agno/memory/db/sqlite.py +0 -193
  486. agno/memory/memory.py +0 -22
  487. agno/memory/row.py +0 -36
  488. agno/memory/summarizer.py +0 -201
  489. agno/memory/summary.py +0 -19
  490. agno/memory/team.py +0 -415
  491. agno/memory/v2/__init__.py +0 -2
  492. agno/memory/v2/db/__init__.py +0 -1
  493. agno/memory/v2/db/base.py +0 -42
  494. agno/memory/v2/db/firestore.py +0 -339
  495. agno/memory/v2/db/mongodb.py +0 -196
  496. agno/memory/v2/db/postgres.py +0 -214
  497. agno/memory/v2/db/redis.py +0 -187
  498. agno/memory/v2/db/schema.py +0 -54
  499. agno/memory/v2/db/sqlite.py +0 -209
  500. agno/memory/v2/manager.py +0 -437
  501. agno/memory/v2/memory.py +0 -1097
  502. agno/memory/v2/schema.py +0 -55
  503. agno/memory/v2/summarizer.py +0 -215
  504. agno/memory/workflow.py +0 -38
  505. agno/models/ollama/tools.py +0 -430
  506. agno/models/qwen/__init__.py +0 -5
  507. agno/playground/__init__.py +0 -10
  508. agno/playground/deploy.py +0 -3
  509. agno/playground/playground.py +0 -3
  510. agno/playground/serve.py +0 -3
  511. agno/playground/settings.py +0 -3
  512. agno/reranker/__init__.py +0 -0
  513. agno/run/v2/__init__.py +0 -0
  514. agno/run/v2/workflow.py +0 -567
  515. agno/storage/__init__.py +0 -0
  516. agno/storage/agent/__init__.py +0 -0
  517. agno/storage/agent/dynamodb.py +0 -1
  518. agno/storage/agent/json.py +0 -1
  519. agno/storage/agent/mongodb.py +0 -1
  520. agno/storage/agent/postgres.py +0 -1
  521. agno/storage/agent/singlestore.py +0 -1
  522. agno/storage/agent/sqlite.py +0 -1
  523. agno/storage/agent/yaml.py +0 -1
  524. agno/storage/base.py +0 -60
  525. agno/storage/dynamodb.py +0 -673
  526. agno/storage/firestore.py +0 -297
  527. agno/storage/gcs_json.py +0 -261
  528. agno/storage/in_memory.py +0 -234
  529. agno/storage/json.py +0 -237
  530. agno/storage/mongodb.py +0 -328
  531. agno/storage/mysql.py +0 -685
  532. agno/storage/postgres.py +0 -682
  533. agno/storage/redis.py +0 -336
  534. agno/storage/session/__init__.py +0 -16
  535. agno/storage/session/agent.py +0 -64
  536. agno/storage/session/team.py +0 -63
  537. agno/storage/session/v2/__init__.py +0 -5
  538. agno/storage/session/workflow.py +0 -61
  539. agno/storage/singlestore.py +0 -606
  540. agno/storage/sqlite.py +0 -646
  541. agno/storage/workflow/__init__.py +0 -0
  542. agno/storage/workflow/mongodb.py +0 -1
  543. agno/storage/workflow/postgres.py +0 -1
  544. agno/storage/workflow/sqlite.py +0 -1
  545. agno/storage/yaml.py +0 -241
  546. agno/tools/thinking.py +0 -73
  547. agno/utils/defaults.py +0 -57
  548. agno/utils/filesystem.py +0 -39
  549. agno/utils/git.py +0 -52
  550. agno/utils/json_io.py +0 -30
  551. agno/utils/load_env.py +0 -19
  552. agno/utils/py_io.py +0 -19
  553. agno/utils/pyproject.py +0 -18
  554. agno/utils/resource_filter.py +0 -31
  555. agno/workflow/v2/__init__.py +0 -21
  556. agno/workflow/v2/types.py +0 -357
  557. agno/workflow/v2/workflow.py +0 -3312
  558. agno/workspace/__init__.py +0 -0
  559. agno/workspace/config.py +0 -325
  560. agno/workspace/enums.py +0 -6
  561. agno/workspace/helpers.py +0 -52
  562. agno/workspace/operator.py +0 -757
  563. agno/workspace/settings.py +0 -158
  564. agno-1.8.1.dist-info/METADATA +0 -982
  565. agno-1.8.1.dist-info/RECORD +0 -566
  566. agno-1.8.1.dist-info/entry_points.txt +0 -3
  567. /agno/{app → db/migrations}/__init__.py +0 -0
  568. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  569. /agno/{cli → integrations}/__init__.py +0 -0
  570. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  571. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  572. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  573. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  574. /agno/{app → os/interfaces}/slack/security.py +0 -0
  575. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  576. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  577. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  578. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
  579. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
  580. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/top_level.txt +0 -0
agno/memory/v2/memory.py DELETED
@@ -1,1097 +0,0 @@
1
- import json
2
- from copy import deepcopy
3
- from dataclasses import dataclass, field
4
- from datetime import datetime
5
- from os import getenv
6
- from typing import Any, Dict, List, Literal, Optional, Type, Union
7
-
8
- from pydantic import BaseModel, Field
9
-
10
- from agno.media import AudioArtifact, ImageArtifact, VideoArtifact
11
- from agno.memory.v2.db.base import MemoryDb
12
- from agno.memory.v2.db.schema import MemoryRow
13
- from agno.memory.v2.manager import MemoryManager
14
- from agno.memory.v2.schema import SessionSummary, UserMemory
15
- from agno.memory.v2.summarizer import SessionSummarizer
16
- from agno.models.base import Model
17
- from agno.models.message import Message
18
- from agno.run.base import RunStatus
19
- from agno.run.response import RunResponse
20
- from agno.run.team import TeamRunResponse
21
- from agno.utils.log import log_debug, log_warning, logger, set_log_level_to_debug, set_log_level_to_info
22
- from agno.utils.prompts import get_json_output_prompt
23
- from agno.utils.string import parse_response_model_str
24
-
25
-
26
- class MemorySearchResponse(BaseModel):
27
- """Model for Memory Search Response."""
28
-
29
- memory_ids: List[str] = Field(
30
- ..., description="The IDs of the memories that are most semantically similar to the query."
31
- )
32
-
33
-
34
- @dataclass
35
- class TeamMemberInteraction:
36
- member_name: str
37
- task: str
38
- response: Union[RunResponse, TeamRunResponse]
39
-
40
- def to_dict(self) -> Dict[str, Any]:
41
- return {
42
- "member_name": self.member_name,
43
- "task": self.task,
44
- "response": self.response.to_dict(),
45
- }
46
-
47
- @classmethod
48
- def from_dict(cls, data: Dict[str, Any]) -> "TeamMemberInteraction":
49
- if data["response"].get("agent_id"):
50
- return cls(
51
- member_name=data["member_name"], task=data["task"], response=RunResponse.from_dict(data["response"])
52
- )
53
- else:
54
- return cls(
55
- member_name=data["member_name"], task=data["task"], response=TeamRunResponse.from_dict(data["response"])
56
- )
57
-
58
-
59
- @dataclass
60
- class TeamContext:
61
- # List of team member interaction, represented as a request and a response
62
- member_interactions: List[TeamMemberInteraction] = field(default_factory=list)
63
- text: Optional[str] = None
64
-
65
- def to_dict(self) -> Dict[str, Any]:
66
- return {
67
- "member_interactions": [interaction.to_dict() for interaction in self.member_interactions],
68
- "text": self.text,
69
- }
70
-
71
- @classmethod
72
- def from_dict(cls, data: Dict[str, Any]) -> "TeamContext":
73
- return cls(
74
- member_interactions=[
75
- TeamMemberInteraction.from_dict(interaction) for interaction in data["member_interactions"]
76
- ],
77
- text=data["text"],
78
- )
79
-
80
-
81
- @dataclass
82
- class Memory:
83
- # Model used for memories and summaries
84
- model: Optional[Model] = None
85
-
86
- # Memories per memory ID per user
87
- memories: Optional[Dict[str, Dict[str, UserMemory]]] = None
88
- # Manager to manage memories
89
- memory_manager: Optional[MemoryManager] = None
90
-
91
- # Session summaries per session per user
92
- summaries: Optional[Dict[str, Dict[str, SessionSummary]]] = None
93
- # Summarizer to generate session summaries
94
- summary_manager: Optional[SessionSummarizer] = None
95
-
96
- db: Optional[MemoryDb] = None
97
-
98
- # runs per session
99
- runs: Optional[Dict[str, List[Union[RunResponse, TeamRunResponse]]]] = None
100
-
101
- # Team context per session
102
- team_context: Optional[Dict[str, TeamContext]] = None
103
-
104
- # Whether to delete memories
105
- delete_memories: bool = False
106
- # Whether to clear memories
107
- clear_memories: bool = False
108
-
109
- debug_mode: bool = False
110
- version: int = 2
111
-
112
- def __init__(
113
- self,
114
- model: Optional[Model] = None,
115
- memory_manager: Optional[MemoryManager] = None,
116
- summarizer: Optional[SessionSummarizer] = None,
117
- db: Optional[MemoryDb] = None,
118
- memories: Optional[Dict[str, Dict[str, UserMemory]]] = None,
119
- summaries: Optional[Dict[str, Dict[str, SessionSummary]]] = None,
120
- runs: Optional[Dict[str, List[Union[RunResponse, TeamRunResponse]]]] = None,
121
- debug_mode: bool = False,
122
- delete_memories: bool = False,
123
- clear_memories: bool = False,
124
- ):
125
- self.memories = memories or {}
126
- self.summaries = summaries or {}
127
- self.runs = runs or {}
128
-
129
- self.debug_mode = debug_mode
130
-
131
- self.delete_memories = delete_memories
132
- self.clear_memories = clear_memories
133
-
134
- self.model = model
135
-
136
- if self.model is not None and isinstance(self.model, str):
137
- raise ValueError("Model must be a Model object, not a string")
138
-
139
- self.memory_manager = memory_manager
140
-
141
- self.summary_manager = summarizer
142
-
143
- self.db = db
144
-
145
- # We are making memories
146
- if self.model is not None:
147
- if self.memory_manager is None:
148
- self.memory_manager = MemoryManager(model=deepcopy(self.model))
149
- # Set the model on the memory manager if it is not set
150
- if self.memory_manager.model is None:
151
- self.memory_manager.model = deepcopy(self.model)
152
-
153
- # We are making session summaries
154
- if self.model is not None:
155
- if self.summary_manager is None:
156
- self.summary_manager = SessionSummarizer(model=deepcopy(self.model))
157
- # Set the model on the summary_manager if it is not set
158
- elif self.summary_manager.model is None:
159
- self.summary_manager.model = deepcopy(self.model)
160
-
161
- self.debug_mode = debug_mode
162
-
163
- def set_model(self, model: Model) -> None:
164
- if self.memory_manager is None:
165
- self.memory_manager = MemoryManager(model=deepcopy(model))
166
- if self.memory_manager.model is None:
167
- self.memory_manager.model = deepcopy(model)
168
- if self.summary_manager is None:
169
- self.summary_manager = SessionSummarizer(model=deepcopy(model))
170
- if self.summary_manager.model is None:
171
- self.summary_manager.model = deepcopy(model)
172
-
173
- def get_model(self) -> Model:
174
- if self.model is None:
175
- try:
176
- from agno.models.openai import OpenAIChat
177
- except ModuleNotFoundError as e:
178
- logger.exception(e)
179
- logger.error(
180
- "Agno uses `openai` as the default model provider. Please provide a `model` or install `openai`."
181
- )
182
- exit(1)
183
- self.model = OpenAIChat(id="gpt-4o")
184
- return self.model
185
-
186
- def refresh_from_db(self, user_id: Optional[str] = None):
187
- if self.db:
188
- # If no user_id is provided, read all memories
189
- if user_id is None:
190
- all_memories = self.db.read_memories()
191
- else:
192
- all_memories = self.db.read_memories(user_id=user_id)
193
-
194
- # Reset the memories
195
- self.memories = {}
196
- for memory in all_memories:
197
- if memory.user_id is not None and memory.id is not None:
198
- self.memories.setdefault(memory.user_id, {})[memory.id] = UserMemory.from_dict(memory.memory)
199
-
200
- def set_log_level(self):
201
- if self.debug_mode or getenv("AGNO_DEBUG", "false").lower() == "true":
202
- self.debug_mode = True
203
- set_log_level_to_debug()
204
- else:
205
- set_log_level_to_info()
206
-
207
- def initialize(self, user_id: Optional[str] = None):
208
- self.set_log_level()
209
- self.refresh_from_db(user_id=user_id)
210
-
211
- def to_dict(self) -> Dict[str, Any]:
212
- _memory_dict = {}
213
- # Add summary if it exists
214
- if self.summaries is not None:
215
- _memory_dict["summaries"] = {
216
- user_id: {session_id: summary.to_dict() for session_id, summary in session_summaries.items()}
217
- for user_id, session_summaries in self.summaries.items()
218
- }
219
- # Add memories if they exist
220
- if self.memories is not None:
221
- _memory_dict["memories"] = {
222
- user_id: {memory_id: memory.to_dict() for memory_id, memory in user_memories.items()}
223
- for user_id, user_memories in self.memories.items()
224
- }
225
- # Add runs if they exist
226
- if self.runs is not None:
227
- _memory_dict["runs"] = {}
228
- for session_id, runs in self.runs.items():
229
- if session_id is not None:
230
- _memory_dict["runs"][session_id] = [run.to_dict() for run in runs] # type: ignore
231
-
232
- if self.team_context is not None:
233
- _memory_dict["team_context"] = {}
234
- for session_id, team_context in self.team_context.items():
235
- if session_id is not None:
236
- _memory_dict["team_context"][session_id] = team_context.to_dict()
237
-
238
- _memory_dict = {k: v for k, v in _memory_dict.items() if v is not None}
239
- return _memory_dict
240
-
241
- # -*- Public Functions
242
- def get_user_memories(self, user_id: Optional[str] = None) -> List[UserMemory]:
243
- """Get the user memories for a given user id"""
244
- if user_id is None:
245
- user_id = "default"
246
-
247
- self.refresh_from_db(user_id=user_id)
248
-
249
- if self.memories is None:
250
- return []
251
- return list(self.memories.get(user_id, {}).values())
252
-
253
- def get_session_summaries(self, user_id: Optional[str] = None) -> List[SessionSummary]:
254
- """Get the session summaries for a given user id"""
255
- if user_id is None:
256
- user_id = "default"
257
- self.refresh_from_db(user_id=user_id)
258
- if self.summaries is None:
259
- return []
260
- return list(self.summaries.get(user_id, {}).values())
261
-
262
- def get_user_memory(self, memory_id: str, user_id: Optional[str] = None) -> Optional[UserMemory]:
263
- """Get the user memory for a given user id"""
264
- if user_id is None:
265
- user_id = "default"
266
- self.refresh_from_db(user_id=user_id)
267
- if self.memories is None:
268
- return None
269
- return self.memories.get(user_id, {}).get(memory_id, None)
270
-
271
- def get_session_summary(self, session_id: str, user_id: Optional[str] = None) -> Optional[SessionSummary]:
272
- """Get the session summary for a given user id"""
273
- if user_id is None:
274
- user_id = "default"
275
- if self.summaries is None:
276
- return None
277
- return self.summaries.get(user_id, {}).get(session_id, None)
278
-
279
- def add_user_memory(
280
- self,
281
- memory: UserMemory,
282
- user_id: Optional[str] = None,
283
- refresh_from_db: bool = True,
284
- ) -> str:
285
- """Add a user memory for a given user id
286
- Args:
287
- memory (UserMemory): The memory to add
288
- user_id (Optional[str]): The user id to add the memory to. If not provided, the memory is added to the "default" user.
289
- Returns:
290
- str: The id of the memory
291
- """
292
- from uuid import uuid4
293
-
294
- memory_id = memory.memory_id or str(uuid4())
295
- if memory.memory_id is None:
296
- memory.memory_id = memory_id
297
- if user_id is None:
298
- user_id = "default"
299
-
300
- # Refresh from the DB
301
- if refresh_from_db:
302
- self.refresh_from_db(user_id=user_id)
303
-
304
- if not memory.last_updated:
305
- memory.last_updated = datetime.now()
306
-
307
- self.memories.setdefault(user_id, {})[memory_id] = memory # type: ignore
308
- if self.db:
309
- self._upsert_db_memory(
310
- memory=MemoryRow(
311
- id=memory_id,
312
- user_id=user_id,
313
- memory=memory.to_dict(),
314
- last_updated=memory.last_updated or datetime.now(),
315
- )
316
- )
317
-
318
- return memory_id
319
-
320
- def replace_user_memory(
321
- self,
322
- memory_id: str,
323
- memory: UserMemory,
324
- user_id: Optional[str] = None,
325
- refresh_from_db: bool = True,
326
- ) -> Optional[str]:
327
- """Replace a user memory for a given user id
328
- Args:
329
- memory_id (str): The id of the memory to replace
330
- memory (UserMemory): The memory to add
331
- user_id (Optional[str]): The user id to add the memory to. If not provided, the memory is added to the "default" user.
332
- Returns:
333
- str: The id of the memory
334
- """
335
-
336
- if user_id is None:
337
- user_id = "default"
338
-
339
- # Refresh from the DB
340
- if refresh_from_db:
341
- self.refresh_from_db(user_id=user_id)
342
-
343
- if not memory.last_updated:
344
- memory.last_updated = datetime.now()
345
-
346
- if memory_id not in self.memories[user_id]: # type: ignore
347
- log_warning(f"Memory {memory_id} not found for user {user_id}")
348
- return None
349
-
350
- self.memories.setdefault(user_id, {})[memory_id] = memory # type: ignore
351
- if self.db:
352
- self._upsert_db_memory(
353
- memory=MemoryRow(
354
- id=memory_id,
355
- user_id=user_id,
356
- memory=memory.to_dict(),
357
- last_updated=memory.last_updated or datetime.now(),
358
- )
359
- )
360
-
361
- return memory_id
362
-
363
- def delete_user_memory(
364
- self,
365
- memory_id: str,
366
- user_id: Optional[str] = None,
367
- refresh_from_db: bool = True,
368
- ) -> None:
369
- """Delete a user memory for a given user id
370
- Args:
371
- memory_id (str): The id of the memory to delete
372
- user_id (Optional[str]): The user id to delete the memory from. If not provided, the memory is deleted from the "default" user.
373
- """
374
- if user_id is None:
375
- user_id = "default"
376
-
377
- # Refresh from the DB
378
- if refresh_from_db:
379
- self.refresh_from_db(user_id=user_id)
380
-
381
- if memory_id not in self.memories[user_id]: # type: ignore
382
- log_warning(f"Memory {memory_id} not found for user {user_id}")
383
- return None
384
-
385
- del self.memories[user_id][memory_id] # type: ignore
386
- if self.db:
387
- self._delete_db_memory(memory_id=memory_id)
388
-
389
- def delete_session_summary(self, user_id: str, session_id: str) -> None:
390
- """Delete a session summary for a given user id
391
- Args:
392
- user_id (str): The user id to delete the memory from
393
- session_id (str): The id of the session to delete
394
- """
395
- del self.summaries[user_id][session_id] # type: ignore
396
-
397
- def get_runs(self, session_id: str) -> List[Union[RunResponse, TeamRunResponse]]:
398
- """Get all runs for a given session id"""
399
- if self.runs is None:
400
- return []
401
- return self.runs.get(session_id, [])
402
-
403
- # -*- Agent Functions
404
- def create_session_summary(self, session_id: str, user_id: Optional[str] = None) -> Optional[SessionSummary]:
405
- """Creates a summary of the session"""
406
-
407
- if not self.summary_manager:
408
- raise ValueError("Summarizer not initialized")
409
-
410
- self.set_log_level()
411
-
412
- if user_id is None:
413
- user_id = "default"
414
-
415
- summary_response = self.summary_manager.run(conversation=self.get_messages_for_session(session_id=session_id))
416
- if summary_response is None:
417
- return None
418
- session_summary = SessionSummary(
419
- summary=summary_response.summary, topics=summary_response.topics, last_updated=datetime.now()
420
- )
421
- self.summaries.setdefault(user_id, {})[session_id] = session_summary # type: ignore
422
-
423
- return session_summary
424
-
425
- async def acreate_session_summary(self, session_id: str, user_id: Optional[str] = None) -> Optional[SessionSummary]:
426
- """Creates a summary of the session"""
427
- if not self.summary_manager:
428
- raise ValueError("Summarizer not initialized")
429
-
430
- self.set_log_level()
431
-
432
- if user_id is None:
433
- user_id = "default"
434
-
435
- summary_response = await self.summary_manager.arun(
436
- conversation=self.get_messages_for_session(session_id=session_id)
437
- )
438
- if summary_response is None:
439
- return None
440
- session_summary = SessionSummary(
441
- summary=summary_response.summary, topics=summary_response.topics, last_updated=datetime.now()
442
- )
443
- self.summaries.setdefault(user_id, {})[session_id] = session_summary # type: ignore
444
- return session_summary
445
-
446
- def create_user_memories(
447
- self,
448
- message: Optional[str] = None,
449
- messages: Optional[List[Message]] = None,
450
- user_id: Optional[str] = None,
451
- refresh_from_db: bool = True,
452
- ) -> str:
453
- """Creates memories from multiple messages and adds them to the memory db."""
454
- self.set_log_level()
455
- if not messages and not message:
456
- raise ValueError("You must provide either a message or a list of messages")
457
-
458
- if message:
459
- messages = [Message(role="user", content=message)]
460
-
461
- if not messages or not isinstance(messages, list):
462
- raise ValueError("Invalid messages list")
463
-
464
- if not self.memory_manager:
465
- raise ValueError("Memory manager not initialized")
466
-
467
- if self.db is None:
468
- log_warning("MemoryDb not provided.")
469
- return "Please provide a db to store memories"
470
-
471
- if user_id is None:
472
- user_id = "default"
473
-
474
- if refresh_from_db:
475
- self.refresh_from_db(user_id=user_id)
476
-
477
- existing_memories = self.memories.get(user_id, {}) # type: ignore
478
- existing_memories = [
479
- {"memory_id": memory_id, "memory": memory.memory} for memory_id, memory in existing_memories.items()
480
- ]
481
- response = self.memory_manager.create_or_update_memories( # type: ignore
482
- messages=messages,
483
- existing_memories=existing_memories,
484
- user_id=user_id,
485
- db=self.db,
486
- delete_memories=self.delete_memories,
487
- clear_memories=self.clear_memories,
488
- )
489
-
490
- # We refresh from the DB
491
- self.refresh_from_db(user_id=user_id)
492
- return response
493
-
494
- async def acreate_user_memories(
495
- self,
496
- message: Optional[str] = None,
497
- messages: Optional[List[Message]] = None,
498
- user_id: Optional[str] = None,
499
- refresh_from_db: bool = True,
500
- ) -> str:
501
- """Creates memories from multiple messages and adds them to the memory db."""
502
- self.set_log_level()
503
- if not messages and not message:
504
- raise ValueError("You must provide either a message or a list of messages")
505
-
506
- if message:
507
- messages = [Message(role="user", content=message)]
508
-
509
- if not messages or not isinstance(messages, list):
510
- raise ValueError("Invalid messages list")
511
-
512
- if not self.memory_manager:
513
- raise ValueError("Memory manager not initialized")
514
-
515
- if self.db is None:
516
- log_warning("MemoryDb not provided.")
517
- return "Please provide a db to store memories"
518
-
519
- if user_id is None:
520
- user_id = "default"
521
-
522
- if refresh_from_db:
523
- self.refresh_from_db(user_id=user_id)
524
-
525
- existing_memories = self.memories.get(user_id, {}) # type: ignore
526
- existing_memories = [
527
- {"memory_id": memory_id, "memory": memory.memory} for memory_id, memory in existing_memories.items()
528
- ]
529
-
530
- response = await self.memory_manager.acreate_or_update_memories( # type: ignore
531
- messages=messages,
532
- existing_memories=existing_memories,
533
- user_id=user_id,
534
- db=self.db,
535
- delete_memories=self.delete_memories,
536
- clear_memories=self.clear_memories,
537
- )
538
-
539
- # We refresh from the DB
540
- self.refresh_from_db()
541
-
542
- return response
543
-
544
- def update_memory_task(self, task: str, user_id: Optional[str] = None) -> str:
545
- """Updates the memory with a task"""
546
- if not self.memory_manager:
547
- raise ValueError("Memory manager not initialized")
548
-
549
- if not self.db:
550
- log_warning("MemoryDb not provided.")
551
- return "Please provide a db to store memories"
552
-
553
- if user_id is None:
554
- user_id = "default"
555
-
556
- self.refresh_from_db(user_id=user_id)
557
-
558
- existing_memories = self.memories.get(user_id, {}) # type: ignore
559
- existing_memories = [
560
- {"memory_id": memory_id, "memory": memory.memory} for memory_id, memory in existing_memories.items()
561
- ]
562
- # The memory manager updates the DB directly
563
- response = self.memory_manager.run_memory_task( # type: ignore
564
- task=task,
565
- existing_memories=existing_memories,
566
- user_id=user_id,
567
- db=self.db,
568
- delete_memories=self.delete_memories,
569
- clear_memories=self.clear_memories,
570
- )
571
-
572
- # We refresh from the DB
573
- self.refresh_from_db(user_id=user_id)
574
-
575
- return response
576
-
577
- async def aupdate_memory_task(self, task: str, user_id: Optional[str] = None) -> str:
578
- """Updates the memory with a task"""
579
- self.set_log_level()
580
- if not self.memory_manager:
581
- raise ValueError("Memory manager not initialized")
582
-
583
- if not self.db:
584
- log_warning("MemoryDb not provided.")
585
- return "Please provide a db to store memories"
586
-
587
- if user_id is None:
588
- user_id = "default"
589
-
590
- self.refresh_from_db(user_id=user_id)
591
-
592
- existing_memories = self.memories.get(user_id, {}) # type: ignore
593
- existing_memories = [
594
- {"memory_id": memory_id, "memory": memory.memory} for memory_id, memory in existing_memories.items()
595
- ]
596
- # The memory manager updates the DB directly
597
- response = await self.memory_manager.arun_memory_task( # type: ignore
598
- task=task,
599
- existing_memories=existing_memories,
600
- user_id=user_id,
601
- db=self.db,
602
- delete_memories=self.delete_memories,
603
- clear_memories=self.clear_memories,
604
- )
605
-
606
- # We refresh from the DB
607
- self.refresh_from_db(user_id=user_id)
608
-
609
- return response
610
-
611
- # -*- DB Functions
612
- def _upsert_db_memory(self, memory: MemoryRow) -> str:
613
- """Use this function to add a memory to the database."""
614
- try:
615
- if not self.db:
616
- raise ValueError("Memory db not initialized")
617
- self.db.upsert_memory(memory)
618
- return "Memory added successfully"
619
- except Exception as e:
620
- logger.warning(f"Error storing memory in db: {e}")
621
- return f"Error adding memory: {e}"
622
-
623
- def _delete_db_memory(self, memory_id: str) -> str:
624
- """Use this function to delete a memory from the database."""
625
- try:
626
- if not self.db:
627
- raise ValueError("Memory db not initialized")
628
- self.db.delete_memory(memory_id=memory_id)
629
- return "Memory deleted successfully"
630
- except Exception as e:
631
- logger.warning(f"Error deleting memory in db: {e}")
632
- return f"Error deleting memory: {e}"
633
-
634
- # -*- Utility Functions
635
- def get_messages_for_session(
636
- self,
637
- session_id: str,
638
- user_role: str = "user",
639
- assistant_role: Optional[List[str]] = None,
640
- skip_history_messages: bool = True,
641
- ) -> List[Message]:
642
- """Returns a list of messages for the session that iterate through user message and assistant response."""
643
-
644
- if assistant_role is None:
645
- assistant_role = ["assistant", "model", "CHATBOT"]
646
-
647
- final_messages: List[Message] = []
648
- session_runs = self.runs.get(session_id, []) if self.runs else []
649
- for run_response in session_runs:
650
- if run_response and run_response.messages:
651
- user_message_from_run = None
652
- assistant_message_from_run = None
653
-
654
- # Start from the beginning to look for the user message
655
- for message in run_response.messages:
656
- if hasattr(message, "from_history") and message.from_history and skip_history_messages:
657
- continue
658
- if message.role == user_role:
659
- user_message_from_run = message
660
- break
661
-
662
- # Start from the end to look for the assistant response
663
- for message in run_response.messages[::-1]:
664
- if hasattr(message, "from_history") and message.from_history and skip_history_messages:
665
- continue
666
- if message.role in assistant_role:
667
- assistant_message_from_run = message
668
- break
669
-
670
- if user_message_from_run and assistant_message_from_run:
671
- final_messages.append(user_message_from_run)
672
- final_messages.append(assistant_message_from_run)
673
- return final_messages
674
-
675
- def add_run(self, session_id: str, run: Union[RunResponse, TeamRunResponse]) -> None:
676
- """Adds a RunResponse to the runs list."""
677
- if not self.runs:
678
- self.runs = {}
679
-
680
- if session_id not in self.runs:
681
- self.runs[session_id] = []
682
-
683
- # Check if run already exists with the same run_id
684
- if hasattr(run, "run_id") and run.run_id:
685
- run_id = run.run_id
686
- # Look for existing run with same ID
687
- for i, existing_run in enumerate(self.runs[session_id]):
688
- if hasattr(existing_run, "run_id") and existing_run.run_id == run_id:
689
- # Replace existing run
690
- self.runs[session_id][i] = run
691
- log_debug(f"Replaced existing run with run_id {run_id} in memory")
692
- return
693
-
694
- self.runs[session_id].append(run)
695
- log_debug("Added RunResponse to Memory")
696
-
697
- def get_messages_from_last_n_runs(
698
- self,
699
- session_id: str,
700
- agent_id: Optional[str] = None,
701
- team_id: Optional[str] = None,
702
- last_n: Optional[int] = None,
703
- skip_role: Optional[str] = None,
704
- skip_status: Optional[List[RunStatus]] = None,
705
- skip_history_messages: bool = True,
706
- ) -> List[Message]:
707
- """Returns the messages from the last_n runs, excluding previously tagged history messages.
708
- Args:
709
- session_id: The session id to get the messages from.
710
- agent_id: The id of the agent to get the messages from.
711
- team_id: The id of the team to get the messages from.
712
- last_n: The number of runs to return from the end of the conversation. Defaults to all runs.
713
- skip_role: Skip messages with this role.
714
- skip_status: Skip messages with this status.
715
- skip_history_messages: Skip messages that were tagged as history in previous runs.
716
- Returns:
717
- A list of Messages from the specified runs, excluding history messages.
718
- """
719
- if not self.runs:
720
- return []
721
-
722
- if skip_status is None:
723
- skip_status = [RunStatus.paused, RunStatus.cancelled, RunStatus.error]
724
-
725
- session_runs = self.runs.get(session_id, [])
726
- # Filter by agent_id and team_id
727
- if agent_id:
728
- session_runs = [run for run in session_runs if hasattr(run, "agent_id") and run.agent_id == agent_id] # type: ignore
729
- if team_id:
730
- session_runs = [run for run in session_runs if hasattr(run, "team_id") and run.team_id == team_id] # type: ignore
731
-
732
- # Filter by status
733
- session_runs = [run for run in session_runs if hasattr(run, "status") and run.status not in skip_status] # type: ignore
734
-
735
- # Filter by last_n
736
- runs_to_process = session_runs[-last_n:] if last_n is not None else session_runs
737
- messages_from_history = []
738
- system_message = None
739
- for run_response in runs_to_process:
740
- if not (run_response and run_response.messages):
741
- continue
742
-
743
- for message in run_response.messages:
744
- # Skip messages with specified role
745
- if skip_role and message.role == skip_role:
746
- continue
747
- # Skip messages that were tagged as history in previous runs
748
- if hasattr(message, "from_history") and message.from_history and skip_history_messages:
749
- continue
750
- if message.role == "system":
751
- # Only add the system message once
752
- if system_message is None:
753
- system_message = message
754
- messages_from_history.append(system_message)
755
- else:
756
- messages_from_history.append(message)
757
-
758
- log_debug(f"Getting messages from previous runs: {len(messages_from_history)}")
759
- return messages_from_history
760
-
761
- def get_tool_calls(self, session_id: str, num_calls: Optional[int] = None) -> List[Dict[str, Any]]:
762
- """Returns a list of tool calls from the messages"""
763
-
764
- tool_calls = []
765
- session_runs = self.runs.get(session_id, []) if self.runs else []
766
- for run_response in session_runs[::-1]:
767
- if run_response and run_response.messages:
768
- for message in run_response.messages:
769
- if message.tool_calls:
770
- for tool_call in message.tool_calls:
771
- tool_calls.append(tool_call)
772
- if num_calls and len(tool_calls) >= num_calls:
773
- return tool_calls
774
- return tool_calls
775
-
776
- def search_user_memories(
777
- self,
778
- query: Optional[str] = None,
779
- limit: Optional[int] = None,
780
- retrieval_method: Optional[Literal["last_n", "first_n", "agentic"]] = None,
781
- user_id: Optional[str] = None,
782
- refresh_from_db: bool = True,
783
- ) -> List[UserMemory]:
784
- """Search through user memories using the specified retrieval method.
785
-
786
- Args:
787
- query: The search query for agentic search. Required if retrieval_method is "agentic".
788
- limit: Maximum number of memories to return. Defaults to self.retrieval_limit if not specified. Optional.
789
- retrieval_method: The method to use for retrieving memories. Defaults to self.retrieval if not specified.
790
- - "last_n": Return the most recent memories
791
- - "first_n": Return the oldest memories
792
- - "agentic": Return memories most similar to the query, but using an agentic approach
793
- user_id: The user to search for. Optional.
794
-
795
- Returns:
796
- A list of UserMemory objects matching the search criteria.
797
- """
798
-
799
- if user_id is None:
800
- user_id = "default"
801
-
802
- self.set_log_level()
803
-
804
- if refresh_from_db:
805
- self.refresh_from_db(user_id=user_id)
806
-
807
- if not self.memories:
808
- return []
809
-
810
- # Use default retrieval method if not specified
811
- retrieval_method = retrieval_method
812
- # Use default limit if not specified
813
- limit = limit
814
-
815
- # Handle different retrieval methods
816
- if retrieval_method == "agentic":
817
- if not query:
818
- raise ValueError("Query is required for agentic search")
819
-
820
- return self._search_user_memories_agentic(user_id=user_id, query=query, limit=limit)
821
-
822
- elif retrieval_method == "first_n":
823
- return self._get_first_n_memories(user_id=user_id, limit=limit)
824
-
825
- else: # Default to last_n
826
- return self._get_last_n_memories(user_id=user_id, limit=limit)
827
-
828
- def get_response_format(self) -> Union[Dict[str, Any], Type[BaseModel]]:
829
- model = self.get_model()
830
- if model.supports_native_structured_outputs:
831
- return MemorySearchResponse
832
-
833
- elif model.supports_json_schema_outputs:
834
- return {
835
- "type": "json_schema",
836
- "json_schema": {
837
- "name": MemorySearchResponse.__name__,
838
- "schema": MemorySearchResponse.model_json_schema(),
839
- },
840
- }
841
- else:
842
- return {"type": "json_object"}
843
-
844
- def _search_user_memories_agentic(self, user_id: str, query: str, limit: Optional[int] = None) -> List[UserMemory]:
845
- """Search through user memories using agentic search."""
846
- if not self.memories:
847
- return []
848
-
849
- model = self.get_model()
850
-
851
- response_format = self.get_response_format()
852
-
853
- log_debug("Searching for memories", center=True)
854
-
855
- # Get all memories as a list
856
- user_memories: Dict[str, UserMemory] = self.memories[user_id]
857
- system_message_str = "Your task is to search through user memories and return the IDs of the memories that are related to the query.\n"
858
- system_message_str += "\n<user_memories>\n"
859
- for memory in user_memories.values():
860
- system_message_str += f"ID: {memory.memory_id}\n"
861
- system_message_str += f"Memory: {memory.memory}\n"
862
- if memory.topics:
863
- system_message_str += f"Topics: {','.join(memory.topics)}\n"
864
- system_message_str += "\n"
865
- system_message_str = system_message_str.strip()
866
- system_message_str += "\n</user_memories>\n\n"
867
- system_message_str += "REMEMBER: Only return the IDs of the memories that are related to the query."
868
-
869
- if response_format == {"type": "json_object"}:
870
- system_message_str += "\n" + get_json_output_prompt(MemorySearchResponse) # type: ignore
871
-
872
- messages_for_model = [
873
- Message(role="system", content=system_message_str),
874
- Message(
875
- role="user",
876
- content=f"Return the IDs of the memories related to the following query: {query}",
877
- ),
878
- ]
879
-
880
- # Generate a response from the Model (includes running function calls)
881
- response = model.response(messages=messages_for_model, response_format=response_format)
882
- log_debug("Search for memories complete", center=True)
883
-
884
- memory_search: Optional[MemorySearchResponse] = None
885
- # If the model natively supports structured outputs, the parsed value is already in the structured format
886
- if (
887
- model.supports_native_structured_outputs
888
- and response.parsed is not None
889
- and isinstance(response.parsed, MemorySearchResponse)
890
- ):
891
- memory_search = response.parsed
892
-
893
- # Otherwise convert the response to the structured format
894
- if isinstance(response.content, str):
895
- try:
896
- memory_search = parse_response_model_str(response.content, MemorySearchResponse) # type: ignore
897
-
898
- # Update RunResponse
899
- if memory_search is None:
900
- log_warning("Failed to convert memory_search response to MemorySearchResponse")
901
- return []
902
- except Exception as e:
903
- log_warning(f"Failed to convert memory_search response to MemorySearchResponse: {e}")
904
- return []
905
-
906
- memories_to_return = []
907
- if memory_search:
908
- for memory_id in memory_search.memory_ids:
909
- memories_to_return.append(user_memories[memory_id])
910
- return memories_to_return[:limit]
911
-
912
- def _get_last_n_memories(self, user_id: str, limit: Optional[int] = None) -> List[UserMemory]:
913
- """Get the most recent user memories.
914
-
915
- Args:
916
- limit: Maximum number of memories to return.
917
-
918
- Returns:
919
- A list of the most recent UserMemory objects.
920
- """
921
- if not self.memories:
922
- return []
923
-
924
- memories_dict = self.memories.get(user_id, {})
925
-
926
- # Sort memories by last_updated timestamp if available
927
- if memories_dict:
928
- # Convert to list of values for sorting
929
- memories_list = list(memories_dict.values())
930
-
931
- # Sort memories by last_updated timestamp (newest first)
932
- # If last_updated is None, place at the beginning of the list
933
- sorted_memories_list = sorted(
934
- memories_list,
935
- key=lambda memory: memory.last_updated or datetime.min,
936
- )
937
- else:
938
- sorted_memories_list = []
939
-
940
- if limit is not None and limit > 0:
941
- sorted_memories_list = sorted_memories_list[-limit:]
942
-
943
- return sorted_memories_list
944
-
945
- def _get_first_n_memories(self, user_id: str, limit: Optional[int] = None) -> List[UserMemory]:
946
- """Get the oldest user memories.
947
-
948
- Args:
949
- limit: Maximum number of memories to return.
950
-
951
- Returns:
952
- A list of the oldest UserMemory objects.
953
- """
954
- if not self.memories:
955
- return []
956
-
957
- memories_dict = self.memories.get(user_id, {})
958
- # Sort memories by last_updated timestamp if available
959
- if memories_dict:
960
- # Convert to list of values for sorting
961
- memories_list = list(memories_dict.values())
962
-
963
- # Sort memories by last_updated timestamp (oldest first)
964
- # If last_updated is None, place at the end of the list
965
- sorted_memories_list = sorted(
966
- memories_list,
967
- key=lambda memory: memory.last_updated or datetime.max,
968
- )
969
-
970
- else:
971
- sorted_memories_list = []
972
-
973
- if limit is not None and limit > 0:
974
- sorted_memories_list = sorted_memories_list[:limit]
975
-
976
- return sorted_memories_list
977
-
978
- def clear(self) -> None:
979
- """Clears the memory."""
980
- if self.db:
981
- self.db.clear()
982
- self.memories = {}
983
- self.summaries = {}
984
- self.runs = {}
985
-
986
- # -*- Team Functions
987
- def add_interaction_to_team_context(
988
- self, session_id: str, member_name: str, task: str, run_response: Union[RunResponse, TeamRunResponse]
989
- ) -> None:
990
- if self.team_context is None:
991
- self.team_context = {}
992
- if session_id not in self.team_context:
993
- self.team_context[session_id] = TeamContext()
994
- self.team_context[session_id].member_interactions.append(
995
- TeamMemberInteraction(
996
- member_name=member_name,
997
- task=task,
998
- response=run_response,
999
- )
1000
- )
1001
- log_debug(f"Updated team context with member name: {member_name}")
1002
-
1003
- def set_team_context_text(self, session_id: str, text: Union[dict, str]) -> None:
1004
- if self.team_context is None:
1005
- self.team_context = {}
1006
- if session_id not in self.team_context:
1007
- self.team_context[session_id] = TeamContext()
1008
- if isinstance(text, dict):
1009
- if self.team_context[session_id].text is not None:
1010
- try:
1011
- current_context = json.loads(self.team_context[session_id].text) # type: ignore
1012
- except Exception:
1013
- current_context = {}
1014
- else:
1015
- current_context = {}
1016
- current_context.update(text)
1017
- self.team_context[session_id].text = json.dumps(current_context)
1018
- else:
1019
- # If string then we overwrite the current context
1020
- self.team_context[session_id].text = text
1021
-
1022
- def get_team_context_str(self, session_id: str) -> str:
1023
- if not self.team_context:
1024
- return ""
1025
- session_team_context = self.team_context.get(session_id, None)
1026
- if session_team_context and session_team_context.text:
1027
- return f"<team context>\n{session_team_context.text}\n</team context>\n"
1028
- return ""
1029
-
1030
- def get_team_member_interactions_str(self, session_id: str) -> str:
1031
- if not self.team_context:
1032
- return ""
1033
- team_member_interactions_str = ""
1034
- session_team_context = self.team_context.get(session_id, None)
1035
- if session_team_context and session_team_context.member_interactions:
1036
- team_member_interactions_str += "<member interactions>\n"
1037
-
1038
- for interaction in session_team_context.member_interactions:
1039
- response_dict = interaction.response.to_dict()
1040
- response_content = (
1041
- response_dict.get("content")
1042
- or ",".join([tool.get("content", "") for tool in response_dict.get("tools", [])])
1043
- or ""
1044
- )
1045
- team_member_interactions_str += f"Member: {interaction.member_name}\n"
1046
- team_member_interactions_str += f"Task: {interaction.task}\n"
1047
- team_member_interactions_str += f"Response: {response_content}\n"
1048
- team_member_interactions_str += "\n"
1049
- team_member_interactions_str += "</member interactions>\n"
1050
- return team_member_interactions_str
1051
-
1052
- def get_team_context_images(self, session_id: str) -> List[ImageArtifact]:
1053
- if not self.team_context:
1054
- return []
1055
- images = []
1056
- session_team_context = self.team_context.get(session_id, None)
1057
- if session_team_context and session_team_context.member_interactions:
1058
- for interaction in session_team_context.member_interactions:
1059
- if interaction.response.images:
1060
- images.extend(interaction.response.images)
1061
- return images
1062
-
1063
- def get_team_context_videos(self, session_id: str) -> List[VideoArtifact]:
1064
- if not self.team_context:
1065
- return []
1066
- videos = []
1067
- session_team_context = self.team_context.get(session_id, None)
1068
- if session_team_context and session_team_context.member_interactions:
1069
- for interaction in session_team_context.member_interactions:
1070
- if interaction.response.videos:
1071
- videos.extend(interaction.response.videos)
1072
- return videos
1073
-
1074
- def get_team_context_audio(self, session_id: str) -> List[AudioArtifact]:
1075
- if not self.team_context:
1076
- return []
1077
- audio = []
1078
- session_team_context = self.team_context.get(session_id, None)
1079
- if session_team_context and session_team_context.member_interactions:
1080
- for interaction in session_team_context.member_interactions:
1081
- if interaction.response.audio:
1082
- audio.extend(interaction.response.audio)
1083
- return audio
1084
-
1085
- def __deepcopy__(self, memo):
1086
- from copy import deepcopy
1087
-
1088
- # Create a new instance without calling __init__
1089
- copied_obj = self.__class__.__new__(self.__class__)
1090
- memo[id(self)] = copied_obj
1091
-
1092
- # Copy attributes, reusing specific objects
1093
- shared_objects = {"db", "memory_manager", "summary_manager", "team_context"}
1094
- for k, v in self.__dict__.items():
1095
- setattr(copied_obj, k, v if k in shared_objects else deepcopy(v, memo))
1096
-
1097
- return copied_obj