memorylake-openclaw 0.0.14 → 0.0.15-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +118 -3
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -68,6 +68,52 @@ interface MemoryItem {
|
|
|
68
68
|
user_id?: string;
|
|
69
69
|
created_at?: string;
|
|
70
70
|
updated_at?: string;
|
|
71
|
+
has_unresolved_conflict?: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface ConflictMemorySnapshot {
|
|
75
|
+
memory_id: string;
|
|
76
|
+
memory_history_id?: string;
|
|
77
|
+
memory_text: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface ConflictFileChunk {
|
|
81
|
+
chunk: { type?: string; text: string; range?: string };
|
|
82
|
+
document_id?: string;
|
|
83
|
+
document_name?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
interface ConflictResolve {
|
|
87
|
+
id: string;
|
|
88
|
+
strategy: string;
|
|
89
|
+
keep_memory_id?: string;
|
|
90
|
+
forgotten_memory_ids?: string[];
|
|
91
|
+
resolved_by?: string;
|
|
92
|
+
created_at?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface ConflictItem {
|
|
96
|
+
id: string;
|
|
97
|
+
name: string;
|
|
98
|
+
description: string;
|
|
99
|
+
category: "m2m" | "m2d";
|
|
100
|
+
conflict_type: "logical" | "knowledge";
|
|
101
|
+
memory_ids: string[];
|
|
102
|
+
memory_snapshots: ConflictMemorySnapshot[];
|
|
103
|
+
file_chunks: ConflictFileChunk[];
|
|
104
|
+
resolved: boolean;
|
|
105
|
+
resolve?: ConflictResolve;
|
|
106
|
+
stale?: boolean;
|
|
107
|
+
event_id?: string;
|
|
108
|
+
created_at?: string;
|
|
109
|
+
updated_at?: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
interface ConflictListResponse {
|
|
113
|
+
items: ConflictItem[];
|
|
114
|
+
page: number;
|
|
115
|
+
total: number;
|
|
116
|
+
page_size: number;
|
|
71
117
|
}
|
|
72
118
|
|
|
73
119
|
interface AddResultItem {
|
|
@@ -250,6 +296,7 @@ interface MemoryLakeProvider {
|
|
|
250
296
|
searchWeb(query: string, options: WebSearchOptions): Promise<WebSearchResponse>;
|
|
251
297
|
searchOpenData(query: string, options: OpenDataSearchOptions): Promise<OpenDataSearchResponse>;
|
|
252
298
|
getProject(): Promise<ProjectInfo>;
|
|
299
|
+
listConflicts(memoryIds: string[], userId: string): Promise<ConflictItem[]>;
|
|
253
300
|
}
|
|
254
301
|
|
|
255
302
|
// ============================================================================
|
|
@@ -270,14 +317,17 @@ class PlatformProvider implements MemoryLakeProvider {
|
|
|
270
317
|
private readonly webSearchPath: string;
|
|
271
318
|
private readonly openDataSearchPath: string;
|
|
272
319
|
private readonly projectPath: string;
|
|
273
|
-
|
|
320
|
+
private readonly conflictsPath: string;
|
|
321
|
+
private readonly projectId: string;
|
|
274
322
|
|
|
275
323
|
constructor(host: string, apiKey: string, projectId: string) {
|
|
324
|
+
this.projectId = projectId;
|
|
276
325
|
this.basePath = `openapi/memorylake/api/v2/projects/${projectId}/memories`;
|
|
277
326
|
this.docSearchPath = `openapi/memorylake/api/v1/projects/${projectId}/documents/search`;
|
|
278
327
|
this.webSearchPath = "openapi/memorylake/api/v1/search";
|
|
279
328
|
this.openDataSearchPath = "openapi/memorylake/api/v1/search/opendata";
|
|
280
329
|
this.projectPath = `openapi/memorylake/api/v1/projects/${projectId}`;
|
|
330
|
+
this.conflictsPath = `openapi/memorylake/api/v2/projects/${projectId}/memories/conflicts`;
|
|
281
331
|
this.http = got.extend({
|
|
282
332
|
prefixUrl: host,
|
|
283
333
|
headers: {
|
|
@@ -310,6 +360,7 @@ class PlatformProvider implements MemoryLakeProvider {
|
|
|
310
360
|
const body: Record<string, unknown> = {
|
|
311
361
|
query,
|
|
312
362
|
user_id: options.user_id,
|
|
363
|
+
with_conflicts: true,
|
|
313
364
|
};
|
|
314
365
|
if (options.top_k != null) body.top_k = options.top_k;
|
|
315
366
|
if (options.threshold != null) body.threshold = options.threshold;
|
|
@@ -422,6 +473,23 @@ class PlatformProvider implements MemoryLakeProvider {
|
|
|
422
473
|
return info;
|
|
423
474
|
}
|
|
424
475
|
|
|
476
|
+
async listConflicts(memoryIds: string[], userId: string): Promise<ConflictItem[]> {
|
|
477
|
+
if (memoryIds.length === 0) return [];
|
|
478
|
+
const searchParams: Record<string, string> = {
|
|
479
|
+
resolved: "false",
|
|
480
|
+
memory_ids: memoryIds.join(","),
|
|
481
|
+
};
|
|
482
|
+
const resp = await this.http
|
|
483
|
+
.get(this.conflictsPath, {
|
|
484
|
+
searchParams,
|
|
485
|
+
headers: { "X-User-ID": userId },
|
|
486
|
+
})
|
|
487
|
+
.json<ApiResponse<ConflictListResponse>>();
|
|
488
|
+
if (!resp.success) throw new Error(resp.message ?? "list conflicts failed");
|
|
489
|
+
const data = resp.data;
|
|
490
|
+
return Array.isArray(data?.items) ? data.items : [];
|
|
491
|
+
}
|
|
492
|
+
|
|
425
493
|
}
|
|
426
494
|
|
|
427
495
|
// ============================================================================
|
|
@@ -435,6 +503,7 @@ function normalizeMemoryItem(raw: any): MemoryItem {
|
|
|
435
503
|
user_id: raw.user_id,
|
|
436
504
|
created_at: raw.created_at,
|
|
437
505
|
updated_at: raw.updated_at,
|
|
506
|
+
has_unresolved_conflict: raw.has_unresolved_conflict ?? false,
|
|
438
507
|
};
|
|
439
508
|
}
|
|
440
509
|
|
|
@@ -548,6 +617,24 @@ function buildWebSearchContext(results: WebSearchResult[]): string {
|
|
|
548
617
|
.join("\n\n");
|
|
549
618
|
}
|
|
550
619
|
|
|
620
|
+
function buildConflictContext(conflicts: ConflictItem[], maxChunkLength = 200): string {
|
|
621
|
+
return conflicts
|
|
622
|
+
.map((c) => {
|
|
623
|
+
const parts: string[] = [
|
|
624
|
+
`- [${c.conflict_type}] ${c.description}`,
|
|
625
|
+
];
|
|
626
|
+
for (const snap of c.memory_snapshots ?? []) {
|
|
627
|
+
parts.push(` Memory(${snap.memory_id}): ${snap.memory_text.slice(0, maxChunkLength)}`);
|
|
628
|
+
}
|
|
629
|
+
for (const fc of c.file_chunks ?? []) {
|
|
630
|
+
const docLabel = fc.document_name ?? fc.document_id ?? "unknown";
|
|
631
|
+
parts.push(` Document(${docLabel}): ${fc.chunk.text.slice(0, maxChunkLength)}`);
|
|
632
|
+
}
|
|
633
|
+
return parts.join("\n");
|
|
634
|
+
})
|
|
635
|
+
.join("\n");
|
|
636
|
+
}
|
|
637
|
+
|
|
551
638
|
function buildOpenDataContext(results: OpenDataSearchResult[]): string {
|
|
552
639
|
const filtered = results.map((r) => {
|
|
553
640
|
const item: Record<string, unknown> = {};
|
|
@@ -1774,15 +1861,40 @@ const memoryPlugin = {
|
|
|
1774
1861
|
const contextParts: string[] = [];
|
|
1775
1862
|
|
|
1776
1863
|
if (memoryResult.status === "fulfilled" && memoryResult.value.length > 0) {
|
|
1777
|
-
const
|
|
1864
|
+
const memories = memoryResult.value;
|
|
1865
|
+
const memoryContext = memories
|
|
1778
1866
|
.map((r) => `- ${r.content}`)
|
|
1779
1867
|
.join("\n");
|
|
1780
1868
|
contextParts.push(
|
|
1781
1869
|
`<relevant-memories>\nThe following memories may be relevant to this conversation:\n${memoryContext}\n</relevant-memories>`,
|
|
1782
1870
|
);
|
|
1783
1871
|
api.logger.info(
|
|
1784
|
-
`memorylake-openclaw: injecting ${
|
|
1872
|
+
`memorylake-openclaw: injecting ${memories.length} memories into context`,
|
|
1785
1873
|
);
|
|
1874
|
+
|
|
1875
|
+
// Fetch conflict details for memories flagged with unresolved conflicts
|
|
1876
|
+
const conflictedIds = memories
|
|
1877
|
+
.filter((m) => m.has_unresolved_conflict)
|
|
1878
|
+
.map((m) => m.id);
|
|
1879
|
+
if (conflictedIds.length > 0) {
|
|
1880
|
+
try {
|
|
1881
|
+
const conflicts = await effectiveProvider.listConflicts(conflictedIds, effectiveCfg.userId);
|
|
1882
|
+
if (conflicts.length > 0) {
|
|
1883
|
+
const conflictContext = buildConflictContext(conflicts);
|
|
1884
|
+
contextParts.push(
|
|
1885
|
+
`<memory-conflicts>\nThe following conflicts exist among the recalled memories. ` +
|
|
1886
|
+
`Consider these contradictions when using the above memories.\n` +
|
|
1887
|
+
`If you have not already informed the user about these conflicts in this conversation, briefly mention that some recalled memories contain contradictions and note which points are uncertain. Do not repeat this notice if you have already done so.\n` +
|
|
1888
|
+
`${conflictContext}\n</memory-conflicts>`,
|
|
1889
|
+
);
|
|
1890
|
+
api.logger.info(
|
|
1891
|
+
`memorylake-openclaw: injecting ${conflicts.length} memory conflicts into context`,
|
|
1892
|
+
);
|
|
1893
|
+
}
|
|
1894
|
+
} catch (err) {
|
|
1895
|
+
api.logger.warn(`memorylake-openclaw: conflict fetch failed: ${String(err)}`);
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1786
1898
|
} else if (memoryResult.status === "rejected") {
|
|
1787
1899
|
api.logger.warn(`memorylake-openclaw: memory recall failed: ${String(memoryResult.reason)}`);
|
|
1788
1900
|
}
|
|
@@ -1880,6 +1992,9 @@ const memoryPlugin = {
|
|
|
1880
1992
|
if (textContent.includes("<relevant-memories>")) {
|
|
1881
1993
|
textContent = textContent.replace(/<relevant-memories>[\s\S]*?<\/relevant-memories>\s*/g, "").trim();
|
|
1882
1994
|
}
|
|
1995
|
+
if (textContent.includes("<memory-conflicts>")) {
|
|
1996
|
+
textContent = textContent.replace(/<memory-conflicts>[\s\S]*?<\/memory-conflicts>\s*/g, "").trim();
|
|
1997
|
+
}
|
|
1883
1998
|
if (textContent.includes("<relevant-documents>")) {
|
|
1884
1999
|
textContent = textContent.replace(/<relevant-documents>[\s\S]*?<\/relevant-documents>\s*/g, "").trim();
|
|
1885
2000
|
}
|