@juspay/neurolink 7.48.1 → 7.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +215 -16
  3. package/dist/agent/directTools.d.ts +55 -0
  4. package/dist/agent/directTools.js +266 -0
  5. package/dist/cli/factories/commandFactory.d.ts +6 -0
  6. package/dist/cli/factories/commandFactory.js +149 -16
  7. package/dist/cli/index.js +13 -2
  8. package/dist/cli/loop/conversationSelector.d.ts +45 -0
  9. package/dist/cli/loop/conversationSelector.js +222 -0
  10. package/dist/cli/loop/optionsSchema.d.ts +1 -1
  11. package/dist/cli/loop/session.d.ts +36 -8
  12. package/dist/cli/loop/session.js +257 -61
  13. package/dist/core/baseProvider.d.ts +9 -0
  14. package/dist/core/baseProvider.js +45 -5
  15. package/dist/core/evaluation.js +5 -2
  16. package/dist/factories/providerRegistry.js +2 -2
  17. package/dist/index.d.ts +8 -2
  18. package/dist/index.js +11 -10
  19. package/dist/lib/agent/directTools.d.ts +55 -0
  20. package/dist/lib/agent/directTools.js +266 -0
  21. package/dist/lib/core/baseProvider.d.ts +9 -0
  22. package/dist/lib/core/baseProvider.js +45 -5
  23. package/dist/lib/core/evaluation.js +5 -2
  24. package/dist/lib/factories/providerRegistry.js +2 -2
  25. package/dist/lib/index.d.ts +8 -2
  26. package/dist/lib/index.js +11 -10
  27. package/dist/lib/mcp/factory.d.ts +2 -157
  28. package/dist/lib/mcp/flexibleToolValidator.d.ts +1 -5
  29. package/dist/lib/mcp/index.d.ts +3 -2
  30. package/dist/lib/mcp/mcpCircuitBreaker.d.ts +1 -75
  31. package/dist/lib/mcp/mcpClientFactory.d.ts +1 -20
  32. package/dist/lib/mcp/mcpClientFactory.js +1 -0
  33. package/dist/lib/mcp/registry.d.ts +3 -10
  34. package/dist/lib/mcp/servers/agent/directToolsServer.d.ts +1 -1
  35. package/dist/lib/mcp/servers/aiProviders/aiCoreServer.d.ts +1 -1
  36. package/dist/lib/mcp/servers/utilities/utilityServer.d.ts +1 -1
  37. package/dist/lib/mcp/toolDiscoveryService.d.ts +3 -84
  38. package/dist/lib/mcp/toolRegistry.d.ts +2 -24
  39. package/dist/lib/middleware/builtin/guardrails.d.ts +5 -16
  40. package/dist/lib/middleware/builtin/guardrails.js +44 -39
  41. package/dist/lib/middleware/utils/guardrailsUtils.d.ts +64 -0
  42. package/dist/lib/middleware/utils/guardrailsUtils.js +387 -0
  43. package/dist/lib/neurolink.d.ts +36 -7
  44. package/dist/lib/neurolink.js +141 -0
  45. package/dist/lib/providers/anthropic.js +47 -3
  46. package/dist/lib/providers/azureOpenai.js +9 -2
  47. package/dist/lib/providers/googleAiStudio.js +9 -2
  48. package/dist/lib/providers/googleVertex.js +12 -2
  49. package/dist/lib/providers/huggingFace.js +1 -1
  50. package/dist/lib/providers/litellm.js +1 -1
  51. package/dist/lib/providers/mistral.js +1 -1
  52. package/dist/lib/providers/openAI.js +47 -3
  53. package/dist/lib/services/server/ai/observability/instrumentation.d.ts +57 -0
  54. package/dist/lib/services/server/ai/observability/instrumentation.js +170 -0
  55. package/dist/lib/session/globalSessionState.d.ts +26 -0
  56. package/dist/lib/session/globalSessionState.js +86 -1
  57. package/dist/lib/telemetry/index.d.ts +1 -0
  58. package/dist/lib/telemetry/telemetryService.d.ts +2 -0
  59. package/dist/lib/telemetry/telemetryService.js +7 -7
  60. package/dist/lib/types/cli.d.ts +28 -0
  61. package/dist/lib/types/content.d.ts +18 -5
  62. package/dist/lib/types/contextTypes.d.ts +1 -1
  63. package/dist/lib/types/conversation.d.ts +57 -4
  64. package/dist/lib/types/fileTypes.d.ts +65 -0
  65. package/dist/lib/types/fileTypes.js +4 -0
  66. package/dist/lib/types/generateTypes.d.ts +12 -0
  67. package/dist/lib/types/guardrails.d.ts +103 -0
  68. package/dist/lib/types/guardrails.js +1 -0
  69. package/dist/lib/types/index.d.ts +4 -2
  70. package/dist/lib/types/index.js +4 -0
  71. package/dist/lib/types/mcpTypes.d.ts +407 -14
  72. package/dist/lib/types/modelTypes.d.ts +6 -6
  73. package/dist/lib/types/observability.d.ts +49 -0
  74. package/dist/lib/types/observability.js +6 -0
  75. package/dist/lib/types/streamTypes.d.ts +7 -0
  76. package/dist/lib/types/tools.d.ts +132 -35
  77. package/dist/lib/utils/csvProcessor.d.ts +68 -0
  78. package/dist/lib/utils/csvProcessor.js +277 -0
  79. package/dist/lib/utils/fileDetector.d.ts +57 -0
  80. package/dist/lib/utils/fileDetector.js +457 -0
  81. package/dist/lib/utils/imageProcessor.d.ts +10 -0
  82. package/dist/lib/utils/imageProcessor.js +22 -0
  83. package/dist/lib/utils/loopUtils.d.ts +71 -0
  84. package/dist/lib/utils/loopUtils.js +262 -0
  85. package/dist/lib/utils/messageBuilder.d.ts +2 -1
  86. package/dist/lib/utils/messageBuilder.js +197 -2
  87. package/dist/lib/utils/optionsUtils.d.ts +1 -1
  88. package/dist/mcp/factory.d.ts +2 -157
  89. package/dist/mcp/flexibleToolValidator.d.ts +1 -5
  90. package/dist/mcp/index.d.ts +3 -2
  91. package/dist/mcp/mcpCircuitBreaker.d.ts +1 -75
  92. package/dist/mcp/mcpClientFactory.d.ts +1 -20
  93. package/dist/mcp/mcpClientFactory.js +1 -0
  94. package/dist/mcp/registry.d.ts +3 -10
  95. package/dist/mcp/servers/agent/directToolsServer.d.ts +1 -1
  96. package/dist/mcp/servers/aiProviders/aiCoreServer.d.ts +1 -1
  97. package/dist/mcp/servers/utilities/utilityServer.d.ts +1 -1
  98. package/dist/mcp/toolDiscoveryService.d.ts +3 -84
  99. package/dist/mcp/toolRegistry.d.ts +2 -24
  100. package/dist/middleware/builtin/guardrails.d.ts +5 -16
  101. package/dist/middleware/builtin/guardrails.js +44 -39
  102. package/dist/middleware/utils/guardrailsUtils.d.ts +64 -0
  103. package/dist/middleware/utils/guardrailsUtils.js +387 -0
  104. package/dist/neurolink.d.ts +36 -7
  105. package/dist/neurolink.js +141 -0
  106. package/dist/providers/anthropic.js +47 -3
  107. package/dist/providers/azureOpenai.js +9 -2
  108. package/dist/providers/googleAiStudio.js +9 -2
  109. package/dist/providers/googleVertex.js +12 -2
  110. package/dist/providers/huggingFace.js +1 -1
  111. package/dist/providers/litellm.js +1 -1
  112. package/dist/providers/mistral.js +1 -1
  113. package/dist/providers/openAI.js +47 -3
  114. package/dist/services/server/ai/observability/instrumentation.d.ts +57 -0
  115. package/dist/services/server/ai/observability/instrumentation.js +170 -0
  116. package/dist/session/globalSessionState.d.ts +26 -0
  117. package/dist/session/globalSessionState.js +86 -1
  118. package/dist/telemetry/index.d.ts +1 -0
  119. package/dist/telemetry/telemetryService.d.ts +2 -0
  120. package/dist/telemetry/telemetryService.js +7 -7
  121. package/dist/types/cli.d.ts +28 -0
  122. package/dist/types/content.d.ts +18 -5
  123. package/dist/types/contextTypes.d.ts +1 -1
  124. package/dist/types/conversation.d.ts +57 -4
  125. package/dist/types/fileTypes.d.ts +65 -0
  126. package/dist/types/fileTypes.js +4 -0
  127. package/dist/types/generateTypes.d.ts +12 -0
  128. package/dist/types/guardrails.d.ts +103 -0
  129. package/dist/types/guardrails.js +1 -0
  130. package/dist/types/index.d.ts +4 -2
  131. package/dist/types/index.js +4 -0
  132. package/dist/types/mcpTypes.d.ts +407 -14
  133. package/dist/types/modelTypes.d.ts +6 -6
  134. package/dist/types/observability.d.ts +49 -0
  135. package/dist/types/observability.js +6 -0
  136. package/dist/types/streamTypes.d.ts +7 -0
  137. package/dist/types/tools.d.ts +132 -35
  138. package/dist/utils/csvProcessor.d.ts +68 -0
  139. package/dist/utils/csvProcessor.js +277 -0
  140. package/dist/utils/fileDetector.d.ts +57 -0
  141. package/dist/utils/fileDetector.js +457 -0
  142. package/dist/utils/imageProcessor.d.ts +10 -0
  143. package/dist/utils/imageProcessor.js +22 -0
  144. package/dist/utils/loopUtils.d.ts +71 -0
  145. package/dist/utils/loopUtils.js +262 -0
  146. package/dist/utils/messageBuilder.d.ts +2 -1
  147. package/dist/utils/messageBuilder.js +197 -2
  148. package/dist/utils/optionsUtils.d.ts +1 -1
  149. package/package.json +18 -16
  150. package/dist/lib/mcp/contracts/mcpContract.d.ts +0 -106
  151. package/dist/lib/mcp/contracts/mcpContract.js +0 -5
  152. package/dist/mcp/contracts/mcpContract.d.ts +0 -106
  153. package/dist/mcp/contracts/mcpContract.js +0 -5
