Let a tool call your own API
Introduction
Section titled “Introduction”You will build a tool, list_invoices, that calls your own REST API using the chat user’s credentials, so the agent only sees what that user may see. The tool is opt-in: only the agent whose YAML names it receives it.
What you need
Section titled “What you need”- A running server with
PilotooModule.forRoot(see The server). - An API that accepts the same
Authorizationheader your chat users send.
1. Write the tool
Section titled “1. Write the tool”A tool is a LangChain tool. Its second argument is the run configuration; createHostFetch(config) returns a fetch that adds the caller’s Authorization header to every request.
import { tool } from '@langchain/core/tools';import { createHostFetch } from '@pilotoo/agent-runtime';import { z } from 'zod';
export function createInvoiceTool(apiUrl: string) { return tool( async ({ status }, config) => { const hostFetch = createHostFetch(config); const response = await hostFetch(`${apiUrl}/invoices?status=${encodeURIComponent(status)}`); if (!response.ok) return `The API answered HTTP ${response.status}.`; return await response.text(); }, { name: 'list_invoices', description: "Lists the signed-in user's invoices, filtered by status.", schema: z.object({ status: z.enum(['open', 'paid', 'overdue']) }), }, );}2. Register it, opt-in
Section titled “2. Register it, opt-in”tools receives the registry. { optIn: true } keeps the tool away from every agent that does not name it.
import { Module } from '@nestjs/common';import { PilotooModule } from '@pilotoo/server';
import { createInvoiceTool } from './invoices.tool';
@Module({ imports: [ PilotooModule.forRoot({ env: process.env, tools: (registry) => { registry.register(createInvoiceTool(process.env.API_URL ?? 'http://localhost:3000'), { optIn: true }); }, }), ],})export class AppModule {}3. Give it to one agent
Section titled “3. Give it to one agent”id: billingname: Billingdescription: Answers questions about invoices.status: activeruntime: systemPrompt: >- You help the user with their invoices. Use list_invoices before answering anything about amounts or dates. profileId: default tools: [list_invoices] builtinTools: [] skills: [] knowledge: []presentation: {}How it works
Section titled “How it works”- The server resolves the caller once per request and hands the result to the run as its context.
createHostFetch(config)reads the caller’sAuthorizationvalue from that context. The context is never saved with the conversation. - Without credentials (an anonymous local run), the returned
fetchadds no header and behaves like the global one. - An agent with
tools: nulldoes not get opt-in tools. Only an agent that listslist_invoicesdoes.
Next steps
Section titled “Next steps”- Tools: registering, opt-in and the tool lifecycle.
- Sign in with your existing session: how the caller’s identity is resolved.
- Agents: the full agent YAML.