Skip to content

Commit 5522776

Browse files
authored
Merge pull request #524 from mattn/perf/strings-builder
Use strings.Builder instead of += concatenation in loops
2 parents 1ef33c9 + df49f66 commit 5522776

File tree

3 files changed

+56
-62
lines changed

3 files changed

+56
-62
lines changed

pkg/agent/context.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,15 @@ func (cb *ContextBuilder) LoadBootstrapFiles() string {
146146
"IDENTITY.md",
147147
}
148148

149-
var result string
149+
var sb strings.Builder
150150
for _, filename := range bootstrapFiles {
151151
filePath := filepath.Join(cb.workspace, filename)
152152
if data, err := os.ReadFile(filePath); err == nil {
153-
result += fmt.Sprintf("## %s\n\n%s\n\n", filename, string(data))
153+
fmt.Fprintf(&sb, "## %s\n\n%s\n\n", filename, data)
154154
}
155155
}
156156

157-
return result
157+
return sb.String()
158158
}
159159

160160
func (cb *ContextBuilder) BuildMessages(history []providers.Message, summary string, currentMessage string, media []string, channel, chatID string) []providers.Message {

pkg/agent/loop.go

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -828,49 +828,49 @@ func formatMessagesForLog(messages []providers.Message) string {
828828
return "[]"
829829
}
830830

831-
var result string
832-
result += "[\n"
831+
var sb strings.Builder
832+
sb.WriteString("[\n")
833833
for i, msg := range messages {
834-
result += fmt.Sprintf(" [%d] Role: %s\n", i, msg.Role)
834+
fmt.Fprintf(&sb, " [%d] Role: %s\n", i, msg.Role)
835835
if len(msg.ToolCalls) > 0 {
836-
result += " ToolCalls:\n"
836+
sb.WriteString(" ToolCalls:\n")
837837
for _, tc := range msg.ToolCalls {
838-
result += fmt.Sprintf(" - ID: %s, Type: %s, Name: %s\n", tc.ID, tc.Type, tc.Name)
838+
fmt.Fprintf(&sb, " - ID: %s, Type: %s, Name: %s\n", tc.ID, tc.Type, tc.Name)
839839
if tc.Function != nil {
840-
result += fmt.Sprintf(" Arguments: %s\n", utils.Truncate(tc.Function.Arguments, 200))
840+
fmt.Fprintf(&sb, " Arguments: %s\n", utils.Truncate(tc.Function.Arguments, 200))
841841
}
842842
}
843843
}
844844
if msg.Content != "" {
845845
content := utils.Truncate(msg.Content, 200)
846-
result += fmt.Sprintf(" Content: %s\n", content)
846+
fmt.Fprintf(&sb, " Content: %s\n", content)
847847
}
848848
if msg.ToolCallID != "" {
849-
result += fmt.Sprintf(" ToolCallID: %s\n", msg.ToolCallID)
849+
fmt.Fprintf(&sb, " ToolCallID: %s\n", msg.ToolCallID)
850850
}
851-
result += "\n"
851+
sb.WriteString("\n")
852852
}
853-
result += "]"
854-
return result
853+
sb.WriteString("]")
854+
return sb.String()
855855
}
856856

