feat: finalise multi-profil Codex/Claude avec catalogue de modèles
- Backend : clone_profile_from_seed généralisé (non OpenCode) - Backend : catalogue static Claude/Codex (3 modèles chacun, 1 recommandé) - Backend : commandes Tauri list_claude_models/list_codex_models - Frontend : ProfilesSettings refonte en onglets Codex/Claude + create/duplicate/edit/delete - Frontend : ModelSelect searchable partagé + fallback saisie manuelle - Frontend : assignation agent nom · modèle - Tests QA : 4 profils modèles distincts (2 Claude, 2 Codex) assignés à agents
This commit is contained in:
@ -4,15 +4,17 @@
|
||||
|
||||
use app_tauri_lib::dto::{
|
||||
parse_delete_profile, parse_profile_id, CloneOpenCodeProfileFromSeedRequestDto,
|
||||
ConfigureProfilesRequestDto, DetectProfilesRequestDto, DetectProfilesResponseDto,
|
||||
FirstRunStateDto, ProfileListDto, SaveProfileRequestDto,
|
||||
CloneProfileFromSeedRequestDto, ConfigureProfilesRequestDto, DetectProfilesRequestDto,
|
||||
DetectProfilesResponseDto, FirstRunStateDto, ProfileListDto, ProfileModelCatalogDto,
|
||||
SaveProfileRequestDto,
|
||||
};
|
||||
use application::{
|
||||
CloneOpenCodeProfileFromSeedInput, ConfigureProfilesInput, DetectProfilesInput,
|
||||
DetectProfilesOutput, FirstRunStateOutput, ProfileAvailability, SaveProfileInput,
|
||||
CloneOpenCodeProfileFromSeedInput, CloneProfileFromSeedInput, ConfigureProfilesInput,
|
||||
DetectProfilesInput, DetectProfilesOutput, FirstRunStateOutput, ProfileAvailability,
|
||||
SaveProfileInput,
|
||||
};
|
||||
use domain::ids::{LocalModelServerId, ProfileId};
|
||||
use domain::profile::{AgentProfile, ContextInjection, OpenCodeConfig};
|
||||
use domain::profile::{AgentProfile, ContextInjection, OpenCodeConfig, StructuredAdapter};
|
||||
use serde_json::json;
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -121,6 +123,41 @@ fn clone_opencode_profile_from_seed_request_deserialises_camelcase_config() {
|
||||
assert_eq!(opencode.local_model_server_id, Some(server_id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clone_profile_from_seed_request_deserialises_camelcase_overrides() {
|
||||
let seed_id = Uuid::from_u128(42);
|
||||
let raw = json!({
|
||||
"seedProfileId": seed_id.to_string(),
|
||||
"name": "Codex GPT-5",
|
||||
"model": "gpt-5-codex"
|
||||
});
|
||||
|
||||
let dto: CloneProfileFromSeedRequestDto = serde_json::from_value(raw).unwrap();
|
||||
let input: CloneProfileFromSeedInput = dto.into();
|
||||
assert_eq!(input.seed_profile_id, ProfileId::from_uuid(seed_id));
|
||||
assert_eq!(input.name.as_deref(), Some("Codex GPT-5"));
|
||||
assert_eq!(input.model.as_deref(), Some("gpt-5-codex"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn profile_model_catalogue_dto_serialises_searchable_camelcase_entries() {
|
||||
let dto = ProfileModelCatalogDto(vec![app_tauri_lib::dto::ProfileModelCatalogEntryDto {
|
||||
adapter: StructuredAdapter::Codex,
|
||||
model_id: "gpt-5-codex".to_owned(),
|
||||
display_name: "GPT-5 Codex".to_owned(),
|
||||
aliases: vec!["codex".to_owned()],
|
||||
recommended: true,
|
||||
}]);
|
||||
|
||||
let value = serde_json::to_value(&dto).unwrap();
|
||||
let arr = value.as_array().expect("transparent array");
|
||||
assert_eq!(arr[0]["adapter"], "codex");
|
||||
assert_eq!(arr[0]["modelId"], "gpt-5-codex");
|
||||
assert_eq!(arr[0]["displayName"], "GPT-5 Codex");
|
||||
assert_eq!(arr[0]["aliases"], json!(["codex"]));
|
||||
assert_eq!(arr[0]["recommended"], true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn opencode_config_dto_omits_local_model_server_id_when_none() {
|
||||
let config = OpenCodeConfig::new(
|
||||
|
||||
Reference in New Issue
Block a user