Skip to main content
This page explains what 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

The exact field names follow the OpenAPI schema in sdk/openapi/openapi.json; the auto-rendered API reference is the authoritative source.

Top-level fields

SDK ergonomics

The SDKs unpack the body into a Decision object:
blocked_by / blockedBy is the easiest lever for branching in application code:
The SDK translates server keys (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 in analyzer_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

The classifier scored 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

The safety judge fired on hate speech with confidence 0.88. The combined policy’s 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_status to ERROR.
  • In an asynchronous step, every analyzer in the group still runs to completion. Any error in the group flips overall_status to ERROR, but you’ll see the other analyzers’ results too.
When 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

When terminated_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’s default_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 as request_id in the body.
  • X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset — current rate-limit window state.
  • X-Billing-Status, X-Subscription-Status — subscription health. active is normal; past_due / canceled flag attention.
  • X-Agnes-Test-Mode: true — sandbox response. Exclude from billing dashboards.

Common questions

Why does blocked_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_early means.
  • API reference — full auto-rendered schema with interactive playground.