@falai/agent 0.4.0 → 0.5.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 (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 +465 -275
  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 +57 -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 -9
  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 +72 -0
  78. package/dist/cjs/types/session.d.ts.map +1 -0
  79. package/dist/cjs/types/session.js +140 -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 +465 -275
  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 +57 -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 -9
  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 +72 -0
  167. package/dist/types/session.d.ts.map +1 -0
  168. package/dist/types/session.js +132 -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 +95 -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 +679 -332
  206. package/src/core/Events.ts +12 -2
  207. package/src/core/PersistenceManager.ts +83 -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 -10
  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 +207 -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 -105
  240. package/dist/cjs/core/PreparationEngine.d.ts.map +0 -1
  241. package/dist/cjs/core/PreparationEngine.js +0 -320
  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 -105
  264. package/dist/core/PreparationEngine.d.ts.map +0 -1
  265. package/dist/core/PreparationEngine.js +0 -316
  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 -500
  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,25 +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
40
- this.preparationEngine = new PreparationEngine_1.PreparationEngine(options.ai);
50
+ // Initialize routing and response engines
51
+ this.routingEngine = new RoutingEngine_1.RoutingEngine({
52
+ maxCandidates: 5,
53
+ allowRouteSwitch: true,
54
+ switchThreshold: 70,
55
+ });
56
+ this.responseEngine = new ResponseEngine_1.ResponseEngine();
41
57
  // Initialize persistence if configured
42
58
  if (options.persistence) {
43
59
  this.persistenceManager = new PersistenceManager_1.PersistenceManager(options.persistence);
@@ -67,23 +83,6 @@ class Agent {
67
83
  this.createRoute(routeOptions);
68
84
  });
69
85
  }
70
- if (options.observations) {
71
- options.observations.forEach((obsOptions) => {
72
- const obs = this.createObservation(obsOptions.description);
73
- // If route refs were provided, resolve and disambiguate
74
- if (obsOptions.routeRefs && obsOptions.routeRefs.length > 0) {
75
- const resolvedRoutes = obsOptions.routeRefs
76
- .map((ref) => {
77
- // Try to find route by ID or title
78
- return this.routes.find((r) => r.id === ref || r.title === ref);
79
- })
80
- .filter((r) => r !== undefined);
81
- if (resolvedRoutes.length > 0) {
82
- obs.disambiguate(resolvedRoutes);
83
- }
84
- }
85
- });
86
- }
87
86
  }
88
87
  /**
89
88
  * Get agent name
@@ -105,6 +104,7 @@ class Agent {
105
104
  }
106
105
  /**
107
106
  * Create a new route (journey)
107
+ * @template TExtracted - Type of data extracted throughout the route
108
108
  */
109
109
  createRoute(options) {
110
110
  const route = new Route_1.Route(options);
@@ -141,21 +141,28 @@ class Agent {
141
141
  this.capabilities.push(capabilityWithId);
142
142
  return this;
143
143
  }
144
- /**
145
- * Create an observation for disambiguation
146
- */
147
- createObservation(description) {
148
- const observation = new Observation_1.Observation({ description });
149
- this.observations.push(observation);
150
- return observation;
151
- }
152
144
  /**
153
145
  * Add a domain with its tools/methods
146
+ * Automatically tags all ToolRef objects with their domain name for security enforcement
154
147
  */
155
148
  addDomain(name, domainObject) {
156
- 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);
157
164
  // Attach to the domain property for easy access
158
- this.domain[name] = domainObject;
165
+ this.domain[name] = taggedDomain;
159
166
  }
160
167
  /**
161
168
  * Update the agent's context
@@ -173,6 +180,26 @@ class Agent {
173
180
  await this.options.hooks.onContextUpdate(this.context, previousContext);
174
181
  }
175
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
+ }
176
203
  /**
177
204
  * Get current context (fetches from provider if configured)
178
205
  * @internal
@@ -185,6 +212,46 @@ class Agent {
185
212
  // Otherwise return the stored context
186
213
  return this.context;
187
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
+ }
188
255
  /**
189
256
  * Generate a response based on history and context as a stream
190
257
  */
@@ -199,138 +266,208 @@ class Agent {
199
266
  this.context = currentContext;
200
267
  }
201
268
  // Merge context with override
202
- let effectiveContext = {
269
+ const effectiveContext = {
203
270
  ...currentContext,
204
271
  ...contextOverride,
205
272
  };
206
- // RUN PREPARATION ITERATIONS
207
- // This is where tools execute automatically based on:
208
- // 1. Matched guidelines with associated tools
209
- // 2. State machine transitions with toolState
210
- //
211
- // The AI will NEVER see these tools - they execute before message generation
212
- const preparationResult = await this.preparationEngine.prepare({
213
- history,
214
- currentState: params.state,
215
- context: effectiveContext,
216
- routes: this.routes,
217
- guidelines: this.guidelines,
218
- maxIterations: this.options.maxEngineIterations || 1,
219
- });
220
- // Update context with results from tool executions
221
- effectiveContext = preparationResult.finalContext;
222
- // Log tool executions for debugging
223
- if (preparationResult.toolExecutions.length > 0) {
224
- 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
+ }
225
301
  }
