Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
25a6af2
Refactor knowledge base path initialization
edwinjosechittilappilly Oct 21, 2025
8ea7379
Update component_index.json
edwinjosechittilappilly Oct 21, 2025
b94bd74
Add IBM watsonx.ai support to starter projects
edwinjosechittilappilly Oct 22, 2025
516257d
Add Ollama to supported LLM providers in starter projects
edwinjosechittilappilly Oct 22, 2025
c805135
Update Ollama model input constants and logic
edwinjosechittilappilly Oct 22, 2025
3c18df1
Merge branch 'main' into lf-agents-ibm
edwinjosechittilappilly Oct 22, 2025
ca46214
Add Notion integration components
edwinjosechittilappilly Oct 22, 2025
af4ee00
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 22, 2025
8c62e30
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Oct 22, 2025
b513476
[autofix.ci] apply automated fixes (attempt 3/3)
autofix-ci[bot] Oct 22, 2025
aec2ad5
Update agent code and code_hash in starter projects
edwinjosechittilappilly Oct 22, 2025
ae58791
Merge branch 'lf-agents-ibm' of https://github.com/langflow-ai/langfl…
edwinjosechittilappilly Oct 22, 2025
6458a57
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 22, 2025
e0a4334
Merge branch 'main' into lf-agents-ibm
edwinjosechittilappilly Oct 28, 2025
7ba346b
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 28, 2025
129ebc0
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Oct 28, 2025
b10b241
Update component_index.json
edwinjosechittilappilly Oct 29, 2025
39dd011
Merge branch 'lf-agents-ibm' of https://github.com/langflow-ai/langfl…
edwinjosechittilappilly Oct 29, 2025
9b95388
Use PEP 604 union syntax for provider_name type hints
edwinjosechittilappilly Oct 29, 2025
8e6c84c
Remove commented watsonx_inputs_filtered line
edwinjosechittilappilly Oct 30, 2025
85e2a3e
Merge branch 'main' into lf-agents-ibm
edwinjosechittilappilly Oct 30, 2025
5fb82d1
Update component_index.json
edwinjosechittilappilly Oct 30, 2025
5f84a78
Add support for new LLM providers and agent config fields
edwinjosechittilappilly Oct 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/lfx/src/lfx/_assets/component_index.json

Large diffs are not rendered by default.

81 changes: 74 additions & 7 deletions src/lfx/src/lfx/base/models/model_input_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,26 @@ class ModelProvidersDict(TypedDict):
is_active: bool


def get_filtered_inputs(component_class):
def get_filtered_inputs(component_class, provider_name: str | None = None):
base_input_names = {field.name for field in LCModelComponent.get_base_inputs()}
component_instance = component_class()

return [process_inputs(input_) for input_ in component_instance.inputs if input_.name not in base_input_names]
return [
process_inputs(input_, provider_name)
for input_ in component_instance.inputs
if input_.name not in base_input_names
]


