Hooks: persist session memory on /reset

This commit is contained in:
Vignesh Natarajan
2026-02-20 20:19:29 -08:00
parent 544c213d42
commit d583399c92
8 changed files with 39 additions and 19 deletions

View File

@@ -6,9 +6,9 @@ This directory contains hooks that ship with OpenClaw. These hooks are automatic
### 💾 session-memory
Automatically saves session context to memory when you issue `/new`.
Automatically saves session context to memory when you issue `/new` or `/reset`.
**Events**: `command:new`
**Events**: `command:new`, `command:reset`
**What it does**: Creates a dated memory file with LLM-generated slug based on conversation content.
**Output**: `<workspace>/memory/YYYY-MM-DD-slug.md` (defaults to `~/.openclaw/workspace`)

View File

@@ -1,13 +1,13 @@
---
name: session-memory
description: "Save session context to memory when /new command is issued"
description: "Save session context to memory when /new or /reset command is issued"
homepage: https://docs.openclaw.ai/automation/hooks#session-memory
metadata:
{
"openclaw":
{
"emoji": "💾",
"events": ["command:new"],
"events": ["command:new", "command:reset"],
"requires": { "config": ["workspace.dir"] },
"install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with OpenClaw" }],
},
@@ -16,11 +16,11 @@ metadata:
# Session Memory Hook
Automatically saves session context to your workspace memory when you issue the `/new` command.
Automatically saves session context to your workspace memory when you issue `/new` or `/reset`.
## What It Does
When you run `/new` to start a fresh session:
When you run `/new` or `/reset` to start a fresh session:
1. **Finds the previous session** - Uses the pre-reset session entry to locate the correct transcript
2. **Extracts conversation** - Reads the last N user/assistant messages from the session (default: 15, configurable)

View File

@@ -44,8 +44,9 @@ async function runNewWithPreviousSessionEntry(params: {
tempDir: string;
previousSessionEntry: { sessionId: string; sessionFile?: string };
cfg?: OpenClawConfig;
action?: "new" | "reset";
}): Promise<{ files: string[]; memoryContent: string }> {
const event = createHookEvent("command", "new", "agent:main:main", {
const event = createHookEvent("command", params.action ?? "new", "agent:main:main", {
cfg:
params.cfg ??
({
@@ -66,6 +67,7 @@ async function runNewWithPreviousSessionEntry(params: {
async function runNewWithPreviousSession(params: {
sessionContent: string;
cfg?: (tempDir: string) => OpenClawConfig;
action?: "new" | "reset";
}): Promise<{ tempDir: string; files: string[]; memoryContent: string }> {
const tempDir = await makeTempWorkspace("openclaw-session-memory-");
const sessionsDir = path.join(tempDir, "sessions");
@@ -86,6 +88,7 @@ async function runNewWithPreviousSession(params: {
const { files, memoryContent } = await runNewWithPreviousSessionEntry({
tempDir,
cfg,
action: params.action,
previousSessionEntry: {
sessionId: "test-123",
sessionFile,
@@ -158,6 +161,21 @@ describe("session-memory hook", () => {
expect(memoryContent).toContain("assistant: 2+2 equals 4");
});
it("creates memory file with session content on /reset command", async () => {
const sessionContent = createMockSessionContent([
{ role: "user", content: "Please reset and keep notes" },
{ role: "assistant", content: "Captured before reset" },
]);
const { files, memoryContent } = await runNewWithPreviousSession({
sessionContent,
action: "reset",
});
expect(files.length).toBe(1);
expect(memoryContent).toContain("user: Please reset and keep notes");
expect(memoryContent).toContain("assistant: Captured before reset");
});
it("filters out non-message entries (tool calls, system)", async () => {
// Create session with mixed entry types
const sessionContent = createMockSessionContent([

View File

@@ -1,7 +1,7 @@
/**
* Session memory hook handler
*
* Saves session context to memory when /new command is triggered
* Saves session context to memory when /new or /reset command is triggered
* Creates a new dated memory file with LLM-generated slug
*/
@@ -167,16 +167,17 @@ async function findPreviousSessionFile(params: {
}
/**
* Save session context to memory when /new command is triggered
* Save session context to memory when /new or /reset command is triggered
*/
const saveSessionToMemory: HookHandler = async (event) => {
// Only trigger on 'new' command
if (event.type !== "command" || event.action !== "new") {
// Only trigger on reset/new commands
const isResetCommand = event.action === "new" || event.action === "reset";
if (event.type !== "command" || !isResetCommand) {
return;
}
try {
log.debug("Hook triggered for /new command");
log.debug("Hook triggered for reset/new command", { action: event.action });
const context = event.context || {};
const cfg = context.cfg as OpenClawConfig | undefined;