An agent as a tool
One agent hands part of its work to another by calling it, the way it calls any tool.
pnpm add @niscorp/cortex @niscorp/signal zod openaiThe model
createSignal makes the client that calls the model. Cortex is handed this client, here for Groq, and Signal reads the key from GROQ_API_KEY.
import { z } from 'zod';
import { createSignal } from '@niscorp/signal';
import { asTool, defineAgent, defineTool } from '@niscorp/cortex';
const llm = createSignal('groq');An agent with one tool
This agent has the tool for seats, and nothing else. Its description is what another agent’s model will read to decide when to call it.
const seatsLeft = defineTool({
id: 'seatsLeft',
name: 'seatsLeft',
description: 'How many seats are left on a night',
input: z.object({ night: z.string().describe('The night, as YYYY-MM-DD') }),
execute: ({ night }) => ({ night, left: night === '2026-10-24' ? 113 : 120 }),
});
const programme = defineAgent({
id: 'programme',
description: 'Knows how many seats are left on a night.',
instructions: 'Answer from the seatsLeft tool, in one sentence.',
tools: [seatsLeft],
});Wrap it as a tool
asTool turns an agent into an ordinary tool. When the desk’s model calls it, the programme agent runs its own loop, with its own tool, and its answer comes back as the tool’s result.
const desk = defineAgent({
id: 'desk',
instructions: 'Help the customer. Ask the programme agent about seats.',
tools: [asTool(programme, { llm, deps: undefined })],
});One stream for both
The inner agent’s events arrive in the outer run’s stream. agentPath says which agent an event came from.
const run = desk.run('Are there seats left on 2026-10-24?', { llm });
run.onEvent((event) => {
if (event.type === 'tool-start') console.log(event.agentPath.join(' > '), 'calls', event.call.toolId);
});
const result = await run.result;
console.log(result.ok ? result.output.response : result.error.message);Run it.
This file asks a model, so it is not run on this site. When the desk’s model hands the question on, it prints desk calls programme, then desk > programme calls seatsLeft, and the desk’s sentence with the 113 seats in it.
GROQ_API_KEY=your-key npx tsx delegate.mts