@falai/agent 0.4.1 → 0.5.1

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 (285) hide show
  1. package/README.md +21 -74
  2. package/dist/cjs/core/Agent.d.ts +22 -29
  3. package/dist/cjs/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/core/Agent.js +464 -291
  5. package/dist/cjs/core/Agent.js.map +1 -1
  6. package/dist/cjs/core/Events.d.ts +10 -1
  7. package/dist/cjs/core/Events.d.ts.map +1 -1
  8. package/dist/cjs/core/Events.js +3 -2
  9. package/dist/cjs/core/Events.js.map +1 -1
  10. package/dist/cjs/core/PersistenceManager.d.ts +19 -0
  11. package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
  12. package/dist/cjs/core/PersistenceManager.js +55 -0
  13. package/dist/cjs/core/PersistenceManager.js.map +1 -1
  14. package/dist/cjs/core/PromptComposer.d.ts +24 -0
  15. package/dist/cjs/core/PromptComposer.d.ts.map +1 -0
  16. package/dist/cjs/core/PromptComposer.js +127 -0
  17. package/dist/cjs/core/PromptComposer.js.map +1 -0
  18. package/dist/cjs/core/ResponseEngine.d.ts +19 -0
  19. package/dist/cjs/core/ResponseEngine.d.ts.map +1 -0
  20. package/dist/cjs/core/ResponseEngine.js +51 -0
  21. package/dist/cjs/core/ResponseEngine.js.map +1 -0
  22. package/dist/cjs/core/Route.d.ts +18 -12
  23. package/dist/cjs/core/Route.d.ts.map +1 -1
  24. package/dist/cjs/core/Route.js +15 -9
  25. package/dist/cjs/core/Route.js.map +1 -1
  26. package/dist/cjs/core/RoutingEngine.d.ts +38 -0
  27. package/dist/cjs/core/RoutingEngine.d.ts.map +1 -0
  28. package/dist/cjs/core/RoutingEngine.js +110 -0
  29. package/dist/cjs/core/RoutingEngine.js.map +1 -0
  30. package/dist/cjs/core/State.d.ts +15 -4
  31. package/dist/cjs/core/State.d.ts.map +1 -1
  32. package/dist/cjs/core/State.js +21 -2
  33. package/dist/cjs/core/State.js.map +1 -1
  34. package/dist/cjs/core/ToolExecutor.d.ts +29 -0
  35. package/dist/cjs/core/ToolExecutor.d.ts.map +1 -0
  36. package/dist/cjs/core/ToolExecutor.js +73 -0
  37. package/dist/cjs/core/ToolExecutor.js.map +1 -0
  38. package/dist/cjs/core/Transition.d.ts +5 -5
  39. package/dist/cjs/core/Transition.d.ts.map +1 -1
  40. package/dist/cjs/core/Transition.js.map +1 -1
  41. package/dist/cjs/index.d.ts +6 -8
  42. package/dist/cjs/index.d.ts.map +1 -1
  43. package/dist/cjs/index.js +8 -10
  44. package/dist/cjs/index.js.map +1 -1
  45. package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -1
  46. package/dist/cjs/providers/AnthropicProvider.js +10 -13
  47. package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
  48. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  49. package/dist/cjs/providers/GeminiProvider.js +12 -8
  50. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  51. package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
  52. package/dist/cjs/providers/OpenAIProvider.js +10 -53
  53. package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
  54. package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
  55. package/dist/cjs/providers/OpenRouterProvider.js +10 -53
  56. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
  57. package/dist/cjs/types/agent.d.ts +13 -12
  58. package/dist/cjs/types/agent.d.ts.map +1 -1
  59. package/dist/cjs/types/ai.d.ts +8 -2
  60. package/dist/cjs/types/ai.d.ts.map +1 -1
  61. package/dist/cjs/types/history.d.ts +8 -0
  62. package/dist/cjs/types/history.d.ts.map +1 -1
  63. package/dist/cjs/types/index.d.ts +0 -3
  64. package/dist/cjs/types/index.d.ts.map +1 -1
  65. package/dist/cjs/types/index.js +1 -3
  66. package/dist/cjs/types/index.js.map +1 -1
  67. package/dist/cjs/types/route.d.ts +39 -4
  68. package/dist/cjs/types/route.d.ts.map +1 -1
  69. package/dist/cjs/types/routing.d.ts +16 -0
  70. package/dist/cjs/types/routing.d.ts.map +1 -0
  71. package/dist/cjs/types/routing.js +3 -0
  72. package/dist/cjs/types/routing.js.map +1 -0
  73. package/dist/cjs/types/schema.d.ts +22 -0
  74. package/dist/cjs/types/schema.d.ts.map +1 -0
  75. package/dist/cjs/types/schema.js +3 -0
  76. package/dist/cjs/types/schema.js.map +1 -0
  77. package/dist/cjs/types/session.d.ts +77 -0
  78. package/dist/cjs/types/session.d.ts.map +1 -0
  79. package/dist/cjs/types/session.js +146 -0
  80. package/dist/cjs/types/session.js.map +1 -0
  81. package/dist/cjs/types/tool.d.ts +11 -5
  82. package/dist/cjs/types/tool.d.ts.map +1 -1
  83. package/dist/cjs/utils/id.d.ts +0 -5
  84. package/dist/cjs/utils/id.d.ts.map +1 -1
  85. package/dist/cjs/utils/id.js +0 -10
  86. package/dist/cjs/utils/id.js.map +1 -1
  87. package/dist/cjs/utils/schema.d.ts +17 -0
  88. package/dist/cjs/utils/schema.d.ts.map +1 -0
  89. package/dist/cjs/utils/schema.js +32 -0
  90. package/dist/cjs/utils/schema.js.map +1 -0
  91. package/dist/core/Agent.d.ts +22 -29
  92. package/dist/core/Agent.d.ts.map +1 -1
  93. package/dist/core/Agent.js +464 -291
  94. package/dist/core/Agent.js.map +1 -1
  95. package/dist/core/Events.d.ts +10 -1
  96. package/dist/core/Events.d.ts.map +1 -1
  97. package/dist/core/Events.js +3 -2
  98. package/dist/core/Events.js.map +1 -1
  99. package/dist/core/PersistenceManager.d.ts +19 -0
  100. package/dist/core/PersistenceManager.d.ts.map +1 -1
  101. package/dist/core/PersistenceManager.js +55 -0
  102. package/dist/core/PersistenceManager.js.map +1 -1
  103. package/dist/core/PromptComposer.d.ts +24 -0
  104. package/dist/core/PromptComposer.d.ts.map +1 -0
  105. package/dist/core/PromptComposer.js +123 -0
  106. package/dist/core/PromptComposer.js.map +1 -0
  107. package/dist/core/ResponseEngine.d.ts +19 -0
  108. package/dist/core/ResponseEngine.d.ts.map +1 -0
  109. package/dist/core/ResponseEngine.js +47 -0
  110. package/dist/core/ResponseEngine.js.map +1 -0
  111. package/dist/core/Route.d.ts +18 -12
  112. package/dist/core/Route.d.ts.map +1 -1
  113. package/dist/core/Route.js +15 -9
  114. package/dist/core/Route.js.map +1 -1
  115. package/dist/core/RoutingEngine.d.ts +38 -0
  116. package/dist/core/RoutingEngine.d.ts.map +1 -0
  117. package/dist/core/RoutingEngine.js +106 -0
  118. package/dist/core/RoutingEngine.js.map +1 -0
  119. package/dist/core/State.d.ts +15 -4
  120. package/dist/core/State.d.ts.map +1 -1
  121. package/dist/core/State.js +21 -2
  122. package/dist/core/State.js.map +1 -1
  123. package/dist/core/ToolExecutor.d.ts +29 -0
  124. package/dist/core/ToolExecutor.d.ts.map +1 -0
  125. package/dist/core/ToolExecutor.js +69 -0
  126. package/dist/core/ToolExecutor.js.map +1 -0
  127. package/dist/core/Transition.d.ts +5 -5
  128. package/dist/core/Transition.d.ts.map +1 -1
  129. package/dist/core/Transition.js.map +1 -1
  130. package/dist/index.d.ts +6 -8
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +3 -5
  133. package/dist/index.js.map +1 -1
  134. package/dist/providers/AnthropicProvider.d.ts.map +1 -1
  135. package/dist/providers/AnthropicProvider.js +10 -13
  136. package/dist/providers/AnthropicProvider.js.map +1 -1
  137. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  138. package/dist/providers/GeminiProvider.js +12 -8
  139. package/dist/providers/GeminiProvider.js.map +1 -1
  140. package/dist/providers/OpenAIProvider.d.ts.map +1 -1
  141. package/dist/providers/OpenAIProvider.js +10 -53
  142. package/dist/providers/OpenAIProvider.js.map +1 -1
  143. package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
  144. package/dist/providers/OpenRouterProvider.js +10 -53
  145. package/dist/providers/OpenRouterProvider.js.map +1 -1
  146. package/dist/types/agent.d.ts +13 -12
  147. package/dist/types/agent.d.ts.map +1 -1
  148. package/dist/types/ai.d.ts +8 -2
  149. package/dist/types/ai.d.ts.map +1 -1
  150. package/dist/types/history.d.ts +8 -0
  151. package/dist/types/history.d.ts.map +1 -1
  152. package/dist/types/index.d.ts +0 -3
  153. package/dist/types/index.d.ts.map +1 -1
  154. package/dist/types/index.js +0 -1
  155. package/dist/types/index.js.map +1 -1
  156. package/dist/types/route.d.ts +39 -4
  157. package/dist/types/route.d.ts.map +1 -1
  158. package/dist/types/routing.d.ts +16 -0
  159. package/dist/types/routing.d.ts.map +1 -0
  160. package/dist/types/routing.js +2 -0
  161. package/dist/types/routing.js.map +1 -0
  162. package/dist/types/schema.d.ts +22 -0
  163. package/dist/types/schema.d.ts.map +1 -0
  164. package/dist/types/schema.js +2 -0
  165. package/dist/types/schema.js.map +1 -0
  166. package/dist/types/session.d.ts +77 -0
  167. package/dist/types/session.d.ts.map +1 -0
  168. package/dist/types/session.js +138 -0
  169. package/dist/types/session.js.map +1 -0
  170. package/dist/types/tool.d.ts +11 -5
  171. package/dist/types/tool.d.ts.map +1 -1
  172. package/dist/utils/id.d.ts +0 -5
  173. package/dist/utils/id.d.ts.map +1 -1
  174. package/dist/utils/id.js +0 -9
  175. package/dist/utils/id.js.map +1 -1
  176. package/dist/utils/schema.d.ts +17 -0
  177. package/dist/utils/schema.d.ts.map +1 -0
  178. package/dist/utils/schema.js +27 -0
  179. package/dist/utils/schema.js.map +1 -0
  180. package/docs/ADAPTERS.md +83 -3
  181. package/docs/API_REFERENCE.md +329 -104
  182. package/docs/ARCHITECTURE.md +284 -286
  183. package/docs/CONSTRUCTOR_OPTIONS.md +192 -135
  184. package/docs/CONTEXT_MANAGEMENT.md +311 -28
  185. package/docs/CONTRIBUTING.md +1 -1
  186. package/docs/DOMAINS.md +61 -0
  187. package/docs/GETTING_STARTED.md +177 -88
  188. package/docs/PERSISTENCE.md +170 -23
  189. package/docs/README.md +7 -10
  190. package/examples/business-onboarding.ts +21 -9
  191. package/examples/company-qna-agent.ts +508 -0
  192. package/examples/declarative-agent.ts +143 -26
  193. package/examples/domain-scoping.ts +31 -10
  194. package/examples/extracted-data-modification.ts +415 -0
  195. package/examples/healthcare-agent.ts +194 -90
  196. package/examples/openai-agent.ts +67 -25
  197. package/examples/opensearch-persistence.ts +455 -151
  198. package/examples/persistent-onboarding.ts +162 -96
  199. package/examples/prisma-persistence.ts +371 -125
  200. package/examples/redis-persistence.ts +393 -23
  201. package/examples/rules-prohibitions.ts +32 -11
  202. package/examples/streaming-agent.ts +61 -13
  203. package/examples/travel-agent.ts +266 -133
  204. package/package.json +1 -1
  205. package/src/core/Agent.ts +668 -356
  206. package/src/core/Events.ts +12 -2
  207. package/src/core/PersistenceManager.ts +81 -0
  208. package/src/core/PromptComposer.ts +143 -0
  209. package/src/core/ResponseEngine.ts +82 -0
  210. package/src/core/Route.ts +32 -17
  211. package/src/core/RoutingEngine.ts +165 -0
  212. package/src/core/State.ts +55 -15
  213. package/src/core/ToolExecutor.ts +117 -0
  214. package/src/core/Transition.ts +5 -5
  215. package/src/index.ts +12 -21
  216. package/src/providers/AnthropicProvider.ts +10 -13
  217. package/src/providers/GeminiProvider.ts +12 -8
  218. package/src/providers/OpenAIProvider.ts +10 -56
  219. package/src/providers/OpenRouterProvider.ts +10 -56
  220. package/src/types/agent.ts +16 -13
  221. package/src/types/ai.ts +6 -2
  222. package/src/types/history.ts +8 -0
  223. package/src/types/index.ts +0 -11
  224. package/src/types/route.ts +41 -5
  225. package/src/types/routing.ts +18 -0
  226. package/src/types/schema.ts +23 -0
  227. package/src/types/session.ts +219 -0
  228. package/src/types/tool.ts +29 -7
  229. package/src/utils/id.ts +0 -10
  230. package/src/utils/schema.ts +32 -0
  231. package/dist/cjs/core/ConditionEvaluator.d.ts +0 -72
  232. package/dist/cjs/core/ConditionEvaluator.d.ts.map +0 -1
  233. package/dist/cjs/core/ConditionEvaluator.js +0 -272
  234. package/dist/cjs/core/ConditionEvaluator.js.map +0 -1
  235. package/dist/cjs/core/Observation.d.ts +0 -24
  236. package/dist/cjs/core/Observation.d.ts.map +0 -1
  237. package/dist/cjs/core/Observation.js +0 -39
  238. package/dist/cjs/core/Observation.js.map +0 -1
  239. package/dist/cjs/core/PreparationEngine.d.ts +0 -116
  240. package/dist/cjs/core/PreparationEngine.d.ts.map +0 -1
  241. package/dist/cjs/core/PreparationEngine.js +0 -353
  242. package/dist/cjs/core/PreparationEngine.js.map +0 -1
  243. package/dist/cjs/core/PromptBuilder.d.ts +0 -136
  244. package/dist/cjs/core/PromptBuilder.d.ts.map +0 -1
  245. package/dist/cjs/core/PromptBuilder.js +0 -421
  246. package/dist/cjs/core/PromptBuilder.js.map +0 -1
  247. package/dist/cjs/types/observation.d.ts +0 -27
  248. package/dist/cjs/types/observation.d.ts.map +0 -1
  249. package/dist/cjs/types/observation.js +0 -6
  250. package/dist/cjs/types/observation.js.map +0 -1
  251. package/dist/cjs/types/prompt.d.ts +0 -46
  252. package/dist/cjs/types/prompt.d.ts.map +0 -1
  253. package/dist/cjs/types/prompt.js +0 -19
  254. package/dist/cjs/types/prompt.js.map +0 -1
  255. package/dist/core/ConditionEvaluator.d.ts +0 -72
  256. package/dist/core/ConditionEvaluator.d.ts.map +0 -1
  257. package/dist/core/ConditionEvaluator.js +0 -268
  258. package/dist/core/ConditionEvaluator.js.map +0 -1
  259. package/dist/core/Observation.d.ts +0 -24
  260. package/dist/core/Observation.d.ts.map +0 -1
  261. package/dist/core/Observation.js +0 -35
  262. package/dist/core/Observation.js.map +0 -1
  263. package/dist/core/PreparationEngine.d.ts +0 -116
  264. package/dist/core/PreparationEngine.d.ts.map +0 -1
  265. package/dist/core/PreparationEngine.js +0 -349
  266. package/dist/core/PreparationEngine.js.map +0 -1
  267. package/dist/core/PromptBuilder.d.ts +0 -136
  268. package/dist/core/PromptBuilder.d.ts.map +0 -1
  269. package/dist/core/PromptBuilder.js +0 -417
  270. package/dist/core/PromptBuilder.js.map +0 -1
  271. package/dist/types/observation.d.ts +0 -27
  272. package/dist/types/observation.d.ts.map +0 -1
  273. package/dist/types/observation.js +0 -5
  274. package/dist/types/observation.js.map +0 -1
  275. package/dist/types/prompt.d.ts +0 -46
  276. package/dist/types/prompt.d.ts.map +0 -1
  277. package/dist/types/prompt.js +0 -16
  278. package/dist/types/prompt.js.map +0 -1
  279. package/docs/STRUCTURE.md +0 -58
  280. package/src/core/ConditionEvaluator.ts +0 -381
  281. package/src/core/Observation.ts +0 -47
  282. package/src/core/PreparationEngine.ts +0 -561
  283. package/src/core/PromptBuilder.ts +0 -617
  284. package/src/types/observation.ts +0 -29
  285. package/src/types/prompt.ts +0 -49
