Google Gemini
Use @codespar/google-genai to give Google Gemini agents commerce capabilities in Latin America.
Google Gemini Adapter
The @codespar/google-genai adapter converts CodeSpar session tools into Google's Gemini FunctionDeclaration format. It provides helpers to build the full tools config for getGenerativeModel() and handle function call responses. Works with Gemini 1.5 Pro, Gemini 1.5 Flash, and Gemini 2.0 models.
Installation
npm install @codespar/sdk @codespar/google-genai @google/generative-aipnpm add @codespar/sdk @codespar/google-genai @google/generative-aiyarn add @codespar/sdk @codespar/google-genai @google/generative-ai@codespar/google-genai has a peer dependency on @codespar/sdk@^0.2.0. You also need @google/generative-ai for the Gemini runtime.
API Reference
getToolsConfig(session): Promise<{ functionDeclarations }[]>
Fetches all tools and returns the full tools config array ready to pass to getGenerativeModel(). This is the most common entry point.
import { CodeSpar } from "@codespar/sdk";
import { getToolsConfig } from "@codespar/google-genai";
import { GoogleGenerativeAI } from "@google/generative-ai";
const codespar = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });
const session = await codespar.sessions.create({
servers: ["stripe", "mercadopago"],
});
const toolsConfig = await getToolsConfig(session);
const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);
const model = genAI.getGenerativeModel({
model: "gemini-1.5-pro",
tools: toolsConfig,
});getTools(session): Promise<GeminiFunctionDeclaration[]>
Returns the raw array of FunctionDeclaration objects without the wrapper. Use when you need to manipulate declarations before passing to Gemini.
import { getTools } from "@codespar/google-genai";
const declarations = await getTools(session);
// Filter to only payment tools
const paymentDecls = declarations.filter((d) => d.name.includes("pay"));toGeminiTool(tool): GeminiFunctionDeclaration
Converts a single CodeSpar tool to a Gemini FunctionDeclaration.
import { toGeminiTool } from "@codespar/google-genai";
const allTools = await session.tools();
const decl = toGeminiTool(allTools[0]);
// { name: "codespar_checkout", description: "...", parameters: { type: "object", ... } }handleFunctionCall(session, functionCall): Promise<ToolResult>
Executes a Gemini function call response by routing through the CodeSpar session. Takes { name, args } from the Gemini response.
import { handleFunctionCall } from "@codespar/google-genai";
// functionCall comes from response.functionCalls()[0]
const result = await handleFunctionCall(session, {
name: "codespar_checkout",
args: { provider: "stripe", amount: 4990, currency: "BRL" },
});Full agent loop
This is a complete example of a Gemini agent with CodeSpar tools:
import { GoogleGenerativeAI } from "@google/generative-ai";
import { CodeSpar } from "@codespar/sdk";
import { getToolsConfig, handleFunctionCall } from "@codespar/google-genai";
const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);
const codespar = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });
async function run(userMessage: string) {
// 1. Create a session
const session = await codespar.sessions.create({
servers: ["stripe", "asaas", "correios"],
});
// 2. Get tools config for Gemini
const toolsConfig = await getToolsConfig(session);
// 3. Create the model with tools
const model = genAI.getGenerativeModel({
model: "gemini-1.5-pro",
tools: toolsConfig,
systemInstruction:
"You are a commerce assistant for a Brazilian e-commerce store. " +
"Use the available tools to handle payments, invoicing, and shipping. " +
"Respond in the same language the user writes in.",
});
// 4. Start a chat
const chat = model.startChat();
let response = await chat.sendMessage(userMessage);
// 5. Tool call loop
const MAX_ITERATIONS = 10;
let iterations = 0;
while (iterations < MAX_ITERATIONS) {
const functionCalls = response.functionCalls();
if (!functionCalls || functionCalls.length === 0) break;
// Execute each function call
const functionResponses = [];
for (const fc of functionCalls) {
let resultData: unknown;
try {
const result = await handleFunctionCall(session, fc);
resultData = result.data;
} catch (error) {
resultData = {
error: error instanceof Error ? error.message : "Function call failed",
};
}
functionResponses.push({
functionResponse: {
name: fc.name,
response: resultData,
},
});
}
// Send function results back
response = await chat.sendMessage(functionResponses);
iterations++;
}
// 6. Clean up
await session.close();
return response.text();
}
const reply = await run("Generate a boleto for R$250 due in 7 days");
console.log(reply);Handling parallel tool calls
Gemini may return multiple function calls in a single response. Execute them in parallel:
const functionCalls = response.functionCalls() ?? [];
const results = await Promise.all(
functionCalls.map(async (fc) => {
const result = await handleFunctionCall(session, fc);
return {
functionResponse: { name: fc.name, response: result.data },
};
})
);
response = await chat.sendMessage(results);You must return a response for every function call. Omitting a response will cause Gemini to return an error.
Streaming
Use sendMessageStream for streaming responses:
import { GoogleGenerativeAI } from "@google/generative-ai";
import { CodeSpar } from "@codespar/sdk";
import { getToolsConfig, handleFunctionCall } from "@codespar/google-genai";
const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);
const codespar = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });
async function runStreaming(userMessage: string) {
const session = await codespar.sessions.create({
servers: ["stripe", "mercadopago"],
});
const toolsConfig = await getToolsConfig(session);
const model = genAI.getGenerativeModel({
model: "gemini-1.5-flash",
tools: toolsConfig,
});
const chat = model.startChat();
const streamResult = await chat.sendMessageStream(userMessage);
for await (const chunk of streamResult.stream) {
const text = chunk.text();
if (text) process.stdout.write(text);
}
const response = await streamResult.response;
const functionCalls = response.functionCalls();
if (functionCalls && functionCalls.length > 0) {
for (const fc of functionCalls) {
const result = await handleFunctionCall(session, fc);
console.log(`\nTool ${fc.name}:`, result.data);
}
}
await session.close();
}
await runStreaming("Create a Pix payment for R$150");Error handling
Wrap handleFunctionCall in try-catch and return errors as function responses:
for (const fc of functionCalls) {
let resultData: unknown;
try {
const result = await handleFunctionCall(session, fc);
resultData = result.data;
} catch (error) {
resultData = {
error: error instanceof Error ? error.message : "Function call failed",
function_name: fc.name,
};
}
functionResponses.push({
functionResponse: { name: fc.name, response: resultData },
});
}Returning errors as function responses lets Gemini reason about the failure and decide to retry or try a different approach.
Best practices
-
Always close sessions. Use
try/finallyto ensuresession.close()runs. -
Use
getToolsConfig. It returns the correct envelope format forgetGenerativeModel(). UsegetToolsonly when you need to manipulate declarations. -
Prefer Gemini 1.5 Pro for tool calling. It has the best function-calling accuracy. Flash works but may be less reliable with complex schemas.
-
Set a descriptive system instruction. Tell Gemini what domain it operates in.
-
Limit loop iterations. Add
MAX_ITERATIONSto prevent infinite function-call loops. -
Scope servers narrowly. Fewer tools means better function selection accuracy.
Next steps
- Sessions -- Session lifecycle and configuration
- Tools and Meta-Tools -- Understand the 6 meta-tools and routing
- OpenAI Adapter -- If you prefer OpenAI models
- Claude Adapter -- If you prefer Anthropic models
- Quickstart -- End-to-end setup in under 5 minutes