@automagik/omni 2.260317.3 → 2.260320.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/index.js +39 -17
- package/dist/resolve.d.ts.map +1 -1
- package/dist/server/index.js +399 -300
- package/package.json +9 -9
package/dist/server/index.js
CHANGED
|
@@ -27890,6 +27890,19 @@ async function executeLogAction(config2, context2, _deps) {
|
|
|
27890
27890
|
};
|
|
27891
27891
|
}
|
|
27892
27892
|
}
|
|
27893
|
+
function extractMessages(context2) {
|
|
27894
|
+
if (context2.debounce?.messages && context2.debounce.messages.length > 0) {
|
|
27895
|
+
const messages = context2.debounce.messages.map((m2) => m2.text).filter((t) => !!t);
|
|
27896
|
+
if (messages.length === 0) {
|
|
27897
|
+
return { error: "no text content found in debounced messages" };
|
|
27898
|
+
}
|
|
27899
|
+
return messages;
|
|
27900
|
+
}
|
|
27901
|
+
const messageContent = context2.payload.content ?? context2.payload.text ?? "";
|
|
27902
|
+
if (!messageContent)
|
|
27903
|
+
return { error: "message content not found in payload" };
|
|
27904
|
+
return [messageContent];
|
|
27905
|
+
}
|
|
27893
27906
|
function extractAgentCallContext(config2, context2) {
|
|
27894
27907
|
const instanceId = config2.providerId ? substituteTemplate(config2.providerId, context2) : context2.payload.instanceId;
|
|
27895
27908
|
if (!instanceId) {
|
|
@@ -27903,9 +27916,9 @@ function extractAgentCallContext(config2, context2) {
|
|
|
27903
27916
|
return { error: "chatId not found in payload" };
|
|
27904
27917
|
if (!senderId)
|
|
27905
27918
|
return { error: "senderId not found in payload" };
|
|
27906
|
-
const
|
|
27907
|
-
if (
|
|
27908
|
-
return
|
|
27919
|
+
const messagesResult = extractMessages(context2);
|
|
27920
|
+
if ("error" in messagesResult)
|
|
27921
|
+
return messagesResult;
|
|
27909
27922
|
const agentId = substituteTemplate(config2.agentId, context2);
|
|
27910
27923
|
if (!agentId)
|
|
27911
27924
|
return { error: "agentId is required" };
|
|
@@ -27916,7 +27929,7 @@ function extractAgentCallContext(config2, context2) {
|
|
|
27916
27929
|
chatId,
|
|
27917
27930
|
senderId,
|
|
27918
27931
|
senderName,
|
|
27919
|
-
messages:
|
|
27932
|
+
messages: messagesResult
|
|
27920
27933
|
}
|
|
27921
27934
|
};
|
|
27922
27935
|
}
|
|
@@ -29510,7 +29523,7 @@ class GenieClient {
|
|
|
29510
29523
|
this.targetAgentTemplate = config2.targetAgent;
|
|
29511
29524
|
this.agentRole = config2.agentRole;
|
|
29512
29525
|
this.autoSpawn = config2.autoSpawn ?? true;
|
|
29513
|
-
this.autoSpawnDir = config2.autoSpawnDir ??
|
|
29526
|
+
this.autoSpawnDir = config2.autoSpawnDir ?? "";
|
|
29514
29527
|
this.hasTemplates = /\{\w+\}/.test(this.teamNameTemplate) || /\{\w+\}/.test(this.agentNameTemplate) || /\{\w+\}/.test(this.targetAgentTemplate);
|
|
29515
29528
|
}
|
|
29516
29529
|
isTeamKnown(teamName) {
|
|
@@ -222904,7 +222917,7 @@ var init_sentry_scrub = __esm(() => {
|
|
|
222904
222917
|
var require_package8 = __commonJS((exports, module) => {
|
|
222905
222918
|
module.exports = {
|
|
222906
222919
|
name: "@omni/api",
|
|
222907
|
-
version: "2.
|
|
222920
|
+
version: "2.260320.2",
|
|
222908
222921
|
type: "module",
|
|
222909
222922
|
exports: {
|
|
222910
222923
|
".": {
|
|
@@ -331865,7 +331878,7 @@ var init_instances3 = __esm(() => {
|
|
|
331865
331878
|
slackAppToken: exports_external.string().optional().nullable().describe("Slack app token (persisted for reconnection)"),
|
|
331866
331879
|
slackSigningSecret: exports_external.string().optional().nullable().describe("Slack signing secret (persisted for reconnection)"),
|
|
331867
331880
|
readReceipts: exports_external.enum(["on", "off", "exclude-self"]).default("on").describe("Read receipt mode: on (default), off, or exclude-self (skip receipts for the instance own number)"),
|
|
331868
|
-
groupHistorySize: exports_external.number().int().min(0).max(200).default(50).describe("Number of context messages to include
|
|
331881
|
+
groupHistorySize: exports_external.number().int().min(0).max(200).default(50).describe("Number of context messages to include when dispatching to agent. Groups use the full value; DMs are capped at 20. (0 = disabled, max 200)"),
|
|
331869
331882
|
reactionAck: exports_external.enum(["on", "off"]).default("off").describe("Reaction ack mode: on to send a reaction while agent processes"),
|
|
331870
331883
|
reactionAckEmoji: exports_external.record(exports_external.string()).optional().nullable().describe('Per-channel emoji map for reaction ack (e.g. {"whatsapp":"\\u2705"})'),
|
|
331871
331884
|
ackTimeoutMs: exports_external.number().int().min(0).max(120000).default(30000).describe("Ack timeout in milliseconds (max 120000)")
|
|
@@ -333756,6 +333769,19 @@ async function resolveMessageFromRef(services, ref) {
|
|
|
333756
333769
|
}
|
|
333757
333770
|
return found;
|
|
333758
333771
|
}
|
|
333772
|
+
async function verifyMessageInstanceOwnership(services, message2, instanceId) {
|
|
333773
|
+
if (!message2.chatId)
|
|
333774
|
+
return;
|
|
333775
|
+
const chat2 = await services.chats.getById(message2.chatId);
|
|
333776
|
+
if (chat2 && chat2.instanceId !== instanceId) {
|
|
333777
|
+
throw new OmniError({
|
|
333778
|
+
code: ERROR_CODES.FORBIDDEN,
|
|
333779
|
+
message: "Message does not belong to this instance",
|
|
333780
|
+
context: { instanceId, messageInstanceId: chat2.instanceId },
|
|
333781
|
+
recoverable: false
|
|
333782
|
+
});
|
|
333783
|
+
}
|
|
333784
|
+
}
|
|
333759
333785
|
var log77, mediaDownloadLog, messagesRoutes, UUID_REGEX, MessageSourceSchema, MessageTypeSchema, MessageStatusSchema, DeliveryStatusSchema, listQuerySchema12, createMessageSchema, updateMessageSchema, recordEditSchema, addReactionSchema, removeReactionSchema, updateDeliveryStatusSchema, MentionSchema, sendTextSchema, sendMediaSchema, sendReactionSchema, sendStickerSchema, sendContactSchema, sendLocationSchema, messageRefSchema, _mediaStorageForDownload = null, sendTtsSchema, forwardMessageSchema, sendPresenceSchema, markMessageReadSchema, markBatchReadSchema, sendPollSchema, sendEmbedSchema, editMessageChannelSchema, deleteMessageChannelSchema, starMessageSchema;
|
|
333760
333786
|
var init_messages5 = __esm(() => {
|
|
333761
333787
|
init_dist6();
|
|
@@ -335035,10 +335061,28 @@ var init_messages5 = __esm(() => {
|
|
|
335035
335061
|
recoverable: false
|
|
335036
335062
|
});
|
|
335037
335063
|
}
|
|
335038
|
-
|
|
335064
|
+
let resolvedMessageId = messageId;
|
|
335065
|
+
if (isUUID(messageId)) {
|
|
335066
|
+
const message2 = await services.messages.getById(messageId);
|
|
335067
|
+
await verifyMessageInstanceOwnership(services, message2, instanceId);
|
|
335068
|
+
resolvedMessageId = message2.externalId;
|
|
335069
|
+
log77.debug("Resolved internal UUID to external ID", { messageId, externalId: resolvedMessageId });
|
|
335070
|
+
}
|
|
335071
|
+
try {
|
|
335072
|
+
await plugin6.editMessage(instanceId, channelId, resolvedMessageId, text3);
|
|
335073
|
+
} catch (error2) {
|
|
335074
|
+
if (error2 instanceof OmniError)
|
|
335075
|
+
throw error2;
|
|
335076
|
+
throw new OmniError({
|
|
335077
|
+
code: ERROR_CODES.CHANNEL_SEND_FAILED,
|
|
335078
|
+
message: `Failed to edit message: ${error2 instanceof Error ? error2.message : String(error2)}`,
|
|
335079
|
+
context: { instanceId, channelType: instance4.channel, messageId: resolvedMessageId },
|
|
335080
|
+
recoverable: false
|
|
335081
|
+
});
|
|
335082
|
+
}
|
|
335039
335083
|
return c.json({
|
|
335040
335084
|
success: true,
|
|
335041
|
-
data: { messageId, edited: true }
|
|
335085
|
+
data: { messageId, externalId: resolvedMessageId, edited: true }
|
|
335042
335086
|
});
|
|
335043
335087
|
});
|
|
335044
335088
|
messagesRoutes.post("/delete-channel", zValidator("json", deleteMessageChannelSchema), async (c) => {
|
|
@@ -337611,6 +337655,93 @@ function buildWhatsAppMessageContext(rawPayload, chatId, instance4, text3) {
|
|
|
337611
337655
|
return { isDirectMessage, mentionsBot, isReplyToBot, text: text3 };
|
|
337612
337656
|
}
|
|
337613
337657
|
|
|
337658
|
+
// ../api/src/plugins/message-debouncer.ts
|
|
337659
|
+
class MessageDebouncer {
|
|
337660
|
+
buffers = new Map;
|
|
337661
|
+
timers = new Map;
|
|
337662
|
+
inFlight = new Set;
|
|
337663
|
+
onFlush;
|
|
337664
|
+
constructor(onFlush) {
|
|
337665
|
+
this.onFlush = onFlush;
|
|
337666
|
+
}
|
|
337667
|
+
getChatKey(instanceId, chatId) {
|
|
337668
|
+
return `${instanceId}:${chatId}`;
|
|
337669
|
+
}
|
|
337670
|
+
buffer(instanceId, chatId, message2, config4) {
|
|
337671
|
+
const chatKey = this.getChatKey(instanceId, chatId);
|
|
337672
|
+
const buffer3 = this.buffers.get(chatKey) ?? [];
|
|
337673
|
+
buffer3.push(message2);
|
|
337674
|
+
this.buffers.set(chatKey, buffer3);
|
|
337675
|
+
if (this.inFlight.has(chatKey))
|
|
337676
|
+
return;
|
|
337677
|
+
this.restartTimer(chatKey, config4);
|
|
337678
|
+
}
|
|
337679
|
+
onUserTyping(instanceId, chatId, config4) {
|
|
337680
|
+
const chatKey = this.getChatKey(instanceId, chatId);
|
|
337681
|
+
if (config4.restartOnTyping && this.buffers.has(chatKey)) {
|
|
337682
|
+
log83.debug("Restarting debounce timer on user typing", { chatKey });
|
|
337683
|
+
this.restartTimer(chatKey, config4);
|
|
337684
|
+
}
|
|
337685
|
+
}
|
|
337686
|
+
restartTimer(chatKey, config4) {
|
|
337687
|
+
const existing = this.timers.get(chatKey);
|
|
337688
|
+
if (config4.mode === "fixed" && existing)
|
|
337689
|
+
return;
|
|
337690
|
+
if (existing)
|
|
337691
|
+
clearTimeout(existing);
|
|
337692
|
+
let delay2;
|
|
337693
|
+
switch (config4.mode) {
|
|
337694
|
+
case "disabled":
|
|
337695
|
+
delay2 = 0;
|
|
337696
|
+
break;
|
|
337697
|
+
case "fixed":
|
|
337698
|
+
delay2 = config4.minMs;
|
|
337699
|
+
break;
|
|
337700
|
+
case "randomized":
|
|
337701
|
+
delay2 = config4.minMs + Math.random() * (config4.maxMs - config4.minMs);
|
|
337702
|
+
break;
|
|
337703
|
+
default:
|
|
337704
|
+
delay2 = 0;
|
|
337705
|
+
}
|
|
337706
|
+
const timer2 = setTimeout(() => this.flush(chatKey), delay2);
|
|
337707
|
+
this.timers.set(chatKey, timer2);
|
|
337708
|
+
}
|
|
337709
|
+
async flush(chatKey) {
|
|
337710
|
+
const messages4 = this.buffers.get(chatKey);
|
|
337711
|
+
const timer2 = this.timers.get(chatKey);
|
|
337712
|
+
this.buffers.delete(chatKey);
|
|
337713
|
+
this.timers.delete(chatKey);
|
|
337714
|
+
if (timer2)
|
|
337715
|
+
clearTimeout(timer2);
|
|
337716
|
+
if (!messages4?.length)
|
|
337717
|
+
return;
|
|
337718
|
+
this.inFlight.add(chatKey);
|
|
337719
|
+
try {
|
|
337720
|
+
await this.onFlush(chatKey, messages4);
|
|
337721
|
+
} catch (error2) {
|
|
337722
|
+
log83.error("Error flushing debounced messages", { chatKey, error: String(error2) });
|
|
337723
|
+
} finally {
|
|
337724
|
+
this.inFlight.delete(chatKey);
|
|
337725
|
+
const pending = this.buffers.get(chatKey);
|
|
337726
|
+
if (pending?.length) {
|
|
337727
|
+
setTimeout(() => this.flush(chatKey), 0);
|
|
337728
|
+
}
|
|
337729
|
+
}
|
|
337730
|
+
}
|
|
337731
|
+
clear() {
|
|
337732
|
+
for (const timer2 of this.timers.values())
|
|
337733
|
+
clearTimeout(timer2);
|
|
337734
|
+
this.buffers.clear();
|
|
337735
|
+
this.timers.clear();
|
|
337736
|
+
this.inFlight.clear();
|
|
337737
|
+
}
|
|
337738
|
+
}
|
|
337739
|
+
var log83;
|
|
337740
|
+
var init_message_debouncer = __esm(() => {
|
|
337741
|
+
init_src();
|
|
337742
|
+
log83 = createLogger("message-debouncer");
|
|
337743
|
+
});
|
|
337744
|
+
|
|
337614
337745
|
// ../api/src/plugins/session-storage.ts
|
|
337615
337746
|
function scopeSessionKey(providerId, sessionKey) {
|
|
337616
337747
|
return `provider:${providerId}:session:${sessionKey}`;
|
|
@@ -337699,7 +337830,7 @@ class RateLimiter {
|
|
|
337699
337830
|
let timestamps = this.counters.get(key) ?? [];
|
|
337700
337831
|
timestamps = timestamps.filter((ts) => now - ts < this.windowMs);
|
|
337701
337832
|
if (timestamps.length >= maxPerMinute) {
|
|
337702
|
-
|
|
337833
|
+
log84.debug("Rate limit exceeded", { key, count: timestamps.length, limit: maxPerMinute });
|
|
337703
337834
|
return false;
|
|
337704
337835
|
}
|
|
337705
337836
|
timestamps.push(now);
|
|
@@ -337731,7 +337862,7 @@ class ReactionDedup {
|
|
|
337731
337862
|
}
|
|
337732
337863
|
const msgCount = this.messageCounters.get(messageId) ?? 0;
|
|
337733
337864
|
if (msgCount >= this.maxPerMessage) {
|
|
337734
|
-
|
|
337865
|
+
log84.debug("Reaction per-message limit reached", { messageId, count: msgCount });
|
|
337735
337866
|
return true;
|
|
337736
337867
|
}
|
|
337737
337868
|
this.seen.set(key, Date.now());
|
|
@@ -337754,73 +337885,6 @@ class ReactionDedup {
|
|
|
337754
337885
|
return false;
|
|
337755
337886
|
}
|
|
337756
337887
|
}
|
|
337757
|
-
|
|
337758
|
-
class MessageDebouncer {
|
|
337759
|
-
buffers = new Map;
|
|
337760
|
-
timers = new Map;
|
|
337761
|
-
onFlush;
|
|
337762
|
-
constructor(onFlush) {
|
|
337763
|
-
this.onFlush = onFlush;
|
|
337764
|
-
}
|
|
337765
|
-
getChatKey(instanceId, chatId) {
|
|
337766
|
-
return `${instanceId}:${chatId}`;
|
|
337767
|
-
}
|
|
337768
|
-
buffer(instanceId, chatId, message2, config4) {
|
|
337769
|
-
const chatKey = this.getChatKey(instanceId, chatId);
|
|
337770
|
-
const buffer3 = this.buffers.get(chatKey) ?? [];
|
|
337771
|
-
buffer3.push(message2);
|
|
337772
|
-
this.buffers.set(chatKey, buffer3);
|
|
337773
|
-
this.restartTimer(chatKey, config4);
|
|
337774
|
-
}
|
|
337775
|
-
onUserTyping(instanceId, chatId, config4) {
|
|
337776
|
-
const chatKey = this.getChatKey(instanceId, chatId);
|
|
337777
|
-
if (config4.restartOnTyping && this.buffers.has(chatKey)) {
|
|
337778
|
-
log83.debug("Restarting debounce timer on user typing", { chatKey });
|
|
337779
|
-
this.restartTimer(chatKey, config4);
|
|
337780
|
-
}
|
|
337781
|
-
}
|
|
337782
|
-
restartTimer(chatKey, config4) {
|
|
337783
|
-
const existing = this.timers.get(chatKey);
|
|
337784
|
-
if (config4.mode === "fixed" && existing)
|
|
337785
|
-
return;
|
|
337786
|
-
if (existing)
|
|
337787
|
-
clearTimeout(existing);
|
|
337788
|
-
let delay2;
|
|
337789
|
-
switch (config4.mode) {
|
|
337790
|
-
case "disabled":
|
|
337791
|
-
delay2 = 0;
|
|
337792
|
-
break;
|
|
337793
|
-
case "fixed":
|
|
337794
|
-
delay2 = config4.minMs;
|
|
337795
|
-
break;
|
|
337796
|
-
case "randomized":
|
|
337797
|
-
delay2 = config4.minMs + Math.random() * (config4.maxMs - config4.minMs);
|
|
337798
|
-
break;
|
|
337799
|
-
default:
|
|
337800
|
-
delay2 = 0;
|
|
337801
|
-
}
|
|
337802
|
-
const timer2 = setTimeout(() => this.flush(chatKey), delay2);
|
|
337803
|
-
this.timers.set(chatKey, timer2);
|
|
337804
|
-
}
|
|
337805
|
-
async flush(chatKey) {
|
|
337806
|
-
const messages4 = this.buffers.get(chatKey);
|
|
337807
|
-
this.buffers.delete(chatKey);
|
|
337808
|
-
this.timers.delete(chatKey);
|
|
337809
|
-
if (messages4?.length) {
|
|
337810
|
-
try {
|
|
337811
|
-
await this.onFlush(chatKey, messages4);
|
|
337812
|
-
} catch (error2) {
|
|
337813
|
-
log83.error("Error flushing debounced messages", { chatKey, error: String(error2) });
|
|
337814
|
-
}
|
|
337815
|
-
}
|
|
337816
|
-
}
|
|
337817
|
-
clear() {
|
|
337818
|
-
for (const timer2 of this.timers.values())
|
|
337819
|
-
clearTimeout(timer2);
|
|
337820
|
-
this.buffers.clear();
|
|
337821
|
-
this.timers.clear();
|
|
337822
|
-
}
|
|
337823
|
-
}
|
|
337824
337888
|
function getDebounceConfig(instance4) {
|
|
337825
337889
|
return {
|
|
337826
337890
|
mode: instance4.messageDebounceMode ?? "disabled",
|
|
@@ -337906,7 +337970,7 @@ async function sendTypingPresence(channel4, instanceId, chatId, state) {
|
|
|
337906
337970
|
await plugin6.sendTyping(instanceId, chatId, duration);
|
|
337907
337971
|
}
|
|
337908
337972
|
} catch (error2) {
|
|
337909
|
-
|
|
337973
|
+
log84.debug("Failed to send typing presence", { error: String(error2) });
|
|
337910
337974
|
}
|
|
337911
337975
|
}
|
|
337912
337976
|
async function sendTextMessage5(channel4, instanceId, chatId, text3, messageFormatMode = "convert", replyTo, correlationId, senderAgentId) {
|
|
@@ -337922,7 +337986,7 @@ async function sendTextMessage5(channel4, instanceId, chatId, text3, messageForm
|
|
|
337922
337986
|
}
|
|
337923
337987
|
async function sendErrorFeedback(channel4, instanceId, chatId, error2) {
|
|
337924
337988
|
const errorMsg = error2 instanceof Error ? error2.message : String(error2);
|
|
337925
|
-
|
|
337989
|
+
log84.error("agent_dispatch_error", { channel: channel4, instanceId, chatId, error: errorMsg });
|
|
337926
337990
|
const text3 = "\u26A0\uFE0F Sorry, I ran into an issue processing your message. Please try again.";
|
|
337927
337991
|
await sendTextMessage5(channel4, instanceId, chatId, text3);
|
|
337928
337992
|
}
|
|
@@ -337972,7 +338036,7 @@ function resolveMediaPath2(mediaUrl) {
|
|
|
337972
338036
|
const fullPath = resolve2(MEDIA_BASE_PATH3, relativePath);
|
|
337973
338037
|
const basePath = resolve2(MEDIA_BASE_PATH3);
|
|
337974
338038
|
if (!fullPath.startsWith(`${basePath}/`) && fullPath !== basePath) {
|
|
337975
|
-
|
|
338039
|
+
log84.warn("Path traversal attempt blocked", { mediaUrl, resolved: fullPath, basePath });
|
|
337976
338040
|
return null;
|
|
337977
338041
|
}
|
|
337978
338042
|
return fullPath;
|
|
@@ -338029,7 +338093,7 @@ async function waitForMediaProcessing(services, instanceId, chatId, externalId,
|
|
|
338029
338093
|
return MEDIA_WAIT_NULL;
|
|
338030
338094
|
const chat2 = await services.chats.findByExternalIdSmart(instanceId, chatId);
|
|
338031
338095
|
if (!chat2) {
|
|
338032
|
-
|
|
338096
|
+
log84.warn("Chat not found for media wait", { instanceId, chatId });
|
|
338033
338097
|
return MEDIA_WAIT_NULL;
|
|
338034
338098
|
}
|
|
338035
338099
|
const deadline = Date.now() + 60000;
|
|
@@ -338037,14 +338101,14 @@ async function waitForMediaProcessing(services, instanceId, chatId, externalId,
|
|
|
338037
338101
|
const msg = await services.messages.getByExternalId(chat2.id, externalId);
|
|
338038
338102
|
const result = checkProcessedColumn(msg, column2);
|
|
338039
338103
|
if (result === "error") {
|
|
338040
|
-
|
|
338104
|
+
log84.warn("Media processing failed", { instanceId, chatId, externalId, error: msg?.[column2] });
|
|
338041
338105
|
return MEDIA_WAIT_NULL;
|
|
338042
338106
|
}
|
|
338043
338107
|
if (result !== "pending")
|
|
338044
338108
|
return result;
|
|
338045
338109
|
await sleep4(pollMs);
|
|
338046
338110
|
}
|
|
338047
|
-
|
|
338111
|
+
log84.warn("Media processing wait timed out", { instanceId, chatId, externalId, contentType });
|
|
338048
338112
|
return MEDIA_WAIT_NULL;
|
|
338049
338113
|
}
|
|
338050
338114
|
function formatProcessedMedia(contentType, fullPath, processedText, includePath, sendMediaPathTypes) {
|
|
@@ -338082,12 +338146,11 @@ async function resolveQuotedMessage(services, instanceId, chatId, replyToId) {
|
|
|
338082
338146
|
const content = getMessageContentText(quoted);
|
|
338083
338147
|
if (!content)
|
|
338084
338148
|
return null;
|
|
338085
|
-
const
|
|
338086
|
-
const truncated = content.length > maxLen ? `${content.slice(0, maxLen)}...` : content;
|
|
338149
|
+
const truncated = content.length > QUOTED_MESSAGE_MAX_CHARS ? `${content.slice(0, QUOTED_MESSAGE_MAX_CHARS)}...` : content;
|
|
338087
338150
|
const timeStr = time3 ? ` at ${time3}` : "";
|
|
338088
338151
|
return `[Quoting ${sender}${timeStr}: ${truncated}]`;
|
|
338089
338152
|
} catch (error2) {
|
|
338090
|
-
|
|
338153
|
+
log84.debug("Failed to resolve quoted message", { replyToId, error: String(error2) });
|
|
338091
338154
|
return null;
|
|
338092
338155
|
}
|
|
338093
338156
|
}
|
|
@@ -338160,11 +338223,11 @@ async function resolveContactName2(services, instanceId, jid, cacheMap) {
|
|
|
338160
338223
|
try {
|
|
338161
338224
|
const chat2 = await services.chats.findByExternalIdSmart(instanceId, jid);
|
|
338162
338225
|
if (chat2?.name) {
|
|
338163
|
-
|
|
338226
|
+
log84.debug("Contact name from DB fallback", { jid, name: chat2.name });
|
|
338164
338227
|
return chat2.name;
|
|
338165
338228
|
}
|
|
338166
338229
|
} catch (error2) {
|
|
338167
|
-
|
|
338230
|
+
log84.warn("Failed to query DB for contact", { jid, error: String(error2) });
|
|
338168
338231
|
}
|
|
338169
338232
|
return null;
|
|
338170
338233
|
}
|
|
@@ -338196,14 +338259,14 @@ async function applyJidMentionReplacement(services, instanceId, jid, jidToName,
|
|
|
338196
338259
|
async function replaceMentionsWithContactNames(services, instanceId, text3, mentionedJids, mentionedContacts) {
|
|
338197
338260
|
if (!mentionedJids?.length)
|
|
338198
338261
|
return text3;
|
|
338199
|
-
|
|
338262
|
+
log84.debug("Starting mention replacement", { mentionCount: mentionedJids.length });
|
|
338200
338263
|
const jidToName = buildJidNameMap(mentionedContacts);
|
|
338201
338264
|
const stats = { resolved: 0, replaced: 0, unresolved: 0, skipped: 0 };
|
|
338202
338265
|
let replacedText = text3;
|
|
338203
338266
|
for (const jid of mentionedJids) {
|
|
338204
338267
|
replacedText = await applyJidMentionReplacement(services, instanceId, jid, jidToName, replacedText, stats);
|
|
338205
338268
|
}
|
|
338206
|
-
|
|
338269
|
+
log84.debug("Mention replacement complete", {
|
|
338207
338270
|
original: text3,
|
|
338208
338271
|
replaced: replacedText,
|
|
338209
338272
|
mentionCount: mentionedJids.length,
|
|
@@ -338272,7 +338335,7 @@ async function fetchSenderMetadata(services, channel4, instanceId, senderId) {
|
|
|
338272
338335
|
platformUsername: identity?.platformUsername ?? undefined
|
|
338273
338336
|
};
|
|
338274
338337
|
} catch (error2) {
|
|
338275
|
-
|
|
338338
|
+
log84.debug("Failed to fetch sender identity metadata", { error: String(error2) });
|
|
338276
338339
|
return {};
|
|
338277
338340
|
}
|
|
338278
338341
|
}
|
|
@@ -338286,7 +338349,7 @@ async function fetchChatMetadata(services, instanceId, chatId, chatType) {
|
|
|
338286
338349
|
participantCount: chat2?.participantCount ?? undefined
|
|
338287
338350
|
};
|
|
338288
338351
|
} catch (error2) {
|
|
338289
|
-
|
|
338352
|
+
log84.debug("Failed to fetch chat metadata", { error: String(error2) });
|
|
338290
338353
|
return {};
|
|
338291
338354
|
}
|
|
338292
338355
|
}
|
|
@@ -338308,7 +338371,7 @@ async function routeStreamDelta(sender, delta) {
|
|
|
338308
338371
|
}
|
|
338309
338372
|
async function resolveStreamingCapabilities(services, instance4, channel4, chatId, traceId, db2) {
|
|
338310
338373
|
if (!instance4.agentStreamMode) {
|
|
338311
|
-
|
|
338374
|
+
log84.debug("Stream guard: agentStreamMode is falsy", {
|
|
338312
338375
|
instanceId: instance4.id,
|
|
338313
338376
|
agentStreamMode: instance4.agentStreamMode,
|
|
338314
338377
|
chatId
|
|
@@ -338317,7 +338380,7 @@ async function resolveStreamingCapabilities(services, instance4, channel4, chatI
|
|
|
338317
338380
|
}
|
|
338318
338381
|
const provider = await getAgentProvider(services, instance4, db2);
|
|
338319
338382
|
if (!provider?.triggerStream) {
|
|
338320
|
-
|
|
338383
|
+
log84.debug("Stream guard: provider has no triggerStream", {
|
|
338321
338384
|
instanceId: instance4.id,
|
|
338322
338385
|
hasProvider: !!provider,
|
|
338323
338386
|
chatId
|
|
@@ -338326,7 +338389,7 @@ async function resolveStreamingCapabilities(services, instance4, channel4, chatI
|
|
|
338326
338389
|
}
|
|
338327
338390
|
const plugin6 = await getPlugin(channel4);
|
|
338328
338391
|
if (!plugin6?.capabilities?.canStreamResponse || !plugin6.createStreamSender) {
|
|
338329
|
-
|
|
338392
|
+
log84.debug("Stream guard: channel does not support streaming", {
|
|
338330
338393
|
channel: channel4,
|
|
338331
338394
|
canStream: plugin6?.capabilities?.canStreamResponse,
|
|
338332
338395
|
chatId
|
|
@@ -338335,7 +338398,7 @@ async function resolveStreamingCapabilities(services, instance4, channel4, chatI
|
|
|
338335
338398
|
}
|
|
338336
338399
|
const streamKey = `${instance4.id}:${chatId}`;
|
|
338337
338400
|
if (activeStreams.has(streamKey)) {
|
|
338338
|
-
|
|
338401
|
+
log84.info("Stream guard: parallel stream blocked, falling back to accumulate", {
|
|
338339
338402
|
instanceId: instance4.id,
|
|
338340
338403
|
chatId,
|
|
338341
338404
|
traceId
|
|
@@ -338358,7 +338421,7 @@ async function consumeStream(generator, sender, instanceId, chatId, traceId) {
|
|
|
338358
338421
|
hadContent = true;
|
|
338359
338422
|
await routeStreamDelta(sender, delta);
|
|
338360
338423
|
}
|
|
338361
|
-
|
|
338424
|
+
log84.info("Streaming response complete", {
|
|
338362
338425
|
instanceId,
|
|
338363
338426
|
chatId,
|
|
338364
338427
|
durationMs: Date.now() - startTime3,
|
|
@@ -338486,7 +338549,7 @@ async function dispatchViaStreamingProvider(services, instance4, messages4, trig
|
|
|
338486
338549
|
}
|
|
338487
338550
|
return streamResult;
|
|
338488
338551
|
} catch (err) {
|
|
338489
|
-
|
|
338552
|
+
log84.error("Streaming dispatch failed, falling back", {
|
|
338490
338553
|
instanceId: instance4.id,
|
|
338491
338554
|
chatId,
|
|
338492
338555
|
error: String(err),
|
|
@@ -338536,20 +338599,26 @@ async function buildContextMessages(services, instance4, chatId, currentMessageI
|
|
|
338536
338599
|
if (!chat2) {
|
|
338537
338600
|
return [];
|
|
338538
338601
|
}
|
|
338602
|
+
const effectiveLimit = chat2.chatType === "group" ? historyLimit : Math.min(historyLimit, DM_HISTORY_LIMIT);
|
|
338539
338603
|
const messagesResult = await services.messages.list({
|
|
338540
338604
|
chatId: chat2.id,
|
|
338541
|
-
limit:
|
|
338605
|
+
limit: effectiveLimit
|
|
338542
338606
|
});
|
|
338543
338607
|
const recentMessages = messagesResult.items;
|
|
338544
338608
|
if (!recentMessages || recentMessages.length === 0) {
|
|
338545
338609
|
return [];
|
|
338546
338610
|
}
|
|
338547
338611
|
const lastBotMessageIndex = recentMessages.findIndex((msg) => msg.isFromMe === true);
|
|
338548
|
-
if (lastBotMessageIndex === -1 || lastBotMessageIndex === 0) {
|
|
338549
|
-
return [];
|
|
338550
|
-
}
|
|
338551
338612
|
const currentMessageIdSet = new Set(currentMessageIds.filter(Boolean));
|
|
338552
|
-
|
|
338613
|
+
let contextMsgs;
|
|
338614
|
+
if (chat2.chatType !== "group") {
|
|
338615
|
+
contextMsgs = recentMessages.filter((msg) => !currentMessageIdSet.has(msg.externalId));
|
|
338616
|
+
} else {
|
|
338617
|
+
if (lastBotMessageIndex === -1 || lastBotMessageIndex === 0) {
|
|
338618
|
+
return [];
|
|
338619
|
+
}
|
|
338620
|
+
contextMsgs = recentMessages.slice(0, lastBotMessageIndex).filter((msg) => !currentMessageIdSet.has(msg.externalId));
|
|
338621
|
+
}
|
|
338553
338622
|
if (contextMsgs.length === 0) {
|
|
338554
338623
|
return [];
|
|
338555
338624
|
}
|
|
@@ -338564,7 +338633,7 @@ async function buildContextMessages(services, instance4, chatId, currentMessageI
|
|
|
338564
338633
|
return `[${name}${time3 ? ` - ${time3}` : ""}] ${text3}`;
|
|
338565
338634
|
});
|
|
338566
338635
|
} catch (error2) {
|
|
338567
|
-
|
|
338636
|
+
log84.warn("Failed to build context messages", { error: error2, chatId, instanceId: instance4.id });
|
|
338568
338637
|
return [];
|
|
338569
338638
|
}
|
|
338570
338639
|
}
|
|
@@ -338599,7 +338668,7 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
|
|
|
338599
338668
|
return false;
|
|
338600
338669
|
const { messageTexts, mediaFiles } = await prepareAgentContent(services, instance4, messages4);
|
|
338601
338670
|
if (!messageTexts.length && !mediaFiles.length) {
|
|
338602
|
-
|
|
338671
|
+
log84.debug("No text or media content for provider trigger, skipping");
|
|
338603
338672
|
return false;
|
|
338604
338673
|
}
|
|
338605
338674
|
if (!messageTexts.length && mediaFiles.length) {
|
|
@@ -338635,7 +338704,7 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
|
|
|
338635
338704
|
recordJourneyCheckpoint(correlationId, "T9", JOURNEY_STAGES.T9);
|
|
338636
338705
|
await forwardToChainedInstance(instance4, parts, correlationId, messages4);
|
|
338637
338706
|
}
|
|
338638
|
-
|
|
338707
|
+
log84.info("Agent response via IAgentProvider", {
|
|
338639
338708
|
instanceId: instance4.id,
|
|
338640
338709
|
chatId,
|
|
338641
338710
|
parts: result?.parts.length ?? 0,
|
|
@@ -338649,14 +338718,14 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
|
|
|
338649
338718
|
async function dispatchViaLegacy(services, instance4, messages4, triggerType, channel4, chatId, senderId, personId, senderName, traceId, perThreadExtraContext, senderAgentId) {
|
|
338650
338719
|
const { messageTexts, mediaFiles } = await prepareAgentContent(services, instance4, messages4);
|
|
338651
338720
|
if (perThreadExtraContext?.length) {
|
|
338652
|
-
|
|
338721
|
+
log84.warn("per_thread context available but legacy dispatch path has limited support \u2014 prepending as text", {
|
|
338653
338722
|
instanceId: instance4.id,
|
|
338654
338723
|
contextCount: perThreadExtraContext.length
|
|
338655
338724
|
});
|
|
338656
338725
|
messageTexts.unshift(...perThreadExtraContext);
|
|
338657
338726
|
}
|
|
338658
338727
|
if (!messageTexts.length && !mediaFiles.length) {
|
|
338659
|
-
|
|
338728
|
+
log84.debug("No text or media content in messages, skipping agent call");
|
|
338660
338729
|
return;
|
|
338661
338730
|
}
|
|
338662
338731
|
if (!messageTexts.length && mediaFiles.length) {
|
|
@@ -338690,7 +338759,7 @@ async function dispatchViaLegacy(services, instance4, messages4, triggerType, ch
|
|
|
338690
338759
|
recordJourneyCheckpoint(correlationId, "T8", JOURNEY_STAGES.T8);
|
|
338691
338760
|
await sendResponseParts(channel4, instance4.id, chatId, parts, getSplitDelayConfig(instance4), _fmtMode, replyTo, correlationId, senderAgentId);
|
|
338692
338761
|
recordJourneyCheckpoint(correlationId, "T9", JOURNEY_STAGES.T9);
|
|
338693
|
-
|
|
338762
|
+
log84.info("Agent response via legacy runner", {
|
|
338694
338763
|
instanceId: instance4.id,
|
|
338695
338764
|
chatId,
|
|
338696
338765
|
parts: result.parts.length,
|
|
@@ -338710,14 +338779,14 @@ async function performSessionReset(instance4, sessionId, chatId, services, db2,
|
|
|
338710
338779
|
sessionActuallyReset = true;
|
|
338711
338780
|
}
|
|
338712
338781
|
} catch (err) {
|
|
338713
|
-
|
|
338782
|
+
log84.warn("Failed to reset provider session", { error: String(err), instanceId: instance4.id, sessionId });
|
|
338714
338783
|
}
|
|
338715
338784
|
if (sessionActuallyReset) {
|
|
338716
338785
|
sessionActivityStore.recordReset(instance4.id, sessionId, Date.now());
|
|
338717
338786
|
eventBus.publish("session.reset", { instanceId: instance4.id, sessionId, timestamp: Date.now() }, { instanceId: instance4.id, channelType: channel4 }).catch((err) => {
|
|
338718
|
-
|
|
338787
|
+
log84.warn("Failed to publish session.reset event", { error: String(err), instanceId: instance4.id, sessionId });
|
|
338719
338788
|
});
|
|
338720
|
-
|
|
338789
|
+
log84.info("Session reset triggered", {
|
|
338721
338790
|
instanceId: instance4.id,
|
|
338722
338791
|
sessionId,
|
|
338723
338792
|
strategy: resetStrategy,
|
|
@@ -338760,7 +338829,7 @@ async function markPerThreadSessionInitialized(db2, instanceId, sessionId) {
|
|
|
338760
338829
|
target: [agentSessions.instanceId, agentSessions.sessionKey],
|
|
338761
338830
|
set: { lastUsedAt: now, updatedAt: now }
|
|
338762
338831
|
});
|
|
338763
|
-
|
|
338832
|
+
log84.info("per_thread session initialized", { instanceId, sessionId });
|
|
338764
338833
|
}
|
|
338765
338834
|
function mimeToContentType(mimeType) {
|
|
338766
338835
|
if (mimeType.startsWith("audio/"))
|
|
@@ -338799,7 +338868,7 @@ async function processMediaFile(msg, mimeType, mediaService) {
|
|
|
338799
338868
|
const result = await mediaService.process(localPath, mimeType, { caption: msg.content.caption });
|
|
338800
338869
|
return result.success && result.content ? result.content : null;
|
|
338801
338870
|
} catch (err) {
|
|
338802
|
-
|
|
338871
|
+
log84.debug("Media processing failed for history message", { error: String(err), messageId: msg.externalId });
|
|
338803
338872
|
return null;
|
|
338804
338873
|
} finally {
|
|
338805
338874
|
if (ownedTempFile) {
|
|
@@ -338836,7 +338905,7 @@ async function processHistoryMessage2(msg, mediaService, reactFn, unreactFn) {
|
|
|
338836
338905
|
async function fetchAndProcessThreadHistory(services, instance4, channel4, chatId, threadId2) {
|
|
338837
338906
|
const plugin6 = await getPlugin(channel4);
|
|
338838
338907
|
if (!plugin6?.fetchHistory) {
|
|
338839
|
-
|
|
338908
|
+
log84.debug("Channel plugin does not support fetchHistory", { instanceId: instance4.id, channel: channel4 });
|
|
338840
338909
|
return [];
|
|
338841
338910
|
}
|
|
338842
338911
|
let historyResult;
|
|
@@ -338847,7 +338916,7 @@ async function fetchAndProcessThreadHistory(services, instance4, channel4, chatI
|
|
|
338847
338916
|
limit: 200
|
|
338848
338917
|
});
|
|
338849
338918
|
} catch (err) {
|
|
338850
|
-
|
|
338919
|
+
log84.warn("fetchHistory failed, proceeding without thread context", {
|
|
338851
338920
|
error: String(err),
|
|
338852
338921
|
instanceId: instance4.id,
|
|
338853
338922
|
channel: channel4
|
|
@@ -338877,7 +338946,7 @@ async function fetchAndProcessThreadHistory(services, instance4, channel4, chatI
|
|
|
338877
338946
|
const results = await Promise.all(batch.map((msg) => processHistoryMessage2(msg, mediaService, reactFn, unreactFn)));
|
|
338878
338947
|
contextMessages.push(...results);
|
|
338879
338948
|
}
|
|
338880
|
-
|
|
338949
|
+
log84.info("Thread history fetched", {
|
|
338881
338950
|
instanceId: instance4.id,
|
|
338882
338951
|
channel: channel4,
|
|
338883
338952
|
chatId,
|
|
@@ -338888,7 +338957,7 @@ async function fetchAndProcessThreadHistory(services, instance4, channel4, chatI
|
|
|
338888
338957
|
return contextMessages;
|
|
338889
338958
|
}
|
|
338890
338959
|
async function handlePerThreadLazyInit(services, instance4, channel4, chatId, threadId2, sessionId, db2) {
|
|
338891
|
-
|
|
338960
|
+
log84.info("per_thread lazy init", {
|
|
338892
338961
|
instanceId: instance4.id,
|
|
338893
338962
|
channel: channel4,
|
|
338894
338963
|
chatId,
|
|
@@ -338899,7 +338968,7 @@ async function handlePerThreadLazyInit(services, instance4, channel4, chatId, th
|
|
|
338899
338968
|
try {
|
|
338900
338969
|
await markPerThreadSessionInitialized(db2, instance4.id, sessionId);
|
|
338901
338970
|
} catch (err) {
|
|
338902
|
-
|
|
338971
|
+
log84.warn("Failed to mark per_thread session initialized", {
|
|
338903
338972
|
error: String(err),
|
|
338904
338973
|
instanceId: instance4.id,
|
|
338905
338974
|
sessionId
|
|
@@ -338941,7 +339010,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
338941
339010
|
const ackHandle = startAck(plugin6, ackProvider, instance4.id, chatId, messageId, channel4, ackConfig);
|
|
338942
339011
|
const personId = await resolvePersonId(services, channel4, instance4.id, senderId, firstMessage.metadata.personId);
|
|
338943
339012
|
if (!personId) {
|
|
338944
|
-
|
|
339013
|
+
log84.warn("Could not resolve person ID, skipping agent", {
|
|
338945
339014
|
instanceId: instance4.id,
|
|
338946
339015
|
chatId,
|
|
338947
339016
|
senderId
|
|
@@ -338954,7 +339023,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
338954
339023
|
const pushName = rawPayload.pushName ?? rawPayload.displayName;
|
|
338955
339024
|
const senderName = await services.agentRunner.getSenderName(personId, pushName);
|
|
338956
339025
|
const senderAgentId = await resolveDispatchSenderAgentId(db2, instance4);
|
|
338957
|
-
|
|
339026
|
+
log84.info("Dispatching to agent", {
|
|
338958
339027
|
instanceId: instance4.id,
|
|
338959
339028
|
chatId,
|
|
338960
339029
|
messageCount: messages4.length,
|
|
@@ -338967,7 +339036,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
338967
339036
|
const agentAckMessage = inst.agentAckMessage ?? null;
|
|
338968
339037
|
if (agentAckMessage) {
|
|
338969
339038
|
sendTextMessage5(channel4, instance4.id, chatId, agentAckMessage).catch((err) => {
|
|
338970
|
-
|
|
339039
|
+
log84.warn("Failed to send agent ack message", { instanceId: instance4.id, chatId, error: String(err) });
|
|
338971
339040
|
});
|
|
338972
339041
|
}
|
|
338973
339042
|
const perThreadExtraContext = await resolvePerThreadExtraContext(db2, services, instance4, channel4, chatId, senderId, firstMessage);
|
|
@@ -338980,7 +339049,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
338980
339049
|
handled = await dispatchViaProvider(services, instance4, messages4, triggerType, channel4, chatId, senderId, personId, senderName, traceId, rawEvent, db2, perThreadExtraContext, senderAgentId);
|
|
338981
339050
|
}
|
|
338982
339051
|
} catch (providerError) {
|
|
338983
|
-
|
|
339052
|
+
log84.error("Provider dispatch failed, falling back to legacy", {
|
|
338984
339053
|
instanceId: instance4.id,
|
|
338985
339054
|
chatId,
|
|
338986
339055
|
error: String(providerError),
|
|
@@ -338991,12 +339060,12 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
|
|
|
338991
339060
|
ackHandle.remove();
|
|
338992
339061
|
return;
|
|
338993
339062
|
}
|
|
338994
|
-
|
|
339063
|
+
log84.debug("No IAgentProvider resolved or provider failed, using legacy agentRunner path", {
|
|
338995
339064
|
instanceId: instance4.id
|
|
338996
339065
|
});
|
|
338997
339066
|
await dispatchViaLegacy(services, instance4, messages4, triggerType, channel4, chatId, senderId, personId, senderName, traceId, perThreadExtraContext, senderAgentId);
|
|
338998
339067
|
} catch (error2) {
|
|
338999
|
-
|
|
339068
|
+
log84.error("Failed to process agent response", {
|
|
339000
339069
|
instanceId: instance4.id,
|
|
339001
339070
|
chatId,
|
|
339002
339071
|
error: String(error2),
|
|
@@ -339040,7 +339109,7 @@ function createOpenClawProviderInstance(provider, instance4) {
|
|
|
339040
339109
|
}
|
|
339041
339110
|
function createAgnoProvider(provider, instance4) {
|
|
339042
339111
|
if (!provider.apiKey) {
|
|
339043
|
-
|
|
339112
|
+
log84.warn("Provider has no API key, falling back to legacy path", { providerId: provider.id });
|
|
339044
339113
|
return null;
|
|
339045
339114
|
}
|
|
339046
339115
|
const client = createProviderClient({
|
|
@@ -339062,7 +339131,7 @@ function createClaudeCodeProviderInstance(provider, instance4, db2) {
|
|
|
339062
339131
|
const schemaConfig = provider.schemaConfig ?? {};
|
|
339063
339132
|
const projectPath = schemaConfig.projectPath;
|
|
339064
339133
|
if (!projectPath) {
|
|
339065
|
-
|
|
339134
|
+
log84.error("Claude Code provider missing projectPath", { providerId: provider.id });
|
|
339066
339135
|
throw new Error("Claude Code provider requires schemaConfig.projectPath");
|
|
339067
339136
|
}
|
|
339068
339137
|
return new ClaudeCodeAgentProvider(provider.id, provider.name, {
|
|
@@ -339093,7 +339162,7 @@ function createWebhookProvider(provider) {
|
|
|
339093
339162
|
}
|
|
339094
339163
|
function createAgUiProviderInstance(provider, instance4) {
|
|
339095
339164
|
if (!provider.apiKey) {
|
|
339096
|
-
|
|
339165
|
+
log84.warn("AG-UI provider has no API key, falling back to legacy path", { providerId: provider.id });
|
|
339097
339166
|
return null;
|
|
339098
339167
|
}
|
|
339099
339168
|
const schemaConfig = provider.schemaConfig ?? {};
|
|
@@ -339112,7 +339181,7 @@ function createAgUiProviderInstance(provider, instance4) {
|
|
|
339112
339181
|
}
|
|
339113
339182
|
function createA2AProviderInstance(provider, instance4) {
|
|
339114
339183
|
if (!provider.apiKey) {
|
|
339115
|
-
|
|
339184
|
+
log84.warn("A2A provider has no API key, falling back to legacy path", { providerId: provider.id });
|
|
339116
339185
|
return null;
|
|
339117
339186
|
}
|
|
339118
339187
|
const schemaConfig = provider.schemaConfig ?? {};
|
|
@@ -339134,12 +339203,13 @@ function createGenieProviderInstance(provider, instance4) {
|
|
|
339134
339203
|
const agentName = typeof schemaConfig.agentName === "string" ? schemaConfig.agentName : "";
|
|
339135
339204
|
const targetAgent = typeof schemaConfig.targetAgent === "string" ? schemaConfig.targetAgent : "";
|
|
339136
339205
|
if (!agentName || !targetAgent) {
|
|
339137
|
-
|
|
339206
|
+
log84.error("Genie provider missing agentName or targetAgent in schemaConfig", { providerId: provider.id });
|
|
339138
339207
|
return null;
|
|
339139
339208
|
}
|
|
339140
339209
|
const teamName = typeof schemaConfig.teamName === "string" ? schemaConfig.teamName : "genie";
|
|
339141
339210
|
const agentRole = typeof schemaConfig.agentRole === "string" ? schemaConfig.agentRole : "team-lead";
|
|
339142
|
-
const
|
|
339211
|
+
const autoSpawnDir = typeof schemaConfig.autoSpawnDir === "string" ? schemaConfig.autoSpawnDir : undefined;
|
|
339212
|
+
const client = createGenieClient({ teamName, agentName, targetAgent, agentRole, autoSpawnDir });
|
|
339143
339213
|
return new GenieAgentProvider(provider.id, provider.name, client, {
|
|
339144
339214
|
prefixSenderName: instance4.agentPrefixSenderName ?? true
|
|
339145
339215
|
});
|
|
@@ -339173,7 +339243,7 @@ function resolveProvider(provider, instance4, db2) {
|
|
|
339173
339243
|
agentProvider = createGenieProviderInstance(provider, instance4);
|
|
339174
339244
|
break;
|
|
339175
339245
|
default:
|
|
339176
|
-
|
|
339246
|
+
log84.debug("Provider schema not supported for IAgentProvider dispatch", {
|
|
339177
339247
|
schema: provider.schema,
|
|
339178
339248
|
providerId: provider.id
|
|
339179
339249
|
});
|
|
@@ -339193,7 +339263,7 @@ async function getAgentProvider(services, instance4, db2) {
|
|
|
339193
339263
|
return null;
|
|
339194
339264
|
return resolveProvider(provider, instance4, db2);
|
|
339195
339265
|
} catch (error2) {
|
|
339196
|
-
|
|
339266
|
+
log84.warn("Failed to resolve agent provider, falling back to legacy", {
|
|
339197
339267
|
instanceId: instance4.id,
|
|
339198
339268
|
providerId: instance4.agentProviderId,
|
|
339199
339269
|
error: String(error2)
|
|
@@ -339227,7 +339297,7 @@ async function applyInstanceFkAndReturn(db2, instance4) {
|
|
|
339227
339297
|
}
|
|
339228
339298
|
async function resolveEffectiveInstance(services, db2, instance4, chatId, personId) {
|
|
339229
339299
|
if (!chatId) {
|
|
339230
|
-
|
|
339300
|
+
log84.debug("No internal chatId \u2014 using instance default agent", { instanceId: instance4.id, personId });
|
|
339231
339301
|
return applyInstanceFkAndReturn(db2, instance4);
|
|
339232
339302
|
}
|
|
339233
339303
|
const route = await services.routeResolver.resolve(instance4.id, chatId, personId);
|
|
@@ -339251,7 +339321,7 @@ async function resolveEffectiveInstance(services, db2, instance4, chatId, person
|
|
|
339251
339321
|
if (effectiveAgentFkId) {
|
|
339252
339322
|
await applyAgentFkOverrides(db2, effectiveAgentFkId, effectiveInstance);
|
|
339253
339323
|
}
|
|
339254
|
-
|
|
339324
|
+
log84.debug("Route resolved and merged", {
|
|
339255
339325
|
instanceId: instance4.id,
|
|
339256
339326
|
chatId,
|
|
339257
339327
|
personId,
|
|
@@ -339271,7 +339341,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
|
|
|
339271
339341
|
const chat2 = await services.chats.findByExternalIdSmart(baseInstance.id, externalChatId);
|
|
339272
339342
|
const internalChatId = chat2?.id;
|
|
339273
339343
|
const { instance: instance4, routeId: _routeId } = await resolveEffectiveInstance(services, db2, baseInstance, internalChatId, metadata.personId);
|
|
339274
|
-
|
|
339344
|
+
log84.info("Dispatching reaction trigger", {
|
|
339275
339345
|
instanceId: instance4.id,
|
|
339276
339346
|
chatId: externalChatId,
|
|
339277
339347
|
routeChatId: internalChatId ?? "none",
|
|
@@ -339311,7 +339381,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
|
|
|
339311
339381
|
const _fmtMode = instance4.messageFormatMode ?? "convert";
|
|
339312
339382
|
await sendResponseParts(channel4, instance4.id, externalChatId, result2.parts, getSplitDelayConfig(instance4), _fmtMode, payload.messageId);
|
|
339313
339383
|
}
|
|
339314
|
-
|
|
339384
|
+
log84.info("Reaction trigger response via provider", {
|
|
339315
339385
|
instanceId: instance4.id,
|
|
339316
339386
|
chatId: externalChatId,
|
|
339317
339387
|
routeChatId: internalChatId,
|
|
@@ -339323,7 +339393,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
|
|
|
339323
339393
|
});
|
|
339324
339394
|
return;
|
|
339325
339395
|
}
|
|
339326
|
-
|
|
339396
|
+
log84.debug("No IAgentProvider resolved, using legacy agentRunner path", {
|
|
339327
339397
|
instanceId: instance4.id
|
|
339328
339398
|
});
|
|
339329
339399
|
const personId = await resolvePersonId(services, channel4, instance4.id, payload.from, metadata.personId);
|
|
@@ -339349,7 +339419,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
|
|
|
339349
339419
|
const _fmtMode = instance4.messageFormatMode ?? "convert";
|
|
339350
339420
|
await sendResponseParts(channel4, instance4.id, externalChatId, result.parts, getSplitDelayConfig(instance4), _fmtMode, payload.messageId);
|
|
339351
339421
|
}
|
|
339352
|
-
|
|
339422
|
+
log84.info("Reaction trigger response via legacy runner", {
|
|
339353
339423
|
instanceId: instance4.id,
|
|
339354
339424
|
chatId: externalChatId,
|
|
339355
339425
|
routeChatId: internalChatId,
|
|
@@ -339358,7 +339428,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
|
|
|
339358
339428
|
traceId: metadata.traceId
|
|
339359
339429
|
});
|
|
339360
339430
|
} catch (error2) {
|
|
339361
|
-
|
|
339431
|
+
log84.error("Failed to process reaction trigger", {
|
|
339362
339432
|
instanceId: instance4.id,
|
|
339363
339433
|
chatId: externalChatId,
|
|
339364
339434
|
routeChatId: internalChatId,
|
|
@@ -339400,7 +339470,7 @@ async function resolveLidMentionBot(chatsService, instanceId, ownerIdentifier, m
|
|
|
339400
339470
|
for (const lidJid of lidMentions) {
|
|
339401
339471
|
if (ownerIsLid && extractPhoneFromJid(lidJid) === ownerPhone) {
|
|
339402
339472
|
messageContext.mentionsBot = true;
|
|
339403
|
-
|
|
339473
|
+
log84.debug("LID mention matches owner LID directly", { lidJid, ownerIdentifier });
|
|
339404
339474
|
break;
|
|
339405
339475
|
}
|
|
339406
339476
|
try {
|
|
@@ -339409,14 +339479,14 @@ async function resolveLidMentionBot(chatsService, instanceId, ownerIdentifier, m
|
|
|
339409
339479
|
const resolvedPhone = extractPhoneFromJid(mapping);
|
|
339410
339480
|
if (resolvedPhone === ownerPhone) {
|
|
339411
339481
|
messageContext.mentionsBot = true;
|
|
339412
|
-
|
|
339482
|
+
log84.debug("LID resolved to instance owner via DB", { lidJid, resolvedPhone, ownerPhone });
|
|
339413
339483
|
break;
|
|
339414
339484
|
}
|
|
339415
339485
|
if (ownerIsLid) {
|
|
339416
339486
|
const ownerMapping = await chatsService.findLidMapping(instanceId, ownerIdentifier);
|
|
339417
339487
|
if (ownerMapping && extractPhoneFromJid(ownerMapping) === resolvedPhone) {
|
|
339418
339488
|
messageContext.mentionsBot = true;
|
|
339419
|
-
|
|
339489
|
+
log84.debug("LID resolved to owner via reverse mapping", { lidJid, resolvedPhone, ownerIdentifier });
|
|
339420
339490
|
break;
|
|
339421
339491
|
}
|
|
339422
339492
|
}
|
|
@@ -339450,15 +339520,15 @@ function needsLidMentionCheck(messageContext, instance4) {
|
|
|
339450
339520
|
}
|
|
339451
339521
|
async function shouldProcessMessage3(agentRunner, accessService, chatsService, messagesService, routeResolver, rateLimiter, payload, metadata) {
|
|
339452
339522
|
if (!metadata.instanceId) {
|
|
339453
|
-
|
|
339523
|
+
log84.debug("No instanceId in metadata", { from: payload.from, chatId: payload.chatId });
|
|
339454
339524
|
return null;
|
|
339455
339525
|
}
|
|
339456
339526
|
if (payload.from === metadata.platformIdentityId) {
|
|
339457
|
-
|
|
339527
|
+
log84.debug("Message from self, skipping", { instanceId: metadata.instanceId, from: payload.from });
|
|
339458
339528
|
return null;
|
|
339459
339529
|
}
|
|
339460
339530
|
if (isTrashEmojiOnly(payload.content?.text)) {
|
|
339461
|
-
|
|
339531
|
+
log84.debug("Skipping trash emoji message (session-cleaner handles this)", {
|
|
339462
339532
|
instanceId: metadata.instanceId,
|
|
339463
339533
|
chatId: payload.chatId
|
|
339464
339534
|
});
|
|
@@ -339466,16 +339536,16 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
|
|
|
339466
339536
|
}
|
|
339467
339537
|
const chatId = payload.chatId ?? "";
|
|
339468
339538
|
if (isBroadcastOrNewsletter(chatId)) {
|
|
339469
|
-
|
|
339539
|
+
log84.debug("Skipping newsletter/broadcast message", { instanceId: metadata.instanceId, chatId });
|
|
339470
339540
|
return null;
|
|
339471
339541
|
}
|
|
339472
339542
|
const instance4 = await agentRunner.getInstanceWithProvider(metadata.instanceId);
|
|
339473
339543
|
if (!instance4?.agentId) {
|
|
339474
|
-
|
|
339544
|
+
log84.debug("Instance has no agentId", { instanceId: metadata.instanceId });
|
|
339475
339545
|
return null;
|
|
339476
339546
|
}
|
|
339477
339547
|
if (!instanceTriggersOnEvent(instance4, "message.received")) {
|
|
339478
|
-
|
|
339548
|
+
log84.debug("Instance does not trigger on message.received", { instanceId: instance4.id });
|
|
339479
339549
|
return null;
|
|
339480
339550
|
}
|
|
339481
339551
|
const messageContext = buildMessageContext(payload, instance4);
|
|
@@ -339485,7 +339555,7 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
|
|
|
339485
339555
|
await resolveLidMentionBot(chatsService, metadata.instanceId, instance4.ownerIdentifier, mentionedJids, messageContext);
|
|
339486
339556
|
}
|
|
339487
339557
|
await resolveSlackThreadReply(chatsService, messagesService, instance4, payload, messageContext);
|
|
339488
|
-
|
|
339558
|
+
log84.debug("Message context built", {
|
|
339489
339559
|
instanceId: instance4.id,
|
|
339490
339560
|
chatId: payload.chatId,
|
|
339491
339561
|
isDirectMessage: messageContext.isDirectMessage,
|
|
@@ -339495,7 +339565,7 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
|
|
|
339495
339565
|
});
|
|
339496
339566
|
const effectiveReplyFilter = await resolveEffectiveReplyFilter(chatsService, routeResolver, instance4.id, payload.chatId, instance4.agentReplyFilter);
|
|
339497
339567
|
if (!shouldAgentReply(effectiveReplyFilter, messageContext)) {
|
|
339498
|
-
|
|
339568
|
+
log84.debug("Message did not pass reply filter", {
|
|
339499
339569
|
instanceId: instance4.id,
|
|
339500
339570
|
chatId: payload.chatId,
|
|
339501
339571
|
messageContext,
|
|
@@ -339506,7 +339576,7 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
|
|
|
339506
339576
|
const channel4 = metadata.channelType ?? "whatsapp";
|
|
339507
339577
|
const rateLimit = instance4.triggerRateLimit;
|
|
339508
339578
|
if (!rateLimiter.isAllowed(payload.from, channel4, instance4.id, rateLimit ?? DEFAULT_RATE_LIMIT)) {
|
|
339509
|
-
|
|
339579
|
+
log84.info("Rate limited", { instanceId: instance4.id, from: payload.from, channel: channel4 });
|
|
339510
339580
|
return null;
|
|
339511
339581
|
}
|
|
339512
339582
|
const accessDenied = await checkAccessWithFallback(accessService, instance4, payload, channel4);
|
|
@@ -339524,7 +339594,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
|
|
|
339524
339594
|
const primaryId = payload.from ?? "";
|
|
339525
339595
|
let accessResult = await accessService.checkAccess(instance4, primaryId, channel4);
|
|
339526
339596
|
if (!accessResult.allowed && participantAlt && participantAlt !== primaryId) {
|
|
339527
|
-
|
|
339597
|
+
log84.warn("Access fallback to participantAlt", {
|
|
339528
339598
|
instanceId: instance4.id,
|
|
339529
339599
|
primaryId,
|
|
339530
339600
|
participantAlt,
|
|
@@ -339533,7 +339603,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
|
|
|
339533
339603
|
accessResult = await accessService.checkAccess(instance4, participantAlt, channel4);
|
|
339534
339604
|
}
|
|
339535
339605
|
if (!accessResult.allowed && resolvedSenderPhone && resolvedSenderPhone !== primaryId && resolvedSenderPhone !== participantAlt) {
|
|
339536
|
-
|
|
339606
|
+
log84.debug("Access fallback to resolvedSenderPhone (LID\u2192phone)", {
|
|
339537
339607
|
instanceId: instance4.id,
|
|
339538
339608
|
primaryId,
|
|
339539
339609
|
resolvedSenderPhone,
|
|
@@ -339543,7 +339613,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
|
|
|
339543
339613
|
}
|
|
339544
339614
|
if (accessResult.allowed)
|
|
339545
339615
|
return false;
|
|
339546
|
-
|
|
339616
|
+
log84.info("Access denied", {
|
|
339547
339617
|
instanceId: instance4.id,
|
|
339548
339618
|
chatId: payload.chatId,
|
|
339549
339619
|
from: payload.from,
|
|
@@ -339552,7 +339622,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
|
|
|
339552
339622
|
});
|
|
339553
339623
|
if (accessResult.mode === "allowlist" && !accessResult.rule && primaryId) {
|
|
339554
339624
|
accessService.requestPairing(instance4.id, primaryId).catch((err) => {
|
|
339555
|
-
|
|
339625
|
+
log84.warn("Failed to create pairing request", { instanceId: instance4.id, from: primaryId, error: String(err) });
|
|
339556
339626
|
});
|
|
339557
339627
|
}
|
|
339558
339628
|
if (accessResult.rule?.action !== "silent_block" && accessResult.rule?.blockMessage) {
|
|
@@ -339569,20 +339639,20 @@ async function shouldProcessReaction(agentRunner, accessService, rateLimiter, re
|
|
|
339569
339639
|
if (!instanceTriggersOnEvent(instance4, eventType))
|
|
339570
339640
|
return null;
|
|
339571
339641
|
if (!isReactionTrigger(instance4, payload.emoji)) {
|
|
339572
|
-
|
|
339642
|
+
log84.debug("Reaction emoji not in trigger list", { instanceId: instance4.id, emoji: payload.emoji });
|
|
339573
339643
|
return null;
|
|
339574
339644
|
}
|
|
339575
339645
|
const channel4 = metadata.channelType ?? "whatsapp";
|
|
339576
339646
|
const rateLimit = instance4.triggerRateLimit;
|
|
339577
339647
|
if (!rateLimiter.isAllowed(payload.from, channel4, instance4.id, rateLimit ?? DEFAULT_RATE_LIMIT)) {
|
|
339578
|
-
|
|
339648
|
+
log84.info("Rate limited reaction trigger", { instanceId: instance4.id, from: payload.from });
|
|
339579
339649
|
return null;
|
|
339580
339650
|
}
|
|
339581
339651
|
const accessDenied = await checkAccessWithFallback(accessService, instance4, payload, channel4);
|
|
339582
339652
|
if (accessDenied)
|
|
339583
339653
|
return null;
|
|
339584
339654
|
if (reactionDedup.isDuplicate(payload.messageId, payload.emoji, payload.from)) {
|
|
339585
|
-
|
|
339655
|
+
log84.debug("Duplicate reaction, skipping", {
|
|
339586
339656
|
instanceId: instance4.id,
|
|
339587
339657
|
messageId: payload.messageId,
|
|
339588
339658
|
emoji: payload.emoji
|
|
@@ -339615,7 +339685,7 @@ async function shouldRespondViaGate(instance4, messages4, chatType, settings) {
|
|
|
339615
339685
|
try {
|
|
339616
339686
|
const apiKey = await settings.getSecret("gemini.api_key", "GEMINI_API_KEY");
|
|
339617
339687
|
if (!apiKey) {
|
|
339618
|
-
|
|
339688
|
+
log84.warn("Gate: no Gemini API key, fail-open", { traceId });
|
|
339619
339689
|
return true;
|
|
339620
339690
|
}
|
|
339621
339691
|
const controller = new AbortController;
|
|
@@ -339633,13 +339703,13 @@ async function shouldRespondViaGate(instance4, messages4, chatType, settings) {
|
|
|
339633
339703
|
});
|
|
339634
339704
|
clearTimeout(timeout);
|
|
339635
339705
|
if (!res.ok) {
|
|
339636
|
-
|
|
339706
|
+
log84.warn("Gate: API error, fail-open", { traceId, status: res.status, durationMs: Date.now() - startMs });
|
|
339637
339707
|
return true;
|
|
339638
339708
|
}
|
|
339639
339709
|
const data = await res.json();
|
|
339640
339710
|
const answer = data.candidates?.[0]?.content?.parts?.[0]?.text?.trim().toLowerCase() ?? "";
|
|
339641
339711
|
const shouldRespond = !answer.startsWith("skip");
|
|
339642
|
-
|
|
339712
|
+
log84.info("Gate decision", {
|
|
339643
339713
|
traceId,
|
|
339644
339714
|
decision: shouldRespond ? "respond" : "skip",
|
|
339645
339715
|
rawAnswer: answer,
|
|
@@ -339653,14 +339723,14 @@ async function shouldRespondViaGate(instance4, messages4, chatType, settings) {
|
|
|
339653
339723
|
clearTimeout(timeout);
|
|
339654
339724
|
const errName = fetchError.name;
|
|
339655
339725
|
if (errName === "AbortError") {
|
|
339656
|
-
|
|
339726
|
+
log84.warn("Gate: timeout, fail-open", { traceId, durationMs: Date.now() - startMs });
|
|
339657
339727
|
} else {
|
|
339658
|
-
|
|
339728
|
+
log84.warn("Gate: fetch error, fail-open", { traceId, error: String(fetchError) });
|
|
339659
339729
|
}
|
|
339660
339730
|
return true;
|
|
339661
339731
|
}
|
|
339662
339732
|
} catch (error2) {
|
|
339663
|
-
|
|
339733
|
+
log84.warn("Gate: unexpected error, fail-open", { traceId, error: String(error2) });
|
|
339664
339734
|
return true;
|
|
339665
339735
|
}
|
|
339666
339736
|
}
|
|
@@ -339670,7 +339740,7 @@ async function shouldSkipViaGate(triggerType, firstMsg, instance4, messages4, se
|
|
|
339670
339740
|
const chatType = determineChatType(firstMsg.payload.chatId, firstMsg.metadata.channelType ?? "whatsapp", firstMsg.payload.rawPayload ?? {});
|
|
339671
339741
|
const shouldRespond = await shouldRespondViaGate(instance4, messages4, chatType, services.settings);
|
|
339672
339742
|
if (!shouldRespond) {
|
|
339673
|
-
|
|
339743
|
+
log84.info("Gate skipped response", {
|
|
339674
339744
|
instanceId: instance4.id,
|
|
339675
339745
|
chatId: firstMsg.payload.chatId,
|
|
339676
339746
|
triggerType,
|
|
@@ -339693,7 +339763,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
339693
339763
|
const instanceId = firstMsg.metadata.instanceId;
|
|
339694
339764
|
const baseInstance = await agentRunner.getInstanceWithProvider(instanceId);
|
|
339695
339765
|
if (!baseInstance) {
|
|
339696
|
-
|
|
339766
|
+
log84.warn("Instance not found for debounced messages", { instanceId });
|
|
339697
339767
|
return;
|
|
339698
339768
|
}
|
|
339699
339769
|
const externalChatId = firstMsg.payload.chatId;
|
|
@@ -339741,7 +339811,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
339741
339811
|
timestamp: event.timestamp
|
|
339742
339812
|
}, effectiveDebounceConfig);
|
|
339743
339813
|
} catch (error2) {
|
|
339744
|
-
|
|
339814
|
+
log84.error("Error processing message for dispatch", {
|
|
339745
339815
|
instanceId: metadata.instanceId,
|
|
339746
339816
|
error: String(error2)
|
|
339747
339817
|
});
|
|
@@ -339770,7 +339840,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
339770
339840
|
traceId
|
|
339771
339841
|
}, event, db2);
|
|
339772
339842
|
} catch (error2) {
|
|
339773
|
-
|
|
339843
|
+
log84.error("Error processing reaction for dispatch", {
|
|
339774
339844
|
instanceId: metadata.instanceId,
|
|
339775
339845
|
error: String(error2)
|
|
339776
339846
|
});
|
|
@@ -339799,7 +339869,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
339799
339869
|
traceId
|
|
339800
339870
|
}, event, db2);
|
|
339801
339871
|
} catch (error2) {
|
|
339802
|
-
|
|
339872
|
+
log84.error("Error processing reaction removal for dispatch", {
|
|
339803
339873
|
instanceId: metadata.instanceId,
|
|
339804
339874
|
error: String(error2)
|
|
339805
339875
|
});
|
|
@@ -339826,7 +339896,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
339826
339896
|
debouncer.onUserTyping(metadata.instanceId, payload.chatId, debounceConfig);
|
|
339827
339897
|
}
|
|
339828
339898
|
} catch (error2) {
|
|
339829
|
-
|
|
339899
|
+
log84.debug("Error handling typing event", { error: String(error2) });
|
|
339830
339900
|
}
|
|
339831
339901
|
}, {
|
|
339832
339902
|
durable: "agent-dispatcher-typing",
|
|
@@ -339835,22 +339905,22 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
339835
339905
|
startFrom: "last",
|
|
339836
339906
|
concurrency: 10
|
|
339837
339907
|
});
|
|
339838
|
-
|
|
339908
|
+
log84.info("Agent dispatcher initialized (message + reaction + reaction-removed triggers)");
|
|
339839
339909
|
} catch (error2) {
|
|
339840
|
-
|
|
339910
|
+
log84.error("Failed to set up agent dispatcher", { error: String(error2) });
|
|
339841
339911
|
clearInterval(cleanupInterval2);
|
|
339842
339912
|
debouncer.clear();
|
|
339843
339913
|
throw error2;
|
|
339844
339914
|
}
|
|
339845
339915
|
return async () => {
|
|
339846
|
-
|
|
339916
|
+
log84.info("Shutting down agent dispatcher");
|
|
339847
339917
|
clearInterval(cleanupInterval2);
|
|
339848
339918
|
debouncer.clear();
|
|
339849
339919
|
const disposePromises = [];
|
|
339850
339920
|
for (const [key, provider] of providerCache.entries()) {
|
|
339851
339921
|
if (provider.dispose) {
|
|
339852
339922
|
disposePromises.push(provider.dispose().catch((err) => {
|
|
339853
|
-
|
|
339923
|
+
log84.warn("Error disposing provider", { key, error: String(err) });
|
|
339854
339924
|
}));
|
|
339855
339925
|
}
|
|
339856
339926
|
}
|
|
@@ -339860,7 +339930,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
339860
339930
|
try {
|
|
339861
339931
|
client.stop();
|
|
339862
339932
|
} catch (err) {
|
|
339863
|
-
|
|
339933
|
+
log84.warn("Error stopping OpenClaw client", { providerId: id, error: String(err) });
|
|
339864
339934
|
}
|
|
339865
339935
|
}));
|
|
339866
339936
|
}
|
|
@@ -339868,7 +339938,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
339868
339938
|
let timeoutId;
|
|
339869
339939
|
const timeoutGuard = new Promise((resolve3) => {
|
|
339870
339940
|
timeoutId = setTimeout(() => {
|
|
339871
|
-
|
|
339941
|
+
log84.warn("Dispatcher shutdown timed out after 5s, proceeding");
|
|
339872
339942
|
resolve3([]);
|
|
339873
339943
|
}, 5000);
|
|
339874
339944
|
});
|
|
@@ -339881,10 +339951,10 @@ async function setupAgentDispatcher(eventBus, services, db2) {
|
|
|
339881
339951
|
}
|
|
339882
339952
|
providerCache.clear();
|
|
339883
339953
|
openclawClientPool.clear();
|
|
339884
|
-
|
|
339954
|
+
log84.info("Agent dispatcher shutdown complete");
|
|
339885
339955
|
};
|
|
339886
339956
|
}
|
|
339887
|
-
var
|
|
339957
|
+
var log84, QUOTED_MESSAGE_MAX_CHARS = 4000, DM_HISTORY_LIMIT = 20, DEFAULT_RATE_LIMIT = 5, DEFAULT_RATE_WINDOW_MS = 60000, CHANNEL_MESSAGE_LIMITS, DEFAULT_MESSAGE_LIMIT = 4000, MEDIA_BASE_PATH3, MEDIA_ICONS, MEDIA_WAIT_NULL, DEFAULT_SEND_MEDIA_PATH_TYPES, BOT_PREFIX = "\uD83E\uDD16 ", activeStreams, sessionActivityStore, PROC_REACT_START, PROC_REACT_DONE = "\u2705", providerCache, openclawClientPool, DEFAULT_GATE_MODEL = "gemini-3-flash-preview", GATE_TIMEOUT_MS = 3000, setupAgentResponder;
|
|
339888
339958
|
var init_agent_dispatcher = __esm(() => {
|
|
339889
339959
|
init_src2();
|
|
339890
339960
|
init_src();
|
|
@@ -339895,9 +339965,10 @@ var init_agent_dispatcher = __esm(() => {
|
|
|
339895
339965
|
init_sentry_scrub();
|
|
339896
339966
|
init_agent_runner();
|
|
339897
339967
|
init_loader2();
|
|
339968
|
+
init_message_debouncer();
|
|
339898
339969
|
init_session_storage();
|
|
339899
339970
|
init_src6();
|
|
339900
|
-
|
|
339971
|
+
log84 = createLogger("agent-dispatcher");
|
|
339901
339972
|
CHANNEL_MESSAGE_LIMITS = {
|
|
339902
339973
|
discord: 2000,
|
|
339903
339974
|
"whatsapp-baileys": 65536,
|
|
@@ -339967,7 +340038,7 @@ async function setupSyncWorker(eventBus, services, channelRegistry2, database) {
|
|
|
339967
340038
|
await eventBus.subscribe("sync.started", async (event) => {
|
|
339968
340039
|
const payload = event.payload;
|
|
339969
340040
|
const { jobId, instanceId, type, config: config4 } = payload;
|
|
339970
|
-
|
|
340041
|
+
log85.info("Processing sync job", { jobId, instanceId, type });
|
|
339971
340042
|
try {
|
|
339972
340043
|
await services.syncJobs.start(jobId);
|
|
339973
340044
|
const instance4 = await services.instances.getById(instanceId);
|
|
@@ -339994,12 +340065,12 @@ async function setupSyncWorker(eventBus, services, channelRegistry2, database) {
|
|
|
339994
340065
|
case "history-push":
|
|
339995
340066
|
break;
|
|
339996
340067
|
default:
|
|
339997
|
-
|
|
340068
|
+
log85.warn("Unknown sync type", { jobId, type });
|
|
339998
340069
|
await services.syncJobs.fail(jobId, `Unknown sync type: ${type}`);
|
|
339999
340070
|
}
|
|
340000
340071
|
} catch (error2) {
|
|
340001
340072
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
340002
|
-
|
|
340073
|
+
log85.error("Sync job failed", { jobId, error: errorMessage });
|
|
340003
340074
|
await services.syncJobs.fail(jobId, errorMessage);
|
|
340004
340075
|
}
|
|
340005
340076
|
}, {
|
|
@@ -340007,15 +340078,15 @@ async function setupSyncWorker(eventBus, services, channelRegistry2, database) {
|
|
|
340007
340078
|
queue: "sync-workers",
|
|
340008
340079
|
startFrom: "new"
|
|
340009
340080
|
});
|
|
340010
|
-
|
|
340081
|
+
log85.info("Sync worker initialized - listening for sync.started events");
|
|
340011
340082
|
} catch (error2) {
|
|
340012
|
-
|
|
340083
|
+
log85.error("Failed to set up sync worker", { error: String(error2) });
|
|
340013
340084
|
throw error2;
|
|
340014
340085
|
}
|
|
340015
340086
|
}
|
|
340016
340087
|
async function buildWhatsAppAnchors(instanceId, _services) {
|
|
340017
340088
|
if (!db2) {
|
|
340018
|
-
|
|
340089
|
+
log85.warn("Database not available for building anchors");
|
|
340019
340090
|
return [];
|
|
340020
340091
|
}
|
|
340021
340092
|
const result = await db2.execute(sql`
|
|
@@ -340051,20 +340122,20 @@ async function buildWhatsAppAnchors(instanceId, _services) {
|
|
|
340051
340122
|
});
|
|
340052
340123
|
}
|
|
340053
340124
|
}
|
|
340054
|
-
|
|
340125
|
+
log85.info("Built WhatsApp anchors", { instanceId, anchorCount: anchors.length });
|
|
340055
340126
|
return anchors;
|
|
340056
340127
|
}
|
|
340057
340128
|
function buildAnchorsForExplicitChatJids(jobId, chatJids, dbAnchors) {
|
|
340058
|
-
|
|
340129
|
+
log85.info("Using explicit chatJids for sync", { jobId, chatJids });
|
|
340059
340130
|
const anchors = [];
|
|
340060
340131
|
for (const jid of chatJids) {
|
|
340061
340132
|
const dbAnchor = dbAnchors.find((a3) => a3.chatJid === jid);
|
|
340062
340133
|
if (dbAnchor) {
|
|
340063
|
-
|
|
340134
|
+
log85.debug("Found DB anchor for chatJid", { jobId, chatJid: jid, anchorId: dbAnchor.messageKey.id });
|
|
340064
340135
|
anchors.push(dbAnchor);
|
|
340065
340136
|
continue;
|
|
340066
340137
|
}
|
|
340067
|
-
|
|
340138
|
+
log85.debug("No DB anchor for chatJid, will fetch recent", { jobId, chatJid: jid });
|
|
340068
340139
|
anchors.push({
|
|
340069
340140
|
chatJid: jid,
|
|
340070
340141
|
messageKey: { remoteJid: jid, id: "", fromMe: false },
|
|
@@ -340090,7 +340161,7 @@ async function discoverAnchorsFromPlugin(jobId, instanceId, plugin6, dbAnchors,
|
|
|
340090
340161
|
discovered.push({ chatJid: jid, messageKey: { remoteJid: jid, id: "", fromMe: false }, timestamp: Date.now() });
|
|
340091
340162
|
}
|
|
340092
340163
|
if (discovered.length > 0) {
|
|
340093
|
-
|
|
340164
|
+
log85.info("Discovered chats from DB + Baileys not in anchors", {
|
|
340094
340165
|
jobId,
|
|
340095
340166
|
discoveredCount: discovered.length,
|
|
340096
340167
|
fromDb: dbExternalIds.length,
|
|
@@ -340111,7 +340182,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
340111
340182
|
throw new Error(`No plugin found for channel type: ${channelType}`);
|
|
340112
340183
|
}
|
|
340113
340184
|
if (!("fetchHistory" in plugin6) || typeof plugin6.fetchHistory !== "function") {
|
|
340114
|
-
|
|
340185
|
+
log85.warn("Plugin does not support fetchHistory", { channelType });
|
|
340115
340186
|
await services.syncJobs.complete(jobId);
|
|
340116
340187
|
return;
|
|
340117
340188
|
}
|
|
@@ -340120,7 +340191,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
340120
340191
|
let fetched = 0;
|
|
340121
340192
|
let stored = 0;
|
|
340122
340193
|
let duplicates = 0;
|
|
340123
|
-
|
|
340194
|
+
log85.info("Starting message sync", {
|
|
340124
340195
|
jobId,
|
|
340125
340196
|
instanceId,
|
|
340126
340197
|
channelType,
|
|
@@ -340130,13 +340201,13 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
340130
340201
|
if (channelType === "whatsapp-baileys" && config4.chatJids?.length) {
|
|
340131
340202
|
const dbAnchors = await buildWhatsAppAnchors(instanceId, services);
|
|
340132
340203
|
anchors = await resolveWhatsAppAnchors(jobId, instanceId, config4, plugin6, dbAnchors, services);
|
|
340133
|
-
|
|
340204
|
+
log85.info("WhatsApp per-chat active sync", { jobId, anchorCount: anchors.length, chatJids: config4.chatJids });
|
|
340134
340205
|
} else if (channelType === "whatsapp-baileys") {
|
|
340135
340206
|
const dbAnchors = await buildWhatsAppAnchors(instanceId, services);
|
|
340136
340207
|
const discoveredAnchors = await discoverAnchorsFromPlugin(jobId, instanceId, plugin6, dbAnchors, services);
|
|
340137
340208
|
anchors = [...dbAnchors, ...discoveredAnchors];
|
|
340138
340209
|
if (anchors.length > 0) {
|
|
340139
|
-
|
|
340210
|
+
log85.info("WhatsApp default sync with DB+cache discovery", {
|
|
340140
340211
|
jobId,
|
|
340141
340212
|
instanceId,
|
|
340142
340213
|
dbAnchorCount: dbAnchors.length,
|
|
@@ -340144,7 +340215,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
340144
340215
|
totalAnchors: anchors.length
|
|
340145
340216
|
});
|
|
340146
340217
|
} else {
|
|
340147
|
-
|
|
340218
|
+
log85.info("WhatsApp passive sync (no prior data)", { jobId, instanceId });
|
|
340148
340219
|
}
|
|
340149
340220
|
}
|
|
340150
340221
|
const fetchOptions = {
|
|
@@ -340186,7 +340257,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
340186
340257
|
});
|
|
340187
340258
|
stored++;
|
|
340188
340259
|
} catch (error2) {
|
|
340189
|
-
|
|
340260
|
+
log85.warn("Failed to store synced message", {
|
|
340190
340261
|
externalId: msg.externalId,
|
|
340191
340262
|
error: String(error2)
|
|
340192
340263
|
});
|
|
@@ -340203,7 +340274,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
|
|
|
340203
340274
|
duplicates
|
|
340204
340275
|
});
|
|
340205
340276
|
await services.syncJobs.complete(jobId);
|
|
340206
|
-
|
|
340277
|
+
log85.info("Message sync completed", {
|
|
340207
340278
|
jobId,
|
|
340208
340279
|
fetched,
|
|
340209
340280
|
stored,
|
|
@@ -340250,14 +340321,14 @@ async function processContactsSync(jobId, instanceId, channelType, config4, serv
|
|
|
340250
340321
|
throw new Error(`No plugin found for channel type: ${channelType}`);
|
|
340251
340322
|
}
|
|
340252
340323
|
if (!("fetchContacts" in plugin6) || typeof plugin6.fetchContacts !== "function") {
|
|
340253
|
-
|
|
340324
|
+
log85.warn("Plugin does not support fetchContacts", { channelType });
|
|
340254
340325
|
await services.syncJobs.complete(jobId);
|
|
340255
340326
|
return;
|
|
340256
340327
|
}
|
|
340257
340328
|
let fetched = 0;
|
|
340258
340329
|
let stored = 0;
|
|
340259
340330
|
let linked = 0;
|
|
340260
|
-
|
|
340331
|
+
log85.info("Starting contacts sync", {
|
|
340261
340332
|
jobId,
|
|
340262
340333
|
instanceId,
|
|
340263
340334
|
channelType
|
|
@@ -340296,7 +340367,7 @@ async function processContactsSync(jobId, instanceId, channelType, config4, serv
|
|
|
340296
340367
|
await updateDmChatName(services, instanceId, c.platformUserId, c.name);
|
|
340297
340368
|
}
|
|
340298
340369
|
} catch (error2) {
|
|
340299
|
-
|
|
340370
|
+
log85.warn("Failed to store synced contact", {
|
|
340300
340371
|
platformUserId: c.platformUserId,
|
|
340301
340372
|
error: String(error2)
|
|
340302
340373
|
});
|
|
@@ -340313,7 +340384,7 @@ async function processContactsSync(jobId, instanceId, channelType, config4, serv
|
|
|
340313
340384
|
duplicates: 0
|
|
340314
340385
|
});
|
|
340315
340386
|
await services.syncJobs.complete(jobId);
|
|
340316
|
-
|
|
340387
|
+
log85.info("Contacts sync completed", {
|
|
340317
340388
|
jobId,
|
|
340318
340389
|
fetched,
|
|
340319
340390
|
stored,
|
|
@@ -340327,7 +340398,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
|
|
|
340327
340398
|
}
|
|
340328
340399
|
const fetchMethod = channelType === "discord" ? "fetchGuilds" : "fetchGroups";
|
|
340329
340400
|
if (!(fetchMethod in plugin6) || typeof plugin6[fetchMethod] !== "function") {
|
|
340330
|
-
|
|
340401
|
+
log85.warn(`Plugin does not support ${fetchMethod}`, { channelType });
|
|
340331
340402
|
await services.syncJobs.complete(jobId);
|
|
340332
340403
|
return;
|
|
340333
340404
|
}
|
|
@@ -340338,7 +340409,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
|
|
|
340338
340409
|
let fetched = 0;
|
|
340339
340410
|
let stored = 0;
|
|
340340
340411
|
let updated = 0;
|
|
340341
|
-
|
|
340412
|
+
log85.info("Starting groups sync", {
|
|
340342
340413
|
jobId,
|
|
340343
340414
|
instanceId,
|
|
340344
340415
|
channelType
|
|
@@ -340388,7 +340459,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
|
|
|
340388
340459
|
stored++;
|
|
340389
340460
|
}
|
|
340390
340461
|
} catch (error2) {
|
|
340391
|
-
|
|
340462
|
+
log85.warn("Failed to store synced group", {
|
|
340392
340463
|
externalId: g2.externalId,
|
|
340393
340464
|
error: String(error2)
|
|
340394
340465
|
});
|
|
@@ -340429,7 +340500,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
|
|
|
340429
340500
|
stored++;
|
|
340430
340501
|
}
|
|
340431
340502
|
} catch (error2) {
|
|
340432
|
-
|
|
340503
|
+
log85.warn("Failed to store synced guild", {
|
|
340433
340504
|
externalId: g2.externalId,
|
|
340434
340505
|
error: String(error2)
|
|
340435
340506
|
});
|
|
@@ -340444,7 +340515,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
|
|
|
340444
340515
|
duplicates: updated
|
|
340445
340516
|
});
|
|
340446
340517
|
await services.syncJobs.complete(jobId);
|
|
340447
|
-
|
|
340518
|
+
log85.info("Groups sync completed", {
|
|
340448
340519
|
jobId,
|
|
340449
340520
|
fetched,
|
|
340450
340521
|
stored,
|
|
@@ -340554,12 +340625,12 @@ async function setupHistoryPushTracker(eventBus, services) {
|
|
|
340554
340625
|
throw error2;
|
|
340555
340626
|
}
|
|
340556
340627
|
}
|
|
340557
|
-
var
|
|
340628
|
+
var log85, RATE_LIMITS2, db2 = null, historyPushLog;
|
|
340558
340629
|
var init_sync_worker = __esm(() => {
|
|
340559
340630
|
init_src();
|
|
340560
340631
|
init_src4();
|
|
340561
340632
|
init_drizzle_orm();
|
|
340562
|
-
|
|
340633
|
+
log85 = createLogger("sync-worker");
|
|
340563
340634
|
RATE_LIMITS2 = {
|
|
340564
340635
|
"whatsapp-baileys": 30,
|
|
340565
340636
|
discord: 50,
|
|
@@ -340623,15 +340694,15 @@ async function handleTrashEmojiMessage(services, db3, event) {
|
|
|
340623
340694
|
return;
|
|
340624
340695
|
if (!isTrashEmojiOnly2(content.text))
|
|
340625
340696
|
return;
|
|
340626
|
-
|
|
340697
|
+
log86.info("Trash emoji detected, clearing session", { instanceId, chatId, from });
|
|
340627
340698
|
try {
|
|
340628
340699
|
const { sessionId, sessionStrategy } = await clearAgentSession(services, db3, instanceId, from, chatId);
|
|
340629
|
-
|
|
340700
|
+
log86.info("Session cleared successfully", { instanceId, sessionId, sessionStrategy });
|
|
340630
340701
|
try {
|
|
340631
340702
|
await sendMessage(services, instanceId, chatId, "\u2705 Conversa limpa! Sua sess\xE3o com o assistente foi resetada.");
|
|
340632
|
-
|
|
340703
|
+
log86.info("Sent session cleared confirmation", { instanceId, chatId });
|
|
340633
340704
|
} catch (sendError) {
|
|
340634
|
-
|
|
340705
|
+
log86.error("Failed to send confirmation message", { instanceId, chatId, error: String(sendError) });
|
|
340635
340706
|
}
|
|
340636
340707
|
} catch (error2) {
|
|
340637
340708
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -340642,14 +340713,14 @@ async function handleTrashEmojiMessage(services, db3, event) {
|
|
|
340642
340713
|
"Session clearing not supported for"
|
|
340643
340714
|
];
|
|
340644
340715
|
if (skippableErrors.some((e) => errorMessage.includes(e))) {
|
|
340645
|
-
|
|
340716
|
+
log86.debug("Session clearing skipped", { instanceId, reason: errorMessage });
|
|
340646
340717
|
return;
|
|
340647
340718
|
}
|
|
340648
|
-
|
|
340719
|
+
log86.error("Failed to clear session", { instanceId, chatId, error: errorMessage });
|
|
340649
340720
|
try {
|
|
340650
340721
|
await sendMessage(services, instanceId, chatId, "\u274C Erro ao limpar sess\xE3o. Tente novamente.");
|
|
340651
340722
|
} catch (sendError) {
|
|
340652
|
-
|
|
340723
|
+
log86.error("Failed to send error message", { instanceId, chatId, error: String(sendError) });
|
|
340653
340724
|
}
|
|
340654
340725
|
}
|
|
340655
340726
|
}
|
|
@@ -340663,13 +340734,13 @@ async function setupSessionCleaner(eventBus, services, db3) {
|
|
|
340663
340734
|
startFrom: "last",
|
|
340664
340735
|
concurrency: 5
|
|
340665
340736
|
});
|
|
340666
|
-
|
|
340737
|
+
log86.info("Session cleaner initialized");
|
|
340667
340738
|
} catch (error2) {
|
|
340668
|
-
|
|
340739
|
+
log86.error("Failed to set up session cleaner", { error: String(error2) });
|
|
340669
340740
|
throw error2;
|
|
340670
340741
|
}
|
|
340671
340742
|
}
|
|
340672
|
-
var
|
|
340743
|
+
var log86;
|
|
340673
340744
|
var init_session_cleaner = __esm(() => {
|
|
340674
340745
|
init_src();
|
|
340675
340746
|
init_src4();
|
|
@@ -340677,7 +340748,7 @@ var init_session_cleaner = __esm(() => {
|
|
|
340677
340748
|
init_agent_runner();
|
|
340678
340749
|
init_agent_dispatcher();
|
|
340679
340750
|
init_loader2();
|
|
340680
|
-
|
|
340751
|
+
log86 = createLogger("session-cleaner");
|
|
340681
340752
|
});
|
|
340682
340753
|
|
|
340683
340754
|
// ../api/src/plugins/instance-monitor.ts
|
|
@@ -341215,14 +341286,14 @@ async function sendInboxMessage(msg, inboxName, team, channelRegistry2, patterns
|
|
|
341215
341286
|
return "ok";
|
|
341216
341287
|
const parsed = parseMetadata(msg.text);
|
|
341217
341288
|
if (!parsed.instance || !parsed.chat || !parsed.channel) {
|
|
341218
|
-
|
|
341289
|
+
log87.debug("Skipping message \u2014 missing routing metadata", { team, inboxName, from: msg.from });
|
|
341219
341290
|
return "ok";
|
|
341220
341291
|
}
|
|
341221
341292
|
if (!parsed.cleanText)
|
|
341222
341293
|
return "ok";
|
|
341223
341294
|
const plugin6 = channelRegistry2.get(parsed.channel);
|
|
341224
341295
|
if (!plugin6) {
|
|
341225
|
-
|
|
341296
|
+
log87.warn("Channel plugin not found", { channel: parsed.channel, team, inboxName });
|
|
341226
341297
|
return "ok";
|
|
341227
341298
|
}
|
|
341228
341299
|
const outgoing = {
|
|
@@ -341234,7 +341305,7 @@ async function sendInboxMessage(msg, inboxName, team, channelRegistry2, patterns
|
|
|
341234
341305
|
try {
|
|
341235
341306
|
const result = await plugin6.sendMessage(parsed.instance, outgoing);
|
|
341236
341307
|
if (result.success) {
|
|
341237
|
-
|
|
341308
|
+
log87.info("Forwarded reply", {
|
|
341238
341309
|
team,
|
|
341239
341310
|
inboxName,
|
|
341240
341311
|
channel: parsed.channel,
|
|
@@ -341244,11 +341315,11 @@ async function sendInboxMessage(msg, inboxName, team, channelRegistry2, patterns
|
|
|
341244
341315
|
messageId: result.messageId
|
|
341245
341316
|
});
|
|
341246
341317
|
} else {
|
|
341247
|
-
|
|
341318
|
+
log87.error("sendMessage failed", { team, inboxName, channel: parsed.channel, error: result.error });
|
|
341248
341319
|
}
|
|
341249
341320
|
return "ok";
|
|
341250
341321
|
} catch (err) {
|
|
341251
|
-
|
|
341322
|
+
log87.error("sendMessage threw", { team, inboxName, error: String(err) });
|
|
341252
341323
|
return "retry";
|
|
341253
341324
|
}
|
|
341254
341325
|
}
|
|
@@ -341272,7 +341343,7 @@ async function processInbox(inboxName, team, state, channelRegistry2, patterns)
|
|
|
341272
341343
|
const entry = state.cursors[cursorKey] ?? { lastIndex: 0 };
|
|
341273
341344
|
let { lastIndex } = entry;
|
|
341274
341345
|
if (lastIndex > inbox.length) {
|
|
341275
|
-
|
|
341346
|
+
log87.warn("Inbox shrank (truncated/rotated), resetting cursor", {
|
|
341276
341347
|
team,
|
|
341277
341348
|
inboxName,
|
|
341278
341349
|
oldCursor: lastIndex,
|
|
@@ -341325,20 +341396,20 @@ async function setupInboxBridge(services, channelRegistry2) {
|
|
|
341325
341396
|
let patterns = [];
|
|
341326
341397
|
try {
|
|
341327
341398
|
patterns = await discoverAgentPatterns(services);
|
|
341328
|
-
|
|
341399
|
+
log87.info("Inbox bridge started", {
|
|
341329
341400
|
patterns: patterns.map((p2) => ({ raw: p2.raw, isTemplate: p2.isTemplate, prefix: p2.prefix }))
|
|
341330
341401
|
});
|
|
341331
341402
|
} catch (err) {
|
|
341332
|
-
|
|
341403
|
+
log87.warn("Initial agent discovery failed", { error: String(err) });
|
|
341333
341404
|
}
|
|
341334
341405
|
const discoveryTimer = setInterval(async () => {
|
|
341335
341406
|
try {
|
|
341336
341407
|
patterns = await discoverAgentPatterns(services);
|
|
341337
|
-
|
|
341408
|
+
log87.debug("Agent patterns refreshed", {
|
|
341338
341409
|
patterns: patterns.map((p2) => ({ raw: p2.raw, isTemplate: p2.isTemplate, prefix: p2.prefix }))
|
|
341339
341410
|
});
|
|
341340
341411
|
} catch (err) {
|
|
341341
|
-
|
|
341412
|
+
log87.warn("Agent discovery refresh failed", { error: String(err) });
|
|
341342
341413
|
}
|
|
341343
341414
|
}, DISCOVERY_INTERVAL_MS);
|
|
341344
341415
|
discoveryTimer.unref();
|
|
@@ -341350,7 +341421,7 @@ async function setupInboxBridge(services, channelRegistry2) {
|
|
|
341350
341421
|
try {
|
|
341351
341422
|
await pollInboxes(patterns, channelRegistry2);
|
|
341352
341423
|
} catch (err) {
|
|
341353
|
-
|
|
341424
|
+
log87.error("Poll cycle error", { error: String(err) });
|
|
341354
341425
|
} finally {
|
|
341355
341426
|
polling = false;
|
|
341356
341427
|
}
|
|
@@ -341359,13 +341430,13 @@ async function setupInboxBridge(services, channelRegistry2) {
|
|
|
341359
341430
|
return async () => {
|
|
341360
341431
|
clearInterval(discoveryTimer);
|
|
341361
341432
|
clearInterval(pollTimer);
|
|
341362
|
-
|
|
341433
|
+
log87.info("Inbox bridge stopped");
|
|
341363
341434
|
};
|
|
341364
341435
|
}
|
|
341365
|
-
var
|
|
341436
|
+
var log87, CLAUDE_TEAMS_DIR, BRIDGE_STATE_PATH, POLL_INTERVAL_MS2 = 2000, DISCOVERY_INTERVAL_MS = 60000, CURSOR_TTL_MS;
|
|
341366
341437
|
var init_inbox_bridge = __esm(() => {
|
|
341367
341438
|
init_src();
|
|
341368
|
-
|
|
341439
|
+
log87 = createLogger("inbox-bridge");
|
|
341369
341440
|
CLAUDE_TEAMS_DIR = join25(homedir3(), ".claude", "teams");
|
|
341370
341441
|
BRIDGE_STATE_PATH = join25(homedir3(), ".claude", "bridge", "state.json");
|
|
341371
341442
|
CURSOR_TTL_MS = 24 * 60 * 60 * 1000;
|
|
@@ -341398,7 +341469,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
341398
341469
|
recordScheduledJob("dead-letter-auto-retry", "success", durationSec);
|
|
341399
341470
|
const pendingCount = await services.deadLetters.getPendingCount();
|
|
341400
341471
|
deadLettersPending.set(pendingCount);
|
|
341401
|
-
|
|
341472
|
+
log88.info("Dead letter auto-retry completed", result);
|
|
341402
341473
|
} catch (err) {
|
|
341403
341474
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
341404
341475
|
recordScheduledJob("dead-letter-auto-retry", "failure", durationSec);
|
|
@@ -341420,7 +341491,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
341420
341491
|
recordScheduledJob("payload-cleanup", "success", durationSec);
|
|
341421
341492
|
const stats = await services.payloadStore.getStats();
|
|
341422
341493
|
payloadStorageSize.set(stats.totalSizeCompressed);
|
|
341423
|
-
|
|
341494
|
+
log88.info("Payload cleanup completed", { deleted });
|
|
341424
341495
|
} catch (err) {
|
|
341425
341496
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
341426
341497
|
recordScheduledJob("payload-cleanup", "failure", durationSec);
|
|
@@ -341440,7 +341511,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
341440
341511
|
const deleted = await services.deadLetters.cleanupExpired();
|
|
341441
341512
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
341442
341513
|
recordScheduledJob("dead-letter-cleanup", "success", durationSec);
|
|
341443
|
-
|
|
341514
|
+
log88.info("Dead letter cleanup completed", { deleted });
|
|
341444
341515
|
} catch (err) {
|
|
341445
341516
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
341446
341517
|
recordScheduledJob("dead-letter-cleanup", "failure", durationSec);
|
|
@@ -341469,7 +341540,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
341469
341540
|
});
|
|
341470
341541
|
jobsCreated++;
|
|
341471
341542
|
} catch (err) {
|
|
341472
|
-
|
|
341543
|
+
log88.warn("Failed to create contacts sync job for instance", {
|
|
341473
341544
|
instanceId: instance4.id,
|
|
341474
341545
|
error: String(err)
|
|
341475
341546
|
});
|
|
@@ -341477,7 +341548,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
341477
341548
|
}
|
|
341478
341549
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
341479
341550
|
recordScheduledJob("contacts-sync-daily", "success", durationSec);
|
|
341480
|
-
|
|
341551
|
+
log88.info("Daily contacts sync jobs created", { jobsCreated, instanceCount: instances2.length });
|
|
341481
341552
|
} catch (err) {
|
|
341482
341553
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
341483
341554
|
recordScheduledJob("contacts-sync-daily", "failure", durationSec);
|
|
@@ -341506,7 +341577,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
341506
341577
|
});
|
|
341507
341578
|
jobsCreated++;
|
|
341508
341579
|
} catch (err) {
|
|
341509
|
-
|
|
341580
|
+
log88.warn("Failed to create groups sync job for instance", {
|
|
341510
341581
|
instanceId: instance4.id,
|
|
341511
341582
|
error: String(err)
|
|
341512
341583
|
});
|
|
@@ -341514,7 +341585,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
341514
341585
|
}
|
|
341515
341586
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
341516
341587
|
recordScheduledJob("groups-sync-daily", "success", durationSec);
|
|
341517
|
-
|
|
341588
|
+
log88.info("Daily groups sync jobs created", { jobsCreated, instanceCount: instances2.length });
|
|
341518
341589
|
} catch (err) {
|
|
341519
341590
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
341520
341591
|
recordScheduledJob("groups-sync-daily", "failure", durationSec);
|
|
@@ -341543,7 +341614,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
341543
341614
|
}
|
|
341544
341615
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
341545
341616
|
recordScheduledJob("unread-count-refresh", "success", durationSec);
|
|
341546
|
-
|
|
341617
|
+
log88.debug("Refreshed unread counts", { instanceCount: waInstances.length });
|
|
341547
341618
|
} catch (err) {
|
|
341548
341619
|
const durationSec = (Date.now() - startTime3) / 1000;
|
|
341549
341620
|
recordScheduledJob("unread-count-refresh", "failure", durationSec);
|
|
@@ -341554,7 +341625,7 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
341554
341625
|
});
|
|
341555
341626
|
updateSchedulerMetrics();
|
|
341556
341627
|
scheduler.start();
|
|
341557
|
-
|
|
341628
|
+
log88.info("Scheduler started", {
|
|
341558
341629
|
jobs: scheduler.listJobs().map((j) => ({
|
|
341559
341630
|
name: j.name,
|
|
341560
341631
|
cron: j.cron,
|
|
@@ -341574,14 +341645,14 @@ function updateSchedulerMetrics() {
|
|
|
341574
341645
|
function stopScheduler() {
|
|
341575
341646
|
const scheduler = getScheduler();
|
|
341576
341647
|
scheduler.stop();
|
|
341577
|
-
|
|
341648
|
+
log88.info("Scheduler stopped");
|
|
341578
341649
|
}
|
|
341579
|
-
var
|
|
341650
|
+
var log88;
|
|
341580
341651
|
var init_scheduler2 = __esm(() => {
|
|
341581
341652
|
init_src();
|
|
341582
341653
|
init_esm5();
|
|
341583
341654
|
init_sentry_scrub();
|
|
341584
|
-
|
|
341655
|
+
log88 = createLogger("scheduler:setup");
|
|
341585
341656
|
});
|
|
341586
341657
|
|
|
341587
341658
|
// ../api/src/utils/startup-banner.ts
|
|
@@ -341655,12 +341726,12 @@ function printStartupBanner(options) {
|
|
|
341655
341726
|
process.stdout.write(`${line3}
|
|
341656
341727
|
`);
|
|
341657
341728
|
}
|
|
341658
|
-
|
|
341729
|
+
log89.info("Server ready", { host, port, version: version4 });
|
|
341659
341730
|
}
|
|
341660
|
-
var
|
|
341731
|
+
var log89, COLORS3, BOX, ANSI_ESCAPE_PATTERN;
|
|
341661
341732
|
var init_startup_banner = __esm(() => {
|
|
341662
341733
|
init_src();
|
|
341663
|
-
|
|
341734
|
+
log89 = createLogger("api:startup");
|
|
341664
341735
|
COLORS3 = {
|
|
341665
341736
|
reset: "\x1B[0m",
|
|
341666
341737
|
dim: "\x1B[2m",
|
|
@@ -341820,84 +341891,84 @@ function setupShutdownHandlers(server, earlyShutdown) {
|
|
|
341820
341891
|
}
|
|
341821
341892
|
async function setupEventBusServices(eventBus, services, db3) {
|
|
341822
341893
|
if (!eventBus) {
|
|
341823
|
-
|
|
341894
|
+
log90.warn("Skipping event bus services (no event bus)");
|
|
341824
341895
|
return;
|
|
341825
341896
|
}
|
|
341826
341897
|
try {
|
|
341827
341898
|
await setupMessagePersistence(eventBus, services);
|
|
341828
341899
|
} catch (error2) {
|
|
341829
|
-
|
|
341900
|
+
log90.error("Failed to set up message persistence", { error: String(error2) });
|
|
341830
341901
|
}
|
|
341831
341902
|
try {
|
|
341832
341903
|
await setupMediaProcessor(eventBus, db3, services);
|
|
341833
341904
|
} catch (error2) {
|
|
341834
|
-
|
|
341905
|
+
log90.error("Failed to set up media processor", { error: String(error2) });
|
|
341835
341906
|
}
|
|
341836
341907
|
try {
|
|
341837
341908
|
globalDispatcherCleanup = await setupAgentResponder(eventBus, services, db3);
|
|
341838
341909
|
} catch (error2) {
|
|
341839
|
-
|
|
341910
|
+
log90.error("Failed to set up agent dispatcher", { error: String(error2) });
|
|
341840
341911
|
}
|
|
341841
341912
|
if (globalChannelRegistry) {
|
|
341842
341913
|
try {
|
|
341843
341914
|
globalInboxBridgeCleanup = await setupInboxBridge(services, globalChannelRegistry);
|
|
341844
341915
|
} catch (error2) {
|
|
341845
|
-
|
|
341916
|
+
log90.error("Failed to set up inbox bridge", { error: String(error2) });
|
|
341846
341917
|
}
|
|
341847
341918
|
}
|
|
341848
341919
|
try {
|
|
341849
341920
|
await services.automations.startEngine({});
|
|
341850
341921
|
} catch (error2) {
|
|
341851
|
-
|
|
341922
|
+
log90.error("Failed to start automation engine", { error: String(error2) });
|
|
341852
341923
|
}
|
|
341853
341924
|
try {
|
|
341854
341925
|
await setupSessionCleaner(eventBus, services, db3);
|
|
341855
341926
|
} catch (error2) {
|
|
341856
|
-
|
|
341927
|
+
log90.error("Failed to set up session cleaner", { error: String(error2) });
|
|
341857
341928
|
}
|
|
341858
341929
|
if (globalChannelRegistry) {
|
|
341859
341930
|
try {
|
|
341860
341931
|
await setupSyncWorker(eventBus, services, globalChannelRegistry, db3);
|
|
341861
341932
|
} catch (error2) {
|
|
341862
|
-
|
|
341933
|
+
log90.error("Failed to set up sync worker", { error: String(error2) });
|
|
341863
341934
|
}
|
|
341864
341935
|
}
|
|
341865
341936
|
try {
|
|
341866
341937
|
await setupHistoryPushTracker(eventBus, services);
|
|
341867
341938
|
} catch (error2) {
|
|
341868
|
-
|
|
341939
|
+
log90.error("Failed to set up history-push tracker", { error: String(error2) });
|
|
341869
341940
|
}
|
|
341870
341941
|
}
|
|
341871
341942
|
async function waitForDatabaseReady(db3, maxAttempts = 30) {
|
|
341872
|
-
|
|
341943
|
+
log90.info("Waiting for database readiness");
|
|
341873
341944
|
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
341874
341945
|
try {
|
|
341875
341946
|
await db3.execute(sql`SELECT 1`);
|
|
341876
|
-
|
|
341947
|
+
log90.info("Database ready", { attempt });
|
|
341877
341948
|
return;
|
|
341878
341949
|
} catch {
|
|
341879
341950
|
if (attempt === maxAttempts) {
|
|
341880
341951
|
throw new Error(`Database not ready after ${maxAttempts} attempts`);
|
|
341881
341952
|
}
|
|
341882
|
-
|
|
341953
|
+
log90.warn("Database not ready, retrying...", { attempt });
|
|
341883
341954
|
await new Promise((resolve3) => setTimeout(resolve3, 1000));
|
|
341884
341955
|
}
|
|
341885
341956
|
}
|
|
341886
341957
|
}
|
|
341887
341958
|
async function main() {
|
|
341888
|
-
|
|
341959
|
+
log90.info("Starting Omni API v2");
|
|
341889
341960
|
enableDefaultMetrics();
|
|
341890
341961
|
const pgserveConfig = resolvePgserveConfig();
|
|
341891
341962
|
const databaseUrl = await startEmbeddedPgserve(pgserveConfig);
|
|
341892
|
-
|
|
341963
|
+
log90.info("Connecting to database");
|
|
341893
341964
|
const db3 = createDb({ url: databaseUrl });
|
|
341894
341965
|
const earlyShutdown = async () => {
|
|
341895
|
-
|
|
341966
|
+
log90.info("Shutdown during startup \u2014 cleaning up");
|
|
341896
341967
|
try {
|
|
341897
341968
|
await closeDb();
|
|
341898
341969
|
await stopEmbeddedPgserve();
|
|
341899
341970
|
} catch (err) {
|
|
341900
|
-
|
|
341971
|
+
log90.error("Cleanup failed during early shutdown", { error: String(err) });
|
|
341901
341972
|
} finally {
|
|
341902
341973
|
process.exit(1);
|
|
341903
341974
|
}
|
|
@@ -341911,7 +341982,7 @@ async function main() {
|
|
|
341911
341982
|
await stopEmbeddedPgserve();
|
|
341912
341983
|
throw error2;
|
|
341913
341984
|
}
|
|
341914
|
-
|
|
341985
|
+
log90.info("Running database migrations");
|
|
341915
341986
|
const migrationStart = Date.now();
|
|
341916
341987
|
const MIGRATION_TIMEOUT_MS = 60000;
|
|
341917
341988
|
try {
|
|
@@ -341924,7 +341995,7 @@ async function main() {
|
|
|
341924
341995
|
await stopEmbeddedPgserve();
|
|
341925
341996
|
throw error2;
|
|
341926
341997
|
}
|
|
341927
|
-
|
|
341998
|
+
log90.info("Database migrations complete", { durationMs: Date.now() - migrationStart });
|
|
341928
341999
|
const eventBus = await connectToNats(db3);
|
|
341929
342000
|
if (eventBus) {
|
|
341930
342001
|
try {
|
|
@@ -341939,9 +342010,9 @@ async function main() {
|
|
|
341939
342010
|
try {
|
|
341940
342011
|
await services.settings.seedDefaults();
|
|
341941
342012
|
} catch (error2) {
|
|
341942
|
-
|
|
342013
|
+
log90.error("Failed to seed default settings", { error: String(error2) });
|
|
341943
342014
|
}
|
|
341944
|
-
|
|
342015
|
+
log90.info("Initializing API key");
|
|
341945
342016
|
let apiKeyInfo;
|
|
341946
342017
|
try {
|
|
341947
342018
|
const keyResult = await services.apiKeys.initializePrimaryKey();
|
|
@@ -341951,17 +342022,17 @@ async function main() {
|
|
|
341951
342022
|
isFromEnv: keyResult.isFromEnv
|
|
341952
342023
|
};
|
|
341953
342024
|
if (keyResult.isNew) {
|
|
341954
|
-
|
|
342025
|
+
log90.info("Generated new primary API key");
|
|
341955
342026
|
} else if (keyResult.isFromEnv) {
|
|
341956
|
-
|
|
342027
|
+
log90.info("Using primary API key from environment");
|
|
341957
342028
|
} else {
|
|
341958
|
-
|
|
342029
|
+
log90.info("Using existing primary API key");
|
|
341959
342030
|
}
|
|
341960
342031
|
} catch (error2) {
|
|
341961
|
-
|
|
342032
|
+
log90.error("Failed to initialize primary API key", { error: String(error2) });
|
|
341962
342033
|
}
|
|
341963
342034
|
await setupEventBusServices(eventBus, services, db3);
|
|
341964
|
-
|
|
342035
|
+
log90.info("Starting scheduler");
|
|
341965
342036
|
setupScheduler(services, globalChannelRegistry);
|
|
341966
342037
|
const server = startBunServer(app);
|
|
341967
342038
|
printStartupBanner({
|
|
@@ -341975,7 +342046,7 @@ async function main() {
|
|
|
341975
342046
|
});
|
|
341976
342047
|
setupShutdownHandlers(server, earlyShutdown);
|
|
341977
342048
|
}
|
|
341978
|
-
var import__package3,
|
|
342049
|
+
var import__package3, log90, natsLog, pluginLog, shutdownLog, PORT, HOST, NATS_URL, globalEventBus = null, globalChannelRegistry = null, globalInstanceMonitor = null, globalDispatcherCleanup = null, globalInboxBridgeCleanup = null;
|
|
341979
342050
|
var init_src7 = __esm(() => {
|
|
341980
342051
|
init_instrument2();
|
|
341981
342052
|
init_src();
|
|
@@ -341995,7 +342066,7 @@ var init_src7 = __esm(() => {
|
|
|
341995
342066
|
level: process.env.LOG_LEVEL ?? "info",
|
|
341996
342067
|
format: process.env.LOG_FORMAT ?? "auto"
|
|
341997
342068
|
});
|
|
341998
|
-
|
|
342069
|
+
log90 = createLogger("api:startup");
|
|
341999
342070
|
natsLog = createLogger("api:nats");
|
|
342000
342071
|
pluginLog = createLogger("api:plugins");
|
|
342001
342072
|
shutdownLog = createLogger("api:shutdown");
|
|
@@ -342003,7 +342074,7 @@ var init_src7 = __esm(() => {
|
|
|
342003
342074
|
HOST = process.env.API_HOST ?? "0.0.0.0";
|
|
342004
342075
|
NATS_URL = process.env.NATS_URL ?? "nats://localhost:4222";
|
|
342005
342076
|
main().catch((error2) => {
|
|
342006
|
-
|
|
342077
|
+
log90.error("Failed to start API server", { error: String(error2) });
|
|
342007
342078
|
process.exit(1);
|
|
342008
342079
|
});
|
|
342009
342080
|
});
|
|
@@ -458921,6 +458992,9 @@ function fromJid(jid) {
|
|
|
458921
458992
|
const id = jid.split("@")[0] || "";
|
|
458922
458993
|
return { id, isGroup, isUser, isBroadcast, isLid };
|
|
458923
458994
|
}
|
|
458995
|
+
function isGroupJid(jid) {
|
|
458996
|
+
return jid.endsWith(JID_SUFFIX.GROUP);
|
|
458997
|
+
}
|
|
458924
458998
|
function isUserJid(jid) {
|
|
458925
458999
|
return jid.endsWith(JID_SUFFIX.USER);
|
|
458926
459000
|
}
|
|
@@ -460300,7 +460374,6 @@ async function removeReaction4(sock, jid, targetMessageId, fromMe = true) {
|
|
|
460300
460374
|
|
|
460301
460375
|
// ../channel-whatsapp/src/senders/stream.ts
|
|
460302
460376
|
init_src();
|
|
460303
|
-
|
|
460304
460377
|
// ../channel-whatsapp/src/utils/split-message.ts
|
|
460305
460378
|
var DEFAULT_MAX_LENGTH2 = 65536;
|
|
460306
460379
|
function splitByDelimiter(text, delimiter) {
|
|
@@ -460670,14 +460743,16 @@ class WhatsAppStreamSender {
|
|
|
460670
460743
|
this.messageId = result?.key?.id ?? null;
|
|
460671
460744
|
this.firstMessageSent = true;
|
|
460672
460745
|
} else {
|
|
460673
|
-
|
|
460674
|
-
|
|
460675
|
-
|
|
460676
|
-
|
|
460677
|
-
|
|
460678
|
-
|
|
460679
|
-
|
|
460680
|
-
|
|
460746
|
+
const sock = this.getSock();
|
|
460747
|
+
const editKey = {
|
|
460748
|
+
remoteJid: this.jid,
|
|
460749
|
+
id: this.messageId,
|
|
460750
|
+
fromMe: true
|
|
460751
|
+
};
|
|
460752
|
+
if (isGroupJid(this.jid)) {
|
|
460753
|
+
editKey.participant = sock.user?.id;
|
|
460754
|
+
}
|
|
460755
|
+
await sock.sendMessage(this.jid, { text, edit: editKey });
|
|
460681
460756
|
}
|
|
460682
460757
|
this.lastRenderedText = text;
|
|
460683
460758
|
this.lastEditAt = Date.now();
|
|
@@ -460693,14 +460768,16 @@ class WhatsAppStreamSender {
|
|
|
460693
460768
|
async doEditRaw(text) {
|
|
460694
460769
|
if (!this.messageId)
|
|
460695
460770
|
throw new Error("No message to edit");
|
|
460696
|
-
|
|
460697
|
-
|
|
460698
|
-
|
|
460699
|
-
|
|
460700
|
-
|
|
460701
|
-
|
|
460702
|
-
|
|
460703
|
-
|
|
460771
|
+
const sock = this.getSock();
|
|
460772
|
+
const editKey = {
|
|
460773
|
+
remoteJid: this.jid,
|
|
460774
|
+
id: this.messageId,
|
|
460775
|
+
fromMe: true
|
|
460776
|
+
};
|
|
460777
|
+
if (isGroupJid(this.jid)) {
|
|
460778
|
+
editKey.participant = sock.user?.id;
|
|
460779
|
+
}
|
|
460780
|
+
await sock.sendMessage(this.jid, { text, edit: editKey });
|
|
460704
460781
|
this.lastRenderedText = text;
|
|
460705
460782
|
this.lastEditAt = Date.now();
|
|
460706
460783
|
}
|
|
@@ -463229,11 +463306,33 @@ class WhatsAppPlugin extends BaseChannelPlugin {
|
|
|
463229
463306
|
await this.humanDelay(instanceId);
|
|
463230
463307
|
const sock = this.getSocket(instanceId);
|
|
463231
463308
|
const jid = toJid(chatJid);
|
|
463232
|
-
|
|
463233
|
-
|
|
463234
|
-
|
|
463235
|
-
|
|
463236
|
-
|
|
463309
|
+
const editKey = {
|
|
463310
|
+
remoteJid: jid,
|
|
463311
|
+
id: messageId,
|
|
463312
|
+
fromMe
|
|
463313
|
+
};
|
|
463314
|
+
if (isGroupJid(jid) && fromMe) {
|
|
463315
|
+
editKey.participant = sock.user?.id;
|
|
463316
|
+
}
|
|
463317
|
+
try {
|
|
463318
|
+
const result = await sock.sendMessage(jid, { edit: editKey, text: newText });
|
|
463319
|
+
this.logger.info("Message edited", {
|
|
463320
|
+
instanceId,
|
|
463321
|
+
chatJid: jid,
|
|
463322
|
+
messageId,
|
|
463323
|
+
fromMe,
|
|
463324
|
+
resultKeyId: result?.key?.id
|
|
463325
|
+
});
|
|
463326
|
+
} catch (error) {
|
|
463327
|
+
this.logger.error("Failed to edit message via Baileys", {
|
|
463328
|
+
instanceId,
|
|
463329
|
+
chatJid: jid,
|
|
463330
|
+
messageId,
|
|
463331
|
+
fromMe,
|
|
463332
|
+
error: error instanceof Error ? error.message : String(error)
|
|
463333
|
+
});
|
|
463334
|
+
throw mapBaileysError(error);
|
|
463335
|
+
}
|
|
463237
463336
|
}
|
|
463238
463337
|
getSocket(instanceId) {
|
|
463239
463338
|
const sock = this.sockets.get(instanceId);
|