mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-06-29 11:41:30 +08:00
feat(hermes): add lsp diagnostic controls
This commit is contained in:
@@ -300,6 +300,13 @@ const WEB_DEFAULTS = {
|
||||
webExtractBackend: '',
|
||||
}
|
||||
|
||||
const LSP_DEFAULTS = {
|
||||
lspEnabled: true,
|
||||
lspWaitMode: 'document',
|
||||
lspWaitTimeout: 5,
|
||||
lspInstallStrategy: 'auto',
|
||||
}
|
||||
|
||||
const STT_DEFAULTS = {
|
||||
sttEnabled: true,
|
||||
sttProvider: 'auto',
|
||||
@@ -368,6 +375,8 @@ const TERMINAL_VERCEL_RUNTIMES = ['node24', 'node22', 'python3.13']
|
||||
const BROWSER_ENGINES = ['auto', 'lightpanda', 'chrome']
|
||||
const BROWSER_DIALOG_POLICIES = ['must_respond', 'auto_dismiss', 'auto_accept']
|
||||
const WEB_BACKENDS = ['', 'tavily', 'firecrawl', 'parallel', 'exa', 'searxng', 'brave', 'brave_free', 'ddgs', 'xai', 'native']
|
||||
const LSP_WAIT_MODES = ['document', 'full']
|
||||
const LSP_INSTALL_STRATEGIES = ['auto', 'manual', 'off']
|
||||
const STT_PROVIDERS = ['auto', 'local', 'groq', 'openai', 'mistral']
|
||||
const STT_LOCAL_MODELS = ['tiny', 'base', 'small', 'medium', 'large-v3', 'turbo']
|
||||
const STT_OPENAI_MODELS = ['whisper-1', 'gpt-4o-mini-transcribe', 'gpt-4o-transcribe']
|
||||
@@ -434,6 +443,7 @@ export function render() {
|
||||
let privacyValues = { ...PRIVACY_DEFAULTS }
|
||||
let browserValues = { ...BROWSER_DEFAULTS }
|
||||
let webValues = { ...WEB_DEFAULTS }
|
||||
let lspValues = { ...LSP_DEFAULTS }
|
||||
let sttValues = { ...STT_DEFAULTS }
|
||||
let ttsVoiceValues = { ...TTS_VOICE_DEFAULTS }
|
||||
let terminalValues = { ...TERMINAL_DEFAULTS }
|
||||
@@ -474,6 +484,7 @@ export function render() {
|
||||
let privacyLoading = true
|
||||
let browserLoading = true
|
||||
let webLoading = true
|
||||
let lspLoading = true
|
||||
let sttLoading = true
|
||||
let ttsVoiceLoading = true
|
||||
let terminalLoading = true
|
||||
@@ -514,6 +525,7 @@ export function render() {
|
||||
let privacySaving = false
|
||||
let browserSaving = false
|
||||
let webSaving = false
|
||||
let lspSaving = false
|
||||
let sttSaving = false
|
||||
let ttsVoiceSaving = false
|
||||
let terminalSaving = false
|
||||
@@ -554,6 +566,7 @@ export function render() {
|
||||
let privacyError = null
|
||||
let browserError = null
|
||||
let webError = null
|
||||
let lspError = null
|
||||
let sttError = null
|
||||
let ttsVoiceError = null
|
||||
let terminalError = null
|
||||
@@ -567,7 +580,7 @@ export function render() {
|
||||
}
|
||||
|
||||
function isBusy() {
|
||||
return loading || runtimeLoading || sessionsMaintenanceLoading || updatesLoading || compressionLoading || promptCachingLoading || openrouterCacheLoading || providerRoutingLoading || auxiliaryLoading || toolGuardrailsLoading || memoryLoading || skillsLoading || curatorLoading || quickCommandsLoading || modelLoading || modelAliasesLoading || hooksLoading || providerOverridesLoading || mcpServersLoading || agentToolsetsLoading || platformToolsetsLoading || agentRuntimeLoading || unauthorizedDmLoading || securityLoading || displayLoading || humanDelayLoading || kanbanLoading || streamingLoading || executionLimitsLoading || ioSafetyLoading || checkpointsLoading || cronLoading || loggingLoading || approvalsLoading || privacyLoading || browserLoading || webLoading || sttLoading || ttsVoiceLoading || terminalLoading || saving || runtimeSaving || sessionsMaintenanceSaving || updatesSaving || compressionSaving || promptCachingSaving || openrouterCacheSaving || providerRoutingSaving || auxiliarySaving || toolGuardrailsSaving || memorySaving || skillsSaving || curatorSaving || quickCommandsSaving || modelSaving || modelAliasesSaving || hooksSaving || providerOverridesSaving || mcpServersSaving || agentToolsetsSaving || platformToolsetsSaving || agentRuntimeSaving || unauthorizedDmSaving || securitySaving || displaySaving || humanDelaySaving || kanbanSaving || streamingSaving || executionLimitsSaving || ioSafetySaving || checkpointsSaving || cronSaving || loggingSaving || approvalsSaving || privacySaving || browserSaving || webSaving || sttSaving || ttsVoiceSaving || terminalSaving
|
||||
return loading || runtimeLoading || sessionsMaintenanceLoading || updatesLoading || compressionLoading || promptCachingLoading || openrouterCacheLoading || providerRoutingLoading || auxiliaryLoading || toolGuardrailsLoading || memoryLoading || skillsLoading || curatorLoading || quickCommandsLoading || modelLoading || modelAliasesLoading || hooksLoading || providerOverridesLoading || mcpServersLoading || agentToolsetsLoading || platformToolsetsLoading || agentRuntimeLoading || unauthorizedDmLoading || securityLoading || displayLoading || humanDelayLoading || kanbanLoading || streamingLoading || executionLimitsLoading || ioSafetyLoading || checkpointsLoading || cronLoading || loggingLoading || approvalsLoading || privacyLoading || browserLoading || webLoading || lspLoading || sttLoading || ttsVoiceLoading || terminalLoading || saving || runtimeSaving || sessionsMaintenanceSaving || updatesSaving || compressionSaving || promptCachingSaving || openrouterCacheSaving || providerRoutingSaving || auxiliarySaving || toolGuardrailsSaving || memorySaving || skillsSaving || curatorSaving || quickCommandsSaving || modelSaving || modelAliasesSaving || hooksSaving || providerOverridesSaving || mcpServersSaving || agentToolsetsSaving || platformToolsetsSaving || agentRuntimeSaving || unauthorizedDmSaving || securitySaving || displaySaving || humanDelaySaving || kanbanSaving || streamingSaving || executionLimitsSaving || ioSafetySaving || checkpointsSaving || cronSaving || loggingSaving || approvalsSaving || privacySaving || browserSaving || webSaving || lspSaving || sttSaving || ttsVoiceSaving || terminalSaving
|
||||
}
|
||||
|
||||
function option(labelKey, value, selected) {
|
||||
@@ -2257,7 +2270,7 @@ export function render() {
|
||||
}
|
||||
|
||||
function renderWebConfigPanel() {
|
||||
const disabled = loading || saving || webLoading || webSaving || browserSaving || approvalsSaving || cronSaving || loggingSaving || privacySaving || sttSaving || terminalSaving || runtimeSaving || compressionSaving || promptCachingSaving || openrouterCacheSaving || providerRoutingSaving || auxiliarySaving || toolGuardrailsSaving || memorySaving || skillsSaving || quickCommandsSaving || providerOverridesSaving || agentToolsetsSaving || agentRuntimeSaving || unauthorizedDmSaving || streamingSaving || executionLimitsSaving || ioSafetySaving || checkpointsSaving
|
||||
const disabled = loading || saving || webLoading || webSaving || browserSaving || lspSaving || approvalsSaving || cronSaving || loggingSaving || privacySaving || sttSaving || terminalSaving || runtimeSaving || compressionSaving || promptCachingSaving || openrouterCacheSaving || providerRoutingSaving || auxiliarySaving || toolGuardrailsSaving || memorySaving || skillsSaving || quickCommandsSaving || providerOverridesSaving || agentToolsetsSaving || agentRuntimeSaving || unauthorizedDmSaving || streamingSaving || executionLimitsSaving || ioSafetySaving || checkpointsSaving
|
||||
return `
|
||||
<div class="hm-panel hm-config-runtime-panel hm-config-web-panel">
|
||||
<div class="hm-panel-header">
|
||||
@@ -2298,8 +2311,54 @@ export function render() {
|
||||
`
|
||||
}
|
||||
|
||||
function renderLspConfigPanel() {
|
||||
const disabled = loading || saving || lspLoading || lspSaving || webSaving || browserSaving || approvalsSaving || cronSaving || loggingSaving || privacySaving || sttSaving || terminalSaving || runtimeSaving || compressionSaving || promptCachingSaving || openrouterCacheSaving || providerRoutingSaving || auxiliarySaving || toolGuardrailsSaving || memorySaving || skillsSaving || quickCommandsSaving || providerOverridesSaving || agentToolsetsSaving || agentRuntimeSaving || unauthorizedDmSaving || streamingSaving || executionLimitsSaving || ioSafetySaving || checkpointsSaving
|
||||
return `
|
||||
<div class="hm-panel hm-config-runtime-panel hm-config-lsp-panel">
|
||||
<div class="hm-panel-header">
|
||||
<div>
|
||||
<div class="hm-panel-title">${t('engine.hermesLspConfigTitle')}</div>
|
||||
<div class="hm-channel-panel-desc">${t('engine.hermesLspConfigDesc')}</div>
|
||||
</div>
|
||||
<div class="hm-panel-actions">
|
||||
<span class="hm-muted">${lspSaving ? t('engine.hermesConfigStatusSaving') : lspLoading ? t('engine.hermesConfigStatusLoading') : t('engine.hermesLspConfigStatusReady')}</span>
|
||||
<button class="hm-btn hm-btn--cta hm-btn--sm" id="hm-lsp-save" ${disabled ? 'disabled' : ''}>${t('engine.hermesLspConfigSave')}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hm-panel-body">
|
||||
${renderError(lspError)}
|
||||
<div class="hm-config-check-grid">
|
||||
<label class="hm-channel-check">
|
||||
<input id="hm-lsp-enabled" type="checkbox" ${lspValues.lspEnabled ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
|
||||
<span>${t('engine.hermesLspConfigEnabled')}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="hm-config-runtime-grid hm-config-lsp-grid">
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesLspConfigWaitMode')}</span>
|
||||
<select id="hm-lsp-wait-mode" class="hm-input" ${disabled ? 'disabled' : ''}>
|
||||
${LSP_WAIT_MODES.map(mode => option(`engine.hermesLspConfigWaitMode_${mode}`, mode, lspValues.lspWaitMode)).join('')}
|
||||
</select>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesLspConfigWaitTimeout')}</span>
|
||||
<input id="hm-lsp-wait-timeout" class="hm-input" type="number" inputmode="decimal" min="0.1" max="120" step="0.1" value="${esc(lspValues.lspWaitTimeout)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesLspConfigInstallStrategy')}</span>
|
||||
<select id="hm-lsp-install-strategy" class="hm-input" ${disabled ? 'disabled' : ''}>
|
||||
${LSP_INSTALL_STRATEGIES.map(strategy => option(`engine.hermesLspConfigInstallStrategy_${strategy}`, strategy, lspValues.lspInstallStrategy)).join('')}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="hm-channel-footnote">${t('engine.hermesLspConfigFootnote')}</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
function renderSttPanel() {
|
||||
const disabled = loading || saving || sttLoading || sttSaving || webSaving || approvalsSaving || cronSaving || loggingSaving || privacySaving || browserSaving || terminalSaving || runtimeSaving || compressionSaving || promptCachingSaving || openrouterCacheSaving || providerRoutingSaving || auxiliarySaving || toolGuardrailsSaving || memorySaving || skillsSaving || quickCommandsSaving || providerOverridesSaving || agentToolsetsSaving || agentRuntimeSaving || unauthorizedDmSaving || streamingSaving || executionLimitsSaving || ioSafetySaving || checkpointsSaving
|
||||
const disabled = loading || saving || sttLoading || sttSaving || webSaving || lspSaving || approvalsSaving || cronSaving || loggingSaving || privacySaving || browserSaving || terminalSaving || runtimeSaving || compressionSaving || promptCachingSaving || openrouterCacheSaving || providerRoutingSaving || auxiliarySaving || toolGuardrailsSaving || memorySaving || skillsSaving || quickCommandsSaving || providerOverridesSaving || agentToolsetsSaving || agentRuntimeSaving || unauthorizedDmSaving || streamingSaving || executionLimitsSaving || ioSafetySaving || checkpointsSaving
|
||||
return `
|
||||
<div class="hm-panel hm-config-runtime-panel hm-config-stt-panel">
|
||||
<div class="hm-panel-header">
|
||||
@@ -2628,6 +2687,7 @@ export function render() {
|
||||
${renderPrivacyPanel()}
|
||||
${renderBrowserPanel()}
|
||||
${renderWebConfigPanel()}
|
||||
${renderLspConfigPanel()}
|
||||
${renderSttPanel()}
|
||||
${renderTtsVoicePanel()}
|
||||
${renderCompressionPanel()}
|
||||
@@ -2708,6 +2768,7 @@ export function render() {
|
||||
el.querySelector('#hm-privacy-save')?.addEventListener('click', savePrivacyConfig)
|
||||
el.querySelector('#hm-browser-save')?.addEventListener('click', saveBrowserConfig)
|
||||
el.querySelector('#hm-web-config-save')?.addEventListener('click', saveWebConfig)
|
||||
el.querySelector('#hm-lsp-save')?.addEventListener('click', saveLspConfig)
|
||||
el.querySelector('#hm-stt-save')?.addEventListener('click', saveSttConfig)
|
||||
el.querySelector('#hm-tts-voice-save')?.addEventListener('click', saveTtsVoiceConfig)
|
||||
el.querySelector('#hm-terminal-save')?.addEventListener('click', saveTerminal)
|
||||
@@ -2898,6 +2959,11 @@ export function render() {
|
||||
webValues = { ...WEB_DEFAULTS, ...(data?.values || {}) }
|
||||
}
|
||||
|
||||
async function loadLspConfig() {
|
||||
const data = await api.hermesLspConfigRead()
|
||||
lspValues = { ...LSP_DEFAULTS, ...(data?.values || {}) }
|
||||
}
|
||||
|
||||
async function loadSttConfig() {
|
||||
const data = await api.hermesSttConfigRead()
|
||||
sttValues = { ...STT_DEFAULTS, ...(data?.values || {}) }
|
||||
@@ -2951,6 +3017,7 @@ export function render() {
|
||||
privacyLoading = true
|
||||
browserLoading = true
|
||||
webLoading = true
|
||||
lspLoading = true
|
||||
sttLoading = true
|
||||
ttsVoiceLoading = true
|
||||
terminalLoading = true
|
||||
@@ -2990,6 +3057,7 @@ export function render() {
|
||||
privacyError = null
|
||||
browserError = null
|
||||
webError = null
|
||||
lspError = null
|
||||
sttError = null
|
||||
ttsVoiceError = null
|
||||
terminalError = null
|
||||
@@ -3153,6 +3221,14 @@ export function render() {
|
||||
webLoading = false
|
||||
draw()
|
||||
}
|
||||
try {
|
||||
await loadLspConfig()
|
||||
} catch (err) {
|
||||
lspError = humanizeError(err, t('engine.hermesLspConfigLoadFailed') || 'Load LSP config failed')
|
||||
} finally {
|
||||
lspLoading = false
|
||||
draw()
|
||||
}
|
||||
try {
|
||||
await loadSttConfig()
|
||||
} catch (err) {
|
||||
@@ -4498,6 +4574,34 @@ export function render() {
|
||||
}
|
||||
}
|
||||
|
||||
async function saveLspConfig() {
|
||||
const form = {
|
||||
lspEnabled: !!el.querySelector('#hm-lsp-enabled')?.checked,
|
||||
lspWaitMode: el.querySelector('#hm-lsp-wait-mode')?.value || 'document',
|
||||
lspWaitTimeout: el.querySelector('#hm-lsp-wait-timeout')?.value || '5',
|
||||
lspInstallStrategy: el.querySelector('#hm-lsp-install-strategy')?.value || 'auto',
|
||||
}
|
||||
lspSaving = true
|
||||
lspError = null
|
||||
draw()
|
||||
try {
|
||||
const result = await api.hermesLspConfigSave(form)
|
||||
lspValues = { ...LSP_DEFAULTS, ...(result?.values || form) }
|
||||
await refreshRawAfterStructuredSave()
|
||||
const backup = result?.backup || ''
|
||||
toast({
|
||||
message: t('engine.hermesLspConfigSaveSuccess'),
|
||||
hint: backup ? t('engine.hermesConfigBackupHint', { path: backup }) : '',
|
||||
}, 'success')
|
||||
} catch (err) {
|
||||
lspError = humanizeError(err, t('engine.hermesLspConfigSaveFailed') || 'Save LSP config failed')
|
||||
toast(lspError, 'error')
|
||||
} finally {
|
||||
lspSaving = false
|
||||
draw()
|
||||
}
|
||||
}
|
||||
|
||||
async function saveSttConfig() {
|
||||
const form = {
|
||||
sttEnabled: !!el.querySelector('#hm-stt-enabled')?.checked,
|
||||
|
||||
@@ -581,6 +581,8 @@ export const api = {
|
||||
hermesBrowserConfigSave: (form) => invoke('hermes_browser_config_save', { form }),
|
||||
hermesWebConfigRead: () => invoke('hermes_web_config_read'),
|
||||
hermesWebConfigSave: (form) => invoke('hermes_web_config_save', { form }),
|
||||
hermesLspConfigRead: () => invoke('hermes_lsp_config_read'),
|
||||
hermesLspConfigSave: (form) => invoke('hermes_lsp_config_save', { form }),
|
||||
hermesSttConfigRead: () => invoke('hermes_stt_config_read'),
|
||||
hermesSttConfigSave: (form) => invoke('hermes_stt_config_save', { form }),
|
||||
hermesTtsVoiceConfigRead: () => invoke('hermes_tts_voice_config_read'),
|
||||
|
||||
@@ -739,6 +739,23 @@ export default {
|
||||
hermesWebConfigBackend_xai: _('xAI Search', 'xAI Search', 'xAI Search'),
|
||||
hermesWebConfigBackend_native: _('原生提取', 'Native extraction', '原生提取'),
|
||||
hermesWebConfigFootnote: _('这里写入 web.backend、web.search_backend 和 web.extract_backend。留空会删除覆盖,让 Hermes 按密钥、可用 provider 和上游默认策略自动选择;未知 web 字段会保留在 raw YAML 中。', 'This writes web.backend, web.search_backend, and web.extract_backend. Leaving a value empty removes the override so Hermes can auto-select based on keys, available providers, and upstream defaults. Unknown web fields stay in raw YAML.', '這裡寫入 web.backend、web.search_backend 和 web.extract_backend。留空會刪除覆蓋,讓 Hermes 按密鑰、可用 provider 和上游預設策略自動選擇;未知 web 欄位會保留在 raw YAML 中。'),
|
||||
hermesLspConfigTitle: _('LSP 语义诊断', 'LSP semantic diagnostics', 'LSP 語意診斷'),
|
||||
hermesLspConfigDesc: _('控制写文件和补丁后的语言服务器诊断等待、工作区扫描和缺失服务器自动安装策略。', 'Control language-server diagnostic waits, workspace scans, and missing-server install strategy after file writes and patches.', '控制寫檔和補丁後的語言伺服器診斷等待、工作區掃描和缺失伺服器自動安裝策略。'),
|
||||
hermesLspConfigStatusReady: _('结构化配置', 'structured settings', '結構化設定'),
|
||||
hermesLspConfigSave: _('保存 LSP 配置', 'Save LSP settings', '儲存 LSP 設定'),
|
||||
hermesLspConfigSaveSuccess: _('LSP 语义诊断配置已保存,建议重启 Hermes Gateway 生效', 'LSP semantic diagnostic settings saved. Restart Hermes Gateway to take effect.', 'LSP 語意診斷設定已儲存,建議重啟 Hermes Gateway 生效'),
|
||||
hermesLspConfigLoadFailed: _('加载 LSP 语义诊断配置失败', 'Load LSP semantic diagnostic settings failed', '載入 LSP 語意診斷設定失敗'),
|
||||
hermesLspConfigSaveFailed: _('保存 LSP 语义诊断配置失败', 'Save LSP semantic diagnostic settings failed', '儲存 LSP 語意診斷設定失敗'),
|
||||
hermesLspConfigEnabled: _('启用 LSP 语义诊断', 'Enable LSP semantic diagnostics', '啟用 LSP 語意診斷'),
|
||||
hermesLspConfigWaitMode: _('诊断等待模式', 'Diagnostic wait mode', '診斷等待模式'),
|
||||
hermesLspConfigWaitMode_document: _('仅当前文件', 'Current file only', '僅目前檔案'),
|
||||
hermesLspConfigWaitMode_full: _('工作区诊断', 'Workspace diagnostics', '工作區診斷'),
|
||||
hermesLspConfigWaitTimeout: _('诊断等待秒数', 'Diagnostic wait seconds', '診斷等待秒數'),
|
||||
hermesLspConfigInstallStrategy: _('缺失服务器处理', 'Missing server handling', '缺失伺服器處理'),
|
||||
hermesLspConfigInstallStrategy_auto: _('自动安装', 'Auto install', '自動安裝'),
|
||||
hermesLspConfigInstallStrategy_manual: _('仅使用 PATH', 'Use PATH only', '僅使用 PATH'),
|
||||
hermesLspConfigInstallStrategy_off: _('关闭自动安装', 'Disable auto install', '關閉自動安裝'),
|
||||
hermesLspConfigFootnote: _('这里写入 lsp.enabled、lsp.wait_mode、lsp.wait_timeout 和 lsp.install_strategy。高级 lsp.servers 覆盖保留在 raw YAML;远程或沙箱后端是否触发宿主 LSP 以 Hermes 运行时工作目录和 Git workspace 检测为准。', 'This writes lsp.enabled, lsp.wait_mode, lsp.wait_timeout, and lsp.install_strategy. Advanced lsp.servers overrides stay in raw YAML. Whether remote or sandbox backends trigger host LSP depends on the Hermes runtime cwd and Git workspace detection.', '這裡寫入 lsp.enabled、lsp.wait_mode、lsp.wait_timeout 和 lsp.install_strategy。進階 lsp.servers 覆蓋保留在 raw YAML;遠端或沙箱後端是否觸發宿主 LSP 以 Hermes 執行時工作目錄和 Git workspace 偵測為準。'),
|
||||
hermesSttConfigTitle: _('语音转写', 'Speech transcription', '語音轉寫'),
|
||||
hermesSttConfigDesc: _('控制消息平台语音消息是否自动转写,以及本地、OpenAI 和 Mistral 转写模型。适合需要处理语音反馈的渠道。', 'Control automatic voice-message transcription for messaging platforms, plus local, OpenAI, and Mistral transcription models. Useful for channels that receive voice feedback.', '控制訊息平台語音訊息是否自動轉寫,以及本機、OpenAI 和 Mistral 轉寫模型。適合需要處理語音回饋的渠道。'),
|
||||
hermesSttConfigStatusReady: _('结构化配置', 'structured settings', '結構化設定'),
|
||||
|
||||
Reference in New Issue
Block a user