Files
dsh-plugin-model-enhancer/build-client.cjs
T

1955 lines
69 KiB
JavaScript

// 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);