mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 21:03:05 -07:00
fix(patch): cherry-pick c31f053 to release/v0.23.0-preview.4-pr-16004 to patch version v0.23.0-preview.4 and create version 0.23.0-preview.5 (#16027)
This commit is contained in:
+17
-10
@@ -12,7 +12,7 @@ import prettierConfig from 'eslint-config-prettier';
|
||||
import importPlugin from 'eslint-plugin-import';
|
||||
import vitest from '@vitest/eslint-plugin';
|
||||
import globals from 'globals';
|
||||
import licenseHeader from 'eslint-plugin-license-header';
|
||||
import headers from 'eslint-plugin-headers';
|
||||
import path from 'node:path';
|
||||
import url from 'node:url';
|
||||
|
||||
@@ -209,19 +209,26 @@ export default tseslint.config(
|
||||
{
|
||||
files: ['./**/*.{tsx,ts,js}'],
|
||||
plugins: {
|
||||
'license-header': licenseHeader,
|
||||
headers,
|
||||
import: importPlugin,
|
||||
},
|
||||
rules: {
|
||||
'license-header/header': [
|
||||
'headers/header-format': [
|
||||
'error',
|
||||
[
|
||||
'/**',
|
||||
' * @license',
|
||||
' * Copyright 2025 Google LLC',
|
||||
' * SPDX-License-Identifier: Apache-2.0',
|
||||
' */',
|
||||
],
|
||||
{
|
||||
source: 'string',
|
||||
content: [
|
||||
'@license',
|
||||
'Copyright (year) Google LLC',
|
||||
'SPDX-License-Identifier: Apache-2.0',
|
||||
].join('\n'),
|
||||
patterns: {
|
||||
year: {
|
||||
pattern: '202[5-6]',
|
||||
defaultValue: '2026',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
'import/enforce-node-protocol-usage': ['error', 'always'],
|
||||
},
|
||||
|
||||
Generated
+14
-21
@@ -36,8 +36,8 @@
|
||||
"esbuild-plugin-wasm": "^1.1.0",
|
||||
"eslint": "^9.24.0",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
"eslint-plugin-headers": "^1.3.3",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-license-header": "^0.8.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"glob": "^12.0.0",
|
||||
@@ -8865,6 +8865,19 @@
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-headers": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-headers/-/eslint-plugin-headers-1.3.3.tgz",
|
||||
"integrity": "sha512-VzZY4+cGRoR5HpALLARH+ibIjB6a2w12/cFEayORHXMRHMzDnweSjpmvxyzX3rsSIVCg01zmvepB7Tnmaj4kGQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >= 18.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=7"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import": {
|
||||
"version": "2.32.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
|
||||
@@ -8919,16 +8932,6 @@
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-license-header": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-license-header/-/eslint-plugin-license-header-0.8.0.tgz",
|
||||
"integrity": "sha512-khTCz6G3JdoQfwrtY4XKl98KW4PpnWUKuFx8v+twIRhJADEyYglMDC0td8It75C1MZ88gcvMusWuUlJsos7gYg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"requireindex": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react": {
|
||||
"version": "7.37.5",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
|
||||
@@ -15069,16 +15072,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/requireindex": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz",
|
||||
"integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.5"
|
||||
}
|
||||
},
|
||||
"node_modules/requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
|
||||
+1
-1
@@ -94,8 +94,8 @@
|
||||
"esbuild-plugin-wasm": "^1.1.0",
|
||||
"eslint": "^9.24.0",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
"eslint-plugin-headers": "^1.3.3",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-license-header": "^0.8.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"glob": "^12.0.0",
|
||||
|
||||
@@ -57,6 +57,7 @@ import {
|
||||
applyModelSelection,
|
||||
createAvailabilityContextProvider,
|
||||
} from '../availability/policyHelpers.js';
|
||||
import { resolveModel } from '../config/models.js';
|
||||
import type { RetryAvailabilityContext } from '../utils/retry.js';
|
||||
|
||||
const MAX_TURNS = 100;
|
||||
@@ -397,7 +398,7 @@ export class GeminiClient {
|
||||
|
||||
// Availability logic: The configured model is the source of truth,
|
||||
// including any permanent fallbacks (config.setModel) or manual overrides.
|
||||
return this.config.getActiveModel();
|
||||
return resolveModel(this.config.getActiveModel());
|
||||
}
|
||||
|
||||
async *sendMessageStream(
|
||||
|
||||
@@ -123,8 +123,26 @@ describe('calculateRequestTokenCount', () => {
|
||||
|
||||
// Should fallback to estimation:
|
||||
// 'Hello': 5 chars * 0.25 = 1.25
|
||||
// inlineData: JSON.stringify length / 4
|
||||
expect(count).toBeGreaterThan(0);
|
||||
// inlineData: 3000
|
||||
// Total: 3001.25 -> 3001
|
||||
expect(count).toBe(3001);
|
||||
expect(mockContentGenerator.countTokens).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use fixed estimate for images in fallback', async () => {
|
||||
vi.mocked(mockContentGenerator.countTokens).mockRejectedValue(
|
||||
new Error('API error'),
|
||||
);
|
||||
const request = [
|
||||
{ inlineData: { mimeType: 'image/png', data: 'large_data' } },
|
||||
];
|
||||
|
||||
const count = await calculateRequestTokenCount(
|
||||
request,
|
||||
mockContentGenerator,
|
||||
model,
|
||||
);
|
||||
|
||||
expect(count).toBe(3000);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import type { PartListUnion, Part } from '@google/genai';
|
||||
import type { ContentGenerator } from '../core/contentGenerator.js';
|
||||
import { debugLogger } from './debugLogger.js';
|
||||
|
||||
// Token estimation constants
|
||||
// ASCII characters (0-127) are roughly 4 chars per token
|
||||
@@ -13,6 +14,8 @@ const ASCII_TOKENS_PER_CHAR = 0.25;
|
||||
// Non-ASCII characters (including CJK) are often 1-2 tokens per char.
|
||||
// We use 1.3 as a conservative estimate to avoid underestimation.
|
||||
const NON_ASCII_TOKENS_PER_CHAR = 1.3;
|
||||
// Fixed token estimate for images
|
||||
const IMAGE_TOKEN_ESTIMATE = 3000;
|
||||
|
||||
/**
|
||||
* Estimates token count for parts synchronously using a heuristic.
|
||||
@@ -31,12 +34,23 @@ export function estimateTokenCountSync(parts: Part[]): number {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// For non-text parts (functionCall, functionResponse, executableCode, etc.),
|
||||
// For images, we use a fixed safe estimate (3,000 tokens) covering
|
||||
// up to 4K resolution on Gemini 3.
|
||||
// See: https://ai.google.dev/gemini-api/docs/vision#token_counting
|
||||
const inlineData = 'inlineData' in part ? part.inlineData : undefined;
|
||||
const fileData = 'fileData' in part ? part.fileData : undefined;
|
||||
const mimeType = inlineData?.mimeType || fileData?.mimeType;
|
||||
|
||||
if (mimeType?.startsWith('image/')) {
|
||||
totalTokens += IMAGE_TOKEN_ESTIMATE;
|
||||
} else {
|
||||
// For other non-text parts (functionCall, functionResponse, etc.),
|
||||
// we fallback to the JSON string length heuristic.
|
||||
// Note: This is an approximation.
|
||||
totalTokens += JSON.stringify(part).length / 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Math.floor(totalTokens);
|
||||
}
|
||||
|
||||
@@ -69,8 +83,9 @@ export async function calculateRequestTokenCount(
|
||||
contents: [{ role: 'user', parts }],
|
||||
});
|
||||
return response.totalTokens ?? 0;
|
||||
} catch {
|
||||
} catch (error) {
|
||||
// Fallback to local estimation if the API call fails
|
||||
debugLogger.debug('countTokens API failed:', error);
|
||||
return estimateTokenCountSync(parts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ try {
|
||||
|
||||
const fileContent = `/**
|
||||
* @license
|
||||
* Copyright ${new Date().getFullYear()} Google LLC
|
||||
* Copyright ${new Date().getUTCFullYear()} Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user