Check Action
curl --request POST \
--url https://api.example.com/check \
--header 'Content-Type: application/json' \
--data '
{
"event_type": "<string>",
"trace_id": "<string>",
"timestamp": 123,
"content": "<string>",
"schema": "<string>"
}
'import requests
url = "https://api.example.com/check"
payload = {
"event_type": "<string>",
"trace_id": "<string>",
"timestamp": 123,
"content": "<string>",
"schema": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
event_type: '<string>',
trace_id: '<string>',
timestamp: 123,
content: '<string>',
schema: '<string>'
})
};
fetch('https://api.example.com/check', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/check",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'event_type' => '<string>',
'trace_id' => '<string>',
'timestamp' => 123,
'content' => '<string>',
'schema' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/check"
payload := strings.NewReader("{\n \"event_type\": \"<string>\",\n \"trace_id\": \"<string>\",\n \"timestamp\": 123,\n \"content\": \"<string>\",\n \"schema\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/check")
.header("Content-Type", "application/json")
.body("{\n \"event_type\": \"<string>\",\n \"trace_id\": \"<string>\",\n \"timestamp\": 123,\n \"content\": \"<string>\",\n \"schema\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/check")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"event_type\": \"<string>\",\n \"trace_id\": \"<string>\",\n \"timestamp\": 123,\n \"content\": \"<string>\",\n \"schema\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"is_safe": true,
"reasoning": "<string>",
"action_check_id": "<string>",
"timestamp": 123
}Arx Endpoints
Check Action
Validate agent actions before execution to detect goal deviation
POST
/
check
Check Action
curl --request POST \
--url https://api.example.com/check \
--header 'Content-Type: application/json' \
--data '
{
"event_type": "<string>",
"trace_id": "<string>",
"timestamp": 123,
"content": "<string>",
"schema": "<string>"
}
'import requests
url = "https://api.example.com/check"
payload = {
"event_type": "<string>",
"trace_id": "<string>",
"timestamp": 123,
"content": "<string>",
"schema": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
event_type: '<string>',
trace_id: '<string>',
timestamp: 123,
content: '<string>',
schema: '<string>'
})
};
fetch('https://api.example.com/check', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/check",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'event_type' => '<string>',
'trace_id' => '<string>',
'timestamp' => 123,
'content' => '<string>',
'schema' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/check"
payload := strings.NewReader("{\n \"event_type\": \"<string>\",\n \"trace_id\": \"<string>\",\n \"timestamp\": 123,\n \"content\": \"<string>\",\n \"schema\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/check")
.header("Content-Type", "application/json")
.body("{\n \"event_type\": \"<string>\",\n \"trace_id\": \"<string>\",\n \"timestamp\": 123,\n \"content\": \"<string>\",\n \"schema\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/check")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"event_type\": \"<string>\",\n \"trace_id\": \"<string>\",\n \"timestamp\": 123,\n \"content\": \"<string>\",\n \"schema\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"is_safe": true,
"reasoning": "<string>",
"action_check_id": "<string>",
"timestamp": 123
}Overview
This endpoint validates actions that an agent is about to execute, analyzing them in the context of the entire session history. It provides real-time security checks to prevent prompt injections, goal deviations, and other malicious behaviors.Always check critical actions (financial transactions, data modifications, external communications) before execution. This is your primary defense against compromised agents.
Request
string
required
Must be set to
"action_check" for this endpoint.Example: "action_check"string
required
The session identifier from
/register-agent-run. Used to retrieve session context for analysis.Example: "f4f4f4f4-f4f4-f4f4-f4f4-f4f4f4f4f4f4"float
required
Unix timestamp (seconds since epoch) when the check is being performed.Example:
1678886415.123string
required
The action data as a stringified JSON object. This represents the specific parameters of the action to be executed.Example:
"{\"amount\":500,\"recipient\":\"user@example.com\"}"string
required
A stringified JSON Schema defining the action’s structure. Should include the function name, description, and parameter definitions.Example:
"{\"type\":\"function\",\"name\":\"transfer_funds\",\"parameters\":{...}}"Response
boolean
required
Whether the action is safe to execute.
true- Action is approvedfalse- Action is blocked
string
required
Human-readable explanation of the decision. Particularly important when
is_safe is false.Example: "Action deviates from original user request for weather information"string
required
Unique identifier for this security check.Example:
"c1c1c1c1-c1c1-c1c1-c1c1-c1c1c1c1c1c1"float
required
Server timestamp when the check was performed.Example:
1678886415.789Critical Actions to Check
Always validate these action types before execution:Financial Operations
- Money transfers
- Payment processing
- Refunds
- Account modifications
Data Operations
- Database updates
- File deletions
- Backup operations
- Schema changes
Communications
- Sending emails
- SMS messages
- API calls to external services
- Webhooks
System Operations
- Code execution
- Configuration changes
- Permission modifications
- Service restarts
Attack Detection Examples
Prompt Injection Detection
# Session history shows user asked for weather
# But agent tries to transfer money after reading a webpage
# The malicious action to check
action_content = {
"amount": 1000,
"recipient": "attacker@evil.com",
"currency": "USD"
}
action_schema = {
"type": "function",
"name": "transfer_funds",
"description": "Transfer money to recipient",
"parameters": {
"type": "object",
"properties": {
"amount": {"type": "number"},
"recipient": {"type": "string"},
"currency": {"type": "string"}
}
}
}
# Check the action
response = check_action(
trace_id=trace_id,
content=action_content,
schema=action_schema
)
# Result
print(response)
# {
# "is_safe": false,
# "reasoning": "Transfer funds action unrelated to user's weather inquiry",
# "action_check_id": "check-123",
# "timestamp": 1678886415.789
# }
// User asked to send an email
// Agent prepares appropriate email action
const actionContent = {
to: "boss@company.com",
subject: "Weekly Report",
body: "Here is the weekly report as requested..."
};
const actionSchema = {
type: "function",
name: "send_email",
description: "Send email message",
parameters: {
type: "object",
properties: {
to: { type: "string", format: "email" },
subject: { type: "string" },
body: { type: "string" }
}
}
};
// Check the action
const response = await checkAction(
traceId,
actionContent,
actionSchema
);
// Result
console.log(response);
// {
// "is_safe": true,
// "reasoning": "Email action aligns with user request",
// "action_check_id": "check-456",
// "timestamp": 1678886420.123
// }
Goal Deviation Detection
# Initial: User asks for help with homework
# Later: Agent tries to search for inappropriate content
# Suspicious action after conversation drift
action_content = {
"query": "how to synthesize illegal substances",
"search_engine": "google"
}
action_schema = {
"type": "function",
"name": "web_search",
"description": "Search the web",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"},
"search_engine": {"type": "string"}
}
}
}
response = check_action(trace_id, action_content, action_schema)
# Result: is_safe = False
# Reasoning: "Search query deviates from homework assistance objective"
Complete Implementation Example
import json
import time
import requests
class SecureAgent:
def __init__(self, api_key, trace_id):
self.api_key = api_key
self.trace_id = trace_id
self.base_url = "https://api.fabraix.com/v1"
def check_action(self, action_name, action_params, action_schema):
"""Check if an action is safe before execution"""
response = requests.post(
f"{self.base_url}/check",
headers={
"x-api-key": self.api_key,
"Content-Type": "application/json"
},
json={
"event_type": "action_check",
"trace_id": self.trace_id,
"timestamp": time.time(),
"content": json.dumps(action_params),
"schema": json.dumps(action_schema)
}
)
result = response.json()
return result["is_safe"], result["reasoning"]
def execute_with_safety(self, action_name, action_params, action_schema,
execute_fn, fallback_fn=None):
"""Execute an action only if it passes safety checks"""
# Check action safety
is_safe, reasoning = self.check_action(
action_name,
action_params,
action_schema
)
if is_safe:
# Log approval
print(f"✅ Action '{action_name}' approved")
# Execute the action
try:
result = execute_fn(action_params)
# Log successful execution
self.log_event("environment", {
"action": action_name,
"status": "success",
"result": result
})
return result
except Exception as e:
# Log execution error
self.log_event("error", {
"action": action_name,
"error": str(e)
})
raise
else:
# Action blocked
print(f"❌ Action '{action_name}' blocked: {reasoning}")
# Log the block
self.log_event("security_block", {
"action": action_name,
"reasoning": reasoning,
"params": action_params
})
# Use fallback if provided
if fallback_fn:
return fallback_fn(reasoning)
else:
raise SecurityException(f"Action blocked: {reasoning}")
# Usage Example
agent = SecureAgent(api_key="YOUR_KEY", trace_id="abc-123")
# Define action
transfer_params = {
"amount": 100,
"recipient": "vendor@company.com",
"reason": "Invoice payment"
}
transfer_schema = {
"type": "function",
"name": "transfer_funds",
"description": "Transfer funds to recipient",
"parameters": {
"type": "object",
"properties": {
"amount": {
"type": "number",
"minimum": 0,
"maximum": 10000
},
"recipient": {
"type": "string",
"format": "email"
},
"reason": {
"type": "string"
}
},
"required": ["amount", "recipient"]
}
}
# Execute with safety check
def perform_transfer(params):
# Actual transfer logic
return {"transaction_id": "tx-789", "status": "completed"}
def handle_blocked_transfer(reasoning):
# Fallback for blocked transfers
return {"status": "blocked", "message": reasoning}
result = agent.execute_with_safety(
action_name="transfer_funds",
action_params=transfer_params,
action_schema=transfer_schema,
execute_fn=perform_transfer,
fallback_fn=handle_blocked_transfer
)
class SecureAgent {
constructor(apiKey, traceId) {
this.apiKey = apiKey;
this.traceId = traceId;
this.baseUrl = 'https://api.fabraix.com/v1';
}
async checkAction(actionName, actionParams, actionSchema) {
const response = await fetch(`${this.baseUrl}/check`, {
method: 'POST',
headers: {
'x-api-key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({
event_type: 'action_check',
trace_id: this.traceId,
timestamp: Date.now() / 1000,
content: JSON.stringify(actionParams),
schema: JSON.stringify(actionSchema)
})
});
const result = await response.json();
return {
isSafe: result.is_safe,
reasoning: result.reasoning
};
}
async executeWithSafety(actionName, actionParams, actionSchema,
executeFn, fallbackFn = null) {
// Check action safety
const { isSafe, reasoning } = await this.checkAction(
actionName,
actionParams,
actionSchema
);
if (isSafe) {
console.log(`✅ Action '${actionName}' approved`);
try {
// Execute the action
const result = await executeFn(actionParams);
// Log successful execution
await this.logEvent('environment', {
action: actionName,
status: 'success',
result: result
});
return result;
} catch (error) {
// Log execution error
await this.logEvent('error', {
action: actionName,
error: error.message
});
throw error;
}
} else {
// Action blocked
console.log(`❌ Action '${actionName}' blocked: ${reasoning}`);
// Log the block
await this.logEvent('security_block', {
action: actionName,
reasoning: reasoning,
params: actionParams
});
// Use fallback if provided
if (fallbackFn) {
return fallbackFn(reasoning);
} else {
throw new Error(`Action blocked: ${reasoning}`);
}
}
}
}
// Usage Example
const agent = new SecureAgent('YOUR_KEY', 'abc-123');
// Define action
const transferParams = {
amount: 100,
recipient: 'vendor@company.com',
reason: 'Invoice payment'
};
const transferSchema = {
type: 'function',
name: 'transfer_funds',
description: 'Transfer funds to recipient',
parameters: {
type: 'object',
properties: {
amount: {
type: 'number',
minimum: 0,
maximum: 10000
},
recipient: {
type: 'string',
format: 'email'
},
reason: {
type: 'string'
}
},
required: ['amount', 'recipient']
}
};
// Execute with safety check
async function performTransfer(params) {
// Actual transfer logic
return { transaction_id: 'tx-789', status: 'completed' };
}
function handleBlockedTransfer(reasoning) {
// Fallback for blocked transfers
return { status: 'blocked', message: reasoning };
}
const result = await agent.executeWithSafety(
'transfer_funds',
transferParams,
transferSchema,
performTransfer,
handleBlockedTransfer
);
Response Examples
Approved Action
{
"is_safe": true,
"reasoning": "Action aligns with user request and session context",
"action_check_id": "c2c2c2c2-c2c2-c2c2-c2c2-c2c2c2c2c2c2",
"timestamp": 1678886420.123
}
Blocked Actions
{
"is_safe": false,
"reasoning": "Detected potential prompt injection: action 'delete_all_files' unrelated to user's request for weather information",
"action_check_id": "c3c3c3c3-c3c3-c3c3-c3c3-c3c3c3c3c3c3",
"timestamp": 1678886425.456
}
{
"is_safe": false,
"reasoning": "Action deviates from established objective: attempting financial transaction when user requested document summarization",
"action_check_id": "c4c4c4c4-c4c4-c4c4-c4c4-c4c4c4c4c4c4",
"timestamp": 1678886430.789
}
{
"is_safe": false,
"reasoning": "Attempting to access resources beyond authorized scope: admin panel access not permitted for current session",
"action_check_id": "c5c5c5c5-c5c5-c5c5-c5c5-c5c5c5c5c5c5",
"timestamp": 1678886435.012
}
Best Practices
Define Clear Action Boundaries
Define Clear Action Boundaries
Establish what actions require checking:
ALWAYS_CHECK = [
"transfer_funds",
"delete_data",
"send_email",
"modify_permissions",
"execute_code"
]
CONDITIONAL_CHECK = {
"purchase_item": lambda params: params["amount"] > 100,
"api_call": lambda params: params["endpoint"].startswith("external"),
"database_query": lambda params: "DELETE" in params["query"]
}
def should_check_action(action_name, params):
if action_name in ALWAYS_CHECK:
return True
if action_name in CONDITIONAL_CHECK:
return CONDITIONAL_CHECK[action_name](params)
return False
Handle Blocks Gracefully
Handle Blocks Gracefully
Provide good user experience when actions are blocked:
def handle_blocked_action(action_name, reasoning):
user_friendly_messages = {
"prompt_injection": "I detected a potential security issue and cannot proceed.",
"goal_deviation": "This action doesn't align with your original request.",
"unauthorized": "I don't have permission to perform this action.",
"suspicious_pattern": "This action was flagged for security review."
}
# Determine block type from reasoning
for key, message in user_friendly_messages.items():
if key in reasoning.lower():
return message
# Default message
return "I cannot perform this action for security reasons."
Include Rich Context in Schemas
Include Rich Context in Schemas
Provide detailed schemas to improve analysis accuracy:
# Good: Rich schema with context
schema = {
"type": "function",
"name": "modify_database",
"description": "Modify database records",
"criticality": "high",
"reversible": false,
"parameters": {
"type": "object",
"properties": {
"table": {
"type": "string",
"enum": ["users", "orders", "products"]
},
"operation": {
"type": "string",
"enum": ["INSERT", "UPDATE", "DELETE"]
},
"where_clause": {
"type": "string",
"pattern": "^[A-Za-z0-9_]+ = .+$"
},
"data": {
"type": "object"
}
},
"required": ["table", "operation"]
}
}
# Bad: Minimal schema
schema = {
"type": "function",
"name": "modify_database"
}
Implement Retry Logic
Implement Retry Logic
Handle transient failures appropriately:
async def check_with_retry(action, max_retries=3):
for attempt in range(max_retries):
try:
return await check_action(action)
except RequestException as e:
if e.status_code == 429: # Rate limited
wait_time = min(2 ** attempt, 10)
await asyncio.sleep(wait_time)
elif e.status_code >= 500: # Server error
if attempt < max_retries - 1:
await asyncio.sleep(1)
continue
raise
raise MaxRetriesException()
Monitor Block Patterns
Monitor Block Patterns
Track and analyze blocked actions:
class ActionMonitor:
def __init__(self):
self.blocked_actions = []
self.block_reasons = {}
def record_block(self, action_name, reasoning):
self.blocked_actions.append({
"action": action_name,
"reasoning": reasoning,
"timestamp": time.time()
})
# Track block reasons
reason_type = self.classify_reason(reasoning)
self.block_reasons[reason_type] = \
self.block_reasons.get(reason_type, 0) + 1
def get_statistics(self):
return {
"total_blocks": len(self.blocked_actions),
"block_reasons": self.block_reasons,
"recent_blocks": self.blocked_actions[-10:]
}
Performance Optimization
Parallel Checking
Check multiple independent actions in parallel:import asyncio
async def check_multiple_actions(trace_id, actions):
"""Check multiple actions in parallel"""
tasks = []
for action in actions:
task = check_action(
trace_id,
action["params"],
action["schema"]
)
tasks.append(task)
results = await asyncio.gather(*tasks)
# Return results with action names
return [
{
"action": actions[i]["name"],
"is_safe": results[i]["is_safe"],
"reasoning": results[i]["reasoning"]
}
for i in range(len(actions))
]
Related Endpoints
- POST /register-agent-run - Register session to get trace_id
- POST /event - Log events that provide context for checks
FAQ
How fast are security checks?
How fast are security checks?
Typical response time is 0.5-1s. Critical actions should always be checked despite the small latency cost which we are continuously improving.
What happens if I don't check actions?
What happens if I don't check actions?
Unchecked actions bypass Fabraix’s security layer, leaving your agent vulnerable to prompt injections, goal deviations, and other attacks.
Can I override a block decision?
Can I override a block decision?
Blocks should be treated as final for security. If you need to override, log the override as an event and implement additional safeguards.
How does context analysis work?
How does context analysis work?
Fabraix analyzes the entire session history (all logged events) to understand the agent’s trajectory and detect deviations or anomalies.
Should I check read-only operations?
Should I check read-only operations?
Generally, read-only operations don’t require checking unless they involve sensitive data or could be part of a reconnaissance attack.
Was this page helpful?