dsh-daughter 0.1.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -12
- package/bin/connector-token.mjs +78 -0
- package/config.yaml +141 -1
- package/dist/config.js +234 -4
- package/dist/host.d.ts +2 -0
- package/dist/host.js +241 -19
- package/dist/index.d.ts +2 -0
- package/dist/index.js +223 -19
- package/dist/runtime/connector-auth.d.ts +56 -0
- package/dist/runtime/connector-auth.js +148 -0
- package/dist/runtime/content.d.ts +11 -2
- package/dist/runtime/content.js +36 -6
- package/dist/runtime/desktop-input.d.ts +2 -0
- package/dist/runtime/desktop-input.js +3 -1
- package/dist/runtime/desktop-observe.d.ts +16 -0
- package/dist/runtime/desktop-observe.js +30 -8
- package/dist/runtime/douyin-link.d.ts +49 -0
- package/dist/runtime/douyin-link.js +102 -0
- package/dist/runtime/expression.d.ts +60 -0
- package/dist/runtime/expression.js +113 -0
- package/dist/runtime/filter.js +23 -0
- package/dist/runtime/maintenance.d.ts +0 -5
- package/dist/runtime/maintenance.js +59 -8
- package/dist/runtime/memory.d.ts +34 -2
- package/dist/runtime/memory.js +130 -18
- package/dist/runtime/motivation.d.ts +65 -0
- package/dist/runtime/motivation.js +282 -0
- package/dist/runtime/panels.js +34 -1
- package/dist/runtime/personality.js +3 -11
- package/dist/runtime/pet-link.d.ts +87 -0
- package/dist/runtime/pet-link.js +129 -0
- package/dist/runtime/reset.d.ts +40 -0
- package/dist/runtime/reset.js +253 -0
- package/dist/runtime/speak.d.ts +79 -0
- package/dist/runtime/speak.js +277 -0
- package/dist/runtime/state.js +66 -9
- package/dist/runtime/vpet-control.d.ts +2 -0
- package/dist/runtime/vpet-control.js +5 -3
- package/dist/store.d.ts +63 -1
- package/dist/store.js +233 -14
- package/dist/types.d.ts +253 -0
- package/dist/util.d.ts +10 -0
- package/dist/util.js +37 -0
- package/package.json +9 -2
package/dist/config.js
CHANGED
|
@@ -21,6 +21,9 @@ export const defaultConfig = {
|
|
|
21
21
|
link_proximity: 0.1,
|
|
22
22
|
},
|
|
23
23
|
min_score: 0.12,
|
|
24
|
+
min_semantic: 0.01,
|
|
25
|
+
reconstruct_distance: 0.08,
|
|
26
|
+
reconstruct_cooldown_minutes: 360,
|
|
24
27
|
expand_fulltext: true,
|
|
25
28
|
fulltext_excerpt_chars: 120,
|
|
26
29
|
},
|
|
@@ -28,6 +31,7 @@ export const defaultConfig = {
|
|
|
28
31
|
max_depth: 2,
|
|
29
32
|
max_injected: 2,
|
|
30
33
|
hop_decay: 0.6,
|
|
34
|
+
fallback_when_no_match: true,
|
|
31
35
|
},
|
|
32
36
|
skills: {
|
|
33
37
|
max_main: 1,
|
|
@@ -38,6 +42,66 @@ export const defaultConfig = {
|
|
|
38
42
|
min_associated_score: 0.15,
|
|
39
43
|
min_steps_to_learn: 2,
|
|
40
44
|
},
|
|
45
|
+
motivation: {
|
|
46
|
+
enabled: true,
|
|
47
|
+
trait_threshold_gain: 0.25,
|
|
48
|
+
min_threshold: 0.05,
|
|
49
|
+
trait_signal_gain: 0.2,
|
|
50
|
+
familiarity: { k: 3, peak: 0.45, sigma: 0.35 },
|
|
51
|
+
memory: {
|
|
52
|
+
outcome_weight: 0.4,
|
|
53
|
+
emotion_weight: 0.3,
|
|
54
|
+
efficacy_weight: 0.3,
|
|
55
|
+
half_life_days: 30,
|
|
56
|
+
lookback_days: 30,
|
|
57
|
+
},
|
|
58
|
+
breaker: { fail_streak: 3, base_cooldown_min: 10, max_cooldown_min: 1440 },
|
|
59
|
+
emotion_override: {
|
|
60
|
+
safety_low: 0.35,
|
|
61
|
+
safety_low_offset: 0.1,
|
|
62
|
+
stress_high: 0.7,
|
|
63
|
+
stress_high_offset: 0.08,
|
|
64
|
+
pleasure_low: -0.25,
|
|
65
|
+
pleasure_low_offset: 0.06,
|
|
66
|
+
arousal_high: 0.4,
|
|
67
|
+
arousal_high_offset: -0.05,
|
|
68
|
+
fatigue_high: 0.8,
|
|
69
|
+
fatigue_high_offset: 0.08,
|
|
70
|
+
clamp_min: -0.15,
|
|
71
|
+
clamp_max: 0.2,
|
|
72
|
+
},
|
|
73
|
+
situation: { min_multiplier: 0.85, max_multiplier: 1.15 },
|
|
74
|
+
hold_ratio: 0.7,
|
|
75
|
+
},
|
|
76
|
+
speak: {
|
|
77
|
+
// 默认关闭:主动开口是自主行为,必须显式开启,不能装完就自己说话
|
|
78
|
+
enabled: false,
|
|
79
|
+
check_interval_min: 3,
|
|
80
|
+
// 活跃档:安静 25 分钟就进入考虑区间,思念 2 小时就到半饱和。
|
|
81
|
+
// 早期 45/180/0.62 的组合在写代码的场景下要沉默四五个小时才开口,等于装了个哑巴。
|
|
82
|
+
min_idle_min: 25,
|
|
83
|
+
idle_half_min: 120,
|
|
84
|
+
trait_urge_gain: 1,
|
|
85
|
+
threshold: 0.52,
|
|
86
|
+
threshold_min: 0.4,
|
|
87
|
+
refractory_min: 60,
|
|
88
|
+
max_per_day: 8,
|
|
89
|
+
quiet_hours: [0, 7],
|
|
90
|
+
quiet_penalty: 0.35,
|
|
91
|
+
busy_penalty: 0.25,
|
|
92
|
+
hold_ratio: 0.75,
|
|
93
|
+
carry_step: 0.05,
|
|
94
|
+
carry_decay: 0.02,
|
|
95
|
+
carry_max: 0.25,
|
|
96
|
+
jitter: 0.04,
|
|
97
|
+
},
|
|
98
|
+
expression: {
|
|
99
|
+
enabled: true,
|
|
100
|
+
// 默认只发桌宠;要接别的应用,在 config.yaml 里加 pet / http / file 出口
|
|
101
|
+
sinks: [{ type: 'vpet' }],
|
|
102
|
+
// 出厂配置下若 dsh-pet 在跑,就让它接管,避免两套桌宠各弹一遍
|
|
103
|
+
prefer_pet: true,
|
|
104
|
+
},
|
|
41
105
|
reflex: {
|
|
42
106
|
enabled: true,
|
|
43
107
|
max_match_ms: 5,
|
|
@@ -74,6 +138,10 @@ export const defaultConfig = {
|
|
|
74
138
|
backend: 'sqlite',
|
|
75
139
|
single_writer: true,
|
|
76
140
|
},
|
|
141
|
+
security: {
|
|
142
|
+
// 留空 = 使用 brain/brainstem/connector_token;显式填写则固定用它(§12.2)
|
|
143
|
+
connector_token: '',
|
|
144
|
+
},
|
|
77
145
|
decay: {
|
|
78
146
|
weight_decay_rate: 0.02,
|
|
79
147
|
recall_boost: 0.05,
|
|
@@ -107,9 +175,18 @@ export const defaultConfig = {
|
|
|
107
175
|
evidence_cap: 200,
|
|
108
176
|
},
|
|
109
177
|
desktop: {
|
|
110
|
-
|
|
178
|
+
// 默认关闭(§12.2):桌面连接器能给的是屏幕画面与键鼠注入,
|
|
179
|
+
// 属于"开了就有风险"的能力,必须由用户显式打开。
|
|
180
|
+
enabled: false,
|
|
111
181
|
bridge_url: 'http://127.0.0.1:47614',
|
|
112
182
|
},
|
|
183
|
+
douyin: {
|
|
184
|
+
enabled: true,
|
|
185
|
+
// 抖音插件的共享记忆库(QQ/抖音共用的那份),只读
|
|
186
|
+
memory_db: '~/.dsh/douyin-browser/memory/shared.sqlite',
|
|
187
|
+
poll_interval_min: 10,
|
|
188
|
+
max_items: 5,
|
|
189
|
+
},
|
|
113
190
|
filter: {
|
|
114
191
|
enabled: true,
|
|
115
192
|
source_weights: {
|
|
@@ -124,6 +201,7 @@ export const defaultConfig = {
|
|
|
124
201
|
},
|
|
125
202
|
shield: { sources: [], keywords: [], patterns: [] },
|
|
126
203
|
habituation: { window_minutes: 30, max_repeat: 3 },
|
|
204
|
+
burst: { window_minutes: 60, max_keep: 3, exempt_sources: ['chat', 'qq', 'douyin_dm'] },
|
|
127
205
|
salience: { drop_below: 0.2 },
|
|
128
206
|
forget: { enabled: true, idle_days: 30, min_salience: 0.2 },
|
|
129
207
|
},
|
|
@@ -189,9 +267,6 @@ function warnUnsupported(config, logger) {
|
|
|
189
267
|
backend: config.storage.backend,
|
|
190
268
|
});
|
|
191
269
|
}
|
|
192
|
-
if (config.desktop.enabled) {
|
|
193
|
-
logger.warn('dsh-daughter: desktop.enabled=true,但桌面端能力尚未实现(§14 里程碑 P9),配置值已忽略');
|
|
194
|
-
}
|
|
195
270
|
if (!config.safety.diagnosis_labels_forbidden) {
|
|
196
271
|
logger.warn('dsh-daughter: diagnosis_labels_forbidden=false,输出侧诊断词检查已关闭(不建议)');
|
|
197
272
|
}
|
|
@@ -217,6 +292,10 @@ function mergeDeep(base, override) {
|
|
|
217
292
|
}
|
|
218
293
|
function normalizeConfig(config) {
|
|
219
294
|
config.retrieval.top_k = Math.max(1, Math.round(num(config.retrieval.top_k, 5)));
|
|
295
|
+
config.retrieval.min_semantic = clampUnit(num(config.retrieval.min_semantic, 0.01), 0.01);
|
|
296
|
+
// 回看感受的触发距离:0 会让每次召回都写一条,1 等于永不写,两端都无意义
|
|
297
|
+
config.retrieval.reconstruct_distance = Math.min(0.5, clampUnit(num(config.retrieval.reconstruct_distance, 0.08), 0.08));
|
|
298
|
+
config.retrieval.reconstruct_cooldown_minutes = Math.min(1440, Math.max(0, Math.round(num(config.retrieval.reconstruct_cooldown_minutes, 360))));
|
|
220
299
|
// 打分权重归一化到和为 1:min_score 是绝对门限,权重整体放大 3 倍会让召回条数
|
|
221
300
|
// 静默变化,不归一化等于把两个无关参数耦合在一起
|
|
222
301
|
const weights = config.retrieval.score_weights;
|
|
@@ -236,7 +315,140 @@ function normalizeConfig(config) {
|
|
|
236
315
|
config.retrieval.expand_fulltext = config.retrieval.expand_fulltext !== false;
|
|
237
316
|
config.retrieval.fulltext_excerpt_chars = Math.min(400, Math.max(40, Math.round(num(config.retrieval.fulltext_excerpt_chars, 120))));
|
|
238
317
|
config.skills.min_steps_to_learn = Math.min(8, Math.max(2, Math.round(num(config.skills.min_steps_to_learn, 2))));
|
|
318
|
+
if (!config.motivation || typeof config.motivation !== 'object') {
|
|
319
|
+
config.motivation = structuredClone(defaultConfig.motivation);
|
|
320
|
+
}
|
|
321
|
+
const motivation = config.motivation;
|
|
322
|
+
const defaults = defaultConfig.motivation;
|
|
323
|
+
motivation.familiarity ??= { ...defaults.familiarity };
|
|
324
|
+
motivation.memory ??= { ...defaults.memory };
|
|
325
|
+
motivation.breaker ??= { ...defaults.breaker };
|
|
326
|
+
motivation.emotion_override ??= { ...defaults.emotion_override };
|
|
327
|
+
motivation.situation ??= { ...defaults.situation };
|
|
328
|
+
motivation.enabled = motivation.enabled !== false;
|
|
329
|
+
motivation.trait_threshold_gain = clampUnit(motivation.trait_threshold_gain, 0.25);
|
|
330
|
+
// 下限不能超过基础阈值,否则 skill 永远不可能 act
|
|
331
|
+
motivation.min_threshold = clampRange(motivation.min_threshold, 0, Math.max(0, Math.min(0.5, config.skills.min_main_score)), defaults.min_threshold);
|
|
332
|
+
// 上限 0.9:乘子最低留 0.1,避免人格把某个通道直接归零
|
|
333
|
+
motivation.trait_signal_gain = clampRange(motivation.trait_signal_gain, 0, 0.9, defaults.trait_signal_gain);
|
|
334
|
+
motivation.familiarity.k = Math.max(1, num(motivation.familiarity.k, 3));
|
|
335
|
+
motivation.familiarity.peak = clampUnit(motivation.familiarity.peak, 0.45);
|
|
336
|
+
motivation.familiarity.sigma = clampRange(motivation.familiarity.sigma, 0.05, 1, 0.35);
|
|
337
|
+
const memory = motivation.memory;
|
|
338
|
+
const memoryKeys = ['outcome_weight', 'emotion_weight', 'efficacy_weight'];
|
|
339
|
+
let memorySum = 0;
|
|
340
|
+
for (const key of memoryKeys) {
|
|
341
|
+
memory[key] = Math.max(0, num(memory[key], defaultConfig.motivation.memory[key]));
|
|
342
|
+
memorySum += memory[key];
|
|
343
|
+
}
|
|
344
|
+
if (!(memorySum > 0)) {
|
|
345
|
+
Object.assign(memory, defaultConfig.motivation.memory);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
for (const key of memoryKeys)
|
|
349
|
+
memory[key] = Number((memory[key] / memorySum).toFixed(4));
|
|
350
|
+
}
|
|
351
|
+
memory.half_life_days = clampRange(memory.half_life_days, 0.1, 3650, 30);
|
|
352
|
+
memory.lookback_days = Math.min(3650, Math.max(1, Math.round(num(memory.lookback_days, 30))));
|
|
353
|
+
const breaker = motivation.breaker;
|
|
354
|
+
breaker.fail_streak = Math.min(20, Math.max(1, Math.round(num(breaker.fail_streak, 3))));
|
|
355
|
+
breaker.base_cooldown_min = clampRange(breaker.base_cooldown_min, 0, 1440, 10);
|
|
356
|
+
breaker.max_cooldown_min = clampRange(breaker.max_cooldown_min, breaker.base_cooldown_min, 10080, 1440);
|
|
357
|
+
const override = motivation.emotion_override;
|
|
358
|
+
override.safety_low = clampUnit(override.safety_low, 0.35);
|
|
359
|
+
override.safety_low_offset = clampRange(override.safety_low_offset, -0.5, 0.5, 0.1);
|
|
360
|
+
override.stress_high = clampUnit(override.stress_high, 0.7);
|
|
361
|
+
override.stress_high_offset = clampRange(override.stress_high_offset, -0.5, 0.5, 0.08);
|
|
362
|
+
override.pleasure_low = clampRange(override.pleasure_low, -1, 1, -0.25);
|
|
363
|
+
override.pleasure_low_offset = clampRange(override.pleasure_low_offset, -0.5, 0.5, 0.06);
|
|
364
|
+
override.arousal_high = clampRange(override.arousal_high, -1, 1, 0.4);
|
|
365
|
+
override.arousal_high_offset = clampRange(override.arousal_high_offset, -0.5, 0.5, -0.05);
|
|
366
|
+
override.fatigue_high = clampUnit(override.fatigue_high, 0.8);
|
|
367
|
+
override.fatigue_high_offset = clampRange(override.fatigue_high_offset, -0.5, 0.5, 0.08);
|
|
368
|
+
override.clamp_min = clampRange(override.clamp_min, -0.5, 0.5, -0.15);
|
|
369
|
+
override.clamp_max = clampRange(override.clamp_max, override.clamp_min, 0.5, 0.2);
|
|
370
|
+
motivation.situation.min_multiplier = clampRange(motivation.situation.min_multiplier, 0.5, 2, 0.85);
|
|
371
|
+
motivation.situation.max_multiplier = clampRange(motivation.situation.max_multiplier, motivation.situation.min_multiplier, 2, 1.15);
|
|
372
|
+
motivation.hold_ratio = clampUnit(motivation.hold_ratio, 0.7);
|
|
373
|
+
if (!config.speak || typeof config.speak !== 'object') {
|
|
374
|
+
config.speak = structuredClone(defaultConfig.speak);
|
|
375
|
+
}
|
|
376
|
+
const speak = config.speak;
|
|
377
|
+
speak.enabled = speak.enabled !== false;
|
|
378
|
+
speak.check_interval_min = clampRange(speak.check_interval_min, 1, 120, 3);
|
|
379
|
+
speak.min_idle_min = clampRange(speak.min_idle_min, 1, 2880, 25);
|
|
380
|
+
speak.idle_half_min = clampRange(speak.idle_half_min, 5, 2880, 120);
|
|
381
|
+
speak.trait_urge_gain = clampRange(speak.trait_urge_gain, 0, 2, 1);
|
|
382
|
+
speak.threshold = clampRange(speak.threshold, 0.1, 1, 0.52);
|
|
383
|
+
// 下限不能高于基础阈值,否则等于把门槛整体抬高
|
|
384
|
+
speak.threshold_min = clampRange(speak.threshold_min, 0, speak.threshold, 0.4);
|
|
385
|
+
speak.refractory_min = clampRange(speak.refractory_min, 0, 10080, 60);
|
|
386
|
+
speak.max_per_day = Math.min(48, Math.max(0, Math.round(num(speak.max_per_day, 8))));
|
|
387
|
+
speak.quiet_penalty = clampRange(speak.quiet_penalty, 0, 1, 0.35);
|
|
388
|
+
// 会议/游戏仍然要能拦住:这个系数调小,长时间沉默会连开会都敢插话
|
|
389
|
+
speak.busy_penalty = clampRange(speak.busy_penalty, 0, 1, 0.25);
|
|
390
|
+
speak.hold_ratio = clampRange(speak.hold_ratio, 0.1, 1, 0.75);
|
|
391
|
+
speak.carry_step = clampRange(speak.carry_step, 0, 0.5, 0.05);
|
|
392
|
+
speak.carry_decay = clampRange(speak.carry_decay, 0, 0.5, 0.02);
|
|
393
|
+
speak.carry_max = clampRange(speak.carry_max, 0, 1, 0.25);
|
|
394
|
+
speak.jitter = clampRange(speak.jitter, 0, 0.3, 0.04);
|
|
395
|
+
// 安静时段:YAML 可能写成字符串或只有一个值,统一收敛成 [起, 止)
|
|
396
|
+
const quietRaw = Array.isArray(speak.quiet_hours) ? speak.quiet_hours : defaultConfig.speak.quiet_hours;
|
|
397
|
+
const quietStart = Math.min(23, Math.max(0, Math.round(num(quietRaw[0], 0))));
|
|
398
|
+
const quietEnd = Math.min(24, Math.max(0, Math.round(num(quietRaw[1], 7))));
|
|
399
|
+
speak.quiet_hours = [quietStart, quietEnd];
|
|
400
|
+
if (!config.expression || typeof config.expression !== 'object') {
|
|
401
|
+
config.expression = structuredClone(defaultConfig.expression);
|
|
402
|
+
}
|
|
403
|
+
const expression = config.expression;
|
|
404
|
+
expression.enabled = expression.enabled !== false;
|
|
405
|
+
expression.prefer_pet = expression.prefer_pet !== false;
|
|
406
|
+
const rawSinks = Array.isArray(expression.sinks) ? expression.sinks : [];
|
|
407
|
+
const sinks = [];
|
|
408
|
+
for (const item of rawSinks) {
|
|
409
|
+
if (!item || typeof item !== 'object')
|
|
410
|
+
continue;
|
|
411
|
+
const type = String(item.type ?? '');
|
|
412
|
+
if (type === 'vpet') {
|
|
413
|
+
sinks.push({ type: 'vpet' });
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (type === 'http') {
|
|
417
|
+
const url = typeof item.url === 'string' ? item.url.trim() : '';
|
|
418
|
+
if (!url)
|
|
419
|
+
continue;
|
|
420
|
+
sinks.push({ type: 'http', url, timeout_ms: clampRange(item.timeout_ms, 200, 30000, 3000) });
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if (type === 'pet') {
|
|
424
|
+
// url 可省略:缺省由宿主在运行时用自己监听的端口拼出来,省得用户抄端口
|
|
425
|
+
const url = typeof item.url === 'string' ? item.url.trim() : '';
|
|
426
|
+
const petId = typeof item.pet === 'string' ? item.pet.trim() : '';
|
|
427
|
+
const route = typeof item.route === 'string' ? item.route.trim() : '';
|
|
428
|
+
sinks.push({
|
|
429
|
+
type: 'pet',
|
|
430
|
+
...(url ? { url } : {}),
|
|
431
|
+
...(petId ? { pet: petId } : {}),
|
|
432
|
+
...(route ? { route } : {}),
|
|
433
|
+
timeout_ms: clampRange(item.timeout_ms, 200, 30000, 3000),
|
|
434
|
+
// 0 是合法值(只要动作不要文字),所以下限放 0
|
|
435
|
+
duration_ms: clampRange(item.duration_ms, 0, 60000, 10000),
|
|
436
|
+
});
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
if (type === 'file') {
|
|
440
|
+
const path = typeof item.path === 'string' ? item.path.trim() : '';
|
|
441
|
+
if (!path)
|
|
442
|
+
continue;
|
|
443
|
+
sinks.push({ type: 'file', path });
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
// 未知 type 静默丢弃,配置手滑不该拖垮整个插件
|
|
447
|
+
}
|
|
448
|
+
// 一个都没配成时退回桌宠:宁可只到气泡,也不要静默丢消息
|
|
449
|
+
expression.sinks = sinks.length > 0 ? sinks : [{ type: 'vpet' }];
|
|
239
450
|
config.association.max_depth = Math.min(3, Math.max(1, Math.round(num(config.association.max_depth, 2))));
|
|
451
|
+
config.association.fallback_when_no_match = config.association.fallback_when_no_match !== false;
|
|
240
452
|
config.budget.max_total_tokens = Math.max(200, Math.round(num(config.budget.max_total_tokens, 3000)));
|
|
241
453
|
config.safety.thresholds.stress_level1 = num(config.safety.thresholds.stress_level1, 0.7);
|
|
242
454
|
config.safety.thresholds.safety_level2 = num(config.safety.thresholds.safety_level2, 0.35);
|
|
@@ -247,6 +459,10 @@ function normalizeConfig(config) {
|
|
|
247
459
|
const filter = config.filter;
|
|
248
460
|
filter.habituation.window_minutes = Math.min(1440, Math.max(1, Math.round(num(filter.habituation.window_minutes, 30))));
|
|
249
461
|
filter.habituation.max_repeat = Math.min(20, Math.max(1, Math.round(num(filter.habituation.max_repeat, 3))));
|
|
462
|
+
filter.burst.window_minutes = Math.min(1440, Math.max(1, Math.round(num(filter.burst.window_minutes, 60))));
|
|
463
|
+
filter.burst.max_keep = Math.min(20, Math.max(1, Math.round(num(filter.burst.max_keep, 3))));
|
|
464
|
+
filter.burst.exempt_sources = (Array.isArray(filter.burst.exempt_sources) ? filter.burst.exempt_sources : [])
|
|
465
|
+
.filter((source) => typeof source === 'string' && source.length > 0);
|
|
250
466
|
filter.salience.drop_below = clampUnit(filter.salience.drop_below, 0.2);
|
|
251
467
|
filter.forget.idle_days = Math.min(3650, Math.max(1, Math.round(num(filter.forget.idle_days, 30))));
|
|
252
468
|
filter.forget.min_salience = clampUnit(filter.forget.min_salience, 0.2);
|
|
@@ -265,6 +481,17 @@ function normalizeConfig(config) {
|
|
|
265
481
|
bodyLink.fatigue_weight = clampUnit(bodyLink.fatigue_weight, 0.5);
|
|
266
482
|
bodyLink.stress_weight = clampUnit(bodyLink.stress_weight, 0.3);
|
|
267
483
|
bodyLink.max_influence = clampUnit(bodyLink.max_influence, 0.6);
|
|
484
|
+
const douyin = config.douyin;
|
|
485
|
+
douyin.enabled = douyin.enabled !== false;
|
|
486
|
+
douyin.memory_db = typeof douyin.memory_db === 'string' ? douyin.memory_db.trim() : '';
|
|
487
|
+
// 1 分钟一次已经比自己刷得还勤,再快只是空读;上限一天一次的量级足够追平
|
|
488
|
+
douyin.poll_interval_min = Math.min(1440, Math.max(1, Math.round(num(douyin.poll_interval_min, 10))));
|
|
489
|
+
douyin.max_items = Math.min(20, Math.max(1, Math.round(num(douyin.max_items, 5))));
|
|
490
|
+
// 连接器认证(§12.2):空字符串表示"用文件令牌",过短的显式令牌在运行时会被忽略并告警
|
|
491
|
+
config.security ??= { connector_token: '' };
|
|
492
|
+
config.security.connector_token = String(config.security.connector_token ?? '').trim();
|
|
493
|
+
config.desktop.enabled = config.desktop.enabled === true;
|
|
494
|
+
config.desktop.bridge_url = String(config.desktop.bridge_url ?? '').trim() || 'http://127.0.0.1:47614';
|
|
268
495
|
return config;
|
|
269
496
|
}
|
|
270
497
|
function num(value, fallback) {
|
|
@@ -274,3 +501,6 @@ function clampUnit(value, fallback) {
|
|
|
274
501
|
const number = num(value, fallback);
|
|
275
502
|
return Math.min(1, Math.max(0, number));
|
|
276
503
|
}
|
|
504
|
+
function clampRange(value, min, max, fallback) {
|
|
505
|
+
return Math.min(max, Math.max(min, num(value, fallback)));
|
|
506
|
+
}
|
package/dist/host.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ interface HostCtx {
|
|
|
11
11
|
effect(fn: () => (() => void) | void, label?: string): () => void;
|
|
12
12
|
emit?(name: string, payload: unknown): void;
|
|
13
13
|
webServer?: {
|
|
14
|
+
/** 宿主实际监听的端口(配置写 0 时由系统分配),dsh-pet 出口靠它拼本机地址 */
|
|
15
|
+
port?: number;
|
|
14
16
|
register(route: {
|
|
15
17
|
kind: 'exact' | 'prefix';
|
|
16
18
|
path: string;
|