Skip to content

Commit 7b50c9c

Browse files
Dwij1704fenilfaldu
andauthored
Add LangGraph integration with AgentOps (#1107)
* Add LangGraph integration with AgentOps for enhanced observability * feat: Add LangGraph examples demonstrating improved AgentOps instrumentation * fix notebook --------- Co-authored-by: Fenil Faldu <[email protected]>
1 parent b0563b2 commit 7b50c9c

File tree

10 files changed

+1607
-0
lines changed

10 files changed

+1607
-0
lines changed

agentops/instrumentation/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ class InstrumentorConfig(TypedDict):
125125
"class_name": "SmolagentsInstrumentor",
126126
"min_version": "1.0.0",
127127
},
128+
"langgraph": {
129+
"module_name": "agentops.instrumentation.agentic.langgraph",
130+
"class_name": "LanggraphInstrumentor",
131+
"min_version": "0.2.0",
132+
},
128133
}
129134

130135
# Combine all target packages for monitoring
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from agentops.instrumentation.agentic.langgraph.instrumentation import LanggraphInstrumentor
2+
3+
__all__ = ["LanggraphInstrumentor"]
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from typing import Dict, Any
2+
import json
3+
4+
5+
def ensure_no_none_values(attributes: Dict[str, Any]) -> Dict[str, Any]:
6+
return {k: v for k, v in attributes.items() if v is not None}
7+
8+
9+
def set_graph_attributes(span: Any, graph_nodes: list = None, graph_edges: list = None) -> None:
10+
if graph_nodes:
11+
span.set_attribute("langgraph.graph.nodes", json.dumps(graph_nodes))
12+
span.set_attribute("langgraph.graph.node_count", len(graph_nodes))
13+
14+
for i, node in enumerate(graph_nodes):
15+
span.set_attribute(f"langgraph.node.{i}.name", node)
16+
span.set_attribute(f"langgraph.node.{i}.type", "unknown")
17+
18+
if graph_edges:
19+
span.set_attribute("langgraph.graph.edges", json.dumps(graph_edges))
20+
span.set_attribute("langgraph.graph.edge_count", len(graph_edges))
21+
22+
for i, edge in enumerate(graph_edges):
23+
parts = edge.split("->")
24+
if len(parts) == 2:
25+
span.set_attribute(f"langgraph.edge.{i}.source", parts[0])
26+
span.set_attribute(f"langgraph.edge.{i}.target", parts[1])
27+
28+
29+
def extract_messages_from_input(input_data: Any) -> list:
30+
if isinstance(input_data, dict) and "messages" in input_data:
31+
return input_data["messages"]
32+
return []
33+
34+
35+
def extract_messages_from_output(output_data: Any) -> list:
36+
if isinstance(output_data, dict) and "messages" in output_data:
37+
return output_data["messages"]
38+
return []
39+
40+
41+
def get_message_content(message: Any) -> str:
42+
if hasattr(message, "content"):
43+
return str(message.content)
44+
return ""
45+
46+
47+
def get_message_role(message: Any) -> str:
48+
if hasattr(message, "role"):
49+
return message.role
50+
elif hasattr(message, "type"):
51+
return message.type
52+
elif hasattr(message, "__class__"):
53+
return message.__class__.__name__.replace("Message", "").lower()
54+
return "unknown"

0 commit comments

Comments
 (0)