@use-lattice/litmus 0.121.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/LICENSE +19 -0
  2. package/dist/src/accounts-Bt1oJb1Z.cjs +219 -0
  3. package/dist/src/accounts-DjOU8Rm3.js +178 -0
  4. package/dist/src/agentic-utils-D03IiXQc.js +153 -0
  5. package/dist/src/agentic-utils-Dh7xaMQM.cjs +180 -0
  6. package/dist/src/agents-C6BIMlZa.js +231 -0
  7. package/dist/src/agents-DvIpNX1L.cjs +666 -0
  8. package/dist/src/agents-ZP0RP9vV.cjs +231 -0
  9. package/dist/src/agents-maJXdjbR.js +665 -0
  10. package/dist/src/aimlapi-BTbQjG2E.cjs +30 -0
  11. package/dist/src/aimlapi-CwMxqfXP.js +30 -0
  12. package/dist/src/audio-BBUdvsde.cjs +97 -0
  13. package/dist/src/audio-D5DPZ7I-.js +97 -0
  14. package/dist/src/base-BEysXrkq.cjs +222 -0
  15. package/dist/src/base-C451JQfq.js +193 -0
  16. package/dist/src/blobs-BY8MDmpo.js +230 -0
  17. package/dist/src/blobs-BgcNn97m.cjs +256 -0
  18. package/dist/src/cache-BBE_lsTA.cjs +4 -0
  19. package/dist/src/cache-BkrqU5Ba.js +237 -0
  20. package/dist/src/cache-DsCxFlsZ.cjs +297 -0
  21. package/dist/src/chat-CPJWDP6a.cjs +289 -0
  22. package/dist/src/chat-CXX3xzkk.cjs +811 -0
  23. package/dist/src/chat-CcDgZFJ4.js +787 -0
  24. package/dist/src/chat-Dz5ZeGO2.js +289 -0
  25. package/dist/src/chatkit-Dw0mKkML.cjs +1158 -0
  26. package/dist/src/chatkit-swAIVuea.js +1157 -0
  27. package/dist/src/chunk-DEq-mXcV.js +15 -0
  28. package/dist/src/claude-agent-sdk-BXZJtOg6.js +379 -0
  29. package/dist/src/claude-agent-sdk-CkfyjDoG.cjs +383 -0
  30. package/dist/src/cloudflare-ai-BzpJcqUH.js +161 -0
  31. package/dist/src/cloudflare-ai-Cmy_R1y2.cjs +161 -0
  32. package/dist/src/cloudflare-gateway-B9tVQKok.cjs +272 -0
  33. package/dist/src/cloudflare-gateway-DrD3ew3H.js +272 -0
  34. package/dist/src/codex-sdk-Dezj9Nwm.js +1056 -0
  35. package/dist/src/codex-sdk-Dl9D4k5B.cjs +1060 -0
  36. package/dist/src/cometapi-C-9YvCHC.js +54 -0
  37. package/dist/src/cometapi-DHgDKoO2.cjs +54 -0
  38. package/dist/src/completion-B8Ctyxpr.js +120 -0
  39. package/dist/src/completion-Cxrt08sj.cjs +131 -0
  40. package/dist/src/createHash-BwgE13yv.cjs +27 -0
  41. package/dist/src/createHash-DmPQkvBh.js +15 -0
  42. package/dist/src/docker-BiqcTwLv.js +80 -0
  43. package/dist/src/docker-C7tEJnP-.cjs +80 -0
  44. package/dist/src/esm-C62Zofr1.cjs +409 -0
  45. package/dist/src/esm-DMVc93eh.js +379 -0
  46. package/dist/src/evalResult-C3NJPQOo.cjs +301 -0
  47. package/dist/src/evalResult-C7JJAPBb.js +295 -0
  48. package/dist/src/evalResult-DoVTZZWI.cjs +2 -0
  49. package/dist/src/extractor-DnMD3fwt.cjs +391 -0
  50. package/dist/src/extractor-DtlL28vL.js +374 -0
  51. package/dist/src/fetch-BTxakTSg.cjs +1133 -0
  52. package/dist/src/fetch-DQckpUFz.js +928 -0
  53. package/dist/src/fileExtensions-DnqA1y9x.js +85 -0
  54. package/dist/src/fileExtensions-bYh77CN8.cjs +114 -0
  55. package/dist/src/genaiTracer-CyZrmaK0.cjs +268 -0
  56. package/dist/src/genaiTracer-D3fD9dNV.js +256 -0
  57. package/dist/src/graders-BNscxFrU.js +13644 -0
  58. package/dist/src/graders-D2oE9Msq.js +2 -0
  59. package/dist/src/graders-c0Ez_w-9.cjs +2 -0
  60. package/dist/src/graders-d0F2M3e9.cjs +14056 -0
  61. package/dist/src/image-0ZhE0VlR.cjs +280 -0
  62. package/dist/src/image-CWE1pdNv.js +257 -0
  63. package/dist/src/image-D9ZK6hwL.js +163 -0
  64. package/dist/src/image-DKZgZITg.cjs +163 -0
  65. package/dist/src/index.cjs +11366 -0
  66. package/dist/src/index.d.cts +19640 -0
  67. package/dist/src/index.d.ts +19641 -0
  68. package/dist/src/index.js +11306 -0
  69. package/dist/src/invariant-Ddh24eXh.js +25 -0
  70. package/dist/src/invariant-kfQ8Bu82.cjs +30 -0
  71. package/dist/src/knowledgeBase-BgPyGFUd.cjs +122 -0
  72. package/dist/src/knowledgeBase-DyHilYaP.js +122 -0
  73. package/dist/src/litellm-CyMeneHS.js +135 -0
  74. package/dist/src/litellm-DWDF73yF.cjs +135 -0
  75. package/dist/src/logger-C40ZGil9.js +717 -0
  76. package/dist/src/logger-DyfK9PBt.cjs +917 -0
  77. package/dist/src/luma-ray-BAU9X_ep.cjs +315 -0
  78. package/dist/src/luma-ray-nwVseBbv.js +313 -0
  79. package/dist/src/messages-B5ADWTTv.js +245 -0
  80. package/dist/src/messages-BCnZfqrS.cjs +257 -0
  81. package/dist/src/meteor-DLZZ3osF.cjs +134 -0
  82. package/dist/src/meteor-DUiCJRC-.js +134 -0
  83. package/dist/src/modelslab-00cveB8L.cjs +163 -0
  84. package/dist/src/modelslab-D9sCU_L7.js +163 -0
  85. package/dist/src/nova-reel-CTapvqYH.js +276 -0
  86. package/dist/src/nova-reel-DlWuuroF.cjs +278 -0
  87. package/dist/src/nova-sonic-5UPWfeMv.cjs +363 -0
  88. package/dist/src/nova-sonic-BhSwQNym.js +363 -0
  89. package/dist/src/openai-BWrJK9d8.cjs +52 -0
  90. package/dist/src/openai-DumO8WQn.js +47 -0
  91. package/dist/src/openclaw-B8brrjC_.cjs +577 -0
  92. package/dist/src/openclaw-Bkayww9q.js +571 -0
  93. package/dist/src/opencode-sdk-7xjoDNiM.cjs +562 -0
  94. package/dist/src/opencode-sdk-SGwAPxht.js +558 -0
  95. package/dist/src/otlpReceiver-CoAHfAN9.cjs +15 -0
  96. package/dist/src/otlpReceiver-oO3EQwI9.js +14 -0
  97. package/dist/src/providerRegistry-4yjhaEM8.js +45 -0
  98. package/dist/src/providerRegistry-DhV4rJIc.cjs +50 -0
  99. package/dist/src/providers-B5RJVG-7.cjs +33609 -0
  100. package/dist/src/providers-BdmZCLzV.js +33262 -0
  101. package/dist/src/providers-CxtRxn8e.js +2 -0
  102. package/dist/src/providers-DnQLNbx1.cjs +3 -0
  103. package/dist/src/pythonUtils-BD0druiM.cjs +275 -0
  104. package/dist/src/pythonUtils-IBhn5YGR.js +249 -0
  105. package/dist/src/quiverai-BDOwZBsM.cjs +213 -0
  106. package/dist/src/quiverai-D3JTF5lD.js +213 -0
  107. package/dist/src/responses-B2LCDCXZ.js +667 -0
  108. package/dist/src/responses-BvNm4Xv9.cjs +685 -0
  109. package/dist/src/rubyUtils-B0NwnfpY.cjs +245 -0
  110. package/dist/src/rubyUtils-BroxzZ7c.cjs +2 -0
  111. package/dist/src/rubyUtils-hqVw5UvJ.js +222 -0
  112. package/dist/src/sagemaker-Cno2V-Sx.js +689 -0
  113. package/dist/src/sagemaker-fV_KUgs5.cjs +691 -0
  114. package/dist/src/server-BOuAXb06.cjs +238 -0
  115. package/dist/src/server-CtI-EWzm.cjs +2 -0
  116. package/dist/src/server-Cy3DZymt.js +189 -0
  117. package/dist/src/slack-CP8xBePa.js +135 -0
  118. package/dist/src/slack-DSQ1yXVb.cjs +135 -0
  119. package/dist/src/store-BwDDaBjb.cjs +246 -0
  120. package/dist/src/store-DcbLC593.cjs +2 -0
  121. package/dist/src/store-IGpqMIkv.js +240 -0
  122. package/dist/src/tables-3Q2cL7So.cjs +373 -0
  123. package/dist/src/tables-Bi2fjr4W.js +288 -0
  124. package/dist/src/telemetry-Bg2WqF79.js +161 -0
  125. package/dist/src/telemetry-D0x6u5kX.cjs +166 -0
  126. package/dist/src/telemetry-DXNimrI0.cjs +2 -0
  127. package/dist/src/text-B_UCRPp2.js +22 -0
  128. package/dist/src/text-CW1cyrwj.cjs +33 -0
  129. package/dist/src/tokenUsageUtils-NYT-WKS6.js +138 -0
  130. package/dist/src/tokenUsageUtils-bVa1ga6f.cjs +173 -0
  131. package/dist/src/transcription-Cl_W16Pr.js +122 -0
  132. package/dist/src/transcription-yt1EecY8.cjs +124 -0
  133. package/dist/src/transform-BCtGrl_W.cjs +228 -0
  134. package/dist/src/transform-Bv6gG2MJ.cjs +1688 -0
  135. package/dist/src/transform-CY1wbpRy.js +1507 -0
  136. package/dist/src/transform-DU8rUL9P.cjs +2 -0
  137. package/dist/src/transform-yWaShiKr.js +216 -0
  138. package/dist/src/transformersAvailability-BGkzavwb.js +35 -0
  139. package/dist/src/transformersAvailability-DKoRtQLy.cjs +35 -0
  140. package/dist/src/types-5aqHpBwE.cjs +3769 -0
  141. package/dist/src/types-Bn6D9c4U.js +3300 -0
  142. package/dist/src/util-BkKlTkI2.js +293 -0
  143. package/dist/src/util-CTh0bfOm.cjs +1119 -0
  144. package/dist/src/util-D17oBwo7.cjs +328 -0
  145. package/dist/src/util-DsS_-v4p.js +613 -0
  146. package/dist/src/util-DuntT1Ga.js +951 -0
  147. package/dist/src/util-aWjdCYMI.cjs +667 -0
  148. package/dist/src/utils-CisQwpjA.js +94 -0
  149. package/dist/src/utils-yWamDvmz.cjs +123 -0
  150. package/dist/tsconfig.tsbuildinfo +1 -0
  151. package/drizzle/0000_lush_hellion.sql +36 -0
  152. package/drizzle/0001_wide_calypso.sql +3 -0
  153. package/drizzle/0002_tidy_juggernaut.sql +1 -0
  154. package/drizzle/0003_lively_naoko.sql +8 -0
  155. package/drizzle/0004_minor_peter_quill.sql +19 -0
  156. package/drizzle/0005_silky_millenium_guard.sql +2 -0
  157. package/drizzle/0006_harsh_caretaker.sql +42 -0
  158. package/drizzle/0007_cloudy_wong.sql +1 -0
  159. package/drizzle/0008_broad_boomer.sql +2 -0
  160. package/drizzle/0009_strong_marten_broadcloak.sql +19 -0
  161. package/drizzle/0010_needy_bishop.sql +11 -0
  162. package/drizzle/0011_moaning_millenium_guard.sql +1 -0
  163. package/drizzle/0012_late_marten_broadcloak.sql +2 -0
  164. package/drizzle/0013_previous_dormammu.sql +9 -0
  165. package/drizzle/0014_lazy_captain_universe.sql +2 -0
  166. package/drizzle/0015_zippy_wallop.sql +29 -0
  167. package/drizzle/0016_jazzy_zemo.sql +2 -0
  168. package/drizzle/0017_reflective_praxagora.sql +4 -0
  169. package/drizzle/0018_fat_vanisher.sql +22 -0
  170. package/drizzle/0019_new_clint_barton.sql +8 -0
  171. package/drizzle/0020_skinny_maverick.sql +1 -0
  172. package/drizzle/0021_mysterious_madelyne_pryor.sql +13 -0
  173. package/drizzle/0022_sleepy_ultimo.sql +25 -0
  174. package/drizzle/0023_wooden_mandrill.sql +2 -0
  175. package/drizzle/AGENTS.md +68 -0
  176. package/drizzle/CLAUDE.md +1 -0
  177. package/drizzle/meta/0000_snapshot.json +221 -0
  178. package/drizzle/meta/0001_snapshot.json +214 -0
  179. package/drizzle/meta/0002_snapshot.json +221 -0
  180. package/drizzle/meta/0005_snapshot.json +369 -0
  181. package/drizzle/meta/0006_snapshot.json +638 -0
  182. package/drizzle/meta/0007_snapshot.json +640 -0
  183. package/drizzle/meta/0008_snapshot.json +649 -0
  184. package/drizzle/meta/0009_snapshot.json +554 -0
  185. package/drizzle/meta/0010_snapshot.json +619 -0
  186. package/drizzle/meta/0011_snapshot.json +627 -0
  187. package/drizzle/meta/0012_snapshot.json +639 -0
  188. package/drizzle/meta/0013_snapshot.json +717 -0
  189. package/drizzle/meta/0014_snapshot.json +717 -0
  190. package/drizzle/meta/0015_snapshot.json +897 -0
  191. package/drizzle/meta/0016_snapshot.json +1031 -0
  192. package/drizzle/meta/0018_snapshot.json +1210 -0
  193. package/drizzle/meta/0019_snapshot.json +1165 -0
  194. package/drizzle/meta/0020_snapshot.json +1232 -0
  195. package/drizzle/meta/0021_snapshot.json +1311 -0
  196. package/drizzle/meta/0022_snapshot.json +1481 -0
  197. package/drizzle/meta/0023_snapshot.json +1496 -0
  198. package/drizzle/meta/_journal.json +174 -0
  199. package/package.json +240 -0
