fix(core): Prepend user message to loop detection history if it starts with a function call (#11860)

This commit is contained in:
Sandy Tao
2025-10-24 21:22:26 -07:00
committed by GitHub
parent 73570f1c86
commit a2d7f82b49
2 changed files with 37 additions and 0 deletions

View File

@@ -5,6 +5,7 @@
*/
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import type { Content } from '@google/genai';
import type { Config } from '../config/config.js';
import type { GeminiClient } from '../core/client.js';
import type { BaseLlmClient } from '../core/baseLlmClient.js';
@@ -754,4 +755,34 @@ describe('LoopDetectionService LLM Checks', () => {
expect(result).toBe(false);
expect(mockBaseLlmClient.generateJson).not.toHaveBeenCalled();
});
it('should prepend user message if history starts with a function call', async () => {
const functionCallHistory: Content[] = [
{
role: 'model',
parts: [{ functionCall: { name: 'someTool', args: {} } }],
},
{
role: 'model',
parts: [{ text: 'Some follow up text' }],
},
];
vi.mocked(mockGeminiClient.getHistory).mockReturnValue(functionCallHistory);
mockBaseLlmClient.generateJson = vi
.fn()
.mockResolvedValue({ confidence: 0.1 });
await advanceTurns(30);
expect(mockBaseLlmClient.generateJson).toHaveBeenCalledTimes(1);
const calledArg = vi.mocked(mockBaseLlmClient.generateJson).mock
.calls[0][0];
expect(calledArg.contents[0]).toEqual({
role: 'user',
parts: [{ text: 'Recent conversation history:' }],
});
// Verify the original history follows
expect(calledArg.contents[1]).toEqual(functionCallHistory[0]);
});
});

View File

@@ -404,6 +404,12 @@ export class LoopDetectionService {
...trimmedHistory,
{ role: 'user', parts: [{ text: taskPrompt }] },
];
if (contents.length > 0 && isFunctionCall(contents[0])) {
contents.unshift({
role: 'user',
parts: [{ text: 'Recent conversation history:' }],
});
}
const schema: Record<string, unknown> = {
type: 'object',
properties: {