mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-07-03 05:31:33 +08:00
feat(hermes): add display reliability settings
This commit is contained in:
@@ -63,6 +63,17 @@ const SECURITY_DEFAULTS = {
|
||||
tirithFailOpen: true,
|
||||
}
|
||||
|
||||
const DISPLAY_DEFAULTS = {
|
||||
displayToolProgress: 'all',
|
||||
displayToolProgressCommand: false,
|
||||
displayInterimAssistantMessages: true,
|
||||
displayRuntimeFooterEnabled: false,
|
||||
displayRuntimeFooterFields: 'model\ncontext_pct\ncwd',
|
||||
displayFileMutationVerifier: true,
|
||||
displayLanguage: 'en',
|
||||
displayResumeDisplay: 'full',
|
||||
}
|
||||
|
||||
const HUMAN_DELAY_DEFAULTS = {
|
||||
humanDelayMode: 'off',
|
||||
humanDelayMinMs: 800,
|
||||
@@ -109,6 +120,9 @@ const STREAMING_TRANSPORTS = ['edit', 'auto', 'draft', 'off']
|
||||
const CODE_EXECUTION_MODES = ['project', 'strict']
|
||||
const TERMINAL_BACKENDS = ['local', 'ssh', 'docker', 'singularity', 'modal', 'daytona', 'vercel_sandbox']
|
||||
const UNAUTHORIZED_DM_BEHAVIORS = ['pair', 'ignore']
|
||||
const DISPLAY_TOOL_PROGRESS_VALUES = ['off', 'new', 'all', 'verbose']
|
||||
const DISPLAY_LANGUAGE_VALUES = ['en', 'zh', 'zh-hant', 'ja', 'de', 'es', 'fr', 'tr', 'uk', 'af', 'ko', 'it', 'ga', 'pt', 'ru', 'hu']
|
||||
const DISPLAY_RESUME_VALUES = ['full', 'minimal']
|
||||
const HUMAN_DELAY_MODES = ['off', 'natural', 'custom']
|
||||
|
||||
export function render() {
|
||||
@@ -124,6 +138,7 @@ export function render() {
|
||||
let quickCommandsValues = { ...QUICK_COMMANDS_DEFAULTS }
|
||||
let unauthorizedDmValues = { ...UNAUTHORIZED_DM_DEFAULTS }
|
||||
let securityValues = { ...SECURITY_DEFAULTS }
|
||||
let displayValues = { ...DISPLAY_DEFAULTS }
|
||||
let humanDelayValues = { ...HUMAN_DELAY_DEFAULTS }
|
||||
let streamingValues = { ...STREAMING_DEFAULTS }
|
||||
let executionLimitsValues = { ...EXECUTION_LIMITS_DEFAULTS }
|
||||
@@ -137,6 +152,7 @@ export function render() {
|
||||
let quickCommandsLoading = true
|
||||
let unauthorizedDmLoading = true
|
||||
let securityLoading = true
|
||||
let displayLoading = true
|
||||
let humanDelayLoading = true
|
||||
let streamingLoading = true
|
||||
let executionLimitsLoading = true
|
||||
@@ -150,6 +166,7 @@ export function render() {
|
||||
let quickCommandsSaving = false
|
||||
let unauthorizedDmSaving = false
|
||||
let securitySaving = false
|
||||
let displaySaving = false
|
||||
let humanDelaySaving = false
|
||||
let streamingSaving = false
|
||||
let executionLimitsSaving = false
|
||||
@@ -163,6 +180,7 @@ export function render() {
|
||||
let quickCommandsError = null
|
||||
let unauthorizedDmError = null
|
||||
let securityError = null
|
||||
let displayError = null
|
||||
let humanDelayError = null
|
||||
let streamingError = null
|
||||
let executionLimitsError = null
|
||||
@@ -177,7 +195,7 @@ export function render() {
|
||||
}
|
||||
|
||||
function isBusy() {
|
||||
return loading || runtimeLoading || compressionLoading || toolGuardrailsLoading || memoryLoading || skillsLoading || quickCommandsLoading || unauthorizedDmLoading || securityLoading || humanDelayLoading || streamingLoading || executionLimitsLoading || terminalLoading || saving || runtimeSaving || compressionSaving || toolGuardrailsSaving || memorySaving || skillsSaving || quickCommandsSaving || unauthorizedDmSaving || securitySaving || humanDelaySaving || streamingSaving || executionLimitsSaving || terminalSaving
|
||||
return loading || runtimeLoading || compressionLoading || toolGuardrailsLoading || memoryLoading || skillsLoading || quickCommandsLoading || unauthorizedDmLoading || securityLoading || displayLoading || humanDelayLoading || streamingLoading || executionLimitsLoading || terminalLoading || saving || runtimeSaving || compressionSaving || toolGuardrailsSaving || memorySaving || skillsSaving || quickCommandsSaving || unauthorizedDmSaving || securitySaving || displaySaving || humanDelaySaving || streamingSaving || executionLimitsSaving || terminalSaving
|
||||
}
|
||||
|
||||
function option(labelKey, value, selected) {
|
||||
@@ -533,6 +551,70 @@ export function render() {
|
||||
`
|
||||
}
|
||||
|
||||
function renderDisplayConfigPanel() {
|
||||
const disabled = loading || saving || displayLoading || displaySaving || runtimeSaving || compressionSaving || toolGuardrailsSaving || memorySaving || skillsSaving || quickCommandsSaving || unauthorizedDmSaving || securitySaving || humanDelaySaving || streamingSaving || executionLimitsSaving || terminalSaving
|
||||
return `
|
||||
<div class="hm-panel hm-config-runtime-panel hm-config-display-panel">
|
||||
<div class="hm-panel-header">
|
||||
<div>
|
||||
<div class="hm-panel-title">${t('engine.hermesDisplayConfigTitle')}</div>
|
||||
<div class="hm-channel-panel-desc">${t('engine.hermesDisplayConfigDesc')}</div>
|
||||
</div>
|
||||
<div class="hm-panel-actions">
|
||||
<span class="hm-muted">${displaySaving ? t('engine.hermesConfigStatusSaving') : displayLoading ? t('engine.hermesConfigStatusLoading') : t('engine.hermesDisplayConfigStatusReady')}</span>
|
||||
<button class="hm-btn hm-btn--cta hm-btn--sm" id="hm-display-save" ${disabled ? 'disabled' : ''}>${t('engine.hermesDisplayConfigSave')}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hm-panel-body">
|
||||
${renderError(displayError)}
|
||||
<div class="hm-config-runtime-grid hm-config-display-grid">
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesDisplayConfigToolProgress')}</span>
|
||||
<select id="hm-display-tool-progress" class="hm-input" ${disabled ? 'disabled' : ''}>
|
||||
${DISPLAY_TOOL_PROGRESS_VALUES.map(mode => option(`engine.hermesDisplayConfigToolProgress_${mode}`, mode, displayValues.displayToolProgress)).join('')}
|
||||
</select>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesDisplayConfigLanguage')}</span>
|
||||
<select id="hm-display-language" class="hm-input" ${disabled ? 'disabled' : ''}>
|
||||
${DISPLAY_LANGUAGE_VALUES.map(mode => option(`engine.hermesDisplayConfigLanguage_${mode}`, mode, displayValues.displayLanguage)).join('')}
|
||||
</select>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesDisplayConfigResumeDisplay')}</span>
|
||||
<select id="hm-display-resume-display" class="hm-input" ${disabled ? 'disabled' : ''}>
|
||||
${DISPLAY_RESUME_VALUES.map(mode => option(`engine.hermesDisplayConfigResumeDisplay_${mode}`, mode, displayValues.displayResumeDisplay)).join('')}
|
||||
</select>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesDisplayConfigRuntimeFooterFields')}</span>
|
||||
<textarea id="hm-display-runtime-footer-fields" class="hm-input" ${disabled ? 'disabled' : ''} style="min-height:96px;resize:vertical">${esc(displayValues.displayRuntimeFooterFields)}</textarea>
|
||||
</label>
|
||||
</div>
|
||||
<div class="hm-config-check-grid">
|
||||
<label class="hm-channel-check">
|
||||
<input id="hm-display-tool-progress-command" type="checkbox" ${displayValues.displayToolProgressCommand ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
|
||||
<span>${t('engine.hermesDisplayConfigToolProgressCommand')}</span>
|
||||
</label>
|
||||
<label class="hm-channel-check">
|
||||
<input id="hm-display-interim-assistant-messages" type="checkbox" ${displayValues.displayInterimAssistantMessages ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
|
||||
<span>${t('engine.hermesDisplayConfigInterimAssistantMessages')}</span>
|
||||
</label>
|
||||
<label class="hm-channel-check">
|
||||
<input id="hm-display-runtime-footer-enabled" type="checkbox" ${displayValues.displayRuntimeFooterEnabled ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
|
||||
<span>${t('engine.hermesDisplayConfigRuntimeFooterEnabled')}</span>
|
||||
</label>
|
||||
<label class="hm-channel-check">
|
||||
<input id="hm-display-file-mutation-verifier" type="checkbox" ${displayValues.displayFileMutationVerifier ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
|
||||
<span>${t('engine.hermesDisplayConfigFileMutationVerifier')}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="hm-channel-footnote">${t('engine.hermesDisplayConfigFootnote')}</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
function renderHumanDelayConfigPanel() {
|
||||
const disabled = loading || saving || humanDelayLoading || humanDelaySaving || runtimeSaving || compressionSaving || toolGuardrailsSaving || memorySaving || skillsSaving || quickCommandsSaving || unauthorizedDmSaving || securitySaving || streamingSaving || executionLimitsSaving || terminalSaving
|
||||
return `
|
||||
@@ -791,6 +873,7 @@ export function render() {
|
||||
${renderQuickCommandsConfigPanel()}
|
||||
${renderUnauthorizedDmConfigPanel()}
|
||||
${renderSecurityConfigPanel()}
|
||||
${renderDisplayConfigPanel()}
|
||||
${renderHumanDelayConfigPanel()}
|
||||
|
||||
<div class="hm-panel">
|
||||
@@ -819,6 +902,7 @@ export function render() {
|
||||
el.querySelector('#hm-quick-commands-save')?.addEventListener('click', saveQuickCommandsConfig)
|
||||
el.querySelector('#hm-unauthorized-dm-save')?.addEventListener('click', saveUnauthorizedDmConfig)
|
||||
el.querySelector('#hm-security-save')?.addEventListener('click', saveSecurityConfig)
|
||||
el.querySelector('#hm-display-save')?.addEventListener('click', saveDisplayConfig)
|
||||
el.querySelector('#hm-human-delay-save')?.addEventListener('click', saveHumanDelayConfig)
|
||||
el.querySelector('#hm-streaming-save')?.addEventListener('click', saveStreaming)
|
||||
el.querySelector('#hm-execution-limits-save')?.addEventListener('click', saveExecutionLimits)
|
||||
@@ -870,6 +954,11 @@ export function render() {
|
||||
securityValues = { ...SECURITY_DEFAULTS, ...(data?.values || {}) }
|
||||
}
|
||||
|
||||
async function loadDisplayConfig() {
|
||||
const data = await api.hermesDisplayConfigRead()
|
||||
displayValues = { ...DISPLAY_DEFAULTS, ...(data?.values || {}) }
|
||||
}
|
||||
|
||||
async function loadHumanDelayConfig() {
|
||||
const data = await api.hermesHumanDelayConfigRead()
|
||||
humanDelayValues = { ...HUMAN_DELAY_DEFAULTS, ...(data?.values || {}) }
|
||||
@@ -900,6 +989,7 @@ export function render() {
|
||||
quickCommandsLoading = true
|
||||
unauthorizedDmLoading = true
|
||||
securityLoading = true
|
||||
displayLoading = true
|
||||
humanDelayLoading = true
|
||||
streamingLoading = true
|
||||
executionLimitsLoading = true
|
||||
@@ -913,6 +1003,7 @@ export function render() {
|
||||
quickCommandsError = null
|
||||
unauthorizedDmError = null
|
||||
securityError = null
|
||||
displayError = null
|
||||
humanDelayError = null
|
||||
streamingError = null
|
||||
executionLimitsError = null
|
||||
@@ -1013,6 +1104,14 @@ export function render() {
|
||||
securityLoading = false
|
||||
draw()
|
||||
}
|
||||
try {
|
||||
await loadDisplayConfig()
|
||||
} catch (err) {
|
||||
displayError = humanizeError(err, t('engine.hermesDisplayConfigLoadFailed') || 'Load display config failed')
|
||||
} finally {
|
||||
displayLoading = false
|
||||
draw()
|
||||
}
|
||||
try {
|
||||
await loadHumanDelayConfig()
|
||||
} catch (err) {
|
||||
@@ -1066,6 +1165,9 @@ export function render() {
|
||||
try {
|
||||
await loadSecurityConfig()
|
||||
} catch {}
|
||||
try {
|
||||
await loadDisplayConfig()
|
||||
} catch {}
|
||||
try {
|
||||
await loadHumanDelayConfig()
|
||||
} catch {}
|
||||
@@ -1312,6 +1414,38 @@ export function render() {
|
||||
}
|
||||
}
|
||||
|
||||
async function saveDisplayConfig() {
|
||||
const form = {
|
||||
displayToolProgress: el.querySelector('#hm-display-tool-progress')?.value || 'all',
|
||||
displayToolProgressCommand: !!el.querySelector('#hm-display-tool-progress-command')?.checked,
|
||||
displayInterimAssistantMessages: !!el.querySelector('#hm-display-interim-assistant-messages')?.checked,
|
||||
displayRuntimeFooterEnabled: !!el.querySelector('#hm-display-runtime-footer-enabled')?.checked,
|
||||
displayRuntimeFooterFields: el.querySelector('#hm-display-runtime-footer-fields')?.value || 'model\ncontext_pct\ncwd',
|
||||
displayFileMutationVerifier: !!el.querySelector('#hm-display-file-mutation-verifier')?.checked,
|
||||
displayLanguage: el.querySelector('#hm-display-language')?.value || 'en',
|
||||
displayResumeDisplay: el.querySelector('#hm-display-resume-display')?.value || 'full',
|
||||
}
|
||||
displaySaving = true
|
||||
displayError = null
|
||||
draw()
|
||||
try {
|
||||
const result = await api.hermesDisplayConfigSave(form)
|
||||
displayValues = { ...DISPLAY_DEFAULTS, ...(result?.values || form) }
|
||||
await refreshRawAfterStructuredSave()
|
||||
const backup = result?.backup || ''
|
||||
toast({
|
||||
message: t('engine.hermesDisplayConfigSaveSuccess'),
|
||||
hint: backup ? t('engine.hermesConfigBackupHint', { path: backup }) : '',
|
||||
}, 'success')
|
||||
} catch (err) {
|
||||
displayError = humanizeError(err, t('engine.hermesDisplayConfigSaveFailed') || 'Save display config failed')
|
||||
toast(displayError, 'error')
|
||||
} finally {
|
||||
displaySaving = false
|
||||
draw()
|
||||
}
|
||||
}
|
||||
|
||||
async function saveHumanDelayConfig() {
|
||||
const form = {
|
||||
humanDelayMode: el.querySelector('#hm-human-delay-mode')?.value || 'off',
|
||||
|
||||
Reference in New Issue
Block a user