clawgram 2.3.3 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/channel.js CHANGED
@@ -470,6 +470,12 @@ const createChannelPlugin = (runtimes) => {
470
470
  MessageSidFull: normalized.messageId,
471
471
  Timestamp: normalized.timestamp,
472
472
  ReplyToId: normalized.replyToMessageId,
473
+ // Core renders these itself as `[Replying to: "…"]` ahead of the
474
+ // user body — it keys off Provider being "telegram", which is set
475
+ // below. Without them a highlighted reply reaches the agent as
476
+ // bare text, and the fragment the person pointed at is lost.
477
+ ReplyToQuoteText: normalized.replyQuoteText,
478
+ ReplyToIsQuote: normalized.replyIsQuote,
473
479
  MessageThreadId: normalized.messageThreadId,
474
480
  NativeChannelId: normalized.chatId,
475
481
  OriginatingChannel: "clawgram",
@@ -746,6 +752,10 @@ const createChannelPlugin = (runtimes) => {
746
752
  SenderUsername: normalized.senderUsername,
747
753
  SenderName: normalized.senderDisplay,
748
754
  ReplyToId: normalized.replyToMessageId,
755
+ // Same reason as the group path: highlighted replies happen in
756
+ // direct messages too, and the fragment is not part of the text.
757
+ ReplyToQuoteText: normalized.replyQuoteText,
758
+ ReplyToIsQuote: normalized.replyIsQuote,
749
759
  NativeChannelId: normalized.chatId,
750
760
  },
751
761
  deliver: async (payload) => {
package/dist/history.js CHANGED
@@ -227,6 +227,14 @@ function resolveSenderDisplay(msg) {
227
227
  return joined;
228
228
  return readSender(msg, "title") ?? readSender(msg, "username");
229
229
  }
230
+ /**
231
+ * Same rule as the inbound path (`normalize.ts`): the text is the evidence,
232
+ * not the `quote` flag, and blank text means no highlight.
233
+ */
234
+ function resolveHistoryReplyQuote(msg) {
235
+ const raw = msg?.replyTo?.quoteText ?? msg?.quoteText;
236
+ return typeof raw === "string" && raw.trim() ? raw : undefined;
237
+ }
230
238
  /**
231
239
  * Deliberately drops `raw`. Inbound events carry it because the runtime may need
232
240
  * the original object; history is read straight into a model's context, where an
@@ -258,6 +266,7 @@ function normalizeHistoryMessage(msg, fallbackChatId) {
258
266
  timestamp,
259
267
  sentAt: timestamp === undefined ? undefined : new Date(timestamp * 1000).toISOString(),
260
268
  replyToMessageId: toStringId(msg?.replyTo?.replyToMsgId) ?? toStringId(msg?.replyToMsgId),
269
+ replyQuoteText: resolveHistoryReplyQuote(msg),
261
270
  messageThreadId: toStringId(msg?.replyTo?.replyToTopId) ?? toStringId(msg?.replyToTopId),
262
271
  media: (0, media_1.describeMedia)(msg?.media),
263
272
  isOutgoing: msg?.out === true,
package/dist/normalize.js CHANGED
@@ -66,6 +66,21 @@ function resolveMessageThreadId(msg) {
66
66
  return (toStringId(msg?.replyTo?.replyToMsgId) ??
67
67
  toStringId(msg?.replyToMsgId));
68
68
  }
69
+ /**
70
+ * The highlighted fragment of a reply, when there is one.
71
+ *
72
+ * Telegram sends the flag and the text separately, and clients in the wild are
73
+ * not consistent about the flag. The text is the evidence: if `quoteText` has
74
+ * content, a fragment was highlighted regardless of what `quote` says. Blank
75
+ * text is treated as no highlight rather than as an empty one.
76
+ */
77
+ function resolveReplyQuote(msg) {
78
+ const raw = msg?.replyTo?.quoteText ?? msg?.quoteText;
79
+ const text = typeof raw === "string" && raw.trim() ? raw : undefined;
80
+ if (!text)
81
+ return {};
82
+ return { text, isQuote: true };
83
+ }
69
84
  function normalizeTelegramEvent(event, accountId) {
70
85
  const msg = event?.message;
71
86
  if (!msg)
@@ -84,6 +99,7 @@ function normalizeTelegramEvent(event, accountId) {
84
99
  const replyToMessageId = toStringId(msg.replyTo?.replyToMsgId) ??
85
100
  toStringId(msg.replyToMsgId);
86
101
  const messageThreadId = resolveMessageThreadId(msg);
102
+ const replyQuote = resolveReplyQuote(msg);
87
103
  const text = typeof msg.message === "string"
88
104
  ? msg.message
89
105
  : typeof msg.text === "string"
@@ -116,6 +132,8 @@ function normalizeTelegramEvent(event, accountId) {
116
132
  messageId,
117
133
  text,
118
134
  replyToMessageId,
135
+ replyQuoteText: replyQuote.text,
136
+ replyIsQuote: replyQuote.isQuote,
119
137
  chatType,
120
138
  timestamp: toTimestamp(msg.date),
121
139
  isOutgoing: Boolean(msg.out),
@@ -2,7 +2,7 @@
2
2
  "id": "clawgram",
3
3
  "name": "Clawgram",
4
4
  "description": "Clawgram — personal Telegram (MTProto userbot) channel for OpenClaw. Your AI assistant reads and responds as you.",
5
- "version": "2.3.3",
5
+ "version": "2.4.0",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawgram",
3
- "version": "2.3.3",
3
+ "version": "2.4.0",
4
4
  "description": "Clawgram — personal Telegram (MTProto userbot) channel for OpenClaw. Your AI assistant reads and responds as you.",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {