llm_call step, and tools are declared with @tool, so every
tool call is recorded as a tool_call step. On a re-dispatch the agent runs
from the top and recorded steps replay instead of calling the model or the tool
again.
Install
Model calls
Build theAsyncOpenAI client yourself with http_client(), and hand it to the
model:
Prompt cache key
Againstapi.openai.com, the Runner generates a random prompt_cache_key for
each run. The key is part of the request body, so every model call would get a
new step identity on resume and run again instead of
replaying. Set the key to the execution id:
Tools
@tool keeps the function’s signature and docstring, so function_tool builds
the tool schema from it as usual:
function_tool turns a tool’s exception into an error message for
the model. A tool held for approval raises to park the execution, so pass
failure_error_function=None to let it unwind the run instead. A denied tool
still returns the rule’s reason to the model, since a denial doesn’t raise.
Mark anything with a side effect, such as sending an email or creating a
ticket, at_most_once. See idempotency.
The agent
The SDK’sAgent and Rebuno’s Agent share a name, so import one under an
alias:
What Rebuno adds
- Policy. Every model and tool call is checked against policy before it runs. A denied tool returns the rule’s reason to the model as the tool result, so the agent can take a different path.
- Approvals. A tool that requires approval parks the execution. Once it’s approved, the agent is dispatched again, the earlier steps replay, and the approved call runs.
- Recovery. If the worker dies partway through, the next dispatch replays every completed step and continues from the first one that didn’t finish. Model calls that already ran are not paid for twice.
Full example
examples/frameworks/python/openai_agents_agent.py
is a support agent that investigates a customer issue, creates a ticket, and
emails a summary after approval.