feat(bundles): consolidate langwatch evaluator into lfx-bundles

langwatch -> lfx_bundles/langwatch (1 component). The LangWatchComponent is a
pure httpx REST wrapper (its only non-core touchpoint is lfx.base.langwatch.utils,
which is also httpx-based) — the langwatch SDK extra in langflow-base is for the
tracing service, not this component, so the bundle declares no extra deps.

Moves + shim + `all` regen; 4 migration entries (0 ambiguous). Component index
23->22 categories, 141->140 components. Backend langwatch test repointed
(16 passed). SKIP=detect-secrets: only flags are regenerated component_index
code_hash hex (false positives).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Eric Hare
2026-06-16 12:51:13 -07:00
parent b97579cfff
commit 594e4db2fc
9 changed files with 63 additions and 268 deletions

View File

@ -155,6 +155,9 @@ PROVIDER_DEPS: dict[str, list[str]] = {
"cuga>=0.2.20,<0.3.0; sys_platform != 'darwin' and python_version < '3.14'",
"cuga>=0.2.20,<0.3.0; sys_platform == 'darwin' and platform_machine == 'arm64' and python_version < '3.14'",
],
# --- tranche 9: langwatch evaluator (pure httpx REST; the langwatch SDK extra
# is for the tracing service, not this component) ---
"langwatch": [],
}
_OPTIONAL_DEPS_HEADER = (

View File

@ -7,9 +7,9 @@ import pytest
import respx
from httpx import Response
from lfx.base.langwatch.utils import get_cached_evaluators
from lfx.components.langwatch.langwatch import LangWatchComponent
from lfx.schema.data import Data
from lfx.schema.dotdict import dotdict
from lfx_bundles.langwatch.langwatch import LangWatchComponent
from tests.base import ComponentTestBaseWithoutClient
@ -94,7 +94,7 @@ class TestLangWatchComponent(ComponentTestBaseWithoutClient):
"""Clear the LRU cache before each test."""
get_cached_evaluators.cache_clear()
@patch("lfx.components.langwatch.langwatch.httpx.get")
@patch("lfx_bundles.langwatch.langwatch.httpx.get")
async def test_set_evaluators_success(self, mock_get, component, mock_evaluators):
"""Test successful setting of evaluators."""
mock_response = Mock()
@ -106,7 +106,7 @@ class TestLangWatchComponent(ComponentTestBaseWithoutClient):
component.set_evaluators(endpoint)
assert component.evaluators == mock_evaluators
@patch("lfx.components.langwatch.langwatch.httpx.get")
@patch("lfx_bundles.langwatch.langwatch.httpx.get")
async def test_set_evaluators_empty_response(self, mock_get, component):
"""Test setting evaluators with empty response."""
mock_response = Mock()
@ -196,7 +196,7 @@ class TestLangWatchComponent(ComponentTestBaseWithoutClient):
# Should set the selected evaluator
assert result["evaluator_name"]["value"] == "test_evaluator"
@patch("lfx.components.langwatch.langwatch.httpx.get")
@patch("lfx_bundles.langwatch.langwatch.httpx.get")
@respx.mock
async def test_evaluate_success(self, mock_get, component, mock_evaluators):
"""Test successful evaluation."""
@ -248,7 +248,7 @@ class TestLangWatchComponent(ComponentTestBaseWithoutClient):
assert isinstance(result, Data)
assert "No evaluator selected" in result.data["error"]
@patch("lfx.components.langwatch.langwatch.httpx.get")
@patch("lfx_bundles.langwatch.langwatch.httpx.get")
@respx.mock
async def test_evaluate_evaluator_not_found(self, mock_get, component, mock_evaluators):
"""Test evaluation with non-existent evaluator."""
@ -266,7 +266,7 @@ class TestLangWatchComponent(ComponentTestBaseWithoutClient):
assert isinstance(result, Data)
assert "Selected evaluator 'non_existent_evaluator' not found" in result.data["error"]
@patch("lfx.components.langwatch.langwatch.httpx.get")
@patch("lfx_bundles.langwatch.langwatch.httpx.get")
@respx.mock
async def test_evaluate_http_error(self, mock_get, component, mock_evaluators):
"""Test evaluation with HTTP error."""
@ -290,7 +290,7 @@ class TestLangWatchComponent(ComponentTestBaseWithoutClient):
assert isinstance(result, Data)
assert "Evaluation error" in result.data["error"]
@patch("lfx.components.langwatch.langwatch.httpx.get")
@patch("lfx_bundles.langwatch.langwatch.httpx.get")
@respx.mock
async def test_evaluate_with_tracing(self, mock_get, component, mock_evaluators):
"""Test evaluation with tracing service."""
@ -333,7 +333,7 @@ class TestLangWatchComponent(ComponentTestBaseWithoutClient):
assert isinstance(result, Data)
assert result.data == expected_response
@patch("lfx.components.langwatch.langwatch.httpx.get")
@patch("lfx_bundles.langwatch.langwatch.httpx.get")
@respx.mock
async def test_evaluate_with_contexts_parsing(self, mock_get, component, mock_evaluators):
"""Test evaluation with contexts parsing."""
@ -371,7 +371,7 @@ class TestLangWatchComponent(ComponentTestBaseWithoutClient):
assert isinstance(result, Data)
assert result.data == expected_response
@patch("lfx.components.langwatch.langwatch.httpx.get")
@patch("lfx_bundles.langwatch.langwatch.httpx.get")
@respx.mock
async def test_evaluate_timeout_handling(self, mock_get, component, mock_evaluators):
"""Test evaluation with timeout."""

View File

@ -56,6 +56,7 @@ homeassistant = ["requests>=2.32.0"]
huggingface = ["langchain-huggingface~=1.2.0; sys_platform != 'darwin' or platform_machine != 'x86_64'", "huggingface-hub[inference]>=1.0.0,<2.0.0", "langchain-community>=0.4.1,<1.0.0"]
icosacomputing = ["requests>=2.32.0"]
jigsawstack = ["jigsawstack==0.2.7"]
langwatch = []
litellm = ["langchain-openai>=1.1.6", "openai>=1.68.2,<3.0.0"]
lmstudio = ["langchain-openai>=1.1.6", "openai>=1.68.2,<3.0.0", "langchain-nvidia-ai-endpoints~=1.0.0"]
maritalk = ["langchain-community>=0.4.1,<1.0.0"]
@ -126,6 +127,7 @@ all = [
"lfx-bundles[huggingface]",
"lfx-bundles[icosacomputing]",
"lfx-bundles[jigsawstack]",
"lfx-bundles[langwatch]",
"lfx-bundles[litellm]",
"lfx-bundles[lmstudio]",
"lfx-bundles[maritalk]",

View File

@ -0,0 +1,3 @@
from .langwatch import LangWatchComponent
__all__ = ["LangWatchComponent"]

View File

@ -3,7 +3,6 @@ import os
from typing import Any
import httpx
from lfx.base.langwatch.utils import get_cached_evaluators
from lfx.custom.custom_component.component import Component
from lfx.inputs.inputs import MultilineInput

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,22 @@
from .langwatch import LangWatchComponent
# lfx-bundles-shim
"""Compatibility shim: lfx.components.langwatch moved to lfx-bundles.
__all__ = ["LangWatchComponent"]
This module re-points to the installed bundle distribution. It contains
no component implementations and no third-party dependencies, and is
removed once the deprecation window closes (M4).
"""
import importlib
import sys
try:
sys.modules[__name__] = importlib.import_module("lfx_bundles.langwatch")
except ModuleNotFoundError as exc:
if exc.name is not None and (exc.name == "lfx_bundles" or exc.name.startswith("lfx_bundles.")):
msg = (
"The 'langwatch' components moved to the 'lfx-bundles' distribution. "
"Install it with: pip install lfx-bundles "
"(or 'pip install langflow', which bundles it)."
)
raise ModuleNotFoundError(msg, name="lfx_bundles") from exc
raise

View File

@ -4560,6 +4560,26 @@
"legacy_slot": "ext:cuga:CugaComponent@official-pre-a",
"target": "ext:cuga:CugaComponent@official",
"added_in": "1.11.0"
},
{
"bare_class_name": "LangWatchComponent",
"target": "ext:langwatch:LangWatchComponent@official",
"added_in": "1.11.0"
},
{
"import_path": "lfx.components.langwatch.langwatch.LangWatchComponent",
"target": "ext:langwatch:LangWatchComponent@official",
"added_in": "1.11.0"
},
{
"import_path": "lfx.components.langwatch.LangWatchComponent",
"target": "ext:langwatch:LangWatchComponent@official",
"added_in": "1.11.0"
},
{
"legacy_slot": "ext:langwatch:LangWatchComponent@official-pre-a",
"target": "ext:langwatch:LangWatchComponent@official",
"added_in": "1.11.0"
}
],
"ambiguous_bare_names": [

3
uv.lock generated
View File

@ -9546,6 +9546,7 @@ requires-dist = [
{ name = "lfx-bundles", extras = ["huggingface"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
{ name = "lfx-bundles", extras = ["icosacomputing"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
{ name = "lfx-bundles", extras = ["jigsawstack"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
{ name = "lfx-bundles", extras = ["langwatch"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
{ name = "lfx-bundles", extras = ["litellm"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
{ name = "lfx-bundles", extras = ["lmstudio"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
{ name = "lfx-bundles", extras = ["maritalk"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
@ -9623,7 +9624,7 @@ requires-dist = [
{ name = "youtube-transcript-api", marker = "extra == 'youtube'", specifier = ">=1.0.0,<2.0.0" },
{ name = "zep-python", marker = "extra == 'zep'", specifier = "==2.0.2" },
]
provides-extras = ["agentql", "aiml", "altk", "apify", "assemblyai", "azure", "baidu", "bing", "chroma", "cleanlab", "clickhouse", "cloudflare", "codeagents", "cometapi", "composio", "confluence", "couchbase", "cuga", "deepseek", "elastic", "exa", "firecrawl", "git", "glean", "google", "groq", "homeassistant", "huggingface", "icosacomputing", "jigsawstack", "litellm", "lmstudio", "maritalk", "mem0", "milvus", "mistral", "mongodb", "needle", "novita", "nvidia", "olivya", "ollama", "openrouter", "perplexity", "pgvector", "pinecone", "qdrant", "redis", "sambanova", "scrapegraph", "searchapi", "serpapi", "spider", "supabase", "tavily", "toolguard", "twelvelabs", "unstructured", "upstash", "vectara", "vertexai", "vllm", "weaviate", "wikipedia", "wolframalpha", "xai", "yahoosearch", "youtube", "zep", "all"]
provides-extras = ["agentql", "aiml", "altk", "apify", "assemblyai", "azure", "baidu", "bing", "chroma", "cleanlab", "clickhouse", "cloudflare", "codeagents", "cometapi", "composio", "confluence", "couchbase", "cuga", "deepseek", "elastic", "exa", "firecrawl", "git", "glean", "google", "groq", "homeassistant", "huggingface", "icosacomputing", "jigsawstack", "langwatch", "litellm", "lmstudio", "maritalk", "mem0", "milvus", "mistral", "mongodb", "needle", "novita", "nvidia", "olivya", "ollama", "openrouter", "perplexity", "pgvector", "pinecone", "qdrant", "redis", "sambanova", "scrapegraph", "searchapi", "serpapi", "spider", "supabase", "tavily", "toolguard", "twelvelabs", "unstructured", "upstash", "vectara", "vertexai", "vllm", "weaviate", "wikipedia", "wolframalpha", "xai", "yahoosearch", "youtube", "zep", "all"]
[[package]]
name = "lfx-cohere"