Skip to main content
Kensa is a pytest plugin. Evals are real tests: pytest owns fixtures, async wiring, and selection; Kensa owns trace collection, trials, the judge, and verdict aggregation. Install with the rest of your dev dependencies:

Anatomy of an eval

Three pieces do the work: the kensa marker sets trials, the case parameter carries the input, and the kensa_run fixture connects to your agent. Each successful CaseResult exposes its trace through result.trace.

The harness fixture

kensa_run is yours. Setup finds and cites the production function or class that starts one conversation, then waits for your approval before writing this adapter:
The repository factory keeps ownership of prompts, tools, routing, configuration, state, effects, and cleanup. Each trial gets one conversation instance, reused across simulated turns. If the repository exposes no production function or class that can run one conversation, setup reports cannot wire before editing. See Setup safety.

Fixtures and marker

Async agents

Async tests work through the normal pytest async plugins:
Direct synchronous agents return immediately. Coroutine or dynamically awaitable agents return an awaitable with identical result semantics.

Simulated conversations

Supplying a simulator runs bounded sequential alternation on the same agent instance. Simulated runs are always awaitable:
Any object with respond(messages) returning ConversationResponse can be a custom Simulator. Kensa assigns generated roles, keeps agent output separate from visible content, excludes private system and tool context from simulator history, and never retries a responder.

Trials and verdicts

Each case expands into one pytest item per trial:
Kensa aggregates the trials per case at session end: fail, flaky, and error fail the pytest session. Aggregates preserve the requested configured_trials; total excludes skips, and skips alone do not make an aggregate partial.

Structured failure provenance

Every failed, errored, or skipped trial contains one structured failure; passing and provisional trials contain "failure": null. Kensa rejects unknown statuses, legacy error or error_kind fields, and status/failure mismatches when reconstructing an artifact. Eval authors can explicitly attribute a failure at the boundary that knows its owner:
KensaEvalError, TrialFailure, and the FailureCategory type are public from kensa.pytest. Evidence must be strict JSON and is deep-snapshotted separately from the human-readable message. The categories are: Automatic classification uses typed exceptions before wrapper ownership. A reachable KensaEvalError wins first, then LLMConfigurationError, then KensaCaseError. Kensa follows an explicit Python cause, otherwise an unsuppressed context, and traverses exception groups from left to right without parsing exception text. Responder failures use ConversationError ownership. Simulator contract, execution, and timeout failures are simulator; agent execution and timeout failures are agent; an invalid agent response is harness/agent_contract. Direct assertions are agent/assertion. Setup and teardown failures are harness; regular skips are harness/skip, and expected failures from either pytest.mark.xfail or pytest.xfail() are harness/xfail. Direct call timeouts and other untyped call exceptions are unknown. Starting case.run(...) does not change an untyped exception to an agent failure.

Reliability, cost, and latency

Kensa reports τ-bench pass^k as C(passes, k) / C(trials, k), averaged across eligible pytest group_id cohorts. Each point includes its cohort count because fewer cohorts may qualify as k increases. Only passes, assertion failures, and errors explicitly categorized as agent enter reliability, latency, and cost populations. Smoke, skipped, provisional, simulator, judge, configuration, infrastructure, harness, and unknown error trials are excluded. The terminal and Markdown reports show the eligible-trial count and nonzero excluded-error categories. JSON summary includes zero-filled error_counts for every category and excluded_error_trials. This eligibility boundary measures agent behavior conditional on a valid adapter and harness. It does not weaken the gate: excluded errors still produce aggregate error, fail pytest, and make kensa eval exit unsuccessfully. Flaky aggregate behavior is unchanged. Cost totals appear only when at least one cost-relevant trial exists and all are priced; cost per pass also requires a pass. Otherwise they are null; known_cost_usd and cost_coverage report partial data. JSON artifacts expose these metrics under summary.

Versioned result artifacts

All result artifacts use the strict kensa.result.v1 schema, including initial and interrupted snapshots. Load them through the public API:
Invalid or unsupported artifacts raise a path-specific ValueError; the loader never returns partial data or accepts legacy schemas.

Plugin options

The plugin adds these pytest options:

Running evals

Plain pytest is a valid gate:
Use kensa eval when you want CI-friendly artifacts written automatically:
kensa eval runs trials on four local workers with a 300-second timeout. Use --workers 1 for sequential execution and --trial-timeout or timeout_s to change the limit. On timeout, Kensa preserves reported results and the timed-out trial’s latest evidence, then marks the artifact incomplete. Workers do not share process globals or session fixtures and increase provider concurrency. The parallel watchdog applies only to local workers launched by kensa eval; direct and remote xdist runs are not contained. Judge calls time out after 30 seconds by default; built-in judges return an error result, while custom providers receive the configured limit. kensa eval also enables artifact writing and checks evals readiness - it expects at least one passing non-smoke eval. See the CLI reference and CI.
Last modified on August 16, 2026