@falai/agent 0.5.5 → 0.6.1
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 +88 -864
- 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 +13 -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/EXAMPLES.md +419 -0
- package/docs/GETTING_STARTED.md +1 -1
- package/docs/PERSISTENCE.md +3 -3
- package/examples/business-onboarding.ts +88 -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
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
|
}
|