openclaw-cortex-memory 0.1.0-Alpha.20 → 0.1.0-Alpha.21
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 +163 -228
- package/SKILL.md +71 -332
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +194 -6
- package/dist/index.js.map +1 -1
- package/dist/openclaw.plugin.json +208 -12
- package/dist/src/dedup/three_stage_deduplicator.d.ts.map +1 -1
- package/dist/src/dedup/three_stage_deduplicator.js +1 -2
- package/dist/src/dedup/three_stage_deduplicator.js.map +1 -1
- package/dist/src/engine/ts_engine.d.ts +31 -0
- package/dist/src/engine/ts_engine.d.ts.map +1 -1
- package/dist/src/engine/ts_engine.js +262 -14
- package/dist/src/engine/ts_engine.js.map +1 -1
- package/dist/src/engine/types.d.ts +1 -0
- package/dist/src/engine/types.d.ts.map +1 -1
- package/dist/src/graph/ontology.d.ts +65 -15
- package/dist/src/graph/ontology.d.ts.map +1 -1
- package/dist/src/graph/ontology.js +316 -4
- package/dist/src/graph/ontology.js.map +1 -1
- package/dist/src/quality/llm_output_validator.d.ts +48 -0
- package/dist/src/quality/llm_output_validator.d.ts.map +1 -0
- package/dist/src/quality/llm_output_validator.js +404 -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 +284 -8
- 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 -43
- package/dist/src/session/session_end.d.ts.map +1 -1
- package/dist/src/session/session_end.js +21 -233
- package/dist/src/session/session_end.js.map +1 -1
- package/dist/src/store/archive_store.d.ts +20 -7
- package/dist/src/store/archive_store.d.ts.map +1 -1
- package/dist/src/store/archive_store.js +96 -61
- package/dist/src/store/archive_store.js.map +1 -1
- package/dist/src/store/graph_memory_store.d.ts +44 -0
- package/dist/src/store/graph_memory_store.d.ts.map +1 -0
- package/dist/src/store/graph_memory_store.js +168 -0
- package/dist/src/store/graph_memory_store.js.map +1 -0
- package/dist/src/store/read_store.d.ts +27 -0
- package/dist/src/store/read_store.d.ts.map +1 -1
- package/dist/src/store/read_store.js +653 -94
- package/dist/src/store/read_store.js.map +1 -1
- package/dist/src/store/vector_store.d.ts +1 -0
- package/dist/src/store/vector_store.d.ts.map +1 -1
- package/dist/src/store/vector_store.js +1 -0
- package/dist/src/store/vector_store.js.map +1 -1
- package/dist/src/store/write_store.d.ts +7 -0
- package/dist/src/store/write_store.d.ts.map +1 -1
- package/dist/src/store/write_store.js +15 -3
- package/dist/src/store/write_store.js.map +1 -1
- package/dist/src/sync/session_sync.d.ts +48 -0
- package/dist/src/sync/session_sync.d.ts.map +1 -1
- package/dist/src/sync/session_sync.js +277 -78
- package/dist/src/sync/session_sync.js.map +1 -1
- package/openclaw.plugin.json +208 -12
- package/package.json +6 -4
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { GraphQualityMode } from "../graph/ontology";
|
|
1
2
|
interface LoggerLike {
|
|
2
3
|
debug: (message: string, ...args: unknown[]) => void;
|
|
3
4
|
info: (message: string, ...args: unknown[]) => void;
|
|
@@ -13,6 +14,7 @@ interface SessionSyncOptions {
|
|
|
13
14
|
baseURL?: string;
|
|
14
15
|
baseUrl?: string;
|
|
15
16
|
};
|
|
17
|
+
graphQualityMode?: GraphQualityMode;
|
|
16
18
|
archiveStore: {
|
|
17
19
|
storeEvents(events: Array<{
|
|
18
20
|
event_type: string;
|
|
@@ -22,10 +24,14 @@ interface SessionSyncOptions {
|
|
|
22
24
|
source: string;
|
|
23
25
|
target: string;
|
|
24
26
|
type: string;
|
|
27
|
+
evidence_span?: string;
|
|
28
|
+
confidence?: number;
|
|
25
29
|
}>;
|
|
30
|
+
entity_types?: Record<string, string>;
|
|
26
31
|
outcome?: string;
|
|
27
32
|
session_id: string;
|
|
28
33
|
source_file: string;
|
|
34
|
+
source_text?: string;
|
|
29
35
|
confidence?: number;
|
|
30
36
|
source_event_id?: string;
|
|
31
37
|
actor?: string;
|
|
@@ -39,6 +45,31 @@ interface SessionSyncOptions {
|
|
|
39
45
|
}>;
|
|
40
46
|
}>;
|
|
41
47
|
};
|
|
48
|
+
graphMemoryStore?: {
|
|
49
|
+
append(input: {
|
|
50
|
+
sourceEventId: string;
|
|
51
|
+
sourceLayer: "archive_event" | "active_only";
|
|
52
|
+
archiveEventId?: string;
|
|
53
|
+
sessionId: string;
|
|
54
|
+
sourceFile?: string;
|
|
55
|
+
eventType?: string;
|
|
56
|
+
entities?: string[];
|
|
57
|
+
entity_types?: Record<string, string>;
|
|
58
|
+
relations?: Array<{
|
|
59
|
+
source: string;
|
|
60
|
+
target: string;
|
|
61
|
+
type: string;
|
|
62
|
+
evidence_span?: string;
|
|
63
|
+
confidence?: number;
|
|
64
|
+
}>;
|
|
65
|
+
gateSource: "sync" | "session_end" | "manual";
|
|
66
|
+
confidence?: number;
|
|
67
|
+
sourceText?: string;
|
|
68
|
+
}): Promise<{
|
|
69
|
+
success: boolean;
|
|
70
|
+
reason?: string;
|
|
71
|
+
}>;
|
|
72
|
+
};
|
|
42
73
|
writeStore: {
|
|
43
74
|
writeMemory(args: {
|
|
44
75
|
text: string;
|
|
@@ -51,6 +82,10 @@ interface SessionSyncOptions {
|
|
|
51
82
|
}>;
|
|
52
83
|
};
|
|
53
84
|
requireLlmForWrite?: boolean;
|
|
85
|
+
writePolicy?: {
|
|
86
|
+
activeTextMaxChars?: number;
|
|
87
|
+
archiveSourceTextMaxChars?: number;
|
|
88
|
+
};
|
|
54
89
|
}
|
|
55
90
|
export declare function createSessionSync(options: SessionSyncOptions): {
|
|
56
91
|
syncMemory(): Promise<{
|
|
@@ -73,6 +108,19 @@ export declare function createSessionSync(options: SessionSyncOptions): {
|
|
|
73
108
|
archiveEvent: number;
|
|
74
109
|
skipReasons: Record<string, number>;
|
|
75
110
|
}>;
|
|
111
|
+
routeTranscript(args: {
|
|
112
|
+
sessionId: string;
|
|
113
|
+
sourceFile: string;
|
|
114
|
+
transcript: string;
|
|
115
|
+
}): Promise<{
|
|
116
|
+
imported: number;
|
|
117
|
+
skipped: number;
|
|
118
|
+
ok: boolean;
|
|
119
|
+
llmDecisions: number;
|
|
120
|
+
activeOnly: number;
|
|
121
|
+
archiveEvent: number;
|
|
122
|
+
skipReasons: Record<string, number>;
|
|
123
|
+
}>;
|
|
76
124
|
};
|
|
77
125
|
export {};
|
|
78
126
|
//# sourceMappingURL=session_sync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session_sync.d.ts","sourceRoot":"","sources":["../../../src/sync/session_sync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session_sync.d.ts","sourceRoot":"","sources":["../../../src/sync/session_sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -37,6 +37,7 @@ exports.createSessionSync = createSessionSync;
|
|
|
37
37
|
const crypto = __importStar(require("crypto"));
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
|
+
const llm_output_validator_1 = require("../quality/llm_output_validator");
|
|
40
41
|
function asRecord(value) {
|
|
41
42
|
if (typeof value === "object" && value !== null) {
|
|
42
43
|
return value;
|
|
@@ -211,11 +212,22 @@ function normalizeBaseUrl(value) {
|
|
|
211
212
|
return "";
|
|
212
213
|
return value.endsWith("/") ? value.slice(0, -1) : value;
|
|
213
214
|
}
|
|
214
|
-
|
|
215
|
+
function buildEventSnippet(text) {
|
|
216
|
+
const lines = text
|
|
217
|
+
.split(/\r?\n/)
|
|
218
|
+
.map(line => line.trim())
|
|
219
|
+
.filter(Boolean)
|
|
220
|
+
.filter(line => line.length >= 8);
|
|
221
|
+
const actionPattern = /(决定|完成|修复|阻塞|失败|成功|上线|部署|实现|依赖|owner|blocked|resolved|fixed|depends|decide|complete)/i;
|
|
222
|
+
const picked = lines.filter(line => actionPattern.test(line));
|
|
223
|
+
const use = picked.length > 0 ? picked : lines.slice(-20);
|
|
224
|
+
return use.slice(-30).join("\n").slice(-8000);
|
|
225
|
+
}
|
|
226
|
+
const WRITE_GATE_PROMPT_VERSION = "write-gate.v1.3.0";
|
|
215
227
|
const WRITE_GATE_REGRESSION_SAMPLES = [
|
|
216
|
-
"
|
|
217
|
-
"
|
|
218
|
-
"
|
|
228
|
+
"鏍蜂緥A: 鈥滀粖澶╄璁轰簡涓夌鏂规锛屽皻鏈喅绛栤€?=> active_only",
|
|
229
|
+
"鏍蜂緥B: 鈥滃喅瀹氶噰鐢˙鏂规骞跺畬鎴愪笂绾匡紝閿欒鐜囦笅闄嶅埌0.2%鈥?=> archive_event",
|
|
230
|
+
"鏍蜂緥C: 鈥滃ソ鐨勬敹鍒拌阿璋⑩€?=> skip",
|
|
219
231
|
];
|
|
220
232
|
function parseArchiveEventPayload(value) {
|
|
221
233
|
if (!value || typeof value !== "object") {
|
|
@@ -239,70 +251,167 @@ function parseArchiveEventPayload(value) {
|
|
|
239
251
|
const source = typeof relation.source === "string" ? relation.source.trim() : "";
|
|
240
252
|
const target = typeof relation.target === "string" ? relation.target.trim() : "";
|
|
241
253
|
const type = typeof relation.type === "string" ? relation.type.trim() : "related_to";
|
|
254
|
+
const evidenceSpan = typeof relation.evidence_span === "string" ? relation.evidence_span.trim() : "";
|
|
255
|
+
const confidence = typeof relation.confidence === "number"
|
|
256
|
+
? Math.max(0, Math.min(1, relation.confidence))
|
|
257
|
+
: undefined;
|
|
242
258
|
if (!source || !target)
|
|
243
259
|
return null;
|
|
244
|
-
return { source, target, type };
|
|
260
|
+
return { source, target, type, evidence_span: evidenceSpan || undefined, confidence };
|
|
245
261
|
})
|
|
246
|
-
.filter(
|
|
262
|
+
.filter(Boolean)
|
|
247
263
|
: [];
|
|
264
|
+
const entity_types = typeof obj.entity_types === "object" && obj.entity_types !== null && !Array.isArray(obj.entity_types)
|
|
265
|
+
? Object.fromEntries(Object.entries(obj.entity_types)
|
|
266
|
+
.filter(([key, value]) => typeof key === "string" && key.trim().length > 0 && typeof value === "string" && value.trim().length > 0)
|
|
267
|
+
.map(([key, value]) => [key.trim(), value.trim()]))
|
|
268
|
+
: undefined;
|
|
248
269
|
return {
|
|
249
270
|
event_type: eventType,
|
|
250
271
|
summary,
|
|
251
272
|
entities,
|
|
273
|
+
entity_types,
|
|
252
274
|
relations,
|
|
253
275
|
outcome: typeof obj.outcome === "string" ? obj.outcome.trim() : "",
|
|
254
276
|
confidence: typeof obj.confidence === "number" ? Math.max(0, Math.min(1, obj.confidence)) : 0.6,
|
|
255
277
|
};
|
|
256
278
|
}
|
|
257
|
-
function
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
279
|
+
function parseGraphPayload(value) {
|
|
280
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
const obj = value;
|
|
284
|
+
const entities = Array.isArray(obj.entities)
|
|
285
|
+
? obj.entities.map(v => (typeof v === "string" ? v.trim() : "")).filter(Boolean)
|
|
286
|
+
: [];
|
|
287
|
+
const entity_types = typeof obj.entity_types === "object" && obj.entity_types !== null && !Array.isArray(obj.entity_types)
|
|
288
|
+
? Object.fromEntries(Object.entries(obj.entity_types)
|
|
289
|
+
.filter(([key, val]) => typeof key === "string" && key.trim() && typeof val === "string" && val.trim())
|
|
290
|
+
.map(([key, val]) => [key.trim(), val.trim()]))
|
|
291
|
+
: undefined;
|
|
292
|
+
const relations = Array.isArray(obj.relations)
|
|
293
|
+
? obj.relations
|
|
294
|
+
.map(item => {
|
|
271
295
|
if (!item || typeof item !== "object")
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
296
|
+
return null;
|
|
297
|
+
const rel = item;
|
|
298
|
+
const source = typeof rel.source === "string" ? rel.source.trim() : "";
|
|
299
|
+
const target = typeof rel.target === "string" ? rel.target.trim() : "";
|
|
300
|
+
const type = typeof rel.type === "string" && rel.type.trim() ? rel.type.trim() : "related_to";
|
|
301
|
+
if (!source || !target)
|
|
302
|
+
return null;
|
|
303
|
+
const evidenceSpan = typeof rel.evidence_span === "string" ? rel.evidence_span.trim() : "";
|
|
304
|
+
const confidence = typeof rel.confidence === "number"
|
|
305
|
+
? Math.max(0, Math.min(1, rel.confidence))
|
|
306
|
+
: undefined;
|
|
307
|
+
return {
|
|
308
|
+
source,
|
|
309
|
+
target,
|
|
310
|
+
type,
|
|
311
|
+
...(evidenceSpan ? { evidence_span: evidenceSpan } : {}),
|
|
312
|
+
...(typeof confidence === "number" ? { confidence } : {}),
|
|
313
|
+
};
|
|
314
|
+
})
|
|
315
|
+
.filter((item) => item !== null)
|
|
316
|
+
: [];
|
|
317
|
+
if (entities.length === 0 || relations.length === 0) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
entities,
|
|
322
|
+
entity_types,
|
|
323
|
+
relations,
|
|
324
|
+
confidence: typeof obj.confidence === "number" ? Math.max(0, Math.min(1, obj.confidence)) : undefined,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
function parseLlmGateDecisions(raw, logger) {
|
|
328
|
+
const validation = (0, llm_output_validator_1.validateLlmJsonOutput)(raw);
|
|
329
|
+
if (!validation.valid) {
|
|
330
|
+
if (logger) {
|
|
331
|
+
logger.warn(`quality_gate_decisions_invalid errors=${validation.errors.join("|")}`);
|
|
332
|
+
}
|
|
333
|
+
return [];
|
|
334
|
+
}
|
|
335
|
+
if (validation.warnings.length > 0 && logger) {
|
|
336
|
+
logger.debug(`quality_gate_decisions_warnings warnings=${validation.warnings.join("|")}`);
|
|
337
|
+
}
|
|
338
|
+
const root = validation.data;
|
|
339
|
+
const parsed = Array.isArray(root) ? root : root;
|
|
340
|
+
const output = [];
|
|
341
|
+
const pushDecision = (obj, target) => {
|
|
342
|
+
let event = null;
|
|
343
|
+
if (target === "archive_event") {
|
|
344
|
+
const eventValidation = (0, llm_output_validator_1.validateArchiveEvent)(obj.event || obj);
|
|
345
|
+
if (eventValidation.valid && eventValidation.cleaned) {
|
|
346
|
+
event = {
|
|
347
|
+
event_type: eventValidation.cleaned.event_type || "insight",
|
|
348
|
+
summary: eventValidation.cleaned.summary,
|
|
349
|
+
entities: eventValidation.cleaned.entities,
|
|
350
|
+
entity_types: eventValidation.cleaned.entity_types,
|
|
351
|
+
relations: eventValidation.cleaned.relations,
|
|
352
|
+
outcome: eventValidation.cleaned.outcome || "",
|
|
353
|
+
confidence: eventValidation.cleaned.confidence,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
if (logger) {
|
|
358
|
+
logger.warn(`quality_event_invalid errors=${eventValidation.errors.join("|")}`);
|
|
359
|
+
}
|
|
360
|
+
return;
|
|
277
361
|
}
|
|
278
|
-
const event = target === "archive_event"
|
|
279
|
-
? parseArchiveEventPayload(obj.event || obj)
|
|
280
|
-
: null;
|
|
281
|
-
output.push({
|
|
282
|
-
target_layer: target,
|
|
283
|
-
active_text: typeof obj.active_text === "string" ? obj.active_text.trim() : "",
|
|
284
|
-
event: event || undefined,
|
|
285
|
-
reason: typeof obj.reason === "string" ? obj.reason.trim() : "",
|
|
286
|
-
});
|
|
287
362
|
}
|
|
288
|
-
|
|
289
|
-
|
|
363
|
+
output.push({
|
|
364
|
+
candidate_id: typeof obj.candidate_id === "string" ? obj.candidate_id.trim() : "",
|
|
365
|
+
target_layer: target,
|
|
366
|
+
active_text: typeof obj.active_text === "string" ? obj.active_text.trim() : "",
|
|
367
|
+
event: event || undefined,
|
|
368
|
+
graph: parseGraphPayload(obj.graph) || undefined,
|
|
369
|
+
reason: typeof obj.reason === "string" ? obj.reason.trim() : "",
|
|
370
|
+
});
|
|
371
|
+
};
|
|
372
|
+
if (Array.isArray(parsed)) {
|
|
373
|
+
if (logger) {
|
|
374
|
+
logger.warn("quality_gate_decisions_invalid format=array_not_supported_require_routing_plan");
|
|
290
375
|
}
|
|
291
376
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
377
|
+
else if (parsed && typeof parsed === "object") {
|
|
378
|
+
const rootObj = parsed;
|
|
379
|
+
const routingPlan = (typeof rootObj.routing_plan === "object" && rootObj.routing_plan !== null)
|
|
380
|
+
? rootObj.routing_plan
|
|
381
|
+
: null;
|
|
382
|
+
if (routingPlan) {
|
|
383
|
+
const buckets = [
|
|
384
|
+
{ key: "archive_event", items: routingPlan.archive_event },
|
|
385
|
+
{ key: "active_only", items: routingPlan.active_only },
|
|
386
|
+
{ key: "skip", items: routingPlan.skip },
|
|
387
|
+
];
|
|
388
|
+
for (const bucket of buckets) {
|
|
389
|
+
if (!Array.isArray(bucket.items))
|
|
390
|
+
continue;
|
|
391
|
+
for (const item of bucket.items) {
|
|
392
|
+
if (!item || typeof item !== "object")
|
|
393
|
+
continue;
|
|
394
|
+
pushDecision(item, bucket.key);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
298
397
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
398
|
+
else if (logger) {
|
|
399
|
+
logger.warn("quality_gate_decisions_invalid missing_routing_plan");
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (output.length === 0 && logger) {
|
|
403
|
+
logger.warn("quality_gate_decisions_empty");
|
|
404
|
+
}
|
|
405
|
+
const deduped = [];
|
|
406
|
+
const seen = new Set();
|
|
407
|
+
for (const item of output) {
|
|
408
|
+
const key = `${item.target_layer}|${item.event?.summary || item.active_text || item.reason || ""}`;
|
|
409
|
+
if (seen.has(key))
|
|
410
|
+
continue;
|
|
411
|
+
seen.add(key);
|
|
412
|
+
deduped.push(item);
|
|
304
413
|
}
|
|
305
|
-
return
|
|
414
|
+
return deduped;
|
|
306
415
|
}
|
|
307
416
|
async function extractGateDecisionsWithLlm(args) {
|
|
308
417
|
const endpoint = args.llm.baseUrl.endsWith("/chat/completions")
|
|
@@ -313,30 +422,35 @@ async function extractGateDecisionsWithLlm(args) {
|
|
|
313
422
|
temperature: 0.1,
|
|
314
423
|
response_format: { type: "json_object" },
|
|
315
424
|
messages: [
|
|
316
|
-
{ role: "system", content: "
|
|
425
|
+
{ role: "system", content: "You are a memory write-gate router. Output JSON only." },
|
|
317
426
|
{
|
|
318
427
|
role: "user",
|
|
319
428
|
content: [
|
|
320
429
|
`prompt_version=${WRITE_GATE_PROMPT_VERSION}`,
|
|
321
|
-
"
|
|
322
|
-
"
|
|
323
|
-
"
|
|
324
|
-
"
|
|
325
|
-
"
|
|
326
|
-
"
|
|
327
|
-
"
|
|
328
|
-
"
|
|
329
|
-
"
|
|
330
|
-
"
|
|
331
|
-
"
|
|
332
|
-
"active_only:
|
|
333
|
-
"
|
|
334
|
-
"
|
|
335
|
-
"
|
|
430
|
+
"Execute in 3 stages:",
|
|
431
|
+
"Stage1) Split transcript into candidate_events[]. One candidate should contain one principal event only.",
|
|
432
|
+
"Stage2) Route each candidate_event into target_layer: active_only | archive_event | skip.",
|
|
433
|
+
"Stage3) Output routing plan only. Do NOT claim data has been written.",
|
|
434
|
+
"Classification:",
|
|
435
|
+
"A) active_only: process context, ongoing discussion, temporary status, no stable conclusion.",
|
|
436
|
+
"B) archive_event: reusable event with clear subject + action/decision + outcome/phase conclusion.",
|
|
437
|
+
"C) skip: noise/repetition/chitchat/no clear business value.",
|
|
438
|
+
"Constraints:",
|
|
439
|
+
"- For archive_event: if confidence < 0.35, prefer skip.",
|
|
440
|
+
"- Relations must be grounded in source text. Do not fabricate.",
|
|
441
|
+
"- For active_only: active_text is required.",
|
|
442
|
+
"- Optional graph for active_only: graph={entities[],entity_types,relations[],confidence}.",
|
|
443
|
+
"- For relations: each relation should include source,target,type,evidence_span,confidence.",
|
|
444
|
+
"- If evidence_span or confidence is missing, do not output that relation.",
|
|
445
|
+
"Output JSON schema:",
|
|
446
|
+
"{\"candidate_events\":[{\"candidate_id\":\"c1\",\"span\":\"...\",\"normalized_text\":\"...\"}],\"routing_plan\":{\"archive_event\":[{\"candidate_id\":\"c1\",\"event\":{\"event_type\":\"decision\",\"summary\":\"...\",\"entities\":[\"A\"],\"entity_types\":{\"A\":\"Project\"},\"relations\":[],\"outcome\":\"...\",\"confidence\":0.82}}],\"active_only\":[],\"skip\":[]}}",
|
|
447
|
+
"routing_plan.archive_event[] item: {candidate_id,event}",
|
|
448
|
+
"routing_plan.active_only[] item: {candidate_id,active_text,graph}",
|
|
449
|
+
"routing_plan.skip[] item: {candidate_id,reason}",
|
|
336
450
|
...WRITE_GATE_REGRESSION_SAMPLES,
|
|
337
|
-
"
|
|
451
|
+
"Output JSON only.",
|
|
338
452
|
"",
|
|
339
|
-
args.transcript
|
|
453
|
+
buildEventSnippet(args.transcript),
|
|
340
454
|
].join("\n"),
|
|
341
455
|
},
|
|
342
456
|
],
|
|
@@ -366,7 +480,7 @@ async function extractGateDecisionsWithLlm(args) {
|
|
|
366
480
|
lastError = new Error("sync_llm_empty");
|
|
367
481
|
continue;
|
|
368
482
|
}
|
|
369
|
-
return parseLlmGateDecisions(content);
|
|
483
|
+
return parseLlmGateDecisions(content, args.logger);
|
|
370
484
|
}
|
|
371
485
|
catch (error) {
|
|
372
486
|
clearTimeout(timeoutId);
|
|
@@ -390,6 +504,12 @@ function createSessionSync(options) {
|
|
|
390
504
|
}
|
|
391
505
|
async function storeFromTranscript(args) {
|
|
392
506
|
const skipReasons = {};
|
|
507
|
+
const activeTextMaxChars = typeof options.writePolicy?.activeTextMaxChars === "number"
|
|
508
|
+
? Math.max(500, Math.min(20000, Math.floor(options.writePolicy.activeTextMaxChars)))
|
|
509
|
+
: 4000;
|
|
510
|
+
const archiveSourceTextMaxChars = typeof options.writePolicy?.archiveSourceTextMaxChars === "number"
|
|
511
|
+
? Math.max(1000, Math.min(30000, Math.floor(options.writePolicy.archiveSourceTextMaxChars)))
|
|
512
|
+
: 8000;
|
|
393
513
|
function bumpReason(reason) {
|
|
394
514
|
const key = reason || "unknown";
|
|
395
515
|
skipReasons[key] = (skipReasons[key] || 0) + 1;
|
|
@@ -407,7 +527,7 @@ function createSessionSync(options) {
|
|
|
407
527
|
}
|
|
408
528
|
options.logger.warn(`Sync gate degraded to active_only for ${args.sessionId}: llm_not_configured`);
|
|
409
529
|
const fallbackWrite = await options.writeStore.writeMemory({
|
|
410
|
-
text: args.transcript.slice(-
|
|
530
|
+
text: args.transcript.slice(-activeTextMaxChars),
|
|
411
531
|
role: "system",
|
|
412
532
|
source: `sync_gate_fallback:${args.sourceFile}`,
|
|
413
533
|
sessionId: args.sessionId,
|
|
@@ -433,6 +553,11 @@ function createSessionSync(options) {
|
|
|
433
553
|
let skipped = 0;
|
|
434
554
|
let activeOnly = 0;
|
|
435
555
|
let archiveEvent = 0;
|
|
556
|
+
let activeAttempted = 0;
|
|
557
|
+
let archiveAttempted = 0;
|
|
558
|
+
let graphAttempted = 0;
|
|
559
|
+
let graphStored = 0;
|
|
560
|
+
let graphSkipped = 0;
|
|
436
561
|
const archiveInputs = [];
|
|
437
562
|
for (const decision of decisions) {
|
|
438
563
|
llmDecisions += 1;
|
|
@@ -442,7 +567,8 @@ function createSessionSync(options) {
|
|
|
442
567
|
continue;
|
|
443
568
|
}
|
|
444
569
|
if (decision.target_layer === "active_only") {
|
|
445
|
-
|
|
570
|
+
activeAttempted += 1;
|
|
571
|
+
const activeText = (decision.active_text || args.transcript).trim().slice(-activeTextMaxChars);
|
|
446
572
|
if (!activeText) {
|
|
447
573
|
skipped += 1;
|
|
448
574
|
bumpReason("active_only_empty");
|
|
@@ -457,6 +583,34 @@ function createSessionSync(options) {
|
|
|
457
583
|
if (writeResult.status === "ok") {
|
|
458
584
|
imported += 1;
|
|
459
585
|
activeOnly += 1;
|
|
586
|
+
if (options.graphMemoryStore && decision.graph) {
|
|
587
|
+
graphAttempted += 1;
|
|
588
|
+
const relationFingerprint = (decision.graph.relations || [])
|
|
589
|
+
.map(rel => `${rel.source}|${rel.type}|${rel.target}|${rel.evidence_span || ""}`)
|
|
590
|
+
.sort()
|
|
591
|
+
.join("||");
|
|
592
|
+
const activeSourceEventId = `active:${args.sessionId}:${crypto.createHash("sha1").update(relationFingerprint || activeText).digest("hex").slice(0, 16)}`;
|
|
593
|
+
const graphResult = await options.graphMemoryStore.append({
|
|
594
|
+
sourceEventId: activeSourceEventId,
|
|
595
|
+
sourceLayer: "active_only",
|
|
596
|
+
sessionId: args.sessionId,
|
|
597
|
+
sourceFile: args.sourceFile,
|
|
598
|
+
eventType: "insight",
|
|
599
|
+
entities: decision.graph.entities,
|
|
600
|
+
entity_types: decision.graph.entity_types,
|
|
601
|
+
relations: decision.graph.relations,
|
|
602
|
+
gateSource: "sync",
|
|
603
|
+
confidence: decision.graph.confidence,
|
|
604
|
+
sourceText: activeText,
|
|
605
|
+
});
|
|
606
|
+
if (!graphResult.success) {
|
|
607
|
+
graphSkipped += 1;
|
|
608
|
+
options.logger.info(`graph_skip_reason=${graphResult.reason} source_event_id=${activeSourceEventId}`);
|
|
609
|
+
}
|
|
610
|
+
else {
|
|
611
|
+
graphStored += 1;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
460
614
|
}
|
|
461
615
|
else {
|
|
462
616
|
skipped += 1;
|
|
@@ -465,6 +619,7 @@ function createSessionSync(options) {
|
|
|
465
619
|
continue;
|
|
466
620
|
}
|
|
467
621
|
if (decision.target_layer === "archive_event") {
|
|
622
|
+
archiveAttempted += 1;
|
|
468
623
|
if (!decision.event) {
|
|
469
624
|
skipped += 1;
|
|
470
625
|
bumpReason("archive_event_missing_payload");
|
|
@@ -475,26 +630,67 @@ function createSessionSync(options) {
|
|
|
475
630
|
summary: decision.event.summary,
|
|
476
631
|
entities: decision.event.entities,
|
|
477
632
|
relations: decision.event.relations,
|
|
633
|
+
entity_types: decision.event.entity_types,
|
|
478
634
|
outcome: decision.event.outcome,
|
|
479
635
|
confidence: decision.event.confidence,
|
|
480
636
|
session_id: args.sessionId,
|
|
481
637
|
source_file: args.sourceFile,
|
|
482
|
-
|
|
638
|
+
source_text: args.transcript.slice(-archiveSourceTextMaxChars),
|
|
639
|
+
source_event_id: decision.candidate_id
|
|
640
|
+
? `candidate:${args.sessionId}:${decision.candidate_id}`
|
|
641
|
+
: `candidate:${args.sessionId}:${crypto.createHash("sha1").update(decision.event.summary).digest("hex").slice(0, 16)}`,
|
|
483
642
|
actor: "sync_llm_gate",
|
|
484
643
|
});
|
|
485
644
|
}
|
|
486
645
|
}
|
|
487
646
|
if (archiveInputs.length > 0) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
647
|
+
let archivedSuccess = 0;
|
|
648
|
+
let archivedSkipped = 0;
|
|
649
|
+
for (const inputRecord of archiveInputs) {
|
|
650
|
+
const archiveResult = await options.archiveStore.storeEvents([inputRecord]);
|
|
651
|
+
imported += archiveResult.stored.length;
|
|
652
|
+
skipped += archiveResult.skipped.length;
|
|
653
|
+
archiveEvent += archiveResult.stored.length;
|
|
654
|
+
archivedSuccess += archiveResult.stored.length;
|
|
655
|
+
archivedSkipped += archiveResult.skipped.length;
|
|
656
|
+
for (const skip of archiveResult.skipped) {
|
|
657
|
+
bumpReason(skip.reason || "archive_store_skipped");
|
|
658
|
+
}
|
|
659
|
+
const archiveRecord = archiveResult.stored[0];
|
|
660
|
+
if (!archiveRecord) {
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
if (!options.graphMemoryStore) {
|
|
664
|
+
continue;
|
|
665
|
+
}
|
|
666
|
+
graphAttempted += 1;
|
|
667
|
+
const graphResult = await options.graphMemoryStore.append({
|
|
668
|
+
// Graph trace points to persisted archive record id for stable lookup.
|
|
669
|
+
sourceEventId: archiveRecord.id,
|
|
670
|
+
sourceLayer: "archive_event",
|
|
671
|
+
archiveEventId: archiveRecord.id,
|
|
672
|
+
sessionId: args.sessionId,
|
|
673
|
+
sourceFile: args.sourceFile,
|
|
674
|
+
eventType: inputRecord.event_type,
|
|
675
|
+
entities: inputRecord.entities,
|
|
676
|
+
entity_types: inputRecord.entity_types,
|
|
677
|
+
relations: inputRecord.relations,
|
|
678
|
+
gateSource: "sync",
|
|
679
|
+
confidence: inputRecord.confidence,
|
|
680
|
+
sourceText: args.transcript,
|
|
681
|
+
});
|
|
682
|
+
if (!graphResult.success) {
|
|
683
|
+
graphSkipped += 1;
|
|
684
|
+
options.logger.info(`graph_skip_reason=${graphResult.reason} source_event_id=${archiveRecord.id}`);
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
graphStored += 1;
|
|
688
|
+
}
|
|
494
689
|
}
|
|
495
|
-
options.logger.info(`sync_archive_result session=${args.sessionId} archived_success=${
|
|
690
|
+
options.logger.info(`sync_archive_result session=${args.sessionId} archived_success=${archivedSuccess} skipped=${archivedSkipped}`);
|
|
496
691
|
}
|
|
497
692
|
options.logger.info(`sync_gate_result session=${args.sessionId} llm_decisions=${llmDecisions} active_only=${activeOnly} archive_event=${archiveEvent} skipped=${skipped}`);
|
|
693
|
+
options.logger.info(`sync_gate_metrics session=${args.sessionId} active_attempted=${activeAttempted} archive_attempted=${archiveAttempted} graph_attempted=${graphAttempted} graph_stored=${graphStored} graph_skipped=${graphSkipped} skip_reason_kinds=${Object.keys(skipReasons).length}`);
|
|
498
694
|
return {
|
|
499
695
|
imported,
|
|
500
696
|
skipped,
|
|
@@ -661,6 +857,9 @@ function createSessionSync(options) {
|
|
|
661
857
|
skipReasons,
|
|
662
858
|
};
|
|
663
859
|
}
|
|
664
|
-
|
|
860
|
+
async function routeTranscript(args) {
|
|
861
|
+
return storeFromTranscript(args);
|
|
862
|
+
}
|
|
863
|
+
return { syncMemory, syncDailySummaries, routeTranscript };
|
|
665
864
|
}
|
|
666
865
|
//# sourceMappingURL=session_sync.js.map
|