@falai/agent 0.9.0-alpha-1 → 0.9.0

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 (217) hide show
  1. package/README.md +34 -22
  2. package/dist/cjs/src/core/Agent.d.ts +77 -59
  3. package/dist/cjs/src/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/src/core/Agent.js +284 -1060
  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/ResponseModal.d.ts +205 -0
  17. package/dist/cjs/src/core/ResponseModal.d.ts.map +1 -0
  18. package/dist/cjs/src/core/ResponseModal.js +1328 -0
  19. package/dist/cjs/src/core/ResponseModal.js.map +1 -0
  20. package/dist/cjs/src/core/ResponsePipeline.d.ts +66 -38
  21. package/dist/cjs/src/core/ResponsePipeline.d.ts.map +1 -1
  22. package/dist/cjs/src/core/ResponsePipeline.js +72 -4
  23. package/dist/cjs/src/core/ResponsePipeline.js.map +1 -1
  24. package/dist/cjs/src/core/Route.d.ts +24 -5
  25. package/dist/cjs/src/core/Route.d.ts.map +1 -1
  26. package/dist/cjs/src/core/Route.js +45 -1
  27. package/dist/cjs/src/core/Route.js.map +1 -1
  28. package/dist/cjs/src/core/RoutingEngine.d.ts +31 -6
  29. package/dist/cjs/src/core/RoutingEngine.d.ts.map +1 -1
  30. package/dist/cjs/src/core/RoutingEngine.js +113 -9
  31. package/dist/cjs/src/core/RoutingEngine.js.map +1 -1
  32. package/dist/cjs/src/core/SessionManager.d.ts +14 -4
  33. package/dist/cjs/src/core/SessionManager.d.ts.map +1 -1
  34. package/dist/cjs/src/core/SessionManager.js +25 -5
  35. package/dist/cjs/src/core/SessionManager.js.map +1 -1
  36. package/dist/cjs/src/core/Step.d.ts +10 -10
  37. package/dist/cjs/src/core/Step.d.ts.map +1 -1
  38. package/dist/cjs/src/core/Step.js.map +1 -1
  39. package/dist/cjs/src/core/ToolExecutor.d.ts +4 -2
  40. package/dist/cjs/src/core/ToolExecutor.d.ts.map +1 -1
  41. package/dist/cjs/src/core/ToolExecutor.js +13 -3
  42. package/dist/cjs/src/core/ToolExecutor.js.map +1 -1
  43. package/dist/cjs/src/index.d.ts +3 -1
  44. package/dist/cjs/src/index.d.ts.map +1 -1
  45. package/dist/cjs/src/index.js +7 -1
  46. package/dist/cjs/src/index.js.map +1 -1
  47. package/dist/cjs/src/types/agent.d.ts +42 -21
  48. package/dist/cjs/src/types/agent.d.ts.map +1 -1
  49. package/dist/cjs/src/types/agent.js.map +1 -1
  50. package/dist/cjs/src/types/ai.d.ts +1 -1
  51. package/dist/cjs/src/types/ai.d.ts.map +1 -1
  52. package/dist/cjs/src/types/index.d.ts +1 -1
  53. package/dist/cjs/src/types/index.d.ts.map +1 -1
  54. package/dist/cjs/src/types/index.js.map +1 -1
  55. package/dist/cjs/src/types/persistence.d.ts +0 -1
  56. package/dist/cjs/src/types/persistence.d.ts.map +1 -1
  57. package/dist/cjs/src/types/route.d.ts +22 -16
  58. package/dist/cjs/src/types/route.d.ts.map +1 -1
  59. package/dist/cjs/src/types/session.d.ts +6 -11
  60. package/dist/cjs/src/types/session.d.ts.map +1 -1
  61. package/dist/cjs/src/types/tool.d.ts +12 -6
  62. package/dist/cjs/src/types/tool.d.ts.map +1 -1
  63. package/dist/cjs/src/utils/clone.d.ts.map +1 -1
  64. package/dist/cjs/src/utils/clone.js +0 -4
  65. package/dist/cjs/src/utils/clone.js.map +1 -1
  66. package/dist/cjs/src/utils/history.d.ts +30 -1
  67. package/dist/cjs/src/utils/history.d.ts.map +1 -1
  68. package/dist/cjs/src/utils/history.js +169 -23
  69. package/dist/cjs/src/utils/history.js.map +1 -1
  70. package/dist/cjs/src/utils/index.d.ts +1 -1
  71. package/dist/cjs/src/utils/index.d.ts.map +1 -1
  72. package/dist/cjs/src/utils/index.js +5 -1
  73. package/dist/cjs/src/utils/index.js.map +1 -1
  74. package/dist/cjs/src/utils/session.d.ts +2 -2
  75. package/dist/cjs/src/utils/session.d.ts.map +1 -1
  76. package/dist/cjs/src/utils/session.js +6 -26
  77. package/dist/cjs/src/utils/session.js.map +1 -1
  78. package/dist/src/core/Agent.d.ts +77 -59
  79. package/dist/src/core/Agent.d.ts.map +1 -1
  80. package/dist/src/core/Agent.js +285 -1061
  81. package/dist/src/core/Agent.js.map +1 -1
  82. package/dist/src/core/PersistenceManager.d.ts.map +1 -1
  83. package/dist/src/core/PersistenceManager.js +48 -25
  84. package/dist/src/core/PersistenceManager.js.map +1 -1
  85. package/dist/src/core/PromptComposer.d.ts +1 -1
  86. package/dist/src/core/PromptComposer.d.ts.map +1 -1
  87. package/dist/src/core/PromptComposer.js.map +1 -1
  88. package/dist/src/core/ResponseEngine.d.ts +13 -12
  89. package/dist/src/core/ResponseEngine.d.ts.map +1 -1
  90. package/dist/src/core/ResponseEngine.js +4 -4
  91. package/dist/src/core/ResponseEngine.js.map +1 -1
  92. package/dist/src/core/ResponseModal.d.ts +205 -0
  93. package/dist/src/core/ResponseModal.d.ts.map +1 -0
  94. package/dist/src/core/ResponseModal.js +1323 -0
  95. package/dist/src/core/ResponseModal.js.map +1 -0
  96. package/dist/src/core/ResponsePipeline.d.ts +66 -38
  97. package/dist/src/core/ResponsePipeline.d.ts.map +1 -1
  98. package/dist/src/core/ResponsePipeline.js +72 -4
  99. package/dist/src/core/ResponsePipeline.js.map +1 -1
  100. package/dist/src/core/Route.d.ts +24 -5
  101. package/dist/src/core/Route.d.ts.map +1 -1
  102. package/dist/src/core/Route.js +45 -1
  103. package/dist/src/core/Route.js.map +1 -1
  104. package/dist/src/core/RoutingEngine.d.ts +31 -6
  105. package/dist/src/core/RoutingEngine.d.ts.map +1 -1
  106. package/dist/src/core/RoutingEngine.js +113 -9
  107. package/dist/src/core/RoutingEngine.js.map +1 -1
  108. package/dist/src/core/SessionManager.d.ts +14 -4
  109. package/dist/src/core/SessionManager.d.ts.map +1 -1
  110. package/dist/src/core/SessionManager.js +25 -5
  111. package/dist/src/core/SessionManager.js.map +1 -1
  112. package/dist/src/core/Step.d.ts +10 -10
  113. package/dist/src/core/Step.d.ts.map +1 -1
  114. package/dist/src/core/Step.js.map +1 -1
  115. package/dist/src/core/ToolExecutor.d.ts +4 -2
  116. package/dist/src/core/ToolExecutor.d.ts.map +1 -1
  117. package/dist/src/core/ToolExecutor.js +13 -3
  118. package/dist/src/core/ToolExecutor.js.map +1 -1
  119. package/dist/src/index.d.ts +3 -1
  120. package/dist/src/index.d.ts.map +1 -1
  121. package/dist/src/index.js +2 -1
  122. package/dist/src/index.js.map +1 -1
  123. package/dist/src/types/agent.d.ts +42 -21
  124. package/dist/src/types/agent.d.ts.map +1 -1
  125. package/dist/src/types/agent.js.map +1 -1
  126. package/dist/src/types/ai.d.ts +1 -1
  127. package/dist/src/types/ai.d.ts.map +1 -1
  128. package/dist/src/types/index.d.ts +1 -1
  129. package/dist/src/types/index.d.ts.map +1 -1
  130. package/dist/src/types/index.js.map +1 -1
  131. package/dist/src/types/persistence.d.ts +0 -1
  132. package/dist/src/types/persistence.d.ts.map +1 -1
  133. package/dist/src/types/route.d.ts +22 -16
  134. package/dist/src/types/route.d.ts.map +1 -1
  135. package/dist/src/types/session.d.ts +6 -11
  136. package/dist/src/types/session.d.ts.map +1 -1
  137. package/dist/src/types/tool.d.ts +12 -6
  138. package/dist/src/types/tool.d.ts.map +1 -1
  139. package/dist/src/utils/clone.d.ts.map +1 -1
  140. package/dist/src/utils/clone.js +0 -4
  141. package/dist/src/utils/clone.js.map +1 -1
  142. package/dist/src/utils/history.d.ts +30 -1
  143. package/dist/src/utils/history.d.ts.map +1 -1
  144. package/dist/src/utils/history.js +165 -23
  145. package/dist/src/utils/history.js.map +1 -1
  146. package/dist/src/utils/index.d.ts +1 -1
  147. package/dist/src/utils/index.d.ts.map +1 -1
  148. package/dist/src/utils/index.js +1 -1
  149. package/dist/src/utils/index.js.map +1 -1
  150. package/dist/src/utils/session.d.ts +2 -2
  151. package/dist/src/utils/session.d.ts.map +1 -1
  152. package/dist/src/utils/session.js +6 -26
  153. package/dist/src/utils/session.js.map +1 -1
  154. package/docs/README.md +5 -4
  155. package/docs/api/README.md +195 -4
  156. package/docs/api/overview.md +232 -13
  157. package/docs/core/agent/README.md +162 -17
  158. package/docs/core/agent/context-management.md +39 -15
  159. package/docs/core/agent/session-management.md +49 -16
  160. package/docs/core/ai-integration/prompt-composition.md +38 -14
  161. package/docs/core/ai-integration/response-processing.md +28 -17
  162. package/docs/core/conversation-flows/data-collection.md +103 -25
  163. package/docs/core/conversation-flows/route-dsl.md +45 -22
  164. package/docs/core/conversation-flows/routes.md +74 -18
  165. package/docs/core/conversation-flows/step-transitions.md +3 -3
  166. package/docs/core/conversation-flows/steps.md +39 -15
  167. package/docs/core/routing/intelligent-routing.md +18 -9
  168. package/docs/core/tools/tool-definition.md +8 -8
  169. package/docs/core/tools/tool-execution.md +26 -26
  170. package/docs/core/tools/tool-scoping.md +5 -5
  171. package/docs/guides/getting-started/README.md +54 -32
  172. package/docs/guides/migration/README.md +72 -0
  173. package/docs/guides/migration/response-modal-refactor.md +518 -0
  174. package/examples/advanced-patterns/knowledge-based-agent.ts +37 -28
  175. package/examples/advanced-patterns/persistent-onboarding.ts +70 -41
  176. package/examples/advanced-patterns/route-lifecycle-hooks.ts +28 -2
  177. package/examples/advanced-patterns/streaming-responses.ts +197 -119
  178. package/examples/ai-providers/anthropic-integration.ts +40 -33
  179. package/examples/ai-providers/openai-integration.ts +25 -25
  180. package/examples/conversation-flows/completion-transitions.ts +36 -32
  181. package/examples/core-concepts/basic-agent.ts +76 -78
  182. package/examples/core-concepts/modern-streaming-api.ts +309 -0
  183. package/examples/core-concepts/schema-driven-extraction.ts +20 -16
  184. package/examples/core-concepts/session-management.ts +65 -53
  185. package/examples/integrations/database-integration.ts +49 -34
  186. package/examples/integrations/healthcare-integration.ts +96 -91
  187. package/examples/integrations/search-integration.ts +79 -82
  188. package/examples/integrations/server-session-management.ts +25 -17
  189. package/examples/persistence/database-persistence.ts +61 -45
  190. package/examples/persistence/memory-sessions.ts +52 -63
  191. package/examples/persistence/redis-persistence.ts +81 -95
  192. package/examples/tools/basic-tools.ts +73 -62
  193. package/examples/tools/data-enrichment-tools.ts +52 -44
  194. package/package.json +1 -1
  195. package/src/core/Agent.ts +396 -1499
  196. package/src/core/PersistenceManager.ts +51 -27
  197. package/src/core/PromptComposer.ts +1 -1
  198. package/src/core/ResponseEngine.ts +21 -19
  199. package/src/core/ResponseModal.ts +1722 -0
  200. package/src/core/ResponsePipeline.ts +175 -60
  201. package/src/core/Route.ts +58 -6
  202. package/src/core/RoutingEngine.ts +174 -27
  203. package/src/core/SessionManager.ts +32 -8
  204. package/src/core/Step.ts +20 -12
  205. package/src/core/ToolExecutor.ts +19 -5
  206. package/src/index.ts +11 -0
  207. package/src/types/agent.ts +47 -23
  208. package/src/types/ai.ts +1 -1
  209. package/src/types/index.ts +2 -0
  210. package/src/types/persistence.ts +0 -1
  211. package/src/types/route.ts +22 -16
  212. package/src/types/session.ts +6 -12
  213. package/src/types/tool.ts +15 -9
  214. package/src/utils/clone.ts +6 -8
  215. package/src/utils/history.ts +190 -27
  216. package/src/utils/index.ts +4 -0
  217. package/src/utils/session.ts +6 -31
