Skip to content

[BUG] SequentialTaskAgentComponent skips convert_llm at Agent factory; sibling factory applies it #13848

Description

@Fr3ya

Bug Description

SequentialTaskAgentComponent.build_agent_and_task at src/lfx/src/lfx/components/crewai/sequential_task_agent.py:107-127 constructs crewai.Agent(llm=self.llm, ...) with the raw LanguageModel handle from its HandleInput. It never calls convert_llm() (the helper that wraps a LangChain BaseChatModel into a crewai.LLM). The sibling factory CrewAIAgentComponent.build_output at src/lfx/src/lfx/components/crewai/crewai.py:83-108 (line 93) does call convert_llm(self.llm) at the same construction point, so the two Agent factories in the same package disagree on whether the Agent leaves the factory with a CrewAI-typed .llm or a raw LangChain handle.

the conversion is performed lazily by BaseCrewComponent.get_tasks_and_agents (line 166: agent.llm = convert_llm(agent.llm)) only when the Agent is consumed via a SequentialCrewComponent. Any other consumer of the SequentialTask.agent port — i.e. any visual-graph edge from this factory's output that doesn't terminate at a SequentialCrew — receives an Agent whose .llm is the wrong type for CrewAI's executor.

Important caveat. SequentialTaskAgentComponent declares legacy = True (line 11), so the framework already discourages new flows from using it. If the plan is to delete it, this report is moot; if it stays in the codebase to support saved flows, the asymmetry with the non-legacy sibling is worth resolving with the one-line fix.

Reproduction

The reproducer below AST-parses the two factories and asserts the asymmetry plus the lazy-wrap deferral downstream. No langflow / crewai install is required.

from __future__ import annotations
import ast, sys
from pathlib import Path

REPO = Path("/path/to/cloned/langflow")    # adjust to your checkout
FACTORY = REPO/"src/lfx/src/lfx/components/crewai/sequential_task_agent.py"
SIBLING = REPO/"src/lfx/src/lfx/components/crewai/crewai.py"
WRAPPER = REPO/"src/lfx/src/lfx/base/agents/crewai/crew.py"

def find_method(tree, cls, name):
    for n in ast.walk(tree):
        if isinstance(n, ast.ClassDef) and n.name == cls:
            for s in n.body:
                if isinstance(s, (ast.FunctionDef, ast.AsyncFunctionDef)) and s.name == name:
                    return s
def find_agent_call(fn):
    for s in ast.walk(fn):
        if isinstance(s, ast.Call) and isinstance(s.func, ast.Name) and s.func.id == "Agent":
            return s
def kwarg_src(call, name):
    for kw in call.keywords:
        if kw.arg == name: return ast.unparse(kw.value)

# Check 1: factory passes self.llm raw (no convert_llm)
fn = find_method(ast.parse(FACTORY.read_text()), "SequentialTaskAgentComponent", "build_agent_and_task")
factory_llm = kwarg_src(find_agent_call(fn), "llm")
print(f"factory llm kwarg          = {factory_llm!r}")
assert factory_llm == "self.llm", factory_llm
assert "convert_llm" not in FACTORY.read_text(), "factory unexpectedly mentions convert_llm"

# Check 2: sibling factory DOES wrap with convert_llm
fn = find_method(ast.parse(SIBLING.read_text()), "CrewAIAgentComponent", "build_output")
sibling_llm = kwarg_src(find_agent_call(fn), "llm")
print(f"sibling llm kwarg          = {sibling_llm!r}")
assert "convert_llm" in sibling_llm

# Check 3: downstream wrapper lazy-converts (only fires for SequentialCrew consumers)
fn = find_method(ast.parse(WRAPPER.read_text()), "BaseCrewComponent", "get_tasks_and_agents")
lazy_wrap_found = any(
    isinstance(s, ast.Assign) and isinstance(s.targets[0], ast.Attribute)
    and s.targets[0].attr == "llm" and isinstance(s.targets[0].value, ast.Name)
    and s.targets[0].value.id == "agent" and "convert_llm" in ast.unparse(s.value)
    for s in ast.walk(fn)
)
print(f"downstream lazy wrap found = {lazy_wrap_found}")
assert lazy_wrap_found

print("CONFIRMED BUG: SequentialTaskAgentComponent skips convert_llm; sibling does not")

Expected behavior

Either (a) both SequentialTaskAgentComponent.build_agent_and_task and CrewAIAgentComponent.build_output apply convert_llm eagerly at the Agent(...) construction site, or (b) the SequentialTaskAgentComponent is removed since it is already marked legacy = True. The current state — one factory wraps, the other does not — leaves Agents produced by the legacy component with a non-CrewAI .llm whenever the Agent is consumed outside the SequentialCrew lazy-wrap path.

Who can help?

No response

Operating System

Ubuntu Linux 22.04

Langflow Version

1.10.0 (bug is in source at commit 43d3510ec74ad3125f1e1e0b5598900c0e0e70f8, current main)

Python Version

3.12

Screenshot

No response

Flow File

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions