@falai/agent 1.1.3 → 1.2.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 (193) hide show
  1. package/README.md +9 -0
  2. package/dist/cjs/core/Agent.d.ts +17 -1
  3. package/dist/cjs/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/core/Agent.js +47 -0
  5. package/dist/cjs/core/Agent.js.map +1 -1
  6. package/dist/cjs/core/BatchPromptBuilder.d.ts +3 -0
  7. package/dist/cjs/core/BatchPromptBuilder.d.ts.map +1 -1
  8. package/dist/cjs/core/BatchPromptBuilder.js +4 -1
  9. package/dist/cjs/core/BatchPromptBuilder.js.map +1 -1
  10. package/dist/cjs/core/CompactionEngine.d.ts +65 -0
  11. package/dist/cjs/core/CompactionEngine.d.ts.map +1 -0
  12. package/dist/cjs/core/CompactionEngine.js +251 -0
  13. package/dist/cjs/core/CompactionEngine.js.map +1 -0
  14. package/dist/cjs/core/PromptComposer.d.ts +8 -1
  15. package/dist/cjs/core/PromptComposer.d.ts.map +1 -1
  16. package/dist/cjs/core/PromptComposer.js +238 -126
  17. package/dist/cjs/core/PromptComposer.js.map +1 -1
  18. package/dist/cjs/core/PromptSectionCache.d.ts +57 -0
  19. package/dist/cjs/core/PromptSectionCache.d.ts.map +1 -0
  20. package/dist/cjs/core/PromptSectionCache.js +108 -0
  21. package/dist/cjs/core/PromptSectionCache.js.map +1 -0
  22. package/dist/cjs/core/ResponseEngine.d.ts +3 -2
  23. package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
  24. package/dist/cjs/core/ResponseEngine.js +8 -8
  25. package/dist/cjs/core/ResponseEngine.js.map +1 -1
  26. package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
  27. package/dist/cjs/core/ResponseModal.js +120 -70
  28. package/dist/cjs/core/ResponseModal.js.map +1 -1
  29. package/dist/cjs/core/ResponsePipeline.d.ts +2 -1
  30. package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
  31. package/dist/cjs/core/ResponsePipeline.js +17 -19
  32. package/dist/cjs/core/ResponsePipeline.js.map +1 -1
  33. package/dist/cjs/core/RoutingEngine.d.ts +10 -0
  34. package/dist/cjs/core/RoutingEngine.d.ts.map +1 -1
  35. package/dist/cjs/core/RoutingEngine.js +5 -4
  36. package/dist/cjs/core/RoutingEngine.js.map +1 -1
  37. package/dist/cjs/core/SessionManager.d.ts.map +1 -1
  38. package/dist/cjs/core/SessionManager.js +20 -0
  39. package/dist/cjs/core/SessionManager.js.map +1 -1
  40. package/dist/cjs/core/StreamingToolExecutor.d.ts +142 -0
  41. package/dist/cjs/core/StreamingToolExecutor.d.ts.map +1 -0
  42. package/dist/cjs/core/StreamingToolExecutor.js +455 -0
  43. package/dist/cjs/core/StreamingToolExecutor.js.map +1 -0
  44. package/dist/cjs/core/ToolManager.d.ts +18 -1
  45. package/dist/cjs/core/ToolManager.d.ts.map +1 -1
  46. package/dist/cjs/core/ToolManager.js +91 -0
  47. package/dist/cjs/core/ToolManager.js.map +1 -1
  48. package/dist/cjs/index.d.ts +5 -1
  49. package/dist/cjs/index.d.ts.map +1 -1
  50. package/dist/cjs/index.js +8 -2
  51. package/dist/cjs/index.js.map +1 -1
  52. package/dist/cjs/providers/AnthropicProvider.d.ts +7 -0
  53. package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -1
  54. package/dist/cjs/providers/AnthropicProvider.js +109 -19
  55. package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
  56. package/dist/cjs/providers/GeminiProvider.d.ts +32 -0
  57. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  58. package/dist/cjs/providers/GeminiProvider.js +160 -53
  59. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  60. package/dist/cjs/providers/OpenAIProvider.d.ts +5 -0
  61. package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
  62. package/dist/cjs/providers/OpenAIProvider.js +65 -18
  63. package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
  64. package/dist/cjs/providers/OpenRouterProvider.d.ts +5 -0
  65. package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
  66. package/dist/cjs/providers/OpenRouterProvider.js +57 -18
  67. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
  68. package/dist/cjs/types/agent.d.ts +44 -0
  69. package/dist/cjs/types/agent.d.ts.map +1 -1
  70. package/dist/cjs/types/agent.js.map +1 -1
  71. package/dist/cjs/types/ai.d.ts +2 -2
  72. package/dist/cjs/types/ai.d.ts.map +1 -1
  73. package/dist/cjs/types/compaction.d.ts +50 -0
  74. package/dist/cjs/types/compaction.d.ts.map +1 -0
  75. package/dist/cjs/types/compaction.js +6 -0
  76. package/dist/cjs/types/compaction.js.map +1 -0
  77. package/dist/cjs/types/index.d.ts +4 -2
  78. package/dist/cjs/types/index.d.ts.map +1 -1
  79. package/dist/cjs/types/index.js.map +1 -1
  80. package/dist/cjs/types/tool.d.ts +84 -0
  81. package/dist/cjs/types/tool.d.ts.map +1 -1
  82. package/dist/core/Agent.d.ts +17 -1
  83. package/dist/core/Agent.d.ts.map +1 -1
  84. package/dist/core/Agent.js +47 -0
  85. package/dist/core/Agent.js.map +1 -1
  86. package/dist/core/BatchPromptBuilder.d.ts +3 -0
  87. package/dist/core/BatchPromptBuilder.d.ts.map +1 -1
  88. package/dist/core/BatchPromptBuilder.js +4 -1
  89. package/dist/core/BatchPromptBuilder.js.map +1 -1
  90. package/dist/core/CompactionEngine.d.ts +65 -0
  91. package/dist/core/CompactionEngine.d.ts.map +1 -0
  92. package/dist/core/CompactionEngine.js +244 -0
  93. package/dist/core/CompactionEngine.js.map +1 -0
  94. package/dist/core/PromptComposer.d.ts +8 -1
  95. package/dist/core/PromptComposer.d.ts.map +1 -1
  96. package/dist/core/PromptComposer.js +238 -126
  97. package/dist/core/PromptComposer.js.map +1 -1
  98. package/dist/core/PromptSectionCache.d.ts +57 -0
  99. package/dist/core/PromptSectionCache.d.ts.map +1 -0
  100. package/dist/core/PromptSectionCache.js +104 -0
  101. package/dist/core/PromptSectionCache.js.map +1 -0
  102. package/dist/core/ResponseEngine.d.ts +3 -2
  103. package/dist/core/ResponseEngine.d.ts.map +1 -1
  104. package/dist/core/ResponseEngine.js +8 -8
  105. package/dist/core/ResponseEngine.js.map +1 -1
  106. package/dist/core/ResponseModal.d.ts.map +1 -1
  107. package/dist/core/ResponseModal.js +121 -71
  108. package/dist/core/ResponseModal.js.map +1 -1
  109. package/dist/core/ResponsePipeline.d.ts +2 -1
  110. package/dist/core/ResponsePipeline.d.ts.map +1 -1
  111. package/dist/core/ResponsePipeline.js +18 -20
  112. package/dist/core/ResponsePipeline.js.map +1 -1
  113. package/dist/core/RoutingEngine.d.ts +10 -0
  114. package/dist/core/RoutingEngine.d.ts.map +1 -1
  115. package/dist/core/RoutingEngine.js +6 -5
  116. package/dist/core/RoutingEngine.js.map +1 -1
  117. package/dist/core/SessionManager.d.ts.map +1 -1
  118. package/dist/core/SessionManager.js +17 -0
  119. package/dist/core/SessionManager.js.map +1 -1
  120. package/dist/core/StreamingToolExecutor.d.ts +142 -0
  121. package/dist/core/StreamingToolExecutor.d.ts.map +1 -0
  122. package/dist/core/StreamingToolExecutor.js +448 -0
  123. package/dist/core/StreamingToolExecutor.js.map +1 -0
  124. package/dist/core/ToolManager.d.ts +18 -1
  125. package/dist/core/ToolManager.d.ts.map +1 -1
  126. package/dist/core/ToolManager.js +91 -0
  127. package/dist/core/ToolManager.js.map +1 -1
  128. package/dist/index.d.ts +5 -1
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +3 -0
  131. package/dist/index.js.map +1 -1
  132. package/dist/providers/AnthropicProvider.d.ts +7 -0
  133. package/dist/providers/AnthropicProvider.d.ts.map +1 -1
  134. package/dist/providers/AnthropicProvider.js +109 -19
  135. package/dist/providers/AnthropicProvider.js.map +1 -1
  136. package/dist/providers/GeminiProvider.d.ts +32 -0
  137. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  138. package/dist/providers/GeminiProvider.js +160 -53
  139. package/dist/providers/GeminiProvider.js.map +1 -1
  140. package/dist/providers/OpenAIProvider.d.ts +5 -0
  141. package/dist/providers/OpenAIProvider.d.ts.map +1 -1
  142. package/dist/providers/OpenAIProvider.js +65 -18
  143. package/dist/providers/OpenAIProvider.js.map +1 -1
  144. package/dist/providers/OpenRouterProvider.d.ts +5 -0
  145. package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
  146. package/dist/providers/OpenRouterProvider.js +57 -18
  147. package/dist/providers/OpenRouterProvider.js.map +1 -1
  148. package/dist/types/agent.d.ts +44 -0
  149. package/dist/types/agent.d.ts.map +1 -1
  150. package/dist/types/agent.js.map +1 -1
  151. package/dist/types/ai.d.ts +2 -2
  152. package/dist/types/ai.d.ts.map +1 -1
  153. package/dist/types/compaction.d.ts +50 -0
  154. package/dist/types/compaction.d.ts.map +1 -0
  155. package/dist/types/compaction.js +5 -0
  156. package/dist/types/compaction.js.map +1 -0
  157. package/dist/types/index.d.ts +4 -2
  158. package/dist/types/index.d.ts.map +1 -1
  159. package/dist/types/index.js.map +1 -1
  160. package/dist/types/tool.d.ts +84 -0
  161. package/dist/types/tool.d.ts.map +1 -1
  162. package/docs/api/overview.md +140 -0
  163. package/docs/core/tools/enhanced-tool.md +186 -0
  164. package/docs/core/tools/streaming-execution.md +161 -0
  165. package/docs/guides/context-compaction.md +96 -0
  166. package/docs/guides/prompt-optimization.md +164 -0
  167. package/examples/advanced-patterns/context-compaction.ts +223 -0
  168. package/examples/advanced-patterns/streaming-responses.ts +85 -7
  169. package/examples/tools/enhanced-tool-metadata.ts +268 -0
  170. package/examples/tools/streaming-tool-execution.ts +283 -0
  171. package/package.json +1 -1
  172. package/src/core/Agent.ts +58 -2
  173. package/src/core/BatchPromptBuilder.ts +4 -1
  174. package/src/core/CompactionEngine.ts +318 -0
  175. package/src/core/PromptComposer.ts +259 -156
  176. package/src/core/PromptSectionCache.ts +136 -0
  177. package/src/core/ResponseEngine.ts +7 -11
  178. package/src/core/ResponseModal.ts +133 -83
  179. package/src/core/ResponsePipeline.ts +22 -22
  180. package/src/core/RoutingEngine.ts +16 -5
  181. package/src/core/SessionManager.ts +19 -0
  182. package/src/core/StreamingToolExecutor.ts +572 -0
  183. package/src/core/ToolManager.ts +151 -41
  184. package/src/index.ts +14 -0
  185. package/src/providers/AnthropicProvider.ts +121 -24
  186. package/src/providers/GeminiProvider.ts +174 -54
  187. package/src/providers/OpenAIProvider.ts +77 -25
  188. package/src/providers/OpenRouterProvider.ts +68 -25
  189. package/src/types/agent.ts +45 -0
  190. package/src/types/ai.ts +2 -2
  191. package/src/types/compaction.ts +52 -0
  192. package/src/types/index.ts +35 -14
  193. package/src/types/tool.ts +108 -0