@@ -4,29 +4,47 @@
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Agent = void 0;
7
- const history_1 = require("../types/history");
8
7
  const utils_1 = require("../utils");
9
8
  const Route_1 = require("./Route");
10
- const Step_1 = require("./Step");
11
9
  const PersistenceManager_1 = require("./PersistenceManager");
12
10
  const SessionManager_1 = require("./SessionManager");
13
11
  const RoutingEngine_1 = require("./RoutingEngine");
14
- const ResponseEngine_1 = require("./ResponseEngine");
15
12
  const ToolExecutor_1 = require("./ToolExecutor");
16
- const ResponsePipeline_1 = require("./ResponsePipeline");
17
- const constants_1 = require("../constants");
13
+ const ResponseModal_1 = require("./ResponseModal");
18
14
  /**
19
- * Main Agent class with generic context support
15
+ * Error thrown when data validation fails
20
16
  */
17
+ class DataValidationError extends Error {
18
+ constructor(errors, message) {
19
+ super(message || "Data validation failed");
20
+ this.errors = errors;
21
+ this.name = "DataValidationError";
22
+ }
23
+ }
24
+ /**
25
+ * Error thrown when route configuration is invalid
26
+ */
27
+ class RouteConfigurationError extends Error {
28
+ constructor(routeTitle, invalidFields, message) {
29
+ super(message || `Route configuration error in '${routeTitle}'`);
30
+ this.routeTitle = routeTitle;
31
+ this.invalidFields = invalidFields;
32
+ this.name = "RouteConfigurationError";
33
+ }
34
+ }
35
+ /**
36
+ * Main Agent class with generic context and data support
37
+ */
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
39
  class Agent {
22
40
  constructor(options) {
23
41
  this.options = options;
24
42
  this.terms = [];
25
43
  this.guidelines = [];
26
44
  this.tools = [];
27
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
45
  this.routes = [];
29
46
  this.knowledgeBase = {};
47
+ this.collectedData = {};
30
48
  // Set log level based on debug option
31
49
  if (options.debug) {
32
50
  utils_1.logger.setLevel(utils_1.LoggerLevel.DEBUG);
@@ -35,26 +53,60 @@ class Agent {
35
53
  if (options.context !== undefined && options.contextProvider) {
36
54
  throw new Error("Cannot provide both 'context' and 'contextProvider'. Choose one.");
37
55
  }
56
+ // Initialize and validate agent-level schema if provided
57
+ if (options.schema) {
58
+ this.schema = options.schema;
59
+ this.validateSchema(this.schema);
60
+ utils_1.logger.debug("[Agent] Agent-level schema initialized and validated");
61
+ }
38
62
  // Initialize context if provided
39
63
  this.context = options.context;
64
+ // Initialize collected data with initial data if provided
65
+ if (options.initialData) {
66
+ if (this.schema) {
67
+ const validation = this.validateData(options.initialData);
68
+ if (!validation.valid) {
69
+ throw new Error(`Initial data validation failed: ${validation.errors.map(e => e.message).join(', ')}`);
70
+ }
71
+ }
72
+ this.collectedData = { ...options.initialData };
73
+ utils_1.logger.debug("[Agent] Initial data set:", this.collectedData);
74
+ }
40
75
  // Initialize current session if provided
41
76
  this.currentSession = options.session;
42
- // Initialize routing and response engines
77
+ // Initialize routing engine
43
78
  this.routingEngine = new RoutingEngine_1.RoutingEngine({
44
79
  maxCandidates: 5,
45
80
  allowRouteSwitch: true,
46
81
  switchThreshold: 70,
47
82
  });
48
- 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));
83
+ // Initialize ResponseModal for handling all response generation
84
+ this.responseModal = new ResponseModal_1.ResponseModal(this);
50
85
  // Initialize persistence if configured
51
86
  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
- });
87
+ try {
88
+ // Validate persistence configuration
89
+ if (!options.persistence.adapter) {
90
+ throw new Error("Persistence adapter is required when persistence is configured");
91
+ }
92
+ if (!options.persistence.adapter.sessionRepository) {
93
+ throw new Error("Persistence adapter must provide a sessionRepository");
94
+ }
95
+ if (!options.persistence.adapter.messageRepository) {
96
+ throw new Error("Persistence adapter must provide a messageRepository");
97
+ }
98
+ this.persistenceManager = new PersistenceManager_1.PersistenceManager(options.persistence);
99
+ // Initialize the adapter if it has an initialize method
100
+ if (options.persistence.adapter.initialize) {
101
+ options.persistence.adapter.initialize().catch((error) => {
102
+ utils_1.logger.error("[Agent] Persistence adapter initialization failed:", error instanceof Error ? error.message : String(error));
103
+ });
104
+ }
105
+ }
106
+ catch (error) {
107
+ const errorMessage = error instanceof Error ? error.message : String(error);
108
+ utils_1.logger.error("[Agent] Failed to initialize persistence:", errorMessage);
109
+ throw new Error(`Failed to initialize persistence: ${errorMessage}`);
58
110
  }
