# API Adapters Reference

API adapters provide protocol-specific interfaces for interacting with Xaibo agents. They translate external API requests into Xaibo agent calls and format responses according to the target protocol specifications.

!!! tip "Authentication Setup Guide"
    For step-by-step authentication setup instructions, see the [authentication how-to guide](../../how-to/authentication.md).

## Available Adapters

- **[OpenAiApiAdapter](#openaiapiadapter)** - OpenAI Chat Completions API compatibility
- **[OpenAiResponsesApiAdapter](openai-responses-adapter.md)** - OpenAI Responses API with conversation management
- **[McpApiAdapter](#mcpapiadapter)** - Model Context Protocol (MCP) server functionality
- **[UiApiAdapter](#uiapiadapter)** - GraphQL API for web interface

## OpenAiApiAdapter

Provides OpenAI Chat Completions API compatibility for Xaibo agents.

**Source**: [`src/xaibo/server/adapters/openai.py`](https://github.com/xpressai/xaibo/blob/main/src/xaibo/server/adapters/openai.py)

**Class Path**: `xaibo.server.adapters.OpenAiApiAdapter`

### Constructor

```python
OpenAiApiAdapter(xaibo: Xaibo, streaming_timeout=10, api_key: Optional[str] = None)
```

#### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `xaibo` | `Xaibo` | Xaibo instance containing registered agents |
| `streaming_timeout` | `int` | Timeout in seconds for streaming responses (default: 10) |
| `api_key` | `Optional[str]` | API key for authentication. If provided, all requests must include valid Authorization header. Falls back to `OPENAI_API_KEY` environment variable if not specified. |

### API Endpoints

#### GET `/openai/models`

Returns list of available agents as OpenAI-compatible models.

**Authentication:** Required if API key is configured.

**Request Headers:**
```http
Authorization: Bearer sk-your-api-key  # Required if authentication enabled
```

**Response Format:**

```json
{
  "object": "list",
  "data": [
    {
      "id": "my-agent",
      "object": "model",
      "created": 0,
      "owned_by": "organization-owner"
    }
  ]
}
```

#### POST `/openai/chat/completions`

OpenAI-compatible chat completions endpoint.

**Authentication:** Required if API key is configured.

**Request Headers:**
```http
Content-Type: application/json
Authorization: Bearer sk-your-api-key  # Required if authentication enabled
```

**Request Format:**

```json
{
  "model": "agent-id",
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful assistant."
    },
    {
      "role": "user",
      "content": "Hello, how are you?"
    }
  ],
  "temperature": 0.7,
  "max_tokens": 2048,
  "stream": false
}
```

**Request Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `model` | `str` | Yes | Xaibo agent ID to use |
| `messages` | `List[dict]` | Yes | Conversation messages |
| `stream` | `bool` | No | Enable streaming responses |
| `temperature` | `float` | No | *Not yet implemented* - Sampling temperature (0.0-2.0) |
| `max_tokens` | `int` | No | *Not yet implemented* - Maximum tokens to generate |
| `top_p` | `float` | No | *Not yet implemented* - Nucleus sampling parameter |
| `stop` | `List[str]` | No | *Not yet implemented* - Stop sequences |
| `presence_penalty` | `float` | No | *Not yet implemented* - Presence penalty (-2.0 to 2.0) |
| `frequency_penalty` | `float` | No | *Not yet implemented* - Frequency penalty (-2.0 to 2.0) |
| `user` | `str` | No | *Not yet implemented* - User identifier |

**Response Format (Non-Streaming):**

```json
{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "model": "agent-id",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello! I'm doing well, thank you for asking."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 0,
    "completion_tokens": 0,
    "total_tokens": 0
  }
}
```

**Response Format (Streaming):**

```
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"agent-id","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"agent-id","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"agent-id","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]
```

### Message Format Support

#### Text Messages

Currently only text messages are supported:

```json
{
  "role": "user",
  "content": "What is the weather like?"
}
```

#### Image Messages (*Planned*)

Image message support is planned for future releases:

```json
{
  "role": "user",
  "content": [
    {
      "type": "text",
      "text": "What's in this image?"
    },
    {
      "type": "image_url",
      "image_url": {
        "url": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
      }
    }
  ]
}
```

#### Function Calls (*Planned*)

Function call support is planned for future releases:

```json
{
  "role": "assistant",
  "content": null,
  "function_call": {
    "name": "get_weather",
    "arguments": "{\"city\": \"San Francisco\"}"
  }
}
```

### Error Handling

#### Authentication Errors

When API key authentication is enabled:

**Missing Authorization Header:**
```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer

{
  "detail": "Missing Authorization header"
}
```

**Invalid API Key:**
```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer

{
  "detail": "Invalid API key"
}
```

#### Agent Not Found

```json
{
  "detail": "model not found"
}
```

**Note**: Token counting is not yet implemented, so the `usage` field in responses currently returns zeros. Full OpenAI-compatible error response format and specific error codes are planned for future releases.

### Example Usage

#### cURL

**Without Authentication:**
```bash
curl -X POST http://localhost:8000/openai/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "my-agent",
    "messages": [
      {"role": "user", "content": "Hello!"}
    ],
    "temperature": 0.7
  }'
```

**With Authentication:**
```bash
curl -X POST http://localhost:8000/openai/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-your-api-key" \
  -d '{
    "model": "my-agent",
    "messages": [
      {"role": "user", "content": "Hello!"}
    ],
    "temperature": 0.7
  }'
```

#### Python (OpenAI SDK)

**Without Authentication:**
```python
import openai

client = openai.OpenAI(
    base_url="http://localhost:8000/openai",
    api_key="not-needed"  # No authentication required
)

response = client.chat.completions.create(
    model="my-agent",
    messages=[
        {"role": "user", "content": "Hello!"}
    ],
    temperature=0.7
)

print(response.choices[0].message.content)
```

**With Authentication:**
```python
import openai

client = openai.OpenAI(
    base_url="http://localhost:8000/openai",
    api_key="sk-your-api-key"  # Use your configured API key
)

response = client.chat.completions.create(
    model="my-agent",
    messages=[
        {"role": "user", "content": "Hello!"}
    ],
    temperature=0.7
)

print(response.choices[0].message.content)
```

#### Streaming

```python
stream = client.chat.completions.create(
    model="my-agent",
    messages=[{"role": "user", "content": "Tell me a story"}],
    stream=True
)

for chunk in stream:
    if chunk.choices[0].delta.content is not None:
        print(chunk.choices[0].delta.content, end="")
```

## McpApiAdapter

Implements Model Context Protocol (MCP) server functionality.

**Source**: [`src/xaibo/server/adapters/mcp.py`](https://github.com/xpressai/xaibo/blob/main/src/xaibo/server/adapters/mcp.py)

**Class Path**: `xaibo.server.adapters.McpApiAdapter`

### Constructor

```python
McpApiAdapter(xaibo: Xaibo, api_key: Optional[str] = None)
```

#### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `xaibo` | `Xaibo` | Xaibo instance containing registered agents |
| `api_key` | `Optional[str]` | API key for authentication. If provided, all requests must include valid Authorization header. Falls back to `MCP_API_KEY` environment variable if not specified. |

### API Endpoints

#### POST `/mcp/`

Main MCP JSON-RPC 2.0 endpoint for all protocol communication.

**Authentication:** Required if API key is configured.

**Request Headers:**
```http
Content-Type: application/json
Authorization: Bearer your-api-key  # Required if authentication enabled
```

**Request Format:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "method_name",
  "params": {
    "param1": "value1",
    "param2": "value2"
  }
}
```

**Response Format:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "data": "response_data"
  }
}
```

**Error Response Format:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32600,
    "message": "Invalid Request",
    "data": "Additional error information"
  }
}
```

**Authentication Error Response:**

```json
{
  "jsonrpc": "2.0",
  "id": null,
  "error": {
    "code": -32001,
    "message": "Missing Authorization header"
  }
}
```

### Supported MCP Methods

#### `initialize`

Establishes connection and exchanges capabilities.

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "clientInfo": {
      "name": "my-client",
      "version": "1.0.0"
    },
    "capabilities": {}
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "serverInfo": {
      "name": "xaibo-mcp-server",
      "version": "1.0.0"
    },
    "capabilities": {
      "tools": {}
    }
  }
}
```

#### `notifications/initialized`

Confirms initialization completion.

**Request:**

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}
```

**Response:** No response (notification)

#### `tools/list`

Returns available Xaibo agents as MCP tools.

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list",
  "params": {}
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "my-agent",
        "description": "Execute Xaibo agent 'my-agent'",
        "inputSchema": {
          "type": "object",
          "properties": {
            "message": {
              "type": "string",
              "description": "The text message to send to the agent"
            }
          },
          "required": ["message"]
        }
      }
    ]
  }
}
```

#### `tools/call`

Executes a specific agent with provided arguments.

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "my-agent",
    "arguments": {
      "message": "Hello, what can you help me with?"
    }
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Hello! I'm a helpful assistant. I can help you with various tasks..."
      }
    ]
  }
}
```

### Agent Entry Points

For agents with multiple entry points, tools are named as `agent_id.entry_point`:

```json
{
  "tools": [
    {
      "name": "multi-agent.text",
      "description": "Execute text handler for 'multi-agent'"
    },
    {
      "name": "multi-agent.image", 
      "description": "Execute image handler for 'multi-agent'"
    }
  ]
}
```

### Error Codes

| Code | Description | Meaning |
|------|-------------|---------|
| `-32700` | Parse error | Invalid JSON |
| `-32600` | Invalid Request | Missing required fields |
| `-32601` | Method not found | Unsupported MCP method |
| `-32602` | Invalid params | Missing agent or arguments |
| `-32603` | Internal error | Agent execution failure |
| `-32001` | Authentication error | Missing, invalid, or malformed Authorization header |

### Example Usage

#### cURL

**Without Authentication:**
```bash
# Initialize connection
curl -X POST http://localhost:8000/mcp/ \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2024-11-05",
      "clientInfo": {"name": "test-client", "version": "1.0.0"}
    }
  }'

