Skip to content

Commit a552a45

Browse files
committed
feat(translator): add token counting functionality for Gemini, Claude, and CLI - Introduced `TokenCount` handling across various Codex translators (Gemini, Claude, CLI) with respective implementations. - Added utility methods for token counting and formatting responses. - Integrated `tiktoken-go/tokenizer` library for tokenization. - Updated CodexExecutor with token counting logic to support multiple models including GPT-5 variants. - Refined go.mod and go.sum to include new dependencies. feat(runtime): add token counting functionality across executors - Implemented token counting in OpenAICompatExecutor, QwenExecutor, and IFlowExecutor. - Added utilities for token counting and response formatting using `tiktoken-go/tokenizer`. - Integrated token counting into translators for Gemini, Claude, and Gemini CLI. - Enhanced multiple model support, including GPT-5 variants, for token counting. docs: update environment variable instructions for multi-model support - Added details for setting `ANTHROPIC_DEFAULT_OPUS_MODEL`, `ANTHROPIC_DEFAULT_SONNET_MODEL`, and `ANTHROPIC_DEFAULT_HAIKU_MODEL` for version 2.x.x. - Clarified usage of `ANTHROPIC_MODEL` and `ANTHROPIC_SMALL_FAST_MODEL` for version 1.x.x. - Expanded examples for setting environment variables across different models including Gemini, GPT-5, Claude, and Qwen3.
1 parent f6cf784 commit a552a45

21 files changed

+588
-22
lines changed

README.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,12 +556,17 @@ The server will relay the `loadCodeAssist`, `onboardUser`, and `countTokens` req
556556

557557
## Claude Code with multiple account load balancing
558558

559-
Start CLI Proxy API server, and then set the `ANTHROPIC_BASE_URL`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_MODEL`, `ANTHROPIC_SMALL_FAST_MODEL` environment variables.
559+
Start CLI Proxy API server, and then set the `ANTHROPIC_BASE_URL`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_DEFAULT_OPUS_MODEL`, `ANTHROPIC_DEFAULT_SONNET_MODEL`, `ANTHROPIC_DEFAULT_HAIKU_MODEL` (or `ANTHROPIC_MODEL`, `ANTHROPIC_SMALL_FAST_MODEL` for version 1.x.x) environment variables.
560560

561561
Using Gemini models:
562562
```bash
563563
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
564564
export ANTHROPIC_AUTH_TOKEN=sk-dummy
565+
# version 2.x.x
566+
export ANTHROPIC_DEFAULT_OPUS_MODEL=gemini-2.5-pro
567+
export ANTHROPIC_DEFAULT_SONNET_MODEL=gemini-2.5-flash
568+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=gemini-2.5-flash-lite
569+
# version 1.x.x
565570
export ANTHROPIC_MODEL=gemini-2.5-pro
566571
export ANTHROPIC_SMALL_FAST_MODEL=gemini-2.5-flash
567572
```
@@ -570,6 +575,11 @@ Using OpenAI GPT 5 models:
570575
```bash
571576
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
572577
export ANTHROPIC_AUTH_TOKEN=sk-dummy
578+
# version 2.x.x
579+
export ANTHROPIC_DEFAULT_OPUS_MODEL=gpt-5-high
580+
export ANTHROPIC_DEFAULT_SONNET_MODEL=gpt-5-medium
581+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=gpt-5-minimal
582+
# version 1.x.x
573583
export ANTHROPIC_MODEL=gpt-5
574584
export ANTHROPIC_SMALL_FAST_MODEL=gpt-5-minimal
575585
```
@@ -578,6 +588,11 @@ Using OpenAI GPT 5 Codex models:
578588
```bash
579589
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
580590
export ANTHROPIC_AUTH_TOKEN=sk-dummy
591+
# version 2.x.x
592+
export ANTHROPIC_DEFAULT_OPUS_MODEL=gpt-5-codex-high
593+
export ANTHROPIC_DEFAULT_SONNET_MODEL=gpt-5-codex-medium
594+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=gpt-5-codex-low
595+
# version 1.x.x
581596
export ANTHROPIC_MODEL=gpt-5-codex
582597
export ANTHROPIC_SMALL_FAST_MODEL=gpt-5-codex-low
583598
```
@@ -586,6 +601,11 @@ Using Claude models:
586601
```bash
587602
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
588603
export ANTHROPIC_AUTH_TOKEN=sk-dummy
604+
# version 2.x.x
605+
export ANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-4-1-20250805
606+
export ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-5-20250929
607+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=claude-3-5-haiku-20241022
608+
# version 1.x.x
589609
export ANTHROPIC_MODEL=claude-sonnet-4-20250514
590610
export ANTHROPIC_SMALL_FAST_MODEL=claude-3-5-haiku-20241022
591611
```
@@ -594,6 +614,11 @@ Using Qwen models:
594614
```bash
595615
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
596616
export ANTHROPIC_AUTH_TOKEN=sk-dummy
617+
# version 2.x.x
618+
export ANTHROPIC_DEFAULT_OPUS_MODEL=qwen3-coder-plus
619+
export ANTHROPIC_DEFAULT_SONNET_MODEL=qwen3-coder-plus
620+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=qwen3-coder-flash
621+
# version 1.x.x
597622
export ANTHROPIC_MODEL=qwen3-coder-plus
598623
export ANTHROPIC_SMALL_FAST_MODEL=qwen3-coder-flash
599624
```
@@ -602,6 +627,11 @@ Using iFlow models:
602627
```bash
603628
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
604629
export ANTHROPIC_AUTH_TOKEN=sk-dummy
630+
# version 2.x.x
631+
export ANTHROPIC_DEFAULT_OPUS_MODEL=qwen3-max
632+
export ANTHROPIC_DEFAULT_SONNET_MODEL=qwen3-coder-plus
633+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=qwen3-235b-a22b-instruct
634+
# version 1.x.x
605635
export ANTHROPIC_MODEL=qwen3-max
606636
export ANTHROPIC_SMALL_FAST_MODEL=qwen3-235b-a22b-instruct
607637
```

README_CN.md

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,12 +564,17 @@ export CODE_ASSIST_ENDPOINT="http://127.0.0.1:8317"
564564

565565
## Claude Code 的使用方法
566566

567-
启动 CLI Proxy API 服务器, 设置如下系统环境变量 `ANTHROPIC_BASE_URL`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_MODEL`, `ANTHROPIC_SMALL_FAST_MODEL`
567+
启动 CLI Proxy API 服务器, 设置如下系统环境变量 `ANTHROPIC_BASE_URL`, `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_DEFAULT_OPUS_MODEL`, `ANTHROPIC_DEFAULT_SONNET_MODEL`, `ANTHROPIC_DEFAULT_HAIKU_MODEL` (或 `ANTHROPIC_MODEL`, `ANTHROPIC_SMALL_FAST_MODEL` 对应 1.x.x 版本)
568568

569569
使用 Gemini 模型:
570570
```bash
571571
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
572572
export ANTHROPIC_AUTH_TOKEN=sk-dummy
573+
# 2.x.x 版本
574+
export ANTHROPIC_DEFAULT_OPUS_MODEL=gemini-2.5-pro
575+
export ANTHROPIC_DEFAULT_SONNET_MODEL=gemini-2.5-flash
576+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=gemini-2.5-flash-lite
577+
# 1.x.x 版本
573578
export ANTHROPIC_MODEL=gemini-2.5-pro
574579
export ANTHROPIC_SMALL_FAST_MODEL=gemini-2.5-flash
575580
```
@@ -578,6 +583,11 @@ export ANTHROPIC_SMALL_FAST_MODEL=gemini-2.5-flash
578583
```bash
579584
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
580585
export ANTHROPIC_AUTH_TOKEN=sk-dummy
586+
# 2.x.x 版本
587+
export ANTHROPIC_DEFAULT_OPUS_MODEL=gpt-5-high
588+
export ANTHROPIC_DEFAULT_SONNET_MODEL=gpt-5-medium
589+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=gpt-5-minimal
590+
# 1.x.x 版本
581591
export ANTHROPIC_MODEL=gpt-5
582592
export ANTHROPIC_SMALL_FAST_MODEL=gpt-5-minimal
583593
```
@@ -586,15 +596,24 @@ export ANTHROPIC_SMALL_FAST_MODEL=gpt-5-minimal
586596
```bash
587597
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
588598
export ANTHROPIC_AUTH_TOKEN=sk-dummy
599+
# 2.x.x 版本
600+
export ANTHROPIC_DEFAULT_OPUS_MODEL=gpt-5-codex-high
601+
export ANTHROPIC_DEFAULT_SONNET_MODEL=gpt-5-codex-medium
602+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=gpt-5-codex-low
603+
# 1.x.x 版本
589604
export ANTHROPIC_MODEL=gpt-5-codex
590605
export ANTHROPIC_SMALL_FAST_MODEL=gpt-5-codex-low
591606
```
592607

593-
594608
使用 Claude 模型:
595609
```bash
596610
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
597611
export ANTHROPIC_AUTH_TOKEN=sk-dummy
612+
# 2.x.x 版本
613+
export ANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-4-1-20250805
614+
export ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-5-20250929
615+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=claude-3-5-haiku-20241022
616+
# 1.x.x 版本
598617
export ANTHROPIC_MODEL=claude-sonnet-4-20250514
599618
export ANTHROPIC_SMALL_FAST_MODEL=claude-3-5-haiku-20241022
600619
```
@@ -603,6 +622,11 @@ export ANTHROPIC_SMALL_FAST_MODEL=claude-3-5-haiku-20241022
603622
```bash
604623
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
605624
export ANTHROPIC_AUTH_TOKEN=sk-dummy
625+
# 2.x.x 版本
626+
export ANTHROPIC_DEFAULT_OPUS_MODEL=qwen3-coder-plus
627+
export ANTHROPIC_DEFAULT_SONNET_MODEL=qwen3-coder-plus
628+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=qwen3-coder-flash
629+
# 1.x.x 版本
606630
export ANTHROPIC_MODEL=qwen3-coder-plus
607631
export ANTHROPIC_SMALL_FAST_MODEL=qwen3-coder-flash
608632
```
@@ -611,6 +635,11 @@ export ANTHROPIC_SMALL_FAST_MODEL=qwen3-coder-flash
611635
```bash
612636
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
613637
export ANTHROPIC_AUTH_TOKEN=sk-dummy
638+
# 2.x.x 版本
639+
export ANTHROPIC_DEFAULT_OPUS_MODEL=qwen3-max
640+
export ANTHROPIC_DEFAULT_SONNET_MODEL=qwen3-coder-plus
641+
export ANTHROPIC_DEFAULT_HAIKU_MODEL=qwen3-235b-a22b-instruct
642+
# 1.x.x 版本
614643
export ANTHROPIC_MODEL=qwen3-max
615644
export ANTHROPIC_SMALL_FAST_MODEL=qwen3-235b-a22b-instruct
616645
```

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ require (
77
github.com/gin-gonic/gin v1.10.1
88
github.com/go-git/go-git/v6 v6.0.0-20251009132922-75a182125145
99
github.com/google/uuid v1.6.0
10-
github.com/joho/godotenv v1.5.1
1110
github.com/jackc/pgx/v5 v5.7.6
11+
github.com/joho/godotenv v1.5.1
1212
github.com/klauspost/compress v1.17.4
1313
github.com/minio/minio-go/v7 v7.0.66
1414
github.com/sirupsen/logrus v1.9.3
1515
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
1616
github.com/tidwall/gjson v1.18.0
1717
github.com/tidwall/sjson v1.2.5
18+
github.com/tiktoken-go/tokenizer v0.7.0
1819
golang.org/x/crypto v0.43.0
1920
golang.org/x/net v0.46.0
2021
golang.org/x/oauth2 v0.30.0
@@ -32,6 +33,7 @@ require (
3233
github.com/cloudwego/base64x v0.1.4 // indirect
3334
github.com/cloudwego/iasm v0.2.0 // indirect
3435
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
36+
github.com/dlclark/regexp2 v1.11.5 // indirect
3537
github.com/dustin/go-humanize v1.0.1 // indirect
3638
github.com/emirpasic/gods v1.18.1 // indirect
3739
github.com/gabriel-vasile/mimetype v1.4.3 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGL
2323
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2424
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2525
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
26+
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
27+
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
2628
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
2729
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
2830
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
@@ -147,6 +149,8 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
147149
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
148150
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
149151
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
152+
github.com/tiktoken-go/tokenizer v0.7.0 h1:VMu6MPT0bXFDHr7UPh9uii7CNItVt3X9K90omxL54vw=
153+
github.com/tiktoken-go/tokenizer v0.7.0/go.mod h1:6UCYI/DtOallbmL7sSy30p6YQv60qNyU/4aVigPOx6w=
150154
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
151155
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
152156
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=

internal/runtime/executor/codex_executor.go

Lines changed: 175 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
log "github.com/sirupsen/logrus"
2121
"github.com/tidwall/gjson"
2222
"github.com/tidwall/sjson"
23+
"github.com/tiktoken-go/tokenizer"
2324

2425
"github.com/gin-gonic/gin"
2526
"github.com/google/uuid"
@@ -277,7 +278,180 @@ func (e *CodexExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Au
277278
}
278279

279280
func (e *CodexExecutor) CountTokens(ctx context.Context, auth *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (cliproxyexecutor.Response, error) {
280-
return cliproxyexecutor.Response{Payload: []byte{}}, fmt.Errorf("not implemented")
281+
from := opts.SourceFormat
282+
to := sdktranslator.FromString("codex")
283+
body := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), false)
284+
285+
modelForCounting := req.Model
286+
287+
if util.InArray([]string{"gpt-5", "gpt-5-minimal", "gpt-5-low", "gpt-5-medium", "gpt-5-high"}, req.Model) {
288+
modelForCounting = "gpt-5"
289+
body, _ = sjson.SetBytes(body, "model", "gpt-5")
290+
switch req.Model {
291+
case "gpt-5-minimal":
292+
body, _ = sjson.SetBytes(body, "reasoning.effort", "minimal")
293+
case "gpt-5-low":
294+
body, _ = sjson.SetBytes(body, "reasoning.effort", "low")
295+
case "gpt-5-medium":
296+
body, _ = sjson.SetBytes(body, "reasoning.effort", "medium")
297+
case "gpt-5-high":
298+
body, _ = sjson.SetBytes(body, "reasoning.effort", "high")
299+
default:
300+
body, _ = sjson.SetBytes(body, "reasoning.effort", "low")
301+
}
302+
} else if util.InArray([]string{"gpt-5-codex", "gpt-5-codex-low", "gpt-5-codex-medium", "gpt-5-codex-high"}, req.Model) {
303+
modelForCounting = "gpt-5"
304+
body, _ = sjson.SetBytes(body, "model", "gpt-5-codex")
305+
switch req.Model {
306+
case "gpt-5-codex-low":
307+
body, _ = sjson.SetBytes(body, "reasoning.effort", "low")
308+
case "gpt-5-codex-medium":
309+
body, _ = sjson.SetBytes(body, "reasoning.effort", "medium")
310+
case "gpt-5-codex-high":
311+
body, _ = sjson.SetBytes(body, "reasoning.effort", "high")
312+
default:
313+
body, _ = sjson.SetBytes(body, "reasoning.effort", "low")
314+
}
315+
}
316+
317+
body, _ = sjson.DeleteBytes(body, "previous_response_id")
318+
body, _ = sjson.SetBytes(body, "stream", false)
319+
320+
enc, err := tokenizerForCodexModel(modelForCounting)
321+
if err != nil {
322+
return cliproxyexecutor.Response{}, fmt.Errorf("codex executor: tokenizer init failed: %w", err)
323+
}
324+
325+
count, err := countCodexInputTokens(enc, body)
326+
if err != nil {
327+
return cliproxyexecutor.Response{}, fmt.Errorf("codex executor: token counting failed: %w", err)
328+
}
329+
330+
usageJSON := fmt.Sprintf(`{"response":{"usage":{"input_tokens":%d,"output_tokens":0,"total_tokens":%d}}}`, count, count)
331+
translated := sdktranslator.TranslateTokenCount(ctx, to, from, count, []byte(usageJSON))
332+
return cliproxyexecutor.Response{Payload: []byte(translated)}, nil
333+
}
334+
335+
func tokenizerForCodexModel(model string) (tokenizer.Codec, error) {
336+
sanitized := strings.ToLower(strings.TrimSpace(model))
337+
switch {
338+
case sanitized == "":
339+
return tokenizer.Get(tokenizer.Cl100kBase)
340+
case strings.HasPrefix(sanitized, "gpt-5"):
341+
return tokenizer.ForModel(tokenizer.GPT5)
342+
case strings.HasPrefix(sanitized, "gpt-4.1"):
343+
return tokenizer.ForModel(tokenizer.GPT41)
344+
case strings.HasPrefix(sanitized, "gpt-4o"):
345+
return tokenizer.ForModel(tokenizer.GPT4o)
346+
case strings.HasPrefix(sanitized, "gpt-4"):
347+
return tokenizer.ForModel(tokenizer.GPT4)
348+
case strings.HasPrefix(sanitized, "gpt-3.5"), strings.HasPrefix(sanitized, "gpt-3"):
349+
return tokenizer.ForModel(tokenizer.GPT35Turbo)
350+
default:
351+
return tokenizer.Get(tokenizer.Cl100kBase)
352+
}
353+
}
354+
355+
func countCodexInputTokens(enc tokenizer.Codec, body []byte) (int64, error) {
356+
if enc == nil {
357+
return 0, fmt.Errorf("encoder is nil")
358+
}
359+
if len(body) == 0 {
360+
return 0, nil
361+
}
362+
363+
root := gjson.ParseBytes(body)
364+
var segments []string
365+
366+
if inst := strings.TrimSpace(root.Get("instructions").String()); inst != "" {
367+
segments = append(segments, inst)
368+
}
369+
370+
inputItems := root.Get("input")
371+
if inputItems.IsArray() {
372+
arr := inputItems.Array()
373+
for i := range arr {
374+
item := arr[i]
375+
switch item.Get("type").String() {
376+
case "message":
377+
content := item.Get("content")
378+
if content.IsArray() {
379+
parts := content.Array()
380+
for j := range parts {
381+
part := parts[j]
382+
if text := strings.TrimSpace(part.Get("text").String()); text != "" {
383+
segments = append(segments, text)
384+
}
385+
}
386+
}
387+
case "function_call":
388+
if name := strings.TrimSpace(item.Get("name").String()); name != "" {
389+
segments = append(segments, name)
390+
}
391+
if args := strings.TrimSpace(item.Get("arguments").String()); args != "" {
392+
segments = append(segments, args)
393+
}
394+
case "function_call_output":
395+
if out := strings.TrimSpace(item.Get("output").String()); out != "" {
396+
segments = append(segments, out)
397+
}
398+
default:
399+
if text := strings.TrimSpace(item.Get("text").String()); text != "" {
400+
segments = append(segments, text)
401+
}
402+
}
403+
}
404+
}
405+
406+
tools := root.Get("tools")
407+
if tools.IsArray() {
408+
tarr := tools.Array()
409+
for i := range tarr {
410+
tool := tarr[i]
411+
if name := strings.TrimSpace(tool.Get("name").String()); name != "" {
412+
segments = append(segments, name)
413+
}
414+
if desc := strings.TrimSpace(tool.Get("description").String()); desc != "" {
415+
segments = append(segments, desc)
416+
}
417+
if params := tool.Get("parameters"); params.Exists() {
418+
val := params.Raw
419+
if params.Type == gjson.String {
420+
val = params.String()
421+
}
422+
if trimmed := strings.TrimSpace(val); trimmed != "" {
423+
segments = append(segments, trimmed)
424+
}
425+
}
426+
}
427+
}
428+
429+
textFormat := root.Get("text.format")
430+
if textFormat.Exists() {
431+
if name := strings.TrimSpace(textFormat.Get("name").String()); name != "" {
432+
segments = append(segments, name)
433+
}
434+
if schema := textFormat.Get("schema"); schema.Exists() {
435+
val := schema.Raw
436+
if schema.Type == gjson.String {
437+
val = schema.String()
438+
}
439+
if trimmed := strings.TrimSpace(val); trimmed != "" {
440+
segments = append(segments, trimmed)
441+
}
442+
}
443+
}
444+
445+
text := strings.Join(segments, "\n")
446+
if text == "" {
447+
return 0, nil
448+
}
449+
450+
count, err := enc.Count(text)
451+
if err != nil {
452+
return 0, err
453+
}
454+
return int64(count), nil
281455
}
282456

283457
func (e *CodexExecutor) Refresh(ctx context.Context, auth *cliproxyauth.Auth) (*cliproxyauth.Auth, error) {

0 commit comments

Comments
 (0)