From 0c1635011fb1817f58357cdf87f9e9c0a2b7cab8 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 26 May 2025 11:49:09 +0200 Subject: [PATCH 01/10] fix(langchain): anthropic usage parsing (#1194) --- langfuse/callback/langchain.py | 12 ++++++++++++ langfuse/extract_model.py | 5 ++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/langfuse/callback/langchain.py b/langfuse/callback/langchain.py index 5b41fa1a0..ef6a63e2c 100644 --- a/langfuse/callback/langchain.py +++ b/langfuse/callback/langchain.py @@ -56,10 +56,12 @@ try: from langgraph.errors import GraphBubbleUp + CONTROL_FLOW_EXCEPTION_TYPES.add(GraphBubbleUp) except ImportError: pass + class LangchainCallbackHandler( LangchainBaseCallbackHandler, LangfuseBaseCallbackHandler ): @@ -1173,6 +1175,16 @@ def _parse_usage_model(usage: typing.Union[pydantic.BaseModel, dict]): "token_count" ] + usage_model = ( + { + k: v + for k, v in usage_model.items() + if v is not None and not isinstance(v, str) + } + if isinstance(usage_model, dict) + else usage_model + ) + return usage_model if usage_model else None diff --git a/langfuse/extract_model.py b/langfuse/extract_model.py index 192522846..5880e9624 100644 --- a/langfuse/extract_model.py +++ b/langfuse/extract_model.py @@ -106,7 +106,10 @@ def _extract_model_name( def _extract_model_from_repr_by_pattern( - id: str, serialized: Optional[Dict[str, Any]], pattern: str, default: Optional[str] = None + id: str, + serialized: Optional[Dict[str, Any]], + pattern: str, + default: Optional[str] = None, ): if serialized is None: return None From c9b7205d081966b2be482a365a75c8ebe06bbd84 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 26 May 2025 11:50:55 +0200 Subject: [PATCH 02/10] chore: release v2.60.6 --- langfuse/version.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/langfuse/version.py b/langfuse/version.py index 63a799b34..0d422cbaa 100644 --- a/langfuse/version.py +++ b/langfuse/version.py @@ -1,3 +1,3 @@ """@private""" -__version__ = "2.60.5" +__version__ = "2.60.6" diff --git a/pyproject.toml b/pyproject.toml index fcdac460e..06332d669 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "langfuse" -version = "2.60.5" +version = "2.60.6" description = "A client library for accessing langfuse" authors = ["langfuse "] license = "MIT" From 454120e6ddba4e4014cc570e27983ffe7351cc61 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Tue, 27 May 2025 11:42:46 +0200 Subject: [PATCH 03/10] fix(langchain): vertex token counts (#1198) --- langfuse/callback/langchain.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/langfuse/callback/langchain.py b/langfuse/callback/langchain.py index ef6a63e2c..46445cc6b 100644 --- a/langfuse/callback/langchain.py +++ b/langfuse/callback/langchain.py @@ -1139,9 +1139,11 @@ def _parse_usage_model(usage: typing.Union[pydantic.BaseModel, dict]): and "modality" in item and "token_count" in item ): - usage_model[f"input_modality_{item['modality']}"] = item[ - "token_count" - ] + value = item["token_count"] + usage_model[f"input_modality_{item['modality']}"] = value + + if "input" in usage_model: + usage_model["input"] = max(0, usage_model["input"] - value) # Vertex AI if "candidates_tokens_details" in usage_model and isinstance( @@ -1155,9 +1157,11 @@ def _parse_usage_model(usage: typing.Union[pydantic.BaseModel, dict]): and "modality" in item and "token_count" in item ): - usage_model[f"output_modality_{item['modality']}"] = item[ - "token_count" - ] + value = item["token_count"] + usage_model[f"output_modality_{item['modality']}"] = value + + if "output" in usage_model: + usage_model["output"] = max(0, usage_model["output"] - value) # Vertex AI if "cache_tokens_details" in usage_model and isinstance( @@ -1171,9 +1175,11 @@ def _parse_usage_model(usage: typing.Union[pydantic.BaseModel, dict]): and "modality" in item and "token_count" in item ): - usage_model[f"cached_modality_{item['modality']}"] = item[ - "token_count" - ] + value = item["token_count"] + usage_model[f"cached_modality_{item['modality']}"] = value + + if "input" in usage_model: + usage_model["input"] = max(0, usage_model["input"] - value) usage_model = ( { From 4dc9258ea1f1add2d106a49aeda8bac1318b485f Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Tue, 27 May 2025 13:04:30 +0200 Subject: [PATCH 04/10] chore: release v2.60.7 --- langfuse/version.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/langfuse/version.py b/langfuse/version.py index 0d422cbaa..8b18554de 100644 --- a/langfuse/version.py +++ b/langfuse/version.py @@ -1,3 +1,3 @@ """@private""" -__version__ = "2.60.6" +__version__ = "2.60.7" diff --git a/pyproject.toml b/pyproject.toml index 06332d669..4f6cf12b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "langfuse" -version = "2.60.6" +version = "2.60.7" description = "A client library for accessing langfuse" authors = ["langfuse "] license = "MIT" From 80a6066b96c8826f2b37053076905d192bbbfce5 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Tue, 3 Jun 2025 17:36:41 +0200 Subject: [PATCH 05/10] fix(langchain): deployment version in azure model (#1203) --- langfuse/extract_model.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/langfuse/extract_model.py b/langfuse/extract_model.py index 5880e9624..cd8d58ca8 100644 --- a/langfuse/extract_model.py +++ b/langfuse/extract_model.py @@ -53,12 +53,25 @@ def _extract_model_name( return kwargs.get("invocation_params").get("model_name") deployment_name = None - if serialized.get("kwargs").get("openai_api_version"): - deployment_name = serialized.get("kwargs").get("deployment_version") deployment_version = None + + if serialized.get("kwargs").get("openai_api_version"): + deployment_version = serialized.get("kwargs").get("deployment_version") + if serialized.get("kwargs").get("deployment_name"): deployment_name = serialized.get("kwargs").get("deployment_name") - return deployment_name + "-" + deployment_version + + if not isinstance(deployment_name, str): + return None + + if not isinstance(deployment_version, str): + return deployment_name + + return ( + f"{deployment_name}-{deployment_version}" + if deployment_version and deployment_version not in deployment_name + else deployment_name + ) # Third, for some models, we are unable to extract the model by a path in an object. Langfuse provides us with a string representation of the model pbjects # We use regex to extract the model from the repr string From 04bb7241a2d106c8c2d808f22843ff064288bf14 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Tue, 3 Jun 2025 17:39:12 +0200 Subject: [PATCH 06/10] chore: release v2.60.8 --- langfuse/version.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/langfuse/version.py b/langfuse/version.py index 8b18554de..8c79cacac 100644 --- a/langfuse/version.py +++ b/langfuse/version.py @@ -1,3 +1,3 @@ """@private""" -__version__ = "2.60.7" +__version__ = "2.60.8" diff --git a/pyproject.toml b/pyproject.toml index 4f6cf12b2..ab21305b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "langfuse" -version = "2.60.7" +version = "2.60.8" description = "A client library for accessing langfuse" authors = ["langfuse "] license = "MIT" From b8838c507419f41cfe0ccca14328d76692ecaa99 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Sun, 29 Jun 2025 11:37:36 +0200 Subject: [PATCH 07/10] fix(openai): chat completions parse out of beta (sdk-v2) (#1232) * fix(openai): chat.completions.parse out of beta * push --- langfuse/openai.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/langfuse/openai.py b/langfuse/openai.py index f27fedcff..d0c7a815b 100644 --- a/langfuse/openai.py +++ b/langfuse/openai.py @@ -62,6 +62,7 @@ class OpenAiDefinition: type: str sync: bool min_version: Optional[str] = None + max_version: Optional[str] = None OPENAI_METHODS_V0 = [ @@ -118,6 +119,7 @@ class OpenAiDefinition: type="chat", sync=True, min_version="1.50.0", + max_version="1.92.0", ), OpenAiDefinition( module="openai.resources.beta.chat.completions", @@ -126,6 +128,23 @@ class OpenAiDefinition: type="chat", sync=False, min_version="1.50.0", + max_version="1.92.0", + ), + OpenAiDefinition( + module="openai.resources.chat.completions", + object="Completions", + method="parse", + type="chat", + sync=True, + min_version="1.92.0", + ), + OpenAiDefinition( + module="openai.resources.chat.completions", + object="AsyncCompletions", + method="parse", + type="chat", + sync=False, + min_version="1.92.0", ), OpenAiDefinition( module="openai.resources.responses", @@ -876,6 +895,11 @@ def register_tracing(self): ) < Version(resource.min_version): continue + if resource.max_version is not None and Version( + openai.__version__ + ) >= Version(resource.max_version): + continue + wrap_function_wrapper( resource.module, f"{resource.object}.{resource.method}", From 3e25a3c2ffba9a2585d363cc0b3acbc58dc9a433 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Sun, 29 Jun 2025 11:38:55 +0200 Subject: [PATCH 08/10] chore: release v2.60.9 --- langfuse/version.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/langfuse/version.py b/langfuse/version.py index 8c79cacac..a25f133e5 100644 --- a/langfuse/version.py +++ b/langfuse/version.py @@ -1,3 +1,3 @@ """@private""" -__version__ = "2.60.8" +__version__ = "2.60.9" diff --git a/pyproject.toml b/pyproject.toml index ab21305b4..2f907d40f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "langfuse" -version = "2.60.8" +version = "2.60.9" description = "A client library for accessing langfuse" authors = ["langfuse "] license = "MIT" From 07150c59e8f7020a3eb5494eb14c198cde85ad68 Mon Sep 17 00:00:00 2001 From: Gaurav Dhiman Date: Tue, 16 Sep 2025 17:05:40 +0200 Subject: [PATCH 09/10] fix(v2-stable): task_done exception on dropped item (#1336) --- langfuse/_task_manager/ingestion_consumer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/langfuse/_task_manager/ingestion_consumer.py b/langfuse/_task_manager/ingestion_consumer.py index 16d426de0..987353409 100644 --- a/langfuse/_task_manager/ingestion_consumer.py +++ b/langfuse/_task_manager/ingestion_consumer.py @@ -211,10 +211,12 @@ def _truncate_item_in_place( # if item does not have body or input/output fields, drop the event if "body" not in event or ( - "input" not in event["body"] and "output" not in event["body"] + "input" not in event["body"] + and "output" not in event["body"] + and "metadata" not in event["body"] ): self._log.warning( - "Item does not have body or input/output fields, dropping item." + "Item does not have body or input/output/metadata fields, dropping item." ) self._ingestion_queue.task_done() return 0 From 7ab91ab6e27ea86730a0d59945ac0a93931b52ee Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Tue, 16 Sep 2025 17:07:37 +0200 Subject: [PATCH 10/10] chore: release v2.60.10 --- langfuse/version.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/langfuse/version.py b/langfuse/version.py index a25f133e5..768cb44e5 100644 --- a/langfuse/version.py +++ b/langfuse/version.py @@ -1,3 +1,3 @@ """@private""" -__version__ = "2.60.9" +__version__ = "2.60.10" diff --git a/pyproject.toml b/pyproject.toml index 2f907d40f..a1e2902f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "langfuse" -version = "2.60.9" +version = "2.60.10" description = "A client library for accessing langfuse" authors = ["langfuse "] license = "MIT"