mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-03-30 04:22:58 +00:00
976 lines
24 KiB
Go
976 lines
24 KiB
Go
package common
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/QuantumNous/new-api/types"
|
|
)
|
|
|
|
func TestApplyParamOverrideTrimPrefix(t *testing.T) {
|
|
// trim_prefix example:
|
|
// {"operations":[{"path":"model","mode":"trim_prefix","value":"openai/"}]}
|
|
input := []byte(`{"model":"openai/gpt-4","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "trim_prefix",
|
|
"value": "openai/",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideTrimSuffix(t *testing.T) {
|
|
// trim_suffix example:
|
|
// {"operations":[{"path":"model","mode":"trim_suffix","value":"-latest"}]}
|
|
input := []byte(`{"model":"gpt-4-latest","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "trim_suffix",
|
|
"value": "-latest",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideTrimNoop(t *testing.T) {
|
|
// trim_prefix no-op example:
|
|
// {"operations":[{"path":"model","mode":"trim_prefix","value":"openai/"}]}
|
|
input := []byte(`{"model":"gpt-4","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "trim_prefix",
|
|
"value": "openai/",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideTrimRequiresValue(t *testing.T) {
|
|
// trim_prefix requires value example:
|
|
// {"operations":[{"path":"model","mode":"trim_prefix"}]}
|
|
input := []byte(`{"model":"gpt-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "trim_prefix",
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := ApplyParamOverride(input, override, nil)
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestApplyParamOverrideReplace(t *testing.T) {
|
|
// replace example:
|
|
// {"operations":[{"path":"model","mode":"replace","from":"openai/","to":""}]}
|
|
input := []byte(`{"model":"openai/gpt-4o-mini","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "replace",
|
|
"from": "openai/",
|
|
"to": "",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4o-mini","temperature":0.7}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideRegexReplace(t *testing.T) {
|
|
// regex_replace example:
|
|
// {"operations":[{"path":"model","mode":"regex_replace","from":"^gpt-","to":"openai/gpt-"}]}
|
|
input := []byte(`{"model":"gpt-4o-mini","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "regex_replace",
|
|
"from": "^gpt-",
|
|
"to": "openai/gpt-",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"openai/gpt-4o-mini","temperature":0.7}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideReplaceRequiresFrom(t *testing.T) {
|
|
// replace requires from example:
|
|
// {"operations":[{"path":"model","mode":"replace"}]}
|
|
input := []byte(`{"model":"gpt-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "replace",
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := ApplyParamOverride(input, override, nil)
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestApplyParamOverrideRegexReplaceRequiresPattern(t *testing.T) {
|
|
// regex_replace requires from(pattern) example:
|
|
// {"operations":[{"path":"model","mode":"regex_replace"}]}
|
|
input := []byte(`{"model":"gpt-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "regex_replace",
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := ApplyParamOverride(input, override, nil)
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestApplyParamOverrideDelete(t *testing.T) {
|
|
input := []byte(`{"model":"gpt-4","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "temperature",
|
|
"mode": "delete",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
|
|
var got map[string]interface{}
|
|
if err := json.Unmarshal(out, &got); err != nil {
|
|
t.Fatalf("failed to unmarshal output JSON: %v", err)
|
|
}
|
|
if _, exists := got["temperature"]; exists {
|
|
t.Fatalf("expected temperature to be deleted")
|
|
}
|
|
}
|
|
|
|
func TestApplyParamOverrideSet(t *testing.T) {
|
|
input := []byte(`{"model":"gpt-4","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "temperature",
|
|
"mode": "set",
|
|
"value": 0.1,
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideSetKeepOrigin(t *testing.T) {
|
|
input := []byte(`{"model":"gpt-4","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "temperature",
|
|
"mode": "set",
|
|
"value": 0.1,
|
|
"keep_origin": true,
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideMove(t *testing.T) {
|
|
input := []byte(`{"model":"gpt-4","meta":{"x":1}}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"mode": "move",
|
|
"from": "model",
|
|
"to": "meta.model",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"meta":{"x":1,"model":"gpt-4"}}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideMoveMissingSource(t *testing.T) {
|
|
input := []byte(`{"meta":{"x":1}}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"mode": "move",
|
|
"from": "model",
|
|
"to": "meta.model",
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := ApplyParamOverride(input, override, nil)
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestApplyParamOverridePrependAppendString(t *testing.T) {
|
|
input := []byte(`{"model":"gpt-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "prepend",
|
|
"value": "openai/",
|
|
},
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "append",
|
|
"value": "-latest",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"openai/gpt-4-latest"}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverridePrependAppendArray(t *testing.T) {
|
|
input := []byte(`{"arr":[1,2]}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "arr",
|
|
"mode": "prepend",
|
|
"value": 0,
|
|
},
|
|
map[string]interface{}{
|
|
"path": "arr",
|
|
"mode": "append",
|
|
"value": []interface{}{3, 4},
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"arr":[0,1,2,3,4]}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideAppendObjectMergeKeepOrigin(t *testing.T) {
|
|
input := []byte(`{"obj":{"a":1}}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "obj",
|
|
"mode": "append",
|
|
"keep_origin": true,
|
|
"value": map[string]interface{}{
|
|
"a": 2,
|
|
"b": 3,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"obj":{"a":1,"b":3}}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideAppendObjectMergeOverride(t *testing.T) {
|
|
input := []byte(`{"obj":{"a":1}}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "obj",
|
|
"mode": "append",
|
|
"value": map[string]interface{}{
|
|
"a": 2,
|
|
"b": 3,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"obj":{"a":2,"b":3}}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideConditionORDefault(t *testing.T) {
|
|
input := []byte(`{"model":"gpt-4","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "temperature",
|
|
"mode": "set",
|
|
"value": 0.1,
|
|
"conditions": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "prefix",
|
|
"value": "gpt",
|
|
},
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "prefix",
|
|
"value": "claude",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideConditionAND(t *testing.T) {
|
|
input := []byte(`{"model":"gpt-4","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "temperature",
|
|
"mode": "set",
|
|
"value": 0.1,
|
|
"logic": "AND",
|
|
"conditions": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "prefix",
|
|
"value": "gpt",
|
|
},
|
|
map[string]interface{}{
|
|
"path": "temperature",
|
|
"mode": "gt",
|
|
"value": 0.5,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideConditionInvert(t *testing.T) {
|
|
input := []byte(`{"model":"gpt-4","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "temperature",
|
|
"mode": "set",
|
|
"value": 0.1,
|
|
"conditions": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "prefix",
|
|
"value": "gpt",
|
|
"invert": true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideConditionPassMissingKey(t *testing.T) {
|
|
input := []byte(`{"temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "temperature",
|
|
"mode": "set",
|
|
"value": 0.1,
|
|
"conditions": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "prefix",
|
|
"value": "gpt",
|
|
"pass_missing_key": true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"temperature":0.1}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideConditionFromContext(t *testing.T) {
|
|
input := []byte(`{"temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "temperature",
|
|
"mode": "set",
|
|
"value": 0.1,
|
|
"conditions": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "prefix",
|
|
"value": "gpt",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := map[string]interface{}{
|
|
"model": "gpt-4",
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, ctx)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"temperature":0.1}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideNegativeIndexPath(t *testing.T) {
|
|
input := []byte(`{"arr":[{"model":"a"},{"model":"b"}]}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "arr.-1.model",
|
|
"mode": "set",
|
|
"value": "c",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"arr":[{"model":"a"},{"model":"c"}]}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideRegexReplaceInvalidPattern(t *testing.T) {
|
|
// regex_replace invalid pattern example:
|
|
// {"operations":[{"path":"model","mode":"regex_replace","from":"(","to":"x"}]}
|
|
input := []byte(`{"model":"gpt-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "regex_replace",
|
|
"from": "(",
|
|
"to": "x",
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := ApplyParamOverride(input, override, nil)
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestApplyParamOverrideCopy(t *testing.T) {
|
|
// copy example:
|
|
// {"operations":[{"mode":"copy","from":"model","to":"original_model"}]}
|
|
input := []byte(`{"model":"gpt-4","temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"mode": "copy",
|
|
"from": "model",
|
|
"to": "original_model",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4","original_model":"gpt-4","temperature":0.7}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideCopyMissingSource(t *testing.T) {
|
|
// copy missing source example:
|
|
// {"operations":[{"mode":"copy","from":"model","to":"original_model"}]}
|
|
input := []byte(`{"temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"mode": "copy",
|
|
"from": "model",
|
|
"to": "original_model",
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := ApplyParamOverride(input, override, nil)
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestApplyParamOverrideCopyRequiresFromTo(t *testing.T) {
|
|
// copy requires from/to example:
|
|
// {"operations":[{"mode":"copy"}]}
|
|
input := []byte(`{"model":"gpt-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"mode": "copy",
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := ApplyParamOverride(input, override, nil)
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestApplyParamOverrideEnsurePrefix(t *testing.T) {
|
|
// ensure_prefix example:
|
|
// {"operations":[{"path":"model","mode":"ensure_prefix","value":"openai/"}]}
|
|
input := []byte(`{"model":"gpt-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "ensure_prefix",
|
|
"value": "openai/",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"openai/gpt-4"}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideEnsurePrefixNoop(t *testing.T) {
|
|
// ensure_prefix no-op example:
|
|
// {"operations":[{"path":"model","mode":"ensure_prefix","value":"openai/"}]}
|
|
input := []byte(`{"model":"openai/gpt-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "ensure_prefix",
|
|
"value": "openai/",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"openai/gpt-4"}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideEnsureSuffix(t *testing.T) {
|
|
// ensure_suffix example:
|
|
// {"operations":[{"path":"model","mode":"ensure_suffix","value":"-latest"}]}
|
|
input := []byte(`{"model":"gpt-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "ensure_suffix",
|
|
"value": "-latest",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4-latest"}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideEnsureSuffixNoop(t *testing.T) {
|
|
// ensure_suffix no-op example:
|
|
// {"operations":[{"path":"model","mode":"ensure_suffix","value":"-latest"}]}
|
|
input := []byte(`{"model":"gpt-4-latest"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "ensure_suffix",
|
|
"value": "-latest",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4-latest"}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideEnsureRequiresValue(t *testing.T) {
|
|
// ensure_prefix requires value example:
|
|
// {"operations":[{"path":"model","mode":"ensure_prefix"}]}
|
|
input := []byte(`{"model":"gpt-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "ensure_prefix",
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := ApplyParamOverride(input, override, nil)
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestApplyParamOverrideTrimSpace(t *testing.T) {
|
|
// trim_space example:
|
|
// {"operations":[{"path":"model","mode":"trim_space"}]}
|
|
input := []byte("{\"model\":\" gpt-4 \\n\"}")
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "trim_space",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4"}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideToLower(t *testing.T) {
|
|
// to_lower example:
|
|
// {"operations":[{"path":"model","mode":"to_lower"}]}
|
|
input := []byte(`{"model":"GPT-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "to_lower",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"gpt-4"}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideToUpper(t *testing.T) {
|
|
// to_upper example:
|
|
// {"operations":[{"path":"model","mode":"to_upper"}]}
|
|
input := []byte(`{"model":"gpt-4"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "model",
|
|
"mode": "to_upper",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"model":"GPT-4"}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideReturnError(t *testing.T) {
|
|
input := []byte(`{"model":"gemini-2.5-pro"}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"mode": "return_error",
|
|
"value": map[string]interface{}{
|
|
"message": "forced bad request by param override",
|
|
"status_code": 422,
|
|
"code": "forced_bad_request",
|
|
"type": "invalid_request_error",
|
|
"skip_retry": true,
|
|
},
|
|
"conditions": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "retry.is_retry",
|
|
"mode": "full",
|
|
"value": true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := map[string]interface{}{
|
|
"retry": map[string]interface{}{
|
|
"index": 1,
|
|
"is_retry": true,
|
|
},
|
|
}
|
|
|
|
_, err := ApplyParamOverride(input, override, ctx)
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
returnErr, ok := AsParamOverrideReturnError(err)
|
|
if !ok {
|
|
t.Fatalf("expected ParamOverrideReturnError, got %T: %v", err, err)
|
|
}
|
|
if returnErr.StatusCode != 422 {
|
|
t.Fatalf("expected status 422, got %d", returnErr.StatusCode)
|
|
}
|
|
if returnErr.Code != "forced_bad_request" {
|
|
t.Fatalf("expected code forced_bad_request, got %s", returnErr.Code)
|
|
}
|
|
if !returnErr.SkipRetry {
|
|
t.Fatalf("expected skip_retry true")
|
|
}
|
|
}
|
|
|
|
func TestApplyParamOverridePruneObjectsByTypeString(t *testing.T) {
|
|
input := []byte(`{
|
|
"messages":[
|
|
{"role":"assistant","content":[
|
|
{"type":"output_text","text":"a"},
|
|
{"type":"redacted_thinking","text":"secret"},
|
|
{"type":"tool_call","name":"tool_a"}
|
|
]},
|
|
{"role":"assistant","content":[
|
|
{"type":"output_text","text":"b"},
|
|
{"type":"wrapper","parts":[
|
|
{"type":"redacted_thinking","text":"secret2"},
|
|
{"type":"output_text","text":"c"}
|
|
]}
|
|
]}
|
|
]
|
|
}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"mode": "prune_objects",
|
|
"value": "redacted_thinking",
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{
|
|
"messages":[
|
|
{"role":"assistant","content":[
|
|
{"type":"output_text","text":"a"},
|
|
{"type":"tool_call","name":"tool_a"}
|
|
]},
|
|
{"role":"assistant","content":[
|
|
{"type":"output_text","text":"b"},
|
|
{"type":"wrapper","parts":[
|
|
{"type":"output_text","text":"c"}
|
|
]}
|
|
]}
|
|
]
|
|
}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverridePruneObjectsWhereAndPath(t *testing.T) {
|
|
input := []byte(`{
|
|
"a":{"items":[{"type":"redacted_thinking","id":1},{"type":"output_text","id":2}]},
|
|
"b":{"items":[{"type":"redacted_thinking","id":3},{"type":"output_text","id":4}]}
|
|
}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "a",
|
|
"mode": "prune_objects",
|
|
"value": map[string]interface{}{
|
|
"where": map[string]interface{}{
|
|
"type": "redacted_thinking",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, nil)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{
|
|
"a":{"items":[{"type":"output_text","id":2}]},
|
|
"b":{"items":[{"type":"redacted_thinking","id":3},{"type":"output_text","id":4}]}
|
|
}`, string(out))
|
|
}
|
|
|
|
func TestApplyParamOverrideNormalizeThinkingSignatureUnsupported(t *testing.T) {
|
|
input := []byte(`{"items":[{"type":"redacted_thinking"}]}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"mode": "normalize_thinking_signature",
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := ApplyParamOverride(input, override, nil)
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestApplyParamOverrideConditionFromRetryAndLastErrorContext(t *testing.T) {
|
|
info := &RelayInfo{
|
|
RetryIndex: 1,
|
|
LastError: types.WithOpenAIError(types.OpenAIError{
|
|
Message: "invalid thinking signature",
|
|
Type: "invalid_request_error",
|
|
Code: "bad_thought_signature",
|
|
}, 400),
|
|
}
|
|
ctx := BuildParamOverrideContext(info)
|
|
|
|
input := []byte(`{"temperature":0.7}`)
|
|
override := map[string]interface{}{
|
|
"operations": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "temperature",
|
|
"mode": "set",
|
|
"value": 0.1,
|
|
"logic": "AND",
|
|
"conditions": []interface{}{
|
|
map[string]interface{}{
|
|
"path": "is_retry",
|
|
"mode": "full",
|
|
"value": true,
|
|
},
|
|
map[string]interface{}{
|
|
"path": "last_error.code",
|
|
"mode": "contains",
|
|
"value": "thought_signature",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := ApplyParamOverride(input, override, ctx)
|
|
if err != nil {
|
|
t.Fatalf("ApplyParamOverride returned error: %v", err)
|
|
}
|
|
assertJSONEqual(t, `{"temperature":0.1}`, string(out))
|
|
}
|
|
|
|
func assertJSONEqual(t *testing.T, want, got string) {
|
|
t.Helper()
|
|
|
|
var wantObj interface{}
|
|
var gotObj interface{}
|
|
|
|
if err := json.Unmarshal([]byte(want), &wantObj); err != nil {
|
|
t.Fatalf("failed to unmarshal want JSON: %v", err)
|
|
}
|
|
if err := json.Unmarshal([]byte(got), &gotObj); err != nil {
|
|
t.Fatalf("failed to unmarshal got JSON: %v", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(wantObj, gotObj) {
|
|
t.Fatalf("json not equal\nwant: %s\ngot: %s", want, got)
|
|
}
|
|
}
|