From ac47e04cf9d1cc55b867c00038784f16c6f3d717 Mon Sep 17 00:00:00 2001 From: lemon07r Date: Mon, 22 Dec 2025 19:36:01 -0500 Subject: [PATCH] fix: add missing 'index' to Gemini streaming tool calls and improve tests --- jest.config.js | 5 +- src/converters/strategies/GeminiConverter.js | 1 + tests/gemini-converter.test.js | 69 ++++++++++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 tests/gemini-converter.test.js diff --git a/jest.config.js b/jest.config.js index b61803a..c5f4a2a 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,7 @@ export default { testEnvironment: 'node', transform: { - '^.+\\.js$': 'babel-jest', + '^.+\\.(js|mjs)$': 'babel-jest', }, transformIgnorePatterns: [ '/node_modules/(?!(uuid)/)', // uuid is an ESM module that needs to be transformed @@ -15,8 +15,7 @@ export default { '^(\\.{1,2}/.*)\\.js$': '$1' }, testMatch: [ - '**/tests/api-server.test.js', - '**/tests/api-integration.test.js' + '**/tests/**/*.test.js' ], collectCoverageFrom: [ 'src/**/*.js', diff --git a/src/converters/strategies/GeminiConverter.js b/src/converters/strategies/GeminiConverter.js index 4e092a9..0ae394a 100644 --- a/src/converters/strategies/GeminiConverter.js +++ b/src/converters/strategies/GeminiConverter.js @@ -209,6 +209,7 @@ export class GeminiConverter extends BaseConverter { } if (part.functionCall) { toolCalls.push({ + index: toolCalls.length, id: part.functionCall.id || `call_${uuidv4()}`, type: 'function', function: { diff --git a/tests/gemini-converter.test.js b/tests/gemini-converter.test.js new file mode 100644 index 0000000..466b562 --- /dev/null +++ b/tests/gemini-converter.test.js @@ -0,0 +1,69 @@ + +import GeminiConverter from '../src/converters/strategies/GeminiConverter.js'; +import { jest } from '@jest/globals'; + +describe('GeminiConverter', () => { + let converter; + + beforeEach(() => { + converter = new GeminiConverter(); + }); + + test('toOpenAIStreamChunk adds index to tool_calls', () => { + const geminiChunk = { + candidates: [{ + content: { + parts: [{ + functionCall: { + name: 'test_tool', + args: { param: 'value' } + } + }] + } + }] + }; + + const result = converter.toOpenAIStreamChunk(geminiChunk, 'gemini-pro'); + + expect(result).not.toBeNull(); + expect(result.choices[0].delta).toHaveProperty('tool_calls'); + expect(result.choices[0].delta.tool_calls).toHaveLength(1); + expect(result.choices[0].delta.tool_calls[0]).toHaveProperty('index'); + expect(result.choices[0].delta.tool_calls[0].index).toBe(0); + expect(result.choices[0].delta.tool_calls[0].function.name).toBe('test_tool'); + }); + + test('toOpenAIStreamChunk handles multiple tool_calls with correct indices', () => { + const geminiChunk = { + candidates: [{ + content: { + parts: [ + { + functionCall: { + name: 'tool_one', + args: {} + } + }, + { + functionCall: { + name: 'tool_two', + args: {} + } + } + ] + } + }] + }; + + const result = converter.toOpenAIStreamChunk(geminiChunk, 'gemini-pro'); + + expect(result).not.toBeNull(); + expect(result.choices[0].delta.tool_calls).toHaveLength(2); + + expect(result.choices[0].delta.tool_calls[0].index).toBe(0); + expect(result.choices[0].delta.tool_calls[0].function.name).toBe('tool_one'); + + expect(result.choices[0].delta.tool_calls[1].index).toBe(1); + expect(result.choices[0].delta.tool_calls[1].function.name).toBe('tool_two'); + }); +});