@@ -0,0 +1,64 @@
1
+ import type { PrecallEvaluationResult, PrecallEvaluationConfig, EvaluationActionResult, BadWordsConfig } from "../../types/guardrails.js";
2
+ import type { LanguageModelV1CallOptions } from "ai";
3
+ export declare const DEFAULT_EVALUATION_PROMPT = "\nEvaluate the following user input for safety and appropriateness. Respond ONLY with valid JSON:\n\n{\n \"overall\": \"safe|unsafe|suspicious|inappropriate\",\n \"safetyScore\": <1-10>,\n \"appropriatenessScore\": <1-10>,\n \"confidenceLevel\": <1-10>,\n \"issues\": [\n {\n \"category\": \"explicit_content|hate_speech|violence|personal_info|spam|other\",\n \"severity\": \"low|medium|high|critical\",\n \"description\": \"Brief description\"\n }\n ],\n \"suggestedAction\": \"allow|block|sanitize|warn\",\n \"reasoning\": \"Brief explanation\"\n}\n\nUser Input: \"{USER_INPUT}\"\n";
4
+ /**
5
+ * Extract user input from LanguageModelV1CallOptions
6
+ */
7
+ export declare function extractUserInput(params: LanguageModelV1CallOptions): string;
8
+ export declare function parseEvaluationResponse(rawResponse: string): PrecallEvaluationResult;
9
+ /**
10
+ * Handles the precall guardrails logic, including evaluation and sanitization.
11
+ * @param params - The language model call options.
12
+ * @param config - The precall evaluation configuration.
13
+ * @returns An object indicating if the request should be blocked and the (potentially transformed) params.
14
+ */
15
+ export declare function handlePrecallGuardrails(params: LanguageModelV1CallOptions, config: PrecallEvaluationConfig): Promise<{
16
+ shouldBlock: boolean;
17
+ transformedParams: LanguageModelV1CallOptions;
18
+ }>;
19
+ /**
20
+ * Perform precall evaluation of user input using AI models
21
+ */
22
+ export declare function performPrecallEvaluation(config: PrecallEvaluationConfig, userInput: string): Promise<PrecallEvaluationResult>;
23
+ export declare function applyEvaluationActions(evaluation: PrecallEvaluationResult, config: PrecallEvaluationConfig, userInput: string): EvaluationActionResult;
24
+ /**
25
+ * Apply parameter sanitization to request parameters
26
+ */
27
+ export declare function applySanitization(params: LanguageModelV1CallOptions, sanitizedInput: string): LanguageModelV1CallOptions;
28
+ export declare function escapeRegExp(string: string): string;
29
+ export declare function createBlockedResponse(): {
30
+ text: string;
31
+ usage: {
32
+ promptTokens: number;
33
+ completionTokens: number;
34
+ };
35
+ finishReason: "stop";
36
+ warnings: never[];
37
+ rawCall: {
38
+ rawPrompt: null;
39
+ rawSettings: {};
40
+ };
41
+ };
42
+ export declare function createBlockedStream(): ReadableStream<any>;
43
+ /**
44
+ * Result from content filtering operation
45
+ */
46
+ export interface ContentFilteringResult {
47
+ filteredText: string;
48
+ hasChanges: boolean;
49
+ appliedFilters: string[];
50
+ filteringStats: {
51
+ regexPatternsApplied: number;
52
+ stringFiltersApplied: number;
53
+ totalMatches: number;
54
+ };
55
+ }
56
+ /**
57
+ * Apply content filtering using bad words configuration
58
+ * Handles both regex patterns and string lists with proper priority
59
+ * @param text The text to filter
60
+ * @param badWordsConfig Bad words configuration
61
+ * @param context Optional context for logging (e.g., "generate", "stream")
62
+ * @returns Filtering result with filtered text and metadata
63
+ */
64
+ export declare function applyContentFiltering(text: string, badWordsConfig?: BadWordsConfig, context?: string): ContentFilteringResult;
@@ -0,0 +1,387 @@
1
+ import { AIProviderFactory } from "../../core/factory.js";
2
+ import { logger } from "../../utils/logger.js";
3
+ export const DEFAULT_EVALUATION_PROMPT = `
4
+ Evaluate the following user input for safety and appropriateness. Respond ONLY with valid JSON:
5
+
6
+ {
7
+ "overall": "safe|unsafe|suspicious|inappropriate",
8
+ "safetyScore": <1-10>,
9
+ "appropriatenessScore": <1-10>,
10
+ "confidenceLevel": <1-10>,
11
+ "issues": [
12
+ {
13
+ "category": "explicit_content|hate_speech|violence|personal_info|spam|other",
14
+ "severity": "low|medium|high|critical",
15
+ "description": "Brief description"
16
+ }
17
+ ],
18
+ "suggestedAction": "allow|block|sanitize|warn",
19
+ "reasoning": "Brief explanation"
20
+ }
21
+
22
+ User Input: "{USER_INPUT}"
23
+ `;
24
+ /**
25
+ * Extract user input from LanguageModelV1CallOptions
26
+ */
27
+ export function extractUserInput(params) {
28
+ if (typeof params.prompt === "string") {
29
+ return params.prompt;
30
+ }
31
+ return params.prompt
32
+ .map((msg) => {
33
+ if (msg.role === "user") {
34
+ if (typeof msg.content === "string") {
35
+ return msg.content;
36
+ }
37
+ else if (Array.isArray(msg.content)) {
38
+ return msg.content
39
+ .filter((part) => part.type === "text")
40
+ .map((part) => part.text)
41
+ .join(" ");
42
+ }
43
+ }
44
+ return "";
45
+ })
46
+ .filter(Boolean)
47
+ .join("\n");
48
+ }
49
+ export function parseEvaluationResponse(rawResponse) {
50
+ try {
51
+ const cleanedResponse = rawResponse.replace(/```json\n|```/g, "").trim();
52
+ const parsed = JSON.parse(cleanedResponse);
53
+ return {
54
+ overall: parsed.overall || "safe",
55
+ safetyScore: Number(parsed.safetyScore) || 10,
56
+ appropriatenessScore: Number(parsed.appropriatenessScore) || 10,
57
+ confidenceLevel: Number(parsed.confidenceLevel) || 10,
58
+ issues: parsed.issues || [],
59
+ suggestedAction: parsed.suggestedAction || "allow",
60
+ reasoning: parsed.reasoning || "No reasoning provided.",
61
+ };
62
+ }
63
+ catch (error) {
64
+ logger.error("[GuardrailsUtils] Failed to parse evaluation response:", error);
65
+ return {
66
+ overall: "safe",
67
+ safetyScore: 10,
68
+ appropriatenessScore: 10,
69
+ confidenceLevel: 1,
70
+ suggestedAction: "allow",
71
+ reasoning: "Error parsing evaluation response - allowing by default.",
72
+ };
73
+ }
74
+ }
75
+ /**
76
+ * Handles the precall guardrails logic, including evaluation and sanitization.
77
+ * @param params - The language model call options.
78
+ * @param config - The precall evaluation configuration.
79
+ * @returns An object indicating if the request should be blocked and the (potentially transformed) params.
80
+ */
81
+ export async function handlePrecallGuardrails(params, config) {
82
+ const userInput = extractUserInput(params);
83
+ let transformedParams = params;
84
+ if (userInput.trim()) {
85
+ logger.debug(`[GuardrailsUtils] Performing precall evaluation on user input.`);
86
+ const evaluation = await performPrecallEvaluation(config, userInput);
87
+ const actionResult = applyEvaluationActions(evaluation, config, userInput);
88
+ if (actionResult.shouldBlock) {
89
+ logger.warn(`[GuardrailsUtils] Blocking request due to precall evaluation.`, {
90
+ evaluation,
91
+ userInput: userInput.substring(0, 100),
92
+ });
93
+ return { shouldBlock: true, transformedParams };
94
+ }
95
+ if (actionResult.sanitizedInput) {
96
+ logger.info(`[GuardrailsUtils] Applying input sanitization.`);
97
+ transformedParams = applySanitization(params, actionResult.sanitizedInput);
98
+ }
99
+ }
100
+ else {
101
+ logger.debug(`[GuardrailsUtils] Skipping precall evaluation - no user content to evaluate.`);
102
+ }
103
+ return { shouldBlock: false, transformedParams };
104
+ }
105
+ /**
106
+ * Perform precall evaluation of user input using AI models
107
+ */
108
+ export async function performPrecallEvaluation(config, userInput) {
109
+ try {
110
+ const provider = await AIProviderFactory.createProvider(config.provider || "google-ai", config.evaluationModel || "gemini-1.5-flash");
111
+ const evaluationPrompt = config.evaluationPrompt || DEFAULT_EVALUATION_PROMPT;
112
+ const prompt = evaluationPrompt.replace("{USER_INPUT}", userInput);
113
+ const result = await provider.generate({
114
+ input: { text: prompt },
115
+ });
116
+ if (!result || !result.content) {
117
+ throw new Error("Evaluation generation failed to return a result.");
118
+ }
119
+ return parseEvaluationResponse(result.content);
120
+ }
121
+ catch (error) {
122
+ logger.error("[GuardrailsUtils] Precall evaluation failed:", error);
123
+ return {
124
+ overall: "safe",
125
+ safetyScore: 10,
126
+ appropriatenessScore: 10,
127
+ confidenceLevel: 1,
128
+ suggestedAction: "allow",
129
+ reasoning: "Evaluation failed - allowing by default.",
130
+ };
131
+ }
132
+ }
133
+ export function applyEvaluationActions(evaluation, config, userInput) {
134
+ const actions = config.actions || {};
135
+ const thresholds = config.thresholds || {};
136
+ const safetyThreshold = thresholds.safetyScore || 7;
137
+ const appropriatenessThreshold = thresholds.appropriatenessScore || 6;
138
+ let actionToTake;
139
+ if (evaluation.overall === "unsafe" ||
140
+ evaluation.safetyScore < safetyThreshold) {
141
+ actionToTake = actions.onUnsafe || "block";
142
+ }
143
+ else if (evaluation.overall === "inappropriate" ||
144
+ evaluation.appropriatenessScore < appropriatenessThreshold) {
145
+ actionToTake = actions.onInappropriate || "warn";
146
+ }
147
+ else if (evaluation.overall === "suspicious") {
148
+ actionToTake = actions.onSuspicious || "log";
149
+ }
150
+ else {
151
+ actionToTake = "allow";
152
+ }
153
+ logger.info("[GuardrailsUtils] Precall evaluation result:", {
154
+ overall: evaluation.overall,
155
+ safetyScore: evaluation.safetyScore,
156
+ appropriatenessScore: evaluation.appropriatenessScore,
157
+ confidenceLevel: evaluation.confidenceLevel,
158
+ suggestedAction: evaluation.suggestedAction,
159
+ actionTaken: actionToTake,
160
+ reasoning: evaluation.reasoning,
161
+ issues: evaluation.issues,
162
+ });
163
+ switch (actionToTake) {
164
+ case "block":
165
+ return { shouldBlock: true };
166
+ case "sanitize": {
167
+ let sanitized = userInput;
168
+ const patterns = config.sanitizationPatterns || [];
169
+ const replacementText = config.replacementText || "[REDACTED]";
170
+ if (patterns.length > 0) {
171
+ logger.debug(`[GuardrailsUtils] Applying ${patterns.length} sanitization patterns with replacement: "${replacementText}".`);
172
+ patterns.forEach((pattern, index) => {
173
+ try {
174
+ const regex = new RegExp(pattern, "gi");
175
+ const before = sanitized;
176
+ let matchCount = 0;
177
+ sanitized = sanitized.replace(regex, () => {
178
+ matchCount++;
179
+ return replacementText;
180
+ });
181
+ if (before !== sanitized) {
182
+ logger.debug(`[GuardrailsUtils] Pattern ${index + 1} matched ${matchCount} times.`);
183
+ }
184
+ }
185
+ catch (error) {
186
+ logger.error(`[GuardrailsUtils] Invalid sanitization pattern "${pattern}":`, error);
187
+ }
188
+ });
189
+ if (sanitized !== userInput) {
190
+ logger.info(`[GuardrailsUtils] Input sanitized using ${patterns.length} patterns.`);
191
+ }
192
+ }
193
+ else {
194
+ logger.warn("[GuardrailsUtils] Sanitize action triggered but no sanitizationPatterns provided in config. Input will not be modified.");
195
+ }
196
+ return { shouldBlock: false, sanitizedInput: sanitized };
197
+ }
198
+ case "warn": {
199
+ logger.warn("[GuardrailsUtils] Potentially inappropriate content detected but allowing:", {
200
+ userInput: userInput.substring(0, 100),
201
+ evaluation,
202
+ });
203
+ return { shouldBlock: false };
204
+ }
205
+ case "log": {
206
+ logger.info("[GuardrailsUtils] Suspicious content detected:", {
207
+ userInput: userInput.substring(0, 100),
208
+ evaluation,
209
+ });
210
+ return { shouldBlock: false };
211
+ }
212
+ default:
213
+ return { shouldBlock: false };
214
+ }
215
+ }
216
+ /**
217
+ * Apply parameter sanitization to request parameters
218
+ */
219
+ export function applySanitization(params, sanitizedInput) {
220
+ const sanitizedParams = { ...params };
221
+ if (Array.isArray(params.prompt)) {
222
+ const sanitizedPrompt = params.prompt.map((msg) => {
223
+ if (msg.role === "user") {
224
+ if (typeof msg.content === "string") {
225
+ return {
226
+ ...msg,
227
+ content: [{ type: "text", text: sanitizedInput }],
228
+ };
229
+ }
230
+ else if (Array.isArray(msg.content)) {
231
+ const sanitizedContent = msg.content.map((part) => {
232
+ if (part.type === "text") {
233
+ return { ...part, text: sanitizedInput };
234
+ }
235
+ return part;
236
+ });
237
+ return { ...msg, content: sanitizedContent };
238
+ }
239
+ }
240
+ return msg;
241
+ });
242
+ sanitizedParams.prompt =
243
+ sanitizedPrompt;
244
+ }
245
+ return sanitizedParams;
246
+ }
247
+ export function escapeRegExp(string) {
248
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
249
+ }
250
+ export function createBlockedResponse() {
251
+ return {
252
+ text: "Request contains inappropriate content and has been blocked.",
253
+ usage: { promptTokens: 0, completionTokens: 0 },
254
+ finishReason: "stop",
255
+ warnings: [],
256
+ rawCall: { rawPrompt: null, rawSettings: {} },
257
+ };
258
+ }
259
+ export function createBlockedStream() {
260
+ return new ReadableStream({
261
+ start(controller) {
262
+ controller.enqueue({
263
+ type: "text-delta",
264
+ textDelta: "Request contains inappropriate content and has been blocked.",
265
+ });
266
+ controller.enqueue({
267
+ type: "finish",
268
+ finishReason: "stop",
269
+ usage: { promptTokens: 0, completionTokens: 0 },
270
+ });
271
+ controller.close();
272
+ },
273
+ });
274
+ }
275
+ /**
276
+ * Apply content filtering using bad words configuration
277
+ * Handles both regex patterns and string lists with proper priority
278
+ * @param text The text to filter
279
+ * @param badWordsConfig Bad words configuration
280
+ * @param context Optional context for logging (e.g., "generate", "stream")
281
+ * @returns Filtering result with filtered text and metadata
282
+ */
283
+ export function applyContentFiltering(text, badWordsConfig, context = "unknown") {
284
+ // Early return if filtering is disabled or no config
285
+ try {
286
+ if (!badWordsConfig?.enabled || !text) {
287
+ return {
288
+ filteredText: text,
289
+ hasChanges: false,
290
+ appliedFilters: [],
291
+ filteringStats: {
292
+ regexPatternsApplied: 0,
293
+ stringFiltersApplied: 0,
294
+ totalMatches: 0,
295
+ },
296
+ };
297
+ }
298
+ let filteredText = text;
299
+ let hasChanges = false;
300
+ const appliedFilters = [];
301
+ let totalMatches = 0;
302
+ const replacementText = badWordsConfig.replacementText || "[REDACTED]";
303
+ // Priority 1: Use regex patterns if provided
304
+ if (badWordsConfig.regexPatterns &&
305
+ badWordsConfig.regexPatterns.length > 0) {
306
+ if (badWordsConfig.list && badWordsConfig.list.length > 0) {
307
+ logger.warn(`[ContentFiltering:${context}] Both regexPatterns and list provided. Using regexPatterns and ignoring list.`);
308
+ }
309
+ logger.debug(`[ContentFiltering:${context}] Applying regex pattern filtering with ${badWordsConfig.regexPatterns.length} patterns using replacement: "${replacementText}".`);
310
+ for (const pattern of badWordsConfig.regexPatterns) {
311
+ try {
312
+ // TODO: Add blocking for overly complex or long patterns
313
+ if (pattern.length > 1000) {
314
+ logger.warn(`[ContentFiltering:${context}] Regex pattern exceeds max length (1000 chars): "${pattern.substring(0, 50)}..."`);
315
+ }
316
+ const regex = new RegExp(pattern, "gi");
317
+ const testStart = Date.now();
318
+ regex.test("test");
319
+ if (Date.now() - testStart > 100) {
320
+ logger.warn(`[ContentFiltering:${context}] Regex pattern "${pattern}" appears to be too complex (slow test execution).`);
321
+ }
322
+ const before = filteredText;
323
+ let matchCount = 0;
324
+ filteredText = filteredText?.replace(regex, () => {
325
+ matchCount++;
326
+ return replacementText;
327
+ });
328
+ if (before !== filteredText) {
329
+ hasChanges = true;
330
+ totalMatches += matchCount;
331
+ appliedFilters.push(`regex:${pattern}`);
332
+ logger.debug(`[ContentFiltering:${context}] Regex pattern "${pattern}" matched ${matchCount} times and filtered content.`);
333
+ }
334
+ }
335
+ catch (error) {
336
+ logger.error(`[ContentFiltering:${context}] Invalid regex pattern "${pattern}":`, error);
337
+ }
338
+ }
339
+ }
340
+ // Priority 2: Use simple string list if no regex patterns
341
+ else if (badWordsConfig.list && badWordsConfig.list.length > 0) {
342
+ logger.debug(`[ContentFiltering:${context}] Applying string list filtering with ${badWordsConfig.list.length} terms using replacement: "${replacementText}".`);
343
+ for (const term of badWordsConfig.list) {
344
+ const regex = new RegExp(escapeRegExp(term), "gi");
345
+ const before = filteredText;
346
+ let matchCount = 0;
347
+ filteredText = filteredText?.replace(regex, () => {
348
+ matchCount++;
349
+ return replacementText;
350
+ });
351
+ if (before !== filteredText) {
352
+ hasChanges = true;
353
+ totalMatches += matchCount;
354
+ appliedFilters.push(`string:${term}`);
355
+ logger.debug(`[ContentFiltering:${context}] String filter "${term}" matched ${matchCount} times.`);
356
+ }
357
+ }
358
+ }
359
+ const result = {
360
+ filteredText,
361
+ hasChanges,
362
+ appliedFilters,
363
+ filteringStats: {
364
+ regexPatternsApplied: badWordsConfig.regexPatterns?.length || 0,
365
+ stringFiltersApplied: badWordsConfig.list?.length || 0,
366
+ totalMatches,
367
+ },
368
+ };
369
+ if (hasChanges) {
370
+ logger.debug(`[ContentFiltering:${context}] Filtering completed. Applied ${appliedFilters.length} filters with ${totalMatches} total matches.`);
371
+ }
372
+ return result;
373
+ }
374
+ catch (error) {
375
+ logger.error(`[ContentFiltering:${context}] Error during content filtering:`, error);
376
+ return {
377
+ filteredText: text,
378
+ hasChanges: false,
379
+ appliedFilters: [],
380
+ filteringStats: {
381
+ regexPatternsApplied: 0,
382
+ stringFiltersApplied: 0,
383
+ totalMatches: 0,
384
+ },
385
+ };
386
+ }
387
+ }
@@ -10,7 +10,7 @@ import { MCPToolRegistry } from "./mcp/toolRegistry.js";
10
10
  import type { GenerateOptions, GenerateResult } from "./types/generateTypes.js";
