agno 0.1.2__py3-none-any.whl → 2.3.13__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 (723) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +44 -5
  3. agno/agent/agent.py +10531 -2975
  4. agno/api/agent.py +14 -53
  5. agno/api/api.py +7 -46
  6. agno/api/evals.py +22 -0
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -25
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +6 -9
  11. agno/api/schemas/evals.py +16 -0
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +10 -10
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +16 -0
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +22 -26
  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/compression/__init__.py +3 -0
  25. agno/compression/manager.py +247 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +946 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2781 -0
  33. agno/db/dynamo/schemas.py +442 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +2379 -0
  37. agno/db/firestore/schemas.py +181 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1791 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1312 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1777 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/manager.py +199 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/migrations/versions/v2_3_0.py +938 -0
  51. agno/db/mongo/__init__.py +17 -0
  52. agno/db/mongo/async_mongo.py +2760 -0
  53. agno/db/mongo/mongo.py +2597 -0
  54. agno/db/mongo/schemas.py +119 -0
  55. agno/db/mongo/utils.py +276 -0
  56. agno/db/mysql/__init__.py +4 -0
  57. agno/db/mysql/async_mysql.py +2912 -0
  58. agno/db/mysql/mysql.py +2923 -0
  59. agno/db/mysql/schemas.py +186 -0
  60. agno/db/mysql/utils.py +488 -0
  61. agno/db/postgres/__init__.py +4 -0
  62. agno/db/postgres/async_postgres.py +2579 -0
  63. agno/db/postgres/postgres.py +2870 -0
  64. agno/db/postgres/schemas.py +187 -0
  65. agno/db/postgres/utils.py +442 -0
  66. agno/db/redis/__init__.py +3 -0
  67. agno/db/redis/redis.py +2141 -0
  68. agno/db/redis/schemas.py +159 -0
  69. agno/db/redis/utils.py +346 -0
  70. agno/db/schemas/__init__.py +4 -0
  71. agno/db/schemas/culture.py +120 -0
  72. agno/db/schemas/evals.py +34 -0
  73. agno/db/schemas/knowledge.py +40 -0
  74. agno/db/schemas/memory.py +61 -0
  75. agno/db/singlestore/__init__.py +3 -0
  76. agno/db/singlestore/schemas.py +179 -0
  77. agno/db/singlestore/singlestore.py +2877 -0
  78. agno/db/singlestore/utils.py +384 -0
  79. agno/db/sqlite/__init__.py +4 -0
  80. agno/db/sqlite/async_sqlite.py +2911 -0
  81. agno/db/sqlite/schemas.py +181 -0
  82. agno/db/sqlite/sqlite.py +2908 -0
  83. agno/db/sqlite/utils.py +429 -0
  84. agno/db/surrealdb/__init__.py +3 -0
  85. agno/db/surrealdb/metrics.py +292 -0
  86. agno/db/surrealdb/models.py +334 -0
  87. agno/db/surrealdb/queries.py +71 -0
  88. agno/db/surrealdb/surrealdb.py +1908 -0
  89. agno/db/surrealdb/utils.py +147 -0
  90. agno/db/utils.py +118 -0
  91. agno/eval/__init__.py +24 -0
  92. agno/eval/accuracy.py +666 -276
  93. agno/eval/agent_as_judge.py +861 -0
  94. agno/eval/base.py +29 -0
  95. agno/eval/performance.py +779 -0
  96. agno/eval/reliability.py +241 -62
  97. agno/eval/utils.py +120 -0
  98. agno/exceptions.py +143 -1
  99. agno/filters.py +354 -0
  100. agno/guardrails/__init__.py +6 -0
  101. agno/guardrails/base.py +19 -0
  102. agno/guardrails/openai.py +144 -0
  103. agno/guardrails/pii.py +94 -0
  104. agno/guardrails/prompt_injection.py +52 -0
  105. agno/hooks/__init__.py +3 -0
  106. agno/hooks/decorator.py +164 -0
  107. agno/integrations/discord/__init__.py +3 -0
  108. agno/integrations/discord/client.py +203 -0
  109. agno/knowledge/__init__.py +5 -1
  110. agno/{document → knowledge}/chunking/agentic.py +22 -14
  111. agno/{document → knowledge}/chunking/document.py +2 -2
  112. agno/{document → knowledge}/chunking/fixed.py +7 -6
  113. agno/knowledge/chunking/markdown.py +151 -0
  114. agno/{document → knowledge}/chunking/recursive.py +15 -3
  115. agno/knowledge/chunking/row.py +39 -0
  116. agno/knowledge/chunking/semantic.py +91 -0
  117. agno/knowledge/chunking/strategy.py +165 -0
  118. agno/knowledge/content.py +74 -0
  119. agno/knowledge/document/__init__.py +5 -0
  120. agno/{document → knowledge/document}/base.py +12 -2
  121. agno/knowledge/embedder/__init__.py +5 -0
  122. agno/knowledge/embedder/aws_bedrock.py +343 -0
  123. agno/knowledge/embedder/azure_openai.py +210 -0
  124. agno/{embedder → knowledge/embedder}/base.py +8 -0
  125. agno/knowledge/embedder/cohere.py +323 -0
  126. agno/knowledge/embedder/fastembed.py +62 -0
  127. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  128. agno/knowledge/embedder/google.py +258 -0
  129. agno/knowledge/embedder/huggingface.py +94 -0
  130. agno/knowledge/embedder/jina.py +182 -0
  131. agno/knowledge/embedder/langdb.py +22 -0
  132. agno/knowledge/embedder/mistral.py +206 -0
  133. agno/knowledge/embedder/nebius.py +13 -0
  134. agno/knowledge/embedder/ollama.py +154 -0
  135. agno/knowledge/embedder/openai.py +195 -0
  136. agno/knowledge/embedder/sentence_transformer.py +63 -0
  137. agno/{embedder → knowledge/embedder}/together.py +1 -1
  138. agno/knowledge/embedder/vllm.py +262 -0
  139. agno/knowledge/embedder/voyageai.py +165 -0
  140. agno/knowledge/knowledge.py +3006 -0
  141. agno/knowledge/reader/__init__.py +7 -0
  142. agno/knowledge/reader/arxiv_reader.py +81 -0
  143. agno/knowledge/reader/base.py +95 -0
  144. agno/knowledge/reader/csv_reader.py +164 -0
  145. agno/knowledge/reader/docx_reader.py +82 -0
  146. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  147. agno/knowledge/reader/firecrawl_reader.py +201 -0
  148. agno/knowledge/reader/json_reader.py +88 -0
  149. agno/knowledge/reader/markdown_reader.py +137 -0
  150. agno/knowledge/reader/pdf_reader.py +431 -0
  151. agno/knowledge/reader/pptx_reader.py +101 -0
  152. agno/knowledge/reader/reader_factory.py +313 -0
  153. agno/knowledge/reader/s3_reader.py +89 -0
  154. agno/knowledge/reader/tavily_reader.py +193 -0
  155. agno/knowledge/reader/text_reader.py +127 -0
  156. agno/knowledge/reader/web_search_reader.py +325 -0
  157. agno/knowledge/reader/website_reader.py +455 -0
  158. agno/knowledge/reader/wikipedia_reader.py +91 -0
  159. agno/knowledge/reader/youtube_reader.py +78 -0
  160. agno/knowledge/remote_content/remote_content.py +88 -0
  161. agno/knowledge/reranker/__init__.py +3 -0
  162. agno/{reranker → knowledge/reranker}/base.py +1 -1
  163. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  164. agno/knowledge/reranker/infinity.py +195 -0
  165. agno/knowledge/reranker/sentence_transformer.py +54 -0
  166. agno/knowledge/types.py +39 -0
  167. agno/knowledge/utils.py +234 -0
  168. agno/media.py +439 -95
  169. agno/memory/__init__.py +16 -3
  170. agno/memory/manager.py +1474 -123
  171. agno/memory/strategies/__init__.py +15 -0
  172. agno/memory/strategies/base.py +66 -0
  173. agno/memory/strategies/summarize.py +196 -0
  174. agno/memory/strategies/types.py +37 -0
  175. agno/models/aimlapi/__init__.py +5 -0
  176. agno/models/aimlapi/aimlapi.py +62 -0
  177. agno/models/anthropic/__init__.py +4 -0
  178. agno/models/anthropic/claude.py +960 -496
  179. agno/models/aws/__init__.py +15 -0
  180. agno/models/aws/bedrock.py +686 -451
  181. agno/models/aws/claude.py +190 -183
  182. agno/models/azure/__init__.py +18 -1
  183. agno/models/azure/ai_foundry.py +489 -0
  184. agno/models/azure/openai_chat.py +89 -40
  185. agno/models/base.py +2477 -550
  186. agno/models/cerebras/__init__.py +12 -0
  187. agno/models/cerebras/cerebras.py +565 -0
  188. agno/models/cerebras/cerebras_openai.py +131 -0
  189. agno/models/cohere/__init__.py +4 -0
  190. agno/models/cohere/chat.py +306 -492
  191. agno/models/cometapi/__init__.py +5 -0
  192. agno/models/cometapi/cometapi.py +74 -0
  193. agno/models/dashscope/__init__.py +5 -0
  194. agno/models/dashscope/dashscope.py +90 -0
  195. agno/models/deepinfra/__init__.py +5 -0
  196. agno/models/deepinfra/deepinfra.py +45 -0
  197. agno/models/deepseek/__init__.py +4 -0
  198. agno/models/deepseek/deepseek.py +110 -9
  199. agno/models/fireworks/__init__.py +4 -0
  200. agno/models/fireworks/fireworks.py +19 -22
  201. agno/models/google/__init__.py +3 -7
  202. agno/models/google/gemini.py +1717 -662
  203. agno/models/google/utils.py +22 -0
  204. agno/models/groq/__init__.py +4 -0
  205. agno/models/groq/groq.py +391 -666
  206. agno/models/huggingface/__init__.py +4 -0
  207. agno/models/huggingface/huggingface.py +266 -538
  208. agno/models/ibm/__init__.py +5 -0
  209. agno/models/ibm/watsonx.py +432 -0
  210. agno/models/internlm/__init__.py +3 -0
  211. agno/models/internlm/internlm.py +20 -3
  212. agno/models/langdb/__init__.py +1 -0
  213. agno/models/langdb/langdb.py +60 -0
  214. agno/models/litellm/__init__.py +14 -0
  215. agno/models/litellm/chat.py +503 -0
  216. agno/models/litellm/litellm_openai.py +42 -0
  217. agno/models/llama_cpp/__init__.py +5 -0
  218. agno/models/llama_cpp/llama_cpp.py +22 -0
  219. agno/models/lmstudio/__init__.py +5 -0
  220. agno/models/lmstudio/lmstudio.py +25 -0
  221. agno/models/message.py +361 -39
  222. agno/models/meta/__init__.py +12 -0
  223. agno/models/meta/llama.py +502 -0
  224. agno/models/meta/llama_openai.py +79 -0
  225. agno/models/metrics.py +120 -0
  226. agno/models/mistral/__init__.py +4 -0
  227. agno/models/mistral/mistral.py +293 -393
  228. agno/models/nebius/__init__.py +3 -0
  229. agno/models/nebius/nebius.py +53 -0
  230. agno/models/nexus/__init__.py +3 -0
  231. agno/models/nexus/nexus.py +22 -0
  232. agno/models/nvidia/__init__.py +4 -0
  233. agno/models/nvidia/nvidia.py +22 -3
  234. agno/models/ollama/__init__.py +4 -2
  235. agno/models/ollama/chat.py +257 -492
  236. agno/models/openai/__init__.py +7 -0
  237. agno/models/openai/chat.py +725 -770
  238. agno/models/openai/like.py +16 -2
  239. agno/models/openai/responses.py +1121 -0
  240. agno/models/openrouter/__init__.py +4 -0
  241. agno/models/openrouter/openrouter.py +62 -5
  242. agno/models/perplexity/__init__.py +5 -0
  243. agno/models/perplexity/perplexity.py +203 -0
  244. agno/models/portkey/__init__.py +3 -0
  245. agno/models/portkey/portkey.py +82 -0
  246. agno/models/requesty/__init__.py +5 -0
  247. agno/models/requesty/requesty.py +69 -0
  248. agno/models/response.py +177 -7
  249. agno/models/sambanova/__init__.py +4 -0
  250. agno/models/sambanova/sambanova.py +23 -4
  251. agno/models/siliconflow/__init__.py +5 -0
  252. agno/models/siliconflow/siliconflow.py +42 -0
  253. agno/models/together/__init__.py +4 -0
  254. agno/models/together/together.py +21 -164
  255. agno/models/utils.py +266 -0
  256. agno/models/vercel/__init__.py +3 -0
  257. agno/models/vercel/v0.py +43 -0
  258. agno/models/vertexai/__init__.py +0 -1
  259. agno/models/vertexai/claude.py +190 -0
  260. agno/models/vllm/__init__.py +3 -0
  261. agno/models/vllm/vllm.py +83 -0
  262. agno/models/xai/__init__.py +2 -0
  263. agno/models/xai/xai.py +111 -7
  264. agno/os/__init__.py +3 -0
  265. agno/os/app.py +1027 -0
  266. agno/os/auth.py +244 -0
  267. agno/os/config.py +126 -0
  268. agno/os/interfaces/__init__.py +1 -0
  269. agno/os/interfaces/a2a/__init__.py +3 -0
  270. agno/os/interfaces/a2a/a2a.py +42 -0
  271. agno/os/interfaces/a2a/router.py +249 -0
  272. agno/os/interfaces/a2a/utils.py +924 -0
  273. agno/os/interfaces/agui/__init__.py +3 -0
  274. agno/os/interfaces/agui/agui.py +47 -0
  275. agno/os/interfaces/agui/router.py +147 -0
  276. agno/os/interfaces/agui/utils.py +574 -0
  277. agno/os/interfaces/base.py +25 -0
  278. agno/os/interfaces/slack/__init__.py +3 -0
  279. agno/os/interfaces/slack/router.py +148 -0
  280. agno/os/interfaces/slack/security.py +30 -0
  281. agno/os/interfaces/slack/slack.py +47 -0
  282. agno/os/interfaces/whatsapp/__init__.py +3 -0
  283. agno/os/interfaces/whatsapp/router.py +210 -0
  284. agno/os/interfaces/whatsapp/security.py +55 -0
  285. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  286. agno/os/mcp.py +293 -0
  287. agno/os/middleware/__init__.py +9 -0
  288. agno/os/middleware/jwt.py +797 -0
  289. agno/os/router.py +258 -0
  290. agno/os/routers/__init__.py +3 -0
  291. agno/os/routers/agents/__init__.py +3 -0
  292. agno/os/routers/agents/router.py +599 -0
  293. agno/os/routers/agents/schema.py +261 -0
  294. agno/os/routers/evals/__init__.py +3 -0
  295. agno/os/routers/evals/evals.py +450 -0
  296. agno/os/routers/evals/schemas.py +174 -0
  297. agno/os/routers/evals/utils.py +231 -0
  298. agno/os/routers/health.py +31 -0
  299. agno/os/routers/home.py +52 -0
  300. agno/os/routers/knowledge/__init__.py +3 -0
  301. agno/os/routers/knowledge/knowledge.py +1008 -0
  302. agno/os/routers/knowledge/schemas.py +178 -0
  303. agno/os/routers/memory/__init__.py +3 -0
  304. agno/os/routers/memory/memory.py +661 -0
  305. agno/os/routers/memory/schemas.py +88 -0
  306. agno/os/routers/metrics/__init__.py +3 -0
  307. agno/os/routers/metrics/metrics.py +190 -0
  308. agno/os/routers/metrics/schemas.py +47 -0
  309. agno/os/routers/session/__init__.py +3 -0
  310. agno/os/routers/session/session.py +997 -0
  311. agno/os/routers/teams/__init__.py +3 -0
  312. agno/os/routers/teams/router.py +512 -0
  313. agno/os/routers/teams/schema.py +257 -0
  314. agno/os/routers/traces/__init__.py +3 -0
  315. agno/os/routers/traces/schemas.py +414 -0
  316. agno/os/routers/traces/traces.py +499 -0
  317. agno/os/routers/workflows/__init__.py +3 -0
  318. agno/os/routers/workflows/router.py +624 -0
  319. agno/os/routers/workflows/schema.py +75 -0
  320. agno/os/schema.py +534 -0
  321. agno/os/scopes.py +469 -0
  322. agno/{playground → os}/settings.py +7 -15
  323. agno/os/utils.py +973 -0
  324. agno/reasoning/anthropic.py +80 -0
  325. agno/reasoning/azure_ai_foundry.py +67 -0
  326. agno/reasoning/deepseek.py +63 -0
  327. agno/reasoning/default.py +97 -0
  328. agno/reasoning/gemini.py +73 -0
  329. agno/reasoning/groq.py +71 -0
  330. agno/reasoning/helpers.py +24 -1
  331. agno/reasoning/ollama.py +67 -0
  332. agno/reasoning/openai.py +86 -0
  333. agno/reasoning/step.py +2 -1
  334. agno/reasoning/vertexai.py +76 -0
  335. agno/run/__init__.py +6 -0
  336. agno/run/agent.py +822 -0
  337. agno/run/base.py +247 -0
  338. agno/run/cancel.py +81 -0
  339. agno/run/requirement.py +181 -0
  340. agno/run/team.py +767 -0
  341. agno/run/workflow.py +708 -0
  342. agno/session/__init__.py +10 -0
  343. agno/session/agent.py +260 -0
  344. agno/session/summary.py +265 -0
  345. agno/session/team.py +342 -0
  346. agno/session/workflow.py +501 -0
  347. agno/table.py +10 -0
  348. agno/team/__init__.py +37 -0
  349. agno/team/team.py +9536 -0
  350. agno/tools/__init__.py +7 -0
  351. agno/tools/agentql.py +120 -0
  352. agno/tools/airflow.py +22 -12
  353. agno/tools/api.py +122 -0
  354. agno/tools/apify.py +276 -83
  355. agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
  356. agno/tools/aws_lambda.py +28 -7
  357. agno/tools/aws_ses.py +66 -0
  358. agno/tools/baidusearch.py +11 -4
  359. agno/tools/bitbucket.py +292 -0
  360. agno/tools/brandfetch.py +213 -0
  361. agno/tools/bravesearch.py +106 -0
  362. agno/tools/brightdata.py +367 -0
  363. agno/tools/browserbase.py +209 -0
  364. agno/tools/calcom.py +32 -23
  365. agno/tools/calculator.py +24 -37
  366. agno/tools/cartesia.py +187 -0
  367. agno/tools/{clickup_tool.py → clickup.py} +17 -28
  368. agno/tools/confluence.py +91 -26
  369. agno/tools/crawl4ai.py +139 -43
  370. agno/tools/csv_toolkit.py +28 -22
  371. agno/tools/dalle.py +36 -22
  372. agno/tools/daytona.py +475 -0
  373. agno/tools/decorator.py +169 -14
  374. agno/tools/desi_vocal.py +23 -11
  375. agno/tools/discord.py +32 -29
  376. agno/tools/docker.py +716 -0
  377. agno/tools/duckdb.py +76 -81
  378. agno/tools/duckduckgo.py +43 -40
  379. agno/tools/e2b.py +703 -0
  380. agno/tools/eleven_labs.py +65 -54
  381. agno/tools/email.py +13 -5
  382. agno/tools/evm.py +129 -0
  383. agno/tools/exa.py +324 -42
  384. agno/tools/fal.py +39 -35
  385. agno/tools/file.py +196 -30
  386. agno/tools/file_generation.py +356 -0
  387. agno/tools/financial_datasets.py +288 -0
  388. agno/tools/firecrawl.py +108 -33
  389. agno/tools/function.py +960 -122
  390. agno/tools/giphy.py +34 -12
  391. agno/tools/github.py +1294 -97
  392. agno/tools/gmail.py +922 -0
  393. agno/tools/google_bigquery.py +117 -0
  394. agno/tools/google_drive.py +271 -0
  395. agno/tools/google_maps.py +253 -0
  396. agno/tools/googlecalendar.py +607 -107
  397. agno/tools/googlesheets.py +377 -0
  398. agno/tools/hackernews.py +20 -12
  399. agno/tools/jina.py +24 -14
  400. agno/tools/jira.py +48 -19
  401. agno/tools/knowledge.py +218 -0
  402. agno/tools/linear.py +82 -43
  403. agno/tools/linkup.py +58 -0
  404. agno/tools/local_file_system.py +15 -7
  405. agno/tools/lumalab.py +41 -26
  406. agno/tools/mcp/__init__.py +10 -0
  407. agno/tools/mcp/mcp.py +331 -0
  408. agno/tools/mcp/multi_mcp.py +347 -0
  409. agno/tools/mcp/params.py +24 -0
  410. agno/tools/mcp_toolbox.py +284 -0
  411. agno/tools/mem0.py +193 -0
  412. agno/tools/memory.py +419 -0
  413. agno/tools/mlx_transcribe.py +11 -9
  414. agno/tools/models/azure_openai.py +190 -0
  415. agno/tools/models/gemini.py +203 -0
  416. agno/tools/models/groq.py +158 -0
  417. agno/tools/models/morph.py +186 -0
  418. agno/tools/models/nebius.py +124 -0
  419. agno/tools/models_labs.py +163 -82
  420. agno/tools/moviepy_video.py +18 -13
  421. agno/tools/nano_banana.py +151 -0
  422. agno/tools/neo4j.py +134 -0
  423. agno/tools/newspaper.py +15 -4
  424. agno/tools/newspaper4k.py +19 -6
  425. agno/tools/notion.py +204 -0
  426. agno/tools/openai.py +181 -17
  427. agno/tools/openbb.py +27 -20
  428. agno/tools/opencv.py +321 -0
  429. agno/tools/openweather.py +233 -0
  430. agno/tools/oxylabs.py +385 -0
  431. agno/tools/pandas.py +25 -15
  432. agno/tools/parallel.py +314 -0
  433. agno/tools/postgres.py +238 -185
  434. agno/tools/pubmed.py +125 -13
  435. agno/tools/python.py +48 -35
  436. agno/tools/reasoning.py +283 -0
  437. agno/tools/reddit.py +207 -29
  438. agno/tools/redshift.py +406 -0
  439. agno/tools/replicate.py +69 -26
  440. agno/tools/resend.py +11 -6
  441. agno/tools/scrapegraph.py +179 -19
  442. agno/tools/searxng.py +23 -31
  443. agno/tools/serpapi.py +15 -10
  444. agno/tools/serper.py +255 -0
  445. agno/tools/shell.py +23 -12
  446. agno/tools/shopify.py +1519 -0
  447. agno/tools/slack.py +56 -14
  448. agno/tools/sleep.py +8 -6
  449. agno/tools/spider.py +35 -11
  450. agno/tools/spotify.py +919 -0
  451. agno/tools/sql.py +34 -19
  452. agno/tools/tavily.py +158 -8
  453. agno/tools/telegram.py +18 -8
  454. agno/tools/todoist.py +218 -0
  455. agno/tools/toolkit.py +134 -9
  456. agno/tools/trafilatura.py +388 -0
  457. agno/tools/trello.py +25 -28
  458. agno/tools/twilio.py +18 -9
  459. agno/tools/user_control_flow.py +78 -0
  460. agno/tools/valyu.py +228 -0
  461. agno/tools/visualization.py +467 -0
  462. agno/tools/webbrowser.py +28 -0
  463. agno/tools/webex.py +76 -0
  464. agno/tools/website.py +23 -19
  465. agno/tools/webtools.py +45 -0
  466. agno/tools/whatsapp.py +286 -0
  467. agno/tools/wikipedia.py +28 -19
  468. agno/tools/workflow.py +285 -0
  469. agno/tools/{twitter.py → x.py} +142 -46
  470. agno/tools/yfinance.py +41 -39
  471. agno/tools/youtube.py +34 -17
  472. agno/tools/zendesk.py +15 -5
  473. agno/tools/zep.py +454 -0
  474. agno/tools/zoom.py +86 -37
  475. agno/tracing/__init__.py +12 -0
  476. agno/tracing/exporter.py +157 -0
  477. agno/tracing/schemas.py +276 -0
  478. agno/tracing/setup.py +111 -0
  479. agno/utils/agent.py +938 -0
  480. agno/utils/audio.py +37 -1
  481. agno/utils/certs.py +27 -0
  482. agno/utils/code_execution.py +11 -0
  483. agno/utils/common.py +103 -20
  484. agno/utils/cryptography.py +22 -0
  485. agno/utils/dttm.py +33 -0
  486. agno/utils/events.py +700 -0
  487. agno/utils/functions.py +107 -37
  488. agno/utils/gemini.py +426 -0
  489. agno/utils/hooks.py +171 -0
  490. agno/utils/http.py +185 -0
  491. agno/utils/json_schema.py +159 -37
  492. agno/utils/knowledge.py +36 -0
  493. agno/utils/location.py +19 -0
  494. agno/utils/log.py +221 -8
  495. agno/utils/mcp.py +214 -0
  496. agno/utils/media.py +335 -14
  497. agno/utils/merge_dict.py +22 -1
  498. agno/utils/message.py +77 -2
  499. agno/utils/models/ai_foundry.py +50 -0
  500. agno/utils/models/claude.py +373 -0
  501. agno/utils/models/cohere.py +94 -0
  502. agno/utils/models/llama.py +85 -0
  503. agno/utils/models/mistral.py +100 -0
  504. agno/utils/models/openai_responses.py +140 -0
  505. agno/utils/models/schema_utils.py +153 -0
  506. agno/utils/models/watsonx.py +41 -0
  507. agno/utils/openai.py +257 -0
  508. agno/utils/pickle.py +1 -1
  509. agno/utils/pprint.py +124 -8
  510. agno/utils/print_response/agent.py +930 -0
  511. agno/utils/print_response/team.py +1914 -0
  512. agno/utils/print_response/workflow.py +1668 -0
  513. agno/utils/prompts.py +111 -0
  514. agno/utils/reasoning.py +108 -0
  515. agno/utils/response.py +163 -0
  516. agno/utils/serialize.py +32 -0
  517. agno/utils/shell.py +4 -4
  518. agno/utils/streamlit.py +487 -0
  519. agno/utils/string.py +204 -51
  520. agno/utils/team.py +139 -0
  521. agno/utils/timer.py +9 -2
  522. agno/utils/tokens.py +657 -0
  523. agno/utils/tools.py +19 -1
  524. agno/utils/whatsapp.py +305 -0
  525. agno/utils/yaml_io.py +3 -3
  526. agno/vectordb/__init__.py +2 -0
  527. agno/vectordb/base.py +87 -9
  528. agno/vectordb/cassandra/__init__.py +5 -1
  529. agno/vectordb/cassandra/cassandra.py +383 -27
  530. agno/vectordb/chroma/__init__.py +4 -0
  531. agno/vectordb/chroma/chromadb.py +748 -83
  532. agno/vectordb/clickhouse/__init__.py +7 -1
  533. agno/vectordb/clickhouse/clickhousedb.py +554 -53
  534. agno/vectordb/couchbase/__init__.py +3 -0
  535. agno/vectordb/couchbase/couchbase.py +1446 -0
  536. agno/vectordb/lancedb/__init__.py +5 -0
  537. agno/vectordb/lancedb/lance_db.py +730 -98
  538. agno/vectordb/langchaindb/__init__.py +5 -0
  539. agno/vectordb/langchaindb/langchaindb.py +163 -0
  540. agno/vectordb/lightrag/__init__.py +5 -0
  541. agno/vectordb/lightrag/lightrag.py +388 -0
  542. agno/vectordb/llamaindex/__init__.py +3 -0
  543. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  544. agno/vectordb/milvus/__init__.py +3 -0
  545. agno/vectordb/milvus/milvus.py +966 -78
  546. agno/vectordb/mongodb/__init__.py +9 -1
  547. agno/vectordb/mongodb/mongodb.py +1175 -172
  548. agno/vectordb/pgvector/__init__.py +8 -0
  549. agno/vectordb/pgvector/pgvector.py +599 -115
  550. agno/vectordb/pineconedb/__init__.py +5 -1
  551. agno/vectordb/pineconedb/pineconedb.py +406 -43
  552. agno/vectordb/qdrant/__init__.py +4 -0
  553. agno/vectordb/qdrant/qdrant.py +914 -61
  554. agno/vectordb/redis/__init__.py +9 -0
  555. agno/vectordb/redis/redisdb.py +682 -0
  556. agno/vectordb/singlestore/__init__.py +8 -1
  557. agno/vectordb/singlestore/singlestore.py +771 -0
  558. agno/vectordb/surrealdb/__init__.py +3 -0
  559. agno/vectordb/surrealdb/surrealdb.py +663 -0
  560. agno/vectordb/upstashdb/__init__.py +5 -0
  561. agno/vectordb/upstashdb/upstashdb.py +718 -0
  562. agno/vectordb/weaviate/__init__.py +8 -0
  563. agno/vectordb/weaviate/index.py +15 -0
  564. agno/vectordb/weaviate/weaviate.py +1009 -0
  565. agno/workflow/__init__.py +23 -1
  566. agno/workflow/agent.py +299 -0
  567. agno/workflow/condition.py +759 -0
  568. agno/workflow/loop.py +756 -0
  569. agno/workflow/parallel.py +853 -0
  570. agno/workflow/router.py +723 -0
  571. agno/workflow/step.py +1564 -0
  572. agno/workflow/steps.py +613 -0
  573. agno/workflow/types.py +556 -0
  574. agno/workflow/workflow.py +4327 -514
  575. agno-2.3.13.dist-info/METADATA +639 -0
  576. agno-2.3.13.dist-info/RECORD +613 -0
  577. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
  578. agno-2.3.13.dist-info/licenses/LICENSE +201 -0
  579. agno/api/playground.py +0 -91
  580. agno/api/schemas/playground.py +0 -22
  581. agno/api/schemas/user.py +0 -22
  582. agno/api/schemas/workspace.py +0 -46
  583. agno/api/user.py +0 -160
  584. agno/api/workspace.py +0 -151
  585. agno/cli/auth_server.py +0 -118
  586. agno/cli/config.py +0 -275
  587. agno/cli/console.py +0 -88
  588. agno/cli/credentials.py +0 -23
  589. agno/cli/entrypoint.py +0 -571
  590. agno/cli/operator.py +0 -355
  591. agno/cli/settings.py +0 -85
  592. agno/cli/ws/ws_cli.py +0 -817
  593. agno/constants.py +0 -13
  594. agno/document/__init__.py +0 -1
  595. agno/document/chunking/semantic.py +0 -47
  596. agno/document/chunking/strategy.py +0 -31
  597. agno/document/reader/__init__.py +0 -1
  598. agno/document/reader/arxiv_reader.py +0 -41
  599. agno/document/reader/base.py +0 -22
  600. agno/document/reader/csv_reader.py +0 -84
  601. agno/document/reader/docx_reader.py +0 -46
  602. agno/document/reader/firecrawl_reader.py +0 -99
  603. agno/document/reader/json_reader.py +0 -43
  604. agno/document/reader/pdf_reader.py +0 -219
  605. agno/document/reader/s3/pdf_reader.py +0 -46
  606. agno/document/reader/s3/text_reader.py +0 -51
  607. agno/document/reader/text_reader.py +0 -41
  608. agno/document/reader/website_reader.py +0 -175
  609. agno/document/reader/youtube_reader.py +0 -50
  610. agno/embedder/__init__.py +0 -1
  611. agno/embedder/azure_openai.py +0 -86
  612. agno/embedder/cohere.py +0 -72
  613. agno/embedder/fastembed.py +0 -37
  614. agno/embedder/google.py +0 -73
  615. agno/embedder/huggingface.py +0 -54
  616. agno/embedder/mistral.py +0 -80
  617. agno/embedder/ollama.py +0 -57
  618. agno/embedder/openai.py +0 -74
  619. agno/embedder/sentence_transformer.py +0 -38
  620. agno/embedder/voyageai.py +0 -64
  621. agno/eval/perf.py +0 -201
  622. agno/file/__init__.py +0 -1
  623. agno/file/file.py +0 -16
  624. agno/file/local/csv.py +0 -32
  625. agno/file/local/txt.py +0 -19
  626. agno/infra/app.py +0 -240
  627. agno/infra/base.py +0 -144
  628. agno/infra/context.py +0 -20
  629. agno/infra/db_app.py +0 -52
  630. agno/infra/resource.py +0 -205
  631. agno/infra/resources.py +0 -55
  632. agno/knowledge/agent.py +0 -230
  633. agno/knowledge/arxiv.py +0 -22
  634. agno/knowledge/combined.py +0 -22
  635. agno/knowledge/csv.py +0 -28
  636. agno/knowledge/csv_url.py +0 -19
  637. agno/knowledge/document.py +0 -20
  638. agno/knowledge/docx.py +0 -30
  639. agno/knowledge/json.py +0 -28
  640. agno/knowledge/langchain.py +0 -71
  641. agno/knowledge/llamaindex.py +0 -66
  642. agno/knowledge/pdf.py +0 -28
  643. agno/knowledge/pdf_url.py +0 -26
  644. agno/knowledge/s3/base.py +0 -60
  645. agno/knowledge/s3/pdf.py +0 -21
  646. agno/knowledge/s3/text.py +0 -23
  647. agno/knowledge/text.py +0 -30
  648. agno/knowledge/website.py +0 -88
  649. agno/knowledge/wikipedia.py +0 -31
  650. agno/knowledge/youtube.py +0 -22
  651. agno/memory/agent.py +0 -392
  652. agno/memory/classifier.py +0 -104
  653. agno/memory/db/__init__.py +0 -1
  654. agno/memory/db/base.py +0 -42
  655. agno/memory/db/mongodb.py +0 -189
  656. agno/memory/db/postgres.py +0 -203
  657. agno/memory/db/sqlite.py +0 -193
  658. agno/memory/memory.py +0 -15
  659. agno/memory/row.py +0 -36
  660. agno/memory/summarizer.py +0 -192
  661. agno/memory/summary.py +0 -19
  662. agno/memory/workflow.py +0 -38
  663. agno/models/google/gemini_openai.py +0 -26
  664. agno/models/ollama/hermes.py +0 -221
  665. agno/models/ollama/tools.py +0 -362
  666. agno/models/vertexai/gemini.py +0 -595
  667. agno/playground/__init__.py +0 -3
  668. agno/playground/async_router.py +0 -421
  669. agno/playground/deploy.py +0 -249
  670. agno/playground/operator.py +0 -92
  671. agno/playground/playground.py +0 -91
  672. agno/playground/schemas.py +0 -76
  673. agno/playground/serve.py +0 -55
  674. agno/playground/sync_router.py +0 -405
  675. agno/reasoning/agent.py +0 -68
  676. agno/run/response.py +0 -112
  677. agno/storage/agent/__init__.py +0 -0
  678. agno/storage/agent/base.py +0 -38
  679. agno/storage/agent/dynamodb.py +0 -350
  680. agno/storage/agent/json.py +0 -92
  681. agno/storage/agent/mongodb.py +0 -228
  682. agno/storage/agent/postgres.py +0 -367
  683. agno/storage/agent/session.py +0 -79
  684. agno/storage/agent/singlestore.py +0 -303
  685. agno/storage/agent/sqlite.py +0 -357
  686. agno/storage/agent/yaml.py +0 -93
  687. agno/storage/workflow/__init__.py +0 -0
  688. agno/storage/workflow/base.py +0 -40
  689. agno/storage/workflow/mongodb.py +0 -233
  690. agno/storage/workflow/postgres.py +0 -366
  691. agno/storage/workflow/session.py +0 -60
  692. agno/storage/workflow/sqlite.py +0 -359
  693. agno/tools/googlesearch.py +0 -88
  694. agno/utils/defaults.py +0 -57
  695. agno/utils/filesystem.py +0 -39
  696. agno/utils/git.py +0 -52
  697. agno/utils/json_io.py +0 -30
  698. agno/utils/load_env.py +0 -19
  699. agno/utils/py_io.py +0 -19
  700. agno/utils/pyproject.py +0 -18
  701. agno/utils/resource_filter.py +0 -31
  702. agno/vectordb/singlestore/s2vectordb.py +0 -390
  703. agno/vectordb/singlestore/s2vectordb2.py +0 -355
  704. agno/workspace/__init__.py +0 -0
  705. agno/workspace/config.py +0 -325
  706. agno/workspace/enums.py +0 -6
  707. agno/workspace/helpers.py +0 -48
  708. agno/workspace/operator.py +0 -758
  709. agno/workspace/settings.py +0 -63
  710. agno-0.1.2.dist-info/LICENSE +0 -375
  711. agno-0.1.2.dist-info/METADATA +0 -502
  712. agno-0.1.2.dist-info/RECORD +0 -352
  713. agno-0.1.2.dist-info/entry_points.txt +0 -3
  714. /agno/{cli → db/migrations}/__init__.py +0 -0
  715. /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
  716. /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
  717. /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
  718. /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
  719. /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
  720. /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
  721. /agno/{reranker → utils/models}/__init__.py +0 -0
  722. /agno/{storage → utils/print_response}/__init__.py +0 -0
  723. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
