clawgram 2.7.0 → 2.7.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 +19 -3
- package/dist/helpers.js +23 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/channel.js
CHANGED
|
@@ -781,7 +781,16 @@ const createChannelPlugin = (runtimes, pluginRuntime) => {
|
|
|
781
781
|
// A suppressed silent reply legitimately delivers nothing, so
|
|
782
782
|
// this fallback fires right after it. Without the same check
|
|
783
783
|
// the token would be read back from the transcript and sent.
|
|
784
|
-
|
|
784
|
+
//
|
|
785
|
+
// TTS markup needs the same treatment for the same reason:
|
|
786
|
+
// core strips it on the normal reply path, but this text comes
|
|
787
|
+
// straight out of the transcript. On 2026-08-08 a group got
|
|
788
|
+
// `[[tts:text]]Привет, Вася!…[[/tts:text]]` verbatim. The
|
|
789
|
+
// spoken words are kept — a synthesis that did not happen
|
|
790
|
+
// should degrade to readable text, not to markup.
|
|
791
|
+
const visibleFallbackText = fallbackText
|
|
792
|
+
? (0, helpers_1.stripTtsDirectives)((0, helpers_1.stripSilentReplyToken)(fallbackText))
|
|
793
|
+
: "";
|
|
785
794
|
if (fallbackText && !visibleFallbackText) {
|
|
786
795
|
log?.info?.("clawgram skipping silent transcript fallback", {
|
|
787
796
|
accountId,
|
|
@@ -1634,25 +1643,32 @@ const createChannelPlugin = (runtimes, pluginRuntime) => {
|
|
|
1634
1643
|
}
|
|
1635
1644
|
actionLog.info("clawgram outbound sendMedia", {
|
|
1636
1645
|
accountId: ctx.accountId,
|
|
1637
|
-
|
|
1646
|
+
rawTo: ctx.to,
|
|
1638
1647
|
replyToId: ctx.replyToId ?? null,
|
|
1639
1648
|
threadId: ctx.threadId ?? null,
|
|
1640
1649
|
filePath: ctx.filePath ?? null,
|
|
1641
1650
|
mediaUrl: ctx.mediaUrl ?? null,
|
|
1642
1651
|
hasText: Boolean(ctx.text),
|
|
1643
1652
|
hasCaption: Boolean(ctx.caption),
|
|
1653
|
+
asVoice: ctx.audioAsVoice === true,
|
|
1644
1654
|
});
|
|
1645
1655
|
const file = ctx.filePath ?? ctx.mediaUrl;
|
|
1646
1656
|
if (!file) {
|
|
1647
1657
|
throw new Error("clawgram: sendMedia requires filePath or mediaUrl");
|
|
1648
1658
|
}
|
|
1649
1659
|
const messageThreadId = parseOptionalThreadId(ctx.threadId);
|
|
1660
|
+
// Same normalization `sendText` does two functions up. Without it the
|
|
1661
|
+
// channel prefix reaches peer resolution and the send throws — which is
|
|
1662
|
+
// exactly how a synthesized group reply died on 2026-08-08, silently
|
|
1663
|
+
// enough that the transcript fallback posted it as raw text instead.
|
|
1664
|
+
const target = (0, helpers_1.normalizeOutboundTarget)(ctx.to);
|
|
1650
1665
|
const sent = await gram.sendMedia({
|
|
1651
|
-
target
|
|
1666
|
+
target,
|
|
1652
1667
|
file,
|
|
1653
1668
|
caption: ctx.caption ?? ctx.text,
|
|
1654
1669
|
replyToMessageId: (0, helpers_1.resolveReplyToMessageIdForTarget)(ctx.to, ctx.replyToId),
|
|
1655
1670
|
messageThreadId,
|
|
1671
|
+
asVoice: ctx.audioAsVoice === true,
|
|
1656
1672
|
});
|
|
1657
1673
|
actionLog.info("clawgram outbound sendMedia completed", {
|
|
1658
1674
|
accountId: ctx.accountId,
|
package/dist/helpers.js
CHANGED
|
@@ -16,6 +16,7 @@ exports.resolveActionTarget = resolveActionTarget;
|
|
|
16
16
|
exports.resolveReplyToMessageIdForTarget = resolveReplyToMessageIdForTarget;
|
|
17
17
|
exports.readMessageText = readMessageText;
|
|
18
18
|
exports.readVoiceNoteFlag = readVoiceNoteFlag;
|
|
19
|
+
exports.stripTtsDirectives = stripTtsDirectives;
|
|
19
20
|
exports.resolveAllowFrom = resolveAllowFrom;
|
|
20
21
|
exports.resolveGroupPolicy = resolveGroupPolicy;
|
|
21
22
|
exports.resolveGroups = resolveGroups;
|
|
@@ -194,6 +195,28 @@ function resolveReplyToMessageIdForTarget(rawTarget, replyToId) {
|
|
|
194
195
|
}
|
|
195
196
|
return undefined;
|
|
196
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* Разметка синтеза речи, которая не должна доехать до человека.
|
|
200
|
+
*
|
|
201
|
+
* Core вырезает `[[tts:...]]` из видимого текста сам, но только на штатном
|
|
202
|
+
* пути ответа. Аварийный путь (`readLatestAssistantFallbackFromTranscript`)
|
|
203
|
+
* читает сырой текст из стенограммы, поэтому 2026-08-08 в групповой чат
|
|
204
|
+
* ушло `[[tts:text]]Привет, Вася!…[[/tts:text]]` как есть.
|
|
205
|
+
*
|
|
206
|
+
* Блок `[[tts:text]]…[[/tts:text]]` РАЗВОРАЧИВАЕТСЯ, а не удаляется: внутри
|
|
207
|
+
* лежит то, что агент собирался сказать. Если синтез не состоялся, человек
|
|
208
|
+
* должен получить эти слова текстом — деградация в читаемое, а не в мусор
|
|
209
|
+
* и не в пустоту.
|
|
210
|
+
*/
|
|
211
|
+
const TTS_TEXT_BLOCK = /\[\[tts:text\]\]([\s\S]*?)\[\[\/tts:text\]\]/gi;
|
|
212
|
+
const TTS_DIRECTIVE = /\[\[\s*\/?\s*(?:tts:[^\]]*|audio_as_voice)\s*\]\]/gi;
|
|
213
|
+
function stripTtsDirectives(text) {
|
|
214
|
+
return text
|
|
215
|
+
.replace(TTS_TEXT_BLOCK, (_match, spoken) => spoken)
|
|
216
|
+
.replace(TTS_DIRECTIVE, "")
|
|
217
|
+
.replace(/[ \t]{2,}/g, " ")
|
|
218
|
+
.trim();
|
|
219
|
+
}
|
|
197
220
|
/**
|
|
198
221
|
* Whether an outbound file should become a Telegram voice message.
|
|
199
222
|
*
|
package/openclaw.plugin.json
CHANGED
|
@@ -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.7.
|
|
5
|
+
"version": "2.7.1",
|
|
6
6
|
"configSchema": {
|
|
7
7
|
"type": "object",
|
|
8
8
|
"additionalProperties": false,
|
package/package.json
CHANGED