@juspay/neurolink 9.61.1 → 9.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +23 -17
- package/dist/adapters/tts/googleTTSHandler.js +1 -1
- package/dist/browser/neurolink.min.js +382 -364
- package/dist/cli/commands/serve.js +9 -0
- package/dist/cli/commands/voiceServer.d.ts +7 -0
- package/dist/cli/commands/voiceServer.js +9 -1
- package/dist/cli/factories/commandFactory.js +136 -11
- package/dist/cli/loop/optionsSchema.d.ts +1 -1
- package/dist/cli/utils/audioFileUtils.d.ts +3 -3
- package/dist/cli/utils/audioFileUtils.js +5 -1
- package/dist/core/baseProvider.js +29 -6
- package/dist/factories/providerRegistry.d.ts +14 -0
- package/dist/factories/providerRegistry.js +141 -2
- package/dist/lib/adapters/tts/googleTTSHandler.js +1 -1
- package/dist/lib/core/baseProvider.js +29 -6
- package/dist/lib/factories/providerRegistry.d.ts +14 -0
- package/dist/lib/factories/providerRegistry.js +141 -2
- package/dist/lib/mcp/toolRegistry.js +7 -1
- package/dist/lib/neurolink.d.ts +19 -0
- package/dist/lib/neurolink.js +252 -14
- package/dist/lib/observability/exporters/laminarExporter.js +1 -0
- package/dist/lib/observability/exporters/posthogExporter.js +1 -0
- package/dist/lib/observability/utils/spanSerializer.js +1 -0
- package/dist/lib/server/voice/tokenCompare.d.ts +14 -0
- package/dist/lib/server/voice/tokenCompare.js +23 -0
- package/dist/lib/server/voice/voiceServerApp.js +62 -3
- package/dist/lib/server/voice/voiceWebSocketHandler.d.ts +20 -3
- package/dist/lib/server/voice/voiceWebSocketHandler.js +555 -435
- package/dist/lib/types/generate.d.ts +47 -0
- package/dist/lib/types/hitl.d.ts +3 -0
- package/dist/lib/types/index.d.ts +1 -1
- package/dist/lib/types/index.js +1 -1
- package/dist/lib/types/realtime.d.ts +243 -0
- package/dist/lib/types/realtime.js +70 -0
- package/dist/lib/types/server.d.ts +68 -0
- package/dist/lib/types/span.d.ts +2 -0
- package/dist/lib/types/span.js +2 -0
- package/dist/lib/types/stream.d.ts +36 -14
- package/dist/lib/types/stt.d.ts +585 -0
- package/dist/lib/types/stt.js +90 -0
- package/dist/lib/types/tools.d.ts +2 -0
- package/dist/lib/types/tts.d.ts +23 -11
- package/dist/lib/types/tts.js +7 -0
- package/dist/lib/types/voice.d.ts +272 -0
- package/dist/lib/types/voice.js +137 -0
- package/dist/lib/utils/audioFormatDetector.d.ts +15 -0
- package/dist/lib/utils/audioFormatDetector.js +34 -0
- package/dist/lib/utils/errorHandling.js +4 -0
- package/dist/lib/utils/sttProcessor.d.ts +115 -0
- package/dist/lib/utils/sttProcessor.js +295 -0
- package/dist/lib/voice/RealtimeVoiceAPI.d.ts +183 -0
- package/dist/lib/voice/RealtimeVoiceAPI.js +439 -0
- package/dist/lib/voice/audio-utils.d.ts +135 -0
- package/dist/lib/voice/audio-utils.js +435 -0
- package/dist/lib/voice/errors.d.ts +123 -0
- package/dist/lib/voice/errors.js +386 -0
- package/dist/lib/voice/index.d.ts +26 -0
- package/dist/lib/voice/index.js +55 -0
- package/dist/lib/voice/providers/AzureSTT.d.ts +47 -0
- package/dist/lib/voice/providers/AzureSTT.js +345 -0
- package/dist/lib/voice/providers/AzureTTS.d.ts +59 -0
- package/dist/lib/voice/providers/AzureTTS.js +349 -0
- package/dist/lib/voice/providers/DeepgramSTT.d.ts +40 -0
- package/dist/lib/voice/providers/DeepgramSTT.js +550 -0
- package/dist/lib/voice/providers/ElevenLabsTTS.d.ts +53 -0
- package/dist/lib/voice/providers/ElevenLabsTTS.js +311 -0
- package/dist/lib/voice/providers/GeminiLive.d.ts +52 -0
- package/dist/lib/voice/providers/GeminiLive.js +372 -0
- package/dist/lib/voice/providers/GoogleSTT.d.ts +60 -0
- package/dist/lib/voice/providers/GoogleSTT.js +454 -0
- package/dist/lib/voice/providers/OpenAIRealtime.d.ts +47 -0
- package/dist/lib/voice/providers/OpenAIRealtime.js +412 -0
- package/dist/lib/voice/providers/OpenAISTT.d.ts +41 -0
- package/dist/lib/voice/providers/OpenAISTT.js +286 -0
- package/dist/lib/voice/providers/OpenAITTS.d.ts +49 -0
- package/dist/lib/voice/providers/OpenAITTS.js +271 -0
- package/dist/lib/voice/stream-handler.d.ts +166 -0
- package/dist/lib/voice/stream-handler.js +514 -0
- package/dist/mcp/toolRegistry.js +7 -1
- package/dist/neurolink.d.ts +19 -0
- package/dist/neurolink.js +252 -14
- package/dist/observability/exporters/laminarExporter.js +1 -0
- package/dist/observability/exporters/posthogExporter.js +1 -0
- package/dist/observability/utils/spanSerializer.js +1 -0
- package/dist/server/voice/tokenCompare.d.ts +14 -0
- package/dist/server/voice/tokenCompare.js +22 -0
- package/dist/server/voice/voiceServerApp.js +62 -3
- package/dist/server/voice/voiceWebSocketHandler.d.ts +20 -3
- package/dist/server/voice/voiceWebSocketHandler.js +555 -435
- package/dist/types/generate.d.ts +47 -0
- package/dist/types/hitl.d.ts +3 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/realtime.d.ts +243 -0
- package/dist/types/realtime.js +69 -0
- package/dist/types/server.d.ts +68 -0
- package/dist/types/span.d.ts +2 -0
- package/dist/types/span.js +2 -0
- package/dist/types/stream.d.ts +36 -14
- package/dist/types/stt.d.ts +585 -0
- package/dist/types/stt.js +89 -0
- package/dist/types/tools.d.ts +2 -0
- package/dist/types/tts.d.ts +23 -11
- package/dist/types/tts.js +7 -0
- package/dist/types/voice.d.ts +272 -0
- package/dist/types/voice.js +136 -0
- package/dist/utils/audioFormatDetector.d.ts +15 -0
- package/dist/utils/audioFormatDetector.js +33 -0
- package/dist/utils/errorHandling.js +4 -0
- package/dist/utils/sttProcessor.d.ts +115 -0
- package/dist/utils/sttProcessor.js +294 -0
- package/dist/voice/RealtimeVoiceAPI.d.ts +183 -0
- package/dist/voice/RealtimeVoiceAPI.js +438 -0
- package/dist/voice/audio-utils.d.ts +135 -0
- package/dist/voice/audio-utils.js +434 -0
- package/dist/voice/errors.d.ts +123 -0
- package/dist/voice/errors.js +385 -0
- package/dist/voice/index.d.ts +26 -0
- package/dist/voice/index.js +54 -0
- package/dist/voice/providers/AzureSTT.d.ts +47 -0
- package/dist/voice/providers/AzureSTT.js +344 -0
- package/dist/voice/providers/AzureTTS.d.ts +59 -0
- package/dist/voice/providers/AzureTTS.js +348 -0
- package/dist/voice/providers/DeepgramSTT.d.ts +40 -0
- package/dist/voice/providers/DeepgramSTT.js +549 -0
- package/dist/voice/providers/ElevenLabsTTS.d.ts +53 -0
- package/dist/voice/providers/ElevenLabsTTS.js +310 -0
- package/dist/voice/providers/GeminiLive.d.ts +52 -0
- package/dist/voice/providers/GeminiLive.js +371 -0
- package/dist/voice/providers/GoogleSTT.d.ts +60 -0
- package/dist/voice/providers/GoogleSTT.js +453 -0
- package/dist/voice/providers/OpenAIRealtime.d.ts +47 -0
- package/dist/voice/providers/OpenAIRealtime.js +411 -0
- package/dist/voice/providers/OpenAISTT.d.ts +41 -0
- package/dist/voice/providers/OpenAISTT.js +285 -0
- package/dist/voice/providers/OpenAITTS.d.ts +49 -0
- package/dist/voice/providers/OpenAITTS.js +270 -0
- package/dist/voice/stream-handler.d.ts +166 -0
- package/dist/voice/stream-handler.js +513 -0
- package/package.json +5 -2
|
@@ -107,7 +107,7 @@ export class GoogleTTSHandler {
|
|
|
107
107
|
const languageCodes = voice.languageCodes;
|
|
108
108
|
const primaryLanguageCode = languageCodes[0];
|
|
109
109
|
const voiceType = this.detectVoiceType(voiceName);
|
|
110
|
-
// Map Google's ssmlGender → internal
|
|
110
|
+
// Map Google's ssmlGender → internal TTSGender
|
|
111
111
|
const gender = voice.ssmlGender === "MALE"
|
|
112
112
|
? "male"
|
|
113
113
|
: voice.ssmlGender === "FEMALE"
|
|
@@ -249,6 +249,11 @@ export class BaseProvider {
|
|
|
249
249
|
excludeTools: options.excludeTools,
|
|
250
250
|
skipToolPromptInjection: options.skipToolPromptInjection,
|
|
251
251
|
timeout: options.timeout,
|
|
252
|
+
stt: options.stt,
|
|
253
|
+
// Forward TTS options too — without this, the fake-streaming fallback
|
|
254
|
+
// path silently drops `tts` and the resulting StreamResult never
|
|
255
|
+
// produces a `tts_audio` chunk even when synthesis was requested.
|
|
256
|
+
tts: options.tts,
|
|
252
257
|
};
|
|
253
258
|
logger.debug(`Calling generate for fake streaming`, {
|
|
254
259
|
provider: this.providerName,
|
|
@@ -299,6 +304,23 @@ export class BaseProvider {
|
|
|
299
304
|
imageOutput: result.imageOutput,
|
|
300
305
|
};
|
|
301
306
|
}
|
|
307
|
+
// Yield synthesized audio so callers using stream() with tts.enabled
|
|
308
|
+
// still receive a tts_audio chunk on the fake-streaming fallback
|
|
309
|
+
// path (matches the discriminator used by the real streaming path).
|
|
310
|
+
if (result?.audio) {
|
|
311
|
+
yield {
|
|
312
|
+
type: "tts_audio",
|
|
313
|
+
audio: {
|
|
314
|
+
data: result.audio.buffer,
|
|
315
|
+
format: result.audio.format,
|
|
316
|
+
index: 0,
|
|
317
|
+
isFinal: true,
|
|
318
|
+
cumulativeSize: result.audio.size,
|
|
319
|
+
voice: result.audio.voice,
|
|
320
|
+
sampleRate: result.audio.sampleRate,
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
}
|
|
302
324
|
})(),
|
|
303
325
|
usage: result?.usage,
|
|
304
326
|
provider: result?.provider,
|
|
@@ -587,7 +609,7 @@ export class BaseProvider {
|
|
|
587
609
|
if (!options.tts) {
|
|
588
610
|
return this.enhanceResult(baseResult, options, startTime);
|
|
589
611
|
}
|
|
590
|
-
baseResult.audio = await TTSProcessor.synthesize(textToSynthesize, options.provider ?? this.providerName, options.tts);
|
|
612
|
+
baseResult.audio = await TTSProcessor.synthesize(textToSynthesize, options.tts.provider ?? options.provider ?? this.providerName, options.tts);
|
|
591
613
|
}
|
|
592
614
|
catch (ttsError) {
|
|
593
615
|
logger.error(`TTS synthesis failed in Mode 1 (direct input synthesis):`, ttsError);
|
|
@@ -691,20 +713,21 @@ export class BaseProvider {
|
|
|
691
713
|
const { toolsUsed, toolExecutions } = this.extractToolInformation(generateResult);
|
|
692
714
|
let enhancedResult = this.formatEnhancedResult(generateResult, tools, toolsUsed, toolExecutions, options);
|
|
693
715
|
enhancedResult = await this.synthesizeAIResponseIfNeeded(enhancedResult, options);
|
|
694
|
-
|
|
716
|
+
const finalResult = await this.enhanceResult(enhancedResult, options, startTime);
|
|
717
|
+
return finalResult;
|
|
695
718
|
}
|
|
696
719
|
async synthesizeAIResponseIfNeeded(enhancedResult, options) {
|
|
697
720
|
if (!options.tts?.enabled || !options.tts?.useAiResponse) {
|
|
698
721
|
return enhancedResult;
|
|
699
722
|
}
|
|
700
723
|
const aiResponse = enhancedResult.content;
|
|
701
|
-
const
|
|
702
|
-
if (!aiResponse || !
|
|
724
|
+
const ttsProvider = options.tts?.provider ?? options.provider ?? this.providerName;
|
|
725
|
+
if (!aiResponse || !ttsProvider) {
|
|
703
726
|
logger.warn(`TTS synthesis skipped despite being enabled`, {
|
|
704
727
|
provider: this.providerName,
|
|
705
728
|
hasAiResponse: !!aiResponse,
|
|
706
729
|
aiResponseLength: aiResponse?.length ?? 0,
|
|
707
|
-
hasProvider: !!
|
|
730
|
+
hasProvider: !!ttsProvider,
|
|
708
731
|
ttsConfig: {
|
|
709
732
|
enabled: options.tts?.enabled,
|
|
710
733
|
useAiResponse: options.tts?.useAiResponse,
|
|
@@ -716,7 +739,7 @@ export class BaseProvider {
|
|
|
716
739
|
return enhancedResult;
|
|
717
740
|
}
|
|
718
741
|
try {
|
|
719
|
-
const ttsResult = await TTSProcessor.synthesize(aiResponse,
|
|
742
|
+
const ttsResult = await TTSProcessor.synthesize(aiResponse, ttsProvider, options.tts);
|
|
720
743
|
return {
|
|
721
744
|
...enhancedResult,
|
|
722
745
|
audio: ttsResult,
|
|
@@ -7,6 +7,20 @@ export declare class ProviderRegistry {
|
|
|
7
7
|
private static registered;
|
|
8
8
|
private static registrationPromise;
|
|
9
9
|
private static options;
|
|
10
|
+
/**
|
|
11
|
+
* NEW4: per-handler registration outcomes for the realtime voice
|
|
12
|
+
* providers. `"ok"` = registered; any other string = the error message.
|
|
13
|
+
* Empty until the first `registerAllProviders()` call.
|
|
14
|
+
*/
|
|
15
|
+
static realtimeRegistration: Record<string, "ok" | string>;
|
|
16
|
+
/**
|
|
17
|
+
* Returns a snapshot of voice provider registration outcomes so callers
|
|
18
|
+
* can detect at runtime which voice handlers are usable. Useful in
|
|
19
|
+
* health-check endpoints and CI startup probes.
|
|
20
|
+
*/
|
|
21
|
+
static getRegistrationReport(): {
|
|
22
|
+
realtime: Record<string, "ok" | string>;
|
|
23
|
+
};
|
|
10
24
|
/**
|
|
11
25
|
* Register all providers with the factory
|
|
12
26
|
*/
|
|
@@ -11,6 +11,20 @@ export class ProviderRegistry {
|
|
|
11
11
|
static options = {
|
|
12
12
|
enableManualMCP: false, // Default to disabled for safety
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* NEW4: per-handler registration outcomes for the realtime voice
|
|
16
|
+
* providers. `"ok"` = registered; any other string = the error message.
|
|
17
|
+
* Empty until the first `registerAllProviders()` call.
|
|
18
|
+
*/
|
|
19
|
+
static realtimeRegistration = {};
|
|
20
|
+
/**
|
|
21
|
+
* Returns a snapshot of voice provider registration outcomes so callers
|
|
22
|
+
* can detect at runtime which voice handlers are usable. Useful in
|
|
23
|
+
* health-check endpoints and CI startup probes.
|
|
24
|
+
*/
|
|
25
|
+
static getRegistrationReport() {
|
|
26
|
+
return { realtime: { ...this.realtimeRegistration } };
|
|
27
|
+
}
|
|
14
28
|
/**
|
|
15
29
|
* Register all providers with the factory
|
|
16
30
|
*/
|
|
@@ -152,8 +166,7 @@ export class ProviderRegistry {
|
|
|
152
166
|
const { LlamaCppProvider } = await import("../providers/llamaCpp.js");
|
|
153
167
|
return new LlamaCppProvider(modelName, sdk, undefined, llamaCppCreds);
|
|
154
168
|
}, process.env.LLAMACPP_MODEL || undefined, ["llamacpp", "llama.cpp", "llama-cpp"]);
|
|
155
|
-
logger.debug("All providers registered successfully");
|
|
156
|
-
this.registered = true;
|
|
169
|
+
logger.debug("All AI providers registered successfully");
|
|
157
170
|
// ===== TTS HANDLER REGISTRATION =====
|
|
158
171
|
try {
|
|
159
172
|
// Create handler instance and register explicitly
|
|
@@ -172,6 +185,128 @@ export class ProviderRegistry {
|
|
|
172
185
|
});
|
|
173
186
|
// Don't throw - TTS is optional functionality
|
|
174
187
|
}
|
|
188
|
+
// New TTS providers
|
|
189
|
+
try {
|
|
190
|
+
const { TTSProcessor } = await import("../utils/ttsProcessor.js");
|
|
191
|
+
const { OpenAITTS } = await import("../voice/providers/OpenAITTS.js");
|
|
192
|
+
TTSProcessor.registerHandler("openai-tts", new OpenAITTS());
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
logger.debug(`[ProviderRegistry] openai-tts registration skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
const { TTSProcessor } = await import("../utils/ttsProcessor.js");
|
|
199
|
+
const { ElevenLabsTTS } = await import("../voice/providers/ElevenLabsTTS.js");
|
|
200
|
+
const elevenLabsHandler = new ElevenLabsTTS();
|
|
201
|
+
TTSProcessor.registerHandler("elevenlabs", elevenLabsHandler);
|
|
202
|
+
TTSProcessor.registerHandler("elevenlabs-tts", elevenLabsHandler);
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
logger.debug(`[ProviderRegistry] elevenlabs registration skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
const { TTSProcessor } = await import("../utils/ttsProcessor.js");
|
|
209
|
+
const { AzureTTS } = await import("../voice/providers/AzureTTS.js");
|
|
210
|
+
TTSProcessor.registerHandler("azure-tts", new AzureTTS());
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
logger.debug(`[ProviderRegistry] azure-tts registration skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
214
|
+
}
|
|
215
|
+
// ===== STT HANDLER REGISTRATION =====
|
|
216
|
+
try {
|
|
217
|
+
const { STTProcessor } = await import("../utils/sttProcessor.js");
|
|
218
|
+
try {
|
|
219
|
+
const { OpenAISTT } = await import("../voice/providers/OpenAISTT.js");
|
|
220
|
+
const openAISTT = new OpenAISTT();
|
|
221
|
+
STTProcessor.registerHandler("whisper", openAISTT);
|
|
222
|
+
STTProcessor.registerHandler("openai-stt", openAISTT);
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
logger.debug(`[ProviderRegistry] whisper/openai-stt registration skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
const { DeepgramSTT } = await import("../voice/providers/DeepgramSTT.js");
|
|
229
|
+
STTProcessor.registerHandler("deepgram", new DeepgramSTT());
|
|
230
|
+
}
|
|
231
|
+
catch (err) {
|
|
232
|
+
logger.debug(`[ProviderRegistry] deepgram registration skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const { GoogleSTT } = await import("../voice/providers/GoogleSTT.js");
|
|
236
|
+
STTProcessor.registerHandler("google-stt", new GoogleSTT());
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
logger.debug(`[ProviderRegistry] google-stt registration skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
const { AzureSTT } = await import("../voice/providers/AzureSTT.js");
|
|
243
|
+
STTProcessor.registerHandler("azure-stt", new AzureSTT());
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
logger.debug(`[ProviderRegistry] azure-stt registration skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
247
|
+
}
|
|
248
|
+
logger.debug("STT handlers registered successfully", {
|
|
249
|
+
providers: ["whisper", "deepgram", "google-stt", "azure-stt"],
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
catch (sttError) {
|
|
253
|
+
logger.warn("Failed to register STT handlers - STT functionality will be unavailable", {
|
|
254
|
+
error: sttError instanceof Error ? sttError.message : String(sttError),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
// ===== REALTIME HANDLER REGISTRATION =====
|
|
258
|
+
try {
|
|
259
|
+
const { RealtimeProcessor } = await import("../voice/RealtimeVoiceAPI.js");
|
|
260
|
+
// M9 + NEW4: track per-handler registration outcomes so the final
|
|
261
|
+
// log accurately reflects which voice providers succeeded vs which
|
|
262
|
+
// were skipped — instead of unconditionally claiming "registered
|
|
263
|
+
// successfully" or hiding failures at debug level.
|
|
264
|
+
const realtimeOutcomes = {};
|
|
265
|
+
try {
|
|
266
|
+
const { OpenAIRealtime } = await import("../voice/providers/OpenAIRealtime.js");
|
|
267
|
+
RealtimeProcessor.registerHandler("openai-realtime", new OpenAIRealtime());
|
|
268
|
+
realtimeOutcomes["openai-realtime"] = "ok";
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
272
|
+
realtimeOutcomes["openai-realtime"] = msg;
|
|
273
|
+
// M9: promote per-handler failures to error level so users can
|
|
274
|
+
// see which shipped voice provider failed to register at startup.
|
|
275
|
+
logger.error(`[ProviderRegistry] openai-realtime registration failed: ${msg}`);
|
|
276
|
+
}
|
|
277
|
+
try {
|
|
278
|
+
const { GeminiLive } = await import("../voice/providers/GeminiLive.js");
|
|
279
|
+
RealtimeProcessor.registerHandler("gemini-live", new GeminiLive());
|
|
280
|
+
realtimeOutcomes["gemini-live"] = "ok";
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
284
|
+
realtimeOutcomes["gemini-live"] = msg;
|
|
285
|
+
logger.error(`[ProviderRegistry] gemini-live registration failed: ${msg}`);
|
|
286
|
+
}
|
|
287
|
+
// NEW4: report the actual per-handler outcomes instead of an
|
|
288
|
+
// unconditional success log. Stored on the registry so callers can
|
|
289
|
+
// introspect via getRegistrationReport().
|
|
290
|
+
ProviderRegistry.realtimeRegistration = realtimeOutcomes;
|
|
291
|
+
const skipped = Object.entries(realtimeOutcomes).filter(([, v]) => v !== "ok");
|
|
292
|
+
if (skipped.length === 0) {
|
|
293
|
+
logger.info("[ProviderRegistry] Realtime handlers registered: openai-realtime, gemini-live");
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
logger.warn(`[ProviderRegistry] Realtime handlers partial: ${skipped.length} skipped`, { outcomes: realtimeOutcomes });
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
catch (realtimeError) {
|
|
300
|
+
logger.warn("Failed to register Realtime handlers - Realtime functionality will be unavailable", {
|
|
301
|
+
error: realtimeError instanceof Error
|
|
302
|
+
? realtimeError.message
|
|
303
|
+
: String(realtimeError),
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
// Mark registered ONLY after all blocks (AI + voice) attempted, so a
|
|
307
|
+
// subsequent registerAllProviders() call does not short-circuit when an
|
|
308
|
+
// optional handler block silently failed.
|
|
309
|
+
this.registered = true;
|
|
175
310
|
}
|
|
176
311
|
catch (error) {
|
|
177
312
|
logger.error("Failed to register providers:", error);
|
|
@@ -191,6 +326,10 @@ export class ProviderRegistry {
|
|
|
191
326
|
ProviderFactory.clearRegistrations();
|
|
192
327
|
this.registered = false;
|
|
193
328
|
this.registrationPromise = null;
|
|
329
|
+
// Reset realtime registration too — otherwise getRegistrationReport()
|
|
330
|
+
// can surface stale data from a previous run if the realtime block
|
|
331
|
+
// failed before reaching `realtimeRegistration = realtimeOutcomes`.
|
|
332
|
+
ProviderRegistry.realtimeRegistration = {};
|
|
194
333
|
}
|
|
195
334
|
/**
|
|
196
335
|
* Set registry options (should be called before initialization)
|
|
@@ -301,12 +301,18 @@ export class MCPToolRegistry extends MCPRegistry {
|
|
|
301
301
|
span.setAttribute("tool.arguments_size", argsStr.length);
|
|
302
302
|
// HITL Safety Check: Request confirmation if required
|
|
303
303
|
let finalArgs = args;
|
|
304
|
-
|
|
304
|
+
const HITLState = context?.hitlState;
|
|
305
|
+
if (!HITLState?.triggered &&
|
|
306
|
+
this.hitlManager &&
|
|
307
|
+
this.hitlManager.isEnabled()) {
|
|
305
308
|
const requiresConfirmation = this.hitlManager.requiresConfirmation(toolName, args);
|
|
306
309
|
if (requiresConfirmation) {
|
|
307
310
|
registryLogger.info(`Tool '${toolName}' requires HITL confirmation`);
|
|
308
311
|
span.addEvent("tool.hitl_requested");
|
|
309
312
|
try {
|
|
313
|
+
if (HITLState) {
|
|
314
|
+
HITLState.triggered = true;
|
|
315
|
+
}
|
|
310
316
|
const confirmationResult = await this.hitlManager.requestConfirmation(toolName, args, {
|
|
311
317
|
serverId: tool.serverId,
|
|
312
318
|
sessionId: execContext.sessionId,
|
package/dist/lib/neurolink.d.ts
CHANGED
|
@@ -764,6 +764,25 @@ export declare class NeuroLink {
|
|
|
764
764
|
private validateStreamRequestOptions;
|
|
765
765
|
private maybeHandleWorkflowStreamRequest;
|
|
766
766
|
private runStandardStreamRequest;
|
|
767
|
+
/**
|
|
768
|
+
* TTS Mode 2 synthesis helper for the stream() pipeline.
|
|
769
|
+
*
|
|
770
|
+
* m5 — extracted from runStandardStreamRequest so the surrounding generator
|
|
771
|
+
* stays under the max-lines-per-function lint budget. Behaviour preserved
|
|
772
|
+
* exactly:
|
|
773
|
+
* - When Mode 2 is enabled (`tts.enabled && tts.useAiResponse`) AND the
|
|
774
|
+
* model produced non-empty content: synthesises one final audio buffer
|
|
775
|
+
* and returns it as an `audioChunk` for the caller to `yield`. Resolves
|
|
776
|
+
* `ttsResolver` with the `TTSResult`.
|
|
777
|
+
* - When Mode 2 is enabled but synthesis fails: logs a warning and resolves
|
|
778
|
+
* `ttsResolver` with `undefined`.
|
|
779
|
+
* - When Mode 2 is requested but skipped (empty content / wrong mode):
|
|
780
|
+
* resolves `ttsResolver` with `undefined` early so callers awaiting
|
|
781
|
+
* `result.audio` unblock before the surrounding `finally` cleanup
|
|
782
|
+
* completes (Issue 7 latency micro-opt — the finally block also resolves
|
|
783
|
+
* defensively, so this is a redundant early signal, not a coverage fix).
|
|
784
|
+
*/
|
|
785
|
+
private synthesizeStreamModeTwo;
|
|
767
786
|
/**
|
|
768
787
|
* Prepare stream options: initialize memory, MCP, retrieval, orchestration,
|
|
769
788
|
* Ollama tool auto-disable, factory processing, and tool detection.
|