feat(webui): add MCP CLI toggle and Gemini [1m] suffix settings
- Add ENABLE_EXPERIMENTAL_MCP_CLI toggle in Claude CLI settings (default: true) - Add Gemini 1M Context Mode toggle for [1m] suffix (default: true) - Auto-apply [1m] suffix to existing Gemini model configurations - Add i18n translations for both features (English and Chinese)
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 244 KiB After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 235 KiB After Width: | Height: | Size: 170 KiB |
BIN
images/webui-models.png
Normal file
|
After Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 248 KiB |
@@ -8,6 +8,16 @@ window.Components.claudeConfig = () => ({
|
|||||||
config: { env: {} },
|
config: { env: {} },
|
||||||
models: [],
|
models: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
|
gemini1mSuffix: false,
|
||||||
|
|
||||||
|
// Model fields that may contain Gemini model names
|
||||||
|
geminiModelFields: [
|
||||||
|
'ANTHROPIC_MODEL',
|
||||||
|
'CLAUDE_CODE_SUBAGENT_MODEL',
|
||||||
|
'ANTHROPIC_DEFAULT_OPUS_MODEL',
|
||||||
|
'ANTHROPIC_DEFAULT_SONNET_MODEL',
|
||||||
|
'ANTHROPIC_DEFAULT_HAIKU_MODEL'
|
||||||
|
],
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
// Only fetch config if this is the active sub-tab
|
// Only fetch config if this is the active sub-tab
|
||||||
@@ -28,6 +38,36 @@ window.Components.claudeConfig = () => ({
|
|||||||
this.models = Alpine.store('data').models || [];
|
this.models = Alpine.store('data').models || [];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if any Gemini model has [1m] suffix
|
||||||
|
*/
|
||||||
|
detectGemini1mSuffix() {
|
||||||
|
for (const field of this.geminiModelFields) {
|
||||||
|
const val = this.config.env[field];
|
||||||
|
if (val && val.toLowerCase().includes('gemini') && val.includes('[1m]')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle [1m] suffix for all Gemini models
|
||||||
|
*/
|
||||||
|
toggleGemini1mSuffix(enabled) {
|
||||||
|
for (const field of this.geminiModelFields) {
|
||||||
|
const val = this.config.env[field];
|
||||||
|
if (val && val.toLowerCase().includes('gemini')) {
|
||||||
|
if (enabled && !val.includes('[1m]')) {
|
||||||
|
this.config.env[field] = val.trim() + ' [1m]';
|
||||||
|
} else if (!enabled && val.includes('[1m]')) {
|
||||||
|
this.config.env[field] = val.replace(/\s*\[1m\]$/i, '').trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.gemini1mSuffix = enabled;
|
||||||
|
},
|
||||||
|
|
||||||
async fetchConfig() {
|
async fetchConfig() {
|
||||||
const password = Alpine.store('global').webuiPassword;
|
const password = Alpine.store('global').webuiPassword;
|
||||||
try {
|
try {
|
||||||
@@ -38,6 +78,24 @@ window.Components.claudeConfig = () => ({
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
this.config = data.config || {};
|
this.config = data.config || {};
|
||||||
if (!this.config.env) this.config.env = {};
|
if (!this.config.env) this.config.env = {};
|
||||||
|
|
||||||
|
// Default MCP CLI to true if not set
|
||||||
|
if (this.config.env.ENABLE_EXPERIMENTAL_MCP_CLI === undefined) {
|
||||||
|
this.config.env.ENABLE_EXPERIMENTAL_MCP_CLI = 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect existing [1m] suffix state, default to true
|
||||||
|
const hasExistingSuffix = this.detectGemini1mSuffix();
|
||||||
|
const hasGeminiModels = this.geminiModelFields.some(f =>
|
||||||
|
this.config.env[f]?.toLowerCase().includes('gemini')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Default to enabled: if no suffix found but Gemini models exist, apply suffix
|
||||||
|
if (!hasExistingSuffix && hasGeminiModels) {
|
||||||
|
this.toggleGemini1mSuffix(true);
|
||||||
|
} else {
|
||||||
|
this.gemini1mSuffix = hasExistingSuffix || !hasGeminiModels;
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to fetch Claude config:', e);
|
console.error('Failed to fetch Claude config:', e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,6 +243,12 @@ document.addEventListener('alpine:init', () => {
|
|||||||
oauthTimeout: "⏱️ OAuth authorization timed out. Please try again.",
|
oauthTimeout: "⏱️ OAuth authorization timed out. Please try again.",
|
||||||
oauthWindowClosed: "OAuth window was closed. Authorization may be incomplete.",
|
oauthWindowClosed: "OAuth window was closed. Authorization may be incomplete.",
|
||||||
cancelOAuth: "Cancel",
|
cancelOAuth: "Cancel",
|
||||||
|
// MCP CLI & Gemini 1M
|
||||||
|
mcpCliExperimental: "Experimental MCP CLI",
|
||||||
|
mcpCliDesc: "Enables experimental MCP integration for reliable tool usage with reduced context consumption.",
|
||||||
|
gemini1mMode: "Gemini 1M Context Mode",
|
||||||
|
gemini1mDesc: "Appends [1m] suffix to Gemini models for 1M context window support.",
|
||||||
|
gemini1mWarning: "⚠ Large context may reduce Gemini-3-Pro performance.",
|
||||||
},
|
},
|
||||||
zh: {
|
zh: {
|
||||||
dashboard: "仪表盘",
|
dashboard: "仪表盘",
|
||||||
@@ -475,6 +481,12 @@ document.addEventListener('alpine:init', () => {
|
|||||||
oauthTimeout: "⏱️ OAuth 授权超时,请重试。",
|
oauthTimeout: "⏱️ OAuth 授权超时,请重试。",
|
||||||
oauthWindowClosed: "OAuth 窗口已关闭,授权可能未完成。",
|
oauthWindowClosed: "OAuth 窗口已关闭,授权可能未完成。",
|
||||||
cancelOAuth: "取消",
|
cancelOAuth: "取消",
|
||||||
|
// MCP CLI & Gemini 1M
|
||||||
|
mcpCliExperimental: "实验性 MCP CLI",
|
||||||
|
mcpCliDesc: "启用实验性 MCP 集成,减少上下文消耗,提高工具调用可靠性。",
|
||||||
|
gemini1mMode: "Gemini 1M 上下文模式",
|
||||||
|
gemini1mDesc: "为 Gemini 模型添加 [1m] 后缀以支持 1M 上下文窗口。",
|
||||||
|
gemini1mWarning: "⚠ 大上下文可能降低 Gemini-3-Pro 性能。",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -406,6 +406,53 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- MCP CLI Experimental Mode -->
|
||||||
|
<div class="card bg-space-900/30 border border-space-border/50 p-5">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<span class="text-sm font-medium transition-colors"
|
||||||
|
:class="config.env.ENABLE_EXPERIMENTAL_MCP_CLI === 'true' ? 'text-neon-green' : 'text-gray-300'"
|
||||||
|
x-text="$store.global.t('mcpCliExperimental')">Experimental MCP CLI</span>
|
||||||
|
<span class="text-[11px] text-gray-500" x-text="$store.global.t('mcpCliDesc')">
|
||||||
|
Enables experimental MCP integration for reliable tool usage with reduced context consumption.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<label class="relative inline-flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" class="sr-only peer"
|
||||||
|
:checked="config.env.ENABLE_EXPERIMENTAL_MCP_CLI === 'true'"
|
||||||
|
@change="config.env.ENABLE_EXPERIMENTAL_MCP_CLI = $event.target.checked ? 'true' : 'false'">
|
||||||
|
<div
|
||||||
|
class="w-9 h-5 bg-space-800 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-gray-600 after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-neon-green peer-checked:after:bg-white">
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Gemini 1M Context Suffix Toggle -->
|
||||||
|
<div class="card bg-space-900/30 border border-space-border/50 p-5">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<span class="text-sm font-medium transition-colors"
|
||||||
|
:class="gemini1mSuffix ? 'text-neon-green' : 'text-gray-300'"
|
||||||
|
x-text="$store.global.t('gemini1mMode')">Gemini 1M Context Mode</span>
|
||||||
|
<span class="text-[11px] text-gray-500" x-text="$store.global.t('gemini1mDesc')">
|
||||||
|
Appends [1m] suffix to Gemini models for 1M context window support.
|
||||||
|
</span>
|
||||||
|
<span class="text-[10px] text-yellow-500/80" x-text="$store.global.t('gemini1mWarning')">
|
||||||
|
⚠ Large context may reduce Gemini-3-Pro performance.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<label class="relative inline-flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" class="sr-only peer"
|
||||||
|
:checked="gemini1mSuffix"
|
||||||
|
@change="toggleGemini1mSuffix($event.target.checked)">
|
||||||
|
<div
|
||||||
|
class="w-9 h-5 bg-space-800 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-gray-600 after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-neon-green peer-checked:after:bg-white">
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end pt-2">
|
<div class="flex justify-end pt-2">
|
||||||
<button class="btn btn-sm bg-neon-purple hover:bg-purple-600 border-none text-white px-6 gap-2"
|
<button class="btn btn-sm bg-neon-purple hover:bg-purple-600 border-none text-white px-6 gap-2"
|
||||||
@click="saveClaudeConfig" :disabled="loading">
|
@click="saveClaudeConfig" :disabled="loading">
|
||||||
|
|||||||