diff --git a/pkg/channels/telegram.go b/pkg/channels/telegram.go index bfb78a7f6..b0607d143 100644 --- a/pkg/channels/telegram.go +++ b/pkg/channels/telegram.go @@ -169,12 +169,14 @@ func (c *TelegramChannel) Send(ctx context.Context, msg bus.OutboundMessage) err limit = 4000 // Default Telegram limit (~4096) } - // Telegram HTML tags (like
) can expand content significantly.
-	// We use a safe headroom for the markdown-based split, but never exceed
-	// the configured limit.
-	effectiveMarkdownLimit := limit - 500
+	// Use a percentage-based headroom for the markdown-based split, but never
+	// exceed the configured limit. This scales better for large messages with
+	// extensive formatting or code blocks.
+	effectiveMarkdownLimit := int(float64(limit) * 0.8) // ~80% of limit
 	if effectiveMarkdownLimit < 1 {
 		effectiveMarkdownLimit = 1
+	} else if effectiveMarkdownLimit >= limit {
+		effectiveMarkdownLimit = limit - 1
 	}
 
 	chunks := utils.SplitMessage(msg.Content, effectiveMarkdownLimit)
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 02766341e..00c95365c 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -195,10 +195,9 @@ type ChannelsConfig struct {
 }
 
 type WhatsAppConfig struct {
-	Enabled          bool                `json:"enabled"    env:"PICOCLAW_CHANNELS_WHATSAPP_ENABLED"`
-	BridgeURL        string              `json:"bridge_url" env:"PICOCLAW_CHANNELS_WHATSAPP_BRIDGE_URL"`
-	AllowFrom        FlexibleStringSlice `json:"allow_from" env:"PICOCLAW_CHANNELS_WHATSAPP_ALLOW_FROM"`
-	MaxMessageLength int                 `json:"max_message_length,omitempty" env:"PICOCLAW_CHANNELS_WHATSAPP_MAX_MESSAGE_LENGTH"`
+	Enabled   bool                `json:"enabled"    env:"PICOCLAW_CHANNELS_WHATSAPP_ENABLED"`
+	BridgeURL string              `json:"bridge_url" env:"PICOCLAW_CHANNELS_WHATSAPP_BRIDGE_URL"`
+	AllowFrom FlexibleStringSlice `json:"allow_from" env:"PICOCLAW_CHANNELS_WHATSAPP_ALLOW_FROM"`
 }
 
 type TelegramConfig struct {
@@ -216,7 +215,6 @@ type FeishuConfig struct {
 	EncryptKey        string              `json:"encrypt_key"        env:"PICOCLAW_CHANNELS_FEISHU_ENCRYPT_KEY"`
 	VerificationToken string              `json:"verification_token" env:"PICOCLAW_CHANNELS_FEISHU_VERIFICATION_TOKEN"`
 	AllowFrom         FlexibleStringSlice `json:"allow_from"         env:"PICOCLAW_CHANNELS_FEISHU_ALLOW_FROM"`
-	MaxMessageLength  int                 `json:"max_message_length,omitempty" env:"PICOCLAW_CHANNELS_FEISHU_MAX_MESSAGE_LENGTH"`
 }
 
 type DiscordConfig struct {
@@ -235,19 +233,17 @@ type MaixCamConfig struct {
 }
 
 type QQConfig struct {
-	Enabled          bool                `json:"enabled"    env:"PICOCLAW_CHANNELS_QQ_ENABLED"`
-	AppID            string              `json:"app_id"     env:"PICOCLAW_CHANNELS_QQ_APP_ID"`
-	AppSecret        string              `json:"app_secret" env:"PICOCLAW_CHANNELS_QQ_APP_SECRET"`
-	AllowFrom        FlexibleStringSlice `json:"allow_from" env:"PICOCLAW_CHANNELS_QQ_ALLOW_FROM"`
-	MaxMessageLength int                 `json:"max_message_length,omitempty" env:"PICOCLAW_CHANNELS_QQ_MAX_MESSAGE_LENGTH"`
+	Enabled   bool                `json:"enabled"    env:"PICOCLAW_CHANNELS_QQ_ENABLED"`
+	AppID     string              `json:"app_id"     env:"PICOCLAW_CHANNELS_QQ_APP_ID"`
+	AppSecret string              `json:"app_secret" env:"PICOCLAW_CHANNELS_QQ_APP_SECRET"`
+	AllowFrom FlexibleStringSlice `json:"allow_from" env:"PICOCLAW_CHANNELS_QQ_ALLOW_FROM"`
 }
 
 type DingTalkConfig struct {
-	Enabled          bool                `json:"enabled"       env:"PICOCLAW_CHANNELS_DINGTALK_ENABLED"`
-	ClientID         string              `json:"client_id"     env:"PICOCLAW_CHANNELS_DINGTALK_CLIENT_ID"`
-	ClientSecret     string              `json:"client_secret" env:"PICOCLAW_CHANNELS_DINGTALK_CLIENT_SECRET"`
-	AllowFrom        FlexibleStringSlice `json:"allow_from"    env:"PICOCLAW_CHANNELS_DINGTALK_ALLOW_FROM"`
-	MaxMessageLength int                 `json:"max_message_length,omitempty" env:"PICOCLAW_CHANNELS_DINGTALK_MAX_MESSAGE_LENGTH"`
+	Enabled      bool                `json:"enabled"       env:"PICOCLAW_CHANNELS_DINGTALK_ENABLED"`
+	ClientID     string              `json:"client_id"     env:"PICOCLAW_CHANNELS_DINGTALK_CLIENT_ID"`
+	ClientSecret string              `json:"client_secret" env:"PICOCLAW_CHANNELS_DINGTALK_CLIENT_SECRET"`
+	AllowFrom    FlexibleStringSlice `json:"allow_from"    env:"PICOCLAW_CHANNELS_DINGTALK_ALLOW_FROM"`
 }
 
 type SlackConfig struct {
@@ -276,7 +272,6 @@ type OneBotConfig struct {
 	ReconnectInterval  int                 `json:"reconnect_interval"   env:"PICOCLAW_CHANNELS_ONEBOT_RECONNECT_INTERVAL"`
 	GroupTriggerPrefix []string            `json:"group_trigger_prefix" env:"PICOCLAW_CHANNELS_ONEBOT_GROUP_TRIGGER_PREFIX"`
 	AllowFrom          FlexibleStringSlice `json:"allow_from"           env:"PICOCLAW_CHANNELS_ONEBOT_ALLOW_FROM"`
-	MaxMessageLength   int                 `json:"max_message_length,omitempty" env:"PICOCLAW_CHANNELS_ONEBOT_MAX_MESSAGE_LENGTH"`
 }
 
 type WeComConfig struct {
diff --git a/pkg/utils/message.go b/pkg/utils/message.go
index 0c91d99f9..4bb51074e 100644
--- a/pkg/utils/message.go
+++ b/pkg/utils/message.go
@@ -106,6 +106,10 @@ func SplitMessage(content string, maxLen int) []string {
 						msgEndOffset = startIndex + innerLimit
 					}
 
+					if msgEndOffset > len(runes) {
+						msgEndOffset = len(runes)
+					}
+
 					chunkStr := string(runes[startIndex:msgEndOffset])
 					messages = append(messages, strings.TrimRight(chunkStr, " \t\n\r")+"\n```")
 
@@ -138,6 +142,9 @@ func SplitMessage(content string, maxLen int) []string {
 				} else {
 					// Hard split inside (last resort)
 					msgEndOffset = startIndex + maxLen - 5
+					if msgEndOffset > len(runes) {
+						msgEndOffset = len(runes)
+					}
 					chunkStr := string(runes[startIndex:msgEndOffset])
 					messages = append(messages, strings.TrimRight(chunkStr, " \t\n\r")+"\n```")