diff --git a/pyproject.toml b/pyproject.toml index b8a7d44b4..12ba58856 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -119,6 +119,8 @@ dependencies = [ "ruff>=0.9.7", "langchain-graph-retriever==0.6.1", "graph-retriever==0.6.1", + "ibm-watsonx-ai>=1.3.1", + "langchain-ibm>=0.3.8", "opik>=1.6.3", ] diff --git a/src/backend/base/langflow/components/models/__init__.py b/src/backend/base/langflow/components/models/__init__.py index d9bbc391d..415c868c8 100644 --- a/src/backend/base/langflow/components/models/__init__.py +++ b/src/backend/base/langflow/components/models/__init__.py @@ -20,6 +20,7 @@ from .openrouter import OpenRouterComponent from .perplexity import PerplexityComponent from .sambanova import SambaNovaComponent from .vertexai import ChatVertexAIComponent +from .watsonx import WatsonxAIComponent from .xai import XAIModelComponent __all__ = [ @@ -45,5 +46,6 @@ __all__ = [ "PerplexityComponent", "QianfanChatEndpointComponent", "SambaNovaComponent", + "WatsonxAIComponent", "XAIModelComponent", ] diff --git a/src/backend/base/langflow/components/models/watsonx.py b/src/backend/base/langflow/components/models/watsonx.py new file mode 100644 index 000000000..f77fd7b16 --- /dev/null +++ b/src/backend/base/langflow/components/models/watsonx.py @@ -0,0 +1,204 @@ +import json +import logging +from typing import Any + +import requests +from langchain_ibm import ChatWatsonx +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 import BoolInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput +from langflow.schema.dotdict import dotdict + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +class WatsonxAIComponent(LCModelComponent): + display_name = "IBM watsonx.ai" + description = "Generate text using IBM watsonx.ai foundation models." + icon = "WatsonxAI" + name = "IBMwatsonxModel" + beta = False + + _default_models = ["ibm/granite-3-2b-instruct", "ibm/granite-3-8b-instruct", "ibm/granite-13b-instruct-v2"] + + inputs = [ + *LCModelComponent._base_inputs, + DropdownInput( + name="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", + ], + real_time_refresh=True, + ), + StrInput( + name="project_id", + display_name="watsonx Project ID", + ), + SecretStrInput( + name="api_key", + display_name="API Key", + info="The API Key to use for the model.", + required=True, + ), + DropdownInput( + name="model_name", + display_name="Model Name", + options=[], + value=None, + dynamic=True, + required=True, + ), + IntInput( + name="max_tokens", + display_name="Max Tokens", + advanced=True, + info="The maximum number of tokens to generate.", + range_spec=RangeSpec(min=1, max=4096), + value=1000, + ), + StrInput( + name="stop_sequence", + display_name="Stop Sequence", + advanced=True, + info="Sequence where generation should stop.", + field_type="str", + ), + SliderInput( + name="temperature", + display_name="Temperature", + info="Controls randomness, higher values increase diversity.", + value=0.1, + range_spec=RangeSpec(min=0, max=2, step=0.01), + advanced=True, + ), + SliderInput( + name="top_p", + display_name="Top P", + info="The cumulative probability cutoff for token selection. " + "Lower values mean sampling from a smaller, more top-weighted nucleus.", + value=0.9, + range_spec=RangeSpec(min=0, max=1, step=0.01), + advanced=True, + ), + SliderInput( + name="frequency_penalty", + display_name="Frequency Penalty", + info="Penalty for frequency of token usage.", + value=0.5, + range_spec=RangeSpec(min=-2.0, max=2.0, step=0.01), + advanced=True, + ), + SliderInput( + name="presence_penalty", + display_name="Presence Penalty", + info="Penalty for token presence in prior text.", + value=0.3, + range_spec=RangeSpec(min=-2.0, max=2.0, step=0.01), + advanced=True, + ), + IntInput( + name="seed", + display_name="Random Seed", + advanced=True, + info="The random seed for the model.", + value=8, + ), + BoolInput( + name="logprobs", + display_name="Log Probabilities", + advanced=True, + info="Whether to return log probabilities of the output tokens.", + value=True, + ), + IntInput( + name="top_logprobs", + display_name="Top Log Probabilities", + advanced=True, + info="Number of most likely tokens to return at each position.", + value=3, + range_spec=RangeSpec(min=1, max=20), + ), + StrInput( + name="logit_bias", + display_name="Logit Bias", + advanced=True, + info='JSON string of token IDs to bias or suppress (e.g., {"1003": -100, "1004": 100}).', + field_type="str", + ), + ] + + @staticmethod + def fetch_models(base_url: str) -> list[str]: + """Fetch available models from the watsonx.ai API.""" + try: + endpoint = f"{base_url}/ml/v1/foundation_model_specs" + params = {"version": "2024-09-16", "filters": "function_text_chat,!lifecycle_withdrawn"} + response = requests.get(endpoint, params=params, timeout=10) + response.raise_for_status() + data = response.json() + models = [model["model_id"] for model in data.get("resources", [])] + return sorted(models) + except Exception: + logger.exception("Error fetching models. Using default models.") + return WatsonxAIComponent._default_models + + 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: + 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}" + logger.info(info_message) + except Exception: + logger.exception("Error updating model options.") + + def build_model(self) -> LanguageModel: + # Parse logit_bias from JSON string if provided + logit_bias = None + if hasattr(self, "logit_bias") and self.logit_bias: + try: + logit_bias = json.loads(self.logit_bias) + except json.JSONDecodeError: + logger.warning("Invalid logit_bias JSON format. Using default instead.") + logit_bias = {"1003": -100, "1004": -100} + + chat_params = { + "max_tokens": getattr(self, "max_tokens", None), + "temperature": getattr(self, "temperature", None), + "top_p": getattr(self, "top_p", None), + "frequency_penalty": getattr(self, "frequency_penalty", None), + "presence_penalty": getattr(self, "presence_penalty", None), + "seed": getattr(self, "seed", None), + "stop": [self.stop_sequence] if self.stop_sequence else [], + "n": 1, + "logprobs": getattr(self, "logprobs", True), + "top_logprobs": getattr(self, "top_logprobs", None), + "time_limit": 600000, + "logit_bias": logit_bias, + } + + return ChatWatsonx( + apikey=SecretStr(self.api_key).get_secret_value(), + url=self.url, + project_id=self.project_id, + model_id=self.model_name, + params=chat_params, + streaming=self.stream, + ) diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json index 91e2df3d8..0190cbe7e 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json @@ -9,21 +9,25 @@ "dataType": "ChatInput", "id": "ChatInput-4lamw", "name": "message", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "input_value", "id": "Agent-I23ZV", - "inputTypes": ["Message"], + "inputTypes": [ + "Message" + ], "type": "str" } }, "id": "reactflow__edge-ChatInput-4lamw{œdataTypeœ:œChatInputœ,œidœ:œChatInput-4lamwœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-I23ZV{œfieldNameœ:œinput_valueœ,œidœ:œAgent-I23ZVœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, "source": "ChatInput-4lamw", - "sourceHandle": "{œdataTypeœ:œChatInputœ,œidœ:œChatInput-4lamwœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-4lamwœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", "target": "Agent-I23ZV", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œAgent-I23ZVœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}" + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-I23ZVœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -33,21 +37,27 @@ "dataType": "Agent", "id": "Agent-I23ZV", "name": "response", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "input_value", "id": "ChatOutput-MBTWS", - "inputTypes": ["Data", "DataFrame", "Message"], + "inputTypes": [ + "Data", + "DataFrame", + "Message" + ], "type": "str" } }, "id": "reactflow__edge-Agent-I23ZV{œdataTypeœ:œAgentœ,œidœ:œAgent-I23ZVœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-MBTWS{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-MBTWSœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", "selected": false, "source": "Agent-I23ZV", - "sourceHandle": "{œdataTypeœ:œAgentœ,œidœ:œAgent-I23ZVœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-I23ZVœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", "target": "ChatOutput-MBTWS", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-MBTWSœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}" + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-MBTWSœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" }, { "data": { @@ -55,20 +65,24 @@ "dataType": "APIRequest", "id": "APIRequest-zDdGN", "name": "component_as_tool", - "output_types": ["Tool"] + "output_types": [ + "Tool" + ] }, "targetHandle": { "fieldName": "tools", "id": "Agent-I23ZV", - "inputTypes": ["Tool"], + "inputTypes": [ + "Tool" + ], "type": "other" } }, "id": "xy-edge__APIRequest-zDdGN{œdataTypeœ:œAPIRequestœ,œidœ:œAPIRequest-zDdGNœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-I23ZV{œfieldNameœ:œtoolsœ,œidœ:œAgent-I23ZVœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "source": "APIRequest-zDdGN", - "sourceHandle": "{œdataTypeœ:œAPIRequestœ,œidœ:œAPIRequest-zDdGNœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}", + "sourceHandle": "{œdataTypeœ: œAPIRequestœ, œidœ: œAPIRequest-zDdGNœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", "target": "Agent-I23ZV", - "targetHandle": "{œfieldNameœ:œtoolsœ,œidœ:œAgent-I23ZVœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}" + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-I23ZVœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" } ], "nodes": [ @@ -76,7 +90,9 @@ "data": { "id": "ChatInput-4lamw", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "category": "inputs", "conditional_paths": [], @@ -113,7 +129,9 @@ "name": "message", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -127,7 +145,9 @@ "display_name": "Background Color", "dynamic": false, "info": "The background color of the icon.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -148,7 +168,9 @@ "display_name": "Icon", "dynamic": false, "info": "The icon of the message.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -256,7 +278,10 @@ "dynamic": false, "info": "Type of sender.", "name": "sender", - "options": ["Machine", "User"], + "options": [ + "Machine", + "User" + ], "options_metadata": [], "placeholder": "", "required": false, @@ -273,7 +298,9 @@ "display_name": "Sender Name", "dynamic": false, "info": "Name of the sender.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -294,7 +321,9 @@ "display_name": "Session ID", "dynamic": false, "info": "The session ID of the chat. If empty, the current session ID parameter will be used.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -333,7 +362,9 @@ "display_name": "Text Color", "dynamic": false, "info": "The text color of the name", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -371,7 +402,9 @@ "data": { "id": "ChatOutput-MBTWS", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "category": "outputs", "conditional_paths": [], @@ -408,7 +441,9 @@ "name": "message", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -422,7 +457,9 @@ "display_name": "Background Color", "dynamic": false, "info": "The background color of the icon.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -443,7 +480,9 @@ "display_name": "Icon", "dynamic": false, "info": "The icon of the message.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -500,7 +539,9 @@ "display_name": "Data Template", "dynamic": false, "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -521,7 +562,11 @@ "display_name": "Text", "dynamic": false, "info": "Message to be passed as output.", - "input_types": ["Data", "DataFrame", "Message"], + "input_types": [ + "Data", + "DataFrame", + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -545,7 +590,10 @@ "dynamic": false, "info": "Type of sender.", "name": "sender", - "options": ["Machine", "User"], + "options": [ + "Machine", + "User" + ], "options_metadata": [], "placeholder": "", "required": false, @@ -562,7 +610,9 @@ "display_name": "Sender Name", "dynamic": false, "info": "Name of the sender.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -583,7 +633,9 @@ "display_name": "Session ID", "dynamic": false, "info": "The session ID of the chat. If empty, the current session ID parameter will be used.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -622,7 +674,9 @@ "display_name": "Text Color", "dynamic": false, "info": "The text color of the name", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -744,7 +798,9 @@ "data": { "id": "Agent-I23ZV", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "category": "agents", "conditional_paths": [], @@ -797,7 +853,9 @@ "name": "response", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -830,7 +888,9 @@ "display_name": "Agent Description [Deprecated]", "dynamic": false, "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -912,7 +972,9 @@ "display_name": "OpenAI API Key", "dynamic": false, "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "load_from_db": true, "name": "api_key", "password": true, @@ -965,7 +1027,9 @@ "display_name": "Input", "dynamic": false, "info": "The input provided by the user for the agent to process.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1064,7 +1128,9 @@ "display_name": "External Memory", "dynamic": false, "info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.", - "input_types": ["Memory"], + "input_types": [ + "Memory" + ], "list": false, "list_add_label": "Add More", "name": "memory", @@ -1169,7 +1235,10 @@ "dynamic": false, "info": "Order of the messages.", "name": "order", - "options": ["Ascending", "Descending"], + "options": [ + "Ascending", + "Descending" + ], "options_metadata": [], "placeholder": "", "required": false, @@ -1207,7 +1276,11 @@ "dynamic": false, "info": "Filter by sender type.", "name": "sender", - "options": ["Machine", "User", "Machine and User"], + "options": [ + "Machine", + "User", + "Machine and User" + ], "options_metadata": [], "placeholder": "", "required": false, @@ -1224,7 +1297,9 @@ "display_name": "Sender Name", "dynamic": false, "info": "Filter by sender name.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1245,7 +1320,9 @@ "display_name": "Session ID", "dynamic": false, "info": "The session ID of the chat. If empty, the current session ID parameter will be used.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1267,7 +1344,9 @@ "display_name": "Agent Instructions", "dynamic": false, "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1318,7 +1397,9 @@ "display_name": "Template", "dynamic": false, "info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1358,7 +1439,9 @@ "display_name": "Tools", "dynamic": false, "info": "These are the tools that the agent can use to help with tasks.", - "input_types": ["Tool"], + "input_types": [ + "Tool" + ], "list": true, "list_add_label": "Add More", "name": "tools", @@ -1410,7 +1493,10 @@ "data": { "id": "APIRequest-zDdGN", "node": { - "base_classes": ["Data", "DataFrame"], + "base_classes": [ + "Data", + "DataFrame" + ], "beta": false, "category": "data", "conditional_paths": [], @@ -1451,7 +1537,9 @@ "required_inputs": null, "selected": "Tool", "tool_mode": true, - "types": ["Tool"], + "types": [ + "Tool" + ], "value": "__UNDEFINED__" } ], @@ -1465,7 +1553,9 @@ "display_name": "Body", "dynamic": false, "info": "The body to send with the request as a dictionary (for POST, PATCH, PUT).", - "input_types": ["Data"], + "input_types": [ + "Data" + ], "is_list": true, "list_add_label": "Add More", "name": "body", @@ -1534,7 +1624,9 @@ "display_name": "cURL", "dynamic": false, "info": "Paste a curl command to populate the fields. This will fill in the dictionary fields for headers and body.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1575,7 +1667,9 @@ "display_name": "Headers", "dynamic": false, "info": "The headers to send with the request as a dictionary.", - "input_types": ["Data"], + "input_types": [ + "Data" + ], "is_list": true, "list_add_label": "Add More", "name": "headers", @@ -1648,7 +1742,13 @@ "dynamic": false, "info": "The HTTP method to use.", "name": "method", - "options": ["GET", "POST", "PATCH", "PUT", "DELETE"], + "options": [ + "GET", + "POST", + "PATCH", + "PUT", + "DELETE" + ], "options_metadata": [], "placeholder": "", "real_time_refresh": true, @@ -1666,7 +1766,9 @@ "display_name": "Query Parameters", "dynamic": false, "info": "The query parameters to append to the URL.", - "input_types": ["Data"], + "input_types": [ + "Data" + ], "list": false, "list_add_label": "Add More", "name": "query_params", @@ -1741,7 +1843,10 @@ "description": "Modify tool names and descriptions to help agents understand when to use each tool.", "field_parsers": { "commands": "commands", - "name": ["snake_case", "no_blank"] + "name": [ + "snake_case", + "no_blank" + ] }, "hide_options": true }, @@ -1812,13 +1917,17 @@ "description": "make_requests() - Make HTTP requests using URLs or cURL commands.", "name": "APIRequest-make_requests", "status": true, - "tags": ["APIRequest-make_requests"] + "tags": [ + "APIRequest-make_requests" + ] }, { "description": "as_dataframe() - Make HTTP requests using URLs or cURL commands.", "name": "APIRequest-as_dataframe", "status": true, - "tags": ["APIRequest-as_dataframe"] + "tags": [ + "APIRequest-as_dataframe" + ] } ] }, @@ -1828,7 +1937,9 @@ "display_name": "URLs", "dynamic": false, "info": "Enter one or more URLs, separated by commas.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": true, "list_add_label": "Add More", "load_from_db": false, @@ -1894,5 +2005,7 @@ "is_component": false, "last_tested_version": "1.2.0", "name": "Pokédex Agent", - "tags": ["agents"] -} + "tags": [ + "agents" + ] +} \ No newline at end of file diff --git a/src/backend/base/pyproject.toml b/src/backend/base/pyproject.toml index ea95f26be..eae08e0a6 100644 --- a/src/backend/base/pyproject.toml +++ b/src/backend/base/pyproject.toml @@ -86,6 +86,8 @@ dependencies = [ "elevenlabs>=1.54.0", "webrtcvad>=2.0.10", "scipy>=1.15.2", + "ibm-watsonx-ai>=1.3.1", + "langchain-ibm>=0.3.8", ] [dependency-groups] diff --git a/src/frontend/src/icons/IBMWatsonx/WatsonxAI.jsx b/src/frontend/src/icons/IBMWatsonx/WatsonxAI.jsx new file mode 100644 index 000000000..286800e79 --- /dev/null +++ b/src/frontend/src/icons/IBMWatsonx/WatsonxAI.jsx @@ -0,0 +1,21 @@ +const SvgWatsonxAI = (props) => ( + + + + + + +); +export default SvgWatsonxAI; diff --git a/src/frontend/src/icons/IBMWatsonx/index.tsx b/src/frontend/src/icons/IBMWatsonx/index.tsx new file mode 100644 index 000000000..ef44b8d01 --- /dev/null +++ b/src/frontend/src/icons/IBMWatsonx/index.tsx @@ -0,0 +1,9 @@ +import React, { forwardRef } from "react"; +import SvgWatsonxAI from "./WatsonxAI"; + +export const WatsonxAiIcon = forwardRef< + SVGSVGElement, + React.PropsWithChildren<{}> +>((props, ref) => { + return ; +}); diff --git a/src/frontend/src/icons/IBMWatsonx/watsonx-ai.svg b/src/frontend/src/icons/IBMWatsonx/watsonx-ai.svg new file mode 100644 index 000000000..997f796fa --- /dev/null +++ b/src/frontend/src/icons/IBMWatsonx/watsonx-ai.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index d2676bb23..c490c7ca1 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -296,6 +296,7 @@ import { import { GroqIcon } from "../icons/Groq"; import { HCDIcon } from "../icons/HCD"; import { HuggingFaceIcon } from "../icons/HuggingFace"; +import { WatsonxAiIcon } from "../icons/IBMWatsonx"; import { IFixIcon } from "../icons/IFixIt"; import { IcosaIcon } from "../icons/Icosa"; import { LMStudioIcon } from "../icons/LMStudio"; @@ -757,6 +758,7 @@ export const nodeIconsLucide: iconsType = { VertexAI: VertexAIIcon, ChatVertexAI: VertexAIIcon, VertexAIEmbeddings: VertexAIIcon, + WatsonxAI: WatsonxAiIcon, Share3: ShareIcon, Share4: Share2Icon, WikipediaAPIWrapper: SvgWikipedia, diff --git a/uv.lock b/uv.lock index 48c772358..299161570 100644 --- a/uv.lock +++ b/uv.lock @@ -512,7 +512,7 @@ wheels = [ [[package]] name = "auth0-python" -version = "4.8.1" +version = "4.7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -521,9 +521,9 @@ dependencies = [ { name = "requests" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/27/ca/c5d5aef3599d143b3fa5203be850542ee54e3798392fb80bd3126fd865e2/auth0_python-4.8.1.tar.gz", hash = "sha256:2d46027296a5e6d7c28f2ef1cc3d9b5705f3978de3622a744dabf36b39d53342", size = 74876 } +sdist = { url = "https://files.pythonhosted.org/packages/12/81/3e867262f1f48fdacb1f8e9853497f6283274ba2c3c145e767bc0c7ed3c8/auth0_python-4.7.2.tar.gz", hash = "sha256:5d36b7f26defa946c0a548dddccf0451fc62e9f8e61fd0138c5025ad2506ba8b", size = 73261 } wheels = [ - { url = "https://files.pythonhosted.org/packages/27/70/0025c8f763ece48b9dbffe22b68f843f1cd43a6324ee9f95e94a1d3e4d6c/auth0_python-4.8.1-py3-none-any.whl", hash = "sha256:ac2fea3cba4dc186b2f01a953a08db5f38a543255c19e9298fef4755fe5f9716", size = 134260 }, + { url = "https://files.pythonhosted.org/packages/e4/0e/38cb7b781371e79e9c697fb78f3ccd18fda8bd547d0a2e76e616561a3792/auth0_python-4.7.2-py3-none-any.whl", hash = "sha256:df2224f9b1e170b3aa12d8bc7ff02eadb7cc229307a09ec6b8a55fd1e0e05dc8", size = 131834 }, ] [[package]] @@ -3402,6 +3402,59 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8d/7c/7266143385cbd19c839f9b61cc660d74c5ce2626fea41d8b215ccc5cfba3/hypothesis-6.129.4-py3-none-any.whl", hash = "sha256:45a31fe2b936688b2954f375c7f87e9dfefa4f2cddfa31cdeba15d77600e1286", size = 489542 }, ] +[[package]] +name = "ibm-cos-sdk" +version = "2.13.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ibm-cos-sdk-core" }, + { name = "ibm-cos-sdk-s3transfer" }, + { name = "jmespath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/e6/908791df6fd31d94e80be9597242eac2b942c28b0d4ea1fc6b963d4a6be3/ibm-cos-sdk-2.13.5.tar.gz", hash = "sha256:1aff7f9863ac9072a3db2f0053bec99478b26f3fb5fa797ce96a15bbb13cd40e", size = 58638 } + +[[package]] +name = "ibm-cos-sdk-core" +version = "2.13.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "requests" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/ff/cabdf3d7892c3607297ffb7d77c3caafe2f50f876d29e90c44ac67495cef/ibm-cos-sdk-core-2.13.5.tar.gz", hash = "sha256:d3a99d8b06b3f8c00b1a9501f85538d592463e63ddf8cec32672ab5a0b107b83", size = 1101815 } + +[[package]] +name = "ibm-cos-sdk-s3transfer" +version = "2.13.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ibm-cos-sdk-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/42/f2faefd0c3360928336b93a14db2aff25f556aa50252188efd1ba363e371/ibm-cos-sdk-s3transfer-2.13.5.tar.gz", hash = "sha256:9649b1f2201c6de96ff5a6b5a3686de3a809e6ef3b8b12c7c4f2f7ce72da7749", size = 139491 } + +[[package]] +name = "ibm-watsonx-ai" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "httpx" }, + { name = "ibm-cos-sdk" }, + { name = "importlib-metadata" }, + { name = "lomond" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "requests" }, + { name = "tabulate" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/71/fad93b14427faa0cf95a08f033c3ef29aeac6c2718ea8adae9ebe306e706/ibm_watsonx_ai-1.3.1.tar.gz", hash = "sha256:d32668fbd9a1308f355ee372d3dcc929eadc7f9c1e00a8549d37e9d144a3ddab", size = 693398 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/ab/d1d76b874ad5d0ede9cddaefd3ed0118d6fd3a9e4c571c05b3497417d810/ibm_watsonx_ai-1.3.1-py3-none-any.whl", hash = "sha256:62fa1d4dfd62a7d8013cabf7999f5e0144b502d97a51bccb5c3dbeffc6918ee7", size = 1074052 }, +] + [[package]] name = "identify" version = "2.6.9" @@ -4266,6 +4319,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e3/ed/bf857c2857a7aa1f9b1d436c668a3f1a4071cb2bb6f1d247f98f1ebb3f0a/langchain_groq-0.2.1-py3-none-any.whl", hash = "sha256:98d282fd9d7d99b0f55de0a1daea2d5d350ef697e3cb5e97de06aeba4eca8679", size = 14331 }, ] +[[package]] +name = "langchain-ibm" +version = "0.3.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ibm-watsonx-ai" }, + { name = "langchain-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/1d/a0d5a535beb722dc8275a30e7db9b23938e0a074069cc7d4093507a5bd4f/langchain_ibm-0.3.8.tar.gz", hash = "sha256:b8e606f1581c2bed9a078bae6335f2f70b6f9b25e07736b61f763966be3405bc", size = 23015 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/7d/dc4db1613c2aa53528205a4cd2286720fda92478686f186414e651326c73/langchain_ibm-0.3.8-py3-none-any.whl", hash = "sha256:a3eb4465a50c59aa8f7253d2b500e4cf303c7e2bf6358487def9732abb51a5db", size = 27476 }, +] + [[package]] name = "langchain-milvus" version = "0.1.7" @@ -4466,6 +4532,7 @@ dependencies = [ { name = "google-search-results" }, { name = "graph-retriever" }, { name = "huggingface-hub", extra = ["inference"] }, + { name = "ibm-watsonx-ai" }, { name = "jq" }, { name = "json-repair" }, { name = "kubernetes" }, @@ -4483,6 +4550,7 @@ dependencies = [ { name = "langchain-google-vertexai" }, { name = "langchain-graph-retriever" }, { name = "langchain-groq" }, + { name = "langchain-ibm" }, { name = "langchain-milvus" }, { name = "langchain-mistralai" }, { name = "langchain-mongodb" }, @@ -4653,6 +4721,7 @@ requires-dist = [ { name = "google-search-results", specifier = ">=2.4.1,<3.0.0" }, { name = "graph-retriever", specifier = "==0.6.1" }, { name = "huggingface-hub", extras = ["inference"], specifier = ">=0.23.2,<1.0.0" }, + { name = "ibm-watsonx-ai", specifier = ">=1.3.1" }, { name = "jq", specifier = "==1.8.0" }, { name = "json-repair", specifier = "==0.30.3" }, { name = "kubernetes", specifier = "==31.0.0" }, @@ -4670,6 +4739,7 @@ requires-dist = [ { name = "langchain-google-vertexai", specifier = "==2.0.7" }, { name = "langchain-graph-retriever", specifier = "==0.6.1" }, { name = "langchain-groq", specifier = "==0.2.1" }, + { name = "langchain-ibm", specifier = ">=0.3.8" }, { name = "langchain-milvus", specifier = "==0.1.7" }, { name = "langchain-mistralai", specifier = "==0.2.3" }, { name = "langchain-mongodb", specifier = "==0.2.0" }, @@ -4816,6 +4886,7 @@ dependencies = [ { name = "greenlet" }, { name = "gunicorn" }, { name = "httpx", extra = ["http2"] }, + { name = "ibm-watsonx-ai" }, { name = "jq", marker = "sys_platform != 'win32'" }, { name = "json-repair" }, { name = "jsonquerylang" }, @@ -4823,6 +4894,7 @@ dependencies = [ { name = "langchain-community" }, { name = "langchain-core" }, { name = "langchain-experimental" }, + { name = "langchain-ibm" }, { name = "langchainhub" }, { name = "loguru" }, { name = "mcp" }, @@ -4956,6 +5028,7 @@ requires-dist = [ { name = "greenlet", specifier = ">=3.1.1" }, { name = "gunicorn", specifier = ">=22.0.0,<24.0.0" }, { name = "httpx", extras = ["http2"], specifier = ">=0.27,<1.0.0" }, + { name = "ibm-watsonx-ai", specifier = ">=1.3.1" }, { name = "jq", marker = "sys_platform != 'win32'", specifier = ">=1.7.0,<2.0.0" }, { name = "json-repair", specifier = ">=0.30.3" }, { name = "jsonquerylang", specifier = ">=1.1.1" }, @@ -4963,6 +5036,7 @@ requires-dist = [ { name = "langchain-community", specifier = "~=0.3.10" }, { name = "langchain-core", specifier = "~=0.3.15" }, { name = "langchain-experimental", specifier = ">=0.0.61,<1.0.0" }, + { name = "langchain-ibm", specifier = ">=0.3.8" }, { name = "langchainhub", specifier = "~=0.1.15" }, { name = "llama-cpp-python", marker = "extra == 'all'", specifier = ">=0.2.0" }, { name = "llama-cpp-python", marker = "extra == 'local'", specifier = ">=0.2.0" }, @@ -5361,6 +5435,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595 }, ] +[[package]] +name = "lomond" +version = "0.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/9e/ef7813c910d4a893f2bc763ce9246269f55cc68db21dc1327e376d6a2d02/lomond-0.3.3.tar.gz", hash = "sha256:427936596b144b4ec387ead99aac1560b77c8a78107d3d49415d3abbe79acbd3", size = 28789 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/b1/02eebed49c754b01b17de7705caa8c4ceecfb4f926cdafc220c863584360/lomond-0.3.3-py2.py3-none-any.whl", hash = "sha256:df1dd4dd7b802a12b71907ab1abb08b8ce9950195311207579379eb3b1553de7", size = 35512 }, +] + [[package]] name = "lsprotocol" version = "2023.0.1" @@ -10197,11 +10283,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.3.0" +version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } +sdist = { url = "https://files.pythonhosted.org/packages/36/dd/a6b232f449e1bc71802a5b7950dc3675d32c6dbc2a1bd6d71f065551adb6/urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54", size = 263900 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, + { url = "https://files.pythonhosted.org/packages/96/94/c31f58c7a7f470d5665935262ebd7455c7e4c7782eb525658d3dbf4b9403/urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3", size = 104579 }, ] [[package]]