@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
@@ -0,0 +1,638 @@
1
+ # Error Handling
2
+
3
+ @fali/agent provides comprehensive error handling mechanisms for streaming operations, route completion detection, and agent-session data synchronization. This document covers error propagation patterns, recovery strategies, and best practices.
4
+
5
+ ## Overview
6
+
7
+ The framework handles errors across multiple layers:
8
+
9
+ - **Streaming Error Propagation** - Proper error handling in streaming AI responses
10
+ - **Route Completion Logic** - Accurate detection of route completion states
11
+ - **Session Data Synchronization** - Consistent error handling for agent-session data operations
12
+ - **Tool Execution Errors** - Graceful handling of tool failures
13
+ - **Validation Errors** - Schema and data validation error recovery
14
+
15
+ ## Streaming Error Propagation
16
+
17
+ ### Error Handling in Streaming Responses
18
+
19
+ When using streaming AI providers, errors must be properly propagated from the underlying provider to the application layer:
20
+
21
+ ```typescript
22
+ import { Agent, OpenAIProvider } from "@falai/agent";
23
+
24
+ const agent = new Agent({
25
+ provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
26
+ });
27
+
28
+ try {
29
+ // Streaming response with proper error handling
30
+ for await (const chunk of agent.respondStream({
31
+ message: "Hello",
32
+ sessionId: "user-123"
33
+ })) {
34
+ if (chunk.error) {
35
+ // Handle streaming errors properly
36
+ console.error("Streaming error:", chunk.error);
37
+ break;
38
+ }
39
+
40
+ if (chunk.delta) {
41
+ process.stdout.write(chunk.delta);
42
+ }
43
+ }
44
+ } catch (error) {
45
+ // Catch provider-level streaming errors
46
+ console.error("Provider streaming error:", error.message);
47
+ }
48
+ ```
49
+
50
+ ### MockProvider Error Testing
51
+
52
+ For testing streaming error scenarios, the MockProvider properly propagates configured errors:
53
+
54
+ ```typescript
55
+ import { MockProvider } from "@falai/agent/testing";
56
+
57
+ const mockProvider = new MockProvider({
58
+ streamingError: "Mock provider streaming error for testing"
59
+ });
60
+
61
+ const agent = new Agent({ provider: mockProvider });
62
+
63
+ try {
64
+ for await (const chunk of agent.respondStream({ message: "test" })) {
65
+ // This will throw the configured streaming error
66
+ }
67
+ } catch (error) {
68
+ // Error message will be exactly: "Mock provider streaming error for testing"
69
+ expect(error.message).toBe("Mock provider streaming error for testing");
70
+ }
71
+ ```
72
+
73
+ **Key Points:**
74
+ - Streaming errors are thrown from the async generator itself
75
+ - Error messages are preserved exactly as configured
76
+ - Test logic catches actual provider errors, not test-generated errors
77
+
78
+ ## Route Completion Error Handling
79
+
80
+ ### Proper Route Completion Detection
81
+
82
+ Routes with conditional steps and `endRoute()` calls require careful completion detection:
83
+
84
+ ```typescript
85
+ const route = agent.createRoute({
86
+ title: "Conditional Route",
87
+ requiredFields: ["name", "email"]
88
+ });
89
+
90
+ // Step with skipIf condition
91
+ const askName = route.initialStep.nextStep({
92
+ prompt: "What's your name?",
93
+ collect: ["name"],
94
+ skipIf: (data) => !!data.name, // Skip if name already collected
95
+ });
96
+
97
+ // Step that calls endRoute()
98
+ const confirmDetails = askName.nextStep({
99
+ prompt: "Confirm your details",
100
+ requires: ["name", "email"],
101
+ onComplete: () => {
102
+ // This step calls endRoute() when complete
103
+ return { endRoute: true };
104
+ }
105
+ });
106
+
107
+ // Check route completion properly
108
+ const response = await agent.respond({
109
+ message: "My name is John and email is john@example.com",
110
+ sessionId: "user-123"
111
+ });
112
+
113
+ // Route should be marked complete when all steps are processed
114
+ if (response.isRouteComplete) {
115
+ console.log("Route completed successfully");
116
+ } else {
117
+ console.log("Route still in progress");
118
+ }
119
+ ```
120
+
121
+ ### Handling Route Completion Edge Cases
122
+
123
+ ```typescript
124
+ // Route completion with error handling
125
+ const checkRouteCompletion = (route: Route, collectedData: any) => {
126
+ try {
127
+ // Check if all required fields are present
128
+ const missingFields = route.getMissingRequiredFields(collectedData);
129
+
130
+ if (missingFields.length === 0) {
131
+ // All required data collected
132
+ return { complete: true, reason: "all_data_collected" };
133
+ }
134
+
135
+ // Check if route explicitly ended
136
+ if (route.hasExplicitEnd()) {
137
+ return { complete: true, reason: "explicit_end" };
138
+ }
139
+
140
+ // Check if all steps are skipped/completed
141
+ if (route.allStepsProcessed()) {
142
+ return { complete: true, reason: "all_steps_processed" };
143
+ }
144
+
145
+ return { complete: false, missingFields };
146
+ } catch (error) {
147
+ console.error("Route completion check failed:", error);
148
+ return { complete: false, error: error.message };
149
+ }
150
+ };
151
+ ```
152
+
153
+ ## Agent-Session Data Synchronization
154
+
155
+ ### Bidirectional Data Sync Error Handling
156
+
157
+ Agent and session data must remain synchronized with proper error handling:
158
+
159
+ ```typescript
160
+ class Agent<TContext, TData> {
161
+ async updateCollectedData(updates: Partial<TData>): Promise<void> {
162
+ try {
163
+ // Update agent data
164
+ this.collectedData = { ...this.collectedData, ...updates };
165
+
166
+ // Sync with session data
167
+ if (this.session) {
168
+ await this.session.setData(this.collectedData);
169
+ }
170
+ } catch (error) {
171
+ // Rollback agent data on session sync failure
172
+ console.error("Failed to sync data with session:", error);
173
+ // Restore previous state
174
+ throw new Error(`Data synchronization failed: ${error.message}`);
175
+ }
176
+ }
177
+
178
+ getCollectedData(): Partial<TData> {
179
+ try {
180
+ // Ensure session data is in sync
181
+ if (this.session) {
182
+ const sessionData = this.session.getData<TData>();
183
+ if (sessionData && Object.keys(sessionData).length > 0) {
184
+ this.collectedData = { ...this.collectedData, ...sessionData };
185
+ }
186
+ }
187
+ return this.collectedData;
188
+ } catch (error) {
189
+ console.error("Failed to retrieve collected data:", error);
190
+ return this.collectedData; // Return agent data as fallback
191
+ }
192
+ }
193
+ }
194
+ ```
195
+
196
+ ### Session Data Operations with Error Recovery
197
+
198
+ ```typescript
199
+ class SessionManager<TData> {
200
+ async setData(data: Partial<TData>): Promise<void> {
201
+ try {
202
+ // Validate data before setting
203
+ if (this.schema) {
204
+ this.validateData(data);
205
+ }
206
+
207
+ // Update session data
208
+ this.session.data = { ...this.session.data, ...data };
209
+
210
+ // Sync with agent if available
211
+ if (this.agent) {
212
+ this.agent.collectedData = { ...this.agent.collectedData, ...data };
213
+ }
214
+
215
+ // Persist changes
216
+ await this.save();
217
+ } catch (error) {
218
+ console.error("Session data update failed:", error);
219
+ // Restore previous session state
220
+ await this.restore();
221
+ throw new Error(`Session data update failed: ${error.message}`);
222
+ }
223
+ }
224
+
225
+ private async restore(): Promise<void> {
226
+ try {
227
+ // Reload session from persistence
228
+ const restored = await this.adapter.getSession(this.session.id);
229
+ if (restored) {
230
+ this.session = restored;
231
+ }
232
+ } catch (error) {
233
+ console.error("Failed to restore session state:", error);
234
+ }
235
+ }
236
+ }
237
+ ```
238
+
239
+ ## Session History Error Handling
240
+
241
+ ### Chat Method with Proper History Management
242
+
243
+ ```typescript
244
+ class Agent<TContext, TData> {
245
+ async chat(message: string, sessionId?: string): Promise<AgentResponse<TData>> {
246
+ try {
247
+ // Ensure session exists
248
+ if (!this.session || this.session.id !== sessionId) {
249
+ await this.loadSession(sessionId);
250
+ }
251
+
252
+ // Add user message to history BEFORE processing
253
+ await this.session.addMessage("user", message);
254
+
255
+ // Process the message
256
+ const response = await this.respond({
257
+ message,
258
+ sessionId: this.session.id
259
+ });
260
+
261
+ // Add assistant response to history
262
+ if (response.message) {
263
+ await this.session.addMessage("assistant", response.message);
264
+ }
265
+
266
+ return response;
267
+ } catch (error) {
268
+ console.error("Chat method failed:", error);
269
+
270
+ // Try to remove the user message if response failed
271
+ try {
272
+ await this.session.removeLastMessage("user");
273
+ } catch (rollbackError) {
274
+ console.error("Failed to rollback user message:", rollbackError);
275
+ }
276
+
277
+ throw new Error(`Chat failed: ${error.message}`);
278
+ }
279
+ }
280
+ }
281
+ ```
282
+
283
+ ### History Persistence with Error Recovery
284
+
285
+ ```typescript
286
+ class SessionManager<TData> {
287
+ async addMessage(role: "user" | "assistant", content: string): Promise<void> {
288
+ try {
289
+ const message: HistoryItem = {
290
+ role,
291
+ content,
292
+ timestamp: new Date().toISOString()
293
+ };
294
+
295
+ // Add to in-memory history
296
+ this.session.history.push(message);
297
+
298
+ // Persist immediately
299
+ await this.save();
300
+ } catch (error) {
301
+ // Remove from in-memory history on persistence failure
302
+ this.session.history.pop();
303
+ console.error("Failed to persist message:", error);
304
+ throw new Error(`Message persistence failed: ${error.message}`);
305
+ }
306
+ }
307
+
308
+ async getHistory(): Promise<HistoryItem[]> {
309
+ try {
310
+ // Ensure we have the latest history from persistence
311
+ await this.refresh();
312
+ return this.session.history || [];
313
+ } catch (error) {
314
+ console.error("Failed to retrieve history:", error);
315
+ // Return in-memory history as fallback
316
+ return this.session.history || [];
317
+ }
318
+ }
319
+ }
320
+ ```
321
+
322
+ ## Tool Execution Error Handling
323
+
324
+ ### Graceful Tool Error Recovery
325
+
326
+ ```typescript
327
+ import { Tool } from "@falai/agent";
328
+
329
+ const searchFlights: Tool<Context, [], void, FlightData> = {
330
+ id: "search_flights",
331
+ description: "Search for available flights",
332
+ parameters: {
333
+ type: "object",
334
+ properties: {
335
+ destination: { type: "string" },
336
+ date: { type: "string" }
337
+ },
338
+ required: ["destination", "date"]
339
+ },
340
+ handler: async (toolContext) => {
341
+ try {
342
+ const { data } = toolContext;
343
+
344
+ // Validate required data
345
+ if (!data.destination || !data.date) {
346
+ return {
347
+ error: "Missing required flight search parameters",
348
+ data: undefined
349
+ };
350
+ }
351
+
352
+ // Perform search
353
+ const results = await flightSearchAPI.search({
354
+ destination: data.destination,
355
+ date: data.date
356
+ });
357
+
358
+ return {
359
+ data: "Flight search completed successfully",
360
+ dataUpdate: {
361
+ availableFlights: results,
362
+ searchPerformed: true
363
+ }
364
+ };
365
+ } catch (error) {
366
+ console.error("Flight search failed:", error);
367
+
368
+ return {
369
+ error: `Flight search failed: ${error.message}`,
370
+ data: "I encountered an error while searching for flights. Please try again.",
371
+ dataUpdate: {
372
+ searchError: error.message,
373
+ searchPerformed: false
374
+ }
375
+ };
376
+ }
377
+ }
378
+ };
379
+ ```
380
+
381
+ ## Validation Error Handling
382
+
383
+ ### Schema Validation with Fallback
384
+
385
+ ```typescript
386
+ const validateAndExtractData = <T>(response: string, schema: JSONSchema): T | null => {
387
+ try {
388
+ // Try to extract structured data
389
+ const extracted = extractStructuredData<T>(response, schema);
390
+
391
+ // Validate against schema
392
+ const validation = validateSchema(extracted, schema);
393
+
394
+ if (validation.valid) {
395
+ return extracted;
396
+ } else {
397
+ console.warn("Schema validation failed:", validation.errors);
398
+ // Fall back to manual extraction
399
+ return manualExtraction<T>(response);
400
+ }
401
+ } catch (error) {
402
+ console.error("Data extraction failed:", error);
403
+ // Return null to indicate extraction failure
404
+ return null;
405
+ }
406
+ };
407
+ ```
408
+
409
+ ## Error Recovery Strategies
410
+
411
+ ### Automatic Retry with Backoff
412
+
413
+ ```typescript
414
+ const retryWithBackoff = async <T>(
415
+ operation: () => Promise<T>,
416
+ maxRetries: number = 3,
417
+ baseDelay: number = 1000
418
+ ): Promise<T> => {
419
+ let lastError: Error;
420
+
421
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
422
+ try {
423
+ return await operation();
424
+ } catch (error) {
425
+ lastError = error as Error;
426
+
427
+ if (attempt < maxRetries - 1) {
428
+ const delay = baseDelay * Math.pow(2, attempt);
429
+ console.warn(`Operation failed, retrying in ${delay}ms:`, error.message);
430
+ await new Promise(resolve => setTimeout(resolve, delay));
431
+ }
432
+ }
433
+ }
434
+
435
+ throw new Error(`Operation failed after ${maxRetries} attempts: ${lastError.message}`);
436
+ };
437
+
438
+ // Usage
439
+ const response = await retryWithBackoff(
440
+ () => agent.respond({ message: "Hello", sessionId: "user-123" }),
441
+ 3,
442
+ 1000
443
+ );
444
+ ```
445
+
446
+ ### Circuit Breaker Pattern
447
+
448
+ ```typescript
449
+ class CircuitBreaker {
450
+ private failures = 0;
451
+ private lastFailureTime = 0;
452
+ private state: 'closed' | 'open' | 'half-open' = 'closed';
453
+
454
+ constructor(
455
+ private threshold: number = 5,
456
+ private timeout: number = 60000
457
+ ) {}
458
+
459
+ async execute<T>(operation: () => Promise<T>): Promise<T> {
460
+ if (this.state === 'open') {
461
+ if (Date.now() - this.lastFailureTime > this.timeout) {
462
+ this.state = 'half-open';
463
+ } else {
464
+ throw new Error('Circuit breaker is open');
465
+ }
466
+ }
467
+
468
+ try {
469
+ const result = await operation();
470
+ this.onSuccess();
471
+ return result;
472
+ } catch (error) {
473
+ this.onFailure();
474
+ throw error;
475
+ }
476
+ }
477
+
478
+ private onSuccess(): void {
479
+ this.failures = 0;
480
+ this.state = 'closed';
481
+ }
482
+
483
+ private onFailure(): void {
484
+ this.failures++;
485
+ this.lastFailureTime = Date.now();
486
+
487
+ if (this.failures >= this.threshold) {
488
+ this.state = 'open';
489
+ }
490
+ }
491
+ }
492
+ ```
493
+
494
+ ## Best Practices
495
+
496
+ ### Error Logging and Monitoring
497
+
498
+ ```typescript
499
+ import { Logger } from "@falai/agent/utils";
500
+
501
+ const logger = new Logger("agent-errors");
502
+
503
+ // Structured error logging
504
+ const logError = (context: string, error: Error, metadata?: any) => {
505
+ logger.error({
506
+ context,
507
+ message: error.message,
508
+ stack: error.stack,
509
+ metadata,
510
+ timestamp: new Date().toISOString()
511
+ });
512
+ };
513
+
514
+ // Usage in error handlers
515
+ try {
516
+ await agent.respond({ message, sessionId });
517
+ } catch (error) {
518
+ logError("agent-response", error, { message, sessionId });
519
+ throw error;
520
+ }
521
+ ```
522
+
523
+ ### Error Boundaries for Route Execution
524
+
525
+ ```typescript
526
+ const executeRouteWithErrorBoundary = async (route: Route, context: any) => {
527
+ try {
528
+ return await route.execute(context);
529
+ } catch (error) {
530
+ // Log the error
531
+ logError("route-execution", error, { routeId: route.id });
532
+
533
+ // Provide fallback response
534
+ return {
535
+ message: "I encountered an error processing your request. Please try again.",
536
+ isRouteComplete: false,
537
+ error: error.message
538
+ };
539
+ }
540
+ };
541
+ ```
542
+
543
+ ### Graceful Degradation
544
+
545
+ ```typescript
546
+ const respondWithFallback = async (agent: Agent, message: string) => {
547
+ try {
548
+ // Try normal response
549
+ return await agent.respond({ message });
550
+ } catch (error) {
551
+ console.warn("Normal response failed, using fallback:", error.message);
552
+
553
+ // Fallback to simple response without routing
554
+ return {
555
+ message: "I'm experiencing some technical difficulties. How can I help you?",
556
+ isRouteComplete: false,
557
+ session: agent.session
558
+ };
559
+ }
560
+ };
561
+ ```
562
+
563
+ ## Testing Error Scenarios
564
+
565
+ ### Unit Tests for Error Handling
566
+
567
+ ```typescript
568
+ describe("Error Handling", () => {
569
+ it("should handle streaming errors properly", async () => {
570
+ const mockProvider = new MockProvider({
571
+ streamingError: "Test streaming error"
572
+ });
573
+
574
+ const agent = new Agent({ provider: mockProvider });
575
+
576
+ await expect(async () => {
577
+ for await (const chunk of agent.respondStream({ message: "test" })) {
578
+ // Should throw before yielding any chunks
579
+ }
580
+ }).rejects.toThrow("Test streaming error");
581
+ });
582
+
583
+ it("should handle route completion errors", async () => {
584
+ const route = agent.createRoute({
585
+ title: "Test Route",
586
+ requiredFields: ["name"]
587
+ });
588
+
589
+ // Mock route completion logic to throw
590
+ jest.spyOn(route, 'isComplete').mockImplementation(() => {
591
+ throw new Error("Completion check failed");
592
+ });
593
+
594
+ const response = await agent.respond({ message: "Hello" });
595
+
596
+ // Should handle error gracefully
597
+ expect(response.isRouteComplete).toBe(false);
598
+ });
599
+ });
600
+ ```
601
+
602
+ ## Monitoring and Observability
603
+
604
+ ### Error Metrics Collection
605
+
606
+ ```typescript
607
+ class ErrorMetrics {
608
+ private errorCounts = new Map<string, number>();
609
+ private errorRates = new Map<string, number[]>();
610
+
611
+ recordError(type: string, error: Error): void {
612
+ // Count errors by type
613
+ this.errorCounts.set(type, (this.errorCounts.get(type) || 0) + 1);
614
+
615
+ // Track error rates
616
+ const now = Date.now();
617
+ const rates = this.errorRates.get(type) || [];
618
+ rates.push(now);
619
+
620
+ // Keep only last hour of data
621
+ const oneHourAgo = now - 3600000;
622
+ this.errorRates.set(type, rates.filter(time => time > oneHourAgo));
623
+ }
624
+
625
+ getErrorRate(type: string): number {
626
+ const rates = this.errorRates.get(type) || [];
627
+ return rates.length; // Errors per hour
628
+ }
629
+
630
+ getTopErrors(limit: number = 10): Array<[string, number]> {
631
+ return Array.from(this.errorCounts.entries())
632
+ .sort(([,a], [,b]) => b - a)
633
+ .slice(0, limit);
634
+ }
635
+ }
636
+ ```
637
+
638
+ This comprehensive error handling documentation covers all the key areas identified in the task requirements, providing practical examples and best practices for handling errors in streaming operations, route completion logic, and agent-session data synchronization.