226
- // Build prompt (same as respond method)
227
- const promptBuilder = new PromptBuilder_1.PromptBuilder();
228
- // Add agent identity
229
- if (this.options.description) {
230
- 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, {
231
312
  name: this.options.name,
313
+ goal: this.options.goal,
232
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
+ },
233
328
  });
234
- }
235
- // Add interaction history
236
- promptBuilder.addInteractionHistoryForMessageGeneration(history);
237
- // Add glossary
238
- if (this.terms.length > 0) {
239
- promptBuilder.addGlossary(this.terms);
240
- }
241
- // Add guidelines (convert to GuidelineMatch format, filter enabled only)
242
- const enabledGuidelines = this.guidelines.filter((g) => g.enabled !== false);
243
- if (enabledGuidelines.length > 0) {
244
- const guidelineMatches = enabledGuidelines.map((g) => ({
245
- guideline: g,
246
- }));
247
- promptBuilder.addGuidelinesForMessageGeneration(guidelineMatches);
248
- }
249
- // Add capabilities
250
- if (this.capabilities.length > 0) {
251
- promptBuilder.addCapabilitiesForMessageGeneration(this.capabilities);
252
- }
253
- // Add observations
254
- if (this.observations.length > 0) {
255
- const observationsWithRoutes = this.observations
256
- .map((obs) => ({
257
- description: obs.description,
258
- routes: obs.getRoutes().map((routeRef) => {
259
- const route = this.routes.find((r) => r.id === routeRef.id);
260
- return { title: route?.title || routeRef.id };
261
- }),
262
- }))
263
- .filter((obs) => obs.routes.length > 0);
264
- if (observationsWithRoutes.length > 0) {
265
- 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
+ }
266
352
  }
267
353
  }
268
- // Add active routes with their rules and prohibitions
269
- if (this.routes.length > 0) {
270
- promptBuilder.addActiveRoutes(this.routes.map((r) => ({
271
- title: r.title,
272
- description: r.description,
273
- conditions: r.conditions,
274
- domains: r.getDomains(),
275
- rules: r.getRules(),
276
- prohibitions: r.getProhibitions(),
277
- })));
278
- }
279
- // NOTE: Domains/tools are NOT added to the prompt.
280
- // Tools execute automatically based on state transitions and guideline matching,
281
- // NOT based on AI decisions. The AI should never see available tools.
282
- // Add JSON response schema instructions
283
- promptBuilder.addJsonResponseSchema();
284
- // Build final prompt
285
- const prompt = promptBuilder.build();
286
- // Generate message stream using AI provider with JSON mode enabled
287
- const stream = this.options.ai.generateMessageStream({
288
- prompt,
289
- history,
290
- context: effectiveContext,
291
- signal,
292
- parameters: {
293
- jsonMode: true,
294
- },
295
- });
296
- // Stream chunks to caller
297
- for await (const chunk of stream) {
298
- // Extract route and state from structured response on final chunk
299
- let route = null;
300
- let state = null;
301
- let toolCalls;
302
- if (chunk.done && chunk.structured) {
303
- // Find route by title
304
- if (chunk.structured.route) {
305
- const foundRoute = this.routes.find((r) => r.title === chunk.structured?.route);
306
- if (foundRoute) {
307
- route = {
308
- id: foundRoute.id,
309
- title: foundRoute.title,
310
- };
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);
311
404
  }
312
405
  }
313
- // Create state reference if provided
314
- if (chunk.structured.state) {
315
- state = {
316
- id: "dynamic_state",
317
- description: chunk.structured.state,
318
- };
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);
319
413
  }
320
- // Extract tool calls
321
- if (chunk.structured.toolCalls &&
322
- chunk.structured.toolCalls.length > 0) {
323
- toolCalls = chunk.structured.toolCalls;
414
+ // Auto-save session state on final chunk
415
+ if (chunk.done &&
416
+ this.persistenceManager &&
417
+ session.metadata?.sessionId &&
418
+ this.options.persistence?.autoSave !== false) {
419
+ await this.persistenceManager.saveSessionState(session.metadata.sessionId, session);
420
+ console.log(`[Agent] Auto-saved session state to persistence: ${session.metadata.sessionId}`);
324
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
+ };
325
470
  }
326
- yield {
327
- delta: chunk.delta,
328
- accumulated: chunk.accumulated,
329
- done: chunk.done,
330
- route: route || undefined,
331
- state: state || undefined,
332
- toolCalls,
333
- };
334
471
  }
335
472
  }
