# Admin Assistant — REST API Reference

LLM-powered admin assistant accessed via REST. Send natural language queries about security incidents, jobs, users, groups, and metrics. Responses are generated by Claude using permission-gated tools.

## Requirements

- Feature must be enabled server-side (`LLM_ADMIN_ENABLED = True`)
- User must have `view_admin` permission to access all endpoints
- Tool access depends on the user's additional permissions (see [Permission Mapping](#permission-mapping))

## Endpoints

### Send Message

```
POST /api/assistant
```

Send a message to the assistant and receive an LLM-generated response.

**Permission**: `view_admin`
**Rate limit**: 60/ip, 30/device

**Request body**:

| Field | Type | Required | Description |
|---|---|---|---|
| `message` | string | Yes | Natural language query |
| `conversation_id` | integer | No | Continue an existing conversation |

**Response** (success):

```json
{
    "status": true,
    "data": {
        "response": "Here are the failed jobs in the last hour...",
        "conversation_id": 42,
        "tool_calls_made": [
            {"tool": "query_jobs", "input": {"status": "failed", "minutes": 60}}
        ]
    }
}
```

**Response** (feature disabled — HTTP 404):

```json
{
    "status": false,
    "error": "Assistant is not enabled"
}
```

**Response** (no API key — HTTP 503):

```json
{
    "status": false,
    "error": "LLM API key not configured"
}
```

**Response** (invalid `conversation_id` — HTTP 404):

```json
{
    "status": false,
    "error": "Conversation not found",
    "conversation_id": null
}
```

**Example queries**:

```
"Show me failed jobs in the last hour"
"What's the incident trend this week?"
"Which users were rate-limited today?"
"How many open incidents are there by category?"
"What permissions does user john@example.com have?"
"Block IP 1.2.3.4 for brute force attacks"
```

---

### List Conversations

```
GET /api/assistant/conversation
```

List the requesting user's past conversations. Only returns conversations owned by the authenticated user.

**Permission**: `view_admin`

**Query parameters**:

| Param | Type | Default | Description |
|---|---|---|---|
| `limit` | integer | 20 | Max conversations to return (max 50) |

**Response**:

```json
{
    "status": true,
    "data": [
        {
            "id": 42,
            "title": "Show me failed jobs",
            "created": "2026-04-01 14:30:00+00:00",
            "modified": "2026-04-01 14:32:15+00:00"
        }
    ]
}
```

---

### Get Conversation

```
GET /api/assistant/conversation/<id>
```

Get a conversation with its full message history. Only accessible by the conversation owner.

**Permission**: `view_admin` + owner

**Response**:

```json
{
    "status": true,
    "data": {
        "id": 42,
        "title": "Show me failed jobs",
        "created": "2026-04-01 14:30:00+00:00",
        "modified": "2026-04-01 14:32:15+00:00",
        "messages": [
            {
                "id": 1,
                "role": "user",
                "content": "Show me failed jobs in the last hour",
                "tool_calls": null,
                "created": "2026-04-01 14:30:00+00:00"
            },
            {
                "id": 2,
                "role": "assistant",
                "content": "I found 3 failed jobs in the last hour...",
                "tool_calls": null,
                "created": "2026-04-01 14:30:05+00:00"
            }
        ]
    }
}
```

**Response** (not found / not owner — HTTP 404):

```json
{
    "status": false,
    "error": "Conversation not found"
}
```

---

### Delete Conversation

```
DELETE /api/assistant/conversation/<id>
```

Delete a conversation and all its messages. Only the conversation owner can delete.

**Permission**: `view_admin` + owner

**Response**:

```json
{
    "status": true
}
```

**Response** (not found / not owner — HTTP 404):

```json
{
    "status": false,
    "error": "Conversation not found"
}
```

---

## Permission Mapping

The assistant checks the user's permissions before executing each tool. The tools available to a user depend on their permissions:

| Permission | Tools Available |
|---|---|
| `view_security` | Query incidents, events, event counts, tickets, rulesets, IP history, incident timeline, incident trends |
| `manage_security` | All `view_security` tools + update incident, block IP, create ticket |
| `view_jobs` | Query jobs, job events, job logs, job stats, queue health |
| `manage_jobs` | All `view_jobs` tools + cancel job, retry job |
| `view_admin` | Query users, user detail, user activity, rate limits, permission summary, fetch metrics, system health |
| `view_groups` | Query groups, group detail, group members, group activity |

Users without any of these permissions will receive: `"You don't have permissions for any assistant tools."`

If the LLM tries to call a tool the user doesn't have permission for, the tool returns a permission error to the LLM (not to the client), and the LLM explains what permission is needed.

## Multi-turn Conversations

The assistant maintains conversation context across multiple requests. To continue a conversation, pass the `conversation_id` from the previous response:

```javascript
// First message
const resp1 = await fetch('/api/assistant', {
    method: 'POST',
    headers: {'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json'},
    body: JSON.stringify({message: 'Show me open incidents'})
});
const data1 = await resp1.json();
const convId = data1.data.conversation_id;

// Follow-up in the same conversation
const resp2 = await fetch('/api/assistant', {
    method: 'POST',
    headers: {'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json'},
    body: JSON.stringify({
        message: 'Now show me the timeline for the first one',
        conversation_id: convId
    })
});
```

## Mutating Operations

Tools that modify data (block IP, cancel job, update incident, create ticket) require `manage_*` permissions. The LLM is instructed to confirm with the user before executing these, so the typical flow is:

1. User: "Block IP 1.2.3.4"
2. Assistant: "I'll block IP 1.2.3.4 with a 1-hour TTL. Confirm?"
3. User: "Yes"
4. Assistant: "Done. IP 1.2.3.4 has been blocked for 3600 seconds."

This confirmation happens via conversation turns, not a separate API call.
