From 75040646e335757d84b05ba7afc71c92e938bc5c Mon Sep 17 00:00:00 2001 From: dwrz Date: Sun, 11 Oct 2026 00:55:57 +0000 Subject: [PATCH] Use json v2 --- internal/llm/client_completions.go | 8 +++---- internal/llm/client_completions_test.go | 31 ++++++++++++------------- internal/llm/client_models.go | 4 ++-- internal/llm/llm.go | 2 +- internal/llm/llm_test.go | 2 +- 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/internal/llm/client_completions.go b/internal/llm/client_completions.go index 9705b9a..c861a90 100644 --- a/internal/llm/client_completions.go +++ b/internal/llm/client_completions.go @@ -4,7 +4,7 @@ import ( "bufio" "bytes" "context" - "encoding/json" + "encoding/json/v2" "fmt" "io" "log/slog" @@ -83,7 +83,7 @@ func (c *Client) completions( ThinkingBudgetTokens: p.ThinkingBudgetTokens, ChatTemplateKWARGS: kwargs, ParallelToolCalls: new(true), - }) + }, json.FormatNilSliceAsNull(true)) if err != nil { return nil, fmt.Errorf( "completions: marshal request body: %w", err, @@ -152,7 +152,7 @@ func (c *Client) completions( } var cr = &ChatResponse{} - if err := json.NewDecoder(res.Body).Decode(cr); err != nil { + if err := json.UnmarshalRead(res.Body, cr); err != nil { return nil, fmt.Errorf("completions: decode response: %w", err) } if len(cr.Choices) == 0 { @@ -283,7 +283,7 @@ func (c *Client) CompletionsStream( StreamOptions: &StreamOptions{IncludeUsage: true}, ThinkingBudgetTokens: p.ThinkingBudgetTokens, Tools: p.Tools, - }) + }, json.FormatNilSliceAsNull(true)) if err != nil { cancel() return nil, fmt.Errorf( diff --git a/internal/llm/client_completions_test.go b/internal/llm/client_completions_test.go index 057ea54..d1dac72 100644 --- a/internal/llm/client_completions_test.go +++ b/internal/llm/client_completions_test.go @@ -2,8 +2,7 @@ package llm import ( "context" - "encoding/json" - jsonv2 "encoding/json/v2" + "encoding/json/v2" "errors" "fmt" "io" @@ -457,7 +456,7 @@ func TestCompletionsReturnsUsageAndTimings(t *testing.T) { t.Errorf("unexpected path: %s", r.URL.Path) } var request ChatRequest - if err := json.NewDecoder(r.Body).Decode(&request); err != nil { + if err := json.UnmarshalRead(r.Body, &request); err != nil { t.Error(err) } if request.LogProbs || request.TopLogProbs != 0 { @@ -480,17 +479,17 @@ func TestCompletionsReturnsUsageAndTimings(t *testing.T) { if !reflect.DeepEqual(res.Metadata, want) { t.Errorf("metadata = %#v, want %#v", res.Metadata, want) } - encoded, err := jsonv2.Marshal( - res.Metadata, jsonv2.FormatNilSliceAsNull(true), + encoded, err := json.Marshal( + res.Metadata, json.FormatNilSliceAsNull(true), ) if err != nil { t.Fatal(err) } var gotJSON, wantJSON map[string]any - if err := jsonv2.Unmarshal(encoded, &gotJSON); err != nil { + if err := json.Unmarshal(encoded, &gotJSON); err != nil { t.Fatal(err) } - if err := jsonv2.Unmarshal([]byte(tt.want), &wantJSON); err != nil { + if err := json.Unmarshal([]byte(tt.want), &wantJSON); err != nil { t.Fatal(err) } if !reflect.DeepEqual(gotJSON, wantJSON) { @@ -713,9 +712,9 @@ data: {"choices":[{"index":0,"delta":{},"logprobs":{"content":null,"refusal":[{" wantChunks: 1, }, { - name: "omitted choice index and metadata", - response: "data: {\"choices\":[{\"delta\":{\"content\":\"answer\"}}]}\n\n", - wantText: "answer", + name: "omitted choice index and metadata", + response: "data: {\"choices\":[{\"delta\":{\"content\":\"answer\"}}]}\n\n", + wantText: "answer", wantMetadata: `{ "choice_index":null, "created":null, @@ -730,14 +729,14 @@ data: {"choices":[{"index":0,"delta":{},"logprobs":{"content":null,"refusal":[{" "timings":null, "usage":null }`, - wantChunks: 1, + wantChunks: 1, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { client := newCompletionTestClient(t, func(w http.ResponseWriter, r *http.Request) { var request ChatRequest - if err := json.NewDecoder(r.Body).Decode(&request); err != nil { + if err := json.UnmarshalRead(r.Body, &request); err != nil { t.Error(err) } if request.LogProbs || request.TopLogProbs != 0 { @@ -761,17 +760,17 @@ data: {"choices":[{"index":0,"delta":{},"logprobs":{"content":null,"refusal":[{" if err := json.Unmarshal([]byte(tt.wantMetadata), &want); err != nil { t.Fatal(err) } - encoded, err := jsonv2.Marshal( - result.Metadata, jsonv2.FormatNilSliceAsNull(true), + encoded, err := json.Marshal( + result.Metadata, json.FormatNilSliceAsNull(true), ) if err != nil { t.Fatal(err) } var gotJSON, wantJSON map[string]any - if err := jsonv2.Unmarshal(encoded, &gotJSON); err != nil { + if err := json.Unmarshal(encoded, &gotJSON); err != nil { t.Fatal(err) } - if err := jsonv2.Unmarshal([]byte(tt.wantMetadata), &wantJSON); err != nil { + if err := json.Unmarshal([]byte(tt.wantMetadata), &wantJSON); err != nil { t.Fatal(err) } if !reflect.DeepEqual(gotJSON, wantJSON) { diff --git a/internal/llm/client_models.go b/internal/llm/client_models.go index 1b54cf9..19fc70f 100644 --- a/internal/llm/client_models.go +++ b/internal/llm/client_models.go @@ -2,7 +2,7 @@ package llm import ( "context" - "encoding/json" + "encoding/json/v2" "fmt" "io" "log/slog" @@ -74,7 +74,7 @@ func (c *Client) ListModels(ctx context.Context) ([]Model, error) { } var body ModelsResponse - if err := json.NewDecoder(res.Body).Decode(&body); err != nil { + if err := json.UnmarshalRead(res.Body, &body); err != nil { return nil, fmt.Errorf( "list models: decode response: %w", err, ) diff --git a/internal/llm/llm.go b/internal/llm/llm.go index 8cc76c3..298cac6 100644 --- a/internal/llm/llm.go +++ b/internal/llm/llm.go @@ -3,7 +3,7 @@ package llm import ( - "encoding/json" + "encoding/json/v2" "strings" ) diff --git a/internal/llm/llm_test.go b/internal/llm/llm_test.go index 8b95457..2aca7de 100644 --- a/internal/llm/llm_test.go +++ b/internal/llm/llm_test.go @@ -2,7 +2,7 @@ package llm import ( "context" - "encoding/json" + "encoding/json/v2" "errors" "fmt" "io"