Files
IdeA/frontend/src/adapters/profileCatalog.ts
Blomios ca70ec75f4 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
2026-07-26 16:09:10 +02:00

64 lines
1.7 KiB
TypeScript

import type {
ModelCatalogSource,
ModelCompatibility,
ProfileModelCatalog,
ProfileModelCatalogEntry,
} from "@/domain";
type PartialCatalogEntry = Partial<ProfileModelCatalogEntry> & {
adapter?: "claude" | "codex";
modelId?: string;
displayName?: string;
};
function compatibilityOf(value: unknown): ModelCompatibility {
return value === "compatible" ||
value === "unknown" ||
value === "likelyTooRecent"
? value
: "unknown";
}
function sourceOf(value: unknown): ModelCatalogSource {
return value === "provider" ? "provider" : "catalogue";
}
function normalizeEntry(raw: PartialCatalogEntry): ProfileModelCatalogEntry {
const modelId = raw.modelId ?? "";
return {
adapter: raw.adapter ?? "codex",
modelId,
displayName: raw.displayName ?? modelId,
aliases: Array.isArray(raw.aliases) ? raw.aliases : [],
recommended: Boolean(raw.recommended),
compatibility: compatibilityOf(raw.compatibility),
source: sourceOf(raw.source),
};
}
export function normalizeProfileModelCatalog(raw: unknown): ProfileModelCatalog {
if (Array.isArray(raw)) {
return {
models: raw.map((entry) => normalizeEntry(entry as PartialCatalogEntry)),
cliVersion: null,
warnings: [],
};
}
const catalog =
raw && typeof raw === "object"
? (raw as Partial<ProfileModelCatalog>)
: {};
return {
models: Array.isArray(catalog.models)
? catalog.models.map((entry) => normalizeEntry(entry as PartialCatalogEntry))
: [],
cliVersion:
typeof catalog.cliVersion === "string" ? catalog.cliVersion : null,
warnings: Array.isArray(catalog.warnings)
? catalog.warnings.map(String)
: [],
};
}