@openclaw/feishu 2026.3.11 → 2026.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/send.ts CHANGED
@@ -7,7 +7,7 @@ import { parsePostContent } from "./post.js";
7
7
  import { getFeishuRuntime } from "./runtime.js";
8
8
  import { assertFeishuMessageApiSuccess, toFeishuSendResult } from "./send-result.js";
9
9
  import { resolveFeishuSendTarget } from "./send-target.js";
10
- import type { FeishuSendResult } from "./types.js";
10
+ import type { FeishuChatType, FeishuMessageInfo, FeishuSendResult } from "./types.js";
11
11
 
12
12
  const WITHDRAWN_REPLY_ERROR_CODES = new Set([230011, 231003]);
13
13
 
@@ -43,6 +43,10 @@ function isWithdrawnReplyError(err: unknown): boolean {
43
43
  type FeishuCreateMessageClient = {
44
44
  im: {
45
45
  message: {
46
+ reply: (opts: {
47
+ path: { message_id: string };
48
+ data: { content: string; msg_type: string; reply_in_thread?: true };
49
+ }) => Promise<{ code?: number; msg?: string; data?: { message_id?: string } }>;
46
50
  create: (opts: {
47
51
  params: { receive_id_type: "chat_id" | "email" | "open_id" | "union_id" | "user_id" };
48
52
  data: { receive_id: string; content: string; msg_type: string };
@@ -51,6 +55,30 @@ type FeishuCreateMessageClient = {
51
55
  };
52
56
  };
53
57
 
58
+ type FeishuMessageSender = {
59
+ id?: string;
60
+ id_type?: string;
61
+ sender_type?: string;
62
+ };
63
+
64
+ type FeishuMessageGetItem = {
65
+ message_id?: string;
66
+ chat_id?: string;
67
+ chat_type?: FeishuChatType;
68
+ msg_type?: string;
69
+ body?: { content?: string };
70
+ sender?: FeishuMessageSender;
71
+ create_time?: string;
72
+ };
73
+
74
+ type FeishuGetMessageResponse = {
75
+ code?: number;
76
+ msg?: string;
77
+ data?: FeishuMessageGetItem & {
78
+ items?: FeishuMessageGetItem[];
79
+ };
80
+ };
81
+
54
82
  /** Send a direct message as a fallback when a reply target is unavailable. */
55
83
  async function sendFallbackDirect(
56
84
  client: FeishuCreateMessageClient,
@@ -74,16 +102,49 @@ async function sendFallbackDirect(
74
102
  return toFeishuSendResult(response, params.receiveId);
75
103
  }
76
104
 
77
- export type FeishuMessageInfo = {
78
- messageId: string;
79
- chatId: string;
80
- senderId?: string;
81
- senderOpenId?: string;
82
- senderType?: string;
83
- content: string;
84
- contentType: string;
85
- createTime?: number;
86
- };
105
+ async function sendReplyOrFallbackDirect(
106
+ client: FeishuCreateMessageClient,
107
+ params: {
108
+ replyToMessageId?: string;
109
+ replyInThread?: boolean;
110
+ content: string;
111
+ msgType: string;
112
+ directParams: {
113
+ receiveId: string;
114
+ receiveIdType: "chat_id" | "email" | "open_id" | "union_id" | "user_id";
115
+ content: string;
116
+ msgType: string;
117
+ };
118
+ directErrorPrefix: string;
119
+ replyErrorPrefix: string;
120
+ },
121
+ ): Promise<FeishuSendResult> {
122
+ if (!params.replyToMessageId) {
123
+ return sendFallbackDirect(client, params.directParams, params.directErrorPrefix);
124
+ }
125
+
126
+ let response: { code?: number; msg?: string; data?: { message_id?: string } };
127
+ try {
128
+ response = await client.im.message.reply({
129
+ path: { message_id: params.replyToMessageId },
130
+ data: {
131
+ content: params.content,
132
+ msg_type: params.msgType,
133
+ ...(params.replyInThread ? { reply_in_thread: true } : {}),
134
+ },
135
+ });
136
+ } catch (err) {
137
+ if (!isWithdrawnReplyError(err)) {
138
+ throw err;
139
+ }
140
+ return sendFallbackDirect(client, params.directParams, params.directErrorPrefix);
141
+ }
142
+ if (shouldFallbackFromReplyTarget(response)) {
143
+ return sendFallbackDirect(client, params.directParams, params.directErrorPrefix);
144
+ }
145
+ assertFeishuMessageApiSuccess(response, params.replyErrorPrefix);
146
+ return toFeishuSendResult(response, params.directParams.receiveId);
147
+ }
87
148
 
88
149
  function parseInteractiveCardContent(parsed: unknown): string {
89
150
  if (!parsed || typeof parsed !== "object") {
@@ -177,34 +238,7 @@ export async function getMessageFeishu(params: {
177
238
  try {
178
239
  const response = (await client.im.message.get({
179
240
  path: { message_id: messageId },
180
- })) as {
181
- code?: number;
182
- msg?: string;
183
- data?: {
184
- items?: Array<{
185
- message_id?: string;
186
- chat_id?: string;
187
- msg_type?: string;
188
- body?: { content?: string };
189
- sender?: {
190
- id?: string;
191
- id_type?: string;
192
- sender_type?: string;
193
- };
194
- create_time?: string;
195
- }>;
196
- message_id?: string;
197
- chat_id?: string;
198
- msg_type?: string;
199
- body?: { content?: string };
200
- sender?: {
201
- id?: string;
202
- id_type?: string;
203
- sender_type?: string;
204
- };
205
- create_time?: string;
206
- };
207
- };
241
+ })) as FeishuGetMessageResponse;
208
242
 
209
243
  if (response.code !== 0) {
210
244
  return null;
@@ -228,6 +262,10 @@ export async function getMessageFeishu(params: {
228
262
  return {
229
263
  messageId: item.message_id ?? messageId,
230
264
  chatId: item.chat_id ?? "",
265
+ chatType:
266
+ item.chat_type === "group" || item.chat_type === "private" || item.chat_type === "p2p"
267
+ ? item.chat_type
268
+ : undefined,
231
269
  senderId: item.sender?.id,
232
270
  senderOpenId: item.sender?.id_type === "open_id" ? item.sender?.id : undefined,
233
271
  senderType: item.sender?.sender_type,
@@ -295,32 +333,15 @@ export async function sendMessageFeishu(
295
333
  const { content, msgType } = buildFeishuPostMessagePayload({ messageText });
296
334
 
297
335
  const directParams = { receiveId, receiveIdType, content, msgType };
298
-
299
- if (replyToMessageId) {
300
- let response: { code?: number; msg?: string; data?: { message_id?: string } };
301
- try {
302
- response = await client.im.message.reply({
303
- path: { message_id: replyToMessageId },
304
- data: {
305
- content,
306
- msg_type: msgType,
307
- ...(replyInThread ? { reply_in_thread: true } : {}),
308
- },
309
- });
310
- } catch (err) {
311
- if (!isWithdrawnReplyError(err)) {
312
- throw err;
313
- }
314
- return sendFallbackDirect(client, directParams, "Feishu send failed");
315
- }
316
- if (shouldFallbackFromReplyTarget(response)) {
317
- return sendFallbackDirect(client, directParams, "Feishu send failed");
318
- }
319
- assertFeishuMessageApiSuccess(response, "Feishu reply failed");
320
- return toFeishuSendResult(response, receiveId);
321
- }
322
-
323
- return sendFallbackDirect(client, directParams, "Feishu send failed");
336
+ return sendReplyOrFallbackDirect(client, {
337
+ replyToMessageId,
338
+ replyInThread,
339
+ content,
340
+ msgType,
341
+ directParams,
342
+ directErrorPrefix: "Feishu send failed",
343
+ replyErrorPrefix: "Feishu reply failed",
344
+ });
324
345
  }
325
346
 
326
347
  export type SendFeishuCardParams = {
@@ -339,32 +360,15 @@ export async function sendCardFeishu(params: SendFeishuCardParams): Promise<Feis
339
360
  const content = JSON.stringify(card);
340
361
 
341
362
  const directParams = { receiveId, receiveIdType, content, msgType: "interactive" };
342
-
343
- if (replyToMessageId) {
344
- let response: { code?: number; msg?: string; data?: { message_id?: string } };
345
- try {
346
- response = await client.im.message.reply({
347
- path: { message_id: replyToMessageId },
348
- data: {
349
- content,
350
- msg_type: "interactive",
351
- ...(replyInThread ? { reply_in_thread: true } : {}),
352
- },
353
- });
354
- } catch (err) {
355
- if (!isWithdrawnReplyError(err)) {
356
- throw err;
357
- }
358
- return sendFallbackDirect(client, directParams, "Feishu card send failed");
359
- }
360
- if (shouldFallbackFromReplyTarget(response)) {
361
- return sendFallbackDirect(client, directParams, "Feishu card send failed");
362
- }
363
- assertFeishuMessageApiSuccess(response, "Feishu card reply failed");
364
- return toFeishuSendResult(response, receiveId);
365
- }
366
-
367
- return sendFallbackDirect(client, directParams, "Feishu card send failed");
363
+ return sendReplyOrFallbackDirect(client, {
364
+ replyToMessageId,
365
+ replyInThread,
366
+ content,
367
+ msgType: "interactive",
368
+ directParams,
369
+ directErrorPrefix: "Feishu card send failed",
370
+ replyErrorPrefix: "Feishu card reply failed",
371
+ });
368
372
  }
369
373
 
370
374
  export async function updateCardFeishu(params: {
package/src/types.ts CHANGED
@@ -60,6 +60,20 @@ export type FeishuSendResult = {
60
60
  chatId: string;
61
61
  };
62
62
 
63
+ export type FeishuChatType = "p2p" | "group" | "private";
64
+
65
+ export type FeishuMessageInfo = {
66
+ messageId: string;
67
+ chatId: string;
68
+ chatType?: FeishuChatType;
69
+ senderId?: string;
70
+ senderOpenId?: string;
71
+ senderType?: string;
72
+ content: string;
73
+ contentType: string;
74
+ createTime?: number;
75
+ };
76
+
63
77
  export type FeishuProbeResult = BaseProbeResult<string> & {
64
78
  appId?: string;
65
79
  botName?: string;