From 7fb65c257d8fd5142b6b6c81b863e53abb71d30f Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Fri, 21 Aug 2026 08:36:26 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20am=20setup=20=E2=80=94=20provider=20ope?= =?UTF-8?q?nrouter=20+=20modeles=20proposes=20;=20am=20ai=20=E2=80=94=20ro?= =?UTF-8?q?le=20am-copilot=20par=20defaut=20;=20fix=20migrate=20import=20(?= =?UTF-8?q?config=20active)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - setup: openrouter ajoute aux CHOICES (base URL, OPENROUTER_API_KEY, 6 modeles declares dans le registre embarqué, proposes au choix) - setup: pick_model liste les modeles disponibles (registre) + autre modele - am ai sans --role: am-copilot par defaut (regeneration auto des roles si fichier manquant, degradation douce si echec; role explicite inconnu = erreur) - fix migrate --import: import_bundle ecrivait la config dans user_config_dir() GLOBAL -> ecrasait la config reelle de la machine (et cargo test detruisait la config utilisateur a chaque suite via export_import_round_trip). L'import ecrit desormais dans app.paths.config_dir (config active). v1.1.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- ROADMAP.md | 12 ++++++++++++ config.yaml | 10 ++++++++++ src/commands/ai_cmd.rs | 37 ++++++++++++++++++++++++++----------- src/commands/migrate_cmd.rs | 18 +++++++++++++----- src/i18n.rs | 1 + src/setup.rs | 2 +- 8 files changed, 65 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8630918..655c202 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,7 +21,7 @@ dependencies = [ [[package]] name = "agent-manager" -version = "1.1.1" +version = "1.1.2" dependencies = [ "anyhow", "base64", diff --git a/Cargo.toml b/Cargo.toml index f3d11dc..140943b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "agent-manager" -version = "1.1.1" +version = "1.1.2" edition = "2021" description = "Manage local AI coding agents: list, install, start, stop, update — with automatic dependency handling and a YAML-driven catalog." license = "MIT" diff --git a/ROADMAP.md b/ROADMAP.md index 9b48f15..ff04b79 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -70,6 +70,18 @@ > `settings.providers..base_url` + `.default_model` (le schéma exige > base_url quand un bloc provider est écrit). Test de régression > `setup_persists_under_settings_providers`. +> +> 🔧 **Maintenance v1.1.2 (2026-08-20)** : +> - `am setup` : **openrouter** ajouté au choix des providers (base URL, +> token via OPENROUTER_API_KEY, 6 modèles déclarés proposés) ; +> le choix du modèle liste les modèles disponibles du provider. +> - `am ai` sans `--role` utilise **am-copilot par défaut** (régénération +> automatique des rôles si le fichier manque, dégradation douce). +> - Bug `am migrate --import` : la config importée était écrite dans le +> répertoire config GLOBAL (user_config_dir) au lieu du config actif de +> l'app — l'import écrasait la config réelle de la machine (et la suite +> de tests détruisait la config utilisateur à chaque `cargo test`). +> L'import respecte désormais `app.paths.config_dir` (--config/isolated). --- diff --git a/config.yaml b/config.yaml index fc82dbe..81e1650 100644 --- a/config.yaml +++ b/config.yaml @@ -108,6 +108,16 @@ settings: base_url: https://generativelanguage.googleapis.com/v1beta default_model: gemini-2.5-pro models: [gemini-2.5-pro, gemini-2.5-flash] + openrouter: + base_url: https://openrouter.ai/api/v1 + default_model: deepseek/deepseek-chat-v3-0324 + models: + - deepseek/deepseek-chat-v3-0324 + - anthropic/claude-sonnet-4.5 + - openai/gpt-4o + - google/gemini-2.5-pro + - meta-llama/llama-3.3-70b-instruct + - mistralai/mistral-large-2411 # --- Command aliases ---------------------------------------------------------- aliases: diff --git a/src/commands/ai_cmd.rs b/src/commands/ai_cmd.rs index c64809e..8da1f66 100644 --- a/src/commands/ai_cmd.rs +++ b/src/commands/ai_cmd.rs @@ -75,21 +75,36 @@ fn aichat_installed(app: &App) -> bool { || which::which("aichat").is_ok() } -/// Validate the --role flag: the file must exist among the generated -/// am-* roles (v1.1.0 F3). Returns the aichat --agent arguments. +/// Build the aichat `--agent` arguments for the requested role. Without a +/// `--role` flag the am-copilot role is used by default (v1.1.2): when its +/// file is missing the roles are regenerated on the fly, and a generation +/// failure degrades gracefully (no role). An explicit unknown role is an +/// error. fn role_args(app: &App, role: Option<&str>) -> Result> { - let Some(role) = role else { - return Ok(Vec::new()); - }; + let role = role.unwrap_or("am-copilot"); let dir = crate::roles::aichat_agents_dir(); let path = dir.join(format!("{role}.md")); - if !path.exists() { - bail!(crate::i18n::tr_in( - app.lang(), - "rôle '{}' inconnu — générez les rôles avec: am setup --roles (am-copilot, am-operator, am-dev, am-do, am-analyst, am-orchestrator)" - ).replace("{}", role)); + if path.exists() { + return Ok(vec!["--agent".to_string(), role.to_string()]); } - Ok(vec!["--agent".to_string(), role.to_string()]) + if role == "am-copilot" { + if let Err(e) = crate::roles::generate_all(app) { + app.log.verbose(&format!("roles generation skipped: {e:#}")); + } + if path.exists() { + return Ok(vec!["--agent".to_string(), role.to_string()]); + } + app.log.warn(crate::i18n::tr_in( + app.lang(), + "rôle 'am-copilot' introuvable — lancez am setup --roles", + )); + return Ok(Vec::new()); + } + bail!(crate::i18n::tr_in( + app.lang(), + "rôle '{}' inconnu — générez les rôles avec: am setup --roles (am-copilot, am-operator, am-dev, am-do, am-analyst, am-orchestrator)" + ) + .replace("{}", role)); } /// Conversational mode: aichat -f "" in the foreground, with diff --git a/src/commands/migrate_cmd.rs b/src/commands/migrate_cmd.rs index 69f7a55..0d7a704 100644 --- a/src/commands/migrate_cmd.rs +++ b/src/commands/migrate_cmd.rs @@ -266,9 +266,14 @@ pub fn import_bundle(app: &App, bundle: &Path, confirm: bool) -> Result Result — ex: ask installe claude et lance-le", "usage: ask — e.g. ask installe claude et lance-le"), ("aucune source enregistrée — settings.registry.sources ou: am registry install ", "no sources registered — settings.registry.sources or: am registry install "), ("installation refusée — source non fiable", "installation refused — untrusted source"), diff --git a/src/setup.rs b/src/setup.rs index f6291d3..4ea32ee 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -16,7 +16,7 @@ use std::io::Write; /// Known providers offered by the wizard (from the embedded registry plus /// the local Ollama runtime and a custom endpoint). -const CHOICES: &[&str] = &["anthropic", "openai", "deepseek", "google", "ollama", "custom"]; +const CHOICES: &[&str] = &["anthropic", "openai", "deepseek", "google", "openrouter", "ollama", "custom"]; /// True when the user has not configured a usable default provider yet: /// no `settings.default_provider`, or the default provider has no API