langtrace-python-sdk 3.3.11__py3-none-any.whl → 3.3.13__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/langgraph_example/main.py +173 -0
- langtrace_python_sdk/instrumentation/crewai/patch.py +1 -1
- langtrace_python_sdk/instrumentation/dspy/instrumentation.py +2 -2
- langtrace_python_sdk/instrumentation/langgraph/instrumentation.py +14 -19
- langtrace_python_sdk/instrumentation/langgraph/patch.py +2 -3
- langtrace_python_sdk/langtrace.py +1 -1
- langtrace_python_sdk/version.py +1 -1
- {langtrace_python_sdk-3.3.11.dist-info → langtrace_python_sdk-3.3.13.dist-info}/METADATA +1 -1
- {langtrace_python_sdk-3.3.11.dist-info → langtrace_python_sdk-3.3.13.dist-info}/RECORD +12 -11
- {langtrace_python_sdk-3.3.11.dist-info → langtrace_python_sdk-3.3.13.dist-info}/WHEEL +0 -0
- {langtrace_python_sdk-3.3.11.dist-info → langtrace_python_sdk-3.3.13.dist-info}/entry_points.txt +0 -0
- {langtrace_python_sdk-3.3.11.dist-info → langtrace_python_sdk-3.3.13.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,173 @@
|
|
1
|
+
from typing import TypedDict, Union, Annotated
|
2
|
+
from langchain_core.agents import AgentAction, AgentFinish
|
3
|
+
from langchain_core.tools import tool
|
4
|
+
import operator
|
5
|
+
from dotenv import load_dotenv
|
6
|
+
from langchain_openai import ChatOpenAI
|
7
|
+
|
8
|
+
from langchain import hub
|
9
|
+
from langchain.agents import create_openai_tools_agent
|
10
|
+
import json
|
11
|
+
from langgraph.graph import StateGraph, END
|
12
|
+
from langtrace_python_sdk import langtrace, with_langtrace_root_span
|
13
|
+
|
14
|
+
load_dotenv()
|
15
|
+
|
16
|
+
langtrace.init(write_spans_to_console=False)
|
17
|
+
|
18
|
+
|
19
|
+
class AgentState(TypedDict):
|
20
|
+
input: str
|
21
|
+
agent_out: Union[AgentAction, AgentFinish, None]
|
22
|
+
intermediate_steps: Annotated[list[tuple[AgentAction, str]], operator.add]
|
23
|
+
|
24
|
+
|
25
|
+
ehi_information = """Title: EHI: End-to-end Learning of Hierarchical Index for
|
26
|
+
Efficient Dense Retrieval
|
27
|
+
Summary: Dense embedding-based retrieval is now the industry
|
28
|
+
standard for semantic search and ranking problems, like obtaining relevant web
|
29
|
+
documents for a given query. Such techniques use a two-stage process: (a)
|
30
|
+
contrastive learning to train a dual encoder to embed both the query and
|
31
|
+
documents and (b) approximate nearest neighbor search (ANNS) for finding similar
|
32
|
+
documents for a given query. These two stages are disjoint; the learned
|
33
|
+
embeddings might be ill-suited for the ANNS method and vice-versa, leading to
|
34
|
+
suboptimal performance. In this work, we propose End-to-end Hierarchical
|
35
|
+
Indexing -- EHI -- that jointly learns both the embeddings and the ANNS
|
36
|
+
structure to optimize retrieval performance. EHI uses a standard dual encoder
|
37
|
+
model for embedding queries and documents while learning an inverted file index
|
38
|
+
(IVF) style tree structure for efficient ANNS. To ensure stable and efficient
|
39
|
+
learning of discrete tree-based ANNS structure, EHI introduces the notion of
|
40
|
+
dense path embedding that captures the position of a query/document in the tree.
|
41
|
+
We demonstrate the effectiveness of EHI on several benchmarks, including
|
42
|
+
de-facto industry standard MS MARCO (Dev set and TREC DL19) datasets. For
|
43
|
+
example, with the same compute budget, EHI outperforms state-of-the-art (SOTA)
|
44
|
+
in by 0.6% (MRR@10) on MS MARCO dev set and by 4.2% (nDCG@10) on TREC DL19
|
45
|
+
benchmarks.
|
46
|
+
Author(s): Ramnath Kumar, Anshul Mittal, Nilesh Gupta, Aditya Kusupati,
|
47
|
+
Inderjit Dhillon, Prateek Jain
|
48
|
+
Source: https://arxiv.org/pdf/2310.08891.pdf"""
|
49
|
+
|
50
|
+
|
51
|
+
@tool("search")
|
52
|
+
def search_tool(query: str):
|
53
|
+
"""Searches for information on the topic of artificial intelligence (AI).
|
54
|
+
Cannot be used to research any other topics. Search query must be provided
|
55
|
+
in natural language and be verbose."""
|
56
|
+
# this is a "RAG" emulator
|
57
|
+
return ehi_information
|
58
|
+
|
59
|
+
|
60
|
+
@tool("final_answer")
|
61
|
+
def final_answer_tool(answer: str, source: str):
|
62
|
+
"""Returns a natural language response to the user in `answer`, and a
|
63
|
+
`source` which provides citations for where this information came from.
|
64
|
+
"""
|
65
|
+
return ""
|
66
|
+
|
67
|
+
|
68
|
+
llm = ChatOpenAI()
|
69
|
+
prompt = hub.pull("hwchase17/openai-functions-agent")
|
70
|
+
|
71
|
+
|
72
|
+
query_agent_runnable = create_openai_tools_agent(
|
73
|
+
llm=llm, tools=[final_answer_tool, search_tool], prompt=prompt
|
74
|
+
)
|
75
|
+
|
76
|
+
|
77
|
+
inputs = {"input": "what are EHI embeddings?", "intermediate_steps": []}
|
78
|
+
|
79
|
+
agent_out = query_agent_runnable.invoke(inputs)
|
80
|
+
|
81
|
+
|
82
|
+
def run_query_agent(state: list):
|
83
|
+
print("> run_query_agent")
|
84
|
+
agent_out = query_agent_runnable.invoke(state)
|
85
|
+
return {"agent_out": agent_out}
|
86
|
+
|
87
|
+
|
88
|
+
def execute_search(state: list):
|
89
|
+
print("> execute_search")
|
90
|
+
action = state["agent_out"]
|
91
|
+
tool_call = action[-1].message_log[-1].additional_kwargs["tool_calls"][-1]
|
92
|
+
out = search_tool.invoke(json.loads(tool_call["function"]["arguments"]))
|
93
|
+
return {"intermediate_steps": [{"search": str(out)}]}
|
94
|
+
|
95
|
+
|
96
|
+
def router(state: list):
|
97
|
+
print("> router")
|
98
|
+
if isinstance(state["agent_out"], list):
|
99
|
+
return state["agent_out"][-1].tool
|
100
|
+
else:
|
101
|
+
return "error"
|
102
|
+
|
103
|
+
|
104
|
+
# finally, we will have a single LLM call that MUST use the final_answer structure
|
105
|
+
final_answer_llm = llm.bind_tools([final_answer_tool], tool_choice="final_answer")
|
106
|
+
|
107
|
+
|
108
|
+
# this forced final_answer LLM call will be used to structure output from our
|
109
|
+
# RAG endpoint
|
110
|
+
def rag_final_answer(state: list):
|
111
|
+
print("> final_answer")
|
112
|
+
query = state["input"]
|
113
|
+
context = state["intermediate_steps"][-1]
|
114
|
+
|
115
|
+
prompt = f"""You are a helpful assistant, answer the user's question using the
|
116
|
+
context provided.
|
117
|
+
|
118
|
+
CONTEXT: {context}
|
119
|
+
|
120
|
+
QUESTION: {query}
|
121
|
+
"""
|
122
|
+
out = final_answer_llm.invoke(prompt)
|
123
|
+
function_call = out.additional_kwargs["tool_calls"][-1]["function"]["arguments"]
|
124
|
+
return {"agent_out": function_call}
|
125
|
+
|
126
|
+
|
127
|
+
# we use the same forced final_answer LLM call to handle incorrectly formatted
|
128
|
+
# output from our query_agent
|
129
|
+
def handle_error(state: list):
|
130
|
+
print("> handle_error")
|
131
|
+
query = state["input"]
|
132
|
+
prompt = f"""You are a helpful assistant, answer the user's question.
|
133
|
+
|
134
|
+
QUESTION: {query}
|
135
|
+
"""
|
136
|
+
out = final_answer_llm.invoke(prompt)
|
137
|
+
function_call = out.additional_kwargs["tool_calls"][-1]["function"]["arguments"]
|
138
|
+
return {"agent_out": function_call}
|
139
|
+
|
140
|
+
|
141
|
+
@with_langtrace_root_span("run_graph")
|
142
|
+
def run_graph():
|
143
|
+
graph = StateGraph(AgentState)
|
144
|
+
|
145
|
+
# we have four nodes that will consume our agent state and modify
|
146
|
+
# our agent state based on some internal process
|
147
|
+
graph.add_node("query_agent", run_query_agent)
|
148
|
+
graph.add_node("search", execute_search)
|
149
|
+
graph.add_node("error", handle_error)
|
150
|
+
graph.add_node("rag_final_answer", rag_final_answer)
|
151
|
+
# our graph will always begin with the query agent
|
152
|
+
graph.set_entry_point("query_agent")
|
153
|
+
# conditional edges are controlled by our router
|
154
|
+
graph.add_conditional_edges(
|
155
|
+
"query_agent",
|
156
|
+
router,
|
157
|
+
{
|
158
|
+
"search": "search",
|
159
|
+
"error": "error",
|
160
|
+
"final_answer": END,
|
161
|
+
},
|
162
|
+
)
|
163
|
+
graph.add_edge("search", "rag_final_answer")
|
164
|
+
graph.add_edge("error", END)
|
165
|
+
graph.add_edge("rag_final_answer", END)
|
166
|
+
|
167
|
+
runnable = graph.compile()
|
168
|
+
|
169
|
+
return runnable.invoke({"input": "what are EHI embeddings?"})
|
170
|
+
|
171
|
+
|
172
|
+
if __name__ == "__main__":
|
173
|
+
run_graph()
|
@@ -223,7 +223,7 @@ class CrewAISpanAttributes:
|
|
223
223
|
for task in tasks:
|
224
224
|
self.crew["tasks"].append(
|
225
225
|
{
|
226
|
-
"agent": task.agent.role,
|
226
|
+
"agent": task.agent.role if task.agent else None,
|
227
227
|
"description": task.description,
|
228
228
|
"async_execution": task.async_execution,
|
229
229
|
"expected_output": task.expected_output,
|
@@ -27,12 +27,12 @@ class DspyInstrumentation(BaseInstrumentor):
|
|
27
27
|
The DspyInstrumentor class represents the DSPy instrumentation"""
|
28
28
|
|
29
29
|
def instrumentation_dependencies(self) -> Collection[str]:
|
30
|
-
return ["dspy
|
30
|
+
return ["dspy >= 2.0.0"]
|
31
31
|
|
32
32
|
def _instrument(self, **kwargs):
|
33
33
|
tracer_provider = kwargs.get("tracer_provider")
|
34
34
|
tracer = get_tracer(__name__, "", tracer_provider)
|
35
|
-
version = v("dspy
|
35
|
+
version = v("dspy")
|
36
36
|
_W(
|
37
37
|
"dspy.teleprompt.bootstrap",
|
38
38
|
"BootstrapFewShot.compile",
|
@@ -41,7 +41,8 @@ class LanggraphInstrumentation(BaseInstrumentor):
|
|
41
41
|
# List of modules to patch, with their corresponding patch names
|
42
42
|
modules_to_patch = [
|
43
43
|
(
|
44
|
-
"langgraph.graph.
|
44
|
+
"langgraph.graph.state", # Updated module path
|
45
|
+
"StateGraph", # Updated class name
|
45
46
|
[
|
46
47
|
"add_node",
|
47
48
|
"add_edge",
|
@@ -49,26 +50,20 @@ class LanggraphInstrumentation(BaseInstrumentor):
|
|
49
50
|
"set_finish_point",
|
50
51
|
"add_conditional_edges",
|
51
52
|
],
|
52
|
-
)
|
53
|
+
)
|
53
54
|
]
|
54
55
|
|
55
|
-
for module_name, methods in modules_to_patch:
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
module = f"{name}.{method_name}"
|
67
|
-
wrap_function_wrapper(
|
68
|
-
module_name,
|
69
|
-
module,
|
70
|
-
patch_graph_methods(module, tracer, version),
|
71
|
-
)
|
56
|
+
for module_name, class_name, methods in modules_to_patch:
|
57
|
+
for method_name in methods:
|
58
|
+
# Construct the correct path for the method
|
59
|
+
method_path = f"{class_name}.{method_name}"
|
60
|
+
wrap_function_wrapper(
|
61
|
+
module_name,
|
62
|
+
method_path,
|
63
|
+
patch_graph_methods(
|
64
|
+
f"{module_name}.{method_path}", tracer, version
|
65
|
+
),
|
66
|
+
)
|
72
67
|
|
73
68
|
def _uninstrument(self, **kwargs):
|
74
69
|
pass
|
@@ -30,6 +30,7 @@ from langtrace_python_sdk.constants.instrumentation.common import (
|
|
30
30
|
from importlib_metadata import version as v
|
31
31
|
|
32
32
|
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
|
33
|
+
from langtrace_python_sdk.utils.llm import set_span_attributes
|
33
34
|
|
34
35
|
|
35
36
|
def patch_graph_methods(method_name, tracer, version):
|
@@ -57,9 +58,7 @@ def patch_graph_methods(method_name, tracer, version):
|
|
57
58
|
kind=SpanKind.CLIENT,
|
58
59
|
context=set_span_in_context(trace.get_current_span()),
|
59
60
|
) as span:
|
60
|
-
|
61
|
-
if value is not None:
|
62
|
-
span.set_attribute(field, value)
|
61
|
+
set_span_attributes(span, attributes)
|
63
62
|
try:
|
64
63
|
# Attempt to call the original method
|
65
64
|
result = wrapped(*args, **kwargs)
|
@@ -275,7 +275,7 @@ def init(
|
|
275
275
|
"weaviate-client": WeaviateInstrumentation(),
|
276
276
|
"sqlalchemy": SQLAlchemyInstrumentor(),
|
277
277
|
"ollama": OllamaInstrumentor(),
|
278
|
-
"dspy
|
278
|
+
"dspy": DspyInstrumentation(),
|
279
279
|
"crewai": CrewAIInstrumentation(),
|
280
280
|
"vertexai": VertexAIInstrumentation(),
|
281
281
|
"google-cloud-aiplatform": VertexAIInstrumentation(),
|
langtrace_python_sdk/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "3.3.
|
1
|
+
__version__ = "3.3.13"
|
@@ -61,6 +61,7 @@ examples/langchain_example/langgraph_example.py,sha256=7C2a4Sg0PKbbab03CVkStO3Mz
|
|
61
61
|
examples/langchain_example/langgraph_example_tools.py,sha256=rFwgQYRngeyCz9PuBxnllp5t5PIHk8d-UDKwCQTgkxw,4208
|
62
62
|
examples/langchain_example/sagemaker.py,sha256=V-rTZRyaErHCuo3kfrrZD8AELHJVi3wF7n1YrixfF1s,2330
|
63
63
|
examples/langchain_example/tool.py,sha256=8T8_IDbgA58XbsfyH5_xhA8ZKQfyfyFxF8wor-PsRjA,2556
|
64
|
+
examples/langgraph_example/main.py,sha256=G1bvJ83KmBk6ibs6UFHNaLFTeg9-72dEy2UyhGd7ssI,6031
|
64
65
|
examples/litellm_example/basic.py,sha256=UDbv6-SV7H5_Ogk_IOL22ZX4hv5I_CKCyEHl3r8pf7c,2338
|
65
66
|
examples/litellm_example/config.yaml,sha256=kSAAspBhibtc4D7Abd2vYqm3uIqHR1kjE8nZrSTJqYQ,303
|
66
67
|
examples/litellm_example/proxy_basic.py,sha256=glQvcQ3rYD1QTyQfTwmzlPdzGMiIceRhAzE3_O94_1U,366
|
@@ -104,8 +105,8 @@ examples/vertexai_example/main.py,sha256=gndId5X5ksD-ycxnAWMdEqIDbLc3kz5Vt8vm4YP
|
|
104
105
|
examples/weaviate_example/__init__.py,sha256=8JMDBsRSEV10HfTd-YC7xb4txBjD3la56snk-Bbg2Kw,618
|
105
106
|
examples/weaviate_example/query_text.py,sha256=wPHQTc_58kPoKTZMygVjTj-2ZcdrIuaausJfMxNQnQc,127162
|
106
107
|
langtrace_python_sdk/__init__.py,sha256=VZM6i71NR7pBQK6XvJWRelknuTYUhqwqE7PlicKa5Wg,1166
|
107
|
-
langtrace_python_sdk/langtrace.py,sha256=
|
108
|
-
langtrace_python_sdk/version.py,sha256=
|
108
|
+
langtrace_python_sdk/langtrace.py,sha256=AN6ecuL47c5eIkgYLW-0nDyEZPaqKfOYRbw7ceZzJss,12598
|
109
|
+
langtrace_python_sdk/version.py,sha256=NrcIAr0BNQR9mCN28fqqP9XcjFrymE0bA3_rqg6Oem8,23
|
109
110
|
langtrace_python_sdk/constants/__init__.py,sha256=3CNYkWMdd1DrkGqzLUgNZXjdAlM6UFMlf_F-odAToyc,146
|
110
111
|
langtrace_python_sdk/constants/exporter/langtrace_exporter.py,sha256=d-3Qn5C_NTy1NkmdavZvy-6vePwTC5curN6QMy2haHc,50
|
111
112
|
langtrace_python_sdk/constants/instrumentation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -152,9 +153,9 @@ langtrace_python_sdk/instrumentation/cohere/instrumentation.py,sha256=YQFHZIBd7S
|
|
152
153
|
langtrace_python_sdk/instrumentation/cohere/patch.py,sha256=AnRWIy00XaLdQg670s8FDXoVWai3sF1JKeR70pDuZ7I,20986
|
153
154
|
langtrace_python_sdk/instrumentation/crewai/__init__.py,sha256=_UBKfvQv7l0g2_wnmA5F6CdSAFH0atNOVPd49zsN3aM,88
|
154
155
|
langtrace_python_sdk/instrumentation/crewai/instrumentation.py,sha256=5Umzq8zjEnMEtjZZiMB4DQOPkxZ-1vts7RKC6JWpn24,2969
|
155
|
-
langtrace_python_sdk/instrumentation/crewai/patch.py,sha256=
|
156
|
+
langtrace_python_sdk/instrumentation/crewai/patch.py,sha256=VoyOtGKYzaOIu7UnVNTemZeB3LrCIodrrYwmXLdxRw8,9133
|
156
157
|
langtrace_python_sdk/instrumentation/dspy/__init__.py,sha256=tM1srfi_QgyCzrde4izojMrRq2Wm7Dj5QUvVQXIJzkk,84
|
157
|
-
langtrace_python_sdk/instrumentation/dspy/instrumentation.py,sha256=
|
158
|
+
langtrace_python_sdk/instrumentation/dspy/instrumentation.py,sha256=qx2vBeuODI7rubf-0bkuNzDWu4bLI-E5uabrWTEuH6k,2923
|
158
159
|
langtrace_python_sdk/instrumentation/dspy/patch.py,sha256=H7zF4PVdtepOSpzJuEcckKUjnZQYKlY7yhn3dk6xbpY,10458
|
159
160
|
langtrace_python_sdk/instrumentation/embedchain/__init__.py,sha256=5L6n8-brMnRWZ0CMmHEuN1mrhIxrYLNtxRy0Ujc-hOY,103
|
160
161
|
langtrace_python_sdk/instrumentation/embedchain/instrumentation.py,sha256=dShwm0duy25IvL7g9I_v-2oYuyh2fadeiJqXtXBay-8,1987
|
@@ -175,8 +176,8 @@ langtrace_python_sdk/instrumentation/langchain_core/__init__.py,sha256=kumE_reeq
|
|
175
176
|
langtrace_python_sdk/instrumentation/langchain_core/instrumentation.py,sha256=szTCveG4IP64rlaY4iZATWv2f38k1_DtfbBU60YlfYk,6730
|
176
177
|
langtrace_python_sdk/instrumentation/langchain_core/patch.py,sha256=CXEfbq6E88X_y3JF7CaEEbNCYzSfig5ztNHW-aiiTic,10918
|
177
178
|
langtrace_python_sdk/instrumentation/langgraph/__init__.py,sha256=eitlHloY-aZ4ZuIEJx61AadEA3G7siyecP-V-lziAr8,101
|
178
|
-
langtrace_python_sdk/instrumentation/langgraph/instrumentation.py,sha256=
|
179
|
-
langtrace_python_sdk/instrumentation/langgraph/patch.py,sha256=
|
179
|
+
langtrace_python_sdk/instrumentation/langgraph/instrumentation.py,sha256=lEm_rcOU4JqXGmhG1C2yrIiPbt9vntvxmU7pZg8NYtE,2313
|
180
|
+
langtrace_python_sdk/instrumentation/langgraph/patch.py,sha256=e1cFCDUB8Dwl2ekxgnZ36S2XkWROagRGtxF3Rz5F8RM,4931
|
180
181
|
langtrace_python_sdk/instrumentation/litellm/__init__.py,sha256=8uziCc56rFSRiPkYcrcBRbtppOANkZ7uZssCKAl2MKk,97
|
181
182
|
langtrace_python_sdk/instrumentation/litellm/instrumentation.py,sha256=Km2q_yfZU6nSqPEXG2xbtTSjqv7xSS92Kxqzw-GtQno,2655
|
182
183
|
langtrace_python_sdk/instrumentation/litellm/patch.py,sha256=wGPOlrLo4RHj1lXNv6wOz5H_p4G0XtzhVjgc-2m7Gik,24469
|
@@ -264,8 +265,8 @@ tests/pinecone/cassettes/test_query.yaml,sha256=b5v9G3ssUy00oG63PlFUR3JErF2Js-5A
|
|
264
265
|
tests/pinecone/cassettes/test_upsert.yaml,sha256=neWmQ1v3d03V8WoLl8FoFeeCYImb8pxlJBWnFd_lITU,38607
|
265
266
|
tests/qdrant/conftest.py,sha256=9n0uHxxIjWk9fbYc4bx-uP8lSAgLBVx-cV9UjnsyCHM,381
|
266
267
|
tests/qdrant/test_qdrant.py,sha256=pzjAjVY2kmsmGfrI2Gs2xrolfuaNHz7l1fqGQCjp5_o,3353
|
267
|
-
langtrace_python_sdk-3.3.
|
268
|
-
langtrace_python_sdk-3.3.
|
269
|
-
langtrace_python_sdk-3.3.
|
270
|
-
langtrace_python_sdk-3.3.
|
271
|
-
langtrace_python_sdk-3.3.
|
268
|
+
langtrace_python_sdk-3.3.13.dist-info/METADATA,sha256=PTvFNsHskew8hssq1CAxynLul99E0Z3jZpJRPw9qXWk,15643
|
269
|
+
langtrace_python_sdk-3.3.13.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
270
|
+
langtrace_python_sdk-3.3.13.dist-info/entry_points.txt,sha256=1_b9-qvf2fE7uQNZcbUei9vLpFZBbbh9LrtGw95ssAo,70
|
271
|
+
langtrace_python_sdk-3.3.13.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
272
|
+
langtrace_python_sdk-3.3.13.dist-info/RECORD,,
|
File without changes
|
{langtrace_python_sdk-3.3.11.dist-info → langtrace_python_sdk-3.3.13.dist-info}/entry_points.txt
RENAMED
File without changes
|
{langtrace_python_sdk-3.3.11.dist-info → langtrace_python_sdk-3.3.13.dist-info}/licenses/LICENSE
RENAMED
File without changes
|