Files
goclaw/internal/agent/loop_bench_test.go
T
viettranx 3b4004946e chore: apply go fix syntax upgrades (min/max, switch patterns)
Apply Go 1.21+ min/max builtins and improved switch pattern matching
across test files and utilities. No functional changes.
2026-04-15 11:24:57 +07:00

204 lines
6.2 KiB
Go

package agent
import (
"strings"
"testing"
"github.com/nextlevelbuilder/goclaw/internal/providers"
)
// BenchmarkLimitHistoryTurns_200Messages_Limit20 benchmarks limiting history to last 20 user turns.
// Simulates a conversation with 200 messages (100 user + 100 assistant).
func BenchmarkLimitHistoryTurns_200Messages_Limit20(b *testing.B) {
msgs := makeHistoryMessages(100) // 100 user-assistant pairs = 200 messages
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
limitHistoryTurns(msgs, 20)
}
}
// BenchmarkLimitHistoryTurns_500Messages_Limit10 benchmarks limiting history to last 10 user turns.
// Simulates a longer conversation with 500 messages.
func BenchmarkLimitHistoryTurns_500Messages_Limit10(b *testing.B) {
msgs := makeHistoryMessages(250) // 250 user-assistant pairs = 500 messages
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
limitHistoryTurns(msgs, 10)
}
}
// BenchmarkLimitHistoryTurns_1000Messages_Limit5 benchmarks limiting history to last 5 user turns.
// Simulates a very long conversation with 1000 messages.
func BenchmarkLimitHistoryTurns_1000Messages_Limit5(b *testing.B) {
msgs := makeHistoryMessages(500) // 500 user-assistant pairs = 1000 messages
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
limitHistoryTurns(msgs, 5)
}
}
// BenchmarkSanitizeHistory_Clean benchmarks sanitizing already-clean history.
// No orphaned messages, tool calls matched correctly.
func BenchmarkSanitizeHistory_Clean(b *testing.B) {
msgs := makeHistoryMessages(50) // 50 user-assistant pairs
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
sanitizeHistory(msgs)
}
}
// BenchmarkSanitizeHistory_WithOrphaned benchmarks sanitizing history with orphaned tool messages.
// Common after history truncation.
func BenchmarkSanitizeHistory_WithOrphaned(b *testing.B) {
msgs := makeHistoryMessages(50)
// Insert orphaned tool messages at the start
msgs = append([]providers.Message{
{Role: "tool", ToolCallID: "orphan1", Content: "orphaned result 1"},
{Role: "tool", ToolCallID: "orphan2", Content: "orphaned result 2"},
{Role: "tool", ToolCallID: "orphan3", Content: "orphaned result 3"},
}, msgs...)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
sanitizeHistory(msgs)
}
}
// BenchmarkSanitizeHistory_WithToolCalls benchmarks sanitizing history with tool calls and results.
// Tests the tool call matching and deduplication logic.
func BenchmarkSanitizeHistory_WithToolCalls(b *testing.B) {
msgs := []providers.Message{
{Role: "user", Content: "Use the database tool"},
{Role: "assistant", Content: "I'll query the database", ToolCalls: []providers.ToolCall{
{ID: "call_123", Name: "database", Arguments: map[string]any{"query": "SELECT * FROM users"}},
}},
{Role: "tool", ToolCallID: "call_123", Content: "Results: 5 users"},
{Role: "user", Content: "What about the logs?"},
{Role: "assistant", Content: "Let me check the logs", ToolCalls: []providers.ToolCall{
{ID: "call_456", Name: "file_read", Arguments: map[string]any{"path": "/var/log/app.log"}},
}},
{Role: "tool", ToolCallID: "call_456", Content: "Log contents here"},
{Role: "user", Content: "Thanks"},
}
// Repeat to make it longer
for range 20 {
msgs = append(msgs, msgs[:7]...)
}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
sanitizeHistory(msgs)
}
}
// BenchmarkSanitizeHistory_WithMissingToolResults benchmarks sanitizing history
// with missing tool results that need to be synthesized.
func BenchmarkSanitizeHistory_WithMissingToolResults(b *testing.B) {
msgs := []providers.Message{
{Role: "user", Content: "Use multiple tools"},
{Role: "assistant", Content: "I'll call multiple tools", ToolCalls: []providers.ToolCall{
{ID: "call_1", Name: "tool1", Arguments: map[string]any{"param": "value1"}},
{ID: "call_2", Name: "tool2", Arguments: map[string]any{"param": "value2"}},
{ID: "call_3", Name: "tool3", Arguments: map[string]any{"param": "value3"}},
}},
// Only return result for first tool call
{Role: "tool", ToolCallID: "call_1", Content: "Result 1"},
{Role: "user", Content: "What happened?"},
}
// Repeat to make it longer
for range 25 {
msgs = append(msgs, msgs[:5]...)
}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
sanitizeHistory(msgs)
}
}
// BenchmarkSanitizeHistory_ConsecutiveSameRole benchmarks merging consecutive same-role messages.
// Tests role alternation fixing.
func BenchmarkSanitizeHistory_ConsecutiveSameRole(b *testing.B) {
msgs := []providers.Message{
{Role: "user", Content: "First user message"},
{Role: "user", Content: "Second user message"},
{Role: "user", Content: "Third user message"},
{Role: "assistant", Content: "Response"},
{Role: "user", Content: "Next turn"},
{Role: "assistant", Content: "First assistant response"},
{Role: "assistant", Content: "Second assistant response"},
{Role: "user", Content: "Final user message"},
}
// Repeat to make it longer
for range 30 {
msgs = append(msgs, msgs[:8]...)
}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
sanitizeHistory(msgs)
}
}
// makeHistoryMessages creates a realistic conversation history with alternating user/assistant messages.
// Each pair includes content and some assistant messages have tool calls.
func makeHistoryMessages(pairs int) []providers.Message {
msgs := make([]providers.Message, 0, pairs*2)
content := strings.Repeat("message content ", 10)
for i := range pairs {
// Add user message
msgs = append(msgs, providers.Message{
Role: "user",
Content: content,
})
// Add assistant message (some with tool calls)
assistantMsg := providers.Message{
Role: "assistant",
Content: content,
}
if i%5 == 0 {
assistantMsg.ToolCalls = []providers.ToolCall{
{
ID: "call_" + string(rune('a'+i%26)),
Name: "tool_name",
Arguments: map[string]any{
"param1": "value1",
"param2": 42,
},
},
}
}
msgs = append(msgs, assistantMsg)
// If assistant had tool calls, add tool result
if i%5 == 0 {
msgs = append(msgs, providers.Message{
Role: "tool",
ToolCallID: "call_" + string(rune('a'+i%26)),
Content: "Tool result content",
})
}
}
return msgs
}