agno/media.py CHANGED
@@ -1,134 +1,478 @@
1
1
  from pathlib import Path
2
- from typing import Any, Optional, Union
2
+ from typing import Any, Dict, List, Optional, Tuple, Union
3
+ from uuid import uuid4
3
4
 
4
- from pydantic import BaseModel, model_validator
5
+ from pydantic import BaseModel, field_validator, model_validator
5
6
 
7
+ from agno.utils.log import log_error
6
8
 
7
- class Media(BaseModel):
8
- id: str
9
- original_prompt: Optional[str] = None
10
- revised_prompt: Optional[str] = None
11
9
 
10
+ class Image(BaseModel):
11
+ """Unified Image class for all use cases (input, output, artifacts)"""
12
12
 
13
- class VideoArtifact(Media):
14
- url: str # Remote location for file
15
- eta: Optional[str] = None
16
- length: Optional[str] = None
17
-
13
+ # Core content fields (exactly one required)
14
+ url: Optional[str] = None # Remote location
15
+ filepath: Optional[Union[Path, str]] = None # Local file path
16
+ content: Optional[bytes] = None # Raw image bytes (standardized to bytes)
18
17
 
19
- class ImageArtifact(Media):
20
- url: str # Remote location for file
21
- alt_text: Optional[str] = None
18
+ # Metadata fields
19
+ id: Optional[str] = None # For tracking/referencing
20
+ format: Optional[str] = None # E.g. 'png', 'jpeg', 'webp', 'gif'
21
+ mime_type: Optional[str] = None # E.g. 'image/png', 'image/jpeg'
22
22
 
