feat: flag deprecated models and redesign admin models table#315
Open
MaxEriksson2000 wants to merge 17 commits intodevelopfrom
Open
feat: flag deprecated models and redesign admin models table#315MaxEriksson2000 wants to merge 17 commits intodevelopfrom
MaxEriksson2000 wants to merge 17 commits intodevelopfrom
Conversation
Enrich API responses with deprecation_date from litellm.model_cost at serialization time. Models past their deprecation date are automatically flagged as deprecated. The frontend shows red/yellow labels in the Details column and exposes a Migrate action directly in the dropdown menu for deprecated completion models. Also adds SDK functions for migration history endpoints (already existed in backend but were never wired to frontend) and a Migration History tab in the admin models page. Backend: - New deprecation_lookup utility with get_litellm_deprecation_date() - deprecation_date field on CompletionModelPublic, EmbeddingModelPublic, TranscriptionModelPublic (computed at serialization, no DB migration) - 21 new unit tests covering lookup and enrichment logic Frontend: - Red "Deprecated" / yellow "Retiring YYYY-MM-DD" labels in ModelLabels - Migrate button in ModelActions dropdown for deprecated models - getMigrationHistory/getAllMigrationHistory SDK functions - MigrationHistoryPanel component + tab in admin/models page - Translation keys for EN and SV
Replace the dense tag-based table with a cleaner design: - Remove Details column tags, replace with compact status icons (ModelStatusIcons: deprecation, reasoning, vision, tools) - Remove Security column (moved to ModelDetailDialog) - Add status indicator dot on each model name (green/red/yellow/gray) - New ModelDetailDialog: click model name to see full details (capabilities, hosting, security, metadata, deprecation alert) - Deprecation warning banner above table with model count - Row tinting for deprecated/retiring models (CSS :has selector) - Reorder dropdown actions: neutral first, destructive last - Migrate action available for all completion models, not just deprecated - Enable Vite polling for HMR in Docker dev environment
…istory
Migration validation:
- New GET /completion-models/{id}/migration-validate endpoint for preflight
- Server-side compatibility check on target selection (no client-side approx)
- Security classification blocker: prevents migration to lower-classified model
when spaces require higher classification (cannot be overridden)
- Race condition fix: stale validation responses discarded
- Dual warning format: human-readable warnings + machine-readable warning_codes
Migration execution:
- Fix kwargs reset being a blocker (now informational only)
- Remove auto-delete that ran even on failure; delete only after success
- Spaces included in default migration via MIGRATABLE_ENTITY_TYPES
- Audit logging with COMPLETION_MODEL_MIGRATED action type
Migration history:
- Alembic migration: FK ondelete CASCADE → SET NULL, add model name columns
- Store from_model_name/to_model_name at creation (survives model deletion)
- ModelMigrationHistory: model IDs now Optional[UUID]
- Expandable detail rows: breakdown per entity type, warnings, errors, duration
- Auto-refresh via migrationHistoryRefreshVersion store
Migration dialog UX:
- Impact preview: shows affected resources grouped by type with details
- Collapsible sections per entity type (assistants, apps, questions)
- Spaces info: "Target model will be enabled on N spaces"
- Preflight warnings shown on target selection with translated messages
- Security blocker shown as red panel, disables migrate button
- SDK: validateMigration, getUsageStats, getUsageDetails functions
48 new unit tests across 3 files: - test_migration_validation.py (22): compatibility checks, security blockers, warning codes, kwargs reset, multiple warnings combined - test_migration_history.py (15): stored model names, SET NULL handling, Pydantic nullable IDs, fallback logic, serialization roundtrip - test_migration_endpoint.py (11): audit action type, category mapping, metadata, ValidationResult/MigrationRequest schema tests Updated existing tests for warning_codes field and audit action registration.
- Fix security classification blocker check: was searching for codes in warnings (human-readable text) instead of warning_codes. With confirm_migration=true, a security-blocked migration could pass through. - Fix impact preview total: usage/details endpoint now counts real total across all entity types via separate COUNT queries, instead of returning len(items) which was just the current page size.
Move scattered model settings into a unified flow: - ModelDetailDialog is now read-only info view - EditModelDialog handles all editing: parameters, security classification, default model status - ModelActions dropdown simplified to Edit, Migrate, Delete - Table status dots: red=disabled, icons for deprecated/retiring - SelectSecurityClassification trigger now full-width
6 tasks
Security classification can now be set when adding a model, so admins don't need to create and then immediately edit to set classification. Uses a separate API call after create since the backend create endpoint doesn't accept security_classification directly.
Table name column now shows only the display name — model identifier and context window moved to the detail dialog. Detail dialog always shows both display name and model identifier with consistent styling.
Questions are historical records that must not be migrated — doing so falsely attributes answers to the target model and corrupts token usage analytics. Changes: - Exclude questions from MIGRATABLE_ENTITY_TYPES - Add migrated_to_model_id (FK RESTRICT) and deleted_at to completion_models - Change questions FK from SET NULL to RESTRICT as safety net - Mark source model with migrated_to_model_id after successful migration - Block re-migration of already-migrated models (both preflight and execute) - Soft-delete replaces hard-delete in both tenant and sysadmin endpoints - Update can_access in all three paths (domain, AIModelsService, pydantic) - Filter migrated/deleted models from space assembler, model selection UIs - Add MODEL_IN_USE check before soft-delete via shared has_active_references - Frontend: remove auto-delete after migration, add Migrated label, lock enable switch, exclude migrated from target lists and space settings
Automatically hard-deletes completion models once all references are gone (questions gallrad, active entities migrated, no migration pointers). - Weekly ARQ cron job (Sunday 4 AM) targeting soft-deleted and migrated models - Reuses shared has_active_references from CompletionModelsRepository - Reconciles soft-deleted template FK references before hard-delete - IntegrityError classified as db_restrict skip, not unexpected error - Preserves migration history via immutable from/to_model_original_id columns - History service falls back to original_id when FK is SET NULL after cleanup - Indexes on deleted_at, migrated_to_model_id, and original_id columns
… migration history Simplify the migration history model: remove from/to_model_original_id (dead UUIDs pointing to deleted rows) and replace with provider_type snapshots that give readable audit context. - Remove from_model_original_id and to_model_original_id columns - Add from_provider_type and to_provider_type as audit snapshots - Backfill provider_type from model_providers for existing records - Simplify repo queries to only match live FK IDs (no OR fallback) - History service returns None for model IDs after cleanup (not stale UUIDs) - Per-model history works for live models; use tenant/migration_id after cleanup
Fixes svelte-package failing to generate type declarations due to inferred types referencing internal @melt-ui/svelte modules.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR combines three related improvements to completion model management:
Why
We had two related problems in practice:
This PR separates those concerns properly:
What Changed
1. Deprecated model status in admin
2. Admin model management UX redesign
3. Safer model migration lifecycle
Questions are historical records and are never migrated. Active configuration is migrated to the target model, while questions keep their original
completion_model_id.graph LR subgraph migration["Migration: A → B"] A["Model A<br/>(source)"] -->|"active config migrated"| B["Model B<br/>(target)"] A -.->|"migrated_to_model_id"| B end subgraph preserved["Preserved references"] Q1["Question 1"] -.->|"completion_model_id = A"| A Q2["Question 2"] -.->|"completion_model_id = A"| A Q3["Question 3"] -.->|"completion_model_id = A"| A endcompletion_model_id.migrated_to_model_idinstead of being deleted during the migration flow.Safety layers:
can_accessblocks migrated + deleted models in all 3 pathsis_completion_model_available()enforced in assistant/app/service creationquestions.completion_model_idandmigrated_to_model_id4. Lifecycle cleanup for retired models
Added a weekly cleanup worker (ARQ cron, Sunday 4 AM) that hard-deletes models once all references are gone.
graph LR Start(( )) --> Active Active -->|LiteLLM flags| Deprecated Active -->|admin deletes| SoftDeleted Deprecated -->|admin migrates| Migrated Migrated -->|"cleanup job"| CleanedUp SoftDeleted -->|"cleanup job"| CleanedUp Migrated -. "questions still exist" .-> Migrated SoftDeleted -. "questions still exist" .-> SoftDeleted CleanedUp["Cleaned Up<br/>(hard-deleted, history preserved)"]Cleanup eligibility — ALL must be true:
deleted_at IS NOT NULLormigrated_to_model_id IS NOT NULL)migrated_to_model_idpointing to itSoft-deleted templates are reconciled (FK cleared) before hard-delete.
IntegrityErrorfrom RESTRICT FK is classified asdb_restrict(skip, not error).5. Migration history and auditability
History records survive model cleanup via snapshot fields, not dead UUIDs.
graph TD subgraph before["Before cleanup"] H["Migration History<br/>from_model_id = A (FK)<br/>to_model_id = B (FK)<br/>from_model_name = gpt-3.5-turbo<br/>from_provider_type = openai"] MA["Model A"] MB["Model B"] H -->|FK| MA H -->|FK| MB end subgraph after["After cleanup removes Model A"] H2["Migration History<br/>from_model_id = NULL (SET NULL)<br/>to_model_id = B (FK)<br/>from_model_name = gpt-3.5-turbo ✓<br/>from_provider_type = openai ✓"] MB2["Model B"] H2 -->|FK| MB2 endfrom_model_name/to_model_name— snapshot ofCompletionModels.nameat migration timefrom_provider_type/to_provider_type— snapshot of provider for audit readabilityfrom_model_id/to_model_id— live FK, becomes NULL after cleanup (by design)migration_idafter cleanupSemantics to Note
from_model_id/to_model_idin migration history only represent live model rows.Testing
Added and updated focused unit and integration coverage for:
All 151 completion model + AI model tests pass.
Closes
Closes #316
Closes #317
Closes #320
Closes #323