refactor: Remove Telegram message chunking and simplify reasoning content handling.

This commit is contained in:
Avisek 2026-02-22 23:14:41 +05:30
parent b07ac8081e
commit 08c6b84f9f
4 changed files with 87 additions and 162 deletions

View file

@ -79,25 +79,6 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers
}
}
const telegramMaxMessageLength = 4096
func chunkString(s string, size int) []string {
if size <= 0 || s == "" {
return nil
}
runes := []rune(s)
chunks := make([]string, 0, (len(runes)+size-1)/size)
for i := 0; i < len(runes); i += size {
end := min(i + size, len(runes))
chunks = append(chunks, string(runes[i:end]))
}
return chunks
}
// registerSharedTools registers tools that are shared across all agents (web, message, spawn).
func registerSharedTools(
cfg *config.Config,
@ -486,7 +467,7 @@ func (al *AgentLoop) runAgentLoop(ctx context.Context, agent *AgentInstance, opt
}
func (al *AgentLoop) targetReasoningChannelID(channelName string) (chatID string) {
var channels = al.cfg.Channels
channels := al.cfg.Channels
switch channelName {
case "telegram":
@ -517,25 +498,17 @@ func (al *AgentLoop) targetReasoningChannelID(channelName string) (chatID string
return
}
func (al *AgentLoop) handleReasoning(reasoningContent, channelName, channelID string) {
if reasoningContent == "" || channelName == "" || channelID == "" {
return
}
messages := []string{reasoningContent}
if channelName == "telegram" {
messages = chunkString(reasoningContent, telegramMaxMessageLength)
}
for _, message := range messages {
al.bus.PublishOutbound(bus.OutboundMessage{
Channel: channelName,
ChatID: channelID,
Content: message,
Content: reasoningContent,
})
}
}
// runLLMIteration executes the LLM call loop with tool handling.
func (al *AgentLoop) runLLMIteration(

View file

@ -7,7 +7,6 @@ import (
"path/filepath"
"testing"
"time"
"unicode/utf8"
"github.com/sipeed/picoclaw/pkg/bus"
"github.com/sipeed/picoclaw/pkg/config"
@ -633,37 +632,6 @@ func TestAgentLoop_ContextExhaustionRetry(t *testing.T) {
}
}
func TestChunkString(t *testing.T) {
t.Run("returns nil for invalid size or empty input", func(t *testing.T) {
if got := chunkString("", 10); got != nil {
t.Fatalf("expected nil for empty input, got %v", got)
}
if got := chunkString("abc", 0); got != nil {
t.Fatalf("expected nil for size=0, got %v", got)
}
if got := chunkString("abc", -1); got != nil {
t.Fatalf("expected nil for size<0, got %v", got)
}
})
t.Run("chunks by rune count and preserves utf8 validity", func(t *testing.T) {
in := "ab😀cd界x"
got := chunkString(in, 3)
want := []string{"ab😀", "cd界", "x"}
if len(got) != len(want) {
t.Fatalf("chunk count mismatch: got %d want %d (%v)", len(got), len(want), got)
}
for i := range want {
if got[i] != want[i] {
t.Fatalf("chunk[%d] mismatch: got %q want %q", i, got[i], want[i])
}
if !utf8.ValidString(got[i]) {
t.Fatalf("chunk[%d] is not valid utf8: %q", i, got[i])
}
}
})
}
func TestTargetReasoningChannelID_AllChannels(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "agent-test-*")
if err != nil {
@ -774,42 +742,26 @@ func TestHandleReasoning(t *testing.T) {
}
})
t.Run("chunks telegram messages", func(t *testing.T) {
t.Run("publishes one message for telegram", func(t *testing.T) {
al, msgBus := newLoop(t)
large := make([]rune, telegramMaxMessageLength+5)
for i := range large {
large[i] = '界'
}
largeReasoning := string(large)
al.handleReasoning(largeReasoning, "telegram", "tg-chat")
reasoning := "hello telegram reasoning"
al.handleReasoning(reasoning, "telegram", "tg-chat")
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
defer cancel()
msg1, ok := msgBus.SubscribeOutbound(ctx)
msg, ok := msgBus.SubscribeOutbound(ctx)
if !ok {
t.Fatal("expected first outbound message")
}
msg2, ok := msgBus.SubscribeOutbound(ctx)
if !ok {
t.Fatal("expected second outbound message")
t.Fatal("expected outbound message")
}
if msg1.Channel != "telegram" || msg2.Channel != "telegram" {
t.Fatalf("expected telegram channel messages, got %+v and %+v", msg1, msg2)
if msg.Channel != "telegram" {
t.Fatalf("expected telegram channel message, got %+v", msg)
}
if msg1.ChatID != "tg-chat" || msg2.ChatID != "tg-chat" {
t.Fatalf("expected chatID tg-chat, got %+v and %+v", msg1, msg2)
if msg.ChatID != "tg-chat" {
t.Fatalf("expected chatID tg-chat, got %+v", msg)
}
gotCombined := msg1.Content + msg2.Content
if gotCombined != largeReasoning {
t.Fatalf("chunked content mismatch: got len=%d want len=%d", len(gotCombined), len(largeReasoning))
}
if len([]rune(msg1.Content)) != telegramMaxMessageLength {
t.Fatalf("first chunk rune length = %d, want %d", len([]rune(msg1.Content)), telegramMaxMessageLength)
}
if len([]rune(msg2.Content)) != 5 {
t.Fatalf("second chunk rune length = %d, want 5", len([]rune(msg2.Content)))
if msg.Content != reasoning {
t.Fatalf("content mismatch: got %q want %q", msg.Content, reasoning)
}
})
}