Merge ce8f0c2de1bb6a816c0bbc180e1da0aafc7c7961 into 5bb5d7dab4b29e68b15bb7665d0736f46499a35c
This commit is contained in:
commit
cfebb54fc1
@ -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({
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user