23
+ # Input-specific fields
24
+ detail: Optional[str] = (
25
+ None # low, medium, high or auto (per OpenAI spec https://platform.openai.com/docs/guides/vision?lang=node#low-or-high-fidelity-image-understanding)
26
+ )
23
27
 
24
- class AudioArtifact(Media):
25
- url: Optional[str] = None # Remote location for file
26
- base64_audio: Optional[str] = None # Base64-encoded audio data
27
- length: Optional[str] = None
28
- mime_type: Optional[str] = None
28
+ # Output-specific fields (from tools/LLMs)
29
+ original_prompt: Optional[str] = None # Original generation prompt
30
+ revised_prompt: Optional[str] = None # Revised generation prompt
31
+ alt_text: Optional[str] = None # Alt text description
29
32
 
30
33
  @model_validator(mode="before")
31
- def validate_exclusive_audio(cls, data: Any):
32
- """
33
- Ensure that either `url` or `base64_audio` is provided, but not both.
34
- """
35
- if data.get("url") and data.get("base64_audio"):
36
- raise ValueError("Provide either `url` or `base64_audio`, not both.")
37
- if not data.get("url") and not data.get("base64_audio"):
38
- raise ValueError("Either `url` or `base64_audio` must be provided.")
34
+ def validate_and_normalize_content(cls, data: Any):
35
+ """Ensure exactly one content source and normalize to bytes"""
36
+ if isinstance(data, dict):
37
+ url = data.get("url")
38
+ filepath = data.get("filepath")
39
+ content = data.get("content")
40
+
41
+ # Count non-None sources
42
+ sources = [x for x in [url, filepath, content] if x is not None]
43
+ if len(sources) == 0:
44
+ raise ValueError("One of 'url', 'filepath', or 'content' must be provided")
45
+ elif len(sources) > 1:
46
+ raise ValueError("Only one of 'url', 'filepath', or 'content' should be provided")
47
+
48
+ # Auto-generate ID if not provided
49
+ if data.get("id") is None:
50
+ data["id"] = str(uuid4())
51
+
39
52
  return data
