2026-06-26 14:22:05 +00:00
|
|
|
package llm
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2026-07-08 01:59:11 +00:00
|
|
|
"runtime"
|
|
|
|
|
"sync"
|
2026-07-08 11:52:45 +00:00
|
|
|
|
|
|
|
|
"log/slog"
|
2026-06-26 14:22:05 +00:00
|
|
|
)
|
|
|
|
|
|
2026-07-08 01:59:11 +00:00
|
|
|
// callTools executes each tool call in the message concurrently and returns
|
|
|
|
|
// the resulting tool result messages in the same order as the input calls.
|
|
|
|
|
func (c *Client) callTools(ctx context.Context, msg Message) []Message {
|
|
|
|
|
var (
|
|
|
|
|
results = make([]Message, len(msg.ToolCalls))
|
|
|
|
|
sem = make(chan struct{}, runtime.NumCPU()*2)
|
|
|
|
|
wg sync.WaitGroup
|
|
|
|
|
)
|
|
|
|
|
for i, tc := range msg.ToolCalls {
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
go func(idx int, tc ToolCall) {
|
|
|
|
|
defer wg.Done()
|
|
|
|
|
sem <- struct{}{}
|
|
|
|
|
defer func() { <-sem }()
|
2026-06-26 14:22:05 +00:00
|
|
|
|
|
|
|
|
c.log.InfoContext(
|
|
|
|
|
ctx,
|
2026-07-08 01:59:11 +00:00
|
|
|
"calling tool",
|
2026-06-26 14:22:05 +00:00
|
|
|
slog.String("name", tc.Function.Name),
|
2026-07-08 01:59:11 +00:00
|
|
|
slog.String("args", tc.Function.Arguments),
|
2026-06-26 14:22:05 +00:00
|
|
|
)
|
|
|
|
|
|
2026-07-08 01:59:11 +00:00
|
|
|
result, err := c.registry.Execute(
|
|
|
|
|
ctx, tc.Function.Name, tc.Function.Arguments,
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.log.ErrorContext(
|
|
|
|
|
ctx,
|
|
|
|
|
"failed to call tool",
|
|
|
|
|
slog.Any("error", err),
|
|
|
|
|
slog.String("name", tc.Function.Name),
|
|
|
|
|
)
|
2026-07-08 11:52:45 +00:00
|
|
|
results[idx] = Message{
|
|
|
|
|
Role: RoleTool,
|
|
|
|
|
ContentParts: []ContentPart{{
|
|
|
|
|
Type: ContentTypeText,
|
|
|
|
|
Text: err.Error(),
|
|
|
|
|
}},
|
|
|
|
|
Name: tc.Function.Name,
|
|
|
|
|
ToolCallID: tc.ID,
|
|
|
|
|
}
|
|
|
|
|
return
|
2026-07-08 01:59:11 +00:00
|
|
|
}
|
2026-06-26 14:22:05 +00:00
|
|
|
|
2026-07-08 11:52:45 +00:00
|
|
|
c.log.InfoContext(
|
|
|
|
|
ctx,
|
|
|
|
|
"called tool",
|
|
|
|
|
slog.String("name", tc.Function.Name),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
formatted := result.FormatResult()
|
2026-07-08 01:59:11 +00:00
|
|
|
|
|
|
|
|
results[idx] = Message{
|
|
|
|
|
Role: RoleTool,
|
|
|
|
|
ContentParts: []ContentPart{{
|
2026-07-08 11:52:45 +00:00
|
|
|
Type: ContentTypeText,
|
|
|
|
|
Text: formatted,
|
2026-07-08 01:59:11 +00:00
|
|
|
}},
|
|
|
|
|
Name: tc.Function.Name,
|
|
|
|
|
ToolCallID: tc.ID,
|
|
|
|
|
}
|
|
|
|
|
}(i, tc)
|
2026-06-26 14:22:05 +00:00
|
|
|
}
|
|
|
|
|
|
2026-07-08 01:59:11 +00:00
|
|
|
wg.Wait()
|
|
|
|
|
return results
|
2026-06-26 14:22:05 +00:00
|
|
|
}
|