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/app.py ADDED
@@ -0,0 +1,1027 @@
1
+ from contextlib import asynccontextmanager
2
+ from functools import partial
3
+ from os import getenv
4
+ from typing import Any, Dict, List, Literal, Optional, Union
5
+ from uuid import uuid4
6
+
7
+ from fastapi import APIRouter, FastAPI, HTTPException
8
+ from fastapi.responses import JSONResponse
9
+ from fastapi.routing import APIRoute
10
+ from rich import box
11
+ from rich.panel import Panel
12
+ from starlette.requests import Request
13
+
14
+ from agno.agent.agent import Agent
15
+ from agno.db.base import AsyncBaseDb, BaseDb
16
+ from agno.knowledge.knowledge import Knowledge
17
+ from agno.os.config import (
18
+ AgentOSConfig,
19
+ AuthorizationConfig,
20
+ DatabaseConfig,
21
+ EvalsConfig,
22
+ EvalsDomainConfig,
23
+ KnowledgeConfig,
24
+ KnowledgeDomainConfig,
25
+ MemoryConfig,
26
+ MemoryDomainConfig,
27
+ MetricsConfig,
28
+ MetricsDomainConfig,
29
+ SessionConfig,
30
+ SessionDomainConfig,
31
+ TracesConfig,
32
+ TracesDomainConfig,
33
+ )
34
+ from agno.os.interfaces.base import BaseInterface
35
+ from agno.os.router import get_base_router
36
+ from agno.os.routers.agents import get_agent_router
37
+ from agno.os.routers.evals import get_eval_router
38
+ from agno.os.routers.health import get_health_router
39
+ from agno.os.routers.home import get_home_router
40
+ from agno.os.routers.knowledge import get_knowledge_router
41
+ from agno.os.routers.memory import get_memory_router
42
+ from agno.os.routers.metrics import get_metrics_router
43
+ from agno.os.routers.session import get_session_router
44
+ from agno.os.routers.teams import get_team_router
45
+ from agno.os.routers.traces import get_traces_router
46
+ from agno.os.routers.workflows import get_websocket_router, get_workflow_router
47
+ from agno.os.settings import AgnoAPISettings
48
+ from agno.os.utils import (
49
+ collect_mcp_tools_from_team,
50
+ collect_mcp_tools_from_workflow,
51
+ find_conflicting_routes,
52
+ load_yaml_config,
53
+ resolve_origins,
54
+ setup_tracing_for_os,
55
+ update_cors_middleware,
56
+ )
57
+ from agno.team.team import Team
58
+ from agno.utils.log import log_debug, log_error, log_info, log_warning
59
+ from agno.utils.string import generate_id, generate_id_from_name
60
+ from agno.workflow.workflow import Workflow
61
+
62
+
63
+ @asynccontextmanager
64
+ async def mcp_lifespan(_, mcp_tools):
65
+ """Manage MCP connection lifecycle inside a FastAPI app"""
66
+ # Startup logic: connect to all contextual MCP servers
67
+ for tool in mcp_tools:
68
+ await tool.connect()
69
+
70
+ yield
71
+
72
+ # Shutdown logic: Close all contextual MCP connections
73
+ for tool in mcp_tools:
74
+ await tool.close()
75
+
76
+
77
+ @asynccontextmanager
78
+ async def db_lifespan(app: FastAPI, agent_os: "AgentOS"):
79
+ """Initializes databases in the event loop"""
80
+ if agent_os.auto_provision_dbs:
81
+ agent_os._initialize_sync_databases()
82
+ await agent_os._initialize_async_databases()
83
+ yield
84
+
85
+
86
+ def _combine_app_lifespans(lifespans: list) -> Any:
87
+ """Combine multiple FastAPI app lifespan context managers into one."""
88
+ if len(lifespans) == 1:
89
+ return lifespans[0]
90
+
91
+ from contextlib import asynccontextmanager
92
+
93
+ @asynccontextmanager
94
+ async def combined_lifespan(app):
95
+ async def _run_nested(index: int):
96
+ if index >= len(lifespans):
97
+ yield
98
+ return
99
+
100
+ async with lifespans[index](app):
101
+ async for _ in _run_nested(index + 1):
102
+ yield
103
+
104
+ async for _ in _run_nested(0):
105
+ yield
106
+
107
+ return combined_lifespan
108
+
109
+
110
+ class AgentOS:
111
+ def __init__(
112
+ self,
113
+ id: Optional[str] = None,
114
+ name: Optional[str] = None,
115
+ description: Optional[str] = None,
116
+ version: Optional[str] = None,
117
+ agents: Optional[List[Agent]] = None,
118
+ teams: Optional[List[Team]] = None,
119
+ workflows: Optional[List[Workflow]] = None,
120
+ knowledge: Optional[List[Knowledge]] = None,
121
+ interfaces: Optional[List[BaseInterface]] = None,
122
+ a2a_interface: bool = False,
123
+ authorization: bool = False,
124
+ authorization_config: Optional[AuthorizationConfig] = None,
125
+ cors_allowed_origins: Optional[List[str]] = None,
126
+ config: Optional[Union[str, AgentOSConfig]] = None,
127
+ settings: Optional[AgnoAPISettings] = None,
128
+ lifespan: Optional[Any] = None,
129
+ enable_mcp_server: bool = False,
130
+ base_app: Optional[FastAPI] = None,
131
+ on_route_conflict: Literal["preserve_agentos", "preserve_base_app", "error"] = "preserve_agentos",
132
+ tracing: bool = False,
133
+ tracing_db: Optional[Union[BaseDb, AsyncBaseDb]] = None,
134
+ auto_provision_dbs: bool = True,
135
+ run_hooks_in_background: bool = False,
136
+ telemetry: bool = True,
137
+ ):
138
+ """Initialize AgentOS.
139
+
140
+ Args:
141
+ id: Unique identifier for this AgentOS instance
142
+ name: Name of the AgentOS instance
143
+ description: Description of the AgentOS instance
144
+ version: Version of the AgentOS instance
145
+ agents: List of agents to include in the OS
146
+ teams: List of teams to include in the OS
147
+ workflows: List of workflows to include in the OS
148
+ knowledge: List of knowledge bases to include in the OS
149
+ interfaces: List of interfaces to include in the OS
150
+ a2a_interface: Whether to expose the OS agents and teams in an A2A server
151
+ config: Configuration file path or AgentOSConfig instance
152
+ settings: API settings for the OS
153
+ lifespan: Optional lifespan context manager for the FastAPI app
154
+ enable_mcp_server: Whether to enable MCP (Model Context Protocol)
155
+ base_app: Optional base FastAPI app to use for the AgentOS. All routes and middleware will be added to this app.
156
+ on_route_conflict: What to do when a route conflict is detected in case a custom base_app is provided.
157
+ auto_provision_dbs: Whether to automatically provision databases
158
+ authorization: Whether to enable authorization
159
+ authorization_config: Configuration for the authorization middleware
160
+ cors_allowed_origins: List of allowed CORS origins (will be merged with default Agno domains)
161
+ tracing: If True, enables OpenTelemetry tracing for all agents and teams in the OS
162
+ tracing_db: Dedicated database for storing and reading traces. Recommended for multi-db setups.
163
+ If not provided and tracing=True, the first available db from agents/teams/workflows is used.
164
+ run_hooks_in_background: If True, run agent/team pre/post hooks as FastAPI background tasks (non-blocking)
165
+ telemetry: Whether to enable telemetry
166
+
167
+ """
168
+ if not agents and not workflows and not teams and not knowledge:
169
+ raise ValueError("Either agents, teams, workflows or knowledge bases must be provided.")
170
+
171
+ self.config = load_yaml_config(config) if isinstance(config, str) else config
172
+
173
+ self.agents: Optional[List[Agent]] = agents
174
+ self.workflows: Optional[List[Workflow]] = workflows
175
+ self.teams: Optional[List[Team]] = teams
176
+ self.interfaces = interfaces or []
177
+ self.a2a_interface = a2a_interface
178
+ self.knowledge = knowledge
179
+ self.settings: AgnoAPISettings = settings or AgnoAPISettings()
180
+ self.auto_provision_dbs = auto_provision_dbs
181
+ self._app_set = False
182
+
183
+ if base_app:
184
+ self.base_app: Optional[FastAPI] = base_app
185
+ self._app_set = True
186
+ self.on_route_conflict = on_route_conflict
187
+ else:
188
+ self.base_app = None
189
+ self._app_set = False
190
+ self.on_route_conflict = on_route_conflict
191
+
192
+ self.interfaces = interfaces or []
193
+
194
+ self.name = name
195
+
196
+ self.id = id
197
+ if not self.id:
198
+ self.id = generate_id(self.name) if self.name else str(uuid4())
199
+
200
+ self.version = version
201
+ self.description = description
202
+
203
+ self.telemetry = telemetry
204
+ self.tracing = tracing
205
+ self.tracing_db = tracing_db
206
+
207
+ self.enable_mcp_server = enable_mcp_server
208
+ self.lifespan = lifespan
209
+
210
+ # RBAC
211
+ self.authorization = authorization
212
+ self.authorization_config = authorization_config
213
+
214
+ # CORS configuration - merge user-provided origins with defaults from settings
215
+ self.cors_allowed_origins = resolve_origins(cors_allowed_origins, self.settings.cors_origin_list)
216
+
217
+ # If True, run agent/team hooks as FastAPI background tasks
218
+ self.run_hooks_in_background = run_hooks_in_background
219
+
220
+ # List of all MCP tools used inside the AgentOS
221
+ self.mcp_tools: List[Any] = []
222
+ self._mcp_app: Optional[Any] = None
223
+
224
+ self._initialize_agents()
225
+ self._initialize_teams()
226
+ self._initialize_workflows()
227
+
228
+ if self.tracing:
229
+ self._setup_tracing()
230
+
231
+ if self.telemetry:
232
+ from agno.api.os import OSLaunch, log_os_telemetry
233
+
234
+ log_os_telemetry(launch=OSLaunch(os_id=self.id, data=self._get_telemetry_data()))
235
+
236
+ def _add_agent_os_to_lifespan_function(self, lifespan):
237
+ """
238
+ Inspect a lifespan function and wrap it to pass agent_os if it accepts it.
239
+
240
+ Returns:
241
+ A wrapped lifespan that passes agent_os if the lifespan function expects it.
242
+ """
243
+ # Getting the actual function inside the lifespan
244
+ lifespan_function = lifespan
245
+ if hasattr(lifespan, "__wrapped__"):
246
+ lifespan_function = lifespan.__wrapped__
247
+
248
+ try:
249
+ from inspect import signature
250
+
251
+ # Inspecting the lifespan function signature to find its parameters
252
+ sig = signature(lifespan_function)
253
+ params = list(sig.parameters.keys())
254
+
255
+ # If the lifespan function expects the 'agent_os' parameter, add it
256
+ if "agent_os" in params:
257
+ return partial(lifespan, agent_os=self)
258
+ else:
259
+ return lifespan
260
+
261
+ except (ValueError, TypeError):
262
+ return lifespan
263
+
264
+ def resync(self, app: FastAPI) -> None:
265
+ """Resync the AgentOS to discover, initialize and configure: agents, teams, workflows, databases and knowledge bases."""
266
+ self._initialize_agents()
267
+ self._initialize_teams()
268
+ self._initialize_workflows()
269
+ self._auto_discover_databases()
270
+ self._auto_discover_knowledge_instances()
271
+
272
+ if self.enable_mcp_server:
273
+ from agno.os.mcp import get_mcp_server
274
+
275
+ self._mcp_app = get_mcp_server(self)
276
+
277
+ self._reprovision_routers(app=app)
278
+
279
+ def _reprovision_routers(self, app: FastAPI) -> None:
280
+ """Re-provision all routes for the AgentOS."""
281
+ updated_routers = [
282
+ get_session_router(dbs=self.dbs),
283
+ get_metrics_router(dbs=self.dbs),
284
+ get_knowledge_router(knowledge_instances=self.knowledge_instances),
285
+ get_traces_router(dbs=self.dbs),
286
+ get_memory_router(dbs=self.dbs),
287
+ get_eval_router(dbs=self.dbs, agents=self.agents, teams=self.teams),
288
+ ]
289
+
290
+ # Clear all previously existing routes
291
+ app.router.routes = [
292
+ route
293
+ for route in app.router.routes
294
+ if hasattr(route, "path")
295
+ and route.path in ["/docs", "/redoc", "/openapi.json", "/docs/oauth2-redirect"]
296
+ or route.path.startswith("/mcp") # type: ignore
297
+ ]
298
+
299
+ # Add the built-in routes
300
+ self._add_built_in_routes(app=app)
301
+
302
+ # Add the updated routes
303
+ for router in updated_routers:
304
+ self._add_router(app, router)
305
+
306
+ # Mount MCP if needed
307
+ if self.enable_mcp_server and self._mcp_app:
308
+ app.mount("/", self._mcp_app)
309
+
310
+ def _add_built_in_routes(self, app: FastAPI) -> None:
311
+ """Add all AgentOSbuilt-in routes to the given app."""
312
+ # Add the home router if MCP server is not enabled
313
+ if not self.enable_mcp_server:
314
+ self._add_router(app, get_home_router(self))
315
+
316
+ self._add_router(app, get_health_router(health_endpoint="/health"))
317
+ self._add_router(app, get_base_router(self, settings=self.settings))
318
+ self._add_router(app, get_agent_router(self, settings=self.settings))
319
+ self._add_router(app, get_team_router(self, settings=self.settings))
320
+ self._add_router(app, get_workflow_router(self, settings=self.settings))
321
+ self._add_router(app, get_websocket_router(self, settings=self.settings))
322
+
323
+ # Add A2A interface if relevant
324
+ has_a2a_interface = False
325
+ for interface in self.interfaces:
326
+ if not has_a2a_interface and interface.__class__.__name__ == "A2A":
327
+ has_a2a_interface = True
328
+ interface_router = interface.get_router()
329
+ self._add_router(app, interface_router)
330
+ if self.a2a_interface and not has_a2a_interface:
331
+ from agno.os.interfaces.a2a import A2A
332
+
333
+ a2a_interface = A2A(agents=self.agents, teams=self.teams, workflows=self.workflows)
334
+ self.interfaces.append(a2a_interface)
335
+ self._add_router(app, a2a_interface.get_router())
336
+
337
+ def _make_app(self, lifespan: Optional[Any] = None) -> FastAPI:
338
+ # Adjust the FastAPI app lifespan to handle MCP connections if relevant
339
+ app_lifespan = lifespan
340
+ if self.mcp_tools is not None:
341
+ mcp_tools_lifespan = partial(mcp_lifespan, mcp_tools=self.mcp_tools)
342
+ # If there is already a lifespan, combine it with the MCP lifespan
343
+ if lifespan is not None:
344
+ # Combine both lifespans
345
+ @asynccontextmanager
346
+ async def combined_lifespan(app: FastAPI):
347
+ # Run both lifespans
348
+ async with lifespan(app): # type: ignore
349
+ async with mcp_tools_lifespan(app): # type: ignore
350
+ yield
351
+
352
+ app_lifespan = combined_lifespan
353
+ else:
354
+ app_lifespan = mcp_tools_lifespan
355
+
356
+ return FastAPI(
357
+ title=self.name or "Agno AgentOS",
358
+ version=self.version or "1.0.0",
359
+ description=self.description or "An agent operating system.",
360
+ docs_url="/docs" if self.settings.docs_enabled else None,
361
+ redoc_url="/redoc" if self.settings.docs_enabled else None,
362
+ openapi_url="/openapi.json" if self.settings.docs_enabled else None,
363
+ lifespan=app_lifespan,
364
+ )
365
+
366
+ def _initialize_agents(self) -> None:
367
+ """Initialize and configure all agents for AgentOS usage."""
368
+ if not self.agents:
369
+ return
370
+ for agent in self.agents:
371
+ # Track all MCP tools to later handle their connection
372
+ if agent.tools:
373
+ for tool in agent.tools:
374
+ # Checking if the tool is an instance of MCPTools, MultiMCPTools, or a subclass of those
375
+ if hasattr(type(tool), "__mro__"):
376
+ mro_names = {cls.__name__ for cls in type(tool).__mro__}
377
+ if mro_names & {"MCPTools", "MultiMCPTools"}:
378
+ if tool not in self.mcp_tools:
379
+ self.mcp_tools.append(tool)
380
+
381
+ agent.initialize_agent()
382
+
383
+ # Required for the built-in routes to work
384
+ agent.store_events = True
385
+
386
+ # Propagate run_hooks_in_background setting from AgentOS to agents
387
+ agent._run_hooks_in_background = self.run_hooks_in_background
388
+
389
+ def _initialize_teams(self) -> None:
390
+ """Initialize and configure all teams for AgentOS usage."""
391
+ if not self.teams:
392
+ return
393
+
394
+ for team in self.teams:
395
+ # Track all MCP tools recursively
396
+ collect_mcp_tools_from_team(team, self.mcp_tools)
397
+
398
+ team.initialize_team()
399
+
400
+ for member in team.members:
401
+ if isinstance(member, Agent):
402
+ member.team_id = None
403
+ member.initialize_agent()
404
+ elif isinstance(member, Team):
405
+ member.initialize_team()
406
+
407
+ # Required for the built-in routes to work
408
+ team.store_events = True
409
+
410
+ # Propagate run_hooks_in_background setting to team and all nested members
411
+ team.propagate_run_hooks_in_background(self.run_hooks_in_background)
412
+
413
+ def _initialize_workflows(self) -> None:
414
+ """Initialize and configure all workflows for AgentOS usage."""
415
+ if not self.workflows:
416
+ return
417
+
418
+ if self.workflows:
419
+ for workflow in self.workflows:
420
+ # Track MCP tools recursively in workflow members
421
+ collect_mcp_tools_from_workflow(workflow, self.mcp_tools)
422
+
423
+ if not workflow.id:
424
+ workflow.id = generate_id_from_name(workflow.name)
425
+
426
+ # Required for the built-in routes to work
427
+ workflow.store_events = True
428
+
429
+ # Propagate run_hooks_in_background setting to workflow and all its step agents/teams
430
+ workflow.propagate_run_hooks_in_background(self.run_hooks_in_background)
431
+
432
+ def _setup_tracing(self) -> None:
433
+ """Set up OpenTelemetry tracing for this AgentOS.
434
+
435
+ Uses tracing_db if provided, otherwise falls back to the first available
436
+ database from agents/teams/workflows.
437
+ """
438
+ # Use tracing_db if explicitly provided
439
+ if self.tracing_db is not None:
440
+ setup_tracing_for_os(db=self.tracing_db)
441
+ return
442
+
443
+ # Fall back to finding the first available database
444
+ db: Optional[Union[BaseDb, AsyncBaseDb]] = None
445
+
446
+ for agent in self.agents or []:
447
+ if agent.db:
448
+ db = agent.db
449
+ break
450
+
451
+ if db is None:
452
+ for team in self.teams or []:
453
+ if team.db:
454
+ db = team.db
455
+ break
456
+
457
+ if db is None:
458
+ for workflow in self.workflows or []:
459
+ if workflow.db:
460
+ db = workflow.db
461
+ break
462
+
463
+ if db is None:
464
+ log_warning(
465
+ "tracing=True but no database found. "
466
+ "Provide 'tracing_db' parameter or 'db' parameter to at least one agent/team/workflow."
467
+ )
468
+ return
469
+
470
+ setup_tracing_for_os(db=db)
471
+
472
+ def get_app(self) -> FastAPI:
473
+ if self.base_app:
474
+ fastapi_app = self.base_app
475
+
476
+ # Initialize MCP server if enabled
477
+ if self.enable_mcp_server:
478
+ from agno.os.mcp import get_mcp_server
479
+
480
+ self._mcp_app = get_mcp_server(self)
481
+
482
+ # Collect all lifespans that need to be combined
483
+ lifespans = []
484
+
485
+ # The user provided lifespan
486
+ if self.lifespan:
487
+ # Wrap the user lifespan with agent_os parameter
488
+ wrapped_lifespan = self._add_agent_os_to_lifespan_function(self.lifespan)
489
+ lifespans.append(wrapped_lifespan)
490
+
491
+ # The provided app's existing lifespan
492
+ if fastapi_app.router.lifespan_context:
493
+ lifespans.append(fastapi_app.router.lifespan_context)
494
+
495
+ # The MCP tools lifespan
496
+ if self.mcp_tools:
497
+ lifespans.append(partial(mcp_lifespan, mcp_tools=self.mcp_tools))
498
+
499
+ # The /mcp server lifespan
500
+ if self.enable_mcp_server and self._mcp_app:
501
+ lifespans.append(self._mcp_app.lifespan)
502
+
503
+ # The async database lifespan
504
+ lifespans.append(partial(db_lifespan, agent_os=self))
505
+
506
+ # Combine lifespans and set them in the app
507
+ if lifespans:
508
+ fastapi_app.router.lifespan_context = _combine_app_lifespans(lifespans)
509
+
510
+ else:
511
+ lifespans = []
512
+
513
+ # User provided lifespan
514
+ if self.lifespan:
515
+ lifespans.append(self._add_agent_os_to_lifespan_function(self.lifespan))
516
+
517
+ # MCP tools lifespan
518
+ if self.mcp_tools:
519
+ lifespans.append(partial(mcp_lifespan, mcp_tools=self.mcp_tools))
520
+
521
+ # MCP server lifespan
522
+ if self.enable_mcp_server:
523
+ from agno.os.mcp import get_mcp_server
524
+
525
+ self._mcp_app = get_mcp_server(self)
526
+ lifespans.append(self._mcp_app.lifespan)
527
+
528
+ # Async database initialization lifespan
529
+ lifespans.append(partial(db_lifespan, agent_os=self)) # type: ignore
530
+
531
+ final_lifespan = _combine_app_lifespans(lifespans) if lifespans else None
532
+ fastapi_app = self._make_app(lifespan=final_lifespan)
533
+
534
+ self._add_built_in_routes(app=fastapi_app)
535
+
536
+ self._auto_discover_databases()
537
+ self._auto_discover_knowledge_instances()
538
+
539
+ routers = [
540
+ get_session_router(dbs=self.dbs),
541
+ get_memory_router(dbs=self.dbs),
542
+ get_eval_router(dbs=self.dbs, agents=self.agents, teams=self.teams),
543
+ get_metrics_router(dbs=self.dbs),
544
+ get_knowledge_router(knowledge_instances=self.knowledge_instances),
545
+ get_traces_router(dbs=self.dbs),
546
+ ]
547
+
548
+ for router in routers:
549
+ self._add_router(fastapi_app, router)
550
+
551
+ # Mount MCP if needed
552
+ if self.enable_mcp_server and self._mcp_app:
553
+ fastapi_app.mount("/", self._mcp_app)
554
+
555
+ if not self._app_set:
556
+
557
+ @fastapi_app.exception_handler(HTTPException)
558
+ async def http_exception_handler(_, exc: HTTPException) -> JSONResponse:
559
+ log_error(f"HTTP exception: {exc.status_code} {exc.detail}")
560
+ return JSONResponse(
561
+ status_code=exc.status_code,
562
+ content={"detail": str(exc.detail)},
563
+ )
564
+
565
+ @fastapi_app.exception_handler(Exception)
566
+ async def general_exception_handler(_: Request, exc: Exception) -> JSONResponse:
567
+ import traceback
568
+
569
+ log_error(f"Unhandled exception:\n{traceback.format_exc(limit=5)}")
570
+
571
+ return JSONResponse(
572
+ status_code=getattr(exc, "status_code", 500),
573
+ content={"detail": str(exc)},
574
+ )
575
+
576
+ # Update CORS middleware
577
+ update_cors_middleware(fastapi_app, self.cors_allowed_origins) # type: ignore
578
+
579
+ # Set agent_os_id and cors_allowed_origins on app state
580
+ # This allows middleware (like JWT) to access these values
581
+ fastapi_app.state.agent_os_id = self.id
582
+ fastapi_app.state.cors_allowed_origins = self.cors_allowed_origins
583
+
584
+ # Add JWT middleware if authorization is enabled
585
+ if self.authorization:
586
+ self._add_jwt_middleware(fastapi_app)
587
+
588
+ return fastapi_app
589
+
590
+ def _add_jwt_middleware(self, fastapi_app: FastAPI) -> None:
591
+ from agno.os.middleware.jwt import JWTMiddleware, JWTValidator
592
+
593
+ verify_audience = False
594
+ jwks_file = None
595
+ verification_keys = None
596
+ algorithm = "RS256"
597
+
598
+ if self.authorization_config:
599
+ algorithm = self.authorization_config.algorithm or "RS256"
600
+ verification_keys = self.authorization_config.verification_keys
601
+ jwks_file = self.authorization_config.jwks_file
602
+ verify_audience = self.authorization_config.verify_audience or False
603
+
604
+ log_info(f"Adding JWT middleware for authorization (algorithm: {algorithm})")
605
+
606
+ # Create validator and store on app.state for WebSocket access
607
+ jwt_validator = JWTValidator(
608
+ verification_keys=verification_keys,
609
+ jwks_file=jwks_file,
610
+ algorithm=algorithm,
611
+ )
612
+ fastapi_app.state.jwt_validator = jwt_validator
613
+
614
+ # Add middleware to stack
615
+ fastapi_app.add_middleware(
616
+ JWTMiddleware,
617
+ verification_keys=verification_keys,
618
+ jwks_file=jwks_file,
619
+ algorithm=algorithm,
620
+ authorization=self.authorization,
621
+ verify_audience=verify_audience,
622
+ )
623
+
624
+ def get_routes(self) -> List[Any]:
625
+ """Retrieve all routes from the FastAPI app.
626
+
627
+ Returns:
628
+ List[Any]: List of routes included in the FastAPI app.
629
+ """
630
+ app = self.get_app()
631
+
632
+ return app.routes
633
+
634
+ def _add_router(self, fastapi_app: FastAPI, router: APIRouter) -> None:
635
+ """Add a router to the FastAPI app, avoiding route conflicts.
636
+
637
+ Args:
638
+ router: The APIRouter to add
639
+ """
640
+
641
+ conflicts = find_conflicting_routes(fastapi_app, router)
642
+ conflicting_routes = [conflict["route"] for conflict in conflicts]
643
+
644
+ if conflicts and self._app_set:
645
+ if self.on_route_conflict == "preserve_base_app":
646
+ # Skip conflicting AgentOS routes, prefer user's existing routes
647
+ for conflict in conflicts:
648
+ methods_str = ", ".join(conflict["methods"]) # type: ignore
649
+ log_debug(
650
+ f"Skipping conflicting AgentOS route: {methods_str} {conflict['path']} - "
651
+ f"Using existing custom route instead"
652
+ )
653
+
654
+ # Create a new router without the conflicting routes
655
+ filtered_router = APIRouter()
656
+ for route in router.routes:
657
+ if route not in conflicting_routes:
658
+ filtered_router.routes.append(route)
659
+
660
+ # Use the filtered router if it has any routes left
661
+ if filtered_router.routes:
662
+ fastapi_app.include_router(filtered_router)
663
+
664
+ elif self.on_route_conflict == "preserve_agentos":
665
+ # Log warnings but still add all routes (AgentOS routes will override)
666
+ for conflict in conflicts:
667
+ methods_str = ", ".join(conflict["methods"]) # type: ignore
668
+ log_warning(
669
+ f"Route conflict detected: {methods_str} {conflict['path']} - "
670
+ f"AgentOS route will override existing custom route"
671
+ )
672
+
673
+ # Remove conflicting routes
674
+ for route in fastapi_app.routes:
675
+ for conflict in conflicts:
676
+ if isinstance(route, APIRoute):
677
+ if route.path == conflict["path"] and list(route.methods) == list(conflict["methods"]): # type: ignore
678
+ fastapi_app.routes.pop(fastapi_app.routes.index(route))
679
+
680
+ fastapi_app.include_router(router)
681
+
682
+ elif self.on_route_conflict == "error":
683
+ conflicting_paths = [conflict["path"] for conflict in conflicts]
684
+ raise ValueError(f"Route conflict detected: {conflicting_paths}")
685
+
686
+ else:
687
+ # No conflicts, add router normally
688
+ fastapi_app.include_router(router)
689
+
690
+ def _get_telemetry_data(self) -> Dict[str, Any]:
691
+ """Get the telemetry data for the OS"""
692
+ return {
693
+ "agents": [agent.id for agent in self.agents] if self.agents else None,
694
+ "teams": [team.id for team in self.teams] if self.teams else None,
695
+ "workflows": [workflow.id for workflow in self.workflows] if self.workflows else None,
696
+ "interfaces": [interface.type for interface in self.interfaces] if self.interfaces else None,
697
+ }
698
+
699
+ def _auto_discover_databases(self) -> None:
700
+ """Auto-discover and initialize the databases used by all contextual agents, teams and workflows."""
701
+
702
+ dbs: Dict[str, List[Union[BaseDb, AsyncBaseDb]]] = {}
703
+ knowledge_dbs: Dict[
704
+ str, List[Union[BaseDb, AsyncBaseDb]]
705
+ ] = {} # Track databases specifically used for knowledge
706
+
707
+ for agent in self.agents or []:
708
+ if agent.db:
709
+ self._register_db_with_validation(dbs, agent.db)
710
+ if agent.knowledge and agent.knowledge.contents_db:
711
+ self._register_db_with_validation(knowledge_dbs, agent.knowledge.contents_db)
712
+
713
+ for team in self.teams or []:
714
+ if team.db:
715
+ self._register_db_with_validation(dbs, team.db)
716
+ if team.knowledge and team.knowledge.contents_db:
717
+ self._register_db_with_validation(knowledge_dbs, team.knowledge.contents_db)
718
+
719
+ for workflow in self.workflows or []:
720
+ if workflow.db:
721
+ self._register_db_with_validation(dbs, workflow.db)
722
+
723
+ for knowledge_base in self.knowledge or []:
724
+ if knowledge_base.contents_db:
725
+ self._register_db_with_validation(knowledge_dbs, knowledge_base.contents_db)
726
+
727
+ for interface in self.interfaces or []:
728
+ if interface.agent and interface.agent.db:
729
+ self._register_db_with_validation(dbs, interface.agent.db)
730
+ elif interface.team and interface.team.db:
731
+ self._register_db_with_validation(dbs, interface.team.db)
732
+
733
+ # Register tracing_db if provided (for traces reading)
734
+ if self.tracing_db is not None:
735
+ self._register_db_with_validation(dbs, self.tracing_db)
736
+
737
+ self.dbs = dbs
738
+ self.knowledge_dbs = knowledge_dbs
739
+
740
+ # Initialize all discovered databases
741
+ if self.auto_provision_dbs:
742
+ self._pending_async_db_init = True
743
+
744
+ def _initialize_sync_databases(self) -> None:
745
+ """Initialize sync databases."""
746
+ from itertools import chain
747
+
748
+ unique_dbs = list(
749
+ {
750
+ id(db): db
751
+ for db in chain(
752
+ chain.from_iterable(self.dbs.values()), chain.from_iterable(self.knowledge_dbs.values())
753
+ )
754
+ }.values()
755
+ )
756
+
757
+ for db in unique_dbs:
758
+ if isinstance(db, AsyncBaseDb):
759
+ continue # Skip async dbs
760
+
761
+ try:
762
+ if hasattr(db, "_create_all_tables") and callable(db._create_all_tables):
763
+ db._create_all_tables()
764
+ except Exception as e:
765
+ log_warning(f"Failed to initialize {db.__class__.__name__} (id: {db.id}): {e}")
766
+
767
+ async def _initialize_async_databases(self) -> None:
768
+ """Initialize async databases."""
769
+
770
+ from itertools import chain
771
+
772
+ unique_dbs = list(
773
+ {
774
+ id(db): db
775
+ for db in chain(
776
+ chain.from_iterable(self.dbs.values()), chain.from_iterable(self.knowledge_dbs.values())
777
+ )
778
+ }.values()
779
+ )
780
+
781
+ for db in unique_dbs:
782
+ if not isinstance(db, AsyncBaseDb):
783
+ continue # Skip sync dbs
784
+
785
+ try:
786
+ if hasattr(db, "_create_all_tables") and callable(db._create_all_tables):
787
+ await db._create_all_tables()
788
+ except Exception as e:
789
+ log_warning(f"Failed to initialize async {db.__class__.__name__} (id: {db.id}): {e}")
790
+
791
+ def _get_db_table_names(self, db: BaseDb) -> Dict[str, str]:
792
+ """Get the table names for a database"""
793
+ table_names = {
794
+ "session_table_name": db.session_table_name,
795
+ "culture_table_name": db.culture_table_name,
796
+ "memory_table_name": db.memory_table_name,
797
+ "metrics_table_name": db.metrics_table_name,
798
+ "evals_table_name": db.eval_table_name,
799
+ "knowledge_table_name": db.knowledge_table_name,
800
+ }
801
+ return {k: v for k, v in table_names.items() if v is not None}
802
+
803
+ def _register_db_with_validation(
804
+ self, registered_dbs: Dict[str, List[Union[BaseDb, AsyncBaseDb]]], db: Union[BaseDb, AsyncBaseDb]
805
+ ) -> None:
806
+ """Register a database in the contextual OS after validating it is not conflicting with registered databases"""
807
+ if db.id in registered_dbs:
808
+ registered_dbs[db.id].append(db)
809
+ else:
810
+ registered_dbs[db.id] = [db]
811
+
812
+ def _auto_discover_knowledge_instances(self) -> None:
813
+ """Auto-discover the knowledge instances used by all contextual agents, teams and workflows."""
814
+ seen_ids = set()
815
+ knowledge_instances: List[Knowledge] = []
816
+
817
+ def _add_knowledge_if_not_duplicate(knowledge: "Knowledge") -> None:
818
+ """Add knowledge instance if it's not already in the list (by object identity or db_id)."""
819
+ # Use database ID if available, otherwise use object ID as fallback
820
+ if not knowledge.contents_db:
821
+ return
822
+ if knowledge.contents_db.id in seen_ids:
823
+ return
824
+ seen_ids.add(knowledge.contents_db.id)
825
+ knowledge_instances.append(knowledge)
826
+
827
+ for agent in self.agents or []:
828
+ if agent.knowledge:
829
+ _add_knowledge_if_not_duplicate(agent.knowledge)
830
+
831
+ for team in self.teams or []:
832
+ if team.knowledge:
833
+ _add_knowledge_if_not_duplicate(team.knowledge)
834
+
835
+ for knowledge_base in self.knowledge or []:
836
+ _add_knowledge_if_not_duplicate(knowledge_base)
837
+
838
+ self.knowledge_instances = knowledge_instances
839
+
840
+ def _get_session_config(self) -> SessionConfig:
841
+ session_config = self.config.session if self.config and self.config.session else SessionConfig()
842
+
843
+ if session_config.dbs is None:
844
+ session_config.dbs = []
845
+
846
+ dbs_with_specific_config = [db.db_id for db in session_config.dbs]
847
+ for db_id, dbs in self.dbs.items():
848
+ if db_id not in dbs_with_specific_config:
849
+ # Collect unique table names from all databases with the same id
850
+ unique_tables = list(set(db.session_table_name for db in dbs))
851
+ session_config.dbs.append(
852
+ DatabaseConfig(
853
+ db_id=db_id,
854
+ domain_config=SessionDomainConfig(display_name=db_id),
855
+ tables=unique_tables,
856
+ )
857
+ )
858
+
859
+ return session_config
860
+
861
+ def _get_memory_config(self) -> MemoryConfig:
862
+ memory_config = self.config.memory if self.config and self.config.memory else MemoryConfig()
863
+
864
+ if memory_config.dbs is None:
865
+ memory_config.dbs = []
866
+
867
+ dbs_with_specific_config = [db.db_id for db in memory_config.dbs]
868
+
869
+ for db_id, dbs in self.dbs.items():
870
+ if db_id not in dbs_with_specific_config:
871
+ # Collect unique table names from all databases with the same id
872
+ unique_tables = list(set(db.memory_table_name for db in dbs))
873
+ memory_config.dbs.append(
874
+ DatabaseConfig(
875
+ db_id=db_id,
876
+ domain_config=MemoryDomainConfig(display_name=db_id),
877
+ tables=unique_tables,
878
+ )
879
+ )
880
+
881
+ return memory_config
882
+
883
+ def _get_knowledge_config(self) -> KnowledgeConfig:
884
+ knowledge_config = self.config.knowledge if self.config and self.config.knowledge else KnowledgeConfig()
885
+
886
+ if knowledge_config.dbs is None:
887
+ knowledge_config.dbs = []
888
+
889
+ dbs_with_specific_config = [db.db_id for db in knowledge_config.dbs]
890
+
891
+ # Only add databases that are actually used for knowledge contents
892
+ for db_id in self.knowledge_dbs.keys():
893
+ if db_id not in dbs_with_specific_config:
894
+ knowledge_config.dbs.append(
895
+ DatabaseConfig(
896
+ db_id=db_id,
897
+ domain_config=KnowledgeDomainConfig(display_name=db_id),
898
+ )
899
+ )
900
+
901
+ return knowledge_config
902
+
903
+ def _get_metrics_config(self) -> MetricsConfig:
904
+ metrics_config = self.config.metrics if self.config and self.config.metrics else MetricsConfig()
905
+
906
+ if metrics_config.dbs is None:
907
+ metrics_config.dbs = []
908
+
909
+ dbs_with_specific_config = [db.db_id for db in metrics_config.dbs]
910
+
911
+ for db_id, dbs in self.dbs.items():
912
+ if db_id not in dbs_with_specific_config:
913
+ # Collect unique table names from all databases with the same id
914
+ unique_tables = list(set(db.metrics_table_name for db in dbs))
915
+ metrics_config.dbs.append(
916
+ DatabaseConfig(
917
+ db_id=db_id,
918
+ domain_config=MetricsDomainConfig(display_name=db_id),
919
+ tables=unique_tables,
920
+ )
921
+ )
922
+
923
+ return metrics_config
924
+
925
+ def _get_evals_config(self) -> EvalsConfig:
926
+ evals_config = self.config.evals if self.config and self.config.evals else EvalsConfig()
927
+
928
+ if evals_config.dbs is None:
929
+ evals_config.dbs = []
930
+
931
+ dbs_with_specific_config = [db.db_id for db in evals_config.dbs]
932
+
933
+ for db_id, dbs in self.dbs.items():
934
+ if db_id not in dbs_with_specific_config:
935
+ # Collect unique table names from all databases with the same id
936
+ unique_tables = list(set(db.eval_table_name for db in dbs))
937
+ evals_config.dbs.append(
938
+ DatabaseConfig(
939
+ db_id=db_id,
940
+ domain_config=EvalsDomainConfig(display_name=db_id),
941
+ tables=unique_tables,
942
+ )
943
+ )
944
+
945
+ return evals_config
946
+
947
+ def _get_traces_config(self) -> TracesConfig:
948
+ traces_config = self.config.traces if self.config and self.config.traces else TracesConfig()
949
+
950
+ if traces_config.dbs is None:
951
+ traces_config.dbs = []
952
+
953
+ dbs_with_specific_config = [db.db_id for db in traces_config.dbs]
954
+
955
+ # If tracing_db is explicitly set, only use that database for traces
956
+ if self.tracing_db is not None:
957
+ if self.tracing_db.id not in dbs_with_specific_config:
958
+ traces_config.dbs.append(
959
+ DatabaseConfig(
960
+ db_id=self.tracing_db.id,
961
+ domain_config=TracesDomainConfig(display_name=self.tracing_db.id),
962
+ )
963
+ )
964
+ else:
965
+ # Fall back to all discovered databases
966
+ for db_id in self.dbs.keys():
967
+ if db_id not in dbs_with_specific_config:
968
+ traces_config.dbs.append(
969
+ DatabaseConfig(
970
+ db_id=db_id,
971
+ domain_config=TracesDomainConfig(display_name=db_id),
972
+ )
973
+ )
974
+
975
+ return traces_config
976
+
977
+ def serve(
978
+ self,
979
+ app: Union[str, FastAPI],
980
+ *,
981
+ host: str = "localhost",
982
+ port: int = 7777,
983
+ reload: bool = False,
984
+ workers: Optional[int] = None,
985
+ access_log: bool = False,
986
+ **kwargs,
987
+ ):
988
+ import uvicorn
989
+
990
+ if getenv("AGNO_API_RUNTIME", "").lower() == "stg":
991
+ public_endpoint = "https://os-stg.agno.com/"
992
+ else:
993
+ public_endpoint = "https://os.agno.com/"
994
+
995
+ # Create a terminal panel to announce OS initialization and provide useful info
996
+ from rich.align import Align
997
+ from rich.console import Console, Group
998
+
999
+ panel_group = [
1000
+ Align.center(f"[bold cyan]{public_endpoint}[/bold cyan]"),
1001
+ Align.center(f"\n\n[bold dark_orange]OS running on:[/bold dark_orange] http://{host}:{port}"),
1002
+ ]
1003
+ if bool(self.settings.os_security_key):
1004
+ panel_group.append(Align.center("\n\n[bold chartreuse3]:lock: Security Enabled[/bold chartreuse3]"))
1005
+
1006
+ console = Console()
1007
+ console.print(
1008
+ Panel(
1009
+ Group(*panel_group),
1010
+ title="AgentOS",
1011
+ expand=False,
1012
+ border_style="dark_orange",
1013
+ box=box.DOUBLE_EDGE,
1014
+ padding=(2, 2),
1015
+ )
1016
+ )
1017
+
1018
+ uvicorn.run(
1019
+ app=app,
1020
+ host=host,
1021
+ port=port,
1022
+ reload=reload,
1023
+ workers=workers,
1024
+ access_log=access_log,
1025
+ lifespan="on",
1026
+ **kwargs,
1027
+ )