@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
|
@@ -700,6 +700,45 @@ export async function setLangfuseContext(context, callback) {
|
|
|
700
700
|
export function getLangfuseContext() {
|
|
701
701
|
return contextStorage.getStore();
|
|
702
702
|
}
|
|
703
|
+
/**
|
|
704
|
+
* Capture the current Langfuse AsyncLocalStorage context and return a wrapper
|
|
705
|
+
* that re-enters that context when executing the provided callback.
|
|
706
|
+
*
|
|
707
|
+
* This is essential for preserving trace context across async boundaries that
|
|
708
|
+
* break the automatic ALS propagation chain, such as `setImmediate()`,
|
|
709
|
+
* `setTimeout()`, or event-emitter callbacks. Without this, spans created
|
|
710
|
+
* inside those callbacks become orphaned traces in Langfuse.
|
|
711
|
+
*
|
|
712
|
+
* **How it works:**
|
|
713
|
+
* 1. Captures the current ALS store at call time (synchronously).
|
|
714
|
+
* 2. Returns an async function that, when invoked, re-enters the captured
|
|
715
|
+
* context via `contextStorage.run()` before executing the callback.
|
|
716
|
+
* 3. If no context exists at capture time, the callback runs without
|
|
717
|
+
* ALS wrapping (no-op passthrough).
|
|
718
|
+
*
|
|
719
|
+
* @param fn - The async function to execute within the captured context
|
|
720
|
+
* @returns A new async function that preserves the Langfuse ALS context
|
|
721
|
+
*
|
|
722
|
+
* @example
|
|
723
|
+
* // Before (broken — setImmediate loses ALS context):
|
|
724
|
+
* setImmediate(async () => {
|
|
725
|
+
* await this.checkAndSummarize(session, threshold);
|
|
726
|
+
* });
|
|
727
|
+
*
|
|
728
|
+
* // After (fixed — context is captured and re-entered):
|
|
729
|
+
* const wrappedFn = runWithCurrentLangfuseContext(async () => {
|
|
730
|
+
* await this.checkAndSummarize(session, threshold);
|
|
731
|
+
* });
|
|
732
|
+
* setImmediate(wrappedFn);
|
|
733
|
+
*/
|
|
734
|
+
export function runWithCurrentLangfuseContext(fn) {
|
|
735
|
+
const capturedContext = contextStorage.getStore();
|
|
736
|
+
if (capturedContext) {
|
|
737
|
+
return () => contextStorage.run(capturedContext, fn);
|
|
738
|
+
}
|
|
739
|
+
// No context to preserve — return the function as-is
|
|
740
|
+
return fn;
|
|
741
|
+
}
|
|
703
742
|
/**
|
|
704
743
|
* Get an OpenTelemetry Tracer for creating custom spans
|
|
705
744
|
*
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export declare const ATTR: {
|
|
2
|
+
readonly GEN_AI_SYSTEM: "gen_ai.system";
|
|
3
|
+
readonly GEN_AI_MODEL: "gen_ai.request.model";
|
|
4
|
+
readonly GEN_AI_OPERATION: "gen_ai.operation.name";
|
|
5
|
+
readonly GEN_AI_INPUT_TOKENS: "gen_ai.usage.input_tokens";
|
|
6
|
+
readonly GEN_AI_OUTPUT_TOKENS: "gen_ai.usage.output_tokens";
|
|
7
|
+
readonly GEN_AI_FINISH_REASON: "gen_ai.response.finish_reason";
|
|
8
|
+
readonly GEN_AI_COST_USD: "gen_ai.cost_usd";
|
|
9
|
+
readonly GEN_AI_TOOL_NAME: "gen_ai.tool.name";
|
|
10
|
+
readonly GEN_AI_TEMPERATURE: "gen_ai.request.temperature";
|
|
11
|
+
readonly GEN_AI_MAX_TOKENS: "gen_ai.request.max_tokens";
|
|
12
|
+
readonly NL_PROVIDER: "neurolink.provider";
|
|
13
|
+
readonly NL_MODEL: "neurolink.model";
|
|
14
|
+
readonly NL_STREAM_MODE: "neurolink.stream_mode";
|
|
15
|
+
readonly NL_TOOL_COUNT: "neurolink.tool_count";
|
|
16
|
+
readonly NL_MESSAGE_COUNT: "neurolink.message_count";
|
|
17
|
+
readonly NL_HAS_TOOLS: "neurolink.has_tools";
|
|
18
|
+
readonly NL_INPUT_LENGTH: "neurolink.input_length";
|
|
19
|
+
readonly NL_OUTPUT_LENGTH: "neurolink.output_length";
|
|
20
|
+
readonly NL_REQUEST_ID: "neurolink.request_id";
|
|
21
|
+
readonly NL_PATH: "neurolink.path";
|
|
22
|
+
readonly NL_HAS_MEMORY: "neurolink.has_conversation_memory";
|
|
23
|
+
readonly NL_COST: "neurolink.cost";
|
|
24
|
+
readonly NL_STRUCTURED_OUTPUT: "neurolink.structured_output";
|
|
25
|
+
readonly NL_HAS_FALLBACK: "neurolink.has_fallback";
|
|
26
|
+
readonly MCP_SERVER_ID: "mcp.server_id";
|
|
27
|
+
readonly MCP_TOOL_NAME: "mcp.tool_name";
|
|
28
|
+
readonly MCP_TIMEOUT_MS: "mcp.timeout_ms";
|
|
29
|
+
readonly MCP_TRANSPORT: "mcp.transport";
|
|
30
|
+
readonly MCP_CIRCUIT_STATE: "mcp.circuit_state";
|
|
31
|
+
readonly SESSION_ID: "session.id";
|
|
32
|
+
readonly USER_ID: "user.id";
|
|
33
|
+
readonly MEMORY_TYPE: "memory.type";
|
|
34
|
+
readonly MESSAGE_COUNT: "message.count";
|
|
35
|
+
readonly CONTENT_LENGTH: "content.length";
|
|
36
|
+
readonly RAG_FILE_COUNT: "rag.file_count";
|
|
37
|
+
readonly RAG_STRATEGY: "rag.strategy";
|
|
38
|
+
readonly RAG_CHUNK_SIZE: "rag.chunk_size";
|
|
39
|
+
readonly RAG_TOP_K: "rag.top_k";
|
|
40
|
+
readonly RAG_RESULT_COUNT: "rag.result_count";
|
|
41
|
+
readonly MSG_COUNT: "message.build.count";
|
|
42
|
+
readonly MSG_HAS_IMAGES: "message.has_images";
|
|
43
|
+
readonly MSG_HAS_FILES: "message.has_files";
|
|
44
|
+
readonly MSG_HAS_SYSTEM_PROMPT: "message.has_system_prompt";
|
|
45
|
+
readonly MSG_TOTAL_CONTENT_LENGTH: "message.total_content_length";
|
|
46
|
+
readonly MSG_IS_MULTIMODAL: "message.is_multimodal";
|
|
47
|
+
readonly CONTEXT_STAGE: "context.compaction_stage";
|
|
48
|
+
readonly CONTEXT_TOKENS_BEFORE: "context.tokens_before";
|
|
49
|
+
readonly CONTEXT_TOKENS_AFTER: "context.tokens_after";
|
|
50
|
+
readonly MW_COUNT: "middleware.count";
|
|
51
|
+
readonly MW_NAMES: "middleware.names";
|
|
52
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export const ATTR = {
|
|
2
|
+
// GenAI standard (OpenTelemetry semantic conventions)
|
|
3
|
+
GEN_AI_SYSTEM: "gen_ai.system",
|
|
4
|
+
GEN_AI_MODEL: "gen_ai.request.model",
|
|
5
|
+
GEN_AI_OPERATION: "gen_ai.operation.name",
|
|
6
|
+
GEN_AI_INPUT_TOKENS: "gen_ai.usage.input_tokens",
|
|
7
|
+
GEN_AI_OUTPUT_TOKENS: "gen_ai.usage.output_tokens",
|
|
8
|
+
GEN_AI_FINISH_REASON: "gen_ai.response.finish_reason",
|
|
9
|
+
GEN_AI_COST_USD: "gen_ai.cost_usd",
|
|
10
|
+
GEN_AI_TOOL_NAME: "gen_ai.tool.name",
|
|
11
|
+
GEN_AI_TEMPERATURE: "gen_ai.request.temperature",
|
|
12
|
+
GEN_AI_MAX_TOKENS: "gen_ai.request.max_tokens",
|
|
13
|
+
// NeuroLink custom
|
|
14
|
+
NL_PROVIDER: "neurolink.provider",
|
|
15
|
+
NL_MODEL: "neurolink.model",
|
|
16
|
+
NL_STREAM_MODE: "neurolink.stream_mode",
|
|
17
|
+
NL_TOOL_COUNT: "neurolink.tool_count",
|
|
18
|
+
NL_MESSAGE_COUNT: "neurolink.message_count",
|
|
19
|
+
NL_HAS_TOOLS: "neurolink.has_tools",
|
|
20
|
+
NL_INPUT_LENGTH: "neurolink.input_length",
|
|
21
|
+
NL_OUTPUT_LENGTH: "neurolink.output_length",
|
|
22
|
+
NL_REQUEST_ID: "neurolink.request_id",
|
|
23
|
+
NL_PATH: "neurolink.path",
|
|
24
|
+
NL_HAS_MEMORY: "neurolink.has_conversation_memory",
|
|
25
|
+
NL_COST: "neurolink.cost",
|
|
26
|
+
NL_STRUCTURED_OUTPUT: "neurolink.structured_output",
|
|
27
|
+
NL_HAS_FALLBACK: "neurolink.has_fallback",
|
|
28
|
+
// MCP
|
|
29
|
+
MCP_SERVER_ID: "mcp.server_id",
|
|
30
|
+
MCP_TOOL_NAME: "mcp.tool_name",
|
|
31
|
+
MCP_TIMEOUT_MS: "mcp.timeout_ms",
|
|
32
|
+
MCP_TRANSPORT: "mcp.transport",
|
|
33
|
+
MCP_CIRCUIT_STATE: "mcp.circuit_state",
|
|
34
|
+
// Session/Memory
|
|
35
|
+
SESSION_ID: "session.id",
|
|
36
|
+
USER_ID: "user.id",
|
|
37
|
+
MEMORY_TYPE: "memory.type",
|
|
38
|
+
MESSAGE_COUNT: "message.count",
|
|
39
|
+
CONTENT_LENGTH: "content.length",
|
|
40
|
+
// RAG
|
|
41
|
+
RAG_FILE_COUNT: "rag.file_count",
|
|
42
|
+
RAG_STRATEGY: "rag.strategy",
|
|
43
|
+
RAG_CHUNK_SIZE: "rag.chunk_size",
|
|
44
|
+
RAG_TOP_K: "rag.top_k",
|
|
45
|
+
RAG_RESULT_COUNT: "rag.result_count",
|
|
46
|
+
// Message building
|
|
47
|
+
MSG_COUNT: "message.build.count",
|
|
48
|
+
MSG_HAS_IMAGES: "message.has_images",
|
|
49
|
+
MSG_HAS_FILES: "message.has_files",
|
|
50
|
+
MSG_HAS_SYSTEM_PROMPT: "message.has_system_prompt",
|
|
51
|
+
MSG_TOTAL_CONTENT_LENGTH: "message.total_content_length",
|
|
52
|
+
MSG_IS_MULTIMODAL: "message.is_multimodal",
|
|
53
|
+
// Context
|
|
54
|
+
CONTEXT_STAGE: "context.compaction_stage",
|
|
55
|
+
CONTEXT_TOKENS_BEFORE: "context.tokens_before",
|
|
56
|
+
CONTEXT_TOKENS_AFTER: "context.tokens_after",
|
|
57
|
+
// Middleware
|
|
58
|
+
MW_COUNT: "middleware.count",
|
|
59
|
+
MW_NAMES: "middleware.names",
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=attributes.js.map
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export { TelemetryService, type HealthMetrics } from "./telemetryService.js";
|
|
2
|
+
export { tracers } from "./tracers.js";
|
|
3
|
+
export { withSpan, withClientSpan, type SpanOptions } from "./withSpan.js";
|
|
4
|
+
export { ATTR } from "./attributes.js";
|
|
2
5
|
/**
|
|
3
6
|
* Initialize telemetry for NeuroLink
|
|
4
7
|
* OPTIONAL - Only works when NEUROLINK_TELEMETRY_ENABLED=true
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// Optional Telemetry Infrastructure (Phase 2)
|
|
2
2
|
export { TelemetryService } from "./telemetryService.js";
|
|
3
|
+
export { tracers } from "./tracers.js";
|
|
4
|
+
export { withSpan, withClientSpan } from "./withSpan.js";
|
|
5
|
+
export { ATTR } from "./attributes.js";
|
|
3
6
|
import { logger } from "../utils/logger.js";
|
|
4
7
|
/**
|
|
5
8
|
* Initialize telemetry for NeuroLink
|
|
@@ -32,6 +32,12 @@ export declare class TelemetryService {
|
|
|
32
32
|
private initializeTelemetry;
|
|
33
33
|
private initializeMetrics;
|
|
34
34
|
initialize(): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated Vercel AI SDK's experimental_telemetry creates ai.generateText/ai.streamText
|
|
37
|
+
* spans automatically via OpenTelemetry. Using this method would create duplicate spans.
|
|
38
|
+
* Kept for potential future use with non-Vercel providers (e.g., Amazon Bedrock).
|
|
39
|
+
* See: TelemetryHandler.getTelemetryConfig() for the active telemetry path.
|
|
40
|
+
*/
|
|
35
41
|
traceAIRequest<T>(provider: string, operation: () => Promise<T>, operationType?: string): Promise<T>;
|
|
36
42
|
recordAIRequest(provider: string, model: string, tokens: number, duration: number, cost?: number): void;
|
|
37
43
|
recordAIError(provider: string, error: Error): void;
|
|
@@ -112,6 +112,12 @@ export class TelemetryService {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
// AI Operation Tracing (NO-OP when disabled)
|
|
115
|
+
/**
|
|
116
|
+
* @deprecated Vercel AI SDK's experimental_telemetry creates ai.generateText/ai.streamText
|
|
117
|
+
* spans automatically via OpenTelemetry. Using this method would create duplicate spans.
|
|
118
|
+
* Kept for potential future use with non-Vercel providers (e.g., Amazon Bedrock).
|
|
119
|
+
* See: TelemetryHandler.getTelemetryConfig() for the active telemetry path.
|
|
120
|
+
*/
|
|
115
121
|
async traceAIRequest(provider, operation, operationType = "generate_text") {
|
|
116
122
|
if (!this.enabled || !this.tracer) {
|
|
117
123
|
return await operation();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const tracers: {
|
|
2
|
+
readonly sdk: import("@opentelemetry/api").Tracer;
|
|
3
|
+
readonly provider: import("@opentelemetry/api").Tracer;
|
|
4
|
+
readonly generation: import("@opentelemetry/api").Tracer;
|
|
5
|
+
readonly stream: import("@opentelemetry/api").Tracer;
|
|
6
|
+
readonly http: import("@opentelemetry/api").Tracer;
|
|
7
|
+
readonly mcp: import("@opentelemetry/api").Tracer;
|
|
8
|
+
readonly memory: import("@opentelemetry/api").Tracer;
|
|
9
|
+
readonly redis: import("@opentelemetry/api").Tracer;
|
|
10
|
+
readonly factory: import("@opentelemetry/api").Tracer;
|
|
11
|
+
readonly rag: import("@opentelemetry/api").Tracer;
|
|
12
|
+
readonly context: import("@opentelemetry/api").Tracer;
|
|
13
|
+
readonly middleware: import("@opentelemetry/api").Tracer;
|
|
14
|
+
readonly processor: import("@opentelemetry/api").Tracer;
|
|
15
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { trace } from "@opentelemetry/api";
|
|
2
|
+
export const tracers = {
|
|
3
|
+
sdk: trace.getTracer("neurolink"),
|
|
4
|
+
provider: trace.getTracer("neurolink.provider"),
|
|
5
|
+
generation: trace.getTracer("neurolink.generation"),
|
|
6
|
+
stream: trace.getTracer("neurolink.stream"),
|
|
7
|
+
http: trace.getTracer("neurolink.http"),
|
|
8
|
+
mcp: trace.getTracer("neurolink.mcp"),
|
|
9
|
+
memory: trace.getTracer("neurolink.memory"),
|
|
10
|
+
redis: trace.getTracer("neurolink.redis"),
|
|
11
|
+
factory: trace.getTracer("neurolink.factory"),
|
|
12
|
+
rag: trace.getTracer("neurolink.rag"),
|
|
13
|
+
context: trace.getTracer("neurolink.context"),
|
|
14
|
+
middleware: trace.getTracer("neurolink.middleware"),
|
|
15
|
+
processor: trace.getTracer("neurolink.processor"),
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=tracers.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Span, type Tracer, SpanKind } from "@opentelemetry/api";
|
|
2
|
+
export type SpanOptions = {
|
|
3
|
+
name: string;
|
|
4
|
+
tracer: Tracer;
|
|
5
|
+
kind?: SpanKind;
|
|
6
|
+
attributes?: Record<string, string | number | boolean | undefined>;
|
|
7
|
+
};
|
|
8
|
+
export declare function withSpan<T>(options: SpanOptions, fn: (span: Span) => Promise<T>): Promise<T>;
|
|
9
|
+
export declare function withClientSpan<T>(options: Omit<SpanOptions, "kind">, fn: (span: Span) => Promise<T>): Promise<T>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SpanKind, SpanStatusCode, } from "@opentelemetry/api";
|
|
2
|
+
export async function withSpan(options, fn) {
|
|
3
|
+
const { name, tracer, kind = SpanKind.INTERNAL, attributes } = options;
|
|
4
|
+
return tracer.startActiveSpan(name, { kind }, async (span) => {
|
|
5
|
+
if (attributes) {
|
|
6
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
7
|
+
if (value !== undefined) {
|
|
8
|
+
span.setAttribute(key, value);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const result = await fn(span);
|
|
14
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
span.setStatus({
|
|
19
|
+
code: SpanStatusCode.ERROR,
|
|
20
|
+
message: error instanceof Error ? error.message : String(error),
|
|
21
|
+
});
|
|
22
|
+
if (error instanceof Error) {
|
|
23
|
+
span.recordException(error);
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
span.end();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export async function withClientSpan(options, fn) {
|
|
33
|
+
return withSpan({ ...options, kind: SpanKind.CLIENT }, fn);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=withSpan.js.map
|
|
@@ -424,6 +424,16 @@ export type PruneResult = {
|
|
|
424
424
|
/** Configuration for sliding window truncation (Stage 4). */
|
|
425
425
|
export type TruncationConfig = {
|
|
426
426
|
fraction?: number;
|
|
427
|
+
/** Current estimated tokens (enables adaptive mode) */
|
|
428
|
+
currentTokens?: number;
|
|
429
|
+
/** Target token budget (enables adaptive mode) */
|
|
430
|
+
targetTokens?: number;
|
|
431
|
+
/** Provider for token estimation (enables adaptive mode) */
|
|
432
|
+
provider?: string;
|
|
433
|
+
/** Buffer above required reduction (default: 0.15 = 15%) */
|
|
434
|
+
adaptiveBuffer?: number;
|
|
435
|
+
/** Maximum iterations for adaptive truncation (default: 3) */
|
|
436
|
+
maxIterations?: number;
|
|
427
437
|
};
|
|
428
438
|
/** Result of sliding window truncation (Stage 4). */
|
|
429
439
|
export type TruncationResult = {
|
|
@@ -364,6 +364,20 @@ export type StreamOptions = {
|
|
|
364
364
|
workflow?: string;
|
|
365
365
|
workflowConfig?: import("../workflow/types.js").WorkflowConfig;
|
|
366
366
|
enableSummarization?: boolean;
|
|
367
|
+
/**
|
|
368
|
+
* Maximum cumulative cost (USD) for this session.
|
|
369
|
+
* Once the session spend reaches this limit, subsequent stream() calls
|
|
370
|
+
* will throw a SESSION_BUDGET_EXCEEDED error instead of making API calls.
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```typescript
|
|
374
|
+
* const result = await neurolink.stream({
|
|
375
|
+
* input: { text: "Summarize this" },
|
|
376
|
+
* maxBudgetUsd: 1.00
|
|
377
|
+
* });
|
|
378
|
+
* ```
|
|
379
|
+
*/
|
|
380
|
+
maxBudgetUsd?: number;
|
|
367
381
|
/**
|
|
368
382
|
* RAG (Retrieval-Augmented Generation) configuration.
|
|
369
383
|
*
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
* Conversation Memory Utilities
|
|
3
3
|
* Handles configuration merging and conversation memory operations
|
|
4
4
|
*/
|
|
5
|
+
import { SpanKind, SpanStatusCode } from "@opentelemetry/api";
|
|
6
|
+
import { tracers } from "../telemetry/tracers.js";
|
|
7
|
+
import { withTimeout } from "./errorHandling.js";
|
|
5
8
|
import { DEFAULT_FALLBACK_THRESHOLD, getConversationMemoryDefaults, MEMORY_THRESHOLD_PERCENTAGE, } from "../config/conversationMemory.js";
|
|
6
9
|
import { getAvailableInputTokens } from "../constants/contextWindows.js";
|
|
7
10
|
import { buildSummarizationPrompt } from "../context/prompts/summarizationPrompt.js";
|
|
8
|
-
import { NeuroLink } from "../neurolink.js";
|
|
9
11
|
import { logger } from "./logger.js";
|
|
12
|
+
const memoryTracer = tracers.memory;
|
|
13
|
+
// Cached NeuroLink instance for summarization to avoid creating a new instance per call
|
|
14
|
+
let cachedSummarizer = null;
|
|
10
15
|
/**
|
|
11
16
|
* Apply conversation memory defaults to user configuration
|
|
12
17
|
* Merges user config with environment variables and default values
|
|
@@ -34,41 +39,49 @@ export async function getConversationMessages(conversationMemory, options) {
|
|
|
34
39
|
});
|
|
35
40
|
return [];
|
|
36
41
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
error
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
42
|
+
return memoryTracer.startActiveSpan("neurolink.conversation.getMessages", {
|
|
43
|
+
kind: SpanKind.INTERNAL,
|
|
44
|
+
attributes: {
|
|
45
|
+
"session.id": sessionId,
|
|
46
|
+
"memory.type": conversationMemory.constructor.name,
|
|
47
|
+
},
|
|
48
|
+
}, async (span) => {
|
|
49
|
+
try {
|
|
50
|
+
// Extract userId from context
|
|
51
|
+
const userId = options.context?.userId;
|
|
52
|
+
if (userId) {
|
|
53
|
+
span.setAttribute("user.id", userId);
|
|
54
|
+
}
|
|
55
|
+
const enableSummarization = options.enableSummarization ?? undefined;
|
|
56
|
+
const messages = await conversationMemory.buildContextMessages(sessionId, userId, enableSummarization);
|
|
57
|
+
span.setAttribute("message.count", messages.length);
|
|
58
|
+
if (logger.shouldLog("debug")) {
|
|
59
|
+
logger.debug("[conversationMemoryUtils] Conversation messages retrieved successfully", {
|
|
60
|
+
sessionId,
|
|
61
|
+
messageCount: messages.length,
|
|
62
|
+
messageTypes: messages.map((m) => m.role),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return messages;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
span.setStatus({
|
|
69
|
+
code: SpanStatusCode.ERROR,
|
|
70
|
+
message: error instanceof Error ? error.message : String(error),
|
|
71
|
+
});
|
|
72
|
+
span.recordException(error instanceof Error ? error : new Error(String(error)));
|
|
73
|
+
logger.warn("[conversationMemoryUtils] Failed to get conversation messages", {
|
|
74
|
+
sessionId,
|
|
75
|
+
memoryType: conversationMemory.constructor.name,
|
|
76
|
+
error: error instanceof Error ? error.message : String(error),
|
|
77
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
78
|
+
});
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
span.end();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
72
85
|
}
|
|
73
86
|
/**
|
|
74
87
|
* Store conversation turn for future context
|
|
@@ -128,47 +141,66 @@ export async function storeConversationTurn(conversationMemory, originalOptions,
|
|
|
128
141
|
model: result.model,
|
|
129
142
|
};
|
|
130
143
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
userMessage,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
:
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
144
|
+
await memoryTracer.startActiveSpan("neurolink.conversation.storeTurn", {
|
|
145
|
+
kind: SpanKind.INTERNAL,
|
|
146
|
+
attributes: {
|
|
147
|
+
"session.id": sessionId,
|
|
148
|
+
"content.length": userMessage.length + aiResponse.length,
|
|
149
|
+
},
|
|
150
|
+
}, async (span) => {
|
|
151
|
+
if (userId) {
|
|
152
|
+
span.setAttribute("user.id", userId);
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
await conversationMemory.storeConversationTurn({
|
|
156
|
+
sessionId,
|
|
157
|
+
userId,
|
|
158
|
+
userMessage,
|
|
159
|
+
aiResponse,
|
|
160
|
+
startTimeStamp,
|
|
161
|
+
providerDetails,
|
|
162
|
+
enableSummarization: originalOptions.enableSummarization,
|
|
163
|
+
requestId,
|
|
164
|
+
tokenUsage: result.usage
|
|
165
|
+
? {
|
|
166
|
+
inputTokens: result.usage.input,
|
|
167
|
+
outputTokens: result.usage.output,
|
|
168
|
+
totalTokens: result.usage.total,
|
|
169
|
+
cacheReadTokens: result.usage.cacheReadTokens,
|
|
170
|
+
cacheWriteTokens: result.usage.cacheCreationTokens,
|
|
171
|
+
}
|
|
172
|
+
: undefined,
|
|
173
|
+
});
|
|
174
|
+
logger.debug("[conversationMemoryUtils] Conversation turn stored successfully", {
|
|
175
|
+
requestId,
|
|
176
|
+
sessionId,
|
|
177
|
+
userId,
|
|
178
|
+
memoryType: conversationMemory.constructor.name,
|
|
179
|
+
userMessageLength: userMessage.length,
|
|
180
|
+
aiResponseLength: aiResponse.length,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
span.setStatus({
|
|
185
|
+
code: SpanStatusCode.ERROR,
|
|
186
|
+
message: error instanceof Error ? error.message : String(error),
|
|
187
|
+
});
|
|
188
|
+
span.recordException(error instanceof Error ? error : new Error(String(error)));
|
|
189
|
+
const details = error?.details;
|
|
190
|
+
logger.warn("[conversationMemoryUtils] Failed to store conversation turn", {
|
|
191
|
+
sessionId,
|
|
192
|
+
userId,
|
|
193
|
+
memoryType: conversationMemory.constructor.name,
|
|
194
|
+
error: error instanceof Error ? error.message : String(error),
|
|
195
|
+
innerError: details?.error || "none",
|
|
196
|
+
errorCode: error?.code || "unknown",
|
|
197
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
span.end();
|
|
202
|
+
}
|
|
203
|
+
});
|
|
172
204
|
}
|
|
173
205
|
/**
|
|
174
206
|
* Build context messages from pointer onwards (token-based memory)
|
|
@@ -322,22 +354,29 @@ export function getEffectiveTokenThreshold(provider, model, envOverride, session
|
|
|
322
354
|
*/
|
|
323
355
|
export async function generateSummary(messages, config, logPrefix = "[ConversationMemory]", previousSummary, requestId) {
|
|
324
356
|
const summarizationPrompt = createSummarizationPrompt(messages, previousSummary);
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
});
|
|
357
|
+
const SUMMARIZER_INIT_TIMEOUT = 15_000;
|
|
358
|
+
const SUMMARIZER_GENERATE_TIMEOUT = 60_000;
|
|
328
359
|
try {
|
|
360
|
+
if (!cachedSummarizer) {
|
|
361
|
+
cachedSummarizer = await withTimeout((async () => {
|
|
362
|
+
const { NeuroLink: NeuroLinkClass } = await import("../neurolink.js");
|
|
363
|
+
return new NeuroLinkClass({
|
|
364
|
+
conversationMemory: { enabled: false },
|
|
365
|
+
});
|
|
366
|
+
})(), SUMMARIZER_INIT_TIMEOUT, new Error("Summarizer initialization timed out"));
|
|
367
|
+
}
|
|
329
368
|
if (!config.summarizationProvider || !config.summarizationModel) {
|
|
330
369
|
logger.error(`${logPrefix} Missing summarization provider`, {
|
|
331
370
|
requestId,
|
|
332
371
|
});
|
|
333
372
|
return null;
|
|
334
373
|
}
|
|
335
|
-
const summaryResult = await
|
|
374
|
+
const summaryResult = await withTimeout(cachedSummarizer.generate({
|
|
336
375
|
input: { text: summarizationPrompt },
|
|
337
376
|
provider: config.summarizationProvider,
|
|
338
377
|
model: config.summarizationModel,
|
|
339
378
|
disableTools: true,
|
|
340
|
-
});
|
|
379
|
+
}), SUMMARIZER_GENERATE_TIMEOUT, new Error("Summary generation timed out"));
|
|
341
380
|
return summaryResult.content || null;
|
|
342
381
|
}
|
|
343
382
|
catch (error) {
|
|
@@ -63,6 +63,11 @@ declare class NeuroLinkLogger {
|
|
|
63
63
|
* @returns Formatted prefix string like "[2025-08-18T13:45:30.123Z] [NEUROLINK:ERROR]"
|
|
64
64
|
*/
|
|
65
65
|
private getLogPrefix;
|
|
66
|
+
/**
|
|
67
|
+
* Extracts current OTel trace context (trace_id, span_id) if available.
|
|
68
|
+
* Returns empty object if OTel is not initialized or no active span exists.
|
|
69
|
+
*/
|
|
70
|
+
private getTraceContext;
|
|
66
71
|
/**
|
|
67
72
|
* Safely serialize data to fully expanded JSON string.
|
|
68
73
|
* Handles circular references and non-serializable values.
|