@juspay/neurolink 9.63.1 → 9.65.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 +18 -17
- package/dist/adapters/providerImageAdapter.js +29 -1
- package/dist/adapters/replicate/auth.d.ts +19 -0
- package/dist/adapters/replicate/auth.js +32 -0
- package/dist/adapters/replicate/predictionLifecycle.d.ts +46 -0
- package/dist/adapters/replicate/predictionLifecycle.js +283 -0
- package/dist/adapters/video/klingVideoHandler.d.ts +37 -0
- package/dist/adapters/video/klingVideoHandler.js +305 -0
- package/dist/adapters/video/replicateVideoHandler.d.ts +29 -0
- package/dist/adapters/video/replicateVideoHandler.js +157 -0
- package/dist/adapters/video/runwayVideoHandler.d.ts +32 -0
- package/dist/adapters/video/runwayVideoHandler.js +316 -0
- package/dist/adapters/video/vertexVideoHandler.d.ts +19 -1
- package/dist/adapters/video/vertexVideoHandler.js +42 -11
- package/dist/autoresearch/runner.js +8 -2
- package/dist/avatar/index.d.ts +13 -0
- package/dist/avatar/index.js +13 -0
- package/dist/avatar/providers/DIDAvatar.d.ts +49 -0
- package/dist/avatar/providers/DIDAvatar.js +501 -0
- package/dist/avatar/providers/HeyGenAvatar.d.ts +30 -0
- package/dist/avatar/providers/HeyGenAvatar.js +337 -0
- package/dist/avatar/providers/ReplicateAvatar.d.ts +36 -0
- package/dist/avatar/providers/ReplicateAvatar.js +267 -0
- package/dist/browser/neurolink.min.js +573 -554
- package/dist/cli/commands/mcp.js +29 -0
- package/dist/cli/commands/proxy.js +24 -5
- package/dist/cli/factories/commandFactory.d.ts +25 -1
- package/dist/cli/factories/commandFactory.js +341 -63
- package/dist/cli/loop/optionsSchema.d.ts +1 -1
- package/dist/cli/loop/optionsSchema.js +12 -0
- package/dist/constants/contextWindows.js +101 -0
- package/dist/constants/enums.d.ts +273 -2
- package/dist/constants/enums.js +290 -1
- package/dist/constants/videoErrors.d.ts +4 -0
- package/dist/constants/videoErrors.js +4 -0
- package/dist/core/baseProvider.d.ts +23 -3
- package/dist/core/baseProvider.js +217 -11
- package/dist/core/constants.d.ts +11 -0
- package/dist/core/constants.js +69 -1
- package/dist/core/modules/MessageBuilder.js +20 -0
- package/dist/core/redisConversationMemoryManager.js +6 -0
- package/dist/evaluation/index.d.ts +2 -0
- package/dist/evaluation/index.js +4 -0
- package/dist/factories/providerFactory.js +7 -1
- package/dist/factories/providerRegistry.js +203 -2
- package/dist/features/ppt/contentPlanner.js +42 -14
- package/dist/index.d.ts +9 -1
- package/dist/index.js +16 -1
- package/dist/lib/adapters/providerImageAdapter.js +29 -1
- package/dist/lib/adapters/replicate/auth.d.ts +19 -0
- package/dist/lib/adapters/replicate/auth.js +33 -0
- package/dist/lib/adapters/replicate/predictionLifecycle.d.ts +46 -0
- package/dist/lib/adapters/replicate/predictionLifecycle.js +284 -0
- package/dist/lib/adapters/video/klingVideoHandler.d.ts +37 -0
- package/dist/lib/adapters/video/klingVideoHandler.js +306 -0
- package/dist/lib/adapters/video/replicateVideoHandler.d.ts +29 -0
- package/dist/lib/adapters/video/replicateVideoHandler.js +158 -0
- package/dist/lib/adapters/video/runwayVideoHandler.d.ts +32 -0
- package/dist/lib/adapters/video/runwayVideoHandler.js +317 -0
- package/dist/lib/adapters/video/vertexVideoHandler.d.ts +19 -1
- package/dist/lib/adapters/video/vertexVideoHandler.js +42 -11
- package/dist/lib/autoresearch/runner.js +8 -2
- package/dist/lib/avatar/index.d.ts +13 -0
- package/dist/lib/avatar/index.js +14 -0
- package/dist/lib/avatar/providers/DIDAvatar.d.ts +49 -0
- package/dist/lib/avatar/providers/DIDAvatar.js +502 -0
- package/dist/lib/avatar/providers/HeyGenAvatar.d.ts +30 -0
- package/dist/lib/avatar/providers/HeyGenAvatar.js +338 -0
- package/dist/lib/avatar/providers/ReplicateAvatar.d.ts +36 -0
- package/dist/lib/avatar/providers/ReplicateAvatar.js +268 -0
- package/dist/lib/constants/contextWindows.js +101 -0
- package/dist/lib/constants/enums.d.ts +273 -2
- package/dist/lib/constants/enums.js +290 -1
- package/dist/lib/constants/videoErrors.d.ts +4 -0
- package/dist/lib/constants/videoErrors.js +4 -0
- package/dist/lib/core/baseProvider.d.ts +23 -3
- package/dist/lib/core/baseProvider.js +217 -11
- package/dist/lib/core/constants.d.ts +11 -0
- package/dist/lib/core/constants.js +69 -1
- package/dist/lib/core/modules/MessageBuilder.js +20 -0
- package/dist/lib/core/redisConversationMemoryManager.js +6 -0
- package/dist/lib/evaluation/index.d.ts +2 -0
- package/dist/lib/evaluation/index.js +4 -0
- package/dist/lib/factories/providerFactory.js +7 -1
- package/dist/lib/factories/providerRegistry.js +203 -2
- package/dist/lib/features/ppt/contentPlanner.js +42 -14
- package/dist/lib/index.d.ts +9 -1
- package/dist/lib/index.js +16 -1
- package/dist/lib/memory/hippocampusInitializer.d.ts +2 -2
- package/dist/lib/memory/hippocampusInitializer.js +32 -2
- package/dist/lib/middleware/builtin/lifecycle.js +52 -51
- package/dist/lib/music/index.d.ts +13 -0
- package/dist/lib/music/index.js +14 -0
- package/dist/lib/music/providers/BeatovenMusic.d.ts +31 -0
- package/dist/lib/music/providers/BeatovenMusic.js +334 -0
- package/dist/lib/music/providers/ElevenLabsMusic.d.ts +30 -0
- package/dist/lib/music/providers/ElevenLabsMusic.js +169 -0
- package/dist/lib/music/providers/LyriaMusic.d.ts +29 -0
- package/dist/lib/music/providers/LyriaMusic.js +173 -0
- package/dist/lib/music/providers/ReplicateMusic.d.ts +31 -0
- package/dist/lib/music/providers/ReplicateMusic.js +262 -0
- package/dist/lib/neurolink.d.ts +30 -0
- package/dist/lib/neurolink.js +342 -49
- package/dist/lib/providers/amazonBedrock.d.ts +10 -0
- package/dist/lib/providers/amazonBedrock.js +94 -39
- package/dist/lib/providers/anthropic.js +55 -7
- package/dist/lib/providers/anthropicBaseProvider.js +1 -1
- package/dist/lib/providers/azureOpenai.js +66 -17
- package/dist/lib/providers/cloudflare.d.ts +35 -0
- package/dist/lib/providers/cloudflare.js +174 -0
- package/dist/lib/providers/cohere.d.ts +52 -0
- package/dist/lib/providers/cohere.js +253 -0
- package/dist/lib/providers/deepseek.js +72 -17
- package/dist/lib/providers/fireworks.d.ts +33 -0
- package/dist/lib/providers/fireworks.js +164 -0
- package/dist/lib/providers/googleAiStudio.d.ts +11 -3
- package/dist/lib/providers/googleAiStudio.js +336 -344
- package/dist/lib/providers/googleNativeGemini3.d.ts +107 -2
- package/dist/lib/providers/googleNativeGemini3.js +381 -25
- package/dist/lib/providers/googleVertex.d.ts +116 -129
- package/dist/lib/providers/googleVertex.js +3002 -1988
- package/dist/lib/providers/groq.d.ts +33 -0
- package/dist/lib/providers/groq.js +181 -0
- package/dist/lib/providers/huggingFace.js +9 -8
- package/dist/lib/providers/ideogram.d.ts +34 -0
- package/dist/lib/providers/ideogram.js +184 -0
- package/dist/lib/providers/index.d.ts +13 -0
- package/dist/lib/providers/index.js +13 -0
- package/dist/lib/providers/jina.d.ts +59 -0
- package/dist/lib/providers/jina.js +218 -0
- package/dist/lib/providers/llamaCpp.js +14 -46
- package/dist/lib/providers/lmStudio.js +14 -47
- package/dist/lib/providers/mistral.js +7 -7
- package/dist/lib/providers/nvidiaNim.js +160 -19
- package/dist/lib/providers/ollama.js +7 -7
- package/dist/lib/providers/openAI.d.ts +22 -1
- package/dist/lib/providers/openAI.js +181 -0
- package/dist/lib/providers/openRouter.js +38 -22
- package/dist/lib/providers/openaiCompatible.js +9 -8
- package/dist/lib/providers/perplexity.d.ts +33 -0
- package/dist/lib/providers/perplexity.js +179 -0
- package/dist/lib/providers/recraft.d.ts +34 -0
- package/dist/lib/providers/recraft.js +197 -0
- package/dist/lib/providers/replicate.d.ts +75 -0
- package/dist/lib/providers/replicate.js +403 -0
- package/dist/lib/providers/stability.d.ts +37 -0
- package/dist/lib/providers/stability.js +191 -0
- package/dist/lib/providers/togetherAi.d.ts +33 -0
- package/dist/lib/providers/togetherAi.js +176 -0
- package/dist/lib/providers/voyage.d.ts +47 -0
- package/dist/lib/providers/voyage.js +177 -0
- package/dist/lib/providers/xai.d.ts +33 -0
- package/dist/lib/providers/xai.js +172 -0
- package/dist/lib/telemetry/index.d.ts +1 -1
- package/dist/lib/telemetry/index.js +1 -1
- package/dist/lib/telemetry/tracers.d.ts +19 -0
- package/dist/lib/telemetry/tracers.js +19 -0
- package/dist/lib/telemetry/withSpan.d.ts +35 -0
- package/dist/lib/telemetry/withSpan.js +103 -0
- package/dist/lib/types/aliases.d.ts +14 -0
- package/dist/lib/types/avatar.d.ts +143 -0
- package/dist/lib/types/avatar.js +20 -0
- package/dist/lib/types/cli.d.ts +6 -0
- package/dist/lib/types/common.d.ts +0 -3
- package/dist/lib/types/conversation.d.ts +10 -3
- package/dist/lib/types/generate.d.ts +76 -5
- package/dist/lib/types/index.d.ts +6 -0
- package/dist/lib/types/index.js +8 -0
- package/dist/lib/types/memory.d.ts +96 -0
- package/dist/lib/types/memory.js +23 -0
- package/dist/lib/types/middleware.d.ts +27 -0
- package/dist/lib/types/multimodal.d.ts +35 -2
- package/dist/lib/types/music.d.ts +165 -0
- package/dist/lib/types/music.js +21 -0
- package/dist/lib/types/providers.d.ts +284 -3
- package/dist/lib/types/replicate.d.ts +67 -0
- package/dist/lib/types/replicate.js +10 -0
- package/dist/lib/types/safeFetch.d.ts +15 -0
- package/dist/lib/types/safeFetch.js +7 -0
- package/dist/lib/types/stream.d.ts +8 -1
- package/dist/lib/types/tools.d.ts +13 -0
- package/dist/lib/types/video.d.ts +89 -0
- package/dist/lib/types/video.js +15 -0
- package/dist/lib/utils/avatarProcessor.d.ts +68 -0
- package/dist/lib/utils/avatarProcessor.js +172 -0
- package/dist/lib/utils/cloneOptions.d.ts +36 -0
- package/dist/lib/utils/cloneOptions.js +62 -0
- package/dist/lib/utils/lifecycleCallbacks.d.ts +56 -0
- package/dist/lib/utils/lifecycleCallbacks.js +100 -0
- package/dist/lib/utils/lifecycleTimeout.d.ts +25 -0
- package/dist/lib/utils/lifecycleTimeout.js +39 -0
- package/dist/lib/utils/logSanitize.d.ts +49 -0
- package/dist/lib/utils/logSanitize.js +170 -0
- package/dist/lib/utils/loggingFetch.d.ts +29 -0
- package/dist/lib/utils/loggingFetch.js +60 -0
- package/dist/lib/utils/messageBuilder.d.ts +10 -0
- package/dist/lib/utils/messageBuilder.js +83 -30
- package/dist/lib/utils/modelChoices.js +236 -3
- package/dist/lib/utils/modelDetection.d.ts +11 -0
- package/dist/lib/utils/modelDetection.js +27 -0
- package/dist/lib/utils/musicProcessor.d.ts +67 -0
- package/dist/lib/utils/musicProcessor.js +189 -0
- package/dist/lib/utils/optionsConversion.js +3 -2
- package/dist/lib/utils/parameterValidation.js +14 -4
- package/dist/lib/utils/pricing.js +193 -0
- package/dist/lib/utils/providerConfig.d.ts +55 -0
- package/dist/lib/utils/providerConfig.js +224 -0
- package/dist/lib/utils/providerHealth.js +7 -7
- package/dist/lib/utils/safeFetch.d.ts +26 -0
- package/dist/lib/utils/safeFetch.js +83 -0
- package/dist/lib/utils/schemaConversion.d.ts +1 -1
- package/dist/lib/utils/schemaConversion.js +59 -4
- package/dist/lib/utils/sizeGuard.d.ts +34 -0
- package/dist/lib/utils/sizeGuard.js +45 -0
- package/dist/lib/utils/ssrfGuard.d.ts +52 -0
- package/dist/lib/utils/ssrfGuard.js +411 -0
- package/dist/lib/utils/tokenLimits.js +23 -32
- package/dist/lib/utils/videoProcessor.d.ts +60 -0
- package/dist/lib/utils/videoProcessor.js +201 -0
- package/dist/lib/voice/providers/FishAudioTTS.d.ts +27 -0
- package/dist/lib/voice/providers/FishAudioTTS.js +183 -0
- package/dist/lib/workflow/core/ensembleExecutor.js +26 -9
- package/dist/memory/hippocampusInitializer.d.ts +2 -2
- package/dist/memory/hippocampusInitializer.js +32 -2
- package/dist/middleware/builtin/lifecycle.js +52 -51
- package/dist/music/index.d.ts +13 -0
- package/dist/music/index.js +13 -0
- package/dist/music/providers/BeatovenMusic.d.ts +31 -0
- package/dist/music/providers/BeatovenMusic.js +333 -0
- package/dist/music/providers/ElevenLabsMusic.d.ts +30 -0
- package/dist/music/providers/ElevenLabsMusic.js +168 -0
- package/dist/music/providers/LyriaMusic.d.ts +29 -0
- package/dist/music/providers/LyriaMusic.js +172 -0
- package/dist/music/providers/ReplicateMusic.d.ts +31 -0
- package/dist/music/providers/ReplicateMusic.js +261 -0
- package/dist/neurolink.d.ts +30 -0
- package/dist/neurolink.js +342 -49
- package/dist/providers/amazonBedrock.d.ts +10 -0
- package/dist/providers/amazonBedrock.js +94 -39
- package/dist/providers/anthropic.js +55 -7
- package/dist/providers/anthropicBaseProvider.js +1 -1
- package/dist/providers/azureOpenai.js +66 -17
- package/dist/providers/cloudflare.d.ts +35 -0
- package/dist/providers/cloudflare.js +173 -0
- package/dist/providers/cohere.d.ts +52 -0
- package/dist/providers/cohere.js +252 -0
- package/dist/providers/deepseek.js +72 -17
- package/dist/providers/fireworks.d.ts +33 -0
- package/dist/providers/fireworks.js +163 -0
- package/dist/providers/googleAiStudio.d.ts +11 -3
- package/dist/providers/googleAiStudio.js +335 -344
- package/dist/providers/googleNativeGemini3.d.ts +107 -2
- package/dist/providers/googleNativeGemini3.js +381 -25
- package/dist/providers/googleVertex.d.ts +116 -129
- package/dist/providers/googleVertex.js +3000 -1987
- package/dist/providers/groq.d.ts +33 -0
- package/dist/providers/groq.js +180 -0
- package/dist/providers/huggingFace.js +9 -8
- package/dist/providers/ideogram.d.ts +34 -0
- package/dist/providers/ideogram.js +183 -0
- package/dist/providers/index.d.ts +13 -0
- package/dist/providers/index.js +13 -0
- package/dist/providers/jina.d.ts +59 -0
- package/dist/providers/jina.js +217 -0
- package/dist/providers/llamaCpp.js +14 -46
- package/dist/providers/lmStudio.js +14 -47
- package/dist/providers/mistral.js +7 -7
- package/dist/providers/nvidiaNim.js +160 -19
- package/dist/providers/ollama.js +7 -7
- package/dist/providers/openAI.d.ts +22 -1
- package/dist/providers/openAI.js +181 -0
- package/dist/providers/openRouter.js +38 -22
- package/dist/providers/openaiCompatible.js +9 -8
- package/dist/providers/perplexity.d.ts +33 -0
- package/dist/providers/perplexity.js +178 -0
- package/dist/providers/recraft.d.ts +34 -0
- package/dist/providers/recraft.js +196 -0
- package/dist/providers/replicate.d.ts +75 -0
- package/dist/providers/replicate.js +402 -0
- package/dist/providers/stability.d.ts +37 -0
- package/dist/providers/stability.js +190 -0
- package/dist/providers/togetherAi.d.ts +33 -0
- package/dist/providers/togetherAi.js +175 -0
- package/dist/providers/voyage.d.ts +47 -0
- package/dist/providers/voyage.js +176 -0
- package/dist/providers/xai.d.ts +33 -0
- package/dist/providers/xai.js +171 -0
- package/dist/telemetry/index.d.ts +1 -1
- package/dist/telemetry/index.js +1 -1
- package/dist/telemetry/tracers.d.ts +19 -0
- package/dist/telemetry/tracers.js +19 -0
- package/dist/telemetry/withSpan.d.ts +35 -0
- package/dist/telemetry/withSpan.js +103 -0
- package/dist/types/aliases.d.ts +14 -0
- package/dist/types/avatar.d.ts +143 -0
- package/dist/types/avatar.js +19 -0
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/common.d.ts +0 -3
- package/dist/types/conversation.d.ts +10 -3
- package/dist/types/generate.d.ts +76 -5
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.js +8 -0
- package/dist/types/memory.d.ts +96 -0
- package/dist/types/memory.js +22 -0
- package/dist/types/middleware.d.ts +27 -0
- package/dist/types/multimodal.d.ts +35 -2
- package/dist/types/music.d.ts +165 -0
- package/dist/types/music.js +20 -0
- package/dist/types/providers.d.ts +284 -3
- package/dist/types/replicate.d.ts +67 -0
- package/dist/types/replicate.js +9 -0
- package/dist/types/safeFetch.d.ts +15 -0
- package/dist/types/safeFetch.js +6 -0
- package/dist/types/stream.d.ts +8 -1
- package/dist/types/tools.d.ts +13 -0
- package/dist/types/video.d.ts +89 -0
- package/dist/types/video.js +14 -0
- package/dist/utils/avatarProcessor.d.ts +68 -0
- package/dist/utils/avatarProcessor.js +171 -0
- package/dist/utils/cloneOptions.d.ts +36 -0
- package/dist/utils/cloneOptions.js +61 -0
- package/dist/utils/lifecycleCallbacks.d.ts +56 -0
- package/dist/utils/lifecycleCallbacks.js +99 -0
- package/dist/utils/lifecycleTimeout.d.ts +25 -0
- package/dist/utils/lifecycleTimeout.js +38 -0
- package/dist/utils/logSanitize.d.ts +49 -0
- package/dist/utils/logSanitize.js +169 -0
- package/dist/utils/loggingFetch.d.ts +29 -0
- package/dist/utils/loggingFetch.js +59 -0
- package/dist/utils/messageBuilder.d.ts +10 -0
- package/dist/utils/messageBuilder.js +83 -30
- package/dist/utils/modelChoices.js +236 -3
- package/dist/utils/modelDetection.d.ts +11 -0
- package/dist/utils/modelDetection.js +27 -0
- package/dist/utils/musicProcessor.d.ts +67 -0
- package/dist/utils/musicProcessor.js +188 -0
- package/dist/utils/optionsConversion.js +3 -2
- package/dist/utils/parameterValidation.js +14 -4
- package/dist/utils/pricing.js +193 -0
- package/dist/utils/providerConfig.d.ts +55 -0
- package/dist/utils/providerConfig.js +224 -0
- package/dist/utils/providerHealth.js +7 -7
- package/dist/utils/safeFetch.d.ts +26 -0
- package/dist/utils/safeFetch.js +82 -0
- package/dist/utils/schemaConversion.d.ts +1 -1
- package/dist/utils/schemaConversion.js +59 -4
- package/dist/utils/sizeGuard.d.ts +34 -0
- package/dist/utils/sizeGuard.js +44 -0
- package/dist/utils/ssrfGuard.d.ts +52 -0
- package/dist/utils/ssrfGuard.js +410 -0
- package/dist/utils/tokenLimits.js +23 -32
- package/dist/utils/videoProcessor.d.ts +60 -0
- package/dist/utils/videoProcessor.js +200 -0
- package/dist/voice/providers/FishAudioTTS.d.ts +27 -0
- package/dist/voice/providers/FishAudioTTS.js +182 -0
- package/dist/workflow/core/ensembleExecutor.js +26 -9
- package/package.json +42 -8
package/dist/lib/neurolink.js
CHANGED
|
@@ -62,6 +62,9 @@ import { tracers } from "./telemetry/tracers.js";
|
|
|
62
62
|
import { getConversationMessages, storeConversationTurn, } from "./utils/conversationMemory.js";
|
|
63
63
|
// Enhanced error handling imports
|
|
64
64
|
import { CircuitBreaker, ERROR_CODES, ErrorFactory, isAbortError, isRetriableError, logStructuredError, NeuroLinkError, withRetry, withTimeout, } from "./utils/errorHandling.js";
|
|
65
|
+
import { hasLifecycleErrorFired, markLifecycleErrorFired, } from "./utils/lifecycleCallbacks.js";
|
|
66
|
+
import { resolveLifecycleTimeoutMs } from "./utils/lifecycleTimeout.js";
|
|
67
|
+
import { cloneOptionsForCallIsolation } from "./utils/cloneOptions.js";
|
|
65
68
|
// Factory processing imports
|
|
66
69
|
import { createCleanStreamOptions, enhanceTextGenerationOptions, processFactoryOptions, processStreamingFactoryOptions, validateFactoryConfig, } from "./utils/factoryProcessing.js";
|
|
67
70
|
import { logger, mcpLogger } from "./utils/logger.js";
|
|
@@ -333,7 +336,30 @@ export function markStreamProviderEmittedGenerationEnd(options) {
|
|
|
333
336
|
ctx.providerEmitted = true;
|
|
334
337
|
}
|
|
335
338
|
}
|
|
339
|
+
/**
|
|
340
|
+
* Symbol-based brand for cross-module identification without circular imports.
|
|
341
|
+
*
|
|
342
|
+
* Provider constructors receive `sdk?: unknown` (the factory layer's
|
|
343
|
+
* contract). Rather than duck-typing via `"getInMemoryServers" in sdk`,
|
|
344
|
+
* use `isNeuroLink(value)` from this module to do a brand check —
|
|
345
|
+
* survives minification AND doesn't rely on method-name stability.
|
|
346
|
+
*/
|
|
347
|
+
export const NEUROLINK_BRAND = Symbol.for("@juspay/neurolink/sdk-brand");
|
|
348
|
+
/**
|
|
349
|
+
* Type-guard for opaque values that should be a {@link NeuroLink} instance.
|
|
350
|
+
*
|
|
351
|
+
* Designed for the provider-factory boundary where TS can't carry the type
|
|
352
|
+
* through `UnknownRecord` without forcing every caller into a circular
|
|
353
|
+
* dependency. Cheap to call and unaffected by minification.
|
|
354
|
+
*/
|
|
355
|
+
export function isNeuroLink(value) {
|
|
356
|
+
return (typeof value === "object" &&
|
|
357
|
+
value !== null &&
|
|
358
|
+
value[NEUROLINK_BRAND] === true);
|
|
359
|
+
}
|
|
336
360
|
export class NeuroLink {
|
|
361
|
+
/** @internal Brand for cross-module identification — see {@link isNeuroLink}. */
|
|
362
|
+
[NEUROLINK_BRAND] = true;
|
|
337
363
|
mcpInitialized = false;
|
|
338
364
|
mcpSkipped = false;
|
|
339
365
|
mcpInitPromise = null;
|
|
@@ -2753,7 +2779,66 @@ Current user's request: ${currentInput}`;
|
|
|
2753
2779
|
* @since 1.0.0
|
|
2754
2780
|
*/
|
|
2755
2781
|
async generate(optionsOrPrompt) {
|
|
2756
|
-
|
|
2782
|
+
// Defensive call-isolation clone — mirrors stream(): downstream
|
|
2783
|
+
// generate-prep (memory retrieval, orchestration, RAG/MCP tool
|
|
2784
|
+
// injection) mutates nested branches on the caller-supplied options
|
|
2785
|
+
// object. Without cloning here, callers reusing a single options
|
|
2786
|
+
// bag across generate() calls accumulate state across them.
|
|
2787
|
+
// String prompts are immutable, so they pass through.
|
|
2788
|
+
if (typeof optionsOrPrompt !== "string") {
|
|
2789
|
+
optionsOrPrompt = cloneOptionsForCallIsolation(optionsOrPrompt);
|
|
2790
|
+
}
|
|
2791
|
+
const startedAt = Date.now();
|
|
2792
|
+
try {
|
|
2793
|
+
return await this.runWithFallbackOrchestration(optionsOrPrompt, "generate", (opts) => tracers.sdk.startActiveSpan("neurolink.generate", { kind: SpanKind.INTERNAL }, (generateSpan) => this.executeGenerateWithMetricsContext(opts, generateSpan)));
|
|
2794
|
+
}
|
|
2795
|
+
catch (error) {
|
|
2796
|
+
// Lifecycle middleware (wrapGenerate.catch in builtin/lifecycle.ts)
|
|
2797
|
+
// stamps errors it already surfaced with the shared Symbol marker
|
|
2798
|
+
// (see utils/lifecycleCallbacks.ts). For errors thrown BEFORE the
|
|
2799
|
+
// language model was wrapped (e.g. unknown provider name,
|
|
2800
|
+
// validation failures, factory exceptions), the mark is absent —
|
|
2801
|
+
// fire the consumer's onError here so it sees every failure path.
|
|
2802
|
+
// Awaited so async handlers fully settle before generate()
|
|
2803
|
+
// rethrows, matching the middleware-managed path.
|
|
2804
|
+
await this.fireConsumerOnErrorIfNotFired(optionsOrPrompt, error, startedAt);
|
|
2805
|
+
throw error;
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
async fireConsumerOnErrorIfNotFired(optionsOrPrompt, error, startedAt) {
|
|
2809
|
+
if (hasLifecycleErrorFired(error)) {
|
|
2810
|
+
return;
|
|
2811
|
+
}
|
|
2812
|
+
if (typeof optionsOrPrompt !== "object" || optionsOrPrompt === null) {
|
|
2813
|
+
return;
|
|
2814
|
+
}
|
|
2815
|
+
const opts = optionsOrPrompt;
|
|
2816
|
+
const userOnError = opts.onError;
|
|
2817
|
+
if (!userOnError) {
|
|
2818
|
+
return;
|
|
2819
|
+
}
|
|
2820
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
2821
|
+
// Bound the consumer callback so a never-settling handler can't hang
|
|
2822
|
+
// generate()/stream(). The deadline honors per-call
|
|
2823
|
+
// `lifecycle.timeoutMs` and the `NEUROLINK_LIFECYCLE_TIMEOUT_MS` env
|
|
2824
|
+
// var (CLI surface), falling back to 5_000. Errors raised here are
|
|
2825
|
+
// logged and swallowed; the original failure still propagates to the
|
|
2826
|
+
// caller because the outer catch re-throws.
|
|
2827
|
+
const lifecycle = opts.middleware?.middlewareConfig?.lifecycle?.config;
|
|
2828
|
+
const timeoutMs = resolveLifecycleTimeoutMs(lifecycle);
|
|
2829
|
+
// Mark the error first so the AI-SDK lifecycle middleware can't
|
|
2830
|
+
// re-fire the same callback if the throw races a parallel catch.
|
|
2831
|
+
markLifecycleErrorFired(err);
|
|
2832
|
+
try {
|
|
2833
|
+
await withTimeout(Promise.resolve(userOnError({
|
|
2834
|
+
error: err,
|
|
2835
|
+
duration: Date.now() - startedAt,
|
|
2836
|
+
recoverable: false,
|
|
2837
|
+
})), timeoutMs, new Error(`consumer onError callback timed out after ${timeoutMs}ms`));
|
|
2838
|
+
}
|
|
2839
|
+
catch (e) {
|
|
2840
|
+
logger.warn("[NeuroLink] consumer onError callback error:", e);
|
|
2841
|
+
}
|
|
2757
2842
|
}
|
|
2758
2843
|
/**
|
|
2759
2844
|
* Curator P2-3: wraps a generate/stream call with the fallback
|
|
@@ -2838,15 +2923,23 @@ Current user's request: ${currentInput}`;
|
|
|
2838
2923
|
catch {
|
|
2839
2924
|
/* listener errors are non-fatal */
|
|
2840
2925
|
}
|
|
2926
|
+
// Defensive call-isolation clone for the retry attempt. The shallow
|
|
2927
|
+
// spread below would keep nested branches (`input`, `tools`, `memory`,
|
|
2928
|
+
// `rag`, …) pointing at the same objects the previous attempt's
|
|
2929
|
+
// prepare stages mutated — so the retry inherits e.g. memory-retrieved
|
|
2930
|
+
// history appended to `input.messages`, RAG-injected tools, etc.
|
|
2931
|
+
// Re-cloning at the retry boundary mirrors the entry-level isolation
|
|
2932
|
+
// applied in generate()/stream() so each fallback attempt sees a
|
|
2933
|
+
// fresh options bag.
|
|
2841
2934
|
const retriedOptions = typeof optionsOrPrompt === "object"
|
|
2842
|
-
? {
|
|
2935
|
+
? cloneOptionsForCallIsolation({
|
|
2843
2936
|
...optionsOrPrompt,
|
|
2844
2937
|
...(next.provider && { provider: next.provider }),
|
|
2845
2938
|
...(next.model && { model: next.model }),
|
|
2846
2939
|
// Strip the fallback hooks so the retry doesn't re-orchestrate.
|
|
2847
2940
|
providerFallback: undefined,
|
|
2848
2941
|
modelChain: undefined,
|
|
2849
|
-
}
|
|
2942
|
+
})
|
|
2850
2943
|
: optionsOrPrompt;
|
|
2851
2944
|
const retryAttempt = await this.attemptInner(inner, retriedOptions);
|
|
2852
2945
|
if ("ok" in retryAttempt) {
|
|
@@ -2922,6 +3015,12 @@ Current user's request: ${currentInput}`;
|
|
|
2922
3015
|
const options = typeof optionsOrPrompt === "string"
|
|
2923
3016
|
? { input: { text: optionsOrPrompt } }
|
|
2924
3017
|
: { ...optionsOrPrompt };
|
|
3018
|
+
// Normalise: all downstream code assumes options.input is defined.
|
|
3019
|
+
// Media-only callers may omit `input` entirely (or pass `input: {}`);
|
|
3020
|
+
// synthesise an empty shell so the rest of the pipeline can rely on it.
|
|
3021
|
+
if (!options.input) {
|
|
3022
|
+
options.input = {};
|
|
3023
|
+
}
|
|
2925
3024
|
// Dynamic argument resolution — resolve any function-valued options before downstream use
|
|
2926
3025
|
await this.resolveDynamicOptions(options);
|
|
2927
3026
|
options.model = resolveModel(options.model, this.modelAliasConfig);
|
|
@@ -2932,13 +3031,28 @@ Current user's request: ${currentInput}`;
|
|
|
2932
3031
|
? optionsOrPrompt.length
|
|
2933
3032
|
: options.input?.text?.length || 0);
|
|
2934
3033
|
generateSpan.setAttribute("neurolink.has_tools", !!(options.tools && Object.keys(options.tools).length > 0));
|
|
2935
|
-
//
|
|
2936
|
-
//
|
|
3034
|
+
// Ensure options.input is always an object — callers may omit it for
|
|
3035
|
+
// media-only modes (avatar / music / video) or STT flows. Downstream code
|
|
3036
|
+
// accesses it unconditionally, so we guarantee a non-null object here and
|
|
3037
|
+
// rely on the per-mode checks below to populate / validate the text field.
|
|
3038
|
+
options.input ??= {};
|
|
3039
|
+
// When STT audio is provided, ensure options.input.text is initialised
|
|
3040
|
+
// (the transcription will supply the text inside runStandardGenerateRequest).
|
|
2937
3041
|
const hasSttAudio = !!(options.stt?.enabled && options.stt?.audio);
|
|
2938
|
-
if (hasSttAudio && !options.input) {
|
|
2939
|
-
options.input =
|
|
2940
|
-
}
|
|
2941
|
-
|
|
3042
|
+
if (hasSttAudio && !options.input.text) {
|
|
3043
|
+
options.input.text = "";
|
|
3044
|
+
}
|
|
3045
|
+
// Modality dispatch (video / avatar / music) carries the prompt inside
|
|
3046
|
+
// `output.{video|avatar|music}` — input.text is not meaningful for these
|
|
3047
|
+
// modes. Synthesize an empty input.text and skip validation, mirroring
|
|
3048
|
+
// the STT-audio exception above.
|
|
3049
|
+
const isMediaModalityMode = options.output?.mode === "video" ||
|
|
3050
|
+
options.output?.mode === "avatar" ||
|
|
3051
|
+
options.output?.mode === "music";
|
|
3052
|
+
if (isMediaModalityMode && !options.input.text) {
|
|
3053
|
+
options.input.text = "";
|
|
3054
|
+
}
|
|
3055
|
+
if (!hasSttAudio && !isMediaModalityMode) {
|
|
2942
3056
|
this.assertInputText(options.input?.text, "Input text is required and must be a non-empty string");
|
|
2943
3057
|
}
|
|
2944
3058
|
this.enforceSessionBudget(options.maxBudgetUsd);
|
|
@@ -2948,6 +3062,16 @@ Current user's request: ${currentInput}`;
|
|
|
2948
3062
|
}
|
|
2949
3063
|
async maybeHandleEarlyGenerateResult(options, generateSpan) {
|
|
2950
3064
|
if (options.workflow || options.workflowConfig) {
|
|
3065
|
+
// Workflow engine operates on text; media generation modes (avatar, music,
|
|
3066
|
+
// video, ppt) use dedicated code paths and are incompatible with workflows.
|
|
3067
|
+
const workflowMediaMode = options.output?.mode;
|
|
3068
|
+
if (workflowMediaMode === "avatar" ||
|
|
3069
|
+
workflowMediaMode === "music" ||
|
|
3070
|
+
workflowMediaMode === "video" ||
|
|
3071
|
+
workflowMediaMode === "ppt") {
|
|
3072
|
+
throw new Error(`Workflow mode is not compatible with output.mode="${workflowMediaMode}". ` +
|
|
3073
|
+
'Remove the workflow config or use output.mode="text".');
|
|
3074
|
+
}
|
|
2951
3075
|
if (options.stt?.enabled && options.stt?.audio) {
|
|
2952
3076
|
// prepareGenerateRequest synthesizes input.text = "" for audio-only
|
|
2953
3077
|
// calls, so without this guard generateWithWorkflow runs with an
|
|
@@ -2959,6 +3083,12 @@ Current user's request: ${currentInput}`;
|
|
|
2959
3083
|
}
|
|
2960
3084
|
return this.generateWithWorkflow(options);
|
|
2961
3085
|
}
|
|
3086
|
+
if (options.output?.mode === "music") {
|
|
3087
|
+
return this.generateWithMusic(options, generateSpan);
|
|
3088
|
+
}
|
|
3089
|
+
if (options.output?.mode === "avatar") {
|
|
3090
|
+
return this.generateWithAvatar(options, generateSpan);
|
|
3091
|
+
}
|
|
2962
3092
|
if (options.output?.mode !== "ppt") {
|
|
2963
3093
|
return null;
|
|
2964
3094
|
}
|
|
@@ -3076,7 +3206,7 @@ Current user's request: ${currentInput}`;
|
|
|
3076
3206
|
originalProvider: options.provider || "auto",
|
|
3077
3207
|
orchestratedProvider: orchestratedOptions.provider,
|
|
3078
3208
|
orchestratedModel: orchestratedOptions.model,
|
|
3079
|
-
prompt: options.input
|
|
3209
|
+
prompt: (options.input?.text ?? "").substring(0, 100),
|
|
3080
3210
|
});
|
|
3081
3211
|
Object.assign(options, orchestratedOptions);
|
|
3082
3212
|
if (orchestratedOptions.model) {
|
|
@@ -3121,12 +3251,22 @@ Current user's request: ${currentInput}`;
|
|
|
3121
3251
|
});
|
|
3122
3252
|
}
|
|
3123
3253
|
}
|
|
3124
|
-
|
|
3254
|
+
// Media-only modes (avatar, music, video, ppt) do not have a meaningful
|
|
3255
|
+
// text prompt to augment with memory — skip injection to avoid corrupting
|
|
3256
|
+
// the empty/synthesized input.text that was set for these modes.
|
|
3257
|
+
const mediaOnlyMode = options.output?.mode === "avatar" ||
|
|
3258
|
+
options.output?.mode === "music" ||
|
|
3259
|
+
options.output?.mode === "video" ||
|
|
3260
|
+
options.output?.mode === "ppt";
|
|
3261
|
+
if (mediaOnlyMode ||
|
|
3262
|
+
!this.shouldReadMemory(options.memory, options.context?.userId) ||
|
|
3125
3263
|
!options.context?.userId) {
|
|
3126
3264
|
return;
|
|
3127
3265
|
}
|
|
3128
3266
|
try {
|
|
3129
|
-
|
|
3267
|
+
if (options.input) {
|
|
3268
|
+
options.input.text = await this.retrieveMemory(options.input.text ?? "", options.context.userId, options.memory?.additionalUsers);
|
|
3269
|
+
}
|
|
3130
3270
|
logger.debug("Memory retrieval successful (generate)");
|
|
3131
3271
|
}
|
|
3132
3272
|
catch (error) {
|
|
@@ -3135,7 +3275,7 @@ Current user's request: ${currentInput}`;
|
|
|
3135
3275
|
}
|
|
3136
3276
|
async buildGenerateTextOptions(options, originalPrompt, factoryResult) {
|
|
3137
3277
|
const baseOptions = {
|
|
3138
|
-
prompt: options.input
|
|
3278
|
+
prompt: options.input?.text,
|
|
3139
3279
|
provider: options.provider,
|
|
3140
3280
|
model: options.model,
|
|
3141
3281
|
temperature: options.temperature,
|
|
@@ -3167,6 +3307,12 @@ Current user's request: ${currentInput}`;
|
|
|
3167
3307
|
middleware: options.middleware,
|
|
3168
3308
|
conversationMessages: options.conversationMessages,
|
|
3169
3309
|
credentials: options.credentials,
|
|
3310
|
+
// Lifecycle callbacks must reach the provider so non-AI-SDK paths
|
|
3311
|
+
// (Vertex's native @google/genai, native Bedrock, Ollama, etc.) can
|
|
3312
|
+
// invoke them directly. Pipeline A also still receives them via the
|
|
3313
|
+
// wrapped middleware config set by applyGenerateLifecycleMiddleware.
|
|
3314
|
+
onFinish: options.onFinish,
|
|
3315
|
+
onError: options.onError,
|
|
3170
3316
|
};
|
|
3171
3317
|
const extraContext = options;
|
|
3172
3318
|
if (extraContext.sessionId || extraContext.userId) {
|
|
@@ -3185,11 +3331,11 @@ Current user's request: ${currentInput}`;
|
|
|
3185
3331
|
textOptions.conversationMemoryConfig = this.conversationMemory.config;
|
|
3186
3332
|
textOptions.originalPrompt = originalPrompt;
|
|
3187
3333
|
}
|
|
3188
|
-
const { toolResults, enhancedPrompt } = await this.detectAndExecuteTools(textOptions.prompt || options.input
|
|
3334
|
+
const { toolResults, enhancedPrompt } = await this.detectAndExecuteTools(textOptions.prompt || options.input?.text || "", factoryResult.domainType);
|
|
3189
3335
|
if (enhancedPrompt !== textOptions.prompt) {
|
|
3190
3336
|
textOptions.prompt = enhancedPrompt;
|
|
3191
3337
|
logger.debug("Enhanced prompt with tool results", {
|
|
3192
|
-
originalLength: options.input
|
|
3338
|
+
originalLength: (options.input?.text ?? "").length,
|
|
3193
3339
|
enhancedLength: enhancedPrompt.length,
|
|
3194
3340
|
toolResults: toolResults.length,
|
|
3195
3341
|
});
|
|
@@ -3198,26 +3344,35 @@ Current user's request: ${currentInput}`;
|
|
|
3198
3344
|
}
|
|
3199
3345
|
finalizeGenerateRequestResult(params) {
|
|
3200
3346
|
const { generateSpan, options, textOptions, textResult, factoryResult, originalPrompt, startTime, } = params;
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3347
|
+
// Skip the top-level `generation:end` emission when the provider already
|
|
3348
|
+
// emitted it from its native generate path (Vertex / Google AI Studio).
|
|
3349
|
+
// Without this guard, native-path providers would surface TWO events
|
|
3350
|
+
// per generate call (Pipeline A path: 1 from provider native + 1 here;
|
|
3351
|
+
// standard AI-SDK path: 1 here). The observability suite asserts on
|
|
3352
|
+
// emission count and would (and did) fail.
|
|
3353
|
+
const nativeAlreadyEmitted = !!textResult._generationEndEmitted;
|
|
3354
|
+
if (!nativeAlreadyEmitted) {
|
|
3355
|
+
this.emitter.emit("generation:end", {
|
|
3356
|
+
provider: textResult.provider,
|
|
3357
|
+
responseTime: Date.now() - startTime,
|
|
3358
|
+
toolsUsed: textResult.toolsUsed,
|
|
3359
|
+
timestamp: Date.now(),
|
|
3360
|
+
result: textResult,
|
|
3361
|
+
// Use the effective prompt (which already incorporates STT-transcribed
|
|
3362
|
+
// text for audio-only calls) so observers see the real prompt instead
|
|
3363
|
+
// of an empty string. Falls back through the same chain as before for
|
|
3364
|
+
// text-only calls.
|
|
3365
|
+
prompt: originalPrompt ||
|
|
3366
|
+
options.input?.text ||
|
|
3367
|
+
options.prompt,
|
|
3368
|
+
temperature: textOptions.temperature,
|
|
3369
|
+
maxTokens: textOptions.maxTokens,
|
|
3370
|
+
// A2 fix: Signal that Pipeline A (AI SDK → @langfuse/otel) already
|
|
3371
|
+
// creates a GENERATION observation for this call. The generation:end
|
|
3372
|
+
// listener should skip creating a duplicate Pipeline B span.
|
|
3373
|
+
pipelineAHandled: true,
|
|
3374
|
+
});
|
|
3375
|
+
}
|
|
3221
3376
|
this.emitter.emit("response:end", textResult.content || "");
|
|
3222
3377
|
this.emitter.emit("message", `Generation completed in ${Date.now() - startTime}ms`);
|
|
3223
3378
|
const generateResult = {
|
|
@@ -3255,7 +3410,18 @@ Current user's request: ${currentInput}`;
|
|
|
3255
3410
|
audio: textResult.audio,
|
|
3256
3411
|
transcription: textResult.transcription,
|
|
3257
3412
|
video: textResult.video,
|
|
3413
|
+
avatar: textResult.avatar,
|
|
3414
|
+
music: textResult.music,
|
|
3258
3415
|
ppt: textResult.ppt,
|
|
3416
|
+
// Forward reasoning/reasoningTokens from the provider layer.
|
|
3417
|
+
// BaseProvider's GenerationHandler extracts these from AI-SDK reasoning
|
|
3418
|
+
// parts (DeepSeek's `reasoning_content`, Anthropic thinking blocks,
|
|
3419
|
+
// Gemini thought parts, OpenAI o1) and they're declared on
|
|
3420
|
+
// `GenerateResult`, but the builder previously dropped them on the
|
|
3421
|
+
// floor — so callers asking for `result.reasoning` got `undefined`
|
|
3422
|
+
// even when the model emitted a chain-of-thought.
|
|
3423
|
+
reasoning: textResult.reasoning,
|
|
3424
|
+
reasoningTokens: textResult.reasoningTokens,
|
|
3259
3425
|
...(textResult.retries && { retries: textResult.retries }),
|
|
3260
3426
|
};
|
|
3261
3427
|
if (generateResult.analytics?.cost && generateResult.analytics.cost > 0) {
|
|
@@ -3348,6 +3514,67 @@ Current user's request: ${currentInput}`;
|
|
|
3348
3514
|
ppt: pptResult,
|
|
3349
3515
|
};
|
|
3350
3516
|
}
|
|
3517
|
+
/**
|
|
3518
|
+
* Dispatch a music-generation request to the registered music handler
|
|
3519
|
+
* for the provider named in `options.output.music.provider`.
|
|
3520
|
+
*/
|
|
3521
|
+
async generateWithMusic(options, generateSpan) {
|
|
3522
|
+
const startTime = Date.now();
|
|
3523
|
+
const musicOptions = options.output?.music;
|
|
3524
|
+
if (!musicOptions) {
|
|
3525
|
+
throw new Error('output.mode="music" requires output.music with at least { provider, prompt }.');
|
|
3526
|
+
}
|
|
3527
|
+
const providerName = musicOptions.provider;
|
|
3528
|
+
if (!providerName) {
|
|
3529
|
+
throw new Error('output.music.provider is required (e.g. "beatoven", "elevenlabs-music", "lyria", "replicate").');
|
|
3530
|
+
}
|
|
3531
|
+
const { MusicProcessor } = await import("./utils/musicProcessor.js");
|
|
3532
|
+
const musicResult = await MusicProcessor.generate(providerName, {
|
|
3533
|
+
...musicOptions,
|
|
3534
|
+
prompt: musicOptions.prompt ?? options.input?.text ?? "",
|
|
3535
|
+
});
|
|
3536
|
+
generateSpan.setAttribute("neurolink.music.provider", providerName);
|
|
3537
|
+
generateSpan.setAttribute("neurolink.music.bytes", musicResult.size);
|
|
3538
|
+
generateSpan.setStatus({ code: SpanStatusCode.OK });
|
|
3539
|
+
return {
|
|
3540
|
+
content: `Music generated (${providerName}, ${musicResult.size} bytes, ${musicResult.format}).`,
|
|
3541
|
+
finishReason: "stop",
|
|
3542
|
+
provider: providerName,
|
|
3543
|
+
model: musicResult.metadata?.model ?? providerName,
|
|
3544
|
+
usage: undefined,
|
|
3545
|
+
responseTime: Date.now() - startTime,
|
|
3546
|
+
music: musicResult,
|
|
3547
|
+
};
|
|
3548
|
+
}
|
|
3549
|
+
/**
|
|
3550
|
+
* Dispatch an avatar (lip-sync) request to the registered avatar handler
|
|
3551
|
+
* for the provider named in `options.output.avatar.provider`.
|
|
3552
|
+
*/
|
|
3553
|
+
async generateWithAvatar(options, generateSpan) {
|
|
3554
|
+
const startTime = Date.now();
|
|
3555
|
+
const avatarOptions = options.output?.avatar;
|
|
3556
|
+
if (!avatarOptions) {
|
|
3557
|
+
throw new Error('output.mode="avatar" requires output.avatar with at least { provider, image, audio|text }.');
|
|
3558
|
+
}
|
|
3559
|
+
const providerName = avatarOptions.provider;
|
|
3560
|
+
if (!providerName) {
|
|
3561
|
+
throw new Error('output.avatar.provider is required (e.g. "d-id", "heygen", "replicate").');
|
|
3562
|
+
}
|
|
3563
|
+
const { AvatarProcessor } = await import("./utils/avatarProcessor.js");
|
|
3564
|
+
const avatarResult = await AvatarProcessor.generate(providerName, avatarOptions);
|
|
3565
|
+
generateSpan.setAttribute("neurolink.avatar.provider", providerName);
|
|
3566
|
+
generateSpan.setAttribute("neurolink.avatar.bytes", avatarResult.size);
|
|
3567
|
+
generateSpan.setStatus({ code: SpanStatusCode.OK });
|
|
3568
|
+
return {
|
|
3569
|
+
content: `Avatar generated (${providerName}, ${avatarResult.size} bytes, ${avatarResult.format}).`,
|
|
3570
|
+
finishReason: "stop",
|
|
3571
|
+
provider: providerName,
|
|
3572
|
+
model: avatarResult.metadata?.model ?? providerName,
|
|
3573
|
+
usage: undefined,
|
|
3574
|
+
responseTime: Date.now() - startTime,
|
|
3575
|
+
avatar: avatarResult,
|
|
3576
|
+
};
|
|
3577
|
+
}
|
|
3351
3578
|
/**
|
|
3352
3579
|
* Generate with workflow engine integration
|
|
3353
3580
|
* Returns both original and processed responses for AB testing
|
|
@@ -3357,7 +3584,7 @@ Current user's request: ${currentInput}`;
|
|
|
3357
3584
|
logger.debug("[NeuroLink] Executing workflow generation", {
|
|
3358
3585
|
workflowId: options.workflow,
|
|
3359
3586
|
hasInlineConfig: !!options.workflowConfig,
|
|
3360
|
-
prompt: options.input
|
|
3587
|
+
prompt: (options.input?.text ?? "").substring(0, 100),
|
|
3361
3588
|
startTime: workflowStartTime,
|
|
3362
3589
|
});
|
|
3363
3590
|
// Determine workflow configuration
|
|
@@ -3378,7 +3605,7 @@ Current user's request: ${currentInput}`;
|
|
|
3378
3605
|
}
|
|
3379
3606
|
// Execute workflow
|
|
3380
3607
|
const workflowResult = await runWorkflow(workflowConfig, {
|
|
3381
|
-
prompt: options.input
|
|
3608
|
+
prompt: options.input?.text ?? "",
|
|
3382
3609
|
conversationHistory: options.conversationMessages
|
|
3383
3610
|
?.filter((m) => m.role === "user" || m.role === "assistant")
|
|
3384
3611
|
.map((m) => ({
|
|
@@ -3457,7 +3684,7 @@ Current user's request: ${currentInput}`;
|
|
|
3457
3684
|
logger.debug("[NeuroLink] Executing workflow streaming (progressive)", {
|
|
3458
3685
|
workflowId: options.workflow,
|
|
3459
3686
|
hasInlineConfig: !!options.workflowConfig,
|
|
3460
|
-
prompt: options.input
|
|
3687
|
+
prompt: (options.input?.text ?? "").substring(0, 100),
|
|
3461
3688
|
});
|
|
3462
3689
|
// Determine workflow configuration
|
|
3463
3690
|
let workflowConfig;
|
|
@@ -3477,7 +3704,7 @@ Current user's request: ${currentInput}`;
|
|
|
3477
3704
|
const { runWorkflowWithStreaming } = await import("./workflow/core/workflowRunner.js");
|
|
3478
3705
|
// Execute workflow with progressive streaming
|
|
3479
3706
|
const workflowStream = runWorkflowWithStreaming(workflowConfig, {
|
|
3480
|
-
prompt: options.input
|
|
3707
|
+
prompt: options.input?.text ?? "",
|
|
3481
3708
|
conversationHistory: options.conversationMessages
|
|
3482
3709
|
?.filter((m) => m.role === "user" || m.role === "assistant")
|
|
3483
3710
|
.map((m) => ({
|
|
@@ -4532,10 +4759,22 @@ Current user's request: ${currentInput}`;
|
|
|
4532
4759
|
availableTools: transformToolsForMCP(transformToolsToExpectedFormat(availableTools)),
|
|
4533
4760
|
audio: result.audio,
|
|
4534
4761
|
video: result.video,
|
|
4762
|
+
avatar: result.avatar,
|
|
4763
|
+
music: result.music,
|
|
4535
4764
|
ppt: result.ppt,
|
|
4536
4765
|
imageOutput: result.imageOutput,
|
|
4537
4766
|
analytics: result.analytics,
|
|
4538
4767
|
evaluation: result.evaluation,
|
|
4768
|
+
// Forward reasoning from provider so callers asking for `result.reasoning`
|
|
4769
|
+
// (DeepSeek `reasoning_content`, Anthropic thinking, Gemini thought parts,
|
|
4770
|
+
// OpenAI o1) actually receive it.
|
|
4771
|
+
reasoning: result.reasoning,
|
|
4772
|
+
reasoningTokens: result.reasoningTokens,
|
|
4773
|
+
// Propagate the native-emission flag so finalizeGenerateRequestResult
|
|
4774
|
+
// skips the public top-level `generation:end` emission when the
|
|
4775
|
+
// provider already emitted it itself (Vertex / Google AI Studio).
|
|
4776
|
+
_generationEndEmitted: result
|
|
4777
|
+
._generationEndEmitted,
|
|
4539
4778
|
};
|
|
4540
4779
|
}
|
|
4541
4780
|
/**
|
|
@@ -4807,9 +5046,19 @@ Current user's request: ${currentInput}`;
|
|
|
4807
5046
|
evaluation: result.evaluation,
|
|
4808
5047
|
audio: result.audio,
|
|
4809
5048
|
video: result.video,
|
|
5049
|
+
avatar: result.avatar,
|
|
5050
|
+
music: result.music,
|
|
4810
5051
|
ppt: result.ppt,
|
|
4811
5052
|
// CRITICAL FIX: Include imageOutput for image generation models
|
|
4812
5053
|
imageOutput: result.imageOutput,
|
|
5054
|
+
// Forward reasoning so callers asking for `result.reasoning`
|
|
5055
|
+
// (DeepSeek `reasoning_content`, Anthropic thinking, Gemini
|
|
5056
|
+
// thought parts, OpenAI o1) actually receive it.
|
|
5057
|
+
reasoning: result.reasoning,
|
|
5058
|
+
reasoningTokens: result.reasoningTokens,
|
|
5059
|
+
// Propagate native-emission flag — see attemptMCPGeneration comment.
|
|
5060
|
+
_generationEndEmitted: result
|
|
5061
|
+
._generationEndEmitted,
|
|
4813
5062
|
};
|
|
4814
5063
|
}
|
|
4815
5064
|
catch (error) {
|
|
@@ -5032,7 +5281,30 @@ Current user's request: ${currentInput}`;
|
|
|
5032
5281
|
: [],
|
|
5033
5282
|
optionKeys: Object.keys(options),
|
|
5034
5283
|
});
|
|
5035
|
-
|
|
5284
|
+
// Defensive shallow clone of top-level options + the nested mutable
|
|
5285
|
+
// branches that downstream stages (prepareStreamOptions's memory
|
|
5286
|
+
// retrieval at `options.input.text`, applyStreamOrchestration's merge,
|
|
5287
|
+
// RAG/MCP tool injection, etc.) mutate. Cloning at the entry point
|
|
5288
|
+
// means callers can reuse a single options object across stream()
|
|
5289
|
+
// calls without accumulating mutations across them — the earlier
|
|
5290
|
+
// shallow rebind at the orchestration site only covered the
|
|
5291
|
+
// top-level keys and left `options.input` shared with the caller.
|
|
5292
|
+
options = cloneOptionsForCallIsolation(options);
|
|
5293
|
+
const startedAt = Date.now();
|
|
5294
|
+
try {
|
|
5295
|
+
return await this.streamWithIterationFallback(options);
|
|
5296
|
+
}
|
|
5297
|
+
catch (error) {
|
|
5298
|
+
// Mirror generate(): fire consumer onError for failures that
|
|
5299
|
+
// happened before the wrapped language-model middleware could
|
|
5300
|
+
// observe them (e.g. unknown provider, validation, factory
|
|
5301
|
+
// exceptions). The shared Symbol marker (lifecycleCallbacks.ts)
|
|
5302
|
+
// prevents double-fire when the AI-SDK lifecycle middleware
|
|
5303
|
+
// already handled the error. Awaited so async handlers fully
|
|
5304
|
+
// settle before stream() rethrows.
|
|
5305
|
+
await this.fireConsumerOnErrorIfNotFired(options, error, startedAt);
|
|
5306
|
+
throw error;
|
|
5307
|
+
}
|
|
5036
5308
|
}
|
|
5037
5309
|
/**
|
|
5038
5310
|
* Curator P2-3 / Reviewer Finding #2: stream-fallback that also covers
|
|
@@ -5626,14 +5898,36 @@ Current user's request: ${currentInput}`;
|
|
|
5626
5898
|
streamResult.usage = streamUsage;
|
|
5627
5899
|
}
|
|
5628
5900
|
if (!streamResult.analytics) {
|
|
5901
|
+
// CRITICAL: do NOT `await` a Promise-typed analytics here. Bedrock
|
|
5902
|
+
// resolves its analytics from the stream's `finally` block — it
|
|
5903
|
+
// only completes once the consumer has fully iterated the stream.
|
|
5904
|
+
// Awaiting it before returning the StreamResult deadlocks: caller
|
|
5905
|
+
// can't iterate (no stream yet), analytics can't resolve (no
|
|
5906
|
+
// iteration). Pass the Promise through to the consumer instead;
|
|
5907
|
+
// they (or the cost listener below) can await it after consumption.
|
|
5908
|
+
//
|
|
5909
|
+
// The outer StreamResult type (StreamResult.analytics in
|
|
5910
|
+
// src/lib/types/stream.ts) explicitly allows `AnalyticsData |
|
|
5911
|
+
// Promise<AnalyticsData>` — the cast widens the local
|
|
5912
|
+
// `processStreamResult` return type which only declares the
|
|
5913
|
+
// resolved shape.
|
|
5629
5914
|
streamResult.analytics =
|
|
5630
|
-
streamAnalytics
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5915
|
+
streamAnalytics;
|
|
5916
|
+
}
|
|
5917
|
+
// The cost listener wants a resolved cost, but if the provider gave
|
|
5918
|
+
// us a Promise (Bedrock) we can't tax the stream's return path on it.
|
|
5919
|
+
// Defer cost accumulation: resolve in the background once the analytics
|
|
5920
|
+
// Promise settles. Synchronous analytics (most providers) still fire
|
|
5921
|
+
// immediately because Promise.resolve(non-promise) is sync-ish.
|
|
5922
|
+
Promise.resolve(streamResult.analytics)
|
|
5923
|
+
.then((analytics) => {
|
|
5924
|
+
if (analytics?.cost && analytics.cost > 0) {
|
|
5925
|
+
this._sessionCostUsd += analytics.cost;
|
|
5926
|
+
}
|
|
5927
|
+
})
|
|
5928
|
+
.catch(() => {
|
|
5929
|
+
/* analytics rejection is non-fatal — cost stays unupdated */
|
|
5930
|
+
});
|
|
5637
5931
|
this.emitStreamEndEvents(streamResult);
|
|
5638
5932
|
return this.createStreamResponse(streamResult, processedStream, {
|
|
5639
5933
|
providerName,
|
|
@@ -5728,7 +6022,7 @@ Current user's request: ${currentInput}`;
|
|
|
5728
6022
|
if (this.shouldReadMemory(options.memory, options.context?.userId) &&
|
|
5729
6023
|
options.context?.userId) {
|
|
5730
6024
|
try {
|
|
5731
|
-
options.input.text = await this.retrieveMemory(options.input.text, options.context.userId, options.memory?.additionalUsers);
|
|
6025
|
+
options.input.text = await this.retrieveMemory(options.input.text ?? "", options.context.userId, options.memory?.additionalUsers);
|
|
5732
6026
|
logger.debug("Memory retrieval successful");
|
|
5733
6027
|
}
|
|
5734
6028
|
catch (error) {
|
|
@@ -5752,7 +6046,6 @@ Current user's request: ${currentInput}`;
|
|
|
5752
6046
|
// obvious to future readers, and the lint suppression is scoped
|
|
5753
6047
|
// narrowly to the one statement that actually rebinds the param.
|
|
5754
6048
|
const mergedOptions = { ...options, ...orchestratedOptions };
|
|
5755
|
-
// eslint-disable-next-line no-param-reassign -- see NEW2/Issue 6 above
|
|
5756
6049
|
options = mergedOptions;
|
|
5757
6050
|
// Re-resolve model alias in case orchestration returned an alias
|
|
5758
6051
|
if (orchestratedOptions.model) {
|
|
@@ -7,6 +7,16 @@ export declare class AmazonBedrockProvider extends BaseProvider {
|
|
|
7
7
|
private bedrockClient;
|
|
8
8
|
private conversationHistory;
|
|
9
9
|
private region;
|
|
10
|
+
/**
|
|
11
|
+
* Parse the region segment from a Bedrock ARN.
|
|
12
|
+
* Returns null when the input is not an ARN.
|
|
13
|
+
*
|
|
14
|
+
* Supports all AWS partitions:
|
|
15
|
+
* - `arn:aws:bedrock:…` (commercial)
|
|
16
|
+
* - `arn:aws-cn:bedrock:…` (China)
|
|
17
|
+
* - `arn:aws-us-gov:bedrock:…` (GovCloud)
|
|
18
|
+
*/
|
|
19
|
+
private static extractRegionFromArn;
|
|
10
20
|
constructor(modelName?: string, neurolink?: NeuroLink, region?: string, credentials?: {
|
|
11
21
|
accessKeyId?: string;
|
|
12
22
|
secretAccessKey?: string;
|