Overview
LoopAgent runs its sub-agents in a loop, allowing for iterative refinement and multi-pass processing. The loop continues until:
A sub-agent escalates (signals completion)
Maximum iterations are reached
An error occurs
Basic Usage
import { AgentBuilder , LlmAgent } from '@iqai/adk' ;
const analyzer = new LlmAgent ({
name: 'analyzer' ,
description: 'Analyzes data quality' ,
instruction: 'Check if data quality is sufficient' ,
outputKey: 'quality_score' ,
model: 'gemini-2.5-flash'
});
const improver = new LlmAgent ({
name: 'improver' ,
description: 'Improves data' ,
instruction: 'Improve data based on quality score: {quality_score}' ,
model: 'gemini-2.5-flash'
});
const { runner } = await AgentBuilder
. create ( 'improvement-loop' )
. asLoop ([ analyzer , improver ], 3 ) // Max 3 iterations
. build ();
const result = await runner . ask ( 'Improve this text: ...' );
Creating a LoopAgent
Using AgentBuilder
const { runner } = await AgentBuilder
. create ( 'loop-workflow' )
. asLoop (
[ agent1 , agent2 , agent3 ],
5 // Maximum 5 iterations
)
. build ();
Direct Construction
import { LoopAgent , LlmAgent } from '@iqai/adk' ;
const loop = new LoopAgent ({
name: 'iterative-processor' ,
description: 'Processes data iteratively' ,
subAgents: [
evaluatorAgent ,
refinementAgent
],
maxIterations: 10
});
Configuration
interface LoopAgentConfig {
// Required
name : string ;
description : string ;
// Sub-agents to loop through
subAgents ?: BaseAgent [];
// Maximum iterations (optional)
maxIterations ?: number ;
}
Max Iterations
// Infinite loop (until escalate)
const infiniteLoop = new LoopAgent ({
name: 'infinite' ,
description: 'Loops until done' ,
subAgents: [ agent1 , agent2 ]
// No maxIterations - runs until escalate
});
// Limited iterations
const limitedLoop = new LoopAgent ({
name: 'limited' ,
description: 'Loops up to 5 times' ,
subAgents: [ agent1 , agent2 ],
maxIterations: 5 // Stops after 5 iterations
});
Without maxIterations, the loop runs indefinitely until a sub-agent escalates. Always consider adding a maximum to prevent infinite loops.
Escalation (Early Exit)
Sub-agents can signal completion by escalating:
import { LlmAgent } from '@iqai/adk' ;
const checker = new LlmAgent ({
name: 'quality_checker' ,
description: 'Checks if quality is sufficient' ,
instruction: `
Check the quality score in state.
If quality > 0.8, escalate to signal completion.
Otherwise, continue processing.
` ,
model: 'gemini-2.5-flash'
});
const improver = new LlmAgent ({
name: 'improver' ,
description: 'Improves quality' ,
instruction: 'Improve the content' ,
outputKey: 'quality_score' ,
model: 'gemini-2.5-flash'
});
const { runner } = await AgentBuilder
. create ( 'quality-loop' )
. asLoop ([ checker , improver ], 10 )
. build ();
Escalation is triggered when an event has actions.escalate set to true. This is typically done through specific tool calls or model instructions.
Execution Flow
// Iteration 1:
// - agent1 runs
// - agent2 runs
// - agent3 runs
// Iteration 2:
// - agent1 runs
// - agent2 runs
// - agent3 runs (escalates)
// Loop stops
The loop executes all sub-agents in sequence, then repeats until:
After each sub-agent runs, check if it escalated
After completing all sub-agents, check if maxIterations reached
If neither condition met, start next iteration
Use Cases
Iterative Refinement
const drafter = new LlmAgent ({
name: 'drafter' ,
description: 'Drafts content' ,
instruction: 'Create a draft or improve existing draft' ,
outputKey: 'draft' ,
model: 'gemini-2.5-flash'
});
const critic = new LlmAgent ({
name: 'critic' ,
description: 'Critiques content' ,
instruction: 'Critique this draft: {draft}. If excellent, escalate.' ,
outputKey: 'feedback' ,
model: 'gpt-4'
});
const { runner } = await AgentBuilder
. create ( 'writing-loop' )
. asLoop ([ drafter , critic ], 5 )
. withQuickSession ({ state: { draft: '' } })
. build ();
const result = await runner . ask ( 'Write an article about AI' );
Quality Checking
const processor = new LlmAgent ({
name: 'processor' ,
description: 'Processes data' ,
instruction: 'Process the input data' ,
outputKey: 'processed' ,
model: 'gemini-2.5-flash'
});
const validator = new LlmAgent ({
name: 'validator' ,
description: 'Validates output' ,
instruction: 'Validate quality. If > 90%, escalate.' ,
outputKey: 'quality' ,
model: 'gemini-2.5-flash'
});
const { runner } = await AgentBuilder
. create ( 'validation-loop' )
. asLoop ([ processor , validator ], 3 )
. build ();
Search and Verify
import { createTool } from '@iqai/adk' ;
import { z } from 'zod' ;
const searchTool = createTool ({
name: 'search' ,
description: 'Search for information' ,
schema: z . object ({
query: z . string ()
}),
fn : async ({ query }) => {
// Search implementation
return { results: [] };
}
});
const searcher = new LlmAgent ({
name: 'searcher' ,
description: 'Searches for information' ,
instruction: 'Search for relevant information' ,
tools: [ searchTool ],
outputKey: 'search_results' ,
model: 'gemini-2.5-flash'
});
const verifier = new LlmAgent ({
name: 'verifier' ,
description: 'Verifies information' ,
instruction: 'Verify results: {search_results}. If sufficient, escalate.' ,
model: 'gpt-4'
});
const { runner } = await AgentBuilder
. create ( 'search-verify-loop' )
. asLoop ([ searcher , verifier ], 5 )
. build ();
State Management
Loop agents share state across iterations:
const iteration1 = new LlmAgent ({
name: 'counter' ,
description: 'Increments counter' ,
instruction: `
Get the current count from state (default 0).
Increment by 1.
If count >= 3, escalate.
` ,
outputKey: 'count' ,
model: 'gemini-2.5-flash'
});
const { runner } = await AgentBuilder
. create ( 'counter-loop' )
. asLoop ([ iteration1 ], 10 )
. withQuickSession ({ state: { count: 0 } })
. build ();
// Loop will run 3 times:
// Iteration 1: count = 1
// Iteration 2: count = 2
// Iteration 3: count = 3, escalates
Differences from Other Agents
Feature LoopAgent SequentialAgent ParallelAgent Execution Loops until done Runs once Runs once Iterations Multiple Single Single State Accumulates Passes through Isolated Early Exit Escalate No No Use Case Refinement Pipeline Concurrency
Live Mode
Live mode (audio/video) is not yet supported for LoopAgent. Attempting to use runLive() will throw an error: const loop = new LoopAgent ({
name: 'loop' ,
description: 'Loop agent' ,
subAgents: [ agent1 ]
});
// This will throw an error
for await ( const event of loop . runLive ( context )) {
// Error: "This is not supported yet for LoopAgent."
}
Best Practices
Always Set Max Iterations
// Good
const loop = new LoopAgent ({
name: 'loop' ,
description: 'Safe loop' ,
subAgents: [ agent1 , agent2 ],
maxIterations: 10 // Safety limit
});
// Risky
const loop = new LoopAgent ({
name: 'loop' ,
description: 'Risky loop' ,
subAgents: [ agent1 , agent2 ]
// No max - could loop forever
});
Implement Clear Exit Conditions
Make escalation conditions explicit:
const checker = new LlmAgent ({
name: 'checker' ,
description: 'Checks completion' ,
instruction: `
Check the quality score in state.
If score >= 0.9:
- Set 'completed' to true in state
- Escalate to exit the loop
Otherwise:
- Continue to next iteration
` ,
model: 'gemini-2.5-flash'
});
Use Output Keys for Iteration
const agents = [
new LlmAgent ({
name: 'processor' ,
description: 'Processes data' ,
outputKey: 'iteration_result' ,
model: 'gemini-2.5-flash'
}),
new LlmAgent ({
name: 'evaluator' ,
description: 'Evaluates result' ,
instruction: 'Evaluate: {iteration_result}' ,
outputKey: 'evaluation' ,
model: 'gemini-2.5-flash'
})
];
const { runner } = await AgentBuilder
. create ( 'loop' )
. asLoop ( agents , 5 )
. build ();
Track how many iterations run:
const counter = new LlmAgent ({
name: 'counter' ,
description: 'Tracks iterations' ,
instruction: `
Get current iteration count from state.
Increment by 1.
Log the iteration number.
Check if work is complete.
` ,
outputKey: 'iteration_count' ,
model: 'gemini-2.5-flash'
});
Advanced Example
import { AgentBuilder , LlmAgent , createTool } from '@iqai/adk' ;
import { z } from 'zod' ;
// Tool to mark completion
const completeTool = createTool ({
name: 'mark_complete' ,
description: 'Mark the task as complete' ,
fn : ( _ , context ) => {
context . state . set ( 'completed' , true );
return { success: true };
}
});
// Researcher agent
const researcher = new LlmAgent ({
name: 'researcher' ,
description: 'Researches and gathers information' ,
instruction: `
Research the topic and gather information.
Add findings to the 'research' state.
` ,
outputKey: 'research' ,
model: 'gemini-2.5-flash'
});
// Analyzer agent
const analyzer = new LlmAgent ({
name: 'analyzer' ,
description: 'Analyzes research completeness' ,
instruction: `
Review the research: {research}
Check if we have enough information.
If sufficient:
- Call mark_complete tool
- Escalate to end the loop
If insufficient:
- Identify gaps
- Continue to next iteration
` ,
tools: [ completeTool ],
model: 'gpt-4'
});
// Create loop
const { runner } = await AgentBuilder
. create ( 'research-loop' )
. asLoop ([ researcher , analyzer ], 5 )
. withQuickSession ({
state: {
research: '' ,
completed: false
}
})
. build ();
// Execute
const result = await runner . ask ( 'Research quantum computing applications' );
Next Steps
Workflow Agents Other workflow patterns
LlmAgent Single agent documentation
State Management Managing state across iterations
Tools Creating tools for loop control