---
title: Google Gemini
description: Use @codespar/google-genai to give Google Gemini agents commerce capabilities in Latin America.
---

import { Callout } from "fumadocs-ui/components/callout";
import { Tab, Tabs } from "fumadocs-ui/components/tabs";

# Google Gemini Adapter

<VersionBadge pkg="@codespar/google-genai" />

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.

<Callout type="info">
**Pick this adapter when** you need multimodal commerce flows (photo-of-receipt → invoice), the very long context windows Gemini provides (2M tokens on 1.5 Pro) for reconciling large transaction histories, or your infrastructure already runs on Google Cloud / Vertex AI.
</Callout>

## Framework-specific notes

- **`FunctionDeclaration` is flatter than OpenAI/Anthropic** — no nested `type: "function"` wrapper. The adapter takes care of the conversion, but if you read the `tools` config, it looks different.
- **Multimodal is the differentiator** — pass a `Part` with an image (receipt, screenshot, product photo) in the same prompt as your tool request; Gemini can read the image and pick the right `codespar_invoice` or `codespar_pay` arguments from what it sees.
- **2M-token context** — 1.5 Pro keeps a full month of transaction logs in memory for reconciliation agents without summarization.
- **Parallel function calls in 2.0** — Gemini 2.0 Flash + Pro emit multiple `functionCall` parts per response. Gemini 1.5 does one at a time. Pick the model intentionally based on the flow's concurrency.
- **Vertex AI auth** — if you are on Google Cloud, prefer Vertex AI credentials over API keys. The adapter accepts both but project-scoped IAM scales better for multi-tenant SaaS.

## Installation

<Tabs items={["npm", "pnpm", "yarn"]}>
<Tab value="npm">
```bash
npm install @codespar/sdk @codespar/google-genai @google/generative-ai
```
</Tab>
<Tab value="pnpm">
```bash
pnpm add @codespar/sdk @codespar/google-genai @google/generative-ai
```
</Tab>
<Tab value="yarn">
```bash
yarn add @codespar/sdk @codespar/google-genai @google/generative-ai
```
</Tab>
</Tabs>

<Callout type="info">
`@codespar/google-genai` has a peer dependency on `@codespar/sdk@^0.10.0`. You also need `@google/generative-ai` for the Gemini runtime.
</Callout>
## 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.

```typescript
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.create("user_123", {
  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.

```typescript
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`.

```typescript
import { toGeminiTool } from "@codespar/google-genai";

const allTools = await session.tools();
const decl = toGeminiTool(allTools[0]);
// { name: "codespar_charge", 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.

```typescript
import { handleFunctionCall } from "@codespar/google-genai";

// functionCall comes from response.functionCalls()[0]
const result = await handleFunctionCall(session, {
  name: "codespar_charge",
  args: { provider: "stripe", amount: 4990, currency: "BRL" },
});
```

## Full agent loop

This is a complete example of a Gemini agent with CodeSpar tools:

```typescript title="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.create("user_123", {
    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:

```typescript
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);
```

<Callout type="warn">
You must return a response for every function call. Omitting a response will cause Gemini to return an error.
</Callout>
## Streaming

Use `sendMessageStream` for streaming responses:

```typescript title="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.create("user_123", {
    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:

```typescript
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 },
  });
}
```

<Callout type="info">
Returning errors as function responses lets Gemini reason about the failure and decide to retry or try a different approach.
</Callout>
## 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.

## Newer SDK wrappers

The adapter wires Gemini to `session.tools()` + `session.execute()`. For higher-level flows you can call typed wrappers on the session directly — same routing infrastructure, no LLM hop:

- `session.discover(query)` / `session.charge(args)` / `session.pay(args)` / `session.ship(args)` — typed shortcuts for the meta-tools.
- `session.connectionWizard(serverId)` — open a hosted auth flow for a missing connection.
- `session.paymentStatus(toolCallId)` and `session.paymentStatusStream(toolCallId)` — async settlement correlation (poll or SSE).
- `session.verificationStatus(toolCallId)` and `session.verificationStatusStream(toolCallId)` — KYC outcome polling / SSE.

Full reference at [/docs/api/sdk](/docs/api/sdk).

## Next steps

<NextStepsGrid items={[
  { label: "CONCEPT", title: "Sessions", description: "Session lifecycle and configuration.", href: "/docs/concepts/sessions" },
  { label: "CONCEPT", title: "Tools & Meta-Tools", description: "Meta-tools and how routing works.", href: "/docs/concepts/tools" },
  { label: "PROVIDER", title: "OpenAI Adapter", description: "If you prefer OpenAI models.", href: "/docs/providers/openai" },
  { label: "PROVIDER", title: "Claude Adapter", description: "If you prefer Anthropic models.", href: "/docs/providers/claude" },
  { label: "QUICKSTART", title: "Quickstart", description: "End-to-end setup in under 5 minutes.", href: "/docs/quickstart" },
]} />
