memory-search-plugin 0.8.0 → 1.1.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 +45 -64
- package/identity.ts +28 -88
- package/index.js +136 -273
- package/index.ts +160 -330
- package/openclaw.plugin.json +13 -16
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,190 +1,110 @@
|
|
|
1
|
-
// index.ts
|
|
2
|
-
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
3
|
-
|
|
4
|
-
// gateway-client.ts
|
|
5
|
-
function createGatewayClient(config) {
|
|
6
|
-
const baseUrl = config.gatewayUrl.replace(/\/+$/, "");
|
|
7
|
-
const token = config.gatewayToken || "";
|
|
8
|
-
const authHeaders = token ? { Authorization: `Bearer ${token}` } : {};
|
|
9
|
-
return {
|
|
10
|
-
async callGatewaySearch(options) {
|
|
11
|
-
const url = `${baseUrl}/api/memory/search`;
|
|
12
|
-
const response = await fetch(url, {
|
|
13
|
-
method: "POST",
|
|
14
|
-
headers: { "Content-Type": "application/json", ...authHeaders },
|
|
15
|
-
body: JSON.stringify(options)
|
|
16
|
-
});
|
|
17
|
-
if (!response.ok) {
|
|
18
|
-
const errorBody = await response.text().catch(() => "");
|
|
19
|
-
throw new Error(
|
|
20
|
-
`Gateway search failed: ${response.status} ${response.statusText} ${errorBody}`
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
return response.json();
|
|
24
|
-
},
|
|
25
|
-
async callGatewayGet(options) {
|
|
26
|
-
const url = `${baseUrl}/api/memory/get`;
|
|
27
|
-
const response = await fetch(url, {
|
|
28
|
-
method: "POST",
|
|
29
|
-
headers: { "Content-Type": "application/json", ...authHeaders },
|
|
30
|
-
body: JSON.stringify(options)
|
|
31
|
-
});
|
|
32
|
-
if (!response.ok) {
|
|
33
|
-
const errorBody = await response.text().catch(() => "");
|
|
34
|
-
throw new Error(
|
|
35
|
-
`Gateway get failed: ${response.status} ${response.statusText} ${errorBody}`
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
return response.json();
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
1
|
// identity.ts
|
|
44
|
-
function
|
|
2
|
+
function resolveIdentity(params) {
|
|
45
3
|
const testScene = process.env.MEMORY_GATEWAY_TEST_SCENE;
|
|
46
4
|
if (testScene) {
|
|
47
|
-
|
|
5
|
+
return {
|
|
48
6
|
scene: testScene,
|
|
49
|
-
|
|
7
|
+
sender_id: process.env.MEMORY_GATEWAY_TEST_USER_ID || "test_user",
|
|
8
|
+
owner_id: process.env.MEMORY_GATEWAY_TEST_OWNER_ID || "test_owner",
|
|
50
9
|
group_id: process.env.MEMORY_GATEWAY_TEST_GROUP_ID || null
|
|
51
10
|
};
|
|
52
|
-
console.log("[memory-search-plugin] TEST MODE identity:", JSON.stringify(result));
|
|
53
|
-
return result;
|
|
54
11
|
}
|
|
55
|
-
const
|
|
12
|
+
const senderId = params.sender_id?.trim() || "unknown";
|
|
13
|
+
const ownerId = params.owner_id?.trim() || "";
|
|
56
14
|
const convType = (params.conversation_type || "direct").trim().toLowerCase();
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
};
|
|
15
|
+
const groupId = params.group_id?.trim() || null;
|
|
16
|
+
if (!ownerId) {
|
|
17
|
+
console.warn(
|
|
18
|
+
"[identity] owner_id is empty \u2014 LLM failed to extract from UntrustedContext. owner queries will be skipped to prevent cross-user leak."
|
|
19
|
+
);
|
|
63
20
|
}
|
|
64
|
-
if (
|
|
65
|
-
|
|
21
|
+
if (convType === "group") {
|
|
22
|
+
if (!groupId) {
|
|
23
|
+
console.warn("[identity] group scene but group_id is empty");
|
|
24
|
+
}
|
|
25
|
+
return { scene: "group", sender_id: senderId, owner_id: ownerId, group_id: groupId };
|
|
66
26
|
}
|
|
67
|
-
return { scene: "
|
|
27
|
+
return { scene: "owner", sender_id: senderId, owner_id: ownerId, group_id: null };
|
|
68
28
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
|
|
29
|
+
|
|
30
|
+
// gateway-client.ts
|
|
31
|
+
function createGatewayClient(config) {
|
|
32
|
+
const baseUrl = config.gatewayUrl.replace(/\/+$/, "");
|
|
33
|
+
const headers = {
|
|
34
|
+
"Content-Type": "application/json",
|
|
35
|
+
...config.gatewayToken ? { Authorization: `Bearer ${config.gatewayToken}` } : {}
|
|
36
|
+
};
|
|
37
|
+
async function post(path, body) {
|
|
38
|
+
const resp = await fetch(`${baseUrl}${path}`, {
|
|
39
|
+
method: "POST",
|
|
40
|
+
headers,
|
|
41
|
+
body: JSON.stringify(body)
|
|
42
|
+
});
|
|
43
|
+
if (!resp.ok) {
|
|
44
|
+
const text = await resp.text().catch(() => "");
|
|
45
|
+
throw new Error(`Gateway ${path} failed: ${resp.status} ${text}`);
|
|
85
46
|
}
|
|
86
|
-
return
|
|
47
|
+
return resp.json();
|
|
87
48
|
}
|
|
88
|
-
return {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (!token) return false;
|
|
93
|
-
const ownerUserId = token.split("-").pop() || "";
|
|
94
|
-
return ownerUserId !== "" && ownerUserId === userId;
|
|
95
|
-
}
|
|
96
|
-
function extractAgentId(sessionKey) {
|
|
97
|
-
const parts = (sessionKey || "").split(":");
|
|
98
|
-
return parts.length >= 2 ? parts[1] : "main";
|
|
49
|
+
return {
|
|
50
|
+
callGatewaySearch: (opts) => post("/api/memory/search", opts),
|
|
51
|
+
callGatewayGet: (opts) => post("/api/memory/get", opts)
|
|
52
|
+
};
|
|
99
53
|
}
|
|
100
54
|
|
|
101
55
|
// index.ts
|
|
102
56
|
var buildPromptSection = ({
|
|
103
|
-
availableTools
|
|
104
|
-
citationsMode
|
|
57
|
+
availableTools
|
|
105
58
|
}) => {
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
if (!
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
const lines = ["## Memory Recall", toolGuidance];
|
|
118
|
-
lines.push(
|
|
119
|
-
"**Context extraction:** When calling memory_search or memory_get, you MUST fill in the agent_id, sender_id, conversation_type, and group_id parameters by extracting them from the UntrustedContext section in this conversation. Look for lines like `agent_id: xxx`, `sender_id: xxx`, `conversation_type: xxx`, `group_id: xxx`. If a field is not present, omit it."
|
|
120
|
-
);
|
|
121
|
-
if (citationsMode === "off") {
|
|
122
|
-
lines.push(
|
|
123
|
-
"Citations are disabled: do not mention file paths or line numbers in replies unless the user explicitly asks."
|
|
124
|
-
);
|
|
125
|
-
} else {
|
|
126
|
-
lines.push(
|
|
127
|
-
"Citations: include Source: <path#line> when it helps the user verify memory snippets."
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
lines.push("");
|
|
59
|
+
const hasSearch = availableTools.has("memory_search");
|
|
60
|
+
const hasGet = availableTools.has("memory_get");
|
|
61
|
+
if (!hasSearch && !hasGet) return [];
|
|
62
|
+
const lines = [
|
|
63
|
+
"## Memory Recall",
|
|
64
|
+
"Before answering anything about prior work, decisions, dates, people, preferences, or todos: run memory_search for semantic search. If low confidence after search, say you checked.",
|
|
65
|
+
"",
|
|
66
|
+
"**Context extraction:** When calling memory_search or memory_get, you MUST extract the following from the UntrustedContext section and pass as parameters: `owner_id`, `sender_id`, `agent_id`, `conversation_type`, `group_id`. Look for lines like `owner_id: xxx`, `sender_id: xxx`, etc. If a field is not present, omit it. Do NOT invent or guess values \u2014 only use what is explicitly stated in UntrustedContext.",
|
|
67
|
+
""
|
|
68
|
+
];
|
|
131
69
|
return lines;
|
|
132
70
|
};
|
|
133
|
-
|
|
134
|
-
const normalized = path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
135
|
-
return normalized === "MEMORY.md" || normalized.startsWith("memory/") || normalized.endsWith("/MEMORY.md") || normalized.includes("/memory/");
|
|
136
|
-
}
|
|
137
|
-
function formatSearchResults(results) {
|
|
138
|
-
if (results.length === 0) {
|
|
139
|
-
return "No relevant memories found.";
|
|
140
|
-
}
|
|
141
|
-
return results.map((r, i) => {
|
|
142
|
-
let sourceDesc = r.memory_type;
|
|
143
|
-
if (r.memory_type === "peer" && r.peer_id) {
|
|
144
|
-
sourceDesc = `peer/${r.peer_id}`;
|
|
145
|
-
} else if (r.memory_type === "group" && r.group_id) {
|
|
146
|
-
sourceDesc = `group/${r.group_id}`;
|
|
147
|
-
} else if (r.memory_type === "knowledge" && r.kb_id) {
|
|
148
|
-
sourceDesc = `knowledge/${r.kb_id}`;
|
|
149
|
-
}
|
|
150
|
-
const filePart = r.source_file ? ` | ${r.source_file}` : "";
|
|
151
|
-
const header = `[${i + 1}] (${sourceDesc}, score: ${r.score.toFixed(2)}${filePart})`;
|
|
152
|
-
return `${header}
|
|
153
|
-
${r.content}`;
|
|
154
|
-
}).join("\n\n");
|
|
155
|
-
}
|
|
156
|
-
var index_default = definePluginEntry({
|
|
71
|
+
var index_default = {
|
|
157
72
|
id: "memory-search-plugin",
|
|
158
|
-
name: "Memory Search Plugin",
|
|
159
|
-
description: "Routes memory to external Memory Search Gateway with ACL",
|
|
160
|
-
kind: "memory",
|
|
161
73
|
register(api) {
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
74
|
+
const config = {
|
|
75
|
+
gatewayUrl: api.getConfig?.("MEMORY_GATEWAY_URL") || process.env.MEMORY_GATEWAY_URL || "",
|
|
76
|
+
gatewayToken: api.getConfig?.("MEMORY_GATEWAY_TOKEN") || process.env.MEMORY_GATEWAY_TOKEN || ""
|
|
77
|
+
};
|
|
78
|
+
if (!config.gatewayUrl) {
|
|
79
|
+
console.warn("[memory-search-plugin] MEMORY_GATEWAY_URL not set, plugin disabled");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const gateway = createGatewayClient(config);
|
|
83
|
+
api.registerPromptSection?.({
|
|
84
|
+
id: "memory-recall",
|
|
85
|
+
position: "top",
|
|
86
|
+
build: buildPromptSection
|
|
87
|
+
});
|
|
167
88
|
api.registerTool(
|
|
168
89
|
(ctx) => {
|
|
169
|
-
const fallbackIdentity = ctx.sessionKey ? resolveIdentity(ctx.sessionKey) : null;
|
|
170
|
-
const fallbackAgentId = ctx.sessionKey ? extractAgentId(ctx.sessionKey) : null;
|
|
171
90
|
return {
|
|
172
91
|
name: "memory_search",
|
|
173
|
-
description: "Semantically search
|
|
92
|
+
description: "Semantically search memories. Extract owner_id, sender_id, agent_id, conversation_type, group_id from UntrustedContext.",
|
|
174
93
|
parameters: {
|
|
175
94
|
type: "object",
|
|
176
95
|
properties: {
|
|
177
|
-
query: {
|
|
96
|
+
query: { type: "string", description: "The search query" },
|
|
97
|
+
owner_id: {
|
|
178
98
|
type: "string",
|
|
179
|
-
description: "The
|
|
99
|
+
description: "The owner_id from UntrustedContext (agent owner's user_id, always present)"
|
|
180
100
|
},
|
|
181
|
-
|
|
101
|
+
sender_id: {
|
|
182
102
|
type: "string",
|
|
183
|
-
description: "The
|
|
103
|
+
description: "The sender_id from UntrustedContext (current message sender)"
|
|
184
104
|
},
|
|
185
|
-
|
|
105
|
+
agent_id: {
|
|
186
106
|
type: "string",
|
|
187
|
-
description: "The
|
|
107
|
+
description: "The agent_id from UntrustedContext"
|
|
188
108
|
},
|
|
189
109
|
conversation_type: {
|
|
190
110
|
type: "string",
|
|
@@ -192,15 +112,15 @@ var index_default = definePluginEntry({
|
|
|
192
112
|
},
|
|
193
113
|
group_id: {
|
|
194
114
|
type: "string",
|
|
195
|
-
description: "The group_id from UntrustedContext (only
|
|
115
|
+
description: "The group_id from UntrustedContext (only in group chats)"
|
|
196
116
|
},
|
|
197
117
|
maxResults: {
|
|
198
118
|
type: "number",
|
|
199
|
-
description: "
|
|
119
|
+
description: "Max results (default 20)"
|
|
200
120
|
},
|
|
201
121
|
minScore: {
|
|
202
122
|
type: "number",
|
|
203
|
-
description: "
|
|
123
|
+
description: "Min similarity score 0-1 (default 0.3)"
|
|
204
124
|
}
|
|
205
125
|
},
|
|
206
126
|
required: ["query"]
|
|
@@ -212,50 +132,35 @@ var index_default = definePluginEntry({
|
|
|
212
132
|
content: [{ type: "text", text: "No query provided." }]
|
|
213
133
|
};
|
|
214
134
|
}
|
|
215
|
-
const
|
|
216
|
-
const identity = params.sender_id || params.conversation_type || params.group_id ? resolveIdentityFromParams({
|
|
135
|
+
const identity = resolveIdentity({
|
|
217
136
|
sender_id: params.sender_id,
|
|
137
|
+
owner_id: params.owner_id,
|
|
218
138
|
conversation_type: params.conversation_type,
|
|
219
139
|
group_id: params.group_id
|
|
220
|
-
})
|
|
140
|
+
});
|
|
141
|
+
const agentId = params.agent_id?.trim() || "main";
|
|
221
142
|
console.log(
|
|
222
|
-
`[memory-search
|
|
143
|
+
`[memory-search] search: agent=${agentId} scene=${identity.scene} sender=${identity.sender_id} owner=${identity.owner_id} group=${identity.group_id}`
|
|
223
144
|
);
|
|
224
145
|
try {
|
|
225
146
|
const data = await gateway.callGatewaySearch({
|
|
147
|
+
owner_id: identity.owner_id,
|
|
148
|
+
sender_id: identity.sender_id,
|
|
226
149
|
agent_id: agentId,
|
|
227
|
-
user_id: identity.user_id,
|
|
228
150
|
query,
|
|
229
151
|
scene: identity.scene,
|
|
230
152
|
group_id: identity.group_id,
|
|
231
153
|
limit: params.maxResults || 20,
|
|
232
154
|
threshold: params.minScore || 0.3
|
|
233
155
|
});
|
|
234
|
-
const text =
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
scene: data.scene,
|
|
241
|
-
steps: data.steps
|
|
242
|
-
}
|
|
243
|
-
};
|
|
156
|
+
const text = data.results.length === 0 ? "No relevant memories found." : data.results.map((r, i) => {
|
|
157
|
+
const tag = r.memory_type === "group" && r.group_id ? `group/${r.group_id}` : r.memory_type === "knowledge" && r.kb_id ? `knowledge/${r.kb_id}` : r.memory_type;
|
|
158
|
+
return `[${i + 1}] (${tag}, score: ${r.score.toFixed(2)})
|
|
159
|
+
${r.content}`;
|
|
160
|
+
}).join("\n\n");
|
|
161
|
+
return { content: [{ type: "text", text }] };
|
|
244
162
|
} catch (err) {
|
|
245
|
-
console.error("[memory-search
|
|
246
|
-
try {
|
|
247
|
-
const fallbackTool = api.runtime?.tools?.createMemorySearchTool({
|
|
248
|
-
config: ctx.config,
|
|
249
|
-
agentSessionKey: ctx.sessionKey
|
|
250
|
-
});
|
|
251
|
-
if (fallbackTool) {
|
|
252
|
-
console.warn(
|
|
253
|
-
"[memory-search-plugin] falling back to local memory_search"
|
|
254
|
-
);
|
|
255
|
-
return await fallbackTool.execute(toolCallId, { query, maxResults: params.maxResults, minScore: params.minScore });
|
|
256
|
-
}
|
|
257
|
-
} catch {
|
|
258
|
-
}
|
|
163
|
+
console.error("[memory-search] search failed:", err.message);
|
|
259
164
|
return {
|
|
260
165
|
content: [
|
|
261
166
|
{
|
|
@@ -272,122 +177,89 @@ var index_default = definePluginEntry({
|
|
|
272
177
|
);
|
|
273
178
|
api.registerTool(
|
|
274
179
|
(ctx) => {
|
|
275
|
-
const fallbackIdentity = ctx.sessionKey ? resolveIdentity(ctx.sessionKey) : null;
|
|
276
|
-
const fallbackAgentId = ctx.sessionKey ? extractAgentId(ctx.sessionKey) : null;
|
|
277
180
|
return {
|
|
278
181
|
name: "memory_get",
|
|
279
|
-
description: "
|
|
182
|
+
description: "Search raw chat messages by keyword. Queries the original message log, not the extracted facts. Extract owner_id, sender_id, agent_id, conversation_type, group_id from UntrustedContext.",
|
|
280
183
|
parameters: {
|
|
281
184
|
type: "object",
|
|
282
185
|
properties: {
|
|
283
|
-
|
|
186
|
+
keyword: {
|
|
284
187
|
type: "string",
|
|
285
|
-
description: "
|
|
188
|
+
description: "Keyword to search in chat messages"
|
|
286
189
|
},
|
|
287
|
-
|
|
190
|
+
owner_id: {
|
|
288
191
|
type: "string",
|
|
289
|
-
description: "The
|
|
192
|
+
description: "The owner_id from UntrustedContext"
|
|
290
193
|
},
|
|
291
194
|
sender_id: {
|
|
292
195
|
type: "string",
|
|
293
196
|
description: "The sender_id from UntrustedContext"
|
|
294
197
|
},
|
|
198
|
+
agent_id: {
|
|
199
|
+
type: "string",
|
|
200
|
+
description: "The agent_id from UntrustedContext"
|
|
201
|
+
},
|
|
295
202
|
conversation_type: {
|
|
296
203
|
type: "string",
|
|
297
204
|
description: "The conversation_type from UntrustedContext: 'direct' or 'group'"
|
|
298
205
|
},
|
|
299
206
|
group_id: {
|
|
300
207
|
type: "string",
|
|
301
|
-
description: "The group_id from UntrustedContext (only
|
|
302
|
-
},
|
|
303
|
-
from: {
|
|
304
|
-
type: "number",
|
|
305
|
-
description: "Starting line number (1-indexed)"
|
|
208
|
+
description: "The group_id from UntrustedContext (only in group chats)"
|
|
306
209
|
},
|
|
307
|
-
|
|
210
|
+
limit: {
|
|
308
211
|
type: "number",
|
|
309
|
-
description: "
|
|
212
|
+
description: "Max messages to return (default 20)"
|
|
310
213
|
}
|
|
311
214
|
},
|
|
312
|
-
required: ["
|
|
215
|
+
required: ["keyword"]
|
|
313
216
|
},
|
|
314
217
|
async execute(toolCallId, params) {
|
|
315
|
-
const
|
|
316
|
-
if (!
|
|
218
|
+
const keyword = params.keyword || "";
|
|
219
|
+
if (!keyword) {
|
|
317
220
|
return {
|
|
318
|
-
content: [{ type: "text", text: "No
|
|
221
|
+
content: [{ type: "text", text: "No keyword provided." }]
|
|
319
222
|
};
|
|
320
223
|
}
|
|
321
|
-
|
|
224
|
+
const identity = resolveIdentity({
|
|
225
|
+
sender_id: params.sender_id,
|
|
226
|
+
owner_id: params.owner_id,
|
|
227
|
+
conversation_type: params.conversation_type,
|
|
228
|
+
group_id: params.group_id
|
|
229
|
+
});
|
|
230
|
+
const agentId = params.agent_id?.trim() || "main";
|
|
231
|
+
console.log(
|
|
232
|
+
`[memory-search] get: keyword="${keyword}" agent=${agentId} scene=${identity.scene} owner=${identity.owner_id} group=${identity.group_id}`
|
|
233
|
+
);
|
|
322
234
|
try {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
235
|
+
const data = await gateway.callGatewayGet({
|
|
236
|
+
owner_id: identity.owner_id,
|
|
237
|
+
sender_id: identity.sender_id,
|
|
238
|
+
agent_id: agentId,
|
|
239
|
+
keyword,
|
|
240
|
+
scene: identity.scene,
|
|
241
|
+
group_id: identity.group_id,
|
|
242
|
+
limit: params.limit || 20
|
|
326
243
|
});
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
if (isMemoryPath(path)) {
|
|
330
|
-
const agentId = params.agent_id?.trim() || fallbackAgentId || "main";
|
|
331
|
-
const identity = params.sender_id || params.conversation_type || params.group_id ? resolveIdentityFromParams({
|
|
332
|
-
sender_id: params.sender_id,
|
|
333
|
-
conversation_type: params.conversation_type,
|
|
334
|
-
group_id: params.group_id
|
|
335
|
-
}) : fallbackIdentity || resolveIdentityFromParams({});
|
|
336
|
-
console.log(
|
|
337
|
-
`[memory-search-plugin] get: path=${path} agent_id=${agentId} scene=${identity.scene} user_id=${identity.user_id} (source=${params.sender_id ? "llm_params" : "fallback"})`
|
|
338
|
-
);
|
|
339
|
-
try {
|
|
340
|
-
const data = await gateway.callGatewayGet({
|
|
341
|
-
agent_id: agentId,
|
|
342
|
-
user_id: identity.user_id,
|
|
343
|
-
path,
|
|
344
|
-
scene: identity.scene,
|
|
345
|
-
group_id: identity.group_id,
|
|
346
|
-
from: params.from,
|
|
347
|
-
lines: params.lines
|
|
348
|
-
});
|
|
349
|
-
return {
|
|
350
|
-
content: [{ type: "text", text: data.text }],
|
|
351
|
-
details: { path: data.path, text: data.text }
|
|
352
|
-
};
|
|
353
|
-
} catch (err) {
|
|
354
|
-
console.error("[memory-search-plugin] get failed:", err.message);
|
|
355
|
-
if (err.message?.includes("403")) {
|
|
356
|
-
return {
|
|
357
|
-
content: [
|
|
358
|
-
{
|
|
359
|
-
type: "text",
|
|
360
|
-
text: `Access denied: ${path}`
|
|
361
|
-
}
|
|
362
|
-
]
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
if (originalGetTool) {
|
|
366
|
-
console.warn(
|
|
367
|
-
"[memory-search-plugin] falling back to local memory_get for:",
|
|
368
|
-
path
|
|
369
|
-
);
|
|
370
|
-
return await originalGetTool.execute(toolCallId, { path, from: params.from, lines: params.lines });
|
|
371
|
-
}
|
|
244
|
+
if (data.messages.length === 0) {
|
|
372
245
|
return {
|
|
373
246
|
content: [
|
|
374
|
-
{
|
|
375
|
-
|
|
376
|
-
text: `Failed to read ${path}: Gateway unavailable.`
|
|
377
|
-
}
|
|
378
|
-
],
|
|
379
|
-
details: { path, text: "", error: err.message }
|
|
247
|
+
{ type: "text", text: "No matching messages found." }
|
|
248
|
+
]
|
|
380
249
|
};
|
|
381
250
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
return
|
|
385
|
-
}
|
|
251
|
+
const text = data.messages.map((m) => {
|
|
252
|
+
const tag = m.message_type === "group" && m.group_id ? `group/${m.group_id}` : m.message_type;
|
|
253
|
+
return `[${tag}] ${m.formatted_text}`;
|
|
254
|
+
}).join("\n");
|
|
255
|
+
return { content: [{ type: "text", text }] };
|
|
256
|
+
} catch (err) {
|
|
257
|
+
console.error("[memory-search] get failed:", err.message);
|
|
386
258
|
return {
|
|
387
259
|
content: [
|
|
388
260
|
{
|
|
389
261
|
type: "text",
|
|
390
|
-
text:
|
|
262
|
+
text: "Message search temporarily unavailable."
|
|
391
263
|
}
|
|
392
264
|
]
|
|
393
265
|
};
|
|
@@ -397,17 +269,8 @@ var index_default = definePluginEntry({
|
|
|
397
269
|
},
|
|
398
270
|
{ names: ["memory_get"] }
|
|
399
271
|
);
|
|
400
|
-
api.registerCli(
|
|
401
|
-
({ program }) => {
|
|
402
|
-
try {
|
|
403
|
-
api.runtime?.tools?.registerMemoryCli(program);
|
|
404
|
-
} catch {
|
|
405
|
-
}
|
|
406
|
-
},
|
|
407
|
-
{ commands: ["memory"] }
|
|
408
|
-
);
|
|
409
272
|
}
|
|
410
|
-
}
|
|
273
|
+
};
|
|
411
274
|
export {
|
|
412
275
|
index_default as default
|
|
413
276
|
};
|