diff --git a/app/routers/agent.py b/app/routers/agent.py
index 5136411..16b454f 100644
--- a/app/routers/agent.py
+++ b/app/routers/agent.py
@@ -850,6 +850,7 @@ async def update_provider_config(request: Request):
model=(body.get("model") or "").strip() or None,
api_key=body.get("api_key"),
api_base=(body.get("api_base") or "").strip() or None,
+ clear_keys=(provider == "offline"),
)
llm = LLMClient()
return {
diff --git a/app/services/llm_config.py b/app/services/llm_config.py
index 9a2dbb4..1f249c4 100644
--- a/app/services/llm_config.py
+++ b/app/services/llm_config.py
@@ -80,7 +80,8 @@ def get_llm_config() -> dict:
def set_llm_config(*, provider: str | None = None, model: str | None = None,
- api_key: str | None = None, api_base: str | None = None) -> dict:
+ api_key: str | None = None, api_base: str | None = None,
+ clear_keys: bool = False) -> dict:
"""Upsert the runtime LLM config row (id=1) and return the new effective config.
An empty `api_key`/`api_base` keeps the stored value (so an admin can tweak
@@ -103,6 +104,12 @@ def set_llm_config(*, provider: str | None = None, model: str | None = None,
cfg["last_error"] = ""
if api_base is not None and api_base.strip():
cfg["api_base"] = api_base.strip()
+ if clear_keys:
+ cfg["api_key"] = ""
+ cfg["api_base"] = ""
+ cfg["verified"] = 0
+ cfg["verified_model"] = ""
+ cfg["last_error"] = ""
with get_conn() as conn:
conn.execute(
diff --git a/app/templates/settings.html b/app/templates/settings.html
index fdf619b..f5f1324 100644
--- a/app/templates/settings.html
+++ b/app/templates/settings.html
@@ -600,6 +600,7 @@
🔌 Tester la connexion
Test…
+
@@ -1107,6 +1108,8 @@ document.addEventListener('alpine:init', function() {
finally { f.testing = false; }
},
async deleteUserKey(id) {
+ var pname = id.charAt(0).toUpperCase() + id.slice(1);
+ if (!confirm('Supprimer la clé API pour ' + pname + ' ?\nLe fournisseur ne sera plus disponible dans le panneau Agent.')) return;
var f = this.keyForm(id);
f.deleting = true; f.msg = ''; f.ok = false;
try {
@@ -1185,6 +1188,31 @@ document.addEventListener('alpine:init', function() {
} catch(e) { this.llmMsg = 'Erreur réseau'; }
finally { this.llmSaving = false; }
},
+ async resetGlobalLlm() {
+ if (!confirm("Réinitialiser le fournisseur par défaut à « hors-ligne » ?\nTous les utilisateurs perdront l'accès au fournisseur IA actuel.")) return;
+ this.llmSaving = true;
+ this.llmMsg = ''; this.llmMsgOk = false;
+ try {
+ var r = await this.adminFetch('/api/agent/providers', {
+ method: 'PATCH',
+ headers: {'Content-Type':'application/json'},
+ body: JSON.stringify({provider: 'offline', model: '', api_key: '', api_base: ''})
+ });
+ var d = await r.json();
+ if (r.ok) {
+ this.llmForm = {provider: 'offline', model: '', api_key: '', api_base: ''};
+ this.llmHasKey = false;
+ this.llmDefaultProvider = 'offline';
+ this.llmProviderModels = [];
+ this.llmMsgOk = true;
+ this.llmMsg = 'Fournisseur réinitialisé : mode hors-ligne actif.';
+ this.syncLlmStatus();
+ } else {
+ this.llmMsg = d.detail || 'Erreur lors de la réinitialisation';
+ }
+ } catch(e) { this.llmMsg = 'Erreur réseau'; }
+ finally { this.llmSaving = false; }
+ },
async testLlm() {
if (!this.llmForm.provider) return;
this.llmTesting = true;