@falai/agent 0.9.0-alpha-2 → 0.9.2

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 (179) hide show
  1. package/README.md +42 -34
  2. package/dist/cjs/src/core/Agent.d.ts +48 -44
  3. package/dist/cjs/src/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/src/core/Agent.js +151 -1110
  5. package/dist/cjs/src/core/Agent.js.map +1 -1
  6. package/dist/cjs/src/core/ResponseModal.d.ts +211 -0
  7. package/dist/cjs/src/core/ResponseModal.d.ts.map +1 -0
  8. package/dist/cjs/src/core/ResponseModal.js +1394 -0
  9. package/dist/cjs/src/core/ResponseModal.js.map +1 -0
  10. package/dist/cjs/src/core/ResponsePipeline.d.ts +8 -4
  11. package/dist/cjs/src/core/ResponsePipeline.d.ts.map +1 -1
  12. package/dist/cjs/src/core/ResponsePipeline.js +48 -20
  13. package/dist/cjs/src/core/ResponsePipeline.js.map +1 -1
  14. package/dist/cjs/src/core/Route.d.ts +12 -5
  15. package/dist/cjs/src/core/Route.d.ts.map +1 -1
  16. package/dist/cjs/src/core/Route.js +26 -5
  17. package/dist/cjs/src/core/Route.js.map +1 -1
  18. package/dist/cjs/src/core/RoutingEngine.d.ts +5 -0
  19. package/dist/cjs/src/core/RoutingEngine.d.ts.map +1 -1
  20. package/dist/cjs/src/core/RoutingEngine.js +37 -25
  21. package/dist/cjs/src/core/RoutingEngine.js.map +1 -1
  22. package/dist/cjs/src/core/SessionManager.d.ts +9 -1
  23. package/dist/cjs/src/core/SessionManager.d.ts.map +1 -1
  24. package/dist/cjs/src/core/SessionManager.js +27 -5
  25. package/dist/cjs/src/core/SessionManager.js.map +1 -1
  26. package/dist/cjs/src/core/Step.d.ts +60 -7
  27. package/dist/cjs/src/core/Step.d.ts.map +1 -1
  28. package/dist/cjs/src/core/Step.js +151 -4
  29. package/dist/cjs/src/core/Step.js.map +1 -1
  30. package/dist/cjs/src/core/ToolManager.d.ts +234 -0
  31. package/dist/cjs/src/core/ToolManager.d.ts.map +1 -0
  32. package/dist/cjs/src/core/ToolManager.js +1117 -0
  33. package/dist/cjs/src/core/ToolManager.js.map +1 -0
  34. package/dist/cjs/src/index.d.ts +5 -4
  35. package/dist/cjs/src/index.d.ts.map +1 -1
  36. package/dist/cjs/src/index.js +11 -3
  37. package/dist/cjs/src/index.js.map +1 -1
  38. package/dist/cjs/src/types/agent.d.ts +2 -1
  39. package/dist/cjs/src/types/agent.d.ts.map +1 -1
  40. package/dist/cjs/src/types/ai.d.ts +1 -1
  41. package/dist/cjs/src/types/ai.d.ts.map +1 -1
  42. package/dist/cjs/src/types/index.d.ts +3 -2
  43. package/dist/cjs/src/types/index.d.ts.map +1 -1
  44. package/dist/cjs/src/types/index.js +3 -1
  45. package/dist/cjs/src/types/index.js.map +1 -1
  46. package/dist/cjs/src/types/route.d.ts +6 -4
  47. package/dist/cjs/src/types/route.d.ts.map +1 -1
  48. package/dist/cjs/src/types/tool.d.ts +84 -14
  49. package/dist/cjs/src/types/tool.d.ts.map +1 -1
  50. package/dist/cjs/src/types/tool.js +13 -0
  51. package/dist/cjs/src/types/tool.js.map +1 -1
  52. package/dist/cjs/src/utils/clone.d.ts.map +1 -1
  53. package/dist/cjs/src/utils/clone.js +0 -4
  54. package/dist/cjs/src/utils/clone.js.map +1 -1
  55. package/dist/cjs/src/utils/history.d.ts +30 -1
  56. package/dist/cjs/src/utils/history.d.ts.map +1 -1
  57. package/dist/cjs/src/utils/history.js +169 -23
  58. package/dist/cjs/src/utils/history.js.map +1 -1
  59. package/dist/cjs/src/utils/index.d.ts +1 -1
  60. package/dist/cjs/src/utils/index.d.ts.map +1 -1
  61. package/dist/cjs/src/utils/index.js +5 -1
  62. package/dist/cjs/src/utils/index.js.map +1 -1
  63. package/dist/src/core/Agent.d.ts +48 -44
  64. package/dist/src/core/Agent.d.ts.map +1 -1
  65. package/dist/src/core/Agent.js +152 -1111
  66. package/dist/src/core/Agent.js.map +1 -1
  67. package/dist/src/core/ResponseModal.d.ts +211 -0
  68. package/dist/src/core/ResponseModal.d.ts.map +1 -0
  69. package/dist/src/core/ResponseModal.js +1389 -0
  70. package/dist/src/core/ResponseModal.js.map +1 -0
  71. package/dist/src/core/ResponsePipeline.d.ts +8 -4
  72. package/dist/src/core/ResponsePipeline.d.ts.map +1 -1
  73. package/dist/src/core/ResponsePipeline.js +48 -20
  74. package/dist/src/core/ResponsePipeline.js.map +1 -1
  75. package/dist/src/core/Route.d.ts +12 -5
  76. package/dist/src/core/Route.d.ts.map +1 -1
  77. package/dist/src/core/Route.js +26 -5
  78. package/dist/src/core/Route.js.map +1 -1
  79. package/dist/src/core/RoutingEngine.d.ts +5 -0
  80. package/dist/src/core/RoutingEngine.d.ts.map +1 -1
  81. package/dist/src/core/RoutingEngine.js +37 -25
  82. package/dist/src/core/RoutingEngine.js.map +1 -1
  83. package/dist/src/core/SessionManager.d.ts +9 -1
  84. package/dist/src/core/SessionManager.d.ts.map +1 -1
  85. package/dist/src/core/SessionManager.js +27 -5
  86. package/dist/src/core/SessionManager.js.map +1 -1
  87. package/dist/src/core/Step.d.ts +60 -7
  88. package/dist/src/core/Step.d.ts.map +1 -1
  89. package/dist/src/core/Step.js +151 -4
  90. package/dist/src/core/Step.js.map +1 -1
  91. package/dist/src/core/ToolManager.d.ts +234 -0
  92. package/dist/src/core/ToolManager.d.ts.map +1 -0
  93. package/dist/src/core/ToolManager.js +1111 -0
  94. package/dist/src/core/ToolManager.js.map +1 -0
  95. package/dist/src/index.d.ts +5 -4
  96. package/dist/src/index.d.ts.map +1 -1
  97. package/dist/src/index.js +3 -2
  98. package/dist/src/index.js.map +1 -1
  99. package/dist/src/types/agent.d.ts +2 -1
  100. package/dist/src/types/agent.d.ts.map +1 -1
  101. package/dist/src/types/ai.d.ts +1 -1
  102. package/dist/src/types/ai.d.ts.map +1 -1
  103. package/dist/src/types/index.d.ts +3 -2
  104. package/dist/src/types/index.d.ts.map +1 -1
  105. package/dist/src/types/index.js +1 -0
  106. package/dist/src/types/index.js.map +1 -1
  107. package/dist/src/types/route.d.ts +6 -4
  108. package/dist/src/types/route.d.ts.map +1 -1
  109. package/dist/src/types/tool.d.ts +84 -14
  110. package/dist/src/types/tool.d.ts.map +1 -1
  111. package/dist/src/types/tool.js +12 -1
  112. package/dist/src/types/tool.js.map +1 -1
  113. package/dist/src/utils/clone.d.ts.map +1 -1
  114. package/dist/src/utils/clone.js +0 -4
  115. package/dist/src/utils/clone.js.map +1 -1
  116. package/dist/src/utils/history.d.ts +30 -1
  117. package/dist/src/utils/history.d.ts.map +1 -1
  118. package/dist/src/utils/history.js +165 -23
  119. package/dist/src/utils/history.js.map +1 -1
  120. package/dist/src/utils/index.d.ts +1 -1
  121. package/dist/src/utils/index.d.ts.map +1 -1
  122. package/dist/src/utils/index.js +1 -1
  123. package/dist/src/utils/index.js.map +1 -1
  124. package/docs/CONTRIBUTING.md +40 -0
  125. package/docs/README.md +14 -6
  126. package/docs/api/README.md +235 -45
  127. package/docs/api/overview.md +140 -33
  128. package/docs/core/agent/session-management.md +152 -5
  129. package/docs/core/ai-integration/response-processing.md +115 -4
  130. package/docs/core/conversation-flows/routes.md +130 -0
  131. package/docs/core/error-handling.md +638 -0
  132. package/docs/core/tools/tool-definition.md +684 -60
  133. package/docs/core/tools/tool-scoping.md +244 -53
  134. package/docs/guides/error-handling-patterns.md +578 -0
  135. package/docs/guides/getting-started/README.md +139 -28
  136. package/docs/guides/migration/README.md +72 -0
  137. package/docs/guides/migration/response-modal-refactor.md +518 -0
  138. package/examples/advanced-patterns/knowledge-based-agent.ts +6 -6
  139. package/examples/advanced-patterns/persistent-onboarding.ts +30 -43
  140. package/examples/advanced-patterns/streaming-responses.ts +169 -96
  141. package/examples/ai-providers/anthropic-integration.ts +9 -5
  142. package/examples/ai-providers/openai-integration.ts +11 -7
  143. package/examples/core-concepts/basic-agent.ts +106 -67
  144. package/examples/core-concepts/modern-streaming-api.ts +309 -0
  145. package/examples/core-concepts/schema-driven-extraction.ts +10 -7
  146. package/examples/core-concepts/session-management.ts +71 -18
  147. package/examples/integrations/healthcare-integration.ts +15 -29
  148. package/examples/integrations/server-session-management.ts +3 -3
  149. package/examples/persistence/memory-sessions.ts +3 -3
  150. package/examples/tools/basic-tools.ts +293 -89
  151. package/examples/tools/data-enrichment-tools.ts +185 -75
  152. package/package.json +1 -1
  153. package/src/core/Agent.ts +190 -1529
  154. package/src/core/ResponseModal.ts +1798 -0
  155. package/src/core/ResponsePipeline.ts +83 -57
  156. package/src/core/Route.ts +39 -12
  157. package/src/core/RoutingEngine.ts +46 -42
  158. package/src/core/SessionManager.ts +39 -7
  159. package/src/core/Step.ts +198 -20
  160. package/src/core/ToolManager.ts +1394 -0
  161. package/src/index.ts +19 -3
  162. package/src/types/agent.ts +2 -1
  163. package/src/types/ai.ts +1 -1
  164. package/src/types/index.ts +13 -2
  165. package/src/types/route.ts +6 -4
  166. package/src/types/tool.ts +116 -25
  167. package/src/utils/clone.ts +6 -8
  168. package/src/utils/history.ts +190 -27
  169. package/src/utils/index.ts +4 -0
  170. package/dist/cjs/src/core/ToolExecutor.d.ts +0 -45
  171. package/dist/cjs/src/core/ToolExecutor.d.ts.map +0 -1
  172. package/dist/cjs/src/core/ToolExecutor.js +0 -84
  173. package/dist/cjs/src/core/ToolExecutor.js.map +0 -1
  174. package/dist/src/core/ToolExecutor.d.ts +0 -45
  175. package/dist/src/core/ToolExecutor.d.ts.map +0 -1
  176. package/dist/src/core/ToolExecutor.js +0 -80
  177. package/dist/src/core/ToolExecutor.js.map +0 -1
  178. package/docs/core/tools/tool-execution.md +0 -815
  179. package/src/core/ToolExecutor.ts +0 -126
