OpenAI Agents SDK¶
mimir.integrations.openai_agents.as_function_tool converts a decision tool into a FunctionTool for use in an Agent's tool list. The typed result is returned as structured data.
guard(tool, check) gates any FunctionTool with a tool-call check: a certified denial is rejected with the check's reason, and an escalated call pauses the run with RunState.approve or RunState.reject for human review.
Tested from openai-agents 0.21.
Native tools¶
"""An OpenAI Agents SDK agent that routes support tickets with a MIMIR decision tool.
Install `mimir-decisions[local,openai-agents]`, set `OPENAI_API_KEY`, then run
`make example NAME=openai_agents/agent`.
"""
import asyncio
from typing import Final
from agents import Agent, Model, Runner
from mimir import Choice, Decider, Mimir
from mimir.integrations.openai_agents import as_function_tool
TEAMS: Final = {
"billing": "Billing: payments, refunds and invoices",
"security": "Security: account access, passwords and fraud",
"shipping": "Shipping: deliveries, tracking and returns",
}
INSTRUCTIONS: Final = (
"Route the customer's ticket with route_ticket, then tell the customer which team will "
"answer. If the decision is deferred, say that a person will review the ticket."
)
def build_agent(decider: Decider, model: str | Model | None = None) -> Agent[None]:
"""The support agent, answering with `decider`; `model` defaults to the SDK's."""
route_ticket = decider.tool(
"route_ticket",
Choice("Which team should handle this ticket?", TEAMS),
description="Route a customer support ticket to the team that owns it.",
)
return Agent(
name="support",
instructions=INSTRUCTIONS,
tools=[as_function_tool(route_ticket)],
model=model,
)
async def main() -> None:
agent = build_agent(Mimir.from_pretrained("Mythologic/MIMIR-1"))
result = await Runner.run(agent, "I was charged twice for order 4412.")
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())
Tool-call check¶
"""An OpenAI Agents SDK agent whose refunds MIMIR checks against the refund rules first.
A certified yes runs the refund, a certified no rejects it with the reason, and anything else
pauses the run until a person at the console approves or rejects it. Install
`mimir-decisions[local,openai-agents]`, set `OPENAI_API_KEY`, then run
`make example NAME=openai_agents/guarded_agent`.
"""
import asyncio
from typing import Final
from agents import Agent, FunctionTool, Model, Runner, RunResult, function_tool
from mimir import Decider, Mimir
from mimir.integrations.openai_agents import guard
RULES: Final = (
"A refund is at most the amount the customer paid for the order.",
"Refunds above 500 dollars need a manager's approval.",
)
INSTRUCTIONS: Final = "Issue the refunds customers ask for with issue_refund."
@function_tool
def issue_refund(order: str, amount: float) -> str:
"""Refund `amount` dollars on `order`."""
return f"Refunded {amount:.2f} dollars on order {order}."
def build_agent(
decider: Decider, refund: FunctionTool = issue_refund, model: str | Model | None = None
) -> Agent[None]:
"""The refunds agent, its `refund` tool checked by `decider` against `RULES`."""
check = decider.tool_call_check(RULES, tools=[refund.name])
return Agent(
name="refunds", instructions=INSTRUCTIONS, tools=[guard(refund, check)], model=model
)
async def run_with_approvals(agent: Agent[None], request: str) -> RunResult:
"""Run `agent`, asking at the console about each call the check escalates."""
result = await Runner.run(agent, request)
while result.interruptions:
state = result.to_state()
for pending in result.interruptions:
answer = input(f"Approve {pending.name} {pending.arguments}? [y/N] ")
if answer.strip().lower() == "y":
state.approve(pending)
else:
state.reject(pending)
result = await Runner.run(agent, state)
return result
async def main() -> None:
agent = build_agent(Mimir.from_pretrained("Mythologic/MIMIR-1"))
result = await run_with_approvals(agent, "Refund 900 dollars on order 4412.")
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())
Over MCP¶
"""An OpenAI Agents SDK agent using MIMIR's MCP server over stdio.
The server runs `examples/tools.yaml`, so the agent sees `route_ticket` and passes only the
ticket. Install `openai-agents` and `uv`, set `OPENAI_API_KEY`, then run
`make example NAME=openai_agents/mcp_agent`.
"""
import asyncio
from collections.abc import Sequence
from pathlib import Path
from typing import Final
from agents import Agent, Model, Runner
from agents.mcp import MCPServer, MCPServerStdio
TOOLS: Final = Path(__file__).parents[1] / "tools.yaml"
SERVER: Final = (
"uvx",
("--from", "mimir-decisions[local,mcp]", "mimir-decisions", "mcp", "--tools", str(TOOLS)),
)
INSTRUCTIONS: Final = (
"Route the customer's ticket with route_ticket, then tell the customer which team will "
"answer. If the decision is deferred, say that a person will review the ticket."
)
def mimir_server(command: str, arguments: Sequence[str]) -> MCPServerStdio:
"""MIMIR's MCP server, started as `command` with `arguments`."""
return MCPServerStdio(
params={"command": command, "args": list(arguments)},
name="mimir",
client_session_timeout_seconds=90,
)
def build_agent(server: MCPServer, model: str | Model | None = None) -> Agent[None]:
"""The support agent, with the tools of `server`; `model` defaults to the SDK's."""
return Agent(name="support", instructions=INSTRUCTIONS, mcp_servers=[server], model=model)
async def main() -> None:
async with mimir_server(*SERVER) as server:
result = await Runner.run(build_agent(server), "I was charged twice for order 4412.")
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())