Files
clawgo/pkg/tools/parallel.go
2026-02-13 13:50:09 +08:00

109 lines
2.5 KiB
Go

package tools
import (
"context"
"fmt"
"sync"
)
const maxParallelToolCalls = 8
type ParallelTool struct {
registry *ToolRegistry
}
func NewParallelTool(registry *ToolRegistry) *ParallelTool {
return &ParallelTool{registry: registry}
}
func (t *ParallelTool) Name() string {
return "parallel"
}
func (t *ParallelTool) Description() string {
return "Execute multiple tools concurrently using Go's goroutines. Returns a map of tool names/IDs to their results."
}
func (t *ParallelTool) Parameters() map[string]interface{} {
return map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"calls": map[string]interface{}{
"type": "array",
"items": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"tool": map[string]interface{}{
"type": "string",
"description": "Name of the tool to call",
},
"arguments": map[string]interface{}{
"type": "object",
"description": "Arguments for the tool",
},
"id": map[string]interface{}{
"type": "string",
"description": "Optional unique ID to identify this specific result",
},
},
"required": []string{"tool", "arguments"},
},
},
},
"required": []string{"calls"},
}
}
func (t *ParallelTool) Execute(ctx context.Context, args map[string]interface{}) (string, error) {
callsRaw, ok := args["calls"].([]interface{})
if !ok {
return "", fmt.Errorf("calls must be an array")
}
results := make(map[string]string)
var mu sync.Mutex
var wg sync.WaitGroup
sem := make(chan struct{}, maxParallelToolCalls)
for i, c := range callsRaw {
call, ok := c.(map[string]interface{})
if !ok {
continue
}
toolName, _ := call["tool"].(string)
toolArgs, _ := call["arguments"].(map[string]interface{})
id, _ := call["id"].(string)
if id == "" {
id = fmt.Sprintf("call_%d_%s", i, toolName)
}
wg.Add(1)
go func(id, name string, args map[string]interface{}) {
defer wg.Done()
sem <- struct{}{}
defer func() { <-sem }()
res, err := t.registry.Execute(ctx, name, args)
mu.Lock()
defer mu.Unlock()
if err != nil {
results[id] = fmt.Sprintf("Error: %v", err)
} else {
results[id] = res
}
}(id, toolName, toolArgs)
}
wg.Wait()
// Simple string representation for the agent
var output string
for id, res := range results {
output += fmt.Sprintf("--- Result for %s ---\n%s\n", id, res)
}
return output, nil
}