mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-14 02:15:57 +00:00
- Token cost tracking: accumulate input/output tokens per subagent, include in announce messages and persist to DB - Per-edition rate limits: MaxSubagentConcurrent/Depth on Edition struct, tenant-scoped concurrency enforcement in Spawn/RunSync - WaitAll action: spawn(action=wait, timeout=N) blocks until all children complete, returns merged summary - Auto-retry: configurable MaxRetries (default 2) with linear backoff for transient LLM failures - Producer-consumer announce queue: merges staggered subagent results into single LLM run (same pattern as team task announces) - Raw metadata in bus messages to prevent double-formatting - Fire-and-forget DB persistence with detached context + tenant scope - Split oversized files for <200 line compliance
71 lines
2.1 KiB
Go
71 lines
2.1 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/tools"
|
|
)
|
|
|
|
// buildMergedSubagentAnnounce creates the announce message for one or more subagent results.
|
|
func buildMergedSubagentAnnounce(entries []subagentAnnounceEntry, roster tools.SubagentRoster) string {
|
|
var sb strings.Builder
|
|
|
|
if len(entries) == 1 {
|
|
e := entries[0]
|
|
statusLabel := "completed successfully"
|
|
if e.Status == "failed" {
|
|
statusLabel = "failed"
|
|
} else if e.Status == "cancelled" {
|
|
statusLabel = "was cancelled"
|
|
}
|
|
fmt.Fprintf(&sb, "[System Message] A subagent task %q just %s.\n\nResult:\n%s\n\nStats: runtime %s, iterations %d, tokens %d in / %d out\n",
|
|
e.Label, statusLabel, e.Content,
|
|
e.Runtime.Round(time.Millisecond), e.Iterations,
|
|
e.InputTokens, e.OutputTokens)
|
|
} else {
|
|
completed, failed := 0, 0
|
|
for _, e := range entries {
|
|
switch e.Status {
|
|
case "completed":
|
|
completed++
|
|
case "failed":
|
|
failed++
|
|
}
|
|
}
|
|
if failed > 0 && completed > 0 {
|
|
fmt.Fprintf(&sb, "[System Message] %d subagent task(s) completed, %d failed.\n", completed, failed)
|
|
} else if failed > 0 {
|
|
fmt.Fprintf(&sb, "[System Message] %d subagent task(s) failed.\n", failed)
|
|
} else {
|
|
fmt.Fprintf(&sb, "[System Message] %d subagent tasks completed.\n", completed)
|
|
}
|
|
for i, e := range entries {
|
|
fmt.Fprintf(&sb, "\n--- Task #%d: %q (%s, %s, tokens %d/%d) ---\nResult: %s\n",
|
|
i+1, e.Label, e.Status,
|
|
e.Runtime.Round(time.Millisecond),
|
|
e.InputTokens, e.OutputTokens, e.Content)
|
|
}
|
|
}
|
|
|
|
// Append roster for context.
|
|
sb.WriteString("\n")
|
|
sb.WriteString(tools.BuildReplyInstruction(roster))
|
|
|
|
// Smart prompting based on remaining tasks.
|
|
running := 0
|
|
for _, e := range roster.Entries {
|
|
if e.Status == tools.TaskStatusRunning {
|
|
running++
|
|
}
|
|
}
|
|
if running == 0 {
|
|
sb.WriteString("\n\nAll subagent tasks finished. Present a comprehensive summary of ALL results to the user.")
|
|
} else {
|
|
sb.WriteString("\n\nSome subagents are still running. Briefly acknowledge this result (1-2 sentences). A full summary will come when all tasks complete.")
|
|
}
|
|
|
|
return sb.String()
|
|
}
|