diff --git a/clientlibs/utils.js b/clientlibs/utils.js index fe06b2d..7dd3ecc 100644 --- a/clientlibs/utils.js +++ b/clientlibs/utils.js @@ -1337,7 +1337,7 @@ function textInferenceSettingsToggleHandler(settingsNode) { if (!settingsNode?.widgets) return; const useSystemPromptWidget = settingsNode.widgets.find(w => w && w.name === "useSystemPrompt"); - const systemWidget = settingsNode.widgets.find(w => w && (w.name === "systemPrompt" || w.name === "system")); + const systemWidget = settingsNode.widgets.find(w => w && w.name === "system"); const useMaxTokensWidget = settingsNode.widgets.find(w => w && w.name === "useMaxTokens"); const maxTokensWidget = settingsNode.widgets.find(w => w && w.name === "maxTokens"); const useTemperatureWidget = settingsNode.widgets.find(w => w && w.name === "useTemperature"); @@ -1346,16 +1346,6 @@ function textInferenceSettingsToggleHandler(settingsNode) { const topPWidget = settingsNode.widgets.find(w => w && w.name === "topP"); const useTopKWidget = settingsNode.widgets.find(w => w && w.name === "useTopK"); const topKWidget = settingsNode.widgets.find(w => w && w.name === "topK"); - const useStopSequencesWidget = settingsNode.widgets.find(w => w && w.name === "useStopSequences"); - const stopSequencesWidget = settingsNode.widgets.find(w => w && w.name === "stopSequences"); - const usePresencePenaltyWidget = settingsNode.widgets.find(w => w && w.name === "usePresencePenalty"); - const presencePenaltyWidget = settingsNode.widgets.find(w => w && w.name === "presencePenalty"); - const useFrequencyPenaltyWidget = settingsNode.widgets.find(w => w && w.name === "useFrequencyPenalty"); - const frequencyPenaltyWidget = settingsNode.widgets.find(w => w && w.name === "frequencyPenalty"); - const useToolsWidget = settingsNode.widgets.find(w => w && w.name === "useTools"); - const toolsWidget = settingsNode.widgets.find(w => w && w.name === "tools"); - const useToolChoiceWidget = settingsNode.widgets.find(w => w && w.name === "useToolChoice"); - const toolChoiceWidget = settingsNode.widgets.find(w => w && w.name === "toolChoice"); function toggleWidgetState(useWidget, paramWidget) { if (!useWidget || !paramWidget) return; @@ -1378,11 +1368,6 @@ function textInferenceSettingsToggleHandler(settingsNode) { if (useTemperatureWidget && temperatureWidget) toggleWidgetState(useTemperatureWidget, temperatureWidget); if (useTopPWidget && topPWidget) toggleWidgetState(useTopPWidget, topPWidget); if (useTopKWidget && topKWidget) toggleWidgetState(useTopKWidget, topKWidget); - if (useStopSequencesWidget && stopSequencesWidget) toggleWidgetState(useStopSequencesWidget, stopSequencesWidget); - if (usePresencePenaltyWidget && presencePenaltyWidget) toggleWidgetState(usePresencePenaltyWidget, presencePenaltyWidget); - if (useFrequencyPenaltyWidget && frequencyPenaltyWidget) toggleWidgetState(useFrequencyPenaltyWidget, frequencyPenaltyWidget); - if (useToolsWidget && toolsWidget) toggleWidgetState(useToolsWidget, toolsWidget); - if (useToolChoiceWidget && toolChoiceWidget) toggleWidgetState(useToolChoiceWidget, toolChoiceWidget); } function videoSettingsToggleHandler(settingsNode) { @@ -3062,9 +3047,6 @@ function textModelSearchFilterHandler(textModelSearchNode) { "Google": [ "google:gemini@3-flash (Gemini 3 Flash)", ], - "Zai": [ - "zai-glm-5-1 (ZAI GLM 5.1)", - ], }; function filterModelList() { diff --git a/modules/textInferenceSettings.py b/modules/textInferenceSettings.py index 7cc977b..4725e5b 100644 --- a/modules/textInferenceSettings.py +++ b/modules/textInferenceSettings.py @@ -1,15 +1,11 @@ -import json -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, Tuple class RunwareTextInferenceSettings: """Optional generation controls for Runware Text Inference (flat task.settings per API).""" _MAX_SYSTEM_CHARS = 200000 - _MAX_TOKENS_CAP = 131072 - _MAX_TOP_K = 100647 - _MAX_STOP_ITEMS = 5 - _MAX_STOP_ITEM_CHARS = 50 + _MAX_TOKENS_CAP = 196608 @classmethod def INPUT_TYPES(cls): @@ -20,17 +16,17 @@ class RunwareTextInferenceSettings: "default": False, "tooltip": "Include systemPrompt in settings.", }), - "systemPrompt": ("STRING", { + "system": ("STRING", { "multiline": True, "default": "", - "tooltip": "System instruction (max 200,000 chars).", + "tooltip": "System instruction (max 200,000 characters). Sent as systemPrompt.", }), "useMaxTokens": ("BOOLEAN", { "default": False, "tooltip": "Include maxTokens in settings.", }), "maxTokens": ("INT", { - "default": 4096, + "default": 32768, "min": 1, "max": cls._MAX_TOKENS_CAP, "step": 1, @@ -42,21 +38,21 @@ class RunwareTextInferenceSettings: }), "temperature": ("FLOAT", { "default": 1.0, - "min": 0.0, + "min": 0.01, "max": 1.0, "step": 0.01, - "tooltip": "Sampling temperature (0.0–1.0).", + "tooltip": "Sampling temperature on (0, 1].", }), "useTopP": ("BOOLEAN", { "default": False, "tooltip": "Include topP in settings.", }), "topP": ("FLOAT", { - "default": 1.0, - "min": 0.01, + "default": 0.95, + "min": 0.0, "max": 1.0, "step": 0.01, - "tooltip": "Nucleus sampling (0.01–1.0).", + "tooltip": "Nucleus sampling (0.0–1.0).", }), "useTopK": ("BOOLEAN", { "default": False, @@ -65,62 +61,13 @@ class RunwareTextInferenceSettings: "topK": ("INT", { "default": 40, "min": 1, - "max": cls._MAX_TOP_K, + "max": 128, "step": 1, - "tooltip": f"Top-k sampling (1–{cls._MAX_TOP_K}).", + "tooltip": "Top-k sampling (1–128).", }), - "useStopSequences": ("BOOLEAN", { - "default": False, - "tooltip": "Include stopSequences in settings.", - }), - "stopSequences": ("STRING", { - "multiline": True, - "default": "", - "tooltip": "Stop sequences: one per line (max 5 items, 50 chars each).", - }), - "usePresencePenalty": ("BOOLEAN", { - "default": False, - "tooltip": "Include presencePenalty in settings.", - }), - "presencePenalty": ("FLOAT", { - "default": 0.0, - "min": -2.0, - "max": 2.0, - "step": 0.01, - "tooltip": "Presence penalty (-2.0 to 2.0).", - }), - "useFrequencyPenalty": ("BOOLEAN", { - "default": False, - "tooltip": "Include frequencyPenalty in settings.", - }), - "frequencyPenalty": ("FLOAT", { - "default": 0.0, - "min": -2.0, - "max": 2.0, - "step": 0.01, - "tooltip": "Frequency penalty (-2.0 to 2.0).", - }), - "useTools": ("BOOLEAN", { - "default": False, - "tooltip": "Include tools in settings.", - }), - "tools": ("STRING", { - "multiline": True, - "default": "[]", - "tooltip": "JSON array for tools.", - }), - "useToolChoice": ("BOOLEAN", { - "default": False, - "tooltip": "Include toolChoice in settings.", - }), - "toolChoice": ("STRING", { - "multiline": True, - "default": "{}", - "tooltip": "JSON object for toolChoice.", - }), - "thinkingLevel": (["none", "low", "medium", "high"], { - "default": "none", - "tooltip": "Extended reasoning level: none, low, medium, high.", + "thinkingLevel": (["off", "minimal", "low", "medium", "high"], { + "default": "off", + "tooltip": "thinkingLevel in settings (omit when off).", }), }, } @@ -130,102 +77,34 @@ class RunwareTextInferenceSettings: FUNCTION = "create_settings" CATEGORY = "Runware/Text" DESCRIPTION = ( - "Optional text inference settings (systemPrompt, maxTokens, temperature, topP, topK, " - "stopSequences, presencePenalty, frequencyPenalty, tools, toolChoice, thinkingLevel). " + "Optional text inference settings (flat: systemPrompt, maxTokens, temperature, topP, topK, thinkingLevel). " "Connect to Runware Text Inference." ) - @staticmethod - def _parse_json_setting(raw: Any, expected_type: type, field_name: str) -> Any: - if isinstance(raw, expected_type): - return raw - if raw is None: - return expected_type() - - text = str(raw).strip() - if not text: - return expected_type() - - try: - parsed = json.loads(text) - except Exception as exc: - raise Exception(f"{field_name} must be valid JSON.") from exc - - if not isinstance(parsed, expected_type): - expected = "array" if expected_type is list else "object" - raise Exception(f"{field_name} must be a JSON {expected}.") - return parsed - - def _parse_stop_sequences(self, raw: Any) -> List[str]: - if raw is None: - return [] - - items: List[str] = [] - if isinstance(raw, (list, tuple)): - for item in raw: - text = str(item).strip() - if text: - items.append(text) - else: - text = str(raw).strip() - if text: - normalized = text.replace("\r\n", "\n").replace(",", "\n") - items = [segment.strip() for segment in normalized.split("\n") if segment.strip()] - - if len(items) > self._MAX_STOP_ITEMS: - raise Exception(f"stopSequences supports up to {self._MAX_STOP_ITEMS} items.") - for idx, item in enumerate(items, start=1): - if len(item) > self._MAX_STOP_ITEM_CHARS: - raise Exception( - f"stopSequences item {idx} exceeds {self._MAX_STOP_ITEM_CHARS} characters." - ) - return items - def create_settings(self, **kwargs) -> Tuple[Dict[str, Any], ...]: out: Dict[str, Any] = {} if kwargs.get("useSystemPrompt", False): - sys_text = (kwargs.get("systemPrompt") or kwargs.get("system") or "").strip() + sys_text = (kwargs.get("system") or "").strip() if sys_text: if len(sys_text) > self._MAX_SYSTEM_CHARS: sys_text = sys_text[: self._MAX_SYSTEM_CHARS] out["systemPrompt"] = sys_text if kwargs.get("useMaxTokens", False): - out["maxTokens"] = int(kwargs.get("maxTokens", 4096)) + out["maxTokens"] = int(kwargs.get("maxTokens", 32768)) if kwargs.get("useTemperature", False): out["temperature"] = float(kwargs.get("temperature", 1.0)) if kwargs.get("useTopP", False): - out["topP"] = float(kwargs.get("topP", 1.0)) + out["topP"] = float(kwargs.get("topP", 0.95)) if kwargs.get("useTopK", False): out["topK"] = int(kwargs.get("topK", 40)) - if kwargs.get("useStopSequences", False): - parsed_stop = self._parse_stop_sequences(kwargs.get("stopSequences", "")) - if parsed_stop: - out["stopSequences"] = parsed_stop - - if kwargs.get("usePresencePenalty", False): - out["presencePenalty"] = float(kwargs.get("presencePenalty", 0.0)) - - if kwargs.get("useFrequencyPenalty", False): - out["frequencyPenalty"] = float(kwargs.get("frequencyPenalty", 0.0)) - - if kwargs.get("useTools", False): - parsed_tools = self._parse_json_setting(kwargs.get("tools"), list, "tools") - if parsed_tools: - out["tools"] = parsed_tools - - if kwargs.get("useToolChoice", False): - parsed_choice = self._parse_json_setting(kwargs.get("toolChoice"), dict, "toolChoice") - if parsed_choice: - out["toolChoice"] = parsed_choice - - tl = kwargs.get("thinkingLevel", "none") - if tl != "none": + tl = kwargs.get("thinkingLevel", "off") + if tl != "off": out["thinkingLevel"] = tl if not out: diff --git a/modules/textModelSearch.py b/modules/textModelSearch.py index d81e7ed..46c6e93 100644 --- a/modules/textModelSearch.py +++ b/modules/textModelSearch.py @@ -16,9 +16,6 @@ class RunwareTextModelSearch: "Google": [ "google:gemini@3-flash (Gemini 3 Flash)", ], - "Zai": [ - "zai-glm-5-1 (ZAI GLM 5.1)", - ], } MODEL_PROVIDERS = [ @@ -26,7 +23,6 @@ class RunwareTextModelSearch: "Google", "MiniMax", "OpenAI", - "Zai", ] @classmethod diff --git a/modules/utils/runwareUtils.py b/modules/utils/runwareUtils.py index 75ba920..0c97b0f 100644 --- a/modules/utils/runwareUtils.py +++ b/modules/utils/runwareUtils.py @@ -158,7 +158,7 @@ def getCustomEndpoint(): custom_endpoint = os.getenv("RUNWARE_CUSTOM_ENDPOINT") if custom_endpoint and isinstance(custom_endpoint, str): return custom_endpoint - return "https://api.runware.dev/v1" + return "https://api.runware.ai/v1" SESSION_TIMEOUT = getTimeout() RUNWARE_API_KEY = getAPIKey() diff --git a/workflows/Runware_Text_Inference_GLM_5_1.json b/workflows/Runware_Text_Inference_GLM_5_1.json deleted file mode 100644 index 893030b..0000000 --- a/workflows/Runware_Text_Inference_GLM_5_1.json +++ /dev/null @@ -1 +0,0 @@ -{"id":"f1dab8a9-11a7-4fa3-9a3b-35351c84a964","revision":0,"last_node_id":10,"last_link_id":6,"nodes":[{"id":1,"type":"Runware Text Inference","pos":[497.6562194824219,734.759521484375],"size":[270,122],"flags":{},"order":4,"mode":0,"inputs":[{"localized_name":"model","name":"model","type":"RUNWARETEXTMODEL","link":1},{"localized_name":"messages","name":"messages","type":"RUNWARETEXTINFERENCEMESSAGES","link":4},{"localized_name":"settings","name":"settings","shape":7,"type":"RUNWARETEXTINFERENCESETTINGS","link":6},{"localized_name":"providerSettings","name":"providerSettings","shape":7,"type":"RUNWAREPROVIDERSETTINGS","link":null}],"outputs":[{"localized_name":"text","name":"text","type":"STRING","links":[2]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"6d47a67b859745d5a86f463d8edfd7da0d1cfa6b","Node name for S&R":"Runware Text Inference"},"widgets_values":[],"bgcolor":"#5345bf"},{"id":5,"type":"Runware Text Inference Messages","pos":[503.0782165527344,919.4880981445312],"size":[255.45077514648438,166],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"Message Segment 1","name":"Message Segment 1","type":"RUNWARETEXTINFERENCEMESSAGE","link":5},{"localized_name":"Message Segment 2","name":"Message Segment 2","shape":7,"type":"RUNWARETEXTINFERENCEMESSAGE","link":null},{"localized_name":"Message Segment 3","name":"Message Segment 3","shape":7,"type":"RUNWARETEXTINFERENCEMESSAGE","link":null},{"localized_name":"Message Segment 4","name":"Message Segment 4","shape":7,"type":"RUNWARETEXTINFERENCEMESSAGE","link":null},{"localized_name":"Message Segment 5","name":"Message Segment 5","shape":7,"type":"RUNWARETEXTINFERENCEMESSAGE","link":null},{"localized_name":"Message Segment 6","name":"Message Segment 6","shape":7,"type":"RUNWARETEXTINFERENCEMESSAGE","link":null},{"localized_name":"Message Segment 7","name":"Message Segment 7","shape":7,"type":"RUNWARETEXTINFERENCEMESSAGE","link":null},{"localized_name":"Message Segment 8","name":"Message Segment 8","shape":7,"type":"RUNWARETEXTINFERENCEMESSAGE","link":null}],"outputs":[{"localized_name":"messages","name":"messages","type":"RUNWARETEXTINFERENCEMESSAGES","links":[4]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"6d47a67b859745d5a86f463d8edfd7da0d1cfa6b","Node name for S&R":"Runware Text Inference Messages"},"widgets_values":[],"bgcolor":"#5345bf"},{"id":9,"type":"Runware Text Inference Settings","pos":[-6.560511112213135,948.0151977539062],"size":[400,658],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"useSystemPrompt","name":"useSystemPrompt","shape":7,"type":"BOOLEAN","widget":{"name":"useSystemPrompt"},"link":null},{"localized_name":"systemPrompt","name":"systemPrompt","shape":7,"type":"STRING","widget":{"name":"systemPrompt"},"link":null},{"localized_name":"useMaxTokens","name":"useMaxTokens","shape":7,"type":"BOOLEAN","widget":{"name":"useMaxTokens"},"link":null},{"localized_name":"maxTokens","name":"maxTokens","shape":7,"type":"INT","widget":{"name":"maxTokens"},"link":null},{"localized_name":"useTemperature","name":"useTemperature","shape":7,"type":"BOOLEAN","widget":{"name":"useTemperature"},"link":null},{"localized_name":"temperature","name":"temperature","shape":7,"type":"FLOAT","widget":{"name":"temperature"},"link":null},{"localized_name":"useTopP","name":"useTopP","shape":7,"type":"BOOLEAN","widget":{"name":"useTopP"},"link":null},{"localized_name":"topP","name":"topP","shape":7,"type":"FLOAT","widget":{"name":"topP"},"link":null},{"localized_name":"useTopK","name":"useTopK","shape":7,"type":"BOOLEAN","widget":{"name":"useTopK"},"link":null},{"localized_name":"topK","name":"topK","shape":7,"type":"INT","widget":{"name":"topK"},"link":null},{"localized_name":"useStopSequences","name":"useStopSequences","shape":7,"type":"BOOLEAN","widget":{"name":"useStopSequences"},"link":null},{"localized_name":"stopSequences","name":"stopSequences","shape":7,"type":"STRING","widget":{"name":"stopSequences"},"link":null},{"localized_name":"usePresencePenalty","name":"usePresencePenalty","shape":7,"type":"BOOLEAN","widget":{"name":"usePresencePenalty"},"link":null},{"localized_name":"presencePenalty","name":"presencePenalty","shape":7,"type":"FLOAT","widget":{"name":"presencePenalty"},"link":null},{"localized_name":"useFrequencyPenalty","name":"useFrequencyPenalty","shape":7,"type":"BOOLEAN","widget":{"name":"useFrequencyPenalty"},"link":null},{"localized_name":"frequencyPenalty","name":"frequencyPenalty","shape":7,"type":"FLOAT","widget":{"name":"frequencyPenalty"},"link":null},{"localized_name":"useTools","name":"useTools","shape":7,"type":"BOOLEAN","widget":{"name":"useTools"},"link":null},{"localized_name":"tools","name":"tools","shape":7,"type":"STRING","widget":{"name":"tools"},"link":null},{"localized_name":"useToolChoice","name":"useToolChoice","shape":7,"type":"BOOLEAN","widget":{"name":"useToolChoice"},"link":null},{"localized_name":"toolChoice","name":"toolChoice","shape":7,"type":"STRING","widget":{"name":"toolChoice"},"link":null},{"localized_name":"thinkingLevel","name":"thinkingLevel","shape":7,"type":"COMBO","widget":{"name":"thinkingLevel"},"link":null}],"outputs":[{"localized_name":"settings","name":"settings","type":"RUNWARETEXTINFERENCESETTINGS","links":[6]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"6d47a67b859745d5a86f463d8edfd7da0d1cfa6b","Node name for S&R":"Runware Text Inference Settings"},"widgets_values":[false,"",false,32768,false,1,true,0.95,false,40,"high","",false,0,false,0,false,"[]",false,"{}","none"],"bgcolor":"#5345bf"},{"id":3,"type":"Runware Text Model Search","pos":[81.07406616210938,741.3767700195312],"size":[270,130],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"Model Search","name":"Model Search","type":"STRING","widget":{"name":"Model Search"},"link":null},{"localized_name":"Model Provider","name":"Model Provider","type":"COMBO","widget":{"name":"Model Provider"},"link":null},{"localized_name":"TextList","name":"TextList","type":"COMBO","widget":{"name":"TextList"},"link":null},{"localized_name":"Use Search Value","name":"Use Search Value","type":"BOOLEAN","widget":{"name":"Use Search Value"},"link":null}],"outputs":[{"localized_name":"model","name":"model","type":"RUNWARETEXTMODEL","links":[1]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"6d47a67b859745d5a86f463d8edfd7da0d1cfa6b","Node name for S&R":"Runware Text Model Search"},"widgets_values":["","Zai","zai-glm-5-1 (ZAI GLM 5.1)",false],"bgcolor":"#5345bf"},{"id":8,"type":"Runware Text Inference Message","pos":[457.5366516113281,1134.87060546875],"size":[400,200],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"role","name":"role","type":"COMBO","widget":{"name":"role"},"link":null},{"localized_name":"content","name":"content","type":"STRING","widget":{"name":"content"},"link":null}],"outputs":[{"localized_name":"message","name":"message","type":"RUNWARETEXTINFERENCEMESSAGE","links":[5]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"6d47a67b859745d5a86f463d8edfd7da0d1cfa6b","Node name for S&R":"Runware Text Inference Message"},"widgets_values":["user","Outline a 5-step plan to buy beta fish from a pet store"],"bgcolor":"#5345bf"},{"id":4,"type":"Runware Save Text","pos":[950.5037841796875,745.9119262695312],"size":[621.9185791015625,757.6689453125],"flags":{},"order":5,"mode":0,"inputs":[{"localized_name":"text","name":"text","type":"STRING","widget":{"name":"text"},"link":2}],"outputs":[{"localized_name":"text","name":"text","type":"STRING","links":null}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"6d47a67b859745d5a86f463d8edfd7da0d1cfa6b","Node name for S&R":"Runware Save Text"},"widgets_values":["Here is a 5-step plan to successfully buy a healthy betta fish from a pet store:\n\n**Step 1: Set Up the Tank First (The \"Cycle Before You Buy\" Rule)**\nNever buy the fish and the tank on the same day. A betta needs a properly cycled tank to survive, which means building up beneficial bacteria that break down toxic fish waste. \n* **Buy the essentials:** A tank (5 gallons minimum is highly recommended), a gentle filter, an adjustable heater (bettas need 78-80°F water), substrate, hiding spots, and a lid (bettas are jumpers). \n* **Start the Nitrogen Cycle:** Set up the tank, turn on the filter and heater, and add a water conditioner and beneficial bacteria starter. This cycling process takes 2 to 6 weeks. Only move to Step 2 once the tank can process ammonia and nitrite down to 0 ppm.\n\n**Step 2: Choose a Reputable Store**\nNot all pet stores care for their fish equally. Scout out a few stores in your area before committing to buying.\n* **Inspect the store:** Look at the overall cleanliness of the fish area. Are the aisles tidy? Do the tanks look well-maintained?\n* **Look at the other fish:** Are the tanks overcrowded? Are there dead fish in the tanks? If a store has multiple dead or visibly sick fish, walk away.\n\n**Step 3: Inspect and Select a Healthy Betta**\nBettas are often kept in small cups, which makes them vulnerable to illness. You need to observe the fish closely before choosing one.\n* **Look at the water:** A little discoloration is normal, but if the water is thick, foul-smelling, or filled with floating debris, the fish is likely stressed.\n* **Observe the fish's body:** Look for clear, bright eyes, intact fins (no ragged, black, or white-edged tears), and smooth scales. Avoid fish with white fuzzy patches (fungus), white spots (ich), or bloated stomachs.\n* **Observe the fish's behavior:** A healthy betta is alert. Gently tap the cup or wave your hand near it. The fish should respond by flaring its gills, swimming actively, or looking at you. Avoid fish that float listlessly at the top or sink to the bottom unresponsive.\n\n**Step 4: Purchase and Transport Safely**\nOnce you have chosen your fish, it is time to bring it home. Minimizing stress during transport is crucial.\n* **Buy the right food:** If you haven't already, purchase high-quality betta pellets (with fish meal or whole fish as the first ingredient) and maybe some freeze-dried bloodworms for treats.\n* **Transport smartly:** Pet stores usually give you a small plastic bag. If it is very cold or hot outside, place the bagged fish inside a paper bag to block out light (which reduces stress), and then inside a small cooler or insulated bag to regulate the temperature. Go straight home—do not run other errands.\n\n**Step 5: Acclimate to the New Tank**\nDo not simply pour the fish directly into its new tank. The water parameters (temperature, pH) from the store's cup are very different from your established tank. Sudden changes can send a fish into shock.\n* **Float the cup:** Gently pour the fish and the store water into a small, clean container (or keep it in the bag). Float this container in your prepared tank for 15–20 minutes so the temperatures equalize.\n* **Drip acclimate:** Over the next 20–30 minutes, add small amounts (about a tablespoon at a time) of your tank water into the container with the fish. This slowly adjusts the fish to your water's chemistry.\n* **Net and release:** Once the water volume in the container has roughly doubled with your tank water, use a soft net to gently scoop the fish out and place it into its new tank. **Do not** pour the water from the store into your tank, as it may contain parasites or diseases. Turn off the tank lights for the first few hours to let the fish decompress."],"bgcolor":"#5345bf"}],"links":[[1,3,0,1,0,"RUNWARETEXTMODEL"],[2,1,0,4,0,"STRING"],[4,5,0,1,1,"RUNWARETEXTINFERENCEMESSAGES"],[5,8,0,5,0,"RUNWARETEXTINFERENCEMESSAGE"],[6,9,0,1,2,"RUNWARETEXTINFERENCESETTINGS"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.6830134553650705,"offset":[307.04397258867573,-505.9291598819246]}},"version":0.4} \ No newline at end of file