@juspay/neurolink 9.64.0 → 9.65.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +33 -9
- package/dist/agent/directTools.js +11 -3
- 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 +624 -601
- package/dist/cli/commands/mcp.js +29 -0
- package/dist/cli/commands/proxy.js +24 -5
- package/dist/cli/factories/commandFactory.d.ts +11 -1
- package/dist/cli/factories/commandFactory.js +291 -38
- 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 +22 -2
- package/dist/core/baseProvider.js +217 -11
- package/dist/core/constants.d.ts +12 -0
- package/dist/core/constants.js +72 -1
- 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 +202 -5
- 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 +33 -9
- package/dist/lib/agent/directTools.js +11 -3
- 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 +22 -2
- package/dist/lib/core/baseProvider.js +217 -11
- package/dist/lib/core/constants.d.ts +12 -0
- package/dist/lib/core/constants.js +72 -1
- 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 +202 -5
- 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/middleware/builtin/lifecycle.js +39 -9
- 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 +323 -77
- 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.js +126 -10
- package/dist/lib/providers/googleNativeGemini3.d.ts +26 -6
- package/dist/lib/providers/googleNativeGemini3.js +276 -29
- package/dist/lib/providers/googleVertex.js +639 -181
- 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 +35 -23
- 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/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/conversation.d.ts +16 -0
- package/dist/lib/types/generate.d.ts +62 -5
- package/dist/lib/types/index.d.ts +5 -0
- package/dist/lib/types/index.js +7 -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 +144 -1
- 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 +2 -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 +51 -8
- package/dist/lib/utils/lifecycleCallbacks.js +82 -26
- 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.js +43 -25
- package/dist/lib/utils/modelChoices.js +236 -3
- 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/safeFetch.d.ts +26 -0
- package/dist/lib/utils/safeFetch.js +83 -0
- 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/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/middleware/builtin/lifecycle.js +39 -9
- 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 +323 -77
- 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.js +126 -10
- package/dist/providers/googleNativeGemini3.d.ts +26 -6
- package/dist/providers/googleNativeGemini3.js +276 -29
- package/dist/providers/googleVertex.js +639 -181
- 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 +35 -23
- 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/avatar.d.ts +143 -0
- package/dist/types/avatar.js +19 -0
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/conversation.d.ts +16 -0
- package/dist/types/generate.d.ts +62 -5
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +7 -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 +144 -1
- 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 +2 -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 +51 -8
- package/dist/utils/lifecycleCallbacks.js +82 -26
- 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.js +43 -25
- package/dist/utils/modelChoices.js +236 -3
- 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/safeFetch.d.ts +26 -0
- package/dist/utils/safeFetch.js +82 -0
- 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/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 +32 -5
package/dist/lib/neurolink.js
CHANGED
|
@@ -62,9 +62,11 @@ 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
|
-
import { fireOnErrorOnce } from "./utils/lifecycleCallbacks.js";
|
|
68
70
|
import { logger, mcpLogger } from "./utils/logger.js";
|
|
69
71
|
import { extractMcpErrorText } from "./utils/mcpErrorText.js";
|
|
70
72
|
import { createCustomToolServerInfo, detectCategory, } from "./utils/mcpDefaults.js";
|
|
@@ -334,7 +336,30 @@ export function markStreamProviderEmittedGenerationEnd(options) {
|
|
|
334
336
|
ctx.providerEmitted = true;
|
|
335
337
|
}
|
|
336
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
|
+
}
|
|
337
360
|
export class NeuroLink {
|
|
361
|
+
/** @internal Brand for cross-module identification — see {@link isNeuroLink}. */
|
|
362
|
+
[NEUROLINK_BRAND] = true;
|
|
338
363
|
mcpInitialized = false;
|
|
339
364
|
mcpSkipped = false;
|
|
340
365
|
mcpInitPromise = null;
|
|
@@ -2754,28 +2779,65 @@ Current user's request: ${currentInput}`;
|
|
|
2754
2779
|
* @since 1.0.0
|
|
2755
2780
|
*/
|
|
2756
2781
|
async generate(optionsOrPrompt) {
|
|
2757
|
-
|
|
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();
|
|
2758
2792
|
try {
|
|
2759
2793
|
return await this.runWithFallbackOrchestration(optionsOrPrompt, "generate", (opts) => tracers.sdk.startActiveSpan("neurolink.generate", { kind: SpanKind.INTERNAL }, (generateSpan) => this.executeGenerateWithMetricsContext(opts, generateSpan)));
|
|
2760
2794
|
}
|
|
2761
2795
|
catch (error) {
|
|
2762
|
-
//
|
|
2763
|
-
//
|
|
2764
|
-
//
|
|
2765
|
-
//
|
|
2766
|
-
//
|
|
2767
|
-
//
|
|
2768
|
-
//
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
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({
|
|
2774
2834
|
error: err,
|
|
2775
|
-
duration: Date.now() -
|
|
2835
|
+
duration: Date.now() - startedAt,
|
|
2776
2836
|
recoverable: false,
|
|
2777
|
-
});
|
|
2778
|
-
|
|
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);
|
|
2779
2841
|
}
|
|
2780
2842
|
}
|
|
2781
2843
|
/**
|
|
@@ -2861,15 +2923,23 @@ Current user's request: ${currentInput}`;
|
|
|
2861
2923
|
catch {
|
|
2862
2924
|
/* listener errors are non-fatal */
|
|
2863
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.
|
|
2864
2934
|
const retriedOptions = typeof optionsOrPrompt === "object"
|
|
2865
|
-
? {
|
|
2935
|
+
? cloneOptionsForCallIsolation({
|
|
2866
2936
|
...optionsOrPrompt,
|
|
2867
2937
|
...(next.provider && { provider: next.provider }),
|
|
2868
2938
|
...(next.model && { model: next.model }),
|
|
2869
2939
|
// Strip the fallback hooks so the retry doesn't re-orchestrate.
|
|
2870
2940
|
providerFallback: undefined,
|
|
2871
2941
|
modelChain: undefined,
|
|
2872
|
-
}
|
|
2942
|
+
})
|
|
2873
2943
|
: optionsOrPrompt;
|
|
2874
2944
|
const retryAttempt = await this.attemptInner(inner, retriedOptions);
|
|
2875
2945
|
if ("ok" in retryAttempt) {
|
|
@@ -2945,6 +3015,12 @@ Current user's request: ${currentInput}`;
|
|
|
2945
3015
|
const options = typeof optionsOrPrompt === "string"
|
|
2946
3016
|
? { input: { text: optionsOrPrompt } }
|
|
2947
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
|
+
}
|
|
2948
3024
|
// Dynamic argument resolution — resolve any function-valued options before downstream use
|
|
2949
3025
|
await this.resolveDynamicOptions(options);
|
|
2950
3026
|
options.model = resolveModel(options.model, this.modelAliasConfig);
|
|
@@ -2955,13 +3031,28 @@ Current user's request: ${currentInput}`;
|
|
|
2955
3031
|
? optionsOrPrompt.length
|
|
2956
3032
|
: options.input?.text?.length || 0);
|
|
2957
3033
|
generateSpan.setAttribute("neurolink.has_tools", !!(options.tools && Object.keys(options.tools).length > 0));
|
|
2958
|
-
//
|
|
2959
|
-
//
|
|
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).
|
|
2960
3041
|
const hasSttAudio = !!(options.stt?.enabled && options.stt?.audio);
|
|
2961
|
-
if (hasSttAudio && !options.input) {
|
|
2962
|
-
options.input =
|
|
2963
|
-
}
|
|
2964
|
-
|
|
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) {
|
|
2965
3056
|
this.assertInputText(options.input?.text, "Input text is required and must be a non-empty string");
|
|
2966
3057
|
}
|
|
2967
3058
|
this.enforceSessionBudget(options.maxBudgetUsd);
|
|
@@ -2971,6 +3062,16 @@ Current user's request: ${currentInput}`;
|
|
|
2971
3062
|
}
|
|
2972
3063
|
async maybeHandleEarlyGenerateResult(options, generateSpan) {
|
|
2973
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
|
+
}
|
|
2974
3075
|
if (options.stt?.enabled && options.stt?.audio) {
|
|
2975
3076
|
// prepareGenerateRequest synthesizes input.text = "" for audio-only
|
|
2976
3077
|
// calls, so without this guard generateWithWorkflow runs with an
|
|
@@ -2982,6 +3083,12 @@ Current user's request: ${currentInput}`;
|
|
|
2982
3083
|
}
|
|
2983
3084
|
return this.generateWithWorkflow(options);
|
|
2984
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
|
+
}
|
|
2985
3092
|
if (options.output?.mode !== "ppt") {
|
|
2986
3093
|
return null;
|
|
2987
3094
|
}
|
|
@@ -3099,7 +3206,7 @@ Current user's request: ${currentInput}`;
|
|
|
3099
3206
|
originalProvider: options.provider || "auto",
|
|
3100
3207
|
orchestratedProvider: orchestratedOptions.provider,
|
|
3101
3208
|
orchestratedModel: orchestratedOptions.model,
|
|
3102
|
-
prompt: options.input
|
|
3209
|
+
prompt: (options.input?.text ?? "").substring(0, 100),
|
|
3103
3210
|
});
|
|
3104
3211
|
Object.assign(options, orchestratedOptions);
|
|
3105
3212
|
if (orchestratedOptions.model) {
|
|
@@ -3144,12 +3251,22 @@ Current user's request: ${currentInput}`;
|
|
|
3144
3251
|
});
|
|
3145
3252
|
}
|
|
3146
3253
|
}
|
|
3147
|
-
|
|
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) ||
|
|
3148
3263
|
!options.context?.userId) {
|
|
3149
3264
|
return;
|
|
3150
3265
|
}
|
|
3151
3266
|
try {
|
|
3152
|
-
|
|
3267
|
+
if (options.input) {
|
|
3268
|
+
options.input.text = await this.retrieveMemory(options.input.text ?? "", options.context.userId, options.memory?.additionalUsers);
|
|
3269
|
+
}
|
|
3153
3270
|
logger.debug("Memory retrieval successful (generate)");
|
|
3154
3271
|
}
|
|
3155
3272
|
catch (error) {
|
|
@@ -3158,7 +3275,7 @@ Current user's request: ${currentInput}`;
|
|
|
3158
3275
|
}
|
|
3159
3276
|
async buildGenerateTextOptions(options, originalPrompt, factoryResult) {
|
|
3160
3277
|
const baseOptions = {
|
|
3161
|
-
prompt: options.input
|
|
3278
|
+
prompt: options.input?.text,
|
|
3162
3279
|
provider: options.provider,
|
|
3163
3280
|
model: options.model,
|
|
3164
3281
|
temperature: options.temperature,
|
|
@@ -3214,11 +3331,11 @@ Current user's request: ${currentInput}`;
|
|
|
3214
3331
|
textOptions.conversationMemoryConfig = this.conversationMemory.config;
|
|
3215
3332
|
textOptions.originalPrompt = originalPrompt;
|
|
3216
3333
|
}
|
|
3217
|
-
const { toolResults, enhancedPrompt } = await this.detectAndExecuteTools(textOptions.prompt || options.input
|
|
3334
|
+
const { toolResults, enhancedPrompt } = await this.detectAndExecuteTools(textOptions.prompt || options.input?.text || "", factoryResult.domainType);
|
|
3218
3335
|
if (enhancedPrompt !== textOptions.prompt) {
|
|
3219
3336
|
textOptions.prompt = enhancedPrompt;
|
|
3220
3337
|
logger.debug("Enhanced prompt with tool results", {
|
|
3221
|
-
originalLength: options.input
|
|
3338
|
+
originalLength: (options.input?.text ?? "").length,
|
|
3222
3339
|
enhancedLength: enhancedPrompt.length,
|
|
3223
3340
|
toolResults: toolResults.length,
|
|
3224
3341
|
});
|
|
@@ -3227,26 +3344,35 @@ Current user's request: ${currentInput}`;
|
|
|
3227
3344
|
}
|
|
3228
3345
|
finalizeGenerateRequestResult(params) {
|
|
3229
3346
|
const { generateSpan, options, textOptions, textResult, factoryResult, originalPrompt, startTime, } = params;
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
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
|
+
}
|
|
3250
3376
|
this.emitter.emit("response:end", textResult.content || "");
|
|
3251
3377
|
this.emitter.emit("message", `Generation completed in ${Date.now() - startTime}ms`);
|
|
3252
3378
|
const generateResult = {
|
|
@@ -3284,7 +3410,18 @@ Current user's request: ${currentInput}`;
|
|
|
3284
3410
|
audio: textResult.audio,
|
|
3285
3411
|
transcription: textResult.transcription,
|
|
3286
3412
|
video: textResult.video,
|
|
3413
|
+
avatar: textResult.avatar,
|
|
3414
|
+
music: textResult.music,
|
|
3287
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,
|
|
3288
3425
|
...(textResult.retries && { retries: textResult.retries }),
|
|
3289
3426
|
};
|
|
3290
3427
|
if (generateResult.analytics?.cost && generateResult.analytics.cost > 0) {
|
|
@@ -3377,6 +3514,67 @@ Current user's request: ${currentInput}`;
|
|
|
3377
3514
|
ppt: pptResult,
|
|
3378
3515
|
};
|
|
3379
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
|
+
}
|
|
3380
3578
|
/**
|
|
3381
3579
|
* Generate with workflow engine integration
|
|
3382
3580
|
* Returns both original and processed responses for AB testing
|
|
@@ -3386,7 +3584,7 @@ Current user's request: ${currentInput}`;
|
|
|
3386
3584
|
logger.debug("[NeuroLink] Executing workflow generation", {
|
|
3387
3585
|
workflowId: options.workflow,
|
|
3388
3586
|
hasInlineConfig: !!options.workflowConfig,
|
|
3389
|
-
prompt: options.input
|
|
3587
|
+
prompt: (options.input?.text ?? "").substring(0, 100),
|
|
3390
3588
|
startTime: workflowStartTime,
|
|
3391
3589
|
});
|
|
3392
3590
|
// Determine workflow configuration
|
|
@@ -3407,7 +3605,7 @@ Current user's request: ${currentInput}`;
|
|
|
3407
3605
|
}
|
|
3408
3606
|
// Execute workflow
|
|
3409
3607
|
const workflowResult = await runWorkflow(workflowConfig, {
|
|
3410
|
-
prompt: options.input
|
|
3608
|
+
prompt: options.input?.text ?? "",
|
|
3411
3609
|
conversationHistory: options.conversationMessages
|
|
3412
3610
|
?.filter((m) => m.role === "user" || m.role === "assistant")
|
|
3413
3611
|
.map((m) => ({
|
|
@@ -3486,7 +3684,7 @@ Current user's request: ${currentInput}`;
|
|
|
3486
3684
|
logger.debug("[NeuroLink] Executing workflow streaming (progressive)", {
|
|
3487
3685
|
workflowId: options.workflow,
|
|
3488
3686
|
hasInlineConfig: !!options.workflowConfig,
|
|
3489
|
-
prompt: options.input
|
|
3687
|
+
prompt: (options.input?.text ?? "").substring(0, 100),
|
|
3490
3688
|
});
|
|
3491
3689
|
// Determine workflow configuration
|
|
3492
3690
|
let workflowConfig;
|
|
@@ -3506,7 +3704,7 @@ Current user's request: ${currentInput}`;
|
|
|
3506
3704
|
const { runWorkflowWithStreaming } = await import("./workflow/core/workflowRunner.js");
|
|
3507
3705
|
// Execute workflow with progressive streaming
|
|
3508
3706
|
const workflowStream = runWorkflowWithStreaming(workflowConfig, {
|
|
3509
|
-
prompt: options.input
|
|
3707
|
+
prompt: options.input?.text ?? "",
|
|
3510
3708
|
conversationHistory: options.conversationMessages
|
|
3511
3709
|
?.filter((m) => m.role === "user" || m.role === "assistant")
|
|
3512
3710
|
.map((m) => ({
|
|
@@ -4561,10 +4759,22 @@ Current user's request: ${currentInput}`;
|
|
|
4561
4759
|
availableTools: transformToolsForMCP(transformToolsToExpectedFormat(availableTools)),
|
|
4562
4760
|
audio: result.audio,
|
|
4563
4761
|
video: result.video,
|
|
4762
|
+
avatar: result.avatar,
|
|
4763
|
+
music: result.music,
|
|
4564
4764
|
ppt: result.ppt,
|
|
4565
4765
|
imageOutput: result.imageOutput,
|
|
4566
4766
|
analytics: result.analytics,
|
|
4567
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,
|
|
4568
4778
|
};
|
|
4569
4779
|
}
|
|
4570
4780
|
/**
|
|
@@ -4836,9 +5046,19 @@ Current user's request: ${currentInput}`;
|
|
|
4836
5046
|
evaluation: result.evaluation,
|
|
4837
5047
|
audio: result.audio,
|
|
4838
5048
|
video: result.video,
|
|
5049
|
+
avatar: result.avatar,
|
|
5050
|
+
music: result.music,
|
|
4839
5051
|
ppt: result.ppt,
|
|
4840
5052
|
// CRITICAL FIX: Include imageOutput for image generation models
|
|
4841
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,
|
|
4842
5062
|
};
|
|
4843
5063
|
}
|
|
4844
5064
|
catch (error) {
|
|
@@ -5061,23 +5281,28 @@ Current user's request: ${currentInput}`;
|
|
|
5061
5281
|
: [],
|
|
5062
5282
|
optionKeys: Object.keys(options),
|
|
5063
5283
|
});
|
|
5064
|
-
|
|
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();
|
|
5065
5294
|
try {
|
|
5066
5295
|
return await this.streamWithIterationFallback(options);
|
|
5067
5296
|
}
|
|
5068
5297
|
catch (error) {
|
|
5069
|
-
//
|
|
5070
|
-
//
|
|
5071
|
-
//
|
|
5072
|
-
//
|
|
5073
|
-
//
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
error: err,
|
|
5078
|
-
duration: Date.now() - startTime,
|
|
5079
|
-
recoverable: false,
|
|
5080
|
-
});
|
|
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);
|
|
5081
5306
|
throw error;
|
|
5082
5307
|
}
|
|
5083
5308
|
}
|
|
@@ -5673,14 +5898,36 @@ Current user's request: ${currentInput}`;
|
|
|
5673
5898
|
streamResult.usage = streamUsage;
|
|
5674
5899
|
}
|
|
5675
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.
|
|
5676
5914
|
streamResult.analytics =
|
|
5677
|
-
streamAnalytics
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
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
|
+
});
|
|
5684
5931
|
this.emitStreamEndEvents(streamResult);
|
|
5685
5932
|
return this.createStreamResponse(streamResult, processedStream, {
|
|
5686
5933
|
providerName,
|
|
@@ -5775,7 +6022,7 @@ Current user's request: ${currentInput}`;
|
|
|
5775
6022
|
if (this.shouldReadMemory(options.memory, options.context?.userId) &&
|
|
5776
6023
|
options.context?.userId) {
|
|
5777
6024
|
try {
|
|
5778
|
-
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);
|
|
5779
6026
|
logger.debug("Memory retrieval successful");
|
|
5780
6027
|
}
|
|
5781
6028
|
catch (error) {
|
|
@@ -5799,7 +6046,6 @@ Current user's request: ${currentInput}`;
|
|
|
5799
6046
|
// obvious to future readers, and the lint suppression is scoped
|
|
5800
6047
|
// narrowly to the one statement that actually rebinds the param.
|
|
5801
6048
|
const mergedOptions = { ...options, ...orchestratedOptions };
|
|
5802
|
-
// eslint-disable-next-line no-param-reassign -- see NEW2/Issue 6 above
|
|
5803
6049
|
options = mergedOptions;
|
|
5804
6050
|
// Re-resolve model alias in case orchestration returned an alias
|
|
5805
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;
|