mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-08-09 00:16:57 -07:00
fix(core): skip merged function-response turns when finding the active loop (#28565)
This commit is contained in:
@@ -2447,6 +2447,37 @@ describe('GeminiChat', () => {
|
||||
expect(newContents[5]?.parts?.[1]).not.toHaveProperty('thoughtSignature');
|
||||
});
|
||||
|
||||
it('should skip a user turn that has text alongside a functionResponse when locating the active loop', () => {
|
||||
const chat = new GeminiChat(mockConfig, '', [], []);
|
||||
// `coalesceConsecutiveRoles` can merge a function response turn with the
|
||||
// prompt that follows it, producing a user turn holding both.
|
||||
const history: Content[] = [
|
||||
{ role: 'user', parts: [{ text: 'First prompt' }] },
|
||||
{
|
||||
role: 'model',
|
||||
parts: [
|
||||
{ text: 'Working on it' },
|
||||
{ functionCall: { name: 'some_tool', args: {} } },
|
||||
],
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
parts: [
|
||||
{ functionResponse: { name: 'some_tool', response: {} } },
|
||||
{ text: 'Second prompt' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const newContents = chat.ensureActiveLoopHasThoughtSignatures(history);
|
||||
|
||||
// The merged turn must not be taken as the loop start, otherwise the
|
||||
// model turn before it is left unsigned while the API still validates it.
|
||||
expect(newContents[1]?.parts?.[1]?.thoughtSignature).toBe(
|
||||
SYNTHETIC_THOUGHT_SIGNATURE,
|
||||
);
|
||||
});
|
||||
|
||||
it('should not modify contents if there is no user text message', () => {
|
||||
const chat = new GeminiChat(mockConfig, '', [], []);
|
||||
const history: Content[] = [
|
||||
|
||||
@@ -1044,11 +1044,19 @@ export class GeminiChat {
|
||||
requestContents: readonly Content[],
|
||||
): readonly Content[] {
|
||||
// First, find the start of the active loop by finding the last user turn
|
||||
// with a text message, i.e. that is not a function response.
|
||||
// with a text message, i.e. that is not a function response. Testing for
|
||||
// text alone is not enough: `coalesceConsecutiveRoles` can merge a function
|
||||
// response turn with the prompt that follows it, and starting the loop at
|
||||
// such a turn starts it later than the API starts the turn, leaving earlier
|
||||
// function calls unsigned but still validated.
|
||||
let activeLoopStartIndex = -1;
|
||||
for (let i = requestContents.length - 1; i >= 0; i--) {
|
||||
const content = requestContents[i];
|
||||
if (content.role === 'user' && content.parts?.some((part) => part.text)) {
|
||||
if (
|
||||
content.role === 'user' &&
|
||||
content.parts?.some((part) => part.text) &&
|
||||
!content.parts?.some((part) => part.functionResponse)
|
||||
) {
|
||||
activeLoopStartIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user