59
111
  }
60
112
  // Initialize from options - use create methods for consistency
@@ -92,6 +144,116 @@ class Agent {
92
144
  });
93
145
  }
94
146
  }
147
+ /**
148
+ * Validate the agent-level schema structure
149
+ * @private
150
+ */
151
+ validateSchema(schema) {
152
+ if (!schema || typeof schema !== 'object') {
153
+ throw new Error("Agent schema must be a valid JSON Schema object. " +
154
+ "Provide a schema with 'type': 'object' and 'properties' to define the data structure.");
155
+ }
156
+ if (schema.type !== 'object') {
157
+ throw new Error(`Agent schema must be of type 'object', but received '${String(schema.type)}'. ` +
158
+ "Agent-level schemas must define object structures for data collection.");
159
+ }
160
+ if (!schema.properties || typeof schema.properties !== 'object') {
161
+ throw new Error("Agent schema must have a 'properties' field defining the data fields. " +
162
+ "Example: { type: 'object', properties: { name: { type: 'string' }, email: { type: 'string' } } }");
163
+ }
164
+ utils_1.logger.debug("[Agent] Schema validation passed");
165
+ }
166
+ /**
167
+ * Validate data against the agent-level schema
168
+ */
169
+ validateData(data) {
170
+ if (!this.schema) {
171
+ // No schema defined, consider all data valid
172
+ return { valid: true, errors: [], warnings: [] };
173
+ }
174
+ const errors = [];
175
+ const warnings = [];
176
+ // Basic validation - check if provided fields exist in schema
177
+ if (this.schema.properties) {
178
+ for (const [key, value] of Object.entries(data)) {
179
+ if (!(key in this.schema.properties)) {
180
+ errors.push({
181
+ field: key,
182
+ value,
183
+ message: `Field '${key}' is not defined in agent schema`,
184
+ schemaPath: `properties.${key}`
185
+ });
186
+ }
187
+ }
188
+ }
189
+ // Check required fields if specified
190
+ if (this.schema.required && Array.isArray(this.schema.required)) {
191
+ for (const requiredField of this.schema.required) {
192
+ if (!(requiredField in data) || data[requiredField] === undefined) {
193
+ warnings.push({
194
+ field: requiredField,
195
+ value: undefined,
196
+ message: `Required field '${requiredField}' is missing`,
197
+ schemaPath: `required`
198
+ });
199
+ }
200
+ }
201
+ }
202
+ return {
203
+ valid: errors.length === 0,
204
+ errors,
205
+ warnings
206
+ };
207
+ }
208
+ /**
209
+ * Check if a field is valid according to the agent schema
210
+ * @param field - The field key to validate
211
+ * @returns true if field exists in schema or no schema is defined, false otherwise
212
+ */
213
+ isValidSchemaField(field) {
214
+ if (!this.schema || !this.schema.properties) {
215
+ // No schema defined, consider all fields valid
216
+ return true;
217
+ }
218
+ return field in this.schema.properties;
219
+ }
220
+ /**
221
+ * Get the current collected data
222
+ */
223
+ getCollectedData() {
224
+ return { ...this.collectedData };
225
+ }
226
+ /**
227
+ * Update collected data with validation
228
+ */
229
+ async updateCollectedData(updates) {
230
+ // Validate the updates
231
+ const validation = this.validateData(updates);
232
+ if (!validation.valid) {
233
+ const errorMessages = validation.errors.map(e => e.message).join(', ');
234
+ throw new DataValidationError(validation.errors, `Data validation failed: ${errorMessages}`);
235
+ }
236
+ // Log warnings if any
237
+ if (validation.warnings.length > 0) {
238
+ const warningMessages = validation.warnings.map(w => w.message).join(', ');
239
+ utils_1.logger.warn(`[Agent] Data validation warnings: ${warningMessages}`);
240
+ }
241
+ // Merge updates with current data
242
+ const previousData = { ...this.collectedData };
243
+ this.collectedData = {
244
+ ...this.collectedData,
245
+ ...updates
246
+ };
247
+ // Trigger agent-level lifecycle hook if configured
248
+ if (this.options.hooks?.onDataUpdate) {
249
+ this.collectedData = await this.options.hooks.onDataUpdate(this.collectedData, previousData);
250
+ }
251
+ // Update current session if it exists to keep it in sync
252
+ if (this.currentSession) {
253
+ this.currentSession = (0, utils_1.mergeCollected)(this.currentSession, this.collectedData);
254
+ }
255
+ utils_1.logger.debug("[Agent] Collected data updated:", updates);
256
+ }
95
257
  /**
96
258
  * Get agent name
97
259
  */
@@ -117,10 +279,25 @@ class Agent {
117
279
  return this.options.identity;
118
280
  }
119
281
  /**
120
- * Create a new route (journey)
121
- * @template TData - Type of data collected throughout the route
282
+ * Create a new route (journey) using agent-level data type
122
283
  */
