Agent Loop¶
The AgentLoop is the intended execution boundary for all tool-calling work. You write the outer LLM loop (calling the model, managing message history, enforcing iteration limits); AgentLoop.process_turn handles everything between LLM responses—concurrent tool dispatch via asyncio.gather and state-change-gated context re-rendering.
Calling ToolRegistry.invoke directly is fine for unit tests, but production loops should go through process_turn to get concurrent dispatch and context management for free.
Turn Lifecycle¶
flowchart TB
A["TurnInput<br/>(role, content, tool_calls)"] --> B["Render Context"]
B --> C["Execute Tool Calls<br/>(concurrent)"]
C --> D{State changed?}
D -->|yes| E["Re-render Context"]
D -->|no| F["Return TurnResult"]
E --> F
Usage¶
from hybi.agent import AgentSession, AgentLoop, TurnInput, ToolCall
session = AgentSession.create(hb)
loop = AgentLoop(session)
# Build a turn from parsed LLM output
turn = TurnInput(
role="assistant",
content="Let me search for that.",
tool_calls=[
ToolCall(id="call_1", name="search", arguments={"query": "kinase inhibitors"}),
ToolCall(id="call_2", name="list_collections", arguments={}),
],
)
# Process the turn
result = await loop.process_turn(turn)
# Inspect results
for tr in result.tool_results:
print(tr.success, tr.data)
# Context snapshots (empty string if skip_render=True)
print(result.context_before)
print(result.context_after) # only populated if state_changed
print(result.state_changed) # True if a mutating tool succeeded
# (ingest, mutate, manage, connect, or external)
Single Tool Execution¶
# Execute one tool call outside the full turn cycle
call = ToolCall(id="call_1", name="explore", arguments={"collection": "drugs"})
result = await loop.execute_tool_call(call)
AgentLoop¶
hybi.agent.loop.AgentLoop
¶
Executes the per-turn agent cycle.
The loop coordinates between the tool registry and context renderer. The LLM generation step happens externally -- this class handles tool execution and context rendering.
__init__(session)
¶
process_turn(turn, *, skip_render=False)
async
¶
Process a single conversational turn.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
turn
|
TurnInput
|
The input for this turn (user/assistant message + optional tool calls). |
required |
skip_render
|
bool
|
If True, skip render() calls (for structuring turns). |
False
|
Returns:
| Type | Description |
|---|---|
TurnResult
|
TurnResult with tool results, context snapshots, and change flag. |
execute_tool_call(call)
async
¶
Execute a single tool call outside the full turn cycle.
TurnInput¶
Input for a single agent turn.
hybi.agent.loop.TurnInput
dataclass
¶
Input for a single agent turn.
TurnResult¶
Result of a single agent turn.
hybi.agent.loop.TurnResult
dataclass
¶
Result of a single agent turn.