agno 0.1.2__py3-none-any.whl → 2.3.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (723) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +44 -5
  3. agno/agent/agent.py +10531 -2975
  4. agno/api/agent.py +14 -53
  5. agno/api/api.py +7 -46
  6. agno/api/evals.py +22 -0
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -25
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +6 -9
  11. agno/api/schemas/evals.py +16 -0
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +10 -10
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +16 -0
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +22 -26
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/compression/__init__.py +3 -0
  25. agno/compression/manager.py +247 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +946 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2781 -0
  33. agno/db/dynamo/schemas.py +442 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +2379 -0
  37. agno/db/firestore/schemas.py +181 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1791 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1312 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1777 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/manager.py +199 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/migrations/versions/v2_3_0.py +938 -0
  51. agno/db/mongo/__init__.py +17 -0
  52. agno/db/mongo/async_mongo.py +2760 -0
  53. agno/db/mongo/mongo.py +2597 -0
  54. agno/db/mongo/schemas.py +119 -0
  55. agno/db/mongo/utils.py +276 -0
  56. agno/db/mysql/__init__.py +4 -0
  57. agno/db/mysql/async_mysql.py +2912 -0
  58. agno/db/mysql/mysql.py +2923 -0
  59. agno/db/mysql/schemas.py +186 -0
  60. agno/db/mysql/utils.py +488 -0
  61. agno/db/postgres/__init__.py +4 -0
  62. agno/db/postgres/async_postgres.py +2579 -0
  63. agno/db/postgres/postgres.py +2870 -0
  64. agno/db/postgres/schemas.py +187 -0
  65. agno/db/postgres/utils.py +442 -0
  66. agno/db/redis/__init__.py +3 -0
  67. agno/db/redis/redis.py +2141 -0
  68. agno/db/redis/schemas.py +159 -0
  69. agno/db/redis/utils.py +346 -0
  70. agno/db/schemas/__init__.py +4 -0
  71. agno/db/schemas/culture.py +120 -0
  72. agno/db/schemas/evals.py +34 -0
  73. agno/db/schemas/knowledge.py +40 -0
  74. agno/db/schemas/memory.py +61 -0
  75. agno/db/singlestore/__init__.py +3 -0
  76. agno/db/singlestore/schemas.py +179 -0
  77. agno/db/singlestore/singlestore.py +2877 -0
  78. agno/db/singlestore/utils.py +384 -0
  79. agno/db/sqlite/__init__.py +4 -0
  80. agno/db/sqlite/async_sqlite.py +2911 -0
  81. agno/db/sqlite/schemas.py +181 -0
  82. agno/db/sqlite/sqlite.py +2908 -0
  83. agno/db/sqlite/utils.py +429 -0
  84. agno/db/surrealdb/__init__.py +3 -0
  85. agno/db/surrealdb/metrics.py +292 -0
  86. agno/db/surrealdb/models.py +334 -0
  87. agno/db/surrealdb/queries.py +71 -0
  88. agno/db/surrealdb/surrealdb.py +1908 -0
  89. agno/db/surrealdb/utils.py +147 -0
  90. agno/db/utils.py +118 -0
  91. agno/eval/__init__.py +24 -0
  92. agno/eval/accuracy.py +666 -276
  93. agno/eval/agent_as_judge.py +861 -0
  94. agno/eval/base.py +29 -0
  95. agno/eval/performance.py +779 -0
  96. agno/eval/reliability.py +241 -62
  97. agno/eval/utils.py +120 -0
  98. agno/exceptions.py +143 -1
  99. agno/filters.py +354 -0
  100. agno/guardrails/__init__.py +6 -0
  101. agno/guardrails/base.py +19 -0
  102. agno/guardrails/openai.py +144 -0
  103. agno/guardrails/pii.py +94 -0
  104. agno/guardrails/prompt_injection.py +52 -0
  105. agno/hooks/__init__.py +3 -0
  106. agno/hooks/decorator.py +164 -0
  107. agno/integrations/discord/__init__.py +3 -0
  108. agno/integrations/discord/client.py +203 -0
  109. agno/knowledge/__init__.py +5 -1
  110. agno/{document → knowledge}/chunking/agentic.py +22 -14
  111. agno/{document → knowledge}/chunking/document.py +2 -2
  112. agno/{document → knowledge}/chunking/fixed.py +7 -6
  113. agno/knowledge/chunking/markdown.py +151 -0
  114. agno/{document → knowledge}/chunking/recursive.py +15 -3
  115. agno/knowledge/chunking/row.py +39 -0
  116. agno/knowledge/chunking/semantic.py +91 -0
  117. agno/knowledge/chunking/strategy.py +165 -0
  118. agno/knowledge/content.py +74 -0
  119. agno/knowledge/document/__init__.py +5 -0
  120. agno/{document → knowledge/document}/base.py +12 -2
  121. agno/knowledge/embedder/__init__.py +5 -0
  122. agno/knowledge/embedder/aws_bedrock.py +343 -0
  123. agno/knowledge/embedder/azure_openai.py +210 -0
  124. agno/{embedder → knowledge/embedder}/base.py +8 -0
  125. agno/knowledge/embedder/cohere.py +323 -0
  126. agno/knowledge/embedder/fastembed.py +62 -0
  127. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  128. agno/knowledge/embedder/google.py +258 -0
  129. agno/knowledge/embedder/huggingface.py +94 -0
  130. agno/knowledge/embedder/jina.py +182 -0
  131. agno/knowledge/embedder/langdb.py +22 -0
  132. agno/knowledge/embedder/mistral.py +206 -0
  133. agno/knowledge/embedder/nebius.py +13 -0
  134. agno/knowledge/embedder/ollama.py +154 -0
  135. agno/knowledge/embedder/openai.py +195 -0
  136. agno/knowledge/embedder/sentence_transformer.py +63 -0
  137. agno/{embedder → knowledge/embedder}/together.py +1 -1
  138. agno/knowledge/embedder/vllm.py +262 -0
  139. agno/knowledge/embedder/voyageai.py +165 -0
  140. agno/knowledge/knowledge.py +3006 -0
  141. agno/knowledge/reader/__init__.py +7 -0
  142. agno/knowledge/reader/arxiv_reader.py +81 -0
  143. agno/knowledge/reader/base.py +95 -0
  144. agno/knowledge/reader/csv_reader.py +164 -0
  145. agno/knowledge/reader/docx_reader.py +82 -0
  146. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  147. agno/knowledge/reader/firecrawl_reader.py +201 -0
  148. agno/knowledge/reader/json_reader.py +88 -0
  149. agno/knowledge/reader/markdown_reader.py +137 -0
  150. agno/knowledge/reader/pdf_reader.py +431 -0
  151. agno/knowledge/reader/pptx_reader.py +101 -0
  152. agno/knowledge/reader/reader_factory.py +313 -0
  153. agno/knowledge/reader/s3_reader.py +89 -0
  154. agno/knowledge/reader/tavily_reader.py +193 -0
  155. agno/knowledge/reader/text_reader.py +127 -0
  156. agno/knowledge/reader/web_search_reader.py +325 -0
  157. agno/knowledge/reader/website_reader.py +455 -0
  158. agno/knowledge/reader/wikipedia_reader.py +91 -0
  159. agno/knowledge/reader/youtube_reader.py +78 -0
  160. agno/knowledge/remote_content/remote_content.py +88 -0
  161. agno/knowledge/reranker/__init__.py +3 -0
  162. agno/{reranker → knowledge/reranker}/base.py +1 -1
  163. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  164. agno/knowledge/reranker/infinity.py +195 -0
  165. agno/knowledge/reranker/sentence_transformer.py +54 -0
  166. agno/knowledge/types.py +39 -0
  167. agno/knowledge/utils.py +234 -0
  168. agno/media.py +439 -95
  169. agno/memory/__init__.py +16 -3
  170. agno/memory/manager.py +1474 -123
  171. agno/memory/strategies/__init__.py +15 -0
  172. agno/memory/strategies/base.py +66 -0
  173. agno/memory/strategies/summarize.py +196 -0
  174. agno/memory/strategies/types.py +37 -0
  175. agno/models/aimlapi/__init__.py +5 -0
  176. agno/models/aimlapi/aimlapi.py +62 -0
  177. agno/models/anthropic/__init__.py +4 -0
  178. agno/models/anthropic/claude.py +960 -496
  179. agno/models/aws/__init__.py +15 -0
  180. agno/models/aws/bedrock.py +686 -451
  181. agno/models/aws/claude.py +190 -183
  182. agno/models/azure/__init__.py +18 -1
  183. agno/models/azure/ai_foundry.py +489 -0
  184. agno/models/azure/openai_chat.py +89 -40
  185. agno/models/base.py +2477 -550
  186. agno/models/cerebras/__init__.py +12 -0
  187. agno/models/cerebras/cerebras.py +565 -0
  188. agno/models/cerebras/cerebras_openai.py +131 -0
  189. agno/models/cohere/__init__.py +4 -0
  190. agno/models/cohere/chat.py +306 -492
  191. agno/models/cometapi/__init__.py +5 -0
  192. agno/models/cometapi/cometapi.py +74 -0
  193. agno/models/dashscope/__init__.py +5 -0
  194. agno/models/dashscope/dashscope.py +90 -0
  195. agno/models/deepinfra/__init__.py +5 -0
  196. agno/models/deepinfra/deepinfra.py +45 -0
  197. agno/models/deepseek/__init__.py +4 -0
  198. agno/models/deepseek/deepseek.py +110 -9
  199. agno/models/fireworks/__init__.py +4 -0
  200. agno/models/fireworks/fireworks.py +19 -22
  201. agno/models/google/__init__.py +3 -7
  202. agno/models/google/gemini.py +1717 -662
  203. agno/models/google/utils.py +22 -0
  204. agno/models/groq/__init__.py +4 -0
  205. agno/models/groq/groq.py +391 -666
  206. agno/models/huggingface/__init__.py +4 -0
  207. agno/models/huggingface/huggingface.py +266 -538
  208. agno/models/ibm/__init__.py +5 -0
  209. agno/models/ibm/watsonx.py +432 -0
  210. agno/models/internlm/__init__.py +3 -0
  211. agno/models/internlm/internlm.py +20 -3
  212. agno/models/langdb/__init__.py +1 -0
  213. agno/models/langdb/langdb.py +60 -0
  214. agno/models/litellm/__init__.py +14 -0
  215. agno/models/litellm/chat.py +503 -0
  216. agno/models/litellm/litellm_openai.py +42 -0
  217. agno/models/llama_cpp/__init__.py +5 -0
  218. agno/models/llama_cpp/llama_cpp.py +22 -0
  219. agno/models/lmstudio/__init__.py +5 -0
  220. agno/models/lmstudio/lmstudio.py +25 -0
  221. agno/models/message.py +361 -39
  222. agno/models/meta/__init__.py +12 -0
  223. agno/models/meta/llama.py +502 -0
  224. agno/models/meta/llama_openai.py +79 -0
  225. agno/models/metrics.py +120 -0
  226. agno/models/mistral/__init__.py +4 -0
  227. agno/models/mistral/mistral.py +293 -393
  228. agno/models/nebius/__init__.py +3 -0
  229. agno/models/nebius/nebius.py +53 -0
  230. agno/models/nexus/__init__.py +3 -0
  231. agno/models/nexus/nexus.py +22 -0
  232. agno/models/nvidia/__init__.py +4 -0
  233. agno/models/nvidia/nvidia.py +22 -3
  234. agno/models/ollama/__init__.py +4 -2
  235. agno/models/ollama/chat.py +257 -492
  236. agno/models/openai/__init__.py +7 -0
  237. agno/models/openai/chat.py +725 -770
  238. agno/models/openai/like.py +16 -2
  239. agno/models/openai/responses.py +1121 -0
  240. agno/models/openrouter/__init__.py +4 -0
  241. agno/models/openrouter/openrouter.py +62 -5
  242. agno/models/perplexity/__init__.py +5 -0
  243. agno/models/perplexity/perplexity.py +203 -0
  244. agno/models/portkey/__init__.py +3 -0
  245. agno/models/portkey/portkey.py +82 -0
  246. agno/models/requesty/__init__.py +5 -0
  247. agno/models/requesty/requesty.py +69 -0
  248. agno/models/response.py +177 -7
  249. agno/models/sambanova/__init__.py +4 -0
  250. agno/models/sambanova/sambanova.py +23 -4
  251. agno/models/siliconflow/__init__.py +5 -0
  252. agno/models/siliconflow/siliconflow.py +42 -0
  253. agno/models/together/__init__.py +4 -0
  254. agno/models/together/together.py +21 -164
  255. agno/models/utils.py +266 -0
  256. agno/models/vercel/__init__.py +3 -0
  257. agno/models/vercel/v0.py +43 -0
  258. agno/models/vertexai/__init__.py +0 -1
  259. agno/models/vertexai/claude.py +190 -0
  260. agno/models/vllm/__init__.py +3 -0
  261. agno/models/vllm/vllm.py +83 -0
  262. agno/models/xai/__init__.py +2 -0
  263. agno/models/xai/xai.py +111 -7
  264. agno/os/__init__.py +3 -0
  265. agno/os/app.py +1027 -0
  266. agno/os/auth.py +244 -0
  267. agno/os/config.py +126 -0
  268. agno/os/interfaces/__init__.py +1 -0
  269. agno/os/interfaces/a2a/__init__.py +3 -0
  270. agno/os/interfaces/a2a/a2a.py +42 -0
  271. agno/os/interfaces/a2a/router.py +249 -0
  272. agno/os/interfaces/a2a/utils.py +924 -0
  273. agno/os/interfaces/agui/__init__.py +3 -0
  274. agno/os/interfaces/agui/agui.py +47 -0
  275. agno/os/interfaces/agui/router.py +147 -0
  276. agno/os/interfaces/agui/utils.py +574 -0
  277. agno/os/interfaces/base.py +25 -0
  278. agno/os/interfaces/slack/__init__.py +3 -0
  279. agno/os/interfaces/slack/router.py +148 -0
  280. agno/os/interfaces/slack/security.py +30 -0
  281. agno/os/interfaces/slack/slack.py +47 -0
  282. agno/os/interfaces/whatsapp/__init__.py +3 -0
  283. agno/os/interfaces/whatsapp/router.py +210 -0
  284. agno/os/interfaces/whatsapp/security.py +55 -0
  285. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  286. agno/os/mcp.py +293 -0
  287. agno/os/middleware/__init__.py +9 -0
  288. agno/os/middleware/jwt.py +797 -0
  289. agno/os/router.py +258 -0
  290. agno/os/routers/__init__.py +3 -0
  291. agno/os/routers/agents/__init__.py +3 -0
  292. agno/os/routers/agents/router.py +599 -0
  293. agno/os/routers/agents/schema.py +261 -0
  294. agno/os/routers/evals/__init__.py +3 -0
  295. agno/os/routers/evals/evals.py +450 -0
  296. agno/os/routers/evals/schemas.py +174 -0
  297. agno/os/routers/evals/utils.py +231 -0
  298. agno/os/routers/health.py +31 -0
  299. agno/os/routers/home.py +52 -0
  300. agno/os/routers/knowledge/__init__.py +3 -0
  301. agno/os/routers/knowledge/knowledge.py +1008 -0
  302. agno/os/routers/knowledge/schemas.py +178 -0
  303. agno/os/routers/memory/__init__.py +3 -0
  304. agno/os/routers/memory/memory.py +661 -0
  305. agno/os/routers/memory/schemas.py +88 -0
  306. agno/os/routers/metrics/__init__.py +3 -0
  307. agno/os/routers/metrics/metrics.py +190 -0
  308. agno/os/routers/metrics/schemas.py +47 -0
  309. agno/os/routers/session/__init__.py +3 -0
  310. agno/os/routers/session/session.py +997 -0
  311. agno/os/routers/teams/__init__.py +3 -0
  312. agno/os/routers/teams/router.py +512 -0
  313. agno/os/routers/teams/schema.py +257 -0
  314. agno/os/routers/traces/__init__.py +3 -0
  315. agno/os/routers/traces/schemas.py +414 -0
  316. agno/os/routers/traces/traces.py +499 -0
  317. agno/os/routers/workflows/__init__.py +3 -0
  318. agno/os/routers/workflows/router.py +624 -0
  319. agno/os/routers/workflows/schema.py +75 -0
  320. agno/os/schema.py +534 -0
  321. agno/os/scopes.py +469 -0
  322. agno/{playground → os}/settings.py +7 -15
  323. agno/os/utils.py +973 -0
  324. agno/reasoning/anthropic.py +80 -0
  325. agno/reasoning/azure_ai_foundry.py +67 -0
  326. agno/reasoning/deepseek.py +63 -0
  327. agno/reasoning/default.py +97 -0
  328. agno/reasoning/gemini.py +73 -0
  329. agno/reasoning/groq.py +71 -0
  330. agno/reasoning/helpers.py +24 -1
  331. agno/reasoning/ollama.py +67 -0
  332. agno/reasoning/openai.py +86 -0
  333. agno/reasoning/step.py +2 -1
  334. agno/reasoning/vertexai.py +76 -0
  335. agno/run/__init__.py +6 -0
  336. agno/run/agent.py +822 -0
  337. agno/run/base.py +247 -0
  338. agno/run/cancel.py +81 -0
  339. agno/run/requirement.py +181 -0
  340. agno/run/team.py +767 -0
  341. agno/run/workflow.py +708 -0
  342. agno/session/__init__.py +10 -0
  343. agno/session/agent.py +260 -0
  344. agno/session/summary.py +265 -0
  345. agno/session/team.py +342 -0
  346. agno/session/workflow.py +501 -0
  347. agno/table.py +10 -0
  348. agno/team/__init__.py +37 -0
  349. agno/team/team.py +9536 -0
  350. agno/tools/__init__.py +7 -0
  351. agno/tools/agentql.py +120 -0
  352. agno/tools/airflow.py +22 -12
  353. agno/tools/api.py +122 -0
  354. agno/tools/apify.py +276 -83
  355. agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
  356. agno/tools/aws_lambda.py +28 -7
  357. agno/tools/aws_ses.py +66 -0
  358. agno/tools/baidusearch.py +11 -4
  359. agno/tools/bitbucket.py +292 -0
  360. agno/tools/brandfetch.py +213 -0
  361. agno/tools/bravesearch.py +106 -0
  362. agno/tools/brightdata.py +367 -0
  363. agno/tools/browserbase.py +209 -0
  364. agno/tools/calcom.py +32 -23
  365. agno/tools/calculator.py +24 -37
  366. agno/tools/cartesia.py +187 -0
  367. agno/tools/{clickup_tool.py → clickup.py} +17 -28
  368. agno/tools/confluence.py +91 -26
  369. agno/tools/crawl4ai.py +139 -43
  370. agno/tools/csv_toolkit.py +28 -22
  371. agno/tools/dalle.py +36 -22
  372. agno/tools/daytona.py +475 -0
  373. agno/tools/decorator.py +169 -14
  374. agno/tools/desi_vocal.py +23 -11
  375. agno/tools/discord.py +32 -29
  376. agno/tools/docker.py +716 -0
  377. agno/tools/duckdb.py +76 -81
  378. agno/tools/duckduckgo.py +43 -40
  379. agno/tools/e2b.py +703 -0
  380. agno/tools/eleven_labs.py +65 -54
  381. agno/tools/email.py +13 -5
  382. agno/tools/evm.py +129 -0
  383. agno/tools/exa.py +324 -42
  384. agno/tools/fal.py +39 -35
  385. agno/tools/file.py +196 -30
  386. agno/tools/file_generation.py +356 -0
  387. agno/tools/financial_datasets.py +288 -0
  388. agno/tools/firecrawl.py +108 -33
  389. agno/tools/function.py +960 -122
  390. agno/tools/giphy.py +34 -12
  391. agno/tools/github.py +1294 -97
  392. agno/tools/gmail.py +922 -0
  393. agno/tools/google_bigquery.py +117 -0
  394. agno/tools/google_drive.py +271 -0
  395. agno/tools/google_maps.py +253 -0
  396. agno/tools/googlecalendar.py +607 -107
  397. agno/tools/googlesheets.py +377 -0
  398. agno/tools/hackernews.py +20 -12
  399. agno/tools/jina.py +24 -14
  400. agno/tools/jira.py +48 -19
  401. agno/tools/knowledge.py +218 -0
  402. agno/tools/linear.py +82 -43
  403. agno/tools/linkup.py +58 -0
  404. agno/tools/local_file_system.py +15 -7
  405. agno/tools/lumalab.py +41 -26
  406. agno/tools/mcp/__init__.py +10 -0
  407. agno/tools/mcp/mcp.py +331 -0
  408. agno/tools/mcp/multi_mcp.py +347 -0
  409. agno/tools/mcp/params.py +24 -0
  410. agno/tools/mcp_toolbox.py +284 -0
  411. agno/tools/mem0.py +193 -0
  412. agno/tools/memory.py +419 -0
  413. agno/tools/mlx_transcribe.py +11 -9
  414. agno/tools/models/azure_openai.py +190 -0
  415. agno/tools/models/gemini.py +203 -0
  416. agno/tools/models/groq.py +158 -0
  417. agno/tools/models/morph.py +186 -0
  418. agno/tools/models/nebius.py +124 -0
  419. agno/tools/models_labs.py +163 -82
  420. agno/tools/moviepy_video.py +18 -13
  421. agno/tools/nano_banana.py +151 -0
  422. agno/tools/neo4j.py +134 -0
  423. agno/tools/newspaper.py +15 -4
  424. agno/tools/newspaper4k.py +19 -6
  425. agno/tools/notion.py +204 -0
  426. agno/tools/openai.py +181 -17
  427. agno/tools/openbb.py +27 -20
  428. agno/tools/opencv.py +321 -0
  429. agno/tools/openweather.py +233 -0
  430. agno/tools/oxylabs.py +385 -0
  431. agno/tools/pandas.py +25 -15
  432. agno/tools/parallel.py +314 -0
  433. agno/tools/postgres.py +238 -185
  434. agno/tools/pubmed.py +125 -13
  435. agno/tools/python.py +48 -35
  436. agno/tools/reasoning.py +283 -0
  437. agno/tools/reddit.py +207 -29
  438. agno/tools/redshift.py +406 -0
  439. agno/tools/replicate.py +69 -26
  440. agno/tools/resend.py +11 -6
  441. agno/tools/scrapegraph.py +179 -19
  442. agno/tools/searxng.py +23 -31
  443. agno/tools/serpapi.py +15 -10
  444. agno/tools/serper.py +255 -0
  445. agno/tools/shell.py +23 -12
  446. agno/tools/shopify.py +1519 -0
  447. agno/tools/slack.py +56 -14
  448. agno/tools/sleep.py +8 -6
  449. agno/tools/spider.py +35 -11
  450. agno/tools/spotify.py +919 -0
  451. agno/tools/sql.py +34 -19
  452. agno/tools/tavily.py +158 -8
  453. agno/tools/telegram.py +18 -8
  454. agno/tools/todoist.py +218 -0
  455. agno/tools/toolkit.py +134 -9
  456. agno/tools/trafilatura.py +388 -0
  457. agno/tools/trello.py +25 -28
  458. agno/tools/twilio.py +18 -9
  459. agno/tools/user_control_flow.py +78 -0
  460. agno/tools/valyu.py +228 -0
  461. agno/tools/visualization.py +467 -0
  462. agno/tools/webbrowser.py +28 -0
  463. agno/tools/webex.py +76 -0
  464. agno/tools/website.py +23 -19
  465. agno/tools/webtools.py +45 -0
  466. agno/tools/whatsapp.py +286 -0
  467. agno/tools/wikipedia.py +28 -19
  468. agno/tools/workflow.py +285 -0
  469. agno/tools/{twitter.py → x.py} +142 -46
  470. agno/tools/yfinance.py +41 -39
  471. agno/tools/youtube.py +34 -17
  472. agno/tools/zendesk.py +15 -5
  473. agno/tools/zep.py +454 -0
  474. agno/tools/zoom.py +86 -37
  475. agno/tracing/__init__.py +12 -0
  476. agno/tracing/exporter.py +157 -0
  477. agno/tracing/schemas.py +276 -0
  478. agno/tracing/setup.py +111 -0
  479. agno/utils/agent.py +938 -0
  480. agno/utils/audio.py +37 -1
  481. agno/utils/certs.py +27 -0
  482. agno/utils/code_execution.py +11 -0
  483. agno/utils/common.py +103 -20
  484. agno/utils/cryptography.py +22 -0
  485. agno/utils/dttm.py +33 -0
  486. agno/utils/events.py +700 -0
  487. agno/utils/functions.py +107 -37
  488. agno/utils/gemini.py +426 -0
  489. agno/utils/hooks.py +171 -0
  490. agno/utils/http.py +185 -0
  491. agno/utils/json_schema.py +159 -37
  492. agno/utils/knowledge.py +36 -0
  493. agno/utils/location.py +19 -0
  494. agno/utils/log.py +221 -8
  495. agno/utils/mcp.py +214 -0
  496. agno/utils/media.py +335 -14
  497. agno/utils/merge_dict.py +22 -1
  498. agno/utils/message.py +77 -2
  499. agno/utils/models/ai_foundry.py +50 -0
  500. agno/utils/models/claude.py +373 -0
  501. agno/utils/models/cohere.py +94 -0
  502. agno/utils/models/llama.py +85 -0
  503. agno/utils/models/mistral.py +100 -0
  504. agno/utils/models/openai_responses.py +140 -0
  505. agno/utils/models/schema_utils.py +153 -0
  506. agno/utils/models/watsonx.py +41 -0
  507. agno/utils/openai.py +257 -0
  508. agno/utils/pickle.py +1 -1
  509. agno/utils/pprint.py +124 -8
  510. agno/utils/print_response/agent.py +930 -0
  511. agno/utils/print_response/team.py +1914 -0
  512. agno/utils/print_response/workflow.py +1668 -0
  513. agno/utils/prompts.py +111 -0
  514. agno/utils/reasoning.py +108 -0
  515. agno/utils/response.py +163 -0
  516. agno/utils/serialize.py +32 -0
  517. agno/utils/shell.py +4 -4
  518. agno/utils/streamlit.py +487 -0
  519. agno/utils/string.py +204 -51
  520. agno/utils/team.py +139 -0
  521. agno/utils/timer.py +9 -2
  522. agno/utils/tokens.py +657 -0
  523. agno/utils/tools.py +19 -1
  524. agno/utils/whatsapp.py +305 -0
  525. agno/utils/yaml_io.py +3 -3
  526. agno/vectordb/__init__.py +2 -0
  527. agno/vectordb/base.py +87 -9
  528. agno/vectordb/cassandra/__init__.py +5 -1
  529. agno/vectordb/cassandra/cassandra.py +383 -27
  530. agno/vectordb/chroma/__init__.py +4 -0
  531. agno/vectordb/chroma/chromadb.py +748 -83
  532. agno/vectordb/clickhouse/__init__.py +7 -1
  533. agno/vectordb/clickhouse/clickhousedb.py +554 -53
  534. agno/vectordb/couchbase/__init__.py +3 -0
  535. agno/vectordb/couchbase/couchbase.py +1446 -0
  536. agno/vectordb/lancedb/__init__.py +5 -0
  537. agno/vectordb/lancedb/lance_db.py +730 -98
  538. agno/vectordb/langchaindb/__init__.py +5 -0
  539. agno/vectordb/langchaindb/langchaindb.py +163 -0
  540. agno/vectordb/lightrag/__init__.py +5 -0
  541. agno/vectordb/lightrag/lightrag.py +388 -0
  542. agno/vectordb/llamaindex/__init__.py +3 -0
  543. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  544. agno/vectordb/milvus/__init__.py +3 -0
  545. agno/vectordb/milvus/milvus.py +966 -78
  546. agno/vectordb/mongodb/__init__.py +9 -1
  547. agno/vectordb/mongodb/mongodb.py +1175 -172
  548. agno/vectordb/pgvector/__init__.py +8 -0
  549. agno/vectordb/pgvector/pgvector.py +599 -115
  550. agno/vectordb/pineconedb/__init__.py +5 -1
  551. agno/vectordb/pineconedb/pineconedb.py +406 -43
  552. agno/vectordb/qdrant/__init__.py +4 -0
  553. agno/vectordb/qdrant/qdrant.py +914 -61
  554. agno/vectordb/redis/__init__.py +9 -0
  555. agno/vectordb/redis/redisdb.py +682 -0
  556. agno/vectordb/singlestore/__init__.py +8 -1
  557. agno/vectordb/singlestore/singlestore.py +771 -0
  558. agno/vectordb/surrealdb/__init__.py +3 -0
  559. agno/vectordb/surrealdb/surrealdb.py +663 -0
  560. agno/vectordb/upstashdb/__init__.py +5 -0
  561. agno/vectordb/upstashdb/upstashdb.py +718 -0
  562. agno/vectordb/weaviate/__init__.py +8 -0
  563. agno/vectordb/weaviate/index.py +15 -0
  564. agno/vectordb/weaviate/weaviate.py +1009 -0
  565. agno/workflow/__init__.py +23 -1
  566. agno/workflow/agent.py +299 -0
  567. agno/workflow/condition.py +759 -0
  568. agno/workflow/loop.py +756 -0
  569. agno/workflow/parallel.py +853 -0
  570. agno/workflow/router.py +723 -0
  571. agno/workflow/step.py +1564 -0
  572. agno/workflow/steps.py +613 -0
  573. agno/workflow/types.py +556 -0
  574. agno/workflow/workflow.py +4327 -514
  575. agno-2.3.13.dist-info/METADATA +639 -0
  576. agno-2.3.13.dist-info/RECORD +613 -0
  577. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
  578. agno-2.3.13.dist-info/licenses/LICENSE +201 -0
  579. agno/api/playground.py +0 -91
  580. agno/api/schemas/playground.py +0 -22
  581. agno/api/schemas/user.py +0 -22
  582. agno/api/schemas/workspace.py +0 -46
  583. agno/api/user.py +0 -160
  584. agno/api/workspace.py +0 -151
  585. agno/cli/auth_server.py +0 -118
  586. agno/cli/config.py +0 -275
  587. agno/cli/console.py +0 -88
  588. agno/cli/credentials.py +0 -23
  589. agno/cli/entrypoint.py +0 -571
  590. agno/cli/operator.py +0 -355
  591. agno/cli/settings.py +0 -85
  592. agno/cli/ws/ws_cli.py +0 -817
  593. agno/constants.py +0 -13
  594. agno/document/__init__.py +0 -1
  595. agno/document/chunking/semantic.py +0 -47
  596. agno/document/chunking/strategy.py +0 -31
  597. agno/document/reader/__init__.py +0 -1
  598. agno/document/reader/arxiv_reader.py +0 -41
  599. agno/document/reader/base.py +0 -22
  600. agno/document/reader/csv_reader.py +0 -84
  601. agno/document/reader/docx_reader.py +0 -46
  602. agno/document/reader/firecrawl_reader.py +0 -99
  603. agno/document/reader/json_reader.py +0 -43
  604. agno/document/reader/pdf_reader.py +0 -219
  605. agno/document/reader/s3/pdf_reader.py +0 -46
  606. agno/document/reader/s3/text_reader.py +0 -51
  607. agno/document/reader/text_reader.py +0 -41
  608. agno/document/reader/website_reader.py +0 -175
  609. agno/document/reader/youtube_reader.py +0 -50
  610. agno/embedder/__init__.py +0 -1
  611. agno/embedder/azure_openai.py +0 -86
  612. agno/embedder/cohere.py +0 -72
  613. agno/embedder/fastembed.py +0 -37
  614. agno/embedder/google.py +0 -73
  615. agno/embedder/huggingface.py +0 -54
  616. agno/embedder/mistral.py +0 -80
  617. agno/embedder/ollama.py +0 -57
  618. agno/embedder/openai.py +0 -74
  619. agno/embedder/sentence_transformer.py +0 -38
  620. agno/embedder/voyageai.py +0 -64
  621. agno/eval/perf.py +0 -201
  622. agno/file/__init__.py +0 -1
  623. agno/file/file.py +0 -16
  624. agno/file/local/csv.py +0 -32
  625. agno/file/local/txt.py +0 -19
  626. agno/infra/app.py +0 -240
  627. agno/infra/base.py +0 -144
  628. agno/infra/context.py +0 -20
  629. agno/infra/db_app.py +0 -52
  630. agno/infra/resource.py +0 -205
  631. agno/infra/resources.py +0 -55
  632. agno/knowledge/agent.py +0 -230
  633. agno/knowledge/arxiv.py +0 -22
  634. agno/knowledge/combined.py +0 -22
  635. agno/knowledge/csv.py +0 -28
  636. agno/knowledge/csv_url.py +0 -19
  637. agno/knowledge/document.py +0 -20
  638. agno/knowledge/docx.py +0 -30
  639. agno/knowledge/json.py +0 -28
  640. agno/knowledge/langchain.py +0 -71
  641. agno/knowledge/llamaindex.py +0 -66
  642. agno/knowledge/pdf.py +0 -28
  643. agno/knowledge/pdf_url.py +0 -26
  644. agno/knowledge/s3/base.py +0 -60
  645. agno/knowledge/s3/pdf.py +0 -21
  646. agno/knowledge/s3/text.py +0 -23
  647. agno/knowledge/text.py +0 -30
  648. agno/knowledge/website.py +0 -88
  649. agno/knowledge/wikipedia.py +0 -31
  650. agno/knowledge/youtube.py +0 -22
  651. agno/memory/agent.py +0 -392
  652. agno/memory/classifier.py +0 -104
  653. agno/memory/db/__init__.py +0 -1
  654. agno/memory/db/base.py +0 -42
  655. agno/memory/db/mongodb.py +0 -189
  656. agno/memory/db/postgres.py +0 -203
  657. agno/memory/db/sqlite.py +0 -193
  658. agno/memory/memory.py +0 -15
  659. agno/memory/row.py +0 -36
  660. agno/memory/summarizer.py +0 -192
  661. agno/memory/summary.py +0 -19
  662. agno/memory/workflow.py +0 -38
  663. agno/models/google/gemini_openai.py +0 -26
  664. agno/models/ollama/hermes.py +0 -221
  665. agno/models/ollama/tools.py +0 -362
  666. agno/models/vertexai/gemini.py +0 -595
  667. agno/playground/__init__.py +0 -3
  668. agno/playground/async_router.py +0 -421
  669. agno/playground/deploy.py +0 -249
  670. agno/playground/operator.py +0 -92
  671. agno/playground/playground.py +0 -91
  672. agno/playground/schemas.py +0 -76
  673. agno/playground/serve.py +0 -55
  674. agno/playground/sync_router.py +0 -405
  675. agno/reasoning/agent.py +0 -68
  676. agno/run/response.py +0 -112
  677. agno/storage/agent/__init__.py +0 -0
  678. agno/storage/agent/base.py +0 -38
  679. agno/storage/agent/dynamodb.py +0 -350
  680. agno/storage/agent/json.py +0 -92
  681. agno/storage/agent/mongodb.py +0 -228
  682. agno/storage/agent/postgres.py +0 -367
  683. agno/storage/agent/session.py +0 -79
  684. agno/storage/agent/singlestore.py +0 -303
  685. agno/storage/agent/sqlite.py +0 -357
  686. agno/storage/agent/yaml.py +0 -93
  687. agno/storage/workflow/__init__.py +0 -0
  688. agno/storage/workflow/base.py +0 -40
  689. agno/storage/workflow/mongodb.py +0 -233
  690. agno/storage/workflow/postgres.py +0 -366
  691. agno/storage/workflow/session.py +0 -60
  692. agno/storage/workflow/sqlite.py +0 -359
  693. agno/tools/googlesearch.py +0 -88
  694. agno/utils/defaults.py +0 -57
  695. agno/utils/filesystem.py +0 -39
  696. agno/utils/git.py +0 -52
  697. agno/utils/json_io.py +0 -30
  698. agno/utils/load_env.py +0 -19
  699. agno/utils/py_io.py +0 -19
  700. agno/utils/pyproject.py +0 -18
  701. agno/utils/resource_filter.py +0 -31
  702. agno/vectordb/singlestore/s2vectordb.py +0 -390
  703. agno/vectordb/singlestore/s2vectordb2.py +0 -355
  704. agno/workspace/__init__.py +0 -0
  705. agno/workspace/config.py +0 -325
  706. agno/workspace/enums.py +0 -6
  707. agno/workspace/helpers.py +0 -48
  708. agno/workspace/operator.py +0 -758
  709. agno/workspace/settings.py +0 -63
  710. agno-0.1.2.dist-info/LICENSE +0 -375
  711. agno-0.1.2.dist-info/METADATA +0 -502
  712. agno-0.1.2.dist-info/RECORD +0 -352
  713. agno-0.1.2.dist-info/entry_points.txt +0 -3
  714. /agno/{cli → db/migrations}/__init__.py +0 -0
  715. /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
  716. /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
  717. /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
  718. /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
  719. /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
  720. /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
  721. /agno/{reranker → utils/models}/__init__.py +0 -0
  722. /agno/{storage → utils/print_response}/__init__.py +0 -0
  723. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,930 @@
