.agents/references/runner-lifecycle.md
Use this reference for changes to Runner, turn accounting, guardrails, hooks, handoffs, interruptions, cancellation, or streaming and non-streaming behavior.
A turn is one logical model invocation plus processing of that response. Tool execution, handoff resolution, session persistence, interruption resume, and retries inside that logical invocation do not independently consume turns.
get_new_response() remain part of that turn.NextStepInterruption continues the paused turn. Resolve stored approvals and tool work before deciding whether another model call is needed.max_turns and the current turn in RunState; resume must not reset the budget or charge a turn twice.RunState round-trips.SingleStepResult.next_step is the control boundary after one model response and its local side effects:
| Step | Meaning |
|---|---|
NextStepRunAgain | Continue with the current agent and make another model call |
NextStepHandoff | Switch the current agent, emit the transition, then continue |
NextStepFinalOutput | A final candidate exists; finish terminal hooks, output guardrails, persistence, and result construction |
NextStepInterruption | Persist enough processed state to resume pending approvals without rerunning completed work |
Do not bypass this state machine with path-local completion logic. New terminal or pausable behavior must define non-streaming, streaming, session, tracing, and serialized-resume semantics.
RunItemStreamEvent and AgentUpdatedStreamEvent emission must follow the same processed items and agent transitions used by the non-streaming result.stream_events() is the stream driver's cleanup boundary. Keep consuming it until exhaustion after normal completion or cancel(), or explicitly close the async iterator; merely breaking after the last visible token does not prove session writes, guardrails, compaction, sandbox cleanup, usage, or terminal errors have settled.after_turn cancellation leaves the current model/tool turn running so it can persist state and usage before the next turn. Preserve this distinction instead of treating both modes as queue shutdown.stream_events() after the required queued events are handled. Preserve run_loop_exception as a diagnostic view of the background task, not as a replacement completion primitive.task.cancel() is a request, not cleanup completion. Await cancelled tasks when their finally blocks, exceptions, or owned resources affect run correctness.NextStep outcome, including interruption resume.src/agents/run.pysrc/agents/run_internal/run_loop.pysrc/agents/run_internal/run_steps.pysrc/agents/run_internal/turn_preparation.pysrc/agents/run_internal/turn_resolution.pysrc/agents/run_internal/guardrails.pytests/test_agent_runner.pytests/test_agent_runner_streamed.pytests/test_cancel_streaming.pytests/test_guardrails.pytests/test_run_state.pydocs/streaming.mddocs/results.md