mirror of https://github.com/openclaw/openclaw.git
Hooks: persist session memory on /reset
This commit is contained in:
parent
544c213d42
commit
d583399c92
|
|
@ -45,6 +45,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Gateway/Pairing: clear persisted paired-device state when the gateway client closes with `device token mismatch` (`1008`) so reconnect flows can cleanly re-enter pairing. (#22071) Thanks @mbelinky.
|
||||
- Memory/QMD: respect per-agent `memorySearch.enabled=false` during gateway QMD startup initialization, split multi-collection QMD searches into per-collection queries (`search`/`vsearch`/`query`) to avoid sparse-term drops, prefer collection-hinted doc resolution to avoid stale-hash collisions, retry boot updates on transient lock/timeout failures, skip `qmd embed` in BM25-only `search` mode (including `memory index --force`), and serialize embed runs globally with failure backoff to prevent CPU storms on multi-agent hosts. (#20581, #21590, #20513, #20001, #21266, #21583, #20346, #19493) Thanks @danielrevivo, @zanderkrause, @sunyan034-cmd, @tilleulenspiegel, @dae-oss, @adamlongcreativellc, @jonathanadams96, and @kiliansitel.
|
||||
- Memory/Builtin: prevent automatic sync races with manager shutdown by skipping post-close sync starts and waiting for in-flight sync before closing SQLite, so `onSearch`/`onSessionStart` no longer fail with `database is not open` in ephemeral CLI flows. (#20556, #7464) Thanks @FuzzyTG and @henrybottter.
|
||||
- Hooks/Session memory: trigger bundled `session-memory` persistence on both `/new` and `/reset` so reset flows no longer skip markdown transcript capture before archival. (#21382) Thanks @mofesolapaul.
|
||||
- Signal/Outbound: preserve case for Base64 group IDs during outbound target normalization so cross-context routing and policy checks no longer break when group IDs include uppercase characters. (#5578) Thanks @heyhudson.
|
||||
- Providers/Copilot: drop persisted assistant `thinking` blocks for Claude models (while preserving turn structure/tool blocks) so follow-up requests no longer fail on invalid `thinkingSignature` payloads. (#19459) Thanks @jackheuberger.
|
||||
- Providers/Copilot: add `claude-sonnet-4.6` and `claude-sonnet-4.5` to the default GitHub Copilot model catalog and add coverage for model-list/definition helpers. (#20270, fixes #20091) Thanks @Clawborn.
|
||||
|
|
|
|||
|
|
@ -86,13 +86,13 @@ describe("onboard-hooks", () => {
|
|||
createMockHook(
|
||||
{
|
||||
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",
|
||||
filePath: "/mock/workspace/hooks/session-memory/HOOK.md",
|
||||
baseDir: "/mock/workspace/hooks/session-memory",
|
||||
handlerPath: "/mock/workspace/hooks/session-memory/handler.js",
|
||||
hookKey: "session-memory",
|
||||
emoji: "💾",
|
||||
events: ["command:new"],
|
||||
events: ["command:new", "command:reset"],
|
||||
},
|
||||
eligible,
|
||||
),
|
||||
|
|
@ -147,7 +147,7 @@ describe("onboard-hooks", () => {
|
|||
{
|
||||
value: "session-memory",
|
||||
label: "💾 session-memory",
|
||||
hint: "Save session context to memory when /new command is issued",
|
||||
hint: "Save session context to memory when /new or /reset command is issued",
|
||||
},
|
||||
{
|
||||
value: "command-logger",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export async function setupInternalHooks(
|
|||
await prompter.note(
|
||||
[
|
||||
"Hooks let you automate actions when agent commands are issued.",
|
||||
"Example: Save session context to memory when you issue /new.",
|
||||
"Example: Save session context to memory when you issue /new or /reset.",
|
||||
"",
|
||||
"Learn more: https://docs.openclaw.ai/automation/hooks",
|
||||
].join("\n"),
|
||||
|
|
|
|||
|
|
@ -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`)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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([
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -232,14 +232,14 @@ describe("resolveOpenClawMetadata", () => {
|
|||
// This is the actual format used in the bundled hooks
|
||||
const content = `---
|
||||
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" }],
|
||||
},
|
||||
|
|
@ -256,7 +256,7 @@ metadata:
|
|||
const openclaw = resolveOpenClawMetadata(frontmatter);
|
||||
expect(openclaw).toBeDefined();
|
||||
expect(openclaw?.emoji).toBe("💾");
|
||||
expect(openclaw?.events).toEqual(["command:new"]);
|
||||
expect(openclaw?.events).toEqual(["command:new", "command:reset"]);
|
||||
expect(openclaw?.requires?.config).toEqual(["workspace.dir"]);
|
||||
expect(openclaw?.install?.[0].kind).toBe("bundled");
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue