Search Docs…

Search Docs…

Reference

CoAgent API Reference

This document provides comprehensive reference documentation for the CoAgent REST API, including endpoints, request/response schemas, authentication, error handling, and client examples for Python and Rust.

Base URL and Versioning

The CoAgent API uses versioned endpoints with the following base URL structure:

http://localhost:3000/api/v1

For production deployments, replace localhost:3000 with your CoAgent instance URL.

Authentication

Currently, CoAgent operates without authentication for local development. For production deployments, authentication may be implemented at the infrastructure level (API Gateway, reverse proxy, etc.).

Content Type

All API requests must include the Content-Type: application/json header when sending JSON data.

Rate Limiting

CoAgent implements rate limiting to protect against abuse. When rate limits are exceeded, the API returns HTTP 429 (Too Many Requests).

  • Default limit: 100 requests per minute per client

  • Burst limit: 20 concurrent requests

  • Retry behavior: Clients should implement exponential backoff

Error Handling

HTTP Status Codes

Status Code

Description

200

OK - Request succeeded

201

Created - Resource created successfully

400

Bad Request - Invalid request parameters

404

Not Found - Resource not found

409

Conflict - Resource already exists

429

Too Many Requests - Rate limit exceeded

500

Internal Server Error - Server error

502

Bad Gateway - Upstream service error

503

Service Unavailable - Service temporarily unavailable

Error Response Format

All error responses follow this consistent format:

{
  "error": {
    "code": "INVALID_REQUEST",
    "message": "The request parameters are invalid",
    "details": {
      "field": "prompt",
      "reason": "Prompt cannot be empty"
    }
  }
}

Core Endpoints

Health Check

Check the health status of the CoAgent service.

GET /health

Response

{
  "status": "healthy",
  "version": "0.1.0",
  "uptime_seconds": 3600
}

Example

curl -X

Evaluation Endpoints

Create Evaluation

Execute a single AI model evaluation.

POST /api/v1/evals

Request Body

Field

Type

Required

Description

run_id

string

Yes

Unique identifier for this evaluation run

preamble

string

Yes

System message or context for the model

prompt

string

Yes

User prompt to send to the model

model_ref

object

Yes

Model reference configuration

log_meta

object

No

Additional metadata for logging

Model Reference Object

Field

Type

Required

Description

provider_id

string

Yes

ID of the model provider

model_name

string

Yes

Name of the specific model

Request Example

{
  "run_id": "eval_123e4567-e89b-12d3-a456-426614174000",
  "preamble": "You are a helpful customer support assistant.",
  "prompt": "I need help with returning a product I bought last week",
  "model_ref": {
    "provider_id": "openai-prod",
    "model_name": "gpt-4"
  },
  "log_meta": {
    "user_id": "user_456",
    "session_id": "session_789",
    "component": "customer-support"
  }
}

Response

Field

Type

Description

response

string

Generated response from the AI model

token_usage

object

Token usage statistics

run_id

string

Echo of the request run_id

Token Usage Object

Field

Type

Description

prompt_tokens

integer

Tokens used for the prompt

completion_tokens

integer

Tokens used for the completion

total_tokens

integer

Total tokens used

Response Example

{
  "response": "I'd be happy to help you with your return. To process your return efficiently, I'll need a few details: What product are you looking to return, and do you have your order number or receipt?",
  "token_usage": {
    "prompt_tokens": 45,
    "completion_tokens": 38,
    "total_tokens": 83
  },
  "run_id": "eval_123e4567-e89b-12d3-a456-426614174000"
}

Error Responses

Invalid Request (400)
{
  "error": {
    "code": "INVALID_REQUEST",
    "message": "Missing required field: prompt",
    "details": {
      "field": "prompt",
      "reason": "Prompt field is required and cannot be empty"
    }
  }
}
Model Not Found (404)
{
  "error": {
    "code": "MODEL_NOT_FOUND",
    "message": "The specified model was not found",
    "details": {
      "provider_id": "openai-prod",
      "model_name": "gpt-5",
      "available_models": ["gpt-4", "gpt-3.5-turbo"]
    }
  }
}
Rate Limited (429)
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Too many requests, please try again later",
    "details": {
      "retry_after_seconds": 60,
      "limit": "100 requests per minute"
    }
  }
}

Agent Management Endpoints

List Agents

Retrieve all configured agents.

GET /api/v1/agents

Response

