Skip to content

Commit 821dc1d

Browse files
feat: add install scripts (#1323)
## Description add install or update scripts for memos openclaw local plugin Related Issue (Required): Fixes #issue_number ## Type of change Please delete options that are not relevant. - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Refactor (does not change functionality, e.g. code style improvements, linting) - [ ] Documentation update ## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - [ ] Unit Test - [ ] Test Script Or Test Steps (please provide) - [ ] Pipeline Automated API Test (please provide) ## Checklist - [ ] I have performed a self-review of my own code | 我已自行检查了自己的代码 - [ ] I have commented my code in hard-to-understand areas | 我已在难以理解的地方对代码进行了注释 - [ ] I have added tests that prove my fix is effective or that my feature works | 我已添加测试以证明我的修复有效或功能正常 - [ ] I have created related documentation issue/PR in [MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) (if applicable) | 我已在 [MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) 中创建了相关的文档 issue/PR(如果适用) - [ ] I have linked the issue to this PR (if applicable) | 我已将 issue 链接到此 PR(如果适用) - [ ] I have mentioned the person who will review this PR | 我已提及将审查此 PR 的人 ## Reviewer Checklist - [ ] closes #xxxx (Replace xxxx with the GitHub issue number) - [ ] Made sure Checks passed - [ ] Tests have been provided
2 parents 84028f2 + 629adb9 commit 821dc1d

File tree

3 files changed

+716
-15
lines changed

3 files changed

+716
-15
lines changed

apps/memos-local-openclaw/index.ts

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,6 +1779,31 @@ Groups: ${groupNames.length > 0 ? groupNames.join(", ") : "(none)"}`,
17791779
{ name: "network_skill_pull" },
17801780
);
17811781

1782+
// ─── Inject recall context as system message (hidden from chat UI) ───
1783+
// `prependContext` (from before_agent_start) is prepended to user messages and
1784+
// therefore visible in the chat box. To keep injected memories invisible to the
1785+
// user while still feeding them to the model, we stash the recall result in
1786+
// `pendingRecallContext` and inject it as a system-level message via the
1787+
// `before_context_send` hook, which fires synchronously during prompt assembly.
1788+
let pendingRecallContext: string | null = null;
1789+
1790+
api.on("before_context_send", (event: { messages: Array<{ role: string; content: string | unknown }> }) => {
1791+
if (!pendingRecallContext) return;
1792+
const memoryContext = pendingRecallContext;
1793+
pendingRecallContext = null;
1794+
// Insert after the last system message (before the first user/assistant turn).
1795+
// This keeps the static system prompt at the very beginning of the sequence so
1796+
// KV-cache prefixes stay stable across requests — the provider can reuse the
1797+
// cached keys/values for the system prompt even though the memory block changes.
1798+
const firstNonSystemIdx = event.messages.findIndex((m) => m.role !== "system");
1799+
if (firstNonSystemIdx === -1) {
1800+
event.messages.push({ role: "system", content: memoryContext });
1801+
} else {
1802+
event.messages.splice(firstNonSystemIdx, 0, { role: "system", content: memoryContext });
1803+
}
1804+
ctx.log.info(`before_context_send: injected recall context as system message at idx=${firstNonSystemIdx === -1 ? event.messages.length - 1 : firstNonSystemIdx} (${memoryContext.length} chars)`);
1805+
});
1806+
17821807
// ─── Auto-recall: inject relevant memories before agent starts ───
17831808

17841809
api.on("before_agent_start", async (event: { prompt?: string; messages?: unknown[] }, hookCtx?: { agentId?: string; sessionKey?: string }) => {
@@ -1884,7 +1909,8 @@ Groups: ${groupNames.length > 0 ? groupNames.join(", ") : "(none)"}`,
18841909
"\n\nYou SHOULD call `skill_get` to retrieve the full guide before attempting the task.";
18851910
ctx.log.info(`auto-recall-skill (no-memory path): injecting ${topSkills.length} skill(s)`);
18861911
try { store.recordApiLog("skill_search", { type: "auto_recall_skill", query }, JSON.stringify(topSkills), dur, true); } catch { /* best-effort */ }
1887-
return { prependContext: skillContext };
1912+
pendingRecallContext = skillContext;
1913+
return {};
18881914
}
18891915
} catch (err) {
18901916
ctx.log.debug(`auto-recall-skill (no-memory path): failed: ${err}`);
@@ -1893,11 +1919,11 @@ Groups: ${groupNames.length > 0 ? groupNames.join(", ") : "(none)"}`,
18931919

18941920
if (query.length > 50) {
18951921
const noRecallHint =
1896-
"## Memory system — ACTION REQUIRED\n\n" +
1922+
"## Memory system\n\n" +
18971923
"Auto-recall found no results for a long query. " +
1898-
"You MUST call `memory_search` now with a shortened query (2-5 key words) before answering. " +
1899-
"Do NOT skip this step. Do NOT answer without searching first.";
1900-
return { prependContext: noRecallHint };
1924+
"Call `memory_search` with a shortened query (2-5 key words) before answering.";
1925+
pendingRecallContext = noRecallHint;
1926+
return {};
19011927
}
19021928
return;
19031929
}
@@ -1933,7 +1959,7 @@ Groups: ${groupNames.length > 0 ? groupNames.join(", ") : "(none)"}`,
19331959
}), dur, true);
19341960
if (query.length > 50) {
19351961
const noRecallHint =
1936-
"## Memory system — ACTION REQUIRED\n\n" +
1962+
"## Memory system\n\n" +
19371963
"Auto-recall found no relevant results for a long query. " +
19381964
"You MUST call `memory_search` now with a shortened query (2-5 key words) before answering. " +
19391965
"Do NOT skip this step. Do NOT answer without searching first.";
@@ -1985,11 +2011,9 @@ Groups: ${groupNames.length > 0 ? groupNames.join(", ") : "(none)"}`,
19852011
const tipsText = "\n\nAvailable follow-up tools:\n" + tips.join("\n");
19862012

19872013
const contextParts = [
1988-
"## User's conversation history (from memory system)",
2014+
"## Recalled memories",
19892015
"",
1990-
"IMPORTANT: The following are facts from previous conversations with this user.",
1991-
"You MUST treat these as established knowledge and use them directly when answering.",
1992-
"Do NOT say you don't know or don't have information if the answer is in these memories.",
2016+
"The following facts were retrieved from previous conversations with this user. Treat them as established knowledge.",
19932017
"",
19942018
lines.join("\n\n"),
19952019
];
@@ -2073,18 +2097,18 @@ Groups: ${groupNames.length > 0 ? groupNames.join(", ") : "(none)"}`,
20732097
}), recallDur, true);
20742098
telemetry.trackAutoRecall(filteredHits.length, recallDur);
20752099

2076-
ctx.log.info(`auto-recall: returning prependContext (${context.length} chars), sufficient=${sufficient}, skills=${skillSection ? "yes" : "no"}`);
2100+
ctx.log.info(`auto-recall: stashing recall context for system message injection (${context.length} chars), sufficient=${sufficient}, skills=${skillSection ? "yes" : "no"}`);
20772101

20782102
if (!sufficient) {
20792103
const searchHint =
20802104
"\n\nIf these memories don't fully answer the question, " +
20812105
"call `memory_search` with a shorter or rephrased query to find more.";
2082-
return { prependContext: context + searchHint };
2106+
pendingRecallContext = context + searchHint;
2107+
return {};
20832108
}
20842109

2085-
return {
2086-
prependContext: context,
2087-
};
2110+
pendingRecallContext = context;
2111+
return {};
20882112
} catch (err) {
20892113
const dur = performance.now() - recallT0;
20902114
store.recordToolCall("memory_search", dur, false);

0 commit comments

Comments
 (0)