@juspay/neurolink 7.37.0 → 7.37.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 (61) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cli/commands/config.d.ts +18 -18
  3. package/dist/cli/factories/commandFactory.d.ts +24 -0
  4. package/dist/cli/factories/commandFactory.js +297 -245
  5. package/dist/core/baseProvider.d.ts +40 -3
  6. package/dist/core/baseProvider.js +689 -352
  7. package/dist/core/constants.d.ts +2 -30
  8. package/dist/core/constants.js +15 -43
  9. package/dist/factories/providerFactory.js +23 -6
  10. package/dist/index.d.ts +3 -2
  11. package/dist/index.js +4 -3
  12. package/dist/lib/core/baseProvider.d.ts +40 -3
  13. package/dist/lib/core/baseProvider.js +689 -352
  14. package/dist/lib/core/constants.d.ts +2 -30
  15. package/dist/lib/core/constants.js +15 -43
  16. package/dist/lib/factories/providerFactory.js +23 -6
  17. package/dist/lib/index.d.ts +3 -2
  18. package/dist/lib/index.js +4 -3
  19. package/dist/lib/mcp/externalServerManager.js +2 -2
  20. package/dist/lib/mcp/registry.js +2 -2
  21. package/dist/lib/mcp/servers/agent/directToolsServer.js +19 -10
  22. package/dist/lib/mcp/toolRegistry.js +4 -8
  23. package/dist/lib/neurolink.d.ts +62 -27
  24. package/dist/lib/neurolink.js +415 -719
  25. package/dist/lib/providers/amazonBedrock.js +2 -2
  26. package/dist/lib/providers/googleVertex.d.ts +3 -23
  27. package/dist/lib/providers/googleVertex.js +14 -342
  28. package/dist/lib/providers/openAI.d.ts +23 -0
  29. package/dist/lib/providers/openAI.js +313 -6
  30. package/dist/lib/providers/sagemaker/language-model.d.ts +2 -2
  31. package/dist/lib/sdk/toolRegistration.js +18 -1
  32. package/dist/lib/types/common.d.ts +98 -0
  33. package/dist/lib/types/streamTypes.d.ts +13 -6
  34. package/dist/lib/types/typeAliases.d.ts +3 -2
  35. package/dist/lib/utils/parameterValidation.js +6 -25
  36. package/dist/lib/utils/promptRedaction.js +4 -4
  37. package/dist/lib/utils/schemaConversion.d.ts +14 -0
  38. package/dist/lib/utils/schemaConversion.js +140 -0
  39. package/dist/lib/utils/transformationUtils.js +143 -5
  40. package/dist/mcp/externalServerManager.js +2 -2
  41. package/dist/mcp/registry.js +2 -2
  42. package/dist/mcp/servers/agent/directToolsServer.js +19 -10
  43. package/dist/mcp/toolRegistry.js +4 -8
  44. package/dist/neurolink.d.ts +62 -27
  45. package/dist/neurolink.js +415 -719
  46. package/dist/providers/amazonBedrock.js +2 -2
  47. package/dist/providers/googleVertex.d.ts +3 -23
  48. package/dist/providers/googleVertex.js +14 -342
  49. package/dist/providers/openAI.d.ts +23 -0
  50. package/dist/providers/openAI.js +313 -6
  51. package/dist/providers/sagemaker/language-model.d.ts +2 -2
  52. package/dist/sdk/toolRegistration.js +18 -1
  53. package/dist/types/common.d.ts +98 -0
  54. package/dist/types/streamTypes.d.ts +13 -6
  55. package/dist/types/typeAliases.d.ts +3 -2
  56. package/dist/utils/parameterValidation.js +6 -25
  57. package/dist/utils/promptRedaction.js +4 -4
  58. package/dist/utils/schemaConversion.d.ts +14 -0
  59. package/dist/utils/schemaConversion.js +140 -0
  60. package/dist/utils/transformationUtils.js +143 -5
  61. package/package.json +3 -2
@@ -10,6 +10,7 @@ import { validateApiKey, createOpenAIConfig, getProviderModel, } from "../utils/
10
10
  import { streamAnalyticsCollector } from "../core/streamAnalytics.js";
11
11
  import { buildMessagesArray } from "../utils/messageBuilder.js";
12
12
  import { createProxyFetch } from "../proxy/proxyFetch.js";
