diff --git a/CHANGELOG.md b/CHANGELOG.md index e8b3d855300..56143615b29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Docs: https://docs.openclaw.ai - Telegram/media downloads: thread the same direct or proxy transport policy into SSRF-guarded file fetches so inbound attachments keep working when Telegram falls back between env-proxy and direct networking. (#44639) Thanks @obviyus. - Agents/compaction: compare post-compaction token sanity checks against full-session pre-compaction totals and skip the check when token estimation fails, so sessions with large bootstrap context keep real token counts instead of falling back to unknown. (#28347) thanks @efe-arv. - Discord/gateway startup: treat plain-text and transient `/gateway/bot` metadata fetch failures as transient startup errors so Discord gateway boot no longer crashes on unhandled rejections. (#44397) Thanks @jalehman. +- Gateway/session reset: preserve `lastAccountId` and `lastThreadId` across gateway session resets so replies keep routing back to the same account and thread after `/reset`. (#44773) Thanks @Lanfei. ## 2026.3.12 diff --git a/src/gateway/server.sessions.gateway-server-sessions-a.test.ts b/src/gateway/server.sessions.gateway-server-sessions-a.test.ts index 1decc4b9178..034020a61fe 100644 --- a/src/gateway/server.sessions.gateway-server-sessions-a.test.ts +++ b/src/gateway/server.sessions.gateway-server-sessions-a.test.ts @@ -266,6 +266,7 @@ describe("gateway server sessions", () => { lastChannel: "whatsapp", lastTo: "+1555", lastAccountId: "work", + lastThreadId: "1737500000.123456", }, "discord:group:dev": { sessionId: "sess-group", @@ -336,6 +337,7 @@ describe("gateway server sessions", () => { channel: "whatsapp", to: "+1555", accountId: "work", + threadId: "1737500000.123456", }); const active = await rpcReq<{ @@ -545,13 +547,27 @@ describe("gateway server sessions", () => { const reset = await rpcReq<{ ok: true; key: string; - entry: { sessionId: string; modelProvider?: string; model?: string }; + entry: { + sessionId: string; + modelProvider?: string; + model?: string; + lastAccountId?: string; + lastThreadId?: string | number; + }; }>(ws, "sessions.reset", { key: "agent:main:main" }); expect(reset.ok).toBe(true); expect(reset.payload?.key).toBe("agent:main:main"); expect(reset.payload?.entry.sessionId).not.toBe("sess-main"); expect(reset.payload?.entry.modelProvider).toBe("openai"); expect(reset.payload?.entry.model).toBe("gpt-test-a"); + expect(reset.payload?.entry.lastAccountId).toBe("work"); + expect(reset.payload?.entry.lastThreadId).toBe("1737500000.123456"); + const storeAfterReset = JSON.parse(await fs.readFile(storePath, "utf-8")) as Record< + string, + { lastAccountId?: string; lastThreadId?: string | number } + >; + expect(storeAfterReset["agent:main:main"]?.lastAccountId).toBe("work"); + expect(storeAfterReset["agent:main:main"]?.lastThreadId).toBe("1737500000.123456"); const filesAfterReset = await fs.readdir(dir); expect(filesAfterReset.some((f) => f.startsWith("sess-main.jsonl.reset."))).toBe(true);