Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ sdks/python/src/agent_control/
import agent_control

# Initialization
agent_control.init(agent_name="...", agent_id="...")
agent_control.init(agent_name="...", agent_name="...")

# Decorator
@agent_control.control()
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ async def setup():
# 1. Register agent first (required before assigning policy)
agent = Agent(
# Your agent's UUID
agent_id="550e8400-e29b-41d4-a716-446655440000",
agent_name="550e8400-e29b-41d4-a716-446655440000",
agent_name="My Chatbot",
agent_created_at=datetime.now(UTC).isoformat()
)
Expand Down Expand Up @@ -165,7 +165,7 @@ async def setup():
# 5. Assign policy to agent
await policies.assign_policy_to_agent(
client,
agent_id=AGENT_ID,
agent_name=AGENT_ID,
policy_id=policy["policy_id"]
)

Expand Down Expand Up @@ -199,7 +199,7 @@ from agent_control import control, ControlViolationError
# Initialize your agent
agent_control.init(
agent_name="My Chatbot",
agent_id="550e8400-e29b-41d4-a716-446655440000"
agent_name="550e8400-e29b-41d4-a716-446655440000"
)

# Protect any function (like LLM calls)
Expand Down
14 changes: 7 additions & 7 deletions docs/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ import agent_control

agent_control.init(
agent_name="my-agent", # Required: human-readable name
agent_id="550e8400-e29b-41d4-a716-446655440000", # Required: UUID
agent_name="550e8400-e29b-41d4-a716-446655440000", # Required: UUID
server_url="http://localhost:8000", # Optional: defaults to env var
steps=[ # Optional: register available steps
{
Expand Down Expand Up @@ -770,12 +770,12 @@ Default: `http://localhost:8000/api/v1`
|--------|----------|-------------|
| `GET` | `/agents` | List all agents |
| `POST` | `/agents/initAgent` | Register a new agent |
| `GET` | `/agents/{agent_id}` | Get agent details |
| `PATCH` | `/agents/{agent_id}` | Update agent |
| `GET` | `/agents/{agent_id}/controls` | List controls for agent |
| `GET` | `/agents/{agent_id}/policy` | Get agent's policy |
| `POST` | `/agents/{agent_id}/policy/{policy_id}` | Assign policy |
| `DELETE` | `/agents/{agent_id}/policy` | Remove policy |
| `GET` | `/agents/{agent_name}` | Get agent details |
| `PATCH` | `/agents/{agent_name}` | Update agent |
| `GET` | `/agents/{agent_name}/controls` | List controls for agent |
| `GET` | `/agents/{agent_name}/policy` | Get agent's policy |
| `POST` | `/agents/{agent_name}/policy/{policy_id}` | Assign policy |
| `DELETE` | `/agents/{agent_name}/policy` | Remove policy |

**Controls**:

Expand Down
40 changes: 20 additions & 20 deletions docs/observability.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class EventStore(ABC):

@abstractmethod
async def query_stats(
self, agent_uuid: UUID, time_range: timedelta, control_id: int | None = None
self, agent_name: UUID, time_range: timedelta, control_id: int | None = None
) -> StatsResult:
"""Query stats (aggregated at query time)."""
pass
Expand Down Expand Up @@ -220,12 +220,12 @@ Events are stored with minimal indexed columns + JSONB for flexibility:
CREATE TABLE control_execution_events (
control_execution_id VARCHAR(36) PRIMARY KEY,
timestamp TIMESTAMPTZ NOT NULL,
agent_uuid UUID NOT NULL,
agent_name UUID NOT NULL,
data JSONB NOT NULL -- Full event stored here
);

-- Primary index for time-range queries per agent
CREATE INDEX ix_events_agent_time ON control_execution_events (agent_uuid, timestamp DESC);
CREATE INDEX ix_events_agent_time ON control_execution_events (agent_name, timestamp DESC);

-- Expression index for grouping by control
CREATE INDEX ix_events_data_control_id ON control_execution_events ((data->>'control_id'));
Expand All @@ -245,7 +245,7 @@ Each control evaluation produces an event (stored in the `data` JSONB column):
control_execution_id: string, // Unique ID (for correlation)
trace_id: string, // OpenTelemetry trace ID (32 hex chars)
span_id: string, // OpenTelemetry span ID (16 hex chars)
agent_uuid: UUID,
agent_name: UUID,
agent_name: string,
control_id: number,
control_name: string,
Expand All @@ -272,9 +272,9 @@ All observability endpoints are under `/api/v1/observability/`.
|----------|----------|------------|---------|
| **Health check** | `GET /status` | — | System status |
| **Ingest events** | `POST /events` | `events[]` in body | Ingestion result |
| **Agent overview** | `GET /stats` | `agent_uuid`, `time_range` | `totals` + `controls[]` |
| **Agent overview** | `GET /stats` | `agent_name`, `time_range` | `totals` + `controls[]` |
| **Agent trends** | `GET /stats` | + `include_timeseries=true` | `totals.timeseries[]` included |
| **Control stats** | `GET /stats/controls/{id}` | `agent_uuid`, `time_range` | `control_id`, `control_name`, `stats` |
| **Control stats** | `GET /stats/controls/{id}` | `agent_name`, `time_range` | `control_id`, `control_name`, `stats` |
| **Control trends** | `GET /stats/controls/{id}` | + `include_timeseries=true` | `stats.timeseries[]` included |
| **Query raw events** | `POST /events/query` | Filters in body | `events[]` with pagination |

Expand Down Expand Up @@ -323,7 +323,7 @@ Content-Type: application/json
"control_execution_id": "...",
"trace_id": "...",
"span_id": "...",
"agent_uuid": "...",
"agent_name": "...",
"control_id": 1,
"control_name": "block-toxic",
"matched": true,
Expand All @@ -350,14 +350,14 @@ Content-Type: application/json
Get agent-level aggregated statistics with per-control breakdown.

```http
GET /api/v1/observability/stats?agent_uuid=<uuid>&time_range=<range>&include_timeseries=<bool>
GET /api/v1/observability/stats?agent_name=<uuid>&time_range=<range>&include_timeseries=<bool>
```

**Query Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_uuid` | UUID | Yes | Agent to get stats for |
| `agent_name` | UUID | Yes | Agent to get stats for |
| `time_range` | string | No | Time range: `1m`, `5m`, `15m`, `1h`, `24h`, `7d`, `30d`, `180d`, `365d` (default: `5m`) |
| `include_timeseries` | boolean | No | Include time-series data for trend visualization (default: `false`) |

Expand All @@ -379,13 +379,13 @@ When `include_timeseries=true`, data is bucketed automatically based on the time

**Example Request:**
```bash
curl "http://localhost:8000/api/v1/observability/stats?agent_uuid=563de065-23aa-5d75-b594-cfa73abcc53c&time_range=1h"
curl "http://localhost:8000/api/v1/observability/stats?agent_name=563de065-23aa-5d75-b594-cfa73abcc53c&time_range=1h"
```

**Example Response:**
```json
{
"agent_uuid": "563de065-23aa-5d75-b594-cfa73abcc53c",
"agent_name": "563de065-23aa-5d75-b594-cfa73abcc53c",
"time_range": "1h",
"totals": {
"execution_count": 8,
Expand Down Expand Up @@ -442,13 +442,13 @@ curl "http://localhost:8000/api/v1/observability/stats?agent_uuid=563de065-23aa-

**Example Request with Time-Series:**
```bash
curl "http://localhost:8000/api/v1/observability/stats?agent_uuid=563de065-23aa-5d75-b594-cfa73abcc53c&time_range=1h&include_timeseries=true"
curl "http://localhost:8000/api/v1/observability/stats?agent_name=563de065-23aa-5d75-b594-cfa73abcc53c&time_range=1h&include_timeseries=true"
```

**Example Response with Time-Series:**
```json
{
"agent_uuid": "563de065-23aa-5d75-b594-cfa73abcc53c",
"agent_name": "563de065-23aa-5d75-b594-cfa73abcc53c",
"time_range": "1h",
"totals": {
"execution_count": 8,
Expand Down Expand Up @@ -512,7 +512,7 @@ Empty buckets are included with zero counts and `null` averages to ensure consis
Get statistics for a single control.

```http
GET /api/v1/observability/stats/controls/{control_id}?agent_uuid=<uuid>&time_range=<range>&include_timeseries=<bool>
GET /api/v1/observability/stats/controls/{control_id}?agent_name=<uuid>&time_range=<range>&include_timeseries=<bool>
```

**Path Parameters:**
Expand All @@ -525,19 +525,19 @@ GET /api/v1/observability/stats/controls/{control_id}?agent_uuid=<uuid>&time_ran

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_uuid` | UUID | Yes | Agent to get stats for |
| `agent_name` | UUID | Yes | Agent to get stats for |
| `time_range` | string | No | Time range: `1m`, `5m`, `15m`, `1h`, `24h`, `7d`, `30d`, `180d`, `365d` (default: `5m`) |
| `include_timeseries` | boolean | No | Include time-series data for trend visualization (default: `false`) |

**Example Request:**
```bash
curl "http://localhost:8000/api/v1/observability/stats/controls/1?agent_uuid=563de065-23aa-5d75-b594-cfa73abcc53c&time_range=1h&include_timeseries=true"
curl "http://localhost:8000/api/v1/observability/stats/controls/1?agent_name=563de065-23aa-5d75-b594-cfa73abcc53c&time_range=1h&include_timeseries=true"
```

**Example Response:**
```json
{
"agent_uuid": "563de065-23aa-5d75-b594-cfa73abcc53c",
"agent_name": "563de065-23aa-5d75-b594-cfa73abcc53c",
"time_range": "1h",
"control_id": 1,
"control_name": "block-prompt-injection",
Expand Down Expand Up @@ -595,7 +595,7 @@ Content-Type: application/json
| `trace_id` | string | No | Filter by trace ID |
| `span_id` | string | No | Filter by span ID |
| `control_execution_id` | string | No | Get specific event |
| `agent_uuid` | UUID | No | Filter by agent |
| `agent_name` | UUID | No | Filter by agent |
| `control_ids` | integer[] | No | Filter by control IDs |
| `actions` | string[] | No | Filter by actions: `allow`, `deny`, `warn`, `log` |
| `matched` | boolean | No | Filter by matched status |
Expand All @@ -611,7 +611,7 @@ Content-Type: application/json
curl -X POST "http://localhost:8000/api/v1/observability/events/query" \
-H "Content-Type: application/json" \
-d '{
"agent_uuid": "563de065-23aa-5d75-b594-cfa73abcc53c",
"agent_name": "563de065-23aa-5d75-b594-cfa73abcc53c",
"matched": true,
"limit": 5
}'
Expand All @@ -625,7 +625,7 @@ curl -X POST "http://localhost:8000/api/v1/observability/events/query" \
"control_execution_id": "92df0332-170c-4bc6-aefd-ab50be311062",
"trace_id": "5848335875e1d7269e148170ccb617ca",
"span_id": "c25549deddcaecbe",
"agent_uuid": "563de065-23aa-5d75-b594-cfa73abcc53c",
"agent_name": "563de065-23aa-5d75-b594-cfa73abcc53c",
"agent_name": "Customer Support Agent",
"control_id": 3,
"control_name": "block-credit-card",
Expand Down
2 changes: 1 addition & 1 deletion docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ async def test_sdk_denies_on_local_control() -> None:
# When: evaluating via the SDK public API
result = await check_evaluation_with_local(
client=client,
agent_uuid=agent_uuid,
agent_name=agent_name,
step=Step(type="tool", name="db_query", input={"sql": "SELECT 1"}, output=None),
stage="pre",
controls=controls,
Expand Down
Loading
Loading