openclaw-lark-multi-agent 1.0.1 β 1.0.3
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/feishu-bot.d.ts +3 -0
- package/dist/feishu-bot.js +50 -15
- package/dist/message-store.d.ts +1 -0
- package/dist/message-store.js +4 -0
- package/package.json +1 -1
package/dist/feishu-bot.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export declare class FeishuBot {
|
|
|
33
33
|
private delayedFailureTimers;
|
|
34
34
|
/** Last time a real assistant-visible reply was successfully handed to the delivery pipeline. */
|
|
35
35
|
private lastRealDeliveryAt;
|
|
36
|
+
/** Active chatSend trigger target so final replies and proactive session.message share one delivery key. */
|
|
37
|
+
private activeDeliveryTargets;
|
|
36
38
|
private adminOpenId;
|
|
37
39
|
private static allBots;
|
|
38
40
|
constructor(config: BotConfig, openclawClient: OpenClawClient, store: MessageStore, adminOpenId?: string);
|
|
@@ -84,6 +86,7 @@ export declare class FeishuBot {
|
|
|
84
86
|
private formatUserVisibleError;
|
|
85
87
|
private isRuntimeFailureText;
|
|
86
88
|
private cancelDelayedFailure;
|
|
89
|
+
private setActiveDeliveryTarget;
|
|
87
90
|
private scheduleDelayedFailure;
|
|
88
91
|
private deliverySessionKey;
|
|
89
92
|
private stableHash;
|
package/dist/feishu-bot.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import * as lark from "@larksuiteoapi/node-sdk";
|
|
2
|
+
import { createRequire } from "module";
|
|
2
3
|
import { existsSync, readFileSync, statSync } from "fs";
|
|
3
4
|
import { basename, extname, resolve } from "path";
|
|
4
5
|
import { getBridgeAttachmentAllowedRoots, getBridgeAttachmentsDir } from "./paths.js";
|
|
5
6
|
import { buildFeishuCardElements } from "./markdown.js";
|
|
6
7
|
import { discussionManager } from "./discussion-manager.js";
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const LMA_VERSION = require("../package.json").version;
|
|
7
10
|
const MAX_BOT_STREAK = 10;
|
|
8
11
|
const BRIDGE_ATTACHMENTS_DIR = getBridgeAttachmentsDir();
|
|
9
12
|
const BRIDGE_ATTACHMENT_ALLOWED_ROOTS = getBridgeAttachmentAllowedRoots();
|
|
@@ -39,6 +42,8 @@ export class FeishuBot {
|
|
|
39
42
|
delayedFailureTimers = new Map();
|
|
40
43
|
/** Last time a real assistant-visible reply was successfully handed to the delivery pipeline. */
|
|
41
44
|
lastRealDeliveryAt = new Map();
|
|
45
|
+
/** Active chatSend trigger target so final replies and proactive session.message share one delivery key. */
|
|
46
|
+
activeDeliveryTargets = new Map();
|
|
42
47
|
adminOpenId;
|
|
43
48
|
static allBots = new Map();
|
|
44
49
|
constructor(config, openclawClient, store, adminOpenId) {
|
|
@@ -146,7 +151,8 @@ export class FeishuBot {
|
|
|
146
151
|
const parsed = this.extractBridgeAttachments(text);
|
|
147
152
|
if (parsed.text.trim() || parsed.attachments.length > 0)
|
|
148
153
|
this.cancelDelayedFailure(chatId);
|
|
149
|
-
|
|
154
|
+
const activeTarget = this.activeDeliveryTargets.get(chatId);
|
|
155
|
+
await this.enqueueAndDispatchDelivery(chatId, "assistant_visible", this.deliverySourceId("proactive", `${Date.now()}:${Math.random()}:${parsed.text.trim()}|${JSON.stringify(parsed.attachments)}`), parsed.text.trim(), parsed.attachments, activeTarget?.messageId, activeTarget ? `trigger:${activeTarget.triggerId}` : undefined);
|
|
150
156
|
}
|
|
151
157
|
catch (err) {
|
|
152
158
|
console.error(`[${this.config.name}] Failed to deliver proactive msg:`, err.message);
|
|
@@ -279,8 +285,11 @@ export class FeishuBot {
|
|
|
279
285
|
}
|
|
280
286
|
if (messageType !== "text" && messageType !== "image" && messageType !== "file" && messageType !== "audio" && messageType !== "sticker" && messageType !== "post")
|
|
281
287
|
return;
|
|
282
|
-
// --- Dedup:
|
|
283
|
-
|
|
288
|
+
// --- Dedup: atomically claim this message for this bot before any await.
|
|
289
|
+
// Feishu/WebSocket can deliver the same event more than once; a separate
|
|
290
|
+
// has-then-mark sequence races and can send the same user message into
|
|
291
|
+
// OpenClaw twice.
|
|
292
|
+
if (!this.store.tryMarkBotProcessed(this.config.name, messageId))
|
|
284
293
|
return;
|
|
285
294
|
// --- Cache chat info (lazy, at most once per hour) ---
|
|
286
295
|
await this.fetchAndCacheChatInfo(chatId, chatType);
|
|
@@ -385,8 +394,6 @@ export class FeishuBot {
|
|
|
385
394
|
});
|
|
386
395
|
if (insertedId < 0)
|
|
387
396
|
insertedId = this.store.getMessageId(messageId) || -1;
|
|
388
|
-
// Mark as processed only after successful parse + insert
|
|
389
|
-
this.store.markBotProcessed(this.config.name, messageId);
|
|
390
397
|
// --- Commands: in p2p always respond; in group, check shouldRespond first ---
|
|
391
398
|
// Single slash commands are handled by the bridge. Double slash commands were
|
|
392
399
|
// already unescaped above and should pass through to OpenClaw instead.
|
|
@@ -668,16 +675,26 @@ export class FeishuBot {
|
|
|
668
675
|
}
|
|
669
676
|
}
|
|
670
677
|
try {
|
|
671
|
-
const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
678
|
+
const releaseActiveDeliveryTarget = lastHuman.messageId ? this.setActiveDeliveryTarget(chatId, triggerId, lastHuman.messageId) : () => { };
|
|
679
|
+
let reply;
|
|
680
|
+
try {
|
|
681
|
+
reply = await this.openclawClient.chatSendWithContext({
|
|
682
|
+
sessionKey,
|
|
683
|
+
unsyncedMessages: contextMsgs,
|
|
684
|
+
currentMessage: lastHuman.content,
|
|
685
|
+
currentSenderName: lastHuman.senderName,
|
|
686
|
+
deliver: false,
|
|
687
|
+
// Keep bridge UX responsive; long agent/tool loops should surface a clear failure
|
|
688
|
+
// instead of leaving reactions stuck forever.
|
|
689
|
+
timeoutMs: 1_800_000,
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
finally {
|
|
693
|
+
// OpenClaw may emit the final assistant session.message just after
|
|
694
|
+
// collectReply returns. Keep the trigger mapping briefly so proactive
|
|
695
|
+
// and chat-final paths share the same delivery key.
|
|
696
|
+
releaseActiveDeliveryTarget();
|
|
697
|
+
}
|
|
681
698
|
console.log(`[${this.config.name}] OpenClaw reply collected for ${chatId.slice(-8)} in ${Date.now() - queueStartedAt}ms`);
|
|
682
699
|
const parsedReply = this.extractBridgeAttachments(reply);
|
|
683
700
|
const visibleReply = parsedReply.text;
|
|
@@ -933,6 +950,23 @@ export class FeishuBot {
|
|
|
933
950
|
clearTimeout(timer);
|
|
934
951
|
this.delayedFailureTimers.delete(chatId);
|
|
935
952
|
}
|
|
953
|
+
setActiveDeliveryTarget(chatId, triggerId, messageId) {
|
|
954
|
+
const existing = this.activeDeliveryTargets.get(chatId);
|
|
955
|
+
if (existing?.timer)
|
|
956
|
+
clearTimeout(existing.timer);
|
|
957
|
+
const token = Symbol(`${chatId}:${triggerId}`);
|
|
958
|
+
this.activeDeliveryTargets.set(chatId, { triggerId, messageId, token });
|
|
959
|
+
return () => {
|
|
960
|
+
const timer = setTimeout(() => {
|
|
961
|
+
const current = this.activeDeliveryTargets.get(chatId);
|
|
962
|
+
if (current?.token === token)
|
|
963
|
+
this.activeDeliveryTargets.delete(chatId);
|
|
964
|
+
}, 60_000);
|
|
965
|
+
const current = this.activeDeliveryTargets.get(chatId);
|
|
966
|
+
if (current?.token === token)
|
|
967
|
+
current.timer = timer;
|
|
968
|
+
};
|
|
969
|
+
}
|
|
936
970
|
scheduleDelayedFailure(chatId, replyToMessageId, text, triggerId) {
|
|
937
971
|
const lastRealDelivery = this.lastRealDeliveryAt.get(chatId) || 0;
|
|
938
972
|
if (Date.now() - lastRealDelivery < 90_000) {
|
|
@@ -1434,6 +1468,7 @@ export class FeishuBot {
|
|
|
1434
1468
|
`π ${this.config.name} Bot Status`,
|
|
1435
1469
|
`ββββββββββββββββββ`,
|
|
1436
1470
|
`π€ Bot: ${this.config.name}`,
|
|
1471
|
+
`π§© LMA: ${LMA_VERSION}`,
|
|
1437
1472
|
`π§ 樑ε: ${model}`,
|
|
1438
1473
|
`π¬ δΌθ―: ${chatLabel} (${chatType === "p2p" ? "η§θ" : "ηΎ€θ"})`,
|
|
1439
1474
|
`π Session: ${sessionExists} | ${status}`,
|
package/dist/message-store.d.ts
CHANGED
package/dist/message-store.js
CHANGED
|
@@ -625,6 +625,10 @@ export class MessageStore {
|
|
|
625
625
|
markBotProcessed(botName, messageId) {
|
|
626
626
|
this.db.prepare(`INSERT OR IGNORE INTO processed_events (bot_name, message_id) VALUES (?, ?)`).run(botName, messageId);
|
|
627
627
|
}
|
|
628
|
+
tryMarkBotProcessed(botName, messageId) {
|
|
629
|
+
const result = this.db.prepare(`INSERT OR IGNORE INTO processed_events (bot_name, message_id) VALUES (?, ?)`).run(botName, messageId);
|
|
630
|
+
return result.changes === 1;
|
|
631
|
+
}
|
|
628
632
|
close() {
|
|
629
633
|
this.db.close();
|
|
630
634
|
}
|