Skip to content

Commit 9079d96

Browse files
author
Miso
committed
feat: add per-agent auto-recall control (autoRecallIncludeAgents)
Implement per-agent auto-recall control as suggested in #474: - Add autoRecallIncludeAgents config option (whitelist mode): when set, ONLY these agents receive auto-recall injection - autoRecallExcludeAgents was already implemented in logic but missing from the plugin schema — add it to configSchema so users can configure it - autoRecallIncludeAgents takes precedence over autoRecallExcludeAgents when both are set - Include schema definitions for both fields - Add unit tests covering parsing, filtering, and mixed-agent runtime logic - Tests: 19 passing
1 parent 263af0d commit 9079d96

3 files changed

Lines changed: 310 additions & 26 deletions

File tree

index.ts

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ interface PluginConfig {
113113
recallMode?: "full" | "summary" | "adaptive" | "off";
114114
/** Agent IDs excluded from auto-recall injection. Useful for background agents (e.g. memory-distiller, cron workers) whose output should not be contaminated by injected memory context. */
115115
autoRecallExcludeAgents?: string[];
116+
/** Agent IDs included in auto-recall injection (whitelist mode). When set, ONLY these agents receive auto-recall. Cannot be used together with autoRecallExcludeAgents. */
117+
autoRecallIncludeAgents?: string[];
116118
captureAssistant?: boolean;
117119
retrieval?: {
118120
mode?: "hybrid" | "vector";
@@ -2309,18 +2311,28 @@ const memoryLanceDBProPlugin = {
23092311

23102312
const AUTO_RECALL_TIMEOUT_MS = parsePositiveInt(config.autoRecallTimeoutMs) ?? 5_000; // configurable; default raised from 3s to 5s for remote embedding APIs behind proxies
23112313
api.on("before_prompt_build", async (event: any, ctx: any) => {
2312-
// Per-agent exclusion: skip auto-recall for agents in the exclusion list.
2314+
// Per-agent inclusion/exclusion: autoRecallIncludeAgents takes precedence over autoRecallExcludeAgents.
2315+
// - If autoRecallIncludeAgents is set: ONLY these agents receive auto-recall
2316+
// - Else if autoRecallExcludeAgents is set: all agents EXCEPT these receive auto-recall
23132317
const agentId = resolveHookAgentId(ctx?.agentId, (event as any).sessionKey);
2314-
if (
2315-
Array.isArray(config.autoRecallExcludeAgents) &&
2316-
config.autoRecallExcludeAgents.length > 0 &&
2317-
agentId !== undefined &&
2318-
config.autoRecallExcludeAgents.includes(agentId)
2319-
) {
2320-
api.logger.debug?.(
2321-
`memory-lancedb-pro: auto-recall skipped for excluded agent '${agentId}'`,
2322-
);
2323-
return;
2318+
if (agentId !== undefined) {
2319+
if (Array.isArray(config.autoRecallIncludeAgents) && config.autoRecallIncludeAgents.length > 0) {
2320+
if (!config.autoRecallIncludeAgents.includes(agentId)) {
2321+
api.logger.debug?.(
2322+
`memory-lancedb-pro: auto-recall skipped for agent '${agentId}' not in autoRecallIncludeAgents`,
2323+
);
2324+
return;
2325+
}
2326+
} else if (
2327+
Array.isArray(config.autoRecallExcludeAgents) &&
2328+
config.autoRecallExcludeAgents.length > 0 &&
2329+
config.autoRecallExcludeAgents.includes(agentId)
2330+
) {
2331+
api.logger.debug?.(
2332+
`memory-lancedb-pro: auto-recall skipped for excluded agent '${agentId}'`,
2333+
);
2334+
return;
2335+
}
23242336
}
23252337

23262338
// Manually increment turn counter for this session
@@ -3969,6 +3981,9 @@ export function parsePluginConfig(value: unknown): PluginConfig {
39693981
autoRecallExcludeAgents: Array.isArray(cfg.autoRecallExcludeAgents)
39703982
? cfg.autoRecallExcludeAgents.filter((id: unknown): id is string => typeof id === "string" && id.trim() !== "")
39713983
: undefined,
3984+
autoRecallIncludeAgents: Array.isArray(cfg.autoRecallIncludeAgents)
3985+
? cfg.autoRecallIncludeAgents.filter((id: unknown): id is string => typeof id === "string" && id.trim() !== "")
3986+
: undefined,
39723987
captureAssistant: cfg.captureAssistant === true,
39733988
retrieval:
39743989
typeof cfg.retrieval === "object" && cfg.retrieval !== null

openclaw.plugin.json

Lines changed: 91 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,31 @@
160160
},
161161
"recallMode": {
162162
"type": "string",
163-
"enum": ["full", "summary", "adaptive", "off"],
163+
"enum": [
164+
"full",
165+
"summary",
166+
"adaptive",
167+
"off"
168+
],
164169
"default": "full",
165170
"description": "Auto-recall depth mode. 'full': inject with configured per-item budget. 'summary': L0 abstracts only (compact). 'adaptive': analyze query intent to auto-select category and depth. 'off': disable auto-recall injection."
166171
},
172+
"autoRecallExcludeAgents": {
173+
"type": "array",
174+
"items": {
175+
"type": "string"
176+
},
177+
"default": [],
178+
"description": "Agent IDs excluded from auto-recall injection. When set, these agents will NOT receive auto-recalled memories. Useful for background agents (e.g. cron workers) whose output should not be contaminated by injected context. Cannot be used with autoRecallIncludeAgents."
179+
},
180+
"autoRecallIncludeAgents": {
181+
"type": "array",
182+
"items": {
183+
"type": "string"
184+
},
185+
"default": [],
186+
"description": "Agent IDs included in auto-recall injection (whitelist mode). When set, ONLY these agents will receive auto-recall. Cannot be used with autoRecallExcludeAgents. Overrides autoRecallExcludeAgents if both are set."
187+
},
167188
"captureAssistant": {
168189
"type": "boolean"
169190
},
@@ -259,23 +280,78 @@
259280
"type": "object",
260281
"additionalProperties": false,
261282
"properties": {
262-
"utility": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.1 },
263-
"confidence": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.1 },
264-
"novelty": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.1 },
265-
"recency": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.1 },
266-
"typePrior": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.6 }
283+
"utility": {
284+
"type": "number",
285+
"minimum": 0,
286+
"maximum": 1,
287+
"default": 0.1
288+
},
289+
"confidence": {
290+
"type": "number",
291+
"minimum": 0,
292+
"maximum": 1,
293+
"default": 0.1
294+
},
295+
"novelty": {
296+
"type": "number",
297+
"minimum": 0,
298+
"maximum": 1,
299+
"default": 0.1
300+
},
301+
"recency": {
302+
"type": "number",
303+
"minimum": 0,
304+
"maximum": 1,
305+
"default": 0.1
306+
},
307+
"typePrior": {
308+
"type": "number",
309+
"minimum": 0,
310+
"maximum": 1,
311+
"default": 0.6
312+
}
267313
}
268314
},
269315
"typePriors": {
270316
"type": "object",
271317
"additionalProperties": false,
272318
"properties": {
273-
"profile": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.95 },
274-
"preferences": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.9 },
275-
"entities": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.75 },
276-
"events": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.45 },
277-
"cases": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.8 },
278-
"patterns": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.85 }
319+
"profile": {
320+
"type": "number",
321+
"minimum": 0,
322+
"maximum": 1,
323+
"default": 0.95
324+
},
325+
"preferences": {
326+
"type": "number",
327+
"minimum": 0,
328+
"maximum": 1,
329+
"default": 0.9
330+
},
331+
"entities": {
332+
"type": "number",
333+
"minimum": 0,
334+
"maximum": 1,
335+
"default": 0.75
336+
},
337+
"events": {
338+
"type": "number",
339+
"minimum": 0,
340+
"maximum": 1,
341+
"default": 0.45
342+
},
343+
"cases": {
344+
"type": "number",
345+
"minimum": 0,
346+
"maximum": 1,
347+
"default": 0.8
348+
},
349+
"patterns": {
350+
"type": "number",
351+
"minimum": 0,
352+
"maximum": 1,
353+
"default": 0.85
354+
}
279355
}
280356
}
281357
}
@@ -1146,7 +1222,7 @@
11461222
},
11471223
"decay.intrinsicWeight": {
11481224
"label": "Decay Intrinsic Weight",
1149-
"help": "Weight of importance × confidence in lifecycle score.",
1225+
"help": "Weight of importance \u00d7 confidence in lifecycle score.",
11501226
"advanced": true
11511227
},
11521228
"decay.betaCore": {
@@ -1353,7 +1429,7 @@
13531429
},
13541430
"memoryCompaction.similarityThreshold": {
13551431
"label": "Similarity Threshold",
1356-
"help": "How similar two memories must be to merge (0–1). 0.88 is a good starting point; raise to 0.92+ for conservative merges.",
1432+
"help": "How similar two memories must be to merge (0\u20131). 0.88 is a good starting point; raise to 0.92+ for conservative merges.",
13571433
"advanced": true
13581434
},
13591435
"memoryCompaction.cooldownHours": {
@@ -1380,4 +1456,4 @@
13801456
"advanced": true
13811457
}
13821458
}
1383-
}
1459+
}

0 commit comments

Comments
 (0)