agno 2.2.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 (575) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +51 -0
  3. agno/agent/agent.py +10405 -0
  4. agno/api/__init__.py +0 -0
  5. agno/api/agent.py +28 -0
  6. agno/api/api.py +40 -0
  7. agno/api/evals.py +22 -0
  8. agno/api/os.py +17 -0
  9. agno/api/routes.py +13 -0
  10. agno/api/schemas/__init__.py +9 -0
  11. agno/api/schemas/agent.py +16 -0
  12. agno/api/schemas/evals.py +16 -0
  13. agno/api/schemas/os.py +14 -0
  14. agno/api/schemas/response.py +6 -0
  15. agno/api/schemas/team.py +16 -0
  16. agno/api/schemas/utils.py +21 -0
  17. agno/api/schemas/workflows.py +16 -0
  18. agno/api/settings.py +53 -0
  19. agno/api/team.py +30 -0
  20. agno/api/workflow.py +28 -0
  21. agno/cloud/aws/base.py +214 -0
  22. agno/cloud/aws/s3/__init__.py +2 -0
  23. agno/cloud/aws/s3/api_client.py +43 -0
  24. agno/cloud/aws/s3/bucket.py +195 -0
  25. agno/cloud/aws/s3/object.py +57 -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 +598 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2042 -0
  33. agno/db/dynamo/schemas.py +314 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +1795 -0
  37. agno/db/firestore/schemas.py +140 -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 +1335 -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 +1160 -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 +1328 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/__init__.py +0 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/mongo/__init__.py +17 -0
  51. agno/db/mongo/async_mongo.py +2026 -0
  52. agno/db/mongo/mongo.py +1982 -0
  53. agno/db/mongo/schemas.py +87 -0
  54. agno/db/mongo/utils.py +259 -0
  55. agno/db/mysql/__init__.py +3 -0
  56. agno/db/mysql/mysql.py +2308 -0
  57. agno/db/mysql/schemas.py +138 -0
  58. agno/db/mysql/utils.py +355 -0
  59. agno/db/postgres/__init__.py +4 -0
  60. agno/db/postgres/async_postgres.py +1927 -0
  61. agno/db/postgres/postgres.py +2260 -0
  62. agno/db/postgres/schemas.py +139 -0
  63. agno/db/postgres/utils.py +442 -0
  64. agno/db/redis/__init__.py +3 -0
  65. agno/db/redis/redis.py +1660 -0
  66. agno/db/redis/schemas.py +123 -0
  67. agno/db/redis/utils.py +346 -0
  68. agno/db/schemas/__init__.py +4 -0
  69. agno/db/schemas/culture.py +120 -0
  70. agno/db/schemas/evals.py +33 -0
  71. agno/db/schemas/knowledge.py +40 -0
  72. agno/db/schemas/memory.py +46 -0
  73. agno/db/schemas/metrics.py +0 -0
  74. agno/db/singlestore/__init__.py +3 -0
  75. agno/db/singlestore/schemas.py +130 -0
  76. agno/db/singlestore/singlestore.py +2272 -0
  77. agno/db/singlestore/utils.py +384 -0
  78. agno/db/sqlite/__init__.py +4 -0
  79. agno/db/sqlite/async_sqlite.py +2293 -0
  80. agno/db/sqlite/schemas.py +133 -0
  81. agno/db/sqlite/sqlite.py +2288 -0
  82. agno/db/sqlite/utils.py +431 -0
  83. agno/db/surrealdb/__init__.py +3 -0
  84. agno/db/surrealdb/metrics.py +292 -0
  85. agno/db/surrealdb/models.py +309 -0
  86. agno/db/surrealdb/queries.py +71 -0
  87. agno/db/surrealdb/surrealdb.py +1353 -0
  88. agno/db/surrealdb/utils.py +147 -0
  89. agno/db/utils.py +116 -0
  90. agno/debug.py +18 -0
  91. agno/eval/__init__.py +14 -0
  92. agno/eval/accuracy.py +834 -0
  93. agno/eval/performance.py +773 -0
  94. agno/eval/reliability.py +306 -0
  95. agno/eval/utils.py +119 -0
  96. agno/exceptions.py +161 -0
  97. agno/filters.py +354 -0
  98. agno/guardrails/__init__.py +6 -0
  99. agno/guardrails/base.py +19 -0
  100. agno/guardrails/openai.py +144 -0
  101. agno/guardrails/pii.py +94 -0
  102. agno/guardrails/prompt_injection.py +52 -0
  103. agno/integrations/__init__.py +0 -0
  104. agno/integrations/discord/__init__.py +3 -0
  105. agno/integrations/discord/client.py +203 -0
  106. agno/knowledge/__init__.py +5 -0
  107. agno/knowledge/chunking/__init__.py +0 -0
  108. agno/knowledge/chunking/agentic.py +79 -0
  109. agno/knowledge/chunking/document.py +91 -0
  110. agno/knowledge/chunking/fixed.py +57 -0
  111. agno/knowledge/chunking/markdown.py +151 -0
  112. agno/knowledge/chunking/recursive.py +63 -0
  113. agno/knowledge/chunking/row.py +39 -0
  114. agno/knowledge/chunking/semantic.py +86 -0
  115. agno/knowledge/chunking/strategy.py +165 -0
  116. agno/knowledge/content.py +74 -0
  117. agno/knowledge/document/__init__.py +5 -0
  118. agno/knowledge/document/base.py +58 -0
  119. agno/knowledge/embedder/__init__.py +5 -0
  120. agno/knowledge/embedder/aws_bedrock.py +343 -0
  121. agno/knowledge/embedder/azure_openai.py +210 -0
  122. agno/knowledge/embedder/base.py +23 -0
  123. agno/knowledge/embedder/cohere.py +323 -0
  124. agno/knowledge/embedder/fastembed.py +62 -0
  125. agno/knowledge/embedder/fireworks.py +13 -0
  126. agno/knowledge/embedder/google.py +258 -0
  127. agno/knowledge/embedder/huggingface.py +94 -0
  128. agno/knowledge/embedder/jina.py +182 -0
  129. agno/knowledge/embedder/langdb.py +22 -0
  130. agno/knowledge/embedder/mistral.py +206 -0
  131. agno/knowledge/embedder/nebius.py +13 -0
  132. agno/knowledge/embedder/ollama.py +154 -0
  133. agno/knowledge/embedder/openai.py +195 -0
  134. agno/knowledge/embedder/sentence_transformer.py +63 -0
  135. agno/knowledge/embedder/together.py +13 -0
  136. agno/knowledge/embedder/vllm.py +262 -0
  137. agno/knowledge/embedder/voyageai.py +165 -0
  138. agno/knowledge/knowledge.py +1988 -0
  139. agno/knowledge/reader/__init__.py +7 -0
  140. agno/knowledge/reader/arxiv_reader.py +81 -0
  141. agno/knowledge/reader/base.py +95 -0
  142. agno/knowledge/reader/csv_reader.py +166 -0
  143. agno/knowledge/reader/docx_reader.py +82 -0
  144. agno/knowledge/reader/field_labeled_csv_reader.py +292 -0
  145. agno/knowledge/reader/firecrawl_reader.py +201 -0
  146. agno/knowledge/reader/json_reader.py +87 -0
  147. agno/knowledge/reader/markdown_reader.py +137 -0
  148. agno/knowledge/reader/pdf_reader.py +431 -0
  149. agno/knowledge/reader/pptx_reader.py +101 -0
  150. agno/knowledge/reader/reader_factory.py +313 -0
  151. agno/knowledge/reader/s3_reader.py +89 -0
  152. agno/knowledge/reader/tavily_reader.py +194 -0
  153. agno/knowledge/reader/text_reader.py +115 -0
  154. agno/knowledge/reader/web_search_reader.py +372 -0
  155. agno/knowledge/reader/website_reader.py +455 -0
  156. agno/knowledge/reader/wikipedia_reader.py +59 -0
  157. agno/knowledge/reader/youtube_reader.py +78 -0
  158. agno/knowledge/remote_content/__init__.py +0 -0
  159. agno/knowledge/remote_content/remote_content.py +88 -0
  160. agno/knowledge/reranker/__init__.py +3 -0
  161. agno/knowledge/reranker/base.py +14 -0
  162. agno/knowledge/reranker/cohere.py +64 -0
  163. agno/knowledge/reranker/infinity.py +195 -0
  164. agno/knowledge/reranker/sentence_transformer.py +54 -0
  165. agno/knowledge/types.py +39 -0
  166. agno/knowledge/utils.py +189 -0
  167. agno/media.py +462 -0
  168. agno/memory/__init__.py +3 -0
  169. agno/memory/manager.py +1327 -0
  170. agno/models/__init__.py +0 -0
  171. agno/models/aimlapi/__init__.py +5 -0
  172. agno/models/aimlapi/aimlapi.py +45 -0
  173. agno/models/anthropic/__init__.py +5 -0
  174. agno/models/anthropic/claude.py +757 -0
  175. agno/models/aws/__init__.py +15 -0
  176. agno/models/aws/bedrock.py +701 -0
  177. agno/models/aws/claude.py +378 -0
  178. agno/models/azure/__init__.py +18 -0
  179. agno/models/azure/ai_foundry.py +485 -0
  180. agno/models/azure/openai_chat.py +131 -0
  181. agno/models/base.py +2175 -0
  182. agno/models/cerebras/__init__.py +12 -0
  183. agno/models/cerebras/cerebras.py +501 -0
  184. agno/models/cerebras/cerebras_openai.py +112 -0
  185. agno/models/cohere/__init__.py +5 -0
  186. agno/models/cohere/chat.py +389 -0
  187. agno/models/cometapi/__init__.py +5 -0
  188. agno/models/cometapi/cometapi.py +57 -0
  189. agno/models/dashscope/__init__.py +5 -0
  190. agno/models/dashscope/dashscope.py +91 -0
  191. agno/models/deepinfra/__init__.py +5 -0
  192. agno/models/deepinfra/deepinfra.py +28 -0
  193. agno/models/deepseek/__init__.py +5 -0
  194. agno/models/deepseek/deepseek.py +61 -0
  195. agno/models/defaults.py +1 -0
  196. agno/models/fireworks/__init__.py +5 -0
  197. agno/models/fireworks/fireworks.py +26 -0
  198. agno/models/google/__init__.py +5 -0
  199. agno/models/google/gemini.py +1085 -0
  200. agno/models/groq/__init__.py +5 -0
  201. agno/models/groq/groq.py +556 -0
  202. agno/models/huggingface/__init__.py +5 -0
  203. agno/models/huggingface/huggingface.py +491 -0
  204. agno/models/ibm/__init__.py +5 -0
  205. agno/models/ibm/watsonx.py +422 -0
  206. agno/models/internlm/__init__.py +3 -0
  207. agno/models/internlm/internlm.py +26 -0
  208. agno/models/langdb/__init__.py +1 -0
  209. agno/models/langdb/langdb.py +48 -0
  210. agno/models/litellm/__init__.py +14 -0
  211. agno/models/litellm/chat.py +468 -0
  212. agno/models/litellm/litellm_openai.py +25 -0
  213. agno/models/llama_cpp/__init__.py +5 -0
  214. agno/models/llama_cpp/llama_cpp.py +22 -0
  215. agno/models/lmstudio/__init__.py +5 -0
  216. agno/models/lmstudio/lmstudio.py +25 -0
  217. agno/models/message.py +434 -0
  218. agno/models/meta/__init__.py +12 -0
  219. agno/models/meta/llama.py +475 -0
  220. agno/models/meta/llama_openai.py +78 -0
  221. agno/models/metrics.py +120 -0
  222. agno/models/mistral/__init__.py +5 -0
  223. agno/models/mistral/mistral.py +432 -0
  224. agno/models/nebius/__init__.py +3 -0
  225. agno/models/nebius/nebius.py +54 -0
  226. agno/models/nexus/__init__.py +3 -0
  227. agno/models/nexus/nexus.py +22 -0
  228. agno/models/nvidia/__init__.py +5 -0
  229. agno/models/nvidia/nvidia.py +28 -0
  230. agno/models/ollama/__init__.py +5 -0
  231. agno/models/ollama/chat.py +441 -0
  232. agno/models/openai/__init__.py +9 -0
  233. agno/models/openai/chat.py +883 -0
  234. agno/models/openai/like.py +27 -0
  235. agno/models/openai/responses.py +1050 -0
  236. agno/models/openrouter/__init__.py +5 -0
  237. agno/models/openrouter/openrouter.py +66 -0
  238. agno/models/perplexity/__init__.py +5 -0
  239. agno/models/perplexity/perplexity.py +187 -0
  240. agno/models/portkey/__init__.py +3 -0
  241. agno/models/portkey/portkey.py +81 -0
  242. agno/models/requesty/__init__.py +5 -0
  243. agno/models/requesty/requesty.py +52 -0
  244. agno/models/response.py +199 -0
  245. agno/models/sambanova/__init__.py +5 -0
  246. agno/models/sambanova/sambanova.py +28 -0
  247. agno/models/siliconflow/__init__.py +5 -0
  248. agno/models/siliconflow/siliconflow.py +25 -0
  249. agno/models/together/__init__.py +5 -0
  250. agno/models/together/together.py +25 -0
  251. agno/models/utils.py +266 -0
  252. agno/models/vercel/__init__.py +3 -0
  253. agno/models/vercel/v0.py +26 -0
  254. agno/models/vertexai/__init__.py +0 -0
  255. agno/models/vertexai/claude.py +70 -0
  256. agno/models/vllm/__init__.py +3 -0
  257. agno/models/vllm/vllm.py +78 -0
  258. agno/models/xai/__init__.py +3 -0
  259. agno/models/xai/xai.py +113 -0
  260. agno/os/__init__.py +3 -0
  261. agno/os/app.py +876 -0
  262. agno/os/auth.py +57 -0
  263. agno/os/config.py +104 -0
  264. agno/os/interfaces/__init__.py +1 -0
  265. agno/os/interfaces/a2a/__init__.py +3 -0
  266. agno/os/interfaces/a2a/a2a.py +42 -0
  267. agno/os/interfaces/a2a/router.py +250 -0
  268. agno/os/interfaces/a2a/utils.py +924 -0
  269. agno/os/interfaces/agui/__init__.py +3 -0
  270. agno/os/interfaces/agui/agui.py +47 -0
  271. agno/os/interfaces/agui/router.py +144 -0
  272. agno/os/interfaces/agui/utils.py +534 -0
  273. agno/os/interfaces/base.py +25 -0
  274. agno/os/interfaces/slack/__init__.py +3 -0
  275. agno/os/interfaces/slack/router.py +148 -0
  276. agno/os/interfaces/slack/security.py +30 -0
  277. agno/os/interfaces/slack/slack.py +47 -0
  278. agno/os/interfaces/whatsapp/__init__.py +3 -0
  279. agno/os/interfaces/whatsapp/router.py +211 -0
  280. agno/os/interfaces/whatsapp/security.py +53 -0
  281. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  282. agno/os/mcp.py +292 -0
  283. agno/os/middleware/__init__.py +7 -0
  284. agno/os/middleware/jwt.py +233 -0
  285. agno/os/router.py +1763 -0
  286. agno/os/routers/__init__.py +3 -0
  287. agno/os/routers/evals/__init__.py +3 -0
  288. agno/os/routers/evals/evals.py +430 -0
  289. agno/os/routers/evals/schemas.py +142 -0
  290. agno/os/routers/evals/utils.py +162 -0
  291. agno/os/routers/health.py +31 -0
  292. agno/os/routers/home.py +52 -0
  293. agno/os/routers/knowledge/__init__.py +3 -0
  294. agno/os/routers/knowledge/knowledge.py +997 -0
  295. agno/os/routers/knowledge/schemas.py +178 -0
  296. agno/os/routers/memory/__init__.py +3 -0
  297. agno/os/routers/memory/memory.py +515 -0
  298. agno/os/routers/memory/schemas.py +62 -0
  299. agno/os/routers/metrics/__init__.py +3 -0
  300. agno/os/routers/metrics/metrics.py +190 -0
  301. agno/os/routers/metrics/schemas.py +47 -0
  302. agno/os/routers/session/__init__.py +3 -0
  303. agno/os/routers/session/session.py +997 -0
  304. agno/os/schema.py +1055 -0
  305. agno/os/settings.py +43 -0
  306. agno/os/utils.py +630 -0
  307. agno/py.typed +0 -0
  308. agno/reasoning/__init__.py +0 -0
  309. agno/reasoning/anthropic.py +80 -0
  310. agno/reasoning/azure_ai_foundry.py +67 -0
  311. agno/reasoning/deepseek.py +63 -0
  312. agno/reasoning/default.py +97 -0
  313. agno/reasoning/gemini.py +73 -0
  314. agno/reasoning/groq.py +71 -0
  315. agno/reasoning/helpers.py +63 -0
  316. agno/reasoning/ollama.py +67 -0
  317. agno/reasoning/openai.py +86 -0
  318. agno/reasoning/step.py +31 -0
  319. agno/reasoning/vertexai.py +76 -0
  320. agno/run/__init__.py +6 -0
  321. agno/run/agent.py +787 -0
  322. agno/run/base.py +229 -0
  323. agno/run/cancel.py +81 -0
  324. agno/run/messages.py +32 -0
  325. agno/run/team.py +753 -0
  326. agno/run/workflow.py +708 -0
  327. agno/session/__init__.py +10 -0
  328. agno/session/agent.py +295 -0
  329. agno/session/summary.py +265 -0
  330. agno/session/team.py +392 -0
  331. agno/session/workflow.py +205 -0
  332. agno/team/__init__.py +37 -0
  333. agno/team/team.py +8793 -0
  334. agno/tools/__init__.py +10 -0
  335. agno/tools/agentql.py +120 -0
  336. agno/tools/airflow.py +69 -0
  337. agno/tools/api.py +122 -0
  338. agno/tools/apify.py +314 -0
  339. agno/tools/arxiv.py +127 -0
  340. agno/tools/aws_lambda.py +53 -0
  341. agno/tools/aws_ses.py +66 -0
  342. agno/tools/baidusearch.py +89 -0
  343. agno/tools/bitbucket.py +292 -0
  344. agno/tools/brandfetch.py +213 -0
  345. agno/tools/bravesearch.py +106 -0
  346. agno/tools/brightdata.py +367 -0
  347. agno/tools/browserbase.py +209 -0
  348. agno/tools/calcom.py +255 -0
  349. agno/tools/calculator.py +151 -0
  350. agno/tools/cartesia.py +187 -0
  351. agno/tools/clickup.py +244 -0
  352. agno/tools/confluence.py +240 -0
  353. agno/tools/crawl4ai.py +158 -0
  354. agno/tools/csv_toolkit.py +185 -0
  355. agno/tools/dalle.py +110 -0
  356. agno/tools/daytona.py +475 -0
  357. agno/tools/decorator.py +262 -0
  358. agno/tools/desi_vocal.py +108 -0
  359. agno/tools/discord.py +161 -0
  360. agno/tools/docker.py +716 -0
  361. agno/tools/duckdb.py +379 -0
  362. agno/tools/duckduckgo.py +91 -0
  363. agno/tools/e2b.py +703 -0
  364. agno/tools/eleven_labs.py +196 -0
  365. agno/tools/email.py +67 -0
  366. agno/tools/evm.py +129 -0
  367. agno/tools/exa.py +396 -0
  368. agno/tools/fal.py +127 -0
  369. agno/tools/file.py +240 -0
  370. agno/tools/file_generation.py +350 -0
  371. agno/tools/financial_datasets.py +288 -0
  372. agno/tools/firecrawl.py +143 -0
  373. agno/tools/function.py +1187 -0
  374. agno/tools/giphy.py +93 -0
  375. agno/tools/github.py +1760 -0
  376. agno/tools/gmail.py +922 -0
  377. agno/tools/google_bigquery.py +117 -0
  378. agno/tools/google_drive.py +270 -0
  379. agno/tools/google_maps.py +253 -0
  380. agno/tools/googlecalendar.py +674 -0
  381. agno/tools/googlesearch.py +98 -0
  382. agno/tools/googlesheets.py +377 -0
  383. agno/tools/hackernews.py +77 -0
  384. agno/tools/jina.py +101 -0
  385. agno/tools/jira.py +170 -0
  386. agno/tools/knowledge.py +218 -0
  387. agno/tools/linear.py +426 -0
  388. agno/tools/linkup.py +58 -0
  389. agno/tools/local_file_system.py +90 -0
  390. agno/tools/lumalab.py +183 -0
  391. agno/tools/mcp/__init__.py +10 -0
  392. agno/tools/mcp/mcp.py +331 -0
  393. agno/tools/mcp/multi_mcp.py +347 -0
  394. agno/tools/mcp/params.py +24 -0
  395. agno/tools/mcp_toolbox.py +284 -0
  396. agno/tools/mem0.py +193 -0
  397. agno/tools/memori.py +339 -0
  398. agno/tools/memory.py +419 -0
  399. agno/tools/mlx_transcribe.py +139 -0
  400. agno/tools/models/__init__.py +0 -0
  401. agno/tools/models/azure_openai.py +190 -0
  402. agno/tools/models/gemini.py +203 -0
  403. agno/tools/models/groq.py +158 -0
  404. agno/tools/models/morph.py +186 -0
  405. agno/tools/models/nebius.py +124 -0
  406. agno/tools/models_labs.py +195 -0
  407. agno/tools/moviepy_video.py +349 -0
  408. agno/tools/neo4j.py +134 -0
  409. agno/tools/newspaper.py +46 -0
  410. agno/tools/newspaper4k.py +93 -0
  411. agno/tools/notion.py +204 -0
  412. agno/tools/openai.py +202 -0
  413. agno/tools/openbb.py +160 -0
  414. agno/tools/opencv.py +321 -0
  415. agno/tools/openweather.py +233 -0
  416. agno/tools/oxylabs.py +385 -0
  417. agno/tools/pandas.py +102 -0
  418. agno/tools/parallel.py +314 -0
  419. agno/tools/postgres.py +257 -0
  420. agno/tools/pubmed.py +188 -0
  421. agno/tools/python.py +205 -0
  422. agno/tools/reasoning.py +283 -0
  423. agno/tools/reddit.py +467 -0
  424. agno/tools/replicate.py +117 -0
  425. agno/tools/resend.py +62 -0
  426. agno/tools/scrapegraph.py +222 -0
  427. agno/tools/searxng.py +152 -0
  428. agno/tools/serpapi.py +116 -0
  429. agno/tools/serper.py +255 -0
  430. agno/tools/shell.py +53 -0
  431. agno/tools/slack.py +136 -0
  432. agno/tools/sleep.py +20 -0
  433. agno/tools/spider.py +116 -0
  434. agno/tools/sql.py +154 -0
  435. agno/tools/streamlit/__init__.py +0 -0
  436. agno/tools/streamlit/components.py +113 -0
  437. agno/tools/tavily.py +254 -0
  438. agno/tools/telegram.py +48 -0
  439. agno/tools/todoist.py +218 -0
  440. agno/tools/tool_registry.py +1 -0
  441. agno/tools/toolkit.py +146 -0
  442. agno/tools/trafilatura.py +388 -0
  443. agno/tools/trello.py +274 -0
  444. agno/tools/twilio.py +186 -0
  445. agno/tools/user_control_flow.py +78 -0
  446. agno/tools/valyu.py +228 -0
  447. agno/tools/visualization.py +467 -0
  448. agno/tools/webbrowser.py +28 -0
  449. agno/tools/webex.py +76 -0
  450. agno/tools/website.py +54 -0
  451. agno/tools/webtools.py +45 -0
  452. agno/tools/whatsapp.py +286 -0
  453. agno/tools/wikipedia.py +63 -0
  454. agno/tools/workflow.py +278 -0
  455. agno/tools/x.py +335 -0
  456. agno/tools/yfinance.py +257 -0
  457. agno/tools/youtube.py +184 -0
  458. agno/tools/zendesk.py +82 -0
  459. agno/tools/zep.py +454 -0
  460. agno/tools/zoom.py +382 -0
  461. agno/utils/__init__.py +0 -0
  462. agno/utils/agent.py +820 -0
  463. agno/utils/audio.py +49 -0
  464. agno/utils/certs.py +27 -0
  465. agno/utils/code_execution.py +11 -0
  466. agno/utils/common.py +132 -0
  467. agno/utils/dttm.py +13 -0
  468. agno/utils/enum.py +22 -0
  469. agno/utils/env.py +11 -0
  470. agno/utils/events.py +696 -0
  471. agno/utils/format_str.py +16 -0
  472. agno/utils/functions.py +166 -0
  473. agno/utils/gemini.py +426 -0
  474. agno/utils/hooks.py +57 -0
  475. agno/utils/http.py +74 -0
  476. agno/utils/json_schema.py +234 -0
  477. agno/utils/knowledge.py +36 -0
  478. agno/utils/location.py +19 -0
  479. agno/utils/log.py +255 -0
  480. agno/utils/mcp.py +214 -0
  481. agno/utils/media.py +352 -0
  482. agno/utils/merge_dict.py +41 -0
  483. agno/utils/message.py +118 -0
  484. agno/utils/models/__init__.py +0 -0
  485. agno/utils/models/ai_foundry.py +43 -0
  486. agno/utils/models/claude.py +358 -0
  487. agno/utils/models/cohere.py +87 -0
  488. agno/utils/models/llama.py +78 -0
  489. agno/utils/models/mistral.py +98 -0
  490. agno/utils/models/openai_responses.py +140 -0
  491. agno/utils/models/schema_utils.py +153 -0
  492. agno/utils/models/watsonx.py +41 -0
  493. agno/utils/openai.py +257 -0
  494. agno/utils/pickle.py +32 -0
  495. agno/utils/pprint.py +178 -0
  496. agno/utils/print_response/__init__.py +0 -0
  497. agno/utils/print_response/agent.py +842 -0
  498. agno/utils/print_response/team.py +1724 -0
  499. agno/utils/print_response/workflow.py +1668 -0
  500. agno/utils/prompts.py +111 -0
  501. agno/utils/reasoning.py +108 -0
  502. agno/utils/response.py +163 -0
  503. agno/utils/response_iterator.py +17 -0
  504. agno/utils/safe_formatter.py +24 -0
  505. agno/utils/serialize.py +32 -0
  506. agno/utils/shell.py +22 -0
  507. agno/utils/streamlit.py +487 -0
  508. agno/utils/string.py +231 -0
  509. agno/utils/team.py +139 -0
  510. agno/utils/timer.py +41 -0
  511. agno/utils/tools.py +102 -0
  512. agno/utils/web.py +23 -0
  513. agno/utils/whatsapp.py +305 -0
  514. agno/utils/yaml_io.py +25 -0
  515. agno/vectordb/__init__.py +3 -0
  516. agno/vectordb/base.py +127 -0
  517. agno/vectordb/cassandra/__init__.py +5 -0
  518. agno/vectordb/cassandra/cassandra.py +501 -0
  519. agno/vectordb/cassandra/extra_param_mixin.py +11 -0
  520. agno/vectordb/cassandra/index.py +13 -0
  521. agno/vectordb/chroma/__init__.py +5 -0
  522. agno/vectordb/chroma/chromadb.py +929 -0
  523. agno/vectordb/clickhouse/__init__.py +9 -0
  524. agno/vectordb/clickhouse/clickhousedb.py +835 -0
  525. agno/vectordb/clickhouse/index.py +9 -0
  526. agno/vectordb/couchbase/__init__.py +3 -0
  527. agno/vectordb/couchbase/couchbase.py +1442 -0
  528. agno/vectordb/distance.py +7 -0
  529. agno/vectordb/lancedb/__init__.py +6 -0
  530. agno/vectordb/lancedb/lance_db.py +995 -0
  531. agno/vectordb/langchaindb/__init__.py +5 -0
  532. agno/vectordb/langchaindb/langchaindb.py +163 -0
  533. agno/vectordb/lightrag/__init__.py +5 -0
  534. agno/vectordb/lightrag/lightrag.py +388 -0
  535. agno/vectordb/llamaindex/__init__.py +3 -0
  536. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  537. agno/vectordb/milvus/__init__.py +4 -0
  538. agno/vectordb/milvus/milvus.py +1182 -0
  539. agno/vectordb/mongodb/__init__.py +9 -0
  540. agno/vectordb/mongodb/mongodb.py +1417 -0
  541. agno/vectordb/pgvector/__init__.py +12 -0
  542. agno/vectordb/pgvector/index.py +23 -0
  543. agno/vectordb/pgvector/pgvector.py +1462 -0
  544. agno/vectordb/pineconedb/__init__.py +5 -0
  545. agno/vectordb/pineconedb/pineconedb.py +747 -0
  546. agno/vectordb/qdrant/__init__.py +5 -0
  547. agno/vectordb/qdrant/qdrant.py +1134 -0
  548. agno/vectordb/redis/__init__.py +9 -0
  549. agno/vectordb/redis/redisdb.py +694 -0
  550. agno/vectordb/search.py +7 -0
  551. agno/vectordb/singlestore/__init__.py +10 -0
  552. agno/vectordb/singlestore/index.py +41 -0
  553. agno/vectordb/singlestore/singlestore.py +763 -0
  554. agno/vectordb/surrealdb/__init__.py +3 -0
  555. agno/vectordb/surrealdb/surrealdb.py +699 -0
  556. agno/vectordb/upstashdb/__init__.py +5 -0
  557. agno/vectordb/upstashdb/upstashdb.py +718 -0
  558. agno/vectordb/weaviate/__init__.py +8 -0
  559. agno/vectordb/weaviate/index.py +15 -0
  560. agno/vectordb/weaviate/weaviate.py +1005 -0
  561. agno/workflow/__init__.py +23 -0
  562. agno/workflow/agent.py +299 -0
  563. agno/workflow/condition.py +738 -0
  564. agno/workflow/loop.py +735 -0
  565. agno/workflow/parallel.py +824 -0
  566. agno/workflow/router.py +702 -0
  567. agno/workflow/step.py +1432 -0
  568. agno/workflow/steps.py +592 -0
  569. agno/workflow/types.py +520 -0
  570. agno/workflow/workflow.py +4321 -0
  571. agno-2.2.13.dist-info/METADATA +614 -0
  572. agno-2.2.13.dist-info/RECORD +575 -0
  573. agno-2.2.13.dist-info/WHEEL +5 -0
  574. agno-2.2.13.dist-info/licenses/LICENSE +201 -0
  575. agno-2.2.13.dist-info/top_level.txt +1 -0
