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:
parent
3e57679c69
commit
7912b22d8f
14 changed files with 129 additions and 129 deletions
|
|
@ -362,7 +362,6 @@ func mediaTempDirPattern() string {
|
|||
return "^" + regexp.QuoteMeta(filepath.Clean(media.TempDir())) + "(?:" + sep + "|$)"
|
||||
}
|
||||
|
||||
|
||||
func expandHome(path string) string {
|
||||
if path == "" {
|
||||
return path
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
// Fast path: text-only message (most common) — avoid Builder alloc
|
||||
var content string
|
||||
if !hasMedia {
|
||||
if message.Text != "" {
|
||||
content += message.Text
|
||||
content = message.Text
|
||||
}
|
||||
} else {
|
||||
var cb strings.Builder
|
||||
if message.Text != "" {
|
||||
cb.WriteString(message.Text)
|
||||
}
|
||||
|
||||
if message.Caption != "" {
|
||||
if content != "" {
|
||||
content += "\n"
|
||||
if cb.Len() > 0 {
|
||||
cb.WriteByte('\n')
|
||||
}
|
||||
content += message.Caption
|
||||
cb.WriteString(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"
|
||||
if cb.Len() > 0 {
|
||||
cb.WriteByte('\n')
|
||||
}
|
||||
content += "[image: photo]"
|
||||
cb.WriteString("[image: photo]")
|
||||
}
|
||||
}
|
||||
|
||||
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 cb.Len() > 0 {
|
||||
cb.WriteByte('\n')
|
||||
}
|
||||
content += "[voice]"
|
||||
cb.WriteString("[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 cb.Len() > 0 {
|
||||
cb.WriteByte('\n')
|
||||
}
|
||||
content += "[audio]"
|
||||
cb.WriteString("[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 cb.Len() > 0 {
|
||||
cb.WriteByte('\n')
|
||||
}
|
||||
content += "[file]"
|
||||
cb.WriteString("[file]")
|
||||
}
|
||||
}
|
||||
|
||||
content = cb.String()
|
||||
}
|
||||
if content == "" {
|
||||
content = "[empty message]"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
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')
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue