Skip to main content

LangChain and LangGraph observability for Tuner SDKs

Project description

tuner-langchain

LangChain and LangGraph observability for Tuner SDKs.

Captures node transitions, tool calls, and tool results from LangChain and LangGraph agents and feeds them into the Tuner transcript pipeline — giving you full visibility into what your orchestration layer did on every call.


Overview

When users run LangChain or LangGraph as the orchestration layer inside a LiveKit or Pipecat voice agent, tool calls and node transitions happen inside the graph — invisible to the voice framework. This package bridges that gap.

It works by attaching a LangChain callback handler to the graph invocation. The handler captures every node transition and tool call with wall-clock timestamps, and the Tuner SDK mappers inject them into the transcript at flush time — in the correct position between the user message and the bot response.


Installation

Not yet on PyPI. Install locally from the repo:

pip install -e /path/to/tuner-langchain

Once published:

pip install tuner-langchain

Requirements: Python ≥ 3.10, langchain-core >= 1.0, < 2.0


Usage

With LiveKit

from livekit.agents import AgentSession, JobContext
from livekit.plugins import langchain
from tuner import TunerPlugin

async def entrypoint(ctx: JobContext):
    session = AgentSession(...) 

    plugin = TunerPlugin(session, ctx)
    handler = plugin.attach_langgraph() 

    session = AgentSession(
        llm=langchain.LLMAdapter(
            graph=my_compiled_graph,
            config={"callbacks": [handler]},  # ← pass it here
        ),
        ...
    )

    await session.start(...)

For plain LangChain (non-graph):

handler = plugin.attach_langchain()
chain.invoke(inputs, config={"callbacks": [handler]})

What gets captured

Node transitions (node_transition)

Every named LangGraph node or LangChain chain step:

Field Description
node_name The node/step name as defined in the graph
start_ms Start time relative to call start
end_ms End time relative to call start
duration_ms Execution time in milliseconds
inputs Node inputs (omitted when empty)
outputs Node outputs (omitted when empty)
error Error message if the node failed
node_instructions System prompt active during this node's LLM call

LangGraph internal nodes (__start__, __end__, compiled graph root) are filtered out automatically.

Tool calls (agent_function + agent_result)

Every tool invocation inside the graph:

Field Description
tool_name Tool name
inputs Raw input string passed to the tool
output Tool result or error message
is_error Whether the tool raised an error
duration_ms Tool execution time in milliseconds
start_ms Invocation time relative to call start

Data Privacy

By default, tuner-langchain forwards the following data to the Tuner ingestion API:

Field Captured by default How to disable
Node instructions node_instructions=False
Tool inputs tool_inputs=False
Tool outputs tool_outputs=False
Node inputs node_inputs=False
Node outputs node_outputs=False

Node instructions are capped at 300 characters. Tool error output is always captured regardless of tool_outputs — errors are not considered sensitive and are required for debugging.

To disable specific fields, pass a CaptureConfig to attach_langgraph() or attach_langchain():

from tuner_langchain import CaptureConfig

handler = plugin.attach_langgraph(
    capture=CaptureConfig(
        node_instructions=False,
        tool_inputs=False,
        tool_outputs=False,
        node_inputs=False,
        node_outputs=False,
    )
)

How it fits in the transcript

All segments are sorted chronologically by start_ms — the correct execution order:

user message
  node_transition  "intent_classifier"   (start_ms, end_ms, duration_ms)
  node_transition  "booking_node"        (start_ms, end_ms, inputs, outputs)
  agent_function   "get_patient_info"    (start_ms, inputs)
  agent_result     "get_patient_info"    (start_ms, output, duration_ms)
agent text response
user message
  ...

The segment shape is identical to what Tuner produces for non-LangGraph tool calls — same role, same tool object structure, same timing fields. The Tuner API and frontend handle both paths transparently.


Architecture

src/tuner_langchain/
├── __init__.py          public API
├── models.py            NodeTransition, ToolCallEvent, GraphInvocation
├── accumulator.py       TunerAccumulator — stores events per session
├── segment_builder.py   segments_from_invocation() — used by SDK mappers at flush
└── handlers/
    ├── __init__.py
    ├── base.py          TunerBaseHandler — shared tool + chain-end logic
    ├── langgraph.py     TunerLangGraphHandler — filters __start__/__end__
    └── langchain.py     TunerLangChainHandler — filters anonymous wrappers

TunerBaseHandler holds all shared logic. TunerLangGraphHandler and TunerLangChainHandler only override on_chain_start — the one place where the two frameworks differ in how chain names are interpreted.


Public API

from tuner_langchain import (
    # Handlers — pass to graph/chain config
    TunerLangGraphHandler,
    TunerLangChainHandler,

    # Accumulator — one per session, created by attach_langgraph() / attach_langchain()
    TunerAccumulator,

    # Segment builder — used internally by SDK mappers at flush time
    segments_from_invocation,

    # Models
    GraphInvocation,
    NodeTransition,
    ToolCallEvent,
)

Development

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest tests/ -v

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tuner_langchain-0.1.0.tar.gz (19.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tuner_langchain-0.1.0-py3-none-any.whl (16.6 kB view details)

Uploaded Python 3

File details

Details for the file tuner_langchain-0.1.0.tar.gz.

File metadata

  • Download URL: tuner_langchain-0.1.0.tar.gz
  • Upload date:
  • Size: 19.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.7

File hashes

Hashes for tuner_langchain-0.1.0.tar.gz
Algorithm Hash digest
SHA256 98e1869c1d68c4dd26ba0e7037e7daaa3005b26da91ffca84f3e7fff7a7ec96f
MD5 de951486435c061150008dd65ebc2eb2
BLAKE2b-256 68abd4acf2da0a69f0ec892c8117daa5c3d8b92561a5f8745712573c7485957e

See more details on using hashes here.

File details

Details for the file tuner_langchain-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for tuner_langchain-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3e0b68ce77a2c2482614e24a1c99eedd2632e06ad8d00c3478c43df0f90d456c
MD5 603939b6dc96f73dad1631ea4f55ab5c
BLAKE2b-256 04af8c0c9a978d20982512fecc991061fd94364e2c06e6ef721264ccd8ec7ed8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page