@juspay/neurolink 7.1.0 → 7.2.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 (92) hide show
  1. package/CHANGELOG.md +8 -2
  2. package/README.md +16 -11
  3. package/dist/cli/commands/config.d.ts +2 -2
  4. package/dist/cli/commands/config.js +22 -21
  5. package/dist/cli/commands/mcp.d.ts +79 -0
  6. package/dist/cli/commands/mcp.js +916 -0
  7. package/dist/cli/commands/models.d.ts +63 -0
  8. package/dist/cli/commands/models.js +653 -0
  9. package/dist/cli/commands/ollama.js +56 -55
  10. package/dist/cli/factories/commandFactory.d.ts +14 -0
  11. package/dist/cli/factories/commandFactory.js +346 -47
  12. package/dist/cli/index.js +25 -10
  13. package/dist/cli/utils/completeSetup.js +9 -8
  14. package/dist/cli/utils/envManager.js +7 -6
  15. package/dist/cli/utils/interactiveSetup.js +20 -19
  16. package/dist/core/analytics.js +25 -38
  17. package/dist/core/baseProvider.d.ts +8 -0
  18. package/dist/core/baseProvider.js +177 -68
  19. package/dist/core/constants.d.ts +11 -0
  20. package/dist/core/constants.js +17 -0
  21. package/dist/core/evaluation.js +25 -14
  22. package/dist/core/factory.js +19 -18
  23. package/dist/core/streamAnalytics.d.ts +65 -0
  24. package/dist/core/streamAnalytics.js +125 -0
  25. package/dist/lib/core/analytics.js +25 -38
  26. package/dist/lib/core/baseProvider.d.ts +8 -0
  27. package/dist/lib/core/baseProvider.js +177 -68
  28. package/dist/lib/core/constants.d.ts +11 -0
  29. package/dist/lib/core/constants.js +17 -0
  30. package/dist/lib/core/evaluation.js +25 -14
  31. package/dist/lib/core/factory.js +19 -18
  32. package/dist/lib/core/streamAnalytics.d.ts +65 -0
  33. package/dist/lib/core/streamAnalytics.js +125 -0
  34. package/dist/lib/models/modelRegistry.d.ts +132 -0
  35. package/dist/lib/models/modelRegistry.js +483 -0
  36. package/dist/lib/models/modelResolver.d.ts +115 -0
  37. package/dist/lib/models/modelResolver.js +467 -0
  38. package/dist/lib/neurolink.d.ts +4 -1
  39. package/dist/lib/neurolink.js +101 -67
  40. package/dist/lib/providers/anthropic.js +3 -0
  41. package/dist/lib/providers/googleAiStudio.js +13 -0
  42. package/dist/lib/providers/huggingFace.js +15 -3
  43. package/dist/lib/providers/mistral.js +19 -7
  44. package/dist/lib/providers/ollama.js +31 -7
  45. package/dist/lib/providers/openAI.js +12 -0
  46. package/dist/lib/sdk/toolRegistration.js +2 -2
  47. package/dist/lib/types/cli.d.ts +56 -1
  48. package/dist/lib/types/contextTypes.d.ts +110 -0
  49. package/dist/lib/types/contextTypes.js +176 -0
  50. package/dist/lib/types/index.d.ts +4 -1
  51. package/dist/lib/types/mcpTypes.d.ts +118 -7
  52. package/dist/lib/types/providers.d.ts +81 -0
  53. package/dist/lib/types/streamTypes.d.ts +44 -7
  54. package/dist/lib/types/tools.d.ts +9 -0
  55. package/dist/lib/types/universalProviderOptions.d.ts +3 -1
  56. package/dist/lib/types/universalProviderOptions.js +2 -1
  57. package/dist/lib/utils/logger.d.ts +7 -0
  58. package/dist/lib/utils/logger.js +11 -0
  59. package/dist/lib/utils/performance.d.ts +105 -0
  60. package/dist/lib/utils/performance.js +210 -0
  61. package/dist/lib/utils/retryHandler.d.ts +89 -0
  62. package/dist/lib/utils/retryHandler.js +269 -0
  63. package/dist/models/modelRegistry.d.ts +132 -0
  64. package/dist/models/modelRegistry.js +483 -0
  65. package/dist/models/modelResolver.d.ts +115 -0
  66. package/dist/models/modelResolver.js +468 -0
  67. package/dist/neurolink.d.ts +4 -1
  68. package/dist/neurolink.js +101 -67
  69. package/dist/providers/anthropic.js +3 -0
  70. package/dist/providers/googleAiStudio.js +13 -0
  71. package/dist/providers/huggingFace.js +15 -3
  72. package/dist/providers/mistral.js +19 -7
  73. package/dist/providers/ollama.js +31 -7
  74. package/dist/providers/openAI.js +12 -0
  75. package/dist/sdk/toolRegistration.js +2 -2
  76. package/dist/types/cli.d.ts +56 -1
  77. package/dist/types/contextTypes.d.ts +110 -0
  78. package/dist/types/contextTypes.js +177 -0
  79. package/dist/types/index.d.ts +4 -1
  80. package/dist/types/mcpTypes.d.ts +118 -7
  81. package/dist/types/providers.d.ts +81 -0
  82. package/dist/types/streamTypes.d.ts +44 -7
  83. package/dist/types/tools.d.ts +9 -0
  84. package/dist/types/universalProviderOptions.d.ts +3 -1
  85. package/dist/types/universalProviderOptions.js +3 -1
  86. package/dist/utils/logger.d.ts +7 -0
  87. package/dist/utils/logger.js +11 -0
  88. package/dist/utils/performance.d.ts +105 -0
  89. package/dist/utils/performance.js +210 -0
  90. package/dist/utils/retryHandler.d.ts +89 -0
  91. package/dist/utils/retryHandler.js +269 -0
  92. package/package.json +2 -1