13
+ import { isZodSchema } from "../utils/schemaConversion.js";
13
14
  // Configuration helpers - now using consolidated utility
14
15
  const getOpenAIApiKey = () => {
15
16
  return validateApiKey(createOpenAIConfig());
@@ -32,14 +33,22 @@ export class OpenAIProvider extends BaseProvider {
32
33
  });
33
34
  // Initialize model
34
35
  this.model = openai(this.modelName);
35
- logger.debug("OpenAIProviderV2 initialized", {
36
+ logger.debug("OpenAIProvider constructor called", {
36
37
  model: this.modelName,
37
38
  provider: this.providerName,
39
+ supportsTools: this.supportsTools(),
40
+ className: this.constructor.name,
38
41
  });
39
42
  }
40
43
  // ===================
41
44
  // ABSTRACT METHOD IMPLEMENTATIONS
42
45
  // ===================
46
+ /**
47
+ * Check if this provider supports tool/function calling
48
+ */
49
+ supportsTools() {
50
+ return true; // Re-enable tools now that we understand the issue
51
+ }
43
52
  getProviderName() {
44
53
  return AIProviderName.OPENAI;
45
54
  }
@@ -52,6 +61,128 @@ export class OpenAIProvider extends BaseProvider {
52
61
  getAISDKModel() {
53
62
  return this.model;
54
63
  }
64
+ /**
65
+ * OpenAI-specific tool validation and filtering
66
+ * Filters out tools that might cause streaming issues
67
+ */
68
+ validateAndFilterToolsForOpenAI(tools) {
69
+ const validTools = {};
70
+ for (const [name, tool] of Object.entries(tools)) {
71
+ try {
72
+ // Basic validation - ensure tool has required structure
73
+ if (tool && typeof tool === "object") {
74
+ // Check if tool has description (required by OpenAI)
75
+ if (tool.description && typeof tool.description === "string") {
76
+ // Keep the original tool structure - AI SDK will handle Zod schema conversion internally
77
+ const processedTool = { ...tool };
78
+ // Validate that Zod schemas are properly structured for AI SDK processing
79
+ if (tool.parameters && isZodSchema(tool.parameters)) {
80
+ logger.debug(`OpenAI: Tool ${name} has Zod schema - AI SDK will handle conversion`);
81
+ // Basic validation that the Zod schema has the required structure
82
+ this.validateZodSchema(name, tool.parameters);
83
+ }
84
+ // Include the tool with original Zod schema for AI SDK processing
85
+ if (this.isValidToolStructure(processedTool)) {
86
+ validTools[name] = processedTool;
87
+ }
88
+ else {
89
+ logger.warn(`OpenAI: Filtering out tool with invalid structure: ${name}`, {
90
+ parametersType: typeof processedTool.parameters,
91
+ hasDescription: !!processedTool.description,
92
+ hasExecute: !!processedTool.execute,
93
+ });
94
+ }
95
+ }
96
+ else {
97
+ logger.warn(`OpenAI: Filtering out tool without description: ${name}`);
98
+ }
99
+ }
100
+ else {
101
+ logger.warn(`OpenAI: Filtering out invalid tool: ${name}`);
102
+ }
103
+ }
104
+ catch (error) {
105
+ logger.warn(`OpenAI: Error validating tool ${name}:`, error);
106
+ }
107
+ }
108
+ return validTools;
109
+ }
110
+ /**
111
+ * Validate Zod schema structure
112
+ */
113
+ validateZodSchema(toolName, schema) {
114
+ try {
115
+ const zodSchema = schema;
116
+ if (zodSchema._def && zodSchema._def.typeName) {
117
+ logger.debug(`OpenAI: Zod schema for ${toolName} appears valid`, {
118
+ typeName: zodSchema._def.typeName,
119
+ });
120
+ }
121
+ else {
122
+ logger.warn(`OpenAI: Zod schema for ${toolName} missing typeName - may cause issues`);
123
+ }
124
+ }
125
+ catch (zodValidationError) {
126
+ logger.warn(`OpenAI: Zod schema validation failed for ${toolName}:`, zodValidationError);
127
+ // Continue anyway - let AI SDK handle it
128
+ }
129
+ }
130
+ /**
131
+ * Validate tool structure for OpenAI compatibility
132
+ * More lenient validation to avoid filtering out valid tools
133
+ */
134
+ isValidToolStructure(tool) {
135
+ if (!tool || typeof tool !== "object") {
136
+ return false;
137
+ }
138
+ const toolObj = tool;
139
+ // Ensure tool has description and execute function
140
+ if (!toolObj.description || typeof toolObj.description !== "string") {
141
+ return false;
142
+ }
143
+ if (!toolObj.execute || typeof toolObj.execute !== "function") {
144
+ return false;
145
+ }
146
+ return this.isValidToolParameters(toolObj.parameters);
147
+ }
148
+ /**
149
+ * Validate tool parameters for OpenAI compatibility
150
+ * Ensures the tool has either valid Zod schema or valid JSON schema
151
+ */
152
+ isValidToolParameters(parameters) {
153
+ if (!parameters) {
154
+ // For OpenAI, tools without parameters need an empty object schema
155
+ return true;
156
+ }
157
+ // Check if it's a Zod schema - these are valid
158
+ if (isZodSchema(parameters)) {
159
+ return true;
160
+ }
161
+ // Check if it's a JSON schema
162
+ if (typeof parameters !== "object" || parameters === null) {
163
+ return false;
164
+ }
165
+ const params = parameters;
166
+ // If it's a JSON schema, it should have type "object" for OpenAI
167
+ if (params.type && params.type !== "object") {
168
+ return false;
169
+ }
170
+ // OpenAI requires schemas to have properties field, even if empty
171
+ // If there's no properties field, the schema is incomplete
172
+ if (params.type === "object" && !params.properties) {
173
+ logger.warn(`Tool parameter schema missing properties field:`, params);
174
+ return false;
175
+ }
176
+ // If properties exist, they should be an object
177
+ if (params.properties && typeof params.properties !== "object") {
178
+ return false;
179
+ }
180
+ // If required exists, it should be an array
181
+ if (params.required && !Array.isArray(params.required)) {
182
+ return false;
183
+ }
184
+ return true;
185
+ }
55
186
  handleProviderError(error) {
56
187
  if (error instanceof TimeoutError) {
57
188
  throw new NetworkError(error.message, this.providerName);
@@ -90,9 +221,48 @@ export class OpenAIProvider extends BaseProvider {
90
221
  try {
91
222
  // Get tools consistently with generate method
92
223
  const shouldUseTools = !options.disableTools && this.supportsTools();
93
- const tools = shouldUseTools ? await this.getAllTools() : {};
224
+ const allTools = shouldUseTools ? await this.getAllTools() : {};
225
+ // OpenAI-specific fix: Validate tools format and filter out problematic ones
226
+ let tools = this.validateAndFilterToolsForOpenAI(allTools);
227
+ // OpenAI has limits on the number of tools per request - limit to 3 tools max for testing
228
+ const MAX_TOOLS = 3;
229
+ if (Object.keys(tools).length > MAX_TOOLS) {
230
+ logger.warn(`OpenAI: Too many tools (${Object.keys(tools).length}), limiting to ${MAX_TOOLS} tools`);
231
+ const toolEntries = Object.entries(tools);
232
+ tools = Object.fromEntries(toolEntries.slice(0, MAX_TOOLS));
233
+ }
234
+ // Count tools with Zod schemas for debugging
235
+ const zodToolsCount = Object.values(allTools).filter((tool) => tool &&
236
+ typeof tool === "object" &&
237
+ tool.parameters &&
238
+ isZodSchema(tool.parameters)).length;
239
+ logger.info("OpenAI streaming tools", {
240
+ shouldUseTools,
241
+ allToolsCount: Object.keys(allTools).length,
242
+ filteredToolsCount: Object.keys(tools).length,
243
+ zodToolsCount,
244
+ toolNames: Object.keys(tools),
245
+ filteredOutTools: Object.keys(allTools).filter((name) => !tools[name]),
246
+ });
94
247
  // Build message array from options
95
248
  const messages = buildMessagesArray(options);
249
+ // Debug the actual request being sent to OpenAI
250
+ logger.debug(`OpenAI: streamText request parameters:`, {
251
+ modelName: this.modelName,
252
+ messagesCount: messages.length,
253
+ temperature: options.temperature,
254
+ maxTokens: options.maxTokens,
255
+ toolsCount: Object.keys(tools).length,
256
+ toolChoice: shouldUseTools && Object.keys(tools).length > 0 ? "auto" : "none",
257
+ maxSteps: options.maxSteps || DEFAULT_MAX_STEPS,
258
+ firstToolExample: Object.keys(tools).length > 0
259
+ ? {
260
+ name: Object.keys(tools)[0],
261
+ description: tools[Object.keys(tools)[0]]?.description,
262
+ parametersType: typeof tools[Object.keys(tools)[0]]?.parameters,
263
+ }
264
+ : "no-tools",
265
+ });
96
266
  const result = await streamText({
97
267
  model: this.model,
98
268
  messages: messages,
@@ -100,19 +270,156 @@ export class OpenAIProvider extends BaseProvider {
100
270
  maxTokens: options.maxTokens, // No default limit - unlimited unless specified
101
271
  tools,
102
272
  maxSteps: options.maxSteps || DEFAULT_MAX_STEPS,
103
- toolChoice: shouldUseTools ? "auto" : "none",
273
+ toolChoice: shouldUseTools && Object.keys(tools).length > 0 ? "auto" : "none",
104
274
  abortSignal: timeoutController?.controller.signal,
105
275
  });
106
276
  timeoutController?.cleanup();
107
- // Transform stream to match StreamResult interface using BaseProvider method
108
- const transformedStream = this.createTextStream(result);
277
+ // Debug the actual result structure
278
+ logger.debug(`OpenAI: streamText result structure:`, {
279
+ resultKeys: Object.keys(result),
280
+ hasTextStream: !!result.textStream,
281
+ hasToolCalls: !!result.toolCalls,
282
+ hasToolResults: !!result.toolResults,
283
+ resultType: typeof result,
284
+ });
285
+ // Transform string stream to content object stream using fullStream
286
+ const transformedStream = async function* () {
287
+ try {
288
+ logger.debug(`OpenAI: Starting stream transformation`, {
289
+ hasTextStream: !!result.textStream,
290
+ hasFullStream: !!result.fullStream,
291
+ resultKeys: Object.keys(result),
292
+ toolsEnabled: shouldUseTools,
293
+ toolsCount: Object.keys(tools).length,
294
+ });
295
+ let chunkCount = 0;
296
+ let contentYielded = 0;
297
+ // Try fullStream first (handles both text and tool calls), fallback to textStream
298
+ const streamToUse = result.fullStream || result.textStream;
299
+ if (!streamToUse) {
300
+ logger.error("OpenAI: No stream available in result", {
301
+ resultKeys: Object.keys(result),
302
+ });
303
+ return;
304
+ }
305
+ logger.debug(`OpenAI: Stream source selected:`, {
306
+ usingFullStream: !!result.fullStream,
307
+ usingTextStream: !!result.textStream && !result.fullStream,
308
+ streamSourceType: result.fullStream ? "fullStream" : "textStream",
309
+ });
310
+ for await (const chunk of streamToUse) {
311
+ chunkCount++;
312
+ logger.debug(`OpenAI: Processing chunk ${chunkCount}:`, {
313
+ chunkType: typeof chunk,
314
+ chunkValue: typeof chunk === "string"
315
+ ? chunk.substring(0, 50)
316
+ : "not-string",
317
+ chunkKeys: chunk && typeof chunk === "object"
318
+ ? Object.keys(chunk)
319
+ : "not-object",
320
+ hasText: chunk && typeof chunk === "object" && "text" in chunk,
321
+ hasTextDelta: chunk && typeof chunk === "object" && "textDelta" in chunk,
322
+ hasType: chunk && typeof chunk === "object" && "type" in chunk,
323
+ chunkTypeValue: chunk && typeof chunk === "object" && "type" in chunk
324
+ ? chunk.type
325
+ : "no-type",
326
+ });
327
+ let contentToYield = null;
328
+ // Handle different chunk types from fullStream
329
+ if (chunk && typeof chunk === "object") {
330
+ // Log the full chunk structure for debugging (debug mode only)
331
+ if (process.env.NEUROLINK_DEBUG === "true") {
332
+ logger.debug(`OpenAI: Full chunk structure:`, {
333
+ chunkKeys: Object.keys(chunk),
334
+ fullChunk: JSON.stringify(chunk).substring(0, 500),
335
+ });
336
+ }
337
+ if ("type" in chunk && chunk.type === "error") {
338
+ // Handle error chunks when tools are enabled
339
+ const errorChunk = chunk;
340
+ logger.error(`OpenAI: Error chunk received:`, {
341
+ errorType: errorChunk.type,
342
+ errorDetails: errorChunk.error,
343
+ fullChunk: JSON.stringify(chunk),
344
+ });
345
+ // Throw a more descriptive error for tool-related issues
346
+ const errorMessage = errorChunk.error &&
347
+ typeof errorChunk.error === "object" &&
348
+ "message" in errorChunk.error
349
+ ? String(errorChunk.error.message)
350
+ : "OpenAI API error when tools are enabled";
351
+ throw new Error(`OpenAI streaming error with tools: ${errorMessage}. Try disabling tools with --disableTools`);
352
+ }
353
+ else if ("type" in chunk &&
354
+ chunk.type === "text-delta" &&
355
+ "textDelta" in chunk) {
356
+ // Text delta from fullStream
357
+ contentToYield = chunk.textDelta;
358
+ logger.debug(`OpenAI: Found text-delta:`, {
359
+ textDelta: contentToYield,
360
+ });
361
+ }
362
+ else if ("text" in chunk) {
363
+ // Direct text chunk
364
+ contentToYield = chunk.text;
365
+ logger.debug(`OpenAI: Found direct text:`, {
366
+ text: contentToYield,
367
+ });
368
+ }
369
+ else {
370
+ // Log unhandled chunks in debug mode only
371
+ if (process.env.NEUROLINK_DEBUG === "true") {
372
+ logger.debug(`OpenAI: Unhandled object chunk:`, {
373
+ chunkKeys: Object.keys(chunk),
374
+ chunkType: chunk.type || "no-type",
375
+ fullChunk: JSON.stringify(chunk).substring(0, 500),
376
+ });
377
+ }
378
+ }
379
+ }
380
+ else if (typeof chunk === "string") {
381
+ // Direct string chunk from textStream
382
+ contentToYield = chunk;
383
+ logger.debug(`OpenAI: Found string chunk:`, {
384
+ content: contentToYield,
385
+ });
386
+ }
387
+ else {
388
+ logger.warn(`OpenAI: Unhandled chunk type:`, {
389
+ type: typeof chunk,
390
+ value: String(chunk).substring(0, 100),
391
+ });
392
+ }
393
+ if (contentToYield) {
394
+ contentYielded++;
395
+ logger.debug(`OpenAI: Yielding content ${contentYielded}:`, {
396
+ content: contentToYield.substring(0, 50),
397
+ length: contentToYield.length,
398
+ });
399
+ yield { content: contentToYield };
400
+ }
401
+ }
402
+ logger.debug(`OpenAI: Stream transformation completed`, {
403
+ totalChunks: chunkCount,
404
+ contentYielded,
405
+ success: contentYielded > 0,
406
+ });
407
+ if (contentYielded === 0) {
408
+ logger.warn(`OpenAI: No content was yielded from stream despite processing ${chunkCount} chunks`);
409
+ }
410
+ }
411
+ catch (streamError) {
412
+ logger.error(`OpenAI: Stream transformation error:`, streamError);
413
+ throw streamError;
414
+ }
415
+ };
109
416
  // Create analytics promise that resolves after stream completion
110
417
  const analyticsPromise = streamAnalyticsCollector.createAnalytics(this.providerName, this.modelName, result, Date.now() - startTime, {
111
418
  requestId: `openai-stream-${Date.now()}`,
112
419
  streamingMode: true,
113
420
  });
114
421
  return {
115
- stream: transformedStream,
422
+ stream: transformedStream(),
116
423
  provider: this.providerName,
117
424
  model: this.modelName,
118
425
  analytics: analyticsPromise,
@@ -131,7 +131,7 @@ export declare class SageMakerLanguageModel implements LanguageModelV1 {
131
131
  provider: string;
132
132
  specificationVersion: string;
133
133
  endpointName: string;
134
- modelType: "huggingface" | "mistral" | "custom" | "claude" | "llama" | "jumpstart" | undefined;
134
+ modelType: "custom" | "huggingface" | "mistral" | "claude" | "llama" | "jumpstart" | undefined;
135
135
  region: string;
136
136
  };
137
137
  /**
@@ -178,7 +178,7 @@ export declare class SageMakerLanguageModel implements LanguageModelV1 {
178
178
  provider: string;
179
179
  specificationVersion: string;
180
180
  endpointName: string;
181
- modelType: "huggingface" | "mistral" | "custom" | "claude" | "llama" | "jumpstart" | undefined;
181
+ modelType: "custom" | "huggingface" | "mistral" | "claude" | "llama" | "jumpstart" | undefined;
182
182
  region: string;
183
183
  };
184
184
  }
@@ -5,6 +5,7 @@
5
5
  import { logger } from "../utils/logger.js";
6
6
  import { createMCPServerInfo } from "../utils/mcpDefaults.js";
7
7
  import { validateToolName, validateToolDescription, } from "../utils/parameterValidation.js";
8
+ import { convertZodToJsonSchema, isZodSchema, } from "../utils/schemaConversion.js";
8
9
  /**
9
10
  * Configuration constants for tool validation
10
11
  */
@@ -73,7 +74,9 @@ export function createMCPServerFromTools(serverId, tools, metadata) {
73
74
  mcpTools.push({
74
75
  name,
75
76
  description: tool.description || name,
76
- inputSchema: {},
77
+ inputSchema: tool.parameters
78
+ ? convertSchemaToJsonSchema(tool.parameters)
79
+ : {},
77
80
  });
78
81
  }
79
82
  // SMART DEFAULTS: Use utility to eliminate manual MCPServerInfo creation
@@ -89,6 +92,20 @@ export function createMCPServerFromTools(serverId, tools, metadata) {
89
92
  isCustomTool: false,
90
93
  });
91
94
  }
95
+ /**
96
+ * Helper to convert schema parameters to JSON Schema format
97
+ */
98
+ function convertSchemaToJsonSchema(schema) {
99
+ if (isZodSchema(schema)) {
100
+ return convertZodToJsonSchema(schema);
101
+ }
102
+ // If it's already a JSON Schema object, return as-is
103
+ if (schema && typeof schema === "object") {
104
+ return schema;
105
+ }
106
+ // Return empty object if no schema
107
+ return {};
108
+ }
92
109
  /**
93
110
  * Helper to create a tool with type safety
94
111
  */
@@ -73,3 +73,101 @@ export declare function getErrorMessage(error: unknown): string;
73
73
  * Safe error conversion
74
74
  */
75
75
  export declare function toErrorInfo(error: unknown): ErrorInfo;
76
+ /**
77
+ * NeuroLink Native Event System Types
78
+ */
79
+ /**
80
+ * Tool execution event for real-time streaming
81
+ */
82
+ export interface ToolExecutionEvent {
83
+ type: "tool:start" | "tool:end";
84
+ tool: string;
85
+ input?: unknown;
86
+ result?: unknown;
87
+ error?: string;
88
+ timestamp: number;
89
+ duration?: number;
90
+ executionId: string;
91
+ }
92
+ /**
93
+ * Tool execution summary for completed executions
94
+ */
95
+ export interface ToolExecutionSummary {
96
+ tool: string;
97
+ startTime: number;
98
+ endTime: number;
99
+ duration: number;
100
+ success: boolean;
101
+ result?: unknown;
102
+ error?: string;
103
+ executionId: string;
104
+ metadata?: {
105
+ serverId?: string;
106
+ toolCategory?: "direct" | "custom" | "mcp";
107
+ isExternal?: boolean;
108
+ };
109
+ }
110
+ /**
111
+ * Stream event types for real-time communication
112
+ */
113
+ export interface StreamEvent {
114
+ type: "stream:chunk" | "stream:complete" | "stream:error";
115
+ content?: string;
116
+ metadata?: JsonObject;
117
+ timestamp: number;
118
+ }
119
+ /**
120
+ * Enhanced NeuroLink event types
121
+ * Flexible interface to support both typed and legacy event patterns
122
+ */
123
+ export interface NeuroLinkEvents {
124
+ "tool:start": unknown;
125
+ "tool:end": unknown;
126
+ "stream:start": unknown;
127
+ "stream:end": unknown;
128
+ "stream:chunk": unknown;
129
+ "stream:complete": unknown;
130
+ "stream:error": unknown;
131
+ "generation:start": unknown;
132
+ "generation:end": unknown;
133
+ "response:start": unknown;
134
+ "response:end": unknown;
135
+ "externalMCP:serverConnected": unknown;
136
+ "externalMCP:serverDisconnected": unknown;
137
+ "externalMCP:serverFailed": unknown;
138
+ "externalMCP:toolDiscovered": unknown;
139
+ "externalMCP:toolRemoved": unknown;
140
+ "externalMCP:serverAdded": unknown;
141
+ "externalMCP:serverRemoved": unknown;
142
+ "tools-register:start": unknown;
143
+ "tools-register:end": unknown;
144
+ connected: unknown;
145
+ message: unknown;
146
+ error: unknown;
147
+ log: unknown;
148
+ [key: string]: unknown;
149
+ }
150
+ /**
151
+ * TypeScript utility for typed EventEmitter
152
+ * Flexible interface to support both typed and legacy event patterns
153
+ */
154
+ export interface TypedEventEmitter<TEvents extends Record<string, unknown>> {
155
+ on<K extends keyof TEvents>(event: K, listener: (...args: unknown[]) => void): this;
156
+ emit<K extends keyof TEvents>(event: K, ...args: unknown[]): boolean;
157
+ off<K extends keyof TEvents>(event: K, listener: (...args: unknown[]) => void): this;
158
+ removeAllListeners<K extends keyof TEvents>(event?: K): this;
159
+ listenerCount<K extends keyof TEvents>(event: K): number;
160
+ listeners<K extends keyof TEvents>(event: K): Array<(...args: unknown[]) => void>;
161
+ }
162
+ /**
163
+ * Tool execution context for tracking
164
+ */
165
+ export interface ToolExecutionContext {
166
+ executionId: string;
167
+ tool: string;
168
+ startTime: number;
169
+ endTime?: number;
170
+ result?: unknown;
171
+ error?: string;
172
+ metadata?: JsonObject;
173
+ }
@@ -1,12 +1,13 @@
1
1
  import type { Tool } from "ai";
2
2
  import type { ValidationSchema, StandardRecord } from "./typeAliases.js";
3
- import type { AIProviderName, ProviderConfig } from "./providers.js";
4
- import type { AnalyticsData, TokenUsage } from "./analytics.js";
5
- import type { EvaluationData } from "./evaluation.js";
6
- import type { UnknownRecord, JsonValue } from "./common.js";
7
- import type { ChatMessage } from "./conversation.js";
3
+ import type { ProviderConfig } from "./providers.js";
8
4
  import type { TextContent, ImageContent } from "./content.js";
9
- import type { MiddlewareFactoryOptions } from "./middlewareTypes.js";
5
+ import type { AIProviderName, AnalyticsData } from "../core/types.js";
6
+ import type { TokenUsage } from "./analytics.js";
7
+ import type { EvaluationData } from "../index.js";
8
+ import type { UnknownRecord, JsonValue, ToolExecutionEvent, ToolExecutionSummary } from "./common.js";
9
+ import type { MiddlewareFactoryOptions } from "../types/middlewareTypes.js";
10
+ import type { ChatMessage } from "./conversation.js";
10
11
  /**
11
12
  * Progress tracking and metadata for streaming operations
12
13
  */
@@ -187,6 +188,9 @@ export type StreamResult = {
187
188
  finishReason?: string;
188
189
  toolCalls?: ToolCall[];
189
190
  toolResults?: ToolResult[];
191
+ toolEvents?: AsyncIterable<ToolExecutionEvent>;
192
+ toolExecutions?: ToolExecutionSummary[];
193
+ toolsUsed?: string[];
190
194
  metadata?: {
191
195
  streamId?: string;
192
196
  startTime?: number;
@@ -194,6 +198,9 @@ export type StreamResult = {
194
198
  estimatedDuration?: number;
195
199
  responseTime?: number;
196
200
  fallback?: boolean;
201
+ totalToolExecutions?: number;
202
+ toolExecutionTime?: number;
203
+ hasToolErrors?: boolean;
197
204
  };
198
205
  analytics?: AnalyticsData | Promise<AnalyticsData>;
199
206
  evaluation?: EvaluationData | Promise<EvaluationData>;
@@ -2,14 +2,15 @@
2
2
  * Comprehensive Type Alias Library
3
3
  * Centralizes commonly used complex types to improve readability and maintainability
4
4
  */
5
- import type { ZodType, ZodTypeDef } from "zod";
5
+ import type { ZodTypeAny } from "zod";
6
6
  import type { Schema } from "ai";
7
7
  import type { JsonValue, JsonObject } from "./common.js";
8
8
  /**
9
9
  * Type alias for complex Zod schema type to improve readability
10
10
  * Used across providers and validation systems
11
+ * Using ZodTypeAny to prevent infinite type recursion in zod-to-json-schema
11
12
  */
12
- export type ZodUnknownSchema = ZodType<unknown, ZodTypeDef, unknown>;
13
+ export type ZodUnknownSchema = ZodTypeAny;
13
14
  /**
14
15
  * Union type for schema validation (Zod or AI SDK schema)
15
16
  * Commonly used in provider interfaces and validation functions
@@ -192,28 +192,9 @@ export function validateMCPTool(tool) {
192
192
  if (execError) {
193
193
  errors.push(execError);
194
194
  }
195
- // Additional MCP-specific validation
196
- if (mcpTool.execute) {
197
- try {
198
- // Test execute function with mock data
199
- const mockParams = {};
200
- const mockContext = {
201
- sessionId: "validation-test",
202
- userId: "validation-user",
203
- };
204
- const result = mcpTool.execute(mockParams, mockContext);
205
- const returnsPromise = result && typeof result === "object" && "then" in result;
206
- if (!returnsPromise) {
207
- errors.push(new ValidationError("Execute function must return a Promise", "execute", "NOT_PROMISE", [
208
- "Ensure function returns a Promise<ToolResult>",
209
- "Use async/await pattern",
210
- "Return a result object with success property",
211
- ]));
212
- }
213
- }
214
- catch (error) {
215
- warnings.push(`Execute function validation failed: ${error instanceof Error ? error.message : String(error)}`);
216
- }
195
+ // Simplified validation - just check if execute is a function
196
+ if (mcpTool.execute && typeof mcpTool.execute !== "function") {
197
+ errors.push(new ValidationError("Execute must be a function", "execute", "INVALID_TYPE", ["Provide a function for the execute property"]));
217
198
  }
218
199
  // Check optional properties
219
200
  if (mcpTool.inputSchema && !isNonNullObject(mcpTool.inputSchema)) {
@@ -264,7 +245,7 @@ export function validateTextGenerationOptions(options) {
264
245
  errors.push(tempError);
265
246
  }
266
247
  // Validate maxTokens
267
- const tokensError = validateNumberRange(opts.maxTokens, "maxTokens", 1, 200000);
248
+ const tokensError = validateNumberRange(opts.maxTokens, "maxTokens", 1, 128000);
268
249
  if (tokensError) {
269
250
  errors.push(tokensError);
270
251
  }
@@ -316,7 +297,7 @@ export function validateStreamOptions(options) {
316
297
  errors.push(tempError);
317
298
  }
318
299
  // Validate maxTokens
319
- const tokensError = validateNumberRange(opts.maxTokens, "maxTokens", 1, 200000);
300
+ const tokensError = validateNumberRange(opts.maxTokens, "maxTokens", 1, 128000);
320
301
  if (tokensError) {
321
302
  errors.push(tokensError);
322
303
  }
@@ -349,7 +330,7 @@ export function validateGenerateOptions(options) {
349
330
  if (tempError) {
350
331
  errors.push(tempError);
351
332
  }
352
- const tokensError = validateNumberRange(opts.maxTokens, "maxTokens", 1, 200000);
333
+ const tokensError = validateNumberRange(opts.maxTokens, "maxTokens", 1, 128000);
353
334
  if (tokensError) {
354
335
  errors.push(tokensError);
355
336
  }
@@ -16,8 +16,8 @@ const DEFAULT_REDACTION_OPTIONS = {
16
16
  */
17
17
  export function redactPrompt(prompt, options = {}) {
18
18
  const opts = { ...DEFAULT_REDACTION_OPTIONS, ...options };
19
- if (!prompt || typeof prompt !== 'string') {
20
- return '[INVALID_PROMPT]';
19
+ if (!prompt || typeof prompt !== "string") {
20
+ return "[INVALID_PROMPT]";
21
21
  }
22
22
  const wordCount = prompt.trim().split(/\s+/).length;
23
23
  let redacted = prompt.substring(0, opts.maxLength);
@@ -35,8 +35,8 @@ export function redactPrompt(prompt, options = {}) {
35
35
  * Create a short safe mask for highly sensitive contexts
36
36
  */
37
37
  export function createSafeMask(prompt, _maskLength = 20) {
38
- if (!prompt || typeof prompt !== 'string') {
39
- return '[INVALID_PROMPT]';
38
+ if (!prompt || typeof prompt !== "string") {
39
+ return "[INVALID_PROMPT]";
40
40
  }
41
41
  const wordCount = prompt.trim().split(/\s+/).length;
42
42
  const charCount = prompt.length;