Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
215 changes: 215 additions & 0 deletions examples/agent_control_demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
# Agent Control Demo

Complete example demonstrating the Agent Control workflow: creating controls, running a controlled agent, and dynamically updating controls without code changes.

## Overview

This demo shows how to:
1. Create an agent and register it with the Agent Control server
2. Define controls (regex, list-based) and assign them to a policy
3. Run an agent that uses the `@control` decorator with server-side policies
4. Dynamically update controls on the server (enable/disable rules without redeploying code)

## Prerequisites

Before running this example:

1. **Start the Agent Control server** from the monorepo root:
```bash
cd server && make run
Comment thread
namrataghadi-galileo marked this conversation as resolved.
Outdated
```

2. **Verify server is running**:
```bash
curl http://localhost:8000/health
# Expected: {"status":"healthy","version":"..."}
```

3. **Install dependencies** (if not already done from monorepo root):
```bash
cd /path/to/agent-control
Comment thread
namrataghadi-galileo marked this conversation as resolved.
Outdated
make sync
```

## Quick Start

### Step 1: Create Controls on the Server

Run the setup script to create the agent, controls, and policy:

```bash
uv run python examples/agent_control_demo/setup_controls.py
```

This creates:
- A demo agent (`demo-chatbot`)
- Two controls:
- **block-ssn-output**: Regex control to detect and block Social Security Numbers (SSN)
- **block-banned-words**: List-based control to block profanity and sensitive keywords
- A policy with both controls assigned to the agent

### Step 2: Run the Demo Agent

Start the agent that uses server-side controls:

```bash
uv run python examples/agent_control_demo/demo_agent.py
```

The agent will:
- Initialize with `agent_control.init()` to connect to the server
- Load the assigned policy with all controls
- Apply the `@control()` decorator to protect functions
- Test various scenarios:
- ✅ Normal message (allowed)
- ❌ Message containing banned words (blocked)
- ✅ Message with allowed content (passes)
- ❌ Tool output containing SSN (blocked)

### Step 3: Update Controls Dynamically

Update controls on the server without changing code or restarting the agent:

```bash
# Disable the SSN control (allow SSNs)
uv run python examples/agent_control_demo/update_controls.py --allow-ssn

# Re-enable the SSN control (block SSNs again)
uv run python examples/agent_control_demo/update_controls.py --block-ssn
```

**Key Insight**: Controls are enforced server-side, so you can update rules in real-time without code deployments.

## Files

| File | Description |
|:-----|:------------|
| [setup_controls.py](setup_controls.py) | Creates agent, controls, policy, and assigns policy to agent |
| [demo_agent.py](demo_agent.py) | Demo agent using `@control` decorator with server-side policies |
| [update_controls.py](update_controls.py) | Updates controls dynamically (enable/disable SSN blocking) |

## How It Works

### 1. Server-Side Control Definition

Controls are defined on the server with:
- **Scope**: When to check (step types, stages: pre/post)
- **Selector**: What to check (input, output, specific fields)
- **Evaluator**: How to check (regex patterns, list matching, AI-based)
- **Action**: What to do (allow, deny, steer, warn, log)

Example from `setup_controls.py`:
```python
# Regex control to block SSN in output
control_data = ControlDefinition(
description="Block SSN patterns in output",
enabled=True,
execution="server",
scope=ControlScope(step_types=["tool"], stages=["post"]),
selector=ControlSelector(path="output"),
evaluator=EvaluatorConfig(
name="regex",
config={"pattern": r"\b\d{3}-\d{2}-\d{4}\b"}
),
action=ControlAction(decision="deny")
)
```

### 2. Agent Integration

The agent uses the `@control()` decorator which:
- Automatically fetches assigned policy from server
- Evaluates controls before/after function execution
- Blocks violations or allows safe operations

Example from `demo_agent.py`:
```python
import agent_control
from agent_control import control, ControlViolationError

# Initialize and connect to server
agent_control.init(
agent_name="demo-chatbot",
)

# Apply server-side controls
@control()
async def chat(message: str) -> str:
return f"Echo: {message}"

# Handle violations
try:
response = await chat("user input")
except ControlViolationError as e:
print(f"Blocked: {e.message}")
```

### 3. Dynamic Updates

Controls can be updated on the server without code changes:
- Enable/disable controls
- Update patterns and rules
- Change enforcement decisions (deny → warn)
- Add new controls to existing policies

## Configuration

All scripts use the same agent configuration:

```python
AGENT_NAME = "demo-chatbot"
SERVER_URL = os.getenv("AGENT_CONTROL_URL", "http://localhost:8000")
```

Set `AGENT_CONTROL_URL` environment variable to connect to a different server:
```bash
export AGENT_CONTROL_URL=http://your-server:8000
```

## Troubleshooting

### Server Connection Issues

**Error**: `Failed to connect to server`

**Fix**:
```bash
# Check if server is running
curl http://localhost:8000/health

# If not running, start it
cd server && make run
Comment thread
namrataghadi-galileo marked this conversation as resolved.
Outdated
```

### Agent Not Found

**Error**: `Agent not found` when running `demo_agent.py`

**Fix**: Run `setup_controls.py` first to create the agent and controls:
```bash
uv run python examples/agent_control_demo/setup_controls.py
```

### Import Errors

**Error**: `ModuleNotFoundError: No module named 'agent_control'`

**Fix**: Install dependencies from monorepo root:
```bash
cd /path/to/agent-control
Comment thread
namrataghadi-galileo marked this conversation as resolved.
Outdated
make sync
```

## Next Steps

