@@ -399,7 +399,10 @@ function fromGeminiFunctionResponsePart(part: GeminiPart): Part {
399
399
}
400
400
401
401
// Converts vertex part to genkit part
402
- function fromGeminiPart ( part : GeminiPart ) : Part {
402
+ function fromGeminiPart ( part : GeminiPart , jsonMode : boolean ) : Part {
403
+ if ( jsonMode && part . text !== undefined ) {
404
+ return { data : JSON . parse ( part . text ) } ;
405
+ }
403
406
if ( part . text !== undefined ) return { text : part . text } ;
404
407
if ( part . functionCall ) return fromGeminiFunctionCallPart ( part ) ;
405
408
if ( part . functionResponse ) return fromGeminiFunctionResponsePart ( part ) ;
@@ -411,14 +414,15 @@ function fromGeminiPart(part: GeminiPart): Part {
411
414
}
412
415
413
416
export function fromGeminiCandidate (
414
- candidate : GenerateContentCandidate
417
+ candidate : GenerateContentCandidate ,
418
+ jsonMode : boolean
415
419
) : CandidateData {
416
420
const parts = candidate . content . parts || [ ] ;
417
421
const genkitCandidate : CandidateData = {
418
422
index : candidate . index || 0 , // reasonable default?
419
423
message : {
420
424
role : 'model' ,
421
- content : parts . map ( fromGeminiPart ) ,
425
+ content : parts . map ( ( p ) => fromGeminiPart ( p , jsonMode ) ) ,
422
426
} ,
423
427
finishReason : fromGeminiFinishReason ( candidate . finishReason ) ,
424
428
finishMessage : candidate . finishMessage ,
@@ -518,11 +522,18 @@ export function geminiModel(
518
522
}
519
523
}
520
524
525
+ const tools = request . tools ?. length
526
+ ? [ { functionDeclarations : request . tools ?. map ( toGeminiTool ) } ]
527
+ : [ ] ;
528
+
529
+ // Cannot use tools and function calling at the same time
530
+ const jsonMode =
531
+ ( request . output ?. format === 'json' || ! ! request . output ?. schema ) &&
532
+ tools . length === 0 ;
533
+
521
534
const chatRequest : StartChatParams = {
522
535
systemInstruction,
523
- tools : request . tools ?. length
524
- ? [ { functionDeclarations : request . tools ?. map ( toGeminiTool ) } ]
525
- : [ ] ,
536
+ tools,
526
537
history : messages
527
538
. slice ( 0 , - 1 )
528
539
. map ( ( message ) => toGeminiMessage ( message , model ) ) ,
@@ -532,6 +543,7 @@ export function geminiModel(
532
543
maxOutputTokens : request . config ?. maxOutputTokens ,
533
544
topK : request . config ?. topK ,
534
545
topP : request . config ?. topP ,
546
+ responseMimeType : jsonMode ? 'application/json' : undefined ,
535
547
stopSequences : request . config ?. stopSequences ,
536
548
} ,
537
549
safetySettings : request . config ?. safetySettings ,
@@ -566,7 +578,7 @@ export function geminiModel(
566
578
. sendMessageStream ( msg . parts ) ;
567
579
for await ( const item of result . stream ) {
568
580
( item as GenerateContentResponse ) . candidates ?. forEach ( ( candidate ) => {
569
- const c = fromGeminiCandidate ( candidate ) ;
581
+ const c = fromGeminiCandidate ( candidate , jsonMode ) ;
570
582
streamingCallback ( {
571
583
index : c . index ,
572
584
content : c . message . content ,
@@ -578,7 +590,9 @@ export function geminiModel(
578
590
throw new Error ( 'No valid candidates returned.' ) ;
579
591
}
580
592
return {
581
- candidates : response . candidates ?. map ( fromGeminiCandidate ) || [ ] ,
593
+ candidates :
594
+ response . candidates ?. map ( ( c ) => fromGeminiCandidate ( c , jsonMode ) ) ||
595
+ [ ] ,
582
596
custom : response ,
583
597
} ;
584
598
} else {
@@ -592,7 +606,9 @@ export function geminiModel(
592
606
throw new Error ( 'No valid candidates returned.' ) ;
593
607
}
594
608
const responseCandidates =
595
- result . response . candidates ?. map ( fromGeminiCandidate ) || [ ] ;
609
+ result . response . candidates ?. map ( ( c ) =>
610
+ fromGeminiCandidate ( c , jsonMode )
611
+ ) || [ ] ;
596
612
return {
597
613
candidates : responseCandidates ,
598
614
custom : result . response ,
0 commit comments