agno 1.8.2__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 (589) hide show
  1. agno/agent/__init__.py +19 -27
  2. agno/agent/agent.py +3143 -4170
  3. agno/api/agent.py +11 -67
  4. agno/api/api.py +5 -46
  5. agno/api/evals.py +8 -19
  6. agno/api/os.py +17 -0
  7. agno/api/routes.py +6 -41
  8. agno/api/schemas/__init__.py +9 -0
  9. agno/api/schemas/agent.py +5 -21
  10. agno/api/schemas/evals.py +7 -16
  11. agno/api/schemas/os.py +14 -0
  12. agno/api/schemas/team.py +5 -21
  13. agno/api/schemas/utils.py +21 -0
  14. agno/api/schemas/workflows.py +11 -7
  15. agno/api/settings.py +53 -0
  16. agno/api/team.py +11 -66
  17. agno/api/workflow.py +28 -0
  18. agno/cloud/aws/base.py +214 -0
  19. agno/cloud/aws/s3/__init__.py +2 -0
  20. agno/cloud/aws/s3/api_client.py +43 -0
  21. agno/cloud/aws/s3/bucket.py +195 -0
  22. agno/cloud/aws/s3/object.py +57 -0
  23. agno/db/__init__.py +24 -0
  24. agno/db/base.py +245 -0
  25. agno/db/dynamo/__init__.py +3 -0
  26. agno/db/dynamo/dynamo.py +1743 -0
  27. agno/db/dynamo/schemas.py +278 -0
  28. agno/db/dynamo/utils.py +684 -0
  29. agno/db/firestore/__init__.py +3 -0
  30. agno/db/firestore/firestore.py +1432 -0
  31. agno/db/firestore/schemas.py +130 -0
  32. agno/db/firestore/utils.py +278 -0
  33. agno/db/gcs_json/__init__.py +3 -0
  34. agno/db/gcs_json/gcs_json_db.py +1001 -0
  35. agno/db/gcs_json/utils.py +194 -0
  36. agno/db/in_memory/__init__.py +3 -0
  37. agno/db/in_memory/in_memory_db.py +882 -0
  38. agno/db/in_memory/utils.py +172 -0
  39. agno/db/json/__init__.py +3 -0
  40. agno/db/json/json_db.py +1045 -0
  41. agno/db/json/utils.py +196 -0
  42. agno/db/migrations/v1_to_v2.py +162 -0
  43. agno/db/mongo/__init__.py +3 -0
  44. agno/db/mongo/mongo.py +1416 -0
  45. agno/db/mongo/schemas.py +77 -0
  46. agno/db/mongo/utils.py +204 -0
  47. agno/db/mysql/__init__.py +3 -0
  48. agno/db/mysql/mysql.py +1719 -0
  49. agno/db/mysql/schemas.py +124 -0
  50. agno/db/mysql/utils.py +297 -0
  51. agno/db/postgres/__init__.py +3 -0
  52. agno/db/postgres/postgres.py +1710 -0
  53. agno/db/postgres/schemas.py +124 -0
  54. agno/db/postgres/utils.py +280 -0
  55. agno/db/redis/__init__.py +3 -0
  56. agno/db/redis/redis.py +1367 -0
  57. agno/db/redis/schemas.py +109 -0
  58. agno/db/redis/utils.py +288 -0
  59. agno/db/schemas/__init__.py +3 -0
  60. agno/db/schemas/evals.py +33 -0
  61. agno/db/schemas/knowledge.py +40 -0
  62. agno/db/schemas/memory.py +46 -0
  63. agno/db/singlestore/__init__.py +3 -0
  64. agno/db/singlestore/schemas.py +116 -0
  65. agno/db/singlestore/singlestore.py +1712 -0
  66. agno/db/singlestore/utils.py +326 -0
  67. agno/db/sqlite/__init__.py +3 -0
  68. agno/db/sqlite/schemas.py +119 -0
  69. agno/db/sqlite/sqlite.py +1676 -0
  70. agno/db/sqlite/utils.py +268 -0
  71. agno/db/utils.py +88 -0
  72. agno/eval/__init__.py +14 -0
  73. agno/eval/accuracy.py +154 -48
  74. agno/eval/performance.py +88 -23
  75. agno/eval/reliability.py +73 -20
  76. agno/eval/utils.py +23 -13
  77. agno/integrations/discord/__init__.py +3 -0
  78. agno/{app → integrations}/discord/client.py +10 -10
  79. agno/knowledge/__init__.py +2 -2
  80. agno/{document → knowledge}/chunking/agentic.py +2 -2
  81. agno/{document → knowledge}/chunking/document.py +2 -2
  82. agno/{document → knowledge}/chunking/fixed.py +3 -3
  83. agno/{document → knowledge}/chunking/markdown.py +2 -2
  84. agno/{document → knowledge}/chunking/recursive.py +2 -2
  85. agno/{document → knowledge}/chunking/row.py +2 -2
  86. agno/knowledge/chunking/semantic.py +59 -0
  87. agno/knowledge/chunking/strategy.py +121 -0
  88. agno/knowledge/content.py +74 -0
  89. agno/knowledge/document/__init__.py +5 -0
  90. agno/{document → knowledge/document}/base.py +12 -2
  91. agno/knowledge/embedder/__init__.py +5 -0
  92. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  93. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  94. agno/{embedder → knowledge/embedder}/base.py +6 -0
  95. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  96. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  97. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  98. agno/{embedder → knowledge/embedder}/google.py +74 -1
  99. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  100. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  101. agno/knowledge/embedder/langdb.py +22 -0
  102. agno/knowledge/embedder/mistral.py +139 -0
  103. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  104. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  105. agno/knowledge/embedder/openai.py +223 -0
  106. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  107. agno/{embedder → knowledge/embedder}/together.py +1 -1
  108. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  109. agno/knowledge/knowledge.py +1551 -0
  110. agno/knowledge/reader/__init__.py +7 -0
  111. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  112. agno/knowledge/reader/base.py +88 -0
  113. agno/{document → knowledge}/reader/csv_reader.py +47 -65
  114. agno/knowledge/reader/docx_reader.py +83 -0
  115. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  116. agno/{document → knowledge}/reader/json_reader.py +30 -9
  117. agno/{document → knowledge}/reader/markdown_reader.py +58 -9
  118. agno/{document → knowledge}/reader/pdf_reader.py +71 -126
  119. agno/knowledge/reader/reader_factory.py +268 -0
  120. agno/knowledge/reader/s3_reader.py +101 -0
  121. agno/{document → knowledge}/reader/text_reader.py +31 -10
  122. agno/knowledge/reader/url_reader.py +128 -0
  123. agno/knowledge/reader/web_search_reader.py +366 -0
  124. agno/{document → knowledge}/reader/website_reader.py +37 -10
  125. agno/knowledge/reader/wikipedia_reader.py +59 -0
  126. agno/knowledge/reader/youtube_reader.py +78 -0
  127. agno/knowledge/remote_content/remote_content.py +88 -0
  128. agno/{reranker → knowledge/reranker}/base.py +1 -1
  129. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  130. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  131. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  132. agno/knowledge/types.py +30 -0
  133. agno/knowledge/utils.py +169 -0
  134. agno/media.py +269 -268
  135. agno/memory/__init__.py +2 -10
  136. agno/memory/manager.py +1003 -148
  137. agno/models/aimlapi/__init__.py +2 -2
  138. agno/models/aimlapi/aimlapi.py +6 -6
  139. agno/models/anthropic/claude.py +128 -72
  140. agno/models/aws/bedrock.py +107 -175
  141. agno/models/aws/claude.py +64 -18
  142. agno/models/azure/ai_foundry.py +73 -23
  143. agno/models/base.py +346 -290
  144. agno/models/cerebras/cerebras.py +84 -27
  145. agno/models/cohere/chat.py +106 -98
  146. agno/models/google/gemini.py +105 -46
  147. agno/models/groq/groq.py +97 -35
  148. agno/models/huggingface/huggingface.py +92 -27
  149. agno/models/ibm/watsonx.py +72 -13
  150. agno/models/litellm/chat.py +85 -13
  151. agno/models/message.py +46 -151
  152. agno/models/meta/llama.py +85 -49
  153. agno/models/metrics.py +120 -0
  154. agno/models/mistral/mistral.py +90 -21
  155. agno/models/ollama/__init__.py +0 -2
  156. agno/models/ollama/chat.py +85 -47
  157. agno/models/openai/chat.py +154 -37
  158. agno/models/openai/responses.py +178 -105
  159. agno/models/perplexity/perplexity.py +26 -2
  160. agno/models/portkey/portkey.py +0 -7
  161. agno/models/response.py +15 -9
  162. agno/models/utils.py +20 -0
  163. agno/models/vercel/__init__.py +2 -2
  164. agno/models/vercel/v0.py +1 -1
  165. agno/models/vllm/__init__.py +2 -2
  166. agno/models/vllm/vllm.py +3 -3
  167. agno/models/xai/xai.py +10 -10
  168. agno/os/__init__.py +3 -0
  169. agno/os/app.py +497 -0
  170. agno/os/auth.py +47 -0
  171. agno/os/config.py +103 -0
  172. agno/os/interfaces/agui/__init__.py +3 -0
  173. agno/os/interfaces/agui/agui.py +31 -0
  174. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  175. agno/{app → os/interfaces}/agui/utils.py +65 -28
  176. agno/os/interfaces/base.py +21 -0
  177. agno/os/interfaces/slack/__init__.py +3 -0
  178. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  179. agno/os/interfaces/slack/slack.py +32 -0
  180. agno/os/interfaces/whatsapp/__init__.py +3 -0
  181. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  182. agno/os/interfaces/whatsapp/whatsapp.py +29 -0
  183. agno/os/mcp.py +235 -0
  184. agno/os/router.py +1400 -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 +393 -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 +850 -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 +410 -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 +178 -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 +536 -0
  201. agno/os/schema.py +945 -0
  202. agno/{app/playground → os}/settings.py +7 -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/agent.py +633 -0
  212. agno/run/base.py +53 -77
  213. agno/run/cancel.py +81 -0
  214. agno/run/team.py +243 -96
  215. agno/run/workflow.py +550 -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 +3260 -4824
  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 +43 -23
  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 +20 -17
  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 +22 -12
  244. agno/tools/daytona.py +13 -16
  245. agno/tools/decorator.py +6 -3
  246. agno/tools/desi_vocal.py +17 -8
  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 +62 -62
  252. agno/tools/eleven_labs.py +36 -29
  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 +30 -30
  257. agno/tools/file.py +9 -8
  258. agno/tools/financial_datasets.py +25 -44
  259. agno/tools/firecrawl.py +17 -18
  260. agno/tools/function.py +127 -18
  261. agno/tools/giphy.py +23 -11
  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 +32 -20
  276. agno/tools/mcp.py +1 -2
  277. agno/tools/mem0.py +18 -12
  278. agno/tools/memori.py +14 -10
  279. agno/tools/mlx_transcribe.py +3 -2
  280. agno/tools/models/azure_openai.py +33 -15
  281. agno/tools/models/gemini.py +59 -32
  282. agno/tools/models/groq.py +30 -23
  283. agno/tools/models/nebius.py +28 -12
  284. agno/tools/models_labs.py +40 -16
  285. agno/tools/moviepy_video.py +7 -6
  286. agno/tools/neo4j.py +10 -8
  287. agno/tools/newspaper.py +7 -2
  288. agno/tools/newspaper4k.py +8 -3
  289. agno/tools/openai.py +58 -32
  290. agno/tools/openbb.py +12 -11
  291. agno/tools/opencv.py +63 -47
  292. agno/tools/openweather.py +14 -12
  293. agno/tools/pandas.py +11 -3
  294. agno/tools/postgres.py +4 -12
  295. agno/tools/pubmed.py +4 -1
  296. agno/tools/python.py +9 -22
  297. agno/tools/reasoning.py +35 -27
  298. agno/tools/reddit.py +11 -26
  299. agno/tools/replicate.py +55 -42
  300. agno/tools/resend.py +4 -1
  301. agno/tools/scrapegraph.py +15 -14
  302. agno/tools/searxng.py +10 -23
  303. agno/tools/serpapi.py +6 -3
  304. agno/tools/serper.py +13 -4
  305. agno/tools/shell.py +9 -2
  306. agno/tools/slack.py +12 -11
  307. agno/tools/sleep.py +3 -2
  308. agno/tools/spider.py +24 -4
  309. agno/tools/sql.py +7 -6
  310. agno/tools/tavily.py +6 -4
  311. agno/tools/telegram.py +12 -4
  312. agno/tools/todoist.py +11 -31
  313. agno/tools/toolkit.py +1 -1
  314. agno/tools/trafilatura.py +22 -6
  315. agno/tools/trello.py +9 -22
  316. agno/tools/twilio.py +10 -3
  317. agno/tools/user_control_flow.py +6 -1
  318. agno/tools/valyu.py +34 -5
  319. agno/tools/visualization.py +19 -28
  320. agno/tools/webbrowser.py +4 -3
  321. agno/tools/webex.py +11 -7
  322. agno/tools/website.py +15 -46
  323. agno/tools/webtools.py +12 -4
  324. agno/tools/whatsapp.py +5 -9
  325. agno/tools/wikipedia.py +20 -13
  326. agno/tools/x.py +14 -13
  327. agno/tools/yfinance.py +13 -40
  328. agno/tools/youtube.py +26 -20
  329. agno/tools/zendesk.py +7 -2
  330. agno/tools/zep.py +10 -7
  331. agno/tools/zoom.py +10 -9
  332. agno/utils/common.py +1 -19
  333. agno/utils/events.py +100 -123
  334. agno/utils/gemini.py +1 -1
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/log.py +54 -4
  337. agno/utils/mcp.py +68 -10
  338. agno/utils/media.py +39 -0
  339. agno/utils/message.py +12 -1
  340. agno/utils/models/aws_claude.py +1 -1
  341. agno/utils/models/claude.py +6 -12
  342. agno/utils/models/cohere.py +1 -1
  343. agno/utils/models/mistral.py +8 -7
  344. agno/utils/models/schema_utils.py +3 -3
  345. agno/utils/models/watsonx.py +1 -1
  346. agno/utils/openai.py +1 -1
  347. agno/utils/pprint.py +33 -32
  348. agno/utils/print_response/agent.py +779 -0
  349. agno/utils/print_response/team.py +1669 -0
  350. agno/utils/print_response/workflow.py +1451 -0
  351. agno/utils/prompts.py +14 -14
  352. agno/utils/reasoning.py +87 -0
  353. agno/utils/response.py +42 -42
  354. agno/utils/streamlit.py +481 -0
  355. agno/utils/string.py +8 -22
  356. agno/utils/team.py +50 -0
  357. agno/utils/timer.py +2 -2
  358. agno/vectordb/base.py +33 -21
  359. agno/vectordb/cassandra/cassandra.py +287 -23
  360. agno/vectordb/chroma/chromadb.py +482 -59
  361. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  362. agno/vectordb/couchbase/couchbase.py +309 -29
  363. agno/vectordb/lancedb/lance_db.py +360 -21
  364. agno/vectordb/langchaindb/__init__.py +5 -0
  365. agno/vectordb/langchaindb/langchaindb.py +145 -0
  366. agno/vectordb/lightrag/__init__.py +5 -0
  367. agno/vectordb/lightrag/lightrag.py +374 -0
  368. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  369. agno/vectordb/milvus/milvus.py +242 -32
  370. agno/vectordb/mongodb/mongodb.py +200 -24
  371. agno/vectordb/pgvector/pgvector.py +319 -37
  372. agno/vectordb/pineconedb/pineconedb.py +221 -27
  373. agno/vectordb/qdrant/qdrant.py +334 -14
  374. agno/vectordb/singlestore/singlestore.py +286 -29
  375. agno/vectordb/surrealdb/surrealdb.py +187 -7
  376. agno/vectordb/upstashdb/upstashdb.py +342 -26
  377. agno/vectordb/weaviate/weaviate.py +227 -165
  378. agno/workflow/__init__.py +17 -13
  379. agno/workflow/{v2/condition.py → condition.py} +135 -32
  380. agno/workflow/{v2/loop.py → loop.py} +115 -28
  381. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  382. agno/workflow/{v2/router.py → router.py} +133 -32
  383. agno/workflow/{v2/step.py → step.py} +207 -49
  384. agno/workflow/{v2/steps.py → steps.py} +147 -66
  385. agno/workflow/types.py +482 -0
  386. agno/workflow/workflow.py +2410 -696
  387. agno-2.0.0.dist-info/METADATA +494 -0
  388. agno-2.0.0.dist-info/RECORD +515 -0
  389. agno-2.0.0.dist-info/licenses/LICENSE +201 -0
  390. agno/agent/metrics.py +0 -110
  391. agno/api/app.py +0 -35
  392. agno/api/playground.py +0 -92
  393. agno/api/schemas/app.py +0 -12
  394. agno/api/schemas/playground.py +0 -22
  395. agno/api/schemas/user.py +0 -35
  396. agno/api/schemas/workspace.py +0 -46
  397. agno/api/user.py +0 -160
  398. agno/api/workflows.py +0 -33
  399. agno/api/workspace.py +0 -175
  400. agno/app/agui/__init__.py +0 -3
  401. agno/app/agui/app.py +0 -17
  402. agno/app/agui/sync_router.py +0 -120
  403. agno/app/base.py +0 -186
  404. agno/app/discord/__init__.py +0 -3
  405. agno/app/fastapi/__init__.py +0 -3
  406. agno/app/fastapi/app.py +0 -107
  407. agno/app/fastapi/async_router.py +0 -457
  408. agno/app/fastapi/sync_router.py +0 -448
  409. agno/app/playground/app.py +0 -228
  410. agno/app/playground/async_router.py +0 -1053
  411. agno/app/playground/deploy.py +0 -249
  412. agno/app/playground/operator.py +0 -183
  413. agno/app/playground/schemas.py +0 -223
  414. agno/app/playground/serve.py +0 -55
  415. agno/app/playground/sync_router.py +0 -1045
  416. agno/app/playground/utils.py +0 -46
  417. agno/app/settings.py +0 -15
  418. agno/app/slack/__init__.py +0 -3
  419. agno/app/slack/app.py +0 -19
  420. agno/app/slack/sync_router.py +0 -92
  421. agno/app/utils.py +0 -54
  422. agno/app/whatsapp/__init__.py +0 -3
  423. agno/app/whatsapp/app.py +0 -15
  424. agno/app/whatsapp/sync_router.py +0 -197
  425. agno/cli/auth_server.py +0 -249
  426. agno/cli/config.py +0 -274
  427. agno/cli/console.py +0 -88
  428. agno/cli/credentials.py +0 -23
  429. agno/cli/entrypoint.py +0 -571
  430. agno/cli/operator.py +0 -357
  431. agno/cli/settings.py +0 -96
  432. agno/cli/ws/ws_cli.py +0 -817
  433. agno/constants.py +0 -13
  434. agno/document/__init__.py +0 -5
  435. agno/document/chunking/semantic.py +0 -45
  436. agno/document/chunking/strategy.py +0 -31
  437. agno/document/reader/__init__.py +0 -5
  438. agno/document/reader/base.py +0 -47
  439. agno/document/reader/docx_reader.py +0 -60
  440. agno/document/reader/gcs/pdf_reader.py +0 -44
  441. agno/document/reader/s3/pdf_reader.py +0 -59
  442. agno/document/reader/s3/text_reader.py +0 -63
  443. agno/document/reader/url_reader.py +0 -59
  444. agno/document/reader/youtube_reader.py +0 -58
  445. agno/embedder/__init__.py +0 -5
  446. agno/embedder/langdb.py +0 -80
  447. agno/embedder/mistral.py +0 -82
  448. agno/embedder/openai.py +0 -78
  449. agno/file/__init__.py +0 -5
  450. agno/file/file.py +0 -16
  451. agno/file/local/csv.py +0 -32
  452. agno/file/local/txt.py +0 -19
  453. agno/infra/app.py +0 -240
  454. agno/infra/base.py +0 -144
  455. agno/infra/context.py +0 -20
  456. agno/infra/db_app.py +0 -52
  457. agno/infra/resource.py +0 -205
  458. agno/infra/resources.py +0 -55
  459. agno/knowledge/agent.py +0 -702
  460. agno/knowledge/arxiv.py +0 -33
  461. agno/knowledge/combined.py +0 -36
  462. agno/knowledge/csv.py +0 -144
  463. agno/knowledge/csv_url.py +0 -124
  464. agno/knowledge/document.py +0 -223
  465. agno/knowledge/docx.py +0 -137
  466. agno/knowledge/firecrawl.py +0 -34
  467. agno/knowledge/gcs/__init__.py +0 -0
  468. agno/knowledge/gcs/base.py +0 -39
  469. agno/knowledge/gcs/pdf.py +0 -125
  470. agno/knowledge/json.py +0 -137
  471. agno/knowledge/langchain.py +0 -71
  472. agno/knowledge/light_rag.py +0 -273
  473. agno/knowledge/llamaindex.py +0 -66
  474. agno/knowledge/markdown.py +0 -154
  475. agno/knowledge/pdf.py +0 -164
  476. agno/knowledge/pdf_bytes.py +0 -42
  477. agno/knowledge/pdf_url.py +0 -148
  478. agno/knowledge/s3/__init__.py +0 -0
  479. agno/knowledge/s3/base.py +0 -64
  480. agno/knowledge/s3/pdf.py +0 -33
  481. agno/knowledge/s3/text.py +0 -34
  482. agno/knowledge/text.py +0 -141
  483. agno/knowledge/url.py +0 -46
  484. agno/knowledge/website.py +0 -179
  485. agno/knowledge/wikipedia.py +0 -32
  486. agno/knowledge/youtube.py +0 -35
  487. agno/memory/agent.py +0 -423
  488. agno/memory/classifier.py +0 -104
  489. agno/memory/db/__init__.py +0 -5
  490. agno/memory/db/base.py +0 -42
  491. agno/memory/db/mongodb.py +0 -189
  492. agno/memory/db/postgres.py +0 -203
  493. agno/memory/db/sqlite.py +0 -193
  494. agno/memory/memory.py +0 -22
  495. agno/memory/row.py +0 -36
  496. agno/memory/summarizer.py +0 -201
  497. agno/memory/summary.py +0 -19
  498. agno/memory/team.py +0 -415
  499. agno/memory/v2/__init__.py +0 -2
  500. agno/memory/v2/db/__init__.py +0 -1
  501. agno/memory/v2/db/base.py +0 -42
  502. agno/memory/v2/db/firestore.py +0 -339
  503. agno/memory/v2/db/mongodb.py +0 -196
  504. agno/memory/v2/db/postgres.py +0 -214
  505. agno/memory/v2/db/redis.py +0 -187
  506. agno/memory/v2/db/schema.py +0 -54
  507. agno/memory/v2/db/sqlite.py +0 -209
  508. agno/memory/v2/manager.py +0 -437
  509. agno/memory/v2/memory.py +0 -1097
  510. agno/memory/v2/schema.py +0 -55
  511. agno/memory/v2/summarizer.py +0 -215
  512. agno/memory/workflow.py +0 -38
  513. agno/models/ollama/tools.py +0 -430
  514. agno/models/qwen/__init__.py +0 -5
  515. agno/playground/__init__.py +0 -10
  516. agno/playground/deploy.py +0 -3
  517. agno/playground/playground.py +0 -3
  518. agno/playground/serve.py +0 -3
  519. agno/playground/settings.py +0 -3
  520. agno/reranker/__init__.py +0 -0
  521. agno/run/response.py +0 -467
  522. agno/run/v2/__init__.py +0 -0
  523. agno/run/v2/workflow.py +0 -567
  524. agno/storage/__init__.py +0 -0
  525. agno/storage/agent/__init__.py +0 -0
  526. agno/storage/agent/dynamodb.py +0 -1
  527. agno/storage/agent/json.py +0 -1
  528. agno/storage/agent/mongodb.py +0 -1
  529. agno/storage/agent/postgres.py +0 -1
  530. agno/storage/agent/singlestore.py +0 -1
  531. agno/storage/agent/sqlite.py +0 -1
  532. agno/storage/agent/yaml.py +0 -1
  533. agno/storage/base.py +0 -60
  534. agno/storage/dynamodb.py +0 -673
  535. agno/storage/firestore.py +0 -297
  536. agno/storage/gcs_json.py +0 -261
  537. agno/storage/in_memory.py +0 -234
  538. agno/storage/json.py +0 -237
  539. agno/storage/mongodb.py +0 -328
  540. agno/storage/mysql.py +0 -685
  541. agno/storage/postgres.py +0 -682
  542. agno/storage/redis.py +0 -336
  543. agno/storage/session/__init__.py +0 -16
  544. agno/storage/session/agent.py +0 -64
  545. agno/storage/session/team.py +0 -63
  546. agno/storage/session/v2/__init__.py +0 -5
  547. agno/storage/session/workflow.py +0 -61
  548. agno/storage/singlestore.py +0 -606
  549. agno/storage/sqlite.py +0 -646
  550. agno/storage/workflow/__init__.py +0 -0
  551. agno/storage/workflow/mongodb.py +0 -1
  552. agno/storage/workflow/postgres.py +0 -1
  553. agno/storage/workflow/sqlite.py +0 -1
  554. agno/storage/yaml.py +0 -241
  555. agno/tools/thinking.py +0 -73
  556. agno/utils/defaults.py +0 -57
  557. agno/utils/filesystem.py +0 -39
  558. agno/utils/git.py +0 -52
  559. agno/utils/json_io.py +0 -30
  560. agno/utils/load_env.py +0 -19
  561. agno/utils/py_io.py +0 -19
  562. agno/utils/pyproject.py +0 -18
  563. agno/utils/resource_filter.py +0 -31
  564. agno/workflow/v2/__init__.py +0 -21
  565. agno/workflow/v2/types.py +0 -357
  566. agno/workflow/v2/workflow.py +0 -3313
  567. agno/workspace/__init__.py +0 -0
  568. agno/workspace/config.py +0 -325
  569. agno/workspace/enums.py +0 -6
  570. agno/workspace/helpers.py +0 -52
  571. agno/workspace/operator.py +0 -757
  572. agno/workspace/settings.py +0 -158
  573. agno-1.8.2.dist-info/METADATA +0 -982
  574. agno-1.8.2.dist-info/RECORD +0 -566
  575. agno-1.8.2.dist-info/entry_points.txt +0 -3
  576. agno-1.8.2.dist-info/licenses/LICENSE +0 -375
  577. /agno/{app → db/migrations}/__init__.py +0 -0
  578. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  579. /agno/{cli → integrations}/__init__.py +0 -0
  580. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  581. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  582. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  583. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  584. /agno/{app → os/interfaces}/slack/security.py +0 -0
  585. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  586. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  587. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  588. {agno-1.8.2.dist-info → agno-2.0.0.dist-info}/WHEEL +0 -0
  589. {agno-1.8.2.dist-info → agno-2.0.0.dist-info}/top_level.txt +0 -0
