@juspay/neurolink 9.24.0 → 9.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/adapters/tts/googleTTSHandler.js +26 -1
  3. package/dist/adapters/video/vertexVideoHandler.js +23 -17
  4. package/dist/cli/commands/config.d.ts +3 -3
  5. package/dist/cli/commands/observability.d.ts +53 -0
  6. package/dist/cli/commands/observability.js +453 -0
  7. package/dist/cli/commands/telemetry.d.ts +63 -0
  8. package/dist/cli/commands/telemetry.js +689 -0
  9. package/dist/cli/factories/commandFactory.js +29 -15
  10. package/dist/cli/parser.js +6 -9
  11. package/dist/cli/utils/formatters.d.ts +13 -0
  12. package/dist/cli/utils/formatters.js +23 -0
  13. package/dist/constants/contextWindows.js +6 -0
  14. package/dist/constants/enums.d.ts +6 -0
  15. package/dist/constants/enums.js +8 -2
  16. package/dist/context/budgetChecker.js +75 -48
  17. package/dist/context/contextCompactor.js +135 -127
  18. package/dist/core/baseProvider.d.ts +5 -0
  19. package/dist/core/baseProvider.js +117 -110
  20. package/dist/core/conversationMemoryInitializer.js +7 -4
  21. package/dist/core/conversationMemoryManager.d.ts +2 -0
  22. package/dist/core/conversationMemoryManager.js +6 -2
  23. package/dist/core/modules/GenerationHandler.d.ts +2 -2
  24. package/dist/core/modules/GenerationHandler.js +12 -12
  25. package/dist/evaluation/ragasEvaluator.js +39 -19
  26. package/dist/evaluation/scoring.js +46 -20
  27. package/dist/features/ppt/presentationOrchestrator.js +23 -0
  28. package/dist/features/ppt/slideGenerator.js +13 -0
  29. package/dist/features/ppt/slideRenderers.d.ts +1 -1
  30. package/dist/features/ppt/slideRenderers.js +6 -4
  31. package/dist/features/ppt/slideTypeInference.d.ts +1 -1
  32. package/dist/features/ppt/slideTypeInference.js +75 -73
  33. package/dist/files/fileTools.d.ts +6 -6
  34. package/dist/index.d.ts +46 -12
  35. package/dist/index.js +79 -17
  36. package/dist/lib/adapters/tts/googleTTSHandler.js +26 -1
  37. package/dist/lib/adapters/video/vertexVideoHandler.js +23 -17
  38. package/dist/lib/constants/contextWindows.js +6 -0
  39. package/dist/lib/constants/enums.d.ts +6 -0
  40. package/dist/lib/constants/enums.js +8 -2
  41. package/dist/lib/context/budgetChecker.js +75 -48
  42. package/dist/lib/context/contextCompactor.js +135 -127
  43. package/dist/lib/core/baseProvider.d.ts +5 -0
  44. package/dist/lib/core/baseProvider.js +117 -110
  45. package/dist/lib/core/conversationMemoryInitializer.js +7 -4
  46. package/dist/lib/core/conversationMemoryManager.d.ts +2 -0
  47. package/dist/lib/core/conversationMemoryManager.js +6 -2
  48. package/dist/lib/core/modules/GenerationHandler.d.ts +2 -2
  49. package/dist/lib/core/modules/GenerationHandler.js +12 -12
  50. package/dist/lib/evaluation/ragasEvaluator.js +39 -19
  51. package/dist/lib/evaluation/scoring.js +46 -20
  52. package/dist/lib/features/ppt/presentationOrchestrator.js +23 -0
  53. package/dist/lib/features/ppt/slideGenerator.js +13 -0
  54. package/dist/lib/features/ppt/slideRenderers.d.ts +1 -1
  55. package/dist/lib/features/ppt/slideRenderers.js +6 -4
  56. package/dist/lib/features/ppt/slideTypeInference.d.ts +1 -1
  57. package/dist/lib/features/ppt/slideTypeInference.js +75 -73
  58. package/dist/lib/files/fileTools.d.ts +6 -6
  59. package/dist/lib/index.d.ts +46 -12
  60. package/dist/lib/index.js +79 -17
  61. package/dist/lib/mcp/httpRateLimiter.js +39 -12
  62. package/dist/lib/mcp/httpRetryHandler.js +22 -1
  63. package/dist/lib/mcp/mcpClientFactory.js +13 -15
  64. package/dist/lib/memory/memoryRetrievalTools.js +22 -0
  65. package/dist/lib/neurolink.d.ts +64 -72
  66. package/dist/lib/neurolink.js +1007 -564
  67. package/dist/lib/observability/exporterRegistry.d.ts +152 -0
  68. package/dist/lib/observability/exporterRegistry.js +414 -0
  69. package/dist/lib/observability/exporters/arizeExporter.d.ts +32 -0
  70. package/dist/lib/observability/exporters/arizeExporter.js +139 -0
  71. package/dist/lib/observability/exporters/baseExporter.d.ts +117 -0
  72. package/dist/lib/observability/exporters/baseExporter.js +191 -0
  73. package/dist/lib/observability/exporters/braintrustExporter.d.ts +30 -0
  74. package/dist/lib/observability/exporters/braintrustExporter.js +155 -0
  75. package/dist/lib/observability/exporters/datadogExporter.d.ts +37 -0
  76. package/dist/lib/observability/exporters/datadogExporter.js +197 -0
  77. package/dist/lib/observability/exporters/index.d.ts +13 -0
  78. package/dist/lib/observability/exporters/index.js +14 -0
  79. package/dist/lib/observability/exporters/laminarExporter.d.ts +48 -0
  80. package/dist/lib/observability/exporters/laminarExporter.js +303 -0
  81. package/dist/lib/observability/exporters/langfuseExporter.d.ts +47 -0
  82. package/dist/lib/observability/exporters/langfuseExporter.js +204 -0
  83. package/dist/lib/observability/exporters/langsmithExporter.d.ts +26 -0
  84. package/dist/lib/observability/exporters/langsmithExporter.js +124 -0
  85. package/dist/lib/observability/exporters/otelExporter.d.ts +39 -0
  86. package/dist/lib/observability/exporters/otelExporter.js +165 -0
  87. package/dist/lib/observability/exporters/posthogExporter.d.ts +48 -0
  88. package/dist/lib/observability/exporters/posthogExporter.js +288 -0
  89. package/dist/lib/observability/exporters/sentryExporter.d.ts +32 -0
  90. package/dist/lib/observability/exporters/sentryExporter.js +166 -0
  91. package/dist/lib/observability/index.d.ts +25 -0
  92. package/dist/lib/observability/index.js +32 -0
  93. package/dist/lib/observability/metricsAggregator.d.ts +260 -0
  94. package/dist/lib/observability/metricsAggregator.js +557 -0
  95. package/dist/lib/observability/otelBridge.d.ts +49 -0
  96. package/dist/lib/observability/otelBridge.js +132 -0
  97. package/dist/lib/observability/retryPolicy.d.ts +192 -0
  98. package/dist/lib/observability/retryPolicy.js +384 -0
  99. package/dist/lib/observability/sampling/index.d.ts +4 -0
  100. package/dist/lib/observability/sampling/index.js +5 -0
  101. package/dist/lib/observability/sampling/samplers.d.ts +116 -0
  102. package/dist/lib/observability/sampling/samplers.js +217 -0
  103. package/dist/lib/observability/spanProcessor.d.ts +129 -0
  104. package/dist/lib/observability/spanProcessor.js +304 -0
  105. package/dist/lib/observability/tokenTracker.d.ts +156 -0
  106. package/dist/lib/observability/tokenTracker.js +414 -0
  107. package/dist/lib/observability/types/exporterTypes.d.ts +250 -0
  108. package/dist/lib/observability/types/exporterTypes.js +6 -0
  109. package/dist/lib/observability/types/index.d.ts +6 -0
  110. package/dist/lib/observability/types/index.js +5 -0
  111. package/dist/lib/observability/types/spanTypes.d.ts +244 -0
  112. package/dist/lib/observability/types/spanTypes.js +93 -0
  113. package/dist/lib/observability/utils/index.d.ts +4 -0
  114. package/dist/lib/observability/utils/index.js +5 -0
  115. package/dist/lib/observability/utils/safeMetadata.d.ts +10 -0
  116. package/dist/lib/observability/utils/safeMetadata.js +26 -0
  117. package/dist/lib/observability/utils/spanSerializer.d.ts +115 -0
  118. package/dist/lib/observability/utils/spanSerializer.js +291 -0
  119. package/dist/lib/providers/amazonSagemaker.d.ts +5 -4
  120. package/dist/lib/providers/amazonSagemaker.js +3 -4
  121. package/dist/lib/providers/googleVertex.d.ts +7 -0
  122. package/dist/lib/providers/googleVertex.js +76 -2
  123. package/dist/lib/rag/pipeline/RAGPipeline.d.ts +0 -5
  124. package/dist/lib/rag/pipeline/RAGPipeline.js +122 -87
  125. package/dist/lib/rag/ragIntegration.js +30 -0
  126. package/dist/lib/rag/retrieval/hybridSearch.js +22 -0
  127. package/dist/lib/server/abstract/baseServerAdapter.js +51 -19
  128. package/dist/lib/server/middleware/common.js +44 -12
  129. package/dist/lib/services/server/ai/observability/instrumentation.d.ts +2 -2
  130. package/dist/lib/services/server/ai/observability/instrumentation.js +10 -5
  131. package/dist/lib/types/conversationMemoryInterface.d.ts +2 -0
  132. package/dist/lib/types/modelTypes.d.ts +18 -18
  133. package/dist/lib/types/providers.d.ts +5 -0
  134. package/dist/lib/utils/pricing.js +25 -1
  135. package/dist/lib/utils/ttsProcessor.js +74 -59
  136. package/dist/lib/workflow/config.d.ts +36 -36
  137. package/dist/lib/workflow/core/ensembleExecutor.js +10 -0
  138. package/dist/lib/workflow/core/judgeScorer.js +20 -2
  139. package/dist/lib/workflow/core/workflowRunner.js +34 -1
  140. package/dist/mcp/httpRateLimiter.js +39 -12
  141. package/dist/mcp/httpRetryHandler.js +22 -1
  142. package/dist/mcp/mcpClientFactory.js +13 -15
  143. package/dist/memory/memoryRetrievalTools.js +22 -0
  144. package/dist/neurolink.d.ts +64 -72
  145. package/dist/neurolink.js +1007 -564
  146. package/dist/observability/FEATURE-STATUS.md +269 -0
  147. package/dist/observability/exporterRegistry.d.ts +152 -0
  148. package/dist/observability/exporterRegistry.js +413 -0
  149. package/dist/observability/exporters/arizeExporter.d.ts +32 -0
  150. package/dist/observability/exporters/arizeExporter.js +138 -0
  151. package/dist/observability/exporters/baseExporter.d.ts +117 -0
  152. package/dist/observability/exporters/baseExporter.js +190 -0
  153. package/dist/observability/exporters/braintrustExporter.d.ts +30 -0
  154. package/dist/observability/exporters/braintrustExporter.js +154 -0
  155. package/dist/observability/exporters/datadogExporter.d.ts +37 -0
  156. package/dist/observability/exporters/datadogExporter.js +196 -0
  157. package/dist/observability/exporters/index.d.ts +13 -0
  158. package/dist/observability/exporters/index.js +13 -0
  159. package/dist/observability/exporters/laminarExporter.d.ts +48 -0
  160. package/dist/observability/exporters/laminarExporter.js +302 -0
  161. package/dist/observability/exporters/langfuseExporter.d.ts +47 -0
  162. package/dist/observability/exporters/langfuseExporter.js +203 -0
  163. package/dist/observability/exporters/langsmithExporter.d.ts +26 -0
  164. package/dist/observability/exporters/langsmithExporter.js +123 -0
  165. package/dist/observability/exporters/otelExporter.d.ts +39 -0
  166. package/dist/observability/exporters/otelExporter.js +164 -0
  167. package/dist/observability/exporters/posthogExporter.d.ts +48 -0
  168. package/dist/observability/exporters/posthogExporter.js +287 -0
  169. package/dist/observability/exporters/sentryExporter.d.ts +32 -0
  170. package/dist/observability/exporters/sentryExporter.js +165 -0
  171. package/dist/observability/index.d.ts +25 -0
  172. package/dist/observability/index.js +31 -0
  173. package/dist/observability/metricsAggregator.d.ts +260 -0
  174. package/dist/observability/metricsAggregator.js +556 -0
  175. package/dist/observability/otelBridge.d.ts +49 -0
  176. package/dist/observability/otelBridge.js +131 -0
  177. package/dist/observability/retryPolicy.d.ts +192 -0
  178. package/dist/observability/retryPolicy.js +383 -0
  179. package/dist/observability/sampling/index.d.ts +4 -0
  180. package/dist/observability/sampling/index.js +4 -0
  181. package/dist/observability/sampling/samplers.d.ts +116 -0
  182. package/dist/observability/sampling/samplers.js +216 -0
  183. package/dist/observability/spanProcessor.d.ts +129 -0
  184. package/dist/observability/spanProcessor.js +303 -0
  185. package/dist/observability/tokenTracker.d.ts +156 -0
  186. package/dist/observability/tokenTracker.js +413 -0
  187. package/dist/observability/types/exporterTypes.d.ts +250 -0
  188. package/dist/observability/types/exporterTypes.js +5 -0
  189. package/dist/observability/types/index.d.ts +6 -0
  190. package/dist/observability/types/index.js +4 -0
  191. package/dist/observability/types/spanTypes.d.ts +244 -0
  192. package/dist/observability/types/spanTypes.js +92 -0
  193. package/dist/observability/utils/index.d.ts +4 -0
  194. package/dist/observability/utils/index.js +4 -0
  195. package/dist/observability/utils/safeMetadata.d.ts +10 -0
  196. package/dist/observability/utils/safeMetadata.js +25 -0
  197. package/dist/observability/utils/spanSerializer.d.ts +115 -0
  198. package/dist/observability/utils/spanSerializer.js +290 -0
  199. package/dist/providers/amazonSagemaker.d.ts +5 -4
  200. package/dist/providers/amazonSagemaker.js +3 -4
  201. package/dist/providers/googleVertex.d.ts +7 -0
  202. package/dist/providers/googleVertex.js +76 -2
  203. package/dist/rag/pipeline/RAGPipeline.d.ts +0 -5
  204. package/dist/rag/pipeline/RAGPipeline.js +122 -87
  205. package/dist/rag/ragIntegration.js +30 -0
  206. package/dist/rag/retrieval/hybridSearch.js +22 -0
  207. package/dist/server/abstract/baseServerAdapter.js +51 -19
  208. package/dist/server/middleware/common.js +44 -12
  209. package/dist/services/server/ai/observability/instrumentation.d.ts +2 -2
  210. package/dist/services/server/ai/observability/instrumentation.js +10 -5
  211. package/dist/types/conversationMemoryInterface.d.ts +2 -0
  212. package/dist/types/providers.d.ts +5 -0
  213. package/dist/utils/pricing.js +25 -1
  214. package/dist/utils/ttsProcessor.js +74 -59
  215. package/dist/workflow/config.d.ts +52 -52
  216. package/dist/workflow/core/ensembleExecutor.js +10 -0
  217. package/dist/workflow/core/judgeScorer.js +20 -2
  218. package/dist/workflow/core/workflowRunner.js +34 -1
  219. package/package.json +1 -1
