mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 14:38:25 +00:00
fix(cron): reuse existing sessionId for webhook/cron sessions
When a webhook or cron job provides a stable sessionKey, the session should maintain conversation history across invocations. Previously, resolveCronSession always generated a new sessionId and hardcoded isNewSession: true, preventing any conversation continuity. Changes: - Check if existing entry has a valid sessionId - Evaluate freshness using configured reset policy - Reuse sessionId and set isNewSession: false when fresh - Add forceNew parameter to override reuse behavior - Spread existing entry to preserve conversation context This enables persistent, stateful conversations for webhook-driven agent endpoints when allowRequestSessionKey is configured. Fixes #18027
This commit is contained in:
committed by
Peter Steinberger
parent
952db1a3e2
commit
57c8f62396
@@ -1,12 +1,19 @@
|
||||
import crypto from "node:crypto";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { loadSessionStore, resolveStorePath, type SessionEntry } from "../../config/sessions.js";
|
||||
import {
|
||||
evaluateSessionFreshness,
|
||||
loadSessionStore,
|
||||
resolveSessionResetPolicy,
|
||||
resolveStorePath,
|
||||
type SessionEntry,
|
||||
} from "../../config/sessions.js";
|
||||
|
||||
export function resolveCronSession(params: {
|
||||
cfg: OpenClawConfig;
|
||||
sessionKey: string;
|
||||
nowMs: number;
|
||||
agentId: string;
|
||||
forceNew?: boolean;
|
||||
}) {
|
||||
const sessionCfg = params.cfg.session;
|
||||
const storePath = resolveStorePath(sessionCfg?.store, {
|
||||
@@ -14,12 +21,50 @@ export function resolveCronSession(params: {
|
||||
});
|
||||
const store = loadSessionStore(storePath);
|
||||
const entry = store[params.sessionKey];
|
||||
const sessionId = crypto.randomUUID();
|
||||
const systemSent = false;
|
||||
|
||||
// Check if we can reuse an existing session
|
||||
let sessionId: string;
|
||||
let isNewSession: boolean;
|
||||
let systemSent: boolean;
|
||||
|
||||
if (!params.forceNew && entry?.sessionId) {
|
||||
// Evaluate freshness using the configured reset policy
|
||||
// Cron/webhook sessions use "direct" reset type (1:1 conversation style)
|
||||
const resetPolicy = resolveSessionResetPolicy({
|
||||
sessionCfg,
|
||||
resetType: "direct",
|
||||
});
|
||||
const freshness = evaluateSessionFreshness({
|
||||
updatedAt: entry.updatedAt,
|
||||
now: params.nowMs,
|
||||
policy: resetPolicy,
|
||||
});
|
||||
|
||||
if (freshness.fresh) {
|
||||
// Reuse existing session
|
||||
sessionId = entry.sessionId;
|
||||
isNewSession = false;
|
||||
systemSent = entry.systemSent ?? false;
|
||||
} else {
|
||||
// Session expired, create new
|
||||
sessionId = crypto.randomUUID();
|
||||
isNewSession = true;
|
||||
systemSent = false;
|
||||
}
|
||||
} else {
|
||||
// No existing session or forced new
|
||||
sessionId = crypto.randomUUID();
|
||||
isNewSession = true;
|
||||
systemSent = false;
|
||||
}
|
||||
|
||||
const sessionEntry: SessionEntry = {
|
||||
// Spread existing entry to preserve conversation context when reusing
|
||||
...(isNewSession ? undefined : entry),
|
||||
sessionId,
|
||||
updatedAt: params.nowMs,
|
||||
systemSent,
|
||||
// Preserve user preferences from existing entry
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
model: entry?.model,
|
||||
@@ -34,5 +79,5 @@ export function resolveCronSession(params: {
|
||||
displayName: entry?.displayName,
|
||||
skillsSnapshot: entry?.skillsSnapshot,
|
||||
};
|
||||
return { storePath, store, sessionEntry, systemSent, isNewSession: true };
|
||||
return { storePath, store, sessionEntry, systemSent, isNewSession };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user