@@ -10,6 +10,7 @@ import type {
10
10
  import type { Route } from "./Route";
11
11
  import type { Step } from "./Step";
12
12
  import { PromptComposer } from "./PromptComposer";
13
+ import { PromptSectionCache } from "./PromptSectionCache";
13
14
  import { createTemplateContext, render } from "../utils/template";
14
15
 
15
16
  export interface BuildResponsePromptParams<
@@ -22,7 +23,6 @@ export interface BuildResponsePromptParams<
22
23
  prohibitions: Template<TContext, TData>[];
23
24
  directives: string[] | undefined;
24
25
  history: Event[];
25
- lastMessage: string;
26
26
  agentOptions?: AgentOptions<TContext, TData>;
27
27
  // Combined properties from agent and route
28
28
  combinedGuidelines?: Guideline<TContext, TData>[];
@@ -34,7 +34,6 @@ export interface BuildResponsePromptParams<
34
34
  }
35
35
 
36
36
  export interface BuildFallbackPromptParams<TContext = unknown, TData = unknown> {
37
- history: Event[];
38
37
  agentOptions: AgentOptions<TContext, TData>;
39
38
  terms: Term<TContext, TData>[];
40
39
  guidelines: Guideline<TContext, TData>[];
@@ -43,6 +42,8 @@ export interface BuildFallbackPromptParams<TContext = unknown, TData = unknown>
43
42
  }
