Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 2 additions & 8 deletions integrations/langfuse/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,21 @@ name = "langfuse-haystack"
dynamic = ["version"]
description = "Langfuse integration for Haystack"
readme = "README.md"
requires-python = ">=3.9"
requires-python = ">=3.10"
license = "Apache-2.0"
keywords = []
authors = [{ name = "deepset GmbH", email = "info@deepset.ai" }]
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
dependencies = ["haystack-ai>=2.17.1", "langfuse>=3.3.1, <4.0.0"]
dependencies = ["haystack-ai>=2.22.0", "langfuse>=3.3.1, <4.0.0"]

[project.urls]
Documentation = "https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/langfuse#readme"
Expand Down Expand Up @@ -82,7 +81,6 @@ allow-direct-references = true


[tool.ruff]
target-version = "py39"
line-length = 120

[tool.ruff.lint]
Expand Down Expand Up @@ -128,10 +126,6 @@ ignore = [
# Asserts
"S101",
]
unfixable = [
# Don't touch unused imports
"F401",
]

[tool.ruff.lint.isort]
known-first-party = ["haystack_integrations"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: Apache-2.0

from typing import Any, Optional
from typing import Any

import httpx
from haystack import component, default_from_dict, default_to_dict, logging, tracing
Expand Down Expand Up @@ -118,13 +118,13 @@ def __init__(
self,
name: str,
public: bool = False,
public_key: Optional[Secret] = Secret.from_env_var("LANGFUSE_PUBLIC_KEY"), # noqa: B008
secret_key: Optional[Secret] = Secret.from_env_var("LANGFUSE_SECRET_KEY"), # noqa: B008
httpx_client: Optional[httpx.Client] = None,
span_handler: Optional[SpanHandler] = None,
public_key: Secret | None = Secret.from_env_var("LANGFUSE_PUBLIC_KEY"), # noqa: B008
secret_key: Secret | None = Secret.from_env_var("LANGFUSE_SECRET_KEY"), # noqa: B008
httpx_client: httpx.Client | None = None,
span_handler: SpanHandler | None = None,
*,
host: Optional[str] = None,
langfuse_client_kwargs: Optional[dict[str, Any]] = None,
host: str | None = None,
langfuse_client_kwargs: dict[str, Any] | None = None,
) -> None:
"""
Initialize the LangfuseConnector component.
Expand Down Expand Up @@ -172,7 +172,7 @@ def __init__(
tracing.enable_tracing(self.tracer)

@component.output_types(name=str, trace_url=str, trace_id=str)
def run(self, invocation_context: Optional[dict[str, Any]] = None) -> dict[str, str]:
def run(self, invocation_context: dict[str, Any] | None = None) -> dict[str, str]:
"""
Runs the LangfuseConnector component.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from contextvars import ContextVar
from dataclasses import dataclass
from datetime import datetime
from typing import Any, Literal, Optional, cast
from typing import Any, Literal, cast

from haystack import default_from_dict, default_to_dict, logging
from haystack.dataclasses import ChatMessage
Expand Down Expand Up @@ -48,7 +48,7 @@

# Internal span execution hierarchy for our tracer
# Manages parent-child relationships and prevents cross-request span interleaving
span_stack_var: ContextVar[Optional[list["LangfuseSpan"]]] = ContextVar("span_stack", default=None)
span_stack_var: ContextVar[list["LangfuseSpan"] | None] = ContextVar("span_stack", default=None)


class LangfuseSpan(Span):
Expand Down Expand Up @@ -150,9 +150,9 @@ class SpanContext:

name: str
operation_name: str
component_type: Optional[str]
component_type: str | None
tags: dict[str, Any]
parent_span: Optional[Span]
parent_span: Span | None
trace_name: str = "Haystack"
public: bool = False

Expand Down Expand Up @@ -189,7 +189,7 @@ class SpanHandler(ABC):
"""

def __init__(self) -> None:
self.tracer: Optional[langfuse.Langfuse] = None
self.tracer: langfuse.Langfuse | None = None

def init_tracer(self, tracer: langfuse.Langfuse) -> None:
"""
Expand All @@ -215,7 +215,7 @@ def create_span(self, context: SpanContext) -> LangfuseSpan:
pass

@abstractmethod
def handle(self, span: LangfuseSpan, component_type: Optional[str]) -> None:
def handle(self, span: LangfuseSpan, component_type: str | None) -> None:
"""
Process a span after component execution by attaching metadata and metrics.

Expand Down Expand Up @@ -338,7 +338,7 @@ def create_span(self, context: SpanContext) -> LangfuseSpan:
else:
return LangfuseSpan(self.tracer.start_as_current_span(name=context.name))

def handle(self, span: LangfuseSpan, component_type: Optional[str]) -> None:
def handle(self, span: LangfuseSpan, component_type: str | None) -> None:
# If the span is at the pipeline level, we add input and output keys to the span
at_pipeline_level = span.get_data().get(_PIPELINE_INPUT_KEY) is not None
if at_pipeline_level:
Expand Down Expand Up @@ -420,7 +420,7 @@ def __init__(
tracer: langfuse.Langfuse,
name: str = "Haystack",
public: bool = False,
span_handler: Optional[SpanHandler] = None,
span_handler: SpanHandler | None = None,
) -> None:
"""
Initialize a LangfuseTracer instance.
Expand Down Expand Up @@ -450,7 +450,7 @@ def __init__(

@contextlib.contextmanager
def trace(
self, operation_name: str, tags: Optional[dict[str, Any]] = None, parent_span: Optional[Span] = None
self, operation_name: str, tags: dict[str, Any] | None = None, parent_span: Span | None = None
) -> Iterator[Span]:
tags = tags or {}
span_name = tags.get(_COMPONENT_NAME_KEY, operation_name)
Expand Down Expand Up @@ -541,7 +541,7 @@ def trace(
def flush(self) -> None:
self._tracer.flush()

def current_span(self) -> Optional[Span]:
def current_span(self) -> Span | None:
"""
Return the current active span.

Expand Down
3 changes: 1 addition & 2 deletions integrations/langfuse/tests/test_tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import datetime
import logging
import sys
from typing import Optional
from unittest.mock import MagicMock, Mock, patch

import pytest
Expand Down Expand Up @@ -107,7 +106,7 @@ def flush(self):


class CustomSpanHandler(DefaultSpanHandler):
def handle(self, span: LangfuseSpan, component_type: Optional[str]) -> None:
def handle(self, span: LangfuseSpan, component_type: str | None) -> None:
if component_type == "OpenAIChatGenerator":
output = span.get_data().get(_COMPONENT_OUTPUT_KEY, {})
replies = output.get("replies", [])
Expand Down