Google Gemini
Gemini is captured through the google-genai client (@google/genai on npm).
Wrap the client where you construct it.
import metergraphfrom google import genai
client = metergraph.wrap(genai.Client())
response = client.models.generate_content( model="gemini-2.5-flash", contents="Summarize this invoice.",)import * as mg from "metergraph";import { GoogleGenAI } from "@google/genai";
const client = mg.wrap(new GoogleGenAI({}));
const response = await client.models.generateContent({ model: "gemini-2.5-flash", contents: "Summarize this invoice.",});What gets instrumented
Section titled “What gets instrumented”| Method | Recorded as |
|---|---|
models.generate_content | models.generate_content |
models.generate_content_stream | models.generate_content.stream |
aio.models.generate_content | models.generate_content |
aio.models.generate_content_stream | models.generate_content.stream |
| Method | Recorded as |
|---|---|
models.generateContent | models.generate_content |
models.generateContentStream | models.generate_content.stream |
There is no .aio namespace on the JavaScript client, and none is needed:
its methods are already promise-based.
A method outside this table produces no row. That includes embeddings,
caches, files, tunings and the Live API.
client = metergraph.wrap(genai.Client())
async def summarize(text: str) -> str: response = await client.aio.models.generate_content( model="gemini-2.5-flash", contents=text, ) return response.textOne wrap() covers both namespaces. The sync and async seams are patched
on the same client object.
// Already promise-based. One wrap(), then await as usual.const client = mg.wrap(new GoogleGenAI({}));const response = await client.models.generateContent({ ... });Streaming
Section titled “Streaming”for chunk in client.models.generate_content_stream( model="gemini-2.5-flash", contents="Write a release note.",): print(chunk.text or "", end="")const stream = await client.models.generateContentStream({ model: "gemini-2.5-flash", contents: "Write a release note.",});for await (const chunk of stream) { process.stdout.write(chunk.text ?? "");}The row is finalized when the stream ends, is abandoned, or raises. Time to first token is measured from the first chunk whose candidates carry content, including a chunk whose only content is a function call.
Tool use
Section titled “Tool use”Function calling needs no configuration. Each generate_content call is one
row, so an automatic function-calling loop produces one row per model turn.
Wrap the loop in a trace() to keep it together.
with metergraph.trace("support-agent"): response = client.models.generate_content( model="gemini-2.5-flash", contents=question, config={"tools": [tool_declarations]}, )await mg.trace("support-agent", async () => { return client.models.generateContent({ model: "gemini-2.5-flash", contents: question, config: { tools: [toolDeclarations] }, });});Function calls and their responses are normalized into the same tool-event shape used for the other providers. See Captured fields.
Chat sessions
Section titled “Chat sessions”client.chats is not in the seam table, but chat sessions are still captured.
The chat session holds a reference to the same models object that wrap()
patched, and it resolves the method at call time, so send_message and
send_message_stream land on the instrumented path and produce ordinary
models.generate_content rows.
client = metergraph.wrap(genai.Client())
chat = client.chats.create(model="gemini-2.5-flash")chat.send_message("Hello") # capturedconst client = mg.wrap(new GoogleGenAI({}));
const chat = client.chats.create({ model: "gemini-2.5-flash" });await chat.sendMessage({ message: "Hello" }); // capturedGive the conversation a session ID so the turns group together. See Identity model.
If detection guesses wrong
Section titled “If detection guesses wrong”wrap() identifies a Gemini client by the presence of models.generate_content
(models.generateContent in TypeScript). A proxy, a mock or a subclass that
hides that attribute falls through to the Anthropic branch, and no seams get
patched. The log line tells you: it names the provider it decided on and how
many seams it found.
Name the provider explicitly to settle it.
client = metergraph.wrap(unusual_client, provider="google")const client = mg.wrap(unusualClient, "google");- Name a route to group calls by product surface
- Serverless and short-lived jobs before deploying to a runtime that freezes
- Runnable examples: Python, Node