@zooique/memora 0.3.0 → 1.0.1
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 +5 -5
- package/dist/agent/agent.d.ts +13 -3
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +15 -0
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/assembler.d.ts +3 -0
- package/dist/agent/assembler.d.ts.map +1 -1
- package/dist/agent/assembler.js +11 -2
- package/dist/agent/assembler.js.map +1 -1
- package/dist/agent/guardrail.d.ts +47 -0
- package/dist/agent/guardrail.d.ts.map +1 -0
- package/dist/agent/guardrail.js +51 -0
- package/dist/agent/guardrail.js.map +1 -0
- package/dist/agent/loop.d.ts +0 -17
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +16 -56
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/managers/insightExtractor.d.ts +10 -73
- package/dist/agent/managers/insightExtractor.d.ts.map +1 -1
- package/dist/agent/managers/insightExtractor.js +27 -154
- package/dist/agent/managers/insightExtractor.js.map +1 -1
- package/dist/agent/managers/memoryInspector.d.ts +14 -56
- package/dist/agent/managers/memoryInspector.d.ts.map +1 -1
- package/dist/agent/managers/memoryInspector.js +7 -75
- package/dist/agent/managers/memoryInspector.js.map +1 -1
- package/dist/agent/managers/memoryMutator.d.ts +92 -0
- package/dist/agent/managers/memoryMutator.d.ts.map +1 -0
- package/dist/agent/managers/memoryMutator.js +94 -0
- package/dist/agent/managers/memoryMutator.js.map +1 -0
- package/dist/agent/managers/relationBuilder.d.ts +131 -0
- package/dist/agent/managers/relationBuilder.d.ts.map +1 -0
- package/dist/agent/managers/relationBuilder.js +191 -0
- package/dist/agent/managers/relationBuilder.js.map +1 -0
- package/dist/agent/types.d.ts +8 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/config/loader.d.ts +48 -36
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +29 -31
- package/dist/config/loader.js.map +1 -1
- package/dist/eval/evalTypes.d.ts +15 -6
- package/dist/eval/evalTypes.d.ts.map +1 -1
- package/dist/eval/evalTypes.js +3 -2
- package/dist/eval/evalTypes.js.map +1 -1
- package/dist/index.d.ts +14 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/dist/llm/embedding.d.ts +18 -2
- package/dist/llm/embedding.d.ts.map +1 -1
- package/dist/llm/embedding.js +78 -46
- package/dist/llm/embedding.js.map +1 -1
- package/dist/llm/factory.js +1 -1
- package/dist/llm/factory.js.map +1 -1
- package/dist/llm/openaiCompatible.d.ts.map +1 -1
- package/dist/llm/openaiCompatible.js +11 -2
- package/dist/llm/openaiCompatible.js.map +1 -1
- package/dist/llm/provider.d.ts +0 -14
- package/dist/llm/provider.d.ts.map +1 -1
- package/dist/llm/provider.js.map +1 -1
- package/dist/logging/logger.d.ts +1 -0
- package/dist/logging/logger.d.ts.map +1 -1
- package/dist/logging/logger.js +43 -37
- package/dist/logging/logger.js.map +1 -1
- package/dist/memory/inMemoryStorage.js +1 -1
- package/dist/memory/inMemoryStorage.js.map +1 -1
- package/dist/memory/lockManager.d.ts +48 -0
- package/dist/memory/lockManager.d.ts.map +1 -0
- package/dist/memory/lockManager.js +167 -0
- package/dist/memory/lockManager.js.map +1 -0
- package/dist/memory/projectManager.d.ts +23 -53
- package/dist/memory/projectManager.d.ts.map +1 -1
- package/dist/memory/projectManager.js +47 -228
- package/dist/memory/projectManager.js.map +1 -1
- package/dist/memory/projectRegistry.d.ts +62 -0
- package/dist/memory/projectRegistry.d.ts.map +1 -0
- package/dist/memory/projectRegistry.js +166 -0
- package/dist/memory/projectRegistry.js.map +1 -0
- package/dist/memory/recall.d.ts +3 -3
- package/dist/memory/recall.d.ts.map +1 -1
- package/dist/memory/recall.js +2 -2
- package/dist/memory/recall.js.map +1 -1
- package/dist/memory/sourceValidation.d.ts +43 -0
- package/dist/memory/sourceValidation.d.ts.map +1 -0
- package/dist/memory/sourceValidation.js +139 -0
- package/dist/memory/sourceValidation.js.map +1 -0
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +2 -1
- package/dist/memory/store.js.map +1 -1
- package/dist/memory/types.d.ts +0 -47
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/memory/types.js +0 -138
- package/dist/memory/types.js.map +1 -1
- package/dist/memory/vectorStore.d.ts +68 -7
- package/dist/memory/vectorStore.d.ts.map +1 -1
- package/dist/memory/vectorStore.js +12 -8
- package/dist/memory/vectorStore.js.map +1 -1
- package/dist/security/pathGuard.d.ts.map +1 -1
- package/dist/security/pathGuard.js +3 -1
- package/dist/security/pathGuard.js.map +1 -1
- package/dist/utils/segmenter.d.ts +6 -0
- package/dist/utils/segmenter.d.ts.map +1 -1
- package/dist/utils/segmenter.js +13 -0
- package/dist/utils/segmenter.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 关系构建器 — ADR-014 记忆关系构建的专职 Manager
|
|
3
|
+
*
|
|
4
|
+
* 从 InsightExtractor 拆分出来(P1-3),负责:
|
|
5
|
+
* - 召回关系判断候选记忆(top-5 关键词搜索)
|
|
6
|
+
* - 构建关系判断 prompt 片段(候选列表 + 关系类型说明)
|
|
7
|
+
* - 解析 LLM 输出的 relations 字段并写入 IMemoryRelationStore
|
|
8
|
+
* - contradicts 关系检测 + onConflict 回调通知
|
|
9
|
+
*
|
|
10
|
+
* 设计原则:
|
|
11
|
+
* - 独立于 InsightExtractor 生命周期,仅依赖 IMemoryStorage + IMemoryRelationStore
|
|
12
|
+
* - 静默降级——relationStore 未注入时所有方法返回空/no-op(ADR-014 降级优先)
|
|
13
|
+
* - 薄层代理——关系写入直接透传到 IMemoryRelationStore,仅增加 weight 推断 + targetId 校验
|
|
14
|
+
*
|
|
15
|
+
* 与 InsightExtractor 的分工(P1-3 拆分,1.0 接口稳定化):
|
|
16
|
+
* - InsightExtractor:insight 提取 + 去重 + 写入 + 输入分类
|
|
17
|
+
* - RelationBuilder:候选召回 + prompt 构建 + 关系写入 + 冲突检测
|
|
18
|
+
*
|
|
19
|
+
* 详见 ADR-014(记忆关系侧车模型)+ 迭代文档 P1-3
|
|
20
|
+
*/
|
|
21
|
+
import type { Memory } from '../../memory/types.js';
|
|
22
|
+
import type { IMemoryStorage } from '../../memory/storageInterface.js';
|
|
23
|
+
import type { IMemoryRelationStore } from '../../memory/relationStore.js';
|
|
24
|
+
/**
|
|
25
|
+
* 冲突信息(contradicts 关系检测到时传递给宿主)
|
|
26
|
+
*
|
|
27
|
+
* 由 RelationBuilder.buildRelations 检测到 contradicts 关系时构造,
|
|
28
|
+
* 通过 onConflict 回调传递给 Agent,Agent emit('conflictDetected') 通知宿主。
|
|
29
|
+
*/
|
|
30
|
+
export interface ConflictInfo {
|
|
31
|
+
/** 新写入的 insight 记忆 ID */
|
|
32
|
+
newMemoryId: string;
|
|
33
|
+
/** 新洞察内容(用于 UI 展示) */
|
|
34
|
+
newInsight: string;
|
|
35
|
+
/** 被矛盾的已有记忆 ID */
|
|
36
|
+
targetId: string;
|
|
37
|
+
/** 被矛盾的已有记忆内容(用于 UI 展示) */
|
|
38
|
+
targetContent: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 关系构建器
|
|
42
|
+
*
|
|
43
|
+
* 封装 ADR-014 记忆关系构建的全部逻辑,从 InsightExtractor 拆分(P1-3)。
|
|
44
|
+
* relationStore 未注入时所有方法静默降级(返回空/no-op)。
|
|
45
|
+
*/
|
|
46
|
+
export declare class RelationBuilder {
|
|
47
|
+
private readonly index;
|
|
48
|
+
private readonly relationStore;
|
|
49
|
+
/** 冲突检测回调(由 Agent 通过 bindOnConflict 注入,检测到 contradicts 时触发) */
|
|
50
|
+
private onConflict;
|
|
51
|
+
/**
|
|
52
|
+
* @param index 记忆存储(用于候选召回的关键词搜索)
|
|
53
|
+
* @param relationStore 记忆关系存储(可选,未注入时所有方法静默降级)
|
|
54
|
+
*/
|
|
55
|
+
constructor(index: IMemoryStorage, relationStore?: IMemoryRelationStore | null);
|
|
56
|
+
/** 关系构建是否启用(relationStore 已注入时为 true) */
|
|
57
|
+
get enabled(): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* 绑定冲突检测回调
|
|
60
|
+
*
|
|
61
|
+
* 由 Agent.init() 在创建 InsightExtractor 后调用(与 bindGetRecentHistory 同模式),
|
|
62
|
+
* 解决 Agent 实例晚于 InsightExtractor 创建的时序循环依赖。
|
|
63
|
+
* buildRelations 检测到 contradicts 关系时调用此回调,Agent 在回调中 emit('conflictDetected')。
|
|
64
|
+
*
|
|
65
|
+
* @param fn 冲突检测回调(传入 null 可解除绑定)
|
|
66
|
+
*/
|
|
67
|
+
bindOnConflict(fn: ((info: ConflictInfo) => void) | null): void;
|
|
68
|
+
/**
|
|
69
|
+
* 召回关系判断候选记忆(top-5)
|
|
70
|
+
*
|
|
71
|
+
* 用用户输入关键词搜索已有记忆,作为 LLM 关系判断的参考。
|
|
72
|
+
* 用户输入与提取出的 insight 通常相关,候选记忆也相关。
|
|
73
|
+
* relationStore 未注入时返回空数组(降级)。
|
|
74
|
+
*
|
|
75
|
+
* @param userInput 用户输入(用于关键词搜索)
|
|
76
|
+
* @returns 候选记忆列表(id + content 截断)
|
|
77
|
+
*/
|
|
78
|
+
recallRelationCandidates(userInput: string): Memory[];
|
|
79
|
+
/**
|
|
80
|
+
* 构建候选记忆列表的 prompt 片段
|
|
81
|
+
*
|
|
82
|
+
* 格式:
|
|
83
|
+
* 已有记忆(供关系判断参考):
|
|
84
|
+
* [1] id: xxx, content: xxx
|
|
85
|
+
* [2] id: xxx, content: xxx
|
|
86
|
+
*
|
|
87
|
+
* @param candidates 候选记忆列表
|
|
88
|
+
* @returns prompt 片段(空候选时返回空字符串)
|
|
89
|
+
*/
|
|
90
|
+
buildCandidatesPrompt(candidates: Memory[]): string;
|
|
91
|
+
/**
|
|
92
|
+
* 构建关系判断的 prompt 指令片段
|
|
93
|
+
*
|
|
94
|
+
* 包含 relations 字段格式说明 + 关系类型说明 + 注意事项。
|
|
95
|
+
* relationStore 未注入时返回空字符串(降级,不影响 insight 提取主流程)。
|
|
96
|
+
*
|
|
97
|
+
* @returns prompt 指令片段(relationStore 未注入时为空字符串)
|
|
98
|
+
*/
|
|
99
|
+
buildRelationsPrompt(): string;
|
|
100
|
+
/**
|
|
101
|
+
* 构建关系(写入 IMemoryRelationStore)
|
|
102
|
+
*
|
|
103
|
+
* 解析 LLM 输出的 relations 字段,验证 targetId 在候选列表中,写入关系存储。
|
|
104
|
+
* 降级策略:relationStore 未注入/relations 为空/targetId 无效 → 跳过,不阻塞主流程。
|
|
105
|
+
*
|
|
106
|
+
* 检测到 contradicts 关系时,通过 onConflict 回调通知 Agent,
|
|
107
|
+
* Agent emit('conflictDetected') 触发宿主消费链路(ProactiveBanner 通知用户)。
|
|
108
|
+
*
|
|
109
|
+
* @param insightId 新写入的 insight ID
|
|
110
|
+
* @param insightContent 新写入的 insight 内容(用于冲突通知 UI 展示)
|
|
111
|
+
* @param relations LLM 输出的关系列表
|
|
112
|
+
* @param candidates 候选记忆列表(用于验证 targetId + 查找 targetContent)
|
|
113
|
+
*/
|
|
114
|
+
buildRelations(insightId: string, insightContent: string, relations: Array<{
|
|
115
|
+
targetId?: unknown;
|
|
116
|
+
type?: unknown;
|
|
117
|
+
}>, candidates: Memory[]): void;
|
|
118
|
+
/**
|
|
119
|
+
* 根据关系类型推断 weight(ADR-014 §4)
|
|
120
|
+
*
|
|
121
|
+
* LLM 只输出 type,weight 由代码层推断:
|
|
122
|
+
* - contradicts → 1.0(确定关系,矛盾是强关系)
|
|
123
|
+
* - supports/follows/refines/caused → 0.7(强相关)
|
|
124
|
+
* - related → 0.3(弱相关)
|
|
125
|
+
* - 未知类型 → 0.5(未判断兜底)
|
|
126
|
+
*
|
|
127
|
+
* 设计理由:降低 LLM 认知负担,离散值比连续浮点稳定
|
|
128
|
+
*/
|
|
129
|
+
private weightByType;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=relationBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationBuilder.d.ts","sourceRoot":"","sources":["../../../src/agent/managers/relationBuilder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AActE;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,aAAa,EAAE,MAAM,CAAC;CACvB;AAID;;;;;GAKG;AACH,qBAAa,eAAe;IASxB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAThC,+DAA+D;IAC/D,OAAO,CAAC,UAAU,CAA+C;IAEjE;;;OAGG;gBAEgB,KAAK,EAAE,cAAc,EACrB,aAAa,GAAE,oBAAoB,GAAG,IAAW;IAGpE,yCAAyC;IACzC,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI;IAM/D;;;;;;;;;OASG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;IAMrD;;;;;;;;;;OAUG;IACH,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM;IAWnD;;;;;;;OAOG;IACH,oBAAoB,IAAI,MAAM;IAqB9B;;;;;;;;;;;;;OAaG;IACH,cAAc,CACZ,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,KAAK,CAAC;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,EACxD,UAAU,EAAE,MAAM,EAAE,GACnB,IAAI;IA4CP;;;;;;;;;;OAUG;IACH,OAAO,CAAC,YAAY;CAYrB"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { RELATION_WEIGHTS } from '../../memory/types.js';
|
|
2
|
+
import { escapeLike } from '../../memory/sourceValidation.js';
|
|
3
|
+
import { logger } from '../../logging/logger.js';
|
|
4
|
+
import { nowIso } from '../../utils/time.js';
|
|
5
|
+
// ─── 常量 ────────────────────────────────────────────────
|
|
6
|
+
/** 关系判断:召回候选记忆数量上限(top-5) */
|
|
7
|
+
const RELATION_CANDIDATE_LIMIT = 5;
|
|
8
|
+
/** 关系判断:候选记忆 content 注入 prompt 的截断上限(字符) */
|
|
9
|
+
const RELATION_CANDIDATE_CONTENT_LIMIT = 100;
|
|
10
|
+
// ─── 类 ──────────────────────────────────────────────────
|
|
11
|
+
/**
|
|
12
|
+
* 关系构建器
|
|
13
|
+
*
|
|
14
|
+
* 封装 ADR-014 记忆关系构建的全部逻辑,从 InsightExtractor 拆分(P1-3)。
|
|
15
|
+
* relationStore 未注入时所有方法静默降级(返回空/no-op)。
|
|
16
|
+
*/
|
|
17
|
+
export class RelationBuilder {
|
|
18
|
+
index;
|
|
19
|
+
relationStore;
|
|
20
|
+
/** 冲突检测回调(由 Agent 通过 bindOnConflict 注入,检测到 contradicts 时触发) */
|
|
21
|
+
onConflict = null;
|
|
22
|
+
/**
|
|
23
|
+
* @param index 记忆存储(用于候选召回的关键词搜索)
|
|
24
|
+
* @param relationStore 记忆关系存储(可选,未注入时所有方法静默降级)
|
|
25
|
+
*/
|
|
26
|
+
constructor(index, relationStore = null) {
|
|
27
|
+
this.index = index;
|
|
28
|
+
this.relationStore = relationStore;
|
|
29
|
+
}
|
|
30
|
+
/** 关系构建是否启用(relationStore 已注入时为 true) */
|
|
31
|
+
get enabled() {
|
|
32
|
+
return this.relationStore !== null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 绑定冲突检测回调
|
|
36
|
+
*
|
|
37
|
+
* 由 Agent.init() 在创建 InsightExtractor 后调用(与 bindGetRecentHistory 同模式),
|
|
38
|
+
* 解决 Agent 实例晚于 InsightExtractor 创建的时序循环依赖。
|
|
39
|
+
* buildRelations 检测到 contradicts 关系时调用此回调,Agent 在回调中 emit('conflictDetected')。
|
|
40
|
+
*
|
|
41
|
+
* @param fn 冲突检测回调(传入 null 可解除绑定)
|
|
42
|
+
*/
|
|
43
|
+
bindOnConflict(fn) {
|
|
44
|
+
this.onConflict = fn;
|
|
45
|
+
}
|
|
46
|
+
// ─── 候选召回 + Prompt 构建 ───────────────────────────
|
|
47
|
+
/**
|
|
48
|
+
* 召回关系判断候选记忆(top-5)
|
|
49
|
+
*
|
|
50
|
+
* 用用户输入关键词搜索已有记忆,作为 LLM 关系判断的参考。
|
|
51
|
+
* 用户输入与提取出的 insight 通常相关,候选记忆也相关。
|
|
52
|
+
* relationStore 未注入时返回空数组(降级)。
|
|
53
|
+
*
|
|
54
|
+
* @param userInput 用户输入(用于关键词搜索)
|
|
55
|
+
* @returns 候选记忆列表(id + content 截断)
|
|
56
|
+
*/
|
|
57
|
+
recallRelationCandidates(userInput) {
|
|
58
|
+
if (!this.relationStore)
|
|
59
|
+
return [];
|
|
60
|
+
const snippet = escapeLike(userInput.slice(0, 50));
|
|
61
|
+
return this.index.search(snippet, RELATION_CANDIDATE_LIMIT);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 构建候选记忆列表的 prompt 片段
|
|
65
|
+
*
|
|
66
|
+
* 格式:
|
|
67
|
+
* 已有记忆(供关系判断参考):
|
|
68
|
+
* [1] id: xxx, content: xxx
|
|
69
|
+
* [2] id: xxx, content: xxx
|
|
70
|
+
*
|
|
71
|
+
* @param candidates 候选记忆列表
|
|
72
|
+
* @returns prompt 片段(空候选时返回空字符串)
|
|
73
|
+
*/
|
|
74
|
+
buildCandidatesPrompt(candidates) {
|
|
75
|
+
if (candidates.length === 0)
|
|
76
|
+
return '';
|
|
77
|
+
const lines = candidates.map((m, i) => {
|
|
78
|
+
const safeContent = m.content.length > RELATION_CANDIDATE_CONTENT_LIMIT
|
|
79
|
+
? m.content.slice(0, RELATION_CANDIDATE_CONTENT_LIMIT) + '…'
|
|
80
|
+
: m.content;
|
|
81
|
+
return `[${i + 1}] id: ${m.id}, content: ${safeContent}`;
|
|
82
|
+
});
|
|
83
|
+
return '\n\n已有记忆(供关系判断参考):\n' + lines.join('\n');
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 构建关系判断的 prompt 指令片段
|
|
87
|
+
*
|
|
88
|
+
* 包含 relations 字段格式说明 + 关系类型说明 + 注意事项。
|
|
89
|
+
* relationStore 未注入时返回空字符串(降级,不影响 insight 提取主流程)。
|
|
90
|
+
*
|
|
91
|
+
* @returns prompt 指令片段(relationStore 未注入时为空字符串)
|
|
92
|
+
*/
|
|
93
|
+
buildRelationsPrompt() {
|
|
94
|
+
if (!this.relationStore)
|
|
95
|
+
return '';
|
|
96
|
+
return `\n\n如果提取了 insight,还需判断它与已有记忆的关系,输出 relations 字段:
|
|
97
|
+
relations: [{"targetId": "已有记忆ID", "type": "contradicts|supports|follows|refines|caused|related"}]
|
|
98
|
+
|
|
99
|
+
关系类型说明:
|
|
100
|
+
- contradicts:矛盾(新信息与已有记忆冲突)
|
|
101
|
+
- supports:支持(新信息佐证已有记忆)
|
|
102
|
+
- follows:时间先后(新信息在已有记忆之后发生)
|
|
103
|
+
- refines:细化/演化(新信息细化已有记忆)
|
|
104
|
+
- caused:因果(新信息由已有记忆导致)
|
|
105
|
+
- related:泛相关(有关但非上述类型)
|
|
106
|
+
|
|
107
|
+
注意:
|
|
108
|
+
- targetId 必须是上方"已有记忆"列表中的 ID
|
|
109
|
+
- 无关系时输出空数组 []
|
|
110
|
+
- 不增加额外 LLM 调用,在本次提取中一并完成`;
|
|
111
|
+
}
|
|
112
|
+
// ─── 关系写入 + 冲突检测 ─────────────────────────────
|
|
113
|
+
/**
|
|
114
|
+
* 构建关系(写入 IMemoryRelationStore)
|
|
115
|
+
*
|
|
116
|
+
* 解析 LLM 输出的 relations 字段,验证 targetId 在候选列表中,写入关系存储。
|
|
117
|
+
* 降级策略:relationStore 未注入/relations 为空/targetId 无效 → 跳过,不阻塞主流程。
|
|
118
|
+
*
|
|
119
|
+
* 检测到 contradicts 关系时,通过 onConflict 回调通知 Agent,
|
|
120
|
+
* Agent emit('conflictDetected') 触发宿主消费链路(ProactiveBanner 通知用户)。
|
|
121
|
+
*
|
|
122
|
+
* @param insightId 新写入的 insight ID
|
|
123
|
+
* @param insightContent 新写入的 insight 内容(用于冲突通知 UI 展示)
|
|
124
|
+
* @param relations LLM 输出的关系列表
|
|
125
|
+
* @param candidates 候选记忆列表(用于验证 targetId + 查找 targetContent)
|
|
126
|
+
*/
|
|
127
|
+
buildRelations(insightId, insightContent, relations, candidates) {
|
|
128
|
+
if (!this.relationStore || relations.length === 0)
|
|
129
|
+
return;
|
|
130
|
+
const candidateIds = new Set(candidates.map((m) => m.id));
|
|
131
|
+
const candidateMap = new Map(candidates.map((m) => [m.id, m]));
|
|
132
|
+
const now = nowIso();
|
|
133
|
+
let built = 0;
|
|
134
|
+
for (const rel of relations) {
|
|
135
|
+
// 运行时类型校验(不可信的 LLM 输出)
|
|
136
|
+
if (typeof rel.targetId !== 'string' || typeof rel.type !== 'string')
|
|
137
|
+
continue;
|
|
138
|
+
// targetId 必须在候选列表中(LLM 可能输出不存在的 ID)
|
|
139
|
+
if (!candidateIds.has(rel.targetId))
|
|
140
|
+
continue;
|
|
141
|
+
this.relationStore.addRelation({
|
|
142
|
+
sourceId: insightId,
|
|
143
|
+
targetId: rel.targetId,
|
|
144
|
+
type: rel.type,
|
|
145
|
+
weight: this.weightByType(rel.type),
|
|
146
|
+
createdAt: now,
|
|
147
|
+
});
|
|
148
|
+
built++;
|
|
149
|
+
// contradicts 关系写入时,通过 onConflict 回调通知宿主
|
|
150
|
+
if (rel.type === 'contradicts' && this.onConflict) {
|
|
151
|
+
const targetMemory = candidateMap.get(rel.targetId);
|
|
152
|
+
if (targetMemory) {
|
|
153
|
+
this.onConflict({
|
|
154
|
+
newMemoryId: insightId,
|
|
155
|
+
newInsight: insightContent,
|
|
156
|
+
targetId: rel.targetId,
|
|
157
|
+
targetContent: targetMemory.content,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (built > 0) {
|
|
163
|
+
logger.info({ insightId, built }, 'RelationBuilder: 关系构建完成');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// ─── 私有:工具方法 ───────────────────────────────────
|
|
167
|
+
/**
|
|
168
|
+
* 根据关系类型推断 weight(ADR-014 §4)
|
|
169
|
+
*
|
|
170
|
+
* LLM 只输出 type,weight 由代码层推断:
|
|
171
|
+
* - contradicts → 1.0(确定关系,矛盾是强关系)
|
|
172
|
+
* - supports/follows/refines/caused → 0.7(强相关)
|
|
173
|
+
* - related → 0.3(弱相关)
|
|
174
|
+
* - 未知类型 → 0.5(未判断兜底)
|
|
175
|
+
*
|
|
176
|
+
* 设计理由:降低 LLM 认知负担,离散值比连续浮点稳定
|
|
177
|
+
*/
|
|
178
|
+
weightByType(type) {
|
|
179
|
+
switch (type) {
|
|
180
|
+
case 'contradicts': return RELATION_WEIGHTS.CERTAIN;
|
|
181
|
+
case 'supports':
|
|
182
|
+
case 'follows':
|
|
183
|
+
case 'refines':
|
|
184
|
+
case 'caused':
|
|
185
|
+
return RELATION_WEIGHTS.STRONG;
|
|
186
|
+
case 'related': return RELATION_WEIGHTS.WEAK;
|
|
187
|
+
default: return RELATION_WEIGHTS.UNDEFINED;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=relationBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationBuilder.js","sourceRoot":"","sources":["../../../src/agent/managers/relationBuilder.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -44,6 +44,14 @@ export type AgentChunk = {
|
|
|
44
44
|
} | {
|
|
45
45
|
type: 'text';
|
|
46
46
|
content: string;
|
|
47
|
+
/**
|
|
48
|
+
* 护栏阻断标志(结构化信号)
|
|
49
|
+
*
|
|
50
|
+
* 当输入/输出被护栏规则阻断时为 true,让 eval 框架和宿主 UI
|
|
51
|
+
* 能通过结构化字段判断护栏触发,而非依赖文案子串匹配。
|
|
52
|
+
* 非护栏场景的普通 text chunk 不携带此字段(undefined 等同 false)。
|
|
53
|
+
*/
|
|
54
|
+
guardrailBlocked?: boolean;
|
|
47
55
|
} | {
|
|
48
56
|
type: 'tool_start';
|
|
49
57
|
toolCallId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agent/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,uBAAuB;AACvB,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,CAAC;AAErE;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAqB;IACpC,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,qBAAqB,EAAE,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAC1C;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agent/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,uBAAuB;AACvB,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,CAAC;AAErE;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAqB;IACpC,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,qBAAqB,EAAE,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAC1C;IACE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,GACD;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACxF;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAIrB;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oDAAoD;IACpD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7D,yCAAyC;IACzC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gCAAgC;IAChC,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/C,uCAAuC;IACvC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kBAAkB;IAClB,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACjD;AAID;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,eAAe,GAAG,QAAQ,CAAC"}
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
declare const ConfigSchema: z.ZodObject<{
|
|
3
|
-
llm: z.ZodObject<{
|
|
3
|
+
llm: z.ZodDefault<z.ZodObject<{
|
|
4
4
|
provider: z.ZodDefault<z.ZodString>;
|
|
5
5
|
model: z.ZodDefault<z.ZodString>;
|
|
6
6
|
baseUrl: z.ZodOptional<z.ZodString>;
|
|
@@ -20,18 +20,22 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
20
20
|
apiKey: z.ZodOptional<z.ZodString>;
|
|
21
21
|
/** 该 Provider 的 temperature,未配置时回退到全局 llm.temperature */
|
|
22
22
|
temperature: z.ZodOptional<z.ZodNumber>;
|
|
23
|
+
/** 该 Provider 的上下文窗口大小(token 数),未配置时回退到 memory.maxContextTokens */
|
|
24
|
+
contextWindow: z.ZodOptional<z.ZodNumber>;
|
|
23
25
|
}, "strip", z.ZodTypeAny, {
|
|
24
26
|
model: string;
|
|
25
27
|
provider: string;
|
|
26
28
|
apiKey?: string | undefined;
|
|
27
29
|
temperature?: number | undefined;
|
|
28
30
|
baseUrl?: string | undefined;
|
|
31
|
+
contextWindow?: number | undefined;
|
|
29
32
|
}, {
|
|
30
33
|
model: string;
|
|
31
34
|
provider: string;
|
|
32
35
|
apiKey?: string | undefined;
|
|
33
36
|
temperature?: number | undefined;
|
|
34
37
|
baseUrl?: string | undefined;
|
|
38
|
+
contextWindow?: number | undefined;
|
|
35
39
|
}>>>;
|
|
36
40
|
/**
|
|
37
41
|
* 当前激活的 Provider 别名
|
|
@@ -70,13 +74,6 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
70
74
|
temperature: number;
|
|
71
75
|
model: string;
|
|
72
76
|
provider: string;
|
|
73
|
-
background?: {
|
|
74
|
-
temperature: number;
|
|
75
|
-
model: string;
|
|
76
|
-
provider: string;
|
|
77
|
-
apiKey?: string | undefined;
|
|
78
|
-
baseUrl?: string | undefined;
|
|
79
|
-
} | undefined;
|
|
80
77
|
apiKey?: string | undefined;
|
|
81
78
|
active?: string | undefined;
|
|
82
79
|
baseUrl?: string | undefined;
|
|
@@ -86,15 +83,16 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
86
83
|
apiKey?: string | undefined;
|
|
87
84
|
temperature?: number | undefined;
|
|
88
85
|
baseUrl?: string | undefined;
|
|
86
|
+
contextWindow?: number | undefined;
|
|
89
87
|
}> | undefined;
|
|
90
|
-
}, {
|
|
91
88
|
background?: {
|
|
89
|
+
temperature: number;
|
|
92
90
|
model: string;
|
|
93
91
|
provider: string;
|
|
94
92
|
apiKey?: string | undefined;
|
|
95
|
-
temperature?: number | undefined;
|
|
96
93
|
baseUrl?: string | undefined;
|
|
97
94
|
} | undefined;
|
|
95
|
+
}, {
|
|
98
96
|
apiKey?: string | undefined;
|
|
99
97
|
temperature?: number | undefined;
|
|
100
98
|
model?: string | undefined;
|
|
@@ -107,9 +105,17 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
107
105
|
apiKey?: string | undefined;
|
|
108
106
|
temperature?: number | undefined;
|
|
109
107
|
baseUrl?: string | undefined;
|
|
108
|
+
contextWindow?: number | undefined;
|
|
110
109
|
}> | undefined;
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
background?: {
|
|
111
|
+
model: string;
|
|
112
|
+
provider: string;
|
|
113
|
+
apiKey?: string | undefined;
|
|
114
|
+
temperature?: number | undefined;
|
|
115
|
+
baseUrl?: string | undefined;
|
|
116
|
+
} | undefined;
|
|
117
|
+
}>>;
|
|
118
|
+
memory: z.ZodDefault<z.ZodObject<{
|
|
113
119
|
dataDir: z.ZodDefault<z.ZodString>;
|
|
114
120
|
maxContextTokens: z.ZodDefault<z.ZodNumber>;
|
|
115
121
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -118,8 +124,8 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
118
124
|
}, {
|
|
119
125
|
maxContextTokens?: number | undefined;
|
|
120
126
|
dataDir?: string | undefined;
|
|
121
|
-
}
|
|
122
|
-
security: z.ZodObject<{
|
|
127
|
+
}>>;
|
|
128
|
+
security: z.ZodDefault<z.ZodObject<{
|
|
123
129
|
permission: z.ZodDefault<z.ZodEnum<["owner", "guest"]>>;
|
|
124
130
|
confirmWrites: z.ZodDefault<z.ZodBoolean>;
|
|
125
131
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -128,7 +134,7 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
128
134
|
}, {
|
|
129
135
|
permission?: "owner" | "guest" | undefined;
|
|
130
136
|
confirmWrites?: boolean | undefined;
|
|
131
|
-
}
|
|
137
|
+
}>>;
|
|
132
138
|
allowedPaths: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
133
139
|
persona: z.ZodOptional<z.ZodString>;
|
|
134
140
|
/**
|
|
@@ -155,13 +161,6 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
155
161
|
temperature: number;
|
|
156
162
|
model: string;
|
|
157
163
|
provider: string;
|
|
158
|
-
background?: {
|
|
159
|
-
temperature: number;
|
|
160
|
-
model: string;
|
|
161
|
-
provider: string;
|
|
162
|
-
apiKey?: string | undefined;
|
|
163
|
-
baseUrl?: string | undefined;
|
|
164
|
-
} | undefined;
|
|
165
164
|
apiKey?: string | undefined;
|
|
166
165
|
active?: string | undefined;
|
|
167
166
|
baseUrl?: string | undefined;
|
|
@@ -171,7 +170,15 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
171
170
|
apiKey?: string | undefined;
|
|
172
171
|
temperature?: number | undefined;
|
|
173
172
|
baseUrl?: string | undefined;
|
|
173
|
+
contextWindow?: number | undefined;
|
|
174
174
|
}> | undefined;
|
|
175
|
+
background?: {
|
|
176
|
+
temperature: number;
|
|
177
|
+
model: string;
|
|
178
|
+
provider: string;
|
|
179
|
+
apiKey?: string | undefined;
|
|
180
|
+
baseUrl?: string | undefined;
|
|
181
|
+
} | undefined;
|
|
175
182
|
};
|
|
176
183
|
security: {
|
|
177
184
|
permission: "owner" | "guest";
|
|
@@ -189,14 +196,8 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
189
196
|
baseUrl?: string | undefined;
|
|
190
197
|
} | undefined;
|
|
191
198
|
}, {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
model: string;
|
|
195
|
-
provider: string;
|
|
196
|
-
apiKey?: string | undefined;
|
|
197
|
-
temperature?: number | undefined;
|
|
198
|
-
baseUrl?: string | undefined;
|
|
199
|
-
} | undefined;
|
|
199
|
+
persona?: string | undefined;
|
|
200
|
+
llm?: {
|
|
200
201
|
apiKey?: string | undefined;
|
|
201
202
|
temperature?: number | undefined;
|
|
202
203
|
model?: string | undefined;
|
|
@@ -209,17 +210,24 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
209
210
|
apiKey?: string | undefined;
|
|
210
211
|
temperature?: number | undefined;
|
|
211
212
|
baseUrl?: string | undefined;
|
|
213
|
+
contextWindow?: number | undefined;
|
|
212
214
|
}> | undefined;
|
|
213
|
-
|
|
214
|
-
|
|
215
|
+
background?: {
|
|
216
|
+
model: string;
|
|
217
|
+
provider: string;
|
|
218
|
+
apiKey?: string | undefined;
|
|
219
|
+
temperature?: number | undefined;
|
|
220
|
+
baseUrl?: string | undefined;
|
|
221
|
+
} | undefined;
|
|
222
|
+
} | undefined;
|
|
223
|
+
security?: {
|
|
215
224
|
permission?: "owner" | "guest" | undefined;
|
|
216
225
|
confirmWrites?: boolean | undefined;
|
|
217
|
-
};
|
|
218
|
-
memory
|
|
226
|
+
} | undefined;
|
|
227
|
+
memory?: {
|
|
219
228
|
maxContextTokens?: number | undefined;
|
|
220
229
|
dataDir?: string | undefined;
|
|
221
|
-
};
|
|
222
|
-
persona?: string | undefined;
|
|
230
|
+
} | undefined;
|
|
223
231
|
allowedPaths?: string[] | undefined;
|
|
224
232
|
embedding?: {
|
|
225
233
|
model: string;
|
|
@@ -230,6 +238,10 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
230
238
|
export type Config = z.infer<typeof ConfigSchema>;
|
|
231
239
|
/**
|
|
232
240
|
* 加载配置
|
|
241
|
+
*
|
|
242
|
+
* 单一真理源:所有默认值由 ConfigSchema 的 .default() 声明,
|
|
243
|
+
* 不再维护独立的 DEFAULT_CONFIG 常量(避免两处真理源打架)。
|
|
244
|
+
*
|
|
233
245
|
* @param configPath 显式指定的配置文件路径
|
|
234
246
|
*/
|
|
235
247
|
export declare function loadConfig(configPath?: string): Promise<Config>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgCxB,QAAA,MAAM,YAAY;;;;;;;QASZ;;;;;;WAMG;;;;;;YA7BP,yDAAyD;;YAEzD,mEAAmE;;;;;;;;;;;;;;;;;QA6B/D;;;;;WAKG;;QAEH;;;;;;WAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4BP;;;;;OAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQH,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BrE"}
|
package/dist/config/loader.js
CHANGED
|
@@ -35,13 +35,20 @@ const ProviderConfigSchema = z.object({
|
|
|
35
35
|
apiKey: z.string().optional(),
|
|
36
36
|
/** 该 Provider 的 temperature,未配置时回退到全局 llm.temperature */
|
|
37
37
|
temperature: z.number().min(0).max(2).optional(),
|
|
38
|
+
/** 该 Provider 的上下文窗口大小(token 数),未配置时回退到 memory.maxContextTokens */
|
|
39
|
+
contextWindow: z.number().optional(),
|
|
38
40
|
});
|
|
39
41
|
// 配置 schema(运行时校验)
|
|
40
42
|
// provider 允许任意字符串:预设(mock/deepseek/doubao/openai)开箱即用,
|
|
41
43
|
// 自定义 provider(如 mimo、自部署模型)只要显式配 baseUrl + model 即可
|
|
42
44
|
// 详见 ADR-003
|
|
45
|
+
//
|
|
46
|
+
// 单一真理源:所有默认值由 .default() 声明,ConfigSchema.parse({}) 即可得到完整默认配置。
|
|
47
|
+
// 嵌套对象(llm/memory/security)必须用 .default({}) 声明整体默认值,
|
|
48
|
+
// 否则 zod 会在对象缺失时报 "Required" 而非使用内部字段的 default。
|
|
43
49
|
const ConfigSchema = z.object({
|
|
44
|
-
llm: z
|
|
50
|
+
llm: z
|
|
51
|
+
.object({
|
|
45
52
|
// 旧格式:单一 provider 扁平字段(向后兼容,providers 未配置时生效)
|
|
46
53
|
provider: z.string().default('mock'),
|
|
47
54
|
model: z.string().default('deepseek-chat'),
|
|
@@ -79,15 +86,20 @@ const ConfigSchema = z.object({
|
|
|
79
86
|
temperature: z.number().min(0).max(2).default(0.5),
|
|
80
87
|
})
|
|
81
88
|
.optional(),
|
|
82
|
-
})
|
|
83
|
-
|
|
89
|
+
})
|
|
90
|
+
.default({}),
|
|
91
|
+
memory: z
|
|
92
|
+
.object({
|
|
84
93
|
dataDir: z.string().default('~/.memora'),
|
|
85
94
|
maxContextTokens: z.number().default(DEFAULT_MAX_CONTEXT_TOKENS),
|
|
86
|
-
})
|
|
87
|
-
|
|
95
|
+
})
|
|
96
|
+
.default({}),
|
|
97
|
+
security: z
|
|
98
|
+
.object({
|
|
88
99
|
permission: z.enum(['owner', 'guest']).default('owner'),
|
|
89
100
|
confirmWrites: z.boolean().default(false),
|
|
90
|
-
})
|
|
101
|
+
})
|
|
102
|
+
.default({}),
|
|
91
103
|
// 允许的路径白名单(绝对路径)
|
|
92
104
|
allowedPaths: z.array(z.string()).default([]),
|
|
93
105
|
// 默认角色名(对应 personas/*.md)
|
|
@@ -106,26 +118,12 @@ const ConfigSchema = z.object({
|
|
|
106
118
|
})
|
|
107
119
|
.optional(),
|
|
108
120
|
});
|
|
109
|
-
const DEFAULT_CONFIG = {
|
|
110
|
-
llm: {
|
|
111
|
-
provider: 'mock',
|
|
112
|
-
model: 'mock-model',
|
|
113
|
-
temperature: 0.7,
|
|
114
|
-
},
|
|
115
|
-
memory: {
|
|
116
|
-
dataDir: '~/.memora',
|
|
117
|
-
maxContextTokens: DEFAULT_MAX_CONTEXT_TOKENS,
|
|
118
|
-
},
|
|
119
|
-
security: {
|
|
120
|
-
permission: 'owner',
|
|
121
|
-
confirmWrites: false,
|
|
122
|
-
},
|
|
123
|
-
allowedPaths: [],
|
|
124
|
-
persona: undefined,
|
|
125
|
-
embedding: undefined,
|
|
126
|
-
};
|
|
127
121
|
/**
|
|
128
122
|
* 加载配置
|
|
123
|
+
*
|
|
124
|
+
* 单一真理源:所有默认值由 ConfigSchema 的 .default() 声明,
|
|
125
|
+
* 不再维护独立的 DEFAULT_CONFIG 常量(避免两处真理源打架)。
|
|
126
|
+
*
|
|
129
127
|
* @param configPath 显式指定的配置文件路径
|
|
130
128
|
*/
|
|
131
129
|
export async function loadConfig(configPath) {
|
|
@@ -150,10 +148,10 @@ export async function loadConfig(configPath) {
|
|
|
150
148
|
return expandEnvVars(mergeWithDefaults(config));
|
|
151
149
|
}
|
|
152
150
|
catch {
|
|
153
|
-
//
|
|
151
|
+
// 用户级不存在,使用 schema 默认值(单一真理源)
|
|
154
152
|
}
|
|
155
|
-
// 4.
|
|
156
|
-
return expandEnvVars(
|
|
153
|
+
// 4. 内置默认:ConfigSchema.parse({}) 让 zod 的 .default() 生效
|
|
154
|
+
return expandEnvVars(ConfigSchema.parse({}));
|
|
157
155
|
}
|
|
158
156
|
/**
|
|
159
157
|
* 读取并解析 JSON 文件
|
|
@@ -164,12 +162,12 @@ async function readJsonFile(path) {
|
|
|
164
162
|
}
|
|
165
163
|
/**
|
|
166
164
|
* 合并用户配置与默认值
|
|
165
|
+
*
|
|
166
|
+
* 直接用 ConfigSchema.parse(userConfig),让 zod 的 .default() 填充缺失字段。
|
|
167
|
+
* 不再 spread DEFAULT_CONFIG,避免覆盖 schema default。
|
|
167
168
|
*/
|
|
168
169
|
function mergeWithDefaults(userConfig) {
|
|
169
|
-
return ConfigSchema.parse(
|
|
170
|
-
...DEFAULT_CONFIG,
|
|
171
|
-
...userConfig,
|
|
172
|
-
});
|
|
170
|
+
return ConfigSchema.parse(userConfig);
|
|
173
171
|
}
|
|
174
172
|
/**
|
|
175
173
|
* 展开 ${ENV_VAR} 占位符
|