kirha logo

Plan and Execute

Why use plan mode

The kirha.plan(query, options?) followed by plan.execute(options?) methods to 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,
  vertical: "crypto",
});

const plan = await kirha.plan("current portfolio of the largest USDC holder on Base"); 

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

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

[
  {
    id: "step_PGioAXmvzzmxOV0sIoBG8",
    toolName: "coingecko_searchCoin",
    parameters: {
      limit: 1,
      query: "USDC",
    },
    reasoning: "I need to find the CoinGecko ID for USDC to retrieve its contract address on the Base network.",
  }
  ...
]

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,
  vertical: "crypto",
});

const plan = await kirha.plan("current portfolio of the largest USDC holder on Base");

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,
  vertical: "crypto",
});

const plan = await kirha.plan("current portfolio of the largest USDC holder on Base");

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 after 5 minutes. Attempting to execute an expired plan throws a PlanExpiredError. Generate a new plan if this happens.

Handling expired plans

import { Kirha, PlanExpiredError } from "kirha";

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

const plan = await kirha.plan("current portfolio of the largest USDC holder on Base");

try {
  const result = await plan.execute();
} catch (error) {
  if (error instanceof PlanExpiredError) { 
    // Plan expired, create a new one
    const newPlan = await kirha.plan("current portfolio of the largest USDC holder on Base"); 
    const result = await newPlan.execute(); 
  } 
}

Plan options

Prop

Type

Execute options

Prop

Type

SummarizationConfig

Prop

Type

On this page