window.__ModuleLoader__.load({ id: "dsh-plugin-model-enhancer", factory: (require) => { var module = { exports: {} }; var exports = module.exports; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name2 in all) __defProp(target, name2, { get: all[name2], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/client/index.ts var index_exports = {}; __export(index_exports, { apply: () => apply, inject: () => inject, name: () => name }); module.exports = __toCommonJS(index_exports); // src/client/styles.ts var ENHANCER_CSS = ` .me-footer-card { box-sizing: border-box; margin-top: 16px; padding: 16px; border-radius: 12px; border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.08)); background: var(--dsw-alias-bg-module-platform, rgba(0, 0, 0, 0.02)); display: flex; flex-direction: column; gap: 12px; } body[data-ds-dark-theme] .me-footer-card { border-color: var(--dsw-alias-border-l3, rgba(255, 255, 255, 0.1)); background: var(--dsw-alias-surface-l1, rgba(255, 255, 255, 0.02)); } .me-footer-title { font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary, #0f1115); display: flex; align-items: center; gap: 8px; } body[data-ds-dark-theme] .me-footer-title { color: #fff; } .me-footer-desc { font-size: 13px; color: var(--dsw-alias-label-secondary, #61666b); line-height: 20px; } .me-diff-table { width: 100%; border-collapse: collapse; font-size: 13px; } .me-diff-table th, .me-diff-table td { padding: 6px 8px; border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.08)); } body[data-ds-dark-theme] .me-diff-table th, body[data-ds-dark-theme] .me-diff-table td { border-color: var(--dsw-alias-border-l3, rgba(255, 255, 255, 0.1)); } .me-val-new { color: var(--dsw-alias-state-success-primary, #10b981); font-weight: 500; } `; // src/client/ModelsFooterSettings.tsx var import_react = __toESM(require("react"), 1); // src/client/modelsDev.ts var THINKING_LEVELS_ALL = ["minimal", "low", "medium", "high", "xhigh", "max"]; var modelsDevGlobalCache = null; var modelsDevGlobalPromise = null; async function fetchAllModelsDev() { if (modelsDevGlobalCache) return modelsDevGlobalCache; if (modelsDevGlobalPromise) return modelsDevGlobalPromise; modelsDevGlobalPromise = (async () => { const endpoints = ["/api/models-dev/models", "https://models.dev/api.json"]; let lastError = null; for (const url of endpoints) { try { const res = await fetch(url); if (res.ok) { const json = await res.json(); const list = []; for (const [pId, p] of Object.entries(json)) { if (p && p.models) { for (const [mId, m] of Object.entries(p.models)) { list.push({ providerKey: pId, providerName: p.name || pId, id: m.id || mId, rawKey: mId, ...m }); } } } modelsDevGlobalCache = list; return list; } } catch (e) { lastError = e; } } throw lastError || new Error("Failed to load models.dev"); })(); try { return await modelsDevGlobalPromise; } finally { modelsDevGlobalPromise = null; } } function sanitizePositiveInt(val) { if (typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val && val >= 1) { return val; } if (typeof val === "string" && /^\d+$/.test(val.trim())) { const parsed = parseInt(val.trim(), 10); if (Number.isFinite(parsed) && parsed >= 1) { return parsed; } } return void 0; } function mergeModelCapabilities(m, matched) { if (!m) return m; if (!matched) { const result2 = { ...m }; const validExistingContext = sanitizePositiveInt(m.contextWindow); if (validExistingContext !== void 0) { result2.contextWindow = validExistingContext; } else { delete result2.contextWindow; } const validExistingMaxTokens = sanitizePositiveInt(m.maxTokens); if (validExistingMaxTokens !== void 0) { result2.maxTokens = validExistingMaxTokens; } else { delete result2.maxTokens; } return result2; } const hasImage = Boolean(matched.modalities?.input?.includes("image")); const hasReasoning = Boolean(matched.reasoning); let reasoningLevels = void 0; if (hasReasoning) { reasoningLevels = { off: "none" }; let added = false; if (Array.isArray(matched.reasoning_options)) { for (const opt of matched.reasoning_options) { if (opt.type === "effort" && Array.isArray(opt.values)) { for (const val of opt.values) { if (val === "none" || val === "off") reasoningLevels.off = "none"; else if (THINKING_LEVELS_ALL.includes(val)) { reasoningLevels[val] = val; added = true; } } } } } if (!added) { reasoningLevels.low = "low"; reasoningLevels.medium = "medium"; reasoningLevels.high = "high"; } } const result = { ...m, name: m.name || matched.name, input: m.input || (hasImage ? ["text", "image"] : ["text"]), reasoningEfforts: m.reasoningEfforts !== void 0 ? m.reasoningEfforts : hasReasoning ? reasoningLevels : false }; const resolvedContext = sanitizePositiveInt(m.contextWindow) ?? sanitizePositiveInt(matched.limit?.context); if (resolvedContext !== void 0) { result.contextWindow = resolvedContext; } else { delete result.contextWindow; } const resolvedMaxTokens = sanitizePositiveInt(m.maxTokens) ?? sanitizePositiveInt(matched.limit?.output); if (resolvedMaxTokens !== void 0) { result.maxTokens = resolvedMaxTokens; } else { delete result.maxTokens; } return result; } function normModelKey(key) { if (!key || typeof key !== "string") return ""; return key.toLowerCase().replace(/^[a-z0-9_-]+\//, "").replace(/[-_.:/]/g, "").replace(/\d{8}$/, ""); } function findDevModel(queryId, allList) { if (!queryId || !allList) return null; const q = queryId.trim().toLowerCase(); const qNorm = normModelKey(q); let m = allList.find((x) => x.id?.toLowerCase() === q || x.rawKey?.toLowerCase() === q); if (m) return m; m = allList.find((x) => x.id?.split("/").pop()?.toLowerCase() === q); if (m) return m; m = allList.find((x) => normModelKey(x.id) === qNorm || normModelKey(x.name || "") === qNorm); if (m) return m; m = allList.find((x) => { const n = normModelKey(x.id); return n.length >= 3 && (n.includes(qNorm) || qNorm.includes(n)); }); return m || null; } // src/client/i18n.ts var I18N_DICT = { zh: { // ModelListEditor & Badges batchBtn: "\u4E00\u952E\u8865\u5168", batchBtnBusy: "\u8865\u5168\u4E2D...", batchBtnTitle: "\u6839\u636E\u6A21\u578B ID \u4ECE models.dev \u81EA\u52A8\u5339\u914D\u5E76\u9884\u586B\u5145\u7F3A\u5931\u53C2\u6570", singleBtn: "\u667A\u80FD\u8865\u5168", singleBtnBusy: "\u8865\u5168\u4E2D", singleBtnTitle: "\u4ECE models.dev \u83B7\u53D6\u8BE5\u6A21\u578B\u63A8\u8350\u53C2\u6570", badgeVision: "\u56FE\u50CF", badgeVisionTitle: "\u652F\u6301\u56FE\u50CF\u8F93\u5165 (Vision)", badgeThinking: "\u601D\u8003", badgeThinkingTitle: "\u601D\u8003\u6863\u4F4D: {levels}", defaultEffort: "\u9ED8\u8BA4", modalitiesTitle: "\u8F93\u5165\u6A21\u6001\u652F\u6301 (Input Modalities)", modalityText: "\u6587\u672C\u8F93\u5165 (Text)", modalityVision: "\u56FE\u50CF\u8F93\u5165 (Vision)", reasoningTitle: "\u63A8\u7406\u601D\u8003\u6863\u4F4D (Reasoning Efforts)", enableReasoning: "\u542F\u7528\u6DF1\u5EA6\u601D\u8003", saveBlockedHint: "\u4FDD\u5B58\u53D7\u963B\u63D0\u793A\uFF1A\u6A21\u578B {index} {reason}", fillNoIdError: "\u5217\u8868\u4E2D\u6CA1\u6709\u586B\u5199\u6A21\u578B ID \u7684\u6709\u6548\u6A21\u578B", fillSuccessNotice: "\u4E00\u952E\u8865\u5168\u5B8C\u6210\uFF1A\u5DF2\u5339\u914D\u5E76\u66F4\u65B0 {count}/{total} \u4E2A\u6A21\u578B", fillFailedNotice: "\u4E00\u952E\u8865\u5168\u5931\u8D25: {message}", singleFillRequireId: "\u8BF7\u5148\u586B\u5199\u6A21\u578B ID", singleFillNotFound: '\u672A\u5728 models.dev \u4E2D\u627E\u5230\u4E0E "{id}" \u5339\u914D\u7684\u6A21\u578B\u4FE1\u606F', singleFillFetchFailed: "\u83B7\u53D6 models.dev \u5931\u8D25: {message}", singleFillApplied: '\u5DF2\u9884\u586B\u5145 "{id}" \u63A8\u8350\u53C2\u6570', // PrefillModal & Footer Settings enhancerTitle: "Model Enhancer (\u591A\u6A21\u6001\u4E0E\u63A8\u7406\u53C2\u6570\u589E\u5F3A)", enhancerIntro: "\u914D\u7F6E models.dev \u9884\u586B\u5145\u3001\u8F93\u5165\u6A21\u6001\u4E0E\u63A8\u7406\u601D\u8003\u6863\u4F4D\uFF0C\u5E76\u53EF\u9009\u62E9\u76EE\u6807 Provider \u4E00\u952E\u5E94\u7528\u589E\u5F3A\u914D\u7F6E\u3002", targetProvider: "\u76EE\u6807 Provider\uFF1A", refreshSettings: "\u5237\u65B0\u914D\u7F6E", activeEnhancerNotice: "\u5F53\u524D\u6B63\u5728\u5BF9\u300C{provider}\u300D\u751F\u6548\u589E\u5F3A\u529F\u80FD\u3002", modalTitle: "models.dev \u9884\u586B\u5145\u786E\u8BA4\u4E0E\u9009\u62E9", matchedModelLabel: "\u68C0\u7D22\u5230\u5339\u914D\u6A21\u578B\uFF1A", thSelect: "\u9009\u7528", thField: "\u914D\u7F6E\u9879", thCurrent: "\u5F53\u524D\u8BBE\u7F6E", thRecommended: "models.dev \u63A8\u8350\u503C", fieldName: "\u663E\u793A\u540D\u79F0", fieldContext: "\u4E0A\u4E0B\u6587\u957F\u5EA6", fieldMaxTokens: "\u6700\u5927\u8F93\u51FA", fieldInput: "\u56FE\u50CF\u8F93\u5165", fieldReasoning: "\u63A8\u7406\u601D\u8003\u7B49\u7EA7", fieldUnset: "(\u672A\u8BBE\u7F6E)", fieldDefault: "(\u9ED8\u8BA4)", visionSupported: "\u652F\u6301\u56FE\u50CF", visionOnlyText: "\u4EC5\u6587\u672C", thinkingOff: "\u5173\u95ED\u601D\u8003", thinkingOn: "\u5F00\u542F", cancel: "\u53D6\u6D88", applySelected: "\u5E94\u7528\u5DF2\u9009\u63A8\u8350\u9879" }, en: { // ModelListEditor & Badges batchBtn: "Auto-Fill All", batchBtnBusy: "Filling\u2026", batchBtnTitle: "Auto-match and prefill missing parameters from models.dev", singleBtn: "Auto-Fill", singleBtnBusy: "Filling\u2026", singleBtnTitle: "Fetch recommended parameters for this model from models.dev", badgeVision: "Vision", badgeVisionTitle: "Supports Image/Vision input", badgeThinking: "Reasoning", badgeThinkingTitle: "Reasoning efforts: {levels}", defaultEffort: "Default", modalitiesTitle: "Input Modalities", modalityText: "Text Input", modalityVision: "Vision Input", reasoningTitle: "Reasoning Efforts", enableReasoning: "Enable Deep Reasoning", saveBlockedHint: "Save blocked: Model {index} {reason}", fillNoIdError: "No valid models with a Model ID found in the list", fillSuccessNotice: "Auto-fill complete: matched & updated {count}/{total} models", fillFailedNotice: "Auto-fill failed: {message}", singleFillRequireId: "Please enter a Model ID first", singleFillNotFound: 'No matching model found on models.dev for "{id}"', singleFillFetchFailed: "Failed to fetch models.dev: {message}", singleFillApplied: 'Prefilled recommended parameters for "{id}"', // PrefillModal & Footer Settings enhancerTitle: "Model Enhancer Settings", enhancerIntro: "Configure models.dev auto-fill, input modalities and reasoning effort levels across providers.", targetProvider: "Target Provider:", refreshSettings: "Refresh", activeEnhancerNotice: 'Enhancer active on "{provider}".', modalTitle: "models.dev Prefill Confirmation", matchedModelLabel: "Matched Model: ", thSelect: "Apply", thField: "Property", thCurrent: "Current Setting", thRecommended: "models.dev Value", fieldName: "Display Name", fieldContext: "Context Window", fieldMaxTokens: "Max Output Tokens", fieldInput: "Vision Input", fieldReasoning: "Reasoning Efforts", fieldUnset: "(Unset)", fieldDefault: "(Default)", visionSupported: "Vision Supported", visionOnlyText: "Text Only", thinkingOff: "Disabled", thinkingOn: "Enabled", cancel: "Cancel", applySelected: "Apply Selected" } }; function isZhLocale() { if (typeof navigator !== "undefined") { const lang = (navigator.language || "").toLowerCase(); if (lang.startsWith("zh")) return true; } return false; } function getTranslation(key, isZh = isZhLocale(), params) { const dict = isZh ? I18N_DICT.zh : I18N_DICT.en; let str = dict[key] || I18N_DICT.en[key] || key; if (params) { for (const [k, v] of Object.entries(params)) { str = str.replace(new RegExp(`\\{${k}\\}`, "g"), String(v)); } } return str; } // src/client/ModelsFooterSettings.tsx function ModelsFooterSettings({ ctx }) { const isZh = isZhLocale(); const [loading, setLoading] = (0, import_react.useState)(false); const [providerList, setProviderList] = (0, import_react.useState)([]); const [selectedProvider, setSelectedProvider] = (0, import_react.useState)(""); const [statusMsg, setStatusMsg] = (0, import_react.useState)(null); const [batching, setBatching] = (0, import_react.useState)(false); const loadProviders = async () => { try { setLoading(true); const res = await ctx.remote?.llm?.listConfigurableProviders?.(); if (res?.ok && Array.isArray(res.value)) { setProviderList(res.value); if (res.value.length > 0 && !selectedProvider) { setSelectedProvider(res.value[0].provider); } } } catch (e) { console.error("[model-enhancer] Failed to list providers:", e); } finally { setLoading(false); } }; (0, import_react.useEffect)(() => { loadProviders(); }, []); const handleBatchDevMatch = async () => { if (!selectedProvider) return; setBatching(true); setStatusMsg(null); try { const descRes = await ctx.remote?.settings?.describe?.(); const namespaces = descRes?.ok ? descRes.value.namespaces : []; const piAiNs = namespaces.find((n) => n.ns === "llm-pi-ai"); if (!piAiNs) { setStatusMsg({ type: "err", text: "llm-pi-ai settings namespace not found." }); return; } const provConfig = piAiNs.value?.providers?.[selectedProvider] || {}; const models = Array.isArray(provConfig.models) ? provConfig.models : []; if (models.length === 0) { setStatusMsg({ type: "err", text: getTranslation("fillNoIdError", isZh) }); return; } const allDevModels = await fetchAllModelsDev(); let count = 0; const nextModels = models.map((m) => { if (!m || !m.id) return m; const matched = findDevModel(m.id, allDevModels); if (matched) count++; return mergeModelCapabilities(m, matched); }); const ops = [{ op: "set", path: ["providers", selectedProvider, "models"], value: nextModels }]; const mutateRes = await ctx.remote.settings.mutate("llm-pi-ai", ops, piAiNs.revision); if (mutateRes?.ok) { setStatusMsg({ type: "ok", text: getTranslation("fillSuccessNotice", isZh, { count, total: models.length }) }); } else { setStatusMsg({ type: "err", text: mutateRes?.error?.message || "Failed to mutate settings" }); } } catch (err) { setStatusMsg({ type: "err", text: err.message || String(err) }); } finally { setBatching(false); } }; return import_react.default.createElement( "div", { className: "me-footer-card" }, import_react.default.createElement( "div", { className: "me-footer-title" }, import_react.default.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" }, import_react.default.createElement("path", { d: "M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" })), import_react.default.createElement("span", null, getTranslation("enhancerTitle", isZh)) ), import_react.default.createElement("div", { className: "me-footer-desc" }, getTranslation("enhancerIntro", isZh)), import_react.default.createElement( "div", { style: { display: "flex", alignItems: "center", gap: "12px", flexWrap: "wrap" } }, import_react.default.createElement( "label", { style: { display: "inline-flex", alignItems: "center", gap: "6px", fontSize: "13px", fontWeight: 500 } }, import_react.default.createElement("span", null, getTranslation("targetProvider", isZh)), import_react.default.createElement( "select", { value: selectedProvider, onChange: (e) => setSelectedProvider(e.target.value), style: { height: "32px", borderRadius: "6px", border: "1px solid var(--dsw-alias-border-l2, #ccc)", background: "var(--dsw-alias-bg-module-platform, #fff)", color: "var(--dsw-alias-label-primary, #000)", padding: "0 8px", fontSize: "13px" } }, providerList.map((p) => import_react.default.createElement("option", { key: p.provider, value: p.provider }, `${p.displayName || p.provider} (${p.settingsNs || "generic"})`)) ) ), import_react.default.createElement( "button", { type: "button", disabled: batching || !selectedProvider, onClick: handleBatchDevMatch, style: { height: "32px", borderRadius: "16px", border: "none", background: "#2563eb", color: "#fff", padding: "0 14px", fontSize: "13px", fontWeight: 500, cursor: batching || !selectedProvider ? "not-allowed" : "pointer", opacity: batching || !selectedProvider ? 0.6 : 1, display: "inline-flex", alignItems: "center", gap: "6px" } }, batching ? getTranslation("batchBtnBusy", isZh) : getTranslation("batchBtn", isZh) ), import_react.default.createElement("button", { type: "button", disabled: loading, onClick: loadProviders, style: { height: "32px", borderRadius: "16px", border: "1px solid var(--dsw-alias-border-l2, #ccc)", background: "transparent", color: "var(--dsw-alias-label-secondary, #666)", padding: "0 12px", fontSize: "13px", cursor: "pointer" } }, getTranslation("refreshSettings", isZh)) ), statusMsg ? import_react.default.createElement("div", { style: { fontSize: "12px", padding: "6px 10px", borderRadius: "6px", background: statusMsg.type === "ok" ? "rgba(16, 185, 129, 0.1)" : "rgba(239, 68, 68, 0.1)", color: statusMsg.type === "ok" ? "#10b981" : "#ef4444" } }, statusMsg.text) : null ); } // src/client/ProviderCardExtras.tsx var import_react2 = __toESM(require("react"), 1); function ProviderCardExtras({ provider, configured, keyConfigured, ctx }) { const isZh = isZhLocale(); const [matching, setMatching] = (0, import_react2.useState)(false); const [notice, setNotice] = (0, import_react2.useState)(null); if (provider.settingsNs !== "llm-pi-ai") { return null; } const handleAutoFillProvider = async () => { setMatching(true); setNotice(null); try { const descRes = await ctx.remote?.settings?.describe?.(); const namespaces = descRes?.ok ? descRes.value.namespaces : []; const piAiNs = namespaces.find((n) => n.ns === "llm-pi-ai"); if (!piAiNs) { setNotice({ type: "err", text: "llm-pi-ai namespace missing." }); return; } const provKey = provider.provider; const provConfig = piAiNs.value?.providers?.[provKey] || {}; const models = Array.isArray(provConfig.models) ? provConfig.models : []; if (models.length === 0) { setNotice({ type: "err", text: getTranslation("fillNoIdError", isZh) }); return; } const allDevModels = await fetchAllModelsDev(); let count = 0; const nextModels = models.map((m) => { if (!m || !m.id) return m; const matched = findDevModel(m.id, allDevModels); if (matched) count++; return mergeModelCapabilities(m, matched); }); const ops = [{ op: "set", path: ["providers", provKey, "models"], value: nextModels }]; const mutateRes = await ctx.remote.settings.mutate("llm-pi-ai", ops, piAiNs.revision); if (mutateRes?.ok) { setNotice({ type: "ok", text: getTranslation("fillSuccessNotice", isZh, { count, total: models.length }) }); } else { setNotice({ type: "err", text: mutateRes?.error?.message || "Mutation rejected" }); } } catch (e) { setNotice({ type: "err", text: e.message || String(e) }); } finally { setMatching(false); } }; return import_react2.default.createElement( "div", { style: { padding: "8px 12px", marginTop: "4px", background: "var(--dsw-alias-bg-module-platform, rgba(0, 0, 0, 0.02))", borderRadius: "8px", border: "1px dashed var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.1))", display: "flex", alignItems: "center", justifyContent: "space-between", gap: "8px" } }, import_react2.default.createElement("span", { style: { fontSize: "12px", color: "var(--dsw-alias-label-secondary, #666)" } }, getTranslation("activeEnhancerNotice", isZh, { provider: provider.displayName })), import_react2.default.createElement("button", { type: "button", disabled: matching, onClick: handleAutoFillProvider, style: { height: "26px", padding: "0 10px", borderRadius: "13px", border: "none", background: "#2563eb", color: "#fff", fontSize: "12px", fontWeight: 500, cursor: matching ? "not-allowed" : "pointer", opacity: matching ? 0.7 : 1 } }, matching ? getTranslation("singleBtnBusy", isZh) : getTranslation("batchBtn", isZh)), notice ? import_react2.default.createElement("span", { style: { fontSize: "11px", color: notice.type === "ok" ? "#10b981" : "#ef4444", marginLeft: "8px" } }, notice.text) : null ); } // src/client/index.ts var name = "dsh-plugin-model-enhancer"; var inject = [ "slots", "remote", "remote.settings", "remote.llm" ]; function apply(ctx) { if (typeof document !== "undefined" && !document.querySelector("style[data-plugin='dsh-model-enhancer']")) { const tag = document.createElement("style"); tag.dataset.plugin = "dsh-model-enhancer"; tag.textContent = ENHANCER_CSS; document.head.appendChild(tag); } ctx.inject(["slots"], (scope) => { scope.slots.inject("settings.models.footer", () => scope.slots.register({ name: "settings.models.footer", id: "me-models-footer", order: 50, inject: () => ({ ctx }) }, ModelsFooterSettings)); }); ctx.inject(["slots"], (scope) => { scope.slots.inject("settings.models.provider-card", () => scope.slots.register({ name: "settings.models.provider-card", key: "llm-pi-ai", inject: (ownerProps) => ({ ...ownerProps, ctx }) }, ProviderCardExtras)); }); } return module.exports; } });