Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-langfuse for openSUSE:Factory 
checked in at 2026-05-18 17:47:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-langfuse (Old)
 and      /work/SRC/openSUSE:Factory/.python-langfuse.new.1966 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-langfuse"

Mon May 18 17:47:03 2026 rev:9 rq:1353629 version:4.6.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-langfuse/python-langfuse.changes  
2026-04-25 21:42:57.687487090 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-langfuse.new.1966/python-langfuse.changes    
    2026-05-18 17:47:18.054527801 +0200
@@ -1,0 +2,9 @@
+Sun May 17 21:13:42 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 4.6.1:
+  * feat(ci): add RunnerContext and RegressionError for
+    experiment GH action
+  * ci: allow prerelease branch releases
+  * fix(openai): handle Azure stream chunks without delta
+
+-------------------------------------------------------------------

Old:
----
  langfuse-4.5.1.tar.gz

New:
----
  langfuse-4.6.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-langfuse.spec ++++++
--- /var/tmp/diff_new_pack.pZoEYV/_old  2026-05-18 17:47:18.714555075 +0200
+++ /var/tmp/diff_new_pack.pZoEYV/_new  2026-05-18 17:47:18.718555241 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-langfuse
-Version:        4.5.1
+Version:        4.6.1
 Release:        0
 Summary:        A client library for accessing langfuse
 License:        MIT

++++++ langfuse-4.5.1.tar.gz -> langfuse-4.6.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langfuse-4.5.1/PKG-INFO new/langfuse-4.6.1/PKG-INFO
--- old/langfuse-4.5.1/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
+++ new/langfuse-4.6.1/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: langfuse
-Version: 4.5.1
+Version: 4.6.1
 Summary: A client library for accessing langfuse
 Author: langfuse
 Author-email: langfuse <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langfuse-4.5.1/langfuse/__init__.py 
new/langfuse-4.6.1/langfuse/__init__.py
--- old/langfuse-4.5.1/langfuse/__init__.py     1970-01-01 01:00:00.000000000 
+0100
+++ new/langfuse-4.6.1/langfuse/__init__.py     1970-01-01 01:00:00.000000000 
+0100
@@ -8,7 +8,7 @@
     EvaluatorStats,
     MapperFunction,
 )
-from langfuse.experiment import Evaluation
+from langfuse.experiment import Evaluation, RegressionError, RunnerContext
 
 from ._client import client as _client_module
 from ._client.attributes import LangfuseOtelSpanAttributes
@@ -63,6 +63,8 @@
     "EvaluatorStats",
     "BatchEvaluationResumeToken",
     "BatchEvaluationResult",
+    "RunnerContext",
+    "RegressionError",
     "__version__",
     "is_default_export_span",
     "is_langfuse_span",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langfuse-4.5.1/langfuse/experiment.py 
new/langfuse-4.6.1/langfuse/experiment.py
--- old/langfuse-4.5.1/langfuse/experiment.py   1970-01-01 01:00:00.000000000 
+0100
+++ new/langfuse-4.6.1/langfuse/experiment.py   1970-01-01 01:00:00.000000000 
+0100
@@ -6,7 +6,9 @@
 """
 
 import asyncio
+from datetime import datetime
 from typing import (
+    TYPE_CHECKING,
     Any,
     Awaitable,
     Dict,
@@ -15,12 +17,17 @@
     Protocol,
     TypedDict,
     Union,
+    overload,
 )
 
 from langfuse.api import DatasetItem
 from langfuse.logger import langfuse_logger as logger
 from langfuse.types import ExperimentScoreType
 
+if TYPE_CHECKING:
+    from langfuse._client.client import Langfuse
+    from langfuse.batch_evaluation import CompositeEvaluatorFunction
+
 
 class LocalExperimentItem(TypedDict, total=False):
     """Structure for local experiment data items (not from Langfuse datasets).
@@ -1049,3 +1056,152 @@
         )
 
     return langfuse_evaluator
