Files
ycode/scripts/personalization-prompt-regression.ts
T
xiaohan.yuan 0dc088f1f7 feat(settings): replicate the WorkBuddy personalization panel and wire identity, tone and prompts (TODO 13)
Recover the WorkBuddy 5.8.3 个性化 page from REA evidence (PersonalizationPanel-D16rRGjy.css + tokens): 45 module rules plus scoped light/dark tokens, the five-card 1160px layout (identity card 638x100 with inline editors, reply preference card 638x204, three 638x264 long-text cards with 598x160 previews) and the 640x520 editor modal.

Persist identity, tone, welcome tips, custom instructions, persona and long-term memory in config.json, expose personalization:get/update over IPC, and append the resulting personalization context to each turn's prompt for both the OMP and built-in kernels. Wire 欢迎语 to the streaming loading tips and keep 显示文件修改过程 visibly disabled because YCode has no incremental file-change renderer yet.

Verify with scripts/verify-personalization-settings.cjs: 29 assertions covering geometry, tone options, switches, inline identity editing with blur-discard, editor modal save/cancel, config persistence, reopen, dark surfaces and no renderer errors. Add a pure prompt-builder regression and keep every existing settings regression green.
2026-10-17 10:46:40 +08:00

46 lines
2.5 KiB
TypeScript

/**
* TODO 13:个性化提示词拼装的离线回归。
* 覆盖默认值不产生多余上下文、身份/风格/指令/人设/长期记忆分别进入提示词、超长截断与非法风格回退。
*/
import assert from 'node:assert/strict'
import { buildPersonalizationPrompt, DEFAULT_PERSONA, normalizePersonalization } from '../src/shared/personalization'
const base = normalizePersonalization({})
assert.equal(base.tone, 'default')
assert.equal(base.loadingTips, true)
assert.equal(base.showFileChanges, false)
assert.equal(base.persona, DEFAULT_PERSONA)
assert.equal(buildPersonalizationPrompt(base), '', '默认设置不应把原版人设注入每轮提示词')
const identity = buildPersonalizationPrompt(normalizePersonalization({ userCallName: ' 小明 ', aiName: ' YCode 助手 ' }))
assert.match(identity, /^## 个性化偏好(用户设置,始终遵守)/)
assert.ok(identity.includes('- 用户希望被称呼为:小明'))
assert.ok(identity.includes('- 你的名字是:YCode 助手;自我介绍时使用这个名字。'))
assert.ok(!identity.includes(DEFAULT_PERSONA), '默认人设不应进入提示词')
const tone = buildPersonalizationPrompt(normalizePersonalization({ tone: 'professional' }))
assert.ok(tone.includes('- 回复风格:专业严谨——清晰、准确、值得信赖。'))
const custom = buildPersonalizationPrompt(normalizePersonalization({ customPrompt: '\n先给结论,再给依据。\n' }))
assert.ok(custom.includes('### 用户指令\n先给结论,再给依据。'))
const persona = buildPersonalizationPrompt(normalizePersonalization({ persona: '你是一位严谨的代码审阅者。' }))
assert.ok(persona.includes('### 人设设定\n你是一位严谨的代码审阅者。'))
const memory = buildPersonalizationPrompt(normalizePersonalization({ longTermMemory: '用户偏好 TypeScript。' }))
assert.ok(memory.includes('### 长期记忆\n用户偏好 TypeScript。'))
const long = buildPersonalizationPrompt(normalizePersonalization({ customPrompt: 'x'.repeat(8100) }))
assert.ok(long.includes('(内容过长,已截断)'))
assert.ok(long.length < 8100, '超长字段应被截断')
const fallback = normalizePersonalization({ tone: 'not-a-tone' as never })
assert.equal(fallback.tone, 'default')
assert.equal(buildPersonalizationPrompt(fallback), '')
const tips = normalizePersonalization({ loadingTips: false, showFileChanges: true })
assert.equal(tips.loadingTips, false)
assert.equal(tips.showFileChanges, true)
console.log('personalization-prompt-regression: all checks passed')