#15358·langflow

Multiple components of the same type, wired as separate Agent tools, all get the identical tool name

Author: Lakshay-TripathiCreated Sep 24, 2026Updated Oct 1, 2026
Labelsbugjira

Bug Description

_derive_tool_name() (src/lfx/src/lfx/base/tools/component_tool.py) picks the name an LLM sees for a tool based only on the component's class and its output method name — never on anything specific to that particular node's own configuration:

python
def _derive_tool_name(component: Component, output_method: str, outputs: list[Output]) -> str:
    if output_method in _GENERIC_OUTPUT_METHOD_NAMES and len(outputs) == 1:
        return _class_name_to_tool_name(type(component).__name__)
    return output_method

Both branches return something that depends only on the component's type, never on the specific instance. Any two (or more) components of the same type, each configured differently and each wired as a separate tool into the same Agent's Tools input (e.g. two A2A Agent nodes pointing at two different remote agents), get the exact same tool name. Nothing downstream (ComponentToolkit.get_tools(), or the Agent component's own self.tools handling) checks for or resolves duplicate names before handing the list to the LLM.

Practical effect, confirmed with two different model providers (not a model-reliability quirk): with several same-type tools attached, the model has no way to distinguish them. Depending on the model, this shows up as either (a) the model invoking only one of them and fabricating a plausible-sounding answer for the others, or (b) the model forming distinct, appropriately-targeted calls, with every call executing against whichever single tool instance "won" the name collision, regardless of which one the model intended.

The universal synthetic to_toolkit method (added to every tool-mode component) is not the source of the collision: _should_skip_output filters that output out before a tool is built from it, so _derive_tool_name never receives "to_toolkit" as output_method in practice. The collision comes through the component's own genuine output method — e.g. send_to_agent for A2A Agent — a plain class-level constant, identical across every instance of that class.

Reproduction

  1. Create two flows, each exposing itself as an A2A agent (or use any two components of the same type with different configuration).
  2. In a third flow, add two A2A Agent components, each pointed at one of the two flows above (External mode).
  3. Enable Tool Mode on both, and wire both into one Agent component's Tools input.
  4. Ask the agent something that requires calling both.

Both tools register under the identical name. Depending on the model, either only one is ever genuinely called, or both calls land on the same one regardless of intent — confirmed by checking each target flow's own execution logs, not just the top-level response text.

Verifiable directly at the code level too: build two differently-configured instances of the same component and inspect ComponentToolkit(instance).get_tools()'s resulting tool .name for each — both are identical.

Expected behavior

Each tool-mode component instance wired into an Agent, even when it's the same type as another, should get a name the LLM can use to distinguish them.

Proposed fix

Disambiguate by instance, unconditionally, appending a slug of the component's own node id to whatever name the existing logic would otherwise produce:

python
def _derive_tool_name(component: Component, output_method: str, outputs: list[Output]) -> str:
    if output_method in _GENERIC_OUTPUT_METHOD_NAMES and len(outputs) == 1:
        base = _class_name_to_tool_name(type(component).__name__)
    else:
        base = output_method
    node_id = getattr(component, "_id", None) or ""
    suffix = re.sub(r"[^a-zA-Z0-9_]", "_", str(node_id)).strip("_")
    return f"{base}_{suffix}" if suffix else base

Verified with a multi-tool agent run (two reviews plus a conditional fix step): each call reaches its correct, distinct target, confirmed via each target flow's execution logs. Happy to open a PR.

Langflow Version

1.12.3

Python Version

3.14

Operating System

Linux (Docker, langflowai/langflow:1.12.3 image)