Releases: vstorm-co/pydantic-ai-shields
Releases · vstorm-co/pydantic-ai-shields
0.3.0
[0.3.0] - 2026-03-28
Changed
- Renamed to
pydantic-ai-shields— the package is now focused exclusively on guardrail capabilities built on
pydantic-ai's native capabilities API. The old middleware layer (MiddlewareAgent,AgentMiddleware, etc.) has been
removed — pydantic-ai v1.71+ provides this natively.
Added
- 5 infrastructure capabilities:
CostTracking— token usage tracking, USD cost calculation via genai-prices, budget enforcementToolGuard— block tools viaprepare_toolsor require approval viabefore_tool_executeInputGuard— block/check user input with pluggable guard function (sync or async)OutputGuard— block/check model output with pluggable guard function (sync or async)AsyncGuardrail— run guardrail concurrently with LLM call, 3 timing modes
- 5 built-in content shields (zero external dependencies):
PromptInjection— detect prompt injection / jailbreak across 6 categories with 3 sensitivity levelsPiiDetector— detect PII (email, phone, SSN, credit card, IP) with block or log actionSecretRedaction— block API keys, tokens, credentials in model output (OpenAI, Anthropic, AWS, GitHub,
Slack, JWT, private keys)BlockedKeywords— block forbidden keywords/phrases with case, whole-word, and regex modesNoRefusals— block LLM refusals with 10 built-in patterns and partial refusal support
Removed
- All legacy middleware modules:
MiddlewareAgent,AgentMiddleware,MiddlewareToolset,MiddlewareChain,
MiddlewareContext,ConditionalMiddleware,ParallelMiddleware,AsyncGuardrailMiddleware,
CostTrackingMiddleware, decorators, config loaders, pipeline spec, builder - All legacy examples and documentation
0.2.4
[0.2.4] - 2026-03-19
Fixed
MiddlewareAgentmissingdescriptionproperty — pydantic-ai addeddescriptionas an abstract property onAbstractAgent, causingMiddlewareAgentinstantiation to fail withreportAbstractUsage. Delegates to the wrapped agent with a fallback for older pydantic-ai versions.
0.2.3
[0.2.3] - 2026-03-11
Fixed
MiddlewareAgent.iter()now callsafter_runandon_errormiddleware — previously onlybefore_runwas invoked, making middleware unusable for post-processing (e.g. audit logging, cost tracking) when usingiter()/run_stream().after_runis called in reverse order after iteration completes,on_erroris called when an exception propagates out of theasync withblock. (#17)
0.2.2
0.2.1
[0.2.1] - 2025-02-15
Added
- Cost Tracking Middleware —
CostTrackingMiddlewarefor automatic token usage and USD cost monitoring- Tracks cumulative input/output tokens and USD costs across agent runs
- USD cost calculation via
genai-priceslibrary (supports"provider:model"format) budget_limit_usd— enforces cost budget limits, raisesBudgetExceededErrorwhen exceededon_cost_updatecallback withCostInfodataclass (supports sync and async)reset()method to clear accumulatorscreate_cost_tracking_middleware()factory function
BudgetExceededErrorexception for budget limit enforcementrun_usagemetadata —MiddlewareAgentnow storesresult.usage()in context metadata after each run, enabling cost tracking and other usage-aware middleware
Changed
before_model_requesthook — now invoked via pydantic-ai's history processor mechanism instead of manual message interception. This ensures the hook fires for every model request in bothrun()anditer()modes.- Toolset wrapping —
MiddlewareAgentnow always wraps all toolsets (agent's own + explicitly passed) usingagent.override(toolsets=...), preventing duplicate tool registration. ToolBlockedhandling —MiddlewareToolsetnow catchesToolBlockedexceptions inbefore_tool_calland returns a descriptive string instead of raising, avoiding message ordering issues with pydantic-ai retries.
Dependencies
- Added
genai-prices>=0.0.49as a required dependency (for cost calculation)
0.2.0
[0.2.0] - 2025-02-12
Added
- Middleware Chains -
MiddlewareChainfor grouping middleware into reusable, ordered units- Fluent API:
add(),insert(),remove(),replace(),pop(),clear(),copy() - Chain composition: chains flatten when added to other chains
- Operator support:
+and+=for combining chains - Iteration support:
len(),[],in, iteration
- Fluent API:
- Conditional Middleware -
ConditionalMiddlewarefor branching execution based on runtime conditions- Route to different middleware based on predicate functions
- Supports single middleware or middleware pipelines for each branch
- Predicate receives
ScopedContextfor context-aware decisions when(condition, then, otherwise)helper for fluent syntax
- Pipeline Spec Builder -
PipelineSpecfor building middleware pipelines as portable config dictionaries- Fluent builder API:
add_type(),add_chain(),add_parallel(),add_when() - Export to files:
dump(format="json"|"yaml"),save(path)with auto-detection from extension - Direct compilation:
compile(compiler)delegates to compiler - Helper functions:
type_node(),chain_node(),parallel_node(),when_node()
- Fluent builder API:
- Config Loaders - Functions to load middleware pipelines from JSON/YAML
load_middleware_config_text(text, registry, predicates)- parse from stringload_middleware_config_path(path, registry, predicates)- parse from file- Auto-detection of format from file extension or content
- Registration helpers:
register_middleware(),register_predicate()decorators
- Pipeline Compiler -
MiddlewarePipelineCompilerfor compiling config dictionaries into middlewareMiddlewareRegistryfor storing middleware factories and predicates- Built-in node handlers:
type,chain,parallel,when - Extensible via
register_node_handler()for custom node types - Convenience wrappers:
build_middleware(),build_middleware_list()
- Context Sharing System - Share data between middleware hooks with access control
MiddlewareContextclass for managing shared state across hooksScopedContextclass for enforcing access control based on hook execution orderHookTypeenum defining hook execution order:BEFORE_RUN(1)→BEFORE_MODEL_REQUEST(2)→BEFORE_TOOL_CALL(3)→ON_TOOL_ERROR(4)→AFTER_TOOL_CALL(5)→AFTER_RUN(6)→ON_ERROR(7)- Immutable
configfor read-only global settings - Mutable
metadatafor shared state - Namespaced hook storage with strict access control
- Hooks can only write to their own namespace
- Hooks can only read from earlier or same-phase hooks
- Enable context by passing a
MiddlewareContextinstance toMiddlewareAgent
- Parallel Execution -
ParallelMiddlewarefor running multiple middleware concurrentlyAggregationStrategyenum:ALL_MUST_PASS,FIRST_SUCCESS,RACE,COLLECT_ALL- Early cancellation: remaining tasks are cancelled when result is determined
- Configurable timeout support
- Async Guardrails -
AsyncGuardrailMiddlewarefor concurrent guardrail + LLM executionGuardrailTimingenum:BLOCKING,CONCURRENT,ASYNC_POSTcancel_on_failureoption to short-circuit LLM calls when guardrail fails- Background task management for async post-processing
- Tool Name Filtering - Scope middleware to specific tools
tool_names: set[str] | Noneclass attribute onAgentMiddleware(defaultNone= all tools)_should_handle_tool(tool_name)helper method- Filtering in
MiddlewareToolset,MiddlewareChain, and composite middleware toolsparameter on@before_tool_call,@after_tool_call,@on_tool_errordecorators
on_tool_errorHook - Handle tool execution failures with tool-specific contexton_tool_error(tool_name, tool_args, error, deps, ctx)method onAgentMiddleware- Returns
Exception | None— return a different exception orNoneto re-raise original - New
HookType.ON_TOOL_ERRORenum value - Integrated in
MiddlewareToolset,MiddlewareChain,ParallelMiddleware,ConditionalMiddleware,AsyncGuardrailMiddleware @on_tool_errordecorator with optionaltoolsparameter
- Hook Timeout - Per-middleware timeout enforcement
timeout: float | Noneclass attribute onAgentMiddleware(defaultNone= no timeout)call_with_timeout()utility wrappingasyncio.wait_for()- Enforced in
MiddlewareToolsetandMiddlewareAgentfor all hooks
- Permission Decision Protocol - Structured ALLOW/DENY/ASK decisions for tool authorization
ToolDecisionenum:ALLOW,DENY,ASKToolPermissionResultdataclass withdecision,reason, and optionalmodified_argsbefore_tool_callreturn type extended:dict[str, Any] | ToolPermissionResultPermissionHandlercallback type forASKdecisions:async (tool_name, tool_args, reason) -> boolpermission_handlerparameter onMiddlewareAgentandMiddlewareToolset
- New exceptions:
ParallelExecutionFailed- When parallel execution failsGuardrailTimeout- When guardrail times outAggregationFailed- When result aggregation failsMiddlewareConfigError- When config loading or compilation failsMiddlewareTimeout- When a middleware hook exceeds its timeout
- Project restructured to
src/layout
Changed
- BREAKING: All hook signatures now include
ctx: ScopedContext | None = Noneas the last keyword argumentbefore_run(prompt, deps, ctx)after_run(prompt, output, deps, ctx)before_model_request(messages, deps, ctx)before_tool_call(tool_name, tool_args, deps, ctx)— return type extended todict | ToolPermissionResulton_tool_error(tool_name, tool_args, error, deps, ctx)— NEWafter_tool_call(tool_name, tool_args, tool_result, deps, ctx)on_error(error, deps, ctx)
__version__now usesimportlib.metadatainstead of a hardcoded string- Bumped minimum
pydantic-ai-slimdependency from>=0.1.0to>=1.38
Fixed
- Replaced private pydantic-ai API usage with public alternatives (#11 by @pedroallenrevez)
from pydantic_ai._run_context import RunContext→from pydantic_ai import RunContextAgentRunResult(output=..., _output_tool_name=..., ...)→dataclasses.replace(result, output=output)- Removed dependency on
pydantic_ai._utils.UNSET/Unsetby simplifyingoverride()to use**kwargspass-through
0.1.0
0.1.0 - 2024-12-29
Added
- Initial release
AgentMiddlewarebase class with lifecycle hooks:before_run- Called before agent runsafter_run- Called after agent finishesbefore_model_request- Called before each model requestbefore_tool_call- Called before tool executionafter_tool_call- Called after tool executionon_error- Called when errors occur
MiddlewareAgent- Wrapper agent that applies middlewareMiddlewareToolset- Toolset wrapper for tool call interception- Decorator-based middleware creation:
@before_run@after_run@before_model_request@before_tool_call@after_tool_call@on_error
- Custom exceptions:
MiddlewareError- Base exceptionInputBlocked- Block inputToolBlocked- Block tool callsOutputBlocked- Block output
- Full type safety with generics
- 100% test coverage
- Documentation with MkDocs