123
284
  createRoute(options) {
285
+ // Validate that requiredFields exist in agent schema
286
+ if (options.requiredFields && this.schema?.properties) {
287
+ const invalidRequiredFields = options.requiredFields.filter(field => !(String(field) in this.schema.properties));
288
+ if (invalidRequiredFields.length > 0) {
289
+ throw new RouteConfigurationError(options.title, invalidRequiredFields.map(f => String(f)), `Invalid required fields in route '${options.title}': ${invalidRequiredFields.join(', ')}. ` +
290
+ `Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`);
291
+ }
292
+ }
293
+ // Validate that optionalFields exist in agent schema
294
+ if (options.optionalFields && this.schema?.properties) {
295
+ const invalidOptionalFields = options.optionalFields.filter(field => !(String(field) in this.schema.properties));
296
+ if (invalidOptionalFields.length > 0) {
297
+ throw new RouteConfigurationError(options.title, invalidOptionalFields.map(f => String(f)), `Invalid optional fields in route '${options.title}': ${invalidOptionalFields.join(', ')}. ` +
298
+ `Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`);
299
+ }
300
+ }
124
301
  const route = new Route_1.Route(options);
125
302
  this.routes.push(route);
126
303
  return route;
@@ -205,6 +382,8 @@ class Agent {
205
382
  if (this.options.hooks?.onDataUpdate) {
206
383
  newCollected = (await this.options.hooks.onDataUpdate(newCollected, previousCollected));
207
384
  }
385
+ // Update agent's collected data to stay in sync
386
+ this.collectedData = { ...newCollected };
208
387
  // Return updated session
209
388
  return (0, utils_1.mergeCollected)(session, newCollected);
210
389
  }
@@ -219,894 +398,25 @@ class Agent {
219
398
  // Otherwise return the stored context
220
399
  return this.context;
221
400
  }
401
+ /**
402
+ * Get current schema
403
+ */
404
+ getSchema() {
405
+ return this.schema;
406
+ }
222
407
  /**
223
408
  * Generate a response based on history and context as a stream
224
409
  */
225
410
  async *respondStream(params) {
226
- const { history: simpleHistory, signal } = params;
227
- const history = (0, utils_1.normalizeHistory)(simpleHistory);
228
- // Prepare context and session using the response pipeline
229
- this.responsePipeline.setContext(this.context);
230
- this.responsePipeline.setCurrentSession(this.currentSession);
231
- let session;
232
- const responseContext = await this.responsePipeline.prepareResponseContext({
233
- contextOverride: params.contextOverride,
234
- session: params.session ? (0, utils_1.cloneDeep)(params.session) : undefined,
235
- });
236
- const { effectiveContext } = responseContext;
237
- session = responseContext.session;
238
- // Update our stored context if it was modified by beforeRespond hook
239
- this.context = this.responsePipeline.getStoredContext();
240
- // PHASE 1: PREPARE - Execute prepare function if current step has one
241
- if (session.currentRoute && session.currentStep) {
242
- const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
243
- if (currentRoute) {
244
- const currentStep = currentRoute.getStep(session.currentStep.id);
245
- if (currentStep?.prepare) {
246
- utils_1.logger.debug(`[Agent] Executing prepare for step: ${currentStep.id}`);
247
- await this.executePrepareFinalize(currentStep.prepare, effectiveContext, session.data, currentRoute, currentStep);
248
- }
249
- }
250
- }
251
- // PHASE 2: ROUTING + STEP SELECTION - Use response pipeline
252
- const routingResult = await this.responsePipeline.handleRoutingAndStepSelection({
253
- session,
254
- history,
255
- context: effectiveContext,
256
- signal,
257
- });
258
- const selectedRoute = routingResult.selectedRoute;
259
- const selectedStep = routingResult.selectedStep;
260
- const responseDirectives = routingResult.responseDirectives;
261
- const isRouteComplete = routingResult.isRouteComplete;
262
- session = routingResult.session;
263
- // PHASE 3: DETERMINE NEXT STEP - Use pipeline method
264
- const stepResult = this.responsePipeline.determineNextStep({
265
- selectedRoute,
266
- selectedStep,
267
- session,
268
- isRouteComplete,
269
- });
270
- const nextStep = stepResult.nextStep;
271
- session = stepResult.session;
272
- if (selectedRoute && !isRouteComplete) {
273
- // PHASE 4: RESPONSE GENERATION - Stream message using selected route and step
274
- // Get last user message
275
- const lastUserMessage = (0, utils_1.getLastMessageFromHistory)(history);
276
- // Build response schema for this route (with collect fields from step)
277
- const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep);
278
- // Check if selected route and next step are defined
279
- if (!selectedRoute || !nextStep) {
280
- utils_1.logger.error("[Agent] Selected route or next step is not defined", {
281
- selectedRoute,
282
- nextStep,
283
- });
284
- throw new Error("Selected route or next step is not defined");
285
- }
286
- // Build response prompt
287
- const responsePrompt = await this.responseEngine.buildResponsePrompt({
288
- route: selectedRoute,
289
- currentStep: nextStep,
290
- rules: selectedRoute.getRules(),
291
- prohibitions: selectedRoute.getProhibitions(),
292
- directives: responseDirectives,
293
- history,
294
- lastMessage: lastUserMessage,
295
- agentOptions: this.options,
296
- // Combine agent and route properties according to the specified logic
297
- combinedGuidelines: [
298
- ...this.getGuidelines(),
299
- ...selectedRoute.getGuidelines(),
300
- ],
301
- combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
302
- context: effectiveContext,
303
- session,
304
- });
305
- // Collect available tools for AI
306
- const availableTools = this.collectAvailableTools(selectedRoute, nextStep);
307
- // Generate message stream using AI provider
308
- const stream = this.options.provider.generateMessageStream({
309
- prompt: responsePrompt,
310
- history,
311
- context: effectiveContext,
312
- tools: availableTools,
313
- signal,
314
- parameters: {
315
- jsonSchema: responseSchema,
316
- schemaName: "response_stream_output",
317
- },
318
- });
319
- // Stream chunks to caller
320
- for await (const chunk of stream) {
321
- let toolCalls = undefined;
322
- // Extract tool calls from AI response on final chunk
323
- if (chunk.done && chunk.structured?.toolCalls) {
324
- toolCalls = chunk.structured.toolCalls;
325
- // Execute dynamic tool calls
326
- if (toolCalls.length > 0) {
327
- utils_1.logger.debug(`[Agent] Executing ${toolCalls.length} dynamic tool calls`);
328
- for (const toolCall of toolCalls) {
329
- const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
330
- if (!tool) {
331
- utils_1.logger.warn(`[Agent] Tool not found: ${toolCall.toolName}`);
332
- continue;
333
- }
334
- const toolExecutor = new ToolExecutor_1.ToolExecutor();
335
- const result = await toolExecutor.executeTool({
336
- tool: tool,
337
- context: effectiveContext,
338
- updateContext: this.updateContext.bind(this),
339
- history,
340
- data: session.data,
341
- toolArguments: toolCall.arguments,
342
- });
343
- // Update context with tool results
344
- if (result.contextUpdate) {
345
- await this.updateContext(result.contextUpdate);
346
- }
347
- // Update collected data with tool results
348
- if (result.dataUpdate) {
349
- session = await this.updateData(session, result.dataUpdate);
350
- utils_1.logger.debug(`[Agent] Tool updated collected data:`, result.dataUpdate);
351
- }
352
- utils_1.logger.debug(`[Agent] Executed dynamic tool: ${result.toolName} (success: ${result.success})`);
353
- }
354
- }
355
- }
356
- // TOOL LOOP: Allow AI to make follow-up tool calls after initial tool execution (streaming)
357
- const MAX_TOOL_LOOPS = 5;
358
- let toolLoopCount = 0;
359
- let hasToolCalls = toolCalls && toolCalls.length > 0;
360
- while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
361
- toolLoopCount++;
362
- utils_1.logger.debug(`[Agent] Starting streaming tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS}`);
363
- // Add tool execution results to history so AI knows what happened
364
- const toolResultsEvents = [];
365
- for (const toolCall of toolCalls || []) {
366
- const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
367
- if (tool) {
368
- toolResultsEvents.push({
369
- kind: history_1.EventKind.TOOL,
370
- source: history_1.MessageRole.AGENT,
371
- timestamp: new Date().toISOString(),
372
- data: {
373
- tool_calls: [
374
- {
375
- tool_id: toolCall.toolName,
376
- arguments: toolCall.arguments,
377
- result: {
378
- data: "Tool executed successfully",
379
- },
380
- },
381
- ],
382
- },
383
- });
384
- }
385
- }
386
- // Create updated history with tool results
387
- const updatedHistory = [...history, ...toolResultsEvents];
388
- // Make follow-up streaming AI call to see if more tools are needed
389
- const followUpStream = this.options.provider.generateMessageStream({
390
- prompt: responsePrompt,
391
- history: updatedHistory,
392
- context: effectiveContext,
393
- tools: availableTools,
394
- parameters: {
395
- jsonSchema: responseSchema,
396
- schemaName: "tool_followup",
397
- },
398
- signal,
399
- });
400
- let followUpToolCalls;
401
- for await (const followUpChunk of followUpStream) {
402
- // Extract tool calls from follow-up stream
403
- if (followUpChunk.done && followUpChunk.structured?.toolCalls) {
404
- followUpToolCalls = followUpChunk.structured.toolCalls;
405
- }
406
- }
407
- hasToolCalls = followUpToolCalls && followUpToolCalls.length > 0;
408
- if (hasToolCalls) {
409
- utils_1.logger.debug(`[Agent] Follow-up streaming call produced ${followUpToolCalls.length} additional tool calls`);
410
- // Execute the follow-up tool calls
411
- for (const toolCall of followUpToolCalls) {
412
- const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
413
- if (!tool) {
414
- utils_1.logger.warn(`[Agent] Tool not found in streaming follow-up: ${toolCall.toolName}`);
415
- continue;
416
- }
417
- const toolExecutor = new ToolExecutor_1.ToolExecutor();
418
- const result = await toolExecutor.executeTool({
419
- tool: tool,
420
- context: effectiveContext,
421
- updateContext: this.updateContext.bind(this),
422
- history: updatedHistory,
423
- data: session.data,
424
- toolArguments: toolCall.arguments,
425
- });
426
- // Update context with follow-up tool results
427
- if (result.contextUpdate) {
428
- await this.updateContext(result.contextUpdate);
429
- }
430
- if (result.dataUpdate) {
431
- session = await this.updateData(session, result.dataUpdate);
432
- utils_1.logger.debug(`[Agent] Streaming follow-up tool updated collected data:`, result.dataUpdate);
433
- }
434
- utils_1.logger.debug(`[Agent] Executed streaming follow-up tool: ${result.toolName} (success: ${result.success})`);
435
- }
436
- // Update toolCalls for next iteration
437
- toolCalls = followUpToolCalls;
438
- }
439
- else {
440
- utils_1.logger.debug(`[Agent] Streaming tool loop completed after ${toolLoopCount} iterations`);
441
- // Update toolCalls for final response
442
- toolCalls = followUpToolCalls || [];
443
- break;
444
- }
445
- }
446
- if (toolLoopCount >= MAX_TOOL_LOOPS) {
447
- utils_1.logger.warn(`[Agent] Streaming tool loop limit reached (${MAX_TOOL_LOOPS}), stopping`);
448
- }
449
- // Extract collected data on final chunk
450
- if (chunk.done && chunk.structured && nextStep.collect) {
451
- const collectedData = {};
452
- // The structured response includes both base fields and collected extraction fields
453
- const structuredData = chunk.structured;
454
- for (const field of nextStep.collect) {
455
- if (field in structuredData) {
456
- collectedData[field] = structuredData[field];
457
- }
458
- }
459
- // Merge collected data into session
460
- if (Object.keys(collectedData).length > 0) {
461
- session = await this.updateData(session, collectedData);
462
- utils_1.logger.debug(`[Agent] Collected data:`, collectedData);
463
- }
464
- }
465
- // Extract any additional data from structured response on final chunk
466
- if (chunk.done &&
467
- chunk.structured &&
468
- typeof chunk.structured === "object" &&
469
- "contextUpdate" in chunk.structured) {
470
- await this.updateContext(chunk.structured
471
- .contextUpdate);
472
- }
473
- // Auto-save session step on final chunk
474
- if (chunk.done &&
475
- this.persistenceManager &&
476
- session.id &&
477
- this.options.persistence?.autoSave !== false) {
478
- await this.persistenceManager.saveSessionState(session.id, session);
479
- utils_1.logger.debug(`[Agent] Auto-saved session step to persistence: ${session.id}`);
480
- }
481
- // Execute finalize function on final chunk
482
- if (chunk.done && session.currentRoute && session.currentStep) {
483
- const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
484
- if (currentRoute) {
485
- const currentStep = currentRoute.getStep(session.currentStep.id);
486
- if (currentStep?.finalize) {
487
- utils_1.logger.debug(`[Agent] Executing finalize for step: ${currentStep.id}`);
488
- await this.executePrepareFinalize(currentStep.finalize, effectiveContext, session.data, currentRoute, currentStep);
489
- }
490
- }
491
- }
492
- // Update current session if we have one
493
- if (chunk.done && this.currentSession) {
494
- this.currentSession = session;
495
- }
496
- yield {
497
- delta: chunk.delta,
498
- accumulated: chunk.accumulated,
499
- done: chunk.done,
500
- session, // Return updated session
501
- toolCalls,
502
- isRouteComplete,
503
- metadata: chunk.metadata,
504
- structured: chunk.structured,
505
- };
506
- }
507
- }
508
- else if (isRouteComplete && selectedRoute) {
509
- // Route is complete - generate completion message then check for onComplete transition
510
- const lastUserMessage = (0, utils_1.getLastMessageFromHistory)(history);
511
- // Get endStep spec from route
512
- const endStepSpec = selectedRoute.endStepSpec;
513
- // Create a temporary step for completion message generation using endStep configuration
514
- const completionStep = new Step_1.Step(selectedRoute.id, {
515
- description: endStepSpec.description,
516
- id: endStepSpec.id || constants_1.END_ROUTE_ID,
517
- collect: endStepSpec.collect,
518
- requires: endStepSpec.requires,
519
- prompt: endStepSpec.prompt ||
520
- "Summarize what was accomplished and confirm completion based on the conversation history and collected data",
521
- });
522
- // Build response schema for completion
523
- const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep);
524
- const templateContext = {
525
- context: effectiveContext,
526
- session,
527
- history,
528
- };
529
- // Build completion response prompt
530
- const completionPrompt = await this.responseEngine.buildResponsePrompt({
531
- route: selectedRoute,
532
- currentStep: completionStep,
533
- rules: selectedRoute.getRules(),
534
- prohibitions: selectedRoute.getProhibitions(),
535
- directives: undefined, // No directives for completion
536
- history,
537
- lastMessage: lastUserMessage,
538
- agentOptions: this.options,
539
- // Combine agent and route properties according to the specified logic
540
- combinedGuidelines: [
541
- ...this.getGuidelines(),
542
- ...selectedRoute.getGuidelines(),
543
- ],
544
- combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
545
- context: effectiveContext,
546
- session,
547
- });
548
- // Stream completion message using AI provider
549
- const stream = this.options.provider.generateMessageStream({
550
- prompt: completionPrompt,
551
- history,
552
- context: effectiveContext,
553
- signal,
554
- parameters: {
555
- jsonSchema: responseSchema,
556
- schemaName: "completion_message_stream",
557
- },
558
- });
559
- utils_1.logger.debug(`[Agent] Streaming completion message for route: ${selectedRoute.title}`);
560
- // Check for onComplete transition
561
- const transitionConfig = await selectedRoute.evaluateOnComplete({ data: session.data }, effectiveContext);
562
- if (transitionConfig) {
563
- // Find target route by ID or title
564
- const targetRoute = this.routes.find((r) => r.id === transitionConfig.nextStep ||
565
- r.title === transitionConfig.nextStep);
566
- if (targetRoute) {
567
- const renderedCondition = await (0, utils_1.render)(transitionConfig.condition, templateContext);
568
- // Set pending transition in session
569
- session = {
570
- ...session,
571
- pendingTransition: {
572
- targetRouteId: targetRoute.id,
573
- condition: renderedCondition,
574
- reason: "route_complete",
575
- },
576
- };
577
- utils_1.logger.debug(`[Agent] Route ${selectedRoute.title} completed with pending transition to: ${targetRoute.title}`);
578
- }
579
- else {
580
- utils_1.logger.warn(`[Agent] Route ${selectedRoute.title} completed but target route not found: ${transitionConfig.nextStep}`);
581
- }
582
- }
583
- // Set step to END_ROUTE marker
584
- session = (0, utils_1.enterStep)(session, constants_1.END_ROUTE_ID, "Route completed");
585
- utils_1.logger.debug(`[Agent] Route ${selectedRoute.title} completed. Entered END_ROUTE step.`);
586
- // Stream completion chunks
587
- for await (const chunk of stream) {
588
- // Update current session if we have one
589
- if (chunk.done && this.currentSession) {
590
- this.currentSession = session;
591
- }
592
- yield {
593
- delta: chunk.delta,
594
- accumulated: chunk.accumulated,
595
- done: chunk.done,
596
- session,
597
- toolCalls: undefined,
598
- isRouteComplete: true,
599
- metadata: chunk.metadata,
600
- structured: chunk.structured,
601
- };
602
- }
603
- }
604
- else {
605
- // Fallback: No routes defined, stream a simple response
606
- const fallbackPrompt = await this.responseEngine.buildFallbackPrompt({
607
- history,
608
- agentOptions: this.options,
609
- terms: this.terms,
610
- guidelines: this.guidelines,
611
- context: effectiveContext,
612
- session,
613
- });
614
- const stream = this.options.provider.generateMessageStream({
615
- prompt: fallbackPrompt,
616
- history,
617
- context: effectiveContext,
618
- signal,
619
- parameters: {
620
- jsonSchema: {
621
- type: "object",
622
- properties: {
623
- message: { type: "string" },
624
- },
625
- required: ["message"],
626
- additionalProperties: false,
627
- },
628
- schemaName: "fallback_stream_response",
629
- },
630
- });
631
- for await (const chunk of stream) {
632
- // Update current session if we have one
633
- if (chunk.done && this.currentSession) {
634
- this.currentSession = session;
635
- }
636
- yield {
637
- delta: chunk.delta,
638
- accumulated: chunk.accumulated,
639
- done: chunk.done,
640
- session, // Return updated session
641
- toolCalls: undefined,
642
- isRouteComplete: false,
643
- metadata: chunk.metadata,
644
- structured: chunk.structured,
645
- };
646
- }
647
- }
411
+ // Delegate to ResponseModal
412
+ yield* this.responseModal.respondStream(params);
648
413
  }
