mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-21 22:21:33 +00:00
fix(feishu): support DM ACP binding placement
This commit is contained in:
@@ -118,7 +118,7 @@ type FakeBinding = {
|
||||
targetSessionKey: string;
|
||||
targetKind: "subagent" | "session";
|
||||
conversation: {
|
||||
channel: "discord" | "telegram";
|
||||
channel: "discord" | "telegram" | "feishu";
|
||||
accountId: string;
|
||||
conversationId: string;
|
||||
parentConversationId?: string;
|
||||
@@ -243,7 +243,7 @@ function createSessionBindingCapabilities() {
|
||||
type AcpBindInput = {
|
||||
targetSessionKey: string;
|
||||
conversation: {
|
||||
channel?: "discord" | "telegram";
|
||||
channel?: "discord" | "telegram" | "feishu";
|
||||
accountId: string;
|
||||
conversationId: string;
|
||||
};
|
||||
@@ -256,21 +256,28 @@ function createAcpThreadBinding(input: AcpBindInput): FakeBinding {
|
||||
input.placement === "child" ? "thread-created" : input.conversation.conversationId;
|
||||
const boundBy = typeof input.metadata?.boundBy === "string" ? input.metadata.boundBy : "user-1";
|
||||
const channel = input.conversation.channel ?? "discord";
|
||||
return createSessionBinding({
|
||||
targetSessionKey: input.targetSessionKey,
|
||||
conversation:
|
||||
channel === "discord"
|
||||
const conversation =
|
||||
channel === "discord"
|
||||
? {
|
||||
channel: "discord" as const,
|
||||
accountId: input.conversation.accountId,
|
||||
conversationId: nextConversationId,
|
||||
parentConversationId: "parent-1",
|
||||
}
|
||||
: channel === "feishu"
|
||||
? {
|
||||
channel: "discord",
|
||||
channel: "feishu" as const,
|
||||
accountId: input.conversation.accountId,
|
||||
conversationId: nextConversationId,
|
||||
parentConversationId: "parent-1",
|
||||
}
|
||||
: {
|
||||
channel: "telegram",
|
||||
channel: "telegram" as const,
|
||||
accountId: input.conversation.accountId,
|
||||
conversationId: nextConversationId,
|
||||
},
|
||||
};
|
||||
return createSessionBinding({
|
||||
targetSessionKey: input.targetSessionKey,
|
||||
conversation,
|
||||
metadata: { boundBy, webhookId: "wh-1" },
|
||||
});
|
||||
}
|
||||
@@ -350,6 +357,23 @@ async function runTelegramDmAcpCommand(commandBody: string, cfg: OpenClawConfig
|
||||
return handleAcpCommand(createTelegramDmParams(commandBody, cfg), true);
|
||||
}
|
||||
|
||||
function createFeishuDmParams(commandBody: string, cfg: OpenClawConfig = baseCfg) {
|
||||
const params = buildCommandTestParams(commandBody, cfg, {
|
||||
Provider: "feishu",
|
||||
Surface: "feishu",
|
||||
OriginatingChannel: "feishu",
|
||||
OriginatingTo: "user:ou_sender_1",
|
||||
AccountId: "default",
|
||||
SenderId: "ou_sender_1",
|
||||
});
|
||||
params.command.senderId = "user-1";
|
||||
return params;
|
||||
}
|
||||
|
||||
async function runFeishuDmAcpCommand(commandBody: string, cfg: OpenClawConfig = baseCfg) {
|
||||
return handleAcpCommand(createFeishuDmParams(commandBody, cfg), true);
|
||||
}
|
||||
|
||||
describe("/acp command", () => {
|
||||
beforeEach(() => {
|
||||
acpManagerTesting.resetAcpSessionManagerForTests();
|
||||
@@ -553,6 +577,23 @@ describe("/acp command", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("binds Feishu DM ACP spawns to the current DM conversation", async () => {
|
||||
const result = await runFeishuDmAcpCommand("/acp spawn codex --thread here");
|
||||
|
||||
expect(result?.reply?.text).toContain("Spawned ACP session agent:codex:acp:");
|
||||
expect(result?.reply?.text).toContain("Bound this thread to");
|
||||
expect(hoisted.sessionBindingBindMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
placement: "current",
|
||||
conversation: expect.objectContaining({
|
||||
channel: "feishu",
|
||||
accountId: "default",
|
||||
conversationId: "ou_sender_1",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("requires explicit ACP target when acp.defaultAgent is not configured", async () => {
|
||||
const result = await runDiscordAcpCommand("/acp spawn");
|
||||
|
||||
|
||||
@@ -66,8 +66,7 @@ function resolveFeishuSenderScopedConversationId(params: {
|
||||
.find((binding) => {
|
||||
if (
|
||||
binding.conversation.channel !== "feishu" ||
|
||||
binding.conversation.accountId !== params.accountId ||
|
||||
binding.conversation.parentConversationId !== parentConversationId
|
||||
binding.conversation.accountId !== params.accountId
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ async function bindSpawnedAcpSessionToThread(params: {
|
||||
|
||||
const currentThreadId = bindingContext.threadId ?? "";
|
||||
const currentConversationId = bindingContext.conversationId?.trim() || "";
|
||||
const requiresThreadIdForHere = channel !== "telegram";
|
||||
const requiresThreadIdForHere = channel !== "telegram" && channel !== "feishu";
|
||||
if (
|
||||
threadMode === "here" &&
|
||||
((requiresThreadIdForHere && !currentThreadId) ||
|
||||
@@ -137,7 +137,12 @@ async function bindSpawnedAcpSessionToThread(params: {
|
||||
};
|
||||
}
|
||||
|
||||
const placement = channel === "telegram" ? "current" : currentThreadId ? "current" : "child";
|
||||
const placement =
|
||||
channel === "telegram" || channel === "feishu"
|
||||
? "current"
|
||||
: currentThreadId
|
||||
? "current"
|
||||
: "child";
|
||||
if (!capabilities.placements.includes(placement)) {
|
||||
return {
|
||||
ok: false,
|
||||
|
||||
Reference in New Issue
Block a user