Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.pecta.ai/llms.txt

Use this file to discover all available pages before exploring further.

Gates are the core primitive in Pecta. Each gate is a single pass/fail check that runs against an agent’s output before it reaches the user. You compose any number of gates when you call createEngine, and the engine runs all of them in parallel under a shared timeout budget. Fail-fast (the default) aborts remaining gates the moment one fails, keeping evaluation latency low.

All built-in gates

GateCategoryWhat it checks
gates.latencyGeneralctx.latency_ms exceeds a configurable maxMs threshold
gates.schemaGeneralctx.output matches a Zod schema you provide
gates.filesystemGeneralDestructive rm commands, path traversal, and sensitive directories
gates.piiGeneralEmail addresses, SSN-shaped strings, and phone numbers in output
gates.contentGeneralEmpty output and AI refusal/disclaimer phrases
gates.rtb.tmaxGuardRTBSkips downstream gates when the OpenRTB tmax deadline is exhausted
gates.rtb.impidMatchRTBEvery bid.impid matches a request imp.id
gates.rtb.adomainVerifyRTBPlaceholder or malformed advertiser domains
gates.rtb.bidSanityRTBBid price is not unrealistically far above the floor price
gates.rtb.audienceSafetyRTBChild-directed inventory does not receive unsafe ad categories
gates.rtb.bcatComplianceRTBResponse creative does not appear in the request bcat block list

Composing gates

Pass a gates array to createEngine. The engine validates that every gate has a unique name and a run function, then returns an Engine object whose evaluate method you call for each agent output.
import { createEngine, gates } from "@pecta/core";
import { z } from "zod";

const engine = createEngine({
  gates: [
    gates.latency({ maxMs: 200 }),
    gates.schema(z.object({ answer: z.string().min(1) })),
    gates.filesystem(),
    gates.pii(),
    gates.content(),
  ],
  timeout: 50,   // total ms budget across all gates (default 50)
  failFast: true, // abort remaining gates on first failure (default true)
});

const result = await engine.evaluate({
  agent_id: "research-bot-v2",
  tool: "web.search",
  output: { answer: "The capital of France is Paris." },
  latency_ms: 120,
});

if (!result.passed) {
  const failures = result.gates.filter((g) => !g.passed && !g.skipped);
  console.error("blocked by:", failures.map((g) => g.name));
}
The return value is an EvaluationResult:
{
  evaluation_id: "V1StGXR8_Z5jdHi6B-myT",
  agent_id: "research-bot-v2",
  tool: "web.search",
  passed: false,
  gates: [
    { name: "latency", passed: false, reason: "latency 120ms exceeds 100ms threshold", latency_ms: 0.12 },
    { name: "schema",  passed: false, reason: "pecta:aborted: pecta:fail-fast", latency_ms: 0.01 },
    // ...
  ],
  total_latency_ms: 0.95,
  timestamp: "2026-05-07T14:32:00.000Z"
}

Timeout budget

The timeout option (default 50 ms) is a wall-clock budget shared across all gates. When the budget expires, the engine fires an AbortController signal. Gates that check signal.aborted before doing expensive work return immediately; any gate that is still running when the timer fires has its result recorded as passed: false with reason: "pecta:aborted: pecta:timeout".
Setting timeout too low can cause gates to return aborted results even when the output is valid. Start with the default 50 ms and reduce only after profiling your gate set.

Fail-fast behavior

When failFast is true (the default), the engine aborts the shared AbortController the instant a gate returns passed: false. Gates that have not yet returned will see signal.aborted === true. The engine still waits for every Promise to settle, but aborted gates complete almost immediately. Total evaluation latency is therefore dominated by the first failing gate, not the full gate set. Set failFast: false if you want verdicts from every gate regardless of earlier failures — useful for auditing or debugging.
A gate that returns skipped: true is treated as passing. The tmaxGuard RTB gate uses this to opt out of evaluation when the OpenRTB deadline is already exhausted.

Custom gates

You can write your own gate and pass it alongside the built-in ones. See the custom gates page for the full interface and a worked example.