@falai/agent 0.9.0-alpha-1 → 0.9.0-alpha-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 (166) hide show
  1. package/README.md +34 -22
  2. package/dist/cjs/src/core/Agent.d.ts +52 -24
  3. package/dist/cjs/src/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/src/core/Agent.js +266 -39
  5. package/dist/cjs/src/core/Agent.js.map +1 -1
  6. package/dist/cjs/src/core/PersistenceManager.d.ts.map +1 -1
  7. package/dist/cjs/src/core/PersistenceManager.js +48 -25
  8. package/dist/cjs/src/core/PersistenceManager.js.map +1 -1
  9. package/dist/cjs/src/core/PromptComposer.d.ts +1 -1
  10. package/dist/cjs/src/core/PromptComposer.d.ts.map +1 -1
  11. package/dist/cjs/src/core/PromptComposer.js.map +1 -1
  12. package/dist/cjs/src/core/ResponseEngine.d.ts +13 -12
  13. package/dist/cjs/src/core/ResponseEngine.d.ts.map +1 -1
  14. package/dist/cjs/src/core/ResponseEngine.js +4 -4
  15. package/dist/cjs/src/core/ResponseEngine.js.map +1 -1
  16. package/dist/cjs/src/core/ResponsePipeline.d.ts +66 -38
  17. package/dist/cjs/src/core/ResponsePipeline.d.ts.map +1 -1
  18. package/dist/cjs/src/core/ResponsePipeline.js +71 -3
  19. package/dist/cjs/src/core/ResponsePipeline.js.map +1 -1
  20. package/dist/cjs/src/core/Route.d.ts +24 -5
  21. package/dist/cjs/src/core/Route.d.ts.map +1 -1
  22. package/dist/cjs/src/core/Route.js +45 -1
  23. package/dist/cjs/src/core/Route.js.map +1 -1
  24. package/dist/cjs/src/core/RoutingEngine.d.ts +31 -6
  25. package/dist/cjs/src/core/RoutingEngine.d.ts.map +1 -1
  26. package/dist/cjs/src/core/RoutingEngine.js +113 -9
  27. package/dist/cjs/src/core/RoutingEngine.js.map +1 -1
  28. package/dist/cjs/src/core/SessionManager.d.ts +14 -4
  29. package/dist/cjs/src/core/SessionManager.d.ts.map +1 -1
  30. package/dist/cjs/src/core/SessionManager.js +25 -5
  31. package/dist/cjs/src/core/SessionManager.js.map +1 -1
  32. package/dist/cjs/src/core/Step.d.ts +10 -10
  33. package/dist/cjs/src/core/Step.d.ts.map +1 -1
  34. package/dist/cjs/src/core/Step.js.map +1 -1
  35. package/dist/cjs/src/core/ToolExecutor.d.ts +4 -2
  36. package/dist/cjs/src/core/ToolExecutor.d.ts.map +1 -1
  37. package/dist/cjs/src/core/ToolExecutor.js +13 -3
  38. package/dist/cjs/src/core/ToolExecutor.js.map +1 -1
  39. package/dist/cjs/src/types/agent.d.ts +41 -21
  40. package/dist/cjs/src/types/agent.d.ts.map +1 -1
  41. package/dist/cjs/src/types/agent.js.map +1 -1
  42. package/dist/cjs/src/types/index.d.ts +1 -1
  43. package/dist/cjs/src/types/index.d.ts.map +1 -1
  44. package/dist/cjs/src/types/index.js.map +1 -1
  45. package/dist/cjs/src/types/persistence.d.ts +0 -1
  46. package/dist/cjs/src/types/persistence.d.ts.map +1 -1
  47. package/dist/cjs/src/types/route.d.ts +22 -16
  48. package/dist/cjs/src/types/route.d.ts.map +1 -1
  49. package/dist/cjs/src/types/session.d.ts +6 -11
  50. package/dist/cjs/src/types/session.d.ts.map +1 -1
  51. package/dist/cjs/src/types/tool.d.ts +12 -6
  52. package/dist/cjs/src/types/tool.d.ts.map +1 -1
  53. package/dist/cjs/src/utils/session.d.ts +2 -2
  54. package/dist/cjs/src/utils/session.d.ts.map +1 -1
  55. package/dist/cjs/src/utils/session.js +6 -26
  56. package/dist/cjs/src/utils/session.js.map +1 -1
  57. package/dist/src/core/Agent.d.ts +52 -24
  58. package/dist/src/core/Agent.d.ts.map +1 -1
  59. package/dist/src/core/Agent.js +266 -39
  60. package/dist/src/core/Agent.js.map +1 -1
  61. package/dist/src/core/PersistenceManager.d.ts.map +1 -1
  62. package/dist/src/core/PersistenceManager.js +48 -25
  63. package/dist/src/core/PersistenceManager.js.map +1 -1
  64. package/dist/src/core/PromptComposer.d.ts +1 -1
  65. package/dist/src/core/PromptComposer.d.ts.map +1 -1
  66. package/dist/src/core/PromptComposer.js.map +1 -1
  67. package/dist/src/core/ResponseEngine.d.ts +13 -12
  68. package/dist/src/core/ResponseEngine.d.ts.map +1 -1
  69. package/dist/src/core/ResponseEngine.js +4 -4
  70. package/dist/src/core/ResponseEngine.js.map +1 -1
  71. package/dist/src/core/ResponsePipeline.d.ts +66 -38
  72. package/dist/src/core/ResponsePipeline.d.ts.map +1 -1
  73. package/dist/src/core/ResponsePipeline.js +71 -3
  74. package/dist/src/core/ResponsePipeline.js.map +1 -1
  75. package/dist/src/core/Route.d.ts +24 -5
  76. package/dist/src/core/Route.d.ts.map +1 -1
  77. package/dist/src/core/Route.js +45 -1
  78. package/dist/src/core/Route.js.map +1 -1
  79. package/dist/src/core/RoutingEngine.d.ts +31 -6
  80. package/dist/src/core/RoutingEngine.d.ts.map +1 -1
  81. package/dist/src/core/RoutingEngine.js +113 -9
  82. package/dist/src/core/RoutingEngine.js.map +1 -1
  83. package/dist/src/core/SessionManager.d.ts +14 -4
  84. package/dist/src/core/SessionManager.d.ts.map +1 -1
  85. package/dist/src/core/SessionManager.js +25 -5
  86. package/dist/src/core/SessionManager.js.map +1 -1
  87. package/dist/src/core/Step.d.ts +10 -10
  88. package/dist/src/core/Step.d.ts.map +1 -1
  89. package/dist/src/core/Step.js.map +1 -1
  90. package/dist/src/core/ToolExecutor.d.ts +4 -2
  91. package/dist/src/core/ToolExecutor.d.ts.map +1 -1
  92. package/dist/src/core/ToolExecutor.js +13 -3
  93. package/dist/src/core/ToolExecutor.js.map +1 -1
  94. package/dist/src/types/agent.d.ts +41 -21
  95. package/dist/src/types/agent.d.ts.map +1 -1
  96. package/dist/src/types/agent.js.map +1 -1
  97. package/dist/src/types/index.d.ts +1 -1
  98. package/dist/src/types/index.d.ts.map +1 -1
  99. package/dist/src/types/index.js.map +1 -1
  100. package/dist/src/types/persistence.d.ts +0 -1
  101. package/dist/src/types/persistence.d.ts.map +1 -1
  102. package/dist/src/types/route.d.ts +22 -16
  103. package/dist/src/types/route.d.ts.map +1 -1
  104. package/dist/src/types/session.d.ts +6 -11
  105. package/dist/src/types/session.d.ts.map +1 -1
  106. package/dist/src/types/tool.d.ts +12 -6
  107. package/dist/src/types/tool.d.ts.map +1 -1
  108. package/dist/src/utils/session.d.ts +2 -2
  109. package/dist/src/utils/session.d.ts.map +1 -1
  110. package/dist/src/utils/session.js +6 -26
  111. package/dist/src/utils/session.js.map +1 -1
  112. package/docs/README.md +3 -3
  113. package/docs/api/README.md +35 -4
  114. package/docs/api/overview.md +166 -12
  115. package/docs/core/agent/README.md +162 -17
  116. package/docs/core/agent/context-management.md +39 -15
  117. package/docs/core/agent/session-management.md +49 -16
  118. package/docs/core/ai-integration/prompt-composition.md +38 -14
  119. package/docs/core/ai-integration/response-processing.md +28 -17
  120. package/docs/core/conversation-flows/data-collection.md +103 -25
  121. package/docs/core/conversation-flows/route-dsl.md +45 -22
  122. package/docs/core/conversation-flows/routes.md +74 -18
  123. package/docs/core/conversation-flows/step-transitions.md +3 -3
  124. package/docs/core/conversation-flows/steps.md +39 -15
  125. package/docs/core/routing/intelligent-routing.md +18 -9
  126. package/docs/core/tools/tool-definition.md +8 -8
  127. package/docs/core/tools/tool-execution.md +26 -26
  128. package/docs/core/tools/tool-scoping.md +5 -5
  129. package/docs/guides/getting-started/README.md +54 -32
  130. package/examples/advanced-patterns/knowledge-based-agent.ts +37 -28
  131. package/examples/advanced-patterns/persistent-onboarding.ts +70 -41
  132. package/examples/advanced-patterns/route-lifecycle-hooks.ts +28 -2
  133. package/examples/advanced-patterns/streaming-responses.ts +28 -23
  134. package/examples/ai-providers/anthropic-integration.ts +40 -33
  135. package/examples/ai-providers/openai-integration.ts +25 -25
  136. package/examples/conversation-flows/completion-transitions.ts +36 -32
  137. package/examples/core-concepts/basic-agent.ts +76 -78
  138. package/examples/core-concepts/schema-driven-extraction.ts +20 -16
  139. package/examples/core-concepts/session-management.ts +65 -53
  140. package/examples/integrations/database-integration.ts +49 -34
  141. package/examples/integrations/healthcare-integration.ts +96 -91
  142. package/examples/integrations/search-integration.ts +79 -82
  143. package/examples/integrations/server-session-management.ts +25 -17
  144. package/examples/persistence/database-persistence.ts +61 -45
  145. package/examples/persistence/memory-sessions.ts +52 -63
  146. package/examples/persistence/redis-persistence.ts +81 -95
  147. package/examples/tools/basic-tools.ts +73 -62
  148. package/examples/tools/data-enrichment-tools.ts +52 -44
  149. package/package.json +1 -1
  150. package/src/core/Agent.ts +418 -128
  151. package/src/core/PersistenceManager.ts +51 -27
  152. package/src/core/PromptComposer.ts +1 -1
  153. package/src/core/ResponseEngine.ts +21 -19
  154. package/src/core/ResponsePipeline.ts +174 -59
  155. package/src/core/Route.ts +58 -6
  156. package/src/core/RoutingEngine.ts +174 -27
  157. package/src/core/SessionManager.ts +32 -8
  158. package/src/core/Step.ts +20 -12
  159. package/src/core/ToolExecutor.ts +19 -5
  160. package/src/types/agent.ts +46 -23
  161. package/src/types/index.ts +2 -0
  162. package/src/types/persistence.ts +0 -1
  163. package/src/types/route.ts +22 -16
  164. package/src/types/session.ts +6 -12
  165. package/src/types/tool.ts +15 -9
  166. package/src/utils/session.ts +6 -31
