@@ -717,11 +717,31 @@ func (h *Handler) downloadFile(fileID string) ([]byte, error) {
717717}
718718
719719func (h * Handler ) sendResponse (chatID int64 , text string ) {
720- if len (text ) >= maxMessageLen {
721- h .sendAsFile (chatID , text )
720+ if len (text ) < maxMessageLen {
721+ h .sendSingleMessage (chatID , text )
722722 return
723723 }
724724
725+ // Split long responses into multiple messages.
726+ parts := splitMessage (text , maxMessageLen - 100 ) // leave margin for safety
727+ allOK := true
728+ for i , part := range parts {
729+ if ! h .sendSingleMessage (chatID , part ) {
730+ h .logger .Warn ("chunk send failed, falling back to file" , "chunk" , i + 1 , "of" , len (parts ))
731+ allOK = false
732+ break
733+ }
734+ }
735+ if allOK {
736+ return
737+ }
738+
739+ // Fallback: send as file.
740+ h .sendAsFile (chatID , text )
741+ }
742+
743+ // sendSingleMessage sends one chunk as HTML (with plain-text fallback). Returns true on success.
744+ func (h * Handler ) sendSingleMessage (chatID int64 , text string ) bool {
725745 htmlText := markdownToTelegramHTML (text )
726746 msg := tgbotapi .NewMessage (chatID , htmlText )
727747 msg .ParseMode = tgbotapi .ModeHTML
@@ -731,8 +751,10 @@ func (h *Handler) sendResponse(chatID int64, text string) {
731751 msg .Text = text
732752 if _ , err := h .bot .Send (msg ); err != nil {
733753 h .logger .Error ("failed to send response" , "chat_id" , chatID , "err" , err )
754+ return false
734755 }
735756 }
757+ return true
736758}
737759
738760func (h * Handler ) sendAsFile (chatID int64 , text string ) {
@@ -753,6 +775,43 @@ func (h *Handler) sendAsFile(chatID int64, text string) {
753775 }
754776}
755777
778+ // splitMessage splits text into chunks of at most maxLen bytes,
779+ // breaking at paragraph boundaries (\n\n), then line boundaries (\n).
780+ func splitMessage (text string , maxLen int ) []string {
781+ if len (text ) <= maxLen {
782+ return []string {text }
783+ }
784+
785+ var parts []string
786+ for len (text ) > 0 {
787+ if len (text ) <= maxLen {
788+ parts = append (parts , text )
789+ break
790+ }
791+
792+ chunk := text [:maxLen ]
793+
794+ // Try to break at a paragraph boundary.
795+ if idx := strings .LastIndex (chunk , "\n \n " ); idx > maxLen / 4 {
796+ parts = append (parts , text [:idx ])
797+ text = strings .TrimLeft (text [idx :], "\n " )
798+ continue
799+ }
800+
801+ // Try to break at a line boundary.
802+ if idx := strings .LastIndex (chunk , "\n " ); idx > maxLen / 4 {
803+ parts = append (parts , text [:idx ])
804+ text = text [idx + 1 :]
805+ continue
806+ }
807+
808+ // Hard break at maxLen.
809+ parts = append (parts , chunk )
810+ text = text [maxLen :]
811+ }
812+ return parts
813+ }
814+
756815// send sends a bot-generated message with MarkdownV2 (text must be pre-escaped).
757816func (h * Handler ) send (chatID int64 , text string ) {
758817 msg := tgbotapi .NewMessage (chatID , text )
0 commit comments