agno 1.8.1__py3-none-any.whl → 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (590) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +3143 -4170
  4. agno/api/agent.py +11 -67
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +8 -19
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -41
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +5 -21
  11. agno/api/schemas/evals.py +7 -16
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +5 -21
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +11 -7
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +11 -66
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/db/__init__.py +24 -0
  25. agno/db/base.py +245 -0
  26. agno/db/dynamo/__init__.py +3 -0
  27. agno/db/dynamo/dynamo.py +1743 -0
  28. agno/db/dynamo/schemas.py +278 -0
  29. agno/db/dynamo/utils.py +684 -0
  30. agno/db/firestore/__init__.py +3 -0
  31. agno/db/firestore/firestore.py +1432 -0
  32. agno/db/firestore/schemas.py +130 -0
  33. agno/db/firestore/utils.py +278 -0
  34. agno/db/gcs_json/__init__.py +3 -0
  35. agno/db/gcs_json/gcs_json_db.py +1001 -0
  36. agno/db/gcs_json/utils.py +194 -0
  37. agno/db/in_memory/__init__.py +3 -0
  38. agno/db/in_memory/in_memory_db.py +882 -0
  39. agno/db/in_memory/utils.py +172 -0
  40. agno/db/json/__init__.py +3 -0
  41. agno/db/json/json_db.py +1045 -0
  42. agno/db/json/utils.py +196 -0
  43. agno/db/migrations/v1_to_v2.py +162 -0
  44. agno/db/mongo/__init__.py +3 -0
  45. agno/db/mongo/mongo.py +1416 -0
  46. agno/db/mongo/schemas.py +77 -0
  47. agno/db/mongo/utils.py +204 -0
  48. agno/db/mysql/__init__.py +3 -0
  49. agno/db/mysql/mysql.py +1719 -0
  50. agno/db/mysql/schemas.py +124 -0
  51. agno/db/mysql/utils.py +297 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1710 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +280 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1367 -0
  58. agno/db/redis/schemas.py +109 -0
  59. agno/db/redis/utils.py +288 -0
  60. agno/db/schemas/__init__.py +3 -0
  61. agno/db/schemas/evals.py +33 -0
  62. agno/db/schemas/knowledge.py +40 -0
  63. agno/db/schemas/memory.py +46 -0
  64. agno/db/singlestore/__init__.py +3 -0
  65. agno/db/singlestore/schemas.py +116 -0
  66. agno/db/singlestore/singlestore.py +1712 -0
  67. agno/db/singlestore/utils.py +326 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1676 -0
  71. agno/db/sqlite/utils.py +268 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +154 -48
  75. agno/eval/performance.py +88 -23
  76. agno/eval/reliability.py +73 -20
  77. agno/eval/utils.py +23 -13
  78. agno/integrations/discord/__init__.py +3 -0
  79. agno/{app → integrations}/discord/client.py +15 -11
  80. agno/knowledge/__init__.py +2 -2
  81. agno/{document → knowledge}/chunking/agentic.py +2 -2
  82. agno/{document → knowledge}/chunking/document.py +2 -2
  83. agno/{document → knowledge}/chunking/fixed.py +3 -3
  84. agno/{document → knowledge}/chunking/markdown.py +2 -2
  85. agno/{document → knowledge}/chunking/recursive.py +2 -2
  86. agno/{document → knowledge}/chunking/row.py +2 -2
  87. agno/knowledge/chunking/semantic.py +59 -0
  88. agno/knowledge/chunking/strategy.py +121 -0
  89. agno/knowledge/content.py +74 -0
  90. agno/knowledge/document/__init__.py +5 -0
  91. agno/{document → knowledge/document}/base.py +12 -2
  92. agno/knowledge/embedder/__init__.py +5 -0
  93. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  94. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  95. agno/{embedder → knowledge/embedder}/base.py +6 -0
  96. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  97. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  98. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  99. agno/{embedder → knowledge/embedder}/google.py +74 -1
  100. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  101. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  102. agno/knowledge/embedder/langdb.py +22 -0
  103. agno/knowledge/embedder/mistral.py +139 -0
  104. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  105. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  106. agno/knowledge/embedder/openai.py +223 -0
  107. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  108. agno/{embedder → knowledge/embedder}/together.py +1 -1
  109. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  110. agno/knowledge/knowledge.py +1551 -0
  111. agno/knowledge/reader/__init__.py +7 -0
  112. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  113. agno/knowledge/reader/base.py +88 -0
  114. agno/{document → knowledge}/reader/csv_reader.py +47 -65
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/{document → knowledge}/reader/json_reader.py +30 -9
  118. agno/{document → knowledge}/reader/markdown_reader.py +58 -9
  119. agno/{document → knowledge}/reader/pdf_reader.py +71 -126
  120. agno/knowledge/reader/reader_factory.py +268 -0
  121. agno/knowledge/reader/s3_reader.py +101 -0
  122. agno/{document → knowledge}/reader/text_reader.py +31 -10
  123. agno/knowledge/reader/url_reader.py +128 -0
  124. agno/knowledge/reader/web_search_reader.py +366 -0
  125. agno/{document → knowledge}/reader/website_reader.py +37 -10
  126. agno/knowledge/reader/wikipedia_reader.py +59 -0
  127. agno/knowledge/reader/youtube_reader.py +78 -0
  128. agno/knowledge/remote_content/remote_content.py +88 -0
  129. agno/{reranker → knowledge/reranker}/base.py +1 -1
  130. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  131. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  132. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  133. agno/knowledge/types.py +30 -0
  134. agno/knowledge/utils.py +169 -0
  135. agno/media.py +269 -268
  136. agno/memory/__init__.py +2 -10
  137. agno/memory/manager.py +1003 -148
  138. agno/models/aimlapi/__init__.py +2 -2
  139. agno/models/aimlapi/aimlapi.py +6 -6
  140. agno/models/anthropic/claude.py +131 -131
  141. agno/models/aws/bedrock.py +110 -182
  142. agno/models/aws/claude.py +64 -18
  143. agno/models/azure/ai_foundry.py +73 -23
  144. agno/models/base.py +346 -290
  145. agno/models/cerebras/cerebras.py +84 -27
  146. agno/models/cohere/chat.py +106 -98
  147. agno/models/google/gemini.py +105 -46
  148. agno/models/groq/groq.py +97 -35
  149. agno/models/huggingface/huggingface.py +92 -27
  150. agno/models/ibm/watsonx.py +72 -13
  151. agno/models/litellm/chat.py +85 -13
  152. agno/models/message.py +46 -151
  153. agno/models/meta/llama.py +85 -49
  154. agno/models/metrics.py +120 -0
  155. agno/models/mistral/mistral.py +90 -21
  156. agno/models/ollama/__init__.py +0 -2
  157. agno/models/ollama/chat.py +85 -47
  158. agno/models/openai/chat.py +154 -37
  159. agno/models/openai/responses.py +178 -105
  160. agno/models/perplexity/perplexity.py +26 -2
  161. agno/models/portkey/portkey.py +0 -7
  162. agno/models/response.py +15 -9
  163. agno/models/utils.py +20 -0
  164. agno/models/vercel/__init__.py +2 -2
  165. agno/models/vercel/v0.py +1 -1
  166. agno/models/vllm/__init__.py +2 -2
  167. agno/models/vllm/vllm.py +3 -3
  168. agno/models/xai/xai.py +10 -10
  169. agno/os/__init__.py +3 -0
  170. agno/os/app.py +497 -0
  171. agno/os/auth.py +47 -0
  172. agno/os/config.py +103 -0
  173. agno/os/interfaces/agui/__init__.py +3 -0
  174. agno/os/interfaces/agui/agui.py +31 -0
  175. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  176. agno/{app → os/interfaces}/agui/utils.py +77 -33
  177. agno/os/interfaces/base.py +21 -0
  178. agno/os/interfaces/slack/__init__.py +3 -0
  179. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  180. agno/os/interfaces/slack/slack.py +32 -0
  181. agno/os/interfaces/whatsapp/__init__.py +3 -0
  182. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  183. agno/os/interfaces/whatsapp/whatsapp.py +29 -0
  184. agno/os/mcp.py +235 -0
  185. agno/os/router.py +1400 -0
  186. agno/os/routers/__init__.py +3 -0
  187. agno/os/routers/evals/__init__.py +3 -0
  188. agno/os/routers/evals/evals.py +393 -0
  189. agno/os/routers/evals/schemas.py +142 -0
  190. agno/os/routers/evals/utils.py +161 -0
  191. agno/os/routers/knowledge/__init__.py +3 -0
  192. agno/os/routers/knowledge/knowledge.py +850 -0
  193. agno/os/routers/knowledge/schemas.py +118 -0
  194. agno/os/routers/memory/__init__.py +3 -0
  195. agno/os/routers/memory/memory.py +410 -0
  196. agno/os/routers/memory/schemas.py +58 -0
  197. agno/os/routers/metrics/__init__.py +3 -0
  198. agno/os/routers/metrics/metrics.py +178 -0
  199. agno/os/routers/metrics/schemas.py +47 -0
  200. agno/os/routers/session/__init__.py +3 -0
  201. agno/os/routers/session/session.py +536 -0
  202. agno/os/schema.py +945 -0
  203. agno/{app/playground → os}/settings.py +7 -15
  204. agno/os/utils.py +270 -0
  205. agno/reasoning/azure_ai_foundry.py +4 -4
  206. agno/reasoning/deepseek.py +4 -4
  207. agno/reasoning/default.py +6 -11
  208. agno/reasoning/groq.py +4 -4
  209. agno/reasoning/helpers.py +4 -6
  210. agno/reasoning/ollama.py +4 -4
  211. agno/reasoning/openai.py +4 -4
  212. agno/run/agent.py +633 -0
  213. agno/run/base.py +53 -77
  214. agno/run/cancel.py +81 -0
  215. agno/run/team.py +243 -96
  216. agno/run/workflow.py +550 -12
  217. agno/session/__init__.py +10 -0
  218. agno/session/agent.py +244 -0
  219. agno/session/summary.py +225 -0
  220. agno/session/team.py +262 -0
  221. agno/{storage/session/v2 → session}/workflow.py +47 -24
  222. agno/team/__init__.py +15 -16
  223. agno/team/team.py +3260 -4824
  224. agno/tools/agentql.py +14 -5
  225. agno/tools/airflow.py +9 -4
  226. agno/tools/api.py +7 -3
  227. agno/tools/apify.py +2 -46
  228. agno/tools/arxiv.py +8 -3
  229. agno/tools/aws_lambda.py +7 -5
  230. agno/tools/aws_ses.py +7 -1
  231. agno/tools/baidusearch.py +4 -1
  232. agno/tools/bitbucket.py +4 -4
  233. agno/tools/brandfetch.py +14 -11
  234. agno/tools/bravesearch.py +4 -1
  235. agno/tools/brightdata.py +43 -23
  236. agno/tools/browserbase.py +13 -4
  237. agno/tools/calcom.py +12 -10
  238. agno/tools/calculator.py +10 -27
  239. agno/tools/cartesia.py +20 -17
  240. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  241. agno/tools/confluence.py +8 -8
  242. agno/tools/crawl4ai.py +7 -1
  243. agno/tools/csv_toolkit.py +9 -8
  244. agno/tools/dalle.py +22 -12
  245. agno/tools/daytona.py +13 -16
  246. agno/tools/decorator.py +6 -3
  247. agno/tools/desi_vocal.py +17 -8
  248. agno/tools/discord.py +11 -8
  249. agno/tools/docker.py +30 -42
  250. agno/tools/duckdb.py +34 -53
  251. agno/tools/duckduckgo.py +8 -7
  252. agno/tools/e2b.py +62 -62
  253. agno/tools/eleven_labs.py +36 -29
  254. agno/tools/email.py +4 -1
  255. agno/tools/evm.py +7 -1
  256. agno/tools/exa.py +19 -14
  257. agno/tools/fal.py +30 -30
  258. agno/tools/file.py +9 -8
  259. agno/tools/financial_datasets.py +25 -44
  260. agno/tools/firecrawl.py +22 -22
  261. agno/tools/function.py +127 -18
  262. agno/tools/giphy.py +23 -11
  263. agno/tools/github.py +48 -126
  264. agno/tools/gmail.py +45 -61
  265. agno/tools/google_bigquery.py +7 -6
  266. agno/tools/google_maps.py +11 -26
  267. agno/tools/googlesearch.py +7 -2
  268. agno/tools/googlesheets.py +21 -17
  269. agno/tools/hackernews.py +9 -5
  270. agno/tools/jina.py +5 -4
  271. agno/tools/jira.py +18 -9
  272. agno/tools/knowledge.py +31 -32
  273. agno/tools/linear.py +19 -34
  274. agno/tools/linkup.py +5 -1
  275. agno/tools/local_file_system.py +8 -5
  276. agno/tools/lumalab.py +32 -20
  277. agno/tools/mcp.py +1 -2
  278. agno/tools/mem0.py +18 -12
  279. agno/tools/memori.py +14 -10
  280. agno/tools/mlx_transcribe.py +3 -2
  281. agno/tools/models/azure_openai.py +33 -15
  282. agno/tools/models/gemini.py +59 -32
  283. agno/tools/models/groq.py +30 -23
  284. agno/tools/models/nebius.py +28 -12
  285. agno/tools/models_labs.py +40 -16
  286. agno/tools/moviepy_video.py +7 -6
  287. agno/tools/neo4j.py +10 -8
  288. agno/tools/newspaper.py +7 -2
  289. agno/tools/newspaper4k.py +8 -3
  290. agno/tools/openai.py +58 -32
  291. agno/tools/openbb.py +12 -11
  292. agno/tools/opencv.py +63 -47
  293. agno/tools/openweather.py +14 -12
  294. agno/tools/pandas.py +11 -3
  295. agno/tools/postgres.py +4 -12
  296. agno/tools/pubmed.py +4 -1
  297. agno/tools/python.py +9 -22
  298. agno/tools/reasoning.py +35 -27
  299. agno/tools/reddit.py +11 -26
  300. agno/tools/replicate.py +55 -42
  301. agno/tools/resend.py +4 -1
  302. agno/tools/scrapegraph.py +15 -14
  303. agno/tools/searxng.py +10 -23
  304. agno/tools/serpapi.py +6 -3
  305. agno/tools/serper.py +13 -4
  306. agno/tools/shell.py +9 -2
  307. agno/tools/slack.py +12 -11
  308. agno/tools/sleep.py +3 -2
  309. agno/tools/spider.py +24 -4
  310. agno/tools/sql.py +7 -6
  311. agno/tools/tavily.py +6 -4
  312. agno/tools/telegram.py +12 -4
  313. agno/tools/todoist.py +11 -31
  314. agno/tools/toolkit.py +1 -1
  315. agno/tools/trafilatura.py +22 -6
  316. agno/tools/trello.py +9 -22
  317. agno/tools/twilio.py +10 -3
  318. agno/tools/user_control_flow.py +6 -1
  319. agno/tools/valyu.py +34 -5
  320. agno/tools/visualization.py +19 -28
  321. agno/tools/webbrowser.py +4 -3
  322. agno/tools/webex.py +11 -7
  323. agno/tools/website.py +15 -46
  324. agno/tools/webtools.py +12 -4
  325. agno/tools/whatsapp.py +5 -9
  326. agno/tools/wikipedia.py +20 -13
  327. agno/tools/x.py +14 -13
  328. agno/tools/yfinance.py +13 -40
  329. agno/tools/youtube.py +26 -20
  330. agno/tools/zendesk.py +7 -2
  331. agno/tools/zep.py +10 -7
  332. agno/tools/zoom.py +10 -9
  333. agno/utils/common.py +1 -19
  334. agno/utils/events.py +100 -123
  335. agno/utils/gemini.py +32 -2
  336. agno/utils/knowledge.py +29 -0
  337. agno/utils/log.py +54 -4
  338. agno/utils/mcp.py +68 -10
  339. agno/utils/media.py +39 -0
  340. agno/utils/message.py +12 -1
  341. agno/utils/models/aws_claude.py +1 -1
  342. agno/utils/models/claude.py +47 -4
  343. agno/utils/models/cohere.py +1 -1
  344. agno/utils/models/mistral.py +8 -7
  345. agno/utils/models/schema_utils.py +3 -3
  346. agno/utils/models/watsonx.py +1 -1
  347. agno/utils/openai.py +1 -1
  348. agno/utils/pprint.py +33 -32
  349. agno/utils/print_response/agent.py +779 -0
  350. agno/utils/print_response/team.py +1669 -0
  351. agno/utils/print_response/workflow.py +1451 -0
  352. agno/utils/prompts.py +14 -14
  353. agno/utils/reasoning.py +87 -0
  354. agno/utils/response.py +42 -42
  355. agno/utils/streamlit.py +481 -0
  356. agno/utils/string.py +8 -22
  357. agno/utils/team.py +50 -0
  358. agno/utils/timer.py +2 -2
  359. agno/vectordb/base.py +33 -21
  360. agno/vectordb/cassandra/cassandra.py +287 -23
  361. agno/vectordb/chroma/chromadb.py +482 -59
  362. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  363. agno/vectordb/couchbase/couchbase.py +309 -29
  364. agno/vectordb/lancedb/lance_db.py +360 -21
  365. agno/vectordb/langchaindb/__init__.py +5 -0
  366. agno/vectordb/langchaindb/langchaindb.py +145 -0
  367. agno/vectordb/lightrag/__init__.py +5 -0
  368. agno/vectordb/lightrag/lightrag.py +374 -0
  369. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  370. agno/vectordb/milvus/milvus.py +242 -32
  371. agno/vectordb/mongodb/mongodb.py +200 -24
  372. agno/vectordb/pgvector/pgvector.py +319 -37
  373. agno/vectordb/pineconedb/pineconedb.py +221 -27
  374. agno/vectordb/qdrant/qdrant.py +334 -14
  375. agno/vectordb/singlestore/singlestore.py +286 -29
  376. agno/vectordb/surrealdb/surrealdb.py +187 -7
  377. agno/vectordb/upstashdb/upstashdb.py +342 -26
  378. agno/vectordb/weaviate/weaviate.py +227 -165
  379. agno/workflow/__init__.py +17 -13
  380. agno/workflow/{v2/condition.py → condition.py} +135 -32
  381. agno/workflow/{v2/loop.py → loop.py} +115 -28
  382. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  383. agno/workflow/{v2/router.py → router.py} +133 -32
  384. agno/workflow/{v2/step.py → step.py} +207 -49
  385. agno/workflow/{v2/steps.py → steps.py} +147 -66
  386. agno/workflow/types.py +482 -0
  387. agno/workflow/workflow.py +2410 -696
  388. agno-2.0.0.dist-info/METADATA +494 -0
  389. agno-2.0.0.dist-info/RECORD +515 -0
  390. agno-2.0.0.dist-info/licenses/LICENSE +201 -0
  391. agno/agent/metrics.py +0 -107
  392. agno/api/app.py +0 -35
  393. agno/api/playground.py +0 -92
  394. agno/api/schemas/app.py +0 -12
  395. agno/api/schemas/playground.py +0 -22
  396. agno/api/schemas/user.py +0 -35
  397. agno/api/schemas/workspace.py +0 -46
  398. agno/api/user.py +0 -160
  399. agno/api/workflows.py +0 -33
  400. agno/api/workspace.py +0 -175
  401. agno/app/agui/__init__.py +0 -3
  402. agno/app/agui/app.py +0 -17
  403. agno/app/agui/sync_router.py +0 -120
  404. agno/app/base.py +0 -186
  405. agno/app/discord/__init__.py +0 -3
  406. agno/app/fastapi/__init__.py +0 -3
  407. agno/app/fastapi/app.py +0 -107
  408. agno/app/fastapi/async_router.py +0 -457
  409. agno/app/fastapi/sync_router.py +0 -448
  410. agno/app/playground/app.py +0 -228
  411. agno/app/playground/async_router.py +0 -1050
  412. agno/app/playground/deploy.py +0 -249
  413. agno/app/playground/operator.py +0 -183
  414. agno/app/playground/schemas.py +0 -220
  415. agno/app/playground/serve.py +0 -55
  416. agno/app/playground/sync_router.py +0 -1042
  417. agno/app/playground/utils.py +0 -46
  418. agno/app/settings.py +0 -15
  419. agno/app/slack/__init__.py +0 -3
  420. agno/app/slack/app.py +0 -19
  421. agno/app/slack/sync_router.py +0 -92
  422. agno/app/utils.py +0 -54
  423. agno/app/whatsapp/__init__.py +0 -3
  424. agno/app/whatsapp/app.py +0 -15
  425. agno/app/whatsapp/sync_router.py +0 -197
  426. agno/cli/auth_server.py +0 -249
  427. agno/cli/config.py +0 -274
  428. agno/cli/console.py +0 -88
  429. agno/cli/credentials.py +0 -23
  430. agno/cli/entrypoint.py +0 -571
  431. agno/cli/operator.py +0 -357
  432. agno/cli/settings.py +0 -96
  433. agno/cli/ws/ws_cli.py +0 -817
  434. agno/constants.py +0 -13
  435. agno/document/__init__.py +0 -5
  436. agno/document/chunking/semantic.py +0 -45
  437. agno/document/chunking/strategy.py +0 -31
  438. agno/document/reader/__init__.py +0 -5
  439. agno/document/reader/base.py +0 -47
  440. agno/document/reader/docx_reader.py +0 -60
  441. agno/document/reader/gcs/pdf_reader.py +0 -44
  442. agno/document/reader/s3/pdf_reader.py +0 -59
  443. agno/document/reader/s3/text_reader.py +0 -63
  444. agno/document/reader/url_reader.py +0 -59
  445. agno/document/reader/youtube_reader.py +0 -58
  446. agno/embedder/__init__.py +0 -5
  447. agno/embedder/langdb.py +0 -80
  448. agno/embedder/mistral.py +0 -82
  449. agno/embedder/openai.py +0 -78
  450. agno/file/__init__.py +0 -5
  451. agno/file/file.py +0 -16
  452. agno/file/local/csv.py +0 -32
  453. agno/file/local/txt.py +0 -19
  454. agno/infra/app.py +0 -240
  455. agno/infra/base.py +0 -144
  456. agno/infra/context.py +0 -20
  457. agno/infra/db_app.py +0 -52
  458. agno/infra/resource.py +0 -205
  459. agno/infra/resources.py +0 -55
  460. agno/knowledge/agent.py +0 -702
  461. agno/knowledge/arxiv.py +0 -33
  462. agno/knowledge/combined.py +0 -36
  463. agno/knowledge/csv.py +0 -144
  464. agno/knowledge/csv_url.py +0 -124
  465. agno/knowledge/document.py +0 -223
  466. agno/knowledge/docx.py +0 -137
  467. agno/knowledge/firecrawl.py +0 -34
  468. agno/knowledge/gcs/__init__.py +0 -0
  469. agno/knowledge/gcs/base.py +0 -39
  470. agno/knowledge/gcs/pdf.py +0 -125
  471. agno/knowledge/json.py +0 -137
  472. agno/knowledge/langchain.py +0 -71
  473. agno/knowledge/light_rag.py +0 -273
  474. agno/knowledge/llamaindex.py +0 -66
  475. agno/knowledge/markdown.py +0 -154
  476. agno/knowledge/pdf.py +0 -164
  477. agno/knowledge/pdf_bytes.py +0 -42
  478. agno/knowledge/pdf_url.py +0 -148
  479. agno/knowledge/s3/__init__.py +0 -0
  480. agno/knowledge/s3/base.py +0 -64
  481. agno/knowledge/s3/pdf.py +0 -33
  482. agno/knowledge/s3/text.py +0 -34
  483. agno/knowledge/text.py +0 -141
  484. agno/knowledge/url.py +0 -46
  485. agno/knowledge/website.py +0 -179
  486. agno/knowledge/wikipedia.py +0 -32
  487. agno/knowledge/youtube.py +0 -35
  488. agno/memory/agent.py +0 -423
  489. agno/memory/classifier.py +0 -104
  490. agno/memory/db/__init__.py +0 -5
  491. agno/memory/db/base.py +0 -42
  492. agno/memory/db/mongodb.py +0 -189
  493. agno/memory/db/postgres.py +0 -203
  494. agno/memory/db/sqlite.py +0 -193
  495. agno/memory/memory.py +0 -22
  496. agno/memory/row.py +0 -36
  497. agno/memory/summarizer.py +0 -201
  498. agno/memory/summary.py +0 -19
  499. agno/memory/team.py +0 -415
  500. agno/memory/v2/__init__.py +0 -2
  501. agno/memory/v2/db/__init__.py +0 -1
  502. agno/memory/v2/db/base.py +0 -42
  503. agno/memory/v2/db/firestore.py +0 -339
  504. agno/memory/v2/db/mongodb.py +0 -196
  505. agno/memory/v2/db/postgres.py +0 -214
  506. agno/memory/v2/db/redis.py +0 -187
  507. agno/memory/v2/db/schema.py +0 -54
  508. agno/memory/v2/db/sqlite.py +0 -209
  509. agno/memory/v2/manager.py +0 -437
  510. agno/memory/v2/memory.py +0 -1097
  511. agno/memory/v2/schema.py +0 -55
  512. agno/memory/v2/summarizer.py +0 -215
  513. agno/memory/workflow.py +0 -38
  514. agno/models/ollama/tools.py +0 -430
  515. agno/models/qwen/__init__.py +0 -5
  516. agno/playground/__init__.py +0 -10
  517. agno/playground/deploy.py +0 -3
  518. agno/playground/playground.py +0 -3
  519. agno/playground/serve.py +0 -3
  520. agno/playground/settings.py +0 -3
  521. agno/reranker/__init__.py +0 -0
  522. agno/run/response.py +0 -467
  523. agno/run/v2/__init__.py +0 -0
  524. agno/run/v2/workflow.py +0 -567
  525. agno/storage/__init__.py +0 -0
  526. agno/storage/agent/__init__.py +0 -0
  527. agno/storage/agent/dynamodb.py +0 -1
  528. agno/storage/agent/json.py +0 -1
  529. agno/storage/agent/mongodb.py +0 -1
  530. agno/storage/agent/postgres.py +0 -1
  531. agno/storage/agent/singlestore.py +0 -1
  532. agno/storage/agent/sqlite.py +0 -1
  533. agno/storage/agent/yaml.py +0 -1
  534. agno/storage/base.py +0 -60
  535. agno/storage/dynamodb.py +0 -673
  536. agno/storage/firestore.py +0 -297
  537. agno/storage/gcs_json.py +0 -261
  538. agno/storage/in_memory.py +0 -234
  539. agno/storage/json.py +0 -237
  540. agno/storage/mongodb.py +0 -328
  541. agno/storage/mysql.py +0 -685
  542. agno/storage/postgres.py +0 -682
  543. agno/storage/redis.py +0 -336
  544. agno/storage/session/__init__.py +0 -16
  545. agno/storage/session/agent.py +0 -64
  546. agno/storage/session/team.py +0 -63
  547. agno/storage/session/v2/__init__.py +0 -5
  548. agno/storage/session/workflow.py +0 -61
  549. agno/storage/singlestore.py +0 -606
  550. agno/storage/sqlite.py +0 -646
  551. agno/storage/workflow/__init__.py +0 -0
  552. agno/storage/workflow/mongodb.py +0 -1
  553. agno/storage/workflow/postgres.py +0 -1
  554. agno/storage/workflow/sqlite.py +0 -1
  555. agno/storage/yaml.py +0 -241
  556. agno/tools/thinking.py +0 -73
  557. agno/utils/defaults.py +0 -57
  558. agno/utils/filesystem.py +0 -39
  559. agno/utils/git.py +0 -52
  560. agno/utils/json_io.py +0 -30
  561. agno/utils/load_env.py +0 -19
  562. agno/utils/py_io.py +0 -19
  563. agno/utils/pyproject.py +0 -18
  564. agno/utils/resource_filter.py +0 -31
  565. agno/workflow/v2/__init__.py +0 -21
  566. agno/workflow/v2/types.py +0 -357
  567. agno/workflow/v2/workflow.py +0 -3312
  568. agno/workspace/__init__.py +0 -0
  569. agno/workspace/config.py +0 -325
  570. agno/workspace/enums.py +0 -6
  571. agno/workspace/helpers.py +0 -52
  572. agno/workspace/operator.py +0 -757
  573. agno/workspace/settings.py +0 -158
  574. agno-1.8.1.dist-info/METADATA +0 -982
  575. agno-1.8.1.dist-info/RECORD +0 -566
  576. agno-1.8.1.dist-info/entry_points.txt +0 -3
  577. agno-1.8.1.dist-info/licenses/LICENSE +0 -375
  578. /agno/{app → db/migrations}/__init__.py +0 -0
  579. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  580. /agno/{cli → integrations}/__init__.py +0 -0
  581. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  582. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  583. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  584. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  585. /agno/{app → os/interfaces}/slack/security.py +0 -0
  586. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  587. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  588. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  589. {agno-1.8.1.dist-info → agno-2.0.0.dist-info}/WHEEL +0 -0
  590. {agno-1.8.1.dist-info → agno-2.0.0.dist-info}/top_level.txt +0 -0
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()}