@songsid/agend 2.1.2 → 2.1.3-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3140,9 +3140,13 @@ export class FleetManager {
3140
3140
  await this.handleClassicChannelMessage(classicName, syntheticMsg);
3141
3141
  return;
3142
3142
  }
3143
- // Strip @bot from text and forward as /chat
3144
- const cleanText = botUser ? text.replace(new RegExp(`@${botUser}`, "gi"), "").trim() : text;
3145
- if (cleanText.startsWith("/raw") && !this.classicChannels.isAdmin(msg.userId)) {
3143
+ // Keep the bot's own @mention visible to the agent as a self-marker
3144
+ // instead of stripping it (#498). Telegram never delivers a bot its
3145
+ // own messages, so the marker cannot echo back into a loop.
3146
+ const tgSelfMentionRe = botUser ? new RegExp(`@${botUser}`, "gi") : null;
3147
+ const strippedText = tgSelfMentionRe ? text.replace(tgSelfMentionRe, "").trim() : text;
3148
+ const cleanText = tgSelfMentionRe ? text.replace(tgSelfMentionRe, `@${botUser} (you)`).trim() : text;
3149
+ if (strippedText.startsWith("/raw") && !this.classicChannels.isAdmin(msg.userId)) {
3146
3150
  await msgAdapter?.sendText(chatId, t("cmd.admin_required", "/raw"));
3147
3151
  return;
3148
3152
  }
@@ -5267,18 +5271,27 @@ When users create specialized instances, suggest these configurations:
5267
5271
  }
5268
5272
  return;
5269
5273
  }
5270
- // Strip the @mention from text
5271
- const cleanText = text.replace(new RegExp(`<@${adapterBotUserId}>`, "g"), "").trim();
5272
- if (!cleanText && !msg.attachments?.length)
5274
+ // Rewrite the bot's own @mention into a readable self-marker instead of
5275
+ // stripping it (#498): when several people are tagged in one message the
5276
+ // agent must see that it is among them. Loop safety does not depend on
5277
+ // this strip — the adapter drops the bot's own messages on inbound, so a
5278
+ // reply containing the marker (or even a raw self-mention) never
5279
+ // re-enters this path.
5280
+ const selfMentionRe = new RegExp(`<@${adapterBotUserId}>`, "g");
5281
+ const strippedText = text.replace(selfMentionRe, "").trim();
5282
+ if (!strippedText && !msg.attachments?.length)
5273
5283
  return;
5284
+ const selfMarker = mentionWorld?.botUsername ? `@${mentionWorld.botUsername} (you)` : `${mentionTag} (you)`;
5285
+ const cleanText = text.replace(selfMentionRe, selfMarker).trim();
5274
5286
  const classicAdapter = this.worlds.get(msg.adapterId ?? "")?.adapter ?? this.adapter;
5275
5287
  const collabReactChatId = msg.threadId ?? msg.chatId;
5276
5288
  if (classicAdapter && collabReactChatId && msg.messageId) {
5277
5289
  classicAdapter.react(collabReactChatId, msg.messageId, "👀")
5278
5290
  .catch(e => this.logger.debug({ err: e.message }, "Auto-react failed"));
5279
5291
  }
5280
- // Block /raw bypass
5281
- if (cleanText.startsWith("/raw "))
5292
+ // Block /raw bypass — check the mention-stripped text so the self-marker
5293
+ // prefix can't be used to sneak "/raw" past this gate.
5294
+ if (strippedText.startsWith("/raw "))
5282
5295
  return;
5283
5296
  // Attachments already saved at the top of the collab block.
5284
5297
  if (saved && classicAdapter && collabReactChatId && msg.messageId) {