@falai/agent 0.6.6 → 0.6.8
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 +162 -30
- package/dist/cjs/core/Agent.d.ts +18 -0
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +219 -16
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/Route.d.ts +12 -1
- package/dist/cjs/core/Route.d.ts.map +1 -1
- package/dist/cjs/core/Route.js +38 -1
- package/dist/cjs/core/Route.js.map +1 -1
- package/dist/cjs/core/RoutingEngine.d.ts.map +1 -1
- package/dist/cjs/core/RoutingEngine.js +3 -1
- package/dist/cjs/core/RoutingEngine.js.map +1 -1
- package/dist/cjs/core/State.js +1 -1
- package/dist/cjs/core/State.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/route.d.ts +51 -0
- package/dist/cjs/types/route.d.ts.map +1 -1
- package/dist/cjs/types/session.d.ts +17 -1
- package/dist/cjs/types/session.d.ts.map +1 -1
- package/dist/cjs/types/session.js.map +1 -1
- package/dist/core/Agent.d.ts +18 -0
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +220 -17
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/Route.d.ts +12 -1
- package/dist/core/Route.d.ts.map +1 -1
- package/dist/core/Route.js +38 -1
- package/dist/core/Route.js.map +1 -1
- package/dist/core/RoutingEngine.d.ts.map +1 -1
- package/dist/core/RoutingEngine.js +3 -1
- package/dist/core/RoutingEngine.js.map +1 -1
- package/dist/core/State.js +1 -1
- package/dist/core/State.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/route.d.ts +51 -0
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/session.d.ts +17 -1
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js.map +1 -1
- package/docs/EXAMPLES.md +51 -2
- package/docs/ROUTES.md +345 -1
- package/docs/STATES.md +97 -7
- package/examples/business-onboarding.ts +10 -12
- package/examples/company-qna-agent.ts +4 -5
- package/examples/healthcare-agent.ts +63 -0
- package/examples/persistent-onboarding.ts +6 -8
- package/examples/route-transitions.ts +242 -0
- package/examples/travel-agent.ts +60 -0
- package/package.json +1 -1
- package/src/core/Agent.ts +339 -17
- package/src/core/Route.ts +53 -1
- package/src/core/RoutingEngine.ts +3 -1
- package/src/core/State.ts +1 -1
- package/src/index.ts +3 -1
- package/src/types/route.ts +57 -0
- package/src/types/session.ts +20 -2
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route Transitions Example
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates how to use onComplete to automatically transition between routes
|
|
5
|
+
* after a route completes, enabling flows like:
|
|
6
|
+
* - Post-booking feedback collection
|
|
7
|
+
* - Upsell after purchase
|
|
8
|
+
* - Satisfaction surveys after support
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
Agent,
|
|
13
|
+
GeminiProvider,
|
|
14
|
+
createMessageEvent,
|
|
15
|
+
EventSource,
|
|
16
|
+
END_STATE,
|
|
17
|
+
type SessionState,
|
|
18
|
+
} from "../src/index";
|
|
19
|
+
|
|
20
|
+
// Type definitions for our booking data
|
|
21
|
+
interface BookingData {
|
|
22
|
+
hotelName: string;
|
|
23
|
+
date: string;
|
|
24
|
+
guests: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface FeedbackData {
|
|
28
|
+
rating: number;
|
|
29
|
+
comments?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function main() {
|
|
33
|
+
// Create agent
|
|
34
|
+
const agent = new Agent({
|
|
35
|
+
name: "HotelBot",
|
|
36
|
+
description: "A hotel booking assistant with feedback collection",
|
|
37
|
+
ai: new GeminiProvider({
|
|
38
|
+
apiKey: process.env.GEMINI_API_KEY!,
|
|
39
|
+
model: "models/gemini-2.0-flash-exp",
|
|
40
|
+
}),
|
|
41
|
+
debug: true,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Route 1: Hotel Booking
|
|
45
|
+
const bookingRoute = agent.createRoute<BookingData>({
|
|
46
|
+
title: "Book Hotel",
|
|
47
|
+
description: "Collects hotel booking information",
|
|
48
|
+
conditions: ["User wants to book a hotel"],
|
|
49
|
+
extractionSchema: {
|
|
50
|
+
type: "object",
|
|
51
|
+
properties: {
|
|
52
|
+
hotelName: { type: "string" },
|
|
53
|
+
date: { type: "string" },
|
|
54
|
+
guests: { type: "number" },
|
|
55
|
+
},
|
|
56
|
+
required: ["hotelName", "date", "guests"],
|
|
57
|
+
},
|
|
58
|
+
// Configure completion message at route level
|
|
59
|
+
endState: {
|
|
60
|
+
chatState: "Confirm the booking with a summary of the hotel, date, and number of guests. Be enthusiastic!",
|
|
61
|
+
},
|
|
62
|
+
// Option 1: Simple string
|
|
63
|
+
onComplete: "Collect Feedback",
|
|
64
|
+
// Option 2: Object with condition
|
|
65
|
+
// onComplete: {
|
|
66
|
+
// transitionTo: "Collect Feedback",
|
|
67
|
+
// condition: "if booking was successful"
|
|
68
|
+
// },
|
|
69
|
+
// Option 3: Function with logic
|
|
70
|
+
// onComplete: (session) => {
|
|
71
|
+
// if (session.extracted?.guests && session.extracted.guests > 5) {
|
|
72
|
+
// return "VIP Feedback"; // Different feedback for large groups
|
|
73
|
+
// }
|
|
74
|
+
// return "Collect Feedback";
|
|
75
|
+
// },
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const askHotel = bookingRoute.initialState.transitionTo({
|
|
79
|
+
chatState: "Ask which hotel they want to book",
|
|
80
|
+
gather: ["hotelName"],
|
|
81
|
+
skipIf: (extracted) => !!extracted.hotelName,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const askDate = askHotel.transitionTo({
|
|
85
|
+
chatState: "Ask for the booking date",
|
|
86
|
+
gather: ["date"],
|
|
87
|
+
skipIf: (extracted) => !!extracted.date,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const askGuests = askDate.transitionTo({
|
|
91
|
+
chatState: "Ask for the number of guests",
|
|
92
|
+
gather: ["guests"],
|
|
93
|
+
skipIf: (extracted) => !!extracted.guests,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// No need to specify chatState here - using route-level endState configuration
|
|
97
|
+
askGuests.transitionTo({
|
|
98
|
+
state: END_STATE,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Route 2: Feedback Collection
|
|
102
|
+
const feedbackRoute = agent.createRoute<FeedbackData>({
|
|
103
|
+
title: "Collect Feedback",
|
|
104
|
+
description: "Collects user feedback after booking",
|
|
105
|
+
conditions: ["User wants to provide feedback"],
|
|
106
|
+
extractionSchema: {
|
|
107
|
+
type: "object",
|
|
108
|
+
properties: {
|
|
109
|
+
rating: { type: "number" },
|
|
110
|
+
comments: { type: "string" },
|
|
111
|
+
},
|
|
112
|
+
required: ["rating"],
|
|
113
|
+
},
|
|
114
|
+
// Configure completion message for feedback route
|
|
115
|
+
endState: {
|
|
116
|
+
chatState: "Thank the user warmly for their feedback and let them know their input is valuable",
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const askRating = feedbackRoute.initialState.transitionTo({
|
|
121
|
+
chatState: "Ask for rating from 1 to 5",
|
|
122
|
+
gather: ["rating"],
|
|
123
|
+
skipIf: (extracted) => !!extracted.rating,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const askComments = askRating.transitionTo({
|
|
127
|
+
chatState: "Ask for any additional comments (optional)",
|
|
128
|
+
gather: ["comments"],
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// No need to specify chatState here - using route-level endState configuration
|
|
132
|
+
askComments.transitionTo({
|
|
133
|
+
state: END_STATE,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
console.log("\n=== Route Transitions Example ===\n");
|
|
137
|
+
|
|
138
|
+
// Conversation 1: User provides all booking info at once
|
|
139
|
+
let session: SessionState | undefined;
|
|
140
|
+
let history = [
|
|
141
|
+
createMessageEvent(
|
|
142
|
+
EventSource.CUSTOMER,
|
|
143
|
+
"Alice",
|
|
144
|
+
"I want to book the Grand Hotel for 2 guests on December 25th"
|
|
145
|
+
),
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
console.log("User:", history[0].data.message);
|
|
149
|
+
|
|
150
|
+
// First response - should handle booking
|
|
151
|
+
const response1 = await agent.respond({ history, session });
|
|
152
|
+
console.log("\nBot:", response1.message);
|
|
153
|
+
console.log("Route complete?", response1.isRouteComplete);
|
|
154
|
+
console.log(
|
|
155
|
+
"Pending transition?",
|
|
156
|
+
response1.session?.pendingTransition?.targetRouteId
|
|
157
|
+
);
|
|
158
|
+
console.log("Extracted booking data:", response1.session?.extracted);
|
|
159
|
+
|
|
160
|
+
session = response1.session;
|
|
161
|
+
history = [
|
|
162
|
+
...history,
|
|
163
|
+
{ ...createMessageEvent(EventSource.AI_AGENT, "Bot", response1.message), id: "2" },
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
// Second response - should auto-transition to a feedback route
|
|
167
|
+
history = [
|
|
168
|
+
...history,
|
|
169
|
+
createMessageEvent(EventSource.CUSTOMER, "Alice", "Yes, please proceed!"),
|
|
170
|
+
];
|
|
171
|
+
console.log("\nUser:", "Yes, please proceed!");
|
|
172
|
+
|
|
173
|
+
const response2 = await agent.respond({ history, session });
|
|
174
|
+
console.log("\nBot:", response2.message);
|
|
175
|
+
console.log("Current route:", response2.session?.currentRoute?.title);
|
|
176
|
+
console.log("Route complete?", response2.isRouteComplete);
|
|
177
|
+
|
|
178
|
+
session = response2.session;
|
|
179
|
+
history = [
|
|
180
|
+
...history,
|
|
181
|
+
{ ...createMessageEvent(EventSource.AI_AGENT, "Bot", response2.message), id: "4" },
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
// Third response - provide rating
|
|
185
|
+
history = [
|
|
186
|
+
...history,
|
|
187
|
+
createMessageEvent(
|
|
188
|
+
EventSource.CUSTOMER,
|
|
189
|
+
"Alice",
|
|
190
|
+
"I'd rate it 5 stars! The process was very smooth."
|
|
191
|
+
),
|
|
192
|
+
];
|
|
193
|
+
console.log("\nUser:", "I'd rate it 5 stars! The process was very smooth.");
|
|
194
|
+
|
|
195
|
+
const response3 = await agent.respond({ history, session });
|
|
196
|
+
console.log("\nBot:", response3.message);
|
|
197
|
+
console.log("Current route:", response3.session?.currentRoute?.title);
|
|
198
|
+
console.log("Extracted feedback data:", response3.session?.extracted);
|
|
199
|
+
console.log("Route complete?", response3.isRouteComplete);
|
|
200
|
+
|
|
201
|
+
console.log("\n=== Manual Transition Example ===\n");
|
|
202
|
+
|
|
203
|
+
// Demonstrate manual transition using agent.transitionToRoute()
|
|
204
|
+
let session2: SessionState | undefined;
|
|
205
|
+
let history2 = [
|
|
206
|
+
createMessageEvent(
|
|
207
|
+
EventSource.CUSTOMER,
|
|
208
|
+
"Bob",
|
|
209
|
+
"I want to book the Sunset Resort for 4 people on New Year's Eve"
|
|
210
|
+
),
|
|
211
|
+
];
|
|
212
|
+
|
|
213
|
+
console.log("User:", history2[0].data.message);
|
|
214
|
+
|
|
215
|
+
const manualResponse = await agent.respond({ history: history2, session: session2 });
|
|
216
|
+
console.log("\nBot:", manualResponse.message);
|
|
217
|
+
console.log("Route complete?", manualResponse.isRouteComplete);
|
|
218
|
+
|
|
219
|
+
if (manualResponse.isRouteComplete && manualResponse.session) {
|
|
220
|
+
// Manually trigger transition instead of auto-transition
|
|
221
|
+
console.log("\n[Manually transitioning to feedback route...]");
|
|
222
|
+
session2 = agent.transitionToRoute("Collect Feedback", manualResponse.session);
|
|
223
|
+
console.log(
|
|
224
|
+
"Pending transition set:",
|
|
225
|
+
session2.pendingTransition?.targetRouteId
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
history2 = [
|
|
229
|
+
...history2,
|
|
230
|
+
{ ...createMessageEvent(EventSource.AI_AGENT, "Bot", manualResponse.message), id: "2" },
|
|
231
|
+
createMessageEvent(EventSource.CUSTOMER, "Bob", "Great!"),
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
const feedbackResponse = await agent.respond({ history: history2, session: session2 });
|
|
235
|
+
console.log("\nBot:", feedbackResponse.message);
|
|
236
|
+
console.log("Current route:", feedbackResponse.session?.currentRoute?.title);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
console.log("\n=== Done ===\n");
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
main().catch(console.error);
|
package/examples/travel-agent.ts
CHANGED
|
@@ -37,6 +37,12 @@ interface BookingStatusData {
|
|
|
37
37
|
email?: string;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
interface TravelFeedbackData {
|
|
41
|
+
rating: number;
|
|
42
|
+
bookingExperience?: string;
|
|
43
|
+
recommendToFriend?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
40
46
|
// Tools with data access
|
|
41
47
|
const getAvailableDestinations = defineTool(
|
|
42
48
|
"get_available_destinations",
|
|
@@ -219,11 +225,20 @@ async function createTravelAgent() {
|
|
|
219
225
|
});
|
|
220
226
|
|
|
221
227
|
// Create flight booking route with data extraction
|
|
228
|
+
// NEW: Added onComplete to automatically collect feedback after booking
|
|
222
229
|
const flightBookingRoute = agent.createRoute<FlightBookingData>({
|
|
223
230
|
title: "Book a Flight",
|
|
224
231
|
description:
|
|
225
232
|
"Helps the customer find and book a flight to their desired destination.",
|
|
226
233
|
conditions: ["The customer wants to book a flight"],
|
|
234
|
+
// NEW: Transition to feedback collection after successful booking
|
|
235
|
+
onComplete: (session) => {
|
|
236
|
+
// Dynamic logic: only collect feedback if destination is known
|
|
237
|
+
if (session.extracted?.destination) {
|
|
238
|
+
return "Travel Feedback";
|
|
239
|
+
}
|
|
240
|
+
return undefined; // No transition
|
|
241
|
+
},
|
|
227
242
|
extractionSchema: {
|
|
228
243
|
type: "object",
|
|
229
244
|
properties: {
|
|
@@ -393,6 +408,51 @@ async function createTravelAgent() {
|
|
|
393
408
|
condition: "Booking information provided to customer",
|
|
394
409
|
});
|
|
395
410
|
|
|
411
|
+
// NEW: Travel Feedback route - collects feedback after booking
|
|
412
|
+
const feedbackRoute = agent.createRoute<TravelFeedbackData>({
|
|
413
|
+
title: "Travel Feedback",
|
|
414
|
+
description: "Collects customer feedback after flight booking",
|
|
415
|
+
conditions: ["Collect travel booking feedback"],
|
|
416
|
+
extractionSchema: {
|
|
417
|
+
type: "object",
|
|
418
|
+
properties: {
|
|
419
|
+
rating: {
|
|
420
|
+
type: "number",
|
|
421
|
+
description: "Overall booking experience rating 1-5",
|
|
422
|
+
},
|
|
423
|
+
bookingExperience: {
|
|
424
|
+
type: "string",
|
|
425
|
+
description: "Description of booking experience",
|
|
426
|
+
},
|
|
427
|
+
recommendToFriend: {
|
|
428
|
+
type: "boolean",
|
|
429
|
+
description: "Would they recommend us to a friend",
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
required: ["rating"],
|
|
433
|
+
},
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
const askFeedbackRating = feedbackRoute.initialState.transitionTo({
|
|
437
|
+
chatState:
|
|
438
|
+
"Ask for overall rating from 1 to 5 for the booking experience",
|
|
439
|
+
gather: ["rating"],
|
|
440
|
+
skipIf: (extracted) => !!extracted.rating,
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
const askRecommendation = askFeedbackRating.transitionTo({
|
|
444
|
+
chatState:
|
|
445
|
+
"Ask if they would recommend our service to a friend (yes/no)",
|
|
446
|
+
gather: ["recommendToFriend"],
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
const thankForFeedback = askRecommendation.transitionTo({
|
|
450
|
+
chatState:
|
|
451
|
+
"Thank them for their feedback and wish them a great trip!",
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
thankForFeedback.transitionTo({ state: END_STATE });
|
|
455
|
+
|
|
396
456
|
// Global guidelines
|
|
397
457
|
agent.createGuideline({
|
|
398
458
|
condition: "The customer asks about travel insurance",
|