40
53
 
54
+ def get_content_bytes(self) -> Optional[bytes]:
55
+ """Get image content as raw bytes, loading from URL/file if needed"""
56
+ if self.content:
57
+ return self.content
58
+ elif self.url:
59
+ import httpx
41
60
 
42
- class Video(BaseModel):
43
- filepath: Optional[Union[Path, str]] = None # Absolute local location for video
44
- content: Optional[Any] = None # Actual video bytes content
61
+ return httpx.get(self.url).content
62
+ elif self.filepath:
63
+ with open(self.filepath, "rb") as f:
64
+ return f.read()
65
+ return None
66
+
67
+ def to_base64(self) -> Optional[str]:
68
+ """Convert content to base64 string for transmission/storage"""
69
+ content_bytes = self.get_content_bytes()
70
+ if content_bytes:
71
+ import base64
72
+
73
+ return base64.b64encode(content_bytes).decode("utf-8")
74
+ return None
75
+
76
+ @classmethod
77
+ def from_base64(
78
+ cls,
79
+ base64_content: str,
80
+ id: Optional[str] = None,
81
+ mime_type: Optional[str] = None,
82
+ format: Optional[str] = None,
83
+ **kwargs,
84
+ ) -> "Image":
85
+ """Create Image from base64 content"""
86
+ import base64
87
+
88
+ try:
89
+ content_bytes = base64.b64decode(base64_content)
90
+ except Exception:
91
+ content_bytes = base64_content.encode("utf-8")
92
+
93
+ return cls(content=content_bytes, id=id or str(uuid4()), mime_type=mime_type, format=format, **kwargs)
94
+
95
+ def to_dict(self, include_base64_content: bool = True) -> Dict[str, Any]:
96
+ """Convert to dict, optionally including base64-encoded content"""
97
+ result = {
98
+ "id": self.id,
99
+ "url": self.url,
100
+ "filepath": str(self.filepath) if self.filepath else None,
101
+ "format": self.format,
102
+ "mime_type": self.mime_type,
103
+ "detail": self.detail,
104
+ "original_prompt": self.original_prompt,
105
+ "revised_prompt": self.revised_prompt,
106
+ "alt_text": self.alt_text,
107
+ }
108
+
109
+ if include_base64_content and self.content:
110
+ result["content"] = self.to_base64()
111
+
112
+ return {k: v for k, v in result.items() if v is not None}
45
113
 
