Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Results

When you call the Runner.run methods, you receive one of two result types:

Both inherit from RunResultBase, which exposes the shared result surfaces such as final_output, new_items, last_agent, raw_responses, and to_state().

RunResultStreaming adds streaming-specific controls such as stream_events(), current_agent, is_complete, and cancel(...).

Choose the right result surface

Most applications only need a few result properties or helpers:

If you need... Use
The final answer to show the user final_output
A replay-ready next-turn input list with the full local transcript to_input_list()
Rich run items with agent, tool, handoff, and approval metadata new_items
The agent that should usually handle the next user turn last_agent
OpenAI Responses API chaining with previous_response_id last_response_id
Pending approvals and a resumable snapshot interruptions and to_state()
Metadata about the current nested Agent.as_tool() invocation agent_tool_invocation
Raw model calls or guardrail diagnostics raw_responses and the guardrail result arrays

Final output

The final_output property contains the final output of the last agent that ran. This is either:

  • a str, if the last agent did not have an output_type defined
  • an object of type last_agent.output_type, if the last agent had an output type defined
  • None, if the run stopped before a final output was produced, for example because it paused on an approval interruption

Note

final_output is typed as Any. Handoffs can change which agent finishes the run, so the SDK cannot statically know the full set of possible output types.

In streaming mode, final_output stays None until the stream has finished processing. See Streaming for the event-by-event flow.

Input, next-turn history, and new items

These surfaces answer different questions:

Property or helper What it contains Best for
input The base input for this run segment. If a handoff input filter rewrote the history, this reflects the filtered input the run continued with. Auditing what this run actually used as input
to_input_list() A replay-ready next-turn input list built from input plus the converted new_items from this run. Manual chat loops and client-managed conversation state
new_items Rich RunItem wrappers with agent, tool, handoff, and approval metadata. Logs, UIs, audits, and debugging
raw_responses Raw ModelResponse objects from each model call in the run. Provider-level diagnostics or raw response inspection

In practice:

  • Use to_input_list() when your application manually carries the entire conversation transcript.
  • Use session=... when you want the SDK to load and save history for you.
  • If you are using OpenAI server-managed state with conversation_id or previous_response_id, usually pass only the new user input and reuse the stored ID instead of resending to_input_list().

Unlike the JavaScript SDK, Python does not expose a separate output property for the model-shaped delta only. Use new_items when you need SDK metadata, or inspect raw_responses when you need the raw model payloads.

New items

new_items gives you the richest view of what happened during the run. Common item types are:

Choose new_items over to_input_list() whenever you need agent associations, tool outputs, handoff boundaries, or approval boundaries.

Continue or resume the conversation

Next-turn agent

last_agent contains the last agent that ran. This is often the best agent to reuse for the next user turn after handoffs.

In streaming mode, RunResultStreaming.current_agent updates as the run progresses, so you can observe handoffs before the stream finishes.

Interruptions and run state

If a tool needs approval, pending approvals are exposed in RunResult.interruptions or RunResultStreaming.interruptions. This can include approvals raised by direct tools, by tools reached after a handoff, or by nested Agent.as_tool() runs.

Call to_state() to capture a resumable RunState, approve or reject the pending items, and then resume with Runner.run(...) or Runner.run_streamed(...).

from agents import Agent, Runner

agent = Agent(name="Assistant", instructions="Use tools when needed.")
result = await Runner.run(agent, "Delete temp files that are no longer needed.")

if result.interruptions:
    state = result.to_state()
    for interruption in result.interruptions:
        state.approve(interruption)
    result = await Runner.run(agent, state)

For streaming runs, finish consuming stream_events() first, then inspect result.interruptions and resume from result.to_state(). For the full approval flow, see Human-in-the-loop.

Server-managed continuation

last_response_id is the latest model response ID from the run. Pass it back as previous_response_id on the next turn when you want to continue an OpenAI Responses API chain.

If you already continue the conversation with to_input_list(), session, or conversation_id, you usually do not need last_response_id. If you need every model response from a multi-step run, inspect raw_responses instead.

Agent-as-tool metadata

When a result comes from a nested Agent.as_tool() run, agent_tool_invocation exposes immutable metadata about the outer tool call:

  • tool_name
  • tool_call_id
  • tool_arguments

For ordinary top-level runs, agent_tool_invocation is None.

This is especially useful inside custom_output_extractor, where you may need the outer tool name, call ID, or raw arguments while post-processing the nested result. See Tools for the surrounding Agent.as_tool() patterns.

If you also need the parsed structured input for that nested run, read context_wrapper.tool_input. That is the field RunState serializes generically for nested tool input, while agent_tool_invocation is the live result accessor for the current nested invocation.

Streaming lifecycle and diagnostics

RunResultStreaming inherits the same result surfaces above, but adds streaming-specific controls:

Keep consuming stream_events() until the async iterator finishes. A streaming run is not complete until that iterator ends, and summary properties such as final_output, interruptions, raw_responses, and session-persistence side effects may still be settling after the last visible token arrives.

If you call cancel(), continue consuming stream_events() so cancellation and cleanup can finish correctly.

Python does not expose a separate streamed completed promise or error property. Terminal streaming failures are surfaced by raising from stream_events(), and is_complete reflects whether the run has reached its terminal state.

Raw responses

raw_responses contains the raw model responses collected during the run. Multi-step runs can produce more than one response, for example across handoffs or repeated model/tool/model cycles.

last_response_id is just the ID from the last entry in raw_responses.

Guardrail results

Agent-level guardrails are exposed as input_guardrail_results and output_guardrail_results.

Tool guardrails are exposed separately as tool_input_guardrail_results and tool_output_guardrail_results.

These arrays accumulate across the run, so they are useful for logging decisions, storing extra guardrail metadata, or debugging why a run was blocked.

Context and usage

context_wrapper exposes your app context together with SDK-managed runtime metadata such as approvals, usage, and nested tool_input.

Usage is tracked on context_wrapper.usage. For streamed runs, the usage totals can lag until the stream's final chunks have been processed. See Context management for the full wrapper shape and persistence caveats.