openclaw-cortex-memory 0.1.0-Alpha.9 → 0.1.0
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/LICENSE +21 -0
- package/README.md +347 -290
- package/SIGNATURE.md +7 -0
- package/SKILL.md +96 -345
- package/dist/index.d.ts +69 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1130 -1330
- package/dist/index.js.map +1 -1
- package/dist/openclaw.plugin.json +377 -18
- package/dist/src/dedup/three_stage_deduplicator.d.ts.map +1 -1
- package/dist/src/dedup/three_stage_deduplicator.js +13 -3
- package/dist/src/dedup/three_stage_deduplicator.js.map +1 -1
- package/dist/src/engine/memory_engine.d.ts +5 -1
- package/dist/src/engine/memory_engine.d.ts.map +1 -1
- package/dist/src/engine/ts_engine.d.ts +149 -0
- package/dist/src/engine/ts_engine.d.ts.map +1 -1
- package/dist/src/engine/ts_engine.js +863 -203
- package/dist/src/engine/ts_engine.js.map +1 -1
- package/dist/src/engine/types.d.ts +20 -0
- package/dist/src/engine/types.d.ts.map +1 -1
- package/dist/src/graph/ontology.d.ts +87 -15
- package/dist/src/graph/ontology.d.ts.map +1 -1
- package/dist/src/graph/ontology.js +999 -12
- package/dist/src/graph/ontology.js.map +1 -1
- package/dist/src/net/http_post.d.ts +17 -0
- package/dist/src/net/http_post.d.ts.map +1 -0
- package/dist/src/net/http_post.js +56 -0
- package/dist/src/net/http_post.js.map +1 -0
- package/dist/src/quality/llm_output_validator.d.ts +65 -0
- package/dist/src/quality/llm_output_validator.d.ts.map +1 -0
- package/dist/src/quality/llm_output_validator.js +635 -0
- package/dist/src/quality/llm_output_validator.js.map +1 -0
- package/dist/src/reflect/reflector.d.ts.map +1 -1
- package/dist/src/reflect/reflector.js +296 -26
- package/dist/src/reflect/reflector.js.map +1 -1
- package/dist/src/rules/rule_store.d.ts.map +1 -1
- package/dist/src/rules/rule_store.js +75 -16
- package/dist/src/rules/rule_store.js.map +1 -1
- package/dist/src/session/session_end.d.ts +20 -42
- package/dist/src/session/session_end.d.ts.map +1 -1
- package/dist/src/session/session_end.js +21 -218
- package/dist/src/session/session_end.js.map +1 -1
- package/dist/src/store/archive_store.d.ts +28 -7
- package/dist/src/store/archive_store.d.ts.map +1 -1
- package/dist/src/store/archive_store.js +367 -130
- package/dist/src/store/archive_store.js.map +1 -1
- package/dist/src/store/graph_memory_store.d.ts +115 -0
- package/dist/src/store/graph_memory_store.d.ts.map +1 -0
- package/dist/src/store/graph_memory_store.js +1061 -0
- package/dist/src/store/graph_memory_store.js.map +1 -0
- package/dist/src/store/read_store.d.ts +75 -0
- package/dist/src/store/read_store.d.ts.map +1 -1
- package/dist/src/store/read_store.js +1837 -312
- package/dist/src/store/read_store.js.map +1 -1
- package/dist/src/store/vector_store.d.ts +2 -0
- package/dist/src/store/vector_store.d.ts.map +1 -1
- package/dist/src/store/vector_store.js +19 -3
- package/dist/src/store/vector_store.js.map +1 -1
- package/dist/src/store/write_store.d.ts +11 -0
- package/dist/src/store/write_store.d.ts.map +1 -1
- package/dist/src/store/write_store.js +242 -42
- package/dist/src/store/write_store.js.map +1 -1
- package/dist/src/sync/session_sync.d.ts +72 -1
- package/dist/src/sync/session_sync.d.ts.map +1 -1
- package/dist/src/sync/session_sync.js +2246 -126
- package/dist/src/sync/session_sync.js.map +1 -1
- package/dist/src/wiki/wiki_linter.d.ts +26 -0
- package/dist/src/wiki/wiki_linter.d.ts.map +1 -0
- package/dist/src/wiki/wiki_linter.js +339 -0
- package/dist/src/wiki/wiki_linter.js.map +1 -0
- package/dist/src/wiki/wiki_logger.d.ts +10 -0
- package/dist/src/wiki/wiki_logger.d.ts.map +1 -0
- package/dist/src/wiki/wiki_logger.js +78 -0
- package/dist/src/wiki/wiki_logger.js.map +1 -0
- package/dist/src/wiki/wiki_maintainer.d.ts +39 -0
- package/dist/src/wiki/wiki_maintainer.d.ts.map +1 -0
- package/dist/src/wiki/wiki_maintainer.js +38 -0
- package/dist/src/wiki/wiki_maintainer.js.map +1 -0
- package/dist/src/wiki/wiki_projector.d.ts +35 -0
- package/dist/src/wiki/wiki_projector.d.ts.map +1 -0
- package/dist/src/wiki/wiki_projector.js +1151 -0
- package/dist/src/wiki/wiki_projector.js.map +1 -0
- package/dist/src/wiki/wiki_queue.d.ts +29 -0
- package/dist/src/wiki/wiki_queue.d.ts.map +1 -0
- package/dist/src/wiki/wiki_queue.js +137 -0
- package/dist/src/wiki/wiki_queue.js.map +1 -0
- package/openclaw.plugin.json +377 -18
- package/package.json +52 -6
- package/schema/graph.schema.yaml +330 -0
- package/scripts/cli.js +67 -13
- package/scripts/repair-memory.js +321 -0
- package/skills/cortex-memory/SKILL.md +83 -0
- package/skills/cortex-memory/references/agent-manual.md +127 -0
- package/skills/cortex-memory/references/configuration.md +109 -0
- package/skills/cortex-memory/references/publish-checklist.md +45 -0
- package/skills/cortex-memory/references/system-prompt-template.md +27 -0
- package/skills/cortex-memory/references/tools.md +191 -0
|
@@ -33,11 +33,18 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.normalizeEntityName = normalizeEntityName;
|
|
37
|
+
exports.getEntityMatchKeys = getEntityMatchKeys;
|
|
36
38
|
exports.loadGraphSchema = loadGraphSchema;
|
|
37
39
|
exports.normalizeEventType = normalizeEventType;
|
|
38
40
|
exports.normalizeRelationType = normalizeRelationType;
|
|
41
|
+
exports.isCanonicalRelationType = isCanonicalRelationType;
|
|
42
|
+
exports.getDefaultGraphSchema = getDefaultGraphSchema;
|
|
43
|
+
exports.buildRelationPromptHint = buildRelationPromptHint;
|
|
39
44
|
exports.buildCanonicalId = buildCanonicalId;
|
|
40
45
|
exports.validateRelations = validateRelations;
|
|
46
|
+
exports.normalizeEntityType = normalizeEntityType;
|
|
47
|
+
exports.validateGraphPayload = validateGraphPayload;
|
|
41
48
|
const crypto = __importStar(require("crypto"));
|
|
42
49
|
const fs = __importStar(require("fs"));
|
|
43
50
|
const path = __importStar(require("path"));
|
|
@@ -85,29 +92,217 @@ const DEFAULT_SCHEMA = {
|
|
|
85
92
|
followup: "follow_up",
|
|
86
93
|
next_action: "follow_up",
|
|
87
94
|
},
|
|
95
|
+
entityTypes: [
|
|
96
|
+
"Person",
|
|
97
|
+
"FamilyMember",
|
|
98
|
+
"Friend",
|
|
99
|
+
"Team",
|
|
100
|
+
"Project",
|
|
101
|
+
"Task",
|
|
102
|
+
"Plan",
|
|
103
|
+
"Milestone",
|
|
104
|
+
"Location",
|
|
105
|
+
"Event",
|
|
106
|
+
"Schedule",
|
|
107
|
+
"Habit",
|
|
108
|
+
"HealthItem",
|
|
109
|
+
"FinanceItem",
|
|
110
|
+
"Issue",
|
|
111
|
+
"Fix",
|
|
112
|
+
"Decision",
|
|
113
|
+
"Action",
|
|
114
|
+
"Risk",
|
|
115
|
+
"Blocker",
|
|
116
|
+
"Assumption",
|
|
117
|
+
"Concept",
|
|
118
|
+
"Resource",
|
|
119
|
+
"Document",
|
|
120
|
+
"ConfigFile",
|
|
121
|
+
"Preference",
|
|
122
|
+
"Case",
|
|
123
|
+
"Pattern",
|
|
124
|
+
"Date",
|
|
125
|
+
],
|
|
126
|
+
entityAliases: {
|
|
127
|
+
"OpenClaw": ["openclaw", "插件", "该项目", "本项目"],
|
|
128
|
+
"FamilyMember": ["家人", "家庭成员", "亲人"],
|
|
129
|
+
"Friend": ["朋友", "好友"],
|
|
130
|
+
"Team": ["团队", "小组", "组", "班组"],
|
|
131
|
+
"Location": ["地点", "位置", "住址", "地址"],
|
|
132
|
+
"Event": ["活动", "事情", "事项"],
|
|
133
|
+
"Schedule": ["日程", "安排", "计划表"],
|
|
134
|
+
"Habit": ["习惯", "作息"],
|
|
135
|
+
"HealthItem": ["健康", "体检", "药物", "锻炼"],
|
|
136
|
+
"FinanceItem": ["账单", "支出", "收入", "预算"],
|
|
137
|
+
"Plan": ["计划", "方案", "路线图"],
|
|
138
|
+
"Preference": ["偏好", "习惯选择"],
|
|
139
|
+
"Document": ["文档", "说明文档", "手册", "wiki", "README", "PRD", "方案文档"],
|
|
140
|
+
"Resource": ["资源", "物品", "物件", "设备", "工具", "素材", "资产"],
|
|
141
|
+
"ConfigFile": ["配置文件", "config", "配置"],
|
|
142
|
+
"Decision": ["决策", "决定", "拍板"],
|
|
143
|
+
"Action": ["动作", "操作", "执行"],
|
|
144
|
+
"Risk": ["风险", "隐患"],
|
|
145
|
+
"Blocker": ["阻塞", "卡点", "障碍"],
|
|
146
|
+
"Assumption": ["假设", "前提"],
|
|
147
|
+
"Concept": ["概念", "术语"],
|
|
148
|
+
"Case": ["案例", "case"],
|
|
149
|
+
"Pattern": ["模式", "pattern"],
|
|
150
|
+
"Date": ["日期", "时间", "时间点"],
|
|
151
|
+
"Person": ["我", "自己", "本人", "同事", "客户", "用户", "姓名", "名字", "人名", "成员", "联系人"],
|
|
152
|
+
"Project": ["项目", "工程", "项目线"],
|
|
153
|
+
"Task": ["任务", "待办", "todo", "工单", "事项"],
|
|
154
|
+
"Milestone": ["里程碑", "节点"],
|
|
155
|
+
"Issue": ["问题", "故障", "报错"],
|
|
156
|
+
"Fix": ["修复", "解决方案"],
|
|
157
|
+
},
|
|
88
158
|
relationTypes: [
|
|
89
159
|
"depends_on",
|
|
90
160
|
"blocks",
|
|
91
|
-
"
|
|
161
|
+
"unblocks",
|
|
92
162
|
"causes",
|
|
163
|
+
"impacts",
|
|
93
164
|
"resolves",
|
|
165
|
+
"encountered_bug",
|
|
166
|
+
"solved_with",
|
|
167
|
+
"uses_tech",
|
|
168
|
+
"integrates_with",
|
|
169
|
+
"migrates_to",
|
|
170
|
+
"replaced_by",
|
|
171
|
+
"has_subtask",
|
|
94
172
|
"belongs_to",
|
|
95
173
|
"owned_by",
|
|
96
|
-
"references",
|
|
97
|
-
"prefers",
|
|
98
174
|
"implements",
|
|
99
175
|
"requires",
|
|
176
|
+
"plans_to",
|
|
177
|
+
"planned_for",
|
|
178
|
+
"scheduled_for",
|
|
179
|
+
"references",
|
|
180
|
+
"documents",
|
|
181
|
+
"defined_in",
|
|
182
|
+
"configured_in",
|
|
183
|
+
"supports",
|
|
184
|
+
"conflicts_with",
|
|
185
|
+
"duplicates",
|
|
186
|
+
"supersedes",
|
|
187
|
+
"assigned_to",
|
|
188
|
+
"reviewed_by",
|
|
189
|
+
"approved_by",
|
|
190
|
+
"rejected_by",
|
|
191
|
+
"reported_by",
|
|
192
|
+
"lives_in",
|
|
193
|
+
"cares_for",
|
|
194
|
+
"pays_for",
|
|
195
|
+
"prefers",
|
|
196
|
+
"has_spouse",
|
|
197
|
+
"has_child",
|
|
198
|
+
"birthday_on",
|
|
199
|
+
"anniversary_on",
|
|
100
200
|
],
|
|
101
201
|
relationTypeAliases: {
|
|
102
202
|
dependency: "depends_on",
|
|
103
203
|
blocked_by: "blocks",
|
|
104
|
-
|
|
204
|
+
unblock: "unblocks",
|
|
205
|
+
impact: "impacts",
|
|
206
|
+
plan_to: "plans_to",
|
|
207
|
+
plan_for: "planned_for",
|
|
208
|
+
schedule_for: "scheduled_for",
|
|
209
|
+
located_in: "lives_in",
|
|
210
|
+
care_for: "cares_for",
|
|
211
|
+
pay_for: "pays_for",
|
|
212
|
+
support: "supports",
|
|
213
|
+
conflict_with: "conflicts_with",
|
|
214
|
+
use_tech: "uses_tech",
|
|
215
|
+
tech_stack: "uses_tech",
|
|
216
|
+
integrate_with: "integrates_with",
|
|
217
|
+
migrate_to: "migrates_to",
|
|
218
|
+
replace_by: "replaced_by",
|
|
219
|
+
replace_with: "replaced_by",
|
|
220
|
+
bug: "encountered_bug",
|
|
221
|
+
bug_on: "encountered_bug",
|
|
222
|
+
fix_with: "solved_with",
|
|
223
|
+
solve_with: "solved_with",
|
|
224
|
+
solved_by: "solved_with",
|
|
225
|
+
subtask_of: "has_subtask",
|
|
226
|
+
child_task: "has_subtask",
|
|
227
|
+
documented_by: "documents",
|
|
228
|
+
defined_by: "defined_in",
|
|
229
|
+
config_in: "configured_in",
|
|
230
|
+
duplicate_of: "duplicates",
|
|
231
|
+
superseded_by: "supersedes",
|
|
232
|
+
assign_to: "assigned_to",
|
|
233
|
+
review_by: "reviewed_by",
|
|
234
|
+
approve_by: "approved_by",
|
|
235
|
+
reject_by: "rejected_by",
|
|
236
|
+
report_by: "reported_by",
|
|
237
|
+
"依赖于": "depends_on",
|
|
238
|
+
"依赖": "depends_on",
|
|
239
|
+
"取决于": "depends_on",
|
|
240
|
+
"阻塞": "blocks",
|
|
241
|
+
"卡住": "blocks",
|
|
242
|
+
"解除阻塞": "unblocks",
|
|
243
|
+
"导致": "causes",
|
|
244
|
+
"引起": "causes",
|
|
245
|
+
"影响": "impacts",
|
|
246
|
+
"解决": "resolves",
|
|
247
|
+
"修复": "resolves",
|
|
248
|
+
"遇到报错": "encountered_bug",
|
|
249
|
+
"通过": "solved_with",
|
|
250
|
+
"使用技术": "uses_tech",
|
|
251
|
+
"集成": "integrates_with",
|
|
252
|
+
"迁移到": "migrates_to",
|
|
253
|
+
"被替代": "replaced_by",
|
|
254
|
+
"子任务": "has_subtask",
|
|
255
|
+
"属于": "belongs_to",
|
|
256
|
+
"归属": "belongs_to",
|
|
257
|
+
"负责": "owned_by",
|
|
258
|
+
"由": "owned_by",
|
|
259
|
+
"参考": "references",
|
|
260
|
+
"引用": "references",
|
|
261
|
+
"偏好": "prefers",
|
|
262
|
+
"更喜欢": "prefers",
|
|
263
|
+
"实现": "implements",
|
|
264
|
+
"需要": "requires",
|
|
265
|
+
"计划做": "plans_to",
|
|
266
|
+
"打算": "plans_to",
|
|
267
|
+
"计划于": "planned_for",
|
|
268
|
+
"安排在": "scheduled_for",
|
|
269
|
+
"约在": "scheduled_for",
|
|
270
|
+
"住在": "lives_in",
|
|
271
|
+
"居住在": "lives_in",
|
|
272
|
+
"照顾": "cares_for",
|
|
273
|
+
"看护": "cares_for",
|
|
274
|
+
"支付": "pays_for",
|
|
275
|
+
"付款": "pays_for",
|
|
276
|
+
"支持": "supports",
|
|
277
|
+
"冲突": "conflicts_with",
|
|
278
|
+
"矛盾": "conflicts_with",
|
|
279
|
+
"记录": "documents",
|
|
280
|
+
"定义于": "defined_in",
|
|
281
|
+
"配置于": "configured_in",
|
|
282
|
+
"重复": "duplicates",
|
|
283
|
+
"取代": "supersedes",
|
|
284
|
+
"分配给": "assigned_to",
|
|
285
|
+
"评审": "reviewed_by",
|
|
286
|
+
"批准": "approved_by",
|
|
287
|
+
"拒绝": "rejected_by",
|
|
288
|
+
"报告": "reported_by",
|
|
105
289
|
belongs: "belongs_to",
|
|
106
290
|
owner_of: "owned_by",
|
|
107
291
|
refer_to: "references",
|
|
108
292
|
preference_for: "prefers",
|
|
109
293
|
implement: "implements",
|
|
110
294
|
need: "requires",
|
|
295
|
+
technology: "uses_tech",
|
|
296
|
+
encountered_issue: "encountered_bug",
|
|
297
|
+
spouse: "has_spouse",
|
|
298
|
+
wife_of: "has_spouse",
|
|
299
|
+
husband_of: "has_spouse",
|
|
300
|
+
child_of: "has_child",
|
|
301
|
+
parent_of: "has_child",
|
|
302
|
+
birthday: "birthday_on",
|
|
303
|
+
born_on: "birthday_on",
|
|
304
|
+
anniversary: "anniversary_on",
|
|
305
|
+
married_on: "anniversary_on",
|
|
111
306
|
},
|
|
112
307
|
relationRules: [
|
|
113
308
|
{ type: "depends_on", fromTypes: ["Task", "Plan", "Milestone"], toTypes: ["Task", "Plan", "Milestone"], allowSelfLoop: false },
|
|
@@ -116,7 +311,38 @@ const DEFAULT_SCHEMA = {
|
|
|
116
311
|
{ type: "resolves", fromTypes: ["Fix", "Decision", "Action"], toTypes: ["Issue", "Blocker"], allowSelfLoop: false },
|
|
117
312
|
{ type: "belongs_to", fromTypes: ["Task", "Issue", "Fix", "Decision"], toTypes: ["Project", "Plan", "Milestone"], allowSelfLoop: false },
|
|
118
313
|
{ type: "owned_by", fromTypes: ["Task", "Plan", "Project", "Issue"], toTypes: ["Person", "Team"], allowSelfLoop: false },
|
|
314
|
+
{ type: "uses_tech", fromTypes: ["Project", "Task", "Fix", "Action"], toTypes: ["Resource", "Document", "Concept", "Project"], allowSelfLoop: false },
|
|
315
|
+
{ type: "encountered_bug", fromTypes: ["Project", "Task", "Action"], toTypes: ["Issue", "Blocker"], allowSelfLoop: false },
|
|
316
|
+
{ type: "solved_with", fromTypes: ["Issue", "Blocker"], toTypes: ["Fix", "Action", "Decision", "Resource"], allowSelfLoop: false },
|
|
317
|
+
{ type: "has_subtask", fromTypes: ["Project", "Plan", "Milestone", "Task"], toTypes: ["Task"], allowSelfLoop: false },
|
|
318
|
+
{ type: "planned_for", fromTypes: ["Task", "Plan", "Milestone"], toTypes: ["Date", "Schedule", "Milestone"], allowSelfLoop: false },
|
|
319
|
+
],
|
|
320
|
+
highValueRelationTypes: [
|
|
321
|
+
"depends_on",
|
|
322
|
+
"blocks",
|
|
323
|
+
"unblocks",
|
|
324
|
+
"causes",
|
|
325
|
+
"impacts",
|
|
326
|
+
"resolves",
|
|
327
|
+
"encountered_bug",
|
|
328
|
+
"solved_with",
|
|
329
|
+
"uses_tech",
|
|
330
|
+
"integrates_with",
|
|
331
|
+
"migrates_to",
|
|
332
|
+
"replaced_by",
|
|
333
|
+
"has_subtask",
|
|
334
|
+
"belongs_to",
|
|
335
|
+
"owned_by",
|
|
336
|
+
"implements",
|
|
337
|
+
"requires",
|
|
338
|
+
"planned_for",
|
|
339
|
+
"scheduled_for",
|
|
119
340
|
],
|
|
341
|
+
relatedToMaxRatio: 0,
|
|
342
|
+
relatedToMaxAbsolute: 0,
|
|
343
|
+
minRelationConfidence: 0.35,
|
|
344
|
+
evidenceSpanRequired: true,
|
|
345
|
+
endpointMentionRequired: true,
|
|
120
346
|
defaultEntityType: "Concept",
|
|
121
347
|
};
|
|
122
348
|
function toLowerMap(input) {
|
|
@@ -136,6 +362,171 @@ function toKeyedRules(input) {
|
|
|
136
362
|
function schemaFilePath(projectRoot) {
|
|
137
363
|
return path.join(projectRoot, "schema", "graph.schema.yaml");
|
|
138
364
|
}
|
|
365
|
+
function clampNumber(value, min, max, fallback) {
|
|
366
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
367
|
+
return fallback;
|
|
368
|
+
}
|
|
369
|
+
return Math.max(min, Math.min(max, value));
|
|
370
|
+
}
|
|
371
|
+
function sanitizeEntityAliases(input) {
|
|
372
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
373
|
+
return DEFAULT_SCHEMA.entityAliases;
|
|
374
|
+
}
|
|
375
|
+
const output = {};
|
|
376
|
+
for (const [canonical, aliasesRaw] of Object.entries(input)) {
|
|
377
|
+
const canonicalName = canonical.trim();
|
|
378
|
+
if (!canonicalName)
|
|
379
|
+
continue;
|
|
380
|
+
const aliases = Array.isArray(aliasesRaw)
|
|
381
|
+
? aliasesRaw.map(item => (typeof item === "string" ? item.trim() : "")).filter(Boolean)
|
|
382
|
+
: [];
|
|
383
|
+
output[canonicalName] = aliases;
|
|
384
|
+
}
|
|
385
|
+
return Object.keys(output).length > 0 ? output : DEFAULT_SCHEMA.entityAliases;
|
|
386
|
+
}
|
|
387
|
+
function normalizeAliasKey(value) {
|
|
388
|
+
return value
|
|
389
|
+
.normalize("NFKC")
|
|
390
|
+
.toLowerCase()
|
|
391
|
+
.replace(/[`"'“”‘’]/g, "")
|
|
392
|
+
.replace(/[【】[\]{}()<>]/g, " ")
|
|
393
|
+
.replace(/[_\-\/\\|]+/g, " ")
|
|
394
|
+
.replace(/[,:;!?]+/g, " ")
|
|
395
|
+
.replace(/\s+/g, " ")
|
|
396
|
+
.trim();
|
|
397
|
+
}
|
|
398
|
+
function buildEntityLookupKeys(value) {
|
|
399
|
+
const trimmed = value.trim();
|
|
400
|
+
if (!trimmed) {
|
|
401
|
+
return [];
|
|
402
|
+
}
|
|
403
|
+
const normalized = normalizeAliasKey(trimmed);
|
|
404
|
+
const compact = normalized.replace(/\s+/g, "");
|
|
405
|
+
const keys = new Set();
|
|
406
|
+
keys.add(trimmed.toLowerCase());
|
|
407
|
+
if (normalized) {
|
|
408
|
+
keys.add(normalized);
|
|
409
|
+
}
|
|
410
|
+
if (compact) {
|
|
411
|
+
keys.add(compact);
|
|
412
|
+
}
|
|
413
|
+
return [...keys];
|
|
414
|
+
}
|
|
415
|
+
function chooseCanonicalAlias(leftRaw, rightRaw) {
|
|
416
|
+
const left = leftRaw.trim();
|
|
417
|
+
const right = rightRaw.trim();
|
|
418
|
+
if (!left)
|
|
419
|
+
return right;
|
|
420
|
+
if (!right)
|
|
421
|
+
return left;
|
|
422
|
+
const leftAscii = /[A-Za-z]/.test(left);
|
|
423
|
+
const rightAscii = /[A-Za-z]/.test(right);
|
|
424
|
+
if (leftAscii && !rightAscii)
|
|
425
|
+
return left;
|
|
426
|
+
if (!leftAscii && rightAscii)
|
|
427
|
+
return right;
|
|
428
|
+
return left.length >= right.length ? left : right;
|
|
429
|
+
}
|
|
430
|
+
function buildRuntimeAliasLookup(sourceText) {
|
|
431
|
+
const lookup = new Map();
|
|
432
|
+
const text = (sourceText || "").trim();
|
|
433
|
+
if (!text) {
|
|
434
|
+
return lookup;
|
|
435
|
+
}
|
|
436
|
+
const pairPattern = /([^()\n()]{1,80})\s*[((]\s*([^()\n()]{1,80})\s*[))]/g;
|
|
437
|
+
let matched = pairPattern.exec(text);
|
|
438
|
+
while (matched) {
|
|
439
|
+
const left = (matched[1] || "").trim();
|
|
440
|
+
const right = (matched[2] || "").trim();
|
|
441
|
+
if (left && right && left !== right) {
|
|
442
|
+
const canonical = chooseCanonicalAlias(left, right);
|
|
443
|
+
const alias = canonical === left ? right : left;
|
|
444
|
+
for (const key of buildEntityLookupKeys(alias)) {
|
|
445
|
+
lookup.set(key, canonical);
|
|
446
|
+
}
|
|
447
|
+
for (const key of buildEntityLookupKeys(canonical)) {
|
|
448
|
+
lookup.set(key, canonical);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
matched = pairPattern.exec(text);
|
|
452
|
+
}
|
|
453
|
+
return lookup;
|
|
454
|
+
}
|
|
455
|
+
function buildAliasLookup(schema) {
|
|
456
|
+
const lookup = new Map();
|
|
457
|
+
for (const [canonical, aliases] of Object.entries(schema.entityAliases || {})) {
|
|
458
|
+
const normalizedCanonical = canonical.trim();
|
|
459
|
+
if (!normalizedCanonical)
|
|
460
|
+
continue;
|
|
461
|
+
for (const key of buildEntityLookupKeys(normalizedCanonical)) {
|
|
462
|
+
lookup.set(key, normalizedCanonical);
|
|
463
|
+
}
|
|
464
|
+
for (const alias of aliases || []) {
|
|
465
|
+
for (const key of buildEntityLookupKeys(alias)) {
|
|
466
|
+
lookup.set(key, normalizedCanonical);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return lookup;
|
|
471
|
+
}
|
|
472
|
+
function normalizeEntityName(raw, schema, runtimeAliasLookup) {
|
|
473
|
+
const value = raw.trim();
|
|
474
|
+
if (!value)
|
|
475
|
+
return "";
|
|
476
|
+
const lookup = buildAliasLookup(schema);
|
|
477
|
+
for (const key of buildEntityLookupKeys(value)) {
|
|
478
|
+
const runtimeMapped = runtimeAliasLookup?.get(key);
|
|
479
|
+
if (runtimeMapped) {
|
|
480
|
+
return runtimeMapped;
|
|
481
|
+
}
|
|
482
|
+
const schemaMapped = lookup.get(key);
|
|
483
|
+
if (schemaMapped) {
|
|
484
|
+
return schemaMapped;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return value;
|
|
488
|
+
}
|
|
489
|
+
function getEntityMatchKeys(raw, schema) {
|
|
490
|
+
const value = raw.trim();
|
|
491
|
+
if (!value) {
|
|
492
|
+
return [];
|
|
493
|
+
}
|
|
494
|
+
const canonical = normalizeEntityName(value, schema);
|
|
495
|
+
const keys = new Set();
|
|
496
|
+
for (const key of buildEntityLookupKeys(value)) {
|
|
497
|
+
keys.add(key);
|
|
498
|
+
}
|
|
499
|
+
for (const key of buildEntityLookupKeys(canonical)) {
|
|
500
|
+
keys.add(key);
|
|
501
|
+
}
|
|
502
|
+
for (const alias of schema.entityAliases[canonical] || []) {
|
|
503
|
+
for (const key of buildEntityLookupKeys(alias)) {
|
|
504
|
+
keys.add(key);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return [...keys];
|
|
508
|
+
}
|
|
509
|
+
function tokenizeForMatch(value) {
|
|
510
|
+
return value.toLowerCase().replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim();
|
|
511
|
+
}
|
|
512
|
+
function entityMentionedInText(entity, sourceText, schema) {
|
|
513
|
+
const text = tokenizeForMatch(sourceText || "");
|
|
514
|
+
if (!text)
|
|
515
|
+
return false;
|
|
516
|
+
const canonical = normalizeEntityName(entity, schema);
|
|
517
|
+
const target = tokenizeForMatch(canonical || entity);
|
|
518
|
+
if (target && text.includes(target)) {
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
const aliases = schema.entityAliases[canonical] || [];
|
|
522
|
+
for (const alias of aliases) {
|
|
523
|
+
const normalized = tokenizeForMatch(alias);
|
|
524
|
+
if (normalized && text.includes(normalized)) {
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
139
530
|
function loadGraphSchema(projectRoot) {
|
|
140
531
|
const filePath = schemaFilePath(projectRoot);
|
|
141
532
|
if (!fs.existsSync(filePath)) {
|
|
@@ -150,9 +541,19 @@ function loadGraphSchema(projectRoot) {
|
|
|
150
541
|
return {
|
|
151
542
|
eventTypes: Array.isArray(parsed.eventTypes) && parsed.eventTypes.length > 0 ? parsed.eventTypes : DEFAULT_SCHEMA.eventTypes,
|
|
152
543
|
eventTypeAliases: parsed.eventTypeAliases && typeof parsed.eventTypeAliases === "object" ? parsed.eventTypeAliases : DEFAULT_SCHEMA.eventTypeAliases,
|
|
544
|
+
entityTypes: Array.isArray(parsed.entityTypes) && parsed.entityTypes.length > 0 ? parsed.entityTypes : DEFAULT_SCHEMA.entityTypes,
|
|
545
|
+
entityAliases: sanitizeEntityAliases(parsed.entityAliases),
|
|
153
546
|
relationTypes: Array.isArray(parsed.relationTypes) && parsed.relationTypes.length > 0 ? parsed.relationTypes : DEFAULT_SCHEMA.relationTypes,
|
|
154
547
|
relationTypeAliases: parsed.relationTypeAliases && typeof parsed.relationTypeAliases === "object" ? parsed.relationTypeAliases : DEFAULT_SCHEMA.relationTypeAliases,
|
|
155
548
|
relationRules: Array.isArray(parsed.relationRules) && parsed.relationRules.length > 0 ? parsed.relationRules : DEFAULT_SCHEMA.relationRules,
|
|
549
|
+
highValueRelationTypes: Array.isArray(parsed.highValueRelationTypes) && parsed.highValueRelationTypes.length > 0
|
|
550
|
+
? parsed.highValueRelationTypes.map(item => String(item).trim()).filter(Boolean)
|
|
551
|
+
: DEFAULT_SCHEMA.highValueRelationTypes,
|
|
552
|
+
relatedToMaxRatio: clampNumber(parsed.relatedToMaxRatio, 0, 1, DEFAULT_SCHEMA.relatedToMaxRatio),
|
|
553
|
+
relatedToMaxAbsolute: Math.max(0, Math.floor(clampNumber(parsed.relatedToMaxAbsolute, 0, 20, DEFAULT_SCHEMA.relatedToMaxAbsolute))),
|
|
554
|
+
minRelationConfidence: clampNumber(parsed.minRelationConfidence, 0, 1, DEFAULT_SCHEMA.minRelationConfidence),
|
|
555
|
+
evidenceSpanRequired: typeof parsed.evidenceSpanRequired === "boolean" ? parsed.evidenceSpanRequired : DEFAULT_SCHEMA.evidenceSpanRequired,
|
|
556
|
+
endpointMentionRequired: typeof parsed.endpointMentionRequired === "boolean" ? parsed.endpointMentionRequired : DEFAULT_SCHEMA.endpointMentionRequired,
|
|
156
557
|
defaultEntityType: typeof parsed.defaultEntityType === "string" && parsed.defaultEntityType.trim()
|
|
157
558
|
? parsed.defaultEntityType.trim()
|
|
158
559
|
: DEFAULT_SCHEMA.defaultEntityType,
|
|
@@ -177,6 +578,9 @@ function normalizeEventType(raw, schema) {
|
|
|
177
578
|
}
|
|
178
579
|
function normalizeRelationType(raw, schema) {
|
|
179
580
|
const value = raw.trim().toLowerCase();
|
|
581
|
+
if (!value) {
|
|
582
|
+
return "";
|
|
583
|
+
}
|
|
180
584
|
const relationTypes = new Set(schema.relationTypes.map(item => item.toLowerCase()));
|
|
181
585
|
const aliases = toLowerMap(schema.relationTypeAliases);
|
|
182
586
|
if (relationTypes.has(value)) {
|
|
@@ -186,7 +590,349 @@ function normalizeRelationType(raw, schema) {
|
|
|
186
590
|
if (mapped) {
|
|
187
591
|
return mapped;
|
|
188
592
|
}
|
|
189
|
-
|
|
593
|
+
const snakeCase = value.replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
594
|
+
if (/^[a-z][a-z0-9_]*$/.test(snakeCase)) {
|
|
595
|
+
return snakeCase;
|
|
596
|
+
}
|
|
597
|
+
return "";
|
|
598
|
+
}
|
|
599
|
+
function isCanonicalRelationType(type, schema) {
|
|
600
|
+
const value = type.trim().toLowerCase();
|
|
601
|
+
if (!value) {
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
const relationTypes = new Set(schema.relationTypes.map(item => item.toLowerCase()));
|
|
605
|
+
return relationTypes.has(value);
|
|
606
|
+
}
|
|
607
|
+
function getDefaultGraphSchema() {
|
|
608
|
+
return DEFAULT_SCHEMA;
|
|
609
|
+
}
|
|
610
|
+
function buildRelationPromptHint(schema) {
|
|
611
|
+
return [
|
|
612
|
+
`Allowed canonical relation types: ${schema.relationTypes.join(", ")}.`,
|
|
613
|
+
"Never use related_to.",
|
|
614
|
+
"If no canonical relation fits, create a snake_case custom relation, set relation_origin=llm_custom, and include relation_definition.",
|
|
615
|
+
].join(" ");
|
|
616
|
+
}
|
|
617
|
+
const GENERIC_ENTITY_BLOCKLIST = new Set([
|
|
618
|
+
"用户",
|
|
619
|
+
"我",
|
|
620
|
+
"我们",
|
|
621
|
+
"你",
|
|
622
|
+
"你们",
|
|
623
|
+
"他",
|
|
624
|
+
"她",
|
|
625
|
+
"他们",
|
|
626
|
+
"问题",
|
|
627
|
+
"方案",
|
|
628
|
+
"实体",
|
|
629
|
+
"系统",
|
|
630
|
+
"task",
|
|
631
|
+
"issue",
|
|
632
|
+
"solution",
|
|
633
|
+
"system",
|
|
634
|
+
"person",
|
|
635
|
+
"user",
|
|
636
|
+
"thing",
|
|
637
|
+
]);
|
|
638
|
+
function isGenericEntityName(raw) {
|
|
639
|
+
const value = normalizeAliasKey(String(raw || ""));
|
|
640
|
+
return value ? GENERIC_ENTITY_BLOCKLIST.has(value) : false;
|
|
641
|
+
}
|
|
642
|
+
function collectEntitiesFromRelations(relations, schema, runtimeAliasLookup) {
|
|
643
|
+
const output = new Set();
|
|
644
|
+
for (const relation of relations) {
|
|
645
|
+
const source = normalizeEntityName(relation.source || "", schema, runtimeAliasLookup);
|
|
646
|
+
const target = normalizeEntityName(relation.target || "", schema, runtimeAliasLookup);
|
|
647
|
+
if (source)
|
|
648
|
+
output.add(source);
|
|
649
|
+
if (target)
|
|
650
|
+
output.add(target);
|
|
651
|
+
}
|
|
652
|
+
return [...output];
|
|
653
|
+
}
|
|
654
|
+
function extractResourceReferences(sourceText) {
|
|
655
|
+
const text = (sourceText || "").trim();
|
|
656
|
+
if (!text) {
|
|
657
|
+
return [];
|
|
658
|
+
}
|
|
659
|
+
const output = new Set();
|
|
660
|
+
const urlMatches = text.match(/https?:\/\/[^\s)>"'`]+|www\.[^\s)>"'`]+/gi) || [];
|
|
661
|
+
const normalizedUrls = urlMatches.map(item => item.trim()).filter(Boolean);
|
|
662
|
+
for (const item of urlMatches) {
|
|
663
|
+
output.add(item.trim());
|
|
664
|
+
}
|
|
665
|
+
const pathMatches = text.match(/[A-Za-z]:\\[^\s"']+|(?:\.{0,2}\/)?(?:[\w.-]+\/)+[\w.-]+\.[A-Za-z0-9]{1,12}/g) || [];
|
|
666
|
+
for (const item of pathMatches) {
|
|
667
|
+
const value = item.trim();
|
|
668
|
+
const compact = value.replace(/^\.\/+/, "").replace(/^\/+/, "");
|
|
669
|
+
const coveredByUrl = normalizedUrls.some(url => url.includes(value) || (compact && url.includes(compact)));
|
|
670
|
+
if (coveredByUrl) {
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
if (value.length >= 4) {
|
|
674
|
+
output.add(value);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return [...output].slice(0, 12);
|
|
678
|
+
}
|
|
679
|
+
function inferEntityTypeFromName(entity, schema) {
|
|
680
|
+
const valid = new Set(schema.entityTypes);
|
|
681
|
+
const value = entity.trim();
|
|
682
|
+
if (!value) {
|
|
683
|
+
return schema.defaultEntityType;
|
|
684
|
+
}
|
|
685
|
+
if (valid.has("Date") && /(?:\d{4}-\d{2}-\d{2}|\d{1,2}月\d{1,2}日|\d{1,2}[/-]\d{1,2})/.test(value)) {
|
|
686
|
+
return "Date";
|
|
687
|
+
}
|
|
688
|
+
if (valid.has("Resource") && /^(https?:\/\/|www\.)/i.test(value)) {
|
|
689
|
+
return "Resource";
|
|
690
|
+
}
|
|
691
|
+
if (valid.has("Document")
|
|
692
|
+
&& (/([/\\].+\.[A-Za-z0-9]{1,12})$/.test(value) || /\.(md|txt|pdf|docx?|pptx?|xlsx?|json|yaml|yml|xml|html?)$/i.test(value))) {
|
|
693
|
+
return "Document";
|
|
694
|
+
}
|
|
695
|
+
if (valid.has("Team") && /(team|org|organization|团队|组织|公司)/i.test(value)) {
|
|
696
|
+
return "Team";
|
|
697
|
+
}
|
|
698
|
+
if (valid.has("Project") && /(project|repo|仓库|项目|工程)/i.test(value)) {
|
|
699
|
+
return "Project";
|
|
700
|
+
}
|
|
701
|
+
return schema.defaultEntityType;
|
|
702
|
+
}
|
|
703
|
+
function inferEvidenceSpanFromSource(sourceText, candidates) {
|
|
704
|
+
const text = (sourceText || "").trim();
|
|
705
|
+
if (!text) {
|
|
706
|
+
return undefined;
|
|
707
|
+
}
|
|
708
|
+
const normalizedText = tokenizeForMatch(text);
|
|
709
|
+
const uniqueCandidates = [...new Set(candidates.map(item => item.trim()).filter(Boolean))]
|
|
710
|
+
.sort((a, b) => b.length - a.length);
|
|
711
|
+
for (const candidate of uniqueCandidates) {
|
|
712
|
+
const normalized = tokenizeForMatch(candidate);
|
|
713
|
+
if (normalized && normalizedText.includes(normalized)) {
|
|
714
|
+
return candidate;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return undefined;
|
|
718
|
+
}
|
|
719
|
+
function inferContextChunkFromSource(sourceText, anchors) {
|
|
720
|
+
const text = (sourceText || "").trim().replace(/\s+/g, " ");
|
|
721
|
+
if (!text)
|
|
722
|
+
return undefined;
|
|
723
|
+
const normalizedAnchors = anchors.map(item => String(item || "").trim()).filter(Boolean);
|
|
724
|
+
let hitIndex = -1;
|
|
725
|
+
let hitAnchor = "";
|
|
726
|
+
for (const anchor of normalizedAnchors) {
|
|
727
|
+
const idx = text.indexOf(anchor);
|
|
728
|
+
if (idx >= 0) {
|
|
729
|
+
hitIndex = idx;
|
|
730
|
+
hitAnchor = anchor;
|
|
731
|
+
break;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
if (hitIndex < 0) {
|
|
735
|
+
const fallback = text.slice(0, Math.min(text.length, 100)).trim();
|
|
736
|
+
return fallback || undefined;
|
|
737
|
+
}
|
|
738
|
+
const targetLength = 80;
|
|
739
|
+
const minLength = 50;
|
|
740
|
+
const maxLength = 120;
|
|
741
|
+
let start = Math.max(0, hitIndex - Math.floor((targetLength - hitAnchor.length) / 2));
|
|
742
|
+
let end = Math.min(text.length, start + targetLength);
|
|
743
|
+
if ((end - start) < minLength) {
|
|
744
|
+
end = Math.min(text.length, start + minLength);
|
|
745
|
+
}
|
|
746
|
+
if ((end - start) > maxLength) {
|
|
747
|
+
end = start + maxLength;
|
|
748
|
+
}
|
|
749
|
+
if (end >= text.length && (end - start) < minLength) {
|
|
750
|
+
start = Math.max(0, end - minLength);
|
|
751
|
+
}
|
|
752
|
+
const chunk = text.slice(start, end).trim();
|
|
753
|
+
return chunk || undefined;
|
|
754
|
+
}
|
|
755
|
+
function summaryMentionsEntity(summary, entity, schema, runtimeAliasLookup) {
|
|
756
|
+
const normalizedSummary = tokenizeForMatch(summary || "");
|
|
757
|
+
if (!normalizedSummary) {
|
|
758
|
+
return false;
|
|
759
|
+
}
|
|
760
|
+
const canonical = normalizeEntityName(entity, schema, runtimeAliasLookup);
|
|
761
|
+
const candidates = new Set([
|
|
762
|
+
entity,
|
|
763
|
+
canonical,
|
|
764
|
+
...(schema.entityAliases[canonical] || []),
|
|
765
|
+
]);
|
|
766
|
+
for (const candidateRaw of candidates) {
|
|
767
|
+
const candidate = tokenizeForMatch(candidateRaw || "");
|
|
768
|
+
if (candidate && normalizedSummary.includes(candidate)) {
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return false;
|
|
773
|
+
}
|
|
774
|
+
function missingEntitiesInSummary(args) {
|
|
775
|
+
const missing = [];
|
|
776
|
+
for (const entity of args.entities) {
|
|
777
|
+
if (!summaryMentionsEntity(args.summary, entity, args.schema, args.runtimeAliasLookup)) {
|
|
778
|
+
missing.push(entity);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
return missing;
|
|
782
|
+
}
|
|
783
|
+
function normalizeSourceTextNav(args) {
|
|
784
|
+
const nav = args.sourceTextNav || {};
|
|
785
|
+
const layerRaw = typeof nav.layer === "string" ? nav.layer.trim() : "";
|
|
786
|
+
const layer = layerRaw === "archive_event" || layerRaw === "active_only"
|
|
787
|
+
? layerRaw
|
|
788
|
+
: args.sourceLayer;
|
|
789
|
+
const sourceEventId = (typeof nav.source_event_id === "string" ? nav.source_event_id : "").trim()
|
|
790
|
+
|| args.sourceEventId.trim()
|
|
791
|
+
|| (typeof args.archiveEventId === "string" ? args.archiveEventId.trim() : "");
|
|
792
|
+
const sourceMemoryId = (typeof nav.source_memory_id === "string" ? nav.source_memory_id : "").trim()
|
|
793
|
+
|| sourceEventId;
|
|
794
|
+
const sessionId = (typeof nav.session_id === "string" ? nav.session_id : "").trim()
|
|
795
|
+
|| args.sessionId.trim();
|
|
796
|
+
const sourceFile = (typeof nav.source_file === "string" ? nav.source_file : "").trim()
|
|
797
|
+
|| (typeof args.sourceFile === "string" ? args.sourceFile.trim() : "");
|
|
798
|
+
const fulltextAnchor = typeof nav.fulltext_anchor === "string" ? nav.fulltext_anchor.trim() : "";
|
|
799
|
+
if (!layer || !sessionId || !sourceFile || !sourceEventId || !sourceMemoryId) {
|
|
800
|
+
return null;
|
|
801
|
+
}
|
|
802
|
+
return {
|
|
803
|
+
layer,
|
|
804
|
+
session_id: sessionId,
|
|
805
|
+
source_file: sourceFile,
|
|
806
|
+
source_memory_id: sourceMemoryId,
|
|
807
|
+
source_event_id: sourceEventId,
|
|
808
|
+
fulltext_anchor: fulltextAnchor || undefined,
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
function shouldRetryWithFallbackRelations(rejectedReasons) {
|
|
812
|
+
const hardStopReasons = new Set([
|
|
813
|
+
"missing_relation_confidence",
|
|
814
|
+
"missing_evidence_span",
|
|
815
|
+
"low_relation_confidence",
|
|
816
|
+
"empty_edge",
|
|
817
|
+
]);
|
|
818
|
+
for (const reason of rejectedReasons) {
|
|
819
|
+
if (hardStopReasons.has(reason)) {
|
|
820
|
+
return false;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return true;
|
|
824
|
+
}
|
|
825
|
+
function buildFallbackRelations(args) {
|
|
826
|
+
const output = [];
|
|
827
|
+
const dedupe = new Set();
|
|
828
|
+
const entitySet = new Set(args.entities);
|
|
829
|
+
const sourceText = (args.sourceText || "").trim();
|
|
830
|
+
const fallbackConfidence = Math.max(args.schema.minRelationConfidence + 0.05, 0.55);
|
|
831
|
+
const pushRelation = (relation) => {
|
|
832
|
+
const source = normalizeEntityName(relation.source || "", args.schema, args.runtimeAliasLookup);
|
|
833
|
+
const target = normalizeEntityName(relation.target || "", args.schema, args.runtimeAliasLookup);
|
|
834
|
+
const type = normalizeRelationType(relation.type || "", args.schema);
|
|
835
|
+
const isCanonical = isCanonicalRelationType(type, args.schema);
|
|
836
|
+
const relationOrigin = relation.relation_origin || (isCanonical ? "canonical" : "llm_custom");
|
|
837
|
+
const relationDefinitionRaw = typeof relation.relation_definition === "string" ? relation.relation_definition.trim() : "";
|
|
838
|
+
const relationDefinition = relationOrigin === "llm_custom"
|
|
839
|
+
? (relationDefinitionRaw || `LLM custom relation inferred from type '${type}'.`)
|
|
840
|
+
: relationDefinitionRaw;
|
|
841
|
+
const evidenceSpan = typeof relation.evidence_span === "string" ? relation.evidence_span.trim() : "";
|
|
842
|
+
const contextChunkRaw = typeof relation.context_chunk === "string" ? relation.context_chunk.trim() : "";
|
|
843
|
+
const contextChunk = contextChunkRaw || inferContextChunkFromSource(sourceText, [evidenceSpan, source, target].filter(Boolean));
|
|
844
|
+
const confidence = typeof relation.confidence === "number"
|
|
845
|
+
? Math.max(0, Math.min(1, relation.confidence))
|
|
846
|
+
: fallbackConfidence;
|
|
847
|
+
if (!source || !target || source === target)
|
|
848
|
+
return;
|
|
849
|
+
if (!entitySet.has(source) || !entitySet.has(target))
|
|
850
|
+
return;
|
|
851
|
+
if (!type || type === "related_to")
|
|
852
|
+
return;
|
|
853
|
+
if (relationOrigin === "llm_custom" && !relationDefinition)
|
|
854
|
+
return;
|
|
855
|
+
if (!evidenceSpan)
|
|
856
|
+
return;
|
|
857
|
+
const key = `${source}|${type}|${target}`;
|
|
858
|
+
if (dedupe.has(key))
|
|
859
|
+
return;
|
|
860
|
+
dedupe.add(key);
|
|
861
|
+
output.push({
|
|
862
|
+
source,
|
|
863
|
+
target,
|
|
864
|
+
type,
|
|
865
|
+
relation_origin: relationOrigin,
|
|
866
|
+
relation_definition: relationDefinition || undefined,
|
|
867
|
+
mapping_hint: typeof relation.mapping_hint === "string" ? relation.mapping_hint.trim() || undefined : undefined,
|
|
868
|
+
evidence_span: evidenceSpan,
|
|
869
|
+
context_chunk: contextChunk,
|
|
870
|
+
confidence,
|
|
871
|
+
});
|
|
872
|
+
};
|
|
873
|
+
for (const relation of args.relations) {
|
|
874
|
+
const sourceRaw = (relation.source || "").trim();
|
|
875
|
+
const targetRaw = (relation.target || "").trim();
|
|
876
|
+
const evidence = (typeof relation.evidence_span === "string" && relation.evidence_span.trim())
|
|
877
|
+
|| inferEvidenceSpanFromSource(sourceText, [sourceRaw, targetRaw])
|
|
878
|
+
|| "";
|
|
879
|
+
pushRelation({
|
|
880
|
+
source: sourceRaw,
|
|
881
|
+
target: targetRaw,
|
|
882
|
+
type: relation.type || "",
|
|
883
|
+
relation_origin: relation.relation_origin,
|
|
884
|
+
relation_definition: relation.relation_definition,
|
|
885
|
+
mapping_hint: relation.mapping_hint,
|
|
886
|
+
evidence_span: evidence,
|
|
887
|
+
context_chunk: inferContextChunkFromSource(sourceText, [evidence, sourceRaw, targetRaw].filter(Boolean)),
|
|
888
|
+
confidence: typeof relation.confidence === "number" ? relation.confidence : fallbackConfidence,
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
if (output.length === 0) {
|
|
892
|
+
const resources = args.entities.filter(entity => {
|
|
893
|
+
const type = (args.entityTypes[entity] || "").trim();
|
|
894
|
+
return type === "Resource" || type === "Document";
|
|
895
|
+
});
|
|
896
|
+
const anchors = args.entities.filter(entity => !resources.includes(entity) && (args.entityTypes[entity] || "").trim() !== "Date");
|
|
897
|
+
const anchor = anchors[0];
|
|
898
|
+
if (anchor) {
|
|
899
|
+
for (const resource of resources.slice(0, 3)) {
|
|
900
|
+
const evidence = inferEvidenceSpanFromSource(sourceText, [resource, anchor]) || "";
|
|
901
|
+
pushRelation({
|
|
902
|
+
source: anchor,
|
|
903
|
+
target: resource,
|
|
904
|
+
type: "references",
|
|
905
|
+
evidence_span: evidence,
|
|
906
|
+
context_chunk: inferContextChunkFromSource(sourceText, [evidence, anchor, resource].filter(Boolean)),
|
|
907
|
+
confidence: fallbackConfidence,
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
if (output.length === 0) {
|
|
913
|
+
const nonDateEntities = args.entities.filter(entity => (args.entityTypes[entity] || "").trim() !== "Date");
|
|
914
|
+
if (nonDateEntities.length >= 2) {
|
|
915
|
+
const source = nonDateEntities[0];
|
|
916
|
+
for (const target of nonDateEntities.slice(1)) {
|
|
917
|
+
const evidence = inferEvidenceSpanFromSource(sourceText, [source, target]) || "";
|
|
918
|
+
pushRelation({
|
|
919
|
+
source,
|
|
920
|
+
target,
|
|
921
|
+
type: "co_occurs_with",
|
|
922
|
+
relation_origin: "llm_custom",
|
|
923
|
+
relation_definition: "Source and target are explicitly co-mentioned within the same source chunk.",
|
|
924
|
+
mapping_hint: "references",
|
|
925
|
+
evidence_span: evidence,
|
|
926
|
+
context_chunk: inferContextChunkFromSource(sourceText, [evidence, source, target].filter(Boolean)),
|
|
927
|
+
confidence: fallbackConfidence,
|
|
928
|
+
});
|
|
929
|
+
if (output.length > 0) {
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
return output;
|
|
190
936
|
}
|
|
191
937
|
function buildCanonicalId(args) {
|
|
192
938
|
const entities = (args.entities || []).map(item => item.trim().toLowerCase()).filter(Boolean).sort();
|
|
@@ -203,30 +949,75 @@ function buildCanonicalId(args) {
|
|
|
203
949
|
return `can_${crypto.createHash("sha1").update(payload).digest("hex").slice(0, 20)}`;
|
|
204
950
|
}
|
|
205
951
|
function validateRelations(args) {
|
|
952
|
+
const mode = args.qualityMode || "warn";
|
|
206
953
|
const accepted = [];
|
|
207
954
|
const rejected = [];
|
|
208
|
-
const
|
|
955
|
+
const warnings = [];
|
|
956
|
+
const runtimeAliasLookup = args.runtimeAliasLookup || new Map();
|
|
957
|
+
const normalizedSourceText = (args.sourceText || "").trim().replace(/\s+/g, " ");
|
|
958
|
+
const entitySet = new Set(args.entities
|
|
959
|
+
.map(item => normalizeEntityName(item, args.schema, runtimeAliasLookup))
|
|
960
|
+
.filter(Boolean));
|
|
209
961
|
const rules = toKeyedRules(args.schema.relationRules);
|
|
210
962
|
const typeMap = {};
|
|
211
963
|
for (const [name, type] of Object.entries(args.entityTypes || {})) {
|
|
212
964
|
if (typeof name === "string" && typeof type === "string" && name.trim() && type.trim()) {
|
|
213
|
-
|
|
965
|
+
const normalizedName = normalizeEntityName(name, args.schema, runtimeAliasLookup);
|
|
966
|
+
if (normalizedName) {
|
|
967
|
+
typeMap[normalizedName] = type.trim();
|
|
968
|
+
}
|
|
214
969
|
}
|
|
215
970
|
}
|
|
216
971
|
for (const relation of args.relations) {
|
|
217
|
-
const source = relation.source.
|
|
218
|
-
const target = relation.target.
|
|
972
|
+
const source = normalizeEntityName(relation.source || "", args.schema, runtimeAliasLookup);
|
|
973
|
+
const target = normalizeEntityName(relation.target || "", args.schema, runtimeAliasLookup);
|
|
219
974
|
const type = normalizeRelationType(relation.type, args.schema);
|
|
220
|
-
const
|
|
975
|
+
const typeIsCanonical = isCanonicalRelationType(type, args.schema);
|
|
976
|
+
const relationOriginRaw = typeof relation.relation_origin === "string" ? relation.relation_origin.trim() : "";
|
|
977
|
+
const relationOriginProvided = relationOriginRaw === "canonical" || relationOriginRaw === "llm_custom"
|
|
978
|
+
? relationOriginRaw
|
|
979
|
+
: "";
|
|
980
|
+
// Keep relation_origin aligned with normalized type to avoid blocking valid custom relations.
|
|
981
|
+
const relationOrigin = typeIsCanonical ? "canonical" : "llm_custom";
|
|
982
|
+
const relationDefinition = typeof relation.relation_definition === "string" ? relation.relation_definition.trim() : "";
|
|
983
|
+
const mappingHint = typeof relation.mapping_hint === "string" ? relation.mapping_hint.trim() : "";
|
|
984
|
+
const confidence = typeof relation.confidence === "number"
|
|
985
|
+
? Math.max(0, Math.min(1, relation.confidence))
|
|
986
|
+
: undefined;
|
|
987
|
+
const evidenceSpan = typeof relation.evidence_span === "string" ? relation.evidence_span.trim() : "";
|
|
988
|
+
const contextChunkRaw = typeof relation.context_chunk === "string" ? relation.context_chunk.trim() : "";
|
|
989
|
+
const contextChunk = contextChunkRaw || inferContextChunkFromSource(normalizedSourceText, [evidenceSpan, source, target].filter(Boolean));
|
|
990
|
+
const normalized = {
|
|
991
|
+
source,
|
|
992
|
+
target,
|
|
993
|
+
type,
|
|
994
|
+
relation_origin: relationOrigin,
|
|
995
|
+
relation_definition: relationDefinition || undefined,
|
|
996
|
+
mapping_hint: mappingHint || undefined,
|
|
997
|
+
confidence,
|
|
998
|
+
evidence_span: evidenceSpan || undefined,
|
|
999
|
+
context_chunk: contextChunk || undefined,
|
|
1000
|
+
};
|
|
221
1001
|
if (!source || !target) {
|
|
222
1002
|
rejected.push({ reason: "empty_edge", relation: normalized });
|
|
223
1003
|
continue;
|
|
224
1004
|
}
|
|
1005
|
+
if (!type) {
|
|
1006
|
+
rejected.push({ reason: "invalid_relation_type", relation: normalized });
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
if (type === "related_to") {
|
|
1010
|
+
rejected.push({ reason: "related_to_detected", relation: normalized });
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
1013
|
+
if (relationOriginProvided && relationOriginProvided !== relationOrigin) {
|
|
1014
|
+
warnings.push({ reason: "relation_origin_autocorrected", relation: normalized });
|
|
1015
|
+
}
|
|
225
1016
|
if (!entitySet.has(source) || !entitySet.has(target)) {
|
|
226
1017
|
rejected.push({ reason: "edge_entity_missing", relation: normalized });
|
|
227
1018
|
continue;
|
|
228
1019
|
}
|
|
229
|
-
const rule = rules.get(type);
|
|
1020
|
+
const rule = typeIsCanonical ? rules.get(type) : undefined;
|
|
230
1021
|
if (source === target && !(rule?.allowSelfLoop ?? false)) {
|
|
231
1022
|
rejected.push({ reason: "self_loop_blocked", relation: normalized });
|
|
232
1023
|
continue;
|
|
@@ -245,8 +1036,204 @@ function validateRelations(args) {
|
|
|
245
1036
|
continue;
|
|
246
1037
|
}
|
|
247
1038
|
}
|
|
1039
|
+
if (typeof confidence === "number" && confidence < args.schema.minRelationConfidence) {
|
|
1040
|
+
rejected.push({ reason: "low_relation_confidence", relation: normalized });
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
1043
|
+
if (typeof confidence !== "number") {
|
|
1044
|
+
rejected.push({ reason: "missing_relation_confidence", relation: normalized });
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
1047
|
+
if (args.schema.evidenceSpanRequired && !evidenceSpan) {
|
|
1048
|
+
rejected.push({ reason: "missing_evidence_span", relation: normalized });
|
|
1049
|
+
continue;
|
|
1050
|
+
}
|
|
1051
|
+
if (mode !== "off" && args.schema.evidenceSpanRequired && args.sourceText) {
|
|
1052
|
+
if (evidenceSpan && !tokenizeForMatch(args.sourceText).includes(tokenizeForMatch(evidenceSpan))) {
|
|
1053
|
+
if (mode === "strict") {
|
|
1054
|
+
rejected.push({ reason: "evidence_span_not_in_source", relation: normalized });
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
warnings.push({ reason: "evidence_span_not_in_source", relation: normalized });
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
if (mode !== "off") {
|
|
1061
|
+
if (!contextChunk) {
|
|
1062
|
+
warnings.push({ reason: "missing_context_chunk", relation: normalized });
|
|
1063
|
+
}
|
|
1064
|
+
else {
|
|
1065
|
+
const length = contextChunk.length;
|
|
1066
|
+
if (length < 50 || length > 120) {
|
|
1067
|
+
warnings.push({ reason: "context_chunk_length_out_of_range", relation: normalized });
|
|
1068
|
+
}
|
|
1069
|
+
if (normalizedSourceText && !normalizedSourceText.includes(contextChunk)) {
|
|
1070
|
+
warnings.push({ reason: "context_chunk_not_in_source", relation: normalized });
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
if (mode !== "off" && args.schema.endpointMentionRequired && args.sourceText) {
|
|
1075
|
+
const sourceHit = entityMentionedInText(source, args.sourceText, args.schema);
|
|
1076
|
+
const targetHit = entityMentionedInText(target, args.sourceText, args.schema);
|
|
1077
|
+
if (!sourceHit || !targetHit) {
|
|
1078
|
+
if (mode === "strict") {
|
|
1079
|
+
rejected.push({ reason: "endpoint_not_in_source_text", relation: normalized });
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
warnings.push({ reason: "endpoint_not_in_source_text", relation: normalized });
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
248
1085
|
accepted.push(normalized);
|
|
249
1086
|
}
|
|
250
|
-
return { accepted, rejected };
|
|
1087
|
+
return { accepted, rejected, warnings };
|
|
1088
|
+
}
|
|
1089
|
+
function normalizeEntityType(raw, schema) {
|
|
1090
|
+
const value = raw.trim();
|
|
1091
|
+
const entityTypes = new Set(schema.entityTypes.map(item => item));
|
|
1092
|
+
if (entityTypes.has(value)) {
|
|
1093
|
+
return value;
|
|
1094
|
+
}
|
|
1095
|
+
return schema.defaultEntityType;
|
|
1096
|
+
}
|
|
1097
|
+
function validateGraphPayload(args) {
|
|
1098
|
+
const sourceEventId = (args.sourceEventId || "").trim();
|
|
1099
|
+
if (!sourceEventId) {
|
|
1100
|
+
return { valid: false, reason: "source_event_id_empty" };
|
|
1101
|
+
}
|
|
1102
|
+
const summary = typeof args.summary === "string" ? args.summary.trim() : "";
|
|
1103
|
+
if (!summary) {
|
|
1104
|
+
return { valid: false, reason: "missing_summary" };
|
|
1105
|
+
}
|
|
1106
|
+
const sourceTextNav = normalizeSourceTextNav({
|
|
1107
|
+
sourceTextNav: args.source_text_nav,
|
|
1108
|
+
sourceLayer: args.sourceLayer,
|
|
1109
|
+
sourceEventId,
|
|
1110
|
+
archiveEventId: args.archiveEventId,
|
|
1111
|
+
sessionId: args.sessionId,
|
|
1112
|
+
sourceFile: args.sourceFile,
|
|
1113
|
+
});
|
|
1114
|
+
if (!sourceTextNav) {
|
|
1115
|
+
return { valid: false, reason: "fulltext_navigation_missing" };
|
|
1116
|
+
}
|
|
1117
|
+
const baseWarnings = [];
|
|
1118
|
+
const runtimeAliasLookup = buildRuntimeAliasLookup(args.sourceText);
|
|
1119
|
+
const normalizedInputEntities = Array.isArray(args.entities)
|
|
1120
|
+
? args.entities
|
|
1121
|
+
.map(item => normalizeEntityName(typeof item === "string" ? item : "", args.schema, runtimeAliasLookup))
|
|
1122
|
+
.filter(Boolean)
|
|
1123
|
+
: [];
|
|
1124
|
+
const relationEndpoints = collectEntitiesFromRelations(Array.isArray(args.relations) ? args.relations : [], args.schema, runtimeAliasLookup);
|
|
1125
|
+
const resourceEntities = extractResourceReferences(args.sourceText)
|
|
1126
|
+
.map(item => normalizeEntityName(item, args.schema, runtimeAliasLookup))
|
|
1127
|
+
.filter(Boolean);
|
|
1128
|
+
const dedupedEntities = [...new Set([...normalizedInputEntities, ...relationEndpoints, ...resourceEntities])];
|
|
1129
|
+
const entities = dedupedEntities.filter(entity => !isGenericEntityName(entity));
|
|
1130
|
+
if (entities.length !== dedupedEntities.length) {
|
|
1131
|
+
baseWarnings.push("generic_entity_rejected");
|
|
1132
|
+
}
|
|
1133
|
+
if (entities.length === 0) {
|
|
1134
|
+
return { valid: false, reason: "entities_empty" };
|
|
1135
|
+
}
|
|
1136
|
+
const summaryMissingEntities = missingEntitiesInSummary({ summary, entities, schema: args.schema, runtimeAliasLookup });
|
|
1137
|
+
if (summaryMissingEntities.length > 0) {
|
|
1138
|
+
const summaryCoverageMode = args.qualityMode || "warn";
|
|
1139
|
+
const missingAllEntities = summaryMissingEntities.length >= entities.length;
|
|
1140
|
+
if (summaryCoverageMode === "strict" || missingAllEntities) {
|
|
1141
|
+
return { valid: false, reason: "summary_missing_entities" };
|
|
1142
|
+
}
|
|
1143
|
+
baseWarnings.push(`summary_missing_entities_partial:${summaryMissingEntities.length}/${entities.length}`);
|
|
1144
|
+
}
|
|
1145
|
+
const entityTypes = args.entity_types || {};
|
|
1146
|
+
const validEntityTypes = new Set(args.schema.entityTypes);
|
|
1147
|
+
const normalizedEntityTypes = {};
|
|
1148
|
+
for (const [nameRaw, typeRaw] of Object.entries(entityTypes)) {
|
|
1149
|
+
if (typeof typeRaw !== "string")
|
|
1150
|
+
continue;
|
|
1151
|
+
const normalizedName = normalizeEntityName(nameRaw.trim(), args.schema, runtimeAliasLookup);
|
|
1152
|
+
if (!normalizedName)
|
|
1153
|
+
continue;
|
|
1154
|
+
normalizedEntityTypes[normalizedName] = typeRaw.trim();
|
|
1155
|
+
}
|
|
1156
|
+
for (const entity of entities) {
|
|
1157
|
+
const providedType = normalizedEntityTypes[entity];
|
|
1158
|
+
if (providedType && validEntityTypes.has(providedType)) {
|
|
1159
|
+
normalizedEntityTypes[entity] = providedType;
|
|
1160
|
+
}
|
|
1161
|
+
else {
|
|
1162
|
+
normalizedEntityTypes[entity] = inferEntityTypeFromName(entity, args.schema);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
const relationValidation = validateRelations({
|
|
1166
|
+
relations: Array.isArray(args.relations) ? args.relations : [],
|
|
1167
|
+
entities,
|
|
1168
|
+
entityTypes: normalizedEntityTypes,
|
|
1169
|
+
schema: args.schema,
|
|
1170
|
+
sourceText: args.sourceText,
|
|
1171
|
+
qualityMode: args.qualityMode,
|
|
1172
|
+
runtimeAliasLookup,
|
|
1173
|
+
});
|
|
1174
|
+
let acceptedRelations = relationValidation.accepted;
|
|
1175
|
+
const warnings = [...baseWarnings, ...relationValidation.warnings.map(item => item.reason)];
|
|
1176
|
+
if (acceptedRelations.length === 0) {
|
|
1177
|
+
const rejectedReasons = new Set(relationValidation.rejected.map(item => item.reason));
|
|
1178
|
+
if (!shouldRetryWithFallbackRelations(rejectedReasons)) {
|
|
1179
|
+
return { valid: false, reason: "relations_empty_or_invalid" };
|
|
1180
|
+
}
|
|
1181
|
+
const fallbackRelations = buildFallbackRelations({
|
|
1182
|
+
entities,
|
|
1183
|
+
entityTypes: normalizedEntityTypes,
|
|
1184
|
+
relations: Array.isArray(args.relations) ? args.relations : [],
|
|
1185
|
+
sourceText: args.sourceText,
|
|
1186
|
+
schema: args.schema,
|
|
1187
|
+
runtimeAliasLookup,
|
|
1188
|
+
});
|
|
1189
|
+
if (fallbackRelations.length > 0) {
|
|
1190
|
+
const fallbackValidation = validateRelations({
|
|
1191
|
+
relations: fallbackRelations,
|
|
1192
|
+
entities,
|
|
1193
|
+
entityTypes: normalizedEntityTypes,
|
|
1194
|
+
schema: args.schema,
|
|
1195
|
+
sourceText: args.sourceText,
|
|
1196
|
+
qualityMode: args.qualityMode,
|
|
1197
|
+
runtimeAliasLookup,
|
|
1198
|
+
});
|
|
1199
|
+
if (fallbackValidation.accepted.length > 0) {
|
|
1200
|
+
acceptedRelations = fallbackValidation.accepted;
|
|
1201
|
+
warnings.push("fallback_relations_applied");
|
|
1202
|
+
warnings.push(...fallbackValidation.warnings.map(item => item.reason));
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
if (acceptedRelations.length === 0) {
|
|
1207
|
+
return { valid: false, reason: "relations_empty_or_invalid" };
|
|
1208
|
+
}
|
|
1209
|
+
const id = `gph_${Date.now().toString(36)}_${crypto.randomBytes(4).toString("hex")}`;
|
|
1210
|
+
return {
|
|
1211
|
+
valid: true,
|
|
1212
|
+
warnings: [...new Set(warnings)],
|
|
1213
|
+
normalized: {
|
|
1214
|
+
id,
|
|
1215
|
+
summary,
|
|
1216
|
+
source_text_nav: sourceTextNav,
|
|
1217
|
+
source_event_id: args.sourceEventId.trim(),
|
|
1218
|
+
source_layer: args.sourceLayer,
|
|
1219
|
+
archive_event_id: typeof args.archiveEventId === "string" && args.archiveEventId.trim()
|
|
1220
|
+
? args.archiveEventId.trim()
|
|
1221
|
+
: undefined,
|
|
1222
|
+
session_id: args.sessionId,
|
|
1223
|
+
source_file: typeof args.sourceFile === "string" && args.sourceFile.trim()
|
|
1224
|
+
? args.sourceFile.trim()
|
|
1225
|
+
: undefined,
|
|
1226
|
+
timestamp: new Date().toISOString(),
|
|
1227
|
+
entities,
|
|
1228
|
+
entity_types: normalizedEntityTypes,
|
|
1229
|
+
relations: acceptedRelations,
|
|
1230
|
+
gate_source: args.gateSource,
|
|
1231
|
+
event_type: typeof args.eventType === "string" && args.eventType.trim()
|
|
1232
|
+
? normalizeEventType(args.eventType, args.schema)
|
|
1233
|
+
: undefined,
|
|
1234
|
+
schema_version: "1.0.0",
|
|
1235
|
+
confidence: args.confidence,
|
|
1236
|
+
},
|
|
1237
|
+
};
|
|
251
1238
|
}
|
|
252
1239
|
//# sourceMappingURL=ontology.js.map
|