kirha logo

Plan and Execute

Why use plan mode

kirha.plan(query, options?) and plan.execute(options?) separate planning from execution. Instead of running a query immediately, it returns a plan showing which data providers will be called, what parameters will be used, and the estimated cost. You review the plan, and only then decide to execute it.

This is a human-in-the-loop pattern: the agent proposes a plan, a human (or your application logic) validates it, and execution only happens after explicit approval. This gives you full transparency and control over what data providers are queried and how much each request costs.

Use plan mode when you need to:

  • Control costs: review estimated charges before committing to execution
  • Human approval: let an operator inspect and approve queries before they run
  • Audit trail: log exactly which tools are called with which parameters
  • Conditional execution: decide whether to proceed based on the plan contents

Workflow

Create a plan

import { Kirha } from "kirha";

const kirha = new Kirha({ apiKey: process.env.KIRHA_API_KEY });

const plan = await kirha.plan("List top 10 stablecoins yield on Ethereum"); 

console.log(plan.id);
console.log(plan.steps);

Each step describes a tool call with its parameters and reasoning:

[
  {
    id: "step_Uwn7xvGsCTALIfJhbN1NS",
    toolName: "defillama_searchYieldPools",
    parameters: {
      chain: "Ethereum",
      stablecoin: true,
      limit: 10,
      sortBy: "apy:desc",
    },
    reasoning: "Search for the top 10 stablecoin yield pools on Ethereum, sorted by highest APY to give the user the best yield opportunities.",
  }
]

Review the plan

Steps can reference outputs from previous steps using $fromStep and $outputKey, allowing the planner to compose multiple tool calls into a pipeline.

import { Kirha } from "kirha";

const kirha = new Kirha({ apiKey: process.env.KIRHA_API_KEY });

const plan = await kirha.plan("List top 10 stablecoins yield on Ethereum");

for (const step of plan.steps) { 
  console.log(`Tool: ${step.toolName}`); 
  console.log(`Params: ${JSON.stringify(step.parameters)}`); 
  console.log(`Reason: ${step.reasoning}`); 
} 

Execute the plan

Once you're satisfied with the plan, call plan.execute() to run it.

import { Kirha } from "kirha";

const kirha = new Kirha({ apiKey: process.env.KIRHA_API_KEY });

const plan = await kirha.plan("List top 10 stablecoins yield on Ethereum");

for (const step of plan.steps) {
  console.log(`Tool: ${step.toolName}`);
  console.log(`Params: ${JSON.stringify(step.parameters)}`);
  console.log(`Reason: ${step.reasoning}`);
}

const result = await plan.execute(); 
console.log(result.data); 

Plan expiration

Plans expire 5 minutes after creation, and a plan runs only once. Executing an expired plan throws a PlanExpiredError. Create a new plan if this happens.

To execute a plan created earlier, for example after an approval step, fetch it by id with kirha.getPlan(id).execute().

Handling expired plans

import { Kirha, PlanExpiredError } from "kirha";

const kirha = new Kirha({ apiKey: process.env.KIRHA_API_KEY });

const plan = await kirha.plan("List top 10 stablecoins yield on Ethereum");

try {
  const result = await plan.execute();
} catch (error) {
  if (error instanceof PlanExpiredError) { 
    // Plan expired, create a new one
    const newPlan = await kirha.plan("List top 10 stablecoins yield on Ethereum"); 
    const result = await newPlan.execute(); 
  } 
}

Plan options

Prop

Type

Execute options

Prop

Type

SummarizationConfig

type SummarizationConfig = true | { instruction?: string };

On this page