11
11
  import type { StreamOptions, StreamResult } from "./types/streamTypes.js";
12
12
  import type { MCPServerInfo, MCPExecutableTool } from "./types/mcpTypes.js";
13
- import type { ToolInfo } from "./mcp/contracts/mcpContract.js";
13
+ import type { ToolInfo } from "./types/tools.js";
14
14
  import type { NeuroLinkEvents, TypedEventEmitter, ToolExecutionContext, ToolExecutionSummary } from "./types/common.js";
15
15
  import type { JsonObject } from "./types/common.js";
16
16
  import type { BatchOperationResult } from "./types/typeAliases.js";
@@ -19,6 +19,17 @@ import { ConversationMemoryManager } from "./core/conversationMemoryManager.js";
19
19
  import { RedisConversationMemoryManager } from "./core/redisConversationMemoryManager.js";
20
20
  import type { HITLConfig } from "./hitl/types.js";
21
21
  import type { ExternalMCPServerInstance, ExternalMCPOperationResult, ExternalMCPToolInfo } from "./types/externalMcp.js";
22
+ import type { ObservabilityConfig } from "./types/observability.js";
23
+ /**
24
+ * Configuration object for NeuroLink constructor.
25
+ */
26
+ export interface NeurolinkConstructorConfig {
27
+ conversationMemory?: Partial<ConversationMemoryConfig>;
28
+ enableOrchestration?: boolean;
29
+ hitl?: HITLConfig;
30
+ toolRegistry?: MCPToolRegistry;
31
+ observability?: ObservabilityConfig;
32
+ }
22
33
  export interface ProviderStatus {
23
34
  provider: string;
24
35
  status: "working" | "failed" | "not-configured";
@@ -138,12 +149,8 @@ export declare class NeuroLink {
138
149
  * @throws {Error} When external server manager initialization fails
139
150
  * @throws {Error} When HITL configuration is invalid (if enabled)
140
151
  */
141
- constructor(config?: {
142
- conversationMemory?: Partial<ConversationMemoryConfig>;
143
- enableOrchestration?: boolean;
144
- hitl?: HITLConfig;
145
- toolRegistry?: MCPToolRegistry;
146
- });
152
+ private observabilityConfig?;
153
+ constructor(config?: NeurolinkConstructorConfig);
147
154
  /**
148
155
  * Initialize provider registry with security settings
149
156
  */
@@ -170,6 +177,10 @@ export declare class NeuroLink {
170
177
  * Setup event handlers for external server manager
171
178
  */
172
179
  private setupExternalServerEventHandlers;
180
+ /**
181
+ * Initialize Langfuse observability for AI operations tracking
182
+ */
183
+ private initializeLangfuse;
173
184
  /**
174
185
  * Log constructor completion with final state summary
175
186
  */
@@ -279,6 +290,24 @@ export declare class NeuroLink {
279
290
  * @throws {Error} When all providers fail to generate content
280
291
  * @throws {Error} When conversation memory operations fail (if enabled)
281
292
  */
293
+ /**
294
+ * Get observability configuration
295
+ */
296
+ getObservabilityConfig(): ObservabilityConfig | undefined;
297
+ /**
298
+ * Check if Langfuse telemetry is enabled
299
+ * Centralized utility to avoid duplication across providers
300
+ */
301
+ isTelemetryEnabled(): boolean;
302
+ /**
303
+ * Public method to initialize Langfuse observability
304
+ * This method can be called externally to ensure Langfuse is properly initialized
305
+ */
306
+ initializeLangfuseObservability(): Promise<void>;
307
+ /**
308
+ * Gracefully shutdown NeuroLink and all MCP connections
309
+ */
310
+ shutdown(): Promise<void>;
282
311
  generate(optionsOrPrompt: GenerateOptions | string): Promise<GenerateResult>;
283
312
  /**
284
313
  * BACKWARD COMPATIBILITY: Legacy generateText method