@@ -2,9 +2,9 @@
2
2
  * Conversation Memory Initializer
3
3
  * Provides integration with Redis storage for conversation memory
4
4
  */
5
- import { createConversationMemoryManager, getStorageType, getRedisConfigFromEnv, } from "./conversationMemoryFactory.js";
6
5
  import { applyConversationMemoryDefaults } from "../utils/conversationMemory.js";
7
6
  import { logger } from "../utils/logger.js";
7
+ import { createConversationMemoryManager, getRedisConfigFromEnv, getStorageType, } from "./conversationMemoryFactory.js";
8
8
  /**
9
9
  * Initialize conversation memory for NeuroLink
10
10
  * This function decides whether to use in-memory or Redis storage
@@ -30,11 +30,14 @@ export async function initializeConversationMemory(config) {
30
30
  maxTurnsPerSession: memoryConfig.maxTurnsPerSession,
31
31
  enableSummarization: memoryConfig.enableSummarization,
32
32
  });
33
- // Determine storage type from environment
34
- const storageType = getStorageType();
33
+ // Determine storage type: if redisConfig is passed in the SDK config, use Redis
34
+ // regardless of STORAGE_TYPE env var. This lets consumers configure Redis via the API.
35
+ const hasRedisConfig = !!config.conversationMemory?.redisConfig;
36
+ const storageType = hasRedisConfig ? "redis" : getStorageType();
35
37
  logger.debug("[conversationMemoryInitializer] Storage type determined", {
36
38
  storageType,
37
- fromEnv: !!process.env.STORAGE_TYPE,
39
+ fromConfig: hasRedisConfig,
40
+ fromEnv: !hasRedisConfig && !!process.env.STORAGE_TYPE,
38
41
  });
39
42
  if (storageType === "redis") {
40
43
  logger.info("[conversationMemoryInitializer] Initializing Redis-based conversation memory manager");
@@ -71,4 +71,6 @@ export declare class ConversationMemoryManager implements IConversationMemoryMan
71
71
  * Resets summary pointers since old pointers may reference messages that no longer exist.
72
72
  */
