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

EndpointMethodDescription
/GETWelcome page with API info
/healthGETHealth check endpoint
/invokePOSTSynchronous agent invocation
/streamPOSTStreaming agent responses
/docsGETInteractive API documentation
/openapi.jsonGETOpenAPI 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

Performance Profiling

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

Development Tools

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