Skip to main content
Two integration options — choose what fits your project:
pip install langsight google-genai
import langsight

langsight.auto_patch()   # patches all Gemini (and OpenAI/Anthropic) clients globally

from google import genai

async def run(question: str) -> str:
    async with langsight.session(agent_name="analyst") as session_id:
        client = genai.Client()   # automatically traced — no wrap_llm() needed
        response = await client.aio.models.generate_content(
            model="gemini-2.5-flash",
            contents=[question],
        )
        return response.text
Set environment variables once:
export LANGSIGHT_URL=http://localhost:8000
export LANGSIGHT_API_KEY=ls_your_key
export LANGSIGHT_PROJECT_ID=my-project

Option B: Explicit wrap_llm()

When you need per-call control, or when auto_patch() is not suitable:
import langsight
from google import genai

ls = langsight.init()  # reads LANGSIGHT_URL, LANGSIGHT_API_KEY, LANGSIGHT_PROJECT_ID

async with langsight.session(agent_name="analyst") as session_id:
    # agent_name and session_id inherited from context — no need to pass them
    client = ls.wrap_llm(genai.Client())

    # Async — your existing code, unchanged
    response = await client.aio.models.generate_content(
        model="gemini-2.5-flash",
        contents=[...],
        config=config,
    )
    # Auto-traced: LLM generation span + llm_intent spans per tool decision
The wrapper intercepts client.models.generate_content() (sync) and client.aio.models.generate_content() (async). All other attributes and methods forward to the original client unchanged.
agent_name, session_id, and trace_id are optional when called inside langsight.session() — the context is inherited automatically. Only pass them explicitly when you need to override the context values.

Multi-agent example

The recommended pattern for orchestrator → analyst → procurement workflows:
Every agent needs input= and sess.set_output() — not just the orchestrator. Without them, the Input/Output panel in the session graph will be empty for that agent’s node, even though the session itself is tracked correctly.
import langsight
from google import genai

langsight.auto_patch()  # patches all Gemini clients + MCP sessions globally

async def orchestrator(question: str):
    async with langsight.session(agent_name="orchestrator", input=question) as sess:
        client = genai.Client()
        response = await client.aio.models.generate_content(
            model="gemini-2.5-flash", contents=[question], config=config,
        )
        sess.set_output(response.text)  # ← captures final answer in dashboard
        return response.text

async def analyst(question: str, session_id: str):
    # input= and sess.set_output() required for Input/Output to appear in the
    # session graph right panel for this agent's node
    async with langsight.session(agent_name="analyst", session_id=session_id, input=question) as sess:
        client = genai.Client()
        data = await catalog_mcp_session.call_tool("search", {"q": question})
        result = process(data)
        sess.set_output(result)  # ← without this, Output is blank in dashboard
        return result

async def procurement(findings: str, session_id: str):
    async with langsight.session(agent_name="procurement", session_id=session_id, input=findings) as sess:
        client = genai.Client()
        plan = await generate_plan(findings)
        sess.set_output(plan)
        return plan
Rule of thumb: every session() block that represents a meaningful agent turn should have:
  • input= — what the agent received (user question, upstream findings, etc.)
  • sess.set_output(result) — what the agent produced
This is what populates the Input / Output panel in the session detail view for each node.
Sub-agents that are awaited directly (not spawned via asyncio.create_task()) inherit the parent session context automatically. But for Input/Output to appear per-agent, pass session_id explicitly and use input= + sess.set_output():
async with langsight.session(agent_name="orchestrator", input=question) as sess:
    session_id = str(sess)
    result = await analyst(question, session_id=session_id)
    sess.set_output(result)

async def analyst(question: str, session_id: str):
    async with langsight.session(agent_name="analyst", session_id=session_id, input=question) as sess:
        answer = await do_work(question)
        sess.set_output(answer)
        return answer
If you omit session_id=session_id, each sub-agent creates its own independent session and the spans will not appear in the parent session’s graph.

What gets traced

SpanFields
LLM generationserver_name="gemini", tool_name="generate/gemini-2.5-flash", span_type="agent", tokens, model_id
Function call (per tool)tool_name from response, span_type="tool_call", parent_span_id linking to the LLM span, input_args
Session: sess-001
├── gemini/generate/gemini-2.5-flash  1200ms  success  (512 in / 128 out)
│   ├── list_products                                    success
│   └── get_stock_level                                  success

Combining with MCP tracing

wrap_llm() and wrap() work independently. Use both when your agent calls Gemini directly and also uses MCP servers. Inside a session() block, agent_name and session_id are inherited automatically — no threading needed:
async with langsight.session(agent_name="analyst") as session_id:
    # Trace LLM calls — agent_name and session_id inherited from context
    client = ls.wrap_llm(genai.Client())

    # Trace MCP tool calls — same
    traced_mcp = ls.wrap(mcp_session, server_name="postgres-mcp")

Parameters

client = ls.wrap_llm(
    genai.Client(),            # required — google.genai.Client instance
    agent_name="my-agent",     # optional — shown in dashboard
    session_id="sess-001",     # optional — groups spans into a session
    trace_id="trace-abc",      # optional — links across multi-agent tasks
)

PII redaction

ls = LangSightClient(url="http://localhost:8000", redact_payloads=True)
# Tool arguments from function_call parts are not captured
If you’re using the older google-generativeai package (pip install google-generativeai):
import google.generativeai as genai

raw_model = genai.GenerativeModel("gemini-2.5-flash")
model = ls.wrap_llm(raw_model, agent_name="analyst", session_id="sess-001")

response = model.generate_content("Analyze this data", tools=[...])
The legacy wrapper intercepts model.generate_content() (sync) and model.generate_content_async() (async).