Skip to content

The agent loop

AgentLoop

class AgentLoop(config: AgentLoopConfig, emit: Callable[[AgentEvent], Awaitable[None]] | None = None, tools: list[AgentTool] | None = None, model: Any = None, abort_signal: AbortSignal | None = None, hook_dispatcher: ExtensionRunner | None = None, steer_queue: list[Any] | None = None)

tau_agent_core.agent_loop.AgentLoop

The core agent loop.

Drives conversations, executes tools, and emits events.

Reference: PHASE-2-SUBPHASE-1.md, "Implementation Outline" section. Reference: SUBPHASE-0.0.md, "5. Agent Events" section.

Constructor parameters

  • config: AgentLoopConfig — Agent loop configuration.
  • emit: Callable[[AgentEvent], Awaitable[None]] | None = None — Callback to emit AgentEvents (fire-and-forget; returns None).
  • tools: list[AgentTool] | None = None — (no description)
  • model: Any = None — (no description)
  • abort_signal: AbortSignal | None = None — (no description)
  • hook_dispatcher: ExtensionRunner | None = None — (no description)
  • steer_queue: list[Any] | None = None — (no description)

add_tool

add_tool(tool: AgentTool) -> None

tau_agent_core.agent_loop.AgentLoop.add_tool

Add a tool to the agent loop.

Parameters

  • tool: AgentTool — The AgentTool to register.

has_hook_handlers

has_hook_handlers(event: str) -> bool

tau_agent_core.agent_loop.AgentLoop.has_hook_handlers

Whether any extension has a handler for the mutating hook event.

The zero-extension fast path (pi agent-session.ts:407-411): the four hook call-sites (S11-S14) call this before dispatching so a session with no extensions — or a standalone loop with no injected dispatcher — does no hook work at all. Returns False when no dispatcher was injected.

Parameters

  • event: str — (no description)

run

run(prompts: list[Any], context: list[Any] | None = None) -> list[Any]

tau_agent_core.agent_loop.AgentLoop.run

Run the full agent loop for one or more prompts.

This is the main entry point. It: 1. Emits agent_start 2. Adds prompt messages to context 3. Loops: call LLM, execute tool calls, repeat until done 4. Emits agent_end with final messages

Parameters

  • prompts: list[Any] — Messages to start with — user messages, and any extension-injected custom message dicts (serialized custom→user at the wire by _stream_response).
  • context: list[Any] | None = None — Existing message history.

Returns

List of messages produced by the agent loop.

run_continue

run_continue(context: list[Any] | None = None) -> list[Any]

tau_agent_core.agent_loop.AgentLoop.run_continue

Run another agent turn without adding new messages.

Similar to run() but does not add new prompts. Used for follow-up turns.

Parameters

  • context: list[Any] | None = None — Existing message history.

Returns

List of messages produced.

AgentLoopConfig

tau_agent_core.agent_loop_types.AgentLoopConfig

Configuration for the agent loop.

api_key

tau_agent_core.agent_loop_types.AgentLoopConfig.api_key: str | None

API key forwarded to the provider (None = use env/provider default)

max_retries

tau_agent_core.agent_loop_types.AgentLoopConfig.max_retries: int

Maximum retry attempts for failed tool calls

max_turns

tau_agent_core.agent_loop_types.AgentLoopConfig.max_turns: int | None

Turn ceiling, or None (the default) for no ceiling

model

tau_agent_core.agent_loop_types.AgentLoopConfig.model: str | None

Model identifier (e.g., "gpt-4o")

reasoning

tau_agent_core.agent_loop_types.AgentLoopConfig.reasoning: str | None

Requested thinking level ("off".."xhigh"), or None

repeat_tool_call_limit

tau_agent_core.agent_loop_types.AgentLoopConfig.repeat_tool_call_limit: int | None

How many turns in a row may repeat the same wholly-failing batch of tool calls before the loop stops itself. Default 3; None disables the check.

system_prompt

tau_agent_core.agent_loop_types.AgentLoopConfig.system_prompt: str | None

System prompt for the agent

temperature

tau_agent_core.agent_loop_types.AgentLoopConfig.temperature: float | None

Sampling temperature, or None (the default) to send none

tool_execution_mode

tau_agent_core.agent_loop_types.AgentLoopConfig.tool_execution_mode: Literal['sequential', 'parallel']

How tools are executed

BlockedCall

class BlockedCall(call: PreparedToolCall, error: str, blocked_by_extension: str | None = None)

tau_agent_core.agent_loop.BlockedCall

A tool call that was blocked (e.g., argument validation failed).

blocked_by_extension names the extension that VETOED the call via a tool_call hook (S50, anchor G11); it is None for a block that is NOT an extension veto (argument-validation failure, fail-closed handler throw) — those stay a generic errored result rather than the "⛔ blocked by " render.

Constructor parameters

  • call: PreparedToolCall — (no description)
  • error: str — (no description)
  • blocked_by_extension: str | None = None — (no description)

ErrorCall

class ErrorCall(call: PreparedToolCall, error: str)

tau_agent_core.agent_loop.ErrorCall

A tool call that raised an error during preparation.

Constructor parameters

  • call: PreparedToolCall — (no description)
  • error: str — (no description)

FinalizedToolCall

tau_agent_core.agent_loop_types.FinalizedToolCall

A tool call after execution has completed.

Created when the agent loop finishes executing a PreparedToolCall.

arguments

tau_agent_core.agent_loop_types.FinalizedToolCall.arguments: dict[str, Any]

The arguments that were passed

id

tau_agent_core.agent_loop_types.FinalizedToolCall.id: str

The tool call ID

is_error

tau_agent_core.agent_loop_types.FinalizedToolCall.is_error: bool

Whether the execution failed

name

tau_agent_core.agent_loop_types.FinalizedToolCall.name: str

Name of the tool that was executed

result

tau_agent_core.agent_loop_types.FinalizedToolCall.result: Any | None

The execution result (from the tool)

PreparedToolCall

tau_agent_core.agent_loop_types.PreparedToolCall

A tool call prepared for execution, extracted from LLM response.

Created when the agent loop receives a tool call from the model. Before execution, the tool call is validated and wrapped in this type.

arguments

tau_agent_core.agent_loop_types.PreparedToolCall.arguments: dict[str, Any]

Validated arguments dict (parsed from model output)

id

tau_agent_core.agent_loop_types.PreparedToolCall.id: str

Unique tool call ID (from model response)

name

tau_agent_core.agent_loop_types.PreparedToolCall.name: str

Name of the tool to execute

completed_messages

completed_messages(exc: BaseException) -> list[Any]

tau_agent_core.agent_loop.completed_messages

The messages an agent-loop run had already completed when exc ended it.

Empty for any other exception, so a caller can ask unconditionally. The caller that matters is :meth:~tau_agent_core.agent_session.AgentSession._run_one_turn, which persists these before re-raising — the requirement in docs/PLAN-0.9.4.md §3: every complete message or tool result should be persisted.

Parameters

  • exc: BaseException — (no description)