agno 2.2.13__py3-none-any.whl → 2.4.3__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 (383) hide show
  1. agno/agent/__init__.py +6 -0
  2. agno/agent/agent.py +5252 -3145
  3. agno/agent/remote.py +525 -0
  4. agno/api/api.py +2 -0
  5. agno/client/__init__.py +3 -0
  6. agno/client/a2a/__init__.py +10 -0
  7. agno/client/a2a/client.py +554 -0
  8. agno/client/a2a/schemas.py +112 -0
  9. agno/client/a2a/utils.py +369 -0
  10. agno/client/os.py +2669 -0
  11. agno/compression/__init__.py +3 -0
  12. agno/compression/manager.py +247 -0
  13. agno/culture/manager.py +2 -2
  14. agno/db/base.py +927 -6
  15. agno/db/dynamo/dynamo.py +788 -2
  16. agno/db/dynamo/schemas.py +128 -0
  17. agno/db/dynamo/utils.py +26 -3
  18. agno/db/firestore/firestore.py +674 -50
  19. agno/db/firestore/schemas.py +41 -0
  20. agno/db/firestore/utils.py +25 -10
  21. agno/db/gcs_json/gcs_json_db.py +506 -3
  22. agno/db/gcs_json/utils.py +14 -2
  23. agno/db/in_memory/in_memory_db.py +203 -4
  24. agno/db/in_memory/utils.py +14 -2
  25. agno/db/json/json_db.py +498 -2
  26. agno/db/json/utils.py +14 -2
  27. agno/db/migrations/manager.py +199 -0
  28. agno/db/migrations/utils.py +19 -0
  29. agno/db/migrations/v1_to_v2.py +54 -16
  30. agno/db/migrations/versions/__init__.py +0 -0
  31. agno/db/migrations/versions/v2_3_0.py +977 -0
  32. agno/db/mongo/async_mongo.py +1013 -39
  33. agno/db/mongo/mongo.py +684 -4
  34. agno/db/mongo/schemas.py +48 -0
  35. agno/db/mongo/utils.py +17 -0
  36. agno/db/mysql/__init__.py +2 -1
  37. agno/db/mysql/async_mysql.py +2958 -0
  38. agno/db/mysql/mysql.py +722 -53
  39. agno/db/mysql/schemas.py +77 -11
  40. agno/db/mysql/utils.py +151 -8
  41. agno/db/postgres/async_postgres.py +1254 -137
  42. agno/db/postgres/postgres.py +2316 -93
  43. agno/db/postgres/schemas.py +153 -21
  44. agno/db/postgres/utils.py +22 -7
  45. agno/db/redis/redis.py +531 -3
  46. agno/db/redis/schemas.py +36 -0
  47. agno/db/redis/utils.py +31 -15
  48. agno/db/schemas/evals.py +1 -0
  49. agno/db/schemas/memory.py +20 -9
  50. agno/db/singlestore/schemas.py +70 -1
  51. agno/db/singlestore/singlestore.py +737 -74
  52. agno/db/singlestore/utils.py +13 -3
  53. agno/db/sqlite/async_sqlite.py +1069 -89
  54. agno/db/sqlite/schemas.py +133 -1
  55. agno/db/sqlite/sqlite.py +2203 -165
  56. agno/db/sqlite/utils.py +21 -11
  57. agno/db/surrealdb/models.py +25 -0
  58. agno/db/surrealdb/surrealdb.py +603 -1
  59. agno/db/utils.py +60 -0
  60. agno/eval/__init__.py +26 -3
  61. agno/eval/accuracy.py +25 -12
  62. agno/eval/agent_as_judge.py +871 -0
  63. agno/eval/base.py +29 -0
  64. agno/eval/performance.py +10 -4
  65. agno/eval/reliability.py +22 -13
  66. agno/eval/utils.py +2 -1
  67. agno/exceptions.py +42 -0
  68. agno/hooks/__init__.py +3 -0
  69. agno/hooks/decorator.py +164 -0
  70. agno/integrations/discord/client.py +13 -2
  71. agno/knowledge/__init__.py +4 -0
  72. agno/knowledge/chunking/code.py +90 -0
  73. agno/knowledge/chunking/document.py +65 -4
  74. agno/knowledge/chunking/fixed.py +4 -1
  75. agno/knowledge/chunking/markdown.py +102 -11
  76. agno/knowledge/chunking/recursive.py +2 -2
  77. agno/knowledge/chunking/semantic.py +130 -48
  78. agno/knowledge/chunking/strategy.py +18 -0
  79. agno/knowledge/embedder/azure_openai.py +0 -1
  80. agno/knowledge/embedder/google.py +1 -1
  81. agno/knowledge/embedder/mistral.py +1 -1
  82. agno/knowledge/embedder/nebius.py +1 -1
  83. agno/knowledge/embedder/openai.py +16 -12
  84. agno/knowledge/filesystem.py +412 -0
  85. agno/knowledge/knowledge.py +4261 -1199
  86. agno/knowledge/protocol.py +134 -0
  87. agno/knowledge/reader/arxiv_reader.py +3 -2
  88. agno/knowledge/reader/base.py +9 -7
  89. agno/knowledge/reader/csv_reader.py +91 -42
  90. agno/knowledge/reader/docx_reader.py +9 -10
  91. agno/knowledge/reader/excel_reader.py +225 -0
  92. agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
  93. agno/knowledge/reader/firecrawl_reader.py +3 -2
  94. agno/knowledge/reader/json_reader.py +16 -22
  95. agno/knowledge/reader/markdown_reader.py +15 -14
  96. agno/knowledge/reader/pdf_reader.py +33 -28
  97. agno/knowledge/reader/pptx_reader.py +9 -10
  98. agno/knowledge/reader/reader_factory.py +135 -1
  99. agno/knowledge/reader/s3_reader.py +8 -16
  100. agno/knowledge/reader/tavily_reader.py +3 -3
  101. agno/knowledge/reader/text_reader.py +15 -14
  102. agno/knowledge/reader/utils/__init__.py +17 -0
  103. agno/knowledge/reader/utils/spreadsheet.py +114 -0
  104. agno/knowledge/reader/web_search_reader.py +8 -65
  105. agno/knowledge/reader/website_reader.py +16 -13
  106. agno/knowledge/reader/wikipedia_reader.py +36 -3
  107. agno/knowledge/reader/youtube_reader.py +3 -2
  108. agno/knowledge/remote_content/__init__.py +33 -0
  109. agno/knowledge/remote_content/config.py +266 -0
  110. agno/knowledge/remote_content/remote_content.py +105 -17
  111. agno/knowledge/utils.py +76 -22
  112. agno/learn/__init__.py +71 -0
  113. agno/learn/config.py +463 -0
  114. agno/learn/curate.py +185 -0
  115. agno/learn/machine.py +725 -0
  116. agno/learn/schemas.py +1114 -0
  117. agno/learn/stores/__init__.py +38 -0
  118. agno/learn/stores/decision_log.py +1156 -0
  119. agno/learn/stores/entity_memory.py +3275 -0
  120. agno/learn/stores/learned_knowledge.py +1583 -0
  121. agno/learn/stores/protocol.py +117 -0
  122. agno/learn/stores/session_context.py +1217 -0
  123. agno/learn/stores/user_memory.py +1495 -0
  124. agno/learn/stores/user_profile.py +1220 -0
  125. agno/learn/utils.py +209 -0
  126. agno/media.py +22 -6
  127. agno/memory/__init__.py +14 -1
  128. agno/memory/manager.py +223 -8
  129. agno/memory/strategies/__init__.py +15 -0
  130. agno/memory/strategies/base.py +66 -0
  131. agno/memory/strategies/summarize.py +196 -0
  132. agno/memory/strategies/types.py +37 -0
  133. agno/models/aimlapi/aimlapi.py +17 -0
  134. agno/models/anthropic/claude.py +434 -59
  135. agno/models/aws/bedrock.py +121 -20
  136. agno/models/aws/claude.py +131 -274
  137. agno/models/azure/ai_foundry.py +10 -6
  138. agno/models/azure/openai_chat.py +33 -10
  139. agno/models/base.py +1162 -561
  140. agno/models/cerebras/cerebras.py +120 -24
  141. agno/models/cerebras/cerebras_openai.py +21 -2
  142. agno/models/cohere/chat.py +65 -6
  143. agno/models/cometapi/cometapi.py +18 -1
  144. agno/models/dashscope/dashscope.py +2 -3
  145. agno/models/deepinfra/deepinfra.py +18 -1
  146. agno/models/deepseek/deepseek.py +69 -3
  147. agno/models/fireworks/fireworks.py +18 -1
  148. agno/models/google/gemini.py +959 -89
  149. agno/models/google/utils.py +22 -0
  150. agno/models/groq/groq.py +48 -18
  151. agno/models/huggingface/huggingface.py +17 -6
  152. agno/models/ibm/watsonx.py +16 -6
  153. agno/models/internlm/internlm.py +18 -1
  154. agno/models/langdb/langdb.py +13 -1
  155. agno/models/litellm/chat.py +88 -9
  156. agno/models/litellm/litellm_openai.py +18 -1
  157. agno/models/message.py +24 -5
  158. agno/models/meta/llama.py +40 -13
  159. agno/models/meta/llama_openai.py +22 -21
  160. agno/models/metrics.py +12 -0
  161. agno/models/mistral/mistral.py +8 -4
  162. agno/models/n1n/__init__.py +3 -0
  163. agno/models/n1n/n1n.py +57 -0
  164. agno/models/nebius/nebius.py +6 -7
  165. agno/models/nvidia/nvidia.py +20 -3
  166. agno/models/ollama/__init__.py +2 -0
  167. agno/models/ollama/chat.py +17 -6
  168. agno/models/ollama/responses.py +100 -0
  169. agno/models/openai/__init__.py +2 -0
  170. agno/models/openai/chat.py +117 -26
  171. agno/models/openai/open_responses.py +46 -0
  172. agno/models/openai/responses.py +110 -32
  173. agno/models/openrouter/__init__.py +2 -0
  174. agno/models/openrouter/openrouter.py +67 -2
  175. agno/models/openrouter/responses.py +146 -0
  176. agno/models/perplexity/perplexity.py +19 -1
  177. agno/models/portkey/portkey.py +7 -6
  178. agno/models/requesty/requesty.py +19 -2
  179. agno/models/response.py +20 -2
  180. agno/models/sambanova/sambanova.py +20 -3
  181. agno/models/siliconflow/siliconflow.py +19 -2
  182. agno/models/together/together.py +20 -3
  183. agno/models/vercel/v0.py +20 -3
  184. agno/models/vertexai/claude.py +124 -4
  185. agno/models/vllm/vllm.py +19 -14
  186. agno/models/xai/xai.py +19 -2
  187. agno/os/app.py +467 -137
  188. agno/os/auth.py +253 -5
  189. agno/os/config.py +22 -0
  190. agno/os/interfaces/a2a/a2a.py +7 -6
  191. agno/os/interfaces/a2a/router.py +635 -26
  192. agno/os/interfaces/a2a/utils.py +32 -33
  193. agno/os/interfaces/agui/agui.py +5 -3
  194. agno/os/interfaces/agui/router.py +26 -16
  195. agno/os/interfaces/agui/utils.py +97 -57
  196. agno/os/interfaces/base.py +7 -7
  197. agno/os/interfaces/slack/router.py +16 -7
  198. agno/os/interfaces/slack/slack.py +7 -7
  199. agno/os/interfaces/whatsapp/router.py +35 -7
  200. agno/os/interfaces/whatsapp/security.py +3 -1
  201. agno/os/interfaces/whatsapp/whatsapp.py +11 -8
  202. agno/os/managers.py +326 -0
  203. agno/os/mcp.py +652 -79
  204. agno/os/middleware/__init__.py +4 -0
  205. agno/os/middleware/jwt.py +718 -115
  206. agno/os/middleware/trailing_slash.py +27 -0
  207. agno/os/router.py +105 -1558
  208. agno/os/routers/agents/__init__.py +3 -0
  209. agno/os/routers/agents/router.py +655 -0
  210. agno/os/routers/agents/schema.py +288 -0
  211. agno/os/routers/components/__init__.py +3 -0
  212. agno/os/routers/components/components.py +475 -0
  213. agno/os/routers/database.py +155 -0
  214. agno/os/routers/evals/evals.py +111 -18
  215. agno/os/routers/evals/schemas.py +38 -5
  216. agno/os/routers/evals/utils.py +80 -11
  217. agno/os/routers/health.py +3 -3
  218. agno/os/routers/knowledge/knowledge.py +284 -35
  219. agno/os/routers/knowledge/schemas.py +14 -2
  220. agno/os/routers/memory/memory.py +274 -11
  221. agno/os/routers/memory/schemas.py +44 -3
  222. agno/os/routers/metrics/metrics.py +30 -15
  223. agno/os/routers/metrics/schemas.py +10 -6
  224. agno/os/routers/registry/__init__.py +3 -0
  225. agno/os/routers/registry/registry.py +337 -0
  226. agno/os/routers/session/session.py +143 -14
  227. agno/os/routers/teams/__init__.py +3 -0
  228. agno/os/routers/teams/router.py +550 -0
  229. agno/os/routers/teams/schema.py +280 -0
  230. agno/os/routers/traces/__init__.py +3 -0
  231. agno/os/routers/traces/schemas.py +414 -0
  232. agno/os/routers/traces/traces.py +549 -0
  233. agno/os/routers/workflows/__init__.py +3 -0
  234. agno/os/routers/workflows/router.py +757 -0
  235. agno/os/routers/workflows/schema.py +139 -0
  236. agno/os/schema.py +157 -584
  237. agno/os/scopes.py +469 -0
  238. agno/os/settings.py +3 -0
  239. agno/os/utils.py +574 -185
  240. agno/reasoning/anthropic.py +85 -1
  241. agno/reasoning/azure_ai_foundry.py +93 -1
  242. agno/reasoning/deepseek.py +102 -2
  243. agno/reasoning/default.py +6 -7
  244. agno/reasoning/gemini.py +87 -3
  245. agno/reasoning/groq.py +109 -2
  246. agno/reasoning/helpers.py +6 -7
  247. agno/reasoning/manager.py +1238 -0
  248. agno/reasoning/ollama.py +93 -1
  249. agno/reasoning/openai.py +115 -1
  250. agno/reasoning/vertexai.py +85 -1
  251. agno/registry/__init__.py +3 -0
  252. agno/registry/registry.py +68 -0
  253. agno/remote/__init__.py +3 -0
  254. agno/remote/base.py +581 -0
  255. agno/run/__init__.py +2 -4
  256. agno/run/agent.py +134 -19
  257. agno/run/base.py +49 -1
  258. agno/run/cancel.py +65 -52
  259. agno/run/cancellation_management/__init__.py +9 -0
  260. agno/run/cancellation_management/base.py +78 -0
  261. agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
  262. agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
  263. agno/run/requirement.py +181 -0
  264. agno/run/team.py +111 -19
  265. agno/run/workflow.py +2 -1
  266. agno/session/agent.py +57 -92
  267. agno/session/summary.py +1 -1
  268. agno/session/team.py +62 -115
  269. agno/session/workflow.py +353 -57
  270. agno/skills/__init__.py +17 -0
  271. agno/skills/agent_skills.py +377 -0
  272. agno/skills/errors.py +32 -0
  273. agno/skills/loaders/__init__.py +4 -0
  274. agno/skills/loaders/base.py +27 -0
  275. agno/skills/loaders/local.py +216 -0
  276. agno/skills/skill.py +65 -0
  277. agno/skills/utils.py +107 -0
  278. agno/skills/validator.py +277 -0
  279. agno/table.py +10 -0
  280. agno/team/__init__.py +5 -1
  281. agno/team/remote.py +447 -0
  282. agno/team/team.py +3769 -2202
  283. agno/tools/brandfetch.py +27 -18
  284. agno/tools/browserbase.py +225 -16
  285. agno/tools/crawl4ai.py +3 -0
  286. agno/tools/duckduckgo.py +25 -71
  287. agno/tools/exa.py +0 -21
  288. agno/tools/file.py +14 -13
  289. agno/tools/file_generation.py +12 -6
  290. agno/tools/firecrawl.py +15 -7
  291. agno/tools/function.py +94 -113
  292. agno/tools/google_bigquery.py +11 -2
  293. agno/tools/google_drive.py +4 -3
  294. agno/tools/knowledge.py +9 -4
  295. agno/tools/mcp/mcp.py +301 -18
  296. agno/tools/mcp/multi_mcp.py +269 -14
  297. agno/tools/mem0.py +11 -10
  298. agno/tools/memory.py +47 -46
  299. agno/tools/mlx_transcribe.py +10 -7
  300. agno/tools/models/nebius.py +5 -5
  301. agno/tools/models_labs.py +20 -10
  302. agno/tools/nano_banana.py +151 -0
  303. agno/tools/parallel.py +0 -7
  304. agno/tools/postgres.py +76 -36
  305. agno/tools/python.py +14 -6
  306. agno/tools/reasoning.py +30 -23
  307. agno/tools/redshift.py +406 -0
  308. agno/tools/shopify.py +1519 -0
  309. agno/tools/spotify.py +919 -0
  310. agno/tools/tavily.py +4 -1
  311. agno/tools/toolkit.py +253 -18
  312. agno/tools/websearch.py +93 -0
  313. agno/tools/website.py +1 -1
  314. agno/tools/wikipedia.py +1 -1
  315. agno/tools/workflow.py +56 -48
  316. agno/tools/yfinance.py +12 -11
  317. agno/tracing/__init__.py +12 -0
  318. agno/tracing/exporter.py +161 -0
  319. agno/tracing/schemas.py +276 -0
  320. agno/tracing/setup.py +112 -0
  321. agno/utils/agent.py +251 -10
  322. agno/utils/cryptography.py +22 -0
  323. agno/utils/dttm.py +33 -0
  324. agno/utils/events.py +264 -7
  325. agno/utils/hooks.py +111 -3
  326. agno/utils/http.py +161 -2
  327. agno/utils/mcp.py +49 -8
  328. agno/utils/media.py +22 -1
  329. agno/utils/models/ai_foundry.py +9 -2
  330. agno/utils/models/claude.py +20 -5
  331. agno/utils/models/cohere.py +9 -2
  332. agno/utils/models/llama.py +9 -2
  333. agno/utils/models/mistral.py +4 -2
  334. agno/utils/os.py +0 -0
  335. agno/utils/print_response/agent.py +99 -16
  336. agno/utils/print_response/team.py +223 -24
  337. agno/utils/print_response/workflow.py +0 -2
  338. agno/utils/prompts.py +8 -6
  339. agno/utils/remote.py +23 -0
  340. agno/utils/response.py +1 -13
  341. agno/utils/string.py +91 -2
  342. agno/utils/team.py +62 -12
  343. agno/utils/tokens.py +657 -0
  344. agno/vectordb/base.py +15 -2
  345. agno/vectordb/cassandra/cassandra.py +1 -1
  346. agno/vectordb/chroma/__init__.py +2 -1
  347. agno/vectordb/chroma/chromadb.py +468 -23
  348. agno/vectordb/clickhouse/clickhousedb.py +1 -1
  349. agno/vectordb/couchbase/couchbase.py +6 -2
  350. agno/vectordb/lancedb/lance_db.py +7 -38
  351. agno/vectordb/lightrag/lightrag.py +7 -6
  352. agno/vectordb/milvus/milvus.py +118 -84
  353. agno/vectordb/mongodb/__init__.py +2 -1
  354. agno/vectordb/mongodb/mongodb.py +14 -31
  355. agno/vectordb/pgvector/pgvector.py +120 -66
  356. agno/vectordb/pineconedb/pineconedb.py +2 -19
  357. agno/vectordb/qdrant/__init__.py +2 -1
  358. agno/vectordb/qdrant/qdrant.py +33 -56
  359. agno/vectordb/redis/__init__.py +2 -1
  360. agno/vectordb/redis/redisdb.py +19 -31
  361. agno/vectordb/singlestore/singlestore.py +17 -9
  362. agno/vectordb/surrealdb/surrealdb.py +2 -38
  363. agno/vectordb/weaviate/__init__.py +2 -1
  364. agno/vectordb/weaviate/weaviate.py +7 -3
  365. agno/workflow/__init__.py +5 -1
  366. agno/workflow/agent.py +2 -2
  367. agno/workflow/condition.py +12 -10
  368. agno/workflow/loop.py +28 -9
  369. agno/workflow/parallel.py +21 -13
  370. agno/workflow/remote.py +362 -0
  371. agno/workflow/router.py +12 -9
  372. agno/workflow/step.py +261 -36
  373. agno/workflow/steps.py +12 -8
  374. agno/workflow/types.py +40 -77
  375. agno/workflow/workflow.py +939 -213
  376. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
  377. agno-2.4.3.dist-info/RECORD +677 -0
  378. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
  379. agno/tools/googlesearch.py +0 -98
  380. agno/tools/memori.py +0 -339
  381. agno-2.2.13.dist-info/RECORD +0 -575
  382. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
  383. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import List, Optional
