Mark a value as a secret, so LangSmith masks it instead of tracing it.
::
from langsmith import LangSmithSecret
API_KEY = LangSmithSecret(os.environ["VENDOR_API_KEY"])
See :class:LangSmithSecret for the guarantees and the known limits.
Written in place of a secret. Distinct from the regex anonymizer's
[SECRET_DETECTED] so the two mechanisms are distinguishable in a trace.
A string that LangSmith serializes as [LANGSMITH SECRET].
Wrap a credential once, where it is read, and LangSmith masks it wherever it appears in a trace, at any nesting depth::
@traceable
def call_vendor(api_key: str, prompt: str) -> str: ...
call_vendor(api_key=LangSmithSecret(key), prompt="hi")
# traced inputs: {"api_key": "[LANGSMITH SECRET]", "prompt": "hi"}
It is a real str everywhere else: json.dumps, logging and
third-party clients all see the true value. Operations that derive a new
string return a LangSmithSecret again, so the marker is not lost by
.strip() or slicing.
Known limits:
f"Bearer {secret}", "".join([secret]) and
"Bearer {}".format(secret) yield a plain str: those build the
result in C, where the operand gets no say in its type. Wrap the finished
value instead -- LangSmithSecret(f"Bearer {key}"). Concatenation and
% are covered, in either operand order.secret.encode() returns the real bytes, by design.__str__ interpolates a secret leaks it wherever
LangSmith stringifies that object. __repr__ is masked; __str__
belongs to the object.