@ganglion/weacpx-channel-feishu 0.2.0 → 0.2.2
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/dist/inbound.d.ts +18 -0
- package/dist/index.js +67 -12
- package/package.json +1 -1
package/dist/inbound.d.ts
CHANGED
|
@@ -7,6 +7,24 @@ export declare function parseFeishuConversationId(chatKey: string): {
|
|
|
7
7
|
chatId: string;
|
|
8
8
|
threadId?: string;
|
|
9
9
|
} | null;
|
|
10
|
+
/**
|
|
11
|
+
* Builds the chat-route metadata weacpx records for the current coordinator
|
|
12
|
+
* session. The host requires `chatType` to be `"direct"` or `"group"`, but
|
|
13
|
+
* Feishu reports `chat_type` as `"p2p"` (direct) or `"group"`, so `"p2p"` and
|
|
14
|
+
* any unexpected value normalize to `"direct"`. Without this, interactive
|
|
15
|
+
* Feishu turns recorded a route with no `chatType`, which blocked the in-session
|
|
16
|
+
* scheduled_create/list/cancel tools and group-owner command authorization.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildFeishuRouteMetadata(input: {
|
|
19
|
+
chatType: string | undefined;
|
|
20
|
+
senderOpenId?: string;
|
|
21
|
+
chatId: string;
|
|
22
|
+
}): {
|
|
23
|
+
channel: "feishu";
|
|
24
|
+
chatType: "direct" | "group";
|
|
25
|
+
senderId?: string;
|
|
26
|
+
groupId?: string;
|
|
27
|
+
};
|
|
10
28
|
export declare function shouldHandleFeishuMessage(input: {
|
|
11
29
|
event: FeishuMessageEvent;
|
|
12
30
|
botOpenId?: string;
|
package/dist/index.js
CHANGED
|
@@ -78312,6 +78312,15 @@ function parseFeishuConversationId(chatKey) {
|
|
|
78312
78312
|
}
|
|
78313
78313
|
return { accountId: parts[1], chatId: parts[2] };
|
|
78314
78314
|
}
|
|
78315
|
+
function buildFeishuRouteMetadata(input) {
|
|
78316
|
+
const isGroup = input.chatType === "group";
|
|
78317
|
+
return {
|
|
78318
|
+
channel: "feishu",
|
|
78319
|
+
chatType: isGroup ? "group" : "direct",
|
|
78320
|
+
...input.senderOpenId ? { senderId: input.senderOpenId } : {},
|
|
78321
|
+
...isGroup ? { groupId: input.chatId } : {}
|
|
78322
|
+
};
|
|
78323
|
+
}
|
|
78315
78324
|
function shouldHandleFeishuMessage(input) {
|
|
78316
78325
|
const text = input.parsedText ?? parseFeishuText(input.event.message.content);
|
|
78317
78326
|
if (input.event.message.message_type !== "text" && !input.allowMediaOnly && text.trim().length === 0) {
|
|
@@ -80373,7 +80382,8 @@ class FeishuChannel {
|
|
|
80373
80382
|
if (input.accountId && input.accountId !== route.accountId) {
|
|
80374
80383
|
throw new Error(`scheduled Feishu accountId "${input.accountId}" does not match chatKey account "${route.accountId}"`);
|
|
80375
80384
|
}
|
|
80376
|
-
|
|
80385
|
+
const runtime = this.accounts.get(route.accountId);
|
|
80386
|
+
if (!runtime) {
|
|
80377
80387
|
throw new Error(`feishu account "${route.accountId}" is not started; check channel.options.accounts and enabled flags`);
|
|
80378
80388
|
}
|
|
80379
80389
|
const deliverText = async (text) => {
|
|
@@ -80385,6 +80395,22 @@ class FeishuChannel {
|
|
|
80385
80395
|
await this.sendRouteText(input.chatKey, input.replyContextToken, trimmed);
|
|
80386
80396
|
};
|
|
80387
80397
|
await this.sendRouteText(input.chatKey, input.replyContextToken, input.noticeText);
|
|
80398
|
+
const effectiveReplyMode = resolveEffectiveReplyMode(runtime.account.replyMode, undefined);
|
|
80399
|
+
const cardController = effectiveReplyMode === "streaming" ? await this.trySeedStreamingCard({
|
|
80400
|
+
runtime,
|
|
80401
|
+
accountId: route.accountId,
|
|
80402
|
+
chatId: route.chatId,
|
|
80403
|
+
...input.replyContextToken ? { replyToMessageId: input.replyContextToken } : {}
|
|
80404
|
+
}) : null;
|
|
80405
|
+
const deliverReply = async (text) => {
|
|
80406
|
+
if (input.abortSignal?.aborted)
|
|
80407
|
+
return;
|
|
80408
|
+
if (cardController) {
|
|
80409
|
+
cardController.appendStream(text);
|
|
80410
|
+
return;
|
|
80411
|
+
}
|
|
80412
|
+
await deliverText(text);
|
|
80413
|
+
};
|
|
80388
80414
|
try {
|
|
80389
80415
|
const response = await this.agent.chat({
|
|
80390
80416
|
accountId: route.accountId,
|
|
@@ -80393,10 +80419,26 @@ class FeishuChannel {
|
|
|
80393
80419
|
...input.replyContextToken ? { replyContextToken: input.replyContextToken } : {},
|
|
80394
80420
|
...input.abortSignal ? { abortSignal: input.abortSignal } : {},
|
|
80395
80421
|
metadata: { channel: "feishu", scheduledSessionAlias: input.sessionAlias },
|
|
80396
|
-
reply:
|
|
80422
|
+
reply: deliverReply,
|
|
80423
|
+
...cardController ? {
|
|
80424
|
+
onToolEvent: (event) => {
|
|
80425
|
+
if (input.abortSignal?.aborted)
|
|
80426
|
+
return;
|
|
80427
|
+
cardController.recordToolEvent(event);
|
|
80428
|
+
},
|
|
80429
|
+
onThought: (chunk) => {
|
|
80430
|
+
if (input.abortSignal?.aborted)
|
|
80431
|
+
return;
|
|
80432
|
+
cardController.appendReasoning(chunk);
|
|
80433
|
+
}
|
|
80434
|
+
} : {}
|
|
80397
80435
|
});
|
|
80398
|
-
if (input.abortSignal?.aborted)
|
|
80436
|
+
if (input.abortSignal?.aborted) {
|
|
80437
|
+
if (cardController && !cardController.isTerminated()) {
|
|
80438
|
+
await cardController.abort(abortAck()).catch(() => {});
|
|
80439
|
+
}
|
|
80399
80440
|
return;
|
|
80441
|
+
}
|
|
80400
80442
|
const media = normalizeMediaArray(response.media);
|
|
80401
80443
|
if (media.length > 0) {
|
|
80402
80444
|
await this.logger.error("feishu.scheduled.media_unsupported", "scheduled feishu media responses are not supported", {
|
|
@@ -80407,11 +80449,23 @@ class FeishuChannel {
|
|
|
80407
80449
|
count: media.length
|
|
80408
80450
|
});
|
|
80409
80451
|
}
|
|
80410
|
-
|
|
80452
|
+
if (cardController) {
|
|
80453
|
+
const responseText = response.text?.trim() ?? "";
|
|
80454
|
+
await cardController.complete(responseText.length > 0 ? response.text : undefined);
|
|
80455
|
+
if (cardController.isDegraded() && responseText.length > 0) {
|
|
80456
|
+
await deliverText(response.text);
|
|
80457
|
+
}
|
|
80458
|
+
} else {
|
|
80459
|
+
await deliverText(response.text);
|
|
80460
|
+
}
|
|
80411
80461
|
} catch (error) {
|
|
80412
|
-
|
|
80413
|
-
await
|
|
80414
|
-
}
|
|
80462
|
+
if (cardController && !cardController.isTerminated()) {
|
|
80463
|
+
await cardController.fail(error instanceof Error ? error.message : String(error)).catch(() => {});
|
|
80464
|
+
} else {
|
|
80465
|
+
try {
|
|
80466
|
+
await deliverText(formatScheduledFailureText(input, error));
|
|
80467
|
+
} catch {}
|
|
80468
|
+
}
|
|
80415
80469
|
throw error;
|
|
80416
80470
|
}
|
|
80417
80471
|
}
|
|
@@ -80593,7 +80647,7 @@ class FeishuChannel {
|
|
|
80593
80647
|
return;
|
|
80594
80648
|
const effectiveReplyMode = resolveEffectiveReplyMode(runtime.account.replyMode, chatType);
|
|
80595
80649
|
if (effectiveReplyMode === "streaming") {
|
|
80596
|
-
await this.trySeedStreamingCard({ runtime, accountId, chatId, messageId
|
|
80650
|
+
active.cardController = await this.trySeedStreamingCard({ runtime, accountId, chatId, replyToMessageId: messageId });
|
|
80597
80651
|
}
|
|
80598
80652
|
if (active.suppressed) {
|
|
80599
80653
|
if (active.cardController && !active.cardController.isTerminated()) {
|
|
@@ -80625,6 +80679,7 @@ class FeishuChannel {
|
|
|
80625
80679
|
text: requestText,
|
|
80626
80680
|
...media.length > 0 ? { media } : {},
|
|
80627
80681
|
replyContextToken: messageId,
|
|
80682
|
+
metadata: buildFeishuRouteMetadata({ chatType, senderOpenId: active.senderOpenId, chatId }),
|
|
80628
80683
|
reply: safeReply,
|
|
80629
80684
|
...active.cardController ? {
|
|
80630
80685
|
onToolEvent: (event) => {
|
|
@@ -80666,7 +80721,7 @@ class FeishuChannel {
|
|
|
80666
80721
|
}
|
|
80667
80722
|
}
|
|
80668
80723
|
async trySeedStreamingCard(input) {
|
|
80669
|
-
const { runtime, accountId, chatId
|
|
80724
|
+
const { runtime, accountId, chatId } = input;
|
|
80670
80725
|
try {
|
|
80671
80726
|
const controller = new StreamingCardController({
|
|
80672
80727
|
client: runtime.client.sdk,
|
|
@@ -80681,8 +80736,8 @@ class FeishuChannel {
|
|
|
80681
80736
|
this.logger?.error("feishu.card.degraded", "streaming card updates failing; will deliver answer via plain reply", { accountId, chatId, consecutiveFailures, bufferChars: buffer.length });
|
|
80682
80737
|
}
|
|
80683
80738
|
});
|
|
80684
|
-
await controller.seed({ to: chatId, replyToMessageId:
|
|
80685
|
-
|
|
80739
|
+
await controller.seed({ to: chatId, ...input.replyToMessageId ? { replyToMessageId: input.replyToMessageId } : {} });
|
|
80740
|
+
return controller;
|
|
80686
80741
|
} catch (error) {
|
|
80687
80742
|
const permErr = extractPermissionError(error);
|
|
80688
80743
|
await this.logger.info("feishu.streaming.fallback", "streaming card seed failed; falling back to static", {
|
|
@@ -80693,7 +80748,7 @@ class FeishuChannel {
|
|
|
80693
80748
|
});
|
|
80694
80749
|
if (permErr)
|
|
80695
80750
|
await this.maybeNotifyPermissionError({ runtime, chatId, error });
|
|
80696
|
-
|
|
80751
|
+
return null;
|
|
80697
80752
|
}
|
|
80698
80753
|
}
|
|
80699
80754
|
async deliverResponse(input) {
|