fix: preserve account binding metadata on rebind

This commit is contained in:
Tak Hoffman
2026-04-10 19:11:51 -05:00
parent 270630ba35
commit 6afff0642e
2 changed files with 66 additions and 3 deletions

View File

@@ -0,0 +1,60 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-runtime";
import { beforeEach, describe, expect, it } from "vitest";
import { __testing, createBlueBubblesConversationBindingManager } from "./conversation-bindings.js";
const baseCfg = {
session: { mainKey: "main", scope: "per-sender" },
} satisfies OpenClawConfig;
describe("BlueBubbles conversation bindings", () => {
beforeEach(() => {
__testing.resetBlueBubblesConversationBindingsForTests();
});
it("preserves existing metadata when rebinding the same conversation", async () => {
const manager = createBlueBubblesConversationBindingManager({
cfg: baseCfg,
accountId: "default",
});
manager.bindConversation({
conversationId: "chat-guid-1",
targetKind: "subagent",
targetSessionKey: "agent:main:subagent:child",
metadata: {
agentId: "codex",
label: "child",
boundBy: "system",
},
});
await getSessionBindingService().bind({
targetSessionKey: "agent:main:subagent:child",
targetKind: "subagent",
conversation: {
channel: "bluebubbles",
accountId: "default",
conversationId: "chat-guid-1",
},
placement: "current",
metadata: {
label: "child",
},
});
expect(
getSessionBindingService().resolveByConversation({
channel: "bluebubbles",
accountId: "default",
conversationId: "chat-guid-1",
}),
).toMatchObject({
metadata: expect.objectContaining({
agentId: "codex",
label: "child",
boundBy: "system",
}),
});
});
});

View File

@@ -158,6 +158,9 @@ export function createAccountScopedConversationBindingManager<TKind extends stri
if (!normalizedConversationId || !normalizedTargetSessionKey) {
return null;
}
const existing = getState<TKind>(params.stateKey).bindingsByAccountConversation.get(
resolveBindingKey({ accountId, conversationId: normalizedConversationId }),
);
const now = Date.now();
const record: AccountScopedConversationBindingRecord<TKind> = {
accountId,
@@ -167,15 +170,15 @@ export function createAccountScopedConversationBindingManager<TKind extends stri
agentId:
typeof metadata?.agentId === "string" && metadata.agentId.trim()
? metadata.agentId.trim()
: resolveAgentIdFromSessionKey(normalizedTargetSessionKey),
: (existing?.agentId ?? resolveAgentIdFromSessionKey(normalizedTargetSessionKey)),
label:
typeof metadata?.label === "string" && metadata.label.trim()
? metadata.label.trim()
: undefined,
: existing?.label,
boundBy:
typeof metadata?.boundBy === "string" && metadata.boundBy.trim()
? metadata.boundBy.trim()
: undefined,
: existing?.boundBy,
boundAt: now,
lastActivityAt: now,
};