@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
@@ -13,17 +13,39 @@ import { ToolExecutor } from "./ToolExecutor";
13
13
  import { ResponsePipeline } from "./ResponsePipeline";
14
14
  import { END_ROUTE_ID } from "../constants";
15
15
  /**
16
- * Main Agent class with generic context support
16
+ * Error thrown when data validation fails
17
17
  */
18
+ class DataValidationError extends Error {
19
+ constructor(errors, message) {
20
+ super(message || "Data validation failed");
21
+ this.errors = errors;
22
+ this.name = "DataValidationError";
23
+ }
24
+ }
25
+ /**
26
+ * Error thrown when route configuration is invalid
27
+ */
28
+ class RouteConfigurationError extends Error {
29
+ constructor(routeTitle, invalidFields, message) {
30
+ super(message || `Route configuration error in '${routeTitle}'`);
31
+ this.routeTitle = routeTitle;
32
+ this.invalidFields = invalidFields;
33
+ this.name = "RouteConfigurationError";
34
+ }
35
+ }
36
+ /**
37
+ * Main Agent class with generic context and data support
38
+ */
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
40
  export class Agent {
19
41
  constructor(options) {
20
42
  this.options = options;
21
43
  this.terms = [];
22
44
  this.guidelines = [];
23
45
  this.tools = [];
24
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
46
  this.routes = [];
26
47
  this.knowledgeBase = {};
48
+ this.collectedData = {};
27
49
  // Set log level based on debug option
28
50
  if (options.debug) {
29
51
  logger.setLevel(LoggerLevel.DEBUG);
@@ -32,8 +54,25 @@ export class Agent {
32
54
  if (options.context !== undefined && options.contextProvider) {
33
55
  throw new Error("Cannot provide both 'context' and 'contextProvider'. Choose one.");
34
56
  }
57
+ // Initialize and validate agent-level schema if provided
58
+ if (options.schema) {
59
+ this.schema = options.schema;
60
+ this.validateSchema(this.schema);
61
+ logger.debug("[Agent] Agent-level schema initialized and validated");
62
+ }
35
63
  // Initialize context if provided
36
64
  this.context = options.context;
65
+ // Initialize collected data with initial data if provided
66
+ if (options.initialData) {
67
+ if (this.schema) {
68
+ const validation = this.validateData(options.initialData);
69
+ if (!validation.valid) {
70
+ throw new Error(`Initial data validation failed: ${validation.errors.map(e => e.message).join(', ')}`);
71
+ }
72
+ }
73
+ this.collectedData = { ...options.initialData };
74
+ logger.debug("[Agent] Initial data set:", this.collectedData);
75
+ }
37
76
  // Initialize current session if provided
38
77
  this.currentSession = options.session;
39
78
  // Initialize routing and response engines
@@ -43,15 +82,32 @@ export class Agent {
43
82
  switchThreshold: 70,
44
83
  });
45
84
  this.responseEngine = new ResponseEngine();
46
- this.responsePipeline = new ResponsePipeline(options, this.routes, this.tools, this.routingEngine, this.updateContext.bind(this), this.updateData.bind(this));
85
+ this.responsePipeline = new ResponsePipeline(options, this.routes, this.tools, this.routingEngine, this.updateContext.bind(this), this.updateData.bind(this), this.updateCollectedData.bind(this));
47
86
  // Initialize persistence if configured
48
87
  if (options.persistence) {
49
- this.persistenceManager = new PersistenceManager(options.persistence);
50
- // Initialize the adapter if it has an initialize method
51
- if (options.persistence.adapter.initialize) {
52
- options.persistence.adapter.initialize().catch((error) => {
53
- logger.error("[Agent] Persistence adapter initialization failed:", error);
54
- });
88
+ try {
89
+ // Validate persistence configuration
90
+ if (!options.persistence.adapter) {
91
+ throw new Error("Persistence adapter is required when persistence is configured");
92
+ }
93
+ if (!options.persistence.adapter.sessionRepository) {
94
+ throw new Error("Persistence adapter must provide a sessionRepository");
95
+ }
96
+ if (!options.persistence.adapter.messageRepository) {
97
+ throw new Error("Persistence adapter must provide a messageRepository");
98
+ }
99
+ this.persistenceManager = new PersistenceManager(options.persistence);
100
+ // Initialize the adapter if it has an initialize method
101
+ if (options.persistence.adapter.initialize) {
102
+ options.persistence.adapter.initialize().catch((error) => {
103
+ logger.error("[Agent] Persistence adapter initialization failed:", error instanceof Error ? error.message : String(error));
104
+ });
105
+ }
106
+ }
107
+ catch (error) {
108
+ const errorMessage = error instanceof Error ? error.message : String(error);
109
+ logger.error("[Agent] Failed to initialize persistence:", errorMessage);
110
+ throw new Error(`Failed to initialize persistence: ${errorMessage}`);
55
111
  }
56
112
  }
57
113
  // Initialize from options - use create methods for consistency
@@ -89,6 +145,116 @@ export class Agent {
89
145
  });
90
146
  }
91
147
  }
148
+ /**
149
+ * Validate the agent-level schema structure
150
+ * @private
151
+ */
152
+ validateSchema(schema) {
153
+ if (!schema || typeof schema !== 'object') {
154
+ throw new Error("Agent schema must be a valid JSON Schema object. " +
155
+ "Provide a schema with 'type': 'object' and 'properties' to define the data structure.");
156
+ }
157
+ if (schema.type !== 'object') {
158
+ throw new Error(`Agent schema must be of type 'object', but received '${String(schema.type)}'. ` +
159
+ "Agent-level schemas must define object structures for data collection.");
160
+ }
161
+ if (!schema.properties || typeof schema.properties !== 'object') {
162
+ throw new Error("Agent schema must have a 'properties' field defining the data fields. " +
163
+ "Example: { type: 'object', properties: { name: { type: 'string' }, email: { type: 'string' } } }");
164
+ }
165
+ logger.debug("[Agent] Schema validation passed");
166
+ }
167
+ /**
168
+ * Validate data against the agent-level schema
169
+ */
170
+ validateData(data) {
171
+ if (!this.schema) {
172
+ // No schema defined, consider all data valid
173
+ return { valid: true, errors: [], warnings: [] };
174
+ }
175
+ const errors = [];
176
+ const warnings = [];
177
+ // Basic validation - check if provided fields exist in schema
178
+ if (this.schema.properties) {
179
+ for (const [key, value] of Object.entries(data)) {
180
+ if (!(key in this.schema.properties)) {
181
+ errors.push({
182
+ field: key,
183
+ value,
184
+ message: `Field '${key}' is not defined in agent schema`,
185
+ schemaPath: `properties.${key}`
186
+ });
187
+ }
188
+ }
189
+ }
190
+ // Check required fields if specified
191
+ if (this.schema.required && Array.isArray(this.schema.required)) {
192
+ for (const requiredField of this.schema.required) {
193
+ if (!(requiredField in data) || data[requiredField] === undefined) {
194
+ warnings.push({
195
+ field: requiredField,
196
+ value: undefined,
197
+ message: `Required field '${requiredField}' is missing`,
198
+ schemaPath: `required`
199
+ });
200
+ }
201
+ }
202
+ }
203
+ return {
204
+ valid: errors.length === 0,
205
+ errors,
206
+ warnings
207
+ };
208
+ }
209
+ /**
210
+ * Check if a field is valid according to the agent schema
211
+ * @param field - The field key to validate
212
+ * @returns true if field exists in schema or no schema is defined, false otherwise
213
+ */
214
+ isValidSchemaField(field) {
215
+ if (!this.schema || !this.schema.properties) {
216
+ // No schema defined, consider all fields valid
217
+ return true;
218
+ }
219
+ return field in this.schema.properties;
220
+ }
221
+ /**
222
+ * Get the current collected data
223
+ */
224
+ getCollectedData() {
225
+ return { ...this.collectedData };
226
+ }
227
+ /**
228
+ * Update collected data with validation
229
+ */
230
+ async updateCollectedData(updates) {
231
+ // Validate the updates
232
+ const validation = this.validateData(updates);
233
+ if (!validation.valid) {
234
+ const errorMessages = validation.errors.map(e => e.message).join(', ');
235
+ throw new DataValidationError(validation.errors, `Data validation failed: ${errorMessages}`);
236
+ }
237
+ // Log warnings if any
238
+ if (validation.warnings.length > 0) {
239
+ const warningMessages = validation.warnings.map(w => w.message).join(', ');
240
+ logger.warn(`[Agent] Data validation warnings: ${warningMessages}`);
241
+ }
242
+ // Merge updates with current data
243
+ const previousData = { ...this.collectedData };
244
+ this.collectedData = {
245
+ ...this.collectedData,
246
+ ...updates
247
+ };
248
+ // Trigger agent-level lifecycle hook if configured
249
+ if (this.options.hooks?.onDataUpdate) {
250
+ this.collectedData = await this.options.hooks.onDataUpdate(this.collectedData, previousData);
251
+ }
252
+ // Update current session if it exists to keep it in sync
253
+ if (this.currentSession) {
254
+ this.currentSession = mergeCollected(this.currentSession, this.collectedData);
255
+ }
256
+ logger.debug("[Agent] Collected data updated:", updates);
257
+ }
92
258
  /**
93
259
  * Get agent name
94
260
  */
@@ -114,10 +280,25 @@ export class Agent {
114
280
  return this.options.identity;
115
281
  }
116
282
  /**
117
- * Create a new route (journey)
118
- * @template TData - Type of data collected throughout the route
283
+ * Create a new route (journey) using agent-level data type
119
284
  */
120
285
  createRoute(options) {
286
+ // Validate that requiredFields exist in agent schema
287
+ if (options.requiredFields && this.schema?.properties) {
288
+ const invalidRequiredFields = options.requiredFields.filter(field => !(String(field) in this.schema.properties));
289
+ if (invalidRequiredFields.length > 0) {
290
+ throw new RouteConfigurationError(options.title, invalidRequiredFields.map(f => String(f)), `Invalid required fields in route '${options.title}': ${invalidRequiredFields.join(', ')}. ` +
291
+ `Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`);
292
+ }
293
+ }
294
+ // Validate that optionalFields exist in agent schema
295
+ if (options.optionalFields && this.schema?.properties) {
296
+ const invalidOptionalFields = options.optionalFields.filter(field => !(String(field) in this.schema.properties));
297
+ if (invalidOptionalFields.length > 0) {
298
+ throw new RouteConfigurationError(options.title, invalidOptionalFields.map(f => String(f)), `Invalid optional fields in route '${options.title}': ${invalidOptionalFields.join(', ')}. ` +
299
+ `Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`);
300
+ }
301
+ }
121
302
  const route = new Route(options);
122
303
  this.routes.push(route);
123
304
  return route;
@@ -202,6 +383,8 @@ export class Agent {
202
383
  if (this.options.hooks?.onDataUpdate) {
203
384
  newCollected = (await this.options.hooks.onDataUpdate(newCollected, previousCollected));
204
385
  }
386
+ // Update agent's collected data to stay in sync
387
+ this.collectedData = { ...newCollected };
205
388
  // Return updated session
206
389
  return mergeCollected(session, newCollected);
207
390
  }
@@ -216,6 +399,12 @@ export class Agent {
216
399
  // Otherwise return the stored context
217
400
  return this.context;
218
401
  }
402
+ /**
403
+ * Get current schema
404
+ */
405
+ getSchema() {
406
+ return this.schema;
407
+ }
219
408
  /**
220
409
  * Generate a response based on history and context as a stream
221
410
  */
@@ -232,6 +421,11 @@ export class Agent {
232
421
  });
233
422
  const { effectiveContext } = responseContext;
234
423
  session = responseContext.session;
424
+ // Merge agent's collected data into session (agent data takes precedence)
425
+ if (Object.keys(this.collectedData).length > 0) {
426
+ session = mergeCollected(session, this.collectedData);
427
+ logger.debug("[Agent] Merged agent collected data into session:", this.collectedData);
428
+ }
235
429
  // Update our stored context if it was modified by beforeRespond hook
236
430
  this.context = this.responsePipeline.getStoredContext();
237
431
  // PHASE 1: PREPARE - Execute prepare function if current step has one
@@ -271,7 +465,7 @@ export class Agent {
271
465
  // Get last user message
272
466
  const lastUserMessage = getLastMessageFromHistory(history);
273
467
  // Build response schema for this route (with collect fields from step)
274
- const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep);
468
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.schema);
275
469
  // Check if selected route and next step are defined