857857
// formatToolsForLog formats tool definitions for logging
858-
func formatToolsForLog(tools []providers.ToolDefinition) string {
859-
if len(tools) == 0 {
858+
func formatToolsForLog(toolDefs []providers.ToolDefinition) string {
859+
if len(toolDefs) == 0 {
860860
return "[]"
861861
}
862862

863-
var result string
864-
result += "[\n"
865-
for i, tool := range tools {
866-
result += fmt.Sprintf(" [%d] Type: %s, Name: %s\n", i, tool.Type, tool.Function.Name)
867-
result += fmt.Sprintf(" Description: %s\n", tool.Function.Description)
863+
var sb strings.Builder
864+
sb.WriteString("[\n")
865+
for i, tool := range toolDefs {
866+
fmt.Fprintf(&sb, " [%d] Type: %s, Name: %s\n", i, tool.Type, tool.Function.Name)
867+
fmt.Fprintf(&sb, " Description: %s\n", tool.Function.Description)
868868
if len(tool.Function.Parameters) > 0 {
869-
result += fmt.Sprintf(" Parameters: %s\n", utils.Truncate(fmt.Sprintf("%v", tool.Function.Parameters), 200))
869+
fmt.Fprintf(&sb, " Parameters: %s\n", utils.Truncate(fmt.Sprintf("%v", tool.Function.Parameters), 200))
870870
}
871871
}
872-
result += "]"
873-
return result
872+
sb.WriteString("]")
873+
return sb.String()
874874
}
875875

876876
// summarizeSession summarizes the conversation history for a session.
@@ -946,14 +946,18 @@ func (al *AgentLoop) summarizeSession(agent *AgentInstance, sessionKey string) {
946946

947947
// summarizeBatch summarizes a batch of messages.
948948
func (al *AgentLoop) summarizeBatch(ctx context.Context, agent *AgentInstance, batch []providers.Message, existingSummary string) (string, error) {
949-
prompt := "Provide a concise summary of this conversation segment, preserving core context and key points.\n"
949+
var sb strings.Builder
950+
sb.WriteString("Provide a concise summary of this conversation segment, preserving core context and key points.\n")
950951
if existingSummary != "" {
951-
prompt += "Existing context: " + existingSummary + "\n"
952+
sb.WriteString("Existing context: ")
953+
sb.WriteString(existingSummary)
954+
sb.WriteString("\n")
952955
}
953-
prompt += "\nCONVERSATION:\n"
956+
sb.WriteString("\nCONVERSATION:\n")
954957
for _, m := range batch {
955-
prompt += fmt.Sprintf("%s: %s\n", m.Role, m.Content)
958+
fmt.Fprintf(&sb, "%s: %s\n", m.Role, m.Content)
956959
}
960+
prompt := sb.String()
957961

958962
response, err := agent.Provider.Chat(ctx, []providers.Message{{Role: "user", Content: prompt}}, nil, agent.Model, map[string]interface{}{
959963
"max_tokens": 1024,

pkg/agent/memory.go

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"fmt"
1111
"os"
1212
"path/filepath"
13+
"strings"
1314
"time"
1415
)
1516

@@ -100,7 +101,8 @@ func (ms *MemoryStore) AppendToday(content string) error {
100101
// GetRecentDailyNotes returns daily notes from the last N days.
101102
// Contents are joined with "---" separator.
102103
func (ms *MemoryStore) GetRecentDailyNotes(days int) string {
103-
var notes []string
104+
var sb strings.Builder
105+
first := true
104106

105107
for i := 0; i < days; i++ {
106108
date := time.Now().AddDate(0, 0, -i)
@@ -109,53 +111,41 @@ func (ms *MemoryStore) GetRecentDailyNotes(days int) string {
109111
filePath := filepath.Join(ms.memoryDir, monthDir, dateStr+".md")
110112

111113
if data, err := os.ReadFile(filePath); err == nil {
112-
notes = append(notes, string(data))
114+
if !first {
115+
sb.WriteString("\n\n---\n\n")
116+
}
117+
sb.Write(data)
118+
first = false
113119
}
114120
}
115121

116-
if len(notes) == 0 {
117-
return ""
118-
}
119-
120-
// Join with separator
121-
var result string
122-
for i, note := range notes {
123-
if i > 0 {
124-
result += "\n\n---\n\n"
125-
}
126-
result += note
127-
}
128-
return result
122+
return sb.String()
129123
}
130124

131125
// GetMemoryContext returns formatted memory context for the agent prompt.
132126
// Includes long-term memory and recent daily notes.
133127
func (ms *MemoryStore) GetMemoryContext() string {
134-
var parts []string
135-
136-
// Long-term memory
137128
longTerm := ms.ReadLongTerm()
138-
if longTerm != "" {
139-
parts = append(parts, "## Long-term Memory\n\n"+longTerm)
140-
}
141-
142-
// Recent daily notes (last 3 days)
143129
recentNotes := ms.GetRecentDailyNotes(3)
144-
if recentNotes != "" {
145-
parts = append(parts, "## Recent Daily Notes\n\n"+recentNotes)
146-
}
147130

148-
if len(parts) == 0 {
131+
if longTerm == "" && recentNotes == "" {
149132
return ""
150133
}
151134

152-
// Join parts with separator
153-
var result string
154-
for i, part := range parts {
155-
if i > 0 {
156-
result += "\n\n---\n\n"
135+
var sb strings.Builder
136+
137+
if longTerm != "" {
138+
sb.WriteString("## Long-term Memory\n\n")
139+
sb.WriteString(longTerm)
140+
}
141+
142+
if recentNotes != "" {
143+
if longTerm != "" {
144+
sb.WriteString("\n\n---\n\n")
157145
}
158-
result += part
146+
sb.WriteString("## Recent Daily Notes\n\n")
147+
sb.WriteString(recentNotes)
159148
}
160-
return fmt.Sprintf("# Memory\n\n%s", result)
149+
150+
return sb.String()
161151
}

0 commit comments

Comments
 (0)