649
414
  /**
650
415
  * Generate a response based on history and context
651
416
  */
652
417
  async respond(params) {
653
- const { history: simpleHistory, contextOverride, signal } = params;
654
- const history = (0, utils_1.normalizeHistory)(simpleHistory);
655
- // Get current context (may fetch from provider)
656
- let currentContext = await this.getContext();
657
- // Call beforeRespond hook if configured
658
- if (this.options.hooks?.beforeRespond && currentContext !== undefined) {
659
- currentContext = await this.options.hooks.beforeRespond(currentContext);
660
- // Update stored context with the result from beforeRespond
661
- this.context = currentContext;
662
- }
663
- // Merge context with override
664
- const effectiveContext = {
665
- ...currentContext,
666
- ...contextOverride,
667
- };
668
- // Initialize or get session (use current session if available)
669
- let session = (0, utils_1.cloneDeep)(params.session) ||
670
- (0, utils_1.cloneDeep)(this.currentSession) ||
671
- (await this.session.getOrCreate());
672
- // PHASE 1: PREPARE - Execute prepare function if current step has one
673
- if (session.currentRoute && session.currentStep) {
674
- const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
675
- if (currentRoute) {
676
- const currentStep = currentRoute.getStep(session.currentStep.id);
677
- if (currentStep?.prepare) {
678
- utils_1.logger.debug(`[Agent] Executing prepare for step: ${currentStep.id}`);
679
- await this.executePrepareFinalize(currentStep.prepare, effectiveContext, session.data, currentRoute, currentStep);
680
- }
681
- }
682
- }
683
- // PHASE 2: ROUTING + STEP SELECTION - Determine which route and step to use (combined)
684
- let selectedRoute;
685
- let responseDirectives;
686
- let selectedStep;
687
- let isRouteComplete = false;
688
- // Check for pending transition from previous route completion
689
- if (session.pendingTransition) {
690
- const targetRoute = this.routes.find((r) => r.id === session.pendingTransition?.targetRouteId);
691
- if (targetRoute) {
692
- utils_1.logger.debug(`[Agent] Auto-transitioning from pending transition to route: ${targetRoute.title}`);
693
- // Clear pending transition and enter new route
694
- session = {
695
- ...session,
696
- pendingTransition: undefined,
697
- };
698
- session = (0, utils_1.enterRoute)(session, targetRoute.id, targetRoute.title);
699
- // Merge initial data if available
700
- if (targetRoute.initialData) {
701
- session = (0, utils_1.mergeCollected)(session, targetRoute.initialData);
702
- }
703
- selectedRoute = targetRoute;
704
- }
705
- else {
706
- utils_1.logger.warn(`[Agent] Pending transition target route not found: ${session.pendingTransition.targetRouteId}`);
707
- // Clear invalid transition
708
- session = {
709
- ...session,
710
- pendingTransition: undefined,
711
- };
712
- }
713
- }
714
- // If no pending transition or transition handled, do normal routing
715
- if (this.routes.length > 0 && !selectedRoute) {
716
- const orchestration = await this.routingEngine.decideRouteAndStep({
717
- routes: this.routes,
718
- session,
719
- history,
720
- agentOptions: this.options,
721
- provider: this.options.provider,
722
- context: effectiveContext,
723
- signal,
724
- });
725
- selectedRoute = orchestration.selectedRoute;
726
- selectedStep = orchestration.selectedStep;
727
- responseDirectives = orchestration.responseDirectives;
728
- session = orchestration.session;
729
- isRouteComplete = orchestration.isRouteComplete || false;
730
- // Log if route is complete
731
- if (isRouteComplete) {
732
- utils_1.logger.debug(`[Agent] Route complete: all required data collected, END_ROUTE reached`);
733
- }
734
- }
735
- // PHASE 3: DETERMINE NEXT STEP - Use step from combined decision or get initial step
736
- let message;
737
- let toolCalls = undefined;
738
- let responsePrompt;
739
- let availableTools = [];
740
- let responseSchema;
741
- let nextStep;
742
- // Get last user message (needed for both route and completion handling)
743
- const lastUserMessage = (0, utils_1.getLastMessageFromHistory)(history);
744
- if (selectedRoute && !isRouteComplete) {
745
- // If we have a selected step from the combined routing decision, use it
746
- if (selectedStep) {
747
- nextStep = selectedStep;
748
- }
749
- else {
750
- // New route or no step selected - get initial step or first valid step
751
- const candidates = this.routingEngine.getCandidateSteps(selectedRoute, undefined, session.data || {});
752
- if (candidates.length > 0) {
753
- nextStep = candidates[0].step;
754
- utils_1.logger.debug(`[Agent] Using first valid step: ${nextStep.id} for new route`);
755
- }
756
- else {
757
- // Fallback to initial step even if it should be skipped
758
- nextStep = selectedRoute.initialStep;
759
- utils_1.logger.warn(`[Agent] No valid steps found, using initial step: ${nextStep.id}`);
760
- }
761
- }
762
- // Update session with next step
763
- session = (0, utils_1.enterStep)(session, nextStep.id, nextStep.description);
764
- utils_1.logger.debug(`[Agent] Entered step: ${nextStep.id}`);
765
- // PHASE 4: RESPONSE GENERATION - Generate message using selected route and step
766
- // Get last user message
767
- const lastUserMessage = (0, utils_1.getLastMessageFromHistory)(history);
768
- // Build response schema for this route (with collect fields from step)
769
- responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep);
770
- // Build response prompt
771
- responsePrompt = await this.responseEngine.buildResponsePrompt({
772
- route: selectedRoute,
773
- currentStep: nextStep,
774
- rules: selectedRoute.getRules(),
775
- prohibitions: selectedRoute.getProhibitions(),
776
- directives: responseDirectives,
777
- history,
778
- lastMessage: lastUserMessage,
779
- agentOptions: this.options,
780
- // Combine agent and route properties according to the specified logic
781
- combinedGuidelines: [
782
- ...this.getGuidelines(),
783
- ...selectedRoute.getGuidelines(),
784
- ],
785
- combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
786
- context: effectiveContext,
787
- session,
788
- });
789
- // Collect available tools for AI
790
- availableTools = this.collectAvailableTools(selectedRoute, nextStep);
791
- }
792
- else {
793
- // No route selected - generate basic response without route context
794
- utils_1.logger.debug(`[Agent] No route selected, generating basic response`);
795
- // Build basic response prompt without route context
796
- responsePrompt = await this.responseEngine.buildFallbackPrompt({
797
- history,
798
- agentOptions: this.options,
799
- terms: this.getTerms(),
800
- guidelines: this.getGuidelines(),
801
- context: effectiveContext,
802
- session,
803
- });
804
- // Use agent-level tools only
805
- availableTools = [...this.tools];
806
- responseSchema = undefined;
807
- }
808
- // Generate message using AI provider (common for both route and no-route cases)
809
- const result = await this.options.provider.generateMessage({
810
- prompt: responsePrompt,
811
- history,
812
- context: effectiveContext,
813
- tools: availableTools,
814
- signal,
815
- parameters: responseSchema
816
- ? {
817
- jsonSchema: responseSchema,
818
- schemaName: "response_output",
819
- }
820
- : undefined,
821
- });
822
- message = result.structured?.message || result.message;
823
- // Process dynamic tool calls from AI response (common for both route and no-route cases)
824
- if (result.structured?.toolCalls) {
825
- toolCalls = result.structured.toolCalls;
826
- // Execute dynamic tool calls
827
- if (toolCalls.length > 0) {
828
- utils_1.logger.debug(`[Agent] Executing ${toolCalls.length} dynamic tool calls`);
829
- for (const toolCall of toolCalls) {
830
- const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
831
- if (!tool) {
832
- utils_1.logger.warn(`[Agent] Tool not found: ${toolCall.toolName}`);
833
- continue;
834
- }
835
- const toolExecutor = new ToolExecutor_1.ToolExecutor();
836
- const toolResult = await toolExecutor.executeTool({
837
- tool: tool,
838
- context: effectiveContext,
839
- updateContext: this.updateContext.bind(this),
840
- history,
841
- data: session.data,
842
- toolArguments: toolCall.arguments,
843
- });
844
- // Update context with tool results
845
- if (toolResult.contextUpdate) {
846
- await this.updateContext(toolResult.contextUpdate);
847
- }
848
- // Update collected data with tool results
849
- if (toolResult.dataUpdate) {
850
- session = await this.updateData(session, toolResult.dataUpdate);
851
- utils_1.logger.debug(`[Agent] Tool updated collected data:`, toolResult.dataUpdate);
852
- }
853
- utils_1.logger.debug(`[Agent] Executed dynamic tool: ${toolResult.toolName} (success: ${toolResult.success})`);
854
- }
855
- }
856
- }
857
- // TOOL LOOP: Allow AI to make follow-up tool calls after initial tool execution
858
- const MAX_TOOL_LOOPS = 5;
859
- let toolLoopCount = 0;
860
- let hasToolCalls = toolCalls && toolCalls.length > 0;
861
- while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
862
- toolLoopCount++;
863
- utils_1.logger.debug(`[Agent] Starting tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS}`);
864
- // Add tool execution results to history so AI knows what happened
865
- const toolResultsEvents = [];
866
- for (const toolCall of toolCalls || []) {
867
- const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
868
- if (tool) {
869
- toolResultsEvents.push({
870
- kind: history_1.EventKind.TOOL,
871
- source: history_1.MessageRole.AGENT,
872
- timestamp: new Date().toISOString(),
873
- data: {
874
- tool_calls: [
875
- {
876
- tool_id: toolCall.toolName,
877
- arguments: toolCall.arguments,
878
- result: {
879
- data: "Tool executed successfully",
880
- },
881
- },
882
- ],
883
- },
884
- });
885
- }
886
- }
887
- // Create updated history with tool results
888
- const updatedHistory = [...history, ...toolResultsEvents];
889
- // Make follow-up AI call to see if more tools are needed
890
- const followUpResult = await this.options.provider.generateMessage({
891
- prompt: responsePrompt,
892
- history: updatedHistory,
893
- context: effectiveContext,
894
- tools: availableTools,
895
- parameters: {
896
- jsonSchema: responseSchema,
897
- schemaName: "tool_followup",
898
- },
899
- signal,
900
- });
901
- // Check if follow-up call has more tool calls
902
- const followUpToolCalls = followUpResult.structured?.toolCalls;
903
- hasToolCalls = followUpToolCalls && followUpToolCalls.length > 0;
904
- if (hasToolCalls) {
905
- utils_1.logger.debug(`[Agent] Follow-up call produced ${followUpToolCalls.length} additional tool calls`);
906
- // Execute the follow-up tool calls
907
- for (const toolCall of followUpToolCalls) {
908
- const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
909
- if (!tool) {
910
- utils_1.logger.warn(`[Agent] Tool not found in follow-up: ${toolCall.toolName}`);
911
- continue;
912
- }
913
- const toolExecutor = new ToolExecutor_1.ToolExecutor();
914
- const toolResult = await toolExecutor.executeTool({
915
- tool: tool,
916
- context: effectiveContext,
917
- updateContext: this.updateContext.bind(this),
918
- history: updatedHistory,
919
- data: session.data,
920
- toolArguments: toolCall.arguments,
921
- });
922
- // Update context with follow-up tool results
923
- if (toolResult.contextUpdate) {
924
- await this.updateContext(toolResult.contextUpdate);
925
- }
926
- if (toolResult.dataUpdate) {
927
- session = await this.updateData(session, toolResult.dataUpdate);
928
- utils_1.logger.debug(`[Agent] Follow-up tool updated collected data:`, toolResult.dataUpdate);
929
- }
930
- utils_1.logger.debug(`[Agent] Executed follow-up tool: ${toolResult.toolName} (success: ${toolResult.success})`);
931
- }
932
- // Update toolCalls for next iteration or final response
933
- toolCalls = followUpToolCalls;
934
- }
935
- else {
936
- utils_1.logger.debug(`[Agent] Tool loop completed after ${toolLoopCount} iterations`);
937
- // Update final message and toolCalls from follow-up result if no more tools
938
- message = followUpResult.structured?.message || followUpResult.message;
939
- toolCalls = followUpToolCalls || [];
940
- break;
941
- }
942
- }
943
- if (toolLoopCount >= MAX_TOOL_LOOPS) {
944
- utils_1.logger.warn(`[Agent] Tool loop limit reached (${MAX_TOOL_LOOPS}), stopping`);
945
- }
946
- // Extract collected data from final response (only for route-based interactions)
947
- if (selectedRoute && result.structured && nextStep?.collect) {
948
- const collectedData = {};
949
- // The structured response includes both base fields and collected extraction fields
950
- const structuredData = result.structured;
951
- for (const field of nextStep.collect) {
952
- if (field in structuredData) {
953
- collectedData[field] = structuredData[field];
954
- }
955
- }
956
- // Merge collected data into session
957
- if (Object.keys(collectedData).length > 0) {
958
- session = await this.updateData(session, collectedData);
959
- utils_1.logger.debug(`[Agent] Collected data:`, collectedData);
960
- }
961
- }
962
- // Extract any additional data from structured response
963
- if (result.structured &&
964
- typeof result.structured === "object" &&
965
- "contextUpdate" in result.structured) {
966
- await this.updateContext(result.structured
967
- .contextUpdate);
968
- }
969
- // Handle route completion if route is complete
970
- if (isRouteComplete) {
971
- // Route is complete - generate completion message then check for onComplete transition
972
- // Get endStep spec from route
973
- const endStepSpec = selectedRoute.endStepSpec;
974
- // Create a temporary step for completion message generation using endStep configuration
975
- const completionStep = new Step_1.Step(selectedRoute.id, {
976
- description: endStepSpec.description,
977
- id: endStepSpec.id || constants_1.END_ROUTE_ID,
978
- collect: endStepSpec.collect,
979
- requires: endStepSpec.requires,
980
- prompt: endStepSpec.prompt ||
981
- "Summarize what was accomplished and confirm completion based on the conversation history and collected data",
982
- });
983
- // Build response schema for completion
984
- const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep);
985
- const templateContext = {
986
- context: effectiveContext,
987
- session,
988
- history,
989
- };
990
- if (!selectedRoute) {
991
- throw new Error("Selected route is not defined");
992
- }
993
- // Build completion response prompt
994
- const completionPrompt = await this.responseEngine.buildResponsePrompt({
995
- route: selectedRoute,
996
- currentStep: completionStep,
997
- rules: selectedRoute.getRules(),
998
- prohibitions: selectedRoute.getProhibitions(),
999
- directives: undefined, // No directives for completion
1000
- history,
1001
- lastMessage: lastUserMessage,
1002
- agentOptions: this.options,
1003
- // Combine agent and route properties according to the specified logic
1004
- combinedGuidelines: [
1005
- ...this.getGuidelines(),
1006
- ...selectedRoute.getGuidelines(),
1007
- ],
1008
- combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
1009
- context: effectiveContext,
1010
- session,
1011
- });
1012
- // Generate completion message using AI provider
1013
- const completionResult = await this.options.provider.generateMessage({
1014
- prompt: completionPrompt,
1015
- history,
1016
- context: effectiveContext,
1017
- signal,
1018
- parameters: {
1019
- jsonSchema: responseSchema,
1020
- schemaName: "completion_message",
1021
- },
1022
- });
1023
- message =
1024
- completionResult.structured?.message || completionResult.message;
1025
- utils_1.logger.debug(`[Agent] Generated completion message for route: ${selectedRoute.title}`);
1026
- // Check for onComplete transition
1027
- const transitionConfig = await selectedRoute.evaluateOnComplete({ data: session.data }, effectiveContext);
1028
- if (transitionConfig) {
1029
- // Find target route by ID or title
1030
- const targetRoute = this.routes.find((r) => r.id === transitionConfig.nextStep ||
1031
- r.title === transitionConfig.nextStep);
1032
- if (targetRoute) {
1033
- const renderedCondition = await (0, utils_1.render)(transitionConfig.condition, templateContext);
1034
- // Set pending transition in session
1035
- session = {
1036
- ...session,
1037
- pendingTransition: {
1038
- targetRouteId: targetRoute.id,
1039
- condition: renderedCondition,
1040
- reason: "route_complete",
1041
- },
1042
- };
1043
- utils_1.logger.debug(`[Agent] Route ${selectedRoute.title} completed with pending transition to: ${targetRoute.title}`);
1044
- }
1045
- else {
1046
- utils_1.logger.warn(`[Agent] Route ${selectedRoute.title} completed but target route not found: ${transitionConfig.nextStep}`);
1047
- }
1048
- }
1049
- // Set step to END_ROUTE marker
1050
- session = (0, utils_1.enterStep)(session, constants_1.END_ROUTE_ID, "Route completed");
1051
- utils_1.logger.debug(`[Agent] Route ${selectedRoute.title} completed. Entered END_ROUTE step.`);
1052
- }
1053
- else {
1054
- // Fallback: No routes defined, generate a simple response
1055
- const fallbackPrompt = await this.responseEngine.buildFallbackPrompt({
1056
- history,
1057
- agentOptions: this.options,
1058
- terms: this.terms,
1059
- guidelines: this.guidelines,
1060
- context: effectiveContext,
1061
- session,
1062
- });
1063
- const result = await this.options.provider.generateMessage({
1064
- prompt: fallbackPrompt,
1065
- history,
1066
- context: effectiveContext,
1067
- signal,
1068
- parameters: {
1069
- jsonSchema: {
1070
- type: "object",
1071
- properties: {
1072
- message: { type: "string" },
1073
- },
1074
- required: ["message"],
1075
- additionalProperties: false,
1076
- },
1077
- schemaName: "fallback_response",
1078
- },
1079
- });
1080
- message = result.structured?.message || result.message;
1081
- }
1082
- // Auto-save session step to persistence if configured
1083
- if (this.persistenceManager &&
1084
- session.id &&
1085
- this.options.persistence?.autoSave !== false) {
1086
- await this.persistenceManager.saveSessionState(session.id, session);
1087
- utils_1.logger.debug(`[Agent] Auto-saved session step to persistence: ${session.id}`);
1088
- }
1089
- // Execute finalize function
1090
- if (session.currentRoute && session.currentStep) {
1091
- const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
1092
- if (currentRoute) {
1093
- const currentStep = currentRoute.getStep(session.currentStep.id);
1094
- if (currentStep?.finalize) {
1095
- utils_1.logger.debug(`[Agent] Executing finalize for step: ${currentStep.id}`);
1096
- await this.executePrepareFinalize(currentStep.finalize, effectiveContext, session.data, currentRoute, currentStep);
1097
- }
1098
- }
1099
- }
1100
- // Update current session if we have one
1101
- if (this.currentSession) {
1102
- this.currentSession = session;
1103
- }
1104
- return {
1105
- message,
1106
- session, // Return updated session with route/step info
1107
- toolCalls,
1108
- isRouteComplete, // Indicates if the route has reached END_ROUTE with all data collected
1109
- };
418
+ // Delegate to ResponseModal
419
+ return this.responseModal.respond(params);
1110
420
  }
