@igniter-js/agents 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,1585 @@
1
+ # @igniter-js/agents
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/@igniter-js/agents.svg)](https://www.npmjs.com/package/@igniter-js/agents)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Production-ready, type-safe AI agent framework for Igniter.js. Build intelligent agents with custom tools, persistent memory, comprehensive observability, and seamless multi-agent orchestration.
7
+
8
+ ## Table of Contents
9
+
10
+ - [Overview](#overview)
11
+ - [Features](#features)
12
+ - [Installation](#installation)
13
+ - [Quick Start](#quick-start)
14
+ - [Core Concepts](#core-concepts)
15
+ - [Building Agents](#building-agents)
16
+ - [Tools & Toolsets](#tools--toolsets)
17
+ - [Memory System](#memory-system)
18
+ - [MCP Integration](#mcp-integration)
19
+ - [Telemetry & Observability](#telemetry--observability)
20
+ - [Multi-Agent Orchestration](#multi-agent-orchestration)
21
+ - [Real-World Examples](#real-world-examples)
22
+ - [Best Practices](#best-practices)
23
+ - [API Reference](#api-reference)
24
+ - [Troubleshooting](#troubleshooting)
25
+
26
+ ---
27
+
28
+ ## Overview
29
+
30
+ @igniter-js/agents solves a critical gap in AI application development: **building production-grade agents that are type-safe, observable, and maintainable**.
31
+
32
+ ### The Problem
33
+
34
+ Traditional AI agent frameworks face several challenges:
35
+
36
+ - **Type Safety Gaps:** Tool definitions are validated at runtime, leading to errors in production
37
+ - **Memory Management:** Stateless interactions lose context across requests
38
+ - **Tool Orchestration:** Complex toolsets are hard to compose and validate
39
+ - **Observability Blind Spots:** Understanding agent behavior requires manual instrumentation
40
+ - **Multi-Agent Complexity:** Coordinating multiple specialized agents is error-prone
41
+
42
+ ### The Solution
43
+
44
+ @igniter-js/agents provides:
45
+
46
+ | Capability | Benefit |
47
+ |-----------|---------|
48
+ | **Type-Safe Tooling** | Compile-time validation of tool inputs/outputs prevents runtime errors |
49
+ | **Persistent Memory** | Adapter-based storage maintains conversation context across sessions |
50
+ | **Builder Pattern** | Fluent, immutable configuration ensures predictable agent behavior |
51
+ | **Comprehensive Telemetry** | Track every agent operation for deep observability and debugging |
52
+ | **MCP Support** | Native integration with Model Context Protocol for extensibility |
53
+ | **Manager Orchestration** | Coordinate multiple specialized agents with a single manager |
54
+
55
+ ### When to Use This Package
56
+
57
+ ✅ **Use @igniter-js/agents when:**
58
+ - Building conversational AI applications with persistent context
59
+ - Creating specialized AI agents for different domains (support, sales, analytics, etc.)
60
+ - Needing strong type safety and compile-time validation
61
+ - Requiring comprehensive observability into agent behavior
62
+ - Coordinating complex multi-agent workflows
63
+ - Integrating with external tools via MCP servers
64
+
65
+ ❌ **Consider alternatives if:**
66
+ - Building simple, stateless AI integrations (use `@ai-sdk/openai` directly)
67
+ - Working in browser/client environments (agents are server-only)
68
+ - Needing only a simple chat interface without complex tooling
69
+
70
+ ---
71
+
72
+ ## Features
73
+
74
+ ### Core Capabilities
75
+
76
+ - ✅ **Type-Safe Tooling** — Strong TypeScript inference for tool inputs/outputs with Zod validation
77
+ - ✅ **Agent Lifecycle Management** — Built-in hooks for start, completion, error handling
78
+ - ✅ **Prompt Templates** — Context-aware prompt building with variable interpolation
79
+ - ✅ **MCP Integration** — Connect to Model Context Protocol servers for external tools
80
+ - ✅ **Persistent Memory** — Working memory + chat history with multiple adapter options
81
+ - ✅ **Full Telemetry** — Optional `@igniter-js/telemetry` integration for observability
82
+ - ✅ **Logger Integration** — Structured logging with `IgniterLogger`
83
+ - ✅ **Manager Orchestration** — Run and supervise multiple agents with a single manager
84
+ - ✅ **Server-Only Protection** — Browser import protection via `shim.ts`
85
+
86
+ ### Memory Adapters
87
+
88
+ - **In-Memory** — Fast, ephemeral storage for development and testing
89
+ - **JSON File** — Local file-based persistence for single-machine deployments
90
+ - **Extensible** — Build custom adapters for any backend (Redis, PostgreSQL, etc.)
91
+
92
+ ### Models Supported
93
+
94
+ Works with any provider supported by [Vercel AI SDK](https://sdk.vercel.ai/docs/models):
95
+
96
+ - OpenAI (GPT-4, GPT-3.5)
97
+ - Anthropic (Claude)
98
+ - Google Gemini
99
+ - Mistral
100
+ - Cohere
101
+ - Local models via Ollama
102
+ - And more...
103
+
104
+ ---
105
+
106
+ ## Installation
107
+
108
+ ### Core Dependencies
109
+
110
+ ```bash
111
+ # npm
112
+ npm install @igniter-js/agents ai zod
113
+
114
+ # pnpm
115
+ pnpm add @igniter-js/agents ai zod
116
+
117
+ # yarn
118
+ yarn add @igniter-js/agents ai zod
119
+
120
+ # bun
121
+ bun add @igniter-js/agents ai zod
122
+ ```
123
+
124
+ ### AI Model Provider (Required)
125
+
126
+ Choose and install your preferred AI model provider:
127
+
128
+ ```bash
129
+ # OpenAI (recommended)
130
+ npm install @ai-sdk/openai
131
+
132
+ # Anthropic
133
+ npm install @ai-sdk/anthropic
134
+
135
+ # Google Gemini
136
+ npm install @ai-sdk/google
137
+
138
+ # Mistral
139
+ npm install @ai-sdk/mistral
140
+
141
+ # Or use any other AI SDK provider...
142
+ ```
143
+
144
+ ### Optional Telemetry
145
+
146
+ For production observability:
147
+
148
+ ```bash
149
+ npm install @igniter-js/telemetry
150
+ ```
151
+
152
+ ### Optional MCP Support
153
+
154
+ To connect external tools via Model Context Protocol:
155
+
156
+ ```bash
157
+ npm install @ai-sdk/mcp @modelcontextprotocol/sdk
158
+ ```
159
+
160
+ ### Runtime Requirements
161
+
162
+ - **Node.js:** 18.0.0 or higher
163
+ - **Bun:** 1.0.0 or higher
164
+ - **Deno:** 1.30.0 or higher
165
+ - **Browser:** ❌ Not supported (server-only)
166
+
167
+ ---
168
+
169
+ ## Quick Start
170
+
171
+ ### 1. Basic Agent with a Single Tool
172
+
173
+ ```typescript
174
+ import {
175
+ IgniterAgent,
176
+ IgniterAgentTool,
177
+ IgniterAgentToolset,
178
+ } from '@igniter-js/agents'
179
+ import { openai } from '@ai-sdk/openai'
180
+ import { z } from 'zod'
181
+
182
+ // Define a tool with type-safe schema
183
+ const weatherTool = IgniterAgentTool
184
+ .create('get_weather')
185
+ .withDescription('Get current weather for a location')
186
+ .withInput(
187
+ z.object({
188
+ location: z.string().describe('City name or coordinates'),
189
+ unit: z.enum(['C', 'F']).default('C').describe('Temperature unit'),
190
+ })
191
+ )
192
+ .withExecute(async ({ location, unit }) => {
193
+ // Your weather API integration here
194
+ return {
195
+ location,
196
+ temperature: 22,
197
+ unit,
198
+ condition: 'Partly Cloudy',
199
+ }
200
+ })
201
+ .build()
202
+
203
+ // Create a toolset grouping related tools
204
+ const weatherToolset = IgniterAgentToolset
205
+ .create('weather')
206
+ .addTool(weatherTool)
207
+ .build()
208
+
209
+ // Build and run the agent
210
+ const agent = IgniterAgent
211
+ .create('weather-assistant')
212
+ .withModel(openai('gpt-4'))
213
+ .addToolset(weatherToolset)
214
+ .build()
215
+
216
+ await agent.start()
217
+
218
+ // Generate a response (agent chooses to use tools as needed)
219
+ const result = await agent.generate({
220
+ messages: [
221
+ {
222
+ role: 'user',
223
+ content: 'What is the weather like in London right now?',
224
+ },
225
+ ],
226
+ })
227
+
228
+ console.log(result.content)
229
+ ```
230
+
231
+ ### 2. Agent with Memory (Multi-Turn Conversations)
232
+
233
+ ```typescript
234
+ import {
235
+ IgniterAgent,
236
+ IgniterAgentInMemoryAdapter,
237
+ } from '@igniter-js/agents'
238
+ import { openai } from '@ai-sdk/openai'
239
+
240
+ // Create a memory adapter
241
+ const memory = IgniterAgentInMemoryAdapter.create({
242
+ namespace: 'my-app',
243
+ maxChats: 50,
244
+ })
245
+
246
+ // Build agent with memory
247
+ const agent = IgniterAgent
248
+ .create('assistant')
249
+ .withModel(openai('gpt-4'))
250
+ .withMemory(memory)
251
+ .withSystemPrompt(
252
+ 'You are a helpful assistant. Remember previous conversations with this user.'
253
+ )
254
+ .build()
255
+
256
+ await agent.start()
257
+
258
+ // First turn
259
+ let response = await agent.generate({
260
+ messages: [
261
+ { role: 'user', content: 'My name is Alice and I live in Paris' },
262
+ ],
263
+ })
264
+ console.log(response.content)
265
+
266
+ // Second turn - agent remembers context from first turn
267
+ response = await agent.generate({
268
+ messages: [{ role: 'user', content: "What's my name and where do I live?" }],
269
+ })
270
+ console.log(response.content) // Will reference Alice and Paris
271
+ ```
272
+
273
+ ### 3. Agent with Prompt Templates
274
+
275
+ ```typescript
276
+ import {
277
+ IgniterAgent,
278
+ IgniterAgentPrompt,
279
+ } from '@igniter-js/agents'
280
+ import { openai } from '@ai-sdk/openai'
281
+
282
+ // Create a reusable prompt template
283
+ const customerSupportPrompt = IgniterAgentPrompt
284
+ .create(`You are {{company}} customer support agent. Your tone is {{tone}}.`)
285
+
286
+ const agent = IgniterAgent
287
+ .create('support-bot')
288
+ .withModel(openai('gpt-4'))
289
+ .withPrompt(customerSupportPrompt)
290
+ .build()
291
+
292
+ await agent.start()
293
+
294
+ // Use template with dynamic values
295
+ const response = await agent.generate({
296
+ messages: [
297
+ { role: 'user', content: 'I need help with my order' },
298
+ ],
299
+ options: {
300
+ company: 'TechCorp',
301
+ tone: 'friendly and professional',
302
+ },
303
+ })
304
+
305
+ console.log(response.content)
306
+ ```
307
+
308
+ ---
309
+
310
+ ## Core Concepts
311
+
312
+ ### Agent
313
+
314
+ An **Agent** is the core runtime that:
315
+ - Receives user messages
316
+ - Decides which tools to use
317
+ - Executes tools and processes results
318
+ - Maintains conversation context via memory
319
+ - Emits telemetry for observability
320
+
321
+ Create agents with `IgniterAgent.create()` and configure via the builder pattern.
322
+
323
+ ### Tool
324
+
325
+ A **Tool** is a typed, executable function that:
326
+ - Has a name and description
327
+ - Accepts validated inputs (Zod schema)
328
+ - Returns structured output
329
+ - Can be reused across agents
330
+ - Automatically provides schema to AI model
331
+
332
+ Tools are the interface between agents and your application logic.
333
+
334
+ ### Toolset
335
+
336
+ A **Toolset** is a collection of related tools, organized by domain:
337
+ - Groups tools logically (e.g., "database", "api", "analytics")
338
+ - Enables selective tool availability
339
+ - Improves agent performance through focused tool selection
340
+ - Can be shared across multiple agents
341
+
342
+ ### Memory
343
+
344
+ **Memory** is how agents maintain context:
345
+ - **Working Memory:** Current session state and variables
346
+ - **Chat History:** Persisted conversation messages
347
+ - **Adapters:** Pluggable storage backends (in-memory, file, custom)
348
+
349
+ Memory is optional but highly recommended for multi-turn conversations.
350
+
351
+ ### Manager
352
+
353
+ A **Manager** orchestrates multiple agents:
354
+ - Routes requests to appropriate agents
355
+ - Shares common resources (logger, telemetry, memory)
356
+ - Monitors agent health and lifecycle
357
+ - Enables agent-to-agent communication
358
+
359
+ ---
360
+
361
+ ## Building Agents
362
+
363
+ ### Complete Agent Setup
364
+
365
+ ```typescript
366
+ import {
367
+ IgniterAgent,
368
+ IgniterAgentInMemoryAdapter,
369
+ IgniterAgentTool,
370
+ IgniterAgentToolset,
371
+ } from '@igniter-js/agents'
372
+ import { openai } from '@ai-sdk/openai'
373
+ import { z } from 'zod'
374
+
375
+ // Step 1: Define tools
376
+ const getTodaysTasks = IgniterAgentTool
377
+ .create('get_todays_tasks')
378
+ .withDescription('Retrieve tasks for today')
379
+ .withInput(z.object({ priority: z.enum(['high', 'medium', 'low']).optional() }))
380
+ .withExecute(async ({ priority }) => {
381
+ // Fetch tasks from database
382
+ return [
383
+ { id: 1, title: 'Review PR', priority: 'high' },
384
+ { id: 2, title: 'Update docs', priority: 'medium' },
385
+ ]
386
+ })
387
+ .build()
388
+
389
+ const addTask = IgniterAgentTool
390
+ .create('add_task')
391
+ .withDescription('Add a new task')
392
+ .withInput(
393
+ z.object({
394
+ title: z.string(),
395
+ priority: z.enum(['high', 'medium', 'low']).default('medium'),
396
+ })
397
+ )
398
+ .withExecute(async ({ title, priority }) => {
399
+ // Save to database
400
+ return { id: 3, title, priority, created: new Date() }
401
+ })
402
+ .build()
403
+
404
+ // Step 2: Create toolset
405
+ const tasksToolset = IgniterAgentToolset
406
+ .create('tasks')
407
+ .addTool(getTodaysTasks)
408
+ .addTool(addTask)
409
+ .build()
410
+
411
+ // Step 3: Create memory
412
+ const memory = IgniterAgentInMemoryAdapter.create({
413
+ namespace: 'productivity-app',
414
+ })
415
+
416
+ // Step 4: Build agent
417
+ const productivityAgent = IgniterAgent
418
+ .create('productivity-assistant')
419
+ .withModel(openai('gpt-4'))
420
+ .withSystemPrompt('You are a productivity assistant. Help users manage their tasks.')
421
+ .withMemory(memory)
422
+ .addToolset(tasksToolset)
423
+ .withMaxToolCalls(5) // Prevent infinite loops
424
+ .build()
425
+
426
+ await productivityAgent.start()
427
+
428
+ // Step 5: Use the agent
429
+ const response = await productivityAgent.generate({
430
+ messages: [
431
+ {
432
+ role: 'user',
433
+ content: 'What are my high-priority tasks today? And add a meeting reminder.',
434
+ },
435
+ ],
436
+ })
437
+
438
+ console.log(response.content)
439
+ ```
440
+
441
+ ### Agent Configuration Options
442
+
443
+ | Option | Type | Description |
444
+ |--------|------|-------------|
445
+ | `withModel()` | `LanguageModel` | AI model to use (required) |
446
+ | `withSystemPrompt()` | `string` | System-level instructions |
447
+ | `withPrompt()` | `IgniterAgentPrompt` | Template-based prompts with variables |
448
+ | `withMemory()` | `IgniterAgentMemory` | Persistent context storage |
449
+ | `addToolset()` | `IgniterAgentToolset` | Collection of tools |
450
+ | `withMaxToolCalls()` | `number` | Prevent tool loop runaway (default: 10) |
451
+ | `withLogger()` | `IgniterLogger` | Structured logging |
452
+ | `withTelemetry()` | `IgniterTelemetryManager` | Observable events |
453
+ | `onAgentStart()` | `Hook` | Executed before generation starts |
454
+ | `onAgentComplete()` | `Hook` | Executed after successful generation |
455
+ | `onAgentError()` | `Hook` | Executed on error |
456
+
457
+ ---
458
+
459
+ ## Tools & Toolsets
460
+
461
+ ### Defining Type-Safe Tools
462
+
463
+ Tools enforce strict type contracts between your agent and implementation:
464
+
465
+ ```typescript
466
+ import { IgniterAgentTool } from '@igniter-js/agents'
467
+ import { z } from 'zod'
468
+
469
+ // Tool with input and output validation
470
+ const databaseQuery = IgniterAgentTool
471
+ .create('query_database')
472
+ .withDescription('Execute a database query')
473
+ .withInput(
474
+ z.object({
475
+ query: z.string().describe('SQL query to execute'),
476
+ maxResults: z.number().default(100).describe('Max rows to return'),
477
+ })
478
+ )
479
+ .withOutput(
480
+ z.array(z.record(z.any())).describe('Query result rows')
481
+ )
482
+ .withExecute(async ({ query, maxResults }) => {
483
+ // Execute query with strict type safety
484
+ const results = await db.query(query)
485
+ return results.slice(0, maxResults)
486
+ })
487
+ .build()
488
+
489
+ // Tool without output validation (returns any)
490
+ const sendEmail = IgniterAgentTool
491
+ .create('send_email')
492
+ .withDescription('Send an email to a recipient')
493
+ .withInput(
494
+ z.object({
495
+ to: z.string().email(),
496
+ subject: z.string(),
497
+ body: z.string(),
498
+ })
499
+ )
500
+ .withExecute(async ({ to, subject, body }) => {
501
+ const result = await emailService.send({ to, subject, body })
502
+ return { messageId: result.id, sent: true }
503
+ })
504
+ .build()
505
+ ```
506
+
507
+ ### Organizing Tools into Toolsets
508
+
509
+ Group related tools for better organization and selective availability:
510
+
511
+ ```typescript
512
+ import { IgniterAgentToolset } from '@igniter-js/agents'
513
+
514
+ // Database toolset
515
+ const databaseTools = IgniterAgentToolset
516
+ .create('database')
517
+ .addTool(queryTool)
518
+ .addTool(insertTool)
519
+ .addTool(updateTool)
520
+ .addTool(deleteTool)
521
+ .build()
522
+
523
+ // Email toolset
524
+ const emailTools = IgniterAgentToolset
525
+ .create('email')
526
+ .addTool(sendEmailTool)
527
+ .addTool(listEmailsTool)
528
+ .addTool(deleteEmailTool)
529
+ .build()
530
+
531
+ // Add selectively to agents
532
+ const adminAgent = IgniterAgent
533
+ .create('admin')
534
+ .addToolset(databaseTools)
535
+ .addToolset(emailTools)
536
+ .build()
537
+
538
+ const customerAgent = IgniterAgent
539
+ .create('customer-support')
540
+ .addToolset(emailTools) // Only email access
541
+ .build()
542
+ ```
543
+
544
+ ### Tool Best Practices
545
+
546
+ ```typescript
547
+ // ❌ BAD: Vague description
548
+ const tool1 = IgniterAgentTool
549
+ .create('process')
550
+ .withDescription('Process something')
551
+ .build()
552
+
553
+ // ✅ GOOD: Clear, specific description
554
+ const tool2 = IgniterAgentTool
555
+ .create('create_support_ticket')
556
+ .withDescription(
557
+ 'Create a new customer support ticket. Include category, priority, and issue description. ' +
558
+ 'Returns ticket ID and estimated resolution time.'
559
+ )
560
+ .build()
561
+
562
+ // ❌ BAD: No input validation
563
+ const tool3 = IgniterAgentTool
564
+ .create('send_message')
565
+ .withExecute(async (input: any) => {
566
+ // input could be anything!
567
+ })
568
+ .build()
569
+
570
+ // ✅ GOOD: Strict input validation with helpful descriptions
571
+ const tool4 = IgniterAgentTool
572
+ .create('send_message')
573
+ .withInput(
574
+ z.object({
575
+ userId: z.string().uuid().describe('Target user ID'),
576
+ message: z.string().min(1).max(1000).describe('Message text'),
577
+ priority: z.enum(['low', 'normal', 'urgent']).optional(),
578
+ })
579
+ )
580
+ .withExecute(async ({ userId, message, priority }) => {
581
+ // Fully typed, validated input
582
+ })
583
+ .build()
584
+
585
+ // ❌ BAD: Tool with side effects and long operations without context
586
+ const tool5 = IgniterAgentTool
587
+ .create('process_large_file')
588
+ .withExecute(async () => {
589
+ // Long-running operation with no feedback
590
+ await processMultiGBFile()
591
+ })
592
+ .build()
593
+
594
+ // ✅ GOOD: Tool with progress tracking and timeout
595
+ const tool6 = IgniterAgentTool
596
+ .create('process_large_file')
597
+ .withDescription('Process a large file. May take several minutes.')
598
+ .withInput(z.object({ filePath: z.string() }))
599
+ .withExecute(async ({ filePath }, context) => {
600
+ // Has access to context like timeout settings
601
+ const result = await processFile(filePath, {
602
+ onProgress: (pct) => console.log(`Progress: ${pct}%`),
603
+ timeout: 5 * 60 * 1000, // 5 minutes
604
+ })
605
+ return result
606
+ })
607
+ .build()
608
+ ```
609
+
610
+ ---
611
+
612
+ ## Memory System
613
+
614
+ ### Memory Adapters
615
+
616
+ Agents without memory are stateless. Each request starts fresh with no context of previous interactions. Memory solves this by persisting conversation history and working state.
617
+
618
+ #### In-Memory Adapter (Development)
619
+
620
+ Fast, ephemeral storage. Perfect for development and testing.
621
+
622
+ ```typescript
623
+ import { IgniterAgentInMemoryAdapter } from '@igniter-js/agents/adapters'
624
+
625
+ const memory = IgniterAgentInMemoryAdapter.create({
626
+ namespace: 'my-app', // Namespace for isolation
627
+ maxChats: 100, // Maximum conversations to keep
628
+ ttlMs: 24 * 60 * 60 * 1000, // TTL for entries (24 hours)
629
+ })
630
+
631
+ const agent = IgniterAgent.create('assistant')
632
+ .withMemory(memory)
633
+ .build()
634
+
635
+ // Data is stored in process memory and lost on restart
636
+ ```
637
+
638
+ #### JSON File Adapter (Persistence)
639
+
640
+ File-based storage for local development with persistence across restarts.
641
+
642
+ ```typescript
643
+ import { IgniterAgentJSONFileAdapter } from '@igniter-js/agents/adapters'
644
+
645
+ const memory = IgniterAgentJSONFileAdapter.create({
646
+ dataDir: './data/agent-memory', // Directory for JSON files
647
+ namespace: 'my-app',
648
+ maxChats: 1000,
649
+ autoSync: true, // Auto-save to disk
650
+ syncIntervalMs: 5000, // Sync every 5 seconds
651
+ })
652
+
653
+ await memory.connect()
654
+
655
+ const agent = IgniterAgent.create('assistant')
656
+ .withMemory(memory)
657
+ .build()
658
+
659
+ // Data persists across process restarts
660
+ await memory.disconnect() // Flush remaining data before exit
661
+ ```
662
+
663
+ #### Persisting Across Sessions
664
+
665
+ ```typescript
666
+ // Session 1: Create agent, have conversation, save
667
+ {
668
+ const memory = IgniterAgentJSONFileAdapter.create({
669
+ dataDir: './agent-data',
670
+ })
671
+ await memory.connect()
672
+
673
+ const agent = IgniterAgent.create('assistant')
674
+ .withMemory(memory)
675
+ .build()
676
+
677
+ await agent.generate({
678
+ messages: [{ role: 'user', content: 'I like TypeScript' }],
679
+ })
680
+
681
+ await memory.disconnect()
682
+ }
683
+
684
+ // Session 2: Load previous conversation context
685
+ {
686
+ const memory = IgniterAgentJSONFileAdapter.create({
687
+ dataDir: './agent-data', // Same directory
688
+ })
689
+ await memory.connect()
690
+
691
+ const agent = IgniterAgent.create('assistant')
692
+ .withMemory(memory)
693
+ .build()
694
+
695
+ // Agent remembers "user likes TypeScript"
696
+ const response = await agent.generate({
697
+ messages: [{ role: 'user', content: 'Recommend a library for me' }],
698
+ })
699
+ }
700
+ ```
701
+
702
+ ### Working Memory Operations
703
+
704
+ Working memory stores contextual information beyond chat history:
705
+
706
+ ```typescript
707
+ const memory = IgniterAgentInMemoryAdapter.create()
708
+
709
+ // Store custom context
710
+ await memory.updateWorkingMemory({
711
+ scope: 'user',
712
+ identifier: 'user-123',
713
+ content: {
714
+ preferences: { language: 'TypeScript', framework: 'React' },
715
+ tokens: { remaining: 500 },
716
+ },
717
+ })
718
+
719
+ // Retrieve context
720
+ const userContext = await memory.getWorkingMemory({
721
+ scope: 'user',
722
+ identifier: 'user-123',
723
+ })
724
+
725
+ console.log(userContext) // { preferences: {...}, tokens: {...} }
726
+ ```
727
+
728
+ ### Memory Best Practices
729
+
730
+ ```typescript
731
+ // ❌ BAD: Storing sensitive data
732
+ await memory.updateWorkingMemory({
733
+ scope: 'user',
734
+ identifier: 'user-123',
735
+ content: {
736
+ apiKey: 'sk-1234567890', // Don't store secrets!
737
+ creditCard: '4111111111111111', // Don't store PII!
738
+ password: 'SuperSecret123', // Never store passwords!
739
+ },
740
+ })
741
+
742
+ // ✅ GOOD: Storing non-sensitive, useful context
743
+ await memory.updateWorkingMemory({
744
+ scope: 'user',
745
+ identifier: 'user-123',
746
+ content: {
747
+ preferences: { language: 'en-US', timezone: 'UTC' },
748
+ subscriptionTier: 'pro',
749
+ hasApiAccess: true, // Flags, not secrets
750
+ lastLoginAt: '2025-12-24T10:30:00Z',
751
+ },
752
+ })
753
+
754
+ // ❌ BAD: Unbounded memory growth
755
+ for (let i = 0; i < 1_000_000; i++) {
756
+ await memory.updateWorkingMemory({
757
+ scope: 'cache',
758
+ identifier: `key-${i}`,
759
+ content: largeData,
760
+ })
761
+ }
762
+
763
+ // ✅ GOOD: Bounded, managed memory
764
+ const memory = IgniterAgentInMemoryAdapter.create({
765
+ maxChats: 100, // Limit conversations
766
+ ttlMs: 24 * 60 * 60 * 1000, // Expire old entries
767
+ })
768
+
769
+ // Periodic cleanup
770
+ setInterval(async () => {
771
+ await memory.prune() // Remove expired entries
772
+ }, 60 * 60 * 1000)
773
+ ```
774
+
775
+ ---
776
+
777
+ ## MCP Integration
778
+
779
+ Model Context Protocol (MCP) enables agents to access external tools and resources via standardized servers.
780
+
781
+ ### Basic MCP Setup
782
+
783
+ ```typescript
784
+ import { IgniterAgentMCPClient } from '@igniter-js/agents'
785
+ import { openai } from '@ai-sdk/openai'
786
+
787
+ // Connect to filesystem MCP server
788
+ const filesystemMCP = IgniterAgentMCPClient
789
+ .create('filesystem')
790
+ .withType('stdio')
791
+ .withCommand('npx')
792
+ .withArgs(['-y', '@modelcontextprotocol/server-filesystem', '/tmp'])
793
+ .build()
794
+
795
+ const agent = IgniterAgent
796
+ .create('file-assistant')
797
+ .withModel(openai('gpt-4'))
798
+ .addMCP(filesystemMCP)
799
+ .build()
800
+
801
+ await agent.start()
802
+
803
+ // Agent can now list files, read content, etc. via MCP
804
+ const response = await agent.generate({
805
+ messages: [
806
+ { role: 'user', content: 'List all JSON files in /tmp' },
807
+ ],
808
+ })
809
+
810
+ console.log(response.content)
811
+ ```
812
+
813
+ ### Multiple MCP Servers
814
+
815
+ ```typescript
816
+ const filesystemMCP = IgniterAgentMCPClient
817
+ .create('filesystem')
818
+ .withType('stdio')
819
+ .withCommand('npx')
820
+ .withArgs(['-y', '@modelcontextprotocol/server-filesystem', '/app'])
821
+ .build()
822
+
823
+ const databaseMCP = IgniterAgentMCPClient
824
+ .create('postgres')
825
+ .withType('stdio')
826
+ .withCommand('npx')
827
+ .withArgs(['-y', '@modelcontextprotocol/server-postgres', 'postgresql://...'])
828
+ .build()
829
+
830
+ const analyticsAgent = IgniterAgent
831
+ .create('analytics')
832
+ .withModel(openai('gpt-4'))
833
+ .addMCP(filesystemMCP) // File access
834
+ .addMCP(databaseMCP) // Database access
835
+ .build()
836
+
837
+ await analyticsAgent.start()
838
+
839
+ // Agent can access both filesystems and databases
840
+ ```
841
+
842
+ ---
843
+
844
+ ## Telemetry & Observability
845
+
846
+ ### Basic Telemetry Setup
847
+
848
+ ```typescript
849
+ import { IgniterTelemetry } from '@igniter-js/telemetry'
850
+ import { IgniterAgentTelemetryEvents } from '@igniter-js/agents/telemetry'
851
+
852
+ const telemetry = IgniterTelemetry
853
+ .create()
854
+ .withService('my-ai-app')
855
+ .addEvents(IgniterAgentTelemetryEvents)
856
+ .build()
857
+
858
+ const agent = IgniterAgent
859
+ .create('assistant')
860
+ .withModel(openai('gpt-4'))
861
+ .withTelemetry(telemetry)
862
+ .build()
863
+
864
+ await agent.start()
865
+
866
+ // All agent operations are automatically tracked
867
+ ```
868
+
869
+ ### Telemetry Events
870
+
871
+ The package automatically emits these telemetry events:
872
+
873
+ | Event | When | Attributes |
874
+ |-------|------|-----------|
875
+ | `agent.started` | Agent begins processing | `agent_id`, `model` |
876
+ | `agent.completed` | Agent finished successfully | `agent_id`, `duration_ms` |
877
+ | `agent.error` | Agent encountered error | `agent_id`, `error_code` |
878
+ | `tool.called` | Tool invoked | `tool_name`, `agent_id` |
879
+ | `tool.completed` | Tool finished | `tool_name`, `duration_ms` |
880
+ | `tool.error` | Tool failed | `tool_name`, `error_code` |
881
+ | `memory.stored` | Data saved to memory | `scope`, `size_bytes` |
882
+ | `memory.retrieved` | Data loaded from memory | `scope`, `hit_ms` |
883
+
884
+ ```typescript
885
+ // Events are emitted automatically with your telemetry adapter
886
+ // Example: View events in your observability backend
887
+ const events = await telemetry.query({
888
+ service: 'my-ai-app',
889
+ eventType: 'agent.completed',
890
+ timeRange: 'last_hour',
891
+ })
892
+
893
+ console.log(`Completed ${events.length} agent requests in the last hour`)
894
+ ```
895
+
896
+ ---
897
+
898
+ ## Multi-Agent Orchestration
899
+
900
+ ### Manager Setup
901
+
902
+ ```typescript
903
+ import { IgniterAgentManager } from '@igniter-js/agents'
904
+
905
+ // Create specialized agents
906
+ const supportAgent = IgniterAgent
907
+ .create('support')
908
+ .withModel(openai('gpt-4'))
909
+ .addToolset(supportToolset)
910
+ .build()
911
+
912
+ const salesAgent = IgniterAgent
913
+ .create('sales')
914
+ .withModel(openai('gpt-4'))
915
+ .addToolset(salesToolset)
916
+ .build()
917
+
918
+ const analyticsAgent = IgniterAgent
919
+ .create('analytics')
920
+ .withModel(openai('gpt-4'))
921
+ .addToolset(analyticsToolset)
922
+ .build()
923
+
924
+ // Create shared memory
925
+ const sharedMemory = IgniterAgentInMemoryAdapter.create()
926
+
927
+ // Create manager with shared resources
928
+ const manager = IgniterAgentManager
929
+ .create()
930
+ .withMemory(sharedMemory)
931
+ .withLogger(logger)
932
+ .withTelemetry(telemetry)
933
+ .addAgent('support', supportAgent)
934
+ .addAgent('sales', salesAgent)
935
+ .addAgent('analytics', analyticsAgent)
936
+ .build()
937
+
938
+ await manager.startAll()
939
+
940
+ // Route requests to appropriate agents
941
+ async function routeRequest(request: CustomerRequest) {
942
+ const agentId = request.type === 'support' ? 'support' : 'sales'
943
+ const agent = manager.getAgent(agentId)
944
+
945
+ return agent.generate({
946
+ messages: [{ role: 'user', content: request.message }],
947
+ })
948
+ }
949
+ ```
950
+
951
+ ### Agent Communication
952
+
953
+ Agents in a manager can reference shared context:
954
+
955
+ ```typescript
956
+ // All agents share the same memory adapter
957
+ const sharedMemory = IgniterAgentJSONFileAdapter.create({
958
+ dataDir: './shared-context',
959
+ })
960
+
961
+ await sharedMemory.connect()
962
+
963
+ const manager = IgniterAgentManager
964
+ .create()
965
+ .withMemory(sharedMemory)
966
+ .addAgent('support', supportAgent)
967
+ .addAgent('sales', salesAgent)
968
+ .build()
969
+
970
+ // Both agents can access shared user context
971
+ await sharedMemory.updateWorkingMemory({
972
+ scope: 'user',
973
+ identifier: 'user-123',
974
+ content: {
975
+ accountStatus: 'premium',
976
+ supportTickets: 5,
977
+ purchaseHistory: [...],
978
+ },
979
+ })
980
+
981
+ // Support agent uses this context
982
+ const supportResponse = await manager.getAgent('support').generate({
983
+ messages: [{ role: 'user', content: 'I have a problem' }],
984
+ })
985
+
986
+ // Sales agent also uses this context
987
+ const salesResponse = await manager.getAgent('sales').generate({
988
+ messages: [{ role: 'user', content: 'Show me upgrades' }],
989
+ })
990
+ ```
991
+
992
+ ---
993
+
994
+ ## Real-World Examples
995
+
996
+ ### Example 1: Customer Support Chatbot
997
+
998
+ ```typescript
999
+ import {
1000
+ IgniterAgent,
1001
+ IgniterAgentTool,
1002
+ IgniterAgentToolset,
1003
+ IgniterAgentJSONFileAdapter,
1004
+ } from '@igniter-js/agents'
1005
+ import { openai } from '@ai-sdk/openai'
1006
+ import { z } from 'zod'
1007
+
1008
+ // Tools
1009
+ const searchTicketsTool = IgniterAgentTool
1010
+ .create('search_tickets')
1011
+ .withDescription('Search customer support tickets')
1012
+ .withInput(z.object({
1013
+ customerId: z.string(),
1014
+ status: z.enum(['open', 'closed', 'pending']).optional(),
1015
+ }))
1016
+ .withExecute(async ({ customerId, status }) => {
1017
+ // Query ticket database
1018
+ return {
1019
+ tickets: [
1020
+ { id: 'T001', status: 'open', subject: 'Billing issue' },
1021
+ { id: 'T002', status: 'closed', subject: 'Login help' },
1022
+ ],
1023
+ }
1024
+ })
1025
+ .build()
1026
+
1027
+ const createTicketTool = IgniterAgentTool
1028
+ .create('create_ticket')
1029
+ .withDescription('Create a new support ticket')
1030
+ .withInput(z.object({
1031
+ customerId: z.string(),
1032
+ subject: z.string(),
1033
+ description: z.string(),
1034
+ priority: z.enum(['low', 'medium', 'high']),
1035
+ }))
1036
+ .withExecute(async ({ customerId, subject, description, priority }) => {
1037
+ // Create ticket in database
1038
+ return {
1039
+ ticketId: 'T003',
1040
+ created: new Date(),
1041
+ }
1042
+ })
1043
+ .build()
1044
+
1045
+ const sendEmailTool = IgniterAgentTool
1046
+ .create('send_email')
1047
+ .withDescription('Send email to customer')
1048
+ .withInput(z.object({
1049
+ to: z.string().email(),
1050
+ subject: z.string(),
1051
+ body: z.string(),
1052
+ }))
1053
+ .withExecute(async ({ to, subject, body }) => {
1054
+ // Send email via provider
1055
+ return { sent: true, messageId: 'msg-123' }
1056
+ })
1057
+ .build()
1058
+
1059
+ // Create agent
1060
+ const supportAgent = IgniterAgent
1061
+ .create('support-bot')
1062
+ .withModel(openai('gpt-4'))
1063
+ .withSystemPrompt(`
1064
+ You are a helpful customer support agent. Your goal is to:
1065
+ 1. Understand the customer's issue
1066
+ 2. Search for relevant tickets or information
1067
+ 3. Create new tickets if needed
1068
+ 4. Send follow-up emails with solutions
1069
+
1070
+ Be empathetic, clear, and professional.
1071
+ `)
1072
+ .withMemory(
1073
+ IgniterAgentJSONFileAdapter.create({
1074
+ dataDir: './support-memory',
1075
+ namespace: 'support',
1076
+ })
1077
+ )
1078
+ .addToolset(
1079
+ IgniterAgentToolset
1080
+ .create('support')
1081
+ .addTool(searchTicketsTool)
1082
+ .addTool(createTicketTool)
1083
+ .addTool(sendEmailTool)
1084
+ .build()
1085
+ )
1086
+ .build()
1087
+
1088
+ await supportAgent.start()
1089
+
1090
+ // Use it
1091
+ const response = await supportAgent.generate({
1092
+ messages: [
1093
+ {
1094
+ role: 'user',
1095
+ content: 'I\\'ve been charged twice for my subscription!',
1096
+ },
1097
+ ],
1098
+ })
1099
+
1100
+ console.log(response.content)
1101
+ ```
1102
+
1103
+ ### Example 2: Data Analysis Agent
1104
+
1105
+ ```typescript
1106
+ import { IgniterAgent, IgniterAgentTool, IgniterAgentToolset } from '@igniter-js/agents'
1107
+ import { openai } from '@ai-sdk/openai'
1108
+ import { z } from 'zod'
1109
+
1110
+ const queryDatabaseTool = IgniterAgentTool
1111
+ .create('query_database')
1112
+ .withDescription('Execute SQL query on analytics database')
1113
+ .withInput(z.object({
1114
+ query: z.string(),
1115
+ limit: z.number().default(1000),
1116
+ }))
1117
+ .withExecute(async ({ query, limit }) => {
1118
+ // Execute query
1119
+ const results = [
1120
+ { date: '2025-12-01', revenue: 15000, customers: 250 },
1121
+ { date: '2025-12-02', revenue: 18000, customers: 280 },
1122
+ ]
1123
+ return results.slice(0, limit)
1124
+ })
1125
+ .build()
1126
+
1127
+ const generateChartTool = IgniterAgentTool
1128
+ .create('generate_chart')
1129
+ .withDescription('Create visualization from data')
1130
+ .withInput(z.object({
1131
+ type: z.enum(['line', 'bar', 'pie', 'scatter']),
1132
+ data: z.array(z.record(z.any())),
1133
+ title: z.string(),
1134
+ }))
1135
+ .withExecute(async ({ type, data, title }) => {
1136
+ // Generate chart
1137
+ return {
1138
+ chartUrl: 'https://charts.example.com/chart-123.png',
1139
+ format: type,
1140
+ }
1141
+ })
1142
+ .build()
1143
+
1144
+ const analyticsAgent = IgniterAgent
1145
+ .create('data-analyst')
1146
+ .withModel(openai('gpt-4'))
1147
+ .withSystemPrompt('You are a data analyst. Answer questions with data and create visualizations.')
1148
+ .addToolset(
1149
+ IgniterAgentToolset
1150
+ .create('analytics')
1151
+ .addTool(queryDatabaseTool)
1152
+ .addTool(generateChartTool)
1153
+ .build()
1154
+ )
1155
+ .build()
1156
+
1157
+ await analyticsAgent.start()
1158
+
1159
+ const response = await analyticsAgent.generate({
1160
+ messages: [
1161
+ {
1162
+ role: 'user',
1163
+ content: 'Show me revenue trends for the last 30 days with a chart',
1164
+ },
1165
+ ],
1166
+ })
1167
+
1168
+ console.log(response.content)
1169
+ ```
1170
+
1171
+ ---
1172
+
1173
+ ## Best Practices
1174
+
1175
+ ### 1. Type Safety First
1176
+
1177
+ ```typescript
1178
+ // ✅ Always define strict Zod schemas
1179
+ const tool = IgniterAgentTool
1180
+ .create('my-tool')
1181
+ .withInput(
1182
+ z.object({
1183
+ userId: z.string().uuid(),
1184
+ email: z.string().email(),
1185
+ age: z.number().int().min(0).max(150),
1186
+ })
1187
+ )
1188
+ .build()
1189
+
1190
+ // ❌ Avoid any or unvalidated inputs
1191
+ const badTool = IgniterAgentTool
1192
+ .create('bad-tool')
1193
+ .withExecute(async (input: any) => {})
1194
+ .build()
1195
+ ```
1196
+
1197
+ ### 2. Memory Management
1198
+
1199
+ ```typescript
1200
+ // ✅ Set reasonable limits
1201
+ const memory = IgniterAgentInMemoryAdapter.create({
1202
+ maxChats: 100, // Prevent unbounded growth
1203
+ ttlMs: 7 * 24 * 60 * 60 * 1000, // Auto-expire old data
1204
+ })
1205
+
1206
+ // ✅ Prune periodically
1207
+ setInterval(async () => {
1208
+ await memory.prune()
1209
+ }, 6 * 60 * 60 * 1000) // Every 6 hours
1210
+
1211
+ // ❌ Avoid storing sensitive data
1212
+ await memory.updateWorkingMemory({
1213
+ scope: 'user',
1214
+ identifier: 'user-123',
1215
+ content: {
1216
+ apiKey: secret, // ❌ Never!
1217
+ password: password, // ❌ Never!
1218
+ },
1219
+ })
1220
+ ```
1221
+
1222
+ ### 3. Error Handling
1223
+
1224
+ ```typescript
1225
+ // ✅ Always handle agent generation errors
1226
+ try {
1227
+ const response = await agent.generate({
1228
+ messages: [...],
1229
+ })
1230
+ } catch (error) {
1231
+ if (error instanceof IgniterAgentError) {
1232
+ console.error(`Agent error: ${error.code}`, error.details)
1233
+ } else {
1234
+ console.error('Unknown error:', error)
1235
+ }
1236
+ }
1237
+
1238
+ // ✅ Set tool execution timeouts
1239
+ const tool = IgniterAgentTool
1240
+ .create('long-operation')
1241
+ .withExecute(async () => {
1242
+ return Promise.race([
1243
+ doLongOperation(),
1244
+ new Promise((_, reject) =>
1245
+ setTimeout(() => reject(new Error('Timeout')), 30000)
1246
+ ),
1247
+ ])
1248
+ })
1249
+ .build()
1250
+ ```
1251
+
1252
+ ### 4. Tool Design
1253
+
1254
+ ```typescript
1255
+ // ✅ Keep tools focused and single-purpose
1256
+ const getUserTool = IgniterAgentTool
1257
+ .create('get_user')
1258
+ .withDescription('Get user by ID')
1259
+ .build()
1260
+
1261
+ const updateUserTool = IgniterAgentTool
1262
+ .create('update_user')
1263
+ .withDescription('Update user fields')
1264
+ .build()
1265
+
1266
+ // ❌ Avoid tools that do too much
1267
+ const megaTool = IgniterAgentTool
1268
+ .create('user_operations')
1269
+ .withDescription('Get, update, delete users and their data')
1270
+ .build()
1271
+
1272
+ // ✅ Provide excellent descriptions
1273
+ const goodTool = IgniterAgentTool
1274
+ .create('transfer_funds')
1275
+ .withDescription(
1276
+ 'Transfer money between accounts. Requires source and destination ' +
1277
+ 'account IDs, amount in cents, and optional memo. Returns transaction ' +
1278
+ 'ID and confirmation number. May fail if insufficient funds or ' +
1279
+ 'account is frozen.'
1280
+ )
1281
+ .build()
1282
+ ```
1283
+
1284
+ ### 5. Observability
1285
+
1286
+ ```typescript
1287
+ // ✅ Always use telemetry in production
1288
+ import { IgniterTelemetry } from '@igniter-js/telemetry'
1289
+ import { IgniterAgentTelemetryEvents } from '@igniter-js/agents/telemetry'
1290
+
1291
+ const telemetry = IgniterTelemetry
1292
+ .create()
1293
+ .withService('my-ai-service')
1294
+ .addEvents(IgniterAgentTelemetryEvents)
1295
+ .build()
1296
+
1297
+ const agent = IgniterAgent
1298
+ .create('assistant')
1299
+ .withTelemetry(telemetry)
1300
+ .build()
1301
+
1302
+ // ✅ Add logger hooks for debugging
1303
+ .onAgentStart((input) => {
1304
+ console.log(`Starting agent with input: ${input.length} messages`)
1305
+ })
1306
+ .onAgentComplete((result) => {
1307
+ console.log(`Agent completed in ${result.duration}ms`)
1308
+ })
1309
+ .onAgentError((error) => {
1310
+ console.error(`Agent error: ${error.code}`, error.details)
1311
+ })
1312
+ ```
1313
+
1314
+ ---
1315
+
1316
+ ## API Reference
1317
+
1318
+ ### IgniterAgent
1319
+
1320
+ ```typescript
1321
+ interface IgniterAgent {
1322
+ // Configuration
1323
+ withModel(model: LanguageModel): IgniterAgent
1324
+ withSystemPrompt(prompt: string): IgniterAgent
1325
+ withPrompt(prompt: IgniterAgentPrompt): IgniterAgent
1326
+ withMemory(memory: IgniterAgentMemory): IgniterAgent
1327
+ addToolset(toolset: IgniterAgentToolset): IgniterAgent
1328
+ withLogger(logger: IgniterLogger): IgniterAgent
1329
+ withTelemetry(telemetry: IgniterTelemetryManager): IgniterAgent
1330
+ withMaxToolCalls(max: number): IgniterAgent
1331
+
1332
+ // Hooks
1333
+ onAgentStart(hook: Hook): IgniterAgent
1334
+ onAgentComplete(hook: Hook): IgniterAgent
1335
+ onAgentError(hook: Hook): IgniterAgent
1336
+
1337
+ // Build
1338
+ build(): IgniterAgentCore
1339
+
1340
+ // Runtime
1341
+ start(): Promise<void>
1342
+ generate(input: GenerateInput): Promise<GenerateOutput>
1343
+ stream(input: GenerateInput): AsyncIterable<StreamChunk>
1344
+ }
1345
+ ```
1346
+
1347
+ ### IgniterAgentTool
1348
+
1349
+ ```typescript
1350
+ interface IgniterAgentTool {
1351
+ // Schema
1352
+ withDescription(desc: string): IgniterAgentTool
1353
+ withInput(schema: ZodSchema): IgniterAgentTool
1354
+ withOutput(schema: ZodSchema): IgniterAgentTool
1355
+
1356
+ // Handler
1357
+ withExecute(handler: (input: any) => Promise<any>): IgniterAgentTool
1358
+
1359
+ // Build
1360
+ build(): IgniterAgentToolCore
1361
+ }
1362
+ ```
1363
+
1364
+ ### IgniterAgentMemory
1365
+
1366
+ ```typescript
1367
+ interface IgniterAgentMemory {
1368
+ // Working memory
1369
+ getWorkingMemory(key: { scope: string; identifier: string }): Promise<any>
1370
+ updateWorkingMemory(data: {
1371
+ scope: string
1372
+ identifier: string
1373
+ content: any
1374
+ }): Promise<void>
1375
+
1376
+ // Chat history
1377
+ getChatHistory(chatId: string): Promise<Message[]>
1378
+ appendMessage(chatId: string, message: Message): Promise<void>
1379
+
1380
+ // Lifecycle
1381
+ connect(): Promise<void>
1382
+ disconnect(): Promise<void>
1383
+ prune(): Promise<void>
1384
+ }
1385
+ ```
1386
+
1387
+ ---
1388
+
1389
+ ## Troubleshooting
1390
+
1391
+ ### Agent not calling tools
1392
+
1393
+ **Problem:** Agent generates text responses but never uses available tools.
1394
+
1395
+ **Solution:**
1396
+ 1. Verify tool descriptions are clear and relevant
1397
+ 2. Check tool input schemas match expected parameters
1398
+ 3. Ensure tool is added to a toolset and toolset is added to agent
1399
+ 4. Review system prompt — doesn't discourage tool usage
1400
+ 5. Check telemetry events for `tool.called` — should be emitted if agent attempts to use tools
1401
+
1402
+ ```typescript
1403
+ // Debug: Log all tools the agent knows about
1404
+ const tools = agent.getAvailableTools()
1405
+ console.log('Available tools:', tools.map(t => t.name))
1406
+ ```
1407
+
1408
+ ### Memory not persisting
1409
+
1410
+ **Problem:** Agent doesn't remember previous conversations.
1411
+
1412
+ **Solution:**
1413
+ 1. Verify memory adapter is configured with `withMemory()`
1414
+ 2. For file adapters, call `await memory.connect()` before using
1415
+ 3. Check that you're not disconnecting between requests
1416
+ 4. Ensure the memory has the same namespace
1417
+ 5. Verify storage backend has write permissions
1418
+
1419
+ ```typescript
1420
+ // Check memory implementation
1421
+ const memory = IgniterAgentJSONFileAdapter.create({
1422
+ dataDir: './agent-memory',
1423
+ })
1424
+
1425
+ await memory.connect()
1426
+
1427
+ // Verify it's connected
1428
+ const status = await memory.getStatus()
1429
+ console.log('Memory connected:', status.connected)
1430
+ ```
1431
+
1432
+ ### Tool execution errors
1433
+
1434
+ **Problem:** Tools fail during execution.
1435
+
1436
+ **Solution:**
1437
+ 1. Check tool input matches defined schema
1438
+ 2. Add error handling in tool handler
1439
+ 3. Review telemetry events for `tool.error` — will show error code
1440
+ 4. Add logging to understand what's failing
1441
+ 5. Ensure external dependencies (databases, APIs) are accessible
1442
+
1443
+ ```typescript
1444
+ // Better error handling in tool
1445
+ const tool = IgniterAgentTool
1446
+ .create('risky-operation')
1447
+ .withExecute(async (input) => {
1448
+ try {
1449
+ return await performOperation(input)
1450
+ } catch (error) {
1451
+ console.error('Tool failed:', error)
1452
+ throw new IgniterAgentError('OPERATION_FAILED', {
1453
+ originalError: error instanceof Error ? error.message : String(error),
1454
+ })
1455
+ }
1456
+ })
1457
+ .build()
1458
+ ```
1459
+
1460
+ ### Type inference not working
1461
+
1462
+ **Problem:** Tool input types not inferred correctly.
1463
+
1464
+ **Solution:**
1465
+ 1. Use `z.infer<typeof schema>` to explicitly type inputs
1466
+ 2. Ensure Zod version matches (v4+)
1467
+ 3. Add explicit type parameters if needed
1468
+ 4. Check TypeScript version (need 4.9+)
1469
+
1470
+ ```typescript
1471
+ // Explicitly type tool handler
1472
+ const schema = z.object({ userId: z.string() })
1473
+ type Input = z.infer<typeof schema>
1474
+
1475
+ const tool = IgniterAgentTool
1476
+ .create('typed-tool')
1477
+ .withInput(schema)
1478
+ .withExecute(async (input: Input) => {
1479
+ // Now input is properly typed
1480
+ })
1481
+ .build()
1482
+ ```
1483
+
1484
+ ### High latency with MCP
1485
+
1486
+ **Problem:** Responses are slow when using MCP servers.
1487
+
1488
+ **Solution:**
1489
+ 1. Check MCP server health and latency
1490
+ 2. Reduce number of tools to speed up tool selection
1491
+ 3. Use tool descriptions to guide model selection
1492
+ 4. Consider moving frequently used tools to regular tools
1493
+ 5. Monitor telemetry for MCP-specific events
1494
+
1495
+ ### Memory growing too large
1496
+
1497
+ **Problem:** Memory adapter consuming excessive disk space or memory.
1498
+
1499
+ **Solution:**
1500
+ 1. Set reasonable `maxChats` limit
1501
+ 2. Configure `ttlMs` to auto-expire old data
1502
+ 3. Call `prune()` periodically to clean up
1503
+ 4. Monitor memory adapter size with telemetry
1504
+ 5. Use file adapter instead of in-memory for large workloads
1505
+
1506
+ ```typescript
1507
+ const memory = IgniterAgentInMemoryAdapter.create({
1508
+ maxChats: 50,
1509
+ ttlMs: 24 * 60 * 60 * 1000, // 24 hours
1510
+ })
1511
+
1512
+ // Prune every hour
1513
+ setInterval(() => memory.prune(), 60 * 60 * 1000)
1514
+
1515
+ // Monitor size
1516
+ const stats = await memory.getStats()
1517
+ console.log(`Memory size: ${stats.sizeBytes} bytes`)
1518
+ ```
1519
+
1520
+ ---
1521
+
1522
+ ## Advanced Topics
1523
+
1524
+ ### Custom Memory Adapters
1525
+
1526
+ Implement your own memory adapter for custom storage backends:
1527
+
1528
+ ```typescript
1529
+ import { IgniterAgentMemoryAdapter } from '@igniter-js/agents'
1530
+
1531
+ class CustomMemoryAdapter implements IgniterAgentMemoryAdapter {
1532
+ async connect(): Promise<void> {
1533
+ // Connect to your backend
1534
+ }
1535
+
1536
+ async disconnect(): Promise<void> {
1537
+ // Cleanup connections
1538
+ }
1539
+
1540
+ async getWorkingMemory(key: { scope: string; identifier: string }) {
1541
+ // Retrieve from your backend
1542
+ }
1543
+
1544
+ async updateWorkingMemory(data: any) {
1545
+ // Save to your backend
1546
+ }
1547
+
1548
+ // Implement other required methods...
1549
+ }
1550
+
1551
+ const memory = new CustomMemoryAdapter()
1552
+ const agent = IgniterAgent.create('assistant')
1553
+ .withMemory(memory)
1554
+ .build()
1555
+ ```
1556
+
1557
+ ### Agent-to-Agent Communication
1558
+
1559
+ Have agents delegate to each other:
1560
+
1561
+ ```typescript
1562
+ const analysisToolForSalesAgent = IgniterAgentTool
1563
+ .create('request_analysis')
1564
+ .withDescription('Request data analysis from analytics agent')
1565
+ .withInput(z.object({ query: z.string() }))
1566
+ .withExecute(async ({ query }) => {
1567
+ // Delegate to analytics agent
1568
+ const analyticsAgent = manager.getAgent('analytics')
1569
+ const result = await analyticsAgent.generate({
1570
+ messages: [{ role: 'user', content: query }],
1571
+ })
1572
+ return { analysis: result.content }
1573
+ })
1574
+ .build()
1575
+ ```
1576
+
1577
+ ---
1578
+
1579
+ ## License
1580
+
1581
+ MIT
1582
+
1583
+ ## Support
1584
+
1585
+ For issues, questions, or contributions, visit the [Igniter.js repository](https://github.com/felipebarcelospro/igniter-js)