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
@@ -0,0 +1,503 @@
1
+ import json
2
+ from dataclasses import dataclass
3
+ from os import getenv
4
+ from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Type, Union
5
+
6
+ from pydantic import BaseModel
7
+
8
+ from agno.models.base import Model
9
+ from agno.models.message import Message
10
+ from agno.models.metrics import Metrics
11
+ from agno.models.response import ModelResponse
12
+ from agno.run.agent import RunOutput
13
+ from agno.tools.function import Function
14
+ from agno.utils.log import log_debug, log_error, log_warning
15
+ from agno.utils.openai import _format_file_for_message, audio_to_message, images_to_message
16
+ from agno.utils.tokens import count_schema_tokens
17
+
18
+ try:
19
+ import litellm
20
+ from litellm import validate_environment
21
+ except ImportError:
22
+ raise ImportError("`litellm` not installed. Please install it via `pip install litellm`")
23
+
24
+
25
+ @dataclass
26
+ class LiteLLM(Model):
27
+ """
28
+ A class for interacting with LiteLLM Python SDK.
29
+
30
+ LiteLLM allows you to use a unified interface for various LLM providers.
31
+ For more information, see: https://docs.litellm.ai/docs/
32
+ """
33
+
34
+ id: str = "gpt-4o"
35
+ name: str = "LiteLLM"
36
+ provider: str = "LiteLLM"
37
+
38
+ api_key: Optional[str] = None
39
+ api_base: Optional[str] = None
40
+ max_tokens: Optional[int] = None
41
+ temperature: float = 0.7
42
+ top_p: float = 1.0
43
+ metadata: Optional[Dict[str, Any]] = None
44
+ extra_headers: Optional[Dict[str, Any]] = None
45
+ extra_query: Optional[Dict[str, Any]] = None
46
+ extra_body: Optional[Dict[str, Any]] = None
47
+ request_params: Optional[Dict[str, Any]] = None
48
+
49
+ client: Optional[Any] = None
50
+
51
+ def __post_init__(self):
52
+ """Initialize the model after the dataclass initialization."""
53
+ super().__post_init__()
54
+
55
+ # Set up API key from environment variable if not already set
56
+ if not self.client and not self.api_key:
57
+ self.api_key = getenv("LITELLM_API_KEY")
58
+ if not self.api_key:
59
+ # Check for other present valid keys, e.g. OPENAI_API_KEY if self.id is an OpenAI model
60
+ env_validation = validate_environment(model=self.id, api_base=self.api_base)
61
+ if not env_validation.get("keys_in_environment"):
62
+ log_error(
63
+ "LITELLM_API_KEY not set. Please set the LITELLM_API_KEY or other valid environment variables."
64
+ )
65
+
66
+ def get_client(self) -> Any:
67
+ """
68
+ Returns a LiteLLM client.
69
+
70
+ Returns:
71
+ Any: An instance of the LiteLLM client.
72
+ """
73
+ if self.client is not None:
74
+ return self.client
75
+
76
+ self.client = litellm
77
+ return self.client
78
+
79
+ def _format_messages(self, messages: List[Message], compress_tool_results: bool = False) -> List[Dict[str, Any]]:
80
+ """Format messages for LiteLLM API."""
81
+ formatted_messages = []
82
+ for m in messages:
83
+ # Use compressed content for tool messages if compression is active
84
+ if m.role == "tool":
85
+ content = m.get_content(use_compressed_content=compress_tool_results)
86
+ else:
87
+ content = m.content if m.content is not None else ""
88
+
89
+ msg = {"role": m.role, "content": content}
90
+
91
+ # Handle media
92
+ if (m.images is not None and len(m.images) > 0) or (m.audio is not None and len(m.audio) > 0):
93
+ if isinstance(m.content, str):
94
+ content_list = [{"type": "text", "text": m.content}]
95
+ if m.images is not None:
96
+ content_list.extend(images_to_message(images=m.images))
97
+ if m.audio is not None:
98
+ content_list.extend(audio_to_message(audio=m.audio))
99
+ msg["content"] = content_list
100
+
101
+ if m.videos is not None and len(m.videos) > 0:
102
+ log_warning("Video input is currently unsupported by LLM providers.")
103
+
104
+ # Handle files
105
+ if m.files is not None:
106
+ if isinstance(msg["content"], str):
107
+ content_list = [{"type": "text", "text": msg["content"]}]
108
+ else:
109
+ content_list = msg["content"] if isinstance(msg["content"], list) else []
110
+ for file in m.files:
111
+ file_part = _format_file_for_message(file)
112
+ if file_part:
113
+ content_list.append(file_part)
114
+ msg["content"] = content_list
115
+
116
+ # Handle tool calls in assistant messages
117
+ if m.role == "assistant" and m.tool_calls:
118
+ msg["tool_calls"] = [
119
+ {
120
+ "id": tc.get("id", f"call_{i}"),
121
+ "type": "function",
122
+ "function": {"name": tc["function"]["name"], "arguments": tc["function"]["arguments"]},
123
+ }
124
+ for i, tc in enumerate(m.tool_calls)
125
+ ]
126
+
127
+ # Handle tool responses
128
+ if m.role == "tool":
129
+ msg["tool_call_id"] = m.tool_call_id or ""
130
+ msg["name"] = m.name or ""
131
+
132
+ if m.audio is not None and len(m.audio) > 0:
133
+ log_warning("Audio input is currently unsupported.")
134
+
135
+ if m.images is not None and len(m.images) > 0:
136
+ log_warning("Image input is currently unsupported.")
137
+
138
+ if m.videos is not None and len(m.videos) > 0:
139
+ log_warning("Video input is currently unsupported.")
140
+ formatted_messages.append(msg)
141
+
142
+ return formatted_messages
143
+
144
+ def get_request_params(self, tools: Optional[List[Dict[str, Any]]] = None) -> Dict[str, Any]:
145
+ """
146
+ Returns keyword arguments for API requests.
147
+
148
+ Returns:
149
+ Dict[str, Any]: The API kwargs for the model.
150
+ """
151
+ base_params: Dict[str, Any] = {
152
+ "model": self.id,
153
+ "temperature": self.temperature,
154
+ "top_p": self.top_p,
155
+ }
156
+
157
+ if self.max_tokens:
158
+ base_params["max_tokens"] = self.max_tokens
159
+ if self.api_key:
160
+ base_params["api_key"] = self.api_key
161
+ if self.api_base:
162
+ base_params["api_base"] = self.api_base
163
+ if self.extra_headers:
164
+ base_params["extra_headers"] = self.extra_headers
165
+ if self.extra_query:
166
+ base_params["extra_query"] = self.extra_query
167
+ if tools:
168
+ base_params["tools"] = tools
169
+ base_params["tool_choice"] = "auto"
170
+
171
+ # Handle metadata via extra_body as per LiteLLM docs
172
+ if self.metadata:
173
+ if self.extra_body:
174
+ base_params["extra_body"] = {**self.extra_body, "metadata": self.metadata}
175
+ else:
176
+ base_params["extra_body"] = {"metadata": self.metadata}
177
+ elif self.extra_body:
178
+ base_params["extra_body"] = self.extra_body
179
+
180
+ # Add additional request params if provided
181
+ request_params: Dict[str, Any] = {k: v for k, v in base_params.items() if v is not None}
182
+ if self.request_params:
183
+ request_params.update(self.request_params)
184
+
185
+ if request_params:
186
+ log_debug(f"Calling {self.provider} with request parameters: {request_params}", log_level=2)
187
+ return request_params
188
+
189
+ def invoke(
190
+ self,
191
+ messages: List[Message],
192
+ assistant_message: Message,
193
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
194
+ tools: Optional[List[Dict[str, Any]]] = None,
195
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
196
+ run_response: Optional[RunOutput] = None,
197
+ compress_tool_results: bool = False,
198
+ ) -> ModelResponse:
199
+ """Sends a chat completion request to the LiteLLM API."""
200
+ completion_kwargs = self.get_request_params(tools=tools)
201
+ completion_kwargs["messages"] = self._format_messages(messages, compress_tool_results)
202
+
203
+ if run_response and run_response.metrics:
204
+ run_response.metrics.set_time_to_first_token()
205
+
206
+ assistant_message.metrics.start_timer()
207
+
208
+ provider_response = self.get_client().completion(**completion_kwargs)
209
+
210
+ assistant_message.metrics.stop_timer()
211
+
212
+ model_response = self._parse_provider_response(provider_response, response_format=response_format)
213
+ return model_response
214
+
215
+ def invoke_stream(
216
+ self,
217
+ messages: List[Message],
218
+ assistant_message: Message,
219
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
220
+ tools: Optional[List[Dict[str, Any]]] = None,
221
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
222
+ run_response: Optional[RunOutput] = None,
223
+ compress_tool_results: bool = False,
224
+ ) -> Iterator[ModelResponse]:
225
+ """Sends a streaming chat completion request to the LiteLLM API."""
226
+ completion_kwargs = self.get_request_params(tools=tools)
227
+ completion_kwargs["messages"] = self._format_messages(messages, compress_tool_results)
228
+ completion_kwargs["stream"] = True
229
+ completion_kwargs["stream_options"] = {"include_usage": True}
230
+
231
+ if run_response and run_response.metrics:
232
+ run_response.metrics.set_time_to_first_token()
233
+
234
+ assistant_message.metrics.start_timer()
235
+
236
+ for chunk in self.get_client().completion(**completion_kwargs):
237
+ yield self._parse_provider_response_delta(chunk)
238
+
239
+ assistant_message.metrics.stop_timer()
240
+
241
+ async def ainvoke(
242
+ self,
243
+ messages: List[Message],
244
+ assistant_message: Message,
245
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
246
+ tools: Optional[List[Dict[str, Any]]] = None,
247
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
248
+ run_response: Optional[RunOutput] = None,
249
+ compress_tool_results: bool = False,
250
+ ) -> ModelResponse:
251
+ """Sends an asynchronous chat completion request to the LiteLLM API."""
252
+ completion_kwargs = self.get_request_params(tools=tools)
253
+ completion_kwargs["messages"] = self._format_messages(messages, compress_tool_results)
254
+
255
+ if run_response and run_response.metrics:
256
+ run_response.metrics.set_time_to_first_token()
257
+
258
+ assistant_message.metrics.start_timer()
259
+
260
+ provider_response = await self.get_client().acompletion(**completion_kwargs)
261
+
262
+ assistant_message.metrics.stop_timer()
263
+
264
+ model_response = self._parse_provider_response(provider_response, response_format=response_format)
265
+ return model_response
266
+
267
+ async def ainvoke_stream(
268
+ self,
269
+ messages: List[Message],
270
+ assistant_message: Message,
271
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
272
+ tools: Optional[List[Dict[str, Any]]] = None,
273
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
274
+ run_response: Optional[RunOutput] = None,
275
+ compress_tool_results: bool = False,
276
+ ) -> AsyncIterator[ModelResponse]:
277
+ """Sends an asynchronous streaming chat request to the LiteLLM API."""
278
+ completion_kwargs = self.get_request_params(tools=tools)
279
+ completion_kwargs["messages"] = self._format_messages(messages, compress_tool_results)
280
+ completion_kwargs["stream"] = True
281
+ completion_kwargs["stream_options"] = {"include_usage": True}
282
+
283
+ if run_response and run_response.metrics:
284
+ run_response.metrics.set_time_to_first_token()
285
+
286
+ assistant_message.metrics.start_timer()
287
+
288
+ try:
289
+ # litellm.acompletion returns a coroutine that resolves to an async iterator
290
+ # We need to await it first to get the actual async iterator
291
+ async_stream = await self.get_client().acompletion(**completion_kwargs)
292
+ async for chunk in async_stream:
293
+ yield self._parse_provider_response_delta(chunk)
294
+
295
+ assistant_message.metrics.stop_timer()
296
+
297
+ except Exception as e:
298
+ log_error(f"Error in streaming response: {e}")
299
+ raise
300
+
301
+ def _parse_provider_response(self, response: Any, **kwargs) -> ModelResponse:
302
+ """Parse the provider response."""
303
+ model_response = ModelResponse()
304
+
305
+ response_message = response.choices[0].message
306
+
307
+ if response_message.content is not None:
308
+ model_response.content = response_message.content
309
+
310
+ if hasattr(response_message, "tool_calls") and response_message.tool_calls:
311
+ model_response.tool_calls = []
312
+ for tool_call in response_message.tool_calls:
313
+ model_response.tool_calls.append(
314
+ {
315
+ "id": tool_call.id,
316
+ "type": "function",
317
+ "function": {"name": tool_call.function.name, "arguments": tool_call.function.arguments},
318
+ }
319
+ )
320
+
321
+ if response.usage is not None:
322
+ model_response.response_usage = self._get_metrics(response.usage)
323
+
324
+ return model_response
325
+
326
+ def _parse_provider_response_delta(self, response_delta: Any) -> ModelResponse:
327
+ """Parse the provider response delta for streaming responses."""
328
+ model_response = ModelResponse()
329
+
330
+ if hasattr(response_delta, "choices") and len(response_delta.choices) > 0:
331
+ choice_delta = response_delta.choices[0].delta
332
+
333
+ if choice_delta:
334
+ if hasattr(choice_delta, "content") and choice_delta.content is not None:
335
+ model_response.content = choice_delta.content
336
+
337
+ if hasattr(choice_delta, "tool_calls") and choice_delta.tool_calls:
338
+ processed_tool_calls = []
339
+ for tool_call in choice_delta.tool_calls:
340
+ # Get the actual index from the tool call, defaulting to 0 if not available
341
+ actual_index = getattr(tool_call, "index", 0) if hasattr(tool_call, "index") else 0
342
+
343
+ # Create a basic structure with the correct index
344
+ tool_call_dict = {"index": actual_index, "type": "function"}
345
+
346
+ # Extract ID if available
347
+ if hasattr(tool_call, "id") and tool_call.id is not None:
348
+ tool_call_dict["id"] = tool_call.id
349
+
350
+ # Extract function data
351
+ function_data = {}
352
+ if hasattr(tool_call, "function"):
353
+ if hasattr(tool_call.function, "name") and tool_call.function.name is not None:
354
+ function_data["name"] = tool_call.function.name
355
+ if hasattr(tool_call.function, "arguments") and tool_call.function.arguments is not None:
356
+ function_data["arguments"] = tool_call.function.arguments
357
+
358
+ tool_call_dict["function"] = function_data
359
+ processed_tool_calls.append(tool_call_dict)
360
+
361
+ model_response.tool_calls = processed_tool_calls
362
+
363
+ # Add usage metrics if present in streaming response
364
+ if hasattr(response_delta, "usage") and response_delta.usage is not None:
365
+ model_response.response_usage = self._get_metrics(response_delta.usage)
366
+
367
+ return model_response
368
+
369
+ @staticmethod
370
+ def parse_tool_calls(tool_calls_data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
371
+ """
372
+ Build tool calls from streamed tool call data.
373
+
374
+ Args:
375
+ tool_calls_data (List[Dict[str, Any]]): The tool call data to build from.
376
+
377
+ Returns:
378
+ List[Dict[str, Any]]: The built tool calls.
379
+ """
380
+ # Early return for empty list
381
+ if not tool_calls_data:
382
+ return []
383
+
384
+ # Group tool calls by index
385
+ tool_calls_by_index: Dict[int, Dict[str, Any]] = {}
386
+
387
+ for tc in tool_calls_data:
388
+ # Get index (default to 0)
389
+ index = tc.get("index", 0)
390
+ if not isinstance(index, int):
391
+ index = 0
392
+
393
+ # Initialize if first time seeing this index
394
+ if index not in tool_calls_by_index:
395
+ tool_calls_by_index[index] = {"id": None, "type": "function", "function": {"name": "", "arguments": ""}}
396
+
397
+ # Update with new information
398
+ if tc.get("id") is not None:
399
+ tool_calls_by_index[index]["id"] = tc["id"]
400
+
401
+ if tc.get("type") is not None:
402
+ tool_calls_by_index[index]["type"] = tc["type"]
403
+
404
+ # Update function information
405
+ function_data = tc.get("function", {})
406
+ if not isinstance(function_data, dict):
407
+ function_data = {}
408
+
409
+ # Update function name if provided
410
+ if function_data.get("name") is not None:
411
+ name = function_data.get("name", "")
412
+ if isinstance(tool_calls_by_index[index]["function"], dict):
413
+ # type: ignore
414
+ tool_calls_by_index[index]["function"]["name"] = name
415
+
416
+ # Update function arguments if provided
417
+ if function_data.get("arguments") is not None:
418
+ args = function_data.get("arguments", "")
419
+ if isinstance(tool_calls_by_index[index]["function"], dict):
420
+ current_args = tool_calls_by_index[index]["function"].get("arguments", "") # type: ignore
421
+ if isinstance(current_args, str) and isinstance(args, str):
422
+ # type: ignore
423
+ tool_calls_by_index[index]["function"]["arguments"] = current_args + args
424
+
425
+ # Process arguments - Ensure they're valid JSON for the Message.log() method
426
+ result = []
427
+ for tc in tool_calls_by_index.values():
428
+ # Make a safe copy to avoid modifying the original
429
+ tc_copy = {
430
+ "id": tc.get("id"),
431
+ "type": tc.get("type", "function"),
432
+ "function": {"name": "", "arguments": ""},
433
+ }
434
+
435
+ # Safely copy function data
436
+ if isinstance(tc.get("function"), dict):
437
+ func_dict = tc.get("function", {})
438
+ tc_copy["function"]["name"] = func_dict.get("name", "")
439
+
440
+ # Process arguments
441
+ args = func_dict.get("arguments", "")
442
+ if args and isinstance(args, str):
443
+ try:
444
+ # Check if arguments are already valid JSON
445
+ parsed = json.loads(args)
446
+ # If it's not a dict, convert to a JSON string of a dict
447
+ if not isinstance(parsed, dict):
448
+ tc_copy["function"]["arguments"] = json.dumps({"value": parsed})
449
+ else:
450
+ tc_copy["function"]["arguments"] = args
451
+ except json.JSONDecodeError:
452
+ # If not valid JSON, make it a JSON dict
453
+ tc_copy["function"]["arguments"] = json.dumps({"text": args})
454
+
455
+ result.append(tc_copy)
456
+
457
+ return result
458
+
459
+ def _get_metrics(self, response_usage: Any) -> Metrics:
460
+ """
461
+ Parse the given LiteLLM usage into an Agno Metrics object.
462
+
463
+ Args:
464
+ response_usage: Usage data from LiteLLM
465
+
466
+ Returns:
467
+ Metrics: Parsed metrics data
468
+ """
469
+ metrics = Metrics()
470
+
471
+ if isinstance(response_usage, dict):
472
+ metrics.input_tokens = response_usage.get("prompt_tokens") or 0
473
+ metrics.output_tokens = response_usage.get("completion_tokens") or 0
474
+ else:
475
+ metrics.input_tokens = response_usage.prompt_tokens or 0
476
+ metrics.output_tokens = response_usage.completion_tokens or 0
477
+
478
+ metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
479
+
480
+ return metrics
481
+
482
+ def count_tokens(
483
+ self,
484
+ messages: List[Message],
485
+ tools: Optional[List[Union[Function, Dict[str, Any]]]] = None,
486
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
487
+ ) -> int:
488
+ formatted_messages = self._format_messages(messages, compress_tool_results=True)
489
+ formatted_tools = self._format_tools(tools) if tools else None
490
+ tokens = litellm.token_counter(
491
+ model=self.id,
492
+ messages=formatted_messages,
493
+ tools=formatted_tools, # type: ignore
494
+ )
495
+ return tokens + count_schema_tokens(response_format, self.id)
496
+
497
+ async def acount_tokens(
498
+ self,
499
+ messages: List[Message],
500
+ tools: Optional[List[Union[Function, Dict[str, Any]]]] = None,
501
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
502
+ ) -> int:
503
+ return self.count_tokens(messages, tools, response_format)
@@ -0,0 +1,42 @@
1
+ from dataclasses import dataclass, field
2
+ from os import getenv
3
+ from typing import Any, Dict, Optional
4
+
5
+ from agno.exceptions import ModelAuthenticationError
6
+ from agno.models.openai.like import OpenAILike
7
+
8
+
9
+ @dataclass
10
+ class LiteLLMOpenAI(OpenAILike):
11
+ """
12
+ A class for interacting with LiteLLM.
13
+
14
+ Attributes:
15
+ id (str): The id of the LiteLLM model. Default is "gpt-4o".
16
+ name (str): The name of this chat model instance. Default is "LiteLLM".
17
+ provider (str): The provider of the model. Default is "LiteLLM".
18
+ base_url (str): The base url to which the requests are sent.
19
+ """
20
+
21
+ id: str = "gpt-4o"
22
+ name: str = "LiteLLM"
23
+ provider: str = "LiteLLM"
24
+
25
+ api_key: Optional[str] = field(default_factory=lambda: getenv("LITELLM_API_KEY"))
26
+ base_url: str = "http://0.0.0.0:4000"
27
+
28
+ def _get_client_params(self) -> Dict[str, Any]:
29
+ """
30
+ Returns client parameters for API requests, checking for LITELLM_API_KEY.
31
+
32
+ Returns:
33
+ Dict[str, Any]: A dictionary of client parameters for API requests.
34
+ """
35
+ if not self.api_key:
36
+ self.api_key = getenv("LITELLM_API_KEY")
37
+ if not self.api_key:
38
+ raise ModelAuthenticationError(
39
+ message="LITELLM_API_KEY not set. Please set the LITELLM_API_KEY environment variable.",
40
+ model_name=self.name,
41
+ )
42
+ return super()._get_client_params()
@@ -0,0 +1,5 @@
1
+ from agno.models.llama_cpp.llama_cpp import LlamaCpp
2
+
3
+ __all__ = [
4
+ "LlamaCpp",
5
+ ]
@@ -0,0 +1,22 @@
1
+ from dataclasses import dataclass
2
+
3
+ from agno.models.openai.like import OpenAILike
4
+
5
+
6
+ @dataclass
7
+ class LlamaCpp(OpenAILike):
8
+ """
9
+ A class for interacting with LLMs using Llama CPP.
10
+
11
+ Attributes:
12
+ id (str): The id of the Llama CPP model. Default is "ggml-org/gpt-oss-20b-GGUF".
13
+ name (str): The name of this chat model instance. Default is "LlamaCpp".
14
+ provider (str): The provider of the model. Default is "LlamaCpp".
15
+ base_url (str): The base url to which the requests are sent.
16
+ """
17
+
18
+ id: str = "ggml-org/gpt-oss-20b-GGUF"
19
+ name: str = "LlamaCpp"
20
+ provider: str = "LlamaCpp"
21
+
22
+ base_url: str = "http://127.0.0.1:8080/v1"
@@ -0,0 +1,5 @@
1
+ from agno.models.lmstudio.lmstudio import LMStudio
2
+
3
+ __all__ = [
4
+ "LMStudio",
5
+ ]
@@ -0,0 +1,25 @@
1
+ from dataclasses import dataclass
2
+
3
+ from agno.models.openai.like import OpenAILike
4
+
5
+
6
+ @dataclass
7
+ class LMStudio(OpenAILike):
8
+ """
9
+ A class for interacting with LM Studio.
10
+
11
+ Attributes:
12
+ id (str): The id of the LM Studio model. Default is "qwen2.5-7b-instruct-1m".
13
+ name (str): The name of this chat model instance. Default is "LMStudio".
14
+ provider (str): The provider of the model. Default is "LMStudio".
15
+ base_url (str): The base url to which the requests are sent.
16
+ """
17
+
18
+ id: str = "qwen2.5-7b-instruct-1m"
19
+ name: str = "LMStudio"
20
+ provider: str = "LMStudio"
21
+
22
+ base_url: str = "http://127.0.0.1:1234/v1"
23
+
24
+ supports_native_structured_outputs: bool = False
25
+ supports_json_schema_outputs: bool = True