1111
421
  /**
1112
422
  * Get all routes
@@ -1114,6 +424,27 @@ class Agent {
1114
424
  getRoutes() {
1115
425
  return [...this.routes];
1116
426
  }
427
+ /**
428
+ * Get agent options
429
+ * @internal Used by ResponseModal
430
+ */
431
+ getAgentOptions() {
432
+ return this.options;
433
+ }
434
+ /**
435
+ * Get routing engine
436
+ * @internal Used by ResponseModal
437
+ */
438
+ getRoutingEngine() {
439
+ return this.routingEngine;
440
+ }
441
+ /**
442
+ * Get the updateData method bound to this agent
443
+ * @internal Used by ResponseModal
444
+ */
445
+ getUpdateDataMethod() {
446
+ return this.updateData.bind(this);
447
+ }
1117
448
  /**
1118
449
  * Get all terms
1119
450
  */
@@ -1127,85 +458,45 @@ class Agent {
1127
458
  return [...this.tools];
1128
459
  }
1129
460
  /**
1130
- * Find an available tool by name for the given route
1131
- * Route-level tools take precedence over agent-level tools
1132
- * @private
461
+ * Get all guidelines
1133
462
  */
1134
- findAvailableTool(toolName, route) {
1135
- // Check route-level tools first (if route provided)
1136
- if (route) {
1137
- const routeTool = route
1138
- .getTools()
1139
- .find((tool) => tool.id === toolName || tool.name === toolName);
1140
- if (routeTool)
1141
- return routeTool;
1142
- }
1143
- // Fall back to agent-level tools
1144
- return this.tools.find((tool) => tool.id === toolName || tool.name === toolName);
463
+ getGuidelines() {
464
+ return [...this.guidelines];
1145
465
  }
1146
466
  /**
1147
- * Collect all available tools for the given route and step context
1148
- * @private
467
+ * Get the agent's knowledge base
1149
468
  */
1150
- collectAvailableTools(route, step) {
1151
- const availableTools = new Map();
1152
- // Add agent-level tools
1153
- this.tools.forEach((tool) => {
1154
- availableTools.set(tool.id, tool);
1155
- });
1156
- // Add route-level tools (these take precedence)
1157
- if (route) {
1158
- route.getTools().forEach((tool) => {
1159
- availableTools.set(tool.id, tool);
1160
- });
1161
- }
1162
- // Filter by step-level allowed tools if specified
1163
- if (step?.tools) {
1164
- const allowedToolIds = new Set();
1165
- const stepTools = [];
1166
- for (const toolRef of step.tools) {
1167
- if (typeof toolRef === "string") {
1168
- // Reference to registered tool
1169
- allowedToolIds.add(toolRef);
1170
- }
1171
- else {
1172
- // Inline tool definition
1173
- if (toolRef.id) {
1174
- allowedToolIds.add(toolRef.id);
1175
- stepTools.push(toolRef);
1176
- }
1177
- }
1178
- }
1179
- // If step specifies tools, only include those
1180
- if (allowedToolIds.size > 0) {
1181
- const filteredTools = new Map();
1182
- for (const toolId of allowedToolIds) {
1183
- const tool = availableTools.get(toolId);
1184
- if (tool) {
1185
- filteredTools.set(toolId, tool);
1186
- }
1187
- }
1188
- // Add inline tools
1189
- stepTools.forEach((tool) => {
1190
- if (tool.id) {
1191
- filteredTools.set(tool.id, tool);
1192
- }
1193
- });
1194
- availableTools.clear();
1195
- filteredTools.forEach((tool, id) => availableTools.set(id, tool));
1196
- }
1197
- }
1198
- // Convert to the format expected by AI providers
1199
- return Array.from(availableTools.values()).map((tool) => ({
1200
- id: tool.id,
1201
- name: tool.name || tool.id,
1202
- description: tool.description,
1203
- parameters: tool.parameters,
1204
- }));
469
+ getKnowledgeBase() {
470
+ return { ...this.knowledgeBase };
471
+ }
472
+ /**
473
+ * Get the persistence manager (if configured)
474
+ */
475
+ getPersistenceManager() {
476
+ return this.persistenceManager;
477
+ }
478
+ /**
479
+ * Check if persistence is enabled
480
+ */
481
+ hasPersistence() {
482
+ return this.persistenceManager !== undefined;
483
+ }
484
+ /**
485
+ * Set the current session for convenience methods
486
+ * @param session - Session step to use for subsequent calls
487
+ */
488
+ setCurrentSession(session) {
489
+ this.currentSession = session;
490
+ }
491
+ /**
492
+ * Get the current session (if set)
493
+ */
494
+ getCurrentSession() {
495
+ return this.currentSession;
1205
496
  }
1206
497
  /**
1207
498
  * Execute a prepare or finalize function/tool
1208
- * @private
499
+ * @internal Used by ResponseModal
1209
500
  */
1210
501
  async executePrepareFinalize(prepareOrFinalize, context, data, route, step) {
1211
502
  if (!prepareOrFinalize)
@@ -1253,6 +544,7 @@ class Agent {
1253
544
  tool,
1254
545
  context,
1255
546
  updateContext: this.updateContext.bind(this),
547
+ updateData: this.updateCollectedData.bind(this),
1256
548
  history: [], // Empty history for prepare/finalize
1257
549
  data,
1258
550
  });
@@ -1268,61 +560,6 @@ class Agent {
1268
560
  }
1269
561
  }
1270
562
  }
