mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 16:50:43 +00:00
fix: reject duplicate session entry slots
This commit is contained in:
@@ -142,6 +142,56 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects duplicate promoted SessionEntry slot keys across registrations", () => {
|
||||
const { config, registry } = createPluginRegistryFixture();
|
||||
registerTestPlugin({
|
||||
registry,
|
||||
config,
|
||||
record: createPluginRecord({ id: "slot-owner", name: "Slot Owner" }),
|
||||
register(api) {
|
||||
api.registerSessionExtension({
|
||||
namespace: "workflow",
|
||||
description: "first promoted slot",
|
||||
sessionEntrySlotKey: "approvalSnapshot",
|
||||
});
|
||||
api.registerSessionExtension({
|
||||
namespace: "recovery",
|
||||
description: "same plugin duplicate slot",
|
||||
sessionEntrySlotKey: " approvalSnapshot ",
|
||||
});
|
||||
},
|
||||
});
|
||||
registerTestPlugin({
|
||||
registry,
|
||||
config,
|
||||
record: createPluginRecord({ id: "slot-colliding-plugin", name: "Slot Colliding" }),
|
||||
register(api) {
|
||||
api.registerSessionExtension({
|
||||
namespace: "workflow",
|
||||
description: "cross-plugin duplicate slot",
|
||||
sessionEntrySlotKey: "approvalSnapshot",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
expect(registry.registry.sessionExtensions ?? []).toHaveLength(1);
|
||||
expect(registry.registry.sessionExtensions?.[0]?.extension.sessionEntrySlotKey).toBe(
|
||||
"approvalSnapshot",
|
||||
);
|
||||
expect(registry.registry.diagnostics).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
pluginId: "slot-owner",
|
||||
message: "sessionEntrySlotKey already registered: approvalSnapshot",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
pluginId: "slot-colliding-plugin",
|
||||
message: "sessionEntrySlotKey already registered: approvalSnapshot",
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("clears promoted SessionEntry slots with plugin-owned session state", async () => {
|
||||
const { config, registry } = createPluginRegistryFixture();
|
||||
registerTestPlugin({
|
||||
|
||||
@@ -1626,6 +1626,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
|
||||
const namespace = normalizeHostHookString(extension.namespace);
|
||||
const description = normalizeHostHookString(extension.description);
|
||||
const project = extension.project;
|
||||
let normalizedSessionEntrySlotKey: string | undefined;
|
||||
let invalidMessage: string | undefined;
|
||||
if (!namespace || !description) {
|
||||
invalidMessage = "session extension registration requires namespace and description";
|
||||
@@ -1639,6 +1640,8 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
|
||||
const slotKey = normalizeSessionEntrySlotKey(extension.sessionEntrySlotKey);
|
||||
if (!slotKey.ok) {
|
||||
invalidMessage = slotKey.error;
|
||||
} else {
|
||||
normalizedSessionEntrySlotKey = slotKey.key;
|
||||
}
|
||||
}
|
||||
if (invalidMessage) {
|
||||
@@ -1662,6 +1665,28 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (normalizedSessionEntrySlotKey) {
|
||||
const existingSlot = (registry.sessionExtensions ?? []).find((entry) => {
|
||||
const existingSlotKey = entry.extension.sessionEntrySlotKey;
|
||||
if (existingSlotKey === undefined) {
|
||||
return false;
|
||||
}
|
||||
const normalizedExistingSlotKey = normalizeSessionEntrySlotKey(existingSlotKey);
|
||||
return (
|
||||
normalizedExistingSlotKey.ok &&
|
||||
normalizedExistingSlotKey.key === normalizedSessionEntrySlotKey
|
||||
);
|
||||
});
|
||||
if (existingSlot) {
|
||||
pushDiagnostic({
|
||||
level: "error",
|
||||
pluginId: record.id,
|
||||
source: record.source,
|
||||
message: `sessionEntrySlotKey already registered: ${normalizedSessionEntrySlotKey}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
(registry.sessionExtensions ??= []).push({
|
||||
pluginId: record.id,
|
||||
pluginName: record.name,
|
||||
@@ -1669,6 +1694,9 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
|
||||
...extension,
|
||||
namespace,
|
||||
description,
|
||||
...(normalizedSessionEntrySlotKey
|
||||
? { sessionEntrySlotKey: normalizedSessionEntrySlotKey }
|
||||
: {}),
|
||||
},
|
||||
source: record.source,
|
||||
rootDir: record.rootDir,
|
||||
|
||||
Reference in New Issue
Block a user