@ganglion/weacpx-channel-feishu 0.1.2 → 0.2.1
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/channel.d.ts +2 -1
- package/dist/index.js +107 -6
- package/package.json +2 -2
package/dist/channel.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChannelStartInput, CoordinatorMessageInput, CreateChannelDeps, MessageChannelRuntime, OrchestrationDeliveryCallbacks } from "weacpx/plugin-api";
|
|
1
|
+
import type { ChannelStartInput, CoordinatorMessageInput, CreateChannelDeps, ScheduledChannelMessageInput, MessageChannelRuntime, OrchestrationDeliveryCallbacks } from "weacpx/plugin-api";
|
|
2
2
|
import type { FeishuResolvedAccountConfig } from "./config.js";
|
|
3
3
|
import { type FeishuLarkClient } from "./lark-client.js";
|
|
4
4
|
type OrchestrationTaskRecord = Parameters<MessageChannelRuntime["notifyTaskCompletion"]>[0];
|
|
@@ -27,6 +27,7 @@ export declare class FeishuChannel implements MessageChannelRuntime {
|
|
|
27
27
|
notifyTaskCompletion(task: OrchestrationTaskRecord): Promise<void>;
|
|
28
28
|
notifyTaskProgress(task: OrchestrationTaskRecord, text: string): Promise<void>;
|
|
29
29
|
sendCoordinatorMessage(input: CoordinatorMessageInput): Promise<void>;
|
|
30
|
+
sendScheduledMessage(input: ScheduledChannelMessageInput): Promise<void>;
|
|
30
31
|
private sendRouteText;
|
|
31
32
|
private handleMessageEvent;
|
|
32
33
|
/**
|
package/dist/index.js
CHANGED
|
@@ -80363,6 +80363,103 @@ class FeishuChannel {
|
|
|
80363
80363
|
async sendCoordinatorMessage(input) {
|
|
80364
80364
|
await this.sendRouteText(input.chatKey, input.replyContextToken, input.text);
|
|
80365
80365
|
}
|
|
80366
|
+
async sendScheduledMessage(input) {
|
|
80367
|
+
if (!this.agent || !this.logger) {
|
|
80368
|
+
throw new Error("FeishuChannel.start() must be called before scheduled message delivery");
|
|
80369
|
+
}
|
|
80370
|
+
const route = parseFeishuConversationId(input.chatKey);
|
|
80371
|
+
if (!route)
|
|
80372
|
+
throw new Error(`cannot deliver Feishu scheduled message to non-Feishu chatKey: ${input.chatKey}`);
|
|
80373
|
+
if (input.accountId && input.accountId !== route.accountId) {
|
|
80374
|
+
throw new Error(`scheduled Feishu accountId "${input.accountId}" does not match chatKey account "${route.accountId}"`);
|
|
80375
|
+
}
|
|
80376
|
+
const runtime = this.accounts.get(route.accountId);
|
|
80377
|
+
if (!runtime) {
|
|
80378
|
+
throw new Error(`feishu account "${route.accountId}" is not started; check channel.options.accounts and enabled flags`);
|
|
80379
|
+
}
|
|
80380
|
+
const deliverText = async (text) => {
|
|
80381
|
+
if (input.abortSignal?.aborted)
|
|
80382
|
+
return;
|
|
80383
|
+
const trimmed = text?.trim() ?? "";
|
|
80384
|
+
if (trimmed.length === 0)
|
|
80385
|
+
return;
|
|
80386
|
+
await this.sendRouteText(input.chatKey, input.replyContextToken, trimmed);
|
|
80387
|
+
};
|
|
80388
|
+
await this.sendRouteText(input.chatKey, input.replyContextToken, input.noticeText);
|
|
80389
|
+
const effectiveReplyMode = resolveEffectiveReplyMode(runtime.account.replyMode, undefined);
|
|
80390
|
+
const cardController = effectiveReplyMode === "streaming" ? await this.trySeedStreamingCard({
|
|
80391
|
+
runtime,
|
|
80392
|
+
accountId: route.accountId,
|
|
80393
|
+
chatId: route.chatId,
|
|
80394
|
+
...input.replyContextToken ? { replyToMessageId: input.replyContextToken } : {}
|
|
80395
|
+
}) : null;
|
|
80396
|
+
const deliverReply = async (text) => {
|
|
80397
|
+
if (input.abortSignal?.aborted)
|
|
80398
|
+
return;
|
|
80399
|
+
if (cardController) {
|
|
80400
|
+
cardController.appendStream(text);
|
|
80401
|
+
return;
|
|
80402
|
+
}
|
|
80403
|
+
await deliverText(text);
|
|
80404
|
+
};
|
|
80405
|
+
try {
|
|
80406
|
+
const response = await this.agent.chat({
|
|
80407
|
+
accountId: route.accountId,
|
|
80408
|
+
conversationId: input.chatKey,
|
|
80409
|
+
text: input.promptText,
|
|
80410
|
+
...input.replyContextToken ? { replyContextToken: input.replyContextToken } : {},
|
|
80411
|
+
...input.abortSignal ? { abortSignal: input.abortSignal } : {},
|
|
80412
|
+
metadata: { channel: "feishu", scheduledSessionAlias: input.sessionAlias },
|
|
80413
|
+
reply: deliverReply,
|
|
80414
|
+
...cardController ? {
|
|
80415
|
+
onToolEvent: (event) => {
|
|
80416
|
+
if (input.abortSignal?.aborted)
|
|
80417
|
+
return;
|
|
80418
|
+
cardController.recordToolEvent(event);
|
|
80419
|
+
},
|
|
80420
|
+
onThought: (chunk) => {
|
|
80421
|
+
if (input.abortSignal?.aborted)
|
|
80422
|
+
return;
|
|
80423
|
+
cardController.appendReasoning(chunk);
|
|
80424
|
+
}
|
|
80425
|
+
} : {}
|
|
80426
|
+
});
|
|
80427
|
+
if (input.abortSignal?.aborted) {
|
|
80428
|
+
if (cardController && !cardController.isTerminated()) {
|
|
80429
|
+
await cardController.abort(abortAck()).catch(() => {});
|
|
80430
|
+
}
|
|
80431
|
+
return;
|
|
80432
|
+
}
|
|
80433
|
+
const media = normalizeMediaArray(response.media);
|
|
80434
|
+
if (media.length > 0) {
|
|
80435
|
+
await this.logger.error("feishu.scheduled.media_unsupported", "scheduled feishu media responses are not supported", {
|
|
80436
|
+
accountId: route.accountId,
|
|
80437
|
+
chatKey: input.chatKey,
|
|
80438
|
+
taskId: input.taskId,
|
|
80439
|
+
sessionAlias: input.sessionAlias,
|
|
80440
|
+
count: media.length
|
|
80441
|
+
});
|
|
80442
|
+
}
|
|
80443
|
+
if (cardController) {
|
|
80444
|
+
const responseText = response.text?.trim() ?? "";
|
|
80445
|
+
await cardController.complete(responseText.length > 0 ? response.text : undefined);
|
|
80446
|
+
if (cardController.isDegraded() && responseText.length > 0) {
|
|
80447
|
+
await deliverText(response.text);
|
|
80448
|
+
}
|
|
80449
|
+
} else {
|
|
80450
|
+
await deliverText(response.text);
|
|
80451
|
+
}
|
|
80452
|
+
} catch (error) {
|
|
80453
|
+
if (cardController && !cardController.isTerminated()) {
|
|
80454
|
+
await cardController.fail(error instanceof Error ? error.message : String(error)).catch(() => {});
|
|
80455
|
+
} else {
|
|
80456
|
+
try {
|
|
80457
|
+
await deliverText(formatScheduledFailureText(input, error));
|
|
80458
|
+
} catch {}
|
|
80459
|
+
}
|
|
80460
|
+
throw error;
|
|
80461
|
+
}
|
|
80462
|
+
}
|
|
80366
80463
|
async sendRouteText(chatKey, replyContextToken, text) {
|
|
80367
80464
|
const route = parseFeishuConversationId(chatKey);
|
|
80368
80465
|
if (!route)
|
|
@@ -80541,7 +80638,7 @@ class FeishuChannel {
|
|
|
80541
80638
|
return;
|
|
80542
80639
|
const effectiveReplyMode = resolveEffectiveReplyMode(runtime.account.replyMode, chatType);
|
|
80543
80640
|
if (effectiveReplyMode === "streaming") {
|
|
80544
|
-
await this.trySeedStreamingCard({ runtime, accountId, chatId, messageId
|
|
80641
|
+
active.cardController = await this.trySeedStreamingCard({ runtime, accountId, chatId, replyToMessageId: messageId });
|
|
80545
80642
|
}
|
|
80546
80643
|
if (active.suppressed) {
|
|
80547
80644
|
if (active.cardController && !active.cardController.isTerminated()) {
|
|
@@ -80614,7 +80711,7 @@ class FeishuChannel {
|
|
|
80614
80711
|
}
|
|
80615
80712
|
}
|
|
80616
80713
|
async trySeedStreamingCard(input) {
|
|
80617
|
-
const { runtime, accountId, chatId
|
|
80714
|
+
const { runtime, accountId, chatId } = input;
|
|
80618
80715
|
try {
|
|
80619
80716
|
const controller = new StreamingCardController({
|
|
80620
80717
|
client: runtime.client.sdk,
|
|
@@ -80629,8 +80726,8 @@ class FeishuChannel {
|
|
|
80629
80726
|
this.logger?.error("feishu.card.degraded", "streaming card updates failing; will deliver answer via plain reply", { accountId, chatId, consecutiveFailures, bufferChars: buffer.length });
|
|
80630
80727
|
}
|
|
80631
80728
|
});
|
|
80632
|
-
await controller.seed({ to: chatId, replyToMessageId:
|
|
80633
|
-
|
|
80729
|
+
await controller.seed({ to: chatId, ...input.replyToMessageId ? { replyToMessageId: input.replyToMessageId } : {} });
|
|
80730
|
+
return controller;
|
|
80634
80731
|
} catch (error) {
|
|
80635
80732
|
const permErr = extractPermissionError(error);
|
|
80636
80733
|
await this.logger.info("feishu.streaming.fallback", "streaming card seed failed; falling back to static", {
|
|
@@ -80641,7 +80738,7 @@ class FeishuChannel {
|
|
|
80641
80738
|
});
|
|
80642
80739
|
if (permErr)
|
|
80643
80740
|
await this.maybeNotifyPermissionError({ runtime, chatId, error });
|
|
80644
|
-
|
|
80741
|
+
return null;
|
|
80645
80742
|
}
|
|
80646
80743
|
}
|
|
80647
80744
|
async deliverResponse(input) {
|
|
@@ -80826,6 +80923,10 @@ class FeishuChannel {
|
|
|
80826
80923
|
return true;
|
|
80827
80924
|
}
|
|
80828
80925
|
}
|
|
80926
|
+
function formatScheduledFailureText(input, error) {
|
|
80927
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
80928
|
+
return input.taskId ? `⏰ 定时任务 #${input.taskId} 执行失败:${message}` : `⏰ 定时任务执行失败:${message}`;
|
|
80929
|
+
}
|
|
80829
80930
|
function defaultMimeForKind(kind) {
|
|
80830
80931
|
if (kind === "image")
|
|
80831
80932
|
return "image/*";
|
|
@@ -81061,7 +81162,7 @@ var feishuCliProvider = {
|
|
|
81061
81162
|
var plugin = {
|
|
81062
81163
|
apiVersion: 1,
|
|
81063
81164
|
name: "@ganglion/weacpx-channel-feishu",
|
|
81064
|
-
minWeacpxVersion: "0.
|
|
81165
|
+
minWeacpxVersion: "0.5.0",
|
|
81065
81166
|
channels: [
|
|
81066
81167
|
{
|
|
81067
81168
|
type: "feishu",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ganglion/weacpx-channel-feishu",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Feishu channel plugin for weacpx.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": ["weacpx", "feishu", "channel", "plugin"],
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"files": ["dist", "README.md"],
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"weacpx": ">=0.
|
|
23
|
+
"weacpx": ">=0.5.0-0"
|
|
24
24
|
},
|
|
25
25
|
"peerDependenciesMeta": {
|
|
26
26
|
"weacpx": {
|