Agent Loop & Tool Continuation
Relevant source files
The following files were used as context for generating this wiki page:
The Agent Loop & Tool Continuation system provides the core model-agnostic execution engine for the plugsuits project. It manages the iterative process where an AI agent receives messages, generates responses, executes tool calls, and determines whether to continue the conversation or stop based on the model's finish reasons.
This system is primarily implemented in the @ai-sdk-tool/harness package, which serves as the foundational agent harness built on the Vercel AI SDK. It enables both interactive Terminal UI (TUI) and headless JSONL execution modes by providing a consistent set of loop control primitives.
Sources: packages/harness/README.md:3-8, AGENTS.md:21-31
Core Agent Loop Logic
The runAgentLoop function is the primary entry point for executing an agent. It orchestrates a loop that continues until a stop condition is met, such as reaching a maximum iteration count, receiving an abort signal, or the model determining it has finished its task.
Loop Execution Flow
The loop follows a standard sequence for each iteration:
- Model Invocation: The agent's
streammethod is called with current messages. - Result Processing: The system awaits the final response and finish reason.
- Continuation Check: The system evaluates if another iteration is required using a continuation predicate.
- Hook Execution: Optional hooks like
onToolCallandonStepCompleteare triggered during the process.
This diagram illustrates the iterative lifecycle of the runAgentLoop function.
Sources: packages/harness/src/loop.ts, packages/harness/README.md:46-77
Tool Loop Control and Continuation
A critical aspect of the agent's autonomy is its ability to continue running when it needs to process tool results. The project uses a manual tool-loop continuation strategy rather than relying solely on provider-native tool handling.
Continuation Predicates
The shouldContinueManualToolLoop function serves as the default gatekeeper. It returns true specifically when the model's finish reason is "tool-calls", signaling that the agent has initiated actions that require a response from the environment.
| Feature | Description |
|---|---|
| Manual Loop | Intentionally constrained to specific finish reasons like tool-calls and unknown. |
| Iteration Limits | Supports maxIterations to prevent infinite loops (defaulting to unlimited in the harness core). |
| Abort Support | Integrates with AbortSignal for graceful cancellation. |
Sources: packages/harness/src/tool-loop-control.ts, AGENTS.md:83-84, packages/harness/README.md:189-204
Tool Continuation Sequence
The sequence below shows how the agent interacts with the loop to handle tool calls:
Advanced Continuation Patterns
TODO Continuation Middleware
In advanced implementations like @ai-sdk-tool/cea, the loop is enhanced with a "Todo Continuation" mechanism. This ensures the agent remains active until all tasks in a todo.json file are marked as complete, even if the model itself thinks it has finished.
- Incomplete Task Check: After a model turn, the system checks for pending todos.
- Reminder Generation: If tasks remain, a reminder message is injected into the history.
- Loop Re-entry: The finish reason is forced to
"tool-calls"to trigger another iteration.
Sources: packages/cea/src/entrypoints/main.ts:333-366, packages/harness/README.md:144-162
Middleware Chain
The buildMiddlewareChain utility allows developers to wrap language model calls with cross-cutting concerns that can affect the loop, such as logging, caching, or automatic prompt modification.
const middlewares = buildMiddlewareChain({
middlewares: [loggingMiddleware, cachingMiddleware],
});
const wrappedModel = wrapLanguageModel({
model: openai("gpt-4o"),
middleware: middlewares[0],
});
Sources: packages/harness/src/middleware.ts, packages/harness/README.md:213-222
API Summary for Loop Control
| Function / Class | Location | Role |
|---|---|---|
runAgentLoop | packages/harness/src/loop.ts | The core iteration engine for the agent. |
shouldContinueManualToolLoop | packages/harness/src/tool-loop-control.ts | Predicate that returns true on "tool-calls". |
normalizeFinishReason | packages/harness/src/tool-loop-control.ts | Maps provider-specific strings to canonical reasons. |
TodoContinuation | packages/harness/README.md | Logic for continuing the loop based on task status. |
buildMiddlewareChain | packages/harness/src/middleware.ts | Composable chain for model call interception. |
Sources: packages/harness/src/loop.ts, packages/harness/src/tool-loop-control.ts, packages/harness/src/middleware.ts, packages/harness/README.md:206-211
The Agent Loop and Tool Continuation system ensures that the plugsuits agents can autonomously perform complex, multi-step coding tasks by providing a robust framework for managing state, tool execution, and lifecycle control across different execution environments.