@f5-sales-demo/pi-ai 21.0.0 → 21.2.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 CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ### Changed
8
+
9
+ - Replaced Vertex Gemini 3.6 Flash with GA Gemini 3.7 Flash and made full Vertex Gemini Flash and Pro models default to HIGH thinking while preserving supported explicit effort overrides ([#3460](https://github.com/f5-sales-demo/xcsh/issues/3460)).
10
+
7
11
  ### Fixed
8
12
 
9
13
  - Omit an empty OpenAI-compatible `tools` field unless prior tool-call history requires the explicit empty array, and suppress the internal no-auth credential sentinel from keyless request headers ([#2942](https://github.com/f5-sales-demo/xcsh/issues/2942), [#3361](https://github.com/f5-sales-demo/xcsh/issues/3361)).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5-sales-demo/pi-ai",
4
- "version": "21.0.0",
4
+ "version": "21.2.0",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://github.com/f5-sales-demo/xcsh",
7
7
  "author": "Can Boluk",
@@ -46,7 +46,7 @@
46
46
  "@anthropic-ai/sdk": "^0.115",
47
47
  "@aws-sdk/client-bedrock-runtime": "^3",
48
48
  "@bufbuild/protobuf": "^2.11",
49
- "@f5-sales-demo/pi-utils": "21.0.0",
49
+ "@f5-sales-demo/pi-utils": "21.2.0",
50
50
  "@google/genai": "^2.15",
51
51
  "@sinclair/typebox": "^0.34",
52
52
  "@smithy/node-http-handler": "^4.4",
@@ -80,7 +80,7 @@ const ANTHROPIC_ADAPTIVE_EFFORTS: readonly Effort[] = [
80
80
  */
81
81
  const ANTHROPIC_EXTENDED_EFFORT_VERSIONS: ReadonlySet<string> = new Set(["5.0"]);
82
82
 
83
- const GEMINI_3_PRO_EFFORTS: readonly Effort[] = [Effort.Low, Effort.High];
83
+ const GEMINI_3_PRO_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High];
84
84
  const GEMINI_3_FLASH_EFFORTS: readonly Effort[] = [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High];
85
85
  const GPT_5_2_PLUS_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High, Effort.XHigh];
86
86
  const GPT_5_1_CODEX_MINI_EFFORTS: readonly Effort[] = [Effort.Medium, Effort.High];
@@ -397,11 +397,22 @@ function inferModelThinking<TApi extends Api>(model: ApiModel<TApi>): ThinkingCo
397
397
  if (!minLevel || !maxLevel) {
398
398
  throw new Error(`Model ${model.provider}/${model.id} resolved to an empty thinking range`);
399
399
  }
400
- return {
400
+ const thinking: ThinkingConfig = {
401
401
  mode: inferThinkingControlMode(model, parsedModel),
402
402
  minLevel,
403
403
  maxLevel,
404
404
  };
405
+ if (
406
+ model.provider === "google-vertex" &&
407
+ parsedModel.family === "gemini" &&
408
+ !model.id.toLowerCase().includes("lite")
409
+ ) {
410
+ thinking.defaultLevel = Effort.High;
411
+ if (parsedModel.version.major === 3) {
412
+ thinking.canDisable = false;
413
+ }
414
+ }
415
+ return thinking;
405
416
  }
406
417
 
407
418
  function normalizeThinkingConfig(thinking: ThinkingConfig | undefined): ThinkingConfig | undefined {
@@ -414,7 +425,13 @@ function normalizeThinkingConfig(thinking: ThinkingConfig | undefined): Thinking
414
425
  function thinkingsEqual(left: ThinkingConfig | undefined, right: ThinkingConfig | undefined): boolean {
415
426
  if (left === right) return true;
416
427
  if (!left || !right) return false;
417
- return left.mode === right.mode && left.minLevel === right.minLevel && left.maxLevel === right.maxLevel;
428
+ return (
429
+ left.mode === right.mode &&
430
+ left.minLevel === right.minLevel &&
431
+ left.maxLevel === right.maxLevel &&
432
+ left.defaultLevel === right.defaultLevel &&
433
+ left.canDisable === right.canDisable
434
+ );
418
435
  }
419
436
 
420
437
  function expandEffortRange(thinking: ThinkingConfig): readonly Effort[] {
package/src/models.json CHANGED
@@ -7030,9 +7030,9 @@
7030
7030
  }
7031
7031
  },
7032
7032
  "google-vertex": {
7033
- "gemini-3.6-flash": {
7034
- "id": "gemini-3.6-flash",
7035
- "name": "Gemini 3.6 Flash",
7033
+ "gemini-3.7-flash": {
7034
+ "id": "gemini-3.7-flash",
7035
+ "name": "Gemini 3.7 Flash",
7036
7036
  "api": "google-vertex",
7037
7037
  "provider": "google-vertex",
7038
7038
  "baseUrl": "https://{location}-aiplatform.googleapis.com",
@@ -7042,9 +7042,9 @@
7042
7042
  "image"
7043
7043
  ],
7044
7044
  "cost": {
7045
- "input": 0,
7046
- "output": 0,
7047
- "cacheRead": 0,
7045
+ "input": 0.75,
7046
+ "output": 3.75,
7047
+ "cacheRead": 0.075,
7048
7048
  "cacheWrite": 0
7049
7049
  },
7050
7050
  "contextWindow": 1048576,
@@ -7052,7 +7052,9 @@
7052
7052
  "thinking": {
7053
7053
  "mode": "google-level",
7054
7054
  "minLevel": "low",
7055
- "maxLevel": "high"
7055
+ "maxLevel": "high",
7056
+ "defaultLevel": "high",
7057
+ "canDisable": false
7056
7058
  }
7057
7059
  },
7058
7060
  "gemini-1.5-flash": {
@@ -7177,7 +7179,8 @@
7177
7179
  "thinking": {
7178
7180
  "mode": "budget",
7179
7181
  "minLevel": "minimal",
7180
- "maxLevel": "high"
7182
+ "maxLevel": "high",
7183
+ "defaultLevel": "high"
7181
7184
  }
7182
7185
  },
7183
7186
  "gemini-2.5-flash-lite": {
@@ -7252,7 +7255,8 @@
7252
7255
  "thinking": {
7253
7256
  "mode": "budget",
7254
7257
  "minLevel": "minimal",
7255
- "maxLevel": "high"
7258
+ "maxLevel": "high",
7259
+ "defaultLevel": "high"
7256
7260
  }
7257
7261
  },
7258
7262
  "gemini-3-flash-preview": {
@@ -7277,7 +7281,9 @@
7277
7281
  "thinking": {
7278
7282
  "mode": "google-level",
7279
7283
  "minLevel": "minimal",
7280
- "maxLevel": "high"
7284
+ "maxLevel": "high",
7285
+ "defaultLevel": "high",
7286
+ "canDisable": false
7281
7287
  }
7282
7288
  },
7283
7289
  "gemini-3-pro-preview": {
@@ -7302,7 +7308,9 @@
7302
7308
  "thinking": {
7303
7309
  "mode": "google-level",
7304
7310
  "minLevel": "low",
7305
- "maxLevel": "high"
7311
+ "maxLevel": "high",
7312
+ "defaultLevel": "high",
7313
+ "canDisable": false
7306
7314
  }
7307
7315
  },
7308
7316
  "gemini-3.1-pro-preview": {
@@ -7327,7 +7335,9 @@
7327
7335
  "thinking": {
7328
7336
  "mode": "google-level",
7329
7337
  "minLevel": "low",
7330
- "maxLevel": "high"
7338
+ "maxLevel": "high",
7339
+ "defaultLevel": "high",
7340
+ "canDisable": false
7331
7341
  }
7332
7342
  },
7333
7343
  "gemini-3.1-pro-preview-customtools": {
@@ -7352,7 +7362,9 @@
7352
7362
  "thinking": {
7353
7363
  "mode": "google-level",
7354
7364
  "minLevel": "low",
7355
- "maxLevel": "high"
7365
+ "maxLevel": "high",
7366
+ "defaultLevel": "high",
7367
+ "canDisable": false
7356
7368
  }
7357
7369
  }
7358
7370
  },
@@ -62,10 +62,10 @@ function resolveThoughtSignature(isSameProviderAndModel: boolean, signature: str
62
62
  }
63
63
 
64
64
  /**
65
- * Claude models via Google APIs require explicit tool call IDs in function calls/responses.
65
+ * Models with strict Google tool round trips require explicit matching call/response IDs.
66
66
  */
67
67
  export function requiresToolCallId(modelId: string): boolean {
68
- return modelId.startsWith("claude-");
68
+ return modelId.startsWith("claude-") || modelId === "gemini-3.7-flash";
69
69
  }
70
70
 
71
71
  function getGeminiMajorVersion(modelId: string): number | undefined {
@@ -177,7 +177,7 @@ export function convertMessages<T extends GoogleApiType>(model: Model<T>, contex
177
177
  ...(requiresToolCallId(model.id) ? { id: block.id } : {}),
178
178
  },
179
179
  };
180
- if (model.provider === "google-vertex" && part?.functionCall?.id) {
180
+ if (model.provider === "google-vertex" && model.id !== "gemini-3.7-flash" && part?.functionCall?.id) {
181
181
  delete part.functionCall.id; // Vertex AI does not support 'id' in functionCall
182
182
  }
183
183
  if (effectiveSignature) {
@@ -228,7 +228,11 @@ export function convertMessages<T extends GoogleApiType>(model: Model<T>, contex
228
228
  },
229
229
  };
230
230
 
231
- if (model.provider === "google-vertex" && functionResponsePart.functionResponse?.id) {
231
+ if (
232
+ model.provider === "google-vertex" &&
233
+ model.id !== "gemini-3.7-flash" &&
234
+ functionResponsePart.functionResponse?.id
235
+ ) {
232
236
  delete functionResponsePart.functionResponse.id; // Vertex AI does not support 'id' in functionResponse
233
237
  }
234
238
 
@@ -108,7 +108,7 @@ export const streamGoogleVertex: StreamFunction<"google-vertex"> = (
108
108
  const project = apiKey ? undefined : await resolveGoogleVertexProject(options);
109
109
  const location = apiKey ? undefined : resolveGoogleVertexLocation(options);
110
110
  const client = apiKey ? createClientWithApiKey(model, apiKey) : createClient(model, project!, location!);
111
- const params = buildParams(model, context, options);
111
+ const params = buildGoogleVertexParams(model, context, options);
112
112
  options?.onPayload?.(params);
113
113
  rawRequestDump = {
114
114
  provider: model.provider,
@@ -467,33 +467,34 @@ export function googleVertexRequestUrl(modelId: string, project: string, locatio
467
467
  return `https://${host}/${API_VERSION}/projects/${project}/locations/${location}/publishers/google/models/${modelId}:streamGenerateContent`;
468
468
  }
469
469
 
470
- function buildParams(
470
+ export function buildGoogleVertexParams(
471
471
  model: Model<"google-vertex">,
472
472
  context: Context,
473
473
  options: GoogleVertexOptions = {},
474
474
  ): GenerateContentParameters {
475
475
  const contents = convertMessages(model, context);
476
+ const isGemini37Flash = model.id === "gemini-3.7-flash";
476
477
 
477
478
  const generationConfig: GoogleVertexSamplingConfig = {};
478
- if (options.temperature !== undefined) {
479
+ if (!isGemini37Flash && options.temperature !== undefined) {
479
480
  generationConfig.temperature = options.temperature;
480
481
  }
481
482
  if (options.maxTokens !== undefined) {
482
483
  generationConfig.maxOutputTokens = options.maxTokens;
483
484
  }
484
- if (options.topP !== undefined) {
485
+ if (!isGemini37Flash && options.topP !== undefined) {
485
486
  generationConfig.topP = options.topP;
486
487
  }
487
- if (options.topK !== undefined) {
488
+ if (!isGemini37Flash && options.topK !== undefined) {
488
489
  generationConfig.topK = options.topK;
489
490
  }
490
- if (options.minP !== undefined) {
491
+ if (!isGemini37Flash && options.minP !== undefined) {
491
492
  generationConfig.minP = options.minP;
492
493
  }
493
- if (options.presencePenalty !== undefined) {
494
+ if (!isGemini37Flash && options.presencePenalty !== undefined) {
494
495
  generationConfig.presencePenalty = options.presencePenalty;
495
496
  }
496
- if (options.repetitionPenalty !== undefined) {
497
+ if (!isGemini37Flash && options.repetitionPenalty !== undefined) {
497
498
  generationConfig.repetitionPenalty = options.repetitionPenalty;
498
499
  }
499
500
 
@@ -513,11 +514,13 @@ function buildParams(
513
514
  config.toolConfig = undefined;
514
515
  }
515
516
 
516
- if (options.thinking?.enabled && model.reasoning) {
517
+ if (model.reasoning && (options.thinking?.enabled || isGemini37Flash)) {
517
518
  const cfg: ThinkingConfig = { includeThoughts: true };
518
- if (options.thinking.level !== undefined) {
519
+ if (options.thinking?.level !== undefined) {
519
520
  cfg.thinkingLevel = THINKING_LEVEL_MAP[options.thinking.level];
520
- } else if (options.thinking.budgetTokens !== undefined) {
521
+ } else if (isGemini37Flash) {
522
+ cfg.thinkingLevel = ThinkingLevel.HIGH;
523
+ } else if (options.thinking?.budgetTokens !== undefined) {
521
524
  cfg.thinkingBudget = options.thinking.budgetTokens;
522
525
  }
523
526
  config.thinkingConfig = cfg;
package/src/types.ts CHANGED
@@ -83,6 +83,10 @@ export interface ThinkingConfig {
83
83
  minLevel: Effort;
84
84
  /** Most intensive supported user-facing effort level. */
85
85
  maxLevel: Effort;
86
+ /** Model-specific effort used when no explicit or saved effort is selected. */
87
+ defaultLevel?: Effort;
88
+ /** Whether callers may explicitly disable thinking. Defaults to true. */
89
+ canDisable?: boolean;
86
90
  /** Provider-specific transport used to encode the selected effort. */
87
91
  mode: ThinkingControlMode;
88
92
  }