+
+
+class RunnerContext:
+    """Wraps :meth:`Langfuse.run_experiment` with CI-injected defaults.
+
+    Intended for use with the ``langfuse/experiment-action`` GitHub Action
+    (https://github.com/langfuse/experiment-action). The action builds a
+    ``RunnerContext`` before invoking the user's ``experiment(context)``
+    function. Defaults set here (dataset, metadata tags) are applied when
+    the user omits them on the :meth:`run_experiment` call; users can
+    override any default by passing the corresponding argument explicitly.
+    """
+
+    def __init__(
+        self,
+        *,
+        client: "Langfuse",
+        data: Optional[ExperimentData] = None,
+        dataset_version: Optional[datetime] = None,
+        metadata: Optional[Dict[str, str]] = None,
+    ):
+        """Build a ``RunnerContext`` populated with defaults for 
``run_experiment``.
+
+        Typically called by the ``langfuse/experiment-action`` GitHub Action,
+        not by end users directly. Every field except ``client`` is optional:
+        fields left as ``None`` simply mean the corresponding argument must be
+        supplied on the :meth:`run_experiment` call.
+
+        Args:
+            client: Initialized Langfuse SDK client used to execute the
+                experiment. The action creates this from the
+                ``langfuse_public_key`` / ``langfuse_secret_key`` /
+                ``langfuse_base_url`` inputs.
+            data: Default dataset items to run the experiment on. Accepts
+                either ``List[LocalExperimentItem]`` or ``List[DatasetItem]``.
+                Injected by the action when ``dataset_name`` is configured.
+                If ``None``, the user must pass ``data=`` to
+                :meth:`run_experiment`.
+            dataset_version: Optional pinned dataset version. Injected by the
+                action when ``dataset_version`` is configured.
+            metadata: Default metadata attached to every experiment trace and
+                the dataset run. The action injects GitHub-sourced tags (SHA,
+                PR link, workflow run link, branch, GH user, etc.). Merged
+                with any ``metadata`` passed to :meth:`run_experiment`, with
+                user-supplied keys winning on collision.
+        """
+        self.client = client
+        self.data = data
+        self.dataset_version = dataset_version
+        self.metadata = metadata
+
+    def run_experiment(
+        self,
+        *,
+        name: str,
+        run_name: Optional[str] = None,
+        description: Optional[str] = None,
+        data: Optional[ExperimentData] = None,
+        task: TaskFunction,
+        evaluators: List[EvaluatorFunction] = [],
+        composite_evaluator: Optional["CompositeEvaluatorFunction"] = None,
+        run_evaluators: List[RunEvaluatorFunction] = [],
+        max_concurrency: int = 50,
+        metadata: Optional[Dict[str, str]] = None,
+        _dataset_version: Optional[datetime] = None,
+    ) -> ExperimentResult:
+        resolved_data = data if data is not None else self.data
+        if resolved_data is None:
+            raise ValueError(
+                "`data` must be provided either on the RunnerContext or the 
run_experiment call"
+            )
+
+        resolved_dataset_version = (
+            _dataset_version if _dataset_version is not None else 
self.dataset_version
+        )
+
+        merged_metadata: Optional[Dict[str, str]]
+        if self.metadata is None and metadata is None:
+            merged_metadata = None
+        else:
+            merged_metadata = {**(self.metadata or {}), **(metadata or {})}
+
+        return self.client.run_experiment(
+            name=name,
+            run_name=run_name,
+            description=description,
+            data=resolved_data,
+            task=task,
+            evaluators=evaluators,
+            composite_evaluator=composite_evaluator,
+            run_evaluators=run_evaluators,
+            max_concurrency=max_concurrency,
+            metadata=merged_metadata,
+            _dataset_version=resolved_dataset_version,
+        )
+
+
+class RegressionError(Exception):
+    """Raised by a user's ``experiment`` function to signal a CI gate failure.
+
+    Intended for use with the ``langfuse/experiment-action`` GitHub Action
+    (https://github.com/langfuse/experiment-action). The action catches this
+    exception and, when ``should_fail_on_error`` is enabled, fails the
+    workflow run and renders a callout in the PR comment using
+    ``metric``/``value``/``threshold`` if supplied, otherwise ``str(exc)``.
+
+    Callers choose one of three forms:
+
+    - ``RegressionError(result=r)`` — minimal, generic message.
+    - ``RegressionError(result=r, message="...")`` — free-form message.
+    - ``RegressionError(result=r, metric="acc", value=0.7, threshold=0.9)`` —
+      structured; ``metric`` and ``value`` must be provided together so the
+      action can render a targeted callout without ``None`` placeholders.
+    """
+
+    @overload
+    def __init__(self, *, result: ExperimentResult) -> None: ...
+    @overload
+    def __init__(self, *, result: ExperimentResult, message: str) -> None: ...
+    @overload
+    def __init__(
+        self,
+        *,
+        result: ExperimentResult,
+        metric: str,
+        value: float,
+        threshold: Optional[float] = None,
+        message: Optional[str] = None,
+    ) -> None: ...
+    def __init__(
+        self,
+        *,
+        result: ExperimentResult,
+        metric: Optional[str] = None,
+        value: Optional[float] = None,
+        threshold: Optional[float] = None,
+        message: Optional[str] = None,
+    ):
+        self.result = result
+        self.metric = metric
+        self.value = value
+        self.threshold = threshold
+        if message is not None:
+            formatted = message
+        elif metric is not None and value is not None:
+            formatted = f"Regression on `{metric}`: {value} (threshold 
{threshold})"
+        else:
+            formatted = "Experiment regression detected"
+        super().__init__(formatted)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langfuse-4.5.1/langfuse/openai.py 
new/langfuse-4.6.1/langfuse/openai.py
--- old/langfuse-4.5.1/langfuse/openai.py       1970-01-01 01:00:00.000000000 
+0100
+++ new/langfuse-4.6.1/langfuse/openai.py       1970-01-01 01:00:00.000000000 
+0100
@@ -640,7 +640,9 @@
             chunk = chunk.__dict__
 
         model = model or chunk.get("model", None) or None
-        usage = chunk.get("usage", None)
+        chunk_usage = chunk.get("usage", None)
+        if chunk_usage is not None:
+            usage = chunk_usage
 
         choices = chunk.get("choices", [])
 
@@ -649,11 +651,16 @@
                 choice = choice.__dict__
             if resource.type == "chat":
                 delta = choice.get("delta", None)
-                finish_reason = choice.get("finish_reason", None)
+                choice_finish_reason = choice.get("finish_reason", None)
+                if choice_finish_reason is not None:
+                    finish_reason = choice_finish_reason
 
-                if _is_openai_v1():
+                if _is_openai_v1() and delta is not None:
                     delta = delta.__dict__
 
+                if delta is None:
+                    delta = {}
+
                 if delta.get("role", None) is not None:
                     completion["role"] = delta["role"]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langfuse-4.5.1/pyproject.toml 
new/langfuse-4.6.1/pyproject.toml
--- old/langfuse-4.5.1/pyproject.toml   1970-01-01 01:00:00.000000000 +0100
+++ new/langfuse-4.6.1/pyproject.toml   1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
 [project]
 name = "langfuse"
-version = "4.5.1"
+version = "4.6.1"
 description = "A client library for accessing langfuse"
 readme = "README.md"
 authors = [{ name = "langfuse", email = "[email protected]" }]

Reply via email to