From bf81a5b04a694420c94ff4137d3244807818d894 Mon Sep 17 00:00:00 2001 From: Daniel Weis Date: Fri, 8 May 2026 08:12:36 +0000 Subject: [PATCH 1/4] Fix function calling sequence error by allowing empty text in valid content --- packages/core/src/core/geminiChat.test.ts | 23 +++++++++++++++++++++++ packages/core/src/core/geminiChat.ts | 8 +++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/core/src/core/geminiChat.test.ts b/packages/core/src/core/geminiChat.test.ts index 1a54821f52a..27da7bbba0b 100644 --- a/packages/core/src/core/geminiChat.test.ts +++ b/packages/core/src/core/geminiChat.test.ts @@ -2796,4 +2796,27 @@ describe('GeminiChat', () => { ]); }); }); + + describe('getHistory with curated: true', () => { + it('should not drop model turns with function calls and empty text', () => { + const history: Content[] = [ + { role: 'user', parts: [{ text: 'Hello' }] }, + { + role: 'model', + parts: [{ functionCall: { name: 'test_tool', args: {} }, text: '' }], + }, + { + role: 'user', + parts: [{ functionResponse: { name: 'test_tool', response: {} } }], + }, + ]; + const chatWithHistory = new GeminiChat(mockConfig, '', [], history); + + const curatedHistory = chatWithHistory.getHistory(true); + + expect(curatedHistory.length).toBe(3); + expect(curatedHistory[1].role).toBe('model'); + expect(curatedHistory[1].parts![0].functionCall).toBeDefined(); + }); + }); }); diff --git a/packages/core/src/core/geminiChat.ts b/packages/core/src/core/geminiChat.ts index 398214a028f..4181e28d69d 100644 --- a/packages/core/src/core/geminiChat.ts +++ b/packages/core/src/core/geminiChat.ts @@ -146,7 +146,13 @@ function isValidContent(content: Content): boolean { if (part === undefined || Object.keys(part).length === 0) { return false; } - if (!part.thought && part.text !== undefined && part.text === '') { + if ( + !part.thought && + !part.functionCall && + !part.functionResponse && + part.text !== undefined && + part.text === '' + ) { return false; } } From 14c156b572821888c6bb8f95f4632b7787e17021 Mon Sep 17 00:00:00 2001 From: Daniel Weis Date: Fri, 8 May 2026 14:16:24 -0400 Subject: [PATCH 2/4] style: make isValidContent robust by checking inlineData and fileData --- packages/core/src/core/geminiChat.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/core/src/core/geminiChat.ts b/packages/core/src/core/geminiChat.ts index 4181e28d69d..daa6e9d11bc 100644 --- a/packages/core/src/core/geminiChat.ts +++ b/packages/core/src/core/geminiChat.ts @@ -150,6 +150,8 @@ function isValidContent(content: Content): boolean { !part.thought && !part.functionCall && !part.functionResponse && + !part.inlineData && + !part.fileData && part.text !== undefined && part.text === '' ) { From c379adbfa5fb27f82490819d82a0db0a55402a41 Mon Sep 17 00:00:00 2001 From: Daniel Weis Date: Fri, 8 May 2026 18:19:37 +0000 Subject: [PATCH 3/4] test: add tests for inlineData and fileData in isValidContent --- packages/core/src/core/geminiChat.test.ts | 34 +++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/core/src/core/geminiChat.test.ts b/packages/core/src/core/geminiChat.test.ts index 27da7bbba0b..b36acedc9bb 100644 --- a/packages/core/src/core/geminiChat.test.ts +++ b/packages/core/src/core/geminiChat.test.ts @@ -2818,5 +2818,39 @@ describe('GeminiChat', () => { expect(curatedHistory[1].role).toBe('model'); expect(curatedHistory[1].parts![0].functionCall).toBeDefined(); }); + + it('should not drop model turns with inlineData and empty text', () => { + const history: Content[] = [ + { role: 'user', parts: [{ text: 'Hello' }] }, + { + role: 'model', + parts: [{ inlineData: { mimeType: 'image/jpeg', data: 'base64...' }, text: '' }], + }, + ]; + const chatWithHistory = new GeminiChat(mockConfig, '', [], history); + + const curatedHistory = chatWithHistory.getHistory(true); + + expect(curatedHistory.length).toBe(2); + expect(curatedHistory[1].role).toBe('model'); + expect(curatedHistory[1].parts![0].inlineData).toBeDefined(); + }); + + it('should not drop model turns with fileData and empty text', () => { + const history: Content[] = [ + { role: 'user', parts: [{ text: 'Hello' }] }, + { + role: 'model', + parts: [{ fileData: { mimeType: 'image/jpeg', fileUri: 'https://...' }, text: '' }], + }, + ]; + const chatWithHistory = new GeminiChat(mockConfig, '', [], history); + + const curatedHistory = chatWithHistory.getHistory(true); + + expect(curatedHistory.length).toBe(2); + expect(curatedHistory[1].role).toBe('model'); + expect(curatedHistory[1].parts![0].fileData).toBeDefined(); + }); }); }); From dc659071f376154312759869d7f179e329b050d6 Mon Sep 17 00:00:00 2001 From: Daniel Weis Date: Fri, 8 May 2026 14:24:18 -0400 Subject: [PATCH 4/4] Run lint --- packages/core/src/core/geminiChat.test.ts | 26 ++++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/core/src/core/geminiChat.test.ts b/packages/core/src/core/geminiChat.test.ts index b36acedc9bb..f689d86a1ce 100644 --- a/packages/core/src/core/geminiChat.test.ts +++ b/packages/core/src/core/geminiChat.test.ts @@ -2811,9 +2811,9 @@ describe('GeminiChat', () => { }, ]; const chatWithHistory = new GeminiChat(mockConfig, '', [], history); - + const curatedHistory = chatWithHistory.getHistory(true); - + expect(curatedHistory.length).toBe(3); expect(curatedHistory[1].role).toBe('model'); expect(curatedHistory[1].parts![0].functionCall).toBeDefined(); @@ -2824,13 +2824,18 @@ describe('GeminiChat', () => { { role: 'user', parts: [{ text: 'Hello' }] }, { role: 'model', - parts: [{ inlineData: { mimeType: 'image/jpeg', data: 'base64...' }, text: '' }], + parts: [ + { + inlineData: { mimeType: 'image/jpeg', data: 'base64...' }, + text: '', + }, + ], }, ]; const chatWithHistory = new GeminiChat(mockConfig, '', [], history); - + const curatedHistory = chatWithHistory.getHistory(true); - + expect(curatedHistory.length).toBe(2); expect(curatedHistory[1].role).toBe('model'); expect(curatedHistory[1].parts![0].inlineData).toBeDefined(); @@ -2841,13 +2846,18 @@ describe('GeminiChat', () => { { role: 'user', parts: [{ text: 'Hello' }] }, { role: 'model', - parts: [{ fileData: { mimeType: 'image/jpeg', fileUri: 'https://...' }, text: '' }], + parts: [ + { + fileData: { mimeType: 'image/jpeg', fileUri: 'https://...' }, + text: '', + }, + ], }, ]; const chatWithHistory = new GeminiChat(mockConfig, '', [], history); - + const curatedHistory = chatWithHistory.getHistory(true); - + expect(curatedHistory.length).toBe(2); expect(curatedHistory[1].role).toBe('model'); expect(curatedHistory[1].parts![0].fileData).toBeDefined();