Works with the AI Agents you already use

    Claude CodeClaude CodeCursorCursorCodex CLICodex CLIMuseMuseDotsDots+22 more

    Building Langflow Components — Safe, Tested, Forever-Named

    1

    Ship Langflow Components safely: permanent names, typed inputs/outputs, AI runtime rules, ComponentTestBase tests.

    Free

    Security scanned
    Building Langflow Components — Safe, Tested, Forever-Named

    Building Langflow Components — Safe, Tested, Forever-Named

    Example session with this skill installed

    In our Langflow checkout we already maintain the acme bundle (src/bundles/acme/, package lfx_acme, has AcmeChatModelComponent). Add a component for Acme's moderation API so flows can check text before sending it to a model.

    API (from Acme's docs):

    POST https://moderation.acme.example/v1/check
    Authorization: Bearer <api key>
    Body:     { "text": "<string>" }
    200:      { "flagged": true, "categories": ["harassment"] }
    401 bad key · 429 rate limited · 5xx server error
    
    • Read your context and instructions
    • Compiled the building langflow components

    Summary. This is a niche partner integration, and the acme bundle already exists. So the component goes into that bundle and needs no new bundle or RFC. The class name AcmeModerationComponent and the input and output names below are permanent: please confirm them before this merges. The component calls an AI service, so it has an explicit timeout, maps HTTP failures to clear messages on the node, and never logs the text or the key.

    Placement and names (decide once)

    File: src/bundles/acme/src/lfx_acme/components/acme/acme_moderation.py. Before creating it, check that no existing Acme component already wraps /v1/check.

    • Class: AcmeModerationComponent, following <Provider><Capability>Component.
    • Inputs: api_key, input_value, timeout_seconds. Output: moderation_result.

    Icon: "shield-check" (Lucide). If AcmeChatModelComponent uses a custom Acme SVG, use that instead so the bundle stays consistent.

    Component

    import time
    from typing import NoReturn
    
    from langflow.custom import Component
    from langflow.io import IntInput, MessageTextInput, Output, SecretStrInput
    from langflow.schema import Data
    from loguru import logger
    
    MODERATION_URL = "https://moderation.acme.example/v1/check"
    STATUS_MESSAGES = {
        401: "Acme rejected the API key. Check your secret.",
        429: "Acme rate limit reached. Try again later.",
    }
    
    def _status_message(status_code: int) -> str:
        return STATUS_MESSAGES.get(status_code, f"Acme Moderation failed: HTTP {status_code}")
    
    class AcmeModerationComponent(Component):
        display_name = "Acme Moderation"
        description = "Check text with Acme's moderation API and return whether it was flagged."
        icon = "shield-check"
        documentation = "https://moderation.acme.example/docs"
    
        inputs = [
            SecretStrInput(
                name="api_key",
                display_name="API Key",
                info="Acme Moderation API key. Stored encrypted.",
                required=True,
            ),
            MessageTextInput(name="input_value", display_name="Text", required=True),
            IntInput(name="timeout_seconds", display_name="Timeout (s)", value=10, advanced=True),
        ]
    
        outputs = [
            Output(display_name="Moderation Result", name="moderation_result", method="check_text"),
        ]
    
        def check_text(self) -> Data:
            import httpx
    
            start = time.monotonic()
            try:
                response = httpx.post(
                    MODERATION_URL,
                    headers={"Authorization": f"Bearer {self.api_key}"},
                    json={"text": self.input_value},
                    timeout=self.timeout_seconds,
                )
                response.raise_for_status()
            except httpx.TimeoutException as exc:
                self._fail(f"Acme Moderation timed out after {self.timeout_seconds}s.", "timeout", start, exc)
            except httpx.HTTPStatusError as exc:
                self._fail(_status_message(exc.response.status_code), "http_error", start, exc)
            except httpx.RequestError as exc:
                self._fail("Could not reach Acme Moderation.", "unreachable", start, exc)
    
            body = response.json()
            logger.info(
                "acme.moderation",
                outcome="success",
                text_chars=len(self.input_value),
                duration_ms=int((time.monotonic() - start) * 1000),
            )
            return Data(data={"flagged": bool(body["flagged"]), "categories": list(body.get("categories", []))})
    
        def _fail(self, message: str, outcome: str, start: float, exc: Exception) -> NoReturn:
            logger.warning(
                "acme.moderation",
                outcome=outcome,
                duration_ms=int((time.monotonic() - start) * 1000),
            )
            self.status = message
            raise ValueError(message) from exc
    

    httpx is imported inside the method, so loading the bundle never fails because of it. The logs record the outcome, the text length and the duration. They never record the text, the response or the key. There are no retries: none are implemented by hand, and with no Acme SDK there is nothing to delegate them to. A flow that needs retries can add them around the node.

    Registration and changelog

    • Add AcmeModerationComponent to src/bundles/acme/src/lfx_acme/components/acme/__init__.py, keeping the alphabetical order.
    • Add httpx to the bundle's pyproject.toml with a compatible range, unless langflow-base already provides it.
    • In src/bundles/acme/BUNDLE_API.md, under ## [Unreleased] → ### Added: `AcmeModerationComponent`: check text with Acme's moderation API (`/v1/check`).

    Tests (src/bundles/acme/tests/unit/components/test_acme_moderation.py)

    import os
    
    import httpx
    import pytest
    from langflow.schema import Data
    from lfx_acme.components.acme.acme_moderation import AcmeModerationComponent
    
    from tests.base import ComponentTestBaseWithoutClient
    
    class TestAcmeModerationComponent(ComponentTestBaseWithoutClient):
        @pytest.fixture
        def component_class(self):
            return AcmeModerationComponent
    
        @pytest.fixture
        def default_kwargs(self):
            return {"api_key": "test-key", "input_value": "Hello there", "timeout_seconds": 10}
    
        @pytest.fixture
        def file_names_mapping(self):
            return {}
    
        @pytest.mark.api_key_required
        def test_should_return_moderation_data_when_called_against_real_api(self, component_class, default_kwargs):
            default_kwargs["api_key"] = os.environ["ACME_MODERATION_API_KEY"]
            result = component_class(**default_kwargs).check_text()
            assert isinstance(result, Data)
            assert isinstance(result.data["flagged"], bool)
    
        def test_should_raise_value_error_when_request_times_out(self, component_class, default_kwargs, mocker):
            mocker.patch("httpx.post", side_effect=httpx.ReadTimeout("slow"))
            component = component_class(**default_kwargs)
            with pytest.raises(ValueError, match="timed out after 10s"):
                component.check_text()
            assert "timed out" in component.status
    
        def test_should_report_rate_limit_when_api_returns_429(self, component_class, default_kwargs, mocker):
            request = httpx.Request("POST", "https://moderation.acme.example/v1/check")
            mocker.patch("httpx.post", return_value=httpx.Response(429, request=request))
            component = component_class(**default_kwargs)
            with pytest.raises(ValueError, match="rate limit"):
                component.check_text()
    

    The real API test is the main check. Mocks cover only the timeout and the 429, which a sandbox can't reliably reproduce, as Langflow's testing policy recommends. The base class's automatic tests (instantiation, inputs, outputs) run from the three fixtures.

    Commands to run (not executed here)

    LFX_DEV=acme make backend      # the component should appear in the sidebar; drag it onto a flow
    uv sync --group dev --package lfx-acme
    uv run pytest src/bundles/acme/tests/ -v
    make format_backend && uv run git commit
    

    The expected outcome: the two mocked tests pass, and the api_key_required test is skipped unless ACME_MODERATION_API_KEY is set. None of this has been run yet.

    Next steps

    1. Confirm the class, input and output names. After the merge they can't change.
    2. Run the commands above. Check that the node renders and that a 401 shows "Acme rejected the API key" on the node.
    3. Learning capture: nothing new beyond SKILL.md and AGENTS.md came up, so no learnings/ entry was written.
    nothing new beyond SKILL.md and AGENTS.md

    Connects securely to your tools. The creator never sees your data.

    About this skill

    Building Langflow Components is a workflow skill for creating and shipping custom Components for Langflow, the visual builder for LLM flows. A Component is a Python class that appears as a node in the flow editor. Its class name and its input and output names are stored in every saved flow, so a careless rename breaks other people's work without any warning.

    Problems it solves

    • Renamed classes or inputs that delete a component from every saved flow.
    • MessageTextInput used for API keys, so they are stored in clear text.
    • SDK clients created at import time, which crash the whole backend.
    • LLM calls without a timeout that hang a flow.
    • Raw prompts and keys in logs.
    • Niche components placed in langflow-base.
    • Bundle changes that fail the BUNDLE_API.md changelog check.

    The 12-step workflow. Each step ends with a check you can verify:

    1. Decide between bundle and base.
    2. Choose a class name you can keep forever (<Provider><Capability>Component).
    3. Pick the icon.
    4. Define inputs and outputs with permanent names.
    5. Implement the output methods, importing the SDK inside the method.
    6. Apply the AI runtime rules (explicit timeout, mapped errors, redaction).
    7. Hot-reload with LFX_DEV.
    8. Test with ComponentTestBaseWith[out]Client and its three required fixtures.
    9. Prefer real integrations marked api_key_required.
    10. Register the component.
    11. Commit with uv run git commit.
    12. Record a learning.

    References

    • component-anatomy.md: tool, Data, DataFrame and multi-output shapes, plus deprecating without breaking flows.
    • io-reference.md: every input and output type.
    • testing.md: base classes, fixtures, marks, real integrations vs mocks.
    • ai-component-patterns.md: timeouts, retries, error mapping, streaming, token accounting, redaction.
    • icons.md: wiring a custom SVG icon.
    • bundles.md: bundle layout and the BUNDLE_API.md changelog check.

    When it triggers. "Create a component", "add an OpenAI/Anthropic/Chroma integration", "wrap this LangChain class as a Component".

    This is a community skill, not affiliated with or endorsed by the Langflow project. Free and MIT-licensed. Part of the claude-skills-czl collection.

    Source on GitHub: this skill · full repository

    How to use

    Skills on Agensi run inside your AI agent. Copy the prompt, paste it into your agent, and it connects to Agensi and installs this skill for you. If a payment is needed, your agent shows it to you first.

    Reviews

    No reviews yet

    Be one of the first to try it. Every listed skill passes our trust checks below.

    Security scanned

    Passed our 8-point scan before listing

    Fresh listing

    Recently published to Agensi

    Free forever

    No account required to browse

    Trust & safety

    Security scanned

    Verified clean 11 days ago

    • Free to download with an account

    Listed11 days ago

    What's inside

    Frequently Asked Questions