Merge 522c09656fd59e469948b2316aa54c525804cbd0 into 5e417b44e1540f528d2ae63e3e20229a902d1db2

This commit is contained in:
Bryan Tegomoh, MD, MPH 2026-03-20 21:50:59 -04:00 committed by GitHub
commit f78950c282
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 76 additions and 1 deletions

View File

@ -939,7 +939,7 @@ export async function updateLastRoute(params: {
lastAccountId: normalized.lastAccountId,
lastThreadId: normalized.lastThreadId,
};
const next = mergeSessionEntry(
const next = mergeSessionEntryPreserveActivity(
existing,
metaPatch ? { ...basePatch, ...metaPatch } : basePatch,
);

View File

@ -0,0 +1,75 @@
import crypto from "node:crypto";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { clearSessionStoreCacheForTest, loadSessionStore, saveSessionStore, updateLastRoute } from "./store.js";
import type { SessionEntry } from "./types.js";
// Prevent reads of a real openclaw.json during tests.
vi.mock("../config.js", () => ({
loadConfig: vi.fn().mockReturnValue({}),
}));
let testDir = "";
beforeEach(async () => {
testDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ulr-test-"));
});
afterEach(async () => {
clearSessionStoreCacheForTest();
await fs.rm(testDir, { recursive: true, force: true });
});
function makeEntry(updatedAt: number): SessionEntry {
return { sessionId: crypto.randomUUID(), updatedAt };
}
describe("updateLastRoute", () => {
it("does not bump updatedAt for an existing session", async () => {
// Verifies fix for issue #49515: updateLastRoute was calling mergeSessionEntry
// which reset updatedAt to Date.now() on every inbound message, preventing
// idle/daily session resets from firing.
const storePath = path.join(testDir, "sessions.json");
const sessionKey = "agent:main:telegram:dm:user-1";
const originalUpdatedAt = Date.now() - 60_000; // 1 minute ago
const initial: Record<string, SessionEntry> = {
[sessionKey]: makeEntry(originalUpdatedAt),
};
await saveSessionStore(storePath, initial);
await updateLastRoute({
storePath,
sessionKey,
deliveryContext: { channel: "telegram", to: "telegram:user-1" },
});
const store = loadSessionStore(storePath);
const entry = store[sessionKey];
expect(entry).toBeDefined();
// updatedAt must not be bumped to wall-clock time — it should stay at originalUpdatedAt
// so that evaluateSessionFreshness can correctly detect idle sessions.
expect(entry!.updatedAt).toBe(originalUpdatedAt);
});
it("sets updatedAt to now for a new (non-existing) session", async () => {
const storePath = path.join(testDir, "sessions.json");
await saveSessionStore(storePath, {});
const before = Date.now();
await updateLastRoute({
storePath,
sessionKey: "agent:main:telegram:dm:user-2",
deliveryContext: { channel: "telegram", to: "telegram:user-2" },
});
const after = Date.now();
const store = loadSessionStore(storePath);
const entry = store["agent:main:telegram:dm:user-2"];
expect(entry).toBeDefined();
expect(entry!.updatedAt).toBeGreaterThanOrEqual(before);
expect(entry!.updatedAt).toBeLessThanOrEqual(after);
});
});