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/os/auth.py ADDED
@@ -0,0 +1,244 @@
1
+ from typing import List, Set
2
+
3
+ from fastapi import Depends, HTTPException, Request
4
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
5
+
6
+ from agno.os.scopes import get_accessible_resource_ids
7
+ from agno.os.settings import AgnoAPISettings
8
+
9
+ # Create a global HTTPBearer instance
10
+ security = HTTPBearer(auto_error=False)
11
+
12
+
13
+ def get_authentication_dependency(settings: AgnoAPISettings):
14
+ """
15
+ Create an authentication dependency function for FastAPI routes.
16
+
17
+ Args:
18
+ settings: The API settings containing the security key
19
+
20
+ Returns:
21
+ A dependency function that can be used with FastAPI's Depends()
22
+ """
23
+
24
+ async def auth_dependency(credentials: HTTPAuthorizationCredentials = Depends(security)) -> bool:
25
+ # If no security key is set, skip authentication entirely
26
+ if not settings or not settings.os_security_key:
27
+ return True
28
+
29
+ # If security is enabled but no authorization header provided, fail
30
+ if not credentials:
31
+ raise HTTPException(status_code=401, detail="Authorization header required")
32
+
33
+ token = credentials.credentials
34
+
35
+ # Verify the token
36
+ if token != settings.os_security_key:
37
+ raise HTTPException(status_code=401, detail="Invalid authentication token")
38
+
39
+ return True
40
+
41
+ return auth_dependency
42
+
43
+
44
+ def validate_websocket_token(token: str, settings: AgnoAPISettings) -> bool:
45
+ """
46
+ Validate a bearer token for WebSocket authentication (legacy os_security_key method).
47
+
48
+ Args:
49
+ token: The bearer token to validate
50
+ settings: The API settings containing the security key
51
+
52
+ Returns:
53
+ True if the token is valid or authentication is disabled, False otherwise
54
+ """
55
+ # If no security key is set, skip authentication entirely
56
+ if not settings or not settings.os_security_key:
57
+ return True
58
+
59
+ # Verify the token matches the configured security key
60
+ return token == settings.os_security_key
61
+
62
+
63
+ def get_accessible_resources(request: Request, resource_type: str) -> Set[str]:
64
+ """
65
+ Get the set of resource IDs the user has access to based on their scopes.
66
+
67
+ This function is used to filter lists of resources (agents, teams, workflows)
68
+ based on the user's scopes from their JWT token.
69
+
70
+ Args:
71
+ request: The FastAPI request object (contains request.state.scopes)
72
+ resource_type: Type of resource ("agents", "teams", "workflows")
73
+
74
+ Returns:
75
+ Set of resource IDs the user can access. Returns {"*"} for wildcard access.
76
+
77
+ Usage:
78
+ accessible_ids = get_accessible_resources(request, "agents")
79
+ if "*" not in accessible_ids:
80
+ agents = [a for a in agents if a.id in accessible_ids]
81
+
82
+ Examples:
83
+ >>> # User with specific agent access
84
+ >>> # Token scopes: ["agent-os:my-os:agents:my-agent:read"]
85
+ >>> get_accessible_resources(request, "agents")
86
+ {'my-agent'}
87
+
88
+ >>> # User with wildcard access
89
+ >>> # Token scopes: ["agent-os:my-os:agents:*:read"] or ["admin"]
90
+ >>> get_accessible_resources(request, "agents")
91
+ {'*'}
92
+
93
+ >>> # User with agent-os level access (global resource scope)
94
+ >>> # Token scopes: ["agent-os:my-os:agents:read"]
95
+ >>> get_accessible_resources(request, "agents")
96
+ {'*'}
97
+ """
98
+ # Check if accessible_resource_ids is already cached in request state (set by JWT middleware)
99
+ # This happens when user doesn't have global scope but has specific resource scopes
100
+ cached_ids = getattr(request.state, "accessible_resource_ids", None)
101
+ if cached_ids is not None:
102
+ return cached_ids
103
+
104
+ # Get user's scopes from request state (set by JWT middleware)
105
+ user_scopes = getattr(request.state, "scopes", [])
106
+
107
+ # Get accessible resource IDs
108
+ accessible_ids = get_accessible_resource_ids(user_scopes=user_scopes, resource_type=resource_type)
109
+
110
+ return accessible_ids
111
+
112
+
113
+ def filter_resources_by_access(request: Request, resources: List, resource_type: str) -> List:
114
+ """
115
+ Filter a list of resources based on user's access permissions.
116
+
117
+ Args:
118
+ request: The FastAPI request object
119
+ resources: List of resource objects (agents, teams, or workflows) with 'id' attribute
120
+ resource_type: Type of resource ("agents", "teams", "workflows")
121
+
122
+ Returns:
123
+ Filtered list of resources the user has access to
124
+
125
+ Usage:
126
+ agents = filter_resources_by_access(request, all_agents, "agents")
127
+ teams = filter_resources_by_access(request, all_teams, "teams")
128
+ workflows = filter_resources_by_access(request, all_workflows, "workflows")
129
+
130
+ Examples:
131
+ >>> # User with specific access
132
+ >>> agents = [Agent(id="agent-1"), Agent(id="agent-2"), Agent(id="agent-3")]
133
+ >>> # Token scopes: ["agent-os:my-os:agents:agent-1:read", "agent-os:my-os:agents:agent-2:read"]
134
+ >>> filter_resources_by_access(request, agents, "agents")
135
+ [Agent(id="agent-1"), Agent(id="agent-2")]
136
+
137
+ >>> # User with wildcard access
138
+ >>> # Token scopes: ["admin"]
139
+ >>> filter_resources_by_access(request, agents, "agents")
140
+ [Agent(id="agent-1"), Agent(id="agent-2"), Agent(id="agent-3")]
141
+ """
142
+ accessible_ids = get_accessible_resources(request, resource_type)
143
+
144
+ # Wildcard access - return all resources
145
+ if "*" in accessible_ids:
146
+ return resources
147
+
148
+ # Filter to only accessible resources
149
+ return [r for r in resources if r.id in accessible_ids]
150
+
151
+
152
+ def check_resource_access(request: Request, resource_id: str, resource_type: str, action: str = "read") -> bool:
153
+ """
154
+ Check if user has access to a specific resource.
155
+
156
+ Args:
157
+ request: The FastAPI request object
158
+ resource_id: ID of the resource to check
159
+ resource_type: Type of resource ("agents", "teams", "workflows")
160
+ action: Action to check ("read", "run", etc.)
161
+
162
+ Returns:
163
+ True if user has access, False otherwise
164
+
165
+ Usage:
166
+ if not check_resource_access(request, agent_id, "agents", "run"):
167
+ raise HTTPException(status_code=403, detail="Access denied")
168
+
169
+ Examples:
170
+ >>> # Token scopes: ["agent-os:my-os:agents:my-agent:read", "agent-os:my-os:agents:my-agent:run"]
171
+ >>> check_resource_access(request, "my-agent", "agents", "run")
172
+ True
173
+
174
+ >>> check_resource_access(request, "other-agent", "agents", "run")
175
+ False
176
+ """
177
+ accessible_ids = get_accessible_resources(request, resource_type)
178
+
179
+ # Wildcard access grants all permissions
180
+ if "*" in accessible_ids:
181
+ return True
182
+
183
+ # Check if user has access to this specific resource
184
+ return resource_id in accessible_ids
185
+
186
+
187
+ def require_resource_access(resource_type: str, action: str, resource_id_param: str):
188
+ """
189
+ Create a dependency that checks if the user has access to a specific resource.
190
+
191
+ This dependency factory creates a FastAPI dependency that automatically checks
192
+ authorization when authorization is enabled. It extracts the resource ID from
193
+ the path parameters and verifies the user has the required access.
194
+
195
+ Args:
196
+ resource_type: Type of resource ("agents", "teams", "workflows")
197
+ action: Action to check ("read", "run")
198
+ resource_id_param: Name of the path parameter containing the resource ID
199
+
200
+ Returns:
201
+ A dependency function for use with FastAPI's Depends()
202
+
203
+ Usage:
204
+ @router.post("/agents/{agent_id}/runs")
205
+ async def create_agent_run(
206
+ agent_id: str,
207
+ request: Request,
208
+ _: None = Depends(require_resource_access("agents", "run", "agent_id")),
209
+ ):
210
+ ...
211
+
212
+ @router.get("/agents/{agent_id}")
213
+ async def get_agent(
214
+ agent_id: str,
215
+ request: Request,
216
+ _: None = Depends(require_resource_access("agents", "read", "agent_id")),
217
+ ):
218
+ ...
219
+
220
+ Examples:
221
+ >>> # Creates dependency for checking agent run access
222
+ >>> dep = require_resource_access("agents", "run", "agent_id")
223
+
224
+ >>> # Creates dependency for checking team read access
225
+ >>> dep = require_resource_access("teams", "read", "team_id")
226
+ """
227
+ # Map resource_type to singular form for error messages
228
+ resource_singular = {
229
+ "agents": "agent",
230
+ "teams": "team",
231
+ "workflows": "workflow",
232
+ }.get(resource_type, resource_type.rstrip("s"))
233
+
234
+ async def dependency(request: Request):
235
+ # Only check authorization if it's enabled
236
+ if not getattr(request.state, "authorization_enabled", False):
237
+ return
238
+
239
+ # Get the resource_id from path parameters
240
+ resource_id = request.path_params.get(resource_id_param)
241
+ if resource_id and not check_resource_access(request, resource_id, resource_type, action):
242
+ raise HTTPException(status_code=403, detail=f"Access denied to {action} this {resource_singular}")
243
+
244
+ return dependency
agno/os/config.py ADDED
@@ -0,0 +1,126 @@
1
+ """Schemas related to the AgentOS configuration"""
2
+
3
+ from typing import Generic, List, Optional, TypeVar
4
+
5
+ from pydantic import BaseModel, field_validator
6
+
7
+
8
+ class AuthorizationConfig(BaseModel):
9
+ """Configuration for the JWT middleware"""
10
+
11
+ verification_keys: Optional[List[str]] = None
12
+ jwks_file: Optional[str] = None
13
+ algorithm: Optional[str] = None
14
+ verify_audience: Optional[bool] = None
15
+
16
+
17
+ class EvalsDomainConfig(BaseModel):
18
+ """Configuration for the Evals domain of the AgentOS"""
19
+
20
+ display_name: Optional[str] = None
21
+ available_models: Optional[List[str]] = None
22
+
23
+
24
+ class SessionDomainConfig(BaseModel):
25
+ """Configuration for the Session domain of the AgentOS"""
26
+
27
+ display_name: Optional[str] = None
28
+
29
+
30
+ class KnowledgeDomainConfig(BaseModel):
31
+ """Configuration for the Knowledge domain of the AgentOS"""
32
+
33
+ display_name: Optional[str] = None
34
+
35
+
36
+ class MetricsDomainConfig(BaseModel):
37
+ """Configuration for the Metrics domain of the AgentOS"""
38
+
39
+ display_name: Optional[str] = None
40
+
41
+
42
+ class MemoryDomainConfig(BaseModel):
43
+ """Configuration for the Memory domain of the AgentOS"""
44
+
45
+ display_name: Optional[str] = None
46
+
47
+
48
+ class TracesDomainConfig(BaseModel):
49
+ """Configuration for the Traces domain of the AgentOS"""
50
+
51
+ display_name: Optional[str] = None
52
+
53
+
54
+ DomainConfigType = TypeVar("DomainConfigType")
55
+
56
+
57
+ class DatabaseConfig(BaseModel, Generic[DomainConfigType]):
58
+ """Configuration for a domain when used with the contextual database"""
59
+
60
+ db_id: str
61
+ domain_config: Optional[DomainConfigType] = None
62
+ tables: Optional[List[str]] = None
63
+
64
+
65
+ class EvalsConfig(EvalsDomainConfig):
66
+ """Configuration for the Evals domain of the AgentOS"""
67
+
68
+ dbs: Optional[List[DatabaseConfig[EvalsDomainConfig]]] = None
69
+
70
+
71
+ class SessionConfig(SessionDomainConfig):
72
+ """Configuration for the Session domain of the AgentOS"""
73
+
74
+ dbs: Optional[List[DatabaseConfig[SessionDomainConfig]]] = None
75
+
76
+
77
+ class MemoryConfig(MemoryDomainConfig):
78
+ """Configuration for the Memory domain of the AgentOS"""
79
+
80
+ dbs: Optional[List[DatabaseConfig[MemoryDomainConfig]]] = None
81
+
82
+
83
+ class KnowledgeConfig(KnowledgeDomainConfig):
84
+ """Configuration for the Knowledge domain of the AgentOS"""
85
+
86
+ dbs: Optional[List[DatabaseConfig[KnowledgeDomainConfig]]] = None
87
+
88
+
89
+ class MetricsConfig(MetricsDomainConfig):
90
+ """Configuration for the Metrics domain of the AgentOS"""
91
+
92
+ dbs: Optional[List[DatabaseConfig[MetricsDomainConfig]]] = None
93
+
94
+
95
+ class TracesConfig(TracesDomainConfig):
96
+ """Configuration for the Traces domain of the AgentOS"""
97
+
98
+ dbs: Optional[List[DatabaseConfig[TracesDomainConfig]]] = None
99
+
100
+
101
+ class ChatConfig(BaseModel):
102
+ """Configuration for the Chat page of the AgentOS"""
103
+
104
+ quick_prompts: dict[str, list[str]]
105
+
106
+ # Limit the number of quick prompts to 3 (per agent/team/workflow)
107
+ @field_validator("quick_prompts")
108
+ @classmethod
109
+ def limit_lists(cls, v):
110
+ for key, lst in v.items():
111
+ if len(lst) > 3:
112
+ raise ValueError(f"Too many quick prompts for '{key}', maximum allowed is 3")
113
+ return v
114
+
115
+
116
+ class AgentOSConfig(BaseModel):
117
+ """General configuration for an AgentOS instance"""
118
+
119
+ available_models: Optional[List[str]] = None
120
+ chat: Optional[ChatConfig] = None
121
+ evals: Optional[EvalsConfig] = None
122
+ knowledge: Optional[KnowledgeConfig] = None
123
+ memory: Optional[MemoryConfig] = None
124
+ session: Optional[SessionConfig] = None
125
+ metrics: Optional[MetricsConfig] = None
126
+ traces: Optional[TracesConfig] = None
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,3 @@
1
+ from agno.os.interfaces.a2a.a2a import A2A
2
+
3
+ __all__ = ["A2A"]
@@ -0,0 +1,42 @@
1
+ """Main class for the A2A app, used to expose an Agno Agent, Team, or Workflow in an A2A compatible format."""
2
+
3
+ from typing import Optional
4
+
5
+ from fastapi.routing import APIRouter
6
+ from typing_extensions import List
7
+
8
+ from agno.agent import Agent
9
+ from agno.os.interfaces.a2a.router import attach_routes
10
+ from agno.os.interfaces.base import BaseInterface
11
+ from agno.team import Team
12
+ from agno.workflow import Workflow
13
+
14
+
15
+ class A2A(BaseInterface):
16
+ type = "a2a"
17
+
18
+ router: APIRouter
19
+
20
+ def __init__(
21
+ self,
22
+ agents: Optional[List[Agent]] = None,
23
+ teams: Optional[List[Team]] = None,
24
+ workflows: Optional[List[Workflow]] = None,
25
+ prefix: str = "/a2a",
26
+ tags: Optional[List[str]] = None,
27
+ ):
28
+ self.agents = agents
29
+ self.teams = teams
30
+ self.workflows = workflows
31
+ self.prefix = prefix
32
+ self.tags = tags or ["A2A"]
33
+
34
+ if not (self.agents or self.teams or self.workflows):
35
+ raise ValueError("Agents, Teams, or Workflows are required to setup the A2A interface.")
36
+
37
+ def get_router(self, **kwargs) -> APIRouter:
38
+ self.router = APIRouter(prefix=self.prefix, tags=self.tags) # type: ignore
39
+
40
+ self.router = attach_routes(router=self.router, agents=self.agents, teams=self.teams, workflows=self.workflows)
41
+
42
+ return self.router
@@ -0,0 +1,249 @@
1
+ """Async router handling exposing an Agno Agent or Team in an A2A compatible format."""
2
+
3
+ from typing import Optional, Union
4
+ from uuid import uuid4
5
+
6
+ from fastapi import HTTPException, Request
7
+ from fastapi.responses import StreamingResponse
8
+ from fastapi.routing import APIRouter
9
+ from typing_extensions import List
10
+
11
+ try:
12
+ from a2a.types import SendMessageSuccessResponse, Task, TaskState, TaskStatus
13
+ except ImportError as e:
14
+ raise ImportError("`a2a` not installed. Please install it with `pip install -U a2a-sdk`") from e
15
+
16
+ from agno.agent import Agent
17
+ from agno.os.interfaces.a2a.utils import (
18
+ map_a2a_request_to_run_input,
19
+ map_run_output_to_a2a_task,
20
+ stream_a2a_response_with_error_handling,
21
+ )
22
+ from agno.os.utils import get_agent_by_id, get_request_kwargs, get_team_by_id, get_workflow_by_id
23
+ from agno.team import Team
24
+ from agno.workflow import Workflow
25
+
26
+
27
+ def attach_routes(
28
+ router: APIRouter,
29
+ agents: Optional[List[Agent]] = None,
30
+ teams: Optional[List[Team]] = None,
31
+ workflows: Optional[List[Workflow]] = None,
32
+ ) -> APIRouter:
33
+ if agents is None and teams is None and workflows is None:
34
+ raise ValueError("Agents, Teams, or Workflows are required to setup the A2A interface.")
35
+
36
+ @router.post(
37
+ "/message/send",
38
+ operation_id="send_message",
39
+ name="send_message",
40
+ description="Send a message to an Agno Agent, Team, or Workflow. "
41
+ "The Agent, Team or Workflow is identified via the 'agentId' field in params.message or X-Agent-ID header. "
42
+ "Optional: Pass user ID via X-User-ID header (recommended) or 'userId' in params.message.metadata.",
43
+ response_model_exclude_none=True,
44
+ responses={
45
+ 200: {
46
+ "description": "Message sent successfully",
47
+ "content": {
48
+ "application/json": {
49
+ "example": {
50
+ "jsonrpc": "2.0",
51
+ "id": "request-123",
52
+ "result": {
53
+ "task": {
54
+ "id": "task-456",
55
+ "context_id": "context-789",
56
+ "status": "completed",
57
+ "history": [
58
+ {
59
+ "message_id": "msg-1",
60
+ "role": "agent",
61
+ "parts": [{"kind": "text", "text": "Response from agent"}],
62
+ }
63
+ ],
64
+ }
65
+ },
66
+ }
67
+ }
68
+ },
69
+ },
70
+ 400: {"description": "Invalid request or unsupported method"},
71
+ 404: {"description": "Agent, Team, or Workflow not found"},
72
+ },
73
+ response_model=SendMessageSuccessResponse,
74
+ )
75
+ async def a2a_send_message(request: Request):
76
+ request_body = await request.json()
77
+ kwargs = await get_request_kwargs(request, a2a_send_message)
78
+
79
+ # 1. Get the Agent, Team, or Workflow to run
80
+ agent_id = request_body.get("params", {}).get("message", {}).get("agentId") or request.headers.get("X-Agent-ID")
81
+ if not agent_id:
82
+ raise HTTPException(
83
+ status_code=400,
84
+ detail="Entity ID required. Provide it via 'agentId' in params.message or 'X-Agent-ID' header.",
85
+ )
86
+ entity: Optional[Union[Agent, Team, Workflow]] = None
87
+ if agents:
88
+ entity = get_agent_by_id(agent_id, agents)
89
+ if not entity and teams:
90
+ entity = get_team_by_id(agent_id, teams)
91
+ if not entity and workflows:
92
+ entity = get_workflow_by_id(agent_id, workflows)
93
+ if entity is None:
94
+ raise HTTPException(status_code=404, detail=f"Agent, Team, or Workflow with ID '{agent_id}' not found")
95
+
96
+ # 2. Map the request to our run_input and run variables
97
+ run_input = await map_a2a_request_to_run_input(request_body, stream=False)
98
+ context_id = request_body.get("params", {}).get("message", {}).get("contextId")
99
+ user_id = request.headers.get("X-User-ID")
100
+ if not user_id:
101
+ user_id = request_body.get("params", {}).get("message", {}).get("metadata", {}).get("userId")
102
+
103
+ # 3. Run the agent, team, or workflow
104
+ try:
105
+ if isinstance(entity, Workflow):
106
+ response = await entity.arun(
107
+ input=run_input.input_content,
108
+ images=list(run_input.images) if run_input.images else None,
109
+ videos=list(run_input.videos) if run_input.videos else None,
110
+ audio=list(run_input.audios) if run_input.audios else None,
111
+ files=list(run_input.files) if run_input.files else None,
112
+ session_id=context_id,
113
+ user_id=user_id,
114
+ **kwargs,
115
+ )
116
+ else:
117
+ response = await entity.arun(
118
+ input=run_input.input_content,
119
+ images=run_input.images,
120
+ videos=run_input.videos,
121
+ audio=run_input.audios,
122
+ files=run_input.files,
123
+ session_id=context_id,
124
+ user_id=user_id,
125
+ **kwargs,
126
+ )
127
+
128
+ # 4. Send the response
129
+ a2a_task = map_run_output_to_a2a_task(response)
130
+ return SendMessageSuccessResponse(
131
+ id=request_body.get("id", "unknown"),
132
+ result=a2a_task,
133
+ )
134
+
135
+ # Handle all critical errors
136
+ except Exception as e:
137
+ from a2a.types import Message as A2AMessage
138
+ from a2a.types import Part, Role, TextPart
139
+
140
+ error_message = A2AMessage(
141
+ message_id=str(uuid4()),
142
+ role=Role.agent,
143
+ parts=[Part(root=TextPart(text=f"Error: {str(e)}"))],
144
+ context_id=context_id or str(uuid4()),
145
+ )
146
+ failed_task = Task(
147
+ id=str(uuid4()),
148
+ context_id=context_id or str(uuid4()),
149
+ status=TaskStatus(state=TaskState.failed),
150
+ history=[error_message],
151
+ )
152
+
153
+ return SendMessageSuccessResponse(
154
+ id=request_body.get("id", "unknown"),
155
+ result=failed_task,
156
+ )
157
+
158
+ @router.post(
159
+ "/message/stream",
160
+ operation_id="stream_message",
161
+ name="stream_message",
162
+ description="Stream a message to an Agno Agent, Team, or Workflow."
163
+ "The Agent, Team or Workflow is identified via the 'agentId' field in params.message or X-Agent-ID header. "
164
+ "Optional: Pass user ID via X-User-ID header (recommended) or 'userId' in params.message.metadata. "
165
+ "Returns real-time updates as newline-delimited JSON (NDJSON).",
166
+ response_model_exclude_none=True,
167
+ responses={
168
+ 200: {
169
+ "description": "Streaming response with task updates",
170
+ "content": {
171
+ "application/x-ndjson": {
172
+ "example": '{"jsonrpc":"2.0","id":"request-123","result":{"taskId":"task-456","status":"working"}}\n'
173
+ '{"jsonrpc":"2.0","id":"request-123","result":{"messageId":"msg-1","role":"agent","parts":[{"kind":"text","text":"Response"}]}}\n'
174
+ }
175
+ },
176
+ },
177
+ 400: {"description": "Invalid request or unsupported method"},
178
+ 404: {"description": "Agent, Team, or Workflow not found"},
179
+ },
180
+ )
181
+ async def a2a_stream_message(request: Request):
182
+ request_body = await request.json()
183
+ kwargs = await get_request_kwargs(request, a2a_stream_message)
184
+
185
+ # 1. Get the Agent, Team, or Workflow to run
186
+ agent_id = request_body.get("params", {}).get("message", {}).get("agentId")
187
+ if not agent_id:
188
+ agent_id = request.headers.get("X-Agent-ID")
189
+ if not agent_id:
190
+ raise HTTPException(
191
+ status_code=400,
192
+ detail="Entity ID required. Provide 'agentId' in params.message or 'X-Agent-ID' header.",
193
+ )
194
+ entity: Optional[Union[Agent, Team, Workflow]] = None
195
+ if agents:
196
+ entity = get_agent_by_id(agent_id, agents)
197
+ if not entity and teams:
198
+ entity = get_team_by_id(agent_id, teams)
199
+ if not entity and workflows:
200
+ entity = get_workflow_by_id(agent_id, workflows)
201
+ if entity is None:
202
+ raise HTTPException(status_code=404, detail=f"Agent, Team, or Workflow with ID '{agent_id}' not found")
203
+
204
+ # 2. Map the request to our run_input and run variables
205
+ run_input = await map_a2a_request_to_run_input(request_body, stream=True)
206
+ context_id = request_body.get("params", {}).get("message", {}).get("contextId")
207
+ user_id = request.headers.get("X-User-ID")
208
+ if not user_id:
209
+ user_id = request_body.get("params", {}).get("message", {}).get("metadata", {}).get("userId")
210
+
211
+ # 3. Run the Agent, Team, or Workflow and stream the response
212
+ try:
213
+ if isinstance(entity, Workflow):
214
+ event_stream = entity.arun(
215
+ input=run_input.input_content,
216
+ images=list(run_input.images) if run_input.images else None,
217
+ videos=list(run_input.videos) if run_input.videos else None,
218
+ audio=list(run_input.audios) if run_input.audios else None,
219
+ files=list(run_input.files) if run_input.files else None,
220
+ session_id=context_id,
221
+ user_id=user_id,
222
+ stream=True,
223
+ stream_events=True,
224
+ **kwargs,
225
+ )
226
+ else:
227
+ event_stream = entity.arun( # type: ignore[assignment]
228
+ input=run_input.input_content,
229
+ images=run_input.images,
230
+ videos=run_input.videos,
231
+ audio=run_input.audios,
232
+ files=run_input.files,
233
+ session_id=context_id,
234
+ user_id=user_id,
235
+ stream=True,
236
+ stream_events=True,
237
+ **kwargs,
238
+ )
239
+
240
+ # 4. Stream the response
241
+ return StreamingResponse(
242
+ stream_a2a_response_with_error_handling(event_stream=event_stream, request_id=request_body["id"]), # type: ignore[arg-type]
243
+ media_type="application/x-ndjson",
244
+ )
245
+
246
+ except Exception as e:
247
+ raise HTTPException(status_code=500, detail=f"Failed to start run: {str(e)}")
248
+
249
+ return router