Feat/ai samples function calling - #1075
Conversation
Wiz Scan Summary
To detect these findings earlier in the dev lifecycle, try the Wiz Code extension for VS Code, JetBrains, or Visual Studio. |
There was a problem hiding this comment.
Code Review
This pull request introduces implementation examples for Firebase AI features, specifically adding function-calling capabilities and structured output generation (JSON and Enum schemas) with corresponding UI views. The review feedback highlights two critical issues in the function-calling service: first, the tools parameter in getAiModel must be passed as an array rather than a single object to avoid compilation or runtime errors; second, when the model returns multiple function calls, all responses must be collected and sent back together to prevent the Gemini API from throwing a runtime error.
| const model = getAiModel('gemini-3.6-flash', { | ||
| model: "gemini-3.6-flash", | ||
| // Provide the function declaration to the model. | ||
| tools: fetchWeatherTool | ||
| }); |
There was a problem hiding this comment.
The tools configuration parameter expects an array of tools (e.g., [fetchWeatherTool]) rather than a single tool object. Passing a single object will cause a TypeScript compilation error or runtime failure. Additionally, the model property is redundant here since it is already specified as the first argument to getAiModel.
const model = getAiModel('gemini-3.6-flash', {
// Provide the function declaration to the model.
tools: [fetchWeatherTool]
});| const functionCalls = result.response.functionCalls() ?? []; | ||
| let functionCall; | ||
| let functionResult; | ||
| // When the model responds with one or more function calls, invoke the function(s). | ||
| if (functionCalls.length > 0) { | ||
| for (const call of functionCalls) { | ||
| if (call.name === "fetchWeather") { | ||
| // Forward the structured input data prepared by the model | ||
| // to the hypothetical external API. | ||
| functionResult = await fetchWeather(call.args as { location: { city: string; state: string }; date: string }); | ||
| functionCall = call; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Step 5: Send the response from the function back to the model | ||
| * so that the model can use it to generate its final response. | ||
| */ | ||
|
|
||
| if (functionCall && functionResult) { | ||
| result = await chat.sendMessage([ | ||
| { | ||
| functionResponse: { | ||
| name: functionCall.name, // "fetchWeather" | ||
| response: functionResult, | ||
| }, | ||
| }, | ||
| ]); | ||
| } |
There was a problem hiding this comment.
When the model returns multiple function calls in a single turn, the Gemini API requires that you provide a response for each of the requested function calls in the next message. If you only send a single response back (the last one that was overwritten in the loop), the API will throw a runtime error. Collecting all responses into an array and sending them together resolves this issue and ensures robust multi-turn function calling.
const functionCalls = result.response.functionCalls() ?? [];
const functionResponses = [];
// When the model responds with one or more function calls, invoke the function(s).
for (const call of functionCalls) {
if (call.name === "fetchWeather") {
// Forward the structured input data prepared by the model
// to the hypothetical external API.
const functionResult = await fetchWeather(call.args as { location: { city: string; state: string }; date: string });
functionResponses.push({
functionResponse: {
name: call.name,
response: functionResult,
},
});
}
}
/**
* Step 5: Send the response from the function back to the model
* so that the model can use it to generate its final response.
*/
if (functionResponses.length > 0) {
result = await chat.sendMessage(functionResponses);
}5444eb7 to
e79f5e6
Compare
ac1a63b to
f2d1a6c
Compare
|
Branch got messy; creating a new one for a cleaner start. |
No description provided.