@@ -0,0 +1,467 @@
1
+ /**
2
+ * Model Resolver for NeuroLink CLI Commands
3
+ * Provides model resolution, search, and recommendation functionality
4
+ * Part of Phase 4.1 - Models Command System
5
+ */
6
+ import { MODEL_REGISTRY, MODEL_ALIASES, USE_CASE_RECOMMENDATIONS, getAllModels, getModelById, getModelsByProvider, getAvailableProviders, calculateCost, formatModelForDisplay, } from "./modelRegistry.js";
7
+ /**
8
+ * Model resolver class with advanced search and recommendation functionality
9
+ */
10
+ export class ModelResolver {
11
+ /**
12
+ * Resolve model ID from alias or fuzzy name
13
+ */
14
+ static resolveModel(query) {
15
+ const normalizedQuery = query.toLowerCase().trim();
16
+ // Exact match first
17
+ if (MODEL_REGISTRY[query]) {
18
+ return MODEL_REGISTRY[query];
19
+ }
20
+ // Alias match
21
+ if (MODEL_ALIASES[normalizedQuery]) {
22
+ const resolvedId = MODEL_ALIASES[normalizedQuery];
23
+ return MODEL_REGISTRY[resolvedId] || null;
24
+ }
25
+ // Fuzzy matching
26
+ const allModels = getAllModels();
27
+ // Try partial matching on ID
28
+ const idMatch = allModels.find((model) => model.id.toLowerCase().includes(normalizedQuery) ||
29
+ normalizedQuery.includes(model.id.toLowerCase()));
30
+ if (idMatch) {
31
+ return idMatch;
32
+ }
33
+ // Try partial matching on name
34
+ const nameMatch = allModels.find((model) => model.name.toLowerCase().includes(normalizedQuery) ||
35
+ normalizedQuery.includes(model.name.toLowerCase()));
36
+ if (nameMatch) {
37
+ return nameMatch;
38
+ }
39
+ // Try provider-specific matching
40
+ const providerMatch = allModels.find((model) => {
41
+ const providerQuery = `${model.provider}-${normalizedQuery}`;
42
+ return (model.id.toLowerCase().includes(providerQuery) ||
43
+ model.name.toLowerCase().includes(normalizedQuery));
44
+ });
45
+ if (providerMatch) {
46
+ return providerMatch;
47
+ }
48
+ return null;
49
+ }
50
+ /**
51
+ * Search models with advanced filtering
52
+ */
53
+ static searchModels(filters) {
54
+ const allModels = getAllModels();
55
+ const results = [];
56
+ for (const model of allModels) {
57
+ const matchResult = this.evaluateModelMatch(model, filters);
58
+ if (matchResult.score > 0) {
59
+ results.push(matchResult);
60
+ }
61
+ }
62
+ // Sort by score (highest first)
63
+ return results.sort((a, b) => b.score - a.score);
64
+ }
65
+ /**
66
+ * Get best model for specific use case
67
+ */
68
+ static getBestModel(context) {
69
+ const allModels = getAllModels();
70
+ const scored = allModels.map((model) => ({
71
+ model,
72
+ score: this.scoreModelForContext(model, context),
73
+ }));
74
+ // Sort by score
75
+ scored.sort((a, b) => b.score - a.score);
76
+ const best = scored[0];
77
+ const alternatives = scored.slice(1, 4).map((s) => s.model);
78
+ return {
79
+ model: best.model,
80
+ score: best.score,
81
+ reasoning: this.generateRecommendationReasoning(best.model, context),
82
+ alternatives,
83
+ };
84
+ }
85
+ /**
86
+ * Compare multiple models
87
+ */
88
+ static compareModels(modelIds) {
89
+ const models = modelIds
90
+ .map((id) => this.resolveModel(id))
91
+ .filter((model) => model !== null);
92
+ if (models.length === 0) {
93
+ throw new Error(`No valid models found for comparison. Invalid IDs: ${modelIds.join(", ")}. Use 'models list' to see available model IDs.`);
94
+ }
95
+ // Build comparison data
96
+ const capabilities = {
97
+ vision: [],
98
+ functionCalling: [],
99
+ codeGeneration: [],
100
+ reasoning: [],
101
+ multimodal: [],
102
+ streaming: [],
103
+ jsonMode: [],
104
+ };
105
+ // Group models by capabilities
106
+ for (const model of models) {
107
+ for (const [capability, supported] of Object.entries(model.capabilities)) {
108
+ if (supported) {
109
+ capabilities[capability].push(model);
110
+ }
111
+ }
112
+ }
113
+ // Find pricing extremes
114
+ const sortedByCost = [...models].sort((a, b) => a.pricing.inputCostPer1K +
115
+ a.pricing.outputCostPer1K -
116
+ (b.pricing.inputCostPer1K + b.pricing.outputCostPer1K));
117
+ // Find context size extremes
118
+ const sortedByContext = [...models].sort((a, b) => b.limits.maxContextTokens - a.limits.maxContextTokens);
119
+ // Group by performance
120
+ const performance = {
121
+ fast: models.filter((m) => m.performance.speed === "fast"),
122
+ medium: models.filter((m) => m.performance.speed === "medium"),
123
+ slow: models.filter((m) => m.performance.speed === "slow"),
124
+ highQuality: models.filter((m) => m.performance.quality === "high"),
125
+ mediumQuality: models.filter((m) => m.performance.quality === "medium"),
126
+ lowQuality: models.filter((m) => m.performance.quality === "low"),
127
+ };
128
+ return {
129
+ models,
130
+ comparison: {
131
+ capabilities,
132
+ pricing: {
133
+ cheapest: sortedByCost[0],
134
+ mostExpensive: sortedByCost[sortedByCost.length - 1],
135
+ },
136
+ performance,
137
+ contextSize: {
138
+ largest: sortedByContext[0],
139
+ smallest: sortedByContext[sortedByContext.length - 1],
140
+ },
141
+ },
142
+ };
143
+ }
144
+ /**
145
+ * Get models by category
146
+ */
147
+ static getModelsByCategory(category) {
148
+ return getAllModels().filter((model) => model.category === category);
149
+ }
150
+ /**
151
+ * Get recommended models for use case
152
+ */
153
+ static getRecommendedModelsForUseCase(useCase) {
154
+ const recommendedIds = USE_CASE_RECOMMENDATIONS[useCase] || [];
155
+ return recommendedIds
156
+ .map((id) => getModelById(id))
157
+ .filter((model) => model !== null);
158
+ }
159
+ /**
160
+ * Calculate cost comparison for models
161
+ */
162
+ static calculateCostComparison(models, inputTokens = 1000, outputTokens = 500) {
163
+ return models
164
+ .map((model) => ({
165
+ model,
166
+ cost: calculateCost(model, inputTokens, outputTokens),
167
+ costPer1K: model.pricing.inputCostPer1K + model.pricing.outputCostPer1K,
168
+ }))
169
+ .sort((a, b) => a.cost - b.cost);
170
+ }
171
+ /**
172
+ * Get model statistics
173
+ */
174
+ static getModelStatistics() {
175
+ const allModels = getAllModels();
176
+ const providers = getAvailableProviders();
177
+ // Count by provider
178
+ const byProvider = providers.reduce((acc, provider) => {
179
+ acc[provider] = getModelsByProvider(provider).length;
180
+ return acc;
181
+ }, {});
182
+ // Count by category
183
+ const byCategory = allModels.reduce((acc, model) => {
184
+ acc[model.category] = (acc[model.category] || 0) + 1;
185
+ return acc;
186
+ }, {});
187
+ // Capability statistics
188
+ const capabilityStats = allModels.reduce((acc, model) => {
189
+ for (const [capability, supported] of Object.entries(model.capabilities)) {
190
+ if (supported) {
191
+ acc[capability] = (acc[capability] || 0) + 1;
192
+ }
193
+ }
194
+ return acc;
195
+ }, {});
196
+ // Cost statistics
197
+ const costs = allModels.map((m) => m.pricing.inputCostPer1K + m.pricing.outputCostPer1K);
198
+ const avgCost = costs.reduce((a, b) => a + b, 0) / costs.length;
199
+ const minCost = Math.min(...costs);
200
+ const maxCost = Math.max(...costs);
201
+ return {
202
+ total: allModels.length,
203
+ providers: Object.keys(byProvider).length,
204
+ byProvider,
205
+ byCategory,
206
+ capabilities: capabilityStats,
207
+ pricing: {
208
+ average: avgCost,
209
+ min: minCost,
210
+ max: maxCost,
211
+ free: allModels.filter((m) => m.pricing.inputCostPer1K === 0).length,
212
+ },
213
+ deprecated: allModels.filter((m) => m.deprecated).length,
214
+ };
215
+ }
216
+ /**
217
+ * Evaluate how well a model matches search filters
218
+ */
219
+ static evaluateModelMatch(model, filters) {
220
+ let score = 0;
221
+ const matchReasons = [];
222
+ // Provider filter
223
+ if (filters.provider) {
224
+ const providers = Array.isArray(filters.provider)
225
+ ? filters.provider
226
+ : [filters.provider];
227
+ if (providers.includes(model.provider)) {
228
+ score += 10;
229
+ matchReasons.push(`Provider: ${model.provider}`);
230
+ }
231
+ else {
232
+ return { model, score: 0, matchReasons: [] };
233
+ }
234
+ }
235
+ // Capability filter
236
+ if (filters.capability) {
237
+ const capabilities = Array.isArray(filters.capability)
238
+ ? filters.capability
239
+ : [filters.capability];
240
+ for (const capability of capabilities) {
241
+ if (model.capabilities[capability]) {
242
+ score += 15;
243
+ matchReasons.push(`Has capability: ${capability}`);
244
+ }
245
+ }
246
+ }
247
+ // Use case filter
248
+ if (filters.useCase) {
249
+ const useCaseScore = model.useCases[filters.useCase];
250
+ if (useCaseScore >= 7) {
251
+ score += useCaseScore * 2;
252
+ matchReasons.push(`Good for ${filters.useCase} (${useCaseScore}/10)`);
253
+ }
254
+ }
255
+ // Cost filter
256
+ if (filters.maxCost) {
257
+ const totalCost = model.pricing.inputCostPer1K + model.pricing.outputCostPer1K;
258
+ if (totalCost <= filters.maxCost) {
259
+ score += 5;
260
+ matchReasons.push(`Within cost limit ($${totalCost.toFixed(6)}/1K)`);
261
+ }
262
+ else {
263
+ score -= 5;
264
+ }
265
+ }
266
+ // Context size filters
267
+ if (filters.minContextSize &&
268
+ model.limits.maxContextTokens >= filters.minContextSize) {
269
+ score += 5;
270
+ matchReasons.push(`Meets min context: ${model.limits.maxContextTokens}`);
271
+ }
272
+ if (filters.maxContextSize &&
273
+ model.limits.maxContextTokens <= filters.maxContextSize) {
274
+ score += 3;
275
+ matchReasons.push(`Within max context: ${model.limits.maxContextTokens}`);
276
+ }
277
+ // Performance filters
278
+ if (filters.performance) {
279
+ if (model.performance.speed === filters.performance ||
280
+ model.performance.quality === filters.performance) {
281
+ score += 8;
282
+ matchReasons.push(`Performance: ${filters.performance}`);
283
+ }
284
+ }
285
+ // Category filter
286
+ if (filters.category) {
287
+ const categories = Array.isArray(filters.category)
288
+ ? filters.category
289
+ : [filters.category];
290
+ if (categories.includes(model.category)) {
291
+ score += 7;
292
+ matchReasons.push(`Category: ${model.category}`);
293
+ }
294
+ }
295
+ // Base relevance score
296
+ if (score === 0) {
297
+ score = 1; // Minimal relevance for any model
298
+ matchReasons.push("Basic match");
299
+ }
300
+ return { model, score, matchReasons };
301
+ }
302
+ /**
303
+ * Score model for recommendation context
304
+ */
305
+ static scoreModelForContext(model, context) {
306
+ let score = 0;
307
+ // Use case scoring
308
+ if (context.useCase) {
309
+ score += model.useCases[context.useCase] * 10;
310
+ }
311
+ // Cost scoring
312
+ if (context.maxCost) {
313
+ const totalCost = model.pricing.inputCostPer1K + model.pricing.outputCostPer1K;
314
+ if (totalCost <= context.maxCost) {
315
+ score += 20;
316
+ }
317
+ else {
318
+ score -= 30; // Heavy penalty for exceeding cost
319
+ }
320
+ }
321
+ // Quality scoring
322
+ if (context.minQuality) {
323
+ const qualityScore = context.minQuality === "high"
324
+ ? 3
325
+ : context.minQuality === "medium"
326
+ ? 2
327
+ : 1;
328
+ const modelQuality = model.performance.quality === "high"
329
+ ? 3
330
+ : model.performance.quality === "medium"
331
+ ? 2
332
+ : 1;
333
+ if (modelQuality >= qualityScore) {
334
+ score += 15;
335
+ }
336
+ else {
337
+ score -= 10;
338
+ }
339
+ }
340
+ // Required capabilities
341
+ if (context.requireCapabilities) {
342
+ for (const capability of context.requireCapabilities) {
343
+ if (model.capabilities[capability]) {
344
+ score += 12;
345
+ }
346
+ else {
347
+ score -= 25; // Heavy penalty for missing required capability
348
+ }
349
+ }
350
+ }
351
+ // Provider exclusions
352
+ if (context.excludeProviders?.includes(model.provider)) {
353
+ score -= 50;
354
+ }
355
+ // Context size requirements
356
+ if (context.contextSize &&
357
+ model.limits.maxContextTokens >= context.contextSize) {
358
+ score += 10;
359
+ }
360
+ // Local preference
361
+ if (context.preferLocal && model.isLocal) {
362
+ score += 15;
363
+ }
364
+ // Deprecated models penalty
365
+ if (model.deprecated) {
366
+ score -= 20;
367
+ }
368
+ return Math.max(0, score); // Ensure non-negative score
369
+ }
370
+ /**
371
+ * Generate recommendation reasoning
372
+ */
373
+ static generateRecommendationReasoning(model, context) {
374
+ const reasons = [];
375
+ if (context.useCase) {
376
+ const score = model.useCases[context.useCase];
377
+ reasons.push(`Excellent for ${context.useCase} (${score}/10 rating)`);
378
+ }
379
+ if (model.pricing.inputCostPer1K === 0) {
380
+ reasons.push("Free to use (local execution)");
381
+ }
382
+ else {
383
+ const costPer1K = model.pricing.inputCostPer1K + model.pricing.outputCostPer1K;
384
+ if (costPer1K < 0.001) {
385
+ reasons.push("Very cost-effective");
386
+ }
387
+ }
388
+ if (model.performance.quality === "high") {
389
+ reasons.push("High-quality outputs");
390
+ }
391
+ if (model.performance.speed === "fast") {
392
+ reasons.push("Fast response times");
393
+ }
394
+ if (model.limits.maxContextTokens > 100000) {
395
+ reasons.push("Large context window for complex tasks");
396
+ }
397
+ const strongCapabilities = Object.entries(model.capabilities)
398
+ .filter(([_, supported]) => supported)
399
+ .map(([capability]) => capability);
400
+ if (strongCapabilities.length > 0) {
401
+ reasons.push(`Supports: ${strongCapabilities.join(", ")}`);
402
+ }
403
+ if (model.releaseDate) {
404
+ const releaseYear = new Date(model.releaseDate).getFullYear();
405
+ if (releaseYear >= 2024) {
406
+ reasons.push("Recent model with latest capabilities");
407
+ }
408
+ }
409
+ return reasons;
410
+ }
411
+ }
412
+ /**
413
+ * Utility functions for CLI integration
414
+ */
415
+ /**
416
+ * Format search results for CLI display
417
+ */
418
+ export function formatSearchResults(results) {
419
+ return results.map((result) => {
420
+ const modelDisplay = formatModelForDisplay(result.model);
421
+ return {
422
+ ...(typeof modelDisplay === "object" && modelDisplay !== null
423
+ ? modelDisplay
424
+ : {}),
425
+ relevanceScore: result.score,
426
+ matchReasons: result.matchReasons,
427
+ };
428
+ });
429
+ }
430
+ /**
431
+ * Format recommendation for CLI display
432
+ */
433
+ export function formatRecommendation(recommendation) {
434
+ return {
435
+ recommended: formatModelForDisplay(recommendation.model),
436
+ score: recommendation.score,
437
+ reasoning: recommendation.reasoning,
438
+ alternatives: recommendation.alternatives.map(formatModelForDisplay),
439
+ };
440
+ }
441
+ /**
442
+ * Format model comparison for CLI display
443
+ */
444
+ export function formatComparison(comparison) {
445
+ return {
446
+ models: comparison.models.map(formatModelForDisplay),
447
+ summary: {
448
+ capabilities: Object.entries(comparison.comparison.capabilities).map(([capability, models]) => ({
449
+ capability,
450
+ supportedBy: models.map((m) => m.id),
451
+ count: models.length,
452
+ })),
453
+ pricing: {
454
+ cheapest: comparison.comparison.pricing.cheapest.id,
455
+ mostExpensive: comparison.comparison.pricing.mostExpensive.id,
456
+ },
457
+ contextSize: {
458
+ largest: comparison.comparison.contextSize.largest.id,
459
+ smallest: comparison.comparison.contextSize.smallest.id,
460
+ },
461
+ performance: Object.entries(comparison.comparison.performance).map(([type, models]) => ({
462
+ type,
463
+ models: models.map((m) => m.id),
464
+ })),
465
+ },
466
+ };
467
+ }
@@ -29,6 +29,7 @@ export interface MCPStatus {
29
29
  customToolsCount: number;
30
30
  inMemoryServersCount: number;
31
31
  error?: string;
32
+ [key: string]: unknown;
32
33
  }
33
34
  export interface MCPServerInfo {
34
35
  id: string;
@@ -143,7 +144,9 @@ export declare class NeuroLink {
143
144
  * Get comprehensive status of all AI providers
144
145
  * Primary method for provider health checking and diagnostics
145
146
  */
146
- getProviderStatus(): Promise<ProviderStatus[]>;
147
+ getProviderStatus(options?: {
148
+ quiet?: boolean;
149
+ }): Promise<ProviderStatus[]>;
147
150
  /**
148
151
  * Test a specific AI provider's connectivity and authentication
149
152
  * @param providerName - Name of the provider to test