@falai/agent 0.6.7 → 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.
Files changed (60) hide show
  1. package/README.md +162 -30
  2. package/dist/cjs/core/Agent.d.ts +18 -0
  3. package/dist/cjs/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/core/Agent.js +218 -15
  5. package/dist/cjs/core/Agent.js.map +1 -1
  6. package/dist/cjs/core/Route.d.ts +12 -1
  7. package/dist/cjs/core/Route.d.ts.map +1 -1
  8. package/dist/cjs/core/Route.js +38 -1
  9. package/dist/cjs/core/Route.js.map +1 -1
  10. package/dist/cjs/core/RoutingEngine.d.ts.map +1 -1
  11. package/dist/cjs/core/RoutingEngine.js +3 -1
  12. package/dist/cjs/core/RoutingEngine.js.map +1 -1
  13. package/dist/cjs/core/State.js +1 -1
  14. package/dist/cjs/core/State.js.map +1 -1
  15. package/dist/cjs/index.d.ts +2 -2
  16. package/dist/cjs/index.d.ts.map +1 -1
  17. package/dist/cjs/index.js.map +1 -1
  18. package/dist/cjs/types/route.d.ts +51 -0
  19. package/dist/cjs/types/route.d.ts.map +1 -1
  20. package/dist/cjs/types/session.d.ts +17 -1
  21. package/dist/cjs/types/session.d.ts.map +1 -1
  22. package/dist/cjs/types/session.js.map +1 -1
  23. package/dist/core/Agent.d.ts +18 -0
  24. package/dist/core/Agent.d.ts.map +1 -1
  25. package/dist/core/Agent.js +219 -16
  26. package/dist/core/Agent.js.map +1 -1
  27. package/dist/core/Route.d.ts +12 -1
  28. package/dist/core/Route.d.ts.map +1 -1
  29. package/dist/core/Route.js +38 -1
  30. package/dist/core/Route.js.map +1 -1
  31. package/dist/core/RoutingEngine.d.ts.map +1 -1
  32. package/dist/core/RoutingEngine.js +3 -1
  33. package/dist/core/RoutingEngine.js.map +1 -1
  34. package/dist/core/State.js +1 -1
  35. package/dist/core/State.js.map +1 -1
  36. package/dist/index.d.ts +2 -2
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/types/route.d.ts +51 -0
  40. package/dist/types/route.d.ts.map +1 -1
  41. package/dist/types/session.d.ts +17 -1
  42. package/dist/types/session.d.ts.map +1 -1
  43. package/dist/types/session.js.map +1 -1
  44. package/docs/EXAMPLES.md +51 -2
  45. package/docs/ROUTES.md +345 -1
  46. package/docs/STATES.md +97 -7
  47. package/examples/business-onboarding.ts +10 -12
  48. package/examples/company-qna-agent.ts +4 -5
  49. package/examples/healthcare-agent.ts +63 -0
  50. package/examples/persistent-onboarding.ts +6 -8
  51. package/examples/route-transitions.ts +242 -0
  52. package/examples/travel-agent.ts +60 -0
  53. package/package.json +1 -1
  54. package/src/core/Agent.ts +338 -16
  55. package/src/core/Route.ts +53 -1
  56. package/src/core/RoutingEngine.ts +3 -1
  57. package/src/core/State.ts +1 -1
  58. package/src/index.ts +3 -1
  59. package/src/types/route.ts +57 -0
  60. 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);
@@ -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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@falai/agent",
3
- "version": "0.6.7",
3
+ "version": "0.6.8",
4
4
  "description": "Standalone, strongly-typed AI Agent framework with route DSL and AI provider strategy",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",