Tawa docs
SDK Reference

Scanning

Every scan method on the Python client — analyze, RAG protection, and agent protection.

Every scan method hits the same underlying detection pipeline with different provenance — a plain prompt, a retrieved document chunk, a tool call, and so on — and they all return the same ScanResult shape (RAG-family methods add a couple of extra fields; scan_retrieval returns a list plus an aggregate verdict instead). Methods on AsyncTawaGuard have the same signatures as TawaGuard, as coroutines.

analyze

The general-purpose entry point. Scans a plain prompt before it reaches your LLM.

result = client.analyze("Ignore all previous instructions…")

Result

ScanResult is a frozen dataclass:

FieldTypeDescription
actionScanActionThe action to enforce: "allow" or "block". The gateway collapses the engine's "review" per your app's setting. Against a gateway that predates engine_action, the engine's raw label (any of "allow" | "block" | "soft_block" | "hard_block" | "review" | "sandbox" | "ambiguous" | "ood")
engine_actionScanAction | NoneThe engine's own label before collapsing, for example "review". Falls back to action when the gateway does not send it
needs_reviewboolTrue when the engine was uncertain (its action was "review"), whether action is "allow" or "block". "ood" does not set it
riskfloat | NoneHow likely the input is malicious (0-1), regardless of action. None for older responses or out-of-distribution input
confidencefloatConfidence in action (0-1). Equals risk for any flagging action, and 1 - risk for allow
suggestion"allow" | "block" | NoneCoarse hint for the undecided actions (ambiguous/review/sandbox)
rationalestrHuman-readable explanation of the decision
policyPolicyVerdict | NoneDirectives signaled by the worker's policy engine, if any
languageLanguageInfo | NoneLanguage identification detail, None while language ID is disabled
score_breakdowndict[str, Any] | NoneDiagnostic detail behind the decision — shape varies by which decision path fired
if result.action == "allow":
    print(f"Safe ({result.confidence:.2f} confidence)")
else:
    print(f"Blocked: {result.rationale}")

if result.needs_review:
    # The engine was uncertain; engine_action holds its own label.
    print(f"Flagged for review (engine said {result.engine_action})")

See The review flag. Against a gateway that predates these fields, needs_review is derived from action == "review" and action carries the engine's raw label, so keep handling "review", "soft_block", "sandbox", and "ambiguous" if you support such a gateway.

Options

Every scan method accepts cuid, tenant_id, policy_overrides, and language as keyword arguments, forwarded straight to the worker per call.

RAG protection

Scan retrieved content before it's assembled into a prompt.

# A single retrieved chunk, before it enters the assembled context.
chunk_result = client.scan_chunk(chunk_text, chunk_id="doc-42#3")

# The fully assembled prompt (system + retrieved chunks + user turn),
# immediately before the LLM call.
context_result = client.scan_context(assembled_prompt)

# An entire retrieved set in one call — a per-chunk verdict plus an
# aggregate.
from tawaguard import RagChunkInput

result = client.scan_retrieval(
    query,
    [
        RagChunkInput(chunk_id="doc-42#1", text="…"),
        RagChunkInput(chunk_id="doc-42#2", text="…"),
    ],
)
print(result.per_chunk, result.aggregate)

result.aggregate.flagged_chunk_ids  # chunks enforced as block
result.aggregate.review_chunk_ids   # chunks the engine flagged, blocked or not

See the RAG protection cookbook for a full walkthrough combining all three.

Agent protection

Inspect a proposed tool call before it executes, and its output before it re-enters the agent loop.

call_result = client.scan_tool_call("run_query", {"sql": "SELECT …"})
if call_result.action != "allow":
    # withhold the tool call
    ...

output_result = client.scan_tool_output("run_query", query_result)

See the Agent protection cookbook for a full walkthrough with both gates and policy directive handling.

Scanning a model's reply

There's no dedicated scan_response method in the Python SDK yet — use analyze() on the model's reply text if you want to apply an equivalent check by hand.

On this page