@juspay/neurolink 7.6.0 → 7.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/README.md +79 -4
  3. package/dist/cli/commands/config.d.ts +275 -3
  4. package/dist/cli/commands/config.js +121 -0
  5. package/dist/cli/commands/mcp.js +77 -28
  6. package/dist/cli/factories/commandFactory.js +359 -6
  7. package/dist/core/analytics.js +7 -27
  8. package/dist/core/baseProvider.js +43 -4
  9. package/dist/core/constants.d.ts +46 -0
  10. package/dist/core/constants.js +47 -0
  11. package/dist/core/dynamicModels.d.ts +16 -4
  12. package/dist/core/dynamicModels.js +130 -26
  13. package/dist/core/evaluation.js +5 -1
  14. package/dist/core/evaluationProviders.d.ts +6 -2
  15. package/dist/core/evaluationProviders.js +41 -125
  16. package/dist/core/factory.d.ts +5 -0
  17. package/dist/core/factory.js +62 -50
  18. package/dist/core/modelConfiguration.d.ts +246 -0
  19. package/dist/core/modelConfiguration.js +775 -0
  20. package/dist/core/types.d.ts +22 -3
  21. package/dist/core/types.js +5 -1
  22. package/dist/factories/providerRegistry.js +3 -3
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +1 -1
  25. package/dist/lib/core/analytics.js +7 -27
  26. package/dist/lib/core/baseProvider.js +43 -4
  27. package/dist/lib/core/constants.d.ts +46 -0
  28. package/dist/lib/core/constants.js +47 -0
  29. package/dist/lib/core/dynamicModels.d.ts +16 -4
  30. package/dist/lib/core/dynamicModels.js +130 -26
  31. package/dist/lib/core/evaluation.js +5 -1
  32. package/dist/lib/core/evaluationProviders.d.ts +6 -2
  33. package/dist/lib/core/evaluationProviders.js +41 -125
  34. package/dist/lib/core/factory.d.ts +5 -0
  35. package/dist/lib/core/factory.js +63 -50
  36. package/dist/lib/core/modelConfiguration.d.ts +246 -0
  37. package/dist/lib/core/modelConfiguration.js +775 -0
  38. package/dist/lib/core/types.d.ts +22 -3
  39. package/dist/lib/core/types.js +5 -1
  40. package/dist/lib/factories/providerRegistry.js +3 -3
  41. package/dist/lib/index.d.ts +1 -1
  42. package/dist/lib/index.js +1 -1
  43. package/dist/lib/mcp/factory.d.ts +5 -5
  44. package/dist/lib/mcp/factory.js +2 -2
  45. package/dist/lib/mcp/servers/utilities/utilityServer.d.ts +1 -1
  46. package/dist/lib/mcp/servers/utilities/utilityServer.js +1 -1
  47. package/dist/lib/mcp/toolRegistry.js +2 -2
  48. package/dist/lib/neurolink.d.ts +168 -12
  49. package/dist/lib/neurolink.js +685 -123
  50. package/dist/lib/providers/anthropic.js +52 -2
  51. package/dist/lib/providers/googleAiStudio.js +4 -0
  52. package/dist/lib/providers/googleVertex.d.ts +75 -9
  53. package/dist/lib/providers/googleVertex.js +365 -46
  54. package/dist/lib/providers/huggingFace.d.ts +52 -11
  55. package/dist/lib/providers/huggingFace.js +180 -42
  56. package/dist/lib/providers/litellm.d.ts +9 -9
  57. package/dist/lib/providers/litellm.js +103 -16
  58. package/dist/lib/providers/ollama.d.ts +52 -17
  59. package/dist/lib/providers/ollama.js +276 -68
  60. package/dist/lib/sdk/toolRegistration.d.ts +42 -0
  61. package/dist/lib/sdk/toolRegistration.js +269 -27
  62. package/dist/lib/telemetry/telemetryService.d.ts +6 -0
  63. package/dist/lib/telemetry/telemetryService.js +38 -3
  64. package/dist/lib/types/contextTypes.d.ts +75 -11
  65. package/dist/lib/types/contextTypes.js +227 -1
  66. package/dist/lib/types/domainTypes.d.ts +62 -0
  67. package/dist/lib/types/domainTypes.js +5 -0
  68. package/dist/lib/types/generateTypes.d.ts +52 -0
  69. package/dist/lib/types/index.d.ts +1 -0
  70. package/dist/lib/types/mcpTypes.d.ts +1 -1
  71. package/dist/lib/types/mcpTypes.js +1 -1
  72. package/dist/lib/types/streamTypes.d.ts +14 -0
  73. package/dist/lib/types/universalProviderOptions.d.ts +1 -1
  74. package/dist/lib/utils/errorHandling.d.ts +142 -0
  75. package/dist/lib/utils/errorHandling.js +316 -0
  76. package/dist/lib/utils/factoryProcessing.d.ts +74 -0
  77. package/dist/lib/utils/factoryProcessing.js +588 -0
  78. package/dist/lib/utils/optionsConversion.d.ts +54 -0
  79. package/dist/lib/utils/optionsConversion.js +126 -0
  80. package/dist/lib/utils/optionsUtils.d.ts +246 -0
  81. package/dist/lib/utils/optionsUtils.js +960 -0
  82. package/dist/lib/utils/providerHealth.d.ts +107 -0
  83. package/dist/lib/utils/providerHealth.js +507 -0
  84. package/dist/lib/utils/providerUtils.d.ts +17 -0
  85. package/dist/lib/utils/providerUtils.js +271 -16
  86. package/dist/lib/utils/timeout.js +1 -1
  87. package/dist/lib/utils/tokenLimits.d.ts +33 -0
  88. package/dist/lib/utils/tokenLimits.js +118 -0
  89. package/dist/mcp/factory.d.ts +5 -5
  90. package/dist/mcp/factory.js +2 -2
  91. package/dist/mcp/servers/utilities/utilityServer.d.ts +1 -1
  92. package/dist/mcp/servers/utilities/utilityServer.js +1 -1
  93. package/dist/mcp/toolRegistry.js +2 -2
  94. package/dist/neurolink.d.ts +168 -12
  95. package/dist/neurolink.js +685 -123
  96. package/dist/providers/anthropic.js +52 -2
  97. package/dist/providers/googleAiStudio.js +4 -0
  98. package/dist/providers/googleVertex.d.ts +75 -9
  99. package/dist/providers/googleVertex.js +365 -46
  100. package/dist/providers/huggingFace.d.ts +52 -11
  101. package/dist/providers/huggingFace.js +181 -43
  102. package/dist/providers/litellm.d.ts +9 -9
  103. package/dist/providers/litellm.js +103 -16
  104. package/dist/providers/ollama.d.ts +52 -17
  105. package/dist/providers/ollama.js +276 -68
  106. package/dist/sdk/toolRegistration.d.ts +42 -0
  107. package/dist/sdk/toolRegistration.js +269 -27
  108. package/dist/telemetry/telemetryService.d.ts +6 -0
  109. package/dist/telemetry/telemetryService.js +38 -3
  110. package/dist/types/contextTypes.d.ts +75 -11
  111. package/dist/types/contextTypes.js +227 -2
  112. package/dist/types/domainTypes.d.ts +62 -0
  113. package/dist/types/domainTypes.js +5 -0
  114. package/dist/types/generateTypes.d.ts +52 -0
  115. package/dist/types/index.d.ts +1 -0
  116. package/dist/types/mcpTypes.d.ts +1 -1
  117. package/dist/types/mcpTypes.js +1 -1
  118. package/dist/types/streamTypes.d.ts +14 -0
  119. package/dist/types/universalProviderOptions.d.ts +1 -1
  120. package/dist/types/universalProviderOptions.js +0 -1
  121. package/dist/utils/errorHandling.d.ts +142 -0
  122. package/dist/utils/errorHandling.js +316 -0
  123. package/dist/utils/factoryProcessing.d.ts +74 -0
  124. package/dist/utils/factoryProcessing.js +588 -0
  125. package/dist/utils/optionsConversion.d.ts +54 -0
  126. package/dist/utils/optionsConversion.js +126 -0
  127. package/dist/utils/optionsUtils.d.ts +246 -0
  128. package/dist/utils/optionsUtils.js +960 -0
  129. package/dist/utils/providerHealth.d.ts +107 -0
  130. package/dist/utils/providerHealth.js +507 -0
  131. package/dist/utils/providerUtils.d.ts +17 -0
  132. package/dist/utils/providerUtils.js +271 -16
  133. package/dist/utils/timeout.js +1 -1
  134. package/dist/utils/tokenLimits.d.ts +33 -0
  135. package/dist/utils/tokenLimits.js +118 -0
  136. package/package.json +2 -2
