Replace the global SSL-disabled context with a per-provider
skipSSLVerify option. SSL verification is now ON by default,
with Chinese API providers pre-configured to skip verification.
Adds a toggle switch in the Provider Manager UI.
* fix: mask API keys in provider endpoint responses
The GET /llm_toolkit/providers endpoint now returns masked keys
(e.g. "sk-••••••xxxx") instead of full API keys. The POST save
handler preserves existing keys when it receives a masked value,
and the check-connectivity endpoint accepts a providerId to look
up the real key server-side instead of requiring it from the frontend.
* fix: prioritize user-typed key over stored key in check endpoint
Motivation:
Users needed a more convenient way to select LLM providers and models directly on the LLM Translator node without mandatory external configuration nodes, and requested clearer guidance on how to use the glossary feature.
Implementation:
- Refactored llm_translator.py to dynamically read from providers.json and support standalone configuration.
- Extended the provider_manager.js frontend extension to support the LLMTranslator node for dynamic dropdown syncing.
- Enhanced widget placeholders with detailed multi-line instructions and examples.
- Updated .gitignore to exclude session-specific documents.
Motivation:
ESC worked only on first open because the listener was registered inside the first-time DOM creation block. On close(), it was detached. On subsequent show() calls, the modal DOM already existed so the function returned early — the listener was NEVER re-attached.
Implementation:
Extracted listener management into two symmetric private methods: _attachEscListener() and _detachEscListener(). show() now calls _attachEscListener on EVERY open (both first-time and subsequent). _closeModal is stored as an instance method so it can be referenced on re-opens. closeModal() calls _detachEscListener() symmetrically. This pattern is leak-proof and correctly re-attaches on every modal activation.
Motivation:
When the UI completely re-renders (like when switching between English and Chinese), the old DOM gets destroyed but the window event listener was not properly cleared and the new modal failed to reattach the listener effectively, breaking the ESC key to close.
Implementation:
Added cleanup logic before attaching a new 'keydown' listener to the window object to ensure the _escListener stays active.
Motivation:
The previous toggle switch animation was abrupt and rigid. The clickable area also spanned the entire row width, which led to unintentional clicks.
Implementation:
- CSS: Replaced static transitions with cubic-bezier spring physics, hardware-accelerated transforms (translate), and pressed-state squish feedback.
- JS: Wrapped the switch in a constrained flex container, replacing the full-width <label> wrapper to fix the clickable area.
Motivation:
The save button's style was originally an overly bright gradient, making it feel out of place compared to the frosted glass aesthetics. Additionally, the user requested the ability to close the modal using the Escape key.
Implementation:
1. Updated '.llm-pm-actions-right button:last-child' CSS to use a restrained translucent background similar to the sidebar items, keeping it cohesive with the glassmorphism design.
2. Added a global 'keydown' listener on 'Escape' inside 'ProviderManager.show()' which correctly triggers 'closeModal()' (also checking for unsaved changes) and automatically removes itself when closed.
Motivation:
The language switcher's change event listener was never registered because () does not support an initialization callback as its 4th argument. Additionally, the Chinese translation for 'LLM Manager' was inaccurate (模型管家).
Implementation:
1. Replaced the unsupported callback with an IIFE to manually create the select element, set its value, and add the 'change' event listener.
2. Updated 'I18N_DICT' to change '模型管家' to 'LLM 管理器' for better accuracy.
Motivation:
Users found it cumbersome to delete and re-type a model name if they made a typo.
Implementation:
Added ondblclick listener and pointer cursor to model tags. Reuses the new custom showPrompt dialog for editing.
Motivation:
With 12 system providers, the provider dropdown menu in ComfyUI was too cluttered. Users only configure 1-2 providers on average.
Implementation:
1. Updated default_providers.json to disable most system providers out of the box (except Qwen and DeepSeek).
2. Filtered out disabled providers from INPUT_TYPES in openai_compatible.py.
3. Added equivalent filter to dynamic model dropdown logic in provider_manager.js.
Motivation:
1. Native browser alerts/confirms block the main thread and break aesthetic immersion.
2. The UI had mixed Chinese and English text, confusing international users.
Implementation:
1. Created unified showDialog, showPrompt, showAlert, and showConfirm components.
2. Migrated delete confirmation and connection checks to the new asynchronous UI dialogs.
3. Updated 'providers.json' templates to use purely English names for consistency.
Motivation:
Users faced data loss when navigating without saving, lacked visual feedback after saving, and the model dropdown logic was broken for the new LLM_CONFIG mode.
Implementation:
1. Replaced 'Custom/手动输入' with 'LLM_CONFIG (from input)' in nodeCreated event.
2. Added visual toast and temporary color change to 'Save' button.
3. Implemented hasUnsavedChanges() and canNavigateAway() pattern to warn users before discarding modified provider data.
Motivation:
Users need a way to verify they have entered their API keys correctly without the keys being permanently visible.
Implementation:
Added a toggle button with an eye icon next to the API key input in the Provider Manager UI. It switches the input type between 'password' and 'text'.
Motivation:
The button text 'Save Provider' was slightly too long and generic 'Save' is cleaner and more professional for the UI.
Implementation:
1. Updated the button innerHTML in provider_manager.js from 'Save Provider' to 'Save'.
2. Updated the corresponding references in both README.md and README_CN.md.
Motivation:
Labels in the provider dropdown were showing redundant internal IDs like '(iflow)', which looked cluttered and unprofessional to end users.
Implementation:
1. Modified openai_compatible.py to generate clean name-only labels.
2. Updated both backend lookup logic and frontend nodeCreated hook in provider_manager.js to align with the name-only matching scheme.