Tool loop
Type: kb/types/tag-readme.md · Tags: computational-model, context-engineering, tool-loop
Many LLM applications share a common operational core: construct a task frame, give the model tools, and loop until it stops.
state = initial_task_frame()
while not done(state):
turn = llm_call(state, tools=tools)
if turn.type == "tool_request":
result = execute_tool(turn.request)
state = absorb(state, turn.request, result)
else:
state = absorb(state, turn.output)
Frameworks own this loop because the mechanics are repetitive protocol work — parsing tool requests, dispatching to handlers, serializing results, feeding them back, handling streaming and retries. Abstracting that away is good engineering, just as abstracting HTTP parsing is. In the bounded-context orchestration model this loop is the singleton-batch case with select frozen to one policy — append the result, re-ask with the same tools — owned by the framework rather than the application. Keeping that loop optional is the design stance these notes argue for.
Many useful interventions can stay hidden inside this loop without changing its structure: logging, approvals, budget checks, checkpoints, deterministic transforms on tool results. A stateful singleton runtime behind the tool boundary can go further, holding recursion state and branch records. The recovery is genuine — but the question is not whether the loop can absorb bookkeeping. It is who gets to decide what the next step can do.
Pressure and forcing cases
Three cases expose where progression authority lives. The first two can make a single framework-owned loop insufficient; the third distinguishes a scheduler's role from its callable interface:
- subtasks that need different tools force loop exposure in agent frameworks — decomposition creates children that need different capability surfaces; the parent must construct fresh calls with different tool sets, which a fixed loop cannot express
- semantic sub-goals that exceed one context window become scheduling problems — some sub-goals require deterministic orchestration over smaller semantic judgments because the material doesn't fit in one bounded call
- cross-task transition policy remains scheduling behind a tool interface — codifying cross-task progression creates scheduler logic wherever that logic is placed; a tool interface hides the role only when it obscures the progression authority
Resolution
The first case calls for sub-agents — fresh tool loops with their own prompt, capability surface, and stop condition. The second calls for something more: symbolic composition of agents — code-controlled iteration, filtering, and aggregation over multiple agent invocations. The third is placement-neutral: an application loop, lower-level runtime, or explicitly named workflow tool can own the codified transitions, but the tool protocol does not make that responsibility ordinary capability implementation. Sub-agents are the atomic unit; symbolic orchestration is what the application does with them.
The framework's job is therefore to keep the tool loop optional: run the frozen loop for the common case, but expose the bounded call beneath it so application code can spawn child loops and compose them. The mechanism is small — the practical scheduler is the host language: demote the loop to a returning, per-call-parameterized agent() call (plus one tool-execution hook), and ordinary host-language control flow becomes select while its variables hold K. ("Expose the loop" was the earlier name for this same move.) A further question, once orchestrators are written this way, is what to retain across runs: run-state stays ephemeral while recurring strategies are the promotion target.
Downstream consequences
- session history should not be the default next context — sub-tasks should start with constructed prompts, not inherit the parent's full conversation
- final task success does not establish intended-path health — when primary and fallback success share one terminal state, the parent needs independent path evidence to distinguish them
- Designing a Memory System for LLM-Based Agents — applies the fallback/recovery problem to memory extraction: successful runs can still teach the system about broken primary paths and degraded guarantees
-
silent disambiguation is the semantic analogue of tool fallback — the same observability problem for ambiguous specs rather than broken tools
-
conversation vs prompt refinement in agent-to-agent coordination — once sub-agents exist, the parent must choose how results come back: trace preservation, compression, or context forking
Related approaches
- RLM has the model write ephemeral orchestrators over sub-agents — boundary case: the model writes an ephemeral symbolic orchestrator that composes agents via
recursive_llm()— the loop is exposed to the model rather than the programmer, but discarded after each run - Claude Code dynamic workflows — shipped instance: a harness exposing a returning
agent()plus host-language composition beneath its frozen loop — RLM's authorship model with persistence added, but in a sandboxed guest language, with capability surfaces, the dispatch interior, and the inter-workflow seams still framework-owned
Relevant Notes:
- bounded-context orchestration model — foundation: the framework-owned tool loop is a singleton-batch selection policy inside the scheduling model
- llm-mediated schedulers are a degraded variant of the clean model — consequence: workarounds for hidden loops push scheduling into the conversational medium
- "agent" is a tool loop — convention: grounds the sub-agent mechanism by equating "agent" with "tool loop"
- agent orchestration occupies a multi-dimensional design space — broader context: the tool loop is one dimension; scheduler placement, persistence, coordination form, and return artifacts vary independently
Other tagged notes
- Agent orchestration needs a privilege quarantine, not just a permission scope - When one agent in an orchestration reads untrusted content, the defense is a role-level privilege quarantine — barring that agent from high-privilege actions entirely — not finer per-call tool scoping
- Compiling a coordination strategy preserves primitive authority but expands aggregate authority - Compiling a coordination strategy preserves the primitive action alphabet but expands aggregate authority — the single-context envelope it escapes bounded both compute and effect volume
- The chat-history model trades context efficiency for implementation simplicity - Chat history persists because appending messages preserves information and avoids interface design, but that convenience trades away selective loading under bounded context