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 };