@@ -16,17 +16,39 @@ const ToolExecutor_1 = require("./ToolExecutor");
16
16
  const ResponsePipeline_1 = require("./ResponsePipeline");
17
17
  const constants_1 = require("../constants");
18
18
  /**
19
- * Main Agent class with generic context support
19
+ * Error thrown when data validation fails
20
20
  */
21
+ class DataValidationError extends Error {
22
+ constructor(errors, message) {
23
+ super(message || "Data validation failed");
24
+ this.errors = errors;
25
+ this.name = "DataValidationError";
26
+ }
27
+ }
28
+ /**
29
+ * Error thrown when route configuration is invalid
30
+ */
31
+ class RouteConfigurationError extends Error {
32
+ constructor(routeTitle, invalidFields, message) {
33
+ super(message || `Route configuration error in '${routeTitle}'`);
34
+ this.routeTitle = routeTitle;
35
+ this.invalidFields = invalidFields;
36
+ this.name = "RouteConfigurationError";
37
+ }
38
+ }
39
+ /**
40
+ * Main Agent class with generic context and data support
41
+ */
42
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
43
  class Agent {
22
44
  constructor(options) {
23
45
  this.options = options;
24
46
  this.terms = [];
25
47
  this.guidelines = [];
26
48
  this.tools = [];
27
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
49
  this.routes = [];
29
50
  this.knowledgeBase = {};
51
+ this.collectedData = {};
30
52
  // Set log level based on debug option
31
53
  if (options.debug) {
32
54
  utils_1.logger.setLevel(utils_1.LoggerLevel.DEBUG);
@@ -35,8 +57,25 @@ class Agent {
35
57
  if (options.context !== undefined && options.contextProvider) {
36
58
  throw new Error("Cannot provide both 'context' and 'contextProvider'. Choose one.");
37
59
  }
60
+ // Initialize and validate agent-level schema if provided
61
+ if (options.schema) {
62
+ this.schema = options.schema;
63
+ this.validateSchema(this.schema);
64
+ utils_1.logger.debug("[Agent] Agent-level schema initialized and validated");
65
+ }
38
66
  // Initialize context if provided
39
67
  this.context = options.context;
68
+ // Initialize collected data with initial data if provided
69
+ if (options.initialData) {
70
+ if (this.schema) {
71
+ const validation = this.validateData(options.initialData);
72
+ if (!validation.valid) {
73
+ throw new Error(`Initial data validation failed: ${validation.errors.map(e => e.message).join(', ')}`);
74
+ }
75
+ }
76
+ this.collectedData = { ...options.initialData };
77
+ utils_1.logger.debug("[Agent] Initial data set:", this.collectedData);
78
+ }
40
79
  // Initialize current session if provided
41
80
  this.currentSession = options.session;
42
81
  // Initialize routing and response engines
@@ -46,15 +85,32 @@ class Agent {
46
85
  switchThreshold: 70,
47
86
  });
48
87
  this.responseEngine = new ResponseEngine_1.ResponseEngine();
49
- this.responsePipeline = new ResponsePipeline_1.ResponsePipeline(options, this.routes, this.tools, this.routingEngine, this.updateContext.bind(this), this.updateData.bind(this));
88
+ this.responsePipeline = new ResponsePipeline_1.ResponsePipeline(options, this.routes, this.tools, this.routingEngine, this.updateContext.bind(this), this.updateData.bind(this), this.updateCollectedData.bind(this));
50
89
  // Initialize persistence if configured
51
90
  if (options.persistence) {
52
- this.persistenceManager = new PersistenceManager_1.PersistenceManager(options.persistence);
53
- // Initialize the adapter if it has an initialize method
54
- if (options.persistence.adapter.initialize) {
55
- options.persistence.adapter.initialize().catch((error) => {
56
- utils_1.logger.error("[Agent] Persistence adapter initialization failed:", error);
57
- });
91
+ try {
92
+ // Validate persistence configuration
93
+ if (!options.persistence.adapter) {
94
+ throw new Error("Persistence adapter is required when persistence is configured");
95
+ }
96
+ if (!options.persistence.adapter.sessionRepository) {
97
+ throw new Error("Persistence adapter must provide a sessionRepository");
98
+ }
99
+ if (!options.persistence.adapter.messageRepository) {
100
+ throw new Error("Persistence adapter must provide a messageRepository");
101
+ }
102
+ this.persistenceManager = new PersistenceManager_1.PersistenceManager(options.persistence);
103
+ // Initialize the adapter if it has an initialize method
104
+ if (options.persistence.adapter.initialize) {
105
+ options.persistence.adapter.initialize().catch((error) => {
106
+ utils_1.logger.error("[Agent] Persistence adapter initialization failed:", error instanceof Error ? error.message : String(error));
107
+ });
108
+ }
109
+ }
110
+ catch (error) {
111
+ const errorMessage = error instanceof Error ? error.message : String(error);
112
+ utils_1.logger.error("[Agent] Failed to initialize persistence:", errorMessage);
113
+ throw new Error(`Failed to initialize persistence: ${errorMessage}`);
58
114
  }
59
115
  }
60
116
  // Initialize from options - use create methods for consistency
@@ -92,6 +148,116 @@ class Agent {
92
148
  });
93
149
  }
94
150
  }
151
+ /**
152
+ * Validate the agent-level schema structure
153
+ * @private
154
+ */
155
+ validateSchema(schema) {
156
+ if (!schema || typeof schema !== 'object') {
157
+ throw new Error("Agent schema must be a valid JSON Schema object. " +
158
+ "Provide a schema with 'type': 'object' and 'properties' to define the data structure.");
159
+ }
160
+ if (schema.type !== 'object') {
161
+ throw new Error(`Agent schema must be of type 'object', but received '${String(schema.type)}'. ` +
162
+ "Agent-level schemas must define object structures for data collection.");
163
+ }
164
+ if (!schema.properties || typeof schema.properties !== 'object') {
165
+ throw new Error("Agent schema must have a 'properties' field defining the data fields. " +
166
+ "Example: { type: 'object', properties: { name: { type: 'string' }, email: { type: 'string' } } }");
167
+ }
168
+ utils_1.logger.debug("[Agent] Schema validation passed");
169
+ }
170
+ /**
171
+ * Validate data against the agent-level schema
172
+ */
173
+ validateData(data) {
174
+ if (!this.schema) {
175
+ // No schema defined, consider all data valid
176
+ return { valid: true, errors: [], warnings: [] };
177
+ }
178
+ const errors = [];
179
+ const warnings = [];
180
+ // Basic validation - check if provided fields exist in schema
181
+ if (this.schema.properties) {
182
+ for (const [key, value] of Object.entries(data)) {
183
+ if (!(key in this.schema.properties)) {
184
+ errors.push({
185
+ field: key,
186
+ value,
187
+ message: `Field '${key}' is not defined in agent schema`,
188
+ schemaPath: `properties.${key}`
189
+ });
190
+ }
191
+ }
192
+ }
193
+ // Check required fields if specified
194
+ if (this.schema.required && Array.isArray(this.schema.required)) {
195
+ for (const requiredField of this.schema.required) {
196
+ if (!(requiredField in data) || data[requiredField] === undefined) {
197
+ warnings.push({
198
+ field: requiredField,
199
+ value: undefined,
200
+ message: `Required field '${requiredField}' is missing`,
201
+ schemaPath: `required`
202
+ });
203
+ }
204
+ }
205
+ }
206
+ return {
207
+ valid: errors.length === 0,
208
+ errors,
209
+ warnings
210
+ };
211
+ }
212
+ /**
213
+ * Check if a field is valid according to the agent schema
214
+ * @param field - The field key to validate
215
+ * @returns true if field exists in schema or no schema is defined, false otherwise
216
+ */
217
+ isValidSchemaField(field) {
218
+ if (!this.schema || !this.schema.properties) {
219
+ // No schema defined, consider all fields valid
220
+ return true;
221
+ }
222
+ return field in this.schema.properties;
223
+ }
224
+ /**
225
+ * Get the current collected data
226
+ */
227
+ getCollectedData() {
228
+ return { ...this.collectedData };
229
+ }
230
+ /**
231
+ * Update collected data with validation
232
+ */
233
+ async updateCollectedData(updates) {
234
+ // Validate the updates
235
+ const validation = this.validateData(updates);
236
+ if (!validation.valid) {
237
+ const errorMessages = validation.errors.map(e => e.message).join(', ');
238
+ throw new DataValidationError(validation.errors, `Data validation failed: ${errorMessages}`);
239
+ }
240
+ // Log warnings if any
241
+ if (validation.warnings.length > 0) {
242
+ const warningMessages = validation.warnings.map(w => w.message).join(', ');
243
+ utils_1.logger.warn(`[Agent] Data validation warnings: ${warningMessages}`);
244
+ }
245
+ // Merge updates with current data
246
+ const previousData = { ...this.collectedData };
247
+ this.collectedData = {
248
+ ...this.collectedData,
249
+ ...updates
250
+ };
251
+ // Trigger agent-level lifecycle hook if configured
252
+ if (this.options.hooks?.onDataUpdate) {
253
+ this.collectedData = await this.options.hooks.onDataUpdate(this.collectedData, previousData);
254
+ }
255
+ // Update current session if it exists to keep it in sync
256
+ if (this.currentSession) {
257
+ this.currentSession = (0, utils_1.mergeCollected)(this.currentSession, this.collectedData);
258
+ }
259
+ utils_1.logger.debug("[Agent] Collected data updated:", updates);
260
+ }
95
261
  /**
96
262
  * Get agent name
97
263
  */
@@ -117,10 +283,25 @@ class Agent {
117
283
  return this.options.identity;
118
284
  }
119
285
  /**
120
- * Create a new route (journey)
121
- * @template TData - Type of data collected throughout the route
286
+ * Create a new route (journey) using agent-level data type
122
287
  */
123
288
  createRoute(options) {
289
+ // Validate that requiredFields exist in agent schema
290
+ if (options.requiredFields && this.schema?.properties) {
291
+ const invalidRequiredFields = options.requiredFields.filter(field => !(String(field) in this.schema.properties));
292
+ if (invalidRequiredFields.length > 0) {
293
+ throw new RouteConfigurationError(options.title, invalidRequiredFields.map(f => String(f)), `Invalid required fields in route '${options.title}': ${invalidRequiredFields.join(', ')}. ` +
294
+ `Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`);
295
+ }
296
+ }
297
+ // Validate that optionalFields exist in agent schema
298
+ if (options.optionalFields && this.schema?.properties) {
299
+ const invalidOptionalFields = options.optionalFields.filter(field => !(String(field) in this.schema.properties));
300
+ if (invalidOptionalFields.length > 0) {
301
+ throw new RouteConfigurationError(options.title, invalidOptionalFields.map(f => String(f)), `Invalid optional fields in route '${options.title}': ${invalidOptionalFields.join(', ')}. ` +
302
+ `Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`);
303
+ }
304
+ }
124
305
  const route = new Route_1.Route(options);
125
306
  this.routes.push(route);
126
307
  return route;
@@ -205,6 +386,8 @@ class Agent {
205
386
  if (this.options.hooks?.onDataUpdate) {
206
387
  newCollected = (await this.options.hooks.onDataUpdate(newCollected, previousCollected));
207
388
  }
389
+ // Update agent's collected data to stay in sync
390
+ this.collectedData = { ...newCollected };
208
391
  // Return updated session
209
392
  return (0, utils_1.mergeCollected)(session, newCollected);
210
393
  }
@@ -219,6 +402,12 @@ class Agent {
219
402
  // Otherwise return the stored context
220
403
  return this.context;
221
404
  }
405
+ /**
406
+ * Get current schema
407
+ */
408
+ getSchema() {
409
+ return this.schema;
410
+ }
222
411
  /**
223
412
  * Generate a response based on history and context as a stream
224
413
  */
@@ -235,6 +424,11 @@ class Agent {
235
424
  });
236
425
  const { effectiveContext } = responseContext;
237
426
  session = responseContext.session;
427
+ // Merge agent's collected data into session (agent data takes precedence)
428
+ if (Object.keys(this.collectedData).length > 0) {
429
+ session = (0, utils_1.mergeCollected)(session, this.collectedData);
430
+ utils_1.logger.debug("[Agent] Merged agent collected data into session:", this.collectedData);
431
+ }
238
432
  // Update our stored context if it was modified by beforeRespond hook
239
433
  this.context = this.responsePipeline.getStoredContext();
240
434
  // PHASE 1: PREPARE - Execute prepare function if current step has one
@@ -274,7 +468,7 @@ class Agent {
274
468
  // Get last user message
275
469
  const lastUserMessage = (0, utils_1.getLastMessageFromHistory)(history);
276
470
  // Build response schema for this route (with collect fields from step)
277
- const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep);
471
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.schema);
278
472
  // Check if selected route and next step are defined