73
73
  setSessionMessages(sessionId: string, messages: ChatMessage[], userId?: string): Promise<void>;
74
+ /** Close/shutdown — no-op for in-memory manager (no external connections to release) */
75
+ close(): Promise<void>;
74
76
  }
@@ -6,11 +6,11 @@ import { randomUUID } from "crypto";
6
6
  import { DEFAULT_MAX_SESSIONS, MEMORY_THRESHOLD_PERCENTAGE, MESSAGES_PER_TURN, } from "../config/conversationMemory.js";
7
7
  import { TokenUtils } from "../constants/tokens.js";
8
8
  import { SummarizationEngine } from "../context/summarizationEngine.js";
9
+ import { runWithCurrentLangfuseContext } from "../services/server/ai/observability/instrumentation.js";
10
+ import { tracers, withSpan } from "../telemetry/index.js";
9
11
  import { ConversationMemoryError } from "../types/conversation.js";
10
12
  import { buildContextFromPointer, getEffectiveTokenThreshold, } from "../utils/conversationMemory.js";
11
- import { runWithCurrentLangfuseContext } from "../services/server/ai/observability/instrumentation.js";
12
13
  import { logger } from "../utils/logger.js";
13
- import { tracers, withSpan } from "../telemetry/index.js";
14
14
  export class ConversationMemoryManager {
15
15
  sessions = new Map();
16
16
  config;
@@ -337,5 +337,9 @@ export class ConversationMemoryManager {
337
337
  session.lastCountedAt = undefined;
338
338
  session.lastActivity = Date.now();
339
339
  }
340
+ /** Close/shutdown — no-op for in-memory manager (no external connections to release) */
341
+ async close() {
342
+ // In-memory manager has nothing to close
343
+ }
340
344
  }
