From c241764b7dfb7e847f69ce3ed6c3b1d407deacc1 Mon Sep 17 00:00:00 2001 From: fatelei Date: Thu, 19 Feb 2026 23:34:05 +0800 Subject: [PATCH] chore: merge user message --- pkg/agent/context.go | 29 +++++++++++------ pkg/agent/context_test.go | 65 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 pkg/agent/context_test.go diff --git a/pkg/agent/context.go b/pkg/agent/context.go index f61caaff8..555de8a06 100644 --- a/pkg/agent/context.go +++ b/pkg/agent/context.go @@ -12,7 +12,6 @@ import ( "github.com/sipeed/picoclaw/pkg/providers" "github.com/sipeed/picoclaw/pkg/skills" "github.com/sipeed/picoclaw/pkg/tools" - "github.com/sipeed/picoclaw/pkg/utils" ) type ContextBuilder struct { @@ -201,12 +200,23 @@ func (cb *ContextBuilder) BuildMessages(history []providers.Message, summary str // Diegox-17 // --- FIN DEL FIX --- + var coalescedUser *providers.Message if len(history) > 0 && history[len(history)-1].Role == "user" { - logger.WarnCF("agent", "Removing trailing user message from history to prevent consecutive user messages", - map[string]interface{}{ - "content_preview": utils.Truncate(history[len(history)-1].Content, 50), - }) + last := history[len(history)-1] history = history[:len(history)-1] + merged := last.Content + if merged != "" && currentMessage != "" { + merged += "\n\n" + currentMessage + } else if currentMessage != "" { + merged = currentMessage + } + coalescedUser = &providers.Message{Role: "user", Content: merged} + logger.InfoCF("agent", "Coalesced consecutive user messages", + map[string]interface{}{ + "prev_len": len(last.Content), + "new_len": len(currentMessage), + "merged_len": len(merged), + }) } messages = append(messages, providers.Message{ @@ -216,10 +226,11 @@ func (cb *ContextBuilder) BuildMessages(history []providers.Message, summary str messages = append(messages, history...) - messages = append(messages, providers.Message{ - Role: "user", - Content: currentMessage, - }) + if coalescedUser != nil { + messages = append(messages, *coalescedUser) + } else { + messages = append(messages, providers.Message{Role: "user", Content: currentMessage}) + } return messages } diff --git a/pkg/agent/context_test.go b/pkg/agent/context_test.go new file mode 100644 index 000000000..3eb054c8e --- /dev/null +++ b/pkg/agent/context_test.go @@ -0,0 +1,65 @@ +package agent + +import ( + "os" + "path/filepath" + "testing" + + "github.com/sipeed/picoclaw/pkg/providers" +) + +// helper to create a temporary workspace for ContextBuilder +func withTempWorkspace(t *testing.T, fn func(string)) { + t.Helper() + dir := t.TempDir() + // ensure required subdirs exist if any future logic reads them + _ = os.MkdirAll(filepath.Join(dir, "skills"), 0755) + fn(dir) +} + +func TestBuildMessages_CoalescesConsecutiveUserMessages(t *testing.T) { + withTempWorkspace(t, func(ws string) { + cb := NewContextBuilder(ws) + + history := []providers.Message{ + {Role: "system", Content: "sys"}, + {Role: "assistant", Content: "hi"}, + {Role: "user", Content: "first"}, + } + + msgs := cb.BuildMessages(history, "", "second", nil, "cli", "chat1") + if len(msgs) < 2 { + t.Fatalf("expected at least 2 messages, got %d", len(msgs)) + } + if msgs[0].Role != "system" { + t.Fatalf("expected first message to be system, got %s", msgs[0].Role) + } + // ensure no consecutive user messages and last is a single coalesced user + last := msgs[len(msgs)-1] + if last.Role != "user" { + t.Fatalf("expected last message role=user, got %s", last.Role) + } + if last.Content != "first\n\nsecond" { + t.Fatalf("expected coalesced content 'first\\n\\nsecond', got %q", last.Content) + } + }) +} + +func TestBuildMessages_AppendsUserIfNoConsecutive(t *testing.T) { + withTempWorkspace(t, func(ws string) { + cb := NewContextBuilder(ws) + history := []providers.Message{ + {Role: "assistant", Content: "hi"}, + } + msgs := cb.BuildMessages(history, "", "second", nil, "cli", "chat1") + if len(msgs) < 3 { + t.Fatalf("expected at least 3 messages (system + history + user), got %d", len(msgs)) + } + if msgs[len(msgs)-1].Role != "user" { + t.Fatalf("expected last message role=user, got %s", msgs[len(msgs)-1].Role) + } + if msgs[len(msgs)-2].Role == "user" { + t.Fatalf("did not expect consecutive user messages") + } + }) +} \ No newline at end of file