{
  "agents": [
    {
      "id": "agent_123",
      "name": "customer-support-agent",
      "description": "Agent for handling customer support queries",
      "preamble": "You are a helpful customer support assistant.",
      "created_at": "2024-01-15T10:30:00Z",
      "updated_at": "2024-01-15T10:30:00Z"
    }
  ]
}

Create Agent

Create a new agent configuration.

POST /api/v1/agents

Request Body

Field

Type

Required

Description

name

string

Yes

Unique name for the agent

description

string

No

Human-readable description

preamble

string

Yes

System message for the agent

Request Example

{
  "name": "technical-support-agent",
  "description": "Agent specialized in technical support queries",
  "preamble": "You are a knowledgeable technical support specialist. Provide clear, step-by-step solutions to technical problems."
}

Response

{
  "id": "agent_456",
  "name": "technical-support-agent",
  "description": "Agent specialized in technical support queries",
  "preamble": "You are a knowledgeable technical support specialist. Provide clear, step-by-step solutions to technical problems.",
  "created_at": "2024-01-15T11:00:00Z",
  "updated_at": "2024-01-15T11:00:00Z"
}

Get Agent

Retrieve a specific agent by ID.

GET /api/v1/agents/{agent_id}

Response

{
  "id": "agent_123",
  "name": "customer-support-agent",
  "description": "Agent for handling customer support queries",
  "preamble": "You are a helpful customer support assistant.",
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z"
}

Update Agent

Update an existing agent configuration.

PUT /api/v1/agents/{agent_id}

Request Body

Same as Create Agent, all fields optional.

Delete Agent

Delete an agent configuration.

DELETE /api/v1/agents/{agent_id}

Response

204 No Content

Model Provider Endpoints

List Providers

Retrieve all configured model providers.

GET /api/v1/providers

Response

{
  "providers": [
    {
      "id": "provider_123",
      "name": "OpenAI Production",
      "provider_type": "openai",
      "available_models": ["gpt-4", "gpt-3.5-turbo"],
      "created_at": "2024-01-15T09:00:00Z",
      "status": "active"
    }
  ]
}

Create Provider

Create a new model provider.

POST /api/v1/providers

Request Body

Field

Type

Required

Description

name

string

Yes

Display name for the provider

provider_type

string

Yes

Type of provider (openai, anthropic, etc.)

api_key

string

Yes

API key for the provider

available_models

array

Yes

List of available model names

Request Example

{
  "name": "Anthropic Claude",
  "provider_type": "anthropic",
  "api_key": "sk-ant-...",
  "available_models": ["claude-3-sonnet", "claude-3-haiku"]
}

Test Management Endpoints

List Test Sets

Retrieve all test sets.

GET /api/v1/testsets

Response

{
  "testsets": [
    {
      "id": "testset_123",
      "name": "Customer Support Evaluation",
      "description": "Test cases for customer support scenarios",
      "case_count": 15,
      "created_at": "2024-01-15T08:00:00Z"
    }
  ]
}

Create Test Set

Create a new test set.

POST /api/v1/testsets

Request Body

Field

Type

Required

Description

name

string

Yes

Name of the test set

description

string

No

Description of the test set

cases

array

Yes

Array of test cases

Run Test Set

Execute a test set against specified configurations.

POST /api/v1/testsets/{testset_id}/run

Request Body

{
  "selected_configs": ["config_123", "config_456"]
}

Response

{
  "run_id": "run_789",
  "status": "running",
  "started_at": "2024-01-15T12:00:00Z"
}

Get Test Run Results

Retrieve results from a test run.

GET /api/v1/testruns/{run_id}

Response

{
  "run_id": "run_789",
  "testset_id": "testset_123",
  "status": "completed",
  "started_at": "2024-01-15T12:00:00Z",
  "completed_at": "2024-01-15T12:05:30Z",
  "total_cases": 15,
  "passed_cases": 13,
  "failed_cases": 2,
  "warning_cases": 0,
  "agent_results": [
    {
      "config_id": "config_123",
      "passed": 7,
      "failed": 1,
      "warnings": 0
    }
  ]
}

Client Examples

Python Client Example

import requests
import json
from typing import Optional, Dict, Any

