Agent Observability Standard
The Agent Observability Standard (AOS) provides specification for building trustworthy agents. Agents that implement AOS can be deployed with higher trust. They are instrumentable, traceable and inspectable. They are an open book
They have a dynamic bill-of-material, a clear audit trail and hard inline-controls.
Trustworthiness of agents builds upon the foundation of existing standards (MCP and A2A), but provides value regardless. It build upon cybersecurity and observability standards including OpenTelemetry, OCSF, CycloneDX, SPDX and SWID.
AOS makes agents trustworthy.
Work in progress
This page is currently under development.
Want to contribute? Check out the GitHub issue and join the discussion!
Trustworthy agents are
Init agent with AOS
from langchain.agents import initialize_agent, Tool
from langchain.llms import OpenAI
from aos import AOSInstrument
# Initialize LLM and tools
llm = OpenAI(temperature=0)
tools = [
Tool(
name="Search",
func=search_api,
description="Search the web for information"
),
Tool(
name="Calculator",
func=calculate,
description="Perform mathematical calculations"
)
]
# Create agent with AOS instrumentation
agent = initialize_agent(
tools,
llm,
agent="zero-shot-react-description",
verbose=True
)
# Wrap with AOS for observability
aos_agent = AOSInstrument(agent)
import { createAgent } from '@vercel/ai'
import { AOSInstrument } from '@aos/sdk'
// Define tools
const tools = {
search: {
description: 'Search the web for information',
parameters: z.object({
query: z.string()
}),
execute: async ({ query }) => searchAPI(query)
},
calculate: {
description: 'Perform mathematical calculations',
parameters: z.object({
expression: z.string()
}),
execute: async ({ expression }) => evaluate(expression)
}
}
// Create agent with AOS instrumentation
const agent = createAgent({
model: 'gpt-4',
tools,
system: 'You are a helpful assistant'
})
const aosAgent = new AOSInstrument(agent)
{
"jsonrpc": "2.0",
"method": "agent/create",
"params": {
"name": "research-assistant",
"capabilities": {
"tools": ["search", "calculate"],
"models": ["claude-3-opus"],
"protocols": ["mcp", "aos"]
},
"aos": {
"instrumentation": {
"enabled": true,
"hooks": ["agentTrigger", "toolCallRequest", "message"]
},
"trace": {
"format": "opentelemetry",
"endpoint": "https://observability.example.com/v1/traces"
}
}
}
}
# Agent manifest with AOS capabilities
apiVersion: a2a.io/v1
kind: Agent
metadata:
name: research-assistant
namespace: production
spec:
model:
provider: anthropic
name: claude-3-opus
capabilities:
- search
- calculate
observability:
aos:
version: "1.0"
instrumentation:
hooks:
- agentTrigger
- toolCallRequest
- message
trace:
provider: opentelemetry
endpoint: https://telemetry.example.com
inspect:
format: cyclonedx
dynamic: true
Instrumentable
Runtime Hooks
Value: Hooks to agent runtime and lifecycle events.
Description: Specifies hooks that allow intervention at agent's lifecycle and run-time execution.
Standards: AOS Instrument.
from aos import GuardianAgent, PolicyResponse
# Create a Guardian Agent to enforce policies
guardian = GuardianAgent(
endpoint="https://guardian.example.com",
policies=["data-protection", "cost-control"]
)
# Hook into agent runtime
@aos_agent.hook("toolCallRequest")
async def on_tool_call(context):
# Guardian evaluates the tool call
response = await guardian.evaluate({
"hook": "toolCallRequest",
"tool": context.tool_name,
"parameters": context.parameters,
"session": context.session_id
})
if response.action == "DENY":
raise PermissionError(f"Tool call denied: {response.reason}")
elif response.action == "MODIFY":
# Apply Guardian's modifications
context.parameters = response.modifications
return response
# Example: Guardian denies sensitive data access
result = await aos_agent.run("Search for employee SSN records")
# > PermissionError: Tool call denied: Accessing PII data violates policy
import { GuardianAgent, HookContext } from '@aos/guardian'
// Configure Guardian Agent
const guardian = new GuardianAgent({
endpoint: 'https://guardian.example.com',
policies: ['data-protection', 'cost-control']
})
// Register hooks for runtime control
aosAgent.registerHook('toolCallRequest', async (context: HookContext) => {
const response = await guardian.evaluate({
hook: 'toolCallRequest',
tool: context.toolName,
parameters: context.parameters,
session: context.sessionId
})
switch (response.action) {
case 'DENY':
throw new Error(`Denied: ${response.reason}`)
case 'MODIFY':
context.parameters = response.modifications
break
}
return response
})
// Example: Cost control policy in action
await aosAgent.run('Generate 1000 images using DALL-E')
// > Error: Denied: Request exceeds cost threshold ($50 limit)
{
"jsonrpc": "2.0",
"method": "aos/registerHook",
"params": {
"hook": "toolCallRequest",
"guardianEndpoint": "https://guardian.example.com/evaluate",
"policies": ["data-protection", "cost-control"]
}
}
// Example hook evaluation request from Guardian
{
"jsonrpc": "2.0",
"method": "guardian/evaluate",
"params": {
"hook": "toolCallRequest",
"context": {
"tool": "database_query",
"parameters": {
"query": "SELECT * FROM customers"
},
"session": "sess_123"
}
}
}
// Guardian response
{
"jsonrpc": "2.0",
"result": {
"action": "MODIFY",
"modifications": {
"query": "SELECT id, name FROM customers LIMIT 100"
},
"reason": "Limited query to prevent full data exposure"
}
}
# Available AOS hooks for instrumentation
agentTrigger:
description: Fires when agent starts processing
can_modify: true
can_deny: true
message:
description: Fires for each message in conversation
can_modify: true
can_deny: true
toolCallRequest:
description: Fires before tool execution
can_modify: true
can_deny: true
knowledgeRetrieval:
description: Fires when accessing knowledge bases
can_modify: false
can_deny: true
memoryStore:
description: Fires when storing to memory
can_modify: true
can_deny: true
Traceable
Comprehensive Audit Logs
Value: Comprehensive audit logs.
Description: Specifies events that capture AI agent lifecycle and runtime execution. Extends OpenTelemetry and OCSF specs with these properties.
Standards: AOS Trace. Extends OpenTelemetry, OCSF.
from opentelemetry import trace
from aos.trace import AOSTraceProvider
# Configure OpenTelemetry with AOS extensions
tracer = trace.get_tracer(
"research-assistant",
provider=AOSTraceProvider()
)
# Agent execution with automatic tracing
with tracer.start_as_current_span("agent_session") as span:
span.set_attribute("aos.session.id", "sess_123")
span.set_attribute("aos.agent.name", "research-assistant")
result = await aos_agent.run("Find recent AI safety papers")
# Trace output includes:
# - Complete reasoning chain
# - Tool calls with parameters
# - Model interactions
# - Decision points
{
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"spanId": "00f067aa0ba902b7",
"operationName": "agent_session",
"startTime": "2024-01-15T10:30:00Z",
"attributes": {
"aos.session.id": "sess_123",
"aos.agent.name": "research-assistant",
"aos.reasoning.steps": 3,
"aos.tools.called": ["web-search", "summarize"]
},
"events": [
{
"name": "aos.step.reasoning",
"timestamp": "2024-01-15T10:30:01Z",
"attributes": {
"thought": "Need to search for recent AI safety papers",
"action": "tool_call",
"tool": "web-search"
}
}
]
}
import { OpenTelemetryTracer } from '@aos/trace'
// Configure tracing for TypeScript agent
const tracer = new OpenTelemetryTracer({
serviceName: 'research-assistant',
endpoint: 'https://telemetry.example.com'
})
// Wrap agent with tracing
const tracedAgent = tracer.instrument(aosAgent)
// Execute with automatic tracing
const result = await tracedAgent.run('Find recent AI safety papers')
// Trace includes same comprehensive data as Python example
{
"jsonrpc": "2.0",
"method": "aos/trace/emit",
"params": {
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"spanId": "00f067aa0ba902b7",
"event": {
"type": "agent.execution",
"timestamp": "2024-01-15T10:30:00Z",
"attributes": {
"session.id": "sess_123",
"agent.name": "research-assistant",
"reasoning.steps": 3,
"tools.called": ["web-search", "summarize"]
}
}
}
}
# A2A trace event
apiVersion: a2a.io/v1
kind: TraceEvent
metadata:
traceId: "4bf92f3577b34da6a3ce929d0e0e4736"
spanId: "00f067aa0ba902b7"
timestamp: "2024-01-15T10:30:00Z"
spec:
eventType: agent.execution
agent:
name: research-assistant
session: sess_123
execution:
reasoningSteps: 3
toolsCalled:
- web-search
- summarize
observability:
format: opentelemetry
endpoint: https://telemetry.example.com
from aos.trace import OCSFLogger
# Configure OCSF security event logging
security_logger = OCSFLogger(
endpoint="https://siem.example.com/ocsf",
api_key="your-api-key"
)
# Attach to agent for security events
aos_agent.attach_logger(security_logger)
# Execute agent - security events logged automatically
result = await aos_agent.run("Access customer database")
{
"activity_id": 1,
"activity_name": "Agent Execution",
"category_uid": 3,
"category_name": "Application Activity",
"class_uid": 3001,
"class_name": "AI Agent Activity",
"severity_id": 1,
"time": 1705318200,
"metadata": {
"version": "1.0.0",
"product": {
"name": "AOS Agent",
"vendor_name": "Example Corp"
}
},
"actor": {
"session": {
"uid": "sess_123",
"created_time": 1705318200
},
"idp": {
"name": "research-assistant",
"uid": "agent_456"
}
},
"aos_extensions": {
"reasoning_chain": [
{
"step": 1,
"thought": "User wants database access",
"action": "evaluate_permissions"
}
],
"tools_invoked": ["database_query"],
"data_accessed": ["customers.personal_info"],
"risk_score": 8.5
}
}
import { AOSTraceStream } from '@aos/trace'
// Stream trace events in real-time
const traceStream = new AOSTraceStream(aosAgent)
traceStream.on('event', (event) => {
// Log to your observability platform
console.log(`[${event.timestamp}] ${event.type}:`, event.data)
// Send to security monitoring
if (event.severity === 'high') {
alertSecurityTeam(event)
}
})
// Enable streaming
await traceStream.start()
// Example output during agent execution:
// [2024-01-15T10:30:01Z] session.start: {id: 'sess_789', user: 'alice'}
// [2024-01-15T10:30:02Z] reasoning.step: {thought: 'Analyzing request...'}
// [2024-01-15T10:30:03Z] tool.call: {name: 'database_query', risk: 'high'}
// [2024-01-15T10:30:04Z] security.alert: {reason: 'Sensitive data access'}
Inspectable
Agent Bill of Materials (AgBOM)
Value: Dynamic agent-aware bill-of-material.
Description: Specifies properties that capture tools, models and capabilities of an AI agent. Extends SBOM standard specs with these properties – AgBOM. Goes further to add dynamic updates to AgBOM to account for dynamic agent capability discovery.
Standards: AOS Inspect. Extends CycloneDX, SPDX, SWID.
from aos.inspect import generate_agbom
# Generate Agent Bill of Materials in CycloneDX format
agbom = generate_agbom(aos_agent, format="cyclonedx")
print(agbom.to_json(indent=2))
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"version": 1,
"metadata": {
"timestamp": "2024-01-15T10:30:00Z",
"component": {
"type": "ai-agent",
"name": "research-assistant",
"version": "1.0.0"
}
},
"components": [
{
"type": "ai-model",
"name": "gpt-4",
"version": "2024-01-01",
"supplier": "OpenAI",
"properties": [
{"name": "parameters", "value": "175B"},
{"name": "context_window", "value": "128000"}
]
},
{
"type": "tool",
"name": "web-search",
"version": "2.1.0",
"description": "Search the web for information"
}
]
}
{
"jsonrpc": "2.0",
"method": "aos/agbom/generate",
"params": {
"format": "cyclonedx",
"agent_id": "research-assistant"
}
}
// Response
{
"jsonrpc": "2.0",
"result": {
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"version": 1,
"metadata": {
"timestamp": "2024-01-15T10:30:00Z",
"component": {
"type": "ai-agent",
"name": "research-assistant",
"version": "1.0.0"
}
},
"components": [
{
"type": "ai-model",
"name": "claude-3-opus",
"version": "2024-01-01",
"supplier": "Anthropic"
}
]
}
}
# Request AgBOM via A2A
apiVersion: a2a.io/v1
kind: AgBOMRequest
metadata:
name: research-assistant-agbom
spec:
agent: research-assistant
format: cyclonedx
includeRuntime: true
---
# Response
apiVersion: a2a.io/v1
kind: AgBOM
metadata:
name: research-assistant-agbom
timestamp: "2024-01-15T10:30:00Z"
spec:
format: cyclonedx
version: "1.0.0"
components:
- type: ai-agent
name: research-assistant
models:
- name: claude-3-opus
version: "2024-01-01"
supplier: Anthropic
tools:
- name: web-search
version: "2.1.0"
from aos.inspect import generate_agbom
# Generate Agent Bill of Materials in SPDX format
agbom = generate_agbom(aos_agent, format="spdx")
print(agbom.to_string())
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: research-assistant-agbom
DocumentNamespace: https://example.com/agbom/research-assistant
Creator: Tool: aos-sdk-1.0
Created: 2024-01-15T10:30:00Z
# Package: AI Agent
PackageName: research-assistant
SPDXID: SPDXRef-Agent
PackageVersion: 1.0.0
PackageSupplier: Organization: Example Corp
PackageDownloadLocation: NOASSERTION
# AI Model Component
PackageName: gpt-4
SPDXID: SPDXRef-Model-GPT4
PackageVersion: 2024-01-01
PackageSupplier: Organization: OpenAI
PackageProperty: ModelParameters: 175B
PackageProperty: ContextWindow: 128000
# Tool Component
PackageName: web-search
SPDXID: SPDXRef-Tool-WebSearch
PackageVersion: 2.1.0
PackageDescription: Search the web for information
from aos.inspect import DynamicAgBOM
import asyncio
# Enable dynamic AgBOM updates
dynamic_agbom = DynamicAgBOM(aos_agent)
# Subscribe to capability changes
@dynamic_agbom.on_update
async def on_capability_change(event):
print(f"Agent capability changed: {event.change_type}")
print(f"Component: {event.component}")
# Automatically update AgBOM
new_agbom = await dynamic_agbom.regenerate()
# Notify security systems
await notify_security_team(new_agbom)
# Example: Agent discovers new tool at runtime
await aos_agent.run("I need to analyze this PDF document")
# Output:
# Agent capability changed: COMPONENT_ADDED
# Component: {"type": "tool", "name": "pdf-analyzer", "version": "1.2.0"}
#
# New component automatically added to AgBOM
import { DynamicAgBOM, AgBOMEvent } from '@aos/inspect'
// Create dynamic AgBOM monitor
const dynamicAgBOM = new DynamicAgBOM(aosAgent)
// Listen for capability changes
dynamicAgBOM.on('update', async (event: AgBOMEvent) => {
console.log(`Capability ${event.changeType}: ${event.component.name}`)
// Get updated AgBOM
const currentAgBOM = await dynamicAgBOM.getCurrent()
// Validate against policies
const validation = await validateAgainstPolicy(currentAgBOM)
if (!validation.approved) {
// Disable unapproved capability
await aosAgent.disableComponent(event.component.id)
console.warn(`Disabled unapproved component: ${event.component.name}`)
}
})
// Example output when agent adds new model:
// Capability ADDED: claude-3-opus
// Validating against policy...
// Component approved and active