@ynhcj/xiaoyi-channel 0.0.192-beta → 0.0.193-beta
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.
|
@@ -39,15 +39,18 @@ export async function handleMemoryQueryEvent(context, cfg) {
|
|
|
39
39
|
let result;
|
|
40
40
|
try {
|
|
41
41
|
switch (action) {
|
|
42
|
-
case "
|
|
42
|
+
case "MemoryStateSet":
|
|
43
43
|
result = handleMemoryStateSet(params);
|
|
44
44
|
break;
|
|
45
|
-
case "
|
|
45
|
+
case "UserMdQuery":
|
|
46
46
|
result = handleUserMdQuery();
|
|
47
47
|
break;
|
|
48
|
-
case "
|
|
48
|
+
case "MemoryMdQuery":
|
|
49
49
|
result = handleMemoryMdQuery();
|
|
50
50
|
break;
|
|
51
|
+
case "MemoryHistory":
|
|
52
|
+
result = handleMemoryHistory();
|
|
53
|
+
break;
|
|
51
54
|
default:
|
|
52
55
|
log.error(`[MEMORY-QUERY] Unknown action: ${action}`);
|
|
53
56
|
result = { error: `Unknown action: ${action}` };
|
|
@@ -66,7 +69,7 @@ export async function handleMemoryQueryEvent(context, cfg) {
|
|
|
66
69
|
const command = {
|
|
67
70
|
header: {
|
|
68
71
|
namespace: "AgentEvent",
|
|
69
|
-
name: "
|
|
72
|
+
name: "MemoryQuery",
|
|
70
73
|
},
|
|
71
74
|
payload: {
|
|
72
75
|
action,
|
|
@@ -162,3 +165,86 @@ function readMdFile(filePath) {
|
|
|
162
165
|
return { fileDetail: "" };
|
|
163
166
|
}
|
|
164
167
|
}
|
|
168
|
+
const MEMORY_LOG_PATH = path.join(os.homedir(), ".openclaw", ".memory.log");
|
|
169
|
+
const MEMORY_HISTORY_DAYS = 7;
|
|
170
|
+
const MEMORY_RETENTION_DAYS = 30;
|
|
171
|
+
/**
|
|
172
|
+
* Read ~/.openclaw/.memory.log, return last 7 days grouped by date,
|
|
173
|
+
* then prune entries older than 30 days.
|
|
174
|
+
*
|
|
175
|
+
* Log line format: `2026-06-22T15:18:00|user.md|更新了xxxx`
|
|
176
|
+
* Only split on the first two `|`; everything after is the detail
|
|
177
|
+
* (detail itself may contain `|`).
|
|
178
|
+
*/
|
|
179
|
+
function handleMemoryHistory() {
|
|
180
|
+
let content;
|
|
181
|
+
try {
|
|
182
|
+
content = readFileSync(MEMORY_LOG_PATH, "utf-8");
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
if (err.code === "ENOENT") {
|
|
186
|
+
logger.log(`[MEMORY-QUERY] memory.log not found: ${MEMORY_LOG_PATH}`);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
logger.error(`[MEMORY-QUERY] Failed to read memory.log:`, err);
|
|
190
|
+
}
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
const lines = content.split("\n");
|
|
194
|
+
const now = new Date();
|
|
195
|
+
const historySince = new Date(now);
|
|
196
|
+
historySince.setDate(now.getDate() - (MEMORY_HISTORY_DAYS - 1));
|
|
197
|
+
historySince.setHours(0, 0, 0, 0);
|
|
198
|
+
const retentionSince = new Date(now);
|
|
199
|
+
retentionSince.setDate(now.getDate() - (MEMORY_RETENTION_DAYS - 1));
|
|
200
|
+
retentionSince.setHours(0, 0, 0, 0);
|
|
201
|
+
const byDate = new Map();
|
|
202
|
+
const keptLines = [];
|
|
203
|
+
for (const raw of lines) {
|
|
204
|
+
const line = raw.trimEnd();
|
|
205
|
+
if (!line)
|
|
206
|
+
continue;
|
|
207
|
+
// Split on only the first two `|`; rest is detail (may contain `|`).
|
|
208
|
+
const firstPipe = line.indexOf("|");
|
|
209
|
+
if (firstPipe === -1)
|
|
210
|
+
continue;
|
|
211
|
+
const secondPipe = line.indexOf("|", firstPipe + 1);
|
|
212
|
+
if (secondPipe === -1)
|
|
213
|
+
continue;
|
|
214
|
+
const timestamp = line.slice(0, firstPipe);
|
|
215
|
+
const fileName = line.slice(firstPipe + 1, secondPipe);
|
|
216
|
+
const detail = line.slice(secondPipe + 1);
|
|
217
|
+
// timestamp format: 2026-06-22T15:18:00
|
|
218
|
+
const datePart = timestamp.slice(0, 10);
|
|
219
|
+
const timePart = timestamp.slice(11, 19);
|
|
220
|
+
const entryDate = new Date(`${datePart}T00:00:00`);
|
|
221
|
+
// Retain log lines within the 30-day window.
|
|
222
|
+
if (!isNaN(entryDate.getTime()) && entryDate >= retentionSince) {
|
|
223
|
+
keptLines.push(line);
|
|
224
|
+
}
|
|
225
|
+
// Include in response if within the 7-day window.
|
|
226
|
+
if (!isNaN(entryDate.getTime()) && entryDate >= historySince) {
|
|
227
|
+
let bucket = byDate.get(datePart);
|
|
228
|
+
if (!bucket) {
|
|
229
|
+
bucket = [];
|
|
230
|
+
byDate.set(datePart, bucket);
|
|
231
|
+
}
|
|
232
|
+
bucket.push({ fileName, detail, time: timePart });
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Build ans array sorted by date ascending, each entry is { <date>: [...] }.
|
|
236
|
+
const ans = Array.from(byDate.keys())
|
|
237
|
+
.sort()
|
|
238
|
+
.map((dateStr) => ({ [dateStr]: byDate.get(dateStr) }));
|
|
239
|
+
// Prune memory.log: keep only the last 30 days.
|
|
240
|
+
try {
|
|
241
|
+
const newContent = keptLines.length > 0 ? `${keptLines.join("\n")}\n` : "";
|
|
242
|
+
writeFileSync(MEMORY_LOG_PATH, newContent, "utf-8");
|
|
243
|
+
logger.log(`[MEMORY-QUERY] Pruned memory.log, kept ${keptLines.length} entries (>= ${retentionSince.toISOString().slice(0, 10)})`);
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
logger.error(`[MEMORY-QUERY] Failed to prune memory.log:`, err);
|
|
247
|
+
}
|
|
248
|
+
logger.log(`[MEMORY-QUERY] MemoryHistory: returning ${ans.length} date buckets`);
|
|
249
|
+
return ans;
|
|
250
|
+
}
|
package/dist/src/websocket.js
CHANGED
|
@@ -630,8 +630,8 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
630
630
|
messageId: a2aRequest.id,
|
|
631
631
|
});
|
|
632
632
|
}
|
|
633
|
-
else if (item.header?.namespace === "AgentEvent" && item.header?.name === "
|
|
634
|
-
log.log("[XY] AgentEvent.
|
|
633
|
+
else if (item.header?.namespace === "AgentEvent" && item.header?.name === "MemoryQuery") {
|
|
634
|
+
log.log("[XY] AgentEvent.MemoryQuery detected, emitting memory-query-event");
|
|
635
635
|
this.emit("memory-query-event", {
|
|
636
636
|
...(item.payload ?? {}),
|
|
637
637
|
sessionId,
|
|
@@ -728,8 +728,8 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
728
728
|
messageId: a2aRequest.id,
|
|
729
729
|
});
|
|
730
730
|
}
|
|
731
|
-
else if (item.header?.namespace === "AgentEvent" && item.header?.name === "
|
|
732
|
-
log.log("[XY] AgentEvent.
|
|
731
|
+
else if (item.header?.namespace === "AgentEvent" && item.header?.name === "MemoryQuery") {
|
|
732
|
+
log.log("[XY] AgentEvent.MemoryQuery detected (wrapped format), emitting memory-query-event");
|
|
733
733
|
this.emit("memory-query-event", {
|
|
734
734
|
...(item.payload ?? {}),
|
|
735
735
|
sessionId: inboundMsg.sessionId || a2aRequest.params?.sessionId,
|