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
Bug Description
SequentialTaskAgentComponent.build_agent_and_taskatsrc/lfx/src/lfx/components/crewai/sequential_task_agent.py:107-127constructscrewai.Agent(llm=self.llm, ...)with the rawLanguageModelhandle from itsHandleInput. It never callsconvert_llm()(the helper that wraps a LangChainBaseChatModelinto acrewai.LLM). The sibling factoryCrewAIAgentComponent.build_outputatsrc/lfx/src/lfx/components/crewai/crewai.py:83-108(line 93) does callconvert_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.llmor 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 aSequentialCrewComponent. Any other consumer of theSequentialTask.agentport — i.e. any visual-graph edge from this factory's output that doesn't terminate at aSequentialCrew— receives an Agent whose.llmis the wrong type for CrewAI's executor.Important caveat.
SequentialTaskAgentComponentdeclareslegacy = 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/crewaiinstall is required.Expected behavior
Either (a) both
SequentialTaskAgentComponent.build_agent_and_taskandCrewAIAgentComponent.build_outputapplyconvert_llmeagerly at theAgent(...)construction site, or (b) theSequentialTaskAgentComponentis removed since it is already markedlegacy = True. The current state — one factory wraps, the other does not — leaves Agents produced by the legacy component with a non-CrewAI.llmwhenever the Agent is consumed outside theSequentialCrewlazy-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, currentmain)Python Version
3.12
Screenshot
No response
Flow File
No response