Skip to content

Commit 9b9f7af

Browse files
viktoravelinojordanrfrazierautofix-ci[bot]HzaRashid
authored andcommitted
feat: deployment page and stepper UI with watsonx Orchestrate integration (#12303)
* feat: deployment page list * feat: add deployment stepper modal with context-based state management Implement a multi-step deployment creation flow with 4 steps (Provider, Type, Attach Flows, Review). State is centralized in a scoped DeploymentStepperContext to avoid prop-drilling across step components. Includes bug fixes for version re-selection and connection pre-selection. * feat: replace mock flows and versions with real API data in deployment stepper Fetch real flows from the API (scoped to current folder) and versions per-flow lazily when selected. Enrich selectedVersionByFlow context to store versionTag alongside versionId so the review step can display it without re-fetching. Remove MOCK_FLOWS_WITH_VERSIONS from mock-data. * refactor: improve deployment stepper code quality and conventions Rename all new deployment files to kebab-case per project conventions, fix context re-render issues with useMemo/useCallback, replace raw Tailwind colors with design tokens, add missing data-testid and ARIA attributes, fix Deploy button disabled on review step, and move shared FlowTabType to a dedicated types file. * refactor: align deployment provider types and UI to backend contracts - Rename ProviderInstance -> ProviderAccount to match backend naming - Update ProviderAccount fields to match DeploymentProviderAccountGetResponse (provider_key, provider_url, provider_tenant_id, created_at, updated_at) - Update ProviderCredentials fields to match DeploymentProviderAccountCreateRequest (provider_key, provider_url, api_key) - Rename all "instance" UI terminology to "environment" (tabs, labels, components) - Auto-select watsonx Orchestrate on mount as the only supported provider - Remove Kubernetes from mock providers; update mock data to use watsonx_orchestrate only * feat: add react-query hooks for deployments and provider accounts with mock data - Add useGetProviderAccounts hook (GET /deployments/providers) replacing direct MOCK_PROVIDER_INSTANCES import in step-provider.tsx - Add useGetDeployments hook (GET /deployments) replacing direct MOCK_DEPLOYMENTS import in deployments-page.tsx - Replace fake setTimeout loading state with hook isLoading state - Register DEPLOYMENTS and DEPLOYMENT_PROVIDER_ACCOUNTS URL constants - Real API calls are commented out with TODO markers for easy swap when backend is ready * chore: remove stale biome-ignore suppression in step-attach-flows * fix: replace button role=radio with semantic input type=radio in ProviderCard * fix: replace button role=radio with semantic radio inputs across deployment stepper - Extract RadioSelectItem component (label + sr-only input + checkbox indicator) used by version, connection, and environment selectors - Fix step-type.tsx type cards with label/input pattern (matching ProviderCard) - Add role="radiogroup" wrapper to EnvironmentList - Fix envVars key: use stable crypto.randomUUID() id instead of array index * feat: add name field to provider accounts, multi-select connections, and real API call - Add `name` field to ProviderAccount, ProviderCredentials, and mock data - Switch connection selection from single to multi-select (CheckboxSelectItem) - Allow creating new connections inline from the attach flows step - Lift connections state up to DeploymentStepperContext - Move ConnectionItem type from step-attach-flows to shared types.ts - Wire up real API call in useGetProviderAccounts (remove mock) * feat: wire deploy button and populate deployments page with real API data - Add usePostDeployment and usePostProviderAccount mutation hooks - Wire Deploy button in stepper modal: creates provider account if needed, then POSTs to /api/v1/deployments with WXO provider_data shape - Fix environment_variables payload: wrap values as { value, source: "raw" } to satisfy EnvVarValueSpec schema - Fix connection app_id: prefix with conn_ so WXO name validation passes (names must start with a letter) - Multi-select connections with checkbox UI; persist connections in context so they survive back/forward navigation - Update Deployment type to match API response shape; remove mock fields (url, status, health, lastModifiedBy) - Wire useGetDeployments to real API; load provider ID from useGetProviderAccounts - Update deployments table to display real fields: name, type, attached_count, provider name, updated_at * refactor: extract DeploymentsContent component to eliminate nested ternary * feat: add Test Deployment chat modal for deployed agents Implements a chat interface to test deployments directly from the UI. Wires up two entry points: the stepper modal "Test" button (inline transition) and the deployments table play button (standalone dialog). - Add usePostDeploymentExecution and useGetDeploymentExecution hooks hitting POST/GET /api/v1/deployments/executions - Build test-deployment-modal: ChatHeader, ChatMessages, ChatInput, ChatMessageBubble with user/bot avatars, loading dots, tool traces - useDeploymentChat hook: recursive setTimeout polling (max 30 × 1.5s), thread_id persistence for multi-turn, watsonx response parsing (response_type/type text, wxo_thread_id extraction) - Stepper modal transitions inline to TestDeploymentContent on Test click - Deployments table play button opens standalone TestDeploymentModal * feat: add syntax highlighting to chat code blocks using SimplifiedCodeTabComponent * feat: add action menu and icon-based type badge to deployments table - Add dropdown action menu (Duplicate, Update, Delete) to each row - Replace left-border type badge with icon-based badge (Bot for Agent, Plug for MCP) * refactor: remove connected status from provider card in stepper * feat: auto-detect flow env vars in deployment connection form - Add POST /deployments/variables/detections backend endpoint that scans flow version data for credential fields (load_from_db=True globals and password=True fallbacks) and returns detected variable names - Derive meaningful env var names from the model field's category when no global variable is linked (e.g. OPENAI_API_KEY from category "OpenAI") - Add DetectEnvVarsRequest/DetectedEnvVar/DetectEnvVarsResponse schemas - Add usePostDetectDeploymentEnvVars frontend mutation hook - Pre-populate Create Connection env var rows with detected keys/values when attaching a flow version; global variable selections render as tags via InputComponent with global variable picker support * feat: add empty state and smart default tab for available connections - Default to "Create Connection" tab when no connections exist - Show empty state with icon, description, and shortcut link when the Available Connections tab has no items * feat: redesign review step with two-column layout and env vars section Match new design reference with Deployment/Attached Flows columns and a masked Configuration section showing env variable keys. * feat: integrate delete deployment with loading state and fix test modal flow - Add useDeleteDeployment hook (DELETE /deployments/{id}, refetches list) - Show spinner + faded row while deletion is in progress; fix race where deleteTarget was cleared before isPending resolved by using separate deletingId state - Redesign StepDeployStatus with animated spinner, ping ring, and success checkmark - After deploy, "Test" closes the stepper and opens the standalone TestDeploymentModal (consistent UI, correct providerId, chat reset on close) - Prevent closing the stepper modal while deployment is in progress * refactor: address PR review concerns for deployment UI - Split step-attach-flows.tsx (656→274 lines) into FlowListPanel, VersionPanel, and ConnectionPanel sub-components - Extract Watsonx parser utilities into watsonx-result-parsers.ts, reducing use-deployment-chat.ts from 384 to 277 lines - Surface detectEnvVars errors via setErrorData instead of silently resetting state - Add EnvVarEntry named type to types.ts, replacing inline shape repeated across two files - Move import json to module level in deployments.py (PEP 8) - Fix URL construction in useGetDeploymentExecution to use axios params option, consistent with other hooks - Remove commented-out MOCK_CONNECTIONS dead code - Add TODO comment to hardcoded "watsonx-orchestrate" provider key * refactor: apply React best practices and remove mock data from deployment UI - Fix barrel imports: import directly from source files in deployments-page, step-provider, and step-attach-flows - Replace useEffect auto-select with derived effectiveFlowId in step-attach-flows - Fix async state init bug for environmentTab using useRef guard pattern - Fix stale closure in handleAddEnvVar with functional setState - Wrap useState initial value in lazy initializer for envVars - Wrap all 8 handlers in useCallback; wrap panel components in memo() - Remove mock-data.ts; move PROVIDERS constant inline to step-provider - Drop MOCK_CONNECTIONS (was empty array) from context - Simplify step-provider UI: remove provider selection radio group since only one provider exists; show watsonx Orchestrate as a static display * feat: add Deploy button to canvas toolbar Adds a primary-colored Deploy button at the far right of the canvas toolbar. Clicking it saves the flow, creates a version snapshot, and opens the deployment stepper modal with the current flow and version pre-selected in the Attach Flows step, including auto-detection of environment variable keys. * chore: disable ENABLE_DEPLOYMENTS feature flag * fix: forward LANGFLOW_FEATURE_WXO_DEPLOYMENTS env var to frontend The feature flag was reading from import.meta.env but the variable was never injected by Vite's define config, so the deployments feature was always disabled regardless of the .env value. * feat: implement providers tab with environment list Replace the "coming soon" placeholder in the Providers sub-tab with a real table showing existing provider accounts (name, URL, provider key, created date) fetched from the API, including loading skeleton and empty state. * feat: add provider creation modal with tab-aware action button Create AddProviderModal with name, API key, and URL fields matching the deploy modal. The top-right button now switches between "New Deployment" and "New Environment" based on the active sub-tab. * feat: implement provider account deletion with confirmation modal Add useDeleteProviderAccount hook, wire it through ProvidersContent and ProvidersTable with loading/disabled row state on delete, and reuse DeleteConfirmationModal for the confirmation flow. * fix: correct provider_key to watsonx-orchestrate and add API key visibility toggle Fix the provider_key value sent to the API. Add eye/eye-off toggle to the API Key input in both the add provider modal and the deploy stepper's provider step. * feat: navigate to deployments tab and open test modal after canvas deploy After a successful deployment from the canvas deploy button, clicking "Test" navigates to the deployments tab and auto-opens the test modal. Also adds eye toggle to the deploy stepper's API Key field. * Add llm config to deployment creation workflow * [autofix.ci] apply automated fixes * feat: add useGetDeploymentLlms query hook Add missing query hook for the GET /deployments/llms endpoint, resolving the broken import in step-type.tsx. * Create provider env inline of step Ensures the list llm call has an authed provider account to use * feat: add extensibility for wxo tools in deployments api (#12425) * feat(deployments): surface tool_ids in WXO API for explicit tool control - Fix bind to reuse existing WXO tools via attachment lookup instead of always creating new ones - Add tool_id-based operations (bind_tool, unbind_tool, remove_tool_by_id) alongside existing flow_version_id operations - Add PATCH /deployments/snapshots/{provider_snapshot_id} endpoint to update snapshot content with a new flow version (blast-radius bounded to Langflow-tracked tools only) - Add update_snapshot method to WXO adapter - Enrich flow version list with deployment info (tool_id, tool_name, app_ids) via FlowVersionReadWithDeployments API schema - Surface tool_id in WatsonxApiToolAppBinding responses; flow_version_id becomes optional for tool-id-based operations * Revert "feat: Add Langflow Assistant chat panel for component generation (#11636)" This reverts commit 61fac94139abfdfbc4cc7545dca712530d9e6777. * Add some comments * Reapply "feat: Add Langflow Assistant chat panel for component generation (#11636)" This reverts commit d7f08791f049c84f80cfb02827fec7f5464d59f8. * fix(deployments): review fixes for wxo tools extensibility PR - Add best-effort compensating rollback to update_snapshot endpoint - Add N+1 TODO for provider account batch-fetch in build_deployment_info_map - Remove unpopulated app_ids field from FlowVersionDeploymentInfo - Use elif chains in validate_operation_references for tool-id ops - Strip provider_snapshot_id once at function entry - Add note about WXO-only update_snapshot adapter method - Replace call-count-based _MultiQueryFakeDb with table-name dispatch - Fix SnapshotUpdateRequest docstring route path * fix doc --------- Co-authored-by: Jordan Frazier <jordan.frazier@datastax.com> * feat: allow attaching flows without connections in deployment stepper Connections are now optional when attaching flows in step 3. Users can skip the connection panel and proceed with just a version selected. The deploy payload iterates selectedVersionByFlow so flows without connections are included with an empty app_ids array. * feat: show attached connections per flow in deployment stepper Display connection names under each flow in the flow list panel so users can see what's attached at a glance. Refactor the review step to show configuration scoped per flow instead of a flat list. * remove unused enriched flow version data. to be replaced by a new endpoint in /deployments * Allow nonraw env vars wxo (#12435) Allow vars to be interpreted through global vars * feat: add update existing deployment from canvas deploy button (#12440) * feat: add update existing deployment from canvas deploy button When clicking Deploy on the canvas, if the flow already has existing deployments, a choice dialog is shown allowing the user to either update an existing deployment or create a new one. Updating calls PATCH /deployments/snapshots/{provider_snapshot_id} with the new flow version. Backend changes: - New GET /deployments/flow-attachments/{flow_id} endpoint to discover existing deployments for a flow - New CRUD function list_attachments_for_flow_with_deployment_info - New schemas FlowDeploymentAttachmentItem/FlowDeploymentAttachmentsResponse - Fix update_snapshot to properly construct flow_definition with nested data structure, name, description, and last_tested_version - Fix rollback path to cache ORM values before session.rollback() Frontend changes: - New useGetFlowDeploymentAttachments and usePatchSnapshot hooks - New DeployChoiceDialog component with radio selection - Modified deploy button to check for existing deployments on click * feat: add flow_ids filter to deployments endpoint and fix snapshot update Add a `flow_ids` query parameter to GET /deployments so the frontend can discover which deployments a flow is part of. The response includes a new `matched_attachments` field with per-attachment `flow_version_id` and `provider_snapshot_id`, replacing the non-existent flow-attachments endpoint. Refactor PATCH /snapshots to accept BaseFlowArtifact (via the mapper's new resolve_snapshot_update_artifact method) instead of a raw dict, fixing the misleading "Deployment name must include at least one alphanumeric character" error that occurred because flow_version.data lacks a name field. Frontend: rewrite useGetFlowDeploymentAttachments to query the real GET /deployments endpoint per provider account. * feat: refactor deploy dialog with update-snapshot flow and phased UI Restructure deploy-choice-dialog into modular phases (provider, review, deployment, update) to support both new deployments and snapshot updates. Add use-get-deployments-by-providers query replacing the removed flow-attachments endpoint, extract provider-credentials-form component, and add error/navigation helpers. Backend: validate flow_id as string in WatsonX Orchestrate service before deployment. * [autofix.ci] apply automated fixes * ruff --------- Co-authored-by: Hamza Rashid <hzarashid@gmail.com> Co-authored-by: Hamza Rashid <74062092+HzaRashid@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * feat: reorder model field and add scrollable dropdown in deploy wizard type step Move Model select to appear after Agent Name (before Description) and constrain the dropdown with max-height + scroll. A bouncing chevron indicator fades in/out to signal more items below. * feat(deployments): add paginated deployment flow-version listing (#12453) * feat(deployments): add paginated deployment flow-version listing with snapshot sync Add a new read path for listing flow versions attached to a deployment: - introduces GET /deployments/{deployment_id}/flows with page/size pagination - returns attachment-scoped metadata (flow_version id, flow_id, version_number, attached_at, provider_snapshot_id) - keeps provider-owned fields under provider_data on each item Implement snapshot-aware synchronization behavior for this list endpoint: - loads deployment attachments from DB, extracts provider_snapshot_id values, and verifies them via adapter list_snapshots(snapshot_ids=...) - removes stale attachment rows when snapshot IDs no longer exist on the provider - falls back to DB-only response without enrichment on any sync failure (including partial failures after list_snapshots) Refactor mapper boundaries to follow shape_* contract conventions: - helper now passes through SnapshotListResult | None instead of pre-building enrichment maps - route delegates full response shaping to mapper.shape_flow_version_list_result(...) - base mapper performs direct DB->API mapping for flow-version list items - WXO mapper overrides list shaping to enrich provider_data with connection_app_ids from snapshot binding.langflow.connections Normalize WXO connection extraction into a shared read-path helper: - add extract_langflow_connections_binding(...) in core/tools.py - reuse it in verify_tools_by_ids and service config listing to avoid duplicated nested payload parsing Add/adjust persistence and tests: - add CRUD helpers for paginated attachment+flow_version join and attachment counting - extend schema and route tests for new response models/endpoint behavior - add mapper tests for base direct mapping and WXO-specific enrichment - add sync tests for snapshot-id verification, stale-row cleanup, and fallback semantics * fix(deployments): normalize wxo snapshot provider_data contracts Validate and normalize snapshot connection payloads across mapper/service flows, and align flow-version item provider_data to use app_ids. Add typed snapshot-item schema support in lfx and expand tests for missing/malformed snapshot provider_data behavior. * add flow name * return empty app_ids list instead of null --------- Co-authored-by: Jordan Frazier <jordan.frazier@datastax.com> * ref: remove resource name prefix (#12459) * refactor: remove resource_name_prefix from all naming paths Remove the resource_name_prefix concept entirely. Tool names now use the exact flow name (or user-provided name in the future). Agent names use the deployment name directly with no prefix. BE: - Delete resource_name_prefix.py - Remove field + validators from API schemas (create + update) - Remove field + validators from adapter schemas (create + update) - Remove from mapper _build_provider_payload_body - Remove resource_prefix from ProviderCreatePlan and ProviderUpdatePlan - Remove tool_name_prefix from all tool creation functions - Remove resolve_resource_name_prefix from utils - Remove prefix constants from constants.py - Remove prefixed_deployment_name from config.py - Clean 5 test files (remove prefix-only tests, update payloads) FE: - Remove toResourceNamePrefix function from types.ts - Remove resource_name_prefix from DeploymentCreateRequest type - Remove usage from deployment-stepper-context.tsx payload builder * [autofix.ci] apply automated fixes * refactor: remove resource_name_prefix from all naming paths Remove the resource_name_prefix concept entirely. Tool names now use the exact flow name (or user-provided name in the future). Agent names use the deployment name directly with no prefix. BE: - Delete resource_name_prefix.py - Remove field + validators from API schemas (create + update) - Remove field + validators from adapter schemas (create + update) - Remove from mapper _build_provider_payload_body - Remove resource_prefix from ProviderCreatePlan and ProviderUpdatePlan - Remove tool_name_prefix from all tool creation functions - Remove resolve_resource_name_prefix from utils - Remove prefix constants from constants.py - Remove prefixed_deployment_name from config.py - Clean 5 test files (remove prefix-only tests, update payloads) FE: - Remove toResourceNamePrefix function from types.ts - Remove resource_name_prefix from DeploymentCreateRequest type - Remove usage from deployment-stepper-context.tsx payload builder --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * feat: wxo custom tool naming (#12460) feat: custom tool naming when attaching flows to deployments Users can now name tools when attaching flows in the deployment stepper. If left blank, the flow name is used as the tool name. BE: - Add optional tool_name field to WatsonxApiBindOperation - Mapper overrides raw_name_by_flow_version_id with user-provided tool_name - Apply custom name to both raw payloads and provider bind operations FE: - Add toolNameByFlow state + setToolNameByFlow to stepper context - Include tool_name in bind operations when set (trimmed, omitted if empty) - Tool Name input in version panel (shown when a version is selected) - Review step shows tool name (custom or flow name) in config cards with flow name + version underneath * feat(deployments): derive connection ID from user-provided name Replace random UUID generation with a sanitized version of the connection name. Input is restricted to alphanumeric, underscore, and space characters; spaces are converted to underscores in the ID. * feat(deployments): prevent duplicate connection names Disable the Create Connection button and show a validation error when a connection with the same name (case-insensitive) already exists. * refactor(deployments): extract page logic into custom hooks and self-contained tab components Extract state management from the monolithic DeploymentsPage into focused custom hooks (useDeleteWithConfirmation, useProviderFilter, useTestDeploymentModal) and consolidate each tab's modals into its own content component, reducing the page from 270 to 62 lines. * fix(deployments): forward thread_id through WxO execution lifecycle * fix(deployments): extract WxO tool call traces from actual step_history format The parser expected tool_use/tool_result fields but WxO returns type: "tool_calls" with tool_calls[] and type: "tool_response" — traces were never being extracted. Rewrites extractToolTraces to correlate calls with responses via tool_call_id, captures agent_display_name, and makes each trace individually expandable. * feat(deployments): refactor WXO deployment schemas and create response mapping (#12454) * feat(deployments): add paginated deployment flow-version listing with snapshot sync Add a new read path for listing flow versions attached to a deployment: - introduces GET /deployments/{deployment_id}/flows with page/size pagination - returns attachment-scoped metadata (flow_version id, flow_id, version_number, attached_at, provider_snapshot_id) - keeps provider-owned fields under provider_data on each item Implement snapshot-aware synchronization behavior for this list endpoint: - loads deployment attachments from DB, extracts provider_snapshot_id values, and verifies them via adapter list_snapshots(snapshot_ids=...) - removes stale attachment rows when snapshot IDs no longer exist on the provider - falls back to DB-only response without enrichment on any sync failure (including partial failures after list_snapshots) Refactor mapper boundaries to follow shape_* contract conventions: - helper now passes through SnapshotListResult | None instead of pre-building enrichment maps - route delegates full response shaping to mapper.shape_flow_version_list_result(...) - base mapper performs direct DB->API mapping for flow-version list items - WXO mapper overrides list shaping to enrich provider_data with connection_app_ids from snapshot binding.langflow.connections Normalize WXO connection extraction into a shared read-path helper: - add extract_langflow_connections_binding(...) in core/tools.py - reuse it in verify_tools_by_ids and service config listing to avoid duplicated nested payload parsing Add/adjust persistence and tests: - add CRUD helpers for paginated attachment+flow_version join and attachment counting - extend schema and route tests for new response models/endpoint behavior - add mapper tests for base direct mapping and WXO-specific enrichment - add sync tests for snapshot-id verification, stale-row cleanup, and fallback semantics * fix(deployments): normalize wxo snapshot provider_data contracts Validate and normalize snapshot connection payloads across mapper/service flows, and align flow-version item provider_data to use app_ids. Add typed snapshot-item schema support in lfx and expand tests for missing/malformed snapshot provider_data behavior. * add flow name * return empty app_ids list instead of null * feat(deployments): refactor WXO deployment schemas and create response mapping Restructure the Watsonx Orchestrate deployment contracts to remove redundant connection declaration and make create responses explicit and typed. - Remove `existing_app_ids` from API and adapter `connections` payload schemas. - Replace shared API payload base with separate create/update models and focused validators. - Keep validation strict (no legacy/backward-compat handling for removed fields). - Derive provider-side `existing_app_ids` in plan builders from: operation app_ids - connections.raw_payloads[*].app_id - Stop passing `existing_app_ids` through mapper payload translation. - Add explicit create response shaping via mapper (`shape_deployment_create_result`) and route integration. - Introduce typed create provider_data structure with `created_app_ids` and `tool_app_bindings`. - Document and enforce `source_ref` normalization semantics: UUID refs map to `flow_version_id`; non-UUID refs map to `None`; empty refs error. - Remove obsolete create-response helper path and align mapper interface signatures. - Update unit tests and assertions to reflect the new contract and validation wording. * improve api error logs (remove internal details and surface more informative message when an invalid field is provided * feat(deployments): API contract updates, bug fixes, and observability improvements BREAKING CHANGES (API): - Move variable detection endpoint from POST /deployments/variables/detections to POST /variables/detections (variables router) - Rename `reference_ids` to `flow_version_ids` in DetectVarsRequest schema - Remove `existing_app_ids` from WXO create/update connection payloads - Remove `resource_name_prefix` from WXO create/update payloads - Add optional `tool_name` field to WXO bind operations Backend: - Rename DetectEnvVarsRequest/Response to DetectVarsRequest/Response (internal) - Fix tool name mismatch (`name_of_raw not found in tools.raw_payloads`) during deployment updates by applying tool_name override and aligning filtered_raw_payloads with name-updated artifacts in the WXO mapper - Fix "Missing snapshot bindings for added flow versions on update" by filtering out already-attached flow version IDs in the route handler before calling resolve_added_snapshot_bindings_for_update (stateless, DB-backed filtering) - Switch WXO adapter core modules (retry, update, shared, create, tools) from stdlib logging to lfx.log.logger (structlog) for consistent log output - Upgrade rollback log calls from info to warning level for visibility - Add logger.exception() calls in handle_adapter_errors() for DeploymentServiceError, NotImplementedError, and ValueError to surface provider errors (e.g. validation failures) in backend logs with tracebacks Frontend: - Remove existingAppIds from deployment stepper context and create payload - Move detect-env-vars hook from deployments/ to variables/ query directory - Update step-attach-flows import path and payload field (flow_version_ids) Tests: - Add 15 unit tests for detect_env_vars endpoint and _derive_env_var_name helper - Add 3 route-handler tests for already-attached flow version filtering on update - Update WXO adapter tests: drop existing_app_ids, fix agent name assertions, fix mock signatures, adapt logging test for structlog * fix: harden detect_env_vars endpoint against abuse - Add max_length=50 on flow_version_ids to prevent resource exhaustion - Hide /detections from OpenAPI schema (consistent with other variable routes) - Return unresolved_ids in response so callers know which version IDs were skipped * feat: add update agent impl (#12475) * Allow updating an agent ONLY allows attaching and detaching Flows. Does NOT allow attaching / detaching connections, or editing attached tool names. * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * remove print * add missing files * mypy * Add edit flow tests * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * feat: add list all conns impl for wxo create deploy workflow (#12476) * feat(deployments): list all WXO tenant connections in create workflow - Fix backend list_configs to handle SDK Pydantic model objects (not just dicts) - Add useGetDeploymentConfigs hook to fetch tenant connections by provider - Seed existing connections into the attach-flows step on mount - Add search/filter input for the available connections list - Raise configs endpoint page size cap to 10k for large tenants * test(deployments): add list_configs tests for Pydantic model handling Cover the fix where SDK ConnectionsClient.list() returns Pydantic model objects instead of dicts: pure models, mixed dicts+models, deduplication, and non-dict/non-model skip behavior. * add todo * [autofix.ci] apply automated fixes * fix(tests): update imports for removed to_deployment_create_response helper The helper was replaced by BaseDeploymentMapper.shape_deployment_create_result in the schema refactor (#12454). Update both test files to use the new method. * fix(tests): remove shape_deployment_create_result from passthrough test Method signature changed from single-arg passthrough to (result, deployment_row) in the schema refactor (#12454). It's now tested in test_deployment_description_and_type.py. * tests --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * feat(deployments): improve attach flow step UX in deploy modal (#12482) - Add detach flow button in both create and edit modes - Defer version attachment until connection step is completed (skip/attach) - Replace radio indicators with clickable version items that auto-advance to connections - Move tool name editing to review page with inline edit/confirm pattern - Sort newly created connections to top of list and remove variable count display - Add visual distinction (blue border/bg) for attached versions - Split review page connections into "Existing" and "New" sections * feat(deployments): add expandable rows to show attached flows (#12483) Allow users to click the "Attached" count in the deployments table to expand a row showing the flow names and versions. Flows are fetched lazily via GET /deployments/{id}/flows only when the row is expanded. * feat(deployments): replace Duplicate with Details modal (#12492) feat(deployments): replace Duplicate action with Details modal Replace the unused "Duplicate" action menu item with a "Details" option that opens a read-only modal showing deployment info, attached flows, and their connections. Data is fetched via useGetDeployment, useGetDeploymentAttachments, and useGetDeploymentConfigs. * Add wxo lfx req override * feat(wxo): tool name handling, rename support, and ownership safety (#12502) * feat(wxo): tool name handling, rename support, and ownership safety - Fix update_snapshot to preserve existing wxO tool name instead of deriving from flow name (prevents overwriting custom tool names) - Add _validate_tool_name at API boundary with deferred validation so user-provided tool_name overrides aren't blocked by invalid flow names - Add rename_tool operation (API + provider + plan + apply) with safety checks: tool must be on agent, must exist, must have binding.langflow - Add verify_langflow_owned guard to all tool mutation paths (create, update, rename) to prevent modifying non-Langflow-managed tools - Add WXO_LFX_REQUIREMENT_OVERRIDE env var for lfx version pinning - Pre-seed resolved_connections from existing agent tools during update - Surface tool_name in /flows endpoint response from wxO snapshot data - Pre-populate tool names and connections in edit mode stepper (FE) - Emit rename_tool operations from FE when pre-existing tool name changes - Sort attached flows to top of flow list in edit mode (FE) - Fix FE sending unsupported existing_app_ids field in update payload - Add 24 backend + 6 frontend tests covering ownership checks, rename safety, name validation, plan building, env var override, and payloads * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * chore(wxo): trim verbose pre-seeding logs, add plan entry/exit logging - Condense per-tool pre-seeding debug logs into a single summary line - Add plan summary log at entry of apply_provider_create_plan_with_rollback - Add plan summary log at entry of apply_provider_update_plan_with_rollback - Add agent creation result log in create path * fix(wxo): resolve mypy, ruff, and lint errors - Fix dict[str, str] → dict[UUID, str] type annotation for raw_name_by_flow_version_id in mapper create/update paths (mypy) - Move logger assignment after imports in config.py (ruff E402) - Remove unnecessary result variable in shared.py (ruff TRY300/RET504) - Add raise-from chain in tools.py _resolve_lfx_requirement (ruff B904) - Hoist class aliases to module level in tests (ruff N806) * fix(wxo): resolve mypy, ruff, and lint errors - Fix dict[str, str] → dict[UUID, str] type annotation for raw_name_by_flow_version_id in mapper create/update paths (mypy) - Use .items() for dict iteration instead of key-only loop (ruff PLC0206) - Move logger assignment after imports in config.py (ruff E402) - Remove unnecessary result variable in shared.py (ruff TRY300/RET504) - Add raise-from chain in tools.py _resolve_lfx_requirement (ruff B904) - Split long log format string in create.py (ruff E501) - Hoist class aliases to module level in tests (ruff N806) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * refactor(deployments): Revise v1 deployments API (#12478) * refactor(deployments): trim top-level deployment API surface for WXO-first flow - Remove unused deployment stub routes and schemas: - drop POST /deployments/{deployment_id}/redeploy and /duplicate handlers - remove DeploymentRedeployResponse and DeploymentDuplicateResponse usage - remove corresponding route-handler unit tests - Simplify deployment list response contract: - remove deployment_type from DeploymentListResponse - update deployments route and base/WXO mapper list shapers to stop passing deployment_type - Make deployment request schemas API-owned and stricter: - replace shared-kernel strict wrappers with DeploymentSpec / DeploymentSpecUpdate - remove create/update top-level config and flow-version mutation fields (flow_version_ids, add_flow_version_ids, remove_flow_version_ids, config) - tighten update validation to only accept spec and/or provider_data - Align mapper behavior with trimmed API contracts: - base mapper create/update now maps spec explicitly to BaseDeploymentData/BaseDeploymentDataUpdate - remove base create/update handling for top-level snapshot/config/flow-version passthrough - make base util_create_flow_version_ids and util_flow_version_patch return empty results by default - update WXO mapper to use explicit spec mapping and provider_data-only operation reconciliation - remove WXO 422 guards tied to removed top-level config/flow-version request fields - Remove obsolete provider_spec plumbing in adapter schema/utilities: - drop ProviderSpecModel and T_DeploymentSpec usage from lfx deployment schema - make BaseDeploymentData inherit directly from BaseModel - remove unused build_agent_payload helper that depended on provider_spec from WXO utils - Update tests to reflect the trimmed contracts and current behavior: - remove schema tests for removed config/flow-version helper models - update schema compatibility tests to reject provider_spec in API deployment spec - update base mapper tests for new create-result shaping and provider payload validation expectations - remove WXO mapper tests asserting rejected top-level config/flow-version inputs - adjust WXO mapper naming assertions to current flow/tool naming behavior - update sync/service/payload formalization tests for provider_data-driven operations and provider_spec removal * refactor(deployments): normalize deployment metadata and list payload contracts - Source `get_deployment` name/description/type/timestamps from DB deployment rows and stop injecting `resource_key` into provider payloads. - Clarify schema docs that `resource_key` is provider-originated but Langflow-owned once persisted. - Replace `DeploymentConfigListItem`/`DeploymentSnapshotListItem` response envelopes with paginated `provider_data` payloads in API schemas. - Update base deployment mapper to serialize config/snapshot items directly into paginated `provider_data.configs` and `provider_data.snapshots`. - Add WXO API payload models and validation slots for config-list and snapshot-list provider result metadata. - Add WXO adapter payload result contracts (`WatsonxConfigListResultData`, `WatsonxSnapshotListResultData`) and register them in deployment payload schemas. - Update WXO service list-config/list-snapshot flows to parse and emit normalized provider result metadata (tenant scope now `{}`, deployment scope includes `deployment_id` and optional `tool_ids`). - Remove `provider_data` from `lfx` `ConfigListItem` to align with the new list response contract. - Update mapper registration tests to assert config/snapshot payload slots are wired. - Update route-handler tests for new provider-result expectations and add regression coverage that `resource_key` is not injected into `provider_data`. - Rewrite deployment schema tests around provider-data-only config/snapshot list responses and field-surface checks. - Update WXO service tests for tenant-scope provider-result normalization. - Update `lfx` schema tests to remove obsolete config-item `provider_data` assertions. * feat(deployments): add WXO mapper shaping for config-list and snapshot-list responses - Add `shape_config_list_result` and `shape_snapshot_list_result` to WXO deployment mapper with pagination, slot validation, and HTTP 500 on malformed payloads. - Add `WatsonxApiConfigListItem` and `WatsonxApiSnapshotListItem` strict payload models with string normalization validators. - Wire `configs` and `snapshots` item lists into the existing `WatsonxApiConfigListProviderData` and `WatsonxApiSnapshotListProviderData` provider-data envelopes. - Add mapper unit tests for config-list slot validation, snapshot-list connections extraction, and malformed-payload rejection. - Remove obsolete `resource_name_prefix` and `connections` from deployment-sync update test fixture. * feat(deployments): add provider identity to responses, nest execution endpoints under deployments Surface provider_id and provider_key on all deployment responses so clients can identify which provider owns a deployment without a side lookup. Nest execution endpoints under their parent deployment path and drop redundant deployment_id / provider_id parameters that clients previously had to supply. Deployment responses: - Add provider_id (UUID) and provider_key (str) to _DeploymentResponseBase, propagating to DeploymentGetResponse, DeploymentCreateResponse, DeploymentUpdateResponse, DeploymentStatusResponse, and DeploymentListItem. - Add provider_key parameter to BaseDeploymentMapper.shape_deployment_create_result, shape_deployment_update_result, and shape_deployment_list_items. - Update WatsonxOrchestrateDeploymentMapper overrides to match. - Update resolve_adapter_from_deployment to return (row, adapter, provider_key) and resolve_adapter_mapper_from_deployment to return (row, adapter, mapper, provider_key). - All route handlers pass provider_key through to shape methods and response constructors. Execution endpoints: - POST /executions → POST /deployments/{deployment_id}/executions. deployment_id moves from the request body to the URL path. - GET /executions/{execution_id}?deployment_id=... → GET /deployments/{deployment_id}/executions/{execution_id}. deployment_id moves from a query param to the URL path. - Remove deployment_id from ExecutionCreateRequest schema. - Remove unused resolve_adapter_mapper_from_provider_id import. Tests: - Update all mapper tests to pass provider_key and assert provider_id / provider_key on shaped responses. - Update route handler mocks for new helper return tuple sizes. - Remove deployment_id from ExecutionCreateRequest test constructions. - Fix pre-existing broken test_deployments_response_mapping.py (was importing removed to_deployment_create_response helper; now uses BaseDeploymentMapper.shape_deployment_create_result). * refactor(deployments): delegate conflict error messaging to provider mappers Move provider-specific conflict formatting out of shared helpers by adding a base mapper hook and a Watsonx override, thread mapper-aware conflict formatting through adapter error handling, and add tests for mapper delegation and fallback behavior. * refactor(deployments): rename provider-account API fields and make update identifiers immutable - rename provider-account API fields for cleaner contracts: - create/get: provider_tenant_id -> tenant_id - create/get: provider_url -> url - keep provider_key and provider_data unchanged - enforce immutable provider-account identifiers on PATCH: - remove tenant_id and url from DeploymentProviderAccountUpdateRequest - remove update-path URL allowlist validation - trigger update credential verification only when provider_data changes - limit provider-account updates to name and provider_data - simplify mapper update behavior: - resolve_provider_tenant_id now uses tenant_id parameter naming - remove no-op WXO resolve_provider_account_update override - remove dead auth_utils/decrypt path in WXO update verification - align frontend deployment-provider-account usage with new API fields: - POST payload now sends url - ProviderAccount/ProviderCredentials now use tenant_id/url - deployment provider UI components now read/write url consistently - update deployment mapper rules and backend tests for new contract - verify with targeted backend tests: 245 passed * fix(deployments): flatten API payloads, normalize execution routes, and trim null response fields - flatten v1 deployment API request contracts by removing nested `spec` from create/update payloads - create now uses top-level `name`, `description`, `type` - update now uses top-level `name`, `description`, `provider_data` - update backend handlers and mapper wiring to consume top-level deployment fields end-to-end - fix execution route paths to avoid duplicated segment: - `/api/v1/deployments/{deployment_id}/executions` - `/api/v1/deployments/{deployment_id}/executions/{execution_id}` - align frontend execution query hooks/chat flow with deployment-id path params and remove provider-id execution params - add response null-trimming tweaks in deployment read/list endpoints: - set `response_model_exclude_none=True` on deployment list route - set `response_model_exclude_none=True` on deployment get route - normalize empty/non-dict `provider_data` to `None` before shaping detail response - tighten watsonx API mapper payload contract: - type `connections.raw_payloads[*].environment_variables` as `dict[EnvVarKey, EnvVarValueSpec]` - remove unused API-level `provider_config` field from update raw connection payload - refresh backend/frontend tests and deployment endpoint docs to match current API shapes and routes * feat(deployments): redesign list contracts and normalize WXO payloads Rework deployment list and flow attachment contracts to support flow-filtered list responses and lazy flow-version lookup in the frontend deploy dialog. Normalize WXO provider payload shapes by flattening provider entries, renaming identifier fields, and tightening adapter/API validation. - replace deployment list-item matched_attachments with conditional flow_version_ids (omitted when no flow filter is provided) - add flow_ids support to GET /api/v1/deployments/{id}/flows and propagate it through deployment sync helpers and flow_version_deployment_attachment CRUD filters - flatten load_from_provider deployment entries, rename provider resource_key to id, and validate WXO entries with explicit fields - rename WXO provider_data snapshot_ids to tool_ids for provider list/config metadata payloads - inline WXO provider list entry model_validate payload construction for cleaner mapper logic - add deployment description max-length contract in adapter/API schemas and enforce it in deployment CRUD create/update paths - update frontend deploy-choice dialog to a two-request flow (list deployments first, fetch /flows on selection) and align FE deployment types/query hook params - refresh mapper/route/schema/sync/frontend tests and add dedicated CRUD tests for deployment description length validation * feat(deployments): align WXO provider_data list and connection payload contracts - make provider-only deployment list responses use provider_data.deployments and omit top-level deployments/pagination fields - rename config/snapshot provider_data list keys to connections and tools, and move page/size/total into provider_data - remove provider_data.deployment_id from config/snapshot list payload shaping - rename API connection input fields from raw_payloads to key_value and environment_variables to credentials - add explicit credential item model (key/value/source) with duplicate-key validation - map API credentials list back to adapter environment_variables dict in mapper for adapter compatibility - make shared pagination fields optional in deployment response schemas and update config-list provider_data description to "connections" - set response_model_exclude_none on /configs and /snapshots list routes to suppress unused top-level null pagination fields - apply formatter quote normalization in WXO config validation debug log * feat(deployments): add connection type to config listings, enforce security_scheme, and trim leaked adapter fields - Config list items now expose a `type` field derived from the provider's `security_scheme`, enabling callers to distinguish connection types (e.g. `key_value_creds`) without a separate lookup - Requests that return provider_data without a valid `security_scheme` now fail fast with HTTP 500 instead of silently omitting the type - Config list responses no longer leak `tool_ids` or `deployment_id` — these were adapter-internal fields with no frontend or API consumers - Snapshot list responses no longer leak `deployment_id` * feat(deployments): flatten WXO API operations into per-entity keyed fields Replace the discriminated `operations` array with explicit per-entity fields for better type safety and developer experience: - Create: `add_flows` + `upsert_tools` (create-only item, no remove_app_ids) - Update: `upsert_flows` + `upsert_tools` + `remove_flows` + `remove_tools` Each item carries its own add/remove app-id deltas instead of relying on op-tag dispatch. The mapper consumes the new shapes directly and produces unchanged adapter-layer operations, eliminating all isinstance dispatch. Also corrects FlowVersionPatch semantics: upsert_flows.remove_app_ids now only unbinds connections without detaching the flow from the agent; detachment is exclusively driven by remove_flows. * feat(deployments): align watsonx create/update payloads and created-tools responses - Add `resource_key` to deployment create/update API responses and mapper output. - Replace API-facing `tool_app_bindings` with `created_tools` in watsonx mapper responses. - Shape `created_tools` from created snapshot/tool refs only (not all referenced tools). - Flatten request `provider_data.connections` from nested `connections.key_value` to a direct list. - Add duplicate `connections.app_id` validation using Counter and update related validation messages. - Document connection typing strategy: implicit key_value today, future type field with default. - Add strict `flow_version_id` validation on `WatsonxApiCreatedTool` (accept UUID or UUID string; reject other types/invalid UUIDs). - Update mapper/unit tests for new response contract, flattened connections, and non-UUID rejection. * fix(deployments): allow watsonx updates without llm Make PATCH provider_data.llm optional in the Watsonx deployment flow while preserving create-time llm requirements. - allow missing llm in the API update payload model - only include llm in mapper-built provider payloads when explicitly provided - remove adapter update-schema validation that required llm for update operations - clarify validator docs for empty/no-op provider_data handling - update mapper/service/schema tests to accept update payloads without llm * fix(deployments): normalize wxo config list to connection_id/app_id and fix provider_accounts naming Align the config-list contract end-to-end so that items are keyed by connection_id + app_id (matching the upstream SDK model) instead of opaque id/name pairs derived from dict introspection. Backend: - Reshape mapper/payloads to emit connection_id/app_id/type. - Replace loose dict/model_dump parsing with strict ListConfigsResponse type checks; add _build_config_list_item factory and _normalize_optional_text with documented SDK quirk guards. - Enrich deployment-scope configs with security_scheme type via get_drafts_by_ids. - Rename DeploymentProviderAccountListResponse.providers to provider_accounts for consistency with the entity name. - Remove leftover debug print/hardcoded requirements in core/tools. Frontend: - Migrate DeploymentConfigItem to connection_id/app_id/type and unwrap provider_data.connections in the query hook. - Access provider_accounts instead of providers on the list response. - Add onBlur confirm for editable tool names; fix overflow/truncation in the connection panel. Tests: - Use real ListConfigsResponse SDK model in service tests. - Add scope-shape consistency, type preservation, dict-filtering, and mapper contract tests. * fix(deployments): remove stale-tool fallback in list_snapshots and log unresolved IDs Replace the phantom-stub fallback that synthesized SnapshotItems for agent-referenced tool IDs when get_drafts_by_ids returned no results. Those tools were likely deleted on the provider, and returning stubs with the ID as the name and empty connections masked stale references and risked corrupting downstream attachment sync. Now returns only snapshots that actually resolve from the provider and logs a warning with the stale tool IDs for observability. Also handles partial resolution (some tools found, some not). Update existing test to provide real tool data and add coverage for all-stale and partial-resolution scenarios. * fix(deployments): fail fast on invalid wxo config entries and trust provider identifiers Fail fast when wxO returns unexpected config-list entry types, and preserve provider-provided connection/app identifiers without local normalization or deduplication. Also narrow conflict-detail mapping for connection errors to real conflict messages and update tests to match the new behavior. * refactor: move tenant_id from top-level into provider_data for provider accounts tenant_id is a provider-specific concept (e.g., WXO tenant vs Azure AD tenant vs AWS account_id) and does not have universal semantics across deployment providers. Moving it into provider_data keeps the top-level API surface limited to Langflow-universal fields (id, name, provider_key, url, timestamps) and lets each provider define its own metadata shape. API schema changes: - DeploymentProviderAccountCreateRequest: remove top-level tenant_id field; tenant_id now arrives inside provider_data alongside api_key - DeploymentProviderAccountGetResponse: remove top-level tenant_id; add provider_data field for non-sensitive provider metadata (e.g. {"tenant_id": "..."} for WXO); credentials are excluded - DeploymentProviderAccountUpdateRequest: unchanged (already uses provider_data for credential rotation) Base mapper (base.py): - resolve_provider_tenant_id: signature changed from (provider_url, tenant_id) to (provider_url, provider_data); delegates to new resolve_provider_tenant_id_from_data() for extraction/validation - shape_provider_account_response: now includes provider_data via new shape_provider_account_provider_data() method that returns non-sensitive metadata (tenant_id when present) WXO mapper (watsonx_orchestrate/mapper.py): - resolve_provider_tenant_id: updated signature; extracts tenant_id from provider_data first, falls back to URL extraction - _validate_provider_data: strips mapper-owned metadata keys (tenant_id) before passing to WatsonxVerifyCredentialsPayload slot (extra=forbid) - New _credential_provider_data() helper for metadata/credential separation Route + helpers: - deployments.py create_provider_account: passes payload.provider_data (not payload.tenant_id) to resolve_provider_tenant_id - helpers.py resolve_provider_tenant_id: updated parameter from tenant_id to provider_data Frontend: - ProviderAccount type: replaced tenant_id with optional provider_data RULES.md: updated credential flow and defense-in-depth sections to reflect provider_data as the source for provider metadata. Tests: updated schema, base mapper, WXO mapper, and route handler tests to use provider_data for tenant_id. Added tests for tenant metadata passthrough, credential field filtering, and top-level tenant_id rejection. Fixed two pre-existing test stubs missing resource_key. No DB model or migration changes -- provider_tenant_id column remains; the mapper extracts it from provider_data and stores it as before. * fix: follow deployment boundary rules and fail fast (wxo) (#12539) * feat(wxo): filter configs to key_value_creds, surface type and environment, harden mapper contract Service layer (service.py): - Filter list_configs to only return connections with security_scheme == "key_value_creds" in both tenant and deployment scopes - Surface `environment` field alongside `type` in provider_data for config list items - Normalize security_scheme via _normalize_optional_text to handle SDK enum/tuple quirks - Extract _warn_if_expected_ids_missing helper to deduplicate staleness warnings - Remove defensive isinstance checks on provider responses (trust the provider) - Replace conflicting-binding error with last-write-wins (app_to_connection_id.update) - Deduplicate connection IDs before calling get_drafts_by_ids Mapper layer (mapper.py): - Fail fast with HTTP 500 if config list item is missing a truthy `type` - Conditionally include `environment` in shaped config list payload Payloads (payloads.py): - Add `environment: str | None` field to WatsonxApiConfigListItem with normalizing validator Tests: - Add test for deployment-scope key_value_creds filtering (mixed security schemes) - Add test for tenant-scope key_value_creds filtering (oauth2 excluded) - Add test for environment metadata passthrough in mapper and service - Add tests for provider failure paths (tenant list failure, None response, tool fetch failure) - Add tests for edge cases (latest-binding-wins, skip enrichment with no connections, malformed detailed connection) - Update mapper tests to assert fail-fast on missing type - Update existing fixtures to include security_scheme where required by new filtering * refactor(deployments): move flow-version tool_name into provider_data Move provider tool_name from a top-level flow-version response field into provider_data, aligning API ownership boundaries for provider-originated non-persisted fields. - Remove top-level tool_name from DeploymentFlowVersionListItem - Add tool_name to WatsonxApiDeploymentFlowVersionItemData with normalization - Update WXO mapper to shape tool_name under provider_data - Update frontend attachments type and consumer to read provider_data.tool_name - Update backend tests for new response contract location - Add explicit RULES.md requirement for non-persisted provider data placement * make environment required * refactor list configs method and fix broken tests * feat(deployments): type-to-confirm dialog for deployment deletion (#12546) * feat(deployments): replace simple delete confirm with type-to-confirm dialog Deleting a deployment is irreversible — it removes the agent from both Langflow and Watsonx Orchestrate permanently. Require the user to type the deployment name before the Delete button activates, matching industry-standard patterns (GitHub, AWS). - Add `TypeToConfirmDeleteDialog` component (deployment-specific, not shared) - Input resets on close; label + placeholder for accessibility - Replace `DeleteConfirmationModal` in `deployments-content.tsx` - 6 unit tests covering all confirmation behaviours * fix(deployments): address PR review findings on type-to-confirm dialog - Fix icon spacing: replace pr-1 with mr-2 on AlertTriangle (padding was compressing the SVG viewport instead of creating sibling spacing) - Fix label copy: "agent name" → "deployment name" to cover both agent and MCP deployment types - Remove unused cancelDelete from useDeleteWithConfirmation — callers close the dialog via setModalOpen; the export was dead code - Add case-sensitivity test to type-to-confirm-delete-dialog tests - Add unit tests for useDeleteWithConfirmation hook (8 tests covering requestDelete, confirmDelete, onSettled, onError, and setModalOpen) * test(deployments): add comprehensive frontend test suite for WXO deployments (#12535) * test(deployments): add unit tests for all deployment API query and mutation hooks 16 test files covering deployment queries, mutations, provider accounts, execution hooks, and env var detection (59 tests total). * test(deployments): add stepper context create-mode tests and expand edit-mode/tool-naming coverage Step 2 of the frontend deployment test plan — 63 new tests (93 total) covering create-mode payload builders, step validation, provider selection, multi-flow scenarios, partial update payloads, detach/re-attach flows, and tool naming edge cases. * test(deployments): add component rendering tests for Step 3 (163 tests, 10 files) Covers tables, stepper steps, connection panel, and modals with data-testid additions to source components for reliable targeting. * test(deployments): add custom hook unit tests for Step 4 (121 tests, 7 files) Covers useErrorAlert, useProviderFilter, useNavigateToTest, useDeleteWithConfirmation, useTestDeploymentModal, useDeploymentChat (polling, thread_id, timeouts, tool traces), and watsonx-result-parsers (extractText, extractToolTraces, extractThreadId). * test(deployments): add deploy button and choice dialog unit tests for Step 5 (76 tests, 3 files) - deploy-button.test.tsx (12 tests): feature-flag rendering, disabled states (no flow/preparing/dialog open), handleDeploy click, animate-pulse on icon - deploy-choice-dialog/index.test.tsx (30 tests): phase transitions (provider → deployments → review → update), auto-select single attachment, provider key mapping, patchSnapshot args, update/error flows, onUpdateComplete - deploy-choice-dialog/hooks/use-prepare-deploy.test.ts (34 tests): handleDeploy save/snapshot/provider fetch, no-flow bail-out, deployModal vs choiceDialog branching, error handling, handleChooseNew, handleUpdateComplete, resetChoiceState * test(deployments): add E2E Playwright tests for Step 6 (28 tests, 5 files) - deployments-page.spec.ts: page nav, empty/loaded states (5 tests) - deployment-create.spec.ts: full create wizard, POST, deploy status (6 tests) - deployment-edit.spec.ts: edit mode, PATCH, cancel (5 tests) - deployment-providers.spec.ts: add/delete providers, confirmation (6 tests) - deployment-test-modal.spec.ts: chat, polling, multi-turn, reset (6 tests) Add shared deployment-mocks.ts for mock data reuse across all specs. Add data-testid to stepper modal title, add-provider modal title, and test-deployment modal title to avoid strict-mode selector violations. Add data-testid to provider radio items in step-provider.tsx. Set LANGFLOW_FEATURE_WXO_DEPLOYMENTS=true in CI workflow env. * fix(tests): update deployment E2E mocks for wxo-fe API changes - provider_accounts field rename: { providers } → { provider_accounts } - ProviderAccount.provider_url → ProviderAccount.url - Execution endpoints moved to deployment-scoped URLs: POST /deployments/executions → /deployments/{id}/executions GET /deployments/executions/{exec_id} → /deployments/{id}/executions/{exec_id} - Remove deployment_id from POST execution request body (now in URL path) * fix(tests): update unit tests for wxo-fe API shape changes - ProviderAccount: provider_url → url, removed provider_tenant_id - Provider list response: { providers } → { provider_accounts } - ProviderCredentials: provider_url → url - Deployment payload: spec.{name,description,type} → top-level fields - Provider data: operations → add_flows/upsert_flows/remove_flows - Connections: raw_payloads[].environment_variables → connections[].credentials - DeploymentConfigItem: { id, name } → { app_id, connection_id } * fix(tests): align frontend tests with revised deployments API shape Update unit tests, E2E mocks, and the ProviderAccountListResponse type to match the API changes from the v1 deployments revision (#12478): - execution endpoints now use deployment_id in URL path - getExecution uses deployment_id + execution_id (no provider_id) - provider accounts response key changed to provider_accounts - deployment configs response wrapped in provider_data - deploy-choice-dialog now uses useGetDeploymentAttachments * fix(ci): read LANGFLOW_FEATURE_WXO_DEPLOYMENTS from process.env fallback Vite config only read feature flags from the .env file via dotenv, ignoring CI workflow environment variables. This caused all 28 deployment E2E tests to fail because the flag was never enabled. * fix(tests): add missing resource_key to deployment mapper test mocks The SimpleNamespace mocks in TestCreateResponse and TestMapperUpdateResult were missing the resource_key attribute now required by the mapper. * test(deployments): add E2E tests for type-to-confirm deployment deletion Adds testid to the delete dropdown item and four Playwright tests covering: - dialog opens on delete action - confirm button disabled until name matches exactly - confirming with correct name calls DELETE /api/v1/deployments/{id} - cancel dismisses without calling DELETE * chore: trigger CI * fix(deployments): remove unused description field from connection panel (#12549) The Description input in the Create Connection tab was never persisted — ConnectionItem has no description field and the value was not sent to any API. * fix(deployments): enforce single-environment filter on deployments page (#12551) fix(deployments): enforce single-environment filter and reorder provider form fields Remove the "All environments" global listing mode from the deployments page. Deployments are now always fetched for a single selected environment, avoiding N parallel API calls that each trigger a backend sync. Also differentiates empty states (no providers vs no deployments) and reorders the provider credentials form to show URL before API key. * be test * be test --------- Co-authored-by: Jordan Frazier <jordan.frazier@datastax.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Hamza Rashid <74062092+HzaRashid@users.noreply.github.com> Co-authored-by: Hamza Rashid <hzarashid@gmail.com> Co-author…
1 parent f60e644 commit 9b9f7af

20 files changed

Lines changed: 1441 additions & 166 deletions

File tree

.secrets.baseline

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2936,14 +2936,6 @@
29362936
}
29372937
],
29382938
"src/backend/tests/unit/api/v1/test_deployment_schemas.py": [
2939-
{
2940-
"type": "Secret Keyword",
2941-
"filename": "src/backend/tests/unit/api/v1/test_deployment_schemas.py",
2942-
"hashed_secret": "99091d046a81493ef2545d8c3cd8e881e8702893",
2943-
"is_verified": false,
2944-
"line_number": 49,
2945-
"is_secret": false
2946-
},
29472939
{
29482940
"type": "Secret Keyword",
29492941
"filename": "src/backend/tests/unit/api/v1/test_deployment_schemas.py",

src/backend/base/langflow/api/v1/deployments.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,7 @@ async def get_deployment_status(
14001400
)
14011401
async def list_deployment_flow_versions(
14021402
deployment_id: DeploymentIdPath,
1403-
session: DbSessionReadOnly,
1403+
session: DbSession,
14041404
current_user: CurrentActiveUser,
14051405
page: Annotated[int, Query(ge=1)] = 1,
14061406
size: Annotated[int, Query(ge=1, le=50)] = 20,

src/backend/base/langflow/api/v1/mappers/deployments/base.py

Lines changed: 107 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -679,26 +679,105 @@ async def resolve_rollback_update(
679679
_ = (user_id, deployment_db_id, deployment_resource_key, db)
680680
return None
681681

682+
def shape_deployment_update_result(
683+
self,
684+
*,
685+
rows: list[tuple[FlowVersionDeploymentAttachment, FlowVersion, str | None]],
686+
snapshot_result: SnapshotListResult | None,
687+
page: int,
688+
size: int,
689+
total: int,
690+
) -> DeploymentFlowVersionListResponse:
691+
_ = snapshot_result
692+
flow_versions = [
693+
DeploymentFlowVersionListItem(
694+
id=flow_version.id,
695+
flow_id=flow_version.flow_id,
696+
flow_name=flow_name,
697+
version_number=flow_version.version_number,
698+
attached_at=attachment.created_at,
699+
provider_snapshot_id=(attachment.provider_snapshot_id or "").strip() or None,
700+
provider_data=None,
701+
)
702+
for attachment, flow_version, flow_name in rows
703+
]
704+
return DeploymentFlowVersionListResponse(
705+
flow_versions=flow_versions,
706+
page=page,
707+
size=size,
708+
total=total,
709+
)
710+
711+
def shape_deployment_create_result(
712+
self,
713+
result: DeploymentCreateResult,
714+
deployment_row: Deployment,
715+
*,
716+
provider_key: str,
717+
) -> DeploymentCreateResponse:
718+
provider_data = result.provider_result if isinstance(result.provider_result, dict) else None
719+
return DeploymentCreateResponse(
720+
id=deployment_row.id,
721+
provider_id=deployment_row.deployment_provider_account_id,
722+
provider_key=provider_key,
723+
name=deployment_row.name,
724+
description=deployment_row.description,
725+
type=deployment_row.deployment_type,
726+
created_at=deployment_row.created_at,
727+
updated_at=deployment_row.updated_at,
728+
resource_key=deployment_row.resource_key,
729+
provider_data=provider_data,
730+
)
731+
682732
def shape_deployment_update_result(
683733
self,
684734
result: DeploymentUpdateResult,
685735
deployment_row: Deployment,
736+
*,
737+
provider_key: str,
686738
) -> DeploymentUpdateResponse:
687739
provider_data = result.provider_result if isinstance(result.provider_result, dict) else None
688740
return DeploymentUpdateResponse(
689741
id=deployment_row.id,
742+
provider_id=deployment_row.deployment_provider_account_id,
743+
provider_key=provider_key,
690744
name=deployment_row.name,
691745
description=deployment_row.description,
692746
type=deployment_row.deployment_type,
693747
created_at=deployment_row.created_at,
694748
updated_at=deployment_row.updated_at,
749+
resource_key=deployment_row.resource_key,
695750
provider_data=provider_data,
696751
)
697752

698-
def resolve_provider_tenant_id(self, *, provider_url: str, provider_tenant_id: str | None) -> str | None:
753+
def resolve_provider_tenant_id(
754+
self,
755+
*,
756+
provider_url: str,
757+
provider_data: dict[str, Any],
758+
) -> str | None:
699759
"""Resolve provider tenant id for provider-account create/update."""
700760
_ = provider_url
701-
return provider_tenant_id
761+
return self.resolve_provider_tenant_id_from_data(provider_data=provider_data)
762+
763+
def resolve_provider_tenant_id_from_data(self, *, provider_data: dict[str, Any]) -> str | None:
764+
"""Extract optional tenant/account identifier from provider_data."""
765+
raw_tenant_id = provider_data.get("tenant_id")
766+
if raw_tenant_id is None:
767+
return None
768+
if not isinstance(raw_tenant_id, str):
769+
msg = "provider_data.tenant_id must be a string when provided."
770+
raise ValueError(msg) # noqa: TRY004 - route layer maps ValueError to HTTP 4xx
771+
tenant_id = raw_tenant_id.strip()
772+
return tenant_id or None
773+
774+
def format_conflict_detail(self, raw_message: str) -> str:
775+
"""Format provider conflict errors for API responses.
776+
777+
Provider-specific mappers may override this to map provider-native
778+
conflict wording to clearer end-user guidance.
779+
"""
780+
return f"A resource with this name already exists in the provider. {raw_message}"
702781

703782
def resolve_credential_fields(
704783
self,
@@ -723,24 +802,19 @@ def resolve_provider_account_update(
723802
"""Assemble DB column-value kwargs for a provider-account update.
724803
725804
Only fields present in ``payload.model_fields_set`` are included so
726-
the CRUD layer receives a minimal diff. Provider mappers may override
727-
to add cross-field logic (e.g. re-deriving tenant from URL).
805+
the CRUD layer receives a minimal diff. Provider-account update fields
806+
are intentionally limited to mutable values (display name and
807+
credentials).
728808
"""
809+
_ = existing_account
729810
update_kwargs: dict[str, Any] = {}
730811
if "name" in payload.model_fields_set:
731812
update_kwargs["name"] = payload.name
732-
if "provider_url" in payload.model_fields_set:
733-
update_kwargs["provider_url"] = payload.provider_url
734813
if "provider_data" in payload.model_fields_set:
735814
if payload.provider_data is None:
736815
msg = "'provider_data' cannot be null when provided."
737816
raise ValueError(msg)
738817
update_kwargs.update(self.resolve_credential_fields(provider_data=payload.provider_data))
739-
if "provider_tenant_id" in payload.model_fields_set:
740-
update_kwargs["provider_tenant_id"] = self.resolve_provider_tenant_id(
741-
provider_url=payload.provider_url or existing_account.provider_url,
742-
provider_tenant_id=payload.provider_tenant_id,
743-
)
744818
return update_kwargs
745819

746820
def resolve_verify_credentials(
@@ -755,7 +829,7 @@ def resolve_verify_credentials(
755829
provider mapper overrides.
756830
"""
757831
return VerifyCredentials(
758-
base_url=payload.provider_url,
832+
base_url=payload.url,
759833
)
760834

761835
def resolve_verify_credentials_for_update(
@@ -766,12 +840,12 @@ def resolve_verify_credentials_for_update(
766840
) -> VerifyCredentials | None:
767841
"""Build adapter verify-credentials input for provider-account updates.
768842
769-
Returns ``None`` when the update does not touch credentials or URL.
843+
Returns ``None`` when the update does not touch credentials.
770844
Provider-specific mappers must override this when update-time
771845
verification is supported.
772846
"""
773847
_ = existing_account
774-
if "provider_url" not in payload.model_fields_set and "provider_data" not in payload.model_fields_set:
848+
if "provider_data" not in payload.model_fields_set:
775849
return None
776850
msg = "Credential verification for provider account updates is not implemented for this provider."
777851
raise NotImplementedError(msg)
@@ -783,13 +857,26 @@ def shape_provider_account_response(
783857
return DeploymentProviderAccountGetResponse(
784858
id=provider_account.id,
785859
name=provider_account.name,
786-
provider_tenant_id=provider_account.provider_tenant_id,
787860
provider_key=provider_account.provider_key,
788-
provider_url=provider_account.provider_url,
861+
url=provider_account.provider_url,
862+
provider_data=self.shape_provider_account_provider_data(provider_account),
789863
created_at=provider_account.created_at,
790864
updated_at=provider_account.updated_at,
791865
)
792866

867+
def shape_provider_account_provider_data(
868+
self,
869+
provider_account: DeploymentProviderAccount,
870+
) -> dict[str, Any] | None:
871+
"""Return non-sensitive provider metadata for provider-account responses."""
872+
raw_tenant_id = provider_account.provider_tenant_id
873+
if raw_tenant_id is None:
874+
return None
875+
tenant_id = str(raw_tenant_id).strip()
876+
if not tenant_id:
877+
return None
878+
return {"tenant_id": tenant_id}
879+
793880
def util_create_flow_artifact_provider_data(
794881
self,
795882
*,
@@ -805,7 +892,8 @@ def util_create_flow_artifact_provider_data(
805892

806893
def util_create_flow_version_ids(self, payload: DeploymentCreateRequest) -> list[UUID]:
807894
"""Resolve flow-version ids referenced by create payload."""
808-
return list(payload.flow_version_ids or [])
895+
_ = payload
896+
return []
809897

810898
def util_existing_deployment_resource_key_for_create(
811899
self,
@@ -893,10 +981,8 @@ def util_flow_version_patch(self, payload: DeploymentUpdateRequest) -> FlowVersi
893981
894982
Contract schema: ``FlowVersionPatch``.
895983
"""
896-
return FlowVersionPatch(
897-
add_flow_version_ids=list(payload.add_flow_version_ids or []),
898-
remove_flow_version_ids=list(payload.remove_flow_version_ids or []),
899-
)
984+
_ = payload
985+
return FlowVersionPatch()
900986

901987
def util_snapshot_ids_to_verify(
902988
self,

src/backend/base/langflow/api/v1/mappers/deployments/helpers.py

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -303,25 +303,6 @@ def raise_http_for_value_error(exc: ValueError) -> None:
303303
raise HTTPException(status_code=status_code, detail=str(exc)) from exc
304304

305305

306-
def _friendly_conflict_message(raw_message: str) -> str:
307-
"""Rewrite provider conflict errors into user-friendly messages."""
308-
lower = raw_message.lower()
309-
if "agent" in lower and ("already exists" in lower or "conflict" in lower):
310-
return (
311-
"An agent with this name already exists in the provider. "
312-
"Please choose a different name or delete the existing agent first."
313-
)
314-
if "connection" in lower or "app_id" in lower:
315-
return (
316-
"A connection referenced in this request already exists in the provider. "
317-
"Reference it as an existing connection instead of creating a new one."
318-
)
319-
if "tool" in lower and ("already exists" in lower or "conflict" in lower):
320-
return "A tool with this name already exists in the provider. Please choose a different name."
321-
# Fall back to a cleaned-up version of the raw message.
322-
return f"A resource with this name already exists in the provider. {raw_message}"
323-
324-
325306
@contextmanager
326307
def handle_adapter_errors(*, mapper: BaseDeploymentMapper | None = None):
327308
"""Map deployment adapter exceptions to appropriate HTTP responses.
@@ -378,6 +359,28 @@ async def flow_version_ids_for_flows(db, *, flow_ids: list[UUID], user_id: UUID)
378359
return list((await db.exec(stmt)).all())
379360

380361

362+
def normalize_flow_ids_query(flow_ids: list[UUID] | None) -> list[UUID]:
363+
"""Return a deduplicated list from an already-validated ``flow_ids`` query param.
364+
365+
``FlowIdsQuery`` (Pydantic) handles UUID parsing and max-length
366+
validation, so this is intentionally thin.
367+
"""
368+
if not flow_ids:
369+
return []
370+
return list(dict.fromkeys(flow_ids))
371+
372+
373+
async def flow_version_ids_for_flows(db, *, flow_ids: list[UUID], user_id: UUID) -> list[UUID]:
374+
"""Return all flow-version IDs belonging to the given flows and user."""
375+
if not flow_ids:
376+
return []
377+
stmt = select(FlowVersion.id).where(
378+
col(FlowVersion.flow_id).in_(flow_ids),
379+
FlowVersion.user_id == user_id,
380+
)
381+
return list((await db.exec(stmt)).all())
382+
383+
381384
async def get_owned_provider_account_or_404(
382385
*,
383386
provider_id: UUID,

0 commit comments

Comments
 (0)