mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-25 16:12:13 +00:00
Persist generic binding touch updates
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
bindGenericCurrentConversation,
|
||||
getGenericCurrentConversationBindingCapabilities,
|
||||
resolveGenericCurrentConversationBinding,
|
||||
touchGenericCurrentConversationBinding,
|
||||
unbindGenericCurrentConversationBindings,
|
||||
} from "./current-conversation-bindings.js";
|
||||
|
||||
@@ -248,4 +249,41 @@ describe("generic current-conversation bindings", () => {
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("persists touched activity across reloads", async () => {
|
||||
const bound = await bindGenericCurrentConversation({
|
||||
targetSessionKey: "agent:codex:acp:slack-dm",
|
||||
targetKind: "session",
|
||||
conversation: {
|
||||
channel: "slack",
|
||||
accountId: "default",
|
||||
conversationId: "user:U123",
|
||||
},
|
||||
metadata: {
|
||||
label: "slack-dm",
|
||||
},
|
||||
});
|
||||
|
||||
expect(bound).not.toBeNull();
|
||||
|
||||
touchGenericCurrentConversationBinding(
|
||||
"generic:slack\u241fdefault\u241f\u241fuser:U123",
|
||||
1_234_567_890,
|
||||
);
|
||||
|
||||
__testing.resetCurrentConversationBindingsForTests();
|
||||
|
||||
expect(
|
||||
resolveGenericCurrentConversationBinding({
|
||||
channel: "slack",
|
||||
accountId: "default",
|
||||
conversationId: "user:U123",
|
||||
})?.metadata,
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
label: "slack-dm",
|
||||
lastActivityAt: 1_234_567_890,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import { normalizeConversationText } from "../../acp/conversation-id.js";
|
||||
import { normalizeAnyChannelId } from "../../channels/registry.js";
|
||||
import { resolveStateDir } from "../../config/paths.js";
|
||||
import { loadJsonFile } from "../../infra/json-file.js";
|
||||
import { writeJsonFileAtomically } from "../../plugin-sdk/json-store.js";
|
||||
import { saveJsonFile } from "../../plugin-sdk/json-store.js";
|
||||
import { getActivePluginChannelRegistryFromState } from "../../plugins/runtime-state.js";
|
||||
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
|
||||
import { normalizeConversationRef } from "./session-binding-normalization.js";
|
||||
@@ -25,7 +25,6 @@ const CURRENT_BINDINGS_FILE_VERSION = 1;
|
||||
const CURRENT_BINDINGS_ID_PREFIX = "generic:";
|
||||
|
||||
let bindingsLoaded = false;
|
||||
let persistPromise: Promise<void> = Promise.resolve();
|
||||
const bindingsByConversationKey = new Map<string, SessionBindingRecord>();
|
||||
|
||||
function buildConversationKey(ref: ConversationRef): string {
|
||||
@@ -85,17 +84,8 @@ function loadBindingsIntoMemory(): void {
|
||||
}
|
||||
}
|
||||
|
||||
async function persistBindingsToDisk(): Promise<void> {
|
||||
await writeJsonFileAtomically(resolveBindingsFilePath(), toPersistedFile());
|
||||
}
|
||||
|
||||
function enqueuePersist(): Promise<void> {
|
||||
persistPromise = persistPromise
|
||||
.catch(() => {})
|
||||
.then(async () => {
|
||||
await persistBindingsToDisk();
|
||||
});
|
||||
return persistPromise;
|
||||
function persistBindingsToDisk(): void {
|
||||
saveJsonFile(resolveBindingsFilePath(), toPersistedFile());
|
||||
}
|
||||
|
||||
function pruneExpiredBinding(key: string): SessionBindingRecord | null {
|
||||
@@ -108,7 +98,7 @@ function pruneExpiredBinding(key: string): SessionBindingRecord | null {
|
||||
return record;
|
||||
}
|
||||
bindingsByConversationKey.delete(key);
|
||||
void enqueuePersist();
|
||||
persistBindingsToDisk();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -183,7 +173,7 @@ export async function bindGenericCurrentConversation(
|
||||
},
|
||||
};
|
||||
bindingsByConversationKey.set(key, record);
|
||||
await enqueuePersist();
|
||||
persistBindingsToDisk();
|
||||
return record;
|
||||
}
|
||||
|
||||
@@ -225,6 +215,7 @@ export function touchGenericCurrentConversationBinding(bindingId: string, at = D
|
||||
lastActivityAt: at,
|
||||
},
|
||||
});
|
||||
persistBindingsToDisk();
|
||||
}
|
||||
|
||||
export async function unbindGenericCurrentConversationBindings(
|
||||
@@ -240,7 +231,7 @@ export async function unbindGenericCurrentConversationBindings(
|
||||
if (record) {
|
||||
bindingsByConversationKey.delete(key);
|
||||
removed.push(record);
|
||||
await enqueuePersist();
|
||||
persistBindingsToDisk();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
@@ -256,7 +247,7 @@ export async function unbindGenericCurrentConversationBindings(
|
||||
removed.push(record);
|
||||
}
|
||||
if (removed.length > 0) {
|
||||
await enqueuePersist();
|
||||
persistBindingsToDisk();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
@@ -268,7 +259,6 @@ export const __testing = {
|
||||
}) {
|
||||
bindingsLoaded = false;
|
||||
bindingsByConversationKey.clear();
|
||||
persistPromise = Promise.resolve();
|
||||
if (params?.deletePersistedFile) {
|
||||
const filePath = resolveBindingsFilePath(params.env);
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user