Alpha (v0.1.0) — This package is implemented and tested but not yet published to PyPI. Install from source or wait for the public release. See the Python overview for setup instructions.
The mutagent-langgraph package provides a graph tracer that captures graph executions, node invocations, and edge transitions in LangGraph workflows.
import osfrom mutagent_tracing import init_tracing, shutdown_tracingfrom mutagent_langgraph import MutagentGraphTracer# Initialize MutagenT tracinginit_tracing( api_key=os.environ["MUTAGENT_API_KEY"], environment="production",)tracer = MutagentGraphTracer()def classify(text: str) -> str: """Classify input text.""" return "positive" if "good" in text.lower() else "negative"def respond(sentiment: str) -> str: """Generate a response based on sentiment.""" if sentiment == "positive": return "Glad to hear that!" return "Sorry to hear that. How can I help?"# Trace the full graph executionwith tracer.trace_graph("sentiment_pipeline", input_data={"text": "This is good!"}): with tracer.trace_node("classifier"): sentiment = classify("This is good!") tracer.trace_edge("classifier", "responder") with tracer.trace_node("responder"): response = respond(sentiment)print(response)# Flush remaining spans on exitshutdown_tracing()
For cases where context managers are not suitable, use the imperative start/end methods:
# Graph levelexecution_id = tracer.handle_graph_start("my_graph", input_data={"key": "value"})# ... do work ...tracer.handle_graph_end(execution_id, output_data={"result": "done"})# Node levelnode_id = tracer.handle_node_start("my_node", input_data={"key": "value"})# ... do work ...tracer.handle_node_end(node_id, output_data={"result": "done"})
The imperative API is useful when integrating with existing LangGraph event hooks or when the graph execution flow does not map cleanly to Python with blocks.
Track conditional edges to see which branches your graph takes:
with tracer.trace_graph("router_graph"): with tracer.trace_node("classifier"): category = classify(user_input) if category == "technical": tracer.trace_edge("classifier", "tech_support", condition="category == 'technical'") with tracer.trace_node("tech_support"): result = handle_tech(user_input) else: tracer.trace_edge("classifier", "general_support", condition="category != 'technical'") with tracer.trace_node("general_support"): result = handle_general(user_input)
Errors raised inside context managers are automatically captured. The span is recorded with ERROR status and the error message is preserved:
with tracer.trace_graph("my_graph"): with tracer.trace_node("risky_node"): raise ValueError("Something went wrong") # The node span and graph span both get ERROR status
For the imperative API, pass the error explicitly:
execution_id = tracer.handle_graph_start("my_graph")try: node_id = tracer.handle_node_start("risky_node") raise ValueError("Something went wrong")except Exception as e: tracer.handle_node_end(node_id, error=e) tracer.handle_graph_end(execution_id, error=e)