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-injectedcustommessage 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
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)