feat: migrate from loguru to structlog (#9321)

* refactor: Enhance logging configuration with structured logging and buffer support

* feat: Add structlog dependency for enhanced logging support

* refactor: Update ruff dependency to version 0.12.7 and remove unused pylint references

* Refactor logging imports to use langflow.logging.logger

- Replaced instances of loguru logger with langflow.logging.logger across multiple files.
- Updated logging calls to use asynchronous methods where applicable (e.g., await logger.awarning).
- Ensured consistent logging practices throughout the codebase by standardizing the logger import.

* refactor: Add missing docstring rule to ruff configuration

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* [autofix.ci] apply automated fixes

* fix: update logger calls to use async methods in DatabaseService

* fix: update logger calls to use async methods in initialize_database and session_getter

* fix: update logger calls to use async methods in LangflowRunnerExperimental

* fix: update logger calls to use async methods across various services

* Refactor logging to use asynchronous logger methods across multiple components

- Updated logging calls in  to use async logger methods for error handling and debugging.
- Modified  to utilize async logging for error messages during file deletion.
- Changed logging in , , and other agent-related files to use async methods for error and debug messages.
- Refactored logging in various components including , , , and others to ensure consistent use of async logging.
- Updated , , and  to replace synchronous logging with asynchronous counterparts.
- Ensured all logging changes maintain the original message structure while enhancing performance with async capabilities.

* [autofix.ci] apply automated fixes

* fix: update logger calls to use async methods in various components

* feat: add InterceptHandler to route standard logging messages to structlog

* refactor: remove async_file parameter from logger configuration

* fix: correct log level mapping and enhance log rotation validation

* refactor: remove unused logging import and streamline schema imports

* Refactor logging in AssemblyAI components and other modules to use exc_info for better error tracing

- Updated logging statements in AssemblyAI components (e.g., assemblyai_get_subtitles, assemblyai_lemur, assemblyai_list_transcripts, etc.) to use logger.debug with exc_info=True for improved error context.
- Modified logging in various helper and utility functions to enhance error reporting.
- Ensured consistent logging practices across the codebase for better maintainability and debugging.

* refactor: remove InterceptHandler from logger configuration to avoid recursion

* refactor: enhance test coverage for logger module with comprehensive test cases

* refactor: add rule to ignore mutable objects without __hash__ method in linter

* fix various lint issues

* refactor: update function signatures to improve clarity and consistency

* refactor: streamline import statements and enhance response handling in voice mode

* refactor: simplify lifespan cleanup logic

* refactor: remove unused caplog fixture and improve graph test clarity

* fix: specify logger type as BoundLogger for clarity

* [autofix.ci] apply automated fixes

* refactor: remove unused logger and correct return statement in arun_flow_from_json

* refactor: update logger usage to support async methods in tests

* fix: correct datetime bounds for hypothesis strategies to avoid timezone issues

* fix: update warning message for invalid string input type in tests

* refactor: simplify message handling tests by removing database session mocks

* refactor: remove redundant comment from test_max_size function in test_logger.py

* fix: update patch target for DEV setting in remove_exception_in_production test

* fix: update patch target for DEV setting in remove_exception_in_production test

* fix: update patching of DEV setting in remove_exception_in_production tests to use module import

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Gabriel Luiz Freitas Almeida 2025-08-22 14:56:07 -03:00 committed by GitHub
commit a1629a7553
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
203 changed files with 2038 additions and 1250 deletions

View file

@ -113,8 +113,6 @@ dependencies = [
"pydantic-ai>=0.0.19",
"smolagents>=1.8.0",
"apify-client>=1.8.1",
"pylint>=3.3.4",
"ruff>=0.9.7",
"langchain-graph-retriever==0.6.1",
"graph-retriever==0.6.1",
"ibm-watsonx-ai>=1.3.1",
@ -127,6 +125,7 @@ dependencies = [
"docling_core>=2.36.1",
"filelock>=3.18.0",
"jigsawstack==0.2.7",
"structlog>=25.4.0",
"aiosqlite==0.21.0",
"fastparquet>=2024.11.0",
"traceloop-sdk>=0.43.1",
@ -138,7 +137,7 @@ dev = [
"types-redis>=4.6.0.5",
"ipykernel>=6.29.0",
"mypy>=1.11.0",
"ruff>=0.9.7,<0.10",
"ruff>=0.12.7",
"httpx>=0.27.0",
"pytest>=8.2.0",
"types-requests>=2.32.0",
@ -298,7 +297,9 @@ ignore = [
"TD002", # Missing author in TODO
"TD003", # Missing issue link in TODO
"TRY301", # A bit too harsh (Abstract `raise` to an inner function)
"PLC0415", # Inline imports
"D10", # Missing docstrings
"PLW1641", # Object does not implement `__hash__` method (mutable objects shouldn't be hashable)
# Rules that are TODOs
"ANN",
]
@ -308,6 +309,7 @@ external = ["RUF027"]
[tool.ruff.lint.per-file-ignores]
"scripts/*" = ["D1", "INP", "T201"]
"src/backend/base/langflow/alembic/versions/*" = ["INP001", "D415", "PGH003"]
"src/backend/tests/*" = [
"D1",
"PLR2004",

View file

@ -162,7 +162,7 @@ def wait_for_server_ready(host, port, protocol) -> None:
except HTTPError:
time.sleep(1)
except Exception: # noqa: BLE001
logger.opt(exception=True).debug("Error while waiting for the server to become ready.")
logger.debug("Error while waiting for the server to become ready.", exc_info=True)
time.sleep(1)

View file

@ -6,19 +6,19 @@ Create Date: 2024-04-12 18:11:06.454037
"""
from typing import Sequence, Union
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
from loguru import logger
from sqlalchemy.dialects import postgresql
from sqlalchemy.engine.reflection import Inspector
from langflow.logging.logger import logger
# revision identifiers, used by Alembic.
revision: str = "4e5980a44eaa"
down_revision: Union[str, None] = "79e675cb6752"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
down_revision: str | None = "79e675cb6752"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
@ -37,11 +37,10 @@ def upgrade() -> None:
type_=sa.DateTime(timezone=True),
existing_nullable=False,
)
elif created_at_column is None:
logger.warning("Column 'created_at' not found in table 'apikey'")
else:
if created_at_column is None:
logger.warning("Column 'created_at' not found in table 'apikey'")
else:
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'apikey'")
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'apikey'")
if "variable" in table_names:
columns = inspector.get_columns("variable")
created_at_column = next((column for column in columns if column["name"] == "created_at"), None)
@ -54,11 +53,10 @@ def upgrade() -> None:
type_=sa.DateTime(timezone=True),
existing_nullable=True,
)
elif created_at_column is None:
logger.warning("Column 'created_at' not found in table 'variable'")
else:
if created_at_column is None:
logger.warning("Column 'created_at' not found in table 'variable'")
else:
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'variable'")
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'variable'")
if updated_at_column is not None and isinstance(updated_at_column["type"], postgresql.TIMESTAMP):
batch_op.alter_column(
"updated_at",
@ -66,11 +64,10 @@ def upgrade() -> None:
type_=sa.DateTime(timezone=True),
existing_nullable=True,
)
elif updated_at_column is None:
logger.warning("Column 'updated_at' not found in table 'variable'")
else:
if updated_at_column is None:
logger.warning("Column 'updated_at' not found in table 'variable'")
else:
logger.warning(f"Column 'updated_at' has type {updated_at_column['type']} in table 'variable'")
logger.warning(f"Column 'updated_at' has type {updated_at_column['type']} in table 'variable'")
# ### end Alembic commands ###
@ -92,11 +89,10 @@ def downgrade() -> None:
type_=postgresql.TIMESTAMP(),
existing_nullable=True,
)
elif updated_at_column is None:
logger.warning("Column 'updated_at' not found in table 'variable'")
else:
if updated_at_column is None:
logger.warning("Column 'updated_at' not found in table 'variable'")
else:
logger.warning(f"Column 'updated_at' has type {updated_at_column['type']} in table 'variable'")
logger.warning(f"Column 'updated_at' has type {updated_at_column['type']} in table 'variable'")
if created_at_column is not None and isinstance(created_at_column["type"], sa.DateTime):
batch_op.alter_column(
"created_at",
@ -104,11 +100,10 @@ def downgrade() -> None:
type_=postgresql.TIMESTAMP(),
existing_nullable=True,
)
elif created_at_column is None:
logger.warning("Column 'created_at' not found in table 'variable'")
else:
if created_at_column is None:
logger.warning("Column 'created_at' not found in table 'variable'")
else:
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'variable'")
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'variable'")
if "apikey" in table_names:
columns = inspector.get_columns("apikey")
@ -121,10 +116,9 @@ def downgrade() -> None:
type_=postgresql.TIMESTAMP(),
existing_nullable=False,
)
elif created_at_column is None:
logger.warning("Column 'created_at' not found in table 'apikey'")
else:
if created_at_column is None:
logger.warning("Column 'created_at' not found in table 'apikey'")
else:
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'apikey'")
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'apikey'")
# ### end Alembic commands ###

View file

@ -6,16 +6,16 @@ Create Date: 2024-04-13 10:57:23.061709
"""
from typing import Sequence, Union
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
from loguru import logger
from sqlalchemy.engine.reflection import Inspector
down_revision: Union[str, None] = "4e5980a44eaa"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
from langflow.logging.logger import logger
down_revision: str | None = "4e5980a44eaa"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
# Revision identifiers, used by Alembic.
revision = "58b28437a398"

View file

@ -6,19 +6,19 @@ Create Date: 2024-04-11 19:23:10.697335
"""
from typing import Sequence, Union
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
from loguru import logger
from sqlalchemy.dialects import postgresql
from sqlalchemy.engine.reflection import Inspector
from langflow.logging.logger import logger
# revision identifiers, used by Alembic.
revision: str = "79e675cb6752"
down_revision: Union[str, None] = "e3bc869fa272"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
down_revision: str | None = "e3bc869fa272"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
@ -37,11 +37,10 @@ def upgrade() -> None:
type_=sa.DateTime(timezone=True),
existing_nullable=False,
)
elif created_at_column is None:
logger.warning("Column 'created_at' not found in table 'apikey'")
else:
if created_at_column is None:
logger.warning("Column 'created_at' not found in table 'apikey'")
else:
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'apikey'")
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'apikey'")
if "variable" in table_names:
columns = inspector.get_columns("variable")
created_at_column = next((column for column in columns if column["name"] == "created_at"), None)
@ -54,11 +53,10 @@ def upgrade() -> None:
type_=sa.DateTime(timezone=True),
existing_nullable=True,
)
elif created_at_column is None:
logger.warning("Column 'created_at' not found in table 'variable'")
else:
if created_at_column is None:
logger.warning("Column 'created_at' not found in table 'variable'")
else:
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'variable'")
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'variable'")
if updated_at_column is not None and isinstance(updated_at_column["type"], postgresql.TIMESTAMP):
batch_op.alter_column(
"updated_at",
@ -66,11 +64,10 @@ def upgrade() -> None:
type_=sa.DateTime(timezone=True),
existing_nullable=True,
)
elif updated_at_column is None:
logger.warning("Column 'updated_at' not found in table 'variable'")
else:
if updated_at_column is None:
logger.warning("Column 'updated_at' not found in table 'variable'")
else:
logger.warning(f"Column 'updated_at' has type {updated_at_column['type']} in table 'variable'")
logger.warning(f"Column 'updated_at' has type {updated_at_column['type']} in table 'variable'")
# ### end Alembic commands ###
@ -92,11 +89,10 @@ def downgrade() -> None:
type_=postgresql.TIMESTAMP(),
existing_nullable=True,
)
elif updated_at_column is None:
logger.warning("Column 'updated_at' not found in table 'variable'")
else:
if updated_at_column is None:
logger.warning("Column 'updated_at' not found in table 'variable'")
else:
logger.warning(f"Column 'updated_at' has type {updated_at_column['type']} in table 'variable'")
logger.warning(f"Column 'updated_at' has type {updated_at_column['type']} in table 'variable'")
if created_at_column is not None and isinstance(created_at_column["type"], sa.DateTime):
batch_op.alter_column(
"created_at",
@ -104,11 +100,10 @@ def downgrade() -> None:
type_=postgresql.TIMESTAMP(),
existing_nullable=True,
)
elif created_at_column is None:
logger.warning("Column 'created_at' not found in table 'variable'")
else:
if created_at_column is None:
logger.warning("Column 'created_at' not found in table 'variable'")
else:
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'variable'")
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'variable'")
if "apikey" in table_names:
columns = inspector.get_columns("apikey")
@ -121,10 +116,9 @@ def downgrade() -> None:
type_=postgresql.TIMESTAMP(),
existing_nullable=False,
)
elif created_at_column is None:
logger.warning("Column 'created_at' not found in table 'apikey'")
else:
if created_at_column is None:
logger.warning("Column 'created_at' not found in table 'apikey'")
else:
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'apikey'")
logger.warning(f"Column 'created_at' has type {created_at_column['type']} in table 'apikey'")
# ### end Alembic commands ###

View file

@ -1,4 +1,4 @@
"""Add unique constraints
"""Add unique constraints.
Revision ID: b2fa308044b5
Revises: 0b8757876a7c
@ -6,25 +6,25 @@ Create Date: 2024-01-26 13:31:14.797548
"""
from typing import Sequence, Union
from collections.abc import Sequence
import sqlalchemy as sa
import sqlmodel
from alembic import op
from loguru import logger # noqa
from sqlalchemy.engine.reflection import Inspector
from langflow.logging.logger import logger
# revision identifiers, used by Alembic.
revision: str = "b2fa308044b5"
down_revision: Union[str, None] = "0b8757876a7c"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
down_revision: str | None = "0b8757876a7c"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = sa.inspect(conn) # type: ignore
inspector = sa.inspect(conn)
tables = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ###
try:
@ -53,14 +53,13 @@ def upgrade() -> None:
if "fk_flow_user_id_user" not in constraint_names:
batch_op.create_foreign_key("fk_flow_user_id_user", "user", ["user_id"], ["id"])
except Exception as e:
except Exception as e: # noqa: BLE001
logger.exception(f"Error during upgrade: {e}")
pass
def downgrade() -> None:
conn = op.get_bind()
inspector = sa.inspect(conn) # type: ignore
inspector = sa.inspect(conn)
try:
# Re-create the dropped table 'flowstyle' if it was previously dropped in upgrade
if "flowstyle" not in inspector.get_table_names():
@ -97,6 +96,6 @@ def downgrade() -> None:
if "fk_flow_user_id_user" in constraint_names:
batch_op.drop_constraint("fk_flow_user_id_user", type_="foreignkey")
except Exception as e:
except Exception as e: # noqa: BLE001
# It's generally a good idea to log the exception or handle it in a way other than a bare pass
print(f"Error during downgrade: {e}")
logger.exception(f"Error during downgrade: {e}")

View file

@ -6,7 +6,6 @@ import uuid
from collections.abc import AsyncIterator
from fastapi import BackgroundTasks, HTTPException, Response
from loguru import logger
from sqlmodel import select
from langflow.api.disconnect import DisconnectHandlerStreamingResponse
@ -20,16 +19,12 @@ from langflow.api.utils import (
get_top_level_vertices,
parse_exception,
)
from langflow.api.v1.schemas import (
FlowDataRequest,
InputValueRequest,
ResultDataResponse,
VertexBuildResponse,
)
from langflow.api.v1.schemas import FlowDataRequest, InputValueRequest, ResultDataResponse, VertexBuildResponse
from langflow.events.event_manager import EventManager
from langflow.exceptions.component import ComponentBuildError
from langflow.graph.graph.base import Graph
from langflow.graph.utils import log_vertex_build
from langflow.logging.logger import logger
from langflow.schema.message import ErrorMessage
from langflow.schema.schema import OutputValue
from langflow.services.database.models.flow.model import Flow
@ -75,7 +70,7 @@ async def start_flow_build(
)
queue_service.start_job(job_id, task_coro)
except Exception as e:
logger.exception("Failed to create queue and start task")
await logger.aexception("Failed to create queue and start task")
raise HTTPException(status_code=500, detail=str(e)) from e
return job_id
@ -91,7 +86,7 @@ async def get_flow_events_response(
main_queue, event_manager, event_task, _ = queue_service.get_queue_data(job_id)
if event_delivery in (EventDeliveryType.STREAMING, EventDeliveryType.DIRECT):
if event_task is None:
logger.error(f"No event task found for job {job_id}")
await logger.aerror(f"No event task found for job {job_id}")
raise HTTPException(status_code=404, detail="No event task found for job")
return await create_flow_response(
queue=main_queue,
@ -130,19 +125,19 @@ async def get_flow_events_response(
content = "\n".join([event for event in events if event is not None])
return Response(content=content, media_type="application/x-ndjson")
except asyncio.CancelledError as exc:
logger.info(f"Event polling was cancelled for job {job_id}")
await logger.ainfo(f"Event polling was cancelled for job {job_id}")
raise HTTPException(status_code=499, detail="Event polling was cancelled") from exc
except asyncio.TimeoutError:
logger.warning(f"Timeout while waiting for events for job {job_id}")
await logger.awarning(f"Timeout while waiting for events for job {job_id}")
return Response(content="", media_type="application/x-ndjson") # Return empty response instead of error
except JobQueueNotFoundError as exc:
logger.error(f"Job not found: {job_id}. Error: {exc!s}")
await logger.aerror(f"Job not found: {job_id}. Error: {exc!s}")
raise HTTPException(status_code=404, detail=f"Job not found: {exc!s}") from exc
except Exception as exc:
if isinstance(exc, HTTPException):
raise
logger.exception(f"Unexpected error processing flow events for job {job_id}")
await logger.aexception(f"Unexpected error processing flow events for job {job_id}")
raise HTTPException(status_code=500, detail=f"Unexpected error: {exc!s}") from exc
@ -161,9 +156,9 @@ async def create_flow_response(
break
get_time = time.time()
yield value.decode("utf-8")
logger.debug(f"Event {event_id} consumed in {get_time - put_time:.4f}s")
await logger.adebug(f"Event {event_id} consumed in {get_time - put_time:.4f}s")
except Exception as exc: # noqa: BLE001
logger.exception(f"Error consuming event: {exc}")
await logger.aexception(f"Error consuming event: {exc}")
break
def on_disconnect() -> None:
@ -233,7 +228,7 @@ async def generate_flow_events(
if "stream or streaming set to True" in str(exc):
raise HTTPException(status_code=400, detail=str(exc)) from exc
logger.exception("Error checking build status")
await logger.aexception("Error checking build status")
raise HTTPException(status_code=500, detail=str(exc)) from exc
return first_layer, vertices_to_run, graph
@ -317,7 +312,7 @@ async def generate_flow_events(
tb = exc.formatted_traceback
else:
tb = traceback.format_exc()
logger.exception("Error building Component")
await logger.aexception("Error building Component")
params = format_exception_message(exc)
message = {"errorMessage": params, "stackTrace": tb}
valid = False
@ -390,7 +385,7 @@ async def generate_flow_events(
component_error_message=str(exc),
),
)
logger.exception("Error building Component")
await logger.aexception("Error building Component")
message = parse_exception(exc)
raise HTTPException(status_code=500, detail=message) from exc
@ -411,7 +406,7 @@ async def generate_flow_events(
try:
vertex_build_response: VertexBuildResponse = await _build_vertex(vertex_id, graph, event_manager)
except asyncio.CancelledError as exc:
logger.error(f"Build cancelled: {exc}")
await logger.aerror(f"Build cancelled: {exc}")
raise
# send built event or error event
@ -459,7 +454,7 @@ async def generate_flow_events(
background_tasks.add_task(graph.end_all_traces_in_context())
raise
except Exception as e:
logger.error(f"Error building vertices: {e}")
await logger.aerror(f"Error building vertices: {e}")
custom_component = graph.get_vertex(vertex_id).custom_component
trace_name = getattr(custom_component, "trace_name", None)
error_message = ErrorMessage(
@ -499,11 +494,11 @@ async def cancel_flow_build(
_, _, event_task, _ = queue_service.get_queue_data(job_id)
if event_task is None:
logger.warning(f"No event task found for job_id {job_id}")
await logger.awarning(f"No event task found for job_id {job_id}")
return True # Nothing to cancel is still a success
if event_task.done():
logger.info(f"Task for job_id {job_id} is already completed")
await logger.ainfo(f"Task for job_id {job_id} is already completed")
return True # Nothing to cancel is still a success
# Store the task reference to check status after cleanup
@ -515,18 +510,18 @@ async def cancel_flow_build(
except asyncio.CancelledError:
# Check if the task was actually cancelled
if task_before_cleanup.cancelled():
logger.info(f"Successfully cancelled flow build for job_id {job_id} (CancelledError caught)")
await logger.ainfo(f"Successfully cancelled flow build for job_id {job_id} (CancelledError caught)")
return True
# If the task wasn't cancelled, re-raise the exception
logger.error(f"CancelledError caught but task for job_id {job_id} was not cancelled")
await logger.aerror(f"CancelledError caught but task for job_id {job_id} was not cancelled")
raise
# If no exception was raised, verify that the task was actually cancelled
# The task should be done (cancelled) after cleanup
if task_before_cleanup.cancelled():
logger.info(f"Successfully cancelled flow build for job_id {job_id}")
await logger.ainfo(f"Successfully cancelled flow build for job_id {job_id}")
return True
# If we get here, the task wasn't cancelled properly
logger.error(f"Failed to cancel flow build for job_id {job_id}, task is still running")
await logger.aerror(f"Failed to cancel flow build for job_id {job_id}, task is still running")
return False

View file

@ -1,11 +1,11 @@
import uuid
from fastapi import APIRouter, HTTPException, status
from loguru import logger
from pydantic import BaseModel
from sqlmodel import select
from langflow.api.utils import DbSession
from langflow.logging.logger import logger
from langflow.services.database.models.flow.model import Flow
from langflow.services.deps import get_chat_service
@ -49,7 +49,7 @@ async def health_check(
(await session.exec(stmt)).first()
response.db = "ok"
except Exception: # noqa: BLE001
logger.exception("Error checking database")
await logger.aexception("Error checking database")
try:
chat = get_chat_service()
@ -57,7 +57,7 @@ async def health_check(
await chat.get_cache("health_check")
response.chat = "ok"
except Exception: # noqa: BLE001
logger.exception("Error checking chat service")
await logger.aexception("Error checking chat service")
if response.has_error():
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=response.model_dump())

View file

@ -8,11 +8,11 @@ from typing import TYPE_CHECKING, Annotated, Any
from fastapi import Depends, HTTPException, Query
from fastapi_pagination import Params
from loguru import logger
from sqlalchemy import delete
from sqlmodel.ext.asyncio.session import AsyncSession
from langflow.graph.graph.base import Graph
from langflow.logging.logger import logger
from langflow.services.auth.utils import get_current_active_user, get_current_active_user_mcp
from langflow.services.database.models.flow.model import Flow
from langflow.services.database.models.message.model import MessageTable
@ -119,7 +119,7 @@ async def check_langflow_version(component: StoreComponentCreate) -> None:
if langflow_version is None:
raise HTTPException(status_code=500, detail="Unable to verify the latest version of Langflow")
if langflow_version != component.last_tested_version:
logger.warning(
await logger.awarning(
f"Your version of Langflow ({component.last_tested_version}) is outdated. "
f"Please update to the latest version ({langflow_version}) and try again."
)
@ -371,7 +371,7 @@ async def verify_public_flow_and_get_user(flow_id: uuid.UUID, client_id: str | N
user = await get_user_by_flow_id_or_endpoint_name(str(flow_id))
except Exception as exc:
logger.exception(f"Error getting user for public flow {flow_id}")
await logger.aexception(f"Error getting user for public flow {flow_id}")
raise HTTPException(status_code=403, detail="Flow is not accessible") from exc
if not user:

View file

@ -5,10 +5,10 @@ from uuid import UUID
from langchain_core.agents import AgentAction, AgentFinish
from langchain_core.callbacks.base import AsyncCallbackHandler
from loguru import logger
from typing_extensions import override
from langflow.api.v1.schemas import ChatResponse, PromptResponse
from langflow.logging.logger import logger
from langflow.services.deps import get_chat_service, get_socket_service
from langflow.utils.util import remove_ansi_escape_codes
@ -78,7 +78,7 @@ class AsyncStreamingLLMCallbackHandleSIO(AsyncCallbackHandler):
for resp in resps:
await self.socketio_service.emit_token(to=self.sid, data=resp.model_dump())
except Exception: # noqa: BLE001
logger.exception("Error sending response")
await logger.aexception("Error sending response")
async def on_tool_error(
self,

View file

@ -6,23 +6,10 @@ import traceback
import uuid
from typing import TYPE_CHECKING, Annotated
from fastapi import (
APIRouter,
BackgroundTasks,
Body,
Depends,
HTTPException,
Request,
status,
)
from fastapi import APIRouter, BackgroundTasks, Body, Depends, HTTPException, Request, status
from fastapi.responses import StreamingResponse
from loguru import logger
from langflow.api.build import (
cancel_flow_build,
get_flow_events_response,
start_flow_build,
)
from langflow.api.build import cancel_flow_build, get_flow_events_response, start_flow_build
from langflow.api.limited_background_tasks import LimitVertexBuildBackgroundTasks
from langflow.api.utils import (
CurrentActiveUser,
@ -48,6 +35,7 @@ from langflow.api.v1.schemas import (
from langflow.exceptions.component import ComponentBuildError
from langflow.graph.graph.base import Graph
from langflow.graph.utils import log_vertex_build
from langflow.logging.logger import logger
from langflow.schema.schema import OutputValue
from langflow.services.cache.utils import CacheMiss
from langflow.services.chat.service import ChatService
@ -135,7 +123,7 @@ async def retrieve_vertices_order(
)
if "stream or streaming set to True" in str(exc):
raise HTTPException(status_code=400, detail=str(exc)) from exc
logger.exception("Error checking build status")
await logger.aexception("Error checking build status")
raise HTTPException(status_code=500, detail=str(exc)) from exc
@ -239,17 +227,17 @@ async def cancel_build(
return CancelFlowResponse(success=False, message="Failed to cancel flow build")
except asyncio.CancelledError:
# If CancelledError reaches here, it means the task was not successfully cancelled
logger.error(f"Failed to cancel flow build for job_id {job_id} (CancelledError caught)")
await logger.aerror(f"Failed to cancel flow build for job_id {job_id} (CancelledError caught)")
return CancelFlowResponse(success=False, message="Failed to cancel flow build")
except ValueError as exc:
# Job not found
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
except JobQueueNotFoundError as exc:
logger.error(f"Job not found: {job_id}. Error: {exc!s}")
await logger.aerror(f"Job not found: {job_id}. Error: {exc!s}")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Job not found: {exc!s}") from exc
except Exception as exc:
# Any other unexpected error
logger.exception(f"Error cancelling flow build for job_id {job_id}: {exc}")
await logger.aexception(f"Error cancelling flow build for job_id {job_id}: {exc}")
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
@ -297,7 +285,7 @@ async def build_vertex(
cache = await chat_service.get_cache(flow_id_str)
if isinstance(cache, CacheMiss):
# If there's no cache
logger.warning(f"No cache found for {flow_id_str}. Building graph starting at {vertex_id}")
await logger.awarning(f"No cache found for {flow_id_str}. Building graph starting at {vertex_id}")
graph = await build_graph_from_db(
flow_id=flow_id,
session=await anext(get_session()),
@ -331,7 +319,7 @@ async def build_vertex(
tb = exc.formatted_traceback
else:
tb = traceback.format_exc()
logger.exception("Error building Component")
await logger.aexception("Error building Component")
params = format_exception_message(exc)
message = {"errorMessage": params, "stackTrace": tb}
valid = False
@ -408,7 +396,7 @@ async def build_vertex(
component_error_message=str(exc),
),
)
logger.exception("Error building Component")
await logger.aexception("Error building Component")
message = parse_exception(exc)
raise HTTPException(status_code=500, detail=message) from exc
@ -421,14 +409,14 @@ async def _stream_vertex(flow_id: str, vertex_id: str, chat_service: ChatService
try:
cache = await chat_service.get_cache(flow_id)
except Exception as exc: # noqa: BLE001
logger.exception("Error building Component")
await logger.aexception("Error building Component")
yield str(StreamData(event="error", data={"error": str(exc)}))
return
if isinstance(cache, CacheMiss):
# If there's no cache
msg = f"No cache found for {flow_id}."
logger.error(msg)
await logger.aerror(msg)
yield str(StreamData(event="error", data={"error": msg}))
return
else:
@ -437,13 +425,13 @@ async def _stream_vertex(flow_id: str, vertex_id: str, chat_service: ChatService
try:
vertex: InterfaceVertex = graph.get_vertex(vertex_id)
except Exception as exc: # noqa: BLE001
logger.exception("Error building Component")
await logger.aexception("Error building Component")
yield str(StreamData(event="error", data={"error": str(exc)}))
return
if not hasattr(vertex, "stream"):
msg = f"Vertex {vertex_id} does not support streaming"
logger.error(msg)
await logger.aerror(msg)
yield str(StreamData(event="error", data={"error": msg}))
return
@ -460,7 +448,7 @@ async def _stream_vertex(flow_id: str, vertex_id: str, chat_service: ChatService
yield str(stream_data)
elif not vertex.frozen or not vertex.built:
logger.debug(f"Streaming vertex {vertex_id}")
await logger.adebug(f"Streaming vertex {vertex_id}")
stream_data = StreamData(
event="message",
data={"message": f"Streaming vertex {vertex_id}"},
@ -474,7 +462,7 @@ async def _stream_vertex(flow_id: str, vertex_id: str, chat_service: ChatService
)
yield str(stream_data)
except Exception as exc: # noqa: BLE001
logger.exception("Error building Component")
await logger.aexception("Error building Component")
exc_message = parse_exception(exc)
if exc_message == "The message must be an iterator or an async iterator.":
exc_message = "This stream has already been closed."
@ -487,11 +475,11 @@ async def _stream_vertex(flow_id: str, vertex_id: str, chat_service: ChatService
yield str(stream_data)
else:
msg = f"No result found for vertex {vertex_id}"
logger.error(msg)
await logger.aerror(msg)
yield str(StreamData(event="error", data={"error": msg}))
return
finally:
logger.debug("Closing stream")
await logger.adebug("Closing stream")
if graph:
await chat_service.set_cache(flow_id, graph)
yield str(StreamData(event="close", data={"message": "Stream closed"}))
@ -625,7 +613,7 @@ async def build_public_tmp(
flow_name=flow_name or f"{client_id}_{flow_id}",
)
except Exception as exc:
logger.exception("Error building public flow")
await logger.aexception("Error building public flow")
if isinstance(exc, HTTPException):
raise
raise HTTPException(status_code=500, detail=str(exc)) from exc

View file

@ -11,7 +11,6 @@ import sqlalchemy as sa
from fastapi import APIRouter, BackgroundTasks, Body, Depends, HTTPException, Request, UploadFile, status
from fastapi.encoders import jsonable_encoder
from fastapi.responses import StreamingResponse
from loguru import logger
from sqlmodel import select
from langflow.api.utils import CurrentActiveUser, DbSession, parse_value
@ -41,6 +40,7 @@ from langflow.graph.schema import RunOutputs
from langflow.helpers.flow import get_flow_by_id_or_endpoint_name
from langflow.helpers.user import get_user_by_flow_id_or_endpoint_name
from langflow.interface.initialize.loading import update_params_with_load_from_db_fields
from langflow.logging.logger import logger
from langflow.processing.process import process_tweaks, run_graph_internal
from langflow.schema.graph import Tweaks
from langflow.services.auth.utils import api_key_security, get_current_active_user
@ -184,7 +184,7 @@ async def simple_run_flow_task(
)
except Exception: # noqa: BLE001
logger.exception(f"Error running flow {flow.id} task")
await logger.aexception(f"Error running flow {flow.id} task")
async def consume_and_yield(queue: asyncio.Queue, client_consumed_queue: asyncio.Queue) -> AsyncGenerator:
@ -215,7 +215,7 @@ async def consume_and_yield(queue: asyncio.Queue, client_consumed_queue: asyncio
yield value
get_time_yield = time.time()
client_consumed_queue.put_nowait(event_id)
logger.debug(
await logger.adebug(
f"consumed event {event_id} "
f"(time in queue, {get_time - put_time:.4f}, "
f"client {get_time_yield - get_time:.4f})"
@ -264,7 +264,7 @@ async def run_flow_generator(
event_manager.on_end(data={"result": result.model_dump()})
await client_consumed_queue.get()
except (ValueError, InvalidChatInputError, SerializationError) as e:
logger.error(f"Error running flow: {e}")
await logger.aerror(f"Error running flow: {e}")
event_manager.on_error(data={"error": str(e)})
finally:
await event_manager.queue.put((None, None, time.time))
@ -331,7 +331,7 @@ async def simplified_run_flow(
)
async def on_disconnect() -> None:
logger.debug("Client disconnected, closing tasks")
await logger.adebug("Client disconnected, closing tasks")
main_task.cancel()
return StreamingResponse(
@ -414,7 +414,7 @@ async def webhook_run_flow(
"""
telemetry_service = get_telemetry_service()
start_time = time.perf_counter()
logger.debug("Received webhook request")
await logger.adebug("Received webhook request")
error_msg = ""
try:
try:
@ -442,7 +442,7 @@ async def webhook_run_flow(
session_id=None,
)
logger.debug("Starting background task")
await logger.adebug("Starting background task")
background_tasks.add_task(
simple_run_flow_task,
flow=flow,
@ -553,7 +553,7 @@ async def experimental_run_flow(
except sa.exc.StatementError as exc:
# StatementError('(builtins.ValueError) badly formed hexadecimal UUID string')
if "badly formed hexadecimal UUID string" in str(exc):
logger.error(f"Flow ID {flow_id_str} is not a valid UUID")
await logger.aerror(f"Flow ID {flow_id_str} is not a valid UUID")
# This means the Flow ID is not a valid UUID which means it can't find the flow
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
@ -600,7 +600,7 @@ async def experimental_run_flow(
async def process(_flow_id) -> None:
"""Endpoint to process an input with a given flow_id."""
# Raise a depreciation warning
logger.warning(
await logger.awarning(
"The /process endpoint is deprecated and will be removed in a future version. Please use /run instead."
)
raise HTTPException(
@ -643,7 +643,7 @@ async def create_upload_file(
file_path=file_path,
)
except Exception as exc:
logger.exception("Error saving file")
await logger.aexception("Error saving file")
raise HTTPException(status_code=500, detail=str(exc)) from exc

View file

@ -55,7 +55,7 @@ async def _save_flow_to_fs(flow: Flow) -> None:
try:
await f.write(flow.model_dump_json())
except OSError:
logger.exception("Failed to write flow %s to path %s", flow.name, flow.fs_path)
await logger.aexception("Failed to write flow %s to path %s", flow.name, flow.fs_path)
async def _new_flow(

View file

@ -6,10 +6,10 @@ from pathlib import Path
import pandas as pd
from fastapi import APIRouter, HTTPException
from langchain_chroma import Chroma
from loguru import logger
from pydantic import BaseModel
from langflow.api.utils import CurrentActiveUser
from langflow.logging import logger
from langflow.services.deps import get_settings_service
router = APIRouter(tags=["Knowledge Bases"], prefix="/knowledge_bases")
@ -330,7 +330,7 @@ async def list_knowledge_bases(current_user: CurrentActiveUser) -> list[Knowledg
except OSError as _:
# Log the exception and skip directories that can't be read
logger.exception("Error reading knowledge base directory '%s'", kb_dir)
await logger.aexception("Error reading knowledge base directory '%s'", kb_dir)
continue
# Sort by name alphabetically
@ -422,7 +422,7 @@ async def delete_knowledge_bases_bulk(request: BulkDeleteRequest, current_user:
shutil.rmtree(kb_path)
deleted_count += 1
except (OSError, PermissionError) as e:
logger.exception("Error deleting knowledge base '%s': %s", kb_name, e)
await logger.aexception("Error deleting knowledge base '%s': %s", kb_name, e)
# Continue with other deletions even if one fails
if not_found_kbs and deleted_count == 0:

View file

@ -4,7 +4,6 @@ import pydantic
from anyio import BrokenResourceError
from fastapi import APIRouter, HTTPException, Request, Response
from fastapi.responses import HTMLResponse, StreamingResponse
from loguru import logger
from mcp import types
from mcp.server import NotificationOptions, Server
from mcp.server.sse import SseServerTransport
@ -18,6 +17,7 @@ from langflow.api.v1.mcp_utils import (
handle_mcp_errors,
handle_read_resource,
)
from langflow.logging.logger import logger
from langflow.services.deps import get_settings_service
router = APIRouter(prefix="/mcp", tags=["mcp"])
@ -83,22 +83,22 @@ async def im_alive():
@router.get("/sse", response_class=StreamingResponse)
async def handle_sse(request: Request, current_user: CurrentActiveMCPUser):
msg = f"Starting SSE connection, server name: {server.name}"
logger.info(msg)
await logger.ainfo(msg)
token = current_user_ctx.set(current_user)
try:
async with sse.connect_sse(request.scope, request.receive, request._send) as streams:
try:
msg = "Starting SSE connection"
logger.debug(msg)
await logger.adebug(msg)
msg = f"Stream types: read={type(streams[0])}, write={type(streams[1])}"
logger.debug(msg)
await logger.adebug(msg)
notification_options = NotificationOptions(
prompts_changed=True, resources_changed=True, tools_changed=True
)
init_options = server.create_initialization_options(notification_options)
msg = f"Initialization options: {init_options}"
logger.debug(msg)
await logger.adebug(msg)
try:
await server.run(streams[0], streams[1], init_options)
@ -106,20 +106,20 @@ async def handle_sse(request: Request, current_user: CurrentActiveMCPUser):
validation_error = find_validation_error(exc)
if validation_error:
msg = "Validation error in MCP:" + str(validation_error)
logger.debug(msg)
await logger.adebug(msg)
else:
msg = f"Error in MCP: {exc!s}"
logger.debug(msg)
await logger.adebug(msg)
return
except BrokenResourceError:
# Handle gracefully when client disconnects
logger.info("Client disconnected from SSE connection")
await logger.ainfo("Client disconnected from SSE connection")
except asyncio.CancelledError:
logger.info("SSE connection was cancelled")
await logger.ainfo("SSE connection was cancelled")
raise
except Exception as e:
msg = f"Error in MCP: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise
finally:
current_user_ctx.reset(token)
@ -130,8 +130,8 @@ async def handle_messages(request: Request):
try:
await sse.handle_post_message(request.scope, request.receive, request._send)
except (BrokenResourceError, BrokenPipeError) as e:
logger.info("MCP Server disconnected")
await logger.ainfo("MCP Server disconnected")
raise HTTPException(status_code=404, detail=f"MCP Server disconnected, error: {e}") from e
except Exception as e:
logger.error(f"Internal server error: {e}")
await logger.aerror(f"Internal server error: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {e}") from e

View file

@ -1,6 +1,5 @@
import asyncio
import json
import logging
import os
import platform
from asyncio.subprocess import create_subprocess_exec
@ -29,19 +28,13 @@ from langflow.api.v1.mcp_utils import (
handle_mcp_errors,
handle_read_resource,
)
from langflow.api.v1.schemas import (
MCPInstallRequest,
MCPProjectResponse,
MCPProjectUpdateRequest,
MCPSettings,
)
from langflow.api.v1.schemas import MCPInstallRequest, MCPProjectResponse, MCPProjectUpdateRequest, MCPSettings
from langflow.base.mcp.constants import MAX_MCP_SERVER_NAME_LENGTH
from langflow.base.mcp.util import sanitize_mcp_name
from langflow.logging import logger
from langflow.services.database.models import Flow, Folder
from langflow.services.deps import get_settings_service, session_scope
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/mcp/project", tags=["mcp_projects"])
# Create project-specific context variable
@ -116,7 +109,7 @@ async def list_project_tools(
tools.append(tool)
except Exception as e: # noqa: BLE001
msg = f"Error in listing project tools: {e!s} from flow: {name}"
logger.warning(msg)
await logger.awarning(msg)
continue
# Get project-level auth settings
@ -128,14 +121,14 @@ async def list_project_tools(
except Exception as e:
msg = f"Error listing project tools: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise HTTPException(status_code=500, detail=str(e)) from e
return MCPProjectResponse(tools=tools, auth_settings=auth_settings)
@router.head("/{project_id}/sse", response_class=HTMLResponse, include_in_schema=False)
async def im_alive():
async def im_alive(project_id: str): # noqa: ARG001
return Response()
@ -158,7 +151,7 @@ async def handle_project_sse(
# Get project-specific SSE transport and MCP server
sse = get_project_sse(project_id)
project_server = get_project_mcp_server(project_id)
logger.debug("Project MCP server name: %s", project_server.server.name)
await logger.adebug("Project MCP server name: %s", project_server.server.name)
# Set context variables
user_token = current_user_ctx.set(current_user)
@ -167,7 +160,7 @@ async def handle_project_sse(
try:
async with sse.connect_sse(request.scope, request.receive, request._send) as streams:
try:
logger.debug("Starting SSE connection for project %s", project_id)
await logger.adebug("Starting SSE connection for project %s", project_id)
notification_options = NotificationOptions(
prompts_changed=True, resources_changed=True, tools_changed=True
@ -176,15 +169,15 @@ async def handle_project_sse(
try:
await project_server.server.run(streams[0], streams[1], init_options)
except Exception:
logger.exception("Error in project MCP")
except Exception: # noqa: BLE001
await logger.aexception("Error in project MCP")
except BrokenResourceError:
logger.info("Client disconnected from project SSE connection")
await logger.ainfo("Client disconnected from project SSE connection")
except asyncio.CancelledError:
logger.info("Project SSE connection was cancelled")
await logger.ainfo("Project SSE connection was cancelled")
raise
except Exception:
logger.exception("Error in project MCP")
await logger.aexception("Error in project MCP")
raise
finally:
current_user_ctx.reset(user_token)
@ -213,7 +206,7 @@ async def handle_project_messages(project_id: UUID, request: Request, current_us
sse = get_project_sse(project_id)
await sse.handle_post_message(request.scope, request.receive, request._send)
except BrokenResourceError as e:
logger.info("Project MCP Server disconnected for project %s", project_id)
await logger.ainfo("Project MCP Server disconnected for project %s", project_id)
raise HTTPException(status_code=404, detail=f"Project MCP Server disconnected, error: {e}") from e
finally:
current_user_ctx.reset(user_token)
@ -279,7 +272,7 @@ async def update_project_mcp_settings(
except Exception as e:
msg = f"Error updating project MCP settings: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise HTTPException(status_code=500, detail=str(e)) from e
@ -372,7 +365,7 @@ async def install_mcp_config(
is_wsl = os_type == "Linux" and "microsoft" in platform.uname().release.lower()
if is_wsl:
logger.debug("WSL detected, using Windows-specific configuration")
await logger.adebug("WSL detected, using Windows-specific configuration")
# If we're in WSL and the host is localhost, we might need to adjust the URL
# so Windows applications can reach the WSL service
@ -391,18 +384,18 @@ async def install_mcp_config(
if proc.returncode == 0 and stdout.strip():
wsl_ip = stdout.decode().strip().split()[0] # Get first IP address
logger.debug("Using WSL IP for external access: %s", wsl_ip)
await logger.adebug("Using WSL IP for external access: %s", wsl_ip)
# Replace the localhost with the WSL IP in the URL
sse_url = sse_url.replace(f"http://{host}:{port}", f"http://{wsl_ip}:{port}")
except OSError as e:
logger.warning("Failed to get WSL IP address: %s. Using default URL.", str(e))
await logger.awarning("Failed to get WSL IP address: %s. Using default URL.", str(e))
else:
args = ["mcp-proxy", sse_url]
if os_type == "Windows":
command = "cmd"
args = ["/c", "uvx", *args]
logger.debug("Windows detected, using cmd command")
await logger.adebug("Windows detected, using cmd command")
name = project.name
@ -417,7 +410,7 @@ async def install_mcp_config(
}
server_name = f"lf-{sanitize_mcp_name(name)[: (MAX_MCP_SERVER_NAME_LENGTH - 4)]}"
logger.debug("Installing MCP config for project: %s (server name: %s)", project.name, server_name)
await logger.adebug("Installing MCP config for project: %s (server name: %s)", project.name, server_name)
# Determine the config file path based on the client and OS
if body.client.lower() == "cursor":
@ -469,7 +462,7 @@ async def install_mcp_config(
status_code=400, detail="Windows C: drive not mounted at /mnt/c in WSL"
)
except (OSError, CalledProcessError) as e:
logger.warning("Failed to determine Windows user path in WSL: %s", str(e))
await logger.awarning("Failed to determine Windows user path in WSL: %s", str(e))
raise HTTPException(
status_code=400, detail=f"Could not determine Windows Claude config path in WSL: {e!s}"
) from e
@ -505,11 +498,11 @@ async def install_mcp_config(
except Exception as e:
msg = f"Error installing MCP configuration: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise HTTPException(status_code=500, detail=str(e)) from e
else:
message = f"Successfully installed MCP configuration for {body.client}"
logger.info(message)
await logger.ainfo(message)
return {"message": message}
@ -533,7 +526,7 @@ async def check_installed_mcp_servers(
name = project.name
project_server_name = f"lf-{sanitize_mcp_name(name)[: (MAX_MCP_SERVER_NAME_LENGTH - 4)]}"
logger.debug(
await logger.adebug(
"Checking for installed MCP servers for project: %s (server name: %s)", project.name, project_server_name
)
@ -542,26 +535,28 @@ async def check_installed_mcp_servers(
# Check Cursor configuration
cursor_config_path = Path.home() / ".cursor" / "mcp.json"
logger.debug("Checking Cursor config at: %s (exists: %s)", cursor_config_path, cursor_config_path.exists())
await logger.adebug(
"Checking Cursor config at: %s (exists: %s)", cursor_config_path, cursor_config_path.exists()
)
if cursor_config_path.exists():
try:
with cursor_config_path.open("r") as f:
cursor_config = json.load(f)
if "mcpServers" in cursor_config and project_server_name in cursor_config["mcpServers"]:
logger.debug("Found Cursor config for project server: %s", project_server_name)
await logger.adebug("Found Cursor config for project server: %s", project_server_name)
results.append("cursor")
else:
logger.debug(
await logger.adebug(
"Cursor config exists but no entry for server: %s (available servers: %s)",
project_server_name,
list(cursor_config.get("mcpServers", {}).keys()),
)
except json.JSONDecodeError:
logger.warning("Failed to parse Cursor config JSON at: %s", cursor_config_path)
await logger.awarning("Failed to parse Cursor config JSON at: %s", cursor_config_path)
# Check Windsurf configuration
windsurf_config_path = Path.home() / ".codeium" / "windsurf" / "mcp_config.json"
logger.debug(
await logger.adebug(
"Checking Windsurf config at: %s (exists: %s)", windsurf_config_path, windsurf_config_path.exists()
)
if windsurf_config_path.exists():
@ -569,16 +564,16 @@ async def check_installed_mcp_servers(
with windsurf_config_path.open("r") as f:
windsurf_config = json.load(f)
if "mcpServers" in windsurf_config and project_server_name in windsurf_config["mcpServers"]:
logger.debug("Found Windsurf config for project server: %s", project_server_name)
await logger.adebug("Found Windsurf config for project server: %s", project_server_name)
results.append("windsurf")
else:
logger.debug(
await logger.adebug(
"Windsurf config exists but no entry for server: %s (available servers: %s)",
project_server_name,
list(windsurf_config.get("mcpServers", {}).keys()),
)
except json.JSONDecodeError:
logger.warning("Failed to parse Windsurf config JSON at: %s", windsurf_config_path)
await logger.awarning("Failed to parse Windsurf config JSON at: %s", windsurf_config_path)
# Check Claude configuration
claude_config_path = None
@ -623,7 +618,7 @@ async def check_installed_mcp_servers(
user_dirs[0] / "AppData" / "Roaming" / "Claude" / "claude_desktop_config.json"
)
except (OSError, CalledProcessError) as e:
logger.warning(
await logger.awarning(
"Failed to determine Windows user path in WSL for checking Claude config: %s", str(e)
)
# Don't set claude_config_path, so it will be skipped
@ -632,27 +627,27 @@ async def check_installed_mcp_servers(
claude_config_path = Path(os.environ["APPDATA"]) / "Claude" / "claude_desktop_config.json"
if claude_config_path and claude_config_path.exists():
logger.debug("Checking Claude config at: %s", claude_config_path)
await logger.adebug("Checking Claude config at: %s", claude_config_path)
try:
with claude_config_path.open("r") as f:
claude_config = json.load(f)
if "mcpServers" in claude_config and project_server_name in claude_config["mcpServers"]:
logger.debug("Found Claude config for project server: %s", project_server_name)
await logger.adebug("Found Claude config for project server: %s", project_server_name)
results.append("claude")
else:
logger.debug(
await logger.adebug(
"Claude config exists but no entry for server: %s (available servers: %s)",
project_server_name,
list(claude_config.get("mcpServers", {}).keys()),
)
except json.JSONDecodeError:
logger.warning("Failed to parse Claude config JSON at: %s", claude_config_path)
await logger.awarning("Failed to parse Claude config JSON at: %s", claude_config_path)
else:
logger.debug("Claude config path not found or doesn't exist: %s", claude_config_path)
await logger.adebug("Claude config path not found or doesn't exist: %s", claude_config_path)
except Exception as e:
msg = f"Error checking MCP configuration: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise HTTPException(status_code=500, detail=str(e)) from e
return results
@ -719,11 +714,11 @@ async def init_mcp_servers():
try:
get_project_sse(project.id)
get_project_mcp_server(project.id)
except Exception as e:
except Exception as e: # noqa: BLE001
msg = f"Failed to initialize MCP server for project {project.id}: {e}"
logger.exception(msg)
await logger.aexception(msg)
# Continue to next project even if this one fails
except Exception as e:
except Exception as e: # noqa: BLE001
msg = f"Failed to initialize MCP servers: {e}"
logger.exception(msg)
await logger.aexception(msg)

View file

@ -12,7 +12,6 @@ from typing import Any, ParamSpec, TypeVar
from urllib.parse import quote, unquote, urlparse
from uuid import uuid4
from loguru import logger
from mcp import types
from sqlmodel import select
@ -21,6 +20,7 @@ from langflow.api.v1.schemas import SimplifiedAPIRequest
from langflow.base.mcp.constants import MAX_MCP_TOOL_NAME_LENGTH
from langflow.base.mcp.util import get_flow_snake_case, get_unique_name, sanitize_mcp_name
from langflow.helpers.flow import json_schema_from_flow
from langflow.logging.logger import logger
from langflow.schema.message import Message
from langflow.services.database.models import Flow
from langflow.services.database.models.user.model import User
@ -43,7 +43,7 @@ def handle_mcp_errors(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[
return await func(*args, **kwargs)
except Exception as e:
msg = f"Error in {func.__name__}: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise
return wrapper
@ -108,11 +108,11 @@ async def handle_list_resources(project_id=None):
resources.append(resource)
except FileNotFoundError as e:
msg = f"Error listing files for flow {flow.id}: {e}"
logger.debug(msg)
await logger.adebug(msg)
continue
except Exception as e:
msg = f"Error in listing resources: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise
return resources
@ -150,7 +150,7 @@ async def handle_read_resource(uri: str) -> bytes:
return base64.b64encode(content)
except Exception as e:
msg = f"Error reading resource {uri}: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise
@ -271,7 +271,7 @@ async def handle_call_tool(
return await with_db_session(execute_tool)
except Exception as e:
msg = f"Error executing tool {name}: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise
@ -339,10 +339,10 @@ async def handle_list_tools(project_id=None, *, mcp_enabled_only=False):
existing_names.add(name)
except Exception as e: # noqa: BLE001
msg = f"Error in listing tools: {e!s} from flow: {base_name}"
logger.warning(msg)
await logger.awarning(msg)
continue
except Exception as e:
msg = f"Error in listing tools: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise
return tools

View file

@ -2,9 +2,9 @@ from typing import Annotated
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query
from loguru import logger
from langflow.api.utils import CurrentActiveUser, check_langflow_version
from langflow.logging.logger import logger
from langflow.services.auth import utils as auth_utils
from langflow.services.deps import get_settings_service, get_store_service
from langflow.services.store.exceptions import CustomError

View file

@ -1,9 +1,9 @@
from fastapi import APIRouter, HTTPException
from loguru import logger
from langflow.api.utils import CurrentActiveUser
from langflow.api.v1.base import Code, CodeValidationResponse, PromptValidationResponse, ValidatePromptRequest
from langflow.base.prompts.api_utils import process_prompt_template
from langflow.logging.logger import logger
from langflow.utils.validate import validate_code
# build router
@ -19,7 +19,7 @@ async def post_validate_code(code: Code, _current_user: CurrentActiveUser) -> Co
function=errors.get("function", {}),
)
except Exception as e:
logger.opt(exception=True).debug("Error validating code")
logger.debug("Error validating code", exc_info=True)
raise HTTPException(status_code=500, detail=str(e)) from e

View file

@ -33,11 +33,7 @@ from langflow.services.database.models.flow.model import Flow
from langflow.services.database.models.message.model import MessageTable
from langflow.services.database.models.user.model import User
from langflow.services.deps import get_variable_service, session_scope
from langflow.utils.voice_utils import (
BYTES_PER_24K_FRAME,
VAD_SAMPLE_RATE_16K,
resample_24k_to_16k,
)
from langflow.utils.voice_utils import BYTES_PER_24K_FRAME, VAD_SAMPLE_RATE_16K, resample_24k_to_16k
router = APIRouter(prefix="/voice", tags=["Voice"])
@ -121,8 +117,8 @@ async def authenticate_and_get_openai_key(session: DbSession, user: User, websoc
)
return None, None
except Exception as e: # noqa: BLE001
logger.error(f"Error with API key: {e}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error with API key: {e}")
await logger.aerror(traceback.format_exc())
return None, None
return user, openai_key
@ -185,13 +181,13 @@ class ElevenLabsClientManager:
session=session,
)
except (InvalidToken, ValueError) as e:
logger.error(f"Error with ElevenLabs API key: {e}")
await logger.aerror(f"Error with ElevenLabs API key: {e}")
cls._api_key = os.getenv("ELEVENLABS_API_KEY", "")
if not cls._api_key:
logger.error("ElevenLabs API key not found")
await logger.aerror("ElevenLabs API key not found")
return None
except (KeyError, AttributeError, sqlalchemy.exc.SQLAlchemyError) as e:
logger.error(f"Exception getting ElevenLabs API key: {e}")
await logger.aerror(f"Exception getting ElevenLabs API key: {e}")
return None
if cls._api_key:
@ -310,25 +306,25 @@ async def process_message_queue(queue_key, session):
try:
await aadd_messagetables([message], session)
logger.debug(f"Added message to DB: {message.text[:30]}...")
await logger.adebug(f"Added message to DB: {message.text[:30]}...")
except ValueError as e:
logger.error(f"Error saving message to database (ValueError): {e}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error saving message to database (ValueError): {e}")
await logger.aerror(traceback.format_exc())
except sqlalchemy.exc.SQLAlchemyError as e:
logger.error(f"Error saving message to database (SQLAlchemyError): {e}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error saving message to database (SQLAlchemyError): {e}")
await logger.aerror(traceback.format_exc())
except (KeyError, AttributeError, TypeError) as e:
# More specific exceptions instead of blind Exception
logger.error(f"Error saving message to database: {e}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error saving message to database: {e}")
await logger.aerror(traceback.format_exc())
finally:
message_queues[queue_key].task_done()
if message_queues[queue_key].empty():
break
except Exception as e: # noqa: BLE001
logger.debug(f"Message queue processor for {queue_key} was cancelled: {e}")
logger.error(traceback.format_exc())
await logger.adebug(f"Message queue processor for {queue_key} was cancelled: {e}")
await logger.aerror(traceback.format_exc())
class SendQueues:
@ -369,7 +365,7 @@ class SendQueues:
logger.trace("OPENAI BLOCKING")
# log_event(msg, DIRECTION_TO_OPENAI)
except Exception: # noqa: BLE001
logger.error(traceback.format_exc())
await logger.aerror(traceback.format_exc())
def client_send(self, payload):
try:
@ -387,7 +383,7 @@ class SendQueues:
self.log_event(msg, LF_TO_CLIENT)
await self.client_ws.send_text(json.dumps(msg))
except Exception: # noqa: BLE001
logger.error(traceback.format_exc())
await logger.aerror(traceback.format_exc())
async def close(self):
self.openai_send_q.put_nowait(None)
@ -462,7 +458,7 @@ async def handle_function_call(
create_response()
except json.JSONDecodeError as e:
trace = traceback.format_exc()
logger.error(f"JSON decode error: {e!s}\ntrace: {trace}")
await logger.aerror(f"JSON decode error: {e!s}\ntrace: {trace}")
function_output = {
"type": "conversation.item.create",
"item": {
@ -474,7 +470,7 @@ async def handle_function_call(
msg_handler.openai_send(function_output)
except ValueError as e:
trace = traceback.format_exc()
logger.error(f"Value error: {e!s}\ntrace: {trace}")
await logger.aerror(f"Value error: {e!s}\ntrace: {trace}")
function_output = {
"type": "conversation.item.create",
"item": {
@ -486,7 +482,7 @@ async def handle_function_call(
msg_handler.openai_send(function_output)
except (ConnectionError, websockets.exceptions.WebSocketException) as e:
trace = traceback.format_exc()
logger.error(f"Connection error: {e!s}\ntrace: {trace}")
await logger.aerror(f"Connection error: {e!s}\ntrace: {trace}")
function_output = {
"type": "conversation.item.create",
"item": {
@ -497,8 +493,8 @@ async def handle_function_call(
}
msg_handler.openai_send(function_output)
except (KeyError, AttributeError, TypeError) as e:
logger.error(f"Error executing flow: {e}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error executing flow: {e}")
await logger.aerror(traceback.format_exc())
function_output = {
"type": "conversation.item.create",
"item": {
@ -751,7 +747,7 @@ async def flow_as_tool_websocket(
except Exception as e: # noqa: BLE001
err_msg = {"error": f"Failed to load flow: {e!s}"}
await client_websocket.send_json(err_msg)
logger.error(f"Failed to load flow: {e}")
await logger.aerror(f"Failed to load flow: {e}")
return
url = "wss://api.openai.com/v1/realtime?model=gpt-4o-mini-realtime-preview"
@ -800,7 +796,7 @@ async def flow_as_tool_websocket(
msg_handler.openai_send({"type": "response.cancel"})
bot_speaking_flag[0] = False
except Exception as e: # noqa: BLE001
logger.error(f"[ERROR] VAD processing failed (ValueError): {e}")
await logger.aerror(f"[ERROR] VAD processing failed (ValueError): {e}")
continue
if has_speech:
last_speech_time = datetime.now(tz=timezone.utc)
@ -856,7 +852,7 @@ async def flow_as_tool_websocket(
return new_session
class Response:
def __init__(self, response_id: str, use_elevenlabs: bool | None = None):
def __init__(self, response_id: str, *, use_elevenlabs: bool | None = None):
if use_elevenlabs is None:
use_elevenlabs = False
self.response_id = response_id
@ -925,7 +921,7 @@ async def flow_as_tool_websocket(
# client_send_event_from_thread(event, main_loop)
msg_handler.client_send(event)
except Exception: # noqa: BLE001
logger.error(traceback.format_exc())
await logger.aerror(traceback.format_exc())
async def forward_to_openai() -> None:
nonlocal openai_realtime_session
@ -954,10 +950,10 @@ async def flow_as_tool_websocket(
msg_handler.openai_send(msg)
num_audio_samples = 0
elif msg.get("type") == "langflow.voice_mode.config":
logger.info(f"langflow.voice_mode.config {msg}")
await logger.ainfo(f"langflow.voice_mode.config {msg}")
voice_config.progress_enabled = msg.get("progress_enabled", True)
elif msg.get("type") == "langflow.elevenlabs.config":
logger.info(f"langflow.elevenlabs.config {msg}")
await logger.ainfo(f"langflow.elevenlabs.config {msg}")
voice_config.use_elevenlabs = msg["enabled"]
voice_config.elevenlabs_voice = msg.get("voice_id", voice_config.elevenlabs_voice)
@ -997,7 +993,7 @@ async def flow_as_tool_websocket(
if do_forward:
msg_handler.client_send(event)
if event_type == "response.created":
responses[response_id] = Response(response_id, voice_config.use_elevenlabs)
responses[response_id] = Response(response_id, use_elevenlabs=voice_config.use_elevenlabs)
if function_call:
if function_call.is_prog_enabled and not function_call.prog_rsp_id:
function_call.prog_rsp_id = response_id
@ -1021,12 +1017,12 @@ async def flow_as_tool_websocket(
message_text = event.get("text", "")
await add_message_to_db(message_text, session, flow_id, session_id, "Machine", "AI")
except ValueError as err:
logger.error(f"Error saving message to database (ValueError): {err}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error saving message to database (ValueError): {err}")
await logger.aerror(traceback.format_exc())
except (KeyError, AttributeError, TypeError) as err:
# Replace blind Exception with specific exceptions
logger.error(f"Error saving message to database: {err}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error saving message to database: {err}")
await logger.aerror(traceback.format_exc())
elif event_type == "response.output_item.added":
bot_speaking_flag[0] = True
@ -1050,12 +1046,12 @@ async def flow_as_tool_websocket(
if transcript and transcript.strip():
await add_message_to_db(transcript, session, flow_id, session_id, "Machine", "AI")
except ValueError as err:
logger.error(f"Error saving message to database (ValueError): {err}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error saving message to database (ValueError): {err}")
await logger.aerror(traceback.format_exc())
except (KeyError, AttributeError, TypeError) as err:
# Replace blind Exception with specific exceptions
logger.error(f"Error saving message to database: {err}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error saving message to database: {err}")
await logger.aerror(traceback.format_exc())
bot_speaking_flag[0] = False
elif event_type == "response.done":
msg_handler.openai_unblock()
@ -1080,12 +1076,12 @@ async def flow_as_tool_websocket(
if message_text and message_text.strip():
await add_message_to_db(message_text, session, flow_id, session_id, "User", "User")
except ValueError as e:
logger.error(f"Error saving message to database (ValueError): {e}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error saving message to database (ValueError): {e}")
await logger.aerror(traceback.format_exc())
except (KeyError, AttributeError, TypeError) as e:
# Replace blind Exception with specific exceptions
logger.error(f"Error saving message to database: {e}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error saving message to database: {e}")
await logger.aerror(traceback.format_exc())
elif event_type == "error":
pass
@ -1104,12 +1100,12 @@ async def flow_as_tool_websocket(
# Check for exceptions in results
for result in results:
if isinstance(result, Exception):
logger.error("WS loop failed:", exc_info=result)
logger.error(traceback.format_exc())
await logger.aerror("WS loop failed:", exc_info=result)
await logger.aerror(traceback.format_exc())
except Exception as e: # noqa: BLE001
# Handle any other exceptions
logger.error(f"WS loop failed: {e}")
logger.error(traceback.format_exc())
await logger.aerror(f"WS loop failed: {e}")
await logger.aerror(traceback.format_exc())
finally:
# shared cleanup for writers & sockets
async def close():
@ -1119,8 +1115,8 @@ async def flow_as_tool_websocket(
await close()
except Exception as e: # noqa: BLE001
logger.error(f"Unexpected error: {e}")
logger.error(traceback.format_exc())
await logger.aerror(f"Unexpected error: {e}")
await logger.aerror(traceback.format_exc())
finally:
# Make sure to clean up the task
if vad_task and not vad_task.done():
@ -1232,16 +1228,16 @@ async def flow_tts_websocket(
elif event.get("type") == "input_audio_buffer.commit":
openai_send(event)
elif event.get("type") == "langflow.elevenlabs.config":
logger.info(f"langflow.elevenlabs.config {event}")
await logger.ainfo(f"langflow.elevenlabs.config {event}")
tts_config.use_elevenlabs = event["enabled"]
tts_config.elevenlabs_voice = event.get("voice_id", tts_config.elevenlabs_voice)
elif event.get("type") == "voice.settings":
# Store the voice setting
if event.get("voice"):
tts_config.openai_voice = event.get("voice")
logger.info(f"Updated OpenAI voice to: {tts_config.openai_voice}")
await logger.ainfo(f"Updated OpenAI voice to: {tts_config.openai_voice}")
except Exception as e: # noqa: BLE001
logger.error(f"Error in WebSocket communication: {e}")
await logger.aerror(f"Error in WebSocket communication: {e}")
async def forward_to_client() -> None:
try:
@ -1312,7 +1308,7 @@ async def flow_tts_websocket(
audio_event = {"type": "response.audio.delta", "delta": base64_audio}
client_send(audio_event)
except Exception as e: # noqa: BLE001
logger.error(f"Error in WebSocket communication: {e}")
await logger.aerror(f"Error in WebSocket communication: {e}")
try:
# Create tasks and gather them for concurrent execution
@ -1321,13 +1317,13 @@ async def flow_tts_websocket(
await asyncio.gather(task1, task2)
except Exception as exc: # noqa: BLE001
# handle any exceptions from any task
logger.error("WS loop failed:", exc_info=exc)
await logger.aerror("WS loop failed:", exc_info=exc)
finally:
# shared cleanup for writers & sockets
await close()
except Exception as e: # noqa: BLE001
logger.error(f"Unexpected error: {e}")
logger.error(traceback.format_exc())
await logger.aerror(f"Unexpected error: {e}")
await logger.aerror(traceback.format_exc())
def extract_transcript(json_data):
@ -1367,13 +1363,13 @@ async def get_elevenlabs_voice_ids(
for voice in voices
]
except ValueError as e:
logger.error(f"Error fetching ElevenLabs voices (ValueError): {e}")
await logger.aerror(f"Error fetching ElevenLabs voices (ValueError): {e}")
return {"error": str(e)}
except requests.RequestException as e:
logger.error(f"Error fetching ElevenLabs voices (RequestException): {e}")
await logger.aerror(f"Error fetching ElevenLabs voices (RequestException): {e}")
return {"error": str(e)}
except (KeyError, AttributeError, TypeError) as e:
# More specific exceptions instead of blind Exception
logger.error(f"Error fetching ElevenLabs voices: {e}")
logger.error(traceback.format_exc())
await logger.aerror(f"Error fetching ElevenLabs voices: {e}")
await logger.aerror(traceback.format_exc())
return {"error": str(e)}

View file

@ -11,11 +11,11 @@ from zoneinfo import ZoneInfo
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
from fastapi.responses import StreamingResponse
from loguru import logger
from sqlmodel import col, select
from langflow.api.schemas import UploadFileResponse
from langflow.api.utils import CurrentActiveUser, DbSession
from langflow.logging.logger import logger
from langflow.services.database.models.file.model import File as UserFile
from langflow.services.deps import get_settings_service, get_storage_service
from langflow.services.storage.service import StorageService
@ -488,7 +488,7 @@ async def delete_file(
raise
except Exception as e:
# Log and return a generic server error
logger.error("Error deleting file %s: %s", file_id, e)
await logger.aerror("Error deleting file %s: %s", file_id, e)
raise HTTPException(status_code=500, detail=f"Error deleting file: {e}") from e
return {"detail": f"File {file_to_delete.name} deleted successfully"}

View file

@ -115,6 +115,7 @@ async def get_servers(
session: DbSession,
storage_service=Depends(get_storage_service),
settings_service=Depends(get_settings_service),
*,
action_count: bool | None = None,
):
"""Get the list of available servers."""
@ -140,27 +141,27 @@ async def get_servers(
server_info["error"] = "No tools found"
except ValueError as e:
# Configuration validation errors, invalid URLs, etc.
logger.error(f"Configuration error for server {server_name}: {e}")
await logger.aerror(f"Configuration error for server {server_name}: {e}")
server_info["error"] = f"Configuration error: {e}"
except ConnectionError as e:
# Network connection and timeout issues
logger.error(f"Connection error for server {server_name}: {e}")
await logger.aerror(f"Connection error for server {server_name}: {e}")
server_info["error"] = f"Connection failed: {e}"
except (TimeoutError, asyncio.TimeoutError) as e:
# Timeout errors
logger.error(f"Timeout error for server {server_name}: {e}")
await logger.aerror(f"Timeout error for server {server_name}: {e}")
server_info["error"] = "Timeout when checking server tools"
except OSError as e:
# System-level errors (process execution, file access)
logger.error(f"System error for server {server_name}: {e}")
await logger.aerror(f"System error for server {server_name}: {e}")
server_info["error"] = f"System error: {e}"
except (KeyError, TypeError) as e:
# Data parsing and access errors
logger.error(f"Data error for server {server_name}: {e}")
await logger.aerror(f"Data error for server {server_name}: {e}")
server_info["error"] = f"Configuration data error: {e}"
except (RuntimeError, ProcessLookupError, PermissionError) as e:
# Runtime and process-related errors
logger.error(f"Runtime error for server {server_name}: {e}")
await logger.aerror(f"Runtime error for server {server_name}: {e}")
server_info["error"] = f"Runtime error: {e}"
except Exception as e: # noqa: BLE001
# Generic catch-all for other exceptions (including ExceptionGroup)
@ -168,15 +169,15 @@ async def get_servers(
# Extract the first underlying exception for a more meaningful error message
underlying_error = e.exceptions[0]
if hasattr(underlying_error, "exceptions"):
logger.error(
await logger.aerror(
f"Error checking server {server_name}: {underlying_error}, {underlying_error.exceptions}"
)
underlying_error = underlying_error.exceptions[0]
else:
logger.exception(f"Error checking server {server_name}: {underlying_error}")
await logger.aexception(f"Error checking server {server_name}: {underlying_error}")
server_info["error"] = f"Error loading server: {underlying_error}"
else:
logger.exception(f"Error checking server {server_name}: {e}")
await logger.aexception(f"Error checking server {server_name}: {e}")
server_info["error"] = f"Error loading server: {e}"
return server_info

View file

@ -2,10 +2,10 @@ import concurrent.futures
import json
import httpx
from loguru import logger
from pydantic import BaseModel, SecretStr
from langflow.field_typing import Embeddings
from langflow.logging.logger import logger
class AIMLEmbeddingsImpl(BaseModel, Embeddings):

View file

@ -1,6 +1,5 @@
from loguru import logger
from langflow.graph.schema import ResultData, RunOutputs
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.message import Message

View file

@ -1 +0,0 @@
# noqa: A005

View file

@ -2,7 +2,8 @@ from functools import lru_cache
from typing import Any
import httpx
from loguru import logger
from langflow.logging.logger import logger
@lru_cache(maxsize=1)

View file

@ -15,12 +15,12 @@ import httpx
from anyio import ClosedResourceError
from httpx import codes as httpx_codes
from langchain_core.tools import StructuredTool
from loguru import logger
from mcp import ClientSession
from mcp.shared.exceptions import McpError
from pydantic import BaseModel, Field, create_model
from sqlmodel import select
from langflow.logging.logger import logger
from langflow.services.database.models.flow.model import Flow
from langflow.services.deps import get_settings_service
@ -214,7 +214,7 @@ def create_tool_coroutine(tool_name: str, arg_schema: type[BaseModel], client) -
try:
return await client.run_tool(tool_name, arguments=validated.model_dump())
except Exception as e:
logger.error(f"Tool '{tool_name}' execution failed: {e}")
await logger.aerror(f"Tool '{tool_name}' execution failed: {e}")
# Re-raise with more context
msg = f"Tool '{tool_name}' execution failed: {e}"
raise ValueError(msg) from e
@ -264,7 +264,7 @@ def get_unique_name(base_name, max_length, existing_names):
i += 1
async def get_flow_snake_case(flow_name: str, user_id: str, session, is_action: bool | None = None) -> Flow | None:
async def get_flow_snake_case(flow_name: str, user_id: str, session, *, is_action: bool | None = None) -> Flow | None:
uuid_user_id = UUID(user_id) if isinstance(user_id, str) else user_id
stmt = select(Flow).where(Flow.user_id == uuid_user_id).where(Flow.is_component == False) # noqa: E712
flows = (await session.exec(stmt)).all()
@ -506,7 +506,7 @@ class MCPSessionManager:
break
except (RuntimeError, KeyError, ClosedResourceError, ValueError, asyncio.TimeoutError) as e:
# Handle common recoverable errors without stopping the cleanup loop
logger.warning(f"Error in periodic cleanup: {e}")
await logger.awarning(f"Error in periodic cleanup: {e}")
async def _cleanup_idle_sessions(self):
"""Clean up sessions that have been idle for too long."""
@ -523,7 +523,7 @@ class MCPSessionManager:
# Clean up idle sessions
for session_id in sessions_to_remove:
logger.info(f"Cleaning up idle session {session_id} for server {server_key}")
await logger.ainfo(f"Cleaning up idle session {session_id} for server {server_key}")
await self._cleanup_session_by_id(server_key, session_id)
# Remove server entry if no sessions left
@ -561,7 +561,7 @@ class MCPSessionManager:
# Use a shorter timeout for the connectivity test to fail fast
response = await asyncio.wait_for(session.list_tools(), timeout=3.0)
except (asyncio.TimeoutError, ConnectionError, OSError, ValueError) as e:
logger.debug(f"Session connectivity test failed (standard error): {e}")
await logger.adebug(f"Session connectivity test failed (standard error): {e}")
return False
except Exception as e:
# Handle MCP-specific errors that might not be in the standard list
@ -574,27 +574,27 @@ class MCPSessionManager:
or "Transport closed" in error_str
or "Stream closed" in error_str
):
logger.debug(f"Session connectivity test failed (MCP connection error): {e}")
await logger.adebug(f"Session connectivity test failed (MCP connection error): {e}")
return False
# Re-raise unexpected errors
logger.warning(f"Unexpected error in connectivity test: {e}")
await logger.awarning(f"Unexpected error in connectivity test: {e}")
raise
else:
# Validate that we got a meaningful response
if response is None:
logger.debug("Session connectivity test failed: received None response")
await logger.adebug("Session connectivity test failed: received None response")
return False
try:
# Check if we can access the tools list (even if empty)
tools = getattr(response, "tools", None)
if tools is None:
logger.debug("Session connectivity test failed: no tools attribute in response")
await logger.adebug("Session connectivity test failed: no tools attribute in response")
return False
except (AttributeError, TypeError) as e:
logger.debug(f"Session connectivity test failed while validating response: {e}")
await logger.adebug(f"Session connectivity test failed while validating response: {e}")
return False
else:
logger.debug(f"Session connectivity test passed: found {len(tools)} tools")
await logger.adebug(f"Session connectivity test passed: found {len(tools)} tools")
return True
async def get_session(self, context_id: str, connection_params, transport_type: str):
@ -625,32 +625,32 @@ class MCPSessionManager:
# Quick health check
if await self._validate_session_connectivity(session):
logger.debug(f"Reusing existing session {session_id} for server {server_key}")
await logger.adebug(f"Reusing existing session {session_id} for server {server_key}")
# record mapping & bump ref-count for backwards compatibility
self._context_to_session[context_id] = (server_key, session_id)
self._session_refcount[(server_key, session_id)] = (
self._session_refcount.get((server_key, session_id), 0) + 1
)
return session
logger.info(f"Session {session_id} for server {server_key} failed health check, cleaning up")
await logger.ainfo(f"Session {session_id} for server {server_key} failed health check, cleaning up")
await self._cleanup_session_by_id(server_key, session_id)
else:
# Task is done, clean up
logger.info(f"Session {session_id} for server {server_key} task is done, cleaning up")
await logger.ainfo(f"Session {session_id} for server {server_key} task is done, cleaning up")
await self._cleanup_session_by_id(server_key, session_id)
# Check if we've reached the maximum number of sessions for this server
if len(sessions) >= MAX_SESSIONS_PER_SERVER:
# Remove the oldest session
oldest_session_id = min(sessions.keys(), key=lambda x: sessions[x]["last_used"])
logger.info(
await logger.ainfo(
f"Maximum sessions reached for server {server_key}, removing oldest session {oldest_session_id}"
)
await self._cleanup_session_by_id(server_key, oldest_session_id)
# Create new session
session_id = f"{server_key}_{len(sessions)}"
logger.info(f"Creating new session {session_id} for server {server_key}")
await logger.ainfo(f"Creating new session {session_id} for server {server_key}")
if transport_type == "stdio":
session, task = await self._create_stdio_session(session_id, connection_params)
@ -700,7 +700,7 @@ class MCPSessionManager:
try:
await event.wait()
except asyncio.CancelledError:
logger.info(f"Session {session_id} is shutting down")
await logger.ainfo(f"Session {session_id} is shutting down")
except Exception as e: # noqa: BLE001
if not session_future.done():
session_future.set_exception(e)
@ -723,7 +723,7 @@ class MCPSessionManager:
await task
self._background_tasks.discard(task)
msg = f"Timeout waiting for STDIO session {session_id} to initialize"
logger.error(msg)
await logger.aerror(msg)
raise ValueError(msg) from timeout_err
return session, task
@ -759,7 +759,7 @@ class MCPSessionManager:
try:
await event.wait()
except asyncio.CancelledError:
logger.info(f"Session {session_id} is shutting down")
await logger.ainfo(f"Session {session_id} is shutting down")
except Exception as e: # noqa: BLE001
if not session_future.done():
session_future.set_exception(e)
@ -782,7 +782,7 @@ class MCPSessionManager:
await task
self._background_tasks.discard(task)
msg = f"Timeout waiting for SSE session {session_id} to initialize"
logger.error(msg)
await logger.aerror(msg)
raise ValueError(msg) from timeout_err
return session, task
@ -813,9 +813,9 @@ class MCPSessionManager:
if hasattr(session, "aclose"):
try:
await session.aclose()
logger.debug("Successfully closed session %s using aclose()", session_id)
await logger.adebug("Successfully closed session %s using aclose()", session_id)
except Exception as e: # noqa: BLE001
logger.debug("Error closing session %s with aclose(): %s", session_id, e)
await logger.adebug("Error closing session %s with aclose(): %s", session_id, e)
# If no aclose, try regular close method
elif hasattr(session, "close"):
@ -824,18 +824,20 @@ class MCPSessionManager:
if inspect.iscoroutinefunction(session.close):
# It's an async method
await session.close()
logger.debug("Successfully closed session %s using async close()", session_id)
await logger.adebug("Successfully closed session %s using async close()", session_id)
else:
# Try calling it and check if result is awaitable
close_result = session.close()
if inspect.isawaitable(close_result):
await close_result
logger.debug("Successfully closed session %s using awaitable close()", session_id)
await logger.adebug(
"Successfully closed session %s using awaitable close()", session_id
)
else:
# It's a synchronous close
logger.debug("Successfully closed session %s using sync close()", session_id)
await logger.adebug("Successfully closed session %s using sync close()", session_id)
except Exception as e: # noqa: BLE001
logger.debug("Error closing session %s with close(): %s", session_id, e)
await logger.adebug("Error closing session %s with close(): %s", session_id, e)
# Cancel the background task which will properly close the session
if "task" in session_info:
@ -845,9 +847,9 @@ class MCPSessionManager:
try:
await task
except asyncio.CancelledError:
logger.info(f"Cancelled task for session {session_id}")
await logger.ainfo(f"Cancelled task for session {session_id}")
except Exception as e: # noqa: BLE001
logger.warning(f"Error cleaning up session {session_id}: {e}")
await logger.awarning(f"Error cleaning up session {session_id}: {e}")
finally:
# Remove from sessions dict
del sessions[session_id]
@ -900,7 +902,7 @@ class MCPSessionManager:
"""
mapping = self._context_to_session.get(context_id)
if not mapping:
logger.debug(f"No session mapping found for context_id {context_id}")
await logger.adebug(f"No session mapping found for context_id {context_id}")
return
server_key, session_id = mapping
@ -1031,7 +1033,7 @@ class MCPStdioClient:
for attempt in range(max_retries):
try:
logger.debug(f"Attempting to run tool '{tool_name}' (attempt {attempt + 1}/{max_retries})")
await logger.adebug(f"Attempting to run tool '{tool_name}' (attempt {attempt + 1}/{max_retries})")
# Get or create persistent session
session = await self._get_or_create_session()
@ -1041,7 +1043,7 @@ class MCPStdioClient:
)
except Exception as e:
current_error_type = type(e).__name__
logger.warning(f"Tool '{tool_name}' failed on attempt {attempt + 1}: {current_error_type} - {e}")
await logger.awarning(f"Tool '{tool_name}' failed on attempt {attempt + 1}: {current_error_type} - {e}")
# Import specific MCP error types for detection
try:
@ -1056,14 +1058,14 @@ class MCPStdioClient:
# If we're getting the same error type repeatedly, don't retry
if last_error_type == current_error_type and attempt > 0:
logger.error(f"Repeated {current_error_type} error for tool '{tool_name}', not retrying")
await logger.aerror(f"Repeated {current_error_type} error for tool '{tool_name}', not retrying")
break
last_error_type = current_error_type
# If it's a connection error (ClosedResourceError or MCP connection closed) and we have retries left
if (is_closed_resource_error or is_mcp_connection_error) and attempt < max_retries - 1:
logger.warning(
await logger.awarning(
f"MCP session connection issue for tool '{tool_name}', retrying with fresh session..."
)
# Clean up the dead session
@ -1076,7 +1078,7 @@ class MCPStdioClient:
# If it's a timeout error and we have retries left, try once more
if is_timeout_error and attempt < max_retries - 1:
logger.warning(f"Tool '{tool_name}' timed out, retrying...")
await logger.awarning(f"Tool '{tool_name}' timed out, retrying...")
# Don't clean up session for timeouts, might just be a slow response
await asyncio.sleep(1.0)
continue
@ -1089,7 +1091,7 @@ class MCPStdioClient:
or is_timeout_error
):
msg = f"Failed to run tool '{tool_name}' after {attempt + 1} attempts: {e}"
logger.error(msg)
await logger.aerror(msg)
# Clean up failed session from cache
if self._session_context and self._component_cache:
cache_key = f"mcp_session_stdio_{self._session_context}"
@ -1099,12 +1101,12 @@ class MCPStdioClient:
# Re-raise unexpected errors
raise
else:
logger.debug(f"Tool '{tool_name}' completed successfully")
await logger.adebug(f"Tool '{tool_name}' completed successfully")
return result
# This should never be reached due to the exception handling above
msg = f"Failed to run tool '{tool_name}': Maximum retries exceeded with repeated {last_error_type} errors"
logger.error(msg)
await logger.aerror(msg)
raise ValueError(msg)
async def disconnect(self):
@ -1213,7 +1215,7 @@ class MCPSseClient:
return response.headers.get("Location", url)
# Don't treat 404 as an error here - let the main connection handle it
except (httpx.RequestError, httpx.HTTPError) as e:
logger.warning(f"Error checking redirects: {e}")
await logger.awarning(f"Error checking redirects: {e}")
return url
async def _connect_to_server(
@ -1336,7 +1338,7 @@ class MCPSseClient:
for attempt in range(max_retries):
try:
logger.debug(f"Attempting to run tool '{tool_name}' (attempt {attempt + 1}/{max_retries})")
await logger.adebug(f"Attempting to run tool '{tool_name}' (attempt {attempt + 1}/{max_retries})")
# Get or create persistent session
session = await self._get_or_create_session()
@ -1349,7 +1351,7 @@ class MCPSseClient:
)
except Exception as e:
current_error_type = type(e).__name__
logger.warning(f"Tool '{tool_name}' failed on attempt {attempt + 1}: {current_error_type} - {e}")
await logger.awarning(f"Tool '{tool_name}' failed on attempt {attempt + 1}: {current_error_type} - {e}")
# Import specific MCP error types for detection
try:
@ -1367,14 +1369,14 @@ class MCPSseClient:
# If we're getting the same error type repeatedly, don't retry
if last_error_type == current_error_type and attempt > 0:
logger.error(f"Repeated {current_error_type} error for tool '{tool_name}', not retrying")
await logger.aerror(f"Repeated {current_error_type} error for tool '{tool_name}', not retrying")
break
last_error_type = current_error_type
# If it's a connection error (ClosedResourceError or MCP connection closed) and we have retries left
if (is_closed_resource_error or is_mcp_connection_error) and attempt < max_retries - 1:
logger.warning(
await logger.awarning(
f"MCP session connection issue for tool '{tool_name}', retrying with fresh session..."
)
# Clean up the dead session
@ -1387,7 +1389,7 @@ class MCPSseClient:
# If it's a timeout error and we have retries left, try once more
if is_timeout_error and attempt < max_retries - 1:
logger.warning(f"Tool '{tool_name}' timed out, retrying...")
await logger.awarning(f"Tool '{tool_name}' timed out, retrying...")
# Don't clean up session for timeouts, might just be a slow response
await asyncio.sleep(1.0)
continue
@ -1400,7 +1402,7 @@ class MCPSseClient:
or is_timeout_error
):
msg = f"Failed to run tool '{tool_name}' after {attempt + 1} attempts: {e}"
logger.error(msg)
await logger.aerror(msg)
# Clean up failed session from cache
if self._session_context and self._component_cache:
cache_key = f"mcp_session_sse_{self._session_context}"
@ -1410,12 +1412,12 @@ class MCPSseClient:
# Re-raise unexpected errors
raise
else:
logger.debug(f"Tool '{tool_name}' completed successfully")
await logger.adebug(f"Tool '{tool_name}' completed successfully")
return result
# This should never be reached due to the exception handling above
msg = f"Failed to run tool '{tool_name}': Maximum retries exceeded with repeated {last_error_type} errors"
logger.error(msg)
await logger.aerror(msg)
raise ValueError(msg)
async def disconnect(self):

View file

@ -3,10 +3,10 @@ from typing import Any
from fastapi import HTTPException
from langchain_core.prompts import PromptTemplate
from loguru import logger
from langflow.inputs.inputs import DefaultPromptField
from langflow.interface.utils import extract_input_variables_from_prompt
from langflow.logging.logger import logger
_INVALID_CHARACTERS = {
" ",

View file

@ -3,13 +3,13 @@ from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langchain_core.tools import BaseTool, ToolException
from loguru import logger
from typing_extensions import override
from langflow.base.flow_processing.utils import build_data_from_result_data, format_flow_output_data
from langflow.graph.graph.base import Graph # cannot be a part of TYPE_CHECKING # noqa: TC001
from langflow.graph.vertex.base import Vertex # cannot be a part of TYPE_CHECKING # noqa: TC001
from langflow.helpers.flow import build_schema_from_inputs, get_arg_names, get_flow_inputs, run_flow
from langflow.logging.logger import logger
from langflow.utils.async_helpers import run_until_complete
if TYPE_CHECKING:
@ -109,7 +109,7 @@ class FlowTool(BaseTool):
try:
run_id = self.graph.run_id if hasattr(self, "graph") and self.graph else None
except Exception: # noqa: BLE001
logger.opt(exception=True).warning("Failed to set run_id")
logger.warning("Failed to set run_id", exc_info=True)
run_id = None
run_outputs = await run_flow(
tweaks={key: {"input_value": value} for key, value in tweaks.items()},

View file

@ -1,7 +1,6 @@
from abc import abstractmethod
from typing import TYPE_CHECKING
from loguru import logger
from typing_extensions import override
from langflow.custom.custom_component.component import Component, _get_component_toolkit
@ -9,11 +8,8 @@ from langflow.field_typing import Tool
from langflow.graph.graph.base import Graph
from langflow.graph.vertex.base import Vertex
from langflow.helpers.flow import get_flow_inputs
from langflow.inputs.inputs import (
DropdownInput,
InputTypes,
MessageInput,
)
from langflow.inputs.inputs import DropdownInput, InputTypes, MessageInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.dataframe import DataFrame
from langflow.schema.dotdict import dotdict

View file

@ -4,13 +4,13 @@ from typing import Any
import requests
from bs4 import BeautifulSoup
from langchain.tools import StructuredTool
from loguru import logger
from markdown import markdown
from pydantic import BaseModel, Field
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.inputs.inputs import MultilineInput, SecretStrInput, StrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
MIN_ROWS_IN_TABLE = 3
@ -84,7 +84,7 @@ class AddContentToPage(LCToolComponent):
error_message += f" Status code: {e.response.status_code}, Response: {e.response.text}"
return error_message
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error adding content to Notion page")
logger.debug("Error adding content to Notion page", exc_info=True)
return f"Error: An unexpected error occurred while adding content to Notion page. {e}"
def process_node(self, node):

View file

@ -1,11 +1,11 @@
import requests
from langchain.tools import StructuredTool
from loguru import logger
from pydantic import BaseModel, Field
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.inputs.inputs import SecretStrInput, StrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -64,5 +64,5 @@ class NotionDatabaseProperties(LCToolComponent):
except ValueError as e:
return f"Error parsing Notion API response: {e}"
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error fetching Notion database properties")
logger.debug("Error fetching Notion database properties", exc_info=True)
return f"An unexpected error occurred: {e}"

View file

@ -3,12 +3,12 @@ from typing import Any
import requests
from langchain.tools import StructuredTool
from loguru import logger
from pydantic import BaseModel, Field
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.inputs.inputs import MultilineInput, SecretStrInput, StrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -118,5 +118,5 @@ class NotionListPages(LCToolComponent):
except KeyError:
return "Unexpected response format from Notion API"
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error querying Notion database")
logger.debug("Error querying Notion database", exc_info=True)
return f"An unexpected error occurred: {e}"

View file

@ -1,11 +1,11 @@
import requests
from langchain.tools import StructuredTool
from loguru import logger
from pydantic import BaseModel, Field
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.inputs.inputs import SecretStrInput, StrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -65,7 +65,7 @@ class NotionPageContent(LCToolComponent):
error_message += f" Status code: {e.response.status_code}, Response: {e.response.text}"
return error_message
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error retrieving Notion page content")
logger.debug("Error retrieving Notion page content", exc_info=True)
return f"Error: An unexpected error occurred while retrieving Notion page content. {e}"
def parse_blocks(self, blocks: list) -> str:

View file

@ -3,12 +3,12 @@ from typing import Any
import requests
from langchain.tools import StructuredTool
from loguru import logger
from pydantic import BaseModel, Field
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.inputs.inputs import MultilineInput, SecretStrInput, StrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data

View file

@ -1,17 +1,9 @@
import httpx
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.field_typing.range_spec import RangeSpec
from langflow.io import (
BoolInput,
DropdownInput,
IntInput,
MessageTextInput,
MultilineInput,
Output,
SecretStrInput,
)
from langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, MultilineInput, Output, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data

View file

@ -135,13 +135,13 @@ class AgentComponent(ToolCallingAgentComponent):
# return result
except (ValueError, TypeError, KeyError) as e:
logger.error(f"{type(e).__name__}: {e!s}")
await logger.aerror(f"{type(e).__name__}: {e!s}")
raise
except ExceptionWithMessageError as e:
logger.error(f"ExceptionWithMessageError occurred: {e}")
await logger.aerror(f"ExceptionWithMessageError occurred: {e}")
raise
except Exception as e:
logger.error(f"Unexpected error: {e!s}")
await logger.aerror(f"Unexpected error: {e!s}")
raise
else:
return result

View file

@ -117,12 +117,12 @@ class MCPToolsComponent(ComponentWithCache):
schema_inputs = schema_to_langflow_inputs(input_schema)
if not schema_inputs:
msg = f"No input parameters defined for tool '{tool_obj.name}'"
logger.warning(msg)
await logger.awarning(msg)
return []
except Exception as e:
msg = f"Error validating schema inputs: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise ValueError(msg) from e
else:
return schema_inputs
@ -202,11 +202,11 @@ class MCPToolsComponent(ComponentWithCache):
except (TimeoutError, asyncio.TimeoutError) as e:
msg = f"Timeout updating tool list: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise TimeoutError(msg) from e
except Exception as e:
msg = f"Error updating tool list: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise ValueError(msg) from e
else:
return tool_list, {"name": server_name, "config": server_config}
@ -223,7 +223,7 @@ class MCPToolsComponent(ComponentWithCache):
build_config["tool"]["placeholder"] = "Select a tool"
except (TimeoutError, asyncio.TimeoutError) as e:
msg = f"Timeout updating tool list: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
if not build_config["tools_metadata"]["show"]:
build_config["tool"]["show"] = True
build_config["tool"]["options"] = []
@ -249,7 +249,7 @@ class MCPToolsComponent(ComponentWithCache):
break
if tool_obj is None:
msg = f"Tool {field_value} not found in available tools: {self.tools}"
logger.warning(msg)
await logger.awarning(msg)
return build_config
await self._update_tool_config(build_config, field_value)
except Exception as e:
@ -333,7 +333,7 @@ class MCPToolsComponent(ComponentWithCache):
except Exception as e:
msg = f"Error in update_build_config: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise ValueError(msg) from e
else:
return build_config
@ -386,7 +386,7 @@ class MCPToolsComponent(ComponentWithCache):
msg = f"Tool {tool_name} not found in available tools: {self.tools}"
self.remove_non_default_keys(build_config)
build_config["tool"]["value"] = ""
logger.warning(msg)
await logger.awarning(msg)
return
try:
@ -404,14 +404,14 @@ class MCPToolsComponent(ComponentWithCache):
self.schema_inputs = await self._validate_schema_inputs(tool_obj)
if not self.schema_inputs:
msg = f"No input parameters to configure for tool '{tool_name}'"
logger.info(msg)
await logger.ainfo(msg)
return
# Add new inputs to build config
for schema_input in self.schema_inputs:
if not schema_input or not hasattr(schema_input, "name"):
msg = "Invalid schema input detected, skipping"
logger.warning(msg)
await logger.awarning(msg)
continue
try:
@ -428,16 +428,16 @@ class MCPToolsComponent(ComponentWithCache):
except (AttributeError, KeyError, TypeError) as e:
msg = f"Error processing schema input {schema_input}: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
continue
except ValueError as e:
msg = f"Schema validation error for tool {tool_name}: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
self.schema_inputs = []
return
except (AttributeError, KeyError, TypeError) as e:
msg = f"Error updating tool config: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise ValueError(msg) from e
async def build_output(self) -> DataFrame:
@ -474,7 +474,7 @@ class MCPToolsComponent(ComponentWithCache):
return DataFrame(data=[{"error": "You must select a tool"}])
except Exception as e:
msg = f"Error in build_output: {e!s}"
logger.exception(msg)
await logger.aexception(msg)
raise ValueError(msg) from e
def _get_session_context(self) -> str | None:

View file

@ -1,7 +1,6 @@
from typing import Any, cast
import requests
from loguru import logger
from pydantic import ValidationError
from langflow.base.models.anthropic_constants import (
@ -14,6 +13,7 @@ from langflow.base.models.model import LCModelComponent
from langflow.field_typing import LanguageModel
from langflow.field_typing.range_spec import RangeSpec
from langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, SecretStrInput, SliderInput
from langflow.logging.logger import logger
from langflow.schema.dotdict import dotdict
@ -101,7 +101,7 @@ class AnthropicModelComponent(LCModelComponent):
return output
def get_models(self, tool_model_enabled: bool | None = None) -> list[str]:
def get_models(self, *, tool_model_enabled: bool | None = None) -> list[str]:
try:
import anthropic
@ -129,7 +129,7 @@ class AnthropicModelComponent(LCModelComponent):
model_with_tool = ChatAnthropic(
model=model, # Use the current model being checked
anthropic_api_key=self.api_key,
anthropic_api_url=cast(str, self.base_url) or DEFAULT_ANTHROPIC_API_URL,
anthropic_api_url=cast("str", self.base_url) or DEFAULT_ANTHROPIC_API_URL,
)
if (

View file

@ -1,8 +1,8 @@
import assemblyai as aai
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.io import DataInput, DropdownInput, IntInput, Output, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -58,7 +58,7 @@ class AssemblyAIGetSubtitles(Component):
transcript = aai.Transcript.get_by_id(transcript_id)
except Exception as e: # noqa: BLE001
error = f"Getting transcription failed: {e}"
logger.opt(exception=True).debug(error)
logger.debug(error, exc_info=True)
self.status = error
return Data(data={"error": error})

View file

@ -1,8 +1,8 @@
import assemblyai as aai
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.io import DataInput, DropdownInput, FloatInput, IntInput, MultilineInput, Output, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -131,7 +131,7 @@ class AssemblyAILeMUR(Component):
try:
response = self.perform_lemur_action(transcript_group, self.endpoint)
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error running LeMUR")
logger.debug("Error running LeMUR", exc_info=True)
error = f"An Error happened: {e}"
self.status = error
return Data(data={"error": error})

View file

@ -1,8 +1,8 @@
import assemblyai as aai
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -86,7 +86,7 @@ class AssemblyAIListTranscripts(Component):
transcripts = convert_page_to_data_list(page)
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error listing transcripts")
logger.debug("Error listing transcripts", exc_info=True)
error_data = Data(data={"error": f"An error occurred: {e}"})
self.status = [error_data]
return [error_data]

View file

@ -1,9 +1,9 @@
import assemblyai as aai
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.field_typing.range_spec import RangeSpec
from langflow.io import DataInput, FloatInput, Output, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -54,7 +54,7 @@ class AssemblyAITranscriptionJobPoller(Component):
transcript = aai.Transcript.get_by_id(self.transcript_id.data["transcript_id"])
except Exception as e: # noqa: BLE001
error = f"Getting transcription failed: {e}"
logger.opt(exception=True).debug(error)
logger.debug(error, exc_info=True)
self.status = error
return Data(data={"error": error})

View file

@ -1,10 +1,10 @@
from pathlib import Path
import assemblyai as aai
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.io import BoolInput, DropdownInput, FileInput, MessageTextInput, Output, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -176,7 +176,7 @@ class AssemblyAITranscriptionJobCreator(Component):
try:
transcript = aai.Transcriber().submit(audio, config=config)
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error submitting transcription job")
logger.debug("Error submitting transcription job", exc_info=True)
self.status = f"An error occurred: {e}"
return Data(data={"error": f"An error occurred: {e}"})

View file

@ -3,12 +3,12 @@ import re
import requests
from bs4 import BeautifulSoup
from langchain_community.document_loaders import RecursiveUrlLoader
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.field_typing.range_spec import RangeSpec
from langflow.helpers.data import safe_convert
from langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SliderInput, TableInput
from langflow.logging.logger import logger
from langflow.schema.dataframe import DataFrame
from langflow.schema.message import Message
from langflow.services.deps import get_settings_service

View file

@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Any, cast
from astra_assistants.astra_assistants_manager import AssistantManager
from langchain_core.agents import AgentFinish
from loguru import logger
from langflow.base.agents.events import ExceptionWithMessageError, process_agent_events
from langflow.base.astra_assistants.util import (
@ -15,6 +14,7 @@ from langflow.base.astra_assistants.util import (
)
from langflow.custom.custom_component.component_with_cache import ComponentWithCache
from langflow.inputs.inputs import DropdownInput, FileInput, HandleInput, MultilineInput
from langflow.logging.logger import logger
from langflow.memory import delete_message
from langflow.schema.content_block import ContentBlock
from langflow.schema.message import Message
@ -186,8 +186,8 @@ class AstraAssistantManager(ComponentWithCache):
self.initialized = True
async def process_inputs(self) -> None:
logger.info(f"env_set is {self.env_set}")
logger.info(self.input_tools)
await logger.ainfo(f"env_set is {self.env_set}")
await logger.ainfo(self.input_tools)
tools = []
tool_obj = None
if self.input_tools is None:

View file

@ -1,8 +1,7 @@
from loguru import logger
from langflow.base.astra_assistants.util import get_patched_openai_client
from langflow.custom.custom_component.component_with_cache import ComponentWithCache
from langflow.inputs.inputs import MultilineInput, StrInput
from langflow.logging.logger import logger
from langflow.schema.message import Message
from langflow.template.field.base import Output

View file

@ -1,7 +1,6 @@
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.io import DataInput, Output
from langflow.logging.logger import logger
from langflow.schema.data import Data

View file

@ -1,12 +1,11 @@
from typing import TYPE_CHECKING, Any
from loguru import logger
from langflow.base.flow_processing.utils import build_data_from_result_data
from langflow.custom.custom_component.custom_component import CustomComponent
from langflow.graph.graph.base import Graph
from langflow.graph.vertex.base import Vertex
from langflow.helpers.flow import get_flow_inputs
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.dotdict import dotdict
from langflow.template.field.base import Input
@ -36,7 +35,7 @@ class SubFlowComponent(CustomComponent):
return None
async def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
logger.debug(f"Updating build config with field value {field_value} and field name {field_name}")
await logger.adebug(f"Updating build config with field value {field_value} and field name {field_name}")
if field_name == "flow_name":
build_config["flow_name"]["options"] = await self.get_flow_names()
# Clean up the build config
@ -47,11 +46,11 @@ class SubFlowComponent(CustomComponent):
try:
flow_data = await self.get_flow(field_value)
except Exception: # noqa: BLE001
logger.exception(f"Error getting flow {field_value}")
await logger.aexception(f"Error getting flow {field_value}")
else:
if not flow_data:
msg = f"Flow {field_value} not found."
logger.error(msg)
await logger.aerror(msg)
else:
try:
graph = Graph.from_payload(flow_data.data["data"])
@ -60,7 +59,7 @@ class SubFlowComponent(CustomComponent):
# Add inputs to the build config
build_config = self.add_inputs_to_build_config(inputs, build_config)
except Exception: # noqa: BLE001
logger.exception(f"Error building graph for flow {field_value}")
await logger.aexception(f"Error building graph for flow {field_value}")
return build_config
@ -121,5 +120,5 @@ class SubFlowComponent(CustomComponent):
data.extend(build_data_from_result_data(output))
self.status = data
logger.debug(data)
await logger.adebug(data)
return data

View file

@ -68,9 +68,9 @@ class VectaraSelfQueryRetriverComponent(CustomComponent):
metadata_field_obj.append(attribute_info)
return SelfQueryRetriever.from_llm(
self.llm, # noqa: ignore[attr-defined]
self.vectorstore, # noqa: ignore[attr-defined]
self.document_content_description, # noqa: ignore[attr-defined]
self.llm, # type: ignore[attr-defined]
self.vectorstore, # type: ignore[attr-defined]
self.document_content_description, # type: ignore[attr-defined]
metadata_field_obj,
verbose=True,
)

View file

@ -1,8 +1,8 @@
import logging
from typing import TYPE_CHECKING
from langflow.custom.custom_component.component import Component
from langflow.io import HandleInput, MessageInput, Output
from langflow.logging.logger import logger
from langflow.schema.data import Data
if TYPE_CHECKING:
@ -57,8 +57,8 @@ class TextEmbedderComponent(Component):
embedding_vector = embeddings[0]
self.status = {"text": text_content, "embeddings": embedding_vector}
return Data(data={"text": text_content, "embeddings": embedding_vector})
except Exception as e:
logging.exception("Error generating embeddings")
except Exception as e: # noqa: BLE001
logger.exception("Error generating embeddings")
error_data = Data(data={"text": "", "embeddings": [], "error": str(e)})
self.status = {"error": str(e)}
return error_data

View file

@ -1,13 +1,6 @@
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.io import (
BoolInput,
DataInput,
MultilineInput,
Output,
SecretStrInput,
)
from langflow.io import BoolInput, DataInput, MultilineInput, Output, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data

View file

@ -11,11 +11,11 @@ from googleapiclient.discovery import build
from langchain_core.chat_sessions import ChatSession
from langchain_core.messages import HumanMessage
from langchain_google_community.gmail.loader import GMailLoader
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.inputs.inputs import MessageTextInput
from langflow.io import SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.template.field.base import Output

View file

@ -1,21 +1,14 @@
from typing import Any
import requests
from loguru import logger
from pydantic.v1 import SecretStr
from langflow.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS
from langflow.base.models.model import LCModelComponent
from langflow.field_typing import LanguageModel
from langflow.field_typing.range_spec import RangeSpec
from langflow.inputs.inputs import (
BoolInput,
DropdownInput,
FloatInput,
IntInput,
SecretStrInput,
SliderInput,
)
from langflow.inputs.inputs import BoolInput, DropdownInput, FloatInput, IntInput, SecretStrInput, SliderInput
from langflow.logging.logger import logger
from langflow.schema.dotdict import dotdict
@ -105,7 +98,7 @@ class GoogleGenerativeAIComponent(LCModelComponent):
google_api_key=SecretStr(google_api_key).get_secret_value(),
)
def get_models(self, tool_model_enabled: bool | None = None) -> list[str]:
def get_models(self, *, tool_model_enabled: bool | None = None) -> list[str]:
try:
import google.generativeai as genai

View file

@ -1,5 +1,4 @@
import requests
from loguru import logger
from pydantic.v1 import SecretStr
from langflow.base.models.groq_constants import (
@ -11,6 +10,7 @@ from langflow.base.models.model import LCModelComponent
from langflow.field_typing import LanguageModel
from langflow.field_typing.range_spec import RangeSpec
from langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, SecretStrInput, SliderInput
from langflow.logging.logger import logger
class GroqModel(LCModelComponent):
@ -74,7 +74,7 @@ class GroqModel(LCModelComponent):
),
]
def get_models(self, tool_model_enabled: bool | None = None) -> list[str]:
def get_models(self, *, tool_model_enabled: bool | None = None) -> list[str]:
try:
url = f"{self.base_url}/openai/v1/models"
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}

View file

@ -1,10 +1,9 @@
from datetime import datetime
from zoneinfo import ZoneInfo, available_timezones
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.io import DropdownInput, Output
from langflow.logging.logger import logger
from langflow.schema.message import Message
@ -37,7 +36,7 @@ class CurrentDateComponent(Component):
self.status = result
return Message(text=result)
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error getting current date")
logger.debug("Error getting current date", exc_info=True)
error_message = f"Error: {e}"
self.status = error_message
return Message(text=error_message)

View file

@ -220,7 +220,7 @@ class MemoryComponent(Component):
stored = stored[-n_messages:] if order == "ASC" else stored[:n_messages]
# self.status = stored
return cast(Data, stored)
return cast("Data", stored)
async def retrieve_messages_as_text(self) -> Message:
stored_text = data_to_text(self.template, await self.retrieve_messages())

View file

@ -3,13 +3,13 @@ from typing import Any
import requests
from langchain_ibm import ChatWatsonx
from loguru import logger
from pydantic.v1 import SecretStr
from langflow.base.models.model import LCModelComponent
from langflow.field_typing import LanguageModel
from langflow.field_typing.range_spec import RangeSpec
from langflow.inputs.inputs import BoolInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput
from langflow.logging.logger import logger
from langflow.schema.dotdict import dotdict

View file

@ -4,12 +4,12 @@ import requests
from ibm_watsonx_ai import APIClient, Credentials
from ibm_watsonx_ai.metanames import EmbedTextParamsMetaNames
from langchain_ibm import WatsonxEmbeddings
from loguru import logger
from pydantic.v1 import SecretStr
from langflow.base.embeddings.model import LCEmbeddingsModel
from langflow.field_typing import Embeddings
from langflow.io import BoolInput, DropdownInput, IntInput, SecretStrInput, StrInput
from langflow.logging.logger import logger
from langflow.schema.dotdict import dotdict

View file

@ -3,7 +3,6 @@ import os
from typing import Any
import httpx
from loguru import logger
from langflow.base.langwatch.utils import get_cached_evaluators
from langflow.custom.custom_component.component import Component
@ -18,6 +17,7 @@ from langflow.io import (
Output,
SecretStrInput,
)
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.dotdict import dotdict
@ -226,7 +226,7 @@ class LangWatchComponent(Component):
if not evaluator_name:
if self.evaluators:
evaluator_name = next(iter(self.evaluators))
logger.info(f"No evaluator was selected. Using default: {evaluator_name}")
await logger.ainfo(f"No evaluator was selected. Using default: {evaluator_name}")
else:
return Data(
data={"error": "No evaluator selected and no evaluators available. Please choose an evaluator."}
@ -237,7 +237,7 @@ class LangWatchComponent(Component):
if not evaluator:
return Data(data={"error": f"Selected evaluator '{evaluator_name}' not found."})
logger.info(f"Evaluating with evaluator: {evaluator_name}")
await logger.ainfo(f"Evaluating with evaluator: {evaluator_name}")
endpoint = f"/api/evaluations/{evaluator_name}/evaluate"
url = f"{os.getenv('LANGWATCH_ENDPOINT', 'https://app.langwatch.ai')}{endpoint}"

View file

@ -1,6 +1,5 @@
from typing import Any
from loguru import logger
from typing_extensions import override
from langflow.base.langchain_utilities.model import LCToolComponent
@ -9,6 +8,7 @@ from langflow.field_typing import Tool
from langflow.graph.graph.base import Graph
from langflow.helpers.flow import get_flow_inputs
from langflow.io import BoolInput, DropdownInput, Output, StrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.dotdict import dotdict
@ -91,7 +91,7 @@ class FlowToolComponent(LCToolComponent):
try:
graph.set_run_id(self.graph.run_id)
except Exception: # noqa: BLE001
logger.opt(exception=True).warning("Failed to set run_id")
logger.warning("Failed to set run_id", exc_info=True)
inputs = get_flow_inputs(graph)
tool_description = self.tool_description.strip() or flow_data.description
tool = FlowTool(

View file

@ -85,4 +85,4 @@ class NotifyComponent(Component):
self.status = "No record provided."
self._vertex.is_state = True
self.graph.activate_state_vertices(name=self.context_key, caller=self._id)
return cast(Data, input_value)
return cast("Data", input_value)

View file

@ -1,9 +1,8 @@
from typing import Any
from loguru import logger
from langflow.base.tools.run_flow import RunFlowBaseComponent
from langflow.helpers.flow import run_flow
from langflow.logging.logger import logger
from langflow.schema.dotdict import dotdict
@ -34,7 +33,7 @@ class RunFlowComponent(RunFlowBaseComponent):
build_config = self.update_build_config_from_graph(build_config, graph)
except Exception as e:
msg = f"Error building graph for flow {field_value}"
logger.exception(msg)
await logger.aexception(msg)
raise RuntimeError(msg) from e
return build_config

View file

@ -1,13 +1,12 @@
from typing import Any
from loguru import logger
from langflow.base.flow_processing.utils import build_data_from_result_data
from langflow.custom.custom_component.component import Component
from langflow.graph.graph.base import Graph
from langflow.graph.vertex.base import Vertex
from langflow.helpers.flow import get_flow_inputs
from langflow.io import DropdownInput, Output
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.dotdict import dotdict
@ -41,11 +40,11 @@ class SubFlowComponent(Component):
try:
flow_data = await self.get_flow(field_value)
except Exception: # noqa: BLE001
logger.exception(f"Error getting flow {field_value}")
await logger.aexception(f"Error getting flow {field_value}")
else:
if not flow_data:
msg = f"Flow {field_value} not found."
logger.error(msg)
await logger.aerror(msg)
else:
try:
graph = Graph.from_payload(flow_data.data["data"])
@ -54,7 +53,7 @@ class SubFlowComponent(Component):
# Add inputs to the build config
build_config = self.add_inputs_to_build_config(inputs, build_config)
except Exception: # noqa: BLE001
logger.exception(f"Error building graph for flow {field_value}")
await logger.aexception(f"Error building graph for flow {field_value}")
return build_config

View file

@ -1,17 +1,11 @@
import os
from loguru import logger
from mem0 import Memory, MemoryClient
from langflow.base.memory.model import LCChatMemoryComponent
from langflow.inputs.inputs import (
DictInput,
HandleInput,
MessageTextInput,
NestedDictInput,
SecretStrInput,
)
from langflow.inputs.inputs import DictInput, HandleInput, MessageTextInput, NestedDictInput, SecretStrInput
from langflow.io import Output
from langflow.logging.logger import logger
from langflow.schema.data import Data

View file

@ -1,6 +1,5 @@
from typing import Any
from loguru import logger
from requests.exceptions import ConnectionError # noqa: A004
from urllib3.exceptions import MaxRetryError, NameResolutionError
@ -8,6 +7,7 @@ from langflow.base.models.model import LCModelComponent
from langflow.field_typing import LanguageModel
from langflow.field_typing.range_spec import RangeSpec
from langflow.inputs.inputs import BoolInput, DropdownInput, IntInput, MessageTextInput, SecretStrInput, SliderInput
from langflow.logging.logger import logger
from langflow.schema.dotdict import dotdict
@ -97,7 +97,7 @@ class NVIDIAModelComponent(LCModelComponent):
),
]
def get_models(self, tool_model_enabled: bool | None = None) -> list[str]:
def get_models(self, *, tool_model_enabled: bool | None = None) -> list[str]:
try:
from langchain_nvidia_ai_endpoints import ChatNVIDIA
except ImportError as e:
@ -114,7 +114,7 @@ class NVIDIAModelComponent(LCModelComponent):
def update_build_config(self, build_config: dotdict, _field_value: Any, field_name: str | None = None):
if field_name in {"model_name", "tool_model_enabled", "base_url", "api_key"}:
try:
ids = self.get_models(self.tool_model_enabled)
ids = self.get_models(tool_model_enabled=self.tool_model_enabled)
build_config["model_name"]["options"] = ids
if "value" not in build_config["model_name"] or build_config["model_name"]["value"] is None:

View file

@ -1,10 +1,10 @@
import json
import httpx
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.io import MessageTextInput, Output
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -83,7 +83,7 @@ class OlivyaComponent(Component):
"Content-Type": "application/json",
}
logger.info("Sending POST request with payload: %s", payload)
await logger.ainfo("Sending POST request with payload: %s", payload)
# Send the POST request with a timeout
async with httpx.AsyncClient() as client:
@ -97,19 +97,19 @@ class OlivyaComponent(Component):
# Parse and return the successful response
response_data = response.json()
logger.info("Request successful: %s", response_data)
await logger.ainfo("Request successful: %s", response_data)
except httpx.HTTPStatusError as http_err:
logger.exception("HTTP error occurred")
await logger.aexception("HTTP error occurred")
response_data = {"error": f"HTTP error occurred: {http_err}", "response_text": response.text}
except httpx.RequestError as req_err:
logger.exception("Request failed")
await logger.aexception("Request failed")
response_data = {"error": f"Request failed: {req_err}"}
except json.JSONDecodeError as json_err:
logger.exception("Response parsing failed")
await logger.aexception("Response parsing failed")
response_data = {"error": f"Response parsing failed: {json_err}", "raw_response": response.text}
except Exception as e: # noqa: BLE001
logger.exception("An unexpected error occurred")
await logger.aexception("An unexpected error occurred")
response_data = {"error": f"An unexpected error occurred: {e!s}"}
# Return the response as part of the output

View file

@ -245,11 +245,13 @@ class ChatOllamaComponent(LCModelComponent):
if field_name in {"model_name", "base_url", "tool_model_enabled"}:
if await self.is_valid_ollama_url(self.base_url):
tool_model_enabled = build_config["tool_model_enabled"].get("value", False) or self.tool_model_enabled
build_config["model_name"]["options"] = await self.get_models(self.base_url, tool_model_enabled)
build_config["model_name"]["options"] = await self.get_models(
self.base_url, tool_model_enabled=tool_model_enabled
)
elif await self.is_valid_ollama_url(build_config["base_url"].get("value", "")):
tool_model_enabled = build_config["tool_model_enabled"].get("value", False) or self.tool_model_enabled
build_config["model_name"]["options"] = await self.get_models(
build_config["base_url"].get("value", ""), tool_model_enabled
build_config["base_url"].get("value", ""), tool_model_enabled=tool_model_enabled
)
else:
build_config["model_name"]["options"] = []
@ -265,7 +267,7 @@ class ChatOllamaComponent(LCModelComponent):
return build_config
async def get_models(self, base_url_value: str, tool_model_enabled: bool | None = None) -> list[str]:
async def get_models(self, base_url_value: str, *, tool_model_enabled: bool | None = None) -> list[str]:
"""Fetches a list of models from the Ollama API that do not have the "embedding" capability.
Args:
@ -298,13 +300,13 @@ class ChatOllamaComponent(LCModelComponent):
models = tags_response.json()
if asyncio.iscoroutine(models):
models = await models
logger.debug(f"Available models: {models}")
await logger.adebug(f"Available models: {models}")
# Filter models that are NOT embedding models
model_ids = []
for model in models[self.JSON_MODELS_KEY]:
model_name = model[self.JSON_NAME_KEY]
logger.debug(f"Checking model: {model_name}")
await logger.adebug(f"Checking model: {model_name}")
payload = {"model": model_name}
show_response = await client.post(show_url, json=payload)
@ -313,7 +315,7 @@ class ChatOllamaComponent(LCModelComponent):
if asyncio.iscoroutine(json_data):
json_data = await json_data
capabilities = json_data.get(self.JSON_CAPABILITIES_KEY, [])
logger.debug(f"Model: {model_name}, Capabilities: {capabilities}")
await logger.adebug(f"Model: {model_name}, Capabilities: {capabilities}")
if self.DESIRED_CAPABILITY in capabilities and (
not tool_model_enabled or self.TOOL_CALLING_CAPABILITY in capabilities

View file

@ -3,10 +3,10 @@ from __future__ import annotations
from typing import TYPE_CHECKING, Any, cast
import toml # type: ignore[import-untyped]
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.io import BoolInput, DataFrameInput, HandleInput, MessageTextInput, MultilineInput, Output
from langflow.logging.logger import logger
from langflow.schema.dataframe import DataFrame
if TYPE_CHECKING:
@ -144,11 +144,11 @@ class BatchRunComponent(Component):
user_texts = df[col_name].astype(str).tolist()
else:
user_texts = [
self._format_row_as_toml(cast(dict[str, Any], row)) for row in df.to_dict(orient="records")
self._format_row_as_toml(cast("dict[str, Any]", row)) for row in df.to_dict(orient="records")
]
total_rows = len(user_texts)
logger.info(f"Processing {total_rows} rows with batch run")
await logger.ainfo(f"Processing {total_rows} rows with batch run")
# Prepare the batch of conversations
conversations = [
@ -185,21 +185,21 @@ class BatchRunComponent(Component):
):
response_text = response[1].content if hasattr(response[1], "content") else str(response[1])
row = self._create_base_row(
cast(dict[str, Any], original_row), model_response=response_text, batch_index=idx
cast("dict[str, Any]", original_row), model_response=response_text, batch_index=idx
)
self._add_metadata(row, success=True, system_msg=system_msg)
rows.append(row)
# Log progress
if (idx + 1) % max(1, total_rows // 10) == 0:
logger.info(f"Processed {idx + 1}/{total_rows} rows")
await logger.ainfo(f"Processed {idx + 1}/{total_rows} rows")
logger.info("Batch processing completed successfully")
await logger.ainfo("Batch processing completed successfully")
return DataFrame(rows)
except (KeyError, AttributeError) as e:
# Handle data structure and attribute access errors
logger.error(f"Data processing error: {e!s}")
error_row = self._create_base_row({col: "" for col in df.columns}, model_response="", batch_index=-1)
await logger.aerror(f"Data processing error: {e!s}")
error_row = self._create_base_row(dict.fromkeys(df.columns, ""), model_response="", batch_index=-1)
self._add_metadata(error_row, success=False, error=str(e))
return DataFrame([error_row])

View file

@ -181,7 +181,7 @@ class DataOperationsComponent(Component):
raise ValueError(msg)
# Data transformation operations
def select_keys(self, evaluate: bool | None = None) -> Data:
def select_keys(self, *, evaluate: bool | None = None) -> Data:
"""Select specific keys from the data dictionary."""
self.validate_single_data("Select Keys")
data_dict = self.get_normalized_data()
@ -266,7 +266,7 @@ class DataOperationsComponent(Component):
logger.info("evaluating data")
return Data(**self.recursive_eval(self.get_data_dict()))
def combine_data(self, evaluate: bool | None = None) -> Data:
def combine_data(self, *, evaluate: bool | None = None) -> Data:
"""Combine multiple data objects into one."""
logger.info("combining data")
if not self.data_is_list():

View file

@ -1,10 +1,9 @@
from enum import Enum
from typing import cast
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.io import DataInput, DropdownInput, Output
from langflow.logging.logger import logger
from langflow.schema.dataframe import DataFrame

View file

@ -1,7 +1,6 @@
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.io import MessageInput, Output
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.message import Message
@ -32,6 +31,6 @@ class MessageToDataComponent(Component):
return Data(data=self.message.data)
msg = "Error converting Message to Data: Input must be a Message object"
logger.opt(exception=True).debug(msg)
logger.debug(msg, exc_info=True)
self.status = msg
return Data(data={"error": msg})

View file

@ -3,11 +3,11 @@ from json import JSONDecodeError
import jq
from json_repair import repair_json
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.inputs.inputs import HandleInput, MessageTextInput
from langflow.io import Output
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.message import Message

View file

@ -1,10 +1,9 @@
from collections.abc import Callable
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.custom.utils import get_function
from langflow.io import CodeInput, Output
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.dotdict import dotdict
from langflow.schema.message import Message
@ -58,7 +57,7 @@ class PythonFunctionComponent(Component):
func = get_function(function_code)
return func()
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error executing function")
logger.debug("Error executing function", exc_info=True)
return f"Error executing function: {e}"
def execute_function_data(self) -> list[Data]:

View file

@ -2,12 +2,12 @@ from typing import Any
from langchain_community.utilities.serpapi import SerpAPIWrapper
from langchain_core.tools import ToolException
from loguru import logger
from pydantic import BaseModel, Field
from langflow.custom.custom_component.component import Component
from langflow.inputs.inputs import DictInput, IntInput, MultilineInput, SecretStrInput
from langflow.io import Output
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.message import Message

View file

@ -1,8 +1,8 @@
import httpx
from loguru import logger
from langflow.custom import Component
from langflow.io import BoolInput, DropdownInput, MessageTextInput, Output, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema import Data
from langflow.schema.dataframe import DataFrame

View file

@ -1,8 +1,8 @@
import httpx
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.inputs.inputs import BoolInput, DropdownInput, IntInput, MessageTextInput, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.dataframe import DataFrame
from langflow.template.field.base import Output

View file

@ -3,12 +3,12 @@ import operator
from langchain.tools import StructuredTool
from langchain_core.tools import ToolException
from loguru import logger
from pydantic import BaseModel, Field
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.inputs.inputs import MessageTextInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -87,7 +87,7 @@ class CalculatorToolComponent(LCToolComponent):
self.status = error_message
return [Data(data={"error": error_message, "input": expression})]
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error evaluating expression")
logger.debug("Error evaluating expression", exc_info=True)
error_message = f"Error: {e}"
self.status = error_message
return [Data(data={"error": error_message, "input": expression})]

View file

@ -4,21 +4,14 @@ from typing import Any
from langchain.agents import Tool
from langchain_core.tools import StructuredTool
from loguru import logger
from pydantic.v1 import Field, create_model
from pydantic.v1.fields import Undefined
from typing_extensions import override
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.inputs.inputs import (
BoolInput,
DropdownInput,
FieldTypes,
HandleInput,
MessageTextInput,
MultilineInput,
)
from langflow.inputs.inputs import BoolInput, DropdownInput, FieldTypes, HandleInput, MessageTextInput, MultilineInput
from langflow.io import Output
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.dotdict import dotdict
@ -139,7 +132,7 @@ class PythonCodeStructuredTool(LCToolComponent):
build_config["tool_function"]["options"] = names
except Exception as e: # noqa: BLE001
self.status = f"Failed to extract names: {e}"
logger.opt(exception=True).debug(self.status)
logger.debug(self.status, exc_info=True)
build_config["tool_function"]["options"] = ["Failed to parse", str(e)]
return build_config

View file

@ -3,12 +3,12 @@ import importlib
from langchain.tools import StructuredTool
from langchain_core.tools import ToolException
from langchain_experimental.utilities import PythonREPL
from loguru import logger
from pydantic import BaseModel, Field
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.inputs.inputs import StrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -78,7 +78,7 @@ class PythonREPLToolComponent(LCToolComponent):
try:
return python_repl.run(code)
except Exception as e:
logger.opt(exception=True).debug("Error running Python code")
logger.debug("Error running Python code", exc_info=True)
raise ToolException(str(e)) from e
tool = StructuredTool.from_function(

View file

@ -5,12 +5,12 @@ from typing import Any
import requests
from langchain.agents import Tool
from langchain_core.tools import StructuredTool
from loguru import logger
from pydantic.v1 import Field, create_model
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.inputs.inputs import DropdownInput, IntInput, MessageTextInput, MultiselectInput
from langflow.io import Output
from langflow.logging.logger import logger
from langflow.schema.dotdict import dotdict
@ -76,7 +76,7 @@ class SearXNGToolComponent(LCToolComponent):
build_config["language"]["options"] = languages.copy()
except Exception as e: # noqa: BLE001
self.status = f"Failed to extract names: {e}"
logger.opt(exception=True).debug(self.status)
logger.debug(self.status, exc_info=True)
build_config["categories"]["options"] = ["Failed to parse", str(e)]
return build_config
@ -112,7 +112,7 @@ class SearXNGToolComponent(LCToolComponent):
num_results = min(SearxSearch._max_results, len(response["results"]))
return [response["results"][i] for i in range(num_results)]
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error running SearXNG Search")
logger.debug("Error running SearXNG Search", exc_info=True)
return [f"Failed to search: {e}"]
SearxSearch._url = self.url

View file

@ -3,12 +3,12 @@ from typing import Any
from langchain.tools import StructuredTool
from langchain_community.utilities.serpapi import SerpAPIWrapper
from langchain_core.tools import ToolException
from loguru import logger
from pydantic import BaseModel, Field
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.inputs.inputs import DictInput, IntInput, MultilineInput, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
@ -111,7 +111,7 @@ class SerpAPIComponent(LCToolComponent):
data_list = [Data(data=result, text=result.get("snippet", "")) for result in results]
except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error running SerpAPI")
logger.debug("Error running SerpAPI", exc_info=True)
self.status = f"Error: {e}"
return [Data(data={"error": str(e)}, text=str(e))]

View file

@ -3,12 +3,12 @@ from enum import Enum
import httpx
from langchain.tools import StructuredTool
from langchain_core.tools import ToolException
from loguru import logger
from pydantic import BaseModel, Field
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.inputs.inputs import BoolInput, DropdownInput, IntInput, MessageTextInput, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
# Add at the top with other constants
@ -338,7 +338,7 @@ Note: Check 'Advanced' for all options.
raise ToolException(error_message) from e
except Exception as e:
error_message = f"Unexpected error: {e}"
logger.opt(exception=True).debug("Error running Tavily Search")
logger.debug("Error running Tavily Search", exc_info=True)
self.status = error_message
raise ToolException(error_message) from e
return data_results

View file

@ -5,12 +5,12 @@ from enum import Enum
import yfinance as yf
from langchain.tools import StructuredTool
from langchain_core.tools import ToolException
from loguru import logger
from pydantic import BaseModel, Field
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.inputs.inputs import DropdownInput, IntInput, MessageTextInput
from langflow.logging.logger import logger
from langflow.schema.data import Data

View file

@ -29,9 +29,9 @@ class TwelveLabsVideoEmbeddings(Embeddings):
# First try to use video embedding, then fall back to clip embedding if available
if result["video_embedding"] is not None:
embeddings.append(cast(list[float], result["video_embedding"]))
embeddings.append(cast("list[float]", result["video_embedding"]))
elif result["clip_embeddings"] and len(result["clip_embeddings"]) > 0:
embeddings.append(cast(list[float], result["clip_embeddings"][0]))
embeddings.append(cast("list[float]", result["clip_embeddings"][0]))
else:
# If neither is available, raise an error
error_msg = "No embeddings were generated for the video"
@ -45,9 +45,9 @@ class TwelveLabsVideoEmbeddings(Embeddings):
# First try to use video embedding, then fall back to clip embedding if available
if result["video_embedding"] is not None:
return cast(list[float], result["video_embedding"])
return cast("list[float]", result["video_embedding"])
if result["clip_embeddings"] and len(result["clip_embeddings"]) > 0:
return cast(list[float], result["clip_embeddings"][0])
return cast("list[float]", result["clip_embeddings"][0])
# If neither is available, raise an error
error_msg = "No embeddings were generated for the video"
raise ValueError(error_msg)

View file

@ -2,13 +2,13 @@ from copy import deepcopy
from pathlib import Path
from langchain_chroma import Chroma
from loguru import logger
from typing_extensions import override
from langflow.base.vectorstores.model import LCVectorStoreComponent, check_cached_vector_store
from langflow.base.vectorstores.utils import chroma_collection_to_data
from langflow.inputs.inputs import MultilineInput
from langflow.io import BoolInput, DropdownInput, HandleInput, IntInput, MessageTextInput, TabInput
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.dataframe import DataFrame
from langflow.template.field.base import Output

View file

@ -4,12 +4,12 @@ from enum import Enum
import yfinance as yf
from langchain_core.tools import ToolException
from loguru import logger
from pydantic import BaseModel, Field
from langflow.custom.custom_component.component import Component
from langflow.inputs.inputs import DropdownInput, IntInput, MessageTextInput
from langflow.io import Output
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.dataframe import DataFrame

View file

@ -6,6 +6,7 @@ from googleapiclient.errors import HttpError
from langflow.custom.custom_component.component import Component
from langflow.inputs.inputs import BoolInput, DropdownInput, IntInput, SecretStrInput
from langflow.logging.logger import logger
from langflow.schema.dataframe import DataFrame
from langflow.template.field.base import Output
@ -279,8 +280,6 @@ class YouTubeTrendingComponent(Component):
return DataFrame(pd.DataFrame({"error": [error_message]}))
except Exception as e:
import logging
logging.exception("An unexpected error occurred:")
except Exception as e: # noqa: BLE001
logger.exception("An unexpected error occurred:")
return DataFrame(pd.DataFrame({"error": [str(e)]}))

View file

@ -1,7 +1,8 @@
from collections.abc import Callable
import emoji
from loguru import logger
from langflow.logging.logger import logger
def validate_icon(value: str):

View file

@ -8,10 +8,10 @@ from typing import Any
from cachetools import TTLCache, keys
from fastapi import HTTPException
from loguru import logger
from langflow.custom.eval import eval_custom_component_code
from langflow.custom.schema import CallableCodeDetails, ClassCodeDetails, MissingDefault
from langflow.logging.logger import logger
class CodeSyntaxError(HTTPException):

View file

@ -5,11 +5,11 @@ from typing import TYPE_CHECKING, Any, ClassVar
from cachetools import TTLCache, cachedmethod
from fastapi import HTTPException
from loguru import logger
from langflow.custom.attributes import ATTR_FUNC_MAPPING
from langflow.custom.code_parser.code_parser import CodeParser
from langflow.custom.eval import eval_custom_component_code
from langflow.logging.logger import logger
from langflow.utils import validate
if TYPE_CHECKING:

View file

@ -5,9 +5,9 @@ from pathlib import Path
import anyio
from aiofile import async_open
from loguru import logger
from langflow.custom.custom_component.component import Component
from langflow.logging.logger import logger
MAX_DEPTH = 2
@ -255,7 +255,7 @@ class DirectoryReader:
try:
output_types = self.get_output_types_from_code(result_content)
except Exception: # noqa: BLE001
logger.opt(exception=True).debug("Error while getting output types from code")
logger.debug("Error while getting output types from code", exc_info=True)
output_types = [component_name_camelcase]
else:
output_types = [component_name_camelcase]
@ -278,7 +278,7 @@ class DirectoryReader:
try:
file_content = await self.aread_file_content(file_path)
except Exception: # noqa: BLE001
logger.exception(f"Error while reading file {file_path}")
await logger.aexception(f"Error while reading file {file_path}")
return False, f"Could not read {file_path}"
if file_content is None:
@ -300,7 +300,7 @@ class DirectoryReader:
async def abuild_component_menu_list(self, file_paths):
response = {"menu": []}
logger.debug("-------------------- Async Building component menu list --------------------")
await logger.adebug("-------------------- Async Building component menu list --------------------")
tasks = [self.process_file_async(file_path) for file_path in file_paths]
results = await asyncio.gather(*tasks)
@ -311,7 +311,7 @@ class DirectoryReader:
filename = file_path_.name
if not validation_result:
logger.error(f"Error while processing file {file_path}")
await logger.aerror(f"Error while processing file {file_path}")
menu_result = self.find_menu(response, menu_name) or {
"name": menu_name,
@ -329,7 +329,7 @@ class DirectoryReader:
try:
output_types = await asyncio.to_thread(self.get_output_types_from_code, result_content)
except Exception: # noqa: BLE001
logger.exception("Error while getting output types from code")
await logger.aexception("Error while getting output types from code")
output_types = [component_name_camelcase]
else:
output_types = [component_name_camelcase]
@ -346,7 +346,7 @@ class DirectoryReader:
if menu_result not in response["menu"]:
response["menu"].append(menu_result)
logger.debug("-------------------- Component menu list built --------------------")
await logger.adebug("-------------------- Component menu list built --------------------")
return response
@staticmethod

View file

@ -1,8 +1,7 @@
import asyncio
from loguru import logger
from langflow.custom.directory_reader.directory_reader import DirectoryReader
from langflow.logging.logger import logger
from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode

View file

@ -11,7 +11,6 @@ from typing import Any
from uuid import UUID
from fastapi import HTTPException
from loguru import logger
from pydantic import BaseModel
from langflow.custom.custom_component.component import Component
@ -25,6 +24,7 @@ from langflow.custom.eval import eval_custom_component_code
from langflow.custom.schema import MissingDefault
from langflow.field_typing.range_spec import RangeSpec
from langflow.helpers.custom import format_type
from langflow.logging.logger import logger
from langflow.schema.dotdict import dotdict
from langflow.template.field.base import Input
from langflow.template.frontend_node.custom_components import ComponentFrontendNode, CustomComponentFrontendNode
@ -500,7 +500,7 @@ def build_custom_component_template_from_inputs(
if code_hash:
frontend_node.metadata["code_hash"] = code_hash
except Exception as exc: # noqa: BLE001
logger.opt(exception=exc).debug(f"Error generating code hash for {custom_component.__class__.__name__}")
logger.debug(f"Error generating code hash for {custom_component.__class__.__name__}", exc_info=exc)
return frontend_node.to_dict(keep_name=False), cc_instance
@ -573,7 +573,7 @@ def build_custom_component_template(
if code_hash:
frontend_node.metadata["code_hash"] = code_hash
except Exception as exc: # noqa: BLE001
logger.opt(exception=exc).debug(f"Error generating code hash for {custom_component.__class__.__name__}")
logger.debug(f"Error generating code hash for {custom_component.__class__.__name__}", exc_info=exc)
return frontend_node.to_dict(keep_name=False), custom_instance
except Exception as exc:
@ -646,7 +646,7 @@ async def abuild_custom_components(components_paths: list[str]):
if not components_paths:
return {}
logger.debug(f"Building custom components from {components_paths}")
await logger.adebug(f"Building custom components from {components_paths}")
custom_components_from_file: dict = {}
processed_paths = set()
for path in components_paths:
@ -657,7 +657,7 @@ async def abuild_custom_components(components_paths: list[str]):
custom_component_dict = await abuild_custom_component_list_from_path(path_str)
if custom_component_dict:
category = next(iter(custom_component_dict))
logger.debug(f"Loading {len(custom_component_dict[category])} component(s) from category {category}")
await logger.adebug(f"Loading {len(custom_component_dict[category])} component(s) from category {category}")
custom_components_from_file = merge_nested_dicts_with_renaming(
custom_components_from_file, custom_component_dict
)
@ -745,18 +745,18 @@ async def get_single_component_dict(component_type: str, component_name: str, co
if hasattr(module, "template"):
return module.template
except ImportError as e:
logger.error(f"Import error loading component {module_path}: {e!s}")
await logger.aerror(f"Import error loading component {module_path}: {e!s}")
except AttributeError as e:
logger.error(f"Attribute error loading component {module_path}: {e!s}")
await logger.aerror(f"Attribute error loading component {module_path}: {e!s}")
except ValueError as e:
logger.error(f"Value error loading component {module_path}: {e!s}")
await logger.aerror(f"Value error loading component {module_path}: {e!s}")
except (KeyError, IndexError) as e:
logger.error(f"Data structure error loading component {module_path}: {e!s}")
await logger.aerror(f"Data structure error loading component {module_path}: {e!s}")
except RuntimeError as e:
logger.error(f"Runtime error loading component {module_path}: {e!s}")
logger.debug("Full traceback for runtime error", exc_info=True)
await logger.aerror(f"Runtime error loading component {module_path}: {e!s}")
await logger.adebug("Full traceback for runtime error", exc_info=True)
except OSError as e:
logger.error(f"OS error loading component {module_path}: {e!s}")
await logger.aerror(f"OS error loading component {module_path}: {e!s}")
# If we get here, the component wasn't found or couldn't be loaded
return None
@ -811,43 +811,43 @@ async def load_custom_component(component_name: str, components_paths: list[str]
if hasattr(module, "get_template"):
return module.get_template()
except ImportError as e:
logger.error(f"Import error loading component {component_file}: {e!s}")
logger.debug("Import error traceback", exc_info=True)
await logger.aerror(f"Import error loading component {component_file}: {e!s}")
await logger.adebug("Import error traceback", exc_info=True)
except AttributeError as e:
logger.error(f"Attribute error loading component {component_file}: {e!s}")
logger.debug("Attribute error traceback", exc_info=True)
await logger.aerror(f"Attribute error loading component {component_file}: {e!s}")
await logger.adebug("Attribute error traceback", exc_info=True)
except (ValueError, TypeError) as e:
logger.error(f"Value/Type error loading component {component_file}: {e!s}")
logger.debug("Value/Type error traceback", exc_info=True)
await logger.aerror(f"Value/Type error loading component {component_file}: {e!s}")
await logger.adebug("Value/Type error traceback", exc_info=True)
except (KeyError, IndexError) as e:
logger.error(f"Data structure error loading component {component_file}: {e!s}")
logger.debug("Data structure error traceback", exc_info=True)
await logger.aerror(f"Data structure error loading component {component_file}: {e!s}")
await logger.adebug("Data structure error traceback", exc_info=True)
except RuntimeError as e:
logger.error(f"Runtime error loading component {component_file}: {e!s}")
logger.debug("Runtime error traceback", exc_info=True)
await logger.aerror(f"Runtime error loading component {component_file}: {e!s}")
await logger.adebug("Runtime error traceback", exc_info=True)
except OSError as e:
logger.error(f"OS error loading component {component_file}: {e!s}")
logger.debug("OS error traceback", exc_info=True)
await logger.aerror(f"OS error loading component {component_file}: {e!s}")
await logger.adebug("OS error traceback", exc_info=True)
except ImportError as e:
logger.error(f"Import error loading custom component {component_name}: {e!s}")
await logger.aerror(f"Import error loading custom component {component_name}: {e!s}")
return None
except AttributeError as e:
logger.error(f"Attribute error loading custom component {component_name}: {e!s}")
await logger.aerror(f"Attribute error loading custom component {component_name}: {e!s}")
return None
except ValueError as e:
logger.error(f"Value error loading custom component {component_name}: {e!s}")
await logger.aerror(f"Value error loading custom component {component_name}: {e!s}")
return None
except (KeyError, IndexError) as e:
logger.error(f"Data structure error loading custom component {component_name}: {e!s}")
await logger.aerror(f"Data structure error loading custom component {component_name}: {e!s}")
return None
except RuntimeError as e:
logger.error(f"Runtime error loading custom component {component_name}: {e!s}")
await logger.aerror(f"Runtime error loading custom component {component_name}: {e!s}")
logger.debug("Full traceback for runtime error", exc_info=True)
return None
# If we get here, the component wasn't found in any of the paths
logger.warning(f"Component {component_name} not found in any of the provided paths")
await logger.awarning(f"Component {component_name} not found in any of the provided paths")
return None

View file

@ -8,9 +8,9 @@ from functools import partial
from typing import TYPE_CHECKING
from fastapi.encoders import jsonable_encoder
from loguru import logger
from typing_extensions import Protocol
from langflow.logging.logger import logger
from langflow.schema.playground_events import create_event_by_type
if TYPE_CHECKING:

View file

@ -2,9 +2,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING, Any, cast
from loguru import logger
from langflow.graph.edge.schema import EdgeData, LoopTargetHandleDict, SourceHandle, TargetHandle, TargetHandleDict
from langflow.logging.logger import logger
from langflow.schema.schema import INPUT_FIELD_NAME
if TYPE_CHECKING:
@ -28,7 +27,7 @@ class Edge:
try:
if "name" in self._target_handle:
self.target_handle: TargetHandle = TargetHandle.from_loop_target_handle(
cast(LoopTargetHandleDict, self._target_handle)
cast("LoopTargetHandleDict", self._target_handle)
)
else:
self.target_handle = TargetHandle(**self._target_handle)

View file

@ -15,8 +15,6 @@ from functools import partial
from itertools import chain
from typing import TYPE_CHECKING, Any, cast
from loguru import logger
from langflow.exceptions.component import ComponentBuildError
from langflow.graph.edge.base import CycleEdge, Edge
from langflow.graph.graph.constants import Finish, lazy_load_vertex_dict
@ -36,7 +34,7 @@ from langflow.graph.utils import log_vertex_build
from langflow.graph.vertex.base import Vertex, VertexStates
from langflow.graph.vertex.schema import NodeData, NodeTypeEnum
from langflow.graph.vertex.vertex_types import ComponentVertex, InterfaceVertex, StateVertex
from langflow.logging.logger import LogConfig, configure
from langflow.logging.logger import LogConfig, configure, logger
from langflow.schema.dotdict import dotdict
from langflow.schema.schema import INPUT_FIELD_NAME, InputType, OutputValue
from langflow.services.cache.utils import CacheMiss
@ -848,7 +846,7 @@ class Graph:
event_manager=event_manager,
)
run_output_object = RunOutputs(inputs=run_inputs, outputs=run_outputs)
logger.debug(f"Run outputs: {run_output_object}")
await logger.adebug(f"Run outputs: {run_output_object}")
vertex_outputs.append(run_output_object)
return vertex_outputs
@ -1449,7 +1447,7 @@ class Graph:
if vertex.result is not None:
vertex.result.used_frozen_result = True
except Exception: # noqa: BLE001
logger.opt(exception=True).debug("Error finalizing build")
logger.debug("Error finalizing build", exc_info=True)
should_build = True
except KeyError:
should_build = True
@ -1476,7 +1474,7 @@ class Graph:
except Exception as exc:
if not isinstance(exc, ComponentBuildError):
logger.exception("Error building Component")
await logger.aexception("Error building Component")
raise
if vertex.result is not None:
@ -1557,20 +1555,20 @@ class Graph:
tasks.append(task)
vertex_task_run_count[vertex_id] = vertex_task_run_count.get(vertex_id, 0) + 1
logger.debug(f"Running layer {layer_index} with {len(tasks)} tasks, {current_batch}")
await logger.adebug(f"Running layer {layer_index} with {len(tasks)} tasks, {current_batch}")
try:
next_runnable_vertices = await self._execute_tasks(
tasks, lock=lock, has_webhook_component=has_webhook_component
)
except Exception:
logger.exception(f"Error executing tasks in layer {layer_index}")
await logger.aexception(f"Error executing tasks in layer {layer_index}")
raise
if not next_runnable_vertices:
break
to_process.extend(next_runnable_vertices)
layer_index += 1
logger.debug("Graph processing complete")
await logger.adebug("Graph processing complete")
return self
def find_next_runnable_vertices(self, vertex_successors_ids: list[str]) -> list[str]:
@ -1634,7 +1632,7 @@ class Graph:
from langflow.api.utils import format_exception_message
tb = traceback.format_exc()
logger.exception("Error building Component")
await logger.aexception("Error building Component")
params = format_exception_message(result)
message = {"errorMessage": params, "stackTrace": tb}
@ -1680,7 +1678,7 @@ class Graph:
vertex_id = tasks[i].get_name().split(" ")[0]
if isinstance(result, Exception):
logger.error(f"Task {task_name} failed with exception: {result}")
await logger.aerror(f"Task {task_name} failed with exception: {result}")
if has_webhook_component:
await self._log_vertex_build_from_exception(vertex_id, result)
@ -1710,7 +1708,7 @@ class Graph:
# This could usually happen with input vertices like ChatInput
self.run_manager.remove_vertex_from_runnables(v.id)
logger.debug(f"Vertex {v.id}, result: {v.built_result}, object: {v.built_object}")
await logger.adebug(f"Vertex {v.id}, result: {v.built_result}, object: {v.built_object}")
for v in vertices:
next_runnable_vertices = await self.get_next_runnable_vertices(lock, vertex=v, cache=False)
@ -1996,6 +1994,10 @@ class Graph:
f"{edges_repr}"
)
def __hash__(self) -> int:
"""Return hash of the graph based on its string representation."""
return hash(self.__repr__())
def get_vertex_predecessors_ids(self, vertex_id: str) -> list[str]:
"""Get the predecessor IDs of a vertex."""
return [v.id for v in self.get_predecessors(self.get_vertex(vertex_id))]

View file

@ -17,6 +17,9 @@ class Finish:
def __eq__(self, /, other):
return isinstance(other, Finish)
def __hash__(self) -> int:
return hash(type(self))
def _import_vertex_types():
from langflow.graph.vertex import vertex_types

View file

@ -6,9 +6,9 @@ from typing import TYPE_CHECKING, Any
from uuid import UUID
import pandas as pd
from loguru import logger
from langflow.interface.utils import extract_input_variables_from_prompt
from langflow.logging.logger import logger
from langflow.schema.data import Data
from langflow.schema.message import Message
from langflow.serialization.serialization import get_max_items_length, get_max_text_length, serialize
@ -141,7 +141,7 @@ async def log_transaction(
result_dict[key] = value.to_dict()
outputs = result_dict
except Exception as e: # noqa: BLE001
logger.warning(f"Error serializing result: {e!s}")
await logger.awarning(f"Error serializing result: {e!s}")
outputs = None
else:
outputs = None
@ -159,9 +159,9 @@ async def log_transaction(
with session.no_autoflush:
inserted = await crud_log_transaction(session, transaction)
if inserted:
logger.debug(f"Logged transaction: {inserted.id}")
await logger.adebug(f"Logged transaction: {inserted.id}")
except Exception as exc: # noqa: BLE001
logger.error(f"Error logging transaction: {exc!s}")
await logger.aerror(f"Error logging transaction: {exc!s}")
async def log_vertex_build(
@ -198,9 +198,9 @@ async def log_vertex_build(
)
async with session_getter(get_db_service()) as session:
inserted = await crud_log_vertex_build(session, vertex_build)
logger.debug(f"Logged vertex build: {inserted.build_id}")
await logger.adebug(f"Logged vertex build: {inserted.build_id}")
except Exception: # noqa: BLE001
logger.exception("Error logging vertex build")
await logger.aexception("Error logging vertex build")
def rewrite_file_path(file_path: str):

View file

@ -8,14 +8,13 @@ from collections.abc import AsyncIterator, Callable, Iterator, Mapping
from enum import Enum
from typing import TYPE_CHECKING, Any
from loguru import logger
from langflow.exceptions.component import ComponentBuildError
from langflow.graph.schema import INPUT_COMPONENTS, OUTPUT_COMPONENTS, InterfaceComponentTypes, ResultData
from langflow.graph.utils import UnbuiltObject, UnbuiltResult, log_transaction
from langflow.graph.vertex.param_handler import ParameterHandler
from langflow.interface import initialize
from langflow.interface.listing import lazy_load_dict
from langflow.logging.logger import logger
from langflow.schema.artifact import ArtifactType
from langflow.schema.data import Data
from langflow.schema.message import Message
@ -378,7 +377,7 @@ class Vertex:
event_manager: EventManager | None = None,
) -> None:
"""Initiate the build process."""
logger.debug(f"Building {self.display_name}")
await logger.adebug(f"Building {self.display_name}")
await self._build_each_vertex_in_params_dict()
if self.base_type is None:
@ -599,7 +598,7 @@ class Vertex:
self.params[key].append(result)
except AttributeError as e:
logger.exception(e)
await logger.aexception(e)
msg = (
f"Params {key} ({self.params[key]}) is not a list and cannot be extended with {result}"
f"Error building Component {self.display_name}: \n\n{e}"
@ -646,7 +645,7 @@ class Vertex:
self._update_built_object_and_artifacts(result)
except Exception as exc:
tb = traceback.format_exc()
logger.exception(exc)
await logger.aexception(exc)
msg = f"Error building Component {self.display_name}: \n\n{exc}"
raise ComponentBuildError(msg, tb) from exc

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