> ## Documentation Index
> Fetch the complete documentation index at: https://thethirdpenco-feat-tool-lifecycle-events.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# AgentTurn

> API reference for live agent turn execution

`AgentTurn` represents one live execution of an `Agent`.

Create one with `agent.turn(...)`. Do not instantiate `AgentTurn` directly unless you are extending the framework.

## Import

```python theme={null}
from ai_query.agents import AgentTurn, TurnOptions, TurnResult
```

## Constructor

```python theme={null}
AgentTurn(
    agent: Agent[Any],
    message: Content,
    *,
    options: TurnOptions | None = None,
) -> None
```

Normally called internally by:

```python theme={null}
turn = agent.turn("Fix the failing test")
```

## Properties

<ResponseField name="id" type="str">
  Unique turn ID.
</ResponseField>

<ResponseField name="agent_id" type="str">
  ID of the owning agent.
</ResponseField>

<ResponseField name="agent" type="Agent[Any]">
  Owning agent instance.
</ResponseField>

<ResponseField name="message" type="Message">
  Initial user message for the turn.
</ResponseField>

<ResponseField name="options" type="TurnOptions">
  Per-turn options.
</ResponseField>

<ResponseField name="started" type="bool">
  `True` after the turn has started.
</ResponseField>

<ResponseField name="done" type="bool">
  `True` after the turn finishes, fails, or is aborted.
</ResponseField>

## events

```python theme={null}
async def events(self) -> AsyncIterator[TurnEvent]
```

Starts the turn if needed and yields typed lifecycle events.

```python theme={null}
async for event in turn.events():
    ...
```

Common event types:

| Type                                                 | Meaning                                                                                                            |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `turn.started`                                       | The turn was created and user input was appended.                                                                  |
| `step.started`                                       | A model step is about to run.                                                                                      |
| `text.delta`                                         | Assistant answer text.                                                                                             |
| `reasoning.delta`                                    | Provider reasoning output or metadata; inspect `event.event.kind` for `summary`, `delta`, `signature`, or `state`. |
| `tool_call.started` / `tool_call.delta`              | Provider tool-call fragments, when available.                                                                      |
| `tool_call.ready`                                    | A normalized `ToolCall` is ready for execution or error handling.                                                  |
| `tool_execution.started` / `tool_execution.finished` | Local tool function execution lifecycle.                                                                           |
| `tool_result`                                        | Final tool result after hooks, in provider order.                                                                  |
| `step.finished`                                      | The model step was persisted.                                                                                      |
| `turn.finished` / `turn.failed`                      | Terminal turn outcome.                                                                                             |

Returns:

<ResponseField name="AsyncIterator[TurnEvent]" type="AsyncIterator[TurnEvent]">
  Stream of turn events. The iterator ends after `turn.finished` or `turn.failed`.
</ResponseField>

## text\_stream

```python theme={null}
async def text_stream(self) -> AsyncIterator[str]
```

Convenience stream over `events()` that yields only `text.delta` text.

```python theme={null}
async for chunk in turn.text_stream():
    print(chunk, end="")
```

## result

```python theme={null}
async def result(self) -> TurnResult
```

Starts the turn if needed and waits for the structured result.

Returns:

<ResponseField name="TurnResult" type="TurnResult">
  Final structured result.
</ResponseField>

Raises:

<ResponseField name="AbortError" type="Exception">
  Raised if the turn is aborted.
</ResponseField>

<ResponseField name="Exception" type="Exception">
  Propagates provider, tool, or runtime failures.
</ResponseField>

## wait

```python theme={null}
async def wait(self) -> TurnResult
```

Alias for `result()`.

## send

```python theme={null}
async def send(
    self,
    message: Content,
    *,
    role: Literal["user", "system"] = "user",
) -> None
```

Queues a steering message for the next safe step boundary.

Parameters:

<ParamField path="message" type="Content" required>
  Message content to inject into the active turn.
</ParamField>

<ParamField path="role" type="Literal['user', 'system']">
  Role for the injected message. Defaults to `"user"`.
</ParamField>

Notes:

* `send()` does not mutate a provider request already in flight.
* queued messages are injected before the next model call.
* queued messages are scoped to this turn.

## steer

```python theme={null}
async def steer(
    self,
    message: Content,
    *,
    role: Literal["user", "system"] = "user",
) -> None
```

Alias for `send()`.

## abort

```python theme={null}
def abort(self, reason: str | None = None) -> None
```

Aborts the turn.

Parameters:

<ParamField path="reason" type="str | None">
  Optional abort reason.
</ParamField>

## TurnOptions

```python theme={null}
@dataclass
class TurnOptions:
    tools: ToolSet | None = None
    stop_when: StopCondition | list[StopCondition] | None = None
    reasoning: ReasoningConfig | None = None
    provider_options: ProviderOptions | None = None
    retry: RetryPolicy | None = None
    signal: AbortSignal | None = None
    hooks: AgentHooks | None = None
    metadata: dict[str, Any] = field(default_factory=dict)
```

Fields:

<ParamField path="tools" type="ToolSet | None">
  Per-turn tools. Defaults to the agent's tools.
</ParamField>

<ParamField path="stop_when" type="StopCondition | list[StopCondition] | None">
  Per-turn stop conditions. Defaults to the agent's `stop_when`.
</ParamField>

<ParamField path="reasoning" type="ReasoningConfig | None">
  Per-turn reasoning controls. Defaults to the agent's `reasoning`.
</ParamField>

<ParamField path="provider_options" type="ProviderOptions | None">
  Per-turn provider options. Defaults to the agent's `provider_options`.
</ParamField>

<ParamField path="retry" type="RetryPolicy | None">
  Per-turn provider-call retry policy. Defaults to the agent's `retry`.
</ParamField>

<ParamField path="signal" type="AbortSignal | None">
  External abort signal that also aborts the turn.
</ParamField>

<ParamField path="hooks" type="AgentHooks | None">
  Per-turn hook overrides. These merge over agent-level default hooks.
</ParamField>

<ParamField path="metadata" type="dict[str, Any]">
  Application metadata. Not sent to the provider by default.
</ParamField>

## TurnResult

```python theme={null}
@dataclass
class TurnResult:
    turn_id: str
    agent_id: str
    text: str
    finish_reason: str | None
    usage: Usage | None
    steps: list[StepResult]
    started_at: float
    ended_at: float
    output_message: Message
```

## TurnEvent

```python theme={null}
TurnEvent = (
    TurnStarted
    | TextDelta
    | ReasoningDelta
    | StepStarted
    | StepRetrying
    | ToolCallStartedEvent
    | ToolCallDeltaEvent
    | ToolCallReadyEvent
    | ToolExecutionStartedEvent
    | ToolExecutionFinishedEvent
    | ToolResultEvent
    | StepFinished
    | TurnFinished
    | TurnFailed
)
```

### TurnStarted

```python theme={null}
@dataclass
class TurnStarted:
    type: Literal["turn.started"]
    turn_id: str
    agent_id: str
    message: Message
    created_at: float
```

### TextDelta

```python theme={null}
@dataclass
class TextDelta:
    type: Literal["text.delta"]
    text: str
```

### ReasoningDelta

```python theme={null}
@dataclass
class ReasoningDelta:
    type: Literal["reasoning.delta"]
    event: ReasoningEvent
```

### StepStarted

```python theme={null}
@dataclass
class StepStarted:
    type: Literal["step.started"]
    step_number: int
```

### StepFinished

```python theme={null}
@dataclass
class StepFinished:
    type: Literal["step.finished"]
    step_number: int
    step: StepResult
    usage: Usage | None
```

`usage` is the provider-reported usage for this step.

### StepRetrying

```python theme={null}
@dataclass
class StepRetrying:
    type: Literal["step.retrying"]
    step_number: int
    attempt: int
    max_attempts: int
    delay: float
    error: str
```

### Tool lifecycle events

`AgentTurn` forwards the same `ToolCallStartedEvent`, `ToolCallDeltaEvent`,
`ToolCallReadyEvent`,
`ToolExecutionStartedEvent`, `ToolExecutionFinishedEvent`, and `ToolResultEvent`
objects exposed by `stream_text().event_stream`. This preserves tool call IDs,
provider indexes, execution completion order, and normalized results across core
and agent APIs.

### TurnFinished

```python theme={null}
@dataclass
class TurnFinished:
    type: Literal["turn.finished"]
    result: TurnResult
```

### TurnFailed

```python theme={null}
@dataclass
class TurnFailed:
    type: Literal["turn.failed"]
    error: str
```

## Example

```python theme={null}
turn = agent.turn("Fix the failing test")

async for event in turn.events():
    match event.type:
        case "text.delta":
            print(event.text, end="", flush=True)
        case "step.started":
            print(f"step {event.step_number}")
        case "step.retrying":
            print(f"retrying step {event.step_number}, attempt {event.attempt}")
        case "turn.failed":
            print(event.error)

result = await turn.result()
```

## See Also

* [Hooks](/core/hooks)
* [Agent](/reference/agent)
* [Live Turns](/core/live-turns)
* [Results](/reference/types/results)
