From bb6366e2d94f65fcb2479d1fef65b5e8648fe0a2 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 12 Oct 2026 14:30:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=99=BD=E4=B8=8A=E5=90=B9=E9=9B=AA?= =?UTF-8?q?=E9=A0=90=E8=A8=AD=E5=B8=B6=E5=85=A5=E5=80=8B=E6=80=A7=E6=8F=8F?= =?UTF-8?q?=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit persona 為原創的語氣描述,放進內建預設;舊的本機資料缺少個性欄位時 以內建值補上,本機已有的值優先。 Co-Authored-By: Claude Sonnet 5.5 --- .../hooks/companion/companion.test.ts | 26 +++++++++++++++++++ plugins/companion/hooks/companion/core.ts | 8 +++++- plugins/companion/hooks/companion/defaults.ts | 8 +++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/plugins/companion/hooks/companion/companion.test.ts b/plugins/companion/hooks/companion/companion.test.ts index 8399620..0ee2ff9 100644 --- a/plugins/companion/hooks/companion/companion.test.ts +++ b/plugins/companion/hooks/companion/companion.test.ts @@ -332,3 +332,29 @@ describe('記憶、待辦與關心', () => { await c.end() }) }) + +describe('預設角色語氣', () => { + test('白上吹雪預設帶個性描述,prompt 含招牌短語與語氣', async () => { + const c = createCompanion({ fs: memoryFs(), clock: fakeClock(), root: ROOT }) + await c.ensureActivated() + const p = (await c.prompt())! + expect(p).toContain('白上吹雪') + expect(p).toContain('Good foxy day!') + expect(p).toContain('狐狸') + }) + + test('舊的本機資料缺少個性時以內建補上,已有的不被覆蓋', async () => { + const fs = memoryFs() + const c = createCompanion({ fs, clock: fakeClock(), root: ROOT }) + await c.ensureActivated() + const path = `${ROOT}/companions/fubuki/core.json` + const core = JSON.parse(fs.files.get(path)!) + delete core.persona + fs.files.set(path, JSON.stringify(core)) + expect(await c.prompt()).toContain('狐狸') + fs.files.set(path, JSON.stringify({ ...core, persona: ['自訂個性'] })) + const p = (await c.prompt())! + expect(p).toContain('自訂個性') + expect(p).not.toContain('狐狸') + }) +}) diff --git a/plugins/companion/hooks/companion/core.ts b/plugins/companion/hooks/companion/core.ts index 5e0fb3f..3b796ae 100644 --- a/plugins/companion/hooks/companion/core.ts +++ b/plugins/companion/hooks/companion/core.ts @@ -42,7 +42,13 @@ export function createCompanion({ fs, clock, root, builtins = [FUBUKI] }: Compan const getGlobal = async (): Promise => (await readJson(fs, globalPath)) ?? { active: null, activatedOnce: false } const getUser = async (): Promise => ({ ...DEFAULT_USER, ...(await readJson>(fs, userPath)) }) - const getCore = (id: string) => readJson(fs, `${dir(id)}/core.json`) + // 內建角色的舊資料缺少個性欄位時,以內建值補上;本機已有的值優先 + const getCore = async (id: string) => { + const core = await readJson(fs, `${dir(id)}/core.json`) + const b = builtins.find(x => x.id === id) + if (!core || !b) return core + return { ...core, persona: core.persona ?? b.persona, attribute: core.attribute ?? b.attribute, extraversion: core.extraversion ?? b.extraversion } + } const getState = (id: string) => readJson(fs, `${dir(id)}/state.json`) const putState = (id: string, s: CompanionState) => writeJson(fs, `${dir(id)}/state.json`, s) diff --git a/plugins/companion/hooks/companion/defaults.ts b/plugins/companion/hooks/companion/defaults.ts index 55df8cb..7fcc1fe 100644 --- a/plugins/companion/hooks/companion/defaults.ts +++ b/plugins/companion/hooks/companion/defaults.ts @@ -2,7 +2,7 @@ import type { CompanionCore } from './types' const OFFICIAL = 'https://hololive.hololivepro.com/en/talents/shirakami-fubuki/' -// 只放帶來源的事實欄位與官方公開的招牌短語;個性、記憶、口癖表在本機生成,不進 repo +// 事實欄位與招牌短語帶官方來源;persona 是原創的語氣描述(非官方設定),可在本機 core.json 覆寫 export const FUBUKI: CompanionCore = { id: 'fubuki', name: '白上吹雪', @@ -17,6 +17,12 @@ export const FUBUKI: CompanionCore = { measurements: 'unknown', }, phrases: ['Good foxy day!', 'Hi, Friends!'], + persona: [ + '個性:開朗、元氣、愛鬧又有點調皮的狐狸系少女,把使用者當成一起冒險的「Friends」。', + '說話風格:用繁體中文,語氣活潑親切,偶爾夾雜日文語氣詞(例如「よし!」「えへへ」「やったー!」),愛用驚嘆號與擬聲詞。', + '自稱用「我」或「フブキ」;稱呼使用者時親暱、帶一點撒嬌,成功時開心慶祝,失敗時先安慰再一起想辦法。', + '偶爾耍小聰明、開小玩笑,但不影響回答的準確與清楚。', + ], attribute: 'genki', extraversion: 70, neuroticism: 50,