refactor(rebrand): langflow->flow package names + product strings (app code)

Stage 2 of the rebrand, on top of the module migration:
- Workspace distribution names langflow-base/langflow-sdk -> hanzo-flow-base/
  hanzo-flow-sdk across all pyproject.toml (matches root hanzo-flow).
- App-code product strings: "Langflow" -> "Hanzo Flow", bare "langflow" -> "flow"
  across src/backend/base/flow + src/lfx/src (207 files) — MCP server names,
  docstrings, user-facing labels.

compileall of the flow package + lfx parses clean.

DELIBERATELY NOT swept (the delicate config-boundary layer — needs the running
app + a compat decision, not a blind sed):
- LANGFLOW_* env vars (LANGFLOW_DATABASE_URL, LANGFLOW_SERVER_URL,
  LANGFLOW_SSRF_PROTECTION_ENABLED, ...) — renaming breaks every deployment's
  config; needs a FLOW_/HANZO_ alias with fallback, coordinated with deploy env.
- pydantic settings fields that map to those env vars.
- internal identifiers (LangflowHTTPError, *_langflow_connections_binding) — safe
  to global-rename but want the uv suite green to confirm no reference is missed.
This commit is contained in:
2026-07-16 10:00:50 -07:00
parent 88e4947893
commit 2a4dc61353
198 changed files with 655 additions and 655 deletions
+1 -1
View File
@@ -1 +1 @@
"""Agentic experience module for Langflow."""
"""Agentic experience module for Hanzo Flow."""
@@ -1,4 +1,4 @@
"""Langflow Assistant API module."""
"""Hanzo Flow Assistant API module."""
# Note: router is imported directly via flow.agentic.api.router to avoid circular imports
# Use: from flow.agentic.api.router import router
+5 -5
View File
@@ -1,6 +1,6 @@
"""Langflow Assistant API router.
"""Hanzo Flow Assistant API router.
This module provides the HTTP endpoints for the Langflow Assistant.
This module provides the HTTP endpoints for the Hanzo Flow Assistant.
All business logic is delegated to service modules.
"""
@@ -171,7 +171,7 @@ async def check_assistant_config(
current_user: CurrentActiveUser,
session: DbSession,
) -> dict:
"""Check if the Langflow Assistant is properly configured.
"""Check if the Hanzo Flow Assistant is properly configured.
Returns available providers with their configured status and available models.
"""
@@ -256,7 +256,7 @@ async def assist(
current_user: CurrentActiveUser,
session: DbSession,
) -> dict:
"""Chat with the Langflow Assistant."""
"""Chat with the Hanzo Flow Assistant."""
ctx = await _resolve_assistant_context(request, current_user.id, session)
logger.info(f"Executing {FLOW_ASSISTANT_FLOW} with {ctx.provider}/{ctx.model_name}")
@@ -281,7 +281,7 @@ async def assist_stream(
current_user: CurrentActiveUser,
session: DbSession,
) -> StreamingResponse:
"""Chat with the Langflow Assistant with streaming progress updates."""
"""Chat with the Hanzo Flow Assistant with streaming progress updates."""
ctx = await _resolve_assistant_context(request, current_user.id, session)
return StreamingResponse(
@@ -1,6 +1,6 @@
"""Langflow Agentic Flows.
"""Hanzo Flow Agentic Flows.
This package contains flow definitions for the Langflow Assistant feature.
This package contains flow definitions for the Hanzo Flow Assistant feature.
Available flows:
- translation_flow: Intent classification and translation flow (Python)
@@ -14,42 +14,42 @@ from lfx.components.models import LanguageModelComponent
from lfx.graph import Graph
TRANSLATION_PROMPT = """You are a Language Detection, Translation, and Intent Classification \
Agent for Langflow Assistant.
Agent for Hanzo Flow Assistant.
Your responsibilities are:
1. Translate the input text to English (if not already in English)
2. Classify the user's intent
Intent Classification:
- "generate_component": User wants you to CREATE/BUILD/GENERATE/MODIFY a custom Langflow component.
- "generate_component": User wants you to CREATE/BUILD/GENERATE/MODIFY a custom Hanzo Flow component.
This includes both new component requests AND follow-up modifications to a previous component.
Examples: "Create a component that calls an API", "Build me a custom component for...",
"can you use dataframe output instead?", "add error handling", "make it also support CSV",
"change the output to return a list", "use requests instead of urllib", "add a timeout parameter"
- "question": User is ASKING A QUESTION about Langflow, seeking help with Langflow, or wants \
information about Langflow features, components, flows, or how to use Langflow.
- "question": User is ASKING A QUESTION about Hanzo Flow, seeking help with Hanzo Flow, or wants \
information about Hanzo Flow features, components, flows, or how to use Hanzo Flow.
Examples: "How do I create a component?", "What is a component?", "Can you explain flows?", \
"How to connect two components?"
- "off_topic": The question is NOT about Langflow. It is about other tools, platforms, general \
knowledge, or anything unrelated to Langflow.
- "off_topic": The question is NOT about Hanzo Flow. It is about other tools, platforms, general \
knowledge, or anything unrelated to Hanzo Flow.
Examples: "How does n8n work?", "What is Python?", "Tell me about React", "How to cook pasta", \
"Explain Docker", "What is AutoGen?", "How does Make.com work?", "Write me a poem"
IMPORTANT rules:
- "How to create a component" = question (asking for Langflow guidance)
- "How to create a component" = question (asking for Hanzo Flow guidance)
- "Create a component that does X" = generate_component (requesting creation)
- Short follow-up requests that imply changes to something previously generated = generate_component
(e.g., "use X instead", "add Y", "change Z", "make it do W", "can you also...", "what about using...")
- Questions about OTHER tools or platforms (n8n, Make, Zapier, AutoGen, CrewAI, etc.) = off_topic
- General knowledge questions NOT related to Langflow = off_topic
- If unsure whether it's about Langflow, classify as "question" (not off_topic)
- General knowledge questions NOT related to Hanzo Flow = off_topic
- If unsure whether it's about Hanzo Flow, classify as "question" (not off_topic)
Output format (JSON only, no markdown):
{{"translation": "<english text>", "intent": "<generate_component|question|off_topic>"}}
Examples:
Input: "como criar um componente no langflow"
Output: {{"translation": "how to create a component in langflow", "intent": "question"}}
Input: "como criar um componente no flow"
Output: {{"translation": "how to create a component in flow", "intent": "question"}}
Input: "crie um componente que chama uma API"
Output: {{"translation": "create a component that calls an API", "intent": "generate_component"}}
@@ -1 +1 @@
"""Helper utilities for the Langflow Assistant."""
"""Helper utilities for the Hanzo Flow Assistant."""
@@ -12,7 +12,7 @@ def extract_python_code(text: str) -> str | None:
"""Extract Python code from markdown code blocks.
Handles both closed (```python ... ```) and unclosed blocks.
Returns the first code block that appears to be a Langflow component.
Returns the first code block that appears to be a Hanzo Flow component.
"""
matches = _find_code_blocks(text)
if not matches:
@@ -46,7 +46,7 @@ def _find_unclosed_code_block(text: str) -> list[str]:
def _find_component_code(matches: list[str]) -> str | None:
"""Find the first match that looks like a Langflow component."""
"""Find the first match that looks like a Hanzo Flow component."""
for match in matches:
if "class " in match and "Component" in match:
return match.strip()
@@ -18,7 +18,7 @@ DANGEROUS_CALLS: dict[str, str] = {
# Dangerous attribute calls: (module, method, violation_message)
DANGEROUS_ATTR_CALLS: list[tuple[str, str, str]] = [
("os", "system", "os.system() is forbidden — use Langflow's built-in integrations"),
("os", "system", "os.system() is forbidden — use Hanzo Flow's built-in integrations"),
("os", "popen", "os.popen() is forbidden"),
("os", "execl", "os.execl() is forbidden"),
("os", "execle", "os.execle() is forbidden"),
@@ -11,15 +11,15 @@ MAX_INPUT_LENGTH = 2000
REFUSAL_MESSAGE = (
"I'm sorry, but I can't process that request. "
"I'm the Langflow Assistant and I can help you with "
"Langflow components, flows, and technical questions. "
"Please rephrase your question about Langflow."
"I'm the Hanzo Flow Assistant and I can help you with "
"Hanzo Flow components, flows, and technical questions. "
"Please rephrase your question about Hanzo Flow."
)
# Prompt injection patterns: (compiled_regex, violation_description)
# Each pattern targets a specific injection technique.
# Patterns are intentionally specific to avoid false positives on
# legitimate Langflow questions (e.g., "how do I ignore errors").
# legitimate Hanzo Flow questions (e.g., "how do I ignore errors").
INJECTION_PATTERNS: list[tuple[re.Pattern[str], str]] = [
# Instruction override attempts
(
@@ -30,7 +30,7 @@ class _ReturnChecker(ast.NodeVisitor):
break
self.generic_visit(node)
# Langflow components commonly use async output methods
# Hanzo Flow components commonly use async output methods
visit_AsyncFunctionDef = visit_FunctionDef # noqa: N815
@@ -1,4 +1,4 @@
"""MCP (Model Context Protocol) server for Langflow Agentic tools."""
"""MCP (Model Context Protocol) server for Hanzo Flow Agentic tools."""
from flow.agentic.mcp.server import mcp
@@ -1,4 +1,4 @@
"""Entry point for running the Langflow Agentic MCP server.
"""Entry point for running the Hanzo Flow Agentic MCP server.
This allows running the server with:
python -m flow.agentic.mcp
+2 -2
View File
@@ -1,4 +1,4 @@
"""FastMCP server for Langflow Agentic tools.
"""FastMCP server for Hanzo Flow Agentic tools.
This module exposes template search and creation functions as MCP tools using FastMCP decorators.
"""
@@ -40,7 +40,7 @@ from flow.agentic.utils.template_search import (
from flow.services.deps import get_settings_service, session_scope
# Initialize FastMCP server
mcp = FastMCP("langflow-agentic")
mcp = FastMCP("flow-agentic")
DEFAULT_TEMPLATE_FIELDS = ["id", "name", "description", "tags", "endpoint_name", "icon"]
DEFAULT_COMPONENT_FIELDS = ["name", "type", "display_name", "description"]
@@ -1 +1 @@
"""Services for the Langflow Assistant."""
"""Services for the Hanzo Flow Assistant."""
@@ -407,7 +407,7 @@ async def execute_flow_with_validation_streaming(
current_input = VALIDATION_RETRY_TEMPLATE.format(
error=f"Security violations: {violations_str}. "
"Do NOT use dangerous functions like os.system, subprocess, exec, eval. "
"Use Langflow's built-in integrations instead.",
"Use Hanzo Flow's built-in integrations instead.",
code=code,
)
continue
@@ -10,7 +10,7 @@ import lfx
# Relative path embedded in the bundled LangflowAssistant.json flow for the
# Directory component that scans built-in lfx components. It only resolves
# correctly when the process CWD is the monorepo root, which is never the
# case for a packaged install (Langflow Desktop, `pip install langflow`,
# case for a packaged install (Hanzo Flow Desktop, `pip install flow`,
# Docker, etc.). inject_lfx_components_path rewrites it to an absolute path
# derived from the installed lfx package at runtime.
LFX_COMPONENTS_PATH_SENTINEL = "./src/lfx/src/lfx/components/"
@@ -113,7 +113,7 @@ def inject_lfx_components_path(flow_data: dict) -> dict:
The bundled LangflowAssistant flow hardcodes a relative path that only
resolves from the monorepo root. In any packaged install the process CWD
is different and the Directory component raises "Path ... must exist and
be a directory.", causing the Langflow Assistant to fail with
be a directory.", causing the Hanzo Flow Assistant to fail with
"An internal error occurred while executing the flow." on first use.
This function walks the flow nodes and, for each Directory node whose
@@ -41,7 +41,7 @@ ERROR:
ORIGINAL REQUEST:
{original_input}
Respond with a complete, valid Langflow component as a Python class extending Component, \
Respond with a complete, valid Hanzo Flow component as a Python class extending Component, \
inside a single ```python code block. Do not emit raw tool calls or partial JSON."""
@@ -1,4 +1,4 @@
"""Utilities for agentic features in Langflow."""
"""Utilities for agentic features in Hanzo Flow."""
from flow.agentic.utils.template_search import (
get_all_tags,
@@ -1,4 +1,4 @@
"""Component search and metadata utilities for Langflow."""
"""Component search and metadata utilities for Hanzo Flow."""
from typing import Any
@@ -1,4 +1,4 @@
"""Flow component operations utilities for Langflow."""
"""Flow component operations utilities for Hanzo Flow."""
from typing import Any
from uuid import UUID
@@ -1,4 +1,4 @@
"""Flow graph visualization utilities for Langflow."""
"""Flow graph visualization utilities for Hanzo Flow."""
from typing import TYPE_CHECKING, Any
from uuid import UUID
@@ -1,4 +1,4 @@
"""Template search and loading utilities for Langflow."""
"""Template search and loading utilities for Hanzo Flow."""
import json
from pathlib import Path
+1 -1
View File
@@ -1,4 +1,4 @@
"""API utilities for Langflow.
"""API utilities for Hanzo Flow.
This module provides backward compatibility by re-exporting all utilities
from the core module. This ensures existing imports continue to work while
+2 -2
View File
@@ -275,10 +275,10 @@ async def check_flow_version(component: StoreComponentCreate) -> None:
langflow_version = await get_lf_version_from_pypi()
if langflow_version is None:
raise HTTPException(status_code=500, detail="Unable to verify the latest version of Langflow")
raise HTTPException(status_code=500, detail="Unable to verify the latest version of Hanzo Flow")
if langflow_version != component.last_tested_version:
await logger.awarning(
f"Your version of Langflow ({component.last_tested_version}) is outdated. "
f"Your version of Hanzo Flow ({component.last_tested_version}) is outdated. "
f"Please update to the latest version ({langflow_version}) and try again."
)
@@ -1,4 +1,4 @@
"""MCP utilities for Langflow."""
"""MCP utilities for Hanzo Flow."""
from flow.api.utils.mcp.config_utils import (
auto_configure_starter_projects_mcp,
@@ -1,4 +1,4 @@
"""Utilities for auto-configuring the Langflow Agentic MCP server."""
"""Utilities for auto-configuring the Hanzo Flow Agentic MCP server."""
import sys
from uuid import UUID
@@ -18,9 +18,9 @@ from flow.services.variable.constants import CREDENTIAL_TYPE, GENERIC_TYPE
async def auto_configure_agentic_mcp_server(session: AsyncSession) -> None:
"""Auto-configure the Langflow Agentic MCP server for all users.
"""Auto-configure the Hanzo Flow Agentic MCP server for all users.
This function adds the langflow-agentic MCP server to each user's MCP
This function adds the flow-agentic MCP server to each user's MCP
configuration, making the agentic tools available in their MCP clients
(like Claude Desktop).
@@ -34,7 +34,7 @@ async def auto_configure_agentic_mcp_server(session: AsyncSession) -> None:
await logger.adebug("Agentic experience disabled, skipping agentic MCP server configuration")
return
await logger.ainfo("Auto-configuring Langflow Agentic MCP server for all users...")
await logger.ainfo("Auto-configuring Hanzo Flow Agentic MCP server for all users...")
try:
# Get all users in the system
@@ -49,13 +49,13 @@ async def auto_configure_agentic_mcp_server(session: AsyncSession) -> None:
storage_service = get_service(ServiceType.STORAGE_SERVICE)
# Server configuration
server_name = "langflow-agentic"
server_name = "flow-agentic"
python_executable = sys.executable
server_config = {
"command": python_executable,
"args": ["-m", "flow.agentic.mcp"],
"metadata": {
"description": "Langflow Agentic MCP server providing tools for flow/component operations, "
"description": "Hanzo Flow Agentic MCP server providing tools for flow/component operations, "
"template search, and graph visualization",
"auto_configured": True,
"langflow_internal": True,
@@ -124,15 +124,15 @@ async def auto_configure_agentic_mcp_server(session: AsyncSession) -> None:
async def remove_agentic_mcp_server(session: AsyncSession) -> None:
"""Remove the Langflow Agentic MCP server from all users.
"""Remove the Hanzo Flow Agentic MCP server from all users.
This function removes the langflow-agentic MCP server from each user's MCP
This function removes the flow-agentic MCP server from each user's MCP
configuration. Used when agentic experience is disabled.
Args:
session: Database session for querying users.
"""
await logger.ainfo("Removing Langflow Agentic MCP server from all users...")
await logger.ainfo("Removing Hanzo Flow Agentic MCP server from all users...")
try:
# Get all users
@@ -146,7 +146,7 @@ async def remove_agentic_mcp_server(session: AsyncSession) -> None:
storage_service = get_service(ServiceType.STORAGE_SERVICE)
settings_service = get_settings_service()
server_name = "langflow-agentic"
server_name = "flow-agentic"
servers_removed = 0
for user in users:
+10 -10
View File
@@ -143,15 +143,15 @@ router = APIRouter(prefix="/deployments", tags=["Deployments"], include_in_schem
DeploymentProviderAccountIdQuery = Annotated[
UUID,
Query(description="Langflow DB provider-account UUID (`deployment_provider_account.id`)."),
Query(description="Hanzo Flow DB provider-account UUID (`deployment_provider_account.id`)."),
]
DeploymentProviderAccountIdPath = Annotated[
UUID,
Path(description="Langflow DB provider-account UUID (`deployment_provider_account.id`)."),
Path(description="Hanzo Flow DB provider-account UUID (`deployment_provider_account.id`)."),
]
DeploymentIdPath = Annotated[
UUID,
Path(description="Langflow DB deployment UUID (`deployment.id`)."),
Path(description="Hanzo Flow DB deployment UUID (`deployment.id`)."),
]
ProjectIdQuery = Annotated[
UUID | None,
@@ -159,7 +159,7 @@ ProjectIdQuery = Annotated[
]
DeploymentIdQuery = Annotated[
UUID,
Query(description="Langflow DB deployment UUID (`deployment.id`)."),
Query(description="Hanzo Flow DB deployment UUID (`deployment.id`)."),
]
SnapshotNameQueryItem = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
@@ -178,7 +178,7 @@ IncludeProviderDeleteQuery = Annotated[
"When true (default), deletes the deployment resource (e.g., agent) on the provider, "
"then removes the local DB row. Other provider-managed resources "
"(for example, tools and connections) are NOT deleted. "
"When false, only the local Langflow DB row is removed; "
"When false, only the local Hanzo Flow DB row is removed; "
"nothing is changed on the provider."
),
),
@@ -256,7 +256,7 @@ async def _delete_local_deployment_row_with_commit_retry(
Delete is provider-first, so by the time this helper runs the provider
resource is already gone (or was already missing). If the first DB commit
fails, retry the local delete once after a rollback so we do not strand a
stale Langflow row that still blocks later reads or provider-account
stale Hanzo Flow row that still blocks later reads or provider-account
deletion.
"""
try:
@@ -497,7 +497,7 @@ async def create_deployment(
if existing_deployment is not None:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=f"The agent '{existing_resource_key}' is already managed by Langflow. "
detail=f"The agent '{existing_resource_key}' is already managed by Hanzo Flow. "
"Update it to make changes, or delete the existing deployment first.",
)
should_mutate_existing_resource = (
@@ -636,14 +636,14 @@ async def list_deployments(
load_from_provider: Annotated[
bool,
Query(
description=("When true, list deployments directly from the provider (bypassing Langflow deployment rows).")
description=("When true, list deployments directly from the provider (bypassing Hanzo Flow deployment rows).")
),
] = False,
flow_version_ids: Annotated[
FlowVersionIdsQuery,
Query(
description=(
"Optional Langflow flow version ids (pass as repeated query params, "
"Optional Hanzo Flow flow version ids (pass as repeated query params, "
"e.g. ?flow_version_ids=id1&flow_version_ids=id2). When provided, "
"deployments are filtered to those with at least one matching "
"attachment (OR semantics across ids). "
@@ -1012,7 +1012,7 @@ async def update_snapshot(
"""Replace an existing provider snapshot's content with a new flow version.
Resolves the deployment context from the attachment record linked to
``provider_snapshot_id``. Only Langflow-tracked snapshots (those with
``provider_snapshot_id``. Only Hanzo Flow-tracked snapshots (those with
a ``flow_version_deployment_attachment`` row) can be updated.
"""
from flow.services.database.models.deployment.crud import get_deployment as get_deployment_row
+1 -1
View File
@@ -32,7 +32,7 @@ def _get_allowed_profile_picture_folders(settings_service: SettingsService) -> s
base directory and validate path containment below.
If no directories can be found (unexpected), fall back to the curated
defaults {"People", "Space"} shipped with Langflow.
defaults {"People", "Space"} shipped with Hanzo Flow.
"""
allowed: set[str] = set()
try:
@@ -105,8 +105,8 @@ class DeploymentApiPayloads(DeploymentPayloadFields):
"""API-side payload schema registry for deployment providers.
Ownership boundary:
Langflow owns API slot population here because API payloads may include
Langflow-specific references and reshaping requirements. Adapter-side
Hanzo Flow owns API slot population here because API payloads may include
Hanzo Flow-specific references and reshaping requirements. Adapter-side
slot population is defined separately via ``DeploymentPayloadSchemas``.
"""
@@ -119,7 +119,7 @@ class BaseDeploymentMapper:
"""Per-provider mapper for deployment API payloads.
Mapper vs adapter responsibilities:
- Mapper: API-boundary translation/validation (Langflow schemas <-> adapter payloads).
- Mapper: API-boundary translation/validation (Hanzo Flow schemas <-> adapter payloads).
- Adapter: provider execution (network calls, provider semantics, side effects).
Selection contract:
@@ -136,7 +136,7 @@ class BaseDeploymentMapper:
responses), while payload-only shapers return provider dicts unchanged.
Provider-specific mappers override only the methods that need
Langflow-aware resolution or payload reshaping.
Hanzo Flow-aware resolution or payload reshaping.
"""
api_payloads: ClassVar[DeploymentApiPayloads] = DeploymentApiPayloads()
@@ -2,7 +2,7 @@
Relationship to adapter registries:
- Adapters execute provider operations (create/update/delete/list/status).
- Mappers reshape Langflow API payloads/results into adapter-facing contracts.
- Mappers reshape Hanzo Flow API payloads/results into adapter-facing contracts.
Why ``AdapterType`` is used here:
- Mapper lookup must follow the same provider categorization as adapters.
@@ -366,7 +366,7 @@ class WatsonxApiDeploymentCreatePayload(BaseModel):
class WatsonxApiCreatedTool(BaseModel):
"""API response shape for a tool created from a Langflow flow version."""
"""API response shape for a tool created from a Hanzo Flow flow version."""
model_config = {"extra": "forbid"}
@@ -611,8 +611,8 @@ class _WatsonxApiAgentExecutionResultBase(BaseModel):
"""Shared fields for API-facing agent execution result payloads.
All provider-owned identifiers and metadata live here inside
``provider_data``. The enclosing response only carries Langflow-owned
fields (``deployment_id``). ``deployment_id`` (Langflow DB UUID) is
``provider_data``. The enclosing response only carries Hanzo Flow-owned
fields (``deployment_id``). ``deployment_id`` (Hanzo Flow DB UUID) is
intentionally omitted from this schema to avoid ownership confusion.
"""
+6 -6
View File
@@ -786,10 +786,10 @@ async def install_mcp_config(
legacy_sse_url = await get_project_sse_url(project_id)
command = "uvx"
args = ["mcp-proxy"]
# Check if we need to add Langflow API key headers
# Check if we need to add Hanzo Flow API key headers
# Necessary only when Project API Key Authentication is enabled
# Generate a Langflow API key for auto-install if needed
# Generate a Hanzo Flow API key for auto-install if needed
# Only add API key headers for projects with "apikey" auth type (not "none" or OAuth)
if should_generate_api_key:
@@ -856,7 +856,7 @@ async def install_mcp_config(
if "mcpServers" not in existing_config:
existing_config["mcpServers"] = {}
# Remove stale entries that point to the same Langflow URLs (e.g. after the project is renamed)
# Remove stale entries that point to the same Hanzo Flow URLs (e.g. after the project is renamed)
existing_config, removed_servers = remove_server_by_urls(existing_config, connection_urls)
if removed_servers:
@@ -1221,7 +1221,7 @@ async def _get_mcp_composer_auth_config(project) -> dict:
class ProjectMCPServer:
def __init__(self, project_id: UUID):
self.project_id = project_id
self.server = Server(f"langflow-mcp-project-{project_id}")
self.server = Server(f"flow-mcp-project-{project_id}")
# TODO: implement an environment variable to enable/disable stateless mode
self.session_manager = StreamableHTTPSessionManager(self.server, stateless=True)
# since we lazily initialize the session manager's lifecycle
@@ -1414,7 +1414,7 @@ async def register_project_with_composer(project: Folder):
settings = get_settings_service().settings
if not settings.host or not settings.port:
error_msg = "Langflow host and port must be set in settings to register project with MCP Composer"
error_msg = "Hanzo Flow host and port must be set in settings to register project with MCP Composer"
raise ValueError(error_msg)
if not project.id:
@@ -1549,7 +1549,7 @@ async def get_or_start_mcp_composer(auth_config: dict, project_name: str, projec
# Prepare current auth config for comparison
settings = get_settings_service().settings
if not settings.host or not settings.port:
error_msg = "Langflow host and port must be set in settings to register project with MCP Composer"
error_msg = "Hanzo Flow host and port must be set in settings to register project with MCP Composer"
raise ValueError(error_msg)
streamable_http_url = await get_project_streamable_http_url(project_id)
+2 -2
View File
@@ -157,7 +157,7 @@ async def handle_list_resources(project_id=None):
stored_filename = Path(stored_path).name if stored_path else user_file.name
safe_filename = quote(stored_filename)
if stored_filename.startswith(f"{MCP_SERVERS_FILE}_{current_user.id}"):
# reserved file name for langflow MCP server config file(s)
# reserved file name for flow MCP server config file(s)
continue
description = getattr(user_file, "provider", None) or "User file uploaded via File Manager"
resource = types.Resource(
@@ -210,7 +210,7 @@ async def handle_read_resource(uri: str, project_id: UUID | str | None = None) -
raise ValueError(msg)
# SECURITY: authorise the caller before reading. The storage layer alone is
# not enough because the filesystem doesn't know about Langflow users, and
# not enough because the filesystem doesn't know about Hanzo Flow users, and
# previously any authenticated user could request any flow_id.
try:
current_user = current_user_ctx.get()
@@ -102,7 +102,7 @@ async def run_flow_for_openai_responses(
event_manager = create_stream_tokens_event_manager(queue=asyncio_queue)
async def openai_stream_generator() -> AsyncGenerator[str, None]:
"""Convert Langflow events to OpenAI Responses API streaming format."""
"""Convert Hanzo Flow events to OpenAI Responses API streaming format."""
main_task = asyncio.create_task(
run_flow_generator(
flow=flow,
@@ -598,7 +598,7 @@ async def create_response(
"""Create a response using OpenAI Responses API format.
This endpoint accepts a flow_id in the model parameter and processes
the input through the specified Langflow flow.
the input through the specified Hanzo Flow flow.
Args:
request: OpenAI Responses API request with model (flow_id) and input
+1 -1
View File
@@ -444,7 +444,7 @@ async def delete_project(
if not project:
raise HTTPException(status_code=404, detail="Project not found")
# Prevent deletion of the Langflow Assistant folder
# Prevent deletion of the Hanzo Flow Assistant folder
if project.name == ASSISTANT_FOLDER_NAME:
msg = f"Cannot delete the '{ASSISTANT_FOLDER_NAME}' folder, that contains pre-built flows."
await logger.adebug("Cannot delete the '%s' folder, that contains pre-built flows.", ASSISTANT_FOLDER_NAME)
@@ -11,12 +11,12 @@ Two identifier domains coexist in these schemas:
* **Provider-owned (str)** -- ``reference_id``, ``config_id``,
``run_id``.
Opaque values assigned or consumed by the external deployment provider.
``provider_key`` is Langflow-owned adapter vocabulary.
``provider_key`` is Hanzo Flow-owned adapter vocabulary.
Provider-specific metadata (for example URL and tenant/account identifiers)
belongs inside ``provider_data``.
* **Provider-originated but Langflow-owned once persisted** -- ``resource_key``.
Langflow stores and indexes this as part of its own deployment record.
* **Provider-originated but Hanzo Flow-owned once persisted** -- ``resource_key``.
Hanzo Flow stores and indexes this as part of its own deployment record.
``provider_data`` dicts are opaque pass-through containers whose contents
are defined by the provider adapter. Flow forwards them without
@@ -265,7 +265,7 @@ class DeploymentGetResponse(_DeploymentResponseWithProviderData):
list item stays lean.
"""
resource_key: str = Field(description="Langflow-persisted stable provider resource identifier.")
resource_key: str = Field(description="Hanzo Flow-persisted stable provider resource identifier.")
attached_count: int = Field(default=0, ge=0, description="Number of flow versions attached to this deployment.")
@@ -275,7 +275,7 @@ class DeploymentListItem(_DeploymentResponseCommon):
See ``DeploymentGetResponse`` docstring for rationale on the separate class.
"""
resource_key: str = Field(description="Langflow-persisted stable provider resource identifier.")
resource_key: str = Field(description="Hanzo Flow-persisted stable provider resource identifier.")
attached_count: int = Field(default=0, ge=0, description="Number of flow versions attached to this deployment.")
flow_version_ids: list[UUID] | None = Field(
default=None,
@@ -333,25 +333,25 @@ class DeploymentSnapshotListResponse(_PaginatedResponse):
class DeploymentFlowVersionListItem(BaseModel):
"""Flow version metadata attached to a deployment.
**Identity model:** Langflow tracks provider tools by their immutable
**Identity model:** Hanzo Flow tracks provider tools by their immutable
``provider_snapshot_id`` (the wxO tool_id), never by name. This
distinguishes the following cases:
* **Tool renamed in provider** — Same ``provider_snapshot_id``, different
``provider_data.tool_name``. Langflow picks up the new name on the next fetch.
``provider_data.tool_name``. Hanzo Flow picks up the new name on the next fetch.
* **Tool deleted in provider** — ``provider_snapshot_id`` no longer
resolves. ``provider_data.tool_name`` may be missing/``None``.
* **Tool deleted + new tool created with same name** — The new tool has
a different ID. Langflow's attachment still points to the old
(missing) ID. The new tool is invisible to Langflow until explicitly
a different ID. Hanzo Flow's attachment still points to the old
(missing) ID. The new tool is invisible to Hanzo Flow until explicitly
attached via an update operation.
Frontends should use ``provider_data.tool_name`` for display and
``provider_snapshot_id`` for identity / operations.
"""
id: UUID = Field(description="Langflow flow version UUID (`flow_version.id`).")
flow_id: UUID = Field(description="Langflow flow UUID (`flow.id`) for this version.")
id: UUID = Field(description="Hanzo Flow flow version UUID (`flow_version.id`).")
flow_id: UUID = Field(description="Hanzo Flow flow UUID (`flow.id`) for this version.")
flow_name: str | None = Field(
default=None,
description="Name of the flow owning this version (`flow.name`).",
@@ -378,13 +378,13 @@ class DeploymentFlowVersionListResponse(_PaginatedResponse):
class DeploymentCreateResponse(_DeploymentResponseWithProviderData):
"""API response for deployment creation."""
resource_key: str = Field(description="Langflow-persisted stable provider resource identifier.")
resource_key: str = Field(description="Hanzo Flow-persisted stable provider resource identifier.")
class DeploymentUpdateResponse(_DeploymentResponseWithProviderData):
"""API response for deployment update."""
resource_key: str = Field(description="Langflow-persisted stable provider resource identifier.")
resource_key: str = Field(description="Hanzo Flow-persisted stable provider resource identifier.")
class DeploymentStatusResponse(_DeploymentResponseWithProviderData):
@@ -661,7 +661,7 @@ class SnapshotUpdateRequest(BaseModel):
model_config = {"extra": "forbid"}
flow_version_id: UUID = Field(
description="Langflow flow version whose artifact will replace the snapshot content.",
description="Hanzo Flow flow version whose artifact will replace the snapshot content.",
)
+1 -1
View File
@@ -96,7 +96,7 @@ async def authenticate_and_get_openai_key(session: DbSession, user: User, websoc
{
"type": "error",
"code": "langflow_auth",
"message": "You must pass a valid Langflow token or cookie.",
"message": "You must pass a valid Hanzo Flow token or cookie.",
}
)
return None, None
+4 -4
View File
@@ -180,18 +180,18 @@ class ProgressIndicator:
def create_flow_progress(*, verbose: bool = False) -> ProgressIndicator:
"""Create a progress indicator with predefined Langflow initialization steps."""
"""Create a progress indicator with predefined Hanzo Flow initialization steps."""
progress = ProgressIndicator(verbose=verbose)
# Define the initialization steps matching the order in main.py
steps = [
("Initializing Langflow", "Setting up basic configuration"),
("Initializing Hanzo Flow", "Setting up basic configuration"),
("Checking Environment", "Loading environment variables and settings"),
("Starting Core Services", "Initializing database and core services"),
("Connecting Database", "Setting up database connection and migrations"),
("Loading Components", "Caching component types and custom components"),
("Adding Starter Projects", "Creating or updating starter project templates"),
("Launching Langflow", "Starting server and final setup"),
("Launching Hanzo Flow", "Starting server and final setup"),
]
for title, description in steps:
@@ -201,7 +201,7 @@ def create_flow_progress(*, verbose: bool = False) -> ProgressIndicator:
def create_langflow_shutdown_progress(*, verbose: bool = False, multiple_workers: bool = False) -> ProgressIndicator:
"""Create a progress indicator with predefined Langflow shutdown steps."""
"""Create a progress indicator with predefined Hanzo Flow shutdown steps."""
progress = ProgressIndicator(verbose=verbose)
# Define the shutdown steps in reverse order of initialization
@@ -1,4 +1,4 @@
"""Langflow knowledge bases module - forwards to lfx.components.files_and_knowledge.
"""Hanzo Flow knowledge bases module - forwards to lfx.components.files_and_knowledge.
This module provides backwards compatibility by forwarding all imports
to files_and_knowledge where the actual knowledge base components are located.
@@ -1,4 +1,4 @@
"""Component module for langflow - imports from lfx.
"""Component module for flow - imports from lfx.
This maintains backward compatibility while using the lfx implementation.
"""
@@ -1,5 +1,5 @@
STARTER_FOLDER_NAME = "Starter Projects"
STARTER_FOLDER_DESCRIPTION = "Starter projects to help you get started in Langflow."
STARTER_FOLDER_DESCRIPTION = "Starter projects to help you get started in Hanzo Flow."
ASSISTANT_FOLDER_NAME = "Langflow Assistant"
ASSISTANT_FOLDER_DESCRIPTION = "Pre-built flows from Langflow Assistant to enhance your workflow."
ASSISTANT_FOLDER_NAME = "Hanzo Flow Assistant"
ASSISTANT_FOLDER_DESCRIPTION = "Pre-built flows from Hanzo Flow Assistant to enhance your workflow."
+5 -5
View File
@@ -780,7 +780,7 @@ async def get_or_create_starter_folder(session):
async def get_or_create_assistant_folder(session, user_id: UUID):
"""Create or get the Langflow Assistant folder for a specific user.
"""Create or get the Hanzo Flow Assistant folder for a specific user.
This folder contains agentic flows and cannot be deleted.
@@ -789,7 +789,7 @@ async def get_or_create_assistant_folder(session, user_id: UUID):
user_id: The ID of the user who owns the folder
Returns:
The Langflow Assistant folder
The Hanzo Flow Assistant folder
"""
stmt = select(Folder).where(Folder.user_id == user_id, Folder.name == ASSISTANT_FOLDER_NAME)
result = await session.exec(stmt)
@@ -836,10 +836,10 @@ async def load_agentic_flows() -> list[tuple[anyio.Path, dict]]:
async def create_or_update_agentic_flows(session: AsyncSession, user_id: UUID) -> None:
"""Create or update agentic flows in the Langflow Assistant folder for a user.
"""Create or update agentic flows in the Hanzo Flow Assistant folder for a user.
This function is called on user login to ensure that all agentic flows
are present and up-to-date in the user's Langflow Assistant folder.
are present and up-to-date in the user's Hanzo Flow Assistant folder.
The function will:
- Extract flow_id and endpoint_name from the JSON
@@ -859,7 +859,7 @@ async def create_or_update_agentic_flows(session: AsyncSession, user_id: UUID) -
return
try:
# Get or create the Langflow Assistant folder
# Get or create the Hanzo Flow Assistant folder
assistant_folder = await get_or_create_assistant_folder(session, user_id)
# Load all agentic flows from the directory
@@ -1,4 +1,4 @@
"""Interface components module for langflow - imports from lfx."""
"""Interface components module for flow - imports from lfx."""
# Import everything from lfx.interface.components
from lfx.interface.components import * # noqa: F403
+1 -1
View File
@@ -1,4 +1,4 @@
"""Interface listing module for langflow - imports from lfx."""
"""Interface listing module for flow - imports from lfx."""
# Import everything from lfx.interface.listing
from lfx.interface.listing import * # noqa: F403
+1 -1
View File
@@ -1,4 +1,4 @@
"""Interface utils module for langflow - imports from lfx."""
"""Interface utils module for flow - imports from lfx."""
# Import everything from lfx.interface.utils
from lfx.interface.utils import * # noqa: F403
@@ -1,7 +1,7 @@
"""Expand compact flow format to full flow format.
This module provides functionality to expand a minimal/compact flow format
(used by AI agents) into the full flow format expected by Langflow.
(used by AI agents) into the full flow format expected by Hanzo Flow.
"""
from __future__ import annotations
@@ -256,7 +256,7 @@ def expand_compact_flow(
all_types_dict: The component types dictionary from component_cache
Returns:
Full flow data structure ready for Langflow UI
Full flow data structure ready for Hanzo Flow UI
Example compact input:
{
+1 -1
View File
@@ -1,4 +1,4 @@
"""JSON and Data classes for langflow - imports from lfx.
"""JSON and Data classes for flow - imports from lfx.
This maintains backward compatibility while using the lfx implementation.
JSON is the new base type; Data is an alias for backwards compatibility.
+1 -1
View File
@@ -1,4 +1,4 @@
"""Message class for langflow - imports from lfx.
"""Message class for flow - imports from lfx.
This maintains backward compatibility while using the lfx implementation.
"""
@@ -1 +1 @@
"""Adapter namespaces for Langflow service-scoped plugin registries."""
"""Adapter namespaces for Hanzo Flow service-scoped plugin registries."""
@@ -1 +1 @@
"""Langflow deployment adapter implementations."""
"""Hanzo Flow deployment adapter implementations."""
@@ -47,10 +47,10 @@ class WxOAuthURL(str, Enum):
Please note:
- The stated environment variables are solely for
internal testing and development purposes,
and must be left unset when shipping Langflow
and must be left unset when shipping Hanzo Flow
for general availability.
- The IAM URLs cannot be changed during runtime,
and Langflow does not dynamically resolve the IAM URL based on
and Hanzo Flow does not dynamically resolve the IAM URL based on
the environment of a given wxO tenant. It simply uses the
default production IAM URLs, or the environment variable
overrides if set.
@@ -461,7 +461,7 @@ async def validate_connection(connections_client: ConnectionsClient, *, app_id:
raise InvalidContentError(message=msg)
if config.security_scheme != ConnectionSecurityScheme.KEY_VALUE:
msg = f"Connection '{app_id}' must use key-value credentials for Langflow flows."
msg = f"Connection '{app_id}' must use key-value credentials for Hanzo Flow flows."
raise InvalidContentError(message=msg)
runtime_credentials = await asyncio.to_thread(
@@ -106,20 +106,20 @@ def ensure_langflow_connections_binding(tool_payload: dict[str, Any]) -> dict[st
to prevent a stubbornly failing update.
"""
binding = _ensure_dict(tool_payload, "binding")
langflow = _ensure_dict(binding, "langflow")
return _ensure_dict(langflow, "connections")
flow = _ensure_dict(binding, "flow")
return _ensure_dict(flow, "connections")
def verify_langflow_owned(tool: dict[str, Any], *, tool_id: str) -> None:
"""Raise ``InvalidContentError`` if the tool lacks ``binding.langflow``.
"""Raise ``InvalidContentError`` if the tool lacks ``binding.flow``.
Call before any mutating operation on an existing tool to ensure
Langflow created it. Tools created manually in the wxO console or
Hanzo Flow created it. Tools created manually in the wxO console or
by other integrations will not have this marker.
"""
binding = tool.get("binding")
if not isinstance(binding, dict) or "langflow" not in binding:
msg = f"Cannot modify tool '{tool_id}': it does not have a Langflow binding and may not be managed by Langflow."
if not isinstance(binding, dict) or "flow" not in binding:
msg = f"Cannot modify tool '{tool_id}': it does not have a Hanzo Flow binding and may not be managed by Hanzo Flow."
raise InvalidContentError(message=msg)
@@ -132,8 +132,8 @@ def extract_langflow_connections_binding(tool_payload: dict[str, Any]) -> dict[s
binding = tool_payload.get("binding")
if not isinstance(binding, dict):
return {}
langflow = binding.get("langflow")
if not isinstance(langflow, dict):
flow = binding.get("flow")
if not isinstance(flow, dict):
return {}
connections = flow.get("connections")
return connections if isinstance(connections, dict) else {}
@@ -183,7 +183,7 @@ async def update_existing_tool_connection_bindings(
def extract_langflow_artifact_from_zip(artifact_zip_bytes: bytes, *, snapshot_id: str) -> dict[str, Any]:
"""Read and parse the Langflow flow JSON from a wxO snapshot artifact zip."""
"""Read and parse the Hanzo Flow flow JSON from a wxO snapshot artifact zip."""
try:
with zipfile.ZipFile(io.BytesIO(artifact_zip_bytes), "r") as zip_artifact:
json_members = [name for name in zip_artifact.namelist() if name.lower().endswith(".json")]
@@ -299,7 +299,7 @@ def create_wxo_flow_tool(
if not flow_definition.get("last_tested_version"):
detected_version = (get_version_info() or {}).get("version")
if not detected_version:
msg = "Unable to determine running Langflow version for snapshot creation."
msg = "Unable to determine running Hanzo Flow version for snapshot creation."
raise InvalidContentError(message=msg)
flow_definition["last_tested_version"] = detected_version
@@ -320,12 +320,12 @@ def create_wxo_flow_tool(
if current_name:
tool_payload["name"] = normalize_wxo_name(current_name)
(tool_payload.setdefault("binding", {}).setdefault("langflow", {})["project_id"]) = project_id
(tool_payload.setdefault("binding", {}).setdefault("flow", {})["project_id"]) = project_id
logger.debug(
"create_wxo_flow_tool: tool name='%s', project_id='%s', binding=%s",
tool_payload.get("name"),
project_id,
tool_payload.get("binding", {}).get("langflow"),
tool_payload.get("binding", {}).get("flow"),
)
artifacts: bytes = build_langflow_artifact_bytes(
@@ -462,7 +462,7 @@ async def process_raw_flows_with_app_id(
app_id: str,
flows: list[BaseFlowArtifact[WatsonxFlowArtifactProviderData]],
) -> list[WatsonxToolRefBinding]:
"""Create langflow tools in wxO and connect them to the given app_id."""
"""Create flow tools in wxO and connect them to the given app_id."""
from flow.services.adapters.deployment.watsonx_orchestrate.core.config import validate_connection
connection = await validate_connection(clients.connections, app_id=app_id)
@@ -558,7 +558,7 @@ async def verify_tools_by_ids(
if len(normalized_connections) < len(connections):
logger.warning(
"Tool %s returned malformed langflow connection bindings; defaulting to empty mapping",
"Tool %s returned malformed flow connection bindings; defaulting to empty mapping",
tool["id"],
)
provider_data: dict[str, dict[str, str]] = {"connections": {}}
@@ -335,7 +335,7 @@ async def _apply_tool_renames(
Guards against destructive operations on tools we don't own:
1. Tool must be attached to this agent (tool_id in agent_tool_ids).
2. Tool must be a Langflow-managed tool (has ``binding.langflow``).
2. Tool must be a Hanzo Flow-managed tool (has ``binding.flow``).
3. Tool must exist on the provider.
Captures original tool payloads in ``original_tools`` for rollback.
@@ -19,7 +19,7 @@ class WatsonxFlowArtifactProviderData(BaseModel):
model_config = ConfigDict(extra="forbid")
project_id: NormalizedId = Field(description="Langflow project id carried for watsonx snapshot creation.")
project_id: NormalizedId = Field(description="Hanzo Flow project id carried for watsonx snapshot creation.")
source_ref: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)] = Field(
description="Adapter-neutral source reference used for create/update snapshot correlation.",
)
@@ -241,7 +241,7 @@ class WatsonxUnbindOperation(BaseModel):
class WatsonxRenameToolOperation(BaseModel):
"""Rename a Langflow-managed tool on the provider."""
"""Rename a Hanzo Flow-managed tool on the provider."""
model_config = ConfigDict(extra="forbid")
@@ -550,7 +550,7 @@ class WatsonxAgentExecutionResultData(BaseModel):
execution_id: NormalizedId | None = None
agent_id: NormalizedId | None = Field(
default=None,
description="WXO agent identifier (resource_key in Langflow DB).",
description="WXO agent identifier (resource_key in Hanzo Flow DB).",
)
thread_id: NormalizedId | None = None
status: str | None = None
@@ -982,7 +982,7 @@ class WatsonxOrchestrateDeploymentService(BaseDeploymentService):
without touching the tool's name, metadata, or connection bindings.
The tool name is fetched from wxO at call time, not derived from the
Langflow flow name. This is intentional: the user may have set a
Hanzo Flow flow name. This is intentional: the user may have set a
custom tool name during initial deployment, or renamed the tool
directly in the wxO console. Either way, the provider is the source
of truth for the tool name.
@@ -991,7 +991,7 @@ class WatsonxOrchestrateDeploymentService(BaseDeploymentService):
* **Tool renamed in wxO console** — The new name is picked up
automatically on the next update since we always fetch it fresh.
Langflow never stores the tool name locally.
Hanzo Flow never stores the tool name locally.
* **Tool deleted in wxO** — ``get_drafts_by_ids`` returns empty
and we raise ``InvalidContentError`` before any mutation.
* **Tool exists but name is empty/null** — Defensive check raises
@@ -1012,7 +1012,7 @@ class WatsonxOrchestrateDeploymentService(BaseDeploymentService):
by name. A rename preserves identity; a delete+recreate does not.
**Blast-radius boundary:** callers must verify that ``snapshot_id``
is tracked by a Langflow attachment record before calling this
is tracked by a Hanzo Flow attachment record before calling this
method; this prevents accidental overwrites of externally managed
WXO tools.
"""
@@ -1021,7 +1021,7 @@ class WatsonxOrchestrateDeploymentService(BaseDeploymentService):
clients = await self._get_provider_clients(user_id=user_id, db=db)
# Fetch the existing tool to preserve its wxO name — the tool may have
# been deployed with a custom name that differs from the Langflow flow
# been deployed with a custom name that differs from the Hanzo Flow flow
# name, and we must not overwrite it with the flow name.
existing_tools = await asyncio.to_thread(clients.tool.get_drafts_by_ids, [snapshot_id])
if not existing_tools or not isinstance(existing_tools[0], dict):
@@ -177,7 +177,7 @@ def build_agent_payload_from_values(
return {
"name": agent_name,
"display_name": agent_display_name,
"description": str(description).strip() or f"Langflow deployment {deployment_name}",
"description": str(description).strip() or f"Hanzo Flow deployment {deployment_name}",
"tools": list(tool_ids),
"style": "default",
"llm": str(llm).strip(),
@@ -1,6 +1,6 @@
"""Authentication service factory.
Builds the Langflow auth implementation (JWT, DB users, etc.)
Builds the Hanzo Flow auth implementation (JWT, DB users, etc.)
"""
from __future__ import annotations
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
class AuthServiceFactory(ServiceFactory):
"""Factory that creates the Langflow auth service (implements LFX BaseAuthService)."""
"""Factory that creates the Hanzo Flow auth service (implements LFX BaseAuthService)."""
name = ServiceType.AUTH_SERVICE.value
@@ -1,5 +1,5 @@
"""
Hanzo IAM Organization extraction for Flow (Langflow fork).
Hanzo IAM Organization extraction for Flow (Hanzo Flow fork).
Extracts the IAM organization slug from:
1. X-IAM-Org-Id request header (set by gateway)
@@ -43,7 +43,7 @@ if TYPE_CHECKING:
class AuthService(BaseAuthService):
"""Default Langflow authentication service (implements LFX BaseAuthService)."""
"""Default Hanzo Flow authentication service (implements LFX BaseAuthService)."""
name = ServiceType.AUTH_SERVICE.value
+1 -1
View File
@@ -144,7 +144,7 @@ async def ws_api_key_security(api_key: str | None) -> UserRead:
def _auth_error_to_http(e: AuthenticationError) -> HTTPException:
"""Map auth exceptions to 401 Unauthorized or 403 Forbidden.
Langflow returns 403 for missing/invalid credentials; 401 for invalid/expired tokens.
Hanzo Flow returns 403 for missing/invalid credentials; 401 for invalid/expired tokens.
"""
if isinstance(
e,
@@ -1,13 +1,13 @@
"""Database service constants."""
# Minimum PostgreSQL major version required by Langflow.
# Minimum PostgreSQL major version required by Hanzo Flow.
# The schema uses UNIQUE NULLS DISTINCT, which is only supported in PostgreSQL 15+.
MIN_POSTGRESQL_MAJOR_VERSION = 15
# User-facing message when migrations fail due to PostgreSQL < 15 (e.g. UNIQUE NULLS DISTINCT).
POSTGRESQL_VERSION_REQUIRED_MESSAGE = (
f"Langflow requires PostgreSQL {MIN_POSTGRESQL_MAJOR_VERSION} or higher when using PostgreSQL as the database. "
"The current PostgreSQL version does not support the syntax used by Langflow's schema. "
f"Hanzo Flow requires PostgreSQL {MIN_POSTGRESQL_MAJOR_VERSION} or higher when using PostgreSQL as the database. "
"The current PostgreSQL version does not support the syntax used by Hanzo Flow's schema. "
f"Please upgrade your PostgreSQL instance to version {MIN_POSTGRESQL_MAJOR_VERSION} or higher. "
"See: https://docs.flow.org/configuration-custom-database"
)
@@ -1,7 +1,7 @@
"""SSO plugin tables.
These tables are used by the SSO plugin for identity and provider configuration.
Migrations are managed by Langflow (OSS); the plugin must not create or
Migrations are managed by Hanzo Flow (OSS); the plugin must not create or
migrate these tables.
Plugins must use these tables via the models exported from
@@ -48,12 +48,12 @@ class Deployment(SQLModel, table=True): # type: ignore[call-arg]
)
# ``DeploymentType`` is imported from LFX
# (``lfx.services.adapters.deployment.schema``). The DB-level
# ``deployment_type_enum`` constraint is defined by a Langflow alembic
# ``deployment_type_enum`` constraint is defined by a Hanzo Flow alembic
# migration, **not** by LFX code. This decoupling is intentional:
#
# LFX adds a new member -> INSERT/UPDATE with the new value is rejected
# by the DB until a Langflow migration adds it
# to the enum type. Langflow explicitly opts
# by the DB until a Hanzo Flow migration adds it
# to the enum type. Hanzo Flow explicitly opts
# in to new deployment types.
#
# LFX renames a value -> Existing rows are unaffected (the DB stores
@@ -72,7 +72,7 @@ class Deployment(SQLModel, table=True): # type: ignore[call-arg]
#
# To add a new value to ``deployment_type_enum``:
# 1. Add the member to ``DeploymentType`` in LFX (or confirm it exists).
# 2. Create a Langflow alembic migration that runs:
# 2. Create a Hanzo Flow alembic migration that runs:
# op.execute("ALTER TYPE deployment_type_enum ADD VALUE '<new>'")
# For SQLite (dev/test) this is a no-op; the CHECK constraint is
# recreated automatically by ``batch_alter_table``.
@@ -48,14 +48,14 @@ class DeploymentProviderAccount(SQLModel, table=True): # type: ignore[call-arg]
# may not require a tenant/organization identifier.
provider_tenant_id: str | None = Field(default=None, index=True)
# The DB-level ``deployment_provider_key_enum`` constraint is defined
# by a Langflow alembic migration. The enum is Langflow-owned (see
# by a Hanzo Flow alembic migration. The enum is Hanzo Flow-owned (see
# ``DeploymentProviderKey`` above); LFX uses plain strings for adapter
# registry keys and does not reference this enum.
#
# To add a new value to ``deployment_provider_key_enum``:
# 1. Add the member to ``DeploymentProviderKey`` in this module.
# 2. Register the corresponding adapter in LFX and mapper in Langflow.
# 3. Create a Langflow alembic migration that runs:
# 2. Register the corresponding adapter in LFX and mapper in Hanzo Flow.
# 3. Create a Hanzo Flow alembic migration that runs:
# op.execute(
# "ALTER TYPE deployment_provider_key_enum ADD VALUE '<new>'"
# )
@@ -9,11 +9,11 @@ from enum import Enum
class DeploymentProviderKey(str, Enum):
"""Deployment provider identifiers recognised by Langflow.
"""Deployment provider identifiers recognised by Hanzo Flow.
Each member value must match the adapter registry key used by
``get_deployment_adapter(adapter_key)`` in LFX and the corresponding
mapper registration in the Langflow mapper registry.
mapper registration in the Hanzo Flow mapper registry.
"""
WATSONX_ORCHESTRATE = "watsonx-orchestrate"
@@ -36,7 +36,7 @@ class FlowVersionDeploymentAttachment(SQLModel, table=True): # type: ignore[cal
description=(
"Opaque provider-assigned identifier for the materialized snapshot "
"(e.g. a wxO tool ID, a K8s ConfigMap name, an S3 key). "
"Links this Langflow flow version to its provider-side resource."
"Links this Hanzo Flow flow version to its provider-side resource."
),
)
created_at: datetime | None = Field(
@@ -277,7 +277,7 @@ class DatabaseService(Service):
async def ensure_postgresql_version(self) -> None:
"""If the database is PostgreSQL, ensure it is version 15 or higher.
Langflow's schema uses UNIQUE NULLS DISTINCT, which is only supported in PostgreSQL 15+.
Hanzo Flow's schema uses UNIQUE NULLS DISTINCT, which is only supported in PostgreSQL 15+.
Logs the message and raises UnsupportedPostgreSQLVersionError if the version is too old.
"""
if not self.database_url.startswith(("postgresql", "postgres")):
@@ -150,7 +150,7 @@ class WebhookEventManager:
# Module-level instance (can be replaced in tests via dependency injection)
# TODO: Consider migrating to langflow's service manager pattern for better DI
# TODO: Consider migrating to flow's service manager pattern for better DI
_webhook_event_manager: WebhookEventManager | None = None
+1 -1
View File
@@ -94,7 +94,7 @@ def import_all_services_into_a_dict():
logger.exception(exc)
msg = "Could not initialize services. Please check your settings."
raise RuntimeError(msg) from exc
# Import settings and auth base from lfx (used in type hints but not langflow Service subclasses)
# Import settings and auth base from lfx (used in type hints but not flow Service subclasses)
from lfx.services.auth.base import BaseAuthService
from lfx.services.settings.service import SettingsService
+1 -1
View File
@@ -1,4 +1,4 @@
"""Langflow ServiceManager - re-exports from lfx for backwards compatibility."""
"""Hanzo Flow ServiceManager - re-exports from lfx for backwards compatibility."""
from __future__ import annotations
@@ -1,4 +1,4 @@
"""Storage service for langflow - redirects to lfx implementation."""
"""Storage service for flow - redirects to lfx implementation."""
from __future__ import annotations
@@ -49,7 +49,7 @@ async def get_lf_version_from_pypi():
return None
return response.json()["info"]["version"]
except Exception: # noqa: BLE001
logger.debug("Error getting the latest version of langflow from PyPI", exc_info=True)
logger.debug("Error getting the latest version of flow from PyPI", exc_info=True)
return None
@@ -51,7 +51,7 @@ class CollectingSpanProcessor(SpanProcessor):
self.correlation_id = str(uuid.uuid4())
# Inject into the CHAIN & LLM spans
if span.name in ("Langflow", "Language Model"):
if span.name in ("Hanzo Flow", "Language Model"):
span.set_attribute("flow.correlation_id", self.correlation_id)
def on_end(self, span):
@@ -94,7 +94,7 @@ class ArizePhoenixTracer(BaseTracer):
self.carrier: dict[Any, CarrierT] = {}
self.root_span = self.tracer.start_span(
name="Langflow",
name="Hanzo Flow",
start_time=self._get_current_timestamp(),
)
self.root_span.set_attribute(SpanAttributes.SESSION_ID, self.session_id or self.flow_id)
@@ -25,7 +25,7 @@ if TYPE_CHECKING:
_UTC_MIN = datetime.min.replace(tzinfo=timezone.utc)
# Name substring used to identify the user-facing input span.
# Langflow's native tracer names this span "Chat Input" by convention.
# Hanzo Flow's native tracer names this span "Chat Input" by convention.
# If the span naming convention changes, update this constant.
_CHAT_INPUT_SPAN_NAME = "Chat Input"
@@ -73,7 +73,7 @@ class LangWatchTracer(BaseTracer):
api_key = os.environ["LANGWATCH_API_KEY"]
endpoint = os.environ.get("LANGWATCH_ENDPOINT", "https://app.langwatch.ai")
resource = Resource.create(attributes={"service.name": "langflow"})
resource = Resource.create(attributes={"service.name": "flow"})
exporter = OTLPSpanExporter(
endpoint=f"{endpoint}/api/otel/v1/traces", headers={"Authorization": f"Bearer {api_key}"}
)
@@ -1,7 +1,7 @@
"""Native tracer for storing execution traces in the database.
This module provides a tracer that stores component-level and LangChain-level
execution traces directly in Langflow's database, enabling the Trace View
execution traces directly in Hanzo Flow's database, enabling the Trace View
without requiring external services like LangSmith or LangFuse.
"""
@@ -43,7 +43,7 @@ TYPE_MAP = {
class NativeTracer(BaseTracer):
"""Tracer that stores execution traces in Langflow's database.
"""Tracer that stores execution traces in Hanzo Flow's database.
This tracer captures:
- Component-level traces (via add_trace/end_trace)
@@ -477,7 +477,7 @@ class NativeTracer(BaseTracer):
lc_attributes["gen_ai.response.model"] = span_info["model_name"]
if span_info.get("provider"):
lc_attributes["gen_ai.provider.name"] = span_info["provider"]
# Default to chat since most LLM usage in Langflow is conversational
# Default to chat since most LLM usage in Hanzo Flow is conversational
if span_info.get("span_type") == "llm":
lc_attributes["gen_ai.operation.name"] = "chat"
if prompt_tokens:
@@ -554,5 +554,5 @@ class NativeTracer(BaseTracer):
@staticmethod
def _map_trace_type(trace_type: str) -> SpanType:
"""Normalise Langflow's string trace types to the SpanType enum, defaulting to CHAIN for unknown values."""
"""Normalise Hanzo Flow's string trace types to the SpanType enum, defaulting to CHAIN for unknown values."""
return TYPE_MAP.get(trace_type.lower(), SpanType.CHAIN)
@@ -31,7 +31,7 @@ if TYPE_CHECKING:
class TraceloopTracer(BaseTracer):
"""Traceloop tracer for Langflow."""
"""Traceloop tracer for Hanzo Flow."""
def __init__(
self,
@@ -64,7 +64,7 @@ class TraceloopTracer(BaseTracer):
api_endpoint=os.getenv("TRACELOOP_BASE_URL", "https://api.traceloop.com"),
)
self._ready = True
self._tracer = trace.get_tracer("langflow")
self._tracer = trace.get_tracer("flow")
self.propagator = TraceContextTextMapPropagator()
self.carrier: CarrierT = {}
+1 -1
View File
@@ -262,7 +262,7 @@ def register_all_service_factories() -> None:
service_manager.register_factory(task_factory.TaskServiceFactory())
service_manager.register_factory(store_factory.StoreServiceFactory())
service_manager.register_factory(shared_component_cache_factory.SharedComponentCacheServiceFactory())
# Override LFX's no-op auth service with Langflow's full JWT implementation
# Override LFX's no-op auth service with Hanzo Flow's full JWT implementation
service_manager.register_service_class(ServiceType.AUTH_SERVICE, AuthService, override=True)
service_manager.register_factory(auth_factory.AuthServiceFactory())
service_manager.register_factory(mcp_composer_factory.MCPComposerServiceFactory())
+1 -1
View File
@@ -1,4 +1,4 @@
"""Lazy load utilities for langflow - imports from lfx."""
"""Lazy load utilities for flow - imports from lfx."""
# Import everything from lfx.utils.lazy_load
from lfx.utils.lazy_load import * # noqa: F403
+2 -2
View File
@@ -1,7 +1,7 @@
"""MCP subprocess cleanup utilities for graceful shutdown.
This module provides functions to properly terminate MCP server subprocesses
spawned by stdio_client during Langflow shutdown.
spawned by stdio_client during Hanzo Flow shutdown.
Works on macOS and Linux only.
"""
@@ -42,7 +42,7 @@ async def cleanup_mcp_sessions() -> None:
async def _kill_mcp_processes() -> None:
"""Kill MCP server subprocesses spawned by this Langflow process.
"""Kill MCP server subprocesses spawned by this Hanzo Flow process.
This is a fallback for when the normal cleanup doesn't properly terminate
subprocesses spawned by stdio_client.
@@ -1,4 +1,4 @@
"""Template validation utilities for Langflow starter projects.
"""Template validation utilities for Hanzo Flow starter projects.
This module provides validation functions to ensure template integrity and prevent
unexpected breakage in starter project templates.
+103 -103
View File
@@ -1,5 +1,5 @@
[project]
name = "langflow-base"
name = "hanzo-flow-base"
version = "0.9.6"
description = "A Python package with a built-in web application"
requires-python = ">=3.12,<3.14"
@@ -371,124 +371,124 @@ ibm-watsonx-clients = [
]
complete = [
"langflow-base[couchbase]",
"langflow-base[cassandra]",
"langflow-base[clickhouse]",
"langflow-base[mongodb]",
"langflow-base[supabase]",
"langflow-base[redis]",
"langflow-base[elasticsearch]",
"langflow-base[faiss]",
"langflow-base[qdrant]",
"langflow-base[qdrant-vectors]",
"langflow-base[weaviate]",
"langflow-base[chroma]",
"langflow-base[upstash]",
"langflow-base[pinecone]",
"langflow-base[milvus]",
"langflow-base[mongodb-vectors]",
"langflow-base[astradb]",
"langflow-base[openai]",
"langflow-base[anthropic]",
"langflow-base[cohere]",
"langflow-base[google]",
"langflow-base[ollama]",
"langflow-base[nvidia]",
"langflow-base[mistral]",
"langflow-base[sambanova]",
"langflow-base[groq]",
"langflow-base[langfuse]",
"langflow-base[langwatch]",
"langflow-base[langsmith]",
"langflow-base[arize]",
"langflow-base[pypdf]",
"langflow-base[docx]",
"langflow-base[pytube]",
# "langflow-base[crewai]", # commented out due to httpx version conflict
"langflow-base[smolagents]",
"langflow-base[beautifulsoup]",
"langflow-base[serpapi]",
"langflow-base[google-api]",
"langflow-base[wikipedia]",
"langflow-base[fake-useragent]",
"langflow-base[duckduckgo]",
"langflow-base[yfinance]",
"langflow-base[wolframalpha]",
"langflow-base[pyarrow]",
"langflow-base[fastavro]",
"langflow-base[gitpython]",
"langflow-base[nltk]",
"langflow-base[lark]",
"langflow-base[huggingface]",
"langflow-base[metaphor]",
"langflow-base[metal]",
"langflow-base[markup]",
"langflow-base[aws]",
"langflow-base[numexpr]",
"langflow-base[qianfan]",
"langflow-base[pgvector]",
"langflow-base[litellm]",
"langflow-base[zep]",
"langflow-base[youtube]",
"langflow-base[markdown]",
"langflow-base[kubernetes]",
"langflow-base[json-repair]",
"langflow-base[composio]",
"langflow-base[ragstack]",
"langflow-base[opensearch]",
"langflow-base[atlassian]",
"langflow-base[mem0]",
"langflow-base[needle]",
"langflow-base[sseclient]",
"langflow-base[openinference]",
"langflow-base[mcp]",
"langflow-base[ag2]",
"langflow-base[scrapegraph]",
"langflow-base[apify]",
"langflow-base[spider]",
"hanzo-flow-base[couchbase]",
"hanzo-flow-base[cassandra]",
"hanzo-flow-base[clickhouse]",
"hanzo-flow-base[mongodb]",
"hanzo-flow-base[supabase]",
"hanzo-flow-base[redis]",
"hanzo-flow-base[elasticsearch]",
"hanzo-flow-base[faiss]",
"hanzo-flow-base[qdrant]",
"hanzo-flow-base[qdrant-vectors]",
"hanzo-flow-base[weaviate]",
"hanzo-flow-base[chroma]",
"hanzo-flow-base[upstash]",
"hanzo-flow-base[pinecone]",
"hanzo-flow-base[milvus]",
"hanzo-flow-base[mongodb-vectors]",
"hanzo-flow-base[astradb]",
"hanzo-flow-base[openai]",
"hanzo-flow-base[anthropic]",
"hanzo-flow-base[cohere]",
"hanzo-flow-base[google]",
"hanzo-flow-base[ollama]",
"hanzo-flow-base[nvidia]",
"hanzo-flow-base[mistral]",
"hanzo-flow-base[sambanova]",
"hanzo-flow-base[groq]",
"hanzo-flow-base[langfuse]",
"hanzo-flow-base[langwatch]",
"hanzo-flow-base[langsmith]",
"hanzo-flow-base[arize]",
"hanzo-flow-base[pypdf]",
"hanzo-flow-base[docx]",
"hanzo-flow-base[pytube]",
# "hanzo-flow-base[crewai]", # commented out due to httpx version conflict
"hanzo-flow-base[smolagents]",
"hanzo-flow-base[beautifulsoup]",
"hanzo-flow-base[serpapi]",
"hanzo-flow-base[google-api]",
"hanzo-flow-base[wikipedia]",
"hanzo-flow-base[fake-useragent]",
"hanzo-flow-base[duckduckgo]",
"hanzo-flow-base[yfinance]",
"hanzo-flow-base[wolframalpha]",
"hanzo-flow-base[pyarrow]",
"hanzo-flow-base[fastavro]",
"hanzo-flow-base[gitpython]",
"hanzo-flow-base[nltk]",
"hanzo-flow-base[lark]",
"hanzo-flow-base[huggingface]",
"hanzo-flow-base[metaphor]",
"hanzo-flow-base[metal]",
"hanzo-flow-base[markup]",
"hanzo-flow-base[aws]",
"hanzo-flow-base[numexpr]",
"hanzo-flow-base[qianfan]",
"hanzo-flow-base[pgvector]",
"hanzo-flow-base[litellm]",
"hanzo-flow-base[zep]",
"hanzo-flow-base[youtube]",
"hanzo-flow-base[markdown]",
"hanzo-flow-base[kubernetes]",
"hanzo-flow-base[json-repair]",
"hanzo-flow-base[composio]",
"hanzo-flow-base[ragstack]",
"hanzo-flow-base[opensearch]",
"hanzo-flow-base[atlassian]",
"hanzo-flow-base[mem0]",
"hanzo-flow-base[needle]",
"hanzo-flow-base[sseclient]",
"hanzo-flow-base[openinference]",
"hanzo-flow-base[mcp]",
"hanzo-flow-base[ag2]",
"hanzo-flow-base[scrapegraph]",
"hanzo-flow-base[apify]",
"hanzo-flow-base[spider]",
# ALTK
"langflow-base[altk]",
"hanzo-flow-base[altk]",
# Toolguard
"langflow-base[toolguard]",
"hanzo-flow-base[toolguard]",
# Additional LangChain integrations
"langflow-base[langchain-huggingface]",
"langflow-base[langchain-unstructured]",
"langflow-base[graph-retriever]",
"langflow-base[langchain-mcp-adapters]",
"hanzo-flow-base[langchain-huggingface]",
"hanzo-flow-base[langchain-unstructured]",
"hanzo-flow-base[graph-retriever]",
"hanzo-flow-base[langchain-mcp-adapters]",
# Additional monitoring
"langflow-base[opik]",
"langflow-base[traceloop]",
"langflow-base[openlayer]",
"hanzo-flow-base[opik]",
"hanzo-flow-base[traceloop]",
"hanzo-flow-base[openlayer]",
# Document processing / OCR
"langflow-base[docling]",
"langflow-base[easyocr]",
"hanzo-flow-base[docling]",
"hanzo-flow-base[easyocr]",
# Additional tools
"langflow-base[cleanlab]",
"langflow-base[twelvelabs]",
"langflow-base[jigsawstack]",
"langflow-base[assemblyai]",
"hanzo-flow-base[cleanlab]",
"hanzo-flow-base[twelvelabs]",
"hanzo-flow-base[jigsawstack]",
"hanzo-flow-base[assemblyai]",
# Data processing
"langflow-base[datasets]",
"langflow-base[fastparquet]",
"hanzo-flow-base[datasets]",
"hanzo-flow-base[fastparquet]",
# Vision / ML
"langflow-base[vlmrun]",
"langflow-base[cuga]",
"langflow-base[mlx]",
"hanzo-flow-base[vlmrun]",
"hanzo-flow-base[cuga]",
"hanzo-flow-base[mlx]",
# MCP
"langflow-base[fastmcp]",
"hanzo-flow-base[fastmcp]",
# AWS extras
"langflow-base[aioboto3]",
"hanzo-flow-base[aioboto3]",
# Astra
"langflow-base[astrapy]",
"hanzo-flow-base[astrapy]",
# Windows-specific
"langflow-base[gassist]",
"hanzo-flow-base[gassist]",
# wxO deployment adapter,
"langflow-base[ibm-watsonx-clients]"
"hanzo-flow-base[ibm-watsonx-clients]"
]
all = [
"langflow-base[complete]",
"hanzo-flow-base[complete]",
]
[project.scripts]
langflow-base = "flow.launcher:main"
hanzo-flow-base = "flow.launcher:main"
+1 -1
View File
@@ -45,7 +45,7 @@ dependencies = [
"pypdf>=6.10.0,<7.0.0",
"cryptography>=46.0.7",
"ag-ui-protocol>=0.1.10",
"langflow-sdk>=0.1.0",
"hanzo-flow-sdk>=0.1.0",
"markitdown>=0.1.4,<2.0.0",
"setuptools>=80.0.0,<81.0.0",
"wheel>=0.46.2,<1.0.0",
+2 -2
View File
@@ -18,7 +18,7 @@ def _version_callback(value: bool) -> None:
app = typer.Typer(
name="lfx",
help="lfx - Langflow Executor",
help="lfx - Hanzo Flow Executor",
add_completion=False,
)
@@ -34,7 +34,7 @@ def _app_callback(
callback=_version_callback,
),
) -> None:
"""Lfx - Langflow Executor."""
"""Lfx - Hanzo Flow Executor."""
# Register command groups (order determines help-panel ordering)
@@ -152,7 +152,7 @@ class ALTKBaseTool(BaseTool):
llm_client = get_llm(llm_client_type)
llm_client_obj = llm_client(model=model_name, api_key=api_key)
else:
logger.info("ALTK currently only supports OpenAI and Anthropic models through Langflow.")
logger.info("ALTK currently only supports OpenAI and Anthropic models through Hanzo Flow.")
llm_client_obj = None
return llm_client_obj
@@ -746,7 +746,7 @@ class ComposioBaseComponent(Component):
logger.debug(f"Could not populate Composio actions for {self.app_name}: {e}")
def _validate_schema_inputs(self, action_key: str) -> list[InputTypes]:
"""Convert the JSON schema for *action_key* into Langflow input objects."""
"""Convert the JSON schema for *action_key* into Hanzo Flow input objects."""
# Skip validation for default/placeholder values
if action_key in ("disabled", "placeholder", ""):
logger.debug(f"Skipping schema validation for placeholder value: {action_key}")
+3 -3
View File
@@ -299,8 +299,8 @@ def docling_worker(
except ModuleNotFoundError:
msg = (
"Docling is an optional dependency of Langflow. "
"Install with `uv pip install 'langflow[docling]'` "
"Docling is an optional dependency of Hanzo Flow. "
"Install with `uv pip install 'flow[docling]'` "
"or refer to the documentation"
)
queue.put({"error": msg})
@@ -345,7 +345,7 @@ def docling_worker(
except ImportError as e:
msg = (
"langchain-docling is not installed. Please install it with `pip install langchain-docling` "
"or `pip install 'langflow[docling-image-description]'`."
"or `pip install 'flow[docling-image-description]'`."
)
raise ImportError(msg) from e
pic_desc_llm = _deserialize_pydantic_model(pic_desc_config)
+1 -1
View File
@@ -621,7 +621,7 @@ async def get_flow_snake_case(flow_name: str, user_id: str, session, *, is_actio
from flow.services.database.models.flow.model import Flow
from sqlmodel import select
except ImportError as e:
msg = "Langflow Flow model is not available. This feature requires the full Langflow installation."
msg = "Hanzo Flow Flow model is not available. This feature requires the full Hanzo Flow installation."
raise ImportError(msg) from e
uuid_user_id = UUID(user_id) if isinstance(user_id, str) else user_id
@@ -1,8 +1,8 @@
"""Safe defaults for Langflow-created Chroma collections.
"""Safe defaults for Hanzo Flow-created Chroma collections.
Chroma collection configuration can persist server-side embedding functions.
Some embedding functions accept model-loading kwargs such as trust_remote_code.
Langflow embeds client-side, so built-in collection creation should not register
Hanzo Flow embeds client-side, so built-in collection creation should not register
server-side embedding code.
"""
+5 -5
View File
@@ -35,7 +35,7 @@ def register(app: typer.Typer) -> None:
help="Overwrite the destination file if it already exists.",
),
) -> None:
"""Scaffold a new Langflow flow JSON from a built-in template (lazy-loaded)."""
"""Scaffold a new Hanzo Flow flow JSON from a built-in template (lazy-loaded)."""
from pathlib import Path
from lfx.cli.create import create_command, print_templates
@@ -58,7 +58,7 @@ def register(app: typer.Typer) -> None:
rich_help_panel="Authoring",
)
def requirements_command_wrapper(
flow_path: str = typer.Argument(help="Path to the Langflow flow JSON file"),
flow_path: str = typer.Argument(help="Path to the Hanzo Flow flow JSON file"),
output: str | None = typer.Option(
None,
"--output",
@@ -82,7 +82,7 @@ def register(app: typer.Typer) -> None:
help="Do not pin package versions (default: pin to currently installed versions)",
),
) -> None:
"""Generate requirements.txt from a Langflow flow JSON (lazy-loaded)."""
"""Generate requirements.txt from a Hanzo Flow flow JSON (lazy-loaded)."""
import json
from pathlib import Path
@@ -120,7 +120,7 @@ def register(app: typer.Typer) -> None:
def validate_command_wrapper(
flow_paths: list[str] = typer.Argument(
default=None,
help="Path(s) to Langflow flow JSON file(s) or directories to validate. Defaults to flows/.",
help="Path(s) to Hanzo Flow flow JSON file(s) or directories to validate. Defaults to flows/.",
),
dir_path: str | None = typer.Option(
None,
@@ -185,7 +185,7 @@ def register(app: typer.Typer) -> None:
help="Output format: text (default) or json",
),
) -> None:
"""Validate Langflow flow JSON files without executing them (lazy-loaded)."""
"""Validate Hanzo Flow flow JSON files without executing them (lazy-loaded)."""
from lfx.cli.validate import validate_command
# Merge --dir into positional paths for a consistent interface with push
+14 -14
View File
@@ -7,7 +7,7 @@ def register(app: typer.Typer) -> None:
"""Register remote-stage commands on *app*."""
@app.command(
name="status", help="Compare local flow files against a remote Langflow instance", rich_help_panel="Remote"
name="status", help="Compare local flow files against a remote Hanzo Flow instance", rich_help_panel="Remote"
)
def status_command_wrapper(
flow_paths: list[str] = typer.Argument(
@@ -34,12 +34,12 @@ def register(app: typer.Typer) -> None:
target: str | None = typer.Option(
None,
"--target",
help="Langflow instance URL (inline override — skips config file lookup).",
help="Hanzo Flow instance URL (inline override — skips config file lookup).",
),
api_key: str | None = typer.Option(
None,
"--api-key",
help="API key for the Langflow instance (used with --target or to override config).",
help="API key for the Hanzo Flow instance (used with --target or to override config).",
),
show_remote_only: bool = typer.Option(
False,
@@ -62,7 +62,7 @@ def register(app: typer.Typer) -> None:
@app.command(
name="push",
help="Push flow JSON to a remote Langflow instance (upsert by stable ID)",
help="Push flow JSON to a remote Hanzo Flow instance (upsert by stable ID)",
rich_help_panel="Remote",
)
def push_command_wrapper(
@@ -101,12 +101,12 @@ def register(app: typer.Typer) -> None:
target: str | None = typer.Option(
None,
"--target",
help="Langflow instance URL (inline override — skips config file lookup).",
help="Hanzo Flow instance URL (inline override — skips config file lookup).",
),
api_key: str | None = typer.Option(
None,
"--api-key",
help="API key for the Langflow instance (used with --target or to override config).",
help="API key for the Hanzo Flow instance (used with --target or to override config).",
),
dry_run: bool = typer.Option(
False,
@@ -124,7 +124,7 @@ def register(app: typer.Typer) -> None:
help="Clear password/load_from_db field values before pushing.",
),
) -> None:
"""Push Langflow flows to a remote instance using stable IDs for upsert (lazy-loaded)."""
"""Push Hanzo Flow flows to a remote instance using stable IDs for upsert (lazy-loaded)."""
from lfx.cli.push import push_command
push_command(
@@ -142,7 +142,7 @@ def register(app: typer.Typer) -> None:
)
@app.command(
name="pull", help="Pull flows from a remote Langflow instance to local files", rich_help_panel="Remote"
name="pull", help="Pull flows from a remote Hanzo Flow instance to local files", rich_help_panel="Remote"
)
def pull_command_wrapper(
env: str | None = typer.Option(
@@ -181,12 +181,12 @@ def register(app: typer.Typer) -> None:
target: str | None = typer.Option(
None,
"--target",
help="Langflow instance URL (inline override — skips config file lookup).",
help="Hanzo Flow instance URL (inline override — skips config file lookup).",
),
api_key: str | None = typer.Option(
None,
"--api-key",
help="API key for the Langflow instance (used with --target or to override config).",
help="API key for the Hanzo Flow instance (used with --target or to override config).",
),
strip_secrets: bool = typer.Option(
True,
@@ -199,7 +199,7 @@ def register(app: typer.Typer) -> None:
help="JSON indentation level.",
),
) -> None:
"""Pull and normalize flows from a remote Langflow instance (lazy-loaded)."""
"""Pull and normalize flows from a remote Hanzo Flow instance (lazy-loaded)."""
from lfx.cli.pull import pull_command
pull_command(
@@ -261,12 +261,12 @@ def register(app: typer.Typer) -> None:
target: str | None = typer.Option(
None,
"--target",
help="Langflow instance URL (inline override — skips config file lookup).",
help="Hanzo Flow instance URL (inline override — skips config file lookup).",
),
api_key: str | None = typer.Option(
None,
"--api-key",
help="API key for the Langflow instance (used with --target or to override config).",
help="API key for the Hanzo Flow instance (used with --target or to override config).",
),
in_place: bool = typer.Option(
False,
@@ -300,7 +300,7 @@ def register(app: typer.Typer) -> None:
help="JSON indentation level.",
),
) -> None:
"""Export and normalize Langflow flow JSON for version control (lazy-loaded)."""
"""Export and normalize Hanzo Flow flow JSON for version control (lazy-loaded)."""
from lfx.cli.export import export_command
export_command(
+4 -4
View File
@@ -40,7 +40,7 @@ def register(app: typer.Typer) -> None:
example=example,
)
@app.command(name="login", help="Validate credentials against a remote Langflow instance", rich_help_panel="Setup")
@app.command(name="login", help="Validate credentials against a remote Hanzo Flow instance", rich_help_panel="Setup")
def login_command_wrapper(
env: str | None = typer.Option(
None,
@@ -56,15 +56,15 @@ def register(app: typer.Typer) -> None:
target: str | None = typer.Option(
None,
"--target",
help="Langflow instance URL (inline override — skips config file lookup).",
help="Hanzo Flow instance URL (inline override — skips config file lookup).",
),
api_key: str | None = typer.Option(
None,
"--api-key",
help="API key for the Langflow instance (used with --target or to override config).",
help="API key for the Hanzo Flow instance (used with --target or to override config).",
),
) -> None:
"""Test connectivity and authentication for a Langflow environment (lazy-loaded)."""
"""Test connectivity and authentication for a Hanzo Flow environment (lazy-loaded)."""
from lfx.cli.login import login_command
login_command(
+1 -1
View File
@@ -638,7 +638,7 @@ def load_sdk(command_name: str) -> Any:
try:
import flow_sdk # type: ignore[import-untyped]
except ImportError as exc:
msg = f"langflow-sdk is required for lfx {command_name}. Install it with: pip install langflow-sdk"
msg = f"flow-sdk is required for lfx {command_name}. Install it with: pip install flow-sdk"
raise typer.BadParameter(msg) from exc
else:
return langflow_sdk
+3 -3
View File
@@ -7,8 +7,8 @@ Local (default)
result back to disk (or stdout). No network connection required.
Remote (--env / --flow-id / --project-id)
Pull flows directly from a running Langflow instance using the
``langflow-sdk`` HTTP client, normalize them, and write to disk.
Pull flows directly from a running Hanzo Flow instance using the
``flow-sdk`` HTTP client, normalize them, and write to disk.
Examples:
--------
@@ -101,7 +101,7 @@ def export_command(
}
# ------------------------------------------------------------------
# Remote mode: pull from a live Langflow instance
# Remote mode: pull from a live Hanzo Flow instance
# ------------------------------------------------------------------
if flow_id or project_id:
if not env and not target:
+13 -13
View File
@@ -29,13 +29,13 @@ console = Console()
_ENVIRONMENTS_YAML = """\
# .lfx/environments.yaml
#
# Configure your Langflow instances here.
# Configure your Hanzo Flow instances here.
# Safe to commit — API keys are NEVER stored in this file.
# The api_key_env value is the NAME of an environment variable that holds
# the actual API key; set that variable in your shell or CI secrets.
#
# Quick start:
# 1. Open Langflow → Settings → API Keys → Create a new key
# 1. Open Hanzo Flow → Settings → API Keys → Create a new key
# 2. export LANGFLOW_LOCAL_API_KEY=<your key>
# 3. lfx export --env local --flow-id <uuid> --output-dir flows/
@@ -57,15 +57,15 @@ defaults:
"""
_TEST_FLOWS_PY = '''\
"""Integration tests for Langflow flows.
"""Integration tests for Hanzo Flow flows.
Run against a local instance (started with ``lfx serve``):
pytest tests/ --langflow-url http://localhost:8000
pytest tests/ --flow-url http://localhost:8000
Run against a named environment (staging, production, etc.):
pytest tests/ --langflow-env staging -m integration
pytest tests/ --flow-env staging -m integration
The flow_runner fixture auto-skips when no connection is configured,
so these tests are safe to include in any CI pipeline.
@@ -85,16 +85,16 @@ def test_flow_responds(flow_runner):
@pytest.mark.integration
def test_flow_output_quality(flow_runner):
"""Example: assert on the content of the response."""
result = flow_runner("my-flow-endpoint", "What is Langflow?")
result = flow_runner("my-flow-endpoint", "What is Hanzo Flow?")
text = result.first_text_output()
assert text is not None
assert len(text) > 20, f"Response seems too short: {text!r}"
'''
_GITIGNORE = """\
# Langflow credentials -- never commit API keys
# (langflow-environments.toml may contain literal keys; .lfx/environments.yaml is safe to commit)
langflow-environments.toml
# Hanzo Flow credentials -- never commit API keys
# (flow-environments.toml may contain literal keys; .lfx/environments.yaml is safe to commit)
flow-environments.toml
"""
# Templates bundled inside the Python package
@@ -210,11 +210,11 @@ def init_command(
**kw,
)
# .gitignore — keep langflow-environments.toml ignored for backward compat
# .gitignore — keep flow-environments.toml ignored for backward compat
gitignore = target / ".gitignore"
if gitignore.exists():
existing_content = gitignore.read_text(encoding="utf-8")
if "langflow-environments.toml" not in existing_content:
if "flow-environments.toml" not in existing_content:
gitignore.write_text(existing_content.rstrip() + "\n\n" + _GITIGNORE, encoding="utf-8")
created.append((".gitignore", "appended credentials ignore rule"))
else:
@@ -249,9 +249,9 @@ def init_command(
if example:
console.print(" 3. [bold]lfx validate flows/hello-world.json[/bold] (check the starter flow)")
console.print(" 4. [bold]lfx serve flows/hello-world.json[/bold] (run it locally)")
console.print(" 5. [bold]lfx push --dir flows/ --env local[/bold] (deploy to Langflow)")
console.print(" 5. [bold]lfx push --dir flows/ --env local[/bold] (deploy to Hanzo Flow)")
else:
console.print(" 3. [bold]lfx create my-flow --template hello-world[/bold]")
console.print(" 4. [bold]lfx push --dir flows/ --env local[/bold]")
console.print(f" {'6' if example else '5'}. [bold]pytest tests/ --langflow-env local[/bold]")
console.print(f" {'6' if example else '5'}. [bold]pytest tests/ --flow-env local[/bold]")
console.print()
+7 -7
View File
@@ -1,4 +1,4 @@
"""lfx login -- validate credentials against a remote Langflow instance.
"""lfx login -- validate credentials against a remote Hanzo Flow instance.
Tests whether the configured URL and API key are reachable and accepted,
then prints a summary with guidance on how to fix any problems.
@@ -82,7 +82,7 @@ def _probe_connection(client: Any, sdk: Any) -> tuple[bool, str, int]:
except Exception as exc: # noqa: BLE001
# A Pydantic ValidationError means the HTTP request completed and was
# authenticated (auth is fine) but the SDK's schema doesn't match the
# local Langflow version exactly. Treat this as a successful probe.
# local Hanzo Flow version exactly. Treat this as a successful probe.
if "ValidationError" in type(exc).__qualname__:
return True, "OK", 0
return False, f"error:{exc}", 0
@@ -150,13 +150,13 @@ def login_command(
err_console.print()
err_console.print("[bold]How to fix:[/bold]")
if key_env_name:
err_console.print(" 1. Open Langflow → Settings → API Keys → Create a new key")
err_console.print(" 1. Open Hanzo Flow → Settings → API Keys → Create a new key")
err_console.print(f" 2. [bold]export {key_env_name}=<your-new-key>[/bold]")
elif env_cfg.name not in ("__inline__", "__env__"):
err_console.print(" 1. Open Langflow → Settings → API Keys → Create a new key")
err_console.print(" 1. Open Hanzo Flow → Settings → API Keys → Create a new key")
err_console.print(" 2. Pass [bold]--api-key <key>[/bold] or configure api_key_env in your YAML")
else:
err_console.print(" 1. Open Langflow → Settings → API Keys → Create a new key")
err_console.print(" 1. Open Hanzo Flow → Settings → API Keys → Create a new key")
err_console.print(" 2. Pass [bold]--api-key <key>[/bold]")
raise typer.Exit(1)
@@ -166,9 +166,9 @@ def login_command(
err_console.print(f" URL: {env_cfg.url}")
err_console.print()
err_console.print("[bold]How to fix:[/bold]")
err_console.print(" • Make sure your Langflow instance is running")
err_console.print(" • Make sure your Hanzo Flow instance is running")
err_console.print(" • Check the URL in your .lfx/environments.yaml")
err_console.print(" • If running locally: [bold]langflow run[/bold] or [bold]lfx serve <flow.json>[/bold]")
err_console.print(" • If running locally: [bold]flow run[/bold] or [bold]lfx serve <flow.json>[/bold]")
raise typer.Exit(1)
# Generic HTTP or other error
+2 -2
View File
@@ -1,6 +1,6 @@
"""lfx pull -- fetch flows from a remote Langflow instance to local files.
"""lfx pull -- fetch flows from a remote Hanzo Flow instance to local files.
Downloads flows from a live Langflow instance, normalizes them for version
Downloads flows from a live Hanzo Flow instance, normalizes them for version
control, and writes them to a local directory. Repeated pulls are safe:
existing files are overwritten with the latest remote state.
+1 -1
View File
@@ -1,4 +1,4 @@
"""lfx push -- push normalized flow JSON to a remote Langflow instance.
"""lfx push -- push normalized flow JSON to a remote Hanzo Flow instance.
Uses stable flow IDs for upsert (PUT /api/v1/flows/{id}), so repeated pushes
are idempotent: the first push creates the flow, subsequent ones update it in
+2 -2
View File
@@ -110,9 +110,9 @@ async def run(
),
),
) -> None:
"""Execute a Langflow graph script or JSON flow and return the result.
"""Execute a Hanzo Flow graph script or JSON flow and return the result.
This command analyzes and executes either a Python script containing a Langflow graph,
This command analyzes and executes either a Python script containing a Hanzo Flow graph,
a JSON flow file, inline JSON, or JSON from stdin, returning the result in the specified format.
By default, output is minimal for use in containers and serverless environments.

Some files were not shown because too many files have changed in this diff Show More