mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:10:44 +00:00
fix(telegram): send interactive fallback replies
This commit is contained in:
@@ -63,6 +63,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Feishu: use the shared channel progress formatter for streaming-card tool status lines, including raw command/detail output and message-tool filtering. Thanks @vincentkoc.
|
||||
- Mattermost: use the shared progress draft formatter for tool status previews, including raw command/detail output when `agents.defaults.toolProgressDetail: "raw"` is enabled. Thanks @vincentkoc.
|
||||
- Mattermost: suppress standalone default tool-progress messages while draft previews are active, including when draft tool lines are disabled. Thanks @vincentkoc.
|
||||
- Telegram: deliver button-only interactive replies by sending the shared fallback button-label text with the inline keyboard instead of dropping the reply as empty. Thanks @vincentkoc.
|
||||
- OpenAI Codex: honor `auth.order.openai-codex` when starting app-server clients without an explicit auth profile, so status/model probes and implicit startup use the configured Codex account instead of falling back to the default profile. Thanks @vincentkoc.
|
||||
- OpenAI Codex: let SSRF-guarded provider requests inherit OpenClaw's undici IPv4/IPv6 fallback policy, so ChatGPT-backed Codex runs recover on IPv4-working hosts when DNS still returns unreachable IPv6 addresses. Fixes #76857. Thanks @jplavoiemtl and @SymbolStar.
|
||||
- Gateway/systemd: preserve operator-added secrets in the Gateway env file across re-stage while clearing OpenClaw-managed keys (such as `OPENCLAW_GATEWAY_TOKEN`) so a fresh staging value is never shadowed by a stale env-file copy; operator secrets are also retained when the state-dir `.env` is empty. Fixes #76860. Thanks @hclsys.
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
renderTelegramHtmlText,
|
||||
wrapFileReferencesInHtml,
|
||||
} from "../format.js";
|
||||
import { resolveTelegramInteractiveTextFallback } from "../interactive-fallback.js";
|
||||
import { buildInlineKeyboard } from "../send.js";
|
||||
import { resolveTelegramVoiceSend } from "../voice.js";
|
||||
import {
|
||||
@@ -751,7 +752,17 @@ export async function deliverReplies(params: {
|
||||
? [reply.mediaUrl]
|
||||
: [];
|
||||
const hasMedia = mediaList.length > 0;
|
||||
if (!reply?.text && !hasMedia) {
|
||||
const resolvedReplyText =
|
||||
resolveTelegramInteractiveTextFallback({
|
||||
text: reply?.text,
|
||||
interactive: reply?.interactive,
|
||||
}) ??
|
||||
reply?.text ??
|
||||
"";
|
||||
if (reply && resolvedReplyText !== (reply.text ?? "")) {
|
||||
reply = { ...reply, text: resolvedReplyText };
|
||||
}
|
||||
if (!resolvedReplyText && !hasMedia) {
|
||||
if (reply?.audioAsVoice) {
|
||||
logVerbose("telegram reply has audioAsVoice without media/text; skipping");
|
||||
continue;
|
||||
@@ -760,7 +771,7 @@ export async function deliverReplies(params: {
|
||||
continue;
|
||||
}
|
||||
|
||||
const rawContent = reply.text || "";
|
||||
const rawContent = resolvedReplyText;
|
||||
const replyToId =
|
||||
params.replyToMode === "off" ? undefined : resolveTelegramReplyId(reply.replyToId);
|
||||
const replyQuote = resolveReplyQuoteForSend({
|
||||
|
||||
@@ -257,6 +257,35 @@ describe("deliverReplies", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("uses interactive button labels as fallback text for button-only replies", async () => {
|
||||
const runtime = createRuntime(false);
|
||||
const sendMessage = vi.fn().mockResolvedValue({ message_id: 3, chat: { id: "123" } });
|
||||
const bot = createBot({ sendMessage });
|
||||
|
||||
await deliverWith({
|
||||
replies: [
|
||||
{
|
||||
interactive: {
|
||||
blocks: [{ type: "buttons", buttons: [{ label: "Retry", value: "cmd:retry" }] }],
|
||||
},
|
||||
},
|
||||
],
|
||||
runtime,
|
||||
bot,
|
||||
});
|
||||
|
||||
expect(runtime.error).not.toHaveBeenCalled();
|
||||
expect(sendMessage).toHaveBeenCalledWith(
|
||||
"123",
|
||||
expect.stringContaining("Retry"),
|
||||
expect.objectContaining({
|
||||
reply_markup: {
|
||||
inline_keyboard: [[{ text: "Retry", callback_data: "cmd:retry" }]],
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("reports message_sent success=false when hooks blank out a text-only reply", async () => {
|
||||
messageHookRunner.hasHooks.mockImplementation(
|
||||
(name: string) => name === "message_sending" || name === "message_sent",
|
||||
|
||||
Reference in New Issue
Block a user