PR #25 ยท pramaan-io/pramaan-agents ยท merged 2026-06-03
An agent answering in court can't afford a hallucinated citation, a leaked matter, or a runaway bill.
Admissibility needs 4 hard checks, not a polite filter.
End-of-pipeline check is too late โ the breach already happened.
The fix โ Check, cap, lock, verify โ every run, every answer.
Roadmap ยท Agent Platform
sequenceDiagram autonumber participant request as Agent run participant controller as Guardrail controller participant model as Model + tools participant recorder as MatterChat recorder request->>controller: AgentRunRequest controller->>controller: circuit_breaker.check_before_run controller->>model: cost_cap.check_before_model_call model->>model: tool call โ tenant_boundary model->>controller: validate_answer (citations) controller-->>recorder: record_run_outcome
| Method | in โ out | what it does |
|---|---|---|
CircuitStateStore | (class) | |
load | (firm_id) โ list[dict[str, Any]] | |
save | (firm_id, samples) โ None |
Implements the CircuitBreakerGuardrail that tracks per-firm error rate in a rolling window and emits the circuit_open status, blocking cascading retries on the MatterChat recorder path.
| new class | signature |
|---|---|
CircuitStateStore | (class) |
load | (firm_id) โ list[dict[str, Any]] |
save | (firm_id, samples) โ None |
DynamoDBCircuitStateStore | (class) |
CircuitBreakerGuardrail | (store, threshold, window_seconds, min_samples) |
check_before_run | (firm_id) โ None |
record_outcome | (firm_id, error) โ None |
_fresh_samples | (firm_id) โ list[dict[str, Any]] |
Hosts the GuardrailController, GuardrailRunContext and GuardrailToolCallRecorder that orchestrate the four guardrails across run, model, tool and answer stages of every AgentRunRequest.
| new class | signature |
|---|---|
GuardrailRunContext | (request, run_id, source_verification, cost_cap) |
GuardrailController | (circuit_breaker) |
context_for | (request, run_id) โ GuardrailRunContext |
record_run_outcome | (firm_id, error) โ None |
wrap_recorder | (recorder, context) โ ToolCallRecorder |
before_model_call | (context, prompt_text, user_message, history) โ None |
after_model_call | (context, input_tokens, output_tokens) โ None |
validate_answer | (context, content) โ None |
GuardrailToolCallRecorder | (inner, context, _tool_names) |
after_tool_call | (event) โ None |
Implements the CostCapGuardrail that estimates USD cost from token counts and aborts the model call before spend exceeds the configured cap, emitting the aborted_cost status.
| new class | signature |
|---|---|
CostCapGuardrail | (cap_usd, input_price_per_million, output_price_per_million, spent_usd) |
check_before_model_call | (prompt_text, user_message, history_text) โ None |
record_model_usage | (input_tokens, output_tokens) โ None |
_cost | (input_tokens, output_tokens) โ Decimal |
_ensure_under_cap | (additional_usd) โ None |
estimate_tokens | (text) โ int |
_decimal_env | (name, default) โ Decimal |
Defines the SourceVerificationGuardrail that re-checks every citation in the final answer against the fetched quotes before the answer leaves the agent.
| new class | signature |
|---|---|
SourceVerificationGuardrail | (fetched_quotes) |
validate_answer | (content) โ None |
citations_in | (content) โ list[tuple[str, str]] |
Defines the TenantBoundaryGuardrail that validates firm_id and matter_id on every tool call so no cross-tenant data access can slip through the MatterChat recorder.
| new class | signature |
|---|---|
TenantBoundaryGuardrail | (firm_id, matter_id) |
_uuid_from_input | (value) โ UUID | None |
StrandsHarness now holds guardrail_controller and guardrail_context fields so the four guardrails are invoked inside the agent loop, not bolted on after.
guardrail_controller : GuardrailController | Noneguardrail_context : GuardrailRunContext | NoneAgent runtime app now owns a GuardrailController instance, wiring the four guardrails into every AgentRunRequest path that flows through the runtime.
guardrails : GuardrailControllersrc/pramaan_agents/db/store.py+22 โ4Added the _failure_status helper that maps runtime errors to the canonical block statuses (circuit_open, aborted_cost, guardrail_blocked) before they are persisted to the run record.
| new method | signature |
|---|---|
_failure_status | (error) โ str |
Introduces GuardrailBlockedError and GuardrailTerminalError so guardrail failures are distinguishable from regular runtime errors throughout the recorder path.
| new class | signature |
|---|---|
GuardrailBlockedError | (class) |
GuardrailTerminalError | (class) |
__init__ | (status, message) โ None |
MatterChat tool schema gained an optional matter_id field so the TenantBoundaryGuardrail can verify which matter a tool call is operating on before it executes.
matter_id : UUID | None