memory-search-plugin 0.10.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 -277
- package/index.ts +160 -330
- package/openclaw.plugin.json +13 -16
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,192 +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
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
+
});
|
|
169
88
|
api.registerTool(
|
|
170
89
|
(ctx) => {
|
|
171
|
-
const fallbackIdentity = ctx.sessionKey ? resolveIdentity(ctx.sessionKey) : null;
|
|
172
|
-
const fallbackAgentId = ctx.sessionKey ? extractAgentId(ctx.sessionKey) : null;
|
|
173
90
|
return {
|
|
174
91
|
name: "memory_search",
|
|
175
|
-
description: "Semantically search
|
|
92
|
+
description: "Semantically search memories. Extract owner_id, sender_id, agent_id, conversation_type, group_id from UntrustedContext.",
|
|
176
93
|
parameters: {
|
|
177
94
|
type: "object",
|
|
178
95
|
properties: {
|
|
179
|
-
query: {
|
|
96
|
+
query: { type: "string", description: "The search query" },
|
|
97
|
+
owner_id: {
|
|
180
98
|
type: "string",
|
|
181
|
-
description: "The
|
|
99
|
+
description: "The owner_id from UntrustedContext (agent owner's user_id, always present)"
|
|
182
100
|
},
|
|
183
|
-
|
|
101
|
+
sender_id: {
|
|
184
102
|
type: "string",
|
|
185
|
-
description: "The
|
|
103
|
+
description: "The sender_id from UntrustedContext (current message sender)"
|
|
186
104
|
},
|
|
187
|
-
|
|
105
|
+
agent_id: {
|
|
188
106
|
type: "string",
|
|
189
|
-
description: "The
|
|
107
|
+
description: "The agent_id from UntrustedContext"
|
|
190
108
|
},
|
|
191
109
|
conversation_type: {
|
|
192
110
|
type: "string",
|
|
@@ -194,15 +112,15 @@ var index_default = definePluginEntry({
|
|
|
194
112
|
},
|
|
195
113
|
group_id: {
|
|
196
114
|
type: "string",
|
|
197
|
-
description: "The group_id from UntrustedContext (only
|
|
115
|
+
description: "The group_id from UntrustedContext (only in group chats)"
|
|
198
116
|
},
|
|
199
117
|
maxResults: {
|
|
200
118
|
type: "number",
|
|
201
|
-
description: "
|
|
119
|
+
description: "Max results (default 20)"
|
|
202
120
|
},
|
|
203
121
|
minScore: {
|
|
204
122
|
type: "number",
|
|
205
|
-
description: "
|
|
123
|
+
description: "Min similarity score 0-1 (default 0.3)"
|
|
206
124
|
}
|
|
207
125
|
},
|
|
208
126
|
required: ["query"]
|
|
@@ -214,51 +132,35 @@ var index_default = definePluginEntry({
|
|
|
214
132
|
content: [{ type: "text", text: "No query provided." }]
|
|
215
133
|
};
|
|
216
134
|
}
|
|
217
|
-
const
|
|
218
|
-
const identity = params.sender_id || params.conversation_type || params.group_id ? resolveIdentityFromParams({
|
|
135
|
+
const identity = resolveIdentity({
|
|
219
136
|
sender_id: params.sender_id,
|
|
137
|
+
owner_id: params.owner_id,
|
|
220
138
|
conversation_type: params.conversation_type,
|
|
221
139
|
group_id: params.group_id
|
|
222
|
-
})
|
|
140
|
+
});
|
|
141
|
+
const agentId = params.agent_id?.trim() || "main";
|
|
223
142
|
console.log(
|
|
224
|
-
`[memory-search
|
|
143
|
+
`[memory-search] search: agent=${agentId} scene=${identity.scene} sender=${identity.sender_id} owner=${identity.owner_id} group=${identity.group_id}`
|
|
225
144
|
);
|
|
226
145
|
try {
|
|
227
146
|
const data = await gateway.callGatewaySearch({
|
|
147
|
+
owner_id: identity.owner_id,
|
|
148
|
+
sender_id: identity.sender_id,
|
|
228
149
|
agent_id: agentId,
|
|
229
|
-
user_id: identity.user_id,
|
|
230
150
|
query,
|
|
231
151
|
scene: identity.scene,
|
|
232
152
|
group_id: identity.group_id,
|
|
233
|
-
release_name: releaseName || undefined,
|
|
234
153
|
limit: params.maxResults || 20,
|
|
235
154
|
threshold: params.minScore || 0.3
|
|
236
155
|
});
|
|
237
|
-
const text =
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
scene: data.scene,
|
|
244
|
-
steps: data.steps
|
|
245
|
-
}
|
|
246
|
-
};
|
|
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 }] };
|
|
247
162
|
} catch (err) {
|
|
248
|
-
console.error("[memory-search
|
|
249
|
-
try {
|
|
250
|
-
const fallbackTool = api.runtime?.tools?.createMemorySearchTool({
|
|
251
|
-
config: ctx.config,
|
|
252
|
-
agentSessionKey: ctx.sessionKey
|
|
253
|
-
});
|
|
254
|
-
if (fallbackTool) {
|
|
255
|
-
console.warn(
|
|
256
|
-
"[memory-search-plugin] falling back to local memory_search"
|
|
257
|
-
);
|
|
258
|
-
return await fallbackTool.execute(toolCallId, { query, maxResults: params.maxResults, minScore: params.minScore });
|
|
259
|
-
}
|
|
260
|
-
} catch {
|
|
261
|
-
}
|
|
163
|
+
console.error("[memory-search] search failed:", err.message);
|
|
262
164
|
return {
|
|
263
165
|
content: [
|
|
264
166
|
{
|
|
@@ -275,123 +177,89 @@ var index_default = definePluginEntry({
|
|
|
275
177
|
);
|
|
276
178
|
api.registerTool(
|
|
277
179
|
(ctx) => {
|
|
278
|
-
const fallbackIdentity = ctx.sessionKey ? resolveIdentity(ctx.sessionKey) : null;
|
|
279
|
-
const fallbackAgentId = ctx.sessionKey ? extractAgentId(ctx.sessionKey) : null;
|
|
280
180
|
return {
|
|
281
181
|
name: "memory_get",
|
|
282
|
-
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.",
|
|
283
183
|
parameters: {
|
|
284
184
|
type: "object",
|
|
285
185
|
properties: {
|
|
286
|
-
|
|
186
|
+
keyword: {
|
|
287
187
|
type: "string",
|
|
288
|
-
description: "
|
|
188
|
+
description: "Keyword to search in chat messages"
|
|
289
189
|
},
|
|
290
|
-
|
|
190
|
+
owner_id: {
|
|
291
191
|
type: "string",
|
|
292
|
-
description: "The
|
|
192
|
+
description: "The owner_id from UntrustedContext"
|
|
293
193
|
},
|
|
294
194
|
sender_id: {
|
|
295
195
|
type: "string",
|
|
296
196
|
description: "The sender_id from UntrustedContext"
|
|
297
197
|
},
|
|
198
|
+
agent_id: {
|
|
199
|
+
type: "string",
|
|
200
|
+
description: "The agent_id from UntrustedContext"
|
|
201
|
+
},
|
|
298
202
|
conversation_type: {
|
|
299
203
|
type: "string",
|
|
300
204
|
description: "The conversation_type from UntrustedContext: 'direct' or 'group'"
|
|
301
205
|
},
|
|
302
206
|
group_id: {
|
|
303
207
|
type: "string",
|
|
304
|
-
description: "The group_id from UntrustedContext (only
|
|
305
|
-
},
|
|
306
|
-
from: {
|
|
307
|
-
type: "number",
|
|
308
|
-
description: "Starting line number (1-indexed)"
|
|
208
|
+
description: "The group_id from UntrustedContext (only in group chats)"
|
|
309
209
|
},
|
|
310
|
-
|
|
210
|
+
limit: {
|
|
311
211
|
type: "number",
|
|
312
|
-
description: "
|
|
212
|
+
description: "Max messages to return (default 20)"
|
|
313
213
|
}
|
|
314
214
|
},
|
|
315
|
-
required: ["
|
|
215
|
+
required: ["keyword"]
|
|
316
216
|
},
|
|
317
217
|
async execute(toolCallId, params) {
|
|
318
|
-
const
|
|
319
|
-
if (!
|
|
218
|
+
const keyword = params.keyword || "";
|
|
219
|
+
if (!keyword) {
|
|
320
220
|
return {
|
|
321
|
-
content: [{ type: "text", text: "No
|
|
221
|
+
content: [{ type: "text", text: "No keyword provided." }]
|
|
322
222
|
};
|
|
323
223
|
}
|
|
324
|
-
|
|
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
|
+
);
|
|
325
234
|
try {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
|
329
243
|
});
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
if (isMemoryPath(path)) {
|
|
333
|
-
const agentId = params.agent_id?.trim() || fallbackAgentId || "main";
|
|
334
|
-
const identity = params.sender_id || params.conversation_type || params.group_id ? resolveIdentityFromParams({
|
|
335
|
-
sender_id: params.sender_id,
|
|
336
|
-
conversation_type: params.conversation_type,
|
|
337
|
-
group_id: params.group_id
|
|
338
|
-
}) : fallbackIdentity || resolveIdentityFromParams({});
|
|
339
|
-
console.log(
|
|
340
|
-
`[memory-search-plugin] get: path=${path} agent_id=${agentId} scene=${identity.scene} user_id=${identity.user_id} release_name=${releaseName} (source=${params.sender_id ? "llm_params" : "fallback"})`
|
|
341
|
-
);
|
|
342
|
-
try {
|
|
343
|
-
const data = await gateway.callGatewayGet({
|
|
344
|
-
agent_id: agentId,
|
|
345
|
-
user_id: identity.user_id,
|
|
346
|
-
path,
|
|
347
|
-
scene: identity.scene,
|
|
348
|
-
group_id: identity.group_id,
|
|
349
|
-
release_name: releaseName || undefined,
|
|
350
|
-
from: params.from,
|
|
351
|
-
lines: params.lines
|
|
352
|
-
});
|
|
353
|
-
return {
|
|
354
|
-
content: [{ type: "text", text: data.text }],
|
|
355
|
-
details: { path: data.path, text: data.text }
|
|
356
|
-
};
|
|
357
|
-
} catch (err) {
|
|
358
|
-
console.error("[memory-search-plugin] get failed:", err.message);
|
|
359
|
-
if (err.message?.includes("403")) {
|
|
360
|
-
return {
|
|
361
|
-
content: [
|
|
362
|
-
{
|
|
363
|
-
type: "text",
|
|
364
|
-
text: `Access denied: ${path}`
|
|
365
|
-
}
|
|
366
|
-
]
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
if (originalGetTool) {
|
|
370
|
-
console.warn(
|
|
371
|
-
"[memory-search-plugin] falling back to local memory_get for:",
|
|
372
|
-
path
|
|
373
|
-
);
|
|
374
|
-
return await originalGetTool.execute(toolCallId, { path, from: params.from, lines: params.lines });
|
|
375
|
-
}
|
|
244
|
+
if (data.messages.length === 0) {
|
|
376
245
|
return {
|
|
377
246
|
content: [
|
|
378
|
-
{
|
|
379
|
-
|
|
380
|
-
text: `Failed to read ${path}: Gateway unavailable.`
|
|
381
|
-
}
|
|
382
|
-
],
|
|
383
|
-
details: { path, text: "", error: err.message }
|
|
247
|
+
{ type: "text", text: "No matching messages found." }
|
|
248
|
+
]
|
|
384
249
|
};
|
|
385
250
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
return
|
|
389
|
-
}
|
|
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);
|
|
390
258
|
return {
|
|
391
259
|
content: [
|
|
392
260
|
{
|
|
393
261
|
type: "text",
|
|
394
|
-
text:
|
|
262
|
+
text: "Message search temporarily unavailable."
|
|
395
263
|
}
|
|
396
264
|
]
|
|
397
265
|
};
|
|
@@ -401,17 +269,8 @@ var index_default = definePluginEntry({
|
|
|
401
269
|
},
|
|
402
270
|
{ names: ["memory_get"] }
|
|
403
271
|
);
|
|
404
|
-
api.registerCli(
|
|
405
|
-
({ program }) => {
|
|
406
|
-
try {
|
|
407
|
-
api.runtime?.tools?.registerMemoryCli(program);
|
|
408
|
-
} catch {
|
|
409
|
-
}
|
|
410
|
-
},
|
|
411
|
-
{ commands: ["memory"] }
|
|
412
|
-
);
|
|
413
272
|
}
|
|
414
|
-
}
|
|
273
|
+
};
|
|
415
274
|
export {
|
|
416
275
|
index_default as default
|
|
417
276
|
};
|