codex-provider-overrides.test.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import { describe, expect, it } from "vitest";
  2. import {
  3. applyCodexProviderOverrides,
  4. applyCodexProviderOverridesWithAudit,
  5. } from "@/lib/codex/provider-overrides";
  6. describe("Codex 供应商级参数覆写", () => {
  7. it("当 providerType 不是 codex 时,应直接返回原对象且不做任何处理", () => {
  8. const provider = {
  9. providerType: "claude",
  10. codexReasoningEffortPreference: "high",
  11. codexParallelToolCallsPreference: "false",
  12. };
  13. const input: Record<string, unknown> = {
  14. model: "gpt-5-codex",
  15. input: [],
  16. parallel_tool_calls: true,
  17. reasoning: { effort: "low", summary: "auto" },
  18. };
  19. const output = applyCodexProviderOverrides(provider as any, input);
  20. expect(output).toBe(input);
  21. expect(output).toEqual(input);
  22. });
  23. it("当所有偏好均为 inherit/null 时,应保持请求不变", () => {
  24. const provider = {
  25. providerType: "codex",
  26. codexReasoningEffortPreference: null,
  27. codexReasoningSummaryPreference: null,
  28. codexTextVerbosityPreference: null,
  29. codexParallelToolCallsPreference: null,
  30. };
  31. const input: Record<string, unknown> = {
  32. model: "gpt-5-codex",
  33. input: [],
  34. parallel_tool_calls: false,
  35. reasoning: { effort: "low", summary: "auto" },
  36. text: { verbosity: "medium" },
  37. };
  38. const snapshot = structuredClone(input);
  39. const output = applyCodexProviderOverrides(provider as any, input);
  40. expect(output).toEqual(snapshot);
  41. expect(input).toEqual(snapshot);
  42. });
  43. it("当偏好值为字符串 inherit 时,应视为不覆写", () => {
  44. const provider = {
  45. providerType: "codex",
  46. codexReasoningEffortPreference: "inherit",
  47. codexReasoningSummaryPreference: "inherit",
  48. codexTextVerbosityPreference: "inherit",
  49. codexParallelToolCallsPreference: "inherit",
  50. };
  51. const input: Record<string, unknown> = {
  52. model: "gpt-5-codex",
  53. input: [],
  54. parallel_tool_calls: false,
  55. reasoning: { effort: "low", summary: "auto" },
  56. text: { verbosity: "medium", other: "keep" },
  57. };
  58. const snapshot = structuredClone(input);
  59. const output = applyCodexProviderOverrides(provider as any, input);
  60. expect(output).toEqual(snapshot);
  61. expect(input).toEqual(snapshot);
  62. });
  63. it("当强制 parallel_tool_calls 时,应覆写为对应布尔值", () => {
  64. const provider = {
  65. providerType: "codex",
  66. codexParallelToolCallsPreference: "false",
  67. };
  68. const input: Record<string, unknown> = {
  69. model: "gpt-5-codex",
  70. input: [],
  71. parallel_tool_calls: true,
  72. };
  73. const output = applyCodexProviderOverrides(provider as any, input);
  74. expect(output.parallel_tool_calls).toBe(false);
  75. expect(input.parallel_tool_calls).toBe(true);
  76. });
  77. it("当强制 reasoning.effort/summary 时,应覆写并保留 reasoning 的其他字段", () => {
  78. const provider = {
  79. providerType: "codex",
  80. codexReasoningEffortPreference: "high",
  81. codexReasoningSummaryPreference: "detailed",
  82. };
  83. const input: Record<string, unknown> = {
  84. model: "gpt-5-codex",
  85. input: [],
  86. reasoning: { effort: "low", summary: "auto", extra: "keep" },
  87. };
  88. const output = applyCodexProviderOverrides(provider as any, input);
  89. expect(output.reasoning).toEqual({ effort: "high", summary: "detailed", extra: "keep" });
  90. expect((input.reasoning as any).effort).toBe("low");
  91. });
  92. it("当请求缺少 reasoning/text 时,强制值应自动补齐对象结构", () => {
  93. const provider = {
  94. providerType: "codex",
  95. codexReasoningEffortPreference: "minimal",
  96. codexReasoningSummaryPreference: "auto",
  97. codexTextVerbosityPreference: "high",
  98. };
  99. const input: Record<string, unknown> = {
  100. model: "gpt-5-codex",
  101. input: [],
  102. };
  103. const output = applyCodexProviderOverrides(provider as any, input);
  104. expect(output.reasoning).toEqual({ effort: "minimal", summary: "auto" });
  105. expect(output.text).toEqual({ verbosity: "high" });
  106. });
  107. it("审计:当 providerType 不是 codex 时,应返回 audit=null 且保持引用不变", () => {
  108. const provider = {
  109. id: 123,
  110. name: "P",
  111. providerType: "claude",
  112. codexParallelToolCallsPreference: "false",
  113. };
  114. const input: Record<string, unknown> = {
  115. model: "gpt-5-codex",
  116. input: [],
  117. parallel_tool_calls: true,
  118. };
  119. const result = applyCodexProviderOverridesWithAudit(provider as any, input);
  120. expect(result.request).toBe(input);
  121. expect(result.audit).toBeNull();
  122. });
  123. it("审计:当所有偏好均为 inherit/null 时,应返回 audit=null 且不做覆写", () => {
  124. const provider = {
  125. providerType: "codex",
  126. codexReasoningEffortPreference: "inherit",
  127. codexReasoningSummaryPreference: null,
  128. codexTextVerbosityPreference: "inherit",
  129. codexParallelToolCallsPreference: null,
  130. };
  131. const input: Record<string, unknown> = {
  132. model: "gpt-5-codex",
  133. input: [],
  134. parallel_tool_calls: false,
  135. reasoning: { effort: "low", summary: "auto" },
  136. text: { verbosity: "medium" },
  137. };
  138. const result = applyCodexProviderOverridesWithAudit(provider as any, input);
  139. expect(result.request).toBe(input);
  140. expect(result.audit).toBeNull();
  141. });
  142. it("审计:当偏好命中但值未变化时,应标记 changed=false 并记录 before/after", () => {
  143. const provider = {
  144. id: 1,
  145. name: "codex-provider",
  146. providerType: "codex",
  147. codexParallelToolCallsPreference: "false",
  148. };
  149. const input: Record<string, unknown> = {
  150. model: "gpt-5-codex",
  151. input: [],
  152. parallel_tool_calls: false,
  153. };
  154. const result = applyCodexProviderOverridesWithAudit(provider as any, input);
  155. expect(result.audit?.hit).toBe(true);
  156. expect(result.audit?.changed).toBe(false);
  157. expect(result.audit?.providerId).toBe(1);
  158. expect(result.audit?.providerName).toBe("codex-provider");
  159. const parallelChange = result.audit?.changes.find((c) => c.path === "parallel_tool_calls");
  160. expect(parallelChange).toEqual({
  161. path: "parallel_tool_calls",
  162. before: false,
  163. after: false,
  164. changed: false,
  165. });
  166. });
  167. it("审计:当偏好命中且值变化时,应标记 changed=true 并记录变化明细", () => {
  168. const provider = {
  169. id: 2,
  170. name: "codex-provider",
  171. providerType: "codex",
  172. codexReasoningEffortPreference: "high",
  173. codexReasoningSummaryPreference: "detailed",
  174. codexTextVerbosityPreference: "high",
  175. codexParallelToolCallsPreference: "true",
  176. };
  177. const input: Record<string, unknown> = {
  178. model: "gpt-5-codex",
  179. input: [],
  180. parallel_tool_calls: false,
  181. reasoning: { effort: "low", summary: "auto" },
  182. text: { verbosity: "low" },
  183. };
  184. const result = applyCodexProviderOverridesWithAudit(provider as any, input);
  185. expect(result.audit?.hit).toBe(true);
  186. expect(result.audit?.changed).toBe(true);
  187. const changedPaths = (result.audit?.changes ?? []).filter((c) => c.changed).map((c) => c.path);
  188. expect(changedPaths).toEqual([
  189. "parallel_tool_calls",
  190. "reasoning.effort",
  191. "reasoning.summary",
  192. "text.verbosity",
  193. ]);
  194. });
  195. });