langtrace-python-sdk 3.8.8__py3-none-any.whl → 3.8.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- examples/neo4j_example/__init__.py +8 -0
- examples/neo4j_example/basic.py +26 -0
- examples/neo4j_graphrag_example/__init__.py +9 -0
- examples/neo4j_graphrag_example/basic.py +52 -0
- examples/neo4j_graphrag_example/data/abramov.pdf +0 -0
- langtrace_python_sdk/constants/instrumentation/neo4j.py +36 -0
- langtrace_python_sdk/instrumentation/__init__.py +1 -0
- langtrace_python_sdk/instrumentation/agno/instrumentation.py +22 -1
- langtrace_python_sdk/instrumentation/agno/patch.py +169 -55
- langtrace_python_sdk/instrumentation/google_genai/instrumentation.py +1 -1
- langtrace_python_sdk/instrumentation/neo4j/__init__.py +3 -0
- langtrace_python_sdk/instrumentation/neo4j/instrumentation.py +51 -0
- langtrace_python_sdk/instrumentation/neo4j/patch.py +180 -0
- langtrace_python_sdk/instrumentation/weaviate/patch.py +4 -4
- langtrace_python_sdk/langtrace.py +4 -3
- langtrace_python_sdk/utils/llm.py +11 -13
- langtrace_python_sdk/version.py +1 -1
- {langtrace_python_sdk-3.8.8.dist-info → langtrace_python_sdk-3.8.10.dist-info}/METADATA +2 -2
- {langtrace_python_sdk-3.8.8.dist-info → langtrace_python_sdk-3.8.10.dist-info}/RECORD +22 -13
- {langtrace_python_sdk-3.8.8.dist-info → langtrace_python_sdk-3.8.10.dist-info}/WHEEL +0 -0
- {langtrace_python_sdk-3.8.8.dist-info → langtrace_python_sdk-3.8.10.dist-info}/entry_points.txt +0 -0
- {langtrace_python_sdk-3.8.8.dist-info → langtrace_python_sdk-3.8.10.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
import os
|
2
|
+
from langtrace_python_sdk import langtrace
|
3
|
+
from neo4j import GraphDatabase
|
4
|
+
|
5
|
+
langtrace.init()
|
6
|
+
|
7
|
+
def execute_query():
|
8
|
+
driver = GraphDatabase.driver(
|
9
|
+
os.getenv("NEO4J_URI"),
|
10
|
+
auth=(os.getenv("NEO4J_USERNAME"), os.getenv("NEO4J_PASSWORD"))
|
11
|
+
)
|
12
|
+
|
13
|
+
records, summary, keys = driver.execute_query(
|
14
|
+
"MATCH (p:Person {age: $age}) RETURN p.name AS name",
|
15
|
+
age=42,
|
16
|
+
database_=os.getenv("NEO4J_DATABASE"),
|
17
|
+
)
|
18
|
+
|
19
|
+
# Loop through results and do something with them
|
20
|
+
for person in records:
|
21
|
+
print(person)
|
22
|
+
# Summary information
|
23
|
+
print("The query `{query}` returned {records_count} records in {time} ms.".format(
|
24
|
+
query=summary.query, records_count=len(records),
|
25
|
+
time=summary.result_available_after,
|
26
|
+
))
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import os
|
2
|
+
from langtrace_python_sdk import langtrace
|
3
|
+
from langtrace_python_sdk.utils.with_root_span import with_langtrace_root_span
|
4
|
+
from neo4j import GraphDatabase
|
5
|
+
from neo4j_graphrag.generation import GraphRAG
|
6
|
+
from neo4j_graphrag.indexes import create_vector_index
|
7
|
+
from neo4j_graphrag.llm import OpenAILLM as LLM
|
8
|
+
from neo4j_graphrag.embeddings import OpenAIEmbeddings as Embeddings
|
9
|
+
from neo4j_graphrag.retrievers import VectorRetriever
|
10
|
+
from neo4j_graphrag.experimental.pipeline.kg_builder import SimpleKGPipeline
|
11
|
+
|
12
|
+
langtrace.init()
|
13
|
+
|
14
|
+
neo4j_driver = GraphDatabase.driver(os.getenv("NEO4J_URI"), auth=(os.getenv("NEO4J_USERNAME"), os.getenv("NEO4J_PASSWORD")))
|
15
|
+
|
16
|
+
ex_llm=LLM(
|
17
|
+
model_name="gpt-4o-mini",
|
18
|
+
model_params={
|
19
|
+
"response_format": {"type": "json_object"},
|
20
|
+
"temperature": 0
|
21
|
+
})
|
22
|
+
|
23
|
+
embedder = Embeddings()
|
24
|
+
|
25
|
+
@with_langtrace_root_span("run_neo_rag")
|
26
|
+
async def search():
|
27
|
+
# 1. Build KG and Store in Neo4j Database
|
28
|
+
kg_builder_pdf = SimpleKGPipeline(
|
29
|
+
llm=ex_llm,
|
30
|
+
driver=neo4j_driver,
|
31
|
+
embedder=embedder,
|
32
|
+
from_pdf=True
|
33
|
+
)
|
34
|
+
await kg_builder_pdf.run_async(file_path='src/examples/neo4j_graphrag_example/data/abramov.pdf')
|
35
|
+
|
36
|
+
create_vector_index(neo4j_driver, name="text_embeddings", label="Chunk",
|
37
|
+
embedding_property="embedding", dimensions=1536, similarity_fn="cosine")
|
38
|
+
|
39
|
+
# 2. KG Retriever
|
40
|
+
vector_retriever = VectorRetriever(
|
41
|
+
neo4j_driver,
|
42
|
+
index_name="text_embeddings",
|
43
|
+
embedder=embedder
|
44
|
+
)
|
45
|
+
|
46
|
+
# 3. GraphRAG Class
|
47
|
+
llm = LLM(model_name="gpt-4o")
|
48
|
+
rag = GraphRAG(llm=llm, retriever=vector_retriever)
|
49
|
+
|
50
|
+
# 4. Run
|
51
|
+
response = rag.search("What did the author do in college?")
|
52
|
+
print(response.answer)
|
Binary file
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from langtrace.trace_attributes import Neo4jMethods
|
2
|
+
|
3
|
+
APIS = {
|
4
|
+
"RUN": {
|
5
|
+
"METHOD": Neo4jMethods.RUN.value,
|
6
|
+
"OPERATION": "run",
|
7
|
+
},
|
8
|
+
"BEGIN_TRANSACTION": {
|
9
|
+
"METHOD": Neo4jMethods.BEGIN_TRANSACTION.value,
|
10
|
+
"OPERATION": "begin_transaction",
|
11
|
+
},
|
12
|
+
"READ_TRANSACTION": {
|
13
|
+
"METHOD": Neo4jMethods.READ_TRANSACTION.value,
|
14
|
+
"OPERATION": "read_transaction",
|
15
|
+
},
|
16
|
+
"WRITE_TRANSACTION": {
|
17
|
+
"METHOD": Neo4jMethods.WRITE_TRANSACTION.value,
|
18
|
+
"OPERATION": "write_transaction",
|
19
|
+
},
|
20
|
+
"EXECUTE_READ": {
|
21
|
+
"METHOD": Neo4jMethods.EXECUTE_READ.value,
|
22
|
+
"OPERATION": "execute_read",
|
23
|
+
},
|
24
|
+
"EXECUTE_WRITE": {
|
25
|
+
"METHOD": Neo4jMethods.EXECUTE_WRITE.value,
|
26
|
+
"OPERATION": "execute_write",
|
27
|
+
},
|
28
|
+
"EXECUTE_QUERY": {
|
29
|
+
"METHOD": Neo4jMethods.EXECUTE_QUERY.value,
|
30
|
+
"OPERATION": "execute_query",
|
31
|
+
},
|
32
|
+
"TX_RUN": {
|
33
|
+
"METHOD": Neo4jMethods.TX_RUN.value,
|
34
|
+
"OPERATION": "tx_run",
|
35
|
+
},
|
36
|
+
}
|
@@ -22,6 +22,7 @@ from .litellm import LiteLLMInstrumentation
|
|
22
22
|
from .llamaindex import LlamaindexInstrumentation
|
23
23
|
from .milvus import MilvusInstrumentation
|
24
24
|
from .mistral import MistralInstrumentation
|
25
|
+
from .neo4j import Neo4jInstrumentation
|
25
26
|
from .neo4j_graphrag import Neo4jGraphRAGInstrumentation
|
26
27
|
from .ollama import OllamaInstrumentor
|
27
28
|
from .openai import OpenAIInstrumentation
|
@@ -21,7 +21,7 @@ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
21
21
|
from opentelemetry.trace import get_tracer
|
22
22
|
from wrapt import wrap_function_wrapper as _W
|
23
23
|
|
24
|
-
from .patch import patch_agent, patch_memory
|
24
|
+
from .patch import patch_agent, patch_memory, patch_team
|
25
25
|
|
26
26
|
|
27
27
|
class AgnoInstrumentation(BaseInstrumentor):
|
@@ -76,6 +76,27 @@ class AgnoInstrumentation(BaseInstrumentor):
|
|
76
76
|
patch_memory("AgentMemory.aupdate_summary", version, tracer),
|
77
77
|
)
|
78
78
|
|
79
|
+
_W(
|
80
|
+
"agno.team.team",
|
81
|
+
"Team.run",
|
82
|
+
patch_team("Team.run", version, tracer),
|
83
|
+
)
|
84
|
+
_W(
|
85
|
+
"agno.team.team",
|
86
|
+
"Team.arun",
|
87
|
+
patch_team("Team.arun", version, tracer),
|
88
|
+
)
|
89
|
+
_W(
|
90
|
+
"agno.team.team",
|
91
|
+
"Team._run",
|
92
|
+
patch_team("Team._run", version, tracer),
|
93
|
+
)
|
94
|
+
_W(
|
95
|
+
"agno.team.team",
|
96
|
+
"Team._arun",
|
97
|
+
patch_team("Team._arun", version, tracer),
|
98
|
+
)
|
99
|
+
|
79
100
|
except Exception:
|
80
101
|
pass
|
81
102
|
|
@@ -26,9 +26,7 @@ from opentelemetry.trace.status import Status, StatusCode
|
|
26
26
|
|
27
27
|
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
|
28
28
|
from langtrace_python_sdk.constants.instrumentation.common import (
|
29
|
-
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
30
|
-
SERVICE_PROVIDERS,
|
31
|
-
)
|
29
|
+
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY, SERVICE_PROVIDERS)
|
32
30
|
from langtrace_python_sdk.utils import set_span_attribute
|
33
31
|
from langtrace_python_sdk.utils.llm import get_span_name, set_span_attributes
|
34
32
|
from langtrace_python_sdk.utils.misc import serialize_args, serialize_kwargs
|
@@ -62,9 +60,9 @@ def patch_agent(operation_name, version, tracer: Tracer):
|
|
62
60
|
try:
|
63
61
|
set_span_attributes(span, attributes)
|
64
62
|
AgnoSpanAttributes(span=span, instance=instance)
|
65
|
-
|
63
|
+
|
66
64
|
result = wrapped(*args, **kwargs)
|
67
|
-
|
65
|
+
|
68
66
|
span.set_status(Status(StatusCode.OK))
|
69
67
|
|
70
68
|
if operation_name in ["Agent._run", "Agent._arun", "Agent.run", "Agent.arun", "Agent.print_response"]:
|
@@ -72,14 +70,14 @@ def patch_agent(operation_name, version, tracer: Tracer):
|
|
72
70
|
if hasattr(instance, "run_response") and instance.run_response:
|
73
71
|
if hasattr(instance.run_response, "run_id") and instance.run_response.run_id:
|
74
72
|
set_span_attribute(span, "agno.agent.run_id", instance.run_response.run_id)
|
75
|
-
|
73
|
+
|
76
74
|
if hasattr(instance.run_response, "created_at") and instance.run_response.created_at:
|
77
75
|
set_span_attribute(span, "agno.agent.timestamp", instance.run_response.created_at)
|
78
76
|
|
79
77
|
if hasattr(instance.run_response, "content") and instance.run_response.content:
|
80
78
|
content = str(instance.run_response.content)
|
81
79
|
set_span_attribute(span, "agno.agent.response_content", content)
|
82
|
-
|
80
|
+
|
83
81
|
# Capture any tools that were used
|
84
82
|
if hasattr(instance.run_response, "tools") and instance.run_response.tools:
|
85
83
|
tools = instance.run_response.tools
|
@@ -122,7 +120,7 @@ def patch_agent(operation_name, version, tracer: Tracer):
|
|
122
120
|
else:
|
123
121
|
set_span_attribute(span, "agno.agent.token_usage.input",
|
124
122
|
metrics['input_tokens'])
|
125
|
-
|
123
|
+
|
126
124
|
if 'output_tokens' in metrics:
|
127
125
|
if isinstance(metrics['output_tokens'], list) and metrics['output_tokens']:
|
128
126
|
set_span_attribute(span, "agno.agent.token_usage.output",
|
@@ -130,7 +128,7 @@ def patch_agent(operation_name, version, tracer: Tracer):
|
|
130
128
|
else:
|
131
129
|
set_span_attribute(span, "agno.agent.token_usage.output",
|
132
130
|
metrics['output_tokens'])
|
133
|
-
|
131
|
+
|
134
132
|
if 'total_tokens' in metrics:
|
135
133
|
if isinstance(metrics['total_tokens'], list) and metrics['total_tokens']:
|
136
134
|
set_span_attribute(span, "agno.agent.token_usage.total",
|
@@ -140,21 +138,21 @@ def patch_agent(operation_name, version, tracer: Tracer):
|
|
140
138
|
metrics['total_tokens'])
|
141
139
|
except Exception as err:
|
142
140
|
set_span_attribute(span, "agno.agent.run_response_error", str(err))
|
143
|
-
|
141
|
+
|
144
142
|
return result
|
145
|
-
|
143
|
+
|
146
144
|
except Exception as err:
|
147
145
|
span.record_exception(err)
|
148
146
|
span.set_status(Status(StatusCode.ERROR, str(err)))
|
149
147
|
raise
|
150
|
-
|
148
|
+
|
151
149
|
return traced_method
|
152
150
|
|
153
151
|
|
154
152
|
def patch_memory(operation_name, version, tracer: Tracer):
|
155
153
|
"""
|
156
154
|
Apply instrumentation patches to AgentMemory class methods.
|
157
|
-
|
155
|
+
|
158
156
|
Args:
|
159
157
|
operation_name: The name of the operation
|
160
158
|
version: The version of Agno
|
@@ -163,7 +161,7 @@ def patch_memory(operation_name, version, tracer: Tracer):
|
|
163
161
|
def traced_method(wrapped, instance, args, kwargs):
|
164
162
|
service_provider = SERVICE_PROVIDERS.get("AGNO", "agno")
|
165
163
|
extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
|
166
|
-
|
164
|
+
|
167
165
|
# Collect basic span attributes
|
168
166
|
span_attributes = {
|
169
167
|
"langtrace.sdk.name": "langtrace-python-sdk",
|
@@ -180,7 +178,7 @@ def patch_memory(operation_name, version, tracer: Tracer):
|
|
180
178
|
inputs["args"] = serialize_args(*args)
|
181
179
|
if len(kwargs) > 0:
|
182
180
|
inputs["kwargs"] = serialize_kwargs(**kwargs)
|
183
|
-
|
181
|
+
|
184
182
|
span_attributes["agno.memory.inputs"] = json.dumps(inputs)
|
185
183
|
|
186
184
|
if hasattr(instance, "messages"):
|
@@ -199,10 +197,10 @@ def patch_memory(operation_name, version, tracer: Tracer):
|
|
199
197
|
try:
|
200
198
|
# Set attributes
|
201
199
|
set_span_attributes(span, attributes)
|
202
|
-
|
200
|
+
|
203
201
|
# Execute the wrapped method
|
204
202
|
result = wrapped(*args, **kwargs)
|
205
|
-
|
203
|
+
|
206
204
|
# Add memory stats after operation
|
207
205
|
if hasattr(instance, "messages"):
|
208
206
|
set_span_attribute(span, "agno.memory.messages_count_after", len(instance.messages))
|
@@ -210,37 +208,153 @@ def patch_memory(operation_name, version, tracer: Tracer):
|
|
210
208
|
set_span_attribute(span, "agno.memory.runs_count_after", len(instance.runs))
|
211
209
|
if hasattr(instance, "memories") and instance.memories:
|
212
210
|
set_span_attribute(span, "agno.memory.memories_count_after", len(instance.memories))
|
213
|
-
|
211
|
+
|
214
212
|
# Record execution time
|
215
213
|
set_span_attribute(span, "agno.memory.execution_time_ms", int((time.time() - start_time) * 1000))
|
216
|
-
|
214
|
+
|
217
215
|
# Record success status
|
218
216
|
span.set_status(Status(StatusCode.OK))
|
219
|
-
|
217
|
+
|
220
218
|
# Add result if relevant
|
221
219
|
if result is not None:
|
222
220
|
set_span_attribute(span, "agno.memory.result", str(result))
|
223
|
-
|
221
|
+
|
224
222
|
return result
|
225
|
-
|
223
|
+
|
226
224
|
except Exception as err:
|
227
225
|
# Record the exception
|
228
226
|
span.record_exception(err)
|
229
227
|
span.set_status(Status(StatusCode.ERROR, str(err)))
|
230
228
|
raise
|
231
|
-
|
229
|
+
|
232
230
|
return traced_method
|
233
231
|
|
234
232
|
|
233
|
+
def patch_team(operation_name, version, tracer: Tracer):
|
234
|
+
def traced_method(wrapped, instance, args, kwargs):
|
235
|
+
service_provider = SERVICE_PROVIDERS.get("AGNO", "agno")
|
236
|
+
extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
|
237
|
+
|
238
|
+
span_attributes = {
|
239
|
+
"langtrace.sdk.name": "langtrace-python-sdk",
|
240
|
+
"langtrace.service.name": service_provider,
|
241
|
+
"langtrace.service.type": "framework",
|
242
|
+
"langtrace.service.version": version,
|
243
|
+
"langtrace.version": v(LANGTRACE_SDK_NAME),
|
244
|
+
**(extra_attributes if extra_attributes is not None else {}),
|
245
|
+
}
|
246
|
+
|
247
|
+
inputs = {}
|
248
|
+
if len(args) > 0:
|
249
|
+
inputs["args"] = serialize_args(*args)
|
250
|
+
if len(kwargs) > 0:
|
251
|
+
inputs["kwargs"] = serialize_kwargs(**kwargs)
|
252
|
+
span_attributes["agno.team.inputs"] = json.dumps(inputs)
|
253
|
+
attributes = FrameworkSpanAttributes(**span_attributes)
|
254
|
+
|
255
|
+
with tracer.start_as_current_span(
|
256
|
+
get_span_name(operation_name), kind=SpanKind.CLIENT
|
257
|
+
) as span:
|
258
|
+
try:
|
259
|
+
set_span_attributes(span, attributes)
|
260
|
+
AgnoSpanAttributes(span=span, instance=instance)
|
261
|
+
|
262
|
+
result = wrapped(*args, **kwargs)
|
263
|
+
|
264
|
+
span.set_status(Status(StatusCode.OK))
|
265
|
+
|
266
|
+
if operation_name in ["Team.run", "Team.arun", "Team._run", "Team._arun"]:
|
267
|
+
try:
|
268
|
+
if hasattr(instance, "run_response") and instance.run_response:
|
269
|
+
if hasattr(instance.run_response, "run_id") and instance.run_response.run_id:
|
270
|
+
set_span_attribute(span, "agno.team.run_id", instance.run_response.run_id)
|
271
|
+
|
272
|
+
if hasattr(instance.run_response, "created_at") and instance.run_response.created_at:
|
273
|
+
set_span_attribute(span, "agno.team.timestamp", instance.run_response.created_at)
|
274
|
+
|
275
|
+
if hasattr(instance.run_response, "content") and instance.run_response.content:
|
276
|
+
content = str(instance.run_response.content)
|
277
|
+
set_span_attribute(span, "agno.team.response_content", content)
|
278
|
+
|
279
|
+
# Capture any tools that were used
|
280
|
+
if hasattr(instance.run_response, "tools") and instance.run_response.tools:
|
281
|
+
tools = instance.run_response.tools
|
282
|
+
tool_summary = []
|
283
|
+
for tool in tools:
|
284
|
+
if 'tool_name' in tool:
|
285
|
+
tool_summary.append(tool['tool_name'])
|
286
|
+
elif 'function' in tool and 'name' in tool['function']:
|
287
|
+
tool_summary.append(tool['function']['name'])
|
288
|
+
set_span_attribute(span, "agno.team.tools_used", json.dumps(tool_summary))
|
289
|
+
|
290
|
+
if hasattr(instance.run_response, "metrics") and instance.run_response.metrics:
|
291
|
+
metrics = instance.run_response.metrics
|
292
|
+
for metric_name, metric_values in metrics.items():
|
293
|
+
if isinstance(metric_values, list):
|
294
|
+
|
295
|
+
if all(isinstance(v, (int, float)) for v in metric_values):
|
296
|
+
set_span_attribute(
|
297
|
+
span,
|
298
|
+
f"agno.team.metrics.{metric_name}",
|
299
|
+
sum(metric_values) / len(metric_values) if metric_values else 0
|
300
|
+
)
|
301
|
+
elif len(metric_values) > 0:
|
302
|
+
set_span_attribute(
|
303
|
+
span,
|
304
|
+
f"agno.team.metrics.{metric_name}",
|
305
|
+
str(metric_values[-1])
|
306
|
+
)
|
307
|
+
else:
|
308
|
+
set_span_attribute(
|
309
|
+
span,
|
310
|
+
f"agno.team.metrics.{metric_name}",
|
311
|
+
str(metric_values)
|
312
|
+
)
|
313
|
+
|
314
|
+
if 'input_tokens' in metrics:
|
315
|
+
if isinstance(metrics['input_tokens'], list) and metrics['input_tokens']:
|
316
|
+
set_span_attribute(span, "agno.team.token_usage.input",
|
317
|
+
sum(metrics['input_tokens']))
|
318
|
+
else:
|
319
|
+
set_span_attribute(span, "agno.team.token_usage.input",
|
320
|
+
metrics['input_tokens'])
|
321
|
+
|
322
|
+
if 'output_tokens' in metrics:
|
323
|
+
if isinstance(metrics['output_tokens'], list) and metrics['output_tokens']:
|
324
|
+
set_span_attribute(span, "agno.team.token_usage.output",
|
325
|
+
sum(metrics['output_tokens']))
|
326
|
+
else:
|
327
|
+
set_span_attribute(span, "agno.team.token_usage.output",
|
328
|
+
metrics['output_tokens'])
|
329
|
+
|
330
|
+
if 'total_tokens' in metrics:
|
331
|
+
if isinstance(metrics['total_tokens'], list) and metrics['total_tokens']:
|
332
|
+
set_span_attribute(span, "agno.team.token_usage.total",
|
333
|
+
sum(metrics['total_tokens']))
|
334
|
+
else:
|
335
|
+
set_span_attribute(span, "agno.team.token_usage.total",
|
336
|
+
metrics['total_tokens'])
|
337
|
+
except Exception as err:
|
338
|
+
set_span_attribute(span, "agno.team.run_response_error", str(err))
|
339
|
+
|
340
|
+
return result
|
341
|
+
|
342
|
+
except Exception as err:
|
343
|
+
span.record_exception(err)
|
344
|
+
span.set_status(Status(StatusCode.ERROR, str(err)))
|
345
|
+
raise
|
346
|
+
|
347
|
+
return traced_method
|
348
|
+
|
235
349
|
class AgnoSpanAttributes:
|
236
350
|
"""
|
237
351
|
Helper class to extract and set Agno Agent attributes on spans.
|
238
352
|
"""
|
239
|
-
|
353
|
+
|
240
354
|
def __init__(self, span: Span, instance: Any) -> None:
|
241
355
|
"""
|
242
356
|
Initialize with a span and Agno instance.
|
243
|
-
|
357
|
+
|
244
358
|
Args:
|
245
359
|
span: OpenTelemetry span to update
|
246
360
|
instance: Agno Agent instance
|
@@ -248,14 +362,14 @@ class AgnoSpanAttributes:
|
|
248
362
|
self.span = span
|
249
363
|
self.instance = instance
|
250
364
|
self.agent_data = {}
|
251
|
-
|
365
|
+
|
252
366
|
self.run()
|
253
|
-
|
367
|
+
|
254
368
|
def run(self) -> None:
|
255
369
|
"""Process the instance attributes and add them to the span."""
|
256
370
|
# Collect basic agent attributes
|
257
371
|
self.collect_agent_attributes()
|
258
|
-
|
372
|
+
|
259
373
|
# Add attributes to span
|
260
374
|
for key, value in self.agent_data.items():
|
261
375
|
if value is not None:
|
@@ -264,68 +378,68 @@ class AgnoSpanAttributes:
|
|
264
378
|
f"agno.agent.{key}",
|
265
379
|
str(value) if not isinstance(value, (int, float, bool)) else value
|
266
380
|
)
|
267
|
-
|
381
|
+
|
268
382
|
def collect_agent_attributes(self) -> None:
|
269
383
|
"""Collect important attributes from the Agent instance."""
|
270
384
|
# Extract basic agent information
|
271
385
|
if hasattr(self.instance, "agent_id"):
|
272
386
|
self.agent_data["id"] = self.instance.agent_id
|
273
|
-
|
387
|
+
|
274
388
|
if hasattr(self.instance, "name"):
|
275
389
|
self.agent_data["name"] = self.instance.name
|
276
|
-
|
390
|
+
|
277
391
|
if hasattr(self.instance, "session_id"):
|
278
392
|
self.agent_data["session_id"] = self.instance.session_id
|
279
|
-
|
393
|
+
|
280
394
|
if hasattr(self.instance, "user_id"):
|
281
395
|
self.agent_data["user_id"] = self.instance.user_id
|
282
|
-
|
396
|
+
|
283
397
|
if hasattr(self.instance, "run_id"):
|
284
398
|
self.agent_data["run_id"] = self.instance.run_id
|
285
|
-
|
286
|
-
|
399
|
+
|
400
|
+
# Extract model information
|
287
401
|
if hasattr(self.instance, "model") and self.instance.model:
|
288
402
|
model = self.instance.model
|
289
403
|
model_info = {}
|
290
|
-
|
404
|
+
|
291
405
|
if hasattr(model, "id"):
|
292
406
|
model_info["id"] = model.id
|
293
|
-
|
407
|
+
|
294
408
|
if hasattr(model, "name"):
|
295
409
|
model_info["name"] = model.name
|
296
|
-
|
410
|
+
|
297
411
|
if hasattr(model, "provider"):
|
298
412
|
model_info["provider"] = model.provider
|
299
|
-
|
413
|
+
|
300
414
|
# Add temperature if available
|
301
415
|
if hasattr(model, "temperature") and model.temperature is not None:
|
302
416
|
model_info["temperature"] = model.temperature
|
303
|
-
|
417
|
+
|
304
418
|
# Add max_tokens if available
|
305
419
|
if hasattr(model, "max_tokens") and model.max_tokens is not None:
|
306
420
|
model_info["max_tokens"] = model.max_tokens
|
307
|
-
|
421
|
+
|
308
422
|
self.agent_data["model"] = json.dumps(model_info)
|
309
|
-
|
423
|
+
|
310
424
|
# Extract tool information
|
311
425
|
if hasattr(self.instance, "tools") and self.instance.tools:
|
312
426
|
tool_info = []
|
313
427
|
for tool in self.instance.tools:
|
314
428
|
tool_data = {}
|
315
|
-
|
429
|
+
|
316
430
|
# Handle different types of tools
|
317
431
|
if hasattr(tool, "name"):
|
318
432
|
tool_data["name"] = tool.name
|
319
|
-
|
433
|
+
|
320
434
|
# Handle DuckDuckGoTools and similar toolkits
|
321
435
|
if hasattr(tool, "functions") and isinstance(tool.functions, dict):
|
322
436
|
tool_data["functions"] = list(tool.functions.keys())
|
323
|
-
|
437
|
+
|
324
438
|
elif hasattr(tool, "__name__"):
|
325
439
|
tool_data["name"] = tool.__name__
|
326
440
|
else:
|
327
441
|
tool_data["name"] = str(tool)
|
328
|
-
|
442
|
+
|
329
443
|
# Add functions if available
|
330
444
|
if not "functions" in tool_data and hasattr(tool, "functions"):
|
331
445
|
if callable(getattr(tool, "functions")):
|
@@ -336,28 +450,28 @@ class AgnoSpanAttributes:
|
|
336
450
|
for f in tool_functions]
|
337
451
|
except:
|
338
452
|
pass
|
339
|
-
|
453
|
+
|
340
454
|
tool_info.append(tool_data)
|
341
|
-
|
455
|
+
|
342
456
|
self.agent_data["tools"] = json.dumps(tool_info)
|
343
|
-
|
457
|
+
|
344
458
|
# Extract reasoning settings
|
345
459
|
if hasattr(self.instance, "reasoning") and self.instance.reasoning:
|
346
460
|
self.agent_data["reasoning_enabled"] = True
|
347
|
-
|
461
|
+
|
348
462
|
if hasattr(self.instance, "reasoning_model") and self.instance.reasoning_model:
|
349
463
|
self.agent_data["reasoning_model"] = str(self.instance.reasoning_model.id)
|
350
|
-
|
464
|
+
|
351
465
|
if hasattr(self.instance, "reasoning_min_steps"):
|
352
466
|
self.agent_data["reasoning_min_steps"] = self.instance.reasoning_min_steps
|
353
|
-
|
467
|
+
|
354
468
|
if hasattr(self.instance, "reasoning_max_steps"):
|
355
469
|
self.agent_data["reasoning_max_steps"] = self.instance.reasoning_max_steps
|
356
|
-
|
470
|
+
|
357
471
|
# Extract knowledge settings
|
358
472
|
if hasattr(self.instance, "knowledge") and self.instance.knowledge:
|
359
473
|
self.agent_data["knowledge_enabled"] = True
|
360
|
-
|
474
|
+
|
361
475
|
# Extract streaming settings
|
362
476
|
if hasattr(self.instance, "stream"):
|
363
|
-
self.agent_data["stream"] = self.instance.stream
|
477
|
+
self.agent_data["stream"] = self.instance.stream
|
@@ -8,7 +8,7 @@ from .patch import patch_google_genai, patch_google_genai_streaming
|
|
8
8
|
|
9
9
|
class GoogleGenaiInstrumentation(BaseInstrumentor):
|
10
10
|
def instrumentation_dependencies(self) -> Collection[str]:
|
11
|
-
return ["google-genai >= 0.1.0"
|
11
|
+
return ["google-genai >= 0.1.0"]
|
12
12
|
|
13
13
|
def _instrument(self, **kwargs):
|
14
14
|
trace_provider = kwargs.get("tracer_provider")
|
@@ -0,0 +1,51 @@
|
|
1
|
+
"""
|
2
|
+
Copyright (c) 2025 Scale3 Labs
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
"""
|
16
|
+
|
17
|
+
import importlib.metadata
|
18
|
+
import logging
|
19
|
+
from typing import Collection
|
20
|
+
|
21
|
+
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
22
|
+
from opentelemetry.trace import get_tracer
|
23
|
+
from wrapt import wrap_function_wrapper
|
24
|
+
|
25
|
+
from langtrace_python_sdk.constants.instrumentation.neo4j import APIS
|
26
|
+
from langtrace_python_sdk.instrumentation.neo4j.patch import driver_patch
|
27
|
+
|
28
|
+
logging.basicConfig(level=logging.FATAL)
|
29
|
+
|
30
|
+
|
31
|
+
class Neo4jInstrumentation(BaseInstrumentor):
|
32
|
+
"""
|
33
|
+
The Neo4jInstrumentation class represents the Neo4j graph database instrumentation
|
34
|
+
"""
|
35
|
+
|
36
|
+
def instrumentation_dependencies(self) -> Collection[str]:
|
37
|
+
return ["neo4j >= 5.25.0"]
|
38
|
+
|
39
|
+
def _instrument(self, **kwargs):
|
40
|
+
tracer_provider = kwargs.get("tracer_provider")
|
41
|
+
tracer = get_tracer(__name__, "", tracer_provider)
|
42
|
+
version = importlib.metadata.version("neo4j")
|
43
|
+
|
44
|
+
wrap_function_wrapper(
|
45
|
+
"neo4j._sync.driver",
|
46
|
+
"Driver.execute_query",
|
47
|
+
driver_patch("EXECUTE_QUERY", version, tracer),
|
48
|
+
)
|
49
|
+
|
50
|
+
def _uninstrument(self, **kwargs):
|
51
|
+
pass
|
@@ -0,0 +1,180 @@
|
|
1
|
+
"""
|
2
|
+
Copyright (c) 2025 Scale3 Labs
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
"""
|
16
|
+
|
17
|
+
import json
|
18
|
+
|
19
|
+
from langtrace_python_sdk.utils.llm import get_span_name
|
20
|
+
from langtrace_python_sdk.utils.silently_fail import silently_fail
|
21
|
+
from langtrace.trace_attributes import DatabaseSpanAttributes
|
22
|
+
from langtrace_python_sdk.utils import set_span_attribute
|
23
|
+
from opentelemetry import baggage, trace
|
24
|
+
from opentelemetry.trace import SpanKind
|
25
|
+
from opentelemetry.trace.status import Status, StatusCode
|
26
|
+
from opentelemetry.trace.propagation import set_span_in_context
|
27
|
+
|
28
|
+
from langtrace_python_sdk.constants.instrumentation.common import (
|
29
|
+
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
30
|
+
SERVICE_PROVIDERS,
|
31
|
+
)
|
32
|
+
from langtrace_python_sdk.constants.instrumentation.neo4j import APIS
|
33
|
+
from importlib.metadata import version as v
|
34
|
+
|
35
|
+
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
|
36
|
+
|
37
|
+
|
38
|
+
def driver_patch(operation_name, version, tracer):
|
39
|
+
def traced_method(wrapped, instance, args, kwargs):
|
40
|
+
|
41
|
+
api = APIS[operation_name]
|
42
|
+
service_provider = SERVICE_PROVIDERS.get("NEO4J", "neo4j")
|
43
|
+
extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
|
44
|
+
span_attributes = {
|
45
|
+
"langtrace.sdk.name": "langtrace-python-sdk",
|
46
|
+
"langtrace.service.name": service_provider,
|
47
|
+
"langtrace.service.type": "vectordb",
|
48
|
+
"langtrace.service.version": version,
|
49
|
+
"langtrace.version": v(LANGTRACE_SDK_NAME),
|
50
|
+
"db.system": "neo4j",
|
51
|
+
"db.operation": api["OPERATION"],
|
52
|
+
"db.query": json.dumps(args[0]) if args and len(args) > 0 else "",
|
53
|
+
**(extra_attributes if extra_attributes is not None else {}),
|
54
|
+
}
|
55
|
+
|
56
|
+
attributes = DatabaseSpanAttributes(**span_attributes)
|
57
|
+
|
58
|
+
with tracer.start_as_current_span(
|
59
|
+
name=get_span_name(api["METHOD"]),
|
60
|
+
kind=SpanKind.CLIENT,
|
61
|
+
context=set_span_in_context(trace.get_current_span()),
|
62
|
+
) as span:
|
63
|
+
for field, value in attributes.model_dump(by_alias=True).items():
|
64
|
+
if value is not None:
|
65
|
+
span.set_attribute(field, value)
|
66
|
+
|
67
|
+
if operation_name == "EXECUTE_QUERY":
|
68
|
+
_set_execute_query_attributes(span, args, kwargs)
|
69
|
+
|
70
|
+
try:
|
71
|
+
result = wrapped(*args, **kwargs)
|
72
|
+
|
73
|
+
if isinstance(result, tuple) and len(result) == 3:
|
74
|
+
records, result_summary, keys = result
|
75
|
+
_set_result_attributes(span, records, result_summary, keys)
|
76
|
+
else:
|
77
|
+
res = json.dumps(result)
|
78
|
+
set_span_attribute(span, "neo4j.result.query_response", res)
|
79
|
+
|
80
|
+
span.set_status(StatusCode.OK)
|
81
|
+
return result
|
82
|
+
except Exception as err:
|
83
|
+
span.record_exception(err)
|
84
|
+
span.set_status(Status(StatusCode.ERROR, str(err)))
|
85
|
+
raise
|
86
|
+
|
87
|
+
return traced_method
|
88
|
+
|
89
|
+
|
90
|
+
@silently_fail
|
91
|
+
def _set_execute_query_attributes(span, args, kwargs):
|
92
|
+
query = args[0] if args else kwargs.get("query_", None)
|
93
|
+
if query:
|
94
|
+
if hasattr(query, "text"):
|
95
|
+
set_span_attribute(span, "db.query", query.text)
|
96
|
+
if hasattr(query, "metadata") and query.metadata:
|
97
|
+
set_span_attribute(span, "db.query.metadata", json.dumps(query.metadata))
|
98
|
+
if hasattr(query, "timeout") and query.timeout:
|
99
|
+
set_span_attribute(span, "db.query.timeout", query.timeout)
|
100
|
+
else:
|
101
|
+
set_span_attribute(span, "db.query", query)
|
102
|
+
|
103
|
+
parameters = kwargs.get("parameters_", None)
|
104
|
+
if parameters:
|
105
|
+
try:
|
106
|
+
set_span_attribute(span, "db.statement.parameters", json.dumps(parameters))
|
107
|
+
except (TypeError, ValueError):
|
108
|
+
pass
|
109
|
+
|
110
|
+
database = kwargs.get("database_", None)
|
111
|
+
if database:
|
112
|
+
set_span_attribute(span, "neo4j.db.name", database)
|
113
|
+
|
114
|
+
routing = kwargs.get("routing_", None)
|
115
|
+
if routing:
|
116
|
+
set_span_attribute(span, "neo4j.db.routing", str(routing))
|
117
|
+
|
118
|
+
|
119
|
+
@silently_fail
|
120
|
+
def _set_result_attributes(span, records, result_summary, keys):
|
121
|
+
"""
|
122
|
+
Set attributes related to the query result and summary
|
123
|
+
"""
|
124
|
+
if records is not None:
|
125
|
+
record_count = len(records)
|
126
|
+
set_span_attribute(span, "neo4j.result.record_count", record_count)
|
127
|
+
if record_count > 0:
|
128
|
+
set_span_attribute(span, "neo4j.result.records", json.dumps(records))
|
129
|
+
|
130
|
+
if keys is not None:
|
131
|
+
set_span_attribute(span, "neo4j.result.keys", json.dumps(keys))
|
132
|
+
|
133
|
+
if result_summary:
|
134
|
+
if hasattr(result_summary, "database") and result_summary.database:
|
135
|
+
set_span_attribute(span, "neo4j.db.name", result_summary.database)
|
136
|
+
|
137
|
+
if hasattr(result_summary, "query_type") and result_summary.query_type:
|
138
|
+
set_span_attribute(span, "neo4j.result.query_type", result_summary.query_type)
|
139
|
+
|
140
|
+
if hasattr(result_summary, "parameters") and result_summary.parameters:
|
141
|
+
try:
|
142
|
+
set_span_attribute(span, "neo4j.result.parameters", json.dumps(result_summary.parameters))
|
143
|
+
except (TypeError, ValueError):
|
144
|
+
pass
|
145
|
+
|
146
|
+
if hasattr(result_summary, "result_available_after") and result_summary.result_available_after is not None:
|
147
|
+
set_span_attribute(span, "neo4j.result.available_after_ms", result_summary.result_available_after)
|
148
|
+
|
149
|
+
if hasattr(result_summary, "result_consumed_after") and result_summary.result_consumed_after is not None:
|
150
|
+
set_span_attribute(span, "neo4j.result.consumed_after_ms", result_summary.result_consumed_after)
|
151
|
+
|
152
|
+
if hasattr(result_summary, "counters") and result_summary.counters:
|
153
|
+
counters = result_summary.counters
|
154
|
+
if hasattr(counters, "nodes_created") and counters.nodes_created:
|
155
|
+
set_span_attribute(span, "neo4j.result.nodes_created", counters.nodes_created)
|
156
|
+
|
157
|
+
if hasattr(counters, "nodes_deleted") and counters.nodes_deleted:
|
158
|
+
set_span_attribute(span, "neo4j.result.nodes_deleted", counters.nodes_deleted)
|
159
|
+
|
160
|
+
if hasattr(counters, "relationships_created") and counters.relationships_created:
|
161
|
+
set_span_attribute(span, "neo4j.result.relationships_created", counters.relationships_created)
|
162
|
+
|
163
|
+
if hasattr(counters, "relationships_deleted") and counters.relationships_deleted:
|
164
|
+
set_span_attribute(span, "neo4j.result.relationships_deleted", counters.relationships_deleted)
|
165
|
+
|
166
|
+
if hasattr(counters, "properties_set") and counters.properties_set:
|
167
|
+
set_span_attribute(span, "neo4j.result.properties_set", counters.properties_set)
|
168
|
+
|
169
|
+
if hasattr(result_summary, "plan") and result_summary.plan:
|
170
|
+
try:
|
171
|
+
set_span_attribute(span, "neo4j.result.plan", json.dumps(result_summary.plan))
|
172
|
+
except (TypeError, ValueError):
|
173
|
+
pass
|
174
|
+
|
175
|
+
if hasattr(result_summary, "notifications") and result_summary.notifications:
|
176
|
+
try:
|
177
|
+
set_span_attribute(span, "neo4j.result.notification_count", len(result_summary.notifications))
|
178
|
+
set_span_attribute(span, "neo4j.result.notifications", json.dumps(result_summary.notifications))
|
179
|
+
except (AttributeError, TypeError):
|
180
|
+
pass
|
@@ -26,9 +26,7 @@ from opentelemetry.trace.status import Status, StatusCode
|
|
26
26
|
|
27
27
|
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
|
28
28
|
from langtrace_python_sdk.constants.instrumentation.common import (
|
29
|
-
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
30
|
-
SERVICE_PROVIDERS,
|
31
|
-
)
|
29
|
+
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY, SERVICE_PROVIDERS)
|
32
30
|
from langtrace_python_sdk.constants.instrumentation.weaviate import APIS
|
33
31
|
from langtrace_python_sdk.utils.llm import get_span_name
|
34
32
|
from langtrace_python_sdk.utils.misc import extract_input_params, to_iso_format
|
@@ -53,6 +51,8 @@ def extract_inputs(args, kwargs):
|
|
53
51
|
for k, v in kwargs.items()
|
54
52
|
if k not in ["properties", "fusion_type", "filters"]
|
55
53
|
}
|
54
|
+
# don't include vector in kwargs_without_properties
|
55
|
+
kwargs_without_properties.pop("vector", None)
|
56
56
|
extracted_params.update(extract_input_params(args, kwargs_without_properties))
|
57
57
|
if kwargs.get("filters", None):
|
58
58
|
extracted_params["filters"] = str(kwargs["filters"])
|
@@ -109,7 +109,7 @@ def get_response_object_attributes(response_object):
|
|
109
109
|
**{k: convert_value(v) for k, v in response_object.properties.items()},
|
110
110
|
"uuid": str(response_object.uuid) if hasattr(response_object, "uuid") else None,
|
111
111
|
"collection": getattr(response_object, "collection", None),
|
112
|
-
"vector": getattr(response_object, "vector", None),
|
112
|
+
# "vector": getattr(response_object, "vector", None),
|
113
113
|
"references": getattr(response_object, "references", None),
|
114
114
|
"metadata": (
|
115
115
|
extract_metadata(response_object.metadata)
|
@@ -47,9 +47,9 @@ from langtrace_python_sdk.instrumentation import (
|
|
47
47
|
CrewaiToolsInstrumentation, DspyInstrumentation, EmbedchainInstrumentation,
|
48
48
|
GeminiInstrumentation, GoogleGenaiInstrumentation, GraphlitInstrumentation,
|
49
49
|
GroqInstrumentation, LangchainCommunityInstrumentation,
|
50
|
-
LangchainCoreInstrumentation, LangchainInstrumentation,
|
51
|
-
|
52
|
-
|
50
|
+
LangchainCoreInstrumentation, LangchainInstrumentation, LanggraphInstrumentation,
|
51
|
+
LiteLLMInstrumentation, LlamaindexInstrumentation, MilvusInstrumentation,
|
52
|
+
MistralInstrumentation, Neo4jInstrumentation, Neo4jGraphRAGInstrumentation,
|
53
53
|
OllamaInstrumentor, OpenAIAgentsInstrumentation, OpenAIInstrumentation,
|
54
54
|
PhiDataInstrumentation, PineconeInstrumentation, PyMongoInstrumentation,
|
55
55
|
QdrantInstrumentation, VertexAIInstrumentation, WeaviateInstrumentation)
|
@@ -284,6 +284,7 @@ def init(
|
|
284
284
|
"phidata": PhiDataInstrumentation(),
|
285
285
|
"agno": AgnoInstrumentation(),
|
286
286
|
"mistralai": MistralInstrumentation(),
|
287
|
+
"neo4j": Neo4jInstrumentation(),
|
287
288
|
"neo4j-graphrag": Neo4jGraphRAGInstrumentation(),
|
288
289
|
"boto3": AWSBedrockInstrumentation(),
|
289
290
|
"autogen": AutogenInstrumentation(),
|
@@ -14,25 +14,24 @@ See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
15
15
|
"""
|
16
16
|
|
17
|
+
import json
|
18
|
+
import os
|
17
19
|
from typing import Any, Dict, Union
|
18
|
-
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
|
19
|
-
from langtrace_python_sdk.utils import set_span_attribute
|
20
|
-
from langtrace_python_sdk.types import NOT_GIVEN
|
21
|
-
from tiktoken import get_encoding, list_encoding_names
|
22
20
|
|
23
|
-
from langtrace_python_sdk.constants.instrumentation.common import (
|
24
|
-
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
25
|
-
TIKTOKEN_MODEL_MAPPING,
|
26
|
-
)
|
27
|
-
from langtrace_python_sdk.constants.instrumentation.openai import OPENAI_COST_TABLE
|
28
|
-
from langtrace.trace_attributes import SpanAttributes
|
29
21
|
from importlib_metadata import version as v
|
30
|
-
import
|
22
|
+
from langtrace.trace_attributes import SpanAttributes
|
31
23
|
from opentelemetry import baggage
|
32
24
|
from opentelemetry.trace import Span
|
33
25
|
from opentelemetry.trace.status import StatusCode
|
26
|
+
from tiktoken import get_encoding, list_encoding_names
|
34
27
|
|
35
|
-
import
|
28
|
+
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
|
29
|
+
from langtrace_python_sdk.constants.instrumentation.common import (
|
30
|
+
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY, TIKTOKEN_MODEL_MAPPING)
|
31
|
+
from langtrace_python_sdk.constants.instrumentation.openai import \
|
32
|
+
OPENAI_COST_TABLE
|
33
|
+
from langtrace_python_sdk.types import NOT_GIVEN
|
34
|
+
from langtrace_python_sdk.utils import set_span_attribute
|
36
35
|
|
37
36
|
|
38
37
|
def get_span_name(operation_name):
|
@@ -437,7 +436,6 @@ class StreamWrapper:
|
|
437
436
|
"".join(self.result_content), response_model
|
438
437
|
)
|
439
438
|
if self._span_started:
|
440
|
-
print("SPAAN", self.span)
|
441
439
|
set_span_attribute(
|
442
440
|
self.span,
|
443
441
|
SpanAttributes.LLM_RESPONSE_MODEL,
|
langtrace_python_sdk/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "3.8.
|
1
|
+
__version__ = "3.8.10"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: langtrace-python-sdk
|
3
|
-
Version: 3.8.
|
3
|
+
Version: 3.8.10
|
4
4
|
Summary: Python SDK for LangTrace
|
5
5
|
Project-URL: Homepage, https://github.com/Scale3-Labs/langtrace-python-sdk
|
6
6
|
Author-email: Scale3 Labs <engineering@scale3labs.com>
|
@@ -23,7 +23,7 @@ Requires-Dist: sentry-sdk>=2.14.0
|
|
23
23
|
Requires-Dist: setuptools
|
24
24
|
Requires-Dist: sqlalchemy
|
25
25
|
Requires-Dist: tiktoken>=0.1.1
|
26
|
-
Requires-Dist: trace-attributes==7.2.
|
26
|
+
Requires-Dist: trace-attributes==7.2.1
|
27
27
|
Requires-Dist: transformers>=4.11.3
|
28
28
|
Requires-Dist: ujson>=5.10.0
|
29
29
|
Provides-Extra: dev
|
@@ -83,6 +83,11 @@ examples/mistral_example/complete.py,sha256=Ydf5iOCGM2tySSd5vzGvNh3Qz39aTpxcCItB
|
|
83
83
|
examples/mistral_example/complete_async.py,sha256=-SVOLNLNi5JL3o4obBsCXKOt8A6b61j3otbrrYPOOtM,586
|
84
84
|
examples/mistral_example/embeddings.py,sha256=LKq_k3Y-TS2SCkyFKw2tLiYreVRHqlY6z0Gfh1y_7u0,468
|
85
85
|
examples/mongo_vector_search_example/main.py,sha256=6bHOxR3LfAZwmGmv74jgNCciATS5h5e-Tb5z0cD0z3Q,1542
|
86
|
+
examples/neo4j_example/__init__.py,sha256=YG7-_cQnXt-fJQtH2bJu_uSNyVCmYyUevU4H-GML_Sk,200
|
87
|
+
examples/neo4j_example/basic.py,sha256=xw5fNi5y-U5wzrVIsnvbKBZDURUzoYriawu6nyEXi3o,780
|
88
|
+
examples/neo4j_graphrag_example/__init__.py,sha256=YCXutcM3otTKEff1S3qTciFBxOMrQw7mQ4WGfJ7-mU8,230
|
89
|
+
examples/neo4j_graphrag_example/basic.py,sha256=uYf4O8bT3GkU5Qa-tluEr9sYTm5gjdzHAKf-C8bi5GY,1727
|
90
|
+
examples/neo4j_graphrag_example/data/abramov.pdf,sha256=Fm93bGdz74PJel-Dw_wZeuqqedloTTZiOakIWLzYDPA,46933
|
86
91
|
examples/ollama_example/__init__.py,sha256=qOx0jGCPuSpRCPiqtDVm7F0z8hIZ8C75hDZ_C8Apz-s,399
|
87
92
|
examples/ollama_example/basic.py,sha256=EPbsigOF4xBDBgLgAD0EzPo737ycVm7aXZr7F5Xt-A4,1062
|
88
93
|
examples/openai_example/__init__.py,sha256=6faH7wTegSozKmS89sd1Tgv8AcEH0GfKkC7YaBWA8tg,849
|
@@ -115,8 +120,8 @@ examples/vertexai_example/main.py,sha256=gndId5X5ksD-ycxnAWMdEqIDbLc3kz5Vt8vm4YP
|
|
115
120
|
examples/weaviate_example/__init__.py,sha256=8JMDBsRSEV10HfTd-YC7xb4txBjD3la56snk-Bbg2Kw,618
|
116
121
|
examples/weaviate_example/query_text.py,sha256=wPHQTc_58kPoKTZMygVjTj-2ZcdrIuaausJfMxNQnQc,127162
|
117
122
|
langtrace_python_sdk/__init__.py,sha256=VZM6i71NR7pBQK6XvJWRelknuTYUhqwqE7PlicKa5Wg,1166
|
118
|
-
langtrace_python_sdk/langtrace.py,sha256=
|
119
|
-
langtrace_python_sdk/version.py,sha256=
|
123
|
+
langtrace_python_sdk/langtrace.py,sha256=P7aHGunNP8YQqd2glsVLXhSe4QDeAarfG2eCV9hhAm4,13944
|
124
|
+
langtrace_python_sdk/version.py,sha256=Sz-5SfPXsiZbJO0dp0pVWeIm92HyINLVnoY9zyB3FQI,23
|
120
125
|
langtrace_python_sdk/constants/__init__.py,sha256=3CNYkWMdd1DrkGqzLUgNZXjdAlM6UFMlf_F-odAToyc,146
|
121
126
|
langtrace_python_sdk/constants/exporter/langtrace_exporter.py,sha256=EVCrouYCpY98f0KSaKr4PzNxPULTZZO6dSA_crEOyJU,106
|
122
127
|
langtrace_python_sdk/constants/instrumentation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -131,6 +136,7 @@ langtrace_python_sdk/constants/instrumentation/groq.py,sha256=VFXmIl4aqGY_fS0PAm
|
|
131
136
|
langtrace_python_sdk/constants/instrumentation/litellm.py,sha256=bMAlpY2scFe6Lql0Nl7euGNSO9QEV5Uzne12hnw3mSE,449
|
132
137
|
langtrace_python_sdk/constants/instrumentation/milvus.py,sha256=lnl7RtV2Wc66mEmtVMjV5eWalt-caH4-sQEHpN1LmEE,1029
|
133
138
|
langtrace_python_sdk/constants/instrumentation/mistral.py,sha256=9PlmcC5P5_BHJ-zsX1xekht6rSm7arTin58HAfdYvLk,730
|
139
|
+
langtrace_python_sdk/constants/instrumentation/neo4j.py,sha256=-coUUCiroN2shr_C-HcWPYPmEcjIz1CQpaXtZo2uVFU,1002
|
134
140
|
langtrace_python_sdk/constants/instrumentation/ollama.py,sha256=H_-S0xjqRsi5qSp7mAlK7Y9NlQ3BqOkG6ASogqqgdJY,212
|
135
141
|
langtrace_python_sdk/constants/instrumentation/openai.py,sha256=uEOH5UXapU2DSf2AdgXTRhhJEHGWXUNFkUGD5QafflM,1164
|
136
142
|
langtrace_python_sdk/constants/instrumentation/pinecone.py,sha256=0TityERbGWaHGSN8-vyYZtYCjVj8fQOKae8lng0O0Bk,478
|
@@ -141,10 +147,10 @@ langtrace_python_sdk/constants/instrumentation/weaviate.py,sha256=gtv-JBxvNGClEM
|
|
141
147
|
langtrace_python_sdk/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
142
148
|
langtrace_python_sdk/extensions/langtrace_exporter.py,sha256=ckd8dMmY6h2oxE04p1JFLwUB5PSJX_Cy4eDFEM6aj4Y,6605
|
143
149
|
langtrace_python_sdk/extensions/langtrace_filesystem.py,sha256=34fZutG28EJ66l67OvTGsydAH3ZpXgikdE7hVLqBpG4,7863
|
144
|
-
langtrace_python_sdk/instrumentation/__init__.py,sha256=
|
150
|
+
langtrace_python_sdk/instrumentation/__init__.py,sha256=sUVSZtidQev87AspZmWK4M8J51mBnJXXNDwfBsl_Dcs,2692
|
145
151
|
langtrace_python_sdk/instrumentation/agno/__init__.py,sha256=95fn4oA-CHB0mxc6KnVB20KSbXGl_ZZr9n99EEaXzrY,91
|
146
|
-
langtrace_python_sdk/instrumentation/agno/instrumentation.py,sha256=
|
147
|
-
langtrace_python_sdk/instrumentation/agno/patch.py,sha256=
|
152
|
+
langtrace_python_sdk/instrumentation/agno/instrumentation.py,sha256=DWOIEl9Q4IhCFgFQPW3pILdVq_C0RJiaGm_diZ73XJU,3284
|
153
|
+
langtrace_python_sdk/instrumentation/agno/patch.py,sha256=wHMDNiH-XOUTnqC6HKGGbYOp04R8DG2xJqm9Ex_h9AE,22868
|
148
154
|
langtrace_python_sdk/instrumentation/anthropic/__init__.py,sha256=donrurJAGYlxrSRA3BIf76jGeUcAx9Tq8CVpah68S0Y,101
|
149
155
|
langtrace_python_sdk/instrumentation/anthropic/instrumentation.py,sha256=ndXdruI0BG7n75rsuEpKjfzePxrZxg40gZ39ONmD_v4,1845
|
150
156
|
langtrace_python_sdk/instrumentation/anthropic/patch.py,sha256=ztPN4VZujoxYOKhTbFnup7Ibms9NAzYCPAJY43NUgKw,4935
|
@@ -185,7 +191,7 @@ langtrace_python_sdk/instrumentation/gemini/__init__.py,sha256=ilWmKA4Li-g3DX6R1
|
|
185
191
|
langtrace_python_sdk/instrumentation/gemini/instrumentation.py,sha256=eGWr2dy1f_9TVZiXSH_MlNQINyS4I28EsOTKREdMVio,1304
|
186
192
|
langtrace_python_sdk/instrumentation/gemini/patch.py,sha256=PG5E5v253x2ufQ81-aUUFzDRYq-DDhiqwmNoplHPjsM,6261
|
187
193
|
langtrace_python_sdk/instrumentation/google_genai/__init__.py,sha256=nQ2kSsUDpLGZ_kz2QGddDwnawL9juVA7pW4G-BOe5VI,98
|
188
|
-
langtrace_python_sdk/instrumentation/google_genai/instrumentation.py,sha256=
|
194
|
+
langtrace_python_sdk/instrumentation/google_genai/instrumentation.py,sha256=rSB3nOXXe4gMVPWMGPnIHvWjqyPeRvifxOI62ulJ7uY,1049
|
189
195
|
langtrace_python_sdk/instrumentation/google_genai/patch.py,sha256=X0TWY1D4XHweaNu70PlXBDzKEaHIibLpkJiIsp4jF6A,4115
|
190
196
|
langtrace_python_sdk/instrumentation/graphlit/__init__.py,sha256=mkUPwozR-I-D5ZrumJs1gS7sSouY0UN68Ne9LiNEBTs,92
|
191
197
|
langtrace_python_sdk/instrumentation/graphlit/instrumentation.py,sha256=V9GRZ6cj2lt20xCVfL55lGU4p0HlZxAYUqwpWogXDtY,2074
|
@@ -218,6 +224,9 @@ langtrace_python_sdk/instrumentation/milvus/patch.py,sha256=0yY5aQz0x7hpQZ8U-0qf
|
|
218
224
|
langtrace_python_sdk/instrumentation/mistral/__init__.py,sha256=mkGALBQvq0jSfwDl6TU09SFwnVs6O4zkUi-yVmd3SNg,90
|
219
225
|
langtrace_python_sdk/instrumentation/mistral/instrumentation.py,sha256=qtCkHCSOaiicUChbmTID4lcK1rbeW8oRSbpda2ogbgM,2328
|
220
226
|
langtrace_python_sdk/instrumentation/mistral/patch.py,sha256=5EzqMeIEcMUH8P-l9-ijpRNWSc6mYwe9Gz0VY4PLrS0,6559
|
227
|
+
langtrace_python_sdk/instrumentation/neo4j/__init__.py,sha256=6pG7SKOSKENaFEsstMJ4ZUH9wUP53JdQKdjHzJ4Lbko,86
|
228
|
+
langtrace_python_sdk/instrumentation/neo4j/instrumentation.py,sha256=KECuFv7OuVBgh_NTZl4_W18GAGbKnaeQqRZM8NPZgjU,1668
|
229
|
+
langtrace_python_sdk/instrumentation/neo4j/patch.py,sha256=wPAxslFdsHdYU5k1nHzWAqaHxQA-HhxgfVnb_U5qaZ0,7922
|
221
230
|
langtrace_python_sdk/instrumentation/neo4j_graphrag/__init__.py,sha256=K-Qpfh-kn2EPxnYZ_oubLZNqAUO9Cx7mnMrJu_ms3UU,102
|
222
231
|
langtrace_python_sdk/instrumentation/neo4j_graphrag/instrumentation.py,sha256=FLnddPSozuu5puqYD_FnXLMFet8YToVdWP-cY5QZrvM,2216
|
223
232
|
langtrace_python_sdk/instrumentation/neo4j_graphrag/patch.py,sha256=4c7NKcTJeYsbi5V4aSsuPzTiFoBqtlcXmYx2bMlE7qg,9713
|
@@ -248,11 +257,11 @@ langtrace_python_sdk/instrumentation/vertexai/instrumentation.py,sha256=yz4trw0B
|
|
248
257
|
langtrace_python_sdk/instrumentation/vertexai/patch.py,sha256=PzBio8x6zdVpX286TKtaTR-sf1HCHQ7RrdvpyNaGk4Q,5571
|
249
258
|
langtrace_python_sdk/instrumentation/weaviate/__init__.py,sha256=Mc-Je6evPo-kKQzerTG7bd1XO5JOh4YGTE3wBxaUBwg,99
|
250
259
|
langtrace_python_sdk/instrumentation/weaviate/instrumentation.py,sha256=Kwq5QQTUQNRHrWrMnNe9X0TcqtXGiNpBidsuToRTqG0,2417
|
251
|
-
langtrace_python_sdk/instrumentation/weaviate/patch.py,sha256=
|
260
|
+
langtrace_python_sdk/instrumentation/weaviate/patch.py,sha256=igqYUR_bEjs1XtyyZ8z3N2Eb3pbtjb6gqeEhVtnLKxw,7036
|
252
261
|
langtrace_python_sdk/types/__init__.py,sha256=SJSJzkgPjGGTVJXUZ_FyR3p9DJ5kWGx7iAnJfY4ZYHU,4669
|
253
262
|
langtrace_python_sdk/utils/__init__.py,sha256=VVDOG-QLd59ZvSHp0avjof0sbxlZ1QQOf0KoOF7ofhQ,3310
|
254
263
|
langtrace_python_sdk/utils/langtrace_sampler.py,sha256=BupNndHbU9IL_wGleKetz8FdcveqHMBVz1bfKTTW80w,1753
|
255
|
-
langtrace_python_sdk/utils/llm.py,sha256=
|
264
|
+
langtrace_python_sdk/utils/llm.py,sha256=UOPgt8OcOyjBiBEtxWGYBVLg9EfVCBLyusgcVwLr8Us,23425
|
256
265
|
langtrace_python_sdk/utils/misc.py,sha256=LaQr5LOmZMiuwVdjYh7aIu6o2C_Xb1wgpQGNOVmRzfE,1918
|
257
266
|
langtrace_python_sdk/utils/prompt_registry.py,sha256=n5dQMVLBw8aJZY8Utvf67bncc25ELf6AH9BYw8_hSzo,2619
|
258
267
|
langtrace_python_sdk/utils/sdk_version_checker.py,sha256=F-VVVH7Fmhr5LcY0IIe-34zIi5RQcx26uuxFpPzZesM,1782
|
@@ -303,8 +312,8 @@ tests/pinecone/cassettes/test_query.yaml,sha256=b5v9G3ssUy00oG63PlFUR3JErF2Js-5A
|
|
303
312
|
tests/pinecone/cassettes/test_upsert.yaml,sha256=neWmQ1v3d03V8WoLl8FoFeeCYImb8pxlJBWnFd_lITU,38607
|
304
313
|
tests/qdrant/conftest.py,sha256=9n0uHxxIjWk9fbYc4bx-uP8lSAgLBVx-cV9UjnsyCHM,381
|
305
314
|
tests/qdrant/test_qdrant.py,sha256=pzjAjVY2kmsmGfrI2Gs2xrolfuaNHz7l1fqGQCjp5_o,3353
|
306
|
-
langtrace_python_sdk-3.8.
|
307
|
-
langtrace_python_sdk-3.8.
|
308
|
-
langtrace_python_sdk-3.8.
|
309
|
-
langtrace_python_sdk-3.8.
|
310
|
-
langtrace_python_sdk-3.8.
|
315
|
+
langtrace_python_sdk-3.8.10.dist-info/METADATA,sha256=-4u_t1c_jWQZ_yk1oIedRtGD9L5gCxcUbJBwfwTbfh0,15845
|
316
|
+
langtrace_python_sdk-3.8.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
317
|
+
langtrace_python_sdk-3.8.10.dist-info/entry_points.txt,sha256=1_b9-qvf2fE7uQNZcbUei9vLpFZBbbh9LrtGw95ssAo,70
|
318
|
+
langtrace_python_sdk-3.8.10.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
319
|
+
langtrace_python_sdk-3.8.10.dist-info/RECORD,,
|
File without changes
|
{langtrace_python_sdk-3.8.8.dist-info → langtrace_python_sdk-3.8.10.dist-info}/entry_points.txt
RENAMED
File without changes
|
{langtrace_python_sdk-3.8.8.dist-info → langtrace_python_sdk-3.8.10.dist-info}/licenses/LICENSE
RENAMED
File without changes
|