Merge pull request #524 from mattn/perf/strings-builder

Use strings.Builder instead of += concatenation in loops
This commit is contained in:
Meng Zhuo 2026-02-20 23:24:47 +08:00 committed by GitHub
commit 55227762e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 57 additions and 63 deletions

View file

@ -146,15 +146,15 @@ func (cb *ContextBuilder) LoadBootstrapFiles() string {
"IDENTITY.md", "IDENTITY.md",
} }
var result string var sb strings.Builder
for _, filename := range bootstrapFiles { for _, filename := range bootstrapFiles {
filePath := filepath.Join(cb.workspace, filename) filePath := filepath.Join(cb.workspace, filename)
if data, err := os.ReadFile(filePath); err == nil { if data, err := os.ReadFile(filePath); err == nil {
result += fmt.Sprintf("## %s\n\n%s\n\n", filename, string(data)) fmt.Fprintf(&sb, "## %s\n\n%s\n\n", filename, data)
} }
} }
return result return sb.String()
} }
func (cb *ContextBuilder) BuildMessages(history []providers.Message, summary string, currentMessage string, media []string, channel, chatID string) []providers.Message { func (cb *ContextBuilder) BuildMessages(history []providers.Message, summary string, currentMessage string, media []string, channel, chatID string) []providers.Message {

View file

@ -828,49 +828,49 @@ func formatMessagesForLog(messages []providers.Message) string {
return "[]" return "[]"
} }
var result string var sb strings.Builder
result += "[\n" sb.WriteString("[\n")
for i, msg := range messages { for i, msg := range messages {
result += fmt.Sprintf(" [%d] Role: %s\n", i, msg.Role) fmt.Fprintf(&sb, " [%d] Role: %s\n", i, msg.Role)
if len(msg.ToolCalls) > 0 { if len(msg.ToolCalls) > 0 {
result += " ToolCalls:\n" sb.WriteString(" ToolCalls:\n")
for _, tc := range msg.ToolCalls { for _, tc := range msg.ToolCalls {
result += fmt.Sprintf(" - ID: %s, Type: %s, Name: %s\n", tc.ID, tc.Type, tc.Name) fmt.Fprintf(&sb, " - ID: %s, Type: %s, Name: %s\n", tc.ID, tc.Type, tc.Name)
if tc.Function != nil { if tc.Function != nil {
result += fmt.Sprintf(" Arguments: %s\n", utils.Truncate(tc.Function.Arguments, 200)) fmt.Fprintf(&sb, " Arguments: %s\n", utils.Truncate(tc.Function.Arguments, 200))
} }
} }
} }
if msg.Content != "" { if msg.Content != "" {
content := utils.Truncate(msg.Content, 200) content := utils.Truncate(msg.Content, 200)
result += fmt.Sprintf(" Content: %s\n", content) fmt.Fprintf(&sb, " Content: %s\n", content)
} }
if msg.ToolCallID != "" { if msg.ToolCallID != "" {
result += fmt.Sprintf(" ToolCallID: %s\n", msg.ToolCallID) fmt.Fprintf(&sb, " ToolCallID: %s\n", msg.ToolCallID)
} }
result += "\n" sb.WriteString("\n")
} }
result += "]" sb.WriteString("]")
return result return sb.String()
} }
// formatToolsForLog formats tool definitions for logging // formatToolsForLog formats tool definitions for logging
func formatToolsForLog(tools []providers.ToolDefinition) string { func formatToolsForLog(toolDefs []providers.ToolDefinition) string {
if len(tools) == 0 { if len(toolDefs) == 0 {
return "[]" return "[]"
} }
var result string var sb strings.Builder
result += "[\n" sb.WriteString("[\n")
for i, tool := range tools { for i, tool := range toolDefs {
result += fmt.Sprintf(" [%d] Type: %s, Name: %s\n", i, tool.Type, tool.Function.Name) fmt.Fprintf(&sb, " [%d] Type: %s, Name: %s\n", i, tool.Type, tool.Function.Name)
result += fmt.Sprintf(" Description: %s\n", tool.Function.Description) fmt.Fprintf(&sb, " Description: %s\n", tool.Function.Description)
if len(tool.Function.Parameters) > 0 { if len(tool.Function.Parameters) > 0 {
result += fmt.Sprintf(" Parameters: %s\n", utils.Truncate(fmt.Sprintf("%v", tool.Function.Parameters), 200)) fmt.Fprintf(&sb, " Parameters: %s\n", utils.Truncate(fmt.Sprintf("%v", tool.Function.Parameters), 200))
} }
} }
result += "]" sb.WriteString("]")
return result return sb.String()
} }
// summarizeSession summarizes the conversation history for a session. // summarizeSession summarizes the conversation history for a session.
@ -946,14 +946,18 @@ func (al *AgentLoop) summarizeSession(agent *AgentInstance, sessionKey string) {
// summarizeBatch summarizes a batch of messages. // summarizeBatch summarizes a batch of messages.
func (al *AgentLoop) summarizeBatch(ctx context.Context, agent *AgentInstance, batch []providers.Message, existingSummary string) (string, error) { func (al *AgentLoop) summarizeBatch(ctx context.Context, agent *AgentInstance, batch []providers.Message, existingSummary string) (string, error) {
prompt := "Provide a concise summary of this conversation segment, preserving core context and key points.\n" var sb strings.Builder
sb.WriteString("Provide a concise summary of this conversation segment, preserving core context and key points.\n")
if existingSummary != "" { if existingSummary != "" {
prompt += "Existing context: " + existingSummary + "\n" sb.WriteString("Existing context: ")
sb.WriteString(existingSummary)
sb.WriteString("\n")
} }
prompt += "\nCONVERSATION:\n" sb.WriteString("\nCONVERSATION:\n")
for _, m := range batch { for _, m := range batch {
prompt += fmt.Sprintf("%s: %s\n", m.Role, m.Content) fmt.Fprintf(&sb, "%s: %s\n", m.Role, m.Content)
} }
prompt := sb.String()
response, err := agent.Provider.Chat(ctx, []providers.Message{{Role: "user", Content: prompt}}, nil, agent.Model, map[string]interface{}{ response, err := agent.Provider.Chat(ctx, []providers.Message{{Role: "user", Content: prompt}}, nil, agent.Model, map[string]interface{}{
"max_tokens": 1024, "max_tokens": 1024,

View file

@ -10,6 +10,7 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"time" "time"
) )
@ -100,7 +101,8 @@ func (ms *MemoryStore) AppendToday(content string) error {
// GetRecentDailyNotes returns daily notes from the last N days. // GetRecentDailyNotes returns daily notes from the last N days.
// Contents are joined with "---" separator. // Contents are joined with "---" separator.
func (ms *MemoryStore) GetRecentDailyNotes(days int) string { func (ms *MemoryStore) GetRecentDailyNotes(days int) string {
var notes []string var sb strings.Builder
first := true
for i := 0; i < days; i++ { for i := 0; i < days; i++ {
date := time.Now().AddDate(0, 0, -i) date := time.Now().AddDate(0, 0, -i)
@ -109,53 +111,41 @@ func (ms *MemoryStore) GetRecentDailyNotes(days int) string {
filePath := filepath.Join(ms.memoryDir, monthDir, dateStr+".md") filePath := filepath.Join(ms.memoryDir, monthDir, dateStr+".md")
if data, err := os.ReadFile(filePath); err == nil { if data, err := os.ReadFile(filePath); err == nil {
notes = append(notes, string(data)) if !first {
sb.WriteString("\n\n---\n\n")
}
sb.Write(data)
first = false
} }
} }
if len(notes) == 0 { return sb.String()
return ""
}
// Join with separator
var result string
for i, note := range notes {
if i > 0 {
result += "\n\n---\n\n"
}
result += note
}
return result
} }
// GetMemoryContext returns formatted memory context for the agent prompt. // GetMemoryContext returns formatted memory context for the agent prompt.
// Includes long-term memory and recent daily notes. // Includes long-term memory and recent daily notes.
func (ms *MemoryStore) GetMemoryContext() string { func (ms *MemoryStore) GetMemoryContext() string {
var parts []string
// Long-term memory
longTerm := ms.ReadLongTerm() longTerm := ms.ReadLongTerm()
if longTerm != "" {
parts = append(parts, "## Long-term Memory\n\n"+longTerm)
}
// Recent daily notes (last 3 days)
recentNotes := ms.GetRecentDailyNotes(3) recentNotes := ms.GetRecentDailyNotes(3)
if recentNotes != "" {
parts = append(parts, "## Recent Daily Notes\n\n"+recentNotes)
}
if len(parts) == 0 { if longTerm == "" && recentNotes == "" {
return "" return ""
} }
// Join parts with separator var sb strings.Builder
var result string
for i, part := range parts { if longTerm != "" {
if i > 0 { sb.WriteString("## Long-term Memory\n\n")
result += "\n\n---\n\n" sb.WriteString(longTerm)
}
result += part
} }
return fmt.Sprintf("# Memory\n\n%s", result)
if recentNotes != "" {
if longTerm != "" {
sb.WriteString("\n\n---\n\n")
}
sb.WriteString("## Recent Daily Notes\n\n")
sb.WriteString(recentNotes)
}
return sb.String()
} }