feat: catalogue dynamique modèles Codex/Claude avec compatibilité CLI locale

Ajout du catalogue enrichi pour les modèles Codex et Claude avec:
- Compatibilité estimée avec la version CLI locale détectée
- Source d'origine (catalogue/Provider) pour chaque entrée
- Support du catalogue Provider API externe
- Matrice de compatibilité embarquée dans l'application

Frontend:
- UI de configuration des modèles avec affichage des états de compatibilité
- Suggestions dynamiques avec badges de compatibilité
- Messages d'aide contextuels (compatible/unknown/likelyTooRecent)
- Alertes non-bloquantes pour les modèles trop récents
- Gestion des échecs de catalogue avec saisie manuelle conservée

Backend:
- Ports CliVersionReader, ProviderModelCatalogue, CompatibilityMatrixSource
- Implémentations: ProcessCliVersionReader, HttpProviderModelCatalogue, EmbeddedCompatibilityMatrix
- Enrichissement des DTOs avec compatibility, cli_version, warnings
- Tests unitaires complets pour le resolver de catalogue
This commit is contained in:
2026-07-26 16:09:10 +02:00
parent e7bf1d3666
commit ca70ec75f4
25 changed files with 1582 additions and 167 deletions

View File

@ -1067,6 +1067,10 @@ pub struct ProfileModelCatalogEntryDto {
pub aliases: Vec<String>,
/// Whether this entry is the conservative default suggestion.
pub recommended: bool,
/// Compatibility state against the locally detected CLI version.
pub compatibility: domain::ModelCompatibility,
/// Source that contributed the model entry.
pub source: domain::ModelCatalogSource,
}
impl From<application::ProfileModelCatalogEntry> for ProfileModelCatalogEntryDto {
@ -1077,24 +1081,41 @@ impl From<application::ProfileModelCatalogEntry> for ProfileModelCatalogEntryDto
display_name: entry.display_name,
aliases: entry.aliases,
recommended: entry.recommended,
compatibility: entry.compatibility,
source: entry.source,
}
}
}
/// A list of curated structured-profile models.
/// Enriched structured-profile model catalogue.
#[derive(Debug, Clone, Serialize)]
#[serde(transparent)]
pub struct ProfileModelCatalogDto(pub Vec<ProfileModelCatalogEntryDto>);
#[serde(rename_all = "camelCase")]
pub struct ProfileModelCatalogDto {
/// The catalogue entries.
pub models: Vec<ProfileModelCatalogEntryDto>,
/// Best-effort local CLI version.
pub cli_version: Option<String>,
/// Non-fatal fallback/degradation warnings.
pub warnings: Vec<String>,
}
impl From<application::ListClaudeModelsOutput> for ProfileModelCatalogDto {
fn from(out: application::ListClaudeModelsOutput) -> Self {
Self(out.models.into_iter().map(Into::into).collect())
Self {
models: out.models.into_iter().map(Into::into).collect(),
cli_version: out.cli_version.map(|version| version.raw),
warnings: out.warnings,
}
}
}
impl From<application::ListCodexModelsOutput> for ProfileModelCatalogDto {
fn from(out: application::ListCodexModelsOutput) -> Self {
Self(out.models.into_iter().map(Into::into).collect())
Self {
models: out.models.into_iter().map(Into::into).collect(),
cli_version: out.cli_version.map(|version| version.raw),
warnings: out.warnings,
}
}
}