feat: implémentation et QA ticket99 - agent model configuration v2

- backend A-C: VO Codex/Claude, renderers/projecteurs modèle, SecretRef/env, catalogues/use cases/Tauri commands
- frontend D: profils Codex/Claude provider->model->secret, validations, conservation SecretRef
- fix: app-tauri embedded_server isolant IDEA_WEB_ROOT

QA: backend 57/57 tests, frontend 74/74 tests OK
This commit is contained in:
2026-07-26 11:56:25 +02:00
parent 13fb538880
commit dae07d35bb
27 changed files with 2358 additions and 143 deletions

View File

@ -9,6 +9,8 @@ import type {
AgentDrift,
AppExitWorkGuardState,
AgentProfile,
ClaudeProviderCatalogEntry,
CodexProviderCatalogEntry,
DiagnosticWarning,
DomainEvent,
EmbedderEngines,
@ -103,6 +105,8 @@ import type {
ReattachResult,
RemoteGateway,
ReviewPluginPackageInput,
SaveClaudeProviderProfileInput,
SaveCodexProviderProfileInput,
SaveOpenCodeProviderProfileInput,
SkillGateway,
StoppedLiveAgent,
@ -1250,6 +1254,7 @@ export const MOCK_REFERENCE_PROFILES: AgentProfile[] = [
contextInjection: { strategy: "conventionFile", target: "CLAUDE.md" },
detect: "claude --version",
cwdTemplate: "{projectRoot}",
structuredAdapter: "claude",
},
{
id: "mock-codex",
@ -1259,6 +1264,7 @@ export const MOCK_REFERENCE_PROFILES: AgentProfile[] = [
contextInjection: { strategy: "conventionFile", target: "AGENTS.md" },
detect: "codex --version",
cwdTemplate: "{projectRoot}",
structuredAdapter: "codex",
},
{
id: "mock-opencode",
@ -1291,6 +1297,25 @@ const MOCK_OPENCODE_PROVIDERS: OpenCodeProviderCatalogEntry[] = [
},
];
/** Static mock catalogue mirroring the backend Codex provider list. */
const MOCK_CODEX_PROVIDERS: CodexProviderCatalogEntry[] = [
{
providerId: "openai",
displayName: "OpenAI",
models: ["gpt-5", "gpt-5-mini", "gpt-5-codex", "o3"],
customSupported: true,
},
];
/** Static mock catalogue mirroring the backend Claude provider list. */
const MOCK_CLAUDE_PROVIDERS: ClaudeProviderCatalogEntry[] = [
{
providerId: "anthropic",
displayName: "Anthropic",
models: ["claude-sonnet-4-5", "claude-opus-4-1", "claude-haiku-3-5"],
},
];
/**
* In-memory profiles gateway. Tracks configured profiles and a first-run flag so
* the wizard can be driven and tested fully offline. By default it reports the
@ -1386,6 +1411,53 @@ export class MockProfileGateway implements ProfileGateway {
this.configured = true;
return structuredClone(saved);
}
async listCodexProviders(): Promise<CodexProviderCatalogEntry[]> {
return structuredClone(MOCK_CODEX_PROVIDERS);
}
async saveCodexProviderProfile(
input: SaveCodexProviderProfileInput,
): Promise<AgentProfile> {
const saved: AgentProfile = {
...structuredClone(input.profile),
codexProvider: {
providerId: input.providerId,
model: input.model,
apiKeyRef:
input.profile.codexProvider?.apiKeyRef ?? `mock-secret-${input.profile.id}`,
custom: input.custom,
},
};
const i = this.profiles.findIndex((p) => p.id === saved.id);
if (i >= 0) this.profiles[i] = saved;
else this.profiles.push(saved);
this.configured = true;
return structuredClone(saved);
}
async listClaudeProviders(): Promise<ClaudeProviderCatalogEntry[]> {
return structuredClone(MOCK_CLAUDE_PROVIDERS);
}
async saveClaudeProviderProfile(
input: SaveClaudeProviderProfileInput,
): Promise<AgentProfile> {
const saved: AgentProfile = {
...structuredClone(input.profile),
claudeProvider: {
providerId: input.providerId,
model: input.model,
apiKeyRef:
input.profile.claudeProvider?.apiKeyRef ?? `mock-secret-${input.profile.id}`,
},
};
const i = this.profiles.findIndex((p) => p.id === saved.id);
if (i >= 0) this.profiles[i] = saved;
else this.profiles.push(saved);
this.configured = true;
return structuredClone(saved);
}
}
/**