feat: Add full provider variable metadata and multi-variable support#11446
feat: Add full provider variable metadata and multi-variable support#11446HimavarshaVS merged 134 commits intomainfrom
Conversation
Enhances provider variable handling by introducing a metadata structure for all required variables per provider, including support for providers with multiple required variables (e.g., IBM WatsonX). Updates backend API to return full variable info, adapts frontend to dynamically render and save multiple variables, and adds comprehensive tests for the new API response. Also updates static mappings and introduces a new React hook for fetching provider variable metadata.
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughThe changes extend provider variable configuration from a single API key per provider to support multiple variables with metadata. The backend API endpoint returns enriched variable information including required, secret, and option fields. Frontend, service, and core model logic are updated to handle multi-variable validation, storage, and UI rendering, with new utility functions for variable lookup and IBM WatsonX multi-variable support. Changes
Sequence Diagram(s)sequenceDiagram
participant FrontendUI as Frontend UI
participant APIHook as API Hook
participant BackendAPI as Backend API
participant Service as Variable Service
participant LFXCore as LFX Core
participant Storage as Variable Storage
FrontendUI->>APIHook: useGetProviderVariables()
APIHook->>BackendAPI: GET /api/v1/models/provider-variable-mapping
BackendAPI->>LFXCore: get_model_provider_metadata()
LFXCore-->>BackendAPI: {provider: [{variable_key, required, is_secret, options, ...}]}
BackendAPI-->>APIHook: Provider variables mapping
APIHook-->>FrontendUI: Update state with variable metadata
FrontendUI->>FrontendUI: Render dynamic inputs for each variable
Note over FrontendUI: Display required/secret flags,<br/>dropdowns for options, text inputs
FrontendUI->>FrontendUI: User enters/selects values for all variables
FrontendUI->>BackendAPI: POST/PATCH save all variables (batch)
BackendAPI->>Service: Process variable updates
Service->>LFXCore: get_provider_required_variable_keys(provider)
LFXCore-->>Service: Required variable keys for provider
Service->>Storage: Validate & store all required variables
Storage-->>Service: Success/error per variable
Service->>LFXCore: _validate_and_get_enabled_providers()
LFXCore-->>Service: Enabled providers (all required vars present)
Service-->>BackendAPI: Success/aggregated errors
BackendAPI-->>FrontendUI: Update status & clear inputs
FrontendUI->>FrontendUI: Mark provider as enabled, refresh queries
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error, 2 warnings)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is ❌ Your patch status has failed because the patch coverage (19.48%) is below the target coverage (40.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #11446 +/- ##
==========================================
- Coverage 35.54% 35.32% -0.22%
==========================================
Files 1529 1534 +5
Lines 74372 75081 +709
Branches 11154 11312 +158
==========================================
+ Hits 26433 26521 +88
- Misses 46502 47113 +611
- Partials 1437 1447 +10
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds structured provider variable metadata (supporting multiple required variables per provider) and updates backend + frontend to use the richer mapping, including tests for the new API response.
Changes:
- Backend: replaces single
variable_namemapping with per-providervariables[]metadata and exposes it via/provider-variable-mapping. - Frontend: introduces a new query hook and updates the provider modal to render/save multiple variables dynamically.
- Tests: adds unit coverage to validate the new endpoint response and backward-compatible mapping behavior.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/lfx/src/lfx/services/settings/constants.py | Adds IBM WatsonX env vars to the global “variables to load” list. |
| src/lfx/src/lfx/base/models/unified_models.py | Introduces multi-variable provider metadata and updates provider enablement/validation logic. |
| src/lfx/src/lfx/base/models/init.py | Re-exports new provider-variable helper functions. |
| src/backend/base/langflow/api/v1/models.py | Updates provider-variable-mapping endpoint to return full variable metadata. |
| src/backend/base/langflow/services/variable/service.py | Uses provider metadata to set default_fields for all provider variables and validates secrets. |
| src/frontend/src/constants/providerConstants.ts | Adds ProviderVariable interface and deprecates static mapping usage. |
| src/frontend/src/controllers/API/queries/models/use-get-provider-variables.ts | Adds hook to fetch provider variable metadata from the API. |
| src/frontend/src/modals/modelProviderModal/components/ModelProvidersContent.tsx | Updates UI to render/save multiple variables, including dropdown options. |
| src/backend/tests/unit/api/v1/test_models_enabled_providers.py | Adds tests for the new endpoint response and IBM WatsonX multi-variable behavior. |
Files not reviewed (1)
- src/frontend/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for provider in provider_variable_map: | ||
| # Get all required variable keys for this provider | ||
| required_var_keys = get_provider_required_variable_keys(provider) |
There was a problem hiding this comment.
_validate_and_get_enabled_providersdecrypts every required variable value. With the new metadata, some required variables are explicitly non-secret (e.g.,WATSONX_PROJECT_ID, WATSONX_URL) and will likely be stored unencrypted; attempting to decrypt those will fail and prevent the provider from ever being enabled. Fix by looking up each required variable’s metadata and only decrypting values for is_secret=True; for non-secret variables, validate presence using the raw stored value instead of decrypt_api_key` (and ensure the function is passed the right variable set if it currently only includes credentials).
|
|
||
| return enabled |
There was a problem hiding this comment.
This will mark any provider with zero “required” variables as enabled unconditionally. For Ollama (where the base URL is optional in metadata), this is a behavior change vs. the previous logic (which only enabled providers when a corresponding variable existed). Consider requiring that some provider variable exists (e.g., the “primary” variable from provider_variable_map[provider] or any variable in storage) before adding it to enabled, rather than enabling by default.
| return enabled | |
| # Provider has no required variables (like Ollama with optional base URL). | |
| # Only enable the provider if at least one configured variable exists | |
| # (for example, the "primary" variable from provider_variable_map). | |
| primary_var_name = provider_variable_map.get(provider) | |
| if primary_var_name and primary_var_name in credential_variables: | |
| enabled.add(provider) |
| if (selectedProvider && isUserInputRef.current) { | ||
| // Find the variable that was just changed and has a value | ||
| const variableToSave = providerVariables.find((v) => | ||
| variableValues[v.variable_key]?.trim(), | ||
| ); | ||
| if (variableToSave) { | ||
| handleSaveVariable(variableToSave); | ||
| } |
There was a problem hiding this comment.
The debounced autosave picks the first variable in providerVariables that currently has a non-empty value, not the variable that was last edited. For providers with multiple fields (e.g., WatsonX), once the first field is filled, subsequent edits to other fields will keep re-saving the first field and may never persist the others. Track the “last changed variable_key” (e.g., via a ref/state set in each onChange/onValueChange handler) and save that specific variable instead of using find(...).
|
|
||
| const onError = (error: any) => { | ||
| setValidationFailed(true); | ||
| setSavingVariableKey(null); |
There was a problem hiding this comment.
On error you clear savingVariableKey, but the UI’s error indicator is gated on savingVariableKey === variable.variable_key. This makes it impossible to render the error icon for the field that failed. Use a separate piece of state for “failedVariableKey” (or keep savingVariableKey until the UI can display and the user edits again) so the error is attributable to the correct input.
| setSavingVariableKey(null); |
| endIcon={ | ||
| isSaving | ||
| ? "LoaderCircle" | ||
| : validationFailed && | ||
| savingVariableKey === variable.variable_key | ||
| ? "X" | ||
| : isConfigured | ||
| ? "Check" | ||
| : undefined | ||
| } |
There was a problem hiding this comment.
Because savingVariableKey is set to null in onError, the condition validationFailed && savingVariableKey === variable.variable_key will never be true after a failed save, so the “X” icon won’t show. Tie the error state to the failing variable via a dedicated failedVariableKey, or don’t null out the key until after the error is rendered/acknowledged.
| async def get_model_provider_mapping() -> dict[str, list[dict]]: | ||
| """Return provider variables mapping with full variable info. | ||
|
|
||
| Each provider maps to a list of variable objects containing: | ||
| - variable_name: Display name shown to user | ||
| - variable_key: Environment variable key | ||
| - description: Help text for the variable | ||
| - required: Whether the variable is required | ||
| - is_secret: Whether to treat as credential | ||
| - is_list: Whether it accepts multiple values | ||
| - options: Predefined options for dropdowns | ||
| """ | ||
| metadata = get_model_provider_metadata() | ||
| return {provider: meta.get("variables", []) for provider, meta in metadata.items()} | ||
|
|
||
|
|
There was a problem hiding this comment.
This endpoint changes its response shape from dict[str, str] (provider → variable key) to dict[str, list[dict]] (provider → variable metadata list). Since the path stayed the same, existing clients expecting the prior schema will break. If backward compatibility is required, consider either (a) introducing a new endpoint (e.g., /provider-variables), (b) adding a query param (e.g., ?format=full|legacy), or (c) returning both shapes (e.g., { mapping: ..., variables: ... }) during a deprecation window.
| async def get_model_provider_mapping() -> dict[str, list[dict]]: | |
| """Return provider variables mapping with full variable info. | |
| Each provider maps to a list of variable objects containing: | |
| - variable_name: Display name shown to user | |
| - variable_key: Environment variable key | |
| - description: Help text for the variable | |
| - required: Whether the variable is required | |
| - is_secret: Whether to treat as credential | |
| - is_list: Whether it accepts multiple values | |
| - options: Predefined options for dropdowns | |
| """ | |
| metadata = get_model_provider_metadata() | |
| return {provider: meta.get("variables", []) for provider, meta in metadata.items()} | |
| async def get_model_provider_mapping( | |
| format: Annotated[ | |
| str, | |
| Query( | |
| description="Response format: 'legacy' for simple mapping, 'full' for variable metadata.", | |
| alias="format", | |
| ), | |
| ] = "legacy", | |
| ) -> dict: | |
| """Return provider variables mapping. | |
| Backwards compatible behavior: | |
| - By default (format=legacy), returns a simple mapping of provider -> variable key, | |
| matching the original endpoint behavior: | |
| { | |
| "openai": "OPENAI_API_KEY", | |
| "anthropic": "ANTHROPIC_API_KEY", | |
| ... | |
| } | |
| - When format=full, returns provider -> list of variable metadata objects: | |
| { | |
| "openai": [ | |
| { | |
| "variable_name": "...", | |
| "variable_key": "...", | |
| "description": "...", | |
| "required": true, | |
| "is_secret": true, | |
| "is_list": false, | |
| "options": [...] | |
| }, | |
| ... | |
| ], | |
| ... | |
| } | |
| """ | |
| if format == "full": | |
| metadata = get_model_provider_metadata() | |
| return {provider: meta.get("variables", []) for provider, meta in metadata.items()} | |
| # Default: legacy simple mapping (provider -> variable key) | |
| return get_model_provider_variable_mapping() |
| metadata = get_model_provider_metadata() | ||
| return {provider: meta.get("variables", []) for provider, meta in metadata.items()} |
There was a problem hiding this comment.
This endpoint changes its response shape from dict[str, str] (provider → variable key) to dict[str, list[dict]] (provider → variable metadata list). Since the path stayed the same, existing clients expecting the prior schema will break. If backward compatibility is required, consider either (a) introducing a new endpoint (e.g., /provider-variables), (b) adding a query param (e.g., ?format=full|legacy), or (c) returning both shapes (e.g., { mapping: ..., variables: ... }) during a deprecation window.
Replaces per-variable auto-save with a batch save for all provider variables, improving UX and reducing API calls. Updates input handling to show masked values for secrets, disables save button until all required fields are filled, and provides clearer feedback for configured variables.
…w-ai/langflow into EJ/add-multi-api-support
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…fields with just one input
Enhances provider variable handling by introducing a metadata structure for all required variables per provider, including support for providers with multiple required variables (e.g., IBM WatsonX). Updates backend API to return full variable info, adapts frontend to dynamically render and save multiple variables, and adds comprehensive tests for the new API response. Also updates static mappings and introduces a new React hook for fetching provider variable metadata.
Summary by CodeRabbit
New Features
Tests
Documentation