@falai/agent 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/README.md +42 -34
  2. package/dist/cjs/src/core/Agent.d.ts +19 -5
  3. package/dist/cjs/src/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/src/core/Agent.js +79 -35
  5. package/dist/cjs/src/core/Agent.js.map +1 -1
  6. package/dist/cjs/src/core/ResponseModal.d.ts +9 -3
  7. package/dist/cjs/src/core/ResponseModal.d.ts.map +1 -1
  8. package/dist/cjs/src/core/ResponseModal.js +121 -55
  9. package/dist/cjs/src/core/ResponseModal.js.map +1 -1
  10. package/dist/cjs/src/core/ResponsePipeline.d.ts +8 -4
  11. package/dist/cjs/src/core/ResponsePipeline.d.ts.map +1 -1
  12. package/dist/cjs/src/core/ResponsePipeline.js +47 -19
  13. package/dist/cjs/src/core/ResponsePipeline.js.map +1 -1
  14. package/dist/cjs/src/core/Route.d.ts +12 -5
  15. package/dist/cjs/src/core/Route.d.ts.map +1 -1
  16. package/dist/cjs/src/core/Route.js +26 -5
  17. package/dist/cjs/src/core/Route.js.map +1 -1
  18. package/dist/cjs/src/core/RoutingEngine.d.ts +5 -0
  19. package/dist/cjs/src/core/RoutingEngine.d.ts.map +1 -1
  20. package/dist/cjs/src/core/RoutingEngine.js +37 -25
  21. package/dist/cjs/src/core/RoutingEngine.js.map +1 -1
  22. package/dist/cjs/src/core/SessionManager.d.ts +9 -1
  23. package/dist/cjs/src/core/SessionManager.d.ts.map +1 -1
  24. package/dist/cjs/src/core/SessionManager.js +27 -5
  25. package/dist/cjs/src/core/SessionManager.js.map +1 -1
  26. package/dist/cjs/src/core/Step.d.ts +60 -7
  27. package/dist/cjs/src/core/Step.d.ts.map +1 -1
  28. package/dist/cjs/src/core/Step.js +151 -4
  29. package/dist/cjs/src/core/Step.js.map +1 -1
  30. package/dist/cjs/src/core/ToolManager.d.ts +234 -0
  31. package/dist/cjs/src/core/ToolManager.d.ts.map +1 -0
  32. package/dist/cjs/src/core/ToolManager.js +1117 -0
  33. package/dist/cjs/src/core/ToolManager.js.map +1 -0
  34. package/dist/cjs/src/index.d.ts +2 -3
  35. package/dist/cjs/src/index.d.ts.map +1 -1
  36. package/dist/cjs/src/index.js +5 -3
  37. package/dist/cjs/src/index.js.map +1 -1
  38. package/dist/cjs/src/types/agent.d.ts +1 -1
  39. package/dist/cjs/src/types/agent.d.ts.map +1 -1
  40. package/dist/cjs/src/types/index.d.ts +3 -2
  41. package/dist/cjs/src/types/index.d.ts.map +1 -1
  42. package/dist/cjs/src/types/index.js +3 -1
  43. package/dist/cjs/src/types/index.js.map +1 -1
  44. package/dist/cjs/src/types/route.d.ts +6 -4
  45. package/dist/cjs/src/types/route.d.ts.map +1 -1
  46. package/dist/cjs/src/types/tool.d.ts +84 -14
  47. package/dist/cjs/src/types/tool.d.ts.map +1 -1
  48. package/dist/cjs/src/types/tool.js +13 -0
  49. package/dist/cjs/src/types/tool.js.map +1 -1
  50. package/dist/src/core/Agent.d.ts +19 -5
  51. package/dist/src/core/Agent.d.ts.map +1 -1
  52. package/dist/src/core/Agent.js +79 -35
  53. package/dist/src/core/Agent.js.map +1 -1
  54. package/dist/src/core/ResponseModal.d.ts +9 -3
  55. package/dist/src/core/ResponseModal.d.ts.map +1 -1
  56. package/dist/src/core/ResponseModal.js +121 -55
  57. package/dist/src/core/ResponseModal.js.map +1 -1
  58. package/dist/src/core/ResponsePipeline.d.ts +8 -4
  59. package/dist/src/core/ResponsePipeline.d.ts.map +1 -1
  60. package/dist/src/core/ResponsePipeline.js +47 -19
  61. package/dist/src/core/ResponsePipeline.js.map +1 -1
  62. package/dist/src/core/Route.d.ts +12 -5
  63. package/dist/src/core/Route.d.ts.map +1 -1
  64. package/dist/src/core/Route.js +26 -5
  65. package/dist/src/core/Route.js.map +1 -1
  66. package/dist/src/core/RoutingEngine.d.ts +5 -0
  67. package/dist/src/core/RoutingEngine.d.ts.map +1 -1
  68. package/dist/src/core/RoutingEngine.js +37 -25
  69. package/dist/src/core/RoutingEngine.js.map +1 -1
  70. package/dist/src/core/SessionManager.d.ts +9 -1
  71. package/dist/src/core/SessionManager.d.ts.map +1 -1
  72. package/dist/src/core/SessionManager.js +27 -5
  73. package/dist/src/core/SessionManager.js.map +1 -1
  74. package/dist/src/core/Step.d.ts +60 -7
  75. package/dist/src/core/Step.d.ts.map +1 -1
  76. package/dist/src/core/Step.js +151 -4
  77. package/dist/src/core/Step.js.map +1 -1
  78. package/dist/src/core/ToolManager.d.ts +234 -0
  79. package/dist/src/core/ToolManager.d.ts.map +1 -0
  80. package/dist/src/core/ToolManager.js +1111 -0
  81. package/dist/src/core/ToolManager.js.map +1 -0
  82. package/dist/src/index.d.ts +2 -3
  83. package/dist/src/index.d.ts.map +1 -1
  84. package/dist/src/index.js +1 -1
  85. package/dist/src/index.js.map +1 -1
  86. package/dist/src/types/agent.d.ts +1 -1
  87. package/dist/src/types/agent.d.ts.map +1 -1
  88. package/dist/src/types/index.d.ts +3 -2
  89. package/dist/src/types/index.d.ts.map +1 -1
  90. package/dist/src/types/index.js +1 -0
  91. package/dist/src/types/index.js.map +1 -1
  92. package/dist/src/types/route.d.ts +6 -4
  93. package/dist/src/types/route.d.ts.map +1 -1
  94. package/dist/src/types/tool.d.ts +84 -14
  95. package/dist/src/types/tool.d.ts.map +1 -1
  96. package/dist/src/types/tool.js +12 -1
  97. package/dist/src/types/tool.js.map +1 -1
  98. package/docs/CONTRIBUTING.md +40 -0
  99. package/docs/README.md +12 -5
  100. package/docs/api/README.md +75 -45
  101. package/docs/api/overview.md +74 -32
  102. package/docs/core/agent/session-management.md +152 -5
  103. package/docs/core/ai-integration/response-processing.md +115 -4
  104. package/docs/core/conversation-flows/routes.md +130 -0
  105. package/docs/core/error-handling.md +638 -0
  106. package/docs/core/tools/tool-definition.md +684 -60
  107. package/docs/core/tools/tool-scoping.md +244 -53
  108. package/docs/guides/error-handling-patterns.md +578 -0
  109. package/docs/guides/getting-started/README.md +139 -28
  110. package/examples/advanced-patterns/knowledge-based-agent.ts +6 -6
  111. package/examples/advanced-patterns/persistent-onboarding.ts +30 -43
  112. package/examples/ai-providers/anthropic-integration.ts +9 -5
  113. package/examples/ai-providers/openai-integration.ts +11 -7
  114. package/examples/core-concepts/basic-agent.ts +106 -67
  115. package/examples/core-concepts/schema-driven-extraction.ts +10 -7
  116. package/examples/core-concepts/session-management.ts +71 -18
  117. package/examples/integrations/healthcare-integration.ts +15 -29
  118. package/examples/integrations/server-session-management.ts +3 -3
  119. package/examples/persistence/memory-sessions.ts +3 -3
  120. package/examples/tools/basic-tools.ts +293 -89
  121. package/examples/tools/data-enrichment-tools.ts +185 -75
  122. package/package.json +1 -1
  123. package/src/core/Agent.ts +98 -44
  124. package/src/core/ResponseModal.ts +148 -72
  125. package/src/core/ResponsePipeline.ts +82 -56
  126. package/src/core/Route.ts +39 -12
  127. package/src/core/RoutingEngine.ts +46 -42
  128. package/src/core/SessionManager.ts +39 -7
  129. package/src/core/Step.ts +198 -20
  130. package/src/core/ToolManager.ts +1394 -0
  131. package/src/index.ts +8 -3
  132. package/src/types/agent.ts +1 -1
  133. package/src/types/index.ts +13 -2
  134. package/src/types/route.ts +6 -4
  135. package/src/types/tool.ts +116 -25
  136. package/dist/cjs/src/core/ToolExecutor.d.ts +0 -45
  137. package/dist/cjs/src/core/ToolExecutor.d.ts.map +0 -1
  138. package/dist/cjs/src/core/ToolExecutor.js +0 -84
  139. package/dist/cjs/src/core/ToolExecutor.js.map +0 -1
  140. package/dist/src/core/ToolExecutor.d.ts +0 -45
  141. package/dist/src/core/ToolExecutor.d.ts.map +0 -1
  142. package/dist/src/core/ToolExecutor.js +0 -80
  143. package/dist/src/core/ToolExecutor.js.map +0 -1
  144. package/docs/core/tools/tool-execution.md +0 -815
  145. package/src/core/ToolExecutor.ts +0 -126
