mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 06:04:43 +00:00
143 lines
4 KiB
Python
143 lines
4 KiB
Python
"""
|
||
Sandbox Agent – Python + Docker example.
|
||
|
||
Starts a Docker container running sandbox-agent, connects to the sandbox-agent server, creates a session, sends a prompt, and
|
||
prints the streamed response.
|
||
|
||
Usage:
|
||
pip install -r requirements.txt
|
||
python main.py
|
||
"""
|
||
|
||
import json
|
||
import os
|
||
import signal
|
||
import subprocess
|
||
import sys
|
||
import time
|
||
|
||
import docker
|
||
import httpx
|
||
|
||
from client import SandboxConnection
|
||
from credentials import build_container_env, detect_agent
|
||
|
||
PORT = 3000
|
||
DOCKERFILE_DIR = os.path.join(os.path.dirname(__file__), "..", "shared")
|
||
IMAGE_NAME = "sandbox-agent-examples:latest"
|
||
|
||
|
||
def build_image(client: docker.DockerClient) -> str:
|
||
"""Build the shared example Docker image if it doesn't exist."""
|
||
try:
|
||
client.images.get(IMAGE_NAME)
|
||
return IMAGE_NAME
|
||
except docker.errors.ImageNotFound:
|
||
pass
|
||
|
||
print(f"Building {IMAGE_NAME} (first run only)...")
|
||
subprocess.run(
|
||
["docker", "build", "-t", IMAGE_NAME, DOCKERFILE_DIR],
|
||
check=True,
|
||
stdout=subprocess.DEVNULL,
|
||
stderr=subprocess.PIPE,
|
||
)
|
||
return IMAGE_NAME
|
||
|
||
|
||
def wait_for_health(base_url: str, timeout_s: float = 120) -> None:
|
||
deadline = time.monotonic() + timeout_s
|
||
last_err: str | None = None
|
||
while time.monotonic() < deadline:
|
||
try:
|
||
r = httpx.get(f"{base_url}/v1/health", timeout=5)
|
||
if r.status_code == 200 and r.json().get("status") == "ok":
|
||
return
|
||
last_err = f"health returned {r.status_code}"
|
||
except Exception as exc:
|
||
last_err = str(exc)
|
||
time.sleep(0.5)
|
||
raise RuntimeError(f"Timed out waiting for /v1/health: {last_err}")
|
||
|
||
|
||
def main() -> None:
|
||
agent = detect_agent()
|
||
print(f"Agent: {agent}")
|
||
|
||
client = docker.from_env()
|
||
image = build_image(client)
|
||
|
||
env = build_container_env()
|
||
|
||
print("Starting container...")
|
||
container = client.containers.run(
|
||
image,
|
||
command=[
|
||
"sh", "-c",
|
||
f"sandbox-agent install-agent {agent} && "
|
||
f"sandbox-agent server --no-token --host 0.0.0.0 --port {PORT}",
|
||
],
|
||
environment=env,
|
||
ports={f"{PORT}/tcp": PORT},
|
||
detach=True,
|
||
auto_remove=True,
|
||
)
|
||
|
||
def cleanup(*_args: object) -> None:
|
||
print("\nCleaning up...")
|
||
try:
|
||
container.stop(timeout=5)
|
||
except Exception:
|
||
pass
|
||
|
||
signal.signal(signal.SIGINT, cleanup)
|
||
signal.signal(signal.SIGTERM, cleanup)
|
||
|
||
try:
|
||
base_url = f"http://127.0.0.1:{PORT}"
|
||
print(f"Waiting for server at {base_url}...")
|
||
wait_for_health(base_url)
|
||
print("Server ready.")
|
||
print(f"Inspector: {base_url}/ui/")
|
||
|
||
# -- Session flow ----------------------------------------------------
|
||
conn = SandboxConnection(base_url, agent)
|
||
|
||
print("Connecting...")
|
||
init_result = conn.initialize()
|
||
agent_info = init_result.get("result", {}).get("agentInfo", {})
|
||
print(f"Connected to: {agent_info.get('title', agent)} {agent_info.get('version', '')}")
|
||
|
||
session_id = conn.new_session()
|
||
print(f"Session: {session_id}")
|
||
|
||
prompt_text = "Say hello and tell me what you are. Be brief (one sentence)."
|
||
print(f"\n> {prompt_text}")
|
||
response = conn.prompt(session_id, prompt_text)
|
||
|
||
if "error" in response:
|
||
err = response["error"]
|
||
print(f"Error: {err.get('message', err)}")
|
||
else:
|
||
print(f"Stop reason: {response.get('result', {}).get('stopReason', 'unknown')}")
|
||
|
||
# Give SSE events a moment to arrive.
|
||
time.sleep(1)
|
||
|
||
if conn.events:
|
||
for ev in conn.events:
|
||
if ev.get("method") == "session/update":
|
||
content = ev.get("params", {}).get("update", {}).get("content", {})
|
||
if content.get("text"):
|
||
print(content["text"], end="")
|
||
print()
|
||
|
||
conn.close()
|
||
print("\nDone.")
|
||
|
||
finally:
|
||
cleanup()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|