agno 1.8.0__py3-none-any.whl → 2.0.0a1__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 (583) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +2781 -4126
  4. agno/api/agent.py +9 -65
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +6 -17
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -41
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +5 -21
  11. agno/api/schemas/evals.py +7 -16
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +5 -21
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +11 -7
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +9 -64
  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/db/__init__.py +24 -0
  25. agno/db/base.py +245 -0
  26. agno/db/dynamo/__init__.py +3 -0
  27. agno/db/dynamo/dynamo.py +1749 -0
  28. agno/db/dynamo/schemas.py +278 -0
  29. agno/db/dynamo/utils.py +684 -0
  30. agno/db/firestore/__init__.py +3 -0
  31. agno/db/firestore/firestore.py +1438 -0
  32. agno/db/firestore/schemas.py +130 -0
  33. agno/db/firestore/utils.py +278 -0
  34. agno/db/gcs_json/__init__.py +3 -0
  35. agno/db/gcs_json/gcs_json_db.py +1001 -0
  36. agno/db/gcs_json/utils.py +194 -0
  37. agno/db/in_memory/__init__.py +3 -0
  38. agno/db/in_memory/in_memory_db.py +888 -0
  39. agno/db/in_memory/utils.py +172 -0
  40. agno/db/json/__init__.py +3 -0
  41. agno/db/json/json_db.py +1051 -0
  42. agno/db/json/utils.py +196 -0
  43. agno/db/migrations/v1_to_v2.py +162 -0
  44. agno/db/mongo/__init__.py +3 -0
  45. agno/db/mongo/mongo.py +1417 -0
  46. agno/db/mongo/schemas.py +77 -0
  47. agno/db/mongo/utils.py +204 -0
  48. agno/db/mysql/__init__.py +3 -0
  49. agno/db/mysql/mysql.py +1719 -0
  50. agno/db/mysql/schemas.py +124 -0
  51. agno/db/mysql/utils.py +298 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1720 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +281 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1371 -0
  58. agno/db/redis/schemas.py +109 -0
  59. agno/db/redis/utils.py +288 -0
  60. agno/db/schemas/__init__.py +3 -0
  61. agno/db/schemas/evals.py +33 -0
  62. agno/db/schemas/knowledge.py +40 -0
  63. agno/db/schemas/memory.py +46 -0
  64. agno/db/singlestore/__init__.py +3 -0
  65. agno/db/singlestore/schemas.py +116 -0
  66. agno/db/singlestore/singlestore.py +1722 -0
  67. agno/db/singlestore/utils.py +327 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1680 -0
  71. agno/db/sqlite/utils.py +269 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +142 -43
  75. agno/eval/performance.py +88 -23
  76. agno/eval/reliability.py +73 -20
  77. agno/eval/utils.py +23 -13
  78. agno/integrations/discord/__init__.py +3 -0
  79. agno/{app → integrations}/discord/client.py +10 -10
  80. agno/knowledge/__init__.py +2 -2
  81. agno/{document → knowledge}/chunking/agentic.py +2 -2
  82. agno/{document → knowledge}/chunking/document.py +2 -2
  83. agno/{document → knowledge}/chunking/fixed.py +3 -3
  84. agno/{document → knowledge}/chunking/markdown.py +2 -2
  85. agno/{document → knowledge}/chunking/recursive.py +2 -2
  86. agno/{document → knowledge}/chunking/row.py +2 -2
  87. agno/knowledge/chunking/semantic.py +59 -0
  88. agno/knowledge/chunking/strategy.py +121 -0
  89. agno/knowledge/content.py +74 -0
  90. agno/knowledge/document/__init__.py +5 -0
  91. agno/{document → knowledge/document}/base.py +12 -2
  92. agno/knowledge/embedder/__init__.py +5 -0
  93. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  94. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  95. agno/{embedder → knowledge/embedder}/base.py +6 -0
  96. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  97. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  98. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  99. agno/{embedder → knowledge/embedder}/google.py +74 -1
  100. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  101. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  102. agno/knowledge/embedder/langdb.py +22 -0
  103. agno/knowledge/embedder/mistral.py +139 -0
  104. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  105. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  106. agno/knowledge/embedder/openai.py +223 -0
  107. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  108. agno/{embedder → knowledge/embedder}/together.py +1 -1
  109. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  110. agno/knowledge/knowledge.py +1515 -0
  111. agno/knowledge/reader/__init__.py +7 -0
  112. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  113. agno/knowledge/reader/base.py +88 -0
  114. agno/{document → knowledge}/reader/csv_reader.py +68 -15
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/knowledge/reader/gcs_reader.py +67 -0
  118. agno/{document → knowledge}/reader/json_reader.py +30 -9
  119. agno/{document → knowledge}/reader/markdown_reader.py +36 -9
  120. agno/{document → knowledge}/reader/pdf_reader.py +79 -21
  121. agno/knowledge/reader/reader_factory.py +275 -0
  122. agno/knowledge/reader/s3_reader.py +171 -0
  123. agno/{document → knowledge}/reader/text_reader.py +31 -10
  124. agno/knowledge/reader/url_reader.py +84 -0
  125. agno/knowledge/reader/web_search_reader.py +389 -0
  126. agno/{document → knowledge}/reader/website_reader.py +37 -10
  127. agno/knowledge/reader/wikipedia_reader.py +59 -0
  128. agno/knowledge/reader/youtube_reader.py +78 -0
  129. agno/knowledge/remote_content/remote_content.py +88 -0
  130. agno/{reranker → knowledge/reranker}/base.py +1 -1
  131. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  132. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  133. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  134. agno/knowledge/types.py +30 -0
  135. agno/knowledge/utils.py +169 -0
  136. agno/media.py +2 -2
  137. agno/memory/__init__.py +2 -10
  138. agno/memory/manager.py +1003 -148
  139. agno/models/aimlapi/__init__.py +2 -2
  140. agno/models/aimlapi/aimlapi.py +6 -6
  141. agno/models/anthropic/claude.py +129 -82
  142. agno/models/aws/bedrock.py +107 -175
  143. agno/models/aws/claude.py +64 -18
  144. agno/models/azure/ai_foundry.py +73 -23
  145. agno/models/base.py +347 -287
  146. agno/models/cerebras/cerebras.py +84 -27
  147. agno/models/cohere/chat.py +106 -98
  148. agno/models/dashscope/dashscope.py +14 -5
  149. agno/models/google/gemini.py +123 -53
  150. agno/models/groq/groq.py +97 -35
  151. agno/models/huggingface/huggingface.py +92 -27
  152. agno/models/ibm/watsonx.py +72 -13
  153. agno/models/litellm/chat.py +85 -13
  154. agno/models/message.py +38 -144
  155. agno/models/meta/llama.py +85 -49
  156. agno/models/metrics.py +120 -0
  157. agno/models/mistral/mistral.py +90 -21
  158. agno/models/ollama/__init__.py +0 -2
  159. agno/models/ollama/chat.py +84 -46
  160. agno/models/openai/chat.py +135 -27
  161. agno/models/openai/responses.py +233 -115
  162. agno/models/perplexity/perplexity.py +26 -2
  163. agno/models/portkey/portkey.py +0 -7
  164. agno/models/response.py +14 -8
  165. agno/models/utils.py +20 -0
  166. agno/models/vercel/__init__.py +2 -2
  167. agno/models/vercel/v0.py +1 -1
  168. agno/models/vllm/__init__.py +2 -2
  169. agno/models/vllm/vllm.py +3 -3
  170. agno/models/xai/xai.py +10 -10
  171. agno/os/__init__.py +3 -0
  172. agno/os/app.py +393 -0
  173. agno/os/auth.py +47 -0
  174. agno/os/config.py +103 -0
  175. agno/os/interfaces/agui/__init__.py +3 -0
  176. agno/os/interfaces/agui/agui.py +31 -0
  177. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  178. agno/{app → os/interfaces}/agui/utils.py +65 -28
  179. agno/os/interfaces/base.py +21 -0
  180. agno/os/interfaces/slack/__init__.py +3 -0
  181. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  182. agno/os/interfaces/slack/slack.py +33 -0
  183. agno/os/interfaces/whatsapp/__init__.py +3 -0
  184. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  185. agno/os/interfaces/whatsapp/whatsapp.py +30 -0
  186. agno/os/router.py +843 -0
  187. agno/os/routers/__init__.py +3 -0
  188. agno/os/routers/evals/__init__.py +3 -0
  189. agno/os/routers/evals/evals.py +204 -0
  190. agno/os/routers/evals/schemas.py +142 -0
  191. agno/os/routers/evals/utils.py +161 -0
  192. agno/os/routers/knowledge/__init__.py +3 -0
  193. agno/os/routers/knowledge/knowledge.py +413 -0
  194. agno/os/routers/knowledge/schemas.py +118 -0
  195. agno/os/routers/memory/__init__.py +3 -0
  196. agno/os/routers/memory/memory.py +179 -0
  197. agno/os/routers/memory/schemas.py +58 -0
  198. agno/os/routers/metrics/__init__.py +3 -0
  199. agno/os/routers/metrics/metrics.py +58 -0
  200. agno/os/routers/metrics/schemas.py +47 -0
  201. agno/os/routers/session/__init__.py +3 -0
  202. agno/os/routers/session/session.py +163 -0
  203. agno/os/schema.py +892 -0
  204. agno/{app/playground → os}/settings.py +8 -15
  205. agno/os/utils.py +270 -0
  206. agno/reasoning/azure_ai_foundry.py +4 -4
  207. agno/reasoning/deepseek.py +4 -4
  208. agno/reasoning/default.py +6 -11
  209. agno/reasoning/groq.py +4 -4
  210. agno/reasoning/helpers.py +4 -6
  211. agno/reasoning/ollama.py +4 -4
  212. agno/reasoning/openai.py +4 -4
  213. agno/run/{response.py → agent.py} +144 -72
  214. agno/run/base.py +44 -58
  215. agno/run/cancel.py +83 -0
  216. agno/run/team.py +133 -77
  217. agno/run/workflow.py +537 -12
  218. agno/session/__init__.py +10 -0
  219. agno/session/agent.py +244 -0
  220. agno/session/summary.py +225 -0
  221. agno/session/team.py +262 -0
  222. agno/{storage/session/v2 → session}/workflow.py +47 -24
  223. agno/team/__init__.py +15 -16
  224. agno/team/team.py +2967 -4243
  225. agno/tools/agentql.py +14 -5
  226. agno/tools/airflow.py +9 -4
  227. agno/tools/api.py +7 -3
  228. agno/tools/apify.py +2 -46
  229. agno/tools/arxiv.py +8 -3
  230. agno/tools/aws_lambda.py +7 -5
  231. agno/tools/aws_ses.py +7 -1
  232. agno/tools/baidusearch.py +4 -1
  233. agno/tools/bitbucket.py +4 -4
  234. agno/tools/brandfetch.py +14 -11
  235. agno/tools/bravesearch.py +4 -1
  236. agno/tools/brightdata.py +42 -22
  237. agno/tools/browserbase.py +13 -4
  238. agno/tools/calcom.py +12 -10
  239. agno/tools/calculator.py +10 -27
  240. agno/tools/cartesia.py +18 -13
  241. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  242. agno/tools/confluence.py +71 -18
  243. agno/tools/crawl4ai.py +7 -1
  244. agno/tools/csv_toolkit.py +9 -8
  245. agno/tools/dalle.py +18 -11
  246. agno/tools/daytona.py +13 -16
  247. agno/tools/decorator.py +6 -3
  248. agno/tools/desi_vocal.py +16 -7
  249. agno/tools/discord.py +11 -8
  250. agno/tools/docker.py +30 -42
  251. agno/tools/duckdb.py +34 -53
  252. agno/tools/duckduckgo.py +8 -7
  253. agno/tools/e2b.py +62 -62
  254. agno/tools/eleven_labs.py +35 -28
  255. agno/tools/email.py +4 -1
  256. agno/tools/evm.py +7 -1
  257. agno/tools/exa.py +19 -14
  258. agno/tools/fal.py +29 -29
  259. agno/tools/file.py +9 -8
  260. agno/tools/financial_datasets.py +25 -44
  261. agno/tools/firecrawl.py +22 -22
  262. agno/tools/function.py +68 -17
  263. agno/tools/giphy.py +22 -10
  264. agno/tools/github.py +48 -126
  265. agno/tools/gmail.py +46 -62
  266. agno/tools/google_bigquery.py +7 -6
  267. agno/tools/google_maps.py +11 -26
  268. agno/tools/googlesearch.py +7 -2
  269. agno/tools/googlesheets.py +21 -17
  270. agno/tools/hackernews.py +9 -5
  271. agno/tools/jina.py +5 -4
  272. agno/tools/jira.py +18 -9
  273. agno/tools/knowledge.py +31 -32
  274. agno/tools/linear.py +18 -33
  275. agno/tools/linkup.py +5 -1
  276. agno/tools/local_file_system.py +8 -5
  277. agno/tools/lumalab.py +31 -19
  278. agno/tools/mem0.py +18 -12
  279. agno/tools/memori.py +14 -10
  280. agno/tools/mlx_transcribe.py +3 -2
  281. agno/tools/models/azure_openai.py +32 -14
  282. agno/tools/models/gemini.py +58 -31
  283. agno/tools/models/groq.py +29 -20
  284. agno/tools/models/nebius.py +27 -11
  285. agno/tools/models_labs.py +39 -15
  286. agno/tools/moviepy_video.py +7 -6
  287. agno/tools/neo4j.py +134 -0
  288. agno/tools/newspaper.py +7 -2
  289. agno/tools/newspaper4k.py +8 -3
  290. agno/tools/openai.py +57 -26
  291. agno/tools/openbb.py +12 -11
  292. agno/tools/opencv.py +62 -46
  293. agno/tools/openweather.py +14 -12
  294. agno/tools/pandas.py +11 -3
  295. agno/tools/postgres.py +4 -12
  296. agno/tools/pubmed.py +4 -1
  297. agno/tools/python.py +9 -22
  298. agno/tools/reasoning.py +35 -27
  299. agno/tools/reddit.py +11 -26
  300. agno/tools/replicate.py +54 -41
  301. agno/tools/resend.py +4 -1
  302. agno/tools/scrapegraph.py +15 -14
  303. agno/tools/searxng.py +10 -23
  304. agno/tools/serpapi.py +6 -3
  305. agno/tools/serper.py +13 -4
  306. agno/tools/shell.py +9 -2
  307. agno/tools/slack.py +12 -11
  308. agno/tools/sleep.py +3 -2
  309. agno/tools/spider.py +24 -4
  310. agno/tools/sql.py +7 -6
  311. agno/tools/tavily.py +6 -4
  312. agno/tools/telegram.py +12 -4
  313. agno/tools/todoist.py +11 -31
  314. agno/tools/toolkit.py +1 -1
  315. agno/tools/trafilatura.py +22 -6
  316. agno/tools/trello.py +9 -22
  317. agno/tools/twilio.py +10 -3
  318. agno/tools/user_control_flow.py +6 -1
  319. agno/tools/valyu.py +34 -5
  320. agno/tools/visualization.py +19 -28
  321. agno/tools/webbrowser.py +4 -3
  322. agno/tools/webex.py +11 -7
  323. agno/tools/website.py +15 -46
  324. agno/tools/webtools.py +12 -4
  325. agno/tools/whatsapp.py +5 -9
  326. agno/tools/wikipedia.py +20 -13
  327. agno/tools/x.py +14 -13
  328. agno/tools/yfinance.py +13 -40
  329. agno/tools/youtube.py +26 -20
  330. agno/tools/zendesk.py +7 -2
  331. agno/tools/zep.py +10 -7
  332. agno/tools/zoom.py +10 -9
  333. agno/utils/common.py +1 -19
  334. agno/utils/events.py +95 -118
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/location.py +2 -2
  337. agno/utils/log.py +2 -2
  338. agno/utils/mcp.py +11 -5
  339. agno/utils/media.py +39 -0
  340. agno/utils/message.py +12 -1
  341. agno/utils/models/claude.py +6 -4
  342. agno/utils/models/mistral.py +8 -7
  343. agno/utils/models/schema_utils.py +3 -3
  344. agno/utils/pprint.py +33 -32
  345. agno/utils/print_response/agent.py +779 -0
  346. agno/utils/print_response/team.py +1565 -0
  347. agno/utils/print_response/workflow.py +1451 -0
  348. agno/utils/prompts.py +14 -14
  349. agno/utils/reasoning.py +87 -0
  350. agno/utils/response.py +42 -42
  351. agno/utils/string.py +8 -22
  352. agno/utils/team.py +50 -0
  353. agno/utils/timer.py +2 -2
  354. agno/vectordb/base.py +33 -21
  355. agno/vectordb/cassandra/cassandra.py +287 -23
  356. agno/vectordb/chroma/chromadb.py +482 -59
  357. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  358. agno/vectordb/couchbase/couchbase.py +309 -29
  359. agno/vectordb/lancedb/lance_db.py +360 -21
  360. agno/vectordb/langchaindb/__init__.py +5 -0
  361. agno/vectordb/langchaindb/langchaindb.py +145 -0
  362. agno/vectordb/lightrag/__init__.py +5 -0
  363. agno/vectordb/lightrag/lightrag.py +374 -0
  364. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  365. agno/vectordb/milvus/milvus.py +242 -32
  366. agno/vectordb/mongodb/mongodb.py +200 -24
  367. agno/vectordb/pgvector/pgvector.py +319 -37
  368. agno/vectordb/pineconedb/pineconedb.py +221 -27
  369. agno/vectordb/qdrant/qdrant.py +356 -14
  370. agno/vectordb/singlestore/singlestore.py +286 -29
  371. agno/vectordb/surrealdb/surrealdb.py +187 -7
  372. agno/vectordb/upstashdb/upstashdb.py +342 -26
  373. agno/vectordb/weaviate/weaviate.py +227 -165
  374. agno/workflow/__init__.py +17 -13
  375. agno/workflow/{v2/condition.py → condition.py} +135 -32
  376. agno/workflow/{v2/loop.py → loop.py} +115 -28
  377. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  378. agno/workflow/{v2/router.py → router.py} +133 -32
  379. agno/workflow/{v2/step.py → step.py} +200 -42
  380. agno/workflow/{v2/steps.py → steps.py} +147 -66
  381. agno/workflow/types.py +482 -0
  382. agno/workflow/workflow.py +2394 -696
  383. agno-2.0.0a1.dist-info/METADATA +355 -0
  384. agno-2.0.0a1.dist-info/RECORD +514 -0
  385. agno/agent/metrics.py +0 -107
  386. agno/api/app.py +0 -35
  387. agno/api/playground.py +0 -92
  388. agno/api/schemas/app.py +0 -12
  389. agno/api/schemas/playground.py +0 -22
  390. agno/api/schemas/user.py +0 -35
  391. agno/api/schemas/workspace.py +0 -46
  392. agno/api/user.py +0 -160
  393. agno/api/workflows.py +0 -33
  394. agno/api/workspace.py +0 -175
  395. agno/app/agui/__init__.py +0 -3
  396. agno/app/agui/app.py +0 -17
  397. agno/app/agui/sync_router.py +0 -120
  398. agno/app/base.py +0 -186
  399. agno/app/discord/__init__.py +0 -3
  400. agno/app/fastapi/__init__.py +0 -3
  401. agno/app/fastapi/app.py +0 -107
  402. agno/app/fastapi/async_router.py +0 -457
  403. agno/app/fastapi/sync_router.py +0 -448
  404. agno/app/playground/app.py +0 -228
  405. agno/app/playground/async_router.py +0 -1050
  406. agno/app/playground/deploy.py +0 -249
  407. agno/app/playground/operator.py +0 -183
  408. agno/app/playground/schemas.py +0 -220
  409. agno/app/playground/serve.py +0 -55
  410. agno/app/playground/sync_router.py +0 -1042
  411. agno/app/playground/utils.py +0 -46
  412. agno/app/settings.py +0 -15
  413. agno/app/slack/__init__.py +0 -3
  414. agno/app/slack/app.py +0 -19
  415. agno/app/slack/sync_router.py +0 -92
  416. agno/app/utils.py +0 -54
  417. agno/app/whatsapp/__init__.py +0 -3
  418. agno/app/whatsapp/app.py +0 -15
  419. agno/app/whatsapp/sync_router.py +0 -197
  420. agno/cli/auth_server.py +0 -249
  421. agno/cli/config.py +0 -274
  422. agno/cli/console.py +0 -88
  423. agno/cli/credentials.py +0 -23
  424. agno/cli/entrypoint.py +0 -571
  425. agno/cli/operator.py +0 -357
  426. agno/cli/settings.py +0 -96
  427. agno/cli/ws/ws_cli.py +0 -817
  428. agno/constants.py +0 -13
  429. agno/document/__init__.py +0 -5
  430. agno/document/chunking/semantic.py +0 -45
  431. agno/document/chunking/strategy.py +0 -31
  432. agno/document/reader/__init__.py +0 -5
  433. agno/document/reader/base.py +0 -47
  434. agno/document/reader/docx_reader.py +0 -60
  435. agno/document/reader/gcs/pdf_reader.py +0 -44
  436. agno/document/reader/s3/pdf_reader.py +0 -59
  437. agno/document/reader/s3/text_reader.py +0 -63
  438. agno/document/reader/url_reader.py +0 -59
  439. agno/document/reader/youtube_reader.py +0 -58
  440. agno/embedder/__init__.py +0 -5
  441. agno/embedder/langdb.py +0 -80
  442. agno/embedder/mistral.py +0 -82
  443. agno/embedder/openai.py +0 -78
  444. agno/file/__init__.py +0 -5
  445. agno/file/file.py +0 -16
  446. agno/file/local/csv.py +0 -32
  447. agno/file/local/txt.py +0 -19
  448. agno/infra/app.py +0 -240
  449. agno/infra/base.py +0 -144
  450. agno/infra/context.py +0 -20
  451. agno/infra/db_app.py +0 -52
  452. agno/infra/resource.py +0 -205
  453. agno/infra/resources.py +0 -55
  454. agno/knowledge/agent.py +0 -698
  455. agno/knowledge/arxiv.py +0 -33
  456. agno/knowledge/combined.py +0 -36
  457. agno/knowledge/csv.py +0 -144
  458. agno/knowledge/csv_url.py +0 -124
  459. agno/knowledge/document.py +0 -223
  460. agno/knowledge/docx.py +0 -137
  461. agno/knowledge/firecrawl.py +0 -34
  462. agno/knowledge/gcs/__init__.py +0 -0
  463. agno/knowledge/gcs/base.py +0 -39
  464. agno/knowledge/gcs/pdf.py +0 -125
  465. agno/knowledge/json.py +0 -137
  466. agno/knowledge/langchain.py +0 -71
  467. agno/knowledge/light_rag.py +0 -273
  468. agno/knowledge/llamaindex.py +0 -66
  469. agno/knowledge/markdown.py +0 -154
  470. agno/knowledge/pdf.py +0 -164
  471. agno/knowledge/pdf_bytes.py +0 -42
  472. agno/knowledge/pdf_url.py +0 -148
  473. agno/knowledge/s3/__init__.py +0 -0
  474. agno/knowledge/s3/base.py +0 -64
  475. agno/knowledge/s3/pdf.py +0 -33
  476. agno/knowledge/s3/text.py +0 -34
  477. agno/knowledge/text.py +0 -141
  478. agno/knowledge/url.py +0 -46
  479. agno/knowledge/website.py +0 -179
  480. agno/knowledge/wikipedia.py +0 -32
  481. agno/knowledge/youtube.py +0 -35
  482. agno/memory/agent.py +0 -423
  483. agno/memory/classifier.py +0 -104
  484. agno/memory/db/__init__.py +0 -5
  485. agno/memory/db/base.py +0 -42
  486. agno/memory/db/mongodb.py +0 -189
  487. agno/memory/db/postgres.py +0 -203
  488. agno/memory/db/sqlite.py +0 -193
  489. agno/memory/memory.py +0 -22
  490. agno/memory/row.py +0 -36
  491. agno/memory/summarizer.py +0 -201
  492. agno/memory/summary.py +0 -19
  493. agno/memory/team.py +0 -415
  494. agno/memory/v2/__init__.py +0 -2
  495. agno/memory/v2/db/__init__.py +0 -1
  496. agno/memory/v2/db/base.py +0 -42
  497. agno/memory/v2/db/firestore.py +0 -339
  498. agno/memory/v2/db/mongodb.py +0 -196
  499. agno/memory/v2/db/postgres.py +0 -214
  500. agno/memory/v2/db/redis.py +0 -187
  501. agno/memory/v2/db/schema.py +0 -54
  502. agno/memory/v2/db/sqlite.py +0 -209
  503. agno/memory/v2/manager.py +0 -437
  504. agno/memory/v2/memory.py +0 -1097
  505. agno/memory/v2/schema.py +0 -55
  506. agno/memory/v2/summarizer.py +0 -215
  507. agno/memory/workflow.py +0 -38
  508. agno/models/ollama/tools.py +0 -430
  509. agno/models/qwen/__init__.py +0 -5
  510. agno/playground/__init__.py +0 -10
  511. agno/playground/deploy.py +0 -3
  512. agno/playground/playground.py +0 -3
  513. agno/playground/serve.py +0 -3
  514. agno/playground/settings.py +0 -3
  515. agno/reranker/__init__.py +0 -0
  516. agno/run/v2/__init__.py +0 -0
  517. agno/run/v2/workflow.py +0 -567
  518. agno/storage/__init__.py +0 -0
  519. agno/storage/agent/__init__.py +0 -0
  520. agno/storage/agent/dynamodb.py +0 -1
  521. agno/storage/agent/json.py +0 -1
  522. agno/storage/agent/mongodb.py +0 -1
  523. agno/storage/agent/postgres.py +0 -1
  524. agno/storage/agent/singlestore.py +0 -1
  525. agno/storage/agent/sqlite.py +0 -1
  526. agno/storage/agent/yaml.py +0 -1
  527. agno/storage/base.py +0 -60
  528. agno/storage/dynamodb.py +0 -673
  529. agno/storage/firestore.py +0 -297
  530. agno/storage/gcs_json.py +0 -261
  531. agno/storage/in_memory.py +0 -234
  532. agno/storage/json.py +0 -237
  533. agno/storage/mongodb.py +0 -328
  534. agno/storage/mysql.py +0 -685
  535. agno/storage/postgres.py +0 -682
  536. agno/storage/redis.py +0 -336
  537. agno/storage/session/__init__.py +0 -16
  538. agno/storage/session/agent.py +0 -64
  539. agno/storage/session/team.py +0 -63
  540. agno/storage/session/v2/__init__.py +0 -5
  541. agno/storage/session/workflow.py +0 -61
  542. agno/storage/singlestore.py +0 -606
  543. agno/storage/sqlite.py +0 -646
  544. agno/storage/workflow/__init__.py +0 -0
  545. agno/storage/workflow/mongodb.py +0 -1
  546. agno/storage/workflow/postgres.py +0 -1
  547. agno/storage/workflow/sqlite.py +0 -1
  548. agno/storage/yaml.py +0 -241
  549. agno/tools/thinking.py +0 -73
  550. agno/utils/defaults.py +0 -57
  551. agno/utils/filesystem.py +0 -39
  552. agno/utils/git.py +0 -52
  553. agno/utils/json_io.py +0 -30
  554. agno/utils/load_env.py +0 -19
  555. agno/utils/py_io.py +0 -19
  556. agno/utils/pyproject.py +0 -18
  557. agno/utils/resource_filter.py +0 -31
  558. agno/workflow/v2/__init__.py +0 -21
  559. agno/workflow/v2/types.py +0 -357
  560. agno/workflow/v2/workflow.py +0 -3312
  561. agno/workspace/__init__.py +0 -0
  562. agno/workspace/config.py +0 -325
  563. agno/workspace/enums.py +0 -6
  564. agno/workspace/helpers.py +0 -52
  565. agno/workspace/operator.py +0 -757
  566. agno/workspace/settings.py +0 -158
  567. agno-1.8.0.dist-info/METADATA +0 -979
  568. agno-1.8.0.dist-info/RECORD +0 -565
  569. agno-1.8.0.dist-info/entry_points.txt +0 -3
  570. /agno/{app → db/migrations}/__init__.py +0 -0
  571. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  572. /agno/{cli → integrations}/__init__.py +0 -0
  573. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  574. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  575. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  576. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  577. /agno/{app → os/interfaces}/slack/security.py +0 -0
  578. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  579. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  580. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  581. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
  582. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
  583. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1565 @@
