feat: v1.0 — am ask : langage naturel → commande am, règles locales FR/EN hors-ligne, raffinement LLM optionnel via le registre providers (token keyring, jamais de données du journal), cache des traductions, confirmation avant exécution, désactivable (closes #78)

- src/ask.rs : traducteur par règles (verbes FR/EN, pronoms, nicknames d'agents, séquences «et/puis»), cache ask_cache.json, POST /chat/completions du provider résolu avec Bearer du keyring, validation des commandes retournées, dégradation silencieuse sans token
- settings.ask {enabled (défaut true), provider, model} + doc config.yaml ; CLI/REPL/help/man/i18n
- 7 tests : règles (installe claude et lance-le → 2 commandes), cache, LLM via serveur tiny_http (token Bearer, zéro donnée du journal), dégradation, désactivation
This commit is contained in:
2026-08-19 22:01:00 -04:00
parent 7cab1a0b5c
commit 12eb09b01a
12 changed files with 652 additions and 3 deletions
+32
View File
@@ -140,6 +140,11 @@ pub struct Settings {
/// Nothing is collected or sent while `enabled` is false (the default).
#[serde(default)]
pub telemetry: Option<TelemetrySettings>,
/// am ask (issue #78): natural language → am command. The local rules
/// are always available; the optional LLM refinement uses the provider
/// registry. `enabled: false` turns the whole command off.
#[serde(default)]
pub ask: Option<AskSettings>,
/// Plugin scripts (issue #75): default timeout and enable list.
#[serde(default)]
pub plugins: Option<PluginSettings>,
@@ -167,6 +172,30 @@ pub struct TelemetrySettings {
pub endpoint: Option<String>,
}
/// am ask settings (issue #78): the LLM refinement is optional — without a
/// provider, the local rule-based translator still works, offline.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct AskSettings {
/// Master switch; false disables `am ask` entirely (issue #78).
pub enabled: bool,
/// Provider of the registry used for the refinement call. Falls back
/// to settings.default_provider when unset. None = rules only.
pub provider: Option<String>,
/// Model for the refinement call. Falls back to the provider default.
pub model: Option<String>,
}
impl Default for AskSettings {
fn default() -> Self {
AskSettings {
enabled: true,
provider: None,
model: None,
}
}
}
/// One entry of the LLM provider registry (issue #88).
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(deny_unknown_fields)]
@@ -872,6 +901,9 @@ pub fn merge(base: &mut Config, overlay: Config) {
if o.telemetry.is_some() {
s.telemetry = o.telemetry;
}
if o.ask.is_some() {
s.ask = o.ask;
}
if o.plugins.is_some() {
s.plugins = o.plugins;
}