@@ -4,12 +4,29 @@ import {
44 takeMessageIdAfterStop ,
55} from "openclaw/plugin-sdk/channel-outbound" ;
66import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime" ;
7- import { buildTelegramThreadParams , type TelegramThreadSpec } from "./bot/helpers.js" ;
7+ import {
8+ buildTelegramThreadParams ,
9+ shouldAllowTelegramThreadlessFallback ,
10+ type TelegramThreadSpec ,
11+ } from "./bot/helpers.js" ;
812import { isSafeToRetrySendError , isTelegramClientRejection } from "./network-errors.js" ;
913import { normalizeTelegramReplyToMessageId } from "./outbound-params.js" ;
1014
1115const TELEGRAM_STREAM_MAX_CHARS = 4096 ;
1216const DEFAULT_THROTTLE_MS = 1000 ;
17+ const THREAD_NOT_FOUND_RE = / 4 0 0 : \s * B a d R e q u e s t : \s * m e s s a g e t h r e a d n o t f o u n d / i;
18+
19+ type TelegramSendMessageParams = Parameters < Bot [ "api" ] [ "sendMessage" ] > [ 2 ] ;
20+
21+ function hasNumericMessageThreadId (
22+ params : TelegramSendMessageParams | undefined ,
23+ ) : params is TelegramSendMessageParams & { message_thread_id : number } {
24+ return (
25+ typeof params === "object" &&
26+ params !== null &&
27+ typeof ( params as { message_thread_id ?: unknown } ) . message_thread_id === "number"
28+ ) ;
29+ }
1330
1431export type TelegramDraftStream = {
1532 update : ( text : string ) => void ;
@@ -122,17 +139,42 @@ export function createTelegramDraftStream(params: {
122139 renderedParseMode : "HTML" | undefined ;
123140 sendGeneration : number ;
124141 } ;
125- const sendRenderedMessage = async ( sendArgs : {
142+ const sendRenderedMessageWithThreadFallback = async ( sendArgs : {
126143 renderedText : string ;
127144 renderedParseMode : "HTML" | undefined ;
145+ fallbackWarnMessage : string ;
128146 } ) => {
129147 const sendParams = sendArgs . renderedParseMode
130148 ? {
131149 ...replyParams ,
132150 parse_mode : sendArgs . renderedParseMode ,
133151 }
134152 : replyParams ;
135- return await params . api . sendMessage ( chatId , sendArgs . renderedText , sendParams ) ;
153+ const usedThreadParams = hasNumericMessageThreadId ( sendParams ) ;
154+ try {
155+ return {
156+ sent : await params . api . sendMessage ( chatId , sendArgs . renderedText , sendParams ) ,
157+ usedThreadParams,
158+ } ;
159+ } catch ( err ) {
160+ if ( ! usedThreadParams || ! THREAD_NOT_FOUND_RE . test ( String ( err ) ) ) {
161+ throw err ;
162+ }
163+ if ( ! shouldAllowTelegramThreadlessFallback ( params . thread ) ) {
164+ throw err ;
165+ }
166+ const threadlessParams : TelegramSendMessageParams = { ...sendParams } ;
167+ delete threadlessParams . message_thread_id ;
168+ params . warn ?.( sendArgs . fallbackWarnMessage ) ;
169+ return {
170+ sent : await params . api . sendMessage (
171+ chatId ,
172+ sendArgs . renderedText ,
173+ Object . keys ( threadlessParams ) . length > 0 ? threadlessParams : undefined ,
174+ ) ,
175+ usedThreadParams : false ,
176+ } ;
177+ }
136178 } ;
137179 const sendMessageTransportPreview = async ( {
138180 renderedText,
@@ -151,12 +193,14 @@ export function createTelegramDraftStream(params: {
151193 return true ;
152194 }
153195 messageSendAttempted = true ;
154- let sent : Awaited < ReturnType < typeof sendRenderedMessage > > ;
196+ let sent : Awaited < ReturnType < typeof sendRenderedMessageWithThreadFallback > > [ "sent" ] ;
155197 try {
156- sent = await sendRenderedMessage ( {
198+ ( { sent } = await sendRenderedMessageWithThreadFallback ( {
157199 renderedText,
158200 renderedParseMode,
159- } ) ;
201+ fallbackWarnMessage :
202+ "telegram stream preview send failed with message_thread_id, retrying without thread" ,
203+ } ) ) ;
160204 } catch ( err ) {
161205 if ( isSafeToRetrySendError ( err ) || isTelegramClientRejection ( err ) ) {
162206 messageSendAttempted = false ;
0 commit comments