Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
9ddc018
init commit
nimarb Aug 11, 2025
1bc90b0
Use as_type
nimarb Aug 12, 2025
7f71789
clean
nimarb Aug 12, 2025
df8ff8e
cleanup
nimarb Aug 12, 2025
c3be3d8
cleanup
nimarb Aug 12, 2025
c1bd882
Merge branch 'main' into nimar/lfe-6153-generalized-graphs-python
nimarb Aug 12, 2025
2f34092
todo clarifty case sensitivity
nimarb Aug 12, 2025
6b36bd1
format
nimarb Aug 12, 2025
6e0695b
revert
nimarb Aug 12, 2025
ab0cbf3
add test
nimarb Aug 12, 2025
81b255a
lower case
nimarb Aug 12, 2025
b164e41
fix lint
nimarb Aug 12, 2025
ef49cde
format
nimarb Aug 12, 2025
89b1b3e
Merge branch 'main' into nimar/lfe-6153-generalized-graphs-python
nimarb Aug 12, 2025
8af5b67
types
nimarb Aug 12, 2025
bdb8147
cleanup
nimarb Aug 12, 2025
0898095
fix test
nimarb Aug 13, 2025
abd14de
update
nimarb Aug 15, 2025
0d696ea
Merge branch 'main' into nimar/lfe-6153-generalized-graphs-python
nimarb Aug 15, 2025
53a9bff
update
nimarb Aug 15, 2025
180cb96
fix cases
nimarb Aug 15, 2025
e41c018
fix some more types
nimarb Aug 15, 2025
5c3a510
update SDK
nimarb Aug 15, 2025
dc5e199
fix types
nimarb Aug 15, 2025
60f124b
add type checing isntructions
nimarb Aug 15, 2025
649da3a
restore
nimarb Aug 15, 2025
31c524c
restore 2
nimarb Aug 15, 2025
0d403e9
restore
nimarb Aug 15, 2025
df71a69
restore 3
nimarb Aug 15, 2025
c07a95a
simplify
nimarb Aug 15, 2025
abddc45
simplift
nimarb Aug 15, 2025
0b25836
simplify
nimarb Aug 15, 2025
a09044a
fix case
nimarb Aug 15, 2025
e4bcc7b
rearrange spans
nimarb Aug 15, 2025
f0a3224
restrucure a bit
nimarb Aug 18, 2025
04d6576
cleanup
nimarb Aug 18, 2025
79cb0a5
make mypy happy
nimarb Aug 18, 2025
8756e11
py3.9 compat
nimarb Aug 18, 2025
9f510ad
happy mypy
nimarb Aug 18, 2025
4498380
cleanup
nimarb Aug 18, 2025
0267755
a bit more clean
nimarb Aug 18, 2025
5aba0ba
cleanup
nimarb Aug 18, 2025
14f73bd
overload all the things
nimarb Aug 19, 2025
55dce5b
overload
nimarb Aug 19, 2025
37c284b
rename spanwrapper to observation wrapper
nimarb Aug 19, 2025
c08055d
don't update events
nimarb Aug 19, 2025
717c302
fix test
nimarb Aug 19, 2025
dc7d7ff
fix span
nimarb Aug 19, 2025
b6b1b01
fix test
nimarb Aug 19, 2025
e537231
langchain
nimarb Aug 19, 2025
f7481d6
formatting
nimarb Aug 19, 2025
0206b4e
add langchain test
nimarb Aug 20, 2025
12b806f
add core test
nimarb Aug 20, 2025
881a65b
Merge branch 'main' into nimar/lfe-6153-generalized-graphs-python
nimarb Aug 20, 2025
1ce911f
cleanup
nimarb Aug 20, 2025
d66d003
add deprecation warning
nimarb Aug 20, 2025
2e0b7a8
fix types
nimarb Aug 20, 2025
0f2c731
change generation like and span like
nimarb Aug 21, 2025
b4fb6a6
fix
nimarb Aug 21, 2025
e7f34fe
test format
nimarb Aug 21, 2025
3aa4af8
from review
nimarb Aug 22, 2025
ddb767e
format
nimarb Aug 22, 2025
599ee51
add generation-like test
nimarb Aug 22, 2025
fa5346c
chore: update auto gen SDK (#1300)
nimarb Aug 22, 2025
bb4cfab
fix lint
nimarb Aug 22, 2025
6da68c9
fix tests
nimarb Aug 22, 2025
34298e8
embedding correct attrs
nimarb Aug 22, 2025
cc7820b
fix typing
nimarb Aug 22, 2025
9f3349f
fix bug
nimarb Aug 22, 2025
9512f06
fix mypy
nimarb Aug 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion langfuse/_client/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,10 @@ def create_span_attributes(
level: Optional[SpanLevel] = None,
status_message: Optional[str] = None,
version: Optional[str] = None,
observation_type: Optional[str] = None,
) -> dict:
attributes = {
LangfuseOtelSpanAttributes.OBSERVATION_TYPE: "span",
LangfuseOtelSpanAttributes.OBSERVATION_TYPE: observation_type or "span",
LangfuseOtelSpanAttributes.OBSERVATION_LEVEL: level,
LangfuseOtelSpanAttributes.OBSERVATION_STATUS_MESSAGE: status_message,
LangfuseOtelSpanAttributes.VERSION: version,
Expand Down
130 changes: 97 additions & 33 deletions langfuse/_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
LangfuseEvent,
LangfuseGeneration,
LangfuseSpan,
LangfuseAgent,
LangfuseTool,
LangfuseChain,
LangfuseRetriever,
LangfuseEmbedding,
)
from langfuse._utils import _get_timestamp
from langfuse._utils.parse_error import handle_fern_exception
Expand Down Expand Up @@ -350,6 +355,20 @@ def start_as_current_span(
level: Optional[SpanLevel] = None,
status_message: Optional[str] = None,
end_on_exit: Optional[bool] = None,
as_type: Optional[
Literal[
"generation",
"span",
"GENERATION",
"EVENT",
"SPAN",
"AGENT",
"TOOL",
"CHAIN",
"RETRIEVER",
"EMBEDDING",
Comment thread
nimarb marked this conversation as resolved.
Outdated
]
],
) -> _AgnosticContextManager[LangfuseSpan]:
"""Create a new span and set it as the current span in a context manager.

Expand Down Expand Up @@ -415,7 +434,7 @@ def start_as_current_span(
return cast(
_AgnosticContextManager[LangfuseSpan],
self._start_as_current_otel_span_with_processed_media(
as_type="span",
as_type=as_type,
Comment thread
nimarb marked this conversation as resolved.
Outdated
name=name,
end_on_exit=end_on_exit,
input=input,
Expand Down Expand Up @@ -666,14 +685,48 @@ def start_as_current_generation(
),
)

def _get_span_class(
self,
as_type: Literal[
"span",
"generation",
"event",
"AGENT",
"TOOL",
"CHAIN",
"RETRIEVER",
"EMBEDDING",
],
):
"""Get the appropriate span class based on as_type."""
# TODO: make it case insensitive
if as_type == "AGENT":
return LangfuseAgent
elif as_type == "TOOL":
return LangfuseTool
elif as_type == "CHAIN":
return LangfuseChain
elif as_type == "RETRIEVER":
return LangfuseRetriever
elif as_type == "EMBEDDING":
return LangfuseEmbedding
elif as_type in ("generation", "GENERATION"):
return LangfuseGeneration
elif as_type in ("event", "EVENT"):
return LangfuseEvent
elif as_type in ("span", "SPAN"):
return LangfuseSpan
else:
return LangfuseSpan
Comment thread
nimarb marked this conversation as resolved.

@_agnosticcontextmanager
def _create_span_with_parent_context(
self,
*,
name: str,
parent: Optional[otel_trace_api.Span] = None,
remote_parent_span: Optional[otel_trace_api.Span] = None,
as_type: Literal["generation", "span"],
as_type: Literal["generation", "span", "agent", "tool", "chain", "retriever"],
end_on_exit: Optional[bool] = None,
input: Optional[Any] = None,
output: Optional[Any] = None,
Expand Down Expand Up @@ -720,7 +773,11 @@ def _start_as_current_otel_span_with_processed_media(
self,
*,
name: str,
as_type: Optional[Literal["generation", "span"]] = None,
as_type: Optional[
Literal[
"generation", "span", "event", "AGENT", "TOOL", "CHAIN", "RETRIEVER"
]
] = None,
end_on_exit: Optional[bool] = None,
input: Optional[Any] = None,
output: Optional[Any] = None,
Expand All @@ -739,37 +796,44 @@ def _start_as_current_otel_span_with_processed_media(
name=name,
end_on_exit=end_on_exit if end_on_exit is not None else True,
) as otel_span:
yield (
LangfuseSpan(
otel_span=otel_span,
langfuse_client=self,
environment=self._environment,
input=input,
output=output,
metadata=metadata,
version=version,
level=level,
status_message=status_message,
)
if as_type == "span"
else LangfuseGeneration(
otel_span=otel_span,
langfuse_client=self,
environment=self._environment,
input=input,
output=output,
metadata=metadata,
version=version,
level=level,
status_message=status_message,
completion_start_time=completion_start_time,
model=model,
model_parameters=model_parameters,
usage_details=usage_details,
cost_details=cost_details,
prompt=prompt,
span_class = self._get_span_class(as_type or "generation")
common_args = {
"otel_span": otel_span,
"langfuse_client": self,
"environment": self._environment,
"input": input,
"output": output,
"metadata": metadata,
"version": version,
"level": level,
"status_message": status_message,
}

if span_class == LangfuseGeneration:
common_args.update(
{
"completion_start_time": completion_start_time,
"model": model,
"model_parameters": model_parameters,
"usage_details": usage_details,
"cost_details": cost_details,
"prompt": prompt,
}
)
)
elif span_class in [
LangfuseAgent,
LangfuseTool,
LangfuseChain,
LangfuseRetriever,
LangfuseEmbedding,
]:
# set their type internally in the class
pass
else:
if as_type is not None:
common_args["as_type"] = as_type

yield span_class(**common_args)

def _get_current_otel_span(self) -> Optional[otel_trace_api.Span]:
current_span = otel_trace_api.get_current_span()
Expand Down
12 changes: 12 additions & 0 deletions langfuse/_client/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,15 @@
"""

LANGFUSE_TRACER_NAME = "langfuse-sdk"

# Valid observation types for the @observe decorator
VALID_OBSERVATION_TYPES = {
Comment thread
nimarb marked this conversation as resolved.
Outdated
"SPAN",
"EVENT",
"GENERATION",
"AGENT",
"TOOL",
"CHAIN",
"RETRIEVER",
"EMBEDDING",
}
Loading
Loading