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
64 lines
1.7 KiB
TypeScript
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)
|
|
: [],
|
|
};
|
|
}
|