diff --git a/README.md b/README.md index 8490935d..94a95b87 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,12 @@ Read more about E2B on the [E2B website](https://e2b.dev) and the official [E2B Python - + + BU Agent SDK + Minimal SDK for building agents + Python + - + diff --git a/examples/bu-agent-sdk-python/.env.template b/examples/bu-agent-sdk-python/.env.template new file mode 100644 index 00000000..810ca243 --- /dev/null +++ b/examples/bu-agent-sdk-python/.env.template @@ -0,0 +1,5 @@ +# Get your E2B API key from https://e2b.dev/dashboard?tab=keys +E2B_API_KEY= + +# Get your Anthropic API key from https://platform.claude.com/settings/keys +ANTHROPIC_API_KEY= diff --git a/examples/bu-agent-sdk-python/.gitignore b/examples/bu-agent-sdk-python/.gitignore new file mode 100644 index 00000000..7a27a481 --- /dev/null +++ b/examples/bu-agent-sdk-python/.gitignore @@ -0,0 +1,5 @@ +# Virtual environments +.venv + +# Environment files +.env \ No newline at end of file diff --git a/examples/bu-agent-sdk-python/README.md b/examples/bu-agent-sdk-python/README.md new file mode 100644 index 00000000..baab70e9 --- /dev/null +++ b/examples/bu-agent-sdk-python/README.md @@ -0,0 +1,29 @@ +# BU Agent SDK with E2B Code Interpreter + +This example shows how to use [bu-agent-sdk](https://github.com/browser-use/agent-sdk) with E2B's [Code Interpreter SDK](https://github.com/e2b-dev/code-interpreter) for data analysis. The agent analyzes CSV data and generates visualizations. + +## Setup & run + +### 1. Install dependencies + +```bash +uv sync +``` + +### 2. Set up `.env` + +1. Copy `.env.template` to `.env` +2. Get [E2B API key](https://e2b.dev/dashboard?tab=keys) +3. Get [Anthropic API key](https://platform.claude.com/settings/keys) + +### 3. Run the example + +```bash +uv run python main.py +``` + +The agent will: +- Spin up an E2B sandbox with pandas, numpy, matplotlib +- Upload `data/employees.csv` +- Analyze the data and generate charts +- Download charts to `output/` diff --git a/examples/bu-agent-sdk-python/data/employees.csv b/examples/bu-agent-sdk-python/data/employees.csv new file mode 100644 index 00000000..dcb2ff30 --- /dev/null +++ b/examples/bu-agent-sdk-python/data/employees.csv @@ -0,0 +1,11 @@ +name,age,city,salary,department +Alice,28,New York,75000,Engineering +Bob,35,San Francisco,95000,Engineering +Charlie,42,Chicago,110000,Management +Diana,31,New York,82000,Marketing +Eve,26,San Francisco,68000,Engineering +Frank,38,Chicago,98000,Management +Grace,29,New York,71000,Marketing +Henry,45,San Francisco,125000,Management +Ivy,33,Chicago,88000,Engineering +Jack,27,New York,65000,Marketing diff --git a/examples/bu-agent-sdk-python/main.py b/examples/bu-agent-sdk-python/main.py new file mode 100644 index 00000000..381b753c --- /dev/null +++ b/examples/bu-agent-sdk-python/main.py @@ -0,0 +1,101 @@ +"""Data analysis agent with E2B sandbox and bu-agent-sdk.""" + +import asyncio +from pathlib import Path +from typing import Annotated + +from dotenv import load_dotenv +from e2b_code_interpreter import Sandbox + +from bu_agent_sdk import Agent +from bu_agent_sdk.agent import FinalResponseEvent, ToolCallEvent, ToolResultEvent +from bu_agent_sdk.llm import ChatAnthropic +from bu_agent_sdk.tools import Depends, tool + +load_dotenv() + +# Config + +INPUT_FILE = Path("data/employees.csv") +OUTPUT_DIR = Path("output") +SYSTEM_PROMPT = "You are a data analyst. Use run_code to execute Python. pandas/numpy/matplotlib are available. Save charts with plt.savefig()." +USER_PROMPT = "Analyze employees.csv: show stats, count by department/city, find highest/lowest paid. Create charts." + +# Sandbox Utils + +_sandbox: Sandbox | None = None + + +def get_sandbox() -> Sandbox: + if _sandbox is None: + raise RuntimeError("Sandbox not initialized") + return _sandbox + + +def download_charts(sandbox: Sandbox): + for f in sandbox.files.list("/home/user"): + if f.name.endswith(".png"): + content = sandbox.files.read(f"/home/user/{f.name}", format="bytes") + (OUTPUT_DIR / f.name).write_bytes(content) + + +# Tools + + +@tool("Run Python code") +async def run_code(code: str, sandbox: Annotated[Sandbox, Depends(get_sandbox)]) -> str: + """Execute Python code in the sandbox and return output.""" + result = sandbox.run_code(code) + + output = "\n".join(filter(None, [ + "\n".join(result.logs.stdout or []), + "\n".join(result.logs.stderr or []), + f"Error: {result.error.name}: {result.error.value}" if result.error else "", + ])) + + return output or "(no output)" + + +# Main Agent Loop + + +async def main(): + global _sandbox + + OUTPUT_DIR.mkdir(exist_ok=True) + _sandbox = Sandbox.create(timeout=300) + print(f"Sandbox: {_sandbox.sandbox_id}\n") + + try: + # Upload input data + _sandbox.files.write(INPUT_FILE.name, INPUT_FILE.read_text()) + + # Create agent + agent = Agent( + llm=ChatAnthropic(model="claude-sonnet-4-5"), + tools=[run_code], + system_prompt=SYSTEM_PROMPT, + dependency_overrides={get_sandbox: lambda: _sandbox}, + ) + + # Run query + print(f"Query: {USER_PROMPT}\n") + + async for event in agent.query_stream(USER_PROMPT): + match event: + case ToolCallEvent(tool=name, args=args): + print(f"[{name}] {str(args)[:100]}...") + case ToolResultEvent(result=result): + print(f" -> {str(result)[:200]}...") + case FinalResponseEvent(content=text): + print(f"\n{text}") + + # Download results + download_charts(_sandbox) + + finally: + _sandbox.kill() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/bu-agent-sdk-python/output/employees_analysis_dashboard.png b/examples/bu-agent-sdk-python/output/employees_analysis_dashboard.png new file mode 100644 index 00000000..61a483e6 Binary files /dev/null and b/examples/bu-agent-sdk-python/output/employees_analysis_dashboard.png differ diff --git a/examples/bu-agent-sdk-python/output/employees_detailed_analysis.png b/examples/bu-agent-sdk-python/output/employees_detailed_analysis.png new file mode 100644 index 00000000..3bd4e852 Binary files /dev/null and b/examples/bu-agent-sdk-python/output/employees_detailed_analysis.png differ diff --git a/examples/bu-agent-sdk-python/pyproject.toml b/examples/bu-agent-sdk-python/pyproject.toml new file mode 100644 index 00000000..b5239032 --- /dev/null +++ b/examples/bu-agent-sdk-python/pyproject.toml @@ -0,0 +1,11 @@ +[project] +name = "bu-agent-sdk-python" +version = "0.1.0" +description = "Data analysis agent using bu-agent-sdk with E2B Code Interpreter" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "bu-agent-sdk", + "e2b-code-interpreter", + "python-dotenv", +]