diff --git a/server/agentengine/internal/helper/encode.go b/server/agentengine/internal/helper/encode.go index 8e9eb905d..6dd5f0a0f 100644 --- a/server/agentengine/internal/helper/encode.go +++ b/server/agentengine/internal/helper/encode.go @@ -15,6 +15,7 @@ package helper import ( + "encoding/base64" "fmt" "log" "reflect" @@ -120,6 +121,9 @@ func convertSnake(path, indent string, o any) (any, error) { } return m, nil case reflect.Slice: + if v.Type().Elem().Kind() == reflect.Uint8 { + return base64.StdEncoding.EncodeToString(v.Bytes()), nil + } res := []any{} for i := 0; i < v.Len(); i++ { elem, err := convertSnake(path+".[]", indent+" ", v.Index(i).Interface()) diff --git a/server/agentengine/internal/helper/encode_test.go b/server/agentengine/internal/helper/encode_test.go index d84bfe62b..bab4470fa 100644 --- a/server/agentengine/internal/helper/encode_test.go +++ b/server/agentengine/internal/helper/encode_test.go @@ -163,6 +163,62 @@ func TestEventLogProbs(t *testing.T) { } } +func TestByteSlice(t *testing.T) { + event := session.Event{ + ID: "1", + LLMResponse: model.LLMResponse{ + Content: &genai.Content{ + Parts: []*genai.Part{ + { + Text: "hi", + ThoughtSignature: []byte{0xDE, 0xAD, 0xBE, 0xEF}, + }, + }, + }, + }, + } + o, err := convertSnake("", "", event) + if err != nil { + t.Fatalf("convertSnake() failed: %v", err) + } + m, ok := o.(map[string]any) + if !ok { + t.Fatalf("o is not a map: %T", o) + } + content, ok := m["content"].(map[string]any) + if !ok { + t.Fatalf("content is not a map: %T", m["content"]) + } + parts, ok := content["parts"].([]any) + if !ok || len(parts) != 1 { + t.Fatalf("parts is not a 1-element slice: %v", content["parts"]) + } + part, ok := parts[0].(map[string]any) + if !ok { + t.Fatalf("part is not a map: %T", parts[0]) + } + want := "3q2+7w==" + if got, _ := part["thought_signature"].(string); got != want { + t.Errorf("thought_signature = %q, want %q", got, want) + } +} + +func TestByteSliceOmitEmpty(t *testing.T) { + type A struct { + Sig []byte `json:"sig,omitempty"` + } + got, err := convertSnake("", "", A{}) + if err != nil { + t.Fatalf("convertSnake() failed: %v", err) + } + m, ok := got.(map[string]any) + if !ok { + t.Fatalf("got is not a map: %T", got) + } + if _, present := m["sig"]; present { + t.Errorf("sig should be omitted for an empty []byte, got: %v", m["sig"]) + } +} func TestEmbedded(t *testing.T) { type A struct { anInteger int