@@ -4,12 +4,27 @@
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Agent = void 0;
7
+ const session_1 = require("../types/session");
8
+ const history_1 = require("../types/history");
9
+ const PromptComposer_1 = require("./PromptComposer");
7
10
  const Route_1 = require("./Route");
8
11
  const DomainRegistry_1 = require("./DomainRegistry");
9
- const PromptBuilder_1 = require("./PromptBuilder");
10
- const Observation_1 = require("./Observation");
11
12
  const PersistenceManager_1 = require("./PersistenceManager");
12
- const PreparationEngine_1 = require("./PreparationEngine");
13
+ const RoutingEngine_1 = require("./RoutingEngine");
14
+ const ResponseEngine_1 = require("./ResponseEngine");
15
+ const ToolExecutor_1 = require("./ToolExecutor");
16
+ /**
17
+ * Helper to extract last message from history
18
+ */
19
+ function getLastMessageFromHistory(history) {
20
+ for (let i = history.length - 1; i >= 0; i--) {
21
+ const event = history[i];
22
+ if (event.kind === history_1.EventKind.MESSAGE) {
23
+ return event.data.message;
24
+ }
25
+ }
26
+ return "";
27
+ }
13
28
  /**
14
29
  * Main Agent class with generic context support
15
30
  */
@@ -19,28 +34,26 @@ class Agent {
19
34
  this.terms = [];
20
35
  this.guidelines = [];
21
36
  this.capabilities = [];
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
38
  this.routes = [];
23
- this.observations = [];
24
39
  this.domainRegistry = new DomainRegistry_1.DomainRegistry();
25
40
  /**
26
41
  * Dynamic domain property - populated via addDomain
27
42
  */
28
43
  this.domain = {};
29
- // Initialize with default values
30
- if (!this.options.maxEngineIterations) {
31
- this.options.maxEngineIterations = 1;
32
- }
33
44
  // Validate context configuration
34
45
  if (options.context !== undefined && options.contextProvider) {
35
46
  throw new Error("Cannot provide both 'context' and 'contextProvider'. Choose one.");
36
47
  }
37
48
  // Initialize context if provided
38
49
  this.context = options.context;
39
- // Initialize preparation engine with AI provider and optional parallelism controls
40
- this.preparationEngine = new PreparationEngine_1.PreparationEngine(options.ai, {
41
- maxParallelLlmCalls: options.preparation?.maxParallelLlmCalls,
42
- maxParallelTools: options.preparation?.maxParallelTools,
50
+ // Initialize routing and response engines
51
+ this.routingEngine = new RoutingEngine_1.RoutingEngine({
52
+ maxCandidates: 5,
53
+ allowRouteSwitch: true,
54
+ switchThreshold: 70,
43
55
  });
56
+ this.responseEngine = new ResponseEngine_1.ResponseEngine();
44
57
  // Initialize persistence if configured
45
58
  if (options.persistence) {
46
59
  this.persistenceManager = new PersistenceManager_1.PersistenceManager(options.persistence);
@@ -70,23 +83,6 @@ class Agent {
70
83
  this.createRoute(routeOptions);
71
84
  });
72
85
  }
73
- if (options.observations) {
74
- options.observations.forEach((obsOptions) => {
75
- const obs = this.createObservation(obsOptions.description);
76
- // If route refs were provided, resolve and disambiguate
77
- if (obsOptions.routeRefs && obsOptions.routeRefs.length > 0) {
78
- const resolvedRoutes = obsOptions.routeRefs
79
- .map((ref) => {
80
- // Try to find route by ID or title
81
- return this.routes.find((r) => r.id === ref || r.title === ref);
82
- })
83
- .filter((r) => r !== undefined);
84
- if (resolvedRoutes.length > 0) {
85
- obs.disambiguate(resolvedRoutes);
86
- }
87
- }
88
- });
89
- }
90
86
  }
91
87
  /**
92
88
  * Get agent name
@@ -108,6 +104,7 @@ class Agent {
108
104
  }
109
105
  /**
110
106
  * Create a new route (journey)
107
+ * @template TExtracted - Type of data extracted throughout the route
111
108
  */
112
109
  createRoute(options) {
113
110
  const route = new Route_1.Route(options);
@@ -144,21 +141,28 @@ class Agent {
144
141
  this.capabilities.push(capabilityWithId);
145
142
  return this;
146
143
  }
147
- /**
148
- * Create an observation for disambiguation
149
- */
150
- createObservation(description) {
151
- const observation = new Observation_1.Observation({ description });
152
- this.observations.push(observation);
153
- return observation;
154
- }
155
144
  /**
156
145
  * Add a domain with its tools/methods
146
+ * Automatically tags all ToolRef objects with their domain name for security enforcement
157
147
  */
158
148
  addDomain(name, domainObject) {
159
- this.domainRegistry.register(name, domainObject);
149
+ // Tag all tools in this domain with the domain name for security enforcement
150
+ const taggedDomain = { ...domainObject };
151
+ for (const key in taggedDomain) {
152
+ const value = taggedDomain[key];
153
+ // Check if value is a ToolRef (has handler, id, name properties)
154
+ if (value &&
155
+ typeof value === "object" &&
156
+ "handler" in value &&
157
+ "id" in value &&
158
+ "name" in value) {
159
+ // Tag the tool with its domain name
160
+ value.domainName = name;
161
+ }
162
+ }
163
+ this.domainRegistry.register(name, taggedDomain);
160
164
  // Attach to the domain property for easy access
161
- this.domain[name] = domainObject;
165
+ this.domain[name] = taggedDomain;
162
166
  }
163
167
  /**
164
168
  * Update the agent's context
@@ -176,6 +180,26 @@ class Agent {
176
180
  await this.options.hooks.onContextUpdate(this.context, previousContext);
177
181
  }
178
182
  }
183
+ /**
184
+ * Update extracted data in session with lifecycle hook support
185
+ * Triggers the onExtractedUpdate lifecycle hook if configured
186
+ * @internal
187
+ */
188
+ async updateExtracted(session, extractedUpdate) {
189
+ const previousExtracted = { ...session.extracted };
190
+ // Merge new extracted data
191
+ let newExtracted = {
192
+ ...session.extracted,
193
+ ...extractedUpdate,
194
+ };
195
+ // Trigger lifecycle hook if configured
196
+ if (this.options.hooks?.onExtractedUpdate) {
197
+ const updatedExtracted = (await this.options.hooks.onExtractedUpdate(newExtracted, previousExtracted));
198
+ newExtracted = updatedExtracted;
199
+ }
200
+ // Return updated session
201
+ return (0, session_1.mergeExtracted)(session, newExtracted);
202
+ }
179
203
  /**
180
204
  * Get current context (fetches from provider if configured)
181
205
  * @internal
@@ -188,6 +212,46 @@ class Agent {
188
212
  // Otherwise return the stored context
189
213
  return this.context;
190
214
  }
215
+ /**
216
+ * Determine the next state in a route based on extracted data
217
+ * @internal
218
+ */
219
+ getNextState(route, currentState, extracted) {
220
+ // If no current state, start from initial state
221
+ if (!currentState) {
222
+ // Check if initial state should be skipped
223
+ if (route.initialState.shouldSkip(extracted)) {
224
+ return this.getNextState(route, route.initialState, extracted);
225
+ }
226
+ return route.initialState;
227
+ }
228
+ // Get transitions from current state
229
+ const transitions = currentState.getTransitions();
230
+ // If no transitions, stay in current state
231
+ if (transitions.length === 0) {
232
+ return currentState;
233
+ }
234
+ // Try to find the next state to transition to
235
+ for (const transition of transitions) {
236
+ const target = transition.getTarget();
237
+ if (!target)
238
+ continue;
239
+ // Check if target state should be skipped
240
+ if (target.shouldSkip(extracted)) {
241
+ // Recursively find next non-skipped state
242
+ return this.getNextState(route, target, extracted);
243
+ }
244
+ // Check if target state has required data
245
+ if (!target.hasRequiredData(extracted)) {
246
+ // Cannot enter this state yet, stay in current state
247
+ continue;
248
+ }
249
+ // Found valid next state
250
+ return target;
251
+ }
252
+ // No valid transition found, stay in current state
253
+ return currentState;
254
+ }
191
255
  /**
192
256
  * Generate a response based on history and context as a stream
193
257
  */
@@ -202,145 +266,208 @@ class Agent {
202
266
  this.context = currentContext;
203
267
  }
204
268
  // Merge context with override
205
- let effectiveContext = {
269
+ const effectiveContext = {
206
270
  ...currentContext,
207
271
  ...contextOverride,
208
272
  };
209
- // RUN PREPARATION ITERATIONS
210
- // This is where tools execute automatically based on:
211
- // 1. Matched guidelines with associated tools
212
- // 2. State machine transitions with toolState
213
- //
214
- // The AI will NEVER see these tools - they execute before message generation
215
- const preparationResult = await this.preparationEngine.prepare({
216
- history,
217
- currentState: params.state,
218
- context: effectiveContext,
219
- routes: this.routes,
220
- guidelines: this.guidelines,
221
- maxIterations: this.options.maxEngineIterations || 1,
222
- });
223
- // Update context with results from tool executions
224
- effectiveContext = preparationResult.finalContext;
225
- // Persist updated context and trigger lifecycle hook
226
- const previousStoredContext = this.context;
227
- this.context = effectiveContext;
228
- if (this.options.hooks?.onContextUpdate &&
229
- previousStoredContext !== undefined) {
230
- await this.options.hooks.onContextUpdate(this.context, previousStoredContext);
231
- }
232
- // Log tool executions for debugging
233
- if (preparationResult.toolExecutions.length > 0) {
234
- console.log(`[Agent] Preparation complete: ${preparationResult.toolExecutions.length} tools executed in ${preparationResult.iterations.length} iterations`);
273
+ // Initialize or get session
274
+ let session = params.session || (0, session_1.createSession)();
275
+ // PHASE 1: TOOL EXECUTION - Execute tools if current state has toolState
276
+ if (session.currentRoute && session.currentState) {
277
+ const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
278
+ if (currentRoute) {
279
+ const currentState = currentRoute.getState(session.currentState.id);
280
+ if (currentState) {
281
+ const transitions = currentState.getTransitions();
282
+ const toolTransition = transitions.find((t) => t.spec.toolState);
283
+ if (toolTransition?.spec.toolState) {
284
+ const toolExecutor = new ToolExecutor_1.ToolExecutor();
285
+ // Get allowed domains from current route for security enforcement
286
+ const allowedDomains = currentRoute.getDomains();
287
+ const result = await toolExecutor.executeTool(toolTransition.spec.toolState, effectiveContext, this.updateContext.bind(this), history, session.extracted, allowedDomains);
288
+ // Update context with tool results
289
+ if (result.contextUpdate) {
290
+ await this.updateContext(result.contextUpdate);
291
+ }
292
+ // Update extracted data with tool results
293
+ if (result.extractedUpdate) {
294
+ session = await this.updateExtracted(session, result.extractedUpdate);
295
+ console.log(`[Agent] Tool updated extracted data:`, result.extractedUpdate);
296
+ }
297
+ console.log(`[Agent] Executed tool: ${result.toolName} (success: ${result.success})`);
298
+ }
299
+ }
300
+ }
235
301
  }
236
- // Build prompt (same as respond method)
237
- const promptBuilder = new PromptBuilder_1.PromptBuilder();
238
- // Add agent identity
239
- if (this.options.description) {
240
- promptBuilder.addAgentIdentity({
302
+ // PHASE 2: ROUTING - Determine which route to use
303
+ let selectedRoute;
304
+ let responseDirectives;
305
+ if (this.routes.length > 0) {
306
+ // Get last user message
307
+ const lastUserMessage = getLastMessageFromHistory(history);
308
+ // Build routing schema
309
+ const routingSchema = this.routingEngine.buildDynamicRoutingSchema(this.routes);
310
+ // Build routing prompt with session context
311
+ const routingPrompt = this.routingEngine.buildRoutingPrompt(history, this.routes, lastUserMessage, {
241
312
  name: this.options.name,
313
+ goal: this.options.goal,
242
314
  description: this.options.description,
315
+ personality: this.options.personality,
316
+ }, session // Pass session for context-aware routing
317
+ );
318
+ // Call AI to score routes (non-streaming for routing decision)
319
+ const routingResult = await this.options.ai.generateMessage({
320
+ prompt: routingPrompt,
321
+ history,
322
+ context: effectiveContext,
323
+ signal,
324
+ parameters: {
325
+ jsonSchema: routingSchema,
326
+ schemaName: "routing_output",
327
+ },
243
328
  });
244
- }
245
- // Add interaction history
246
- promptBuilder.addInteractionHistoryForMessageGeneration(history);
247
- // Add glossary
248
- if (this.terms.length > 0) {
249
- promptBuilder.addGlossary(this.terms);
250
- }
251
- // Add guidelines (convert to GuidelineMatch format, filter enabled only)
252
- const enabledGuidelines = this.guidelines.filter((g) => g.enabled !== false);
253
- if (enabledGuidelines.length > 0) {
254
- const guidelineMatches = enabledGuidelines.map((g) => ({
255
- guideline: g,
256
- }));
257
- promptBuilder.addGuidelinesForMessageGeneration(guidelineMatches);
258
- }
259
- // Add capabilities
260
- if (this.capabilities.length > 0) {
261
- promptBuilder.addCapabilitiesForMessageGeneration(this.capabilities);
262
- }
263
- // Add observations
264
- if (this.observations.length > 0) {
265
- const observationsWithRoutes = this.observations
266
- .map((obs) => ({
267
- description: obs.description,
268
- routes: obs.getRoutes().map((routeRef) => {
269
- const route = this.routes.find((r) => r.id === routeRef.id);
270
- return { title: route?.title || routeRef.id };
271
- }),
272
- }))
273
- .filter((obs) => obs.routes.length > 0);
274
- if (observationsWithRoutes.length > 0) {
275
- promptBuilder.addObservations(observationsWithRoutes);
329
+ // Select best route from scores
330
+ if (routingResult.structured?.routes) {
331
+ const decision = this.routingEngine.decideRouteFromScores({
332
+ context: routingResult.structured.context,
333
+ routes: routingResult.structured.routes,
334
+ responseDirectives: routingResult.structured.responseDirectives,
335
+ });
336
+ selectedRoute = this.routes.find((r) => r.id === decision.routeId);
337
+ responseDirectives = routingResult.structured.responseDirectives;
338
+ if (selectedRoute) {
339
+ console.log(`[Agent] Selected route: ${selectedRoute.title} (score: ${decision.maxScore})`);
340
+ // Update session with selected route (if changed)
341
+ if (!session.currentRoute ||
342
+ session.currentRoute.id !== selectedRoute.id) {
343
+ session = (0, session_1.enterRoute)(session, selectedRoute.id, selectedRoute.title);
344
+ // Merge initial data if provided by the route
345
+ if (selectedRoute.initialData) {
346
+ session = (0, session_1.mergeExtracted)(session, selectedRoute.initialData);
347
+ console.log(`[Agent] Merged initial data:`, selectedRoute.initialData);
348
+ }
349
+ console.log(`[Agent] Entered route: ${selectedRoute.title}`);
350
+ }
351
+ }
276
352
  }
277
353
  }
278
- // Add active routes with their rules and prohibitions
279
- if (this.routes.length > 0) {
280
- promptBuilder.addActiveRoutes(this.routes.map((r) => ({
281
- title: r.title,
282
- description: r.description,
283
- conditions: r.conditions,
284
- domains: r.getDomains(),
285
- rules: r.getRules(),
286
- prohibitions: r.getProhibitions(),
287
- })));
288
- }
289
- // NOTE: Domains/tools are NOT added to the prompt.
290
- // Tools execute automatically based on state transitions and guideline matching,
291
- // NOT based on AI decisions. The AI should never see available tools.
292
- // Add JSON response schema instructions
293
- promptBuilder.addJsonResponseSchema();
294
- // Build final prompt
295
- const prompt = promptBuilder.build();
296
- // Generate message stream using AI provider with JSON mode enabled
297
- const stream = this.options.ai.generateMessageStream({
298
- prompt,
299
- history,
300
- context: effectiveContext,
301
- signal,
302
- parameters: {
303
- jsonMode: true,
304
- },
305
- });
306
- // Stream chunks to caller
307
- for await (const chunk of stream) {
308
- // Extract route and state from structured response on final chunk
309
- let route = null;
310
- let state = null;
311
- let toolCalls;
312
- if (chunk.done && chunk.structured) {
313
- // Find route by title
314
- if (chunk.structured.route) {
315
- const foundRoute = this.routes.find((r) => r.title === chunk.structured?.route);
316
- if (foundRoute) {
317
- route = {
318
- id: foundRoute.id,
319
- title: foundRoute.title,
320
- };
354
+ // PHASE 3: RESPONSE - Stream message using selected route
355
+ if (selectedRoute) {
356
+ // Determine next state based on current extracted data
357
+ const currentStateRef = session.currentState;
358
+ const currentState = currentStateRef
359
+ ? selectedRoute.getState(currentStateRef.id)
360
+ : undefined;
361
+ const nextState = this.getNextState(selectedRoute, currentState, session.extracted);
362
+ // Update session with next state
363
+ session = (0, session_1.enterState)(session, nextState.id, nextState.description);
364
+ console.log(`[Agent] Entered state: ${nextState.id}`);
365
+ // Get last user message
366
+ const lastUserMessage = getLastMessageFromHistory(history);
367
+ // Build response schema for this route (with gather fields from state)
368
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextState);
369
+ // Build response prompt
370
+ const responsePrompt = this.responseEngine.buildResponsePrompt(selectedRoute, selectedRoute.getRules(), selectedRoute.getProhibitions(), responseDirectives, history, lastUserMessage, {
371
+ name: this.options.name,
372
+ goal: this.options.goal,
373
+ description: this.options.description,
374
+ personality: this.options.personality,
375
+ });
376
+ // Generate message stream using AI provider
377
+ const stream = this.options.ai.generateMessageStream({
378
+ prompt: responsePrompt,
379
+ history,
380
+ context: effectiveContext,
381
+ signal,
382
+ parameters: {
383
+ jsonSchema: responseSchema,
384
+ schemaName: "response_stream_output",
385
+ },
386
+ });
387
+ // Stream chunks to caller
388
+ for await (const chunk of stream) {
389
+ const toolCalls = undefined;
390
+ // Extract gathered data on final chunk
391
+ if (chunk.done && chunk.structured && nextState.gatherFields) {
392
+ const gatheredData = {};
393
+ // The structured response includes both base fields and gathered extraction fields
394
+ const structuredData = chunk.structured;
395
+ for (const field of nextState.gatherFields) {
396
+ if (field in structuredData) {
397
+ gatheredData[field] = structuredData[field];
398
+ }
399
+ }
400
+ // Merge gathered data into session
401
+ if (Object.keys(gatheredData).length > 0) {
402
+ session = await this.updateExtracted(session, gatheredData);
403
+ console.log(`[Agent] Extracted data:`, gatheredData);
321
404
  }
322
405
  }
323
- // Create state reference if provided
324
- if (chunk.structured.state) {
325
- state = {
326
- id: "dynamic_state",
327
- description: chunk.structured.state,
328
- };
406
+ // Extract any additional data from structured response on final chunk
407
+ if (chunk.done &&
408
+ chunk.structured &&
409
+ typeof chunk.structured === "object" &&
410
+ "contextUpdate" in chunk.structured) {
411
+ await this.updateContext(chunk.structured
412
+ .contextUpdate);
329
413
  }
330
- // Extract tool calls
331
- if (chunk.structured.toolCalls &&
332
- chunk.structured.toolCalls.length > 0) {
333
- toolCalls = chunk.structured.toolCalls;
414
+ // Auto-save session state on final chunk
415
+ if (chunk.done &&
416
+ this.persistenceManager &&
417
+ session.id &&
418
+ this.options.persistence?.autoSave !== false) {
419
+ await this.persistenceManager.saveSessionState(session.id, session);
420
+ console.log(`[Agent] Auto-saved session state to persistence: ${session.id}`);
334
421
  }
422
+ yield {
423
+ delta: chunk.delta,
424
+ accumulated: chunk.accumulated,
425
+ done: chunk.done,
426
+ session, // Return updated session
427
+ toolCalls,
428
+ };
429
+ }
430
+ }
431
+ else {
432
+ // Fallback: No routes defined, stream a simple response
433
+ const fallbackPrompt = new PromptComposer_1.PromptComposer()
434
+ .addAgentMeta({
435
+ name: this.options.name,
436
+ goal: this.options.goal,
437
+ description: this.options.description,
438
+ })
439
+ .addPersonality(this.options.personality)
440
+ .addInteractionHistory(history)
441
+ .addGlossary(this.terms)
442
+ .addGuidelines(this.guidelines)
443
+ .addCapabilities(this.capabilities)
444
+ .build();
445
+ const stream = this.options.ai.generateMessageStream({
446
+ prompt: fallbackPrompt,
447
+ history,
448
+ context: effectiveContext,
449
+ signal,
450
+ parameters: {
451
+ jsonSchema: {
452
+ type: "object",
453
+ properties: {
454
+ message: { type: "string" },
455
+ },
456
+ required: ["message"],
457
+ additionalProperties: false,
458
+ },
459
+ schemaName: "fallback_stream_response",
460
+ },
461
+ });
462
+ for await (const chunk of stream) {
463
+ yield {
464
+ delta: chunk.delta,
465
+ accumulated: chunk.accumulated,
466
+ done: chunk.done,
467
+ session, // Return updated session
468
+ toolCalls: undefined,
469
+ };
335
470
  }
336
- yield {
337
- delta: chunk.delta,
338
- accumulated: chunk.accumulated,
339
- done: chunk.done,
340
- route: route || undefined,
341
- state: state || undefined,
342
- toolCalls,
343
- };
344
471
  }
345
472
  }
346
473
  /**
@@ -357,142 +484,194 @@ class Agent {
357
484
  this.context = currentContext;
358
485
  }
359
486
  // Merge context with override
360
- let effectiveContext = {
487
+ const effectiveContext = {
361
488
  ...currentContext,
362
489
  ...contextOverride,
363
490
  };
364
- // RUN PREPARATION ITERATIONS
365
- // This is where tools execute automatically based on:
366
- // 1. Matched guidelines with associated tools
367
- // 2. State machine transitions with toolState
368
- //
369
- // The AI will NEVER see these tools - they execute before message generation
370
- const preparationResult = await this.preparationEngine.prepare({
371
- history,
372
- currentState: params.state,
373
- context: effectiveContext,
374
- routes: this.routes,
375
- guidelines: this.guidelines,
376
- maxIterations: this.options.maxEngineIterations || 1,
377
- });
378
- // Update context with results from tool executions
379
- effectiveContext = preparationResult.finalContext;
380
- // Persist updated context and trigger lifecycle hook
381
- const previousStoredContext = this.context;
382
- this.context = effectiveContext;
383
- if (this.options.hooks?.onContextUpdate &&
384
- previousStoredContext !== undefined) {
385
- await this.options.hooks.onContextUpdate(this.context, previousStoredContext);
386
- }
387
- // Log tool executions for debugging
388
- if (preparationResult.toolExecutions.length > 0) {
389
- console.log(`[Agent] Preparation complete: ${preparationResult.toolExecutions.length} tools executed in ${preparationResult.iterations.length} iterations`);
491
+ // Initialize or get session
492
+ let session = params.session || (0, session_1.createSession)();
493
+ // PHASE 1: TOOL EXECUTION - Execute tools if current state has toolState
494
+ if (session.currentRoute && session.currentState) {
495
+ const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
496
+ if (currentRoute) {
497
+ const currentState = currentRoute.getState(session.currentState.id);
498
+ if (currentState) {
499
+ const transitions = currentState.getTransitions();
500
+ const toolTransition = transitions.find((t) => t.spec.toolState);
501
+ if (toolTransition?.spec.toolState) {
502
+ const toolExecutor = new ToolExecutor_1.ToolExecutor();
503
+ // Get allowed domains from current route for security enforcement
504
+ const allowedDomains = currentRoute.getDomains();
505
+ const result = await toolExecutor.executeTool(toolTransition.spec.toolState, effectiveContext, this.updateContext.bind(this), history, session.extracted, allowedDomains);
506
+ // Update context with tool results
507
+ if (result.contextUpdate) {
508
+ await this.updateContext(result.contextUpdate);
509
+ }
510
+ // Update extracted data with tool results
511
+ if (result.extractedUpdate) {
512
+ session = await this.updateExtracted(session, result.extractedUpdate);
513
+ console.log(`[Agent] Tool updated extracted data:`, result.extractedUpdate);
514
+ }
515
+ console.log(`[Agent] Executed tool: ${result.toolName} (success: ${result.success})`);
516
+ }
517
+ }
518
+ }
390
519
  }
391
- // Build prompt
392
- const promptBuilder = new PromptBuilder_1.PromptBuilder();
393
- // Add agent identity
394
- if (this.options.description) {
395
- promptBuilder.addAgentIdentity({
520
+ // PHASE 2: ROUTING - Determine which route to use
521
+ let selectedRoute;
522
+ let responseDirectives;
523
+ if (this.routes.length > 0) {
524
+ // Get last user message
525
+ const lastUserMessage = getLastMessageFromHistory(history);
526
+ // Build routing schema
527
+ const routingSchema = this.routingEngine.buildDynamicRoutingSchema(this.routes);
528
+ // Build routing prompt with session context
529
+ const routingPrompt = this.routingEngine.buildRoutingPrompt(history, this.routes, lastUserMessage, {
396
530
  name: this.options.name,
531
+ goal: this.options.goal,
397
532
  description: this.options.description,
533
+ personality: this.options.personality,
534
+ }, session // Pass session for context-aware routing
535
+ );
536
+ // Call AI to score routes
537
+ const routingResult = await this.options.ai.generateMessage({
538
+ prompt: routingPrompt,
539
+ history,
540
+ context: effectiveContext,
541
+ signal,
542
+ parameters: {
543
+ jsonSchema: routingSchema,
544
+ schemaName: "routing_output",
545
+ },
398
546
  });
399
- }
400
- // Add interaction history
401
- promptBuilder.addInteractionHistoryForMessageGeneration(history);
402
- // Add glossary
403
- if (this.terms.length > 0) {
404
- promptBuilder.addGlossary(this.terms);
405
- }
406
- // Add guidelines (convert to GuidelineMatch format, filter enabled only)
407
- const enabledGuidelines = this.guidelines.filter((g) => g.enabled !== false);
408
- if (enabledGuidelines.length > 0) {
409
- const guidelineMatches = enabledGuidelines.map((g) => ({
410
- guideline: g,
411
- }));
412
- promptBuilder.addGuidelinesForMessageGeneration(guidelineMatches);
413
- }
414
- // Add capabilities
415
- if (this.capabilities.length > 0) {
416
- promptBuilder.addCapabilitiesForMessageGeneration(this.capabilities);
417
- }
418
- // Add observations
419
- if (this.observations.length > 0) {
420
- const observationsWithRoutes = this.observations
421
- .map((obs) => ({
422
- description: obs.description,
423
- routes: obs.getRoutes().map((routeRef) => {
424
- const route = this.routes.find((r) => r.id === routeRef.id);
425
- return { title: route?.title || routeRef.id };
426
- }),
427
- }))
428
- .filter((obs) => obs.routes.length > 0);
429
- if (observationsWithRoutes.length > 0) {
430
- promptBuilder.addObservations(observationsWithRoutes);
547
+ // Select best route from scores
548
+ if (routingResult.structured?.routes) {
549
+ const decision = this.routingEngine.decideRouteFromScores({
550
+ context: routingResult.structured.context,
551
+ routes: routingResult.structured.routes,
552
+ responseDirectives: routingResult.structured.responseDirectives,
553
+ });
554
+ selectedRoute = this.routes.find((r) => r.id === decision.routeId);
555
+ responseDirectives = routingResult.structured.responseDirectives;
556
+ if (selectedRoute) {
557
+ console.log(`[Agent] Selected route: ${selectedRoute.title} (score: ${decision.maxScore})`);
558
+ // Update session with selected route (if changed)
559
+ if (!session.currentRoute ||
560
+ session.currentRoute.id !== selectedRoute.id) {
561
+ session = (0, session_1.enterRoute)(session, selectedRoute.id, selectedRoute.title);
562
+ // Merge initial data if provided by the route
563
+ if (selectedRoute.initialData) {
564
+ session = (0, session_1.mergeExtracted)(session, selectedRoute.initialData);
565
+ console.log(`[Agent] Merged initial data:`, selectedRoute.initialData);
566
+ }
567
+ console.log(`[Agent] Entered route: ${selectedRoute.title}`);
568
+ }
569
+ }
431
570
  }
432
571
  }
433
- // Add active routes with their rules and prohibitions
434
- if (this.routes.length > 0) {
435
- promptBuilder.addActiveRoutes(this.routes.map((r) => ({
436
- title: r.title,
437
- description: r.description,
438
- conditions: r.conditions,
439
- domains: r.getDomains(),
440
- rules: r.getRules(),
441
- prohibitions: r.getProhibitions(),
442
- })));
443
- }
444
- // NOTE: Domains/tools are NOT added to the prompt.
445
- // Tools execute automatically based on state transitions and guideline matching,
446
- // NOT based on AI decisions. The AI should never see available tools.
447
- // Add JSON response schema instructions
448
- promptBuilder.addJsonResponseSchema();
449
- // Build final prompt
450
- const prompt = promptBuilder.build();
451
- // Generate message using AI provider with JSON mode enabled
452
- const result = await this.options.ai.generateMessage({
453
- prompt,
454
- history,
455
- context: effectiveContext,
456
- signal,
457
- parameters: {
458
- jsonMode: true,
459
- },
460
- });
461
- // Parse structured response
462
- let message = result.message;
463
- let route = null;
464
- let state = null;
465
- let toolCalls;
466
- if (result.structured) {
467
- // Extract data from structured response
468
- message = result.structured.message || message;
469
- // Find route by title
470
- if (result.structured.route) {
471
- const foundRoute = this.routes.find((r) => r.title === result.structured?.route);
472
- if (foundRoute) {
473
- route = {
474
- id: foundRoute.id,
475
- title: foundRoute.title,
476
- };
572
+ // PHASE 3: RESPONSE - Generate message using selected route
573
+ let message;
574
+ const toolCalls = undefined;
575
+ if (selectedRoute) {
576
+ // Determine next state based on current extracted data
577
+ const currentStateRef = session.currentState;
578
+ const currentState = currentStateRef
579
+ ? selectedRoute.getState(currentStateRef.id)
580
+ : undefined;
581
+ const nextState = this.getNextState(selectedRoute, currentState, session.extracted);
582
+ // Update session with next state
583
+ session = (0, session_1.enterState)(session, nextState.id, nextState.description);
584
+ console.log(`[Agent] Entered state: ${nextState.id}`);
585
+ // Get last user message
586
+ const lastUserMessage = getLastMessageFromHistory(history);
587
+ // Build response schema for this route (with gather fields from state)
588
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextState);
589
+ // Build response prompt
590
+ const responsePrompt = this.responseEngine.buildResponsePrompt(selectedRoute, selectedRoute.getRules(), selectedRoute.getProhibitions(), responseDirectives, history, lastUserMessage, {
591
+ name: this.options.name,
592
+ goal: this.options.goal,
593
+ description: this.options.description,
594
+ personality: this.options.personality,
595
+ });
596
+ // Generate message using AI provider
597
+ const result = await this.options.ai.generateMessage({
598
+ prompt: responsePrompt,
599
+ history,
600
+ context: effectiveContext,
601
+ signal,
602
+ parameters: {
603
+ jsonSchema: responseSchema,
604
+ schemaName: "response_output",
605
+ },
606
+ });
607
+ message = result.structured?.message || result.message;
608
+ // Extract gathered data from response
609
+ if (result.structured && nextState.gatherFields) {
610
+ const gatheredData = {};
611
+ // The structured response includes both base fields and gathered extraction fields
612
+ const structuredData = result.structured;
613
+ for (const field of nextState.gatherFields) {
614
+ if (field in structuredData) {
615
+ gatheredData[field] = structuredData[field];
616
+ }
617
+ }
618
+ // Merge gathered data into session
619
+ if (Object.keys(gatheredData).length > 0) {
620
+ session = (0, session_1.mergeExtracted)(session, gatheredData);
621
+ console.log(`[Agent] Extracted data:`, gatheredData);
477
622
  }
478
623
  }
479
- // Create state reference if provided
480
- if (result.structured.state) {
481
- state = {
482
- id: "dynamic_state",
483
- description: result.structured.state,
484
- };
485
- }
486
- // Extract tool calls
487
- if (result.structured.toolCalls &&
488
- result.structured.toolCalls.length > 0) {
489
- toolCalls = result.structured.toolCalls;
624
+ // Extract any additional data from structured response
625
+ if (result.structured &&
626
+ typeof result.structured === "object" &&
627
+ "contextUpdate" in result.structured) {
628
+ await this.updateContext(result.structured
629
+ .contextUpdate);
490
630
  }
491
631
  }
632
+ else {
633
+ // Fallback: No routes defined, generate a simple response
634
+ const fallbackPrompt = new PromptComposer_1.PromptComposer()
635
+ .addAgentMeta({
636
+ name: this.options.name,
637
+ goal: this.options.goal,
638
+ description: this.options.description,
639
+ })
640
+ .addPersonality(this.options.personality)
641
+ .addInteractionHistory(history)
642
+ .addGlossary(this.terms)
643
+ .addGuidelines(this.guidelines)
644
+ .addCapabilities(this.capabilities)
645
+ .build();
646
+ const result = await this.options.ai.generateMessage({
647
+ prompt: fallbackPrompt,
648
+ history,
649
+ context: effectiveContext,
650
+ signal,
651
+ parameters: {
652
+ jsonSchema: {
653
+ type: "object",
654
+ properties: {
655
+ message: { type: "string" },
656
+ },
657
+ required: ["message"],
658
+ additionalProperties: false,
659
+ },
660
+ schemaName: "fallback_response",
661
+ },
662
+ });
663
+ message = result.structured?.message || result.message;
664
+ }
665
+ // Auto-save session state to persistence if configured
666
+ if (this.persistenceManager &&
667
+ session.id &&
668
+ this.options.persistence?.autoSave !== false) {
669
+ await this.persistenceManager.saveSessionState(session.id, session);
670
+ console.log(`[Agent] Auto-saved session state to persistence: ${session.id}`);
671
+ }
492
672
  return {
493
673
  message,
494
- route: route || undefined,
495
- state: state || undefined,
674
+ session, // Return updated session with route/state info
496
675
  toolCalls,
497
676
  };
498
677
  }
@@ -520,12 +699,6 @@ class Agent {
520
699
  getCapabilities() {
521
700
  return [...this.capabilities];
522
701
  }
523
- /**
524
- * Get all observations
525
- */
526
- getObservations() {
527
- return [...this.observations];
528
- }
529
702
  /**
530
703
  * Get the domain registry
531
704
  */