feat(backend): support des providers OpenCode cloud (#92)
Ajoute le catalogue statique de providers OpenCode (lot B3), le stockage sécurisé des secrets (SecretStore + adapter infrastructure), et les use cases SaveOpenCodeProviderProfile/DeleteProfile câblés en composition root. Couvre le fix B1 et les tests de régression demandés par QA. cargo build --workspace propre, cargo test --workspace -- --test-threads=1 intégralement vert. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -996,7 +996,8 @@ use application::{
|
||||
CloneOpenCodeProfileFromSeedInput, CloneOpenCodeProfileFromSeedOutput, ConfigureProfilesInput,
|
||||
ConfigureProfilesOutput, DeleteProfileInput, DetectProfilesInput, DetectProfilesOutput,
|
||||
FirstRunStateOutput, ListProfilesOutput, ProfileAvailability, ReferenceProfilesOutput,
|
||||
SaveProfileInput, SaveProfileOutput,
|
||||
SaveOpenCodeProviderProfileInput, SaveOpenCodeProviderProfileOutput, SaveProfileInput,
|
||||
SaveProfileOutput,
|
||||
};
|
||||
use domain::profile::{AgentProfile, OpenCodeConfig};
|
||||
use domain::ProfileId;
|
||||
@ -1043,6 +1044,40 @@ impl From<CloneOpenCodeProfileFromSeedOutput> for ProfileDto {
|
||||
}
|
||||
}
|
||||
|
||||
/// One entry of the static OpenCode cloud-provider catalogue (ticket #92, lot B3).
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OpenCodeProviderDto {
|
||||
/// Identifier in the OpenCode provider registry (e.g. `"anthropic"`).
|
||||
pub provider_id: String,
|
||||
/// Human-readable label for the picker UI.
|
||||
pub display_name: String,
|
||||
/// Model names this provider serves, offered for selection.
|
||||
pub models: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<application::OpenCodeProviderCatalogEntry> for OpenCodeProviderDto {
|
||||
fn from(entry: application::OpenCodeProviderCatalogEntry) -> Self {
|
||||
Self {
|
||||
provider_id: entry.provider_id.to_owned(),
|
||||
display_name: entry.display_name.to_owned(),
|
||||
models: entry.models.iter().map(|&m| m.to_owned()).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of OpenCode cloud-provider catalogue entries (camelCase array on the
|
||||
/// wire).
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct OpenCodeProviderListDto(pub Vec<OpenCodeProviderDto>);
|
||||
|
||||
impl From<application::ListOpenCodeProvidersOutput> for OpenCodeProviderListDto {
|
||||
fn from(out: application::ListOpenCodeProvidersOutput) -> Self {
|
||||
Self(out.providers.into_iter().map(Into::into).collect())
|
||||
}
|
||||
}
|
||||
|
||||
/// Request DTO for `detect_profiles`: the candidate profiles to probe.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -1105,6 +1140,39 @@ impl From<SaveProfileRequestDto> for SaveProfileInput {
|
||||
}
|
||||
}
|
||||
|
||||
/// Request DTO for `save_opencode_provider_profile` (ticket #92, lot B3): the
|
||||
/// profile to upsert plus the literal provider fields. `apiKey` never reaches
|
||||
/// `profiles.json` — the use case seals it into the `SecretStore`.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SaveOpenCodeProviderProfileRequestDto {
|
||||
/// The profile to create or replace (by id).
|
||||
pub profile: AgentProfile,
|
||||
/// Provider id in the OpenCode registry (e.g. `"anthropic"`).
|
||||
pub provider_id: String,
|
||||
/// Model name served by this provider.
|
||||
pub model: String,
|
||||
/// Literal API key, sealed into the `SecretStore` — never persisted as-is.
|
||||
pub api_key: String,
|
||||
}
|
||||
|
||||
impl From<SaveOpenCodeProviderProfileRequestDto> for SaveOpenCodeProviderProfileInput {
|
||||
fn from(dto: SaveOpenCodeProviderProfileRequestDto) -> Self {
|
||||
Self {
|
||||
profile: dto.profile,
|
||||
provider_id: dto.provider_id,
|
||||
model: dto.model,
|
||||
api_key: dto.api_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SaveOpenCodeProviderProfileOutput> for ProfileDto {
|
||||
fn from(out: SaveOpenCodeProviderProfileOutput) -> Self {
|
||||
Self(out.profile)
|
||||
}
|
||||
}
|
||||
|
||||
/// Request DTO for `clone_opencode_profile_from_seed`.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
||||
Reference in New Issue
Block a user