341
345
  //# sourceMappingURL=conversationMemoryManager.js.map
@@ -12,9 +12,9 @@
12
12
  *
13
13
  * @module core/modules/GenerationHandler
14
14
  */
15
- import type { LanguageModelV1, CoreMessage, Tool } from "ai";
15
+ import type { CoreMessage, LanguageModelV1, Tool } from "ai";
16
16
  import { generateText } from "ai";
17
- import type { TextGenerationOptions, EnhancedGenerateResult, AIProviderName, StandardRecord } from "../../types/index.js";
17
+ import type { AIProviderName, EnhancedGenerateResult, StandardRecord, TextGenerationOptions } from "../../types/index.js";
18
18
  /**
19
19
  * GenerationHandler class - Handles text generation operations for AI providers
20
20
  */
@@ -12,13 +12,13 @@
12
12
  *
13
13
  * @module core/modules/GenerationHandler
14
14
  */
15
- import { generateText, Output, NoObjectGeneratedError } from "ai";
16
15
  import { SpanKind, SpanStatusCode } from "@opentelemetry/api";
16
+ import { generateText, NoObjectGeneratedError, Output } from "ai";
17
17
  import { tracers } from "../../telemetry/tracers.js";
18
18
  import { logger } from "../../utils/logger.js";
19
- import { extractTokenUsage, extractCacheCreationTokens, extractCacheReadTokens, calculateCacheSavingsPercent, } from "../../utils/tokenUtils.js";
20
- import { withProviderRetry } from "../../utils/providerRetry.js";
21
19
  import { calculateCost } from "../../utils/pricing.js";
20
+ import { withProviderRetry } from "../../utils/providerRetry.js";
21
+ import { calculateCacheSavingsPercent, extractCacheCreationTokens, extractCacheReadTokens, extractTokenUsage, } from "../../utils/tokenUtils.js";
22
22
  import { DEFAULT_MAX_STEPS } from "../constants.js";
23
23
  const genTracer = tracers.generation;
24
24
  /**
@@ -67,8 +67,8 @@ export class GenerationHandler {
67
67
  // Gemini 2.5 and earlier cannot use tools + structured JSON output simultaneously.
68
68
  // When both are requested on a Google provider, disable structured output (tools take priority).
69
69
  const wantsStructuredOutput = includeStructuredOutput &&
70
- !!options.schema &&
71
- (options.output?.format === "json" ||
70
+ (!!options.schema ||
71
+ options.output?.format === "json" ||
72
72
  options.output?.format === "structured");
73
73
  const useStructuredOutput = wantsStructuredOutput &&
74
74
  !(isGoogleProvider && shouldUseTools && Object.keys(tools).length > 0);
@@ -166,9 +166,9 @@ export class GenerationHandler {
166
166
  return genTracer.startActiveSpan("neurolink.executeGeneration", { kind: SpanKind.INTERNAL }, async (span) => {
167
167
  const shouldUseTools = !options.disableTools && this.supportsToolsFn();
168
168
  const toolCount = Object.keys(tools || {}).length;
169
- const useStructuredOutput = !!options.schema &&
170
- (options.output?.format === "json" ||
171
- options.output?.format === "structured");
169
+ const useStructuredOutput = !!options.schema ||
170
+ options.output?.format === "json" ||
171
+ options.output?.format === "structured";
172
172
  span.setAttribute("gen_ai.system", this.providerName || "unknown");
173
173
  span.setAttribute("neurolink.structured_output", useStructuredOutput);
174
174
  span.setAttribute("neurolink.tool_count", toolCount);
@@ -452,10 +452,10 @@ export class GenerationHandler {
452
452
  * Format the enhanced result
453
453
  */
