We're in development! Things may crash or break

Integrations

Gemini Integration

Track Google Gemini API calls — text generation, streaming, chat sessions, and embeddings — automatically with @fluxgate/gemini.

Install

npm install @fluxgate/sdk @fluxgate/gemini @google/generative-ai

One-time setup

Unlike the OpenAI and Anthropic wrappers, createGeminiCostTracker wraps a model instance, not the top-level client. Create one tracked model per model ID you use.

// lib/gemini.ts
import { GoogleGenerativeAI } from "@google/generative-ai";
import { FluxGate } from "@fluxgate/sdk";
import { createGeminiCostTracker } from "@fluxgate/gemini";

const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
const fg = new FluxGate({ apiKey: process.env.FLUXGATE_API_KEY! });

// Create one tracked model per model ID you use
export const geminiPro = createGeminiCostTracker(
  genAI.getGenerativeModel({ model: "gemini-1.5-pro" }),
  fg,
);

export const geminiFlash = createGeminiCostTracker(
  genAI.getGenerativeModel({ model: "gemini-1.5-flash" }),
  fg,
);

Text generation

import { geminiPro } from "@/lib/gemini";

const result = await geminiPro
  .withContext({
    feature: "content-generation",
    user: { id: session.user.id },
    sessionId: session.id,
  })
  .generateContent(prompt);

const text = result.response.text();
const { cost, trackingId } = result.fluxGateCostTrackingResponse;

Streaming

const result = await geminiPro
  .withContext({ feature: "streaming-gen" })
  .generateContentStream(longPrompt);

for await (const chunk of result.stream) {
  process.stdout.write(chunk.text());
}

// Tracking is finalised once the stream is consumed
const response = await result.response;
console.log(result.fluxGateCostTrackingResponse);

Multi-turn chat sessions

startChat returns a TrackedChatSession. Each sendMessage and sendMessageStream call is tracked individually and attributed to the same context.

const chat = geminiPro
  .withContext({ feature: "chatbot", user: session.user.id })
  .startChat({
    history: [
      { role: "user", parts: [{ text: "Hello" }] },
      { role: "model", parts: [{ text: "Hi! How can I help?" }] },
    ],
  });

const result1 = await chat.sendMessage("What is FluxGate?");
console.log(result1.response.text());

const result2 = await chat.sendMessage("How do I install it?");
console.log(result2.response.text());

Mid-conversation context upgrade

Use .withTracking() on an existing TrackedChatSession to merge additional metadata — useful when a user authenticates mid-session or moves to a paid feature tier.

const premiumChat = chat.withTracking({
  feature: "premium-chatbot",
  user: {
    id: currentUser.id,
    monthlyRevenue: currentUser.mrr,
  },
});

const result = await premiumChat.sendMessage("I need a detailed analysis");

New context keys override matching keys; unmatched keys are preserved from the original context.

Multimodal (vision)

import { GoogleGenerativeAI } from "@google/generative-ai";
import { createGeminiCostTracker } from "@fluxgate/gemini";
import { FluxGate } from "@fluxgate/sdk";
import fs from "fs";

const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
const fg = new FluxGate({ apiKey: process.env.FLUXGATE_API_KEY! });

const vision = createGeminiCostTracker(
  genAI.getGenerativeModel({ model: "gemini-pro-vision" }),
  fg,
);

const imageBytes = fs.readFileSync("./screenshot.jpg").toString("base64");

const result = await vision
  .withContext({ feature: "image-analysis" })
  .generateContent([
    { text: "Describe the UI and identify any accessibility issues." },
    { inlineData: { mimeType: "image/jpeg", data: imageBytes } },
  ]);

Embeddings

const result = await geminiPro
  .withContext({ feature: "vector-search" })
  .embedContent(document);

const vector = result.embedding.values;

Safety settings

Safety-blocked responses are automatically recorded with status: "BLOCKED".

import { HarmCategory, HarmBlockThreshold } from "@google/generative-ai";

const safeModel = createGeminiCostTracker(
  genAI.getGenerativeModel({
    model: "gemini-1.5-pro",
    safetySettings: [
      {
        category: HarmCategory.HARM_CATEGORY_HARASSMENT,
        threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
      },
    ],
  }),
  fg,
);

FluxGateCostTrackingResponse shape

interface FluxGateCostTrackingResponse {
  status:
    | "SUCCESS"
    | "ERROR"
    | "BLOCKED"
    | "MAX_TOKENS"
    | "CONTENT_FILTER"
    | "RECITATION"
    | "MALFORMED_REQUEST";
  cost: number | null; // USD
  trackingId: string | null;
  createdAt: string | null; // ISO 8601
  errorMessage?: string;
}

Tracked automatically: input tokens, output tokens, cached content tokens, model name, latency (ms), stream duration, and finish reason (stop, max_tokens, safety, recitation).

Supported methods

MethodNon-streamingStreaming
generateContent
generateContentStream
startChatsendMessage
startChatsendMessageStream
embedContent

Supported models

gemini-pro, gemini-pro-vision, gemini-ultra, gemini-1.5-pro, gemini-1.5-flash, and any future models supported by @google/generative-ai.