analyze() returns. The shape is the same
whether you call the HTTP endpoint, the Python SDK, or the TypeScript
SDK; the SDKs add a small ergonomic layer on top.
High-level shape
sdk/openapi/openapi.json;
the auto-rendered API reference is the
authoritative source.
Top-level fields
SDK ergonomics
The SDKs unpack the body into aDecision object:
blocked_by / blockedBy is the easiest lever for branching in
application code:
adversarial_detection_analyzer) to
canonical names (prompt-injection-jailbreak) so your code stays
stable even if the server-side key flips later. See
Versioning.
Per-analyzer blocks
Every analyzer reports its result inanalyzer_results.<server_key>.
The shape is consistent across analyzers:
Skipped analyzers carry only
status: "SKIPPED" — they were declared
in the policy but never reached because an earlier analyzer
terminated.
Example: an inbound block by the prompt-injection classifier
0.97 on INJECTION/JAILBREAK, which crossed
both the score threshold (>= 0.85) and the output match in
default-inbound. The execution engine terminated immediately and
flipped overall_status to TERMINATED_EARLY. The remaining
analyzers were skipped.
Example: outbound flag by safety + SDP
is_safe boolean rule terminated the run.
Errors at the analyzer level
A single analyzer error does not always mean the whole call errored. Behavior depends on the step type:- In a sequential step, the first analyzer that errors stops the
step and flips
overall_statustoERROR. - In an asynchronous step, every analyzer in the group still runs
to completion. Any error in the group flips
overall_statustoERROR, but you’ll see the other analyzers’ results too.
overall_status == "ERROR" and the cause is upstream
infrastructure (model service unreachable, DLP API down), the API
response is HTTP 503 with code: "analyzer_unavailable" instead of
a 200 with embedded errors. SDKs retry these automatically. See
analyzer_unavailable.
Termination reason
Whenterminated_early == true, the response carries a structured
termination_reason:
This is the easiest way to surface a precise message to your end
user without parsing every analyzer block.
Aggregated metrics
When the policy’sdefault_telemetry is true, the response carries
totals across the run:
The numbers are summed only over analyzers that ran; skipped
analyzers contribute zero.
Headers worth inspecting
X-Request-ID— same value asrequest_idin the body.X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset— current rate-limit window state.X-Billing-Status,X-Subscription-Status— subscription health.activeis normal;past_due/canceledflag attention.X-Agnes-Test-Mode: true— sandbox response. Exclude from billing dashboards.
Common questions
Why doesblocked_by have multiple analyzers? Asynchronous steps
can have more than one analyzer terminate in the same step. The SDK
reports every analyzer that fired a terminate_immediately rule.
Where is the prompt in the response? It is not echoed back. The
SDKs keep the input you sent locally; the server does not persist it
unless you explicitly ingest into the threat-intel store.
Can I get the cost in tokens, not dollars? total_cost_usd is the
public field. The metered usage report at
agnes.lasscyber.com/agnes-info/billing
shows token-level metering for billing reconciliation.
Next
- Errors — what every error response looks like.
- Combined analyzer — author the
termination rules that decide what
terminated_earlymeans. - API reference — full auto-rendered schema with interactive playground.