@juspay/neurolink 9.15.0 → 9.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/adapters/video/videoAnalyzer.d.ts +1 -1
- package/dist/adapters/video/videoAnalyzer.js +10 -8
- package/dist/cli/commands/setup-anthropic.js +1 -14
- package/dist/cli/commands/setup-azure.js +1 -12
- package/dist/cli/commands/setup-bedrock.js +1 -9
- package/dist/cli/commands/setup-google-ai.js +1 -12
- package/dist/cli/commands/setup-openai.js +1 -14
- package/dist/cli/commands/workflow.d.ts +27 -0
- package/dist/cli/commands/workflow.js +216 -0
- package/dist/cli/factories/commandFactory.js +79 -20
- package/dist/cli/index.js +0 -1
- package/dist/cli/parser.js +4 -1
- package/dist/cli/utils/maskCredential.d.ts +11 -0
- package/dist/cli/utils/maskCredential.js +23 -0
- package/dist/constants/contextWindows.js +107 -16
- package/dist/constants/enums.d.ts +99 -15
- package/dist/constants/enums.js +152 -22
- package/dist/context/budgetChecker.js +1 -1
- package/dist/context/contextCompactor.js +31 -4
- package/dist/context/emergencyTruncation.d.ts +21 -0
- package/dist/context/emergencyTruncation.js +88 -0
- package/dist/context/errorDetection.d.ts +16 -0
- package/dist/context/errorDetection.js +48 -1
- package/dist/context/errors.d.ts +19 -0
- package/dist/context/errors.js +21 -0
- package/dist/context/stages/slidingWindowTruncator.d.ts +6 -0
- package/dist/context/stages/slidingWindowTruncator.js +159 -24
- package/dist/core/baseProvider.js +306 -200
- package/dist/core/conversationMemoryManager.js +104 -61
- package/dist/core/evaluationProviders.js +16 -33
- package/dist/core/factory.js +237 -164
- package/dist/core/modules/GenerationHandler.js +175 -116
- package/dist/core/modules/MessageBuilder.js +222 -170
- package/dist/core/modules/StreamHandler.d.ts +1 -0
- package/dist/core/modules/StreamHandler.js +95 -27
- package/dist/core/modules/TelemetryHandler.d.ts +10 -1
- package/dist/core/modules/TelemetryHandler.js +25 -7
- package/dist/core/modules/ToolsManager.js +115 -191
- package/dist/core/redisConversationMemoryManager.js +418 -282
- package/dist/factories/providerRegistry.d.ts +5 -0
- package/dist/factories/providerRegistry.js +20 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -2
- package/dist/lib/adapters/video/videoAnalyzer.d.ts +1 -1
- package/dist/lib/adapters/video/videoAnalyzer.js +10 -8
- package/dist/lib/constants/contextWindows.js +107 -16
- package/dist/lib/constants/enums.d.ts +99 -15
- package/dist/lib/constants/enums.js +152 -22
- package/dist/lib/context/budgetChecker.js +1 -1
- package/dist/lib/context/contextCompactor.js +31 -4
- package/dist/lib/context/emergencyTruncation.d.ts +21 -0
- package/dist/lib/context/emergencyTruncation.js +89 -0
- package/dist/lib/context/errorDetection.d.ts +16 -0
- package/dist/lib/context/errorDetection.js +48 -1
- package/dist/lib/context/errors.d.ts +19 -0
- package/dist/lib/context/errors.js +22 -0
- package/dist/lib/context/stages/slidingWindowTruncator.d.ts +6 -0
- package/dist/lib/context/stages/slidingWindowTruncator.js +159 -24
- package/dist/lib/core/baseProvider.js +306 -200
- package/dist/lib/core/conversationMemoryManager.js +104 -61
- package/dist/lib/core/evaluationProviders.js +16 -33
- package/dist/lib/core/factory.js +237 -164
- package/dist/lib/core/modules/GenerationHandler.js +175 -116
- package/dist/lib/core/modules/MessageBuilder.js +222 -170
- package/dist/lib/core/modules/StreamHandler.d.ts +1 -0
- package/dist/lib/core/modules/StreamHandler.js +95 -27
- package/dist/lib/core/modules/TelemetryHandler.d.ts +10 -1
- package/dist/lib/core/modules/TelemetryHandler.js +25 -7
- package/dist/lib/core/modules/ToolsManager.js +115 -191
- package/dist/lib/core/redisConversationMemoryManager.js +418 -282
- package/dist/lib/factories/providerRegistry.d.ts +5 -0
- package/dist/lib/factories/providerRegistry.js +20 -2
- package/dist/lib/index.d.ts +2 -2
- package/dist/lib/index.js +4 -2
- package/dist/lib/mcp/externalServerManager.js +66 -0
- package/dist/lib/mcp/mcpCircuitBreaker.js +24 -0
- package/dist/lib/mcp/mcpClientFactory.js +16 -0
- package/dist/lib/mcp/toolDiscoveryService.js +32 -6
- package/dist/lib/mcp/toolRegistry.js +193 -123
- package/dist/lib/neurolink.d.ts +6 -0
- package/dist/lib/neurolink.js +1162 -646
- package/dist/lib/providers/amazonBedrock.d.ts +1 -1
- package/dist/lib/providers/amazonBedrock.js +521 -319
- package/dist/lib/providers/anthropic.js +73 -17
- package/dist/lib/providers/anthropicBaseProvider.js +77 -17
- package/dist/lib/providers/googleAiStudio.d.ts +1 -1
- package/dist/lib/providers/googleAiStudio.js +292 -227
- package/dist/lib/providers/googleVertex.d.ts +36 -1
- package/dist/lib/providers/googleVertex.js +553 -260
- package/dist/lib/providers/ollama.js +329 -278
- package/dist/lib/providers/openAI.js +77 -19
- package/dist/lib/providers/sagemaker/parsers.js +3 -3
- package/dist/lib/providers/sagemaker/streaming.js +3 -3
- package/dist/lib/proxy/proxyFetch.js +81 -48
- package/dist/lib/rag/ChunkerFactory.js +1 -1
- package/dist/lib/rag/chunkers/MarkdownChunker.d.ts +22 -0
- package/dist/lib/rag/chunkers/MarkdownChunker.js +213 -9
- package/dist/lib/rag/chunking/markdownChunker.d.ts +16 -0
- package/dist/lib/rag/chunking/markdownChunker.js +174 -2
- package/dist/lib/rag/pipeline/contextAssembly.js +2 -1
- package/dist/lib/rag/ragIntegration.d.ts +18 -1
- package/dist/lib/rag/ragIntegration.js +94 -14
- package/dist/lib/rag/retrieval/vectorQueryTool.js +21 -4
- package/dist/lib/server/abstract/baseServerAdapter.js +4 -1
- package/dist/lib/server/adapters/fastifyAdapter.js +35 -30
- package/dist/lib/services/server/ai/observability/instrumentation.d.ts +32 -0
- package/dist/lib/services/server/ai/observability/instrumentation.js +39 -0
- package/dist/lib/telemetry/attributes.d.ts +52 -0
- package/dist/lib/telemetry/attributes.js +61 -0
- package/dist/lib/telemetry/index.d.ts +3 -0
- package/dist/lib/telemetry/index.js +3 -0
- package/dist/lib/telemetry/telemetryService.d.ts +6 -0
- package/dist/lib/telemetry/telemetryService.js +6 -0
- package/dist/lib/telemetry/tracers.d.ts +15 -0
- package/dist/lib/telemetry/tracers.js +17 -0
- package/dist/lib/telemetry/withSpan.d.ts +9 -0
- package/dist/lib/telemetry/withSpan.js +35 -0
- package/dist/lib/types/contextTypes.d.ts +10 -0
- package/dist/lib/types/streamTypes.d.ts +14 -0
- package/dist/lib/utils/conversationMemory.js +121 -82
- package/dist/lib/utils/logger.d.ts +5 -0
- package/dist/lib/utils/logger.js +50 -2
- package/dist/lib/utils/messageBuilder.js +22 -42
- package/dist/lib/utils/modelDetection.js +3 -3
- package/dist/lib/utils/providerRetry.d.ts +41 -0
- package/dist/lib/utils/providerRetry.js +114 -0
- package/dist/lib/utils/retryability.d.ts +14 -0
- package/dist/lib/utils/retryability.js +23 -0
- package/dist/lib/utils/sanitizers/svg.js +4 -5
- package/dist/lib/utils/tokenEstimation.d.ts +11 -1
- package/dist/lib/utils/tokenEstimation.js +19 -4
- package/dist/lib/utils/videoAnalysisProcessor.js +7 -3
- package/dist/mcp/externalServerManager.js +66 -0
- package/dist/mcp/mcpCircuitBreaker.js +24 -0
- package/dist/mcp/mcpClientFactory.js +16 -0
- package/dist/mcp/toolDiscoveryService.js +32 -6
- package/dist/mcp/toolRegistry.js +193 -123
- package/dist/neurolink.d.ts +6 -0
- package/dist/neurolink.js +1162 -646
- package/dist/providers/amazonBedrock.d.ts +1 -1
- package/dist/providers/amazonBedrock.js +521 -319
- package/dist/providers/anthropic.js +73 -17
- package/dist/providers/anthropicBaseProvider.js +77 -17
- package/dist/providers/googleAiStudio.d.ts +1 -1
- package/dist/providers/googleAiStudio.js +292 -227
- package/dist/providers/googleVertex.d.ts +36 -1
- package/dist/providers/googleVertex.js +553 -260
- package/dist/providers/ollama.js +329 -278
- package/dist/providers/openAI.js +77 -19
- package/dist/providers/sagemaker/parsers.js +3 -3
- package/dist/providers/sagemaker/streaming.js +3 -3
- package/dist/proxy/proxyFetch.js +81 -48
- package/dist/rag/ChunkerFactory.js +1 -1
- package/dist/rag/chunkers/MarkdownChunker.d.ts +22 -0
- package/dist/rag/chunkers/MarkdownChunker.js +213 -9
- package/dist/rag/chunking/markdownChunker.d.ts +16 -0
- package/dist/rag/chunking/markdownChunker.js +174 -2
- package/dist/rag/pipeline/contextAssembly.js +2 -1
- package/dist/rag/ragIntegration.d.ts +18 -1
- package/dist/rag/ragIntegration.js +94 -14
- package/dist/rag/retrieval/vectorQueryTool.js +21 -4
- package/dist/server/abstract/baseServerAdapter.js +4 -1
- package/dist/server/adapters/fastifyAdapter.js +35 -30
- package/dist/services/server/ai/observability/instrumentation.d.ts +32 -0
- package/dist/services/server/ai/observability/instrumentation.js +39 -0
- package/dist/telemetry/attributes.d.ts +52 -0
- package/dist/telemetry/attributes.js +60 -0
- package/dist/telemetry/index.d.ts +3 -0
- package/dist/telemetry/index.js +3 -0
- package/dist/telemetry/telemetryService.d.ts +6 -0
- package/dist/telemetry/telemetryService.js +6 -0
- package/dist/telemetry/tracers.d.ts +15 -0
- package/dist/telemetry/tracers.js +16 -0
- package/dist/telemetry/withSpan.d.ts +9 -0
- package/dist/telemetry/withSpan.js +34 -0
- package/dist/types/contextTypes.d.ts +10 -0
- package/dist/types/streamTypes.d.ts +14 -0
- package/dist/utils/conversationMemory.js +121 -82
- package/dist/utils/logger.d.ts +5 -0
- package/dist/utils/logger.js +50 -2
- package/dist/utils/messageBuilder.js +22 -42
- package/dist/utils/modelDetection.js +3 -3
- package/dist/utils/providerRetry.d.ts +41 -0
- package/dist/utils/providerRetry.js +113 -0
- package/dist/utils/retryability.d.ts +14 -0
- package/dist/utils/retryability.js +22 -0
- package/dist/utils/sanitizers/svg.js +4 -5
- package/dist/utils/tokenEstimation.d.ts +11 -1
- package/dist/utils/tokenEstimation.js +19 -4
- package/dist/utils/videoAnalysisProcessor.js +7 -3
- package/dist/workflow/config.d.ts +26 -26
- package/package.json +1 -1
|
@@ -5,11 +5,16 @@ import type { ProviderRegistryOptions } from "../types/index.js";
|
|
|
5
5
|
*/
|
|
6
6
|
export declare class ProviderRegistry {
|
|
7
7
|
private static registered;
|
|
8
|
+
private static registrationPromise;
|
|
8
9
|
private static options;
|
|
9
10
|
/**
|
|
10
11
|
* Register all providers with the factory
|
|
11
12
|
*/
|
|
12
13
|
static registerAllProviders(): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Internal registration implementation
|
|
16
|
+
*/
|
|
17
|
+
private static _doRegister;
|
|
13
18
|
/**
|
|
14
19
|
* Check if providers are registered
|
|
15
20
|
*/
|
|
@@ -7,6 +7,7 @@ import { AIProviderName, GoogleAIModels, OpenAIModels, AnthropicModels, VertexMo
|
|
|
7
7
|
*/
|
|
8
8
|
export class ProviderRegistry {
|
|
9
9
|
static registered = false;
|
|
10
|
+
static registrationPromise = null;
|
|
10
11
|
static options = {
|
|
11
12
|
enableManualMCP: false, // Default to disabled for safety
|
|
12
13
|
};
|
|
@@ -17,6 +18,22 @@ export class ProviderRegistry {
|
|
|
17
18
|
if (this.registered) {
|
|
18
19
|
return;
|
|
19
20
|
}
|
|
21
|
+
if (this.registrationPromise) {
|
|
22
|
+
return this.registrationPromise;
|
|
23
|
+
}
|
|
24
|
+
this.registrationPromise = this._doRegister();
|
|
25
|
+
try {
|
|
26
|
+
await this.registrationPromise;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
this.registrationPromise = null; // Allow retry on failure
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Internal registration implementation
|
|
35
|
+
*/
|
|
36
|
+
static async _doRegister() {
|
|
20
37
|
try {
|
|
21
38
|
// Register providers with dynamic import factory functions
|
|
22
39
|
const { ProviderFactory } = await import("./providerFactory.js");
|
|
@@ -34,7 +51,7 @@ export class ProviderRegistry {
|
|
|
34
51
|
ProviderFactory.registerProvider(AIProviderName.ANTHROPIC, async (modelName, _providerName, sdk) => {
|
|
35
52
|
const { AnthropicProvider } = await import("../providers/anthropic.js");
|
|
36
53
|
return new AnthropicProvider(modelName, sdk);
|
|
37
|
-
}, AnthropicModels.
|
|
54
|
+
}, AnthropicModels.CLAUDE_SONNET_4_6, ["claude", "anthropic"]);
|
|
38
55
|
// Register Amazon Bedrock provider
|
|
39
56
|
ProviderFactory.registerProvider(AIProviderName.BEDROCK, async (modelName, _providerName, sdk, region) => {
|
|
40
57
|
const { AmazonBedrockProvider } = await import("../providers/amazonBedrock.js");
|
|
@@ -54,7 +71,7 @@ export class ProviderRegistry {
|
|
|
54
71
|
ProviderFactory.registerProvider(AIProviderName.VERTEX, async (modelName, providerName, sdk, region) => {
|
|
55
72
|
const { GoogleVertexProvider } = await import("../providers/googleVertex.js");
|
|
56
73
|
return new GoogleVertexProvider(modelName, providerName, sdk, region);
|
|
57
|
-
}, VertexModels.
|
|
74
|
+
}, VertexModels.CLAUDE_4_6_SONNET, ["vertex", "googleVertex"]);
|
|
58
75
|
// Register Hugging Face provider (Unified Router implementation)
|
|
59
76
|
ProviderFactory.registerProvider(AIProviderName.HUGGINGFACE, async (modelName) => {
|
|
60
77
|
const { HuggingFaceProvider } = await import("../providers/huggingFace.js");
|
|
@@ -130,6 +147,7 @@ export class ProviderRegistry {
|
|
|
130
147
|
static clearRegistrations() {
|
|
131
148
|
ProviderFactory.clearRegistrations();
|
|
132
149
|
this.registered = false;
|
|
150
|
+
this.registrationPromise = null;
|
|
133
151
|
}
|
|
134
152
|
/**
|
|
135
153
|
* Set registry options (should be called before initialization)
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -49,9 +49,9 @@ export { NeuroLink };
|
|
|
49
49
|
export type { MCPServerInfo } from "./types/mcpTypes.js";
|
|
50
50
|
export type { LangfuseConfig, LangfuseSpanAttributes, ObservabilityConfig, OpenTelemetryConfig, TraceNameFormat, } from "./types/observability.js";
|
|
51
51
|
export { buildObservabilityConfigFromEnv } from "./utils/observabilityHelpers.js";
|
|
52
|
-
import { createContextEnricher, flushOpenTelemetry, getLangfuseContext, getLangfuseHealthStatus, getLangfuseSpanProcessor, getSpanProcessors, getTracer, getTracerProvider, initializeOpenTelemetry, isOpenTelemetryInitialized, isUsingExternalTracerProvider, setLangfuseContext, shutdownOpenTelemetry } from "./services/server/ai/observability/instrumentation.js";
|
|
52
|
+
import { createContextEnricher, flushOpenTelemetry, getLangfuseContext, getLangfuseHealthStatus, getLangfuseSpanProcessor, getSpanProcessors, getTracer, getTracerProvider, initializeOpenTelemetry, isOpenTelemetryInitialized, isUsingExternalTracerProvider, runWithCurrentLangfuseContext, setLangfuseContext, shutdownOpenTelemetry } from "./services/server/ai/observability/instrumentation.js";
|
|
53
53
|
export type { LangfuseContext } from "./services/server/ai/observability/instrumentation.js";
|
|
54
|
-
export { initializeOpenTelemetry, shutdownOpenTelemetry, flushOpenTelemetry, getLangfuseHealthStatus, setLangfuseContext, getLangfuseSpanProcessor, getTracerProvider, isOpenTelemetryInitialized, getSpanProcessors, createContextEnricher, isUsingExternalTracerProvider, getLangfuseContext, getTracer, };
|
|
54
|
+
export { initializeOpenTelemetry, shutdownOpenTelemetry, flushOpenTelemetry, getLangfuseHealthStatus, setLangfuseContext, getLangfuseSpanProcessor, getTracerProvider, isOpenTelemetryInitialized, getSpanProcessors, createContextEnricher, isUsingExternalTracerProvider, getLangfuseContext, getTracer, runWithCurrentLangfuseContext, };
|
|
55
55
|
export { clearAnalyticsMetrics, createAnalyticsMiddleware, getAnalyticsMetrics, } from "./middleware/builtin/analytics.js";
|
|
56
56
|
export { MiddlewareFactory } from "./middleware/factory.js";
|
|
57
57
|
export type { MiddlewareConfig, MiddlewareContext, MiddlewareFactoryOptions, MiddlewarePreset, NeuroLinkMiddleware, } from "./types/middlewareTypes.js";
|
package/dist/lib/index.js
CHANGED
|
@@ -60,13 +60,15 @@ import { createContextEnricher, flushOpenTelemetry,
|
|
|
60
60
|
// Enhanced context and tracing
|
|
61
61
|
getLangfuseContext, getLangfuseHealthStatus, getLangfuseSpanProcessor,
|
|
62
62
|
// NEW EXPORTS - External TracerProvider Support
|
|
63
|
-
getSpanProcessors, getTracer, getTracerProvider, initializeOpenTelemetry, isOpenTelemetryInitialized, isUsingExternalTracerProvider, setLangfuseContext, shutdownOpenTelemetry, } from "./services/server/ai/observability/instrumentation.js";
|
|
63
|
+
getSpanProcessors, getTracer, getTracerProvider, initializeOpenTelemetry, isOpenTelemetryInitialized, isUsingExternalTracerProvider, runWithCurrentLangfuseContext, setLangfuseContext, shutdownOpenTelemetry, } from "./services/server/ai/observability/instrumentation.js";
|
|
64
64
|
import { getTelemetryStatus as getStatus, initializeTelemetry as init, } from "./telemetry/index.js";
|
|
65
65
|
export { initializeOpenTelemetry, shutdownOpenTelemetry, flushOpenTelemetry, getLangfuseHealthStatus, setLangfuseContext, getLangfuseSpanProcessor, getTracerProvider, isOpenTelemetryInitialized,
|
|
66
66
|
// NEW EXPORTS - External TracerProvider Support
|
|
67
67
|
getSpanProcessors, createContextEnricher, isUsingExternalTracerProvider,
|
|
68
68
|
// Enhanced context and tracing
|
|
69
|
-
getLangfuseContext, getTracer,
|
|
69
|
+
getLangfuseContext, getTracer,
|
|
70
|
+
// ALS context propagation helper
|
|
71
|
+
runWithCurrentLangfuseContext, };
|
|
70
72
|
// Analytics Middleware exports
|
|
71
73
|
export { clearAnalyticsMetrics, createAnalyticsMiddleware, getAnalyticsMetrics, } from "./middleware/builtin/analytics.js";
|
|
72
74
|
export { MiddlewareFactory } from "./middleware/factory.js";
|
|
@@ -14,6 +14,9 @@ import { toolRegistry } from "./toolRegistry.js";
|
|
|
14
14
|
import { HITLUserRejectedError, HITLTimeoutError } from "../hitl/hitlErrors.js";
|
|
15
15
|
import { detectCategory } from "../utils/mcpDefaults.js";
|
|
16
16
|
import { isObject, isNonNullObject } from "../utils/typeUtils.js";
|
|
17
|
+
import { TelemetryService } from "../telemetry/telemetryService.js";
|
|
18
|
+
import { tracers } from "../telemetry/tracers.js";
|
|
19
|
+
import { SpanStatusCode } from "@opentelemetry/api";
|
|
17
20
|
/**
|
|
18
21
|
* Recursively substitute environment variables in strings
|
|
19
22
|
* Replaces ${VAR_NAME} with the value from process.env.VAR_NAME
|
|
@@ -745,6 +748,16 @@ export class ExternalServerManager extends EventEmitter {
|
|
|
745
748
|
throw new Error(`Server '${serverId}' not found`);
|
|
746
749
|
}
|
|
747
750
|
const config = instance.config;
|
|
751
|
+
const span = tracers.mcp.startSpan("neurolink.mcp.server.start", {
|
|
752
|
+
attributes: {
|
|
753
|
+
"mcp.server_id": serverId,
|
|
754
|
+
"mcp.transport": config.transport,
|
|
755
|
+
"mcp.command_name": config.command
|
|
756
|
+
? config.command.split(/[\\/]/).pop() || ""
|
|
757
|
+
: "",
|
|
758
|
+
"mcp.command_present": Boolean(config.command),
|
|
759
|
+
},
|
|
760
|
+
});
|
|
748
761
|
try {
|
|
749
762
|
this.updateServerStatus(serverId, "connecting");
|
|
750
763
|
mcpLogger.debug(`[ExternalServerManager] Starting server: ${serverId}`, {
|
|
@@ -803,6 +816,8 @@ export class ExternalServerManager extends EventEmitter {
|
|
|
803
816
|
toolCount: instance.toolsMap.size,
|
|
804
817
|
timestamp: new Date(),
|
|
805
818
|
});
|
|
819
|
+
span.setAttribute("mcp.tool_count", instance.toolsMap.size);
|
|
820
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
806
821
|
mcpLogger.info(`[ExternalServerManager] Server started successfully: ${serverId}`);
|
|
807
822
|
}
|
|
808
823
|
catch (error) {
|
|
@@ -810,8 +825,16 @@ export class ExternalServerManager extends EventEmitter {
|
|
|
810
825
|
this.updateServerStatus(serverId, "failed");
|
|
811
826
|
instance.lastError =
|
|
812
827
|
error instanceof Error ? error.message : String(error);
|
|
828
|
+
span.recordException(error instanceof Error ? error : new Error(String(error)));
|
|
829
|
+
span.setStatus({
|
|
830
|
+
code: SpanStatusCode.ERROR,
|
|
831
|
+
message: error instanceof Error ? error.message : String(error),
|
|
832
|
+
});
|
|
813
833
|
throw error;
|
|
814
834
|
}
|
|
835
|
+
finally {
|
|
836
|
+
span.end();
|
|
837
|
+
}
|
|
815
838
|
}
|
|
816
839
|
/**
|
|
817
840
|
* Stop an external MCP server
|
|
@@ -821,6 +844,11 @@ export class ExternalServerManager extends EventEmitter {
|
|
|
821
844
|
if (!instance) {
|
|
822
845
|
return;
|
|
823
846
|
}
|
|
847
|
+
const span = tracers.mcp.startSpan("neurolink.mcp.server.stop", {
|
|
848
|
+
attributes: {
|
|
849
|
+
"mcp.server_id": serverId,
|
|
850
|
+
},
|
|
851
|
+
});
|
|
824
852
|
try {
|
|
825
853
|
this.updateServerStatus(serverId, "stopping");
|
|
826
854
|
// Clear timers
|
|
@@ -851,11 +879,20 @@ export class ExternalServerManager extends EventEmitter {
|
|
|
851
879
|
instance.process = null;
|
|
852
880
|
}
|
|
853
881
|
this.updateServerStatus(serverId, "stopped");
|
|
882
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
854
883
|
mcpLogger.info(`[ExternalServerManager] Server stopped: ${serverId}`);
|
|
855
884
|
}
|
|
856
885
|
catch (error) {
|
|
857
886
|
mcpLogger.error(`[ExternalServerManager] Error stopping server ${serverId}:`, error);
|
|
858
887
|
this.updateServerStatus(serverId, "failed");
|
|
888
|
+
span.recordException(error instanceof Error ? error : new Error(String(error)));
|
|
889
|
+
span.setStatus({
|
|
890
|
+
code: SpanStatusCode.ERROR,
|
|
891
|
+
message: error instanceof Error ? error.message : String(error),
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
finally {
|
|
895
|
+
span.end();
|
|
859
896
|
}
|
|
860
897
|
}
|
|
861
898
|
/**
|
|
@@ -959,16 +996,32 @@ export class ExternalServerManager extends EventEmitter {
|
|
|
959
996
|
return;
|
|
960
997
|
} // already scheduled
|
|
961
998
|
instance.restartTimer = setTimeout(async () => {
|
|
999
|
+
const restartSpan = tracers.mcp.startSpan("neurolink.mcp.server.restart", {
|
|
1000
|
+
attributes: {
|
|
1001
|
+
"mcp.server_id": serverId,
|
|
1002
|
+
"mcp.restart_attempt": instance.reconnectAttempts,
|
|
1003
|
+
"mcp.restart_delay_ms": delay,
|
|
1004
|
+
},
|
|
1005
|
+
});
|
|
962
1006
|
try {
|
|
963
1007
|
await this.stopServer(serverId);
|
|
964
1008
|
await this.startServer(serverId);
|
|
965
1009
|
// Reset restart attempts on successful restart
|
|
966
1010
|
instance.reconnectAttempts = 0;
|
|
1011
|
+
restartSpan.setStatus({ code: SpanStatusCode.OK });
|
|
967
1012
|
}
|
|
968
1013
|
catch (error) {
|
|
969
1014
|
mcpLogger.error(`[ExternalServerManager] Restart failed for ${serverId}:`, error);
|
|
1015
|
+
restartSpan.recordException(error instanceof Error ? error : new Error(String(error)));
|
|
1016
|
+
restartSpan.setStatus({
|
|
1017
|
+
code: SpanStatusCode.ERROR,
|
|
1018
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1019
|
+
});
|
|
970
1020
|
this.scheduleRestart(serverId); // Try again
|
|
971
1021
|
}
|
|
1022
|
+
finally {
|
|
1023
|
+
restartSpan.end();
|
|
1024
|
+
}
|
|
972
1025
|
}, delay);
|
|
973
1026
|
}
|
|
974
1027
|
/**
|
|
@@ -1376,6 +1429,12 @@ export class ExternalServerManager extends EventEmitter {
|
|
|
1376
1429
|
mcpLogger.debug(`[ExternalServerManager] Tool executed successfully: ${toolName} on ${serverId}`, {
|
|
1377
1430
|
duration,
|
|
1378
1431
|
});
|
|
1432
|
+
try {
|
|
1433
|
+
TelemetryService.getInstance()?.recordMCPToolCall(toolName, duration, true);
|
|
1434
|
+
}
|
|
1435
|
+
catch {
|
|
1436
|
+
/* telemetry should not break execution */
|
|
1437
|
+
}
|
|
1379
1438
|
return result.data;
|
|
1380
1439
|
}
|
|
1381
1440
|
else {
|
|
@@ -1384,6 +1443,13 @@ export class ExternalServerManager extends EventEmitter {
|
|
|
1384
1443
|
}
|
|
1385
1444
|
catch (error) {
|
|
1386
1445
|
instance.metrics.totalErrors++;
|
|
1446
|
+
try {
|
|
1447
|
+
const errorDuration = Date.now() - startTime;
|
|
1448
|
+
TelemetryService.getInstance()?.recordMCPToolCall(toolName, errorDuration, false);
|
|
1449
|
+
}
|
|
1450
|
+
catch {
|
|
1451
|
+
/* telemetry should not break execution */
|
|
1452
|
+
}
|
|
1387
1453
|
mcpLogger.error(`[ExternalServerManager] Tool execution failed: ${toolName} on ${serverId}`, error);
|
|
1388
1454
|
throw error;
|
|
1389
1455
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Provides fault tolerance and prevents cascading failures
|
|
5
5
|
*/
|
|
6
6
|
import { EventEmitter } from "events";
|
|
7
|
+
import { trace } from "@opentelemetry/api";
|
|
7
8
|
import { mcpLogger } from "../utils/logger.js";
|
|
8
9
|
/**
|
|
9
10
|
* MCPCircuitBreaker
|
|
@@ -53,6 +54,17 @@ export class MCPCircuitBreaker extends EventEmitter {
|
|
|
53
54
|
this.halfOpenCalls >= this.config.halfOpenMaxCalls) {
|
|
54
55
|
throw new Error(`Circuit breaker '${this.name}' is half-open but call limit reached`);
|
|
55
56
|
}
|
|
57
|
+
// NLK-GAP-009: Record half-open test event when executing in half-open state
|
|
58
|
+
if (this.state === "half-open") {
|
|
59
|
+
const activeSpan = trace.getActiveSpan();
|
|
60
|
+
if (activeSpan) {
|
|
61
|
+
activeSpan.addEvent("circuit.half_open_test", {
|
|
62
|
+
"circuit.name": this.name,
|
|
63
|
+
"circuit.half_open_call": this.halfOpenCalls + 1,
|
|
64
|
+
"circuit.half_open_max_calls": this.config.halfOpenMaxCalls,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
56
68
|
// Execute operation with timeout
|
|
57
69
|
const result = await Promise.race([
|
|
58
70
|
operation(),
|
|
@@ -145,6 +157,18 @@ export class MCPCircuitBreaker extends EventEmitter {
|
|
|
145
157
|
const oldState = this.state;
|
|
146
158
|
this.state = newState;
|
|
147
159
|
this.lastStateChange = new Date();
|
|
160
|
+
// NLK-GAP-009: Record state transition on active OTel span
|
|
161
|
+
const activeSpan = trace.getActiveSpan();
|
|
162
|
+
if (activeSpan) {
|
|
163
|
+
activeSpan.addEvent("circuit.state_change", {
|
|
164
|
+
"circuit.name": this.name,
|
|
165
|
+
"circuit.from_state": oldState,
|
|
166
|
+
"circuit.to_state": newState,
|
|
167
|
+
"circuit.reason": reason.slice(0, 128),
|
|
168
|
+
"circuit.failure_count": this.callHistory.filter((c) => !c.success)
|
|
169
|
+
.length,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
148
172
|
// Reset counters based on state
|
|
149
173
|
if (newState === "half-open") {
|
|
150
174
|
this.halfOpenCalls = 0;
|
|
@@ -15,6 +15,8 @@ import { globalCircuitBreakerManager } from "./mcpCircuitBreaker.js";
|
|
|
15
15
|
import { withHTTPRetry, DEFAULT_HTTP_RETRY_CONFIG, } from "./httpRetryHandler.js";
|
|
16
16
|
import { globalRateLimiterManager } from "./httpRateLimiter.js";
|
|
17
17
|
import { NeuroLinkOAuthProvider, InMemoryTokenStorage } from "./auth/index.js";
|
|
18
|
+
import { tracers } from "../telemetry/tracers.js";
|
|
19
|
+
import { SpanStatusCode } from "@opentelemetry/api";
|
|
18
20
|
/**
|
|
19
21
|
* MCPClientFactory
|
|
20
22
|
* Factory class for creating MCP clients with different transports
|
|
@@ -36,6 +38,13 @@ export class MCPClientFactory {
|
|
|
36
38
|
*/
|
|
37
39
|
static async createClient(config, timeout = 10000) {
|
|
38
40
|
const startTime = Date.now();
|
|
41
|
+
const span = tracers.mcp.startSpan("neurolink.mcp.client.create", {
|
|
42
|
+
attributes: {
|
|
43
|
+
"mcp.server_id": config.id,
|
|
44
|
+
"mcp.transport": config.transport,
|
|
45
|
+
"mcp.timeout_ms": timeout,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
39
48
|
try {
|
|
40
49
|
mcpLogger.info(`[MCPClientFactory] Creating client for ${config.id}`, {
|
|
41
50
|
transport: config.transport,
|
|
@@ -94,6 +103,7 @@ export class MCPClientFactory {
|
|
|
94
103
|
duration: Date.now() - startTime,
|
|
95
104
|
capabilities: result.capabilities,
|
|
96
105
|
});
|
|
106
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
97
107
|
return {
|
|
98
108
|
...result,
|
|
99
109
|
success: true,
|
|
@@ -103,12 +113,18 @@ export class MCPClientFactory {
|
|
|
103
113
|
catch (error) {
|
|
104
114
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
105
115
|
mcpLogger.error(`[MCPClientFactory] Failed to create client for ${config.id}:`, error);
|
|
116
|
+
// NLK-GAP-004 fix: Record both exception AND error status on span
|
|
117
|
+
span.recordException(error instanceof Error ? error : new Error(errorMessage));
|
|
118
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage });
|
|
106
119
|
return {
|
|
107
120
|
success: false,
|
|
108
121
|
error: errorMessage,
|
|
109
122
|
duration: Date.now() - startTime,
|
|
110
123
|
};
|
|
111
124
|
}
|
|
125
|
+
finally {
|
|
126
|
+
span.end();
|
|
127
|
+
}
|
|
112
128
|
}
|
|
113
129
|
/**
|
|
114
130
|
* Internal client creation logic
|
|
@@ -8,6 +8,10 @@ import { mcpLogger } from "../utils/logger.js";
|
|
|
8
8
|
import { globalCircuitBreakerManager } from "./mcpCircuitBreaker.js";
|
|
9
9
|
import { isObject, isNullish } from "../utils/typeUtils.js";
|
|
10
10
|
import { validateToolName, validateToolDescription, } from "../utils/parameterValidation.js";
|
|
11
|
+
import { withTimeout } from "../utils/errorHandling.js";
|
|
12
|
+
import { SpanKind, SpanStatusCode } from "@opentelemetry/api";
|
|
13
|
+
import { tracers } from "../telemetry/tracers.js";
|
|
14
|
+
const mcpTracer = tracers.mcp;
|
|
11
15
|
/**
|
|
12
16
|
* ToolDiscoveryService
|
|
13
17
|
* Handles automatic tool discovery and registration from external MCP servers
|
|
@@ -336,13 +340,35 @@ export class ToolDiscoveryService extends EventEmitter {
|
|
|
336
340
|
});
|
|
337
341
|
// Execute tool with circuit breaker protection
|
|
338
342
|
const result = await circuitBreaker.execute(async () => {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
+
return mcpTracer.startActiveSpan("neurolink.mcp.callTool", {
|
|
344
|
+
kind: SpanKind.CLIENT,
|
|
345
|
+
attributes: {
|
|
346
|
+
"mcp.server_id": serverId,
|
|
347
|
+
"mcp.tool_name": toolName,
|
|
348
|
+
"mcp.timeout_ms": options.timeout || 30000,
|
|
349
|
+
},
|
|
350
|
+
}, async (callSpan) => {
|
|
351
|
+
try {
|
|
352
|
+
const timeout = options.timeout || 30000;
|
|
353
|
+
const callResult = await withTimeout(client.callTool({
|
|
354
|
+
name: toolName,
|
|
355
|
+
arguments: parameters,
|
|
356
|
+
}), timeout, new Error(`Tool execution timeout: ${toolName}`));
|
|
357
|
+
callSpan.setStatus({ code: SpanStatusCode.OK });
|
|
358
|
+
return callResult;
|
|
359
|
+
}
|
|
360
|
+
catch (err) {
|
|
361
|
+
callSpan.setStatus({
|
|
362
|
+
code: SpanStatusCode.ERROR,
|
|
363
|
+
message: err.message,
|
|
364
|
+
});
|
|
365
|
+
callSpan.recordException(err);
|
|
366
|
+
throw err;
|
|
367
|
+
}
|
|
368
|
+
finally {
|
|
369
|
+
callSpan.end();
|
|
370
|
+
}
|
|
343
371
|
});
|
|
344
|
-
const timeoutPromise = this.createTimeoutPromise(timeout, `Tool execution timeout: ${toolName}`);
|
|
345
|
-
return await Promise.race([executePromise, timeoutPromise]);
|
|
346
372
|
});
|
|
347
373
|
const duration = Date.now() - startTime;
|
|
348
374
|
// Update tool statistics
|