feat(personalization): 简略消息显示改为持久化到配置文件

原来「简略消息显示」只存浏览器 localStorage(experiments),换设备/清缓存即丢。
现迁移到后端 personalization.json,与主题/默认隐藏工作区一致即时保存:

- 后端新增 compact_message_display 字段(默认 full)及清洗(仅 full/brief,
  容错大小写空格,非法回退 full)
- store: PersonalForm 加字段;setCompactMessageDisplay 写 form + 即时 POST;
  加载时同步进旧 experiments 镜像,并一次性迁移本地遗留 brief 回写配置文件
- 抽屉下拉与 ChatArea 改读 form.compact_message_display,experiments 作兜底
- 保留 localStorage 镜像保证向后兼容,老用户首次加载自动迁移偏好

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
JOJO 2026-06-05 23:31:06 +08:00
parent 9399d3f41e
commit 9be775d346
4 changed files with 56 additions and 3 deletions

View File

@ -91,6 +91,7 @@ DEFAULT_PERSONALIZATION_CONFIG: Dict[str, Any] = {
"deep_compress_behavior": "continue", # 手动压缩行为continue-注入并触发请求 / wait-仅插入等待用户
"silent_tool_disable": True, # 禁用工具时不向模型插入提示(默认开启)
"enhanced_tool_display": True, # 增强工具显示
"compact_message_display": "full", # 简略消息显示full-完整原始内容 / brief-一行概要
"show_git_status_bar": True, # 是否显示输入栏上方 Git 状态栏
"versioning_restore_mode": "overwrite", # 版本回溯模式固定为 overwrite
"agents_md_auto_inject": False, # AGENTS.md 自动注入开关
@ -414,6 +415,13 @@ def sanitize_personalization_payload(
else:
base["enhanced_tool_display"] = bool(base.get("enhanced_tool_display", True))
# 简略消息显示full完整原始内容/ brief一行概要
compact_msg = data.get("compact_message_display", base.get("compact_message_display"))
if isinstance(compact_msg, str) and compact_msg.strip().lower() in ("full", "brief"):
base["compact_message_display"] = compact_msg.strip().lower()
else:
base["compact_message_display"] = "full"
# Git 状态栏显示开关
if "show_git_status_bar" in data:
base["show_git_status_bar"] = bool(data.get("show_git_status_bar"))

View File

@ -634,7 +634,11 @@ const blockDisplayMode = computed(() => {
return personalization.experiments.blockDisplayMode || 'stacked';
});
const compactMessageDisplay = computed(() => {
return personalization.experiments.compactMessageDisplay || 'full';
return (
personalization.form.compact_message_display ||
personalization.experiments.compactMessageDisplay ||
'full'
);
});
const stackedBlocksEnabled = computed(() => {
// 使

View File

@ -1779,7 +1779,9 @@ const blockDisplayLabel = computed(() => {
);
});
const currentCompactMessageDisplay = computed(() => experiments.value.compactMessageDisplay);
const currentCompactMessageDisplay = computed(
() => form.value.compact_message_display || 'full'
);
const compactMessageDisplayLabel = computed(() => {
return (

View File

@ -21,6 +21,7 @@ interface PersonalForm {
skill_strict_run_command_background_enabled: boolean;
silent_tool_disable: boolean;
enhanced_tool_display: boolean;
compact_message_display: CompactMessageDisplay;
show_git_status_bar: boolean;
enhanced_tool_display_categories: string[];
enabled_skills: string[];
@ -116,6 +117,7 @@ const defaultForm = (): PersonalForm => ({
skill_strict_run_command_background_enabled: false,
silent_tool_disable: false,
enhanced_tool_display: true,
compact_message_display: 'full',
show_git_status_bar: true,
enhanced_tool_display_categories: [],
enabled_skills: [],
@ -295,6 +297,7 @@ export const usePersonalizationStore = defineStore('personalization', {
!!data.skill_strict_run_command_background_enabled,
silent_tool_disable: !!data.silent_tool_disable,
enhanced_tool_display: data.enhanced_tool_display !== false,
compact_message_display: data.compact_message_display === 'brief' ? 'brief' : 'full',
show_git_status_bar: data.show_git_status_bar !== false,
enhanced_tool_display_categories: Array.isArray(data.enhanced_tool_display_categories)
? data.enhanced_tool_display_categories.filter((item: unknown) => typeof item === 'string')
@ -381,6 +384,18 @@ export const usePersonalizationStore = defineStore('personalization', {
if (this.form.default_hide_workspace) {
useUiStore().setWorkspaceCollapsed(true);
}
// 简略消息显示:以配置文件为准,同步到旧版 localStorage 镜像供 ChatArea 读取。
// 一次性迁移:后端仍为默认 full但本地缓存遗留 brief旧版纯前端记录回写到配置文件。
const cachedCompact = this.experiments.compactMessageDisplay;
if (this.form.compact_message_display === 'full' && cachedCompact === 'brief') {
this.form = { ...this.form, compact_message_display: 'brief' };
void this.persistCompactMessageDisplay('brief');
}
this.experiments = {
...this.experiments,
compactMessageDisplay: this.form.compact_message_display
};
this.persistExperiments();
this.clearFeedback();
},
applyTheme(theme: 'classic' | 'light' | 'dark') {
@ -791,11 +806,35 @@ export const usePersonalizationStore = defineStore('personalization', {
this.persistExperiments();
},
setCompactMessageDisplay(mode: CompactMessageDisplay) {
const target: CompactMessageDisplay = mode === 'brief' ? 'brief' : 'full';
this.form = {
...this.form,
compact_message_display: target
};
// 同步旧版 localStorage 镜像,保持兼容并避免迁移逻辑回写旧值
this.experiments = {
...this.experiments,
compactMessageDisplay: mode
compactMessageDisplay: target
};
this.persistExperiments();
this.clearFeedback();
// 持久化到后端配置文件(即时保存,参照主题/默认隐藏工作区)
void this.persistCompactMessageDisplay(target);
},
async persistCompactMessageDisplay(mode: CompactMessageDisplay) {
try {
const resp = await fetch('/api/personalization', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ compact_message_display: mode })
});
const result = await resp.json();
if (!resp.ok || !result.success) {
console.warn('保存简略消息显示失败:', result?.error);
}
} catch (error) {
console.warn('保存简略消息显示失败:', error);
}
},
setCommunicationStyle(style: 'default' | 'human_like') {
this.form = {