@@ -19,11 +19,11 @@ import type {
19
19
  import { EventKind, MessageRole } from "../types";
20
20
  import type { Agent } from "./Agent";
21
21
  import type { Route } from "./Route";
22
- import { Step } from "./Step";
22
+ import { Step } from "./Step";
23
23
  import { ResponseEngine } from "./ResponseEngine";
24
24
  import { ResponsePipeline } from "./ResponsePipeline";
25
25
  import { cloneDeep, mergeCollected, enterStep, getLastMessageFromHistory, render, logger, historyToEvents } from "../utils";
26
- import { ToolExecutor } from "./ToolExecutor";
26
+ import type { ToolManager } from "./ToolManager";
27
27
  import { END_ROUTE_ID } from "../constants";
28
28
 
29
29
  /**
@@ -98,9 +98,9 @@ export class ResponseGenerationError extends Error {
98
98
  * Create a ResponseGenerationError from an unknown error
99
99
  */
100
100
  static fromError(
101
- error: unknown,
102
- phase: string,
103
- params?: Record<string, unknown>,
101
+ error: unknown,
102
+ phase: string,
103
+ params?: Record<string, unknown>,
104
104
  context?: Record<string, unknown>
105
105
  ): ResponseGenerationError {
106
106
  const message = error instanceof Error ? error.message : String(error);
@@ -149,12 +149,13 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
149
149
  // Initialize response pipeline with agent dependencies
150
150
  this.responsePipeline = new ResponsePipeline<TContext, TData>(
151
151
  this.agent.getAgentOptions(),
152
- this.agent.getRoutes(),
152
+ () => this.agent.getRoutes(), // Pass a function to get routes dynamically
153
153
  this.agent.getTools(),
154
154
  this.agent.getRoutingEngine(),
155
155
  this.agent.updateContext.bind(this.agent),
156
156
  this.agent.getUpdateDataMethod(),
157
- this.agent.updateCollectedData.bind(this.agent)
157
+ this.agent.updateCollectedData.bind(this.agent),
158
+ this.getToolManager()
158
159
  );
159
160
  }
160
161
 
@@ -165,7 +166,6 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
165
166
  try {
166
167
  // Use unified response preparation and routing
167
168
  const responseContext = await this.prepareUnifiedResponseContext(params);
168
-
169
169
  // Generate response using unified logic
170
170
  const result = await this.generateUnifiedResponse(responseContext);
171
171
 
@@ -330,6 +330,21 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
330
330
  return this.responsePipeline;
331
331
  }
332
332
 
333
+ /**
334
+ * Get the ToolManager instance from the agent
335
+ * @private
336
+ */
337
+ private getToolManager(): ToolManager<TContext, TData> | undefined {
338
+ // Check if agent has a tool property (ToolManager)
339
+ if (this.agent && 'tool' in this.agent && this.agent.tool) {
340
+ return this.agent.tool;
341
+ }
342
+
343
+ // Log warning if ToolManager is not available
344
+ logger.warn(`[ResponseModal] ToolManager not available on agent - tool execution will use fallback methods`);
345
+ return undefined;
346
+ }
347
+
333
348
  // UNIFIED RESPONSE LOGIC - Consolidates common logic between streaming and non-streaming
334
349
  // ============================================================================
335
350
 
@@ -406,7 +421,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
406
421
  let routingResult: {
407
422
  selectedRoute?: Route<TContext, TData>;
408
423
  selectedStep?: Step<TContext, TData>;
409
- responseDirectives?: string[];
424
+ responseDirectives?: string[];
410
425
  session: SessionState<TData>;
411
426
  isRouteComplete: boolean;
412
427
  };
@@ -465,7 +480,6 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
465
480
  context: params.context,
466
481
  signal: params.signal,
467
482
  });
