For the complete documentation index, see llms.txt. This page is also available as Markdown.

OpenAI Agents SDK

Record and replay non-streaming OpenAI Agents SDK runs with the separately packaged Kitaru v2 adapter

The Kitaru v2 OpenAI Agents adapter records a native OpenAI Agents SDK run as one Kitaru session. Model calls, tools, hosted tools, and handoffs appear as child nodes inside that session. The OpenAI SDK still executes the agent and returns its own result object.

Run an agent

Install the adapter package:

uv add kitaru-openai-agents

In a Kitaru repository checkout, sync the plugin workspace instead:

uv sync --project plugins --all-packages

Create the OpenAI agent as usual, then pass it to KitaruRunner.run(...) or KitaruRunner.run_sync(...):

import uuid

from agents import Agent

from kitaru_openai_agents import KitaruRunner

agent = Agent(
    name="support_agent",
    instructions="Answer briefly and accurately.",
    model="gpt-5-nano",
)
runner = KitaruRunner(agent_id=uuid.UUID("00000000-0000-0000-0000-000000000001"))

result = runner.run_sync(agent, "Where is my order?")
print(result.final_output)

Use await runner.run(...) in asynchronous code. run_sync(...) must not be called while an event loop is already running.

Both methods return the exact native OpenAI RunResult. Kitaru does not replace it with a custom result type, and it preserves caller-owned agents, hooks, context, OpenAI SDK sessions, run configuration, and response or conversation identifiers unless a worker-managed replay overrides the corresponding supported value.

Kitaru identity

A standalone run must set either agent_id or agent_version_id on KitaruRunner. You can also set session_name and batch_size:

A Kitaru worker provides KITARU_TASK_ID for task-bound runs. In that case, the server links the result session to the task and infers the agent identity, so the runner does not need either identity argument.

Correlate the native result with its session

Pass a sync or async session_observer when constructing KitaruRunner. Kitaru calls it with the new SessionResponse after the session and its root node exist. The callback can retain the session ID, then the caller can associate the exact native result returned later with that Kitaru session:

Define remember_session with async def when it needs to await other work. The observer runs before OpenAI executes the agent, so it identifies the session even if the native run later fails.

What Kitaru records

Before OpenAI executes the agent, Kitaru creates one session and an in-progress root node. As the run proceeds, it records structured observations for supported model calls, direct function-tool calls, provider-hosted tools, handoffs, token usage, final output, and failures. It completes the session only after all observations have been persisted.

Each model-call node names its model and provider and carries an estimated cost from the bundled genai-prices catalog. The OpenAI Agents SDK does not pass the model name the provider reports back to the adapter, so Kitaru records the name the run configured, in the SDK's own order: RunConfig.model, then the agent's model, then the SDK default. Names without a prefix, names prefixed with openai/, and OpenAIResponsesModel or OpenAIChatCompletionsModel instances are recorded with provider openai. Other prefixed names and custom model providers keep the configured name as requested_model but have no provider, served model, or cost, because Kitaru cannot tell which backend served them. A reasoning model's returned summary and reasoning text is stored in its model-call node's outputs and selected as that node's visible reasoning.

These nodes are observations of what the OpenAI SDK run did. They are not independently replayable units, and they do not change how the SDK runs the agent.

Replay behavior

Replay selection is worker-managed through KITARU_REPLAY_ID. KitaruRunner.run(...) and run_sync(...) have no per-run replay argument. Use the Kitaru replay and task flow, which starts the agent task with the selected replay, rather than mutating the process environment around concurrent standalone calls. Environment variables are process-wide, so one concurrent call could otherwise read another call's replay ID.

For the selected replay, the adapter can replace the root input, starting-agent instructions, run-level model, and model settings without mutating the caller's objects.

Direct FunctionTool replay supports three named policies:

  • Passthrough: call the original tool. This is the default.

  • Static: return the recorded or configured static value without calling the original tool.

  • History: return a recorded result with matching canonical JSON arguments without calling the original tool.

The default policy must remain passthrough, so configure history for each named tool you want to replay. A named static or history substitution must match one ordinary, direct, enabled, non-approval FunctionTool on the starting agent. Unsupported, ambiguous, duplicate, or unmatched tool policies fail before Kitaru creates a session or OpenAI calls the model. LLM, hosted, MCP, programmatic, agent-as-tool, handoff-target, and unknown tool substitutions are rejected.

With baseline history scope, repeated calls with identical arguments consume matching recorded results in invocation order. Concurrent identical calls receive distinct occurrences, but the adapter does not promise that callback scheduling reproduces the model response's source order. Cohort-version and agent history scopes use the newest matching result for every call.

Completed history matches replay their result, including null. A matched recorded failure raises ToolPolicyError inside the tool callback and does not execute the live tool. During a normal KitaruRunner run, the OpenAI Agents SDK exposes this as agents.exceptions.UserError with the ToolPolicyError in __cause__. History also fails closed when arguments are not strict canonical JSON, when a completed result contains Kitaru truncation metadata, when the target tool has an SDK timeout, or when the server predates the explicit match contract introduced in Kitaru 0.22.3. Sessions recorded by kitaru-openai-agents 0.1.x stored function arguments in a different shape and may not match calls made by 0.2.0; record a new baseline when you need history replay.

Deliberate exclusions

This first v2 adapter release does not provide:

  • run_streamed or token and event streaming

  • per-call or mid-run replay from recorded observation nodes

  • a Kitaru sandbox helper for OpenAI tools

  • an adapter-specific request or result envelope

  • RunState input or durable approval interruption and resume

  • adapter-specific CLI, MCP, or server support

Approval interruptions fail closed instead of completing the Kitaru session. RunState input is rejected because Kitaru v2 does not yet have a durable interrupted-session state to resume.

Exceptions after OpenAI starts

The adapter exposes two public exceptions in kitaru_openai_agents for failures after OpenAI starts:

  • KitaruRecordingError means OpenAI produced a native result but Kitaru failed while reconciling observations, finalizing the session, or closing the client. Its result field preserves that RunResult; session_id identifies the Kitaru session when available; and phase names the failed recording phase. It sets retry_safe=False and side_effects_possible=True, because automatically running the model or tools again could duplicate work or side effects.

  • UnsupportedInterruptionError means OpenAI returned an approval interruption that this adapter cannot durably resume. Its result field preserves the interrupted native RunResult.

Data safety

Kitaru recording is independent of OpenAI tracing. Disabling OpenAI tracing does not disable Kitaru session and node recording.

The adapter excludes caller context, clients, credentials, environment state, callbacks, OpenAI SDK session objects, private SDK fields, encrypted reasoning content, and unknown-object serialization. Recorded values use deterministic size, depth, and collection limits with truncation metadata.

Effective prompts, tool arguments, tool results, and exception summaries can still contain sensitive application data. Review what your application sends to models and tools, and apply the same access controls and retention policy to Kitaru data that you apply to the original application payloads.

Runnable example

The repository example has a no-cost help check and an opt-in real run:

See examples/python/openai_agents_v2/README.md for setup details.

Last updated

Was this helpful?