Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ interface PluginConfig {
recallMode?: "full" | "summary" | "adaptive" | "off";
/** 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. */
autoRecallExcludeAgents?: string[];
/** Agent IDs included in auto-recall injection (whitelist mode). When set, ONLY these agents receive auto-recall. Unresolved agent context falls back to 'main'. If both include and exclude are set, include wins. */
autoRecallIncludeAgents?: string[];
captureAssistant?: boolean;
retrieval?: {
mode?: "hybrid" | "vector";
Expand Down Expand Up @@ -2291,12 +2293,21 @@ const memoryLanceDBProPlugin = {
const sessionKey = typeof ctx.sessionKey === "string" ? ctx.sessionKey : "";
if (sessionKey.includes(":subagent:")) return;

// Per-agent exclusion: skip auto-recall for agents in the exclusion list.
// Per-agent inclusion/exclusion: autoRecallIncludeAgents takes precedence over autoRecallExcludeAgents.
// - If autoRecallIncludeAgents is set: ONLY these agents receive auto-recall
// - Else if autoRecallExcludeAgents is set: all agents EXCEPT these receive auto-recall

const agentId = resolveHookAgentId(ctx?.agentId, (event as any).sessionKey);
if (
if (Array.isArray(config.autoRecallIncludeAgents) && config.autoRecallIncludeAgents.length > 0) {
if (!config.autoRecallIncludeAgents.includes(agentId)) {
api.logger.debug?.(
`memory-lancedb-pro: auto-recall skipped for agent '${agentId}' not in autoRecallIncludeAgents`,
);
return;
}
} else if (
Array.isArray(config.autoRecallExcludeAgents) &&
config.autoRecallExcludeAgents.length > 0 &&
agentId !== undefined &&
config.autoRecallExcludeAgents.includes(agentId)
) {
api.logger.debug?.(
Expand Down Expand Up @@ -3995,7 +4006,14 @@ export function parsePluginConfig(value: unknown): PluginConfig {
maxRecallPerTurn: parsePositiveInt(cfg.maxRecallPerTurn) ?? 10,
recallMode: (cfg.recallMode === "full" || cfg.recallMode === "summary" || cfg.recallMode === "adaptive" || cfg.recallMode === "off") ? cfg.recallMode : "full",
autoRecallExcludeAgents: Array.isArray(cfg.autoRecallExcludeAgents)
? cfg.autoRecallExcludeAgents.filter((id: unknown): id is string => typeof id === "string" && id.trim() !== "")
? cfg.autoRecallExcludeAgents
.filter((id: unknown): id is string => typeof id === "string" && id.trim() !== "")
.map((id) => id.trim())
: undefined,
autoRecallIncludeAgents: Array.isArray(cfg.autoRecallIncludeAgents)
? cfg.autoRecallIncludeAgents
.filter((id: unknown): id is string => typeof id === "string" && id.trim() !== "")
.map((id) => id.trim())
: undefined,
captureAssistant: cfg.captureAssistant === true,
retrieval:
Expand Down
31 changes: 29 additions & 2 deletions openclaw.plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"description": "Enhanced LanceDB-backed long-term memory with hybrid retrieval, multi-scope isolation, long-context chunking, and management CLI",
"version": "1.1.0-beta.10",
"kind": "memory",
"skills": ["./skills"],
"skills": [
"./skills"
],
"configSchema": {
"type": "object",
"additionalProperties": false,
Expand Down Expand Up @@ -165,6 +167,18 @@
"default": "full",
"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."
},
"autoRecallExcludeAgents": {
"type": "array",
"items": { "type": "string" },
"default": [],
"description": "Blacklist mode for auto-recall injection. Agents in this list are skipped. Agent resolution falls back to 'main' when no explicit agentId is available. If autoRecallIncludeAgents is also set, include wins."
},
"autoRecallIncludeAgents": {
"type": "array",
"items": { "type": "string" },
"default": [],
"description": "Whitelist mode for auto-recall injection. Only agents in this list receive auto-recall. Agent resolution falls back to 'main' when no explicit agentId is available. If both include and exclude are set, autoRecallIncludeAgents takes precedence (whitelist wins)."
},
"captureAssistant": {
"type": "boolean"
},
Expand Down Expand Up @@ -854,7 +868,10 @@
}
}
}
}
},
"required": [
"embedding"
]
},
"uiHints": {
"embedding.apiKey": {
Expand Down Expand Up @@ -1376,6 +1393,16 @@
"label": "Max Extractions Per Hour",
"help": "Rate limit for auto-capture extractions. Prevents excessive LLM calls during rapid-fire sessions.",
"advanced": true
},
"autoRecallExcludeAgents": {
"label": "Auto-Recall Excluded Agents",
"help": "Blacklist mode. Agents here are skipped for auto-recall. If agentId is unavailable it falls back to 'main'. If autoRecallIncludeAgents is set, include wins.",
"advanced": true
},
"autoRecallIncludeAgents": {
"label": "Auto-Recall Included Agents",
"help": "Whitelist mode. Only these agents receive auto-recall. If agentId is unavailable it falls back to 'main'. Includes take precedence over excludes.",
"advanced": true
}
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"author": "win4r",
"license": "MIT",
"scripts": {
"test": "node scripts/verify-ci-test-manifest.mjs && npm run test:cli-smoke && npm run test:core-regression && npm run test:storage-and-schema && npm run test:llm-clients-and-auth && npm run test:packaging-and-workflow",
"test": "node test/embedder-error-hints.test.mjs && node test/cjk-recursion-regression.test.mjs && node test/migrate-legacy-schema.test.mjs && node --test test/config-session-strategy-migration.test.mjs && node --test test/scope-access-undefined.test.mjs && node --test test/reflection-bypass-hook.test.mjs && node --test test/smart-extractor-scope-filter.test.mjs && node --test test/store-empty-scope-filter.test.mjs && node --test test/recall-text-cleanup.test.mjs && node test/update-consistency-lancedb.test.mjs && node --test test/strip-envelope-metadata.test.mjs && node test/cli-smoke.mjs && node test/functional-e2e.mjs && node --test test/per-agent-auto-recall.test.mjs && node test/retriever-rerank-regression.mjs && node test/smart-memory-lifecycle.mjs && node test/smart-extractor-branches.mjs && node test/plugin-manifest-regression.mjs && node --test test/session-summary-before-reset.test.mjs && node --test test/sync-plugin-version.test.mjs && node test/smart-metadata-v2.mjs && node test/vector-search-cosine.test.mjs && node test/context-support-e2e.mjs && node test/temporal-facts.test.mjs && node test/memory-update-supersede.test.mjs && node test/memory-upgrader-diagnostics.test.mjs && node --test test/llm-api-key-client.test.mjs && node --test test/llm-oauth-client.test.mjs && node --test test/cli-oauth-login.test.mjs && node --test test/workflow-fork-guards.test.mjs && node --test test/clawteam-scope.test.mjs && node --test test/cross-process-lock.test.mjs && node --test test/preference-slots.test.mjs && node test/is-latest-auto-supersede.test.mjs && node --test test/temporal-awareness.test.mjs",
"test:cli-smoke": "node scripts/run-ci-tests.mjs --group cli-smoke",
"test:core-regression": "node scripts/run-ci-tests.mjs --group core-regression",
"test:storage-and-schema": "node scripts/run-ci-tests.mjs --group storage-and-schema",
Expand Down Expand Up @@ -62,4 +62,4 @@
"jiti": "^2.6.0",
"typescript": "^5.9.3"
}
}
}
2 changes: 1 addition & 1 deletion scripts/ci-test-manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const CI_TEST_MANIFEST = [
{ group: "core-regression", runner: "node", file: "test/strip-envelope-metadata.test.mjs", args: ["--test"] },
{ group: "cli-smoke", runner: "node", file: "test/cli-smoke.mjs" },
{ group: "cli-smoke", runner: "node", file: "test/functional-e2e.mjs" },
{ group: "storage-and-schema", runner: "node", file: "test/per-agent-auto-recall.test.mjs", args: ["--test"] },
{ group: "core-regression", runner: "node", file: "test/retriever-rerank-regression.mjs" },
{ group: "core-regression", runner: "node", file: "test/smart-memory-lifecycle.mjs" },
{ group: "core-regression", runner: "node", file: "test/smart-extractor-branches.mjs" },
Expand All @@ -41,7 +42,6 @@ export const CI_TEST_MANIFEST = [
{ group: "storage-and-schema", runner: "node", file: "test/cross-process-lock.test.mjs", args: ["--test"] },
{ group: "core-regression", runner: "node", file: "test/preference-slots.test.mjs", args: ["--test"] },
{ group: "core-regression", runner: "node", file: "test/is-latest-auto-supersede.test.mjs" },
{ group: "core-regression", runner: "node", file: "test/hook-dedup-phase1.test.mjs", args: ["--test"] },
{ group: "core-regression", runner: "node", file: "test/temporal-awareness.test.mjs", args: ["--test"] },
// Issue #598 regression tests
{ group: "core-regression", runner: "node", file: "test/store-serialization.test.mjs" },
Expand Down
1 change: 1 addition & 0 deletions scripts/verify-ci-test-manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const EXPECTED_BASELINE = [
{ group: "core-regression", runner: "node", file: "test/strip-envelope-metadata.test.mjs", args: ["--test"] },
{ group: "cli-smoke", runner: "node", file: "test/cli-smoke.mjs" },
{ group: "cli-smoke", runner: "node", file: "test/functional-e2e.mjs" },
{ group: "storage-and-schema", runner: "node", file: "test/per-agent-auto-recall.test.mjs", args: ["--test"] },
{ group: "core-regression", runner: "node", file: "test/retriever-rerank-regression.mjs" },
{ group: "core-regression", runner: "node", file: "test/smart-memory-lifecycle.mjs" },
{ group: "core-regression", runner: "node", file: "test/smart-extractor-branches.mjs" },
Expand Down
Loading
Loading