44
43
 
45
44
  export class ResponseEngine<TContext = unknown, TData = unknown> {
45
+ constructor(private readonly promptSectionCache?: PromptSectionCache) { }
46
+
46
47
  responseSchemaForRoute(
47
48
  route: Route<TContext, TData>,
48
49
  currentStep?: Step<TContext, TData>,
@@ -96,7 +97,6 @@ export class ResponseEngine<TContext = unknown, TData = unknown> {
96
97
  prohibitions,
97
98
  directives,
98
99
  history,
99
- lastMessage,
100
100
  agentOptions,
101
101
  combinedGuidelines,
102
102
  combinedTerms,
@@ -105,7 +105,7 @@ export class ResponseEngine<TContext = unknown, TData = unknown> {
105
105
  agentSchema,
106
106
  } = params;
107
107
  const templateContext = createTemplateContext({ context, session, history });
108
- const pc = new PromptComposer(templateContext);
108
+ const pc = new PromptComposer(templateContext, this.promptSectionCache);
109
109
 
110
110
  // Create combined agent options with route overrides
111
111
  let effectiveAgentOptions = agentOptions;
@@ -153,9 +153,6 @@ export class ResponseEngine<TContext = unknown, TData = unknown> {
153
153
  await pc.addGlossary(combinedTerms);
154
154
  }
155
155
 
156
- await pc.addInteractionHistory(history);
157
- await pc.addLastMessage(lastMessage);
158
-
159
156
  // Add data collection instructions - include ALL route fields, not just current step
160
157
  // Collect all fields from route's required and optional fields
161
158
  const allRouteFields = new Set<string>();
@@ -294,13 +291,12 @@ export class ResponseEngine<TContext = unknown, TData = unknown> {
294
291
  async buildFallbackPrompt(
295
292
  params: BuildFallbackPromptParams<TContext, TData>
296
293
  ): Promise<string> {
297
- const { history, agentOptions, terms, guidelines, context, session } =
294
+ const { agentOptions, terms, guidelines, context, session } =
298
295
  params;
299
- const templateContext = createTemplateContext({ context, session, history });
300
- const pc = new PromptComposer(templateContext);
296
+ const templateContext = createTemplateContext({ context, session });
297
+ const pc = new PromptComposer(templateContext, this.promptSectionCache);
301
298
 
302
299
  await pc.addAgentMeta(agentOptions);
303
- await pc.addInteractionHistory(history);
304
300
  await pc.addGlossary(terms);
305
301
  await pc.addGuidelines(guidelines);
306
302
  await pc.addKnowledgeBase(agentOptions.knowledgeBase);
@@ -12,12 +12,11 @@ import type {
12
12
  HistoryItem,
13
13
  Tool,
14
14
  Event,
15
- ToolEventData,
16
15
  AgentStructuredResponse,
17
16
  Term,
18
17
  StoppedReason,
18
+ ToolCallRequest,
19
19
  } from "../types";
20
- import { EventKind, MessageRole } from "../types";
21
20
  import type { Agent } from "./Agent";
22
21
  import type { Route } from "./Route";
23
22
  import { Step } from "./Step";
@@ -25,7 +24,7 @@ import { ResponseEngine } from "./ResponseEngine";
25
24
  import { ResponsePipeline } from "./ResponsePipeline";
26
25
  import { BatchExecutor, type HookFunction } from "./BatchExecutor";
27
26
  import { BatchPromptBuilder } from "./BatchPromptBuilder";
28
- import { cloneDeep, mergeCollected, enterStep, getLastMessageFromHistory, render, logger, historyToEvents } from "../utils";
27
+ import { cloneDeep, mergeCollected, enterStep, getLastMessageFromHistory, render, logger, historyToEvents, eventsToHistory } from "../utils";
29
28
  import { createTemplateContext } from "../utils/template";
30
29
  import type { ToolManager } from "./ToolManager";
31
30
  import { END_ROUTE_ID } from "../constants";
@@ -157,7 +156,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
157
156
  private readonly options?: ResponseModalOptions
158
157
  ) {
159
158
  // Initialize response engine
160
- this.responseEngine = new ResponseEngine<TContext, TData>();
159
+ this.responseEngine = new ResponseEngine<TContext, TData>(this.agent.promptSectionCache);
161
160
 
162
161
  // Initialize response pipeline with agent dependencies
163
162
  this.responsePipeline = new ResponsePipeline<TContext, TData>(
@@ -175,7 +174,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
175
174
  this.batchExecutor = new BatchExecutor<TContext, TData>();
176
175
 
177
176
  // Initialize batch prompt builder for combined prompts
178
- this.batchPromptBuilder = new BatchPromptBuilder<TContext, TData>();
177
+ this.batchPromptBuilder = new BatchPromptBuilder<TContext, TData>(this.agent.promptSectionCache);
179
178
  }
180
179
 
181
180
  /**
@@ -668,12 +667,15 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
668
667
  `Return ONLY the extracted data as JSON. If no data can be extracted, return an empty object {}.`
669
668
  );
670
669
 
670
+ // Convert Event[] to HistoryItem[] for provider call
671
+ const historyItems = eventsToHistory(history);
672
+
671
673
  // Call AI to extract data
672
674
  const agentOptions = this.agent.getAgentOptions();
673
675
  try {
674
676
  const result = await agentOptions.provider.generateMessage<TContext, Partial<TData>>({
675
677
  prompt: extractionPrompt.join('\n'),
676
- history,
678
+ history: historyItems,
677
679
  context: {} as TContext, // Passed as empty object so AI doesn't "extract" from context
678
680
  // NOTE: context is intentionally NOT passed here.
679
681
  // Passing context caused the AI to "extract" data from the lead's context
@@ -715,7 +717,6 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
715
717
  // Get last user message (needed for both route and completion handling)
716
718
  // Convert HistoryItem[] to Event[] for internal processing
717
719
  const historyEvents = historyToEvents(history);
718
- const lastMessageText = getLastMessageFromHistory(historyEvents);
719
720
 
720
721
  let message: string;
721
722
  let toolCalls: Array<{ toolName: string; arguments: Record<string, unknown> }> | undefined = undefined;
@@ -756,7 +757,6 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
756
757
  session,
757
758
  history,
758
759
  context: effectiveContext,
759
- lastMessageText,
760
760
  historyEvents,
761
761
  signal: undefined,
762
762
  });
@@ -784,7 +784,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
784
784
  selectedRoute,
785
785
  session,
786
786
  context: effectiveContext,
787
- lastMessageText,
787
+ history,
788
788
  historyEvents,
789
789
  signal: undefined,
790
790
  });
@@ -805,7 +805,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
805
805
  // Fallback: No routes defined, generate a simple response
806
806
 
807
807
  message = await this.generateFallbackResponse({
808
- history: historyEvents, // Use Event[] for fallback response
808
+ history,
809
809
  context: effectiveContext,
810
810
  session,
811
811
  });
@@ -925,7 +925,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
925
925
  const agentOptions = this.agent.getAgentOptions();
926
926
  const result = await agentOptions.provider.generateMessage({
927
927
  prompt: batchPromptResult.prompt,
928
- history: historyEvents,
928
+ history, // Use HistoryItem[] for AI provider
929
929
  context,
930
930
  tools: availableTools,
931
931
  signal,
@@ -1124,7 +1124,6 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1124
1124
  // Get last user message (needed for both route and completion handling)
1125
1125
  // Convert HistoryItem[] to Event[] for internal processing
1126
1126
  const historyEvents = historyToEvents(history);
1127
- const lastMessageText = getLastMessageFromHistory(historyEvents);
1128
1127
 
1129
1128
  if (selectedRoute && !isRouteComplete) {
1130
1129
  // Check if we have batch steps to execute
@@ -1152,7 +1151,6 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1152
1151
  session,
1153
1152
  history,
1154
1153
  context: effectiveContext,
1155
- lastMessageText,
1156
1154
  historyEvents,
1157
1155
  });
1158
1156
  }
@@ -1163,14 +1161,14 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1163
1161
  selectedRoute,
1164
1162
  session,
1165
1163
  context: effectiveContext,
1166
- lastMessageText,
1164
+ history,
1167
1165
  historyEvents,
1168
1166
  });
1169
1167
 
1170
1168
  } else {
1171
1169
  // Fallback: No routes defined, stream a simple response
1172
1170
  yield* this.streamFallbackResponse({
1173
- history: historyEvents, // Use Event[] for fallback response
1171
+ history,
1174
1172
  context: effectiveContext,
1175
1173
  session,
1176
1174
  });
@@ -1195,7 +1193,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1195
1193
  batchStoppedReason?: StoppedReason;
1196
1194
  signal?: AbortSignal;
1197
1195
  }): AsyncGenerator<AgentResponseStreamChunk<TData>> {
1198
- const { selectedRoute, batchSteps, context, historyEvents, batchStoppedReason, signal } = params;
1196
+ const { selectedRoute, batchSteps, history, context, historyEvents, batchStoppedReason, signal } = params;
1199
1197
  let session = params.session;
1200
1198
 
1201
1199
  // Create hook executor function
@@ -1250,7 +1248,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1250
1248
  const agentOptions = this.agent.getAgentOptions();
1251
1249
  const stream = agentOptions.provider.generateMessageStream({
1252
1250
  prompt: batchPromptResult.prompt,
1253
- history: historyEvents,
1251
+ history, // Use HistoryItem[] for AI provider
1254
1252
  context,
1255
1253
  tools: availableTools,
1256
1254
  signal,
@@ -1379,17 +1377,16 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1379
1377
  selectedStep?: Step<TContext, TData>;
1380
1378
  responseDirectives?: string[];
1381
1379
  session: SessionState<TData>;
1382
- history: HistoryItem[]; // Keep as HistoryItem[] for AI provider compatibility
1380
+ history: HistoryItem[];
1383
1381
  context: TContext;
1384
- lastMessageText: string; // String version for buildResponsePrompt
1385
- historyEvents: Event[]; // Event[] version for buildResponsePrompt
1382
+ historyEvents: Event[];
1386
1383
  signal?: AbortSignal;
1387
1384
  }): Promise<{
1388
1385
  message: string;
1389
1386
  toolCalls?: Array<{ toolName: string; arguments: Record<string, unknown> }>;
1390
1387
  session: SessionState<TData>;
1391
1388
  }> {
1392
- const { selectedRoute, selectedStep, responseDirectives, history, context, lastMessageText, historyEvents, signal } = params;
1389
+ const { selectedRoute, selectedStep, responseDirectives, history, context, historyEvents, signal } = params;
1393
1390
  let session = params.session;
1394
1391
 
1395
1392
  // Determine next step
@@ -1465,8 +1462,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1465
1462
  rules: selectedRoute.getRules(),
1466
1463
  prohibitions: selectedRoute.getProhibitions(),
1467
1464
  directives: responseDirectives,
1468
- history: historyEvents, // Use Event[] for buildResponsePrompt
1469
- lastMessage: lastMessageText, // Use string for buildResponsePrompt
1465
+ history: historyEvents,
1470
1466
  agentOptions: this.agent.getAgentOptions(),
1471
1467
  combinedGuidelines: [...this.agent.getGuidelines(), ...selectedRoute.getGuidelines()],
1472
1468
  combinedTerms: this.mergeTerms(this.agent.getTerms(), selectedRoute.getTerms()),
@@ -1482,7 +1478,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1482
1478
  const agentOptions = this.agent.getAgentOptions();
1483
1479
  const result = await agentOptions.provider.generateMessage({
1484
1480
  prompt: responsePrompt,
1485
- history: historyEvents, // Use Event[] for AI provider
1481
+ history, // Use HistoryItem[] for AI provider
1486
1482
  context,
1487
1483
  tools: availableTools,
1488
1484
  signal,
@@ -1537,11 +1533,10 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1537
1533
  session: SessionState<TData>;
1538
1534
  history: HistoryItem[];
1539
1535
  context: TContext;
1540
- lastMessageText: string; // String version for buildResponsePrompt
1541
- historyEvents: Event[]; // Event[] version for buildResponsePrompt
1536
+ historyEvents: Event[];
1542
1537
  signal?: AbortSignal;
1543
1538
  }): AsyncGenerator<AgentResponseStreamChunk<TData>> {
1544
- const { selectedRoute, selectedStep, responseDirectives, history, context, lastMessageText, historyEvents, signal } = params;
1539
+ const { selectedRoute, selectedStep, responseDirectives, history, context, historyEvents, signal } = params;
1545
1540
  let session = params.session;
1546
1541
 
1547
1542
  // Determine next step (same logic as non-streaming)
@@ -1608,8 +1603,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1608
1603
  rules: selectedRoute.getRules(),
1609
1604
  prohibitions: selectedRoute.getProhibitions(),
1610
1605
  directives: responseDirectives,
1611
- history: historyEvents, // Use Event[] for buildResponsePrompt
1612
- lastMessage: lastMessageText, // Use string for buildResponsePrompt
1606
+ history: historyEvents,
1613
1607
  agentOptions: this.agent.getAgentOptions(),
1614
1608
  combinedGuidelines: [...this.agent.getGuidelines(), ...selectedRoute.getGuidelines()],
1615
1609
  combinedTerms: this.mergeTerms(this.agent.getTerms(), selectedRoute.getTerms()),
@@ -1625,7 +1619,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1625
1619
  const agentOptions = this.agent.getAgentOptions();
1626
1620
  const stream = agentOptions.provider.generateMessageStream({
1627
1621
  prompt: responsePrompt,
1628
- history: historyEvents, // Use Event[] for AI provider
1622
+ history, // Use HistoryItem[] for AI provider
1629
1623
  context,
1630
1624
  tools: availableTools,
1631
1625
  signal,
@@ -1640,21 +1634,81 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1640
1634
  if (chunk.done && chunk.structured?.toolCalls) {
1641
1635
  toolCalls = chunk.structured.toolCalls;
1642
1636
 
1643
- // Execute tools with unified loop handling
1644
- const toolResult = await this.executeUnifiedToolLoop({
1645
- toolCalls,
1646
- context,
1647
- session,
1648
- history,
1649
- selectedRoute,
1650
- responsePrompt,
1651
- availableTools,
1652
- responseSchema,
1653
- signal,
1654
- });
1637
+ const toolManager = this.getToolManager();
1638
+
1639
+ // Use concurrent execution for the initial batch of tool calls
1640
+ if (toolManager && typeof toolManager.executeWithConcurrency === 'function') {
1641
+ const toolCallRequests: ToolCallRequest[] = toolCalls.map((tc, i) => ({
1642
+ id: `${tc.toolName}-${i}-${Date.now()}`,
1643
+ toolName: tc.toolName,
1644
+ arguments: tc.arguments,
1645
+ }));
1646
+
1647
+ const historyEvents = historyToEvents(history);
1648
+
1649
+ try {
1650
+ for await (const update of toolManager.executeWithConcurrency({
1651
+ toolCalls: toolCallRequests,
1652
+ context,
1653
+ data: session.data,
1654
+ history: historyEvents,
1655
+ signal,
1656
+ route: selectedRoute,
1657
+ step: nextStep,
1658
+ })) {
1659
+ // Apply context updates
1660
+ if (update.contextUpdate) {
1661
+ try {
1662
+ await this.agent.updateContext(update.contextUpdate as Partial<TContext>);
1663
+ } catch (error) {
1664
+ logger.error(`[ResponseModal] Failed to update context from concurrent tool:`, error);
1665
+ }
1666
+ }
1655
1667
 
1656
- session = toolResult.session;
1657
- toolCalls = toolResult.finalToolCalls;
1668
+ // Apply data updates
1669
+ if (update.dataUpdate) {
1670
+ try {
1671
+ const updateDataMethod = this.agent.getUpdateDataMethod();
1672
+ session = await updateDataMethod(session, update.dataUpdate);
1673
+ } catch (error) {
1674
+ logger.error(`[ResponseModal] Failed to update data from concurrent tool:`, error);
1675
+ }
1676
+ }
1677
+
1678
+ // Yield progress updates immediately
1679
+ if (update.progress) {
1680
+ yield {
1681
+ delta: '',
1682
+ accumulated: chunk.accumulated,
1683
+ done: false,
1684
+ session,
1685
+ toolCalls: undefined,
1686
+ isRouteComplete: false,
1687
+ metadata: { toolProgress: update.progress, toolCallId: update.toolCallId },
1688
+ };
1689
+ }
1690
+ }
1691
+
1692
+ logger.debug(`[ResponseModal] Concurrent tool execution completed for ${toolCallRequests.length} tools`);
1693
+ } catch (error) {
1694
+ logger.error(`[ResponseModal] Concurrent tool execution failed, falling back to sequential:`, error);
1695
+ // Fall back to the unified tool loop on failure
1696
+ const toolResult = await this.executeUnifiedToolLoop({
1697
+ toolCalls, context, session, history, selectedRoute,
1698
+ responsePrompt, availableTools, responseSchema, signal,
1699
+ });
1700
+ session = toolResult.session;
1701
+ toolCalls = toolResult.finalToolCalls;
1702
+ }
1703
+ } else {
1704
+ // Fallback: no ToolManager or no executeWithConcurrency, use unified tool loop
1705
+ const toolResult = await this.executeUnifiedToolLoop({
1706
+ toolCalls, context, session, history, selectedRoute,
1707
+ responsePrompt, availableTools, responseSchema, signal,
1708
+ });
1709
+ session = toolResult.session;
1710
+ toolCalls = toolResult.finalToolCalls;
1711
+ }
1658
1712
  }
1659
1713
 
1660
1714
  // Extract collected data on final chunk
@@ -1802,34 +1856,34 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1802
1856
  toolLoopCount++;
1803
1857
  logger.debug(`[ResponseModal] Starting tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS} with ${toolCalls?.length || 0} tool calls`);
1804
1858
 
1805
- // Create tool result events with proper Event format structure
1806
- const toolResultEvents: Event<ToolEventData>[] = [];
1859
+ // Create tool result history items
1860
+ const toolResultHistoryItems: HistoryItem[] = [];
1807
1861
  for (const toolCall of toolCalls || []) {
1808
1862
  const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
1809
1863
  if (tool) {
1810
- // Create proper Event format for tool results
1811
- const toolResultEvent: Event<ToolEventData> = {
1812
- kind: EventKind.TOOL,
1813
- source: MessageRole.AGENT,
1814
- timestamp: new Date().toISOString(),
1815
- data: {
1816
- tool_calls: [
1817
- {
1818
- tool_id: toolCall.toolName,
1819
- arguments: toolCall.arguments,
1820
- result: {
1821
- data: "Tool executed successfully",
1822
- },
1823
- },
1824
- ],
1825
- },
1826
- };
1827
- toolResultEvents.push(toolResultEvent);
1864
+ // Create HistoryItem format for tool results
1865
+ // Add assistant message with tool_calls
1866
+ toolResultHistoryItems.push({
1867
+ role: "assistant" as const,
1868
+ content: null,
1869
+ tool_calls: [{
1870
+ id: toolCall.toolName,
1871
+ name: toolCall.toolName,
1872
+ arguments: toolCall.arguments,
1873
+ }],
1874
+ });
1875
+ // Add tool result
1876
+ toolResultHistoryItems.push({
1877
+ role: "tool" as const,
1878
+ tool_call_id: toolCall.toolName,
1879
+ name: toolCall.toolName,
1880
+ content: "Tool executed successfully",
1881
+ });
1828
1882
  }
1829
1883
  }
1830
1884
 
1831
- // Create updated history with tool results (combine Event arrays)
1832
- const updatedHistoryEvents = [...historyEvents, ...toolResultEvents];
1885
+ // Create updated history with tool results
1886
+ const updatedHistory = [...history, ...toolResultHistoryItems];
1833
1887
 
1834
1888
  // Make follow-up AI call to see if more tools are needed
1835
1889
  // After first iteration, don't provide tools to force a text response
@@ -1844,7 +1898,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1844
1898
 
1845
1899
  const followUpResult = await agentOptions.provider.generateMessage({
1846
1900
  prompt: responsePrompt + (toolLoopCount > 1 ? "\n\nProvide a text response to the user based on the tool results." : ""),
1847
- history: updatedHistoryEvents, // Use Event[] for AI provider
1901
+ history: updatedHistory, // Use HistoryItem[] for AI provider
1848
1902
  context,
1849
1903
  tools: shouldProvideTools ? availableTools : [], // Only provide tools on first iteration
1850
1904
  parameters: responseSchema ? {
@@ -1888,7 +1942,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1888
1942
  context,
1889
1943
  updateContext: this.agent.updateContext.bind(this.agent),
1890
1944
  updateData: this.agent.updateCollectedData.bind(this.agent),
1891
- history: updatedHistoryEvents, // Use Event[] for tool execution
1945
+ history: historyToEvents(updatedHistory), // Convert to Event[] for tool execution
1892
1946
  data: session.data,
1893
1947
  toolArguments: toolCall.arguments,
1894
1948
  });
@@ -2060,11 +2114,11 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
2060
2114
  selectedRoute: Route<TContext, TData>;
2061
2115
  session: SessionState<TData>;
2062
2116
  context: TContext;
2063
- lastMessageText: string; // String version for buildResponsePrompt
2064
- historyEvents: Event[]; // Event[] version for buildResponsePrompt
2117
+ history: HistoryItem[];
2118
+ historyEvents: Event[];
2065
2119
  signal?: AbortSignal;
2066
2120
  }): Promise<string> {
2067
- const { selectedRoute, session, context, lastMessageText, historyEvents, signal } = params;
2121
+ const { selectedRoute, session, context, history, historyEvents, signal } = params;
2068
2122
 
2069
2123
  // Get endStep spec from route
2070
2124
  const endStepSpec = selectedRoute.endStepSpec;
@@ -2120,7 +2174,6 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
2120
2174
  completitionPrompt,
2121
2175
  ],
2122
2176
  history: historyEvents,
2123
- lastMessage: lastMessageText,
2124
2177
  agentOptions: this.agent.getAgentOptions(),
2125
2178
  combinedGuidelines: alwaysActiveGuidelines, // Only non-conditional guidelines
2126
2179
  combinedTerms: this.mergeTerms(this.agent.getTerms(), selectedRoute.getTerms()),
@@ -2135,7 +2188,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
2135
2188
 
2136
2189
  const completionResult = await agentOptions.provider.generateMessage({
2137
2190
  prompt: completionPrompt,
2138
- history: historyEvents,
2191
+ history, // Use HistoryItem[] for AI provider
2139
2192
  context,
2140
2193
  signal,
2141
2194
  parameters: { jsonSchema: completionSchema, schemaName: "completion_message" },
@@ -2179,11 +2232,11 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
2179
2232
  selectedRoute: Route<TContext, TData>;
2180
2233
  session: SessionState<TData>;
2181
2234
  context: TContext;
2182
- lastMessageText: string; // String version for buildResponsePrompt
2183
- historyEvents: Event[]; // Event[] version for buildResponsePrompt
2235
+ history: HistoryItem[];
2236
+ historyEvents: Event[];
2184
2237
  signal?: AbortSignal;
2185
2238
  }): AsyncGenerator<AgentResponseStreamChunk<TData>> {
2186
- const { selectedRoute, context, lastMessageText, historyEvents, signal } = params;
2239
+ const { selectedRoute, context, history, historyEvents, signal } = params;
2187
2240
  let session = params.session;
2188
2241
 
2189
2242
  // Get endStep spec from route
@@ -2209,8 +2262,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
2209
2262
  rules: selectedRoute.getRules(),
2210
2263
  prohibitions: selectedRoute.getProhibitions(),
2211
2264
  directives: undefined, // No directives for completion
2212
- history: historyEvents, // Use Event[] for buildResponsePrompt
2213
- lastMessage: lastMessageText, // Use string for buildResponsePrompt
2265
+ history: historyEvents,
2214
2266
  agentOptions: this.agent.getAgentOptions(),
2215
2267
  combinedGuidelines: [...this.agent.getGuidelines(), ...selectedRoute.getGuidelines()],
2216
2268
  combinedTerms: this.mergeTerms(this.agent.getTerms(), selectedRoute.getTerms()),
@@ -2223,7 +2275,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
2223
2275
  const agentOptions = this.agent.getAgentOptions();
2224
2276
  const stream = agentOptions.provider.generateMessageStream({
2225
2277
  prompt: completionPrompt,
2226
- history: historyEvents, // Use Event[] for AI provider
2278
+ history, // Use HistoryItem[] for AI provider
2227
2279
  context,
2228
2280
  signal,
2229
2281
  parameters: { jsonSchema: responseSchema, schemaName: "completion_message_stream" },
@@ -2292,7 +2344,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
2292
2344
  * @private
2293
2345
  */
2294
2346
  private async generateFallbackResponse(params: {
2295
- history: Event[]; // Use Event[] for buildFallbackPrompt
2347
+ history: HistoryItem[];
2296
2348
  context: TContext;
2297
2349
  session: SessionState<TData>;
2298
2350
  signal?: AbortSignal;
@@ -2303,7 +2355,6 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
2303
2355
 
2304
2356
  // Build basic response prompt without route context
2305
2357
  const fallbackPrompt = await this.responseEngine.buildFallbackPrompt({
2306
- history,
2307
2358
  agentOptions: this.agent.getAgentOptions(),
2308
2359
  terms: this.agent.getTerms(),
2309
2360
  guidelines: this.agent.getGuidelines(),
@@ -2336,7 +2387,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
2336
2387
  * @private
2337
2388
  */
2338
2389
  private async *streamFallbackResponse(params: {
2339
- history: Event[]; // Use Event[] for buildFallbackPrompt
2390
+ history: HistoryItem[];
2340
2391
  context: TContext;
2341
2392
  session: SessionState<TData>;
2342
2393
  signal?: AbortSignal;
@@ -2344,7 +2395,6 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
2344
2395
  const { history, context, session, signal } = params;
2345
2396
 
2346
2397
  const fallbackPrompt = await this.responseEngine.buildFallbackPrompt({
2347
- history,
2348
2398
  agentOptions: this.agent.getAgentOptions(),
2349
2399
  terms: this.agent.getTerms(),
2350
2400
  guidelines: this.agent.getGuidelines(),
@@ -10,7 +10,7 @@ import type {
10
10
  Tool,
11
11
  RouteTransitionConfig,
12
12
  } from "../types";
13
- import { EventKind, MessageRole } from "../types/history";
13
+ import type { HistoryItem } from "../types/history";
14
14
  import {
15
15
  createSession,
16
16
  enterRoute,
@@ -18,6 +18,7 @@ import {
18
18
  mergeCollected,
19
19
  logger,
20
20
  render,
21
+ historyToEvents,
21
22
  } from "../utils";
22
23
  import { createTemplateContext } from "../utils/template";
23
24
  import { Route } from "../core/Route";
@@ -171,7 +172,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
171
172
  };
172
173
  }
173
174
  }
174
-
175
+
175
176
  // If no pending transition or transition handled, do normal routing
176
177
  if (routes.length > 0 && !selectedRoute) {
177
178
  const orchestration = await this.routingEngine.decideRouteAndStep({
@@ -242,7 +243,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
242
243
  currentStep, // Pass current step instead of undefined to maintain progression
243
244
  createTemplateContext({ data: session.data, session, context: contextToUse })
244
245
  );
245
-
246
+
246
247
  if (candidates.length > 0) {
247
248
  nextStep = candidates[0].step;
248
249
  logger.debug(
@@ -368,7 +369,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
368
369
  selectedRoute?: Route<TContext, TData>;
369
370
  nextStep: Step<TContext, TData>;
370
371
  responsePrompt: string;
371
- history: Event[];
372
+ history: HistoryItem[];
372
373
  context: TContext;
373
374
  session: SessionState<TData>;
374
375
  responseSchema: Record<string, unknown>;
@@ -400,31 +401,30 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
400
401
  );
401
402
 
402
403
  // Add tool execution results to history so AI knows what happened
403
- const toolResultsEvents: Event[] = [];
404
+ const toolResultItems: HistoryItem[] = [];
404
405
  for (const toolCall of currentToolCalls || []) {
405
406
  const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
406
407
  if (tool) {
407
- toolResultsEvents.push({
408
- kind: EventKind.TOOL,
409
- source: MessageRole.AGENT,
410
- timestamp: new Date().toISOString(),
411
- data: {
412
- tool_calls: [
413
- {
414
- tool_id: toolCall.toolName,
415
- arguments: toolCall.arguments,
416
- result: {
417
- data: "Tool executed successfully",
418
- },
419
- },
420
- ],
421
- },
408
+ toolResultItems.push({
409
+ role: "assistant" as const,
410
+ content: null,
411
+ tool_calls: [{
412
+ id: toolCall.toolName,
413
+ name: toolCall.toolName,
414
+ arguments: toolCall.arguments,
415
+ }],
416
+ });
417
+ toolResultItems.push({
418
+ role: "tool" as const,
419
+ tool_call_id: toolCall.toolName,
420
+ name: toolCall.toolName,
421
+ content: "Tool executed successfully",
422
422
  });
423
423
  }
424
424
  }
425
425
 
426
426
  // Create updated history with tool results
427
- const updatedHistory = [...history, ...toolResultsEvents];
427
+ const updatedHistory = [...history, ...toolResultItems];
428
428
 
429
429
  // Make follow-up AI call to see if more tools are needed
430
430
  const followUpResult = await this.options.provider.generateMessage({
@@ -454,7 +454,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
454
454
  selectedRoute,
455
455
  context,
456
456
  session: currentSession,
457
- history: updatedHistory,
457
+ history: historyToEvents(updatedHistory),
458
458
  isStreaming,
459
459
  });
460
460