override_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. package common
  2. import (
  3. "encoding/json"
  4. "reflect"
  5. "testing"
  6. "github.com/QuantumNous/new-api/dto"
  7. "github.com/QuantumNous/new-api/setting/model_setting"
  8. )
  9. func TestApplyParamOverrideTrimPrefix(t *testing.T) {
  10. // trim_prefix example:
  11. // {"operations":[{"path":"model","mode":"trim_prefix","value":"openai/"}]}
  12. input := []byte(`{"model":"openai/gpt-4","temperature":0.7}`)
  13. override := map[string]interface{}{
  14. "operations": []interface{}{
  15. map[string]interface{}{
  16. "path": "model",
  17. "mode": "trim_prefix",
  18. "value": "openai/",
  19. },
  20. },
  21. }
  22. out, err := ApplyParamOverride(input, override, nil)
  23. if err != nil {
  24. t.Fatalf("ApplyParamOverride returned error: %v", err)
  25. }
  26. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
  27. }
  28. func TestApplyParamOverrideTrimSuffix(t *testing.T) {
  29. // trim_suffix example:
  30. // {"operations":[{"path":"model","mode":"trim_suffix","value":"-latest"}]}
  31. input := []byte(`{"model":"gpt-4-latest","temperature":0.7}`)
  32. override := map[string]interface{}{
  33. "operations": []interface{}{
  34. map[string]interface{}{
  35. "path": "model",
  36. "mode": "trim_suffix",
  37. "value": "-latest",
  38. },
  39. },
  40. }
  41. out, err := ApplyParamOverride(input, override, nil)
  42. if err != nil {
  43. t.Fatalf("ApplyParamOverride returned error: %v", err)
  44. }
  45. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
  46. }
  47. func TestApplyParamOverrideTrimNoop(t *testing.T) {
  48. // trim_prefix no-op example:
  49. // {"operations":[{"path":"model","mode":"trim_prefix","value":"openai/"}]}
  50. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  51. override := map[string]interface{}{
  52. "operations": []interface{}{
  53. map[string]interface{}{
  54. "path": "model",
  55. "mode": "trim_prefix",
  56. "value": "openai/",
  57. },
  58. },
  59. }
  60. out, err := ApplyParamOverride(input, override, nil)
  61. if err != nil {
  62. t.Fatalf("ApplyParamOverride returned error: %v", err)
  63. }
  64. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
  65. }
  66. func TestApplyParamOverrideTrimRequiresValue(t *testing.T) {
  67. // trim_prefix requires value example:
  68. // {"operations":[{"path":"model","mode":"trim_prefix"}]}
  69. input := []byte(`{"model":"gpt-4"}`)
  70. override := map[string]interface{}{
  71. "operations": []interface{}{
  72. map[string]interface{}{
  73. "path": "model",
  74. "mode": "trim_prefix",
  75. },
  76. },
  77. }
  78. _, err := ApplyParamOverride(input, override, nil)
  79. if err == nil {
  80. t.Fatalf("expected error, got nil")
  81. }
  82. }
  83. func TestApplyParamOverrideReplace(t *testing.T) {
  84. // replace example:
  85. // {"operations":[{"path":"model","mode":"replace","from":"openai/","to":""}]}
  86. input := []byte(`{"model":"openai/gpt-4o-mini","temperature":0.7}`)
  87. override := map[string]interface{}{
  88. "operations": []interface{}{
  89. map[string]interface{}{
  90. "path": "model",
  91. "mode": "replace",
  92. "from": "openai/",
  93. "to": "",
  94. },
  95. },
  96. }
  97. out, err := ApplyParamOverride(input, override, nil)
  98. if err != nil {
  99. t.Fatalf("ApplyParamOverride returned error: %v", err)
  100. }
  101. assertJSONEqual(t, `{"model":"gpt-4o-mini","temperature":0.7}`, string(out))
  102. }
  103. func TestApplyParamOverrideRegexReplace(t *testing.T) {
  104. // regex_replace example:
  105. // {"operations":[{"path":"model","mode":"regex_replace","from":"^gpt-","to":"openai/gpt-"}]}
  106. input := []byte(`{"model":"gpt-4o-mini","temperature":0.7}`)
  107. override := map[string]interface{}{
  108. "operations": []interface{}{
  109. map[string]interface{}{
  110. "path": "model",
  111. "mode": "regex_replace",
  112. "from": "^gpt-",
  113. "to": "openai/gpt-",
  114. },
  115. },
  116. }
  117. out, err := ApplyParamOverride(input, override, nil)
  118. if err != nil {
  119. t.Fatalf("ApplyParamOverride returned error: %v", err)
  120. }
  121. assertJSONEqual(t, `{"model":"openai/gpt-4o-mini","temperature":0.7}`, string(out))
  122. }
  123. func TestApplyParamOverrideReplaceRequiresFrom(t *testing.T) {
  124. // replace requires from example:
  125. // {"operations":[{"path":"model","mode":"replace"}]}
  126. input := []byte(`{"model":"gpt-4"}`)
  127. override := map[string]interface{}{
  128. "operations": []interface{}{
  129. map[string]interface{}{
  130. "path": "model",
  131. "mode": "replace",
  132. },
  133. },
  134. }
  135. _, err := ApplyParamOverride(input, override, nil)
  136. if err == nil {
  137. t.Fatalf("expected error, got nil")
  138. }
  139. }
  140. func TestApplyParamOverrideRegexReplaceRequiresPattern(t *testing.T) {
  141. // regex_replace requires from(pattern) example:
  142. // {"operations":[{"path":"model","mode":"regex_replace"}]}
  143. input := []byte(`{"model":"gpt-4"}`)
  144. override := map[string]interface{}{
  145. "operations": []interface{}{
  146. map[string]interface{}{
  147. "path": "model",
  148. "mode": "regex_replace",
  149. },
  150. },
  151. }
  152. _, err := ApplyParamOverride(input, override, nil)
  153. if err == nil {
  154. t.Fatalf("expected error, got nil")
  155. }
  156. }
  157. func TestApplyParamOverrideDelete(t *testing.T) {
  158. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  159. override := map[string]interface{}{
  160. "operations": []interface{}{
  161. map[string]interface{}{
  162. "path": "temperature",
  163. "mode": "delete",
  164. },
  165. },
  166. }
  167. out, err := ApplyParamOverride(input, override, nil)
  168. if err != nil {
  169. t.Fatalf("ApplyParamOverride returned error: %v", err)
  170. }
  171. var got map[string]interface{}
  172. if err := json.Unmarshal(out, &got); err != nil {
  173. t.Fatalf("failed to unmarshal output JSON: %v", err)
  174. }
  175. if _, exists := got["temperature"]; exists {
  176. t.Fatalf("expected temperature to be deleted")
  177. }
  178. }
  179. func TestApplyParamOverrideSet(t *testing.T) {
  180. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  181. override := map[string]interface{}{
  182. "operations": []interface{}{
  183. map[string]interface{}{
  184. "path": "temperature",
  185. "mode": "set",
  186. "value": 0.1,
  187. },
  188. },
  189. }
  190. out, err := ApplyParamOverride(input, override, nil)
  191. if err != nil {
  192. t.Fatalf("ApplyParamOverride returned error: %v", err)
  193. }
  194. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
  195. }
  196. func TestApplyParamOverrideSetKeepOrigin(t *testing.T) {
  197. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  198. override := map[string]interface{}{
  199. "operations": []interface{}{
  200. map[string]interface{}{
  201. "path": "temperature",
  202. "mode": "set",
  203. "value": 0.1,
  204. "keep_origin": true,
  205. },
  206. },
  207. }
  208. out, err := ApplyParamOverride(input, override, nil)
  209. if err != nil {
  210. t.Fatalf("ApplyParamOverride returned error: %v", err)
  211. }
  212. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
  213. }
  214. func TestApplyParamOverrideMove(t *testing.T) {
  215. input := []byte(`{"model":"gpt-4","meta":{"x":1}}`)
  216. override := map[string]interface{}{
  217. "operations": []interface{}{
  218. map[string]interface{}{
  219. "mode": "move",
  220. "from": "model",
  221. "to": "meta.model",
  222. },
  223. },
  224. }
  225. out, err := ApplyParamOverride(input, override, nil)
  226. if err != nil {
  227. t.Fatalf("ApplyParamOverride returned error: %v", err)
  228. }
  229. assertJSONEqual(t, `{"meta":{"x":1,"model":"gpt-4"}}`, string(out))
  230. }
  231. func TestApplyParamOverrideMoveMissingSource(t *testing.T) {
  232. input := []byte(`{"meta":{"x":1}}`)
  233. override := map[string]interface{}{
  234. "operations": []interface{}{
  235. map[string]interface{}{
  236. "mode": "move",
  237. "from": "model",
  238. "to": "meta.model",
  239. },
  240. },
  241. }
  242. _, err := ApplyParamOverride(input, override, nil)
  243. if err == nil {
  244. t.Fatalf("expected error, got nil")
  245. }
  246. }
  247. func TestApplyParamOverridePrependAppendString(t *testing.T) {
  248. input := []byte(`{"model":"gpt-4"}`)
  249. override := map[string]interface{}{
  250. "operations": []interface{}{
  251. map[string]interface{}{
  252. "path": "model",
  253. "mode": "prepend",
  254. "value": "openai/",
  255. },
  256. map[string]interface{}{
  257. "path": "model",
  258. "mode": "append",
  259. "value": "-latest",
  260. },
  261. },
  262. }
  263. out, err := ApplyParamOverride(input, override, nil)
  264. if err != nil {
  265. t.Fatalf("ApplyParamOverride returned error: %v", err)
  266. }
  267. assertJSONEqual(t, `{"model":"openai/gpt-4-latest"}`, string(out))
  268. }
  269. func TestApplyParamOverridePrependAppendArray(t *testing.T) {
  270. input := []byte(`{"arr":[1,2]}`)
  271. override := map[string]interface{}{
  272. "operations": []interface{}{
  273. map[string]interface{}{
  274. "path": "arr",
  275. "mode": "prepend",
  276. "value": 0,
  277. },
  278. map[string]interface{}{
  279. "path": "arr",
  280. "mode": "append",
  281. "value": []interface{}{3, 4},
  282. },
  283. },
  284. }
  285. out, err := ApplyParamOverride(input, override, nil)
  286. if err != nil {
  287. t.Fatalf("ApplyParamOverride returned error: %v", err)
  288. }
  289. assertJSONEqual(t, `{"arr":[0,1,2,3,4]}`, string(out))
  290. }
  291. func TestApplyParamOverrideAppendObjectMergeKeepOrigin(t *testing.T) {
  292. input := []byte(`{"obj":{"a":1}}`)
  293. override := map[string]interface{}{
  294. "operations": []interface{}{
  295. map[string]interface{}{
  296. "path": "obj",
  297. "mode": "append",
  298. "keep_origin": true,
  299. "value": map[string]interface{}{
  300. "a": 2,
  301. "b": 3,
  302. },
  303. },
  304. },
  305. }
  306. out, err := ApplyParamOverride(input, override, nil)
  307. if err != nil {
  308. t.Fatalf("ApplyParamOverride returned error: %v", err)
  309. }
  310. assertJSONEqual(t, `{"obj":{"a":1,"b":3}}`, string(out))
  311. }
  312. func TestApplyParamOverrideAppendObjectMergeOverride(t *testing.T) {
  313. input := []byte(`{"obj":{"a":1}}`)
  314. override := map[string]interface{}{
  315. "operations": []interface{}{
  316. map[string]interface{}{
  317. "path": "obj",
  318. "mode": "append",
  319. "value": map[string]interface{}{
  320. "a": 2,
  321. "b": 3,
  322. },
  323. },
  324. },
  325. }
  326. out, err := ApplyParamOverride(input, override, nil)
  327. if err != nil {
  328. t.Fatalf("ApplyParamOverride returned error: %v", err)
  329. }
  330. assertJSONEqual(t, `{"obj":{"a":2,"b":3}}`, string(out))
  331. }
  332. func TestApplyParamOverrideConditionORDefault(t *testing.T) {
  333. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  334. override := map[string]interface{}{
  335. "operations": []interface{}{
  336. map[string]interface{}{
  337. "path": "temperature",
  338. "mode": "set",
  339. "value": 0.1,
  340. "conditions": []interface{}{
  341. map[string]interface{}{
  342. "path": "model",
  343. "mode": "prefix",
  344. "value": "gpt",
  345. },
  346. map[string]interface{}{
  347. "path": "model",
  348. "mode": "prefix",
  349. "value": "claude",
  350. },
  351. },
  352. },
  353. },
  354. }
  355. out, err := ApplyParamOverride(input, override, nil)
  356. if err != nil {
  357. t.Fatalf("ApplyParamOverride returned error: %v", err)
  358. }
  359. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
  360. }
  361. func TestApplyParamOverrideConditionAND(t *testing.T) {
  362. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  363. override := map[string]interface{}{
  364. "operations": []interface{}{
  365. map[string]interface{}{
  366. "path": "temperature",
  367. "mode": "set",
  368. "value": 0.1,
  369. "logic": "AND",
  370. "conditions": []interface{}{
  371. map[string]interface{}{
  372. "path": "model",
  373. "mode": "prefix",
  374. "value": "gpt",
  375. },
  376. map[string]interface{}{
  377. "path": "temperature",
  378. "mode": "gt",
  379. "value": 0.5,
  380. },
  381. },
  382. },
  383. },
  384. }
  385. out, err := ApplyParamOverride(input, override, nil)
  386. if err != nil {
  387. t.Fatalf("ApplyParamOverride returned error: %v", err)
  388. }
  389. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
  390. }
  391. func TestApplyParamOverrideConditionInvert(t *testing.T) {
  392. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  393. override := map[string]interface{}{
  394. "operations": []interface{}{
  395. map[string]interface{}{
  396. "path": "temperature",
  397. "mode": "set",
  398. "value": 0.1,
  399. "conditions": []interface{}{
  400. map[string]interface{}{
  401. "path": "model",
  402. "mode": "prefix",
  403. "value": "gpt",
  404. "invert": true,
  405. },
  406. },
  407. },
  408. },
  409. }
  410. out, err := ApplyParamOverride(input, override, nil)
  411. if err != nil {
  412. t.Fatalf("ApplyParamOverride returned error: %v", err)
  413. }
  414. assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
  415. }
  416. func TestApplyParamOverrideConditionPassMissingKey(t *testing.T) {
  417. input := []byte(`{"temperature":0.7}`)
  418. override := map[string]interface{}{
  419. "operations": []interface{}{
  420. map[string]interface{}{
  421. "path": "temperature",
  422. "mode": "set",
  423. "value": 0.1,
  424. "conditions": []interface{}{
  425. map[string]interface{}{
  426. "path": "model",
  427. "mode": "prefix",
  428. "value": "gpt",
  429. "pass_missing_key": true,
  430. },
  431. },
  432. },
  433. },
  434. }
  435. out, err := ApplyParamOverride(input, override, nil)
  436. if err != nil {
  437. t.Fatalf("ApplyParamOverride returned error: %v", err)
  438. }
  439. assertJSONEqual(t, `{"temperature":0.1}`, string(out))
  440. }
  441. func TestApplyParamOverrideConditionFromContext(t *testing.T) {
  442. input := []byte(`{"temperature":0.7}`)
  443. override := map[string]interface{}{
  444. "operations": []interface{}{
  445. map[string]interface{}{
  446. "path": "temperature",
  447. "mode": "set",
  448. "value": 0.1,
  449. "conditions": []interface{}{
  450. map[string]interface{}{
  451. "path": "model",
  452. "mode": "prefix",
  453. "value": "gpt",
  454. },
  455. },
  456. },
  457. },
  458. }
  459. ctx := map[string]interface{}{
  460. "model": "gpt-4",
  461. }
  462. out, err := ApplyParamOverride(input, override, ctx)
  463. if err != nil {
  464. t.Fatalf("ApplyParamOverride returned error: %v", err)
  465. }
  466. assertJSONEqual(t, `{"temperature":0.1}`, string(out))
  467. }
  468. func TestApplyParamOverrideNegativeIndexPath(t *testing.T) {
  469. input := []byte(`{"arr":[{"model":"a"},{"model":"b"}]}`)
  470. override := map[string]interface{}{
  471. "operations": []interface{}{
  472. map[string]interface{}{
  473. "path": "arr.-1.model",
  474. "mode": "set",
  475. "value": "c",
  476. },
  477. },
  478. }
  479. out, err := ApplyParamOverride(input, override, nil)
  480. if err != nil {
  481. t.Fatalf("ApplyParamOverride returned error: %v", err)
  482. }
  483. assertJSONEqual(t, `{"arr":[{"model":"a"},{"model":"c"}]}`, string(out))
  484. }
  485. func TestApplyParamOverrideRegexReplaceInvalidPattern(t *testing.T) {
  486. // regex_replace invalid pattern example:
  487. // {"operations":[{"path":"model","mode":"regex_replace","from":"(","to":"x"}]}
  488. input := []byte(`{"model":"gpt-4"}`)
  489. override := map[string]interface{}{
  490. "operations": []interface{}{
  491. map[string]interface{}{
  492. "path": "model",
  493. "mode": "regex_replace",
  494. "from": "(",
  495. "to": "x",
  496. },
  497. },
  498. }
  499. _, err := ApplyParamOverride(input, override, nil)
  500. if err == nil {
  501. t.Fatalf("expected error, got nil")
  502. }
  503. }
  504. func TestApplyParamOverrideCopy(t *testing.T) {
  505. // copy example:
  506. // {"operations":[{"mode":"copy","from":"model","to":"original_model"}]}
  507. input := []byte(`{"model":"gpt-4","temperature":0.7}`)
  508. override := map[string]interface{}{
  509. "operations": []interface{}{
  510. map[string]interface{}{
  511. "mode": "copy",
  512. "from": "model",
  513. "to": "original_model",
  514. },
  515. },
  516. }
  517. out, err := ApplyParamOverride(input, override, nil)
  518. if err != nil {
  519. t.Fatalf("ApplyParamOverride returned error: %v", err)
  520. }
  521. assertJSONEqual(t, `{"model":"gpt-4","original_model":"gpt-4","temperature":0.7}`, string(out))
  522. }
  523. func TestApplyParamOverrideCopyMissingSource(t *testing.T) {
  524. // copy missing source example:
  525. // {"operations":[{"mode":"copy","from":"model","to":"original_model"}]}
  526. input := []byte(`{"temperature":0.7}`)
  527. override := map[string]interface{}{
  528. "operations": []interface{}{
  529. map[string]interface{}{
  530. "mode": "copy",
  531. "from": "model",
  532. "to": "original_model",
  533. },
  534. },
  535. }
  536. _, err := ApplyParamOverride(input, override, nil)
  537. if err == nil {
  538. t.Fatalf("expected error, got nil")
  539. }
  540. }
  541. func TestApplyParamOverrideCopyRequiresFromTo(t *testing.T) {
  542. // copy requires from/to example:
  543. // {"operations":[{"mode":"copy"}]}
  544. input := []byte(`{"model":"gpt-4"}`)
  545. override := map[string]interface{}{
  546. "operations": []interface{}{
  547. map[string]interface{}{
  548. "mode": "copy",
  549. },
  550. },
  551. }
  552. _, err := ApplyParamOverride(input, override, nil)
  553. if err == nil {
  554. t.Fatalf("expected error, got nil")
  555. }
  556. }
  557. func TestApplyParamOverrideEnsurePrefix(t *testing.T) {
  558. // ensure_prefix example:
  559. // {"operations":[{"path":"model","mode":"ensure_prefix","value":"openai/"}]}
  560. input := []byte(`{"model":"gpt-4"}`)
  561. override := map[string]interface{}{
  562. "operations": []interface{}{
  563. map[string]interface{}{
  564. "path": "model",
  565. "mode": "ensure_prefix",
  566. "value": "openai/",
  567. },
  568. },
  569. }
  570. out, err := ApplyParamOverride(input, override, nil)
  571. if err != nil {
  572. t.Fatalf("ApplyParamOverride returned error: %v", err)
  573. }
  574. assertJSONEqual(t, `{"model":"openai/gpt-4"}`, string(out))
  575. }
  576. func TestApplyParamOverrideEnsurePrefixNoop(t *testing.T) {
  577. // ensure_prefix no-op example:
  578. // {"operations":[{"path":"model","mode":"ensure_prefix","value":"openai/"}]}
  579. input := []byte(`{"model":"openai/gpt-4"}`)
  580. override := map[string]interface{}{
  581. "operations": []interface{}{
  582. map[string]interface{}{
  583. "path": "model",
  584. "mode": "ensure_prefix",
  585. "value": "openai/",
  586. },
  587. },
  588. }
  589. out, err := ApplyParamOverride(input, override, nil)
  590. if err != nil {
  591. t.Fatalf("ApplyParamOverride returned error: %v", err)
  592. }
  593. assertJSONEqual(t, `{"model":"openai/gpt-4"}`, string(out))
  594. }
  595. func TestApplyParamOverrideEnsureSuffix(t *testing.T) {
  596. // ensure_suffix example:
  597. // {"operations":[{"path":"model","mode":"ensure_suffix","value":"-latest"}]}
  598. input := []byte(`{"model":"gpt-4"}`)
  599. override := map[string]interface{}{
  600. "operations": []interface{}{
  601. map[string]interface{}{
  602. "path": "model",
  603. "mode": "ensure_suffix",
  604. "value": "-latest",
  605. },
  606. },
  607. }
  608. out, err := ApplyParamOverride(input, override, nil)
  609. if err != nil {
  610. t.Fatalf("ApplyParamOverride returned error: %v", err)
  611. }
  612. assertJSONEqual(t, `{"model":"gpt-4-latest"}`, string(out))
  613. }
  614. func TestApplyParamOverrideEnsureSuffixNoop(t *testing.T) {
  615. // ensure_suffix no-op example:
  616. // {"operations":[{"path":"model","mode":"ensure_suffix","value":"-latest"}]}
  617. input := []byte(`{"model":"gpt-4-latest"}`)
  618. override := map[string]interface{}{
  619. "operations": []interface{}{
  620. map[string]interface{}{
  621. "path": "model",
  622. "mode": "ensure_suffix",
  623. "value": "-latest",
  624. },
  625. },
  626. }
  627. out, err := ApplyParamOverride(input, override, nil)
  628. if err != nil {
  629. t.Fatalf("ApplyParamOverride returned error: %v", err)
  630. }
  631. assertJSONEqual(t, `{"model":"gpt-4-latest"}`, string(out))
  632. }
  633. func TestApplyParamOverrideEnsureRequiresValue(t *testing.T) {
  634. // ensure_prefix requires value example:
  635. // {"operations":[{"path":"model","mode":"ensure_prefix"}]}
  636. input := []byte(`{"model":"gpt-4"}`)
  637. override := map[string]interface{}{
  638. "operations": []interface{}{
  639. map[string]interface{}{
  640. "path": "model",
  641. "mode": "ensure_prefix",
  642. },
  643. },
  644. }
  645. _, err := ApplyParamOverride(input, override, nil)
  646. if err == nil {
  647. t.Fatalf("expected error, got nil")
  648. }
  649. }
  650. func TestApplyParamOverrideTrimSpace(t *testing.T) {
  651. // trim_space example:
  652. // {"operations":[{"path":"model","mode":"trim_space"}]}
  653. input := []byte("{\"model\":\" gpt-4 \\n\"}")
  654. override := map[string]interface{}{
  655. "operations": []interface{}{
  656. map[string]interface{}{
  657. "path": "model",
  658. "mode": "trim_space",
  659. },
  660. },
  661. }
  662. out, err := ApplyParamOverride(input, override, nil)
  663. if err != nil {
  664. t.Fatalf("ApplyParamOverride returned error: %v", err)
  665. }
  666. assertJSONEqual(t, `{"model":"gpt-4"}`, string(out))
  667. }
  668. func TestApplyParamOverrideToLower(t *testing.T) {
  669. // to_lower example:
  670. // {"operations":[{"path":"model","mode":"to_lower"}]}
  671. input := []byte(`{"model":"GPT-4"}`)
  672. override := map[string]interface{}{
  673. "operations": []interface{}{
  674. map[string]interface{}{
  675. "path": "model",
  676. "mode": "to_lower",
  677. },
  678. },
  679. }
  680. out, err := ApplyParamOverride(input, override, nil)
  681. if err != nil {
  682. t.Fatalf("ApplyParamOverride returned error: %v", err)
  683. }
  684. assertJSONEqual(t, `{"model":"gpt-4"}`, string(out))
  685. }
  686. func TestApplyParamOverrideToUpper(t *testing.T) {
  687. // to_upper example:
  688. // {"operations":[{"path":"model","mode":"to_upper"}]}
  689. input := []byte(`{"model":"gpt-4"}`)
  690. override := map[string]interface{}{
  691. "operations": []interface{}{
  692. map[string]interface{}{
  693. "path": "model",
  694. "mode": "to_upper",
  695. },
  696. },
  697. }
  698. out, err := ApplyParamOverride(input, override, nil)
  699. if err != nil {
  700. t.Fatalf("ApplyParamOverride returned error: %v", err)
  701. }
  702. assertJSONEqual(t, `{"model":"GPT-4"}`, string(out))
  703. }
  704. func TestRemoveDisabledFieldsSkipWhenChannelPassThroughEnabled(t *testing.T) {
  705. input := `{
  706. "service_tier":"flex",
  707. "safety_identifier":"user-123",
  708. "store":true,
  709. "stream_options":{"include_obfuscation":false}
  710. }`
  711. settings := dto.ChannelOtherSettings{}
  712. out, err := RemoveDisabledFields([]byte(input), settings, true)
  713. if err != nil {
  714. t.Fatalf("RemoveDisabledFields returned error: %v", err)
  715. }
  716. assertJSONEqual(t, input, string(out))
  717. }
  718. func TestRemoveDisabledFieldsSkipWhenGlobalPassThroughEnabled(t *testing.T) {
  719. original := model_setting.GetGlobalSettings().PassThroughRequestEnabled
  720. model_setting.GetGlobalSettings().PassThroughRequestEnabled = true
  721. t.Cleanup(func() {
  722. model_setting.GetGlobalSettings().PassThroughRequestEnabled = original
  723. })
  724. input := `{
  725. "service_tier":"flex",
  726. "safety_identifier":"user-123",
  727. "stream_options":{"include_obfuscation":false}
  728. }`
  729. settings := dto.ChannelOtherSettings{}
  730. out, err := RemoveDisabledFields([]byte(input), settings, false)
  731. if err != nil {
  732. t.Fatalf("RemoveDisabledFields returned error: %v", err)
  733. }
  734. assertJSONEqual(t, input, string(out))
  735. }
  736. func TestRemoveDisabledFieldsDefaultFiltering(t *testing.T) {
  737. input := `{
  738. "service_tier":"flex",
  739. "inference_geo":"eu",
  740. "safety_identifier":"user-123",
  741. "store":true,
  742. "stream_options":{"include_obfuscation":false}
  743. }`
  744. settings := dto.ChannelOtherSettings{}
  745. out, err := RemoveDisabledFields([]byte(input), settings, false)
  746. if err != nil {
  747. t.Fatalf("RemoveDisabledFields returned error: %v", err)
  748. }
  749. assertJSONEqual(t, `{"store":true}`, string(out))
  750. }
  751. func TestRemoveDisabledFieldsAllowInferenceGeo(t *testing.T) {
  752. input := `{
  753. "inference_geo":"eu",
  754. "store":true
  755. }`
  756. settings := dto.ChannelOtherSettings{
  757. AllowInferenceGeo: true,
  758. }
  759. out, err := RemoveDisabledFields([]byte(input), settings, false)
  760. if err != nil {
  761. t.Fatalf("RemoveDisabledFields returned error: %v", err)
  762. }
  763. assertJSONEqual(t, `{"inference_geo":"eu","store":true}`, string(out))
  764. }
  765. func assertJSONEqual(t *testing.T, want, got string) {
  766. t.Helper()
  767. var wantObj interface{}
  768. var gotObj interface{}
  769. if err := json.Unmarshal([]byte(want), &wantObj); err != nil {
  770. t.Fatalf("failed to unmarshal want JSON: %v", err)
  771. }
  772. if err := json.Unmarshal([]byte(got), &gotObj); err != nil {
  773. t.Fatalf("failed to unmarshal got JSON: %v", err)
  774. }
  775. if !reflect.DeepEqual(wantObj, gotObj) {
  776. t.Fatalf("json not equal\nwant: %s\ngot: %s", want, got)
  777. }
  778. }