memory-search-plugin 1.3.5 → 1.3.7
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 +0 -2
- package/identity.ts +7 -18
- package/index.js +11 -45
- package/index.ts +8 -44
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/gateway-client.ts
CHANGED
|
@@ -4,7 +4,6 @@ import type { Scene } from "./identity";
|
|
|
4
4
|
|
|
5
5
|
export interface MemorySearchRequest {
|
|
6
6
|
owner_id: string;
|
|
7
|
-
sender_id: string;
|
|
8
7
|
agent_id: string;
|
|
9
8
|
query: string;
|
|
10
9
|
scene: Scene;
|
|
@@ -34,7 +33,6 @@ export interface MemorySearchResponse {
|
|
|
34
33
|
|
|
35
34
|
export interface MemoryGetRequest {
|
|
36
35
|
owner_id: string;
|
|
37
|
-
sender_id: string;
|
|
38
36
|
agent_id: string;
|
|
39
37
|
keyword: string;
|
|
40
38
|
scene: Scene;
|
package/identity.ts
CHANGED
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 身份解析模块
|
|
2
|
+
* 身份解析模块
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* knowledge 场景由特定工具调用或 LLM 判断触发
|
|
4
|
+
* group_id 有值 → scene = "group"
|
|
5
|
+
* group_id 无值 → scene = "owner"
|
|
7
6
|
*
|
|
8
|
-
* owner_id 用于 SQL
|
|
9
|
-
* 不依赖任何环境变量兜底。
|
|
7
|
+
* owner_id 用于 SQL 数据隔离。
|
|
10
8
|
*/
|
|
11
9
|
|
|
12
10
|
export type Scene = "owner" | "group" | "knowledge";
|
|
13
11
|
|
|
14
12
|
export interface ResolvedIdentity {
|
|
15
13
|
scene: Scene;
|
|
16
|
-
sender_id: string;
|
|
17
14
|
owner_id: string;
|
|
18
15
|
group_id: string | null;
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
export interface IdentityParams {
|
|
22
|
-
sender_id?: string;
|
|
23
19
|
owner_id?: string;
|
|
24
|
-
conversation_type?: string;
|
|
25
20
|
group_id?: string;
|
|
26
21
|
}
|
|
27
22
|
|
|
@@ -30,15 +25,12 @@ export function resolveIdentity(params: IdentityParams): ResolvedIdentity {
|
|
|
30
25
|
if (testScene) {
|
|
31
26
|
return {
|
|
32
27
|
scene: testScene,
|
|
33
|
-
sender_id: process.env.MEMORY_GATEWAY_TEST_USER_ID || "test_user",
|
|
34
28
|
owner_id: process.env.MEMORY_GATEWAY_TEST_OWNER_ID || "test_owner",
|
|
35
29
|
group_id: process.env.MEMORY_GATEWAY_TEST_GROUP_ID || null,
|
|
36
30
|
};
|
|
37
31
|
}
|
|
38
32
|
|
|
39
|
-
const senderId = params.sender_id?.trim() || "unknown";
|
|
40
33
|
const ownerId = params.owner_id?.trim() || "";
|
|
41
|
-
const convType = (params.conversation_type || "direct").trim().toLowerCase();
|
|
42
34
|
const groupId = params.group_id?.trim() || null;
|
|
43
35
|
|
|
44
36
|
if (!ownerId) {
|
|
@@ -48,12 +40,9 @@ export function resolveIdentity(params: IdentityParams): ResolvedIdentity {
|
|
|
48
40
|
);
|
|
49
41
|
}
|
|
50
42
|
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
console.warn("[identity] group scene but group_id is empty");
|
|
54
|
-
}
|
|
55
|
-
return { scene: "group", sender_id: senderId, owner_id: ownerId, group_id: groupId };
|
|
43
|
+
if (groupId) {
|
|
44
|
+
return { scene: "group", owner_id: ownerId, group_id: groupId };
|
|
56
45
|
}
|
|
57
46
|
|
|
58
|
-
return { scene: "owner",
|
|
47
|
+
return { scene: "owner", owner_id: ownerId, group_id: null };
|
|
59
48
|
}
|
package/index.js
CHANGED
|
@@ -6,27 +6,21 @@ function resolveIdentity(params) {
|
|
|
6
6
|
if (testScene) {
|
|
7
7
|
return {
|
|
8
8
|
scene: testScene,
|
|
9
|
-
sender_id: process.env.MEMORY_GATEWAY_TEST_USER_ID || "test_user",
|
|
10
9
|
owner_id: process.env.MEMORY_GATEWAY_TEST_OWNER_ID || "test_owner",
|
|
11
10
|
group_id: process.env.MEMORY_GATEWAY_TEST_GROUP_ID || null
|
|
12
11
|
};
|
|
13
12
|
}
|
|
14
|
-
const senderId = params.sender_id?.trim() || "unknown";
|
|
15
13
|
const ownerId = params.owner_id?.trim() || "";
|
|
16
|
-
const convType = (params.conversation_type || "direct").trim().toLowerCase();
|
|
17
14
|
const groupId = params.group_id?.trim() || null;
|
|
18
15
|
if (!ownerId) {
|
|
19
16
|
console.warn(
|
|
20
17
|
"[identity] owner_id is empty — LLM failed to extract from UntrustedContext. owner queries will be skipped to prevent cross-user leak."
|
|
21
18
|
);
|
|
22
19
|
}
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
console.warn("[identity] group scene but group_id is empty");
|
|
26
|
-
}
|
|
27
|
-
return { scene: "group", sender_id: senderId, owner_id: ownerId, group_id: groupId };
|
|
20
|
+
if (groupId) {
|
|
21
|
+
return { scene: "group", owner_id: ownerId, group_id: groupId };
|
|
28
22
|
}
|
|
29
|
-
return { scene: "owner",
|
|
23
|
+
return { scene: "owner", owner_id: ownerId, group_id: null };
|
|
30
24
|
}
|
|
31
25
|
|
|
32
26
|
// gateway-client.ts
|
|
@@ -63,14 +57,8 @@ var buildPromptSection = ({
|
|
|
63
57
|
const hasGet = availableTools.has("memory_get");
|
|
64
58
|
if (!hasSearch && !hasGet) return [];
|
|
65
59
|
const lines = [
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"在调用 `memory_search` 或 `memory_get` 时,必须从 `UntrustedContext` 部分提取以下字段并作为参数传递:`owner_id`、`conversation_type`、`group_id`。查找类似 `owner_id: xxx`、`group_id: xxx` 的内容。如果某个字段不存在,则省略该字段。**不要编造或猜测任何值——只能使用 `UntrustedContext` 中明确提供的内容。",
|
|
69
|
-
"## 强制性隔离规则——必须严格遵守",
|
|
70
|
-
"**规则一:参数必须完全一致。** 在同一对话中,每次调用 `memory_search` / `memory_get`,必须传入与 UntrustedContext 完全相同的 `owner_id`、`conversation_type`、`group_id`。任何时候都不得修改、遗漏或覆盖这些参数。",
|
|
71
|
-
"**规则二:群聊只能访问群组记忆。** 当 `conversation_type=group` 时,只能使用 `scene=group` 搜索。严禁将 `conversation_type` 改为 `direct` 或省略,以访问私人/owner 记忆。",
|
|
72
|
-
"**规则三:私聊使用 `scene=owner`(全局视角)。** 当 `conversation_type=direct` 时,使用 `scene=owner` 搜索。`scene=owner` 是 owner 的全局视角,服务端会返回 owner 私有记忆、所属群的群聊记忆、知识库记忆的合集。返回的所有结果无论来源(owner/group/knowledge)都可以完整展示给用户,不需要做二次过滤。",
|
|
73
|
-
"**规则四:无结果时的处理。** 若搜索无结果或相关性低,直接回复「没有找到相关记忆」,不得编造或推测。"
|
|
60
|
+
"在回答任何关于历史工作、决策、日期、人物、偏好或待办事项的问题之前:使用 `memory_search` 进行记忆语义搜索,`memory_get` 进行记忆关键字检索。如果搜索后置信度仍然较低,请说明你已经进行了检索。",
|
|
61
|
+
"调用 `memory_search` 或 `memory_get` 时,从 `UntrustedContext` 中原样提取 `owner_id`、`agent_id`、`group_id` 作为参数传递。如果 UntrustedContext 中不存在 `group_id` 字段,则不传该参数。不要编造或猜测任何值,只使用 UntrustedContext 中实际存在的字段。"
|
|
74
62
|
];
|
|
75
63
|
return lines;
|
|
76
64
|
};
|
|
@@ -98,30 +86,22 @@ var index_default = definePluginEntry({
|
|
|
98
86
|
(ctx) => {
|
|
99
87
|
return {
|
|
100
88
|
name: "memory_search",
|
|
101
|
-
description: "Semantically search memories. Extract owner_id,
|
|
89
|
+
description: "Semantically search memories. Extract owner_id, agent_id, group_id from UntrustedContext.",
|
|
102
90
|
parameters: {
|
|
103
91
|
type: "object",
|
|
104
92
|
properties: {
|
|
105
93
|
query: { type: "string", description: "The search query" },
|
|
106
94
|
owner_id: {
|
|
107
95
|
type: "string",
|
|
108
|
-
description: "The owner_id from UntrustedContext
|
|
109
|
-
},
|
|
110
|
-
sender_id: {
|
|
111
|
-
type: "string",
|
|
112
|
-
description: "The sender_id from UntrustedContext (current message sender)"
|
|
96
|
+
description: "The owner_id from UntrustedContext"
|
|
113
97
|
},
|
|
114
98
|
agent_id: {
|
|
115
99
|
type: "string",
|
|
116
100
|
description: "The agent_id from UntrustedContext"
|
|
117
101
|
},
|
|
118
|
-
conversation_type: {
|
|
119
|
-
type: "string",
|
|
120
|
-
description: "The conversation_type from UntrustedContext: 'direct' or 'group'"
|
|
121
|
-
},
|
|
122
102
|
group_id: {
|
|
123
103
|
type: "string",
|
|
124
|
-
description: "The group_id from UntrustedContext (only
|
|
104
|
+
description: "The group_id from UntrustedContext (only if present)"
|
|
125
105
|
},
|
|
126
106
|
maxResults: {
|
|
127
107
|
type: "number",
|
|
@@ -142,19 +122,16 @@ var index_default = definePluginEntry({
|
|
|
142
122
|
};
|
|
143
123
|
}
|
|
144
124
|
const identity = resolveIdentity({
|
|
145
|
-
sender_id: params.sender_id,
|
|
146
125
|
owner_id: params.owner_id,
|
|
147
|
-
conversation_type: params.conversation_type,
|
|
148
126
|
group_id: params.group_id
|
|
149
127
|
});
|
|
150
128
|
const agentId = params.agent_id?.trim() || "main";
|
|
151
129
|
console.log(
|
|
152
|
-
`[memory-search] search: agent=${agentId} scene=${identity.scene}
|
|
130
|
+
`[memory-search] search: agent=${agentId} scene=${identity.scene} owner=${identity.owner_id} group=${identity.group_id}`
|
|
153
131
|
);
|
|
154
132
|
try {
|
|
155
133
|
const data = await gateway.callGatewaySearch({
|
|
156
134
|
owner_id: identity.owner_id,
|
|
157
|
-
sender_id: identity.sender_id,
|
|
158
135
|
agent_id: agentId,
|
|
159
136
|
query,
|
|
160
137
|
scene: identity.scene,
|
|
@@ -189,7 +166,7 @@ ${r.content}`;
|
|
|
189
166
|
(ctx) => {
|
|
190
167
|
return {
|
|
191
168
|
name: "memory_get",
|
|
192
|
-
description: "Search raw chat messages by keyword.
|
|
169
|
+
description: "Search raw chat messages by keyword. Extract owner_id, agent_id, group_id from UntrustedContext.",
|
|
193
170
|
parameters: {
|
|
194
171
|
type: "object",
|
|
195
172
|
properties: {
|
|
@@ -201,21 +178,13 @@ ${r.content}`;
|
|
|
201
178
|
type: "string",
|
|
202
179
|
description: "The owner_id from UntrustedContext"
|
|
203
180
|
},
|
|
204
|
-
sender_id: {
|
|
205
|
-
type: "string",
|
|
206
|
-
description: "The sender_id from UntrustedContext"
|
|
207
|
-
},
|
|
208
181
|
agent_id: {
|
|
209
182
|
type: "string",
|
|
210
183
|
description: "The agent_id from UntrustedContext"
|
|
211
184
|
},
|
|
212
|
-
conversation_type: {
|
|
213
|
-
type: "string",
|
|
214
|
-
description: "The conversation_type from UntrustedContext: 'direct' or 'group'"
|
|
215
|
-
},
|
|
216
185
|
group_id: {
|
|
217
186
|
type: "string",
|
|
218
|
-
description: "The group_id from UntrustedContext (only
|
|
187
|
+
description: "The group_id from UntrustedContext (only if present)"
|
|
219
188
|
},
|
|
220
189
|
limit: {
|
|
221
190
|
type: "number",
|
|
@@ -232,9 +201,7 @@ ${r.content}`;
|
|
|
232
201
|
};
|
|
233
202
|
}
|
|
234
203
|
const identity = resolveIdentity({
|
|
235
|
-
sender_id: params.sender_id,
|
|
236
204
|
owner_id: params.owner_id,
|
|
237
|
-
conversation_type: params.conversation_type,
|
|
238
205
|
group_id: params.group_id
|
|
239
206
|
});
|
|
240
207
|
const agentId = params.agent_id?.trim() || "main";
|
|
@@ -244,7 +211,6 @@ ${r.content}`;
|
|
|
244
211
|
try {
|
|
245
212
|
const data = await gateway.callGatewayGet({
|
|
246
213
|
owner_id: identity.owner_id,
|
|
247
|
-
sender_id: identity.sender_id,
|
|
248
214
|
agent_id: agentId,
|
|
249
215
|
keyword,
|
|
250
216
|
scene: identity.scene,
|
package/index.ts
CHANGED
|
@@ -20,14 +20,8 @@ const buildPromptSection = ({
|
|
|
20
20
|
if (!hasSearch && !hasGet) return [];
|
|
21
21
|
|
|
22
22
|
const lines = [
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"在调用 `memory_search` 或 `memory_get` 时,必须从 `UntrustedContext` 部分提取以下字段并作为参数传递:`owner_id`、`conversation_type`、`group_id`。查找类似 `owner_id: xxx`、`group_id: xxx` 的内容。如果某个字段不存在,则省略该字段。**不要编造或猜测任何值——只能使用 `UntrustedContext` 中明确提供的内容。",
|
|
26
|
-
"## 强制性隔离规则——必须严格遵守",
|
|
27
|
-
"**规则一:参数必须完全一致。** 在同一对话中,每次调用 `memory_search` / `memory_get`,必须传入与 UntrustedContext 完全相同的 `owner_id`、`conversation_type`、`group_id`。任何时候都不得修改、遗漏或覆盖这些参数。",
|
|
28
|
-
"**规则二:群聊只能访问群组记忆。** 当 `conversation_type=group` 时,只能使用 `scene=group` 搜索。严禁将 `conversation_type` 改为 `direct` 或省略,以访问私人/owner 记忆。",
|
|
29
|
-
"**规则三:私聊使用 `scene=owner`(全局视角)。** 当 `conversation_type=direct` 时,使用 `scene=owner` 搜索。`scene=owner` 是 owner 的全局视角,服务端会返回 owner 私有记忆、所属群的群聊记忆、知识库记忆的合集。返回的所有结果无论来源(owner/group/knowledge)都可以完整展示给用户,不需要做二次过滤。",
|
|
30
|
-
"**规则四:无结果时的处理。** 若搜索无结果或相关性低,直接回复「没有找到相关记忆」,不得编造或推测。"
|
|
23
|
+
"在回答任何关于历史工作、决策、日期、人物、偏好或待办事项的问题之前:使用 `memory_search` 进行记忆语义搜索,`memory_get` 进行记忆关键字检索。如果搜索后置信度仍然较低,请说明你已经进行了检索。",
|
|
24
|
+
"调用 `memory_search` 或 `memory_get` 时,从 `UntrustedContext` 中原样提取 `owner_id`、`agent_id`、`group_id` 作为参数传递。如果 UntrustedContext 中不存在 `group_id` 字段,则不传该参数。不要编造或猜测任何值,只使用 UntrustedContext 中实际存在的字段。"
|
|
31
25
|
];
|
|
32
26
|
|
|
33
27
|
return lines;
|
|
@@ -68,32 +62,22 @@ export default definePluginEntry({
|
|
|
68
62
|
name: "memory_search",
|
|
69
63
|
description:
|
|
70
64
|
"Semantically search memories. " +
|
|
71
|
-
"Extract owner_id,
|
|
65
|
+
"Extract owner_id, agent_id, group_id from UntrustedContext.",
|
|
72
66
|
parameters: {
|
|
73
67
|
type: "object" as const,
|
|
74
68
|
properties: {
|
|
75
69
|
query: { type: "string" as const, description: "The search query" },
|
|
76
70
|
owner_id: {
|
|
77
71
|
type: "string" as const,
|
|
78
|
-
description:
|
|
79
|
-
"The owner_id from UntrustedContext (agent owner's user_id, always present)",
|
|
80
|
-
},
|
|
81
|
-
sender_id: {
|
|
82
|
-
type: "string" as const,
|
|
83
|
-
description: "The sender_id from UntrustedContext (current message sender)",
|
|
72
|
+
description: "The owner_id from UntrustedContext",
|
|
84
73
|
},
|
|
85
74
|
agent_id: {
|
|
86
75
|
type: "string" as const,
|
|
87
76
|
description: "The agent_id from UntrustedContext",
|
|
88
77
|
},
|
|
89
|
-
conversation_type: {
|
|
90
|
-
type: "string" as const,
|
|
91
|
-
description:
|
|
92
|
-
"The conversation_type from UntrustedContext: 'direct' or 'group'",
|
|
93
|
-
},
|
|
94
78
|
group_id: {
|
|
95
79
|
type: "string" as const,
|
|
96
|
-
description: "The group_id from UntrustedContext (only
|
|
80
|
+
description: "The group_id from UntrustedContext (only if present)",
|
|
97
81
|
},
|
|
98
82
|
maxResults: {
|
|
99
83
|
type: "number" as const,
|
|
@@ -112,9 +96,7 @@ export default definePluginEntry({
|
|
|
112
96
|
params: {
|
|
113
97
|
query?: string;
|
|
114
98
|
owner_id?: string;
|
|
115
|
-
sender_id?: string;
|
|
116
99
|
agent_id?: string;
|
|
117
|
-
conversation_type?: string;
|
|
118
100
|
group_id?: string;
|
|
119
101
|
maxResults?: number;
|
|
120
102
|
minScore?: number;
|
|
@@ -128,22 +110,19 @@ export default definePluginEntry({
|
|
|
128
110
|
}
|
|
129
111
|
|
|
130
112
|
const identity = resolveIdentity({
|
|
131
|
-
sender_id: params.sender_id,
|
|
132
113
|
owner_id: params.owner_id,
|
|
133
|
-
conversation_type: params.conversation_type,
|
|
134
114
|
group_id: params.group_id,
|
|
135
115
|
});
|
|
136
116
|
const agentId = params.agent_id?.trim() || "main";
|
|
137
117
|
|
|
138
118
|
console.log(
|
|
139
119
|
`[memory-search] search: agent=${agentId} scene=${identity.scene} ` +
|
|
140
|
-
`
|
|
120
|
+
`owner=${identity.owner_id} group=${identity.group_id}`
|
|
141
121
|
);
|
|
142
122
|
|
|
143
123
|
try {
|
|
144
124
|
const data = await gateway.callGatewaySearch({
|
|
145
125
|
owner_id: identity.owner_id,
|
|
146
|
-
sender_id: identity.sender_id,
|
|
147
126
|
agent_id: agentId,
|
|
148
127
|
query,
|
|
149
128
|
scene: identity.scene,
|
|
@@ -192,8 +171,7 @@ export default definePluginEntry({
|
|
|
192
171
|
name: "memory_get",
|
|
193
172
|
description:
|
|
194
173
|
"Search raw chat messages by keyword. " +
|
|
195
|
-
"
|
|
196
|
-
"Extract owner_id, sender_id, agent_id, conversation_type, group_id from UntrustedContext.",
|
|
174
|
+
"Extract owner_id, agent_id, group_id from UntrustedContext.",
|
|
197
175
|
parameters: {
|
|
198
176
|
type: "object" as const,
|
|
199
177
|
properties: {
|
|
@@ -205,22 +183,13 @@ export default definePluginEntry({
|
|
|
205
183
|
type: "string" as const,
|
|
206
184
|
description: "The owner_id from UntrustedContext",
|
|
207
185
|
},
|
|
208
|
-
sender_id: {
|
|
209
|
-
type: "string" as const,
|
|
210
|
-
description: "The sender_id from UntrustedContext",
|
|
211
|
-
},
|
|
212
186
|
agent_id: {
|
|
213
187
|
type: "string" as const,
|
|
214
188
|
description: "The agent_id from UntrustedContext",
|
|
215
189
|
},
|
|
216
|
-
conversation_type: {
|
|
217
|
-
type: "string" as const,
|
|
218
|
-
description:
|
|
219
|
-
"The conversation_type from UntrustedContext: 'direct' or 'group'",
|
|
220
|
-
},
|
|
221
190
|
group_id: {
|
|
222
191
|
type: "string" as const,
|
|
223
|
-
description: "The group_id from UntrustedContext (only
|
|
192
|
+
description: "The group_id from UntrustedContext (only if present)",
|
|
224
193
|
},
|
|
225
194
|
limit: {
|
|
226
195
|
type: "number" as const,
|
|
@@ -235,9 +204,7 @@ export default definePluginEntry({
|
|
|
235
204
|
params: {
|
|
236
205
|
keyword?: string;
|
|
237
206
|
owner_id?: string;
|
|
238
|
-
sender_id?: string;
|
|
239
207
|
agent_id?: string;
|
|
240
|
-
conversation_type?: string;
|
|
241
208
|
group_id?: string;
|
|
242
209
|
limit?: number;
|
|
243
210
|
}
|
|
@@ -250,9 +217,7 @@ export default definePluginEntry({
|
|
|
250
217
|
}
|
|
251
218
|
|
|
252
219
|
const identity = resolveIdentity({
|
|
253
|
-
sender_id: params.sender_id,
|
|
254
220
|
owner_id: params.owner_id,
|
|
255
|
-
conversation_type: params.conversation_type,
|
|
256
221
|
group_id: params.group_id,
|
|
257
222
|
});
|
|
258
223
|
const agentId = params.agent_id?.trim() || "main";
|
|
@@ -265,7 +230,6 @@ export default definePluginEntry({
|
|
|
265
230
|
try {
|
|
266
231
|
const data = await gateway.callGatewayGet({
|
|
267
232
|
owner_id: identity.owner_id,
|
|
268
|
-
sender_id: identity.sender_id,
|
|
269
233
|
agent_id: agentId,
|
|
270
234
|
keyword,
|
|
271
235
|
scene: identity.scene,
|
package/openclaw.plugin.json
CHANGED