provider-overrides.test.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. import { describe, expect, test } from "vitest";
  2. import {
  3. applyGeminiGoogleSearchOverride,
  4. applyGeminiGoogleSearchOverrideWithAudit,
  5. } from "@/lib/gemini/provider-overrides";
  6. describe("applyGeminiGoogleSearchOverride", () => {
  7. describe("non-Gemini providers", () => {
  8. test("should return unchanged request for claude provider", () => {
  9. const provider = { providerType: "claude" };
  10. const request = { tools: [{ codeExecution: {} }] };
  11. const result = applyGeminiGoogleSearchOverride(provider, request);
  12. expect(result).toBe(request);
  13. });
  14. test("should return unchanged request for codex provider", () => {
  15. const provider = { providerType: "codex", geminiGoogleSearchPreference: "enabled" };
  16. const request = { contents: [] };
  17. const result = applyGeminiGoogleSearchOverride(provider, request);
  18. expect(result).toBe(request);
  19. });
  20. });
  21. describe("inherit preference", () => {
  22. test("should pass through unchanged when preference is inherit", () => {
  23. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "inherit" };
  24. const request = { contents: [], tools: [{ googleSearch: {} }] };
  25. const result = applyGeminiGoogleSearchOverride(provider, request);
  26. expect(result).toBe(request);
  27. });
  28. test("should pass through unchanged when preference is null", () => {
  29. const provider = { providerType: "gemini", geminiGoogleSearchPreference: null };
  30. const request = { contents: [] };
  31. const result = applyGeminiGoogleSearchOverride(provider, request);
  32. expect(result).toBe(request);
  33. });
  34. test("should pass through unchanged when preference is undefined", () => {
  35. const provider = { providerType: "gemini" };
  36. const request = { contents: [] };
  37. const result = applyGeminiGoogleSearchOverride(provider, request);
  38. expect(result).toBe(request);
  39. });
  40. });
  41. describe("enabled preference", () => {
  42. test("should inject googleSearch tool when not present", () => {
  43. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "enabled" };
  44. const request = { contents: [] };
  45. const result = applyGeminiGoogleSearchOverride(provider, request);
  46. expect(result).not.toBe(request);
  47. expect(result.tools).toEqual([{ googleSearch: {} }]);
  48. });
  49. test("should inject googleSearch tool alongside existing tools", () => {
  50. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "enabled" };
  51. const request = { contents: [], tools: [{ codeExecution: {} }] };
  52. const result = applyGeminiGoogleSearchOverride(provider, request);
  53. expect(result).not.toBe(request);
  54. expect(result.tools).toEqual([{ codeExecution: {} }, { googleSearch: {} }]);
  55. });
  56. test("should not duplicate googleSearch if already present", () => {
  57. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "enabled" };
  58. const request = { contents: [], tools: [{ googleSearch: {} }] };
  59. const result = applyGeminiGoogleSearchOverride(provider, request);
  60. expect(result).toBe(request);
  61. expect(result.tools).toEqual([{ googleSearch: {} }]);
  62. });
  63. test("should work with gemini-cli provider type", () => {
  64. const provider = { providerType: "gemini-cli", geminiGoogleSearchPreference: "enabled" };
  65. const request = { contents: [] };
  66. const result = applyGeminiGoogleSearchOverride(provider, request);
  67. expect(result.tools).toEqual([{ googleSearch: {} }]);
  68. });
  69. });
  70. describe("disabled preference", () => {
  71. test("should remove googleSearch tool when present", () => {
  72. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "disabled" };
  73. const request = { contents: [], tools: [{ googleSearch: {} }] };
  74. const result = applyGeminiGoogleSearchOverride(provider, request);
  75. expect(result).not.toBe(request);
  76. expect(result.tools).toBeUndefined();
  77. });
  78. test("should preserve other tools when removing googleSearch", () => {
  79. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "disabled" };
  80. const request = {
  81. contents: [],
  82. tools: [{ codeExecution: {} }, { googleSearch: {} }, { functionDeclarations: [] }],
  83. };
  84. const result = applyGeminiGoogleSearchOverride(provider, request);
  85. expect(result).not.toBe(request);
  86. expect(result.tools).toEqual([{ codeExecution: {} }, { functionDeclarations: [] }]);
  87. });
  88. test("should pass through unchanged when googleSearch not present", () => {
  89. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "disabled" };
  90. const request = { contents: [], tools: [{ codeExecution: {} }] };
  91. const result = applyGeminiGoogleSearchOverride(provider, request);
  92. expect(result).toBe(request);
  93. });
  94. test("should pass through unchanged when no tools array", () => {
  95. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "disabled" };
  96. const request = { contents: [] };
  97. const result = applyGeminiGoogleSearchOverride(provider, request);
  98. expect(result).toBe(request);
  99. });
  100. });
  101. });
  102. describe("applyGeminiGoogleSearchOverrideWithAudit", () => {
  103. describe("non-Gemini providers", () => {
  104. test("should return null audit for non-Gemini provider", () => {
  105. const provider = { providerType: "claude", geminiGoogleSearchPreference: "enabled" };
  106. const request = { contents: [] };
  107. const { request: result, audit } = applyGeminiGoogleSearchOverrideWithAudit(
  108. provider,
  109. request
  110. );
  111. expect(result).toBe(request);
  112. expect(audit).toBeNull();
  113. });
  114. });
  115. describe("inherit preference", () => {
  116. test("should return null audit when preference is inherit", () => {
  117. const provider = {
  118. id: 1,
  119. name: "Test Gemini",
  120. providerType: "gemini",
  121. geminiGoogleSearchPreference: "inherit",
  122. };
  123. const request = { contents: [] };
  124. const { audit } = applyGeminiGoogleSearchOverrideWithAudit(provider, request);
  125. expect(audit).toBeNull();
  126. });
  127. });
  128. describe("enabled preference", () => {
  129. test("should return inject audit when googleSearch is injected", () => {
  130. const provider = {
  131. id: 1,
  132. name: "Test Gemini",
  133. providerType: "gemini",
  134. geminiGoogleSearchPreference: "enabled",
  135. };
  136. const request = { contents: [] };
  137. const { request: result, audit } = applyGeminiGoogleSearchOverrideWithAudit(
  138. provider,
  139. request
  140. );
  141. expect(result.tools).toEqual([{ googleSearch: {} }]);
  142. expect(audit).toEqual({
  143. type: "gemini_google_search_override",
  144. scope: "request",
  145. hit: true,
  146. providerId: 1,
  147. providerName: "Test Gemini",
  148. action: "inject",
  149. preference: "enabled",
  150. hadGoogleSearchInRequest: false,
  151. });
  152. });
  153. test("should return passthrough audit when googleSearch already present", () => {
  154. const provider = {
  155. id: 2,
  156. name: "Gemini Pro",
  157. providerType: "gemini",
  158. geminiGoogleSearchPreference: "enabled",
  159. };
  160. const request = { contents: [], tools: [{ googleSearch: {} }] };
  161. const { request: result, audit } = applyGeminiGoogleSearchOverrideWithAudit(
  162. provider,
  163. request
  164. );
  165. expect(result).toBe(request);
  166. expect(audit).toEqual({
  167. type: "gemini_google_search_override",
  168. scope: "request",
  169. hit: true,
  170. providerId: 2,
  171. providerName: "Gemini Pro",
  172. action: "passthrough",
  173. preference: "enabled",
  174. hadGoogleSearchInRequest: true,
  175. });
  176. });
  177. });
  178. describe("disabled preference", () => {
  179. test("should return remove audit when googleSearch is removed", () => {
  180. const provider = {
  181. id: 3,
  182. name: "Gemini Flash",
  183. providerType: "gemini",
  184. geminiGoogleSearchPreference: "disabled",
  185. };
  186. const request = { contents: [], tools: [{ googleSearch: {} }] };
  187. const { request: result, audit } = applyGeminiGoogleSearchOverrideWithAudit(
  188. provider,
  189. request
  190. );
  191. expect(result.tools).toBeUndefined();
  192. expect(audit).toEqual({
  193. type: "gemini_google_search_override",
  194. scope: "request",
  195. hit: true,
  196. providerId: 3,
  197. providerName: "Gemini Flash",
  198. action: "remove",
  199. preference: "disabled",
  200. hadGoogleSearchInRequest: true,
  201. });
  202. });
  203. test("should return passthrough audit when no googleSearch to remove", () => {
  204. const provider = {
  205. id: 4,
  206. providerType: "gemini-cli",
  207. geminiGoogleSearchPreference: "disabled",
  208. };
  209. const request = { contents: [], tools: [{ codeExecution: {} }] };
  210. const { request: result, audit } = applyGeminiGoogleSearchOverrideWithAudit(
  211. provider,
  212. request
  213. );
  214. expect(result).toBe(request);
  215. expect(audit).toEqual({
  216. type: "gemini_google_search_override",
  217. scope: "request",
  218. hit: true,
  219. providerId: 4,
  220. providerName: null,
  221. action: "passthrough",
  222. preference: "disabled",
  223. hadGoogleSearchInRequest: false,
  224. });
  225. });
  226. });
  227. describe("edge cases", () => {
  228. test("should handle missing provider id and name", () => {
  229. const provider = {
  230. providerType: "gemini",
  231. geminiGoogleSearchPreference: "enabled",
  232. };
  233. const request = { contents: [] };
  234. const { audit } = applyGeminiGoogleSearchOverrideWithAudit(provider, request);
  235. expect(audit?.providerId).toBeNull();
  236. expect(audit?.providerName).toBeNull();
  237. });
  238. test("should handle non-plain object tools", () => {
  239. const provider = {
  240. providerType: "gemini",
  241. geminiGoogleSearchPreference: "disabled",
  242. };
  243. const request = { contents: [], tools: ["string-tool", 123, null] };
  244. const { request: result } = applyGeminiGoogleSearchOverrideWithAudit(
  245. provider,
  246. request as unknown as Record<string, unknown>
  247. );
  248. expect(result).toBe(request);
  249. });
  250. test("should handle googleSearch with extra properties", () => {
  251. const provider = {
  252. providerType: "gemini",
  253. geminiGoogleSearchPreference: "disabled",
  254. };
  255. const request = {
  256. contents: [],
  257. tools: [{ googleSearch: { dynamicRetrievalConfig: { threshold: 0.5 } } }],
  258. };
  259. const { request: result } = applyGeminiGoogleSearchOverrideWithAudit(provider, request);
  260. expect(result.tools).toBeUndefined();
  261. });
  262. });
  263. });