@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
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared log-sanitization helpers.
|
|
3
|
+
*
|
|
4
|
+
* Centralises truncate + secret-redaction patterns so every provider stays
|
|
5
|
+
* consistent and any regex improvements only need one change.
|
|
6
|
+
*
|
|
7
|
+
* Coverage:
|
|
8
|
+
* - `Authorization: Bearer <token>` (with required whitespace)
|
|
9
|
+
* - `Authorization: Token <token>` (Replicate uses this, not Bearer)
|
|
10
|
+
* - `Authorization: Basic <base64>` (D-ID and similar)
|
|
11
|
+
* - Bare tokens by known provider prefix:
|
|
12
|
+
* sk-/pk- (OpenAI, Anthropic, Stability),
|
|
13
|
+
* r8_ (Replicate), gsk_ (Groq), xai- (xAI), tgp_ (Together),
|
|
14
|
+
* fw_ (Fireworks), pplx- (Perplexity), pa- (Voyage),
|
|
15
|
+
* jina_ (Jina), fish- (Fish Audio)
|
|
16
|
+
* - Generic key=value pairs: api_key=…, access_token: …, secret_key=…
|
|
17
|
+
*/
|
|
18
|
+
const TOKEN_PREFIXES = [
|
|
19
|
+
"sk",
|
|
20
|
+
"pk",
|
|
21
|
+
"r8",
|
|
22
|
+
"gsk",
|
|
23
|
+
"xai",
|
|
24
|
+
"tgp",
|
|
25
|
+
"fw",
|
|
26
|
+
"pplx",
|
|
27
|
+
"pa",
|
|
28
|
+
"jina",
|
|
29
|
+
"fish",
|
|
30
|
+
];
|
|
31
|
+
const PREFIX_PATTERN = TOKEN_PREFIXES.join("|");
|
|
32
|
+
/**
|
|
33
|
+
* Pattern matching common bearer/API-key tokens in plain text.
|
|
34
|
+
*
|
|
35
|
+
* Case-insensitive (`i` flag) since header names ("Authorization") and scheme
|
|
36
|
+
* names ("Bearer", "Token", "Basic") are sometimes lower-cased in error
|
|
37
|
+
* bodies. `g` flag for replace-all.
|
|
38
|
+
*/
|
|
39
|
+
const SECRET_PATTERN = new RegExp(
|
|
40
|
+
// Authorization schemes — required whitespace between scheme and value
|
|
41
|
+
"\\bBearer\\s+[A-Za-z0-9_\\-\\.]{8,}\\b" +
|
|
42
|
+
"|\\bToken\\s+[A-Za-z0-9_\\-\\.]{8,}\\b" +
|
|
43
|
+
"|\\bBasic\\s+[A-Za-z0-9+/=]{12,}\\b" +
|
|
44
|
+
// Bare tokens by known prefix (e.g. `sk-abc…`, `r8_xyz…`)
|
|
45
|
+
`|\\b(?:${PREFIX_PATTERN})[_\\-][A-Za-z0-9_\\-\\.]{8,}\\b` +
|
|
46
|
+
// Generic key=value pairs (URL params, JSON bodies, header dumps)
|
|
47
|
+
"|\\b(?:api[_-]?key|access[_-]?token|secret[_-]?key|refresh[_-]?token)\\s*[:=]\\s*['\"]?[^\\s,;'\"&]+", "gi");
|
|
48
|
+
/** Header names that should always be redacted regardless of value shape. */
|
|
49
|
+
const SENSITIVE_HEADER_NAMES = [
|
|
50
|
+
"authorization",
|
|
51
|
+
"cookie",
|
|
52
|
+
"set-cookie",
|
|
53
|
+
"x-api-key",
|
|
54
|
+
"api-key",
|
|
55
|
+
"apikey",
|
|
56
|
+
"x-auth-token",
|
|
57
|
+
"x-csrf-token",
|
|
58
|
+
];
|
|
59
|
+
/** Object keys that should always be redacted regardless of value shape. */
|
|
60
|
+
const SENSITIVE_OBJECT_KEYS = [
|
|
61
|
+
"apikey",
|
|
62
|
+
"api_key",
|
|
63
|
+
"apiKey",
|
|
64
|
+
"access_token",
|
|
65
|
+
"accessToken",
|
|
66
|
+
"refresh_token",
|
|
67
|
+
"refreshToken",
|
|
68
|
+
"secret",
|
|
69
|
+
"secretkey",
|
|
70
|
+
"secret_key",
|
|
71
|
+
"secretKey",
|
|
72
|
+
"password",
|
|
73
|
+
"authorization",
|
|
74
|
+
"oauth",
|
|
75
|
+
"oauthToken",
|
|
76
|
+
"credentials",
|
|
77
|
+
];
|
|
78
|
+
/**
|
|
79
|
+
* Truncate `text` to `maxLen` chars then replace embedded secrets with `***`.
|
|
80
|
+
*
|
|
81
|
+
* Use this for free-form text logged from response/request bodies. For
|
|
82
|
+
* structured data (records, headers) prefer {@link sanitizeRecord} and
|
|
83
|
+
* {@link sanitizeHeaders} which know to redact by key name as well.
|
|
84
|
+
*
|
|
85
|
+
* @param text - Raw text to sanitize (typically an HTTP response body).
|
|
86
|
+
* @param maxLen - Maximum number of characters to keep (default 500).
|
|
87
|
+
*/
|
|
88
|
+
export function sanitizeForLog(text, maxLen = 500) {
|
|
89
|
+
if (!text) {
|
|
90
|
+
return text;
|
|
91
|
+
}
|
|
92
|
+
return text.slice(0, maxLen).replace(SECRET_PATTERN, "***");
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Recursively sanitize a record/array, returning a structurally identical
|
|
96
|
+
* value with sensitive keys redacted and string values run through
|
|
97
|
+
* {@link sanitizeForLog}.
|
|
98
|
+
*
|
|
99
|
+
* Safe to call on any JSON-shaped data. Cycles are detected and replaced
|
|
100
|
+
* with the string `"[Circular]"` to avoid infinite recursion when logging
|
|
101
|
+
* mid-stream objects that reference themselves.
|
|
102
|
+
*
|
|
103
|
+
* @param value - The value to sanitize.
|
|
104
|
+
* @param maxStringLen - Per-string truncation cap (default 1000).
|
|
105
|
+
*/
|
|
106
|
+
export function sanitizeRecord(value, maxStringLen = 1000) {
|
|
107
|
+
const seen = new WeakSet();
|
|
108
|
+
const walk = (v) => {
|
|
109
|
+
if (v === null || v === undefined) {
|
|
110
|
+
return v;
|
|
111
|
+
}
|
|
112
|
+
if (typeof v === "string") {
|
|
113
|
+
return sanitizeForLog(v, maxStringLen);
|
|
114
|
+
}
|
|
115
|
+
if (typeof v !== "object") {
|
|
116
|
+
return v;
|
|
117
|
+
}
|
|
118
|
+
if (seen.has(v)) {
|
|
119
|
+
return "[Circular]";
|
|
120
|
+
}
|
|
121
|
+
seen.add(v);
|
|
122
|
+
if (Array.isArray(v)) {
|
|
123
|
+
return v.map(walk);
|
|
124
|
+
}
|
|
125
|
+
const out = {};
|
|
126
|
+
for (const [k, val] of Object.entries(v)) {
|
|
127
|
+
if (SENSITIVE_OBJECT_KEYS.some((name) => name.toLowerCase() === k.toLowerCase())) {
|
|
128
|
+
out[k] = "***";
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
out[k] = walk(val);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return out;
|
|
135
|
+
};
|
|
136
|
+
return walk(value);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Sanitize an HTTP headers object — redacts sensitive header names entirely
|
|
140
|
+
* (`***`) and applies {@link sanitizeForLog} to remaining values.
|
|
141
|
+
*
|
|
142
|
+
* Accepts both `Headers` instances and plain-object header maps so providers
|
|
143
|
+
* can log either shape uniformly.
|
|
144
|
+
*/
|
|
145
|
+
export function sanitizeHeaders(headers) {
|
|
146
|
+
if (!headers) {
|
|
147
|
+
return {};
|
|
148
|
+
}
|
|
149
|
+
const out = {};
|
|
150
|
+
const set = (name, value) => {
|
|
151
|
+
if (value === undefined || value === null) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const lower = name.toLowerCase();
|
|
155
|
+
if (SENSITIVE_HEADER_NAMES.includes(lower)) {
|
|
156
|
+
out[name] = "***";
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
out[name] = sanitizeForLog(value, 500);
|
|
160
|
+
};
|
|
161
|
+
if (headers instanceof Headers) {
|
|
162
|
+
headers.forEach((value, key) => set(key, value));
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
166
|
+
set(key, value);
|
|
167
|
+
}
|
|
168
|
+
return out;
|
|
169
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared logging-fetch wrapper.
|
|
3
|
+
*
|
|
4
|
+
* Wraps `createProxyFetch()` and logs every non-2xx upstream response with:
|
|
5
|
+
* - provider label
|
|
6
|
+
* - HTTP status code
|
|
7
|
+
* - URL with embedded credentials / signed query params masked
|
|
8
|
+
* (via `maskProxyUrl`)
|
|
9
|
+
* - request body size (string-body only — multipart/streamed bodies
|
|
10
|
+
* report 0)
|
|
11
|
+
*
|
|
12
|
+
* Response bodies are NOT logged by default (they can echo prompt fragments,
|
|
13
|
+
* tool payloads, or echoed auth tokens). Set `NEUROLINK_DEBUG_HTTP=1` to opt
|
|
14
|
+
* into body logging — and even then bodies are run through `sanitizeForLog`
|
|
15
|
+
* to redact `Bearer …`, `sk-…`, `Token …`, and the other 11 token formats
|
|
16
|
+
* covered by `logSanitize.SECRET_PATTERN`.
|
|
17
|
+
*
|
|
18
|
+
* Previously this same function was hand-rolled in 11 provider files
|
|
19
|
+
* (cohere, xai, groq, togetherAi, fireworks, perplexity, cloudflare,
|
|
20
|
+
* llamaCpp, lmStudio, nvidiaNim, deepseek) with subtly different bodies.
|
|
21
|
+
* Extracting it kills the drift risk and gives a single place to harden.
|
|
22
|
+
*
|
|
23
|
+
* @module utils/loggingFetch
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Construct a fetch-compatible function that logs upstream non-OK responses
|
|
27
|
+
* under the given provider label.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createLoggingFetch(provider: string): typeof fetch;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared logging-fetch wrapper.
|
|
3
|
+
*
|
|
4
|
+
* Wraps `createProxyFetch()` and logs every non-2xx upstream response with:
|
|
5
|
+
* - provider label
|
|
6
|
+
* - HTTP status code
|
|
7
|
+
* - URL with embedded credentials / signed query params masked
|
|
8
|
+
* (via `maskProxyUrl`)
|
|
9
|
+
* - request body size (string-body only — multipart/streamed bodies
|
|
10
|
+
* report 0)
|
|
11
|
+
*
|
|
12
|
+
* Response bodies are NOT logged by default (they can echo prompt fragments,
|
|
13
|
+
* tool payloads, or echoed auth tokens). Set `NEUROLINK_DEBUG_HTTP=1` to opt
|
|
14
|
+
* into body logging — and even then bodies are run through `sanitizeForLog`
|
|
15
|
+
* to redact `Bearer …`, `sk-…`, `Token …`, and the other 11 token formats
|
|
16
|
+
* covered by `logSanitize.SECRET_PATTERN`.
|
|
17
|
+
*
|
|
18
|
+
* Previously this same function was hand-rolled in 11 provider files
|
|
19
|
+
* (cohere, xai, groq, togetherAi, fireworks, perplexity, cloudflare,
|
|
20
|
+
* llamaCpp, lmStudio, nvidiaNim, deepseek) with subtly different bodies.
|
|
21
|
+
* Extracting it kills the drift risk and gives a single place to harden.
|
|
22
|
+
*
|
|
23
|
+
* @module utils/loggingFetch
|
|
24
|
+
*/
|
|
25
|
+
import { createProxyFetch, maskProxyUrl } from "../proxy/proxyFetch.js";
|
|
26
|
+
import { logger } from "./logger.js";
|
|
27
|
+
import { sanitizeForLog } from "./logSanitize.js";
|
|
28
|
+
/**
|
|
29
|
+
* Construct a fetch-compatible function that logs upstream non-OK responses
|
|
30
|
+
* under the given provider label.
|
|
31
|
+
*/
|
|
32
|
+
export function createLoggingFetch(provider) {
|
|
33
|
+
const base = createProxyFetch();
|
|
34
|
+
return (async (input, init) => {
|
|
35
|
+
const url = typeof input === "string"
|
|
36
|
+
? input
|
|
37
|
+
: input instanceof URL
|
|
38
|
+
? input.toString()
|
|
39
|
+
: input.url;
|
|
40
|
+
const reqSize = init?.body && typeof init.body === "string" ? init.body.length : 0;
|
|
41
|
+
const response = await base(input, init);
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
const safeUrl = maskProxyUrl(url) ?? "<redacted>";
|
|
44
|
+
if (process.env.NEUROLINK_DEBUG_HTTP === "1") {
|
|
45
|
+
const clone = response.clone();
|
|
46
|
+
const raw = await clone.text().catch(() => "<unreadable>");
|
|
47
|
+
logger.warn(`[${provider}] upstream ${response.status}`, {
|
|
48
|
+
url: safeUrl,
|
|
49
|
+
body: sanitizeForLog(raw),
|
|
50
|
+
reqSize,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
logger.warn(`[${provider}] upstream ${response.status} url=${safeUrl} reqSize=${reqSize}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return response;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -17,6 +17,16 @@ export declare function convertToModelMessages(messages: MultimodalChatMessage[]
|
|
|
17
17
|
* Enhanced with CSV file processing support
|
|
18
18
|
*/
|
|
19
19
|
export declare function buildMessagesArray(options: TextGenerationOptions | StreamOptions): Promise<ModelMessage[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Process the unified files array with auto-detection.
|
|
22
|
+
* Handles lazy file registration, full processing, and preview injection.
|
|
23
|
+
*
|
|
24
|
+
* Exported so providers that bypass BaseProvider.generate() (e.g.
|
|
25
|
+
* GoogleVertex's native @google/genai path) can still preprocess
|
|
26
|
+
* `input.files` — without this, mimetype-hint and text-file inputs
|
|
27
|
+
* would silently never reach the model on those paths.
|
|
28
|
+
*/
|
|
29
|
+
export declare function processUnifiedFilesArray(options: GenerateOptions, maxSize: number, provider: string): Promise<void>;
|
|
20
30
|
/**
|
|
21
31
|
* Build multimodal message array with image support
|
|
22
32
|
* Detects when images are present and routes through provider adapter
|
|
@@ -534,8 +534,13 @@ export async function buildMessagesArray(options) {
|
|
|
534
534
|
csvSection += metadataText + `\n\n`;
|
|
535
535
|
}
|
|
536
536
|
}
|
|
537
|
-
|
|
537
|
+
// Put the actual CSV content BEFORE the tool instructions —
|
|
538
|
+
// buildCSVToolInstructions references "the CSV data shown above"
|
|
539
|
+
// and the trailing position keeps that reference accurate.
|
|
540
|
+
// Vertex Gemini misreads CSV-only prompts as "no files attached"
|
|
541
|
+
// when the NOTE-then-data order makes the reference dangle.
|
|
538
542
|
csvSection += result.content;
|
|
543
|
+
csvSection += buildCSVToolInstructions(filePath);
|
|
539
544
|
csvContent += csvSection;
|
|
540
545
|
logger.info(`[CSV] ✅ Processed: ${filename}`, result.metadata);
|
|
541
546
|
}
|
|
@@ -597,6 +602,7 @@ export async function buildMessagesArray(options) {
|
|
|
597
602
|
* Mutates options.input.files and options.input.text as needed.
|
|
598
603
|
*/
|
|
599
604
|
function enforceFileBudget(options, provider, model) {
|
|
605
|
+
options.input ??= {};
|
|
600
606
|
if (!options.input.files || options.input.files.length === 0) {
|
|
601
607
|
return;
|
|
602
608
|
}
|
|
@@ -654,6 +660,7 @@ function enforceFileBudget(options, provider, model) {
|
|
|
654
660
|
* Handles CSV, SVG, image, PDF, video, audio, archive, xlsx, docx, pptx, text, and unknown types.
|
|
655
661
|
*/
|
|
656
662
|
function appendDetectedFileResult(result, file, options) {
|
|
663
|
+
options.input ??= {};
|
|
657
664
|
const filename = extractFilename(file);
|
|
658
665
|
if (result.type === "csv") {
|
|
659
666
|
const filePath = typeof file === "string" ? file : filename;
|
|
@@ -664,8 +671,11 @@ function appendDetectedFileResult(result, file, options) {
|
|
|
664
671
|
csvSection += metadataText + `\n\n`;
|
|
665
672
|
}
|
|
666
673
|
}
|
|
667
|
-
|
|
674
|
+
// Put the actual CSV content BEFORE the tool instructions —
|
|
675
|
+
// buildCSVToolInstructions references "the CSV data shown above" and
|
|
676
|
+
// the trailing position keeps that reference accurate.
|
|
668
677
|
csvSection += result.content;
|
|
678
|
+
csvSection += buildCSVToolInstructions(filePath);
|
|
669
679
|
options.input.text += csvSection;
|
|
670
680
|
logger.info(`[FileDetector] ✅ CSV: ${filename}`);
|
|
671
681
|
}
|
|
@@ -771,8 +781,14 @@ function appendDetectedFileResult(result, file, options) {
|
|
|
771
781
|
/**
|
|
772
782
|
* Process the unified files array with auto-detection.
|
|
773
783
|
* Handles lazy file registration, full processing, and preview injection.
|
|
784
|
+
*
|
|
785
|
+
* Exported so providers that bypass BaseProvider.generate() (e.g.
|
|
786
|
+
* GoogleVertex's native @google/genai path) can still preprocess
|
|
787
|
+
* `input.files` — without this, mimetype-hint and text-file inputs
|
|
788
|
+
* would silently never reach the model on those paths.
|
|
774
789
|
*/
|
|
775
|
-
async function processUnifiedFilesArray(options, maxSize, provider) {
|
|
790
|
+
export async function processUnifiedFilesArray(options, maxSize, provider) {
|
|
791
|
+
options.input ??= {};
|
|
776
792
|
if (!options.input.files || options.input.files.length === 0) {
|
|
777
793
|
return;
|
|
778
794
|
}
|
|
@@ -787,7 +803,12 @@ async function processUnifiedFilesArray(options, maxSize, provider) {
|
|
|
787
803
|
},
|
|
788
804
|
}, async (span) => {
|
|
789
805
|
logger.info(`[NEUROLINK] Processing ${totalFiles} file(s) with auto-detection`);
|
|
790
|
-
options.input
|
|
806
|
+
// `options.input` was guaranteed non-null by the `??= {}` guard at the
|
|
807
|
+
// top of processUnifiedFilesArray; re-assert here so TypeScript is happy
|
|
808
|
+
// inside this withSpan closure (it doesn't track mutations across closures).
|
|
809
|
+
options.input ??= {};
|
|
810
|
+
const inp2 = options.input;
|
|
811
|
+
inp2.text = inp2.text || "";
|
|
791
812
|
let includedCount = 0;
|
|
792
813
|
const fileRegistry = options.fileRegistry;
|
|
793
814
|
for (let fileIdx = 0; fileIdx < files.length; fileIdx++) {
|
|
@@ -849,27 +870,43 @@ async function processUnifiedFilesArray(options, maxSize, provider) {
|
|
|
849
870
|
if (fileRegistry && fileRegistry.size > 0) {
|
|
850
871
|
const previewText = await fileRegistry.generatePromptPreview();
|
|
851
872
|
if (previewText) {
|
|
852
|
-
|
|
873
|
+
inp2.text = (inp2.text || "") + previewText;
|
|
853
874
|
logger.info(`[FileDetector] Injected previews for ${fileRegistry.size} lazily-registered file(s)`);
|
|
854
875
|
}
|
|
855
876
|
const registeredFiles = fileRegistry.list();
|
|
856
877
|
for (const ref of registeredFiles) {
|
|
857
878
|
if (ref.extractedImages && ref.extractedImages.length > 0) {
|
|
858
|
-
|
|
859
|
-
...(options.input.images || []),
|
|
860
|
-
...ref.extractedImages,
|
|
861
|
-
];
|
|
879
|
+
inp2.images = [...(inp2.images || []), ...ref.extractedImages];
|
|
862
880
|
logger.info(`[FileDetector] Injected ${ref.extractedImages.length} extracted images from "${ref.filename}"`);
|
|
863
881
|
}
|
|
864
882
|
}
|
|
865
883
|
}
|
|
866
884
|
logger.info(`[NEUROLINK] File processing complete: ${includedCount}/${totalFiles} files included in message`);
|
|
885
|
+
// Augment options.systemPrompt with file-handling guidance so providers
|
|
886
|
+
// that bypass the message-builder's system message and read
|
|
887
|
+
// `options.systemPrompt` directly (e.g. GoogleVertex's native @google/genai
|
|
888
|
+
// path uses `config.systemInstruction = options.systemPrompt`) still see
|
|
889
|
+
// the "treat inlined CSV/PDF as the actual file" guidance. Without this,
|
|
890
|
+
// Vertex Gemini 2.5 reliably responds with "no files attached" even
|
|
891
|
+
// though the CSV content is fully embedded in the user prompt.
|
|
892
|
+
if (includedCount > 0) {
|
|
893
|
+
const filePromptAugmentation = `\n\nIMPORTANT FILE HANDLING INSTRUCTIONS:
|
|
894
|
+
- The full content of the user's local file(s) is INLINED in this message under "## CSV Data from ..." / "## PDF Data from ..." / "## File: ..." headings — it is the actual file the user is asking about.
|
|
895
|
+
- TREAT THE INLINED CONTENT AS IF IT WERE AN ATTACHMENT. Do NOT respond with "no files attached" or ask the user to re-upload — the data is already here.
|
|
896
|
+
- DO NOT use GitHub tools (get_file_contents, search_code, etc.) for local files - they only work for remote repository files.
|
|
897
|
+
- Analyze the inlined file content directly without attempting to fetch or read files using tools.`;
|
|
898
|
+
const existingSystem = (options.systemPrompt || "").trim();
|
|
899
|
+
options.systemPrompt = existingSystem
|
|
900
|
+
? `${existingSystem}${filePromptAugmentation}`
|
|
901
|
+
: filePromptAugmentation.trim();
|
|
902
|
+
}
|
|
867
903
|
});
|
|
868
904
|
}
|
|
869
905
|
/**
|
|
870
906
|
* Process explicit CSV files array and append to options.input.text.
|
|
871
907
|
*/
|
|
872
908
|
async function processExplicitCsvFiles(options) {
|
|
909
|
+
options.input ??= {};
|
|
873
910
|
if (!options.input.csvFiles || options.input.csvFiles.length === 0) {
|
|
874
911
|
return;
|
|
875
912
|
}
|
|
@@ -891,8 +928,11 @@ async function processExplicitCsvFiles(options) {
|
|
|
891
928
|
csvSection += metadataText + `\n\n`;
|
|
892
929
|
}
|
|
893
930
|
}
|
|
894
|
-
|
|
931
|
+
// Put the actual CSV content BEFORE the tool instructions —
|
|
932
|
+
// buildCSVToolInstructions references "the CSV data shown above"
|
|
933
|
+
// and the trailing position keeps that reference accurate.
|
|
895
934
|
csvSection += result.content;
|
|
935
|
+
csvSection += buildCSVToolInstructions(filePath);
|
|
896
936
|
options.input.text += csvSection;
|
|
897
937
|
logger.info(`[CSV] ✅ Processed: ${filename}`);
|
|
898
938
|
}
|
|
@@ -908,6 +948,7 @@ async function processExplicitCsvFiles(options) {
|
|
|
908
948
|
* Enforce post-processing budget on accumulated text content and log token usage.
|
|
909
949
|
*/
|
|
910
950
|
function enforcePostProcessingBudget(options, provider, model) {
|
|
951
|
+
options.input ??= {};
|
|
911
952
|
if (!options.input.text) {
|
|
912
953
|
return;
|
|
913
954
|
}
|
|
@@ -946,6 +987,7 @@ function enforcePostProcessingBudget(options, provider, model) {
|
|
|
946
987
|
* Process explicit PDF files and return structured PDF entries for multimodal processing.
|
|
947
988
|
*/
|
|
948
989
|
async function processExplicitPdfFiles(options, maxSize, provider) {
|
|
990
|
+
options.input ??= {};
|
|
949
991
|
const pdfFiles = [];
|
|
950
992
|
if (!options.input.pdfFiles || options.input.pdfFiles.length === 0) {
|
|
951
993
|
return pdfFiles;
|
|
@@ -981,6 +1023,7 @@ async function processExplicitPdfFiles(options, maxSize, provider) {
|
|
|
981
1023
|
* conversation instructions, structured output instructions, and file handling guidance.
|
|
982
1024
|
*/
|
|
983
1025
|
function buildMultimodalSystemPrompt(options, hasPDFFiles) {
|
|
1026
|
+
options.input ??= {};
|
|
984
1027
|
let systemPrompt = options.systemPrompt?.trim() || "";
|
|
985
1028
|
const hasConversationHistory = options.conversationHistory && options.conversationHistory.length > 0;
|
|
986
1029
|
if (hasConversationHistory) {
|
|
@@ -989,9 +1032,10 @@ function buildMultimodalSystemPrompt(options, hasPDFFiles) {
|
|
|
989
1032
|
if (shouldUseStructuredOutput(options)) {
|
|
990
1033
|
systemPrompt = `${systemPrompt.trim()}${STRUCTURED_OUTPUT_INSTRUCTIONS}`;
|
|
991
1034
|
}
|
|
992
|
-
const
|
|
993
|
-
|
|
994
|
-
|
|
1035
|
+
const inp = options.input;
|
|
1036
|
+
const hasCSVFiles = (inp.csvFiles && inp.csvFiles.length > 0) ||
|
|
1037
|
+
(inp.files &&
|
|
1038
|
+
inp.files.some((f) => typeof f === "string" ? f.toLowerCase().endsWith(".csv") : false));
|
|
995
1039
|
if (hasCSVFiles || hasPDFFiles) {
|
|
996
1040
|
const fileTypes = [];
|
|
997
1041
|
if (hasPDFFiles) {
|
|
@@ -1001,7 +1045,8 @@ function buildMultimodalSystemPrompt(options, hasPDFFiles) {
|
|
|
1001
1045
|
fileTypes.push("CSVs");
|
|
1002
1046
|
}
|
|
1003
1047
|
systemPrompt += `\n\nIMPORTANT FILE HANDLING INSTRUCTIONS:
|
|
1004
|
-
-
|
|
1048
|
+
- The full content of the user's local ${fileTypes.join(", ")} (and any images) is INLINED in this message under the "## CSV Data from ..." / "## PDF Data from ..." headings — it is the actual file the user is asking about.
|
|
1049
|
+
- TREAT THE INLINED CONTENT AS IF IT WERE AN ATTACHMENT. Do NOT respond with "no files attached" or ask the user to re-upload — the data is already here.
|
|
1005
1050
|
- DO NOT use GitHub tools (get_file_contents, search_code, etc.) for local files - they only work for remote repository files
|
|
1006
1051
|
- Analyze the provided file content directly without attempting to fetch or read files using tools
|
|
1007
1052
|
- GitHub MCP tools are ONLY for remote repository operations, not local filesystem access
|
|
@@ -1014,6 +1059,16 @@ function buildMultimodalSystemPrompt(options, hasPDFFiles) {
|
|
|
1014
1059
|
* Detects when images are present and routes through provider adapter
|
|
1015
1060
|
*/
|
|
1016
1061
|
export async function buildMultimodalMessagesArray(options, provider, model) {
|
|
1062
|
+
// Media-only callers (avatar / music / video) may omit `input` entirely.
|
|
1063
|
+
// Normalise to an empty object so all sub-functions can access input.*
|
|
1064
|
+
// without defensive null checks on every field access.
|
|
1065
|
+
if (!options.input) {
|
|
1066
|
+
options.input = {};
|
|
1067
|
+
}
|
|
1068
|
+
// After normalisation `input` is guaranteed non-undefined. Capture it in a
|
|
1069
|
+
// local const so TypeScript sees the definite (non-optional) type in the
|
|
1070
|
+
// rest of this function, avoiding 60+ "possibly undefined" errors.
|
|
1071
|
+
const inp = options.input;
|
|
1017
1072
|
// Compute provider-specific max PDF size once for consistent validation
|
|
1018
1073
|
const pdfConfig = PDFProcessor.getProviderConfig(provider);
|
|
1019
1074
|
const maxSize = pdfConfig
|
|
@@ -1030,20 +1085,19 @@ export async function buildMultimodalMessagesArray(options, provider, model) {
|
|
|
1030
1085
|
// Process explicit PDF files
|
|
1031
1086
|
const pdfFiles = await processExplicitPdfFiles(options, maxSize, provider);
|
|
1032
1087
|
// Check if this is a multimodal request
|
|
1033
|
-
const hasImages = (
|
|
1034
|
-
(
|
|
1035
|
-
options.input.content.some((c) => c.type === "image"));
|
|
1088
|
+
const hasImages = (inp.images && inp.images.length > 0) ||
|
|
1089
|
+
(inp.content && inp.content.some((c) => c.type === "image"));
|
|
1036
1090
|
const hasPDFs = pdfFiles.length > 0;
|
|
1037
1091
|
// If no images or PDFs, use standard message building and convert to MultimodalChatMessage[]
|
|
1038
1092
|
if (!hasImages && !hasPDFs) {
|
|
1039
|
-
if (
|
|
1040
|
-
|
|
1093
|
+
if (inp.csvFiles) {
|
|
1094
|
+
inp.csvFiles = [];
|
|
1041
1095
|
}
|
|
1042
|
-
if (
|
|
1043
|
-
|
|
1096
|
+
if (inp.pdfFiles) {
|
|
1097
|
+
inp.pdfFiles = [];
|
|
1044
1098
|
}
|
|
1045
|
-
if (
|
|
1046
|
-
|
|
1099
|
+
if (inp.files) {
|
|
1100
|
+
inp.files = [];
|
|
1047
1101
|
}
|
|
1048
1102
|
const standardMessages = await buildMessagesArray(options);
|
|
1049
1103
|
return standardMessages.map((msg) => {
|
|
@@ -1128,15 +1182,14 @@ export async function buildMultimodalMessagesArray(options, provider, model) {
|
|
|
1128
1182
|
// Handle multimodal content
|
|
1129
1183
|
try {
|
|
1130
1184
|
let userContent;
|
|
1131
|
-
if (
|
|
1132
|
-
userContent = await convertContentToProviderFormat(
|
|
1185
|
+
if (inp.content && inp.content.length > 0) {
|
|
1186
|
+
userContent = await convertContentToProviderFormat(inp.content, provider, model);
|
|
1133
1187
|
}
|
|
1134
|
-
else if ((
|
|
1135
|
-
|
|
1136
|
-
userContent = await convertMultimodalToProviderFormat(options.input.text, options.input.images || [], pdfFiles, provider, model);
|
|
1188
|
+
else if ((inp.images && inp.images.length > 0) || pdfFiles.length > 0) {
|
|
1189
|
+
userContent = await convertMultimodalToProviderFormat(inp.text ?? "", inp.images || [], pdfFiles, provider, model);
|
|
1137
1190
|
}
|
|
1138
1191
|
else {
|
|
1139
|
-
userContent =
|
|
1192
|
+
userContent = inp.text;
|
|
1140
1193
|
}
|
|
1141
1194
|
if (typeof userContent === "string") {
|
|
1142
1195
|
messages.push({
|
|
@@ -1160,7 +1213,7 @@ export async function buildMultimodalMessagesArray(options, provider, model) {
|
|
|
1160
1213
|
provider,
|
|
1161
1214
|
model,
|
|
1162
1215
|
hasImages,
|
|
1163
|
-
imageCount:
|
|
1216
|
+
imageCount: inp.images?.length || 0,
|
|
1164
1217
|
});
|
|
1165
1218
|
throw error;
|
|
1166
1219
|
}
|