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