Agent loops¶
The agent loops that drive the tool registry: a deterministic planner for tests and a provider-backed loop that lets a language model call tools, observe results, and iterate toward a design.
agent
¶
Tool-calling agent loops for the Fugacio design copilot.
Two complementary loops share one tool registry:
-
run_agent: the original model-agnostic loop. A planner callable(goal, tool_schemas, transcript) -> decisiondecides the next tool call or the final answer, wheredecisionis{"tool": name, "arguments": {...}}or{"final_answer": text}. This keeps the control flow fully testable with a scripted planner and lets any decision policy drop in. -
run_llm_agent: a real multi-turn function-calling loop over anLLMProvider(OpenAI, Anthropic, or the testMockProvider). It maintains the full message history with tool-call ids, executes every requested tool (validating arguments and capturing errors so the model can self-correct), feeds the JSON results back, and returns when the model answers in plain text.
llm_planner bridges the two: it turns a provider into a planner for the
simple loop. A deterministic heuristic_planner is provided for tests and
offline use.
Classes:
| Name | Description |
|---|---|
AgentResult |
Outcome of an agent run. |
Functions:
| Name | Description |
|---|---|
run_agent |
Run the plan/act loop until the planner returns a final answer. |
run_llm_agent |
Drive a real function-calling LLM through the tool registry to an answer. |
llm_planner |
Adapt an |
heuristic_planner |
A deterministic keyword planner: fire the first rule whose keyword is in the goal. |
AgentResult
dataclass
¶
AgentResult(
answer: str,
transcript: list[JsonDict] = list(),
stop_reason: str = "answer",
steps: int = 0,
)
Outcome of an agent run.
Attributes:
| Name | Type | Description |
|---|---|---|
answer |
str
|
The final natural-language (or structured) answer. |
transcript |
list[JsonDict]
|
Ordered tool calls with their arguments and results. |
stop_reason |
str
|
Why the loop ended ( |
steps |
int
|
Number of planner / model turns taken. |
run_agent
¶
run_agent(
goal: str,
planner: Planner,
*,
registry: dict[str, ToolSpec] | None = None,
max_steps: int = 6,
) -> AgentResult
Run the plan/act loop until the planner returns a final answer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
goal
|
str
|
The natural-language design goal. |
required |
planner
|
Planner
|
Decision function (see module docstring); inject an LLM via
|
required |
registry
|
dict[str, ToolSpec] | None
|
Tool registry to expose (defaults to |
None
|
max_steps
|
int
|
Maximum number of tool calls before giving up. |
6
|
Returns:
| Type | Description |
|---|---|
AgentResult
|
An |
run_llm_agent
¶
run_llm_agent(
goal: str,
provider: LLMProvider,
*,
registry: dict[str, ToolSpec] | None = None,
system: str = DEFAULT_SYSTEM_PROMPT,
max_steps: int = 8,
temperature: float = 0.0,
max_tokens: int = 1024,
) -> AgentResult
Drive a real function-calling LLM through the tool registry to an answer.
Maintains the full chat history with tool-call ids, executes each requested tool (validating arguments and turning errors into a JSON error result the model can recover from), and loops until the model replies with plain text or the step budget is exhausted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
goal
|
str
|
The user's natural-language request. |
required |
provider
|
LLMProvider
|
Any |
required |
registry
|
dict[str, ToolSpec] | None
|
Tool registry (defaults to |
None
|
system
|
str
|
System prompt; defaults to |
DEFAULT_SYSTEM_PROMPT
|
max_steps
|
int
|
Maximum model turns. |
8
|
temperature
|
float
|
Sampling temperature. |
0.0
|
max_tokens
|
int
|
Per-turn token cap. |
1024
|
Returns:
| Type | Description |
|---|---|
AgentResult
|
An |
llm_planner
¶
llm_planner(
provider: LLMProvider,
*,
system: str = DEFAULT_SYSTEM_PROMPT,
temperature: float = 0.0,
max_tokens: int = 1024,
) -> Planner
Adapt an LLMProvider into a Planner for run_agent.
On each call it reconstructs the conversation from the goal and transcript,
asks the model for the next step, and maps the first requested tool call to a
{"tool", "arguments"} decision (or the text reply to final_answer).
heuristic_planner
¶
A deterministic keyword planner: fire the first rule whose keyword is in the goal.
Each rule is (keyword, decision); the first keyword found in the goal
(case-insensitive) triggers its decision once. After its tool runs (or if
no rule matches), the planner returns default_answer. Useful for offline
demos and tests without an LLM.