mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-16 12:30:49 +00:00
fix(feishu): preserve sender-scoped ACP rebinding
This commit is contained in:
@@ -1262,6 +1262,9 @@ export async function handleFeishuMessage(params: {
|
||||
configuredBinding = configuredRoute.configuredBinding;
|
||||
route = configuredRoute.route;
|
||||
|
||||
// Bound Feishu conversations intentionally require an exact live conversation-id match.
|
||||
// Sender-scoped topic sessions therefore bind on `chat:topic:root:sender:user`, while
|
||||
// configured ACP bindings may still inherit the shared `chat:topic:root` topic session.
|
||||
const threadBinding = getSessionBindingService().resolveByConversation({
|
||||
channel: "feishu",
|
||||
accountId: account.accountId,
|
||||
|
||||
@@ -247,6 +247,9 @@ export function resolveConfiguredAcpBindingSpecBySessionKey(params: {
|
||||
channel: "feishu",
|
||||
accountId: parsedSessionKey.accountId,
|
||||
conversationId: targetParsed.canonicalConversationId,
|
||||
// Session-key recovery deliberately collapses sender-scoped topic bindings onto the
|
||||
// canonical topic conversation id so `group_topic` and `group_topic_sender` reuse
|
||||
// the same configured ACP session identity.
|
||||
parentConversationId:
|
||||
targetParsed.scope === "group_topic" || targetParsed.scope === "group_topic_sender"
|
||||
? targetParsed.chatId
|
||||
|
||||
@@ -174,6 +174,29 @@ describe("commands-acp context", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves sender-scoped Feishu topic ids after ACP route takeover via ParentSessionKey", () => {
|
||||
const params = buildCommandTestParams("/acp status", baseCfg, {
|
||||
Provider: "feishu",
|
||||
Surface: "feishu",
|
||||
OriginatingChannel: "feishu",
|
||||
OriginatingTo: "chat:oc_group_chat",
|
||||
MessageThreadId: "om_topic_root",
|
||||
SenderId: "ou_topic_user",
|
||||
AccountId: "work",
|
||||
ParentSessionKey:
|
||||
"agent:main:feishu:group:oc_group_chat:topic:om_topic_root:sender:ou_topic_user",
|
||||
});
|
||||
params.sessionKey = "agent:codex:acp:binding:feishu:work:abc123";
|
||||
|
||||
expect(resolveAcpCommandBindingContext(params)).toEqual({
|
||||
channel: "feishu",
|
||||
accountId: "work",
|
||||
threadId: "om_topic_root",
|
||||
conversationId: "oc_group_chat:topic:om_topic_root:sender:ou_topic_user",
|
||||
parentConversationId: "oc_group_chat",
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves Feishu DM conversation ids from user targets", () => {
|
||||
const params = buildCommandTestParams("/acp status", baseCfg, {
|
||||
Provider: "feishu",
|
||||
|
||||
@@ -45,15 +45,16 @@ function resolveFeishuSenderScopedConversationId(params: {
|
||||
threadId?: string;
|
||||
senderId?: string;
|
||||
sessionKey?: string;
|
||||
parentSessionKey?: string;
|
||||
}): string | undefined {
|
||||
const parentConversationId = normalizeConversationText(params.parentConversationId);
|
||||
const threadId = normalizeConversationText(params.threadId);
|
||||
const senderId = normalizeConversationText(params.senderId);
|
||||
const scopedRest = parseAgentSessionKey(params.sessionKey)?.rest?.trim().toLowerCase() ?? "";
|
||||
const expectedScopePrefix = `feishu:group:${parentConversationId?.toLowerCase()}:topic:${threadId?.toLowerCase()}:sender:`;
|
||||
const isSenderScopedSession = Boolean(
|
||||
scopedRest && expectedScopePrefix && scopedRest.startsWith(expectedScopePrefix),
|
||||
);
|
||||
const isSenderScopedSession = [params.sessionKey, params.parentSessionKey].some((candidate) => {
|
||||
const scopedRest = parseAgentSessionKey(candidate)?.rest?.trim().toLowerCase() ?? "";
|
||||
return Boolean(scopedRest && expectedScopePrefix && scopedRest.startsWith(expectedScopePrefix));
|
||||
});
|
||||
if (!parentConversationId || !threadId || !senderId || !isSenderScopedSession) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -123,6 +124,7 @@ export function resolveAcpCommandConversationId(params: HandleCommandsParams): s
|
||||
threadId,
|
||||
senderId: params.command.senderId ?? params.ctx.SenderId,
|
||||
sessionKey: params.sessionKey,
|
||||
parentSessionKey: params.ctx.ParentSessionKey,
|
||||
});
|
||||
return (
|
||||
senderScopedConversationId ??
|
||||
|
||||
@@ -90,7 +90,7 @@ const AcpBindingSchema = z
|
||||
}
|
||||
if (
|
||||
channel === "feishu" &&
|
||||
!/^(ou_[^:]+|on_[^:]+|[^:]+:topic:[^:]+(?::sender:[^:]+)?)$/.test(peerId)
|
||||
!/^(ou_[^:]+|on_[^:]+|oc_[^:]+:topic:[^:]+(?::sender:[^:]+)?)$/.test(peerId)
|
||||
) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
|
||||
Reference in New Issue
Block a user