Skip to content

Commit 5ccdbd0

Browse files
authored
fix(sdk): enforce UUID agent IDs (#9)
* fix(sdk): enforce UUID agent IDs Validate agent_id as UUID in SDK (fail fast) and remove UUID5 fallback so server conflicts surface. Update docs/examples/tests/UI fixtures to use UUIDs and add validation test. * fix(tests): avoid init agent UUID conflicts Use unique init agent names in SDK integration tests and let ruff normalize import order after UUID validation changes. * test(sdk): add UUID validation coverage Add unit and behavioral tests for UUID validation helpers, fail-fast SDK agent_id handling, and init() conflict surfacing to improve coverage of the new UUID enforcement. * Fix ui ci
1 parent 9dd3dd7 commit 5ccdbd0

30 files changed

Lines changed: 305 additions & 98 deletions

‎docs/REFERENCE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ import agent_control
501501

502502
agent_control.init(
503503
agent_name="my-agent", # Required: human-readable name
504-
agent_id="my-agent-v1", # Required: unique identifier
504+
agent_id="550e8400-e29b-41d4-a716-446655440000", # Required: UUID
505505
server_url="http://localhost:8000", # Optional: defaults to env var
506506
steps=[ # Optional: register available steps
507507
{

‎examples/README.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ import agent_control
9292
from agent_control import control, ControlViolationError
9393

9494
# Initialize agent (connects to server, loads policy)
95-
agent_control.init(agent_name="my-bot", agent_id="bot-123")
95+
agent_control.init(
96+
agent_name="my-bot",
97+
agent_id="550e8400-e29b-41d4-a716-446655440000",
98+
)
9699

97100
# Apply the agent's assigned policy
98101
@control()

‎examples/agent_control_demo/demo_agent.py‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

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

5050

@@ -258,4 +258,3 @@ async def run_demo():
258258

259259
if __name__ == "__main__":
260260
asyncio.run(run_demo())
261-

‎examples/agent_control_demo/setup_controls.py‎

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

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

4040

@@ -44,9 +44,8 @@ async def create_agent(client: AgentControlClient) -> str:
4444
print("STEP 1: Creating Agent")
4545
print("=" * 60)
4646

47-
# Generate a deterministic UUID from the agent ID
48-
import uuid
49-
agent_uuid = uuid.uuid5(uuid.NAMESPACE_DNS, AGENT_ID)
47+
# Use the provided UUID for the agent
48+
agent_uuid = UUID(AGENT_ID)
5049

5150
try:
5251
response = await client.http_client.post(
@@ -440,9 +439,8 @@ async def main():
440439
print(" cd server && make run")
441440
return
442441

443-
# Generate agent UUID
444-
import uuid
445-
agent_uuid = str(uuid.uuid5(uuid.NAMESPACE_DNS, AGENT_ID))
442+
# Use the provided UUID for verification
443+
agent_uuid = AGENT_ID
446444

447445
# If verify-only mode, just run verification
448446
if args.verify_only:

‎examples/agent_control_demo/update_controls.py‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@
1919
import asyncio
2020
import os
2121
import sys
22-
import uuid
23-
2422
# Add the SDK to path for development
2523
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../sdks/python/src"))
2624

2725
from agent_control import AgentControlClient
2826

2927
# Configuration
30-
AGENT_ID = "demo-chatbot-v1"
28+
AGENT_ID = "672e50df-af4c-429f-965a-3d7f8262302f"
3129
SERVER_URL = os.getenv("AGENT_CONTROL_URL", "http://localhost:8000")
3230

3331

@@ -156,8 +154,8 @@ async def main():
156154
parser.add_argument("--status", action="store_true", help="Show current status")
157155
args = parser.parse_args()
158156

159-
# Generate agent UUID
160-
agent_uuid = str(uuid.uuid5(uuid.NAMESPACE_DNS, AGENT_ID))
157+
# Use the provided UUID
158+
agent_uuid = AGENT_ID
161159

162160
print("\n" + "=" * 60)
163161
print("AGENT CONTROL DEMO: Update Controls")

‎examples/crewai/content_agent_protection.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
# It's a dependency of agent_control so should be available
4646

4747
# --- Configuration ---
48-
AGENT_ID = "support-crew-demo"
48+
AGENT_ID = "989d84f0-9afe-4fb2-9e9e-e9d076271e29"
4949
AGENT_NAME = "Customer Support Crew"
5050
AGENT_DESCRIPTION = "Customer support crew with PII protection and access controls"
5151

‎examples/crewai/setup_content_controls.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@
1010

1111
import asyncio
1212
import os
13-
import uuid
13+
from uuid import UUID
1414

1515
from agent_control import Agent, AgentControlClient, agents, controls, policies
1616

17-
AGENT_ID = "support-crew-demo"
17+
AGENT_ID = "989d84f0-9afe-4fb2-9e9e-e9d076271e29"
1818
SERVER_URL = os.getenv("AGENT_CONTROL_URL", "http://localhost:8000")
1919

2020

2121
async def setup_content_controls():
2222
"""Create PII protection and unauthorized access controls, policy, and assign to agent."""
2323
async with AgentControlClient(base_url=SERVER_URL) as client:
2424
# 1. Register Agent
25-
agent_uuid = uuid.uuid5(uuid.NAMESPACE_DNS, AGENT_ID)
25+
agent_uuid = UUID(AGENT_ID)
2626

2727
agent = Agent(
2828
agent_id=agent_uuid,

‎examples/customer_support_agent/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ import agent_control
161161

162162
agent_control.init(
163163
agent_name="Customer Support Agent",
164-
agent_id="customer-support-agent",
164+
agent_id="646d5dea-c2e6-4453-b446-7035482b38e4",
165165
agent_description="AI-powered customer support assistant",
166166
)
167167
```

‎examples/customer_support_agent/demo.sh‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,9 @@ setup_demo_controls() {
222222
python setup_demo_controls.py
223223
}
224224

225-
# Generate UUID5 from agent ID (matches Python's uuid.uuid5(uuid.NAMESPACE_DNS, agent_id))
225+
# Agent UUID used by the demo (must match support_agent.py)
226226
get_agent_uuid() {
227-
python3 -c "import uuid; print(uuid.uuid5(uuid.NAMESPACE_DNS, 'customer-support-agent'))"
227+
echo "646d5dea-c2e6-4453-b446-7035482b38e4"
228228
}
229229

230230
show_observability_stats() {

‎examples/customer_support_agent/run_demo.py‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,13 @@
5454
# Add parent directory to path for imports
5555
sys.path.insert(0, str(__file__).rsplit("/", 2)[0])
5656

57-
# Agent ID used in support_agent.py
58-
AGENT_ID = "customer-support-agent"
57+
# Agent UUID used in support_agent.py
58+
AGENT_ID = "646d5dea-c2e6-4453-b446-7035482b38e4"
5959

6060

6161
async def reset_agent():
6262
"""Reset the agent by removing its policy (which disconnects all controls)."""
63-
import uuid
64-
65-
# Generate the same UUID5 that the SDK generates
66-
agent_uuid = str(uuid.uuid5(uuid.NAMESPACE_DNS, AGENT_ID))
63+
agent_uuid = AGENT_ID
6764
server_url = os.getenv("AGENT_CONTROL_URL", "http://localhost:8000")
6865

6966
logger.info(f"Resetting agent '{AGENT_ID}' (UUID: {agent_uuid})")

0 commit comments

Comments
 (0)