diff --git a/examples/tempo-payments-python/.env.template b/examples/tempo-payments-python/.env.template new file mode 100644 index 00000000..8af99037 --- /dev/null +++ b/examples/tempo-payments-python/.env.template @@ -0,0 +1,6 @@ +E2B_API_KEY=your_e2b_api_key +# Your Tempo private key (from ~/.tempo/wallet/keys.toml, the "key" field) +# If not set, the example will copy your local keys.toml into the sandbox instead +TEMPO_PRIVATE_KEY=your_tempo_private_key +# Optional: set this after first build to skip rebuilding +# E2B_TEMPO_TEMPLATE_ID= diff --git a/examples/tempo-payments-python/README.md b/examples/tempo-payments-python/README.md new file mode 100644 index 00000000..bf9bc124 --- /dev/null +++ b/examples/tempo-payments-python/README.md @@ -0,0 +1,40 @@ +# E2B + Tempo: Autonomous Agent Payments + +This example shows how to run an AI agent inside an [E2B sandbox](https://e2b.dev) that can autonomously pay for API services using [Tempo's Machine Payments Protocol (MPP)](https://tempo.xyz). + +The agent makes a paid web search request — Tempo handles the stablecoin payment automatically via HTTP 402 challenge-response. + +## How it works + +1. A custom sandbox template is built with Tempo CLI and pympp pre-installed +2. Your Tempo wallet keys are injected at runtime (never baked into the image) +3. The agent calls a paid API → Tempo handles the 402 payment → agent gets the response + +## Setup & run + +### 1. Install dependencies +``` +poetry install +``` + +### 2. Set up Tempo wallet +```bash +curl -fsSL https://tempo.xyz/install | bash +tempo wallet login +tempo wallet fund +``` + +### 3. Set up `.env` +1. Copy `.env.template` to `.env` +2. Add your [E2B API key](https://e2b.dev/docs/getting-started/api-key) + +### 4. Run the example +``` +poetry run start +``` + +On first run, the template will be built automatically (~1-2 min). Subsequent runs use the cached template. + +## Available services + +100+ MPP-compatible services at [mpp.dev/services](https://mpp.dev/services) including web search, blockchain data, image generation, browser automation, and more. diff --git a/examples/tempo-payments-python/e2b_tempo/main.py b/examples/tempo-payments-python/e2b_tempo/main.py new file mode 100644 index 00000000..84383a02 --- /dev/null +++ b/examples/tempo-payments-python/e2b_tempo/main.py @@ -0,0 +1,73 @@ +import os +from pathlib import Path +from dotenv import load_dotenv +from e2b import Sandbox, Template + +load_dotenv() + +KEYS_TOML = Path.home() / ".tempo" / "wallet" / "keys.toml" + + +def build_template(): + """Build a custom sandbox template with Tempo pre-installed.""" + template = ( + Template() + .from_python_image("3.12") + .apt_install(["curl", "ca-certificates"]) + .run_cmd("curl -fsSL https://tempo.xyz/install | bash") + .run_cmd("/home/user/.tempo/bin/tempo add request") + .pip_install(["pympp"]) + ) + + info = Template.build( + template, + "e2b-tempo", + on_build_logs=lambda log: print(log.message, end=""), + ) + + print(f"\nTemplate built: {info.template_id}") + return info.template_id + + +def main(): + template_id = os.environ.get("E2B_TEMPO_TEMPLATE_ID") + if not template_id: + print("No E2B_TEMPO_TEMPLATE_ID found, building template...") + template_id = build_template() + + tempo_private_key = os.environ.get("TEMPO_PRIVATE_KEY") + + sandbox = Sandbox.create(template=template_id) + print(f"Sandbox started: {sandbox.sandbox_id}") + + try: + if tempo_private_key: + # Use private key directly via --private-key flag + key_flag = f"--private-key {tempo_private_key}" + elif KEYS_TOML.exists(): + # Fallback: copy local keys.toml into the sandbox + keys_content = KEYS_TOML.read_text() + sandbox.files.write("/home/user/.tempo/wallet/keys.toml", keys_content) + key_flag = "" + else: + raise RuntimeError( + "Set TEMPO_PRIVATE_KEY in .env or run 'tempo wallet login' first" + ) + + # Make a paid API call from inside the sandbox + result = sandbox.commands.run( + 'export PATH="$HOME/.tempo/bin:$PATH" && ' + f"tempo request {key_flag} " + '-X POST --json \'{"query":"latest AI news"}\' ' + "https://parallelmpp.dev/api/search" + ) + print("Search results:", result.stdout) + except Exception as e: + print(f"Error: {e}") + finally: + sandbox.kill() + print("Sandbox destroyed.") + + +if __name__ == "__main__": + main() diff --git a/examples/tempo-payments-python/pyproject.toml b/examples/tempo-payments-python/pyproject.toml new file mode 100644 index 00000000..5cd049f3 --- /dev/null +++ b/examples/tempo-payments-python/pyproject.toml @@ -0,0 +1,19 @@ +[tool.poetry] +name = "e2b-tempo" +version = "0.1.0" +description = "E2B sandbox with autonomous Tempo payments via MPP" +authors = ["Max Hager"] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.11" +e2b = "^2.20.0" +pympp = "^0.6.0" +python-dotenv = "^1.0.1" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry.scripts] +start = "e2b_tempo.main:main"