@@ -104,7 +104,7 @@ const response3 = await agent.respond("Also book me a hotel in Tokyo");
104
104
 
105
105
  **SessionManager API:**
106
106
 
107
- The `SessionManager` provides a clean API for session operations:
107
+ The `SessionManager` provides a clean API for session operations with comprehensive error handling:
108
108
 
109
109
  ```typescript
110
110
  // Access the session manager
@@ -114,13 +114,19 @@ const sessionManager = agent.session;
114
114
  await sessionManager.getOrCreate("user-123");
115
115
  await sessionManager.getOrCreate(); // Auto-generates ID
116
116
 
117
- // History management
118
- await sessionManager.addMessage("user", "Hello");
119
- await sessionManager.addMessage("assistant", "Hi there!");
117
+ // History management with error handling
118
+ try {
119
+ await sessionManager.addMessage("user", "Hello");
120
+ await sessionManager.addMessage("assistant", "Hi there!");
121
+ } catch (error) {
122
+ console.error("Failed to add message to history:", error);
123
+ // Message will be rolled back automatically
124
+ }
125
+
120
126
  const history = sessionManager.getHistory();
121
127
  sessionManager.clearHistory();
122
128
 
123
- // Data access
129
+ // Data access with synchronization
124
130
  const data = sessionManager.getData<FlightData>();
125
131
  await sessionManager.setData({ destination: "Paris" });
126
132
 
@@ -130,6 +136,147 @@ await sessionManager.delete();
130
136
  const newSession = await sessionManager.reset(true); // Preserve history
131
137
  ```