3
+ from typing import AsyncIterator, Iterator, List, Optional, Tuple
4
4
 
5
5
  from agno.models.base import Model
6
6
  from agno.models.message import Message
@@ -51,6 +51,48 @@ def get_anthropic_reasoning(reasoning_agent: "Agent", messages: List[Message]) -
51
51
  )
52
52
 
53
53
 
54
+ def get_anthropic_reasoning_stream(
55
+ reasoning_agent: "Agent", # type: ignore # noqa: F821
56
+ messages: List[Message],
57
+ ) -> Iterator[Tuple[Optional[str], Optional[Message]]]:
58
+ """
59
+ Stream reasoning content from Anthropic Claude model.
60
+
61
+ Yields:
62
+ Tuple of (reasoning_content_delta, final_message)
63
+ - During streaming: (reasoning_content_delta, None)
64
+ - At the end: (None, final_message)
65
+ """
66
+ from agno.run.agent import RunEvent
67
+
68
+ reasoning_content: str = ""
69
+ redacted_reasoning_content: Optional[str] = None
70
+
71
+ try:
72
+ for event in reasoning_agent.run(input=messages, stream=True, stream_events=True):
73
+ if hasattr(event, "event"):
74
+ if event.event == RunEvent.run_content:
75
+ # Stream reasoning content as it arrives
76
+ if hasattr(event, "reasoning_content") and event.reasoning_content:
77
+ reasoning_content += event.reasoning_content
78
+ yield (event.reasoning_content, None)
79
+ elif event.event == RunEvent.run_completed:
80
+ pass
81
+ except Exception as e:
82
+ logger.warning(f"Reasoning error: {e}")
83
+ return
84
+
85
+ # Yield final message
86
+ if reasoning_content:
87
+ final_message = Message(
88
+ role="assistant",
89
+ content=f"<thinking>\n{reasoning_content}\n</thinking>",
90
+ reasoning_content=reasoning_content,
91
+ redacted_reasoning_content=redacted_reasoning_content,
92
+ )
93
+ yield (None, final_message)
94
+
95
+
54
96
  async def aget_anthropic_reasoning(reasoning_agent: "Agent", messages: List[Message]) -> Optional[Message]: # type: ignore # noqa: F821