# List available tools
curl -X POST http://localhost:8000/mcp/ \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/list",
    "params": {}
  }'

# Call an agent
curl -X POST http://localhost:8000/mcp/ \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "my-agent",
      "arguments": {"message": "Hello!"}
    }
  }'
```

**With Authentication:**
```bash
# Initialize connection
curl -X POST http://localhost:8000/mcp/ \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-api-key" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2024-11-05",
      "clientInfo": {"name": "test-client", "version": "1.0.0"}
    }
  }'

# List available tools
curl -X POST http://localhost:8000/mcp/ \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-api-key" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/list",
    "params": {}
  }'

# Call an agent
curl -X POST http://localhost:8000/mcp/ \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-api-key" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "my-agent",
      "arguments": {"message": "Hello!"}
    }
  }'
```

#### Python (MCP Client)

**Without Authentication:**
```python
import json
import requests

class MCPClient:
    def __init__(self, base_url: str, api_key: str = None):
        self.base_url = base_url
        self.session = requests.Session()
        self.request_id = 0
        
        # Set up authentication if API key provided
        if api_key:
            self.session.headers.update({
                "Authorization": f"Bearer {api_key}"
            })
    
    def _call(self, method: str, params: dict = None):
        self.request_id += 1
        payload = {
            "jsonrpc": "2.0",
            "id": self.request_id,
            "method": method,
            "params": params or {}
        }
        
        response = self.session.post(
            f"{self.base_url}/mcp/",
            json=payload,
            headers={"Content-Type": "application/json"}
        )
        
        return response.json()
    
    def initialize(self):
        return self._call("initialize", {
            "protocolVersion": "2024-11-05",
            "clientInfo": {"name": "python-client", "version": "1.0.0"}
        })
    
    def list_tools(self):
        return self._call("tools/list")
    
    def call_tool(self, name: str, arguments: dict):
        return self._call("tools/call", {
            "name": name,
            "arguments": arguments
        })