46
- @model_validator(mode="before")
47
- def validate_exclusive_video(cls, data: Any):
48
- """
49
- Ensure that exactly one of `filepath`, or `content` is provided.
50
- """
51
- # Extract the values from the input data
52
- filepath = data.get("filepath")
53
- content = data.get("content")
54
114
 
55
- # Count how many fields are set (not None)
56
- count = len([field for field in [filepath, content] if field is not None])
115
+ class Audio(BaseModel):
116
+ """Unified Audio class for all use cases (input, output, artifacts)"""
57
117
 
58
- if count == 0:
59
- raise ValueError("One of `filepath` or `content` must be provided.")
60
- elif count > 1:
61
- raise ValueError("Only one of `filepath` or `content` should be provided.")
118
+ # Core content fields (exactly one required)
119
+ url: Optional[str] = None
120
+ filepath: Optional[Union[Path, str]] = None
121
+ content: Optional[bytes] = None # Raw audio bytes (standardized to bytes)
62
122
 
63
- return data
123
+ # Metadata fields
124
+ id: Optional[str] = None
125
+ format: Optional[str] = None # E.g. 'mp3', 'wav', 'ogg'
126
+ mime_type: Optional[str] = None # E.g. 'audio/mpeg', 'audio/wav'
64
127
 
