@falai/agent 0.5.5 → 0.6.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/dist/cjs/core/ResponseEngine.js +2 -2
- package/dist/cjs/core/ResponseEngine.js.map +1 -1
- package/dist/cjs/core/Route.d.ts +6 -1
- package/dist/cjs/core/Route.d.ts.map +1 -1
- package/dist/cjs/core/Route.js +19 -1
- package/dist/cjs/core/Route.js.map +1 -1
- package/dist/cjs/core/State.d.ts +1 -2
- package/dist/cjs/core/State.d.ts.map +1 -1
- package/dist/cjs/core/State.js +5 -6
- package/dist/cjs/core/State.js.map +1 -1
- package/dist/cjs/core/Transition.d.ts +2 -2
- package/dist/cjs/core/Transition.d.ts.map +1 -1
- package/dist/cjs/core/Transition.js +3 -2
- package/dist/cjs/core/Transition.js.map +1 -1
- package/dist/cjs/types/route.d.ts +15 -4
- package/dist/cjs/types/route.d.ts.map +1 -1
- package/dist/core/ResponseEngine.js +2 -2
- package/dist/core/ResponseEngine.js.map +1 -1
- package/dist/core/Route.d.ts +6 -1
- package/dist/core/Route.d.ts.map +1 -1
- package/dist/core/Route.js +19 -1
- package/dist/core/Route.js.map +1 -1
- package/dist/core/State.d.ts +1 -2
- package/dist/core/State.d.ts.map +1 -1
- package/dist/core/State.js +5 -6
- package/dist/core/State.js.map +1 -1
- package/dist/core/Transition.d.ts +2 -2
- package/dist/core/Transition.d.ts.map +1 -1
- package/dist/core/Transition.js +3 -2
- package/dist/core/Transition.js.map +1 -1
- package/dist/types/route.d.ts +15 -4
- package/dist/types/route.d.ts.map +1 -1
- package/docs/ADAPTERS.md +1 -1
- package/docs/API_REFERENCE.md +22 -25
- package/docs/ARCHITECTURE.md +18 -22
- package/docs/CONSTRUCTOR_OPTIONS.md +2 -2
- package/docs/CONTEXT_MANAGEMENT.md +1 -1
- package/docs/GETTING_STARTED.md +1 -1
- package/docs/PERSISTENCE.md +3 -3
- package/examples/business-onboarding.ts +86 -70
- package/examples/company-qna-agent.ts +4 -4
- package/examples/custom-database-persistence.ts +2 -2
- package/examples/declarative-agent.ts +3 -3
- package/examples/extracted-data-modification.ts +1 -1
- package/examples/healthcare-agent.ts +24 -30
- package/examples/openai-agent.ts +1 -1
- package/examples/opensearch-persistence.ts +2 -2
- package/examples/persistent-onboarding.ts +2 -2
- package/examples/prisma-persistence.ts +3 -3
- package/examples/redis-persistence.ts +3 -3
- package/examples/travel-agent.ts +73 -96
- package/package.json +1 -1
- package/src/core/ResponseEngine.ts +2 -2
- package/src/core/Route.ts +34 -3
- package/src/core/State.ts +6 -13
- package/src/core/Transition.ts +6 -3
- package/src/types/route.ts +15 -5
|
@@ -130,7 +130,7 @@ async function createHealthcareAgent() {
|
|
|
130
130
|
title: "Schedule an Appointment",
|
|
131
131
|
description: "Helps the patient find a time for their appointment.",
|
|
132
132
|
conditions: ["The patient wants to schedule an appointment"],
|
|
133
|
-
|
|
133
|
+
extractionSchema: {
|
|
134
134
|
type: "object",
|
|
135
135
|
properties: {
|
|
136
136
|
appointmentReason: {
|
|
@@ -161,25 +161,21 @@ async function createHealthcareAgent() {
|
|
|
161
161
|
});
|
|
162
162
|
|
|
163
163
|
// State 1: Gather appointment reason
|
|
164
|
-
const gatherReason = schedulingRoute.initialState.transitionTo(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
"Patient hasn't specified reason for appointment yet"
|
|
171
|
-
);
|
|
164
|
+
const gatherReason = schedulingRoute.initialState.transitionTo({
|
|
165
|
+
chatState: "Ask what the patient needs an appointment for",
|
|
166
|
+
gather: ["appointmentReason"],
|
|
167
|
+
skipIf: (extracted) => !!extracted.appointmentReason,
|
|
168
|
+
condition: "Patient hasn't specified reason for appointment yet",
|
|
169
|
+
});
|
|
172
170
|
|
|
173
171
|
// State 2: Check urgency and show available slots
|
|
174
|
-
const checkUrgency = gatherReason.transitionTo(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
"Reason provided, now assess urgency level"
|
|
182
|
-
);
|
|
172
|
+
const checkUrgency = gatherReason.transitionTo({
|
|
173
|
+
chatState: "Check if this is urgent and show available slots",
|
|
174
|
+
gather: ["urgency"],
|
|
175
|
+
skipIf: (extracted) => !!extracted.urgency,
|
|
176
|
+
requiredData: ["appointmentReason"],
|
|
177
|
+
condition: "Reason provided, now assess urgency level",
|
|
178
|
+
});
|
|
183
179
|
|
|
184
180
|
const showSlots = checkUrgency.transitionTo({
|
|
185
181
|
toolState: getUpcomingSlots,
|
|
@@ -206,22 +202,20 @@ async function createHealthcareAgent() {
|
|
|
206
202
|
requiredData: ["appointmentReason", "preferredTime", "preferredDate"],
|
|
207
203
|
});
|
|
208
204
|
|
|
209
|
-
const schedule = confirmDetails.transitionTo(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
"All details confirmed, book the appointment"
|
|
215
|
-
);
|
|
205
|
+
const schedule = confirmDetails.transitionTo({
|
|
206
|
+
toolState: scheduleAppointment,
|
|
207
|
+
requiredData: ["appointmentReason", "preferredTime", "preferredDate"],
|
|
208
|
+
condition: "All details confirmed, book the appointment",
|
|
209
|
+
});
|
|
216
210
|
|
|
217
211
|
const confirmation = schedule.transitionTo({
|
|
218
212
|
chatState: "Confirm the appointment has been scheduled",
|
|
219
213
|
});
|
|
220
214
|
|
|
221
|
-
confirmation.transitionTo(
|
|
222
|
-
|
|
223
|
-
"Appointment booked successfully"
|
|
224
|
-
);
|
|
215
|
+
confirmation.transitionTo({
|
|
216
|
+
state: END_ROUTE,
|
|
217
|
+
condition: "Appointment booked successfully",
|
|
218
|
+
});
|
|
225
219
|
|
|
226
220
|
// Alternative path: no times work - show later slots
|
|
227
221
|
const laterSlots = presentTimes.transitionTo({
|
|
@@ -250,7 +244,7 @@ async function createHealthcareAgent() {
|
|
|
250
244
|
title: "Lab Results",
|
|
251
245
|
description: "Retrieves the patient's lab results and explains them.",
|
|
252
246
|
conditions: ["The patient wants to see their lab results"],
|
|
253
|
-
|
|
247
|
+
extractionSchema: {
|
|
254
248
|
type: "object",
|
|
255
249
|
properties: {
|
|
256
250
|
testType: {
|
package/examples/openai-agent.ts
CHANGED
|
@@ -112,7 +112,7 @@ async function main() {
|
|
|
112
112
|
title: "Check Weather",
|
|
113
113
|
description: "Help user check weather for a location",
|
|
114
114
|
conditions: ["User wants to know the weather"],
|
|
115
|
-
|
|
115
|
+
extractionSchema: {
|
|
116
116
|
type: "object",
|
|
117
117
|
properties: {
|
|
118
118
|
location: {
|
|
@@ -105,7 +105,7 @@ async function example() {
|
|
|
105
105
|
"User reports an issue or problem",
|
|
106
106
|
"User is dissatisfied",
|
|
107
107
|
],
|
|
108
|
-
|
|
108
|
+
extractionSchema: {
|
|
109
109
|
type: "object",
|
|
110
110
|
properties: {
|
|
111
111
|
category: {
|
|
@@ -337,7 +337,7 @@ async function analyticsExample() {
|
|
|
337
337
|
|
|
338
338
|
const ticketRoute = agent.createRoute<TicketData>({
|
|
339
339
|
title: "Analyze Support Ticket",
|
|
340
|
-
|
|
340
|
+
extractionSchema: {
|
|
341
341
|
type: "object",
|
|
342
342
|
properties: {
|
|
343
343
|
ticketType: { type: "string" },
|
|
@@ -244,7 +244,7 @@ async function createPersistentOnboardingAgent(sessionId: string) {
|
|
|
244
244
|
title: "Business Onboarding",
|
|
245
245
|
description: "Guide user through business information collection",
|
|
246
246
|
conditions: ["User is onboarding their business"],
|
|
247
|
-
|
|
247
|
+
extractionSchema: {
|
|
248
248
|
type: "object",
|
|
249
249
|
properties: {
|
|
250
250
|
businessName: {
|
|
@@ -503,7 +503,7 @@ async function main() {
|
|
|
503
503
|
* - Always-on routing respects intent changes
|
|
504
504
|
*
|
|
505
505
|
* ✅ PATTERN 2: Schema-First Data Extraction
|
|
506
|
-
* -
|
|
506
|
+
* - extractionSchema: Define data contracts upfront
|
|
507
507
|
* - Type-safe extraction throughout conversation
|
|
508
508
|
* - skipIf functions for deterministic state logic
|
|
509
509
|
* - requiredData arrays for prerequisites
|
|
@@ -96,7 +96,7 @@ async function example() {
|
|
|
96
96
|
"User wants to book a flight",
|
|
97
97
|
"User mentions travel, flying, or booking tickets",
|
|
98
98
|
],
|
|
99
|
-
|
|
99
|
+
extractionSchema: {
|
|
100
100
|
type: "object",
|
|
101
101
|
properties: {
|
|
102
102
|
destination: {
|
|
@@ -413,7 +413,7 @@ async function advancedExample() {
|
|
|
413
413
|
const onboardingRoute = agent.createRoute<OnboardingData>({
|
|
414
414
|
title: "User Onboarding",
|
|
415
415
|
description: "Collect user information for account setup",
|
|
416
|
-
|
|
416
|
+
extractionSchema: {
|
|
417
417
|
type: "object",
|
|
418
418
|
properties: {
|
|
419
419
|
fullName: { type: "string" },
|
|
@@ -514,7 +514,7 @@ async function quickStart() {
|
|
|
514
514
|
// Create a simple contact form route
|
|
515
515
|
const contactRoute = agent.createRoute<ContactFormData>({
|
|
516
516
|
title: "Contact Form",
|
|
517
|
-
|
|
517
|
+
extractionSchema: {
|
|
518
518
|
type: "object",
|
|
519
519
|
properties: {
|
|
520
520
|
name: { type: "string" },
|
|
@@ -88,7 +88,7 @@ async function example() {
|
|
|
88
88
|
"User wants to report a problem",
|
|
89
89
|
"User mentions support, help, or issue",
|
|
90
90
|
],
|
|
91
|
-
|
|
91
|
+
extractionSchema: {
|
|
92
92
|
type: "object",
|
|
93
93
|
properties: {
|
|
94
94
|
issue: {
|
|
@@ -286,7 +286,7 @@ async function highThroughputExample() {
|
|
|
286
286
|
// Simple chat route that extracts topic and sentiment
|
|
287
287
|
const chatRoute = agent.createRoute<QuickChatData>({
|
|
288
288
|
title: "General Chat",
|
|
289
|
-
|
|
289
|
+
extractionSchema: {
|
|
290
290
|
type: "object",
|
|
291
291
|
properties: {
|
|
292
292
|
topic: {
|
|
@@ -364,7 +364,7 @@ async function sessionRecoveryExample() {
|
|
|
364
364
|
|
|
365
365
|
const orderRoute = agent.createRoute<OrderData>({
|
|
366
366
|
title: "Place Order",
|
|
367
|
-
|
|
367
|
+
extractionSchema: {
|
|
368
368
|
type: "object",
|
|
369
369
|
properties: {
|
|
370
370
|
productId: { type: "string" },
|
package/examples/travel-agent.ts
CHANGED
|
@@ -223,7 +223,7 @@ async function createTravelAgent() {
|
|
|
223
223
|
description:
|
|
224
224
|
"Helps the customer find and book a flight to their desired destination.",
|
|
225
225
|
conditions: ["The customer wants to book a flight"],
|
|
226
|
-
|
|
226
|
+
extractionSchema: {
|
|
227
227
|
type: "object",
|
|
228
228
|
properties: {
|
|
229
229
|
destination: {
|
|
@@ -270,85 +270,67 @@ async function createTravelAgent() {
|
|
|
270
270
|
});
|
|
271
271
|
|
|
272
272
|
// Build the route flow with data extraction and smart state progression
|
|
273
|
-
const askDestination = flightBookingRoute.initialState.transitionTo(
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
"Customer needs to specify their travel destination"
|
|
280
|
-
);
|
|
273
|
+
const askDestination = flightBookingRoute.initialState.transitionTo({
|
|
274
|
+
chatState: "Ask about the destination",
|
|
275
|
+
gather: ["destination"],
|
|
276
|
+
skipIf: (extracted) => !!extracted.destination,
|
|
277
|
+
condition: "Customer needs to specify their travel destination",
|
|
278
|
+
});
|
|
281
279
|
|
|
282
|
-
const enrichDestination = askDestination.transitionTo(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
"Destination provided, lookup airport code"
|
|
288
|
-
);
|
|
280
|
+
const enrichDestination = askDestination.transitionTo({
|
|
281
|
+
toolState: lookupDestinationCode,
|
|
282
|
+
requiredData: ["destination"],
|
|
283
|
+
condition: "Destination provided, lookup airport code",
|
|
284
|
+
});
|
|
289
285
|
|
|
290
|
-
const askDates = enrichDestination.transitionTo(
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
"Destination confirmed, need travel dates"
|
|
298
|
-
);
|
|
286
|
+
const askDates = enrichDestination.transitionTo({
|
|
287
|
+
chatState: "Ask about preferred travel dates",
|
|
288
|
+
gather: ["departureDate"],
|
|
289
|
+
skipIf: (extracted) => !!extracted.departureDate,
|
|
290
|
+
requiredData: ["destination"],
|
|
291
|
+
condition: "Destination confirmed, need travel dates",
|
|
292
|
+
});
|
|
299
293
|
|
|
300
|
-
const askPassengers = askDates.transitionTo(
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
"Dates confirmed, need passenger count"
|
|
308
|
-
);
|
|
294
|
+
const askPassengers = askDates.transitionTo({
|
|
295
|
+
chatState: "Ask for number of passengers",
|
|
296
|
+
gather: ["passengers"],
|
|
297
|
+
skipIf: (extracted) => !!extracted.passengers,
|
|
298
|
+
requiredData: ["destination", "departureDate"],
|
|
299
|
+
condition: "Dates confirmed, need passenger count",
|
|
300
|
+
});
|
|
309
301
|
|
|
310
|
-
const searchFlightsState = askPassengers.transitionTo(
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
"All basic info gathered, search for available flights"
|
|
316
|
-
);
|
|
302
|
+
const searchFlightsState = askPassengers.transitionTo({
|
|
303
|
+
toolState: searchFlights,
|
|
304
|
+
// Triggered when shouldSearchFlights flag is set by hook
|
|
305
|
+
condition: "All basic info gathered, search for available flights",
|
|
306
|
+
});
|
|
317
307
|
|
|
318
|
-
const presentFlights = searchFlightsState.transitionTo(
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
"Flight search complete, present options to customer"
|
|
323
|
-
);
|
|
308
|
+
const presentFlights = searchFlightsState.transitionTo({
|
|
309
|
+
chatState: "Present available flights and ask which one works for them",
|
|
310
|
+
condition: "Flight search complete, present options to customer",
|
|
311
|
+
});
|
|
324
312
|
|
|
325
313
|
// Happy path: customer selects a flight
|
|
326
|
-
const confirmBooking = presentFlights.transitionTo(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
"Customer interested in a flight, confirm booking details"
|
|
332
|
-
);
|
|
314
|
+
const confirmBooking = presentFlights.transitionTo({
|
|
315
|
+
chatState: "Confirm booking details before proceeding",
|
|
316
|
+
gather: ["cabinClass", "urgency"], // Additional optional data
|
|
317
|
+
condition: "Customer interested in a flight, confirm booking details",
|
|
318
|
+
});
|
|
333
319
|
|
|
334
|
-
const bookFlightState = confirmBooking.transitionTo(
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
"Customer confirmed, proceed with booking"
|
|
339
|
-
);
|
|
320
|
+
const bookFlightState = confirmBooking.transitionTo({
|
|
321
|
+
toolState: bookFlight,
|
|
322
|
+
condition: "Customer confirmed, proceed with booking",
|
|
323
|
+
});
|
|
340
324
|
|
|
341
|
-
const provideConfirmation = bookFlightState.transitionTo(
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
"Booking completed successfully"
|
|
346
|
-
);
|
|
325
|
+
const provideConfirmation = bookFlightState.transitionTo({
|
|
326
|
+
chatState: "Provide confirmation number and booking summary",
|
|
327
|
+
condition: "Booking completed successfully",
|
|
328
|
+
});
|
|
347
329
|
|
|
348
|
-
provideConfirmation.transitionTo(
|
|
349
|
-
|
|
350
|
-
"Customer has confirmation, booking flow complete"
|
|
351
|
-
);
|
|
330
|
+
provideConfirmation.transitionTo({
|
|
331
|
+
state: END_ROUTE,
|
|
332
|
+
condition: "Customer has confirmation, booking flow complete",
|
|
333
|
+
});
|
|
352
334
|
|
|
353
335
|
// Add route-specific guidelines
|
|
354
336
|
flightBookingRoute.createGuideline({
|
|
@@ -370,7 +352,7 @@ async function createTravelAgent() {
|
|
|
370
352
|
description:
|
|
371
353
|
"Retrieves the customer's booking status and provides relevant information.",
|
|
372
354
|
conditions: ["The customer wants to check their booking status"],
|
|
373
|
-
|
|
355
|
+
extractionSchema: {
|
|
374
356
|
type: "object",
|
|
375
357
|
properties: {
|
|
376
358
|
confirmationNumber: {
|
|
@@ -386,34 +368,29 @@ async function createTravelAgent() {
|
|
|
386
368
|
},
|
|
387
369
|
});
|
|
388
370
|
|
|
389
|
-
const askConfirmation = bookingStatusRoute.initialState.transitionTo(
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
);
|
|
371
|
+
const askConfirmation = bookingStatusRoute.initialState.transitionTo({
|
|
372
|
+
chatState: "Ask for the confirmation number or booking reference",
|
|
373
|
+
gather: ["confirmationNumber"],
|
|
374
|
+
skipIf: (extracted) => !!extracted.confirmationNumber,
|
|
375
|
+
condition:
|
|
376
|
+
"Customer wants to check booking status but hasn't provided confirmation number",
|
|
377
|
+
});
|
|
397
378
|
|
|
398
|
-
const checkStatus = askConfirmation.transitionTo(
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
"Confirmation number provided, look up booking details"
|
|
404
|
-
);
|
|
379
|
+
const checkStatus = askConfirmation.transitionTo({
|
|
380
|
+
toolState: getBookingStatus,
|
|
381
|
+
requiredData: ["confirmationNumber"],
|
|
382
|
+
condition: "Confirmation number provided, look up booking details",
|
|
383
|
+
});
|
|
405
384
|
|
|
406
|
-
const provideStatus = checkStatus.transitionTo(
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
"Booking status retrieved successfully"
|
|
411
|
-
);
|
|
385
|
+
const provideStatus = checkStatus.transitionTo({
|
|
386
|
+
chatState: "Provide booking status and relevant information",
|
|
387
|
+
condition: "Booking status retrieved successfully",
|
|
388
|
+
});
|
|
412
389
|
|
|
413
|
-
provideStatus.transitionTo(
|
|
414
|
-
|
|
415
|
-
"Booking information provided to customer"
|
|
416
|
-
);
|
|
390
|
+
provideStatus.transitionTo({
|
|
391
|
+
state: END_ROUTE,
|
|
392
|
+
condition: "Booking information provided to customer",
|
|
393
|
+
});
|
|
417
394
|
|
|
418
395
|
// Global guidelines
|
|
419
396
|
agent.createGuideline({
|
package/package.json
CHANGED
|
@@ -30,9 +30,9 @@ export class ResponseEngine<TContext = unknown> {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// Add gather fields from current state
|
|
33
|
-
if (currentState?.gatherFields && route.
|
|
33
|
+
if (currentState?.gatherFields && route.extractionSchema?.properties) {
|
|
34
34
|
for (const field of currentState.gatherFields) {
|
|
35
|
-
const fieldSchema = route.
|
|
35
|
+
const fieldSchema = route.extractionSchema.properties[field];
|
|
36
36
|
if (fieldSchema) {
|
|
37
37
|
base.properties![field] = fieldSchema;
|
|
38
38
|
}
|
package/src/core/Route.ts
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
* Route (Journey) DSL implementation
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
RouteOptions,
|
|
7
|
+
RouteRef,
|
|
8
|
+
TransitionSpec,
|
|
9
|
+
TransitionResult,
|
|
10
|
+
} from "../types/route";
|
|
6
11
|
import type { StructuredSchema } from "../types/schema";
|
|
7
12
|
import type { Guideline } from "../types/agent";
|
|
8
13
|
|
|
@@ -22,7 +27,7 @@ export class Route<TContext = unknown, TExtracted = unknown> {
|
|
|
22
27
|
public readonly prohibitions: string[];
|
|
23
28
|
public readonly initialState: State<TContext, TExtracted>;
|
|
24
29
|
public readonly responseOutputSchema?: StructuredSchema;
|
|
25
|
-
public readonly
|
|
30
|
+
public readonly extractionSchema?: StructuredSchema;
|
|
26
31
|
public readonly initialData?: Partial<TExtracted>;
|
|
27
32
|
private routingExtrasSchema?: StructuredSchema;
|
|
28
33
|
private guidelines: Guideline[] = [];
|
|
@@ -42,7 +47,7 @@ export class Route<TContext = unknown, TExtracted = unknown> {
|
|
|
42
47
|
);
|
|
43
48
|
this.routingExtrasSchema = options.routingExtrasSchema;
|
|
44
49
|
this.responseOutputSchema = options.responseOutputSchema;
|
|
45
|
-
this.
|
|
50
|
+
this.extractionSchema = options.extractionSchema;
|
|
46
51
|
this.initialData = options.initialData;
|
|
47
52
|
|
|
48
53
|
// Initialize guidelines from options
|
|
@@ -51,6 +56,32 @@ export class Route<TContext = unknown, TExtracted = unknown> {
|
|
|
51
56
|
this.createGuideline(guideline);
|
|
52
57
|
});
|
|
53
58
|
}
|
|
59
|
+
|
|
60
|
+
// Build sequential steps if provided
|
|
61
|
+
if (options.steps && options.steps.length > 0) {
|
|
62
|
+
this.buildSequentialSteps(options.steps);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Build a sequential state machine from an array of steps
|
|
68
|
+
* @private
|
|
69
|
+
*/
|
|
70
|
+
private buildSequentialSteps(
|
|
71
|
+
steps: Array<TransitionSpec<TContext, TExtracted>>
|
|
72
|
+
): void {
|
|
73
|
+
// Import END_ROUTE dynamically to avoid circular dependency
|
|
74
|
+
const END_ROUTE = Symbol.for("END_ROUTE");
|
|
75
|
+
|
|
76
|
+
let currentState: TransitionResult<TContext, TExtracted> =
|
|
77
|
+
this.initialState;
|
|
78
|
+
|
|
79
|
+
for (const step of steps) {
|
|
80
|
+
currentState = currentState.transitionTo(step);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// End the route
|
|
84
|
+
currentState.transitionTo({ state: END_ROUTE });
|
|
54
85
|
}
|
|
55
86
|
|
|
56
87
|
/**
|
package/src/core/State.ts
CHANGED
|
@@ -43,12 +43,10 @@ export class State<TContext = unknown, TExtracted = unknown> {
|
|
|
43
43
|
* Create a transition from this state to another
|
|
44
44
|
*
|
|
45
45
|
* @param spec - Transition specification (chatState, toolState, or direct state)
|
|
46
|
-
* @param condition - Optional condition for this transition
|
|
47
46
|
* @returns TransitionResult that supports chaining
|
|
48
47
|
*/
|
|
49
48
|
transitionTo(
|
|
50
|
-
spec: TransitionSpec<TContext, TExtracted
|
|
51
|
-
condition?: string
|
|
49
|
+
spec: TransitionSpec<TContext, TExtracted>
|
|
52
50
|
): TransitionResult<TContext, TExtracted> {
|
|
53
51
|
// Handle END_ROUTE
|
|
54
52
|
if (
|
|
@@ -58,8 +56,7 @@ export class State<TContext = unknown, TExtracted = unknown> {
|
|
|
58
56
|
) {
|
|
59
57
|
const endTransition = new Transition<TContext, TExtracted>(
|
|
60
58
|
this.getRef(),
|
|
61
|
-
{ state: END_ROUTE }
|
|
62
|
-
condition
|
|
59
|
+
{ state: END_ROUTE, condition: spec.condition }
|
|
63
60
|
);
|
|
64
61
|
this.transitions.push(endTransition);
|
|
65
62
|
|
|
@@ -71,8 +68,7 @@ export class State<TContext = unknown, TExtracted = unknown> {
|
|
|
71
68
|
if (spec.state && typeof spec.state !== "symbol") {
|
|
72
69
|
const transition = new Transition<TContext, TExtracted>(
|
|
73
70
|
this.getRef(),
|
|
74
|
-
spec
|
|
75
|
-
condition
|
|
71
|
+
spec
|
|
76
72
|
);
|
|
77
73
|
this.transitions.push(transition);
|
|
78
74
|
|
|
@@ -90,8 +86,7 @@ export class State<TContext = unknown, TExtracted = unknown> {
|
|
|
90
86
|
);
|
|
91
87
|
const transition = new Transition<TContext, TExtracted>(
|
|
92
88
|
this.getRef(),
|
|
93
|
-
spec
|
|
94
|
-
condition
|
|
89
|
+
spec
|
|
95
90
|
);
|
|
96
91
|
transition.setTarget(targetState);
|
|
97
92
|
|
|
@@ -160,10 +155,8 @@ export class State<TContext = unknown, TExtracted = unknown> {
|
|
|
160
155
|
|
|
161
156
|
return {
|
|
162
157
|
...ref,
|
|
163
|
-
transitionTo: (
|
|
164
|
-
spec
|
|
165
|
-
condition?: string
|
|
166
|
-
) => stateInstance.transitionTo(spec, condition),
|
|
158
|
+
transitionTo: (spec: TransitionSpec<TContext, TExtracted>) =>
|
|
159
|
+
stateInstance.transitionTo(spec),
|
|
167
160
|
};
|
|
168
161
|
}
|
|
169
162
|
|
package/src/core/Transition.ts
CHANGED
|
@@ -10,12 +10,15 @@ import type { State } from "./State";
|
|
|
10
10
|
*/
|
|
11
11
|
export class Transition<TContext = unknown, TExtracted = unknown> {
|
|
12
12
|
private target?: State<TContext, TExtracted>;
|
|
13
|
+
public readonly condition?: string;
|
|
13
14
|
|
|
14
15
|
constructor(
|
|
15
16
|
public readonly source: StateRef,
|
|
16
|
-
public readonly spec: TransitionSpec<TContext, TExtracted
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
public readonly spec: TransitionSpec<TContext, TExtracted>
|
|
18
|
+
) {
|
|
19
|
+
// Extract condition from spec for convenience
|
|
20
|
+
this.condition = spec.condition;
|
|
21
|
+
}
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* Set the target state for this transition
|
package/src/types/route.ts
CHANGED
|
@@ -30,7 +30,7 @@ import type { Guideline } from "./agent";
|
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Options for creating a route
|
|
33
|
-
* @template TExtracted - Type of data extracted throughout the route (inferred from
|
|
33
|
+
* @template TExtracted - Type of data extracted throughout the route (inferred from extractionSchema)
|
|
34
34
|
*/
|
|
35
35
|
export interface RouteOptions<TExtracted = unknown> {
|
|
36
36
|
/** Custom ID for the route (optional - will generate deterministic ID from title if not provided) */
|
|
@@ -57,13 +57,19 @@ export interface RouteOptions<TExtracted = unknown> {
|
|
|
57
57
|
* NEW: Schema defining data to extract throughout this route
|
|
58
58
|
* This creates a type-safe contract for what data the route collects
|
|
59
59
|
*/
|
|
60
|
-
|
|
60
|
+
extractionSchema?: StructuredSchema;
|
|
61
61
|
/**
|
|
62
62
|
* NEW: Initial data to pre-populate when entering this route
|
|
63
63
|
* Useful for restoring sessions or pre-filling known information
|
|
64
64
|
* States with skipIf conditions will be automatically bypassed if data is present
|
|
65
65
|
*/
|
|
66
66
|
initialData?: Partial<TExtracted>;
|
|
67
|
+
/**
|
|
68
|
+
* NEW: Sequential steps for simple linear flows
|
|
69
|
+
* If provided, automatically chains the steps from initialState to END_ROUTE
|
|
70
|
+
* For complex flows with branching, build the state machine manually instead
|
|
71
|
+
*/
|
|
72
|
+
steps?: TransitionSpec<unknown, TExtracted>[];
|
|
67
73
|
}
|
|
68
74
|
|
|
69
75
|
/**
|
|
@@ -81,7 +87,7 @@ export interface TransitionSpec<TContext = unknown, TExtracted = unknown> {
|
|
|
81
87
|
state?: StateRef | symbol;
|
|
82
88
|
/**
|
|
83
89
|
* NEW: Fields to gather from the conversation in this state
|
|
84
|
-
* These should match keys in the route's
|
|
90
|
+
* These should match keys in the route's extractionSchema
|
|
85
91
|
*/
|
|
86
92
|
gather?: string[];
|
|
87
93
|
/**
|
|
@@ -97,6 +103,11 @@ export interface TransitionSpec<TContext = unknown, TExtracted = unknown> {
|
|
|
97
103
|
* Uses string[] for developer-friendly usage (same as gather)
|
|
98
104
|
*/
|
|
99
105
|
requiredData?: string[];
|
|
106
|
+
/**
|
|
107
|
+
* Optional condition for this transition
|
|
108
|
+
* Description of when this transition should be taken
|
|
109
|
+
*/
|
|
110
|
+
condition?: string;
|
|
100
111
|
}
|
|
101
112
|
|
|
102
113
|
/**
|
|
@@ -107,7 +118,6 @@ export interface TransitionResult<TContext = unknown, TExtracted = unknown>
|
|
|
107
118
|
extends StateRef {
|
|
108
119
|
/** Allow chaining transitions */
|
|
109
120
|
transitionTo: (
|
|
110
|
-
spec: TransitionSpec<TContext, TExtracted
|
|
111
|
-
condition?: string
|
|
121
|
+
spec: TransitionSpec<TContext, TExtracted>
|
|
112
122
|
) => TransitionResult<TContext, TExtracted>;
|
|
113
123
|
}
|