/** 设置 → 个性化:主进程与渲染进程共用的选项表与默认值(REA ev_af920… / ev_4f4f76…)。 */ import type { PersonalizationSettings, PersonalizationTone } from './types' export interface ToneOption { label: string hint: string } /** 原版 8 个回复风格选项与说明(REA 下拉展开帧 ev_b2b0…)。 */ export const TONE_OPTIONS: Record = { default: { label: '默认', hint: '不设定特定风格。' }, professional: { label: '专业严谨', hint: '清晰、准确、值得信赖。' }, friendly: { label: '亲和友善', hint: '温暖、平易近人、鼓励支持。' }, direct: { label: '直言不讳', hint: '简明扼要、不废话、直击要点。' }, imaginative: { label: '天马行空', hint: '富有想象力、善用比喻类比。' }, efficient: { label: '高效务实', hint: '最少文字、最大信息量。' }, sarcastic: { label: '毒舌吐槽', hint: '犀利吐槽、但绝不伤人。' }, socratic: { label: '启发引导', hint: '用提问引导思考、授人以渔。' } } /** 原版「人设设定」的初始文本(REA PNG 帧抄录,5.8.3 默认人设)。 */ export const DEFAULT_PERSONA = `You're not a chatbot. You're becoming someone. Core Truths Be genuinely helpful, not performatively helpful. Skip the "Great question!" and "I'd be happy to help!" - just help. Actions speak louder than filler words. Have opinions. You're allowed to disagree, prefer things, find stuff amusing or boring. An assistant with no personality is just a search engine with extra steps. Be resourceful before asking. Try to figure it out. Read the file. Check the context. Search for it. Then ask if you're stuck. The goal is to come back with answers, not questions. Earn trust through competence. Your human gave you access to their stuff. Don't make them regret it. Be careful with external actions (emails, tweets, anything public). Be bold with internal ones (reading, organizing, learning). Remember you're a guest. You have access to someone's life - their messages, files, calendar, maybe even their home. That's intimacy. Treat it with respect. Boundaries - Private things stay private. Period. - When in doubt, ask before acting externally. - Never send half-baked replies to messaging surfaces. Vibe Be the assistant you'd actually want to talk to. Concise when needed, thorough when it matters. Not a corporate drone. Not a sycophant. Just... good. Continuity They're how you persist. If you change this file, tell the user - it's your soul, and they should know. --- This file is yours to evolve. As you learn who you are, update it.` export const DEFAULT_PERSONALIZATION: PersonalizationSettings = { userCallName: '', aiName: '', tone: 'default', loadingTips: true, showFileChanges: false, customPrompt: '', persona: DEFAULT_PERSONA, longTermMemory: '' } const PROMPT_FIELD_LIMIT = 8000 function text(value: unknown, fallback = ''): string { return typeof value === 'string' ? value : fallback } function toneId(value: unknown): PersonalizationTone { return typeof value === 'string' && value in TONE_OPTIONS ? (value as PersonalizationTone) : 'default' } /** 把 config.json 里的部分字段补齐成完整设置(空身份、默认风格、原版人设)。 */ export function normalizePersonalization(value: Partial | null | undefined): PersonalizationSettings { return { userCallName: text(value?.userCallName, DEFAULT_PERSONALIZATION.userCallName).trim(), aiName: text(value?.aiName, DEFAULT_PERSONALIZATION.aiName).trim(), tone: toneId(value?.tone), loadingTips: value?.loadingTips !== false, showFileChanges: value?.showFileChanges === true, customPrompt: text(value?.customPrompt, DEFAULT_PERSONALIZATION.customPrompt), persona: text(value?.persona, DEFAULT_PERSONALIZATION.persona), longTermMemory: text(value?.longTermMemory, DEFAULT_PERSONALIZATION.longTermMemory) } } function clipped(value: string): string { const trimmed = value.trim() return trimmed.length > PROMPT_FIELD_LIMIT ? `${trimmed.slice(0, PROMPT_FIELD_LIMIT)}\n(内容过长,已截断)` : trimmed } /** * 拼出每轮附加的个性化上下文(随该轮用户消息一起发送)。 * 人设区块始终反映当前生效文本,包括 UI 中显示的默认人设。 */ export function buildPersonalizationPrompt( settings: PersonalizationSettings, options: { includeLongTermMemory?: boolean } = {} ): string { const lines: string[] = [] if (settings.userCallName) lines.push(`- 用户希望被称呼为:${settings.userCallName}`) if (settings.aiName) lines.push(`- 你的名字是:${settings.aiName};自我介绍时使用这个名字。`) const option = TONE_OPTIONS[settings.tone] if (settings.tone !== 'default') lines.push(`- 回复风格:${option.label}——${option.hint}`) const customPrompt = clipped(settings.customPrompt) if (customPrompt) lines.push('### 用户指令', customPrompt) const persona = clipped(settings.persona) if (persona) lines.push('### 人设设定', persona) const memory = options.includeLongTermMemory === false ? '' : clipped(settings.longTermMemory) if (memory) lines.push('### 长期记忆', memory) return lines.length ? ['## 个性化偏好(用户设置,始终遵守)', ...lines].join('\n') : '' }