feat: add Azure AI under feature flag - #2209
Conversation
- Implemented Azure AI Foundry settings form for user configuration. - Integrated Azure AI Foundry model fetching and validation in the ingest settings section. - Added Azure AI Foundry logo and settings dialog to the model providers component. - Enhanced model helpers to support Azure AI Foundry as a model provider. - Created API endpoints for fetching Azure AI Foundry models and validating credentials. - Updated configuration management to include Azure AI Foundry settings. - Implemented health check and completion tests for Azure AI Foundry. - Added support for Azure AI Foundry in Langflow global variable synchronization. - Updated settings models to accommodate Azure AI Foundry API key and endpoint. - Enhanced provider health checks to include Azure AI Foundry.
…d additional parameters
…AI Foundry settings
…nclude model parameter
- Introduced Azure OpenAI provider configuration and models. - Updated frontend components to include Azure OpenAI logo and provider options. - Implemented backend API endpoints for Azure OpenAI model retrieval and validation. - Enhanced settings management to accommodate Azure OpenAI API key, endpoint, and version. - Updated provider health checks and validation functions for Azure OpenAI. - Added support for Azure OpenAI in Langflow synchronization. - Modified models and settings schemas to include Azure OpenAI fields.
…int handling across multiple files
Introduce OPENRAG_AZURE_AI_ENABLED to gate Azure AI Foundry / Azure OpenAI functionality across the stack. Adds is_azure_ai_enabled() accessor and documents the env var in .env.example. ConfigManager now only ingests Azure provider env vars when the flag is enabled (prevents env-only re-enable). API: settings endpoint redacts Azure provider state when disabled, returns show_azure_ai_providers, and update/onboarding endpoints reject attempts to configure or select Azure providers when disabled. Model listing endpoints return 404 when Azure is disabled. Frontend hides Azure provider tiles/dialogs when the flag is off. This prevents the UI from learning about or configuring Azure providers unless explicitly enabled.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds feature-gated Azure AI Foundry and Azure OpenAI providers. The change covers configuration, validation, model retrieval, settings persistence, Langflow synchronization, model routing, and frontend configuration workflows. ChangesAzure provider integration
Estimated code review effort: 5 (Critical) | ~90+ minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
|
React Doctor found 1 new issue in 1 file · 1 warning · score 66 / 100 (Needs work) · 0 fixed · vs 1 warning
Reviewed by React Doctor for commit |
| errors.append(f"Embedding deployment '{embedding_deployment_name}': {str(e)}") | ||
|
|
||
| if errors: | ||
| return JSONResponse({"error": "; ".join(errors)}, status_code=400) |
| ) | ||
| except Exception as e: | ||
| return JSONResponse( | ||
| {"error": f"Could not connect to Azure AI Foundry endpoint: {str(e)}"}, |
There was a problem hiding this comment.
Actionable comments posted: 12
🧹 Nitpick comments (2)
frontend/app/settings/_components/azure-openai-settings-dialog.tsx (1)
33-348: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftThe two Azure dialogs duplicate one component. Both files repeat the same state, the same validate and test flow, the same pluralization logic, the same health-cache write, the same error animation blocks, and the same footer wiring. Only the provider key, the payload field names, and the extra
apiVersionfield differ. Every future fix must land twice, and thecanRemoveAzuredivergence already shows that drift. React Doctor also flagged the size of both components.Extract a shared
AzureProviderSettingsDialogthat takes the provider key, the form component, the payload builder, and the removal flag as props.
frontend/app/settings/_components/azure-openai-settings-dialog.tsx#L33-L348: reduce to a thin wrapper over the shared dialog.frontend/app/settings/_components/azure-ai-foundry-settings-dialog.tsx#L33-L336: reduce to a thin wrapper over the shared dialog.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/app/settings/_components/azure-openai-settings-dialog.tsx` around lines 33 - 348, Extract the duplicated dialog logic from AzureOpenAISettingsDialog in frontend/app/settings/_components/azure-openai-settings-dialog.tsx (lines 33-348) and AzureAIFoundrySettingsDialog in frontend/app/settings/_components/azure-ai-foundry-settings-dialog.tsx (lines 33-336) into a shared AzureProviderSettingsDialog. Pass the provider key, provider-specific form component, payload builder, and removal flag as props, preserving each provider’s apiVersion handling, validation/test flows, health-cache update, error rendering, footer wiring, and removal behavior; reduce both existing components to thin provider-specific wrappers.src/api/models.py (1)
430-560: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoffExtract the shared Azure model-resolution flow.
get_azure_openai_modelsandget_azure_ai_foundry_modelsrepeat the same steps: feature gate, resolve values from body or config, validate required fields, run the optional inference tests, then fall back to stored deployment names. Only the validator functions and the required-field set differ. Extract a helper that takes the provider name, the resolved values, and the test callables. This keeps the two handlers to their provider-specific parts.The unused
models_service=Depends(get_models_service)parameter can be removed from both handlers at the same time, because neither body uses it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/api/models.py` around lines 430 - 560, Extract the duplicated Azure model-resolution logic from get_azure_openai_models and get_azure_ai_foundry_models into a shared helper accepting the provider name, resolved credentials/deployment values, and provider-specific validation callables; preserve each handler’s feature gate, required-field differences, inference-test behavior, lightweight validation, and stored-deployment fallback. Remove the unused models_service=Depends(get_models_service) parameter from both handlers and clean up any now-unused import.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/app/settings/_components/azure-ai-foundry-settings-dialog.tsx`:
- Around line 81-86: Replace the no-argument reset in the Azure AI Foundry
dialog’s useEffect with explicit values from
settings.providers?.azure_ai_foundry for endpoint, llmDeploymentName, and
embeddingDeploymentName, while resetting apiKey to an empty string. Apply the
same change in
frontend/app/settings/_components/azure-openai-settings-dialog.tsx at lines
83-88 using settings.providers?.azure_openai and including apiVersion; retain
clearing testConnectionResult when open.
In `@frontend/app/settings/_components/azure-ai-foundry-settings-form.tsx`:
- Around line 56-59: The API key validation must allow edits to
already-configured Azure providers without requiring the secret again. In
frontend/app/settings/_components/azure-ai-foundry-settings-form.tsx lines
56-59, add an isConfigured prop and make the apiKey required rule conditional on
it; in frontend/app/settings/_components/azure-openai-settings-form.tsx lines
57-60, apply the same rule and pass isConfigured from
azure-openai-settings-dialog.tsx.
In `@src/api/models.py`:
- Around line 366-402: Update the Azure AI Foundry model-list flow around the
credential-check response and the `language_models`/`embedding_models` parsing
block: append `/models` to the resource endpoint for the model-list request, and
reuse the existing first credential-check response rather than issuing a second
identical GET. Preserve the current response parsing and fallback behavior.
In `@src/api/provider_health.py`:
- Around line 110-116: Update the provider-health cache key construction in the
surrounding provider health flow to include both api_version and
embedding_api_version alongside their respective provider settings. Ensure
changes to either Azure OpenAI API version produce a distinct key so
validate_provider_setup runs instead of returning stale cached health data.
In `@src/api/provider_validation.py`:
- Around line 1474-1499: The Azure completion validation payloads in
_test_azure_openai_completion and _test_azure_ai_foundry_completion currently
test only chat responses; add the same minimal tools payload used by supported
completion providers to both request bodies. Preserve the existing messages and
token settings while ensuring both Azure tests exercise the tool-calling
fallback path.
- Around line 1322-1327: Fix the Ruff B904 violations in the six Azure validator
timeout handlers by adding an explicit exception cause when raising the new
Exception inside each except httpx.TimeoutException block. Update the handlers
around the affected health-check validators, using from e when the caught
exception is bound or from None when it is not, while preserving the existing
messages and re-raise behavior.
In `@src/api/settings/endpoints.py`:
- Around line 1167-1181: Update the Azure credential-update handling near the
feature-gate check to persist Azure AI Foundry and Azure OpenAI API keys,
endpoints, and azure_openai_api_version into current_config, mark the
corresponding providers as configured, and include Azure deployment metadata.
Update the validation calls around the existing validation blocks to propagate
api_version, ensuring Azure onboarding validates the newly persisted complete
configuration before proceeding.
- Around line 848-887: Move the Azure-specific configuration workflow currently
implemented in the route handler—including updates in the Azure provider blocks,
endpoint normalization, credential removal, fallback selection, and embedding
dependency checks—into an injected settings service. Keep the route handler
limited to request validation, authorization, invoking the service, and
constructing HTTP responses; preserve the existing behavior and use the
service’s existing provider/configuration symbols.
- Around line 544-549: Update the settings endpoint’s Azure mutation branches,
including the deployment-name logic around effective_llm_provider and the
referenced credential, endpoint, API-version, removal, and fallback handling, to
modify working_config instead of current_config. Ensure every Azure change is
applied to the same working_config instance that the save operation at line 1094
persists, while preserving the existing provider-selection behavior.
In `@src/config/config_manager.py`:
- Around line 469-503: Move the Azure feature-flag parsing and environment reads
from the configuration-loading block into typed accessors in config/settings.py,
then have the Azure setup in config_manager use those accessors instead of
os.getenv. Update the relevant settings model/accessor symbols for
OPENRAG_AZURE_AI_ENABLED, Azure AI Foundry, and Azure OpenAI values while
preserving the existing enabled gating and provider configuration behavior.
In `@src/config/settings.py`:
- Around line 1185-1210: Gate the Azure credential and endpoint exports in the
settings-loading path around is_azure_ai_enabled(), covering both
azure_ai_foundry and azure_openai assignments. When Azure is disabled or the
provider configuration is removed, clear the relevant Azure environment
variables, including API keys, base URLs, and API version, so stale routing
state is not retained.
In `@src/services/models_service.py`:
- Around line 116-138: Update the Azure registration logic in the model registry
flow to register persisted deployment names from the configured provider
objects, rather than only the currently active embedding_model and llm_model
values. For both azure_ai_foundry and azure_openai, add each configured
llm_deployment_name and embedding_deployment_name to new_registry with the
corresponding provider identifier, while preserving configured-provider guards
and avoiding empty names.
---
Nitpick comments:
In `@frontend/app/settings/_components/azure-openai-settings-dialog.tsx`:
- Around line 33-348: Extract the duplicated dialog logic from
AzureOpenAISettingsDialog in
frontend/app/settings/_components/azure-openai-settings-dialog.tsx (lines
33-348) and AzureAIFoundrySettingsDialog in
frontend/app/settings/_components/azure-ai-foundry-settings-dialog.tsx (lines
33-336) into a shared AzureProviderSettingsDialog. Pass the provider key,
provider-specific form component, payload builder, and removal flag as props,
preserving each provider’s apiVersion handling, validation/test flows,
health-cache update, error rendering, footer wiring, and removal behavior;
reduce both existing components to thin provider-specific wrappers.
In `@src/api/models.py`:
- Around line 430-560: Extract the duplicated Azure model-resolution logic from
get_azure_openai_models and get_azure_ai_foundry_models into a shared helper
accepting the provider name, resolved credentials/deployment values, and
provider-specific validation callables; preserve each handler’s feature gate,
required-field differences, inference-test behavior, lightweight validation, and
stored-deployment fallback. Remove the unused
models_service=Depends(get_models_service) parameter from both handlers and
clean up any now-unused import.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 0846b1fb-c21a-4a67-8ec5-4661f159e47e
📒 Files selected for processing (27)
.env.examplefrontend/app/api/mutations/useUpdateSettingsMutation.tsfrontend/app/api/queries/useGetModelsQuery.tsfrontend/app/api/queries/useGetSettingsQuery.tsfrontend/app/settings/_components/agent-settings-section.tsxfrontend/app/settings/_components/azure-ai-foundry-settings-dialog.tsxfrontend/app/settings/_components/azure-ai-foundry-settings-form.tsxfrontend/app/settings/_components/azure-openai-settings-dialog.tsxfrontend/app/settings/_components/azure-openai-settings-form.tsxfrontend/app/settings/_components/ingest-settings-section.tsxfrontend/app/settings/_components/model-providers.tsxfrontend/app/settings/_helpers/model-helpers.tsxfrontend/components/icons/azure-ai-foundry-logo.tsxfrontend/components/icons/azure-openai-logo.tsxfrontend/components/provider-health-banner.tsxsrc/api/models.pysrc/api/provider_health.pysrc/api/provider_validation.pysrc/api/settings/endpoints.pysrc/api/settings/helpers.pysrc/api/settings/langflow_sync.pysrc/api/settings/models.pysrc/app/routes/internal.pysrc/config/config_manager.pysrc/config/settings.pysrc/services/models_service.pysrc/utils/container_utils.py
| <Input | ||
| {...register("apiKey", { | ||
| required: "API key is required", | ||
| })} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
The API key rule blocks edits to an already-configured Azure provider. Both dialogs omit the API key from the settings payload when the field is empty, which supports keeping the stored key. Both forms mark the field required unconditionally, so that path is unreachable. A configured user who edits only the deployment names cannot submit without retyping the secret. The shared root cause is that the validation rule ignores the provider's configured state.
frontend/app/settings/_components/azure-ai-foundry-settings-form.tsx#L56-L59: accept anisConfiguredprop and setrequiredtoisConfigured ? false : "API key is required".frontend/app/settings/_components/azure-openai-settings-form.tsx#L57-L60: apply the same conditional rule and passisConfiguredfromazure-openai-settings-dialog.tsx.
📍 Affects 2 files
frontend/app/settings/_components/azure-ai-foundry-settings-form.tsx#L56-L59(this comment)frontend/app/settings/_components/azure-openai-settings-form.tsx#L57-L60
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/app/settings/_components/azure-ai-foundry-settings-form.tsx` around
lines 56 - 59, The API key validation must allow edits to already-configured
Azure providers without requiring the secret again. In
frontend/app/settings/_components/azure-ai-foundry-settings-form.tsx lines
56-59, add an isConfigured prop and make the apiKey required rule conditional on
it; in frontend/app/settings/_components/azure-openai-settings-form.tsx lines
57-60, apply the same rule and pass isConfigured from
azure-openai-settings-dialog.tsx.
| # Try to fetch the deployed model list from the resource endpoint. | ||
| # Azure AI Foundry resource-level endpoints return an OpenAI-compatible | ||
| # GET /models response: {"data": [{"id": "<deployment>", ...}, ...]} | ||
| language_models = [] | ||
| embedding_models = [] | ||
|
|
||
| try: | ||
| async with httpx.AsyncClient() as client: | ||
| list_response = await client.get( | ||
| endpoint.rstrip("/"), | ||
| headers={ | ||
| "Authorization": f"Bearer {api_key}", | ||
| "Content-Type": "application/json", | ||
| }, | ||
| timeout=10.0, | ||
| ) | ||
| logger.info(f"Azure AI Foundry GET /models status: {list_response.status_code}") | ||
| logger.debug(f"Azure AI Foundry GET /models body: {list_response.text[:500]}") | ||
| if list_response.status_code == 200: | ||
| data = list_response.json() | ||
| entries = data.get("data", []) | ||
| for entry in entries: | ||
| model_id = entry.get("id", "") | ||
| if not model_id: | ||
| continue | ||
| item = {"value": model_id, "label": model_id} | ||
| # Heuristic: names containing "embed" go to embedding; rest to language. | ||
| if "embed" in model_id.lower(): | ||
| embedding_models.append(item) | ||
| else: | ||
| language_models.append(item) | ||
| logger.info( | ||
| f"Azure AI Foundry models parsed: {len(language_models)} LLM, {len(embedding_models)} embedding" | ||
| ) | ||
| except Exception as e: | ||
| logger.warning(f"Azure AI Foundry GET /models failed: {e}") | ||
| pass # Fall through to config-based fallback below |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
The model-list call repeats the credential check and never requests /models.
The block at Lines 372-381 issues the same GET to endpoint.rstrip("/") with the same headers and timeout as the credential check at Lines 333-341. Two effects follow. First, every request performs two identical round-trips. Second, the comment at Lines 366-368 states that an OpenAI-compatible GET /models payload is parsed, but no /models path is appended, so data["data"] is normally absent and the dynamic listing always falls through to the stored deployment names.
Append the /models path and reuse the first response instead of repeating the request.
🐛 Proposed fix
try:
async with httpx.AsyncClient() as client:
list_response = await client.get(
- endpoint.rstrip("/"),
+ f"{endpoint.rstrip('/')}/models",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
},
timeout=10.0,
)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/api/models.py` around lines 366 - 402, Update the Azure AI Foundry
model-list flow around the credential-check response and the
`language_models`/`embedding_models` parsing block: append `/models` to the
resource endpoint for the model-list request, and reuse the existing first
credential-check response rather than issuing a second identical GET. Preserve
the current response parsing and fallback behavior.
| api_version = getattr(llm_provider_config, "api_version", None) | ||
| llm_model = current_config.agent.llm_model | ||
|
|
||
| embedding_api_key = getattr(embedding_provider_config, "api_key", None) | ||
| embedding_endpoint = getattr(embedding_provider_config, "endpoint", None) | ||
| embedding_project_id = getattr(embedding_provider_config, "project_id", None) | ||
| embedding_api_version = getattr(embedding_provider_config, "api_version", None) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Add the API versions to the provider-health cache key.
api_version and embedding_api_version now change the validation outcome, because validate_provider_setup builds the Azure OpenAI request URL from them at Lines 204 and 239. The cache key at Lines 123-135 omits both. If a user corrects only the Azure OpenAI API version, every key component stays the same, so the cached healthy payload is returned and the new version is never validated. The banner then reports a stale status until the entry expires.
Include both values in the key.
🐛 Proposed fix
health_cache_key = provider_health_cache.cache_key(
provider=provider,
embedding_provider=embedding_provider,
test_completion=test_completion,
llm_model=llm_model,
embedding_model=embedding_model,
endpoint=endpoint,
project_id=project_id,
api_key=api_key,
+ api_version=api_version,
embedding_api_key=embedding_api_key,
embedding_endpoint=embedding_endpoint,
embedding_project_id=embedding_project_id,
+ embedding_api_version=embedding_api_version,
)Also applies to: 123-135
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/api/provider_health.py` around lines 110 - 116, Update the
provider-health cache key construction in the surrounding provider health flow
to include both api_version and embedding_api_version alongside their respective
provider settings. Ensure changes to either Azure OpenAI API version produce a
distinct key so validate_provider_setup runs instead of returning stale cached
health data.
| # Azure AI Foundry / Azure OpenAI provider settings — gated behind the | ||
| # feature flag (default off) so setting these env vars alone can't | ||
| # silently re-enable the feature. Read the raw env var here (not | ||
| # config.settings.is_azure_ai_enabled) to avoid a circular import. | ||
| azure_ai_enabled = os.getenv("OPENRAG_AZURE_AI_ENABLED", "false").strip().lower() in ( | ||
| "true", | ||
| "1", | ||
| "yes", | ||
| "on", | ||
| ) | ||
| if azure_ai_enabled: | ||
| if os.getenv("AZURE_AI_API_KEY"): | ||
| config_data["providers"]["azure_ai_foundry"]["api_key"] = os.getenv( | ||
| "AZURE_AI_API_KEY" | ||
| ) | ||
| config_data["providers"]["azure_ai_foundry"]["configured"] = True | ||
| if os.getenv("AZURE_AI_API_BASE"): | ||
| config_data["providers"]["azure_ai_foundry"]["endpoint"] = os.getenv( | ||
| "AZURE_AI_API_BASE" | ||
| ) | ||
|
|
||
| if os.getenv("AZURE_OPENAI_API_KEY"): | ||
| config_data["providers"]["azure_openai"]["api_key"] = os.getenv( | ||
| "AZURE_OPENAI_API_KEY" | ||
| ) | ||
| config_data["providers"]["azure_openai"]["configured"] = True | ||
| if os.getenv("AZURE_OPENAI_ENDPOINT"): | ||
| config_data["providers"]["azure_openai"]["endpoint"] = os.getenv( | ||
| "AZURE_OPENAI_ENDPOINT" | ||
| ) | ||
| if os.getenv("AZURE_OPENAI_API_VERSION"): | ||
| config_data["providers"]["azure_openai"]["api_version"] = os.getenv( | ||
| "AZURE_OPENAI_API_VERSION" | ||
| ) | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Route Azure environment access through config/settings.py.
Lines 473-502 read Azure configuration with os.getenv in src/config/config_manager.py. This creates a second configuration source. Move feature-flag parsing and Azure environment access into typed accessors in config/settings.py.
As per path instructions, src/**/*.py requires: “Config values must come from config/settings.py (the only place os.environ is read); never access os.environ elsewhere in the codebase.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/config/config_manager.py` around lines 469 - 503, Move the Azure
feature-flag parsing and environment reads from the configuration-loading block
into typed accessors in config/settings.py, then have the Azure setup in
config_manager use those accessors instead of os.getenv. Update the relevant
settings model/accessor symbols for OPENRAG_AZURE_AI_ENABLED, Azure AI Foundry,
and Azure OpenAI values while preserving the existing enabled gating and
provider configuration behavior.
Source: Path instructions
| # Set Azure AI Foundry credentials | ||
| if config.providers.azure_ai_foundry.api_key: | ||
| os.environ["AZURE_AI_API_KEY"] = config.providers.azure_ai_foundry.api_key | ||
| logger.debug("Loaded Azure AI Foundry API key from config") | ||
| if config.providers.azure_ai_foundry.endpoint: | ||
| os.environ["AZURE_AI_API_BASE"] = config.providers.azure_ai_foundry.endpoint | ||
| logger.debug("Loaded Azure AI Foundry endpoint from config") | ||
|
|
||
| # Set Azure OpenAI Service credentials (LiteLLM azure/ prefix). | ||
| # AZURE_API_BASE must be the bare resource root — LiteLLM appends | ||
| # /openai/deployments/<name>/... itself, so a pasted /openai/v1 | ||
| # suffix would otherwise produce a doubled path (404 at inference). | ||
| if config.providers.azure_openai.api_key: | ||
| os.environ["AZURE_API_KEY"] = config.providers.azure_openai.api_key | ||
| logger.debug("Loaded Azure OpenAI API key from config") | ||
| if config.providers.azure_openai.endpoint: | ||
| from utils.container_utils import normalize_azure_openai_base | ||
|
|
||
| os.environ["AZURE_API_BASE"] = normalize_azure_openai_base( | ||
| config.providers.azure_openai.endpoint | ||
| ) | ||
| logger.debug("Loaded Azure OpenAI endpoint from config") | ||
| if config.providers.azure_openai.api_version: | ||
| os.environ["AZURE_API_VERSION"] = config.providers.azure_openai.api_version | ||
| logger.debug("Loaded Azure OpenAI API version from config") | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Honor the Azure feature flag before exporting credentials.
When Azure was configured before the flag is disabled, this path still exports its credentials and endpoints to LiteLLM-visible environment variables. The disabled feature can therefore retain Azure routing state in the running process. Gate these assignments with is_azure_ai_enabled() and clear the Azure variables when the feature is disabled or the provider is removed. This is required by the PR objective that disabled Azure environment values are not ingested.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/config/settings.py` around lines 1185 - 1210, Gate the Azure credential
and endpoint exports in the settings-loading path around is_azure_ai_enabled(),
covering both azure_ai_foundry and azure_openai assignments. When Azure is
disabled or the provider configuration is removed, clear the relevant Azure
environment variables, including API keys, base URLs, and API version, so stale
routing state is not retained.
| # Azure AI Foundry — register configured deployment names statically; | ||
| # the user provides deployment names manually (no remote model fetch). | ||
| if config.providers.azure_ai_foundry.configured: | ||
| embedding_model = config.knowledge.embedding_model | ||
| llm_model = config.agent.llm_model | ||
| if ( | ||
| embedding_model | ||
| and config.knowledge.embedding_provider == "azure_ai_foundry" | ||
| ): | ||
| new_registry[embedding_model] = "azure_ai_foundry" | ||
| if llm_model and config.agent.llm_provider == "azure_ai_foundry": | ||
| new_registry[llm_model] = "azure_ai_foundry" | ||
|
|
||
| # Azure OpenAI Service — register configured deployment names statically; | ||
| # the user provides deployment names manually (no remote model fetch). | ||
| if config.providers.azure_openai.configured: | ||
| embedding_model = config.knowledge.embedding_model | ||
| llm_model = config.agent.llm_model | ||
| if embedding_model and config.knowledge.embedding_provider == "azure_openai": | ||
| new_registry[embedding_model] = "azure_openai" | ||
| if llm_model and config.agent.llm_provider == "azure_openai": | ||
| new_registry[llm_model] = "azure_openai" | ||
|
|
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm the persisted deployment-name fields exist on the Azure provider configs.
set -euo pipefail
rg -n --type=py -C6 'class Azure.*Config|llm_deployment_name|embedding_deployment_name' src/config | head -100Repository: langflow-ai/openrag
Length of output: 2385
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== candidate files =="
git ls-files | rg '(^src/.*models.py|src/config|src/services/models_service.py)$'
echo "== config manager relevant section =="
sed -n '120,210p' src/config/config_manager.py
echo "== src/services/models_service.py outline =="
ast-grep outline src/services/models_service.py --view expanded
echo "== src/services/models_service.py lines 100-205 =="
sed -n '100,205p' src/services/models_service.py
echo "== api models azure deployment usage =="
rg -n --type=py -C4 'get_azure_ai_foundry_models|azure_ai_foundry|azure_openai|llm_deployment_name|embedding_deployment_name|model_registry' src/api/models.py src/services src/dependencies.py src/main.pyRepository: langflow-ai/openrag
Length of output: 27497
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== all references to model persistence/deployment model fields =="
rg -n --type=py -C4 'embedding_model|llm_model|embedding_provider|llm_provider|embedding_deployment_name|llm_deployment_name|azure_ai_foundry|azure_openai|agent|knowledge' src | head -300
echo "== provider validation azure deployment names =="
rg -n --type=py -C4 'llm_deployment_name|embedding_deployment_name|_test_azure|azure_ai_foundry|azure_openai' src | rg -n --type=py -C4 'validator|provider_validation|models.py'
echo "== behavioral probe for registry behavior =="
python3 - <<'PY'
from pathlib import Path
src = Path("src/services/models_service.py").read_text()
checks = {
"azure_foundry_active_embedding": 'config.knowledge.embedding_provider == "azure_ai_foundry"' in src,
"azure_foundry_stored_llm": 'config.providers.azure_ai_foundry.llm_deployment_name' in src,
"azure_foundry_stored_embed": 'config.providers.azure_ai_foundry.embedding_deployment_name' in src,
"azure_aoai_active_embedding": 'config.knowledge.embedding_provider == "azure_openai"' in src,
"azure_aoai_stored_llm": 'config.providers.azure_openai.llm_deployment_name' in src,
"azure_aoai_stored_embed": 'config.providers.azure_openai.embedding_deployment_name' in src,
"registry_get_returns_raw_in_nonstrict": 'return model_name # OpenAI-compatible models work without a prefix',
"regressed_by_switch_simulation",
}
# Simulate the registry condition: if active provider is OTHER, Azure configured blocks do not add Azure stored deployment names.
provider = "azure_ai_foundry"
configured = True
embedding_model = "azure-embed-deployment"
embedding_provider_active = "other_active_provider"
llm_model = "azure-llm-deployment"
llm_provider_active = "other_active_provider"
new_registry = {}
if configured:
if embedding_model and embedding_provider_active == "azure_ai_foundry":
new_registry[embedding_model] = "azure_ai_foundry"
if llm_model and llm_provider_active == "azure_ai_foundry":
new_registry[llm_model] = "azure_ai_foundry"
checks["switch_drops_stored_embeddings"] = embedding_model not in new_registry and llm_model not in new_registry
print("\n".join(f"{k}: {v}" for k, v in checks.items()))
PYRepository: langflow-ai/openrag
Length of output: 50375
Register the persisted Azure deployment names, not only the active ones.
Azure registry entries are added only when that Azure provider is the active embedding_provider or llm_provider. A corpus embedded with a persisted Azure deployment name stops resolving after an active-provider switch: strict=True raises UnknownEmbeddingProvider, and non-strict lookup returns the bare name so LiteLLM cannot route the request. Register config.providers.azure_ai_foundry and config.providers.azure_openai persisted llm_deployment_name/embedding_deployment_name values instead.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/services/models_service.py` around lines 116 - 138, Update the Azure
registration logic in the model registry flow to register persisted deployment
names from the configured provider objects, rather than only the currently
active embedding_model and llm_model values. For both azure_ai_foundry and
azure_openai, add each configured llm_deployment_name and
embedding_deployment_name to new_registry with the corresponding provider
identifier, while preserving configured-provider guards and avoiding empty
names.
Introduce LANGFLOW_MODEL_VALUE_PROVIDERS and include azure_ai_foundry, so Langflow flow-sync only runs for providers that are routable through Langflow's unified components. Rename Langflow global variables for Azure Foundry to AZURE_AI_FOUNDRY_API_KEY / AZURE_AI_FOUNDRY_ENDPOINT to match Langflow metadata. Add provider display mapping and API-key mapping for Azure AI Foundry, update validation/error text, and log skipped providers when appropriate. Files changed: src/api/settings/langflow_sync.py, src/services/flows_service.py, src/utils/langflow_headers.py
…/openrag into azure-ai-rebase-main
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/services/flows_service.py`:
- Around line 26-32: Move the component-selection logic in
_update_provider_components_locked so it executes before the early return inside
wrap_node_update, ensuring node_tasks is populated. Preserve the existing
compatibility filtering and enable azure_ai_foundry to route through
change_langflow_model_value, so Azure AI Foundry model changes update the
selected flow components instead of returning “No compatible components found.”
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 9a3740c0-c226-41cf-99fe-68528b3a3408
📒 Files selected for processing (3)
src/api/settings/langflow_sync.pysrc/services/flows_service.pysrc/utils/langflow_headers.py
| raise Exception("Azure AI Foundry endpoint URL is required.") | ||
|
|
||
| try: | ||
| if ".openai.azure.com" in endpoint.lower(): |
| "api-key": api_key, | ||
| "Content-Type": "application/json", | ||
| } | ||
| if ".openai.azure.com" in endpoint.lower(): |
| "api-key": api_key, | ||
| "Content-Type": "application/json", | ||
| } | ||
| if ".openai.azure.com" in endpoint.lower(): |
| endpoint = ( | ||
| self._config_manager.get_config().providers.azure_ai_foundry.endpoint or "" | ||
| ) | ||
| if ".openai.azure.com" in endpoint.lower(): |
| "use client"; | ||
|
|
||
| import { useQueryClient } from "@tanstack/react-query"; | ||
| import { AnimatePresence, motion } from "motion/react"; |
There was a problem hiding this comment.
React Doctor · react-doctor/use-lazy-motion (warning)
Importing "motion" ships about 30 kb of extra code and slows page load. Use "m" with LazyMotion instead.
Fix → Use import { LazyMotion, m } from "framer-motion" with domAnimation features. Saves about 30kb.
…2246) component_index.json ships under flows/ but is not a flow. COPY flows/ /app/flows/ puts it where Langflow scans for flows on startup, which crashes trying to load it as one. Remove the copy under /app/flows/ and keep only the one at LANGFLOW_COMPONENTS_INDEX_PATH (/app/component_index.json). The rm must run after USER root: as uid=1000 it fails on the /app/flows/ directory. Ports the two fixes already on main to azure-ai-rebase-main: b8cb84d fix: remove non flow json from flows 1e4455d fix: fixed dockerfile with wrong placement for removal of component index Co-authored-by: Edwin Jose <edwin.jose@ibm.com>
…point handling and embedding overrides
This pull request introduces comprehensive support for Azure AI Foundry and Azure OpenAI as new model providers in the frontend application. It includes changes to the environment configuration, settings management, API queries, and the user interface, allowing users to configure, validate, and manage these Azure providers alongside existing model providers.
Azure Provider Integration
OPENRAG_AZURE_AI_ENABLEDto.env.exampleto control the visibility and availability of Azure AI Foundry and Azure OpenAI providers in the application.ProviderSettingsandSettingsinterfaces to include configuration options and state forazure_ai_foundryandazure_openaiproviders, including deployment names and API versions. [1] [2]API and Query Enhancements
useGetAzureAIFoundryModelsQueryanduseGetAzureOpenAIModelsQuery, including parameter interfaces, for fetching and validating model lists from Azure AI Foundry and Azure OpenAI endpoints. [1] [2]useGetCurrentProviderModelsQueryto support Azure AI Foundry and Azure OpenAI, ensuring the correct models are fetched based on the active provider. [1] [2]Settings and Mutation Support
UpdateSettingsRequestinterface to support setting and removing Azure AI Foundry and Azure OpenAI credentials and endpoints, enabling full lifecycle management of these providers.User Interface Updates
AzureAIFoundrySettingsDialogcomponent, providing a dedicated UI for configuring, validating, testing, and removing Azure AI Foundry provider settings, with user feedback and error handling.These changes collectively enable seamless integration and management of Azure-based model providers within the application's frontend.
Summary by CodeRabbit