perf: eliminate intermediate string allocations in hot paths

- Replace WriteString(fmt.Sprintf(...)) with fmt.Fprintf() across 7 files
  to avoid intermediate string allocation (writes directly to Builder)
- Refactor telegram message composition from O(n²) += to strings.Builder
- Refactor device event formatting from += chain to strings.Builder
- Fix lint issues: misspell, whitespace, gofumpt, gci, unused func

## Benchmark Results

WriteString(Sprintf) vs Fprintf (10-iteration loop, 5 fields each):
  old: 2480 ns/op   2823 B/op   16 allocs/op
  new: 1841 ns/op   1860 B/op    6 allocs/op
  → 26% faster, 34% less memory, 63% fewer allocations

Telegram message build (+= vs strings.Builder):
  AllMedia:  old 403 ns/1104 B/10 allocs → new 118 ns/336 B/3 allocs (3.4x faster)
  LongText:  old 8309 ns/47232 B/10 allocs → new 1483 ns/8064 B/2 allocs (5.6x faster)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
dj-oyu 2026-03-19 11:54:33 +09:00
parent 3e57679c69
commit 7912b22d8f
14 changed files with 129 additions and 129 deletions

View file

@ -362,7 +362,6 @@ func mediaTempDirPattern() string {
return "^" + regexp.QuoteMeta(filepath.Clean(media.TempDir())) + "(?:" + sep + "|$)"
}
func expandHome(path string) string {
if path == "" {
return path

View file

@ -1161,7 +1161,6 @@ func (al *AgentLoop) callLLMWithRetry(
ch, sErr := sp.ChatStream(streamCtx, *messages, toolDefs, model, llmOpts)
if sErr != nil {
return nil, sErr
}
resp, repetition, sErr := consumeStreamWithRepetitionDetection(ch, streamCancel, 1000, onChunk)
if sErr != nil {
@ -1263,7 +1262,6 @@ func (al *AgentLoop) callLLMWithRetry(
opts.SenderID, opts.SenderDisplayName,
)
continue
}
break
}
@ -1375,7 +1373,6 @@ func (al *AgentLoop) publishToolMedia(ctx context.Context, result *tools.ToolRes
})
}
// isNativeSearchProvider reports whether the given LLM provider implements
// NativeSearchCapable and returns true for SupportsNativeSearch.
func isNativeSearchProvider(p providers.LLMProvider) bool {

View file

@ -650,8 +650,8 @@ func (ms *MemoryStore) FormatPlanDisplay() string {
}
var sb strings.Builder
sb.WriteString(fmt.Sprintf("Plan: %s\n", state.taskName))
sb.WriteString(fmt.Sprintf("Status: %s | Phase %d/%d\n\n", state.status, state.currentPhase, len(state.phases)))
fmt.Fprintf(&sb, "Plan: %s\n", state.taskName)
fmt.Fprintf(&sb, "Status: %s | Phase %d/%d\n\n", state.status, state.currentPhase, len(state.phases))
for _, p := range state.phases {
var emoji string
@ -662,7 +662,7 @@ func (ms *MemoryStore) FormatPlanDisplay() string {
} else {
emoji = "\u23F3"
}
sb.WriteString(fmt.Sprintf("%s Phase %d: %s\n", emoji, p.Number, p.Title))
fmt.Fprintf(&sb, "%s Phase %d: %s\n", emoji, p.Number, p.Title)
if p.Number <= state.currentPhase {
for _, s := range p.Steps {
if s.Done {

View file

@ -70,7 +70,7 @@ func (mb *MessageBus) InboundChan() <-chan InboundMessage {
return mb.inbound
}
// ConsumeInbound blocks until an inbound message is available or the context is cancelled.
// ConsumeInbound blocks until an inbound message is available or the context is canceled.
func (mb *MessageBus) ConsumeInbound(ctx context.Context) (InboundMessage, bool) {
select {
case msg, ok := <-mb.inbound:
@ -90,7 +90,7 @@ func (mb *MessageBus) OutboundChan() <-chan OutboundMessage {
return mb.outbound
}
// SubscribeOutbound blocks until an outbound message is available or the context is cancelled.
// SubscribeOutbound blocks until an outbound message is available or the context is canceled.
func (mb *MessageBus) SubscribeOutbound(ctx context.Context) (OutboundMessage, bool) {
select {
case msg, ok := <-mb.outbound:

View file

@ -77,7 +77,7 @@ type channelWorker struct {
}
type Manager struct {
managerExt // fork-specific fields (statusMsgIDs, taskMsgIDs, statusEditTimes)
managerExt // fork-specific fields (statusMsgIDs, taskMsgIDs, statusEditTimes)
channels map[string]Channel
workers map[string]*channelWorker
bus *bus.MessageBus

View file

@ -521,8 +521,9 @@ func (c *TelegramChannel) handleMessage(ctx context.Context, message *telego.Mes
chatID := message.Chat.ID
c.chatIDs[platformID] = chatID
content := ""
mediaPaths := []string{}
hasMedia := message.Caption != "" || len(message.Photo) > 0 ||
message.Voice != nil || message.Audio != nil || message.Document != nil
chatIDStr := fmt.Sprintf("%d", chatID)
messageIDStr := fmt.Sprintf("%d", message.MessageID)
@ -542,63 +543,66 @@ func (c *TelegramChannel) handleMessage(ctx context.Context, message *telego.Mes
return localPath // fallback: use raw path
}
if message.Text != "" {
content += message.Text
}
if message.Caption != "" {
if content != "" {
content += "\n"
// Fast path: text-only message (most common) — avoid Builder alloc
var content string
if !hasMedia {
if message.Text != "" {
content = message.Text
}
content += message.Caption
}
if len(message.Photo) > 0 {
photo := message.Photo[len(message.Photo)-1]
photoPath := c.downloadPhoto(ctx, photo.FileID)
if photoPath != "" {
mediaPaths = append(mediaPaths, storeMedia(photoPath, "photo.jpg"))
if content != "" {
content += "\n"
} else {
var cb strings.Builder
if message.Text != "" {
cb.WriteString(message.Text)
}
if message.Caption != "" {
if cb.Len() > 0 {
cb.WriteByte('\n')
}
content += "[image: photo]"
cb.WriteString(message.Caption)
}
}
if message.Voice != nil {
voicePath := c.downloadFile(ctx, message.Voice.FileID, ".ogg")
if voicePath != "" {
mediaPaths = append(mediaPaths, storeMedia(voicePath, "voice.ogg"))
if content != "" {
content += "\n"
if len(message.Photo) > 0 {
photo := message.Photo[len(message.Photo)-1]
photoPath := c.downloadPhoto(ctx, photo.FileID)
if photoPath != "" {
mediaPaths = append(mediaPaths, storeMedia(photoPath, "photo.jpg"))
if cb.Len() > 0 {
cb.WriteByte('\n')
}
cb.WriteString("[image: photo]")
}
content += "[voice]"
}
}
if message.Audio != nil {
audioPath := c.downloadFile(ctx, message.Audio.FileID, ".mp3")
if audioPath != "" {
mediaPaths = append(mediaPaths, storeMedia(audioPath, "audio.mp3"))
if content != "" {
content += "\n"
if message.Voice != nil {
voicePath := c.downloadFile(ctx, message.Voice.FileID, ".ogg")
if voicePath != "" {
mediaPaths = append(mediaPaths, storeMedia(voicePath, "voice.ogg"))
if cb.Len() > 0 {
cb.WriteByte('\n')
}
cb.WriteString("[voice]")
}
content += "[audio]"
}
}
if message.Document != nil {
docPath := c.downloadFile(ctx, message.Document.FileID, "")
if docPath != "" {
mediaPaths = append(mediaPaths, storeMedia(docPath, "document"))
if content != "" {
content += "\n"
if message.Audio != nil {
audioPath := c.downloadFile(ctx, message.Audio.FileID, ".mp3")
if audioPath != "" {
mediaPaths = append(mediaPaths, storeMedia(audioPath, "audio.mp3"))
if cb.Len() > 0 {
cb.WriteByte('\n')
}
cb.WriteString("[audio]")
}
content += "[file]"
}
if message.Document != nil {
docPath := c.downloadFile(ctx, message.Document.FileID, "")
if docPath != "" {
mediaPaths = append(mediaPaths, storeMedia(docPath, "document"))
if cb.Len() > 0 {
cb.WriteByte('\n')
}
cb.WriteString("[file]")
}
}
content = cb.String()
}
if content == "" {
content = "[empty message]"
}

View file

@ -1,6 +1,9 @@
package events
import "context"
import (
"context"
"strings"
)
type EventSource interface {
Kind() Kind
@ -44,14 +47,26 @@ func (e *DeviceEvent) FormatMessage() string {
actionText = "Disconnected"
}
msg := actionEmoji + " Device " + actionText + "\n\n"
msg += "Type: " + string(e.Kind) + "\n"
msg += "Device: " + e.Vendor + " " + e.Product + "\n"
var b strings.Builder
b.WriteString(actionEmoji)
b.WriteString(" Device ")
b.WriteString(actionText)
b.WriteString("\n\nType: ")
b.WriteString(string(e.Kind))
b.WriteString("\nDevice: ")
b.WriteString(e.Vendor)
b.WriteByte(' ')
b.WriteString(e.Product)
b.WriteByte('\n')
if e.Capabilities != "" {
msg += "Capabilities: " + e.Capabilities + "\n"
b.WriteString("Capabilities: ")
b.WriteString(e.Capabilities)
b.WriteByte('\n')
}
if e.Serial != "" {
msg += "Serial: " + e.Serial + "\n"
b.WriteString("Serial: ")
b.WriteString(e.Serial)
b.WriteByte('\n')
}
return msg
return b.String()
}

View file

@ -375,23 +375,19 @@ func (hs *HeartbeatService) buildResearchContext() string {
b.WriteString("You have research tasks due for progress. For each task below:\n")
b.WriteString("1. If pending, set status to 'active' first\n")
b.WriteString("2. Use web_search to find new information, then add_finding to record it\n")
b.WriteString(
fmt.Sprintf(
"3. **Web search budget: %d calls total this heartbeat** — use them wisely\n",
research.DefaultHeartbeatSearchQuota,
),
)
fmt.Fprintf(&b, "3. **Web search budget: %d calls total this heartbeat** — use them wisely\n",
research.DefaultHeartbeatSearchQuota)
b.WriteString("4. Do NOT set status to 'completed' — research progresses incrementally across heartbeats\n\n")
for _, task := range tasks {
b.WriteString(fmt.Sprintf("### %s [%s] (id: %s)\n", task.Title, task.Status, task.ID))
b.WriteString(fmt.Sprintf("Interval: %s", task.Interval))
fmt.Fprintf(&b, "### %s [%s] (id: %s)\n", task.Title, task.Status, task.ID)
fmt.Fprintf(&b, "Interval: %s", task.Interval)
if !task.LastResearchedAt.IsZero() {
b.WriteString(fmt.Sprintf(" | Last researched: %s", task.LastResearchedAt.Format("2006-01-02 15:04")))
fmt.Fprintf(&b, " | Last researched: %s", task.LastResearchedAt.Format("2006-01-02 15:04"))
}
b.WriteString("\n")
if task.Description != "" {
b.WriteString(fmt.Sprintf("Description: %s\n", task.Description))
fmt.Fprintf(&b, "Description: %s\n", task.Description)
}
docs, err := store.ListDocuments(task.ID)
@ -410,20 +406,20 @@ func (hs *HeartbeatService) buildResearchContext() string {
shown = shown[:maxFindingsPerTask]
}
b.WriteString(fmt.Sprintf("Existing findings (%d total):\n", len(docs)))
fmt.Fprintf(&b, "Existing findings (%d total):\n", len(docs))
for _, d := range shown {
summary := d.Summary
if len(summary) > maxSummaryLen {
summary = summary[:maxSummaryLen] + "..."
}
b.WriteString(fmt.Sprintf("- [%d] %s", d.Seq, d.Title))
fmt.Fprintf(&b, "- [%d] %s", d.Seq, d.Title)
if summary != "" {
b.WriteString(fmt.Sprintf(" — %s", summary))
fmt.Fprintf(&b, " — %s", summary)
}
b.WriteString("\n")
}
if len(docs) > maxFindingsPerTask {
b.WriteString(fmt.Sprintf(" ... and %d more findings\n", len(docs)-maxFindingsPerTask))
fmt.Fprintf(&b, " ... and %d more findings\n", len(docs)-maxFindingsPerTask)
}
b.WriteString("\nAdd NEW findings that build on and extend the above. Do not repeat existing findings.\n\n")
}

View file

@ -35,7 +35,7 @@ func TestProviderChat_StripsGroqAndOllamaPrefixes(t *testing.T) {
},
}
for _, tt := range tests { //nolint:dupl
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var requestBody map[string]any

View file

@ -500,7 +500,7 @@ func TestProviderChat_StripsGroqOllamaDeepseekVivgridNovitaPrefixes(t *testing.T
},
}
for _, tt := range tests { //nolint:dupl
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := p.Chat(t.Context(), []Message{{Role: "user", Content: "hi"}}, nil, tt.input, nil)
if err != nil {

View file

@ -129,12 +129,12 @@ func (t *ResearchTool) RuntimeStatus() string {
b.WriteString("Available research topics:\n")
for _, task := range tasks {
docCount, _ := t.store.DocumentCount(task.ID)
b.WriteString(fmt.Sprintf("- \"%s\" [%s, %d docs] (id: %s)\n",
task.Title, task.Status, docCount, task.ID))
fmt.Fprintf(&b, "- \"%s\" [%s, %d docs] (id: %s)\n",
task.Title, task.Status, docCount, task.ID)
}
if focusID, focusTitle := t.focus.Current(); focusID != "" {
b.WriteString(fmt.Sprintf("\nCurrently focused: \"%s\" (id: %s)\n", focusTitle, focusID))
fmt.Fprintf(&b, "\nCurrently focused: \"%s\" (id: %s)\n", focusTitle, focusID)
}
b.WriteString("\nUse `research recall` to load findings when the user asks about a research topic.\n")
@ -154,11 +154,11 @@ func (t *ResearchTool) listTasks(args map[string]any) *ToolResult {
}
var b strings.Builder
b.WriteString(fmt.Sprintf("Found %d research task(s):\n\n", len(tasks)))
fmt.Fprintf(&b, "Found %d research task(s):\n\n", len(tasks))
for _, task := range tasks {
docCount, _ := t.store.DocumentCount(task.ID)
b.WriteString(fmt.Sprintf("- **%s** [%s] (id: %s, docs: %d)\n %s\n",
task.Title, task.Status, task.ID, docCount, task.Description))
fmt.Fprintf(&b, "- **%s** [%s] (id: %s, docs: %d)\n %s\n",
task.Title, task.Status, task.ID, docCount, task.Description)
}
return NewToolResult(b.String())
}
@ -177,20 +177,20 @@ func (t *ResearchTool) getTask(args map[string]any) *ToolResult {
docs, _ := t.store.ListDocuments(taskID)
var b strings.Builder
b.WriteString(fmt.Sprintf("## %s\n", task.Title))
b.WriteString(fmt.Sprintf("- **Status**: %s\n", task.Status))
b.WriteString(fmt.Sprintf("- **ID**: %s\n", task.ID))
b.WriteString(fmt.Sprintf("- **Output dir**: %s\n", task.OutputDir))
fmt.Fprintf(&b, "## %s\n", task.Title)
fmt.Fprintf(&b, "- **Status**: %s\n", task.Status)
fmt.Fprintf(&b, "- **ID**: %s\n", task.ID)
fmt.Fprintf(&b, "- **Output dir**: %s\n", task.OutputDir)
if task.Description != "" {
b.WriteString(fmt.Sprintf("- **Description**: %s\n", task.Description))
fmt.Fprintf(&b, "- **Description**: %s\n", task.Description)
}
b.WriteString(fmt.Sprintf("- **Created**: %s\n", task.CreatedAt.Format("2006-01-02 15:04")))
fmt.Fprintf(&b, "- **Created**: %s\n", task.CreatedAt.Format("2006-01-02 15:04"))
if len(docs) > 0 {
b.WriteString(fmt.Sprintf("\n### Documents (%d)\n", len(docs)))
fmt.Fprintf(&b, "\n### Documents (%d)\n", len(docs))
for _, d := range docs {
b.WriteString(fmt.Sprintf("- [%d] %s (%s) — %s\n path: %s\n",
d.Seq, d.Title, d.DocType, d.Summary, d.FilePath))
fmt.Fprintf(&b, "- [%d] %s (%s) — %s\n path: %s\n",
d.Seq, d.Title, d.DocType, d.Summary, d.FilePath)
}
} else {
b.WriteString("\nNo documents yet.\n")
@ -313,10 +313,10 @@ func (t *ResearchTool) recall(args map[string]any) *ToolResult {
t.focus.Focus(task.ID, task.Title)
var b strings.Builder
b.WriteString(fmt.Sprintf("# Research Context: %s\n\n", task.Title))
b.WriteString(fmt.Sprintf("**Status**: %s | **Documents**: %d\n", task.Status, len(docs)))
fmt.Fprintf(&b, "# Research Context: %s\n\n", task.Title)
fmt.Fprintf(&b, "**Status**: %s | **Documents**: %d\n", task.Status, len(docs))
if task.Description != "" {
b.WriteString(fmt.Sprintf("**Description**: %s\n", task.Description))
fmt.Fprintf(&b, "**Description**: %s\n", task.Description)
}
b.WriteString("\n---\n\n")
@ -331,7 +331,7 @@ func (t *ResearchTool) recall(args map[string]any) *ToolResult {
absPath := filepath.Join(t.workspace, d.FilePath)
data, readErr := os.ReadFile(absPath)
if readErr != nil {
b.WriteString(fmt.Sprintf("## [%d] %s\n\n(file not found: %s)\n\n", d.Seq, d.Title, d.FilePath))
fmt.Fprintf(&b, "## [%d] %s\n\n(file not found: %s)\n\n", d.Seq, d.Title, d.FilePath)
loaded++
continue
}
@ -340,16 +340,14 @@ func (t *ResearchTool) recall(args map[string]any) *ToolResult {
entrySize := len(d.Title) + len(content) + 40 // rough overhead for headers
if totalBytes+entrySize > maxContextBytes {
remaining := len(docs) - loaded
b.WriteString(
fmt.Sprintf(
"\n---\n*Context limit reached. %d more finding(s) not shown. Use get_task to see the full list.*\n",
remaining,
),
fmt.Fprintf(&b,
"\n---\n*Context limit reached. %d more finding(s) not shown. Use get_task to see the full list.*\n",
remaining,
)
break
}
b.WriteString(fmt.Sprintf("## [%d] %s\n\n", d.Seq, d.Title))
fmt.Fprintf(&b, "## [%d] %s\n\n", d.Seq, d.Title)
b.WriteString(content)
if !strings.HasSuffix(content, "\n") {
b.WriteByte('\n')

View file

@ -97,19 +97,19 @@ func formatSearchResults(query string, results []skills.SearchResult, cached boo
if cached {
source = " (cached)"
}
sb.WriteString(fmt.Sprintf("Found %d skills for %q%s:\n\n", len(results), query, source))
fmt.Fprintf(&sb, "Found %d skills for %q%s:\n\n", len(results), query, source)
for i, r := range results {
sb.WriteString(fmt.Sprintf("%d. **%s**", i+1, r.Slug))
fmt.Fprintf(&sb, "%d. **%s**", i+1, r.Slug)
if r.Version != "" {
sb.WriteString(fmt.Sprintf(" v%s", r.Version))
fmt.Fprintf(&sb, " v%s", r.Version)
}
sb.WriteString(fmt.Sprintf(" (score: %.3f, registry: %s)\n", r.Score, r.RegistryName))
fmt.Fprintf(&sb, " (score: %.3f, registry: %s)\n", r.Score, r.RegistryName)
if r.DisplayName != "" && r.DisplayName != r.Slug {
sb.WriteString(fmt.Sprintf(" Name: %s\n", r.DisplayName))
fmt.Fprintf(&sb, " Name: %s\n", r.DisplayName)
}
if r.Summary != "" {
sb.WriteString(fmt.Sprintf(" %s\n", r.Summary))
fmt.Fprintf(&sb, " %s\n", r.Summary)
}
sb.WriteString("\n")
}

View file

@ -127,11 +127,11 @@ func (t *SpawnStatusTool) Execute(ctx context.Context, args map[string]any) *Too
}
var sb strings.Builder
sb.WriteString(fmt.Sprintf("Subagent status report (%d total):\n", len(tasks)))
fmt.Fprintf(&sb, "Subagent status report (%d total):\n", len(tasks))
for _, status := range []string{"running", "completed", "failed", "canceled"} {
if n := counts[status]; n > 0 {
label := strings.ToUpper(status[:1]) + status[1:] + ":"
sb.WriteString(fmt.Sprintf(" %-10s %d\n", label, n))
fmt.Fprintf(&sb, " %-10s %d\n", label, n)
}
}
sb.WriteString("\n")
@ -148,21 +148,20 @@ func (t *SpawnStatusTool) Execute(ctx context.Context, args map[string]any) *Too
func spawnStatusFormatTask(task *SubagentTask) string {
var sb strings.Builder
header := fmt.Sprintf("[%s] status=%s", task.ID, task.Status)
fmt.Fprintf(&sb, "[%s] status=%s", task.ID, task.Status)
if task.Label != "" {
header += fmt.Sprintf(" label=%q", task.Label)
fmt.Fprintf(&sb, " label=%q", task.Label)
}
if task.AgentID != "" {
header += fmt.Sprintf(" agent=%s", task.AgentID)
fmt.Fprintf(&sb, " agent=%s", task.AgentID)
}
if task.Created > 0 {
created := time.UnixMilli(task.Created).UTC().Format("2006-01-02 15:04:05 UTC")
header += fmt.Sprintf(" created=%s", created)
fmt.Fprintf(&sb, " created=%s", created)
}
sb.WriteString(header)
if task.Task != "" {
sb.WriteString(fmt.Sprintf("\n task: %s", task.Task))
fmt.Fprintf(&sb, "\n task: %s", task.Task)
}
if task.Result != "" {
result := task.Result
@ -171,7 +170,7 @@ func spawnStatusFormatTask(task *SubagentTask) string {
if len(runes) > maxResultLen {
result = string(runes[:maxResultLen]) + "…"
}
sb.WriteString(fmt.Sprintf("\n result: %s", result))
fmt.Fprintf(&sb, "\n result: %s", result)
}
return sb.String()

View file

@ -56,14 +56,6 @@ var gatewayHealthGet = func(url string, timeout time.Duration) (*http.Response,
return client.Get(url)
}
// gatewayHealthScheme returns "https" if the gateway is serving TLS, "http" otherwise.
func gatewayHealthScheme(cfg *config.Config) string {
if cfg != nil && strings.HasPrefix(cfg.Channels.Telegram.WebAppURL, "https://") {
return "https"
}
return "http"
}
// getGatewayHealth checks the gateway health endpoint and returns the status response
// Returns (*health.StatusResponse, statusCode, error). If error is not nil, the other values are not valid.
func (h *Handler) getGatewayHealth(cfg *config.Config, timeout time.Duration) (*health.StatusResponse, int, error) {