From b2e648d9c060825340f693f419cf3d69705ac602 Mon Sep 17 00:00:00 2001 From: selfboot Date: Fri, 30 Jan 2026 17:58:52 +0800 Subject: [PATCH] Webchat: canonicalize main session key for /new (fix #4446) --- src/auto-reply/reply/session.test.ts | 21 +++++++++++++++++++++ src/auto-reply/reply/session.ts | 3 +++ 2 files changed, 24 insertions(+) diff --git a/src/auto-reply/reply/session.test.ts b/src/auto-reply/reply/session.test.ts index db420ce32..1d6114aa8 100644 --- a/src/auto-reply/reply/session.test.ts +++ b/src/auto-reply/reply/session.test.ts @@ -108,6 +108,27 @@ describe("initSessionState thread forking", () => { }); describe("initSessionState RawBody", () => { + it("canonicalizes main session aliases for explicit SessionKey", async () => { + const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-alias-")); + const storePath = path.join(root, "sessions.json"); + const cfg = { + session: { store: storePath, mainKey: "work" }, + agents: { list: [{ id: "ops", default: true }] }, + } as OpenClawConfig; + + const result = await initSessionState({ + ctx: { + Body: "Hello", + SessionKey: "main", + }, + cfg, + commandAuthorized: true, + }); + + expect(result.sessionKey).toBe("agent:ops:work"); + expect(result.sessionCtx.SessionKey).toBe("agent:ops:work"); + }); + it("triggerBodyNormalized correctly extracts commands when Body contains context but RawBody is clean", async () => { const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-rawbody-")); const storePath = path.join(root, "sessions.json"); diff --git a/src/auto-reply/reply/session.ts b/src/auto-reply/reply/session.ts index d7f9305a7..283286eb9 100644 --- a/src/auto-reply/reply/session.ts +++ b/src/auto-reply/reply/session.ts @@ -8,6 +8,7 @@ import type { OpenClawConfig } from "../../config/config.js"; import type { TtsAutoMode } from "../../config/types.tts.js"; import { DEFAULT_RESET_TRIGGERS, + canonicalizeMainSessionAlias, deriveSessionMetaPatch, evaluateSessionFreshness, type GroupKeyResolution, @@ -187,6 +188,7 @@ export async function initSessionState(params: { } sessionKey = resolveSessionKey(sessionScope, sessionCtxForState, mainKey); + sessionKey = canonicalizeMainSessionAlias({ cfg, agentId, sessionKey }); const entry = sessionStore[sessionKey]; const previousSessionEntry = resetTriggered && entry ? { ...entry } : undefined; const now = Date.now(); @@ -337,6 +339,7 @@ export async function initSessionState(params: { const sessionCtx: TemplateContext = { ...ctx, + SessionKey: sessionKey, // Keep BodyStripped aligned with Body (best default for agent prompts). // RawBody is reserved for command/directive parsing and may omit context. BodyStripped: formatInboundBodyWithSenderMeta({