132
138
 
139
+ ### Agent-Session Data Synchronization
140
+
141
+ The framework ensures bidirectional synchronization between agent collected data and session data:
142
+
143
+ ```typescript
144
+ // Agent data updates automatically sync with session
145
+ const agent = new Agent<{}, BookingData>({
146
+ sessionId: "user-123",
147
+ // ... other config
148
+ });
149
+
150
+ try {
151
+ // Update agent data - automatically syncs with session
152
+ await agent.updateCollectedData({
153
+ destination: "Tokyo",
154
+ passengers: 2
155
+ });
156
+
157
+ // Session data is automatically updated
158
+ const sessionData = agent.session.getData<BookingData>();
159
+ console.log(sessionData.destination); // "Tokyo"
160
+
161
+ // Update session data - automatically syncs with agent
162
+ await agent.session.setData({
163
+ checkInDate: "2025-03-15"
164
+ });
165
+
166
+ // Agent data is automatically updated
167
+ const agentData = agent.getCollectedData();
168
+ console.log(agentData.checkInDate); // "2025-03-15"
169
+
170
+ } catch (error) {
171
+ console.error("Data synchronization failed:", error);
172
+ // Both agent and session data remain in consistent state
173
+ }
174
+ ```
175
+
176
+ ### Error Handling in Data Synchronization
177
+
178
+ ```typescript
179
+ class SessionManager<TData> {
180
+ async setData(data: Partial<TData>): Promise<void> {
181
+ const previousData = { ...this.session.data };
182
+
183
+ try {
184
+ // Validate data if schema is available
185
+ if (this.schema) {
186
+ this.validateData(data);
187
+ }
188
+
189
+ // Update session data
190
+ this.session.data = { ...this.session.data, ...data };
191
+
192
+ // Sync with agent collected data
193
+ if (this.agent) {
194
+ await this.agent.updateCollectedData(data);
195
+ }
196
+
197
+ // Persist changes
198
+ await this.save();
199
+
200
+ } catch (error) {
201
+ // Rollback session data on any failure
202
+ this.session.data = previousData;
203
+
204
+ console.error("Session data update failed, rolled back:", error);
205
+ throw new Error(`Data synchronization failed: ${error.message}`);
206
+ }
207
+ }
208
+
209
+ async addMessage(role: "user" | "assistant", content: string): Promise<void> {
210
+ const message: HistoryItem = {
211
+ role,
212
+ content,
213
+ timestamp: new Date().toISOString()
214
+ };
215
+
216
+ try {
217
+ // Add to session history
218
+ this.session.history.push(message);
219
+
220
+ // Persist immediately for reliability
221
+ await this.save();
222
+
223
+ } catch (error) {
224
+ // Remove message from history on persistence failure
225
+ this.session.history.pop();
226
+
227
+ console.error("Failed to persist message:", error);
228
+ throw new Error(`Message persistence failed: ${error.message}`);
229
+ }
230
+ }
231
+ }
232
+ ```
233
+
234
+ ### Chat Method with Proper Error Handling
235
+
236
+ ```typescript
237
+ class Agent<TContext, TData> {
238
+ async chat(message: string, sessionId?: string): Promise<AgentResponse<TData>> {
239
+ try {
240
+ // Ensure session is loaded
241
+ if (!this.session || this.session.id !== sessionId) {
242
+ await this.loadSession(sessionId);
243
+ }
244
+
245
+ // Add user message to history BEFORE processing
246
+ await this.session.addMessage("user", message);
247
+
248
+ // Process the message
249
+ const response = await this.respond({
250
+ message,
251
+ sessionId: this.session.id
252
+ });
253
+
254
+ // Add assistant response to history
255
+ if (response.message) {
256
+ await this.session.addMessage("assistant", response.message);
257
+ }
258
+
259
+ return response;
260
+
261
+ } catch (error) {
262
+ console.error("Chat method failed:", error);
263
+
264
+ // Try to remove the user message if response failed
265
+ try {
266
+ const history = this.session.getHistory();
267
+ if (history.length > 0 && history[history.length - 1].role === "user") {
268
+ await this.session.removeLastMessage();
269
+ }
270
+ } catch (rollbackError) {
271
+ console.error("Failed to rollback user message:", rollbackError);
272
+ }
273
+
274
+ throw new Error(`Chat failed: ${error.message}`);
275
+ }
276
+ }
277
+ }
278
+ ```
279
+
133
280
  **Why?** Automatic session management provides:
