clawgram 2.2.2 → 2.3.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.
package/dist/channel.js CHANGED
@@ -317,6 +317,9 @@ const createChannelPlugin = (runtimes) => {
317
317
  });
318
318
  const sendTextToConversation = async (args) => {
319
319
  const targets = [conversationTarget, ...conversationFallbackTargets];
320
+ // Replies have no per-call parseMode slot — the format is an
321
+ // account setting (2.3.1); absent keeps plain text.
322
+ const replyParseMode = gram.replyParseMode;
320
323
  let lastError;
321
324
  for (const target of targets) {
322
325
  try {
@@ -325,6 +328,7 @@ const createChannelPlugin = (runtimes) => {
325
328
  text: args.text,
326
329
  replyToMessageId: args.replyToMessageId,
327
330
  messageThreadId: args.messageThreadId,
331
+ parseMode: replyParseMode,
328
332
  });
329
333
  }
330
334
  catch (error) {
@@ -1148,6 +1152,7 @@ const createChannelPlugin = (runtimes) => {
1148
1152
  const replyToId = (0, param_readers_1.readStringOrNumberParam)(params, "replyToId") ?? (0, param_readers_1.readStringOrNumberParam)(params, "replyTo");
1149
1153
  const threadId = (0, param_readers_1.readStringOrNumberParam)(params, "threadId");
1150
1154
  const messageThreadId = parseOptionalThreadId(threadId);
1155
+ const parseMode = (0, helpers_1.normalizeParseMode)(params?.parseMode);
1151
1156
  actionLog.info("clawgram handleAction send", {
1152
1157
  requestedAccountId: accountId,
1153
1158
  dryRun: dryRun === true,
@@ -1156,6 +1161,7 @@ const createChannelPlugin = (runtimes) => {
1156
1161
  targetKind,
1157
1162
  replyToId: replyToId ?? null,
1158
1163
  threadId: threadId ?? null,
1164
+ parseMode: parseMode ?? null,
1159
1165
  toolContextCurrentChannelId: toolContext?.currentChannelId ?? null,
1160
1166
  });
1161
1167
  const resolvedAccountId = resolveRuntimeAccountId(cfg, accountId);
@@ -1240,6 +1246,7 @@ const createChannelPlugin = (runtimes) => {
1240
1246
  targetKind,
1241
1247
  replyToMessageId: (0, helpers_1.resolveReplyToMessageIdForTarget)(rawTo, replyToId),
1242
1248
  messageThreadId,
1249
+ parseMode,
1243
1250
  });
1244
1251
  if (sendingToCurrentGroup &&
1245
1252
  !replyToId &&
@@ -1322,6 +1329,7 @@ const createChannelPlugin = (runtimes) => {
1322
1329
  targetKind,
1323
1330
  replyToMessageId: (0, helpers_1.resolveReplyToMessageIdForTarget)(ctx.to, ctx.replyToId),
1324
1331
  messageThreadId,
1332
+ parseMode: gram.replyParseMode,
1325
1333
  });
1326
1334
  actionLog.info("clawgram outbound sendText completed", {
1327
1335
  accountId: ctx.accountId,
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GramJsClientManager = void 0;
4
4
  const telegram_1 = require("telegram");
5
5
  const sessions_1 = require("telegram/sessions");
6
+ const helpers_1 = require("./helpers");
6
7
  const proxy_config_1 = require("./proxy-config");
7
8
  const secret_refs_1 = require("./secret-refs");
8
9
  const history_1 = require("./history");
@@ -289,12 +290,22 @@ class GramJsClientManager {
289
290
  chatType: inferChatTypeFromRaw(chatId ?? raw)
290
291
  };
291
292
  }
293
+ /**
294
+ * Reply format for this account, validated once at read time.
295
+ * The reply pipeline has no per-call parseMode slot (2.3.1).
296
+ */
297
+ get replyParseMode() {
298
+ return (0, helpers_1.normalizeParseMode)(this.config.replyParseMode);
299
+ }
292
300
  async sendText(args) {
293
301
  const resolved = await this.resolvePeer(args.target, { kind: args.targetKind });
294
302
  const messageThreadId = args.messageThreadId ?? resolved.messageThreadId;
295
303
  const replyParams = buildForumReplyParams(messageThreadId, args.replyToMessageId);
296
304
  return this.client.sendMessage(resolved.peer, {
297
305
  message: args.text,
306
+ // GramJS accepts "md" | "html"; absent keeps plain text so every
307
+ // pre-2.3.0 caller behaves exactly as before.
308
+ ...(args.parseMode ? { parseMode: args.parseMode === "markdown" ? "md" : "html" } : {}),
298
309
  ...replyParams,
299
310
  });
300
311
  }
package/dist/helpers.js CHANGED
@@ -33,6 +33,8 @@ exports.resolveChatTarget = resolveChatTarget;
33
33
  exports.isReplyToSelfMessage = isReplyToSelfMessage;
34
34
  exports.resolveSenderProfile = resolveSenderProfile;
35
35
  exports.resolveSenderProfileWithTimeout = resolveSenderProfileWithTimeout;
36
+ exports.normalizeParseMode = normalizeParseMode;
37
+ exports.resolveReplyParseMode = resolveReplyParseMode;
36
38
  const node_fs_1 = require("node:fs");
37
39
  const node_path_1 = __importDefault(require("node:path"));
38
40
  const core_1 = require("openclaw/plugin-sdk/core");
@@ -493,3 +495,32 @@ async function resolveSenderProfile(message, input) {
493
495
  async function resolveSenderProfileWithTimeout(message, input, timeoutMs = 1500) {
494
496
  return await withTimeout(resolveSenderProfile(message, input), timeoutMs) ?? {};
495
497
  }
498
+ /**
499
+ * Send accepts parseMode so drafts can carry real links ([text](url)) instead
500
+ * of bare URLs. The value reaches GramJS, so it is validated here: an unknown
501
+ * mode fails loudly at the action boundary rather than silently sending
502
+ * markup as literal text to a live human.
503
+ */
504
+ function normalizeParseMode(raw) {
505
+ if (raw === undefined || raw === null || raw === "")
506
+ return undefined;
507
+ const value = String(raw).toLowerCase();
508
+ if (value === "md" || value === "markdown")
509
+ return "markdown";
510
+ if (value === "html")
511
+ return "html";
512
+ throw new Error(`clawgram: invalid parseMode "${String(raw)}" — use "markdown" or "html"`);
513
+ }
514
+ /**
515
+ * Reply parse mode for the inbound reply path (2.3.1). The action `send`
516
+ * takes parseMode per-call, but replies to a mention run through the reply
517
+ * pipeline, which has no per-call slot — so the format is a channel setting:
518
+ * `channels.clawgram.accounts.<id>.replyParseMode: "markdown" | "html"`.
519
+ * Absent means plain text, exactly as before 2.3.1. An invalid value throws
520
+ * at config-read time, loud and early, rather than shipping raw markup.
521
+ */
522
+ function resolveReplyParseMode(cfg, accountId) {
523
+ const channel = cfg?.channels?.["clawgram"];
524
+ const account = channel?.accounts?.[accountId] ?? channel;
525
+ return normalizeParseMode(account?.replyParseMode);
526
+ }
@@ -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.2.2",
5
+ "version": "2.3.1",
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.2.2",
3
+ "version": "2.3.1",
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": {
@@ -8,6 +8,7 @@
8
8
  "build:test": "tsc -p tsconfig.test.json",
9
9
  "test": "npm run build:test && node test/ensure-compiled.mjs && node --test \"dist-test/test/*.test.js\"",
10
10
  "prepublishOnly": "npm run build && npm test",
11
+ "release:clawhub": "node scripts/publish-clawhub.mjs",
11
12
  "clawgram-cli": "node dist/clawgram-cli.js",
12
13
  "clawgram-cli:hello": "node dist/clawgram-cli.js --hello",
13
14
  "clawgram-cli:auth": "node dist/clawgram-cli.js --auth"