- Explore [CONCEPTS.md](../../CONCEPTS.md) to understand controls, policies, scopes, and evaluators
- Check out [CrewAI example](../crewai/) for multi-agent orchestration with controls
- Read [SDK documentation](../../sdks/python/README.md) for full API reference
- Try [LangChain example](../langchain/) for LangChain integration

## Resources

- [Main Documentation](../../README.md)
- [SDK Documentation](../../sdks/python/README.md)
- [Server Documentation](../../server/README.md)
- [Models Documentation](../../models/README.md)
5 changes: 2 additions & 3 deletions examples/agent_control_demo/demo_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@

# Configuration
AGENT_NAME = "demo-chatbot"
AGENT_ID = "672e50df-af4c-429f-965a-3d7f8262302f"
SERVER_URL = os.getenv("AGENT_CONTROL_URL", "http://localhost:8000")


Expand Down Expand Up @@ -161,8 +160,8 @@ async def run_demo():
try:
logger.info(f"Initializing agent: {AGENT_NAME}")
agent_control.init(
agent_name=AGENT_ID,
agent_description=AGENT_NAME,
agent_name=AGENT_NAME,
agent_description="Demo chatbot for testing controls",
server_url=SERVER_URL,
)
logger.info("Agent initialized successfully")
Expand Down
18 changes: 5 additions & 13 deletions examples/agent_control_demo/setup_controls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import asyncio
import os
import sys
from uuid import UUID

# Add the SDK to path for development
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../sdks/python/src"))
Expand All @@ -33,7 +32,6 @@

# Configuration
AGENT_NAME = "demo-chatbot"
AGENT_ID = "672e50df-af4c-429f-965a-3d7f8262302f"
SERVER_URL = os.getenv("AGENT_CONTROL_URL", "http://localhost:8000")


Expand All @@ -43,15 +41,12 @@ async def create_agent(client: AgentControlClient) -> str:
print("STEP 1: Creating Agent")
print("=" * 60)

# Use the provided UUID for the agent
agent_name = UUID(AGENT_ID)

try:
response = await client.http_client.post(
"/api/v1/agents/initAgent", # Correct endpoint
json={
"agent": {
"agent_name": str(agent_name),
"agent_name": AGENT_NAME,
"agent_description": "Demo chatbot for testing controls",
},
"steps": []
Expand All @@ -67,8 +62,8 @@ async def create_agent(client: AgentControlClient) -> str:
else:
print(f"✓ Agent already exists: {AGENT_NAME}")

print(f" Agent UUID: {agent_name}")
return str(agent_name)
print(f" Agent Name: {AGENT_NAME}")
return AGENT_NAME

except Exception as e:
print(f"✗ Failed to create agent: {e}")
Expand Down Expand Up @@ -352,7 +347,7 @@ async def main():
print("AGENT CONTROL DEMO: Setup Controls")
print("=" * 60)
print(f"\nServer URL: {SERVER_URL}")
print(f"Agent: {AGENT_NAME} ({AGENT_ID})")
print(f"Agent: {AGENT_NAME}")

async with AgentControlClient(base_url=SERVER_URL) as client:
# Check server health
Expand All @@ -365,12 +360,9 @@ async def main():
print(" cd server && make run")
Comment thread
namrataghadi-galileo marked this conversation as resolved.
Outdated
return

# Use the provided UUID for verification
agent_name = AGENT_ID

# If verify-only mode, just run verification
if args.verify_only:
await verify_full_chain(client, agent_name)
await verify_full_chain(client, AGENT_NAME)
return

# 1. Create agent
Expand Down
17 changes: 7 additions & 10 deletions examples/agent_control_demo/update_controls.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from agent_control import AgentControlClient

# Configuration
AGENT_ID = "672e50df-af4c-429f-965a-3d7f8262302f"
AGENT_NAME = "demo-chatbot"
SERVER_URL = os.getenv("AGENT_CONTROL_URL", "http://localhost:8000")


Expand Down Expand Up @@ -154,14 +154,11 @@ async def main():
parser.add_argument("--status", action="store_true", help="Show current status")
args = parser.parse_args()

# Use the provided UUID
agent_name = AGENT_ID

print("\n" + "=" * 60)
print("AGENT CONTROL DEMO: Update Controls")
print("=" * 60)
print(f"\nServer URL: {SERVER_URL}")
print(f"Agent UUID: {agent_name}")
print(f"Agent Name: {AGENT_NAME}")

async with AgentControlClient(base_url=SERVER_URL) as client:
# Check server health
Expand All @@ -174,7 +171,7 @@ async def main():
return

# Find the SSN control
ctrl = await get_control_by_name(client, agent_name, "block-ssn-output")
ctrl = await get_control_by_name(client, AGENT_NAME, "block-ssn-output")
if not ctrl:
print("\n✗ SSN control not found!")
print(" Run setup_controls.py first:")
Expand All @@ -184,16 +181,16 @@ async def main():
control_id = ctrl.get("id")

if args.status:
await show_current_status(client, agent_name)
await show_current_status(client, AGENT_NAME)
elif args.allow_ssn:
await allow_ssn(client, control_id)
await show_current_status(client, agent_name)
await show_current_status(client, AGENT_NAME)
elif args.block_ssn:
await block_ssn(client, control_id)
await show_current_status(client, agent_name)
await show_current_status(client, AGENT_NAME)
else:
# Default: show status and usage
await show_current_status(client, agent_name)
await show_current_status(client, AGENT_NAME)
print("\n" + "=" * 60)
print("Usage")
print("=" * 60)
Expand Down
Loading
Loading