n8n/packages/@n8n/agents/examples/basic-agent.ts
2026-03-26 11:32:46 +00:00

154 lines
5.0 KiB
TypeScript

/**
* @n8n/agents — Full API Demonstration
*
* This example demonstrates the complete builder-pattern API for creating
* and running AI agents. It shows: tools, agents, memory, guardrails,
* scorers, multi-agent patterns (agent-as-tool), and tool interrupts.
*
* To run with real LLM calls, set ANTHROPIC_API_KEY.
* Without keys, the runtime will throw on actual LLM calls.
*/
import { z } from 'zod';
import { Agent, Guardrail, Memory, Tool } from '../src';
// ---------------------------------------------------------------------------
// Tools
// ---------------------------------------------------------------------------
const searchTool = new Tool('web-search')
.description('Search the web for information on a topic')
.input(
z.object({
query: z.string().describe('The search query'),
maxResults: z.number().default(3).describe('Maximum results to return'),
}),
)
.output(
z.object({
results: z.array(
z.object({
title: z.string(),
snippet: z.string(),
}),
),
}),
)
.handler(async ({ query, maxResults }) => ({
results: Array.from({ length: maxResults }, (_, i) => ({
title: `Result ${i + 1} for "${query}"`,
snippet: `This is a mock search result about ${query}.`,
})),
}));
const writeFileTool = new Tool('write-file')
.description('Write content to a file (suspends for confirmation)')
.input(
z.object({
path: z.string().describe('File path to write to'),
content: z.string().describe('Content to write'),
}),
)
.suspend(z.object({ message: z.string(), severity: z.string() }))
.resume(z.object({ approved: z.boolean() }))
.handler(async ({ path, content }, ctx) => {
if (!ctx.resumeData) {
return await ctx.suspend({ message: `Write to "${path}"?`, severity: 'warning' });
}
if (!ctx.resumeData.approved) return { written: false };
console.log(` [Mock] Would write ${content.length} chars to ${path}`);
return { written: true };
});
// ---------------------------------------------------------------------------
// Memory
// ---------------------------------------------------------------------------
const memory = new Memory()
.lastMessages(20)
.semanticRecall({ topK: 4, messageRange: { before: 1, after: 1 } });
// ---------------------------------------------------------------------------
// Agents
// ---------------------------------------------------------------------------
const researcher = new Agent('researcher')
.model('anthropic/claude-sonnet-4')
.instructions(
'You are a research assistant. Search for information and return structured findings.',
)
.tool(searchTool)
.memory(memory)
.inputGuardrail(
new Guardrail('injection-detector').type('prompt-injection').strategy('block').threshold(0.8),
);
const writer = new Agent('writer')
.model('anthropic/claude-sonnet-4')
.instructions('You write clear, engaging content based on research provided to you.')
.tool(writeFileTool)
.checkpoint('memory');
// ---------------------------------------------------------------------------
// Multi-Agent: Agent as Tool
// ---------------------------------------------------------------------------
const orchestrator = new Agent('orchestrator')
.model('anthropic/claude-sonnet-4')
.instructions(
'You coordinate research and writing. Delegate research to the researcher and writing to the writer.',
)
.tool(researcher.asTool('Delegate research tasks to the research specialist'))
.tool(writer.asTool('Delegate writing tasks to the content writer'));
// ---------------------------------------------------------------------------
// Execution
// ---------------------------------------------------------------------------
async function main() {
console.log('=== @n8n/agents ===\n');
// --- 1. Single agent generate ---
console.log('1. Single agent generate:');
try {
const result = await researcher.generate('Find information about RAG architectures', {
persistence: {
resourceId: 'user-123',
threadId: 'session-1',
},
});
const text = result.messages
.flatMap((m) => ('content' in m ? m.content : []))
.filter((c) => c.type === 'text')
.map((c) => ('text' in c ? c.text : ''))
.join('');
console.log(` Result: ${text.slice(0, 100)}...`);
console.log(
` Usage: ${result.usage?.promptTokens} in, ${result.usage?.completionTokens} out`,
);
} catch (error) {
console.log(` (Expected) Error: ${(error as Error).message}`);
console.log(' (Set ANTHROPIC_API_KEY to run with real LLM calls)');
}
// --- 2. Orchestrator (agent-as-tool pattern) ---
console.log('\n2. Orchestrator (agent-as-tool pattern):');
try {
const orchResult = await orchestrator.generate(
'Research RAG architectures and write a summary',
);
const text = orchResult.messages
.flatMap((m) => ('content' in m ? m.content : []))
.filter((c) => c.type === 'text')
.map((c) => ('text' in c ? c.text : ''))
.join('');
console.log(` Result: ${text.slice(0, 100)}...`);
} catch (error) {
console.log(` (Expected) Error: ${(error as Error).message}`);
}
console.log('\n=== Complete ===');
}
main().catch(console.error);