# Usage without authentication
client = MCPClient("http://localhost:8000")

# Initialize
init_response = client.initialize()
print("Initialized:", init_response)

# List tools
tools_response = client.list_tools()
print("Available tools:", tools_response["result"]["tools"])

# Call agent
result = client.call_tool("my-agent", {"message": "Hello!"})
print("Agent response:", result["result"]["content"])
```

**With Authentication:**
```python
# Usage with authentication
client = MCPClient("http://localhost:8000", api_key="your-api-key")

# Initialize
init_response = client.initialize()
print("Initialized:", init_response)

# List tools
tools_response = client.list_tools()
print("Available tools:", tools_response["result"]["tools"])

# Call agent
result = client.call_tool("my-agent", {"message": "Hello!"})
print("Agent response:", result["result"]["content"])
```

## UiApiAdapter

Provides debug UI and GraphQL API for agent inspection and monitoring.

**Source**: [`src/xaibo/server/adapters/ui.py`](https://github.com/xpressai/xaibo/blob/main/src/xaibo/server/adapters/ui.py)

**Class Path**: `xaibo.server.adapters.UiApiAdapter`

### Constructor

```python
UiApiAdapter(xaibo: Xaibo)
```

#### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `xaibo` | `Xaibo` | Xaibo instance for agent management |

### API Endpoints

#### GET `/`

Serves static UI files.

**Response:** Static files for the web interface

#### POST `/api/ui/graphql`

GraphQL endpoint for querying agent data and execution traces.

**Request Format:**

```json
{
  "query": "query GetAgents { agents { id description modules { id module } } }"
}
```

**Response Format:**

```json
{
  "data": {
    "agents": [
      {
        "id": "my-agent",
        "description": "Example agent",
        "modules": [
          {"id": "llm", "module": "xaibo.primitives.modules.llm.OpenAILLM"}
        ]
      }
    ]
  }
}
```

### GraphQL Schema

#### Agent Type

```graphql
type Agent {
  id: String!
}
```

**Note**: Currently only the `id` field is implemented. The `description`, `modules`, and `exchange` fields are planned for future releases.

#### Module Type

```graphql
type Module {
  id: String!
  module: String!
  config: JSON
  provides: [String!]
  uses: [String!]
}
```

#### Exchange Type

```graphql
type Exchange {
  module: String!
  protocol: String!
  provider: String!
  fieldName: String
}
```

#### DebugTrace Type

```graphql
type DebugTrace {
  agent_id: String!
  events: [Event!]!
}
```

**Note**: The `debug_log` query returns `DebugTrace` instead of `Trace`. The `Trace` type is not implemented.

### Example Queries

#### List All Agents

```graphql
query GetAgents {
  list_agents {
    id
  }
}
```

#### Get Agent Configuration

```graphql
query GetAgentConfig($agentId: String!) {
  agent_config(agent_id: $agentId) {
    id
    modules {
      id
      module
      provides
      uses
      config
    }
    exchange {
      module
      protocol
      provider
    }
  }
}
```

#### Get Debug Traces

```graphql
query GetDebugLog($agentId: String!) {
  debug_log(agent_id: $agentId) {
    agent_id
    events {
      agent_id
      event_name
      event_type
      module_id
      module_class
      method_name
      time
      call_id
      caller_id
      arguments
      result
      exception
    }
  }
}
```

### Debug UI Features

#### Agent Overview

- List of all registered agents
- Agent configuration visualization
- Module dependency graphs

#### Execution Traces

- Real-time trace viewing
- Filtering by agent and event type
- Detailed event inspection

#### Performance Metrics

- Response time statistics
- Token usage tracking
- Error rate monitoring

## Adapter Development

### Creating Custom Adapters

```python
from fastapi import FastAPI
from xaibo import Xaibo

