@@ -660,12 +660,10 @@ export class RealtimeSession extends llm.RealtimeSession {
660660 for ( const f of this . resampleAudio ( frame ) ) {
661661 for ( const nf of this . bstream . write ( f . data . buffer as ArrayBuffer ) ) {
662662 const realtimeInput : types . LiveClientRealtimeInput = {
663- mediaChunks : [
664- {
665- mimeType : 'audio/pcm' ,
666- data : Buffer . from ( nf . data . buffer ) . toString ( 'base64' ) ,
667- } ,
668- ] ,
663+ audio : {
664+ mimeType : 'audio/pcm' ,
665+ data : Buffer . from ( nf . data . buffer ) . toString ( 'base64' ) ,
666+ } ,
669667 } ;
670668 this . sendClientEvent ( {
671669 type : 'realtime_input' ,
@@ -684,6 +682,13 @@ export class RealtimeSession extends llm.RealtimeSession {
684682 }
685683
686684 async generateReply ( instructions ?: string ) : Promise < llm . GenerationCreatedEvent > {
685+ if ( this . options . model === 'gemini-3.1-flash-live-preview' ) {
686+ this . #logger. warn (
687+ 'generateReply is not compatible with gemini-3.1-flash-live-preview and will be ignored.' ,
688+ ) ;
689+ throw new Error ( "generateReply is not compatible with 'gemini-3.1-flash-live-preview'" ) ;
690+ }
691+
687692 if ( this . pendingGenerationFut && ! this . pendingGenerationFut . done ) {
688693 this . #logger. warn (
689694 'generateReply called while another generation is pending, cancelling previous.' ,
@@ -992,13 +997,16 @@ export class RealtimeSession extends llm.RealtimeSession {
992997 }
993998 break ;
994999 case 'realtime_input' :
995- const { mediaChunks, activityStart, activityEnd, text } = msg . value ;
1000+ const { mediaChunks, audio , activityStart, activityEnd, text } = msg . value ;
9961001 if ( this . pendingToolCallIds . size > 0 ) break ;
9971002 if ( mediaChunks ) {
9981003 for ( const mediaChunk of mediaChunks ) {
9991004 await session . sendRealtimeInput ( { media : mediaChunk } ) ;
10001005 }
10011006 }
1007+ if ( audio ) {
1008+ await session . sendRealtimeInput ( { audio } ) ;
1009+ }
10021010 if ( text ) {
10031011 await session . sendRealtimeInput ( { text } ) ;
10041012 }
@@ -1152,6 +1160,16 @@ export class RealtimeSession extends llm.RealtimeSession {
11521160 ) ,
11531161 } ;
11541162 }
1163+ if ( obj . type === 'realtime_input' && obj . value ?. audio ) {
1164+ const ac = obj . value . audio as { mimeType ?: string ; data ?: string } ;
1165+ obj . value = {
1166+ ...obj . value ,
1167+ audio : {
1168+ ...ac ,
1169+ data : typeof ac . data === 'string' ? this . truncateString ( ac . data , maxLength ) : ac . data ,
1170+ } ,
1171+ } ;
1172+ }
11551173 return obj ;
11561174 }
11571175
@@ -1265,17 +1283,15 @@ export class RealtimeSession extends llm.RealtimeSession {
12651283 } ,
12661284 languageCode : opts . language ,
12671285 } ,
1268- tools : [
1269- {
1270- functionDeclarations : this . geminiDeclarations ,
1271- ...this . options . geminiTools ,
1272- } ,
1273- ] ,
1286+ tools :
1287+ this . geminiDeclarations . length > 0 || this . options . geminiTools
1288+ ? [ { functionDeclarations : this . geminiDeclarations , ...this . options . geminiTools } ]
1289+ : undefined ,
12741290 inputAudioTranscription : opts . inputAudioTranscription ,
12751291 outputAudioTranscription : opts . outputAudioTranscription ,
1276- sessionResumption : {
1277- handle : this . sessionResumptionHandle ,
1278- } ,
1292+ sessionResumption : this . sessionResumptionHandle
1293+ ? { handle : this . sessionResumptionHandle }
1294+ : { } ,
12791295 } ;
12801296
12811297 // Add generation fields at TOP LEVEL (NO generationConfig!)
@@ -1527,6 +1543,8 @@ export class RealtimeSession extends llm.RealtimeSession {
15271543 } ) ,
15281544 ) ;
15291545 }
1546+ // This closes message/text/audio/function streams so the consumer can continue.
1547+ this . markCurrentGenerationDone ( ) ;
15301548 }
15311549
15321550 private handleToolCallCancellation ( cancellation : types . LiveServerToolCallCancellation ) : void {
0 commit comments