Skip to main content
Providers

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-ai
pnpm add @codespar/sdk @codespar/google-genai @google/generative-ai
yarn 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:

gemini-agent.ts
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:

gemini-streaming.ts
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

  1. Always close sessions. Use try/finally to ensure session.close() runs.

  2. Use getToolsConfig. It returns the correct envelope format for getGenerativeModel(). Use getTools only when you need to manipulate declarations.

  3. 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.

  4. Set a descriptive system instruction. Tell Gemini what domain it operates in.

  5. Limit loop iterations. Add MAX_ITERATIONS to prevent infinite function-call loops.

  6. Scope servers narrowly. Fewer tools means better function selection accuracy.

Next steps