mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-29 04:10:00 +08:00
feat(hermes): add display analytics controls
This commit is contained in:
@@ -3806,6 +3806,9 @@ export function buildHermesDisplayConfigValues(config = {}) {
|
||||
const display = root.display && typeof root.display === 'object' && !Array.isArray(root.display)
|
||||
? root.display
|
||||
: {}
|
||||
const dashboard = root.dashboard && typeof root.dashboard === 'object' && !Array.isArray(root.dashboard)
|
||||
? root.dashboard
|
||||
: {}
|
||||
const runtimeFooter = display.runtime_footer && typeof display.runtime_footer === 'object' && !Array.isArray(display.runtime_footer)
|
||||
? display.runtime_footer
|
||||
: {}
|
||||
@@ -3822,6 +3825,8 @@ export function buildHermesDisplayConfigValues(config = {}) {
|
||||
displayRuntimeFooterEnabled: readHermesBool(runtimeFooter.enabled, false),
|
||||
displayRuntimeFooterFields: normalizeHermesRuntimeFooterFields(runtimeFooter.fields, false).join('\n'),
|
||||
displayFileMutationVerifier: readHermesBool(display.file_mutation_verifier, true),
|
||||
displayShowCost: readHermesBool(display.show_cost, false),
|
||||
dashboardShowTokenAnalytics: readHermesBool(dashboard.show_token_analytics, false),
|
||||
displayLanguage: normalizeHermesDisplayLanguage(display.language, false),
|
||||
displayResumeDisplay: normalizeHermesDisplayResume(display.resume_display, false),
|
||||
displayBusyInputMode: normalizeHermesDisplayBusyInputMode(display.busy_input_mode, false),
|
||||
@@ -3857,6 +3862,7 @@ export function mergeHermesDisplayConfig(config = {}, form = {}) {
|
||||
runtimeFooter.fields = normalizeHermesRuntimeFooterFields(Object.hasOwn(form, 'displayRuntimeFooterFields') ? form.displayRuntimeFooterFields : currentValues.displayRuntimeFooterFields, true)
|
||||
display.runtime_footer = runtimeFooter
|
||||
display.file_mutation_verifier = formHermesBool(form, 'displayFileMutationVerifier', currentValues.displayFileMutationVerifier)
|
||||
display.show_cost = formHermesBool(form, 'displayShowCost', currentValues.displayShowCost)
|
||||
display.language = normalizeHermesDisplayLanguage(Object.hasOwn(form, 'displayLanguage') ? form.displayLanguage : currentValues.displayLanguage, true)
|
||||
display.resume_display = normalizeHermesDisplayResume(Object.hasOwn(form, 'displayResumeDisplay') ? form.displayResumeDisplay : currentValues.displayResumeDisplay, true)
|
||||
display.busy_input_mode = normalizeHermesDisplayBusyInputMode(Object.hasOwn(form, 'displayBusyInputMode') ? form.displayBusyInputMode : currentValues.displayBusyInputMode, true)
|
||||
@@ -3867,6 +3873,11 @@ export function mergeHermesDisplayConfig(config = {}, form = {}) {
|
||||
display.persistent_output = formHermesBool(form, 'displayPersistentOutput', currentValues.displayPersistentOutput)
|
||||
display.persistent_output_max_lines = parseHermesInteger(Object.hasOwn(form, 'displayPersistentOutputMaxLines') ? form.displayPersistentOutputMaxLines : currentValues.displayPersistentOutputMaxLines, 'display.persistent_output_max_lines', 200, 0, 100000, true)
|
||||
next.display = display
|
||||
const dashboard = next.dashboard && typeof next.dashboard === 'object' && !Array.isArray(next.dashboard)
|
||||
? mergeConfigsPreservingFields(next.dashboard, {})
|
||||
: {}
|
||||
dashboard.show_token_analytics = formHermesBool(form, 'dashboardShowTokenAnalytics', currentValues.dashboardShowTokenAnalytics)
|
||||
next.dashboard = dashboard
|
||||
return next
|
||||
}
|
||||
|
||||
|
||||
@@ -6515,6 +6515,7 @@ fn normalize_hermes_runtime_footer_fields(
|
||||
fn build_hermes_display_config_values(config: &serde_yaml::Value) -> Value {
|
||||
let root = config.as_mapping();
|
||||
let display = root.and_then(|map| yaml_get_mapping(map, "display"));
|
||||
let dashboard = root.and_then(|map| yaml_get_mapping(map, "dashboard"));
|
||||
let runtime_footer = display.and_then(|map| yaml_get_mapping(map, "runtime_footer"));
|
||||
let runtime_footer_fields = normalize_hermes_runtime_footer_fields(
|
||||
runtime_footer.and_then(|map| yaml_get(map, "fields")),
|
||||
@@ -6553,6 +6554,8 @@ fn build_hermes_display_config_values(config: &serde_yaml::Value) -> Value {
|
||||
"displayRuntimeFooterEnabled": runtime_footer.and_then(|map| yaml_bool_field(map, "enabled")).unwrap_or(false),
|
||||
"displayRuntimeFooterFields": runtime_footer_fields.join("\n"),
|
||||
"displayFileMutationVerifier": display.and_then(|map| yaml_bool_field(map, "file_mutation_verifier")).unwrap_or(true),
|
||||
"displayShowCost": display.and_then(|map| yaml_bool_field(map, "show_cost")).unwrap_or(false),
|
||||
"dashboardShowTokenAnalytics": dashboard.and_then(|map| yaml_bool_field(map, "show_token_analytics")).unwrap_or(false),
|
||||
"displayLanguage": normalize_hermes_display_language(
|
||||
display.and_then(|map| yaml_string_field(map, "language")),
|
||||
false,
|
||||
@@ -6707,6 +6710,13 @@ fn merge_hermes_display_config(config: &mut serde_yaml::Value, form: &Value) ->
|
||||
}),
|
||||
),
|
||||
);
|
||||
display.insert(
|
||||
yaml_key("show_cost"),
|
||||
serde_yaml::Value::Bool(
|
||||
form_bool(form, "displayShowCost")
|
||||
.unwrap_or_else(|| current["displayShowCost"].as_bool().unwrap_or(false)),
|
||||
),
|
||||
);
|
||||
display.insert(
|
||||
yaml_key("language"),
|
||||
serde_yaml::Value::String(normalize_hermes_display_language(
|
||||
@@ -6797,6 +6807,17 @@ fn merge_hermes_display_config(config: &mut serde_yaml::Value, form: &Value) ->
|
||||
.collect(),
|
||||
),
|
||||
);
|
||||
let dashboard = yaml_child_object(ensure_yaml_object(config)?, "dashboard")?;
|
||||
dashboard.insert(
|
||||
yaml_key("show_token_analytics"),
|
||||
serde_yaml::Value::Bool(
|
||||
form_bool(form, "dashboardShowTokenAnalytics").unwrap_or_else(|| {
|
||||
current["dashboardShowTokenAnalytics"]
|
||||
.as_bool()
|
||||
.unwrap_or(false)
|
||||
}),
|
||||
),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -22263,6 +22284,8 @@ mod hermes_display_config_tests {
|
||||
"model\ncontext_pct\ncwd"
|
||||
);
|
||||
assert_eq!(values["displayFileMutationVerifier"], true);
|
||||
assert_eq!(values["displayShowCost"], false);
|
||||
assert_eq!(values["dashboardShowTokenAnalytics"], false);
|
||||
assert_eq!(values["displayLanguage"], "en");
|
||||
assert_eq!(values["displayResumeDisplay"], "full");
|
||||
assert_eq!(values["displayBusyInputMode"], "interrupt");
|
||||
@@ -22295,6 +22318,7 @@ display:
|
||||
- duration
|
||||
- cost
|
||||
file_mutation_verifier: false
|
||||
show_cost: true
|
||||
language: ZH
|
||||
resume_display: minimal
|
||||
busy_input_mode: QUEUE
|
||||
@@ -22304,6 +22328,8 @@ display:
|
||||
bell_on_complete: true
|
||||
persistent_output: false
|
||||
persistent_output_max_lines: 80
|
||||
dashboard:
|
||||
show_token_analytics: true
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -22323,6 +22349,8 @@ display:
|
||||
"model\nduration\ncost"
|
||||
);
|
||||
assert_eq!(values["displayFileMutationVerifier"], false);
|
||||
assert_eq!(values["displayShowCost"], true);
|
||||
assert_eq!(values["dashboardShowTokenAnalytics"], true);
|
||||
assert_eq!(values["displayLanguage"], "zh");
|
||||
assert_eq!(values["displayResumeDisplay"], "minimal");
|
||||
assert_eq!(values["displayBusyInputMode"], "queue");
|
||||
@@ -22348,6 +22376,8 @@ display:
|
||||
platforms:
|
||||
telegram:
|
||||
tool_progress: new
|
||||
dashboard:
|
||||
custom_flag: keep-dashboard
|
||||
memory:
|
||||
memory_enabled: true
|
||||
"#,
|
||||
@@ -22369,6 +22399,8 @@ memory:
|
||||
"displayRuntimeFooterEnabled": true,
|
||||
"displayRuntimeFooterFields": "model\ncontext_pct\nduration",
|
||||
"displayFileMutationVerifier": true,
|
||||
"displayShowCost": true,
|
||||
"dashboardShowTokenAnalytics": true,
|
||||
"displayLanguage": "zh-hant",
|
||||
"displayResumeDisplay": "minimal",
|
||||
"displayBusyInputMode": "steer",
|
||||
@@ -22384,6 +22416,14 @@ memory:
|
||||
|
||||
assert_eq!(config["model"]["provider"].as_str(), Some("anthropic"));
|
||||
assert_eq!(config["memory"]["memory_enabled"].as_bool(), Some(true));
|
||||
assert_eq!(
|
||||
config["dashboard"]["custom_flag"].as_str(),
|
||||
Some("keep-dashboard")
|
||||
);
|
||||
assert_eq!(
|
||||
config["dashboard"]["show_token_analytics"].as_bool(),
|
||||
Some(true)
|
||||
);
|
||||
assert_eq!(config["display"]["compact"].as_bool(), Some(true));
|
||||
assert_eq!(config["display"]["skin"].as_str(), Some("slate"));
|
||||
assert_eq!(config["display"]["tool_prefix"].as_str(), Some("│"));
|
||||
@@ -22424,6 +22464,7 @@ memory:
|
||||
config["display"]["file_mutation_verifier"].as_bool(),
|
||||
Some(true)
|
||||
);
|
||||
assert_eq!(config["display"]["show_cost"].as_bool(), Some(true));
|
||||
assert_eq!(config["display"]["language"].as_str(), Some("zh-hant"));
|
||||
assert_eq!(
|
||||
config["display"]["resume_display"].as_str(),
|
||||
|
||||
@@ -200,6 +200,8 @@ const DISPLAY_DEFAULTS = {
|
||||
displayRuntimeFooterEnabled: false,
|
||||
displayRuntimeFooterFields: 'model\ncontext_pct\ncwd',
|
||||
displayFileMutationVerifier: true,
|
||||
displayShowCost: false,
|
||||
dashboardShowTokenAnalytics: false,
|
||||
displayLanguage: 'en',
|
||||
displayResumeDisplay: 'full',
|
||||
displayBusyInputMode: 'interrupt',
|
||||
@@ -1815,6 +1817,14 @@ export function render() {
|
||||
<input id="hm-display-file-mutation-verifier" type="checkbox" ${displayValues.displayFileMutationVerifier ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
|
||||
<span>${t('engine.hermesDisplayConfigFileMutationVerifier')}</span>
|
||||
</label>
|
||||
<label class="hm-channel-check">
|
||||
<input id="hm-display-show-cost" type="checkbox" ${displayValues.displayShowCost ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
|
||||
<span>${t('engine.hermesDisplayConfigShowCost')}</span>
|
||||
</label>
|
||||
<label class="hm-channel-check">
|
||||
<input id="hm-dashboard-show-token-analytics" type="checkbox" ${displayValues.dashboardShowTokenAnalytics ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
|
||||
<span>${t('engine.hermesDisplayConfigShowTokenAnalytics')}</span>
|
||||
</label>
|
||||
<label class="hm-channel-check">
|
||||
<input id="hm-display-timestamps" type="checkbox" ${displayValues.displayTimestamps ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
|
||||
<span>${t('engine.hermesDisplayConfigTimestamps')}</span>
|
||||
@@ -4451,6 +4461,8 @@ export function render() {
|
||||
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,
|
||||
displayShowCost: !!el.querySelector('#hm-display-show-cost')?.checked,
|
||||
dashboardShowTokenAnalytics: !!el.querySelector('#hm-dashboard-show-token-analytics')?.checked,
|
||||
displayLanguage: el.querySelector('#hm-display-language')?.value || 'en',
|
||||
displayResumeDisplay: el.querySelector('#hm-display-resume-display')?.value || 'full',
|
||||
displayBusyInputMode: el.querySelector('#hm-display-busy-input-mode')?.value || 'interrupt',
|
||||
|
||||
@@ -1153,6 +1153,8 @@ export default {
|
||||
hermesDisplayConfigRuntimeFooterEnabled: _('在最终回复追加运行信息', 'Append runtime footer to final replies', '在最終回覆追加執行資訊'),
|
||||
hermesDisplayConfigRuntimeFooterFields: _('运行信息字段(每行一个)', 'Runtime footer fields, one per line', '執行資訊欄位(每行一個)'),
|
||||
hermesDisplayConfigFileMutationVerifier: _('启用文件写入失败校验', 'Enable failed file-mutation verifier', '啟用檔案寫入失敗校驗'),
|
||||
hermesDisplayConfigShowCost: _('在 CLI 状态栏显示成本估算', 'Show estimated cost in CLI status bar', '在 CLI 狀態列顯示成本估算'),
|
||||
hermesDisplayConfigShowTokenAnalytics: _('显示 Token 与成本分析入口', 'Show token and cost analytics surfaces', '顯示 Token 與成本分析入口'),
|
||||
hermesDisplayConfigLanguage: _('静态提示语言', 'Static prompt language', '靜態提示語言'),
|
||||
hermesDisplayConfigLanguage_en: _('英语', 'English', '英語'),
|
||||
hermesDisplayConfigLanguage_zh: _('简体中文', 'Simplified Chinese', '簡體中文'),
|
||||
@@ -1190,7 +1192,7 @@ export default {
|
||||
hermesDisplayConfigBellOnComplete: _('任务完成时播放提示音', 'Play bell when runs complete', '任務完成時播放提示音'),
|
||||
hermesDisplayConfigPersistentOutput: _('保留终端输出用于恢复显示', 'Keep terminal output for display recovery', '保留終端輸出用於恢復顯示'),
|
||||
hermesDisplayConfigPersistentOutputMaxLines: _('保留输出最大行数', 'Max retained output lines', '保留輸出最大行數'),
|
||||
hermesDisplayConfigFootnote: _('这里写入全局 display 配置;平台级覆盖仍在渠道页管理。工具预览长度为 0 时使用 Hermes 默认长度;清理进度只会在支持消息删除的平台成功完成后生效。紧凑横幅和显示皮肤影响 CLI 启动展示。忙时输入控制长跑期间新消息如何处理,后台进程通知控制 messaging watcher 噪音。最终回复 Markdown、时间戳、完成铃声和持久输出影响 CLI 可读性与终端重绘恢复。display.streaming 是 CLI-only,本面板不会把它误写成 Gateway 全局流式设置。运行信息字段支持 model、context_pct、cwd、duration、tokens、cost。', 'This writes global display settings; per-platform overrides remain in channel settings. Tool preview length 0 lets Hermes use its default length; progress cleanup only applies after successful turns on platforms that support message deletion. Compact banner and display skin affect CLI startup presentation. Busy input controls how new messages are handled during long runs, and background process notifications tune messaging watcher noise. Final-response Markdown, timestamps, completion bell, and persistent output affect CLI readability and terminal redraw recovery. display.streaming is CLI-only, so this panel does not write it as a global Gateway streaming setting. Runtime footer fields support model, context_pct, cwd, duration, tokens, and cost.', '這裡寫入全域 display 設定;平台級覆蓋仍在頻道頁管理。工具預覽長度為 0 時使用 Hermes 預設長度;清理進度只會在支援訊息刪除的平台成功完成後生效。緊湊橫幅和顯示皮膚會影響 CLI 啟動展示。忙時輸入控制長跑期間新訊息如何處理,背景程序通知控制 messaging watcher 噪音。最終回覆 Markdown、時間戳、完成鈴聲和持久輸出會影響 CLI 可讀性與終端重繪恢復。display.streaming 是 CLI-only,本面板不會把它誤寫成 Gateway 全域串流設定。執行資訊欄位支援 model、context_pct、cwd、duration、tokens、cost。'),
|
||||
hermesDisplayConfigFootnote: _('这里写入全局 display 配置;平台级覆盖仍在渠道页管理。工具预览长度为 0 时使用 Hermes 默认长度;清理进度只会在支持消息删除的平台成功完成后生效。紧凑横幅和显示皮肤影响 CLI 启动展示。忙时输入控制长跑期间新消息如何处理,后台进程通知控制 messaging watcher 噪音。最终回复 Markdown、时间戳、完成铃声和持久输出影响 CLI 可读性与终端重绘恢复。display.streaming 是 CLI-only,本面板不会把它误写成 Gateway 全局流式设置。运行信息字段支持 model、context_pct、cwd、duration、tokens、cost。成本与 Token 分析是本地 lower-bound 估算,不等同于 provider 账单。', 'This writes global display settings; per-platform overrides remain in channel settings. Tool preview length 0 lets Hermes use its default length; progress cleanup only applies after successful turns on platforms that support message deletion. Compact banner and display skin affect CLI startup presentation. Busy input controls how new messages are handled during long runs, and background process notifications tune messaging watcher noise. Final-response Markdown, timestamps, completion bell, and persistent output affect CLI readability and terminal redraw recovery. display.streaming is CLI-only, so this panel does not write it as a global Gateway streaming setting. Runtime footer fields support model, context_pct, cwd, duration, tokens, and cost. Cost and token analytics are local lower-bound estimates, not provider billing records.', '這裡寫入全域 display 設定;平台級覆蓋仍在頻道頁管理。工具預覽長度為 0 時使用 Hermes 預設長度;清理進度只會在支援訊息刪除的平台成功完成後生效。緊湊橫幅和顯示皮膚會影響 CLI 啟動展示。忙時輸入控制長跑期間新訊息如何處理,背景程序通知控制 messaging watcher 噪音。最終回覆 Markdown、時間戳、完成鈴聲和持久輸出會影響 CLI 可讀性與終端重繪恢復。display.streaming 是 CLI-only,本面板不會把它誤寫成 Gateway 全域串流設定。執行資訊欄位支援 model、context_pct、cwd、duration、tokens、cost。成本與 Token 分析是本地 lower-bound 估算,不等同於 provider 帳單。'),
|
||||
hermesHumanDelayConfigTitle: _('响应节奏', 'Response pacing', '回應節奏'),
|
||||
hermesHumanDelayConfigDesc: _('控制消息平台回复分块之间的等待时间,降低刷屏或模拟更自然发送节奏。', 'Control the wait time between reply chunks on messaging platforms to reduce flooding or mimic a more natural sending rhythm.', '控制訊息平台回覆分塊之間的等待時間,降低刷屏或模擬更自然的傳送節奏。'),
|
||||
hermesHumanDelayConfigStatusReady: _('结构化配置', 'structured settings', '結構化設定'),
|
||||
|
||||
@@ -274,6 +274,8 @@ test('Hermes 配置页会暴露全局显示与可靠性结构化配置字段', (
|
||||
'hm-display-runtime-footer-enabled',
|
||||
'hm-display-runtime-footer-fields',
|
||||
'hm-display-file-mutation-verifier',
|
||||
'hm-display-show-cost',
|
||||
'hm-dashboard-show-token-analytics',
|
||||
'hm-display-language',
|
||||
'hm-display-resume-display',
|
||||
'hm-display-busy-input-mode',
|
||||
|
||||
@@ -22,6 +22,8 @@ test('Hermes 显示配置读取会提供上游默认值', () => {
|
||||
displayRuntimeFooterEnabled: false,
|
||||
displayRuntimeFooterFields: 'model\ncontext_pct\ncwd',
|
||||
displayFileMutationVerifier: true,
|
||||
displayShowCost: false,
|
||||
dashboardShowTokenAnalytics: false,
|
||||
displayLanguage: 'en',
|
||||
displayResumeDisplay: 'full',
|
||||
displayBusyInputMode: 'interrupt',
|
||||
@@ -51,6 +53,7 @@ test('Hermes 显示配置读取会规范化已有字段', () => {
|
||||
fields: ['model', 'duration', 'cost'],
|
||||
},
|
||||
file_mutation_verifier: false,
|
||||
show_cost: true,
|
||||
language: 'ZH',
|
||||
resume_display: 'minimal',
|
||||
busy_input_mode: 'QUEUE',
|
||||
@@ -61,6 +64,9 @@ test('Hermes 显示配置读取会规范化已有字段', () => {
|
||||
persistent_output: false,
|
||||
persistent_output_max_lines: 80,
|
||||
},
|
||||
dashboard: {
|
||||
show_token_analytics: true,
|
||||
},
|
||||
})
|
||||
|
||||
assert.equal(values.displayToolProgress, 'verbose')
|
||||
@@ -75,6 +81,8 @@ test('Hermes 显示配置读取会规范化已有字段', () => {
|
||||
assert.equal(values.displayRuntimeFooterEnabled, true)
|
||||
assert.equal(values.displayRuntimeFooterFields, 'model\nduration\ncost')
|
||||
assert.equal(values.displayFileMutationVerifier, false)
|
||||
assert.equal(values.displayShowCost, true)
|
||||
assert.equal(values.dashboardShowTokenAnalytics, true)
|
||||
assert.equal(values.displayLanguage, 'zh')
|
||||
assert.equal(values.displayResumeDisplay, 'minimal')
|
||||
assert.equal(values.displayBusyInputMode, 'queue')
|
||||
@@ -99,6 +107,9 @@ test('Hermes 显示配置保存会保留未知 YAML 并写入 display', () => {
|
||||
telegram: { tool_progress: 'new' },
|
||||
},
|
||||
},
|
||||
dashboard: {
|
||||
custom_flag: 'keep-dashboard',
|
||||
},
|
||||
memory: { memory_enabled: true },
|
||||
}, {
|
||||
displayToolProgress: 'off',
|
||||
@@ -113,6 +124,8 @@ test('Hermes 显示配置保存会保留未知 YAML 并写入 display', () => {
|
||||
displayRuntimeFooterEnabled: true,
|
||||
displayRuntimeFooterFields: 'model\ncontext_pct\nduration',
|
||||
displayFileMutationVerifier: true,
|
||||
displayShowCost: true,
|
||||
dashboardShowTokenAnalytics: true,
|
||||
displayLanguage: 'zh-hant',
|
||||
displayResumeDisplay: 'minimal',
|
||||
displayBusyInputMode: 'steer',
|
||||
@@ -126,6 +139,8 @@ test('Hermes 显示配置保存会保留未知 YAML 并写入 display', () => {
|
||||
|
||||
assert.deepEqual(next.model, { provider: 'anthropic' })
|
||||
assert.deepEqual(next.memory, { memory_enabled: true })
|
||||
assert.equal(next.dashboard.custom_flag, 'keep-dashboard')
|
||||
assert.equal(next.dashboard.show_token_analytics, true)
|
||||
assert.equal(next.display.compact, true)
|
||||
assert.equal(next.display.skin, 'slate')
|
||||
assert.equal(next.display.tool_prefix, '│')
|
||||
@@ -140,6 +155,7 @@ test('Hermes 显示配置保存会保留未知 YAML 并写入 display', () => {
|
||||
assert.deepEqual(next.display.runtime_footer.fields, ['model', 'context_pct', 'duration'])
|
||||
assert.equal(next.display.runtime_footer.custom_flag, 'keep-footer')
|
||||
assert.equal(next.display.file_mutation_verifier, true)
|
||||
assert.equal(next.display.show_cost, true)
|
||||
assert.equal(next.display.language, 'zh-hant')
|
||||
assert.equal(next.display.resume_display, 'minimal')
|
||||
assert.equal(next.display.busy_input_mode, 'steer')
|
||||
|
||||
Reference in New Issue
Block a user