@automagik/omni 2.260317.2 → 2.260320.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 messageContent = context2.payload.content ?? context2.payload.text ?? "";
27907
- if (!messageContent)
27908
- return { error: "message content not found in payload" };
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: [messageContent]
27932
+ messages: messagesResult
27920
27933
  }
27921
27934
  };
27922
27935
  }
@@ -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.260317.2",
222920
+ version: "2.260320.1",
222908
222921
  type: "module",
222909
222922
  exports: {
222910
222923
  ".": {
@@ -323029,6 +323042,8 @@ function loadEnvVersion() {
323029
323042
  return process.env.OMNI_VERSION ?? process.env.OMNI_SERVER_VERSION ?? process.env.npm_package_version ?? process.env.PACKAGE_VERSION ?? undefined;
323030
323043
  }
323031
323044
  function resolveFallbackVersion() {
323045
+ if (EMBEDDED_VERSION && EMBEDDED_VERSION !== "0.0.0")
323046
+ return EMBEDDED_VERSION;
323032
323047
  return loadRepoPackageVersion() ?? loadEnvVersion() ?? LAST_RESORT_VERSION;
323033
323048
  }
323034
323049
  function loadServerVersionInfo() {
@@ -323052,9 +323067,11 @@ function loadServerVersionInfo() {
323052
323067
  commit: FALLBACK_COMMIT
323053
323068
  };
323054
323069
  }
323055
- var LAST_RESORT_VERSION = "2.0.0-dev.1", FALLBACK_COMMIT = "unknown", SERVER_VERSION_INFO, versionHeadersMiddleware;
323070
+ var import__package, EMBEDDED_VERSION, LAST_RESORT_VERSION = "2.0.0-dev.1", FALLBACK_COMMIT = "unknown", SERVER_VERSION_INFO, versionHeadersMiddleware;
323056
323071
  var init_version_headers = __esm(() => {
323057
323072
  init_factory2();
323073
+ import__package = __toESM(require_package8(), 1);
323074
+ EMBEDDED_VERSION = import__package.default?.version;
323058
323075
  SERVER_VERSION_INFO = loadServerVersionInfo();
323059
323076
  versionHeadersMiddleware = createMiddleware(async (c, next) => {
323060
323077
  const cliVersion = c.req.header("x-omni-cli-version");
@@ -323096,13 +323113,13 @@ var init_webhook_auth = __esm(() => {
323096
323113
  });
323097
323114
 
323098
323115
  // ../api/src/routes/health.ts
323099
- var import__package, VERSION4, startTime2, healthRoutes;
323116
+ var import__package2, VERSION4, startTime2, healthRoutes;
323100
323117
  var init_health = __esm(() => {
323101
323118
  init_src4();
323102
323119
  init_drizzle_orm();
323103
323120
  init_dist2();
323104
- import__package = __toESM(require_package8(), 1);
323105
- VERSION4 = import__package.default.version;
323121
+ import__package2 = __toESM(require_package8(), 1);
323122
+ VERSION4 = import__package2.default.version;
323106
323123
  startTime2 = Date.now();
323107
323124
  healthRoutes = new Hono2;
323108
323125
  healthRoutes.get("/health", async (c) => {
@@ -331861,7 +331878,7 @@ var init_instances3 = __esm(() => {
331861
331878
  slackAppToken: exports_external.string().optional().nullable().describe("Slack app token (persisted for reconnection)"),
331862
331879
  slackSigningSecret: exports_external.string().optional().nullable().describe("Slack signing secret (persisted for reconnection)"),
331863
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)"),
331864
- groupHistorySize: exports_external.number().int().min(0).max(200).default(50).describe("Number of context messages to include for group chats when dispatching to agent (0 = disabled, max 200)"),
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)"),
331865
331882
  reactionAck: exports_external.enum(["on", "off"]).default("off").describe("Reaction ack mode: on to send a reaction while agent processes"),
331866
331883
  reactionAckEmoji: exports_external.record(exports_external.string()).optional().nullable().describe('Per-channel emoji map for reaction ack (e.g. {"whatsapp":"\\u2705"})'),
331867
331884
  ackTimeoutMs: exports_external.number().int().min(0).max(120000).default(30000).describe("Ack timeout in milliseconds (max 120000)")
@@ -333752,6 +333769,19 @@ async function resolveMessageFromRef(services, ref) {
333752
333769
  }
333753
333770
  return found;
333754
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
+ }
333755
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;
333756
333786
  var init_messages5 = __esm(() => {
333757
333787
  init_dist6();
@@ -335031,10 +335061,28 @@ var init_messages5 = __esm(() => {
335031
335061
  recoverable: false
335032
335062
  });
335033
335063
  }
335034
- await plugin6.editMessage(instanceId, channelId, messageId, text3);
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
+ }
335035
335083
  return c.json({
335036
335084
  success: true,
335037
- data: { messageId, edited: true }
335085
+ data: { messageId, externalId: resolvedMessageId, edited: true }
335038
335086
  });
335039
335087
  });
335040
335088
  messagesRoutes.post("/delete-channel", zValidator("json", deleteMessageChannelSchema), async (c) => {
@@ -337607,6 +337655,93 @@ function buildWhatsAppMessageContext(rawPayload, chatId, instance4, text3) {
337607
337655
  return { isDirectMessage, mentionsBot, isReplyToBot, text: text3 };
337608
337656
  }
337609
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
+
337610
337745
  // ../api/src/plugins/session-storage.ts
337611
337746
  function scopeSessionKey(providerId, sessionKey) {
337612
337747
  return `provider:${providerId}:session:${sessionKey}`;
@@ -337695,7 +337830,7 @@ class RateLimiter {
337695
337830
  let timestamps = this.counters.get(key) ?? [];
337696
337831
  timestamps = timestamps.filter((ts) => now - ts < this.windowMs);
337697
337832
  if (timestamps.length >= maxPerMinute) {
337698
- log83.debug("Rate limit exceeded", { key, count: timestamps.length, limit: maxPerMinute });
337833
+ log84.debug("Rate limit exceeded", { key, count: timestamps.length, limit: maxPerMinute });
337699
337834
  return false;
337700
337835
  }
337701
337836
  timestamps.push(now);
@@ -337727,7 +337862,7 @@ class ReactionDedup {
337727
337862
  }
337728
337863
  const msgCount = this.messageCounters.get(messageId) ?? 0;
337729
337864
  if (msgCount >= this.maxPerMessage) {
337730
- log83.debug("Reaction per-message limit reached", { messageId, count: msgCount });
337865
+ log84.debug("Reaction per-message limit reached", { messageId, count: msgCount });
337731
337866
  return true;
337732
337867
  }
337733
337868
  this.seen.set(key, Date.now());
@@ -337750,73 +337885,6 @@ class ReactionDedup {
337750
337885
  return false;
337751
337886
  }
337752
337887
  }
337753
-
337754
- class MessageDebouncer {
337755
- buffers = new Map;
337756
- timers = new Map;
337757
- onFlush;
337758
- constructor(onFlush) {
337759
- this.onFlush = onFlush;
337760
- }
337761
- getChatKey(instanceId, chatId) {
337762
- return `${instanceId}:${chatId}`;
337763
- }
337764
- buffer(instanceId, chatId, message2, config4) {
337765
- const chatKey = this.getChatKey(instanceId, chatId);
337766
- const buffer3 = this.buffers.get(chatKey) ?? [];
337767
- buffer3.push(message2);
337768
- this.buffers.set(chatKey, buffer3);
337769
- this.restartTimer(chatKey, config4);
337770
- }
337771
- onUserTyping(instanceId, chatId, config4) {
337772
- const chatKey = this.getChatKey(instanceId, chatId);
337773
- if (config4.restartOnTyping && this.buffers.has(chatKey)) {
337774
- log83.debug("Restarting debounce timer on user typing", { chatKey });
337775
- this.restartTimer(chatKey, config4);
337776
- }
337777
- }
337778
- restartTimer(chatKey, config4) {
337779
- const existing = this.timers.get(chatKey);
337780
- if (config4.mode === "fixed" && existing)
337781
- return;
337782
- if (existing)
337783
- clearTimeout(existing);
337784
- let delay2;
337785
- switch (config4.mode) {
337786
- case "disabled":
337787
- delay2 = 0;
337788
- break;
337789
- case "fixed":
337790
- delay2 = config4.minMs;
337791
- break;
337792
- case "randomized":
337793
- delay2 = config4.minMs + Math.random() * (config4.maxMs - config4.minMs);
337794
- break;
337795
- default:
337796
- delay2 = 0;
337797
- }
337798
- const timer2 = setTimeout(() => this.flush(chatKey), delay2);
337799
- this.timers.set(chatKey, timer2);
337800
- }
337801
- async flush(chatKey) {
337802
- const messages4 = this.buffers.get(chatKey);
337803
- this.buffers.delete(chatKey);
337804
- this.timers.delete(chatKey);
337805
- if (messages4?.length) {
337806
- try {
337807
- await this.onFlush(chatKey, messages4);
337808
- } catch (error2) {
337809
- log83.error("Error flushing debounced messages", { chatKey, error: String(error2) });
337810
- }
337811
- }
337812
- }
337813
- clear() {
337814
- for (const timer2 of this.timers.values())
337815
- clearTimeout(timer2);
337816
- this.buffers.clear();
337817
- this.timers.clear();
337818
- }
337819
- }
337820
337888
  function getDebounceConfig(instance4) {
337821
337889
  return {
337822
337890
  mode: instance4.messageDebounceMode ?? "disabled",
@@ -337902,7 +337970,7 @@ async function sendTypingPresence(channel4, instanceId, chatId, state) {
337902
337970
  await plugin6.sendTyping(instanceId, chatId, duration);
337903
337971
  }
337904
337972
  } catch (error2) {
337905
- log83.debug("Failed to send typing presence", { error: String(error2) });
337973
+ log84.debug("Failed to send typing presence", { error: String(error2) });
337906
337974
  }
337907
337975
  }
337908
337976
  async function sendTextMessage5(channel4, instanceId, chatId, text3, messageFormatMode = "convert", replyTo, correlationId, senderAgentId) {
@@ -337918,7 +337986,7 @@ async function sendTextMessage5(channel4, instanceId, chatId, text3, messageForm
337918
337986
  }
337919
337987
  async function sendErrorFeedback(channel4, instanceId, chatId, error2) {
337920
337988
  const errorMsg = error2 instanceof Error ? error2.message : String(error2);
337921
- log83.error("agent_dispatch_error", { channel: channel4, instanceId, chatId, error: errorMsg });
337989
+ log84.error("agent_dispatch_error", { channel: channel4, instanceId, chatId, error: errorMsg });
337922
337990
  const text3 = "\u26A0\uFE0F Sorry, I ran into an issue processing your message. Please try again.";
337923
337991
  await sendTextMessage5(channel4, instanceId, chatId, text3);
337924
337992
  }
@@ -337968,7 +338036,7 @@ function resolveMediaPath2(mediaUrl) {
337968
338036
  const fullPath = resolve2(MEDIA_BASE_PATH3, relativePath);
337969
338037
  const basePath = resolve2(MEDIA_BASE_PATH3);
337970
338038
  if (!fullPath.startsWith(`${basePath}/`) && fullPath !== basePath) {
337971
- log83.warn("Path traversal attempt blocked", { mediaUrl, resolved: fullPath, basePath });
338039
+ log84.warn("Path traversal attempt blocked", { mediaUrl, resolved: fullPath, basePath });
337972
338040
  return null;
337973
338041
  }
337974
338042
  return fullPath;
@@ -338025,7 +338093,7 @@ async function waitForMediaProcessing(services, instanceId, chatId, externalId,
338025
338093
  return MEDIA_WAIT_NULL;
338026
338094
  const chat2 = await services.chats.findByExternalIdSmart(instanceId, chatId);
338027
338095
  if (!chat2) {
338028
- log83.warn("Chat not found for media wait", { instanceId, chatId });
338096
+ log84.warn("Chat not found for media wait", { instanceId, chatId });
338029
338097
  return MEDIA_WAIT_NULL;
338030
338098
  }
338031
338099
  const deadline = Date.now() + 60000;
@@ -338033,14 +338101,14 @@ async function waitForMediaProcessing(services, instanceId, chatId, externalId,
338033
338101
  const msg = await services.messages.getByExternalId(chat2.id, externalId);
338034
338102
  const result = checkProcessedColumn(msg, column2);
338035
338103
  if (result === "error") {
338036
- log83.warn("Media processing failed", { instanceId, chatId, externalId, error: msg?.[column2] });
338104
+ log84.warn("Media processing failed", { instanceId, chatId, externalId, error: msg?.[column2] });
338037
338105
  return MEDIA_WAIT_NULL;
338038
338106
  }
338039
338107
  if (result !== "pending")
338040
338108
  return result;
338041
338109
  await sleep4(pollMs);
338042
338110
  }
338043
- log83.warn("Media processing wait timed out", { instanceId, chatId, externalId, contentType });
338111
+ log84.warn("Media processing wait timed out", { instanceId, chatId, externalId, contentType });
338044
338112
  return MEDIA_WAIT_NULL;
338045
338113
  }
338046
338114
  function formatProcessedMedia(contentType, fullPath, processedText, includePath, sendMediaPathTypes) {
@@ -338078,12 +338146,11 @@ async function resolveQuotedMessage(services, instanceId, chatId, replyToId) {
338078
338146
  const content = getMessageContentText(quoted);
338079
338147
  if (!content)
338080
338148
  return null;
338081
- const maxLen = 500;
338082
- 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;
338083
338150
  const timeStr = time3 ? ` at ${time3}` : "";
338084
338151
  return `[Quoting ${sender}${timeStr}: ${truncated}]`;
338085
338152
  } catch (error2) {
338086
- log83.debug("Failed to resolve quoted message", { replyToId, error: String(error2) });
338153
+ log84.debug("Failed to resolve quoted message", { replyToId, error: String(error2) });
338087
338154
  return null;
338088
338155
  }
338089
338156
  }
@@ -338156,11 +338223,11 @@ async function resolveContactName2(services, instanceId, jid, cacheMap) {
338156
338223
  try {
338157
338224
  const chat2 = await services.chats.findByExternalIdSmart(instanceId, jid);
338158
338225
  if (chat2?.name) {
338159
- log83.debug("Contact name from DB fallback", { jid, name: chat2.name });
338226
+ log84.debug("Contact name from DB fallback", { jid, name: chat2.name });
338160
338227
  return chat2.name;
338161
338228
  }
338162
338229
  } catch (error2) {
338163
- log83.warn("Failed to query DB for contact", { jid, error: String(error2) });
338230
+ log84.warn("Failed to query DB for contact", { jid, error: String(error2) });
338164
338231
  }
338165
338232
  return null;
338166
338233
  }
@@ -338192,14 +338259,14 @@ async function applyJidMentionReplacement(services, instanceId, jid, jidToName,
338192
338259
  async function replaceMentionsWithContactNames(services, instanceId, text3, mentionedJids, mentionedContacts) {
338193
338260
  if (!mentionedJids?.length)
338194
338261
  return text3;
338195
- log83.debug("Starting mention replacement", { mentionCount: mentionedJids.length });
338262
+ log84.debug("Starting mention replacement", { mentionCount: mentionedJids.length });
338196
338263
  const jidToName = buildJidNameMap(mentionedContacts);
338197
338264
  const stats = { resolved: 0, replaced: 0, unresolved: 0, skipped: 0 };
338198
338265
  let replacedText = text3;
338199
338266
  for (const jid of mentionedJids) {
338200
338267
  replacedText = await applyJidMentionReplacement(services, instanceId, jid, jidToName, replacedText, stats);
338201
338268
  }
338202
- log83.debug("Mention replacement complete", {
338269
+ log84.debug("Mention replacement complete", {
338203
338270
  original: text3,
338204
338271
  replaced: replacedText,
338205
338272
  mentionCount: mentionedJids.length,
@@ -338268,7 +338335,7 @@ async function fetchSenderMetadata(services, channel4, instanceId, senderId) {
338268
338335
  platformUsername: identity?.platformUsername ?? undefined
338269
338336
  };
338270
338337
  } catch (error2) {
338271
- log83.debug("Failed to fetch sender identity metadata", { error: String(error2) });
338338
+ log84.debug("Failed to fetch sender identity metadata", { error: String(error2) });
338272
338339
  return {};
338273
338340
  }
338274
338341
  }
@@ -338282,7 +338349,7 @@ async function fetchChatMetadata(services, instanceId, chatId, chatType) {
338282
338349
  participantCount: chat2?.participantCount ?? undefined
338283
338350
  };
338284
338351
  } catch (error2) {
338285
- log83.debug("Failed to fetch chat metadata", { error: String(error2) });
338352
+ log84.debug("Failed to fetch chat metadata", { error: String(error2) });
338286
338353
  return {};
338287
338354
  }
338288
338355
  }
@@ -338304,7 +338371,7 @@ async function routeStreamDelta(sender, delta) {
338304
338371
  }
338305
338372
  async function resolveStreamingCapabilities(services, instance4, channel4, chatId, traceId, db2) {
338306
338373
  if (!instance4.agentStreamMode) {
338307
- log83.debug("Stream guard: agentStreamMode is falsy", {
338374
+ log84.debug("Stream guard: agentStreamMode is falsy", {
338308
338375
  instanceId: instance4.id,
338309
338376
  agentStreamMode: instance4.agentStreamMode,
338310
338377
  chatId
@@ -338313,7 +338380,7 @@ async function resolveStreamingCapabilities(services, instance4, channel4, chatI
338313
338380
  }
338314
338381
  const provider = await getAgentProvider(services, instance4, db2);
338315
338382
  if (!provider?.triggerStream) {
338316
- log83.debug("Stream guard: provider has no triggerStream", {
338383
+ log84.debug("Stream guard: provider has no triggerStream", {
338317
338384
  instanceId: instance4.id,
338318
338385
  hasProvider: !!provider,
338319
338386
  chatId
@@ -338322,7 +338389,7 @@ async function resolveStreamingCapabilities(services, instance4, channel4, chatI
338322
338389
  }
338323
338390
  const plugin6 = await getPlugin(channel4);
338324
338391
  if (!plugin6?.capabilities?.canStreamResponse || !plugin6.createStreamSender) {
338325
- log83.debug("Stream guard: channel does not support streaming", {
338392
+ log84.debug("Stream guard: channel does not support streaming", {
338326
338393
  channel: channel4,
338327
338394
  canStream: plugin6?.capabilities?.canStreamResponse,
338328
338395
  chatId
@@ -338331,7 +338398,7 @@ async function resolveStreamingCapabilities(services, instance4, channel4, chatI
338331
338398
  }
338332
338399
  const streamKey = `${instance4.id}:${chatId}`;
338333
338400
  if (activeStreams.has(streamKey)) {
338334
- log83.info("Stream guard: parallel stream blocked, falling back to accumulate", {
338401
+ log84.info("Stream guard: parallel stream blocked, falling back to accumulate", {
338335
338402
  instanceId: instance4.id,
338336
338403
  chatId,
338337
338404
  traceId
@@ -338354,7 +338421,7 @@ async function consumeStream(generator, sender, instanceId, chatId, traceId) {
338354
338421
  hadContent = true;
338355
338422
  await routeStreamDelta(sender, delta);
338356
338423
  }
338357
- log83.info("Streaming response complete", {
338424
+ log84.info("Streaming response complete", {
338358
338425
  instanceId,
338359
338426
  chatId,
338360
338427
  durationMs: Date.now() - startTime3,
@@ -338482,7 +338549,7 @@ async function dispatchViaStreamingProvider(services, instance4, messages4, trig
338482
338549
  }
338483
338550
  return streamResult;
338484
338551
  } catch (err) {
338485
- log83.error("Streaming dispatch failed, falling back", {
338552
+ log84.error("Streaming dispatch failed, falling back", {
338486
338553
  instanceId: instance4.id,
338487
338554
  chatId,
338488
338555
  error: String(err),
@@ -338532,20 +338599,26 @@ async function buildContextMessages(services, instance4, chatId, currentMessageI
338532
338599
  if (!chat2) {
338533
338600
  return [];
338534
338601
  }
338602
+ const effectiveLimit = chat2.chatType === "group" ? historyLimit : Math.min(historyLimit, DM_HISTORY_LIMIT);
338535
338603
  const messagesResult = await services.messages.list({
338536
338604
  chatId: chat2.id,
338537
- limit: historyLimit
338605
+ limit: effectiveLimit
338538
338606
  });
338539
338607
  const recentMessages = messagesResult.items;
338540
338608
  if (!recentMessages || recentMessages.length === 0) {
338541
338609
  return [];
338542
338610
  }
338543
338611
  const lastBotMessageIndex = recentMessages.findIndex((msg) => msg.isFromMe === true);
338544
- if (lastBotMessageIndex === -1 || lastBotMessageIndex === 0) {
338545
- return [];
338546
- }
338547
338612
  const currentMessageIdSet = new Set(currentMessageIds.filter(Boolean));
338548
- const contextMsgs = recentMessages.slice(0, lastBotMessageIndex).filter((msg) => !currentMessageIdSet.has(msg.externalId));
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
+ }
338549
338622
  if (contextMsgs.length === 0) {
338550
338623
  return [];
338551
338624
  }
@@ -338560,7 +338633,7 @@ async function buildContextMessages(services, instance4, chatId, currentMessageI
338560
338633
  return `[${name}${time3 ? ` - ${time3}` : ""}] ${text3}`;
338561
338634
  });
338562
338635
  } catch (error2) {
338563
- log83.warn("Failed to build context messages", { error: error2, chatId, instanceId: instance4.id });
338636
+ log84.warn("Failed to build context messages", { error: error2, chatId, instanceId: instance4.id });
338564
338637
  return [];
338565
338638
  }
338566
338639
  }
@@ -338595,7 +338668,7 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
338595
338668
  return false;
338596
338669
  const { messageTexts, mediaFiles } = await prepareAgentContent(services, instance4, messages4);
338597
338670
  if (!messageTexts.length && !mediaFiles.length) {
338598
- log83.debug("No text or media content for provider trigger, skipping");
338671
+ log84.debug("No text or media content for provider trigger, skipping");
338599
338672
  return false;
338600
338673
  }
338601
338674
  if (!messageTexts.length && mediaFiles.length) {
@@ -338631,7 +338704,7 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
338631
338704
  recordJourneyCheckpoint(correlationId, "T9", JOURNEY_STAGES.T9);
338632
338705
  await forwardToChainedInstance(instance4, parts, correlationId, messages4);
338633
338706
  }
338634
- log83.info("Agent response via IAgentProvider", {
338707
+ log84.info("Agent response via IAgentProvider", {
338635
338708
  instanceId: instance4.id,
338636
338709
  chatId,
338637
338710
  parts: result?.parts.length ?? 0,
@@ -338645,14 +338718,14 @@ async function dispatchViaProvider(services, instance4, messages4, triggerType,
338645
338718
  async function dispatchViaLegacy(services, instance4, messages4, triggerType, channel4, chatId, senderId, personId, senderName, traceId, perThreadExtraContext, senderAgentId) {
338646
338719
  const { messageTexts, mediaFiles } = await prepareAgentContent(services, instance4, messages4);
338647
338720
  if (perThreadExtraContext?.length) {
338648
- log83.warn("per_thread context available but legacy dispatch path has limited support \u2014 prepending as text", {
338721
+ log84.warn("per_thread context available but legacy dispatch path has limited support \u2014 prepending as text", {
338649
338722
  instanceId: instance4.id,
338650
338723
  contextCount: perThreadExtraContext.length
338651
338724
  });
338652
338725
  messageTexts.unshift(...perThreadExtraContext);
338653
338726
  }
338654
338727
  if (!messageTexts.length && !mediaFiles.length) {
338655
- log83.debug("No text or media content in messages, skipping agent call");
338728
+ log84.debug("No text or media content in messages, skipping agent call");
338656
338729
  return;
338657
338730
  }
338658
338731
  if (!messageTexts.length && mediaFiles.length) {
@@ -338686,7 +338759,7 @@ async function dispatchViaLegacy(services, instance4, messages4, triggerType, ch
338686
338759
  recordJourneyCheckpoint(correlationId, "T8", JOURNEY_STAGES.T8);
338687
338760
  await sendResponseParts(channel4, instance4.id, chatId, parts, getSplitDelayConfig(instance4), _fmtMode, replyTo, correlationId, senderAgentId);
338688
338761
  recordJourneyCheckpoint(correlationId, "T9", JOURNEY_STAGES.T9);
338689
- log83.info("Agent response via legacy runner", {
338762
+ log84.info("Agent response via legacy runner", {
338690
338763
  instanceId: instance4.id,
338691
338764
  chatId,
338692
338765
  parts: result.parts.length,
@@ -338706,14 +338779,14 @@ async function performSessionReset(instance4, sessionId, chatId, services, db2,
338706
338779
  sessionActuallyReset = true;
338707
338780
  }
338708
338781
  } catch (err) {
338709
- log83.warn("Failed to reset provider session", { error: String(err), instanceId: instance4.id, sessionId });
338782
+ log84.warn("Failed to reset provider session", { error: String(err), instanceId: instance4.id, sessionId });
338710
338783
  }
338711
338784
  if (sessionActuallyReset) {
338712
338785
  sessionActivityStore.recordReset(instance4.id, sessionId, Date.now());
338713
338786
  eventBus.publish("session.reset", { instanceId: instance4.id, sessionId, timestamp: Date.now() }, { instanceId: instance4.id, channelType: channel4 }).catch((err) => {
338714
- log83.warn("Failed to publish session.reset event", { error: String(err), instanceId: instance4.id, sessionId });
338787
+ log84.warn("Failed to publish session.reset event", { error: String(err), instanceId: instance4.id, sessionId });
338715
338788
  });
338716
- log83.info("Session reset triggered", {
338789
+ log84.info("Session reset triggered", {
338717
338790
  instanceId: instance4.id,
338718
338791
  sessionId,
338719
338792
  strategy: resetStrategy,
@@ -338756,7 +338829,7 @@ async function markPerThreadSessionInitialized(db2, instanceId, sessionId) {
338756
338829
  target: [agentSessions.instanceId, agentSessions.sessionKey],
338757
338830
  set: { lastUsedAt: now, updatedAt: now }
338758
338831
  });
338759
- log83.info("per_thread session initialized", { instanceId, sessionId });
338832
+ log84.info("per_thread session initialized", { instanceId, sessionId });
338760
338833
  }
338761
338834
  function mimeToContentType(mimeType) {
338762
338835
  if (mimeType.startsWith("audio/"))
@@ -338795,7 +338868,7 @@ async function processMediaFile(msg, mimeType, mediaService) {
338795
338868
  const result = await mediaService.process(localPath, mimeType, { caption: msg.content.caption });
338796
338869
  return result.success && result.content ? result.content : null;
338797
338870
  } catch (err) {
338798
- log83.debug("Media processing failed for history message", { error: String(err), messageId: msg.externalId });
338871
+ log84.debug("Media processing failed for history message", { error: String(err), messageId: msg.externalId });
338799
338872
  return null;
338800
338873
  } finally {
338801
338874
  if (ownedTempFile) {
@@ -338832,7 +338905,7 @@ async function processHistoryMessage2(msg, mediaService, reactFn, unreactFn) {
338832
338905
  async function fetchAndProcessThreadHistory(services, instance4, channel4, chatId, threadId2) {
338833
338906
  const plugin6 = await getPlugin(channel4);
338834
338907
  if (!plugin6?.fetchHistory) {
338835
- log83.debug("Channel plugin does not support fetchHistory", { instanceId: instance4.id, channel: channel4 });
338908
+ log84.debug("Channel plugin does not support fetchHistory", { instanceId: instance4.id, channel: channel4 });
338836
338909
  return [];
338837
338910
  }
338838
338911
  let historyResult;
@@ -338843,7 +338916,7 @@ async function fetchAndProcessThreadHistory(services, instance4, channel4, chatI
338843
338916
  limit: 200
338844
338917
  });
338845
338918
  } catch (err) {
338846
- log83.warn("fetchHistory failed, proceeding without thread context", {
338919
+ log84.warn("fetchHistory failed, proceeding without thread context", {
338847
338920
  error: String(err),
338848
338921
  instanceId: instance4.id,
338849
338922
  channel: channel4
@@ -338873,7 +338946,7 @@ async function fetchAndProcessThreadHistory(services, instance4, channel4, chatI
338873
338946
  const results = await Promise.all(batch.map((msg) => processHistoryMessage2(msg, mediaService, reactFn, unreactFn)));
338874
338947
  contextMessages.push(...results);
338875
338948
  }
338876
- log83.info("Thread history fetched", {
338949
+ log84.info("Thread history fetched", {
338877
338950
  instanceId: instance4.id,
338878
338951
  channel: channel4,
338879
338952
  chatId,
@@ -338884,7 +338957,7 @@ async function fetchAndProcessThreadHistory(services, instance4, channel4, chatI
338884
338957
  return contextMessages;
338885
338958
  }
338886
338959
  async function handlePerThreadLazyInit(services, instance4, channel4, chatId, threadId2, sessionId, db2) {
338887
- log83.info("per_thread lazy init", {
338960
+ log84.info("per_thread lazy init", {
338888
338961
  instanceId: instance4.id,
338889
338962
  channel: channel4,
338890
338963
  chatId,
@@ -338895,7 +338968,7 @@ async function handlePerThreadLazyInit(services, instance4, channel4, chatId, th
338895
338968
  try {
338896
338969
  await markPerThreadSessionInitialized(db2, instance4.id, sessionId);
338897
338970
  } catch (err) {
338898
- log83.warn("Failed to mark per_thread session initialized", {
338971
+ log84.warn("Failed to mark per_thread session initialized", {
338899
338972
  error: String(err),
338900
338973
  instanceId: instance4.id,
338901
338974
  sessionId
@@ -338937,7 +339010,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
338937
339010
  const ackHandle = startAck(plugin6, ackProvider, instance4.id, chatId, messageId, channel4, ackConfig);
338938
339011
  const personId = await resolvePersonId(services, channel4, instance4.id, senderId, firstMessage.metadata.personId);
338939
339012
  if (!personId) {
338940
- log83.warn("Could not resolve person ID, skipping agent", {
339013
+ log84.warn("Could not resolve person ID, skipping agent", {
338941
339014
  instanceId: instance4.id,
338942
339015
  chatId,
338943
339016
  senderId
@@ -338950,7 +339023,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
338950
339023
  const pushName = rawPayload.pushName ?? rawPayload.displayName;
338951
339024
  const senderName = await services.agentRunner.getSenderName(personId, pushName);
338952
339025
  const senderAgentId = await resolveDispatchSenderAgentId(db2, instance4);
338953
- log83.info("Dispatching to agent", {
339026
+ log84.info("Dispatching to agent", {
338954
339027
  instanceId: instance4.id,
338955
339028
  chatId,
338956
339029
  messageCount: messages4.length,
@@ -338963,7 +339036,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
338963
339036
  const agentAckMessage = inst.agentAckMessage ?? null;
338964
339037
  if (agentAckMessage) {
338965
339038
  sendTextMessage5(channel4, instance4.id, chatId, agentAckMessage).catch((err) => {
338966
- log83.warn("Failed to send agent ack message", { instanceId: instance4.id, chatId, error: String(err) });
339039
+ log84.warn("Failed to send agent ack message", { instanceId: instance4.id, chatId, error: String(err) });
338967
339040
  });
338968
339041
  }
338969
339042
  const perThreadExtraContext = await resolvePerThreadExtraContext(db2, services, instance4, channel4, chatId, senderId, firstMessage);
@@ -338976,7 +339049,7 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
338976
339049
  handled = await dispatchViaProvider(services, instance4, messages4, triggerType, channel4, chatId, senderId, personId, senderName, traceId, rawEvent, db2, perThreadExtraContext, senderAgentId);
338977
339050
  }
338978
339051
  } catch (providerError) {
338979
- log83.error("Provider dispatch failed, falling back to legacy", {
339052
+ log84.error("Provider dispatch failed, falling back to legacy", {
338980
339053
  instanceId: instance4.id,
338981
339054
  chatId,
338982
339055
  error: String(providerError),
@@ -338987,12 +339060,12 @@ async function processAgentResponse(services, instance4, messages4, triggerType,
338987
339060
  ackHandle.remove();
338988
339061
  return;
338989
339062
  }
338990
- log83.debug("No IAgentProvider resolved or provider failed, using legacy agentRunner path", {
339063
+ log84.debug("No IAgentProvider resolved or provider failed, using legacy agentRunner path", {
338991
339064
  instanceId: instance4.id
338992
339065
  });
338993
339066
  await dispatchViaLegacy(services, instance4, messages4, triggerType, channel4, chatId, senderId, personId, senderName, traceId, perThreadExtraContext, senderAgentId);
338994
339067
  } catch (error2) {
338995
- log83.error("Failed to process agent response", {
339068
+ log84.error("Failed to process agent response", {
338996
339069
  instanceId: instance4.id,
338997
339070
  chatId,
338998
339071
  error: String(error2),
@@ -339036,7 +339109,7 @@ function createOpenClawProviderInstance(provider, instance4) {
339036
339109
  }
339037
339110
  function createAgnoProvider(provider, instance4) {
339038
339111
  if (!provider.apiKey) {
339039
- log83.warn("Provider has no API key, falling back to legacy path", { providerId: provider.id });
339112
+ log84.warn("Provider has no API key, falling back to legacy path", { providerId: provider.id });
339040
339113
  return null;
339041
339114
  }
339042
339115
  const client = createProviderClient({
@@ -339058,7 +339131,7 @@ function createClaudeCodeProviderInstance(provider, instance4, db2) {
339058
339131
  const schemaConfig = provider.schemaConfig ?? {};
339059
339132
  const projectPath = schemaConfig.projectPath;
339060
339133
  if (!projectPath) {
339061
- log83.error("Claude Code provider missing projectPath", { providerId: provider.id });
339134
+ log84.error("Claude Code provider missing projectPath", { providerId: provider.id });
339062
339135
  throw new Error("Claude Code provider requires schemaConfig.projectPath");
339063
339136
  }
339064
339137
  return new ClaudeCodeAgentProvider(provider.id, provider.name, {
@@ -339089,7 +339162,7 @@ function createWebhookProvider(provider) {
339089
339162
  }
339090
339163
  function createAgUiProviderInstance(provider, instance4) {
339091
339164
  if (!provider.apiKey) {
339092
- log83.warn("AG-UI provider has no API key, falling back to legacy path", { providerId: provider.id });
339165
+ log84.warn("AG-UI provider has no API key, falling back to legacy path", { providerId: provider.id });
339093
339166
  return null;
339094
339167
  }
339095
339168
  const schemaConfig = provider.schemaConfig ?? {};
@@ -339108,7 +339181,7 @@ function createAgUiProviderInstance(provider, instance4) {
339108
339181
  }
339109
339182
  function createA2AProviderInstance(provider, instance4) {
339110
339183
  if (!provider.apiKey) {
339111
- log83.warn("A2A provider has no API key, falling back to legacy path", { providerId: provider.id });
339184
+ log84.warn("A2A provider has no API key, falling back to legacy path", { providerId: provider.id });
339112
339185
  return null;
339113
339186
  }
339114
339187
  const schemaConfig = provider.schemaConfig ?? {};
@@ -339130,7 +339203,7 @@ function createGenieProviderInstance(provider, instance4) {
339130
339203
  const agentName = typeof schemaConfig.agentName === "string" ? schemaConfig.agentName : "";
339131
339204
  const targetAgent = typeof schemaConfig.targetAgent === "string" ? schemaConfig.targetAgent : "";
339132
339205
  if (!agentName || !targetAgent) {
339133
- log83.error("Genie provider missing agentName or targetAgent in schemaConfig", { providerId: provider.id });
339206
+ log84.error("Genie provider missing agentName or targetAgent in schemaConfig", { providerId: provider.id });
339134
339207
  return null;
339135
339208
  }
339136
339209
  const teamName = typeof schemaConfig.teamName === "string" ? schemaConfig.teamName : "genie";
@@ -339169,7 +339242,7 @@ function resolveProvider(provider, instance4, db2) {
339169
339242
  agentProvider = createGenieProviderInstance(provider, instance4);
339170
339243
  break;
339171
339244
  default:
339172
- log83.debug("Provider schema not supported for IAgentProvider dispatch", {
339245
+ log84.debug("Provider schema not supported for IAgentProvider dispatch", {
339173
339246
  schema: provider.schema,
339174
339247
  providerId: provider.id
339175
339248
  });
@@ -339189,7 +339262,7 @@ async function getAgentProvider(services, instance4, db2) {
339189
339262
  return null;
339190
339263
  return resolveProvider(provider, instance4, db2);
339191
339264
  } catch (error2) {
339192
- log83.warn("Failed to resolve agent provider, falling back to legacy", {
339265
+ log84.warn("Failed to resolve agent provider, falling back to legacy", {
339193
339266
  instanceId: instance4.id,
339194
339267
  providerId: instance4.agentProviderId,
339195
339268
  error: String(error2)
@@ -339223,7 +339296,7 @@ async function applyInstanceFkAndReturn(db2, instance4) {
339223
339296
  }
339224
339297
  async function resolveEffectiveInstance(services, db2, instance4, chatId, personId) {
339225
339298
  if (!chatId) {
339226
- log83.debug("No internal chatId \u2014 using instance default agent", { instanceId: instance4.id, personId });
339299
+ log84.debug("No internal chatId \u2014 using instance default agent", { instanceId: instance4.id, personId });
339227
339300
  return applyInstanceFkAndReturn(db2, instance4);
339228
339301
  }
339229
339302
  const route = await services.routeResolver.resolve(instance4.id, chatId, personId);
@@ -339247,7 +339320,7 @@ async function resolveEffectiveInstance(services, db2, instance4, chatId, person
339247
339320
  if (effectiveAgentFkId) {
339248
339321
  await applyAgentFkOverrides(db2, effectiveAgentFkId, effectiveInstance);
339249
339322
  }
339250
- log83.debug("Route resolved and merged", {
339323
+ log84.debug("Route resolved and merged", {
339251
339324
  instanceId: instance4.id,
339252
339325
  chatId,
339253
339326
  personId,
@@ -339267,7 +339340,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
339267
339340
  const chat2 = await services.chats.findByExternalIdSmart(baseInstance.id, externalChatId);
339268
339341
  const internalChatId = chat2?.id;
339269
339342
  const { instance: instance4, routeId: _routeId } = await resolveEffectiveInstance(services, db2, baseInstance, internalChatId, metadata.personId);
339270
- log83.info("Dispatching reaction trigger", {
339343
+ log84.info("Dispatching reaction trigger", {
339271
339344
  instanceId: instance4.id,
339272
339345
  chatId: externalChatId,
339273
339346
  routeChatId: internalChatId ?? "none",
@@ -339307,7 +339380,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
339307
339380
  const _fmtMode = instance4.messageFormatMode ?? "convert";
339308
339381
  await sendResponseParts(channel4, instance4.id, externalChatId, result2.parts, getSplitDelayConfig(instance4), _fmtMode, payload.messageId);
339309
339382
  }
339310
- log83.info("Reaction trigger response via provider", {
339383
+ log84.info("Reaction trigger response via provider", {
339311
339384
  instanceId: instance4.id,
339312
339385
  chatId: externalChatId,
339313
339386
  routeChatId: internalChatId,
@@ -339319,7 +339392,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
339319
339392
  });
339320
339393
  return;
339321
339394
  }
339322
- log83.debug("No IAgentProvider resolved, using legacy agentRunner path", {
339395
+ log84.debug("No IAgentProvider resolved, using legacy agentRunner path", {
339323
339396
  instanceId: instance4.id
339324
339397
  });
339325
339398
  const personId = await resolvePersonId(services, channel4, instance4.id, payload.from, metadata.personId);
@@ -339345,7 +339418,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
339345
339418
  const _fmtMode = instance4.messageFormatMode ?? "convert";
339346
339419
  await sendResponseParts(channel4, instance4.id, externalChatId, result.parts, getSplitDelayConfig(instance4), _fmtMode, payload.messageId);
339347
339420
  }
339348
- log83.info("Reaction trigger response via legacy runner", {
339421
+ log84.info("Reaction trigger response via legacy runner", {
339349
339422
  instanceId: instance4.id,
339350
339423
  chatId: externalChatId,
339351
339424
  routeChatId: internalChatId,
@@ -339354,7 +339427,7 @@ async function processReactionTrigger(services, baseInstance, payload, metadata,
339354
339427
  traceId: metadata.traceId
339355
339428
  });
339356
339429
  } catch (error2) {
339357
- log83.error("Failed to process reaction trigger", {
339430
+ log84.error("Failed to process reaction trigger", {
339358
339431
  instanceId: instance4.id,
339359
339432
  chatId: externalChatId,
339360
339433
  routeChatId: internalChatId,
@@ -339396,7 +339469,7 @@ async function resolveLidMentionBot(chatsService, instanceId, ownerIdentifier, m
339396
339469
  for (const lidJid of lidMentions) {
339397
339470
  if (ownerIsLid && extractPhoneFromJid(lidJid) === ownerPhone) {
339398
339471
  messageContext.mentionsBot = true;
339399
- log83.debug("LID mention matches owner LID directly", { lidJid, ownerIdentifier });
339472
+ log84.debug("LID mention matches owner LID directly", { lidJid, ownerIdentifier });
339400
339473
  break;
339401
339474
  }
339402
339475
  try {
@@ -339405,14 +339478,14 @@ async function resolveLidMentionBot(chatsService, instanceId, ownerIdentifier, m
339405
339478
  const resolvedPhone = extractPhoneFromJid(mapping);
339406
339479
  if (resolvedPhone === ownerPhone) {
339407
339480
  messageContext.mentionsBot = true;
339408
- log83.debug("LID resolved to instance owner via DB", { lidJid, resolvedPhone, ownerPhone });
339481
+ log84.debug("LID resolved to instance owner via DB", { lidJid, resolvedPhone, ownerPhone });
339409
339482
  break;
339410
339483
  }
339411
339484
  if (ownerIsLid) {
339412
339485
  const ownerMapping = await chatsService.findLidMapping(instanceId, ownerIdentifier);
339413
339486
  if (ownerMapping && extractPhoneFromJid(ownerMapping) === resolvedPhone) {
339414
339487
  messageContext.mentionsBot = true;
339415
- log83.debug("LID resolved to owner via reverse mapping", { lidJid, resolvedPhone, ownerIdentifier });
339488
+ log84.debug("LID resolved to owner via reverse mapping", { lidJid, resolvedPhone, ownerIdentifier });
339416
339489
  break;
339417
339490
  }
339418
339491
  }
@@ -339446,15 +339519,15 @@ function needsLidMentionCheck(messageContext, instance4) {
339446
339519
  }
339447
339520
  async function shouldProcessMessage3(agentRunner, accessService, chatsService, messagesService, routeResolver, rateLimiter, payload, metadata) {
339448
339521
  if (!metadata.instanceId) {
339449
- log83.debug("No instanceId in metadata", { from: payload.from, chatId: payload.chatId });
339522
+ log84.debug("No instanceId in metadata", { from: payload.from, chatId: payload.chatId });
339450
339523
  return null;
339451
339524
  }
339452
339525
  if (payload.from === metadata.platformIdentityId) {
339453
- log83.debug("Message from self, skipping", { instanceId: metadata.instanceId, from: payload.from });
339526
+ log84.debug("Message from self, skipping", { instanceId: metadata.instanceId, from: payload.from });
339454
339527
  return null;
339455
339528
  }
339456
339529
  if (isTrashEmojiOnly(payload.content?.text)) {
339457
- log83.debug("Skipping trash emoji message (session-cleaner handles this)", {
339530
+ log84.debug("Skipping trash emoji message (session-cleaner handles this)", {
339458
339531
  instanceId: metadata.instanceId,
339459
339532
  chatId: payload.chatId
339460
339533
  });
@@ -339462,16 +339535,16 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
339462
339535
  }
339463
339536
  const chatId = payload.chatId ?? "";
339464
339537
  if (isBroadcastOrNewsletter(chatId)) {
339465
- log83.debug("Skipping newsletter/broadcast message", { instanceId: metadata.instanceId, chatId });
339538
+ log84.debug("Skipping newsletter/broadcast message", { instanceId: metadata.instanceId, chatId });
339466
339539
  return null;
339467
339540
  }
339468
339541
  const instance4 = await agentRunner.getInstanceWithProvider(metadata.instanceId);
339469
339542
  if (!instance4?.agentId) {
339470
- log83.debug("Instance has no agentId", { instanceId: metadata.instanceId });
339543
+ log84.debug("Instance has no agentId", { instanceId: metadata.instanceId });
339471
339544
  return null;
339472
339545
  }
339473
339546
  if (!instanceTriggersOnEvent(instance4, "message.received")) {
339474
- log83.debug("Instance does not trigger on message.received", { instanceId: instance4.id });
339547
+ log84.debug("Instance does not trigger on message.received", { instanceId: instance4.id });
339475
339548
  return null;
339476
339549
  }
339477
339550
  const messageContext = buildMessageContext(payload, instance4);
@@ -339481,7 +339554,7 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
339481
339554
  await resolveLidMentionBot(chatsService, metadata.instanceId, instance4.ownerIdentifier, mentionedJids, messageContext);
339482
339555
  }
339483
339556
  await resolveSlackThreadReply(chatsService, messagesService, instance4, payload, messageContext);
339484
- log83.debug("Message context built", {
339557
+ log84.debug("Message context built", {
339485
339558
  instanceId: instance4.id,
339486
339559
  chatId: payload.chatId,
339487
339560
  isDirectMessage: messageContext.isDirectMessage,
@@ -339491,7 +339564,7 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
339491
339564
  });
339492
339565
  const effectiveReplyFilter = await resolveEffectiveReplyFilter(chatsService, routeResolver, instance4.id, payload.chatId, instance4.agentReplyFilter);
339493
339566
  if (!shouldAgentReply(effectiveReplyFilter, messageContext)) {
339494
- log83.debug("Message did not pass reply filter", {
339567
+ log84.debug("Message did not pass reply filter", {
339495
339568
  instanceId: instance4.id,
339496
339569
  chatId: payload.chatId,
339497
339570
  messageContext,
@@ -339502,7 +339575,7 @@ async function shouldProcessMessage3(agentRunner, accessService, chatsService, m
339502
339575
  const channel4 = metadata.channelType ?? "whatsapp";
339503
339576
  const rateLimit = instance4.triggerRateLimit;
339504
339577
  if (!rateLimiter.isAllowed(payload.from, channel4, instance4.id, rateLimit ?? DEFAULT_RATE_LIMIT)) {
339505
- log83.info("Rate limited", { instanceId: instance4.id, from: payload.from, channel: channel4 });
339578
+ log84.info("Rate limited", { instanceId: instance4.id, from: payload.from, channel: channel4 });
339506
339579
  return null;
339507
339580
  }
339508
339581
  const accessDenied = await checkAccessWithFallback(accessService, instance4, payload, channel4);
@@ -339520,7 +339593,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
339520
339593
  const primaryId = payload.from ?? "";
339521
339594
  let accessResult = await accessService.checkAccess(instance4, primaryId, channel4);
339522
339595
  if (!accessResult.allowed && participantAlt && participantAlt !== primaryId) {
339523
- log83.warn("Access fallback to participantAlt", {
339596
+ log84.warn("Access fallback to participantAlt", {
339524
339597
  instanceId: instance4.id,
339525
339598
  primaryId,
339526
339599
  participantAlt,
@@ -339529,7 +339602,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
339529
339602
  accessResult = await accessService.checkAccess(instance4, participantAlt, channel4);
339530
339603
  }
339531
339604
  if (!accessResult.allowed && resolvedSenderPhone && resolvedSenderPhone !== primaryId && resolvedSenderPhone !== participantAlt) {
339532
- log83.debug("Access fallback to resolvedSenderPhone (LID\u2192phone)", {
339605
+ log84.debug("Access fallback to resolvedSenderPhone (LID\u2192phone)", {
339533
339606
  instanceId: instance4.id,
339534
339607
  primaryId,
339535
339608
  resolvedSenderPhone,
@@ -339539,7 +339612,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
339539
339612
  }
339540
339613
  if (accessResult.allowed)
339541
339614
  return false;
339542
- log83.info("Access denied", {
339615
+ log84.info("Access denied", {
339543
339616
  instanceId: instance4.id,
339544
339617
  chatId: payload.chatId,
339545
339618
  from: payload.from,
@@ -339548,7 +339621,7 @@ async function checkAccessWithFallback(accessService, instance4, payload, channe
339548
339621
  });
339549
339622
  if (accessResult.mode === "allowlist" && !accessResult.rule && primaryId) {
339550
339623
  accessService.requestPairing(instance4.id, primaryId).catch((err) => {
339551
- log83.warn("Failed to create pairing request", { instanceId: instance4.id, from: primaryId, error: String(err) });
339624
+ log84.warn("Failed to create pairing request", { instanceId: instance4.id, from: primaryId, error: String(err) });
339552
339625
  });
339553
339626
  }
339554
339627
  if (accessResult.rule?.action !== "silent_block" && accessResult.rule?.blockMessage) {
@@ -339565,20 +339638,20 @@ async function shouldProcessReaction(agentRunner, accessService, rateLimiter, re
339565
339638
  if (!instanceTriggersOnEvent(instance4, eventType))
339566
339639
  return null;
339567
339640
  if (!isReactionTrigger(instance4, payload.emoji)) {
339568
- log83.debug("Reaction emoji not in trigger list", { instanceId: instance4.id, emoji: payload.emoji });
339641
+ log84.debug("Reaction emoji not in trigger list", { instanceId: instance4.id, emoji: payload.emoji });
339569
339642
  return null;
339570
339643
  }
339571
339644
  const channel4 = metadata.channelType ?? "whatsapp";
339572
339645
  const rateLimit = instance4.triggerRateLimit;
339573
339646
  if (!rateLimiter.isAllowed(payload.from, channel4, instance4.id, rateLimit ?? DEFAULT_RATE_LIMIT)) {
339574
- log83.info("Rate limited reaction trigger", { instanceId: instance4.id, from: payload.from });
339647
+ log84.info("Rate limited reaction trigger", { instanceId: instance4.id, from: payload.from });
339575
339648
  return null;
339576
339649
  }
339577
339650
  const accessDenied = await checkAccessWithFallback(accessService, instance4, payload, channel4);
339578
339651
  if (accessDenied)
339579
339652
  return null;
339580
339653
  if (reactionDedup.isDuplicate(payload.messageId, payload.emoji, payload.from)) {
339581
- log83.debug("Duplicate reaction, skipping", {
339654
+ log84.debug("Duplicate reaction, skipping", {
339582
339655
  instanceId: instance4.id,
339583
339656
  messageId: payload.messageId,
339584
339657
  emoji: payload.emoji
@@ -339611,7 +339684,7 @@ async function shouldRespondViaGate(instance4, messages4, chatType, settings) {
339611
339684
  try {
339612
339685
  const apiKey = await settings.getSecret("gemini.api_key", "GEMINI_API_KEY");
339613
339686
  if (!apiKey) {
339614
- log83.warn("Gate: no Gemini API key, fail-open", { traceId });
339687
+ log84.warn("Gate: no Gemini API key, fail-open", { traceId });
339615
339688
  return true;
339616
339689
  }
339617
339690
  const controller = new AbortController;
@@ -339629,13 +339702,13 @@ async function shouldRespondViaGate(instance4, messages4, chatType, settings) {
339629
339702
  });
339630
339703
  clearTimeout(timeout);
339631
339704
  if (!res.ok) {
339632
- log83.warn("Gate: API error, fail-open", { traceId, status: res.status, durationMs: Date.now() - startMs });
339705
+ log84.warn("Gate: API error, fail-open", { traceId, status: res.status, durationMs: Date.now() - startMs });
339633
339706
  return true;
339634
339707
  }
339635
339708
  const data = await res.json();
339636
339709
  const answer = data.candidates?.[0]?.content?.parts?.[0]?.text?.trim().toLowerCase() ?? "";
339637
339710
  const shouldRespond = !answer.startsWith("skip");
339638
- log83.info("Gate decision", {
339711
+ log84.info("Gate decision", {
339639
339712
  traceId,
339640
339713
  decision: shouldRespond ? "respond" : "skip",
339641
339714
  rawAnswer: answer,
@@ -339649,14 +339722,14 @@ async function shouldRespondViaGate(instance4, messages4, chatType, settings) {
339649
339722
  clearTimeout(timeout);
339650
339723
  const errName = fetchError.name;
339651
339724
  if (errName === "AbortError") {
339652
- log83.warn("Gate: timeout, fail-open", { traceId, durationMs: Date.now() - startMs });
339725
+ log84.warn("Gate: timeout, fail-open", { traceId, durationMs: Date.now() - startMs });
339653
339726
  } else {
339654
- log83.warn("Gate: fetch error, fail-open", { traceId, error: String(fetchError) });
339727
+ log84.warn("Gate: fetch error, fail-open", { traceId, error: String(fetchError) });
339655
339728
  }
339656
339729
  return true;
339657
339730
  }
339658
339731
  } catch (error2) {
339659
- log83.warn("Gate: unexpected error, fail-open", { traceId, error: String(error2) });
339732
+ log84.warn("Gate: unexpected error, fail-open", { traceId, error: String(error2) });
339660
339733
  return true;
339661
339734
  }
339662
339735
  }
@@ -339666,7 +339739,7 @@ async function shouldSkipViaGate(triggerType, firstMsg, instance4, messages4, se
339666
339739
  const chatType = determineChatType(firstMsg.payload.chatId, firstMsg.metadata.channelType ?? "whatsapp", firstMsg.payload.rawPayload ?? {});
339667
339740
  const shouldRespond = await shouldRespondViaGate(instance4, messages4, chatType, services.settings);
339668
339741
  if (!shouldRespond) {
339669
- log83.info("Gate skipped response", {
339742
+ log84.info("Gate skipped response", {
339670
339743
  instanceId: instance4.id,
339671
339744
  chatId: firstMsg.payload.chatId,
339672
339745
  triggerType,
@@ -339689,7 +339762,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
339689
339762
  const instanceId = firstMsg.metadata.instanceId;
339690
339763
  const baseInstance = await agentRunner.getInstanceWithProvider(instanceId);
339691
339764
  if (!baseInstance) {
339692
- log83.warn("Instance not found for debounced messages", { instanceId });
339765
+ log84.warn("Instance not found for debounced messages", { instanceId });
339693
339766
  return;
339694
339767
  }
339695
339768
  const externalChatId = firstMsg.payload.chatId;
@@ -339737,7 +339810,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
339737
339810
  timestamp: event.timestamp
339738
339811
  }, effectiveDebounceConfig);
339739
339812
  } catch (error2) {
339740
- log83.error("Error processing message for dispatch", {
339813
+ log84.error("Error processing message for dispatch", {
339741
339814
  instanceId: metadata.instanceId,
339742
339815
  error: String(error2)
339743
339816
  });
@@ -339766,7 +339839,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
339766
339839
  traceId
339767
339840
  }, event, db2);
339768
339841
  } catch (error2) {
339769
- log83.error("Error processing reaction for dispatch", {
339842
+ log84.error("Error processing reaction for dispatch", {
339770
339843
  instanceId: metadata.instanceId,
339771
339844
  error: String(error2)
339772
339845
  });
@@ -339795,7 +339868,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
339795
339868
  traceId
339796
339869
  }, event, db2);
339797
339870
  } catch (error2) {
339798
- log83.error("Error processing reaction removal for dispatch", {
339871
+ log84.error("Error processing reaction removal for dispatch", {
339799
339872
  instanceId: metadata.instanceId,
339800
339873
  error: String(error2)
339801
339874
  });
@@ -339822,7 +339895,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
339822
339895
  debouncer.onUserTyping(metadata.instanceId, payload.chatId, debounceConfig);
339823
339896
  }
339824
339897
  } catch (error2) {
339825
- log83.debug("Error handling typing event", { error: String(error2) });
339898
+ log84.debug("Error handling typing event", { error: String(error2) });
339826
339899
  }
339827
339900
  }, {
339828
339901
  durable: "agent-dispatcher-typing",
@@ -339831,22 +339904,22 @@ async function setupAgentDispatcher(eventBus, services, db2) {
339831
339904
  startFrom: "last",
339832
339905
  concurrency: 10
339833
339906
  });
339834
- log83.info("Agent dispatcher initialized (message + reaction + reaction-removed triggers)");
339907
+ log84.info("Agent dispatcher initialized (message + reaction + reaction-removed triggers)");
339835
339908
  } catch (error2) {
339836
- log83.error("Failed to set up agent dispatcher", { error: String(error2) });
339909
+ log84.error("Failed to set up agent dispatcher", { error: String(error2) });
339837
339910
  clearInterval(cleanupInterval2);
339838
339911
  debouncer.clear();
339839
339912
  throw error2;
339840
339913
  }
339841
339914
  return async () => {
339842
- log83.info("Shutting down agent dispatcher");
339915
+ log84.info("Shutting down agent dispatcher");
339843
339916
  clearInterval(cleanupInterval2);
339844
339917
  debouncer.clear();
339845
339918
  const disposePromises = [];
339846
339919
  for (const [key, provider] of providerCache.entries()) {
339847
339920
  if (provider.dispose) {
339848
339921
  disposePromises.push(provider.dispose().catch((err) => {
339849
- log83.warn("Error disposing provider", { key, error: String(err) });
339922
+ log84.warn("Error disposing provider", { key, error: String(err) });
339850
339923
  }));
339851
339924
  }
339852
339925
  }
@@ -339856,7 +339929,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
339856
339929
  try {
339857
339930
  client.stop();
339858
339931
  } catch (err) {
339859
- log83.warn("Error stopping OpenClaw client", { providerId: id, error: String(err) });
339932
+ log84.warn("Error stopping OpenClaw client", { providerId: id, error: String(err) });
339860
339933
  }
339861
339934
  }));
339862
339935
  }
@@ -339864,7 +339937,7 @@ async function setupAgentDispatcher(eventBus, services, db2) {
339864
339937
  let timeoutId;
339865
339938
  const timeoutGuard = new Promise((resolve3) => {
339866
339939
  timeoutId = setTimeout(() => {
339867
- log83.warn("Dispatcher shutdown timed out after 5s, proceeding");
339940
+ log84.warn("Dispatcher shutdown timed out after 5s, proceeding");
339868
339941
  resolve3([]);
339869
339942
  }, 5000);
339870
339943
  });
@@ -339877,10 +339950,10 @@ async function setupAgentDispatcher(eventBus, services, db2) {
339877
339950
  }
339878
339951
  providerCache.clear();
339879
339952
  openclawClientPool.clear();
339880
- log83.info("Agent dispatcher shutdown complete");
339953
+ log84.info("Agent dispatcher shutdown complete");
339881
339954
  };
339882
339955
  }
339883
- var log83, 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;
339956
+ 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;
339884
339957
  var init_agent_dispatcher = __esm(() => {
339885
339958
  init_src2();
339886
339959
  init_src();
@@ -339891,9 +339964,10 @@ var init_agent_dispatcher = __esm(() => {
339891
339964
  init_sentry_scrub();
339892
339965
  init_agent_runner();
339893
339966
  init_loader2();
339967
+ init_message_debouncer();
339894
339968
  init_session_storage();
339895
339969
  init_src6();
339896
- log83 = createLogger("agent-dispatcher");
339970
+ log84 = createLogger("agent-dispatcher");
339897
339971
  CHANNEL_MESSAGE_LIMITS = {
339898
339972
  discord: 2000,
339899
339973
  "whatsapp-baileys": 65536,
@@ -339963,7 +340037,7 @@ async function setupSyncWorker(eventBus, services, channelRegistry2, database) {
339963
340037
  await eventBus.subscribe("sync.started", async (event) => {
339964
340038
  const payload = event.payload;
339965
340039
  const { jobId, instanceId, type, config: config4 } = payload;
339966
- log84.info("Processing sync job", { jobId, instanceId, type });
340040
+ log85.info("Processing sync job", { jobId, instanceId, type });
339967
340041
  try {
339968
340042
  await services.syncJobs.start(jobId);
339969
340043
  const instance4 = await services.instances.getById(instanceId);
@@ -339990,12 +340064,12 @@ async function setupSyncWorker(eventBus, services, channelRegistry2, database) {
339990
340064
  case "history-push":
339991
340065
  break;
339992
340066
  default:
339993
- log84.warn("Unknown sync type", { jobId, type });
340067
+ log85.warn("Unknown sync type", { jobId, type });
339994
340068
  await services.syncJobs.fail(jobId, `Unknown sync type: ${type}`);
339995
340069
  }
339996
340070
  } catch (error2) {
339997
340071
  const errorMessage = error2 instanceof Error ? error2.message : String(error2);
339998
- log84.error("Sync job failed", { jobId, error: errorMessage });
340072
+ log85.error("Sync job failed", { jobId, error: errorMessage });
339999
340073
  await services.syncJobs.fail(jobId, errorMessage);
340000
340074
  }
340001
340075
  }, {
@@ -340003,15 +340077,15 @@ async function setupSyncWorker(eventBus, services, channelRegistry2, database) {
340003
340077
  queue: "sync-workers",
340004
340078
  startFrom: "new"
340005
340079
  });
340006
- log84.info("Sync worker initialized - listening for sync.started events");
340080
+ log85.info("Sync worker initialized - listening for sync.started events");
340007
340081
  } catch (error2) {
340008
- log84.error("Failed to set up sync worker", { error: String(error2) });
340082
+ log85.error("Failed to set up sync worker", { error: String(error2) });
340009
340083
  throw error2;
340010
340084
  }
340011
340085
  }
340012
340086
  async function buildWhatsAppAnchors(instanceId, _services) {
340013
340087
  if (!db2) {
340014
- log84.warn("Database not available for building anchors");
340088
+ log85.warn("Database not available for building anchors");
340015
340089
  return [];
340016
340090
  }
340017
340091
  const result = await db2.execute(sql`
@@ -340047,20 +340121,20 @@ async function buildWhatsAppAnchors(instanceId, _services) {
340047
340121
  });
340048
340122
  }
340049
340123
  }
340050
- log84.info("Built WhatsApp anchors", { instanceId, anchorCount: anchors.length });
340124
+ log85.info("Built WhatsApp anchors", { instanceId, anchorCount: anchors.length });
340051
340125
  return anchors;
340052
340126
  }
340053
340127
  function buildAnchorsForExplicitChatJids(jobId, chatJids, dbAnchors) {
340054
- log84.info("Using explicit chatJids for sync", { jobId, chatJids });
340128
+ log85.info("Using explicit chatJids for sync", { jobId, chatJids });
340055
340129
  const anchors = [];
340056
340130
  for (const jid of chatJids) {
340057
340131
  const dbAnchor = dbAnchors.find((a3) => a3.chatJid === jid);
340058
340132
  if (dbAnchor) {
340059
- log84.debug("Found DB anchor for chatJid", { jobId, chatJid: jid, anchorId: dbAnchor.messageKey.id });
340133
+ log85.debug("Found DB anchor for chatJid", { jobId, chatJid: jid, anchorId: dbAnchor.messageKey.id });
340060
340134
  anchors.push(dbAnchor);
340061
340135
  continue;
340062
340136
  }
340063
- log84.debug("No DB anchor for chatJid, will fetch recent", { jobId, chatJid: jid });
340137
+ log85.debug("No DB anchor for chatJid, will fetch recent", { jobId, chatJid: jid });
340064
340138
  anchors.push({
340065
340139
  chatJid: jid,
340066
340140
  messageKey: { remoteJid: jid, id: "", fromMe: false },
@@ -340086,7 +340160,7 @@ async function discoverAnchorsFromPlugin(jobId, instanceId, plugin6, dbAnchors,
340086
340160
  discovered.push({ chatJid: jid, messageKey: { remoteJid: jid, id: "", fromMe: false }, timestamp: Date.now() });
340087
340161
  }
340088
340162
  if (discovered.length > 0) {
340089
- log84.info("Discovered chats from DB + Baileys not in anchors", {
340163
+ log85.info("Discovered chats from DB + Baileys not in anchors", {
340090
340164
  jobId,
340091
340165
  discoveredCount: discovered.length,
340092
340166
  fromDb: dbExternalIds.length,
@@ -340107,7 +340181,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
340107
340181
  throw new Error(`No plugin found for channel type: ${channelType}`);
340108
340182
  }
340109
340183
  if (!("fetchHistory" in plugin6) || typeof plugin6.fetchHistory !== "function") {
340110
- log84.warn("Plugin does not support fetchHistory", { channelType });
340184
+ log85.warn("Plugin does not support fetchHistory", { channelType });
340111
340185
  await services.syncJobs.complete(jobId);
340112
340186
  return;
340113
340187
  }
@@ -340116,7 +340190,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
340116
340190
  let fetched = 0;
340117
340191
  let stored = 0;
340118
340192
  let duplicates = 0;
340119
- log84.info("Starting message sync", {
340193
+ log85.info("Starting message sync", {
340120
340194
  jobId,
340121
340195
  instanceId,
340122
340196
  channelType,
@@ -340126,13 +340200,13 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
340126
340200
  if (channelType === "whatsapp-baileys" && config4.chatJids?.length) {
340127
340201
  const dbAnchors = await buildWhatsAppAnchors(instanceId, services);
340128
340202
  anchors = await resolveWhatsAppAnchors(jobId, instanceId, config4, plugin6, dbAnchors, services);
340129
- log84.info("WhatsApp per-chat active sync", { jobId, anchorCount: anchors.length, chatJids: config4.chatJids });
340203
+ log85.info("WhatsApp per-chat active sync", { jobId, anchorCount: anchors.length, chatJids: config4.chatJids });
340130
340204
  } else if (channelType === "whatsapp-baileys") {
340131
340205
  const dbAnchors = await buildWhatsAppAnchors(instanceId, services);
340132
340206
  const discoveredAnchors = await discoverAnchorsFromPlugin(jobId, instanceId, plugin6, dbAnchors, services);
340133
340207
  anchors = [...dbAnchors, ...discoveredAnchors];
340134
340208
  if (anchors.length > 0) {
340135
- log84.info("WhatsApp default sync with DB+cache discovery", {
340209
+ log85.info("WhatsApp default sync with DB+cache discovery", {
340136
340210
  jobId,
340137
340211
  instanceId,
340138
340212
  dbAnchorCount: dbAnchors.length,
@@ -340140,7 +340214,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
340140
340214
  totalAnchors: anchors.length
340141
340215
  });
340142
340216
  } else {
340143
- log84.info("WhatsApp passive sync (no prior data)", { jobId, instanceId });
340217
+ log85.info("WhatsApp passive sync (no prior data)", { jobId, instanceId });
340144
340218
  }
340145
340219
  }
340146
340220
  const fetchOptions = {
@@ -340182,7 +340256,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
340182
340256
  });
340183
340257
  stored++;
340184
340258
  } catch (error2) {
340185
- log84.warn("Failed to store synced message", {
340259
+ log85.warn("Failed to store synced message", {
340186
340260
  externalId: msg.externalId,
340187
340261
  error: String(error2)
340188
340262
  });
@@ -340199,7 +340273,7 @@ async function processMessageSync(jobId, instanceId, channelType, config4, servi
340199
340273
  duplicates
340200
340274
  });
340201
340275
  await services.syncJobs.complete(jobId);
340202
- log84.info("Message sync completed", {
340276
+ log85.info("Message sync completed", {
340203
340277
  jobId,
340204
340278
  fetched,
340205
340279
  stored,
@@ -340246,14 +340320,14 @@ async function processContactsSync(jobId, instanceId, channelType, config4, serv
340246
340320
  throw new Error(`No plugin found for channel type: ${channelType}`);
340247
340321
  }
340248
340322
  if (!("fetchContacts" in plugin6) || typeof plugin6.fetchContacts !== "function") {
340249
- log84.warn("Plugin does not support fetchContacts", { channelType });
340323
+ log85.warn("Plugin does not support fetchContacts", { channelType });
340250
340324
  await services.syncJobs.complete(jobId);
340251
340325
  return;
340252
340326
  }
340253
340327
  let fetched = 0;
340254
340328
  let stored = 0;
340255
340329
  let linked = 0;
340256
- log84.info("Starting contacts sync", {
340330
+ log85.info("Starting contacts sync", {
340257
340331
  jobId,
340258
340332
  instanceId,
340259
340333
  channelType
@@ -340292,7 +340366,7 @@ async function processContactsSync(jobId, instanceId, channelType, config4, serv
340292
340366
  await updateDmChatName(services, instanceId, c.platformUserId, c.name);
340293
340367
  }
340294
340368
  } catch (error2) {
340295
- log84.warn("Failed to store synced contact", {
340369
+ log85.warn("Failed to store synced contact", {
340296
340370
  platformUserId: c.platformUserId,
340297
340371
  error: String(error2)
340298
340372
  });
@@ -340309,7 +340383,7 @@ async function processContactsSync(jobId, instanceId, channelType, config4, serv
340309
340383
  duplicates: 0
340310
340384
  });
340311
340385
  await services.syncJobs.complete(jobId);
340312
- log84.info("Contacts sync completed", {
340386
+ log85.info("Contacts sync completed", {
340313
340387
  jobId,
340314
340388
  fetched,
340315
340389
  stored,
@@ -340323,7 +340397,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
340323
340397
  }
340324
340398
  const fetchMethod = channelType === "discord" ? "fetchGuilds" : "fetchGroups";
340325
340399
  if (!(fetchMethod in plugin6) || typeof plugin6[fetchMethod] !== "function") {
340326
- log84.warn(`Plugin does not support ${fetchMethod}`, { channelType });
340400
+ log85.warn(`Plugin does not support ${fetchMethod}`, { channelType });
340327
340401
  await services.syncJobs.complete(jobId);
340328
340402
  return;
340329
340403
  }
@@ -340334,7 +340408,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
340334
340408
  let fetched = 0;
340335
340409
  let stored = 0;
340336
340410
  let updated = 0;
340337
- log84.info("Starting groups sync", {
340411
+ log85.info("Starting groups sync", {
340338
340412
  jobId,
340339
340413
  instanceId,
340340
340414
  channelType
@@ -340384,7 +340458,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
340384
340458
  stored++;
340385
340459
  }
340386
340460
  } catch (error2) {
340387
- log84.warn("Failed to store synced group", {
340461
+ log85.warn("Failed to store synced group", {
340388
340462
  externalId: g2.externalId,
340389
340463
  error: String(error2)
340390
340464
  });
@@ -340425,7 +340499,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
340425
340499
  stored++;
340426
340500
  }
340427
340501
  } catch (error2) {
340428
- log84.warn("Failed to store synced guild", {
340502
+ log85.warn("Failed to store synced guild", {
340429
340503
  externalId: g2.externalId,
340430
340504
  error: String(error2)
340431
340505
  });
@@ -340440,7 +340514,7 @@ async function processGroupsSync(jobId, instanceId, channelType, _config, servic
340440
340514
  duplicates: updated
340441
340515
  });
340442
340516
  await services.syncJobs.complete(jobId);
340443
- log84.info("Groups sync completed", {
340517
+ log85.info("Groups sync completed", {
340444
340518
  jobId,
340445
340519
  fetched,
340446
340520
  stored,
@@ -340550,12 +340624,12 @@ async function setupHistoryPushTracker(eventBus, services) {
340550
340624
  throw error2;
340551
340625
  }
340552
340626
  }
340553
- var log84, RATE_LIMITS2, db2 = null, historyPushLog;
340627
+ var log85, RATE_LIMITS2, db2 = null, historyPushLog;
340554
340628
  var init_sync_worker = __esm(() => {
340555
340629
  init_src();
340556
340630
  init_src4();
340557
340631
  init_drizzle_orm();
340558
- log84 = createLogger("sync-worker");
340632
+ log85 = createLogger("sync-worker");
340559
340633
  RATE_LIMITS2 = {
340560
340634
  "whatsapp-baileys": 30,
340561
340635
  discord: 50,
@@ -340619,15 +340693,15 @@ async function handleTrashEmojiMessage(services, db3, event) {
340619
340693
  return;
340620
340694
  if (!isTrashEmojiOnly2(content.text))
340621
340695
  return;
340622
- log85.info("Trash emoji detected, clearing session", { instanceId, chatId, from });
340696
+ log86.info("Trash emoji detected, clearing session", { instanceId, chatId, from });
340623
340697
  try {
340624
340698
  const { sessionId, sessionStrategy } = await clearAgentSession(services, db3, instanceId, from, chatId);
340625
- log85.info("Session cleared successfully", { instanceId, sessionId, sessionStrategy });
340699
+ log86.info("Session cleared successfully", { instanceId, sessionId, sessionStrategy });
340626
340700
  try {
340627
340701
  await sendMessage(services, instanceId, chatId, "\u2705 Conversa limpa! Sua sess\xE3o com o assistente foi resetada.");
340628
- log85.info("Sent session cleared confirmation", { instanceId, chatId });
340702
+ log86.info("Sent session cleared confirmation", { instanceId, chatId });
340629
340703
  } catch (sendError) {
340630
- log85.error("Failed to send confirmation message", { instanceId, chatId, error: String(sendError) });
340704
+ log86.error("Failed to send confirmation message", { instanceId, chatId, error: String(sendError) });
340631
340705
  }
340632
340706
  } catch (error2) {
340633
340707
  const errorMessage = error2 instanceof Error ? error2.message : String(error2);
@@ -340638,14 +340712,14 @@ async function handleTrashEmojiMessage(services, db3, event) {
340638
340712
  "Session clearing not supported for"
340639
340713
  ];
340640
340714
  if (skippableErrors.some((e) => errorMessage.includes(e))) {
340641
- log85.debug("Session clearing skipped", { instanceId, reason: errorMessage });
340715
+ log86.debug("Session clearing skipped", { instanceId, reason: errorMessage });
340642
340716
  return;
340643
340717
  }
340644
- log85.error("Failed to clear session", { instanceId, chatId, error: errorMessage });
340718
+ log86.error("Failed to clear session", { instanceId, chatId, error: errorMessage });
340645
340719
  try {
340646
340720
  await sendMessage(services, instanceId, chatId, "\u274C Erro ao limpar sess\xE3o. Tente novamente.");
340647
340721
  } catch (sendError) {
340648
- log85.error("Failed to send error message", { instanceId, chatId, error: String(sendError) });
340722
+ log86.error("Failed to send error message", { instanceId, chatId, error: String(sendError) });
340649
340723
  }
340650
340724
  }
340651
340725
  }
@@ -340659,13 +340733,13 @@ async function setupSessionCleaner(eventBus, services, db3) {
340659
340733
  startFrom: "last",
340660
340734
  concurrency: 5
340661
340735
  });
340662
- log85.info("Session cleaner initialized");
340736
+ log86.info("Session cleaner initialized");
340663
340737
  } catch (error2) {
340664
- log85.error("Failed to set up session cleaner", { error: String(error2) });
340738
+ log86.error("Failed to set up session cleaner", { error: String(error2) });
340665
340739
  throw error2;
340666
340740
  }
340667
340741
  }
340668
- var log85;
340742
+ var log86;
340669
340743
  var init_session_cleaner = __esm(() => {
340670
340744
  init_src();
340671
340745
  init_src4();
@@ -340673,7 +340747,7 @@ var init_session_cleaner = __esm(() => {
340673
340747
  init_agent_runner();
340674
340748
  init_agent_dispatcher();
340675
340749
  init_loader2();
340676
- log85 = createLogger("session-cleaner");
340750
+ log86 = createLogger("session-cleaner");
340677
340751
  });
340678
340752
 
340679
340753
  // ../api/src/plugins/instance-monitor.ts
@@ -341211,14 +341285,14 @@ async function sendInboxMessage(msg, inboxName, team, channelRegistry2, patterns
341211
341285
  return "ok";
341212
341286
  const parsed = parseMetadata(msg.text);
341213
341287
  if (!parsed.instance || !parsed.chat || !parsed.channel) {
341214
- log86.debug("Skipping message \u2014 missing routing metadata", { team, inboxName, from: msg.from });
341288
+ log87.debug("Skipping message \u2014 missing routing metadata", { team, inboxName, from: msg.from });
341215
341289
  return "ok";
341216
341290
  }
341217
341291
  if (!parsed.cleanText)
341218
341292
  return "ok";
341219
341293
  const plugin6 = channelRegistry2.get(parsed.channel);
341220
341294
  if (!plugin6) {
341221
- log86.warn("Channel plugin not found", { channel: parsed.channel, team, inboxName });
341295
+ log87.warn("Channel plugin not found", { channel: parsed.channel, team, inboxName });
341222
341296
  return "ok";
341223
341297
  }
341224
341298
  const outgoing = {
@@ -341230,7 +341304,7 @@ async function sendInboxMessage(msg, inboxName, team, channelRegistry2, patterns
341230
341304
  try {
341231
341305
  const result = await plugin6.sendMessage(parsed.instance, outgoing);
341232
341306
  if (result.success) {
341233
- log86.info("Forwarded reply", {
341307
+ log87.info("Forwarded reply", {
341234
341308
  team,
341235
341309
  inboxName,
341236
341310
  channel: parsed.channel,
@@ -341240,11 +341314,11 @@ async function sendInboxMessage(msg, inboxName, team, channelRegistry2, patterns
341240
341314
  messageId: result.messageId
341241
341315
  });
341242
341316
  } else {
341243
- log86.error("sendMessage failed", { team, inboxName, channel: parsed.channel, error: result.error });
341317
+ log87.error("sendMessage failed", { team, inboxName, channel: parsed.channel, error: result.error });
341244
341318
  }
341245
341319
  return "ok";
341246
341320
  } catch (err) {
341247
- log86.error("sendMessage threw", { team, inboxName, error: String(err) });
341321
+ log87.error("sendMessage threw", { team, inboxName, error: String(err) });
341248
341322
  return "retry";
341249
341323
  }
341250
341324
  }
@@ -341268,7 +341342,7 @@ async function processInbox(inboxName, team, state, channelRegistry2, patterns)
341268
341342
  const entry = state.cursors[cursorKey] ?? { lastIndex: 0 };
341269
341343
  let { lastIndex } = entry;
341270
341344
  if (lastIndex > inbox.length) {
341271
- log86.warn("Inbox shrank (truncated/rotated), resetting cursor", {
341345
+ log87.warn("Inbox shrank (truncated/rotated), resetting cursor", {
341272
341346
  team,
341273
341347
  inboxName,
341274
341348
  oldCursor: lastIndex,
@@ -341321,20 +341395,20 @@ async function setupInboxBridge(services, channelRegistry2) {
341321
341395
  let patterns = [];
341322
341396
  try {
341323
341397
  patterns = await discoverAgentPatterns(services);
341324
- log86.info("Inbox bridge started", {
341398
+ log87.info("Inbox bridge started", {
341325
341399
  patterns: patterns.map((p2) => ({ raw: p2.raw, isTemplate: p2.isTemplate, prefix: p2.prefix }))
341326
341400
  });
341327
341401
  } catch (err) {
341328
- log86.warn("Initial agent discovery failed", { error: String(err) });
341402
+ log87.warn("Initial agent discovery failed", { error: String(err) });
341329
341403
  }
341330
341404
  const discoveryTimer = setInterval(async () => {
341331
341405
  try {
341332
341406
  patterns = await discoverAgentPatterns(services);
341333
- log86.debug("Agent patterns refreshed", {
341407
+ log87.debug("Agent patterns refreshed", {
341334
341408
  patterns: patterns.map((p2) => ({ raw: p2.raw, isTemplate: p2.isTemplate, prefix: p2.prefix }))
341335
341409
  });
341336
341410
  } catch (err) {
341337
- log86.warn("Agent discovery refresh failed", { error: String(err) });
341411
+ log87.warn("Agent discovery refresh failed", { error: String(err) });
341338
341412
  }
341339
341413
  }, DISCOVERY_INTERVAL_MS);
341340
341414
  discoveryTimer.unref();
@@ -341346,7 +341420,7 @@ async function setupInboxBridge(services, channelRegistry2) {
341346
341420
  try {
341347
341421
  await pollInboxes(patterns, channelRegistry2);
341348
341422
  } catch (err) {
341349
- log86.error("Poll cycle error", { error: String(err) });
341423
+ log87.error("Poll cycle error", { error: String(err) });
341350
341424
  } finally {
341351
341425
  polling = false;
341352
341426
  }
@@ -341355,13 +341429,13 @@ async function setupInboxBridge(services, channelRegistry2) {
341355
341429
  return async () => {
341356
341430
  clearInterval(discoveryTimer);
341357
341431
  clearInterval(pollTimer);
341358
- log86.info("Inbox bridge stopped");
341432
+ log87.info("Inbox bridge stopped");
341359
341433
  };
341360
341434
  }
341361
- var log86, CLAUDE_TEAMS_DIR, BRIDGE_STATE_PATH, POLL_INTERVAL_MS2 = 2000, DISCOVERY_INTERVAL_MS = 60000, CURSOR_TTL_MS;
341435
+ var log87, CLAUDE_TEAMS_DIR, BRIDGE_STATE_PATH, POLL_INTERVAL_MS2 = 2000, DISCOVERY_INTERVAL_MS = 60000, CURSOR_TTL_MS;
341362
341436
  var init_inbox_bridge = __esm(() => {
341363
341437
  init_src();
341364
- log86 = createLogger("inbox-bridge");
341438
+ log87 = createLogger("inbox-bridge");
341365
341439
  CLAUDE_TEAMS_DIR = join25(homedir3(), ".claude", "teams");
341366
341440
  BRIDGE_STATE_PATH = join25(homedir3(), ".claude", "bridge", "state.json");
341367
341441
  CURSOR_TTL_MS = 24 * 60 * 60 * 1000;
@@ -341394,7 +341468,7 @@ function setupScheduler(services, channelRegistry2) {
341394
341468
  recordScheduledJob("dead-letter-auto-retry", "success", durationSec);
341395
341469
  const pendingCount = await services.deadLetters.getPendingCount();
341396
341470
  deadLettersPending.set(pendingCount);
341397
- log87.info("Dead letter auto-retry completed", result);
341471
+ log88.info("Dead letter auto-retry completed", result);
341398
341472
  } catch (err) {
341399
341473
  const durationSec = (Date.now() - startTime3) / 1000;
341400
341474
  recordScheduledJob("dead-letter-auto-retry", "failure", durationSec);
@@ -341416,7 +341490,7 @@ function setupScheduler(services, channelRegistry2) {
341416
341490
  recordScheduledJob("payload-cleanup", "success", durationSec);
341417
341491
  const stats = await services.payloadStore.getStats();
341418
341492
  payloadStorageSize.set(stats.totalSizeCompressed);
341419
- log87.info("Payload cleanup completed", { deleted });
341493
+ log88.info("Payload cleanup completed", { deleted });
341420
341494
  } catch (err) {
341421
341495
  const durationSec = (Date.now() - startTime3) / 1000;
341422
341496
  recordScheduledJob("payload-cleanup", "failure", durationSec);
@@ -341436,7 +341510,7 @@ function setupScheduler(services, channelRegistry2) {
341436
341510
  const deleted = await services.deadLetters.cleanupExpired();
341437
341511
  const durationSec = (Date.now() - startTime3) / 1000;
341438
341512
  recordScheduledJob("dead-letter-cleanup", "success", durationSec);
341439
- log87.info("Dead letter cleanup completed", { deleted });
341513
+ log88.info("Dead letter cleanup completed", { deleted });
341440
341514
  } catch (err) {
341441
341515
  const durationSec = (Date.now() - startTime3) / 1000;
341442
341516
  recordScheduledJob("dead-letter-cleanup", "failure", durationSec);
@@ -341465,7 +341539,7 @@ function setupScheduler(services, channelRegistry2) {
341465
341539
  });
341466
341540
  jobsCreated++;
341467
341541
  } catch (err) {
341468
- log87.warn("Failed to create contacts sync job for instance", {
341542
+ log88.warn("Failed to create contacts sync job for instance", {
341469
341543
  instanceId: instance4.id,
341470
341544
  error: String(err)
341471
341545
  });
@@ -341473,7 +341547,7 @@ function setupScheduler(services, channelRegistry2) {
341473
341547
  }
341474
341548
  const durationSec = (Date.now() - startTime3) / 1000;
341475
341549
  recordScheduledJob("contacts-sync-daily", "success", durationSec);
341476
- log87.info("Daily contacts sync jobs created", { jobsCreated, instanceCount: instances2.length });
341550
+ log88.info("Daily contacts sync jobs created", { jobsCreated, instanceCount: instances2.length });
341477
341551
  } catch (err) {
341478
341552
  const durationSec = (Date.now() - startTime3) / 1000;
341479
341553
  recordScheduledJob("contacts-sync-daily", "failure", durationSec);
@@ -341502,7 +341576,7 @@ function setupScheduler(services, channelRegistry2) {
341502
341576
  });
341503
341577
  jobsCreated++;
341504
341578
  } catch (err) {
341505
- log87.warn("Failed to create groups sync job for instance", {
341579
+ log88.warn("Failed to create groups sync job for instance", {
341506
341580
  instanceId: instance4.id,
341507
341581
  error: String(err)
341508
341582
  });
@@ -341510,7 +341584,7 @@ function setupScheduler(services, channelRegistry2) {
341510
341584
  }
341511
341585
  const durationSec = (Date.now() - startTime3) / 1000;
341512
341586
  recordScheduledJob("groups-sync-daily", "success", durationSec);
341513
- log87.info("Daily groups sync jobs created", { jobsCreated, instanceCount: instances2.length });
341587
+ log88.info("Daily groups sync jobs created", { jobsCreated, instanceCount: instances2.length });
341514
341588
  } catch (err) {
341515
341589
  const durationSec = (Date.now() - startTime3) / 1000;
341516
341590
  recordScheduledJob("groups-sync-daily", "failure", durationSec);
@@ -341539,7 +341613,7 @@ function setupScheduler(services, channelRegistry2) {
341539
341613
  }
341540
341614
  const durationSec = (Date.now() - startTime3) / 1000;
341541
341615
  recordScheduledJob("unread-count-refresh", "success", durationSec);
341542
- log87.debug("Refreshed unread counts", { instanceCount: waInstances.length });
341616
+ log88.debug("Refreshed unread counts", { instanceCount: waInstances.length });
341543
341617
  } catch (err) {
341544
341618
  const durationSec = (Date.now() - startTime3) / 1000;
341545
341619
  recordScheduledJob("unread-count-refresh", "failure", durationSec);
@@ -341550,7 +341624,7 @@ function setupScheduler(services, channelRegistry2) {
341550
341624
  });
341551
341625
  updateSchedulerMetrics();
341552
341626
  scheduler.start();
341553
- log87.info("Scheduler started", {
341627
+ log88.info("Scheduler started", {
341554
341628
  jobs: scheduler.listJobs().map((j) => ({
341555
341629
  name: j.name,
341556
341630
  cron: j.cron,
@@ -341570,14 +341644,14 @@ function updateSchedulerMetrics() {
341570
341644
  function stopScheduler() {
341571
341645
  const scheduler = getScheduler();
341572
341646
  scheduler.stop();
341573
- log87.info("Scheduler stopped");
341647
+ log88.info("Scheduler stopped");
341574
341648
  }
341575
- var log87;
341649
+ var log88;
341576
341650
  var init_scheduler2 = __esm(() => {
341577
341651
  init_src();
341578
341652
  init_esm5();
341579
341653
  init_sentry_scrub();
341580
- log87 = createLogger("scheduler:setup");
341654
+ log88 = createLogger("scheduler:setup");
341581
341655
  });
341582
341656
 
341583
341657
  // ../api/src/utils/startup-banner.ts
@@ -341651,12 +341725,12 @@ function printStartupBanner(options) {
341651
341725
  process.stdout.write(`${line3}
341652
341726
  `);
341653
341727
  }
341654
- log88.info("Server ready", { host, port, version: version4 });
341728
+ log89.info("Server ready", { host, port, version: version4 });
341655
341729
  }
341656
- var log88, COLORS3, BOX, ANSI_ESCAPE_PATTERN;
341730
+ var log89, COLORS3, BOX, ANSI_ESCAPE_PATTERN;
341657
341731
  var init_startup_banner = __esm(() => {
341658
341732
  init_src();
341659
- log88 = createLogger("api:startup");
341733
+ log89 = createLogger("api:startup");
341660
341734
  COLORS3 = {
341661
341735
  reset: "\x1B[0m",
341662
341736
  dim: "\x1B[2m",
@@ -341816,84 +341890,84 @@ function setupShutdownHandlers(server, earlyShutdown) {
341816
341890
  }
341817
341891
  async function setupEventBusServices(eventBus, services, db3) {
341818
341892
  if (!eventBus) {
341819
- log89.warn("Skipping event bus services (no event bus)");
341893
+ log90.warn("Skipping event bus services (no event bus)");
341820
341894
  return;
341821
341895
  }
341822
341896
  try {
341823
341897
  await setupMessagePersistence(eventBus, services);
341824
341898
  } catch (error2) {
341825
- log89.error("Failed to set up message persistence", { error: String(error2) });
341899
+ log90.error("Failed to set up message persistence", { error: String(error2) });
341826
341900
  }
341827
341901
  try {
341828
341902
  await setupMediaProcessor(eventBus, db3, services);
341829
341903
  } catch (error2) {
341830
- log89.error("Failed to set up media processor", { error: String(error2) });
341904
+ log90.error("Failed to set up media processor", { error: String(error2) });
341831
341905
  }
341832
341906
  try {
341833
341907
  globalDispatcherCleanup = await setupAgentResponder(eventBus, services, db3);
341834
341908
  } catch (error2) {
341835
- log89.error("Failed to set up agent dispatcher", { error: String(error2) });
341909
+ log90.error("Failed to set up agent dispatcher", { error: String(error2) });
341836
341910
  }
341837
341911
  if (globalChannelRegistry) {
341838
341912
  try {
341839
341913
  globalInboxBridgeCleanup = await setupInboxBridge(services, globalChannelRegistry);
341840
341914
  } catch (error2) {
341841
- log89.error("Failed to set up inbox bridge", { error: String(error2) });
341915
+ log90.error("Failed to set up inbox bridge", { error: String(error2) });
341842
341916
  }
341843
341917
  }
341844
341918
  try {
341845
341919
  await services.automations.startEngine({});
341846
341920
  } catch (error2) {
341847
- log89.error("Failed to start automation engine", { error: String(error2) });
341921
+ log90.error("Failed to start automation engine", { error: String(error2) });
341848
341922
  }
341849
341923
  try {
341850
341924
  await setupSessionCleaner(eventBus, services, db3);
341851
341925
  } catch (error2) {
341852
- log89.error("Failed to set up session cleaner", { error: String(error2) });
341926
+ log90.error("Failed to set up session cleaner", { error: String(error2) });
341853
341927
  }
341854
341928
  if (globalChannelRegistry) {
341855
341929
  try {
341856
341930
  await setupSyncWorker(eventBus, services, globalChannelRegistry, db3);
341857
341931
  } catch (error2) {
341858
- log89.error("Failed to set up sync worker", { error: String(error2) });
341932
+ log90.error("Failed to set up sync worker", { error: String(error2) });
341859
341933
  }
341860
341934
  }
341861
341935
  try {
341862
341936
  await setupHistoryPushTracker(eventBus, services);
341863
341937
  } catch (error2) {
341864
- log89.error("Failed to set up history-push tracker", { error: String(error2) });
341938
+ log90.error("Failed to set up history-push tracker", { error: String(error2) });
341865
341939
  }
341866
341940
  }
341867
341941
  async function waitForDatabaseReady(db3, maxAttempts = 30) {
341868
- log89.info("Waiting for database readiness");
341942
+ log90.info("Waiting for database readiness");
341869
341943
  for (let attempt = 1;attempt <= maxAttempts; attempt++) {
341870
341944
  try {
341871
341945
  await db3.execute(sql`SELECT 1`);
341872
- log89.info("Database ready", { attempt });
341946
+ log90.info("Database ready", { attempt });
341873
341947
  return;
341874
341948
  } catch {
341875
341949
  if (attempt === maxAttempts) {
341876
341950
  throw new Error(`Database not ready after ${maxAttempts} attempts`);
341877
341951
  }
341878
- log89.warn("Database not ready, retrying...", { attempt });
341952
+ log90.warn("Database not ready, retrying...", { attempt });
341879
341953
  await new Promise((resolve3) => setTimeout(resolve3, 1000));
341880
341954
  }
341881
341955
  }
341882
341956
  }
341883
341957
  async function main() {
341884
- log89.info("Starting Omni API v2");
341958
+ log90.info("Starting Omni API v2");
341885
341959
  enableDefaultMetrics();
341886
341960
  const pgserveConfig = resolvePgserveConfig();
341887
341961
  const databaseUrl = await startEmbeddedPgserve(pgserveConfig);
341888
- log89.info("Connecting to database");
341962
+ log90.info("Connecting to database");
341889
341963
  const db3 = createDb({ url: databaseUrl });
341890
341964
  const earlyShutdown = async () => {
341891
- log89.info("Shutdown during startup \u2014 cleaning up");
341965
+ log90.info("Shutdown during startup \u2014 cleaning up");
341892
341966
  try {
341893
341967
  await closeDb();
341894
341968
  await stopEmbeddedPgserve();
341895
341969
  } catch (err) {
341896
- log89.error("Cleanup failed during early shutdown", { error: String(err) });
341970
+ log90.error("Cleanup failed during early shutdown", { error: String(err) });
341897
341971
  } finally {
341898
341972
  process.exit(1);
341899
341973
  }
@@ -341907,7 +341981,7 @@ async function main() {
341907
341981
  await stopEmbeddedPgserve();
341908
341982
  throw error2;
341909
341983
  }
341910
- log89.info("Running database migrations");
341984
+ log90.info("Running database migrations");
341911
341985
  const migrationStart = Date.now();
341912
341986
  const MIGRATION_TIMEOUT_MS = 60000;
341913
341987
  try {
@@ -341920,7 +341994,7 @@ async function main() {
341920
341994
  await stopEmbeddedPgserve();
341921
341995
  throw error2;
341922
341996
  }
341923
- log89.info("Database migrations complete", { durationMs: Date.now() - migrationStart });
341997
+ log90.info("Database migrations complete", { durationMs: Date.now() - migrationStart });
341924
341998
  const eventBus = await connectToNats(db3);
341925
341999
  if (eventBus) {
341926
342000
  try {
@@ -341935,9 +342009,9 @@ async function main() {
341935
342009
  try {
341936
342010
  await services.settings.seedDefaults();
341937
342011
  } catch (error2) {
341938
- log89.error("Failed to seed default settings", { error: String(error2) });
342012
+ log90.error("Failed to seed default settings", { error: String(error2) });
341939
342013
  }
341940
- log89.info("Initializing API key");
342014
+ log90.info("Initializing API key");
341941
342015
  let apiKeyInfo;
341942
342016
  try {
341943
342017
  const keyResult = await services.apiKeys.initializePrimaryKey();
@@ -341947,21 +342021,21 @@ async function main() {
341947
342021
  isFromEnv: keyResult.isFromEnv
341948
342022
  };
341949
342023
  if (keyResult.isNew) {
341950
- log89.info("Generated new primary API key");
342024
+ log90.info("Generated new primary API key");
341951
342025
  } else if (keyResult.isFromEnv) {
341952
- log89.info("Using primary API key from environment");
342026
+ log90.info("Using primary API key from environment");
341953
342027
  } else {
341954
- log89.info("Using existing primary API key");
342028
+ log90.info("Using existing primary API key");
341955
342029
  }
341956
342030
  } catch (error2) {
341957
- log89.error("Failed to initialize primary API key", { error: String(error2) });
342031
+ log90.error("Failed to initialize primary API key", { error: String(error2) });
341958
342032
  }
341959
342033
  await setupEventBusServices(eventBus, services, db3);
341960
- log89.info("Starting scheduler");
342034
+ log90.info("Starting scheduler");
341961
342035
  setupScheduler(services, globalChannelRegistry);
341962
342036
  const server = startBunServer(app);
341963
342037
  printStartupBanner({
341964
- version: import__package2.default.version,
342038
+ version: import__package3.default.version,
341965
342039
  host: HOST,
341966
342040
  port: PORT,
341967
342041
  docsPath: "/api/v2/docs",
@@ -341971,7 +342045,7 @@ async function main() {
341971
342045
  });
341972
342046
  setupShutdownHandlers(server, earlyShutdown);
341973
342047
  }
341974
- var import__package2, log89, natsLog, pluginLog, shutdownLog, PORT, HOST, NATS_URL, globalEventBus = null, globalChannelRegistry = null, globalInstanceMonitor = null, globalDispatcherCleanup = null, globalInboxBridgeCleanup = null;
342048
+ var import__package3, log90, natsLog, pluginLog, shutdownLog, PORT, HOST, NATS_URL, globalEventBus = null, globalChannelRegistry = null, globalInstanceMonitor = null, globalDispatcherCleanup = null, globalInboxBridgeCleanup = null;
341975
342049
  var init_src7 = __esm(() => {
341976
342050
  init_instrument2();
341977
342051
  init_src();
@@ -341986,12 +342060,12 @@ var init_src7 = __esm(() => {
341986
342060
  init_startup_banner();
341987
342061
  init_app();
341988
342062
  init_services();
341989
- import__package2 = __toESM(require_package8(), 1);
342063
+ import__package3 = __toESM(require_package8(), 1);
341990
342064
  configureLogging({
341991
342065
  level: process.env.LOG_LEVEL ?? "info",
341992
342066
  format: process.env.LOG_FORMAT ?? "auto"
341993
342067
  });
341994
- log89 = createLogger("api:startup");
342068
+ log90 = createLogger("api:startup");
341995
342069
  natsLog = createLogger("api:nats");
341996
342070
  pluginLog = createLogger("api:plugins");
341997
342071
  shutdownLog = createLogger("api:shutdown");
@@ -341999,7 +342073,7 @@ var init_src7 = __esm(() => {
341999
342073
  HOST = process.env.API_HOST ?? "0.0.0.0";
342000
342074
  NATS_URL = process.env.NATS_URL ?? "nats://localhost:4222";
342001
342075
  main().catch((error2) => {
342002
- log89.error("Failed to start API server", { error: String(error2) });
342076
+ log90.error("Failed to start API server", { error: String(error2) });
342003
342077
  process.exit(1);
342004
342078
  });
342005
342079
  });
@@ -458917,6 +458991,9 @@ function fromJid(jid) {
458917
458991
  const id = jid.split("@")[0] || "";
458918
458992
  return { id, isGroup, isUser, isBroadcast, isLid };
458919
458993
  }
458994
+ function isGroupJid(jid) {
458995
+ return jid.endsWith(JID_SUFFIX.GROUP);
458996
+ }
458920
458997
  function isUserJid(jid) {
458921
458998
  return jid.endsWith(JID_SUFFIX.USER);
458922
458999
  }
@@ -460296,7 +460373,6 @@ async function removeReaction4(sock, jid, targetMessageId, fromMe = true) {
460296
460373
 
460297
460374
  // ../channel-whatsapp/src/senders/stream.ts
460298
460375
  init_src();
460299
-
460300
460376
  // ../channel-whatsapp/src/utils/split-message.ts
460301
460377
  var DEFAULT_MAX_LENGTH2 = 65536;
460302
460378
  function splitByDelimiter(text, delimiter) {
@@ -460666,14 +460742,16 @@ class WhatsAppStreamSender {
460666
460742
  this.messageId = result?.key?.id ?? null;
460667
460743
  this.firstMessageSent = true;
460668
460744
  } else {
460669
- await this.getSock().sendMessage(this.jid, {
460670
- text,
460671
- edit: {
460672
- remoteJid: this.jid,
460673
- id: this.messageId,
460674
- fromMe: true
460675
- }
460676
- });
460745
+ const sock = this.getSock();
460746
+ const editKey = {
460747
+ remoteJid: this.jid,
460748
+ id: this.messageId,
460749
+ fromMe: true
460750
+ };
460751
+ if (isGroupJid(this.jid)) {
460752
+ editKey.participant = sock.user?.id;
460753
+ }
460754
+ await sock.sendMessage(this.jid, { text, edit: editKey });
460677
460755
  }
460678
460756
  this.lastRenderedText = text;
460679
460757
  this.lastEditAt = Date.now();
@@ -460689,14 +460767,16 @@ class WhatsAppStreamSender {
460689
460767
  async doEditRaw(text) {
460690
460768
  if (!this.messageId)
460691
460769
  throw new Error("No message to edit");
460692
- await this.getSock().sendMessage(this.jid, {
460693
- text,
460694
- edit: {
460695
- remoteJid: this.jid,
460696
- id: this.messageId,
460697
- fromMe: true
460698
- }
460699
- });
460770
+ const sock = this.getSock();
460771
+ const editKey = {
460772
+ remoteJid: this.jid,
460773
+ id: this.messageId,
460774
+ fromMe: true
460775
+ };
460776
+ if (isGroupJid(this.jid)) {
460777
+ editKey.participant = sock.user?.id;
460778
+ }
460779
+ await sock.sendMessage(this.jid, { text, edit: editKey });
460700
460780
  this.lastRenderedText = text;
460701
460781
  this.lastEditAt = Date.now();
460702
460782
  }
@@ -463225,11 +463305,33 @@ class WhatsAppPlugin extends BaseChannelPlugin {
463225
463305
  await this.humanDelay(instanceId);
463226
463306
  const sock = this.getSocket(instanceId);
463227
463307
  const jid = toJid(chatJid);
463228
- await sock.sendMessage(jid, {
463229
- edit: { remoteJid: jid, id: messageId, fromMe },
463230
- text: newText
463231
- });
463232
- this.logger.info("Message edited", { instanceId, chatJid: jid, messageId, fromMe });
463308
+ const editKey = {
463309
+ remoteJid: jid,
463310
+ id: messageId,
463311
+ fromMe
463312
+ };
463313
+ if (isGroupJid(jid) && fromMe) {
463314
+ editKey.participant = sock.user?.id;
463315
+ }
463316
+ try {
463317
+ const result = await sock.sendMessage(jid, { edit: editKey, text: newText });
463318
+ this.logger.info("Message edited", {
463319
+ instanceId,
463320
+ chatJid: jid,
463321
+ messageId,
463322
+ fromMe,
463323
+ resultKeyId: result?.key?.id
463324
+ });
463325
+ } catch (error) {
463326
+ this.logger.error("Failed to edit message via Baileys", {
463327
+ instanceId,
463328
+ chatJid: jid,
463329
+ messageId,
463330
+ fromMe,
463331
+ error: error instanceof Error ? error.message : String(error)
463332
+ });
463333
+ throw mapBaileysError(error);
463334
+ }
463233
463335
  }
463234
463336
  getSocket(instanceId) {
463235
463337
  const sock = this.sockets.get(instanceId);