1
+ import json
2
+ import warnings
3
+ from collections.abc import Set
4
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Union, cast, get_args
5
+
6
+ from pydantic import BaseModel
7
+ from rich.console import Group
8
+ from rich.json import JSON
9
+ from rich.live import Live
10
+ from rich.markdown import Markdown
11
+ from rich.status import Status
12
+ from rich.text import Text
13
+
14
+ from agno.filters import FilterExpr
15
+ from agno.media import Audio, File, Image, Video
16
+ from agno.models.message import Message
17
+ from agno.reasoning.step import ReasoningStep
18
+ from agno.run.agent import RunEvent, RunOutput, RunOutputEvent, RunPausedEvent
19
+ from agno.utils.log import log_warning
20
+ from agno.utils.message import get_text_from_message
21
+ from agno.utils.response import create_panel, create_paused_run_output_panel, escape_markdown_tags, format_tool_calls
22
+ from agno.utils.timer import Timer
23
+
24
+ if TYPE_CHECKING:
25
+ from agno.agent.agent import Agent
26
+
27
+
28
+ def print_response_stream(
29
+ agent: "Agent",
30
+ input: Union[List, Dict, str, Message, BaseModel, List[Message]],
31
+ session_id: Optional[str] = None,
32
+ session_state: Optional[Dict[str, Any]] = None,
33
+ user_id: Optional[str] = None,
34
+ run_id: Optional[str] = None,
35
+ audio: Optional[Sequence[Audio]] = None,
36
+ images: Optional[Sequence[Image]] = None,
37
+ videos: Optional[Sequence[Video]] = None,
38
+ files: Optional[Sequence[File]] = None,
39
+ knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
40
+ debug_mode: Optional[bool] = None,
41
+ markdown: bool = False,
42
+ show_message: bool = True,
43
+ show_reasoning: bool = True,
44
+ show_full_reasoning: bool = False,
45
+ tags_to_include_in_markdown: Set[str] = {"think", "thinking"},
46
+ console: Optional[Any] = None,
47
+ add_history_to_context: Optional[bool] = None,
48
+ dependencies: Optional[Dict[str, Any]] = None,
49
+ add_dependencies_to_context: Optional[bool] = None,
50
+ add_session_state_to_context: Optional[bool] = None,
51
+ metadata: Optional[Dict[str, Any]] = None,
52
+ **kwargs: Any,
53
+ ):
54
+ _response_content: str = ""
55
+ _response_reasoning_content: str = ""
56
+ response_content_batch: Union[str, JSON, Markdown] = ""
57
+ reasoning_steps: List[ReasoningStep] = []
58
+ accumulated_tool_calls: List = []
59
+
60
+ with Live(console=console) as live_log:
61
+ status = Status("Thinking...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
62
+ live_log.update(status)
63
+ response_timer = Timer()
64
+ response_timer.start()
65
+ # Flag which indicates if the panels should be rendered
66
+ render = False
67
+ # Panels to be rendered
68
+ panels = [status]
69
+ # First render the message panel if the message is not None
70
+ if input and show_message:
71
+ render = True
72
+ # Convert message to a panel
73
+ message_content = get_text_from_message(input)
74
+ message_panel = create_panel(
75
+ content=Text(message_content, style="green"),
76
+ title="Message",
77
+ border_style="cyan",
78
+ )
79
+ panels.append(message_panel)
80
+ if render:
81
+ live_log.update(Group(*panels))
82
+
83
+ input_content = get_text_from_message(input)
84
+
85
+ for response_event in agent.run(
86
+ input=input,
87
+ session_id=session_id,
88
+ session_state=session_state,
89
+ user_id=user_id,
90
+ run_id=run_id,
91
+ audio=audio,
92
+ images=images,
93
+ videos=videos,
94
+ files=files,
95
+ stream=True,
96
+ knowledge_filters=knowledge_filters,
97
+ debug_mode=debug_mode,
98
+ add_history_to_context=add_history_to_context,
99
+ add_dependencies_to_context=add_dependencies_to_context,
100
+ add_session_state_to_context=add_session_state_to_context,
101
+ dependencies=dependencies,
102
+ metadata=metadata,
103
+ **kwargs,
104
+ ):
105
+ if isinstance(response_event, tuple(get_args(RunOutputEvent))):
106
+ if response_event.is_paused: # type: ignore
107
+ response_event = cast(RunPausedEvent, response_event) # type: ignore
108
+ response_panel = create_paused_run_output_panel(response_event) # type: ignore
109
+ panels.append(response_panel)
110
+ live_log.update(Group(*panels))
111
+ return
112
+
113
+ if response_event.event == RunEvent.pre_hook_completed: # type: ignore
114
+ if response_event.run_input is not None: # type: ignore
115
+ input_content = get_text_from_message(response_event.run_input.input_content) # type: ignore
116
+
117
+ if (
118
+ response_event.event == RunEvent.tool_call_started # type: ignore
119
+ and hasattr(response_event, "tool")
120
+ and response_event.tool is not None
121
+ ):
122
+ accumulated_tool_calls.append(response_event.tool)
123
+
124
+ if response_event.event == RunEvent.run_content: # type: ignore
125
+ if hasattr(response_event, "content"):
126
+ if isinstance(response_event.content, str):
127
+ # Don't accumulate text content, parser_model will replace it
128
+ if not (agent.parser_model is not None and agent.output_schema is not None):
129
+ _response_content += response_event.content
130
+ elif agent.output_schema is not None and isinstance(response_event.content, BaseModel):
131
+ try:
132
+ response_content_batch = JSON( # type: ignore
133
+ response_event.content.model_dump_json(exclude_none=True), indent=2
134
+ )
135
+ except Exception as e:
136
+ log_warning(f"Failed to convert response to JSON: {e}")
137
+ else:
138
+ try:
139
+ response_content_batch = JSON(json.dumps(response_event.content), indent=4)
140
+ except Exception as e:
141
+ log_warning(f"Failed to convert response to JSON: {e}")
142
+ if hasattr(response_event, "reasoning_content") and response_event.reasoning_content is not None: # type: ignore
143
+ _response_reasoning_content += response_event.reasoning_content # type: ignore
144
+ if hasattr(response_event, "reasoning_steps") and response_event.reasoning_steps is not None: # type: ignore
145
+ reasoning_steps = response_event.reasoning_steps # type: ignore
146
+
147
+ # Escape special tags before markdown conversion
148
+ if markdown:
149
+ escaped_content = escape_markdown_tags(_response_content, tags_to_include_in_markdown) # type: ignore
150
+ response_content_batch = Markdown(escaped_content)
151
+
152
+ response_content_stream: str = _response_content
153
+
154
+ # Check if we have any response content to display
155
+ if response_content_stream and not markdown:
156
+ response_content = response_content_stream
157
+ else:
158
+ response_content = response_content_batch # type: ignore
159
+
160
+ # Sanitize empty Markdown content
161
+ if isinstance(response_content, Markdown):
162
+ if not (response_content.markup and response_content.markup.strip()):
163
+ response_content = None # type: ignore
164
+
165
+ panels = [status]
166
+ if show_message:
167
+ # Convert message to a panel
168
+ message_panel = create_panel(
169
+ content=Text(input_content, style="green"),
170
+ title="Message",
171
+ border_style="cyan",
172
+ )
173
+ panels.append(message_panel)
174
+
175
+ additional_panels = build_panels_stream(
176
+ response_content=response_content,
177
+ response_event=response_event, # type: ignore
178
+ response_timer=response_timer,
179
+ response_reasoning_content_buffer=_response_reasoning_content,
180
+ reasoning_steps=reasoning_steps,
181
+ show_reasoning=show_reasoning,
182
+ show_full_reasoning=show_full_reasoning,
183
+ accumulated_tool_calls=accumulated_tool_calls,
184
+ compression_manager=agent.compression_manager,
185
+ )
186
+ panels.extend(additional_panels)
187
+ if panels:
188
+ live_log.update(Group(*panels))
189
+
190
+ if agent.memory_manager is not None and agent.memory_manager.memories_updated:
191
+ memory_panel = create_panel(
192
+ content=Text("Memories updated"),
193
+ title="Memories",
194
+ border_style="green",
195
+ )
196
+ panels.append(memory_panel)
197
+ live_log.update(Group(*panels))
198
+ agent.memory_manager.memories_updated = False
199
+
200
+ if agent.session_summary_manager is not None and agent.session_summary_manager.summaries_updated:
201
+ summary_panel = create_panel(
202
+ content=Text("Session summary updated"),
203
+ title="Session Summary",
204
+ border_style="green",
205
+ )
206
+ panels.append(summary_panel)
207
+ live_log.update(Group(*panels))
208
+ agent.session_summary_manager.summaries_updated = False
209
+
210
+ # Clear compression stats after final display
211
+ if agent.compression_manager is not None:
212
+ agent.compression_manager.stats.clear()
213
+
214
+ response_timer.stop()
215
+
216
+ # Final update to remove the "Thinking..." status
217
+ panels = [p for p in panels if not isinstance(p, Status)]
218
+ live_log.update(Group(*panels))
219
+
220
+
221
+ async def aprint_response_stream(
222
+ agent: "Agent",
223
+ input: Union[List, Dict, str, Message, BaseModel, List[Message]],
224
+ session_id: Optional[str] = None,
225
+ session_state: Optional[Dict[str, Any]] = None,
226
+ user_id: Optional[str] = None,
227
+ run_id: Optional[str] = None,
228
+ audio: Optional[Sequence[Audio]] = None,
229
+ images: Optional[Sequence[Image]] = None,
230
+ videos: Optional[Sequence[Video]] = None,
231
+ files: Optional[Sequence[File]] = None,
232
+ knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
233
+ debug_mode: Optional[bool] = None,
234
+ markdown: bool = False,
235
+ show_message: bool = True,
236
+ show_reasoning: bool = True,
237
+ show_full_reasoning: bool = False,
238
+ tags_to_include_in_markdown: Set[str] = {"think", "thinking"},
239
+ console: Optional[Any] = None,
240
+ add_history_to_context: Optional[bool] = None,
241
+ dependencies: Optional[Dict[str, Any]] = None,
242
+ add_dependencies_to_context: Optional[bool] = None,
243
+ add_session_state_to_context: Optional[bool] = None,
244
+ metadata: Optional[Dict[str, Any]] = None,
245
+ **kwargs: Any,
246
+ ):
247
+ _response_content: str = ""
248
+ _response_reasoning_content: str = ""
249
+ reasoning_steps: List[ReasoningStep] = []
250
+ response_content_batch: Union[str, JSON, Markdown] = ""
251
+ accumulated_tool_calls: List = []
252
+
253
+ with Live(console=console) as live_log:
254
+ status = Status("Thinking...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
255
+ live_log.update(status)
256
+ response_timer = Timer()
257
+ response_timer.start()
258
+ # Flag which indicates if the panels should be rendered
259
+ render = False
260
+ # Panels to be rendered
261
+ panels = [status]
262
+ # First render the message panel if the message is not None
263
+ if input and show_message:
264
+ render = True
265
+ # Convert message to a panel
266
+ message_content = get_text_from_message(input)
267
+ message_panel = create_panel(
268
+ content=Text(message_content, style="green"),
269
+ title="Message",
270
+ border_style="cyan",
271
+ )
272
+ panels.append(message_panel)
273
+ if render:
274
+ live_log.update(Group(*panels))
275
+
276
+ result = agent.arun(
277
+ input=input,
278
+ session_id=session_id,
279
+ session_state=session_state,
280
+ user_id=user_id,
281
+ run_id=run_id,
282
+ audio=audio,
283
+ images=images,
284
+ videos=videos,
285
+ files=files,
286
+ stream=True,
287
+ knowledge_filters=knowledge_filters,
288
+ debug_mode=debug_mode,
289
+ add_history_to_context=add_history_to_context,
290
+ add_dependencies_to_context=add_dependencies_to_context,
291
+ add_session_state_to_context=add_session_state_to_context,
292
+ dependencies=dependencies,
293
+ metadata=metadata,
294
+ **kwargs,
295
+ )
296
+
297
+ input_content = get_text_from_message(input)
298
+
299
+ async for resp in result: # type: ignore
300
+ if isinstance(resp, tuple(get_args(RunOutputEvent))):
301
+ if resp.is_paused:
302
+ response_panel = create_paused_run_output_panel(resp) # type: ignore
303
+ panels.append(response_panel)
304
+ live_log.update(Group(*panels))
305
+ break
306
+
307
+ if (
308
+ resp.event == RunEvent.tool_call_started # type: ignore
309
+ and hasattr(resp, "tool")
310
+ and resp.tool is not None
311
+ ):
312
+ accumulated_tool_calls.append(resp.tool)
313
+
314
+ if resp.event == RunEvent.pre_hook_completed: # type: ignore
315
+ if resp.run_input is not None: # type: ignore
316
+ input_content = get_text_from_message(resp.run_input.input_content) # type: ignore
317
+
318
+ if resp.event == RunEvent.run_content: # type: ignore
319
+ if isinstance(resp.content, str):
320
+ # Don't accumulate text content, parser_model will replace it
321
+ if not (agent.parser_model is not None and agent.output_schema is not None):
322
+ _response_content += resp.content
323
+ elif agent.output_schema is not None and isinstance(resp.content, BaseModel):
324
+ try:
325
+ response_content_batch = JSON(resp.content.model_dump_json(exclude_none=True), indent=2) # type: ignore
326
+ except Exception as e:
327
+ log_warning(f"Failed to convert response to JSON: {e}")
328
+ else:
329
+ try:
330
+ response_content_batch = JSON(json.dumps(resp.content), indent=4)
331
+ except Exception as e:
332
+ log_warning(f"Failed to convert response to JSON: {e}")
333
+ if resp.reasoning_content is not None: # type: ignore
334
+ _response_reasoning_content += resp.reasoning_content # type: ignore
335
+
336
+ if hasattr(resp, "reasoning_steps") and resp.reasoning_steps is not None: # type: ignore
337
+ reasoning_steps = resp.reasoning_steps # type: ignore
338
+
339
+ response_content_stream: str = _response_content
340
+
341
+ # Escape special tags before markdown conversion
342
+ if markdown:
343
+ escaped_content = escape_markdown_tags(_response_content, tags_to_include_in_markdown) # type: ignore
344
+ response_content_batch = Markdown(escaped_content)
345
+
346
+ # Check if we have any response content to display
347
+ if response_content_stream and not markdown:
348
+ response_content = response_content_stream
349
+ else:
350
+ response_content = response_content_batch # type: ignore
351
+
352
+ # Sanitize empty Markdown content
353
+ if isinstance(response_content, Markdown):
354
+ if not (response_content.markup and response_content.markup.strip()):
355
+ response_content = None # type: ignore
356
+
357
+ panels = [status]
358
+
359
+ if input_content and show_message:
360
+ render = True
361
+ # Convert message to a panel
362
+ message_panel = create_panel(
363
+ content=Text(input_content, style="green"),
364
+ title="Message",
365
+ border_style="cyan",
366
+ )
367
+ panels.append(message_panel)
368
+
369
+ additional_panels = build_panels_stream(
370
+ response_content=response_content,
371
+ response_event=resp, # type: ignore
372
+ response_timer=response_timer,
373
+ response_reasoning_content_buffer=_response_reasoning_content,
374
+ reasoning_steps=reasoning_steps,
375
+ show_reasoning=show_reasoning,
376
+ show_full_reasoning=show_full_reasoning,
377
+ accumulated_tool_calls=accumulated_tool_calls,
378
+ compression_manager=agent.compression_manager,
379
+ )
380
+ panels.extend(additional_panels)
381
+ if panels:
382
+ live_log.update(Group(*panels))
383
+
384
+ if agent.memory_manager is not None and agent.memory_manager.memories_updated:
385
+ memory_panel = create_panel(
386
+ content=Text("Memories updated"),
387
+ title="Memories",
388
+ border_style="green",
389
+ )
390
+ panels.append(memory_panel)
391
+ live_log.update(Group(*panels))
392
+ agent.memory_manager.memories_updated = False
393
+
394
+ if agent.session_summary_manager is not None and agent.session_summary_manager.summaries_updated:
395
+ summary_panel = create_panel(
396
+ content=Text("Session summary updated"),
397
+ title="Session Summary",
398
+ border_style="green",
399
+ )
400
+ panels.append(summary_panel)
401
+ live_log.update(Group(*panels))
402
+ agent.session_summary_manager.summaries_updated = False
403
+
404
+ # Clear compression stats after final display
405
+ if agent.compression_manager is not None:
406
+ agent.compression_manager.stats.clear()
407
+
408
+ response_timer.stop()
409
+
410
+ # Final update to remove the "Thinking..." status
411
+ panels = [p for p in panels if not isinstance(p, Status)]
412
+ live_log.update(Group(*panels))
413
+
414
+
415
+ def build_panels_stream(
416
+ response_content: Union[str, JSON, Markdown],
417
+ response_event: RunOutputEvent,
418
+ response_timer: Timer,
419
+ response_reasoning_content_buffer: str,
420
+ reasoning_steps: List[ReasoningStep],
421
+ show_reasoning: bool = True,
422
+ show_full_reasoning: bool = False,
423
+ accumulated_tool_calls: Optional[List] = None,
424
+ compression_manager: Optional[Any] = None,
425
+ ):
426
+ panels = []
427
+
428
+ if len(reasoning_steps) > 0 and show_reasoning:
429
+ # Create panels for reasoning steps
430
+ for i, step in enumerate(reasoning_steps, 1):
431
+ # Build step content
432
+ step_content = Text.assemble()
433
+ if step.title is not None:
434
+ step_content.append(f"{step.title}\n", "bold")
435
+ if step.action is not None:
436
+ step_content.append(Text.from_markup(f"[bold]Action:[/bold] {step.action}\n", style="dim"))
437
+ if step.result is not None:
438
+ step_content.append(Text.from_markup(step.result, style="dim"))
439
+
440
+ if show_full_reasoning:
441
+ # Add detailed reasoning information if available
442
+ if step.reasoning is not None:
443
+ step_content.append(Text.from_markup(f"\n[bold]Reasoning:[/bold] {step.reasoning}", style="dim"))
444
+ if step.confidence is not None:
445
+ step_content.append(Text.from_markup(f"\n[bold]Confidence:[/bold] {step.confidence}", style="dim"))
446
+ reasoning_panel = create_panel(content=step_content, title=f"Reasoning step {i}", border_style="green")
447
+ panels.append(reasoning_panel)
448
+
449
+ if len(response_reasoning_content_buffer) > 0 and show_reasoning:
450
+ # Create panel for thinking
451
+ thinking_panel = create_panel(
452
+ content=Text(response_reasoning_content_buffer),
453
+ title=f"Thinking ({response_timer.elapsed:.1f}s)",
454
+ border_style="green",
455
+ )
456
+ panels.append(thinking_panel)
457
+
458
+ if accumulated_tool_calls: # Use accumulated tool calls instead of just current event
459
+ # Create bullet points for each tool call
460
+ tool_calls_content = Text()
461
+ formatted_tool_calls = format_tool_calls(accumulated_tool_calls)
462
+ for formatted_tool_call in formatted_tool_calls:
463
+ tool_calls_content.append(f"• {formatted_tool_call}\n")
464
+
465
+ tool_calls_text = tool_calls_content.plain.rstrip()
466
+
467
+ # Add compression stats if available (don't clear - caller will clear after final display)
468
+ if compression_manager is not None and compression_manager.stats:
469
+ stats = compression_manager.stats
470
+ saved = stats.get("original_size", 0) - stats.get("compressed_size", 0)
471
+ orig = stats.get("original_size", 1)
472
+ if stats.get("tool_results_compressed", 0) > 0:
473
+ tool_calls_text += f"\n\ncompressed: {stats.get('tool_results_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
474
+
475
+ tool_calls_panel = create_panel(
476
+ content=tool_calls_text,
477
+ title="Tool Calls",
478
+ border_style="yellow",
479
+ )
480
+ panels.append(tool_calls_panel)
481
+
482
+ response_panel = None
483
+ if response_content:
484
+ response_panel = create_panel(
485
+ content=response_content,
486
+ title=f"Response ({response_timer.elapsed:.1f}s)",
487
+ border_style="blue",
488
+ )
489
+ panels.append(response_panel)
490
+
491
+ if (
492
+ isinstance(response_event, tuple(get_args(RunOutputEvent)))
493
+ and hasattr(response_event, "citations")
494
+ and response_event.citations is not None
495
+ and response_event.citations.urls is not None
496
+ ):
497
+ md_lines = []
498
+
499
+ # Add search queries if present
500
+ if response_event.citations.search_queries:
501
+ md_lines.append("**Search Queries:**")
502
+ for query in response_event.citations.search_queries:
503
+ md_lines.append(f"- {query}")
504
+ md_lines.append("") # Empty line before URLs
505
+
506
+ # Add URL citations
507
+ md_lines.extend(
508
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
509
+ for i, citation in enumerate(response_event.citations.urls)
510
+ if citation.url # Only include citations with valid URLs
511
+ )
512
+
513
+ md_content = "\n".join(md_lines)
514
+ if md_content: # Only create panel if there are citations
515
+ citations_panel = create_panel(
516
+ content=Markdown(md_content),
517
+ title="Citations",
518
+ border_style="green",
519
+ )
520
+ panels.append(citations_panel)
521
+
522
+ return panels
523
+
524
+
525
+ def print_response(
526
+ agent: "Agent",
527
+ input: Union[List, Dict, str, Message, BaseModel, List[Message]],
528
+ session_id: Optional[str] = None,
529
+ session_state: Optional[Dict[str, Any]] = None,
530
+ user_id: Optional[str] = None,
531
+ run_id: Optional[str] = None,
532
+ audio: Optional[Sequence[Audio]] = None,
533
+ images: Optional[Sequence[Image]] = None,
534
+ videos: Optional[Sequence[Video]] = None,
535
+ files: Optional[Sequence[File]] = None,
536
+ knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
537
+ stream_events: Optional[bool] = None,
538
+ stream_intermediate_steps: Optional[bool] = None,
539
+ debug_mode: Optional[bool] = None,
540
+ markdown: bool = False,
541
+ show_message: bool = True,
542
+ show_reasoning: bool = True,
543
+ show_full_reasoning: bool = False,
544
+ tags_to_include_in_markdown: Set[str] = {"think", "thinking"},
545
+ console: Optional[Any] = None,
546
+ add_history_to_context: Optional[bool] = None,
547
+ dependencies: Optional[Dict[str, Any]] = None,
548
+ add_dependencies_to_context: Optional[bool] = None,
549
+ add_session_state_to_context: Optional[bool] = None,
550
+ metadata: Optional[Dict[str, Any]] = None,
551
+ **kwargs: Any,
552
+ ):
553
+ if stream_events is not None:
554
+ warnings.warn(
555
+ "The 'stream_events' parameter is deprecated and will be removed in future versions. Event streaming is always enabled using the print_response function.",
556
+ DeprecationWarning,
557
+ stacklevel=2,
558
+ )
559
+ if stream_intermediate_steps is not None:
560
+ warnings.warn(
561
+ "The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Event streaming is always enabled using the print_response function.",
562
+ DeprecationWarning,
563
+ stacklevel=2,
564
+ )
565
+
566
+ with Live(console=console) as live_log:
567
+ status = Status("Thinking...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
568
+ live_log.update(status)
569
+ response_timer = Timer()
570
+ response_timer.start()
571
+ # Panels to be rendered
572
+ panels = [status]
573
+ # First render the message panel if the message is not None
574
+ if input and show_message:
575
+ # Convert message to a panel
576
+ message_content = get_text_from_message(input)
577
+ message_panel = create_panel(
578
+ content=Text(message_content, style="green"),
579
+ title="Message",
580
+ border_style="cyan",
581
+ )
582
+ panels.append(message_panel) # type: ignore
583
+ live_log.update(Group(*panels))
584
+
585
+ # Run the agent
586
+ run_response = agent.run(
587
+ input=input,
588
+ session_id=session_id,
589
+ session_state=session_state,
590
+ user_id=user_id,
591
+ run_id=run_id,
592
+ audio=audio,
593
+ images=images,
594
+ videos=videos,
595
+ files=files,
596
+ stream=False,
597
+ stream_events=True,
598
+ knowledge_filters=knowledge_filters,
599
+ debug_mode=debug_mode,
600
+ add_history_to_context=add_history_to_context,
601
+ add_dependencies_to_context=add_dependencies_to_context,
602
+ add_session_state_to_context=add_session_state_to_context,
603
+ dependencies=dependencies,
604
+ metadata=metadata,
605
+ **kwargs,
606
+ )
607
+ response_timer.stop()
608
+
609
+ if run_response.input is not None and run_response.input.input_content != input:
610
+ # Input was modified during the run
611
+ panels = [status]
612
+ if show_message:
613
+ # Convert message to a panel
614
+ message_content = get_text_from_message(run_response.input.input_content)
615
+ message_panel = create_panel(
616
+ content=Text(message_content, style="green"),
617
+ title="Message",
618
+ border_style="cyan",
619
+ )
620
+ panels.append(message_panel) # type: ignore
621
+ live_log.update(Group(*panels))
622
+
623
+ additional_panels = build_panels(
624
+ run_response=run_response,
625
+ output_schema=agent.output_schema, # type: ignore
626
+ response_timer=response_timer,
627
+ show_reasoning=show_reasoning,
628
+ show_full_reasoning=show_full_reasoning,
629
+ tags_to_include_in_markdown=tags_to_include_in_markdown,
630
+ markdown=markdown,
631
+ compression_manager=agent.compression_manager,
632
+ )
633
+ panels.extend(additional_panels)
634
+
635
+ if agent.memory_manager is not None and agent.memory_manager.memories_updated:
636
+ memory_panel = create_panel(
637
+ content=Text("Memories updated"),
638
+ title="Memories",
639
+ border_style="green",
640
+ )
641
+ panels.append(memory_panel)
642
+ live_log.update(Group(*panels))
643
+ agent.memory_manager.memories_updated = False
644
+
645
+ if agent.session_summary_manager is not None and agent.session_summary_manager.summaries_updated:
646
+ summary_panel = create_panel(
647
+ content=Text("Session summary updated"),
648
+ title="Session Summary",
649
+ border_style="green",
650
+ )
651
+ panels.append(summary_panel)
652
+ live_log.update(Group(*panels))
653
+ agent.session_summary_manager.summaries_updated = False
654
+
655
+ # Final update to remove the "Thinking..." status
656
+ panels = [p for p in panels if not isinstance(p, Status)]
657
+ live_log.update(Group(*panels))
658
+
659
+
660
+ async def aprint_response(
661
+ agent: "Agent",
662
+ input: Union[List, Dict, str, Message, BaseModel, List[Message]],
663
+ session_id: Optional[str] = None,
664
+ session_state: Optional[Dict[str, Any]] = None,
665
+ user_id: Optional[str] = None,
666
+ run_id: Optional[str] = None,
667
+ audio: Optional[Sequence[Audio]] = None,
668
+ images: Optional[Sequence[Image]] = None,
669
+ videos: Optional[Sequence[Video]] = None,
670
+ files: Optional[Sequence[File]] = None,
671
+ knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
672
+ debug_mode: Optional[bool] = None,
673
+ markdown: bool = False,
674
+ show_message: bool = True,
675
+ show_reasoning: bool = True,
676
+ show_full_reasoning: bool = False,
677
+ stream_events: Optional[bool] = None,
678
+ stream_intermediate_steps: Optional[bool] = None,
679
+ tags_to_include_in_markdown: Set[str] = {"think", "thinking"},
680
+ console: Optional[Any] = None,
681
+ add_history_to_context: Optional[bool] = None,
682
+ dependencies: Optional[Dict[str, Any]] = None,
683
+ add_dependencies_to_context: Optional[bool] = None,
684
+ add_session_state_to_context: Optional[bool] = None,
685
+ metadata: Optional[Dict[str, Any]] = None,
686
+ **kwargs: Any,
687
+ ):
688
+ if stream_events is not None:
689
+ warnings.warn(
690
+ "The 'stream_events' parameter is deprecated and will be removed in future versions. Event streaming is always enabled using the aprint_response function.",
691
+ DeprecationWarning,
692
+ stacklevel=2,
693
+ )
694
+ if stream_intermediate_steps is not None:
695
+ warnings.warn(
696
+ "The 'stream_intermediate_steps' parameter is deprecated and will be removed in future versions. Event streaming is always enabled using the aprint_response function.",
697
+ DeprecationWarning,
698
+ stacklevel=2,
699
+ )
700
+
701
+ with Live(console=console) as live_log:
702
+ status = Status("Thinking...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
703
+ live_log.update(status)
704
+ response_timer = Timer()
705
+ response_timer.start()
706
+ # Panels to be rendered
707
+ panels = [status]
708
+ # First render the message panel if the message is not None
709
+ if input and show_message:
710
+ # Convert message to a panel
711
+ message_content = get_text_from_message(input)
712
+ message_panel = create_panel(
713
+ content=Text(message_content, style="green"),
714
+ title="Message",
715
+ border_style="cyan",
716
+ )
717
+ panels.append(message_panel)
718
+ live_log.update(Group(*panels))
719
+
720
+ # Run the agent
721
+ run_response = await agent.arun(
722
+ input=input,
723
+ session_id=session_id,
724
+ session_state=session_state,
725
+ user_id=user_id,
726
+ run_id=run_id,
727
+ audio=audio,
728
+ images=images,
729
+ videos=videos,
730
+ files=files,
731
+ stream=False,
732
+ stream_events=True,
733
+ knowledge_filters=knowledge_filters,
734
+ debug_mode=debug_mode,
735
+ add_history_to_context=add_history_to_context,
736
+ add_dependencies_to_context=add_dependencies_to_context,
737
+ add_session_state_to_context=add_session_state_to_context,
738
+ dependencies=dependencies,
739
+ metadata=metadata,
740
+ **kwargs,
741
+ )
742
+ response_timer.stop()
743
+
744
+ if run_response.input is not None and run_response.input.input_content != input:
745
+ # Input was modified during the run
746
+ panels = [status]
747
+ if show_message:
748
+ # Convert message to a panel
749
+ message_content = get_text_from_message(run_response.input.input_content)
750
+ message_panel = create_panel(
751
+ content=Text(message_content, style="green"),
752
+ title="Message",
753
+ border_style="cyan",
754
+ )
755
+ panels.append(message_panel) # type: ignore
756
+ live_log.update(Group(*panels))
757
+
758
+ additional_panels = build_panels(
759
+ run_response=run_response,
760
+ output_schema=agent.output_schema, # type: ignore
761
+ response_timer=response_timer,
762
+ show_reasoning=show_reasoning,
763
+ show_full_reasoning=show_full_reasoning,
764
+ tags_to_include_in_markdown=tags_to_include_in_markdown,
765
+ markdown=markdown,
766
+ compression_manager=agent.compression_manager,
767
+ )
768
+ panels.extend(additional_panels)
769
+
770
+ if agent.memory_manager is not None and agent.memory_manager.memories_updated:
771
+ memory_panel = create_panel(
772
+ content=Text("Memories updated"),
773
+ title="Memories",
774
+ border_style="green",
775
+ )
776
+ panels.append(memory_panel)
777
+ live_log.update(Group(*panels))
778
+ agent.memory_manager.memories_updated = False
779
+
780
+ if agent.session_summary_manager is not None and agent.session_summary_manager.summaries_updated is not None:
781
+ summary_panel = create_panel(
782
+ content=Text("Session summary updated"),
783
+ title="Session Summary",
784
+ border_style="green",
785
+ )
786
+ agent.session_summary_manager.summaries_updated = False
787
+ panels.append(summary_panel)
788
+ live_log.update(Group(*panels))
789
+
790
+ # Final update to remove the "Thinking..." status
791
+ panels = [p for p in panels if not isinstance(p, Status)]
792
+ live_log.update(Group(*panels))
793
+
794
+
795
+ def build_panels(
796
+ run_response: RunOutput,
797
+ response_timer: Timer,
798
+ output_schema: Optional[BaseModel] = None,
799
+ show_reasoning: bool = True,
800
+ show_full_reasoning: bool = False,
801
+ tags_to_include_in_markdown: Optional[Set[str]] = None,
802
+ markdown: bool = False,
803
+ compression_manager: Optional[Any] = None,
804
+ ):
805
+ panels = []
806
+
807
+ reasoning_steps = []
808
+
809
+ if isinstance(run_response, RunOutput) and run_response.is_paused:
810
+ response_panel = create_paused_run_output_panel(run_response)
811
+ panels.append(response_panel)
812
+ return panels
813
+
814
+ if isinstance(run_response, RunOutput) and run_response.reasoning_steps is not None:
815
+ reasoning_steps = run_response.reasoning_steps
816
+
817
+ if len(reasoning_steps) > 0 and show_reasoning:
818
+ # Create panels for reasoning steps
819
+ for i, step in enumerate(reasoning_steps, 1):
820
+ # Build step content
821
+ step_content = Text.assemble()
822
+ if step.title is not None:
823
+ step_content.append(f"{step.title}\n", "bold")
824
+ if step.action is not None:
825
+ step_content.append(Text.from_markup(f"[bold]Action:[/bold] {step.action}\n", style="dim"))
826
+ if step.result is not None:
827
+ step_content.append(Text.from_markup(step.result, style="dim"))
828
+
829
+ if show_full_reasoning:
830
+ # Add detailed reasoning information if available
831
+ if step.reasoning is not None:
832
+ step_content.append(Text.from_markup(f"\n[bold]Reasoning:[/bold] {step.reasoning}", style="dim"))
833
+ if step.confidence is not None:
834
+ step_content.append(Text.from_markup(f"\n[bold]Confidence:[/bold] {step.confidence}", style="dim"))
835
+ reasoning_panel = create_panel(content=step_content, title=f"Reasoning step {i}", border_style="green")
836
+ panels.append(reasoning_panel)
837
+
838
+ if isinstance(run_response, RunOutput) and run_response.reasoning_content is not None and show_reasoning:
839
+ # Create panel for thinking
840
+ thinking_panel = create_panel(
841
+ content=Text(run_response.reasoning_content),
842
+ title=f"Thinking ({response_timer.elapsed:.1f}s)",
843
+ border_style="green",
844
+ )
845
+ panels.append(thinking_panel)
846
+
847
+ # Add tool calls panel if available
848
+ if isinstance(run_response, RunOutput) and run_response.tools:
849
+ # Create bullet points for each tool call
850
+ tool_calls_content = Text()
851
+ formatted_tool_calls = format_tool_calls(run_response.tools)
852
+ for formatted_tool_call in formatted_tool_calls:
853
+ tool_calls_content.append(f"• {formatted_tool_call}\n")
854
+
855
+ tool_calls_text = tool_calls_content.plain.rstrip()
856
+
857
+ # Add compression stats if available
858
+ if compression_manager is not None and compression_manager.stats:
859
+ stats = compression_manager.stats
860
+ saved = stats.get("original_size", 0) - stats.get("compressed_size", 0)
861
+ orig = stats.get("original_size", 1)
862
+ if stats.get("tool_results_compressed", 0) > 0:
863
+ tool_calls_text += f"\n\ncompressed: {stats.get('tool_results_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
864
+ compression_manager.stats.clear()
865
+
866
+ tool_calls_panel = create_panel(
867
+ content=tool_calls_text,
868
+ title="Tool Calls",
869
+ border_style="yellow",
870
+ )
871
+ panels.append(tool_calls_panel)
872
+
873
+ response_content_batch: Union[str, JSON, Markdown] = "" # type: ignore
874
+ if isinstance(run_response, RunOutput):
875
+ if isinstance(run_response.content, str):
876
+ if markdown:
877
+ escaped_content = escape_markdown_tags(run_response.content, tags_to_include_in_markdown) # type: ignore
878
+ response_content_batch = Markdown(escaped_content)
879
+ else:
880
+ response_content_batch = run_response.get_content_as_string(indent=4)
881
+ elif output_schema is not None and isinstance(run_response.content, BaseModel):
882
+ try:
883
+ response_content_batch = JSON(run_response.content.model_dump_json(exclude_none=True), indent=2)
884
+ except Exception as e:
885
+ log_warning(f"Failed to convert response to JSON: {e}")
886
+ else:
887
+ try:
888
+ response_content_batch = JSON(json.dumps(run_response.content), indent=4)
889
+ except Exception as e:
890
+ log_warning(f"Failed to convert response to JSON: {e}")
891
+
892
+ # Create panel for response
893
+ response_panel = create_panel(
894
+ content=response_content_batch,
895
+ title=f"Response ({response_timer.elapsed:.1f}s)",
896
+ border_style="blue",
897
+ )
898
+ panels.append(response_panel)
899
+
900
+ if (
901
+ isinstance(run_response, RunOutput)
902
+ and run_response.citations is not None
903
+ and run_response.citations.urls is not None
904
+ ):
905
+ md_lines = []
906
+
907
+ # Add search queries if present
908
+ if run_response.citations.search_queries:
909
+ md_lines.append("**Search Queries:**")
910
+ for query in run_response.citations.search_queries:
911
+ md_lines.append(f"- {query}")
912
+ md_lines.append("") # Empty line before URLs
913
+
914
+ # Add URL citations
915
+ md_lines.extend(
916
+ f"{i + 1}. [{citation.title or citation.url}]({citation.url})"
917
+ for i, citation in enumerate(run_response.citations.urls)
918
+ if citation.url # Only include citations with valid URLs
919
+ )
920
+
921
+ md_content = "\n".join(md_lines)
922
+ if md_content: # Only create panel if there are citations
923
+ citations_panel = create_panel(
924
+ content=Markdown(md_content),
925
+ title="Citations",
926
+ border_style="green",
927
+ )
928
+ panels.append(citations_panel)
929
+
930
+ return panels