fake.js
2.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
* 测试用假实现(§3 可选导出)。
*
* 让调用方在**无网络**下单测全部判定路径(含降级、合并、block 阻断)——验收 8。
* `createFakeRules` 给一份可注入的规则数据;`createFakeGuardPort` 给一个脚本化的
* LLM 护栏 Port。词表本身由调用方在测试里给(seed),本文件不内置任何真实词表
* (包内 grep 不到硬编码词表——验收 7)。
*/
/**
* 造一份可注入的规则。所有内容来自 `seed`,无内置词表。
*
* @param {object} [seed]
* @param {string[]} [seed.words] 敏感词表(测试自定义)
* @param {number} [seed.lengthMin]
* @param {number} [seed.lengthMax]
* @param {import('./rules-check.js').FormatRule[]} [seed.formatRules]
* @param {Record<string, object>} [seed.policies] 二期 policy 覆盖(一期默认不报错)
* @returns {import('./rules-check.js').Rules}
*/
export function createFakeRules(seed = {}) {
/** @type {import('./rules-check.js').Rules} */
const rules = {
words: Array.isArray(seed.words) ? [...seed.words] : [],
formatRules: Array.isArray(seed.formatRules) ? [...seed.formatRules] : [],
}
if (typeof seed.lengthMin === 'number') rules.lengthMin = seed.lengthMin
if (typeof seed.lengthMax === 'number') rules.lengthMax = seed.lengthMax
if (seed.policies && typeof seed.policies === 'object') rules.policies = seed.policies
return rules
}
/**
* 造一个脚本化的 LLM 护栏 Port,覆盖 unsafe / safe / 抛错 / 动态响应路径。
*
* @param {object} [scripted]
* @param {boolean} [scripted.unsafe] 固定返回的 unsafe 标志
* @param {string[]} [scripted.categories] 固定返回的基础安全类目
* @param {string[]} [scripted.reasons] 固定返回的原因
* @param {Error} [scripted.throws] 若提供,则每次 classify 直接抛它
* @param {(args:{text:string,context?:any,region?:string}) =>
* ({categories?:string[],unsafe?:boolean,reasons?:string[]}|undefined)} [scripted.respond]
* 动态响应钩子,优先于固定值;返回 undefined 视为 safe 空结果
* @returns {{ classify:(args:any) => Promise<any>, calls: any[] }}
*/
export function createFakeGuardPort(scripted = {}) {
/** @type {any[]} */
const calls = []
return {
calls,
async classify(args) {
calls.push(args)
if (scripted.throws) throw scripted.throws
if (typeof scripted.respond === 'function') {
const r = scripted.respond(args)
return {
categories: (r && r.categories) || [],
unsafe: Boolean(r && r.unsafe),
reasons: (r && r.reasons) || [],
}
}
return {
categories: Array.isArray(scripted.categories) ? scripted.categories : [],
unsafe: Boolean(scripted.unsafe),
reasons: Array.isArray(scripted.reasons) ? scripted.reasons : [],
}
},
}
}