@juspay/neurolink 10.8.14 → 10.8.16
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 +4 -0
- package/dist/browser/neurolink.min.js +484 -664
- package/dist/cli/factories/sagemakerCommandFactory.js +2 -11
- package/dist/core/baseProvider.js +2 -2
- package/dist/core/modules/GenerationHandler.d.ts +34 -2
- package/dist/core/modules/GenerationHandler.js +20 -5
- package/dist/features/ppt/slideGenerator.js +10 -18
- package/dist/lib/core/baseProvider.js +2 -2
- package/dist/lib/core/modules/GenerationHandler.d.ts +34 -2
- package/dist/lib/core/modules/GenerationHandler.js +20 -5
- package/dist/lib/features/ppt/slideGenerator.js +10 -18
- package/dist/lib/processors/document/ExcelProcessor.js +11 -19
- package/dist/lib/processors/document/WordProcessor.js +3 -11
- package/dist/lib/processors/media/AudioProcessor.js +3 -12
- package/dist/lib/processors/media/VideoProcessor.d.ts +11 -0
- package/dist/lib/processors/media/VideoProcessor.js +33 -24
- package/dist/lib/providers/sagemaker/client.js +2 -11
- package/dist/lib/server/voice/voiceWebSocketHandler.js +3 -12
- package/dist/lib/services/server/ai/observability/instrumentation.js +2 -11
- package/dist/lib/tasks/backends/bullmqBackend.js +2 -10
- package/dist/lib/utils/tryImport.d.ts +35 -0
- package/dist/lib/utils/tryImport.js +95 -0
- package/dist/processors/document/ExcelProcessor.js +11 -19
- package/dist/processors/document/WordProcessor.js +3 -11
- package/dist/processors/media/AudioProcessor.js +3 -12
- package/dist/processors/media/VideoProcessor.d.ts +11 -0
- package/dist/processors/media/VideoProcessor.js +33 -24
- package/dist/providers/sagemaker/client.js +2 -11
- package/dist/server/voice/voiceWebSocketHandler.js +3 -12
- package/dist/services/server/ai/observability/instrumentation.js +2 -11
- package/dist/tasks/backends/bullmqBackend.js +2 -10
- package/dist/utils/tryImport.d.ts +35 -0
- package/dist/utils/tryImport.js +94 -0
- package/package.json +9 -13
|
@@ -2,19 +2,10 @@ import chalk from "chalk";
|
|
|
2
2
|
import ora from "ora";
|
|
3
3
|
import inquirer from "inquirer";
|
|
4
4
|
async function loadSageMakerControl() {
|
|
5
|
-
|
|
6
|
-
return await import(/* @vite-ignore */ "@aws-sdk/client-sagemaker");
|
|
7
|
-
}
|
|
8
|
-
catch (err) {
|
|
9
|
-
const e = err instanceof Error ? err : null;
|
|
10
|
-
if (e?.code === "ERR_MODULE_NOT_FOUND" &&
|
|
11
|
-
e.message.includes("client-sagemaker")) {
|
|
12
|
-
throw new Error('SageMaker setup requires "@aws-sdk/client-sagemaker". Install it with:\n pnpm add @aws-sdk/client-sagemaker', { cause: err });
|
|
13
|
-
}
|
|
14
|
-
throw err;
|
|
15
|
-
}
|
|
5
|
+
return tryImport("@aws-sdk/client-sagemaker", "SageMaker setup");
|
|
16
6
|
}
|
|
17
7
|
import { logger } from "../../lib/utils/logger.js";
|
|
8
|
+
import { tryImport } from "../../lib/utils/tryImport.js";
|
|
18
9
|
import { checkSageMakerConfiguration, getSageMakerConfig, getConfigurationSummary, clearConfigurationCache, } from "../../lib/providers/sagemaker/config.js";
|
|
19
10
|
import { AmazonSageMakerProvider } from "../../lib/providers/sagemaker/index.js";
|
|
20
11
|
import { runQuickDiagnostics, formatDiagnosticReport, } from "../../lib/providers/sagemaker/diagnostics.js";
|
|
@@ -90,7 +90,7 @@ export class BaseProvider {
|
|
|
90
90
|
this.messageBuilder = new MessageBuilder(this.providerName, this.modelName);
|
|
91
91
|
this.streamHandler = new StreamHandler(this.providerName, this.modelName);
|
|
92
92
|
this.telemetryHandler = new TelemetryHandler(this.providerName, this.modelName, this.neurolink);
|
|
93
|
-
this.generationHandler = new GenerationHandler(this.providerName, this.modelName, () => this.supportsTools(), (options, type) => this.telemetryHandler.getTelemetryConfig(options, type), (toolCalls, toolResults, options, timestamp) => this.handleToolExecutionStorage(toolCalls, toolResults, options, timestamp), () => this.neurolink?.getEventEmitter());
|
|
93
|
+
this.generationHandler = new GenerationHandler(this.providerName, this.modelName, () => this.supportsTools(), (options, type) => this.telemetryHandler.getTelemetryConfig(options, type), (toolCalls, toolResults, options, timestamp) => this.handleToolExecutionStorage(toolCalls, toolResults, options, timestamp), { getEmitterFn: () => this.neurolink?.getEventEmitter() });
|
|
94
94
|
this.utilities = new Utilities(this.providerName, this.modelName, this.defaultTimeout, this.middlewareOptions);
|
|
95
95
|
this.toolsManager = new ToolsManager(this.providerName, this.directTools, this.neurolink, {
|
|
96
96
|
isZodSchema: (schema) => this.isZodSchema(schema),
|
|
@@ -115,7 +115,7 @@ export class BaseProvider {
|
|
|
115
115
|
this.messageBuilder = new MessageBuilder(this.providerName, this.modelName);
|
|
116
116
|
this.streamHandler = new StreamHandler(this.providerName, this.modelName);
|
|
117
117
|
this.telemetryHandler = new TelemetryHandler(this.providerName, this.modelName, this.neurolink);
|
|
118
|
-
this.generationHandler = new GenerationHandler(this.providerName, this.modelName, () => this.supportsTools(), (options, type) => this.telemetryHandler.getTelemetryConfig(options, type), (toolCalls, toolResults, options, timestamp) => this.handleToolExecutionStorage(toolCalls, toolResults, options, timestamp), () => this.neurolink?.getEventEmitter());
|
|
118
|
+
this.generationHandler = new GenerationHandler(this.providerName, this.modelName, () => this.supportsTools(), (options, type) => this.telemetryHandler.getTelemetryConfig(options, type), (toolCalls, toolResults, options, timestamp) => this.handleToolExecutionStorage(toolCalls, toolResults, options, timestamp), { getEmitterFn: () => this.neurolink?.getEventEmitter() });
|
|
119
119
|
this.utilities = new Utilities(this.providerName, this.modelName, this.defaultTimeout, this.middlewareOptions);
|
|
120
120
|
}
|
|
121
121
|
/**
|
|
@@ -48,12 +48,44 @@ export declare class GenerationHandler {
|
|
|
48
48
|
private readonly supportsToolsFn;
|
|
49
49
|
private readonly getTelemetryConfigFn;
|
|
50
50
|
private readonly handleToolStorageFn;
|
|
51
|
-
|
|
51
|
+
/**
|
|
52
|
+
* The remaining, optional dependencies.
|
|
53
|
+
*
|
|
54
|
+
* Grouped rather than added as further positional parameters: the
|
|
55
|
+
* constructor is already at the six-parameter cap, and both of these are
|
|
56
|
+
* optional injection seams rather than required collaborators.
|
|
57
|
+
*
|
|
58
|
+
* `generateTextFn` exists because every other dependency of this class
|
|
59
|
+
* arrives through the constructor while `generateText` was reached by
|
|
60
|
+
* static import. `utils/generation.ts` is a bare re-export of `ai`, and an
|
|
61
|
+
* ESM re-export cannot be substituted from a test, so asserting on the
|
|
62
|
+
* arguments this class builds — the entire contract of the system-message
|
|
63
|
+
* hoisting below — had no seam to work through. Production passes neither.
|
|
64
|
+
*/
|
|
65
|
+
private readonly deps;
|
|
52
66
|
constructor(providerName: AIProviderName, modelName: string, supportsToolsFn: () => boolean, getTelemetryConfigFn: (options: TextGenerationOptions, type: string) => {
|
|
53
67
|
isEnabled: boolean;
|
|
54
68
|
functionId?: string;
|
|
55
69
|
metadata?: Record<string, string | number | boolean>;
|
|
56
|
-
} | undefined, handleToolStorageFn: (toolCalls: unknown[], toolResults: unknown[], options: TextGenerationOptions, timestamp: Date) => Promise<void>,
|
|
70
|
+
} | undefined, handleToolStorageFn: (toolCalls: unknown[], toolResults: unknown[], options: TextGenerationOptions, timestamp: Date) => Promise<void>,
|
|
71
|
+
/**
|
|
72
|
+
* The remaining, optional dependencies.
|
|
73
|
+
*
|
|
74
|
+
* Grouped rather than added as further positional parameters: the
|
|
75
|
+
* constructor is already at the six-parameter cap, and both of these are
|
|
76
|
+
* optional injection seams rather than required collaborators.
|
|
77
|
+
*
|
|
78
|
+
* `generateTextFn` exists because every other dependency of this class
|
|
79
|
+
* arrives through the constructor while `generateText` was reached by
|
|
80
|
+
* static import. `utils/generation.ts` is a bare re-export of `ai`, and an
|
|
81
|
+
* ESM re-export cannot be substituted from a test, so asserting on the
|
|
82
|
+
* arguments this class builds — the entire contract of the system-message
|
|
83
|
+
* hoisting below — had no seam to work through. Production passes neither.
|
|
84
|
+
*/
|
|
85
|
+
deps?: {
|
|
86
|
+
getEmitterFn?: () => TypedEventEmitter<NeuroLinkEvents> | undefined;
|
|
87
|
+
generateTextFn?: typeof generateText;
|
|
88
|
+
});
|
|
57
89
|
/**
|
|
58
90
|
* Helper method to call generateText with optional structured output
|
|
59
91
|
* @private
|
|
@@ -159,14 +159,29 @@ export class GenerationHandler {
|
|
|
159
159
|
supportsToolsFn;
|
|
160
160
|
getTelemetryConfigFn;
|
|
161
161
|
handleToolStorageFn;
|
|
162
|
-
|
|
163
|
-
constructor(providerName, modelName, supportsToolsFn, getTelemetryConfigFn, handleToolStorageFn,
|
|
162
|
+
deps;
|
|
163
|
+
constructor(providerName, modelName, supportsToolsFn, getTelemetryConfigFn, handleToolStorageFn,
|
|
164
|
+
/**
|
|
165
|
+
* The remaining, optional dependencies.
|
|
166
|
+
*
|
|
167
|
+
* Grouped rather than added as further positional parameters: the
|
|
168
|
+
* constructor is already at the six-parameter cap, and both of these are
|
|
169
|
+
* optional injection seams rather than required collaborators.
|
|
170
|
+
*
|
|
171
|
+
* `generateTextFn` exists because every other dependency of this class
|
|
172
|
+
* arrives through the constructor while `generateText` was reached by
|
|
173
|
+
* static import. `utils/generation.ts` is a bare re-export of `ai`, and an
|
|
174
|
+
* ESM re-export cannot be substituted from a test, so asserting on the
|
|
175
|
+
* arguments this class builds — the entire contract of the system-message
|
|
176
|
+
* hoisting below — had no seam to work through. Production passes neither.
|
|
177
|
+
*/
|
|
178
|
+
deps = {}) {
|
|
164
179
|
this.providerName = providerName;
|
|
165
180
|
this.modelName = modelName;
|
|
166
181
|
this.supportsToolsFn = supportsToolsFn;
|
|
167
182
|
this.getTelemetryConfigFn = getTelemetryConfigFn;
|
|
168
183
|
this.handleToolStorageFn = handleToolStorageFn;
|
|
169
|
-
this.
|
|
184
|
+
this.deps = deps;
|
|
170
185
|
}
|
|
171
186
|
/**
|
|
172
187
|
* Helper method to call generateText with optional structured output
|
|
@@ -265,7 +280,7 @@ export class GenerationHandler {
|
|
|
265
280
|
const samplingParams = resolveSamplingParams(this.providerName, getModelId(model, this.modelName || ""), options.temperature !== undefined
|
|
266
281
|
? { temperature: options.temperature }
|
|
267
282
|
: {}, "aiSdk.generateText");
|
|
268
|
-
const result = await generateText({
|
|
283
|
+
const result = await (this.deps.generateTextFn ?? generateText)({
|
|
269
284
|
model,
|
|
270
285
|
...(system && { system }),
|
|
271
286
|
messages: nonSystemMessages,
|
|
@@ -364,7 +379,7 @@ export class GenerationHandler {
|
|
|
364
379
|
// This surfaces AI-SDK-driven tool completions as telemetry events
|
|
365
380
|
// so that tool spans are created even when the SDK runs tools
|
|
366
381
|
// internally (gaps G5 / S2).
|
|
367
|
-
emitToolEndFromStepFinish(this.getEmitterFn?.(), toolResults);
|
|
382
|
+
emitToolEndFromStepFinish(this.deps.getEmitterFn?.(), toolResults);
|
|
368
383
|
// Handle tool execution storage
|
|
369
384
|
this.handleToolStorageFn(toolCalls, toolResults, options, new Date()).catch((error) => {
|
|
370
385
|
logger.warn("[GenerationHandler] Failed to store tool executions", {
|
|
@@ -21,26 +21,18 @@ export async function loadPptxGenJS() {
|
|
|
21
21
|
if (_pptxGenJS) {
|
|
22
22
|
return _pptxGenJS;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return _pptxGenJS;
|
|
34
|
-
}
|
|
35
|
-
catch (err) {
|
|
36
|
-
const e = err instanceof Error ? err : null;
|
|
37
|
-
if (e?.code === "ERR_MODULE_NOT_FOUND" && e.message.includes("pptxgenjs")) {
|
|
38
|
-
throw new Error('PPT generation requires the "pptxgenjs" package. Install it with:\n pnpm add pptxgenjs', { cause: err });
|
|
39
|
-
}
|
|
40
|
-
throw err;
|
|
41
|
-
}
|
|
24
|
+
const mod = await tryImport("pptxgenjs", "PPT generation");
|
|
25
|
+
// ESM/CJS interop: pptxgenjs v4 may double-wrap the default export.
|
|
26
|
+
// The runtime shape is genuinely dynamic, so probe it as `unknown`.
|
|
27
|
+
const rawDefault = mod.default;
|
|
28
|
+
const Ctor = typeof rawDefault === "function"
|
|
29
|
+
? rawDefault
|
|
30
|
+
: rawDefault.default;
|
|
31
|
+
_pptxGenJS = Ctor;
|
|
32
|
+
return _pptxGenJS;
|
|
42
33
|
}
|
|
43
34
|
import { logger } from "../../utils/logger.js";
|
|
35
|
+
import { tryImport } from "../../utils/tryImport.js";
|
|
44
36
|
import { withTimeout, ErrorFactory, NeuroLinkError, } from "../../utils/errorHandling.js";
|
|
45
37
|
import { SpanSerializer, SpanType, SpanStatus, getMetricsAggregator, } from "../../observability/index.js";
|
|
46
38
|
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";
|
|
@@ -90,7 +90,7 @@ export class BaseProvider {
|
|
|
90
90
|
this.messageBuilder = new MessageBuilder(this.providerName, this.modelName);
|
|
91
91
|
this.streamHandler = new StreamHandler(this.providerName, this.modelName);
|
|
92
92
|
this.telemetryHandler = new TelemetryHandler(this.providerName, this.modelName, this.neurolink);
|
|
93
|
-
this.generationHandler = new GenerationHandler(this.providerName, this.modelName, () => this.supportsTools(), (options, type) => this.telemetryHandler.getTelemetryConfig(options, type), (toolCalls, toolResults, options, timestamp) => this.handleToolExecutionStorage(toolCalls, toolResults, options, timestamp), () => this.neurolink?.getEventEmitter());
|
|
93
|
+
this.generationHandler = new GenerationHandler(this.providerName, this.modelName, () => this.supportsTools(), (options, type) => this.telemetryHandler.getTelemetryConfig(options, type), (toolCalls, toolResults, options, timestamp) => this.handleToolExecutionStorage(toolCalls, toolResults, options, timestamp), { getEmitterFn: () => this.neurolink?.getEventEmitter() });
|
|
94
94
|
this.utilities = new Utilities(this.providerName, this.modelName, this.defaultTimeout, this.middlewareOptions);
|
|
95
95
|
this.toolsManager = new ToolsManager(this.providerName, this.directTools, this.neurolink, {
|
|
96
96
|
isZodSchema: (schema) => this.isZodSchema(schema),
|
|
@@ -115,7 +115,7 @@ export class BaseProvider {
|
|
|
115
115
|
this.messageBuilder = new MessageBuilder(this.providerName, this.modelName);
|
|
116
116
|
this.streamHandler = new StreamHandler(this.providerName, this.modelName);
|
|
117
117
|
this.telemetryHandler = new TelemetryHandler(this.providerName, this.modelName, this.neurolink);
|
|
118
|
-
this.generationHandler = new GenerationHandler(this.providerName, this.modelName, () => this.supportsTools(), (options, type) => this.telemetryHandler.getTelemetryConfig(options, type), (toolCalls, toolResults, options, timestamp) => this.handleToolExecutionStorage(toolCalls, toolResults, options, timestamp), () => this.neurolink?.getEventEmitter());
|
|
118
|
+
this.generationHandler = new GenerationHandler(this.providerName, this.modelName, () => this.supportsTools(), (options, type) => this.telemetryHandler.getTelemetryConfig(options, type), (toolCalls, toolResults, options, timestamp) => this.handleToolExecutionStorage(toolCalls, toolResults, options, timestamp), { getEmitterFn: () => this.neurolink?.getEventEmitter() });
|
|
119
119
|
this.utilities = new Utilities(this.providerName, this.modelName, this.defaultTimeout, this.middlewareOptions);
|
|
120
120
|
}
|
|
121
121
|
/**
|
|
@@ -48,12 +48,44 @@ export declare class GenerationHandler {
|
|
|
48
48
|
private readonly supportsToolsFn;
|
|
49
49
|
private readonly getTelemetryConfigFn;
|
|
50
50
|
private readonly handleToolStorageFn;
|
|
51
|
-
|
|
51
|
+
/**
|
|
52
|
+
* The remaining, optional dependencies.
|
|
53
|
+
*
|
|
54
|
+
* Grouped rather than added as further positional parameters: the
|
|
55
|
+
* constructor is already at the six-parameter cap, and both of these are
|
|
56
|
+
* optional injection seams rather than required collaborators.
|
|
57
|
+
*
|
|
58
|
+
* `generateTextFn` exists because every other dependency of this class
|
|
59
|
+
* arrives through the constructor while `generateText` was reached by
|
|
60
|
+
* static import. `utils/generation.ts` is a bare re-export of `ai`, and an
|
|
61
|
+
* ESM re-export cannot be substituted from a test, so asserting on the
|
|
62
|
+
* arguments this class builds — the entire contract of the system-message
|
|
63
|
+
* hoisting below — had no seam to work through. Production passes neither.
|
|
64
|
+
*/
|
|
65
|
+
private readonly deps;
|
|
52
66
|
constructor(providerName: AIProviderName, modelName: string, supportsToolsFn: () => boolean, getTelemetryConfigFn: (options: TextGenerationOptions, type: string) => {
|
|
53
67
|
isEnabled: boolean;
|
|
54
68
|
functionId?: string;
|
|
55
69
|
metadata?: Record<string, string | number | boolean>;
|
|
56
|
-
} | undefined, handleToolStorageFn: (toolCalls: unknown[], toolResults: unknown[], options: TextGenerationOptions, timestamp: Date) => Promise<void>,
|
|
70
|
+
} | undefined, handleToolStorageFn: (toolCalls: unknown[], toolResults: unknown[], options: TextGenerationOptions, timestamp: Date) => Promise<void>,
|
|
71
|
+
/**
|
|
72
|
+
* The remaining, optional dependencies.
|
|
73
|
+
*
|
|
74
|
+
* Grouped rather than added as further positional parameters: the
|
|
75
|
+
* constructor is already at the six-parameter cap, and both of these are
|
|
76
|
+
* optional injection seams rather than required collaborators.
|
|
77
|
+
*
|
|
78
|
+
* `generateTextFn` exists because every other dependency of this class
|
|
79
|
+
* arrives through the constructor while `generateText` was reached by
|
|
80
|
+
* static import. `utils/generation.ts` is a bare re-export of `ai`, and an
|
|
81
|
+
* ESM re-export cannot be substituted from a test, so asserting on the
|
|
82
|
+
* arguments this class builds — the entire contract of the system-message
|
|
83
|
+
* hoisting below — had no seam to work through. Production passes neither.
|
|
84
|
+
*/
|
|
85
|
+
deps?: {
|
|
86
|
+
getEmitterFn?: () => TypedEventEmitter<NeuroLinkEvents> | undefined;
|
|
87
|
+
generateTextFn?: typeof generateText;
|
|
88
|
+
});
|
|
57
89
|
/**
|
|
58
90
|
* Helper method to call generateText with optional structured output
|
|
59
91
|
* @private
|
|
@@ -159,14 +159,29 @@ export class GenerationHandler {
|
|
|
159
159
|
supportsToolsFn;
|
|
160
160
|
getTelemetryConfigFn;
|
|
161
161
|
handleToolStorageFn;
|
|
162
|
-
|
|
163
|
-
constructor(providerName, modelName, supportsToolsFn, getTelemetryConfigFn, handleToolStorageFn,
|
|
162
|
+
deps;
|
|
163
|
+
constructor(providerName, modelName, supportsToolsFn, getTelemetryConfigFn, handleToolStorageFn,
|
|
164
|
+
/**
|
|
165
|
+
* The remaining, optional dependencies.
|
|
166
|
+
*
|
|
167
|
+
* Grouped rather than added as further positional parameters: the
|
|
168
|
+
* constructor is already at the six-parameter cap, and both of these are
|
|
169
|
+
* optional injection seams rather than required collaborators.
|
|
170
|
+
*
|
|
171
|
+
* `generateTextFn` exists because every other dependency of this class
|
|
172
|
+
* arrives through the constructor while `generateText` was reached by
|
|
173
|
+
* static import. `utils/generation.ts` is a bare re-export of `ai`, and an
|
|
174
|
+
* ESM re-export cannot be substituted from a test, so asserting on the
|
|
175
|
+
* arguments this class builds — the entire contract of the system-message
|
|
176
|
+
* hoisting below — had no seam to work through. Production passes neither.
|
|
177
|
+
*/
|
|
178
|
+
deps = {}) {
|
|
164
179
|
this.providerName = providerName;
|
|
165
180
|
this.modelName = modelName;
|
|
166
181
|
this.supportsToolsFn = supportsToolsFn;
|
|
167
182
|
this.getTelemetryConfigFn = getTelemetryConfigFn;
|
|
168
183
|
this.handleToolStorageFn = handleToolStorageFn;
|
|
169
|
-
this.
|
|
184
|
+
this.deps = deps;
|
|
170
185
|
}
|
|
171
186
|
/**
|
|
172
187
|
* Helper method to call generateText with optional structured output
|
|
@@ -265,7 +280,7 @@ export class GenerationHandler {
|
|
|
265
280
|
const samplingParams = resolveSamplingParams(this.providerName, getModelId(model, this.modelName || ""), options.temperature !== undefined
|
|
266
281
|
? { temperature: options.temperature }
|
|
267
282
|
: {}, "aiSdk.generateText");
|
|
268
|
-
const result = await generateText({
|
|
283
|
+
const result = await (this.deps.generateTextFn ?? generateText)({
|
|
269
284
|
model,
|
|
270
285
|
...(system && { system }),
|
|
271
286
|
messages: nonSystemMessages,
|
|
@@ -364,7 +379,7 @@ export class GenerationHandler {
|
|
|
364
379
|
// This surfaces AI-SDK-driven tool completions as telemetry events
|
|
365
380
|
// so that tool spans are created even when the SDK runs tools
|
|
366
381
|
// internally (gaps G5 / S2).
|
|
367
|
-
emitToolEndFromStepFinish(this.getEmitterFn?.(), toolResults);
|
|
382
|
+
emitToolEndFromStepFinish(this.deps.getEmitterFn?.(), toolResults);
|
|
368
383
|
// Handle tool execution storage
|
|
369
384
|
this.handleToolStorageFn(toolCalls, toolResults, options, new Date()).catch((error) => {
|
|
370
385
|
logger.warn("[GenerationHandler] Failed to store tool executions", {
|
|
@@ -21,26 +21,18 @@ export async function loadPptxGenJS() {
|
|
|
21
21
|
if (_pptxGenJS) {
|
|
22
22
|
return _pptxGenJS;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return _pptxGenJS;
|
|
34
|
-
}
|
|
35
|
-
catch (err) {
|
|
36
|
-
const e = err instanceof Error ? err : null;
|
|
37
|
-
if (e?.code === "ERR_MODULE_NOT_FOUND" && e.message.includes("pptxgenjs")) {
|
|
38
|
-
throw new Error('PPT generation requires the "pptxgenjs" package. Install it with:\n pnpm add pptxgenjs', { cause: err });
|
|
39
|
-
}
|
|
40
|
-
throw err;
|
|
41
|
-
}
|
|
24
|
+
const mod = await tryImport("pptxgenjs", "PPT generation");
|
|
25
|
+
// ESM/CJS interop: pptxgenjs v4 may double-wrap the default export.
|
|
26
|
+
// The runtime shape is genuinely dynamic, so probe it as `unknown`.
|
|
27
|
+
const rawDefault = mod.default;
|
|
28
|
+
const Ctor = typeof rawDefault === "function"
|
|
29
|
+
? rawDefault
|
|
30
|
+
: rawDefault.default;
|
|
31
|
+
_pptxGenJS = Ctor;
|
|
32
|
+
return _pptxGenJS;
|
|
42
33
|
}
|
|
43
34
|
import { logger } from "../../utils/logger.js";
|
|
35
|
+
import { tryImport } from "../../utils/tryImport.js";
|
|
44
36
|
import { withTimeout, ErrorFactory, NeuroLinkError, } from "../../utils/errorHandling.js";
|
|
45
37
|
import { SpanSerializer, SpanType, SpanStatus, getMetricsAggregator, } from "../../observability/index.js";
|
|
46
38
|
import { NeuroLink } from "../../neurolink.js";
|
|
@@ -38,30 +38,22 @@
|
|
|
38
38
|
import { BaseFileProcessor } from "../base/BaseFileProcessor.js";
|
|
39
39
|
import { SIZE_LIMITS } from "../config/index.js";
|
|
40
40
|
import { FileErrorCode } from "../errors/index.js";
|
|
41
|
+
import { tryImport } from "../../utils/tryImport.js";
|
|
41
42
|
let _exceljs = null;
|
|
42
43
|
async function loadExcelJS() {
|
|
43
44
|
if (_exceljs) {
|
|
44
45
|
return _exceljs;
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return _exceljs;
|
|
57
|
-
}
|
|
58
|
-
catch (err) {
|
|
59
|
-
const e = err instanceof Error ? err : null;
|
|
60
|
-
if (e?.code === "ERR_MODULE_NOT_FOUND" && e.message.includes("exceljs")) {
|
|
61
|
-
throw new Error('Excel file processing requires the "exceljs" package. Install it with:\n pnpm add exceljs', { cause: err });
|
|
62
|
-
}
|
|
63
|
-
throw err;
|
|
64
|
-
}
|
|
47
|
+
const mod = await tryImport("exceljs", "Excel file processing");
|
|
48
|
+
// exceljs is a CommonJS module. Under Node ESM (and some bundlers) the
|
|
49
|
+
// `Workbook` constructor is exposed at runtime on the namespace's `default`
|
|
50
|
+
// export rather than on the namespace itself — so a bare
|
|
51
|
+
// `new ExcelJS.Workbook()` throws "ExcelJS.Workbook is not a constructor"
|
|
52
|
+
// (TS still types it as present via esModuleInterop, masking the bug).
|
|
53
|
+
// Normalise here so the constructor is reachable regardless of interop style.
|
|
54
|
+
const ns = mod;
|
|
55
|
+
_exceljs = (ns.Workbook ? ns : (ns.default ?? ns));
|
|
56
|
+
return _exceljs;
|
|
65
57
|
}
|
|
66
58
|
// Re-export for consumers who import from this module
|
|
67
59
|
// Import for local use
|
|
@@ -34,22 +34,14 @@
|
|
|
34
34
|
import { BaseFileProcessor } from "../base/BaseFileProcessor.js";
|
|
35
35
|
import { SIZE_LIMITS } from "../config/index.js";
|
|
36
36
|
import { FileErrorCode } from "../errors/index.js";
|
|
37
|
+
import { tryImport } from "../../utils/tryImport.js";
|
|
37
38
|
let _mammoth = null;
|
|
38
39
|
async function loadMammoth() {
|
|
39
40
|
if (_mammoth) {
|
|
40
41
|
return _mammoth;
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return _mammoth;
|
|
45
|
-
}
|
|
46
|
-
catch (err) {
|
|
47
|
-
const e = err instanceof Error ? err : null;
|
|
48
|
-
if (e?.code === "ERR_MODULE_NOT_FOUND" && e.message.includes("mammoth")) {
|
|
49
|
-
throw new Error('Word document processing requires the "mammoth" package. Install it with:\n pnpm add mammoth', { cause: err });
|
|
50
|
-
}
|
|
51
|
-
throw err;
|
|
52
|
-
}
|
|
43
|
+
_mammoth = await tryImport("mammoth", "Word document processing");
|
|
44
|
+
return _mammoth;
|
|
53
45
|
}
|
|
54
46
|
// Re-export for consumers who import from this module
|
|
55
47
|
// Import for local use
|
|
@@ -41,23 +41,14 @@ import { SIZE_LIMITS_MB } from "../config/index.js";
|
|
|
41
41
|
import { FileErrorCode } from "../errors/index.js";
|
|
42
42
|
import { withTimeout } from "../../utils/timeout.js";
|
|
43
43
|
import { formatMediaDuration } from "../../utils/mediaDuration.js";
|
|
44
|
+
import { tryImport } from "../../utils/tryImport.js";
|
|
44
45
|
let _musicMetadata = null;
|
|
45
46
|
async function loadMusicMetadata() {
|
|
46
47
|
if (_musicMetadata) {
|
|
47
48
|
return _musicMetadata;
|
|
48
49
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return _musicMetadata;
|
|
52
|
-
}
|
|
53
|
-
catch (err) {
|
|
54
|
-
const e = err instanceof Error ? err : null;
|
|
55
|
-
if (e?.code === "ERR_MODULE_NOT_FOUND" &&
|
|
56
|
-
e.message.includes("music-metadata")) {
|
|
57
|
-
throw new Error('Audio processing requires the "music-metadata" package. Install it with:\n pnpm add music-metadata', { cause: err });
|
|
58
|
-
}
|
|
59
|
-
throw err;
|
|
60
|
-
}
|
|
50
|
+
_musicMetadata = await tryImport("music-metadata", "Audio processing");
|
|
51
|
+
return _musicMetadata;
|
|
61
52
|
}
|
|
62
53
|
// =============================================================================
|
|
63
54
|
// TYPES
|
|
@@ -45,6 +45,17 @@
|
|
|
45
45
|
*/
|
|
46
46
|
import { BaseFileProcessor } from "../base/BaseFileProcessor.js";
|
|
47
47
|
import type { FileInfo, ProcessedVideo, ProcessorFileProcessingResult, ProcessOptions } from "../../types/index.js";
|
|
48
|
+
/**
|
|
49
|
+
* Narrow a loaded `fluent-ffmpeg` export to the shape this file actually uses:
|
|
50
|
+
* a callable carrying the `ffprobe` and `setFfmpegPath` statics.
|
|
51
|
+
*
|
|
52
|
+
* `tryImport` proves only that the package RESOLVES. Callers invoke the export
|
|
53
|
+
* and reach straight for its statics, so a package whose shape changed (ESM
|
|
54
|
+
* rewrite, major bump, a shim in node_modules) would otherwise surface as
|
|
55
|
+
* "Cannot read properties of undefined (reading 'ffprobe')" from inside
|
|
56
|
+
* probeVideo — blaming the call site instead of the package that is wrong.
|
|
57
|
+
*/
|
|
58
|
+
export declare function assertFluentFfmpegShape(mod: unknown): asserts mod is typeof import("fluent-ffmpeg");
|
|
48
59
|
/**
|
|
49
60
|
* Video Processor - extracts metadata, keyframes, and subtitles from video files.
|
|
50
61
|
*
|
|
@@ -55,39 +55,48 @@ import { SIZE_LIMITS_MB } from "../config/index.js";
|
|
|
55
55
|
import { FileErrorCode } from "../errors/index.js";
|
|
56
56
|
import { tracers, ATTR, withSpan } from "../../telemetry/index.js";
|
|
57
57
|
import { logger } from "../../utils/logger.js";
|
|
58
|
+
import { tryImport } from "../../utils/tryImport.js";
|
|
59
|
+
/**
|
|
60
|
+
* Narrow a loaded `fluent-ffmpeg` export to the shape this file actually uses:
|
|
61
|
+
* a callable carrying the `ffprobe` and `setFfmpegPath` statics.
|
|
62
|
+
*
|
|
63
|
+
* `tryImport` proves only that the package RESOLVES. Callers invoke the export
|
|
64
|
+
* and reach straight for its statics, so a package whose shape changed (ESM
|
|
65
|
+
* rewrite, major bump, a shim in node_modules) would otherwise surface as
|
|
66
|
+
* "Cannot read properties of undefined (reading 'ffprobe')" from inside
|
|
67
|
+
* probeVideo — blaming the call site instead of the package that is wrong.
|
|
68
|
+
*/
|
|
69
|
+
export function assertFluentFfmpegShape(mod) {
|
|
70
|
+
// Not `Partial<typeof import("fluent-ffmpeg")>`: Partial maps over properties
|
|
71
|
+
// and drops the call signature, so `typeof x === "function"` would narrow the
|
|
72
|
+
// result to `never`. Probe the statics structurally instead.
|
|
73
|
+
const statics = mod;
|
|
74
|
+
if (typeof mod !== "function" ||
|
|
75
|
+
typeof statics.ffprobe !== "function" ||
|
|
76
|
+
typeof statics.setFfmpegPath !== "function") {
|
|
77
|
+
throw new Error(`The installed "fluent-ffmpeg" package does not export a callable with ` +
|
|
78
|
+
`ffprobe and setFfmpegPath statics (got ${typeof mod}). ` +
|
|
79
|
+
`Reinstall a compatible version:\n pnpm add fluent-ffmpeg`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
58
82
|
// fluent-ffmpeg's default export is callable + has static methods — avoid caching
|
|
59
83
|
// the module type (it confuses TS); Node's module cache handles dedup.
|
|
60
84
|
async function loadFluentFfmpeg() {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
e.message.includes("fluent-ffmpeg")) {
|
|
69
|
-
throw new Error('Video processing requires the "fluent-ffmpeg" package. Install it with:\n pnpm add fluent-ffmpeg', { cause: err });
|
|
70
|
-
}
|
|
71
|
-
throw err;
|
|
72
|
-
}
|
|
85
|
+
// fluent-ffmpeg is CJS (`export =`), so `typeof import(...)` describes the
|
|
86
|
+
// callable itself and carries no `default`. Under Node ESM the namespace
|
|
87
|
+
// still wraps it, so ask for that shape explicitly.
|
|
88
|
+
const mod = await tryImport("fluent-ffmpeg", "Video processing");
|
|
89
|
+
const ffmpeg = mod.default;
|
|
90
|
+
assertFluentFfmpegShape(ffmpeg);
|
|
91
|
+
return ffmpeg;
|
|
73
92
|
}
|
|
74
93
|
let _mediabunny = null;
|
|
75
94
|
async function loadMediaBunny() {
|
|
76
95
|
if (_mediabunny) {
|
|
77
96
|
return _mediabunny;
|
|
78
97
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return _mediabunny;
|
|
82
|
-
}
|
|
83
|
-
catch (err) {
|
|
84
|
-
const e = err instanceof Error ? err : null;
|
|
85
|
-
if (e?.code === "ERR_MODULE_NOT_FOUND" &&
|
|
86
|
-
e.message.includes("mediabunny")) {
|
|
87
|
-
throw new Error('Video processing requires the "mediabunny" package. Install it with:\n pnpm add mediabunny', { cause: err });
|
|
88
|
-
}
|
|
89
|
-
throw err;
|
|
90
|
-
}
|
|
98
|
+
_mediabunny = await tryImport("mediabunny", "Video processing");
|
|
99
|
+
return _mediabunny;
|
|
91
100
|
}
|
|
92
101
|
// =============================================================================
|
|
93
102
|
// FFMPEG PATH INITIALIZATION
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { handleSageMakerError, SageMakerError, isRetryableError, getRetryDelay, } from "./errors.js";
|
|
8
8
|
import { logger } from "../../utils/logger.js";
|
|
9
|
+
import { tryImport } from "../../utils/tryImport.js";
|
|
9
10
|
/**
|
|
10
11
|
* Lazily load `@aws-sdk/client-sagemaker-runtime`.
|
|
11
12
|
*
|
|
@@ -16,17 +17,7 @@ import { logger } from "../../utils/logger.js";
|
|
|
16
17
|
* error instead of a raw resolution failure.
|
|
17
18
|
*/
|
|
18
19
|
async function loadSageMakerRuntime() {
|
|
19
|
-
|
|
20
|
-
return await import(/* @vite-ignore */ "@aws-sdk/client-sagemaker-runtime");
|
|
21
|
-
}
|
|
22
|
-
catch (err) {
|
|
23
|
-
const e = err instanceof Error ? err : null;
|
|
24
|
-
if (e?.code === "ERR_MODULE_NOT_FOUND" &&
|
|
25
|
-
e.message.includes("client-sagemaker-runtime")) {
|
|
26
|
-
throw new Error('SageMaker inference requires "@aws-sdk/client-sagemaker-runtime". Install it with:\n pnpm add @aws-sdk/client-sagemaker-runtime', { cause: err });
|
|
27
|
-
}
|
|
28
|
-
throw err;
|
|
29
|
-
}
|
|
20
|
+
return tryImport("@aws-sdk/client-sagemaker-runtime", "SageMaker inference");
|
|
30
21
|
}
|
|
31
22
|
/**
|
|
32
23
|
* Enhanced SageMaker Runtime client with retry logic and error handling
|
|
@@ -5,20 +5,11 @@ import { timingSafeEqualString } from "./tokenCompare.js";
|
|
|
5
5
|
import { CartesiaStream } from "../../adapters/tts/cartesiaHandler.js";
|
|
6
6
|
import { NeuroLink } from "../../neurolink.js";
|
|
7
7
|
import { logger } from "../../utils/logger.js";
|
|
8
|
+
import { tryImport } from "../../utils/tryImport.js";
|
|
8
9
|
import { withTimeout } from "../../utils/async/withTimeout.js";
|
|
9
10
|
async function loadCobra(accessKey) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return new mod.Cobra(accessKey);
|
|
13
|
-
}
|
|
14
|
-
catch (err) {
|
|
15
|
-
const e = err instanceof Error ? err : null;
|
|
16
|
-
if (e?.code === "ERR_MODULE_NOT_FOUND" &&
|
|
17
|
-
e.message.includes("cobra-node")) {
|
|
18
|
-
throw new Error('Voice activity detection requires "@picovoice/cobra-node". Install it with:\n pnpm add @picovoice/cobra-node', { cause: err });
|
|
19
|
-
}
|
|
20
|
-
throw err;
|
|
21
|
-
}
|
|
11
|
+
const mod = await tryImport("@picovoice/cobra-node", "Voice activity detection");
|
|
12
|
+
return new mod.Cobra(accessKey);
|
|
22
13
|
}
|
|
23
14
|
const SONIOX_URL = process.env.SONIOX_WS_URL ?? "wss://stt-rt.soniox.com/transcribe-websocket";
|
|
24
15
|
function getRequiredEnv(name) {
|
|
@@ -20,6 +20,7 @@ import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION, } from "@opentelemetry/semanti
|
|
|
20
20
|
import { AsyncLocalStorage } from "async_hooks";
|
|
21
21
|
import { extractMcpErrorText } from "../../../../utils/mcpErrorText.js";
|
|
22
22
|
import { logger } from "../../../../utils/logger.js";
|
|
23
|
+
import { tryImport } from "../../../../utils/tryImport.js";
|
|
23
24
|
import { LANGFUSE_ATTR } from "../../../../telemetry/attributes.js";
|
|
24
25
|
const LOG_PREFIX = "[OpenTelemetry]";
|
|
25
26
|
function createOtelResource(config, serviceName) {
|
|
@@ -568,17 +569,7 @@ class ContextEnricher {
|
|
|
568
569
|
}
|
|
569
570
|
}
|
|
570
571
|
async function createLangfuseProcessor(config) {
|
|
571
|
-
|
|
572
|
-
try {
|
|
573
|
-
mod = await import(/* @vite-ignore */ "@langfuse/otel");
|
|
574
|
-
}
|
|
575
|
-
catch (err) {
|
|
576
|
-
const e = err instanceof Error ? err : null;
|
|
577
|
-
if (e?.code === "ERR_MODULE_NOT_FOUND" && e.message.includes("langfuse")) {
|
|
578
|
-
throw new Error('Langfuse observability requires "@langfuse/otel". Install it with:\n pnpm add @langfuse/otel', { cause: err });
|
|
579
|
-
}
|
|
580
|
-
throw err;
|
|
581
|
-
}
|
|
572
|
+
const mod = await tryImport("@langfuse/otel", "Langfuse observability");
|
|
582
573
|
return new mod.LangfuseSpanProcessor({
|
|
583
574
|
publicKey: config.publicKey,
|
|
584
575
|
secretKey: config.secretKey,
|
|
@@ -7,19 +7,11 @@
|
|
|
7
7
|
* - Survives process restarts (Redis-persisted)
|
|
8
8
|
*/
|
|
9
9
|
import { logger } from "../../utils/logger.js";
|
|
10
|
+
import { tryImport } from "../../utils/tryImport.js";
|
|
10
11
|
import { TaskError } from "../errors.js";
|
|
11
12
|
import { TASK_DEFAULTS, } from "../../types/index.js";
|
|
12
13
|
async function loadBullMQ() {
|
|
13
|
-
|
|
14
|
-
return await import(/* @vite-ignore */ "bullmq");
|
|
15
|
-
}
|
|
16
|
-
catch (err) {
|
|
17
|
-
const e = err instanceof Error ? err : null;
|
|
18
|
-
if (e?.code === "ERR_MODULE_NOT_FOUND" && e.message.includes("bullmq")) {
|
|
19
|
-
throw new Error('BullMQ task backend requires the "bullmq" package. Install it with:\n pnpm add bullmq', { cause: err });
|
|
20
|
-
}
|
|
21
|
-
throw err;
|
|
22
|
-
}
|
|
14
|
+
return tryImport("bullmq", "BullMQ task backend");
|
|
23
15
|
}
|
|
24
16
|
const QUEUE_NAME = "neurolink-tasks";
|
|
25
17
|
export class BullMQBackend {
|