// Script to assemble client.js with complete bidirectional i18n (Chinese & English) const fs = require('fs'); const origClientPath = '/home/cho/.nvm/versions/node/v24.18.0/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai/dsh-client-ui-settings-models/lib/client.js'; const origCode = fs.readFileSync(origClientPath, 'utf8'); const enhancedModelListEditorCode = ` //#region lib/types/client/ModelListEditor.js (REFINED APPROVED LAYOUT & FULL I18N) function textOf(model, key) { const value = model[key]; return typeof value === "string" ? value : ""; } function numberOf(model, key) { const value = model[key]; return typeof value === "number" ? value : void 0; } function IconChevron({ open }) { return (0, react_jsx_runtime.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, style: { transform: open ? "rotate(90deg)" : void 0, transition: "transform 140ms ease" }, children: (0, react_jsx_runtime.jsx)("path", { d: "M6 3.5L10.5 8L6 12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }); } function IconTrash() { return (0, react_jsx_runtime.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: (0, react_jsx_runtime.jsx)("path", { d: "M2.5 4h11M6.5 4V2.5h3V4M4 4l.7 9a1 1 0 001 .9h4.6a1 1 0 001-.9L12 4M6.5 6.8v4.4M9.5 6.8v4.4", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round" }) }); } const CAPACITY_HINT = { contextWindow: "256K", maxTokens: "32K" }; function capacitySpelling(value) { return value === void 0 ? "" : formatCapacity(value); } function adopt(candidate) { return { id: candidate.id, ...candidate.name === void 0 ? {} : { name: candidate.name }, ...candidate.contextWindow === void 0 ? {} : { contextWindow: candidate.contextWindow }, ...candidate.maxTokens === void 0 ? {} : { maxTokens: candidate.maxTokens } }; } // CSS styles const ENHANCER_CSS = \` .VOzbGW_modelRow, .zGbnIq_modelRow, div[class*="modelRow"] { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) 28px 28px auto !important; align-items: center; gap: 6px; display: grid; } .me-model-badges-row { display: flex; gap: 6px; align-items: center; margin-top: 4px; padding-left: 2px; flex-wrap: wrap; } .me-badge { font-size: 11px; line-height: 16px; padding: 0 6px; border-radius: 4px; font-weight: 500; white-space: nowrap; letter-spacing: -0.01em; } .me-badge-vision { color: var(--dsw-alias-state-success-primary, #10b981); border: 1px solid var(--dsw-alias-border-l2, rgba(16, 185, 129, 0.3)); background: var(--dsw-alias-surface-l2, rgba(16, 185, 129, 0.08)); } .me-badge-thinking { color: #9d7dfa; border: 1px solid var(--dsw-alias-border-l2, rgba(157, 125, 250, 0.3)); background: var(--dsw-alias-surface-l2, rgba(157, 125, 250, 0.08)); } .me-action-btn { box-sizing: border-box; height: 28px; padding: 0 9px; font-size: 12px; font-weight: 500; border-radius: 6px; cursor: pointer; border: 1px solid var(--dsw-alias-border-l2, rgba(255,255,255,0.12)); background: var(--dsw-alias-surface-l1, transparent); color: var(--dsw-alias-label-secondary, #999); display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; transition: all 120ms ease; margin-left: 2px; } .me-action-btn:hover:not(:disabled) { background: var(--dsw-alias-surface-l2, rgba(255,255,255,0.06)); color: var(--dsw-alias-label-primary, #fff); border-color: var(--dsw-alias-border-l1, rgba(255,255,255,0.25)); } .me-action-btn:disabled { opacity: 0.4; cursor: not-allowed; } .me-advanced-container { margin-top: 10px; padding: 12px 14px; border-radius: 8px; background: var(--dsw-alias-surface-l1, rgba(255,255,255,0.02)); border: 1px solid var(--dsw-alias-border-l3, rgba(255,255,255,0.08)); display: flex; flex-direction: column; gap: 12px; } .me-advanced-row { display: flex; flex-direction: column; gap: 8px; } .me-advanced-row-header { display: flex; align-items: center; justify-content: space-between; } .me-section-title { font-size: 12px; font-weight: 500; color: var(--dsw-alias-label-secondary, #aaa); } .me-checkbox-group { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; } .me-checkbox-label { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; cursor: pointer; color: var(--dsw-alias-label-primary, inherit); user-select: none; } .me-checkbox-label input[type="checkbox"] { cursor: pointer; accent-color: var(--dsw-alias-button-primary-fill, #4e80ee); } .me-effort-tag { font-size: 11px; line-height: 16px; padding: 2px 7px; border-radius: 4px; background: var(--dsw-alias-surface-l2, rgba(255,255,255,0.06)); border: 1px solid var(--dsw-alias-border-l3, rgba(255,255,255,0.1)); color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; display: inline-flex; align-items: center; gap: 4px; transition: all 120ms ease; user-select: none; } .me-effort-tag.active { background: rgba(157, 125, 250, 0.15); border-color: rgba(157, 125, 250, 0.4); color: #b59fff; font-weight: 500; } .me-diff-table { width: 100%; border-collapse: collapse; margin: 14px 0; font-size: 13px; border-radius: 8px; overflow: hidden; border: 1px solid var(--dsw-alias-border-l2, rgba(255,255,255,0.12)); } .me-diff-table th, .me-diff-table td { padding: 9px 12px; border-bottom: 1px solid var(--dsw-alias-border-l3, rgba(255,255,255,0.08)); text-align: left; } .me-diff-table th { background: var(--dsw-alias-surface-l2, rgba(255,255,255,0.04)); color: var(--dsw-alias-label-secondary, #999); font-weight: 500; font-size: 12px; } .me-diff-table tr:last-child td { border-bottom: none; } .me-val-new { color: var(--dsw-alias-state-success-primary, #10b981); font-weight: 500; } .me-val-old { color: var(--dsw-alias-label-tertiary, #777); text-decoration: line-through; margin-right: 6px; } /* TOOLBAR: WRAP [+] AND [📎] TOGETHER IN A PILL ISLAND CONTAINER (ON THE FAR LEFT) */ div[class*="tools"], div[class*="InputBar_module_css_tools"] { display: flex !important; align-items: center !important; } div[data-slot="conversation.input.left"] { order: -10 !important; display: inline-flex !important; align-items: center !important; } .me-pill-island { box-sizing: border-box; display: inline-flex; align-items: center; gap: 2px; padding: 2px 4px; height: 28px; border-radius: 14px; border: 1px solid var(--dsw-alias-border-l3, rgba(255, 255, 255, 0.1)); background: var(--dsw-alias-surface-l1, rgba(255, 255, 255, 0.03)); margin-right: 6px; flex-shrink: 0; } .me-pill-btn { box-sizing: border-box; width: 22px; height: 22px; border-radius: 50% !important; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #999); display: inline-flex; align-items: center; justify-content: center; cursor: pointer; transition: all 120ms ease; padding: 0; } .me-pill-btn:hover:not(:disabled) { background: var(--dsw-alias-surface-l2, rgba(255,255,255,0.08)) !important; color: var(--dsw-alias-label-primary, #fff); } .me-pill-btn:disabled { opacity: 0.4; cursor: not-allowed; } /* HIDE THE NATIVE STANDALONE PLUS BUTTON SINCE IT IS RE-HOSTED IN THE PILL ISLAND */ button.uV2eYG_add, button[class*="InputBar_module_css_add"] { display: none !important; } /* HIDE DEFAULT TRIGGER AND SHOW CODEX TRIGGER */ div[class*="_7KE1Ra_root"], div[class*="ModelSelect_module_css_root"] { display: none !important; } /* CODEX-STYLE POPUP & SLIDER STYLES: SEAMLESS NO BORDER NORMALLY, PURE OUTLINE (NO BG TINT) ON HOVER/OPEN */ .me-codex-trigger { box-sizing: border-box; display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 10px; border-radius: 14px; border: 1px solid transparent; background: transparent !important; color: var(--dsw-alias-label-primary, #e0e0e0); font-size: 12px; font-weight: 500; cursor: pointer; transition: all 140ms ease; } .me-codex-trigger:hover:not(:disabled), .me-codex-trigger.active-open { background: transparent !important; border-color: var(--dsw-alias-border-l2, rgba(255, 255, 255, 0.16)) !important; } .me-codex-trigger-chevron { color: var(--dsw-alias-label-tertiary, #888); transition: transform 140ms ease; } .me-codex-trigger-chevron.open { transform: rotate(180deg); } .me-codex-popup { position: absolute; bottom: calc(100% + 8px); right: 0; width: 290px; padding: 16px; border-radius: 16px; background: var(--dsw-alias-surface-overlay, #1b1c21); box-shadow: 0 12px 36px rgba(0,0,0,0.55), 0 0 0 1px var(--dsw-alias-border-l3, rgba(255,255,255,0.08)); z-index: 1000; user-select: none; font-family: inherit; color: var(--dsw-alias-label-primary, #fff); } .me-codex-topbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; } .me-codex-icon-btn { background: none; border: none; color: var(--dsw-alias-label-secondary, #8a8d9b); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; padding: 4px; border-radius: 6px; transition: all 120ms ease; } .me-codex-icon-btn:hover { color: var(--dsw-alias-label-primary, #fff); background: var(--dsw-alias-surface-l2, rgba(255,255,255,0.06)); } .me-codex-center { display: flex; flex-direction: column; align-items: center; cursor: pointer; } .me-codex-effort-title { font-size: 15px; font-weight: 600; color: var(--dsw-alias-button-primary-fill, #3b82f6); display: flex; align-items: center; gap: 4px; } .me-codex-model-name { font-size: 12px; color: var(--dsw-alias-label-secondary, #8a8d9b); margin-top: 1px; display: flex; align-items: center; gap: 3px; } .me-codex-model-name:hover { color: var(--dsw-alias-label-primary, #e0e0e0); } /* SLIDER TRACK & THUMB (DSH COMPLIANT: NO CLIP, CALC MARGINS, SOFT SKY-BLUE FILL) */ .me-slider-track-wrap { position: relative; height: 38px; display: flex; align-items: center; cursor: pointer; user-select: none; } .me-slider-track { width: 100%; height: 26px; border-radius: 13px; background: var(--dsw-alias-surface-l2, rgba(255, 255, 255, 0.08)); position: relative; } .me-slider-active-fill { position: absolute; left: 0; top: 0; bottom: 0; background: linear-gradient(90deg, #2563eb, #38bdf8); border-radius: 13px; box-shadow: 0 0 10px rgba(56, 189, 248, 0.25); transition: width 120ms ease; } .me-slider-dots-layer { position: absolute; left: 16px; right: 16px; top: 0; bottom: 0; display: flex; justify-content: space-between; align-items: center; pointer-events: none; } .me-slider-dot { width: 5px; height: 5px; border-radius: 50%; background: rgba(255, 255, 255, 0.35); transition: background 120ms ease; } .me-slider-dot.lit { background: #ffffff; box-shadow: 0 0 4px rgba(255, 255, 255, 0.8); } .me-slider-thumb { position: absolute; top: 50%; width: 32px; height: 32px; border-radius: 50%; background: #ffffff; border: 1px solid rgba(56, 189, 248, 0.3); box-shadow: 0 3px 10px rgba(0,0,0,0.45), 0 0 10px rgba(56, 189, 248, 0.3); transform: translate(-50%, -50%) scale(1); pointer-events: none; transition: left 120ms ease, transform 160ms cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 160ms ease; } .me-slider-track-wrap:hover .me-slider-thumb { transform: translate(-50%, -50%) scale(1.08); box-shadow: 0 4px 14px rgba(0,0,0,0.5), 0 0 14px rgba(56, 189, 248, 0.45); } .me-slider-track-wrap:active .me-slider-thumb { transform: translate(-50%, -50%) scale(1.15); box-shadow: 0 5px 18px rgba(0,0,0,0.6), 0 0 18px rgba(56, 189, 248, 0.55); } /* MODEL PICKER LIST VIEW INSIDE POPUP (DISTINCT GROUP HEADERS & NESTED INDENT) */ .me-model-picker-list { max-height: 240px; overflow-y: auto; margin: -8px -8px 0; padding: 6px 8px 10px; display: flex; flex-direction: column; gap: 3px; } .me-model-group-section { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l3, rgba(255, 255, 255, 0.08)); } .me-model-group-section:first-child { margin-top: 0; padding-top: 2px; border-top: none; } .me-model-picker-group { font-size: 11px; color: #60a5fa; font-weight: 600; padding: 4px 8px; text-transform: uppercase; letter-spacing: 0.06em; display: inline-flex; align-items: center; gap: 4px; background: rgba(59, 130, 246, 0.08); border-radius: 4px; margin-bottom: 4px; } .me-model-picker-item { box-sizing: border-box; width: 100%; padding: 7px 10px 7px 14px; border-radius: 8px; background: transparent; border: none; color: var(--dsw-alias-label-primary, #e2e8f0); font-size: 13px; text-align: left; cursor: pointer; display: flex; align-items: center; justify-content: space-between; transition: all 120ms ease; } .me-model-picker-item:hover { background: var(--dsw-alias-surface-l2, rgba(255,255,255,0.06)); color: #fff; } .me-model-picker-item.active { background: rgba(56, 189, 248, 0.12); color: #38bdf8; font-weight: 500; } \`; 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); } const THINKING_LEVELS_ALL = ["minimal", "low", "medium", "high", "xhigh", "max"]; let modelsDevGlobalCache = null; let 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 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; } function PrefillModal({ isOpen, onClose, original, suggested, onApply, t }) { if (!isOpen || !suggested) return null; const [selectedFields, setSelectedFields] = (0, react.useState)({ name: Boolean(suggested.name && suggested.name !== original.name), contextWindow: Boolean(suggested.contextWindow && suggested.contextWindow !== original.contextWindow), maxTokens: Boolean(suggested.maxTokens && suggested.maxTokens !== original.maxTokens), input: Boolean(suggested.hasImage !== (Array.isArray(original.input) && original.input.includes("image"))), reasoningEfforts: Boolean(suggested.hasReasoning !== (Boolean(original.reasoningEfforts) && original.reasoningEfforts !== false)) }); const toggle = (f) => setSelectedFields((prev) => ({ ...prev, [f]: !prev[f] })); const handleApply = () => { const p = {}; if (selectedFields.name && suggested.name) p.name = suggested.name; if (selectedFields.contextWindow && suggested.contextWindow) p.contextWindow = suggested.contextWindow; if (selectedFields.maxTokens && suggested.maxTokens) p.maxTokens = suggested.maxTokens; if (selectedFields.input) p.input = suggested.hasImage ? ["text", "image"] : ["text"]; if (selectedFields.reasoningEfforts) { p.reasoningEfforts = suggested.hasReasoning ? (suggested.reasoningLevels || { off: "none", low: "low", medium: "medium", high: "high" }) : false; } onApply(p); onClose(); }; const origImg = Array.isArray(original.input) && original.input.includes("image") ? t("visionSupported") : t("visionOnlyText"); const suggImg = suggested.hasImage ? t("visionSupported") : t("visionOnlyText"); const origReason = original.reasoningEfforts === false || !original.reasoningEfforts ? t("thinkingOff") : Object.keys(original.reasoningEfforts).filter((k) => k !== "off").join("/") || t("thinkingOn"); const suggReason = suggested.hasReasoning ? Object.keys(suggested.reasoningLevels || {}).filter((k) => k !== "off").join("/") || t("thinkingOn") : t("thinkingOff"); return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, { open: isOpen, onClose, title: t("modalTitle"), closeLabel: t("cancel"), className: ModelsSection_module_css_default["fetchDialog"], footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", onClick: onClose, children: t("cancel") }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "primary", onClick: handleApply, children: t("applySelected") }) ] }), children: (0, react_jsx_runtime.jsxs)("div", { style: { padding: "4px 0", color: "var(--dsw-alias-label-primary)" }, children: [ (0, react_jsx_runtime.jsxs)("p", { style: { margin: "0 0 14px", fontSize: "13px", color: "var(--dsw-alias-label-secondary)" }, children: [ t("matchedModelLabel"), (0, react_jsx_runtime.jsx)("strong", { style: { color: "var(--dsw-alias-label-primary)", fontWeight: 600 }, children: suggested.sourceModel.name || suggested.sourceModel.id }), \` (\${suggested.sourceModel.providerName || suggested.sourceModel.providerKey})\` ] }), (0, react_jsx_runtime.jsxs)("table", { className: "me-diff-table", children: [ (0, react_jsx_runtime.jsx)("thead", { children: (0, react_jsx_runtime.jsxs)("tr", { children: [ (0, react_jsx_runtime.jsx)("th", { style: { width: "42px", textAlign: "center" }, children: t("thSelect") }), (0, react_jsx_runtime.jsx)("th", { style: { width: "120px" }, children: t("thField") }), (0, react_jsx_runtime.jsx)("th", { children: t("thCurrent") }), (0, react_jsx_runtime.jsx)("th", { children: t("thRecommended") }) ] }) }), (0, react_jsx_runtime.jsxs)("tbody", { children: [ (0, react_jsx_runtime.jsxs)("tr", { children: [ (0, react_jsx_runtime.jsx)("td", { style: { textAlign: "center" }, children: (0, react_jsx_runtime.jsx)("input", { type: "checkbox", checked: selectedFields.name, onChange: () => toggle("name") }) }), (0, react_jsx_runtime.jsx)("td", { children: t("fieldName") }), (0, react_jsx_runtime.jsx)("td", { children: original.name || t("fieldUnset") }), (0, react_jsx_runtime.jsx)("td", { className: "me-val-new", children: suggested.name || "-" }) ] }), (0, react_jsx_runtime.jsxs)("tr", { children: [ (0, react_jsx_runtime.jsx)("td", { style: { textAlign: "center" }, children: (0, react_jsx_runtime.jsx)("input", { type: "checkbox", checked: selectedFields.contextWindow, onChange: () => toggle("contextWindow") }) }), (0, react_jsx_runtime.jsx)("td", { children: t("fieldContext") }), (0, react_jsx_runtime.jsx)("td", { children: formatCapacity(original.contextWindow) || t("fieldDefault") }), (0, react_jsx_runtime.jsx)("td", { className: "me-val-new", children: formatCapacity(suggested.contextWindow) || "-" }) ] }), (0, react_jsx_runtime.jsxs)("tr", { children: [ (0, react_jsx_runtime.jsx)("td", { style: { textAlign: "center" }, children: (0, react_jsx_runtime.jsx)("input", { type: "checkbox", checked: selectedFields.maxTokens, onChange: () => toggle("maxTokens") }) }), (0, react_jsx_runtime.jsx)("td", { children: t("fieldMaxTokens") }), (0, react_jsx_runtime.jsx)("td", { children: formatCapacity(original.maxTokens) || t("fieldDefault") }), (0, react_jsx_runtime.jsx)("td", { className: "me-val-new", children: formatCapacity(suggested.maxTokens) || "-" }) ] }), (0, react_jsx_runtime.jsxs)("tr", { children: [ (0, react_jsx_runtime.jsx)("td", { style: { textAlign: "center" }, children: (0, react_jsx_runtime.jsx)("input", { type: "checkbox", checked: selectedFields.input, onChange: () => toggle("input") }) }), (0, react_jsx_runtime.jsx)("td", { children: t("fieldInput") }), (0, react_jsx_runtime.jsx)("td", { children: origImg }), (0, react_jsx_runtime.jsx)("td", { className: "me-val-new", children: suggImg }) ] }), (0, react_jsx_runtime.jsxs)("tr", { children: [ (0, react_jsx_runtime.jsx)("td", { style: { textAlign: "center" }, children: (0, react_jsx_runtime.jsx)("input", { type: "checkbox", checked: selectedFields.reasoningEfforts, onChange: () => toggle("reasoningEfforts") }) }), (0, react_jsx_runtime.jsx)("td", { children: t("fieldReasoning") }), (0, react_jsx_runtime.jsx)("td", { children: origReason }), (0, react_jsx_runtime.jsx)("td", { className: "me-val-new", children: suggReason }) ] }) ] }) ] }) ] }) }); } function ModelListEditor(props) { const { models, onChange, probe, api, t, disabled } = props; const [busy, setBusy] = (0, react.useState)(false); const [failure, setFailure] = (0, react.useState)(void 0); const [candidates, setCandidates] = (0, react.useState)(void 0); const [picked, setPicked] = (0, react.useState)(/* @__PURE__ */ new Set()); const [expanded, setExpanded] = (0, react.useState)(/* @__PURE__ */ new Set()); const [editing, setEditing] = (0, react.useState)(/* @__PURE__ */ new Map()); // Enhancer states const [matchingIndex, setMatchingIndex] = (0, react.useState)(null); const [confirmModalData, setConfirmModalData] = (0, react.useState)(null); const [batchMatching, setBatchMatching] = (0, react.useState)(false); const [notice, setNotice] = (0, react.useState)(null); const bufferKey = (index, field) => \`\${String(index)}:\${field}\`; const editCapacity = (index, field, text) => { setEditing((current) => new Map(current).set(bufferKey(index, field), text)); patch(index, { [field]: parseCapacity(text) }); }; const capacityText = (model, index, field) => editing.get(bufferKey(index, field)) ?? capacitySpelling(numberOf(model, field)); const reindexOnRemove = (current, index) => { const next = /* @__PURE__ */ new Map(); for (const [key, value] of current) { const at = Number(key.slice(0, key.indexOf(":"))); if (at === index) continue; next.set(at > index ? key.replace(/^\\d+/, String(at - 1)) : key, value); } return next; }; const toggleExpanded = (index) => { setExpanded((current) => { const next = new Set(current); if (!next.delete(index)) next.add(index); return next; }); }; const patch = (index, next) => { onChange(models.map((model, at) => { if (at !== index) return model; const merged = { ...model, ...next }; const cleared = new Set(Object.entries(next).filter(([, value]) => value === void 0 || value === "").map(([key]) => key)); return Object.fromEntries(Object.entries(merged).filter(([key]) => !cleared.has(key))); })); }; const fetchModels = async () => { setBusy(true); setFailure(void 0); try { const response = await api.llm.discoverModels({ settingsNs: probe.settingsNs, ...probe.provider === void 0 ? {} : { provider: probe.provider }, ...probe.baseURL === void 0 || probe.baseURL.length === 0 ? {} : { baseURL: probe.baseURL }, ...probe.api === void 0 ? {} : { api: probe.api }, ...probe.apiKey === void 0 ? {} : { apiKey: probe.apiKey } }); if (!response.result.ok) { setFailure(response.result.error.message); return; } const found = response.result.value.models; if (found.length === 0) { setFailure(t("fetchEmpty")); return; } const known = new Set(models.map((model) => textOf(model, "id"))); setCandidates(found); setPicked(new Set(found.filter((model) => !known.has(model.id)).map((model) => model.id))); } catch (error) { setFailure(messageOf(error)); } finally { setBusy(false); } }; const closePicker = () => { setCandidates(void 0); setPicked(/* @__PURE__ */ new Set()); }; const adoptPicked = () => { if (candidates === void 0) return; const byId = new Map(models.map((model) => [textOf(model, "id"), model])); for (const candidate of candidates) { if (!picked.has(candidate.id)) continue; byId.set(candidate.id, byId.get(candidate.id) ?? adopt(candidate)); } onChange([...byId.values()]); closePicker(); }; const toggle = (id) => { setPicked((current) => { const next = new Set(current); if (!next.delete(id)) next.add(id); return next; }); }; const activeCandidates = candidates ?? []; const allCandidatesPicked = activeCandidates.length > 0 && activeCandidates.every((candidate) => picked.has(candidate.id)); const toggleAllCandidates = () => { setPicked((current) => { return activeCandidates.every((candidate) => current.has(candidate.id)) ? /* @__PURE__ */ new Set() : new Set(activeCandidates.map((candidate) => candidate.id)); }); }; // Enhancer models.dev single match action const handleSingleDevMatch = async (model, index) => { if (!model.id) { setNotice(t("singleFillRequireId")); return; } setMatchingIndex(index); setNotice(null); try { const allDevModels = await fetchAllModelsDev(); const matched = findDevModel(model.id, allDevModels); if (!matched) { setNotice(t("singleFillNotFound", { id: model.id })); return; } const hasImage = Boolean(matched.modalities?.input?.includes("image")); const hasReasoning = Boolean(matched.reasoning); let reasoningLevels = null; 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"; } } setConfirmModalData({ index, original: model, suggested: { sourceModel: matched, name: matched.name || model.name, contextWindow: matched.limit?.context || model.contextWindow, maxTokens: matched.limit?.output || model.maxTokens, hasImage, hasReasoning, reasoningLevels } }); } catch (err) { setNotice(t("singleFillFetchFailed", { message: err.message || err })); } finally { setMatchingIndex(null); } }; // Enhancer models.dev batch match action const handleBatchDevMatch = async () => { if (!models || models.length === 0) return; setBatchMatching(true); setNotice(null); try { const allDevModels = await fetchAllModelsDev(); let count = 0; const cleanedModels = models.filter((m) => m && typeof m.id === "string" && m.id.trim().length > 0); if (cleanedModels.length === 0) { setNotice(t("fillNoIdError")); return; } const nextModels = cleanedModels.map((m) => { const matched = findDevModel(m.id, allDevModels); if (!matched) return m; count++; const hasImage = Boolean(matched.modalities?.input?.includes("image")); const hasReasoning = Boolean(matched.reasoning); let reasoningLevels = undefined; 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"; } } return { ...m, name: m.name || matched.name, contextWindow: m.contextWindow || matched.limit?.context, maxTokens: m.maxTokens || matched.limit?.output, input: m.input || (hasImage ? ["text", "image"] : ["text"]), reasoningEfforts: m.reasoningEfforts !== undefined ? m.reasoningEfforts : (hasReasoning ? reasoningLevels : false) }; }); onChange(nextModels); setNotice(t("fillSuccessNotice", { count, total: cleanedModels.length })); } catch (err) { setNotice(t("fillFailedNotice", { message: err.message || err })); } finally { setBatchMatching(false); } }; const askable = probe.provider !== void 0 || probe.baseURL !== void 0 && probe.baseURL.length > 0; const validationErr = validateDeepSeekModels(models); return (0, react_jsx_runtime.jsxs)("section", { className: ModelsSection_module_css_default["modelCatalog"], "aria-label": t("models"), children: [ (0, react_jsx_runtime.jsxs)("div", { className: ModelsSection_module_css_default["modelListHead"], children: [ (0, react_jsx_runtime.jsxs)("div", { className: ModelsSection_module_css_default["modelCatalogHeading"], children: [ (0, react_jsx_runtime.jsx)("span", { className: ModelsSection_module_css_default["modelCatalogTitle"], children: t("models") }), props.overridden === void 0 ? null : (0, react_jsx_runtime.jsx)("span", { className: ModelsSection_module_css_default["modelCatalogMeta"], children: props.overridden ? t("modelsCustomized") : t("modelsInherited") }) ] }), props.overridden === true && props.onReset !== void 0 ? (0, react_jsx_runtime.jsx)("button", { type: "button", className: ModelsSection_module_css_default["linkButton"], disabled, onClick: props.onReset, children: t("resetModels") }) : null, (0, react_jsx_runtime.jsx)("button", { type: "button", className: ModelsSection_module_css_default["linkButton"], disabled: disabled || busy || !askable || props.probeBlocked !== void 0, title: props.probeBlocked !== void 0 ? t(props.probeBlocked) : askable ? void 0 : t("fetchNeedsBaseUrl"), onClick: () => { fetchModels(); }, children: busy ? t("fetching") : t("fetchModels") }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: ModelsSection_module_css_default["linkButton"], disabled: disabled || batchMatching || models.length === 0, onClick: handleBatchDevMatch, title: t("batchBtnTitle"), children: batchMatching ? t("batchBtnBusy") : t("batchBtn") }) ] }), notice ? (0, react_jsx_runtime.jsx)("p", { className: ModelsSection_module_css_default["advancedHint"], style: { color: notice.includes("失败") || notice.includes("Failed") || notice.includes("failed") ? "var(--dsw-alias-state-error-primary)" : "var(--dsw-alias-state-success-primary)", margin: "4px 0 8px" }, children: notice }) : null, validationErr ? (0, react_jsx_runtime.jsxs)("p", { className: ModelsSection_module_css_default["error"], style: { margin: "4px 0 8px" }, children: [ t("saveBlockedHint", { index: validationErr.index + 1, reason: t(validationErr.key) }) ] }) : null, models.length === 0 ? (0, react_jsx_runtime.jsx)("p", { className: ModelsSection_module_css_default["modelEmpty"], children: t("modelsEmpty") }) : null, models.map((model, index) => { const hasImage = Array.isArray(model.input) && model.input.includes("image"); const reasoningEnabled = Boolean(model.reasoningEfforts) && model.reasoningEfforts !== false; const activeLevels = reasoningEnabled && typeof model.reasoningEfforts === "object" ? Object.keys(model.reasoningEfforts).filter((k) => k !== "off") : []; return (0, react_jsx_runtime.jsxs)("div", { className: ModelsSection_module_css_default["modelEntry"], children: [ (0, react_jsx_runtime.jsxs)("div", { className: ModelsSection_module_css_default["modelRow"], children: [ (0, react_jsx_runtime.jsx)("input", { className: ModelsSection_module_css_default["input"], type: "text", value: textOf(model, "id"), placeholder: t("modelId"), "aria-label": \`\${t("modelId")} \${index + 1}\`, disabled, onChange: (event) => { patch(index, { id: event.target.value }); } }), (0, react_jsx_runtime.jsx)("input", { className: ModelsSection_module_css_default["input"], type: "text", value: textOf(model, "name"), placeholder: t("modelName"), "aria-label": \`\${t("modelName")} \${index + 1}\`, disabled, onChange: (event) => { patch(index, { name: event.target.value === "" ? void 0 : event.target.value }); } }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: ModelsSection_module_css_default["iconButton"], "aria-label": \`\${t("modelAdvanced")} \${index + 1}\`, "aria-expanded": expanded.has(index), title: t("modelAdvanced"), onClick: () => { toggleExpanded(index); }, children: (0, react_jsx_runtime.jsx)(IconChevron, { open: expanded.has(index) }) }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: \`\${ModelsSection_module_css_default["iconButton"]} \${ModelsSection_module_css_default["iconButtonDanger"]}\`, "aria-label": \`\${t("removeModel")} \${index + 1}\`, title: t("removeModel"), disabled, onClick: () => { onChange(models.filter((_model, at) => at !== index)); setExpanded((current) => { const next = /* @__PURE__ */ new Set(); for (const at of current) if (at < index) next.add(at); else if (at > index) next.add(at - 1); return next; }); setEditing((current) => reindexOnRemove(current, index)); }, children: (0, react_jsx_runtime.jsx)(IconTrash, {}) }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: "me-action-btn", disabled: disabled || matchingIndex === index || !model.id, title: t("singleBtnTitle"), onClick: () => { handleSingleDevMatch(model, index); }, children: matchingIndex === index ? t("singleBtnBusy") : t("singleBtn") }) ] }), (hasImage || reasoningEnabled) ? (0, react_jsx_runtime.jsxs)("div", { className: "me-model-badges-row", children: [ hasImage ? (0, react_jsx_runtime.jsx)("span", { className: "me-badge me-badge-vision", title: t("badgeVisionTitle"), children: t("badgeVision") }) : null, reasoningEnabled ? (0, react_jsx_runtime.jsx)("span", { className: "me-badge me-badge-thinking", title: t("badgeThinkingTitle", { levels: activeLevels.join("/") || t("defaultEffort") }), children: t("badgeThinking") + (activeLevels.length ? \` · \${activeLevels.join("/")}\` : "") }) : null ] }) : null, expanded.has(index) ? (0, react_jsx_runtime.jsxs)("div", { className: "me-advanced-container", children: [ (0, react_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "12px" }, children: [ (0, react_jsx_runtime.jsxs)("label", { className: ModelsSection_module_css_default["modelField"], style: { flex: 1 }, children: [ (0, react_jsx_runtime.jsx)("span", { className: ModelsSection_module_css_default["modelFieldLabel"], children: t("modelContextWindow") }), (0, react_jsx_runtime.jsx)("input", { className: ModelsSection_module_css_default["input"], type: "text", inputMode: "numeric", value: capacityText(model, index, "contextWindow"), placeholder: CAPACITY_HINT.contextWindow, "aria-label": \`\${t("modelContextWindow")} \${index + 1}\`, disabled, onChange: (event) => { editCapacity(index, "contextWindow", event.target.value); } }) ] }), (0, react_jsx_runtime.jsxs)("label", { className: ModelsSection_module_css_default["modelField"], style: { flex: 1 }, children: [ (0, react_jsx_runtime.jsx)("span", { className: ModelsSection_module_css_default["modelFieldLabel"], children: t("modelMaxTokens") }), (0, react_jsx_runtime.jsx)("input", { className: ModelsSection_module_css_default["input"], type: "text", inputMode: "numeric", value: capacityText(model, index, "maxTokens"), placeholder: CAPACITY_HINT.maxTokens, "aria-label": \`\${t("modelMaxTokens")} \${index + 1}\`, disabled, onChange: (event) => { editCapacity(index, "maxTokens", event.target.value); } }) ] }) ] }), (0, react_jsx_runtime.jsxs)("div", { className: "me-advanced-row", children: [ (0, react_jsx_runtime.jsx)("div", { className: "me-section-title", children: t("modalitiesTitle") }), (0, react_jsx_runtime.jsxs)("div", { className: "me-checkbox-group", children: [ (0, react_jsx_runtime.jsxs)("label", { className: "me-checkbox-label", children: [ (0, react_jsx_runtime.jsx)("input", { type: "checkbox", checked: true, disabled: true }), t("modalityText") ] }), (0, react_jsx_runtime.jsxs)("label", { className: "me-checkbox-label", children: [ (0, react_jsx_runtime.jsx)("input", { type: "checkbox", checked: hasImage, disabled, onChange: (e) => { const currentInput = Array.isArray(model.input) ? [...model.input] : ["text"]; if (e.target.checked) { if (!currentInput.includes("image")) currentInput.push("image"); } else { const at = currentInput.indexOf("image"); if (at !== -1) currentInput.splice(at, 1); } patch(index, { input: currentInput }); } }), t("modalityVision") ] }) ] }) ] }), (0, react_jsx_runtime.jsxs)("div", { className: "me-advanced-row", children: [ (0, react_jsx_runtime.jsxs)("div", { className: "me-advanced-row-header", children: [ (0, react_jsx_runtime.jsx)("div", { className: "me-section-title", children: t("reasoningTitle") }), (0, react_jsx_runtime.jsxs)("label", { className: "me-checkbox-label", style: { fontSize: "12px" }, children: [ (0, react_jsx_runtime.jsx)("input", { type: "checkbox", checked: reasoningEnabled, disabled, onChange: (e) => { if (e.target.checked) { patch(index, { reasoningEfforts: { off: "none", low: "low", medium: "medium", high: "high" } }); } else { patch(index, { reasoningEfforts: false }); } } }), t("enableReasoning") ] }) ] }), reasoningEnabled ? (0, react_jsx_runtime.jsx)("div", { className: "me-checkbox-group", style: { gap: "6px" }, children: THINKING_LEVELS_ALL.map((lvl) => { const map = typeof model.reasoningEfforts === "object" && model.reasoningEfforts !== null ? model.reasoningEfforts : {}; const active = map[lvl] !== undefined; return (0, react_jsx_runtime.jsxs)("button", { type: "button", className: \`me-effort-tag \${active ? "active" : ""}\`, disabled, onClick: () => { const nextMap = { ...map }; if (active) { delete nextMap[lvl]; } else { nextMap[lvl] = lvl; } patch(index, { reasoningEfforts: nextMap }); }, children: [ (0, react_jsx_runtime.jsx)("span", { style: { display: "inline-block", width: "6px", height: "6px", borderRadius: "50%", background: active ? "#9d7dfa" : "var(--dsw-alias-label-tertiary, #666)" } }), lvl ] }, lvl); }) }) : null ] }) ] }) : null ] }, index); }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: ModelsSection_module_css_default["addModelButton"], disabled, onClick: () => { onChange([...models, { id: "" }]); }, children: t("addModel") }), failure !== void 0 ? (0, react_jsx_runtime.jsx)("p", { className: ModelsSection_module_css_default["error"], children: failure }) : null, (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, { open: candidates !== void 0, onClose: closePicker, title: t("fetchTitle"), closeLabel: t("close"), description: t("fetchDescription"), className: ModelsSection_module_css_default["fetchDialog"], footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", onClick: closePicker, children: t("cancel") }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", onClick: adoptPicked, children: t("fetchAdopt") })] }), children: [(0, react_jsx_runtime.jsx)("div", { className: ModelsSection_module_css_default["candidateActions"], children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", onClick: toggleAllCandidates, children: t(allCandidatesPicked ? "fetchDeselectAll" : "fetchSelectAll") }) }), (0, react_jsx_runtime.jsx)("div", { className: ModelsSection_module_css_default["candidateList"], children: (candidates ?? []).map((candidate) => (0, react_jsx_runtime.jsx)("div", { className: ModelsSection_module_css_default["candidate"], children: (0, react_jsx_runtime.jsxs)("label", { className: ModelsSection_module_css_default["candidateLabel"], children: [(0, react_jsx_runtime.jsx)("input", { type: "checkbox", checked: picked.has(candidate.id), onChange: () => { toggle(candidate.id); } }), (0, react_jsx_runtime.jsx)("span", { className: ModelsSection_module_css_default["candidateId"], children: candidate.id })] }) }, candidate.id)) })] }), confirmModalData ? (0, react_jsx_runtime.jsx)(PrefillModal, { isOpen: true, original: confirmModalData.original, suggested: confirmModalData.suggested, t, onClose: () => setConfirmModalData(null), onApply: (patchData) => { patch(confirmModalData.index, patchData); setNotice(t("singleFillApplied", { id: confirmModalData.original.id })); } }) : null ] }); } //#endregion `; // Splice ModelListEditor const startTag = "//#region lib/types/client/ModelListEditor.js"; const endTag = "//#endregion\n\t\t//#region lib/types/client/CustomProviderCard.js"; const startIndex = origCode.indexOf(startTag); const endIndex = origCode.indexOf(endTag); if (startIndex === -1 || endIndex === -1) { console.error("Failed to find replacement markers!"); process.exit(1); } let finalCode = origCode.slice(0, startIndex) + enhancedModelListEditorCode.trim() + "\n\t\t" + origCode.slice(endIndex); // Update module loader id finalCode = finalCode.replace('id: "@deepseek-ai/dsh-client-ui-settings-models"', 'id: "dsh-plugin-model-enhancer"'); // Extra components: Paperclip & Codex Slider with dynamic language detection const extraComponentsCode = ` // Helper to detect current language ("zh" or "en") function isZhLocale() { return typeof document !== "undefined" && (document.documentElement.lang || "").toLowerCase().startsWith("zh"); } // Paperclip file upload button for conversation.input.left function PaperclipUploadButton(props) { const fileInputRef = (0, react.useRef)(null); const isZh = isZhLocale(); const onButtonClick = () => { fileInputRef.current?.click(); }; const onFileChange = (e) => { const files = e.target.files; if (!files || files.length === 0) return; const textarea = document.querySelector("textarea"); if (textarea) { const dt = new DataTransfer(); for (let i = 0; i < files.length; i++) { dt.items.add(files[i]); } const dropEvt = new DragEvent("drop", { bubbles: true, cancelable: true, dataTransfer: dt }); textarea.dispatchEvent(dropEvt); } e.target.value = ""; }; const onPlusClick = (e) => { e.preventDefault(); const nativeAdd = document.querySelector("button[class*='uV2eYG_add'], button[class*='InputBar_module_css_add']"); if (nativeAdd) { nativeAdd.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true })); } }; return (0, react_jsx_runtime.jsxs)("div", { className: "me-pill-island", children: [ (0, react_jsx_runtime.jsx)("input", { ref: fileInputRef, type: "file", multiple: true, accept: "image/*,.png,.jpg,.jpeg,.webp,.gif", style: { display: "none" }, onChange: onFileChange }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: "me-pill-btn", title: isZh ? "命令菜单 (/)" : "Commands (/)", "aria-label": "Commands", onClick: onPlusClick, children: (0, react_jsx_runtime.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, react_jsx_runtime.jsx)("path", { d: "M8 3v10M3 8h10" }) }) }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: "me-pill-btn", title: isZh ? "上传图片或文件" : "Attach files or images", "aria-label": "Attach files", onClick: onButtonClick, children: (0, react_jsx_runtime.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, react_jsx_runtime.jsx)("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48" }) }) }) ] }); } // Codex Effort Levels translation and order (Zh & En) const CODEX_LEVELS_ZH = [ { id: "off", label: "关", short: "关" }, { id: "minimal", label: "极低", short: "极低" }, { id: "low", label: "低", short: "低" }, { id: "medium", label: "中", short: "中" }, { id: "high", label: "高", short: "高" }, { id: "xhigh", label: "超高", short: "超高" }, { id: "max", label: "最大", short: "最大" } ]; const CODEX_LEVELS_EN = [ { id: "off", label: "Off", short: "Off" }, { id: "minimal", label: "Minimal", short: "Minimal" }, { id: "low", label: "Low", short: "Low" }, { id: "medium", label: "Medium", short: "Medium" }, { id: "high", label: "High", short: "High" }, { id: "xhigh", label: "X-High", short: "X-High" }, { id: "max", label: "Max", short: "Max" } ]; // Codex-style Model and Reasoning Slider selector function CodexModelSelect(props) { const { directory, load, select, available, locked } = props; const state = (0, react.useSyncExternalStore)(directory.subscribe, directory.getSnapshot); const [open, setOpen] = (0, react.useState)(false); const [showModelPicker, setShowModelPicker] = (0, react.useState)(false); const rootRef = (0, react.useRef)(null); const isZh = isZhLocale(); const codexLevels = isZh ? CODEX_LEVELS_ZH : CODEX_LEVELS_EN; (0, react.useEffect)(() => { if (available) load(); }, [available]); (0, react.useEffect)(() => { if (!open) return; const onMouseDown = (e) => { if (!rootRef.current?.contains(e.target)) { setOpen(false); setShowModelPicker(false); } }; document.addEventListener("mousedown", onMouseDown); return () => document.removeEventListener("mousedown", onMouseDown); }, [open]); const choices = (0, react.useMemo)(() => state.groups.flatMap((g) => g.models.map((m) => ({ group: g, model: m }))), [state.groups]); const currentChoice = choices.find((c) => c.group.id === state.current?.provider && c.model.id === state.current?.model); const currentModel = currentChoice?.model; const reasoning = currentModel?.reasoning; // Available reasoning efforts for this model const availableEfforts = (0, react.useMemo)(() => { if (!reasoning || !reasoning.efforts || reasoning.efforts.length === 0) return []; return reasoning.efforts.map((e) => { const found = codexLevels.find((l) => l.id === e.id); return { id: e.id, label: found?.label || e.name || e.id, short: found?.short || e.name || e.id }; }); }, [reasoning, isZh]); const effectiveEffort = state.current?.reasoningEffort ?? reasoning?.defaultEffort; const currentEffortIndex = (0, react.useMemo)(() => { if (availableEfforts.length === 0) return 0; const idx = availableEfforts.findIndex((e) => e.id === effectiveEffort); return idx === -1 ? 0 : idx; }, [availableEfforts, effectiveEffort]); const currentEffortObj = availableEfforts[currentEffortIndex]; const effortDisplayLabel = currentEffortObj ? currentEffortObj.label : (isZh ? "中" : "Medium"); const triggerModelName = currentModel?.name || (isZh ? "选择模型" : "Select model"); const triggerEffortLabel = reasoning ? (currentEffortObj ? currentEffortObj.short : (isZh ? "默认" : "Default")) : null; const onSelectEffortByIndex = (idx) => { if (!currentChoice || !availableEfforts[idx]) return; const effort = availableEfforts[idx].id; select({ provider: currentChoice.group.id, model: currentChoice.model.id, reasoningEffort: effort }); }; const onResetDefault = () => { if (!currentChoice) return; select({ provider: currentChoice.group.id, model: currentChoice.model.id, reasoningEffort: reasoning?.defaultEffort }); }; const onTrackClick = (e) => { if (availableEfforts.length <= 1) return; const rect = e.currentTarget.getBoundingClientRect(); const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width)); const idx = Math.round(ratio * (availableEfforts.length - 1)); onSelectEffortByIndex(idx); }; if (!available) return null; return (0, react_jsx_runtime.jsxs)("div", { ref: rootRef, style: { position: "relative", display: "inline-flex", alignItems: "center" }, children: [ (0, react_jsx_runtime.jsxs)("button", { type: "button", className: \`me-codex-trigger \${open ? "active-open" : ""}\`, disabled: locked, onClick: () => setOpen(!open), children: [ (0, react_jsx_runtime.jsx)("span", { children: triggerModelName }), triggerEffortLabel ? (0, react_jsx_runtime.jsxs)("span", { style: { color: "#3b82f6", fontWeight: 600 }, children: ["· ", triggerEffortLabel] }) : null, (0, react_jsx_runtime.jsx)("svg", { className: \`me-codex-trigger-chevron \${open ? "open" : ""}\`, width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.8", children: (0, react_jsx_runtime.jsx)("path", { d: "M4 6l4 4 4-4" }) }) ] }), open ? (0, react_jsx_runtime.jsxs)("div", { className: "me-codex-popup", children: [ (0, react_jsx_runtime.jsxs)("div", { className: "me-codex-topbar", children: [ (0, react_jsx_runtime.jsx)("div", { className: "me-codex-icon-btn", title: isZh ? "推理强度" : "Reasoning Effort", children: (0, react_jsx_runtime.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: (0, react_jsx_runtime.jsx)("path", { d: "M13 2L3 14h9l-1 8 10-12h-9l1-8z" }) }) }), (0, react_jsx_runtime.jsxs)("div", { className: "me-codex-center", onClick: () => setShowModelPicker(!showModelPicker), title: isZh ? "点击切换模型" : "Click to switch model", children: [ (0, react_jsx_runtime.jsxs)("div", { className: "me-codex-effort-title", children: [ effortDisplayLabel, (0, react_jsx_runtime.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", style: { transform: showModelPicker ? "rotate(90deg)" : void 0, transition: "transform 140ms ease" }, children: (0, react_jsx_runtime.jsx)("path", { d: "M6 3.5L10.5 8L6 12.5" }) }) ] }), (0, react_jsx_runtime.jsx)("div", { className: "me-codex-model-name", children: currentModel?.name || (isZh ? "选择模型" : "Select model") }) ] }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: "me-codex-icon-btn", title: isZh ? "恢复默认档位" : "Reset to default effort", onClick: onResetDefault, children: (0, react_jsx_runtime.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: (0, react_jsx_runtime.jsx)("path", { d: "M3 12a9 9 0 109-9 9.75 9.75 0 00-6.74 2.74L3 8m0 0V3m0 5h5" }) }) }) ] }), showModelPicker ? (0, react_jsx_runtime.jsx)("div", { className: "me-model-picker-list", children: state.groups.map((group) => (0, react_jsx_runtime.jsxs)("div", { className: "me-model-group-section", children: [ (0, react_jsx_runtime.jsxs)("div", { className: "me-model-picker-group", children: [ (0, react_jsx_runtime.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.8", children: (0, react_jsx_runtime.jsx)("path", { d: "M2 4h12M2 8h12M2 12h8" }) }), group.name ] }), group.models.map((m) => { const active = state.current?.provider === group.id && state.current?.model === m.id; return (0, react_jsx_runtime.jsxs)("button", { type: "button", className: \`me-model-picker-item \${active ? "active" : ""}\`, onClick: () => { select({ provider: group.id, model: m.id, reasoningEffort: m.reasoning?.defaultEffort }); setShowModelPicker(false); }, children: [ (0, react_jsx_runtime.jsx)("span", { children: m.name }), active ? (0, react_jsx_runtime.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "#38bdf8", strokeWidth: "2", children: (0, react_jsx_runtime.jsx)("path", { d: "M3.5 8.5l3 3 6-6" }) }) : null ] }, m.id); }) ] }, group.id)) }) : (0, react_jsx_runtime.jsx)("div", { className: "me-slider-track-wrap", onClick: onTrackClick, children: (0, react_jsx_runtime.jsxs)("div", { className: "me-slider-track", children: [ (0, react_jsx_runtime.jsx)("div", { className: "me-slider-active-fill", style: { width: availableEfforts.length <= 1 ? "100%" : \`calc(16px + (100% - 32px) * \${currentEffortIndex / (availableEfforts.length - 1)})\` } }), (0, react_jsx_runtime.jsx)("div", { className: "me-slider-dots-layer", children: availableEfforts.map((eff, i) => (0, react_jsx_runtime.jsx)("div", { className: \`me-slider-dot \${i <= currentEffortIndex ? "lit" : ""}\` }, eff.id)) }), (0, react_jsx_runtime.jsx)("div", { className: "me-slider-thumb", style: { left: availableEfforts.length <= 1 ? "calc(100% - 16px)" : \`calc(16px + (100% - 32px) * \${currentEffortIndex / (availableEfforts.length - 1)})\` } }) ] }) }) ] }) : null ] }); } `; // Inject i18n keys into original en and zh dictionaries const enLocalesPatch = ` // Model Enhancer English Dictionary keys Object.assign(en, { batchBtn: "Auto-Fill All", batchBtnBusy: "Filling…", batchBtnTitle: "Auto-match and prefill missing parameters from models.dev", singleBtn: "Auto-Fill", singleBtnBusy: "Filling…", 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}"', 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", applySelected: "Apply Selected" }); `; const zhLocalesPatch = ` // Model Enhancer Chinese Dictionary keys Object.assign(zh, { batchBtn: "一键补全", batchBtnBusy: "补全中...", batchBtnTitle: "根据模型 ID 从 models.dev 自动匹配并预填充缺失参数", singleBtn: "智能补全", singleBtnBusy: "补全中", singleBtnTitle: "从 models.dev 获取该模型推荐参数", badgeVision: "图像", badgeVisionTitle: "支持图像输入 (Vision)", badgeThinking: "思考", badgeThinkingTitle: "思考档位: {levels}", defaultEffort: "默认", modalitiesTitle: "输入模态支持 (Input Modalities)", modalityText: "文本输入 (Text)", modalityVision: "图像输入 (Vision)", reasoningTitle: "推理思考档位 (Reasoning Efforts)", enableReasoning: "启用深度思考", saveBlockedHint: "保存受阻提示:模型 {index} {reason}", fillNoIdError: "列表中没有填写模型 ID 的有效模型", fillSuccessNotice: "一键补全完成:已匹配并更新 {count}/{total} 个模型", fillFailedNotice: "一键补全失败: {message}", singleFillRequireId: "请先填写模型 ID", singleFillNotFound: '未在 models.dev 中找到与 "{id}" 匹配的模型信息', singleFillFetchFailed: "获取 models.dev 失败: {message}", singleFillApplied: '已预填充 "{id}" 推荐参数', modalTitle: "models.dev 预填充确认与选择", matchedModelLabel: "检索到匹配模型:", thSelect: "选用", thField: "配置项", thCurrent: "当前设置", thRecommended: "models.dev 推荐值", fieldName: "显示名称", fieldContext: "上下文长度", fieldMaxTokens: "最大输出", fieldInput: "图像输入", fieldReasoning: "推理思考等级", fieldUnset: "(未设置)", fieldDefault: "(默认)", visionSupported: "支持图像", visionOnlyText: "仅文本", thinkingOff: "关闭思考", thinkingOn: "开启", applySelected: "应用已选推荐项" }); `; // Insert locales patches into finalCode const zhEndTag = "const zh = {"; const zhIdx = finalCode.indexOf(zhEndTag); const zhObjEndIdx = finalCode.indexOf("};", zhIdx) + 2; finalCode = finalCode.slice(0, zhObjEndIdx) + enLocalesPatch + zhLocalesPatch + finalCode.slice(zhObjEndIdx); // Append extraComponentsCode and custom apply const applyStartTag = "function apply(ctx) {"; const applyIdx = finalCode.indexOf(applyStartTag); const newApply = `function apply(ctx) { ctx.effect(() => ctx.locale.register(NS, { zh, en }), "ui-settings-models: copy dictionaries"); const connection = ctx.get("connection"); const schema = createSettingsSchemaOperations(ctx.settingsSchema); const controller = new ModelsSettingsStore(connection.api, schema, ctx.settingsScope.describe()); const t = ctx.locale.bind(NS); const injected = () => ({ controller, hooks: { snapshot: controller.store }, api: connection.api, schema, t }); ctx.effect(() => { const refreshModels = () => { refreshIfLoaded(controller); }; const disposers = [ ctx.remote.$on("settings/document-updated", () => { refreshModels(); }), ctx.remote.$on("credentials/reference-updated", refreshModels), ctx.remote.$on("llm/adapters-updated", refreshModels), ctx.on("connection/reset", refreshModels) ]; return () => { for (const dispose of disposers) dispose(); }; }, "ui-settings-models: pushed invalidations"); ctx.slots.inject("settings.section", () => ctx.slots.register({ name: "settings.section", id: "models", order: 10, label: () => t("nav"), inject: injected }, ModelsSection)); // 1. Paperclip button in conversation.input.left ctx.slots.inject("conversation.input.left", () => ctx.slots.register({ name: "conversation.input.left", id: "me-paperclip-upload", order: -100 }, PaperclipUploadButton)); // 2. Codex-style model and reasoning selector in conversation.input.right ctx.inject(["slots"], (scope) => { const sessions = ctx.get("sessions"); scope.slots.inject("conversation.input.right", () => scope.slots.register({ name: "conversation.input.right", id: "me-codex-model-selector", order: 100, inject: (sessionId) => { const dirSvc = ctx.get("modelDirectories"); const directory = dirSvc ? dirSvc.directoryFor(sessionId) : null; const available = sessions ? sessions.subagentAddress(sessionId) === void 0 : true; return { available: available && Boolean(directory), directory: directory ? directory.store : { subscribe: () => () => {}, getSnapshot: () => ({ status: "idle", groups: [], current: null }) }, load: () => { if (available && directory) directory.load().catch(() => {}); }, select: (selection) => (available && directory) ? directory.select(selection).then(() => true, () => false) : Promise.resolve(false) }; } }, CodexModelSelect)); }); } //#endregion exports.apply = apply; exports.inject = inject; exports.refreshIfLoaded = refreshIfLoaded; return module.exports; } }); `; finalCode = finalCode.slice(0, applyIdx) + extraComponentsCode + newApply; fs.writeFileSync('/home/cho/Public/dsh-workspace/dsh-plugin-model-enhancer/lib/client.js', finalCode, 'utf8'); console.log("Successfully rebuilt complete client.js with Full i18n (Chinese & English)! Length:", finalCode.length);