62 lines
1.2 KiB
Go
62 lines
1.2 KiB
Go
|
|
package llm
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"fmt"
|
||
|
|
"log/slog"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
// callTools executes each tool call in the message and returns the
|
||
|
|
// resulting tool result messages.
|
||
|
|
func (c *Client) callTools(ctx context.Context, msg Message) (
|
||
|
|
results []Message, err error,
|
||
|
|
) {
|
||
|
|
for _, tc := range msg.ToolCalls {
|
||
|
|
c.log.InfoContext(
|
||
|
|
ctx,
|
||
|
|
"calling tool",
|
||
|
|
slog.String("name", tc.Function.Name),
|
||
|
|
slog.String("args", tc.Function.Arguments),
|
||
|
|
)
|
||
|
|
|
||
|
|
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),
|
||
|
|
)
|
||
|
|
result = fmt.Sprintf(
|
||
|
|
`{"ok": false, "error": %q}`, err,
|
||
|
|
)
|
||
|
|
} else {
|
||
|
|
c.log.InfoContext(
|
||
|
|
ctx,
|
||
|
|
"called tool",
|
||
|
|
slog.String("name", tc.Function.Name),
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Content cannot be empty.
|
||
|
|
if strings.TrimSpace(result) == "" {
|
||
|
|
result = `{"ok": true, "result": null}`
|
||
|
|
}
|
||
|
|
|
||
|
|
toolResult := Message{
|
||
|
|
Role: RoleTool,
|
||
|
|
ContentParts: []ContentPart{{
|
||
|
|
Type: ContentTypeText, Text: result,
|
||
|
|
}},
|
||
|
|
Name: tc.Function.Name,
|
||
|
|
ToolCallID: tc.ID,
|
||
|
|
}
|
||
|
|
results = append(results, toolResult)
|
||
|
|
}
|
||
|
|
|
||
|
|
return results, nil
|
||
|
|
}
|