build_pack.py 產生對白索引(放在使用者資料目錄);render_skill.py 把人格卡渲染成 角色 skill 並檢查精選對白逐字來自索引;插件改成執行期從資料目錄讀索引。 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
55 lines
2.1 KiB
TypeScript
55 lines
2.1 KiB
TypeScript
import { describe, expect, test } from 'claude-code/testing'
|
|
|
|
import type { Complete } from './classify'
|
|
import { resolveConfig } from './config'
|
|
import { buildInjection } from './inject'
|
|
import type { IndexEntry } from './retrieval'
|
|
|
|
const entry = (id: string, fn: IndexEntry['function']): IndexEntry => ({ id, function: fn, emotion: 'neutral', mode: null, text: `句${id}` })
|
|
const indexes: Record<string, IndexEntry[]> = {
|
|
'sao-asuna': [entry('a', 'comfort'), entry('b', 'comfort')],
|
|
'sao-suguha': [],
|
|
}
|
|
const answer = (text: string): Complete => async () => ({ isAnswered: true, text })
|
|
const deps = (opts: Record<string, string>, complete: Complete, calls = { n: 0 }) => ({
|
|
config: resolveConfig(opts),
|
|
loadIndex: async (c: string) => indexes[c] ?? [],
|
|
complete: async (r: Parameters<Complete>[0]) => (calls.n++, complete(r)),
|
|
now: () => 0,
|
|
turn: 0,
|
|
})
|
|
|
|
describe('buildInjection', () => {
|
|
const on = { defaultCharacter: 'sao-asuna', intensity: '2' }
|
|
|
|
test('分類成功時回傳同標籤的對白', async () => {
|
|
const r = await buildInjection(deps(on, answer('comfort')), '測試失敗了')
|
|
expect(r?.fn).toBe('comfort')
|
|
expect(r?.text).toContain('句a')
|
|
})
|
|
|
|
test('沒選角色或強度 0 不呼叫模型', async () => {
|
|
const calls = { n: 0 }
|
|
expect(await buildInjection(deps({ intensity: '2' }, answer('comfort'), calls), 'x')).toBeNull()
|
|
expect(await buildInjection(deps({ ...on, intensity: '0' }, answer('comfort'), calls), 'x')).toBeNull()
|
|
expect(calls.n).toBe(0)
|
|
})
|
|
|
|
test('索引為空不呼叫模型', async () => {
|
|
const calls = { n: 0 }
|
|
expect(await buildInjection(deps({ defaultCharacter: 'sao-suguha', intensity: '2' }, answer('comfort'), calls), 'x')).toBeNull()
|
|
expect(calls.n).toBe(0)
|
|
})
|
|
|
|
test('分類失敗退回不注入,但仍回報耗時', async () => {
|
|
const r = await buildInjection(deps(on, async () => ({ isAnswered: false })), 'x')
|
|
expect(r).toEqual({ text: null, fn: null, ms: 0 })
|
|
})
|
|
|
|
test('該標籤沒有對白時不注入', async () => {
|
|
const r = await buildInjection(deps(on, answer('greet')), 'x')
|
|
expect(r?.fn).toBe('greet')
|
|
expect(r?.text).toBeNull()
|
|
})
|
|
})
|