memory-search-plugin 0.3.0 → 0.5.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/gateway-client.ts +42 -0
- package/index.ts +145 -11
- package/package.json +1 -1
package/gateway-client.ts
CHANGED
|
@@ -57,6 +57,31 @@ export interface MemoryGetResponse {
|
|
|
57
57
|
path: string;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
export interface MemoryRawSnapshotsRequest {
|
|
61
|
+
release_name: string;
|
|
62
|
+
start_time: string; // ISO 8601
|
|
63
|
+
end_time: string; // ISO 8601
|
|
64
|
+
path_prefix?: string; // e.g. "memory/"
|
|
65
|
+
page?: number;
|
|
66
|
+
page_size?: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface MemoryRawSnapshot {
|
|
70
|
+
id: string;
|
|
71
|
+
path: string;
|
|
72
|
+
content: string;
|
|
73
|
+
release_name: string;
|
|
74
|
+
synced_at: string;
|
|
75
|
+
[key: string]: unknown;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface MemoryRawSnapshotsResponse {
|
|
79
|
+
records: MemoryRawSnapshot[];
|
|
80
|
+
total: number;
|
|
81
|
+
page: number;
|
|
82
|
+
page_size: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
60
85
|
// ── Gateway Client ─────────────────────────────────────
|
|
61
86
|
|
|
62
87
|
export interface GatewayClientConfig {
|
|
@@ -67,6 +92,7 @@ export interface GatewayClientConfig {
|
|
|
67
92
|
export interface GatewayClient {
|
|
68
93
|
callGatewaySearch(options: MemorySearchRequest): Promise<MemorySearchResponse>;
|
|
69
94
|
callGatewayGet(options: MemoryGetRequest): Promise<MemoryGetResponse>;
|
|
95
|
+
callGatewayRawSnapshots(options: MemoryRawSnapshotsRequest): Promise<MemoryRawSnapshotsResponse>;
|
|
70
96
|
}
|
|
71
97
|
|
|
72
98
|
export function createGatewayClient(config: GatewayClientConfig): GatewayClient {
|
|
@@ -109,5 +135,21 @@ export function createGatewayClient(config: GatewayClientConfig): GatewayClient
|
|
|
109
135
|
}
|
|
110
136
|
return response.json() as Promise<MemoryGetResponse>;
|
|
111
137
|
},
|
|
138
|
+
|
|
139
|
+
async callGatewayRawSnapshots(options) {
|
|
140
|
+
const url = `${baseUrl}/api/memory/raw_snapshots`;
|
|
141
|
+
const response = await fetch(url, {
|
|
142
|
+
method: "POST",
|
|
143
|
+
headers: { "Content-Type": "application/json", ...authHeaders },
|
|
144
|
+
body: JSON.stringify(options),
|
|
145
|
+
});
|
|
146
|
+
if (!response.ok) {
|
|
147
|
+
const errorBody = await response.text().catch(() => "");
|
|
148
|
+
throw new Error(
|
|
149
|
+
`Gateway raw_snapshots failed: ${response.status} ${response.statusText} ${errorBody}`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
return response.json() as Promise<MemoryRawSnapshotsResponse>;
|
|
153
|
+
},
|
|
112
154
|
};
|
|
113
155
|
}
|
package/index.ts
CHANGED
|
@@ -28,7 +28,7 @@ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
|
28
28
|
import { createGatewayClient } from "./gateway-client";
|
|
29
29
|
import { resolveIdentityFromParams, resolveIdentity, extractAgentId } from "./identity";
|
|
30
30
|
import type { IdentityParams } from "./identity";
|
|
31
|
-
import type { MemorySearchResult } from "./gateway-client";
|
|
31
|
+
import type { MemorySearchResult, MemoryRawSnapshot } from "./gateway-client";
|
|
32
32
|
|
|
33
33
|
// ── Prompt Section ──────────────────────────────────────
|
|
34
34
|
// 告诉 LLM 如何使用 memory 工具(和 memory-core 的逻辑一致)
|
|
@@ -87,7 +87,7 @@ const buildPromptSection = ({
|
|
|
87
87
|
return lines;
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
-
// ── 路径判断
|
|
90
|
+
// ── 路径判断 ────────────────────────────────────────────
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
93
|
* 判断是否是 MEMORY 路径
|
|
@@ -136,6 +136,23 @@ function formatSearchResults(results: MemorySearchResult[]): string {
|
|
|
136
136
|
.join("\n\n");
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
/**
|
|
140
|
+
* 将 raw_snapshots 查询结果格式化为可读文本
|
|
141
|
+
* 包含 path、synced_at、release_name 和内容摘要
|
|
142
|
+
*/
|
|
143
|
+
function formatRawSnapshots(records: MemoryRawSnapshot[]): string {
|
|
144
|
+
if (records.length === 0) {
|
|
145
|
+
return "No matching raw snapshot records found.";
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return records
|
|
149
|
+
.map((r, i) => {
|
|
150
|
+
const header = `[${i + 1}] path: ${r.path} | release: ${r.release_name} | synced_at: ${r.synced_at}`;
|
|
151
|
+
return `${header}\n${r.content}`;
|
|
152
|
+
})
|
|
153
|
+
.join("\n\n");
|
|
154
|
+
}
|
|
155
|
+
|
|
139
156
|
// ── 插件定义 ────────────────────────────────────────────
|
|
140
157
|
|
|
141
158
|
export default definePluginEntry({
|
|
@@ -270,7 +287,7 @@ export default definePluginEntry({
|
|
|
270
287
|
|
|
271
288
|
try {
|
|
272
289
|
const fallbackTool =
|
|
273
|
-
api.runtime
|
|
290
|
+
api.runtime?.tools?.createMemorySearchTool({
|
|
274
291
|
config: ctx.config,
|
|
275
292
|
agentSessionKey: ctx.sessionKey,
|
|
276
293
|
});
|
|
@@ -309,12 +326,6 @@ export default definePluginEntry({
|
|
|
309
326
|
const fallbackIdentity = ctx.sessionKey ? resolveIdentity(ctx.sessionKey) : null;
|
|
310
327
|
const fallbackAgentId = ctx.sessionKey ? extractAgentId(ctx.sessionKey) : null;
|
|
311
328
|
|
|
312
|
-
// 获取原始 memory_get 实现,用于非 MEMORY 路径的 passthrough
|
|
313
|
-
const originalGetTool = api.runtime.tools.createMemoryGetTool({
|
|
314
|
-
config: ctx.config,
|
|
315
|
-
agentSessionKey: ctx.sessionKey,
|
|
316
|
-
});
|
|
317
|
-
|
|
318
329
|
return {
|
|
319
330
|
name: "memory_get",
|
|
320
331
|
description:
|
|
@@ -376,6 +387,17 @@ export default definePluginEntry({
|
|
|
376
387
|
};
|
|
377
388
|
}
|
|
378
389
|
|
|
390
|
+
// 懒加载原始 memory_get 实现,用于非 MEMORY 路径的 passthrough
|
|
391
|
+
let originalGetTool: any = null;
|
|
392
|
+
try {
|
|
393
|
+
originalGetTool = api.runtime?.tools?.createMemoryGetTool({
|
|
394
|
+
config: ctx.config,
|
|
395
|
+
agentSessionKey: ctx.sessionKey,
|
|
396
|
+
});
|
|
397
|
+
} catch {
|
|
398
|
+
// memory-core 被替换后 api.runtime.tools 不可用,忽略
|
|
399
|
+
}
|
|
400
|
+
|
|
379
401
|
// ── 路径分流 ──
|
|
380
402
|
if (isMemoryPath(path)) {
|
|
381
403
|
const agentId = params.agent_id?.trim() || fallbackAgentId || "main";
|
|
@@ -460,11 +482,123 @@ export default definePluginEntry({
|
|
|
460
482
|
);
|
|
461
483
|
|
|
462
484
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
463
|
-
// 4.
|
|
485
|
+
// 4. 注册 memory_raw_snapshots_query → 查询 memory_raw_snapshots 表
|
|
486
|
+
// 按 synced_at 时间段 + path 为 memory/xxx + release_name 过滤
|
|
487
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
488
|
+
api.registerTool(
|
|
489
|
+
(_ctx: any) => {
|
|
490
|
+
return {
|
|
491
|
+
name: "memory_raw_snapshots_query",
|
|
492
|
+
description:
|
|
493
|
+
"Query raw memory snapshot records from the memory_raw_snapshots table. " +
|
|
494
|
+
"Filters by synced_at time range, release_name, and only returns records whose path starts with 'memory/' " +
|
|
495
|
+
"(excluding MEMORY.md, USER.md, etc.).",
|
|
496
|
+
parameters: {
|
|
497
|
+
type: "object" as const,
|
|
498
|
+
properties: {
|
|
499
|
+
release_name: {
|
|
500
|
+
type: "string" as const,
|
|
501
|
+
description: "The release_name to filter by (e.g. 'lobster_xxx')",
|
|
502
|
+
},
|
|
503
|
+
start_time: {
|
|
504
|
+
type: "string" as const,
|
|
505
|
+
description: "Start time in ISO 8601 format (e.g. '2025-05-01T00:00:00Z')",
|
|
506
|
+
},
|
|
507
|
+
end_time: {
|
|
508
|
+
type: "string" as const,
|
|
509
|
+
description: "End time in ISO 8601 format (e.g. '2025-05-07T23:59:59Z')",
|
|
510
|
+
},
|
|
511
|
+
page: {
|
|
512
|
+
type: "number" as const,
|
|
513
|
+
description: "Page number for pagination (default 1)",
|
|
514
|
+
},
|
|
515
|
+
page_size: {
|
|
516
|
+
type: "number" as const,
|
|
517
|
+
description: "Number of records per page (default 50, max 200)",
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
required: ["release_name", "start_time", "end_time"],
|
|
521
|
+
},
|
|
522
|
+
|
|
523
|
+
async execute(
|
|
524
|
+
_toolCallId: string,
|
|
525
|
+
params: {
|
|
526
|
+
release_name?: string;
|
|
527
|
+
start_time?: string;
|
|
528
|
+
end_time?: string;
|
|
529
|
+
page?: number;
|
|
530
|
+
page_size?: number;
|
|
531
|
+
}
|
|
532
|
+
) {
|
|
533
|
+
const releaseName = params.release_name?.trim() || "";
|
|
534
|
+
const startTime = params.start_time?.trim() || "";
|
|
535
|
+
const endTime = params.end_time?.trim() || "";
|
|
536
|
+
|
|
537
|
+
if (!releaseName || !startTime || !endTime) {
|
|
538
|
+
return {
|
|
539
|
+
content: [
|
|
540
|
+
{
|
|
541
|
+
type: "text" as const,
|
|
542
|
+
text: "Missing required parameters: release_name, start_time, and end_time are all required.",
|
|
543
|
+
},
|
|
544
|
+
],
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
console.log(
|
|
549
|
+
`[memory-search-plugin] raw_snapshots_query: release_name=${releaseName} ` +
|
|
550
|
+
`start_time=${startTime} end_time=${endTime} page=${params.page || 1} page_size=${params.page_size || 50}`
|
|
551
|
+
);
|
|
552
|
+
|
|
553
|
+
try {
|
|
554
|
+
const data = await gateway.callGatewayRawSnapshots({
|
|
555
|
+
release_name: releaseName,
|
|
556
|
+
start_time: startTime,
|
|
557
|
+
end_time: endTime,
|
|
558
|
+
path_prefix: "memory/",
|
|
559
|
+
page: params.page || 1,
|
|
560
|
+
page_size: params.page_size || 50,
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
const text = formatRawSnapshots(data.records);
|
|
564
|
+
const summary = `Found ${data.total} record(s) (page ${data.page}, page_size ${data.page_size}).\n\n${text}`;
|
|
565
|
+
|
|
566
|
+
return {
|
|
567
|
+
content: [{ type: "text" as const, text: summary }],
|
|
568
|
+
details: {
|
|
569
|
+
records: data.records,
|
|
570
|
+
total: data.total,
|
|
571
|
+
page: data.page,
|
|
572
|
+
page_size: data.page_size,
|
|
573
|
+
},
|
|
574
|
+
};
|
|
575
|
+
} catch (err: any) {
|
|
576
|
+
console.error("[memory-search-plugin] raw_snapshots_query failed:", err.message);
|
|
577
|
+
return {
|
|
578
|
+
content: [
|
|
579
|
+
{
|
|
580
|
+
type: "text" as const,
|
|
581
|
+
text: `Raw snapshots query failed: ${err.message}`,
|
|
582
|
+
},
|
|
583
|
+
],
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
};
|
|
588
|
+
},
|
|
589
|
+
{ names: ["memory_raw_snapshots_query"] }
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
593
|
+
// 5. 保留 CLI 命令(和 memory-core 一致)
|
|
464
594
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
465
595
|
api.registerCli(
|
|
466
596
|
({ program }: any) => {
|
|
467
|
-
|
|
597
|
+
try {
|
|
598
|
+
api.runtime?.tools?.registerMemoryCli(program);
|
|
599
|
+
} catch {
|
|
600
|
+
// memory-core 被替换后 api.runtime.tools 不可用,忽略
|
|
601
|
+
}
|
|
468
602
|
},
|
|
469
603
|
{ commands: ["memory"] }
|
|
470
604
|
);
|