class CoAgentClient:
    def __init__(self, base_url: str = "http://localhost:3000/api/v1"):
        self.base_url = base_url
        self.session = requests.Session()
        self.session.headers.update({
            "Content-Type": "application/json"
        })
    
    def eval(self, run_id: str, preamble: str, prompt: str, 
             provider_id: str, model_name: str, 
             log_meta: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """Execute a single evaluation."""
        
        payload = {
            "run_id": run_id,
            "preamble": preamble,
            "prompt": prompt,
            "model_ref": {
                "provider_id": provider_id,
                "model_name": model_name
            },
            "log_meta": log_meta or {}
        }
        
        response = self.session.post(
            f"{self.base_url}/evals",
            json=payload
        )
        
        if response.status_code == 200:
            return response.json()
        else:
            response.raise_for_status()
    
    def create_agent(self, name: str, preamble: str, 
                     description: Optional[str] = None) -> Dict[str, Any]:
        """Create a new agent."""
        
        payload = {
            "name": name,
            "preamble": preamble
        }
        if description:
            payload["description"] = description
        
        response = self.session.post(
            f"{self.base_url}/agents",
            json=payload
        )
        
        if response.status_code == 200:
            return response.json()
        else:
            response.raise_for_status()
    
    def list_agents(self) -> Dict[str, Any]:
        """List all agents."""
        
        response = self.session.get(f"{self.base_url}/agents")
        
        if response.status_code == 200:
            return response.json()
        else:
            response.raise_for_status()

# Usage example
client = CoAgentClient()

# Create an evaluation
result = client.eval(
    run_id="eval_12345",
    preamble="You are a helpful assistant.",
    prompt="What are your business hours?",
    provider_id="openai-prod",
    model_name="gpt-4",
    log_meta={"component": "customer-service"}
)

print(f"Response: {result['response']}")
print(f"Tokens used: {result['token_usage']['total_tokens']}")

# Create an agent
agent = client.create_agent(
    name="support-agent",
    preamble="You are a customer support specialist.",
    description="Handles customer inquiries"
)

print(f"Created agent: {agent['id']}")

Rust Client Example

use serde::{Deserialize, Serialize};
use reqwest::Client;
use anyhow::{Result, Context};
use std::collections::HashMap;

#[derive(Debug, Serialize)]
pub struct EvalRequest {
    pub run_id: String,
    pub preamble: String,
    pub prompt: String,
    pub model_ref: ModelRef,
    pub log_meta: HashMap<String, serde_json::Value>,
}

#[derive(Debug, Serialize)]
pub struct ModelRef {
    pub provider_id: String,
    pub model_name: String,
}

#[derive(Debug, Deserialize)]
pub struct EvalResponse {
    pub response: String,
    pub token_usage: Option<TokenUsage>,
    pub run_id: String,
}

#[derive(Debug, Deserialize)]
pub struct TokenUsage {
    pub prompt_tokens: u32,
    pub completion_tokens: u32,
    pub total_tokens: u32,
}

#[derive(Debug, Serialize)]
pub struct CreateAgentRequest {
    pub name: String,
    pub preamble: String,
    pub description: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct Agent {
    pub id: String,
    pub name: String,
    pub description: Option<String>,
    pub preamble: String,
    pub created_at: String,
    pub updated_at: String,
}

pub struct CoAgentClient {
    client: Client,
    base_url: String,
}

impl CoAgentClient {
    pub fn new(base_url: String) -> Self {
        let client = Client::new();
        Self { client, base_url }
    }
    
    pub async fn eval(&self, request: EvalRequest) -> Result<EvalResponse> {
        let url = format!("{}/evals", self.base_url);
        
        let response = self.client
            .post(&url)
            .json(&request)
            .send()
            .await
            .context("Failed to send eval request")?;
        
        if response.status().is_success() {
            let eval_response: EvalResponse = response
                .json()
                .await
                .context("Failed to parse eval response")?;
            Ok(eval_response)
        } else {
            let status = response.status();
            let error_text = response.text().await.unwrap_or_default();
            anyhow::bail!("API error {}: {}", status, error_text);
        }
    }
    
    pub async fn create_agent(&self, request: CreateAgentRequest) -> Result<Agent> {
        let url = format!("{}/agents", self.base_url);
        
        let response = self.client
            .post(&url)
            .json(&request)
            .send()
            .await
            .context("Failed to send create agent request")?;
        
        if response.status().is_success() {
            let agent: Agent = response
                .json()
                .await
                .context("Failed to parse agent response")?;
            Ok(agent)
        } else {
            let status = response.status();
            let error_text = response.text().await.unwrap_or_default();
            anyhow::bail!("API error {}: {}", status, error_text);
        }
    }
    
    pub async fn list_agents(&self) -> Result<Vec<Agent>> {
        let url = format!("{}/agents", self.base_url);
        
        let response = self.client
            .get(&url)
            .send()
            .await
            .context("Failed to send list agents request")?;
        
        if response.status().is_success() {
            #[derive(Deserialize)]
            struct AgentsResponse {
                agents: Vec<Agent>,
            }
            
            let agents_response: AgentsResponse = response
                .json()
                .await
                .context("Failed to parse agents response")?;
            Ok(agents_response.agents)
        } else {
            let status = response.status();
            let error_text = response.text().await.unwrap_or_default();
            anyhow::bail!("API error {}: {}", status, error_text);
        }
    }
}

// Usage example
#[tokio::main]
async fn main() -> Result<()> {
    let client = CoAgentClient::new("http://localhost:3000/api/v1".to_string());
    
    // Create an evaluation
    let eval_request = EvalRequest {
        run_id: "eval_12345".to_string(),
        preamble: "You are a helpful assistant.".to_string(),
        prompt: "What are your business hours?".to_string(),
        model_ref: ModelRef {
            provider_id: "openai-prod".to_string(),
            model_name: "gpt-4".to_string(),
        },
        log_meta: {
            let mut meta = HashMap::new();
            meta.insert("component".to_string(), serde_json::Value::String("customer-service".to_string()));
            meta
        },
    };
    
    let eval_result = client.eval(eval_request).await?;
    println!("Response: {}", eval_result.response);
    if let Some(token_usage) = eval_result.token_usage {
        println!("Tokens used: {}", token_usage.total_tokens);
    }
    
    // Create an agent
    let agent_request = CreateAgentRequest {
        name: "support-agent".to_string(),
        preamble: "You are a customer support specialist.".to_string(),
        description: Some("Handles customer inquiries".to_string()),
    };
    
    let agent = client.create_agent(agent_request).await?;
    println!("Created agent: {}", agent.id);
    
    Ok(())
}

Best Practices

Request ID Generation

Always use unique request IDs for traceability:

Python:

import uuid
run_id = str(uuid.uuid4())

Rust:

use uuid::Uuid;
let run_id = Uuid::new_v4().to_string();

Error Handling

Implement proper error handling and retry logic:

Python:

import time
import random
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

# Configure retries
retry_strategy = Retry(
    total=3,
    status_forcelist=[429, 500, 502, 503, 504],
    backoff_factor=1
)

adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("http://", adapter)
session.mount("https://", adapter)

Rust:

use backoff::{future::retry, ExponentialBackoff};

let result = retry(ExponentialBackoff::default(), || async {
    match client.eval(request.clone()).await {
        Ok(response) => Ok(response),
        Err(e) if should_retry(&e) => Err(backoff::Error::transient(e)),
        Err(e) => Err(backoff::Error::permanent(e)),
    }
}).await?;

Logging and Monitoring

Include structured metadata in all requests:

{
  "log_meta": {
    "service": "my-service",
    "version": "1.0.0",
    "environment": "production",
    "user_id": "user_123",
    "session_id": "session_456",
    "request_id": "req_789"
  }
}

PII Handling

Always redact sensitive information before sending to CoAgent:

Python:

import re

def redact_pii(text: str) -> str:
    # Redact email addresses
    text = re.sub(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', '[REDACTED_EMAIL]', text)
    # Redact phone numbers
    text = re.sub(r'\b\d{3}-?\d{3}-?\d{4}\b', '[REDACTED_PHONE]', text)
    return text

Rate Limiting

Respect rate limits and implement backoff:

def handle_rate_limit(response):
    if response.status_code == 429:
        retry_after = int(response.headers.get('Retry-After', 60))
        time.sleep(retry_after)
        return True
    return False

Troubleshooting

Common Error Scenarios

Connection Refused

  • Cause: CoAgent service is not running

  • Solution: Ensure CoAgent is started with docker-compose up

400 Bad Request

  • Cause: Invalid request format or missing required fields

  • Solution: Validate request payload against API schema

404 Not Found

  • Cause: Agent, provider, or model doesn't exist

  • Solution: Check that referenced resources exist

429 Too Many Requests

  • Cause: Rate limit exceeded

  • Solution: Implement exponential backoff retry logic

500 Internal Server Error

  • Cause: Server-side error in CoAgent

  • Solution: Check CoAgent logs and retry the request

Debug Mode

Enable debug logging to troubleshoot issues:

Python:

import logging
logging.basicConfig(level=logging.DEBUG)

Rust:

env_logger::init();

Health Checks

Always verify CoAgent health before making requests:

curl -f

API Changelog

v0.4.0

  • Initial API release

  • Core evaluation endpoints

  • Agent management

  • Provider management

  • Test set management

In case of issuse contact the development team.