128
+ # Audio-specific metadata
129
+ duration: Optional[float] = None # Duration in seconds
130
+ sample_rate: Optional[int] = 24000 # Sample rate in Hz
131
+ channels: Optional[int] = 1 # Number of audio channels
65
132
 
66
- class Audio(BaseModel):
67
- content: Optional[Any] = None # Actual audio bytes content
68
- filepath: Optional[Union[Path, str]] = None # Absolute local location for audio
69
- format: Optional[str] = None
133
+ # Output-specific fields (from LLMs)
134
+ transcript: Optional[str] = None # Text transcript of audio
135
+ expires_at: Optional[int] = None # Expiration timestamp for temporary URLs
70
136
 
71
137
  @model_validator(mode="before")
72
- def validate_exclusive_audio(cls, data: Any):
73
- """
74
- Ensure that exactly one of `filepath`, or `content` is provided.
75
- """
76
- # Extract the values from the input data
77
- filepath = data.get("filepath")
78
- content = data.get("content")
138
+ def validate_and_normalize_content(cls, data: Any):
139
+ """Ensure exactly one content source and normalize to bytes"""
140
+ if isinstance(data, dict):
141
+ url = data.get("url")
142
+ filepath = data.get("filepath")
143
+ content = data.get("content")
144
+
145
+ sources = [x for x in [url, filepath, content] if x is not None]
146
+ if len(sources) == 0:
147
+ raise ValueError("One of 'url', 'filepath', or 'content' must be provided")
148
+ elif len(sources) > 1:
149
+ raise ValueError("Only one of 'url', 'filepath', or 'content' should be provided")
150
+
151
+ if data.get("id") is None:
152
+ data["id"] = str(uuid4())
79
153
 
