Overview
Local development with RunAgent provides a fast feedback loop for building and testing your agents before deployment. This guide covers local setup, testing, and debugging.
Getting Started
Basic Local Server
# Start local server
runagent serve .
# With custom port
runagent serve . --port 8080
# With hot reload disabled
runagent serve . --no-reload
Server Output
INFO: Started server process [12345]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Testing Your Agent
Using cURL
# Health check
curl http://localhost:8000/health
# Invoke agent
curl -X POST http://localhost:8000/invoke \
-H "Content-Type: application/json" \
-d '{"query": "Hello, agent!"}'
# Stream response
curl -X POST http://localhost:8000/stream \
-H "Content-Type: application/json" \
-d '{"query": "Tell me a story"}' \
--no-buffer
Using Python
import requests
# Test invocation
response = requests.post(
"http://localhost:8000/invoke",
json={"query": "What's the weather?"}
)
print(response.json())
# Test streaming
response = requests.post(
"http://localhost:8000/stream",
json={"query": "Explain quantum physics"},
stream=True
)
for line in response.iter_lines():
if line:
print(line.decode('utf-8'))
Interactive Testing
# test_client.py
import requests
import json
BASE_URL = "http://localhost:8000"
def test_agent():
while True:
query = input("\nEnter query (or 'quit'): ")
if query.lower() == 'quit':
break
response = requests.post(
f"{BASE_URL}/invoke",
json={"query": query}
)
print("\nResponse:")
print(json.dumps(response.json(), indent=2))
if __name__ == "__main__":
test_agent()
Development Features
Hot Reload
Changes to your agent code automatically restart the server:
# agent.py
def invoke(input_data):
# Make changes here - server auto-reloads
return {"response": "Updated response!"}
Debug Mode
# Enable debug logging
runagent serve . --log-level debug
# Or set environment variable
DEBUG=true runagent serve .
Custom Configuration
# dev_config.py
DEV_CONFIG = {
"host": "0.0.0.0", # Expose to network
"port": 8080,
"reload": True,
"log_level": "debug",
"access_log": True
}
# Use in development
# runagent serve . --config dev_config.py
Local API Endpoints
Endpoint | Method | Description |
---|
/ | GET | Welcome page with API info |
/health | GET | Health check endpoint |
/invoke | POST | Synchronous agent invocation |
/stream | POST | Streaming agent responses |
/docs | GET | Interactive API documentation |
/openapi.json | GET | OpenAPI schema |
Debugging Techniques
Logging
import logging
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def invoke(input_data):
logger.debug(f"Received input: {input_data}")
try:
result = process(input_data)
logger.info(f"Processing successful: {result}")
return result
except Exception as e:
logger.error(f"Error processing: {e}", exc_info=True)
raise
Breakpoint Debugging
def invoke(input_data):
# Using built-in debugger
breakpoint() # or import pdb; pdb.set_trace()
# Your agent logic
result = process(input_data)
return result
import time
import cProfile
import pstats
def profile_agent():
profiler = cProfile.Profile()
# Profile agent execution
profiler.enable()
result = invoke({"query": "test"})
profiler.disable()
# Print stats
stats = pstats.Stats(profiler)
stats.sort_stats('cumulative')
stats.print_stats(10) # Top 10 functions
Makefile
# Makefile for common tasks
.PHONY: run test lint format
run:
runagent serve . --reload
test:
pytest tests/ -v
lint:
flake8 . --max-line-length=100
mypy . --ignore-missing-imports
format:
black .
isort .
watch:
watchmedo auto-restart \
--directory=. \
--pattern="*.py" \
--recursive \
-- runagent serve .
Docker Development
# Dockerfile.dev
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["runagent", "serve", ".", "--host", "0.0.0.0"]
# docker-compose.yml
version: '3.8'
services:
agent:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "8000:8000"
volumes:
- .:/app
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
command: runagent serve . --host 0.0.0.0 --reload
Testing Strategies
Unit Tests
# tests/test_agent.py
import pytest
from agent import invoke
def test_invoke_success():
result = invoke({"query": "test"})
assert "response" in result
def test_invoke_error():
with pytest.raises(ValueError):
invoke({}) # Missing required field
@pytest.mark.parametrize("query,expected", [
("Hello", "greeting"),
("Calculate", "math"),
("Search", "web")
])
def test_query_routing(query, expected):
result = invoke({"query": query})
assert result["type"] == expected
Integration Tests
# tests/test_integration.py
import requests
import subprocess
import time
def test_full_workflow():
# Start server
proc = subprocess.Popen(["runagent", "serve", "."])
time.sleep(2) # Wait for startup
try:
# Test endpoints
response = requests.get("http://localhost:8000/health")
assert response.status_code == 200
response = requests.post(
"http://localhost:8000/invoke",
json={"query": "test"}
)
assert response.status_code == 200
finally:
proc.terminate()
Common Issues
Port Already in Use
# Find process using port
lsof -i :8000
# Kill process
kill -9 <PID>
# Or use different port
runagent serve . --port 8001
Module Import Errors
# Check Python path
python -c "import sys; print(sys.path)"
# Add current directory
export PYTHONPATH="${PYTHONPATH}:."
Environment Variables Not Loading
# Check if .env exists
ls -la .env
# Load manually
set -a
source .env
set +a
runagent serve .
See Also