feat(ai): commandes @/ & skills, analyse d'images et capacites des modeles (#81)
CI / lint (push) Successful in 1m10s
CI / security (push) Successful in 43s
CI / test (push) Successful in 2m34s
CI / build (push) Successful in 43s
CI / e2e (push) Successful in 10m59s

This commit is contained in:
2026-09-12 11:38:46 -04:00
parent 88bb817a62
commit f049e208b6
25 changed files with 2581 additions and 31 deletions
+23 -1
View File
@@ -6,6 +6,7 @@ import { syncVaultSelectors, setSelectedVaultContext, refreshSidebarForContext,
import { escapeHtml, safeCreateIcons } from './utils.js';
import { showToast, closeHeaderMenu, closeMobileSidebar } from './ui.js';
import { t, setLocale, getLocale } from './i18n.js';
import { getModelCapabilities, renderCapabilityList } from './ai.js';
let _recentTimestampTimer = null;
let _recentFilesCache = [];
@@ -625,6 +626,13 @@ function initConfigModal() {
await _populateAIModelOptions(aiDefaultProviderSel.value, models[aiDefaultProviderSel.value] || "");
});
}
const aiDefaultModelSel = document.getElementById("cfg-ai-default-model");
if (aiDefaultModelSel) {
aiDefaultModelSel.addEventListener("change", () => {
const providerSel = document.getElementById("cfg-ai-default-provider");
_renderConfigModelCaps(providerSel ? providerSel.value : null, aiDefaultModelSel.value);
});
}
// Load existing keys/defaults on modal open
document.getElementById("config-open-btn").addEventListener("click", loadAIKeys);
document.getElementById("config-open-btn").addEventListener("click", loadAIDefaults);
@@ -1440,7 +1448,10 @@ async function _populateAIModelOptions(provider, selected) {
const modelSel = document.getElementById("cfg-ai-default-model");
if (!modelSel) return;
modelSel.innerHTML = '<option value="">--</option>';
if (!provider) return;
if (!provider) {
_renderConfigModelCaps(null, null);
return;
}
try {
const m = await api("/api/config/ai-models?provider=" + encodeURIComponent(provider));
const list = (m && m.models) || [];
@@ -1451,9 +1462,20 @@ async function _populateAIModelOptions(provider, selected) {
modelSel.innerHTML += '<option value="' + selected + '">' + selected + '</option>';
}
modelSel.value = selected || "";
_renderConfigModelCaps(provider, modelSel.value);
} catch(e) { console.warn("Failed to load default models for", provider, e); }
}
async function _renderConfigModelCaps(provider, model) {
const host = document.getElementById("cfg-ai-default-model-caps");
if (!host) return;
host.innerHTML = "";
if (!provider || !model) return;
const caps = await getModelCapabilities(provider, model);
if (!caps) return;
host.appendChild(renderCapabilityList(caps));
}
async function saveAIKeys() {
const keys = {};
for (const [id, name] of Object.entries(AI_KEY_MAP)) {