agno/storage/dynamodb.py DELETED
@@ -1,673 +0,0 @@
1
- import time
2
- from dataclasses import asdict
3
- from decimal import Decimal
4
- from typing import Any, Dict, List, Literal, Optional
5
-
6
- from agno.storage.base import Storage
7
- from agno.storage.session import Session
8
- from agno.storage.session.agent import AgentSession
9
- from agno.storage.session.team import TeamSession
10
- from agno.storage.session.v2.workflow import WorkflowSession as WorkflowSessionV2
11
- from agno.storage.session.workflow import WorkflowSession
12
- from agno.utils.log import log_debug, log_info, logger
13
-
14
- try:
15
- import boto3
16
- from boto3.dynamodb.conditions import Key
17
- from botocore.exceptions import ClientError
18
- except ImportError:
19
- raise ImportError("`boto3` not installed. Please install using `pip install boto3`.")
20
-
21
-
22
- class DynamoDbStorage(Storage):
23
- def __init__(
24
- self,
25
- table_name: str,
26
- profile_name: Optional[str] = None,
27
- region_name: Optional[str] = None,
28
- aws_access_key_id: Optional[str] = None,
29
- aws_secret_access_key: Optional[str] = None,
30
- endpoint_url: Optional[str] = None,
31
- create_table_if_not_exists: bool = True,
32
- mode: Optional[Literal["agent", "team", "workflow", "workflow_v2"]] = "agent",
33
- create_table_read_capacity_units: int = 5,
34
- create_table_write_capacity_units: int = 5,
35
- ):
36
- """
37
- Initialize the DynamoDbStorage.
38
-
39
- Args:
40
- table_name (str): The name of the DynamoDB table.
41
- profile_name (Optional[str]): AWS profile name to use for credentials.
42
- region_name (Optional[str]): AWS region name.
43
- aws_access_key_id (Optional[str]): AWS access key ID.
44
- aws_secret_access_key (Optional[str]): AWS secret access key.
45
- endpoint_url (Optional[str]): The complete URL to use for the constructed client.
46
- create_table_if_not_exists (bool): Whether to create the table if it does not exist.
47
- mode (Optional[Literal["agent", "team", "workflow", "workflow_v2"]]): The mode of the storage.
48
- create_table_read_capacity_units Optional[int]: Read capacity units for created table (default: 5).
49
- create_table_write_capacity_units Optional[int]: Write capacity units for created table (default: 5).
50
- """
51
- super().__init__(mode)
52
- self.table_name = table_name
53
- self.profile_name = profile_name
54
- self.region_name = region_name
55
- self.endpoint_url = endpoint_url
56
- self.aws_access_key_id = aws_access_key_id
57
- self.aws_secret_access_key = aws_secret_access_key
58
- self.create_table_if_not_exists = create_table_if_not_exists
59
- self.create_table_read_capacity_units = create_table_read_capacity_units
60
- self.create_table_write_capacity_units = create_table_write_capacity_units
61
-
62
- # Create session using profile name if provided
63
- if self.profile_name:
64
- session = boto3.Session(profile_name=self.profile_name)
65
- self.dynamodb = session.resource(
66
- "dynamodb",
67
- region_name=self.region_name,
68
- endpoint_url=self.endpoint_url,
69
- )
70
- else:
71
- # Initialize DynamoDB resource with default credentials
72
- self.dynamodb = boto3.resource(
73
- "dynamodb",
74
- aws_access_key_id=self.aws_access_key_id,
75
- aws_secret_access_key=self.aws_secret_access_key,
76
- region_name=self.region_name,
77
- endpoint_url=self.endpoint_url,
78
- )
79
-
80
- # Initialize table
81
- self.table = self.dynamodb.Table(self.table_name)
82
-
83
- # Optionally create table if it does not exist
84
- if self.create_table_if_not_exists:
85
- self.create()
86
- log_debug(f"Initialized DynamoDbStorage with table '{self.table_name}'")
87
-
88
- @property
89
- def mode(self) -> Literal["agent", "team", "workflow", "workflow_v2"]:
90
- """Get the mode of the storage."""
91
- return super().mode
92
-
93
- @mode.setter
94
- def mode(self, value: Optional[Literal["agent", "team", "workflow", "workflow_v2"]]) -> None:
95
- """Set the mode and refresh the table if mode changes."""
96
- super(DynamoDbStorage, type(self)).mode.fset(self, value) # type: ignore
97
- if value is not None:
98
- if self.create_table_if_not_exists:
99
- self.create()
100
-
101
- def create(self) -> None:
102
- """
103
- Create the DynamoDB table if it does not exist.
104
- """
105
- provisioned_throughput = {
106
- "ReadCapacityUnits": self.create_table_read_capacity_units,
107
- "WriteCapacityUnits": self.create_table_write_capacity_units,
108
- }
109
-
110
- try:
111
- # Check if table exists
112
- self.dynamodb.meta.client.describe_table(TableName=self.table_name)
113
- log_debug(f"Table '{self.table_name}' already exists.")
114
- except ClientError as e:
115
- if e.response["Error"]["Code"] == "ResourceNotFoundException":
116
- log_debug(f"Creating table '{self.table_name}'.")
117
-
118
- attribute_definitions = []
119
- if self.mode == "agent":
120
- attribute_definitions = [
121
- {"AttributeName": "session_id", "AttributeType": "S"},
122
- {"AttributeName": "user_id", "AttributeType": "S"},
123
- {"AttributeName": "agent_id", "AttributeType": "S"},
124
- {"AttributeName": "created_at", "AttributeType": "N"},
125
- ]
126
- elif self.mode == "team":
127
- attribute_definitions = [
128
- {"AttributeName": "session_id", "AttributeType": "S"},
129
- {"AttributeName": "user_id", "AttributeType": "S"},
130
- {"AttributeName": "team_id", "AttributeType": "S"},
131
- {"AttributeName": "created_at", "AttributeType": "N"},
132
- ]
133
- elif self.mode == "workflow":
134
- attribute_definitions = [
135
- {"AttributeName": "session_id", "AttributeType": "S"},
136
- {"AttributeName": "user_id", "AttributeType": "S"},
137
- {"AttributeName": "workflow_id", "AttributeType": "S"},
138
- {"AttributeName": "created_at", "AttributeType": "N"},
139
- ]
140
- elif self.mode == "workflow_v2":
141
- attribute_definitions = [
142
- {"AttributeName": "session_id", "AttributeType": "S"},
143
- {"AttributeName": "user_id", "AttributeType": "S"},
144
- {"AttributeName": "workflow_id", "AttributeType": "S"},
145
- {"AttributeName": "created_at", "AttributeType": "N"},
146
- ]
147
- secondary_indexes = [
148
- {
149
- "IndexName": "user_id-index",
150
- "KeySchema": [
151
- {"AttributeName": "user_id", "KeyType": "HASH"},
152
- {"AttributeName": "created_at", "KeyType": "RANGE"},
153
- ],
154
- "Projection": {"ProjectionType": "ALL"},
155
- "ProvisionedThroughput": provisioned_throughput,
156
- }
157
- ]
158
- if self.mode == "agent":
159
- secondary_indexes.append(
160
- {
161
- "IndexName": "agent_id-index",
162
- "KeySchema": [
163
- {"AttributeName": "agent_id", "KeyType": "HASH"},
164
- {"AttributeName": "created_at", "KeyType": "RANGE"},
165
- ],
166
- "Projection": {"ProjectionType": "ALL"},
167
- "ProvisionedThroughput": provisioned_throughput,
168
- }
169
- )
170
- elif self.mode == "team":
171
- secondary_indexes.append(
172
- {
173
- "IndexName": "team_id-index",
174
- "KeySchema": [
175
- {"AttributeName": "team_id", "KeyType": "HASH"},
176
- {"AttributeName": "created_at", "KeyType": "RANGE"},
177
- ],
178
- "Projection": {"ProjectionType": "ALL"},
179
- "ProvisionedThroughput": provisioned_throughput,
180
- }
181
- )
182
- elif self.mode == "workflow":
183
- secondary_indexes.append(
184
- {
185
- "IndexName": "workflow_id-index",
186
- "KeySchema": [
187
- {"AttributeName": "workflow_id", "KeyType": "HASH"},
188
- {"AttributeName": "created_at", "KeyType": "RANGE"},
189
- ],
190
- "Projection": {"ProjectionType": "ALL"},
191
- "ProvisionedThroughput": provisioned_throughput,
192
- }
193
- )
194
- elif self.mode == "workflow_v2":
195
- secondary_indexes.append(
196
- {
197
- "IndexName": "workflow_id-index",
198
- "KeySchema": [
199
- {"AttributeName": "workflow_id", "KeyType": "HASH"},
200
- {"AttributeName": "created_at", "KeyType": "RANGE"},
201
- ],
202
- "Projection": {"ProjectionType": "ALL"},
203
- "ProvisionedThroughput": provisioned_throughput,
204
- }
205
- )
206
- # Create the table
207
- self.table = self.dynamodb.create_table(
208
- TableName=self.table_name,
209
- KeySchema=[{"AttributeName": "session_id", "KeyType": "HASH"}],
210
- AttributeDefinitions=attribute_definitions,
211
- GlobalSecondaryIndexes=secondary_indexes,
212
- ProvisionedThroughput=provisioned_throughput,
213
- )
214
- # Wait until the table exists.
215
- self.table.wait_until_exists()
216
- log_debug(f"Table '{self.table_name}' created successfully.")
217
- else:
218
- logger.error(f"Unable to create table '{self.table_name}': {e.response['Error']['Message']}")
219
- except Exception as e:
220
- logger.error(f"Exception during table creation: {e}")
221
-
222
- def read(self, session_id: str, user_id: Optional[str] = None) -> Optional[Session]:
223
- """
224
- Read and return a Session from the database.
225
-
226
- Args:
227
- session_id (str): ID of the session to read.
228
- user_id (Optional[str]): User ID to filter by. Defaults to None.
229
-
230
- Returns:
231
- Optional[Session]: Session object if found, None otherwise.
232
- """
233
- try:
234
- key = {"session_id": session_id}
235
- if user_id is not None:
236
- key["user_id"] = user_id
237
-
238
- response = self.table.get_item(Key=key)
239
- item = response.get("Item", None)
240
- if item is not None:
241
- # Convert Decimal to int or float
242
- item = self._deserialize_item(item)
243
- if self.mode == "agent":
244
- return AgentSession.from_dict(item)
245
- elif self.mode == "team":
246
- return TeamSession.from_dict(item)
247
- elif self.mode == "workflow":
248
- return WorkflowSession.from_dict(item)
249
- elif self.mode == "workflow_v2":
250
- return WorkflowSessionV2.from_dict(item)
251
- except Exception as e:
252
- logger.error(f"Error reading session_id '{session_id}' with user_id '{user_id}': {e}")
253
- return None
254
-
255
- def get_all_session_ids(self, user_id: Optional[str] = None, entity_id: Optional[str] = None) -> List[str]:
256
- """
257
- Retrieve all session IDs, optionally filtered by user_id and/or entity_id.
258
-
259
- Args:
260
- user_id (Optional[str], optional): User ID to filter by. Defaults to None.
261
- entity_id (Optional[str], optional): Entity ID to filter by. Defaults to None.
262
-
263
- Returns:
264
- List[str]: List of session IDs matching the criteria.
265
- """
266
- session_ids: List[str] = []
267
- try:
268
- if user_id is not None:
269
- # Query using user_id index
270
- response = self.table.query(
271
- IndexName="user_id-index",
272
- KeyConditionExpression=Key("user_id").eq(user_id),
273
- ProjectionExpression="session_id",
274
- )
275
- items = response.get("Items", [])
276
- session_ids.extend([item["session_id"] for item in items if "session_id" in item])
277
- elif entity_id is not None:
278
- if self.mode == "agent":
279
- # Query using agent_id index
280
- response = self.table.query(
281
- IndexName="agent_id-index",
282
- KeyConditionExpression=Key("agent_id").eq(entity_id),
283
- ProjectionExpression="session_id",
284
- )
285
- elif self.mode == "team":
286
- # Query using team_id index
287
- response = self.table.query(
288
- IndexName="team_id-index",
289
- KeyConditionExpression=Key("team_id").eq(entity_id),
290
- ProjectionExpression="session_id",
291
- )
292
- elif self.mode == "workflow":
293
- # Query using workflow_id index
294
- response = self.table.query(
295
- IndexName="workflow_id-index",
296
- KeyConditionExpression=Key("workflow_id").eq(entity_id),
297
- ProjectionExpression="session_id",
298
- )
299
- items = response.get("Items", []) # type: ignore
300
- session_ids.extend([item["session_id"] for item in items if "session_id" in item])
301
- else:
302
- # Scan the whole table
303
- response = self.table.scan(ProjectionExpression="session_id")
304
- items = response.get("Items", [])
305
- session_ids.extend([item["session_id"] for item in items if "session_id" in item])
306
- except Exception as e:
307
- logger.error(f"Error retrieving session IDs: {e}")
308
- return session_ids
309
-
310
- def get_all_sessions(self, user_id: Optional[str] = None, entity_id: Optional[str] = None) -> List[Session]:
311
- """
312
- Retrieve all sessions, optionally filtered by user_id and/or entity_id.
313
-
314
- Args:
315
- user_id (Optional[str], optional): User ID to filter by. Defaults to None.
316
- entity_id (Optional[str], optional): Entity ID to filter by. Defaults to None.
317
-
318
- Returns:
319
- List[Session]: List of AgentSession or WorkflowSession objects matching the criteria.
320
- """
321
- sessions: List[Session] = []
322
- try:
323
- if user_id is not None:
324
- if self.mode == "agent":
325
- # Query using user_id index
326
- response = self.table.query(
327
- IndexName="user_id-index",
328
- KeyConditionExpression=Key("user_id").eq(user_id),
329
- ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at",
330
- )
331
- elif self.mode == "team":
332
- # Query using user_id index
333
- response = self.table.query(
334
- IndexName="user_id-index",
335
- KeyConditionExpression=Key("user_id").eq(user_id),
336
- ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at",
337
- )
338
- elif self.mode == "workflow":
339
- # Query using user_id index
340
- response = self.table.query(
341
- IndexName="user_id-index",
342
- KeyConditionExpression=Key("user_id").eq(user_id),
343
- ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at",
344
- )
345
- elif self.mode == "workflow_v2":
346
- # Query using user_id index
347
- response = self.table.query(
348
- IndexName="user_id-index",
349
- KeyConditionExpression=Key("user_id").eq(user_id),
350
- ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at",
351
- )
352
- items = response.get("Items", []) # type: ignore
353
- for item in items:
354
- item = self._deserialize_item(item)
355
- _session: Optional[Session] = None
356
- if self.mode == "agent":
357
- _session = AgentSession.from_dict(item)
358
- else:
359
- _session = WorkflowSession.from_dict(item) # type: ignore
360
- if _session is not None:
361
- sessions.append(_session)
362
- elif entity_id is not None:
363
- if self.mode == "agent":
364
- # Query using agent_id index
365
- response = self.table.query(
366
- IndexName="agent_id-index",
367
- KeyConditionExpression=Key("agent_id").eq(entity_id),
368
- ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at",
369
- )
370
- elif self.mode == "team":
371
- # Query using team_id index
372
- response = self.table.query(
373
- IndexName="team_id-index",
374
- KeyConditionExpression=Key("team_id").eq(entity_id),
375
- ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at",
376
- )
377
- elif self.mode == "workflow":
378
- # Query using workflow_id index
379
- response = self.table.query(
380
- IndexName="workflow_id-index",
381
- KeyConditionExpression=Key("workflow_id").eq(entity_id),
382
- ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at",
383
- )
384
- elif self.mode == "workflow_v2":
385
- # Query using workflow_id index
386
- response = self.table.query(
387
- IndexName="workflow_id-index",
388
- KeyConditionExpression=Key("workflow_id").eq(entity_id),
389
- ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at",
390
- )
391
- items = response.get("Items", []) # type: ignore
392
- for item in items:
393
- item = self._deserialize_item(item)
394
- if self.mode == "agent":
395
- _session = AgentSession.from_dict(item) # type: ignore
396
- else:
397
- _session = WorkflowSession.from_dict(item) # type: ignore
398
- if _session is not None:
399
- sessions.append(_session)
400
- else:
401
- # Scan the whole table
402
- if self.mode == "agent":
403
- response = self.table.scan(
404
- ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at"
405
- )
406
- elif self.mode == "team":
407
- response = self.table.scan(
408
- ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at"
409
- )
410
- elif self.mode == "workflow":
411
- response = self.table.scan(
412
- ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at"
413
- )
414
- elif self.mode == "workflow_v2":
415
- response = self.table.scan(
416
- ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at"
417
- )
418
- items = response.get("Items", [])
419
- for item in items:
420
- item = self._deserialize_item(item)
421
- if self.mode == "agent":
422
- _session = AgentSession.from_dict(item) # type: ignore
423
- elif self.mode == "team":
424
- _session = TeamSession.from_dict(item) # type: ignore
425
- else:
426
- _session = WorkflowSession.from_dict(item) # type: ignore
427
- if _session is not None:
428
- sessions.append(_session)
429
- except Exception as e:
430
- logger.error(f"Error retrieving sessions: {e}")
431
- return sessions
432
-
433
- def get_recent_sessions(
434
- self,
435
- user_id: Optional[str] = None,
436
- entity_id: Optional[str] = None,
437
- limit: Optional[int] = 2,
438
- ) -> List[Session]:
439
- """Get the last N sessions, ordered by created_at descending.
440
-
441
- Args:
442
- num_history_sessions: Number of most recent sessions to return
443
- user_id: Filter by user ID
444
- entity_id: Filter by entity ID (agent_id, team_id, or workflow_id)
445
-
446
- Returns:
447
- List[Session]: List of most recent sessions
448
- """
449
- sessions: List[Session] = []
450
- try:
451
- if user_id is not None:
452
- if self.mode == "agent":
453
- response = self.table.query(
454
- IndexName="user_id-index",
455
- KeyConditionExpression=Key("user_id").eq(user_id),
456
- ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at",
457
- ScanIndexForward=False,
458
- Limit=limit if limit is not None else None,
459
- )
460
- elif self.mode == "team":
461
- response = self.table.query(
462
- IndexName="user_id-index",
463
- KeyConditionExpression=Key("user_id").eq(user_id),
464
- ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at",
465
- ScanIndexForward=False,
466
- Limit=limit if limit is not None else None,
467
- )
468
- elif self.mode == "workflow":
469
- response = self.table.query(
470
- IndexName="user_id-index",
471
- KeyConditionExpression=Key("user_id").eq(user_id),
472
- ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at",
473
- ScanIndexForward=False,
474
- Limit=limit if limit is not None else None,
475
- )
476
- elif self.mode == "workflow_v2":
477
- response = self.table.query(
478
- IndexName="user_id-index",
479
- KeyConditionExpression=Key("user_id").eq(user_id),
480
- ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at",
481
- ScanIndexForward=False,
482
- Limit=limit if limit is not None else None,
483
- )
484
- elif entity_id is not None:
485
- if self.mode == "agent":
486
- response = self.table.query(
487
- IndexName="agent_id-index",
488
- KeyConditionExpression=Key("agent_id").eq(entity_id),
489
- ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at",
490
- ScanIndexForward=False,
491
- Limit=limit if limit is not None else None,
492
- )
493
- elif self.mode == "team":
494
- response = self.table.query(
495
- IndexName="team_id-index",
496
- KeyConditionExpression=Key("team_id").eq(entity_id),
497
- ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at",
498
- ScanIndexForward=False,
499
- Limit=limit if limit is not None else None,
500
- )
501
- elif self.mode == "workflow":
502
- response = self.table.query(
503
- IndexName="workflow_id-index",
504
- KeyConditionExpression=Key("workflow_id").eq(entity_id),
505
- ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at",
506
- ScanIndexForward=False,
507
- Limit=limit if limit is not None else None,
508
- )
509
- elif self.mode == "workflow_v2":
510
- response = self.table.query(
511
- IndexName="workflow_id-index",
512
- KeyConditionExpression=Key("workflow_id").eq(entity_id),
513
- ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at",
514
- ScanIndexForward=False,
515
- Limit=limit if limit is not None else None,
516
- )
517
- else:
518
- # If no filters, scan the table and sort by created_at
519
- if self.mode == "agent":
520
- response = self.table.scan(
521
- ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at",
522
- Limit=limit if limit is not None else None,
523
- )
524
- elif self.mode == "team":
525
- response = self.table.scan(
526
- ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at",
527
- Limit=limit if limit is not None else None,
528
- )
529
- elif self.mode == "workflow":
530
- response = self.table.scan(
531
- ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at",
532
- Limit=limit if limit is not None else None,
533
- )
534
- elif self.mode == "workflow_v2":
535
- response = self.table.scan(
536
- ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at",
537
- Limit=limit if limit is not None else None,
538
- )
539
- items = response.get("Items", [])
540
- for item in items:
541
- item = self._deserialize_item(item)
542
- session: Optional[Session] = None
543
-
544
- if self.mode == "agent":
545
- session = AgentSession.from_dict(item)
546
- elif self.mode == "team":
547
- session = TeamSession.from_dict(item)
548
- elif self.mode == "workflow":
549
- session = WorkflowSession.from_dict(item)
550
- elif self.mode == "workflow_v2":
551
- session = WorkflowSessionV2.from_dict(item)
552
- if session is not None:
553
- sessions.append(session)
554
-
555
- except Exception as e:
556
- logger.error(f"Error getting last {limit} sessions: {e}")
557
-
558
- return sessions
559
-
560
- def upsert(self, session: Session) -> Optional[Session]:
561
- """
562
- Create or update a Session in the database.
563
-
564
- Args:
565
- session (Session): The session data to upsert.
566
-
567
- Returns:
568
- Optional[Session]: The upserted Session, or None if operation failed.
569
- """
570
- try:
571
- if self.mode == "workflow_v2":
572
- item = session.to_dict()
573
- else:
574
- item = asdict(session)
575
-
576
- # Add timestamps
577
- current_time = int(time.time())
578
- if "created_at" not in item or item["created_at"] is None:
579
- item["created_at"] = current_time
580
- item["updated_at"] = current_time
581
-
582
- # Convert data to DynamoDB compatible format
583
- item = self._serialize_item(item)
584
-
585
- # Put item into DynamoDB
586
- self.table.put_item(Item=item)
587
- return self.read(session.session_id)
588
- except Exception as e:
589
- logger.error(f"Error upserting session: {e}")
590
- return None
591
-
592
- def delete_session(self, session_id: Optional[str] = None):
593
- """
594
- Delete a session from the database.
595
-
596
- Args:
597
- session_id (Optional[str], optional): ID of the session to delete. Defaults to None.
598
- """
599
- if session_id is None:
600
- logger.warning("No session_id provided for deletion.")
601
- return
602
- try:
603
- self.table.delete_item(Key={"session_id": session_id})
604
- log_info(f"Successfully deleted session with session_id: {session_id}")
605
- except Exception as e:
606
- logger.error(f"Error deleting session: {e}")
607
-
608
- def drop(self) -> None:
609
- """
610
- Drop the table from the database if it exists.
611
- """
612
- try:
613
- self.table.delete()
614
- self.table.wait_until_not_exists()
615
- log_debug(f"Table '{self.table_name}' deleted successfully.")
616
- except Exception as e:
617
- logger.error(f"Error deleting table '{self.table_name}': {e}")
618
-
619
- def upgrade_schema(self) -> None:
620
- """
621
- Upgrade the schema to the latest version.
622
- This method is currently a placeholder and does not perform any actions.
623
- """
624
- pass
625
-
626
- def _serialize_item(self, item: Dict[str, Any]) -> Dict[str, Any]:
627
- """
628
- Serialize item to be compatible with DynamoDB.
629
-
630
- Args:
631
- item (Dict[str, Any]): The item to serialize.
632
-
633
- Returns:
634
- Dict[str, Any]: The serialized item.
635
- """
636
-
637
- def serialize_value(value):
638
- if isinstance(value, float):
639
- return Decimal(str(value))
640
- elif isinstance(value, dict):
641
- return {k: serialize_value(v) for k, v in value.items()}
642
- elif isinstance(value, list):
643
- return [serialize_value(v) for v in value]
644
- else:
645
- return value
646
-
647
- return {k: serialize_value(v) for k, v in item.items() if v is not None}
648
-
649
- def _deserialize_item(self, item: Dict[str, Any]) -> Dict[str, Any]:
650
- """
651
- Deserialize item from DynamoDB format.
652
-
653
- Args:
654
- item (Dict[str, Any]): The item to deserialize.
655
-
656
- Returns:
657
- Dict[str, Any]: The deserialized item.
658
- """
659
-
660
- def deserialize_value(value):
661
- if isinstance(value, Decimal):
662
- if value % 1 == 0:
663
- return int(value)
664
- else:
665
- return float(value)
666
- elif isinstance(value, dict):
667
- return {k: deserialize_value(v) for k, v in value.items()}
668
- elif isinstance(value, list):
669
- return [deserialize_value(v) for v in value]
670
- else:
671
- return value
672
-
673
- return {k: deserialize_value(v) for k, v in item.items()}