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
agno/tools/e2b.py ADDED
@@ -0,0 +1,703 @@
1
+ import base64
2
+ import json
3
+ import tempfile
4
+ import time
5
+ from os import fdopen, getenv
6
+ from pathlib import Path
7
+ from typing import Any, Callable, Dict, List, Optional, Union
8
+ from uuid import uuid4
9
+
10
+ from agno.agent import Agent
11
+ from agno.media import Image
12
+ from agno.team.team import Team
13
+ from agno.tools import Toolkit
14
+ from agno.tools.function import ToolResult
15
+ from agno.utils.code_execution import prepare_python_code
16
+ from agno.utils.log import logger
17
+
18
+ try:
19
+ from e2b_code_interpreter import Sandbox
20
+ except ImportError:
21
+ raise ImportError("`e2b_code_interpreter` not installed. Please install using `pip install e2b_code_interpreter`")
22
+
23
+
24
+ class E2BTools(Toolkit):
25
+ def __init__(
26
+ self,
27
+ api_key: Optional[str] = None,
28
+ timeout: int = 300, # 5 minutes default timeout
29
+ sandbox_options: Optional[Dict[str, Any]] = None,
30
+ **kwargs,
31
+ ):
32
+ """Initialize E2B toolkit for code interpretation and running Python code in a sandbox.
33
+
34
+ Args:
35
+ api_key: E2B API key (defaults to E2B_API_KEY environment variable)
36
+ timeout: Timeout in seconds for the sandbox (default: 5 minutes)
37
+ sandbox_options: Additional options to pass to the Sandbox constructor
38
+ """
39
+
40
+ self.api_key = api_key or getenv("E2B_API_KEY")
41
+ if not self.api_key:
42
+ raise ValueError("E2B_API_KEY not set. Please set the E2B_API_KEY environment variable.")
43
+
44
+ # Create the sandbox once and reuse it
45
+ self.sandbox_options = sandbox_options or {}
46
+
47
+ # According to official docs, the parameter is 'timeout' (in seconds), not 'timeout_ms'
48
+ try:
49
+ self.sandbox = Sandbox.create(api_key=self.api_key, timeout=timeout, **self.sandbox_options)
50
+ except Exception as e:
51
+ logger.error(f"Warning: Could not create sandbox: {e}")
52
+ raise e
53
+
54
+ # Last execution result for reference
55
+ self.last_execution = None
56
+ self.downloaded_files: Dict[int, str] = {}
57
+
58
+ tools: List[Any] = [
59
+ # Code execution
60
+ self.run_python_code,
61
+ # File operations
62
+ self.upload_file,
63
+ self.download_png_result,
64
+ self.download_chart_data,
65
+ self.download_file_from_sandbox,
66
+ # Filesystem operations
67
+ self.list_files,
68
+ self.read_file_content,
69
+ self.write_file_content,
70
+ self.watch_directory,
71
+ # Internet access
72
+ self.get_public_url,
73
+ self.run_server,
74
+ # Sandbox management
75
+ self.set_sandbox_timeout,
76
+ self.get_sandbox_status,
77
+ self.shutdown_sandbox,
78
+ self.list_running_sandboxes,
79
+ # Command execution
80
+ self.run_command,
81
+ self.stream_command,
82
+ self.run_background_command,
83
+ self.kill_background_command,
84
+ ]
85
+
86
+ super().__init__(name="e2b_tools", tools=tools, **kwargs)
87
+
88
+ # Code Execution Functions
89
+ def run_python_code(self, code: str) -> str:
90
+ """
91
+ Run Python code in an isolated E2B sandbox environment.
92
+
93
+ Args:
94
+ code (str): Python code to execute
95
+
96
+ Returns:
97
+ str: Execution results or error message
98
+ """
99
+ try:
100
+ executable_code = prepare_python_code(code)
101
+
102
+ execution = self.sandbox.run_code(executable_code)
103
+ self.last_execution = execution
104
+
105
+ # Check for errors
106
+ if execution.error:
107
+ return f"Error: {execution.error.name}\n{execution.error.value}\n{execution.error.traceback}"
108
+
109
+ # Process results
110
+ results = []
111
+
112
+ # Add logs if available
113
+ if hasattr(execution, "logs") and execution.logs:
114
+ results.append(f"Logs:\n{execution.logs}")
115
+
116
+ # Process individual results
117
+ for i, result in enumerate(execution.results):
118
+ if hasattr(result, "text") and result.text:
119
+ results.append(f"Result {i + 1}: {result.text}")
120
+ elif hasattr(result, "png") and result.png:
121
+ results.append(f"Result {i + 1}: Generated PNG image (use download_png_result to save)")
122
+ elif hasattr(result, "chart") and result.chart:
123
+ chart_type = result.chart.get("type", "unknown")
124
+ results.append(
125
+ f"Result {i + 1}: Generated interactive {chart_type} chart (use download_chart_data to save)"
126
+ )
127
+ else:
128
+ results.append(f"Result {i + 1}: Output available")
129
+
130
+ return json.dumps(results) if results else "Code executed successfully with no output."
131
+
132
+ except Exception as e:
133
+ return json.dumps({"status": "error", "message": f"Error executing code: {str(e)}"})
134
+
135
+ # File Upload/Download Functions
136
+ def upload_file(self, file_path: str, sandbox_path: Optional[str] = None) -> str:
137
+ """
138
+ Upload a file to the E2B sandbox.
139
+
140
+ Args:
141
+ file_path (str): Path to the file on the local system
142
+ sandbox_path (str, optional): Destination path in the sandbox. Defaults to the same filename.
143
+
144
+ Returns:
145
+ str: Path to the file in the sandbox or error message
146
+ """
147
+ try:
148
+ # Determine the sandbox path if not provided
149
+ if not sandbox_path:
150
+ sandbox_path = Path(file_path).name
151
+
152
+ # Upload the file
153
+ with open(file_path, "rb") as f:
154
+ file_in_sandbox = self.sandbox.files.write(sandbox_path, f)
155
+
156
+ return file_in_sandbox.path
157
+ except Exception as e:
158
+ return json.dumps({"status": "error", "message": f"Error uploading file: {str(e)}"})
159
+
160
+ def download_png_result(
161
+ self, agent: Union[Agent, Team], result_index: int = 0, output_path: Optional[str] = None
162
+ ) -> ToolResult:
163
+ """
164
+ Add a PNG image result from the last code execution as an Image object.
165
+
166
+ Args:
167
+ agent: The agent to add the image artifact to
168
+ result_index (int): Index of the result to use (default: 0, the first result)
169
+ output_path (str, optional): Optional path to also save the PNG file. If not provided, image is only added as artifact.
170
+
171
+ Returns:
172
+ ToolResult: Contains the PNG image or error message.
173
+ """
174
+ if not self.last_execution:
175
+ return ToolResult(content="No code has been executed yet")
176
+
177
+ try:
178
+ # Check if the result exists
179
+ if result_index >= len(self.last_execution.results):
180
+ return ToolResult(
181
+ content=f"Result index {result_index} is out of range. Only {len(self.last_execution.results)} results available."
182
+ )
183
+
184
+ result = self.last_execution.results[result_index]
185
+
186
+ # Check if the result has a PNG
187
+ if not result.png:
188
+ return ToolResult(content=f"Result at index {result_index} is not a PNG image")
189
+
190
+ # Decode PNG data from base64
191
+ png_data = base64.b64decode(result.png)
192
+
193
+ # Optionally save to file if output_path is provided
194
+ if output_path:
195
+ with open(output_path, "wb") as f:
196
+ f.write(png_data)
197
+ self.downloaded_files[result_index] = output_path
198
+
199
+ # Create a temporary file to store the image for URL access
200
+ # Create a temp file with .png extension
201
+ fd, temp_path = tempfile.mkstemp(suffix=".png")
202
+ with fdopen(fd, "wb") as tmp:
203
+ tmp.write(png_data)
204
+
205
+ # Generate a file:// URL for the temp file
206
+ file_url = f"file://{temp_path}"
207
+
208
+ # Create Image object
209
+ image_id = str(uuid4())
210
+ image_artifact = Image(
211
+ id=image_id, url=file_url, original_prompt=f"Generated from code execution result {result_index}"
212
+ )
213
+
214
+ if output_path:
215
+ content_msg = f"Image added as artifact with ID {image_id} and saved to {output_path}"
216
+ else:
217
+ content_msg = f"Image added as artifact with ID {image_id}"
218
+
219
+ return ToolResult(content=content_msg, images=[image_artifact])
220
+
221
+ except Exception as e:
222
+ return ToolResult(content=f"Error processing PNG: {str(e)}")
223
+
224
+ def download_chart_data(
225
+ self, agent: Agent, result_index: int = 0, output_path: Optional[str] = None, add_as_artifact: bool = True
226
+ ) -> ToolResult:
227
+ """
228
+ Extract chart data from an interactive chart in the execution results.
229
+ Optionally add the chart as an image artifact.
230
+
231
+ Args:
232
+ agent: The agent to add the chart artifact to
233
+ result_index (int): Index of the result to extract data from (default: 0)
234
+ output_path (str, optional): Path to save the JSON data. Defaults to 'chart-data-{result_index}.json'
235
+ add_as_artifact (bool): Whether to add the chart as an image artifact (default: True)
236
+
237
+ Returns:
238
+ ToolResult: Contains chart information and optionally the chart image.
239
+ """
240
+ if not self.last_execution:
241
+ return ToolResult(content="No code has been executed yet")
242
+
243
+ try:
244
+ # Check if the result exists
245
+ if result_index >= len(self.last_execution.results):
246
+ return ToolResult(
247
+ content=f"Result index {result_index} is out of range. Only {len(self.last_execution.results)} results available."
248
+ )
249
+
250
+ result = self.last_execution.results[result_index]
251
+
252
+ # Check if the result has chart data
253
+ if not result.chart:
254
+ return ToolResult(content=f"Result at index {result_index} does not contain interactive chart data")
255
+
256
+ # Format chart data
257
+ chart_data = result.chart
258
+ chart_type = chart_data.get("type", "unknown")
259
+
260
+ # Determine output path
261
+ if not output_path:
262
+ output_path = f"chart-data-{result_index}.json"
263
+
264
+ # Save chart data as JSON
265
+ with open(output_path, "w") as f:
266
+ json.dump(chart_data, f, indent=2)
267
+
268
+ # Create a summary
269
+ summary = f"Interactive {chart_type} chart data saved to {output_path}\n"
270
+ if "title" in chart_data:
271
+ summary += f"Title: {chart_data['title']}\n"
272
+ if "x_label" in chart_data:
273
+ summary += f"X-axis: {chart_data['x_label']}\n"
274
+ if "y_label" in chart_data:
275
+ summary += f"Y-axis: {chart_data['y_label']}\n"
276
+
277
+ image_artifact = None
278
+ # Add as an image artifact if requested
279
+ if add_as_artifact and result.png:
280
+ # Decode PNG data from base64
281
+ png_data = base64.b64decode(result.png)
282
+
283
+ # Create a temporary file to store the image for URL access
284
+ import os
285
+ import tempfile
286
+
287
+ # Create a temp file with .png extension
288
+ fd, temp_path = tempfile.mkstemp(suffix=".png")
289
+ with os.fdopen(fd, "wb") as tmp:
290
+ tmp.write(png_data)
291
+
292
+ # Generate a file:// URL for the temp file
293
+ file_url = f"file://{temp_path}"
294
+
295
+ # Create Image object
296
+ image_id = str(uuid4())
297
+ image_artifact = Image(
298
+ id=image_id, url=file_url, original_prompt=f"Interactive {chart_type} chart from code execution"
299
+ )
300
+
301
+ summary += f"\nChart image added as artifact with ID {image_id}"
302
+
303
+ if image_artifact:
304
+ return ToolResult(content=summary, images=[image_artifact])
305
+ else:
306
+ return ToolResult(content=summary)
307
+
308
+ except Exception as e:
309
+ return ToolResult(content=f"Error extracting chart data: {str(e)}")
310
+
311
+ def download_file_from_sandbox(self, sandbox_path: str, local_path: Optional[str] = None) -> str:
312
+ """
313
+ Download a file from the E2B sandbox to the local system.
314
+
315
+ Args:
316
+ sandbox_path (str): Path to the file in the sandbox
317
+ local_path (str, optional): Destination path on the local system. Defaults to the same filename.
318
+
319
+ Returns:
320
+ str: Path to the downloaded file or error message
321
+ """
322
+ try:
323
+ # Determine local path if not provided
324
+ if not local_path:
325
+ local_path = Path(sandbox_path).name
326
+
327
+ # Download the file
328
+ content = self.sandbox.files.read(sandbox_path)
329
+
330
+ with open(local_path, "wb") as f:
331
+ f.write(content)
332
+
333
+ return local_path
334
+ except Exception as e:
335
+ return json.dumps({"status": "error", "message": f"Error downloading file: {str(e)}"})
336
+
337
+ # Command Execution Functions
338
+ def run_command(
339
+ self,
340
+ command: str,
341
+ on_stdout: Optional[Callable] = None,
342
+ on_stderr: Optional[Callable] = None,
343
+ background: bool = False,
344
+ ) -> str:
345
+ """
346
+ Run a shell command in the sandbox environment.
347
+
348
+ Args:
349
+ command (str): Shell command to execute
350
+ on_stdout (callable, optional): Callback function for streaming stdout
351
+ on_stderr (callable, optional): Callback function for streaming stderr
352
+ background (bool): Whether to run the command in background
353
+
354
+ Returns:
355
+ str: Command results or error message, or the command object for background execution
356
+ """
357
+ try:
358
+ # Prepare streaming callbacks
359
+ kwargs = {}
360
+ if on_stdout:
361
+ kwargs["on_stdout"] = on_stdout
362
+ if on_stderr:
363
+ kwargs["on_stderr"] = on_stderr
364
+
365
+ # Set background execution if requested
366
+ process_kwargs = {"background": background} # Using a separate dict for process arguments
367
+
368
+ # Execute the command
369
+ result = self.sandbox.commands.run(command, **kwargs, **process_kwargs)
370
+
371
+ # For background execution, return the command object
372
+ if background:
373
+ return "Command started in background. Use the returned command object to interact with it."
374
+
375
+ # For synchronous execution, return the output
376
+ output = []
377
+ if hasattr(result, "stdout") and result.stdout:
378
+ output.append(f"STDOUT:\n{result.stdout}")
379
+ if hasattr(result, "stderr") and result.stderr:
380
+ output.append(f"STDERR:\n{result.stderr}")
381
+
382
+ return json.dumps(output) if output else "Command executed successfully with no output."
383
+
384
+ except Exception as e:
385
+ return json.dumps({"status": "error", "message": f"Error executing command: {str(e)}"})
386
+
387
+ def stream_command(self, command: str) -> str:
388
+ """
389
+ Run a shell command and stream its output.
390
+
391
+ Args:
392
+ command (str): Shell command to execute
393
+
394
+ Returns:
395
+ str: Summary of command execution
396
+ """
397
+ outputs = []
398
+
399
+ def stdout_callback(data):
400
+ outputs.append(f"STDOUT: {data}")
401
+ logger.info(f"STDOUT: {data}")
402
+
403
+ def stderr_callback(data):
404
+ outputs.append(f"STDERR: {data}")
405
+ logger.error(f"STDERR: {data}")
406
+
407
+ try:
408
+ self.run_command(command, on_stdout=stdout_callback, on_stderr=stderr_callback)
409
+ return json.dumps(outputs) if outputs else "Command completed with no output."
410
+ except Exception as e:
411
+ return json.dumps({"status": "error", "message": f"Error streaming command: {str(e)}"})
412
+
413
+ def run_background_command(self, command: str) -> Any:
414
+ """
415
+ Run a shell command in the background.
416
+
417
+ Args:
418
+ command (str): Shell command to execute in background
419
+
420
+ Returns:
421
+ object: Command object that can be used to interact with the background process
422
+ """
423
+ try:
424
+ # Execute the command in background
425
+ command_obj = self.sandbox.commands.run(command, background=True)
426
+ return command_obj
427
+ except Exception as e:
428
+ return json.dumps({"status": "error", "message": f"Error starting background command: {str(e)}"})
429
+
430
+ def kill_background_command(self, command_obj: Any) -> str:
431
+ """
432
+ Kill a background command.
433
+
434
+ Args:
435
+ command_obj: Command object returned from run_background_command
436
+
437
+ Returns:
438
+ str: Result of the kill operation
439
+ """
440
+ try:
441
+ if isinstance(command_obj, str):
442
+ return "Invalid command object. Please provide the object returned from run_background_command."
443
+
444
+ command_obj.kill()
445
+ return "Background command terminated successfully."
446
+ except Exception as e:
447
+ return json.dumps({"status": "error", "message": f"Error killing background command: {str(e)}"})
448
+
449
+ # Filesystem Operations
450
+ def list_files(self, directory_path: str = "/") -> str:
451
+ """
452
+ List files and directories in the specified path in the sandbox.
453
+
454
+ Args:
455
+ directory_path (str): Path to the directory to list (default: root directory)
456
+
457
+ Returns:
458
+ str: List of files and directories or error message
459
+ """
460
+ try:
461
+ files = self.sandbox.files.list(directory_path)
462
+ if not files:
463
+ return f"No files found in {directory_path}"
464
+
465
+ result = f"Contents of {directory_path}:\n"
466
+ for file in files:
467
+ file_type = "Directory" if file.type == "directory" else "File"
468
+ size = f"{file.size} bytes" if file.size is not None else "Unknown size"
469
+ result += f"- {file.name} ({file_type}, {size})\n"
470
+
471
+ return result
472
+ except Exception as e:
473
+ return json.dumps({"status": "error", "message": f"Error listing files: {str(e)}"})
474
+
475
+ def read_file_content(self, file_path: str, encoding: str = "utf-8") -> str:
476
+ """
477
+ Read the content of a file from the sandbox.
478
+
479
+ Args:
480
+ file_path (str): Path to the file in the sandbox
481
+ encoding (str): Encoding to use for text files (default: utf-8)
482
+
483
+ Returns:
484
+ str: File content or error message
485
+ """
486
+ try:
487
+ content = self.sandbox.files.read(file_path)
488
+
489
+ # Check if content is already a string or if it's bytes that need decoding
490
+ if isinstance(content, str):
491
+ return content
492
+ elif isinstance(content, bytes):
493
+ # Try to decode as text if encoding is provided
494
+ try:
495
+ text_content = content.decode(encoding)
496
+ return text_content
497
+ except UnicodeDecodeError:
498
+ return f"File read successfully but contains binary data ({len(content)} bytes). Use download_file_from_sandbox to save it."
499
+ else:
500
+ # Handle unexpected content type
501
+ return f"Unexpected content type: {type(content)}. Expected str or bytes."
502
+
503
+ except Exception as e:
504
+ return json.dumps({"status": "error", "message": f"Error reading file: {str(e)}"})
505
+
506
+ def write_file_content(self, file_path: str, content: str) -> str:
507
+ """
508
+ Write text content to a file in the sandbox.
509
+
510
+ Args:
511
+ file_path (str): Path to the file in the sandbox
512
+ content (str): Text content to write
513
+
514
+ Returns:
515
+ str: Success message or error message
516
+ """
517
+ try:
518
+ # Convert string to bytes
519
+ bytes_content = content.encode("utf-8")
520
+
521
+ # Write the file
522
+ file_info = self.sandbox.files.write(file_path, bytes_content)
523
+
524
+ return file_info.path
525
+ except Exception as e:
526
+ return json.dumps({"status": "error", "message": f"Error writing file: {str(e)}"})
527
+
528
+ def watch_directory(self, directory_path: str, duration_seconds: int = 5) -> str:
529
+ """
530
+ Watch a directory for changes for a specified duration.
531
+
532
+ Args:
533
+ directory_path (str): Path to the directory to watch
534
+ duration_seconds (int): How long to watch for changes in seconds (default: 5 seconds)
535
+
536
+ Returns:
537
+ str: List of changes detected or error message
538
+ """
539
+ try:
540
+ changes = []
541
+
542
+ # Setup watcher
543
+ watcher = self.sandbox.files.watch_dir(directory_path)
544
+
545
+ # Watch for changes
546
+ start_time = time.time()
547
+ while time.time() - start_time < duration_seconds:
548
+ change = watcher.get_change(timeout=0.5)
549
+ if change:
550
+ changes.append(f"{change.event} - {change.path}")
551
+
552
+ # Close watcher
553
+ watcher.close()
554
+
555
+ if changes:
556
+ return json.dumps(
557
+ {
558
+ "status": "success",
559
+ "message": f"Changes detected in {directory_path} over {duration_seconds} seconds:\n"
560
+ + "\n".join(changes),
561
+ }
562
+ )
563
+ else:
564
+ return json.dumps(
565
+ {
566
+ "status": "success",
567
+ "message": f"No changes detected in {directory_path} over {duration_seconds} seconds",
568
+ }
569
+ )
570
+
571
+ except Exception as e:
572
+ return json.dumps({"status": "error", "message": f"Error watching directory: {str(e)}"})
573
+
574
+ # Internet Access Functions
575
+ def get_public_url(self, port: int) -> str:
576
+ """
577
+ Get a public URL for a service running in the sandbox on the specified port.
578
+
579
+ Args:
580
+ port (int): Port number the service is running on in the sandbox
581
+
582
+ Returns:
583
+ str: Public URL or error message
584
+ """
585
+ try:
586
+ host = self.sandbox.get_host(port)
587
+
588
+ return f"http://{host}"
589
+ except Exception as e:
590
+ return json.dumps({"status": "error", "message": f"Error getting public URL: {str(e)}"})
591
+
592
+ def run_server(self, command: str, port: int) -> str:
593
+ """
594
+ Start a server in the sandbox and return its public URL.
595
+
596
+ Args:
597
+ command (str): Command to start the server
598
+ port (int): Port the server will listen on
599
+
600
+ Returns:
601
+ str: Server information including public URL or error message
602
+ """
603
+ try:
604
+ # Start the server in the background
605
+ self.sandbox.commands.run(command, background=True)
606
+
607
+ # # Wait a moment for the server to start
608
+ time.sleep(2)
609
+
610
+ # Get the public URL
611
+ host = self.sandbox.get_host(port)
612
+ url = f"http://{host}"
613
+
614
+ return url
615
+ except Exception as e:
616
+ return json.dumps({"status": "error", "message": f"Error starting server: {str(e)}"})
617
+
618
+ # Sandbox Management Functions
619
+ def set_sandbox_timeout(self, timeout: int) -> str:
620
+ """
621
+ Update the timeout for the sandbox.
622
+
623
+ Args:
624
+ timeout: New timeout in seconds
625
+
626
+ Returns:
627
+ str: Success message or error message
628
+ """
629
+ try:
630
+ # According to the documentation, it might be set_timeout in Python SDK
631
+ if hasattr(self.sandbox, "set_timeout"):
632
+ self.sandbox.set_timeout(timeout)
633
+ # Fallback for direct property access if method doesn't exist
634
+ else:
635
+ self.sandbox.timeout = timeout
636
+
637
+ return str(timeout) # Convert int to str before returning
638
+ except Exception as e:
639
+ return json.dumps({"status": "error", "message": f"Error updating sandbox timeout: {str(e)}"})
640
+
641
+ def get_sandbox_status(self) -> str:
642
+ """
643
+ Get the current status of the sandbox.
644
+
645
+ Returns:
646
+ str: Sandbox status information
647
+ """
648
+ try:
649
+ # Collect sandbox information
650
+ sandbox_id = getattr(self.sandbox, "id", "Unknown")
651
+
652
+ return sandbox_id
653
+
654
+ except Exception as e:
655
+ return json.dumps({"status": "error", "message": f"Error getting sandbox status: {str(e)}"})
656
+
657
+ def shutdown_sandbox(self) -> str:
658
+ """
659
+ Shutdown the sandbox immediately.
660
+
661
+ Returns:
662
+ str: Success message or error message
663
+ """
664
+ try:
665
+ cont = self.sandbox.kill()
666
+ return json.dumps({"status": "success", "message": "Sandbox shut down successfully", "content": cont})
667
+ except Exception as e:
668
+ return json.dumps({"status": "error", "message": f"Error shutting down sandbox: {str(e)}"})
669
+
670
+ def list_running_sandboxes(self) -> str:
671
+ """
672
+ List all running sandboxes.
673
+
674
+ Returns:
675
+ str: JSON string containing information about running sandboxes or error message
676
+ """
677
+ try:
678
+ running_sandboxes = self.sandbox.list()
679
+
680
+ if not running_sandboxes:
681
+ return json.dumps({"status": "success", "message": "No running sandboxes found", "sandboxes": []})
682
+
683
+ sandboxes_info = []
684
+ for sandbox in running_sandboxes:
685
+ info = {
686
+ "sandbox_id": getattr(sandbox, "sandbox_id", "Unknown"),
687
+ "started_at": str(getattr(sandbox, "started_at", "Unknown")),
688
+ "template_id": getattr(sandbox, "template_id", "Unknown"),
689
+ "metadata": getattr(sandbox, "metadata", {}),
690
+ }
691
+ sandboxes_info.append(info)
692
+
693
+ return json.dumps(
694
+ {
695
+ "status": "success",
696
+ "message": f"Found {len(sandboxes_info)} running sandboxes",
697
+ "sandboxes": sandboxes_info,
698
+ },
699
+ indent=2,
700
+ )
701
+
702
+ except Exception as e:
703
+ return json.dumps({"status": "error", "message": f"Error listing running sandboxes: {str(e)}"})