55
97
  """Get reasoning from an Anthropic Claude model asynchronously."""
56
98
  from agno.run.agent import RunOutput
@@ -78,3 +120,45 @@ async def aget_anthropic_reasoning(reasoning_agent: "Agent", messages: List[Mess
78
120
  reasoning_content=reasoning_content,
79
121
  redacted_reasoning_content=redacted_reasoning_content,
80
122
  )
123
+
124
+
125
+ async def aget_anthropic_reasoning_stream(
126
+ reasoning_agent: "Agent", # type: ignore # noqa: F821
127
+ messages: List[Message],
128
+ ) -> AsyncIterator[Tuple[Optional[str], Optional[Message]]]:
129
+ """
130
+ Stream reasoning content from Anthropic Claude model asynchronously.
131
+
132
+ Yields:
133
+ Tuple of (reasoning_content_delta, final_message)
134
+ - During streaming: (reasoning_content_delta, None)
135
+ - At the end: (None, final_message)
136
+ """
137
+ from agno.run.agent import RunEvent
138
+
139
+ reasoning_content: str = ""
140
+ redacted_reasoning_content: Optional[str] = None
141
+
142
+ try:
143
+ async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
144
+ if hasattr(event, "event"):
145
+ if event.event == RunEvent.run_content:
146
+ # Stream reasoning content as it arrives
147
+ if hasattr(event, "reasoning_content") and event.reasoning_content:
148
+ reasoning_content += event.reasoning_content
149
+ yield (event.reasoning_content, None)
150
+ elif event.event == RunEvent.run_completed:
151
+ pass
152
+ except Exception as e:
153
+ logger.warning(f"Reasoning error: {e}")
154
+ return
155
+
156
+ # Yield final message
157
+ if reasoning_content:
158
+ final_message = Message(
159
+ role="assistant",
160
+ content=f"<thinking>\n{reasoning_content}\n</thinking>",
161
+ reasoning_content=reasoning_content,
162
+ redacted_reasoning_content=redacted_reasoning_content,
163
+ )
164
+ yield (None, final_message)
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import List, Optional
3
+ from typing import AsyncIterator, Iterator, List, Optional, Tuple
4
4
 
5
5
  from agno.models.base import Model
6
6
  from agno.models.message import Message
@@ -65,3 +65,95 @@ async def aget_ai_foundry_reasoning(reasoning_agent: "Agent", messages: List[Mes
65
65
  return Message(
66
66
  role="assistant", content=f"<thinking>\n{reasoning_content}\n</thinking>", reasoning_content=reasoning_content
67
67
  )
68
+
69
+
70
+ def get_ai_foundry_reasoning_stream(
71
+ reasoning_agent: "Agent", # type: ignore # noqa: F821
72
+ messages: List[Message],
73
+ ) -> Iterator[Tuple[Optional[str], Optional[Message]]]:
74
+ """
75
+ Stream reasoning content from Azure AI Foundry model.
76
+
77
+ For DeepSeek-R1 models, we use the main content output as reasoning content.
78
+
79
+ Yields:
80
+ Tuple of (reasoning_content_delta, final_message)
81
+ - During streaming: (reasoning_content_delta, None)
82
+ - At the end: (None, final_message)
83
+ """
84
+ from agno.run.agent import RunEvent
85
+
86
+ reasoning_content: str = ""
87
+
88
+ try:
89
+ for event in reasoning_agent.run(input=messages, stream=True, stream_events=True):
90
+ if hasattr(event, "event"):
91
+ if event.event == RunEvent.run_content:
92
+ # Check for reasoning_content attribute first (native reasoning)
93
+ if hasattr(event, "reasoning_content") and event.reasoning_content:
94
+ reasoning_content += event.reasoning_content
95
+ yield (event.reasoning_content, None)
96
+ # Use the main content as reasoning content
97
+ elif hasattr(event, "content") and event.content:
98
+ reasoning_content += event.content
99
+ yield (event.content, None)
100
+ elif event.event == RunEvent.run_completed:
101
+ pass
102
+ except Exception as e:
103
+ logger.warning(f"Reasoning error: {e}")
104
+ return
105
+
106
+ # Yield final message
107
+ if reasoning_content:
108
+ final_message = Message(
109
+ role="assistant",
110
+ content=f"<thinking>\n{reasoning_content}\n</thinking>",
111
+ reasoning_content=reasoning_content,
112
+ )
113
+ yield (None, final_message)
114
+
115
+
116
+ async def aget_ai_foundry_reasoning_stream(
117
+ reasoning_agent: "Agent", # type: ignore # noqa: F821
118
+ messages: List[Message],
119
+ ) -> AsyncIterator[Tuple[Optional[str], Optional[Message]]]:
120
+ """
121
+ Stream reasoning content from Azure AI Foundry model asynchronously.
122
+
123
+ For DeepSeek-R1 models, we use the main content output as reasoning content.
124
+
125
+ Yields:
126
+ Tuple of (reasoning_content_delta, final_message)
127
+ - During streaming: (reasoning_content_delta, None)
128
+ - At the end: (None, final_message)
129
+ """
130
+ from agno.run.agent import RunEvent
131
+
132
+ reasoning_content: str = ""
133
+
134
+ try:
135
+ async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
136
+ if hasattr(event, "event"):
137
+ if event.event == RunEvent.run_content:
138
+ # Check for reasoning_content attribute first (native reasoning)
139
+ if hasattr(event, "reasoning_content") and event.reasoning_content:
140
+ reasoning_content += event.reasoning_content
141
+ yield (event.reasoning_content, None)
142
+ # Use the main content as reasoning content
143
+ elif hasattr(event, "content") and event.content:
144
+ reasoning_content += event.content
145
+ yield (event.content, None)
146
+ elif event.event == RunEvent.run_completed:
147
+ pass
148
+ except Exception as e:
149
+ logger.warning(f"Reasoning error: {e}")
150
+ return
151
+
152
+ # Yield final message
153
+ if reasoning_content:
154
+ final_message = Message(
155
+ role="assistant",
156
+ content=f"<thinking>\n{reasoning_content}\n</thinking>",
157
+ reasoning_content=reasoning_content,
158
+ )
159
+ yield (None, final_message)
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import List, Optional
3
+ from typing import AsyncIterator, Iterator, List, Optional, Tuple
4
4
 
5
5
  from agno.models.base import Model
6
6
  from agno.models.message import Message
@@ -8,7 +8,17 @@ from agno.utils.log import logger
8
8
 
9
9
 
10
10
  def is_deepseek_reasoning_model(reasoning_model: Model) -> bool:
11
- return reasoning_model.__class__.__name__ == "DeepSeek" and reasoning_model.id.lower() == "deepseek-reasoner"
11
+ """Check if the model is a DeepSeek reasoning model.
12
+
13
+ Matches:
14
+ - deepseek-reasoner
15
+ - deepseek-r1 and variants (deepseek-r1-distill-*, etc.)
16
+ """
17
+ if reasoning_model.__class__.__name__ != "DeepSeek":
18
+ return False
19
+
20
+ model_id = reasoning_model.id.lower()
21
+ return "reasoner" in model_id or "r1" in model_id
12
22
 
13
23
 
14
24
  def get_deepseek_reasoning(reasoning_agent: "Agent", messages: List[Message]) -> Optional[Message]: # type: ignore # noqa: F821
@@ -37,6 +47,51 @@ def get_deepseek_reasoning(reasoning_agent: "Agent", messages: List[Message]) ->
37
47
  )
38
48
 
39
49
 
50
+ def get_deepseek_reasoning_stream(
51
+ reasoning_agent: "Agent", # type: ignore # noqa: F821
52
+ messages: List[Message],
53
+ ) -> Iterator[Tuple[Optional[str], Optional[Message]]]:
54
+ """
55
+ Stream reasoning content from DeepSeek model.
56
+
57
+ Yields:
58
+ Tuple of (reasoning_content_delta, final_message)
59
+ - During streaming: (reasoning_content_delta, None)
60
+ - At the end: (None, final_message)
61
+ """
62
+ from agno.run.agent import RunEvent
63
+
64
+ # Update system message role to "system"
65
+ for message in messages:
66
+ if message.role == "developer":
67
+ message.role = "system"
68
+
69
+ reasoning_content: str = ""
70
+
71
+ try:
72
+ for event in reasoning_agent.run(input=messages, stream=True, stream_events=True):
73
+ if hasattr(event, "event"):
74
+ if event.event == RunEvent.run_content:
75
+ # Stream reasoning content as it arrives
76
+ if hasattr(event, "reasoning_content") and event.reasoning_content:
77
+ reasoning_content += event.reasoning_content
78
+ yield (event.reasoning_content, None)
79
+ elif event.event == RunEvent.run_completed:
80
+ pass
81
+ except Exception as e:
82
+ logger.warning(f"Reasoning error: {e}")
83
+ return
84
+
85
+ # Yield final message
86
+ if reasoning_content:
87
+ final_message = Message(
88
+ role="assistant",
89
+ content=f"<thinking>\n{reasoning_content}\n</thinking>",
90
+ reasoning_content=reasoning_content,
91
+ )
92
+ yield (None, final_message)
93
+
94
+
40
95
  async def aget_deepseek_reasoning(reasoning_agent: "Agent", messages: List[Message]) -> Optional[Message]: # type: ignore # noqa: F821
41
96
  from agno.run.agent import RunOutput
42
97
 
@@ -61,3 +116,48 @@ async def aget_deepseek_reasoning(reasoning_agent: "Agent", messages: List[Messa
61
116
  return Message(
62
117
  role="assistant", content=f"<thinking>\n{reasoning_content}\n</thinking>", reasoning_content=reasoning_content
63
118
  )
119
+
120
+
121
+ async def aget_deepseek_reasoning_stream(
122
+ reasoning_agent: "Agent", # type: ignore # noqa: F821
123
+ messages: List[Message],
124
+ ) -> AsyncIterator[Tuple[Optional[str], Optional[Message]]]:
125
+ """
126
+ Stream reasoning content from DeepSeek model asynchronously.
127
+
128
+ Yields:
129
+ Tuple of (reasoning_content_delta, final_message)
130
+ - During streaming: (reasoning_content_delta, None)
131
+ - At the end: (None, final_message)
132
+ """
133
+ from agno.run.agent import RunEvent
134
+
135
+ # Update system message role to "system"
136
+ for message in messages:
137
+ if message.role == "developer":
138
+ message.role = "system"
139
+
140
+ reasoning_content: str = ""
141
+
142
+ try:
143
+ async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
144
+ if hasattr(event, "event"):
145
+ if event.event == RunEvent.run_content:
146
+ # Stream reasoning content as it arrives
147
+ if hasattr(event, "reasoning_content") and event.reasoning_content:
148
+ reasoning_content += event.reasoning_content
149
+ yield (event.reasoning_content, None)
150
+ elif event.event == RunEvent.run_completed:
151
+ pass
152
+ except Exception as e:
153
+ logger.warning(f"Reasoning error: {e}")
154
+ return
155
+
156
+ # Yield final message
157
+ if reasoning_content:
158
+ final_message = Message(
159
+ role="assistant",
160
+ content=f"<thinking>\n{reasoning_content}\n</thinking>",
161
+ reasoning_content=reasoning_content,
162
+ )
163
+ yield (None, final_message)
agno/reasoning/default.py CHANGED
@@ -1,10 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from textwrap import dedent
4
- from typing import Any, Callable, Dict, List, Literal, Optional, Union
4
+ from typing import Callable, Dict, List, Literal, Optional, Union
5
5
 
6
6
  from agno.models.base import Model
7
7
  from agno.reasoning.step import ReasoningSteps
8
+ from agno.run.base import RunContext
8
9
  from agno.tools import Toolkit
9
10
  from agno.tools.function import Function
10
11
 
@@ -19,9 +20,7 @@ def get_default_reasoning_agent(
19
20
  telemetry: bool = True,
20
21
  debug_mode: bool = False,
21
22
  debug_level: Literal[1, 2] = 1,
22
- session_state: Optional[Dict[str, Any]] = None,
23
- dependencies: Optional[Dict[str, Any]] = None,
24
- metadata: Optional[Dict[str, Any]] = None,
23
+ run_context: Optional[RunContext] = None,
25
24
  ) -> Optional["Agent"]: # type: ignore # noqa: F821
26
25
  from agno.agent import Agent
27
26
 
@@ -89,9 +88,9 @@ def get_default_reasoning_agent(
89
88
  telemetry=telemetry,
90
89
  debug_mode=debug_mode,
91
90
  debug_level=debug_level,
92
- session_state=session_state,
93
- dependencies=dependencies,
94
- metadata=metadata,
91
+ session_state=run_context.session_state if run_context else None,
92
+ dependencies=run_context.dependencies if run_context else None,
93
+ metadata=run_context.metadata if run_context else None,
95
94
  )
96
95
 
97
96
  return agent
agno/reasoning/gemini.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import List, Optional
3
+ from typing import AsyncIterator, Iterator, List, Optional, Tuple
4
4
 
5
5
  from agno.models.base import Model
6
6
  from agno.models.message import Message
@@ -13,9 +13,13 @@ def is_gemini_reasoning_model(reasoning_model: Model) -> bool:
13
13
  if not is_gemini_class:
14
14
  return False
15
15
 
16
- # Check if it's a Gemini 2.5+ model (supports thinking)
16
+ # Check if it's a Gemini model with thinking support
17
+ # - Gemini 2.5+ models support thinking
18
+ # - Gemini 3+ models support thinking (including DeepThink variants)
17
19
  model_id = reasoning_model.id.lower()
18
- has_thinking_support = "2.5" in model_id
20
+ has_thinking_support = (
21
+ "2.5" in model_id or "3.0" in model_id or "3.5" in model_id or "deepthink" in model_id or "gemini-3" in model_id
22
+ )
19
23
 
20
24
  # Also check if thinking parameters are set
21
25
  # Note: thinking_budget=0 explicitly disables thinking mode per Google's API docs
@@ -71,3 +75,83 @@ async def aget_gemini_reasoning(reasoning_agent: "Agent", messages: List[Message
71
75
  return Message(
72
76
  role="assistant", content=f"<thinking>\n{reasoning_content}\n</thinking>", reasoning_content=reasoning_content
73
77
  )
78
+
79
+
80
+ def get_gemini_reasoning_stream(
81
+ reasoning_agent: "Agent", # type: ignore # noqa: F821
82
+ messages: List[Message],
83
+ ) -> Iterator[Tuple[Optional[str], Optional[Message]]]:
84
+ """
85
+ Stream reasoning content from Gemini model.
86
+
87
+ Yields:
88
+ Tuple of (reasoning_content_delta, final_message)
89
+ - During streaming: (reasoning_content_delta, None)
90
+ - At the end: (None, final_message)
91
+ """
92
+ from agno.run.agent import RunEvent
93
+
94
+ reasoning_content: str = ""
95
+
96
+ try:
97
+ for event in reasoning_agent.run(input=messages, stream=True, stream_events=True):
98
+ if hasattr(event, "event"):
99
+ if event.event == RunEvent.run_content:
100
+ # Stream reasoning content as it arrives
101
+ if hasattr(event, "reasoning_content") and event.reasoning_content:
102
+ reasoning_content += event.reasoning_content
103
+ yield (event.reasoning_content, None)
104
+ elif event.event == RunEvent.run_completed:
105
+ pass
106
+ except Exception as e:
107
+ logger.warning(f"Reasoning error: {e}")
108
+ return
109
+
110
+ # Yield final message
111
+ if reasoning_content:
112
+ final_message = Message(
113
+ role="assistant",
114
+ content=f"<thinking>\n{reasoning_content}\n</thinking>",
115
+ reasoning_content=reasoning_content,
116
+ )
117
+ yield (None, final_message)
118
+
119
+
120
+ async def aget_gemini_reasoning_stream(
121
+ reasoning_agent: "Agent", # type: ignore # noqa: F821
122
+ messages: List[Message],
123
+ ) -> AsyncIterator[Tuple[Optional[str], Optional[Message]]]:
124
+ """
125
+ Stream reasoning content from Gemini model asynchronously.
126
+
127
+ Yields:
128
+ Tuple of (reasoning_content_delta, final_message)
129
+ - During streaming: (reasoning_content_delta, None)
130
+ - At the end: (None, final_message)
131
+ """
132
+ from agno.run.agent import RunEvent
133
+
134
+ reasoning_content: str = ""
135
+
136
+ try:
137
+ async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
138
+ if hasattr(event, "event"):
139
+ if event.event == RunEvent.run_content:
140
+ # Stream reasoning content as it arrives
141
+ if hasattr(event, "reasoning_content") and event.reasoning_content:
142
+ reasoning_content += event.reasoning_content
143
+ yield (event.reasoning_content, None)
144
+ elif event.event == RunEvent.run_completed:
145
+ pass
146
+ except Exception as e:
147
+ logger.warning(f"Reasoning error: {e}")
148
+ return
149
+
150
+ # Yield final message
151
+ if reasoning_content:
152
+ final_message = Message(
153
+ role="assistant",
154
+ content=f"<thinking>\n{reasoning_content}\n</thinking>",
155
+ reasoning_content=reasoning_content,
156
+ )
157
+ yield (None, final_message)
agno/reasoning/groq.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import List, Optional
3
+ from typing import AsyncIterator, Iterator, List, Optional, Tuple
4
4
 
5
5
  from agno.models.base import Model
6
6
  from agno.models.message import Message
@@ -8,7 +8,12 @@ from agno.utils.log import logger
8
8
 
9
9
 
10
10
  def is_groq_reasoning_model(reasoning_model: Model) -> bool:
11
- return reasoning_model.__class__.__name__ == "Groq" and "deepseek" in reasoning_model.id.lower()
11
+ return reasoning_model.__class__.__name__ == "Groq" and (
12
+ "deepseek" in reasoning_model.id.lower()
13
+ or "openai/gpt-oss-20b" in reasoning_model.id.lower()
14
+ or "openai/gpt-oss-120b" in reasoning_model.id.lower()
15
+ or "qwen/qwen3-32b" in reasoning_model.id.lower()
16
+ )
12
17
 
13
18
 
14
19
  def get_groq_reasoning(reasoning_agent: "Agent", messages: List[Message]) -> Optional[Message]: # type: ignore # noqa: F821
@@ -69,3 +74,105 @@ async def aget_groq_reasoning(reasoning_agent: "Agent", messages: List[Message])
69
74
  return Message(
70
75
  role="assistant", content=f"<thinking>\n{reasoning_content}\n</thinking>", reasoning_content=reasoning_content
71
76
  )
77
+
78
+
79
+ def get_groq_reasoning_stream(
80
+ reasoning_agent: "Agent", # type: ignore # noqa: F821
81
+ messages: List[Message],
82
+ ) -> Iterator[Tuple[Optional[str], Optional[Message]]]:
83
+ """
84
+ Stream reasoning content from Groq model.
85
+
86
+ For DeepSeek models on Groq, we use the main content output as reasoning content.
87
+
88
+ Yields:
89
+ Tuple of (reasoning_content_delta, final_message)
90
+ - During streaming: (reasoning_content_delta, None)
91
+ - At the end: (None, final_message)
92
+ """
93
+ from agno.run.agent import RunEvent
94
+
95
+ # Update system message role to "system"
96
+ for message in messages:
97
+ if message.role == "developer":
98
+ message.role = "system"
99
+
100
+ reasoning_content: str = ""
101
+
102
+ try:
103
+ for event in reasoning_agent.run(input=messages, stream=True, stream_events=True):
104
+ if hasattr(event, "event"):
105
+ if event.event == RunEvent.run_content:
106
+ # Check for reasoning_content attribute first (native reasoning)
107
+ if hasattr(event, "reasoning_content") and event.reasoning_content:
108
+ reasoning_content += event.reasoning_content
109
+ yield (event.reasoning_content, None)
110
+ # Use the main content as reasoning content
111
+ elif hasattr(event, "content") and event.content:
112
+ reasoning_content += event.content
113
+ yield (event.content, None)
114
+ elif event.event == RunEvent.run_completed:
115
+ pass
116
+ except Exception as e:
117
+ logger.warning(f"Reasoning error: {e}")
118
+ return
119
+
120
+ # Yield final message
121
+ if reasoning_content:
122
+ final_message = Message(
123
+ role="assistant",
124
+ content=f"<thinking>\n{reasoning_content}\n</thinking>",
125
+ reasoning_content=reasoning_content,
126
+ )
127
+ yield (None, final_message)
128
+
129
+
130
+ async def aget_groq_reasoning_stream(
131
+ reasoning_agent: "Agent", # type: ignore # noqa: F821
132
+ messages: List[Message],
133
+ ) -> AsyncIterator[Tuple[Optional[str], Optional[Message]]]:
134
+ """
135
+ Stream reasoning content from Groq model asynchronously.
136
+
137
+ For DeepSeek models on Groq, we use the main content output as reasoning content.
138
+
139
+ Yields:
140
+ Tuple of (reasoning_content_delta, final_message)
141
+ - During streaming: (reasoning_content_delta, None)
142
+ - At the end: (None, final_message)
143
+ """
144
+ from agno.run.agent import RunEvent
145
+
146
+ # Update system message role to "system"
147
+ for message in messages:
148
+ if message.role == "developer":
149
+ message.role = "system"
150
+
151
+ reasoning_content: str = ""
152
+
153
+ try:
154
+ async for event in reasoning_agent.arun(input=messages, stream=True, stream_events=True):
155
+ if hasattr(event, "event"):
156
+ if event.event == RunEvent.run_content:
157
+ # Check for reasoning_content attribute first (native reasoning)
158
+ if hasattr(event, "reasoning_content") and event.reasoning_content:
159
+ reasoning_content += event.reasoning_content
160
+ yield (event.reasoning_content, None)
161
+ # Use the main content as reasoning content
162
+ elif hasattr(event, "content") and event.content:
163
+ reasoning_content += event.content
164
+ yield (event.content, None)
165
+ elif event.event == RunEvent.run_completed:
166
+ pass
167
+ except Exception as e:
168
+ logger.warning(f"Reasoning error: {e}")
169
+ return
170
+
171
+ # Yield final message
172
+ if reasoning_content:
173
+ final_message = Message(
174
+ role="assistant",
175
+ content=f"<thinking>\n{reasoning_content}\n</thinking>",
176
+ reasoning_content=reasoning_content,
177
+ )
178
+ yield (None, final_message)
agno/reasoning/helpers.py CHANGED
@@ -1,8 +1,9 @@
1
- from typing import Any, Dict, List, Literal, Optional
1
+ from typing import List, Literal, Optional
2
2
 
3
3
  from agno.models.base import Model
4
4
  from agno.models.message import Message
5
5
  from agno.reasoning.step import NextAction, ReasoningStep
6
+ from agno.run.base import RunContext
6
7
  from agno.run.messages import RunMessages
7
8
  from agno.utils.log import logger
8
9
 
@@ -12,9 +13,7 @@ def get_reasoning_agent(
12
13
  telemetry: bool = False,
13
14
  debug_mode: bool = False,
14
15
  debug_level: Literal[1, 2] = 1,
15
- session_state: Optional[Dict[str, Any]] = None,
16
- dependencies: Optional[Dict[str, Any]] = None,
17
- metadata: Optional[Dict[str, Any]] = None,
16
+ run_context: Optional[RunContext] = None,
18
17
  ) -> "Agent": # type: ignore # noqa: F821
19
18
  from agno.agent import Agent
20
19
 
@@ -23,9 +22,9 @@ def get_reasoning_agent(
23
22
  telemetry=telemetry,
24
23
  debug_mode=debug_mode,
25
24
  debug_level=debug_level,
26
- session_state=session_state,
27
- dependencies=dependencies,
28
- metadata=metadata,
25
+ session_state=run_context.session_state if run_context else None,
26
+ dependencies=run_context.dependencies if run_context else None,
27
+ metadata=run_context.metadata if run_context else None,
29
28
  )
30
29
 
31
30