1271
- /**
1272
- * Get all guidelines
1273
- */
1274
- getGuidelines() {
1275
- return [...this.guidelines];
1276
- }
1277
- /**
1278
- * Get the agent's knowledge base
1279
- */
1280
- getKnowledgeBase() {
1281
- return { ...this.knowledgeBase };
1282
- }
1283
- /**
1284
- * Merge terms with route-specific taking precedence on conflicts
1285
- * @private
1286
- */
1287
- mergeTerms(agentTerms, routeTerms) {
1288
- const merged = new Map();
1289
- // Add agent terms first
1290
- agentTerms.forEach((term) => {
1291
- const name = typeof term.name === "string" ? term.name : term.name.toString();
1292
- merged.set(name, term);
1293
- });
1294
- // Add route terms (these take precedence)
1295
- routeTerms.forEach((term) => {
1296
- const name = typeof term.name === "string" ? term.name : term.name.toString();
1297
- merged.set(name, term);
1298
- });
1299
- return Array.from(merged.values());
1300
- }
1301
- /**
1302
- * Get the persistence manager (if configured)
1303
- */
1304
- getPersistenceManager() {
1305
- return this.persistenceManager;
1306
- }
1307
- /**
1308
- * Check if persistence is enabled
1309
- */
1310
- hasPersistence() {
1311
- return this.persistenceManager !== undefined;
1312
- }
1313
- /**
1314
- * Set the current session for convenience methods
1315
- * @param session - Session step to use for subsequent calls
1316
- */
1317
- setCurrentSession(session) {
1318
- this.currentSession = session;
1319
- }
1320
- /**
1321
- * Get the current session (if set)
1322
- */
1323
- getCurrentSession() {
1324
- return this.currentSession;
1325
- }
1326
563
  /**
1327
564
  * Clear the current session
1328
565
  */
