Merge ce8f0c2de1bb6a816c0bbc180e1da0aafc7c7961 into 5bb5d7dab4b29e68b15bb7665d0736f46499a35c

This commit is contained in:
Saurabh Mishra 2026-03-21 05:30:07 +00:00 committed by GitHub
commit cfebb54fc1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 40 additions and 12 deletions

View File

@ -5,7 +5,7 @@ import {
normalizeConversationText,
parseTelegramChatIdFromTarget,
} from "../../acp/conversation-id.js";
import { resolveSessionAgentId } from "../../agents/agent-scope.js";
import { resolveAgentWorkspaceDir, resolveSessionAgentId } from "../../agents/agent-scope.js";
import { clearBootstrapSnapshotOnSessionRollover } from "../../agents/bootstrap-cache.js";
import { normalizeChatType } from "../../channels/chat-type.js";
import type { OpenClawConfig } from "../../config/config.js";
@ -30,6 +30,7 @@ import {
} from "../../config/sessions.js";
import type { TtsAutoMode } from "../../config/types.tts.js";
import { archiveSessionTranscripts } from "../../gateway/session-utils.fs.js";
import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js";
import { resolveConversationIdFromTargets } from "../../infra/outbound/conversation-id.js";
import { deliverSessionMaintenanceWarning } from "../../infra/session-maintenance-warning.js";
import { createSubsystemLogger } from "../../logging/subsystem.js";
@ -557,6 +558,26 @@ export async function initSessionState(params: {
},
);
// When a session is auto-reset (idle timeout or daily reset), emit a
// session:reset internal hook so the session-memory hook can persist
// the outgoing session context — just as it does for manual /new and /reset.
// Note: this is fire-and-forget; if archival renames the transcript before
// the handler reads it, getRecentSessionContentWithResetFallback() will
// locate it via the .reset.* sibling naming convention.
if (isNewSession && !resetTriggered && previousSessionEntry) {
const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId);
const autoResetEvent = createInternalHookEvent("session", "reset", sessionKey, {
sessionEntry,
previousSessionEntry,
commandSource: "auto-reset",
workspaceDir,
cfg,
});
void triggerInternalHook(autoResetEvent).catch((err) => {
log.debug("session:reset hook error (auto-reset)", { error: String(err) });
});
}
// Archive old transcript so it doesn't accumulate on disk (#14869).
if (previousSessionEntry?.sessionId) {
archiveSessionTranscripts({

View File

@ -1,13 +1,13 @@
---
name: session-memory
description: "Save session context to memory when /new or /reset command is issued"
description: "Save session context to memory when session is reset (manual or automatic)"
homepage: https://docs.openclaw.ai/automation/hooks#session-memory
metadata:
{
"openclaw":
{
"emoji": "💾",
"events": ["command:new", "command:reset"],
"events": ["command:new", "command:reset", "session: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 `/new` or `/reset`.
Automatically saves session context to your workspace memory when a session is reset, whether manually (`/new`, `/reset`) or automatically (idle timeout, daily reset).
## What It Does
When you run `/new` or `/reset` to start a fresh session:
When a session is reset (manually via `/new`/`/reset` or automatically via idle timeout or daily reset):
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

@ -1,8 +1,10 @@
/**
* Session memory hook handler
*
* Saves session context to memory when /new or /reset command is triggered
* Creates a new dated memory file with LLM-generated slug
* Saves session context to memory when a session is reset.
* Handles both manual resets (/new, /reset) and automatic resets
* (idle timeout, daily reset). Creates a new dated memory file
* with LLM-generated slug.
*/
import fs from "node:fs/promises";
@ -194,17 +196,22 @@ async function findPreviousSessionFile(params: {
}
/**
* Save session context to memory when /new or /reset command is triggered
* Save session context to memory when session is reset.
*
* Triggers on:
* - command:new / command:reset (manual /new or /reset commands)
* - session:reset (automatic idle-timeout or daily resets)
*/
const saveSessionToMemory: HookHandler = async (event) => {
// Only trigger on reset/new commands
const isResetCommand = event.action === "new" || event.action === "reset";
if (event.type !== "command" || !isResetCommand) {
const isManualReset =
event.type === "command" && (event.action === "new" || event.action === "reset");
const isAutoReset = event.type === "session" && event.action === "reset";
if (!isManualReset && !isAutoReset) {
return;
}
try {
log.debug("Hook triggered for reset/new command", { action: event.action });
log.debug("Hook triggered for session reset", { type: event.type, action: event.action });
const context = event.context || {};
const cfg = context.cfg as OpenClawConfig | undefined;