1
1
package openai
2
2
3
3
import (
4
+ "encoding/json"
5
+ "os"
6
+
4
7
openai "github.com/gptscript-ai/chat-completion-client"
8
+ "github.com/gptscript-ai/gptscript/pkg/types"
9
+ "github.com/pkoukk/tiktoken-go"
10
+ tiktoken_loader "github.com/pkoukk/tiktoken-go-loader"
5
11
)
6
12
7
13
const DefaultMaxTokens = 128_000
@@ -18,7 +24,7 @@ func getBudget(maxTokens int) int {
18
24
return maxTokens
19
25
}
20
26
21
- func dropMessagesOverCount (maxTokens int , msgs []openai.ChatCompletionMessage ) (result []openai.ChatCompletionMessage ) {
27
+ func dropMessagesOverCount (maxTokens int , msgs []openai.ChatCompletionMessage ) (result []openai.ChatCompletionMessage , err error ) {
22
28
var (
23
29
lastSystem int
24
30
withinBudget int
@@ -27,7 +33,11 @@ func dropMessagesOverCount(maxTokens int, msgs []openai.ChatCompletionMessage) (
27
33
28
34
for i , msg := range msgs {
29
35
if msg .Role == openai .ChatMessageRoleSystem {
30
- budget -= countMessage (msg )
36
+ count , err := countMessage (msg )
37
+ if err != nil {
38
+ return nil , err
39
+ }
40
+ budget -= count
31
41
lastSystem = i
32
42
result = append (result , msg )
33
43
} else {
@@ -37,7 +47,11 @@ func dropMessagesOverCount(maxTokens int, msgs []openai.ChatCompletionMessage) (
37
47
38
48
for i := len (msgs ) - 1 ; i > lastSystem ; i -- {
39
49
withinBudget = i
40
- budget -= countMessage (msgs [i ])
50
+ count , err := countMessage (msgs [i ])
51
+ if err != nil {
52
+ return nil , err
53
+ }
54
+ budget -= count
41
55
if budget <= 0 {
42
56
break
43
57
}
@@ -54,22 +68,58 @@ func dropMessagesOverCount(maxTokens int, msgs []openai.ChatCompletionMessage) (
54
68
if withinBudget == len (msgs )- 1 {
55
69
// We are going to drop all non system messages, which seems useless, so just return them
56
70
// all and let it fail
57
- return msgs
71
+ return msgs , nil
58
72
}
59
73
60
- return append (result , msgs [withinBudget :]... )
74
+ return append (result , msgs [withinBudget :]... ), nil
61
75
}
62
76
63
- func countMessage (msg openai.ChatCompletionMessage ) (count int ) {
64
- count += len (msg .Role )
65
- count += len (msg .Content )
66
- for _ , content := range msg .MultiContent {
67
- count += len (content .Text )
77
+ func countMessage (msg openai.ChatCompletionMessage ) (int , error ) {
78
+ tiktoken .SetBpeLoader (tiktoken_loader .NewOfflineLoader ())
79
+ encoding , err := tiktoken .EncodingForModel ("gpt-4o" )
80
+ if err != nil {
81
+ return 0 , err
82
+ }
83
+
84
+ count := len (encoding .Encode (msg .Role , nil , nil ))
85
+ count += len (encoding .Encode (msg .Content , nil , nil ))
86
+
87
+ // Handle MultiContent by converting to JSON
88
+ multiContentJSON , err := json .Marshal (msg .MultiContent )
89
+ if err != nil {
90
+ return 0 , err
68
91
}
69
- for _ , tool := range msg .ToolCalls {
70
- count += len (tool .Function .Name )
71
- count += len (tool .Function .Arguments )
92
+ count += len (encoding .Encode (string (multiContentJSON ), nil , nil ))
93
+
94
+ // Handle ToolCalls by converting to JSON
95
+ toolCallsJSON , err := json .Marshal (msg .ToolCalls )
96
+ if err != nil {
97
+ return 0 , err
72
98
}
73
- count += len (msg .ToolCallID )
74
- return count / 3
99
+ count += len (encoding .Encode (string (toolCallsJSON ), nil , nil ))
100
+
101
+ count += len (encoding .Encode (msg .ToolCallID , nil , nil ))
102
+
103
+ return count , nil
104
+ }
105
+
106
+ func countTools (tools []types.ChatCompletionTool ) (int , error ) {
107
+ file , err := os .OpenFile ("/Users/grant/log.txt" , os .O_CREATE | os .O_WRONLY | os .O_APPEND , 0644 )
108
+ if err != nil {
109
+ return 0 , err
110
+ }
111
+ defer file .Close ()
112
+ file .WriteString ("counting tools with Tiktoken\n " )
113
+ tiktoken .SetBpeLoader (tiktoken_loader .NewOfflineLoader ())
114
+ encoding , err := tiktoken .EncodingForModel ("gpt-4o" )
115
+ if err != nil {
116
+ return 0 , err
117
+ }
118
+
119
+ toolJSON , err := json .Marshal (tools )
120
+ if err != nil {
121
+ return 0 , err
122
+ }
123
+
124
+ return len (encoding .Encode (string (toolJSON ), nil , nil )), nil
75
125
}
0 commit comments