def process_inputs(component_data: Input):
def process_inputs(component_data: Input, provider_name: str | None = None):
"""Processes and modifies an input configuration based on its type or name.

Adjusts properties such as value, advanced status, real-time refresh, and additional information for specific
input types or names to ensure correct behavior in the UI and provider integration.

Args:
component_data: The input configuration to process.
provider_name: The name of the provider to process the inputs for.

Returns:
The modified input configuration.
Expand All @@ -43,9 +48,11 @@ def process_inputs(component_data: Input):
component_data.advanced = True
component_data.value = True
elif component_data.name in {"temperature", "base_url"}:
component_data = set_advanced_true(component_data)
if provider_name not in ["IBM watsonx.ai", "Ollama"]:
component_data = set_advanced_true(component_data)
elif component_data.name == "model_name":
component_data = set_real_time_refresh_false(component_data)
if provider_name not in ["IBM watsonx.ai"]:
component_data = set_real_time_refresh_false(component_data)
component_data = add_combobox_true(component_data)
component_data = add_info(
component_data,
Expand Down Expand Up @@ -79,6 +86,28 @@ def create_input_fields_dict(inputs: list[Input], prefix: str) -> dict[str, Inpu
return {f"{prefix}{input_.name}": input_.to_dict() for input_ in inputs}


def _get_ollama_inputs_and_fields():
try:
from lfx.components.ollama.ollama import ChatOllamaComponent

ollama_inputs = get_filtered_inputs(ChatOllamaComponent, provider_name="Ollama")
except ImportError as e:
msg = "Ollama is not installed. Please install it with `pip install langchain-ollama`."
raise ImportError(msg) from e
return ollama_inputs, create_input_fields_dict(ollama_inputs, "")


def _get_watsonx_inputs_and_fields():
try:
from lfx.components.ibm.watsonx import WatsonxAIComponent

watsonx_inputs = get_filtered_inputs(WatsonxAIComponent, provider_name="IBM watsonx.ai")
except ImportError as e:
msg = "IBM watsonx.ai is not installed. Please install it with `pip install langchain-ibm-watsonx`."
raise ImportError(msg) from e
return watsonx_inputs, create_input_fields_dict(watsonx_inputs, "")


def _get_google_generative_ai_inputs_and_fields():
try:
from lfx.components.google.google_generative_ai import GoogleGenerativeAIComponent
Expand Down Expand Up @@ -293,6 +322,36 @@ def _get_sambanova_inputs_and_fields():
except ImportError:
pass

try:
from lfx.components.ibm.watsonx import WatsonxAIComponent

watsonx_inputs, watsonx_fields = _get_watsonx_inputs_and_fields()
MODEL_PROVIDERS_DICT["IBM watsonx.ai"] = {
"fields": watsonx_fields,
"inputs": watsonx_inputs,
"prefix": "",
"component_class": WatsonxAIComponent(),
"icon": WatsonxAIComponent.icon,
"is_active": True,
}
except ImportError:
pass

try:
from lfx.components.ollama.ollama import ChatOllamaComponent

ollama_inputs, ollama_fields = _get_ollama_inputs_and_fields()
MODEL_PROVIDERS_DICT["Ollama"] = {
"fields": ollama_fields,
"inputs": ollama_inputs,
"prefix": "",
"component_class": ChatOllamaComponent(),
"icon": ChatOllamaComponent.icon,
"is_active": True,
}
except ImportError:
pass

# Expose only active providers ----------------------------------------------
ACTIVE_MODEL_PROVIDERS_DICT: dict[str, ModelProvidersDict] = {
name: prov for name, prov in MODEL_PROVIDERS_DICT.items() if prov.get("is_active", True)
Expand All @@ -302,10 +361,18 @@ def _get_sambanova_inputs_and_fields():

ALL_PROVIDER_FIELDS: list[str] = [field for prov in ACTIVE_MODEL_PROVIDERS_DICT.values() for field in prov["fields"]]

MODEL_DYNAMIC_UPDATE_FIELDS = ["api_key", "model", "tool_model_enabled", "base_url", "model_name"]
MODEL_DYNAMIC_UPDATE_FIELDS = [
"api_key",
"model",
"tool_model_enabled",
"base_url",
"model_name",
"watsonx_endpoint",
"url",
]

MODELS_METADATA = {name: {"icon": prov["icon"]} for name, prov in ACTIVE_MODEL_PROVIDERS_DICT.items()}

MODEL_PROVIDERS_LIST = ["Anthropic", "Google Generative AI", "OpenAI"]
MODEL_PROVIDERS_LIST = ["Anthropic", "Google Generative AI", "OpenAI", "IBM watsonx.ai", "Ollama"]

MODEL_OPTIONS_METADATA = [MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST if key in MODELS_METADATA]
31 changes: 29 additions & 2 deletions src/lfx/src/lfx/components/agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from lfx.custom.custom_component.component import get_component_toolkit
from lfx.custom.utils import update_component_build_config
from lfx.helpers.base_model import build_model_from_schema
from lfx.inputs.inputs import BoolInput
from lfx.inputs.inputs import BoolInput, SecretStrInput, StrInput
from lfx.io import DropdownInput, IntInput, MessageTextInput, MultilineInput, Output, TableInput
from lfx.log.logger import logger
from lfx.schema.data import Data
Expand Down Expand Up @@ -77,6 +77,32 @@ class AgentComponent(ToolCallingAgentComponent):
},
},
),
SecretStrInput(
name="api_key",
display_name="API Key",
info="The API key to use for the model.",
required=True,
),
StrInput(
name="base_url",
display_name="Base URL",
info="The base URL of the API.",
required=True,
show=False,
),
StrInput(
name="project_id",
display_name="Project ID",
info="The project ID of the model.",
required=True,
show=False,
),
IntInput(
name="max_output_tokens",
display_name="Max Output Tokens",
info="The maximum number of tokens to generate.",
show=False,
),
*openai_inputs_filtered,
MultilineInput(
name="system_prompt",
Expand Down Expand Up @@ -476,7 +502,8 @@ def set_component_params(self, component):
def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:
"""Delete specified fields from build_config."""
for field in fields:
build_config.pop(field, None)
if build_config is not None and field in build_config:
build_config.pop(field, None)

def update_input_types(self, build_config: dotdict) -> dotdict:
"""Update input types for all fields in build_config."""
Expand Down
46 changes: 25 additions & 21 deletions src/lfx/src/lfx/components/ibm/watsonx.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,24 @@ class WatsonxAIComponent(LCModelComponent):
beta = False

_default_models = ["ibm/granite-3-2b-instruct", "ibm/granite-3-8b-instruct", "ibm/granite-13b-instruct-v2"]

_urls = [
"https://us-south.ml.cloud.ibm.com",
"https://eu-de.ml.cloud.ibm.com",
"https://eu-gb.ml.cloud.ibm.com",
"https://au-syd.ml.cloud.ibm.com",
"https://jp-tok.ml.cloud.ibm.com",
"https://ca-tor.ml.cloud.ibm.com",
]
inputs = [
*LCModelComponent.get_base_inputs(),
DropdownInput(
name="url",
name="base_url",
display_name="watsonx API Endpoint",
info="The base URL of the API.",
value=None,
options=[
"https://us-south.ml.cloud.ibm.com",
"https://eu-de.ml.cloud.ibm.com",
"https://eu-gb.ml.cloud.ibm.com",
"https://au-syd.ml.cloud.ibm.com",
"https://jp-tok.ml.cloud.ibm.com",
"https://ca-tor.ml.cloud.ibm.com",
],
value=[],
options=_urls,
real_time_refresh=True,
required=True,
),
StrInput(
name="project_id",
Expand All @@ -56,8 +57,9 @@ class WatsonxAIComponent(LCModelComponent):
display_name="Model Name",
options=[],
value=None,
dynamic=True,
real_time_refresh=True,
required=True,
refresh_button=True,
),
IntInput(
name="max_tokens",
Expand Down Expand Up @@ -155,18 +157,20 @@ def fetch_models(base_url: str) -> list[str]:

def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
"""Update model options when URL or API key changes."""
logger.info("Updating build config. Field name: %s, Field value: %s", field_name, field_value)

if field_name == "url" and field_value:
if field_name == "base_url" and field_value:
try:
models = self.fetch_models(base_url=build_config.url.value)
build_config.model_name.options = models
if build_config.model_name.value:
build_config.model_name.value = models[0]
info_message = f"Updated model options: {len(models)} models found in {build_config.url.value}"
models = self.fetch_models(base_url=field_value)
build_config["model_name"]["options"] = models
if build_config["model_name"]["value"]:
build_config["model_name"]["value"] = models[0]
info_message = f"Updated model options: {len(models)} models found in {field_value}"
logger.info(info_message)
except Exception: # noqa: BLE001
logger.exception("Error updating model options.")
if field_name == "model_name" and field_value and field_value in WatsonxAIComponent._urls:
build_config["model_name"]["options"] = self.fetch_models(base_url=field_value)
build_config["model_name"]["value"] = ""
return build_config

def build_model(self) -> LanguageModel:
# Parse logit_bias from JSON string if provided
Expand Down Expand Up @@ -195,7 +199,7 @@ def build_model(self) -> LanguageModel:

return ChatWatsonx(
apikey=SecretStr(self.api_key).get_secret_value(),
url=self.url,
url=self.base_url,
project_id=self.project_id,
model_id=self.model_name,
params=chat_params,
Expand Down
9 changes: 7 additions & 2 deletions src/lfx/src/lfx/components/ollama/ollama.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,12 @@ class ChatOllamaComponent(LCModelComponent):
name="top_k", display_name="Top K", info="Limits token selection to top K. (Default: 40)", advanced=True
),
FloatInput(name="top_p", display_name="Top P", info="Works together with top-k. (Default: 0.9)", advanced=True),
BoolInput(name="verbose", display_name="Verbose", info="Whether to print out response text.", advanced=True),
BoolInput(
name="enable_verbose_output",
display_name="Ollama Verbose Output",
info="Whether to print out response text.",
advanced=True,
),
MessageTextInput(
name="tags",
display_name="Tags",
Expand Down Expand Up @@ -209,7 +214,7 @@ def build_model(self) -> LanguageModel: # type: ignore[type-var]
"timeout": self.timeout or None,
"top_k": self.top_k or None,
"top_p": self.top_p or None,
"verbose": self.verbose,
"verbose": self.enable_verbose_output or False,
"template": self.template,
}
headers = self.headers
Expand Down
Loading