@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
|
@@ -17,6 +17,61 @@ import { logger } from "../utils/logger.js";
|
|
|
17
17
|
import { convertZodToJsonSchema, ensureNestedSchemaTypes, inlineJsonSchema, isZodSchema, normalizeJsonSchemaObject, } from "../utils/schemaConversion.js";
|
|
18
18
|
import { createNativeThinkingConfig } from "../utils/thinkingConfig.js";
|
|
19
19
|
// ── Functions ──
|
|
20
|
+
/**
|
|
21
|
+
* Google's `function_declarations[].name` validator regex.
|
|
22
|
+
*
|
|
23
|
+
* Empirically (and per the Vertex/AI Studio API error message), the server
|
|
24
|
+
* enforces `[A-Za-z_][A-Za-z0-9_.:-]{0,127}`. Tool names that don't match
|
|
25
|
+
* fail with HTTP 400 "Invalid function name", which surfaces as a misleading
|
|
26
|
+
* tool-calling failure for the whole request.
|
|
27
|
+
*
|
|
28
|
+
* MCP-imported or user-registered tools may legally contain characters
|
|
29
|
+
* outside this set (e.g. `/`, spaces, unicode), so we sanitize defensively
|
|
30
|
+
* before sending to Google. The sanitized name is also used as the
|
|
31
|
+
* `executeMap` key so the round-trip from Google's function-call response
|
|
32
|
+
* back to our executor still works.
|
|
33
|
+
*/
|
|
34
|
+
const GOOGLE_FN_NAME_REGEX = /^[A-Za-z_][A-Za-z0-9_.:-]{0,127}$/;
|
|
35
|
+
const GOOGLE_FN_NAME_MAX_LENGTH = 128;
|
|
36
|
+
export function sanitizeForGoogleFunctionName(name) {
|
|
37
|
+
if (GOOGLE_FN_NAME_REGEX.test(name)) {
|
|
38
|
+
return name;
|
|
39
|
+
}
|
|
40
|
+
let sanitized = name.replace(/[^A-Za-z0-9_.:-]/g, "_");
|
|
41
|
+
if (!/^[A-Za-z_]/.test(sanitized)) {
|
|
42
|
+
sanitized = `_${sanitized}`;
|
|
43
|
+
}
|
|
44
|
+
if (sanitized.length > GOOGLE_FN_NAME_MAX_LENGTH) {
|
|
45
|
+
sanitized = sanitized.slice(0, GOOGLE_FN_NAME_MAX_LENGTH);
|
|
46
|
+
}
|
|
47
|
+
return sanitized;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a sanitized Gemini tool name to one that is both unique within
|
|
51
|
+
* the current request and at most 128 characters. When the candidate
|
|
52
|
+
* collides with an already-used name we append `_2`, `_3`, … — but
|
|
53
|
+
* reserve room for the suffix by truncating the base first so the
|
|
54
|
+
* resolved name never exceeds Google's `function_declarations[].name`
|
|
55
|
+
* limit.
|
|
56
|
+
*
|
|
57
|
+
* @param base The already-sanitized candidate name.
|
|
58
|
+
* @param isTaken Predicate that returns true if `name` is already used.
|
|
59
|
+
*/
|
|
60
|
+
export function resolveUniqueGoogleFunctionName(base, isTaken) {
|
|
61
|
+
if (!isTaken(base)) {
|
|
62
|
+
return base;
|
|
63
|
+
}
|
|
64
|
+
let suffix = 2;
|
|
65
|
+
while (true) {
|
|
66
|
+
const suffixStr = `_${suffix}`;
|
|
67
|
+
const trimmedBase = base.slice(0, GOOGLE_FN_NAME_MAX_LENGTH - suffixStr.length);
|
|
68
|
+
const candidate = `${trimmedBase}${suffixStr}`;
|
|
69
|
+
if (!isTaken(candidate)) {
|
|
70
|
+
return candidate;
|
|
71
|
+
}
|
|
72
|
+
suffix++;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
20
75
|
/**
|
|
21
76
|
* Sanitize a JSON Schema for Gemini's proto-based API.
|
|
22
77
|
*
|
|
@@ -102,6 +157,40 @@ export function sanitizeSchemaForGemini(schema) {
|
|
|
102
157
|
result[branch] = sanitizeSchemaForGemini(result[branch]);
|
|
103
158
|
}
|
|
104
159
|
}
|
|
160
|
+
// JSON Schema Draft-4 `exclusiveMinimum: true` / `exclusiveMaximum: true`
|
|
161
|
+
// (boolean form) is rejected by Gemini's OpenAPI 3.0 validator, which
|
|
162
|
+
// expects a numeric bound. zod-to-json-schema's openApi3 target still
|
|
163
|
+
// emits the Draft-4 form for `z.number().positive()` etc. Translate to
|
|
164
|
+
// the numeric form when paired with `minimum`/`maximum`, or drop.
|
|
165
|
+
if (typeof result.exclusiveMinimum === "boolean") {
|
|
166
|
+
if (result.exclusiveMinimum === true &&
|
|
167
|
+
typeof result.minimum === "number") {
|
|
168
|
+
result.exclusiveMinimum = result.minimum;
|
|
169
|
+
delete result.minimum;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
delete result.exclusiveMinimum;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (typeof result.exclusiveMaximum === "boolean") {
|
|
176
|
+
if (result.exclusiveMaximum === true &&
|
|
177
|
+
typeof result.maximum === "number") {
|
|
178
|
+
result.exclusiveMaximum = result.maximum;
|
|
179
|
+
delete result.maximum;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
delete result.exclusiveMaximum;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Clamp `maximum`/`minimum` past int32 — Gemini's protobuf serializer
|
|
186
|
+
// treats `type: "integer"` as int32 and rejects bounds beyond ~2.1e9.
|
|
187
|
+
const INT32_MAX = 2147483647;
|
|
188
|
+
if (typeof result.maximum === "number" && result.maximum > INT32_MAX) {
|
|
189
|
+
delete result.maximum;
|
|
190
|
+
}
|
|
191
|
+
if (typeof result.minimum === "number" && result.minimum < -INT32_MAX) {
|
|
192
|
+
delete result.minimum;
|
|
193
|
+
}
|
|
105
194
|
return result;
|
|
106
195
|
}
|
|
107
196
|
/**
|
|
@@ -117,8 +206,27 @@ export function sanitizeSchemaForGemini(schema) {
|
|
|
117
206
|
export function sanitizeToolsForGemini(tools) {
|
|
118
207
|
const sanitized = {};
|
|
119
208
|
const dropped = [];
|
|
209
|
+
const renamed = [];
|
|
210
|
+
const originalNameMap = new Map();
|
|
120
211
|
for (const [name, tool] of Object.entries(tools)) {
|
|
121
212
|
try {
|
|
213
|
+
// Sanitize the tool name to fit Google's function_declarations regex.
|
|
214
|
+
// Without this, MCP-imported or user-registered tools whose names contain
|
|
215
|
+
// characters outside [A-Za-z_][A-Za-z0-9_.:-]{0,127} cause the entire
|
|
216
|
+
// request to 400 with "Invalid function name", surfacing as a misleading
|
|
217
|
+
// tool-calling failure. Distinct originals that collapse onto the same
|
|
218
|
+
// sanitized name (e.g. "my/tool" and "my-tool" → "my_tool") are
|
|
219
|
+
// disambiguated with a numeric suffix that preserves Google's 128-char
|
|
220
|
+
// ceiling.
|
|
221
|
+
const candidate = sanitizeForGoogleFunctionName(name);
|
|
222
|
+
const safeName = resolveUniqueGoogleFunctionName(candidate, (n) => n in sanitized);
|
|
223
|
+
// Always record the mapping so downstream code can translate every
|
|
224
|
+
// safeName back to the original — including the no-rename identity
|
|
225
|
+
// mapping, which simplifies the lookup path.
|
|
226
|
+
originalNameMap.set(safeName, name);
|
|
227
|
+
if (safeName !== name) {
|
|
228
|
+
renamed.push({ from: name, to: safeName });
|
|
229
|
+
}
|
|
122
230
|
// Access the legacy `parameters` field that may exist on older AI SDK tools.
|
|
123
231
|
// AI SDK v6 uses `inputSchema`, but v3/v4 tools and third-party wrappers use `parameters`.
|
|
124
232
|
const legacyTool = tool;
|
|
@@ -134,8 +242,8 @@ export function sanitizeToolsForGemini(tools) {
|
|
|
134
242
|
// additionalProperties are removed. The resulting schema is Gemini-compatible
|
|
135
243
|
// but loses some type constraints from the original Zod schema.
|
|
136
244
|
const sanitizedSchema = sanitizeSchemaForGemini(inlined);
|
|
137
|
-
sanitized[
|
|
138
|
-
description: tool.description || `Tool: ${
|
|
245
|
+
sanitized[safeName] = createAISDKTool({
|
|
246
|
+
description: tool.description || `Tool: ${safeName}`,
|
|
139
247
|
inputSchema: aiJsonSchema(sanitizedSchema),
|
|
140
248
|
execute: tool.execute,
|
|
141
249
|
});
|
|
@@ -147,14 +255,14 @@ export function sanitizeToolsForGemini(tools) {
|
|
|
147
255
|
const rawSchema = params
|
|
148
256
|
.jsonSchema;
|
|
149
257
|
const sanitizedSchema = sanitizeSchemaForGemini(inlineJsonSchema(rawSchema));
|
|
150
|
-
sanitized[
|
|
151
|
-
description: tool.description || `Tool: ${
|
|
258
|
+
sanitized[safeName] = createAISDKTool({
|
|
259
|
+
description: tool.description || `Tool: ${safeName}`,
|
|
152
260
|
inputSchema: aiJsonSchema(sanitizedSchema),
|
|
153
261
|
execute: tool.execute,
|
|
154
262
|
});
|
|
155
263
|
}
|
|
156
264
|
else {
|
|
157
|
-
sanitized[
|
|
265
|
+
sanitized[safeName] = tool;
|
|
158
266
|
}
|
|
159
267
|
}
|
|
160
268
|
catch (error) {
|
|
@@ -163,7 +271,12 @@ export function sanitizeToolsForGemini(tools) {
|
|
|
163
271
|
dropped.push(name);
|
|
164
272
|
}
|
|
165
273
|
}
|
|
166
|
-
|
|
274
|
+
if (renamed.length > 0) {
|
|
275
|
+
logger.warn(`[Gemini] ${renamed.length} tool name(s) sanitized for Google's function-name regex: ${renamed
|
|
276
|
+
.map((r) => `"${r.from}" -> "${r.to}"`)
|
|
277
|
+
.join(", ")}`);
|
|
278
|
+
}
|
|
279
|
+
return { tools: sanitized, dropped, originalNameMap };
|
|
167
280
|
}
|
|
168
281
|
export function normalizeToolsForJsonSchemaProvider(tools) {
|
|
169
282
|
const normalizedTools = {};
|
|
@@ -212,11 +325,29 @@ export function buildNativeToolDeclarations(tools) {
|
|
|
212
325
|
const functionDeclarations = [];
|
|
213
326
|
const executeMap = new Map();
|
|
214
327
|
const skippedTools = [];
|
|
328
|
+
const renamedTools = [];
|
|
329
|
+
// Disambiguate distinct originals that collapse onto the same sanitized
|
|
330
|
+
// name (e.g. "my/tool" and "my-tool" both → "my_tool") via
|
|
331
|
+
// resolveUniqueGoogleFunctionName, which appends `_N` while keeping the
|
|
332
|
+
// final string within Google's 128-char limit. Track all assigned names
|
|
333
|
+
// regardless of whether the tool has an `execute` function (tools without
|
|
334
|
+
// execute are still pushed to functionDeclarations). The originalNameMap
|
|
335
|
+
// lets the calling stream loop translate Google-returned function-call
|
|
336
|
+
// names back to the consumer-facing identifier so the sanitization is
|
|
337
|
+
// transport-only.
|
|
338
|
+
const usedNames = new Set();
|
|
339
|
+
const originalNameMap = new Map();
|
|
215
340
|
for (const [name, tool] of Object.entries(tools)) {
|
|
216
341
|
try {
|
|
342
|
+
const candidate = sanitizeForGoogleFunctionName(name);
|
|
343
|
+
const safeName = resolveUniqueGoogleFunctionName(candidate, (n) => usedNames.has(n));
|
|
344
|
+
originalNameMap.set(safeName, name);
|
|
345
|
+
if (safeName !== name) {
|
|
346
|
+
renamedTools.push({ from: name, to: safeName });
|
|
347
|
+
}
|
|
217
348
|
const decl = {
|
|
218
|
-
name,
|
|
219
|
-
description: tool.description || `Tool: ${
|
|
349
|
+
name: safeName,
|
|
350
|
+
description: tool.description || `Tool: ${safeName}`,
|
|
220
351
|
};
|
|
221
352
|
// Access legacy `parameters` (AI SDK v3/v4) or current `inputSchema` (v6)
|
|
222
353
|
const legacyTool = tool;
|
|
@@ -241,8 +372,9 @@ export function buildNativeToolDeclarations(tools) {
|
|
|
241
372
|
decl.parametersJsonSchema = sanitizeSchemaForGemini(inlineJsonSchema(rawSchema));
|
|
242
373
|
}
|
|
243
374
|
functionDeclarations.push(decl);
|
|
375
|
+
usedNames.add(safeName);
|
|
244
376
|
if (tool.execute) {
|
|
245
|
-
executeMap.set(name, tool.execute);
|
|
377
|
+
executeMap.set(decl.name, tool.execute);
|
|
246
378
|
}
|
|
247
379
|
}
|
|
248
380
|
catch (err) {
|
|
@@ -253,7 +385,16 @@ export function buildNativeToolDeclarations(tools) {
|
|
|
253
385
|
if (skippedTools.length > 0) {
|
|
254
386
|
logger.warn(`[buildNativeToolDeclarations] ${skippedTools.length} tool(s) skipped due to schema errors: ${skippedTools.join(", ")}`);
|
|
255
387
|
}
|
|
256
|
-
|
|
388
|
+
if (renamedTools.length > 0) {
|
|
389
|
+
logger.warn(`[buildNativeToolDeclarations] ${renamedTools.length} tool name(s) sanitized for Google's function-name regex: ${renamedTools
|
|
390
|
+
.map((r) => `"${r.from}" -> "${r.to}"`)
|
|
391
|
+
.join(", ")}`);
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
toolsConfig: [{ functionDeclarations }],
|
|
395
|
+
executeMap,
|
|
396
|
+
originalNameMap,
|
|
397
|
+
};
|
|
257
398
|
}
|
|
258
399
|
/**
|
|
259
400
|
* Build the native @google/genai config object shared by stream and generate.
|
|
@@ -493,27 +634,42 @@ export function extractTextFromParts(rawResponseParts) {
|
|
|
493
634
|
* @param executeMap - Map of tool name to execute function
|
|
494
635
|
* @param failedTools - Mutable map tracking per-tool failure counts
|
|
495
636
|
* @param allToolCalls - Mutable array accumulating all tool call records
|
|
496
|
-
* @param options - Optional settings for execution tracking and cancellation
|
|
637
|
+
* @param options - Optional settings for execution tracking and cancellation,
|
|
638
|
+
* plus an `originalNameMap` (Google-safe → consumer-supplied
|
|
639
|
+
* identifier) so the sanitization stays transport-only and
|
|
640
|
+
* consumers see the names they registered.
|
|
497
641
|
* @returns Array of function responses for conversation history
|
|
498
642
|
*/
|
|
499
643
|
export async function executeNativeToolCalls(logLabel, stepFunctionCalls, executeMap, failedTools, allToolCalls, options) {
|
|
500
644
|
const functionResponses = [];
|
|
645
|
+
// Translate a Google-safe sanitized name back to the consumer-facing
|
|
646
|
+
// original name. Falls back to the safe name if the map is missing or
|
|
647
|
+
// doesn't contain the call (e.g. tool added mid-conversation).
|
|
648
|
+
const externalName = (safeName) => options?.originalNameMap?.get(safeName) ?? safeName;
|
|
649
|
+
// Note: tool:start / tool:end events are emitted by ToolsManager's
|
|
650
|
+
// `execute` wrapper (see src/lib/core/modules/ToolsManager.ts:355 and :790)
|
|
651
|
+
// around every tool's execute function. The native paths invoke that same
|
|
652
|
+
// wrapped execute via the executeMap, so emitting here would duplicate.
|
|
501
653
|
for (const call of stepFunctionCalls) {
|
|
502
|
-
|
|
654
|
+
const exposedName = externalName(call.name);
|
|
655
|
+
allToolCalls.push({ toolName: exposedName, args: call.args });
|
|
503
656
|
// Check if this tool has already exceeded retry limit
|
|
504
657
|
const failedInfo = failedTools.get(call.name);
|
|
505
658
|
if (failedInfo && failedInfo.count >= DEFAULT_TOOL_MAX_RETRIES) {
|
|
506
|
-
logger.warn(`${logLabel} Tool "${
|
|
659
|
+
logger.warn(`${logLabel} Tool "${exposedName}" has exceeded retry limit (${DEFAULT_TOOL_MAX_RETRIES}), skipping execution`);
|
|
507
660
|
const errorOutput = {
|
|
508
|
-
error: `TOOL_PERMANENTLY_FAILED: The tool "${
|
|
661
|
+
error: `TOOL_PERMANENTLY_FAILED: The tool "${exposedName}" has failed ${failedInfo.count} times and will not be retried. Last error: ${failedInfo.lastError}. Please proceed without using this tool or inform the user that this functionality is unavailable.`,
|
|
509
662
|
status: "permanently_failed",
|
|
510
663
|
do_not_retry: true,
|
|
511
664
|
};
|
|
665
|
+
// Wire transport-side `name: call.name` (Google needs the sanitized
|
|
666
|
+
// form to match the function declaration) while exposing the
|
|
667
|
+
// consumer-facing name in toolExecutions metadata.
|
|
512
668
|
functionResponses.push({
|
|
513
669
|
functionResponse: { name: call.name, response: errorOutput },
|
|
514
670
|
});
|
|
515
671
|
options?.toolExecutions?.push({
|
|
516
|
-
name:
|
|
672
|
+
name: exposedName,
|
|
517
673
|
input: call.args,
|
|
518
674
|
output: errorOutput,
|
|
519
675
|
});
|
|
@@ -534,7 +690,7 @@ export async function executeNativeToolCalls(logLabel, stepFunctionCalls, execut
|
|
|
534
690
|
functionResponse: { name: call.name, response: { result } },
|
|
535
691
|
});
|
|
536
692
|
options?.toolExecutions?.push({
|
|
537
|
-
name:
|
|
693
|
+
name: exposedName,
|
|
538
694
|
input: call.args,
|
|
539
695
|
output: result,
|
|
540
696
|
});
|
|
@@ -549,12 +705,12 @@ export async function executeNativeToolCalls(logLabel, stepFunctionCalls, execut
|
|
|
549
705
|
currentFailInfo.count++;
|
|
550
706
|
currentFailInfo.lastError = errorMessage;
|
|
551
707
|
failedTools.set(call.name, currentFailInfo);
|
|
552
|
-
logger.warn(`${logLabel} Tool "${
|
|
708
|
+
logger.warn(`${logLabel} Tool "${exposedName}" failed (attempt ${currentFailInfo.count}/${DEFAULT_TOOL_MAX_RETRIES}): ${errorMessage}`);
|
|
553
709
|
// Determine if this is a permanent failure
|
|
554
710
|
const isPermanentFailure = currentFailInfo.count >= DEFAULT_TOOL_MAX_RETRIES;
|
|
555
711
|
const errorOutput = {
|
|
556
712
|
error: isPermanentFailure
|
|
557
|
-
? `TOOL_PERMANENTLY_FAILED: The tool "${
|
|
713
|
+
? `TOOL_PERMANENTLY_FAILED: The tool "${exposedName}" has failed ${currentFailInfo.count} times with error: ${errorMessage}. This tool will not be retried. Please proceed without using this tool or inform the user that this functionality is unavailable.`
|
|
558
714
|
: `TOOL_EXECUTION_ERROR: ${errorMessage}. Retry attempt ${currentFailInfo.count}/${DEFAULT_TOOL_MAX_RETRIES}.`,
|
|
559
715
|
status: isPermanentFailure ? "permanently_failed" : "failed",
|
|
560
716
|
do_not_retry: isPermanentFailure,
|
|
@@ -565,7 +721,7 @@ export async function executeNativeToolCalls(logLabel, stepFunctionCalls, execut
|
|
|
565
721
|
functionResponse: { name: call.name, response: errorOutput },
|
|
566
722
|
});
|
|
567
723
|
options?.toolExecutions?.push({
|
|
568
|
-
name:
|
|
724
|
+
name: exposedName,
|
|
569
725
|
input: call.args,
|
|
570
726
|
output: errorOutput,
|
|
571
727
|
});
|
|
@@ -574,7 +730,7 @@ export async function executeNativeToolCalls(logLabel, stepFunctionCalls, execut
|
|
|
574
730
|
else {
|
|
575
731
|
// Tool not found is a permanent error
|
|
576
732
|
const errorOutput = {
|
|
577
|
-
error: `TOOL_NOT_FOUND: The tool "${
|
|
733
|
+
error: `TOOL_NOT_FOUND: The tool "${exposedName}" does not exist. Do not attempt to call this tool again.`,
|
|
578
734
|
status: "permanently_failed",
|
|
579
735
|
do_not_retry: true,
|
|
580
736
|
};
|
|
@@ -582,7 +738,7 @@ export async function executeNativeToolCalls(logLabel, stepFunctionCalls, execut
|
|
|
582
738
|
functionResponse: { name: call.name, response: errorOutput },
|
|
583
739
|
});
|
|
584
740
|
options?.toolExecutions?.push({
|
|
585
|
-
name:
|
|
741
|
+
name: exposedName,
|
|
586
742
|
input: call.args,
|
|
587
743
|
output: errorOutput,
|
|
588
744
|
});
|
|
@@ -656,22 +812,113 @@ export function buildGeminiResponseSchema(schema) {
|
|
|
656
812
|
* - The current user input should be appended AFTER calling this helper
|
|
657
813
|
* so the prior turns appear first in chronological order.
|
|
658
814
|
*/
|
|
659
|
-
export function prependConversationMessages(contents,
|
|
815
|
+
export function prependConversationMessages(contents,
|
|
816
|
+
// Accept either the full ChatMessage shape (when callers pass real Redis-
|
|
817
|
+
// backed history) or the reduced MinimalChatMessage shape (tests / synthetic
|
|
818
|
+
// callers). Only role, content, tool, args, and metadata.* are read here.
|
|
819
|
+
conversationMessages) {
|
|
660
820
|
if (!conversationMessages || conversationMessages.length === 0) {
|
|
661
821
|
return;
|
|
662
822
|
}
|
|
823
|
+
// Walk prior turns building ordered segments. Tool_call / tool_result rows
|
|
824
|
+
// get grouped by (turnCounter, stepIndex) so parallel calls within a step
|
|
825
|
+
// stay together and don't bleed across turn boundaries. Regular user/
|
|
826
|
+
// assistant messages act as those boundaries.
|
|
827
|
+
//
|
|
828
|
+
// Without this reconstruction, a text-only mapper would strip tool rows
|
|
829
|
+
// from history — leaving the model unaware of any tools it called in
|
|
830
|
+
// prior turns. The grouped emit (model with functionCall parts → user
|
|
831
|
+
// with functionResponse parts) is what @google/genai's own
|
|
832
|
+
// automaticFunctionCalling produces, so the SDK validates it as a
|
|
833
|
+
// well-formed multi-turn conversation.
|
|
834
|
+
const stepMap = new Map();
|
|
835
|
+
const segments = [];
|
|
836
|
+
let turnCounter = 0;
|
|
837
|
+
const makeKey = (stepIndex) => `${turnCounter}:${stepIndex ?? "undefined"}`;
|
|
838
|
+
const getOrCreateStep = (stepIndex) => {
|
|
839
|
+
const key = makeKey(stepIndex);
|
|
840
|
+
const existing = stepMap.get(key);
|
|
841
|
+
if (existing) {
|
|
842
|
+
return existing;
|
|
843
|
+
}
|
|
844
|
+
const step = {
|
|
845
|
+
type: "tool_step",
|
|
846
|
+
callParts: [],
|
|
847
|
+
resultParts: [],
|
|
848
|
+
};
|
|
849
|
+
stepMap.set(key, step);
|
|
850
|
+
segments.push(step);
|
|
851
|
+
return step;
|
|
852
|
+
};
|
|
663
853
|
for (const msg of conversationMessages) {
|
|
664
|
-
if (msg.role
|
|
854
|
+
if (msg.role === "tool_call") {
|
|
855
|
+
const step = getOrCreateStep(msg.metadata?.stepIndex);
|
|
856
|
+
const fcPart = {
|
|
857
|
+
functionCall: {
|
|
858
|
+
name: msg.tool || "unknown",
|
|
859
|
+
args: msg.args || {},
|
|
860
|
+
},
|
|
861
|
+
};
|
|
862
|
+
if (msg.metadata?.thoughtSignature) {
|
|
863
|
+
fcPart.thoughtSignature = msg.metadata.thoughtSignature;
|
|
864
|
+
}
|
|
865
|
+
step.callParts.push(fcPart);
|
|
665
866
|
continue;
|
|
666
867
|
}
|
|
667
|
-
|
|
668
|
-
|
|
868
|
+
if (msg.role === "tool_result") {
|
|
869
|
+
const step = getOrCreateStep(msg.metadata?.stepIndex);
|
|
870
|
+
let responsePayload;
|
|
871
|
+
try {
|
|
872
|
+
responsePayload =
|
|
873
|
+
msg.content !== undefined && msg.content !== null
|
|
874
|
+
? { result: JSON.parse(msg.content) }
|
|
875
|
+
: { result: "success" };
|
|
876
|
+
}
|
|
877
|
+
catch {
|
|
878
|
+
responsePayload = { result: msg.content ?? "success" };
|
|
879
|
+
}
|
|
880
|
+
step.resultParts.push({
|
|
881
|
+
functionResponse: {
|
|
882
|
+
name: msg.tool || "unknown",
|
|
883
|
+
response: responsePayload,
|
|
884
|
+
},
|
|
885
|
+
});
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
// Regular (user / assistant) message — acts as a turn boundary.
|
|
889
|
+
const role = msg.role === "assistant" ? "model" : msg.role;
|
|
890
|
+
if (role !== "user" && role !== "model") {
|
|
669
891
|
continue;
|
|
670
892
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
893
|
+
if (!msg.content || msg.content.trim().length === 0) {
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
// Increment turn counter BEFORE pushing the segment so any tool_calls
|
|
897
|
+
// that follow this message get a fresh (turnCounter, stepIndex) namespace.
|
|
898
|
+
turnCounter++;
|
|
899
|
+
const textPart = { text: msg.content };
|
|
900
|
+
if (msg.metadata?.thoughtSignature) {
|
|
901
|
+
textPart.thoughtSignature = msg.metadata.thoughtSignature;
|
|
902
|
+
}
|
|
903
|
+
segments.push({ type: "regular", role, parts: [textPart] });
|
|
904
|
+
}
|
|
905
|
+
// Emit in order: each ToolStep → model turn (calls) + user turn (results)
|
|
906
|
+
// — same ordering @google/genai's automaticFunctionCalling produces.
|
|
907
|
+
for (const seg of segments) {
|
|
908
|
+
if (seg.type === "regular") {
|
|
909
|
+
contents.push({ role: seg.role, parts: seg.parts });
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
if (seg.callParts.length === 0) {
|
|
913
|
+
if (seg.resultParts.length > 0) {
|
|
914
|
+
logger.debug("[GoogleNativeGemini3] Dropping orphan tool_result segment with no matching tool_call rows", { resultCount: seg.resultParts.length });
|
|
915
|
+
}
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
contents.push({ role: "model", parts: seg.callParts });
|
|
919
|
+
if (seg.resultParts.length > 0) {
|
|
920
|
+
contents.push({ role: "user", parts: seg.resultParts });
|
|
921
|
+
}
|
|
675
922
|
}
|
|
676
923
|
}
|
|
677
924
|
/**
|