mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-30 02:20:38 +00:00
fix: pass rootId to streaming card in Feishu topic groups (openclaw#28346) thanks @Sid-Qin
Verified: - pnpm check - pnpm test extensions/feishu/src/reply-dispatcher.test.ts Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -1019,6 +1019,7 @@ export async function handleFeishuMessage(params: {
|
||||
chatId: ctx.chatId,
|
||||
replyToMessageId: ctx.messageId,
|
||||
replyInThread,
|
||||
rootId: ctx.rootId,
|
||||
mentionTargets: ctx.mentionTargets,
|
||||
accountId: account.accountId,
|
||||
});
|
||||
|
||||
@@ -105,6 +105,7 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
|
||||
agentId: "agent",
|
||||
runtime: { log: vi.fn(), error: vi.fn() } as never,
|
||||
chatId: "oc_chat",
|
||||
rootId: "om_root_topic",
|
||||
});
|
||||
|
||||
const options = createReplyDispatcherWithTypingMock.mock.calls[0]?.[0];
|
||||
@@ -112,6 +113,11 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
|
||||
|
||||
expect(streamingInstances).toHaveLength(1);
|
||||
expect(streamingInstances[0].start).toHaveBeenCalledTimes(1);
|
||||
expect(streamingInstances[0].start).toHaveBeenCalledWith("oc_chat", "chat_id", {
|
||||
replyToMessageId: undefined,
|
||||
replyInThread: undefined,
|
||||
rootId: "om_root_topic",
|
||||
});
|
||||
expect(streamingInstances[0].close).toHaveBeenCalledTimes(1);
|
||||
expect(sendMessageFeishuMock).not.toHaveBeenCalled();
|
||||
expect(sendMarkdownCardFeishuMock).not.toHaveBeenCalled();
|
||||
|
||||
@@ -29,14 +29,23 @@ export type CreateFeishuReplyDispatcherParams = {
|
||||
chatId: string;
|
||||
replyToMessageId?: string;
|
||||
replyInThread?: boolean;
|
||||
rootId?: string;
|
||||
mentionTargets?: MentionTarget[];
|
||||
accountId?: string;
|
||||
};
|
||||
|
||||
export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherParams) {
|
||||
const core = getFeishuRuntime();
|
||||
const { cfg, agentId, chatId, replyToMessageId, replyInThread, mentionTargets, accountId } =
|
||||
params;
|
||||
const {
|
||||
cfg,
|
||||
agentId,
|
||||
chatId,
|
||||
replyToMessageId,
|
||||
replyInThread,
|
||||
rootId,
|
||||
mentionTargets,
|
||||
accountId,
|
||||
} = params;
|
||||
const account = resolveFeishuAccount({ cfg, accountId });
|
||||
const prefixContext = createReplyPrefixContext({ cfg, agentId });
|
||||
|
||||
@@ -105,6 +114,7 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
|
||||
await streaming.start(chatId, resolveReceiveIdType(chatId), {
|
||||
replyToMessageId,
|
||||
replyInThread,
|
||||
rootId,
|
||||
});
|
||||
} catch (error) {
|
||||
params.runtime.error?.(`feishu: streaming start failed: ${String(error)}`);
|
||||
|
||||
@@ -99,7 +99,7 @@ export class FeishuStreamingSession {
|
||||
async start(
|
||||
receiveId: string,
|
||||
receiveIdType: "open_id" | "user_id" | "union_id" | "email" | "chat_id" = "chat_id",
|
||||
options?: { replyToMessageId?: string; replyInThread?: boolean },
|
||||
options?: { replyToMessageId?: string; replyInThread?: boolean; rootId?: string },
|
||||
): Promise<void> {
|
||||
if (this.state) {
|
||||
return;
|
||||
@@ -144,9 +144,20 @@ export class FeishuStreamingSession {
|
||||
const cardId = createData.data.card_id;
|
||||
const cardContent = JSON.stringify({ type: "card", data: { card_id: cardId } });
|
||||
|
||||
// Send card message — reply into thread when configured
|
||||
// Topic-group replies require root_id routing. Prefer create+root_id when available.
|
||||
let sendRes;
|
||||
if (options?.replyToMessageId) {
|
||||
if (options?.rootId) {
|
||||
const createData = {
|
||||
receive_id: receiveId,
|
||||
msg_type: "interactive",
|
||||
content: cardContent,
|
||||
root_id: options.rootId,
|
||||
};
|
||||
sendRes = await this.client.im.message.create({
|
||||
params: { receive_id_type: receiveIdType },
|
||||
data: createData,
|
||||
});
|
||||
} else if (options?.replyToMessageId) {
|
||||
sendRes = await this.client.im.message.reply({
|
||||
path: { message_id: options.replyToMessageId },
|
||||
data: {
|
||||
|
||||
@@ -24,9 +24,9 @@ const sourceRoots = [
|
||||
const allowedRawFetchCallsites = new Set([
|
||||
"extensions/bluebubbles/src/types.ts:131",
|
||||
"extensions/feishu/src/streaming-card.ts:31",
|
||||
"extensions/feishu/src/streaming-card.ts:100",
|
||||
"extensions/feishu/src/streaming-card.ts:141",
|
||||
"extensions/feishu/src/streaming-card.ts:197",
|
||||
"extensions/feishu/src/streaming-card.ts:101",
|
||||
"extensions/feishu/src/streaming-card.ts:143",
|
||||
"extensions/feishu/src/streaming-card.ts:199",
|
||||
"extensions/google-gemini-cli-auth/oauth.ts:372",
|
||||
"extensions/google-gemini-cli-auth/oauth.ts:408",
|
||||
"extensions/google-gemini-cli-auth/oauth.ts:447",
|
||||
|
||||
Reference in New Issue
Block a user