454
454
  formatEnhancedResult(generateResult, tools, toolsUsed, toolExecutions, options) {
455
- // Structured output check
456
- const useStructuredOutput = !!options.schema &&
457
- (options.output?.format === "json" ||
458
- options.output?.format === "structured");
455
+ // Structured output check — schema alone is sufficient to activate
456
+ const useStructuredOutput = !!options.schema ||
457
+ options.output?.format === "json" ||
458
+ options.output?.format === "structured";
459
459
  let content;
460
460
  if (useStructuredOutput) {
461
461
  try {
@@ -1,6 +1,8 @@
1
1
  import { AIProviderFactory } from "../core/factory.js";
2
2
  import { PromptBuilder } from "./prompts.js";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { SpanSerializer, SpanType, SpanStatus, } from "../observability/index.js";
5
+ import { getMetricsAggregator } from "../observability/index.js";
4
6
  /**
5
7
  * Implements a RAGAS-style evaluator that uses a "judge" LLM to score the
6
8
  * quality of an AI response based on rich, contextual information.
@@ -32,27 +34,45 @@ export class RAGASEvaluator {
32
34
  * @returns A promise that resolves to a detailed `EvaluationResult`.
33
35
  */
34
36
  async evaluate(context) {
35
- const startTime = Date.now();
36
- const prompt = this.promptBuilder.buildEvaluationPrompt(context, this.promptGenerator);
37
- const provider = await AIProviderFactory.createProvider(this.providerName, this.evaluationModel);
38
- const result = await provider.generate({
39
- input: { text: prompt },
37
+ const span = SpanSerializer.createSpan(SpanType.EVALUATION, "evaluation.ragas", {
38
+ "evaluation.dimension": "relevance|accuracy|completeness",
39
+ "ai.provider": this.providerName,
40
+ "ai.model": this.evaluationModel,
40
41
  });
41
- if (!result) {
42
- throw new Error("Evaluation generation failed to return a result.");
42
+ const startTime = Date.now();
43
+ try {
44
+ const prompt = this.promptBuilder.buildEvaluationPrompt(context, this.promptGenerator);
45
+ const provider = await AIProviderFactory.createProvider(this.providerName, this.evaluationModel);
46
+ const result = await provider.generate({
47
+ input: { text: prompt },
48
+ });
49
+ if (!result) {
50
+ throw new Error("Evaluation generation failed to return a result.");
51
+ }
52
+ const rawEvaluationResponse = result.content;
53
+ const parsedResult = this.parseEvaluationResponse(rawEvaluationResponse);
54
+ const evaluationTime = Date.now() - startTime;
55
+ const finalResult = {
56
+ ...parsedResult,
57
+ isPassing: parsedResult.finalScore >= this.threshold, // This will be recalculated, but is needed for the type
58
+ evaluationModel: this.evaluationModel,
59
+ evaluationTime,
60
+ attemptNumber: context.attemptNumber,
61
+ rawEvaluationResponse,
62
+ };
63
+ span.durationMs = Date.now() - startTime;
64
+ const endedSpan = SpanSerializer.endSpan(span, SpanStatus.OK);
65
+ getMetricsAggregator().recordSpan(endedSpan);
66
+ return finalResult;
67
+ }
68
+ catch (error) {
69
+ span.durationMs = Date.now() - startTime;
70
+ const endedSpan = SpanSerializer.endSpan(span, SpanStatus.ERROR);
71
+ endedSpan.statusMessage =
72
+ error instanceof Error ? error.message : String(error);
73
+ getMetricsAggregator().recordSpan(endedSpan);
74
+ throw error;
43
75
  }
44
- const rawEvaluationResponse = result.content;
45
- const parsedResult = this.parseEvaluationResponse(rawEvaluationResponse);
46
- const evaluationTime = Date.now() - startTime;
47
- const finalResult = {
48
- ...parsedResult,
49
- isPassing: parsedResult.finalScore >= this.threshold, // This will be recalculated, but is needed for the type
50
- evaluationModel: this.evaluationModel,
51
- evaluationTime,
52
- attemptNumber: context.attemptNumber,
53
- rawEvaluationResponse,
54
- };
55
- return finalResult;
56
76
  }
57
77
  /**
58
78
  * Parses the raw JSON string from the judge LLM into a structured `EvaluationResult` object.
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * @file Contains the logic for mapping raw evaluation results to the structured EvaluationData type.
3
3
  */
4
+ import { SpanSerializer, SpanType, SpanStatus, } from "../observability/index.js";
5
+ import { getMetricsAggregator } from "../observability/index.js";
4
6
  /**
5
7
  * Maps a raw `EvaluationResult` to the structured `EvaluationData` format.
6
8
  * This includes calculating derived fields like `isOffTopic` and `alertSeverity`.
@@ -12,25 +14,49 @@
12
14
  * @returns A structured `EvaluationData` object.
13
15
  */
14
16
  export function mapToEvaluationData(evalContext, result, threshold, offTopicThreshold = 5, highSeverityThreshold = 4) {
15
- const isPassing = result.finalScore >= threshold;
16
- return {
17
- relevance: result.relevanceScore,
18
- accuracy: result.accuracyScore,
19
- completeness: result.completenessScore,
20
- overall: result.finalScore,
21
- isOffTopic: result.finalScore < offTopicThreshold,
22
- alertSeverity: isPassing
23
- ? "none"
24
- : result.finalScore < highSeverityThreshold
25
- ? "high"
26
- : "medium",
27
- reasoning: result.reasoning,
28
- suggestedImprovements: result.suggestedImprovements,
29
- evaluationModel: result.evaluationModel,
30
- evaluationTime: result.evaluationTime,
31
- evaluationAttempt: result.attemptNumber,
32
- responseContent: evalContext.aiResponse,
33
- queryContent: evalContext.userQuery,
34
- };
17
+ const span = SpanSerializer.createSpan(SpanType.EVALUATION, "evaluation.score", {
18
+ "evaluation.dimension": "relevance|accuracy|completeness|overall",
19
+ scores: {
20
+ relevance: result.relevanceScore,
21
+ accuracy: result.accuracyScore,
22
+ completeness: result.completenessScore,
23
+ overall: result.finalScore,
24
+ },
25
+ });
26
+ const startTime = Date.now();
27
+ try {
28
+ const isPassing = result.finalScore >= threshold;
29
+ const evaluationData = {
30
+ relevance: result.relevanceScore,
31
+ accuracy: result.accuracyScore,
32
+ completeness: result.completenessScore,
33
+ overall: result.finalScore,
34
+ isOffTopic: result.finalScore < offTopicThreshold,
35
+ alertSeverity: isPassing
36
+ ? "none"
37
+ : result.finalScore < highSeverityThreshold
38
+ ? "high"
39
+ : "medium",
40
+ reasoning: result.reasoning,
41
+ suggestedImprovements: result.suggestedImprovements,
42
+ evaluationModel: result.evaluationModel,
43
+ evaluationTime: result.evaluationTime,
44
+ evaluationAttempt: result.attemptNumber,
45
+ responseContent: evalContext.aiResponse,
46
+ queryContent: evalContext.userQuery,
47
+ };
48
+ span.durationMs = Date.now() - startTime;
49
+ const endedSpan = SpanSerializer.endSpan(span, SpanStatus.OK);
50
+ getMetricsAggregator().recordSpan(endedSpan);
51
+ return evaluationData;
52
+ }
53
+ catch (error) {
54
+ span.durationMs = Date.now() - startTime;
55
+ const endedSpan = SpanSerializer.endSpan(span, SpanStatus.ERROR);
56
+ endedSpan.statusMessage =
57
+ error instanceof Error ? error.message : String(error);
58
+ getMetricsAggregator().recordSpan(endedSpan);
59
+ throw error;
60
+ }
35
61
  }
36
62
  //# sourceMappingURL=scoring.js.map
@@ -21,6 +21,8 @@ import { SlideGenerator } from "./slideGenerator.js";
21
21
  import { PPT_GENERATION_TIMEOUT_MS } from "./constants.js";
22
22
  import { logger } from "../../utils/logger.js";
23
23
  import { withTimeout, ErrorFactory } from "../../utils/errorHandling.js";
24
+ import { SpanSerializer, SpanType, SpanStatus, } from "../../observability/index.js";
25
+ import { getMetricsAggregator } from "../../observability/index.js";
24
26
  import { generateOutputPath, ensureOutputDirectory, normalizeLogoConfig, getLayoutName, getFailureStage, toError, } from "./utils.js";
25
27
  // ============================================================================
26
28
  // MAIN ORCHESTRATION FUNCTION
@@ -48,6 +50,13 @@ import { generateOutputPath, ensureOutputDirectory, normalizeLogoConfig, getLayo
48
50
  * ```
49
51
  */
50
52
  export async function generatePresentation(options) {
53
+ const span = SpanSerializer.createSpan(SpanType.PPT_GENERATION, "ppt.orchestrate", {
54
+ "ppt.operation": "orchestrate",
55
+ "ppt.slideCount": options.context.pages,
56
+ "ppt.theme": typeof options.context.theme === "string"
57
+ ? options.context.theme
58
+ : "custom",
59
+ });
51
60
  const state = {
52
61
  startTime: Date.now(),
53
62
  contentPlan: null,
@@ -73,6 +82,12 @@ export async function generatePresentation(options) {
73
82
  ErrorFactory.toolTimeout("contentPlanning", PPT_GENERATION_TIMEOUT_MS / 2));
74
83
  // Post-process: ensure title and thank-you slides
75
84
  state.contentPlan = postProcessPlan(planResult);
85
+ // Update span attributes with post-processed plan values (AI may have changed slide count/theme)
86
+ span.attributes["ppt.slideCount"] = state.contentPlan.totalSlides;
87
+ span.attributes["ppt.theme"] =
88
+ typeof state.contentPlan.theme === "string"
89
+ ? state.contentPlan.theme
90
+ : "custom";
76
91
  logger.info("[PresentationOrchestrator] Content plan ready", {
77
92
  title: state.contentPlan.title,
78
93
  totalSlides: state.contentPlan.totalSlides,
@@ -163,6 +178,9 @@ export async function generatePresentation(options) {
163
178
  // =========================================================================
164
179
  // STEP 5: Return Result
165
180
  // =========================================================================
181
+ const endedSpan = SpanSerializer.endSpan(span, SpanStatus.OK);
182
+ getMetricsAggregator().recordSpan(endedSpan);
183
+ neurolink?.recordMetricsSpan(endedSpan);
166
184
  // Use values from content plan (AI may have chosen them if "AI will decide" was passed)
167
185
  const finalTheme = state.contentPlan?.theme || context.theme;
168
186
  const finalAudience = state.contentPlan?.audience || context.audience;
@@ -185,6 +203,11 @@ export async function generatePresentation(options) {
185
203
  };
186
204
  }
187
205
  catch (error) {
206
+ const endedSpan = SpanSerializer.endSpan(span, SpanStatus.ERROR);
207
+ endedSpan.statusMessage =
208
+ error instanceof Error ? error.message : String(error);
209
+ getMetricsAggregator().recordSpan(endedSpan);
210
+ neurolink?.recordMetricsSpan(endedSpan);
188
211
  // Re-throw PPTError as-is
189
212
  if (error instanceof PPTError) {
190
213
  logger.error("[PresentationOrchestrator] Generation failed", {
@@ -19,6 +19,8 @@ import { SLIDE_DIMENSIONS } from "./types.js";
19
19
  import { getTheme, isImageSlideType, enhanceImagePrompt, IMAGE_GENERATION_TIMEOUT_MS, MAX_CONCURRENT_IMAGE_GENERATIONS, } from "./constants.js";
20
20
  import { logger } from "../../utils/logger.js";
21
21
  import { withTimeout, ErrorFactory, NeuroLinkError, } from "../../utils/errorHandling.js";
22
+ import { SpanSerializer, SpanType, SpanStatus, } from "../../observability/index.js";
23
+ import { getMetricsAggregator } from "../../observability/index.js";
22
24
  import { NeuroLink } from "../../neurolink.js";
23
25
  import { LAYOUT_POSITIONS, renderTitleSlide, renderSectionHeaderSlide, renderThankYouSlide, renderContentSlide, renderImageSlide, renderTwoColumnSlide, renderThreeColumnSlide, renderQuoteSlide, renderStatisticsSlide, renderChartSlide, renderTableSlide, renderTimelineSlide, renderProcessFlowSlide, renderComparisonSlide, renderFeaturesSlide, renderTeamSlide, renderConclusionSlide, renderDashboardSlide, renderMixedContentSlide, renderStatsGridSlide, renderIconGridSlide, } from "./slideRenderers.js";
24
26
  // ============================================================================
@@ -86,6 +88,11 @@ export class SlideGenerator {
86
88
  * Generate a single complete slide
87
89
  */
88
90
  async generateSlide(slideSchema) {
91
+ const span = SpanSerializer.createSpan(SpanType.PPT_GENERATION, "ppt.generateSlide", {
92
+ "ppt.operation": "generateSlide",
93
+ "ppt.slideIndex": slideSchema.slideNumber,
94
+ "ppt.theme": this.theme.name,
95
+ });
89
96
  const startTime = Date.now();
90
97
  try {
91
98
  let imageBuffer;
@@ -126,6 +133,8 @@ export class SlideGenerator {
126
133
  hasImage: !!imageBuffer,
127
134
  generationTime,
128
135
  });
136
+ const endedSpan = SpanSerializer.endSpan(span, SpanStatus.OK);
137
+ getMetricsAggregator().recordSpan(endedSpan);
129
138
  return {
130
139
  slideNumber: slideSchema.slideNumber,
131
140
  schema: slideSchema,
@@ -135,6 +144,10 @@ export class SlideGenerator {
135
144
  };
136
145
  }
137
146
  catch (error) {
147
+ const endedSpan = SpanSerializer.endSpan(span, SpanStatus.ERROR);
148
+ endedSpan.statusMessage =
149
+ error instanceof Error ? error.message : String(error);
150
+ getMetricsAggregator().recordSpan(endedSpan);
138
151
  const err = error instanceof NeuroLinkError
139
152
  ? error
140
153
  : ErrorFactory.toolExecutionFailed("slideGenerator", error instanceof Error ? error : new Error(String(error)));
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @module presentation/slideRenderers
8
8
  */
9
- import type { SlideContent, SlideLayout, SlideType, PresentationTheme, BulletPoint, PptxChartName, PptxSlide, BackgroundStyle, RenderContentSlideOptions, ColumnData } from "./types.js";
9
+ import type { BackgroundStyle, BulletPoint, ColumnData, PptxChartName, PptxSlide, PresentationTheme, RenderContentSlideOptions, SlideContent, SlideLayout, SlideType } from "./types.js";
10
10
  export declare const LAYOUT_POSITIONS: {
11
11
  margin: {
12
12
  x: number;
@@ -6,9 +6,9 @@
6
6
  *
7
7
  * @module presentation/slideRenderers
8
8
  */
9
- import { getSlideTypeFormatting, getBulletOptions } from "./constants.js";
10
9
  import { logger } from "../../utils/logger.js";
11
- import { validateImageBuffer, bufferToDataUrl, parseMarkdownText, hasMarkdownFormatting, createFormattedTextProps, calculateFontSize, } from "./utils.js";
10
+ import { getBulletOptions, getSlideTypeFormatting } from "./constants.js";
11
+ import { bufferToDataUrl, calculateFontSize, createFormattedTextProps, hasMarkdownFormatting, parseMarkdownText, validateImageBuffer, } from "./utils.js";
12
12
  // ============================================================================
13
13
  // LAYOUT POSITIONS
14
14
  // ============================================================================
@@ -986,9 +986,11 @@ export function renderThankYouSlide(slide, title, content, theme, imageBuffer) {
986
986
  fit: DEFAULT_TEXT_FIT,
987
987
  });
988
988
  }
989
- if (content.contactInfo.social && content.contactInfo.social.length > 0) {
989
+ if (content.contactInfo.social &&
990
+ Array.isArray(content.contactInfo.social) &&
991
+ content.contactInfo.social.length > 0) {
990
992
  const socialText = content.contactInfo.social
991
- .map((s) => `${s.platform}: ${s.handle}`)
993
+ .map((s) => `${s.platform || ""}: ${s.handle || ""}`)
992
994
  .join(" • ");
993
995
  slide.addText(socialText, {
994
996
  x: 0.5,
@@ -9,7 +9,7 @@
9
9
  * This helps ensure consistent slide rendering when AI doesn't explicitly
10
10
  * specify a slide type, or when we want to normalize AI responses.
11
11
  */
12
- import type { SlideType, BulletStyle, BulletPoint, SlideContent } from "./types.js";
12
+ import type { BulletPoint, BulletStyle, SlideContent, SlideType } from "./types.js";
13
13
  /**
14
14
  * Infer slide type and bullet style from title text
15
15
  */
@@ -20,13 +20,13 @@ const TITLE_KEYWORD_PATTERNS = [
20
20
  // Agenda / Table of Contents - numbered list
21
21
  {
22
22
  patterns: [
23
- /^agenda$/i,
24
- /^table\s+of\s+contents$/i,
25
- /^outline$/i,
26
- /^overview$/i,
27
- /^what\s+we('ll)?\s+cover$/i,
28
- /^today('s)?\s+topics?$/i,
29
- /^session\s+outline$/i,
23
+ /\bagenda\b/i,
24
+ /\btable\s+of\s+contents\b/i,
25
+ /\boutline\b/i,
26
+ /\boverview\b/i,
27
+ /\bwhat\s+we('ll)?\s+cover\b/i,
28
+ /\btoday('s)?\s+topics?\b/i,
29
+ /\bsession\s+outline\b/i,
30
30
  ],
31
31
  slideType: "agenda",
32
32
  bulletStyle: "number",
@@ -34,18 +34,18 @@ const TITLE_KEYWORD_PATTERNS = [
34
34
  // Conclusion / Summary - checkmark
35
35
  {
36
36
  patterns: [
37
- /^conclusion$/i,
38
- /^summary$/i,
39
- /^key\s+takeaways?$/i,
40
- /^takeaways?$/i,
41
- /^recap$/i,
42
- /^in\s+summary$/i,
43
- /^what\s+we('ve)?\s+learned$/i,
44
- /^main\s+points?$/i,
45
- /^key\s+points?$/i,
46
- /^highlights?$/i,
47
- /^achievements?$/i,
48
- /^accomplishments?$/i,
37
+ /\bconclusion\b/i,
38
+ /\bsummary\b/i,
39
+ /\bkey\s+takeaways?\b/i,
40
+ /\btakeaways?\b/i,
41
+ /\brecap\b/i,
42
+ /\bin\s+summary\b/i,
43
+ /\bwhat\s+we('ve)?\s+learned\b/i,
44
+ /\bmain\s+points?\b/i,
45
+ /\bkey\s+points?\b/i,
46
+ /\bhighlights?\b/i,
47
+ /\bachievements?\b/i,
48
+ /\baccomplishments?\b/i,
49
49
  ],
50
50
  slideType: "conclusion",
51
51
  bulletStyle: "checkmark",
@@ -53,15 +53,15 @@ const TITLE_KEYWORD_PATTERNS = [
53
53
  // Closing / Thank You - checkmark
54
54
  {
55
55
  patterns: [
56
- /^thank\s+you$/i,
57
- /^thanks?$/i,
58
- /^questions?\??$/i,
59
- /^q\s*&\s*a$/i,
60
- /^contact(\s+us)?$/i,
61
- /^next\s+steps?$/i,
62
- /^action\s+items?$/i,
63
- /^let('s)?\s+connect$/i,
64
- /^get\s+(in\s+)?touch$/i,
56
+ /\bthank\s+you\b/i,
57
+ /\bthanks?\b/i,
58
+ /\bquestions?\b\??/i,
59
+ /\bq\s*&\s*a\b/i,
60
+ /\bcontact(\s+us)?\b/i,
61
+ /\bnext\s+steps?\b/i,
62
+ /\baction\s+items?\b/i,
63
+ /\blet('s)?\s+connect\b/i,
64
+ /\bget\s+(in\s+)?touch\b/i,
65
65
  ],
66
66
  slideType: "closing",
67
67
  bulletStyle: "checkmark",
@@ -69,14 +69,15 @@ const TITLE_KEYWORD_PATTERNS = [
69
69
  // Comparison - arrow bullets
70
70
  {
71
71
  patterns: [
72
- /^comparison$/i,
73
- /^vs\.?$/i,
74
- /^versus$/i,
75
- /^before\s+(and|&|vs\.?)\s+after$/i,
76
- /^pros?\s+(and|&|vs\.?)\s+cons?$/i,
77
- /^advantages?\s+(and|&|vs\.?)\s+disadvantages?$/i,
78
- /^benefits?\s+(and|&|vs\.?)\s+risks?$/i,
79
- /^old\s+vs\.?\s+new$/i,
72
+ /\bcomparison\b/i,
73
+ /\bcompare\b/i,
74
+ /\bvs\.?\b/i,
75
+ /\bversus\b/i,
76
+ /\bbefore\s+(and|&|vs\.?)\s+after\b/i,
77
+ /\bpros?\s+(and|&|vs\.?)\s+cons?\b/i,
78
+ /\badvantages?\s+(and|&|vs\.?)\s+disadvantages?\b/i,
79
+ /\bbenefits?\s+(and|&|vs\.?)\s+risks?\b/i,
80
+ /\bold\s+vs\.?\s+new\b/i,
80
81
  ],
81
82
  slideType: "comparison",
82
83
  bulletStyle: "arrow",
@@ -84,15 +85,16 @@ const TITLE_KEYWORD_PATTERNS = [
84
85
  // Process / Steps - numbered
85
86
  {
86
87
  patterns: [
87
- /^process$/i,
88
- /^steps?$/i,
89
- /^how\s+to\b/i,
90
- /^workflow$/i,
91
- /^procedure$/i,
92
- /^methodology$/i,
93
- /^\d+\s+steps?\s+to\b/i,
94
- /^implementation\s+steps?$/i,
95
- /^getting\s+started$/i,
88
+ /\bprocess\b/i,
89
+ /\bsteps?\b/i,
90
+ /\bstep[\s-]+by[\s-]+step\b/i,
91
+ /\bhow\s+to\b/i,
92
+ /\bworkflow\b/i,
93
+ /\bprocedure\b/i,
94
+ /\bmethodology\b/i,
95
+ /\d+\s+steps?\s+to\b/i,
96
+ /\bimplementation\s+steps?\b/i,
97
+ /\bgetting\s+started\b/i,
96
98
  ],
97
99
  slideType: "numbered-list",
98
100
  bulletStyle: "number",
@@ -100,21 +102,21 @@ const TITLE_KEYWORD_PATTERNS = [
100
102
  // Features / Benefits - disc (but could be checkmark for benefits)
101
103
  {
102
104
  patterns: [
103
- /^features?$/i,
104
- /^capabilities?$/i,
105
- /^what\s+(we|it)\s+offers?$/i,
106
- /^our\s+offerings?$/i,
105
+ /\bfeatures?\b/i,
106
+ /\bcapabilities?\b/i,
107
+ /\bwhat\s+(we|it)\s+offers?\b/i,
108
+ /\bour\s+offerings?\b/i,
107
109
  ],
108
110
  slideType: "features",
109
111
  bulletStyle: "disc",
110
112
  },
111
113
  {
112
114
  patterns: [
113
- /^benefits?$/i,
114
- /^advantages?$/i,
115
- /^why\s+choose\b/i,
116
- /^reasons?\s+to\b/i,
117
- /^value\s+proposition$/i,
115
+ /\bbenefits?\b/i,
116
+ /\badvantages?\b/i,
117
+ /\bwhy\s+choose\b/i,
118
+ /\breasons?\s+to\b/i,
119
+ /\bvalue\s+proposition\b/i,
118
120
  ],
119
121
  slideType: "content",
120
122
  bulletStyle: "checkmark",
@@ -122,12 +124,12 @@ const TITLE_KEYWORD_PATTERNS = [
122
124
  // Goals / Objectives - checkmark
123
125
  {
124
126
  patterns: [
125
- /^goals?$/i,
126
- /^objectives?$/i,
127
- /^targets?$/i,
128
- /^aims?$/i,
129
- /^our\s+mission$/i,
130
- /^what\s+we\s+aim\s+for$/i,
127
+ /\bgoals?\b/i,
128
+ /\bobjectives?\b/i,
129
+ /\btargets?\b/i,
130
+ /\baims?\b/i,
131
+ /\bour\s+mission\b/i,
132
+ /\bwhat\s+we\s+aim\s+for\b/i,
131
133
  ],
132
134
  slideType: "content",
133
135
  bulletStyle: "checkmark",
@@ -135,13 +137,13 @@ const TITLE_KEYWORD_PATTERNS = [
135
137
  // Challenges / Risks - arrow
136
138
  {
137
139
  patterns: [
138
- /^challenges?$/i,
139
- /^risks?$/i,
140
- /^obstacles?$/i,
141
- /^barriers?$/i,
142
- /^concerns?$/i,
143
- /^issues?$/i,
144
- /^problems?$/i,
140
+ /\bchallenges?\b/i,
141
+ /\brisks?\b/i,
142
+ /\bobstacles?\b/i,
143
+ /\bbarriers?\b/i,
144
+ /\bconcerns?\b/i,
145
+ /\bissues?\b/i,
146
+ /\bproblems?\b/i,
145
147
  ],
146
148
  slideType: "content",
147
149
  bulletStyle: "arrow",
@@ -149,12 +151,12 @@ const TITLE_KEYWORD_PATTERNS = [
149
151
  // Requirements / Checklist - checkmark
150
152
  {
151
153
  patterns: [
152
- /^requirements?$/i,
153
- /^checklist$/i,
154
- /^prerequisites?$/i,
155
- /^what\s+you\s+need$/i,
156
- /^must\s+haves?$/i,
157
- /^essentials?$/i,
154
+ /\brequirements?\b/i,
155
+ /\bchecklist\b/i,
156
+ /\bprerequisites?\b/i,
157
+ /\bwhat\s+you\s+need\b/i,
158
+ /\bmust\s+haves?\b/i,
159
+ /\bessentials?\b/i,
158
160
  ],
159
161
  slideType: "content",
160
162
  bulletStyle: "checkmark",