Skip to content

Commit 383bd00

Browse files
committed
Added parallel auto function calling test case
1 parent 20f957a commit 383bd00

File tree

1 file changed

+137
-1
lines changed

1 file changed

+137
-1
lines changed

packages/firebase_ai/firebase_ai/example/lib/pages/function_calling_page.dart

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,16 @@ class Location {
4141
class _FunctionCallingPageState extends State<FunctionCallingPage> {
4242
late GenerativeModel _functionCallModel;
4343
late GenerativeModel _autoFunctionCallModel;
44+
late GenerativeModel _parallelAutoFunctionCallModel;
4445
late GenerativeModel _codeExecutionModel;
4546
late final AutoFunctionDeclaration _autoFetchWeatherTool;
4647
final List<MessageData> _messages = <MessageData>[];
4748
bool _loading = false;
4849
bool _enableThinking = false;
4950

51+
late final AutoFunctionDeclaration _autoFindRestaurantsTool;
52+
late final AutoFunctionDeclaration _autoGetRestaurantMenuTool;
53+
5054
@override
5155
void initState() {
5256
super.initState();
@@ -74,9 +78,72 @@ class _FunctionCallingPageState extends State<FunctionCallingPage> {
7478
},
7579
callable: _fetchWeatherCallable,
7680
);
81+
_autoFindRestaurantsTool = AutoFunctionDeclaration(
82+
name: 'findRestaurants',
83+
description: 'Find restaurants of a certain cuisine in a given location.',
84+
parameters: {
85+
'cuisine': Schema.string(
86+
description: 'The cuisine of the restaurant.',
87+
),
88+
'location': Schema.string(
89+
description:
90+
'The location to search for restaurants. e.g. San Francisco, CA',
91+
),
92+
},
93+
callable: (args) async {
94+
final cuisine = args['cuisine']! as String;
95+
final location = args['location']! as String;
96+
return findRestaurants(cuisine, location);
97+
},
98+
);
99+
_autoGetRestaurantMenuTool = AutoFunctionDeclaration(
100+
name: 'getRestaurantMenu',
101+
description: 'Get the menu for a specific restaurant.',
102+
parameters: {
103+
'restaurantName': Schema.string(
104+
description: 'The name of the restaurant.',
105+
),
106+
},
107+
callable: (args) async {
108+
final restaurantName = args['restaurantName']! as String;
109+
return getRestaurantMenu(restaurantName);
110+
},
111+
);
77112
_initializeModel();
78113
}
79114

115+
Future<Map<String, Object?>> findRestaurants(
116+
String cuisine,
117+
String location,
118+
) async {
119+
// This is a mock response.
120+
return {
121+
'restaurants': [
122+
{
123+
'name': 'The Golden Spoon',
124+
'cuisine': 'Vegetarian',
125+
'location': 'San Francisco, CA',
126+
},
127+
{
128+
'name': 'Green Leaf Bistro',
129+
'cuisine': 'Vegetarian',
130+
'location': 'San Francisco, CA',
131+
},
132+
],
133+
};
134+
}
135+
136+
Future<Map<String, Object?>> getRestaurantMenu(String restaurantName) async {
137+
// This is a mock response.
138+
return {
139+
'menu': [
140+
{'name': 'Lentil Soup', 'price': '8.99'},
141+
{'name': 'Garden Salad', 'price': '10.99'},
142+
{'name': 'Mushroom Risotto', 'price': '15.99'},
143+
],
144+
};
145+
}
146+
80147
Future<Map<String, Object?>> _fetchWeatherCallable(
81148
Map<String, Object?> args,
82149
) async {
@@ -112,6 +179,15 @@ class _FunctionCallingPageState extends State<FunctionCallingPage> {
112179
Tool.functionDeclarations([_autoFetchWeatherTool]),
113180
],
114181
);
182+
_parallelAutoFunctionCallModel = vertexAI.generativeModel(
183+
model: 'gemini-2.5-flash',
184+
generationConfig: generationConfig,
185+
tools: [
186+
Tool.functionDeclarations(
187+
[_autoFindRestaurantsTool, _autoGetRestaurantMenuTool],
188+
),
189+
],
190+
);
115191
_codeExecutionModel = vertexAI.generativeModel(
116192
model: 'gemini-2.5-flash',
117193
generationConfig: generationConfig,
@@ -135,6 +211,15 @@ class _FunctionCallingPageState extends State<FunctionCallingPage> {
135211
Tool.functionDeclarations([_autoFetchWeatherTool]),
136212
],
137213
);
214+
_parallelAutoFunctionCallModel = googleAI.generativeModel(
215+
model: 'gemini-2.5-flash',
216+
generationConfig: generationConfig,
217+
tools: [
218+
Tool.functionDeclarations(
219+
[_autoFindRestaurantsTool, _autoGetRestaurantMenuTool],
220+
),
221+
],
222+
);
138223
_codeExecutionModel = googleAI.generativeModel(
139224
model: 'gemini-2.5-flash',
140225
generationConfig: generationConfig,
@@ -266,6 +351,17 @@ class _FunctionCallingPageState extends State<FunctionCallingPage> {
266351
child: const Text('Auto Function Calling'),
267352
),
268353
),
354+
const SizedBox(width: 8),
355+
Expanded(
356+
child: ElevatedButton(
357+
onPressed: !_loading
358+
? () async {
359+
await _testParallelAutoFunctionCalling();
360+
}
361+
: null,
362+
child: const Text('Parallel Auto FC'),
363+
),
364+
),
269365
],
270366
),
271367
const SizedBox(height: 8),
@@ -293,7 +389,7 @@ class _FunctionCallingPageState extends State<FunctionCallingPage> {
293389
),
294390
),
295391
],
296-
),
392+
)
297393
],
298394
),
299395
),
@@ -303,6 +399,46 @@ class _FunctionCallingPageState extends State<FunctionCallingPage> {
303399
);
304400
}
305401

402+
Future<void> _testParallelAutoFunctionCalling() async {
403+
setState(() {
404+
_loading = true;
405+
_messages.clear();
406+
});
407+
try {
408+
final autoFunctionCallChat = _parallelAutoFunctionCallModel.startChat();
409+
const prompt =
410+
'Find me a good vegetarian restaurant in San Francisco and get its menu.';
411+
412+
_messages.add(MessageData(text: prompt, fromUser: true));
413+
setState(() {});
414+
415+
// Send the message to the generative model.
416+
final response = await autoFunctionCallChat.sendMessage(
417+
Content.text(prompt),
418+
);
419+
420+
final thought = response.thoughtSummary;
421+
if (thought != null) {
422+
_messages
423+
.add(MessageData(text: thought, fromUser: false, isThought: true));
424+
}
425+
426+
// The SDK should have handled the function call automatically.
427+
// The final response should contain the text from the model.
428+
if (response.text case final text?) {
429+
_messages.add(MessageData(text: text));
430+
} else {
431+
_messages.add(MessageData(text: 'No text response from model.'));
432+
}
433+
} catch (e) {
434+
_showError(e.toString());
435+
} finally {
436+
setState(() {
437+
_loading = false;
438+
});
439+
}
440+
}
441+
306442
Future<void> _testStreamFunctionCalling() async {
307443
setState(() {
308444
_loading = true;

0 commit comments

Comments
 (0)