package promptkit_test import ( "context" "encoding/json" "errors" "net/http" "reflect" "testing" "go.maximumdirect.net/promptkit" ) type receiverMutatingProviderMap map[string]string func (value receiverMutatingProviderMap) MarshalJSON() ([]byte, error) { value["value"] = "encoded" if value["fail"] == "yes" { return nil, errors.New("synthetic encoding failure") } return json.Marshal(map[string]string(value)) } func TestBuiltInEncodingPreservesPreparedProviderValues(t *testing.T) { for _, fail := range []bool{false, true} { name := "successful encoding" if fail { name = "encoding failure diagnostics" } t.Run(name, func(t *testing.T) { calls := 0 config := simpleConfig("message") config.HTTPClient = &http.Client{Transport: encodingOwnershipTransport(t, &calls)} engine, err := promptkit.NewEngine(config) if err != nil { t.Fatal(err) } options := receiverMutatingProviderMap{"value": "original"} if fail { options["fail"] = "yes" } prepared, err := engine.PrepareExecution(context.Background(), promptkit.RunRequest{ PromptID: "prompt", Execution: &promptkit.ExecutionTargetOverride{ ExtraParams: map[string]any{"options": options}, }, }) if err != nil { t.Fatal(err) } before := prepared.Details() result, err := engine.RunPrepared(context.Background(), prepared) if fail { if !errors.Is(err, promptkit.ErrInvalidRequest) || result != nil || calls != 0 { t.Fatalf("encoding failure: result=%+v error=%v dispatches=%d", result, err, calls) } } else if err != nil || result == nil || calls != 1 { t.Fatalf("successful encoding: result=%+v error=%v dispatches=%d", result, err, calls) } else if result.EffectiveModelParams.ExtraParams["options"].(receiverMutatingProviderMap)["value"] != "original" { t.Fatal("custom encoder changed result settings") } if !reflect.DeepEqual(before, prepared.Details()) { t.Fatal("custom encoder changed retained prepared details") } if options["value"] != "original" { t.Fatal("custom encoder changed caller input") } }) } } func TestBuiltInEncodingPreservesSmokeProviderValues(t *testing.T) { calls := 0 config := simpleConfig("unused") config.HTTPClient = &http.Client{Transport: encodingOwnershipTransport(t, &calls)} engine, err := promptkit.NewEngine(config) if err != nil { t.Fatal(err) } options := receiverMutatingProviderMap{"value": "original"} report, err := engine.SmokeTest(context.Background(), promptkit.SmokeTestRequest{ Kind: promptkit.SmokeTestTextInference, ProfileID: "profile", Execution: &promptkit.ExecutionTargetOverride{ExtraParams: map[string]any{"options": options}}, }) if err != nil || report == nil || !report.Completed || calls != 1 { t.Fatalf("smoke result=%+v error=%v dispatches=%d", report, err, calls) } if report.Target.EffectiveSettings.ExtraParams["options"].(receiverMutatingProviderMap)["value"] != "original" { t.Fatal("custom encoder changed smoke report settings") } if options["value"] != "original" { t.Fatal("custom encoder changed caller input") } } func encodingOwnershipTransport(t *testing.T, calls *int) roundTripFunc { t.Helper() return func(request *http.Request) (*http.Response, error) { *calls += 1 var payload struct { Options map[string]string `json:"options"` } if err := json.NewDecoder(request.Body).Decode(&payload); err != nil { return nil, err } if payload.Options["value"] != "encoded" { t.Errorf("custom wire encoding was lost: options=%v", payload.Options) } return observedHTTPResponse(http.StatusOK, `{"choices":[{"message":{"content":"PROMPTKIT_OK"}}]}`), nil } }