mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-22 19:14:33 -07:00
feat(telemetry): Add telemetry for web_fetch fallback attempts (#10749)
This commit is contained in:
@@ -11,12 +11,21 @@ import { ApprovalMode } from '../config/config.js';
|
||||
import { ToolConfirmationOutcome } from './tools.js';
|
||||
import { ToolErrorType } from './tool-error.js';
|
||||
import * as fetchUtils from '../utils/fetch.js';
|
||||
import {
|
||||
logWebFetchFallbackAttempt,
|
||||
WebFetchFallbackAttemptEvent,
|
||||
} from '../telemetry/index.js';
|
||||
|
||||
const mockGenerateContent = vi.fn();
|
||||
const mockGetGeminiClient = vi.fn(() => ({
|
||||
generateContent: mockGenerateContent,
|
||||
}));
|
||||
|
||||
vi.mock('../telemetry/index.js', () => ({
|
||||
logWebFetchFallbackAttempt: vi.fn(),
|
||||
WebFetchFallbackAttemptEvent: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../utils/fetch.js', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof fetchUtils>();
|
||||
return {
|
||||
@@ -70,6 +79,59 @@ describe('WebFetchTool', () => {
|
||||
const result = await invocation.execute(new AbortController().signal);
|
||||
expect(result.error?.type).toBe(ToolErrorType.WEB_FETCH_PROCESSING_ERROR);
|
||||
});
|
||||
|
||||
it('should log telemetry when falling back due to private IP', async () => {
|
||||
vi.spyOn(fetchUtils, 'isPrivateIp').mockReturnValue(true);
|
||||
// Mock fetchWithTimeout to succeed so fallback proceeds
|
||||
vi.spyOn(fetchUtils, 'fetchWithTimeout').mockResolvedValue({
|
||||
ok: true,
|
||||
text: () => Promise.resolve('some content'),
|
||||
} as Response);
|
||||
mockGenerateContent.mockResolvedValue({
|
||||
candidates: [{ content: { parts: [{ text: 'fallback response' }] } }],
|
||||
});
|
||||
|
||||
const tool = new WebFetchTool(mockConfig);
|
||||
const params = { prompt: 'fetch https://private.ip' };
|
||||
const invocation = tool.build(params);
|
||||
await invocation.execute(new AbortController().signal);
|
||||
|
||||
expect(logWebFetchFallbackAttempt).toHaveBeenCalledWith(
|
||||
mockConfig,
|
||||
expect.any(WebFetchFallbackAttemptEvent),
|
||||
);
|
||||
expect(WebFetchFallbackAttemptEvent).toHaveBeenCalledWith('private_ip');
|
||||
});
|
||||
|
||||
it('should log telemetry when falling back due to primary fetch failure', async () => {
|
||||
vi.spyOn(fetchUtils, 'isPrivateIp').mockReturnValue(false);
|
||||
// Mock primary fetch to return empty response, triggering fallback
|
||||
mockGenerateContent.mockResolvedValueOnce({
|
||||
candidates: [],
|
||||
});
|
||||
// Mock fetchWithTimeout to succeed so fallback proceeds
|
||||
vi.spyOn(fetchUtils, 'fetchWithTimeout').mockResolvedValue({
|
||||
ok: true,
|
||||
text: () => Promise.resolve('some content'),
|
||||
} as Response);
|
||||
// Mock fallback LLM call
|
||||
mockGenerateContent.mockResolvedValueOnce({
|
||||
candidates: [{ content: { parts: [{ text: 'fallback response' }] } }],
|
||||
});
|
||||
|
||||
const tool = new WebFetchTool(mockConfig);
|
||||
const params = { prompt: 'fetch https://public.ip' };
|
||||
const invocation = tool.build(params);
|
||||
await invocation.execute(new AbortController().signal);
|
||||
|
||||
expect(logWebFetchFallbackAttempt).toHaveBeenCalledWith(
|
||||
mockConfig,
|
||||
expect.any(WebFetchFallbackAttemptEvent),
|
||||
);
|
||||
expect(WebFetchFallbackAttemptEvent).toHaveBeenCalledWith(
|
||||
'primary_failed',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldConfirmExecute', () => {
|
||||
|
||||
@@ -23,6 +23,10 @@ import { getResponseText } from '../utils/partUtils.js';
|
||||
import { fetchWithTimeout, isPrivateIp } from '../utils/fetch.js';
|
||||
import { convert } from 'html-to-text';
|
||||
import { ProxyAgent, setGlobalDispatcher } from 'undici';
|
||||
import {
|
||||
logWebFetchFallbackAttempt,
|
||||
WebFetchFallbackAttemptEvent,
|
||||
} from '../telemetry/index.js';
|
||||
|
||||
const URL_FETCH_TIMEOUT_MS = 10000;
|
||||
const MAX_CONTENT_LENGTH = 100000;
|
||||
@@ -184,6 +188,10 @@ ${textContent}
|
||||
const isPrivate = isPrivateIp(url);
|
||||
|
||||
if (isPrivate) {
|
||||
logWebFetchFallbackAttempt(
|
||||
this.config,
|
||||
new WebFetchFallbackAttemptEvent('private_ip'),
|
||||
);
|
||||
return this.executeFallback(signal);
|
||||
}
|
||||
|
||||
@@ -243,6 +251,10 @@ ${textContent}
|
||||
}
|
||||
|
||||
if (processingError) {
|
||||
logWebFetchFallbackAttempt(
|
||||
this.config,
|
||||
new WebFetchFallbackAttemptEvent('primary_failed'),
|
||||
);
|
||||
return this.executeFallback(signal);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user