v0.17.0
Added
-
Server-side tool-approval interrupt/resume loop (HITL, part 1 — "turn it on").
A tool flaggedrequires_approvalnow finishes the run on aRUN_FINISHED
interrupt outcome (carrying the tool call id and an approve/deny/edit response
schema) instead of executing; a follow-up run carryingRunAgentInput.resume[]
approves (runs the tool), denies, or overrides its arguments. The entire
lifecycle is upstream (pydantic-ai + the AG-UI adapter) and was already driven by
AgentSession— this release unlocks it:- Pins a direct
ag-ui-protocol>=0.1.19,<0.2dependency (the interrupt/resume
protocol floor;pydantic-ai-slimonly floors it at>=0.1.10). - Puts
DeferredToolRequestsin the agentoutput_type, so approval works for
server-side tools too — the AG-UI adapter only augmentsoutput_typewhen a
run carries frontend tools, so a server-only gated tool would otherwise crash
the run with aRUN_ERROR.
This part turns the loop on; the
TOOL_GUARDpolicy below is what flags tools. - Pins a direct
-
ToolGuard— opt-in server-side approval gate (HITL, part 2 — the policy).
A newDJANGO_AG_UI["TOOL_GUARD"]setting composes aToolGuardcapability
that flips destructive server-side tools to require approval (kind= "unapproved") atprepare_toolstime, so they defer to the interrupt loop
above instead of running mid-stream. Off by default — no surprise gates.- Destructiveness is unified from three sources: a registry
@tool(destructive=True); a drf-mcp tool whose MCPreadOnlyHintisFalse
(the bridge now reads the toolannotationsit previously discarded and
stamps aDESTRUCTIVE_METADATA_KEYonto the tool definition — no drf-mcp
release needed); and per-nameREQUIRE_APPROVAL/EXEMPToverrides
(EXEMPTwins). - Only
functiontools are flipped — anexternal(frontend) tool is already
gated client-side, anoutputtool isn't executed. - See
TOOL_GUARDfor the settings shape.
- Destructiveness is unified from three sources: a registry
Changed
AuditCapabilitynow declares its composition order (get_ordering()→
outermost) instead of relying on list position at thebuild_agentcall site.
This makes capability composition deterministic now that a second capability
(ToolGuard) can join the chain: pydantic-ai'sCombinedCapability
topologically sorts by these constraints, so audit stays outermost (wrapping
every tool execution) regardless of insertion order. No behavioural change with
a single capability.