@falai/agent 0.9.0 → 0.9.2
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 +42 -34
- package/dist/cjs/src/core/Agent.d.ts +19 -5
- package/dist/cjs/src/core/Agent.d.ts.map +1 -1
- package/dist/cjs/src/core/Agent.js +79 -35
- package/dist/cjs/src/core/Agent.js.map +1 -1
- package/dist/cjs/src/core/ResponseModal.d.ts +9 -3
- package/dist/cjs/src/core/ResponseModal.d.ts.map +1 -1
- package/dist/cjs/src/core/ResponseModal.js +121 -55
- package/dist/cjs/src/core/ResponseModal.js.map +1 -1
- package/dist/cjs/src/core/ResponsePipeline.d.ts +8 -4
- package/dist/cjs/src/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/cjs/src/core/ResponsePipeline.js +47 -19
- package/dist/cjs/src/core/ResponsePipeline.js.map +1 -1
- package/dist/cjs/src/core/Route.d.ts +12 -5
- package/dist/cjs/src/core/Route.d.ts.map +1 -1
- package/dist/cjs/src/core/Route.js +26 -5
- package/dist/cjs/src/core/Route.js.map +1 -1
- package/dist/cjs/src/core/RoutingEngine.d.ts +5 -0
- package/dist/cjs/src/core/RoutingEngine.d.ts.map +1 -1
- package/dist/cjs/src/core/RoutingEngine.js +37 -25
- package/dist/cjs/src/core/RoutingEngine.js.map +1 -1
- package/dist/cjs/src/core/SessionManager.d.ts +9 -1
- package/dist/cjs/src/core/SessionManager.d.ts.map +1 -1
- package/dist/cjs/src/core/SessionManager.js +27 -5
- package/dist/cjs/src/core/SessionManager.js.map +1 -1
- package/dist/cjs/src/core/Step.d.ts +60 -7
- package/dist/cjs/src/core/Step.d.ts.map +1 -1
- package/dist/cjs/src/core/Step.js +151 -4
- package/dist/cjs/src/core/Step.js.map +1 -1
- package/dist/cjs/src/core/ToolManager.d.ts +234 -0
- package/dist/cjs/src/core/ToolManager.d.ts.map +1 -0
- package/dist/cjs/src/core/ToolManager.js +1117 -0
- package/dist/cjs/src/core/ToolManager.js.map +1 -0
- package/dist/cjs/src/index.d.ts +2 -3
- package/dist/cjs/src/index.d.ts.map +1 -1
- package/dist/cjs/src/index.js +5 -3
- package/dist/cjs/src/index.js.map +1 -1
- package/dist/cjs/src/types/agent.d.ts +1 -1
- package/dist/cjs/src/types/agent.d.ts.map +1 -1
- package/dist/cjs/src/types/index.d.ts +3 -2
- package/dist/cjs/src/types/index.d.ts.map +1 -1
- package/dist/cjs/src/types/index.js +3 -1
- package/dist/cjs/src/types/index.js.map +1 -1
- package/dist/cjs/src/types/route.d.ts +6 -4
- package/dist/cjs/src/types/route.d.ts.map +1 -1
- package/dist/cjs/src/types/tool.d.ts +84 -14
- package/dist/cjs/src/types/tool.d.ts.map +1 -1
- package/dist/cjs/src/types/tool.js +13 -0
- package/dist/cjs/src/types/tool.js.map +1 -1
- package/dist/src/core/Agent.d.ts +19 -5
- package/dist/src/core/Agent.d.ts.map +1 -1
- package/dist/src/core/Agent.js +79 -35
- package/dist/src/core/Agent.js.map +1 -1
- package/dist/src/core/ResponseModal.d.ts +9 -3
- package/dist/src/core/ResponseModal.d.ts.map +1 -1
- package/dist/src/core/ResponseModal.js +121 -55
- package/dist/src/core/ResponseModal.js.map +1 -1
- package/dist/src/core/ResponsePipeline.d.ts +8 -4
- package/dist/src/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/src/core/ResponsePipeline.js +47 -19
- package/dist/src/core/ResponsePipeline.js.map +1 -1
- package/dist/src/core/Route.d.ts +12 -5
- package/dist/src/core/Route.d.ts.map +1 -1
- package/dist/src/core/Route.js +26 -5
- package/dist/src/core/Route.js.map +1 -1
- package/dist/src/core/RoutingEngine.d.ts +5 -0
- package/dist/src/core/RoutingEngine.d.ts.map +1 -1
- package/dist/src/core/RoutingEngine.js +37 -25
- package/dist/src/core/RoutingEngine.js.map +1 -1
- package/dist/src/core/SessionManager.d.ts +9 -1
- package/dist/src/core/SessionManager.d.ts.map +1 -1
- package/dist/src/core/SessionManager.js +27 -5
- package/dist/src/core/SessionManager.js.map +1 -1
- package/dist/src/core/Step.d.ts +60 -7
- package/dist/src/core/Step.d.ts.map +1 -1
- package/dist/src/core/Step.js +151 -4
- package/dist/src/core/Step.js.map +1 -1
- package/dist/src/core/ToolManager.d.ts +234 -0
- package/dist/src/core/ToolManager.d.ts.map +1 -0
- package/dist/src/core/ToolManager.js +1111 -0
- package/dist/src/core/ToolManager.js.map +1 -0
- package/dist/src/index.d.ts +2 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/types/agent.d.ts +1 -1
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/index.d.ts +3 -2
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +1 -0
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/route.d.ts +6 -4
- package/dist/src/types/route.d.ts.map +1 -1
- package/dist/src/types/tool.d.ts +84 -14
- package/dist/src/types/tool.d.ts.map +1 -1
- package/dist/src/types/tool.js +12 -1
- package/dist/src/types/tool.js.map +1 -1
- package/docs/CONTRIBUTING.md +40 -0
- package/docs/README.md +12 -5
- package/docs/api/README.md +75 -45
- package/docs/api/overview.md +74 -32
- package/docs/core/agent/session-management.md +152 -5
- package/docs/core/ai-integration/response-processing.md +115 -4
- package/docs/core/conversation-flows/routes.md +130 -0
- package/docs/core/error-handling.md +638 -0
- package/docs/core/tools/tool-definition.md +684 -60
- package/docs/core/tools/tool-scoping.md +244 -53
- package/docs/guides/error-handling-patterns.md +578 -0
- package/docs/guides/getting-started/README.md +139 -28
- package/examples/advanced-patterns/knowledge-based-agent.ts +6 -6
- package/examples/advanced-patterns/persistent-onboarding.ts +30 -43
- package/examples/ai-providers/anthropic-integration.ts +9 -5
- package/examples/ai-providers/openai-integration.ts +11 -7
- package/examples/core-concepts/basic-agent.ts +106 -67
- package/examples/core-concepts/schema-driven-extraction.ts +10 -7
- package/examples/core-concepts/session-management.ts +71 -18
- package/examples/integrations/healthcare-integration.ts +15 -29
- package/examples/integrations/server-session-management.ts +3 -3
- package/examples/persistence/memory-sessions.ts +3 -3
- package/examples/tools/basic-tools.ts +293 -89
- package/examples/tools/data-enrichment-tools.ts +185 -75
- package/package.json +1 -1
- package/src/core/Agent.ts +98 -44
- package/src/core/ResponseModal.ts +148 -72
- package/src/core/ResponsePipeline.ts +82 -56
- package/src/core/Route.ts +39 -12
- package/src/core/RoutingEngine.ts +46 -42
- package/src/core/SessionManager.ts +39 -7
- package/src/core/Step.ts +198 -20
- package/src/core/ToolManager.ts +1394 -0
- package/src/index.ts +8 -3
- package/src/types/agent.ts +1 -1
- package/src/types/index.ts +13 -2
- package/src/types/route.ts +6 -4
- package/src/types/tool.ts +116 -25
- package/dist/cjs/src/core/ToolExecutor.d.ts +0 -45
- package/dist/cjs/src/core/ToolExecutor.d.ts.map +0 -1
- package/dist/cjs/src/core/ToolExecutor.js +0 -84
- package/dist/cjs/src/core/ToolExecutor.js.map +0 -1
- package/dist/src/core/ToolExecutor.d.ts +0 -45
- package/dist/src/core/ToolExecutor.d.ts.map +0 -1
- package/dist/src/core/ToolExecutor.js +0 -80
- package/dist/src/core/ToolExecutor.js.map +0 -1
- package/docs/core/tools/tool-execution.md +0 -815
- package/src/core/ToolExecutor.ts +0 -126
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Example: Modifying Collected data with Tools and Hooks
|
|
2
|
+
* Example: Modifying Collected data with Tools and Hooks using ToolManager
|
|
3
3
|
*
|
|
4
4
|
* This demonstrates:
|
|
5
5
|
* 1. Schema-first data extraction with JSON Schema
|
|
6
|
-
* 2.
|
|
6
|
+
* 2. Simplified tools that modify collected data (validation, enrichment)
|
|
7
7
|
* 3. Lifecycle hooks for data validation and business logic
|
|
8
8
|
* 4. Data-driven step flows with code-based logic (skipIf, requires)
|
|
9
9
|
* 5. Three-phase pipeline: PREPARATION → ROUTING → RESPONSE
|
|
10
|
+
* 6. NEW: ToolManager pattern helpers for common data operations
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
import {
|
|
13
14
|
Agent,
|
|
14
15
|
END_ROUTE,
|
|
15
16
|
OpenAIProvider,
|
|
16
|
-
|
|
17
|
+
Tool,
|
|
18
|
+
ToolContext,
|
|
19
|
+
ValidationError,
|
|
17
20
|
} from "../../src";
|
|
18
21
|
|
|
19
22
|
// ==============================================================================
|
|
@@ -44,60 +47,49 @@ interface FlightData {
|
|
|
44
47
|
// TOOLS: Data Enrichment (PREPARATION Phase)
|
|
45
48
|
// ==============================================================================
|
|
46
49
|
|
|
47
|
-
// Tool 1: Convert city names to airport codes
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"New York": "JFK",
|
|
69
|
-
Tokyo: "NRT",
|
|
70
|
-
"Los Angeles": "LAX",
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const destinationCode = airportCodes[destination];
|
|
74
|
-
|
|
75
|
-
console.log(`[Tool] Enriched: ${destination} → ${destinationCode}`);
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
data: undefined,
|
|
79
|
-
dataUpdate: {
|
|
80
|
-
destinationCode,
|
|
81
|
-
} as Partial<FlightData>,
|
|
82
|
-
};
|
|
83
|
-
},
|
|
84
|
-
};
|
|
50
|
+
// Tool 1: Convert city names to airport codes using ToolManager pattern helper
|
|
51
|
+
const enrichDestinationConfig = {
|
|
52
|
+
id: "enrich_destination",
|
|
53
|
+
name: "Destination Code Lookup",
|
|
54
|
+
description: "Convert city names to IATA airport codes",
|
|
55
|
+
fields: ["destination"] as const,
|
|
56
|
+
enricher: async (context: FlightBookingContext, data: Pick<FlightData, "destination">) => {
|
|
57
|
+
const destination = data.destination;
|
|
58
|
+
|
|
59
|
+
if (!destination) {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Simulate airport code lookup
|
|
64
|
+
const airportCodes: Record<string, string> = {
|
|
65
|
+
Paris: "CDG",
|
|
66
|
+
London: "LHR",
|
|
67
|
+
"New York": "JFK",
|
|
68
|
+
Tokyo: "NRT",
|
|
69
|
+
"Los Angeles": "LAX",
|
|
70
|
+
};
|
|
85
71
|
|
|
86
|
-
|
|
87
|
-
|
|
72
|
+
const destinationCode = airportCodes[destination];
|
|
73
|
+
|
|
74
|
+
console.log(`[Tool] Enriched: ${destination} → ${destinationCode}`);
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
destinationCode,
|
|
78
|
+
} as Partial<FlightData>;
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// Tool 2: Parse and validate dates using ToolManager pattern helper
|
|
83
|
+
const validateDateConfig = {
|
|
88
84
|
id: "validate_date",
|
|
89
85
|
name: "Date Parser & Validator",
|
|
90
|
-
description:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
properties: {},
|
|
95
|
-
},
|
|
96
|
-
handler: ({ data }: { data?: Partial<FlightData> }) => {
|
|
97
|
-
const departureDate = (data as Partial<FlightData>)?.departureDate;
|
|
86
|
+
description: "Parse relative dates (today, tomorrow) to ISO format and validate",
|
|
87
|
+
fields: ["departureDate"] as const,
|
|
88
|
+
enricher: async (context: FlightBookingContext, data: Pick<FlightData, "departureDate">) => {
|
|
89
|
+
const departureDate = data.departureDate;
|
|
98
90
|
|
|
99
91
|
if (!departureDate) {
|
|
100
|
-
return {
|
|
92
|
+
return {};
|
|
101
93
|
}
|
|
102
94
|
|
|
103
95
|
let parsedDate: string;
|
|
@@ -130,16 +122,13 @@ const validateDateTool: Tool<FlightBookingContext, FlightData, [], void> = {
|
|
|
130
122
|
console.log(`[Tool] Parsed date: ${departureDate} → ${parsedDate}`);
|
|
131
123
|
|
|
132
124
|
return {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
departureDateParsed: parsedDate,
|
|
136
|
-
} as Partial<FlightData>,
|
|
137
|
-
};
|
|
125
|
+
departureDateParsed: parsedDate,
|
|
126
|
+
} as Partial<FlightData>;
|
|
138
127
|
},
|
|
139
128
|
};
|
|
140
129
|
|
|
141
|
-
// Tool 3: Search for flights (triggered by flag)
|
|
142
|
-
const searchFlightsTool: Tool<FlightBookingContext, FlightData
|
|
130
|
+
// Tool 3: Search for flights (triggered by flag) using unified Tool interface
|
|
131
|
+
const searchFlightsTool: Tool<FlightBookingContext, FlightData> = {
|
|
143
132
|
id: "search_flights",
|
|
144
133
|
name: "Flight Availability Search",
|
|
145
134
|
description: "Search for available flights based on collected data",
|
|
@@ -147,12 +136,12 @@ const searchFlightsTool: Tool<FlightBookingContext, FlightData, [], void> = {
|
|
|
147
136
|
type: "object",
|
|
148
137
|
properties: {},
|
|
149
138
|
},
|
|
150
|
-
handler: (
|
|
151
|
-
const flightData = data
|
|
139
|
+
handler: async (toolContext, args) => {
|
|
140
|
+
const flightData = toolContext.data;
|
|
152
141
|
|
|
153
142
|
if (!flightData?.destinationCode || !flightData?.departureDateParsed) {
|
|
154
143
|
console.log("[Tool] Cannot search flights: missing required data");
|
|
155
|
-
return { data:
|
|
144
|
+
return { data: "Missing required data for flight search" };
|
|
156
145
|
}
|
|
157
146
|
|
|
158
147
|
// Simulate flight search API call
|
|
@@ -176,19 +165,19 @@ const searchFlightsTool: Tool<FlightBookingContext, FlightData, [], void> = {
|
|
|
176
165
|
);
|
|
177
166
|
|
|
178
167
|
return {
|
|
179
|
-
data:
|
|
168
|
+
data: `Found ${flights.length} available flights`,
|
|
180
169
|
contextUpdate: {
|
|
181
170
|
availableFlights: flights,
|
|
182
171
|
},
|
|
183
172
|
dataUpdate: {
|
|
184
|
-
shouldSearchFlights: false,
|
|
185
|
-
}
|
|
173
|
+
shouldSearchFlights: false,
|
|
174
|
+
},
|
|
186
175
|
};
|
|
187
176
|
},
|
|
188
177
|
};
|
|
189
178
|
|
|
190
|
-
// Tool 4: Book the flight
|
|
191
|
-
const bookFlightTool: Tool<FlightBookingContext, FlightData
|
|
179
|
+
// Tool 4: Book the flight using unified Tool interface
|
|
180
|
+
const bookFlightTool: Tool<FlightBookingContext, FlightData> = {
|
|
192
181
|
id: "book_flight",
|
|
193
182
|
name: "Flight Booking Processor",
|
|
194
183
|
description: "Finalize the flight booking",
|
|
@@ -196,11 +185,11 @@ const bookFlightTool: Tool<FlightBookingContext, FlightData, [], void> = {
|
|
|
196
185
|
type: "object",
|
|
197
186
|
properties: {},
|
|
198
187
|
},
|
|
199
|
-
handler: (
|
|
200
|
-
const flightData = data
|
|
188
|
+
handler: async (toolContext, args) => {
|
|
189
|
+
const flightData = toolContext.data;
|
|
201
190
|
console.log("[Tool] Booking flight with data:", flightData);
|
|
202
191
|
// Simulate booking API call
|
|
203
|
-
return { data:
|
|
192
|
+
return { data: "Flight booking confirmed!" };
|
|
204
193
|
},
|
|
205
194
|
};
|
|
206
195
|
|
|
@@ -296,7 +285,7 @@ const agent = new Agent<FlightBookingContext, FlightData>({
|
|
|
296
285
|
description: "I help you find and book flights",
|
|
297
286
|
provider: new OpenAIProvider({
|
|
298
287
|
apiKey: process.env.OPENAI_API_KEY || "your-api-key-here",
|
|
299
|
-
model: "gpt-
|
|
288
|
+
model: "gpt-4o-mini",
|
|
300
289
|
}),
|
|
301
290
|
context: {},
|
|
302
291
|
// NEW: Agent-level schema
|
|
@@ -306,6 +295,117 @@ const agent = new Agent<FlightBookingContext, FlightData>({
|
|
|
306
295
|
},
|
|
307
296
|
});
|
|
308
297
|
|
|
298
|
+
// Pattern 1: Using the enrichDestinationConfig with inline tool creation
|
|
299
|
+
const enrichDestinationTool = {
|
|
300
|
+
id: "enrich_destination",
|
|
301
|
+
name: "Destination Code Lookup",
|
|
302
|
+
description: "Convert city names to IATA airport codes",
|
|
303
|
+
parameters: {
|
|
304
|
+
type: "object",
|
|
305
|
+
properties: {},
|
|
306
|
+
},
|
|
307
|
+
handler: async (context: ToolContext<FlightBookingContext, FlightData>, args?: Record<string, unknown>) => {
|
|
308
|
+
const destination = context.data.destination;
|
|
309
|
+
|
|
310
|
+
if (!destination) {
|
|
311
|
+
return { data: "No destination to enrich" };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Use the original enricher function from the config
|
|
315
|
+
const result = await enrichDestinationConfig.enricher(context.context, { destination });
|
|
316
|
+
|
|
317
|
+
console.log(`[Tool] Enriched: ${destination} → ${result.destinationCode}`);
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
data: `Destination code: ${result.destinationCode}`,
|
|
321
|
+
dataUpdate: result,
|
|
322
|
+
};
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// Pattern 2: Using the validateDateConfig with typed tool interface
|
|
327
|
+
const validateDateTool: Tool<FlightBookingContext, FlightData> = {
|
|
328
|
+
id: "validate_date",
|
|
329
|
+
name: "Date Parser & Validator",
|
|
330
|
+
description: "Parse relative dates (today, tomorrow) to ISO format and validate",
|
|
331
|
+
parameters: {
|
|
332
|
+
type: "object",
|
|
333
|
+
properties: {},
|
|
334
|
+
},
|
|
335
|
+
handler: async (context, args) => {
|
|
336
|
+
const departureDate = context.data.departureDate;
|
|
337
|
+
|
|
338
|
+
if (!departureDate) {
|
|
339
|
+
return { data: "No departure date to validate" };
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Use the original enricher function from the config
|
|
343
|
+
const result = await validateDateConfig.enricher(context.context, { departureDate });
|
|
344
|
+
|
|
345
|
+
console.log(`[Tool] Parsed date: ${departureDate} → ${result.departureDateParsed}`);
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
data: `Parsed date: ${result.departureDateParsed}`,
|
|
349
|
+
dataUpdate: result,
|
|
350
|
+
};
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// Demonstrate different registration methods for data enrichment tools
|
|
355
|
+
|
|
356
|
+
// Method 1: Register enrichment tools for ID-based reference
|
|
357
|
+
agent.tool.register(enrichDestinationTool);
|
|
358
|
+
agent.tool.register(validateDateTool);
|
|
359
|
+
|
|
360
|
+
// Method 2: Use registerMany for multiple tools
|
|
361
|
+
agent.tool.registerMany([searchFlightsTool, bookFlightTool]);
|
|
362
|
+
|
|
363
|
+
// Method 3: Create specialized data enrichment tools using the helper
|
|
364
|
+
const passengerEnrichmentTool = agent.tool.createDataEnrichment({
|
|
365
|
+
id: "enrich_passenger_info",
|
|
366
|
+
fields: ["passengers"] as const,
|
|
367
|
+
enricher: async (context, data) => {
|
|
368
|
+
// Add passenger type classification - return fields that exist in FlightData
|
|
369
|
+
const cabinClass = data.passengers === 1 ? "business" : data.passengers <= 4 ? "economy" : "economy";
|
|
370
|
+
return {
|
|
371
|
+
cabinClass, // This matches the cabinClass field in FlightData
|
|
372
|
+
};
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// Method 4: Create validation tool using the helper
|
|
377
|
+
const flightDataValidator = agent.tool.createValidation({
|
|
378
|
+
id: "validate_flight_data",
|
|
379
|
+
fields: ["destination", "departureDate", "passengers"] as const,
|
|
380
|
+
validator: async (context, data) => {
|
|
381
|
+
const errors: ValidationError[] = [];
|
|
382
|
+
if (!data.destination) errors.push({
|
|
383
|
+
field: "destination",
|
|
384
|
+
value: data.destination,
|
|
385
|
+
message: "Destination is required",
|
|
386
|
+
schemaPath: "destination"
|
|
387
|
+
});
|
|
388
|
+
if (!data.departureDate) errors.push({
|
|
389
|
+
field: "departureDate",
|
|
390
|
+
value: data.departureDate,
|
|
391
|
+
message: "Departure date is required",
|
|
392
|
+
schemaPath: "departureDate"
|
|
393
|
+
});
|
|
394
|
+
if (!data.passengers || data.passengers < 1) errors.push({
|
|
395
|
+
field: "passengers",
|
|
396
|
+
value: data.passengers,
|
|
397
|
+
message: "At least 1 passenger required",
|
|
398
|
+
schemaPath: "passengers"
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
return {
|
|
402
|
+
valid: errors.length === 0,
|
|
403
|
+
errors,
|
|
404
|
+
warnings: [],
|
|
405
|
+
};
|
|
406
|
+
},
|
|
407
|
+
});
|
|
408
|
+
|
|
309
409
|
// Define route with data extraction
|
|
310
410
|
const bookingRoute = agent.createRoute({
|
|
311
411
|
title: "Book Flight",
|
|
@@ -320,6 +420,13 @@ const bookingRoute = agent.createRoute({
|
|
|
320
420
|
optionalFields: ["destinationCode", "departureDateParsed", "cabinClass", "shouldSearchFlights"],
|
|
321
421
|
});
|
|
322
422
|
|
|
423
|
+
// Method 5: Add route-scoped tools (only available in this route)
|
|
424
|
+
bookingRoute.addTool({
|
|
425
|
+
id: "route_specific_tool",
|
|
426
|
+
description: "Tool only available in booking route",
|
|
427
|
+
handler: () => "This tool is scoped to the booking route only",
|
|
428
|
+
});
|
|
429
|
+
|
|
323
430
|
// Step 1: Collect destination
|
|
324
431
|
const collectDestination = bookingRoute.initialStep.nextStep({
|
|
325
432
|
prompt: "Ask where they want to fly",
|
|
@@ -329,7 +436,7 @@ const collectDestination = bookingRoute.initialStep.nextStep({
|
|
|
329
436
|
|
|
330
437
|
// Step 2: Enrich destination (tool execution)
|
|
331
438
|
const enrichDestination = collectDestination.nextStep({
|
|
332
|
-
tools: [
|
|
439
|
+
tools: ["enrich_destination"], // Reference by ID
|
|
333
440
|
requires: ["destination"],
|
|
334
441
|
});
|
|
335
442
|
|
|
@@ -342,7 +449,7 @@ const collectDate = enrichDestination.nextStep({
|
|
|
342
449
|
|
|
343
450
|
// Step 4: Validate/parse date (tool execution)
|
|
344
451
|
const validateDate = collectDate.nextStep({
|
|
345
|
-
tools: [
|
|
452
|
+
tools: ["validate_date"], // Reference by ID
|
|
346
453
|
requires: ["departureDate"],
|
|
347
454
|
});
|
|
348
455
|
|
|
@@ -355,7 +462,7 @@ const collectPassengers = validateDate.nextStep({
|
|
|
355
462
|
|
|
356
463
|
// Step 6: Search flights (triggered by hook setting shouldSearchFlights)
|
|
357
464
|
const searchFlights = collectPassengers.nextStep({
|
|
358
|
-
tools: [
|
|
465
|
+
tools: ["search_flights"], // Reference by ID
|
|
359
466
|
// This step is entered when shouldSearchFlights is true
|
|
360
467
|
// The hook automatically sets this flag when all data is collected
|
|
361
468
|
});
|
|
@@ -371,9 +478,12 @@ const confirmBooking = presentResults.nextStep({
|
|
|
371
478
|
requires: ["destinationCode", "departureDateParsed", "passengers"],
|
|
372
479
|
});
|
|
373
480
|
|
|
481
|
+
// Method 6: Step-scoped tools can be added via the step's tools array
|
|
482
|
+
// Note: Step-scoped tools are typically defined inline in the step configuration
|
|
483
|
+
|
|
374
484
|
// Step 9: Finalize booking
|
|
375
485
|
const finalizeBooking = confirmBooking.nextStep({
|
|
376
|
-
tools: [
|
|
486
|
+
tools: ["book_flight"], // Reference by ID
|
|
377
487
|
when: "User confirms the booking",
|
|
378
488
|
});
|
|
379
489
|
|
package/package.json
CHANGED
package/src/core/Agent.ts
CHANGED
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
StructuredSchema,
|
|
17
17
|
ValidationError,
|
|
18
18
|
ValidationResult,
|
|
19
|
+
|
|
19
20
|
} from "../types";
|
|
20
21
|
import type { StreamOptions, GenerateOptions, RespondParams } from "./ResponseModal";
|
|
21
22
|
import {
|
|
@@ -30,8 +31,9 @@ import { Step } from "./Step";
|
|
|
30
31
|
import { PersistenceManager } from "./PersistenceManager";
|
|
31
32
|
import { SessionManager } from "./SessionManager";
|
|
32
33
|
import { RoutingEngine } from "./RoutingEngine";
|
|
33
|
-
|
|
34
|
+
|
|
34
35
|
import { ResponseModal } from "./ResponseModal";
|
|
36
|
+
import { ToolManager } from "./ToolManager";
|
|
35
37
|
|
|
36
38
|
/**
|
|
37
39
|
* Error thrown when data validation fails
|
|
@@ -60,7 +62,7 @@ class RouteConfigurationError extends Error {
|
|
|
60
62
|
export class Agent<TContext = any, TData = any> {
|
|
61
63
|
private terms: Term<TContext, TData>[] = [];
|
|
62
64
|
private guidelines: Guideline<TContext, TData>[] = [];
|
|
63
|
-
private tools: Tool<TContext, TData
|
|
65
|
+
private tools: Tool<TContext, TData>[] = [];
|
|
64
66
|
private routes: Route<TContext, TData>[] = [];
|
|
65
67
|
private context: TContext | undefined;
|
|
66
68
|
private persistenceManager: PersistenceManager<TData> | undefined;
|
|
@@ -74,6 +76,9 @@ export class Agent<TContext = any, TData = any> {
|
|
|
74
76
|
/** Public session manager for easy session management */
|
|
75
77
|
public session: SessionManager<TData>;
|
|
76
78
|
|
|
79
|
+
/** Public tool manager for simplified tool creation and management */
|
|
80
|
+
public tool: ToolManager<TContext, TData>;
|
|
81
|
+
|
|
77
82
|
constructor(private readonly options: AgentOptions<TContext, TData>) {
|
|
78
83
|
// Set log level based on debug option
|
|
79
84
|
if (options.debug) {
|
|
@@ -188,13 +193,23 @@ export class Agent<TContext = any, TData = any> {
|
|
|
188
193
|
this.knowledgeBase = { ...options.knowledgeBase };
|
|
189
194
|
}
|
|
190
195
|
|
|
191
|
-
// Initialize session manager
|
|
192
|
-
this.session = new SessionManager<TData>(this.persistenceManager);
|
|
196
|
+
// Initialize session manager with reference to this agent for bidirectional sync
|
|
197
|
+
this.session = new SessionManager<TData>(this.persistenceManager, this);
|
|
198
|
+
|
|
199
|
+
// Initialize tool manager with proper type inference
|
|
200
|
+
this.tool = new ToolManager<TContext, TData>(this);
|
|
193
201
|
|
|
194
202
|
// Store sessionId for later use in getOrCreate calls
|
|
195
203
|
if (options.sessionId) {
|
|
204
|
+
this.session.setDefaultSessionId(options.sessionId);
|
|
196
205
|
// The session will be loaded on first getOrCreate call
|
|
197
|
-
this.session.getOrCreate(options.sessionId).
|
|
206
|
+
this.session.getOrCreate(options.sessionId).then((session) => {
|
|
207
|
+
// Sync session data to agent collected data
|
|
208
|
+
if (session.data && Object.keys(session.data).length > 0) {
|
|
209
|
+
this.collectedData = { ...session.data };
|
|
210
|
+
logger.debug("[Agent] Synced session data to collected data:", this.collectedData);
|
|
211
|
+
}
|
|
212
|
+
}).catch((err) => {
|
|
198
213
|
logger.error("Failed to start session", err);
|
|
199
214
|
});
|
|
200
215
|
}
|
|
@@ -294,6 +309,8 @@ export class Agent<TContext = any, TData = any> {
|
|
|
294
309
|
* Get the current collected data
|
|
295
310
|
*/
|
|
296
311
|
getCollectedData(): Partial<TData> {
|
|
312
|
+
// Ensure agent collected data is synced with session
|
|
313
|
+
this.syncSessionDataToCollectedData();
|
|
297
314
|
return { ...this.collectedData };
|
|
298
315
|
}
|
|
299
316
|
|
|
@@ -334,6 +351,13 @@ export class Agent<TContext = any, TData = any> {
|
|
|
334
351
|
this.currentSession = mergeCollected(this.currentSession, this.collectedData);
|
|
335
352
|
}
|
|
336
353
|
|
|
354
|
+
// Also update the session manager's session data (avoid circular call)
|
|
355
|
+
const sessionManagerSession = this.session.current;
|
|
356
|
+
if (sessionManagerSession) {
|
|
357
|
+
sessionManagerSession.data = { ...this.collectedData };
|
|
358
|
+
sessionManagerSession.metadata!.lastUpdatedAt = new Date();
|
|
359
|
+
}
|
|
360
|
+
|
|
337
361
|
logger.debug("[Agent] Collected data updated:", updates);
|
|
338
362
|
}
|
|
339
363
|
|
|
@@ -401,7 +425,7 @@ export class Agent<TContext = any, TData = any> {
|
|
|
401
425
|
}
|
|
402
426
|
}
|
|
403
427
|
|
|
404
|
-
const route = new Route<TContext, TData>(options);
|
|
428
|
+
const route = new Route<TContext, TData>(options, this);
|
|
405
429
|
this.routes.push(route);
|
|
406
430
|
return route;
|
|
407
431
|
}
|
|
@@ -428,18 +452,53 @@ export class Agent<TContext = any, TData = any> {
|
|
|
428
452
|
}
|
|
429
453
|
|
|
430
454
|
/**
|
|
431
|
-
*
|
|
455
|
+
* Add a tool to the agent using the unified Tool interface
|
|
456
|
+
* Creates and adds the tool to agent scope in one operation (BREAKING CHANGE: replaces createTool)
|
|
457
|
+
*/
|
|
458
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
459
|
+
addTool<TResult = any>(
|
|
460
|
+
tool: Tool<TContext, TData, TResult>
|
|
461
|
+
): this {
|
|
462
|
+
// Validate tool before adding
|
|
463
|
+
if (!tool || !tool.id || !tool.handler) {
|
|
464
|
+
throw new Error('Invalid tool: must have id and handler properties');
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Add directly to agent's tools array, preserving the TResult type
|
|
468
|
+
this.tools.push(tool);
|
|
469
|
+
logger.debug(`[Agent] Added tool to agent scope: ${tool.id}`);
|
|
470
|
+
return this;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Register a tool at the agent level (legacy method for backward compatibility)
|
|
475
|
+
* @deprecated Use addTool() with Tool interface instead
|
|
432
476
|
*/
|
|
433
|
-
|
|
477
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
478
|
+
createTool<TResult = any>(tool: Tool<TContext, TData, TResult>): this {
|
|
479
|
+
// Validate tool before adding
|
|
480
|
+
if (!tool || !tool.id || !tool.handler) {
|
|
481
|
+
throw new Error('Invalid tool: must have id and handler properties');
|
|
482
|
+
}
|
|
483
|
+
|
|
434
484
|
this.tools.push(tool);
|
|
485
|
+
logger.debug(`[Agent] Created tool (legacy): ${tool.id}`);
|
|
435
486
|
return this;
|
|
436
487
|
}
|
|
437
488
|
|
|
438
489
|
/**
|
|
439
490
|
* Register multiple tools at the agent level
|
|
440
491
|
*/
|
|
441
|
-
|
|
442
|
-
|
|
492
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
493
|
+
registerTools<TResult = any>(tools: Tool<TContext, TData, TResult>[]): this {
|
|
494
|
+
tools.forEach((tool) => {
|
|
495
|
+
// Validate each tool before adding
|
|
496
|
+
if (!tool || !tool.id || !tool.handler) {
|
|
497
|
+
throw new Error(`Invalid tool in batch: must have id and handler properties (tool: ${tool?.id || 'unknown'})`);
|
|
498
|
+
}
|
|
499
|
+
this.tools.push(tool);
|
|
500
|
+
});
|
|
501
|
+
logger.debug(`[Agent] Registered ${tools.length} tools`);
|
|
443
502
|
return this;
|
|
444
503
|
}
|
|
445
504
|
|
|
@@ -598,7 +657,7 @@ export class Agent<TContext = any, TData = any> {
|
|
|
598
657
|
/**
|
|
599
658
|
* Get all tools
|
|
600
659
|
*/
|
|
601
|
-
getTools(): Tool<TContext, TData
|
|
660
|
+
getTools(): Tool<TContext, TData>[] {
|
|
602
661
|
return [...this.tools];
|
|
603
662
|
}
|
|
604
663
|
|
|
@@ -660,7 +719,7 @@ export class Agent<TContext = any, TData = any> {
|
|
|
660
719
|
async executePrepareFinalize(
|
|
661
720
|
prepareOrFinalize:
|
|
662
721
|
| string
|
|
663
|
-
| Tool<TContext, TData
|
|
722
|
+
| Tool<TContext, TData>
|
|
664
723
|
| ((context: TContext, data?: Partial<TData>) => void | Promise<void>)
|
|
665
724
|
| undefined,
|
|
666
725
|
context: TContext,
|
|
@@ -675,44 +734,24 @@ export class Agent<TContext = any, TData = any> {
|
|
|
675
734
|
await prepareOrFinalize(context, data);
|
|
676
735
|
} else {
|
|
677
736
|
// It's a tool reference - find and execute the tool
|
|
678
|
-
let tool: Tool<TContext, TData
|
|
737
|
+
let tool: Tool<TContext, TData> | undefined;
|
|
679
738
|
|
|
680
739
|
if (typeof prepareOrFinalize === "string") {
|
|
681
|
-
// Tool ID - find it
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
// Add agent-level tools
|
|
685
|
-
this.tools.forEach((t) => {
|
|
686
|
-
availableTools.set(t.id, t);
|
|
687
|
-
});
|
|
688
|
-
|
|
689
|
-
// Add route-level tools
|
|
690
|
-
if (route) {
|
|
691
|
-
route.getTools().forEach((t) => {
|
|
692
|
-
availableTools.set(t.id, t);
|
|
693
|
-
});
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
// Add step-level tools
|
|
697
|
-
if (step?.tools) {
|
|
698
|
-
for (const toolRef of step.tools) {
|
|
699
|
-
if (typeof toolRef === "string") {
|
|
700
|
-
// Keep as is
|
|
701
|
-
} else if (toolRef.id) {
|
|
702
|
-
availableTools.set(toolRef.id, toolRef);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
tool = availableTools.get(prepareOrFinalize);
|
|
740
|
+
// Tool ID - use ToolManager to find it across all scopes
|
|
741
|
+
tool = this.tool.find(prepareOrFinalize, undefined, step, route);
|
|
708
742
|
} else {
|
|
709
|
-
// Tool object -
|
|
710
|
-
|
|
743
|
+
// Tool object - validate it has required properties
|
|
744
|
+
if (prepareOrFinalize.id && typeof prepareOrFinalize.handler === 'function') {
|
|
745
|
+
tool = prepareOrFinalize;
|
|
746
|
+
} else {
|
|
747
|
+
logger.error(`[Agent] Invalid tool object for prepare/finalize: missing id or invalid handler`);
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
711
750
|
}
|
|
712
751
|
|
|
713
752
|
if (tool) {
|
|
714
|
-
|
|
715
|
-
const result = await
|
|
753
|
+
// Use ToolManager for execution
|
|
754
|
+
const result = await this.tool.executeTool({
|
|
716
755
|
tool,
|
|
717
756
|
context,
|
|
718
757
|
updateContext: this.updateContext.bind(this),
|
|
@@ -745,12 +784,27 @@ export class Agent<TContext = any, TData = any> {
|
|
|
745
784
|
this.currentSession = undefined;
|
|
746
785
|
}
|
|
747
786
|
|
|
787
|
+
/**
|
|
788
|
+
* Sync session data to agent collected data
|
|
789
|
+
* @internal Used to keep agent and session data in sync
|
|
790
|
+
*/
|
|
791
|
+
private syncSessionDataToCollectedData(): void {
|
|
792
|
+
const sessionData = this.session.getData();
|
|
793
|
+
if (sessionData && Object.keys(sessionData).length > 0) {
|
|
794
|
+
this.collectedData = { ...sessionData };
|
|
795
|
+
logger.debug("[Agent] Synced session data to collected data:", this.collectedData);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
748
799
|
/**
|
|
749
800
|
* Get collected data from current session or agent-level collected data
|
|
750
801
|
* @param routeId - Optional route ID to get data for (uses current route if not provided)
|
|
751
802
|
* @returns The collected data from the current session or agent-level data
|
|
752
803
|
*/
|
|
753
804
|
getData(): Partial<TData> {
|
|
805
|
+
// Ensure agent collected data is synced with session
|
|
806
|
+
this.syncSessionDataToCollectedData();
|
|
807
|
+
|
|
754
808
|
// If we have a current session, use session data
|
|
755
809
|
if (this.currentSession) {
|
|
756
810
|
// With agent-level data, all routes share the same data structure
|