134
281
 
135
282
  - **Zero Boilerplate** - No manual session creation or persistence code
@@ -118,10 +118,121 @@ agentContext.lastResponseTime = Date.now();
118
118
 
119
119
  Robust error handling for various failure scenarios:
120
120
 
121
- - **Schema validation failures** - Graceful fallback to manual extraction
122
- - **Tool execution errors** - Error recovery and user notification
123
- - **Context update failures** - Rollback and logging
124
- - **Routing errors** - Safe fallback to default behavior
121
+ ### Schema Validation Failures
122
+
123
+ When AI responses don't match expected schemas, the system gracefully falls back:
124
+
125
+ ```typescript
126
+ const processResponse = async (response: string, schema: JSONSchema) => {
127
+ try {
128
+ // Try schema-based extraction first
129
+ const extracted = await extractWithSchema(response, schema);
130
+ return { success: true, data: extracted };
131
+ } catch (schemaError) {
132
+ console.warn("Schema extraction failed, falling back to manual parsing:", schemaError.message);
133
+
134
+ // Fallback to manual extraction
135
+ try {
136
+ const manualData = await manualExtraction(response);
137
+ return { success: true, data: manualData, fallback: true };
138
+ } catch (fallbackError) {
139
+ return {
140
+ success: false,
141
+ error: `Both schema and manual extraction failed: ${fallbackError.message}`
142
+ };
143
+ }
144
+ }
145
+ };
146
+ ```
147
+
148
+ ### Tool Execution Errors
149
+
150
+ Tool failures are handled gracefully with proper error propagation:
151
+
152
+ ```typescript
153
+ const executeTool = async (tool: Tool, params: any) => {
154
+ try {
155
+ const result = await tool.handler(params);
156
+ return { success: true, result };
157
+ } catch (error) {
158
+ console.error(`Tool ${tool.id} execution failed:`, error);
159
+
160
+ return {
161
+ success: false,
162
+ error: error.message,
163
+ fallbackMessage: "I encountered an issue while processing your request. Please try again."
164
+ };
165
+ }
166
+ };
167
+ ```
168
+
169
+ ### Context Update Failures
170
+
171
+ Context updates include rollback mechanisms:
172
+
173
+ ```typescript
174
+ const updateContext = async (newContext: any, previousContext: any) => {
175
+ try {
176
+ await persistContext(newContext);
177
+ return { success: true };
178
+ } catch (error) {
179
+ console.error("Context update failed, rolling back:", error);
180
+
181
+ try {
182
+ await persistContext(previousContext);
183
+ return { success: false, rolledBack: true, error: error.message };
184
+ } catch (rollbackError) {
185
+ return {
186
+ success: false,
187
+ rolledBack: false,
188
+ error: `Update and rollback both failed: ${rollbackError.message}`
189
+ };
190
+ }
191
+ }
192
+ };
193
+ ```
194
+
195
+ ### Streaming Error Propagation
196
+
197
+ Streaming responses properly propagate provider errors:
198
+
199
+ ```typescript
200
+ async function* processStreamingResponse(provider: AIProvider, prompt: string) {
201
+ try {
202
+ for await (const chunk of provider.generateMessageStream(prompt)) {
203
+ yield { success: true, chunk };
204
+ }
205
+ } catch (error) {
206
+ // Ensure streaming errors are properly propagated
207
+ yield { success: false, error: error.message };
208
+ throw error; // Re-throw to stop the stream
209
+ }
210
+ }
211
+ ```
212
+
213
+ ### Routing Errors
214
+
215
+ Safe fallback to default behavior when routing fails:
216
+
217
+ ```typescript
218
+ const selectRoute = async (routes: Route[], context: any) => {
219
+ try {
220
+ const selectedRoute = await aiRouting.selectBestRoute(routes, context);
221
+ return { success: true, route: selectedRoute };
222
+ } catch (routingError) {
223
+ console.warn("AI routing failed, using default route:", routingError.message);
224
+
225
+ // Fallback to first available route or default
226
+ const fallbackRoute = routes.find(r => r.isDefault) || routes[0];
227
+ return {
228
+ success: true,
229
+ route: fallbackRoute,
230
+ fallback: true,
231
+ error: routingError.message
232
+ };
233
+ }
234
+ };
235
+ ```
125
236
 