@@ -1330,19 +567,19 @@ class Agent {
1330
567
  this.currentSession = undefined;
1331
568
  }
1332
569
  /**
1333
- * Get collected data from current session
570
+ * Get collected data from current session or agent-level collected data
1334
571
  * @param routeId - Optional route ID to get data for (uses current route if not provided)
1335
- * @returns The collected data from the current session
572
+ * @returns The collected data from the current session or agent-level data
1336
573
  */
1337
- getData(routeId) {
1338
- if (!this.currentSession) {
1339
- return {};
1340
- }
1341
- if (routeId) {
1342
- return (this.currentSession.dataByRoute?.[routeId] ||
1343
- {});
574
+ getData() {
575
+ // If we have a current session, use session data
576
+ if (this.currentSession) {
577
+ // With agent-level data, all routes share the same data structure
578
+ // No need for route-specific data access
579
+ return (this.currentSession.data) || {};
1344
580
  }
1345
- return this.currentSession.data || {};
581
+ // Otherwise, return agent-level collected data
582
+ return this.getCollectedData();
1346
583
  }
1347
584
  /**
1348
585
  * Manually transition to a different route
@@ -1385,14 +622,14 @@ class Agent {
1385
622
  pendingTransition: {
1386
623
  targetRouteId: targetRoute.id,
1387
624
  condition: renderedCondition,
1388
- reason: "manual",
625
+ reason: "route_complete",
1389
626
  },
1390
627
  };
1391
628
  // Update current session if using it
1392
629
  if (!session && this.currentSession) {
1393
630
  this.currentSession = updatedSession;
1394
631
  }
1395
- utils_1.logger.debug(`[Agent] Set pending manual transition to route: ${targetRoute.title}`);
632
+ utils_1.logger.debug(`[Agent] Set pending transition to route: ${targetRoute.title}`);
1396
633
  return updatedSession;
1397
634
  }
1398
635
  /**
@@ -1400,33 +637,20 @@ class Agent {
1400
637
  * Automatically manages conversation history through the session
1401
638
  */
1402
639
  async chat(message, options) {
1403
- // Determine which history to use
1404
- let history;
1405
- if (options?.history) {
1406
- // Use provided history for this response only
1407
- history = options.history;
1408
- }
1409
- else {
1410
- // Add user message to session history if provided
1411
- if (message) {
1412
- await this.session.addMessage("user", message);
1413
- }
1414
- history = this.session.getHistory();
1415
- }
1416
- // Get or create session
1417
- const session = await this.session.getOrCreate();
1418
- // Use existing respond method with session-managed history
1419
- const result = await this.respond({
1420
- history,
1421
- session,
640
+ // Delegate to ResponseModal.generate()
641
+ return this.responseModal.generate(message, options);
642
+ }
643
+ /**
644
+ * Modern streaming API - simple interface like chat() but returns a stream
645
+ * Automatically manages conversation history through the session
646
+ */
647
+ async *stream(message, options) {
648
+ // Delegate to ResponseModal with the same options structure as chat()
649
+ yield* this.responseModal.stream(message, {
650
+ history: options?.history,
1422
651
  contextOverride: options?.contextOverride,
1423
652
  signal: options?.signal,
1424
653
  });
1425
- // Add agent response to session history (only if not using override history)
1426
- if (!options?.history) {
1427
- await this.session.addMessage("assistant", result.message);
1428
- }
1429
- return result;
1430
654
  }
1431
655
  }
1432
656
  exports.Agent = Agent;