@@ -22,11 +22,13 @@ import {
2222 FunctionResponse ,
2323 GenerateContentRequest ,
2424 GenerateContentResult ,
25+ GenerateContentStreamResult ,
26+ EnhancedGenerateContentResponse ,
2527 SingleRequestOptions ,
2628 Tool ,
2729} from '../types' ;
2830import { ApiSettings } from '../types/internal' ;
29- import { generateContent } from './generate-content' ;
31+ import { generateContent , generateContentStream } from './generate-content' ;
3032
3133const DEFAULT_MAX_SEQUENTIAL_FUNCTION_CALLS = 10 ;
3234
@@ -35,6 +37,11 @@ export interface AutomaticFunctionCallingResult {
3537 addedContents : Content [ ] ;
3638}
3739
40+ export interface AutomaticFunctionCallingStreamResult {
41+ result : GenerateContentStreamResult ;
42+ addedContents : Content [ ] ;
43+ }
44+
3845export async function generateContentWithAutomaticFunctionCalling (
3946 apiSettings : ApiSettings ,
4047 model : string ,
@@ -80,8 +87,61 @@ export async function generateContentWithAutomaticFunctionCalling(
8087 return { result : currentResult , addedContents } ;
8188}
8289
83- function getModelResponseContent ( result : GenerateContentResult ) : Content | undefined {
84- const responseContent = result . response . candidates ?. [ 0 ] ?. content ;
90+ export async function generateContentStreamWithAutomaticFunctionCalling (
91+ apiSettings : ApiSettings ,
92+ model : string ,
93+ params : GenerateContentRequest ,
94+ result : GenerateContentStreamResult ,
95+ requestOptions ?: SingleRequestOptions ,
96+ ) : Promise < AutomaticFunctionCallingStreamResult > {
97+ if ( ! getFunctionDeclarationsWithReferences ( params . tools ) . length ) {
98+ return { result, addedContents : [ ] } ;
99+ }
100+
101+ let remainingFunctionCalls =
102+ requestOptions ?. maxSequentialFunctionCalls ?? DEFAULT_MAX_SEQUENTIAL_FUNCTION_CALLS ;
103+ let currentParams = params ;
104+ let currentResult = result ;
105+ const addedContents : Content [ ] = [ ] ;
106+
107+ while ( remainingFunctionCalls > 0 ) {
108+ const response = await currentResult . response ;
109+ const functionCalls = response . functionCalls ?.( ) ;
110+ if ( ! functionCalls ?. length ) {
111+ return { result : currentResult , addedContents } ;
112+ }
113+
114+ const functionResponses = await callFunctionReferences ( currentParams . tools , functionCalls ) ;
115+ if ( ! functionResponses ) {
116+ return { result : currentResult , addedContents } ;
117+ }
118+
119+ const responseContent = getModelResponseContent ( response ) ;
120+ if ( ! responseContent ) {
121+ return { result : currentResult , addedContents } ;
122+ }
123+
124+ remainingFunctionCalls -= 1 ;
125+ const functionResponseContent : Content = {
126+ role : 'function' ,
127+ parts : functionResponses . map ( functionResponse => ( { functionResponse } ) ) ,
128+ } ;
129+ addedContents . push ( responseContent , functionResponseContent ) ;
130+ currentParams = {
131+ ...currentParams ,
132+ contents : [ ...currentParams . contents , responseContent , functionResponseContent ] ,
133+ } ;
134+ currentResult = await generateContentStream ( apiSettings , model , currentParams , requestOptions ) ;
135+ }
136+
137+ return { result : currentResult , addedContents } ;
138+ }
139+
140+ function getModelResponseContent (
141+ responseOrResult : GenerateContentResult | EnhancedGenerateContentResponse ,
142+ ) : Content | undefined {
143+ const response = 'response' in responseOrResult ? responseOrResult . response : responseOrResult ;
144+ const responseContent = response . candidates ?. [ 0 ] ?. content ;
85145 if ( ! responseContent ) {
86146 return undefined ;
87147 }
0 commit comments