@juspay/neurolink 8.2.0 → 8.4.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.
- package/CHANGELOG.md +12 -0
- package/README.md +13 -3
- package/dist/adapters/providerImageAdapter.d.ts +1 -1
- package/dist/adapters/providerImageAdapter.js +62 -0
- package/dist/agent/directTools.d.ts +0 -72
- package/dist/agent/directTools.js +3 -74
- package/dist/cli/commands/config.d.ts +18 -18
- package/dist/cli/factories/commandFactory.js +1 -0
- package/dist/cli/loop/conversationSelector.js +4 -0
- package/dist/cli/loop/session.js +27 -15
- package/dist/constants/enums.d.ts +1 -0
- package/dist/constants/enums.js +3 -1
- package/dist/constants/tokens.d.ts +3 -0
- package/dist/constants/tokens.js +3 -0
- package/dist/core/baseProvider.d.ts +56 -53
- package/dist/core/baseProvider.js +107 -1095
- package/dist/core/constants.d.ts +3 -0
- package/dist/core/constants.js +6 -3
- package/dist/core/modelConfiguration.js +10 -0
- package/dist/core/modules/GenerationHandler.d.ts +63 -0
- package/dist/core/modules/GenerationHandler.js +230 -0
- package/dist/core/modules/MessageBuilder.d.ts +39 -0
- package/dist/core/modules/MessageBuilder.js +179 -0
- package/dist/core/modules/StreamHandler.d.ts +52 -0
- package/dist/core/modules/StreamHandler.js +103 -0
- package/dist/core/modules/TelemetryHandler.d.ts +64 -0
- package/dist/core/modules/TelemetryHandler.js +170 -0
- package/dist/core/modules/ToolsManager.d.ts +98 -0
- package/dist/core/modules/ToolsManager.js +521 -0
- package/dist/core/modules/Utilities.d.ts +88 -0
- package/dist/core/modules/Utilities.js +329 -0
- package/dist/factories/providerRegistry.js +1 -1
- package/dist/lib/adapters/providerImageAdapter.d.ts +1 -1
- package/dist/lib/adapters/providerImageAdapter.js +62 -0
- package/dist/lib/agent/directTools.d.ts +0 -72
- package/dist/lib/agent/directTools.js +3 -74
- package/dist/lib/constants/enums.d.ts +1 -0
- package/dist/lib/constants/enums.js +3 -1
- package/dist/lib/constants/tokens.d.ts +3 -0
- package/dist/lib/constants/tokens.js +3 -0
- package/dist/lib/core/baseProvider.d.ts +56 -53
- package/dist/lib/core/baseProvider.js +107 -1095
- package/dist/lib/core/constants.d.ts +3 -0
- package/dist/lib/core/constants.js +6 -3
- package/dist/lib/core/modelConfiguration.js +10 -0
- package/dist/lib/core/modules/GenerationHandler.d.ts +63 -0
- package/dist/lib/core/modules/GenerationHandler.js +231 -0
- package/dist/lib/core/modules/MessageBuilder.d.ts +39 -0
- package/dist/lib/core/modules/MessageBuilder.js +180 -0
- package/dist/lib/core/modules/StreamHandler.d.ts +52 -0
- package/dist/lib/core/modules/StreamHandler.js +104 -0
- package/dist/lib/core/modules/TelemetryHandler.d.ts +64 -0
- package/dist/lib/core/modules/TelemetryHandler.js +171 -0
- package/dist/lib/core/modules/ToolsManager.d.ts +98 -0
- package/dist/lib/core/modules/ToolsManager.js +522 -0
- package/dist/lib/core/modules/Utilities.d.ts +88 -0
- package/dist/lib/core/modules/Utilities.js +330 -0
- package/dist/lib/factories/providerRegistry.js +1 -1
- package/dist/lib/mcp/servers/agent/directToolsServer.js +0 -1
- package/dist/lib/models/modelRegistry.js +44 -0
- package/dist/lib/neurolink.js +35 -3
- package/dist/lib/providers/amazonBedrock.js +59 -10
- package/dist/lib/providers/anthropic.js +2 -30
- package/dist/lib/providers/azureOpenai.js +2 -24
- package/dist/lib/providers/googleAiStudio.js +2 -24
- package/dist/lib/providers/googleVertex.js +2 -45
- package/dist/lib/providers/huggingFace.js +3 -31
- package/dist/lib/providers/litellm.d.ts +1 -1
- package/dist/lib/providers/litellm.js +110 -44
- package/dist/lib/providers/mistral.js +5 -32
- package/dist/lib/providers/ollama.d.ts +1 -0
- package/dist/lib/providers/ollama.js +476 -129
- package/dist/lib/providers/openAI.js +2 -28
- package/dist/lib/providers/openaiCompatible.js +3 -31
- package/dist/lib/types/content.d.ts +16 -113
- package/dist/lib/types/content.js +16 -2
- package/dist/lib/types/conversation.d.ts +3 -17
- package/dist/lib/types/generateTypes.d.ts +2 -2
- package/dist/lib/types/index.d.ts +2 -0
- package/dist/lib/types/index.js +2 -0
- package/dist/lib/types/multimodal.d.ts +282 -0
- package/dist/lib/types/multimodal.js +101 -0
- package/dist/lib/types/streamTypes.d.ts +2 -2
- package/dist/lib/utils/imageProcessor.d.ts +1 -1
- package/dist/lib/utils/messageBuilder.js +25 -2
- package/dist/lib/utils/multimodalOptionsBuilder.d.ts +1 -1
- package/dist/lib/utils/pdfProcessor.d.ts +9 -0
- package/dist/lib/utils/pdfProcessor.js +67 -9
- package/dist/mcp/servers/agent/directToolsServer.js +0 -1
- package/dist/models/modelRegistry.js +44 -0
- package/dist/neurolink.js +35 -3
- package/dist/providers/amazonBedrock.js +59 -10
- package/dist/providers/anthropic.js +2 -30
- package/dist/providers/azureOpenai.js +2 -24
- package/dist/providers/googleAiStudio.js +2 -24
- package/dist/providers/googleVertex.js +2 -45
- package/dist/providers/huggingFace.js +3 -31
- package/dist/providers/litellm.d.ts +1 -1
- package/dist/providers/litellm.js +110 -44
- package/dist/providers/mistral.js +5 -32
- package/dist/providers/ollama.d.ts +1 -0
- package/dist/providers/ollama.js +476 -129
- package/dist/providers/openAI.js +2 -28
- package/dist/providers/openaiCompatible.js +3 -31
- package/dist/types/content.d.ts +16 -113
- package/dist/types/content.js +16 -2
- package/dist/types/conversation.d.ts +3 -17
- package/dist/types/generateTypes.d.ts +2 -2
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/multimodal.d.ts +282 -0
- package/dist/types/multimodal.js +100 -0
- package/dist/types/streamTypes.d.ts +2 -2
- package/dist/utils/imageProcessor.d.ts +1 -1
- package/dist/utils/messageBuilder.js +25 -2
- package/dist/utils/multimodalOptionsBuilder.d.ts +1 -1
- package/dist/utils/pdfProcessor.d.ts +9 -0
- package/dist/utils/pdfProcessor.js +67 -9
- package/package.json +5 -2
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools Manager Module
|
|
3
|
+
*
|
|
4
|
+
* Handles all tool registration, discovery, and execution for AI providers.
|
|
5
|
+
* Extracted from BaseProvider to follow Single Responsibility Principle.
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - Tool registration (direct, custom, MCP, external MCP)
|
|
9
|
+
* - Tool discovery and aggregation
|
|
10
|
+
* - Tool creation from definitions and schemas
|
|
11
|
+
* - Tool executor setup
|
|
12
|
+
* - Session context management for MCP tools
|
|
13
|
+
* - Event emission wrapping for tool execution
|
|
14
|
+
*
|
|
15
|
+
* @module core/modules/ToolsManager
|
|
16
|
+
*/
|
|
17
|
+
import { tool as createAISDKTool, jsonSchema } from "ai";
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
import { logger } from "../../utils/logger.js";
|
|
20
|
+
import { getKeysAsString, getKeyCount, } from "../../utils/transformationUtils.js";
|
|
21
|
+
import { convertJsonSchemaToZod } from "../../utils/schemaConversion.js";
|
|
22
|
+
/**
|
|
23
|
+
* ToolsManager class - Handles all tool management operations
|
|
24
|
+
*/
|
|
25
|
+
export class ToolsManager {
|
|
26
|
+
providerName;
|
|
27
|
+
directTools;
|
|
28
|
+
neurolink;
|
|
29
|
+
utilities;
|
|
30
|
+
// Tool storage
|
|
31
|
+
mcpTools;
|
|
32
|
+
customTools;
|
|
33
|
+
toolExecutor;
|
|
34
|
+
// Session context
|
|
35
|
+
sessionId;
|
|
36
|
+
userId;
|
|
37
|
+
constructor(providerName, directTools, neurolink, utilities) {
|
|
38
|
+
this.providerName = providerName;
|
|
39
|
+
this.directTools = directTools;
|
|
40
|
+
this.neurolink = neurolink;
|
|
41
|
+
this.utilities = utilities;
|
|
42
|
+
this.mcpTools = {};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Set session context for MCP tools
|
|
46
|
+
*/
|
|
47
|
+
setSessionContext(sessionId, userId) {
|
|
48
|
+
this.sessionId = sessionId;
|
|
49
|
+
this.userId = userId;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Set up tool executor for a provider to enable actual tool execution
|
|
53
|
+
* @param sdk - The NeuroLinkSDK instance for tool execution
|
|
54
|
+
* @param functionTag - Function name for logging
|
|
55
|
+
*/
|
|
56
|
+
setupToolExecutor(sdk, functionTag) {
|
|
57
|
+
// Store custom tools for use in getAllTools()
|
|
58
|
+
this.customTools = sdk.customTools;
|
|
59
|
+
this.toolExecutor = sdk.executeTool;
|
|
60
|
+
logger.debug(`[${functionTag}] Setting up tool executor for provider`, {
|
|
61
|
+
providerName: this.providerName,
|
|
62
|
+
availableCustomTools: sdk.customTools.size,
|
|
63
|
+
customToolsStored: !!this.customTools,
|
|
64
|
+
toolExecutorStored: !!this.toolExecutor,
|
|
65
|
+
});
|
|
66
|
+
// Note: Tool execution will be handled through getAllTools() -> AI SDK tools
|
|
67
|
+
// The custom tools are converted to AI SDK format in getAllTools() method
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get all available tools - direct tools are ALWAYS available
|
|
71
|
+
* MCP tools are added when available (without blocking)
|
|
72
|
+
*/
|
|
73
|
+
async getAllTools() {
|
|
74
|
+
// Start with wrapped direct tools that emit events
|
|
75
|
+
const tools = {};
|
|
76
|
+
// Wrap direct tools with event emission
|
|
77
|
+
await this.processDirectTools(tools);
|
|
78
|
+
logger.debug(`[ToolsManager] getAllTools called for ${this.providerName}`, {
|
|
79
|
+
neurolinkAvailable: !!this.neurolink,
|
|
80
|
+
neurolinkType: typeof this.neurolink,
|
|
81
|
+
directToolsCount: getKeyCount(this.directTools),
|
|
82
|
+
});
|
|
83
|
+
logger.debug(`[ToolsManager] Direct tools: ${getKeysAsString(this.directTools)}`);
|
|
84
|
+
// Process all tool types using dedicated helper methods
|
|
85
|
+
await this.processCustomTools(tools);
|
|
86
|
+
await this.processExternalMCPTools(tools);
|
|
87
|
+
await this.processMCPTools(tools);
|
|
88
|
+
logger.debug(`[ToolsManager] getAllTools returning tools: ${getKeysAsString(tools)}`);
|
|
89
|
+
return tools;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get direct tools (built-in agent tools)
|
|
93
|
+
*/
|
|
94
|
+
getDirectTools() {
|
|
95
|
+
return this.directTools;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get MCP tools
|
|
99
|
+
*/
|
|
100
|
+
getMCPTools() {
|
|
101
|
+
return this.mcpTools;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get custom tools
|
|
105
|
+
*/
|
|
106
|
+
getCustomTools() {
|
|
107
|
+
return this.customTools;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Process direct tools with event emission wrapping
|
|
111
|
+
*/
|
|
112
|
+
async processDirectTools(tools) {
|
|
113
|
+
if (!this.directTools || Object.keys(this.directTools).length === 0) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
logger.debug(`Loading ${Object.keys(this.directTools).length} direct tools with event emission`);
|
|
117
|
+
for (const [toolName, directTool] of Object.entries(this.directTools)) {
|
|
118
|
+
logger.debug(`Processing direct tool: ${toolName}`, {
|
|
119
|
+
toolName,
|
|
120
|
+
hasExecute: directTool &&
|
|
121
|
+
typeof directTool === "object" &&
|
|
122
|
+
"execute" in directTool,
|
|
123
|
+
hasDescription: directTool &&
|
|
124
|
+
typeof directTool === "object" &&
|
|
125
|
+
"description" in directTool,
|
|
126
|
+
});
|
|
127
|
+
// Wrap the direct tool's execute function with event emission
|
|
128
|
+
if (directTool &&
|
|
129
|
+
typeof directTool === "object" &&
|
|
130
|
+
"execute" in directTool) {
|
|
131
|
+
const originalExecute = directTool.execute;
|
|
132
|
+
// Create a new tool with wrapped execute function
|
|
133
|
+
tools[toolName] = {
|
|
134
|
+
...directTool,
|
|
135
|
+
execute: async (params) => {
|
|
136
|
+
// 🔧 EMIT TOOL START EVENT - Bedrock-compatible format
|
|
137
|
+
if (this.neurolink?.getEventEmitter) {
|
|
138
|
+
const emitter = this.neurolink.getEventEmitter();
|
|
139
|
+
emitter.emit("tool:start", { tool: toolName, input: params });
|
|
140
|
+
logger.debug(`Direct tool:start event emitted for ${toolName}`, {
|
|
141
|
+
toolName,
|
|
142
|
+
input: params,
|
|
143
|
+
hasEmitter: !!emitter,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
const result = await originalExecute(params);
|
|
148
|
+
// 🔧 EMIT TOOL END EVENT - Bedrock-compatible format
|
|
149
|
+
if (this.neurolink?.getEventEmitter) {
|
|
150
|
+
const emitter = this.neurolink.getEventEmitter();
|
|
151
|
+
emitter.emit("tool:end", { tool: toolName, result });
|
|
152
|
+
logger.debug(`Direct tool:end event emitted for ${toolName}`, {
|
|
153
|
+
toolName,
|
|
154
|
+
result: typeof result === "string"
|
|
155
|
+
? result.substring(0, 100)
|
|
156
|
+
: JSON.stringify(result).substring(0, 100),
|
|
157
|
+
hasEmitter: !!emitter,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
// 🔧 EMIT TOOL END EVENT FOR ERROR - Bedrock-compatible format
|
|
164
|
+
if (this.neurolink?.getEventEmitter) {
|
|
165
|
+
const emitter = this.neurolink.getEventEmitter();
|
|
166
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
167
|
+
emitter.emit("tool:end", { tool: toolName, error: errorMsg });
|
|
168
|
+
logger.debug(`Direct tool:end error event emitted for ${toolName}`, {
|
|
169
|
+
toolName,
|
|
170
|
+
error: errorMsg,
|
|
171
|
+
hasEmitter: !!emitter,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// Fallback: include tool as-is if it doesn't have execute function
|
|
181
|
+
tools[toolName] = directTool;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
logger.debug(`Direct tools processing complete`, {
|
|
185
|
+
directToolsProcessed: Object.keys(this.directTools).length,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Process custom tools from setupToolExecutor
|
|
190
|
+
*/
|
|
191
|
+
async processCustomTools(tools) {
|
|
192
|
+
if (!this.customTools || this.customTools.size === 0) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
logger.debug(`[ToolsManager] Loading ${this.customTools.size} custom tools from setupToolExecutor`);
|
|
196
|
+
for (const [toolName, toolDef] of this.customTools.entries()) {
|
|
197
|
+
logger.debug(`Processing custom tool: ${toolName}`, {
|
|
198
|
+
toolDef: typeof toolDef,
|
|
199
|
+
hasExecute: toolDef && typeof toolDef === "object" && "execute" in toolDef,
|
|
200
|
+
hasName: toolDef && typeof toolDef === "object" && "name" in toolDef,
|
|
201
|
+
});
|
|
202
|
+
// Validate tool definition has required execute function
|
|
203
|
+
const toolInfo = toolDef ||
|
|
204
|
+
{};
|
|
205
|
+
if (toolInfo && typeof toolInfo.execute === "function") {
|
|
206
|
+
const tool = await this.createCustomToolFromDefinition(toolName, toolInfo);
|
|
207
|
+
if (tool && !tools[toolName]) {
|
|
208
|
+
tools[toolName] = tool;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
logger.debug(`[ToolsManager] Custom tools processing complete`, {
|
|
213
|
+
customToolsProcessed: this.customTools.size,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Process MCP tools integration
|
|
218
|
+
*/
|
|
219
|
+
async processMCPTools(tools) {
|
|
220
|
+
// MCP tools loading simplified - removed functionCalling dependency
|
|
221
|
+
if (!this.mcpTools) {
|
|
222
|
+
// Set empty tools object - MCP tools are handled at a higher level
|
|
223
|
+
this.mcpTools = {};
|
|
224
|
+
}
|
|
225
|
+
// Add MCP tools if available, but don't overwrite existing direct tools
|
|
226
|
+
// Direct tools (Zod-based) take precedence over MCP tools (JSON Schema)
|
|
227
|
+
if (this.mcpTools) {
|
|
228
|
+
for (const [name, tool] of Object.entries(this.mcpTools)) {
|
|
229
|
+
if (!tools[name]) {
|
|
230
|
+
tools[name] = tool;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Process external MCP tools
|
|
237
|
+
*/
|
|
238
|
+
async processExternalMCPTools(tools) {
|
|
239
|
+
if (!this.neurolink ||
|
|
240
|
+
typeof this.neurolink.getExternalMCPTools !== "function") {
|
|
241
|
+
logger.debug(`[ToolsManager] No external MCP tool interface available`, {
|
|
242
|
+
hasNeuroLink: !!this.neurolink,
|
|
243
|
+
hasGetExternalMCPTools: this.neurolink &&
|
|
244
|
+
typeof this.neurolink.getExternalMCPTools === "function",
|
|
245
|
+
});
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
logger.debug(`[ToolsManager] Loading external MCP tools for ${this.providerName}`);
|
|
250
|
+
const externalTools = await this.neurolink.getExternalMCPTools();
|
|
251
|
+
logger.debug(`[ToolsManager] Found ${externalTools.length} external MCP tools`);
|
|
252
|
+
for (const tool of externalTools) {
|
|
253
|
+
const mcpTool = await this.createExternalMCPTool(tool);
|
|
254
|
+
if (mcpTool && !tools[tool.name]) {
|
|
255
|
+
tools[tool.name] = mcpTool;
|
|
256
|
+
logger.debug(`[ToolsManager] Successfully added external MCP tool: ${tool.name}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
logger.debug(`[ToolsManager] External MCP tools loading complete`, {
|
|
260
|
+
totalToolsAdded: externalTools.length,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
logger.error(`[ToolsManager] Failed to load external MCP tools for ${this.providerName}:`, error);
|
|
265
|
+
// Not an error - external tools are optional
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Create a custom tool from tool definition
|
|
270
|
+
*/
|
|
271
|
+
async createCustomToolFromDefinition(toolName, toolInfo) {
|
|
272
|
+
try {
|
|
273
|
+
logger.debug(`[ToolsManager] Converting custom tool: ${toolName}`);
|
|
274
|
+
let finalSchema;
|
|
275
|
+
let originalInputSchema;
|
|
276
|
+
// Prioritize parameters (Zod), then inputSchema (Zod or JSON Schema)
|
|
277
|
+
if (toolInfo.parameters &&
|
|
278
|
+
this.utilities?.isZodSchema?.(toolInfo.parameters)) {
|
|
279
|
+
finalSchema = toolInfo.parameters;
|
|
280
|
+
}
|
|
281
|
+
else if (toolInfo.inputSchema &&
|
|
282
|
+
this.utilities?.isZodSchema?.(toolInfo.inputSchema)) {
|
|
283
|
+
finalSchema = toolInfo.inputSchema;
|
|
284
|
+
}
|
|
285
|
+
else if (toolInfo.inputSchema &&
|
|
286
|
+
typeof toolInfo.inputSchema === "object") {
|
|
287
|
+
// Use original JSON Schema with jsonSchema() wrapper - NO CONVERSION!
|
|
288
|
+
originalInputSchema = toolInfo.inputSchema;
|
|
289
|
+
finalSchema = jsonSchema(originalInputSchema);
|
|
290
|
+
}
|
|
291
|
+
else if (toolInfo.parameters &&
|
|
292
|
+
typeof toolInfo.parameters === "object") {
|
|
293
|
+
finalSchema = convertJsonSchemaToZod(toolInfo.parameters);
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
finalSchema = z.object({});
|
|
297
|
+
}
|
|
298
|
+
return createAISDKTool({
|
|
299
|
+
description: toolInfo.description || `Tool ${toolName}`,
|
|
300
|
+
parameters: finalSchema,
|
|
301
|
+
execute: async (params) => {
|
|
302
|
+
const startTime = Date.now();
|
|
303
|
+
let executionId;
|
|
304
|
+
if (this.neurolink?.emitToolStart) {
|
|
305
|
+
executionId = this.neurolink.emitToolStart(toolName, params, startTime);
|
|
306
|
+
logger.debug(`Custom tool:start emitted via NeuroLink for ${toolName}`, {
|
|
307
|
+
toolName,
|
|
308
|
+
executionId,
|
|
309
|
+
input: params,
|
|
310
|
+
hasNativeEmission: true,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
try {
|
|
314
|
+
// 🔧 PARAMETER FLOW TRACING - Before NeuroLink executeTool call
|
|
315
|
+
logger.debug(`About to call NeuroLink executeTool for ${toolName}`, {
|
|
316
|
+
toolName,
|
|
317
|
+
paramsBeforeExecution: {
|
|
318
|
+
type: typeof params,
|
|
319
|
+
isNull: params === null,
|
|
320
|
+
isUndefined: params === undefined,
|
|
321
|
+
isEmpty: params &&
|
|
322
|
+
typeof params === "object" &&
|
|
323
|
+
Object.keys(params).length === 0,
|
|
324
|
+
keys: params && typeof params === "object"
|
|
325
|
+
? Object.keys(params)
|
|
326
|
+
: "NOT_OBJECT",
|
|
327
|
+
keysLength: params && typeof params === "object"
|
|
328
|
+
? Object.keys(params).length
|
|
329
|
+
: 0,
|
|
330
|
+
},
|
|
331
|
+
executorInfo: {
|
|
332
|
+
hasExecutor: typeof toolInfo.execute === "function",
|
|
333
|
+
executorType: typeof toolInfo.execute,
|
|
334
|
+
},
|
|
335
|
+
timestamp: Date.now(),
|
|
336
|
+
phase: "BEFORE_NEUROLINK_EXECUTE",
|
|
337
|
+
});
|
|
338
|
+
const result = await toolInfo.execute(params);
|
|
339
|
+
// 🔧 PARAMETER FLOW TRACING - After NeuroLink executeTool call
|
|
340
|
+
logger.debug(`NeuroLink executeTool completed for ${toolName}`, {
|
|
341
|
+
toolName,
|
|
342
|
+
resultInfo: {
|
|
343
|
+
type: typeof result,
|
|
344
|
+
isNull: result === null,
|
|
345
|
+
isUndefined: result === undefined,
|
|
346
|
+
hasError: result && typeof result === "object" && "error" in result,
|
|
347
|
+
},
|
|
348
|
+
timestamp: Date.now(),
|
|
349
|
+
phase: "AFTER_NEUROLINK_EXECUTE",
|
|
350
|
+
});
|
|
351
|
+
const convertedResult = this.utilities?.convertToolResult
|
|
352
|
+
? await this.utilities.convertToolResult(result)
|
|
353
|
+
: result;
|
|
354
|
+
const endTime = Date.now();
|
|
355
|
+
// 🔧 NATIVE NEUROLINK EVENT EMISSION - Tool End (Success)
|
|
356
|
+
if (this.neurolink?.emitToolEnd) {
|
|
357
|
+
this.neurolink.emitToolEnd(toolName, convertedResult, undefined, // no error
|
|
358
|
+
startTime, endTime, executionId);
|
|
359
|
+
logger.debug(`Custom tool:end emitted via NeuroLink for ${toolName}`, {
|
|
360
|
+
toolName,
|
|
361
|
+
executionId,
|
|
362
|
+
duration: endTime - startTime,
|
|
363
|
+
hasResult: convertedResult !== undefined,
|
|
364
|
+
hasNativeEmission: true,
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
return convertedResult;
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
const endTime = Date.now();
|
|
371
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
372
|
+
// 🔧 NATIVE NEUROLINK EVENT EMISSION - Tool End (Error)
|
|
373
|
+
if (this.neurolink?.emitToolEnd) {
|
|
374
|
+
this.neurolink.emitToolEnd(toolName, undefined, // no result
|
|
375
|
+
errorMsg, startTime, endTime, executionId);
|
|
376
|
+
logger.info(`Custom tool:end error emitted via NeuroLink for ${toolName}`, {
|
|
377
|
+
toolName,
|
|
378
|
+
executionId,
|
|
379
|
+
duration: endTime - startTime,
|
|
380
|
+
error: errorMsg,
|
|
381
|
+
hasNativeEmission: true,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
throw error;
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
catch (toolCreationError) {
|
|
390
|
+
logger.error(`Failed to create tool: ${toolName}`, toolCreationError);
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Create an external MCP tool
|
|
396
|
+
*/
|
|
397
|
+
async createExternalMCPTool(tool) {
|
|
398
|
+
try {
|
|
399
|
+
logger.debug(`[ToolsManager] Converting external MCP tool: ${tool.name}`);
|
|
400
|
+
// Use original JSON Schema from MCP tool if available, otherwise use permissive schema
|
|
401
|
+
let finalSchema;
|
|
402
|
+
if (tool.inputSchema && typeof tool.inputSchema === "object") {
|
|
403
|
+
// Clone and fix the schema for OpenAI strict mode compatibility
|
|
404
|
+
const originalSchema = tool.inputSchema;
|
|
405
|
+
const fixedSchema = this.utilities?.fixSchemaForOpenAIStrictMode
|
|
406
|
+
? this.utilities.fixSchemaForOpenAIStrictMode(originalSchema)
|
|
407
|
+
: originalSchema;
|
|
408
|
+
finalSchema = jsonSchema(fixedSchema);
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
finalSchema = this.utilities?.createPermissiveZodSchema
|
|
412
|
+
? this.utilities.createPermissiveZodSchema()
|
|
413
|
+
: z.object({});
|
|
414
|
+
}
|
|
415
|
+
return createAISDKTool({
|
|
416
|
+
description: tool.description || `External MCP tool ${tool.name}`,
|
|
417
|
+
parameters: finalSchema,
|
|
418
|
+
execute: async (params) => {
|
|
419
|
+
logger.debug(`Executing external MCP tool: ${tool.name}`, {
|
|
420
|
+
toolName: tool.name,
|
|
421
|
+
serverId: tool.serverId,
|
|
422
|
+
params: JSON.stringify(params),
|
|
423
|
+
paramsType: typeof params,
|
|
424
|
+
hasNeurolink: !!this.neurolink,
|
|
425
|
+
hasExecuteFunction: this.neurolink &&
|
|
426
|
+
typeof this.neurolink.executeExternalMCPTool === "function",
|
|
427
|
+
timestamp: Date.now(),
|
|
428
|
+
});
|
|
429
|
+
// 🔧 EMIT TOOL START EVENT - Bedrock-compatible format
|
|
430
|
+
if (this.neurolink?.getEventEmitter) {
|
|
431
|
+
const emitter = this.neurolink.getEventEmitter();
|
|
432
|
+
emitter.emit("tool:start", { tool: tool.name, input: params });
|
|
433
|
+
logger.debug(`tool:start event emitted for ${tool.name}`, {
|
|
434
|
+
toolName: tool.name,
|
|
435
|
+
input: params,
|
|
436
|
+
hasEmitter: !!emitter,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
// Execute via NeuroLink's direct tool execution
|
|
440
|
+
if (this.neurolink &&
|
|
441
|
+
typeof this.neurolink.executeExternalMCPTool === "function") {
|
|
442
|
+
try {
|
|
443
|
+
const result = await this.neurolink.executeExternalMCPTool(tool.serverId || "unknown", tool.name, params);
|
|
444
|
+
// 🔧 EMIT TOOL END EVENT - Bedrock-compatible format
|
|
445
|
+
if (this.neurolink?.getEventEmitter) {
|
|
446
|
+
const emitter = this.neurolink.getEventEmitter();
|
|
447
|
+
emitter.emit("tool:end", { tool: tool.name, result });
|
|
448
|
+
logger.debug(`tool:end event emitted for ${tool.name}`, {
|
|
449
|
+
toolName: tool.name,
|
|
450
|
+
result: typeof result === "string"
|
|
451
|
+
? result.substring(0, 100)
|
|
452
|
+
: JSON.stringify(result).substring(0, 100),
|
|
453
|
+
hasEmitter: !!emitter,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
logger.debug(`External MCP tool executed: ${tool.name}`, {
|
|
457
|
+
toolName: tool.name,
|
|
458
|
+
result: typeof result === "string"
|
|
459
|
+
? result.substring(0, 200)
|
|
460
|
+
: JSON.stringify(result).substring(0, 200),
|
|
461
|
+
resultType: typeof result,
|
|
462
|
+
timestamp: Date.now(),
|
|
463
|
+
});
|
|
464
|
+
return result;
|
|
465
|
+
}
|
|
466
|
+
catch (mcpError) {
|
|
467
|
+
// 🔧 EMIT TOOL END EVENT FOR ERROR - Bedrock-compatible format
|
|
468
|
+
if (this.neurolink?.getEventEmitter) {
|
|
469
|
+
const emitter = this.neurolink.getEventEmitter();
|
|
470
|
+
const errorMsg = mcpError instanceof Error
|
|
471
|
+
? mcpError.message
|
|
472
|
+
: String(mcpError);
|
|
473
|
+
emitter.emit("tool:end", { tool: tool.name, error: errorMsg });
|
|
474
|
+
logger.debug(`tool:end error event emitted for ${tool.name}`, {
|
|
475
|
+
toolName: tool.name,
|
|
476
|
+
error: errorMsg,
|
|
477
|
+
hasEmitter: !!emitter,
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
logger.error(`External MCP tool failed: ${tool.name}`, {
|
|
481
|
+
toolName: tool.name,
|
|
482
|
+
serverId: tool.serverId,
|
|
483
|
+
error: mcpError instanceof Error
|
|
484
|
+
? mcpError.message
|
|
485
|
+
: String(mcpError),
|
|
486
|
+
errorStack: mcpError instanceof Error ? mcpError.stack : undefined,
|
|
487
|
+
params: JSON.stringify(params),
|
|
488
|
+
timestamp: Date.now(),
|
|
489
|
+
});
|
|
490
|
+
throw mcpError;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
const error = `Cannot execute external MCP tool: NeuroLink executeExternalMCPTool not available`;
|
|
495
|
+
// 🔧 EMIT TOOL END EVENT FOR ERROR - Bedrock-compatible format
|
|
496
|
+
if (this.neurolink?.getEventEmitter) {
|
|
497
|
+
const emitter = this.neurolink.getEventEmitter();
|
|
498
|
+
emitter.emit("tool:end", { tool: tool.name, error });
|
|
499
|
+
logger.debug(`tool:end error event emitted for ${tool.name}`, {
|
|
500
|
+
toolName: tool.name,
|
|
501
|
+
error,
|
|
502
|
+
hasEmitter: !!emitter,
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
logger.error(`${error}`, {
|
|
506
|
+
toolName: tool.name,
|
|
507
|
+
hasNeurolink: !!this.neurolink,
|
|
508
|
+
neurolinkType: typeof this.neurolink,
|
|
509
|
+
timestamp: Date.now(),
|
|
510
|
+
});
|
|
511
|
+
throw new Error(error);
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
catch (toolCreationError) {
|
|
517
|
+
logger.error(`Failed to create external MCP tool: ${tool.name}`, toolCreationError);
|
|
518
|
+
return null;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
//# sourceMappingURL=ToolsManager.js.map
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities Module
|
|
3
|
+
*
|
|
4
|
+
* Handles validation, normalization, schema conversion, and error handling utilities.
|
|
5
|
+
* Extracted from BaseProvider to follow Single Responsibility Principle.
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - Options validation (text generation and stream options)
|
|
9
|
+
* - Options normalization (string to object conversion)
|
|
10
|
+
* - Provider information formatting
|
|
11
|
+
* - Timeout parsing and calculation
|
|
12
|
+
* - Schema utilities (Zod detection, permissive schema creation, OpenAI strict mode fixes)
|
|
13
|
+
* - Tool result conversion
|
|
14
|
+
* - Middleware options extraction
|
|
15
|
+
* - Common error pattern handling
|
|
16
|
+
*
|
|
17
|
+
* @module core/modules/Utilities
|
|
18
|
+
*/
|
|
19
|
+
import type { AIProviderName, TextGenerationOptions } from "../../types/index.js";
|
|
20
|
+
import type { StreamOptions } from "../../types/streamTypes.js";
|
|
21
|
+
import type { MiddlewareFactoryOptions } from "../../types/middlewareTypes.js";
|
|
22
|
+
import type { ZodUnknownSchema } from "../../types/typeAliases.js";
|
|
23
|
+
/**
|
|
24
|
+
* Utilities class - Provides validation, normalization, and utility methods
|
|
25
|
+
*/
|
|
26
|
+
export declare class Utilities {
|
|
27
|
+
private readonly providerName;
|
|
28
|
+
private readonly modelName;
|
|
29
|
+
private readonly defaultTimeout;
|
|
30
|
+
private readonly middlewareOptions?;
|
|
31
|
+
constructor(providerName: AIProviderName, modelName: string, defaultTimeout?: number, middlewareOptions?: MiddlewareFactoryOptions | undefined);
|
|
32
|
+
/**
|
|
33
|
+
* Validate text generation options
|
|
34
|
+
*/
|
|
35
|
+
validateOptions(options: TextGenerationOptions): void;
|
|
36
|
+
/**
|
|
37
|
+
* Validate stream options
|
|
38
|
+
*/
|
|
39
|
+
validateStreamOptions(options: StreamOptions): void;
|
|
40
|
+
/**
|
|
41
|
+
* Normalize text generation options from string or object
|
|
42
|
+
*/
|
|
43
|
+
normalizeTextOptions(optionsOrPrompt: TextGenerationOptions | string): TextGenerationOptions;
|
|
44
|
+
/**
|
|
45
|
+
* Normalize stream options from string or object
|
|
46
|
+
*/
|
|
47
|
+
normalizeStreamOptions(optionsOrPrompt: StreamOptions | string): StreamOptions;
|
|
48
|
+
/**
|
|
49
|
+
* Get provider information
|
|
50
|
+
*/
|
|
51
|
+
getProviderInfo(): {
|
|
52
|
+
provider: string;
|
|
53
|
+
model: string;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Get timeout value in milliseconds from options
|
|
57
|
+
* Supports number or string formats (e.g., '30s', '2m', '1h')
|
|
58
|
+
*/
|
|
59
|
+
getTimeout(options: TextGenerationOptions | StreamOptions): number;
|
|
60
|
+
/**
|
|
61
|
+
* Check if a schema is a Zod schema
|
|
62
|
+
*/
|
|
63
|
+
isZodSchema(schema: unknown): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Convert tool execution result from MCP format to standard format
|
|
66
|
+
* Handles tool failures gracefully to prevent stream termination
|
|
67
|
+
*/
|
|
68
|
+
convertToolResult(result: unknown): Promise<unknown>;
|
|
69
|
+
/**
|
|
70
|
+
* Create a permissive Zod schema that accepts all parameters as-is
|
|
71
|
+
*/
|
|
72
|
+
createPermissiveZodSchema(): ZodUnknownSchema;
|
|
73
|
+
/**
|
|
74
|
+
* Recursively fix JSON Schema for OpenAI strict mode compatibility
|
|
75
|
+
* OpenAI requires additionalProperties: false at ALL levels and preserves required array
|
|
76
|
+
*/
|
|
77
|
+
fixSchemaForOpenAIStrictMode(schema: Record<string, unknown>): Record<string, unknown>;
|
|
78
|
+
/**
|
|
79
|
+
* Extract middleware options from generation/stream options
|
|
80
|
+
* This is the single source of truth for deciding if middleware should be applied
|
|
81
|
+
*/
|
|
82
|
+
extractMiddlewareOptions(options: TextGenerationOptions | StreamOptions): MiddlewareFactoryOptions | null;
|
|
83
|
+
/**
|
|
84
|
+
* Handle common error patterns across providers
|
|
85
|
+
* Returns transformed error or null if not a common pattern
|
|
86
|
+
*/
|
|
87
|
+
handleCommonErrors(error: unknown): Error | null;
|
|
88
|
+
}
|