468
-
469
483
  // Determine next step using pipeline method for consistency
470
484
  const stepResult = this.responsePipeline.determineNextStep({
471
485
  selectedRoute: routingResult.selectedRoute,
@@ -504,8 +518,11 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
504
518
  let message: string;
505
519
  let toolCalls: Array<{ toolName: string; arguments: Record<string, unknown> }> | undefined = undefined;
506
520
 
521
+
522
+
507
523
  if (selectedRoute && !isRouteComplete) {
508
524
  // Handle normal route processing
525
+
509
526
  const result = await this.processRouteResponse({
510
527
  selectedRoute,
511
528
  selectedStep,
@@ -524,6 +541,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
524
541
 
525
542
  } else if (isRouteComplete && selectedRoute) {
526
543
  // Handle route completion
544
+
527
545
  message = await this.handleRouteCompletion({
528
546
  selectedRoute,
529
547
  session,
@@ -538,6 +556,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
538
556
 
539
557
  } else {
540
558
  // Fallback: No routes defined, generate a simple response
559
+
541
560
  message = await this.generateFallbackResponse({
542
561
  history: historyEvents, // Use Event[] for fallback response
543
562
  context: effectiveContext,
@@ -925,16 +944,24 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
925
944
  }
926
945
 
927
946
  try {
928
- const toolExecutor = new ToolExecutor<TContext, TData>();
929
- const toolResult = await toolExecutor.executeTool({
930
- tool: tool,
931
- context,
932
- updateContext: this.agent.updateContext.bind(this.agent),
933
- updateData: this.agent.updateCollectedData.bind(this.agent),
934
- history: historyEvents, // Use Event[] for tool execution
935
- data: session.data,
936
- toolArguments: toolCall.arguments,
937
- });
947
+ // Use ToolManager for unified tool execution
948
+ const toolManager = this.getToolManager();
949
+ let toolResult;
950
+
951
+ if (toolManager) {
952
+ toolResult = await toolManager.executeTool({
953
+ tool: tool,
954
+ context,
955
+ updateContext: this.agent.updateContext.bind(this.agent),
956
+ updateData: this.agent.updateCollectedData.bind(this.agent),
957
+ history: historyEvents, // Use Event[] for tool execution
958
+ data: session.data,
959
+ toolArguments: toolCall.arguments,
960
+ });
961
+ } else {
962
+ // Fallback: execute tool directly if ToolManager not available
963
+ throw new Error(`ToolManager not available for tool execution: ${toolCall.toolName}`);
964
+ }
938
965
 
939
966
  // Check if tool execution was successful
940
967
  if (!toolResult.success) {
@@ -965,7 +992,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
965
992
  }
966
993
  }
967
994
 
968
- logger.debug(`[ResponseModal] Executed dynamic tool: ${toolResult.toolName} (success: ${toolResult.success})`);
995
+ logger.debug(`[ResponseModal] Executed dynamic tool: ${toolCall.toolName} (success: ${toolResult.success})`);
969
996
  } catch (error) {
970
997
  logger.error(`[ResponseModal] Tool execution error for ${toolCall.toolName}:`, error);
971
998
  // Continue with other tools rather than failing the entire response
@@ -1043,16 +1070,24 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1043
1070
  }
1044
1071
 
1045
1072
  try {
1046
- const toolExecutor = new ToolExecutor<TContext, TData>();
1047
- const toolResult = await toolExecutor.executeTool({
1048
- tool: tool,
1049
- context,
1050
- updateContext: this.agent.updateContext.bind(this.agent),
1051
- updateData: this.agent.updateCollectedData.bind(this.agent),
1052
- history: updatedHistoryEvents, // Use Event[] for tool execution
1053
- data: session.data,
1054
- toolArguments: toolCall.arguments,
1055
- });
1073
+ // Use ToolManager for unified tool execution
1074
+ const toolManager = this.getToolManager();
1075
+ let toolResult;
1076
+
1077
+ if (toolManager) {
1078
+ toolResult = await toolManager.executeTool({
1079
+ tool: tool,
1080
+ context,
1081
+ updateContext: this.agent.updateContext.bind(this.agent),
1082
+ updateData: this.agent.updateCollectedData.bind(this.agent),
1083
+ history: updatedHistoryEvents, // Use Event[] for tool execution
1084
+ data: session.data,
1085
+ toolArguments: toolCall.arguments,
1086
+ });
1087
+ } else {
1088
+ // Fallback: execute tool directly if ToolManager not available
1089
+ throw new Error(`ToolManager not available for follow-up tool execution: ${toolCall.toolName}`);
1090
+ }
1056
1091
 
1057
1092
  // Check if tool execution was successful
1058
1093
  if (!toolResult.success) {
@@ -1079,7 +1114,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1079
1114
  }
1080
1115
  }
1081
1116
 
1082
- logger.debug(`[ResponseModal] Executed follow-up tool: ${toolResult.toolName} (success: ${toolResult.success})`);
1117
+ logger.debug(`[ResponseModal] Executed follow-up tool: ${toolCall.toolName} (success: ${toolResult.success})`);
1083
1118
  } catch (error) {
1084
1119
  logger.error(`[ResponseModal] Follow-up tool execution error for ${toolCall.toolName}:`, error);
1085
1120
  continue;
@@ -1511,19 +1546,28 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1511
1546
  // ============================================================================
1512
1547
 
1513
1548
  /**
1514
- * Find an available tool by name for the given route
1515
- * Route-level tools take precedence over agent-level tools
1549
+ * Find an available tool by name for the given route using ToolManager
1550
+ * Delegates to ToolManager for unified tool resolution
1516
1551
  * @private
1517
1552
  */
1518
1553
  private findAvailableTool(
1519
1554
  toolName: string,
1520
1555
  route?: Route<TContext, TData>
1521
- ): Tool<TContext, TData, unknown[], unknown> | undefined {
1556
+ ): Tool<TContext, TData> | undefined {
1557
+ // Use ToolManager for unified tool resolution
1558
+ const toolManager = this.getToolManager();
1559
+ if (toolManager) {
1560
+ return toolManager.find(toolName, undefined, undefined, route);
1561
+ }
1562
+
1563
+ // Fallback to legacy resolution if ToolManager not available
1564
+ logger.warn(`[ResponseModal] ToolManager not available, using legacy tool resolution for: ${toolName}`);
1565
+
1522
1566
  // Check route-level tools first (if route provided)
1523
1567
  if (route) {
1524
1568
  const routeTool = route
1525
1569
  .getTools()
1526
- .find((tool: Tool<TContext, TData, unknown[], unknown>) => tool.id === toolName || tool.name === toolName);
1570
+ .find((tool: Tool<TContext, TData>) => tool.id === toolName || tool.name === toolName);
1527
1571
  if (routeTool) return routeTool;
1528
1572
  }
1529
1573
 
@@ -1535,7 +1579,8 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1535
1579
  }
1536
1580
 
1537
1581
  /**
1538
- * Collect all available tools for the given route and step context
1582
+ * Collect all available tools for the given route and step context using ToolManager
1583
+ * Delegates to ToolManager for unified tool resolution and deduplication
1539
1584
  * @private
1540
1585
  */
1541
1586
  private collectAvailableTools(
@@ -1547,7 +1592,22 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1547
1592
  description?: string;
1548
1593
  parameters?: unknown;
1549
1594
  }> {
1550
- const availableTools = new Map<string, Tool<TContext, TData, unknown[], unknown>>();
1595
+ // Use ToolManager for unified tool collection if available
1596
+ const toolManager = this.getToolManager();
1597
+ if (toolManager) {
1598
+ const availableTools = toolManager.getAvailable(undefined, step, route);
1599
+ return availableTools.map((tool) => ({
1600
+ id: tool.id,
1601
+ name: tool.name || tool.id,
1602
+ description: tool.description,
1603
+ parameters: tool.parameters,
1604
+ }));
1605
+ }
1606
+
1607
+ // Fallback to legacy collection logic if ToolManager not available
1608
+ logger.warn(`[ResponseModal] ToolManager not available, using legacy tool collection`);
1609
+
1610
+ const availableTools = new Map<string, Tool<TContext, TData>>();
1551
1611
 
1552
1612
  // Add agent-level tools
1553
1613
  this.agent.getTools().forEach((tool) => {
@@ -1556,7 +1616,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1556
1616
 
1557
1617
  // Add route-level tools (these take precedence)
1558
1618
  if (route) {
1559
- route.getTools().forEach((tool: Tool<TContext, TData, unknown[], unknown>) => {
1619
+ route.getTools().forEach((tool: Tool<TContext, TData>) => {
1560
1620
  availableTools.set(tool.id, tool);
1561
1621
  });
1562
1622
  }
@@ -1564,7 +1624,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1564
1624
  // Filter by step-level allowed tools if specified
1565
1625
  if (step?.tools) {
1566
1626
  const allowedToolIds = new Set<string>();
1567
- const stepTools: Tool<TContext, TData, unknown[], unknown>[] = [];
1627
+ const stepTools: Tool<TContext, TData>[] = [];
1568
1628
 
1569
1629
  for (const toolRef of step.tools) {
1570
1630
  if (typeof toolRef === "string") {
@@ -1581,7 +1641,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1581
1641
 
1582
1642
  // If step specifies tools, only include those
1583
1643
  if (allowedToolIds.size > 0) {
1584
- const filteredTools = new Map<string, Tool<TContext, TData, unknown[], unknown>>();
1644
+ const filteredTools = new Map<string, Tool<TContext, TData>>();
1585
1645
  for (const toolId of Array.from(allowedToolIds)) {
1586
1646
  const tool = availableTools.get(toolId);
1587
1647
  if (tool) {
@@ -1615,7 +1675,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1615
1675
  private async executePrepareFinalize(
1616
1676
  prepareOrFinalize:
1617
1677
  | string
1618
- | Tool<TContext, TData, unknown[], unknown>
1678
+ | Tool<TContext, TData>
1619
1679
  | ((context: TContext, data?: Partial<TData>) => void | Promise<void>)
1620
1680
  | undefined,
1621
1681
  context: TContext,
@@ -1630,51 +1690,67 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1630
1690
  await prepareOrFinalize(context, data);
1631
1691
  } else {
1632
1692
  // It's a tool reference - find and execute the tool
1633
- let tool: Tool<TContext, TData, unknown[], unknown> | undefined;
1693
+ let tool: Tool<TContext, TData> | undefined;
1634
1694
 
1635
1695
  if (typeof prepareOrFinalize === "string") {
1636
- // Tool ID - find it in available tools
1637
- const availableTools = new Map<string, Tool<TContext, TData, unknown[], unknown>>();
1638
-
1639
- // Add agent-level tools
1640
- this.agent.getTools().forEach((t) => {
1641
- availableTools.set(t.id, t);
1642
- });
1696
+ // Tool ID - use ToolManager for unified resolution
1697
+ const toolManager = this.getToolManager();
1698
+ if (toolManager) {
1699
+ tool = toolManager.find(prepareOrFinalize, undefined, step, route);
1700
+ } else {
1701
+ // Fallback to legacy resolution if ToolManager not available
1702
+ logger.warn(`[ResponseModal] ToolManager not available, using legacy tool resolution for prepare/finalize: ${prepareOrFinalize}`);
1703
+
1704
+ const availableTools = new Map<string, Tool<TContext, TData>>();
1643
1705
 
1644
- // Add route-level tools
1645
- if (route) {
1646
- route.getTools().forEach((t: Tool<TContext, TData, unknown[], unknown>) => {
1706
+ // Add agent-level tools
1707
+ this.agent.getTools().forEach((t) => {
1647
1708
  availableTools.set(t.id, t);
1648
1709
  });
1649
- }
1650
1710
 
1651
- // Add step-level tools
1652
- if (step?.tools) {
1653
- for (const toolRef of step.tools) {
1654
- if (typeof toolRef === "string") {
1655
- // Keep as is
1656
- } else if (typeof toolRef === 'object' && 'id' in toolRef && toolRef.id) {
1657
- availableTools.set(toolRef.id, toolRef);
1711
+ // Add route-level tools
1712
+ if (route) {
1713
+ route.getTools().forEach((t: Tool<TContext, TData>) => {
1714
+ availableTools.set(t.id, t);
1715
+ });
1716
+ }
1717
+
1718
+ // Add step-level tools
1719
+ if (step?.tools) {
1720
+ for (const toolRef of step.tools) {
1721
+ if (typeof toolRef === "string") {
1722
+ // Keep as is
1723
+ } else if (typeof toolRef === 'object' && 'id' in toolRef && toolRef.id) {
1724
+ availableTools.set(toolRef.id, toolRef);
1725
+ }
1658
1726
  }
1659
1727
  }
1660
- }
1661
1728
 
1662
- tool = availableTools.get(prepareOrFinalize);
1729
+ tool = availableTools.get(prepareOrFinalize);
1730
+ }
1663
1731
  } else {
1664
1732
  // Tool object - use directly
1665
1733
  tool = prepareOrFinalize;
1666
1734
  }
1667
1735
 
1668
1736
  if (tool) {
1669
- const toolExecutor = new ToolExecutor<TContext, TData>();
1670
- const result = await toolExecutor.executeTool({
1671
- tool,
1672
- context,
1673
- updateContext: this.agent.updateContext.bind(this.agent),
1674
- updateData: this.agent.updateCollectedData.bind(this.agent),
1675
- history: [], // Empty history for prepare/finalize
1676
- data,
1677
- });
1737
+ // Use ToolManager for unified tool execution
1738
+ const toolManager = this.getToolManager();
1739
+ let result;
1740
+
1741
+ if (toolManager) {
1742
+ result = await toolManager.executeTool({
1743
+ tool,
1744
+ context,
1745
+ updateContext: this.agent.updateContext.bind(this.agent),
1746
+ updateData: this.agent.updateCollectedData.bind(this.agent),
1747
+ history: [], // Empty history for prepare/finalize
1748
+ data,
1749
+ });
1750
+ } else {
1751
+ // Fallback: execute tool directly if ToolManager not available
1752
+ throw new Error(`ToolManager not available for prepare/finalize tool execution: ${typeof prepareOrFinalize === "string" ? prepareOrFinalize : "inline tool"}`);
1753
+ }
1678
1754
 
1679
1755
  if (!result.success) {
1680
1756
  logger.error(