LlamaIndex Tutorial (TypeScript): handling async tools for intermediate developers
This tutorial shows you how to wire async tools into a LlamaIndex TypeScript agent without blocking the event loop or breaking tool execution order. You need this when your agent has to call external APIs, databases, or internal services that return promises and you still want clean, predictable tool handling.
What You'll Need
- •Node.js 18+
- •A TypeScript project with
ts-nodeortsx - •
llamaindexinstalled - •An OpenAI API key set in your environment
- •Basic familiarity with LlamaIndex agents and tools
- •A terminal that can run TypeScript files directly
Install the package if you have not already:
npm install llamaindex
Set your API key:
export OPENAI_API_KEY="your-key-here"
Step-by-Step
- •Start with a minimal TypeScript file that imports the agent and tool primitives. The key point here is that your tool function can return a
Promise, and LlamaIndex will await it during execution.
import { FunctionTool, ReActAgentWorker, AgentRunner } from "llamaindex";
async function main() {
const weatherTool = FunctionTool.from(
async ({ city }: { city: string }) => {
await new Promise((resolve) => setTimeout(resolve, 500));
return `Weather in ${city}: 24°C and clear`;
},
{
name: "weather_lookup",
description: "Fetches current weather for a city",
}
);
const worker = ReActAgentWorker.fromTools([weatherTool]);
const agent = new AgentRunner({ worker });
const response = await agent.chat({
message: "What's the weather in Nairobi?",
});
console.log(response.message.content);
}
main();
- •Define tools with explicit input schemas when the arguments matter. This avoids brittle string parsing and makes async tool calls easier to validate before they hit an external service.
import { z } from "zod";
import { FunctionTool } from "llamaindex";
const accountLookupSchema = z.object({
accountId: z.string().min(3),
});
const accountLookupTool = FunctionTool.from(
async ({ accountId }: { accountId: string }) => {
await new Promise((resolve) => setTimeout(resolve, 300));
return JSON.stringify({
accountId,
status: "active",
balance: 1250.75,
});
},
{
name: "account_lookup",
description: "Fetches account details by account ID",
parameters: accountLookupSchema,
}
);
- •Combine multiple async tools and let the agent choose between them. In production, this is where you connect services like policy lookup, claims status, or customer profile APIs.
import { FunctionTool, ReActAgentWorker, AgentRunner } from "llamaindex";
const policyTool = FunctionTool.from(
async ({ policyNumber }: { policyNumber: string }) => {
await new Promise((resolve) => setTimeout(resolve, 400));
return `Policy ${policyNumber} is active until 2026-01-01`;
},
{
name: "policy_status",
description: "Checks insurance policy status",
}
);
const claimTool = FunctionTool.from(
async ({ claimId }: { claimId: string }) => {
await new Promise((resolve) => setTimeout(resolve, 400));
return `Claim ${claimId} is under review`;
},
{
name: "claim_status",
description: "Checks claim processing status",
}
);
async function main() {
const worker = ReActAgentWorker.fromTools([policyTool, claimTool]);
const agent = new AgentRunner({ worker });
const response = await agent.chat({
message: "Check policy POL123 and claim CLM456",
});
console.log(response.message.content);
}
main();
- •Wrap external calls with real error handling. Async tools fail in the real world because of timeouts, bad input, rate limits, or downstream outages, so your tool should return controlled errors instead of crashing the whole run.
import { FunctionTool } from "llamaindex";
const customerTool = FunctionTool.from(
async ({ customerId }: { customerId: string }) => {
try {
if (!customerId.startsWith("CUST-")) {
throw new Error("Invalid customer ID format");
}
await new Promise((resolve) => setTimeout(resolve, 250));
return JSON.stringify({
customerId,
tier: "gold",
region: "EU",
});
} catch (error) {
const message =
error instanceof Error ? error.message : "Unknown tool failure";
return JSON.stringify({
error: true,
message,
});
}
},
{
name: "customer_profile",
description: "Returns customer profile data safely",
}
);
- •Run the agent in a single executable file so you can test async behavior end to end. This version keeps everything together and proves that the tool awaits correctly before the final answer is generated.
import { FunctionTool, ReActAgentWorker, AgentRunner } from "llamaindex";
async function main() {
const quoteTool = FunctionTool.from(
async ({ amount }: { amount: number }) => {
await new Promise((resolve) => setTimeout(resolve, 600));
return `Premium quote for $${amount}: $${(amount * .08).toFixed(2)}`;
},
{
name: "premium_quote",
description: "Calculates an insurance premium quote",
}
);
const worker = ReActAgentWorker.fromTools([quoteTool]);
const agent = new AgentRunner({ worker });
const response = await agent.chat({
message: "Give me a premium quote for $5000",
});
console.log(response.message.content);
}
main();
Testing It
Run each file with npx tsx your-file.ts or your preferred TypeScript runner. If the async tool is wired correctly, you should see the tool’s returned data reflected in the final assistant response after the delay completes.
Test at least one success path and one failure path. For example, pass a valid ID like CUST-1001, then pass an invalid one and confirm your tool returns structured error output instead of throwing.
If you are integrating real APIs, add logs inside the tool body so you can confirm request timing and payload shape. That matters more than model output when you're debugging asynchronous execution.
Next Steps
- •Add retry logic and timeouts around external API calls inside tools
- •Use structured outputs from tools instead of plain strings for downstream parsing
- •Explore multi-tool routing patterns for claims intake, KYC checks, or policy servicing
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit