Skip to content

Commit 1ea6b7f

Browse files
authored
fix(js/plugins/google-genai): ignore empty parts in the response (#3482)
1 parent afa61f5 commit 1ea6b7f

File tree

2 files changed

+47
-5
lines changed

2 files changed

+47
-5
lines changed

js/plugins/google-genai/src/common/converters.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ function toGeminiPart(part: Part): GeminiPart {
195195
if (part.custom) {
196196
return toGeminiCustom(part);
197197
}
198-
throw new Error('Unsupported Part type' + JSON.stringify(part));
198+
throw new Error('Unsupported Part type ' + JSON.stringify(part));
199199
}
200200

201201
function toGeminiRole(
@@ -424,7 +424,7 @@ function fromGeminiPart(part: GeminiPart, ref: string): Part {
424424
if (part.executableCode) return fromExecutableCode(part);
425425
if (part.codeExecutionResult) return fromCodeExecutionResult(part);
426426

427-
throw new Error('Unsupported GeminiPart type');
427+
throw new Error('Unsupported GeminiPart type ' + JSON.stringify(part));
428428
}
429429

430430
export function fromGeminiCandidate(candidate: GeminiCandidate): CandidateData {
@@ -433,9 +433,10 @@ export function fromGeminiCandidate(candidate: GeminiCandidate): CandidateData {
433433
index: candidate.index || 0,
434434
message: {
435435
role: 'model',
436-
content: parts.map((part, index) =>
437-
fromGeminiPart(part, index.toString())
438-
),
436+
content: parts
437+
// the model sometimes returns empty parts, ignore those.
438+
.filter((p) => Object.keys(p).length > 0)
439+
.map((part, index) => fromGeminiPart(part, index.toString())),
439440
},
440441
finishReason: fromGeminiFinishReason(candidate.finishReason),
441442
finishMessage: candidate.finishMessage,

js/plugins/google-genai/tests/common/converters_test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,47 @@ describe('fromGeminiCandidate', () => {
679679
custom: { citationMetadata: undefined, safetyRatings: undefined },
680680
},
681681
},
682+
{
683+
should: 'should ignore empty parts',
684+
geminiCandidate: {
685+
index: 0,
686+
content: {
687+
role: 'model',
688+
parts: [
689+
{}, // this one should be skipped
690+
{
691+
text: 'Why did the dog go to the bank?\n\nTo get his bones cashed!',
692+
},
693+
],
694+
},
695+
finishReason: 'STOP',
696+
safetyRatings: [
697+
{ category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE' },
698+
],
699+
},
700+
expectedOutput: {
701+
index: 0,
702+
message: {
703+
role: 'model',
704+
content: [
705+
{
706+
text: 'Why did the dog go to the bank?\n\nTo get his bones cashed!',
707+
},
708+
],
709+
},
710+
finishReason: 'stop',
711+
finishMessage: undefined,
712+
custom: {
713+
citationMetadata: undefined,
714+
safetyRatings: [
715+
{
716+
category: 'HARM_CATEGORY_HATE_SPEECH',
717+
probability: 'NEGLIGIBLE',
718+
},
719+
],
720+
},
721+
},
722+
},
682723
];
683724
for (const test of testCases) {
684725
it(test.should, () => {

0 commit comments

Comments
 (0)