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.
- agno/__init__.py +8 -0
- agno/agent/__init__.py +44 -5
- agno/agent/agent.py +10531 -2975
- agno/api/agent.py +14 -53
- agno/api/api.py +7 -46
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +6 -25
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +6 -9
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/team.py +10 -10
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +22 -26
- agno/api/workflow.py +28 -0
- agno/cloud/aws/base.py +214 -0
- agno/cloud/aws/s3/__init__.py +2 -0
- agno/cloud/aws/s3/api_client.py +43 -0
- agno/cloud/aws/s3/bucket.py +195 -0
- agno/cloud/aws/s3/object.py +57 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/__init__.py +24 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +946 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2781 -0
- agno/db/dynamo/schemas.py +442 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +2379 -0
- agno/db/firestore/schemas.py +181 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1791 -0
- agno/db/gcs_json/utils.py +228 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +1312 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1777 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2760 -0
- agno/db/mongo/mongo.py +2597 -0
- agno/db/mongo/schemas.py +119 -0
- agno/db/mongo/utils.py +276 -0
- agno/db/mysql/__init__.py +4 -0
- agno/db/mysql/async_mysql.py +2912 -0
- agno/db/mysql/mysql.py +2923 -0
- agno/db/mysql/schemas.py +186 -0
- agno/db/mysql/utils.py +488 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +2579 -0
- agno/db/postgres/postgres.py +2870 -0
- agno/db/postgres/schemas.py +187 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +2141 -0
- agno/db/redis/schemas.py +159 -0
- agno/db/redis/utils.py +346 -0
- agno/db/schemas/__init__.py +4 -0
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +34 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +61 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +179 -0
- agno/db/singlestore/singlestore.py +2877 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2911 -0
- agno/db/sqlite/schemas.py +181 -0
- agno/db/sqlite/sqlite.py +2908 -0
- agno/db/sqlite/utils.py +429 -0
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +334 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1908 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +118 -0
- agno/eval/__init__.py +24 -0
- agno/eval/accuracy.py +666 -276
- agno/eval/agent_as_judge.py +861 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +779 -0
- agno/eval/reliability.py +241 -62
- agno/eval/utils.py +120 -0
- agno/exceptions.py +143 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -1
- agno/{document → knowledge}/chunking/agentic.py +22 -14
- agno/{document → knowledge}/chunking/document.py +2 -2
- agno/{document → knowledge}/chunking/fixed.py +7 -6
- agno/knowledge/chunking/markdown.py +151 -0
- agno/{document → knowledge}/chunking/recursive.py +15 -3
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +91 -0
- agno/knowledge/chunking/strategy.py +165 -0
- agno/knowledge/content.py +74 -0
- agno/knowledge/document/__init__.py +5 -0
- agno/{document → knowledge/document}/base.py +12 -2
- agno/knowledge/embedder/__init__.py +5 -0
- agno/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/{embedder → knowledge/embedder}/base.py +8 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
- agno/knowledge/embedder/google.py +258 -0
- agno/knowledge/embedder/huggingface.py +94 -0
- agno/knowledge/embedder/jina.py +182 -0
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +206 -0
- agno/knowledge/embedder/nebius.py +13 -0
- agno/knowledge/embedder/ollama.py +154 -0
- agno/knowledge/embedder/openai.py +195 -0
- agno/knowledge/embedder/sentence_transformer.py +63 -0
- agno/{embedder → knowledge/embedder}/together.py +1 -1
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +3006 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/knowledge/reader/arxiv_reader.py +81 -0
- agno/knowledge/reader/base.py +95 -0
- agno/knowledge/reader/csv_reader.py +164 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +88 -0
- agno/knowledge/reader/markdown_reader.py +137 -0
- agno/knowledge/reader/pdf_reader.py +431 -0
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +313 -0
- agno/knowledge/reader/s3_reader.py +89 -0
- agno/knowledge/reader/tavily_reader.py +193 -0
- agno/knowledge/reader/text_reader.py +127 -0
- agno/knowledge/reader/web_search_reader.py +325 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +91 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/{reranker → knowledge/reranker}/base.py +1 -1
- agno/{reranker → knowledge/reranker}/cohere.py +2 -2
- agno/knowledge/reranker/infinity.py +195 -0
- agno/knowledge/reranker/sentence_transformer.py +54 -0
- agno/knowledge/types.py +39 -0
- agno/knowledge/utils.py +234 -0
- agno/media.py +439 -95
- agno/memory/__init__.py +16 -3
- agno/memory/manager.py +1474 -123
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +62 -0
- agno/models/anthropic/__init__.py +4 -0
- agno/models/anthropic/claude.py +960 -496
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +686 -451
- agno/models/aws/claude.py +190 -183
- agno/models/azure/__init__.py +18 -1
- agno/models/azure/ai_foundry.py +489 -0
- agno/models/azure/openai_chat.py +89 -40
- agno/models/base.py +2477 -550
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +565 -0
- agno/models/cerebras/cerebras_openai.py +131 -0
- agno/models/cohere/__init__.py +4 -0
- agno/models/cohere/chat.py +306 -492
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +74 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +90 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +45 -0
- agno/models/deepseek/__init__.py +4 -0
- agno/models/deepseek/deepseek.py +110 -9
- agno/models/fireworks/__init__.py +4 -0
- agno/models/fireworks/fireworks.py +19 -22
- agno/models/google/__init__.py +3 -7
- agno/models/google/gemini.py +1717 -662
- agno/models/google/utils.py +22 -0
- agno/models/groq/__init__.py +4 -0
- agno/models/groq/groq.py +391 -666
- agno/models/huggingface/__init__.py +4 -0
- agno/models/huggingface/huggingface.py +266 -538
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +432 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +20 -3
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +60 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +503 -0
- agno/models/litellm/litellm_openai.py +42 -0
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/lmstudio/__init__.py +5 -0
- agno/models/lmstudio/lmstudio.py +25 -0
- agno/models/message.py +361 -39
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +502 -0
- agno/models/meta/llama_openai.py +79 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +4 -0
- agno/models/mistral/mistral.py +293 -393
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +53 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +4 -0
- agno/models/nvidia/nvidia.py +22 -3
- agno/models/ollama/__init__.py +4 -2
- agno/models/ollama/chat.py +257 -492
- agno/models/openai/__init__.py +7 -0
- agno/models/openai/chat.py +725 -770
- agno/models/openai/like.py +16 -2
- agno/models/openai/responses.py +1121 -0
- agno/models/openrouter/__init__.py +4 -0
- agno/models/openrouter/openrouter.py +62 -5
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +203 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +82 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +69 -0
- agno/models/response.py +177 -7
- agno/models/sambanova/__init__.py +4 -0
- agno/models/sambanova/sambanova.py +23 -4
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +42 -0
- agno/models/together/__init__.py +4 -0
- agno/models/together/together.py +21 -164
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +43 -0
- agno/models/vertexai/__init__.py +0 -1
- agno/models/vertexai/claude.py +190 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +83 -0
- agno/models/xai/__init__.py +2 -0
- agno/models/xai/xai.py +111 -7
- agno/os/__init__.py +3 -0
- agno/os/app.py +1027 -0
- agno/os/auth.py +244 -0
- agno/os/config.py +126 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +249 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +47 -0
- agno/os/interfaces/agui/router.py +147 -0
- agno/os/interfaces/agui/utils.py +574 -0
- agno/os/interfaces/base.py +25 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/os/interfaces/slack/router.py +148 -0
- agno/os/interfaces/slack/security.py +30 -0
- agno/os/interfaces/slack/slack.py +47 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/os/interfaces/whatsapp/router.py +210 -0
- agno/os/interfaces/whatsapp/security.py +55 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +293 -0
- agno/os/middleware/__init__.py +9 -0
- agno/os/middleware/jwt.py +797 -0
- agno/os/router.py +258 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +599 -0
- agno/os/routers/agents/schema.py +261 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +450 -0
- agno/os/routers/evals/schemas.py +174 -0
- agno/os/routers/evals/utils.py +231 -0
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +1008 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +661 -0
- agno/os/routers/memory/schemas.py +88 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +190 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +997 -0
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +512 -0
- agno/os/routers/teams/schema.py +257 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +624 -0
- agno/os/routers/workflows/schema.py +75 -0
- agno/os/schema.py +534 -0
- agno/os/scopes.py +469 -0
- agno/{playground → os}/settings.py +7 -15
- agno/os/utils.py +973 -0
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +67 -0
- agno/reasoning/deepseek.py +63 -0
- agno/reasoning/default.py +97 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +71 -0
- agno/reasoning/helpers.py +24 -1
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +2 -1
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +822 -0
- agno/run/base.py +247 -0
- agno/run/cancel.py +81 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +767 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +260 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +342 -0
- agno/session/workflow.py +501 -0
- agno/table.py +10 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +9536 -0
- agno/tools/__init__.py +7 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +22 -12
- agno/tools/api.py +122 -0
- agno/tools/apify.py +276 -83
- agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
- agno/tools/aws_lambda.py +28 -7
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +11 -4
- agno/tools/bitbucket.py +292 -0
- agno/tools/brandfetch.py +213 -0
- agno/tools/bravesearch.py +106 -0
- agno/tools/brightdata.py +367 -0
- agno/tools/browserbase.py +209 -0
- agno/tools/calcom.py +32 -23
- agno/tools/calculator.py +24 -37
- agno/tools/cartesia.py +187 -0
- agno/tools/{clickup_tool.py → clickup.py} +17 -28
- agno/tools/confluence.py +91 -26
- agno/tools/crawl4ai.py +139 -43
- agno/tools/csv_toolkit.py +28 -22
- agno/tools/dalle.py +36 -22
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +169 -14
- agno/tools/desi_vocal.py +23 -11
- agno/tools/discord.py +32 -29
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +76 -81
- agno/tools/duckduckgo.py +43 -40
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +65 -54
- agno/tools/email.py +13 -5
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +324 -42
- agno/tools/fal.py +39 -35
- agno/tools/file.py +196 -30
- agno/tools/file_generation.py +356 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +108 -33
- agno/tools/function.py +960 -122
- agno/tools/giphy.py +34 -12
- agno/tools/github.py +1294 -97
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +271 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +607 -107
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +20 -12
- agno/tools/jina.py +24 -14
- agno/tools/jira.py +48 -19
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +82 -43
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +15 -7
- agno/tools/lumalab.py +41 -26
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +193 -0
- agno/tools/memory.py +419 -0
- agno/tools/mlx_transcribe.py +11 -9
- agno/tools/models/azure_openai.py +190 -0
- agno/tools/models/gemini.py +203 -0
- agno/tools/models/groq.py +158 -0
- agno/tools/models/morph.py +186 -0
- agno/tools/models/nebius.py +124 -0
- agno/tools/models_labs.py +163 -82
- agno/tools/moviepy_video.py +18 -13
- agno/tools/nano_banana.py +151 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +15 -4
- agno/tools/newspaper4k.py +19 -6
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +181 -17
- agno/tools/openbb.py +27 -20
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +25 -15
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +238 -185
- agno/tools/pubmed.py +125 -13
- agno/tools/python.py +48 -35
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +207 -29
- agno/tools/redshift.py +406 -0
- agno/tools/replicate.py +69 -26
- agno/tools/resend.py +11 -6
- agno/tools/scrapegraph.py +179 -19
- agno/tools/searxng.py +23 -31
- agno/tools/serpapi.py +15 -10
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +23 -12
- agno/tools/shopify.py +1519 -0
- agno/tools/slack.py +56 -14
- agno/tools/sleep.py +8 -6
- agno/tools/spider.py +35 -11
- agno/tools/spotify.py +919 -0
- agno/tools/sql.py +34 -19
- agno/tools/tavily.py +158 -8
- agno/tools/telegram.py +18 -8
- agno/tools/todoist.py +218 -0
- agno/tools/toolkit.py +134 -9
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +25 -28
- agno/tools/twilio.py +18 -9
- agno/tools/user_control_flow.py +78 -0
- agno/tools/valyu.py +228 -0
- agno/tools/visualization.py +467 -0
- agno/tools/webbrowser.py +28 -0
- agno/tools/webex.py +76 -0
- agno/tools/website.py +23 -19
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +28 -19
- agno/tools/workflow.py +285 -0
- agno/tools/{twitter.py → x.py} +142 -46
- agno/tools/yfinance.py +41 -39
- agno/tools/youtube.py +34 -17
- agno/tools/zendesk.py +15 -5
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +86 -37
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +938 -0
- agno/utils/audio.py +37 -1
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +103 -20
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +700 -0
- agno/utils/functions.py +107 -37
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +171 -0
- agno/utils/http.py +185 -0
- agno/utils/json_schema.py +159 -37
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +221 -8
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +335 -14
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +77 -2
- agno/utils/models/ai_foundry.py +50 -0
- agno/utils/models/claude.py +373 -0
- agno/utils/models/cohere.py +94 -0
- agno/utils/models/llama.py +85 -0
- agno/utils/models/mistral.py +100 -0
- agno/utils/models/openai_responses.py +140 -0
- agno/utils/models/schema_utils.py +153 -0
- agno/utils/models/watsonx.py +41 -0
- agno/utils/openai.py +257 -0
- agno/utils/pickle.py +1 -1
- agno/utils/pprint.py +124 -8
- agno/utils/print_response/agent.py +930 -0
- agno/utils/print_response/team.py +1914 -0
- agno/utils/print_response/workflow.py +1668 -0
- agno/utils/prompts.py +111 -0
- agno/utils/reasoning.py +108 -0
- agno/utils/response.py +163 -0
- agno/utils/serialize.py +32 -0
- agno/utils/shell.py +4 -4
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +204 -51
- agno/utils/team.py +139 -0
- agno/utils/timer.py +9 -2
- agno/utils/tokens.py +657 -0
- agno/utils/tools.py +19 -1
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +3 -3
- agno/vectordb/__init__.py +2 -0
- agno/vectordb/base.py +87 -9
- agno/vectordb/cassandra/__init__.py +5 -1
- agno/vectordb/cassandra/cassandra.py +383 -27
- agno/vectordb/chroma/__init__.py +4 -0
- agno/vectordb/chroma/chromadb.py +748 -83
- agno/vectordb/clickhouse/__init__.py +7 -1
- agno/vectordb/clickhouse/clickhousedb.py +554 -53
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1446 -0
- agno/vectordb/lancedb/__init__.py +5 -0
- agno/vectordb/lancedb/lance_db.py +730 -98
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +163 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +388 -0
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +166 -0
- agno/vectordb/milvus/__init__.py +3 -0
- agno/vectordb/milvus/milvus.py +966 -78
- agno/vectordb/mongodb/__init__.py +9 -1
- agno/vectordb/mongodb/mongodb.py +1175 -172
- agno/vectordb/pgvector/__init__.py +8 -0
- agno/vectordb/pgvector/pgvector.py +599 -115
- agno/vectordb/pineconedb/__init__.py +5 -1
- agno/vectordb/pineconedb/pineconedb.py +406 -43
- agno/vectordb/qdrant/__init__.py +4 -0
- agno/vectordb/qdrant/qdrant.py +914 -61
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +682 -0
- agno/vectordb/singlestore/__init__.py +8 -1
- agno/vectordb/singlestore/singlestore.py +771 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +663 -0
- agno/vectordb/upstashdb/__init__.py +5 -0
- agno/vectordb/upstashdb/upstashdb.py +718 -0
- agno/vectordb/weaviate/__init__.py +8 -0
- agno/vectordb/weaviate/index.py +15 -0
- agno/vectordb/weaviate/weaviate.py +1009 -0
- agno/workflow/__init__.py +23 -1
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +759 -0
- agno/workflow/loop.py +756 -0
- agno/workflow/parallel.py +853 -0
- agno/workflow/router.py +723 -0
- agno/workflow/step.py +1564 -0
- agno/workflow/steps.py +613 -0
- agno/workflow/types.py +556 -0
- agno/workflow/workflow.py +4327 -514
- agno-2.3.13.dist-info/METADATA +639 -0
- agno-2.3.13.dist-info/RECORD +613 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
- agno-2.3.13.dist-info/licenses/LICENSE +201 -0
- agno/api/playground.py +0 -91
- agno/api/schemas/playground.py +0 -22
- agno/api/schemas/user.py +0 -22
- agno/api/schemas/workspace.py +0 -46
- agno/api/user.py +0 -160
- agno/api/workspace.py +0 -151
- agno/cli/auth_server.py +0 -118
- agno/cli/config.py +0 -275
- agno/cli/console.py +0 -88
- agno/cli/credentials.py +0 -23
- agno/cli/entrypoint.py +0 -571
- agno/cli/operator.py +0 -355
- agno/cli/settings.py +0 -85
- agno/cli/ws/ws_cli.py +0 -817
- agno/constants.py +0 -13
- agno/document/__init__.py +0 -1
- agno/document/chunking/semantic.py +0 -47
- agno/document/chunking/strategy.py +0 -31
- agno/document/reader/__init__.py +0 -1
- agno/document/reader/arxiv_reader.py +0 -41
- agno/document/reader/base.py +0 -22
- agno/document/reader/csv_reader.py +0 -84
- agno/document/reader/docx_reader.py +0 -46
- agno/document/reader/firecrawl_reader.py +0 -99
- agno/document/reader/json_reader.py +0 -43
- agno/document/reader/pdf_reader.py +0 -219
- agno/document/reader/s3/pdf_reader.py +0 -46
- agno/document/reader/s3/text_reader.py +0 -51
- agno/document/reader/text_reader.py +0 -41
- agno/document/reader/website_reader.py +0 -175
- agno/document/reader/youtube_reader.py +0 -50
- agno/embedder/__init__.py +0 -1
- agno/embedder/azure_openai.py +0 -86
- agno/embedder/cohere.py +0 -72
- agno/embedder/fastembed.py +0 -37
- agno/embedder/google.py +0 -73
- agno/embedder/huggingface.py +0 -54
- agno/embedder/mistral.py +0 -80
- agno/embedder/ollama.py +0 -57
- agno/embedder/openai.py +0 -74
- agno/embedder/sentence_transformer.py +0 -38
- agno/embedder/voyageai.py +0 -64
- agno/eval/perf.py +0 -201
- agno/file/__init__.py +0 -1
- agno/file/file.py +0 -16
- agno/file/local/csv.py +0 -32
- agno/file/local/txt.py +0 -19
- agno/infra/app.py +0 -240
- agno/infra/base.py +0 -144
- agno/infra/context.py +0 -20
- agno/infra/db_app.py +0 -52
- agno/infra/resource.py +0 -205
- agno/infra/resources.py +0 -55
- agno/knowledge/agent.py +0 -230
- agno/knowledge/arxiv.py +0 -22
- agno/knowledge/combined.py +0 -22
- agno/knowledge/csv.py +0 -28
- agno/knowledge/csv_url.py +0 -19
- agno/knowledge/document.py +0 -20
- agno/knowledge/docx.py +0 -30
- agno/knowledge/json.py +0 -28
- agno/knowledge/langchain.py +0 -71
- agno/knowledge/llamaindex.py +0 -66
- agno/knowledge/pdf.py +0 -28
- agno/knowledge/pdf_url.py +0 -26
- agno/knowledge/s3/base.py +0 -60
- agno/knowledge/s3/pdf.py +0 -21
- agno/knowledge/s3/text.py +0 -23
- agno/knowledge/text.py +0 -30
- agno/knowledge/website.py +0 -88
- agno/knowledge/wikipedia.py +0 -31
- agno/knowledge/youtube.py +0 -22
- agno/memory/agent.py +0 -392
- agno/memory/classifier.py +0 -104
- agno/memory/db/__init__.py +0 -1
- agno/memory/db/base.py +0 -42
- agno/memory/db/mongodb.py +0 -189
- agno/memory/db/postgres.py +0 -203
- agno/memory/db/sqlite.py +0 -193
- agno/memory/memory.py +0 -15
- agno/memory/row.py +0 -36
- agno/memory/summarizer.py +0 -192
- agno/memory/summary.py +0 -19
- agno/memory/workflow.py +0 -38
- agno/models/google/gemini_openai.py +0 -26
- agno/models/ollama/hermes.py +0 -221
- agno/models/ollama/tools.py +0 -362
- agno/models/vertexai/gemini.py +0 -595
- agno/playground/__init__.py +0 -3
- agno/playground/async_router.py +0 -421
- agno/playground/deploy.py +0 -249
- agno/playground/operator.py +0 -92
- agno/playground/playground.py +0 -91
- agno/playground/schemas.py +0 -76
- agno/playground/serve.py +0 -55
- agno/playground/sync_router.py +0 -405
- agno/reasoning/agent.py +0 -68
- agno/run/response.py +0 -112
- agno/storage/agent/__init__.py +0 -0
- agno/storage/agent/base.py +0 -38
- agno/storage/agent/dynamodb.py +0 -350
- agno/storage/agent/json.py +0 -92
- agno/storage/agent/mongodb.py +0 -228
- agno/storage/agent/postgres.py +0 -367
- agno/storage/agent/session.py +0 -79
- agno/storage/agent/singlestore.py +0 -303
- agno/storage/agent/sqlite.py +0 -357
- agno/storage/agent/yaml.py +0 -93
- agno/storage/workflow/__init__.py +0 -0
- agno/storage/workflow/base.py +0 -40
- agno/storage/workflow/mongodb.py +0 -233
- agno/storage/workflow/postgres.py +0 -366
- agno/storage/workflow/session.py +0 -60
- agno/storage/workflow/sqlite.py +0 -359
- agno/tools/googlesearch.py +0 -88
- agno/utils/defaults.py +0 -57
- agno/utils/filesystem.py +0 -39
- agno/utils/git.py +0 -52
- agno/utils/json_io.py +0 -30
- agno/utils/load_env.py +0 -19
- agno/utils/py_io.py +0 -19
- agno/utils/pyproject.py +0 -18
- agno/utils/resource_filter.py +0 -31
- agno/vectordb/singlestore/s2vectordb.py +0 -390
- agno/vectordb/singlestore/s2vectordb2.py +0 -355
- agno/workspace/__init__.py +0 -0
- agno/workspace/config.py +0 -325
- agno/workspace/enums.py +0 -6
- agno/workspace/helpers.py +0 -48
- agno/workspace/operator.py +0 -758
- agno/workspace/settings.py +0 -63
- agno-0.1.2.dist-info/LICENSE +0 -375
- agno-0.1.2.dist-info/METADATA +0 -502
- agno-0.1.2.dist-info/RECORD +0 -352
- agno-0.1.2.dist-info/entry_points.txt +0 -3
- /agno/{cli → db/migrations}/__init__.py +0 -0
- /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
- /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
- /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
- /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
- /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
- /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
- /agno/{reranker → utils/models}/__init__.py +0 -0
- /agno/{storage → utils/print_response}/__init__.py +0 -0
- {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)}"})
|