@juspay/neurolink 9.41.0 → 9.42.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.
- package/CHANGELOG.md +8 -0
- package/README.md +7 -1
- package/dist/auth/anthropicOAuth.d.ts +18 -3
- package/dist/auth/anthropicOAuth.js +149 -4
- package/dist/auth/providers/firebase.js +5 -1
- package/dist/auth/providers/jwt.js +5 -1
- package/dist/auth/providers/workos.js +5 -1
- package/dist/auth/sessionManager.d.ts +1 -1
- package/dist/auth/sessionManager.js +58 -27
- package/dist/browser/neurolink.min.js +354 -334
- package/dist/cli/commands/mcp.d.ts +6 -0
- package/dist/cli/commands/mcp.js +188 -181
- package/dist/cli/commands/proxy.d.ts +2 -1
- package/dist/cli/commands/proxy.js +713 -431
- package/dist/cli/commands/task.js +3 -0
- package/dist/cli/factories/commandFactory.d.ts +2 -0
- package/dist/cli/factories/commandFactory.js +38 -0
- package/dist/cli/parser.js +4 -3
- package/dist/client/aiSdkAdapter.js +3 -0
- package/dist/client/streamingClient.js +30 -10
- package/dist/core/baseProvider.d.ts +6 -1
- package/dist/core/baseProvider.js +208 -230
- package/dist/core/factory.d.ts +3 -0
- package/dist/core/factory.js +138 -188
- package/dist/core/modules/GenerationHandler.js +3 -2
- package/dist/core/redisConversationMemoryManager.js +7 -3
- package/dist/evaluation/BatchEvaluator.js +4 -1
- package/dist/evaluation/hooks/observabilityHooks.js +5 -3
- package/dist/evaluation/pipeline/evaluationPipeline.d.ts +3 -2
- package/dist/evaluation/pipeline/evaluationPipeline.js +24 -9
- package/dist/evaluation/pipeline/strategies/batchStrategy.js +6 -3
- package/dist/evaluation/pipeline/strategies/samplingStrategy.js +18 -10
- package/dist/evaluation/scorers/scorerRegistry.d.ts +3 -0
- package/dist/evaluation/scorers/scorerRegistry.js +353 -282
- package/dist/lib/auth/anthropicOAuth.d.ts +18 -3
- package/dist/lib/auth/anthropicOAuth.js +149 -4
- package/dist/lib/auth/providers/firebase.js +5 -1
- package/dist/lib/auth/providers/jwt.js +5 -1
- package/dist/lib/auth/providers/workos.js +5 -1
- package/dist/lib/auth/sessionManager.d.ts +1 -1
- package/dist/lib/auth/sessionManager.js +58 -27
- package/dist/lib/client/aiSdkAdapter.js +3 -0
- package/dist/lib/client/streamingClient.js +30 -10
- package/dist/lib/core/baseProvider.d.ts +6 -1
- package/dist/lib/core/baseProvider.js +208 -230
- package/dist/lib/core/factory.d.ts +3 -0
- package/dist/lib/core/factory.js +138 -188
- package/dist/lib/core/modules/GenerationHandler.js +3 -2
- package/dist/lib/core/redisConversationMemoryManager.js +7 -3
- package/dist/lib/evaluation/BatchEvaluator.js +4 -1
- package/dist/lib/evaluation/hooks/observabilityHooks.js +5 -3
- package/dist/lib/evaluation/pipeline/evaluationPipeline.d.ts +3 -2
- package/dist/lib/evaluation/pipeline/evaluationPipeline.js +24 -9
- package/dist/lib/evaluation/pipeline/strategies/batchStrategy.js +6 -3
- package/dist/lib/evaluation/pipeline/strategies/samplingStrategy.js +18 -10
- package/dist/lib/evaluation/scorers/scorerRegistry.d.ts +3 -0
- package/dist/lib/evaluation/scorers/scorerRegistry.js +353 -282
- package/dist/lib/mcp/toolRegistry.d.ts +2 -0
- package/dist/lib/mcp/toolRegistry.js +32 -31
- package/dist/lib/neurolink.d.ts +41 -2
- package/dist/lib/neurolink.js +1616 -1681
- package/dist/lib/observability/otelBridge.d.ts +2 -2
- package/dist/lib/observability/otelBridge.js +12 -3
- package/dist/lib/providers/amazonBedrock.js +2 -4
- package/dist/lib/providers/anthropic.d.ts +9 -5
- package/dist/lib/providers/anthropic.js +19 -14
- package/dist/lib/providers/anthropicBaseProvider.d.ts +3 -3
- package/dist/lib/providers/anthropicBaseProvider.js +5 -4
- package/dist/lib/providers/azureOpenai.d.ts +1 -1
- package/dist/lib/providers/azureOpenai.js +5 -4
- package/dist/lib/providers/googleAiStudio.js +30 -6
- package/dist/lib/providers/googleVertex.d.ts +10 -0
- package/dist/lib/providers/googleVertex.js +437 -423
- package/dist/lib/providers/huggingFace.d.ts +3 -3
- package/dist/lib/providers/huggingFace.js +6 -8
- package/dist/lib/providers/litellm.d.ts +1 -0
- package/dist/lib/providers/litellm.js +76 -55
- package/dist/lib/providers/mistral.js +2 -1
- package/dist/lib/providers/ollama.js +93 -23
- package/dist/lib/providers/openAI.d.ts +2 -0
- package/dist/lib/providers/openAI.js +141 -141
- package/dist/lib/providers/openRouter.js +2 -1
- package/dist/lib/providers/openaiCompatible.d.ts +4 -4
- package/dist/lib/providers/openaiCompatible.js +4 -4
- package/dist/lib/proxy/claudeFormat.d.ts +3 -2
- package/dist/lib/proxy/claudeFormat.js +27 -14
- package/dist/lib/proxy/cloaking/plugins/sessionIdentity.d.ts +2 -6
- package/dist/lib/proxy/cloaking/plugins/sessionIdentity.js +9 -33
- package/dist/lib/proxy/modelRouter.js +3 -0
- package/dist/lib/proxy/oauthFetch.d.ts +1 -1
- package/dist/lib/proxy/oauthFetch.js +289 -316
- package/dist/lib/proxy/proxyConfig.js +46 -24
- package/dist/lib/proxy/proxyEnv.d.ts +19 -0
- package/dist/lib/proxy/proxyEnv.js +73 -0
- package/dist/lib/proxy/proxyFetch.js +291 -217
- package/dist/lib/proxy/proxyTracer.d.ts +133 -0
- package/dist/lib/proxy/proxyTracer.js +645 -0
- package/dist/lib/proxy/rawStreamCapture.d.ts +10 -0
- package/dist/lib/proxy/rawStreamCapture.js +83 -0
- package/dist/lib/proxy/requestLogger.d.ts +32 -5
- package/dist/lib/proxy/requestLogger.js +503 -47
- package/dist/lib/proxy/sseInterceptor.d.ts +97 -0
- package/dist/lib/proxy/sseInterceptor.js +427 -0
- package/dist/lib/proxy/usageStats.d.ts +4 -3
- package/dist/lib/proxy/usageStats.js +25 -12
- package/dist/lib/rag/chunkers/MarkdownChunker.js +13 -5
- package/dist/lib/rag/chunking/markdownChunker.js +15 -6
- package/dist/lib/server/routes/claudeProxyRoutes.d.ts +17 -3
- package/dist/lib/server/routes/claudeProxyRoutes.js +3032 -1349
- package/dist/lib/services/server/ai/observability/instrumentation.d.ts +7 -1
- package/dist/lib/services/server/ai/observability/instrumentation.js +337 -161
- package/dist/lib/tasks/backends/bullmqBackend.d.ts +1 -0
- package/dist/lib/tasks/backends/bullmqBackend.js +35 -22
- package/dist/lib/tasks/store/redisTaskStore.d.ts +1 -0
- package/dist/lib/tasks/store/redisTaskStore.js +54 -39
- package/dist/lib/tasks/taskManager.d.ts +5 -0
- package/dist/lib/tasks/taskManager.js +158 -30
- package/dist/lib/telemetry/index.d.ts +2 -1
- package/dist/lib/telemetry/index.js +2 -1
- package/dist/lib/telemetry/telemetryService.d.ts +3 -0
- package/dist/lib/telemetry/telemetryService.js +69 -5
- package/dist/lib/types/cli.d.ts +10 -0
- package/dist/lib/types/proxyTypes.d.ts +160 -5
- package/dist/lib/types/streamTypes.d.ts +25 -3
- package/dist/lib/utils/messageBuilder.js +3 -2
- package/dist/lib/utils/providerHealth.d.ts +19 -0
- package/dist/lib/utils/providerHealth.js +279 -33
- package/dist/lib/utils/providerUtils.js +17 -22
- package/dist/lib/utils/toolChoice.d.ts +4 -0
- package/dist/lib/utils/toolChoice.js +7 -0
- package/dist/mcp/toolRegistry.d.ts +2 -0
- package/dist/mcp/toolRegistry.js +32 -31
- package/dist/neurolink.d.ts +41 -2
- package/dist/neurolink.js +1616 -1681
- package/dist/observability/otelBridge.d.ts +2 -2
- package/dist/observability/otelBridge.js +12 -3
- package/dist/providers/amazonBedrock.js +2 -4
- package/dist/providers/anthropic.d.ts +9 -5
- package/dist/providers/anthropic.js +19 -14
- package/dist/providers/anthropicBaseProvider.d.ts +3 -3
- package/dist/providers/anthropicBaseProvider.js +5 -4
- package/dist/providers/azureOpenai.d.ts +1 -1
- package/dist/providers/azureOpenai.js +5 -4
- package/dist/providers/googleAiStudio.js +30 -6
- package/dist/providers/googleVertex.d.ts +10 -0
- package/dist/providers/googleVertex.js +437 -423
- package/dist/providers/huggingFace.d.ts +3 -3
- package/dist/providers/huggingFace.js +6 -7
- package/dist/providers/litellm.d.ts +1 -0
- package/dist/providers/litellm.js +76 -55
- package/dist/providers/mistral.js +2 -1
- package/dist/providers/ollama.js +93 -23
- package/dist/providers/openAI.d.ts +2 -0
- package/dist/providers/openAI.js +141 -141
- package/dist/providers/openRouter.js +2 -1
- package/dist/providers/openaiCompatible.d.ts +4 -4
- package/dist/providers/openaiCompatible.js +4 -3
- package/dist/proxy/claudeFormat.d.ts +3 -2
- package/dist/proxy/claudeFormat.js +27 -14
- package/dist/proxy/cloaking/plugins/sessionIdentity.d.ts +2 -6
- package/dist/proxy/cloaking/plugins/sessionIdentity.js +9 -33
- package/dist/proxy/modelRouter.js +3 -0
- package/dist/proxy/oauthFetch.d.ts +1 -1
- package/dist/proxy/oauthFetch.js +289 -316
- package/dist/proxy/proxyConfig.js +46 -24
- package/dist/proxy/proxyEnv.d.ts +19 -0
- package/dist/proxy/proxyEnv.js +72 -0
- package/dist/proxy/proxyFetch.js +291 -217
- package/dist/proxy/proxyTracer.d.ts +133 -0
- package/dist/proxy/proxyTracer.js +644 -0
- package/dist/proxy/rawStreamCapture.d.ts +10 -0
- package/dist/proxy/rawStreamCapture.js +82 -0
- package/dist/proxy/requestLogger.d.ts +32 -5
- package/dist/proxy/requestLogger.js +503 -47
- package/dist/proxy/sseInterceptor.d.ts +97 -0
- package/dist/proxy/sseInterceptor.js +426 -0
- package/dist/proxy/usageStats.d.ts +4 -3
- package/dist/proxy/usageStats.js +25 -12
- package/dist/rag/chunkers/MarkdownChunker.js +13 -5
- package/dist/rag/chunking/markdownChunker.js +15 -6
- package/dist/server/routes/claudeProxyRoutes.d.ts +17 -3
- package/dist/server/routes/claudeProxyRoutes.js +3032 -1349
- package/dist/services/server/ai/observability/instrumentation.d.ts +7 -1
- package/dist/services/server/ai/observability/instrumentation.js +337 -161
- package/dist/tasks/backends/bullmqBackend.d.ts +1 -0
- package/dist/tasks/backends/bullmqBackend.js +35 -22
- package/dist/tasks/store/redisTaskStore.d.ts +1 -0
- package/dist/tasks/store/redisTaskStore.js +54 -39
- package/dist/tasks/taskManager.d.ts +5 -0
- package/dist/tasks/taskManager.js +158 -30
- package/dist/telemetry/index.d.ts +2 -1
- package/dist/telemetry/index.js +2 -1
- package/dist/telemetry/telemetryService.d.ts +3 -0
- package/dist/telemetry/telemetryService.js +69 -5
- package/dist/types/cli.d.ts +10 -0
- package/dist/types/proxyTypes.d.ts +160 -5
- package/dist/types/streamTypes.d.ts +25 -3
- package/dist/utils/messageBuilder.js +3 -2
- package/dist/utils/providerHealth.d.ts +19 -0
- package/dist/utils/providerHealth.js +279 -33
- package/dist/utils/providerUtils.js +18 -22
- package/dist/utils/toolChoice.d.ts +4 -0
- package/dist/utils/toolChoice.js +6 -0
- package/docs/assets/dashboards/neurolink-proxy-observability-dashboard.json +6609 -0
- package/docs/changelog.md +252 -0
- package/package.json +19 -2
- package/scripts/observability/check-proxy-telemetry.mjs +235 -0
- package/scripts/observability/docker-compose.proxy-observability.yaml +55 -0
- package/scripts/observability/import-openobserve-dashboard.mjs +240 -0
- package/scripts/observability/manage-local-openobserve.sh +215 -0
- package/scripts/observability/otel-collector.proxy-observability.yaml +78 -0
- package/scripts/observability/proxy-observability.env.example +23 -0
|
@@ -72,7 +72,7 @@ export class ProviderHealthChecker {
|
|
|
72
72
|
};
|
|
73
73
|
try {
|
|
74
74
|
// 1. Check environment configuration
|
|
75
|
-
await this.checkEnvironmentConfiguration(providerName, healthStatus);
|
|
75
|
+
await this.checkEnvironmentConfiguration(providerName, healthStatus, timeout);
|
|
76
76
|
// 2. Check API key validity (basic format validation)
|
|
77
77
|
await this.checkApiKeyValidity(providerName, healthStatus);
|
|
78
78
|
// 3. Optional: Connectivity test
|
|
@@ -129,7 +129,7 @@ export class ProviderHealthChecker {
|
|
|
129
129
|
/**
|
|
130
130
|
* Check environment configuration for a provider
|
|
131
131
|
*/
|
|
132
|
-
static async checkEnvironmentConfiguration(providerName, healthStatus) {
|
|
132
|
+
static async checkEnvironmentConfiguration(providerName, healthStatus, timeout) {
|
|
133
133
|
const requiredEnvVars = this.getRequiredEnvironmentVariables(providerName);
|
|
134
134
|
logger.debug(`[ProviderHealthChecker] Checking environment configuration for ${providerName}`, {
|
|
135
135
|
requiredEnvVars,
|
|
@@ -160,7 +160,7 @@ export class ProviderHealthChecker {
|
|
|
160
160
|
healthStatus.recommendations.push(`Set the following environment variables: ${missingVars.join(", ")}`);
|
|
161
161
|
}
|
|
162
162
|
// Provider-specific configuration checks
|
|
163
|
-
await this.checkProviderSpecificConfig(providerName, healthStatus);
|
|
163
|
+
await this.checkProviderSpecificConfig(providerName, healthStatus, timeout);
|
|
164
164
|
}
|
|
165
165
|
/**
|
|
166
166
|
* Check API key validity (format validation)
|
|
@@ -228,7 +228,8 @@ export class ProviderHealthChecker {
|
|
|
228
228
|
}
|
|
229
229
|
// Providers that don't use API keys directly
|
|
230
230
|
if (providerName === AIProviderName.OLLAMA ||
|
|
231
|
-
providerName === AIProviderName.BEDROCK
|
|
231
|
+
providerName === AIProviderName.BEDROCK ||
|
|
232
|
+
providerName === AIProviderName.LITELLM) {
|
|
232
233
|
healthStatus.hasApiKey = true;
|
|
233
234
|
return;
|
|
234
235
|
}
|
|
@@ -260,30 +261,34 @@ export class ProviderHealthChecker {
|
|
|
260
261
|
healthStatus.warning = "No connectivity test available for this provider";
|
|
261
262
|
return;
|
|
262
263
|
}
|
|
264
|
+
const headers = {
|
|
265
|
+
"User-Agent": "NeuroLink-HealthCheck/1.0",
|
|
266
|
+
...this.getConnectivityHeaders(providerName),
|
|
267
|
+
};
|
|
263
268
|
try {
|
|
264
269
|
const controller = new AbortController();
|
|
265
270
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
headers: {
|
|
271
|
-
"User-Agent": "NeuroLink-HealthCheck/1.0",
|
|
272
|
-
},
|
|
273
|
-
});
|
|
274
|
-
// Fallback to GET if HEAD returns 405 (Method Not Allowed) for restrictive gateways
|
|
275
|
-
if (response.status === 405) {
|
|
276
|
-
response = await proxyFetch(endpoint, {
|
|
277
|
-
method: "GET",
|
|
271
|
+
try {
|
|
272
|
+
const proxyFetch = createProxyFetch();
|
|
273
|
+
let response = await proxyFetch(endpoint, {
|
|
274
|
+
method: "HEAD",
|
|
278
275
|
signal: controller.signal,
|
|
279
|
-
headers
|
|
280
|
-
"User-Agent": "NeuroLink-HealthCheck/1.0",
|
|
281
|
-
},
|
|
276
|
+
headers,
|
|
282
277
|
});
|
|
278
|
+
// Fallback to GET if HEAD returns 405 (Method Not Allowed) for restrictive gateways
|
|
279
|
+
if (response.status === 405) {
|
|
280
|
+
response = await proxyFetch(endpoint, {
|
|
281
|
+
method: "GET",
|
|
282
|
+
signal: controller.signal,
|
|
283
|
+
headers,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
if (!response.ok) {
|
|
287
|
+
healthStatus.configurationIssues.push(`Connectivity test failed: HTTP ${response.status}`);
|
|
288
|
+
}
|
|
283
289
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
healthStatus.configurationIssues.push(`Connectivity test failed: HTTP ${response.status}`);
|
|
290
|
+
finally {
|
|
291
|
+
clearTimeout(timeoutId);
|
|
287
292
|
}
|
|
288
293
|
}
|
|
289
294
|
catch (error) {
|
|
@@ -319,6 +324,14 @@ export class ProviderHealthChecker {
|
|
|
319
324
|
}
|
|
320
325
|
}
|
|
321
326
|
}
|
|
327
|
+
static getConnectivityHeaders(providerName) {
|
|
328
|
+
if (providerName === AIProviderName.LITELLM) {
|
|
329
|
+
return {
|
|
330
|
+
Authorization: `Bearer ${process.env.LITELLM_API_KEY || "sk-anything"}`,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
return {};
|
|
334
|
+
}
|
|
322
335
|
/**
|
|
323
336
|
* Check model availability (if possible without making API calls)
|
|
324
337
|
*/
|
|
@@ -368,6 +381,8 @@ export class ProviderHealthChecker {
|
|
|
368
381
|
return [];
|
|
369
382
|
case AIProviderName.AZURE:
|
|
370
383
|
return ["AZURE_OPENAI_API_KEY", "AZURE_OPENAI_ENDPOINT"];
|
|
384
|
+
case AIProviderName.LITELLM:
|
|
385
|
+
return [];
|
|
371
386
|
case AIProviderName.OLLAMA:
|
|
372
387
|
return []; // Ollama typically doesn't require API keys
|
|
373
388
|
default:
|
|
@@ -391,8 +406,10 @@ export class ProviderHealthChecker {
|
|
|
391
406
|
return "AWS_ACCESS_KEY_ID";
|
|
392
407
|
case AIProviderName.AZURE:
|
|
393
408
|
return "AZURE_OPENAI_API_KEY";
|
|
409
|
+
case AIProviderName.LITELLM:
|
|
410
|
+
return "LITELLM_API_KEY";
|
|
394
411
|
case AIProviderName.OLLAMA:
|
|
395
|
-
return "
|
|
412
|
+
return "OLLAMA_BASE_URL";
|
|
396
413
|
default:
|
|
397
414
|
return "";
|
|
398
415
|
}
|
|
@@ -416,6 +433,8 @@ export class ProviderHealthChecker {
|
|
|
416
433
|
return apiKey.length >= API_KEY_LENGTHS.AWS_ACCESS_KEY; // AWS access key length
|
|
417
434
|
case AIProviderName.AZURE:
|
|
418
435
|
return apiKey.length >= API_KEY_LENGTHS.AZURE_MIN; // Azure OpenAI API key length
|
|
436
|
+
case AIProviderName.LITELLM:
|
|
437
|
+
return apiKey.length > 0;
|
|
419
438
|
case AIProviderName.OLLAMA:
|
|
420
439
|
return true; // Ollama usually doesn't require specific format
|
|
421
440
|
default:
|
|
@@ -437,8 +456,10 @@ export class ProviderHealthChecker {
|
|
|
437
456
|
return null; // Complex authentication required
|
|
438
457
|
case AIProviderName.BEDROCK:
|
|
439
458
|
return null; // AWS endpoints vary by region
|
|
459
|
+
case AIProviderName.LITELLM:
|
|
460
|
+
return this.getLiteLLMModelsUrl();
|
|
440
461
|
case AIProviderName.OLLAMA:
|
|
441
|
-
return
|
|
462
|
+
return this.getOllamaTagsUrl();
|
|
442
463
|
default:
|
|
443
464
|
return null;
|
|
444
465
|
}
|
|
@@ -446,7 +467,7 @@ export class ProviderHealthChecker {
|
|
|
446
467
|
/**
|
|
447
468
|
* Provider-specific configuration checks
|
|
448
469
|
*/
|
|
449
|
-
static async checkProviderSpecificConfig(providerName, healthStatus) {
|
|
470
|
+
static async checkProviderSpecificConfig(providerName, healthStatus, timeout) {
|
|
450
471
|
switch (providerName) {
|
|
451
472
|
case AIProviderName.VERTEX:
|
|
452
473
|
await this.checkVertexAIConfig(healthStatus);
|
|
@@ -457,8 +478,11 @@ export class ProviderHealthChecker {
|
|
|
457
478
|
case AIProviderName.AZURE:
|
|
458
479
|
await this.checkAzureConfig(healthStatus);
|
|
459
480
|
break;
|
|
481
|
+
case AIProviderName.LITELLM:
|
|
482
|
+
await this.checkLiteLLMConfig(healthStatus, timeout);
|
|
483
|
+
break;
|
|
460
484
|
case AIProviderName.OLLAMA:
|
|
461
|
-
await this.checkOllamaConfig(healthStatus);
|
|
485
|
+
await this.checkOllamaConfig(healthStatus, timeout);
|
|
462
486
|
break;
|
|
463
487
|
}
|
|
464
488
|
}
|
|
@@ -648,15 +672,180 @@ export class ProviderHealthChecker {
|
|
|
648
672
|
healthStatus.recommendations.push("Set one of: AZURE_OPENAI_MODEL, AZURE_OPENAI_DEPLOYMENT, or AZURE_OPENAI_DEPLOYMENT_ID");
|
|
649
673
|
}
|
|
650
674
|
}
|
|
675
|
+
static getLiteLLMBaseUrl() {
|
|
676
|
+
return process.env.LITELLM_BASE_URL || "http://localhost:4000";
|
|
677
|
+
}
|
|
678
|
+
static getLiteLLMModelsUrl() {
|
|
679
|
+
return new URL("/v1/models", this.getLiteLLMBaseUrl()).toString();
|
|
680
|
+
}
|
|
681
|
+
static getConfiguredLiteLLMModel() {
|
|
682
|
+
return process.env.LITELLM_MODEL || "openai/gpt-4o-mini";
|
|
683
|
+
}
|
|
684
|
+
static getOllamaBaseUrl() {
|
|
685
|
+
return (process.env.OLLAMA_BASE_URL ||
|
|
686
|
+
process.env.OLLAMA_API_BASE ||
|
|
687
|
+
"http://localhost:11434");
|
|
688
|
+
}
|
|
689
|
+
static getOllamaTagsUrl() {
|
|
690
|
+
return new URL("/api/tags", this.getOllamaBaseUrl()).toString();
|
|
691
|
+
}
|
|
692
|
+
static getConfiguredOllamaModel() {
|
|
693
|
+
return process.env.OLLAMA_MODEL || "llama3.1:8b";
|
|
694
|
+
}
|
|
695
|
+
static async fetchJsonWithTimeout(url, options = {}) {
|
|
696
|
+
const controller = new AbortController();
|
|
697
|
+
const timeoutId = setTimeout(() => controller.abort(), options.timeout ?? this.DEFAULT_TIMEOUT);
|
|
698
|
+
try {
|
|
699
|
+
const proxyFetch = createProxyFetch();
|
|
700
|
+
const response = await proxyFetch(url, {
|
|
701
|
+
method: "GET",
|
|
702
|
+
headers: options.headers,
|
|
703
|
+
signal: controller.signal,
|
|
704
|
+
});
|
|
705
|
+
if (!response.ok) {
|
|
706
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
707
|
+
}
|
|
708
|
+
return await response.json();
|
|
709
|
+
}
|
|
710
|
+
finally {
|
|
711
|
+
clearTimeout(timeoutId);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
static normalizeModelList(models) {
|
|
715
|
+
return models
|
|
716
|
+
.map((entry) => {
|
|
717
|
+
if (typeof entry === "string") {
|
|
718
|
+
return entry;
|
|
719
|
+
}
|
|
720
|
+
if (entry &&
|
|
721
|
+
typeof entry === "object" &&
|
|
722
|
+
"id" in entry &&
|
|
723
|
+
typeof entry.id === "string") {
|
|
724
|
+
return entry.id;
|
|
725
|
+
}
|
|
726
|
+
if (entry &&
|
|
727
|
+
typeof entry === "object" &&
|
|
728
|
+
"name" in entry &&
|
|
729
|
+
typeof entry.name === "string") {
|
|
730
|
+
return entry.name;
|
|
731
|
+
}
|
|
732
|
+
return null;
|
|
733
|
+
})
|
|
734
|
+
.filter((model) => typeof model === "string");
|
|
735
|
+
}
|
|
736
|
+
static hasRequestedModel(availableModels, requestedModel) {
|
|
737
|
+
const normalizedRequestedModel = requestedModel.trim();
|
|
738
|
+
const requiresExactMatch = /@/.test(normalizedRequestedModel);
|
|
739
|
+
return availableModels.some((model) => model === normalizedRequestedModel ||
|
|
740
|
+
(!requiresExactMatch &&
|
|
741
|
+
(model.startsWith(`${normalizedRequestedModel}:`) ||
|
|
742
|
+
model.startsWith(`${normalizedRequestedModel}@`))));
|
|
743
|
+
}
|
|
744
|
+
static async getOllamaAvailableModels(timeout = 2000) {
|
|
745
|
+
const payload = (await this.fetchJsonWithTimeout(this.getOllamaTagsUrl(), {
|
|
746
|
+
timeout,
|
|
747
|
+
}));
|
|
748
|
+
return this.normalizeModelList(payload.models ?? []);
|
|
749
|
+
}
|
|
750
|
+
static async getLiteLLMAvailableModels(timeout = 2000) {
|
|
751
|
+
const payload = (await this.fetchJsonWithTimeout(this.getLiteLLMModelsUrl(), {
|
|
752
|
+
timeout,
|
|
753
|
+
headers: {
|
|
754
|
+
Authorization: `Bearer ${process.env.LITELLM_API_KEY || "sk-anything"}`,
|
|
755
|
+
"Content-Type": "application/json",
|
|
756
|
+
},
|
|
757
|
+
}));
|
|
758
|
+
return this.normalizeModelList(payload.data ?? []);
|
|
759
|
+
}
|
|
760
|
+
static async checkOllamaAvailability(options) {
|
|
761
|
+
try {
|
|
762
|
+
const models = await this.getOllamaAvailableModels(options.timeout);
|
|
763
|
+
if (!this.hasRequestedModel(models, options.model)) {
|
|
764
|
+
return {
|
|
765
|
+
available: false,
|
|
766
|
+
reason: `Configured Ollama model '${options.model}' is not installed`,
|
|
767
|
+
models,
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
return { available: true, models };
|
|
771
|
+
}
|
|
772
|
+
catch (error) {
|
|
773
|
+
return {
|
|
774
|
+
available: false,
|
|
775
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
776
|
+
models: [],
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
static async checkLiteLLMAvailability(options) {
|
|
781
|
+
try {
|
|
782
|
+
const models = await this.getLiteLLMAvailableModels(options.timeout);
|
|
783
|
+
if (models.length === 0) {
|
|
784
|
+
return {
|
|
785
|
+
available: false,
|
|
786
|
+
reason: "LiteLLM returned an empty model list",
|
|
787
|
+
models,
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
if (!this.hasRequestedModel(models, options.model)) {
|
|
791
|
+
return {
|
|
792
|
+
available: false,
|
|
793
|
+
reason: `Configured LiteLLM model '${options.model}' is not exposed by the proxy`,
|
|
794
|
+
models,
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
return { available: true, models };
|
|
798
|
+
}
|
|
799
|
+
catch (error) {
|
|
800
|
+
return {
|
|
801
|
+
available: false,
|
|
802
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
803
|
+
models: [],
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
static async checkLiteLLMConfig(healthStatus, timeout = this.DEFAULT_TIMEOUT) {
|
|
808
|
+
const liteLLMBase = this.getLiteLLMBaseUrl();
|
|
809
|
+
if (!liteLLMBase.startsWith("http")) {
|
|
810
|
+
healthStatus.isConfigured = false;
|
|
811
|
+
healthStatus.configurationIssues.push("Invalid LITELLM_BASE_URL format");
|
|
812
|
+
healthStatus.recommendations.push("Set LITELLM_BASE_URL to a valid URL (e.g., http://localhost:4000)");
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
const availability = await this.checkLiteLLMAvailability({
|
|
816
|
+
model: this.getConfiguredLiteLLMModel(),
|
|
817
|
+
timeout,
|
|
818
|
+
});
|
|
819
|
+
if (!availability.available) {
|
|
820
|
+
healthStatus.isConfigured = false;
|
|
821
|
+
healthStatus.configurationIssues.push(`LiteLLM runtime check failed: ${availability.reason ?? "unknown error"}`);
|
|
822
|
+
healthStatus.recommendations.push("Start the LiteLLM proxy and ensure the configured model is available from /v1/models");
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
healthStatus.isConfigured = true;
|
|
826
|
+
}
|
|
651
827
|
/**
|
|
652
828
|
* Check Ollama configuration
|
|
653
829
|
*/
|
|
654
|
-
static async checkOllamaConfig(healthStatus) {
|
|
655
|
-
const ollamaBase =
|
|
830
|
+
static async checkOllamaConfig(healthStatus, timeout = this.DEFAULT_TIMEOUT) {
|
|
831
|
+
const ollamaBase = this.getOllamaBaseUrl();
|
|
656
832
|
if (!ollamaBase.startsWith("http")) {
|
|
657
|
-
healthStatus.
|
|
658
|
-
healthStatus.
|
|
833
|
+
healthStatus.isConfigured = false;
|
|
834
|
+
healthStatus.configurationIssues.push("Invalid OLLAMA_BASE_URL format (OLLAMA_API_BASE is still accepted as a legacy alias)");
|
|
835
|
+
healthStatus.recommendations.push("Set OLLAMA_BASE_URL to a valid URL (e.g., http://localhost:11434). OLLAMA_API_BASE remains supported as a legacy alias.");
|
|
836
|
+
return;
|
|
659
837
|
}
|
|
838
|
+
const availability = await this.checkOllamaAvailability({
|
|
839
|
+
model: this.getConfiguredOllamaModel(),
|
|
840
|
+
timeout,
|
|
841
|
+
});
|
|
842
|
+
if (!availability.available) {
|
|
843
|
+
healthStatus.isConfigured = false;
|
|
844
|
+
healthStatus.configurationIssues.push(`Ollama runtime check failed: ${availability.reason ?? "unknown error"}`);
|
|
845
|
+
healthStatus.recommendations.push("Start Ollama and install the configured model before using Ollama as a fallback provider");
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
healthStatus.isConfigured = true;
|
|
660
849
|
}
|
|
661
850
|
/**
|
|
662
851
|
* Get common models for a provider
|
|
@@ -703,8 +892,21 @@ export class ProviderHealthChecker {
|
|
|
703
892
|
return [BedrockModels.CLAUDE_3_SONNET, BedrockModels.CLAUDE_3_HAIKU];
|
|
704
893
|
case AIProviderName.AZURE:
|
|
705
894
|
return [OpenAIModels.GPT_4O, OpenAIModels.GPT_4O_MINI, "gpt-35-turbo"];
|
|
706
|
-
case AIProviderName.
|
|
707
|
-
return [
|
|
895
|
+
case AIProviderName.LITELLM:
|
|
896
|
+
return [
|
|
897
|
+
"openai/gpt-4o-mini",
|
|
898
|
+
"anthropic/claude-3-haiku",
|
|
899
|
+
"google/gemini-2.5-flash",
|
|
900
|
+
];
|
|
901
|
+
case AIProviderName.OLLAMA: {
|
|
902
|
+
const envModel = process.env.OLLAMA_MODEL;
|
|
903
|
+
const defaults = [
|
|
904
|
+
"llama3.2:latest",
|
|
905
|
+
"llama3.1:latest",
|
|
906
|
+
"mistral:latest",
|
|
907
|
+
];
|
|
908
|
+
return envModel ? [envModel, ...defaults] : defaults;
|
|
909
|
+
}
|
|
708
910
|
default:
|
|
709
911
|
return [];
|
|
710
912
|
}
|
|
@@ -1139,18 +1341,61 @@ export class ProviderHealthChecker {
|
|
|
1139
1341
|
this.consecutiveFailures.clear();
|
|
1140
1342
|
}
|
|
1141
1343
|
}
|
|
1344
|
+
static async checkFallbackProviderAvailability(providerName, model) {
|
|
1345
|
+
const provider = providerName;
|
|
1346
|
+
if (provider === AIProviderName.OLLAMA) {
|
|
1347
|
+
const availability = await this.checkOllamaAvailability({
|
|
1348
|
+
model,
|
|
1349
|
+
timeout: 2000,
|
|
1350
|
+
});
|
|
1351
|
+
return {
|
|
1352
|
+
available: availability.available,
|
|
1353
|
+
reason: availability.reason,
|
|
1354
|
+
};
|
|
1355
|
+
}
|
|
1356
|
+
if (provider === AIProviderName.LITELLM) {
|
|
1357
|
+
const availability = await this.checkLiteLLMAvailability({
|
|
1358
|
+
model,
|
|
1359
|
+
timeout: 2000,
|
|
1360
|
+
});
|
|
1361
|
+
return {
|
|
1362
|
+
available: availability.available,
|
|
1363
|
+
reason: availability.reason,
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
try {
|
|
1367
|
+
const health = await this.checkProviderHealth(provider, {
|
|
1368
|
+
includeConnectivityTest: false,
|
|
1369
|
+
cacheResults: true,
|
|
1370
|
+
maxCacheAge: 15_000,
|
|
1371
|
+
timeout: 2000,
|
|
1372
|
+
});
|
|
1373
|
+
return {
|
|
1374
|
+
available: health.isHealthy,
|
|
1375
|
+
reason: health.error || health.configurationIssues[0] || health.warning,
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
catch (error) {
|
|
1379
|
+
return {
|
|
1380
|
+
available: false,
|
|
1381
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1142
1385
|
/**
|
|
1143
1386
|
* Get the best healthy provider from a list of options (NON-BLOCKING)
|
|
1144
1387
|
* Prioritizes healthy providers over configured but unhealthy ones
|
|
1145
1388
|
* Uses fast, cached health checks to avoid blocking initialization
|
|
1146
1389
|
*/
|
|
1147
1390
|
static async getBestHealthyProvider(preferredProviders = [
|
|
1391
|
+
"litellm",
|
|
1392
|
+
"ollama",
|
|
1148
1393
|
"openai",
|
|
1149
1394
|
"anthropic",
|
|
1150
1395
|
"vertex",
|
|
1396
|
+
"google-ai",
|
|
1151
1397
|
"bedrock",
|
|
1152
1398
|
"azure",
|
|
1153
|
-
"google-ai",
|
|
1154
1399
|
]) {
|
|
1155
1400
|
const healthStatuses = await this.checkAllProvidersHealth({
|
|
1156
1401
|
includeConnectivityTest: false, // Quick config check only
|
|
@@ -1191,6 +1436,7 @@ export class ProviderHealthChecker {
|
|
|
1191
1436
|
AIProviderName.OPENAI,
|
|
1192
1437
|
AIProviderName.BEDROCK,
|
|
1193
1438
|
AIProviderName.AZURE,
|
|
1439
|
+
AIProviderName.LITELLM,
|
|
1194
1440
|
AIProviderName.OLLAMA,
|
|
1195
1441
|
];
|
|
1196
1442
|
const healthChecks = providers.map((provider) => this.checkProviderHealth(provider, options));
|
|
@@ -50,7 +50,8 @@ export async function getBestProvider(requestedProvider) {
|
|
|
50
50
|
return process.env.DEFAULT_PROVIDER;
|
|
51
51
|
}
|
|
52
52
|
// Special case for Ollama - prioritize local when available
|
|
53
|
-
if (process.env.OLLAMA_BASE_URL
|
|
53
|
+
if ((process.env.OLLAMA_BASE_URL || process.env.OLLAMA_API_BASE) &&
|
|
54
|
+
process.env.OLLAMA_MODEL) {
|
|
54
55
|
try {
|
|
55
56
|
if (await isProviderAvailable("ollama")) {
|
|
56
57
|
logger.debug(`[getBestProvider] Prioritizing working local Ollama`);
|
|
@@ -63,15 +64,18 @@ export async function getBestProvider(requestedProvider) {
|
|
|
63
64
|
}
|
|
64
65
|
/**
|
|
65
66
|
* Provider priority order rationale:
|
|
66
|
-
* -
|
|
67
|
-
*
|
|
67
|
+
* - LiteLLM and Ollama are prioritized first for local/self-hosted deployments,
|
|
68
|
+
* avoiding unnecessary dependence on external providers during fallback scenarios.
|
|
69
|
+
* - Vertex (Google Cloud AI) follows for enterprise-grade reliability.
|
|
70
|
+
* - Google AI follows as second cloud priority for comprehensive Google AI ecosystem support.
|
|
68
71
|
* - OpenAI maintains high priority due to its consistent reliability and broad model support.
|
|
69
|
-
* - Other providers are ordered based on a combination of reliability, feature set, and historical performance
|
|
70
|
-
* - Ollama is kept as a fallback for local deployments when available.
|
|
72
|
+
* - Other providers are ordered based on a combination of reliability, feature set, and historical performance.
|
|
71
73
|
* Please update this comment if the order is changed in the future, and document the rationale for maintainability.
|
|
72
74
|
*/
|
|
73
75
|
const providers = [
|
|
74
|
-
"
|
|
76
|
+
"litellm", // Prioritize self-hosted proxy deployments first
|
|
77
|
+
"ollama", // Local models when the configured runtime target is installed
|
|
78
|
+
"vertex", // Google Cloud AI (enterprise)
|
|
75
79
|
"google-ai", // Google AI ecosystem support
|
|
76
80
|
"openai", // Reliable with broad model support
|
|
77
81
|
"anthropic",
|
|
@@ -79,7 +83,6 @@ export async function getBestProvider(requestedProvider) {
|
|
|
79
83
|
"azure",
|
|
80
84
|
"mistral",
|
|
81
85
|
"huggingface",
|
|
82
|
-
"ollama", // Keep as fallback
|
|
83
86
|
];
|
|
84
87
|
for (const provider of providers) {
|
|
85
88
|
if (await isProviderAvailable(provider)) {
|
|
@@ -99,22 +102,13 @@ async function isProviderAvailable(providerName) {
|
|
|
99
102
|
if (!hasProviderEnvVars(providerName) && providerName !== "ollama") {
|
|
100
103
|
return false;
|
|
101
104
|
}
|
|
105
|
+
if (providerName === "litellm") {
|
|
106
|
+
const availability = await ProviderHealthChecker.checkFallbackProviderAvailability(AIProviderName.LITELLM, process.env.LITELLM_MODEL || "openai/gpt-4o-mini");
|
|
107
|
+
return availability.available;
|
|
108
|
+
}
|
|
102
109
|
if (providerName === "ollama") {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
method: "GET",
|
|
106
|
-
signal: AbortSignal.timeout(2000),
|
|
107
|
-
});
|
|
108
|
-
if (response.ok) {
|
|
109
|
-
const { models } = await response.json();
|
|
110
|
-
const defaultOllamaModel = "llama3.2:latest";
|
|
111
|
-
return models.some((m) => m.name === defaultOllamaModel);
|
|
112
|
-
}
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
110
|
+
const availability = await ProviderHealthChecker.checkFallbackProviderAvailability(AIProviderName.OLLAMA, process.env.OLLAMA_MODEL || "llama3.1:8b");
|
|
111
|
+
return availability.available;
|
|
118
112
|
}
|
|
119
113
|
try {
|
|
120
114
|
const provider = await AIProviderFactory.createProvider(providerName);
|
|
@@ -414,6 +408,7 @@ export function getAvailableProviders() {
|
|
|
414
408
|
"anthropic",
|
|
415
409
|
"azure",
|
|
416
410
|
"google-ai",
|
|
411
|
+
"litellm",
|
|
417
412
|
"huggingface",
|
|
418
413
|
"ollama",
|
|
419
414
|
"mistral",
|
|
@@ -69,6 +69,8 @@ export declare class MCPToolRegistry extends MCPRegistry {
|
|
|
69
69
|
permissions?: string[];
|
|
70
70
|
context?: ExecutionContext;
|
|
71
71
|
}): Promise<ToolInfo[]>;
|
|
72
|
+
private resolveToolExecutionTarget;
|
|
73
|
+
private createExecutionContext;
|
|
72
74
|
/**
|
|
73
75
|
* Get tool information with server details
|
|
74
76
|
*/
|
package/dist/mcp/toolRegistry.js
CHANGED
|
@@ -9,6 +9,7 @@ import { shouldDisableBuiltinTools } from "../utils/toolUtils.js";
|
|
|
9
9
|
import { directAgentTools } from "../agent/directTools.js";
|
|
10
10
|
import { detectCategory, createMCPServerInfo } from "../utils/mcpDefaults.js";
|
|
11
11
|
import { FlexibleToolValidator } from "./flexibleToolValidator.js";
|
|
12
|
+
import { ErrorFactory } from "../utils/errorHandling.js";
|
|
12
13
|
import { HITLUserRejectedError, HITLTimeoutError } from "../hitl/hitlErrors.js";
|
|
13
14
|
import { withSpan, tracers, ATTR } from "../telemetry/index.js";
|
|
14
15
|
import { getAuthContext } from "../auth/authContext.js";
|
|
@@ -263,22 +264,7 @@ export class MCPToolRegistry extends MCPRegistry {
|
|
|
263
264
|
hasContext: context !== undefined,
|
|
264
265
|
sessionId: context?.sessionId,
|
|
265
266
|
});
|
|
266
|
-
|
|
267
|
-
let tool = this.tools.get(toolName);
|
|
268
|
-
registryLogger.info(`🔍 [TOOL_LOOKUP] Direct lookup result for '${toolName}':`, !!tool);
|
|
269
|
-
// If not found, search for tool by name across all entries (for backward compatibility)
|
|
270
|
-
let toolId = toolName;
|
|
271
|
-
if (!tool) {
|
|
272
|
-
const matches = Array.from(this.tools.entries()).filter(([, toolInfo]) => toolInfo.name === toolName);
|
|
273
|
-
if (matches.length > 1) {
|
|
274
|
-
throw new Error(`Ambiguous tool name '${toolName}'. Use fully-qualified name 'serverId.${toolName}'.`);
|
|
275
|
-
}
|
|
276
|
-
if (matches.length === 1) {
|
|
277
|
-
const [candidateToolId, toolInfo] = matches[0];
|
|
278
|
-
tool = toolInfo;
|
|
279
|
-
toolId = candidateToolId;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
267
|
+
const { tool, toolId } = this.resolveToolExecutionTarget(toolName);
|
|
282
268
|
if (!tool) {
|
|
283
269
|
throw new Error(`Tool '${toolName}' not found in registry`);
|
|
284
270
|
}
|
|
@@ -291,21 +277,7 @@ export class MCPToolRegistry extends MCPRegistry {
|
|
|
291
277
|
: "mcp";
|
|
292
278
|
span.setAttribute("tool.type", toolType);
|
|
293
279
|
span.setAttribute(ATTR.MCP_SERVER_ID, serverId);
|
|
294
|
-
|
|
295
|
-
let authUserId;
|
|
296
|
-
try {
|
|
297
|
-
const authCtx = getAuthContext();
|
|
298
|
-
authUserId = authCtx?.user?.id;
|
|
299
|
-
}
|
|
300
|
-
catch {
|
|
301
|
-
// Auth context not available — that's fine
|
|
302
|
-
}
|
|
303
|
-
// Create execution context if not provided
|
|
304
|
-
const execContext = {
|
|
305
|
-
...context,
|
|
306
|
-
sessionId: context?.sessionId ?? randomUUID(),
|
|
307
|
-
userId: context?.userId ?? authUserId,
|
|
308
|
-
};
|
|
280
|
+
const execContext = this.createExecutionContext(context);
|
|
309
281
|
// Get the tool implementation using the resolved toolId
|
|
310
282
|
const toolImpl = this.toolImplementations.get(toolId);
|
|
311
283
|
registryLogger.debug(`Looking for tool '${toolName}' (toolId: '${toolId}'), found: ${!!toolImpl}, type: ${typeof toolImpl?.execute}`);
|
|
@@ -504,6 +476,35 @@ export class MCPToolRegistry extends MCPRegistry {
|
|
|
504
476
|
registryLogger.debug(`Listed ${result.length} unique tools (${filter ? "filtered" : "unfiltered"})`);
|
|
505
477
|
return result;
|
|
506
478
|
}
|
|
479
|
+
resolveToolExecutionTarget(toolName) {
|
|
480
|
+
let tool = this.tools.get(toolName);
|
|
481
|
+
registryLogger.info(`🔍 [TOOL_LOOKUP] Direct lookup result for '${toolName}':`, !!tool);
|
|
482
|
+
let toolId = toolName;
|
|
483
|
+
if (!tool) {
|
|
484
|
+
const matches = Array.from(this.tools.entries()).filter(([, toolInfo]) => toolInfo.name === toolName);
|
|
485
|
+
if (matches.length > 1) {
|
|
486
|
+
throw ErrorFactory.toolExecutionFailed(toolName, new Error(`Ambiguous tool name '${toolName}'. Use fully-qualified name 'serverId.${toolName}'.`));
|
|
487
|
+
}
|
|
488
|
+
if (matches.length === 1) {
|
|
489
|
+
[toolId, tool] = matches[0];
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return { tool, toolId };
|
|
493
|
+
}
|
|
494
|
+
createExecutionContext(context) {
|
|
495
|
+
let authUserId;
|
|
496
|
+
try {
|
|
497
|
+
authUserId = getAuthContext()?.user?.id;
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
// Auth context not available — that's fine
|
|
501
|
+
}
|
|
502
|
+
return {
|
|
503
|
+
...context,
|
|
504
|
+
sessionId: context?.sessionId ?? randomUUID(),
|
|
505
|
+
userId: context?.userId ?? authUserId,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
507
508
|
/**
|
|
508
509
|
* Get tool information with server details
|
|
509
510
|
*/
|