@juspay/neurolink 12.14.15 → 12.14.16

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.
@@ -49,6 +49,15 @@ export declare function createThinkingConfig(options: CreateThinkingConfigOption
49
49
  * ```
50
50
  */
51
51
  export declare function createThinkingConfigFromRecord(options: Record<string, unknown>): ThinkingConfig | undefined;
52
+ /**
53
+ * Maps a qualitative ThinkingLevel onto a numeric thinkingBudget within a
54
+ * model's verified [min, max] range (see `getGemini25ThinkingBudgetRange`).
55
+ * Exported for deterministic testing of the level->budget mapping.
56
+ */
57
+ export declare function mapThinkingLevelToBudget(level: ThinkingLevel, range: {
58
+ min: number;
59
+ max: number;
60
+ }): number;
52
61
  /**
53
62
  * Creates thinkingConfig for native Gemini SDK (not AI SDK).
54
63
  *
@@ -56,17 +65,27 @@ export declare function createThinkingConfigFromRecord(options: Record<string, u
56
65
  * structure is different from the AI SDK providerOptions.
57
66
  *
58
67
  * @param config - The thinkingConfig from options
68
+ * @param modelName - Resolved model id, used to pick the right wire shape.
69
+ * Gemini 3 accepts `thinkingLevel` directly. Gemini 2.5 rejects that field
70
+ * with HTTP 400 INVALID_ARGUMENT "thinking_level not supported by this
71
+ * model" (verified live against Vertex for gemini-2.5-pro, -flash and
72
+ * -flash-lite) and needs a numeric `thinkingBudget` instead — so when
73
+ * `modelName` identifies a Gemini 2.5 model, the requested level is
74
+ * translated into a budget via `mapThinkingLevelToBudget` and
75
+ * `thinkingLevel` is omitted from the result entirely. Omitting
76
+ * `modelName` (or passing a Gemini 3 / unrecognized model) preserves the
77
+ * original behavior of forwarding `thinkingLevel` as-is.
59
78
  * @returns NativeThinkingConfig object or undefined
60
79
  *
61
80
  * @example
62
81
  * ```typescript
63
- * const nativeConfig = createNativeThinkingConfig(options.thinkingConfig);
82
+ * const nativeConfig = createNativeThinkingConfig(options.thinkingConfig, modelName);
64
83
  * if (nativeConfig) {
65
84
  * sdkConfig.thinkingConfig = nativeConfig;
66
85
  * }
67
86
  * ```
68
87
  */
69
- export declare function createNativeThinkingConfig(config: ThinkingConfig | undefined): NativeThinkingConfig | undefined;
88
+ export declare function createNativeThinkingConfig(config: ThinkingConfig | undefined, modelName?: string): NativeThinkingConfig | undefined;
70
89
  /**
71
90
  * Checks if thinkingConfig should be applied based on options.
72
91
  *
@@ -4,6 +4,8 @@
4
4
  * This module provides helper functions to create thinkingConfig objects consistently
5
5
  * across the codebase, reducing duplication in CLI and providers.
6
6
  */
7
+ import { getGemini25ThinkingBudgetRange, isGemini3Model, } from "./modelDetection.js";
8
+ import { logger } from "./logger.js";
7
9
  /**
8
10
  * Default token budget for thinking operations
9
11
  */
@@ -67,6 +69,31 @@ export function createThinkingConfigFromRecord(options) {
67
69
  thinkingBudget,
68
70
  });
69
71
  }
72
+ // Where a ThinkingLevel falls within a model's verified thinkingBudget
73
+ // range. This is a design choice (Vertex has no notion of "levels" for
74
+ // Gemini 2.5 — only a numeric budget), not a vendor-specified mapping:
75
+ // "minimal"/"high" pin the floor/ceiling of the model's own verified range,
76
+ // "low"/"medium" split the middle so all four levels stay distinguishable.
77
+ const THINKING_LEVEL_FRACTIONS = {
78
+ minimal: 0,
79
+ low: 0.25,
80
+ medium: 0.55,
81
+ high: 1,
82
+ };
83
+ /**
84
+ * Maps a qualitative ThinkingLevel onto a numeric thinkingBudget within a
85
+ * model's verified [min, max] range (see `getGemini25ThinkingBudgetRange`).
86
+ * Exported for deterministic testing of the level->budget mapping.
87
+ */
88
+ export function mapThinkingLevelToBudget(level, range) {
89
+ const fraction = THINKING_LEVEL_FRACTIONS[level];
90
+ return Math.round(range.min + fraction * (range.max - range.min));
91
+ }
92
+ // Models for which the "no verified budget range" WARN in
93
+ // createNativeThinkingConfig has already fired. Keyed by model name so a
94
+ // long-running process (or an agentic loop re-generating against the same
95
+ // model) logs the silent-drop once per model instead of once per call.
96
+ const warnedNoBudgetRangeModels = new Set();
70
97
  /**
71
98
  * Creates thinkingConfig for native Gemini SDK (not AI SDK).
72
99
  *
@@ -74,23 +101,55 @@ export function createThinkingConfigFromRecord(options) {
74
101
  * structure is different from the AI SDK providerOptions.
75
102
  *
76
103
  * @param config - The thinkingConfig from options
104
+ * @param modelName - Resolved model id, used to pick the right wire shape.
105
+ * Gemini 3 accepts `thinkingLevel` directly. Gemini 2.5 rejects that field
106
+ * with HTTP 400 INVALID_ARGUMENT "thinking_level not supported by this
107
+ * model" (verified live against Vertex for gemini-2.5-pro, -flash and
108
+ * -flash-lite) and needs a numeric `thinkingBudget` instead — so when
109
+ * `modelName` identifies a Gemini 2.5 model, the requested level is
110
+ * translated into a budget via `mapThinkingLevelToBudget` and
111
+ * `thinkingLevel` is omitted from the result entirely. Omitting
112
+ * `modelName` (or passing a Gemini 3 / unrecognized model) preserves the
113
+ * original behavior of forwarding `thinkingLevel` as-is.
77
114
  * @returns NativeThinkingConfig object or undefined
78
115
  *
79
116
  * @example
80
117
  * ```typescript
81
- * const nativeConfig = createNativeThinkingConfig(options.thinkingConfig);
118
+ * const nativeConfig = createNativeThinkingConfig(options.thinkingConfig, modelName);
82
119
  * if (nativeConfig) {
83
120
  * sdkConfig.thinkingConfig = nativeConfig;
84
121
  * }
85
122
  * ```
86
123
  */
87
- export function createNativeThinkingConfig(config) {
124
+ export function createNativeThinkingConfig(config, modelName) {
88
125
  if (!config?.enabled && !config?.thinkingLevel) {
89
126
  return undefined;
90
127
  }
128
+ const level = config.thinkingLevel ?? DEFAULT_THINKING_LEVEL;
129
+ if (modelName && !isGemini3Model(modelName)) {
130
+ const budgetRange = getGemini25ThinkingBudgetRange(modelName);
131
+ if (budgetRange) {
132
+ return {
133
+ includeThoughts: true,
134
+ thinkingBudget: mapThinkingLevelToBudget(level, budgetRange),
135
+ };
136
+ }
137
+ // Not a Gemini 3 model and not a Gemini 2.5 model we have a verified
138
+ // budget range for: no evidence this model accepts either parameter, so
139
+ // omit thinkingConfig rather than guess a shape that might itself 400.
140
+ // The caller opted into thinking and gets none of it here, so surface it
141
+ // once per model instead of leaving it indistinguishable from "thinking
142
+ // is off".
143
+ if (!warnedNoBudgetRangeModels.has(modelName)) {
144
+ warnedNoBudgetRangeModels.add(modelName);
145
+ logger.warn(`[thinkingConfig] "${modelName}" has no verified Gemini thinkingBudget range; ` +
146
+ "omitting thinkingConfig — requested thinkingLevel is silently disabled.");
147
+ }
148
+ return undefined;
149
+ }
91
150
  return {
92
151
  includeThoughts: true,
93
- thinkingLevel: config.thinkingLevel ?? DEFAULT_THINKING_LEVEL,
152
+ thinkingLevel: level,
94
153
  };
95
154
  }
96
155
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "12.14.15",
3
+ "version": "12.14.16",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (connect any MCP server), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
6
6
  "author": {
@@ -104,14 +104,18 @@
104
104
  "test:loop-engine": "pnpm exec tsx test/continuous-test-suite-loop-engine.ts",
105
105
  "test:middleware": "pnpm exec tsx test/continuous-test-suite-middleware.ts",
106
106
  "test:stream-middleware": "pnpm exec tsx test/continuous-test-suite-stream-middleware.ts",
107
+ "test:stream-tool-telemetry": "pnpm exec tsx test/continuous-test-suite-stream-tool-telemetry.ts",
107
108
  "test:observability": "pnpm exec tsx test/continuous-test-suite-observability.ts",
108
109
  "test:ppt": "pnpm exec tsx test/continuous-test-suite-ppt.ts",
109
110
  "test:vertex-loop-characterization": "tsx test/continuous-test-suite-vertex-loop-characterization.ts",
111
+ "test:vertex-claude-thinking": "pnpm exec tsx test/continuous-test-suite-vertex-claude-thinking.ts",
110
112
  "test:providers": "pnpm exec tsx test/continuous-test-suite-providers.ts",
111
113
  "test:new-providers": "pnpm exec tsx test/continuous-test-suite-new-providers.ts",
112
114
  "test:matrix": "pnpm exec tsx test/continuous-test-suite-provider-matrix.ts",
113
115
  "test:matrix:cli": "pnpm exec tsx test/continuous-test-suite-provider-matrix-cli.ts",
114
116
  "test:thinking-config": "pnpm exec tsx test/continuous-test-suite-sdk-thinking-config.ts",
117
+ "test:gemini-thinking-level": "pnpm exec tsx test/continuous-test-suite-gemini-thinking-level.ts",
118
+ "test:gemini-thinking-level-ai-studio": "pnpm exec tsx test/continuous-test-suite-gemini-thinking-level-ai-studio.ts",
115
119
  "test:mcp:spans": "pnpm exec tsx test/continuous-test-suite-mcp-spans.ts",
116
120
  "test:mcp:infra": "pnpm exec tsx test/continuous-test-suite-mcp-infra.ts",
117
121
  "test:vendor-recovery": "pnpm exec tsx test/continuous-test-suite-native-vendor-recovery.ts",