126
237
  ## Streaming Response Processing
127
238
 
@@ -74,6 +74,8 @@ Routes are selected by the AI routing system based on user intent and conversati
74
74
 
75
75
  Routes complete when all their required fields are present in the agent's collected data, regardless of which route collected the data. This enables flexible cross-route completion scenarios.
76
76
 
77
+ ### Basic Route Completion
78
+
77
79
  ```typescript
78
80
  // Route completion evaluation
79
81
  const isComplete = bookingRoute.isComplete(agent.getCollectedData());
@@ -86,6 +88,134 @@ if (missingFields.length > 0) {
86
88
  }
87
89
  ```
88
90
 
91
+ ### Route Completion with Error Handling
92
+
93
+ Proper error handling ensures accurate route completion detection:
94
+
95
+ ```typescript
96
+ const checkRouteCompletion = async (route: Route, agent: Agent) => {
97
+ try {
98
+ const collectedData = agent.getCollectedData();
99
+
100
+ // Check data-based completion
101
+ if (route.isComplete(collectedData)) {
102
+ return { complete: true, reason: "all_required_data_collected" };
103
+ }
104
+
105
+ // Check step-based completion (for routes with skipIf conditions)
106
+ const allStepsProcessed = route.steps.every(step => {
107
+ if (step.skipIf && step.skipIf(collectedData)) {
108
+ return true; // Step is skipped, counts as processed
109
+ }
110
+ return step.isCompleted;
111
+ });
112
+
113
+ if (allStepsProcessed) {
114
+ return { complete: true, reason: "all_steps_processed" };
115
+ }
116
+
117
+ // Check for explicit route termination
118
+ if (route.hasExplicitEnd()) {
119
+ return { complete: true, reason: "explicit_end_route" };
120
+ }
121
+
122
+ return {
123
+ complete: false,
124
+ missingFields: route.getMissingRequiredFields(collectedData),
125
+ progress: route.getCompletionProgress(collectedData)
126
+ };
127
+ } catch (error) {
128
+ console.error("Route completion check failed:", error);
129
+ return {
130
+ complete: false,
131
+ error: error.message,
132
+ fallback: true
133
+ };
134
+ }
135
+ };
136
+
137
+ // Usage with error handling
138
+ const completionResult = await checkRouteCompletion(bookingRoute, agent);
139
+
140
+ if (completionResult.error) {
141
+ console.warn("Completion check failed, assuming incomplete:", completionResult.error);
142
+ } else if (completionResult.complete) {
143
+ console.log(`Route completed: ${completionResult.reason}`);
144
+ } else {
145
+ console.log(`Route ${Math.round(completionResult.progress * 100)}% complete`);
146
+ console.log(`Missing: ${completionResult.missingFields.join(', ')}`);
147
+ }
148
+ ```
149
+
150
+ ### Handling Routes with Conditional Steps
151
+
152
+ Routes with `skipIf` conditions require special completion logic:
153
+
154
+ ```typescript
155
+ const conditionalRoute = agent.createRoute({
156
+ title: "Conditional Booking",
157
+ requiredFields: ["destination", "dates", "passengers"]
158
+ });
159
+
160
+ const askDestination = conditionalRoute.initialStep.nextStep({
161
+ prompt: "Where would you like to go?",
162
+ collect: ["destination"],
163
+ skipIf: (data) => !!data.destination, // Skip if already collected
164
+ });
165
+
166
+ const askDates = askDestination.nextStep({
167
+ prompt: "When would you like to travel?",
168
+ collect: ["dates"],
169
+ skipIf: (data) => !!data.dates,
170
+ });
171
+
172
+ const confirmBooking = askDates.nextStep({
173
+ prompt: "Confirm your booking details",
174
+ requires: ["destination", "dates", "passengers"],
175
+ onComplete: () => ({ endRoute: true }) // Explicit route termination
176
+ });
177
+
178
+ // Completion detection handles skipped steps
179
+ const response = await agent.respond({
180
+ message: "I want to go to Paris on March 15th for 2 passengers",
181
+ sessionId: "user-123"
182
+ });
183
+
184
+ // All steps may be skipped due to complete data extraction
185
+ // Route should still be marked as complete
186
+ console.log("Route complete:", response.isRouteComplete); // Should be true
187
+ ```
188
+
189
+ ### Error Recovery in Route Completion
190
+
191
+ ```typescript
192
+ const safeRouteCompletion = async (route: Route, agent: Agent) => {
193
+ const maxRetries = 3;
194
+ let attempt = 0;
195
+
196
+ while (attempt < maxRetries) {
197
+ try {
198
+ return await checkRouteCompletion(route, agent);
199
+ } catch (error) {
200
+ attempt++;
201
+ console.warn(`Route completion check attempt ${attempt} failed:`, error.message);
202
+
203
+ if (attempt >= maxRetries) {
204
+ // Final fallback - assume incomplete
205
+ return {
206
+ complete: false,
207
+ error: `Completion check failed after ${maxRetries} attempts: ${error.message}`,
208
+ fallback: true
209
+ };
210
+ }
211
+
212
+ // Brief delay before retry
213
+ await new Promise(resolve => setTimeout(resolve, 100 * attempt));
214
+ }
215
+ }
216
+ };
217
+ ```
218
+
89
219
  ## Route Transitions
90
220
 
91
221
  Routes can automatically transition to other routes upon completion using the `onComplete` configuration. With agent-level data, the target route may already have some of its required data.