Skip to content

Commit 084b132

Browse files
authored
Add RunTree.set() support (#1710)
Useful in conjunction with langchain-ai/langchain#31090. Then from within a langchain runnable, you can do. ``` def my_node(state): if rt := ls.get_current_run_tree(): rt.set(inputs={"foo": state.foo}, outputs={"bar": "my_bar"}) ``` And have it override the defaults. Useful for filtering PII or large values etc.
1 parent b0af7e6 commit 084b132

File tree

3 files changed

+60
-8
lines changed

3 files changed

+60
-8
lines changed

python/langsmith/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from langsmith.utils import ContextThreadPoolExecutor
2121

2222
# Avoid calling into importlib on every call to __version__
23-
__version__ = "0.3.39"
23+
__version__ = "0.3.40"
2424
version = __version__ # for backwards compatibility
2525

2626

@@ -91,7 +91,6 @@ def __getattr__(name: str) -> Any:
9191
from langsmith.run_helpers import get_tracing_context
9292

9393
return get_tracing_context
94-
9594
elif name == "get_current_run_tree":
9695
from langsmith.run_helpers import get_current_run_tree
9796

python/langsmith/run_trees.py

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
LANGSMITH_METADATA = sys.intern(f"{LANGSMITH_PREFIX}metadata")
3434
LANGSMITH_TAGS = sys.intern(f"{LANGSMITH_PREFIX}tags")
3535
LANGSMITH_PROJECT = sys.intern(f"{LANGSMITH_PREFIX}project")
36+
OVERRIDE_OUTPUTS = sys.intern("__omit_auto_outputs")
37+
NOT_PROVIDED = cast(None, object())
3638
_CLIENT: Optional[Client] = None
3739
_LOCK = threading.Lock() # Keeping around for a while for backwards compat
3840

@@ -164,6 +166,51 @@ def __setattr__(self, name, value):
164166
else:
165167
return super().__setattr__(name, value)
166168

169+
def set(
170+
self,
171+
*,
172+
inputs: Optional[Mapping[str, Any]] = NOT_PROVIDED,
173+
outputs: Optional[Mapping[str, Any]] = NOT_PROVIDED,
174+
tags: Optional[Sequence[str]] = NOT_PROVIDED,
175+
metadata: Optional[Mapping[str, Any]] = NOT_PROVIDED,
176+
) -> None:
177+
"""Set the inputs, outputs, tags, and metadata of the run.
178+
179+
If performed, this will override the default behavior of the
180+
end() method to ignore new outputs (that would otherwise be added)
181+
by the @traceable decorator.
182+
183+
If your LangChain or LangGraph versions are sufficiently up-to-date,
184+
this will also override the default behavior LangChainTracer.
185+
186+
Args:
187+
inputs: The inputs to set.
188+
outputs: The outputs to set.
189+
tags: The tags to set.
190+
metadata: The metadata to set.
191+
192+
Returns:
193+
None
194+
"""
195+
if tags is not NOT_PROVIDED:
196+
self.tags = list(tags)
197+
if metadata is not NOT_PROVIDED:
198+
self.extra.setdefault("metadata", {}).update(metadata or {})
199+
if inputs is not NOT_PROVIDED:
200+
# Used by LangChain core to determine whether to
201+
# re-upload the inputs upon run completion
202+
self.extra["inputs_is_truthy"] = False
203+
if inputs is None:
204+
self.inputs = {}
205+
else:
206+
self.inputs = dict(inputs)
207+
if outputs is not NOT_PROVIDED:
208+
self.extra[OVERRIDE_OUTPUTS] = True
209+
if outputs is None:
210+
self.outputs = {}
211+
else:
212+
self.outputs = dict(outputs)
213+
167214
def add_tags(self, tags: Union[Sequence[str], str]) -> None:
168215
"""Add tags to the run."""
169216
if isinstance(tags, str):
@@ -204,6 +251,9 @@ def add_inputs(self, inputs: dict[str, Any]) -> None:
204251
if self.inputs is None:
205252
self.inputs = {}
206253
self.inputs.update(inputs)
254+
# Set to False so LangChain things it needs to
255+
# re-upload inputs
256+
self.extra["inputs_is_truthy"] = False
207257

208258
def add_event(
209259
self,
@@ -252,11 +302,14 @@ def end(
252302
) -> None:
253303
"""Set the end time of the run and all child runs."""
254304
self.end_time = end_time or datetime.now(timezone.utc)
255-
if outputs is not None:
256-
if not self.outputs:
257-
self.outputs = outputs
258-
else:
259-
self.outputs.update(outputs)
305+
# We've already 'set' the outputs, so ignore
306+
# the ones that are automatically included
307+
if not self.extra.get(OVERRIDE_OUTPUTS):
308+
if outputs is not None:
309+
if not self.outputs:
310+
self.outputs = outputs
311+
else:
312+
self.outputs.update(outputs)
260313
if error is not None:
261314
self.error = error
262315
if events is not None:

python/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "langsmith"
3-
version = "0.3.39"
3+
version = "0.3.40"
44
description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform."
55
authors = ["LangChain <[email protected]>"]
66
license = "MIT"

0 commit comments

Comments
 (0)