@@ -0,0 +1,588 @@
1
+ /**
2
+ * Factory options processing utilities
3
+ *
4
+ * Processes factory configuration and ensures it flows through to AI providers
5
+ */
6
+ import { logger } from "./logger.js";
7
+ // Removed crypto import - using faster string-based hash instead
8
+ /**
9
+ * LRU Cache for factory processing results
10
+ * Addresses GitHub Copilot review comment about adding caching for factory processing results
11
+ */
12
+ class FactoryProcessingCache {
13
+ cache = new Map();
14
+ // Object identity cache to avoid recomputing cache keys for same object
15
+ // Using WeakMap to prevent memory leaks - entries are auto-collected when objects are GC'd
16
+ objectKeyCache = new WeakMap();
17
+ maxSize;
18
+ stats = {
19
+ hits: 0,
20
+ misses: 0,
21
+ evictions: 0,
22
+ totalRequests: 0,
23
+ keysCacheHits: 0, // New stat for object identity cache hits
24
+ };
25
+ constructor() {
26
+ // Configurable cache size via environment variable with bounds checking
27
+ const envCacheSize = process.env.NEUROLINK_FACTORY_CACHE_SIZE || "100";
28
+ const parsedSize = parseInt(envCacheSize, 10);
29
+ // Add bounds checking: min 1, max 10000 to prevent memory issues
30
+ if (isNaN(parsedSize) || parsedSize < 1) {
31
+ this.maxSize = 1;
32
+ logger.warn(`Invalid cache size '${envCacheSize}', using minimum value: 1`);
33
+ }
34
+ else if (parsedSize > 10000) {
35
+ this.maxSize = 10000;
36
+ logger.warn(`Cache size '${parsedSize}' exceeds maximum, using maximum value: 10000`);
37
+ }
38
+ else {
39
+ this.maxSize = parsedSize;
40
+ }
41
+ logger.debug(`FactoryProcessingCache initialized with max size: ${this.maxSize}`);
42
+ }
43
+ /**
44
+ * Generate cache key from options using fast non-cryptographic hash
45
+ * Optimized for large options objects by extracting only key fields
46
+ * Uses numeric hash combination to avoid string concatenation in hot paths
47
+ * Implements object identity cache to avoid recomputation for same objects
48
+ */
49
+ generateCacheKey(options) {
50
+ // Use object identity cache if possible for performance
51
+ if (typeof options === "object" && options !== null) {
52
+ const cachedKey = this.objectKeyCache.get(options);
53
+ if (cachedKey) {
54
+ this.stats.keysCacheHits++;
55
+ return cachedKey;
56
+ }
57
+ }
58
+ try {
59
+ // Extract key field hashes directly without string operations
60
+ const factoryConfigHash = this.extractKeyFieldsHash(options.factoryConfig);
61
+ const contextHash = this.extractKeyFieldsHash(options.context);
62
+ // Combine hashes numerically instead of string concatenation
63
+ const combinedHash = this.combineHashes(factoryConfigHash, contextHash);
64
+ const key = combinedHash.toString(16);
65
+ // Cache the computed key for future use (WeakMap auto-cleans on GC)
66
+ if (typeof options === "object" && options !== null) {
67
+ this.objectKeyCache.set(options, key);
68
+ }
69
+ return key;
70
+ }
71
+ catch (error) {
72
+ logger.warn("Failed to generate cache key, using deterministic fallback", { error });
73
+ return "fallback_" + this.stableStringify(options);
74
+ }
75
+ }
76
+ /**
77
+ * Create deterministic string representation for fallback cache keys
78
+ * Ensures identical options always produce the same cache key
79
+ */
80
+ stableStringify(obj) {
81
+ try {
82
+ if (obj === null || obj === undefined) {
83
+ return String(obj);
84
+ }
85
+ if (typeof obj !== "object") {
86
+ return String(obj);
87
+ }
88
+ // For objects, create a stable representation by sorting keys
89
+ const record = obj;
90
+ const sortedKeys = Object.keys(record).sort();
91
+ const pairs = sortedKeys.map((key) => `${key}:${this.stableStringify(record[key])}`);
92
+ return `{${pairs.join(",")}}`;
93
+ }
94
+ catch {
95
+ // Ultimate fallback - use object type
96
+ return `[${typeof obj}]`;
97
+ }
98
+ }
99
+ /**
100
+ * Extract key field hash from objects without string concatenation
101
+ * Uses numeric hash combination for maximum performance in hot paths
102
+ */
103
+ extractKeyFieldsHash(obj) {
104
+ if (!obj || typeof obj !== "object") {
105
+ return this.hashValue(obj);
106
+ }
107
+ const record = obj;
108
+ let hash = 0;
109
+ // Extract only the most identifying fields - ordered by importance
110
+ const importantFields = [
111
+ "domainType",
112
+ "enhancementType",
113
+ "domainConfig",
114
+ "id",
115
+ "type",
116
+ "name",
117
+ ];
118
+ // Use numeric hash combination instead of string operations
119
+ for (let i = 0; i < importantFields.length; i++) {
120
+ const field = importantFields[i];
121
+ const value = record[field];
122
+ if (value !== undefined) {
123
+ // Combine field name hash and value hash numerically
124
+ const fieldHash = this.hashString(field);
125
+ const valueHash = this.hashValue(value);
126
+ hash = this.combineHashes(hash, this.combineHashes(fieldHash, valueHash));
127
+ }
128
+ }
129
+ // If no important fields found, use object structure hash
130
+ if (hash === 0) {
131
+ hash = Object.keys(record).length;
132
+ }
133
+ return hash;
134
+ }
135
+ /**
136
+ * Extract key identifying fields from objects for cache key generation
137
+ * Optimized to avoid expensive operations on large objects
138
+ * @deprecated Use extractKeyFieldsHash for better performance
139
+ */
140
+ extractKeyFields(obj) {
141
+ if (!obj || typeof obj !== "object") {
142
+ return String(obj || "");
143
+ }
144
+ const record = obj;
145
+ // Pre-allocate array with known maximum size for better performance
146
+ const keyFields = [];
147
+ keyFields.length = 0; // Reset but keep allocated memory
148
+ // Extract only the most identifying fields - ordered by importance for early exit
149
+ const importantFields = [
150
+ "domainType",
151
+ "enhancementType",
152
+ "domainConfig",
153
+ "id",
154
+ "type",
155
+ "name",
156
+ ];
157
+ // Use direct property access instead of 'in' operator for better performance
158
+ for (let i = 0; i < importantFields.length; i++) {
159
+ const field = importantFields[i];
160
+ const value = record[field];
161
+ if (value !== undefined) {
162
+ // Avoid template literals in hot path - use direct concatenation
163
+ keyFields.push(field + ":" + String(value));
164
+ }
165
+ }
166
+ // If no important fields found, use a more efficient fallback
167
+ if (keyFields.length === 0) {
168
+ // Cache the keys.length to avoid repeated Object.keys calls
169
+ keyFields.push("keys:" + Object.keys(record).length.toString());
170
+ }
171
+ return keyFields.join(",");
172
+ }
173
+ /**
174
+ * Fast non-cryptographic string hash function
175
+ * Much faster than MD5 for cache key generation
176
+ */
177
+ fastStringHash(str) {
178
+ let hash = 0;
179
+ if (str.length === 0) {
180
+ return "0";
181
+ }
182
+ for (let i = 0; i < str.length; i++) {
183
+ const char = str.charCodeAt(i);
184
+ hash = (hash << 5) - hash + char;
185
+ hash = hash & hash; // Convert to 32bit integer
186
+ }
187
+ // Convert to unsigned 32-bit integer hex string to avoid hash collisions
188
+ return (hash >>> 0).toString(16);
189
+ }
190
+ /**
191
+ * Fast numeric hash function for strings
192
+ * Returns numeric hash instead of string for performance
193
+ */
194
+ hashString(str) {
195
+ let hash = 0;
196
+ if (str.length === 0) {
197
+ return 0;
198
+ }
199
+ for (let i = 0; i < str.length; i++) {
200
+ const char = str.charCodeAt(i);
201
+ hash = (hash << 5) - hash + char;
202
+ hash = hash & hash; // Convert to 32bit integer
203
+ }
204
+ return hash >>> 0;
205
+ }
206
+ /**
207
+ * Hash any value to a numeric hash
208
+ * Optimized for different value types
209
+ */
210
+ hashValue(value) {
211
+ if (value === null) {
212
+ return 0;
213
+ }
214
+ if (value === undefined) {
215
+ return 1;
216
+ }
217
+ const type = typeof value;
218
+ switch (type) {
219
+ case "string":
220
+ return this.hashString(value);
221
+ case "number":
222
+ return (Math.floor(value) >>> 0) % 2147483647;
223
+ case "boolean":
224
+ return value ? 1 : 0;
225
+ case "object":
226
+ // For objects, use a simple structural hash
227
+ try {
228
+ return this.hashString(JSON.stringify(value));
229
+ }
230
+ catch {
231
+ return this.hashString(String(value));
232
+ }
233
+ default:
234
+ return this.hashString(String(value));
235
+ }
236
+ }
237
+ /**
238
+ * Combine two numeric hashes efficiently
239
+ * Uses bitwise operations for maximum performance
240
+ */
241
+ combineHashes(hash1, hash2) {
242
+ // Use a variation of hash combination that minimizes collisions
243
+ return ((hash1 << 5) + hash1 + hash2) & 0x7fffffff;
244
+ }
245
+ /**
246
+ * Get cached result if available
247
+ */
248
+ get(options) {
249
+ this.stats.totalRequests++;
250
+ const key = this.generateCacheKey(options);
251
+ const cached = this.cache.get(key);
252
+ if (cached) {
253
+ // Update access info for LRU
254
+ cached.accessCount++;
255
+ cached.timestamp = Date.now();
256
+ // Move to end (most recently used)
257
+ this.cache.delete(key);
258
+ this.cache.set(key, cached);
259
+ this.stats.hits++;
260
+ logger.debug("Factory processing cache hit", {
261
+ key: key.substring(0, 8),
262
+ });
263
+ return cached.result;
264
+ }
265
+ this.stats.misses++;
266
+ return null;
267
+ }
268
+ /**
269
+ * Store result in cache
270
+ */
271
+ set(options, result) {
272
+ try {
273
+ const key = this.generateCacheKey(options);
274
+ // Evict oldest entry if at capacity
275
+ if (this.cache.size >= this.maxSize) {
276
+ const oldestKey = this.cache.keys().next().value;
277
+ if (oldestKey !== undefined) {
278
+ this.cache.delete(oldestKey);
279
+ this.stats.evictions++;
280
+ }
281
+ }
282
+ this.cache.set(key, {
283
+ result: { ...result }, // Deep copy to prevent mutations
284
+ timestamp: Date.now(),
285
+ accessCount: 1,
286
+ });
287
+ logger.debug("Factory processing result cached", {
288
+ key: key.substring(0, 8),
289
+ cacheSize: this.cache.size,
290
+ });
291
+ }
292
+ catch (error) {
293
+ logger.warn("Failed to cache factory processing result", { error });
294
+ }
295
+ }
296
+ /**
297
+ * Clear cache (useful for testing or memory management)
298
+ */
299
+ clear() {
300
+ const size = this.cache.size;
301
+ this.cache.clear();
302
+ logger.debug(`Factory processing cache cleared (${size} entries removed)`);
303
+ }
304
+ /**
305
+ * Get cache statistics
306
+ */
307
+ getStats() {
308
+ const hitRate = this.stats.totalRequests > 0
309
+ ? Math.round((this.stats.hits / this.stats.totalRequests) * 100 * 100) /
310
+ 100
311
+ : 0;
312
+ return {
313
+ ...this.stats,
314
+ size: this.cache.size,
315
+ hitRate,
316
+ };
317
+ }
318
+ /**
319
+ * Remove entries older than specified age (in milliseconds)
320
+ */
321
+ evictOld(maxAge = 5 * 60 * 1000) {
322
+ // Default: 5 minutes
323
+ const now = Date.now();
324
+ let evicted = 0;
325
+ for (const [key, entry] of this.cache.entries()) {
326
+ if (now - entry.timestamp > maxAge) {
327
+ this.cache.delete(key);
328
+ evicted++;
329
+ }
330
+ }
331
+ if (evicted > 0) {
332
+ logger.debug(`Evicted ${evicted} old cache entries`);
333
+ this.stats.evictions += evicted;
334
+ }
335
+ return evicted;
336
+ }
337
+ }
338
+ // Global cache instance
339
+ const factoryProcessingCache = new FactoryProcessingCache();
340
+ /**
341
+ * Validates if a value conforms to JsonValue type
342
+ * JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue }
343
+ */
344
+ function isJsonValue(value) {
345
+ if (value === null ||
346
+ typeof value === "string" ||
347
+ typeof value === "number" ||
348
+ typeof value === "boolean") {
349
+ return true;
350
+ }
351
+ if (Array.isArray(value)) {
352
+ return value.every((item) => isJsonValue(item));
353
+ }
354
+ if (typeof value === "object" && value !== null) {
355
+ const obj = value;
356
+ return Object.values(obj).every((val) => isJsonValue(val));
357
+ }
358
+ return false;
359
+ }
360
+ /**
361
+ * Safely converts unknown context values to JsonValue-compliant Record
362
+ * Filters out non-JsonValue compliant values and logs warnings
363
+ */
364
+ function validateAndConvertContext(context) {
365
+ if (!context || typeof context !== "object" || Array.isArray(context)) {
366
+ logger.warn("Context must be a plain object, ignoring invalid context");
367
+ return {};
368
+ }
369
+ const validatedContext = {};
370
+ const obj = context;
371
+ for (const [key, value] of Object.entries(obj)) {
372
+ if (isJsonValue(value)) {
373
+ validatedContext[key] = value;
374
+ }
375
+ else {
376
+ logger.warn(`Context value for key "${key}" is not JsonValue compliant, excluding from context`);
377
+ }
378
+ }
379
+ return validatedContext;
380
+ }
381
+ /**
382
+ * Internal factory processing function (for caching)
383
+ */
384
+ function processFactoryOptionsInternal(options) {
385
+ const functionTag = "processFactoryOptionsInternal";
386
+ try {
387
+ const factoryConfig = options.factoryConfig;
388
+ if (!factoryConfig) {
389
+ return { hasFactoryConfig: false };
390
+ }
391
+ logger.debug(`[${functionTag}] Processing factory configuration`, {
392
+ domainType: factoryConfig.domainType,
393
+ enhancementType: factoryConfig.enhancementType,
394
+ validateDomainData: factoryConfig.validateDomainData,
395
+ });
396
+ // Extract domain configuration
397
+ const domainType = factoryConfig.domainType;
398
+ const domainConfig = factoryConfig.domainConfig;
399
+ const enhancementType = factoryConfig.enhancementType;
400
+ // Create processed context that includes domain information with validation
401
+ const processedContext = {
402
+ ...validateAndConvertContext(options.context),
403
+ };
404
+ // Add domain information to context if available
405
+ if (domainType) {
406
+ processedContext.domainType = domainType;
407
+ }
408
+ if (domainConfig) {
409
+ if (isJsonValue(domainConfig)) {
410
+ processedContext.domainConfig = domainConfig;
411
+ }
412
+ else {
413
+ logger.warn("Domain config is not JsonValue compliant, excluding from context");
414
+ }
415
+ }
416
+ if (enhancementType) {
417
+ processedContext.enhancementType = enhancementType;
418
+ }
419
+ // Add factory metadata
420
+ processedContext.factoryEnhanced = true;
421
+ processedContext.factoryProcessedAt = Date.now();
422
+ logger.debug(`[${functionTag}] Factory configuration processed successfully`, {
423
+ domainType,
424
+ enhancementType,
425
+ contextKeys: Object.keys(processedContext),
426
+ });
427
+ return {
428
+ hasFactoryConfig: true,
429
+ domainType,
430
+ domainConfig,
431
+ enhancementType,
432
+ processedContext,
433
+ };
434
+ }
435
+ catch (error) {
436
+ logger.warn(`[${functionTag}] Failed to process factory configuration`, {
437
+ error: error instanceof Error ? error.message : String(error),
438
+ });
439
+ return { hasFactoryConfig: false };
440
+ }
441
+ }
442
+ /**
443
+ * Process factory configuration from enhanced options (with caching)
444
+ * Extracts and validates factory config for provider integration
445
+ */
446
+ export function processFactoryOptions(options) {
447
+ // Try to get result from cache first
448
+ const cachedResult = factoryProcessingCache.get(options);
449
+ if (cachedResult) {
450
+ return cachedResult;
451
+ }
452
+ // Process and cache the result
453
+ const result = processFactoryOptionsInternal(options);
454
+ factoryProcessingCache.set(options, result);
455
+ return result;
456
+ }
457
+ /**
458
+ * Enhance TextGenerationOptions with factory configuration
459
+ * Converts enhanced GenerateOptions/StreamOptions to internal format
460
+ */
461
+ export function enhanceTextGenerationOptions(baseOptions, factoryResult) {
462
+ if (!factoryResult.hasFactoryConfig) {
463
+ return baseOptions;
464
+ }
465
+ // Validate and merge contexts to ensure JsonValue compliance
466
+ const validatedBaseContext = validateAndConvertContext(baseOptions.context);
467
+ const factoryProcessedContext = factoryResult.processedContext || {};
468
+ const enhanced = {
469
+ ...baseOptions,
470
+ // Merge contexts with proper validation to prevent runtime type errors
471
+ context: {
472
+ ...validatedBaseContext,
473
+ ...factoryProcessedContext,
474
+ },
475
+ // Ensure evaluation is enabled when using factory patterns
476
+ enableEvaluation: baseOptions.enableEvaluation ?? true,
477
+ // Use domain type for evaluation if available
478
+ evaluationDomain: factoryResult.domainType || baseOptions.evaluationDomain,
479
+ };
480
+ logger.debug("Enhanced TextGenerationOptions with factory configuration", {
481
+ domainType: factoryResult.domainType,
482
+ enhancementType: factoryResult.enhancementType,
483
+ hasProcessedContext: !!factoryResult.processedContext,
484
+ });
485
+ return enhanced;
486
+ }
487
+ /**
488
+ * Check if options require factory processing
489
+ * Quick check to determine if factory enhancement is needed
490
+ */
491
+ export function requiresFactoryProcessing(options) {
492
+ return !!options?.factoryConfig;
493
+ }
494
+ /**
495
+ * Extract streaming configuration for factory processing
496
+ * Handles streaming-specific factory enhancements
497
+ */
498
+ export function processStreamingFactoryOptions(options) {
499
+ const streamingConfig = options.streaming;
500
+ if (!streamingConfig) {
501
+ return { hasStreamingConfig: false };
502
+ }
503
+ logger.debug("Processing streaming factory configuration", {
504
+ enabled: streamingConfig.enabled,
505
+ chunkSize: streamingConfig.chunkSize,
506
+ enableProgress: streamingConfig.enableProgress,
507
+ });
508
+ return {
509
+ hasStreamingConfig: true,
510
+ streamingEnabled: streamingConfig.enabled,
511
+ enhancedConfig: streamingConfig,
512
+ };
513
+ }
514
+ /**
515
+ * Convert enhanced StreamOptions back to clean StreamOptions
516
+ * Strips factory configuration while preserving enhanced context
517
+ */
518
+ export function createCleanStreamOptions(enhancedOptions) {
519
+ const { factoryConfig, ...cleanOptions } = enhancedOptions;
520
+ // Return clean options without factoryConfig
521
+ return cleanOptions;
522
+ }
523
+ /**
524
+ * Validate factory configuration
525
+ * Ensures factory config is valid before processing
526
+ */
527
+ export function validateFactoryConfig(factoryConfig) {
528
+ const errors = [];
529
+ if (!factoryConfig) {
530
+ return { isValid: true, errors: [] }; // No config is valid
531
+ }
532
+ // Validate domain type if present
533
+ if (factoryConfig.domainType !== undefined) {
534
+ if (typeof factoryConfig.domainType !== "string") {
535
+ errors.push("domainType must be a string");
536
+ }
537
+ else if (factoryConfig.domainType.length === 0) {
538
+ // Empty string is allowed (will be converted to "generic")
539
+ logger.debug("Empty domainType will be converted to 'generic'");
540
+ }
541
+ }
542
+ // Validate domain config if present
543
+ if (factoryConfig.domainConfig !== undefined) {
544
+ if (typeof factoryConfig.domainConfig !== "object" ||
545
+ factoryConfig.domainConfig === null) {
546
+ errors.push("domainConfig must be an object");
547
+ }
548
+ }
549
+ // Validate enhancement type if present
550
+ if (factoryConfig.enhancementType !== undefined) {
551
+ const validTypes = [
552
+ "domain-configuration",
553
+ "streaming-optimization",
554
+ "mcp-integration",
555
+ "legacy-migration",
556
+ "context-conversion",
557
+ ];
558
+ if (!validTypes.includes(factoryConfig.enhancementType)) {
559
+ errors.push(`enhancementType must be one of: ${validTypes.join(", ")}`);
560
+ }
561
+ }
562
+ const isValid = errors.length === 0;
563
+ if (!isValid) {
564
+ logger.warn("Factory configuration validation failed", { errors });
565
+ }
566
+ return { isValid, errors };
567
+ }
568
+ /**
569
+ * Get factory processing cache statistics
570
+ * Useful for monitoring cache performance and debugging
571
+ */
572
+ export function getFactoryProcessingCacheStats() {
573
+ return factoryProcessingCache.getStats();
574
+ }
575
+ /**
576
+ * Clear factory processing cache
577
+ * Useful for testing or memory management
578
+ */
579
+ export function clearFactoryProcessingCache() {
580
+ factoryProcessingCache.clear();
581
+ }
582
+ /**
583
+ * Evict old entries from factory processing cache
584
+ * Useful for periodic cleanup
585
+ */
586
+ export function evictOldFactoryProcessingCache(maxAge) {
587
+ return factoryProcessingCache.evictOld(maxAge);
588
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Type conversion utilities between GenerateOptions and StreamOptions
3
+ *
4
+ * 🔧 FIX: Addresses Issue #2 - Type System Mismatch
5
+ * Factory patterns need to work with both generate() and stream() methods
6
+ */
7
+ import type { GenerateOptions } from "../types/generateTypes.js";
8
+ import type { StreamOptions } from "../types/streamTypes.js";
9
+ import type { UnknownRecord } from "../types/common.js";
10
+ /**
11
+ * Convert GenerateOptions to StreamOptions
12
+ * Preserves all factory configuration and enhancement data
13
+ */
14
+ export declare function convertGenerateToStreamOptions(generateOptions: GenerateOptions): StreamOptions;
15
+ /**
16
+ * Convert StreamOptions to GenerateOptions
17
+ * Useful for fallback scenarios and unified processing
18
+ */
19
+ export declare function convertStreamToGenerateOptions(streamOptions: StreamOptions): GenerateOptions;
20
+ /**
21
+ * Create a unified options interface that works with both methods
22
+ * Useful for factory utilities that need to work with either type
23
+ */
24
+ export type UnifiedOptions = GenerateOptions & StreamOptions;
25
+ /**
26
+ * Check if options object has factory configuration
27
+ * Useful for determining if enhanced processing is needed
28
+ */
29
+ export declare function hasFactoryConfig(options: GenerateOptions | StreamOptions | UnknownRecord): boolean;
30
+ /**
31
+ * Extract factory configuration from either options type
32
+ * Returns null if no factory config is present
33
+ */
34
+ export declare function extractFactoryConfig(options: GenerateOptions | StreamOptions | UnknownRecord): GenerateOptions["factoryConfig"] | null;
35
+ /**
36
+ * Check if options object has streaming configuration
37
+ * Useful for determining if streaming enhancements are needed
38
+ */
39
+ export declare function hasStreamingConfig(options: GenerateOptions | StreamOptions | UnknownRecord): boolean;
40
+ /**
41
+ * Extract streaming configuration from either options type
42
+ * Returns null if no streaming config is present
43
+ */
44
+ export declare function extractStreamingConfig(options: GenerateOptions | StreamOptions | UnknownRecord): GenerateOptions["streaming"] | null;
45
+ /**
46
+ * Create factory-enhanced StreamOptions from domain configuration
47
+ * This is the key function that addresses Issue #2
48
+ */
49
+ export declare function createFactoryAwareStreamOptions(baseOptions: Partial<StreamOptions>, factoryConfig: GenerateOptions["factoryConfig"]): StreamOptions;
50
+ /**
51
+ * Create factory-enhanced GenerateOptions from domain configuration
52
+ * Parallel function for generate() method
53
+ */
54
+ export declare function createFactoryAwareGenerateOptions(baseOptions: Partial<GenerateOptions>, factoryConfig: GenerateOptions["factoryConfig"]): GenerateOptions;