@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.
Files changed (59) hide show
  1. package/README.md +88 -864
  2. package/dist/cjs/core/ResponseEngine.js +2 -2
  3. package/dist/cjs/core/ResponseEngine.js.map +1 -1
  4. package/dist/cjs/core/Route.d.ts +6 -1
  5. package/dist/cjs/core/Route.d.ts.map +1 -1
  6. package/dist/cjs/core/Route.js +19 -1
  7. package/dist/cjs/core/Route.js.map +1 -1
  8. package/dist/cjs/core/State.d.ts +1 -2
  9. package/dist/cjs/core/State.d.ts.map +1 -1
  10. package/dist/cjs/core/State.js +5 -6
  11. package/dist/cjs/core/State.js.map +1 -1
  12. package/dist/cjs/core/Transition.d.ts +2 -2
  13. package/dist/cjs/core/Transition.d.ts.map +1 -1
  14. package/dist/cjs/core/Transition.js +3 -2
  15. package/dist/cjs/core/Transition.js.map +1 -1
  16. package/dist/cjs/types/route.d.ts +15 -4
  17. package/dist/cjs/types/route.d.ts.map +1 -1
  18. package/dist/core/ResponseEngine.js +2 -2
  19. package/dist/core/ResponseEngine.js.map +1 -1
  20. package/dist/core/Route.d.ts +6 -1
  21. package/dist/core/Route.d.ts.map +1 -1
  22. package/dist/core/Route.js +19 -1
  23. package/dist/core/Route.js.map +1 -1
  24. package/dist/core/State.d.ts +1 -2
  25. package/dist/core/State.d.ts.map +1 -1
  26. package/dist/core/State.js +5 -6
  27. package/dist/core/State.js.map +1 -1
  28. package/dist/core/Transition.d.ts +2 -2
  29. package/dist/core/Transition.d.ts.map +1 -1
  30. package/dist/core/Transition.js +3 -2
  31. package/dist/core/Transition.js.map +1 -1
  32. package/dist/types/route.d.ts +15 -4
  33. package/dist/types/route.d.ts.map +1 -1
  34. package/docs/ADAPTERS.md +13 -1
  35. package/docs/API_REFERENCE.md +22 -25
  36. package/docs/ARCHITECTURE.md +18 -22
  37. package/docs/CONSTRUCTOR_OPTIONS.md +2 -2
  38. package/docs/CONTEXT_MANAGEMENT.md +1 -1
  39. package/docs/EXAMPLES.md +419 -0
  40. package/docs/GETTING_STARTED.md +1 -1
  41. package/docs/PERSISTENCE.md +3 -3
  42. package/examples/business-onboarding.ts +88 -70
  43. package/examples/company-qna-agent.ts +4 -4
  44. package/examples/custom-database-persistence.ts +2 -2
  45. package/examples/declarative-agent.ts +3 -3
  46. package/examples/extracted-data-modification.ts +1 -1
  47. package/examples/healthcare-agent.ts +24 -30
  48. package/examples/openai-agent.ts +1 -1
  49. package/examples/opensearch-persistence.ts +2 -2
  50. package/examples/persistent-onboarding.ts +2 -2
  51. package/examples/prisma-persistence.ts +3 -3
  52. package/examples/redis-persistence.ts +3 -3
  53. package/examples/travel-agent.ts +73 -96
  54. package/package.json +1 -1
  55. package/src/core/ResponseEngine.ts +2 -2
  56. package/src/core/Route.ts +34 -3
  57. package/src/core/State.ts +6 -13
  58. package/src/core/Transition.ts +6 -3
  59. package/src/types/route.ts +15 -5
@@ -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
- gatherSchema: {
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
- chatState: "Ask about the destination",
276
- gather: ["destination"],
277
- skipIf: (extracted) => !!extracted.destination,
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
- toolState: lookupDestinationCode,
285
- requiredData: ["destination"],
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
- chatState: "Ask about preferred travel dates",
293
- gather: ["departureDate"],
294
- skipIf: (extracted) => !!extracted.departureDate,
295
- requiredData: ["destination"],
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
- chatState: "Ask for number of passengers",
303
- gather: ["passengers"],
304
- skipIf: (extracted) => !!extracted.passengers,
305
- requiredData: ["destination", "departureDate"],
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
- toolState: searchFlights,
313
- // Triggered when shouldSearchFlights flag is set by hook
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
- chatState: "Present available flights and ask which one works for them",
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
- chatState: "Confirm booking details before proceeding",
329
- gather: ["cabinClass", "urgency"], // Additional optional data
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
- toolState: bookFlight,
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
- chatState: "Provide confirmation number and booking summary",
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
- { state: END_ROUTE },
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
- gatherSchema: {
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
- chatState: "Ask for the confirmation number or booking reference",
392
- gather: ["confirmationNumber"],
393
- skipIf: (extracted) => !!extracted.confirmationNumber,
394
- },
395
- "Customer wants to check booking status but hasn't provided confirmation number"
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
- toolState: getBookingStatus,
401
- requiredData: ["confirmationNumber"],
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
- chatState: "Provide booking status and relevant information",
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
- { state: END_ROUTE },
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@falai/agent",
3
- "version": "0.5.5",
3
+ "version": "0.6.1",
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",
@@ -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.gatherSchema?.properties) {
33
+ if (currentState?.gatherFields && route.extractionSchema?.properties) {
34
34
  for (const field of currentState.gatherFields) {
35
- const fieldSchema = route.gatherSchema.properties[field];
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 { RouteOptions, RouteRef } from "../types/route";
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 gatherSchema?: StructuredSchema;
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.gatherSchema = options.gatherSchema;
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: TransitionSpec<TContext, TExtracted>,
165
- condition?: string
166
- ) => stateInstance.transitionTo(spec, condition),
158
+ transitionTo: (spec: TransitionSpec<TContext, TExtracted>) =>
159
+ stateInstance.transitionTo(spec),
167
160
  };
168
161
  }
169
162
 
@@ -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
- public readonly condition?: string
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
@@ -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 gatherSchema)
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
- gatherSchema?: StructuredSchema;
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 gatherSchema
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
  }