class CustomApiAdapter:
    def __init__(self, xaibo: Xaibo):
        self.xaibo = xaibo
    
    def adapt(self, app: FastAPI):
        """Add routes to the FastAPI application"""
        
        @app.post("/custom/endpoint")
        async def custom_endpoint(request: CustomRequest):
            # Convert request to Xaibo format
            agent_id = request.agent_id
            message = request.message
            
            # Execute agent
            agent = self.xaibo.get_agent(agent_id)
            response = await agent.handle_text_message(message)
            
            # Convert response to custom format
            return CustomResponse(
                result=response.content,
                metadata=response.metadata
            )
```

### Adapter Registration

```python
# Register custom adapter
server = XaiboWebServer(
    xaibo=xaibo,
    adapters=["my.custom.CustomApiAdapter"],
    agent_dir="./agents"
)
```

### Best Practices

1. **Error Handling**: Implement comprehensive error handling
2. **Validation**: Validate all input parameters
3. **Documentation**: Provide clear API documentation
4. **Testing**: Include thorough test coverage
5. **Performance**: Optimize for expected load patterns

## Configuration Examples

### Multi-Adapter Setup

```yaml
# docker-compose.yml
version: '3.8'
services:
  xaibo-server:
    image: xaibo:latest
    ports:
      - "8000:8000"
    command: >
      python -m xaibo.server.web
      --agent-dir /app/agents
      --adapter xaibo.server.adapters.OpenAiApiAdapter
      --adapter xaibo.server.adapters.McpApiAdapter
      --adapter xaibo.server.adapters.UiApiAdapter
      --host 0.0.0.0
      --port 8000
    volumes:
      - ./agents:/app/agents
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
```

### Load Balancer Configuration

```nginx
upstream xaibo_backend {
    server xaibo-1:8000;
    server xaibo-2:8000;
    server xaibo-3:8000;
}

server {
    listen 80;
    server_name api.example.com;
    
    location /openai/ {
        proxy_pass http://xaibo_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
    location /mcp {
        proxy_pass http://xaibo_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}