provider-overrides.test.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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. test("should not inject googleSearch for non-generation Gemini actions when pathname is provided", () => {
  70. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "enabled" };
  71. const request = { content: { parts: [{ text: "hello" }] } };
  72. const result = applyGeminiGoogleSearchOverride(
  73. provider,
  74. request,
  75. "/v1beta/models/gemini-embedding-001:embedContent"
  76. );
  77. expect(result).toBe(request);
  78. });
  79. });
  80. describe("disabled preference", () => {
  81. test("should remove googleSearch tool when present", () => {
  82. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "disabled" };
  83. const request = { contents: [], tools: [{ googleSearch: {} }] };
  84. const result = applyGeminiGoogleSearchOverride(provider, request);
  85. expect(result).not.toBe(request);
  86. expect(result.tools).toBeUndefined();
  87. });
  88. test("should preserve other tools when removing googleSearch", () => {
  89. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "disabled" };
  90. const request = {
  91. contents: [],
  92. tools: [{ codeExecution: {} }, { googleSearch: {} }, { functionDeclarations: [] }],
  93. };
  94. const result = applyGeminiGoogleSearchOverride(provider, request);
  95. expect(result).not.toBe(request);
  96. expect(result.tools).toEqual([{ codeExecution: {} }, { functionDeclarations: [] }]);
  97. });
  98. test("should pass through unchanged when googleSearch not present", () => {
  99. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "disabled" };
  100. const request = { contents: [], tools: [{ codeExecution: {} }] };
  101. const result = applyGeminiGoogleSearchOverride(provider, request);
  102. expect(result).toBe(request);
  103. });
  104. test("should pass through unchanged when no tools array", () => {
  105. const provider = { providerType: "gemini", geminiGoogleSearchPreference: "disabled" };
  106. const request = { contents: [] };
  107. const result = applyGeminiGoogleSearchOverride(provider, request);
  108. expect(result).toBe(request);
  109. });
  110. });
  111. });
  112. describe("applyGeminiGoogleSearchOverrideWithAudit", () => {
  113. describe("non-Gemini providers", () => {
  114. test("should return null audit for non-Gemini provider", () => {
  115. const provider = { providerType: "claude", geminiGoogleSearchPreference: "enabled" };
  116. const request = { contents: [] };
  117. const { request: result, audit } = applyGeminiGoogleSearchOverrideWithAudit(
  118. provider,
  119. request
  120. );
  121. expect(result).toBe(request);
  122. expect(audit).toBeNull();
  123. });
  124. });
  125. describe("inherit preference", () => {
  126. test("should return null audit when preference is inherit", () => {
  127. const provider = {
  128. id: 1,
  129. name: "Test Gemini",
  130. providerType: "gemini",
  131. geminiGoogleSearchPreference: "inherit",
  132. };
  133. const request = { contents: [] };
  134. const { audit } = applyGeminiGoogleSearchOverrideWithAudit(provider, request);
  135. expect(audit).toBeNull();
  136. });
  137. });
  138. describe("enabled preference", () => {
  139. test("should return inject audit when googleSearch is injected", () => {
  140. const provider = {
  141. id: 1,
  142. name: "Test Gemini",
  143. providerType: "gemini",
  144. geminiGoogleSearchPreference: "enabled",
  145. };
  146. const request = { contents: [] };
  147. const { request: result, audit } = applyGeminiGoogleSearchOverrideWithAudit(
  148. provider,
  149. request
  150. );
  151. expect(result.tools).toEqual([{ googleSearch: {} }]);
  152. expect(audit).toEqual({
  153. type: "gemini_google_search_override",
  154. scope: "request",
  155. hit: true,
  156. providerId: 1,
  157. providerName: "Test Gemini",
  158. action: "inject",
  159. preference: "enabled",
  160. hadGoogleSearchInRequest: false,
  161. });
  162. });
  163. test("should return passthrough audit when googleSearch already present", () => {
  164. const provider = {
  165. id: 2,
  166. name: "Gemini Pro",
  167. providerType: "gemini",
  168. geminiGoogleSearchPreference: "enabled",
  169. };
  170. const request = { contents: [], tools: [{ googleSearch: {} }] };
  171. const { request: result, audit } = applyGeminiGoogleSearchOverrideWithAudit(
  172. provider,
  173. request
  174. );
  175. expect(result).toBe(request);
  176. expect(audit).toEqual({
  177. type: "gemini_google_search_override",
  178. scope: "request",
  179. hit: true,
  180. providerId: 2,
  181. providerName: "Gemini Pro",
  182. action: "passthrough",
  183. preference: "enabled",
  184. hadGoogleSearchInRequest: true,
  185. });
  186. });
  187. test("should skip audit for non-generation Gemini actions when pathname is provided", () => {
  188. const provider = {
  189. id: 5,
  190. name: "Gemini Embeddings",
  191. providerType: "gemini",
  192. geminiGoogleSearchPreference: "enabled",
  193. };
  194. const request = { content: { parts: [{ text: "hello" }] } };
  195. const { request: result, audit } = applyGeminiGoogleSearchOverrideWithAudit(
  196. provider,
  197. request,
  198. "/v1beta/models/gemini-embedding-001:embedContent"
  199. );
  200. expect(result).toBe(request);
  201. expect(audit).toBeNull();
  202. });
  203. });
  204. describe("disabled preference", () => {
  205. test("should return remove audit when googleSearch is removed", () => {
  206. const provider = {
  207. id: 3,
  208. name: "Gemini Flash",
  209. providerType: "gemini",
  210. geminiGoogleSearchPreference: "disabled",
  211. };
  212. const request = { contents: [], tools: [{ googleSearch: {} }] };
  213. const { request: result, audit } = applyGeminiGoogleSearchOverrideWithAudit(
  214. provider,
  215. request
  216. );
  217. expect(result.tools).toBeUndefined();
  218. expect(audit).toEqual({
  219. type: "gemini_google_search_override",
  220. scope: "request",
  221. hit: true,
  222. providerId: 3,
  223. providerName: "Gemini Flash",
  224. action: "remove",
  225. preference: "disabled",
  226. hadGoogleSearchInRequest: true,
  227. });
  228. });
  229. test("should return passthrough audit when no googleSearch to remove", () => {
  230. const provider = {
  231. id: 4,
  232. providerType: "gemini-cli",
  233. geminiGoogleSearchPreference: "disabled",
  234. };
  235. const request = { contents: [], tools: [{ codeExecution: {} }] };
  236. const { request: result, audit } = applyGeminiGoogleSearchOverrideWithAudit(
  237. provider,
  238. request
  239. );
  240. expect(result).toBe(request);
  241. expect(audit).toEqual({
  242. type: "gemini_google_search_override",
  243. scope: "request",
  244. hit: true,
  245. providerId: 4,
  246. providerName: null,
  247. action: "passthrough",
  248. preference: "disabled",
  249. hadGoogleSearchInRequest: false,
  250. });
  251. });
  252. });
  253. describe("edge cases", () => {
  254. test("should handle missing provider id and name", () => {
  255. const provider = {
  256. providerType: "gemini",
  257. geminiGoogleSearchPreference: "enabled",
  258. };
  259. const request = { contents: [] };
  260. const { audit } = applyGeminiGoogleSearchOverrideWithAudit(provider, request);
  261. expect(audit?.providerId).toBeNull();
  262. expect(audit?.providerName).toBeNull();
  263. });
  264. test("should handle non-plain object tools", () => {
  265. const provider = {
  266. providerType: "gemini",
  267. geminiGoogleSearchPreference: "disabled",
  268. };
  269. const request = { contents: [], tools: ["string-tool", 123, null] };
  270. const { request: result } = applyGeminiGoogleSearchOverrideWithAudit(
  271. provider,
  272. request as unknown as Record<string, unknown>
  273. );
  274. expect(result).toBe(request);
  275. });
  276. test("should handle googleSearch with extra properties", () => {
  277. const provider = {
  278. providerType: "gemini",
  279. geminiGoogleSearchPreference: "disabled",
  280. };
  281. const request = {
  282. contents: [],
  283. tools: [{ googleSearch: { dynamicRetrievalConfig: { threshold: 0.5 } } }],
  284. };
  285. const { request: result } = applyGeminiGoogleSearchOverrideWithAudit(provider, request);
  286. expect(result.tools).toBeUndefined();
  287. });
  288. });
  289. });