-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtool_calls.go
74 lines (64 loc) · 2.09 KB
/
tool_calls.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package aichat
import (
"encoding/json"
"fmt"
)
// ToolCall represents a call to an external tool or function
type ToolCall struct {
ID string `json:"id,omitempty"`
Type string `json:"type"`
Function Function `json:"function"`
}
// RangePendingToolCalls iterates through messages to find and process tool calls that haven't received a response.
// It performs two passes: first to identify which tool calls have responses, then to process pending calls.
// The provided function is called for each pending tool call.
func (chat *Chat) RangePendingToolCalls(fn func(toolCallContext *ToolCallContext) error) error {
// Create a map to track which tool calls have responses
responded := make(map[string]bool)
// First pass: identify which tool calls have responses
chat.RangeByRole("tool", func(msg *Message) error {
if msg.ToolCallID != "" {
responded[msg.ToolCallID] = true
}
return nil
})
// Second pass: process pending tool calls
return chat.RangeByRole("assistant", func(msg *Message) error {
for _, call := range msg.ToolCalls {
if responded[call.ID] {
continue
}
if err := fn(&ToolCallContext{
Chat: chat,
ToolCall: &call,
}); err != nil {
return err
}
responded[call.ID] = true
}
return nil
})
}
// ToolCallContext represents a tool call within a chat context, managing the lifecycle
// of a single tool invocation including its execution and response handling.
type ToolCallContext struct {
ToolCall *ToolCall
Chat *Chat
}
// Name returns the name of the function
func (tcc *ToolCallContext) Name() string {
return tcc.ToolCall.Function.Name
}
// Arguments returns the arguments to the function as a map
func (tcc *ToolCallContext) Arguments() (map[string]any, error) {
return tcc.ToolCall.Function.ArgumentsMap()
}
// Return sends the result of the function call back to the chat
func (tcc *ToolCallContext) Return(result map[string]any) error {
jsonData, err := json.Marshal(result)
if err != nil {
return fmt.Errorf("failed to marshal result: %v", err)
}
tcc.Chat.AddToolContent(tcc.Name(), tcc.ToolCall.ID, string(jsonData))
return nil
}