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.
@@ -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-ai >= 2.0.0"]
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-ai")
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.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
- module = importlib.import_module(module_name)
57
- for name, obj in inspect.getmembers(
58
- module,
59
- lambda member: inspect.isclass(member)
60
- and member.__module__ == module.__name__,
61
- ):
62
- for method_name, _ in inspect.getmembers(
63
- obj, predicate=inspect.isfunction
64
- ):
65
- if method_name in methods:
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
- for field, value in attributes.model_dump(by_alias=True).items():
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-ai": DspyInstrumentation(),
278
+ "dspy": DspyInstrumentation(),
279
279
  "crewai": CrewAIInstrumentation(),
280
280
  "vertexai": VertexAIInstrumentation(),
281
281
  "google-cloud-aiplatform": VertexAIInstrumentation(),
@@ -1 +1 @@
1
- __version__ = "3.3.11"
1
+ __version__ = "3.3.13"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: langtrace-python-sdk
3
- Version: 3.3.11
3
+ Version: 3.3.13
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>
@@ -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=TtRWuUiWUB0S7JiQpUsF9lZsiyqPG3m9mMDX-QlDgAw,12601
108
- langtrace_python_sdk/version.py,sha256=8z892wHTeofZFdOEAH717nrRAZ1euxjj23yT75bY2Kg,23
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=C2OKKPC-pzfzZWxPc74kHdYsKTX9yRhOgVY47WY9KN8,9109
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=o8URiDvCbZ8LL0I-4xKHkn_Ms2sETBRpn-gOliv3xzQ,2929
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=SUZZhWSIbcfsF1S5NtEqW8QzkRM_pKAuXB7pwk5tsOU,2526
179
- langtrace_python_sdk/instrumentation/langgraph/patch.py,sha256=PGe1ZywXctB_yYqnp8AtD8Xqj7EZ087-S5_2vLRYhEQ,4987
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.11.dist-info/METADATA,sha256=ReGla3YZNI-O-8R3BP4gt1Pu8IyfJOer19fvSuz7XJg,15643
268
- langtrace_python_sdk-3.3.11.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
269
- langtrace_python_sdk-3.3.11.dist-info/entry_points.txt,sha256=1_b9-qvf2fE7uQNZcbUei9vLpFZBbbh9LrtGw95ssAo,70
270
- langtrace_python_sdk-3.3.11.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
271
- langtrace_python_sdk-3.3.11.dist-info/RECORD,,
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,,