80
- # Count how many fields are set (not None)
81
- count = len([field for field in [filepath, content] if field is not None])
154
+ return data
82
155
 
83
- if count == 0:
84
- raise ValueError("One of `filepath` or `content` must be provided.")
85
- elif count > 1:
86
- raise ValueError("Only one of `filepath` or `content` should be provided.")
156
+ def get_content_bytes(self) -> Optional[bytes]:
157
+ """Get audio content as raw bytes"""
158
+ if self.content:
159
+ return self.content
160
+ elif self.url:
161
+ import httpx
87
162
 
88
- return data
163
+ return httpx.get(self.url).content
164
+ elif self.filepath:
165
+ with open(self.filepath, "rb") as f:
166
+ return f.read()
167
+ return None
168
+
169
+ def to_base64(self) -> Optional[str]:
170
+ """Convert content to base64 string"""
171
+ content_bytes = self.get_content_bytes()
172
+ if content_bytes:
173
+ import base64
174
+
175
+ return base64.b64encode(content_bytes).decode("utf-8")
176
+ return None
177
+
178
+ @classmethod
179
+ def from_base64(
180
+ cls,
181
+ base64_content: str,
182
+ id: Optional[str] = None,
183
+ mime_type: Optional[str] = None,
184
+ transcript: Optional[str] = None,
185
+ expires_at: Optional[int] = None,
186
+ sample_rate: Optional[int] = 24000,
187
+ channels: Optional[int] = 1,
188
+ **kwargs,
189
+ ) -> "Audio":
190
+ """Create Audio from base64 content (useful for API responses)"""
191
+ import base64
192
+
193
+ try:
194
+ content_bytes = base64.b64decode(base64_content)
195
+ except Exception:
196
+ # If not valid base64, encode as UTF-8 bytes
197
+ content_bytes = base64_content.encode("utf-8")
198
+
199
+ return cls(
200
+ content=content_bytes,
201
+ id=id or str(uuid4()),
202
+ mime_type=mime_type,
203
+ transcript=transcript,
204
+ expires_at=expires_at,
205
+ sample_rate=sample_rate,
206
+ channels=channels,
207
+ **kwargs,
208
+ )
209
+
210
+ def to_dict(self, include_base64_content: bool = True) -> Dict[str, Any]:
211
+ """Convert to dict, optionally including base64-encoded content"""
212
+ result = {
213
+ "id": self.id,
214
+ "url": self.url,
215
+ "filepath": str(self.filepath) if self.filepath else None,
216
+ "format": self.format,
217
+ "mime_type": self.mime_type,
218
+ "duration": self.duration,
219
+ "sample_rate": self.sample_rate,
220
+ "channels": self.channels,
221
+ "transcript": self.transcript,
222
+ "expires_at": self.expires_at,
223
+ }
224
+
225
+ if include_base64_content and self.content:
226
+ result["content"] = self.to_base64()
227
+
228
+ return {k: v for k, v in result.items() if v is not None}
89
229
 
90
230
 
91
- class AudioOutput(BaseModel):
92
- id: str
93
- content: str # Base64 encoded
94
- expires_at: int
95
- transcript: str
231
+ class Video(BaseModel):
232
+ """Unified Video class for all use cases (input, output, artifacts)"""
96
233
 
234
+ # Core content fields (exactly one required)
235
+ url: Optional[str] = None
236
+ filepath: Optional[Union[Path, str]] = None
237
+ content: Optional[bytes] = None # Raw video bytes (standardized to bytes)
97
238
 
98
- class Image(BaseModel):
99
- url: Optional[str] = None # Remote location for image
100
- filepath: Optional[Union[Path, str]] = None # Absolute local location for image
101
- content: Optional[Any] = None # Actual image bytes content
102
- detail: Optional[str] = (
103
- None # low, medium, high or auto (per OpenAI spec https://platform.openai.com/docs/guides/vision?lang=node#low-or-high-fidelity-image-understanding)
104
- )
239
+ # Metadata fields
105
240
  id: Optional[str] = None
241
+ format: Optional[str] = None # E.g. 'mp4', 'mov', 'avi', 'webm'
242
+ mime_type: Optional[str] = None # E.g. 'video/mp4', 'video/quicktime'
106
243
 
107
- @property
108
- def image_url_content(self) -> Optional[bytes]:
109
- import httpx
244
+ # Video-specific metadata
245
+ duration: Optional[float] = None # Duration in seconds
246
+ width: Optional[int] = None # Video width in pixels
247
+ height: Optional[int] = None # Video height in pixels
248
+ fps: Optional[float] = None # Frames per second
249
+
250
+ # Output-specific fields (from tools)
251
+ eta: Optional[str] = None # Estimated time for generation
252
+ original_prompt: Optional[str] = None
253
+ revised_prompt: Optional[str] = None
254
+
255
+ @model_validator(mode="before")
256
+ def validate_and_normalize_content(cls, data: Any):
257
+ """Ensure exactly one content source and normalize to bytes"""
258
+ if isinstance(data, dict):
259
+ url = data.get("url")
260
+ filepath = data.get("filepath")
261
+ content = data.get("content")
262
+
263
+ sources = [x for x in [url, filepath, content] if x is not None]
264
+ if len(sources) == 0:
265
+ raise ValueError("One of 'url', 'filepath', or 'content' must be provided")
266
+ elif len(sources) > 1:
267
+ raise ValueError("Only one of 'url', 'filepath', or 'content' should be provided")
268
+
269
+ if data.get("id") is None:
270
+ data["id"] = str(uuid4())
271
+
272
+ return data
273
+
274
+ def get_content_bytes(self) -> Optional[bytes]:
275
+ """Get video content as raw bytes"""
276
+ if self.content:
277
+ return self.content
278
+ elif self.url:
279
+ import httpx
110
280
 
111
- if self.url:
112
281
  return httpx.get(self.url).content
