@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/AGENTS.md +2913 -0
- package/CHANGELOG.md +5 -0
- package/README.md +1585 -0
- package/dist/adapters/index.d.mts +2 -0
- package/dist/adapters/index.d.ts +2 -0
- package/dist/adapters/index.js +1024 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/index.mjs +1021 -0
- package/dist/adapters/index.mjs.map +1 -0
- package/dist/index-CX4IgrRt.d.mts +2181 -0
- package/dist/index-CX4IgrRt.d.ts +2181 -0
- package/dist/index.d.mts +3170 -0
- package/dist/index.d.ts +3170 -0
- package/dist/index.js +4045 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +4011 -0
- package/dist/index.mjs.map +1 -0
- package/dist/shim.d.mts +72 -0
- package/dist/shim.d.ts +72 -0
- package/dist/shim.js +105 -0
- package/dist/shim.js.map +1 -0
- package/dist/shim.mjs +89 -0
- package/dist/shim.mjs.map +1 -0
- package/dist/telemetry/index.d.mts +340 -0
- package/dist/telemetry/index.d.ts +340 -0
- package/dist/telemetry/index.js +157 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/index.mjs +155 -0
- package/dist/telemetry/index.mjs.map +1 -0
- package/package.json +116 -0
package/README.md
ADDED
|
@@ -0,0 +1,1585 @@
|
|
|
1
|
+
# @igniter-js/agents
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@igniter-js/agents)
|
|
4
|
+
[](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)
|