Planning enables agents to think ahead, break down complex tasks, and reason about their actions before execution. ADK-TS provides a flexible planning system through the BasePlanner interface and multiple concrete implementations.
The planner enforces specific tags in LLM responses:
// Planning tags/*PLANNING*/1. Use search tool to find current price of Bitcoin2. Use calculator to compute 5 BTC in USD3. Format and return the result/*ACTION*/search("Bitcoin price USD")/*REASONING*/The search returned $42,000 per BTC. Now I'll calculate 5 * 42,000./*ACTION*/calculate("5 * 42000")/*FINAL_ANSWER*/The value of 5 Bitcoin is $210,000 USD.
/*PLANNING*/1. Fetch user data from API2. Process and analyze/*ACTION*/fetchUserData(userId)/*REASONING*/The API returned an error. I need to revise my plan./*REPLANNING*/1. Check if user exists in local cache2. Use cached data if available3. Otherwise inform user of API issue
The PlanReActPlanner works with any model but requires more tokens than BuiltInPlanner due to explicit planning instructions.
Planners are designed for LoopAgent, which iterates until task completion:
import { AgentBuilder, PlanReActPlanner } from '@iqai/adk';const agent = new AgentBuilder() .withName('ResearchAgent') .withModel('gpt-4') .withInstruction(` You are a research assistant. Use available tools to gather information and provide comprehensive answers. `) .withTools([webSearchTool, calculatorTool, noteTakingTool]) .withPlanner(new PlanReActPlanner()) .buildLoop(); // Important: Use buildLoop() for planningconst response = await agent.ask( 'What is the current market cap of Tesla and how does it compare to Ford?');
for await (const event of agent.runAsync(context)) { // Check for planning/reasoning parts if (event.content?.parts) { for (const part of event.content.parts) { if (part.thought) { console.log('Agent thinking:', part.text); } else if (part.text) { console.log('Agent output:', part.text); } } }}
Implement custom planning strategies by extending BasePlanner:
import { BasePlanner } from '@iqai/adk';import type { Part } from '@google/genai';export class TreeOfThoughtsPlanner extends BasePlanner { buildPlanningInstruction(readonlyContext, llmRequest): string { return ` Generate multiple potential approaches to solve this problem. For each approach: 1. Outline the steps 2. Evaluate feasibility 3. Score the approach (1-10) Then, select the highest-scoring approach and execute it. Use the tag /*APPROACHES*/ for listing options. Use the tag /*SELECTED_APPROACH*/ for your choice. Use the tag /*EXECUTION*/ for implementation. `; } processPlanningResponse(callbackContext, responseParts): Part[] { const processedParts: Part[] = []; for (const part of responseParts) { if (part.text?.includes('/*APPROACHES*/') || part.text?.includes('/*SELECTED_APPROACH*/')) { // Mark as thought/reasoning part.thought = true; } if (part.functionCall) { // Allow function calls through processedParts.push(part); } else if (part.text?.includes('/*EXECUTION*/')) { // Include execution text processedParts.push(part); } } return processedParts; }}
const instruction = ` /*PLANNING*/ 1. First step 2. Second step (depends on 1) 3. Third step (depends on 2)`;
Parallel Planning
Identify independent tasks:
const instruction = ` /*PLANNING*/ Parallel tasks (can run simultaneously): - Task A: Fetch user data - Task B: Fetch product catalog - Task C: Fetch pricing info Sequential tasks (after parallel): - Task D: Merge all data - Task E: Generate recommendation`;
Conditional Planning
Branching based on results:
const instruction = ` /*PLANNING*/ 1. Check user authentication status 2a. If authenticated: Load user preferences 2b. If not authenticated: Use default settings 3. Proceed with request`;
Planners work seamlessly with tool-equipped agents:
import { AgentBuilder, PlanReActPlanner, BaseTool } from '@iqai/adk';class DatabaseTool extends BaseTool { name = 'database_query'; description = 'Execute SQL queries against the database'; async execute(context, args) { return await this.db.query(args.sql); }}const agent = new AgentBuilder() .withModel('gpt-4') .withTools([ new DatabaseTool(), new APITool(), new VisualizationTool(), ]) .withPlanner(new PlanReActPlanner()) .withInstruction(` Plan your approach before using tools. Consider which tools to use and in what order. `) .buildLoop();
class ContextAwarePlanner extends BasePlanner { buildPlanningInstruction(readonlyContext, llmRequest): string { const availableTools = llmRequest.config?.tools || []; const toolNames = availableTools.map(t => t.name).join(', '); return ` You have access to these tools: ${toolNames} Plan your approach using only these tools. Break down complex tasks into tool invocations. `; }}