// Gemini function calling with the @google/genai SDK: forced call (FunctionCallingConfigMode.ANY) + functionResponse round trip. // STATUS: LIVE_VERIFIED 2026-09-18 — `node --env-file=.env --experimental-strip-types examples/gemini/tools/function-calling/function_calling.ts` (gemini-3.5-flash-lite, < $0.001). import { GoogleGenAI, FunctionCallingConfigMode, Type } from "@google/genai"; import { logRequest } from "../../../shared/tool-loop/log.ts"; const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY }); const MODEL = "gemini-3.5-flash-lite"; const getWeather = { name: "get_weather", description: "Get the current weather for a city.", parameters: { type: Type.OBJECT, properties: { city: { type: Type.STRING } }, required: ["city"] } }; const contents: any[] = [{ role: "user", parts: [{ text: "Weather in Paris?" }] }]; const r1 = await ai.models.generateContent({ model: MODEL, contents, config: { tools: [{ functionDeclarations: [getWeather] }], toolConfig: { functionCallingConfig: { mode: FunctionCallingConfigMode.ANY, allowedFunctionNames: ["get_weather"] } }, maxOutputTokens: 64 } }); logRequest("gemini", "POST", "/v1beta/models/{model}:generateContent", 200, 0.0001, "function_calling.ts forced"); const modelTurn = r1.candidates![0].content!; // keep the parts verbatim (thoughtSignature is required on echo) const call = r1.functionCalls![0]; console.log("functionCall:", call.name, JSON.stringify(call.args), "id:", call.id); contents.push(modelTurn, { role: "user", parts: [{ functionResponse: { name: call.name!, response: { temperature_c: 18, conditions: "light rain" } } }] }); const r2 = await ai.models.generateContent({ model: MODEL, contents, config: { tools: [{ functionDeclarations: [getWeather] }], maxOutputTokens: 32 } }); logRequest("gemini", "POST", "/v1beta/models/{model}:generateContent", 200, 0.0001, "function_calling.ts functionResponse"); console.log("final:", r2.text, "| usage:", r2.usageMetadata?.totalTokenCount);