279
473
  if (!selectedRoute || !nextStep) {
280
474
  utils_1.logger.error("[Agent] Selected route or next step is not defined", {
@@ -301,6 +495,7 @@ class Agent {
301
495
  combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
302
496
  context: effectiveContext,
303
497
  session,
498
+ agentSchema: this.schema,
304
499
  });
305
500
  // Collect available tools for AI
306
501
  const availableTools = this.collectAvailableTools(selectedRoute, nextStep);
@@ -336,6 +531,7 @@ class Agent {
336
531
  tool: tool,
337
532
  context: effectiveContext,
338
533
  updateContext: this.updateContext.bind(this),
534
+ updateData: this.updateCollectedData.bind(this),
339
535
  history,
340
536
  data: session.data,
341
537
  toolArguments: toolCall.arguments,
@@ -419,6 +615,7 @@ class Agent {
419
615
  tool: tool,
420
616
  context: effectiveContext,
421
617
  updateContext: this.updateContext.bind(this),
618
+ updateData: this.updateCollectedData.bind(this),
422
619
  history: updatedHistory,
423
620
  data: session.data,
424
621
  toolArguments: toolCall.arguments,
@@ -452,12 +649,16 @@ class Agent {
452
649
  // The structured response includes both base fields and collected extraction fields
453
650
  const structuredData = chunk.structured;
454
651
  for (const field of nextStep.collect) {
455
- if (field in structuredData) {
456
- collectedData[field] = structuredData[field];
652
+ const fieldKey = String(field);
653
+ if (fieldKey in structuredData) {
654
+ collectedData[fieldKey] = structuredData[fieldKey];
457
655
  }
458
656
  }
459
- // Merge collected data into session
657
+ // Merge collected data into session using agent-level data validation
460
658
  if (Object.keys(collectedData).length > 0) {
659
+ // Update agent-level collected data with validation
660
+ await this.updateCollectedData(collectedData);
661
+ // Update session with validated data
461
662
  session = await this.updateData(session, collectedData);
462
663
  utils_1.logger.debug(`[Agent] Collected data:`, collectedData);
463
664
  }
@@ -520,7 +721,7 @@ class Agent {
520
721
  "Summarize what was accomplished and confirm completion based on the conversation history and collected data",
521
722
  });
522
723
  // Build response schema for completion
523
- const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep);
724
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.schema);
524
725
  const templateContext = {
525
726
  context: effectiveContext,
526
727
  session,
@@ -544,6 +745,7 @@ class Agent {
544
745
  combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
545
746
  context: effectiveContext,
546
747
  session,
748
+ agentSchema: this.schema,
547
749
  });
548
750
  // Stream completion message using AI provider
549
751
  const stream = this.options.provider.generateMessageStream({
@@ -669,6 +871,11 @@ class Agent {
669
871
  let session = (0, utils_1.cloneDeep)(params.session) ||
670
872
  (0, utils_1.cloneDeep)(this.currentSession) ||
671
873
  (await this.session.getOrCreate());
874
+ // Merge agent's collected data into session (agent data takes precedence)
875
+ if (Object.keys(this.collectedData).length > 0) {
876
+ session = (0, utils_1.mergeCollected)(session, this.collectedData);
877
+ utils_1.logger.debug("[Agent] Merged agent collected data into session:", this.collectedData);
878
+ }
672
879
  // PHASE 1: PREPARE - Execute prepare function if current step has one
673
880
  if (session.currentRoute && session.currentStep) {
674
881
  const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
@@ -766,7 +973,7 @@ class Agent {
766
973
  // Get last user message
767
974
  const lastUserMessage = (0, utils_1.getLastMessageFromHistory)(history);
768
975
  // Build response schema for this route (with collect fields from step)
769
- responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep);
976
+ responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.schema);
770
977
  // Build response prompt
771
978
  responsePrompt = await this.responseEngine.buildResponsePrompt({
772
979
  route: selectedRoute,
@@ -785,6 +992,7 @@ class Agent {
785
992
  combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
786
993
  context: effectiveContext,
787
994
  session,
995
+ agentSchema: this.schema,
788
996
  });
789
997
  // Collect available tools for AI
790
998
  availableTools = this.collectAvailableTools(selectedRoute, nextStep);
@@ -802,7 +1010,7 @@ class Agent {
802
1010
  session,
803
1011
  });
804
1012
  // Use agent-level tools only
805
- availableTools = [...this.tools];
1013
+ availableTools = this.collectAvailableTools();
806
1014
  responseSchema = undefined;
807
1015
  }
808
1016
  // Generate message using AI provider (common for both route and no-route cases)
@@ -837,6 +1045,7 @@ class Agent {
837
1045
  tool: tool,
838
1046
  context: effectiveContext,
839
1047
  updateContext: this.updateContext.bind(this),
1048
+ updateData: this.updateCollectedData.bind(this),
840
1049
  history,
841
1050
  data: session.data,
842
1051
  toolArguments: toolCall.arguments,
@@ -915,6 +1124,7 @@ class Agent {
915
1124
  tool: tool,
916
1125
  context: effectiveContext,
917
1126
  updateContext: this.updateContext.bind(this),
1127
+ updateData: this.updateCollectedData.bind(this),
918
1128
  history: updatedHistory,
919
1129
  data: session.data,
920
1130
  toolArguments: toolCall.arguments,
@@ -949,12 +1159,16 @@ class Agent {
949
1159
  // The structured response includes both base fields and collected extraction fields
950
1160
  const structuredData = result.structured;
951
1161
  for (const field of nextStep.collect) {
952
- if (field in structuredData) {
953
- collectedData[field] = structuredData[field];
1162
+ const fieldKey = String(field);
1163
+ if (fieldKey in structuredData) {
1164
+ collectedData[fieldKey] = structuredData[fieldKey];
954
1165
  }
955
1166
  }
956
- // Merge collected data into session
1167
+ // Merge collected data into session using agent-level data validation
957
1168
  if (Object.keys(collectedData).length > 0) {
1169
+ // Update agent-level collected data with validation
1170
+ await this.updateCollectedData(collectedData);
1171
+ // Update session with validated data
958
1172
  session = await this.updateData(session, collectedData);
959
1173
  utils_1.logger.debug(`[Agent] Collected data:`, collectedData);
960
1174
  }
@@ -980,16 +1194,16 @@ class Agent {
980
1194
  prompt: endStepSpec.prompt ||
981
1195
  "Summarize what was accomplished and confirm completion based on the conversation history and collected data",
982
1196
  });
1197
+ if (!selectedRoute) {
1198
+ throw new Error("Selected route is not defined");
1199
+ }
983
1200
  // Build response schema for completion
984
- const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep);
1201
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.schema);
985
1202
  const templateContext = {
986
1203
  context: effectiveContext,
987
1204
  session,
988
1205
  history,
989
1206
  };
990
- if (!selectedRoute) {
991
- throw new Error("Selected route is not defined");
992
- }
993
1207
  // Build completion response prompt
994
1208
  const completionPrompt = await this.responseEngine.buildResponsePrompt({
995
1209
  route: selectedRoute,
@@ -1008,6 +1222,7 @@ class Agent {
1008
1222
  combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
1009
1223
  context: effectiveContext,
1010
1224
  session,
1225
+ agentSchema: this.schema,
1011
1226
  });
1012
1227
  // Generate completion message using AI provider
1013
1228
  const completionResult = await this.options.provider.generateMessage({
@@ -1253,6 +1468,7 @@ class Agent {
1253
1468
  tool,
1254
1469
  context,
1255
1470
  updateContext: this.updateContext.bind(this),
1471
+ updateData: this.updateCollectedData.bind(this),
1256
1472
  history: [], // Empty history for prepare/finalize
1257
1473
  data,
1258
1474
  });
@@ -1330,19 +1546,19 @@ class Agent {
1330
1546
  this.currentSession = undefined;
1331
1547
  }
1332
1548
  /**
1333
- * Get collected data from current session
1549
+ * Get collected data from current session or agent-level collected data
1334
1550
  * @param routeId - Optional route ID to get data for (uses current route if not provided)
1335
- * @returns The collected data from the current session
1551
+ * @returns The collected data from the current session or agent-level data
1336
1552
  */
1337
- getData(routeId) {
1338
- if (!this.currentSession) {
1339
- return {};
1340
- }
1341
- if (routeId) {
1342
- return (this.currentSession.dataByRoute?.[routeId] ||
1343
- {});
1553
+ getData() {
1554
+ // If we have a current session, use session data
1555
+ if (this.currentSession) {
1556
+ // With agent-level data, all routes share the same data structure
1557
+ // No need for route-specific data access
1558
+ return (this.currentSession.data) || {};
1344
1559
  }
1345
- return this.currentSession.data || {};
1560
+ // Otherwise, return agent-level collected data
1561
+ return this.getCollectedData();
1346
1562
  }
1347
1563
  /**
1348
1564
  * Manually transition to a different route
@@ -1385,14 +1601,14 @@ class Agent {
1385
1601
  pendingTransition: {
1386
1602
  targetRouteId: targetRoute.id,
1387
1603
  condition: renderedCondition,
1388
- reason: "manual",
1604
+ reason: "route_complete",
1389
1605
  },
1390
1606
  };
1391
1607
  // Update current session if using it
1392
1608
  if (!session && this.currentSession) {
1393
1609
  this.currentSession = updatedSession;
1394
1610
  }
1395
- utils_1.logger.debug(`[Agent] Set pending manual transition to route: ${targetRoute.title}`);
1611
+ utils_1.logger.debug(`[Agent] Set pending transition to route: ${targetRoute.title}`);
1396
1612
  return updatedSession;
1397
1613
  }
1398
1614
  /**
@@ -1414,7 +1630,14 @@ class Agent {
1414
1630
  history = this.session.getHistory();
1415
1631
  }
1416
1632
  // Get or create session
1417
- const session = await this.session.getOrCreate();
1633
+ let session = await this.session.getOrCreate();
1634
+ // Merge agent's collected data into session (agent data takes precedence)
1635
+ if (Object.keys(this.collectedData).length > 0) {
1636
+ session = (0, utils_1.mergeCollected)(session, this.collectedData);
1637
+ // Update the session manager with the merged data
1638
+ await this.session.setData(this.collectedData);
1639
+ utils_1.logger.debug("[Agent] Merged agent collected data into chat session:", this.collectedData);
1640
+ }
1418
1641
  // Use existing respond method with session-managed history
1419
1642
  const result = await this.respond({
1420
1643
  history,
@@ -1426,7 +1649,11 @@ class Agent {
1426
1649
  if (!options?.history) {
1427
1650
  await this.session.addMessage("assistant", result.message);
1428
1651
  }
1429
- return result;
1652
+ // Ensure the result includes the current session
1653
+ return {
1654
+ ...result,
1655
+ session: result.session || this.session.current,
1656
+ };
1430
1657
  }
1431
1658
  }
1432
1659
  exports.Agent = Agent;