mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(gateway): stabilize session creator facets (#116624)
This commit is contained in:
committed by
GitHub
parent
9ccc8fcc27
commit
2f860a7736
@@ -15,10 +15,90 @@ const getUserProfileListItem = vi.hoisted(() =>
|
||||
);
|
||||
|
||||
vi.mock("../state/user-profiles.js", () => ({ getUserProfileListItem }));
|
||||
vi.mock("./session-utils-row.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("./session-utils-row.js")>();
|
||||
return {
|
||||
...actual,
|
||||
projectSessionActor: (
|
||||
actor: Parameters<typeof actual.projectSessionActor>[0],
|
||||
identities: Parameters<typeof actual.projectSessionActor>[1],
|
||||
) => {
|
||||
if (actor?.id === "shared-id") {
|
||||
return actor.type === "human"
|
||||
? { type: actor.type, id: actor.id, label: "Alpha" }
|
||||
: { type: actor.type, id: actor.id, label: "Zulu", avatarUrl: "/avatar" };
|
||||
}
|
||||
if (actor?.id === "unicode-id") {
|
||||
return {
|
||||
type: actor.type,
|
||||
id: actor.id,
|
||||
label: actor.type === "human" ? "é" : "e\u0301",
|
||||
};
|
||||
}
|
||||
return actual.projectSessionActor(actor, identities);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
import { listSessionsFromStore, listSessionsFromStoreAsync } from "./session-utils.js";
|
||||
|
||||
afterEach(() => vi.restoreAllMocks());
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
getUserProfileListItem.mockClear();
|
||||
});
|
||||
|
||||
it("keeps creator labels and avatars stable across actor order", () => {
|
||||
const actorOrders = [
|
||||
["human", "agent"],
|
||||
["agent", "human"],
|
||||
] as const;
|
||||
for (const actorOrder of actorOrders) {
|
||||
const store = Object.fromEntries(
|
||||
actorOrder.map((type, index) => [
|
||||
`agent:main:${index}`,
|
||||
{
|
||||
createdActor: { type, id: "shared-id" },
|
||||
sessionId: `session-${index}`,
|
||||
updatedAt: 2 - index,
|
||||
} satisfies SessionEntry,
|
||||
]),
|
||||
);
|
||||
const result = listSessionsFromStore({
|
||||
cfg: {} as OpenClawConfig,
|
||||
storePath: "/tmp/openclaw-session-creator-order",
|
||||
store,
|
||||
opts: { archived: "all" },
|
||||
});
|
||||
|
||||
expect(result.creators).toEqual([{ id: "shared-id", label: "Alpha", avatarUrl: "/avatar" }]);
|
||||
}
|
||||
});
|
||||
|
||||
it("breaks locale-equivalent creator label ties deterministically", () => {
|
||||
for (const actorOrder of [
|
||||
["human", "agent"],
|
||||
["agent", "human"],
|
||||
] as const) {
|
||||
const store = Object.fromEntries(
|
||||
actorOrder.map((type, index) => [
|
||||
`agent:main:unicode-${index}`,
|
||||
{
|
||||
createdActor: { type, id: "unicode-id" },
|
||||
sessionId: `unicode-session-${index}`,
|
||||
updatedAt: 2 - index,
|
||||
} satisfies SessionEntry,
|
||||
]),
|
||||
);
|
||||
const result = listSessionsFromStore({
|
||||
cfg: {} as OpenClawConfig,
|
||||
storePath: "/tmp/openclaw-session-creator-unicode-order",
|
||||
store,
|
||||
opts: { archived: "all" },
|
||||
});
|
||||
|
||||
expect(result.creators).toEqual([{ id: "unicode-id", label: "e\u0301" }]);
|
||||
}
|
||||
});
|
||||
|
||||
it("returns the complete deterministic creator facet independently of pagination", () => {
|
||||
const store: Record<string, SessionEntry> = {
|
||||
|
||||
@@ -82,6 +82,16 @@ type SessionEntrySelection = {
|
||||
hasMore: boolean;
|
||||
};
|
||||
|
||||
function preferredCreatorIdentityValue(
|
||||
current: string | undefined,
|
||||
candidate: string | undefined,
|
||||
): string | undefined {
|
||||
if (!current || !candidate) {
|
||||
return current ?? candidate;
|
||||
}
|
||||
return candidate < current ? candidate : current;
|
||||
}
|
||||
|
||||
function addSessionCreatorIdentity(
|
||||
creators: Map<string, { id: string; label?: string; avatarUrl?: string }>,
|
||||
entry: SessionEntry,
|
||||
@@ -95,15 +105,13 @@ function addSessionCreatorIdentity(
|
||||
const label = normalizeOptionalString(actor?.label);
|
||||
const avatarUrl = normalizeOptionalString(actor?.avatarUrl);
|
||||
const existing = creators.get(id);
|
||||
if (
|
||||
!existing ||
|
||||
(label && (!existing.label || label.localeCompare(existing.label) < 0)) ||
|
||||
(avatarUrl && !existing.avatarUrl)
|
||||
) {
|
||||
const preferredLabel = preferredCreatorIdentityValue(existing?.label, label);
|
||||
const preferredAvatarUrl = preferredCreatorIdentityValue(existing?.avatarUrl, avatarUrl);
|
||||
if (!existing || preferredLabel !== existing.label || preferredAvatarUrl !== existing.avatarUrl) {
|
||||
creators.set(id, {
|
||||
id,
|
||||
...(label ? { label } : existing?.label ? { label: existing.label } : {}),
|
||||
...(avatarUrl ? { avatarUrl } : existing?.avatarUrl ? { avatarUrl: existing.avatarUrl } : {}),
|
||||
...(preferredLabel ? { label: preferredLabel } : {}),
|
||||
...(preferredAvatarUrl ? { avatarUrl: preferredAvatarUrl } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user