refactor: use json valid function from `charmbracelet/x/json`

Andrey Nering created

Change summary

go.mod           |  1 +
go.sum           |  2 ++
openai/json.go   | 14 --------------
openai/openai.go |  5 +++--
4 files changed, 6 insertions(+), 16 deletions(-)

Detailed changes

go.mod 🔗

@@ -4,6 +4,7 @@ go 1.24.5
 
 require (
 	github.com/anthropics/anthropic-sdk-go v1.10.0
+	github.com/charmbracelet/x/json v0.2.0
 	github.com/go-viper/mapstructure/v2 v2.4.0
 	github.com/google/uuid v1.6.0
 	github.com/openai/openai-go/v2 v2.3.0

go.sum 🔗

@@ -1,5 +1,7 @@
 github.com/anthropics/anthropic-sdk-go v1.10.0 h1:jDKQTfC0miIEj21eMmPrNSLKTNdNa3nHZOhd4wZz1cI=
 github.com/anthropics/anthropic-sdk-go v1.10.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE=
+github.com/charmbracelet/x/json v0.2.0 h1:DqB+ZGx2h+Z+1s98HOuOyli+i97wsFQIxP2ZQANTPrQ=
+github.com/charmbracelet/x/json v0.2.0/go.mod h1:opFIflx2YgXgi49xVUu8gEQ21teFAxyMwvOiZhIvWNM=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=

openai/json.go 🔗

@@ -1,14 +0,0 @@
-package openai
-
-import (
-	"encoding/json"
-)
-
-func isValidJSON[T string | []byte](data T) bool {
-	if len(data) == 0 { // hot path
-		return false
-	}
-	var m json.RawMessage
-	err := json.Unmarshal([]byte(data), &m)
-	return err == nil
-}

openai/openai.go 🔗

@@ -12,6 +12,7 @@ import (
 	"strings"
 
 	"github.com/charmbracelet/ai/ai"
+	xjson "github.com/charmbracelet/x/json"
 	"github.com/google/uuid"
 	"github.com/openai/openai-go/v2"
 	"github.com/openai/openai-go/v2/option"
@@ -584,7 +585,7 @@ func (o languageModel) Stream(ctx context.Context, call ai.Call) (ai.StreamRespo
 								return
 							}
 							toolCalls[toolCallDelta.Index] = existingToolCall
-							if isValidJSON(existingToolCall.arguments) {
+							if xjson.IsValid(existingToolCall.arguments) {
 								if !yield(ai.StreamPart{
 									Type: ai.StreamPartTypeToolInputEnd,
 									ID:   existingToolCall.id,
@@ -645,7 +646,7 @@ func (o languageModel) Stream(ctx context.Context, call ai.Call) (ai.StreamRespo
 								}) {
 									return
 								}
-								if isValidJSON(toolCalls[toolCallDelta.Index].arguments) {
+								if xjson.IsValid(toolCalls[toolCallDelta.Index].arguments) {
 									if !yield(ai.StreamPart{
 										Type: ai.StreamPartTypeToolInputEnd,
 										ID:   toolCallDelta.ID,