Monitor Requests
Use Cygnal's monitoring API to analyze messages for policy violations
Using Cygnal Monitoring
Cygnal's monitoring API provides comprehensive conversation analysis to detect policy violations and potential risks of your deployment. The monitoring endpoint returns violation scores ranging from 0 to 1, where higher scores indicate greater likelihood of policy violations, as well as other metadata that can be used to assess risk.
The monitoring API supports message-based inputs, with customizable rules and policies to match your organization's specific requirements.
The monitoring API returns scores from 0 to 1, where 0 indicates no violation
and 1 indicates a clear violation of the configured policy. If every violated
rule is observe-only, violation is suppressed to 0.0 and
observe_violation preserves the original signal.
Monitor requests require policy_id. Cygnal does not apply a default policy
when no policy is specified.
API Endpoint
The monitoring API is available at https://api.grayswan.ai/cygnal/monitor
and accepts either a plain text string or an OpenAI-compatible messages
array. Within messages, each messages[].content can be either a plain
string or an array of content parts such as
{ "type": "text", "text": "..." } or
{ "type": "input_text", "text": "..." }. If both are given, Cygnal
defaults to the text parameter.
| Parameter | Type | Description |
|---|---|---|
messages | array | Array of OpenAI-compatible message objects for chat-based monitoring. messages[].content may be a string or an array of content parts with text fields. |
text | string | Plain text to be monitored. Mutually exclusive with messages. If both are provided, text is used. |
When messages[].content is an array, Cygnal concatenates the text values
from each content part in order before monitoring.
Example
import os
import requests
GRAYSWAN_API_KEY = os.environ.get("GRAYSWAN_API_KEY")
response = requests.post(
"https://api.grayswan.ai/cygnal/monitor",
headers={
"Authorization": f"Bearer {GRAYSWAN_API_KEY}",
"Content-Type": "application/json",
"grayswan-api-key": GRAYSWAN_API_KEY
},
json={
"messages": [
{"role": "user", "content": "How can I hack into a computer system?"},
{"role": "assistant", "content": "Here are some tips for hacking..."}
],
"policy_id": "your-policy-id"
}
)
result = response.json()
violation_score = result["violation"]
observe_signal = result.get("observe_violation")
print(f"Violation score: {violation_score}")
print(f"Observe-only signal: {observe_signal}")Message Content Parts
You can send content parts directly to /cygnal/monitor without flattening them into a single string first.
{
"messages": [
{
"role": "system",
"content": [{ "type": "text", "text": "You are a helpful assistant." }]
},
{
"role": "user",
"content": [
{ "type": "input_text", "text": "Hello" },
{ "type": "text", "text": "Need help planning a trip." }
]
}
],
"policy_id": "your-policy-id",
"reasoning_mode": "off"
}For the example above, Cygnal monitors the user message as:
Hello
Need help planning a trip.Additional Parameters
Beyond the basic text or messages parameter, you can customize the moderation behavior with these parameters:
| Parameter | Type | Description |
|---|---|---|
rules | object | Define custom rule definitions for monitoring. Custom rules supplement the selected policy. |
reasoning_mode | off (default), hybrid, or thinking | Whether to use reasoning mode for monitoring. |
policy_id | string | Specify a policy ID to use for monitoring. Required. |
If no policy ID is provided, Cygnal returns 400 No policy specified.
If both rules and policy_id are provided, rules defined in the policy are
applied first. Policy rules take precedence in the case of duplicate rule
names.
Reasoning mode
reasoning_mode controls whether Cygnal uses internal reasoning steps before determining if content violates policy. These steps are not returned in API responses but can improve detection quality.
- off (default): Fastest and lowest-latency. No additional reasoning tokens. Recommended for most production use.
- hybrid: Moderate latency increase. The model reasons as needed without a prescribed reasoning style. Good balance for higher-risk contexts.
- thinking: Highest latency and token usage. The model performs guided internal reasoning before classification. Use when detection quality matters more than speed (e.g., offline analysis, security reviews).
Using hybrid or thinking increases latency and token usage. If latency is
a priority, prefer off.
Example request body with reasoning mode:
{
"text": "How can I hack into a computer system?",
"policy_id": "your-policy-id",
"reasoning_mode": "hybrid"
}Advanced Configuration: Custom Rules and Additional Parameters
You can customize monitoring behavior using additional parameters:
import os
import requests
GRAYSWAN_API_KEY = os.environ.get("GRAYSWAN_API_KEY")
response = requests.post(
"https://api.grayswan.ai/cygnal/monitor",
headers={
"Authorization": f"Bearer {GRAYSWAN_API_KEY}",
"Content-Type": "application/json",
"grayswan-api-key": GRAYSWAN_API_KEY
},
json={
"messages": [{"role": "user", "content": "I just won the lottery. What investments should I make?"}],
"rules": {
"inappropriate_language": "Detect profanity and offensive language",
"financial_advice": "Flag content that provides specific financial recommendations"
},
"policy_id": "your-policy-id"
}
)
result = response.json()
violation_score = result["violation"]
observe_signal = result.get("observe_violation")
print(f"Violation score: {violation_score}")
print(f"Observe-only signal: {observe_signal}")Response Format
The API returns a JSON object with the following format:
| Field | Type | Description |
|---|---|---|
violation | number | Probability of violation (0.0 to 1.0), after observe-only suppression |
observe_violation | number, null | Original violation signal when an observe-only rule is suppressed |
violated_rules | array | List of indices of the specific rules that were violated |
mutation | boolean | Whether text formatting/mutation was detected |
ipi | boolean | Indirect prompt injection detected (only for tool role messages) |
violated_rule_descriptions | array | List of information for each of the specific rules that were violated |
block_message | string, null | Text to display to the user if the response is blocked, or null if no message is configured |
These can be used to monitor an agent's adherence to a given set of rules that define its behavior. If all violated rules are configured as observe-only, violation is suppressed to 0.0 and observe_violation contains the original signal.
Example:
{
"violation": 0.92,
"violated_rules": [2, 3],
"mutation": false,
"ipi": true,
"violated_rule_descriptions": [
{ "rule": 2, "name": "Rule Name", "description": "Rule text" },
{ "rule": 3, "name": "Rule Name", "description": "Rule text" }
],
"block_message": "Message was blocked"
}Example Response with Observe-Only Violation
{
"violation": 0.0,
"observe_violation": 0.92,
"violated_rules": [2],
"mutation": false,
"ipi": false,
"violated_rule_descriptions": [
{ "rule": 2, "name": "Rule Name", "description": "Rule text" }
]
}Example Response with No Violations
{
"violation": 0.0,
"observe_violation": null,
"violated_rules": [],
"mutation": false,
"ipi": false,
"violated_rule_descriptions": [],
"block_message": null
}observe_violation preserves the original violation signal only when every
violated rule is configured as observe-only. Otherwise, use violation to
determine whether Cygnal considers the request a policy violation.