Overview
package wittgenstein_agent_guardrails
wittgenstein-agent-guardrails — reusable scope-guardrail middleware for pydantic-ai agents.
Classes
-
ScopeSource — Something that knows whether a question is answerable from its data.
-
GuardrailAgent — Wraps a pydantic-ai
Agentwith a scope pre-check.
Functions
-
make_grounding_validator — Build a pydantic-ai
@agent.output_validatorthat rejects answers produced without retrieving any grounding facts this turn.
wittgenstein_agent_guardrails.ScopeSource
mkapi_definition_mkapi class ScopeSource()
Bases : Protocol
Something that knows whether a question is answerable from its data.
Deliberately decoupled from any specific data store (knowledge graph,
vector index, fixture file, ...) so GuardrailAgent stays reusable —
implement this against whatever backs a given agent's knowledge.
Methods
-
is_in_scope — Return True if
questionmatches something this source knows about.
wittgenstein_agent_guardrails.ScopeSource.is_in_scope
mkapi_definition_mkapi method ScopeSource.is_in_scope(question: str) → bool
Return True if question matches something this source knows about.
wittgenstein_agent_guardrails.make_grounding_validator
mkapi_definition_mkapi make_grounding_validator(facts_accessor: Callable[[DepsT], list], ungrounded_message: str = DEFAULT_UNGROUNDED_MESSAGE) → Callable[[Any, str], Any]
Build a pydantic-ai @agent.output_validator that rejects answers
produced without retrieving any grounding facts this turn.
facts_accessor(ctx.deps) should return whatever the agent's tools
accumulated during the run (e.g. knowledge-graph triplets fetched by a
query tool). This is a cheap circuit breaker for "answered without
looking anything up" — it does not perform entailment/NLI between the
answer text and the facts, mirroring the pragmatic, narrow checks
already proven in production (e.g. an NLQ chat agent's
check that only verifies that a query
actually ran). Raising pydantic_ai.ModelRetry is pydantic-ai's retry
signal — it tells the model to try again with corrected output instead
of crashing the whole agent run.
Raises
-
ModelRetry
wittgenstein_agent_guardrails.GuardrailAgent
mkapi_definition_mkapi dataclass GuardrailAgent(inner_agent: Any, scope_source: ScopeSource, refusal_message: str = DEFAULT_REFUSAL_MESSAGE)
Bases : Generic[DepsT]
Wraps a pydantic-ai Agent with a scope pre-check.
Blocks a call before it reaches the inner agent — and therefore before
any LLM call happens — when scope_source.is_in_scope(user_prompt) is
False. Cheaper and safer than only validating the answer after
generation, since an out-of-scope request never reaches the model.
Methods
wittgenstein_agent_guardrails.GuardrailAgent.run
mkapi_definition_mkapi async method GuardrailAgent.run(self, user_prompt: str, deps: DepsT, **kwargs: Any) → str