336
473
  /**
@@ -347,135 +484,194 @@ class Agent {
347
484
  this.context = currentContext;
348
485
  }
349
486
  // Merge context with override
350
- let effectiveContext = {
487
+ const effectiveContext = {
351
488
  ...currentContext,
352
489
  ...contextOverride,
353
490
  };
354
- // RUN PREPARATION ITERATIONS
355
- // This is where tools execute automatically based on:
356
- // 1. Matched guidelines with associated tools
357
- // 2. State machine transitions with toolState
358
- //
359
- // The AI will NEVER see these tools - they execute before message generation
360
- const preparationResult = await this.preparationEngine.prepare({
361
- history,
362
- currentState: params.state,
363
- context: effectiveContext,
364
- routes: this.routes,
365
- guidelines: this.guidelines,
366
- maxIterations: this.options.maxEngineIterations || 1,
367
- });
368
- // Update context with results from tool executions
369
- effectiveContext = preparationResult.finalContext;
370
- // Log tool executions for debugging
371
- if (preparationResult.toolExecutions.length > 0) {
372
- 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
+ }
373
519
  }
374
- // Build prompt
375
- const promptBuilder = new PromptBuilder_1.PromptBuilder();
376
- // Add agent identity
377
- if (this.options.description) {
378
- 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, {
379
530
  name: this.options.name,
531
+ goal: this.options.goal,
380
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
+ },
381
546
  });
382
- }
383
- // Add interaction history
384
- promptBuilder.addInteractionHistoryForMessageGeneration(history);
385
- // Add glossary
386
- if (this.terms.length > 0) {
387
- promptBuilder.addGlossary(this.terms);
388
- }
389
- // Add guidelines (convert to GuidelineMatch format, filter enabled only)
390
- const enabledGuidelines = this.guidelines.filter((g) => g.enabled !== false);
391
- if (enabledGuidelines.length > 0) {
392
- const guidelineMatches = enabledGuidelines.map((g) => ({
393
- guideline: g,
394
- }));
395
- promptBuilder.addGuidelinesForMessageGeneration(guidelineMatches);
396
- }
397
- // Add capabilities
398
- if (this.capabilities.length > 0) {
399
- promptBuilder.addCapabilitiesForMessageGeneration(this.capabilities);
400
- }
401
- // Add observations
402
- if (this.observations.length > 0) {
403
- const observationsWithRoutes = this.observations
404
- .map((obs) => ({
405
- description: obs.description,
406
- routes: obs.getRoutes().map((routeRef) => {
407
- const route = this.routes.find((r) => r.id === routeRef.id);
408
- return { title: route?.title || routeRef.id };
409
- }),
410
- }))
411
- .filter((obs) => obs.routes.length > 0);
412
- if (observationsWithRoutes.length > 0) {
413
- 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
+ }
414
570
  }
415
571
  }
416
- // Add active routes with their rules and prohibitions
417
- if (this.routes.length > 0) {
418
- promptBuilder.addActiveRoutes(this.routes.map((r) => ({
419
- title: r.title,
420
- description: r.description,
421
- conditions: r.conditions,
422
- domains: r.getDomains(),
423
- rules: r.getRules(),
424
- prohibitions: r.getProhibitions(),
425
- })));
426
- }
427
- // NOTE: Domains/tools are NOT added to the prompt.
428
- // Tools execute automatically based on state transitions and guideline matching,
429
- // NOT based on AI decisions. The AI should never see available tools.
430
- // Add JSON response schema instructions
431
- promptBuilder.addJsonResponseSchema();
432
- // Build final prompt
433
- const prompt = promptBuilder.build();
434
- // Generate message using AI provider with JSON mode enabled
435
- const result = await this.options.ai.generateMessage({
436
- prompt,
437
- history,
438
- context: effectiveContext,
439
- signal,
440
- parameters: {
441
- jsonMode: true,
442
- },
443
- });
444
- // Parse structured response
445
- let message = result.message;
446
- let route = null;
447
- let state = null;
448
- let toolCalls;
449
- if (result.structured) {
450
- // Extract data from structured response
451
- message = result.structured.message || message;
452
- // Find route by title
453
- if (result.structured.route) {
454
- const foundRoute = this.routes.find((r) => r.title === result.structured?.route);
455
- if (foundRoute) {
456
- route = {
457
- id: foundRoute.id,
458
- title: foundRoute.title,
459
- };
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);
460
622
  }
461
623
  }
462
- // Create state reference if provided
463
- if (result.structured.state) {
464
- state = {
465
- id: "dynamic_state",
466
- description: result.structured.state,
467
- };
468
- }
469
- // Extract tool calls
470
- if (result.structured.toolCalls &&
471
- result.structured.toolCalls.length > 0) {
472
- 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);
473
630
  }
474
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.metadata?.sessionId &&
668
+ this.options.persistence?.autoSave !== false) {
669
+ await this.persistenceManager.saveSessionState(session.metadata.sessionId, session);
670
+ console.log(`[Agent] Auto-saved session state to persistence: ${session.metadata.sessionId}`);
671
+ }
475
672
  return {
476
673
  message,
477
- route: route || undefined,
478
- state: state || undefined,
674
+ session, // Return updated session with route/state info
479
675
  toolCalls,
480
676
  };
481
677
  }
@@ -503,12 +699,6 @@ class Agent {
503
699
  getCapabilities() {
504
700
  return [...this.capabilities];
505
701
  }
506
- /**
507
- * Get all observations
508
- */
509
- getObservations() {
510
- return [...this.observations];
511
- }
512
702
  /**
513
703
  * Get the domain registry
514
704
  */