276
470
  if (!selectedRoute || !nextStep) {
277
471
  logger.error("[Agent] Selected route or next step is not defined", {
@@ -298,6 +492,7 @@ export class Agent {
298
492
  combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
299
493
  context: effectiveContext,
300
494
  session,
495
+ agentSchema: this.schema,
301
496
  });
302
497
  // Collect available tools for AI
303
498
  const availableTools = this.collectAvailableTools(selectedRoute, nextStep);
@@ -333,6 +528,7 @@ export class Agent {
333
528
  tool: tool,
334
529
  context: effectiveContext,
335
530
  updateContext: this.updateContext.bind(this),
531
+ updateData: this.updateCollectedData.bind(this),
336
532
  history,
337
533
  data: session.data,
338
534
  toolArguments: toolCall.arguments,
@@ -416,6 +612,7 @@ export class Agent {
416
612
  tool: tool,
417
613
  context: effectiveContext,
418
614
  updateContext: this.updateContext.bind(this),
615
+ updateData: this.updateCollectedData.bind(this),
419
616
  history: updatedHistory,
420
617
  data: session.data,
421
618
  toolArguments: toolCall.arguments,
@@ -449,12 +646,16 @@ export class Agent {
449
646
  // The structured response includes both base fields and collected extraction fields
450
647
  const structuredData = chunk.structured;
451
648
  for (const field of nextStep.collect) {
452
- if (field in structuredData) {
453
- collectedData[field] = structuredData[field];
649
+ const fieldKey = String(field);
650
+ if (fieldKey in structuredData) {
651
+ collectedData[fieldKey] = structuredData[fieldKey];
454
652
  }
455
653
  }
456
- // Merge collected data into session
654
+ // Merge collected data into session using agent-level data validation
457
655
  if (Object.keys(collectedData).length > 0) {
656
+ // Update agent-level collected data with validation
657
+ await this.updateCollectedData(collectedData);
658
+ // Update session with validated data
458
659
  session = await this.updateData(session, collectedData);
459
660
  logger.debug(`[Agent] Collected data:`, collectedData);
460
661
  }
@@ -517,7 +718,7 @@ export class Agent {
517
718
  "Summarize what was accomplished and confirm completion based on the conversation history and collected data",
518
719
  });
519
720
  // Build response schema for completion
520
- const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep);
721
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.schema);
521
722
  const templateContext = {
522
723
  context: effectiveContext,
523
724
  session,
@@ -541,6 +742,7 @@ export class Agent {
541
742
  combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
542
743
  context: effectiveContext,
543
744
  session,
745
+ agentSchema: this.schema,
544
746
  });
545
747
  // Stream completion message using AI provider
546
748
  const stream = this.options.provider.generateMessageStream({
@@ -666,6 +868,11 @@ export class Agent {
666
868
  let session = cloneDeep(params.session) ||
667
869
  cloneDeep(this.currentSession) ||
668
870
  (await this.session.getOrCreate());
871
+ // Merge agent's collected data into session (agent data takes precedence)
872
+ if (Object.keys(this.collectedData).length > 0) {
873
+ session = mergeCollected(session, this.collectedData);
874
+ logger.debug("[Agent] Merged agent collected data into session:", this.collectedData);
875
+ }
669
876
  // PHASE 1: PREPARE - Execute prepare function if current step has one
670
877
  if (session.currentRoute && session.currentStep) {
671
878
  const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
@@ -763,7 +970,7 @@ export class Agent {
763
970
  // Get last user message
764
971
  const lastUserMessage = getLastMessageFromHistory(history);
765
972
  // Build response schema for this route (with collect fields from step)
766
- responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep);
973
+ responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.schema);
767
974
  // Build response prompt
768
975
  responsePrompt = await this.responseEngine.buildResponsePrompt({
769
976
  route: selectedRoute,
@@ -782,6 +989,7 @@ export class Agent {
782
989
  combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
783
990
  context: effectiveContext,
784
991
  session,
992
+ agentSchema: this.schema,
785
993
  });
786
994
  // Collect available tools for AI
787
995
  availableTools = this.collectAvailableTools(selectedRoute, nextStep);
@@ -799,7 +1007,7 @@ export class Agent {
799
1007
  session,
800
1008
  });
801
1009
  // Use agent-level tools only
802
- availableTools = [...this.tools];
1010
+ availableTools = this.collectAvailableTools();
803
1011
  responseSchema = undefined;
804
1012
  }
805
1013
  // Generate message using AI provider (common for both route and no-route cases)
@@ -834,6 +1042,7 @@ export class Agent {
834
1042
  tool: tool,
835
1043
  context: effectiveContext,
836
1044
  updateContext: this.updateContext.bind(this),
1045
+ updateData: this.updateCollectedData.bind(this),
837
1046
  history,
838
1047
  data: session.data,
839
1048
  toolArguments: toolCall.arguments,
@@ -912,6 +1121,7 @@ export class Agent {
912
1121
  tool: tool,
913
1122
  context: effectiveContext,
914
1123
  updateContext: this.updateContext.bind(this),
1124
+ updateData: this.updateCollectedData.bind(this),
915
1125
  history: updatedHistory,
916
1126
  data: session.data,
917
1127
  toolArguments: toolCall.arguments,
@@ -946,12 +1156,16 @@ export class Agent {
946
1156
  // The structured response includes both base fields and collected extraction fields
947
1157
  const structuredData = result.structured;
948
1158
  for (const field of nextStep.collect) {
949
- if (field in structuredData) {
950
- collectedData[field] = structuredData[field];
1159
+ const fieldKey = String(field);
1160
+ if (fieldKey in structuredData) {
1161
+ collectedData[fieldKey] = structuredData[fieldKey];
951
1162
  }
952
1163
  }
953
- // Merge collected data into session
1164
+ // Merge collected data into session using agent-level data validation
954
1165
  if (Object.keys(collectedData).length > 0) {
1166
+ // Update agent-level collected data with validation
1167
+ await this.updateCollectedData(collectedData);
1168
+ // Update session with validated data
955
1169
  session = await this.updateData(session, collectedData);
956
1170
  logger.debug(`[Agent] Collected data:`, collectedData);
957
1171
  }
@@ -977,16 +1191,16 @@ export class Agent {
977
1191
  prompt: endStepSpec.prompt ||
978
1192
  "Summarize what was accomplished and confirm completion based on the conversation history and collected data",
979
1193
  });
1194
+ if (!selectedRoute) {
1195
+ throw new Error("Selected route is not defined");
1196
+ }
980
1197
  // Build response schema for completion
981
- const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep);
1198
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.schema);
982
1199
  const templateContext = {
983
1200
  context: effectiveContext,
984
1201
  session,
985
1202
  history,
986
1203
  };
987
- if (!selectedRoute) {
988
- throw new Error("Selected route is not defined");
989
- }
990
1204
  // Build completion response prompt
991
1205
  const completionPrompt = await this.responseEngine.buildResponsePrompt({
992
1206
  route: selectedRoute,
@@ -1005,6 +1219,7 @@ export class Agent {
1005
1219
  combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
1006
1220
  context: effectiveContext,
1007
1221
  session,
1222
+ agentSchema: this.schema,
1008
1223
  });
1009
1224
  // Generate completion message using AI provider
1010
1225
  const completionResult = await this.options.provider.generateMessage({
@@ -1250,6 +1465,7 @@ export class Agent {
1250
1465
  tool,
1251
1466
  context,
1252
1467
  updateContext: this.updateContext.bind(this),
1468
+ updateData: this.updateCollectedData.bind(this),
1253
1469
  history: [], // Empty history for prepare/finalize
1254
1470
  data,
1255
1471
  });
@@ -1327,19 +1543,19 @@ export class Agent {
1327
1543
  this.currentSession = undefined;
1328
1544
  }
1329
1545
  /**
1330
- * Get collected data from current session
1546
+ * Get collected data from current session or agent-level collected data
1331
1547
  * @param routeId - Optional route ID to get data for (uses current route if not provided)
1332
- * @returns The collected data from the current session
1548
+ * @returns The collected data from the current session or agent-level data
1333
1549
  */
1334
- getData(routeId) {
1335
- if (!this.currentSession) {
1336
- return {};
1337
- }
1338
- if (routeId) {
1339
- return (this.currentSession.dataByRoute?.[routeId] ||
1340
- {});
1550
+ getData() {
1551
+ // If we have a current session, use session data
1552
+ if (this.currentSession) {
1553
+ // With agent-level data, all routes share the same data structure
1554
+ // No need for route-specific data access
1555
+ return (this.currentSession.data) || {};
1341
1556
  }
1342
- return this.currentSession.data || {};
1557
+ // Otherwise, return agent-level collected data
1558
+ return this.getCollectedData();
1343
1559
  }
1344
1560
  /**
1345
1561
  * Manually transition to a different route
@@ -1382,14 +1598,14 @@ export class Agent {
1382
1598
  pendingTransition: {
1383
1599
  targetRouteId: targetRoute.id,
1384
1600
  condition: renderedCondition,
1385
- reason: "manual",
1601
+ reason: "route_complete",
1386
1602
  },
1387
1603
  };
1388
1604
  // Update current session if using it
1389
1605
  if (!session && this.currentSession) {
1390
1606
  this.currentSession = updatedSession;
1391
1607
  }
1392
- logger.debug(`[Agent] Set pending manual transition to route: ${targetRoute.title}`);
1608
+ logger.debug(`[Agent] Set pending transition to route: ${targetRoute.title}`);
1393
1609
  return updatedSession;
1394
1610
  }
1395
1611
  /**
@@ -1411,7 +1627,14 @@ export class Agent {
1411
1627
  history = this.session.getHistory();
1412
1628
  }
1413
1629
  // Get or create session
1414
- const session = await this.session.getOrCreate();
1630
+ let session = await this.session.getOrCreate();
1631
+ // Merge agent's collected data into session (agent data takes precedence)
1632
+ if (Object.keys(this.collectedData).length > 0) {
1633
+ session = mergeCollected(session, this.collectedData);
1634
+ // Update the session manager with the merged data
1635
+ await this.session.setData(this.collectedData);
1636
+ logger.debug("[Agent] Merged agent collected data into chat session:", this.collectedData);
1637
+ }
1415
1638
  // Use existing respond method with session-managed history
1416
1639
  const result = await this.respond({
1417
1640
  history,
@@ -1423,7 +1646,11 @@ export class Agent {
1423
1646
  if (!options?.history) {
1424
1647
  await this.session.addMessage("assistant", result.message);
1425
1648
  }
1426
- return result;
1649
+ // Ensure the result includes the current session
1650
+ return {
1651
+ ...result,
1652
+ session: result.session || this.session.current,
1653
+ };
1427
1654
  }
1428
1655
  }
1429
1656
  //# sourceMappingURL=Agent.js.map