Skip to main content
New to the adapters? Start with the wrapping overview and comparison table.
Compatible versions: see the compatibility table for the verified openai-agents range.

HexgateRunner

HexgateRunner is a drop-in replacement for agents.Runner. It wraps the agent’s tools with a PolicyEnforcer at construction time and opens a HexgateContext scope around each Runner.run / run_sync / run_streamed call so role resolution happens at call time.

Under the hood

  • HexgateRunner.run calls wrap_openai_agent, which builds a PolicySet for (api_key, agent.name, tool_names), constructs one PolicyEnforcer, and returns a dataclasses.replace’d copy of the agent with policy-gated tool copies — your original agent is untouched.
  • The runner opens an async with hexgate_context: scope around the underlying Runner.run* call. When the model calls a tool, the guard asks enforcer.decide(...) for a Decision. On non-allow, it returns decision.as_error_message() — a [policy_denied] or [approval_required] markered string the model can interpret and recover from.
  • The run executes inside propagate_attributes(user_id=..., session_id=..., metadata={"user_roles": ...}), so Langfuse spans carry the caller identity.
run_sync and run_streamed work the same way.

Agent-level enforcement

Beyond tool calls, HexgateRunner enforces agent-level policy: admission (may this caller run the agent) at run entry, handoff reach (agent.handoff:<name>) at the SDK’s on_handoff seam — a denied handoff is vetoed before the target runs — and agent-as-tool reach (agent.tool:<name>) at the tool seam. Set HexgateRunner(max_handoff_depth=N) to cap a runaway handoff chain.
Agent-as-tool reach is enforced at the top level. The SDK tags an Agent.as_tool() with its target agent, so when the top-level agent’s policy declares an agents block, that as-tool call is gated under agent.tool:<name> (closed-world, via/constraints honored) rather than by tool name. A reach edge one level deeper — a sub-agent that itself calls another agent as a tool — is not gated yet, because the sub-agent runs unwrapped through the SDK’s own runner; those deeper edges fall back to tool-name gating. On an agents SDK too old to expose the tool origin, even the top level falls back to name-gating and a declared via: tool rule warns at setup.

Runnable example

examples/devops_openai.pyHexgateRunner (OpenAI Agents SDK) end-to-end.