113
- else:
114
- return None
282
+ elif self.filepath:
283
+ with open(self.filepath, "rb") as f:
284
+ return f.read()
285
+ return None
286
+
287
+ def to_base64(self) -> Optional[str]:
288
+ """Convert content to base64 string"""
289
+ content_bytes = self.get_content_bytes()
290
+ if content_bytes:
291
+ import base64
292
+
293
+ return base64.b64encode(content_bytes).decode("utf-8")
294
+ return None
295
+
296
+ @classmethod
297
+ def from_base64(
298
+ cls,
299
+ base64_content: str,
300
+ id: Optional[str] = None,
301
+ mime_type: Optional[str] = None,
302
+ format: Optional[str] = None,
303
+ **kwargs,
304
+ ) -> "Video":
305
+ """Create Image from base64 content"""
306
+ import base64
307
+
308
+ try:
309
+ content_bytes = base64.b64decode(base64_content)
310
+ except Exception:
311
+ content_bytes = base64_content.encode("utf-8")
312
+
313
+ return cls(content=content_bytes, id=id or str(uuid4()), mime_type=mime_type, format=format, **kwargs)
314
+
315
+ def to_dict(self, include_base64_content: bool = True) -> Dict[str, Any]:
316
+ """Convert to dict, optionally including base64-encoded content"""
317
+ result = {
318
+ "id": self.id,
319
+ "url": self.url,
320
+ "filepath": str(self.filepath) if self.filepath else None,
321
+ "format": self.format,
322
+ "mime_type": self.mime_type,
323
+ "duration": self.duration,
324
+ "width": self.width,
325
+ "height": self.height,
326
+ "fps": self.fps,
327
+ "eta": self.eta,
328
+ "original_prompt": self.original_prompt,
329
+ "revised_prompt": self.revised_prompt,
330
+ }
331
+
332
+ if include_base64_content and self.content:
333
+ result["content"] = self.to_base64()
334
+
335
+ return {k: v for k, v in result.items() if v is not None}
336
+
337
+
338
+ class File(BaseModel):
339
+ id: Optional[str] = None
340
+ url: Optional[str] = None
341
+ filepath: Optional[Union[Path, str]] = None
342
+ # Raw bytes content of a file
343
+ content: Optional[Any] = None
344
+ mime_type: Optional[str] = None
345
+
346
+ file_type: Optional[str] = None
347
+ filename: Optional[str] = None
348
+ size: Optional[int] = None
349
+ # External file object (e.g. GeminiFile, must be a valid object as expected by the model you are using)
350
+ external: Optional[Any] = None
351
+ format: Optional[str] = None # E.g. `pdf`, `txt`, `csv`, `xml`, etc.
352
+ name: Optional[str] = None # Name of the file, mandatory for AWS Bedrock document input
115
353
 
116
354
  @model_validator(mode="before")
117
- def validate_exclusive_image(cls, data: Any):
118
- """
119
- Ensure that exactly one of `url`, `filepath`, or `content` is provided.
355
+ @classmethod
356
+ def check_at_least_one_source(cls, data):
357
+ """Ensure at least one of url, filepath, or content is provided."""
358
+ if isinstance(data, dict) and not any(data.get(field) for field in ["url", "filepath", "content", "external"]):
359
+ raise ValueError("At least one of url, filepath, content or external must be provided")
360
+ return data
361
+
362
+ @field_validator("mime_type")
363
+ @classmethod
364
+ def validate_mime_type(cls, v):
365
+ """Validate that the mime_type is one of the allowed types."""
366
+ if v is not None and v not in cls.valid_mime_types():
367
+ raise ValueError(f"Invalid MIME type: {v}. Must be one of: {cls.valid_mime_types()}")
368
+ return v
369
+
370
+ @classmethod
371
+ def valid_mime_types(cls) -> List[str]:
372
+ return [
373
+ "application/pdf",
374
+ "application/json",
375
+ "application/x-javascript",
376
+ "application/json",
377
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
378
+ "text/javascript",
379
+ "application/x-python",
380
+ "text/x-python",
381
+ "text/plain",
382
+ "text/html",
383
+ "text/css",
384
+ "text/md",
385
+ "text/csv",
386
+ "text/xml",
387
+ "text/rtf",
388
+ ]
389
+
390
+ @classmethod
391
+ def from_base64(
392
+ cls,
393
+ base64_content: str,
394
+ id: Optional[str] = None,
395
+ mime_type: Optional[str] = None,
396
+ filename: Optional[str] = None,
397
+ name: Optional[str] = None,
398
+ format: Optional[str] = None,
399
+ ) -> "File":
400
+ """Create File from base64 encoded content or plain text.
401
+
402
+ Handles both base64-encoded binary content and plain text content
403
+ (which is stored as UTF-8 strings for text/* MIME types).
120
404
  """
121
- # Extract the values from the input data
122
- url = data.get("url")
123
- filepath = data.get("filepath")
124
- content = data.get("content")
405
+ import base64
406
+
407
+ try:
408
+ content_bytes = base64.b64decode(base64_content)
409
+ except Exception:
410
+ # If not valid base64, it might be plain text content (text/csv, text/plain, etc.)
411
+ # which is stored as UTF-8 strings, not base64
412
+ content_bytes = base64_content.encode("utf-8")
413
+
414
+ return cls(
415
+ content=content_bytes,
416
+ id=id,
417
+ mime_type=mime_type,
418
+ filename=filename,
419
+ name=name,
420
+ format=format,
421
+ )
125
422
 
126
- # Count how many fields are set (not None)
127
- count = len([field for field in [url, filepath, content] if field is not None])
423
+ @property
424
+ def file_url_content(self) -> Optional[Tuple[bytes, str]]:
425
+ import httpx
128
426
 
129
- if count == 0:
130
- raise ValueError("One of `url`, `filepath`, or `content` must be provided.")
131
- elif count > 1:
132
- raise ValueError("Only one of `url`, `filepath`, or `content` should be provided.")
427
+ if self.url:
428
+ try:
429
+ response = httpx.get(self.url)
430
+ content = response.content
431
+ mime_type = response.headers.get("Content-Type", "").split(";")[0]
432
+ return content, mime_type
433
+ except Exception:
434
+ log_error(f"Failed to download file from {self.url}")
435
+ return None
436
+ else:
437
+ return None
133
438
 
134
- return data
439
+ def _normalise_content(self) -> Optional[Union[str, bytes]]:
440
+ if self.content is None:
441
+ return None
442
+ content_normalised: Union[str, bytes] = self.content
443
+ if content_normalised and isinstance(content_normalised, bytes):
444
+ from base64 import b64encode
445
+
446
+ try:
447
+ if self.mime_type and self.mime_type.startswith("text/"):
448
+ content_normalised = content_normalised.decode("utf-8")
449
+ else:
450
+ content_normalised = b64encode(content_normalised).decode("utf-8")
451
+ except UnicodeDecodeError:
452
+ if isinstance(self.content, bytes):
453
+ content_normalised = b64encode(self.content).decode("utf-8")
454
+ except Exception:
455
+ try:
456
+ if isinstance(self.content, bytes):
457
+ content_normalised = b64encode(self.content).decode("utf-8")
458
+ except Exception:
459
+ pass
460
+ return content_normalised
461
+
462
+ def to_dict(self) -> Dict[str, Any]:
463
+ content_normalised = self._normalise_content()
464
+
465
+ response_dict = {
466
+ "id": self.id,
467
+ "url": self.url,
468
+ "filepath": str(self.filepath) if self.filepath else None,
469
+ "content": content_normalised,
470
+ "mime_type": self.mime_type,
471
+ "file_type": self.file_type,
472
+ "filename": self.filename,
473
+ "size": self.size,
474
+ "external": self.external,
475
+ "format": self.format,
476
+ "name": self.name,
477
+ }
478
+ return {k: v for k, v in response_dict.items() if v is not None}
agno/memory/__init__.py CHANGED
@@ -1,3 +1,16 @@
1
- from agno.memory.agent import AgentMemory
2
- from agno.memory.memory import Memory
3
- from agno.memory.row import MemoryRow
1
+ from agno.memory.manager import MemoryManager, UserMemory
2
+ from agno.memory.strategies import (
3
+ MemoryOptimizationStrategy,
4
+ MemoryOptimizationStrategyFactory,
5
+ MemoryOptimizationStrategyType,
6
+ SummarizeStrategy,
7
+ )
8
+
9
+ __all__ = [
10
+ "MemoryManager",
11
+ "UserMemory",
12
+ "MemoryOptimizationStrategy",
13
+ "MemoryOptimizationStrategyType",
14
+ "MemoryOptimizationStrategyFactory",
15
+ "SummarizeStrategy",
16
+ ]