agno/utils/string.py ADDED
@@ -0,0 +1,231 @@
1
+ import hashlib
2
+ import json
3
+ import re
4
+ import uuid
5
+ from typing import Optional, Type
6
+ from uuid import uuid4
7
+
8
+ from pydantic import BaseModel, ValidationError
9
+
10
+ from agno.utils.log import logger
11
+
12
+
13
+ def is_valid_uuid(uuid_str: str) -> bool:
14
+ """
15
+ Check if a string is a valid UUID
16
+
17
+ Args:
18
+ uuid_str: String to check
19
+
20
+ Returns:
21
+ bool: True if string is a valid UUID, False otherwise
22
+ """
23
+ from uuid import UUID
24
+
25
+ try:
26
+ UUID(str(uuid_str))
27
+ return True
28
+ except (ValueError, AttributeError, TypeError):
29
+ return False
30
+
31
+
32
+ def url_safe_string(input_string):
33
+ # Replace spaces with dashes
34
+ safe_string = input_string.replace(" ", "-")
35
+
36
+ # Convert camelCase to kebab-case
37
+ safe_string = re.sub(r"([a-z0-9])([A-Z])", r"\1-\2", safe_string).lower()
38
+
39
+ # Convert snake_case to kebab-case
40
+ safe_string = safe_string.replace("_", "-")
41
+
42
+ # Remove special characters, keeping alphanumeric, dashes, and dots
43
+ safe_string = re.sub(r"[^\w\-.]", "", safe_string)
44
+
45
+ # Ensure no consecutive dashes
46
+ safe_string = re.sub(r"-+", "-", safe_string)
47
+
48
+ return safe_string
49
+
50
+
51
+ def hash_string_sha256(input_string):
52
+ # Encode the input string to bytes
53
+ encoded_string = input_string.encode("utf-8")
54
+
55
+ # Create a SHA-256 hash object
56
+ sha256_hash = hashlib.sha256()
57
+
58
+ # Update the hash object with the encoded string
59
+ sha256_hash.update(encoded_string)
60
+
61
+ # Get the hexadecimal digest of the hash
62
+ hex_digest = sha256_hash.hexdigest()
63
+
64
+ return hex_digest
65
+
66
+
67
+ def _extract_json_objects(text: str) -> list[str]:
68
+ objs: list[str] = []
69
+ brace_depth = 0
70
+ start_idx: Optional[int] = None
71
+ for idx, ch in enumerate(text):
72
+ if ch == "{" and brace_depth == 0:
73
+ start_idx = idx
74
+ if ch == "{":
75
+ brace_depth += 1
76
+ elif ch == "}":
77
+ brace_depth -= 1
78
+ if brace_depth == 0 and start_idx is not None:
79
+ objs.append(text[start_idx : idx + 1])
80
+ start_idx = None
81
+ return objs
82
+
83
+
84
+ def _clean_json_content(content: str) -> str:
85
+ """Clean and prepare JSON content for parsing."""
86
+ # Handle code blocks
87
+ if "```json" in content:
88
+ content = content.split("```json")[-1].strip()
89
+ parts = content.split("```")
90
+ parts.pop(-1)
91
+ content = "".join(parts)
92
+ elif "```" in content:
93
+ content = content.split("```")[1].strip()
94
+
95
+ # Replace markdown formatting like *"name"* or `"name"` with "name"
96
+ content = re.sub(r'[*`#]?"([A-Za-z0-9_]+)"[*`#]?', r'"\1"', content)
97
+
98
+ # Handle newlines and control characters
99
+ content = content.replace("\n", " ").replace("\r", "")
100
+ content = re.sub(r"[\x00-\x1F\x7F]", "", content)
101
+
102
+ # Escape quotes only in values, not keys
103
+ def escape_quotes_in_values(match):
104
+ key = match.group(1)
105
+ value = match.group(2)
106
+
107
+ if '\\"' in value:
108
+ unescaped_value = value.replace('\\"', '"')
109
+ escaped_value = unescaped_value.replace('"', '\\"')
110
+ else:
111
+ escaped_value = value.replace('"', '\\"')
112
+
113
+ return f'"{key}": "{escaped_value}'
114
+
115
+ # Find and escape quotes in field values
116
+ content = re.sub(r'"(?P<key>[^"]+)"\s*:\s*"(?P<value>.*?)(?="\s*(?:,|\}))', escape_quotes_in_values, content)
117
+
118
+ return content
119
+
120
+
121
+ def _parse_individual_json(content: str, output_schema: Type[BaseModel]) -> Optional[BaseModel]:
122
+ """Parse individual JSON objects from content and merge them based on response model fields."""
123
+ candidate_jsons = _extract_json_objects(content)
124
+ merged_data: dict = {}
125
+
126
+ # Get the expected fields from the response model
127
+ model_fields = output_schema.model_fields if hasattr(output_schema, "model_fields") else {}
128
+
129
+ for candidate in candidate_jsons:
130
+ try:
131
+ candidate_obj = json.loads(candidate)
132
+ except json.JSONDecodeError:
133
+ continue
134
+
135
+ if isinstance(candidate_obj, dict):
136
+ # Merge data based on model fields
137
+ for field_name, field_info in model_fields.items():
138
+ if field_name in candidate_obj:
139
+ field_value = candidate_obj[field_name]
140
+ # If field is a list, extend it; otherwise, use the latest value
141
+ if isinstance(field_value, list):
142
+ if field_name not in merged_data:
143
+ merged_data[field_name] = []
144
+ merged_data[field_name].extend(field_value)
145
+ else:
146
+ merged_data[field_name] = field_value
147
+
148
+ if not merged_data:
149
+ return None
150
+
151
+ try:
152
+ return output_schema.model_validate(merged_data)
153
+ except ValidationError as e:
154
+ logger.warning("Validation failed on merged data: %s", e)
155
+ return None
156
+
157
+
158
+ def parse_response_model_str(content: str, output_schema: Type[BaseModel]) -> Optional[BaseModel]:
159
+ structured_output = None
160
+
161
+ # Extract thinking content first to prevent <think> tags from corrupting JSON
162
+ from agno.utils.reasoning import extract_thinking_content
163
+
164
+ # handle thinking content b/w <think> tags
165
+ if "</think>" in content:
166
+ reasoning_content, output_content = extract_thinking_content(content)
167
+ if reasoning_content:
168
+ content = output_content
169
+
170
+ # Clean content first to simplify all parsing attempts
171
+ cleaned_content = _clean_json_content(content)
172
+
173
+ try:
174
+ # First attempt: direct JSON validation on cleaned content
175
+ structured_output = output_schema.model_validate_json(cleaned_content)
176
+ except (ValidationError, json.JSONDecodeError):
177
+ try:
178
+ # Second attempt: Parse as Python dict
179
+ data = json.loads(cleaned_content)
180
+ structured_output = output_schema.model_validate(data)
181
+ except (ValidationError, json.JSONDecodeError) as e:
182
+ logger.warning(f"Failed to parse cleaned JSON: {e}")
183
+
184
+ # Third attempt: Extract individual JSON objects
185
+ candidate_jsons = _extract_json_objects(cleaned_content)
186
+
187
+ if len(candidate_jsons) == 1:
188
+ # Single JSON object - try to parse it directly
189
+ try:
190
+ data = json.loads(candidate_jsons[0])
191
+ structured_output = output_schema.model_validate(data)
192
+ except (ValidationError, json.JSONDecodeError):
193
+ pass
194
+
195
+ if structured_output is None:
196
+ # Final attempt: Handle concatenated JSON objects with field merging
197
+ structured_output = _parse_individual_json(cleaned_content, output_schema)
198
+ if structured_output is None:
199
+ logger.warning("All parsing attempts failed.")
200
+
201
+ return structured_output
202
+
203
+
204
+ def generate_id(seed: Optional[str] = None) -> str:
205
+ """
206
+ Generate a deterministic UUID5 based on a seed string.
207
+ If no seed is provided, generate a random UUID4.
208
+
209
+ Args:
210
+ seed (str): The seed string to generate the UUID from.
211
+
212
+ Returns:
213
+ str: A deterministic UUID5 string.
214
+ """
215
+ if seed is None:
216
+ return str(uuid4())
217
+ return str(uuid.uuid5(uuid.NAMESPACE_DNS, seed))
218
+
219
+
220
+ def generate_id_from_name(name: Optional[str] = None) -> str:
221
+ """
222
+ Generate a deterministic ID from a name string.
223
+ If no name is provided, generate a random UUID4.
224
+
225
+ Args:
226
+ name (str): The name string to generate the ID from.
227
+ """
228
+ if name:
229
+ return name.lower().replace(" ", "-").replace("_", "-")
230
+ else:
231
+ return str(uuid4())
agno/utils/team.py ADDED
@@ -0,0 +1,139 @@
1
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
2
+
3
+ from agno.agent import Agent
4
+ from agno.media import Audio, File, Image, Video
5
+ from agno.run.agent import RunOutput
6
+ from agno.run.team import TeamRunOutput
7
+ from agno.utils.log import log_debug
8
+ from agno.utils.string import is_valid_uuid, url_safe_string
9
+
10
+ if TYPE_CHECKING:
11
+ from agno.team.team import Team
12
+
13
+
14
+ def format_member_agent_task(
15
+ task_description: str,
16
+ team_member_interactions_str: Optional[str] = None,
17
+ team_history_str: Optional[str] = None,
18
+ ) -> str:
19
+ member_task_str = ""
20
+
21
+ if team_member_interactions_str:
22
+ member_task_str += f"{team_member_interactions_str}\n\n"
23
+
24
+ if team_history_str:
25
+ member_task_str += f"{team_history_str}\n\n"
26
+
27
+ member_task_str += f"{task_description}"
28
+
29
+ return member_task_str
30
+
31
+
32
+ def get_member_id(member: Union[Agent, "Team"]) -> str:
33
+ """
34
+ Get the ID of a member
35
+
36
+ If the member has an agent_id or team_id, use that if it is not a valid UUID.
37
+ Then if the member has a name, convert that to a URL safe string.
38
+ Then if the member has the default UUID ID, use that.
39
+ Otherwise, return None.
40
+ """
41
+ from agno.team.team import Team
42
+
43
+ if isinstance(member, Agent) and member.id is not None and (not is_valid_uuid(member.id)):
44
+ url_safe_member_id = url_safe_string(member.id)
45
+ elif isinstance(member, Team) and member.id is not None and (not is_valid_uuid(member.id)):
46
+ url_safe_member_id = url_safe_string(member.id)
47
+ elif member.name is not None:
48
+ url_safe_member_id = url_safe_string(member.name)
49
+ elif isinstance(member, Agent) and member.id is not None:
50
+ url_safe_member_id = member.id
51
+ elif isinstance(member, Team) and member.id is not None:
52
+ url_safe_member_id = member.id
53
+ else:
54
+ url_safe_member_id = None
55
+ return url_safe_member_id
56
+
57
+
58
+ def add_interaction_to_team_run_context(
59
+ team_run_context: Dict[str, Any],
60
+ member_name: str,
61
+ task: str,
62
+ run_response: Union[RunOutput, TeamRunOutput],
63
+ ) -> None:
64
+ if "member_responses" not in team_run_context:
65
+ team_run_context["member_responses"] = []
66
+ team_run_context["member_responses"].append(
67
+ {
68
+ "member_name": member_name,
69
+ "task": task,
70
+ "run_response": run_response,
71
+ }
72
+ )
73
+ log_debug(f"Updated team run context with member name: {member_name}")
74
+
75
+
76
+ def get_team_member_interactions_str(team_run_context: Dict[str, Any]) -> str:
77
+ if not team_run_context:
78
+ return ""
79
+ team_member_interactions_str = ""
80
+ if "member_responses" in team_run_context:
81
+ team_member_interactions_str += "<member_interaction_context>\nSee below interactions wit other team members.\n"
82
+
83
+ for interaction in team_run_context["member_responses"]:
84
+ response_dict = interaction["run_response"].to_dict()
85
+ response_content = (
86
+ response_dict.get("content")
87
+ or ",".join([tool.get("content", "") for tool in response_dict.get("tools", [])])
88
+ or ""
89
+ )
90
+ team_member_interactions_str += f"Member: {interaction['member_name']}\n"
91
+ team_member_interactions_str += f"Task: {interaction['task']}\n"
92
+ team_member_interactions_str += f"Response: {response_content}\n"
93
+ team_member_interactions_str += "\n"
94
+ team_member_interactions_str += "</member_interaction_context>\n"
95
+ return team_member_interactions_str
96
+
97
+
98
+ def get_team_run_context_images(team_run_context: Dict[str, Any]) -> List[Image]:
99
+ if not team_run_context:
100
+ return []
101
+ images = []
102
+ if "member_responses" in team_run_context:
103
+ for interaction in team_run_context["member_responses"]:
104
+ if interaction["run_response"].images:
105
+ images.extend(interaction["run_response"].images)
106
+ return images
107
+
108
+
109
+ def get_team_run_context_videos(team_run_context: Dict[str, Any]) -> List[Video]:
110
+ if not team_run_context:
111
+ return []
112
+ videos = []
113
+ if "member_responses" in team_run_context:
114
+ for interaction in team_run_context["member_responses"]:
115
+ if interaction["run_response"].videos:
116
+ videos.extend(interaction["run_response"].videos)
117
+ return videos
118
+
119
+
120
+ def get_team_run_context_audio(team_run_context: Dict[str, Any]) -> List[Audio]:
121
+ if not team_run_context:
122
+ return []
123
+ audio = []
124
+ if "member_responses" in team_run_context:
125
+ for interaction in team_run_context["member_responses"]:
126
+ if interaction["run_response"].audio:
127
+ audio.extend(interaction["run_response"].audio)
128
+ return audio
129
+
130
+
131
+ def get_team_run_context_files(team_run_context: Dict[str, Any]) -> List[File]:
132
+ if not team_run_context:
133
+ return []
134
+ files = []
135
+ if "member_responses" in team_run_context:
136
+ for interaction in team_run_context["member_responses"]:
137
+ if interaction["run_response"].files:
138
+ files.extend(interaction["run_response"].files)
139
+ return files
agno/utils/timer.py ADDED
@@ -0,0 +1,41 @@
1
+ from time import perf_counter
2
+ from typing import Optional
3
+
4
+
5
+ class Timer:
6
+ """Timer class for timing code execution"""
7
+
8
+ def __init__(self):
9
+ self.start_time: Optional[float] = None
10
+ self.end_time: Optional[float] = None
11
+ self.elapsed_time: Optional[float] = None
12
+
13
+ @property
14
+ def elapsed(self) -> float:
15
+ return self.elapsed_time or (perf_counter() - self.start_time) if self.start_time else 0.0
16
+
17
+ def start(self) -> float:
18
+ self.start_time = perf_counter()
19
+ return self.start_time
20
+
21
+ def stop(self) -> float:
22
+ self.end_time = perf_counter()
23
+ if self.start_time is not None:
24
+ self.elapsed_time = self.end_time - self.start_time
25
+ return self.end_time
26
+
27
+ def __enter__(self) -> "Timer":
28
+ self.start_time = perf_counter()
29
+ return self
30
+
31
+ def __exit__(self, *args) -> None:
32
+ self.end_time = perf_counter()
33
+ if self.start_time is not None:
34
+ self.elapsed_time = self.end_time - self.start_time
35
+
36
+ def to_dict(self):
37
+ return {
38
+ "start_time": str(self.start_time) if self.start_time is not None else None,
39
+ "end_time": str(self.end_time) if self.end_time is not None else None,
40
+ "elapsed": self.elapsed,
41
+ }
agno/utils/tools.py ADDED
@@ -0,0 +1,102 @@
1
+ from typing import Any, Dict, Optional
2
+
3
+ from agno.models.response import ToolExecution
4
+ from agno.tools.function import Function, FunctionCall
5
+ from agno.utils.functions import get_function_call
6
+
7
+
8
+ def get_function_call_for_tool_call(
9
+ tool_call: Dict[str, Any], functions: Optional[Dict[str, Function]] = None
10
+ ) -> Optional[FunctionCall]:
11
+ if tool_call.get("type") == "function":
12
+ _tool_call_id = tool_call.get("id")
13
+ _tool_call_function = tool_call.get("function")
14
+ if _tool_call_function is not None:
15
+ _tool_call_function_name = _tool_call_function.get("name")
16
+ _tool_call_function_arguments_str = _tool_call_function.get("arguments") or "{}"
17
+ if _tool_call_function_name is not None:
18
+ return get_function_call(
19
+ name=_tool_call_function_name,
20
+ arguments=_tool_call_function_arguments_str,
21
+ call_id=_tool_call_id,
22
+ functions=functions,
23
+ )
24
+ return None
25
+
26
+
27
+ def extract_tool_call_from_string(text: str, start_tag: str = "<tool_call>", end_tag: str = "</tool_call>"):
28
+ start_index = text.find(start_tag) + len(start_tag)
29
+ end_index = text.find(end_tag)
30
+
31
+ # Extracting the content between the tags
32
+ return text[start_index:end_index].strip()
33
+
34
+
35
+ def remove_tool_calls_from_string(text: str, start_tag: str = "<tool_call>", end_tag: str = "</tool_call>"):
36
+ """Remove multiple tool calls from a string."""
37
+ while start_tag in text and end_tag in text:
38
+ start_index = text.find(start_tag)
39
+ end_index = text.find(end_tag) + len(end_tag)
40
+ text = text[:start_index] + text[end_index:]
41
+ return text
42
+
43
+
44
+ def extract_tool_from_xml(xml_str):
45
+ # Find tool_name
46
+ tool_name_start = xml_str.find("<tool_name>") + len("<tool_name>")
47
+ tool_name_end = xml_str.find("</tool_name>")
48
+ tool_name = xml_str[tool_name_start:tool_name_end].strip()
49
+
50
+ # Find and process parameters block
51
+ params_start = xml_str.find("<parameters>") + len("<parameters>")
52
+ params_end = xml_str.find("</parameters>")
53
+ parameters_block = xml_str[params_start:params_end].strip()
54
+
55
+ # Extract individual parameters
56
+ arguments = {}
57
+ while parameters_block:
58
+ # Find the next tag and its closing
59
+ tag_start = parameters_block.find("<") + 1
60
+ tag_end = parameters_block.find(">")
61
+ tag_name = parameters_block[tag_start:tag_end]
62
+
63
+ # Find the tag's closing counterpart
64
+ value_start = tag_end + 1
65
+ value_end = parameters_block.find(f"</{tag_name}>")
66
+ value = parameters_block[value_start:value_end].strip()
67
+
68
+ # Add to arguments
69
+ arguments[tag_name] = value
70
+
71
+ # Move past this tag
72
+ parameters_block = parameters_block[value_end + len(f"</{tag_name}>") :].strip()
73
+
74
+ return {"tool_name": tool_name, "parameters": arguments}
75
+
76
+
77
+ def remove_function_calls_from_string(
78
+ text: str, start_tag: str = "<function_calls>", end_tag: str = "</function_calls>"
79
+ ):
80
+ """Remove multiple function calls from a string."""
81
+ while start_tag in text and end_tag in text:
82
+ start_index = text.find(start_tag)
83
+ end_index = text.find(end_tag) + len(end_tag)
84
+ text = text[:start_index] + text[end_index:]
85
+ return text
86
+
87
+
88
+ def get_function_call_for_tool_execution(
89
+ tool_execution: ToolExecution,
90
+ functions: Optional[Dict[str, Function]] = None,
91
+ ) -> Optional[FunctionCall]:
92
+ import json
93
+
94
+ _tool_call_id = tool_execution.tool_call_id
95
+ _tool_call_function_name = tool_execution.tool_name or ""
96
+ _tool_call_function_arguments_str = json.dumps(tool_execution.tool_args)
97
+ return get_function_call(
98
+ name=_tool_call_function_name,
99
+ arguments=_tool_call_function_arguments_str,
100
+ call_id=_tool_call_id,
101
+ functions=functions,
102
+ )
agno/utils/web.py ADDED
@@ -0,0 +1,23 @@
1
+ import webbrowser
2
+ from pathlib import Path
3
+
4
+ from agno.utils.log import logger
5
+
6
+
7
+ def open_html_file(file_path: Path):
8
+ """
9
+ Opens the specified HTML file in the default web browser.
10
+ :param file_path: Path to the HTML file.
11
+ """
12
+ # Resolve the absolute path
13
+ absolute_path = file_path.resolve()
14
+
15
+ if not absolute_path.is_file():
16
+ logger.error(f"The file '{absolute_path}' does not exist.")
17
+ raise FileNotFoundError(f"The file '{absolute_path}' does not exist.")
18
+
19
+ # Convert the file path to a file URI
20
+ file_url = absolute_path.as_uri()
21
+
22
+ # Open the file in the default web browser
23
+ webbrowser.open(file_url)