Skip to content
Pilotoo
v0.1

Let a tool call your own API

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.

  • A running server with PilotooModule.forRoot (see The server).
  • An API that accepts the same Authorization header your chat users send.

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.

src/invoices.tool.ts
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']) }),
},
);
}

tools receives the registry. { optIn: true } keeps the tool away from every agent that does not name it.

src/app.module.ts
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 {}
.pilotoo/agents/billing.yaml
id: billing
name: Billing
description: Answers questions about invoices.
status: active
runtime:
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: {}
  • The server resolves the caller once per request and hands the result to the run as its context. createHostFetch(config) reads the caller’s Authorization value from that context. The context is never saved with the conversation.
  • Without credentials (an anonymous local run), the returned fetch adds no header and behaves like the global one.
  • An agent with tools: null does not get opt-in tools. Only an agent that lists list_invoices does.