mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 18:54:31 +00:00
feat: Add support for Telegram quote (partial message replies) (#2900)
* feat: Add support for Telegram quote (partial message replies) - Enhanced describeReplyTarget() to detect and extract quoted text from msg.quote - Updated reply formatting to distinguish between full message replies and quotes - Added isQuote flag to replyTarget object for proper identification - Quote replies show as [Quoting user] "quoted text" [/Quoting] - Regular replies unchanged: [Replying to user] full message [/Replying] Resolves need for partial message reply support in Telegram Bot API. Backward compatible with existing reply functionality. * updating references * Mac: finish Moltbot rename * Mac: finish Moltbot rename (paths) * fix(macOS): rename Clawdbot directories to Moltbot for naming consistency Directory renames: - apps/macos/Sources/Clawdbot → Moltbot - apps/macos/Sources/ClawdbotDiscovery → MoltbotDiscovery - apps/macos/Sources/ClawdbotIPC → MoltbotIPC - apps/macos/Sources/ClawdbotMacCLI → MoltbotMacCLI - apps/macos/Sources/ClawdbotProtocol → MoltbotProtocol - apps/macos/Tests/ClawdbotIPCTests → MoltbotIPCTests - apps/shared/ClawdbotKit → MoltbotKit - apps/shared/MoltbotKit/Sources/Clawdbot* → Moltbot* - apps/shared/MoltbotKit/Tests/ClawdbotKitTests → MoltbotKitTests Resource renames: - Clawdbot.icns → Moltbot.icns Code fixes: - Update Package.swift paths to reference Moltbot* directories - Fix clawdbot* → moltbot* symbol references in Swift code: - clawdbotManagedPaths → moltbotManagedPaths - clawdbotExecutable → moltbotExecutable - clawdbotCommand → moltbotCommand - clawdbotNodeCommand → moltbotNodeCommand - clawdbotOAuthDirEnv → moltbotOAuthDirEnv - clawdbotSelectSettingsTab → moltbotSelectSettingsTab * fix: update remaining ClawdbotKit path references to MoltbotKit - scripts/bundle-a2ui.sh: A2UI_APP_DIR path - package.json: format:swift and protocol:check paths - scripts/protocol-gen-swift.ts: output paths - .github/dependabot.yml: directory path and comment - .gitignore: build cache paths - .swiftformat: exclusion paths - .swiftlint.yml: exclusion path - apps/android/app/build.gradle.kts: assets.srcDir path - apps/ios/project.yml: package path - apps/ios/README.md: documentation reference - docs/concepts/typebox.md: documentation reference - apps/shared/MoltbotKit/Package.swift: fix argument order * chore: update Package.resolved after dependency resolution * fix: add MACOS_APP_SOURCES_DIR constant and update test to use new path The cron-protocol-conformance test was using LEGACY_MACOS_APP_SOURCES_DIR which points to the old Clawdbot path. Added a new MACOS_APP_SOURCES_DIR constant for the current Moltbot path and updated the test to use it. * fix: finish Moltbot macOS rename (#2844) (thanks @fal3) * Extensions: use workspace moltbot in memory-core * fix(security): recognize Venice-style claude-opus-45 as top-tier model The security audit was incorrectly flagging venice/claude-opus-45 as 'Below Claude 4.5' because the regex expected -4-5 (with dash) but Venice uses -45 (without dash between 4 and 5). Updated isClaude45OrHigher() regex to match both formats. Added test case to prevent regression. * Branding: update bot.molt bundle IDs + launchd labels * Branding: remove legacy android packages * fix: wire telegram quote support (#2900) Co-authored-by: aduk059 <aduk059@users.noreply.github.com> * fix: support Telegram quote replies (#2900) (thanks @aduk059) --------- Co-authored-by: Gustavo Madeira Santana <gumadeiras@users.noreply.github.com> Co-authored-by: Shadow <shadow@clawd.bot> Co-authored-by: Alex Fallah <alexfallah7@gmail.com> Co-authored-by: Josh Palmer <joshp123@users.noreply.github.com> Co-authored-by: jonisjongithub <jonisjongithub@users.noreply.github.com> Co-authored-by: Gustavo Madeira Santana <gumadeiras@gmail.com> Co-authored-by: aduk059 <aduk059@users.noreply.github.com>
This commit is contained in:
@@ -42,11 +42,21 @@ export async function deliverReplies(params: {
|
||||
onVoiceRecording?: () => Promise<void> | void;
|
||||
/** Controls whether link previews are shown. Default: true (previews enabled). */
|
||||
linkPreview?: boolean;
|
||||
/** Optional quote text for Telegram reply_parameters. */
|
||||
replyQuoteText?: string;
|
||||
}) {
|
||||
const { replies, chatId, runtime, bot, replyToMode, textLimit, messageThreadId, linkPreview } =
|
||||
params;
|
||||
const {
|
||||
replies,
|
||||
chatId,
|
||||
runtime,
|
||||
bot,
|
||||
replyToMode,
|
||||
textLimit,
|
||||
messageThreadId,
|
||||
linkPreview,
|
||||
replyQuoteText,
|
||||
} = params;
|
||||
const chunkMode = params.chunkMode ?? "length";
|
||||
const threadParams = buildTelegramThreadParams(messageThreadId);
|
||||
let hasReplied = false;
|
||||
const chunkText = (markdown: string) => {
|
||||
const markdownChunks =
|
||||
@@ -97,6 +107,7 @@ export async function deliverReplies(params: {
|
||||
await sendTelegramText(bot, chatId, chunk.html, runtime, {
|
||||
replyToMessageId:
|
||||
replyToId && (replyToMode === "all" || !hasReplied) ? replyToId : undefined,
|
||||
replyQuoteText,
|
||||
messageThreadId,
|
||||
textMode: "html",
|
||||
plainText: chunk.text,
|
||||
@@ -140,13 +151,14 @@ export async function deliverReplies(params: {
|
||||
const shouldAttachButtonsToMedia = isFirstMedia && replyMarkup && !followUpText;
|
||||
const mediaParams: Record<string, unknown> = {
|
||||
caption: htmlCaption,
|
||||
reply_to_message_id: replyToMessageId,
|
||||
...(htmlCaption ? { parse_mode: "HTML" } : {}),
|
||||
...(shouldAttachButtonsToMedia ? { reply_markup: replyMarkup } : {}),
|
||||
...buildTelegramSendParams({
|
||||
replyToMessageId,
|
||||
messageThreadId,
|
||||
replyQuoteText,
|
||||
}),
|
||||
};
|
||||
if (threadParams) {
|
||||
mediaParams.message_thread_id = threadParams.message_thread_id;
|
||||
}
|
||||
if (isGif) {
|
||||
await withTelegramApiErrorLogging({
|
||||
operation: "sendAnimation",
|
||||
@@ -207,6 +219,7 @@ export async function deliverReplies(params: {
|
||||
messageThreadId,
|
||||
linkPreview,
|
||||
replyMarkup,
|
||||
replyQuoteText,
|
||||
});
|
||||
// Skip this media item; continue with next.
|
||||
continue;
|
||||
@@ -391,6 +404,7 @@ async function sendTelegramVoiceFallbackText(opts: {
|
||||
messageThreadId?: number;
|
||||
linkPreview?: boolean;
|
||||
replyMarkup?: ReturnType<typeof buildInlineKeyboard>;
|
||||
replyQuoteText?: string;
|
||||
}): Promise<boolean> {
|
||||
const chunks = opts.chunkText(opts.text);
|
||||
let hasReplied = opts.hasReplied;
|
||||
@@ -399,6 +413,7 @@ async function sendTelegramVoiceFallbackText(opts: {
|
||||
await sendTelegramText(opts.bot, opts.chatId, chunk.html, opts.runtime, {
|
||||
replyToMessageId:
|
||||
opts.replyToId && (opts.replyToMode === "all" || !hasReplied) ? opts.replyToId : undefined,
|
||||
replyQuoteText: opts.replyQuoteText,
|
||||
messageThreadId: opts.messageThreadId,
|
||||
textMode: "html",
|
||||
plainText: chunk.text,
|
||||
@@ -415,11 +430,20 @@ async function sendTelegramVoiceFallbackText(opts: {
|
||||
function buildTelegramSendParams(opts?: {
|
||||
replyToMessageId?: number;
|
||||
messageThreadId?: number;
|
||||
replyQuoteText?: string;
|
||||
}): Record<string, unknown> {
|
||||
const threadParams = buildTelegramThreadParams(opts?.messageThreadId);
|
||||
const params: Record<string, unknown> = {};
|
||||
const quoteText = opts?.replyQuoteText?.trim();
|
||||
if (opts?.replyToMessageId) {
|
||||
params.reply_to_message_id = opts.replyToMessageId;
|
||||
if (quoteText) {
|
||||
params.reply_parameters = {
|
||||
message_id: Math.trunc(opts.replyToMessageId),
|
||||
quote: quoteText,
|
||||
};
|
||||
} else {
|
||||
params.reply_to_message_id = opts.replyToMessageId;
|
||||
}
|
||||
}
|
||||
if (threadParams) {
|
||||
params.message_thread_id = threadParams.message_thread_id;
|
||||
@@ -434,6 +458,7 @@ async function sendTelegramText(
|
||||
runtime: RuntimeEnv,
|
||||
opts?: {
|
||||
replyToMessageId?: number;
|
||||
replyQuoteText?: string;
|
||||
messageThreadId?: number;
|
||||
textMode?: "markdown" | "html";
|
||||
plainText?: string;
|
||||
@@ -443,6 +468,7 @@ async function sendTelegramText(
|
||||
): Promise<number | undefined> {
|
||||
const baseParams = buildTelegramSendParams({
|
||||
replyToMessageId: opts?.replyToMessageId,
|
||||
replyQuoteText: opts?.replyQuoteText,
|
||||
messageThreadId: opts?.messageThreadId,
|
||||
});
|
||||
// Add link_preview_options when link preview is disabled.
|
||||
|
||||
Reference in New Issue
Block a user