@@ -0,0 +1,1688 @@
1
+ const require_logger = require("./logger-DyfK9PBt.cjs");
2
+ const require_util = require("./util-CTh0bfOm.cjs");
3
+ const require_fetch = require("./fetch-BTxakTSg.cjs");
4
+ let rfdc = require("rfdc");
5
+ rfdc = require_logger.__toESM(rfdc);
6
+ let zod = require("zod");
7
+ let crypto = require("crypto");
8
+ crypto = require_logger.__toESM(crypto);
9
+ //#region src/util/oauth.ts
10
+ /**
11
+ * Buffer time before token expiry to trigger proactive refresh (60 seconds)
12
+ */
13
+ const TOKEN_REFRESH_BUFFER_MS = 6e4;
14
+ /**
15
+ * Fetch an OAuth token from a token endpoint.
16
+ * Handles both client_credentials and password grant types.
17
+ *
18
+ * @param config - OAuth configuration with rendered/resolved values
19
+ * @returns Token and expiration timestamp
20
+ */
21
+ async function fetchOAuthToken(config) {
22
+ const now = Date.now();
23
+ require_logger.logger.debug("[OAuth] Fetching new token");
24
+ const tokenRequestBody = new URLSearchParams();
25
+ tokenRequestBody.append("grant_type", config.grantType);
26
+ if (config.clientId) tokenRequestBody.append("client_id", config.clientId);
27
+ if (config.clientSecret) tokenRequestBody.append("client_secret", config.clientSecret);
28
+ if (config.grantType === "password") {
29
+ if (config.username) tokenRequestBody.append("username", config.username);
30
+ if (config.password) tokenRequestBody.append("password", config.password);
31
+ }
32
+ if (config.scopes && config.scopes.length > 0) tokenRequestBody.append("scope", config.scopes.join(" "));
33
+ const response = await require_fetch.fetchWithProxy(config.tokenUrl, {
34
+ method: "POST",
35
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
36
+ body: tokenRequestBody.toString()
37
+ });
38
+ if (!response.ok) {
39
+ const errorText = await response.text();
40
+ throw new Error(`OAuth token request failed with status ${response.status} ${response.statusText}: ${errorText}`);
41
+ }
42
+ const tokenData = await response.json();
43
+ if (!tokenData.access_token) throw new Error("OAuth token response missing access_token");
44
+ const expiresAt = now + (tokenData.expires_in || 3600) * 1e3;
45
+ require_logger.logger.debug("[OAuth] Successfully fetched token");
46
+ return {
47
+ accessToken: tokenData.access_token,
48
+ expiresAt
49
+ };
50
+ }
51
+ //#endregion
52
+ //#region src/providers/mcp/util.ts
53
+ /**
54
+ * Render environment variables in server config auth fields.
55
+ * Supports {{VAR_NAME}} syntax for variable substitution.
56
+ */
57
+ function renderAuthVars(server, vars) {
58
+ if (!server.auth) return server;
59
+ const renderVars = vars || process.env;
60
+ return {
61
+ ...server,
62
+ auth: require_util.renderVarsInObject(server.auth, renderVars)
63
+ };
64
+ }
65
+ const oauthTokenCache = /* @__PURE__ */ new Map();
66
+ /**
67
+ * Get the cache key for an OAuth config
68
+ */
69
+ function getOAuthCacheKey(auth) {
70
+ return `${auth.tokenUrl}:${auth.grantType}:${"clientId" in auth ? auth.clientId : ""}:${"username" in auth ? auth.username : ""}`;
71
+ }
72
+ const tokenEndpointCache = /* @__PURE__ */ new Map();
73
+ /**
74
+ * Discover the OAuth token endpoint from the server's well-known metadata.
75
+ * Follows RFC 8414 OAuth 2.0 Authorization Server Metadata.
76
+ * Only requires token_endpoint from the response (unlike SDK which requires authorization_endpoint).
77
+ */
78
+ async function discoverTokenEndpoint(serverUrl) {
79
+ const cached = tokenEndpointCache.get(serverUrl);
80
+ if (cached) {
81
+ require_logger.logger.debug(`[MCP Auth] Using cached token endpoint for ${serverUrl}`);
82
+ return cached;
83
+ }
84
+ const url = new URL(serverUrl);
85
+ const baseUrl = `${url.protocol}//${url.host}`;
86
+ const discoveryUrls = [];
87
+ if (url.pathname && url.pathname !== "/") {
88
+ discoveryUrls.push(`${baseUrl}${url.pathname}/.well-known/oauth-authorization-server`);
89
+ discoveryUrls.push(`${baseUrl}/.well-known/oauth-authorization-server${url.pathname}`);
90
+ }
91
+ discoveryUrls.push(`${baseUrl}/.well-known/oauth-authorization-server`);
92
+ for (const discoveryUrl of discoveryUrls) try {
93
+ require_logger.logger.debug(`[MCP Auth] Trying OAuth discovery at ${discoveryUrl}`);
94
+ const response = await require_fetch.fetchWithProxy(discoveryUrl);
95
+ if (!response.ok) {
96
+ require_logger.logger.debug(`[MCP Auth] Discovery failed at ${discoveryUrl}: ${response.status}`);
97
+ continue;
98
+ }
99
+ const metadata = await response.json();
100
+ if (metadata.token_endpoint) {
101
+ require_logger.logger.debug(`[MCP Auth] Discovered token endpoint: ${metadata.token_endpoint}`);
102
+ tokenEndpointCache.set(serverUrl, metadata.token_endpoint);
103
+ return metadata.token_endpoint;
104
+ }
105
+ require_logger.logger.debug(`[MCP Auth] No token_endpoint in metadata from ${discoveryUrl}`);
106
+ } catch (error) {
107
+ require_logger.logger.debug(`[MCP Auth] Error fetching ${discoveryUrl}: ${error}`);
108
+ }
109
+ throw new Error(`Failed to discover OAuth token endpoint for ${serverUrl}. Please configure tokenUrl explicitly in the auth config.`);
110
+ }
111
+ /**
112
+ * Get OAuth token with expiration info, fetching a new one if needed.
113
+ * If tokenUrl is not configured, attempts OAuth discovery to find the token endpoint.
114
+ * Caches tokens and returns cached version if still valid.
115
+ */
116
+ async function getOAuthTokenWithExpiry(auth, serverUrl) {
117
+ let tokenUrl = auth.tokenUrl;
118
+ if (!tokenUrl) {
119
+ if (!serverUrl) throw new Error("Either tokenUrl or serverUrl is required for OAuth token fetching");
120
+ tokenUrl = await discoverTokenEndpoint(serverUrl);
121
+ }
122
+ const cacheKey = getOAuthCacheKey(auth);
123
+ const cached = oauthTokenCache.get(cacheKey);
124
+ if (cached && Date.now() + 6e4 < cached.expiresAt) {
125
+ require_logger.logger.debug("[MCP Auth] Using cached OAuth token");
126
+ return {
127
+ accessToken: cached.accessToken,
128
+ expiresAt: cached.expiresAt
129
+ };
130
+ }
131
+ const result = await fetchOAuthToken({
132
+ tokenUrl,
133
+ grantType: auth.grantType,
134
+ clientId: auth.clientId,
135
+ clientSecret: auth.clientSecret,
136
+ username: "username" in auth ? auth.username : void 0,
137
+ password: "password" in auth ? auth.password : void 0,
138
+ scopes: auth.scopes
139
+ });
140
+ oauthTokenCache.set(cacheKey, {
141
+ accessToken: result.accessToken,
142
+ expiresAt: result.expiresAt
143
+ });
144
+ require_logger.logger.debug("[MCP Auth] Cached OAuth token");
145
+ return result;
146
+ }
147
+ /**
148
+ * Get OAuth token, fetching a new one if needed.
149
+ * Requires tokenUrl to be configured - throws if not provided.
150
+ */
151
+ async function getOAuthToken(auth) {
152
+ return (await getOAuthTokenWithExpiry(auth)).accessToken;
153
+ }
154
+ /**
155
+ * Get authentication headers for an MCP server configuration.
156
+ * Returns headers for bearer, basic, and api_key (header placement) auth types.
157
+ * For OAuth, use getOAuthToken() first then pass the token.
158
+ * For api_key with query placement, use getAuthQueryParams() instead.
159
+ */
160
+ function getAuthHeaders(server, oauthToken) {
161
+ if (!server.auth) return {};
162
+ switch (server.auth.type) {
163
+ case "bearer":
164
+ if (!server.auth.token) return {};
165
+ return { Authorization: `Bearer ${server.auth.token}` };
166
+ case "basic": return { Authorization: `Basic ${Buffer.from(`${server.auth.username}:${server.auth.password}`).toString("base64")}` };
167
+ case "api_key": {
168
+ const apiKeyAuth = server.auth;
169
+ const value = apiKeyAuth.value || apiKeyAuth.api_key;
170
+ if (!value) return {};
171
+ if ((apiKeyAuth.placement || "header") === "header") return { [apiKeyAuth.keyName || "X-API-Key"]: value };
172
+ return {};
173
+ }
174
+ case "oauth":
175
+ if (oauthToken) return { Authorization: `Bearer ${oauthToken}` };
176
+ require_logger.logger.warn("[MCP Auth] OAuth auth configured but no token provided");
177
+ return {};
178
+ default: return {};
179
+ }
180
+ }
181
+ /**
182
+ * Get authentication query parameters for api_key auth with query placement.
183
+ * Returns an object with key-value pairs to be added to the URL.
184
+ */
185
+ function getAuthQueryParams(server) {
186
+ if (!server.auth || server.auth.type !== "api_key") return {};
187
+ const apiKeyAuth = server.auth;
188
+ const value = apiKeyAuth.value || apiKeyAuth.api_key;
189
+ if (!value) return {};
190
+ if ((apiKeyAuth.placement || "header") !== "query") return {};
191
+ return { [apiKeyAuth.keyName || "X-API-Key"]: value };
192
+ }
193
+ /**
194
+ * Apply query parameters to a URL
195
+ */
196
+ function applyQueryParams(url, params) {
197
+ if (Object.keys(params).length === 0) return url;
198
+ const urlObj = new URL(url);
199
+ for (const [key, value] of Object.entries(params)) urlObj.searchParams.append(key, value);
200
+ return urlObj.toString();
201
+ }
202
+ /**
203
+ * Check if auth requires async token fetching (OAuth)
204
+ */
205
+ function requiresAsyncAuth(server) {
206
+ return server.auth?.type === "oauth";
207
+ }
208
+ //#endregion
209
+ //#region src/util/dataUrl.ts
210
+ /**
211
+ * Check if a string is a data URL
212
+ * @param value String to check
213
+ * @returns true if value is a data URL (starts with "data:")
214
+ *
215
+ * @example
216
+ * isDataUrl("data:image/jpeg;base64,/9j/...") // true
217
+ * isDataUrl("/9j/4AAQSkZJRg...") // false
218
+ * isDataUrl("https://example.com/image.jpg") // false
219
+ */
220
+ function isDataUrl(value) {
221
+ return typeof value === "string" && value.startsWith("data:") && value.length > 5;
222
+ }
223
+ /**
224
+ * Parse a data URL into its components
225
+ *
226
+ * Handles data URLs with optional parameters (e.g., charset, name):
227
+ * - `data:image/jpeg;base64,<data>` - Standard format
228
+ * - `data:image/jpeg;charset=utf-8;base64,<data>` - With charset
229
+ * - `data:image/jpeg;name=photo.jpg;base64,<data>` - With filename
230
+ *
231
+ * @param dataUrl Data URL string
232
+ * @returns Parsed components (mimeType and base64Data) or null if invalid
233
+ *
234
+ * @example
235
+ * parseDataUrl("data:image/jpeg;base64,/9j/...")
236
+ * // { mimeType: "image/jpeg", base64Data: "/9j/..." }
237
+ *
238
+ * parseDataUrl("data:image/jpeg;charset=utf-8;base64,/9j/...")
239
+ * // { mimeType: "image/jpeg", base64Data: "/9j/..." }
240
+ *
241
+ * parseDataUrl("invalid") // null
242
+ */
243
+ function parseDataUrl(dataUrl) {
244
+ if (!isDataUrl(dataUrl)) return null;
245
+ const match = dataUrl.match(/^data:([^;,]+)(?:;[^,]*)?;base64,(.+)$/);
246
+ if (!match) return null;
247
+ return {
248
+ mimeType: match[1].trim(),
249
+ base64Data: match[2].trim()
250
+ };
251
+ }
252
+ /**
253
+ * Extract base64 data from a data URL or return original if not a data URL
254
+ * Useful for providers that expect raw base64 (Anthropic, Google)
255
+ *
256
+ * @param value Data URL or raw base64 string
257
+ * @returns Raw base64 string (data URL prefix stripped if present)
258
+ *
259
+ * @example
260
+ * extractBase64FromDataUrl("data:image/jpeg;base64,/9j/...")
261
+ * // "/9j/..."
262
+ *
263
+ * extractBase64FromDataUrl("/9j/...") // "/9j/..." (unchanged)
264
+ */
265
+ function extractBase64FromDataUrl(value) {
266
+ const parsed = parseDataUrl(value);
267
+ return parsed ? parsed.base64Data : value;
268
+ }
269
+ /**
270
+ * Build a data URI from a MIME type and base64 data.
271
+ *
272
+ * @param mimeType MIME type (e.g. "image/png")
273
+ * @param base64Data Raw base64-encoded data
274
+ * @returns Data URI string
275
+ *
276
+ * @example
277
+ * toDataUri("image/png", "iVBORw0KGgo...")
278
+ * // "data:image/png;base64,iVBORw0KGgo..."
279
+ */
280
+ function toDataUri(mimeType, base64Data) {
281
+ return `data:${mimeType};base64,${base64Data}`;
282
+ }
283
+ //#endregion
284
+ //#region src/providers/google/auth.ts
285
+ /**
286
+ * Centralized authentication manager for Google AI providers.
287
+ *
288
+ * This module handles authentication for both Google AI Studio and Vertex AI,
289
+ * with support for API keys, OAuth/ADC, and service account credentials.
290
+ *
291
+ * Environment variable priority is aligned with the Python SDK:
292
+ * 1. config.apiKey (explicit)
293
+ * 2. VERTEX_API_KEY (Vertex mode only)
294
+ * 3. GOOGLE_API_KEY (primary - Python SDK alignment)
295
+ * 4. GEMINI_API_KEY (secondary)
296
+ */
297
+ /**
298
+ * Centralized authentication manager for Google AI providers.
299
+ *
300
+ * Handles:
301
+ * - API key resolution with proper priority
302
+ * - OAuth client creation for Vertex AI
303
+ * - Service account credential loading
304
+ * - Conflict detection and warnings
305
+ */
306
+ var GoogleAuthManager = class {
307
+ static cachedHasDefaultCredentials;
308
+ static pendingHasDefaultCredentials;
309
+ /**
310
+ * Get API key with proper priority order.
311
+ *
312
+ * Priority (aligned with Python SDK):
313
+ * 1. config.apiKey (explicit)
314
+ * 2. VERTEX_API_KEY (Vertex mode only)
315
+ * 3. GOOGLE_API_KEY (primary - Python SDK alignment)
316
+ * 4. GEMINI_API_KEY (secondary)
317
+ * 5. PALM_API_KEY (legacy)
318
+ *
319
+ * @param config - Provider configuration
320
+ * @param env - Environment overrides
321
+ * @param isVertexMode - Whether in Vertex AI mode
322
+ * @returns The resolved API key and its source
323
+ */
324
+ static getApiKey(config, env, isVertexMode = false) {
325
+ if (config.apiKey) return {
326
+ apiKey: config.apiKey,
327
+ source: "config"
328
+ };
329
+ if (isVertexMode) {
330
+ const vertexKey = env?.VERTEX_API_KEY || require_logger.getEnvString("VERTEX_API_KEY");
331
+ if (vertexKey) {
332
+ require_logger.logger.warn("[Google] VERTEX_API_KEY is not a standard SDK env var. Use GOOGLE_API_KEY instead.");
333
+ return {
334
+ apiKey: vertexKey,
335
+ source: "VERTEX_API_KEY"
336
+ };
337
+ }
338
+ }
339
+ const googleKey = env?.GOOGLE_API_KEY || require_logger.getEnvString("GOOGLE_API_KEY");
340
+ const geminiKey = env?.GEMINI_API_KEY || require_logger.getEnvString("GEMINI_API_KEY");
341
+ const palmKey = isVertexMode ? void 0 : env?.PALM_API_KEY || require_logger.getEnvString("PALM_API_KEY");
342
+ if (googleKey && geminiKey) require_logger.logger.debug("[Google] Both GOOGLE_API_KEY and GEMINI_API_KEY are set. Using GOOGLE_API_KEY.");
343
+ if (googleKey) return {
344
+ apiKey: googleKey,
345
+ source: "GOOGLE_API_KEY"
346
+ };
347
+ if (geminiKey) {
348
+ require_logger.logger.debug("[Google] GEMINI_API_KEY is not a standard SDK env var. Consider using GOOGLE_API_KEY.");
349
+ return {
350
+ apiKey: geminiKey,
351
+ source: "GEMINI_API_KEY"
352
+ };
353
+ }
354
+ if (palmKey) {
355
+ require_logger.logger.warn("[Google] PALM_API_KEY is deprecated. Use GOOGLE_API_KEY instead.");
356
+ return {
357
+ apiKey: palmKey,
358
+ source: "PALM_API_KEY"
359
+ };
360
+ }
361
+ return {
362
+ apiKey: void 0,
363
+ source: "none"
364
+ };
365
+ }
366
+ /**
367
+ * Validate authentication configuration and emit warnings or throw errors for issues.
368
+ *
369
+ * @param config - Authentication configuration
370
+ * @param env - Environment overrides
371
+ * @throws Error if strictMutualExclusivity is true and mutual exclusivity violation detected
372
+ */
373
+ static validateAndWarn(config, env) {
374
+ const { apiKey, credentials, projectId, region, vertexai, strictMutualExclusivity } = config;
375
+ const isStrict = strictMutualExclusivity === true;
376
+ const useVertexEnv = require_logger.getEnvString("GOOGLE_GENAI_USE_VERTEXAI");
377
+ const cloudProject = require_logger.getEnvString("GOOGLE_CLOUD_PROJECT");
378
+ if ((projectId || region) && apiKey) {
379
+ const message = "[Google] Project/location and API key are mutually exclusive in the client initializer. Use either apiKey for express mode OR projectId/region for OAuth mode, not both.";
380
+ if (isStrict) throw new Error(message);
381
+ else require_logger.logger.warn(message);
382
+ }
383
+ if (useVertexEnv && vertexai === false) require_logger.logger.warn("[Google] GOOGLE_GENAI_USE_VERTEXAI is set but vertexai: false was specified in config. Config takes precedence.");
384
+ if (cloudProject && projectId && cloudProject !== projectId) require_logger.logger.warn("[Google] Both GOOGLE_CLOUD_PROJECT and config.projectId are set with different values. Using config.projectId.");
385
+ if (apiKey && credentials) require_logger.logger.debug("[Google] Both apiKey and credentials are set. Using API key (express mode). Set expressMode: false to use OAuth/ADC instead.");
386
+ if (vertexai && !apiKey && !projectId && !cloudProject && !credentials) {
387
+ if (!Boolean(env?.GOOGLE_APPLICATION_CREDENTIALS || process.env.GOOGLE_APPLICATION_CREDENTIALS)) require_logger.logger.debug("[Google] Vertex AI mode enabled but no projectId, credentials, or ADC detected. Authentication may fail.");
388
+ }
389
+ }
390
+ /**
391
+ * Determine if Vertex AI mode should be used.
392
+ *
393
+ * Priority:
394
+ * 1. Explicit vertexai config flag
395
+ * 2. GOOGLE_GENAI_USE_VERTEXAI env var (Python SDK compatibility)
396
+ * 3. Auto-detect from projectId/credentials presence
397
+ * 4. Default: false (Google AI Studio)
398
+ *
399
+ * @param config - Provider configuration
400
+ * @param env - Environment overrides
401
+ * @returns Whether to use Vertex AI mode
402
+ */
403
+ static determineVertexMode(config, env) {
404
+ if (config.vertexai !== void 0) return config.vertexai;
405
+ const useVertexEnv = require_logger.getEnvString("GOOGLE_GENAI_USE_VERTEXAI");
406
+ if (useVertexEnv === "true" || useVertexEnv === "1") {
407
+ require_logger.logger.debug("[Google] Vertex AI mode enabled via GOOGLE_GENAI_USE_VERTEXAI");
408
+ return true;
409
+ }
410
+ if (useVertexEnv === "false" || useVertexEnv === "0") return false;
411
+ const hasProjectId = Boolean(config.projectId || env?.VERTEX_PROJECT_ID || require_logger.getEnvString("VERTEX_PROJECT_ID") || env?.GOOGLE_PROJECT_ID || require_logger.getEnvString("GOOGLE_PROJECT_ID") || require_logger.getEnvString("GOOGLE_CLOUD_PROJECT"));
412
+ const hasCredentials = Boolean(config.credentials);
413
+ if (hasProjectId || hasCredentials) {
414
+ require_logger.logger.debug("[Google] Auto-detected Vertex AI mode from projectId/credentials. Set vertexai: true/false explicitly to suppress this message.");
415
+ return true;
416
+ }
417
+ return false;
418
+ }
419
+ /**
420
+ * Load credentials from file or return as-is.
421
+ *
422
+ * Supports:
423
+ * - file:// prefix to load from external file
424
+ * - Raw JSON string
425
+ * - Pre-parsed object (from config loading pipeline)
426
+ *
427
+ * @param credentials - Credentials string, file path, or pre-parsed object
428
+ * @returns Processed credentials JSON string
429
+ */
430
+ static loadCredentials(credentials) {
431
+ if (!credentials) return;
432
+ if (typeof credentials === "object") return JSON.stringify(credentials);
433
+ if (credentials.startsWith("file://")) try {
434
+ const loaded = require_util.maybeLoadFromExternalFile(credentials);
435
+ if (typeof loaded === "object") return JSON.stringify(loaded);
436
+ return loaded;
437
+ } catch (error) {
438
+ throw new Error(`Failed to load credentials from file: ${error}`);
439
+ }
440
+ return credentials;
441
+ }
442
+ /**
443
+ * Get or create a Google OAuth client.
444
+ *
445
+ * Supports googleAuthOptions passthrough for advanced configuration
446
+ * like custom scopes, keyFilename, universeDomain, etc.
447
+ *
448
+ * @param options - OAuth client options (can also pass string for backward compatibility)
449
+ * @returns OAuth client and detected project ID
450
+ */
451
+ static async getOAuthClient(options = {}) {
452
+ const { credentials, googleAuthOptions, scopes, keyFilename } = typeof options === "string" ? { credentials: options } : options;
453
+ const resolvedScopes = scopes ?? googleAuthOptions?.scopes ?? "https://www.googleapis.com/auth/cloud-platform";
454
+ const authOptions = {
455
+ ...googleAuthOptions,
456
+ scopes: resolvedScopes
457
+ };
458
+ if (keyFilename && !authOptions.keyFilename) authOptions.keyFilename = keyFilename;
459
+ let GoogleAuthClass;
460
+ try {
461
+ GoogleAuthClass = (await import("google-auth-library")).GoogleAuth;
462
+ } catch {
463
+ throw new Error("The google-auth-library package is required for Vertex AI. Please install it: npm install google-auth-library");
464
+ }
465
+ const auth = new GoogleAuthClass(authOptions);
466
+ const processedCredentials = this.loadCredentials(credentials);
467
+ let client;
468
+ if (processedCredentials) {
469
+ let parsedCredentials;
470
+ try {
471
+ parsedCredentials = JSON.parse(processedCredentials);
472
+ } catch (parseError) {
473
+ const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
474
+ throw new Error(`[Google] Invalid credentials JSON format: ${errorMsg}`);
475
+ }
476
+ try {
477
+ client = await auth.fromJSON(parsedCredentials);
478
+ } catch (error) {
479
+ const errorMsg = error instanceof Error ? error.message : String(error);
480
+ require_logger.logger.error(`[Google] Could not load credentials: ${errorMsg}`);
481
+ throw new Error(`[Google] Could not load credentials: ${errorMsg}`);
482
+ }
483
+ } else client = await auth.getClient();
484
+ let projectId;
485
+ try {
486
+ projectId = await auth.getProjectId();
487
+ } catch {
488
+ projectId = void 0;
489
+ }
490
+ return {
491
+ client,
492
+ projectId
493
+ };
494
+ }
495
+ /**
496
+ * Resolve project ID from multiple sources.
497
+ *
498
+ * Priority:
499
+ * 1. config.projectId
500
+ * 2. VERTEX_PROJECT_ID env var
501
+ * 3. GOOGLE_PROJECT_ID env var
502
+ * 4. GOOGLE_CLOUD_PROJECT env var (Python SDK compatibility)
503
+ * 5. Auto-detected from OAuth credentials
504
+ *
505
+ * @param config - Provider configuration
506
+ * @param env - Environment overrides
507
+ * @returns Resolved project ID
508
+ */
509
+ static async resolveProjectId(config, env) {
510
+ const { projectId: authProjectId } = await this.getOAuthClient({
511
+ credentials: config.credentials,
512
+ googleAuthOptions: config.googleAuthOptions,
513
+ keyFilename: config.keyFilename,
514
+ scopes: config.scopes
515
+ });
516
+ const vertexProjectId = env?.VERTEX_PROJECT_ID || require_logger.getEnvString("VERTEX_PROJECT_ID");
517
+ const googleProjectId = env?.GOOGLE_PROJECT_ID || require_logger.getEnvString("GOOGLE_PROJECT_ID");
518
+ const cloudProject = require_logger.getEnvString("GOOGLE_CLOUD_PROJECT");
519
+ if (vertexProjectId && !config.projectId) require_logger.logger.debug("[Google] VERTEX_PROJECT_ID is not a standard SDK env var. Consider using GOOGLE_CLOUD_PROJECT.");
520
+ if (googleProjectId && !config.projectId && !vertexProjectId) require_logger.logger.debug("[Google] GOOGLE_PROJECT_ID is not a standard SDK env var. Consider using GOOGLE_CLOUD_PROJECT.");
521
+ return config.projectId || vertexProjectId || googleProjectId || cloudProject || authProjectId || "";
522
+ }
523
+ /**
524
+ * Resolve region from multiple sources.
525
+ *
526
+ * Priority:
527
+ * 1. config.region
528
+ * 2. VERTEX_REGION env var
529
+ * 3. GOOGLE_CLOUD_LOCATION env var (Python SDK compatibility)
530
+ * 4. Default: 'global' for Vertex AI without API key (SDK aligned), 'us-central1' otherwise
531
+ *
532
+ * @param config - Provider configuration
533
+ * @param env - Environment overrides
534
+ * @param hasApiKey - Whether an API key is configured (affects default region)
535
+ * @returns Resolved region
536
+ */
537
+ static resolveRegion(config, env, hasApiKey) {
538
+ const vertexRegion = env?.VERTEX_REGION || require_logger.getEnvString("VERTEX_REGION");
539
+ const cloudLocation = require_logger.getEnvString("GOOGLE_CLOUD_LOCATION");
540
+ if (vertexRegion && !config.region) require_logger.logger.debug("[Google] VERTEX_REGION is not a standard SDK env var. Consider using GOOGLE_CLOUD_LOCATION.");
541
+ const configuredRegion = config.region || vertexRegion || cloudLocation;
542
+ if (configuredRegion) return configuredRegion;
543
+ if (hasApiKey === false) return "global";
544
+ return "us-central1";
545
+ }
546
+ /**
547
+ * Check if Application Default Credentials are available.
548
+ *
549
+ * @returns True if ADC is available
550
+ */
551
+ static async hasDefaultCredentials() {
552
+ if (this.cachedHasDefaultCredentials !== void 0) return this.cachedHasDefaultCredentials;
553
+ if (!this.pendingHasDefaultCredentials) {
554
+ const probe = (async () => {
555
+ try {
556
+ await this.getOAuthClient();
557
+ return true;
558
+ } catch {
559
+ return false;
560
+ }
561
+ })();
562
+ this.pendingHasDefaultCredentials = probe;
563
+ probe.then((result) => {
564
+ if (this.pendingHasDefaultCredentials === probe) this.cachedHasDefaultCredentials = result;
565
+ return result;
566
+ }).finally(() => {
567
+ if (this.pendingHasDefaultCredentials === probe) this.pendingHasDefaultCredentials = void 0;
568
+ });
569
+ }
570
+ return this.pendingHasDefaultCredentials;
571
+ }
572
+ /**
573
+ * Clear internal auth detection caches (useful for testing).
574
+ */
575
+ static clearCache() {
576
+ this.cachedHasDefaultCredentials = void 0;
577
+ this.pendingHasDefaultCredentials = void 0;
578
+ }
579
+ };
580
+ const loadCredentials = GoogleAuthManager.loadCredentials.bind(GoogleAuthManager);
581
+ const getGoogleClient = GoogleAuthManager.getOAuthClient.bind(GoogleAuthManager);
582
+ const resolveProjectId = GoogleAuthManager.resolveProjectId.bind(GoogleAuthManager);
583
+ const getGoogleApiKey = GoogleAuthManager.getApiKey.bind(GoogleAuthManager);
584
+ const determineGoogleVertexMode = GoogleAuthManager.determineVertexMode.bind(GoogleAuthManager);
585
+ const hasGoogleDefaultCredentials = GoogleAuthManager.hasDefaultCredentials.bind(GoogleAuthManager);
586
+ GoogleAuthManager.clearCache.bind(GoogleAuthManager);
587
+ //#endregion
588
+ //#region src/providers/google/shared.ts
589
+ /**
590
+ * Google AI Studio models with pricing data.
591
+ * Prices are per token (from Google AI pricing page, converted from per-million).
592
+ *
593
+ * Note: Vertex AI may have different pricing for some models.
594
+ */
595
+ const GOOGLE_MODELS = [
596
+ {
597
+ id: "gemini-3.1-pro-preview",
598
+ cost: {
599
+ input: 2 / 1e6,
600
+ output: 12 / 1e6
601
+ },
602
+ tieredCost: {
603
+ threshold: 2e5,
604
+ above: {
605
+ input: 4 / 1e6,
606
+ output: 18 / 1e6
607
+ }
608
+ }
609
+ },
610
+ {
611
+ id: "gemini-3-flash-preview",
612
+ cost: {
613
+ input: .5 / 1e6,
614
+ output: 3 / 1e6
615
+ }
616
+ },
617
+ {
618
+ id: "gemini-3-pro-preview",
619
+ cost: {
620
+ input: 2 / 1e6,
621
+ output: 12 / 1e6
622
+ },
623
+ tieredCost: {
624
+ threshold: 2e5,
625
+ above: {
626
+ input: 4 / 1e6,
627
+ output: 18 / 1e6
628
+ }
629
+ }
630
+ },
631
+ {
632
+ id: "gemini-2.5-pro",
633
+ cost: {
634
+ input: 1.25 / 1e6,
635
+ output: 10 / 1e6
636
+ },
637
+ tieredCost: {
638
+ threshold: 2e5,
639
+ above: {
640
+ input: 2.5 / 1e6,
641
+ output: 15 / 1e6
642
+ }
643
+ }
644
+ },
645
+ ...[
646
+ "gemini-2.5-pro-preview-05-06",
647
+ "gemini-2.5-pro-preview-06-05",
648
+ "gemini-2.5-computer-use-preview-10-2025"
649
+ ].map((id) => ({
650
+ id,
651
+ cost: {
652
+ input: 1.25 / 1e6,
653
+ output: 10 / 1e6
654
+ },
655
+ tieredCost: {
656
+ threshold: 2e5,
657
+ above: {
658
+ input: 2.5 / 1e6,
659
+ output: 15 / 1e6
660
+ }
661
+ }
662
+ })),
663
+ ...[
664
+ "gemini-2.5-flash",
665
+ "gemini-2.5-flash-preview-04-17",
666
+ "gemini-2.5-flash-preview-05-20",
667
+ "gemini-2.5-flash-preview-09-2025"
668
+ ].map((id) => ({
669
+ id,
670
+ cost: {
671
+ input: .3 / 1e6,
672
+ output: 2.5 / 1e6
673
+ }
674
+ })),
675
+ ...["gemini-2.5-flash-lite", "gemini-2.5-flash-lite-preview-09-2025"].map((id) => ({
676
+ id,
677
+ cost: {
678
+ input: .1 / 1e6,
679
+ output: .4 / 1e6
680
+ }
681
+ })),
682
+ ...[
683
+ "gemini-2.0-flash",
684
+ "gemini-2.0-flash-001",
685
+ "gemini-2.0-flash-exp"
686
+ ].map((id) => ({
687
+ id,
688
+ cost: {
689
+ input: .1 / 1e6,
690
+ output: .4 / 1e6
691
+ },
692
+ vertexCost: {
693
+ input: .15 / 1e6,
694
+ output: .6 / 1e6
695
+ }
696
+ })),
697
+ ...[
698
+ "gemini-2.0-flash-lite",
699
+ "gemini-2.0-flash-lite-001",
700
+ "gemini-2.0-flash-lite-preview-02-05"
701
+ ].map((id) => ({
702
+ id,
703
+ cost: {
704
+ input: .075 / 1e6,
705
+ output: .3 / 1e6
706
+ }
707
+ })),
708
+ {
709
+ id: "gemini-2.0-flash-thinking-exp",
710
+ cost: {
711
+ input: .1 / 1e6,
712
+ output: .4 / 1e6
713
+ }
714
+ },
715
+ {
716
+ id: "gemini-2.0-pro",
717
+ cost: {
718
+ input: 1.25 / 1e6,
719
+ output: 10 / 1e6
720
+ }
721
+ },
722
+ {
723
+ id: "gemini-1.5-pro",
724
+ cost: {
725
+ input: 1.25 / 1e6,
726
+ output: 5 / 1e6
727
+ },
728
+ tieredCost: {
729
+ threshold: 128e3,
730
+ above: {
731
+ input: 2.5 / 1e6,
732
+ output: 10 / 1e6
733
+ }
734
+ }
735
+ },
736
+ ...[
737
+ "gemini-1.5-pro-001",
738
+ "gemini-1.5-pro-002",
739
+ "gemini-1.5-pro-latest"
740
+ ].map((id) => ({
741
+ id,
742
+ cost: {
743
+ input: 1.25 / 1e6,
744
+ output: 5 / 1e6
745
+ },
746
+ tieredCost: {
747
+ threshold: 128e3,
748
+ above: {
749
+ input: 2.5 / 1e6,
750
+ output: 10 / 1e6
751
+ }
752
+ }
753
+ })),
754
+ ...["gemini-1.5-pro-preview-0409", "gemini-1.5-pro-preview-0514"].map((id) => ({
755
+ id,
756
+ cost: {
757
+ input: 1.25 / 1e6,
758
+ output: 5 / 1e6
759
+ },
760
+ tieredCost: {
761
+ threshold: 128e3,
762
+ above: {
763
+ input: 2.5 / 1e6,
764
+ output: 10 / 1e6
765
+ }
766
+ }
767
+ })),
768
+ ...[
769
+ "gemini-1.5-flash",
770
+ "gemini-1.5-flash-001",
771
+ "gemini-1.5-flash-002",
772
+ "gemini-1.5-flash-latest",
773
+ "gemini-1.5-flash-preview-0514"
774
+ ].map((id) => ({
775
+ id,
776
+ cost: {
777
+ input: .075 / 1e6,
778
+ output: .3 / 1e6
779
+ },
780
+ tieredCost: {
781
+ threshold: 128e3,
782
+ above: {
783
+ input: .15 / 1e6,
784
+ output: .6 / 1e6
785
+ }
786
+ }
787
+ })),
788
+ ...[
789
+ "gemini-1.5-flash-8b",
790
+ "gemini-1.5-flash-8b-001",
791
+ "gemini-1.5-flash-8b-latest"
792
+ ].map((id) => ({
793
+ id,
794
+ cost: {
795
+ input: .0375 / 1e6,
796
+ output: .15 / 1e6
797
+ },
798
+ tieredCost: {
799
+ threshold: 128e3,
800
+ above: {
801
+ input: .075 / 1e6,
802
+ output: .3 / 1e6
803
+ }
804
+ }
805
+ })),
806
+ ...[
807
+ "gemini-1.0-pro",
808
+ "gemini-1.0-pro-001",
809
+ "gemini-1.0-pro-002",
810
+ "gemini-1.0-pro-vision",
811
+ "gemini-1.0-pro-vision-001"
812
+ ].map((id) => ({
813
+ id,
814
+ cost: {
815
+ input: .5 / 1e6,
816
+ output: 1.5 / 1e6
817
+ }
818
+ })),
819
+ {
820
+ id: "gemini-pro",
821
+ cost: {
822
+ input: .5 / 1e6,
823
+ output: 1.5 / 1e6
824
+ }
825
+ },
826
+ {
827
+ id: "gemini-pro-vision",
828
+ cost: {
829
+ input: .5 / 1e6,
830
+ output: 1.5 / 1e6
831
+ }
832
+ },
833
+ {
834
+ id: "gemini-robotics-er-1.5-preview",
835
+ cost: {
836
+ input: .3 / 1e6,
837
+ output: 2.5 / 1e6
838
+ }
839
+ },
840
+ {
841
+ id: "gemini-embedding-001",
842
+ cost: {
843
+ input: .15 / 1e6,
844
+ output: 0
845
+ }
846
+ },
847
+ { id: "aqa" },
848
+ { id: "chat-bison" },
849
+ { id: "chat-bison-32k" },
850
+ { id: "chat-bison-32k@001" },
851
+ { id: "chat-bison-32k@002" },
852
+ { id: "chat-bison@001" },
853
+ { id: "chat-bison@002" },
854
+ { id: "codechat-bison" },
855
+ { id: "codechat-bison-32k" },
856
+ { id: "codechat-bison-32k@001" },
857
+ { id: "codechat-bison-32k@002" },
858
+ { id: "codechat-bison@001" },
859
+ { id: "codechat-bison@002" },
860
+ { id: "gemini-ultra" },
861
+ { id: "gemma" },
862
+ { id: "codegemma" },
863
+ { id: "paligemma" },
864
+ { id: "medlm-medium" },
865
+ { id: "medlm-large" }
866
+ ];
867
+ /**
868
+ * List of chat model IDs for backwards compatibility.
869
+ * Used for model validation in ai.studio.ts.
870
+ */
871
+ const CHAT_MODELS = GOOGLE_MODELS.map((m) => m.id);
872
+ //#endregion
873
+ //#region src/providers/google/types.ts
874
+ const VALID_SCHEMA_TYPES = [
875
+ "TYPE_UNSPECIFIED",
876
+ "STRING",
877
+ "NUMBER",
878
+ "INTEGER",
879
+ "BOOLEAN",
880
+ "ARRAY",
881
+ "OBJECT"
882
+ ];
883
+ //#endregion
884
+ //#region src/providers/google/util.ts
885
+ /**
886
+ * Normalizes safety settings to use the correct Google API field name `threshold`.
887
+ * Accepts the legacy `probability` field for backwards compatibility and maps it to `threshold`.
888
+ */
889
+ function normalizeSafetySettings(safetySettings) {
890
+ if (!safetySettings) return;
891
+ return safetySettings.map(({ category, threshold, probability }) => ({
892
+ category,
893
+ threshold: threshold || probability || ""
894
+ }));
895
+ }
896
+ /**
897
+ * Calculates the cost for a Google API call.
898
+ *
899
+ * Handles tiered pricing for models where cost varies by prompt size.
900
+ * For example, Gemini Pro models have higher rates for prompts >200k tokens.
901
+ * Some models (e.g. Gemini 2.0 Flash) have different pricing on Vertex AI.
902
+ *
903
+ * @param modelName - The name of the model used
904
+ * @param config - Provider configuration (may contain custom cost override)
905
+ * @param promptTokens - Number of tokens in the prompt
906
+ * @param completionTokens - Number of tokens in the completion
907
+ * @param isVertexMode - Whether the call was made via Vertex AI (uses Vertex pricing when available)
908
+ * @returns The calculated cost in dollars, or undefined if it cannot be calculated
909
+ */
910
+ function calculateGoogleCost(modelName, config, promptTokens, completionTokens, isVertexMode) {
911
+ const model = GOOGLE_MODELS.find((m) => m.id === modelName);
912
+ if (promptTokens != null && completionTokens != null) {
913
+ if (model?.tieredCost && promptTokens > model.tieredCost.threshold) {
914
+ const inputCost = config.cost ?? model.tieredCost.above.input;
915
+ const outputCost = config.cost ?? model.tieredCost.above.output;
916
+ return inputCost * promptTokens + outputCost * completionTokens;
917
+ }
918
+ if (isVertexMode && model?.vertexCost) {
919
+ const inputCost = config.cost ?? model.vertexCost.input;
920
+ const outputCost = config.cost ?? model.vertexCost.output;
921
+ return inputCost * promptTokens + outputCost * completionTokens;
922
+ }
923
+ }
924
+ return require_fetch.calculateCost(modelName, config, promptTokens, completionTokens, GOOGLE_MODELS);
925
+ }
926
+ const ajv = require_logger.getAjv();
927
+ ajv.addKeyword("property_ordering");
928
+ const clone = (0, rfdc.default)();
929
+ const PartSchema = zod.z.object({
930
+ text: zod.z.string().optional(),
931
+ inline_data: zod.z.object({
932
+ mime_type: zod.z.string(),
933
+ data: zod.z.string()
934
+ }).optional()
935
+ });
936
+ const ContentSchema = zod.z.object({
937
+ role: zod.z.enum(["user", "model"]).optional(),
938
+ parts: zod.z.array(PartSchema)
939
+ });
940
+ const GeminiFormatSchema = zod.z.array(ContentSchema);
941
+ function maybeCoerceToGeminiFormat(contents, options) {
942
+ let coerced = false;
943
+ const parseResult = GeminiFormatSchema.safeParse(contents);
944
+ if (parseResult.success) {
945
+ let systemInst = void 0;
946
+ if (typeof contents === "object" && "system_instruction" in contents) {
947
+ systemInst = contents.system_instruction;
948
+ coerced = true;
949
+ }
950
+ return {
951
+ contents: parseResult.data,
952
+ coerced,
953
+ systemInstruction: systemInst
954
+ };
955
+ }
956
+ let coercedContents;
957
+ if (typeof contents === "object" && contents !== null && !Array.isArray(contents) && "system_instruction" in contents) {
958
+ const systemInst = contents.system_instruction;
959
+ if ("contents" in contents) coercedContents = contents.contents;
960
+ else coercedContents = [];
961
+ return {
962
+ contents: coercedContents,
963
+ coerced: true,
964
+ systemInstruction: systemInst
965
+ };
966
+ }
967
+ if (typeof contents === "string") {
968
+ coercedContents = [{ parts: [{ text: contents }] }];
969
+ coerced = true;
970
+ } else if (Array.isArray(contents) && contents.every((item) => typeof item.content === "string")) {
971
+ const targetRole = options?.useAssistantRole ? "assistant" : "model";
972
+ coercedContents = contents.map((item) => ({
973
+ role: item.role === "assistant" ? targetRole : item.role,
974
+ parts: [{ text: item.content }]
975
+ }));
976
+ coerced = true;
977
+ } else if (Array.isArray(contents) && contents.every((item) => item.role && item.content)) {
978
+ const targetRole = options?.useAssistantRole ? "assistant" : "model";
979
+ coercedContents = contents.map((item) => {
980
+ const mappedRole = item.role === "assistant" ? targetRole : item.role;
981
+ if (Array.isArray(item.content)) return {
982
+ role: mappedRole,
983
+ parts: item.content.map((contentItem) => {
984
+ if (typeof contentItem === "string") return { text: contentItem };
985
+ else if (contentItem.type === "text") return { text: contentItem.text };
986
+ else return contentItem;
987
+ })
988
+ };
989
+ else if (typeof item.content === "object") return {
990
+ role: mappedRole,
991
+ parts: [item.content]
992
+ };
993
+ else return {
994
+ role: mappedRole,
995
+ parts: [{ text: item.content }]
996
+ };
997
+ });
998
+ coerced = true;
999
+ } else if (typeof contents === "object" && contents !== null && "parts" in contents) {
1000
+ coercedContents = [contents];
1001
+ coerced = true;
1002
+ } else {
1003
+ require_logger.logger.warn(`Unknown format for Gemini: ${JSON.stringify(contents)}`);
1004
+ return {
1005
+ contents: Array.isArray(contents) ? contents : [],
1006
+ coerced: false,
1007
+ systemInstruction: void 0
1008
+ };
1009
+ }
1010
+ let systemPromptParts = [];
1011
+ coercedContents = coercedContents.filter((message) => {
1012
+ if (message.role === "system" && message.parts.length > 0) {
1013
+ systemPromptParts.push(...message.parts.filter((part) => "text" in part && typeof part.text === "string"));
1014
+ return false;
1015
+ }
1016
+ return true;
1017
+ });
1018
+ if (coercedContents.length === 0 && systemPromptParts.length > 0) {
1019
+ coercedContents = [{
1020
+ role: "user",
1021
+ parts: systemPromptParts
1022
+ }];
1023
+ coerced = true;
1024
+ systemPromptParts = [];
1025
+ }
1026
+ return {
1027
+ contents: coercedContents,
1028
+ coerced,
1029
+ systemInstruction: systemPromptParts.length > 0 ? { parts: systemPromptParts } : void 0
1030
+ };
1031
+ }
1032
+ let cachedGenerativeLanguageAuth = null;
1033
+ /**
1034
+ * Gets an OAuth2 access token for Google APIs.
1035
+ * Used by providers that need to authenticate via OAuth2 instead of API keys.
1036
+ * @param credentials - Optional credentials JSON string or file:// path
1037
+ * @param scopes - Optional scopes to use. Defaults to cloud-platform + generative-language scopes
1038
+ * @returns The access token string, or undefined if authentication fails
1039
+ */
1040
+ async function getGoogleAccessToken(credentials) {
1041
+ try {
1042
+ if (!cachedGenerativeLanguageAuth) {
1043
+ let GoogleAuth;
1044
+ try {
1045
+ GoogleAuth = (await import("google-auth-library")).GoogleAuth;
1046
+ cachedGenerativeLanguageAuth = new GoogleAuth({ scopes: [
1047
+ "https://www.googleapis.com/auth/cloud-platform",
1048
+ "https://www.googleapis.com/auth/generative-language.retriever",
1049
+ "https://www.googleapis.com/auth/generative-language.tuning"
1050
+ ] });
1051
+ } catch {
1052
+ throw new Error("The google-auth-library package is required as a peer dependency. Please install it in your project or globally.");
1053
+ }
1054
+ }
1055
+ const processedCredentials = loadCredentials(credentials);
1056
+ let client;
1057
+ if (processedCredentials) client = await cachedGenerativeLanguageAuth.fromJSON(JSON.parse(processedCredentials));
1058
+ else client = await cachedGenerativeLanguageAuth.getClient();
1059
+ return (await client.getAccessToken()).token || void 0;
1060
+ } catch (error) {
1061
+ require_logger.logger.debug("[GoogleAuth] Could not get access token", { error: error instanceof Error ? error.message : String(error) });
1062
+ return;
1063
+ }
1064
+ }
1065
+ function getCandidate(data) {
1066
+ if (!data || !data.candidates || data.candidates.length < 1) {
1067
+ let errorDetails = "No candidates returned in API response.";
1068
+ if (data?.promptFeedback?.blockReason) {
1069
+ errorDetails = `Response blocked: ${data.promptFeedback.blockReason}`;
1070
+ if (data.promptFeedback.safetyRatings) {
1071
+ const flaggedCategories = data.promptFeedback.safetyRatings.filter((rating) => rating.probability !== "NEGLIGIBLE").map((rating) => `${rating.category}: ${rating.probability}`);
1072
+ if (flaggedCategories.length > 0) errorDetails += ` (Safety ratings: ${flaggedCategories.join(", ")})`;
1073
+ }
1074
+ } else if (data?.promptFeedback?.safetyRatings) {
1075
+ const flaggedCategories = data.promptFeedback.safetyRatings.filter((rating) => rating.probability !== "NEGLIGIBLE").map((rating) => `${rating.category}: ${rating.probability}`);
1076
+ if (flaggedCategories.length > 0) errorDetails = `Response may have been blocked due to safety filters: ${flaggedCategories.join(", ")}`;
1077
+ }
1078
+ errorDetails += `\n\nGot response: ${JSON.stringify(data)}`;
1079
+ throw new Error(errorDetails);
1080
+ }
1081
+ if (data.candidates.length > 1) require_logger.logger.debug(`Expected one candidate in AI Studio API response, but got ${data.candidates.length}: ${JSON.stringify(data)}`);
1082
+ return data.candidates[0];
1083
+ }
1084
+ function formatCandidateContents(candidate) {
1085
+ if (candidate.finishReason && [
1086
+ "SAFETY",
1087
+ "RECITATION",
1088
+ "PROHIBITED_CONTENT",
1089
+ "BLOCKLIST",
1090
+ "SPII"
1091
+ ].includes(candidate.finishReason)) {
1092
+ let errorMessage = `Response was blocked with finish reason: ${candidate.finishReason}`;
1093
+ if (candidate.safetyRatings) {
1094
+ const flaggedCategories = candidate.safetyRatings.filter((rating) => rating.probability !== "NEGLIGIBLE" || rating.blocked).map((rating) => `${rating.category}: ${rating.probability}${rating.blocked ? " (BLOCKED)" : ""}`);
1095
+ if (flaggedCategories.length > 0) errorMessage += `\nSafety ratings: ${flaggedCategories.join(", ")}`;
1096
+ }
1097
+ if (candidate.finishReason === "RECITATION") errorMessage += "\n\nThis typically occurs when the response is too similar to content from the model's training data.";
1098
+ else if (candidate.finishReason === "SAFETY") errorMessage += "\n\nThe response was blocked due to safety filters. Consider adjusting safety settings or modifying your prompt.";
1099
+ throw new Error(errorMessage);
1100
+ }
1101
+ if (candidate.content?.parts) {
1102
+ let output = "";
1103
+ let is_text = true;
1104
+ for (const part of candidate.content.parts) if ("text" in part) output += part.text;
1105
+ else is_text = false;
1106
+ if (is_text) return output;
1107
+ else return candidate.content.parts;
1108
+ } else throw new Error(`No output found in response: ${JSON.stringify(candidate)}`);
1109
+ }
1110
+ function mergeParts(parts1, parts2) {
1111
+ if (parts1 === void 0) return parts2;
1112
+ if (typeof parts1 === "string" && typeof parts2 === "string") return parts1 + parts2;
1113
+ const array1 = typeof parts1 === "string" ? [{ text: parts1 }] : parts1;
1114
+ const array2 = typeof parts2 === "string" ? [{ text: parts2 }] : parts2;
1115
+ array1.push(...array2);
1116
+ return array1;
1117
+ }
1118
+ /**
1119
+ * Normalizes and sanitizes tools configuration for Gemini API compatibility.
1120
+ * - Handles snake_case to camelCase conversion for backwards compatibility
1121
+ * - Sanitizes function declaration schemas to remove unsupported JSON Schema properties
1122
+ * (e.g., additionalProperties, $schema, default) that Gemini doesn't support
1123
+ */
1124
+ function normalizeTools(tools) {
1125
+ return tools.map((tool) => {
1126
+ const normalizedTool = { ...tool };
1127
+ if (tool.google_search && !normalizedTool.googleSearch) normalizedTool.googleSearch = tool.google_search;
1128
+ if (tool.code_execution && !normalizedTool.codeExecution) normalizedTool.codeExecution = tool.code_execution;
1129
+ if (tool.google_search_retrieval && !normalizedTool.googleSearchRetrieval) normalizedTool.googleSearchRetrieval = tool.google_search_retrieval;
1130
+ if (normalizedTool.functionDeclarations) normalizedTool.functionDeclarations = normalizedTool.functionDeclarations.map((fd) => ({
1131
+ ...fd,
1132
+ parameters: fd.parameters ? sanitizeSchemaForGemini(fd.parameters) : void 0
1133
+ }));
1134
+ return normalizedTool;
1135
+ });
1136
+ }
1137
+ function loadFile(config_var, context_vars) {
1138
+ const fileContents = require_util.maybeLoadFromExternalFile(require_util.renderVarsInObject(config_var, context_vars));
1139
+ if (typeof fileContents === "string") try {
1140
+ const parsedContents = JSON.parse(fileContents);
1141
+ return Array.isArray(parsedContents) ? normalizeTools(parsedContents) : parsedContents;
1142
+ } catch (err) {
1143
+ require_logger.logger.debug(`ERROR: failed to convert file contents to JSON:\n${JSON.stringify(err)}`);
1144
+ return fileContents;
1145
+ }
1146
+ if (Array.isArray(fileContents)) return normalizeTools(fileContents);
1147
+ return fileContents;
1148
+ }
1149
+ function isValidBase64Image(data) {
1150
+ const base64Data = isDataUrl(data) ? extractBase64FromDataUrl(data) : data;
1151
+ if (!base64Data || base64Data.length < 20) return false;
1152
+ try {
1153
+ Buffer.from(base64Data, "base64");
1154
+ return base64Data.startsWith("/9j/") || base64Data.startsWith("iVBORw0KGgo") || base64Data.startsWith("R0lGODlh") || base64Data.startsWith("R0lGODdh") || base64Data.startsWith("UklGR") || base64Data.startsWith("Qk0") || base64Data.startsWith("Qk1") || base64Data.startsWith("SUkq") || base64Data.startsWith("TU0A") || base64Data.startsWith("AAABAA");
1155
+ } catch {
1156
+ return false;
1157
+ }
1158
+ }
1159
+ function getMimeTypeFromBase64(base64DataOrUrl) {
1160
+ const parsed = parseDataUrl(base64DataOrUrl);
1161
+ if (parsed) return parsed.mimeType;
1162
+ const base64Data = extractBase64FromDataUrl(base64DataOrUrl);
1163
+ if (base64Data.startsWith("/9j/")) return "image/jpeg";
1164
+ else if (base64Data.startsWith("iVBORw0KGgo")) return "image/png";
1165
+ else if (base64Data.startsWith("R0lGODlh") || base64Data.startsWith("R0lGODdh")) return "image/gif";
1166
+ else if (base64Data.startsWith("UklGR")) return "image/webp";
1167
+ else if (base64Data.startsWith("Qk0") || base64Data.startsWith("Qk1")) return "image/bmp";
1168
+ else if (base64Data.startsWith("SUkq") || base64Data.startsWith("TU0A")) return "image/tiff";
1169
+ else if (base64Data.startsWith("AAABAA")) return "image/x-icon";
1170
+ return "image/jpeg";
1171
+ }
1172
+ function processImagesInContents(contents, contextVars) {
1173
+ if (!contextVars) return contents;
1174
+ if (!Array.isArray(contents)) {
1175
+ require_logger.logger.warn("[Google] contents is not an array in processImagesInContents", {
1176
+ contentsType: typeof contents,
1177
+ contentsValue: contents
1178
+ });
1179
+ return [];
1180
+ }
1181
+ const base64ToVarName = /* @__PURE__ */ new Map();
1182
+ for (const [varName, value] of Object.entries(contextVars)) if (typeof value === "string" && isValidBase64Image(value)) base64ToVarName.set(value, varName);
1183
+ return contents.map((content) => {
1184
+ if (content.parts) {
1185
+ const newParts = [];
1186
+ for (const part of content.parts) if (part.text) {
1187
+ const lines = part.text.split("\n");
1188
+ let foundValidImage = false;
1189
+ let currentTextBlock = "";
1190
+ const processedParts = [];
1191
+ for (const line of lines) {
1192
+ const trimmedLine = line.trim();
1193
+ if (base64ToVarName.has(trimmedLine) && isValidBase64Image(trimmedLine)) {
1194
+ foundValidImage = true;
1195
+ if (currentTextBlock.length > 0) {
1196
+ processedParts.push({ text: currentTextBlock });
1197
+ currentTextBlock = "";
1198
+ }
1199
+ const mimeType = getMimeTypeFromBase64(trimmedLine);
1200
+ const base64Data = isDataUrl(trimmedLine) ? extractBase64FromDataUrl(trimmedLine) : trimmedLine;
1201
+ processedParts.push({ inlineData: {
1202
+ mimeType,
1203
+ data: base64Data
1204
+ } });
1205
+ } else {
1206
+ if (currentTextBlock.length > 0) currentTextBlock += "\n";
1207
+ currentTextBlock += line;
1208
+ }
1209
+ }
1210
+ if (currentTextBlock.length > 0) processedParts.push({ text: currentTextBlock });
1211
+ if (foundValidImage) newParts.push(...processedParts);
1212
+ else newParts.push(part);
1213
+ } else newParts.push(part);
1214
+ return {
1215
+ ...content,
1216
+ parts: newParts
1217
+ };
1218
+ }
1219
+ return content;
1220
+ });
1221
+ }
1222
+ /**
1223
+ * Parses and processes config-level systemInstruction.
1224
+ * Handles file loading, string-to-Content conversion, and Nunjucks template rendering.
1225
+ *
1226
+ * @param configSystemInstruction - The systemInstruction from config (can be string, Content, or undefined)
1227
+ * @param contextVars - Variables for Nunjucks template rendering
1228
+ * @returns Processed Content object or undefined
1229
+ */
1230
+ function parseConfigSystemInstruction(configSystemInstruction, contextVars) {
1231
+ if (!configSystemInstruction) return;
1232
+ let configInstruction = clone(configSystemInstruction);
1233
+ if (typeof configSystemInstruction === "string") configInstruction = loadFile(configSystemInstruction, contextVars);
1234
+ if (typeof configInstruction === "string") configInstruction = { parts: [{ text: configInstruction }] };
1235
+ if (contextVars && configInstruction) {
1236
+ const nunjucks = require_util.getNunjucksEngine();
1237
+ for (const part of configInstruction.parts) if (part.text) try {
1238
+ part.text = nunjucks.renderString(part.text, contextVars);
1239
+ } catch (err) {
1240
+ throw new Error(`Unable to render nunjucks in systemInstruction: ${err}`);
1241
+ }
1242
+ }
1243
+ return configInstruction;
1244
+ }
1245
+ function geminiFormatAndSystemInstructions(prompt, contextVars, configSystemInstruction, options) {
1246
+ let contents = require_fetch.parseChatPrompt(prompt, [{
1247
+ parts: [{ text: prompt }],
1248
+ role: "user"
1249
+ }]);
1250
+ const { contents: updatedContents, coerced, systemInstruction: parsedSystemInstruction } = maybeCoerceToGeminiFormat(contents, options);
1251
+ if (coerced) {
1252
+ require_logger.logger.debug(`Coerced JSON prompt to Gemini format: ${JSON.stringify(contents)}`);
1253
+ contents = updatedContents;
1254
+ }
1255
+ let systemInstruction = parsedSystemInstruction;
1256
+ const parsedConfigInstruction = parseConfigSystemInstruction(configSystemInstruction, contextVars);
1257
+ if (parsedConfigInstruction) systemInstruction = systemInstruction ? { parts: [...parsedConfigInstruction.parts, ...systemInstruction.parts] } : parsedConfigInstruction;
1258
+ contents = processImagesInContents(contents, contextVars);
1259
+ return {
1260
+ contents,
1261
+ systemInstruction
1262
+ };
1263
+ }
1264
+ /**
1265
+ * Recursively traverses a JSON schema object and converts
1266
+ * uppercase type keywords (string values) to lowercase.
1267
+ * Handles nested objects and arrays within the schema.
1268
+ * Creates a deep copy to avoid modifying the original schema.
1269
+ *
1270
+ * @param {object | any} schemaNode - The current node (object or value) being processed.
1271
+ * @returns {object | any} - The processed node with type keywords lowercased.
1272
+ */
1273
+ function normalizeSchemaTypes(schemaNode) {
1274
+ if (typeof schemaNode !== "object" || schemaNode === null) return schemaNode;
1275
+ if (Array.isArray(schemaNode)) return schemaNode.map(normalizeSchemaTypes);
1276
+ const newNode = {};
1277
+ for (const key in schemaNode) if (Object.prototype.hasOwnProperty.call(schemaNode, key)) {
1278
+ const value = schemaNode[key];
1279
+ if (key === "type") if (typeof value === "string" && VALID_SCHEMA_TYPES.includes(value)) newNode[key] = value.toLowerCase();
1280
+ else if (Array.isArray(value)) newNode[key] = value.map((t) => typeof t === "string" && VALID_SCHEMA_TYPES.includes(t) ? t.toLowerCase() : t);
1281
+ else newNode[key] = normalizeSchemaTypes(value);
1282
+ else newNode[key] = normalizeSchemaTypes(value);
1283
+ }
1284
+ return newNode;
1285
+ }
1286
+ function parseStringObject(input) {
1287
+ if (typeof input === "string") return JSON.parse(input);
1288
+ return input;
1289
+ }
1290
+ function validateFunctionCall(output, functions, vars) {
1291
+ let functionCalls;
1292
+ try {
1293
+ let parsedOutput = parseStringObject(output);
1294
+ if ("toolCall" in parsedOutput) {
1295
+ parsedOutput = parsedOutput.toolCall;
1296
+ functionCalls = parsedOutput.functionCalls;
1297
+ } else if (Array.isArray(parsedOutput)) functionCalls = parsedOutput.filter((obj) => Object.prototype.hasOwnProperty.call(obj, "functionCall")).map((obj) => obj.functionCall);
1298
+ else throw new Error("Unrecognized function call format");
1299
+ } catch {
1300
+ throw new Error(`Google did not return a valid-looking function call: ${JSON.stringify(output)}`);
1301
+ }
1302
+ const interpolatedFunctions = loadFile(functions, vars);
1303
+ for (const functionCall of functionCalls) {
1304
+ const functionName = functionCall.name;
1305
+ const functionArgs = parseStringObject(functionCall.args);
1306
+ const functionSchema = (interpolatedFunctions?.find((f) => "functionDeclarations" in f))?.functionDeclarations?.find((f) => f.name === functionName);
1307
+ if (!functionSchema) throw new Error(`Called "${functionName}", but there is no function with that name`);
1308
+ if (Object.keys(functionArgs).length !== 0 && functionSchema?.parameters) {
1309
+ const parameterSchema = normalizeSchemaTypes(functionSchema.parameters);
1310
+ let validate;
1311
+ try {
1312
+ validate = ajv.compile(parameterSchema);
1313
+ } catch (err) {
1314
+ throw new Error(`Tool schema doesn't compile with ajv: ${err}. If this is a valid tool schema you may need to reformulate your assertion without is-valid-function-call.`);
1315
+ }
1316
+ if (!validate(functionArgs)) throw new Error(`Call to "${functionName}":\n${JSON.stringify(functionCall)}\ndoes not match schema:\n${JSON.stringify(validate.errors)}`);
1317
+ } else if (!(JSON.stringify(functionArgs) === "{}" && !functionSchema?.parameters)) throw new Error(`Call to "${functionName}":\n${JSON.stringify(functionCall)}\ndoes not match schema:\n${JSON.stringify(functionSchema)}`);
1318
+ }
1319
+ }
1320
+ /**
1321
+ * Properties supported by Gemini's function calling API.
1322
+ * Based on Google's Schema type definition and API documentation.
1323
+ * @see https://ai.google.dev/api/caching#Schema
1324
+ */
1325
+ const GEMINI_SUPPORTED_SCHEMA_PROPERTIES = new Set([
1326
+ "type",
1327
+ "format",
1328
+ "description",
1329
+ "nullable",
1330
+ "enum",
1331
+ "maxItems",
1332
+ "minItems",
1333
+ "properties",
1334
+ "required",
1335
+ "propertyOrdering",
1336
+ "items"
1337
+ ]);
1338
+ /**
1339
+ * Valid JSON Schema types mapped to Gemini's expected format (uppercase).
1340
+ */
1341
+ const JSON_SCHEMA_TYPE_MAP = {
1342
+ string: "STRING",
1343
+ number: "NUMBER",
1344
+ integer: "INTEGER",
1345
+ boolean: "BOOLEAN",
1346
+ array: "ARRAY",
1347
+ object: "OBJECT",
1348
+ null: "STRING"
1349
+ };
1350
+ /**
1351
+ * Recursively sanitizes a JSON Schema for Gemini API compatibility.
1352
+ *
1353
+ * - Removes unsupported properties (additionalProperties, $schema, default, title, etc.)
1354
+ * - Converts type values to uppercase (string → STRING, object → OBJECT)
1355
+ * - Recursively processes nested schemas in 'properties' and 'items'
1356
+ *
1357
+ * @param schema - The JSON Schema object to sanitize
1358
+ * @returns A sanitized schema compatible with Gemini's function calling API
1359
+ */
1360
+ function sanitizeSchemaForGemini(schema) {
1361
+ if (!schema || typeof schema !== "object") return schema;
1362
+ const result = {};
1363
+ for (const [key, value] of Object.entries(schema)) {
1364
+ if (!GEMINI_SUPPORTED_SCHEMA_PROPERTIES.has(key)) continue;
1365
+ if (key === "type") if (typeof value === "string") result[key] = JSON_SCHEMA_TYPE_MAP[value.toLowerCase()] || value.toUpperCase();
1366
+ else result[key] = value;
1367
+ else if (key === "properties" && typeof value === "object" && value !== null) {
1368
+ result[key] = {};
1369
+ for (const [propName, propSchema] of Object.entries(value)) if (typeof propSchema === "object" && propSchema !== null) result[key][propName] = sanitizeSchemaForGemini(propSchema);
1370
+ else result[key][propName] = propSchema;
1371
+ } else if (key === "items" && typeof value === "object" && value !== null) result[key] = sanitizeSchemaForGemini(value);
1372
+ else result[key] = value;
1373
+ }
1374
+ return result;
1375
+ }
1376
+ /**
1377
+ * Create a cache discriminator from auth headers.
1378
+ *
1379
+ * This is used to ensure different API keys/credentials don't share cached responses.
1380
+ * The discriminator is included as a custom property in fetchWithCache options,
1381
+ * which gets included in the cache key automatically.
1382
+ *
1383
+ * Security note: We hash auth headers rather than using them directly to avoid
1384
+ * exposing sensitive credentials in cache keys or logs. The hash is truncated
1385
+ * to 16 hex characters (64 bits) for brevity - collision probability is acceptably
1386
+ * low for cache key differentiation (birthday problem: ~4 billion entries needed
1387
+ * for 50% collision probability).
1388
+ *
1389
+ * @param headers - Request headers containing auth info
1390
+ * @returns A short hash string for cache key differentiation
1391
+ */
1392
+ function createAuthCacheDiscriminator(headers) {
1393
+ const authValues = [];
1394
+ for (const name of [
1395
+ "authorization",
1396
+ "x-goog-api-key",
1397
+ "x-api-key",
1398
+ "api-key",
1399
+ "x-goog-user-project"
1400
+ ]) {
1401
+ const value = headers[name] || headers[name.toLowerCase()];
1402
+ if (value) authValues.push(`${name}:${value}`);
1403
+ }
1404
+ if (authValues.length === 0) return "";
1405
+ return crypto.default.createHash("sha256").update(authValues.join("|")).digest("hex").substring(0, 16);
1406
+ }
1407
+ //#endregion
1408
+ //#region src/providers/mcp/transform.ts
1409
+ function transformMCPToolsToOpenAi(tools) {
1410
+ return tools.map((tool) => {
1411
+ const schema = tool.inputSchema;
1412
+ let properties = {};
1413
+ let required = void 0;
1414
+ let additionalProperties = void 0;
1415
+ if (schema && typeof schema === "object" && "properties" in schema) {
1416
+ properties = schema.properties ?? {};
1417
+ required = schema.required;
1418
+ if ("additionalProperties" in schema) additionalProperties = schema.additionalProperties;
1419
+ } else if (schema && typeof schema === "object") properties = {};
1420
+ else properties = {};
1421
+ return {
1422
+ type: "function",
1423
+ function: {
1424
+ name: tool.name,
1425
+ description: tool.description,
1426
+ parameters: {
1427
+ type: "object",
1428
+ properties,
1429
+ ...required && required.length > 0 ? { required } : {},
1430
+ ...additionalProperties === void 0 ? {} : { additionalProperties }
1431
+ }
1432
+ }
1433
+ };
1434
+ });
1435
+ }
1436
+ function transformMCPToolsToAnthropic(tools) {
1437
+ return tools.map((tool) => {
1438
+ const { $schema: _$schema, ...cleanSchema } = tool.inputSchema;
1439
+ return {
1440
+ name: tool.name,
1441
+ description: tool.description,
1442
+ input_schema: {
1443
+ type: "object",
1444
+ ...cleanSchema
1445
+ }
1446
+ };
1447
+ });
1448
+ }
1449
+ function transformMCPToolsToGoogle(tools) {
1450
+ return [{ functionDeclarations: tools.map((tool) => {
1451
+ const schema = tool.inputSchema;
1452
+ let parameters;
1453
+ if (schema && typeof schema === "object") {
1454
+ parameters = sanitizeSchemaForGemini(schema);
1455
+ if (!parameters.type) parameters.type = "OBJECT";
1456
+ if (!parameters.properties) parameters.properties = {};
1457
+ } else parameters = {
1458
+ type: "OBJECT",
1459
+ properties: {}
1460
+ };
1461
+ return {
1462
+ name: tool.name,
1463
+ description: tool.description,
1464
+ parameters
1465
+ };
1466
+ }) }];
1467
+ }
1468
+ async function transformMCPConfigToClaudeCode(config) {
1469
+ const serverConfigs = config.servers ?? [];
1470
+ if (config.server) serverConfigs.push(config.server);
1471
+ return (await Promise.all(serverConfigs.map((server) => transformMCPServerConfigToClaudeCode(server)))).reduce((acc, transformed) => {
1472
+ const [key, out] = transformed;
1473
+ acc[key] = out;
1474
+ return acc;
1475
+ }, {});
1476
+ }
1477
+ async function transformMCPServerConfigToClaudeCode(config) {
1478
+ const key = config.name ?? config.url ?? config.command ?? "default";
1479
+ let out;
1480
+ if (config.url) {
1481
+ const renderedConfig = renderAuthVars(config);
1482
+ let oauthToken;
1483
+ if (requiresAsyncAuth(renderedConfig) && renderedConfig.auth?.type === "oauth") oauthToken = await getOAuthToken(renderedConfig.auth);
1484
+ const queryParams = getAuthQueryParams(renderedConfig);
1485
+ out = {
1486
+ type: "http",
1487
+ url: applyQueryParams(config.url, queryParams),
1488
+ headers: {
1489
+ ...config.headers ?? {},
1490
+ ...getAuthHeaders(renderedConfig, oauthToken)
1491
+ }
1492
+ };
1493
+ } else if (config.command && config.args) out = {
1494
+ type: "stdio",
1495
+ command: config.command,
1496
+ args: config.args
1497
+ };
1498
+ else if (config.path) out = {
1499
+ type: "stdio",
1500
+ command: config.path.endsWith(".py") ? process.platform === "win32" ? "python" : "python3" : process.execPath,
1501
+ args: [config.path]
1502
+ };
1503
+ else throw new Error("MCP configuration cannot be converted to Claude Agent SDK MCP server config");
1504
+ return [key, out];
1505
+ }
1506
+ //#endregion
1507
+ Object.defineProperty(exports, "CHAT_MODELS", {
1508
+ enumerable: true,
1509
+ get: function() {
1510
+ return CHAT_MODELS;
1511
+ }
1512
+ });
1513
+ Object.defineProperty(exports, "GoogleAuthManager", {
1514
+ enumerable: true,
1515
+ get: function() {
1516
+ return GoogleAuthManager;
1517
+ }
1518
+ });
1519
+ Object.defineProperty(exports, "TOKEN_REFRESH_BUFFER_MS", {
1520
+ enumerable: true,
1521
+ get: function() {
1522
+ return TOKEN_REFRESH_BUFFER_MS;
1523
+ }
1524
+ });
1525
+ Object.defineProperty(exports, "applyQueryParams", {
1526
+ enumerable: true,
1527
+ get: function() {
1528
+ return applyQueryParams;
1529
+ }
1530
+ });
1531
+ Object.defineProperty(exports, "calculateGoogleCost", {
1532
+ enumerable: true,
1533
+ get: function() {
1534
+ return calculateGoogleCost;
1535
+ }
1536
+ });
1537
+ Object.defineProperty(exports, "createAuthCacheDiscriminator", {
1538
+ enumerable: true,
1539
+ get: function() {
1540
+ return createAuthCacheDiscriminator;
1541
+ }
1542
+ });
1543
+ Object.defineProperty(exports, "determineGoogleVertexMode", {
1544
+ enumerable: true,
1545
+ get: function() {
1546
+ return determineGoogleVertexMode;
1547
+ }
1548
+ });
1549
+ Object.defineProperty(exports, "formatCandidateContents", {
1550
+ enumerable: true,
1551
+ get: function() {
1552
+ return formatCandidateContents;
1553
+ }
1554
+ });
1555
+ Object.defineProperty(exports, "geminiFormatAndSystemInstructions", {
1556
+ enumerable: true,
1557
+ get: function() {
1558
+ return geminiFormatAndSystemInstructions;
1559
+ }
1560
+ });
1561
+ Object.defineProperty(exports, "getAuthHeaders", {
1562
+ enumerable: true,
1563
+ get: function() {
1564
+ return getAuthHeaders;
1565
+ }
1566
+ });
1567
+ Object.defineProperty(exports, "getAuthQueryParams", {
1568
+ enumerable: true,
1569
+ get: function() {
1570
+ return getAuthQueryParams;
1571
+ }
1572
+ });
1573
+ Object.defineProperty(exports, "getCandidate", {
1574
+ enumerable: true,
1575
+ get: function() {
1576
+ return getCandidate;
1577
+ }
1578
+ });
1579
+ Object.defineProperty(exports, "getGoogleAccessToken", {
1580
+ enumerable: true,
1581
+ get: function() {
1582
+ return getGoogleAccessToken;
1583
+ }
1584
+ });
1585
+ Object.defineProperty(exports, "getGoogleApiKey", {
1586
+ enumerable: true,
1587
+ get: function() {
1588
+ return getGoogleApiKey;
1589
+ }
1590
+ });
1591
+ Object.defineProperty(exports, "getGoogleClient", {
1592
+ enumerable: true,
1593
+ get: function() {
1594
+ return getGoogleClient;
1595
+ }
1596
+ });
1597
+ Object.defineProperty(exports, "getOAuthTokenWithExpiry", {
1598
+ enumerable: true,
1599
+ get: function() {
1600
+ return getOAuthTokenWithExpiry;
1601
+ }
1602
+ });
1603
+ Object.defineProperty(exports, "hasGoogleDefaultCredentials", {
1604
+ enumerable: true,
1605
+ get: function() {
1606
+ return hasGoogleDefaultCredentials;
1607
+ }
1608
+ });
1609
+ Object.defineProperty(exports, "loadCredentials", {
1610
+ enumerable: true,
1611
+ get: function() {
1612
+ return loadCredentials;
1613
+ }
1614
+ });
1615
+ Object.defineProperty(exports, "mergeParts", {
1616
+ enumerable: true,
1617
+ get: function() {
1618
+ return mergeParts;
1619
+ }
1620
+ });
1621
+ Object.defineProperty(exports, "normalizeSafetySettings", {
1622
+ enumerable: true,
1623
+ get: function() {
1624
+ return normalizeSafetySettings;
1625
+ }
1626
+ });
1627
+ Object.defineProperty(exports, "normalizeTools", {
1628
+ enumerable: true,
1629
+ get: function() {
1630
+ return normalizeTools;
1631
+ }
1632
+ });
1633
+ Object.defineProperty(exports, "parseDataUrl", {
1634
+ enumerable: true,
1635
+ get: function() {
1636
+ return parseDataUrl;
1637
+ }
1638
+ });
1639
+ Object.defineProperty(exports, "renderAuthVars", {
1640
+ enumerable: true,
1641
+ get: function() {
1642
+ return renderAuthVars;
1643
+ }
1644
+ });
1645
+ Object.defineProperty(exports, "resolveProjectId", {
1646
+ enumerable: true,
1647
+ get: function() {
1648
+ return resolveProjectId;
1649
+ }
1650
+ });
1651
+ Object.defineProperty(exports, "toDataUri", {
1652
+ enumerable: true,
1653
+ get: function() {
1654
+ return toDataUri;
1655
+ }
1656
+ });
1657
+ Object.defineProperty(exports, "transformMCPConfigToClaudeCode", {
1658
+ enumerable: true,
1659
+ get: function() {
1660
+ return transformMCPConfigToClaudeCode;
1661
+ }
1662
+ });
1663
+ Object.defineProperty(exports, "transformMCPToolsToAnthropic", {
1664
+ enumerable: true,
1665
+ get: function() {
1666
+ return transformMCPToolsToAnthropic;
1667
+ }
1668
+ });
1669
+ Object.defineProperty(exports, "transformMCPToolsToGoogle", {
1670
+ enumerable: true,
1671
+ get: function() {
1672
+ return transformMCPToolsToGoogle;
1673
+ }
1674
+ });
1675
+ Object.defineProperty(exports, "transformMCPToolsToOpenAi", {
1676
+ enumerable: true,
1677
+ get: function() {
1678
+ return transformMCPToolsToOpenAi;
1679
+ }
1680
+ });
1681
+ Object.defineProperty(exports, "validateFunctionCall", {
1682
+ enumerable: true,
1683
+ get: function() {
1684
+ return validateFunctionCall;
1685
+ }
1686
+ });
1687
+
1688
+ //# sourceMappingURL=transform-Bv6gG2MJ.cjs.map