1
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Set, Union, get_args
2
+
3
+ from pydantic import BaseModel
4
+
5
+ from agno.media import Audio, File, Image, Video
6
+ from agno.models.message import Message
7
+ from agno.models.response import ToolExecution
8
+ from agno.reasoning.step import ReasoningStep
9
+ from agno.run.agent import RunEvent, RunOutput, ToolCallCompletedEvent
10
+ from agno.run.team import TeamRunEvent, TeamRunOutput, TeamRunOutputEvent
11
+ from agno.utils.log import log_warning
12
+ from agno.utils.message import get_text_from_message
13
+ from agno.utils.response import build_reasoning_step_panel, create_panel, escape_markdown_tags, format_tool_calls
14
+ from agno.utils.timer import Timer
15
+
16
+ if TYPE_CHECKING:
17
+ from agno.team.team import Team
18
+
19
+
20
+ def print_response(
21
+ team: "Team",
22
+ input: Union[List, Dict, str, Message, BaseModel, List[Message]],
23
+ console: Optional[Any] = None,
24
+ show_message: bool = True,
25
+ show_reasoning: bool = True,
26
+ show_full_reasoning: bool = False,
27
+ tags_to_include_in_markdown: Optional[Set[str]] = None,
28
+ session_id: Optional[str] = None,
29
+ session_state: Optional[Dict[str, Any]] = None,
30
+ user_id: Optional[str] = None,
31
+ audio: Optional[Sequence[Audio]] = None,
32
+ images: Optional[Sequence[Image]] = None,
33
+ videos: Optional[Sequence[Video]] = None,
34
+ files: Optional[Sequence[File]] = None,
35
+ markdown: bool = False,
36
+ knowledge_filters: Optional[Dict[str, Any]] = None,
37
+ add_history_to_context: Optional[bool] = None,
38
+ dependencies: Optional[Dict[str, Any]] = None,
39
+ metadata: Optional[Dict[str, Any]] = None,
40
+ debug_mode: Optional[bool] = None,
41
+ **kwargs: Any,
42
+ ) -> None:
43
+ import textwrap
44
+
45
+ from rich.console import Group
46
+ from rich.json import JSON
47
+ from rich.live import Live
48
+ from rich.markdown import Markdown
49
+ from rich.status import Status
50
+ from rich.text import Text
51
+
52
+ from agno.utils.response import format_tool_calls
53
+
54
+ if not tags_to_include_in_markdown:
55
+ tags_to_include_in_markdown = {"think", "thinking"}
56
+
57
+ with Live(console=console) as live_console:
58
+ status = Status("Thinking...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
59
+ live_console.update(status)
60
+
61
+ response_timer = Timer()
62
+ response_timer.start()
63
+ # Panels to be rendered
64
+ panels = [status]
65
+ # First render the message panel if the message is not None
66
+ if input and show_message:
67
+ # Convert message to a panel
68
+ message_content = get_text_from_message(input)
69
+ message_panel = create_panel(
70
+ content=Text(message_content, style="green"),
71
+ title="Message",
72
+ border_style="cyan",
73
+ )
74
+ panels.append(message_panel)
75
+ live_console.update(Group(*panels))
76
+
77
+ # Run the agent
78
+ run_response: TeamRunOutput = team.run( # type: ignore
79
+ input=input,
80
+ images=images,
81
+ audio=audio,
82
+ videos=videos,
83
+ files=files,
84
+ stream=False,
85
+ session_id=session_id,
86
+ session_state=session_state,
87
+ user_id=user_id,
88
+ knowledge_filters=knowledge_filters,
89
+ add_history_to_context=add_history_to_context,
90
+ dependencies=dependencies,
91
+ metadata=metadata,
92
+ debug_mode=debug_mode,
93
+ **kwargs,
94
+ )
95
+ response_timer.stop()
96
+
97
+ team_markdown = False
98
+ member_markdown = {}
99
+ if markdown:
100
+ for member in team.members:
101
+ if member.id is not None:
102
+ member_markdown[member.id] = True
103
+ team_markdown = True
104
+
105
+ if team.output_schema is not None:
106
+ team_markdown = False
107
+
108
+ for member in team.members:
109
+ if member.output_schema is not None and member.id is not None:
110
+ member_markdown[member.id] = False # type: ignore
111
+
112
+ # Handle reasoning
113
+ reasoning_steps = []
114
+ if isinstance(run_response, TeamRunOutput) and run_response.reasoning_steps is not None:
115
+ reasoning_steps = run_response.reasoning_steps
116
+
117
+ if len(reasoning_steps) > 0 and show_reasoning:
118
+ # Create panels for reasoning steps
119
+ for i, step in enumerate(reasoning_steps, 1):
120
+ reasoning_panel = build_reasoning_step_panel(i, step, show_full_reasoning)
121
+ panels.append(reasoning_panel)
122
+ live_console.update(Group(*panels))
123
+
124
+ if isinstance(run_response, TeamRunOutput) and run_response.reasoning_content is not None:
125
+ # Create panel for thinking
126
+ thinking_panel = create_panel(
127
+ content=Text(run_response.reasoning_content),
128
+ title=f"Thinking ({response_timer.elapsed:.1f}s)",
129
+ border_style="green",
130
+ )
131
+ panels.append(thinking_panel)
132
+ live_console.update(Group(*panels))
133
+
134
+ if isinstance(run_response, TeamRunOutput):
135
+ # Handle member responses
136
+ if team.show_members_responses:
137
+ for member_response in run_response.member_responses:
138
+ # Handle member reasoning
139
+ reasoning_steps = []
140
+ if isinstance(member_response, RunOutput) and member_response.reasoning_steps is not None:
141
+ reasoning_steps.extend(member_response.reasoning_steps)
142
+
143
+ if len(reasoning_steps) > 0 and show_reasoning:
144
+ # Create panels for reasoning steps
145
+ for i, step in enumerate(reasoning_steps, 1):
146
+ member_reasoning_panel = build_reasoning_step_panel(
147
+ i, step, show_full_reasoning, color="magenta"
148
+ )
149
+ panels.append(member_reasoning_panel)
150
+
151
+ # Add tool calls panel for member if available
152
+ if hasattr(member_response, "tools") and member_response.tools:
153
+ member_name = None
154
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
155
+ member_name = team._get_member_name(member_response.agent_id)
156
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
157
+ member_name = team._get_member_name(member_response.team_id)
158
+
159
+ if member_name:
160
+ formatted_calls = format_tool_calls(member_response.tools)
161
+ if formatted_calls:
162
+ console_width = console.width if console else 80
163
+ panel_width = console_width + 30
164
+
165
+ lines = []
166
+ for call in formatted_calls:
167
+ wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
168
+ lines.append(wrapped_call)
169
+
170
+ tool_calls_text = "\n\n".join(lines)
171
+
172
+ member_tool_calls_panel = create_panel(
173
+ content=tool_calls_text,
174
+ title=f"{member_name} Tool Calls",
175
+ border_style="yellow",
176
+ )
177
+ panels.append(member_tool_calls_panel)
178
+ live_console.update(Group(*panels))
179
+
180
+ show_markdown = False
181
+ if member_markdown:
182
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
183
+ show_markdown = member_markdown.get(member_response.agent_id, False)
184
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
185
+ show_markdown = member_markdown.get(member_response.team_id, False)
186
+
187
+ member_response_content: Union[str, JSON, Markdown] = team._parse_response_content( # type: ignore
188
+ member_response,
189
+ tags_to_include_in_markdown,
190
+ show_markdown=show_markdown,
191
+ )
192
+
193
+ # Create panel for member response
194
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
195
+ member_response_panel = create_panel(
196
+ content=member_response_content,
197
+ title=f"{team._get_member_name(member_response.agent_id)} Response",
198
+ border_style="magenta",
199
+ )
200
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
201
+ member_response_panel = create_panel(
202
+ content=member_response_content,
203
+ title=f"{team._get_member_name(member_response.team_id)} Response",
204
+ border_style="magenta",
205
+ )
206
+ panels.append(member_response_panel)
207
+
208
+ if member_response.citations is not None and member_response.citations.urls is not None:
209
+ md_content = "\n".join(
210
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
211
+ for i, citation in enumerate(member_response.citations.urls)
212
+ if citation.url # Only include citations with valid URLs
213
+ )
214
+ if md_content: # Only create panel if there are citations
215
+ citations_panel = create_panel(
216
+ content=Markdown(md_content),
217
+ title="Citations",
218
+ border_style="magenta",
219
+ )
220
+ panels.append(citations_panel)
221
+
222
+ live_console.update(Group(*panels))
223
+
224
+ # Add team level tool calls panel if available
225
+ if run_response.tools:
226
+ formatted_calls = format_tool_calls(run_response.tools)
227
+ if formatted_calls:
228
+ console_width = console.width if console else 80
229
+ # Allow for panel borders and padding
230
+ panel_width = console_width + 30
231
+
232
+ lines = []
233
+ for call in formatted_calls:
234
+ wrapped_call = textwrap.fill(
235
+ f"• {call}", width=panel_width, subsequent_indent=" "
236
+ ) # Indent continuation lines
237
+ lines.append(wrapped_call)
238
+
239
+ # Join with blank lines between items
240
+ tool_calls_text = "\n\n".join(lines)
241
+
242
+ team_tool_calls_panel = create_panel(
243
+ content=tool_calls_text,
244
+ title="Team Tool Calls",
245
+ border_style="yellow",
246
+ )
247
+ panels.append(team_tool_calls_panel)
248
+ live_console.update(Group(*panels))
249
+
250
+ response_content_batch: Union[str, JSON, Markdown] = team._parse_response_content( # type: ignore
251
+ run_response, tags_to_include_in_markdown, show_markdown=team_markdown
252
+ )
253
+
254
+ # Create panel for response
255
+ response_panel = create_panel(
256
+ content=response_content_batch,
257
+ title=f"Response ({response_timer.elapsed:.1f}s)",
258
+ border_style="blue",
259
+ )
260
+ panels.append(response_panel)
261
+
262
+ # Add citations
263
+ if run_response.citations is not None and run_response.citations.urls is not None:
264
+ md_content = "\n".join(
265
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
266
+ for i, citation in enumerate(run_response.citations.urls)
267
+ if citation.url # Only include citations with valid URLs
268
+ )
269
+ if md_content: # Only create panel if there are citations
270
+ citations_panel = create_panel(
271
+ content=Markdown(md_content),
272
+ title="Citations",
273
+ border_style="green",
274
+ )
275
+ panels.append(citations_panel)
276
+
277
+ if team.memory_manager is not None:
278
+ if team.memory_manager.memories_updated:
279
+ memory_panel = create_panel(
280
+ content=Text("Memories updated"),
281
+ title="Memories",
282
+ border_style="green",
283
+ )
284
+ panels.append(memory_panel)
285
+
286
+ if team.session_summary_manager is not None and team.session_summary_manager.summaries_updated:
287
+ summary_panel = create_panel(
288
+ content=Text("Session summary updated"),
289
+ title="Session Summary",
290
+ border_style="green",
291
+ )
292
+ panels.append(summary_panel)
293
+ team.session_summary_manager.summaries_updated = False
294
+
295
+ # Final update to remove the "Thinking..." status
296
+ panels = [p for p in panels if not isinstance(p, Status)]
297
+ live_console.update(Group(*panels))
298
+
299
+
300
+ def print_response_stream(
301
+ team: "Team",
302
+ input: Union[List, Dict, str, Message, BaseModel, List[Message]],
303
+ console: Optional[Any] = None,
304
+ show_message: bool = True,
305
+ show_reasoning: bool = True,
306
+ show_full_reasoning: bool = False,
307
+ tags_to_include_in_markdown: Optional[Set[str]] = None,
308
+ session_id: Optional[str] = None,
309
+ session_state: Optional[Dict[str, Any]] = None,
310
+ user_id: Optional[str] = None,
311
+ audio: Optional[Sequence[Audio]] = None,
312
+ images: Optional[Sequence[Image]] = None,
313
+ videos: Optional[Sequence[Video]] = None,
314
+ files: Optional[Sequence[File]] = None,
315
+ markdown: bool = False,
316
+ stream_intermediate_steps: bool = False, # type: ignore
317
+ knowledge_filters: Optional[Dict[str, Any]] = None,
318
+ add_history_to_context: Optional[bool] = None,
319
+ dependencies: Optional[Dict[str, Any]] = None,
320
+ metadata: Optional[Dict[str, Any]] = None,
321
+ debug_mode: Optional[bool] = None,
322
+ **kwargs: Any,
323
+ ) -> None:
324
+ import textwrap
325
+
326
+ from rich.console import Group
327
+ from rich.json import JSON
328
+ from rich.live import Live
329
+ from rich.markdown import Markdown
330
+ from rich.status import Status
331
+ from rich.text import Text
332
+
333
+ from agno.utils.response import format_tool_calls
334
+
335
+ if not tags_to_include_in_markdown:
336
+ tags_to_include_in_markdown = {"think", "thinking"}
337
+
338
+ stream_intermediate_steps = True # With streaming print response, we need to stream intermediate steps
339
+
340
+ _response_content: str = ""
341
+ _response_reasoning_content: str = ""
342
+ reasoning_steps: List[ReasoningStep] = []
343
+
344
+ # Track tool calls by member and team
345
+ member_tool_calls = {} # type: ignore
346
+ team_tool_calls = [] # type: ignore
347
+
348
+ # Track processed tool calls to avoid duplicates
349
+ processed_tool_calls = set()
350
+
351
+ with Live(console=console) as live_console:
352
+ status = Status("Thinking...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
353
+ live_console.update(status)
354
+ response_timer = Timer()
355
+ response_timer.start()
356
+ # Flag which indicates if the panels should be rendered
357
+ render = False
358
+ # Panels to be rendered
359
+ panels = [status]
360
+ # First render the message panel if the message is not None
361
+ if input and show_message:
362
+ render = True
363
+ # Convert message to a panel
364
+ message_content = get_text_from_message(input)
365
+ message_panel = create_panel(
366
+ content=Text(message_content, style="green"),
367
+ title="Message",
368
+ border_style="cyan",
369
+ )
370
+ panels.append(message_panel)
371
+ if render:
372
+ live_console.update(Group(*panels))
373
+
374
+ # Get response from the team
375
+ stream_resp = team.run( # type: ignore
376
+ input=input,
377
+ audio=audio,
378
+ images=images,
379
+ videos=videos,
380
+ files=files,
381
+ stream=True,
382
+ stream_intermediate_steps=stream_intermediate_steps,
383
+ session_id=session_id,
384
+ session_state=session_state,
385
+ user_id=user_id,
386
+ knowledge_filters=knowledge_filters,
387
+ add_history_to_context=add_history_to_context,
388
+ dependencies=dependencies,
389
+ metadata=metadata,
390
+ debug_mode=debug_mode,
391
+ **kwargs,
392
+ )
393
+
394
+ team_markdown = None
395
+ member_markdown = {}
396
+
397
+ # Dict to track member response panels by member_id
398
+ member_response_panels = {}
399
+
400
+ run_id = None
401
+ for resp in stream_resp:
402
+ run_id = resp.run_id
403
+ if team_markdown is None:
404
+ if markdown:
405
+ team_markdown = True
406
+ else:
407
+ team_markdown = False
408
+
409
+ if team.output_schema is not None:
410
+ team_markdown = False
411
+
412
+ if isinstance(resp, tuple(get_args(TeamRunOutputEvent))):
413
+ if resp.event == TeamRunEvent.run_content:
414
+ if isinstance(resp.content, str):
415
+ _response_content += resp.content
416
+ elif team.output_schema is not None and isinstance(resp.content, BaseModel):
417
+ try:
418
+ _response_content = JSON(resp.content.model_dump_json(exclude_none=True), indent=2) # type: ignore
419
+ except Exception as e:
420
+ log_warning(f"Failed to convert response to JSON: {e}")
421
+ if hasattr(resp, "reasoning_content") and resp.reasoning_content is not None: # type: ignore
422
+ _response_reasoning_content += resp.reasoning_content # type: ignore
423
+ if hasattr(resp, "reasoning_steps") and resp.reasoning_steps is not None: # type: ignore
424
+ reasoning_steps = resp.reasoning_steps # type: ignore
425
+
426
+ # Collect team tool calls, avoiding duplicates
427
+ if isinstance(resp, ToolCallCompletedEvent) and resp.tool:
428
+ tool = resp.tool
429
+ # Generate a unique ID for this tool call
430
+ if tool.tool_call_id:
431
+ tool_id = tool.tool_call_id
432
+ else:
433
+ tool_id = str(hash(str(tool)))
434
+ if tool_id not in processed_tool_calls:
435
+ processed_tool_calls.add(tool_id)
436
+ team_tool_calls.append(tool)
437
+
438
+ # Collect member tool calls, avoiding duplicates
439
+ if hasattr(resp, "member_responses") and resp.member_responses:
440
+ for member_response in resp.member_responses:
441
+ member_id = None
442
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
443
+ member_id = member_response.agent_id
444
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
445
+ member_id = member_response.team_id
446
+
447
+ if member_id and hasattr(member_response, "tools") and member_response.tools:
448
+ if member_id not in member_tool_calls:
449
+ member_tool_calls[member_id] = []
450
+
451
+ for tool in member_response.tools:
452
+ # Generate a unique ID for this tool call
453
+ if tool.tool_call_id:
454
+ tool_id = tool.tool_call_id
455
+ else:
456
+ tool_id = str(hash(str(tool)))
457
+ if tool_id not in processed_tool_calls:
458
+ processed_tool_calls.add(tool_id)
459
+ member_tool_calls[member_id].append(tool)
460
+
461
+ response_content_stream: Union[str, Markdown] = _response_content
462
+ # Escape special tags before markdown conversion
463
+ if team_markdown:
464
+ escaped_content = escape_markdown_tags(_response_content, tags_to_include_in_markdown)
465
+ response_content_stream = Markdown(escaped_content)
466
+
467
+ # Create new panels for each chunk
468
+ panels = []
469
+
470
+ if input and show_message:
471
+ render = True
472
+ # Convert message to a panel
473
+ message_content = get_text_from_message(input)
474
+ message_panel = create_panel(
475
+ content=Text(message_content, style="green"),
476
+ title="Message",
477
+ border_style="cyan",
478
+ )
479
+ panels.append(message_panel)
480
+
481
+ if len(reasoning_steps) > 0 and show_reasoning:
482
+ render = True
483
+ # Create panels for reasoning steps
484
+ for i, step in enumerate(reasoning_steps, 1):
485
+ reasoning_panel = build_reasoning_step_panel(i, step, show_full_reasoning)
486
+ panels.append(reasoning_panel)
487
+
488
+ if len(_response_reasoning_content) > 0:
489
+ render = True
490
+ # Create panel for thinking
491
+ thinking_panel = create_panel(
492
+ content=Text(_response_reasoning_content),
493
+ title=f"Thinking ({response_timer.elapsed:.1f}s)",
494
+ border_style="green",
495
+ )
496
+ panels.append(thinking_panel)
497
+ elif _response_content == "":
498
+ # Keep showing status if no content yet
499
+ panels.append(status)
500
+
501
+ # Process member responses and their tool calls
502
+ for member_response in resp.member_responses if hasattr(resp, "member_responses") else []:
503
+ member_id = None
504
+ member_name = "Team Member"
505
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
506
+ member_id = member_response.agent_id
507
+ member_name = team._get_member_name(member_id)
508
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
509
+ member_id = member_response.team_id
510
+
511
+ member_name = team._get_member_name(member_id)
512
+
513
+ # If we have tool calls for this member, display them
514
+ if member_id in member_tool_calls and member_tool_calls[member_id]:
515
+ formatted_calls = format_tool_calls(member_tool_calls[member_id])
516
+ if formatted_calls:
517
+ console_width = console.width if console else 80
518
+ panel_width = console_width + 30
519
+
520
+ lines = []
521
+ for call in formatted_calls:
522
+ wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
523
+ lines.append(wrapped_call)
524
+
525
+ tool_calls_text = "\n\n".join(lines)
526
+
527
+ member_tool_calls_panel = create_panel(
528
+ content=tool_calls_text,
529
+ title=f"{member_name} Tool Calls",
530
+ border_style="yellow",
531
+ )
532
+ panels.append(member_tool_calls_panel)
533
+
534
+ # Process member response content
535
+ if team.show_members_responses and member_id is not None:
536
+ show_markdown = False
537
+ if markdown:
538
+ show_markdown = True
539
+
540
+ member_response_content = team._parse_response_content(
541
+ member_response,
542
+ tags_to_include_in_markdown,
543
+ show_markdown=show_markdown,
544
+ )
545
+
546
+ member_response_panel = create_panel(
547
+ content=member_response_content,
548
+ title=f"{member_name} Response",
549
+ border_style="magenta",
550
+ )
551
+
552
+ panels.append(member_response_panel)
553
+
554
+ # Store for reference
555
+ if member_id is not None:
556
+ member_response_panels[member_id] = member_response_panel
557
+
558
+ # Add team tool calls panel if available (before the team response)
559
+ if team_tool_calls:
560
+ formatted_calls = format_tool_calls(team_tool_calls)
561
+ if formatted_calls:
562
+ console_width = console.width if console else 80
563
+ panel_width = console_width + 30
564
+
565
+ lines = []
566
+ # Create a set to track already added calls by their string representation
567
+ added_calls = set()
568
+ for call in formatted_calls:
569
+ if call not in added_calls:
570
+ added_calls.add(call)
571
+ # Wrap the call text to fit within the panel
572
+ wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
573
+ lines.append(wrapped_call)
574
+
575
+ # Join with blank lines between items
576
+ tool_calls_text = "\n\n".join(lines)
577
+
578
+ team_tool_calls_panel = create_panel(
579
+ content=tool_calls_text,
580
+ title="Team Tool Calls",
581
+ border_style="yellow",
582
+ )
583
+ panels.append(team_tool_calls_panel)
584
+
585
+ # Add the team response panel at the end
586
+ if response_content_stream:
587
+ render = True
588
+ # Create panel for response
589
+ response_panel = create_panel(
590
+ content=response_content_stream,
591
+ title=f"Response ({response_timer.elapsed:.1f}s)",
592
+ border_style="blue",
593
+ )
594
+ panels.append(response_panel)
595
+
596
+ if render or len(panels) > 0:
597
+ live_console.update(Group(*panels))
598
+
599
+ response_timer.stop()
600
+ run_response = team.get_run_output(run_id=run_id) # type: ignore
601
+
602
+ # Add citations
603
+ if hasattr(resp, "citations") and resp.citations is not None and resp.citations.urls is not None:
604
+ md_content = "\n".join(
605
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
606
+ for i, citation in enumerate(resp.citations.urls)
607
+ if citation.url # Only include citations with valid URLs
608
+ )
609
+ if md_content: # Only create panel if there are citations
610
+ citations_panel = create_panel(
611
+ content=Markdown(md_content),
612
+ title="Citations",
613
+ border_style="green",
614
+ )
615
+ panels.append(citations_panel)
616
+ live_console.update(Group(*panels))
617
+
618
+ if team.memory_manager is not None:
619
+ if team.memory_manager.memories_updated:
620
+ memory_panel = create_panel(
621
+ content=Text("Memories updated"),
622
+ title="Memories",
623
+ border_style="green",
624
+ )
625
+ panels.append(memory_panel)
626
+ live_console.update(Group(*panels))
627
+
628
+ if team.session_summary_manager is not None and team.session_summary_manager.summaries_updated:
629
+ summary_panel = create_panel(
630
+ content=Text("Session summary updated"),
631
+ title="Session Summary",
632
+ border_style="green",
633
+ )
634
+ panels.append(summary_panel)
635
+ live_console.update(Group(*panels))
636
+ team.session_summary_manager.summaries_updated = False
637
+
638
+ # Final update to remove the "Thinking..." status
639
+ panels = [p for p in panels if not isinstance(p, Status)]
640
+
641
+ if markdown:
642
+ for member in team.members:
643
+ if member.id is not None:
644
+ member_markdown[member.id] = True
645
+
646
+ for member in team.members:
647
+ if member.output_schema is not None and member.id is not None:
648
+ member_markdown[member.id] = False # type: ignore
649
+
650
+ # Final panels assembly - we'll recreate the panels from scratch to ensure correct order
651
+ final_panels = []
652
+
653
+ # Start with the message
654
+ if input and show_message:
655
+ message_content = get_text_from_message(input)
656
+ message_panel = create_panel(
657
+ content=Text(message_content, style="green"),
658
+ title="Message",
659
+ border_style="cyan",
660
+ )
661
+ final_panels.append(message_panel)
662
+
663
+ # Add reasoning steps
664
+ if reasoning_steps and show_reasoning:
665
+ for i, step in enumerate(reasoning_steps, 1):
666
+ reasoning_panel = build_reasoning_step_panel(i, step, show_full_reasoning)
667
+ final_panels.append(reasoning_panel)
668
+
669
+ # Add thinking panel if available
670
+ if _response_reasoning_content:
671
+ thinking_panel = create_panel(
672
+ content=Text(_response_reasoning_content),
673
+ title=f"Thinking ({response_timer.elapsed:.1f}s)",
674
+ border_style="green",
675
+ )
676
+ final_panels.append(thinking_panel)
677
+
678
+ # Add member tool calls and responses in correct order
679
+ if run_response is not None and hasattr(run_response, "member_responses"):
680
+ for i, member_response in enumerate(run_response.member_responses): # type: ignore
681
+ member_id = None
682
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
683
+ member_id = member_response.agent_id
684
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
685
+ member_id = member_response.team_id
686
+
687
+ if member_id:
688
+ # First add tool calls if any
689
+ if member_id in member_tool_calls and member_tool_calls[member_id]:
690
+ formatted_calls = format_tool_calls(member_tool_calls[member_id])
691
+ if formatted_calls:
692
+ console_width = console.width if console else 80
693
+ panel_width = console_width + 30
694
+
695
+ lines = []
696
+ for call in formatted_calls:
697
+ wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
698
+ lines.append(wrapped_call)
699
+
700
+ tool_calls_text = "\n\n".join(lines)
701
+
702
+ member_name = team._get_member_name(member_id)
703
+ member_tool_calls_panel = create_panel(
704
+ content=tool_calls_text,
705
+ title=f"{member_name} Tool Calls",
706
+ border_style="yellow",
707
+ )
708
+ final_panels.append(member_tool_calls_panel)
709
+
710
+ # Add reasoning steps if any
711
+ reasoning_steps = []
712
+ if member_response.reasoning_steps is not None:
713
+ reasoning_steps = member_response.reasoning_steps
714
+ if reasoning_steps and show_reasoning:
715
+ for j, step in enumerate(reasoning_steps, 1):
716
+ member_reasoning_panel = build_reasoning_step_panel(
717
+ j, step, show_full_reasoning, color="magenta"
718
+ )
719
+ final_panels.append(member_reasoning_panel)
720
+
721
+ # Then add response
722
+ show_markdown = False
723
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
724
+ show_markdown = member_markdown.get(member_response.agent_id, False)
725
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
726
+ show_markdown = member_markdown.get(member_response.team_id, False)
727
+
728
+ member_response_content = team._parse_response_content( # type: ignore
729
+ member_response,
730
+ tags_to_include_in_markdown,
731
+ show_markdown=show_markdown,
732
+ )
733
+
734
+ member_name = "Team Member"
735
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
736
+ member_name = team._get_member_name(member_response.agent_id)
737
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
738
+ member_name = team._get_member_name(member_response.team_id)
739
+
740
+ member_response_panel = create_panel(
741
+ content=member_response_content,
742
+ title=f"{member_name} Response",
743
+ border_style="magenta",
744
+ )
745
+ final_panels.append(member_response_panel)
746
+
747
+ # Add citations if any
748
+ if member_response.citations is not None and member_response.citations.urls is not None:
749
+ md_content = "\n".join(
750
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
751
+ for i, citation in enumerate(member_response.citations.urls)
752
+ if citation.url # Only include citations with valid URLs
753
+ )
754
+ if md_content: # Only create panel if there are citations
755
+ citations_panel = create_panel(
756
+ content=Markdown(md_content),
757
+ title="Citations",
758
+ border_style="magenta",
759
+ )
760
+ final_panels.append(citations_panel)
761
+
762
+ # Add team tool calls before team response
763
+ if team_tool_calls:
764
+ formatted_calls = format_tool_calls(team_tool_calls)
765
+ if formatted_calls:
766
+ console_width = console.width if console else 80
767
+ panel_width = console_width + 30
768
+
769
+ lines = []
770
+ # Create a set to track already added calls by their string representation
771
+ added_calls = set()
772
+ for call in formatted_calls:
773
+ if call not in added_calls:
774
+ added_calls.add(call)
775
+ # Wrap the call text to fit within the panel
776
+ wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
777
+ lines.append(wrapped_call)
778
+
779
+ tool_calls_text = "\n\n".join(lines)
780
+
781
+ team_tool_calls_panel = create_panel(
782
+ content=tool_calls_text,
783
+ title="Team Tool Calls",
784
+ border_style="yellow",
785
+ )
786
+ final_panels.append(team_tool_calls_panel)
787
+
788
+ # Add team response
789
+ if _response_content:
790
+ response_content_stream = _response_content
791
+ if team_markdown:
792
+ escaped_content = escape_markdown_tags(_response_content, tags_to_include_in_markdown)
793
+ response_content_stream = Markdown(escaped_content)
794
+
795
+ response_panel = create_panel(
796
+ content=response_content_stream,
797
+ title=f"Response ({response_timer.elapsed:.1f}s)",
798
+ border_style="blue",
799
+ )
800
+ final_panels.append(response_panel)
801
+
802
+ # Add team citations
803
+ if hasattr(resp, "citations") and resp.citations is not None and resp.citations.urls is not None:
804
+ md_content = "\n".join(
805
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
806
+ for i, citation in enumerate(resp.citations.urls)
807
+ if citation.url # Only include citations with valid URLs
808
+ )
809
+ if md_content: # Only create panel if there are citations
810
+ citations_panel = create_panel(
811
+ content=Markdown(md_content),
812
+ title="Citations",
813
+ border_style="green",
814
+ )
815
+ final_panels.append(citations_panel)
816
+
817
+ # Final update with correctly ordered panels
818
+ live_console.update(Group(*final_panels))
819
+
820
+
821
+ async def aprint_response(
822
+ team: "Team",
823
+ input: Union[List, Dict, str, Message, BaseModel, List[Message]],
824
+ console: Optional[Any] = None,
825
+ show_message: bool = True,
826
+ show_reasoning: bool = True,
827
+ show_full_reasoning: bool = False,
828
+ tags_to_include_in_markdown: Optional[Set[str]] = None,
829
+ session_id: Optional[str] = None,
830
+ session_state: Optional[Dict[str, Any]] = None,
831
+ user_id: Optional[str] = None,
832
+ audio: Optional[Sequence[Audio]] = None,
833
+ images: Optional[Sequence[Image]] = None,
834
+ videos: Optional[Sequence[Video]] = None,
835
+ files: Optional[Sequence[File]] = None,
836
+ markdown: bool = False,
837
+ knowledge_filters: Optional[Dict[str, Any]] = None,
838
+ add_history_to_context: Optional[bool] = None,
839
+ dependencies: Optional[Dict[str, Any]] = None,
840
+ metadata: Optional[Dict[str, Any]] = None,
841
+ debug_mode: Optional[bool] = None,
842
+ **kwargs: Any,
843
+ ) -> None:
844
+ import textwrap
845
+
846
+ from rich.console import Group
847
+ from rich.json import JSON
848
+ from rich.live import Live
849
+ from rich.markdown import Markdown
850
+ from rich.status import Status
851
+ from rich.text import Text
852
+
853
+ from agno.utils.response import format_tool_calls
854
+
855
+ if not tags_to_include_in_markdown:
856
+ tags_to_include_in_markdown = {"think", "thinking"}
857
+
858
+ with Live(console=console) as live_console:
859
+ status = Status("Thinking...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
860
+ live_console.update(status)
861
+
862
+ response_timer = Timer()
863
+ response_timer.start()
864
+ # Panels to be rendered
865
+ panels = [status]
866
+ # First render the message panel if the message is not None
867
+ if input and show_message:
868
+ # Convert message to a panel
869
+ message_content = get_text_from_message(input)
870
+ message_panel = create_panel(
871
+ content=Text(message_content, style="green"),
872
+ title="Message",
873
+ border_style="cyan",
874
+ )
875
+ panels.append(message_panel)
876
+ live_console.update(Group(*panels))
877
+
878
+ # Run the agent
879
+ run_response: TeamRunOutput = await team.arun( # type: ignore
880
+ input=input,
881
+ images=images,
882
+ audio=audio,
883
+ videos=videos,
884
+ files=files,
885
+ stream=False,
886
+ session_id=session_id,
887
+ session_state=session_state,
888
+ user_id=user_id,
889
+ knowledge_filters=knowledge_filters,
890
+ add_history_to_context=add_history_to_context,
891
+ dependencies=dependencies,
892
+ metadata=metadata,
893
+ debug_mode=debug_mode,
894
+ **kwargs,
895
+ )
896
+ response_timer.stop()
897
+
898
+ team_markdown = False
899
+ member_markdown = {}
900
+ if markdown:
901
+ for member in team.members:
902
+ if member.id is not None:
903
+ member_markdown[member.id] = True
904
+ team_markdown = True
905
+
906
+ if team.output_schema is not None:
907
+ team_markdown = False
908
+
909
+ for member in team.members:
910
+ if member.output_schema is not None and member.id is not None:
911
+ member_markdown[member.id] = False # type: ignore
912
+
913
+ # Handle reasoning
914
+ reasoning_steps = []
915
+ if isinstance(run_response, TeamRunOutput) and run_response.reasoning_steps is not None:
916
+ reasoning_steps = run_response.reasoning_steps
917
+
918
+ if len(reasoning_steps) > 0 and show_reasoning:
919
+ # Create panels for reasoning steps
920
+ for i, step in enumerate(reasoning_steps, 1):
921
+ reasoning_panel = build_reasoning_step_panel(i, step, show_full_reasoning)
922
+ panels.append(reasoning_panel)
923
+ live_console.update(Group(*panels))
924
+
925
+ if isinstance(run_response, TeamRunOutput) and run_response.reasoning_content is not None:
926
+ # Create panel for thinking
927
+ thinking_panel = create_panel(
928
+ content=Text(run_response.reasoning_content),
929
+ title=f"Thinking ({response_timer.elapsed:.1f}s)",
930
+ border_style="green",
931
+ )
932
+ panels.append(thinking_panel)
933
+ live_console.update(Group(*panels))
934
+
935
+ if isinstance(run_response, TeamRunOutput):
936
+ # Handle member responses
937
+ if team.show_members_responses:
938
+ for member_response in run_response.member_responses:
939
+ # Handle member reasoning
940
+ reasoning_steps = []
941
+ if isinstance(member_response, RunOutput) and member_response.reasoning_steps is not None:
942
+ reasoning_steps.extend(member_response.reasoning_steps)
943
+
944
+ if len(reasoning_steps) > 0 and show_reasoning:
945
+ # Create panels for reasoning steps
946
+ for i, step in enumerate(reasoning_steps, 1):
947
+ member_reasoning_panel = build_reasoning_step_panel(
948
+ i, step, show_full_reasoning, color="magenta"
949
+ )
950
+ panels.append(member_reasoning_panel)
951
+
952
+ # Add tool calls panel for member if available
953
+ if hasattr(member_response, "tools") and member_response.tools:
954
+ member_name = None
955
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
956
+ member_name = team._get_member_name(member_response.agent_id)
957
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
958
+ member_name = team._get_member_name(member_response.team_id)
959
+
960
+ if member_name:
961
+ # Format tool calls
962
+ formatted_calls = format_tool_calls(member_response.tools)
963
+ if formatted_calls:
964
+ console_width = console.width if console else 80
965
+ panel_width = console_width + 30
966
+
967
+ lines = []
968
+ for call in formatted_calls:
969
+ wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
970
+ lines.append(wrapped_call)
971
+
972
+ tool_calls_text = "\n\n".join(lines)
973
+
974
+ member_tool_calls_panel = create_panel(
975
+ content=tool_calls_text,
976
+ title=f"{member_name} Tool Calls",
977
+ border_style="yellow",
978
+ )
979
+ panels.append(member_tool_calls_panel)
980
+ live_console.update(Group(*panels))
981
+
982
+ show_markdown = False
983
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
984
+ show_markdown = member_markdown.get(member_response.agent_id, False)
985
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
986
+ show_markdown = member_markdown.get(member_response.team_id, False)
987
+
988
+ member_response_content: Union[str, JSON, Markdown] = team._parse_response_content( # type: ignore
989
+ member_response,
990
+ tags_to_include_in_markdown,
991
+ show_markdown=show_markdown,
992
+ )
993
+
994
+ # Create panel for member response
995
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
996
+ member_response_panel = create_panel(
997
+ content=member_response_content,
998
+ title=f"{team._get_member_name(member_response.agent_id)} Response",
999
+ border_style="magenta",
1000
+ )
1001
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
1002
+ member_response_panel = create_panel(
1003
+ content=member_response_content,
1004
+ title=f"{team._get_member_name(member_response.team_id)} Response",
1005
+ border_style="magenta",
1006
+ )
1007
+ panels.append(member_response_panel)
1008
+
1009
+ if member_response.citations is not None and member_response.citations.urls is not None:
1010
+ md_content = "\n".join(
1011
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
1012
+ for i, citation in enumerate(member_response.citations.urls)
1013
+ if citation.url # Only include citations with valid URLs
1014
+ )
1015
+ if md_content:
1016
+ citations_panel = create_panel(
1017
+ content=Markdown(md_content),
1018
+ title="Citations",
1019
+ border_style="magenta",
1020
+ )
1021
+ panels.append(citations_panel)
1022
+
1023
+ live_console.update(Group(*panels))
1024
+
1025
+ # Add team level tool calls panel if available
1026
+ if run_response.tools:
1027
+ formatted_calls = format_tool_calls(run_response.tools)
1028
+ if formatted_calls:
1029
+ console_width = console.width if console else 80
1030
+ # Allow for panel borders and padding
1031
+ panel_width = console_width + 30
1032
+
1033
+ lines = []
1034
+ for call in formatted_calls:
1035
+ # Wrap the call text to fit within the panel
1036
+ wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
1037
+ lines.append(wrapped_call)
1038
+
1039
+ tool_calls_text = "\n\n".join(lines)
1040
+
1041
+ team_tool_calls_panel = create_panel(
1042
+ content=tool_calls_text,
1043
+ title="Team Tool Calls",
1044
+ border_style="yellow",
1045
+ )
1046
+ panels.append(team_tool_calls_panel)
1047
+ live_console.update(Group(*panels))
1048
+
1049
+ response_content_batch: Union[str, JSON, Markdown] = team._parse_response_content( # type: ignore
1050
+ run_response, tags_to_include_in_markdown, show_markdown=team_markdown
1051
+ )
1052
+
1053
+ # Create panel for response
1054
+ response_panel = create_panel(
1055
+ content=response_content_batch,
1056
+ title=f"Response ({response_timer.elapsed:.1f}s)",
1057
+ border_style="blue",
1058
+ )
1059
+ panels.append(response_panel)
1060
+
1061
+ # Add citations
1062
+ if run_response.citations is not None and run_response.citations.urls is not None:
1063
+ md_content = "\n".join(
1064
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
1065
+ for i, citation in enumerate(run_response.citations.urls)
1066
+ if citation.url # Only include citations with valid URLs
1067
+ )
1068
+ if md_content: # Only create panel if there are citations
1069
+ citations_panel = create_panel(
1070
+ content=Markdown(md_content),
1071
+ title="Citations",
1072
+ border_style="green",
1073
+ )
1074
+ panels.append(citations_panel)
1075
+
1076
+ if team.memory_manager is not None:
1077
+ if team.memory_manager.memories_updated:
1078
+ memory_panel = create_panel(
1079
+ content=Text("Memories updated"),
1080
+ title="Memories",
1081
+ border_style="green",
1082
+ )
1083
+ panels.append(memory_panel)
1084
+
1085
+ if team.session_summary_manager is not None and team.session_summary_manager.summaries_updated:
1086
+ summary_panel = create_panel(
1087
+ content=Text("Session summary updated"),
1088
+ title="Session Summary",
1089
+ border_style="green",
1090
+ )
1091
+ panels.append(summary_panel)
1092
+ team.session_summary_manager.summaries_updated = False
1093
+
1094
+ # Final update to remove the "Thinking..." status
1095
+ panels = [p for p in panels if not isinstance(p, Status)]
1096
+ live_console.update(Group(*panels))
1097
+
1098
+
1099
+ async def aprint_response_stream(
1100
+ team: "Team",
1101
+ input: Union[List, Dict, str, Message, BaseModel, List[Message]],
1102
+ console: Optional[Any] = None,
1103
+ show_message: bool = True,
1104
+ show_reasoning: bool = True,
1105
+ show_full_reasoning: bool = False,
1106
+ tags_to_include_in_markdown: Optional[Set[str]] = None,
1107
+ session_id: Optional[str] = None,
1108
+ session_state: Optional[Dict[str, Any]] = None,
1109
+ user_id: Optional[str] = None,
1110
+ audio: Optional[Sequence[Audio]] = None,
1111
+ images: Optional[Sequence[Image]] = None,
1112
+ videos: Optional[Sequence[Video]] = None,
1113
+ files: Optional[Sequence[File]] = None,
1114
+ markdown: bool = False,
1115
+ stream_intermediate_steps: bool = False, # type: ignore
1116
+ knowledge_filters: Optional[Dict[str, Any]] = None,
1117
+ add_history_to_context: Optional[bool] = None,
1118
+ dependencies: Optional[Dict[str, Any]] = None,
1119
+ metadata: Optional[Dict[str, Any]] = None,
1120
+ debug_mode: Optional[bool] = None,
1121
+ **kwargs: Any,
1122
+ ) -> None:
1123
+ import textwrap
1124
+
1125
+ from rich.console import Group
1126
+ from rich.json import JSON
1127
+ from rich.live import Live
1128
+ from rich.markdown import Markdown
1129
+ from rich.status import Status
1130
+ from rich.text import Text
1131
+
1132
+ if not tags_to_include_in_markdown:
1133
+ tags_to_include_in_markdown = {"think", "thinking"}
1134
+
1135
+ stream_intermediate_steps = True # With streaming print response, we need to stream intermediate steps
1136
+
1137
+ _response_content: str = ""
1138
+ _response_reasoning_content: str = ""
1139
+ reasoning_steps: List[ReasoningStep] = []
1140
+
1141
+ # Track tool calls by member and team
1142
+ member_tool_calls = {} # type: ignore
1143
+ team_tool_calls: List[ToolExecution] = []
1144
+
1145
+ # Track processed tool calls to avoid duplicates
1146
+ processed_tool_calls = set()
1147
+
1148
+ # Initialize final_panels here
1149
+ final_panels = [] # type: ignore
1150
+
1151
+ with Live(console=console) as live_console:
1152
+ status = Status("Thinking...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
1153
+ live_console.update(status)
1154
+ response_timer = Timer()
1155
+ response_timer.start()
1156
+ # Flag which indicates if the panels should be rendered
1157
+ render = False
1158
+ # Panels to be rendered
1159
+ panels = [status]
1160
+ # First render the message panel if the message is not None
1161
+ if input and show_message:
1162
+ render = True
1163
+ # Convert message to a panel
1164
+ message_content = get_text_from_message(input)
1165
+ message_panel = create_panel(
1166
+ content=Text(message_content, style="green"),
1167
+ title="Message",
1168
+ border_style="cyan",
1169
+ )
1170
+ panels.append(message_panel)
1171
+ if render:
1172
+ live_console.update(Group(*panels))
1173
+
1174
+ # Get response from the team
1175
+ team_markdown = None
1176
+ member_markdown = {}
1177
+
1178
+ run_id = None
1179
+ async for resp in team.arun( # type: ignore
1180
+ input=input,
1181
+ audio=audio,
1182
+ images=images,
1183
+ videos=videos,
1184
+ files=files,
1185
+ stream=True,
1186
+ stream_intermediate_steps=stream_intermediate_steps,
1187
+ session_id=session_id,
1188
+ session_state=session_state,
1189
+ user_id=user_id,
1190
+ knowledge_filters=knowledge_filters,
1191
+ add_history_to_context=add_history_to_context,
1192
+ dependencies=dependencies,
1193
+ metadata=metadata,
1194
+ debug_mode=debug_mode,
1195
+ **kwargs,
1196
+ ):
1197
+ run_id = resp.run_id
1198
+ if team_markdown is None:
1199
+ if markdown:
1200
+ team_markdown = True
1201
+ else:
1202
+ team_markdown = False
1203
+
1204
+ if team.output_schema is not None:
1205
+ team_markdown = False
1206
+
1207
+ if isinstance(resp, tuple(get_args(TeamRunOutputEvent))):
1208
+ if resp.event == TeamRunEvent.run_content:
1209
+ if isinstance(resp.content, str):
1210
+ _response_content += resp.content
1211
+ elif team.output_schema is not None and isinstance(resp.content, BaseModel):
1212
+ try:
1213
+ _response_content = JSON(resp.content.model_dump_json(exclude_none=True), indent=2) # type: ignore
1214
+ except Exception as e:
1215
+ log_warning(f"Failed to convert response to JSON: {e}")
1216
+ if hasattr(resp, "reasoning_content") and resp.reasoning_content is not None: # type: ignore
1217
+ _response_reasoning_content += resp.reasoning_content # type: ignore
1218
+ if hasattr(resp, "reasoning_steps") and resp.reasoning_steps is not None: # type: ignore
1219
+ reasoning_steps = resp.reasoning_steps # type: ignore
1220
+
1221
+ # Collect team tool calls, avoiding duplicates
1222
+ if isinstance(resp, ToolCallCompletedEvent) and resp.tool:
1223
+ tool = resp.tool
1224
+ # Generate a unique ID for this tool call
1225
+ if tool.tool_call_id is not None:
1226
+ tool_id = tool.tool_call_id
1227
+ else:
1228
+ tool_id = str(hash(str(tool)))
1229
+ if tool_id not in processed_tool_calls:
1230
+ processed_tool_calls.add(tool_id)
1231
+ team_tool_calls.append(tool)
1232
+
1233
+ # Collect member tool calls, avoiding duplicates
1234
+ if hasattr(resp, "member_responses") and resp.member_responses:
1235
+ for member_response in resp.member_responses:
1236
+ member_id = None
1237
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
1238
+ member_id = member_response.agent_id
1239
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
1240
+ member_id = member_response.team_id
1241
+
1242
+ if member_id and hasattr(member_response, "tools") and member_response.tools:
1243
+ if member_id not in member_tool_calls:
1244
+ member_tool_calls[member_id] = []
1245
+
1246
+ for tool in member_response.tools:
1247
+ if tool.tool_call_id is not None:
1248
+ tool_id = tool.tool_call_id
1249
+ else:
1250
+ tool_id = str(hash(str(tool)))
1251
+ if tool_id not in processed_tool_calls:
1252
+ processed_tool_calls.add(tool_id)
1253
+ member_tool_calls[member_id].append(tool)
1254
+
1255
+ response_content_stream: Union[str, Markdown] = _response_content
1256
+ # Escape special tags before markdown conversion
1257
+ if team_markdown:
1258
+ escaped_content = escape_markdown_tags(_response_content, tags_to_include_in_markdown)
1259
+ response_content_stream = Markdown(escaped_content)
1260
+
1261
+ # Create new panels for each chunk
1262
+ panels = [status]
1263
+
1264
+ if input and show_message:
1265
+ render = True
1266
+ # Convert message to a panel
1267
+ message_content = get_text_from_message(input)
1268
+ message_panel = create_panel(
1269
+ content=Text(message_content, style="green"),
1270
+ title="Message",
1271
+ border_style="cyan",
1272
+ )
1273
+ panels.append(message_panel)
1274
+ if render:
1275
+ live_console.update(Group(*panels))
1276
+
1277
+ if len(reasoning_steps) > 0 and show_reasoning:
1278
+ render = True
1279
+ # Create panels for reasoning steps
1280
+ for i, step in enumerate(reasoning_steps, 1):
1281
+ reasoning_panel = build_reasoning_step_panel(i, step, show_full_reasoning)
1282
+ panels.append(reasoning_panel)
1283
+ if render:
1284
+ live_console.update(Group(*panels))
1285
+
1286
+ if len(_response_reasoning_content) > 0:
1287
+ render = True
1288
+ # Create panel for thinking
1289
+ thinking_panel = create_panel(
1290
+ content=Text(_response_reasoning_content),
1291
+ title=f"Thinking ({response_timer.elapsed:.1f}s)",
1292
+ border_style="green",
1293
+ )
1294
+ panels.append(thinking_panel)
1295
+ if render:
1296
+ live_console.update(Group(*panels))
1297
+
1298
+ # Add tool calls panel if available
1299
+ if (
1300
+ resp is not None
1301
+ and hasattr(resp, "tool")
1302
+ and resp.tool is not None
1303
+ and resp.event == RunEvent.tool_call_started
1304
+ ):
1305
+ render = True
1306
+ # Create bullet points for each tool call
1307
+ tool_calls_content = Text()
1308
+ formatted_tool_call = format_tool_calls([resp.tool])
1309
+ tool_calls_content.append(f"• {formatted_tool_call}\n")
1310
+
1311
+ tool_calls_panel = create_panel(
1312
+ content=tool_calls_content.plain.rstrip(),
1313
+ title="Tool Calls",
1314
+ border_style="yellow",
1315
+ )
1316
+ panels.append(tool_calls_panel)
1317
+
1318
+ if response_content_stream:
1319
+ render = True
1320
+ # Create panel for response
1321
+ response_panel = create_panel(
1322
+ content=response_content_stream,
1323
+ title=f"Response ({response_timer.elapsed:.1f}s)",
1324
+ border_style="blue",
1325
+ )
1326
+ panels.append(response_panel)
1327
+ if render:
1328
+ live_console.update(Group(*panels))
1329
+ response_timer.stop()
1330
+
1331
+ run_response = team.get_run_output(run_id=run_id) # type: ignore
1332
+
1333
+ # Add citations
1334
+ if hasattr(resp, "citations") and resp.citations is not None and resp.citations.urls is not None:
1335
+ md_content = "\n".join(
1336
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
1337
+ for i, citation in enumerate(resp.citations.urls)
1338
+ if citation.url # Only include citations with valid URLs
1339
+ )
1340
+ if md_content: # Only create panel if there are citations
1341
+ citations_panel = create_panel(
1342
+ content=Markdown(md_content),
1343
+ title="Citations",
1344
+ border_style="green",
1345
+ )
1346
+ panels.append(citations_panel)
1347
+ live_console.update(Group(*panels))
1348
+
1349
+ if team.memory_manager is not None:
1350
+ if team.memory_manager.memories_updated:
1351
+ memory_panel = create_panel(
1352
+ content=Text("Memories updated"),
1353
+ title="Memories",
1354
+ border_style="green",
1355
+ )
1356
+ panels.append(memory_panel)
1357
+ live_console.update(Group(*panels))
1358
+
1359
+ if team.session_summary_manager is not None and team.session_summary_manager.summaries_updated:
1360
+ summary_panel = create_panel(
1361
+ content=Text("Session summary updated"),
1362
+ title="Session Summary",
1363
+ border_style="green",
1364
+ )
1365
+ panels.append(summary_panel)
1366
+ live_console.update(Group(*panels))
1367
+ team.session_summary_manager.summaries_updated = False
1368
+
1369
+ # Final update to remove the "Thinking..." status
1370
+ panels = [p for p in panels if not isinstance(p, Status)]
1371
+
1372
+ if markdown:
1373
+ for member in team.members:
1374
+ if member.id is not None:
1375
+ member_markdown[member.id] = True # type: ignore
1376
+
1377
+ for member in team.members:
1378
+ if member.output_schema is not None and member.id is not None:
1379
+ member_markdown[member.id] = False # type: ignore
1380
+
1381
+ # Final panels assembly - we'll recreate the panels from scratch to ensure correct order
1382
+ final_panels = []
1383
+
1384
+ # Start with the message
1385
+ if input and show_message:
1386
+ message_content = get_text_from_message(input)
1387
+ message_panel = create_panel(
1388
+ content=Text(message_content, style="green"),
1389
+ title="Message",
1390
+ border_style="cyan",
1391
+ )
1392
+ final_panels.append(message_panel)
1393
+
1394
+ # Add reasoning steps
1395
+ if reasoning_steps and show_reasoning:
1396
+ for i, step in enumerate(reasoning_steps, 1):
1397
+ reasoning_panel = build_reasoning_step_panel(i, step, show_full_reasoning)
1398
+ final_panels.append(reasoning_panel)
1399
+
1400
+ # Add thinking panel if available
1401
+ if _response_reasoning_content:
1402
+ thinking_panel = create_panel(
1403
+ content=Text(_response_reasoning_content),
1404
+ title=f"Thinking ({response_timer.elapsed:.1f}s)",
1405
+ border_style="green",
1406
+ )
1407
+ final_panels.append(thinking_panel)
1408
+
1409
+ # Add member tool calls and responses in correct order
1410
+ if run_response is not None and hasattr(run_response, "member_responses"):
1411
+ for i, member_response in enumerate(run_response.member_responses):
1412
+ member_id = None
1413
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
1414
+ member_id = member_response.agent_id
1415
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
1416
+ member_id = member_response.team_id
1417
+
1418
+ if member_id:
1419
+ # First add tool calls if any
1420
+ if member_id in member_tool_calls and member_tool_calls[member_id]:
1421
+ formatted_calls = format_tool_calls(member_tool_calls[member_id])
1422
+ if formatted_calls:
1423
+ console_width = console.width if console else 80
1424
+ panel_width = console_width + 30
1425
+
1426
+ lines = []
1427
+ # Create a set to track already added calls by their string representation
1428
+ added_calls = set()
1429
+ for call in formatted_calls:
1430
+ if call not in added_calls:
1431
+ added_calls.add(call)
1432
+ # Wrap the call text to fit within the panel
1433
+ wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
1434
+ lines.append(wrapped_call)
1435
+
1436
+ tool_calls_text = "\n\n".join(lines)
1437
+
1438
+ member_name = team._get_member_name(member_id)
1439
+ member_tool_calls_panel = create_panel(
1440
+ content=tool_calls_text,
1441
+ title=f"{member_name} Tool Calls",
1442
+ border_style="yellow",
1443
+ )
1444
+ final_panels.append(member_tool_calls_panel)
1445
+
1446
+ # Add reasoning steps if any
1447
+ reasoning_steps = []
1448
+ if member_response.reasoning_steps is not None:
1449
+ reasoning_steps = member_response.reasoning_steps
1450
+ if reasoning_steps and show_reasoning:
1451
+ for j, step in enumerate(reasoning_steps, 1):
1452
+ member_reasoning_panel = build_reasoning_step_panel(
1453
+ j, step, show_full_reasoning, color="magenta"
1454
+ )
1455
+ final_panels.append(member_reasoning_panel)
1456
+
1457
+ # Add reasoning steps if any
1458
+ reasoning_steps = []
1459
+ if hasattr(member_response, "reasoning_steps") and member_response.reasoning_steps is not None:
1460
+ reasoning_steps = member_response.reasoning_steps
1461
+ if reasoning_steps and show_reasoning:
1462
+ for j, step in enumerate(reasoning_steps, 1):
1463
+ member_reasoning_panel = build_reasoning_step_panel(
1464
+ j, step, show_full_reasoning, color="magenta"
1465
+ )
1466
+ final_panels.append(member_reasoning_panel)
1467
+
1468
+ # Then add response
1469
+ show_markdown = False
1470
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
1471
+ show_markdown = member_markdown.get(member_response.agent_id, False)
1472
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
1473
+ show_markdown = member_markdown.get(member_response.team_id, False)
1474
+
1475
+ member_response_content = team._parse_response_content( # type: ignore
1476
+ member_response,
1477
+ tags_to_include_in_markdown,
1478
+ show_markdown=show_markdown,
1479
+ )
1480
+
1481
+ member_name = "Team Member"
1482
+ if isinstance(member_response, RunOutput) and member_response.agent_id is not None:
1483
+ member_name = team._get_member_name(member_response.agent_id)
1484
+ elif isinstance(member_response, TeamRunOutput) and member_response.team_id is not None:
1485
+ member_name = team._get_member_name(member_response.team_id)
1486
+
1487
+ member_response_panel = create_panel(
1488
+ content=member_response_content,
1489
+ title=f"{member_name} Response",
1490
+ border_style="magenta",
1491
+ )
1492
+ final_panels.append(member_response_panel)
1493
+
1494
+ # Add citations if any
1495
+ if member_response.citations is not None and member_response.citations.urls is not None:
1496
+ md_content = "\n".join(
1497
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
1498
+ for i, citation in enumerate(member_response.citations.urls)
1499
+ if citation.url # Only include citations with valid URLs
1500
+ )
1501
+ if md_content: # Only create panel if there are citations
1502
+ citations_panel = create_panel(
1503
+ content=Markdown(md_content),
1504
+ title="Citations",
1505
+ border_style="magenta",
1506
+ )
1507
+ final_panels.append(citations_panel)
1508
+
1509
+ # Add team tool calls before team response
1510
+ if team_tool_calls:
1511
+ formatted_calls = format_tool_calls(team_tool_calls)
1512
+ if formatted_calls:
1513
+ console_width = console.width if console else 80
1514
+ panel_width = console_width + 30
1515
+
1516
+ lines = []
1517
+ # Create a set to track already added calls by their string representation
1518
+ added_calls = set()
1519
+ for call in formatted_calls:
1520
+ if call not in added_calls:
1521
+ added_calls.add(call)
1522
+ # Wrap the call text to fit within the panel
1523
+ wrapped_call = textwrap.fill(f"• {call}", width=panel_width, subsequent_indent=" ")
1524
+ lines.append(wrapped_call)
1525
+
1526
+ tool_calls_text = "\n\n".join(lines)
1527
+
1528
+ team_tool_calls_panel = create_panel(
1529
+ content=tool_calls_text,
1530
+ title="Team Tool Calls",
1531
+ border_style="yellow",
1532
+ )
1533
+ final_panels.append(team_tool_calls_panel)
1534
+
1535
+ # Add team response
1536
+ if _response_content:
1537
+ response_content_stream = _response_content
1538
+ if team_markdown:
1539
+ escaped_content = escape_markdown_tags(_response_content, tags_to_include_in_markdown)
1540
+ response_content_stream = Markdown(escaped_content)
1541
+
1542
+ response_panel = create_panel(
1543
+ content=response_content_stream,
1544
+ title=f"Response ({response_timer.elapsed:.1f}s)",
1545
+ border_style="blue",
1546
+ )
1547
+ final_panels.append(response_panel)
1548
+
1549
+ # Add team citations
1550
+ if hasattr(resp, "citations") and resp.citations is not None and resp.citations.urls is not None:
1551
+ md_content = "\n".join(
1552
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
1553
+ for i, citation in enumerate(resp.citations.urls)
1554
+ if citation.url # Only include citations with valid URLs
1555
+ )
1556
+ if md_content: # Only create panel if there are citations
1557
+ citations_panel = create_panel(
1558
+ content=Markdown(md_content),
1559
+ title="Citations",
1560
+ border_style="green",
1561
+ )
1562
+ final_panels.append(citations_panel)
1563
+
1564
+ # Final update with correctly ordered panels
1565
+ live_console.update(Group(*final_panels))